1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "media/mojo/services/watch_time_recorder.h"
6 
7 #include <stddef.h>
8 #include <memory>
9 #include <utility>
10 #include <vector>
11 
12 #include "base/bind.h"
13 #include "base/callback_helpers.h"
14 #include "base/hash/hash.h"
15 #include "base/run_loop.h"
16 #include "base/strings/string_number_conversions.h"
17 #include "base/test/metrics/histogram_tester.h"
18 #include "base/test/task_environment.h"
19 #include "base/test/test_message_loop.h"
20 #include "base/threading/thread_task_runner_handle.h"
21 #include "base/time/time.h"
22 #include "components/ukm/test_ukm_recorder.h"
23 #include "media/base/video_codecs.h"
24 #include "media/base/watch_time_keys.h"
25 #include "media/mojo/services/media_metrics_provider.h"
26 #include "mojo/public/cpp/bindings/remote.h"
27 #include "services/metrics/public/cpp/ukm_builders.h"
28 #include "testing/gmock/include/gmock/gmock.h"
29 #include "testing/gtest/include/gtest/gtest.h"
30 #include "url/gurl.h"
31 
32 using UkmEntry = ukm::builders::Media_BasicPlayback;
33 
34 namespace content {
35 class RenderFrameHostDelegate;
36 }  // namespace content
37 
38 namespace media {
39 
40 constexpr char kTestOrigin[] = "https://test.google.com/";
41 
42 class WatchTimeRecorderTest : public testing::Test {
43  public:
WatchTimeRecorderTest()44   WatchTimeRecorderTest()
45       : computation_keys_(
46             {WatchTimeKey::kAudioSrc, WatchTimeKey::kAudioMse,
47              WatchTimeKey::kAudioEme, WatchTimeKey::kAudioVideoSrc,
48              WatchTimeKey::kAudioVideoMse, WatchTimeKey::kAudioVideoEme}),
49         mtbr_keys_({kMeanTimeBetweenRebuffersAudioSrc,
50                     kMeanTimeBetweenRebuffersAudioMse,
51                     kMeanTimeBetweenRebuffersAudioEme,
52                     kMeanTimeBetweenRebuffersAudioVideoSrc,
53                     kMeanTimeBetweenRebuffersAudioVideoMse,
54                     kMeanTimeBetweenRebuffersAudioVideoEme}),
55         smooth_keys_({kRebuffersCountAudioSrc, kRebuffersCountAudioMse,
56                       kRebuffersCountAudioEme, kRebuffersCountAudioVideoSrc,
57                       kRebuffersCountAudioVideoMse,
58                       kRebuffersCountAudioVideoEme}),
59         discard_keys_({kDiscardedWatchTimeAudioSrc, kDiscardedWatchTimeAudioMse,
60                        kDiscardedWatchTimeAudioEme,
61                        kDiscardedWatchTimeAudioVideoSrc,
62                        kDiscardedWatchTimeAudioVideoMse,
63                        kDiscardedWatchTimeAudioVideoEme}) {
64     source_id_ = test_recorder_->GetNewSourceID();
65     ResetMetricRecorders();
66     MediaMetricsProvider::Create(
67         MediaMetricsProvider::BrowsingMode::kIncognito,
68         MediaMetricsProvider::FrameStatus::kTopFrame,
69         base::BindRepeating(&WatchTimeRecorderTest::GetSourceId,
70                             base::Unretained(this)),
71         base::BindRepeating(
__anond669be580102() 72             []() { return learning::FeatureValue(0); }) /* origin callback */,
73         VideoDecodePerfHistory::SaveCallback(),
74         MediaMetricsProvider::GetLearningSessionCallback(),
75         base::BindRepeating(
76             &WatchTimeRecorderTest::GetRecordAggregateWatchTimeCallback,
77             base::Unretained(this)),
78         provider_.BindNewPipeAndPassReceiver());
79   }
80 
~WatchTimeRecorderTest()81   ~WatchTimeRecorderTest() override { base::RunLoop().RunUntilIdle(); }
82 
Initialize(mojom::PlaybackPropertiesPtr properties)83   void Initialize(mojom::PlaybackPropertiesPtr properties) {
84     provider_->Initialize(properties->is_mse,
85                           properties->is_mse ? mojom::MediaURLScheme::kUnknown
86                                              : mojom::MediaURLScheme::kHttp);
87     provider_->AcquireWatchTimeRecorder(std::move(properties),
88                                         wtr_.BindNewPipeAndPassReceiver());
89   }
90 
Initialize(bool has_audio,bool has_video,bool is_mse,bool is_encrypted)91   void Initialize(bool has_audio,
92                   bool has_video,
93                   bool is_mse,
94                   bool is_encrypted) {
95     Initialize(mojom::PlaybackProperties::New(
96         has_audio, has_video, false, false, is_mse, is_encrypted, false));
97   }
98 
ExpectWatchTime(const std::vector<base::StringPiece> & keys,base::TimeDelta value)99   void ExpectWatchTime(const std::vector<base::StringPiece>& keys,
100                        base::TimeDelta value) {
101     for (int i = 0; i <= static_cast<int>(WatchTimeKey::kWatchTimeKeyMax);
102          ++i) {
103       const base::StringPiece test_key =
104           ConvertWatchTimeKeyToStringForUma(static_cast<WatchTimeKey>(i));
105       if (test_key.empty())
106         continue;
107       auto it = std::find(keys.begin(), keys.end(), test_key);
108       if (it == keys.end()) {
109         histogram_tester_->ExpectTotalCount(test_key.as_string(), 0);
110       } else {
111         histogram_tester_->ExpectUniqueSample(test_key.as_string(),
112                                               value.InMilliseconds(), 1);
113       }
114     }
115   }
116 
ExpectHelper(const std::vector<base::StringPiece> & full_key_list,const std::vector<base::StringPiece> & keys,int64_t value)117   void ExpectHelper(const std::vector<base::StringPiece>& full_key_list,
118                     const std::vector<base::StringPiece>& keys,
119                     int64_t value) {
120     for (auto key : full_key_list) {
121       auto it = std::find(keys.begin(), keys.end(), key);
122       if (it == keys.end())
123         histogram_tester_->ExpectTotalCount(key.as_string(), 0);
124       else
125         histogram_tester_->ExpectUniqueSample(key.as_string(), value, 1);
126     }
127   }
128 
ExpectMtbrTime(const std::vector<base::StringPiece> & keys,base::TimeDelta value)129   void ExpectMtbrTime(const std::vector<base::StringPiece>& keys,
130                       base::TimeDelta value) {
131     ExpectHelper(mtbr_keys_, keys, value.InMilliseconds());
132   }
133 
ExpectZeroRebuffers(const std::vector<base::StringPiece> & keys)134   void ExpectZeroRebuffers(const std::vector<base::StringPiece>& keys) {
135     ExpectHelper(smooth_keys_, keys, 0);
136   }
137 
ExpectRebuffers(const std::vector<base::StringPiece> & keys,int count)138   void ExpectRebuffers(const std::vector<base::StringPiece>& keys, int count) {
139     ExpectHelper(smooth_keys_, keys, count);
140   }
141 
ExpectAacAudioCodecProfileHistogram(AudioCodecProfile profile)142   void ExpectAacAudioCodecProfileHistogram(AudioCodecProfile profile) {
143     constexpr char kAudioCodecProfileHistogram[] =
144         "Media.AudioCodecProfile.AAC";
145     histogram_tester_->ExpectUniqueSample(kAudioCodecProfileHistogram,
146                                           static_cast<int64_t>(profile), 1);
147   }
148 
ExpectNoUkmWatchTime()149   void ExpectNoUkmWatchTime() {
150     // We always add a source in testing.
151     ASSERT_EQ(1u, test_recorder_->sources_count());
152     ASSERT_EQ(0u, test_recorder_->entries_count());
153   }
154 
ExpectUkmWatchTime(const std::vector<base::StringPiece> & keys,base::TimeDelta value)155   void ExpectUkmWatchTime(const std::vector<base::StringPiece>& keys,
156                           base::TimeDelta value) {
157     const auto& entries =
158         test_recorder_->GetEntriesByName(UkmEntry::kEntryName);
159     EXPECT_EQ(1u, entries.size());
160     for (const auto* entry : entries) {
161       test_recorder_->ExpectEntrySourceHasUrl(entry, GURL(kTestOrigin));
162       for (auto key : keys) {
163         test_recorder_->ExpectEntryMetric(entry, key.data(),
164                                           value.InMilliseconds());
165       }
166     }
167   }
168 
ResetMetricRecorders()169   void ResetMetricRecorders() {
170     histogram_tester_.reset(new base::HistogramTester());
171     // Ensure cleared global before attempting to create a new TestUkmReporter.
172     test_recorder_.reset();
173     test_recorder_.reset(new ukm::TestAutoSetUkmRecorder());
174     test_recorder_->UpdateSourceURL(source_id_, GURL(kTestOrigin));
175   }
176 
CreateSecondaryProperties()177   mojom::SecondaryPlaybackPropertiesPtr CreateSecondaryProperties() {
178     return mojom::SecondaryPlaybackProperties::New(
179         kCodecAAC, kCodecH264, AudioCodecProfile::kUnknown, H264PROFILE_MAIN,
180         "", "", EncryptionScheme::kUnencrypted, EncryptionScheme::kUnencrypted,
181         gfx::Size(800, 600));
182   }
183 
GetSourceId()184   ukm::SourceId GetSourceId() { return source_id_; }
185 
186   MediaMetricsProvider::RecordAggregateWatchTimeCallback
GetRecordAggregateWatchTimeCallback()187   GetRecordAggregateWatchTimeCallback() {
188     return base::BindRepeating(
189         [](base::WeakPtr<content::RenderFrameHostDelegate> delegate,
190            GURL last_committed_url, base::TimeDelta total_watch_time,
191            base::TimeDelta time_stamp, bool has_video, bool has_audio) {
192           // Do nothing as this mock callback will never be called.
193         },
194         nullptr, GURL());
195   }
196 
197   MOCK_METHOD0(GetCurrentMediaTime, base::TimeDelta());
198 
199  protected:
200   base::test::SingleThreadTaskEnvironment task_environment_;
201   mojo::Remote<mojom::MediaMetricsProvider> provider_;
202   std::unique_ptr<base::HistogramTester> histogram_tester_;
203   std::unique_ptr<ukm::TestAutoSetUkmRecorder> test_recorder_;
204   ukm::SourceId source_id_;
205   mojo::Remote<mojom::WatchTimeRecorder> wtr_;
206   const std::vector<WatchTimeKey> computation_keys_;
207   const std::vector<base::StringPiece> mtbr_keys_;
208   const std::vector<base::StringPiece> smooth_keys_;
209   const std::vector<base::StringPiece> discard_keys_;
210 
211   DISALLOW_COPY_AND_ASSIGN(WatchTimeRecorderTest);
212 };
213 
TEST_F(WatchTimeRecorderTest,TestBasicReporting)214 TEST_F(WatchTimeRecorderTest, TestBasicReporting) {
215   constexpr base::TimeDelta kWatchTime1 = base::TimeDelta::FromSeconds(25);
216   constexpr base::TimeDelta kWatchTime2 = base::TimeDelta::FromSeconds(50);
217 
218   for (int i = 0; i <= static_cast<int>(WatchTimeKey::kWatchTimeKeyMax); ++i) {
219     const WatchTimeKey key = static_cast<WatchTimeKey>(i);
220 
221     auto key_str = ConvertWatchTimeKeyToStringForUma(key);
222     SCOPED_TRACE(key_str.empty() ? base::NumberToString(i)
223                                  : key_str.as_string());
224 
225     // Values for |is_background| and |is_muted| don't matter in this test since
226     // they don't prevent the muted or background keys from being recorded.
227     Initialize(true, false, true, true);
228     wtr_->UpdateSecondaryProperties(CreateSecondaryProperties());
229 
230     wtr_->RecordWatchTime(WatchTimeKey::kWatchTimeKeyMax, kWatchTime1);
231     wtr_->RecordWatchTime(key, kWatchTime1);
232     wtr_->RecordWatchTime(key, kWatchTime2);
233     base::RunLoop().RunUntilIdle();
234 
235     // Nothing should be recorded yet since we haven't finalized.
236     ExpectWatchTime({}, base::TimeDelta());
237 
238     // Only the requested key should be finalized.
239     wtr_->FinalizeWatchTime({key});
240     base::RunLoop().RunUntilIdle();
241 
242     if (!key_str.empty())
243       ExpectWatchTime({key_str}, kWatchTime2);
244 
245     // These keys are only reported for a full finalize.
246     ExpectMtbrTime({}, base::TimeDelta());
247     ExpectZeroRebuffers({});
248     ExpectNoUkmWatchTime();
249 
250     // Verify nothing else is recorded except for what we finalized above.
251     ResetMetricRecorders();
252     wtr_.reset();
253     base::RunLoop().RunUntilIdle();
254     ExpectWatchTime({}, base::TimeDelta());
255     ExpectMtbrTime({}, base::TimeDelta());
256     ExpectZeroRebuffers({});
257 
258     switch (key) {
259       case WatchTimeKey::kAudioAll:
260       case WatchTimeKey::kAudioBackgroundAll:
261       case WatchTimeKey::kAudioVideoAll:
262       case WatchTimeKey::kAudioVideoBackgroundAll:
263       case WatchTimeKey::kAudioVideoMutedAll:
264       case WatchTimeKey::kVideoAll:
265       case WatchTimeKey::kVideoBackgroundAll:
266         ExpectUkmWatchTime({UkmEntry::kWatchTimeName}, kWatchTime2);
267         break;
268 
269       // These keys are not reported, instead we boolean flags for each type.
270       case WatchTimeKey::kAudioMse:
271       case WatchTimeKey::kAudioEme:
272       case WatchTimeKey::kAudioSrc:
273       case WatchTimeKey::kAudioEmbeddedExperience:
274       case WatchTimeKey::kAudioBackgroundMse:
275       case WatchTimeKey::kAudioBackgroundEme:
276       case WatchTimeKey::kAudioBackgroundSrc:
277       case WatchTimeKey::kAudioBackgroundEmbeddedExperience:
278       case WatchTimeKey::kAudioVideoMse:
279       case WatchTimeKey::kAudioVideoEme:
280       case WatchTimeKey::kAudioVideoSrc:
281       case WatchTimeKey::kAudioVideoEmbeddedExperience:
282       case WatchTimeKey::kAudioVideoMutedMse:
283       case WatchTimeKey::kAudioVideoMutedEme:
284       case WatchTimeKey::kAudioVideoMutedSrc:
285       case WatchTimeKey::kAudioVideoMutedEmbeddedExperience:
286       case WatchTimeKey::kAudioVideoBackgroundMse:
287       case WatchTimeKey::kAudioVideoBackgroundEme:
288       case WatchTimeKey::kAudioVideoBackgroundSrc:
289       case WatchTimeKey::kAudioVideoBackgroundEmbeddedExperience:
290       case WatchTimeKey::kVideoMse:
291       case WatchTimeKey::kVideoEme:
292       case WatchTimeKey::kVideoSrc:
293       case WatchTimeKey::kVideoEmbeddedExperience:
294       case WatchTimeKey::kVideoBackgroundMse:
295       case WatchTimeKey::kVideoBackgroundEme:
296       case WatchTimeKey::kVideoBackgroundSrc:
297       case WatchTimeKey::kVideoBackgroundEmbeddedExperience:
298         ExpectUkmWatchTime({}, base::TimeDelta());
299         break;
300 
301       // These keys roll up into the battery watch time field.
302       case WatchTimeKey::kAudioBattery:
303       case WatchTimeKey::kAudioBackgroundBattery:
304       case WatchTimeKey::kAudioVideoBattery:
305       case WatchTimeKey::kAudioVideoMutedBattery:
306       case WatchTimeKey::kAudioVideoBackgroundBattery:
307       case WatchTimeKey::kVideoBattery:
308       case WatchTimeKey::kVideoBackgroundBattery:
309         ExpectUkmWatchTime({UkmEntry::kWatchTime_BatteryName}, kWatchTime2);
310         break;
311 
312       // These keys roll up into the AC watch time field.
313       case WatchTimeKey::kAudioAc:
314       case WatchTimeKey::kAudioBackgroundAc:
315       case WatchTimeKey::kAudioVideoAc:
316       case WatchTimeKey::kAudioVideoBackgroundAc:
317       case WatchTimeKey::kAudioVideoMutedAc:
318       case WatchTimeKey::kVideoAc:
319       case WatchTimeKey::kVideoBackgroundAc:
320         ExpectUkmWatchTime({UkmEntry::kWatchTime_ACName}, kWatchTime2);
321         break;
322 
323       case WatchTimeKey::kAudioVideoDisplayFullscreen:
324       case WatchTimeKey::kAudioVideoMutedDisplayFullscreen:
325       case WatchTimeKey::kVideoDisplayFullscreen:
326         ExpectUkmWatchTime({UkmEntry::kWatchTime_DisplayFullscreenName},
327                            kWatchTime2);
328         break;
329 
330       case WatchTimeKey::kAudioVideoDisplayInline:
331       case WatchTimeKey::kAudioVideoMutedDisplayInline:
332       case WatchTimeKey::kVideoDisplayInline:
333         ExpectUkmWatchTime({UkmEntry::kWatchTime_DisplayInlineName},
334                            kWatchTime2);
335         break;
336 
337       case WatchTimeKey::kAudioVideoDisplayPictureInPicture:
338       case WatchTimeKey::kAudioVideoMutedDisplayPictureInPicture:
339       case WatchTimeKey::kVideoDisplayPictureInPicture:
340         ExpectUkmWatchTime({UkmEntry::kWatchTime_DisplayPictureInPictureName},
341                            kWatchTime2);
342         break;
343 
344       case WatchTimeKey::kAudioNativeControlsOn:
345       case WatchTimeKey::kAudioVideoNativeControlsOn:
346       case WatchTimeKey::kAudioVideoMutedNativeControlsOn:
347       case WatchTimeKey::kVideoNativeControlsOn:
348         ExpectUkmWatchTime({UkmEntry::kWatchTime_NativeControlsOnName},
349                            kWatchTime2);
350         break;
351 
352       case WatchTimeKey::kAudioNativeControlsOff:
353       case WatchTimeKey::kAudioVideoNativeControlsOff:
354       case WatchTimeKey::kAudioVideoMutedNativeControlsOff:
355       case WatchTimeKey::kVideoNativeControlsOff:
356         ExpectUkmWatchTime({UkmEntry::kWatchTime_NativeControlsOffName},
357                            kWatchTime2);
358         break;
359     }
360 
361     ResetMetricRecorders();
362   }
363 }
364 
TEST_F(WatchTimeRecorderTest,TestRebufferingMetrics)365 TEST_F(WatchTimeRecorderTest, TestRebufferingMetrics) {
366   Initialize(true, false, true, true);
367 
368   constexpr base::TimeDelta kWatchTime = base::TimeDelta::FromSeconds(50);
369   for (auto key : computation_keys_)
370     wtr_->RecordWatchTime(key, kWatchTime);
371   wtr_->UpdateUnderflowCount(1);
372   wtr_->UpdateUnderflowCount(2);
373 
374   // Trigger finalization of everything.
375   wtr_->FinalizeWatchTime({});
376   base::RunLoop().RunUntilIdle();
377 
378   ExpectMtbrTime(mtbr_keys_, kWatchTime / 2);
379   ExpectRebuffers(smooth_keys_, 2);
380 
381   // Now rerun the test without any rebuffering.
382   ResetMetricRecorders();
383   for (auto key : computation_keys_)
384     wtr_->RecordWatchTime(key, kWatchTime);
385   wtr_->FinalizeWatchTime({});
386   base::RunLoop().RunUntilIdle();
387 
388   ExpectMtbrTime({}, base::TimeDelta());
389   ExpectZeroRebuffers(smooth_keys_);
390 
391   // Now rerun the test with a small amount of watch time and ensure rebuffering
392   // isn't recorded because we haven't met the watch time requirements.
393   ResetMetricRecorders();
394   constexpr base::TimeDelta kWatchTimeShort = base::TimeDelta::FromSeconds(5);
395   for (auto key : computation_keys_)
396     wtr_->RecordWatchTime(key, kWatchTimeShort);
397   wtr_->UpdateUnderflowCount(1);
398   wtr_->UpdateUnderflowCount(2);
399   wtr_->FinalizeWatchTime({});
400   base::RunLoop().RunUntilIdle();
401 
402   // Nothing should be logged since this doesn't meet requirements.
403   ExpectMtbrTime({}, base::TimeDelta());
404   for (auto key : smooth_keys_)
405     histogram_tester_->ExpectTotalCount(key.as_string(), 0);
406 }
407 
TEST_F(WatchTimeRecorderTest,TestDiscardMetrics)408 TEST_F(WatchTimeRecorderTest, TestDiscardMetrics) {
409   Initialize(true, false, true, true);
410   wtr_->UpdateSecondaryProperties(CreateSecondaryProperties());
411 
412   constexpr base::TimeDelta kWatchTime = base::TimeDelta::FromSeconds(5);
413   for (auto key : computation_keys_)
414     wtr_->RecordWatchTime(key, kWatchTime);
415 
416   // Trigger finalization of everything.
417   wtr_.reset();
418   base::RunLoop().RunUntilIdle();
419 
420   // No standard watch time should be recorded because it falls below the
421   // reporting threshold.
422   ExpectWatchTime({}, base::TimeDelta());
423 
424   // Verify the time was instead logged to the discard keys.
425   for (auto key : discard_keys_) {
426     histogram_tester_->ExpectUniqueSample(key.as_string(),
427                                           kWatchTime.InMilliseconds(), 1);
428   }
429 
430   // UKM watch time won't be logged because we aren't sending "All" keys.
431   ExpectUkmWatchTime({}, base::TimeDelta());
432 }
433 
434 #define EXPECT_UKM(name, value) \
435   test_recorder_->ExpectEntryMetric(entry, name, value)
436 #define EXPECT_NO_UKM(name) \
437   EXPECT_FALSE(test_recorder_->EntryHasMetric(entry, name))
438 #define EXPECT_HAS_UKM(name) \
439   EXPECT_TRUE(test_recorder_->EntryHasMetric(entry, name));
440 
TEST_F(WatchTimeRecorderTest,TestFinalizeNoDuplication)441 TEST_F(WatchTimeRecorderTest, TestFinalizeNoDuplication) {
442   mojom::PlaybackPropertiesPtr properties = mojom::PlaybackProperties::New(
443       true, true, false, false, false, false, false);
444   mojom::SecondaryPlaybackPropertiesPtr secondary_properties =
445       CreateSecondaryProperties();
446   Initialize(properties.Clone());
447   wtr_->UpdateSecondaryProperties(secondary_properties.Clone());
448 
449   // Verify that UKM is reported along with the watch time.
450   constexpr base::TimeDelta kWatchTime = base::TimeDelta::FromSeconds(4);
451   wtr_->RecordWatchTime(WatchTimeKey::kAudioVideoAll, kWatchTime);
452 
453   // Finalize everything. UKM is only recorded at destruction, so this should do
454   // nothing.
455   wtr_->FinalizeWatchTime({});
456   base::RunLoop().RunUntilIdle();
457 
458   // No watch time should have been recorded since this is below the UMA report
459   // threshold.
460   ExpectWatchTime({}, base::TimeDelta());
461   ExpectMtbrTime({}, base::TimeDelta());
462   ExpectZeroRebuffers({});
463   ExpectNoUkmWatchTime();
464 
465   const auto& empty_entries =
466       test_recorder_->GetEntriesByName(UkmEntry::kEntryName);
467   EXPECT_EQ(0u, empty_entries.size());
468 
469   // Verify UKM is logged at destruction time.
470   ResetMetricRecorders();
471   wtr_.reset();
472   base::RunLoop().RunUntilIdle();
473   const auto& entries = test_recorder_->GetEntriesByName(UkmEntry::kEntryName);
474   EXPECT_EQ(1u, entries.size());
475   for (const auto* entry : entries) {
476     test_recorder_->ExpectEntrySourceHasUrl(entry, GURL(kTestOrigin));
477 
478     EXPECT_UKM(UkmEntry::kIsBackgroundName, properties->is_background);
479     EXPECT_UKM(UkmEntry::kIsMutedName, properties->is_muted);
480     EXPECT_UKM(UkmEntry::kAudioCodecName, secondary_properties->audio_codec);
481     EXPECT_UKM(UkmEntry::kVideoCodecName, secondary_properties->video_codec);
482     EXPECT_UKM(UkmEntry::kAudioCodecProfileName,
483                static_cast<int64_t>(secondary_properties->audio_codec_profile));
484     EXPECT_UKM(UkmEntry::kVideoCodecProfileName,
485                secondary_properties->video_codec_profile);
486     EXPECT_UKM(UkmEntry::kHasAudioName, properties->has_audio);
487     EXPECT_UKM(UkmEntry::kHasVideoName, properties->has_video);
488     EXPECT_UKM(
489         UkmEntry::kAudioEncryptionSchemeName,
490         static_cast<int64_t>(secondary_properties->audio_encryption_scheme));
491     EXPECT_UKM(
492         UkmEntry::kVideoEncryptionSchemeName,
493         static_cast<int64_t>(secondary_properties->video_encryption_scheme));
494     EXPECT_UKM(UkmEntry::kIsEMEName, properties->is_eme);
495     EXPECT_UKM(UkmEntry::kIsMSEName, properties->is_mse);
496     EXPECT_UKM(UkmEntry::kLastPipelineStatusName, PIPELINE_OK);
497     EXPECT_UKM(UkmEntry::kRebuffersCountName, 0);
498     EXPECT_UKM(UkmEntry::kCompletedRebuffersCountName, 0);
499     EXPECT_UKM(UkmEntry::kCompletedRebuffersDurationName, 0);
500     EXPECT_UKM(UkmEntry::kVideoNaturalWidthName,
501                secondary_properties->natural_size.width());
502     EXPECT_UKM(UkmEntry::kVideoNaturalHeightName,
503                secondary_properties->natural_size.height());
504     EXPECT_UKM(UkmEntry::kWatchTimeName, kWatchTime.InMilliseconds());
505     EXPECT_UKM(UkmEntry::kAudioDecoderNameName, 0);
506     EXPECT_UKM(UkmEntry::kVideoDecoderNameName, 0);
507     EXPECT_UKM(UkmEntry::kAutoplayInitiatedName, false);
508     EXPECT_HAS_UKM(UkmEntry::kPlayerIDName);
509 
510     EXPECT_NO_UKM(UkmEntry::kMeanTimeBetweenRebuffersName);
511     EXPECT_NO_UKM(UkmEntry::kWatchTime_ACName);
512     EXPECT_NO_UKM(UkmEntry::kWatchTime_BatteryName);
513     EXPECT_NO_UKM(UkmEntry::kWatchTime_NativeControlsOnName);
514     EXPECT_NO_UKM(UkmEntry::kWatchTime_NativeControlsOffName);
515     EXPECT_NO_UKM(UkmEntry::kWatchTime_DisplayFullscreenName);
516     EXPECT_NO_UKM(UkmEntry::kWatchTime_DisplayInlineName);
517     EXPECT_NO_UKM(UkmEntry::kWatchTime_DisplayPictureInPictureName);
518   }
519 }
520 
TEST_F(WatchTimeRecorderTest,FinalizeWithoutWatchTime)521 TEST_F(WatchTimeRecorderTest, FinalizeWithoutWatchTime) {
522   mojom::PlaybackPropertiesPtr properties = mojom::PlaybackProperties::New(
523       true, true, false, false, false, false, false);
524   mojom::SecondaryPlaybackPropertiesPtr secondary_properties =
525       CreateSecondaryProperties();
526   Initialize(properties.Clone());
527   wtr_->UpdateSecondaryProperties(secondary_properties.Clone());
528 
529   // Finalize everything. UKM is only recorded at destruction, so this should do
530   // nothing.
531   wtr_->FinalizeWatchTime({});
532   base::RunLoop().RunUntilIdle();
533 
534   // No watch time should have been recorded even though a finalize event will
535   // be sent, however a UKM entry with the playback properties will still be
536   // generated.
537   ExpectWatchTime({}, base::TimeDelta());
538   ExpectMtbrTime({}, base::TimeDelta());
539   ExpectZeroRebuffers({});
540   ExpectNoUkmWatchTime();
541 
542   const auto& empty_entries =
543       test_recorder_->GetEntriesByName(UkmEntry::kEntryName);
544   EXPECT_EQ(0u, empty_entries.size());
545 
546   // Destructing the recorder should generate a UKM report though.
547   ResetMetricRecorders();
548   wtr_.reset();
549   base::RunLoop().RunUntilIdle();
550   const auto& entries = test_recorder_->GetEntriesByName(UkmEntry::kEntryName);
551   EXPECT_EQ(1u, entries.size());
552   for (const auto* entry : entries) {
553     test_recorder_->ExpectEntrySourceHasUrl(entry, GURL(kTestOrigin));
554 
555     EXPECT_UKM(UkmEntry::kIsBackgroundName, properties->is_background);
556     EXPECT_UKM(UkmEntry::kIsMutedName, properties->is_muted);
557     EXPECT_UKM(UkmEntry::kAudioCodecName, secondary_properties->audio_codec);
558     EXPECT_UKM(UkmEntry::kVideoCodecName, secondary_properties->video_codec);
559     EXPECT_UKM(UkmEntry::kAudioCodecProfileName,
560                static_cast<int64_t>(secondary_properties->audio_codec_profile));
561     EXPECT_UKM(UkmEntry::kVideoCodecProfileName,
562                secondary_properties->video_codec_profile);
563     EXPECT_UKM(UkmEntry::kHasAudioName, properties->has_audio);
564     EXPECT_UKM(UkmEntry::kHasVideoName, properties->has_video);
565     EXPECT_UKM(
566         UkmEntry::kAudioEncryptionSchemeName,
567         static_cast<int64_t>(secondary_properties->audio_encryption_scheme));
568     EXPECT_UKM(
569         UkmEntry::kVideoEncryptionSchemeName,
570         static_cast<int64_t>(secondary_properties->video_encryption_scheme));
571     EXPECT_UKM(UkmEntry::kIsEMEName, properties->is_eme);
572     EXPECT_UKM(UkmEntry::kIsMSEName, properties->is_mse);
573     EXPECT_UKM(UkmEntry::kLastPipelineStatusName, PIPELINE_OK);
574     EXPECT_UKM(UkmEntry::kRebuffersCountName, 0);
575     EXPECT_UKM(UkmEntry::kCompletedRebuffersCountName, 0);
576     EXPECT_UKM(UkmEntry::kCompletedRebuffersDurationName, 0);
577     EXPECT_UKM(UkmEntry::kVideoNaturalWidthName,
578                secondary_properties->natural_size.width());
579     EXPECT_UKM(UkmEntry::kVideoNaturalHeightName,
580                secondary_properties->natural_size.height());
581     EXPECT_UKM(UkmEntry::kAudioDecoderNameName, 0);
582     EXPECT_UKM(UkmEntry::kVideoDecoderNameName, 0);
583     EXPECT_UKM(UkmEntry::kAutoplayInitiatedName, false);
584     EXPECT_HAS_UKM(UkmEntry::kPlayerIDName);
585 
586     EXPECT_NO_UKM(UkmEntry::kMeanTimeBetweenRebuffersName);
587     EXPECT_NO_UKM(UkmEntry::kWatchTimeName);
588     EXPECT_NO_UKM(UkmEntry::kWatchTime_ACName);
589     EXPECT_NO_UKM(UkmEntry::kWatchTime_BatteryName);
590     EXPECT_NO_UKM(UkmEntry::kWatchTime_NativeControlsOnName);
591     EXPECT_NO_UKM(UkmEntry::kWatchTime_NativeControlsOffName);
592     EXPECT_NO_UKM(UkmEntry::kWatchTime_DisplayFullscreenName);
593     EXPECT_NO_UKM(UkmEntry::kWatchTime_DisplayInlineName);
594     EXPECT_NO_UKM(UkmEntry::kWatchTime_DisplayPictureInPictureName);
595   }
596 }
597 
TEST_F(WatchTimeRecorderTest,BasicUkmAudioVideo)598 TEST_F(WatchTimeRecorderTest, BasicUkmAudioVideo) {
599   mojom::PlaybackPropertiesPtr properties = mojom::PlaybackProperties::New(
600       true, true, false, false, false, false, false);
601   mojom::SecondaryPlaybackPropertiesPtr secondary_properties =
602       mojom::SecondaryPlaybackProperties::New(
603           kCodecAAC, kCodecH264, AudioCodecProfile::kXHE_AAC, H264PROFILE_MAIN,
604           "", "", EncryptionScheme::kCenc, EncryptionScheme::kCbcs,
605           gfx::Size(800, 600));
606   Initialize(properties.Clone());
607   wtr_->UpdateSecondaryProperties(secondary_properties.Clone());
608 
609   constexpr base::TimeDelta kWatchTime = base::TimeDelta::FromSeconds(4);
610   wtr_->RecordWatchTime(WatchTimeKey::kAudioVideoAll, kWatchTime);
611   wtr_.reset();
612   base::RunLoop().RunUntilIdle();
613 
614   ExpectAacAudioCodecProfileHistogram(
615       secondary_properties->audio_codec_profile);
616 
617   const auto& entries = test_recorder_->GetEntriesByName(UkmEntry::kEntryName);
618   EXPECT_EQ(1u, entries.size());
619   for (const auto* entry : entries) {
620     test_recorder_->ExpectEntrySourceHasUrl(entry, GURL(kTestOrigin));
621 
622     EXPECT_UKM(UkmEntry::kWatchTimeName, kWatchTime.InMilliseconds());
623     EXPECT_UKM(UkmEntry::kIsBackgroundName, properties->is_background);
624     EXPECT_UKM(UkmEntry::kIsMutedName, properties->is_muted);
625     EXPECT_UKM(UkmEntry::kAudioCodecName, secondary_properties->audio_codec);
626     EXPECT_UKM(UkmEntry::kVideoCodecName, secondary_properties->video_codec);
627     EXPECT_UKM(UkmEntry::kAudioCodecProfileName,
628                static_cast<int64_t>(secondary_properties->audio_codec_profile));
629     EXPECT_UKM(UkmEntry::kVideoCodecProfileName,
630                secondary_properties->video_codec_profile);
631     EXPECT_UKM(UkmEntry::kHasAudioName, properties->has_audio);
632     EXPECT_UKM(UkmEntry::kHasVideoName, properties->has_video);
633     EXPECT_UKM(
634         UkmEntry::kAudioEncryptionSchemeName,
635         static_cast<int64_t>(secondary_properties->audio_encryption_scheme));
636     EXPECT_UKM(
637         UkmEntry::kVideoEncryptionSchemeName,
638         static_cast<int64_t>(secondary_properties->video_encryption_scheme));
639     EXPECT_UKM(UkmEntry::kIsEMEName, properties->is_eme);
640     EXPECT_UKM(UkmEntry::kIsMSEName, properties->is_mse);
641     EXPECT_UKM(UkmEntry::kLastPipelineStatusName, PIPELINE_OK);
642     EXPECT_UKM(UkmEntry::kRebuffersCountName, 0);
643     EXPECT_UKM(UkmEntry::kCompletedRebuffersCountName, 0);
644     EXPECT_UKM(UkmEntry::kCompletedRebuffersDurationName, 0);
645     EXPECT_UKM(UkmEntry::kVideoNaturalWidthName,
646                secondary_properties->natural_size.width());
647     EXPECT_UKM(UkmEntry::kVideoNaturalHeightName,
648                secondary_properties->natural_size.height());
649     EXPECT_HAS_UKM(UkmEntry::kPlayerIDName);
650     EXPECT_UKM(UkmEntry::kAudioDecoderNameName, 0);
651     EXPECT_UKM(UkmEntry::kVideoDecoderNameName, 0);
652     EXPECT_UKM(UkmEntry::kAutoplayInitiatedName, false);
653 
654     EXPECT_NO_UKM(UkmEntry::kMeanTimeBetweenRebuffersName);
655     EXPECT_NO_UKM(UkmEntry::kWatchTime_ACName);
656     EXPECT_NO_UKM(UkmEntry::kWatchTime_BatteryName);
657     EXPECT_NO_UKM(UkmEntry::kWatchTime_NativeControlsOnName);
658     EXPECT_NO_UKM(UkmEntry::kWatchTime_NativeControlsOffName);
659     EXPECT_NO_UKM(UkmEntry::kWatchTime_DisplayFullscreenName);
660     EXPECT_NO_UKM(UkmEntry::kWatchTime_DisplayInlineName);
661     EXPECT_NO_UKM(UkmEntry::kWatchTime_DisplayPictureInPictureName);
662   }
663 }
664 
TEST_F(WatchTimeRecorderTest,BasicUkmAudioVideoWithExtras)665 TEST_F(WatchTimeRecorderTest, BasicUkmAudioVideoWithExtras) {
666   mojom::PlaybackPropertiesPtr properties = mojom::PlaybackProperties::New(
667       true, true, false, false, true, true, false);
668   mojom::SecondaryPlaybackPropertiesPtr secondary_properties =
669       mojom::SecondaryPlaybackProperties::New(
670           kCodecOpus, kCodecVP9, AudioCodecProfile::kUnknown,
671           VP9PROFILE_PROFILE0, "", "", EncryptionScheme::kUnencrypted,
672           EncryptionScheme::kUnencrypted, gfx::Size(800, 600));
673   Initialize(properties.Clone());
674   wtr_->UpdateSecondaryProperties(secondary_properties.Clone());
675 
676   constexpr base::TimeDelta kWatchTime = base::TimeDelta::FromSeconds(54);
677   const base::TimeDelta kWatchTime2 = kWatchTime * 2;
678   const base::TimeDelta kWatchTime3 = kWatchTime / 3;
679   wtr_->RecordWatchTime(WatchTimeKey::kAudioVideoAll, kWatchTime2);
680   wtr_->RecordWatchTime(WatchTimeKey::kAudioVideoAc, kWatchTime);
681 
682   // Ensure partial finalize does not affect final report.
683   wtr_->FinalizeWatchTime({WatchTimeKey::kAudioVideoAc});
684   wtr_->RecordWatchTime(WatchTimeKey::kAudioVideoBattery, kWatchTime);
685   wtr_->RecordWatchTime(WatchTimeKey::kAudioVideoNativeControlsOn, kWatchTime);
686   wtr_->FinalizeWatchTime({WatchTimeKey::kAudioVideoNativeControlsOn});
687   wtr_->RecordWatchTime(WatchTimeKey::kAudioVideoNativeControlsOff, kWatchTime);
688   wtr_->RecordWatchTime(WatchTimeKey::kAudioVideoDisplayFullscreen,
689                         kWatchTime3);
690   wtr_->FinalizeWatchTime({WatchTimeKey::kAudioVideoDisplayFullscreen});
691   wtr_->RecordWatchTime(WatchTimeKey::kAudioVideoDisplayInline, kWatchTime3);
692   wtr_->FinalizeWatchTime({WatchTimeKey::kAudioVideoDisplayInline});
693   wtr_->RecordWatchTime(WatchTimeKey::kAudioVideoDisplayPictureInPicture,
694                         kWatchTime3);
695   wtr_->UpdateUnderflowCount(3);
696   constexpr base::TimeDelta kUnderflowDuration =
697       base::TimeDelta::FromMilliseconds(500);
698   wtr_->UpdateUnderflowDuration(2, kUnderflowDuration);
699   wtr_->UpdateVideoDecodeStats(10, 2);
700   wtr_->OnError(PIPELINE_ERROR_DECODE);
701 
702   secondary_properties->audio_decoder_name = "MojoAudioDecoder";
703   secondary_properties->video_decoder_name = "MojoVideoDecoder";
704   wtr_->UpdateSecondaryProperties(secondary_properties.Clone());
705 
706   wtr_->SetAutoplayInitiated(true);
707 
708   wtr_->OnDurationChanged(base::TimeDelta::FromSeconds(9500));
709 
710   wtr_.reset();
711   base::RunLoop().RunUntilIdle();
712 
713   const auto& entries = test_recorder_->GetEntriesByName(UkmEntry::kEntryName);
714   EXPECT_EQ(1u, entries.size());
715   for (const auto* entry : entries) {
716     test_recorder_->ExpectEntrySourceHasUrl(entry, GURL(kTestOrigin));
717     EXPECT_UKM(UkmEntry::kWatchTimeName, kWatchTime2.InMilliseconds());
718     EXPECT_UKM(UkmEntry::kWatchTime_ACName, kWatchTime.InMilliseconds());
719     EXPECT_UKM(UkmEntry::kWatchTime_BatteryName, kWatchTime.InMilliseconds());
720     EXPECT_UKM(UkmEntry::kWatchTime_NativeControlsOnName,
721                kWatchTime.InMilliseconds());
722     EXPECT_UKM(UkmEntry::kWatchTime_NativeControlsOffName,
723                kWatchTime.InMilliseconds());
724     EXPECT_UKM(UkmEntry::kWatchTime_DisplayFullscreenName,
725                kWatchTime3.InMilliseconds());
726     EXPECT_UKM(UkmEntry::kWatchTime_DisplayInlineName,
727                kWatchTime3.InMilliseconds());
728     EXPECT_UKM(UkmEntry::kWatchTime_DisplayPictureInPictureName,
729                kWatchTime3.InMilliseconds());
730     EXPECT_UKM(UkmEntry::kMeanTimeBetweenRebuffersName,
731                kWatchTime2.InMilliseconds() / 3);
732     EXPECT_HAS_UKM(UkmEntry::kPlayerIDName);
733 
734     // Values taken from .cc private enumeration (and should never change).
735     EXPECT_UKM(UkmEntry::kAudioDecoderNameName, 2);
736     EXPECT_UKM(UkmEntry::kVideoDecoderNameName, 5);
737 
738     // Duration should be rounded up.
739     EXPECT_UKM(UkmEntry::kDurationName, 10000000);
740 
741     EXPECT_UKM(UkmEntry::kIsBackgroundName, properties->is_background);
742     EXPECT_UKM(UkmEntry::kIsMutedName, properties->is_muted);
743     EXPECT_UKM(UkmEntry::kAudioCodecName, secondary_properties->audio_codec);
744     EXPECT_UKM(UkmEntry::kVideoCodecName, secondary_properties->video_codec);
745     EXPECT_UKM(UkmEntry::kAudioCodecProfileName,
746                static_cast<int64_t>(secondary_properties->audio_codec_profile));
747     EXPECT_UKM(UkmEntry::kVideoCodecProfileName,
748                secondary_properties->video_codec_profile);
749     EXPECT_UKM(UkmEntry::kHasAudioName, properties->has_audio);
750     EXPECT_UKM(UkmEntry::kHasVideoName, properties->has_video);
751     EXPECT_UKM(
752         UkmEntry::kAudioEncryptionSchemeName,
753         static_cast<int64_t>(secondary_properties->audio_encryption_scheme));
754     EXPECT_UKM(
755         UkmEntry::kVideoEncryptionSchemeName,
756         static_cast<int64_t>(secondary_properties->video_encryption_scheme));
757     EXPECT_UKM(UkmEntry::kIsEMEName, properties->is_eme);
758     EXPECT_UKM(UkmEntry::kIsMSEName, properties->is_mse);
759     EXPECT_UKM(UkmEntry::kLastPipelineStatusName, PIPELINE_ERROR_DECODE);
760     EXPECT_UKM(UkmEntry::kRebuffersCountName, 3);
761     EXPECT_UKM(UkmEntry::kCompletedRebuffersCountName, 2);
762     EXPECT_UKM(UkmEntry::kCompletedRebuffersDurationName,
763                kUnderflowDuration.InMilliseconds());
764     EXPECT_UKM(UkmEntry::kVideoFramesDecodedName, 10);
765     EXPECT_UKM(UkmEntry::kVideoFramesDroppedName, 2);
766     EXPECT_UKM(UkmEntry::kVideoNaturalWidthName,
767                secondary_properties->natural_size.width());
768     EXPECT_UKM(UkmEntry::kVideoNaturalHeightName,
769                secondary_properties->natural_size.height());
770     EXPECT_UKM(UkmEntry::kAutoplayInitiatedName, true);
771   }
772 }
773 
TEST_F(WatchTimeRecorderTest,BasicUkmAudioVideoBackgroundMuted)774 TEST_F(WatchTimeRecorderTest, BasicUkmAudioVideoBackgroundMuted) {
775   mojom::PlaybackPropertiesPtr properties = mojom::PlaybackProperties::New(
776       true, true, true, true, false, false, false);
777   mojom::SecondaryPlaybackPropertiesPtr secondary_properties =
778       CreateSecondaryProperties();
779   Initialize(properties.Clone());
780   wtr_->UpdateSecondaryProperties(secondary_properties.Clone());
781 
782   constexpr base::TimeDelta kWatchTime = base::TimeDelta::FromSeconds(54);
783   wtr_->RecordWatchTime(WatchTimeKey::kAudioVideoBackgroundAll, kWatchTime);
784   wtr_.reset();
785   base::RunLoop().RunUntilIdle();
786 
787   if (secondary_properties->audio_codec == kCodecAAC) {
788     ExpectAacAudioCodecProfileHistogram(
789         secondary_properties->audio_codec_profile);
790   }
791 
792   const auto& entries = test_recorder_->GetEntriesByName(UkmEntry::kEntryName);
793   EXPECT_EQ(1u, entries.size());
794   for (const auto* entry : entries) {
795     test_recorder_->ExpectEntrySourceHasUrl(entry, GURL(kTestOrigin));
796 
797     EXPECT_UKM(UkmEntry::kWatchTimeName, kWatchTime.InMilliseconds());
798     EXPECT_UKM(UkmEntry::kIsBackgroundName, properties->is_background);
799     EXPECT_UKM(UkmEntry::kIsMutedName, properties->is_muted);
800     EXPECT_UKM(UkmEntry::kAudioCodecName, secondary_properties->audio_codec);
801     EXPECT_UKM(UkmEntry::kVideoCodecName, secondary_properties->video_codec);
802     EXPECT_UKM(UkmEntry::kAudioCodecProfileName,
803                static_cast<int64_t>(secondary_properties->audio_codec_profile));
804     EXPECT_UKM(UkmEntry::kVideoCodecProfileName,
805                secondary_properties->video_codec_profile);
806     EXPECT_UKM(UkmEntry::kHasAudioName, properties->has_audio);
807     EXPECT_UKM(UkmEntry::kHasVideoName, properties->has_video);
808     EXPECT_UKM(
809         UkmEntry::kAudioEncryptionSchemeName,
810         static_cast<int64_t>(secondary_properties->audio_encryption_scheme));
811     EXPECT_UKM(
812         UkmEntry::kVideoEncryptionSchemeName,
813         static_cast<int64_t>(secondary_properties->video_encryption_scheme));
814     EXPECT_UKM(UkmEntry::kIsEMEName, properties->is_eme);
815     EXPECT_UKM(UkmEntry::kIsMSEName, properties->is_mse);
816     EXPECT_UKM(UkmEntry::kLastPipelineStatusName, PIPELINE_OK);
817     EXPECT_UKM(UkmEntry::kRebuffersCountName, 0);
818     EXPECT_UKM(UkmEntry::kCompletedRebuffersCountName, 0);
819     EXPECT_UKM(UkmEntry::kCompletedRebuffersDurationName, 0);
820     EXPECT_UKM(UkmEntry::kVideoNaturalWidthName,
821                secondary_properties->natural_size.width());
822     EXPECT_UKM(UkmEntry::kVideoNaturalHeightName,
823                secondary_properties->natural_size.height());
824     EXPECT_HAS_UKM(UkmEntry::kPlayerIDName);
825     EXPECT_UKM(UkmEntry::kAudioDecoderNameName, 0);
826     EXPECT_UKM(UkmEntry::kVideoDecoderNameName, 0);
827     EXPECT_UKM(UkmEntry::kAutoplayInitiatedName, false);
828 
829     EXPECT_NO_UKM(UkmEntry::kDurationName);
830     EXPECT_NO_UKM(UkmEntry::kMeanTimeBetweenRebuffersName);
831     EXPECT_NO_UKM(UkmEntry::kWatchTime_ACName);
832     EXPECT_NO_UKM(UkmEntry::kWatchTime_BatteryName);
833     EXPECT_NO_UKM(UkmEntry::kWatchTime_NativeControlsOnName);
834     EXPECT_NO_UKM(UkmEntry::kWatchTime_NativeControlsOffName);
835     EXPECT_NO_UKM(UkmEntry::kWatchTime_DisplayFullscreenName);
836     EXPECT_NO_UKM(UkmEntry::kWatchTime_DisplayInlineName);
837     EXPECT_NO_UKM(UkmEntry::kWatchTime_DisplayPictureInPictureName);
838   }
839 }
840 
TEST_F(WatchTimeRecorderTest,BasicUkmAudioVideoDuration)841 TEST_F(WatchTimeRecorderTest, BasicUkmAudioVideoDuration) {
842   mojom::PlaybackPropertiesPtr properties = mojom::PlaybackProperties::New(
843       true, true, false, false, false, false, false);
844   mojom::SecondaryPlaybackPropertiesPtr secondary_properties =
845       CreateSecondaryProperties();
846   Initialize(properties.Clone());
847   wtr_->UpdateSecondaryProperties(secondary_properties.Clone());
848 
849   wtr_->OnDurationChanged(base::TimeDelta::FromSeconds(12345));
850   wtr_.reset();
851   base::RunLoop().RunUntilIdle();
852 
853   if (secondary_properties->audio_codec == kCodecAAC) {
854     ExpectAacAudioCodecProfileHistogram(
855         secondary_properties->audio_codec_profile);
856   }
857 
858   const auto& entries = test_recorder_->GetEntriesByName(UkmEntry::kEntryName);
859   EXPECT_EQ(1u, entries.size());
860   for (const auto* entry : entries) {
861     test_recorder_->ExpectEntrySourceHasUrl(entry, GURL(kTestOrigin));
862 
863     EXPECT_UKM(UkmEntry::kIsBackgroundName, properties->is_background);
864     EXPECT_UKM(UkmEntry::kIsMutedName, properties->is_muted);
865     EXPECT_UKM(UkmEntry::kAudioCodecName, secondary_properties->audio_codec);
866     EXPECT_UKM(UkmEntry::kVideoCodecName, secondary_properties->video_codec);
867     EXPECT_UKM(UkmEntry::kAudioCodecProfileName,
868                static_cast<int64_t>(secondary_properties->audio_codec_profile));
869     EXPECT_UKM(UkmEntry::kVideoCodecProfileName,
870                secondary_properties->video_codec_profile);
871     EXPECT_UKM(UkmEntry::kHasAudioName, properties->has_audio);
872     EXPECT_UKM(UkmEntry::kHasVideoName, properties->has_video);
873     EXPECT_UKM(
874         UkmEntry::kAudioEncryptionSchemeName,
875         static_cast<int64_t>(secondary_properties->audio_encryption_scheme));
876     EXPECT_UKM(
877         UkmEntry::kVideoEncryptionSchemeName,
878         static_cast<int64_t>(secondary_properties->video_encryption_scheme));
879     EXPECT_UKM(UkmEntry::kIsEMEName, properties->is_eme);
880     EXPECT_UKM(UkmEntry::kIsMSEName, properties->is_mse);
881     EXPECT_UKM(UkmEntry::kLastPipelineStatusName, PIPELINE_OK);
882     EXPECT_UKM(UkmEntry::kRebuffersCountName, 0);
883     EXPECT_UKM(UkmEntry::kCompletedRebuffersCountName, 0);
884     EXPECT_UKM(UkmEntry::kCompletedRebuffersDurationName, 0);
885     EXPECT_UKM(UkmEntry::kVideoNaturalWidthName,
886                secondary_properties->natural_size.width());
887     EXPECT_UKM(UkmEntry::kVideoNaturalHeightName,
888                secondary_properties->natural_size.height());
889     EXPECT_HAS_UKM(UkmEntry::kPlayerIDName);
890     EXPECT_UKM(UkmEntry::kAudioDecoderNameName, 0);
891     EXPECT_UKM(UkmEntry::kVideoDecoderNameName, 0);
892     EXPECT_UKM(UkmEntry::kAutoplayInitiatedName, false);
893 
894     // Duration should be rounded to the most significant digit.
895     EXPECT_UKM(UkmEntry::kDurationName, 10000000);
896 
897     EXPECT_NO_UKM(UkmEntry::kMeanTimeBetweenRebuffersName);
898     EXPECT_NO_UKM(UkmEntry::kWatchTime_ACName);
899     EXPECT_NO_UKM(UkmEntry::kWatchTime_BatteryName);
900     EXPECT_NO_UKM(UkmEntry::kWatchTime_NativeControlsOnName);
901     EXPECT_NO_UKM(UkmEntry::kWatchTime_NativeControlsOffName);
902     EXPECT_NO_UKM(UkmEntry::kWatchTime_DisplayFullscreenName);
903     EXPECT_NO_UKM(UkmEntry::kWatchTime_DisplayInlineName);
904     EXPECT_NO_UKM(UkmEntry::kWatchTime_DisplayPictureInPictureName);
905   }
906 }
907 
TEST_F(WatchTimeRecorderTest,BasicUkmAudioVideoDurationInfinite)908 TEST_F(WatchTimeRecorderTest, BasicUkmAudioVideoDurationInfinite) {
909   mojom::PlaybackPropertiesPtr properties = mojom::PlaybackProperties::New(
910       true, true, false, false, false, false, false);
911   mojom::SecondaryPlaybackPropertiesPtr secondary_properties =
912       CreateSecondaryProperties();
913   Initialize(properties.Clone());
914   wtr_->UpdateSecondaryProperties(secondary_properties.Clone());
915 
916   wtr_->OnDurationChanged(kInfiniteDuration);
917   wtr_.reset();
918   base::RunLoop().RunUntilIdle();
919 
920   if (secondary_properties->audio_codec == kCodecAAC) {
921     ExpectAacAudioCodecProfileHistogram(
922         secondary_properties->audio_codec_profile);
923   }
924 
925   const auto& entries = test_recorder_->GetEntriesByName(UkmEntry::kEntryName);
926   EXPECT_EQ(1u, entries.size());
927   for (const auto* entry : entries) {
928     test_recorder_->ExpectEntrySourceHasUrl(entry, GURL(kTestOrigin));
929 
930     EXPECT_UKM(UkmEntry::kIsBackgroundName, properties->is_background);
931     EXPECT_UKM(UkmEntry::kIsMutedName, properties->is_muted);
932     EXPECT_UKM(UkmEntry::kAudioCodecName, secondary_properties->audio_codec);
933     EXPECT_UKM(UkmEntry::kVideoCodecName, secondary_properties->video_codec);
934     EXPECT_UKM(UkmEntry::kAudioCodecProfileName,
935                static_cast<int64_t>(secondary_properties->audio_codec_profile));
936     EXPECT_UKM(UkmEntry::kVideoCodecProfileName,
937                secondary_properties->video_codec_profile);
938     EXPECT_UKM(UkmEntry::kHasAudioName, properties->has_audio);
939     EXPECT_UKM(UkmEntry::kHasVideoName, properties->has_video);
940     EXPECT_UKM(
941         UkmEntry::kAudioEncryptionSchemeName,
942         static_cast<int64_t>(secondary_properties->audio_encryption_scheme));
943     EXPECT_UKM(
944         UkmEntry::kVideoEncryptionSchemeName,
945         static_cast<int64_t>(secondary_properties->video_encryption_scheme));
946     EXPECT_UKM(UkmEntry::kIsEMEName, properties->is_eme);
947     EXPECT_UKM(UkmEntry::kIsMSEName, properties->is_mse);
948     EXPECT_UKM(UkmEntry::kLastPipelineStatusName, PIPELINE_OK);
949     EXPECT_UKM(UkmEntry::kRebuffersCountName, 0);
950     EXPECT_UKM(UkmEntry::kCompletedRebuffersCountName, 0);
951     EXPECT_UKM(UkmEntry::kCompletedRebuffersDurationName, 0);
952     EXPECT_UKM(UkmEntry::kVideoNaturalWidthName,
953                secondary_properties->natural_size.width());
954     EXPECT_UKM(UkmEntry::kVideoNaturalHeightName,
955                secondary_properties->natural_size.height());
956     EXPECT_HAS_UKM(UkmEntry::kPlayerIDName);
957     EXPECT_UKM(UkmEntry::kAudioDecoderNameName, 0);
958     EXPECT_UKM(UkmEntry::kVideoDecoderNameName, 0);
959     EXPECT_UKM(UkmEntry::kAutoplayInitiatedName, false);
960 
961     // Duration should be unrecorded when infinite.
962     EXPECT_NO_UKM(UkmEntry::kDurationName);
963     EXPECT_NO_UKM(UkmEntry::kWatchTimeName);
964     EXPECT_NO_UKM(UkmEntry::kMeanTimeBetweenRebuffersName);
965     EXPECT_NO_UKM(UkmEntry::kWatchTime_ACName);
966     EXPECT_NO_UKM(UkmEntry::kWatchTime_BatteryName);
967     EXPECT_NO_UKM(UkmEntry::kWatchTime_NativeControlsOnName);
968     EXPECT_NO_UKM(UkmEntry::kWatchTime_NativeControlsOffName);
969     EXPECT_NO_UKM(UkmEntry::kWatchTime_DisplayFullscreenName);
970     EXPECT_NO_UKM(UkmEntry::kWatchTime_DisplayInlineName);
971     EXPECT_NO_UKM(UkmEntry::kWatchTime_DisplayPictureInPictureName);
972   }
973 }
974 
975 // Might happen due to timing issues, so ensure no crashes.
TEST_F(WatchTimeRecorderTest,NoSecondaryProperties)976 TEST_F(WatchTimeRecorderTest, NoSecondaryProperties) {
977   mojom::PlaybackPropertiesPtr properties = mojom::PlaybackProperties::New(
978       true, true, false, false, true, true, false);
979   Initialize(properties.Clone());
980 
981   constexpr base::TimeDelta kWatchTime = base::TimeDelta::FromSeconds(54);
982   wtr_->RecordWatchTime(WatchTimeKey::kAudioVideoAll, kWatchTime);
983   wtr_.reset();
984   base::RunLoop().RunUntilIdle();
985   const auto& entries = test_recorder_->GetEntriesByName(UkmEntry::kEntryName);
986   EXPECT_EQ(0u, entries.size());
987 }
988 
TEST_F(WatchTimeRecorderTest,SingleSecondaryPropertiesUnknownToKnown)989 TEST_F(WatchTimeRecorderTest, SingleSecondaryPropertiesUnknownToKnown) {
990   mojom::PlaybackPropertiesPtr properties = mojom::PlaybackProperties::New(
991       true, true, false, false, true, true, false);
992   mojom::SecondaryPlaybackPropertiesPtr secondary_properties1 =
993       mojom::SecondaryPlaybackProperties::New(
994           kUnknownAudioCodec, kUnknownVideoCodec, AudioCodecProfile::kUnknown,
995           VIDEO_CODEC_PROFILE_UNKNOWN, "", "", EncryptionScheme::kUnencrypted,
996           EncryptionScheme::kUnencrypted, gfx::Size(800, 600));
997   Initialize(properties.Clone());
998   wtr_->UpdateSecondaryProperties(secondary_properties1.Clone());
999 
1000   constexpr base::TimeDelta kWatchTime = base::TimeDelta::FromSeconds(54);
1001   wtr_->RecordWatchTime(WatchTimeKey::kAudioVideoAll, kWatchTime);
1002 
1003   mojom::SecondaryPlaybackPropertiesPtr secondary_properties2 =
1004       mojom::SecondaryPlaybackProperties::New(
1005           kCodecAAC, kCodecH264, AudioCodecProfile::kXHE_AAC, H264PROFILE_MAIN,
1006           "FFmpegAudioDecoder", "FFmpegVideoDecoder",
1007           EncryptionScheme::kUnencrypted, EncryptionScheme::kUnencrypted,
1008           gfx::Size(800, 600));
1009   wtr_->UpdateSecondaryProperties(secondary_properties2.Clone());
1010 
1011   wtr_.reset();
1012   base::RunLoop().RunUntilIdle();
1013 
1014   // Since we only transitioned unknown values to known values, there should be
1015   // only a single UKM entry.
1016   const auto& entries = test_recorder_->GetEntriesByName(UkmEntry::kEntryName);
1017   EXPECT_EQ(1u, entries.size());
1018   for (const auto* entry : entries) {
1019     test_recorder_->ExpectEntrySourceHasUrl(entry, GURL(kTestOrigin));
1020     EXPECT_UKM(UkmEntry::kIsBackgroundName, properties->is_background);
1021     EXPECT_UKM(UkmEntry::kIsMutedName, properties->is_muted);
1022     EXPECT_UKM(UkmEntry::kHasAudioName, properties->has_audio);
1023     EXPECT_UKM(UkmEntry::kHasVideoName, properties->has_video);
1024     EXPECT_UKM(UkmEntry::kIsEMEName, properties->is_eme);
1025     EXPECT_UKM(UkmEntry::kIsMSEName, properties->is_mse);
1026     EXPECT_UKM(UkmEntry::kAutoplayInitiatedName, false);
1027     EXPECT_UKM(UkmEntry::kLastPipelineStatusName, PIPELINE_OK);
1028     EXPECT_HAS_UKM(UkmEntry::kPlayerIDName);
1029     EXPECT_UKM(UkmEntry::kWatchTimeName, kWatchTime.InMilliseconds());
1030     EXPECT_UKM(UkmEntry::kAudioDecoderNameName, 1);
1031     EXPECT_UKM(UkmEntry::kVideoDecoderNameName, 2);
1032     EXPECT_UKM(UkmEntry::kRebuffersCountName, 0);
1033     EXPECT_UKM(UkmEntry::kCompletedRebuffersCountName, 0);
1034     EXPECT_UKM(UkmEntry::kCompletedRebuffersDurationName, 0);
1035     EXPECT_UKM(UkmEntry::kAudioCodecName, secondary_properties2->audio_codec);
1036     EXPECT_UKM(UkmEntry::kVideoCodecName, secondary_properties2->video_codec);
1037     EXPECT_UKM(
1038         UkmEntry::kAudioCodecProfileName,
1039         static_cast<int64_t>(secondary_properties2->audio_codec_profile));
1040     EXPECT_UKM(UkmEntry::kVideoCodecProfileName,
1041                secondary_properties2->video_codec_profile);
1042     EXPECT_UKM(
1043         UkmEntry::kAudioEncryptionSchemeName,
1044         static_cast<int64_t>(secondary_properties2->audio_encryption_scheme));
1045     EXPECT_UKM(
1046         UkmEntry::kVideoEncryptionSchemeName,
1047         static_cast<int64_t>(secondary_properties2->video_encryption_scheme));
1048     EXPECT_UKM(UkmEntry::kVideoNaturalWidthName,
1049                secondary_properties2->natural_size.width());
1050     EXPECT_UKM(UkmEntry::kVideoNaturalHeightName,
1051                secondary_properties2->natural_size.height());
1052     EXPECT_NO_UKM(UkmEntry::kDurationName);
1053   }
1054 }
1055 
TEST_F(WatchTimeRecorderTest,MultipleSecondaryPropertiesNoFinalize)1056 TEST_F(WatchTimeRecorderTest, MultipleSecondaryPropertiesNoFinalize) {
1057   mojom::PlaybackPropertiesPtr properties = mojom::PlaybackProperties::New(
1058       true, true, false, false, true, true, false);
1059   mojom::SecondaryPlaybackPropertiesPtr secondary_properties1 =
1060       mojom::SecondaryPlaybackProperties::New(
1061           kCodecOpus, kCodecVP9, AudioCodecProfile::kUnknown,
1062           VP9PROFILE_PROFILE0, "MojoAudioDecoder", "MojoVideoDecoder",
1063           EncryptionScheme::kUnencrypted, EncryptionScheme::kUnencrypted,
1064           gfx::Size(400, 300));
1065   Initialize(properties.Clone());
1066   wtr_->UpdateSecondaryProperties(secondary_properties1.Clone());
1067 
1068   constexpr base::TimeDelta kUnderflowDuration =
1069       base::TimeDelta::FromMilliseconds(250);
1070   constexpr base::TimeDelta kWatchTime1 = base::TimeDelta::FromSeconds(54);
1071   const int kUnderflowCount1 = 2;
1072   wtr_->RecordWatchTime(WatchTimeKey::kAudioVideoAll, kWatchTime1);
1073   wtr_->UpdateUnderflowCount(kUnderflowCount1);
1074   wtr_->UpdateUnderflowDuration(kUnderflowCount1, kUnderflowDuration);
1075 
1076   constexpr int kDecodedFrameCount1 = 10;
1077   constexpr int kDroppedFrameCount1 = 2;
1078   wtr_->UpdateVideoDecodeStats(kDecodedFrameCount1, kDroppedFrameCount1);
1079 
1080   mojom::SecondaryPlaybackPropertiesPtr secondary_properties2 =
1081       mojom::SecondaryPlaybackProperties::New(
1082           kCodecAAC, kCodecH264, AudioCodecProfile::kUnknown, H264PROFILE_MAIN,
1083           "FFmpegAudioDecoder", "FFmpegVideoDecoder", EncryptionScheme::kCenc,
1084           EncryptionScheme::kCenc, gfx::Size(800, 600));
1085   wtr_->UpdateSecondaryProperties(secondary_properties2.Clone());
1086 
1087   constexpr base::TimeDelta kWatchTime2 = base::TimeDelta::FromSeconds(25);
1088   const int kUnderflowCount2 = 3;
1089 
1090   // Watch time and underflow counts continue to accumulate during property
1091   // changes, so we report the sum here instead of just kWatchTime2.
1092   wtr_->RecordWatchTime(WatchTimeKey::kAudioVideoAll,
1093                         kWatchTime1 + kWatchTime2);
1094   wtr_->UpdateUnderflowCount(kUnderflowCount1 + kUnderflowCount2);
1095   wtr_->OnError(PIPELINE_ERROR_DECODE);
1096   wtr_->OnDurationChanged(base::TimeDelta::FromSeconds(5125));
1097 
1098   constexpr int kDecodedFrameCount2 = 20;
1099   constexpr int kDroppedFrameCount2 = 10;
1100   wtr_->UpdateVideoDecodeStats(kDecodedFrameCount1 + kDecodedFrameCount2,
1101                                kDroppedFrameCount1 + kDroppedFrameCount2);
1102 
1103   wtr_.reset();
1104   base::RunLoop().RunUntilIdle();
1105 
1106   // All records should have the following:
1107   const auto& entries = test_recorder_->GetEntriesByName(UkmEntry::kEntryName);
1108   EXPECT_EQ(2u, entries.size());
1109   for (const auto* entry : entries) {
1110     test_recorder_->ExpectEntrySourceHasUrl(entry, GURL(kTestOrigin));
1111     EXPECT_UKM(UkmEntry::kIsBackgroundName, properties->is_background);
1112     EXPECT_UKM(UkmEntry::kIsMutedName, properties->is_muted);
1113     EXPECT_UKM(UkmEntry::kHasAudioName, properties->has_audio);
1114     EXPECT_UKM(UkmEntry::kHasVideoName, properties->has_video);
1115     EXPECT_UKM(UkmEntry::kIsEMEName, properties->is_eme);
1116     EXPECT_UKM(UkmEntry::kIsMSEName, properties->is_mse);
1117     EXPECT_UKM(UkmEntry::kAutoplayInitiatedName, false);
1118     EXPECT_UKM(UkmEntry::kDurationName, 5000000);
1119     EXPECT_HAS_UKM(UkmEntry::kPlayerIDName);
1120 
1121     // All records inherit the final pipeline status code.
1122     EXPECT_UKM(UkmEntry::kLastPipelineStatusName, PIPELINE_ERROR_DECODE);
1123   }
1124 
1125   // The first record should have...
1126   auto* entry = entries[0];
1127   EXPECT_UKM(UkmEntry::kWatchTimeName, kWatchTime1.InMilliseconds());
1128   EXPECT_UKM(UkmEntry::kMeanTimeBetweenRebuffersName,
1129              kWatchTime1.InMilliseconds() / kUnderflowCount1);
1130   EXPECT_UKM(UkmEntry::kAudioDecoderNameName, 2);
1131   EXPECT_UKM(UkmEntry::kVideoDecoderNameName, 5);
1132   EXPECT_UKM(UkmEntry::kRebuffersCountName, kUnderflowCount1);
1133   EXPECT_UKM(UkmEntry::kCompletedRebuffersCountName, kUnderflowCount1);
1134   EXPECT_UKM(UkmEntry::kCompletedRebuffersDurationName,
1135              kUnderflowDuration.InMilliseconds());
1136   EXPECT_UKM(UkmEntry::kVideoFramesDecodedName, kDecodedFrameCount1);
1137   EXPECT_UKM(UkmEntry::kVideoFramesDroppedName, kDroppedFrameCount1);
1138   EXPECT_UKM(UkmEntry::kAudioCodecName, secondary_properties1->audio_codec);
1139   EXPECT_UKM(UkmEntry::kVideoCodecName, secondary_properties1->video_codec);
1140   EXPECT_UKM(UkmEntry::kAudioCodecProfileName,
1141              static_cast<int64_t>(secondary_properties1->audio_codec_profile));
1142   EXPECT_UKM(UkmEntry::kVideoCodecProfileName,
1143              secondary_properties1->video_codec_profile);
1144   EXPECT_UKM(
1145       UkmEntry::kAudioEncryptionSchemeName,
1146       static_cast<int64_t>(secondary_properties1->audio_encryption_scheme));
1147   EXPECT_UKM(
1148       UkmEntry::kVideoEncryptionSchemeName,
1149       static_cast<int64_t>(secondary_properties1->video_encryption_scheme));
1150   EXPECT_UKM(UkmEntry::kVideoNaturalWidthName,
1151              secondary_properties1->natural_size.width());
1152   EXPECT_UKM(UkmEntry::kVideoNaturalHeightName,
1153              secondary_properties1->natural_size.height());
1154 
1155   // The second record should have...
1156   entry = entries[1];
1157   EXPECT_UKM(UkmEntry::kWatchTimeName, kWatchTime2.InMilliseconds());
1158   EXPECT_UKM(UkmEntry::kMeanTimeBetweenRebuffersName,
1159              kWatchTime2.InMilliseconds() / kUnderflowCount2);
1160   EXPECT_UKM(UkmEntry::kAudioDecoderNameName, 1);
1161   EXPECT_UKM(UkmEntry::kVideoDecoderNameName, 2);
1162   EXPECT_UKM(UkmEntry::kRebuffersCountName, kUnderflowCount2);
1163   EXPECT_UKM(UkmEntry::kCompletedRebuffersCountName, 0);
1164   EXPECT_UKM(UkmEntry::kVideoFramesDecodedName, kDecodedFrameCount2);
1165   EXPECT_UKM(UkmEntry::kVideoFramesDroppedName, kDroppedFrameCount2);
1166 
1167   EXPECT_UKM(UkmEntry::kCompletedRebuffersDurationName, 0);
1168   EXPECT_UKM(UkmEntry::kAudioCodecName, secondary_properties2->audio_codec);
1169   EXPECT_UKM(UkmEntry::kVideoCodecName, secondary_properties2->video_codec);
1170   EXPECT_UKM(UkmEntry::kAudioCodecProfileName,
1171              static_cast<int64_t>(secondary_properties2->audio_codec_profile));
1172   EXPECT_UKM(UkmEntry::kVideoCodecProfileName,
1173              secondary_properties2->video_codec_profile);
1174   EXPECT_UKM(
1175       UkmEntry::kAudioEncryptionSchemeName,
1176       static_cast<int64_t>(secondary_properties2->audio_encryption_scheme));
1177   EXPECT_UKM(
1178       UkmEntry::kVideoEncryptionSchemeName,
1179       static_cast<int64_t>(secondary_properties2->video_encryption_scheme));
1180   EXPECT_UKM(UkmEntry::kVideoNaturalWidthName,
1181              secondary_properties2->natural_size.width());
1182   EXPECT_UKM(UkmEntry::kVideoNaturalHeightName,
1183              secondary_properties2->natural_size.height());
1184 }
1185 
TEST_F(WatchTimeRecorderTest,MultipleSecondaryPropertiesNoFinalizeNo2ndWT)1186 TEST_F(WatchTimeRecorderTest, MultipleSecondaryPropertiesNoFinalizeNo2ndWT) {
1187   mojom::PlaybackPropertiesPtr properties = mojom::PlaybackProperties::New(
1188       true, true, false, false, true, true, false);
1189   mojom::SecondaryPlaybackPropertiesPtr secondary_properties1 =
1190       mojom::SecondaryPlaybackProperties::New(
1191           kCodecOpus, kCodecVP9, AudioCodecProfile::kUnknown,
1192           VP9PROFILE_PROFILE0, "MojoAudioDecoder", "MojoVideoDecoder",
1193           EncryptionScheme::kUnencrypted, EncryptionScheme::kUnencrypted,
1194           gfx::Size(400, 300));
1195   Initialize(properties.Clone());
1196   wtr_->UpdateSecondaryProperties(secondary_properties1.Clone());
1197 
1198   constexpr base::TimeDelta kUnderflowDuration =
1199       base::TimeDelta::FromMilliseconds(250);
1200   constexpr base::TimeDelta kWatchTime1 = base::TimeDelta::FromSeconds(54);
1201   const int kUnderflowCount1 = 2;
1202   wtr_->RecordWatchTime(WatchTimeKey::kAudioVideoAll, kWatchTime1);
1203   wtr_->UpdateUnderflowCount(kUnderflowCount1);
1204   wtr_->UpdateUnderflowDuration(kUnderflowCount1, kUnderflowDuration);
1205 
1206   constexpr int kDecodedFrameCount1 = 10;
1207   constexpr int kDroppedFrameCount1 = 2;
1208   wtr_->UpdateVideoDecodeStats(kDecodedFrameCount1, kDroppedFrameCount1);
1209 
1210   mojom::SecondaryPlaybackPropertiesPtr secondary_properties2 =
1211       mojom::SecondaryPlaybackProperties::New(
1212           kCodecAAC, kCodecH264, AudioCodecProfile::kXHE_AAC, H264PROFILE_MAIN,
1213           "FFmpegAudioDecoder", "FFmpegVideoDecoder",
1214           EncryptionScheme::kUnencrypted, EncryptionScheme::kUnencrypted,
1215           gfx::Size(800, 600));
1216   wtr_->UpdateSecondaryProperties(secondary_properties2.Clone());
1217 
1218   // Don't record any watch time to the new record, it should report zero watch
1219   // time upon destruction. This ensures there's always a Finalize to prevent
1220   // UKM was receiving negative values from the previous unfinalized record.
1221   wtr_.reset();
1222   base::RunLoop().RunUntilIdle();
1223 
1224   // All records should have the following:
1225   const auto& entries = test_recorder_->GetEntriesByName(UkmEntry::kEntryName);
1226   EXPECT_EQ(2u, entries.size());
1227   for (const auto* entry : entries) {
1228     test_recorder_->ExpectEntrySourceHasUrl(entry, GURL(kTestOrigin));
1229     EXPECT_UKM(UkmEntry::kIsBackgroundName, properties->is_background);
1230     EXPECT_UKM(UkmEntry::kIsMutedName, properties->is_muted);
1231     EXPECT_UKM(UkmEntry::kHasAudioName, properties->has_audio);
1232     EXPECT_UKM(UkmEntry::kHasVideoName, properties->has_video);
1233     EXPECT_UKM(UkmEntry::kIsEMEName, properties->is_eme);
1234     EXPECT_UKM(UkmEntry::kIsMSEName, properties->is_mse);
1235     EXPECT_UKM(UkmEntry::kAutoplayInitiatedName, false);
1236     EXPECT_UKM(UkmEntry::kLastPipelineStatusName, PIPELINE_OK);
1237     EXPECT_HAS_UKM(UkmEntry::kPlayerIDName);
1238     EXPECT_NO_UKM(UkmEntry::kDurationName);
1239   }
1240 
1241   // The first record should have...
1242   auto* entry = entries[0];
1243   EXPECT_UKM(UkmEntry::kWatchTimeName, kWatchTime1.InMilliseconds());
1244   EXPECT_UKM(UkmEntry::kMeanTimeBetweenRebuffersName,
1245              kWatchTime1.InMilliseconds() / kUnderflowCount1);
1246   EXPECT_UKM(UkmEntry::kAudioDecoderNameName, 2);
1247   EXPECT_UKM(UkmEntry::kVideoDecoderNameName, 5);
1248   EXPECT_UKM(UkmEntry::kRebuffersCountName, kUnderflowCount1);
1249   EXPECT_UKM(UkmEntry::kCompletedRebuffersCountName, kUnderflowCount1);
1250   EXPECT_UKM(UkmEntry::kCompletedRebuffersDurationName,
1251              kUnderflowDuration.InMilliseconds());
1252   EXPECT_UKM(UkmEntry::kVideoFramesDecodedName, kDecodedFrameCount1);
1253   EXPECT_UKM(UkmEntry::kVideoFramesDroppedName, kDroppedFrameCount1);
1254   EXPECT_UKM(UkmEntry::kAudioCodecName, secondary_properties1->audio_codec);
1255   EXPECT_UKM(UkmEntry::kVideoCodecName, secondary_properties1->video_codec);
1256   EXPECT_UKM(UkmEntry::kAudioCodecProfileName,
1257              static_cast<int64_t>(secondary_properties1->audio_codec_profile));
1258   EXPECT_UKM(UkmEntry::kVideoCodecProfileName,
1259              secondary_properties1->video_codec_profile);
1260   EXPECT_UKM(
1261       UkmEntry::kAudioEncryptionSchemeName,
1262       static_cast<int64_t>(secondary_properties1->audio_encryption_scheme));
1263   EXPECT_UKM(
1264       UkmEntry::kVideoEncryptionSchemeName,
1265       static_cast<int64_t>(secondary_properties1->video_encryption_scheme));
1266   EXPECT_UKM(UkmEntry::kVideoNaturalWidthName,
1267              secondary_properties1->natural_size.width());
1268   EXPECT_UKM(UkmEntry::kVideoNaturalHeightName,
1269              secondary_properties1->natural_size.height());
1270 
1271   // The second record should have...
1272   entry = entries[1];
1273   EXPECT_UKM(UkmEntry::kWatchTimeName, 0);
1274   EXPECT_UKM(UkmEntry::kAudioDecoderNameName, 1);
1275   EXPECT_UKM(UkmEntry::kVideoDecoderNameName, 2);
1276   EXPECT_UKM(UkmEntry::kRebuffersCountName, 0);
1277   EXPECT_UKM(UkmEntry::kCompletedRebuffersCountName, 0);
1278   EXPECT_UKM(UkmEntry::kCompletedRebuffersDurationName, 0);
1279   EXPECT_UKM(UkmEntry::kVideoFramesDecodedName, 0);
1280   EXPECT_UKM(UkmEntry::kVideoFramesDroppedName, 0);
1281   EXPECT_UKM(UkmEntry::kAudioCodecName, secondary_properties2->audio_codec);
1282   EXPECT_UKM(UkmEntry::kVideoCodecName, secondary_properties2->video_codec);
1283   EXPECT_UKM(UkmEntry::kAudioCodecProfileName,
1284              static_cast<int64_t>(secondary_properties2->audio_codec_profile));
1285   EXPECT_UKM(UkmEntry::kVideoCodecProfileName,
1286              secondary_properties2->video_codec_profile);
1287   EXPECT_UKM(
1288       UkmEntry::kAudioEncryptionSchemeName,
1289       static_cast<int64_t>(secondary_properties2->audio_encryption_scheme));
1290   EXPECT_UKM(
1291       UkmEntry::kVideoEncryptionSchemeName,
1292       static_cast<int64_t>(secondary_properties2->video_encryption_scheme));
1293   EXPECT_UKM(UkmEntry::kVideoNaturalWidthName,
1294              secondary_properties2->natural_size.width());
1295   EXPECT_UKM(UkmEntry::kVideoNaturalHeightName,
1296              secondary_properties2->natural_size.height());
1297 }
1298 
TEST_F(WatchTimeRecorderTest,MultipleSecondaryPropertiesWithFinalize)1299 TEST_F(WatchTimeRecorderTest, MultipleSecondaryPropertiesWithFinalize) {
1300   mojom::PlaybackPropertiesPtr properties = mojom::PlaybackProperties::New(
1301       true, true, false, false, true, true, false);
1302   mojom::SecondaryPlaybackPropertiesPtr secondary_properties1 =
1303       mojom::SecondaryPlaybackProperties::New(
1304           kCodecOpus, kCodecVP9, AudioCodecProfile::kUnknown,
1305           VP9PROFILE_PROFILE0, "MojoAudioDecoder", "MojoVideoDecoder",
1306           EncryptionScheme::kCbcs, EncryptionScheme::kCbcs,
1307           gfx::Size(400, 300));
1308   Initialize(properties.Clone());
1309   wtr_->UpdateSecondaryProperties(secondary_properties1.Clone());
1310 
1311   constexpr base::TimeDelta kUnderflowDuration =
1312       base::TimeDelta::FromMilliseconds(250);
1313   constexpr base::TimeDelta kWatchTime1 = base::TimeDelta::FromSeconds(54);
1314   const int kUnderflowCount1 = 2;
1315   wtr_->RecordWatchTime(WatchTimeKey::kAudioVideoAll, kWatchTime1);
1316   wtr_->UpdateUnderflowCount(kUnderflowCount1);
1317   wtr_->UpdateUnderflowDuration(kUnderflowCount1, kUnderflowDuration);
1318 
1319   constexpr int kDecodedFrameCount1 = 10;
1320   constexpr int kDroppedFrameCount1 = 2;
1321   wtr_->UpdateVideoDecodeStats(kDecodedFrameCount1, kDroppedFrameCount1);
1322 
1323   // Force a finalize here so that the there is no unfinalized watch time at the
1324   // time of the secondary property update.
1325   wtr_->FinalizeWatchTime({});
1326 
1327   mojom::SecondaryPlaybackPropertiesPtr secondary_properties2 =
1328       mojom::SecondaryPlaybackProperties::New(
1329           kCodecAAC, kCodecH264, AudioCodecProfile::kXHE_AAC, H264PROFILE_MAIN,
1330           "FFmpegAudioDecoder", "FFmpegVideoDecoder",
1331           EncryptionScheme::kUnencrypted, EncryptionScheme::kUnencrypted,
1332           gfx::Size(800, 600));
1333   wtr_->UpdateSecondaryProperties(secondary_properties2.Clone());
1334 
1335   constexpr base::TimeDelta kWatchTime2 = base::TimeDelta::FromSeconds(25);
1336   const int kUnderflowCount2 = 3;
1337 
1338   wtr_->RecordWatchTime(WatchTimeKey::kAudioVideoAll, kWatchTime2);
1339   wtr_->UpdateUnderflowCount(kUnderflowCount2);
1340   wtr_->OnError(PIPELINE_ERROR_DECODE);
1341 
1342   wtr_.reset();
1343   base::RunLoop().RunUntilIdle();
1344 
1345   // All records should have the following:
1346   const auto& entries = test_recorder_->GetEntriesByName(UkmEntry::kEntryName);
1347   EXPECT_EQ(2u, entries.size());
1348   for (const auto* entry : entries) {
1349     test_recorder_->ExpectEntrySourceHasUrl(entry, GURL(kTestOrigin));
1350     EXPECT_UKM(UkmEntry::kIsBackgroundName, properties->is_background);
1351     EXPECT_UKM(UkmEntry::kIsMutedName, properties->is_muted);
1352     EXPECT_UKM(UkmEntry::kHasAudioName, properties->has_audio);
1353     EXPECT_UKM(UkmEntry::kHasVideoName, properties->has_video);
1354     EXPECT_UKM(UkmEntry::kIsEMEName, properties->is_eme);
1355     EXPECT_UKM(UkmEntry::kIsMSEName, properties->is_mse);
1356     EXPECT_UKM(UkmEntry::kAutoplayInitiatedName, false);
1357     EXPECT_HAS_UKM(UkmEntry::kPlayerIDName);
1358     EXPECT_NO_UKM(UkmEntry::kDurationName);
1359 
1360     // All records inherit the final pipeline status code.
1361     EXPECT_UKM(UkmEntry::kLastPipelineStatusName, PIPELINE_ERROR_DECODE);
1362   }
1363 
1364   // The first record should have...
1365   auto* entry = entries[0];
1366   EXPECT_UKM(UkmEntry::kWatchTimeName, kWatchTime1.InMilliseconds());
1367   EXPECT_UKM(UkmEntry::kMeanTimeBetweenRebuffersName,
1368              kWatchTime1.InMilliseconds() / kUnderflowCount1);
1369   EXPECT_UKM(UkmEntry::kAudioDecoderNameName, 2);
1370   EXPECT_UKM(UkmEntry::kVideoDecoderNameName, 5);
1371   EXPECT_UKM(UkmEntry::kRebuffersCountName, kUnderflowCount1);
1372   EXPECT_UKM(UkmEntry::kCompletedRebuffersCountName, kUnderflowCount1);
1373   EXPECT_UKM(UkmEntry::kCompletedRebuffersDurationName,
1374              kUnderflowDuration.InMilliseconds());
1375   EXPECT_UKM(UkmEntry::kVideoFramesDecodedName, kDecodedFrameCount1);
1376   EXPECT_UKM(UkmEntry::kVideoFramesDroppedName, kDroppedFrameCount1);
1377   EXPECT_UKM(UkmEntry::kAudioCodecName, secondary_properties1->audio_codec);
1378   EXPECT_UKM(UkmEntry::kVideoCodecName, secondary_properties1->video_codec);
1379   EXPECT_UKM(UkmEntry::kAudioCodecProfileName,
1380              static_cast<int64_t>(secondary_properties1->audio_codec_profile));
1381   EXPECT_UKM(UkmEntry::kVideoCodecProfileName,
1382              secondary_properties1->video_codec_profile);
1383   EXPECT_UKM(
1384       UkmEntry::kAudioEncryptionSchemeName,
1385       static_cast<int64_t>(secondary_properties1->audio_encryption_scheme));
1386   EXPECT_UKM(
1387       UkmEntry::kVideoEncryptionSchemeName,
1388       static_cast<int64_t>(secondary_properties1->video_encryption_scheme));
1389   EXPECT_UKM(UkmEntry::kVideoNaturalWidthName,
1390              secondary_properties1->natural_size.width());
1391   EXPECT_UKM(UkmEntry::kVideoNaturalHeightName,
1392              secondary_properties1->natural_size.height());
1393 
1394   // The second record should have...
1395   entry = entries[1];
1396   EXPECT_UKM(UkmEntry::kWatchTimeName, kWatchTime2.InMilliseconds());
1397   EXPECT_UKM(UkmEntry::kMeanTimeBetweenRebuffersName,
1398              kWatchTime2.InMilliseconds() / kUnderflowCount2);
1399   EXPECT_UKM(UkmEntry::kAudioDecoderNameName, 1);
1400   EXPECT_UKM(UkmEntry::kVideoDecoderNameName, 2);
1401   EXPECT_UKM(UkmEntry::kRebuffersCountName, kUnderflowCount2);
1402   EXPECT_UKM(UkmEntry::kCompletedRebuffersCountName, 0);
1403   EXPECT_UKM(UkmEntry::kCompletedRebuffersDurationName, 0);
1404   EXPECT_UKM(UkmEntry::kVideoFramesDecodedName, 0);
1405   EXPECT_UKM(UkmEntry::kVideoFramesDroppedName, 0);
1406   EXPECT_UKM(UkmEntry::kAudioCodecName, secondary_properties2->audio_codec);
1407   EXPECT_UKM(UkmEntry::kVideoCodecName, secondary_properties2->video_codec);
1408   EXPECT_UKM(UkmEntry::kAudioCodecProfileName,
1409              static_cast<int64_t>(secondary_properties2->audio_codec_profile));
1410   EXPECT_UKM(UkmEntry::kVideoCodecProfileName,
1411              secondary_properties2->video_codec_profile);
1412   EXPECT_UKM(
1413       UkmEntry::kAudioEncryptionSchemeName,
1414       static_cast<int64_t>(secondary_properties2->audio_encryption_scheme));
1415   EXPECT_UKM(
1416       UkmEntry::kVideoEncryptionSchemeName,
1417       static_cast<int64_t>(secondary_properties2->video_encryption_scheme));
1418   EXPECT_UKM(UkmEntry::kVideoNaturalWidthName,
1419              secondary_properties2->natural_size.width());
1420   EXPECT_UKM(UkmEntry::kVideoNaturalHeightName,
1421              secondary_properties2->natural_size.height());
1422 }
1423 
TEST_F(WatchTimeRecorderTest,MultipleSecondaryPropertiesRebufferCarryover)1424 TEST_F(WatchTimeRecorderTest, MultipleSecondaryPropertiesRebufferCarryover) {
1425   mojom::PlaybackPropertiesPtr properties = mojom::PlaybackProperties::New(
1426       true, true, false, false, true, true, false);
1427   mojom::SecondaryPlaybackPropertiesPtr secondary_properties1 =
1428       mojom::SecondaryPlaybackProperties::New(
1429           kCodecOpus, kCodecVP9, AudioCodecProfile::kUnknown,
1430           VP9PROFILE_PROFILE0, "MojoAudioDecoder", "MojoVideoDecoder",
1431           EncryptionScheme::kCbcs, EncryptionScheme::kCbcs,
1432           gfx::Size(400, 300));
1433   Initialize(properties.Clone());
1434   wtr_->UpdateSecondaryProperties(secondary_properties1.Clone());
1435 
1436   constexpr base::TimeDelta kUnderflowDuration =
1437       base::TimeDelta::FromMilliseconds(250);
1438   constexpr base::TimeDelta kWatchTime1 = base::TimeDelta::FromSeconds(54);
1439   const int kUnderflowCount1 = 2;
1440   wtr_->RecordWatchTime(WatchTimeKey::kAudioVideoAll, kWatchTime1);
1441   wtr_->UpdateUnderflowCount(kUnderflowCount1);
1442 
1443   // Complete all but one of the rebuffers in this update.
1444   wtr_->UpdateUnderflowDuration(kUnderflowCount1 - 1, kUnderflowDuration);
1445 
1446   mojom::SecondaryPlaybackPropertiesPtr secondary_properties2 =
1447       mojom::SecondaryPlaybackProperties::New(
1448           kCodecAAC, kCodecH264, AudioCodecProfile::kXHE_AAC, H264PROFILE_MAIN,
1449           "FFmpegAudioDecoder", "FFmpegVideoDecoder",
1450           EncryptionScheme::kUnencrypted, EncryptionScheme::kUnencrypted,
1451           gfx::Size(800, 600));
1452   wtr_->UpdateSecondaryProperties(secondary_properties2.Clone());
1453 
1454   constexpr base::TimeDelta kWatchTime2 = base::TimeDelta::FromSeconds(25);
1455   const int kUnderflowCount2 = 3;
1456 
1457   // Watch time and underflow counts continue to accumulate during property
1458   // changes, so we report the sum here instead of just kWatchTime2.
1459   wtr_->RecordWatchTime(WatchTimeKey::kAudioVideoAll,
1460                         kWatchTime1 + kWatchTime2);
1461   wtr_->UpdateUnderflowCount(kUnderflowCount1 + kUnderflowCount2);
1462 
1463   // Complete the last underflow in the new property set. Unfortunately this
1464   // means it will now be associated with this block of watch time. Use a non
1465   // integer multiplier to avoid incorrect carry over being hidden.
1466   wtr_->UpdateUnderflowDuration(kUnderflowCount1, kUnderflowDuration * 1.5);
1467 
1468   wtr_->OnError(PIPELINE_ERROR_DECODE);
1469   wtr_->OnDurationChanged(base::TimeDelta::FromSeconds(5125));
1470 
1471   wtr_.reset();
1472   base::RunLoop().RunUntilIdle();
1473 
1474   // All records should have the following:
1475   const auto& entries = test_recorder_->GetEntriesByName(UkmEntry::kEntryName);
1476   EXPECT_EQ(2u, entries.size());
1477   for (const auto* entry : entries) {
1478     test_recorder_->ExpectEntrySourceHasUrl(entry, GURL(kTestOrigin));
1479     EXPECT_UKM(UkmEntry::kIsBackgroundName, properties->is_background);
1480     EXPECT_UKM(UkmEntry::kIsMutedName, properties->is_muted);
1481     EXPECT_UKM(UkmEntry::kHasAudioName, properties->has_audio);
1482     EXPECT_UKM(UkmEntry::kHasVideoName, properties->has_video);
1483     EXPECT_UKM(UkmEntry::kIsEMEName, properties->is_eme);
1484     EXPECT_UKM(UkmEntry::kIsMSEName, properties->is_mse);
1485     EXPECT_UKM(UkmEntry::kAutoplayInitiatedName, false);
1486     EXPECT_UKM(UkmEntry::kDurationName, 5000000);
1487     EXPECT_HAS_UKM(UkmEntry::kPlayerIDName);
1488 
1489     // All records inherit the final pipeline status code.
1490     EXPECT_UKM(UkmEntry::kLastPipelineStatusName, PIPELINE_ERROR_DECODE);
1491   }
1492 
1493   // The first record should have...
1494   auto* entry = entries[0];
1495   EXPECT_UKM(UkmEntry::kWatchTimeName, kWatchTime1.InMilliseconds());
1496   EXPECT_UKM(UkmEntry::kMeanTimeBetweenRebuffersName,
1497              kWatchTime1.InMilliseconds() / kUnderflowCount1);
1498   EXPECT_UKM(UkmEntry::kAudioDecoderNameName, 2);
1499   EXPECT_UKM(UkmEntry::kVideoDecoderNameName, 5);
1500   EXPECT_UKM(UkmEntry::kRebuffersCountName, kUnderflowCount1);
1501   EXPECT_UKM(UkmEntry::kCompletedRebuffersCountName, kUnderflowCount1 - 1);
1502   EXPECT_UKM(UkmEntry::kCompletedRebuffersDurationName,
1503              kUnderflowDuration.InMilliseconds());
1504   EXPECT_UKM(UkmEntry::kAudioCodecName, secondary_properties1->audio_codec);
1505   EXPECT_UKM(UkmEntry::kVideoCodecName, secondary_properties1->video_codec);
1506   EXPECT_UKM(UkmEntry::kAudioCodecProfileName,
1507              static_cast<int64_t>(secondary_properties1->audio_codec_profile));
1508   EXPECT_UKM(UkmEntry::kVideoCodecProfileName,
1509              secondary_properties1->video_codec_profile);
1510   EXPECT_UKM(
1511       UkmEntry::kAudioEncryptionSchemeName,
1512       static_cast<int64_t>(secondary_properties1->audio_encryption_scheme));
1513   EXPECT_UKM(
1514       UkmEntry::kVideoEncryptionSchemeName,
1515       static_cast<int64_t>(secondary_properties1->video_encryption_scheme));
1516   EXPECT_UKM(UkmEntry::kVideoNaturalWidthName,
1517              secondary_properties1->natural_size.width());
1518   EXPECT_UKM(UkmEntry::kVideoNaturalHeightName,
1519              secondary_properties1->natural_size.height());
1520 
1521   // The second record should have...
1522   entry = entries[1];
1523   EXPECT_UKM(UkmEntry::kWatchTimeName, kWatchTime2.InMilliseconds());
1524   EXPECT_UKM(UkmEntry::kMeanTimeBetweenRebuffersName,
1525              kWatchTime2.InMilliseconds() / kUnderflowCount2);
1526   EXPECT_UKM(UkmEntry::kAudioDecoderNameName, 1);
1527   EXPECT_UKM(UkmEntry::kVideoDecoderNameName, 2);
1528   EXPECT_UKM(UkmEntry::kRebuffersCountName, kUnderflowCount2);
1529   EXPECT_UKM(UkmEntry::kCompletedRebuffersCountName, 1);
1530   EXPECT_UKM(UkmEntry::kCompletedRebuffersDurationName,
1531              (kUnderflowDuration * 1.5 - kUnderflowDuration).InMilliseconds());
1532   EXPECT_UKM(UkmEntry::kAudioCodecName, secondary_properties2->audio_codec);
1533   EXPECT_UKM(UkmEntry::kVideoCodecName, secondary_properties2->video_codec);
1534   EXPECT_UKM(UkmEntry::kAudioCodecProfileName,
1535              static_cast<int64_t>(secondary_properties2->audio_codec_profile));
1536   EXPECT_UKM(UkmEntry::kVideoCodecProfileName,
1537              secondary_properties2->video_codec_profile);
1538   EXPECT_UKM(
1539       UkmEntry::kAudioEncryptionSchemeName,
1540       static_cast<int64_t>(secondary_properties2->audio_encryption_scheme));
1541   EXPECT_UKM(
1542       UkmEntry::kVideoEncryptionSchemeName,
1543       static_cast<int64_t>(secondary_properties2->video_encryption_scheme));
1544   EXPECT_UKM(UkmEntry::kVideoNaturalWidthName,
1545              secondary_properties2->natural_size.width());
1546   EXPECT_UKM(UkmEntry::kVideoNaturalHeightName,
1547              secondary_properties2->natural_size.height());
1548 }
1549 
1550 #undef EXPECT_UKM
1551 #undef EXPECT_NO_UKM
1552 #undef EXPECT_HAS_UKM
1553 
TEST_F(WatchTimeRecorderTest,DISABLED_PrintExpectedDecoderNameHashes)1554 TEST_F(WatchTimeRecorderTest, DISABLED_PrintExpectedDecoderNameHashes) {
1555   const std::string kDecoderNames[] = {
1556       "FFmpegAudioDecoder", "FFmpegVideoDecoder",     "GpuVideoDecoder",
1557       "MojoVideoDecoder",   "MojoAudioDecoder",       "VpxVideoDecoder",
1558       "AomVideoDecoder",    "DecryptingAudioDecoder", "DecryptingVideoDecoder",
1559       "Dav1dVideoDecoder",  "FuchsiaVideoDecoder",    "MediaPlayer",
1560       "Gav1VideoDecoder"};
1561   printf("%18s = 0\n", "None");
1562   for (const auto& name : kDecoderNames)
1563     printf("%18s = 0x%08x\n", name.c_str(), base::PersistentHash(name));
1564 }
1565 
1566 }  // namespace media
1567