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 |