diff options
author | joi@chromium.org <joi@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-03-13 10:04:49 +0000 |
---|---|---|
committer | joi@chromium.org <joi@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-03-13 10:04:49 +0000 |
commit | 33247a95e79f9faeb76095c5d0cc8cdc1c498a61 (patch) | |
tree | 47386842718ef921e8619ad219ba2ca1573611d2 | |
parent | c4af841edde77c497369a451f9907a8ae61ef6d3 (diff) | |
download | chromium_src-33247a95e79f9faeb76095c5d0cc8cdc1c498a61.zip chromium_src-33247a95e79f9faeb76095c5d0cc8cdc1c498a61.tar.gz chromium_src-33247a95e79f9faeb76095c5d0cc8cdc1c498a61.tar.bz2 |
Add metrics to track the duration of tracks received over a PeerConnection.
NOTRY=true
TBR=jochen@chromium.org
BUG=348616
Review URL: https://codereview.chromium.org/183973021
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@256780 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | content/browser/renderer_host/media/media_stream_track_metrics_host.cc | 79 | ||||
-rw-r--r-- | content/browser/renderer_host/media/media_stream_track_metrics_host.h | 56 | ||||
-rw-r--r-- | content/browser/renderer_host/render_process_host_impl.cc | 2 | ||||
-rw-r--r-- | content/common/content_message_generator.h | 3 | ||||
-rw-r--r-- | content/common/media/media_stream_track_metrics_host_messages.h | 19 | ||||
-rw-r--r-- | content/content_browser.gypi | 2 | ||||
-rw-r--r-- | content/content_common.gypi | 1 | ||||
-rw-r--r-- | content/renderer/media/remote_media_stream_impl.cc | 55 | ||||
-rw-r--r-- | ipc/ipc_message_start.h | 1 | ||||
-rw-r--r-- | tools/metrics/histograms/histograms.xml | 16 |
10 files changed, 232 insertions, 2 deletions
diff --git a/content/browser/renderer_host/media/media_stream_track_metrics_host.cc b/content/browser/renderer_host/media/media_stream_track_metrics_host.cc new file mode 100644 index 0000000..1a7e420 --- /dev/null +++ b/content/browser/renderer_host/media/media_stream_track_metrics_host.cc @@ -0,0 +1,79 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/browser/renderer_host/media/media_stream_track_metrics_host.h" + +#include "base/metrics/histogram.h" +#include "content/common/media/media_stream_track_metrics_host_messages.h" + +// We use a histogram with a maximum bucket of 16 hours to infinity +// for track durations. +#define UMA_HISTOGRAM_TIMES_16H(name, sample) \ + UMA_HISTOGRAM_CUSTOM_TIMES(name, sample, \ + base::TimeDelta::FromMilliseconds(100), \ + base::TimeDelta::FromHours(16), \ + 50); + +namespace content { + +MediaStreamTrackMetricsHost::MediaStreamTrackMetricsHost() + : BrowserMessageFilter(MediaStreamTrackMetricsHostMsgStart) { +} + +MediaStreamTrackMetricsHost::~MediaStreamTrackMetricsHost() { + // Our render process has exited. We won't receive any more IPC + // messages from it. Assume all tracks ended now. + for (TrackMap::iterator it = tracks_.begin(); + it != tracks_.end(); + ++it) { + IsAudioPlusTimestamp& audio_and_timestamp = it->second; + ReportDuration(audio_and_timestamp.first, audio_and_timestamp.second); + } + tracks_.clear(); +} + +bool MediaStreamTrackMetricsHost::OnMessageReceived( + const IPC::Message& message, + bool* message_was_ok) { + bool handled = true; + + IPC_BEGIN_MESSAGE_MAP_EX(MediaStreamTrackMetricsHost, + message, + *message_was_ok) + IPC_MESSAGE_HANDLER(MediaStreamTrackMetricsHost_AddTrack, OnAddTrack) + IPC_MESSAGE_HANDLER(MediaStreamTrackMetricsHost_RemoveTrack, OnRemoveTrack) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP_EX() + + return handled; +} + +void MediaStreamTrackMetricsHost::OnAddTrack(uint64 id, + bool is_audio, + bool is_remote) { + DCHECK(tracks_.find(id) == tracks_.end()); + DCHECK(is_remote); // Always the case for now. + + tracks_[id] = IsAudioPlusTimestamp(is_audio, base::TimeTicks::Now()); +} + +void MediaStreamTrackMetricsHost::OnRemoveTrack(uint64 id) { + DCHECK(tracks_.find(id) != tracks_.end()); + + IsAudioPlusTimestamp& info = tracks_[id]; + ReportDuration(info.first, info.second); + tracks_.erase(id); +} + +void MediaStreamTrackMetricsHost::ReportDuration(bool is_audio, + base::TimeTicks start_time) { + base::TimeDelta duration = base::TimeTicks::Now() - start_time; + if (is_audio) { + UMA_HISTOGRAM_TIMES_16H("WebRTC.ReceivedAudioTrackDuration", duration); + } else { + UMA_HISTOGRAM_TIMES_16H("WebRTC.ReceivedVideoTrackDuration", duration); + } +} + +} // namespace content diff --git a/content/browser/renderer_host/media/media_stream_track_metrics_host.h b/content/browser/renderer_host/media/media_stream_track_metrics_host.h new file mode 100644 index 0000000..a80830e --- /dev/null +++ b/content/browser/renderer_host/media/media_stream_track_metrics_host.h @@ -0,0 +1,56 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONTENT_BROWSER_RENDERER_HOST_MEDIA_MEDIA_STREAM_TRACK_METRICS_HOST_H_ +#define CONTENT_BROWSER_RENDERER_HOST_MEDIA_MEDIA_STREAM_TRACK_METRICS_HOST_H_ + +#include <map> +#include <string> + +#include "base/time/time.h" +#include "content/public/browser/browser_message_filter.h" + +namespace content { + +// Responsible for logging metrics about audio and video track +// lifetimes. These are based on messages from the renderer that are +// sent when tracks are created and destroyed. Unfortunately we can't +// reliably log the lifetime metric in the renderer because that +// process may be destroyed at any time by the fast shutdown path (see +// RenderProcessHost::FastShutdownIfPossible). +// +// There is one instance of this class per render process. +// +// If the renderer process goes away without sending messages that +// tracks were removed, this class instead infers that the tracks were +// removed. +class MediaStreamTrackMetricsHost + : public BrowserMessageFilter { + public: + explicit MediaStreamTrackMetricsHost(); + + protected: + virtual ~MediaStreamTrackMetricsHost(); + + // BrowserMessageFilter override. + virtual bool OnMessageReceived(const IPC::Message& message, + bool* message_was_ok) OVERRIDE; + + private: + void OnAddTrack(uint64 id, bool is_audio, bool is_remote); + void OnRemoveTrack(uint64 id); + + void ReportDuration(bool is_audio, base::TimeTicks start_time); + + // Keys are unique (per renderer) track IDs, values are pairs: A + // boolean indicating whether the track is an audio track, and a + // timestamp from when the track was created. + typedef std::pair<bool, base::TimeTicks> IsAudioPlusTimestamp; + typedef std::map<uint64, IsAudioPlusTimestamp> TrackMap; + TrackMap tracks_; +}; + +} // namespace content + +#endif // CONTENT_BROWSER_RENDERER_HOST_MEDIA_MEDIA_STREAM_TRACK_METRICS_HOST_H_ diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc index c2ad917..63c29f7 100644 --- a/content/browser/renderer_host/render_process_host_impl.cc +++ b/content/browser/renderer_host/render_process_host_impl.cc @@ -153,6 +153,7 @@ #if defined(ENABLE_WEBRTC) #include "content/browser/media/webrtc_internals.h" +#include "content/browser/renderer_host/media/media_stream_track_metrics_host.h" #include "content/browser/renderer_host/media/webrtc_identity_service_host.h" #include "content/common/media/media_stream_messages.h" #endif @@ -708,6 +709,7 @@ void RenderProcessHostImpl::CreateMessageFilters() { media_stream_manager)); AddFilter( new DeviceRequestMessageFilter(resource_context, media_stream_manager)); + AddFilter(new MediaStreamTrackMetricsHost()); #endif #if defined(ENABLE_PLUGINS) AddFilter(new PepperRendererConnection(GetID())); diff --git a/content/common/content_message_generator.h b/content/common/content_message_generator.h index 44d8ca0..d7f91ec 100644 --- a/content/common/content_message_generator.h +++ b/content/common/content_message_generator.h @@ -31,8 +31,9 @@ #include "content/common/input_messages.h" #include "content/common/java_bridge_messages.h" #include "content/common/media/audio_messages.h" -#include "content/common/media/midi_messages.h" #include "content/common/media/media_stream_messages.h" +#include "content/common/media/media_stream_track_metrics_host_messages.h" +#include "content/common/media/midi_messages.h" #include "content/common/media/peer_connection_tracker_messages.h" #include "content/common/media/video_capture_messages.h" #include "content/common/media/webrtc_identity_messages.h" diff --git a/content/common/media/media_stream_track_metrics_host_messages.h b/content/common/media/media_stream_track_metrics_host_messages.h new file mode 100644 index 0000000..a7ec075 --- /dev/null +++ b/content/common/media/media_stream_track_metrics_host_messages.h @@ -0,0 +1,19 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/values.h" +#include "content/common/content_export.h" +#include "ipc/ipc_message_macros.h" + +#undef IPC_MESSAGE_EXPORT +#define IPC_MESSAGE_EXPORT CONTENT_EXPORT +#define IPC_MESSAGE_START MediaStreamTrackMetricsHostMsgStart + +// Messages sent to MediaStreamTrackMetricsHost. +IPC_MESSAGE_CONTROL3(MediaStreamTrackMetricsHost_AddTrack, + uint64 /* id */, + bool /* is_audio */, + bool /* is_remote */) +IPC_MESSAGE_CONTROL1(MediaStreamTrackMetricsHost_RemoveTrack, + uint64 /* id */) diff --git a/content/content_browser.gypi b/content/content_browser.gypi index e625c45..e8aa6b1 100644 --- a/content/content_browser.gypi +++ b/content/content_browser.gypi @@ -977,6 +977,8 @@ 'browser/renderer_host/media/media_stream_manager.h', 'browser/renderer_host/media/media_stream_provider.h', 'browser/renderer_host/media/media_stream_requester.h', + 'browser/renderer_host/media/media_stream_track_metrics_host.cc', + 'browser/renderer_host/media/media_stream_track_metrics_host.h', 'browser/renderer_host/media/media_stream_ui_proxy.cc', 'browser/renderer_host/media/media_stream_ui_proxy.h', 'browser/renderer_host/media/midi_dispatcher_host.cc', diff --git a/content/content_common.gypi b/content/content_common.gypi index 64d55be..a3cc024 100644 --- a/content/content_common.gypi +++ b/content/content_common.gypi @@ -310,6 +310,7 @@ 'common/media/media_stream_messages.h', 'common/media/media_stream_options.cc', 'common/media/media_stream_options.h', + 'common/media/media_stream_track_metrics_host_messages.h', 'common/media/midi_messages.h', 'common/media/video_capture.h', 'common/media/video_capture_messages.h', diff --git a/content/renderer/media/remote_media_stream_impl.cc b/content/renderer/media/remote_media_stream_impl.cc index 66bdb60..c156007 100644 --- a/content/renderer/media/remote_media_stream_impl.cc +++ b/content/renderer/media/remote_media_stream_impl.cc @@ -8,8 +8,10 @@ #include "base/logging.h" #include "base/strings/utf_string_conversions.h" +#include "content/common/media/media_stream_track_metrics_host_messages.h" #include "content/renderer/media/media_stream.h" #include "content/renderer/media/media_stream_dependency_factory.h" +#include "content/renderer/render_thread_impl.h" #include "third_party/WebKit/public/platform/WebString.h" namespace content { @@ -34,13 +36,26 @@ class RemoteMediaStreamTrackObserver // webrtc::ObserverInterface implementation. virtual void OnChanged() OVERRIDE; + // May be overridden by unit tests to avoid sending IPC messages. + virtual void SendLifetimeMessage(bool creation); + webrtc::MediaStreamTrackInterface::TrackState state_; scoped_refptr<webrtc::MediaStreamTrackInterface> webrtc_track_; blink::WebMediaStreamTrack webkit_track_; + bool sent_ended_message_; DISALLOW_COPY_AND_ASSIGN(RemoteMediaStreamTrackObserver); }; +// We need an ID that is unique for this observer, within the current +// renderer process, for the lifetime of the observer object. The +// simplest approach is to just use the object's pointer value. We +// store it in a uint64 which will be large enough regardless of +// platform. +uint64 MakeUniqueId(RemoteMediaStreamTrackObserver* observer) { + return reinterpret_cast<uint64>(reinterpret_cast<void*>(observer)); +} + } // namespace content namespace { @@ -78,11 +93,19 @@ RemoteMediaStreamTrackObserver::RemoteMediaStreamTrackObserver( const blink::WebMediaStreamTrack& webkit_track) : state_(webrtc_track->state()), webrtc_track_(webrtc_track), - webkit_track_(webkit_track) { + webkit_track_(webkit_track), + sent_ended_message_(false) { webrtc_track->RegisterObserver(this); + + SendLifetimeMessage(true); } RemoteMediaStreamTrackObserver::~RemoteMediaStreamTrackObserver() { + // We send the lifetime-ended message here (it will only get sent if + // not previously sent) in case we never received a kEnded state + // change. + SendLifetimeMessage(false); + webrtc_track_->UnregisterObserver(this); } @@ -104,6 +127,10 @@ void RemoteMediaStreamTrackObserver::OnChanged() { blink::WebMediaStreamSource::ReadyStateLive); break; case webrtc::MediaStreamTrackInterface::kEnded: + // This is a more reliable signal to use for duration, as + // destruction of this object might not happen until + // considerably later. + SendLifetimeMessage(false); webkit_track_.source().setReadyState( blink::WebMediaStreamSource::ReadyStateEnded); break; @@ -113,6 +140,32 @@ void RemoteMediaStreamTrackObserver::OnChanged() { } } +void RemoteMediaStreamTrackObserver::SendLifetimeMessage(bool creation) { + // We need to mirror the lifetime state for tracks to the browser + // process so that the duration of tracks can be accurately + // reported, because of RenderProcessHost::FastShutdownIfPossible, + // which in many cases will simply kill the renderer process. + // + // RenderThreadImpl::current() may be NULL in unit tests. + RenderThreadImpl* render_thread = RenderThreadImpl::current(); + if (render_thread) { + if (creation) { + RenderThreadImpl::current()->Send( + new MediaStreamTrackMetricsHost_AddTrack( + MakeUniqueId(this), + webkit_track_.source().type() == + blink::WebMediaStreamSource::TypeAudio, + true)); + } else { + if (!sent_ended_message_) { + sent_ended_message_ = true; + RenderThreadImpl::current()->Send( + new MediaStreamTrackMetricsHost_RemoveTrack(MakeUniqueId(this))); + } + } + } +} + RemoteMediaStreamImpl::RemoteMediaStreamImpl( webrtc::MediaStreamInterface* webrtc_stream) : webrtc_stream_(webrtc_stream) { diff --git a/ipc/ipc_message_start.h b/ipc/ipc_message_start.h index 7bbde9e1a..10024fc 100644 --- a/ipc/ipc_message_start.h +++ b/ipc/ipc_message_start.h @@ -97,6 +97,7 @@ enum IPCMessageStart { CastMsgStart, CdmMsgStart, ScreenOrientationMsgStart, + MediaStreamTrackMetricsHostMsgStart, LastIPCMsgStart // Must come last. }; diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml index be66c94..1cbb882 100644 --- a/tools/metrics/histograms/histograms.xml +++ b/tools/metrics/histograms/histograms.xml @@ -24529,6 +24529,22 @@ other types of suffix sets. </summary> </histogram> +<histogram name="WebRTC.ReceivedAudioTrackDuration" units="milliseconds"> + <summary> + Durations of audio tracks received over a PeerConnection. This metric is + generated based on the lifetime of an observer added for all received tracks + by content::RemoteMediaStreamImpl. + </summary> +</histogram> + +<histogram name="WebRTC.ReceivedVideoTrackDuration" units="milliseconds"> + <summary> + Durations of video tracks received over a PeerConnection. This metric is + generated based on the lifetime of an observer added for all received tracks + by content::RemoteMediaStreamImpl. + </summary> +</histogram> + <histogram name="WebRTC.ReliableDataChannelMessageSize" units="bytes"> <summary> Sizes of messages sent over reliable data channels. The size of an |