#include <vector>
#include "base/command_line.h"
+#include "base/debug/trace_event.h"
+#include "base/lazy_instance.h"
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
+#include "base/metrics/histogram.h"
#include "base/stl_util.h"
#include "base/strings/utf_string_conversions.h"
#include "content/public/common/content_switches.h"
-#include "content/renderer/media/media_stream_dependency_factory.h"
-#include "content/renderer/media/media_stream_source_extra_data.h"
+#include "content/renderer/media/media_stream_track.h"
#include "content/renderer/media/peer_connection_tracker.h"
#include "content/renderer/media/remote_media_stream_impl.h"
#include "content/renderer/media/rtc_data_channel_handler.h"
#include "content/renderer/media/rtc_dtmf_sender_handler.h"
#include "content/renderer/media/rtc_media_constraints.h"
+#include "content/renderer/media/webrtc/peer_connection_dependency_factory.h"
+#include "content/renderer/media/webrtc/webrtc_media_stream_adapter.h"
#include "content/renderer/media/webrtc_audio_capturer.h"
#include "content/renderer/media/webrtc_audio_device_impl.h"
+#include "content/renderer/media/webrtc_uma_histograms.h"
#include "content/renderer/render_thread_impl.h"
#include "third_party/WebKit/public/platform/WebMediaConstraints.h"
-// TODO(hta): Move the following include to WebRTCStatsRequest.h file.
#include "third_party/WebKit/public/platform/WebMediaStreamSource.h"
-#include "third_party/WebKit/public/platform/WebMediaStreamTrack.h"
#include "third_party/WebKit/public/platform/WebRTCConfiguration.h"
#include "third_party/WebKit/public/platform/WebRTCDataChannelInit.h"
#include "third_party/WebKit/public/platform/WebRTCICECandidate.h"
-#include "third_party/WebKit/public/platform/WebRTCPeerConnectionHandlerClient.h"
+#include "third_party/WebKit/public/platform/WebRTCOfferOptions.h"
#include "third_party/WebKit/public/platform/WebRTCSessionDescription.h"
#include "third_party/WebKit/public/platform/WebRTCSessionDescriptionRequest.h"
-#include "third_party/WebKit/public/platform/WebRTCStatsRequest.h"
#include "third_party/WebKit/public/platform/WebRTCVoidRequest.h"
#include "third_party/WebKit/public/platform/WebURL.h"
-#include "third_party/WebKit/public/web/WebFrame.h"
namespace content {
// Converter functions from WebKit types to libjingle types.
-static void GetNativeIceServers(
+static void GetNativeRtcConfiguration(
const blink::WebRTCConfiguration& server_configuration,
- webrtc::PeerConnectionInterface::IceServers* servers) {
- if (server_configuration.isNull() || !servers)
+ webrtc::PeerConnectionInterface::RTCConfiguration* config) {
+ if (server_configuration.isNull() || !config)
return;
for (size_t i = 0; i < server_configuration.numberOfServers(); ++i) {
webrtc::PeerConnectionInterface::IceServer server;
server.username = base::UTF16ToUTF8(webkit_server.username());
server.password = base::UTF16ToUTF8(webkit_server.credential());
server.uri = webkit_server.uri().spec();
- servers->push_back(server);
+ config->servers.push_back(server);
+ }
+
+ switch (server_configuration.iceTransports()) {
+ case blink::WebRTCIceTransportsNone:
+ config->type = webrtc::PeerConnectionInterface::kNone;
+ break;
+ case blink::WebRTCIceTransportsRelay:
+ config->type = webrtc::PeerConnectionInterface::kRelay;
+ break;
+ case blink::WebRTCIceTransportsAll:
+ config->type = webrtc::PeerConnectionInterface::kAll;
+ break;
+ default:
+ NOTREACHED();
}
}
virtual void OnSuccess(webrtc::SessionDescriptionInterface* desc) OVERRIDE {
tracker_.TrackOnSuccess(desc);
webkit_request_.requestSucceeded(CreateWebKitSessionDescription(desc));
+ delete desc;
}
virtual void OnFailure(const std::string& error) OVERRIDE {
tracker_.TrackOnFailure(error);
class StatsResponse : public webrtc::StatsObserver {
public:
explicit StatsResponse(const scoped_refptr<LocalRTCStatsRequest>& request)
- : request_(request.get()), response_(request_->createResponse().get()) {}
+ : request_(request.get()), response_(request_->createResponse().get()) {
+ // Measure the overall time it takes to satisfy a getStats request.
+ TRACE_EVENT_ASYNC_BEGIN0("webrtc", "getStats_Native", this);
+ }
virtual void OnComplete(
const std::vector<webrtc::StatsReport>& reports) OVERRIDE {
+ TRACE_EVENT0("webrtc", "StatsResponse::OnComplete")
for (std::vector<webrtc::StatsReport>::const_iterator it = reports.begin();
it != reports.end(); ++it) {
if (it->values.size() > 0) {
AddReport(*it);
}
}
+
+ // Record the getSync operation as done before calling into Blink so that
+ // we don't skew the perf measurements of the native code with whatever the
+ // callback might be doing.
+ TRACE_EVENT_ASYNC_END0("webrtc", "getStats_Native", this);
+
request_->requestSucceeded(response_);
}
for (webrtc::StatsReport::Values::const_iterator value_it =
report.values.begin();
value_it != report.values.end(); ++value_it) {
- AddStatistic(idx, value_it->name, value_it->value);
+ AddStatistic(idx, value_it->display_name(), value_it->value);
}
}
- void AddStatistic(int idx, const std::string& name,
- const std::string& value) {
+ void AddStatistic(int idx, const char* name, const std::string& value) {
response_->addStatistic(idx,
blink::WebString::fromUTF8(name),
blink::WebString::fromUTF8(value));
}
- talk_base::scoped_refptr<LocalRTCStatsRequest> request_;
- talk_base::scoped_refptr<LocalRTCStatsResponse> response_;
+ rtc::scoped_refptr<LocalRTCStatsRequest> request_;
+ rtc::scoped_refptr<LocalRTCStatsResponse> response_;
};
// Implementation of LocalRTCStatsRequest.
scoped_refptr<LocalRTCStatsResponse> LocalRTCStatsRequest::createResponse() {
DCHECK(!response_);
- response_ = new talk_base::RefCountedObject<LocalRTCStatsResponse>(
+ response_ = new rtc::RefCountedObject<LocalRTCStatsResponse>(
impl_.createResponse());
return response_.get();
}
impl_.addStatistic(report, name, value);
}
+namespace {
+
+class PeerConnectionUMAObserver : public webrtc::UMAObserver {
+ public:
+ PeerConnectionUMAObserver() {}
+ virtual ~PeerConnectionUMAObserver() {}
+
+ virtual void IncrementCounter(
+ webrtc::PeerConnectionUMAMetricsCounter counter) OVERRIDE {
+ UMA_HISTOGRAM_ENUMERATION("WebRTC.PeerConnection.IPMetrics",
+ counter,
+ webrtc::kBoundary);
+ }
+
+ virtual void AddHistogramSample(
+ webrtc::PeerConnectionUMAMetricsName type, int value) OVERRIDE {
+ switch (type) {
+ case webrtc::kTimeToConnect:
+ UMA_HISTOGRAM_MEDIUM_TIMES(
+ "WebRTC.PeerConnection.TimeToConnect",
+ base::TimeDelta::FromMilliseconds(value));
+ break;
+ case webrtc::kNetworkInterfaces_IPv4:
+ UMA_HISTOGRAM_COUNTS_100("WebRTC.PeerConnection.IPv4Interfaces",
+ value);
+ break;
+ case webrtc::kNetworkInterfaces_IPv6:
+ UMA_HISTOGRAM_COUNTS_100("WebRTC.PeerConnection.IPv6Interfaces",
+ value);
+ break;
+ default:
+ NOTREACHED();
+ }
+ }
+};
+
+base::LazyInstance<std::set<RTCPeerConnectionHandler*> >::Leaky
+ g_peer_connection_handlers = LAZY_INSTANCE_INITIALIZER;
+
+} // namespace
+
RTCPeerConnectionHandler::RTCPeerConnectionHandler(
blink::WebRTCPeerConnectionHandlerClient* client,
- MediaStreamDependencyFactory* dependency_factory)
- : PeerConnectionHandlerBase(dependency_factory),
- client_(client),
+ PeerConnectionDependencyFactory* dependency_factory)
+ : client_(client),
+ dependency_factory_(dependency_factory),
frame_(NULL),
- peer_connection_tracker_(NULL) {
+ peer_connection_tracker_(NULL),
+ num_data_channels_created_(0) {
+ g_peer_connection_handlers.Get().insert(this);
}
RTCPeerConnectionHandler::~RTCPeerConnectionHandler() {
+ g_peer_connection_handlers.Get().erase(this);
if (peer_connection_tracker_)
peer_connection_tracker_->UnregisterPeerConnection(this);
STLDeleteValues(&remote_streams_);
+
+ UMA_HISTOGRAM_COUNTS_10000(
+ "WebRTC.NumDataChannelsPerPeerConnection", num_data_channels_created_);
+}
+
+// static
+void RTCPeerConnectionHandler::DestructAllHandlers() {
+ std::set<RTCPeerConnectionHandler*> handlers(
+ g_peer_connection_handlers.Get().begin(),
+ g_peer_connection_handlers.Get().end());
+ for (std::set<RTCPeerConnectionHandler*>::iterator handler = handlers.begin();
+ handler != handlers.end();
+ ++handler) {
+ (*handler)->client_->releasePeerConnectionHandler();
+ }
+}
+
+void RTCPeerConnectionHandler::ConvertOfferOptionsToConstraints(
+ const blink::WebRTCOfferOptions& options,
+ RTCMediaConstraints* output) {
+ output->AddMandatory(
+ webrtc::MediaConstraintsInterface::kOfferToReceiveAudio,
+ options.offerToReceiveAudio() > 0 ? "true" : "false",
+ true);
+
+ output->AddMandatory(
+ webrtc::MediaConstraintsInterface::kOfferToReceiveVideo,
+ options.offerToReceiveVideo() > 0 ? "true" : "false",
+ true);
+
+ if (!options.voiceActivityDetection()) {
+ output->AddMandatory(
+ webrtc::MediaConstraintsInterface::kVoiceActivityDetection,
+ "false",
+ true);
+ }
+
+ if (options.iceRestart()) {
+ output->AddMandatory(
+ webrtc::MediaConstraintsInterface::kIceRestart, "true", true);
+ }
}
void RTCPeerConnectionHandler::associateWithFrame(blink::WebFrame* frame) {
peer_connection_tracker_ =
RenderThreadImpl::current()->peer_connection_tracker();
- webrtc::PeerConnectionInterface::IceServers servers;
- GetNativeIceServers(server_configuration, &servers);
+ webrtc::PeerConnectionInterface::RTCConfiguration config;
+ GetNativeRtcConfiguration(server_configuration, &config);
RTCMediaConstraints constraints(options);
native_peer_connection_ =
dependency_factory_->CreatePeerConnection(
- servers, &constraints, frame_, this);
+ config, &constraints, frame_, this);
+
if (!native_peer_connection_.get()) {
LOG(ERROR) << "Failed to initialize native PeerConnection.";
return false;
}
if (peer_connection_tracker_)
peer_connection_tracker_->RegisterPeerConnection(
- this, servers, constraints, frame_);
+ this, config, constraints, frame_);
+ uma_observer_ = new rtc::RefCountedObject<PeerConnectionUMAObserver>();
+ native_peer_connection_->RegisterUMAObserver(uma_observer_.get());
return true;
}
const blink::WebRTCConfiguration& server_configuration,
const blink::WebMediaConstraints& options,
PeerConnectionTracker* peer_connection_tracker) {
- webrtc::PeerConnectionInterface::IceServers servers;
- GetNativeIceServers(server_configuration, &servers);
+ webrtc::PeerConnectionInterface::RTCConfiguration config;
+ GetNativeRtcConfiguration(server_configuration, &config);
RTCMediaConstraints constraints(options);
native_peer_connection_ =
dependency_factory_->CreatePeerConnection(
- servers, &constraints, NULL, this);
+ config, &constraints, NULL, this);
if (!native_peer_connection_.get()) {
LOG(ERROR) << "Failed to initialize native PeerConnection.";
return false;
const blink::WebRTCSessionDescriptionRequest& request,
const blink::WebMediaConstraints& options) {
scoped_refptr<CreateSessionDescriptionRequest> description_request(
- new talk_base::RefCountedObject<CreateSessionDescriptionRequest>(
+ new rtc::RefCountedObject<CreateSessionDescriptionRequest>(
request, this, PeerConnectionTracker::ACTION_CREATE_OFFER));
RTCMediaConstraints constraints(options);
native_peer_connection_->CreateOffer(description_request.get(), &constraints);
peer_connection_tracker_->TrackCreateOffer(this, constraints);
}
+void RTCPeerConnectionHandler::createOffer(
+ const blink::WebRTCSessionDescriptionRequest& request,
+ const blink::WebRTCOfferOptions& options) {
+ scoped_refptr<CreateSessionDescriptionRequest> description_request(
+ new rtc::RefCountedObject<CreateSessionDescriptionRequest>(
+ request, this, PeerConnectionTracker::ACTION_CREATE_OFFER));
+
+ RTCMediaConstraints constraints;
+ ConvertOfferOptionsToConstraints(options, &constraints);
+ native_peer_connection_->CreateOffer(description_request.get(), &constraints);
+
+ if (peer_connection_tracker_)
+ peer_connection_tracker_->TrackCreateOffer(this, constraints);
+}
+
void RTCPeerConnectionHandler::createAnswer(
const blink::WebRTCSessionDescriptionRequest& request,
const blink::WebMediaConstraints& options) {
scoped_refptr<CreateSessionDescriptionRequest> description_request(
- new talk_base::RefCountedObject<CreateSessionDescriptionRequest>(
+ new rtc::RefCountedObject<CreateSessionDescriptionRequest>(
request, this, PeerConnectionTracker::ACTION_CREATE_ANSWER));
RTCMediaConstraints constraints(options);
native_peer_connection_->CreateAnswer(description_request.get(),
this, description, PeerConnectionTracker::SOURCE_LOCAL);
scoped_refptr<SetSessionDescriptionRequest> set_request(
- new talk_base::RefCountedObject<SetSessionDescriptionRequest>(
+ new rtc::RefCountedObject<SetSessionDescriptionRequest>(
request, this, PeerConnectionTracker::ACTION_SET_LOCAL_DESCRIPTION));
native_peer_connection_->SetLocalDescription(set_request.get(), native_desc);
}
this, description, PeerConnectionTracker::SOURCE_REMOTE);
scoped_refptr<SetSessionDescriptionRequest> set_request(
- new talk_base::RefCountedObject<SetSessionDescriptionRequest>(
+ new rtc::RefCountedObject<SetSessionDescriptionRequest>(
request, this, PeerConnectionTracker::ACTION_SET_REMOTE_DESCRIPTION));
native_peer_connection_->SetRemoteDescription(set_request.get(), native_desc);
}
bool RTCPeerConnectionHandler::updateICE(
const blink::WebRTCConfiguration& server_configuration,
const blink::WebMediaConstraints& options) {
- webrtc::PeerConnectionInterface::IceServers servers;
- GetNativeIceServers(server_configuration, &servers);
+ webrtc::PeerConnectionInterface::RTCConfiguration config;
+ GetNativeRtcConfiguration(server_configuration, &config);
RTCMediaConstraints constraints(options);
if (peer_connection_tracker_)
- peer_connection_tracker_->TrackUpdateIce(this, servers, constraints);
+ peer_connection_tracker_->TrackUpdateIce(this, config, constraints);
- return native_peer_connection_->UpdateIce(servers,
+ return native_peer_connection_->UpdateIce(config.servers,
&constraints);
}
bool RTCPeerConnectionHandler::addStream(
const blink::WebMediaStream& stream,
const blink::WebMediaConstraints& options) {
- RTCMediaConstraints constraints(options);
+
+ for (ScopedVector<WebRtcMediaStreamAdapter>::iterator adapter_it =
+ local_streams_.begin(); adapter_it != local_streams_.end();
+ ++adapter_it) {
+ if ((*adapter_it)->IsEqual(stream)) {
+ DVLOG(1) << "RTCPeerConnectionHandler::addStream called with the same "
+ << "stream twice. id=" << stream.id().utf8();
+ return false;
+ }
+ }
if (peer_connection_tracker_)
peer_connection_tracker_->TrackAddStream(
this, stream, PeerConnectionTracker::SOURCE_LOCAL);
- // A media stream is connected to a peer connection, enable the
- // peer connection mode for the sources.
- blink::WebVector<blink::WebMediaStreamTrack> audio_tracks;
- stream.audioTracks(audio_tracks);
- for (size_t i = 0; i < audio_tracks.size(); ++i) {
- const blink::WebMediaStreamSource& source = audio_tracks[i].source();
- MediaStreamSourceExtraData* extra_data =
- static_cast<MediaStreamSourceExtraData*>(source.extraData());
- // |extra_data| is NULL if the track is a remote audio track.
- if (extra_data && extra_data->GetAudioCapturer())
- extra_data->GetAudioCapturer()->EnablePeerConnectionMode();
- }
+ PerSessionWebRTCAPIMetrics::GetInstance()->IncrementStreamCounter();
+
+ WebRtcMediaStreamAdapter* adapter =
+ new WebRtcMediaStreamAdapter(stream, dependency_factory_);
+ local_streams_.push_back(adapter);
+
+ webrtc::MediaStreamInterface* webrtc_stream = adapter->webrtc_media_stream();
+ track_metrics_.AddStream(MediaStreamTrackMetrics::SENT_STREAM,
+ webrtc_stream);
- return AddStream(stream, &constraints);
+ RTCMediaConstraints constraints(options);
+ return native_peer_connection_->AddStream(webrtc_stream, &constraints);
}
void RTCPeerConnectionHandler::removeStream(
const blink::WebMediaStream& stream) {
- RemoveStream(stream);
+ // Find the webrtc stream.
+ scoped_refptr<webrtc::MediaStreamInterface> webrtc_stream;
+ for (ScopedVector<WebRtcMediaStreamAdapter>::iterator adapter_it =
+ local_streams_.begin(); adapter_it != local_streams_.end();
+ ++adapter_it) {
+ if ((*adapter_it)->IsEqual(stream)) {
+ webrtc_stream = (*adapter_it)->webrtc_media_stream();
+ local_streams_.erase(adapter_it);
+ break;
+ }
+ }
+ DCHECK(webrtc_stream);
+ native_peer_connection_->RemoveStream(webrtc_stream);
+
if (peer_connection_tracker_)
peer_connection_tracker_->TrackRemoveStream(
this, stream, PeerConnectionTracker::SOURCE_LOCAL);
+ PerSessionWebRTCAPIMetrics::GetInstance()->DecrementStreamCounter();
+ track_metrics_.RemoveStream(MediaStreamTrackMetrics::SENT_STREAM,
+ webrtc_stream);
}
void RTCPeerConnectionHandler::getStats(
const blink::WebRTCStatsRequest& request) {
scoped_refptr<LocalRTCStatsRequest> inner_request(
- new talk_base::RefCountedObject<LocalRTCStatsRequest>(request));
+ new rtc::RefCountedObject<LocalRTCStatsRequest>(request));
getStats(inner_request.get());
}
void RTCPeerConnectionHandler::getStats(LocalRTCStatsRequest* request) {
- talk_base::scoped_refptr<webrtc::StatsObserver> observer(
- new talk_base::RefCountedObject<StatsResponse>(request));
+ rtc::scoped_refptr<webrtc::StatsObserver> observer(
+ new rtc::RefCountedObject<StatsResponse>(request));
webrtc::MediaStreamTrackInterface* track = NULL;
if (request->hasSelector()) {
- track = MediaStreamDependencyFactory::GetNativeMediaStreamTrack(
- request->component());
+ blink::WebMediaStreamSource::Type type =
+ request->component().source().type();
+ std::string track_id = request->component().id().utf8();
+ if (type == blink::WebMediaStreamSource::TypeAudio) {
+ track =
+ native_peer_connection_->local_streams()->FindAudioTrack(track_id);
+ if (!track) {
+ track =
+ native_peer_connection_->remote_streams()->FindAudioTrack(track_id);
+ }
+ } else {
+ DCHECK_EQ(blink::WebMediaStreamSource::TypeVideo, type);
+ track =
+ native_peer_connection_->local_streams()->FindVideoTrack(track_id);
+ if (!track) {
+ track =
+ native_peer_connection_->remote_streams()->FindVideoTrack(track_id);
+ }
+ }
if (!track) {
DVLOG(1) << "GetStats: Track not found.";
// TODO(hta): Consider how to get an error back.
return;
}
}
- GetStats(observer, track);
+ GetStats(observer,
+ track,
+ webrtc::PeerConnectionInterface::kStatsOutputLevelStandard);
}
void RTCPeerConnectionHandler::GetStats(
webrtc::StatsObserver* observer,
- webrtc::MediaStreamTrackInterface* track) {
- if (!native_peer_connection_->GetStats(observer, track)) {
+ webrtc::MediaStreamTrackInterface* track,
+ webrtc::PeerConnectionInterface::StatsOutputLevel level) {
+ TRACE_EVENT0("webrtc", "RTCPeerConnectionHandler::GetStats");
+ if (!native_peer_connection_->GetStats(observer, track, level)) {
DVLOG(1) << "GetStats failed.";
// TODO(hta): Consider how to get an error back.
std::vector<webrtc::StatsReport> no_reports;
config.maxRetransmitTime = init.maxRetransmitTime;
config.protocol = base::UTF16ToUTF8(init.protocol);
- talk_base::scoped_refptr<webrtc::DataChannelInterface> webrtc_channel(
+ rtc::scoped_refptr<webrtc::DataChannelInterface> webrtc_channel(
native_peer_connection_->CreateDataChannel(base::UTF16ToUTF8(label),
&config));
if (!webrtc_channel) {
peer_connection_tracker_->TrackCreateDataChannel(
this, webrtc_channel.get(), PeerConnectionTracker::SOURCE_LOCAL);
+ ++num_data_channels_created_;
+
return new RtcDataChannelHandler(webrtc_channel);
}
const blink::WebMediaStreamTrack& track) {
DVLOG(1) << "createDTMFSender.";
- if (track.source().type() != blink::WebMediaStreamSource::TypeAudio) {
+ MediaStreamTrack* native_track = MediaStreamTrack::GetTrack(track);
+ if (!native_track ||
+ track.source().type() != blink::WebMediaStreamSource::TypeAudio) {
DLOG(ERROR) << "Could not create DTMF sender from a non-audio track.";
return NULL;
}
- webrtc::AudioTrackInterface* audio_track =
- static_cast<webrtc::AudioTrackInterface*>(
- MediaStreamDependencyFactory::GetNativeMediaStreamTrack(track));
-
- talk_base::scoped_refptr<webrtc::DtmfSenderInterface> sender(
+ webrtc::AudioTrackInterface* audio_track = native_track->GetAudioAdapter();
+ rtc::scoped_refptr<webrtc::DtmfSenderInterface> sender(
native_peer_connection_->CreateDtmfSender(audio_track));
if (!sender) {
DLOG(ERROR) << "Could not create native DTMF sender.";
// Called any time the IceConnectionState changes
void RTCPeerConnectionHandler::OnIceConnectionChange(
webrtc::PeerConnectionInterface::IceConnectionState new_state) {
+ if (new_state == webrtc::PeerConnectionInterface::kIceConnectionChecking) {
+ ice_connection_checking_start_ = base::TimeTicks::Now();
+ } else if (new_state ==
+ webrtc::PeerConnectionInterface::kIceConnectionConnected) {
+ // If the state becomes connected, send the time needed for PC to become
+ // connected from checking to UMA. UMA data will help to know how much
+ // time needed for PC to connect with remote peer.
+ UMA_HISTOGRAM_MEDIUM_TIMES(
+ "WebRTC.PeerConnection.TimeToConnect",
+ base::TimeTicks::Now() - ice_connection_checking_start_);
+ }
+
+ track_metrics_.IceConnectionChange(new_state);
blink::WebRTCPeerConnectionHandlerClient::ICEConnectionState state =
GetWebKitIceConnectionState(new_state);
if (peer_connection_tracker_)
this, remote_stream->webkit_stream(),
PeerConnectionTracker::SOURCE_REMOTE);
+ PerSessionWebRTCAPIMetrics::GetInstance()->IncrementStreamCounter();
+
+ track_metrics_.AddStream(MediaStreamTrackMetrics::RECEIVED_STREAM,
+ stream_interface);
+
client_->didAddRemoteStream(remote_stream->webkit_stream());
}
return;
}
+ track_metrics_.RemoveStream(MediaStreamTrackMetrics::RECEIVED_STREAM,
+ stream_interface);
+ PerSessionWebRTCAPIMetrics::GetInstance()->DecrementStreamCounter();
+
scoped_ptr<RemoteMediaStreamImpl> remote_stream(it->second);
const blink::WebMediaStream& webkit_stream = remote_stream->webkit_stream();
DCHECK(!webkit_stream.isNull());