| Index: content/browser/media/media_internals.cc
|
| diff --git a/content/browser/media/media_internals.cc b/content/browser/media/media_internals.cc
|
| index ba7e690622f7ff5b9f7a1cda7cee560ea05fa893..0174c11f5a7c9e6cc644e1e40dfa7f55e45a36ed 100644
|
| --- a/content/browser/media/media_internals.cc
|
| +++ b/content/browser/media/media_internals.cc
|
| @@ -289,6 +289,15 @@ class MediaInternals::MediaInternalsUMAHandler {
|
| const media::MediaLogEvent& event);
|
|
|
| private:
|
| + struct WatchTimeInfo {
|
| + base::TimeDelta all_watch_time = media::kNoTimestamp;
|
| + base::TimeDelta mse_watch_time = media::kNoTimestamp;
|
| + base::TimeDelta eme_watch_time = media::kNoTimestamp;
|
| + base::TimeDelta src_watch_time = media::kNoTimestamp;
|
| + base::TimeDelta ac_watch_time = media::kNoTimestamp;
|
| + base::TimeDelta battery_watch_time = media::kNoTimestamp;
|
| + };
|
| +
|
| struct PipelineInfo {
|
| bool has_pipeline = false;
|
| media::PipelineStatus last_pipeline_status = media::PIPELINE_OK;
|
| @@ -299,6 +308,7 @@ class MediaInternals::MediaInternalsUMAHandler {
|
| std::string audio_codec_name;
|
| std::string video_codec_name;
|
| std::string video_decoder;
|
| + WatchTimeInfo watch_time_info;
|
| };
|
|
|
| // Helper function to report PipelineStatus associated with a player to UMA.
|
| @@ -307,6 +317,50 @@ class MediaInternals::MediaInternalsUMAHandler {
|
| // Helper to generate PipelineStatus UMA name for AudioVideo streams.
|
| std::string GetUMANameForAVStream(const PipelineInfo& player_info);
|
|
|
| + // Saves the watch time info from |event| under |key| at |watch_time| if |key|
|
| + // is present in |event.params|.
|
| + void MaybeSaveWatchTime(const media::MediaLogEvent& event,
|
| + const char* key,
|
| + base::TimeDelta* watch_time) {
|
| + if (!event.params.HasKey(key))
|
| + return;
|
| +
|
| + double in_seconds;
|
| + const bool result =
|
| + event.params.GetDoubleWithoutPathExpansion(key, &in_seconds);
|
| + DCHECK(result);
|
| + *watch_time = base::TimeDelta::FromSecondsD(in_seconds);
|
| +
|
| + DVLOG(2) << "Saved watch time for " << key << " of " << *watch_time;
|
| + }
|
| +
|
| + enum class FinalizeType { EVERYTHING, POWER_ONLY };
|
| + void FinalizeWatchTime(WatchTimeInfo* watch_time_info,
|
| + FinalizeType finalize_type) {
|
| +// Use a macro instead of a function so we can use the histogram macro (which
|
| +// checks that the uma name is a static value). We use a custom time range for
|
| +// the histogram macro to capitalize on common expected watch times.
|
| +#define MAYBE_RECORD_WATCH_TIME(uma_name, watch_time) \
|
| + if (watch_time_info->watch_time != media::kNoTimestamp) { \
|
| + UMA_HISTOGRAM_CUSTOM_TIMES( \
|
| + media::MediaLog::uma_name, watch_time_info->watch_time, \
|
| + base::TimeDelta::FromSeconds(7), base::TimeDelta::FromHours(10), 50); \
|
| + watch_time_info->watch_time = media::kNoTimestamp; \
|
| + }
|
| +
|
| + if (finalize_type == FinalizeType::EVERYTHING) {
|
| + MAYBE_RECORD_WATCH_TIME(kWatchTimeAudioVideoAll, all_watch_time);
|
| + MAYBE_RECORD_WATCH_TIME(kWatchTimeAudioVideoMse, mse_watch_time);
|
| + MAYBE_RECORD_WATCH_TIME(kWatchTimeAudioVideoEme, eme_watch_time);
|
| + MAYBE_RECORD_WATCH_TIME(kWatchTimeAudioVideoSrc, src_watch_time);
|
| + } else {
|
| + DCHECK_EQ(finalize_type, FinalizeType::POWER_ONLY);
|
| + }
|
| + MAYBE_RECORD_WATCH_TIME(kWatchTimeAudioVideoBattery, battery_watch_time);
|
| + MAYBE_RECORD_WATCH_TIME(kWatchTimeAudioVideoAc, ac_watch_time);
|
| +#undef MAYBE_RECORD_WATCH_TIME
|
| + }
|
| +
|
| // Key is player id.
|
| typedef std::map<int, PipelineInfo> PlayerInfoMap;
|
|
|
| @@ -369,6 +423,48 @@ void MediaInternals::MediaInternalsUMAHandler::SavePlayerState(
|
| event.params.GetBoolean("video_dds", &player_info[event.id].video_dds);
|
| }
|
| break;
|
| + case media::MediaLogEvent::Type::WATCH_TIME_UPDATE: {
|
| + DVLOG(2) << "Processing watch time update.";
|
| + WatchTimeInfo& wti = player_info[event.id].watch_time_info;
|
| + MaybeSaveWatchTime(event, media::MediaLog::kWatchTimeAudioVideoAll,
|
| + &wti.all_watch_time);
|
| + MaybeSaveWatchTime(event, media::MediaLog::kWatchTimeAudioVideoMse,
|
| + &wti.mse_watch_time);
|
| + MaybeSaveWatchTime(event, media::MediaLog::kWatchTimeAudioVideoEme,
|
| + &wti.eme_watch_time);
|
| + MaybeSaveWatchTime(event, media::MediaLog::kWatchTimeAudioVideoSrc,
|
| + &wti.src_watch_time);
|
| + MaybeSaveWatchTime(event, media::MediaLog::kWatchTimeAudioVideoBattery,
|
| + &wti.battery_watch_time);
|
| + MaybeSaveWatchTime(event, media::MediaLog::kWatchTimeAudioVideoAc,
|
| + &wti.ac_watch_time);
|
| +
|
| + if (event.params.HasKey(media::MediaLog::kWatchTimeFinalize)) {
|
| + bool should_finalize;
|
| + DCHECK(event.params.GetBoolean(media::MediaLog::kWatchTimeFinalize,
|
| + &should_finalize) &&
|
| + should_finalize);
|
| + FinalizeWatchTime(&wti, FinalizeType::EVERYTHING);
|
| + } else if (event.params.HasKey(
|
| + media::MediaLog::kWatchTimeFinalizePower)) {
|
| + bool should_finalize;
|
| + DCHECK(event.params.GetBoolean(media::MediaLog::kWatchTimeFinalizePower,
|
| + &should_finalize) &&
|
| + should_finalize);
|
| + FinalizeWatchTime(&wti, FinalizeType::POWER_ONLY);
|
| + }
|
| + break;
|
| + }
|
| + case media::MediaLogEvent::Type::WEBMEDIAPLAYER_DESTROYED: {
|
| + // Upon player destruction report UMA data; if the player is not torn down
|
| + // before process exit, it will be logged during OnProcessTerminated().
|
| + auto it = player_info.find(event.id);
|
| + if (it == player_info.end())
|
| + break;
|
| +
|
| + ReportUMAForPipelineStatus(it->second);
|
| + player_info.erase(it);
|
| + }
|
| default:
|
| break;
|
| }
|
| @@ -458,6 +554,7 @@ void MediaInternals::MediaInternalsUMAHandler::OnProcessTerminated(
|
| auto it = players_it->second.begin();
|
| while (it != players_it->second.end()) {
|
| ReportUMAForPipelineStatus(it->second);
|
| + FinalizeWatchTime(&(it->second.watch_time_info), FinalizeType::EVERYTHING);
|
| players_it->second.erase(it++);
|
| }
|
| renderer_info_.erase(players_it);
|
| @@ -529,13 +626,15 @@ void MediaInternals::OnMediaEvents(
|
| DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
| // Notify observers that |event| has occurred.
|
| for (const auto& event : events) {
|
| - if (CanUpdate()) {
|
| - base::string16 update;
|
| - if (ConvertEventToUpdate(render_process_id, event, &update))
|
| - SendUpdate(update);
|
| + // Some events should not be recorded in the UI.
|
| + if (event.type != media::MediaLogEvent::Type::WATCH_TIME_UPDATE) {
|
| + if (CanUpdate()) {
|
| + base::string16 update;
|
| + if (ConvertEventToUpdate(render_process_id, event, &update))
|
| + SendUpdate(update);
|
| + }
|
| + SaveEvent(render_process_id, event);
|
| }
|
| -
|
| - SaveEvent(render_process_id, event);
|
| uma_handler_->SavePlayerState(render_process_id, event);
|
| }
|
| }
|
|
|