OLD | NEW |
---|---|
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/macros.h" | 13 #include "base/macros.h" |
13 #include "base/metrics/histogram_macros.h" | 14 #include "base/metrics/histogram_macros.h" |
14 #include "base/strings/string16.h" | 15 #include "base/strings/string16.h" |
15 #include "base/strings/string_number_conversions.h" | 16 #include "base/strings/string_number_conversions.h" |
16 #include "base/strings/stringprintf.h" | 17 #include "base/strings/stringprintf.h" |
17 #include "build/build_config.h" | 18 #include "build/build_config.h" |
18 #include "content/browser/renderer_host/media/media_stream_manager.h" | 19 #include "content/browser/renderer_host/media/media_stream_manager.h" |
20 #include "content/public/browser/browser_context.h" | |
19 #include "content/public/browser/browser_thread.h" | 21 #include "content/public/browser/browser_thread.h" |
20 #include "content/public/browser/notification_service.h" | 22 #include "content/public/browser/notification_service.h" |
21 #include "content/public/browser/notification_types.h" | 23 #include "content/public/browser/notification_types.h" |
22 #include "content/public/browser/render_frame_host.h" | 24 #include "content/public/browser/render_frame_host.h" |
23 #include "content/public/browser/render_process_host.h" | 25 #include "content/public/browser/render_process_host.h" |
24 #include "content/public/browser/web_contents.h" | 26 #include "content/public/browser/web_contents.h" |
25 #include "content/public/browser/web_ui.h" | 27 #include "content/public/browser/web_ui.h" |
26 #include "media/base/audio_parameters.h" | 28 #include "media/base/audio_parameters.h" |
27 #include "media/base/media_log_event.h" | 29 #include "media/base/media_log_event.h" |
28 #include "media/filters/gpu_video_decoder.h" | 30 #include "media/filters/gpu_video_decoder.h" |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
83 case media::AudioParameters::AUDIO_BITSTREAM_EAC3: | 85 case media::AudioParameters::AUDIO_BITSTREAM_EAC3: |
84 return "eac3"; | 86 return "eac3"; |
85 case media::AudioParameters::AUDIO_FAKE: | 87 case media::AudioParameters::AUDIO_FAKE: |
86 return "fake"; | 88 return "fake"; |
87 } | 89 } |
88 | 90 |
89 NOTREACHED(); | 91 NOTREACHED(); |
90 return "unknown"; | 92 return "unknown"; |
91 } | 93 } |
92 | 94 |
95 // Whether the player is in incognito mode or ChromeOS guest mode. | |
96 bool IsIncognito(int render_process_id) { | |
97 content::RenderProcessHost* render_process_host = | |
98 content::RenderProcessHost::FromID(render_process_id); | |
99 DCHECK(render_process_host); | |
DaleCurtis
2017/04/13 22:46:25
I think these might fail actually; the message com
| |
100 | |
101 content::BrowserContext* browser_context = | |
102 render_process_host->GetBrowserContext(); | |
103 DCHECK(browser_context); | |
104 | |
105 return browser_context->IsOffTheRecord(); | |
106 } | |
107 | |
93 const char kAudioLogStatusKey[] = "status"; | 108 const char kAudioLogStatusKey[] = "status"; |
94 const char kAudioLogUpdateFunction[] = "media.updateAudioComponent"; | 109 const char kAudioLogUpdateFunction[] = "media.updateAudioComponent"; |
95 | 110 |
96 } // namespace | 111 } // namespace |
97 | 112 |
98 namespace content { | 113 namespace content { |
99 | 114 |
100 class AudioLogImpl : public media::AudioLog { | 115 class AudioLogImpl : public media::AudioLog { |
101 public: | 116 public: |
102 AudioLogImpl(int owner_id, | 117 AudioLogImpl(int owner_id, |
(...skipping 191 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
294 base::TimeDelta all_watch_time = media::kNoTimestamp; | 309 base::TimeDelta all_watch_time = media::kNoTimestamp; |
295 base::TimeDelta mse_watch_time = media::kNoTimestamp; | 310 base::TimeDelta mse_watch_time = media::kNoTimestamp; |
296 base::TimeDelta eme_watch_time = media::kNoTimestamp; | 311 base::TimeDelta eme_watch_time = media::kNoTimestamp; |
297 base::TimeDelta src_watch_time = media::kNoTimestamp; | 312 base::TimeDelta src_watch_time = media::kNoTimestamp; |
298 base::TimeDelta ac_watch_time = media::kNoTimestamp; | 313 base::TimeDelta ac_watch_time = media::kNoTimestamp; |
299 base::TimeDelta battery_watch_time = media::kNoTimestamp; | 314 base::TimeDelta battery_watch_time = media::kNoTimestamp; |
300 base::TimeDelta embedded_experience_watch_time = media::kNoTimestamp; | 315 base::TimeDelta embedded_experience_watch_time = media::kNoTimestamp; |
301 }; | 316 }; |
302 | 317 |
303 struct PipelineInfo { | 318 struct PipelineInfo { |
319 explicit PipelineInfo(bool is_incognito) : is_incognito(is_incognito) {} | |
320 | |
304 bool has_pipeline = false; | 321 bool has_pipeline = false; |
305 bool has_ever_played = false; | 322 bool has_ever_played = false; |
306 bool has_reached_have_enough = false; | 323 bool has_reached_have_enough = false; |
307 media::PipelineStatus last_pipeline_status = media::PIPELINE_OK; | 324 media::PipelineStatus last_pipeline_status = media::PIPELINE_OK; |
308 bool has_audio = false; | 325 bool has_audio = false; |
309 bool has_video = false; | 326 bool has_video = false; |
310 bool video_dds = false; | 327 bool video_dds = false; |
311 bool video_decoder_changed = false; | 328 bool video_decoder_changed = false; |
329 bool has_cdm = false; | |
330 bool is_incognito = false; | |
312 std::string audio_codec_name; | 331 std::string audio_codec_name; |
313 std::string video_codec_name; | 332 std::string video_codec_name; |
314 std::string video_decoder; | 333 std::string video_decoder; |
315 WatchTimeInfo watch_time_info; | 334 WatchTimeInfo watch_time_info; |
316 }; | 335 }; |
317 | 336 |
318 // Helper function to report PipelineStatus associated with a player to UMA. | 337 // Helper function to report PipelineStatus associated with a player to UMA. |
319 void ReportUMAForPipelineStatus(const PipelineInfo& player_info); | 338 void ReportUMAForPipelineStatus(const PipelineInfo& player_info); |
320 | 339 |
321 // Helper to generate PipelineStatus UMA name for AudioVideo streams. | 340 // Helper to generate PipelineStatus UMA name for AudioVideo streams. |
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
395 DISALLOW_COPY_AND_ASSIGN(MediaInternalsUMAHandler); | 414 DISALLOW_COPY_AND_ASSIGN(MediaInternalsUMAHandler); |
396 }; | 415 }; |
397 | 416 |
398 MediaInternals::MediaInternalsUMAHandler::MediaInternalsUMAHandler() { | 417 MediaInternals::MediaInternalsUMAHandler::MediaInternalsUMAHandler() { |
399 } | 418 } |
400 | 419 |
401 void MediaInternals::MediaInternalsUMAHandler::SavePlayerState( | 420 void MediaInternals::MediaInternalsUMAHandler::SavePlayerState( |
402 int render_process_id, | 421 int render_process_id, |
403 const media::MediaLogEvent& event) { | 422 const media::MediaLogEvent& event) { |
404 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 423 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
405 PlayerInfoMap& player_info = renderer_info_[render_process_id]; | 424 |
425 PlayerInfoMap& player_info_map = renderer_info_[render_process_id]; | |
426 | |
427 auto it = player_info_map.find(event.id); | |
428 if (it == player_info_map.end()) { | |
429 bool success = false; | |
430 std::tie(it, success) = player_info_map.emplace( | |
DaleCurtis
2017/04/13 22:46:25
Neat hadn't seen this before, but how can we ever
| |
431 std::make_pair(event.id, PipelineInfo(IsIncognito(render_process_id)))); | |
432 if (!success) { | |
433 LOG(ERROR) << "Failed to insert a new PipelineInfo."; | |
434 return; | |
435 } | |
436 } | |
437 | |
438 PipelineInfo& player_info = it->second; | |
439 | |
406 switch (event.type) { | 440 switch (event.type) { |
407 case media::MediaLogEvent::PLAY: { | 441 case media::MediaLogEvent::PLAY: { |
408 player_info[event.id].has_ever_played = true; | 442 player_info.has_ever_played = true; |
409 break; | 443 break; |
410 } | 444 } |
411 case media::MediaLogEvent::PIPELINE_STATE_CHANGED: { | 445 case media::MediaLogEvent::PIPELINE_STATE_CHANGED: { |
412 player_info[event.id].has_pipeline = true; | 446 player_info.has_pipeline = true; |
413 break; | 447 break; |
414 } | 448 } |
415 case media::MediaLogEvent::PIPELINE_ERROR: { | 449 case media::MediaLogEvent::PIPELINE_ERROR: { |
416 int status; | 450 int status; |
417 event.params.GetInteger("pipeline_error", &status); | 451 event.params.GetInteger("pipeline_error", &status); |
418 player_info[event.id].last_pipeline_status = | 452 player_info.last_pipeline_status = |
419 static_cast<media::PipelineStatus>(status); | 453 static_cast<media::PipelineStatus>(status); |
420 break; | 454 break; |
421 } | 455 } |
422 case media::MediaLogEvent::PROPERTY_CHANGE: | 456 case media::MediaLogEvent::PROPERTY_CHANGE: |
423 if (event.params.HasKey("found_audio_stream")) { | 457 if (event.params.HasKey("found_audio_stream")) { |
424 event.params.GetBoolean("found_audio_stream", | 458 event.params.GetBoolean("found_audio_stream", &player_info.has_audio); |
425 &player_info[event.id].has_audio); | |
426 } | 459 } |
427 if (event.params.HasKey("found_video_stream")) { | 460 if (event.params.HasKey("found_video_stream")) { |
428 event.params.GetBoolean("found_video_stream", | 461 event.params.GetBoolean("found_video_stream", &player_info.has_video); |
429 &player_info[event.id].has_video); | |
430 } | 462 } |
431 if (event.params.HasKey("audio_codec_name")) { | 463 if (event.params.HasKey("audio_codec_name")) { |
432 event.params.GetString("audio_codec_name", | 464 event.params.GetString("audio_codec_name", |
433 &player_info[event.id].audio_codec_name); | 465 &player_info.audio_codec_name); |
434 } | 466 } |
435 if (event.params.HasKey("video_codec_name")) { | 467 if (event.params.HasKey("video_codec_name")) { |
436 event.params.GetString("video_codec_name", | 468 event.params.GetString("video_codec_name", |
437 &player_info[event.id].video_codec_name); | 469 &player_info.video_codec_name); |
438 } | 470 } |
439 if (event.params.HasKey("video_decoder")) { | 471 if (event.params.HasKey("video_decoder")) { |
440 std::string previous_video_decoder(player_info[event.id].video_decoder); | 472 std::string previous_video_decoder(player_info.video_decoder); |
441 event.params.GetString("video_decoder", | 473 event.params.GetString("video_decoder", &player_info.video_decoder); |
442 &player_info[event.id].video_decoder); | |
443 if (!previous_video_decoder.empty() && | 474 if (!previous_video_decoder.empty() && |
444 previous_video_decoder != player_info[event.id].video_decoder) { | 475 previous_video_decoder != player_info.video_decoder) { |
445 player_info[event.id].video_decoder_changed = true; | 476 player_info.video_decoder_changed = true; |
446 } | 477 } |
447 } | 478 } |
448 if (event.params.HasKey("video_dds")) { | 479 if (event.params.HasKey("video_dds")) { |
449 event.params.GetBoolean("video_dds", &player_info[event.id].video_dds); | 480 event.params.GetBoolean("video_dds", &player_info.video_dds); |
481 } | |
482 if (event.params.HasKey("has_cdm")) { | |
483 event.params.GetBoolean("has_cdm", &player_info.has_cdm); | |
450 } | 484 } |
451 if (event.params.HasKey("pipeline_buffering_state")) { | 485 if (event.params.HasKey("pipeline_buffering_state")) { |
452 std::string buffering_state; | 486 std::string buffering_state; |
453 event.params.GetString("pipeline_buffering_state", &buffering_state); | 487 event.params.GetString("pipeline_buffering_state", &buffering_state); |
454 if (buffering_state == "BUFFERING_HAVE_ENOUGH") | 488 if (buffering_state == "BUFFERING_HAVE_ENOUGH") |
455 player_info[event.id].has_reached_have_enough = true; | 489 player_info.has_reached_have_enough = true; |
456 } | 490 } |
457 break; | 491 break; |
458 case media::MediaLogEvent::Type::WATCH_TIME_UPDATE: { | 492 case media::MediaLogEvent::Type::WATCH_TIME_UPDATE: { |
459 DVLOG(2) << "Processing watch time update."; | 493 DVLOG(2) << "Processing watch time update."; |
460 PipelineInfo& info = player_info[event.id]; | 494 WatchTimeInfo& wti = player_info.watch_time_info; |
461 WatchTimeInfo& wti = info.watch_time_info; | |
462 // Save audio only watch time information. | 495 // Save audio only watch time information. |
463 MaybeSaveWatchTime(event, media::MediaLog::kWatchTimeAudioAll, | 496 MaybeSaveWatchTime(event, media::MediaLog::kWatchTimeAudioAll, |
464 &wti.all_watch_time); | 497 &wti.all_watch_time); |
465 MaybeSaveWatchTime(event, media::MediaLog::kWatchTimeAudioMse, | 498 MaybeSaveWatchTime(event, media::MediaLog::kWatchTimeAudioMse, |
466 &wti.mse_watch_time); | 499 &wti.mse_watch_time); |
467 MaybeSaveWatchTime(event, media::MediaLog::kWatchTimeAudioEme, | 500 MaybeSaveWatchTime(event, media::MediaLog::kWatchTimeAudioEme, |
468 &wti.eme_watch_time); | 501 &wti.eme_watch_time); |
469 MaybeSaveWatchTime(event, media::MediaLog::kWatchTimeAudioSrc, | 502 MaybeSaveWatchTime(event, media::MediaLog::kWatchTimeAudioSrc, |
470 &wti.src_watch_time); | 503 &wti.src_watch_time); |
471 MaybeSaveWatchTime(event, media::MediaLog::kWatchTimeAudioBattery, | 504 MaybeSaveWatchTime(event, media::MediaLog::kWatchTimeAudioBattery, |
(...skipping 19 matching lines...) Expand all Loading... | |
491 &wti.ac_watch_time); | 524 &wti.ac_watch_time); |
492 MaybeSaveWatchTime( | 525 MaybeSaveWatchTime( |
493 event, media::MediaLog::kWatchTimeAudioVideoEmbeddedExperience, | 526 event, media::MediaLog::kWatchTimeAudioVideoEmbeddedExperience, |
494 &wti.embedded_experience_watch_time); | 527 &wti.embedded_experience_watch_time); |
495 | 528 |
496 if (event.params.HasKey(media::MediaLog::kWatchTimeFinalize)) { | 529 if (event.params.HasKey(media::MediaLog::kWatchTimeFinalize)) { |
497 bool should_finalize; | 530 bool should_finalize; |
498 DCHECK(event.params.GetBoolean(media::MediaLog::kWatchTimeFinalize, | 531 DCHECK(event.params.GetBoolean(media::MediaLog::kWatchTimeFinalize, |
499 &should_finalize) && | 532 &should_finalize) && |
500 should_finalize); | 533 should_finalize); |
501 FinalizeWatchTime(info.has_video, &wti, FinalizeType::EVERYTHING); | 534 FinalizeWatchTime(player_info.has_video, &wti, |
535 FinalizeType::EVERYTHING); | |
502 } else if (event.params.HasKey( | 536 } else if (event.params.HasKey( |
503 media::MediaLog::kWatchTimeFinalizePower)) { | 537 media::MediaLog::kWatchTimeFinalizePower)) { |
504 bool should_finalize; | 538 bool should_finalize; |
505 DCHECK(event.params.GetBoolean(media::MediaLog::kWatchTimeFinalizePower, | 539 DCHECK(event.params.GetBoolean(media::MediaLog::kWatchTimeFinalizePower, |
506 &should_finalize) && | 540 &should_finalize) && |
507 should_finalize); | 541 should_finalize); |
508 FinalizeWatchTime(info.has_video, &wti, FinalizeType::POWER_ONLY); | 542 FinalizeWatchTime(player_info.has_video, &wti, |
543 FinalizeType::POWER_ONLY); | |
509 } | 544 } |
510 break; | 545 break; |
511 } | 546 } |
512 case media::MediaLogEvent::Type::WEBMEDIAPLAYER_DESTROYED: { | 547 case media::MediaLogEvent::Type::WEBMEDIAPLAYER_DESTROYED: { |
513 // Upon player destruction report UMA data; if the player is not torn down | 548 // Upon player destruction report UMA data; if the player is not torn down |
514 // before process exit, it will be logged during OnProcessTerminated(). | 549 // before process exit, it will be logged during OnProcessTerminated(). |
515 auto it = player_info.find(event.id); | 550 auto it = player_info_map.find(event.id); |
516 if (it == player_info.end()) | 551 if (it == player_info_map.end()) |
517 break; | 552 break; |
518 | 553 |
519 ReportUMAForPipelineStatus(it->second); | 554 ReportUMAForPipelineStatus(it->second); |
520 player_info.erase(it); | 555 player_info_map.erase(it); |
521 } | 556 } |
522 default: | 557 default: |
523 break; | 558 break; |
524 } | 559 } |
525 return; | 560 return; |
526 } | 561 } |
527 | 562 |
528 std::string MediaInternals::MediaInternalsUMAHandler::GetUMANameForAVStream( | 563 std::string MediaInternals::MediaInternalsUMAHandler::GetUMANameForAVStream( |
529 const PipelineInfo& player_info) { | 564 const PipelineInfo& player_info) { |
530 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 565 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
(...skipping 21 matching lines...) Expand all Loading... | |
552 } | 587 } |
553 | 588 |
554 if (player_info.video_decoder == media::GpuVideoDecoder::kDecoderName) { | 589 if (player_info.video_decoder == media::GpuVideoDecoder::kDecoderName) { |
555 uma_name += "HW"; | 590 uma_name += "HW"; |
556 } else { | 591 } else { |
557 uma_name += "SW"; | 592 uma_name += "SW"; |
558 } | 593 } |
559 return uma_name; | 594 return uma_name; |
560 } | 595 } |
561 | 596 |
597 // TODO(xhwang): This function reports more metrics than just pipeline status | |
598 // and should be renamed. Similarly, PipelineInfo should be PlayerInfo. | |
562 void MediaInternals::MediaInternalsUMAHandler::ReportUMAForPipelineStatus( | 599 void MediaInternals::MediaInternalsUMAHandler::ReportUMAForPipelineStatus( |
563 const PipelineInfo& player_info) { | 600 const PipelineInfo& player_info) { |
564 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 601 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
565 | 602 |
566 // Don't log pipeline status for players which don't actually have a pipeline; | 603 // Don't log pipeline status for players which don't actually have a pipeline; |
567 // e.g., the Android MediaSourcePlayer implementation. | 604 // e.g., the Android MediaSourcePlayer implementation. |
568 if (!player_info.has_pipeline) | 605 if (!player_info.has_pipeline) |
569 return; | 606 return; |
570 | 607 |
571 if (player_info.has_video && player_info.has_audio) { | 608 if (player_info.has_video && player_info.has_audio) { |
(...skipping 22 matching lines...) Expand all Loading... | |
594 // was reported. | 631 // was reported. |
595 if (!player_info.video_decoder.empty()) { | 632 if (!player_info.video_decoder.empty()) { |
596 UMA_HISTOGRAM_BOOLEAN("Media.VideoDecoderFallback", | 633 UMA_HISTOGRAM_BOOLEAN("Media.VideoDecoderFallback", |
597 player_info.video_decoder_changed); | 634 player_info.video_decoder_changed); |
598 } | 635 } |
599 | 636 |
600 // Report whether this player ever saw a playback event. Used to measure the | 637 // Report whether this player ever saw a playback event. Used to measure the |
601 // effectiveness of efforts to reduce loaded-but-never-used players. | 638 // effectiveness of efforts to reduce loaded-but-never-used players. |
602 if (player_info.has_reached_have_enough) | 639 if (player_info.has_reached_have_enough) |
603 UMA_HISTOGRAM_BOOLEAN("Media.HasEverPlayed", player_info.has_ever_played); | 640 UMA_HISTOGRAM_BOOLEAN("Media.HasEverPlayed", player_info.has_ever_played); |
641 | |
642 // Report whether an encrypted playback is in incognito window, excluding | |
643 // never-used players. | |
644 if (player_info.has_cdm && player_info.has_ever_played) | |
645 UMA_HISTOGRAM_BOOLEAN("Media.EME.IsIncognito", player_info.is_incognito); | |
604 } | 646 } |
605 | 647 |
606 void MediaInternals::MediaInternalsUMAHandler::OnProcessTerminated( | 648 void MediaInternals::MediaInternalsUMAHandler::OnProcessTerminated( |
607 int render_process_id) { | 649 int render_process_id) { |
608 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 650 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
609 | 651 |
610 auto players_it = renderer_info_.find(render_process_id); | 652 auto players_it = renderer_info_.find(render_process_id); |
611 if (players_it == renderer_info_.end()) | 653 if (players_it == renderer_info_.end()) |
612 return; | 654 return; |
613 auto it = players_it->second.begin(); | 655 auto it = players_it->second.begin(); |
(...skipping 258 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
872 audio_streams_cached_data_.GetDictionary(cache_key, &existing_dict)); | 914 audio_streams_cached_data_.GetDictionary(cache_key, &existing_dict)); |
873 existing_dict->MergeDictionary(value); | 915 existing_dict->MergeDictionary(value); |
874 } | 916 } |
875 } | 917 } |
876 | 918 |
877 if (CanUpdate()) | 919 if (CanUpdate()) |
878 SendUpdate(SerializeUpdate(function, value)); | 920 SendUpdate(SerializeUpdate(function, value)); |
879 } | 921 } |
880 | 922 |
881 } // namespace content | 923 } // namespace content |
OLD | NEW |