| 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 <utility> | 10 #include <utility> |
| 11 | 11 |
| 12 #include "base/macros.h" | 12 #include "base/macros.h" |
| 13 #include "base/metrics/histogram.h" | 13 #include "base/metrics/histogram.h" |
| 14 #include "base/strings/string16.h" | 14 #include "base/strings/string16.h" |
| 15 #include "base/strings/string_number_conversions.h" | 15 #include "base/strings/string_number_conversions.h" |
| 16 #include "base/strings/stringprintf.h" | 16 #include "base/strings/stringprintf.h" |
| 17 #include "build/build_config.h" | 17 #include "build/build_config.h" |
| 18 #include "content/browser/renderer_host/media/media_stream_manager.h" | 18 #include "content/browser/renderer_host/media/media_stream_manager.h" |
| 19 #include "content/public/browser/browser_thread.h" | 19 #include "content/public/browser/browser_thread.h" |
| 20 #include "content/public/browser/notification_service.h" | 20 #include "content/public/browser/notification_service.h" |
| 21 #include "content/public/browser/notification_types.h" | 21 #include "content/public/browser/notification_types.h" |
| 22 #include "content/public/browser/render_frame_host.h" | 22 #include "content/public/browser/render_frame_host.h" |
| 23 #include "content/public/browser/render_process_host.h" | 23 #include "content/public/browser/render_process_host.h" |
| 24 #include "content/public/browser/web_contents.h" | 24 #include "content/public/browser/web_contents.h" |
| 25 #include "content/public/browser/web_ui.h" | 25 #include "content/public/browser/web_ui.h" |
| 26 #include "media/base/audio_parameters.h" | 26 #include "media/base/audio_parameters.h" |
| 27 #include "media/base/media_log_event.h" | 27 #include "media/base/media_log_event.h" |
| 28 #include "media/blink/watch_time_reporter.h" |
| 28 #include "media/filters/gpu_video_decoder.h" | 29 #include "media/filters/gpu_video_decoder.h" |
| 29 | 30 |
| 30 #if !defined(OS_ANDROID) | 31 #if !defined(OS_ANDROID) |
| 31 #include "media/filters/decrypting_video_decoder.h" | 32 #include "media/filters/decrypting_video_decoder.h" |
| 32 #endif | 33 #endif |
| 33 | 34 |
| 34 namespace { | 35 namespace { |
| 35 | 36 |
| 36 static base::LazyInstance<content::MediaInternals>::Leaky g_media_internals = | 37 static base::LazyInstance<content::MediaInternals>::Leaky g_media_internals = |
| 37 LAZY_INSTANCE_INITIALIZER; | 38 LAZY_INSTANCE_INITIALIZER; |
| (...skipping 244 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 282 // Called when a render process is terminated. Reports the pipeline status to | 283 // Called when a render process is terminated. Reports the pipeline status to |
| 283 // UMA for every player associated with the renderer process and then deletes | 284 // UMA for every player associated with the renderer process and then deletes |
| 284 // the player state. | 285 // the player state. |
| 285 void OnProcessTerminated(int render_process_id); | 286 void OnProcessTerminated(int render_process_id); |
| 286 | 287 |
| 287 // Helper function to save the event payload to RendererPlayerMap. | 288 // Helper function to save the event payload to RendererPlayerMap. |
| 288 void SavePlayerState(int render_process_id, | 289 void SavePlayerState(int render_process_id, |
| 289 const media::MediaLogEvent& event); | 290 const media::MediaLogEvent& event); |
| 290 | 291 |
| 291 private: | 292 private: |
| 293 struct WatchTimeInfo { |
| 294 base::TimeDelta all_watch_time = media::kNoTimestamp; |
| 295 base::TimeDelta mse_watch_time = media::kNoTimestamp; |
| 296 base::TimeDelta eme_watch_time = media::kNoTimestamp; |
| 297 base::TimeDelta src_watch_time = media::kNoTimestamp; |
| 298 base::TimeDelta ac_watch_time = media::kNoTimestamp; |
| 299 base::TimeDelta battery_watch_time = media::kNoTimestamp; |
| 300 }; |
| 301 |
| 292 struct PipelineInfo { | 302 struct PipelineInfo { |
| 293 bool has_pipeline = false; | 303 bool has_pipeline = false; |
| 294 media::PipelineStatus last_pipeline_status = media::PIPELINE_OK; | 304 media::PipelineStatus last_pipeline_status = media::PIPELINE_OK; |
| 295 bool has_audio = false; | 305 bool has_audio = false; |
| 296 bool has_video = false; | 306 bool has_video = false; |
| 297 bool video_dds = false; | 307 bool video_dds = false; |
| 298 bool video_decoder_changed = false; | 308 bool video_decoder_changed = false; |
| 299 std::string audio_codec_name; | 309 std::string audio_codec_name; |
| 300 std::string video_codec_name; | 310 std::string video_codec_name; |
| 301 std::string video_decoder; | 311 std::string video_decoder; |
| 312 WatchTimeInfo watch_time_info; |
| 302 }; | 313 }; |
| 303 | 314 |
| 304 // Helper function to report PipelineStatus associated with a player to UMA. | 315 // Helper function to report PipelineStatus associated with a player to UMA. |
| 305 void ReportUMAForPipelineStatus(const PipelineInfo& player_info); | 316 void ReportUMAForPipelineStatus(const PipelineInfo& player_info); |
| 306 | 317 |
| 307 // Helper to generate PipelineStatus UMA name for AudioVideo streams. | 318 // Helper to generate PipelineStatus UMA name for AudioVideo streams. |
| 308 std::string GetUMANameForAVStream(const PipelineInfo& player_info); | 319 std::string GetUMANameForAVStream(const PipelineInfo& player_info); |
| 309 | 320 |
| 321 // Saves the watch time info from |event| under |key| at |watch_time| if |key| |
| 322 // is present in |event.params|. |
| 323 void MaybeSaveWatchTime(const media::MediaLogEvent& event, |
| 324 const char* key, |
| 325 base::TimeDelta* watch_time) { |
| 326 if (!event.params.HasKey(key)) |
| 327 return; |
| 328 |
| 329 double in_seconds; |
| 330 const bool result = |
| 331 event.params.GetDoubleWithoutPathExpansion(key, &in_seconds); |
| 332 DCHECK(result); |
| 333 *watch_time = base::TimeDelta::FromSecondsD(in_seconds); |
| 334 |
| 335 DVLOG(2) << "Saved watch time for " << key << " of " << *watch_time; |
| 336 } |
| 337 |
| 310 // Key is player id. | 338 // Key is player id. |
| 311 typedef std::map<int, PipelineInfo> PlayerInfoMap; | 339 typedef std::map<int, PipelineInfo> PlayerInfoMap; |
| 312 | 340 |
| 313 // Key is renderer id. | 341 // Key is renderer id. |
| 314 typedef std::map<int, PlayerInfoMap> RendererPlayerMap; | 342 typedef std::map<int, PlayerInfoMap> RendererPlayerMap; |
| 315 | 343 |
| 316 // Stores player information per renderer. | 344 // Stores player information per renderer. |
| 317 RendererPlayerMap renderer_info_; | 345 RendererPlayerMap renderer_info_; |
| 318 | 346 |
| 319 DISALLOW_COPY_AND_ASSIGN(MediaInternalsUMAHandler); | 347 DISALLOW_COPY_AND_ASSIGN(MediaInternalsUMAHandler); |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 362 &player_info[event.id].video_decoder); | 390 &player_info[event.id].video_decoder); |
| 363 if (!previous_video_decoder.empty() && | 391 if (!previous_video_decoder.empty() && |
| 364 previous_video_decoder != player_info[event.id].video_decoder) { | 392 previous_video_decoder != player_info[event.id].video_decoder) { |
| 365 player_info[event.id].video_decoder_changed = true; | 393 player_info[event.id].video_decoder_changed = true; |
| 366 } | 394 } |
| 367 } | 395 } |
| 368 if (event.params.HasKey("video_dds")) { | 396 if (event.params.HasKey("video_dds")) { |
| 369 event.params.GetBoolean("video_dds", &player_info[event.id].video_dds); | 397 event.params.GetBoolean("video_dds", &player_info[event.id].video_dds); |
| 370 } | 398 } |
| 371 break; | 399 break; |
| 400 case media::MediaLogEvent::Type::WATCH_TIME_UPDATE: { |
| 401 DVLOG(2) << "Processing watch time update."; |
| 402 WatchTimeInfo& wti = player_info[event.id].watch_time_info; |
| 403 MaybeSaveWatchTime(event, |
| 404 media::WatchTimeReporter::kHistogramAudioVideoAll, |
| 405 &wti.all_watch_time); |
| 406 MaybeSaveWatchTime(event, |
| 407 media::WatchTimeReporter::kHistogramAudioVideoMse, |
| 408 &wti.mse_watch_time); |
| 409 MaybeSaveWatchTime(event, |
| 410 media::WatchTimeReporter::kHistogramAudioVideoEme, |
| 411 &wti.eme_watch_time); |
| 412 MaybeSaveWatchTime(event, |
| 413 media::WatchTimeReporter::kHistogramAudioVideoSrc, |
| 414 &wti.src_watch_time); |
| 415 MaybeSaveWatchTime(event, |
| 416 media::WatchTimeReporter::kHistogramAudioVideoBattery, |
| 417 &wti.battery_watch_time); |
| 418 MaybeSaveWatchTime(event, |
| 419 media::WatchTimeReporter::kHistogramAudioVideoAc, |
| 420 &wti.ac_watch_time); |
| 421 break; |
| 422 } |
| 372 default: | 423 default: |
| 373 break; | 424 break; |
| 374 } | 425 } |
| 375 return; | 426 return; |
| 376 } | 427 } |
| 377 | 428 |
| 378 std::string MediaInternals::MediaInternalsUMAHandler::GetUMANameForAVStream( | 429 std::string MediaInternals::MediaInternalsUMAHandler::GetUMANameForAVStream( |
| 379 const PipelineInfo& player_info) { | 430 const PipelineInfo& player_info) { |
| 380 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 431 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 381 static const char kPipelineUmaPrefix[] = "Media.PipelineStatus.AudioVideo."; | 432 static const char kPipelineUmaPrefix[] = "Media.PipelineStatus.AudioVideo."; |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 439 UMA_HISTOGRAM_ENUMERATION("Media.PipelineStatus.Unsupported", | 490 UMA_HISTOGRAM_ENUMERATION("Media.PipelineStatus.Unsupported", |
| 440 player_info.last_pipeline_status, | 491 player_info.last_pipeline_status, |
| 441 media::PIPELINE_STATUS_MAX + 1); | 492 media::PIPELINE_STATUS_MAX + 1); |
| 442 } | 493 } |
| 443 // Report whether video decoder fallback happened, but only if a video decoder | 494 // Report whether video decoder fallback happened, but only if a video decoder |
| 444 // was reported. | 495 // was reported. |
| 445 if (!player_info.video_decoder.empty()) { | 496 if (!player_info.video_decoder.empty()) { |
| 446 UMA_HISTOGRAM_BOOLEAN("Media.VideoDecoderFallback", | 497 UMA_HISTOGRAM_BOOLEAN("Media.VideoDecoderFallback", |
| 447 player_info.video_decoder_changed); | 498 player_info.video_decoder_changed); |
| 448 } | 499 } |
| 500 |
| 501 // Use a macro instead of a function so we can use the histogram macro (which |
| 502 // checks that the uma name is a static value). |
| 503 #define MAYBE_RECORD_WATCH_TIME(uma_name, watch_time) \ |
| 504 if (player_info.watch_time_info.watch_time != media::kNoTimestamp) { \ |
| 505 UMA_HISTOGRAM_LONG_TIMES(media::WatchTimeReporter::uma_name, \ |
| 506 player_info.watch_time_info.watch_time); \ |
| 507 } |
| 508 |
| 509 MAYBE_RECORD_WATCH_TIME(kHistogramAudioVideoAll, all_watch_time); |
| 510 MAYBE_RECORD_WATCH_TIME(kHistogramAudioVideoMse, mse_watch_time); |
| 511 MAYBE_RECORD_WATCH_TIME(kHistogramAudioVideoEme, eme_watch_time); |
| 512 MAYBE_RECORD_WATCH_TIME(kHistogramAudioVideoSrc, src_watch_time); |
| 513 MAYBE_RECORD_WATCH_TIME(kHistogramAudioVideoBattery, battery_watch_time); |
| 514 MAYBE_RECORD_WATCH_TIME(kHistogramAudioVideoAc, ac_watch_time); |
| 515 #undef MAYBE_RECORD_WATCH_TIME |
| 449 } | 516 } |
| 450 | 517 |
| 451 void MediaInternals::MediaInternalsUMAHandler::OnProcessTerminated( | 518 void MediaInternals::MediaInternalsUMAHandler::OnProcessTerminated( |
| 452 int render_process_id) { | 519 int render_process_id) { |
| 453 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 520 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 454 | 521 |
| 455 auto players_it = renderer_info_.find(render_process_id); | 522 auto players_it = renderer_info_.find(render_process_id); |
| 456 if (players_it == renderer_info_.end()) | 523 if (players_it == renderer_info_.end()) |
| 457 return; | 524 return; |
| 458 auto it = players_it->second.begin(); | 525 auto it = players_it->second.begin(); |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 522 | 589 |
| 523 *update = SerializeUpdate("media.onMediaEvent", &dict); | 590 *update = SerializeUpdate("media.onMediaEvent", &dict); |
| 524 return true; | 591 return true; |
| 525 } | 592 } |
| 526 | 593 |
| 527 void MediaInternals::OnMediaEvents( | 594 void MediaInternals::OnMediaEvents( |
| 528 int render_process_id, const std::vector<media::MediaLogEvent>& events) { | 595 int render_process_id, const std::vector<media::MediaLogEvent>& events) { |
| 529 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 596 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 530 // Notify observers that |event| has occurred. | 597 // Notify observers that |event| has occurred. |
| 531 for (const auto& event : events) { | 598 for (const auto& event : events) { |
| 532 if (CanUpdate()) { | 599 // Some events should not be recorded in the UI. |
| 533 base::string16 update; | 600 if (event.type != media::MediaLogEvent::Type::WATCH_TIME_UPDATE) { |
| 534 if (ConvertEventToUpdate(render_process_id, event, &update)) | 601 if (CanUpdate()) { |
| 535 SendUpdate(update); | 602 base::string16 update; |
| 603 if (ConvertEventToUpdate(render_process_id, event, &update)) |
| 604 SendUpdate(update); |
| 605 } |
| 606 SaveEvent(render_process_id, event); |
| 536 } | 607 } |
| 537 | |
| 538 SaveEvent(render_process_id, event); | |
| 539 uma_handler_->SavePlayerState(render_process_id, event); | 608 uma_handler_->SavePlayerState(render_process_id, event); |
| 540 } | 609 } |
| 541 } | 610 } |
| 542 | 611 |
| 543 void MediaInternals::AddUpdateCallback(const UpdateCallback& callback) { | 612 void MediaInternals::AddUpdateCallback(const UpdateCallback& callback) { |
| 544 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 613 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 545 update_callbacks_.push_back(callback); | 614 update_callbacks_.push_back(callback); |
| 546 | 615 |
| 547 base::AutoLock auto_lock(lock_); | 616 base::AutoLock auto_lock(lock_); |
| 548 can_update_ = true; | 617 can_update_ = true; |
| (...skipping 156 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 705 audio_streams_cached_data_.GetDictionary(cache_key, &existing_dict)); | 774 audio_streams_cached_data_.GetDictionary(cache_key, &existing_dict)); |
| 706 existing_dict->MergeDictionary(value); | 775 existing_dict->MergeDictionary(value); |
| 707 } | 776 } |
| 708 } | 777 } |
| 709 | 778 |
| 710 if (CanUpdate()) | 779 if (CanUpdate()) |
| 711 SendUpdate(SerializeUpdate(function, value)); | 780 SendUpdate(SerializeUpdate(function, value)); |
| 712 } | 781 } |
| 713 | 782 |
| 714 } // namespace content | 783 } // namespace content |
| OLD | NEW |