Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(722)

Unified Diff: content/browser/media/media_internals.cc

Issue 697463005: Add PipelineStatus UMA logging to media_internals (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Adding DCHECK for currentthread == IO Created 6 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « content/browser/media/media_internals.h ('k') | media/base/media_log.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: content/browser/media/media_internals.cc
diff --git a/content/browser/media/media_internals.cc b/content/browser/media/media_internals.cc
index 4d600851783452b708edd2a04cb59edf7c2397e6..00fcac3ac5b89d95a7ee4a0c9ff8fb0a71e097d2 100644
--- a/content/browser/media/media_internals.cc
+++ b/content/browser/media/media_internals.cc
@@ -4,13 +4,18 @@
#include "content/browser/media/media_internals.h"
+#include "base/metrics/histogram.h"
#include "base/strings/string16.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/stringprintf.h"
#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/notification_observer.h"
+#include "content/public/browser/notification_registrar.h"
+#include "content/public/browser/notification_service.h"
+#include "content/public/browser/notification_types.h"
+#include "content/public/browser/render_process_host.h"
#include "content/public/browser/web_ui.h"
#include "media/audio/audio_parameters.h"
-#include "media/base/media_log.h"
#include "media/base/media_log_event.h"
namespace {
@@ -170,19 +175,193 @@ void AudioLogImpl::StoreComponentMetadata(int component_id,
dict->SetInteger("component_type", component_);
}
+class MediaInternals::MediaInternalsUMAHandler : public NotificationObserver {
+ public:
+ MediaInternalsUMAHandler();
+
+ // NotificationObserver implementation.
+ void Observe(int type,
+ const NotificationSource& source,
+ const NotificationDetails& details) override;
+
+ // Reports the pipeline status to UMA for every player
+ // associated with the renderer process and then deletes the player state.
+ void LogAndClearPlayersInRenderer(int render_process_id);
+
+ // Helper function to save the event payload to RendererPlayerMap.
+ void SavePlayerState(const media::MediaLogEvent& event,
+ int render_process_id);
+
+ private:
+ struct PipelineInfo {
+ media::PipelineStatus last_pipeline_status;
+ bool has_audio;
+ bool has_video;
+ std::string audio_codec_name;
+ std::string video_codec_name;
+ std::string video_decoder;
+ PipelineInfo()
+ : last_pipeline_status(media::PIPELINE_OK),
+ has_audio(false),
+ has_video(false) {}
+ };
+
+ // Helper function to report PipelineStatus associated with a player to UMA.
+ void ReportUMAForPipelineStatus(const PipelineInfo& player_info);
+
+ // Key is playerid
+ typedef std::map<int, PipelineInfo> PlayerInfoMap;
+
+ // Key is renderer id
+ typedef std::map<int, PlayerInfoMap> RendererPlayerMap;
+
+ // Stores player information per renderer
+ RendererPlayerMap renderer_info_;
+
+ NotificationRegistrar registrar_;
+
+ DISALLOW_COPY_AND_ASSIGN(MediaInternalsUMAHandler);
+};
+
+MediaInternals::MediaInternalsUMAHandler::MediaInternalsUMAHandler() {
+ registrar_.Add(this, NOTIFICATION_RENDERER_PROCESS_TERMINATED,
+ NotificationService::AllBrowserContextsAndSources());
+}
+
+void MediaInternals::MediaInternalsUMAHandler::Observe(
+ int type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_EQ(type, NOTIFICATION_RENDERER_PROCESS_TERMINATED);
+ RenderProcessHost* process = Source<RenderProcessHost>(source).ptr();
+
+ // Post the task to the IO thread to avoid race in updating renderer_info_ map
+ // by both SavePlayerState & LogAndClearPlayersInRenderer from different
+ // threads.
+ // Using base::Unretained() on MediaInternalsUMAHandler is safe since
+ // it is owned by MediaInternals and share the same lifetime
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ base::Bind(&MediaInternalsUMAHandler::LogAndClearPlayersInRenderer,
+ base::Unretained(this), process->GetID()));
+}
+
+void MediaInternals::MediaInternalsUMAHandler::SavePlayerState(
+ const media::MediaLogEvent& event,
+ int render_process_id) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ PlayerInfoMap& player_info = renderer_info_[render_process_id];
+ switch (event.type) {
+ case media::MediaLogEvent::WEBMEDIAPLAYER_CREATED: {
+ // Nothing to do here
+ break;
+ }
+ case media::MediaLogEvent::PIPELINE_ERROR: {
+ int status;
+ event.params.GetInteger("pipeline_error", &status);
+ player_info[event.id].last_pipeline_status =
+ static_cast<media::PipelineStatus>(status);
+ break;
+ }
+ case media::MediaLogEvent::PROPERTY_CHANGE:
+ if (event.params.HasKey("found_audio_stream")) {
+ event.params.GetBoolean("found_audio_stream",
+ &player_info[event.id].has_audio);
+ }
+ if (event.params.HasKey("found_video_stream")) {
+ event.params.GetBoolean("found_video_stream",
+ &player_info[event.id].has_video);
+ }
+ if (event.params.HasKey("audio_codec_name")) {
+ event.params.GetString("audio_codec_name",
+ &player_info[event.id].audio_codec_name);
+ }
+ if (event.params.HasKey("video_codec_name")) {
+ event.params.GetString("video_codec_name",
+ &player_info[event.id].video_codec_name);
+ }
+ if (event.params.HasKey("video_decoder")) {
+ event.params.GetString("video_decoder",
+ &player_info[event.id].video_decoder);
+ }
+ break;
+ default:
+ break;
+ }
+ return;
+}
+
+void MediaInternals::MediaInternalsUMAHandler::ReportUMAForPipelineStatus(
+ const PipelineInfo& player_info) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ if (player_info.has_video && player_info.has_audio) {
+ if (player_info.video_codec_name == "vp8") {
+ UMA_HISTOGRAM_ENUMERATION("Media.PipelineStatus.AudioVideo.VP8",
+ player_info.last_pipeline_status,
+ media::PIPELINE_STATUS_MAX + 1);
+ } else if (player_info.video_codec_name == "vp9") {
+ UMA_HISTOGRAM_ENUMERATION("Media.PipelineStatus.AudioVideo.VP9",
+ player_info.last_pipeline_status,
+ media::PIPELINE_STATUS_MAX + 1);
+ } else if (player_info.video_codec_name == "h264") {
+ if (player_info.video_decoder == "gpu") {
+ UMA_HISTOGRAM_ENUMERATION("Media.PipelineStatus.AudioVideo.HW.H264",
+ player_info.last_pipeline_status,
+ media::PIPELINE_STATUS_MAX + 1);
+ } else {
+ UMA_HISTOGRAM_ENUMERATION("Media.PipelineStatus.AudioVideo.SW.H264",
+ player_info.last_pipeline_status,
+ media::PIPELINE_STATUS_MAX + 1);
+ }
+ } else {
+ UMA_HISTOGRAM_ENUMERATION("Media.PipelineStatus.AudioVideo",
+ player_info.last_pipeline_status,
+ media::PIPELINE_STATUS_MAX + 1);
+ }
+ } else if (player_info.has_audio) {
+ UMA_HISTOGRAM_ENUMERATION("Media.PipelineStatus.Audio",
+ player_info.last_pipeline_status,
+ media::PIPELINE_STATUS_MAX + 1);
+ } else if (player_info.has_video) {
+ UMA_HISTOGRAM_ENUMERATION("Media.PipelineStatus.Video",
+ player_info.last_pipeline_status,
+ media::PIPELINE_STATUS_MAX + 1);
+ } else {
+ UMA_HISTOGRAM_ENUMERATION("Media.PipelineStatus.Unsupported",
+ player_info.last_pipeline_status,
+ media::PIPELINE_STATUS_MAX + 1);
+ }
+}
+
+void MediaInternals::MediaInternalsUMAHandler::LogAndClearPlayersInRenderer(
+ int render_process_id) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ auto players_it = renderer_info_.find(render_process_id);
+ if (players_it == renderer_info_.end())
+ return;
+ auto it = players_it->second.begin();
+ while (it != players_it->second.end()) {
+ ReportUMAForPipelineStatus(it->second);
+ players_it->second.erase(it++);
+ }
+}
+
MediaInternals* MediaInternals::GetInstance() {
return g_media_internals.Pointer();
}
-MediaInternals::MediaInternals() : owner_ids_() {}
+MediaInternals::MediaInternals()
+ : owner_ids_(), uma_handler_(new MediaInternalsUMAHandler()) {
+}
+
MediaInternals::~MediaInternals() {}
void MediaInternals::OnMediaEvents(
int render_process_id, const std::vector<media::MediaLogEvent>& events) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
// Notify observers that |event| has occurred.
- for (std::vector<media::MediaLogEvent>::const_iterator event = events.begin();
- event != events.end(); ++event) {
+ for (auto event = events.begin(); event != events.end(); ++event) {
base::DictionaryValue dict;
dict.SetInteger("renderer", render_process_id);
dict.SetInteger("player", event->id);
@@ -193,8 +372,20 @@ void MediaInternals::OnMediaEvents(
const double ticks = event->time.ToInternalValue();
const double ticks_millis = ticks / base::Time::kMicrosecondsPerMillisecond;
dict.SetDouble("ticksMillis", ticks_millis);
- dict.Set("params", event->params.DeepCopy());
+
+ // Convert PipelineStatus to human readable string
+ if (event->type == media::MediaLogEvent::PIPELINE_ERROR) {
+ int status;
+ event->params.GetInteger("pipeline_error", &status);
+ media::PipelineStatus error = static_cast<media::PipelineStatus>(status);
+ dict.SetString("params.pipeline_error",
+ media::MediaLog::PipelineStatusToString(error));
+ } else {
+ dict.Set("params", event->params.DeepCopy());
+ }
+
SendUpdate(SerializeUpdate("media.onMediaEvent", &dict));
+ uma_handler_->SavePlayerState(*event, render_process_id);
}
}
« no previous file with comments | « content/browser/media/media_internals.h ('k') | media/base/media_log.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698