media_metrics_provider_unittest.cc 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315
  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. #include <stddef.h>
  5. #include <memory>
  6. #include "base/bind.h"
  7. #include "base/callback_helpers.h"
  8. #include "base/run_loop.h"
  9. #include "base/test/metrics/histogram_tester.h"
  10. #include "base/test/test_message_loop.h"
  11. #include "components/ukm/test_ukm_recorder.h"
  12. #include "media/mojo/services/media_metrics_provider.h"
  13. #include "media/mojo/services/watch_time_recorder.h"
  14. #include "mojo/public/cpp/bindings/remote.h"
  15. #include "services/metrics/public/cpp/ukm_builders.h"
  16. #include "testing/gmock/include/gmock/gmock.h"
  17. #include "testing/gtest/include/gtest/gtest.h"
  18. #include "url/gurl.h"
  19. using UkmEntry = ukm::builders::Media_WebMediaPlayerState;
  20. namespace media {
  21. constexpr char kTestOrigin[] = "https://test.google.com/";
  22. class MediaMetricsProviderTest : public testing::Test {
  23. public:
  24. MediaMetricsProviderTest() { ResetMetricRecorders(); }
  25. MediaMetricsProviderTest(const MediaMetricsProviderTest&) = delete;
  26. MediaMetricsProviderTest& operator=(const MediaMetricsProviderTest&) = delete;
  27. ~MediaMetricsProviderTest() override { base::RunLoop().RunUntilIdle(); }
  28. void Initialize(bool is_mse,
  29. bool is_incognito,
  30. bool is_top_frame,
  31. const std::string& origin,
  32. mojom::MediaURLScheme scheme,
  33. mojom::MediaStreamType media_stream_type =
  34. mojom::MediaStreamType::kNone) {
  35. source_id_ = test_recorder_->GetNewSourceID();
  36. test_recorder_->UpdateSourceURL(source_id_, GURL(origin));
  37. MediaMetricsProvider::Create(
  38. (is_incognito ? MediaMetricsProvider::BrowsingMode::kIncognito
  39. : MediaMetricsProvider::BrowsingMode::kNormal),
  40. (is_top_frame ? MediaMetricsProvider::FrameStatus::kTopFrame
  41. : MediaMetricsProvider::FrameStatus::kNotTopFrame),
  42. GetSourceId(), learning::FeatureValue(0),
  43. VideoDecodePerfHistory::SaveCallback(),
  44. MediaMetricsProvider::GetLearningSessionCallback(),
  45. base::BindRepeating(
  46. &MediaMetricsProviderTest::GetRecordAggregateWatchTimeCallback,
  47. base::Unretained(this)),
  48. base::BindRepeating(&MediaMetricsProviderTest::IsShuttingDown,
  49. base::Unretained(this)),
  50. provider_.BindNewPipeAndPassReceiver());
  51. provider_->Initialize(is_mse, scheme, media_stream_type);
  52. }
  53. ukm::SourceId GetSourceId() { return source_id_; }
  54. MediaMetricsProvider::RecordAggregateWatchTimeCallback
  55. GetRecordAggregateWatchTimeCallback() {
  56. return base::NullCallback();
  57. }
  58. MOCK_METHOD(bool, IsShuttingDown, ());
  59. void ResetMetricRecorders() {
  60. // Ensure cleared global before attempting to create a new TestUkmReporter.
  61. test_recorder_.reset();
  62. test_recorder_ = std::make_unique<ukm::TestAutoSetUkmRecorder>();
  63. }
  64. protected:
  65. base::TestMessageLoop message_loop_;
  66. std::unique_ptr<ukm::TestAutoSetUkmRecorder> test_recorder_;
  67. ukm::SourceId source_id_;
  68. mojo::Remote<mojom::MediaMetricsProvider> provider_;
  69. };
  70. #define EXPECT_UKM(name, value) \
  71. test_recorder_->ExpectEntryMetric(entry, name, value)
  72. #define EXPECT_NO_UKM(name) \
  73. EXPECT_FALSE(test_recorder_->EntryHasMetric(entry, name))
  74. #define EXPECT_HAS_UKM(name) \
  75. EXPECT_TRUE(test_recorder_->EntryHasMetric(entry, name));
  76. TEST_F(MediaMetricsProviderTest, TestUkm) {
  77. Initialize(true, false, true, kTestOrigin, mojom::MediaURLScheme::kHttp);
  78. provider_.reset();
  79. base::RunLoop().RunUntilIdle();
  80. {
  81. const auto& entries =
  82. test_recorder_->GetEntriesByName(UkmEntry::kEntryName);
  83. EXPECT_EQ(1u, entries.size());
  84. for (const auto* entry : entries) {
  85. test_recorder_->ExpectEntrySourceHasUrl(entry, GURL(kTestOrigin));
  86. EXPECT_HAS_UKM(UkmEntry::kPlayerIDName);
  87. EXPECT_UKM(UkmEntry::kIsTopFrameName, true);
  88. EXPECT_UKM(UkmEntry::kIsEMEName, false);
  89. EXPECT_UKM(UkmEntry::kKeySystemName, 0);
  90. EXPECT_UKM(UkmEntry::kIsHardwareSecureName, false);
  91. EXPECT_UKM(UkmEntry::kIsMSEName, true);
  92. EXPECT_UKM(UkmEntry::kFinalPipelineStatusName, PIPELINE_OK);
  93. // This is an MSE playback so the URL scheme should not be set.
  94. EXPECT_NO_UKM(UkmEntry::kURLSchemeName);
  95. // This is an MSE playback so no container is available.
  96. EXPECT_NO_UKM(UkmEntry::kContainerNameName);
  97. EXPECT_NO_UKM(UkmEntry::kTimeToMetadataName);
  98. EXPECT_NO_UKM(UkmEntry::kTimeToFirstFrameName);
  99. EXPECT_NO_UKM(UkmEntry::kTimeToPlayReadyName);
  100. }
  101. }
  102. // Now try one with different values and optional parameters set.
  103. const std::string kTestOrigin2 = "https://test2.google.com/";
  104. const std::string kClearKeyKeySystem = "org.w3.clearkey";
  105. const base::TimeDelta kMetadataTime = base::Seconds(1);
  106. const base::TimeDelta kFirstFrameTime = base::Seconds(2);
  107. const base::TimeDelta kPlayReadyTime = base::Seconds(3);
  108. ResetMetricRecorders();
  109. Initialize(false, false, false, kTestOrigin2, mojom::MediaURLScheme::kHttps);
  110. provider_->SetIsEME();
  111. provider_->SetKeySystem(kClearKeyKeySystem);
  112. provider_->SetIsHardwareSecure();
  113. provider_->SetAudioPipelineInfo(
  114. {false, false, AudioDecoderType::kMojo, EncryptionType::kClear});
  115. provider_->SetVideoPipelineInfo(
  116. {false, false, VideoDecoderType::kMojo, EncryptionType::kEncrypted});
  117. provider_->SetTimeToMetadata(kMetadataTime);
  118. provider_->SetTimeToFirstFrame(kFirstFrameTime);
  119. provider_->SetTimeToPlayReady(kPlayReadyTime);
  120. provider_->SetContainerName(container_names::CONTAINER_MOV);
  121. provider_->OnError(PIPELINE_ERROR_DECODE);
  122. provider_.reset();
  123. base::RunLoop().RunUntilIdle();
  124. {
  125. const auto& entries =
  126. test_recorder_->GetEntriesByName(UkmEntry::kEntryName);
  127. EXPECT_EQ(1u, entries.size());
  128. for (const auto* entry : entries) {
  129. test_recorder_->ExpectEntrySourceHasUrl(entry, GURL(kTestOrigin2));
  130. EXPECT_HAS_UKM(UkmEntry::kPlayerIDName);
  131. EXPECT_UKM(UkmEntry::kIsTopFrameName, false);
  132. EXPECT_UKM(UkmEntry::kIsEMEName, true);
  133. EXPECT_UKM(UkmEntry::kKeySystemName, 1);
  134. EXPECT_UKM(UkmEntry::kIsHardwareSecureName, true);
  135. EXPECT_UKM(UkmEntry::kAudioEncryptionTypeName,
  136. static_cast<int64_t>(EncryptionType::kClear));
  137. EXPECT_UKM(UkmEntry::kVideoEncryptionTypeName,
  138. static_cast<int64_t>(EncryptionType::kEncrypted));
  139. EXPECT_UKM(UkmEntry::kIsMSEName, false);
  140. EXPECT_UKM(UkmEntry::kURLSchemeName,
  141. static_cast<int64_t>(mojom::MediaURLScheme::kHttps));
  142. EXPECT_UKM(UkmEntry::kFinalPipelineStatusName, PIPELINE_ERROR_DECODE);
  143. EXPECT_UKM(UkmEntry::kTimeToMetadataName, kMetadataTime.InMilliseconds());
  144. EXPECT_UKM(UkmEntry::kTimeToFirstFrameName,
  145. kFirstFrameTime.InMilliseconds());
  146. EXPECT_UKM(UkmEntry::kTimeToPlayReadyName,
  147. kPlayReadyTime.InMilliseconds());
  148. EXPECT_UKM(UkmEntry::kContainerNameName, container_names::CONTAINER_MOV);
  149. }
  150. }
  151. }
  152. TEST_F(MediaMetricsProviderTest, TestUkmMediaStream) {
  153. Initialize(true, false, true, kTestOrigin, mojom::MediaURLScheme::kMissing,
  154. mojom::MediaStreamType::kRemote);
  155. provider_.reset();
  156. base::RunLoop().RunUntilIdle();
  157. {
  158. const auto& entries =
  159. test_recorder_->GetEntriesByName(UkmEntry::kEntryName);
  160. EXPECT_EQ(0u, entries.size());
  161. }
  162. // Now try one with different values and optional parameters set.
  163. const std::string kTestOrigin2 = "https://test2.google.com/";
  164. const base::TimeDelta kMetadataTime = base::Seconds(1);
  165. const base::TimeDelta kFirstFrameTime = base::Seconds(2);
  166. const base::TimeDelta kPlayReadyTime = base::Seconds(3);
  167. ResetMetricRecorders();
  168. Initialize(false, false, false, kTestOrigin2, mojom::MediaURLScheme::kMissing,
  169. mojom::MediaStreamType::kLocalDeviceCapture);
  170. provider_->SetIsEME();
  171. provider_->SetTimeToMetadata(kMetadataTime);
  172. provider_->SetTimeToFirstFrame(kFirstFrameTime);
  173. provider_->SetTimeToPlayReady(kPlayReadyTime);
  174. provider_->SetContainerName(container_names::CONTAINER_MOV);
  175. provider_->OnError(PIPELINE_ERROR_DECODE);
  176. provider_.reset();
  177. base::RunLoop().RunUntilIdle();
  178. {
  179. const auto& entries =
  180. test_recorder_->GetEntriesByName(UkmEntry::kEntryName);
  181. EXPECT_EQ(0u, entries.size());
  182. }
  183. }
  184. TEST_F(MediaMetricsProviderTest, TestPipelineUMA) {
  185. base::HistogramTester histogram_tester;
  186. Initialize(false, false, false, kTestOrigin, mojom::MediaURLScheme::kHttps);
  187. provider_->SetAudioPipelineInfo(
  188. {false, false, AudioDecoderType::kMojo, EncryptionType::kClear});
  189. provider_->SetVideoPipelineInfo(
  190. {false, false, VideoDecoderType::kMojo, EncryptionType::kEncrypted});
  191. provider_->SetHasAudio(AudioCodec::kVorbis);
  192. provider_->SetHasVideo(VideoCodec::kVP9);
  193. provider_->SetHasPlayed();
  194. provider_->SetHaveEnough();
  195. provider_.reset();
  196. base::RunLoop().RunUntilIdle();
  197. histogram_tester.ExpectBucketCount("Media.PipelineStatus.AudioVideo.VP9.SW",
  198. PIPELINE_OK, 1);
  199. histogram_tester.ExpectBucketCount("Media.VideoDecoderFallback", false, 1);
  200. histogram_tester.ExpectBucketCount("Media.HasEverPlayed", true, 1);
  201. }
  202. TEST_F(MediaMetricsProviderTest, TestPipelineUMAMediaStream) {
  203. base::HistogramTester histogram_tester;
  204. Initialize(false, false, false, kTestOrigin, mojom::MediaURLScheme::kHttps,
  205. mojom::MediaStreamType::kRemote);
  206. provider_->SetAudioPipelineInfo(
  207. {false, false, AudioDecoderType::kMojo, EncryptionType::kClear});
  208. provider_->SetVideoPipelineInfo(
  209. {false, false, VideoDecoderType::kMojo, EncryptionType::kEncrypted});
  210. provider_->SetHasAudio(AudioCodec::kVorbis);
  211. provider_->SetHasVideo(VideoCodec::kVP9);
  212. provider_->SetHasPlayed();
  213. provider_->SetHaveEnough();
  214. provider_.reset();
  215. base::RunLoop().RunUntilIdle();
  216. histogram_tester.ExpectBucketCount("Media.PipelineStatus.AudioVideo.VP9.SW",
  217. PIPELINE_OK, 0);
  218. histogram_tester.ExpectBucketCount("Media.VideoDecoderFallback", false, 0);
  219. histogram_tester.ExpectBucketCount("Media.HasEverPlayed", true, 0);
  220. }
  221. TEST_F(MediaMetricsProviderTest, TestPipelineUMANoAudioWithEme) {
  222. base::HistogramTester histogram_tester;
  223. Initialize(false, false, false, kTestOrigin, mojom::MediaURLScheme::kHttps);
  224. provider_->SetIsEME();
  225. provider_->SetVideoPipelineInfo(
  226. {true, true, VideoDecoderType::kMojo, EncryptionType::kEncrypted});
  227. provider_->SetHasVideo(VideoCodec::kAV1);
  228. provider_->SetHasPlayed();
  229. provider_->SetHaveEnough();
  230. provider_.reset();
  231. base::RunLoop().RunUntilIdle();
  232. histogram_tester.ExpectBucketCount("Media.PipelineStatus.VideoOnly",
  233. PIPELINE_OK, 1);
  234. histogram_tester.ExpectBucketCount("Media.VideoDecoderFallback", false, 1);
  235. histogram_tester.ExpectBucketCount("Media.HasEverPlayed", true, 1);
  236. histogram_tester.ExpectBucketCount("Media.EME.IsIncognito", false, 1);
  237. }
  238. TEST_F(MediaMetricsProviderTest, TestPipelineUMADecoderFallback) {
  239. base::HistogramTester histogram_tester;
  240. Initialize(false, false, false, kTestOrigin, mojom::MediaURLScheme::kHttps);
  241. provider_->SetIsEME();
  242. provider_->SetAudioPipelineInfo(
  243. {false, false, AudioDecoderType::kMojo, EncryptionType::kClear});
  244. provider_->SetVideoPipelineInfo(
  245. {true, false, VideoDecoderType::kD3D11, EncryptionType::kEncrypted});
  246. provider_->SetHasVideo(VideoCodec::kVP9);
  247. provider_->SetHasAudio(AudioCodec::kVorbis);
  248. provider_->SetHasPlayed();
  249. provider_->SetHaveEnough();
  250. provider_->SetVideoPipelineInfo({true, false, VideoDecoderType::kFFmpeg});
  251. provider_.reset();
  252. base::RunLoop().RunUntilIdle();
  253. histogram_tester.ExpectBucketCount("Media.PipelineStatus.AudioVideo.VP9.HW",
  254. PIPELINE_OK, 1);
  255. histogram_tester.ExpectBucketCount("Media.VideoDecoderFallback", true, 1);
  256. histogram_tester.ExpectBucketCount("Media.HasEverPlayed", true, 1);
  257. }
  258. TEST_F(MediaMetricsProviderTest, TestPipelineUMARendererType) {
  259. base::HistogramTester histogram_tester;
  260. Initialize(false, false, false, kTestOrigin, mojom::MediaURLScheme::kHttps);
  261. provider_->SetIsEME();
  262. provider_->SetRendererType(RendererType::kMediaFoundation);
  263. provider_->SetHasVideo(VideoCodec::kVP9);
  264. provider_->SetHasAudio(AudioCodec::kVorbis);
  265. provider_->SetHasPlayed();
  266. provider_->SetHaveEnough();
  267. provider_.reset();
  268. base::RunLoop().RunUntilIdle();
  269. histogram_tester.ExpectBucketCount(
  270. "Media.PipelineStatus.AudioVideo.VP9.MediaFoundationRenderer",
  271. PIPELINE_OK, 1);
  272. }
  273. // Note: Tests for various Acquire* methods are contained with the unittests for
  274. // their respective classes.
  275. #undef EXPECT_UKM
  276. #undef EXPECT_NO_UKM
  277. #undef EXPECT_HAS_UKM
  278. } // namespace media