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> |
(...skipping 271 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
282 // Called when a render process is terminated. Reports the pipeline status to | 282 // 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 | 283 // UMA for every player associated with the renderer process and then deletes |
284 // the player state. | 284 // the player state. |
285 void OnProcessTerminated(int render_process_id); | 285 void OnProcessTerminated(int render_process_id); |
286 | 286 |
287 // Helper function to save the event payload to RendererPlayerMap. | 287 // Helper function to save the event payload to RendererPlayerMap. |
288 void SavePlayerState(int render_process_id, | 288 void SavePlayerState(int render_process_id, |
289 const media::MediaLogEvent& event); | 289 const media::MediaLogEvent& event); |
290 | 290 |
291 private: | 291 private: |
| 292 struct WatchTimeInfo { |
| 293 base::TimeDelta all_watch_time = media::kNoTimestamp; |
| 294 base::TimeDelta mse_watch_time = media::kNoTimestamp; |
| 295 base::TimeDelta eme_watch_time = media::kNoTimestamp; |
| 296 base::TimeDelta src_watch_time = media::kNoTimestamp; |
| 297 base::TimeDelta ac_watch_time = media::kNoTimestamp; |
| 298 base::TimeDelta battery_watch_time = media::kNoTimestamp; |
| 299 }; |
| 300 |
292 struct PipelineInfo { | 301 struct PipelineInfo { |
293 bool has_pipeline = false; | 302 bool has_pipeline = false; |
294 media::PipelineStatus last_pipeline_status = media::PIPELINE_OK; | 303 media::PipelineStatus last_pipeline_status = media::PIPELINE_OK; |
295 bool has_audio = false; | 304 bool has_audio = false; |
296 bool has_video = false; | 305 bool has_video = false; |
297 bool video_dds = false; | 306 bool video_dds = false; |
298 bool video_decoder_changed = false; | 307 bool video_decoder_changed = false; |
299 std::string audio_codec_name; | 308 std::string audio_codec_name; |
300 std::string video_codec_name; | 309 std::string video_codec_name; |
301 std::string video_decoder; | 310 std::string video_decoder; |
| 311 WatchTimeInfo watch_time_info; |
302 }; | 312 }; |
303 | 313 |
304 // Helper function to report PipelineStatus associated with a player to UMA. | 314 // Helper function to report PipelineStatus associated with a player to UMA. |
305 void ReportUMAForPipelineStatus(const PipelineInfo& player_info); | 315 void ReportUMAForPipelineStatus(const PipelineInfo& player_info); |
306 | 316 |
307 // Helper to generate PipelineStatus UMA name for AudioVideo streams. | 317 // Helper to generate PipelineStatus UMA name for AudioVideo streams. |
308 std::string GetUMANameForAVStream(const PipelineInfo& player_info); | 318 std::string GetUMANameForAVStream(const PipelineInfo& player_info); |
309 | 319 |
| 320 // Saves the watch time info from |event| under |key| at |watch_time| if |key| |
| 321 // is present in |event.params|. |
| 322 void MaybeSaveWatchTime(const media::MediaLogEvent& event, |
| 323 const char* key, |
| 324 base::TimeDelta* watch_time) { |
| 325 if (!event.params.HasKey(key)) |
| 326 return; |
| 327 |
| 328 double in_seconds; |
| 329 const bool result = |
| 330 event.params.GetDoubleWithoutPathExpansion(key, &in_seconds); |
| 331 DCHECK(result); |
| 332 *watch_time = base::TimeDelta::FromSecondsD(in_seconds); |
| 333 |
| 334 DVLOG(2) << "Saved watch time for " << key << " of " << *watch_time; |
| 335 } |
| 336 |
| 337 enum class FinalizeType { EVERYTHING, POWER_ONLY }; |
| 338 void FinalizeWatchTime(WatchTimeInfo* watch_time_info, |
| 339 FinalizeType finalize_type) { |
| 340 // Use a macro instead of a function so we can use the histogram macro (which |
| 341 // checks that the uma name is a static value). We use a custom time range for |
| 342 // the histogram macro to capitalize on common expected watch times. |
| 343 #define MAYBE_RECORD_WATCH_TIME(uma_name, watch_time) \ |
| 344 if (watch_time_info->watch_time != media::kNoTimestamp) { \ |
| 345 UMA_HISTOGRAM_CUSTOM_TIMES( \ |
| 346 media::MediaLog::uma_name, watch_time_info->watch_time, \ |
| 347 base::TimeDelta::FromSeconds(7), base::TimeDelta::FromHours(10), 50); \ |
| 348 watch_time_info->watch_time = media::kNoTimestamp; \ |
| 349 } |
| 350 |
| 351 if (finalize_type == FinalizeType::EVERYTHING) { |
| 352 MAYBE_RECORD_WATCH_TIME(kWatchTimeAudioVideoAll, all_watch_time); |
| 353 MAYBE_RECORD_WATCH_TIME(kWatchTimeAudioVideoMse, mse_watch_time); |
| 354 MAYBE_RECORD_WATCH_TIME(kWatchTimeAudioVideoEme, eme_watch_time); |
| 355 MAYBE_RECORD_WATCH_TIME(kWatchTimeAudioVideoSrc, src_watch_time); |
| 356 } else { |
| 357 DCHECK_EQ(finalize_type, FinalizeType::POWER_ONLY); |
| 358 } |
| 359 MAYBE_RECORD_WATCH_TIME(kWatchTimeAudioVideoBattery, battery_watch_time); |
| 360 MAYBE_RECORD_WATCH_TIME(kWatchTimeAudioVideoAc, ac_watch_time); |
| 361 #undef MAYBE_RECORD_WATCH_TIME |
| 362 } |
| 363 |
310 // Key is player id. | 364 // Key is player id. |
311 typedef std::map<int, PipelineInfo> PlayerInfoMap; | 365 typedef std::map<int, PipelineInfo> PlayerInfoMap; |
312 | 366 |
313 // Key is renderer id. | 367 // Key is renderer id. |
314 typedef std::map<int, PlayerInfoMap> RendererPlayerMap; | 368 typedef std::map<int, PlayerInfoMap> RendererPlayerMap; |
315 | 369 |
316 // Stores player information per renderer. | 370 // Stores player information per renderer. |
317 RendererPlayerMap renderer_info_; | 371 RendererPlayerMap renderer_info_; |
318 | 372 |
319 DISALLOW_COPY_AND_ASSIGN(MediaInternalsUMAHandler); | 373 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); | 416 &player_info[event.id].video_decoder); |
363 if (!previous_video_decoder.empty() && | 417 if (!previous_video_decoder.empty() && |
364 previous_video_decoder != player_info[event.id].video_decoder) { | 418 previous_video_decoder != player_info[event.id].video_decoder) { |
365 player_info[event.id].video_decoder_changed = true; | 419 player_info[event.id].video_decoder_changed = true; |
366 } | 420 } |
367 } | 421 } |
368 if (event.params.HasKey("video_dds")) { | 422 if (event.params.HasKey("video_dds")) { |
369 event.params.GetBoolean("video_dds", &player_info[event.id].video_dds); | 423 event.params.GetBoolean("video_dds", &player_info[event.id].video_dds); |
370 } | 424 } |
371 break; | 425 break; |
| 426 case media::MediaLogEvent::Type::WATCH_TIME_UPDATE: { |
| 427 DVLOG(2) << "Processing watch time update."; |
| 428 WatchTimeInfo& wti = player_info[event.id].watch_time_info; |
| 429 MaybeSaveWatchTime(event, media::MediaLog::kWatchTimeAudioVideoAll, |
| 430 &wti.all_watch_time); |
| 431 MaybeSaveWatchTime(event, media::MediaLog::kWatchTimeAudioVideoMse, |
| 432 &wti.mse_watch_time); |
| 433 MaybeSaveWatchTime(event, media::MediaLog::kWatchTimeAudioVideoEme, |
| 434 &wti.eme_watch_time); |
| 435 MaybeSaveWatchTime(event, media::MediaLog::kWatchTimeAudioVideoSrc, |
| 436 &wti.src_watch_time); |
| 437 MaybeSaveWatchTime(event, media::MediaLog::kWatchTimeAudioVideoBattery, |
| 438 &wti.battery_watch_time); |
| 439 MaybeSaveWatchTime(event, media::MediaLog::kWatchTimeAudioVideoAc, |
| 440 &wti.ac_watch_time); |
| 441 |
| 442 if (event.params.HasKey(media::MediaLog::kWatchTimeFinalize)) { |
| 443 bool should_finalize; |
| 444 DCHECK(event.params.GetBoolean(media::MediaLog::kWatchTimeFinalize, |
| 445 &should_finalize) && |
| 446 should_finalize); |
| 447 FinalizeWatchTime(&wti, FinalizeType::EVERYTHING); |
| 448 } else if (event.params.HasKey( |
| 449 media::MediaLog::kWatchTimeFinalizePower)) { |
| 450 bool should_finalize; |
| 451 DCHECK(event.params.GetBoolean(media::MediaLog::kWatchTimeFinalizePower, |
| 452 &should_finalize) && |
| 453 should_finalize); |
| 454 FinalizeWatchTime(&wti, FinalizeType::POWER_ONLY); |
| 455 } |
| 456 break; |
| 457 } |
| 458 case media::MediaLogEvent::Type::WEBMEDIAPLAYER_DESTROYED: { |
| 459 // Upon player destruction report UMA data; if the player is not torn down |
| 460 // before process exit, it will be logged during OnProcessTerminated(). |
| 461 auto it = player_info.find(event.id); |
| 462 if (it == player_info.end()) |
| 463 break; |
| 464 |
| 465 ReportUMAForPipelineStatus(it->second); |
| 466 player_info.erase(it); |
| 467 } |
372 default: | 468 default: |
373 break; | 469 break; |
374 } | 470 } |
375 return; | 471 return; |
376 } | 472 } |
377 | 473 |
378 std::string MediaInternals::MediaInternalsUMAHandler::GetUMANameForAVStream( | 474 std::string MediaInternals::MediaInternalsUMAHandler::GetUMANameForAVStream( |
379 const PipelineInfo& player_info) { | 475 const PipelineInfo& player_info) { |
380 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 476 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
381 static const char kPipelineUmaPrefix[] = "Media.PipelineStatus.AudioVideo."; | 477 static const char kPipelineUmaPrefix[] = "Media.PipelineStatus.AudioVideo."; |
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
451 void MediaInternals::MediaInternalsUMAHandler::OnProcessTerminated( | 547 void MediaInternals::MediaInternalsUMAHandler::OnProcessTerminated( |
452 int render_process_id) { | 548 int render_process_id) { |
453 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 549 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
454 | 550 |
455 auto players_it = renderer_info_.find(render_process_id); | 551 auto players_it = renderer_info_.find(render_process_id); |
456 if (players_it == renderer_info_.end()) | 552 if (players_it == renderer_info_.end()) |
457 return; | 553 return; |
458 auto it = players_it->second.begin(); | 554 auto it = players_it->second.begin(); |
459 while (it != players_it->second.end()) { | 555 while (it != players_it->second.end()) { |
460 ReportUMAForPipelineStatus(it->second); | 556 ReportUMAForPipelineStatus(it->second); |
| 557 FinalizeWatchTime(&(it->second.watch_time_info), FinalizeType::EVERYTHING); |
461 players_it->second.erase(it++); | 558 players_it->second.erase(it++); |
462 } | 559 } |
463 renderer_info_.erase(players_it); | 560 renderer_info_.erase(players_it); |
464 } | 561 } |
465 | 562 |
466 MediaInternals* MediaInternals::GetInstance() { | 563 MediaInternals* MediaInternals::GetInstance() { |
467 return g_media_internals.Pointer(); | 564 return g_media_internals.Pointer(); |
468 } | 565 } |
469 | 566 |
470 MediaInternals::MediaInternals() | 567 MediaInternals::MediaInternals() |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
522 | 619 |
523 *update = SerializeUpdate("media.onMediaEvent", &dict); | 620 *update = SerializeUpdate("media.onMediaEvent", &dict); |
524 return true; | 621 return true; |
525 } | 622 } |
526 | 623 |
527 void MediaInternals::OnMediaEvents( | 624 void MediaInternals::OnMediaEvents( |
528 int render_process_id, const std::vector<media::MediaLogEvent>& events) { | 625 int render_process_id, const std::vector<media::MediaLogEvent>& events) { |
529 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 626 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
530 // Notify observers that |event| has occurred. | 627 // Notify observers that |event| has occurred. |
531 for (const auto& event : events) { | 628 for (const auto& event : events) { |
532 if (CanUpdate()) { | 629 // Some events should not be recorded in the UI. |
533 base::string16 update; | 630 if (event.type != media::MediaLogEvent::Type::WATCH_TIME_UPDATE) { |
534 if (ConvertEventToUpdate(render_process_id, event, &update)) | 631 if (CanUpdate()) { |
535 SendUpdate(update); | 632 base::string16 update; |
| 633 if (ConvertEventToUpdate(render_process_id, event, &update)) |
| 634 SendUpdate(update); |
| 635 } |
| 636 SaveEvent(render_process_id, event); |
536 } | 637 } |
537 | |
538 SaveEvent(render_process_id, event); | |
539 uma_handler_->SavePlayerState(render_process_id, event); | 638 uma_handler_->SavePlayerState(render_process_id, event); |
540 } | 639 } |
541 } | 640 } |
542 | 641 |
543 void MediaInternals::AddUpdateCallback(const UpdateCallback& callback) { | 642 void MediaInternals::AddUpdateCallback(const UpdateCallback& callback) { |
544 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 643 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
545 update_callbacks_.push_back(callback); | 644 update_callbacks_.push_back(callback); |
546 | 645 |
547 base::AutoLock auto_lock(lock_); | 646 base::AutoLock auto_lock(lock_); |
548 can_update_ = true; | 647 can_update_ = true; |
(...skipping 163 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
712 audio_streams_cached_data_.GetDictionary(cache_key, &existing_dict)); | 811 audio_streams_cached_data_.GetDictionary(cache_key, &existing_dict)); |
713 existing_dict->MergeDictionary(value); | 812 existing_dict->MergeDictionary(value); |
714 } | 813 } |
715 } | 814 } |
716 | 815 |
717 if (CanUpdate()) | 816 if (CanUpdate()) |
718 SendUpdate(SerializeUpdate(function, value)); | 817 SendUpdate(SerializeUpdate(function, value)); |
719 } | 818 } |
720 | 819 |
721 } // namespace content | 820 } // namespace content |
OLD | NEW |