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

Side by Side 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: Posting task to IO thread on tab close 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 unified diff | 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 »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 "base/metrics/histogram.h"
7 #include "base/strings/string16.h" 8 #include "base/strings/string16.h"
8 #include "base/strings/string_number_conversions.h" 9 #include "base/strings/string_number_conversions.h"
9 #include "base/strings/stringprintf.h" 10 #include "base/strings/stringprintf.h"
10 #include "content/public/browser/browser_thread.h" 11 #include "content/public/browser/browser_thread.h"
12 #include "content/public/browser/notification_observer.h"
13 #include "content/public/browser/notification_registrar.h"
14 #include "content/public/browser/notification_service.h"
15 #include "content/public/browser/notification_types.h"
16 #include "content/public/browser/render_process_host.h"
11 #include "content/public/browser/web_ui.h" 17 #include "content/public/browser/web_ui.h"
12 #include "media/audio/audio_parameters.h" 18 #include "media/audio/audio_parameters.h"
13 #include "media/base/media_log.h"
14 #include "media/base/media_log_event.h" 19 #include "media/base/media_log_event.h"
15 20
16 namespace { 21 namespace {
17 22
18 static base::LazyInstance<content::MediaInternals>::Leaky g_media_internals = 23 static base::LazyInstance<content::MediaInternals>::Leaky g_media_internals =
19 LAZY_INSTANCE_INITIALIZER; 24 LAZY_INSTANCE_INITIALIZER;
20 25
21 base::string16 SerializeUpdate(const std::string& function, 26 base::string16 SerializeUpdate(const std::string& function,
22 const base::Value* value) { 27 const base::Value* value) {
23 return content::WebUI::GetJavascriptCall( 28 return content::WebUI::GetJavascriptCall(
(...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after
163 FormatCacheKey(component_id), kAudioLogUpdateFunction, &dict); 168 FormatCacheKey(component_id), kAudioLogUpdateFunction, &dict);
164 } 169 }
165 170
166 void AudioLogImpl::StoreComponentMetadata(int component_id, 171 void AudioLogImpl::StoreComponentMetadata(int component_id,
167 base::DictionaryValue* dict) { 172 base::DictionaryValue* dict) {
168 dict->SetInteger("owner_id", owner_id_); 173 dict->SetInteger("owner_id", owner_id_);
169 dict->SetInteger("component_id", component_id); 174 dict->SetInteger("component_id", component_id);
170 dict->SetInteger("component_type", component_); 175 dict->SetInteger("component_type", component_);
171 } 176 }
172 177
178 class MediaInternals::MediaInternalsUMAHandler : public NotificationObserver {
179 public:
180 MediaInternalsUMAHandler();
181
182 // NotificationObserver implementation.
183 void Observe(int type,
184 const NotificationSource& source,
185 const NotificationDetails& details) override;
186
187 // Reports the pipeline status to UMA for every player
188 // associated with the renderer process and then deletes the player state.
189 void LogAndClearPlayersInRenderer(int render_process_id);
190
191 // Helper function to save the event payload to RendererPlayerMap.
192 void SavePlayerState(const media::MediaLogEvent& event,
193 int render_process_id);
194
195 private:
196 struct PipelineInfo {
197 media::PipelineStatus last_pipeline_status;
198 bool has_audio;
199 bool has_video;
200 std::string audio_codec_name;
201 std::string video_codec_name;
202 std::string video_decoder;
203 PipelineInfo()
204 : last_pipeline_status(media::PIPELINE_OK),
205 has_audio(false),
206 has_video(false) {}
207 };
208
209 // Helper function to report PipelineStatus associated with a player to UMA.
210 void ReportUMAForPipelineStatus(const PipelineInfo& player_info);
211
212 // Key is playerid
213 typedef std::map<int, PipelineInfo> PlayerInfoMap;
214
215 // Key is renderer id
216 typedef std::map<int, PlayerInfoMap> RendererPlayerMap;
217
218 // Stores player information per renderer
219 RendererPlayerMap renderer_info_;
220
221 NotificationRegistrar registrar_;
222
223 DISALLOW_COPY_AND_ASSIGN(MediaInternalsUMAHandler);
224 };
225
226 MediaInternals::MediaInternalsUMAHandler::MediaInternalsUMAHandler() {
227 registrar_.Add(this, NOTIFICATION_RENDERER_PROCESS_TERMINATED,
228 NotificationService::AllBrowserContextsAndSources());
229 }
230
231 void MediaInternals::MediaInternalsUMAHandler::Observe(
232 int type,
233 const NotificationSource& source,
234 const NotificationDetails& details) {
235 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
236 DCHECK_EQ(type, NOTIFICATION_RENDERER_PROCESS_TERMINATED);
237 RenderProcessHost* process = Source<RenderProcessHost>(source).ptr();
238
239 // Post the task to the IO thread to avoid race in updating renderer_info_ map
240 // by both SavePlayerState & LogAndClearPlayersInRenderer from different
241 // threads.
242 // Using base::Unretained() on MediaInternalsUMAHandler is safe since
243 // it is owned by MediaInternals and share the same lifetime
prabhur1 2014/11/13 01:54:39 Could you confirm if my assumption is correct abou
DaleCurtis 2014/11/13 01:57:48 Unretained is fine since this class is never destr
prabhur1 2014/11/13 02:12:16 Done.
prabhur1 2014/11/13 02:12:16 Thanks!
244 BrowserThread::PostTask(
245 BrowserThread::IO, FROM_HERE,
246 base::Bind(&MediaInternalsUMAHandler::LogAndClearPlayersInRenderer,
247 base::Unretained(this), process->GetID()));
248 }
249
250 void MediaInternals::MediaInternalsUMAHandler::SavePlayerState(
251 const media::MediaLogEvent& event,
252 int render_process_id) {
253 PlayerInfoMap& player_info = renderer_info_[render_process_id];
DaleCurtis 2014/11/13 01:57:48 Add a DCHECK(CurrentlyOn::IO) ?
prabhur1 2014/11/13 02:12:16 Done.
254 switch (event.type) {
255 case media::MediaLogEvent::WEBMEDIAPLAYER_CREATED: {
256 // Nothing to do here
257 break;
258 }
259 case media::MediaLogEvent::PIPELINE_ERROR: {
260 int status;
261 event.params.GetInteger("pipeline_error", &status);
262 player_info[event.id].last_pipeline_status =
263 static_cast<media::PipelineStatus>(status);
264 break;
265 }
266 case media::MediaLogEvent::PROPERTY_CHANGE:
267 if (event.params.HasKey("found_audio_stream")) {
268 event.params.GetBoolean("found_audio_stream",
269 &player_info[event.id].has_audio);
270 }
271 if (event.params.HasKey("found_video_stream")) {
272 event.params.GetBoolean("found_video_stream",
273 &player_info[event.id].has_video);
274 }
275 if (event.params.HasKey("audio_codec_name")) {
276 event.params.GetString("audio_codec_name",
277 &player_info[event.id].audio_codec_name);
278 }
279 if (event.params.HasKey("video_codec_name")) {
280 event.params.GetString("video_codec_name",
281 &player_info[event.id].video_codec_name);
282 }
283 if (event.params.HasKey("video_decoder")) {
284 event.params.GetString("video_decoder",
285 &player_info[event.id].video_decoder);
286 }
287 break;
288 default:
289 break;
290 }
291 return;
292 }
293
294 void MediaInternals::MediaInternalsUMAHandler::ReportUMAForPipelineStatus(
295 const PipelineInfo& player_info) {
296 if (player_info.has_video && player_info.has_audio) {
DaleCurtis 2014/11/13 01:57:47 Ditto.
prabhur1 2014/11/13 02:12:16 Done.
297 if (player_info.video_codec_name == "vp8") {
298 UMA_HISTOGRAM_ENUMERATION("Media.PipelineStatus.AudioVideo.VP8",
299 player_info.last_pipeline_status,
300 media::PIPELINE_STATUS_MAX + 1);
301 } else if (player_info.video_codec_name == "vp9") {
302 UMA_HISTOGRAM_ENUMERATION("Media.PipelineStatus.AudioVideo.VP9",
303 player_info.last_pipeline_status,
304 media::PIPELINE_STATUS_MAX + 1);
305 } else if (player_info.video_codec_name == "h264") {
306 if (player_info.video_decoder == "gpu") {
307 UMA_HISTOGRAM_ENUMERATION("Media.PipelineStatus.AudioVideo.HW.H264",
308 player_info.last_pipeline_status,
309 media::PIPELINE_STATUS_MAX + 1);
310 } else {
311 UMA_HISTOGRAM_ENUMERATION("Media.PipelineStatus.AudioVideo.SW.H264",
312 player_info.last_pipeline_status,
313 media::PIPELINE_STATUS_MAX + 1);
314 }
315 } else {
316 UMA_HISTOGRAM_ENUMERATION("Media.PipelineStatus.AudioVideo",
317 player_info.last_pipeline_status,
318 media::PIPELINE_STATUS_MAX + 1);
319 }
320 } else if (player_info.has_audio) {
321 UMA_HISTOGRAM_ENUMERATION("Media.PipelineStatus.Audio",
322 player_info.last_pipeline_status,
323 media::PIPELINE_STATUS_MAX + 1);
324 } else if (player_info.has_video) {
325 UMA_HISTOGRAM_ENUMERATION("Media.PipelineStatus.Video",
326 player_info.last_pipeline_status,
327 media::PIPELINE_STATUS_MAX + 1);
328 } else {
329 UMA_HISTOGRAM_ENUMERATION("Media.PipelineStatus.Unsupported",
330 player_info.last_pipeline_status,
331 media::PIPELINE_STATUS_MAX + 1);
332 }
333 }
334
335 void MediaInternals::MediaInternalsUMAHandler::LogAndClearPlayersInRenderer(
336 int render_process_id) {
337 auto players_it = renderer_info_.find(render_process_id);
DaleCurtis 2014/11/13 01:57:47 Ditto.
prabhur1 2014/11/13 02:12:16 Done.
338 if (players_it == renderer_info_.end())
339 return;
340 auto it = players_it->second.begin();
341 while (it != players_it->second.end()) {
342 ReportUMAForPipelineStatus(it->second);
343 players_it->second.erase(it++);
344 }
345 }
346
173 MediaInternals* MediaInternals::GetInstance() { 347 MediaInternals* MediaInternals::GetInstance() {
174 return g_media_internals.Pointer(); 348 return g_media_internals.Pointer();
175 } 349 }
176 350
177 MediaInternals::MediaInternals() : owner_ids_() {} 351 MediaInternals::MediaInternals()
352 : owner_ids_(), uma_handler_(new MediaInternalsUMAHandler()) {
353 }
354
178 MediaInternals::~MediaInternals() {} 355 MediaInternals::~MediaInternals() {}
179 356
180 void MediaInternals::OnMediaEvents( 357 void MediaInternals::OnMediaEvents(
181 int render_process_id, const std::vector<media::MediaLogEvent>& events) { 358 int render_process_id, const std::vector<media::MediaLogEvent>& events) {
182 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 359 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
183 // Notify observers that |event| has occurred. 360 // Notify observers that |event| has occurred.
184 for (std::vector<media::MediaLogEvent>::const_iterator event = events.begin(); 361 for (auto event = events.begin(); event != events.end(); ++event) {
185 event != events.end(); ++event) {
186 base::DictionaryValue dict; 362 base::DictionaryValue dict;
187 dict.SetInteger("renderer", render_process_id); 363 dict.SetInteger("renderer", render_process_id);
188 dict.SetInteger("player", event->id); 364 dict.SetInteger("player", event->id);
189 dict.SetString("type", media::MediaLog::EventTypeToString(event->type)); 365 dict.SetString("type", media::MediaLog::EventTypeToString(event->type));
190 366
191 // TODO(dalecurtis): This is technically not correct. TimeTicks "can't" be 367 // TODO(dalecurtis): This is technically not correct. TimeTicks "can't" be
192 // converted to to a human readable time format. See base/time/time.h. 368 // converted to to a human readable time format. See base/time/time.h.
193 const double ticks = event->time.ToInternalValue(); 369 const double ticks = event->time.ToInternalValue();
194 const double ticks_millis = ticks / base::Time::kMicrosecondsPerMillisecond; 370 const double ticks_millis = ticks / base::Time::kMicrosecondsPerMillisecond;
195 dict.SetDouble("ticksMillis", ticks_millis); 371 dict.SetDouble("ticksMillis", ticks_millis);
196 dict.Set("params", event->params.DeepCopy()); 372
373 // Convert PipelineStatus to human readable string
374 if (event->type == media::MediaLogEvent::PIPELINE_ERROR) {
375 int status;
376 event->params.GetInteger("pipeline_error", &status);
377 media::PipelineStatus error = static_cast<media::PipelineStatus>(status);
378 dict.SetString("params.pipeline_error",
379 media::MediaLog::PipelineStatusToString(error));
380 } else {
381 dict.Set("params", event->params.DeepCopy());
382 }
383
197 SendUpdate(SerializeUpdate("media.onMediaEvent", &dict)); 384 SendUpdate(SerializeUpdate("media.onMediaEvent", &dict));
385 uma_handler_->SavePlayerState(*event, render_process_id);
198 } 386 }
199 } 387 }
200 388
201 void MediaInternals::AddUpdateCallback(const UpdateCallback& callback) { 389 void MediaInternals::AddUpdateCallback(const UpdateCallback& callback) {
202 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 390 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
203 update_callbacks_.push_back(callback); 391 update_callbacks_.push_back(callback);
204 } 392 }
205 393
206 void MediaInternals::RemoveUpdateCallback(const UpdateCallback& callback) { 394 void MediaInternals::RemoveUpdateCallback(const UpdateCallback& callback) {
207 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 395 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after
300 const std::string& function, 488 const std::string& function,
301 const base::DictionaryValue* value) { 489 const base::DictionaryValue* value) {
302 SendUpdate(SerializeUpdate(function, value)); 490 SendUpdate(SerializeUpdate(function, value));
303 491
304 base::AutoLock auto_lock(lock_); 492 base::AutoLock auto_lock(lock_);
305 scoped_ptr<base::Value> out_value; 493 scoped_ptr<base::Value> out_value;
306 CHECK(audio_streams_cached_data_.Remove(cache_key, &out_value)); 494 CHECK(audio_streams_cached_data_.Remove(cache_key, &out_value));
307 } 495 }
308 496
309 } // namespace content 497 } // namespace content
OLDNEW
« 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