summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjoi@chromium.org <joi@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-03-13 10:04:49 +0000
committerjoi@chromium.org <joi@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-03-13 10:04:49 +0000
commit33247a95e79f9faeb76095c5d0cc8cdc1c498a61 (patch)
tree47386842718ef921e8619ad219ba2ca1573611d2
parentc4af841edde77c497369a451f9907a8ae61ef6d3 (diff)
downloadchromium_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.cc79
-rw-r--r--content/browser/renderer_host/media/media_stream_track_metrics_host.h56
-rw-r--r--content/browser/renderer_host/render_process_host_impl.cc2
-rw-r--r--content/common/content_message_generator.h3
-rw-r--r--content/common/media/media_stream_track_metrics_host_messages.h19
-rw-r--r--content/content_browser.gypi2
-rw-r--r--content/content_common.gypi1
-rw-r--r--content/renderer/media/remote_media_stream_impl.cc55
-rw-r--r--ipc/ipc_message_start.h1
-rw-r--r--tools/metrics/histograms/histograms.xml16
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