Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(47)

Side by Side Diff: content/browser/media/media_internals.cc

Issue 2814843005: media: Add incognito EME playback UMA (Closed)
Patch Set: enum Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | media/blink/webmediaplayer_impl.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "content/browser/media/media_internals.h" 5 #include "content/browser/media/media_internals.h"
6 6
7 #include <stddef.h> 7 #include <stddef.h>
8 8
9 #include <memory> 9 #include <memory>
10 #include <tuple>
10 #include <utility> 11 #include <utility>
11 12
12 #include "base/containers/flat_map.h" 13 #include "base/containers/flat_map.h"
13 #include "base/containers/flat_set.h" 14 #include "base/containers/flat_set.h"
14 #include "base/macros.h" 15 #include "base/macros.h"
15 #include "base/metrics/histogram_macros.h" 16 #include "base/metrics/histogram_macros.h"
16 #include "base/strings/string16.h" 17 #include "base/strings/string16.h"
17 #include "base/strings/string_number_conversions.h" 18 #include "base/strings/string_number_conversions.h"
18 #include "base/strings/stringprintf.h" 19 #include "base/strings/stringprintf.h"
19 #include "build/build_config.h" 20 #include "build/build_config.h"
20 #include "content/browser/renderer_host/media/media_stream_manager.h" 21 #include "content/browser/renderer_host/media/media_stream_manager.h"
22 #include "content/public/browser/browser_context.h"
21 #include "content/public/browser/browser_thread.h" 23 #include "content/public/browser/browser_thread.h"
22 #include "content/public/browser/notification_service.h" 24 #include "content/public/browser/notification_service.h"
23 #include "content/public/browser/notification_types.h" 25 #include "content/public/browser/notification_types.h"
24 #include "content/public/browser/render_frame_host.h" 26 #include "content/public/browser/render_frame_host.h"
25 #include "content/public/browser/render_process_host.h" 27 #include "content/public/browser/render_process_host.h"
26 #include "content/public/browser/web_contents.h" 28 #include "content/public/browser/web_contents.h"
27 #include "content/public/browser/web_ui.h" 29 #include "content/public/browser/web_ui.h"
28 #include "media/base/audio_parameters.h" 30 #include "media/base/audio_parameters.h"
29 #include "media/base/media_log_event.h" 31 #include "media/base/media_log_event.h"
30 #include "media/filters/gpu_video_decoder.h" 32 #include "media/filters/gpu_video_decoder.h"
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
85 case media::AudioParameters::AUDIO_BITSTREAM_EAC3: 87 case media::AudioParameters::AUDIO_BITSTREAM_EAC3:
86 return "eac3"; 88 return "eac3";
87 case media::AudioParameters::AUDIO_FAKE: 89 case media::AudioParameters::AUDIO_FAKE:
88 return "fake"; 90 return "fake";
89 } 91 }
90 92
91 NOTREACHED(); 93 NOTREACHED();
92 return "unknown"; 94 return "unknown";
93 } 95 }
94 96
97 // Whether the player is in incognito mode or ChromeOS guest mode.
98 bool IsIncognito(int render_process_id) {
99 content::RenderProcessHost* render_process_host =
100 content::RenderProcessHost::FromID(render_process_id);
101 if (!render_process_host) {
102 // This could happen in tests.
Wez 2017/08/15 20:13:51 This also happens if you start a Hangout, for exam
103 LOG(ERROR) << "Cannot get RenderProcessHost";
104 return false;
105 }
106
107 content::BrowserContext* browser_context =
108 render_process_host->GetBrowserContext();
109 DCHECK(browser_context);
110
111 return browser_context->IsOffTheRecord();
112 }
113
95 const char kAudioLogStatusKey[] = "status"; 114 const char kAudioLogStatusKey[] = "status";
96 const char kAudioLogUpdateFunction[] = "media.updateAudioComponent"; 115 const char kAudioLogUpdateFunction[] = "media.updateAudioComponent";
97 116
98 } // namespace 117 } // namespace
99 118
100 namespace content { 119 namespace content {
101 120
102 class AudioLogImpl : public media::AudioLog { 121 class AudioLogImpl : public media::AudioLog {
103 public: 122 public:
104 AudioLogImpl(int owner_id, 123 AudioLogImpl(int owner_id,
(...skipping 182 matching lines...) Expand 10 before | Expand all | Expand 10 after
287 // the player state. 306 // the player state.
288 void OnProcessTerminated(int render_process_id); 307 void OnProcessTerminated(int render_process_id);
289 308
290 // Helper function to save the event payload to RendererPlayerMap. 309 // Helper function to save the event payload to RendererPlayerMap.
291 void SavePlayerState(int render_process_id, 310 void SavePlayerState(int render_process_id,
292 const media::MediaLogEvent& event); 311 const media::MediaLogEvent& event);
293 312
294 private: 313 private:
295 using WatchTimeInfo = base::flat_map<base::StringPiece, base::TimeDelta>; 314 using WatchTimeInfo = base::flat_map<base::StringPiece, base::TimeDelta>;
296 struct PipelineInfo { 315 struct PipelineInfo {
316 explicit PipelineInfo(bool is_incognito) : is_incognito(is_incognito) {}
317
297 bool has_pipeline = false; 318 bool has_pipeline = false;
298 bool has_ever_played = false; 319 bool has_ever_played = false;
299 bool has_reached_have_enough = false; 320 bool has_reached_have_enough = false;
300 media::PipelineStatus last_pipeline_status = media::PIPELINE_OK; 321 media::PipelineStatus last_pipeline_status = media::PIPELINE_OK;
301 bool has_audio = false; 322 bool has_audio = false;
302 bool has_video = false; 323 bool has_video = false;
303 bool video_dds = false; 324 bool video_dds = false;
304 bool video_decoder_changed = false; 325 bool video_decoder_changed = false;
326 bool has_cdm = false;
327 bool is_incognito = false;
305 std::string audio_codec_name; 328 std::string audio_codec_name;
306 std::string video_codec_name; 329 std::string video_codec_name;
307 std::string video_decoder; 330 std::string video_decoder;
308 WatchTimeInfo watch_time_info; 331 WatchTimeInfo watch_time_info;
309 }; 332 };
310 333
311 // Helper function to report PipelineStatus associated with a player to UMA. 334 // Helper function to report PipelineStatus associated with a player to UMA.
312 void ReportUMAForPipelineStatus(const PipelineInfo& player_info); 335 void ReportUMAForPipelineStatus(const PipelineInfo& player_info);
313 336
314 // Helper to generate PipelineStatus UMA name for AudioVideo streams. 337 // Helper to generate PipelineStatus UMA name for AudioVideo streams.
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
359 }; 382 };
360 383
361 MediaInternals::MediaInternalsUMAHandler::MediaInternalsUMAHandler() 384 MediaInternals::MediaInternalsUMAHandler::MediaInternalsUMAHandler()
362 : watch_time_keys_(media::MediaLog::GetWatchTimeKeys()), 385 : watch_time_keys_(media::MediaLog::GetWatchTimeKeys()),
363 watch_time_power_keys_(media::MediaLog::GetWatchTimePowerKeys()) {} 386 watch_time_power_keys_(media::MediaLog::GetWatchTimePowerKeys()) {}
364 387
365 void MediaInternals::MediaInternalsUMAHandler::SavePlayerState( 388 void MediaInternals::MediaInternalsUMAHandler::SavePlayerState(
366 int render_process_id, 389 int render_process_id,
367 const media::MediaLogEvent& event) { 390 const media::MediaLogEvent& event) {
368 DCHECK_CURRENTLY_ON(BrowserThread::UI); 391 DCHECK_CURRENTLY_ON(BrowserThread::UI);
369 PlayerInfoMap& player_info = renderer_info_[render_process_id]; 392
393 PlayerInfoMap& player_info_map = renderer_info_[render_process_id];
394
395 auto it = player_info_map.find(event.id);
396 if (it == player_info_map.end()) {
397 bool success = false;
398 std::tie(it, success) = player_info_map.emplace(
399 std::make_pair(event.id, PipelineInfo(IsIncognito(render_process_id))));
400 if (!success) {
401 LOG(ERROR) << "Failed to insert a new PipelineInfo.";
402 return;
403 }
404 }
405
406 PipelineInfo& player_info = it->second;
407
370 switch (event.type) { 408 switch (event.type) {
371 case media::MediaLogEvent::PLAY: { 409 case media::MediaLogEvent::PLAY: {
372 player_info[event.id].has_ever_played = true; 410 player_info.has_ever_played = true;
373 break; 411 break;
374 } 412 }
375 case media::MediaLogEvent::PIPELINE_STATE_CHANGED: { 413 case media::MediaLogEvent::PIPELINE_STATE_CHANGED: {
376 player_info[event.id].has_pipeline = true; 414 player_info.has_pipeline = true;
377 break; 415 break;
378 } 416 }
379 case media::MediaLogEvent::PIPELINE_ERROR: { 417 case media::MediaLogEvent::PIPELINE_ERROR: {
380 int status; 418 int status;
381 event.params.GetInteger("pipeline_error", &status); 419 event.params.GetInteger("pipeline_error", &status);
382 player_info[event.id].last_pipeline_status = 420 player_info.last_pipeline_status =
383 static_cast<media::PipelineStatus>(status); 421 static_cast<media::PipelineStatus>(status);
384 break; 422 break;
385 } 423 }
386 case media::MediaLogEvent::PROPERTY_CHANGE: 424 case media::MediaLogEvent::PROPERTY_CHANGE:
387 if (event.params.HasKey("found_audio_stream")) { 425 if (event.params.HasKey("found_audio_stream")) {
388 event.params.GetBoolean("found_audio_stream", 426 event.params.GetBoolean("found_audio_stream", &player_info.has_audio);
389 &player_info[event.id].has_audio);
390 } 427 }
391 if (event.params.HasKey("found_video_stream")) { 428 if (event.params.HasKey("found_video_stream")) {
392 event.params.GetBoolean("found_video_stream", 429 event.params.GetBoolean("found_video_stream", &player_info.has_video);
393 &player_info[event.id].has_video);
394 } 430 }
395 if (event.params.HasKey("audio_codec_name")) { 431 if (event.params.HasKey("audio_codec_name")) {
396 event.params.GetString("audio_codec_name", 432 event.params.GetString("audio_codec_name",
397 &player_info[event.id].audio_codec_name); 433 &player_info.audio_codec_name);
398 } 434 }
399 if (event.params.HasKey("video_codec_name")) { 435 if (event.params.HasKey("video_codec_name")) {
400 event.params.GetString("video_codec_name", 436 event.params.GetString("video_codec_name",
401 &player_info[event.id].video_codec_name); 437 &player_info.video_codec_name);
402 } 438 }
403 if (event.params.HasKey("video_decoder")) { 439 if (event.params.HasKey("video_decoder")) {
404 std::string previous_video_decoder(player_info[event.id].video_decoder); 440 std::string previous_video_decoder(player_info.video_decoder);
405 event.params.GetString("video_decoder", 441 event.params.GetString("video_decoder", &player_info.video_decoder);
406 &player_info[event.id].video_decoder);
407 if (!previous_video_decoder.empty() && 442 if (!previous_video_decoder.empty() &&
408 previous_video_decoder != player_info[event.id].video_decoder) { 443 previous_video_decoder != player_info.video_decoder) {
409 player_info[event.id].video_decoder_changed = true; 444 player_info.video_decoder_changed = true;
410 } 445 }
411 } 446 }
412 if (event.params.HasKey("video_dds")) { 447 if (event.params.HasKey("video_dds")) {
413 event.params.GetBoolean("video_dds", &player_info[event.id].video_dds); 448 event.params.GetBoolean("video_dds", &player_info.video_dds);
449 }
450 if (event.params.HasKey("has_cdm")) {
451 event.params.GetBoolean("has_cdm", &player_info.has_cdm);
414 } 452 }
415 if (event.params.HasKey("pipeline_buffering_state")) { 453 if (event.params.HasKey("pipeline_buffering_state")) {
416 std::string buffering_state; 454 std::string buffering_state;
417 event.params.GetString("pipeline_buffering_state", &buffering_state); 455 event.params.GetString("pipeline_buffering_state", &buffering_state);
418 if (buffering_state == "BUFFERING_HAVE_ENOUGH") 456 if (buffering_state == "BUFFERING_HAVE_ENOUGH")
419 player_info[event.id].has_reached_have_enough = true; 457 player_info.has_reached_have_enough = true;
420 } 458 }
421 break; 459 break;
422 case media::MediaLogEvent::Type::WATCH_TIME_UPDATE: { 460 case media::MediaLogEvent::Type::WATCH_TIME_UPDATE: {
423 DVLOG(2) << "Processing watch time update."; 461 DVLOG(2) << "Processing watch time update.";
424 PipelineInfo& info = player_info[event.id];
425 462
426 for (base::DictionaryValue::Iterator it(event.params); !it.IsAtEnd(); 463 for (base::DictionaryValue::Iterator it(event.params); !it.IsAtEnd();
427 it.Advance()) { 464 it.Advance()) {
428 // Don't log random histogram keys from the untrusted renderer, instead 465 // Don't log random histogram keys from the untrusted renderer, instead
429 // ensure they are from our list of known keys. Use |key_name| from the 466 // ensure they are from our list of known keys. Use |key_name| from the
430 // key map, since otherwise we'll end up storing a StringPiece which 467 // key map, since otherwise we'll end up storing a StringPiece which
431 // points into the soon-to-be-destructed DictionaryValue. 468 // points into the soon-to-be-destructed DictionaryValue.
432 auto key_name = watch_time_keys_.find(it.key()); 469 auto key_name = watch_time_keys_.find(it.key());
433 if (key_name == watch_time_keys_.end()) 470 if (key_name == watch_time_keys_.end())
434 continue; 471 continue;
435 info.watch_time_info[*key_name] = 472 player_info.watch_time_info[*key_name] =
436 base::TimeDelta::FromSecondsD(it.value().GetDouble()); 473 base::TimeDelta::FromSecondsD(it.value().GetDouble());
437 } 474 }
438 475
439 if (event.params.HasKey(media::MediaLog::kWatchTimeFinalize)) { 476 if (event.params.HasKey(media::MediaLog::kWatchTimeFinalize)) {
440 bool should_finalize; 477 bool should_finalize;
441 DCHECK(event.params.GetBoolean(media::MediaLog::kWatchTimeFinalize, 478 DCHECK(event.params.GetBoolean(media::MediaLog::kWatchTimeFinalize,
442 &should_finalize) && 479 &should_finalize) &&
443 should_finalize); 480 should_finalize);
444 FinalizeWatchTime(info.has_video, &info.watch_time_info, 481 FinalizeWatchTime(player_info.has_video, &player_info.watch_time_info,
445 FinalizeType::EVERYTHING); 482 FinalizeType::EVERYTHING);
446 } else if (event.params.HasKey( 483 } else if (event.params.HasKey(
447 media::MediaLog::kWatchTimeFinalizePower)) { 484 media::MediaLog::kWatchTimeFinalizePower)) {
448 bool should_finalize; 485 bool should_finalize;
449 DCHECK(event.params.GetBoolean(media::MediaLog::kWatchTimeFinalizePower, 486 DCHECK(event.params.GetBoolean(media::MediaLog::kWatchTimeFinalizePower,
450 &should_finalize) && 487 &should_finalize) &&
451 should_finalize); 488 should_finalize);
452 FinalizeWatchTime(info.has_video, &info.watch_time_info, 489 FinalizeWatchTime(player_info.has_video, &player_info.watch_time_info,
453 FinalizeType::POWER_ONLY); 490 FinalizeType::POWER_ONLY);
454 } 491 }
455 break; 492 break;
456 } 493 }
457 case media::MediaLogEvent::Type::WEBMEDIAPLAYER_DESTROYED: { 494 case media::MediaLogEvent::Type::WEBMEDIAPLAYER_DESTROYED: {
458 // Upon player destruction report UMA data; if the player is not torn down 495 // Upon player destruction report UMA data; if the player is not torn down
459 // before process exit, it will be logged during OnProcessTerminated(). 496 // before process exit, it will be logged during OnProcessTerminated().
460 auto it = player_info.find(event.id); 497 auto it = player_info_map.find(event.id);
461 if (it == player_info.end()) 498 if (it == player_info_map.end())
462 break; 499 break;
463 500
464 ReportUMAForPipelineStatus(it->second); 501 ReportUMAForPipelineStatus(it->second);
465 FinalizeWatchTime(it->second.has_video, &(it->second.watch_time_info), 502 FinalizeWatchTime(it->second.has_video, &(it->second.watch_time_info),
466 FinalizeType::EVERYTHING); 503 FinalizeType::EVERYTHING);
467 player_info.erase(it); 504 player_info_map.erase(it);
468 } 505 }
469 default: 506 default:
470 break; 507 break;
471 } 508 }
472 return; 509 return;
473 } 510 }
474 511
475 std::string MediaInternals::MediaInternalsUMAHandler::GetUMANameForAVStream( 512 std::string MediaInternals::MediaInternalsUMAHandler::GetUMANameForAVStream(
476 const PipelineInfo& player_info) { 513 const PipelineInfo& player_info) {
477 DCHECK_CURRENTLY_ON(BrowserThread::UI); 514 DCHECK_CURRENTLY_ON(BrowserThread::UI);
(...skipping 21 matching lines...) Expand all
499 } 536 }
500 537
501 if (player_info.video_decoder == media::GpuVideoDecoder::kDecoderName) { 538 if (player_info.video_decoder == media::GpuVideoDecoder::kDecoderName) {
502 uma_name += "HW"; 539 uma_name += "HW";
503 } else { 540 } else {
504 uma_name += "SW"; 541 uma_name += "SW";
505 } 542 }
506 return uma_name; 543 return uma_name;
507 } 544 }
508 545
546 // TODO(xhwang): This function reports more metrics than just pipeline status
547 // and should be renamed. Similarly, PipelineInfo should be PlayerInfo.
509 void MediaInternals::MediaInternalsUMAHandler::ReportUMAForPipelineStatus( 548 void MediaInternals::MediaInternalsUMAHandler::ReportUMAForPipelineStatus(
510 const PipelineInfo& player_info) { 549 const PipelineInfo& player_info) {
511 DCHECK_CURRENTLY_ON(BrowserThread::UI); 550 DCHECK_CURRENTLY_ON(BrowserThread::UI);
512 551
513 // Don't log pipeline status for players which don't actually have a pipeline; 552 // Don't log pipeline status for players which don't actually have a pipeline;
514 // e.g., the Android MediaSourcePlayer implementation. 553 // e.g., the Android MediaSourcePlayer implementation.
515 if (!player_info.has_pipeline) 554 if (!player_info.has_pipeline)
516 return; 555 return;
517 556
518 if (player_info.has_video && player_info.has_audio) { 557 if (player_info.has_video && player_info.has_audio) {
(...skipping 22 matching lines...) Expand all
541 // was reported. 580 // was reported.
542 if (!player_info.video_decoder.empty()) { 581 if (!player_info.video_decoder.empty()) {
543 UMA_HISTOGRAM_BOOLEAN("Media.VideoDecoderFallback", 582 UMA_HISTOGRAM_BOOLEAN("Media.VideoDecoderFallback",
544 player_info.video_decoder_changed); 583 player_info.video_decoder_changed);
545 } 584 }
546 585
547 // Report whether this player ever saw a playback event. Used to measure the 586 // Report whether this player ever saw a playback event. Used to measure the
548 // effectiveness of efforts to reduce loaded-but-never-used players. 587 // effectiveness of efforts to reduce loaded-but-never-used players.
549 if (player_info.has_reached_have_enough) 588 if (player_info.has_reached_have_enough)
550 UMA_HISTOGRAM_BOOLEAN("Media.HasEverPlayed", player_info.has_ever_played); 589 UMA_HISTOGRAM_BOOLEAN("Media.HasEverPlayed", player_info.has_ever_played);
590
591 // Report whether an encrypted playback is in incognito window, excluding
592 // never-used players.
593 if (player_info.has_cdm && player_info.has_ever_played)
594 UMA_HISTOGRAM_BOOLEAN("Media.EME.IsIncognito", player_info.is_incognito);
551 } 595 }
552 596
553 void MediaInternals::MediaInternalsUMAHandler::OnProcessTerminated( 597 void MediaInternals::MediaInternalsUMAHandler::OnProcessTerminated(
554 int render_process_id) { 598 int render_process_id) {
555 DCHECK_CURRENTLY_ON(BrowserThread::UI); 599 DCHECK_CURRENTLY_ON(BrowserThread::UI);
556 600
557 auto players_it = renderer_info_.find(render_process_id); 601 auto players_it = renderer_info_.find(render_process_id);
558 if (players_it == renderer_info_.end()) 602 if (players_it == renderer_info_.end())
559 return; 603 return;
560 auto it = players_it->second.begin(); 604 auto it = players_it->second.begin();
(...skipping 262 matching lines...) Expand 10 before | Expand all | Expand 10 after
823 audio_streams_cached_data_.GetDictionary(cache_key, &existing_dict)); 867 audio_streams_cached_data_.GetDictionary(cache_key, &existing_dict));
824 existing_dict->MergeDictionary(value); 868 existing_dict->MergeDictionary(value);
825 } 869 }
826 } 870 }
827 871
828 if (CanUpdate()) 872 if (CanUpdate())
829 SendUpdate(SerializeUpdate(function, value)); 873 SendUpdate(SerializeUpdate(function, value));
830 } 874 }
831 875
832 } // namespace content 876 } // namespace content
OLDNEW
« no previous file with comments | « no previous file | media/blink/webmediaplayer_impl.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698