1 // Copyright 2017 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "media/mojo/services/watch_time_recorder.h"
13 #include "base/containers/contains.h"
14 #include "base/functional/bind.h"
15 #include "base/functional/callback_helpers.h"
16 #include "base/hash/hash.h"
17 #include "base/run_loop.h"
18 #include "base/strings/string_number_conversions.h"
19 #include "base/strings/string_piece.h"
20 #include "base/test/metrics/histogram_tester.h"
21 #include "base/test/task_environment.h"
22 #include "base/test/test_message_loop.h"
23 #include "base/time/time.h"
24 #include "components/ukm/test_ukm_recorder.h"
25 #include "media/base/video_codecs.h"
26 #include "media/base/watch_time_keys.h"
27 #include "media/mojo/services/media_metrics_provider.h"
28 #include "mojo/public/cpp/bindings/remote.h"
29 #include "services/metrics/public/cpp/ukm_builders.h"
30 #include "testing/gmock/include/gmock/gmock.h"
31 #include "testing/gtest/include/gtest/gtest.h"
34 using UkmEntry = ukm::builders::Media_BasicPlayback;
37 class RenderFrameHostDelegate;
38 } // namespace content
42 constexpr char kTestOrigin[] = "https://test.google.com/";
44 class WatchTimeRecorderTest : public testing::Test {
46 WatchTimeRecorderTest()
48 {WatchTimeKey::kAudioSrc, WatchTimeKey::kAudioMse,
49 WatchTimeKey::kAudioEme, WatchTimeKey::kAudioVideoSrc,
50 WatchTimeKey::kAudioVideoMse, WatchTimeKey::kAudioVideoEme}),
51 mtbr_keys_({kMeanTimeBetweenRebuffersAudioSrc,
52 kMeanTimeBetweenRebuffersAudioMse,
53 kMeanTimeBetweenRebuffersAudioEme,
54 kMeanTimeBetweenRebuffersAudioVideoSrc,
55 kMeanTimeBetweenRebuffersAudioVideoMse,
56 kMeanTimeBetweenRebuffersAudioVideoEme}),
57 smooth_keys_({kRebuffersCountAudioSrc, kRebuffersCountAudioMse,
58 kRebuffersCountAudioEme, kRebuffersCountAudioVideoSrc,
59 kRebuffersCountAudioVideoMse,
60 kRebuffersCountAudioVideoEme}),
61 discard_keys_({kDiscardedWatchTimeAudioSrc, kDiscardedWatchTimeAudioMse,
62 kDiscardedWatchTimeAudioEme,
63 kDiscardedWatchTimeAudioVideoSrc,
64 kDiscardedWatchTimeAudioVideoMse,
65 kDiscardedWatchTimeAudioVideoEme}) {
66 source_id_ = test_recorder_->GetNewSourceID();
67 ResetMetricRecorders();
68 MediaMetricsProvider::Create(
69 MediaMetricsProvider::BrowsingMode::kIncognito,
70 MediaMetricsProvider::FrameStatus::kTopFrame, GetSourceId(),
71 learning::FeatureValue(0), VideoDecodePerfHistory::SaveCallback(),
72 MediaMetricsProvider::GetLearningSessionCallback(),
74 &WatchTimeRecorderTest::GetRecordAggregateWatchTimeCallback,
75 base::Unretained(this)),
76 base::BindRepeating(&WatchTimeRecorderTest::IsShuttingDown,
77 base::Unretained(this)),
78 provider_.BindNewPipeAndPassReceiver());
81 WatchTimeRecorderTest(const WatchTimeRecorderTest&) = delete;
82 WatchTimeRecorderTest& operator=(const WatchTimeRecorderTest&) = delete;
84 ~WatchTimeRecorderTest() override { base::RunLoop().RunUntilIdle(); }
86 void Initialize(mojom::PlaybackPropertiesPtr properties) {
87 provider_->Initialize(properties->is_mse,
88 properties->is_mse ? mojom::MediaURLScheme::kUnknown
89 : mojom::MediaURLScheme::kHttp,
90 properties->media_stream_type);
91 provider_->AcquireWatchTimeRecorder(std::move(properties),
92 wtr_.BindNewPipeAndPassReceiver());
100 mojom::MediaStreamType media_stream_type = mojom::MediaStreamType::kNone,
101 RendererType renderer_type = RendererType::kRendererImpl) {
102 Initialize(mojom::PlaybackProperties::New(
103 has_audio, has_video, false, false, is_mse, is_encrypted, false,
104 media_stream_type, renderer_type));
107 void ExpectWatchTime(const std::vector<base::StringPiece>& keys,
108 base::TimeDelta value) {
109 for (int i = 0; i <= static_cast<int>(WatchTimeKey::kWatchTimeKeyMax);
111 const base::StringPiece test_key =
112 ConvertWatchTimeKeyToStringForUma(static_cast<WatchTimeKey>(i));
113 if (test_key.empty())
115 if (base::Contains(keys, test_key)) {
116 histogram_tester_->ExpectUniqueSample(test_key, value.InMilliseconds(),
119 histogram_tester_->ExpectTotalCount(test_key, 0);
124 void ExpectHelper(const std::vector<base::StringPiece>& full_key_list,
125 const std::vector<base::StringPiece>& keys,
127 for (auto key : full_key_list) {
128 if (base::Contains(keys, key))
129 histogram_tester_->ExpectUniqueSample(key, value, 1);
131 histogram_tester_->ExpectTotalCount(key, 0);
135 void ExpectMtbrTime(const std::vector<base::StringPiece>& keys,
136 base::TimeDelta value) {
137 ExpectHelper(mtbr_keys_, keys, value.InMilliseconds());
140 void ExpectZeroRebuffers(const std::vector<base::StringPiece>& keys) {
141 ExpectHelper(smooth_keys_, keys, 0);
144 void ExpectRebuffers(const std::vector<base::StringPiece>& keys, int count) {
145 ExpectHelper(smooth_keys_, keys, count);
148 void ExpectAacAudioCodecProfileHistogram(AudioCodecProfile profile) {
149 constexpr char kAudioCodecProfileHistogram[] =
150 "Media.AudioCodecProfile.AAC";
151 histogram_tester_->ExpectUniqueSample(kAudioCodecProfileHistogram,
152 static_cast<int64_t>(profile), 1);
155 void ExpectNoUkmWatchTime() {
156 // We always add a source in testing.
157 ASSERT_EQ(1u, test_recorder_->sources_count());
158 ASSERT_EQ(0u, test_recorder_->entries_count());
161 void ExpectUkmWatchTime(const std::vector<base::StringPiece>& keys,
162 base::TimeDelta value) {
163 const auto& entries =
164 test_recorder_->GetEntriesByName(UkmEntry::kEntryName);
165 EXPECT_EQ(1u, entries.size());
166 for (const auto* entry : entries) {
167 test_recorder_->ExpectEntrySourceHasUrl(entry, GURL(kTestOrigin));
168 for (auto key : keys) {
169 test_recorder_->ExpectEntryMetric(entry, key.data(),
170 value.InMilliseconds());
175 void ResetMetricRecorders() {
176 histogram_tester_ = std::make_unique<base::HistogramTester>();
177 // Ensure cleared global before attempting to create a new TestUkmReporter.
178 test_recorder_.reset();
179 test_recorder_ = std::make_unique<ukm::TestAutoSetUkmRecorder>();
180 test_recorder_->UpdateSourceURL(source_id_, GURL(kTestOrigin));
183 mojom::SecondaryPlaybackPropertiesPtr CreateSecondaryProperties() {
184 return mojom::SecondaryPlaybackProperties::New(
185 AudioCodec::kAAC, VideoCodec::kH264, AudioCodecProfile::kUnknown,
186 H264PROFILE_MAIN, AudioDecoderType::kUnknown,
187 VideoDecoderType::kUnknown, EncryptionScheme::kUnencrypted,
188 EncryptionScheme::kUnencrypted, gfx::Size(800, 600));
191 ukm::SourceId GetSourceId() { return source_id_; }
193 MediaMetricsProvider::RecordAggregateWatchTimeCallback
194 GetRecordAggregateWatchTimeCallback() {
195 return base::BindRepeating(
196 [](base::WeakPtr<content::RenderFrameHostDelegate> delegate,
197 GURL last_committed_url, base::TimeDelta total_watch_time,
198 base::TimeDelta time_stamp, bool has_video, bool has_audio) {
199 // Do nothing as this mock callback will never be called.
204 MOCK_METHOD(bool, IsShuttingDown, ());
205 MOCK_METHOD0(GetCurrentMediaTime, base::TimeDelta());
208 base::test::SingleThreadTaskEnvironment task_environment_;
209 mojo::Remote<mojom::MediaMetricsProvider> provider_;
210 std::unique_ptr<base::HistogramTester> histogram_tester_;
211 std::unique_ptr<ukm::TestAutoSetUkmRecorder> test_recorder_;
212 ukm::SourceId source_id_;
213 mojo::Remote<mojom::WatchTimeRecorder> wtr_;
214 const std::vector<WatchTimeKey> computation_keys_;
215 const std::vector<base::StringPiece> mtbr_keys_;
216 const std::vector<base::StringPiece> smooth_keys_;
217 const std::vector<base::StringPiece> discard_keys_;
220 TEST_F(WatchTimeRecorderTest, TestBasicReporting) {
221 constexpr base::TimeDelta kWatchTime1 = base::Seconds(25);
222 constexpr base::TimeDelta kWatchTime2 = base::Seconds(50);
224 for (int i = 0; i <= static_cast<int>(WatchTimeKey::kWatchTimeKeyMax); ++i) {
225 const WatchTimeKey key = static_cast<WatchTimeKey>(i);
227 auto key_str = ConvertWatchTimeKeyToStringForUma(key);
228 SCOPED_TRACE(key_str.empty() ? base::NumberToString(i)
229 : std::string(key_str));
231 // Values for |is_background| and |is_muted| don't matter in this test since
232 // they don't prevent the muted or background keys from being recorded.
233 Initialize(true, false, true, true);
234 wtr_->UpdateSecondaryProperties(CreateSecondaryProperties());
236 wtr_->RecordWatchTime(WatchTimeKey::kWatchTimeKeyMax, kWatchTime1);
237 wtr_->RecordWatchTime(key, kWatchTime1);
238 wtr_->RecordWatchTime(key, kWatchTime2);
239 base::RunLoop().RunUntilIdle();
241 // Nothing should be recorded yet since we haven't finalized.
242 ExpectWatchTime({}, base::TimeDelta());
244 // Only the requested key should be finalized.
245 wtr_->FinalizeWatchTime({key});
246 base::RunLoop().RunUntilIdle();
248 if (!key_str.empty())
249 ExpectWatchTime({key_str}, kWatchTime2);
251 // These keys are only reported for a full finalize.
252 ExpectMtbrTime({}, base::TimeDelta());
253 ExpectZeroRebuffers({});
254 ExpectNoUkmWatchTime();
256 // Verify nothing else is recorded except for what we finalized above.
257 ResetMetricRecorders();
259 base::RunLoop().RunUntilIdle();
260 ExpectWatchTime({}, base::TimeDelta());
261 ExpectMtbrTime({}, base::TimeDelta());
262 ExpectZeroRebuffers({});
265 case WatchTimeKey::kAudioAll:
266 case WatchTimeKey::kAudioBackgroundAll:
267 case WatchTimeKey::kAudioVideoAll:
268 case WatchTimeKey::kAudioVideoBackgroundAll:
269 case WatchTimeKey::kAudioVideoMutedAll:
270 case WatchTimeKey::kVideoAll:
271 case WatchTimeKey::kVideoBackgroundAll:
272 ExpectUkmWatchTime({UkmEntry::kWatchTimeName}, kWatchTime2);
275 // These keys are not reported, instead we boolean flags for each type.
276 case WatchTimeKey::kAudioMse:
277 case WatchTimeKey::kAudioEme:
278 case WatchTimeKey::kAudioSrc:
279 case WatchTimeKey::kAudioEmbeddedExperience:
280 case WatchTimeKey::kAudioBackgroundMse:
281 case WatchTimeKey::kAudioBackgroundEme:
282 case WatchTimeKey::kAudioBackgroundSrc:
283 case WatchTimeKey::kAudioBackgroundEmbeddedExperience:
284 case WatchTimeKey::kAudioVideoMse:
285 case WatchTimeKey::kAudioVideoEme:
286 case WatchTimeKey::kAudioVideoSrc:
287 case WatchTimeKey::kAudioVideoEmbeddedExperience:
288 case WatchTimeKey::kAudioVideoMutedMse:
289 case WatchTimeKey::kAudioVideoMutedEme:
290 case WatchTimeKey::kAudioVideoMutedSrc:
291 case WatchTimeKey::kAudioVideoMutedEmbeddedExperience:
292 case WatchTimeKey::kAudioVideoBackgroundMse:
293 case WatchTimeKey::kAudioVideoBackgroundEme:
294 case WatchTimeKey::kAudioVideoBackgroundSrc:
295 case WatchTimeKey::kAudioVideoBackgroundEmbeddedExperience:
296 case WatchTimeKey::kVideoMse:
297 case WatchTimeKey::kVideoEme:
298 case WatchTimeKey::kVideoSrc:
299 case WatchTimeKey::kVideoEmbeddedExperience:
300 case WatchTimeKey::kVideoBackgroundMse:
301 case WatchTimeKey::kVideoBackgroundEme:
302 case WatchTimeKey::kVideoBackgroundSrc:
303 case WatchTimeKey::kVideoBackgroundEmbeddedExperience:
304 case WatchTimeKey::kAudioVideoMediaFoundationAll:
305 case WatchTimeKey::kAudioVideoMediaFoundationEme:
306 ExpectUkmWatchTime({}, base::TimeDelta());
309 // These keys roll up into the battery watch time field.
310 case WatchTimeKey::kAudioBattery:
311 case WatchTimeKey::kAudioBackgroundBattery:
312 case WatchTimeKey::kAudioVideoBattery:
313 case WatchTimeKey::kAudioVideoMutedBattery:
314 case WatchTimeKey::kAudioVideoBackgroundBattery:
315 case WatchTimeKey::kVideoBattery:
316 case WatchTimeKey::kVideoBackgroundBattery:
317 ExpectUkmWatchTime({UkmEntry::kWatchTime_BatteryName}, kWatchTime2);
320 // These keys roll up into the AC watch time field.
321 case WatchTimeKey::kAudioAc:
322 case WatchTimeKey::kAudioBackgroundAc:
323 case WatchTimeKey::kAudioVideoAc:
324 case WatchTimeKey::kAudioVideoBackgroundAc:
325 case WatchTimeKey::kAudioVideoMutedAc:
326 case WatchTimeKey::kVideoAc:
327 case WatchTimeKey::kVideoBackgroundAc:
328 ExpectUkmWatchTime({UkmEntry::kWatchTime_ACName}, kWatchTime2);
331 case WatchTimeKey::kAudioVideoDisplayFullscreen:
332 case WatchTimeKey::kAudioVideoMutedDisplayFullscreen:
333 case WatchTimeKey::kVideoDisplayFullscreen:
334 ExpectUkmWatchTime({UkmEntry::kWatchTime_DisplayFullscreenName},
338 case WatchTimeKey::kAudioVideoDisplayInline:
339 case WatchTimeKey::kAudioVideoMutedDisplayInline:
340 case WatchTimeKey::kVideoDisplayInline:
341 ExpectUkmWatchTime({UkmEntry::kWatchTime_DisplayInlineName},
345 case WatchTimeKey::kAudioVideoDisplayPictureInPicture:
346 case WatchTimeKey::kAudioVideoMutedDisplayPictureInPicture:
347 case WatchTimeKey::kVideoDisplayPictureInPicture:
348 ExpectUkmWatchTime({UkmEntry::kWatchTime_DisplayPictureInPictureName},
352 case WatchTimeKey::kAudioNativeControlsOn:
353 case WatchTimeKey::kAudioVideoNativeControlsOn:
354 case WatchTimeKey::kAudioVideoMutedNativeControlsOn:
355 case WatchTimeKey::kVideoNativeControlsOn:
356 ExpectUkmWatchTime({UkmEntry::kWatchTime_NativeControlsOnName},
360 case WatchTimeKey::kAudioNativeControlsOff:
361 case WatchTimeKey::kAudioVideoNativeControlsOff:
362 case WatchTimeKey::kAudioVideoMutedNativeControlsOff:
363 case WatchTimeKey::kVideoNativeControlsOff:
364 ExpectUkmWatchTime({UkmEntry::kWatchTime_NativeControlsOffName},
369 ResetMetricRecorders();
373 TEST_F(WatchTimeRecorderTest, TestBasicReportingMediaStream) {
374 constexpr base::TimeDelta kWatchTime1 = base::Seconds(25);
375 constexpr base::TimeDelta kWatchTime2 = base::Seconds(50);
377 for (int i = 0; i <= static_cast<int>(WatchTimeKey::kWatchTimeKeyMax); ++i) {
378 const WatchTimeKey key = static_cast<WatchTimeKey>(i);
380 auto key_str = ConvertWatchTimeKeyToStringForUma(key);
381 SCOPED_TRACE(key_str.empty() ? base::NumberToString(i)
382 : std::string(key_str));
384 // Values for |is_background| and |is_muted| don't matter in this test since
385 // they don't prevent the muted or background keys from being recorded.
386 Initialize(true, false, true, true,
387 mojom::MediaStreamType::kLocalDeviceCapture);
388 wtr_->UpdateSecondaryProperties(CreateSecondaryProperties());
390 wtr_->RecordWatchTime(WatchTimeKey::kWatchTimeKeyMax, kWatchTime1);
391 wtr_->RecordWatchTime(key, kWatchTime1);
392 wtr_->RecordWatchTime(key, kWatchTime2);
393 base::RunLoop().RunUntilIdle();
395 // Nothing should be recorded yet since we haven't finalized.
396 ExpectWatchTime({}, base::TimeDelta());
398 // Only the requested key should be finalized.
399 wtr_->FinalizeWatchTime({key});
400 base::RunLoop().RunUntilIdle();
402 if (!key_str.empty())
403 ExpectWatchTime({}, base::TimeDelta());
405 ExpectMtbrTime({}, base::TimeDelta());
406 ExpectZeroRebuffers({});
407 ExpectNoUkmWatchTime();
409 ResetMetricRecorders();
411 base::RunLoop().RunUntilIdle();
412 ExpectWatchTime({}, base::TimeDelta());
413 ExpectMtbrTime({}, base::TimeDelta());
414 ExpectZeroRebuffers({});
416 // UKM watch time should be recorded even with no UMA.
418 case WatchTimeKey::kAudioAll:
419 case WatchTimeKey::kAudioBackgroundAll:
420 case WatchTimeKey::kAudioVideoAll:
421 case WatchTimeKey::kAudioVideoBackgroundAll:
422 case WatchTimeKey::kAudioVideoMutedAll:
423 case WatchTimeKey::kVideoAll:
424 case WatchTimeKey::kVideoBackgroundAll:
425 ExpectUkmWatchTime({UkmEntry::kWatchTimeName}, kWatchTime2);
428 // These keys are not reported, instead we boolean flags for each type.
429 case WatchTimeKey::kAudioMse:
430 case WatchTimeKey::kAudioEme:
431 case WatchTimeKey::kAudioSrc:
432 case WatchTimeKey::kAudioEmbeddedExperience:
433 case WatchTimeKey::kAudioBackgroundMse:
434 case WatchTimeKey::kAudioBackgroundEme:
435 case WatchTimeKey::kAudioBackgroundSrc:
436 case WatchTimeKey::kAudioBackgroundEmbeddedExperience:
437 case WatchTimeKey::kAudioVideoMse:
438 case WatchTimeKey::kAudioVideoEme:
439 case WatchTimeKey::kAudioVideoSrc:
440 case WatchTimeKey::kAudioVideoEmbeddedExperience:
441 case WatchTimeKey::kAudioVideoMutedMse:
442 case WatchTimeKey::kAudioVideoMutedEme:
443 case WatchTimeKey::kAudioVideoMutedSrc:
444 case WatchTimeKey::kAudioVideoMutedEmbeddedExperience:
445 case WatchTimeKey::kAudioVideoBackgroundMse:
446 case WatchTimeKey::kAudioVideoBackgroundEme:
447 case WatchTimeKey::kAudioVideoBackgroundSrc:
448 case WatchTimeKey::kAudioVideoBackgroundEmbeddedExperience:
449 case WatchTimeKey::kVideoMse:
450 case WatchTimeKey::kVideoEme:
451 case WatchTimeKey::kVideoSrc:
452 case WatchTimeKey::kVideoEmbeddedExperience:
453 case WatchTimeKey::kVideoBackgroundMse:
454 case WatchTimeKey::kVideoBackgroundEme:
455 case WatchTimeKey::kVideoBackgroundSrc:
456 case WatchTimeKey::kVideoBackgroundEmbeddedExperience:
457 case WatchTimeKey::kAudioVideoMediaFoundationAll:
458 case WatchTimeKey::kAudioVideoMediaFoundationEme:
459 ExpectUkmWatchTime({}, base::TimeDelta());
462 // These keys roll up into the battery watch time field.
463 case WatchTimeKey::kAudioBattery:
464 case WatchTimeKey::kAudioBackgroundBattery:
465 case WatchTimeKey::kAudioVideoBattery:
466 case WatchTimeKey::kAudioVideoMutedBattery:
467 case WatchTimeKey::kAudioVideoBackgroundBattery:
468 case WatchTimeKey::kVideoBattery:
469 case WatchTimeKey::kVideoBackgroundBattery:
470 ExpectUkmWatchTime({UkmEntry::kWatchTime_BatteryName}, kWatchTime2);
473 // These keys roll up into the AC watch time field.
474 case WatchTimeKey::kAudioAc:
475 case WatchTimeKey::kAudioBackgroundAc:
476 case WatchTimeKey::kAudioVideoAc:
477 case WatchTimeKey::kAudioVideoBackgroundAc:
478 case WatchTimeKey::kAudioVideoMutedAc:
479 case WatchTimeKey::kVideoAc:
480 case WatchTimeKey::kVideoBackgroundAc:
481 ExpectUkmWatchTime({UkmEntry::kWatchTime_ACName}, kWatchTime2);
484 case WatchTimeKey::kAudioVideoDisplayFullscreen:
485 case WatchTimeKey::kAudioVideoMutedDisplayFullscreen:
486 case WatchTimeKey::kVideoDisplayFullscreen:
487 ExpectUkmWatchTime({UkmEntry::kWatchTime_DisplayFullscreenName},
491 case WatchTimeKey::kAudioVideoDisplayInline:
492 case WatchTimeKey::kAudioVideoMutedDisplayInline:
493 case WatchTimeKey::kVideoDisplayInline:
494 ExpectUkmWatchTime({UkmEntry::kWatchTime_DisplayInlineName},
498 case WatchTimeKey::kAudioVideoDisplayPictureInPicture:
499 case WatchTimeKey::kAudioVideoMutedDisplayPictureInPicture:
500 case WatchTimeKey::kVideoDisplayPictureInPicture:
501 ExpectUkmWatchTime({UkmEntry::kWatchTime_DisplayPictureInPictureName},
505 case WatchTimeKey::kAudioNativeControlsOn:
506 case WatchTimeKey::kAudioVideoNativeControlsOn:
507 case WatchTimeKey::kAudioVideoMutedNativeControlsOn:
508 case WatchTimeKey::kVideoNativeControlsOn:
509 ExpectUkmWatchTime({UkmEntry::kWatchTime_NativeControlsOnName},
513 case WatchTimeKey::kAudioNativeControlsOff:
514 case WatchTimeKey::kAudioVideoNativeControlsOff:
515 case WatchTimeKey::kAudioVideoMutedNativeControlsOff:
516 case WatchTimeKey::kVideoNativeControlsOff:
517 ExpectUkmWatchTime({UkmEntry::kWatchTime_NativeControlsOffName},
522 ResetMetricRecorders();
526 TEST_F(WatchTimeRecorderTest, TestRebufferingMetrics) {
527 Initialize(true, false, true, true);
529 constexpr base::TimeDelta kWatchTime = base::Seconds(50);
530 for (auto key : computation_keys_)
531 wtr_->RecordWatchTime(key, kWatchTime);
532 wtr_->UpdateUnderflowCount(1);
533 wtr_->UpdateUnderflowCount(2);
535 // Trigger finalization of everything.
536 wtr_->FinalizeWatchTime({});
537 base::RunLoop().RunUntilIdle();
539 ExpectMtbrTime(mtbr_keys_, kWatchTime / 2);
540 ExpectRebuffers(smooth_keys_, 2);
542 // Now rerun the test without any rebuffering.
543 ResetMetricRecorders();
544 for (auto key : computation_keys_)
545 wtr_->RecordWatchTime(key, kWatchTime);
546 wtr_->FinalizeWatchTime({});
547 base::RunLoop().RunUntilIdle();
549 ExpectMtbrTime({}, base::TimeDelta());
550 ExpectZeroRebuffers(smooth_keys_);
552 // Now rerun the test with a small amount of watch time and ensure rebuffering
553 // isn't recorded because we haven't met the watch time requirements.
554 ResetMetricRecorders();
555 constexpr base::TimeDelta kWatchTimeShort = base::Seconds(5);
556 for (auto key : computation_keys_)
557 wtr_->RecordWatchTime(key, kWatchTimeShort);
558 wtr_->UpdateUnderflowCount(1);
559 wtr_->UpdateUnderflowCount(2);
560 wtr_->FinalizeWatchTime({});
561 base::RunLoop().RunUntilIdle();
563 // Nothing should be logged since this doesn't meet requirements.
564 ExpectMtbrTime({}, base::TimeDelta());
565 for (auto key : smooth_keys_)
566 histogram_tester_->ExpectTotalCount(key, 0);
569 TEST_F(WatchTimeRecorderTest, TestRebufferingMetricsMediaStream) {
570 Initialize(true, false, true, true,
571 mojom::MediaStreamType::kLocalDeviceCapture);
573 constexpr base::TimeDelta kWatchTime = base::Seconds(50);
574 for (auto key : computation_keys_)
575 wtr_->RecordWatchTime(key, kWatchTime);
576 wtr_->UpdateUnderflowCount(1);
577 wtr_->UpdateUnderflowCount(2);
579 // Trigger finalization of everything.
580 wtr_->FinalizeWatchTime({});
581 base::RunLoop().RunUntilIdle();
583 ExpectMtbrTime({}, base::TimeDelta());
584 ExpectRebuffers({}, 0);
586 // Now rerun the test without any rebuffering.
587 ResetMetricRecorders();
588 for (auto key : computation_keys_)
589 wtr_->RecordWatchTime(key, kWatchTime);
590 wtr_->FinalizeWatchTime({});
591 base::RunLoop().RunUntilIdle();
593 ExpectMtbrTime({}, base::TimeDelta());
594 ExpectRebuffers({}, 0);
597 TEST_F(WatchTimeRecorderTest, TestDiscardMetrics) {
598 Initialize(true, false, true, true);
599 wtr_->UpdateSecondaryProperties(CreateSecondaryProperties());
601 constexpr base::TimeDelta kWatchTime = base::Seconds(5);
602 for (auto key : computation_keys_)
603 wtr_->RecordWatchTime(key, kWatchTime);
605 // Trigger finalization of everything.
607 base::RunLoop().RunUntilIdle();
609 // No standard watch time should be recorded because it falls below the
610 // reporting threshold.
611 ExpectWatchTime({}, base::TimeDelta());
613 // Verify the time was instead logged to the discard keys.
614 for (auto key : discard_keys_) {
615 histogram_tester_->ExpectUniqueSample(key, kWatchTime.InMilliseconds(), 1);
618 // UKM watch time won't be logged because we aren't sending "All" keys.
619 ExpectUkmWatchTime({}, base::TimeDelta());
622 TEST_F(WatchTimeRecorderTest, TestDiscardMetricsMediaStream) {
623 Initialize(true, false, true, true,
624 mojom::MediaStreamType::kLocalDeviceCapture);
625 wtr_->UpdateSecondaryProperties(CreateSecondaryProperties());
627 constexpr base::TimeDelta kWatchTime = base::Seconds(5);
628 for (auto key : computation_keys_)
629 wtr_->RecordWatchTime(key, kWatchTime);
631 // Trigger finalization of everything.
633 base::RunLoop().RunUntilIdle();
635 // No watch time and no discard metrics should be logged.
636 ExpectWatchTime({}, base::TimeDelta());
637 for (auto key : discard_keys_) {
638 histogram_tester_->ExpectTotalCount(key, 0);
641 // UKM watch time won't be logged because we aren't sending "All" keys.
642 ExpectUkmWatchTime({}, base::TimeDelta());
645 #define EXPECT_UKM(name, value) \
646 test_recorder_->ExpectEntryMetric(entry, name, value)
647 #define EXPECT_NO_UKM(name) \
648 EXPECT_FALSE(test_recorder_->EntryHasMetric(entry, name))
649 #define EXPECT_HAS_UKM(name) \
650 EXPECT_TRUE(test_recorder_->EntryHasMetric(entry, name));
652 TEST_F(WatchTimeRecorderTest, TestFinalizeNoDuplication) {
653 mojom::PlaybackPropertiesPtr properties = mojom::PlaybackProperties::New(
654 true, true, false, false, false, false, false,
655 mojom::MediaStreamType::kNone, RendererType::kRendererImpl);
656 mojom::SecondaryPlaybackPropertiesPtr secondary_properties =
657 CreateSecondaryProperties();
658 Initialize(properties.Clone());
659 wtr_->UpdateSecondaryProperties(secondary_properties.Clone());
661 // Verify that UKM is reported along with the watch time.
662 constexpr base::TimeDelta kWatchTime = base::Seconds(4);
663 wtr_->RecordWatchTime(WatchTimeKey::kAudioVideoAll, kWatchTime);
665 // Finalize everything. UKM is only recorded at destruction, so this should do
667 wtr_->FinalizeWatchTime({});
668 base::RunLoop().RunUntilIdle();
670 // No watch time should have been recorded since this is below the UMA report
672 ExpectWatchTime({}, base::TimeDelta());
673 ExpectMtbrTime({}, base::TimeDelta());
674 ExpectZeroRebuffers({});
675 ExpectNoUkmWatchTime();
677 const auto& empty_entries =
678 test_recorder_->GetEntriesByName(UkmEntry::kEntryName);
679 EXPECT_EQ(0u, empty_entries.size());
681 // Verify UKM is logged at destruction time.
682 ResetMetricRecorders();
684 base::RunLoop().RunUntilIdle();
685 const auto& entries = test_recorder_->GetEntriesByName(UkmEntry::kEntryName);
686 EXPECT_EQ(1u, entries.size());
687 for (const auto* entry : entries) {
688 test_recorder_->ExpectEntrySourceHasUrl(entry, GURL(kTestOrigin));
690 EXPECT_UKM(UkmEntry::kIsBackgroundName, properties->is_background);
691 EXPECT_UKM(UkmEntry::kIsMutedName, properties->is_muted);
692 EXPECT_UKM(UkmEntry::kAudioCodecName,
693 static_cast<int>(secondary_properties->audio_codec));
694 EXPECT_UKM(UkmEntry::kVideoCodecName,
695 static_cast<int>(secondary_properties->video_codec));
696 EXPECT_UKM(UkmEntry::kAudioCodecProfileName,
697 static_cast<int64_t>(secondary_properties->audio_codec_profile));
698 EXPECT_UKM(UkmEntry::kVideoCodecProfileName,
699 secondary_properties->video_codec_profile);
700 EXPECT_UKM(UkmEntry::kHasAudioName, properties->has_audio);
701 EXPECT_UKM(UkmEntry::kHasVideoName, properties->has_video);
703 UkmEntry::kAudioEncryptionSchemeName,
704 static_cast<int64_t>(secondary_properties->audio_encryption_scheme));
706 UkmEntry::kVideoEncryptionSchemeName,
707 static_cast<int64_t>(secondary_properties->video_encryption_scheme));
708 EXPECT_UKM(UkmEntry::kIsEMEName, properties->is_eme);
709 EXPECT_UKM(UkmEntry::kIsMSEName, properties->is_mse);
710 EXPECT_UKM(UkmEntry::kMediaStreamTypeName,
711 static_cast<int64_t>(properties->media_stream_type));
712 EXPECT_UKM(UkmEntry::kLastPipelineStatusName, PIPELINE_OK);
713 EXPECT_UKM(UkmEntry::kRebuffersCountName, 0);
714 EXPECT_UKM(UkmEntry::kCompletedRebuffersCountName, 0);
715 EXPECT_UKM(UkmEntry::kCompletedRebuffersDurationName, 0);
716 EXPECT_UKM(UkmEntry::kVideoNaturalWidthName,
717 secondary_properties->natural_size.width());
718 EXPECT_UKM(UkmEntry::kVideoNaturalHeightName,
719 secondary_properties->natural_size.height());
720 EXPECT_UKM(UkmEntry::kWatchTimeName, kWatchTime.InMilliseconds());
721 EXPECT_UKM(UkmEntry::kAudioDecoderNameName, 0);
722 EXPECT_UKM(UkmEntry::kVideoDecoderNameName, 0);
723 EXPECT_UKM(UkmEntry::kAutoplayInitiatedName, false);
724 EXPECT_HAS_UKM(UkmEntry::kPlayerIDName);
726 EXPECT_NO_UKM(UkmEntry::kMeanTimeBetweenRebuffersName);
727 EXPECT_NO_UKM(UkmEntry::kWatchTime_ACName);
728 EXPECT_NO_UKM(UkmEntry::kWatchTime_BatteryName);
729 EXPECT_NO_UKM(UkmEntry::kWatchTime_NativeControlsOnName);
730 EXPECT_NO_UKM(UkmEntry::kWatchTime_NativeControlsOffName);
731 EXPECT_NO_UKM(UkmEntry::kWatchTime_DisplayFullscreenName);
732 EXPECT_NO_UKM(UkmEntry::kWatchTime_DisplayInlineName);
733 EXPECT_NO_UKM(UkmEntry::kWatchTime_DisplayPictureInPictureName);
737 TEST_F(WatchTimeRecorderTest, FinalizeWithoutWatchTime) {
738 mojom::PlaybackPropertiesPtr properties = mojom::PlaybackProperties::New(
739 true, true, false, false, false, false, false,
740 mojom::MediaStreamType::kNone, RendererType::kRendererImpl);
741 mojom::SecondaryPlaybackPropertiesPtr secondary_properties =
742 CreateSecondaryProperties();
743 Initialize(properties.Clone());
744 wtr_->UpdateSecondaryProperties(secondary_properties.Clone());
746 // Finalize everything. UKM is only recorded at destruction, so this should do
748 wtr_->FinalizeWatchTime({});
749 base::RunLoop().RunUntilIdle();
751 // No watch time should have been recorded even though a finalize event will
752 // be sent, however a UKM entry with the playback properties will still be
754 ExpectWatchTime({}, base::TimeDelta());
755 ExpectMtbrTime({}, base::TimeDelta());
756 ExpectZeroRebuffers({});
757 ExpectNoUkmWatchTime();
759 const auto& empty_entries =
760 test_recorder_->GetEntriesByName(UkmEntry::kEntryName);
761 EXPECT_EQ(0u, empty_entries.size());
763 // Destructing the recorder should generate a UKM report though.
764 ResetMetricRecorders();
766 base::RunLoop().RunUntilIdle();
767 const auto& entries = test_recorder_->GetEntriesByName(UkmEntry::kEntryName);
768 EXPECT_EQ(1u, entries.size());
769 for (const auto* entry : entries) {
770 test_recorder_->ExpectEntrySourceHasUrl(entry, GURL(kTestOrigin));
772 EXPECT_UKM(UkmEntry::kIsBackgroundName, properties->is_background);
773 EXPECT_UKM(UkmEntry::kIsMutedName, properties->is_muted);
774 EXPECT_UKM(UkmEntry::kAudioCodecName,
775 static_cast<int>(secondary_properties->audio_codec));
776 EXPECT_UKM(UkmEntry::kVideoCodecName,
777 static_cast<int>(secondary_properties->video_codec));
778 EXPECT_UKM(UkmEntry::kAudioCodecProfileName,
779 static_cast<int64_t>(secondary_properties->audio_codec_profile));
780 EXPECT_UKM(UkmEntry::kVideoCodecProfileName,
781 secondary_properties->video_codec_profile);
782 EXPECT_UKM(UkmEntry::kHasAudioName, properties->has_audio);
783 EXPECT_UKM(UkmEntry::kHasVideoName, properties->has_video);
785 UkmEntry::kAudioEncryptionSchemeName,
786 static_cast<int64_t>(secondary_properties->audio_encryption_scheme));
788 UkmEntry::kVideoEncryptionSchemeName,
789 static_cast<int64_t>(secondary_properties->video_encryption_scheme));
790 EXPECT_UKM(UkmEntry::kIsEMEName, properties->is_eme);
791 EXPECT_UKM(UkmEntry::kIsMSEName, properties->is_mse);
792 EXPECT_UKM(UkmEntry::kMediaStreamTypeName,
793 static_cast<int64_t>(properties->media_stream_type));
794 EXPECT_UKM(UkmEntry::kLastPipelineStatusName, PIPELINE_OK);
795 EXPECT_UKM(UkmEntry::kRebuffersCountName, 0);
796 EXPECT_UKM(UkmEntry::kCompletedRebuffersCountName, 0);
797 EXPECT_UKM(UkmEntry::kCompletedRebuffersDurationName, 0);
798 EXPECT_UKM(UkmEntry::kVideoNaturalWidthName,
799 secondary_properties->natural_size.width());
800 EXPECT_UKM(UkmEntry::kVideoNaturalHeightName,
801 secondary_properties->natural_size.height());
802 EXPECT_UKM(UkmEntry::kAudioDecoderNameName, 0);
803 EXPECT_UKM(UkmEntry::kVideoDecoderNameName, 0);
804 EXPECT_UKM(UkmEntry::kAutoplayInitiatedName, false);
805 EXPECT_HAS_UKM(UkmEntry::kPlayerIDName);
807 EXPECT_NO_UKM(UkmEntry::kMeanTimeBetweenRebuffersName);
808 EXPECT_NO_UKM(UkmEntry::kWatchTimeName);
809 EXPECT_NO_UKM(UkmEntry::kWatchTime_ACName);
810 EXPECT_NO_UKM(UkmEntry::kWatchTime_BatteryName);
811 EXPECT_NO_UKM(UkmEntry::kWatchTime_NativeControlsOnName);
812 EXPECT_NO_UKM(UkmEntry::kWatchTime_NativeControlsOffName);
813 EXPECT_NO_UKM(UkmEntry::kWatchTime_DisplayFullscreenName);
814 EXPECT_NO_UKM(UkmEntry::kWatchTime_DisplayInlineName);
815 EXPECT_NO_UKM(UkmEntry::kWatchTime_DisplayPictureInPictureName);
819 TEST_F(WatchTimeRecorderTest, BasicUkmAudioVideo) {
820 mojom::PlaybackPropertiesPtr properties = mojom::PlaybackProperties::New(
821 true, true, false, false, false, false, false,
822 mojom::MediaStreamType::kNone, RendererType::kRendererImpl);
823 mojom::SecondaryPlaybackPropertiesPtr secondary_properties =
824 mojom::SecondaryPlaybackProperties::New(
825 AudioCodec::kAAC, VideoCodec::kH264, AudioCodecProfile::kXHE_AAC,
826 H264PROFILE_MAIN, AudioDecoderType::kUnknown,
827 VideoDecoderType::kUnknown, EncryptionScheme::kCenc,
828 EncryptionScheme::kCbcs, gfx::Size(800, 600));
829 Initialize(properties.Clone());
830 wtr_->UpdateSecondaryProperties(secondary_properties.Clone());
832 constexpr base::TimeDelta kWatchTime = base::Seconds(4);
833 wtr_->RecordWatchTime(WatchTimeKey::kAudioVideoAll, kWatchTime);
835 base::RunLoop().RunUntilIdle();
837 ExpectAacAudioCodecProfileHistogram(
838 secondary_properties->audio_codec_profile);
840 const auto& entries = test_recorder_->GetEntriesByName(UkmEntry::kEntryName);
841 EXPECT_EQ(1u, entries.size());
842 for (const auto* entry : entries) {
843 test_recorder_->ExpectEntrySourceHasUrl(entry, GURL(kTestOrigin));
845 EXPECT_UKM(UkmEntry::kWatchTimeName, kWatchTime.InMilliseconds());
846 EXPECT_UKM(UkmEntry::kIsBackgroundName, properties->is_background);
847 EXPECT_UKM(UkmEntry::kIsMutedName, properties->is_muted);
848 EXPECT_UKM(UkmEntry::kAudioCodecName,
849 static_cast<int>(secondary_properties->audio_codec));
850 EXPECT_UKM(UkmEntry::kVideoCodecName,
851 static_cast<int>(secondary_properties->video_codec));
852 EXPECT_UKM(UkmEntry::kAudioCodecProfileName,
853 static_cast<int64_t>(secondary_properties->audio_codec_profile));
854 EXPECT_UKM(UkmEntry::kVideoCodecProfileName,
855 secondary_properties->video_codec_profile);
856 EXPECT_UKM(UkmEntry::kHasAudioName, properties->has_audio);
857 EXPECT_UKM(UkmEntry::kHasVideoName, properties->has_video);
859 UkmEntry::kAudioEncryptionSchemeName,
860 static_cast<int64_t>(secondary_properties->audio_encryption_scheme));
862 UkmEntry::kVideoEncryptionSchemeName,
863 static_cast<int64_t>(secondary_properties->video_encryption_scheme));
864 EXPECT_UKM(UkmEntry::kIsEMEName, properties->is_eme);
865 EXPECT_UKM(UkmEntry::kIsMSEName, properties->is_mse);
866 EXPECT_UKM(UkmEntry::kMediaStreamTypeName,
867 static_cast<int64_t>(properties->media_stream_type));
868 EXPECT_UKM(UkmEntry::kLastPipelineStatusName, PIPELINE_OK);
869 EXPECT_UKM(UkmEntry::kRebuffersCountName, 0);
870 EXPECT_UKM(UkmEntry::kCompletedRebuffersCountName, 0);
871 EXPECT_UKM(UkmEntry::kCompletedRebuffersDurationName, 0);
872 EXPECT_UKM(UkmEntry::kVideoNaturalWidthName,
873 secondary_properties->natural_size.width());
874 EXPECT_UKM(UkmEntry::kVideoNaturalHeightName,
875 secondary_properties->natural_size.height());
876 EXPECT_HAS_UKM(UkmEntry::kPlayerIDName);
877 EXPECT_UKM(UkmEntry::kAudioDecoderNameName, 0);
878 EXPECT_UKM(UkmEntry::kVideoDecoderNameName, 0);
879 EXPECT_UKM(UkmEntry::kAutoplayInitiatedName, false);
881 EXPECT_NO_UKM(UkmEntry::kMeanTimeBetweenRebuffersName);
882 EXPECT_NO_UKM(UkmEntry::kWatchTime_ACName);
883 EXPECT_NO_UKM(UkmEntry::kWatchTime_BatteryName);
884 EXPECT_NO_UKM(UkmEntry::kWatchTime_NativeControlsOnName);
885 EXPECT_NO_UKM(UkmEntry::kWatchTime_NativeControlsOffName);
886 EXPECT_NO_UKM(UkmEntry::kWatchTime_DisplayFullscreenName);
887 EXPECT_NO_UKM(UkmEntry::kWatchTime_DisplayInlineName);
888 EXPECT_NO_UKM(UkmEntry::kWatchTime_DisplayPictureInPictureName);
892 TEST_F(WatchTimeRecorderTest, BasicUkmAudioVideoWithExtras) {
893 mojom::PlaybackPropertiesPtr properties = mojom::PlaybackProperties::New(
894 true, true, false, false, true, true, false,
895 mojom::MediaStreamType::kNone, RendererType::kRendererImpl);
896 mojom::SecondaryPlaybackPropertiesPtr secondary_properties =
897 mojom::SecondaryPlaybackProperties::New(
898 AudioCodec::kOpus, VideoCodec::kVP9, AudioCodecProfile::kUnknown,
899 VP9PROFILE_PROFILE0, AudioDecoderType::kUnknown,
900 VideoDecoderType::kUnknown, EncryptionScheme::kUnencrypted,
901 EncryptionScheme::kUnencrypted, gfx::Size(800, 600));
902 Initialize(properties.Clone());
903 wtr_->UpdateSecondaryProperties(secondary_properties.Clone());
905 constexpr base::TimeDelta kWatchTime = base::Seconds(54);
906 const base::TimeDelta kWatchTime2 = kWatchTime * 2;
907 const base::TimeDelta kWatchTime3 = kWatchTime / 3;
908 wtr_->RecordWatchTime(WatchTimeKey::kAudioVideoAll, kWatchTime2);
909 wtr_->RecordWatchTime(WatchTimeKey::kAudioVideoAc, kWatchTime);
911 // Ensure partial finalize does not affect final report.
912 wtr_->FinalizeWatchTime({WatchTimeKey::kAudioVideoAc});
913 wtr_->RecordWatchTime(WatchTimeKey::kAudioVideoBattery, kWatchTime);
914 wtr_->RecordWatchTime(WatchTimeKey::kAudioVideoNativeControlsOn, kWatchTime);
915 wtr_->FinalizeWatchTime({WatchTimeKey::kAudioVideoNativeControlsOn});
916 wtr_->RecordWatchTime(WatchTimeKey::kAudioVideoNativeControlsOff, kWatchTime);
917 wtr_->RecordWatchTime(WatchTimeKey::kAudioVideoDisplayFullscreen,
919 wtr_->FinalizeWatchTime({WatchTimeKey::kAudioVideoDisplayFullscreen});
920 wtr_->RecordWatchTime(WatchTimeKey::kAudioVideoDisplayInline, kWatchTime3);
921 wtr_->FinalizeWatchTime({WatchTimeKey::kAudioVideoDisplayInline});
922 wtr_->RecordWatchTime(WatchTimeKey::kAudioVideoDisplayPictureInPicture,
924 wtr_->UpdateUnderflowCount(3);
925 constexpr base::TimeDelta kUnderflowDuration = base::Milliseconds(500);
926 wtr_->UpdateUnderflowDuration(2, kUnderflowDuration);
927 wtr_->UpdateVideoDecodeStats(10, 2);
928 wtr_->OnError(PIPELINE_ERROR_DECODE);
930 secondary_properties->audio_decoder = AudioDecoderType::kMojo;
931 secondary_properties->video_decoder = VideoDecoderType::kMojo;
932 wtr_->UpdateSecondaryProperties(secondary_properties.Clone());
934 wtr_->SetAutoplayInitiated(true);
936 wtr_->OnDurationChanged(base::Seconds(9500));
939 base::RunLoop().RunUntilIdle();
941 const auto& entries = test_recorder_->GetEntriesByName(UkmEntry::kEntryName);
942 EXPECT_EQ(1u, entries.size());
943 for (const auto* entry : entries) {
944 test_recorder_->ExpectEntrySourceHasUrl(entry, GURL(kTestOrigin));
945 EXPECT_UKM(UkmEntry::kWatchTimeName, kWatchTime2.InMilliseconds());
946 EXPECT_UKM(UkmEntry::kWatchTime_ACName, kWatchTime.InMilliseconds());
947 EXPECT_UKM(UkmEntry::kWatchTime_BatteryName, kWatchTime.InMilliseconds());
948 EXPECT_UKM(UkmEntry::kWatchTime_NativeControlsOnName,
949 kWatchTime.InMilliseconds());
950 EXPECT_UKM(UkmEntry::kWatchTime_NativeControlsOffName,
951 kWatchTime.InMilliseconds());
952 EXPECT_UKM(UkmEntry::kWatchTime_DisplayFullscreenName,
953 kWatchTime3.InMilliseconds());
954 EXPECT_UKM(UkmEntry::kWatchTime_DisplayInlineName,
955 kWatchTime3.InMilliseconds());
956 EXPECT_UKM(UkmEntry::kWatchTime_DisplayPictureInPictureName,
957 kWatchTime3.InMilliseconds());
958 EXPECT_UKM(UkmEntry::kMeanTimeBetweenRebuffersName,
959 kWatchTime2.InMilliseconds() / 3);
960 EXPECT_HAS_UKM(UkmEntry::kPlayerIDName);
962 // Values taken from .cc private enumeration (and should never change).
963 EXPECT_UKM(UkmEntry::kAudioDecoderNameName, 2);
964 EXPECT_UKM(UkmEntry::kVideoDecoderNameName, 5);
966 // Duration should be rounded up.
967 EXPECT_UKM(UkmEntry::kDurationName, 10000000);
969 EXPECT_UKM(UkmEntry::kIsBackgroundName, properties->is_background);
970 EXPECT_UKM(UkmEntry::kIsMutedName, properties->is_muted);
971 EXPECT_UKM(UkmEntry::kAudioCodecName,
972 static_cast<int>(secondary_properties->audio_codec));
973 EXPECT_UKM(UkmEntry::kVideoCodecName,
974 static_cast<int>(secondary_properties->video_codec));
975 EXPECT_UKM(UkmEntry::kAudioCodecProfileName,
976 static_cast<int64_t>(secondary_properties->audio_codec_profile));
977 EXPECT_UKM(UkmEntry::kVideoCodecProfileName,
978 secondary_properties->video_codec_profile);
979 EXPECT_UKM(UkmEntry::kHasAudioName, properties->has_audio);
980 EXPECT_UKM(UkmEntry::kHasVideoName, properties->has_video);
982 UkmEntry::kAudioEncryptionSchemeName,
983 static_cast<int64_t>(secondary_properties->audio_encryption_scheme));
985 UkmEntry::kVideoEncryptionSchemeName,
986 static_cast<int64_t>(secondary_properties->video_encryption_scheme));
987 EXPECT_UKM(UkmEntry::kIsEMEName, properties->is_eme);
988 EXPECT_UKM(UkmEntry::kIsMSEName, properties->is_mse);
989 EXPECT_UKM(UkmEntry::kMediaStreamTypeName,
990 static_cast<int64_t>(properties->media_stream_type));
991 EXPECT_UKM(UkmEntry::kLastPipelineStatusName, PIPELINE_ERROR_DECODE);
992 EXPECT_UKM(UkmEntry::kRebuffersCountName, 3);
993 EXPECT_UKM(UkmEntry::kCompletedRebuffersCountName, 2);
994 EXPECT_UKM(UkmEntry::kCompletedRebuffersDurationName,
995 kUnderflowDuration.InMilliseconds());
996 EXPECT_UKM(UkmEntry::kVideoFramesDecodedName, 10);
997 EXPECT_UKM(UkmEntry::kVideoFramesDroppedName, 2);
998 EXPECT_UKM(UkmEntry::kVideoNaturalWidthName,
999 secondary_properties->natural_size.width());
1000 EXPECT_UKM(UkmEntry::kVideoNaturalHeightName,
1001 secondary_properties->natural_size.height());
1002 EXPECT_UKM(UkmEntry::kAutoplayInitiatedName, true);
1006 TEST_F(WatchTimeRecorderTest, BasicUkmAudioVideoBackgroundMuted) {
1007 mojom::PlaybackPropertiesPtr properties = mojom::PlaybackProperties::New(
1008 true, true, true, true, false, false, false,
1009 mojom::MediaStreamType::kNone, RendererType::kRendererImpl);
1010 mojom::SecondaryPlaybackPropertiesPtr secondary_properties =
1011 CreateSecondaryProperties();
1012 Initialize(properties.Clone());
1013 wtr_->UpdateSecondaryProperties(secondary_properties.Clone());
1015 constexpr base::TimeDelta kWatchTime = base::Seconds(54);
1016 wtr_->RecordWatchTime(WatchTimeKey::kAudioVideoBackgroundAll, kWatchTime);
1018 base::RunLoop().RunUntilIdle();
1020 if (secondary_properties->audio_codec == AudioCodec::kAAC) {
1021 ExpectAacAudioCodecProfileHistogram(
1022 secondary_properties->audio_codec_profile);
1025 const auto& entries = test_recorder_->GetEntriesByName(UkmEntry::kEntryName);
1026 EXPECT_EQ(1u, entries.size());
1027 for (const auto* entry : entries) {
1028 test_recorder_->ExpectEntrySourceHasUrl(entry, GURL(kTestOrigin));
1030 EXPECT_UKM(UkmEntry::kWatchTimeName, kWatchTime.InMilliseconds());
1031 EXPECT_UKM(UkmEntry::kIsBackgroundName, properties->is_background);
1032 EXPECT_UKM(UkmEntry::kIsMutedName, properties->is_muted);
1033 EXPECT_UKM(UkmEntry::kAudioCodecName,
1034 static_cast<int>(secondary_properties->audio_codec));
1035 EXPECT_UKM(UkmEntry::kVideoCodecName,
1036 static_cast<int>(secondary_properties->video_codec));
1037 EXPECT_UKM(UkmEntry::kAudioCodecProfileName,
1038 static_cast<int64_t>(secondary_properties->audio_codec_profile));
1039 EXPECT_UKM(UkmEntry::kVideoCodecProfileName,
1040 secondary_properties->video_codec_profile);
1041 EXPECT_UKM(UkmEntry::kHasAudioName, properties->has_audio);
1042 EXPECT_UKM(UkmEntry::kHasVideoName, properties->has_video);
1044 UkmEntry::kAudioEncryptionSchemeName,
1045 static_cast<int64_t>(secondary_properties->audio_encryption_scheme));
1047 UkmEntry::kVideoEncryptionSchemeName,
1048 static_cast<int64_t>(secondary_properties->video_encryption_scheme));
1049 EXPECT_UKM(UkmEntry::kIsEMEName, properties->is_eme);
1050 EXPECT_UKM(UkmEntry::kIsMSEName, properties->is_mse);
1051 EXPECT_UKM(UkmEntry::kMediaStreamTypeName,
1052 static_cast<int64_t>(properties->media_stream_type));
1053 EXPECT_UKM(UkmEntry::kLastPipelineStatusName, PIPELINE_OK);
1054 EXPECT_UKM(UkmEntry::kRebuffersCountName, 0);
1055 EXPECT_UKM(UkmEntry::kCompletedRebuffersCountName, 0);
1056 EXPECT_UKM(UkmEntry::kCompletedRebuffersDurationName, 0);
1057 EXPECT_UKM(UkmEntry::kVideoNaturalWidthName,
1058 secondary_properties->natural_size.width());
1059 EXPECT_UKM(UkmEntry::kVideoNaturalHeightName,
1060 secondary_properties->natural_size.height());
1061 EXPECT_HAS_UKM(UkmEntry::kPlayerIDName);
1062 EXPECT_UKM(UkmEntry::kAudioDecoderNameName, 0);
1063 EXPECT_UKM(UkmEntry::kVideoDecoderNameName, 0);
1064 EXPECT_UKM(UkmEntry::kAutoplayInitiatedName, false);
1066 EXPECT_NO_UKM(UkmEntry::kDurationName);
1067 EXPECT_NO_UKM(UkmEntry::kMeanTimeBetweenRebuffersName);
1068 EXPECT_NO_UKM(UkmEntry::kWatchTime_ACName);
1069 EXPECT_NO_UKM(UkmEntry::kWatchTime_BatteryName);
1070 EXPECT_NO_UKM(UkmEntry::kWatchTime_NativeControlsOnName);
1071 EXPECT_NO_UKM(UkmEntry::kWatchTime_NativeControlsOffName);
1072 EXPECT_NO_UKM(UkmEntry::kWatchTime_DisplayFullscreenName);
1073 EXPECT_NO_UKM(UkmEntry::kWatchTime_DisplayInlineName);
1074 EXPECT_NO_UKM(UkmEntry::kWatchTime_DisplayPictureInPictureName);
1078 TEST_F(WatchTimeRecorderTest, BasicUkmAudioVideoDuration) {
1079 mojom::PlaybackPropertiesPtr properties = mojom::PlaybackProperties::New(
1080 true, true, false, false, false, false, false,
1081 mojom::MediaStreamType::kNone, RendererType::kRendererImpl);
1082 mojom::SecondaryPlaybackPropertiesPtr secondary_properties =
1083 CreateSecondaryProperties();
1084 Initialize(properties.Clone());
1085 wtr_->UpdateSecondaryProperties(secondary_properties.Clone());
1087 wtr_->OnDurationChanged(base::Seconds(12345));
1089 base::RunLoop().RunUntilIdle();
1091 if (secondary_properties->audio_codec == AudioCodec::kAAC) {
1092 ExpectAacAudioCodecProfileHistogram(
1093 secondary_properties->audio_codec_profile);
1096 const auto& entries = test_recorder_->GetEntriesByName(UkmEntry::kEntryName);
1097 EXPECT_EQ(1u, entries.size());
1098 for (const auto* entry : entries) {
1099 test_recorder_->ExpectEntrySourceHasUrl(entry, GURL(kTestOrigin));
1101 EXPECT_UKM(UkmEntry::kIsBackgroundName, properties->is_background);
1102 EXPECT_UKM(UkmEntry::kIsMutedName, properties->is_muted);
1103 EXPECT_UKM(UkmEntry::kAudioCodecName,
1104 static_cast<int>(secondary_properties->audio_codec));
1105 EXPECT_UKM(UkmEntry::kVideoCodecName,
1106 static_cast<int>(secondary_properties->video_codec));
1107 EXPECT_UKM(UkmEntry::kAudioCodecProfileName,
1108 static_cast<int64_t>(secondary_properties->audio_codec_profile));
1109 EXPECT_UKM(UkmEntry::kVideoCodecProfileName,
1110 secondary_properties->video_codec_profile);
1111 EXPECT_UKM(UkmEntry::kHasAudioName, properties->has_audio);
1112 EXPECT_UKM(UkmEntry::kHasVideoName, properties->has_video);
1114 UkmEntry::kAudioEncryptionSchemeName,
1115 static_cast<int64_t>(secondary_properties->audio_encryption_scheme));
1117 UkmEntry::kVideoEncryptionSchemeName,
1118 static_cast<int64_t>(secondary_properties->video_encryption_scheme));
1119 EXPECT_UKM(UkmEntry::kIsEMEName, properties->is_eme);
1120 EXPECT_UKM(UkmEntry::kIsMSEName, properties->is_mse);
1121 EXPECT_UKM(UkmEntry::kMediaStreamTypeName,
1122 static_cast<int64_t>(properties->media_stream_type));
1123 EXPECT_UKM(UkmEntry::kLastPipelineStatusName, PIPELINE_OK);
1124 EXPECT_UKM(UkmEntry::kRebuffersCountName, 0);
1125 EXPECT_UKM(UkmEntry::kCompletedRebuffersCountName, 0);
1126 EXPECT_UKM(UkmEntry::kCompletedRebuffersDurationName, 0);
1127 EXPECT_UKM(UkmEntry::kVideoNaturalWidthName,
1128 secondary_properties->natural_size.width());
1129 EXPECT_UKM(UkmEntry::kVideoNaturalHeightName,
1130 secondary_properties->natural_size.height());
1131 EXPECT_HAS_UKM(UkmEntry::kPlayerIDName);
1132 EXPECT_UKM(UkmEntry::kAudioDecoderNameName, 0);
1133 EXPECT_UKM(UkmEntry::kVideoDecoderNameName, 0);
1134 EXPECT_UKM(UkmEntry::kAutoplayInitiatedName, false);
1136 // Duration should be rounded to the most significant digit.
1137 EXPECT_UKM(UkmEntry::kDurationName, 10000000);
1139 EXPECT_NO_UKM(UkmEntry::kMeanTimeBetweenRebuffersName);
1140 EXPECT_NO_UKM(UkmEntry::kWatchTime_ACName);
1141 EXPECT_NO_UKM(UkmEntry::kWatchTime_BatteryName);
1142 EXPECT_NO_UKM(UkmEntry::kWatchTime_NativeControlsOnName);
1143 EXPECT_NO_UKM(UkmEntry::kWatchTime_NativeControlsOffName);
1144 EXPECT_NO_UKM(UkmEntry::kWatchTime_DisplayFullscreenName);
1145 EXPECT_NO_UKM(UkmEntry::kWatchTime_DisplayInlineName);
1146 EXPECT_NO_UKM(UkmEntry::kWatchTime_DisplayPictureInPictureName);
1150 TEST_F(WatchTimeRecorderTest, BasicUkmAudioVideoDurationInfinite) {
1151 mojom::PlaybackPropertiesPtr properties = mojom::PlaybackProperties::New(
1152 true, true, false, false, false, false, false,
1153 mojom::MediaStreamType::kNone, RendererType::kRendererImpl);
1154 mojom::SecondaryPlaybackPropertiesPtr secondary_properties =
1155 CreateSecondaryProperties();
1156 Initialize(properties.Clone());
1157 wtr_->UpdateSecondaryProperties(secondary_properties.Clone());
1159 wtr_->OnDurationChanged(kInfiniteDuration);
1161 base::RunLoop().RunUntilIdle();
1163 if (secondary_properties->audio_codec == AudioCodec::kAAC) {
1164 ExpectAacAudioCodecProfileHistogram(
1165 secondary_properties->audio_codec_profile);
1168 const auto& entries = test_recorder_->GetEntriesByName(UkmEntry::kEntryName);
1169 EXPECT_EQ(1u, entries.size());
1170 for (const auto* entry : entries) {
1171 test_recorder_->ExpectEntrySourceHasUrl(entry, GURL(kTestOrigin));
1173 EXPECT_UKM(UkmEntry::kIsBackgroundName, properties->is_background);
1174 EXPECT_UKM(UkmEntry::kIsMutedName, properties->is_muted);
1175 EXPECT_UKM(UkmEntry::kAudioCodecName,
1176 static_cast<int>(secondary_properties->audio_codec));
1177 EXPECT_UKM(UkmEntry::kVideoCodecName,
1178 static_cast<int>(secondary_properties->video_codec));
1179 EXPECT_UKM(UkmEntry::kAudioCodecProfileName,
1180 static_cast<int64_t>(secondary_properties->audio_codec_profile));
1181 EXPECT_UKM(UkmEntry::kVideoCodecProfileName,
1182 secondary_properties->video_codec_profile);
1183 EXPECT_UKM(UkmEntry::kHasAudioName, properties->has_audio);
1184 EXPECT_UKM(UkmEntry::kHasVideoName, properties->has_video);
1186 UkmEntry::kAudioEncryptionSchemeName,
1187 static_cast<int64_t>(secondary_properties->audio_encryption_scheme));
1189 UkmEntry::kVideoEncryptionSchemeName,
1190 static_cast<int64_t>(secondary_properties->video_encryption_scheme));
1191 EXPECT_UKM(UkmEntry::kIsEMEName, properties->is_eme);
1192 EXPECT_UKM(UkmEntry::kIsMSEName, properties->is_mse);
1193 EXPECT_UKM(UkmEntry::kMediaStreamTypeName,
1194 static_cast<int64_t>(properties->media_stream_type));
1195 EXPECT_UKM(UkmEntry::kLastPipelineStatusName, PIPELINE_OK);
1196 EXPECT_UKM(UkmEntry::kRebuffersCountName, 0);
1197 EXPECT_UKM(UkmEntry::kCompletedRebuffersCountName, 0);
1198 EXPECT_UKM(UkmEntry::kCompletedRebuffersDurationName, 0);
1199 EXPECT_UKM(UkmEntry::kVideoNaturalWidthName,
1200 secondary_properties->natural_size.width());
1201 EXPECT_UKM(UkmEntry::kVideoNaturalHeightName,
1202 secondary_properties->natural_size.height());
1203 EXPECT_HAS_UKM(UkmEntry::kPlayerIDName);
1204 EXPECT_UKM(UkmEntry::kAudioDecoderNameName, 0);
1205 EXPECT_UKM(UkmEntry::kVideoDecoderNameName, 0);
1206 EXPECT_UKM(UkmEntry::kAutoplayInitiatedName, false);
1208 // Duration should be unrecorded when infinite.
1209 EXPECT_NO_UKM(UkmEntry::kDurationName);
1210 EXPECT_NO_UKM(UkmEntry::kWatchTimeName);
1211 EXPECT_NO_UKM(UkmEntry::kMeanTimeBetweenRebuffersName);
1212 EXPECT_NO_UKM(UkmEntry::kWatchTime_ACName);
1213 EXPECT_NO_UKM(UkmEntry::kWatchTime_BatteryName);
1214 EXPECT_NO_UKM(UkmEntry::kWatchTime_NativeControlsOnName);
1215 EXPECT_NO_UKM(UkmEntry::kWatchTime_NativeControlsOffName);
1216 EXPECT_NO_UKM(UkmEntry::kWatchTime_DisplayFullscreenName);
1217 EXPECT_NO_UKM(UkmEntry::kWatchTime_DisplayInlineName);
1218 EXPECT_NO_UKM(UkmEntry::kWatchTime_DisplayPictureInPictureName);
1222 TEST_F(WatchTimeRecorderTest, BasicUkmMediaStreamType) {
1223 std::vector<mojom::MediaStreamType> media_stream_types{
1224 mojom::MediaStreamType::kLocalElementCapture,
1225 mojom::MediaStreamType::kLocalDeviceCapture,
1226 mojom::MediaStreamType::kLocalTabCapture,
1227 mojom::MediaStreamType::kLocalDesktopCapture,
1228 mojom::MediaStreamType::kLocalDisplayCapture,
1229 mojom::MediaStreamType::kRemote,
1230 mojom::MediaStreamType::kNone,
1233 for (const auto& media_stream_type : media_stream_types) {
1234 mojom::PlaybackPropertiesPtr properties = mojom::PlaybackProperties::New(
1235 true, true, false, false, false, false, false, media_stream_type,
1236 RendererType::kRendererImpl);
1237 Initialize(properties.Clone());
1238 wtr_->UpdateSecondaryProperties(CreateSecondaryProperties());
1240 constexpr base::TimeDelta kWatchTime = base::Seconds(1);
1241 wtr_->RecordWatchTime(WatchTimeKey::kAudioVideoAll, kWatchTime);
1243 base::RunLoop().RunUntilIdle();
1245 const auto& entries =
1246 test_recorder_->GetEntriesByName(UkmEntry::kEntryName);
1247 ASSERT_EQ(1u, entries.size());
1249 // Check that the media stream type is set correctly.
1250 for (const auto* entry : entries) {
1251 EXPECT_UKM(UkmEntry::kMediaStreamTypeName,
1252 static_cast<int64_t>(media_stream_type));
1254 ResetMetricRecorders();
1258 // Might happen due to timing issues, so ensure no crashes.
1259 TEST_F(WatchTimeRecorderTest, NoSecondaryProperties) {
1260 mojom::PlaybackPropertiesPtr properties = mojom::PlaybackProperties::New(
1261 true, true, false, false, true, true, false,
1262 mojom::MediaStreamType::kNone, RendererType::kRendererImpl);
1263 Initialize(properties.Clone());
1265 constexpr base::TimeDelta kWatchTime = base::Seconds(54);
1266 wtr_->RecordWatchTime(WatchTimeKey::kAudioVideoAll, kWatchTime);
1268 base::RunLoop().RunUntilIdle();
1269 const auto& entries = test_recorder_->GetEntriesByName(UkmEntry::kEntryName);
1270 EXPECT_EQ(0u, entries.size());
1273 TEST_F(WatchTimeRecorderTest, SingleSecondaryPropertiesUnknownToKnown) {
1274 mojom::PlaybackPropertiesPtr properties = mojom::PlaybackProperties::New(
1275 true, true, false, false, true, true, false,
1276 mojom::MediaStreamType::kNone, RendererType::kRendererImpl);
1277 mojom::SecondaryPlaybackPropertiesPtr secondary_properties1 =
1278 mojom::SecondaryPlaybackProperties::New(
1279 AudioCodec::kUnknown, VideoCodec::kUnknown,
1280 AudioCodecProfile::kUnknown, VIDEO_CODEC_PROFILE_UNKNOWN,
1281 AudioDecoderType::kUnknown, VideoDecoderType::kUnknown,
1282 EncryptionScheme::kUnencrypted, EncryptionScheme::kUnencrypted,
1283 gfx::Size(800, 600));
1284 Initialize(properties.Clone());
1285 wtr_->UpdateSecondaryProperties(secondary_properties1.Clone());
1287 constexpr base::TimeDelta kWatchTime = base::Seconds(54);
1288 wtr_->RecordWatchTime(WatchTimeKey::kAudioVideoAll, kWatchTime);
1290 mojom::SecondaryPlaybackPropertiesPtr secondary_properties2 =
1291 mojom::SecondaryPlaybackProperties::New(
1292 AudioCodec::kAAC, VideoCodec::kH264, AudioCodecProfile::kXHE_AAC,
1293 H264PROFILE_MAIN, AudioDecoderType::kFFmpeg,
1294 VideoDecoderType::kFFmpeg, EncryptionScheme::kUnencrypted,
1295 EncryptionScheme::kUnencrypted, gfx::Size(800, 600));
1296 wtr_->UpdateSecondaryProperties(secondary_properties2.Clone());
1299 base::RunLoop().RunUntilIdle();
1301 // Since we only transitioned unknown values to known values, there should be
1302 // only a single UKM entry.
1303 const auto& entries = test_recorder_->GetEntriesByName(UkmEntry::kEntryName);
1304 EXPECT_EQ(1u, entries.size());
1305 for (const auto* entry : entries) {
1306 test_recorder_->ExpectEntrySourceHasUrl(entry, GURL(kTestOrigin));
1307 EXPECT_UKM(UkmEntry::kIsBackgroundName, properties->is_background);
1308 EXPECT_UKM(UkmEntry::kIsMutedName, properties->is_muted);
1309 EXPECT_UKM(UkmEntry::kHasAudioName, properties->has_audio);
1310 EXPECT_UKM(UkmEntry::kHasVideoName, properties->has_video);
1311 EXPECT_UKM(UkmEntry::kIsEMEName, properties->is_eme);
1312 EXPECT_UKM(UkmEntry::kIsMSEName, properties->is_mse);
1313 EXPECT_UKM(UkmEntry::kMediaStreamTypeName,
1314 static_cast<int64_t>(properties->media_stream_type));
1315 EXPECT_UKM(UkmEntry::kAutoplayInitiatedName, false);
1316 EXPECT_UKM(UkmEntry::kLastPipelineStatusName, PIPELINE_OK);
1317 EXPECT_HAS_UKM(UkmEntry::kPlayerIDName);
1318 EXPECT_UKM(UkmEntry::kWatchTimeName, kWatchTime.InMilliseconds());
1319 EXPECT_UKM(UkmEntry::kAudioDecoderNameName, 1);
1320 EXPECT_UKM(UkmEntry::kVideoDecoderNameName, 2);
1321 EXPECT_UKM(UkmEntry::kRebuffersCountName, 0);
1322 EXPECT_UKM(UkmEntry::kCompletedRebuffersCountName, 0);
1323 EXPECT_UKM(UkmEntry::kCompletedRebuffersDurationName, 0);
1324 EXPECT_UKM(UkmEntry::kAudioCodecName,
1325 static_cast<int>(secondary_properties2->audio_codec));
1326 EXPECT_UKM(UkmEntry::kVideoCodecName,
1327 static_cast<int>(secondary_properties2->video_codec));
1329 UkmEntry::kAudioCodecProfileName,
1330 static_cast<int64_t>(secondary_properties2->audio_codec_profile));
1331 EXPECT_UKM(UkmEntry::kVideoCodecProfileName,
1332 secondary_properties2->video_codec_profile);
1334 UkmEntry::kAudioEncryptionSchemeName,
1335 static_cast<int64_t>(secondary_properties2->audio_encryption_scheme));
1337 UkmEntry::kVideoEncryptionSchemeName,
1338 static_cast<int64_t>(secondary_properties2->video_encryption_scheme));
1339 EXPECT_UKM(UkmEntry::kVideoNaturalWidthName,
1340 secondary_properties2->natural_size.width());
1341 EXPECT_UKM(UkmEntry::kVideoNaturalHeightName,
1342 secondary_properties2->natural_size.height());
1343 EXPECT_NO_UKM(UkmEntry::kDurationName);
1347 TEST_F(WatchTimeRecorderTest, MultipleSecondaryPropertiesNoFinalize) {
1348 mojom::PlaybackPropertiesPtr properties = mojom::PlaybackProperties::New(
1349 true, true, false, false, true, true, false,
1350 mojom::MediaStreamType::kNone, RendererType::kRendererImpl);
1351 mojom::SecondaryPlaybackPropertiesPtr secondary_properties1 =
1352 mojom::SecondaryPlaybackProperties::New(
1353 AudioCodec::kOpus, VideoCodec::kVP9, AudioCodecProfile::kUnknown,
1354 VP9PROFILE_PROFILE0, AudioDecoderType::kMojo, VideoDecoderType::kMojo,
1355 EncryptionScheme::kUnencrypted, EncryptionScheme::kUnencrypted,
1356 gfx::Size(400, 300));
1357 Initialize(properties.Clone());
1358 wtr_->UpdateSecondaryProperties(secondary_properties1.Clone());
1360 constexpr base::TimeDelta kUnderflowDuration = base::Milliseconds(250);
1361 constexpr base::TimeDelta kWatchTime1 = base::Seconds(54);
1362 const int kUnderflowCount1 = 2;
1363 wtr_->RecordWatchTime(WatchTimeKey::kAudioVideoAll, kWatchTime1);
1364 wtr_->UpdateUnderflowCount(kUnderflowCount1);
1365 wtr_->UpdateUnderflowDuration(kUnderflowCount1, kUnderflowDuration);
1367 constexpr int kDecodedFrameCount1 = 10;
1368 constexpr int kDroppedFrameCount1 = 2;
1369 wtr_->UpdateVideoDecodeStats(kDecodedFrameCount1, kDroppedFrameCount1);
1371 mojom::SecondaryPlaybackPropertiesPtr secondary_properties2 =
1372 mojom::SecondaryPlaybackProperties::New(
1373 AudioCodec::kAAC, VideoCodec::kH264, AudioCodecProfile::kUnknown,
1374 H264PROFILE_MAIN, AudioDecoderType::kFFmpeg,
1375 VideoDecoderType::kFFmpeg, EncryptionScheme::kCenc,
1376 EncryptionScheme::kCenc, gfx::Size(800, 600));
1377 wtr_->UpdateSecondaryProperties(secondary_properties2.Clone());
1379 constexpr base::TimeDelta kWatchTime2 = base::Seconds(25);
1380 const int kUnderflowCount2 = 3;
1382 // Watch time and underflow counts continue to accumulate during property
1383 // changes, so we report the sum here instead of just kWatchTime2.
1384 wtr_->RecordWatchTime(WatchTimeKey::kAudioVideoAll,
1385 kWatchTime1 + kWatchTime2);
1386 wtr_->UpdateUnderflowCount(kUnderflowCount1 + kUnderflowCount2);
1387 wtr_->OnError(PIPELINE_ERROR_DECODE);
1388 wtr_->OnDurationChanged(base::Seconds(5125));
1390 constexpr int kDecodedFrameCount2 = 20;
1391 constexpr int kDroppedFrameCount2 = 10;
1392 wtr_->UpdateVideoDecodeStats(kDecodedFrameCount1 + kDecodedFrameCount2,
1393 kDroppedFrameCount1 + kDroppedFrameCount2);
1396 base::RunLoop().RunUntilIdle();
1398 // All records should have the following:
1399 const auto& entries = test_recorder_->GetEntriesByName(UkmEntry::kEntryName);
1400 EXPECT_EQ(2u, entries.size());
1401 for (const auto* entry : entries) {
1402 test_recorder_->ExpectEntrySourceHasUrl(entry, GURL(kTestOrigin));
1403 EXPECT_UKM(UkmEntry::kIsBackgroundName, properties->is_background);
1404 EXPECT_UKM(UkmEntry::kIsMutedName, properties->is_muted);
1405 EXPECT_UKM(UkmEntry::kHasAudioName, properties->has_audio);
1406 EXPECT_UKM(UkmEntry::kHasVideoName, properties->has_video);
1407 EXPECT_UKM(UkmEntry::kIsEMEName, properties->is_eme);
1408 EXPECT_UKM(UkmEntry::kIsMSEName, properties->is_mse);
1409 EXPECT_UKM(UkmEntry::kMediaStreamTypeName,
1410 static_cast<int64_t>(properties->media_stream_type));
1411 EXPECT_UKM(UkmEntry::kAutoplayInitiatedName, false);
1412 EXPECT_UKM(UkmEntry::kDurationName, 5000000);
1413 EXPECT_HAS_UKM(UkmEntry::kPlayerIDName);
1415 // All records inherit the final pipeline status code.
1416 EXPECT_UKM(UkmEntry::kLastPipelineStatusName, PIPELINE_ERROR_DECODE);
1419 // The first record should have...
1420 auto* entry = entries[0];
1421 EXPECT_UKM(UkmEntry::kWatchTimeName, kWatchTime1.InMilliseconds());
1422 EXPECT_UKM(UkmEntry::kMeanTimeBetweenRebuffersName,
1423 kWatchTime1.InMilliseconds() / kUnderflowCount1);
1424 EXPECT_UKM(UkmEntry::kAudioDecoderNameName, 2);
1425 EXPECT_UKM(UkmEntry::kVideoDecoderNameName, 5);
1426 EXPECT_UKM(UkmEntry::kRebuffersCountName, kUnderflowCount1);
1427 EXPECT_UKM(UkmEntry::kCompletedRebuffersCountName, kUnderflowCount1);
1428 EXPECT_UKM(UkmEntry::kCompletedRebuffersDurationName,
1429 kUnderflowDuration.InMilliseconds());
1430 EXPECT_UKM(UkmEntry::kVideoFramesDecodedName, kDecodedFrameCount1);
1431 EXPECT_UKM(UkmEntry::kVideoFramesDroppedName, kDroppedFrameCount1);
1432 EXPECT_UKM(UkmEntry::kAudioCodecName,
1433 static_cast<int>(secondary_properties1->audio_codec));
1434 EXPECT_UKM(UkmEntry::kVideoCodecName,
1435 static_cast<int>(secondary_properties1->video_codec));
1436 EXPECT_UKM(UkmEntry::kAudioCodecProfileName,
1437 static_cast<int64_t>(secondary_properties1->audio_codec_profile));
1438 EXPECT_UKM(UkmEntry::kVideoCodecProfileName,
1439 secondary_properties1->video_codec_profile);
1441 UkmEntry::kAudioEncryptionSchemeName,
1442 static_cast<int64_t>(secondary_properties1->audio_encryption_scheme));
1444 UkmEntry::kVideoEncryptionSchemeName,
1445 static_cast<int64_t>(secondary_properties1->video_encryption_scheme));
1446 EXPECT_UKM(UkmEntry::kVideoNaturalWidthName,
1447 secondary_properties1->natural_size.width());
1448 EXPECT_UKM(UkmEntry::kVideoNaturalHeightName,
1449 secondary_properties1->natural_size.height());
1451 // The second record should have...
1453 EXPECT_UKM(UkmEntry::kWatchTimeName, kWatchTime2.InMilliseconds());
1454 EXPECT_UKM(UkmEntry::kMeanTimeBetweenRebuffersName,
1455 kWatchTime2.InMilliseconds() / kUnderflowCount2);
1456 EXPECT_UKM(UkmEntry::kAudioDecoderNameName, 1);
1457 EXPECT_UKM(UkmEntry::kVideoDecoderNameName, 2);
1458 EXPECT_UKM(UkmEntry::kRebuffersCountName, kUnderflowCount2);
1459 EXPECT_UKM(UkmEntry::kCompletedRebuffersCountName, 0);
1460 EXPECT_UKM(UkmEntry::kVideoFramesDecodedName, kDecodedFrameCount2);
1461 EXPECT_UKM(UkmEntry::kVideoFramesDroppedName, kDroppedFrameCount2);
1463 EXPECT_UKM(UkmEntry::kCompletedRebuffersDurationName, 0);
1464 EXPECT_UKM(UkmEntry::kAudioCodecName,
1465 static_cast<int>(secondary_properties2->audio_codec));
1466 EXPECT_UKM(UkmEntry::kVideoCodecName,
1467 static_cast<int>(secondary_properties2->video_codec));
1468 EXPECT_UKM(UkmEntry::kAudioCodecProfileName,
1469 static_cast<int64_t>(secondary_properties2->audio_codec_profile));
1470 EXPECT_UKM(UkmEntry::kVideoCodecProfileName,
1471 secondary_properties2->video_codec_profile);
1473 UkmEntry::kAudioEncryptionSchemeName,
1474 static_cast<int64_t>(secondary_properties2->audio_encryption_scheme));
1476 UkmEntry::kVideoEncryptionSchemeName,
1477 static_cast<int64_t>(secondary_properties2->video_encryption_scheme));
1478 EXPECT_UKM(UkmEntry::kVideoNaturalWidthName,
1479 secondary_properties2->natural_size.width());
1480 EXPECT_UKM(UkmEntry::kVideoNaturalHeightName,
1481 secondary_properties2->natural_size.height());
1484 TEST_F(WatchTimeRecorderTest, MultipleSecondaryPropertiesNoFinalizeNo2ndWT) {
1485 mojom::PlaybackPropertiesPtr properties = mojom::PlaybackProperties::New(
1486 true, true, false, false, true, true, false,
1487 mojom::MediaStreamType::kNone, RendererType::kRendererImpl);
1488 mojom::SecondaryPlaybackPropertiesPtr secondary_properties1 =
1489 mojom::SecondaryPlaybackProperties::New(
1490 AudioCodec::kOpus, VideoCodec::kVP9, AudioCodecProfile::kUnknown,
1491 VP9PROFILE_PROFILE0, AudioDecoderType::kMojo, VideoDecoderType::kMojo,
1492 EncryptionScheme::kUnencrypted, EncryptionScheme::kUnencrypted,
1493 gfx::Size(400, 300));
1494 Initialize(properties.Clone());
1495 wtr_->UpdateSecondaryProperties(secondary_properties1.Clone());
1497 constexpr base::TimeDelta kUnderflowDuration = base::Milliseconds(250);
1498 constexpr base::TimeDelta kWatchTime1 = base::Seconds(54);
1499 const int kUnderflowCount1 = 2;
1500 wtr_->RecordWatchTime(WatchTimeKey::kAudioVideoAll, kWatchTime1);
1501 wtr_->UpdateUnderflowCount(kUnderflowCount1);
1502 wtr_->UpdateUnderflowDuration(kUnderflowCount1, kUnderflowDuration);
1504 constexpr int kDecodedFrameCount1 = 10;
1505 constexpr int kDroppedFrameCount1 = 2;
1506 wtr_->UpdateVideoDecodeStats(kDecodedFrameCount1, kDroppedFrameCount1);
1508 mojom::SecondaryPlaybackPropertiesPtr secondary_properties2 =
1509 mojom::SecondaryPlaybackProperties::New(
1510 AudioCodec::kAAC, VideoCodec::kH264, AudioCodecProfile::kXHE_AAC,
1511 H264PROFILE_MAIN, AudioDecoderType::kFFmpeg,
1512 VideoDecoderType::kFFmpeg, EncryptionScheme::kUnencrypted,
1513 EncryptionScheme::kUnencrypted, gfx::Size(800, 600));
1514 wtr_->UpdateSecondaryProperties(secondary_properties2.Clone());
1516 // Don't record any watch time to the new record, it should report zero watch
1517 // time upon destruction. This ensures there's always a Finalize to prevent
1518 // UKM was receiving negative values from the previous unfinalized record.
1520 base::RunLoop().RunUntilIdle();
1522 // All records should have the following:
1523 const auto& entries = test_recorder_->GetEntriesByName(UkmEntry::kEntryName);
1524 EXPECT_EQ(2u, entries.size());
1525 for (const auto* entry : entries) {
1526 test_recorder_->ExpectEntrySourceHasUrl(entry, GURL(kTestOrigin));
1527 EXPECT_UKM(UkmEntry::kIsBackgroundName, properties->is_background);
1528 EXPECT_UKM(UkmEntry::kIsMutedName, properties->is_muted);
1529 EXPECT_UKM(UkmEntry::kHasAudioName, properties->has_audio);
1530 EXPECT_UKM(UkmEntry::kHasVideoName, properties->has_video);
1531 EXPECT_UKM(UkmEntry::kIsEMEName, properties->is_eme);
1532 EXPECT_UKM(UkmEntry::kIsMSEName, properties->is_mse);
1533 EXPECT_UKM(UkmEntry::kMediaStreamTypeName,
1534 static_cast<int64_t>(properties->media_stream_type));
1535 EXPECT_UKM(UkmEntry::kAutoplayInitiatedName, false);
1536 EXPECT_UKM(UkmEntry::kLastPipelineStatusName, PIPELINE_OK);
1537 EXPECT_HAS_UKM(UkmEntry::kPlayerIDName);
1538 EXPECT_NO_UKM(UkmEntry::kDurationName);
1541 // The first record should have...
1542 auto* entry = entries[0];
1543 EXPECT_UKM(UkmEntry::kWatchTimeName, kWatchTime1.InMilliseconds());
1544 EXPECT_UKM(UkmEntry::kMeanTimeBetweenRebuffersName,
1545 kWatchTime1.InMilliseconds() / kUnderflowCount1);
1546 EXPECT_UKM(UkmEntry::kAudioDecoderNameName, 2);
1547 EXPECT_UKM(UkmEntry::kVideoDecoderNameName, 5);
1548 EXPECT_UKM(UkmEntry::kRebuffersCountName, kUnderflowCount1);
1549 EXPECT_UKM(UkmEntry::kCompletedRebuffersCountName, kUnderflowCount1);
1550 EXPECT_UKM(UkmEntry::kCompletedRebuffersDurationName,
1551 kUnderflowDuration.InMilliseconds());
1552 EXPECT_UKM(UkmEntry::kVideoFramesDecodedName, kDecodedFrameCount1);
1553 EXPECT_UKM(UkmEntry::kVideoFramesDroppedName, kDroppedFrameCount1);
1554 EXPECT_UKM(UkmEntry::kAudioCodecName,
1555 static_cast<int>(secondary_properties1->audio_codec));
1556 EXPECT_UKM(UkmEntry::kVideoCodecName,
1557 static_cast<int>(secondary_properties1->video_codec));
1558 EXPECT_UKM(UkmEntry::kAudioCodecProfileName,
1559 static_cast<int64_t>(secondary_properties1->audio_codec_profile));
1560 EXPECT_UKM(UkmEntry::kVideoCodecProfileName,
1561 secondary_properties1->video_codec_profile);
1563 UkmEntry::kAudioEncryptionSchemeName,
1564 static_cast<int64_t>(secondary_properties1->audio_encryption_scheme));
1566 UkmEntry::kVideoEncryptionSchemeName,
1567 static_cast<int64_t>(secondary_properties1->video_encryption_scheme));
1568 EXPECT_UKM(UkmEntry::kVideoNaturalWidthName,
1569 secondary_properties1->natural_size.width());
1570 EXPECT_UKM(UkmEntry::kVideoNaturalHeightName,
1571 secondary_properties1->natural_size.height());
1573 // The second record should have...
1575 EXPECT_UKM(UkmEntry::kWatchTimeName, 0);
1576 EXPECT_UKM(UkmEntry::kAudioDecoderNameName, 1);
1577 EXPECT_UKM(UkmEntry::kVideoDecoderNameName, 2);
1578 EXPECT_UKM(UkmEntry::kRebuffersCountName, 0);
1579 EXPECT_UKM(UkmEntry::kCompletedRebuffersCountName, 0);
1580 EXPECT_UKM(UkmEntry::kCompletedRebuffersDurationName, 0);
1581 EXPECT_UKM(UkmEntry::kVideoFramesDecodedName, 0);
1582 EXPECT_UKM(UkmEntry::kVideoFramesDroppedName, 0);
1583 EXPECT_UKM(UkmEntry::kAudioCodecName,
1584 static_cast<int>(secondary_properties2->audio_codec));
1585 EXPECT_UKM(UkmEntry::kVideoCodecName,
1586 static_cast<int>(secondary_properties2->video_codec));
1587 EXPECT_UKM(UkmEntry::kAudioCodecProfileName,
1588 static_cast<int64_t>(secondary_properties2->audio_codec_profile));
1589 EXPECT_UKM(UkmEntry::kVideoCodecProfileName,
1590 secondary_properties2->video_codec_profile);
1592 UkmEntry::kAudioEncryptionSchemeName,
1593 static_cast<int64_t>(secondary_properties2->audio_encryption_scheme));
1595 UkmEntry::kVideoEncryptionSchemeName,
1596 static_cast<int64_t>(secondary_properties2->video_encryption_scheme));
1597 EXPECT_UKM(UkmEntry::kVideoNaturalWidthName,
1598 secondary_properties2->natural_size.width());
1599 EXPECT_UKM(UkmEntry::kVideoNaturalHeightName,
1600 secondary_properties2->natural_size.height());
1603 TEST_F(WatchTimeRecorderTest, MultipleSecondaryPropertiesWithFinalize) {
1604 mojom::PlaybackPropertiesPtr properties = mojom::PlaybackProperties::New(
1605 true, true, false, false, true, true, false,
1606 mojom::MediaStreamType::kNone, RendererType::kRendererImpl);
1607 mojom::SecondaryPlaybackPropertiesPtr secondary_properties1 =
1608 mojom::SecondaryPlaybackProperties::New(
1609 AudioCodec::kOpus, VideoCodec::kVP9, AudioCodecProfile::kUnknown,
1610 VP9PROFILE_PROFILE0, AudioDecoderType::kMojo, VideoDecoderType::kMojo,
1611 EncryptionScheme::kCbcs, EncryptionScheme::kCbcs,
1612 gfx::Size(400, 300));
1613 Initialize(properties.Clone());
1614 wtr_->UpdateSecondaryProperties(secondary_properties1.Clone());
1616 constexpr base::TimeDelta kUnderflowDuration = base::Milliseconds(250);
1617 constexpr base::TimeDelta kWatchTime1 = base::Seconds(54);
1618 const int kUnderflowCount1 = 2;
1619 wtr_->RecordWatchTime(WatchTimeKey::kAudioVideoAll, kWatchTime1);
1620 wtr_->UpdateUnderflowCount(kUnderflowCount1);
1621 wtr_->UpdateUnderflowDuration(kUnderflowCount1, kUnderflowDuration);
1623 constexpr int kDecodedFrameCount1 = 10;
1624 constexpr int kDroppedFrameCount1 = 2;
1625 wtr_->UpdateVideoDecodeStats(kDecodedFrameCount1, kDroppedFrameCount1);
1627 // Force a finalize here so that the there is no unfinalized watch time at the
1628 // time of the secondary property update.
1629 wtr_->FinalizeWatchTime({});
1631 mojom::SecondaryPlaybackPropertiesPtr secondary_properties2 =
1632 mojom::SecondaryPlaybackProperties::New(
1633 AudioCodec::kAAC, VideoCodec::kH264, AudioCodecProfile::kXHE_AAC,
1634 H264PROFILE_MAIN, AudioDecoderType::kFFmpeg,
1635 VideoDecoderType::kFFmpeg, EncryptionScheme::kUnencrypted,
1636 EncryptionScheme::kUnencrypted, gfx::Size(800, 600));
1637 wtr_->UpdateSecondaryProperties(secondary_properties2.Clone());
1639 constexpr base::TimeDelta kWatchTime2 = base::Seconds(25);
1640 const int kUnderflowCount2 = 3;
1642 wtr_->RecordWatchTime(WatchTimeKey::kAudioVideoAll, kWatchTime2);
1643 wtr_->UpdateUnderflowCount(kUnderflowCount2);
1644 wtr_->OnError(PIPELINE_ERROR_DECODE);
1647 base::RunLoop().RunUntilIdle();
1649 // All records should have the following:
1650 const auto& entries = test_recorder_->GetEntriesByName(UkmEntry::kEntryName);
1651 EXPECT_EQ(2u, entries.size());
1652 for (const auto* entry : entries) {
1653 test_recorder_->ExpectEntrySourceHasUrl(entry, GURL(kTestOrigin));
1654 EXPECT_UKM(UkmEntry::kIsBackgroundName, properties->is_background);
1655 EXPECT_UKM(UkmEntry::kIsMutedName, properties->is_muted);
1656 EXPECT_UKM(UkmEntry::kHasAudioName, properties->has_audio);
1657 EXPECT_UKM(UkmEntry::kHasVideoName, properties->has_video);
1658 EXPECT_UKM(UkmEntry::kIsEMEName, properties->is_eme);
1659 EXPECT_UKM(UkmEntry::kIsMSEName, properties->is_mse);
1660 EXPECT_UKM(UkmEntry::kMediaStreamTypeName,
1661 static_cast<int64_t>(properties->media_stream_type));
1662 EXPECT_UKM(UkmEntry::kAutoplayInitiatedName, false);
1663 EXPECT_HAS_UKM(UkmEntry::kPlayerIDName);
1664 EXPECT_NO_UKM(UkmEntry::kDurationName);
1666 // All records inherit the final pipeline status code.
1667 EXPECT_UKM(UkmEntry::kLastPipelineStatusName, PIPELINE_ERROR_DECODE);
1670 // The first record should have...
1671 auto* entry = entries[0];
1672 EXPECT_UKM(UkmEntry::kWatchTimeName, kWatchTime1.InMilliseconds());
1673 EXPECT_UKM(UkmEntry::kMeanTimeBetweenRebuffersName,
1674 kWatchTime1.InMilliseconds() / kUnderflowCount1);
1675 EXPECT_UKM(UkmEntry::kAudioDecoderNameName, 2);
1676 EXPECT_UKM(UkmEntry::kVideoDecoderNameName, 5);
1677 EXPECT_UKM(UkmEntry::kRebuffersCountName, kUnderflowCount1);
1678 EXPECT_UKM(UkmEntry::kCompletedRebuffersCountName, kUnderflowCount1);
1679 EXPECT_UKM(UkmEntry::kCompletedRebuffersDurationName,
1680 kUnderflowDuration.InMilliseconds());
1681 EXPECT_UKM(UkmEntry::kVideoFramesDecodedName, kDecodedFrameCount1);
1682 EXPECT_UKM(UkmEntry::kVideoFramesDroppedName, kDroppedFrameCount1);
1683 EXPECT_UKM(UkmEntry::kAudioCodecName,
1684 static_cast<int>(secondary_properties1->audio_codec));
1685 EXPECT_UKM(UkmEntry::kVideoCodecName,
1686 static_cast<int>(secondary_properties1->video_codec));
1687 EXPECT_UKM(UkmEntry::kAudioCodecProfileName,
1688 static_cast<int64_t>(secondary_properties1->audio_codec_profile));
1689 EXPECT_UKM(UkmEntry::kVideoCodecProfileName,
1690 secondary_properties1->video_codec_profile);
1692 UkmEntry::kAudioEncryptionSchemeName,
1693 static_cast<int64_t>(secondary_properties1->audio_encryption_scheme));
1695 UkmEntry::kVideoEncryptionSchemeName,
1696 static_cast<int64_t>(secondary_properties1->video_encryption_scheme));
1697 EXPECT_UKM(UkmEntry::kVideoNaturalWidthName,
1698 secondary_properties1->natural_size.width());
1699 EXPECT_UKM(UkmEntry::kVideoNaturalHeightName,
1700 secondary_properties1->natural_size.height());
1702 // The second record should have...
1704 EXPECT_UKM(UkmEntry::kWatchTimeName, kWatchTime2.InMilliseconds());
1705 EXPECT_UKM(UkmEntry::kMeanTimeBetweenRebuffersName,
1706 kWatchTime2.InMilliseconds() / kUnderflowCount2);
1707 EXPECT_UKM(UkmEntry::kAudioDecoderNameName, 1);
1708 EXPECT_UKM(UkmEntry::kVideoDecoderNameName, 2);
1709 EXPECT_UKM(UkmEntry::kRebuffersCountName, kUnderflowCount2);
1710 EXPECT_UKM(UkmEntry::kCompletedRebuffersCountName, 0);
1711 EXPECT_UKM(UkmEntry::kCompletedRebuffersDurationName, 0);
1712 EXPECT_UKM(UkmEntry::kVideoFramesDecodedName, 0);
1713 EXPECT_UKM(UkmEntry::kVideoFramesDroppedName, 0);
1714 EXPECT_UKM(UkmEntry::kAudioCodecName,
1715 static_cast<int>(secondary_properties2->audio_codec));
1716 EXPECT_UKM(UkmEntry::kVideoCodecName,
1717 static_cast<int>(secondary_properties2->video_codec));
1718 EXPECT_UKM(UkmEntry::kAudioCodecProfileName,
1719 static_cast<int64_t>(secondary_properties2->audio_codec_profile));
1720 EXPECT_UKM(UkmEntry::kVideoCodecProfileName,
1721 secondary_properties2->video_codec_profile);
1723 UkmEntry::kAudioEncryptionSchemeName,
1724 static_cast<int64_t>(secondary_properties2->audio_encryption_scheme));
1726 UkmEntry::kVideoEncryptionSchemeName,
1727 static_cast<int64_t>(secondary_properties2->video_encryption_scheme));
1728 EXPECT_UKM(UkmEntry::kVideoNaturalWidthName,
1729 secondary_properties2->natural_size.width());
1730 EXPECT_UKM(UkmEntry::kVideoNaturalHeightName,
1731 secondary_properties2->natural_size.height());
1734 TEST_F(WatchTimeRecorderTest, MultipleSecondaryPropertiesRebufferCarryover) {
1735 mojom::PlaybackPropertiesPtr properties = mojom::PlaybackProperties::New(
1736 true, true, false, false, true, true, false,
1737 mojom::MediaStreamType::kNone, RendererType::kRendererImpl);
1738 mojom::SecondaryPlaybackPropertiesPtr secondary_properties1 =
1739 mojom::SecondaryPlaybackProperties::New(
1740 AudioCodec::kOpus, VideoCodec::kVP9, AudioCodecProfile::kUnknown,
1741 VP9PROFILE_PROFILE0, AudioDecoderType::kMojo, VideoDecoderType::kMojo,
1742 EncryptionScheme::kCbcs, EncryptionScheme::kCbcs,
1743 gfx::Size(400, 300));
1744 Initialize(properties.Clone());
1745 wtr_->UpdateSecondaryProperties(secondary_properties1.Clone());
1747 constexpr base::TimeDelta kUnderflowDuration = base::Milliseconds(250);
1748 constexpr base::TimeDelta kWatchTime1 = base::Seconds(54);
1749 const int kUnderflowCount1 = 2;
1750 wtr_->RecordWatchTime(WatchTimeKey::kAudioVideoAll, kWatchTime1);
1751 wtr_->UpdateUnderflowCount(kUnderflowCount1);
1753 // Complete all but one of the rebuffers in this update.
1754 wtr_->UpdateUnderflowDuration(kUnderflowCount1 - 1, kUnderflowDuration);
1756 mojom::SecondaryPlaybackPropertiesPtr secondary_properties2 =
1757 mojom::SecondaryPlaybackProperties::New(
1758 AudioCodec::kAAC, VideoCodec::kH264, AudioCodecProfile::kXHE_AAC,
1759 H264PROFILE_MAIN, AudioDecoderType::kFFmpeg,
1760 VideoDecoderType::kFFmpeg, EncryptionScheme::kUnencrypted,
1761 EncryptionScheme::kUnencrypted, gfx::Size(800, 600));
1762 wtr_->UpdateSecondaryProperties(secondary_properties2.Clone());
1764 constexpr base::TimeDelta kWatchTime2 = base::Seconds(25);
1765 const int kUnderflowCount2 = 3;
1767 // Watch time and underflow counts continue to accumulate during property
1768 // changes, so we report the sum here instead of just kWatchTime2.
1769 wtr_->RecordWatchTime(WatchTimeKey::kAudioVideoAll,
1770 kWatchTime1 + kWatchTime2);
1771 wtr_->UpdateUnderflowCount(kUnderflowCount1 + kUnderflowCount2);
1773 // Complete the last underflow in the new property set. Unfortunately this
1774 // means it will now be associated with this block of watch time. Use a non
1775 // integer multiplier to avoid incorrect carry over being hidden.
1776 wtr_->UpdateUnderflowDuration(kUnderflowCount1, kUnderflowDuration * 1.5);
1778 wtr_->OnError(PIPELINE_ERROR_DECODE);
1779 wtr_->OnDurationChanged(base::Seconds(5125));
1782 base::RunLoop().RunUntilIdle();
1784 // All records should have the following:
1785 const auto& entries = test_recorder_->GetEntriesByName(UkmEntry::kEntryName);
1786 EXPECT_EQ(2u, entries.size());
1787 for (const auto* entry : entries) {
1788 test_recorder_->ExpectEntrySourceHasUrl(entry, GURL(kTestOrigin));
1789 EXPECT_UKM(UkmEntry::kIsBackgroundName, properties->is_background);
1790 EXPECT_UKM(UkmEntry::kIsMutedName, properties->is_muted);
1791 EXPECT_UKM(UkmEntry::kHasAudioName, properties->has_audio);
1792 EXPECT_UKM(UkmEntry::kHasVideoName, properties->has_video);
1793 EXPECT_UKM(UkmEntry::kIsEMEName, properties->is_eme);
1794 EXPECT_UKM(UkmEntry::kIsMSEName, properties->is_mse);
1795 EXPECT_UKM(UkmEntry::kMediaStreamTypeName,
1796 static_cast<int64_t>(properties->media_stream_type));
1797 EXPECT_UKM(UkmEntry::kAutoplayInitiatedName, false);
1798 EXPECT_UKM(UkmEntry::kDurationName, 5000000);
1799 EXPECT_HAS_UKM(UkmEntry::kPlayerIDName);
1801 // All records inherit the final pipeline status code.
1802 EXPECT_UKM(UkmEntry::kLastPipelineStatusName, PIPELINE_ERROR_DECODE);
1805 // The first record should have...
1806 auto* entry = entries[0];
1807 EXPECT_UKM(UkmEntry::kWatchTimeName, kWatchTime1.InMilliseconds());
1808 EXPECT_UKM(UkmEntry::kMeanTimeBetweenRebuffersName,
1809 kWatchTime1.InMilliseconds() / kUnderflowCount1);
1810 EXPECT_UKM(UkmEntry::kAudioDecoderNameName, 2);
1811 EXPECT_UKM(UkmEntry::kVideoDecoderNameName, 5);
1812 EXPECT_UKM(UkmEntry::kRebuffersCountName, kUnderflowCount1);
1813 EXPECT_UKM(UkmEntry::kCompletedRebuffersCountName, kUnderflowCount1 - 1);
1814 EXPECT_UKM(UkmEntry::kCompletedRebuffersDurationName,
1815 kUnderflowDuration.InMilliseconds());
1816 EXPECT_UKM(UkmEntry::kAudioCodecName,
1817 static_cast<int>(secondary_properties1->audio_codec));
1818 EXPECT_UKM(UkmEntry::kVideoCodecName,
1819 static_cast<int>(secondary_properties1->video_codec));
1820 EXPECT_UKM(UkmEntry::kAudioCodecProfileName,
1821 static_cast<int64_t>(secondary_properties1->audio_codec_profile));
1822 EXPECT_UKM(UkmEntry::kVideoCodecProfileName,
1823 secondary_properties1->video_codec_profile);
1825 UkmEntry::kAudioEncryptionSchemeName,
1826 static_cast<int64_t>(secondary_properties1->audio_encryption_scheme));
1828 UkmEntry::kVideoEncryptionSchemeName,
1829 static_cast<int64_t>(secondary_properties1->video_encryption_scheme));
1830 EXPECT_UKM(UkmEntry::kVideoNaturalWidthName,
1831 secondary_properties1->natural_size.width());
1832 EXPECT_UKM(UkmEntry::kVideoNaturalHeightName,
1833 secondary_properties1->natural_size.height());
1835 // The second record should have...
1837 EXPECT_UKM(UkmEntry::kWatchTimeName, kWatchTime2.InMilliseconds());
1838 EXPECT_UKM(UkmEntry::kMeanTimeBetweenRebuffersName,
1839 kWatchTime2.InMilliseconds() / kUnderflowCount2);
1840 EXPECT_UKM(UkmEntry::kAudioDecoderNameName, 1);
1841 EXPECT_UKM(UkmEntry::kVideoDecoderNameName, 2);
1842 EXPECT_UKM(UkmEntry::kRebuffersCountName, kUnderflowCount2);
1843 EXPECT_UKM(UkmEntry::kCompletedRebuffersCountName, 1);
1844 EXPECT_UKM(UkmEntry::kCompletedRebuffersDurationName,
1845 (kUnderflowDuration * 1.5 - kUnderflowDuration).InMilliseconds());
1846 EXPECT_UKM(UkmEntry::kAudioCodecName,
1847 static_cast<int>(secondary_properties2->audio_codec));
1848 EXPECT_UKM(UkmEntry::kVideoCodecName,
1849 static_cast<int>(secondary_properties2->video_codec));
1850 EXPECT_UKM(UkmEntry::kAudioCodecProfileName,
1851 static_cast<int64_t>(secondary_properties2->audio_codec_profile));
1852 EXPECT_UKM(UkmEntry::kVideoCodecProfileName,
1853 secondary_properties2->video_codec_profile);
1855 UkmEntry::kAudioEncryptionSchemeName,
1856 static_cast<int64_t>(secondary_properties2->audio_encryption_scheme));
1858 UkmEntry::kVideoEncryptionSchemeName,
1859 static_cast<int64_t>(secondary_properties2->video_encryption_scheme));
1860 EXPECT_UKM(UkmEntry::kVideoNaturalWidthName,
1861 secondary_properties2->natural_size.width());
1862 EXPECT_UKM(UkmEntry::kVideoNaturalHeightName,
1863 secondary_properties2->natural_size.height());
1867 #undef EXPECT_NO_UKM
1868 #undef EXPECT_HAS_UKM
1870 } // namespace media