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
3 // found in the LICENSE file.
5 #include "content/renderer/media/rtc_peer_connection_handler.h"
11 #include "base/command_line.h"
12 #include "base/lazy_instance.h"
13 #include "base/location.h"
14 #include "base/logging.h"
15 #include "base/memory/scoped_ptr.h"
16 #include "base/metrics/histogram.h"
17 #include "base/stl_util.h"
18 #include "base/strings/utf_string_conversions.h"
19 #include "base/thread_task_runner_handle.h"
20 #include "base/trace_event/trace_event.h"
21 #include "content/public/common/content_switches.h"
22 #include "content/renderer/media/media_stream_track.h"
23 #include "content/renderer/media/peer_connection_tracker.h"
24 #include "content/renderer/media/remote_media_stream_impl.h"
25 #include "content/renderer/media/rtc_data_channel_handler.h"
26 #include "content/renderer/media/rtc_dtmf_sender_handler.h"
27 #include "content/renderer/media/rtc_media_constraints.h"
28 #include "content/renderer/media/webrtc/peer_connection_dependency_factory.h"
29 #include "content/renderer/media/webrtc/webrtc_media_stream_adapter.h"
30 #include "content/renderer/media/webrtc_audio_capturer.h"
31 #include "content/renderer/media/webrtc_audio_device_impl.h"
32 #include "content/renderer/media/webrtc_uma_histograms.h"
33 #include "content/renderer/render_thread_impl.h"
34 #include "third_party/WebKit/public/platform/WebMediaConstraints.h"
35 #include "third_party/WebKit/public/platform/WebRTCConfiguration.h"
36 #include "third_party/WebKit/public/platform/WebRTCDataChannelInit.h"
37 #include "third_party/WebKit/public/platform/WebRTCICECandidate.h"
38 #include "third_party/WebKit/public/platform/WebRTCOfferOptions.h"
39 #include "third_party/WebKit/public/platform/WebRTCSessionDescription.h"
40 #include "third_party/WebKit/public/platform/WebRTCSessionDescriptionRequest.h"
41 #include "third_party/WebKit/public/platform/WebRTCVoidRequest.h"
42 #include "third_party/WebKit/public/platform/WebURL.h"
43 #include "third_party/libjingle/source/talk/session/media/mediasession.h"
45 using webrtc::DataChannelInterface
;
46 using webrtc::IceCandidateInterface
;
47 using webrtc::MediaStreamInterface
;
48 using webrtc::PeerConnectionInterface
;
49 using webrtc::PeerConnectionObserver
;
50 using webrtc::StatsReport
;
51 using webrtc::StatsReports
;
56 // Used to back histogram value of "WebRTC.PeerConnection.RtcpMux",
57 // so treat as append-only.
65 // Converter functions from libjingle types to WebKit types.
66 blink::WebRTCPeerConnectionHandlerClient::ICEGatheringState
67 GetWebKitIceGatheringState(
68 webrtc::PeerConnectionInterface::IceGatheringState state
) {
69 using blink::WebRTCPeerConnectionHandlerClient
;
71 case webrtc::PeerConnectionInterface::kIceGatheringNew
:
72 return WebRTCPeerConnectionHandlerClient::ICEGatheringStateNew
;
73 case webrtc::PeerConnectionInterface::kIceGatheringGathering
:
74 return WebRTCPeerConnectionHandlerClient::ICEGatheringStateGathering
;
75 case webrtc::PeerConnectionInterface::kIceGatheringComplete
:
76 return WebRTCPeerConnectionHandlerClient::ICEGatheringStateComplete
;
79 return WebRTCPeerConnectionHandlerClient::ICEGatheringStateNew
;
83 blink::WebRTCPeerConnectionHandlerClient::ICEConnectionState
84 GetWebKitIceConnectionState(
85 webrtc::PeerConnectionInterface::IceConnectionState ice_state
) {
86 using blink::WebRTCPeerConnectionHandlerClient
;
88 case webrtc::PeerConnectionInterface::kIceConnectionNew
:
89 return WebRTCPeerConnectionHandlerClient::ICEConnectionStateStarting
;
90 case webrtc::PeerConnectionInterface::kIceConnectionChecking
:
91 return WebRTCPeerConnectionHandlerClient::ICEConnectionStateChecking
;
92 case webrtc::PeerConnectionInterface::kIceConnectionConnected
:
93 return WebRTCPeerConnectionHandlerClient::ICEConnectionStateConnected
;
94 case webrtc::PeerConnectionInterface::kIceConnectionCompleted
:
95 return WebRTCPeerConnectionHandlerClient::ICEConnectionStateCompleted
;
96 case webrtc::PeerConnectionInterface::kIceConnectionFailed
:
97 return WebRTCPeerConnectionHandlerClient::ICEConnectionStateFailed
;
98 case webrtc::PeerConnectionInterface::kIceConnectionDisconnected
:
99 return WebRTCPeerConnectionHandlerClient::ICEConnectionStateDisconnected
;
100 case webrtc::PeerConnectionInterface::kIceConnectionClosed
:
101 return WebRTCPeerConnectionHandlerClient::ICEConnectionStateClosed
;
104 return WebRTCPeerConnectionHandlerClient::ICEConnectionStateClosed
;
108 blink::WebRTCPeerConnectionHandlerClient::SignalingState
109 GetWebKitSignalingState(webrtc::PeerConnectionInterface::SignalingState state
) {
110 using blink::WebRTCPeerConnectionHandlerClient
;
112 case webrtc::PeerConnectionInterface::kStable
:
113 return WebRTCPeerConnectionHandlerClient::SignalingStateStable
;
114 case webrtc::PeerConnectionInterface::kHaveLocalOffer
:
115 return WebRTCPeerConnectionHandlerClient::SignalingStateHaveLocalOffer
;
116 case webrtc::PeerConnectionInterface::kHaveLocalPrAnswer
:
117 return WebRTCPeerConnectionHandlerClient::SignalingStateHaveLocalPrAnswer
;
118 case webrtc::PeerConnectionInterface::kHaveRemoteOffer
:
119 return WebRTCPeerConnectionHandlerClient::SignalingStateHaveRemoteOffer
;
120 case webrtc::PeerConnectionInterface::kHaveRemotePrAnswer
:
122 WebRTCPeerConnectionHandlerClient::SignalingStateHaveRemotePrAnswer
;
123 case webrtc::PeerConnectionInterface::kClosed
:
124 return WebRTCPeerConnectionHandlerClient::SignalingStateClosed
;
127 return WebRTCPeerConnectionHandlerClient::SignalingStateClosed
;
131 blink::WebRTCSessionDescription
CreateWebKitSessionDescription(
132 const std::string
& sdp
, const std::string
& type
) {
133 blink::WebRTCSessionDescription description
;
134 description
.initialize(base::UTF8ToUTF16(type
), base::UTF8ToUTF16(sdp
));
138 blink::WebRTCSessionDescription
139 CreateWebKitSessionDescription(
140 const webrtc::SessionDescriptionInterface
* native_desc
) {
142 LOG(ERROR
) << "Native session description is null.";
143 return blink::WebRTCSessionDescription();
147 if (!native_desc
->ToString(&sdp
)) {
148 LOG(ERROR
) << "Failed to get SDP string of native session description.";
149 return blink::WebRTCSessionDescription();
152 return CreateWebKitSessionDescription(sdp
, native_desc
->type());
155 void RunClosureWithTrace(const base::Closure
& closure
,
156 const char* trace_event_name
) {
157 TRACE_EVENT0("webrtc", trace_event_name
);
161 void RunSynchronousClosure(const base::Closure
& closure
,
162 const char* trace_event_name
,
163 base::WaitableEvent
* event
) {
165 TRACE_EVENT0("webrtc", trace_event_name
);
171 void GetSdpAndTypeFromSessionDescription(
172 const base::Callback
<const webrtc::SessionDescriptionInterface
*()>&
173 description_callback
,
174 std::string
* sdp
, std::string
* type
) {
175 const webrtc::SessionDescriptionInterface
* description
=
176 description_callback
.Run();
178 description
->ToString(sdp
);
179 *type
= description
->type();
183 // Converter functions from WebKit types to WebRTC types.
185 void GetNativeRtcConfiguration(
186 const blink::WebRTCConfiguration
& blink_config
,
187 webrtc::PeerConnectionInterface::RTCConfiguration
* webrtc_config
) {
188 if (blink_config
.isNull() || !webrtc_config
)
190 for (size_t i
= 0; i
< blink_config
.numberOfServers(); ++i
) {
191 webrtc::PeerConnectionInterface::IceServer server
;
192 const blink::WebRTCICEServer
& webkit_server
=
193 blink_config
.server(i
);
195 base::UTF16ToUTF8(base::StringPiece16(webkit_server
.username()));
197 base::UTF16ToUTF8(base::StringPiece16(webkit_server
.credential()));
198 server
.uri
= webkit_server
.uri().spec();
199 webrtc_config
->servers
.push_back(server
);
202 switch (blink_config
.iceTransports()) {
203 case blink::WebRTCIceTransportsNone
:
204 webrtc_config
->type
= webrtc::PeerConnectionInterface::kNone
;
206 case blink::WebRTCIceTransportsRelay
:
207 webrtc_config
->type
= webrtc::PeerConnectionInterface::kRelay
;
209 case blink::WebRTCIceTransportsAll
:
210 webrtc_config
->type
= webrtc::PeerConnectionInterface::kAll
;
216 switch (blink_config
.bundlePolicy()) {
217 case blink::WebRTCBundlePolicyBalanced
:
218 webrtc_config
->bundle_policy
=
219 webrtc::PeerConnectionInterface::kBundlePolicyBalanced
;
221 case blink::WebRTCBundlePolicyMaxBundle
:
222 webrtc_config
->bundle_policy
=
223 webrtc::PeerConnectionInterface::kBundlePolicyMaxBundle
;
225 case blink::WebRTCBundlePolicyMaxCompat
:
226 webrtc_config
->bundle_policy
=
227 webrtc::PeerConnectionInterface::kBundlePolicyMaxCompat
;
233 switch (blink_config
.rtcpMuxPolicy()) {
234 case blink::WebRTCRtcpMuxPolicyNegotiate
:
235 webrtc_config
->rtcp_mux_policy
=
236 webrtc::PeerConnectionInterface::kRtcpMuxPolicyNegotiate
;
238 case blink::WebRTCRtcpMuxPolicyRequire
:
239 webrtc_config
->rtcp_mux_policy
=
240 webrtc::PeerConnectionInterface::kRtcpMuxPolicyRequire
;
247 class SessionDescriptionRequestTracker
{
249 SessionDescriptionRequestTracker(
250 const base::WeakPtr
<RTCPeerConnectionHandler
>& handler
,
251 const base::WeakPtr
<PeerConnectionTracker
>& tracker
,
252 PeerConnectionTracker::Action action
)
253 : handler_(handler
), tracker_(tracker
), action_(action
) {}
255 void TrackOnSuccess(const webrtc::SessionDescriptionInterface
* desc
) {
256 DCHECK(thread_checker_
.CalledOnValidThread());
257 if (tracker_
&& handler_
) {
260 desc
->ToString(&value
);
261 value
= "type: " + desc
->type() + ", sdp: " + value
;
263 tracker_
->TrackSessionDescriptionCallback(
264 handler_
.get(), action_
, "OnSuccess", value
);
268 void TrackOnFailure(const std::string
& error
) {
269 DCHECK(thread_checker_
.CalledOnValidThread());
270 if (handler_
&& tracker_
) {
271 tracker_
->TrackSessionDescriptionCallback(
272 handler_
.get(), action_
, "OnFailure", error
);
277 const base::WeakPtr
<RTCPeerConnectionHandler
> handler_
;
278 const base::WeakPtr
<PeerConnectionTracker
> tracker_
;
279 PeerConnectionTracker::Action action_
;
280 base::ThreadChecker thread_checker_
;
283 // Class mapping responses from calls to libjingle CreateOffer/Answer and
284 // the blink::WebRTCSessionDescriptionRequest.
285 class CreateSessionDescriptionRequest
286 : public webrtc::CreateSessionDescriptionObserver
{
288 explicit CreateSessionDescriptionRequest(
289 const scoped_refptr
<base::SingleThreadTaskRunner
>& main_thread
,
290 const blink::WebRTCSessionDescriptionRequest
& request
,
291 const base::WeakPtr
<RTCPeerConnectionHandler
>& handler
,
292 const base::WeakPtr
<PeerConnectionTracker
>& tracker
,
293 PeerConnectionTracker::Action action
)
294 : main_thread_(main_thread
),
295 webkit_request_(request
),
296 tracker_(handler
, tracker
, action
) {
299 void OnSuccess(webrtc::SessionDescriptionInterface
* desc
) override
{
300 if (!main_thread_
->BelongsToCurrentThread()) {
301 main_thread_
->PostTask(FROM_HERE
,
302 base::Bind(&CreateSessionDescriptionRequest::OnSuccess
, this, desc
));
306 tracker_
.TrackOnSuccess(desc
);
307 webkit_request_
.requestSucceeded(CreateWebKitSessionDescription(desc
));
308 webkit_request_
.reset();
311 void OnFailure(const std::string
& error
) override
{
312 if (!main_thread_
->BelongsToCurrentThread()) {
313 main_thread_
->PostTask(FROM_HERE
,
314 base::Bind(&CreateSessionDescriptionRequest::OnFailure
, this, error
));
318 tracker_
.TrackOnFailure(error
);
319 webkit_request_
.requestFailed(base::UTF8ToUTF16(error
));
320 webkit_request_
.reset();
324 ~CreateSessionDescriptionRequest() override
{
325 CHECK(webkit_request_
.isNull());
328 const scoped_refptr
<base::SingleThreadTaskRunner
> main_thread_
;
329 blink::WebRTCSessionDescriptionRequest webkit_request_
;
330 SessionDescriptionRequestTracker tracker_
;
333 // Class mapping responses from calls to libjingle
334 // SetLocalDescription/SetRemoteDescription and a blink::WebRTCVoidRequest.
335 class SetSessionDescriptionRequest
336 : public webrtc::SetSessionDescriptionObserver
{
338 explicit SetSessionDescriptionRequest(
339 const scoped_refptr
<base::SingleThreadTaskRunner
>& main_thread
,
340 const blink::WebRTCVoidRequest
& request
,
341 const base::WeakPtr
<RTCPeerConnectionHandler
>& handler
,
342 const base::WeakPtr
<PeerConnectionTracker
>& tracker
,
343 PeerConnectionTracker::Action action
)
344 : main_thread_(main_thread
),
345 webkit_request_(request
),
346 tracker_(handler
, tracker
, action
) {
349 void OnSuccess() override
{
350 if (!main_thread_
->BelongsToCurrentThread()) {
351 main_thread_
->PostTask(FROM_HERE
,
352 base::Bind(&SetSessionDescriptionRequest::OnSuccess
, this));
355 tracker_
.TrackOnSuccess(NULL
);
356 webkit_request_
.requestSucceeded();
357 webkit_request_
.reset();
359 void OnFailure(const std::string
& error
) override
{
360 if (!main_thread_
->BelongsToCurrentThread()) {
361 main_thread_
->PostTask(FROM_HERE
,
362 base::Bind(&SetSessionDescriptionRequest::OnFailure
, this, error
));
365 tracker_
.TrackOnFailure(error
);
366 webkit_request_
.requestFailed(base::UTF8ToUTF16(error
));
367 webkit_request_
.reset();
371 ~SetSessionDescriptionRequest() override
{
372 DCHECK(webkit_request_
.isNull());
376 const scoped_refptr
<base::SingleThreadTaskRunner
> main_thread_
;
377 blink::WebRTCVoidRequest webkit_request_
;
378 SessionDescriptionRequestTracker tracker_
;
381 // Class mapping responses from calls to libjingle
382 // GetStats into a blink::WebRTCStatsCallback.
383 class StatsResponse
: public webrtc::StatsObserver
{
385 explicit StatsResponse(const scoped_refptr
<LocalRTCStatsRequest
>& request
)
386 : request_(request
.get()),
387 main_thread_(base::ThreadTaskRunnerHandle::Get()) {
388 // Measure the overall time it takes to satisfy a getStats request.
389 TRACE_EVENT_ASYNC_BEGIN0("webrtc", "getStats_Native", this);
390 signaling_thread_checker_
.DetachFromThread();
393 void OnComplete(const StatsReports
& reports
) override
{
394 DCHECK(signaling_thread_checker_
.CalledOnValidThread());
395 TRACE_EVENT0("webrtc", "StatsResponse::OnComplete");
396 // We can't use webkit objects directly since they use a single threaded
398 std::vector
<Report
*>* report_copies
= new std::vector
<Report
*>();
399 report_copies
->reserve(reports
.size());
400 for (auto* r
: reports
)
401 report_copies
->push_back(new Report(r
));
403 main_thread_
->PostTaskAndReply(FROM_HERE
,
404 base::Bind(&StatsResponse::DeliverCallback
, this,
405 base::Unretained(report_copies
)),
406 base::Bind(&StatsResponse::DeleteReports
,
407 base::Unretained(report_copies
)));
412 Report(const StatsReport
* report
)
413 : thread_checker(), id(report
->id()->ToString()),
414 type(report
->TypeToString()), timestamp(report
->timestamp()),
415 values(report
->values()) {
419 // Since the values vector holds pointers to const objects that are bound
420 // to the signaling thread, they must be released on the same thread.
421 DCHECK(thread_checker
.CalledOnValidThread());
424 const base::ThreadChecker thread_checker
;
425 const std::string id
, type
;
426 const double timestamp
;
427 const StatsReport::Values values
;
430 static void DeleteReports(std::vector
<Report
*>* reports
) {
431 TRACE_EVENT0("webrtc", "StatsResponse::DeleteReports");
432 for (auto* p
: *reports
)
437 void DeliverCallback(const std::vector
<Report
*>* reports
) {
438 DCHECK(main_thread_
->BelongsToCurrentThread());
439 TRACE_EVENT0("webrtc", "StatsResponse::DeliverCallback");
441 rtc::scoped_refptr
<LocalRTCStatsResponse
> response(
442 request_
->createResponse().get());
443 for (const auto* report
: *reports
) {
444 if (report
->values
.size() > 0)
445 AddReport(response
.get(), *report
);
448 // Record the getStats operation as done before calling into Blink so that
449 // we don't skew the perf measurements of the native code with whatever the
450 // callback might be doing.
451 TRACE_EVENT_ASYNC_END0("webrtc", "getStats_Native", this);
452 request_
->requestSucceeded(response
);
453 request_
= nullptr; // must be freed on the main thread.
456 void AddReport(LocalRTCStatsResponse
* response
, const Report
& report
) {
457 int idx
= response
->addReport(blink::WebString::fromUTF8(report
.id
),
458 blink::WebString::fromUTF8(report
.type
),
460 blink::WebString name
, value_str
;
461 for (const auto& value
: report
.values
) {
462 const StatsReport::ValuePtr
& v
= value
.second
;
463 name
= blink::WebString::fromUTF8(value
.second
->display_name());
465 if (v
->type() == StatsReport::Value::kString
)
466 value_str
= blink::WebString::fromUTF8(v
->string_val());
467 if (v
->type() == StatsReport::Value::kStaticString
)
468 value_str
= blink::WebString::fromUTF8(v
->static_string_val());
470 value_str
= blink::WebString::fromUTF8(v
->ToString());
472 response
->addStatistic(idx
, name
, value_str
);
476 rtc::scoped_refptr
<LocalRTCStatsRequest
> request_
;
477 const scoped_refptr
<base::SingleThreadTaskRunner
> main_thread_
;
478 base::ThreadChecker signaling_thread_checker_
;
481 void GetStatsOnSignalingThread(
482 const scoped_refptr
<webrtc::PeerConnectionInterface
>& pc
,
483 webrtc::PeerConnectionInterface::StatsOutputLevel level
,
484 const scoped_refptr
<webrtc::StatsObserver
>& observer
,
485 const std::string track_id
, blink::WebMediaStreamSource::Type track_type
) {
486 TRACE_EVENT0("webrtc", "GetStatsOnSignalingThread");
488 scoped_refptr
<webrtc::MediaStreamTrackInterface
> track
;
489 if (!track_id
.empty()) {
490 if (track_type
== blink::WebMediaStreamSource::TypeAudio
) {
491 track
= pc
->local_streams()->FindAudioTrack(track_id
);
493 track
= pc
->remote_streams()->FindAudioTrack(track_id
);
495 DCHECK_EQ(blink::WebMediaStreamSource::TypeVideo
, track_type
);
496 track
= pc
->local_streams()->FindVideoTrack(track_id
);
498 track
= pc
->remote_streams()->FindVideoTrack(track_id
);
502 DVLOG(1) << "GetStats: Track not found.";
503 observer
->OnComplete(StatsReports());
508 if (!pc
->GetStats(observer
.get(), track
.get(), level
)) {
509 DVLOG(1) << "GetStats failed.";
510 observer
->OnComplete(StatsReports());
514 class PeerConnectionUMAObserver
: public webrtc::UMAObserver
{
516 PeerConnectionUMAObserver() {}
517 ~PeerConnectionUMAObserver() override
{}
518 void IncrementEnumCounter(webrtc::PeerConnectionEnumCounterType counter_type
,
520 int counter_max
) override
{
521 switch (counter_type
) {
522 case webrtc::kEnumCounterAddressFamily
:
523 UMA_HISTOGRAM_ENUMERATION("WebRTC.PeerConnection.IPMetrics", counter
,
526 case webrtc::kEnumCounterIceCandidatePairTypeUdp
:
527 UMA_HISTOGRAM_ENUMERATION("WebRTC.PeerConnection.CandidatePairType_UDP",
528 counter
, counter_max
);
530 case webrtc::kEnumCounterIceCandidatePairTypeTcp
:
531 UMA_HISTOGRAM_ENUMERATION("WebRTC.PeerConnection.CandidatePairType_TCP",
532 counter
, counter_max
);
534 case webrtc::kPeerConnectionEnumCounterMax
:
540 void AddHistogramSample(webrtc::PeerConnectionUMAMetricsName type
,
541 int value
) override
{
542 // Runs on libjingle's signaling thread.
544 case webrtc::kTimeToConnect
:
545 UMA_HISTOGRAM_MEDIUM_TIMES(
546 "WebRTC.PeerConnection.TimeToConnect",
547 base::TimeDelta::FromMilliseconds(value
));
549 case webrtc::kNetworkInterfaces_IPv4
:
550 UMA_HISTOGRAM_COUNTS_100("WebRTC.PeerConnection.IPv4Interfaces",
553 case webrtc::kNetworkInterfaces_IPv6
:
554 UMA_HISTOGRAM_COUNTS_100("WebRTC.PeerConnection.IPv6Interfaces",
563 base::LazyInstance
<std::set
<RTCPeerConnectionHandler
*> >::Leaky
564 g_peer_connection_handlers
= LAZY_INSTANCE_INITIALIZER
;
568 // Implementation of LocalRTCStatsRequest.
569 LocalRTCStatsRequest::LocalRTCStatsRequest(blink::WebRTCStatsRequest impl
)
573 LocalRTCStatsRequest::LocalRTCStatsRequest() {}
574 LocalRTCStatsRequest::~LocalRTCStatsRequest() {}
576 bool LocalRTCStatsRequest::hasSelector() const {
577 return impl_
.hasSelector();
580 blink::WebMediaStreamTrack
LocalRTCStatsRequest::component() const {
581 return impl_
.component();
584 scoped_refptr
<LocalRTCStatsResponse
> LocalRTCStatsRequest::createResponse() {
585 return scoped_refptr
<LocalRTCStatsResponse
>(
586 new rtc::RefCountedObject
<LocalRTCStatsResponse
>(impl_
.createResponse()));
589 void LocalRTCStatsRequest::requestSucceeded(
590 const LocalRTCStatsResponse
* response
) {
591 impl_
.requestSucceeded(response
->webKitStatsResponse());
594 // Implementation of LocalRTCStatsResponse.
595 blink::WebRTCStatsResponse
LocalRTCStatsResponse::webKitStatsResponse() const {
599 size_t LocalRTCStatsResponse::addReport(blink::WebString type
,
602 return impl_
.addReport(type
, id
, timestamp
);
605 void LocalRTCStatsResponse::addStatistic(size_t report
,
606 blink::WebString name
,
607 blink::WebString value
) {
608 impl_
.addStatistic(report
, name
, value
);
611 // Receives notifications from a PeerConnection object about state changes,
612 // track addition/removal etc. The callbacks we receive here come on the
613 // signaling thread, so this class takes care of delivering them to an
614 // RTCPeerConnectionHandler instance on the main thread.
615 // In order to do safe PostTask-ing, the class is reference counted and
616 // checks for the existence of the RTCPeerConnectionHandler instance before
617 // delivering callbacks on the main thread.
618 class RTCPeerConnectionHandler::Observer
619 : public base::RefCountedThreadSafe
<RTCPeerConnectionHandler::Observer
>,
620 public PeerConnectionObserver
{
622 Observer(const base::WeakPtr
<RTCPeerConnectionHandler
>& handler
)
623 : handler_(handler
), main_thread_(base::ThreadTaskRunnerHandle::Get()) {}
626 friend class base::RefCountedThreadSafe
<RTCPeerConnectionHandler::Observer
>;
627 virtual ~Observer() {}
629 void OnSignalingChange(
630 PeerConnectionInterface::SignalingState new_state
) override
{
631 if (!main_thread_
->BelongsToCurrentThread()) {
632 main_thread_
->PostTask(FROM_HERE
,
633 base::Bind(&RTCPeerConnectionHandler::Observer::OnSignalingChange
,
635 } else if (handler_
) {
636 handler_
->OnSignalingChange(new_state
);
640 void OnAddStream(MediaStreamInterface
* stream
) override
{
642 scoped_ptr
<RemoteMediaStreamImpl
> remote_stream(
643 new RemoteMediaStreamImpl(main_thread_
, stream
));
645 // The webkit object owned by RemoteMediaStreamImpl, will be initialized
646 // asynchronously and the posted task will execude after that initialization
648 main_thread_
->PostTask(FROM_HERE
,
649 base::Bind(&RTCPeerConnectionHandler::Observer::OnAddStreamImpl
,
650 this, base::Passed(&remote_stream
)));
653 void OnRemoveStream(MediaStreamInterface
* stream
) override
{
654 main_thread_
->PostTask(FROM_HERE
,
655 base::Bind(&RTCPeerConnectionHandler::Observer::OnRemoveStreamImpl
,
656 this, make_scoped_refptr(stream
)));
659 void OnDataChannel(DataChannelInterface
* data_channel
) override
{
660 scoped_ptr
<RtcDataChannelHandler
> handler(
661 new RtcDataChannelHandler(main_thread_
, data_channel
));
662 main_thread_
->PostTask(FROM_HERE
,
663 base::Bind(&RTCPeerConnectionHandler::Observer::OnDataChannelImpl
,
664 this, base::Passed(&handler
)));
667 void OnRenegotiationNeeded() override
{
668 if (!main_thread_
->BelongsToCurrentThread()) {
669 main_thread_
->PostTask(FROM_HERE
,
670 base::Bind(&RTCPeerConnectionHandler::Observer::OnRenegotiationNeeded
,
672 } else if (handler_
) {
673 handler_
->OnRenegotiationNeeded();
677 void OnIceConnectionChange(
678 PeerConnectionInterface::IceConnectionState new_state
) override
{
679 if (!main_thread_
->BelongsToCurrentThread()) {
680 main_thread_
->PostTask(FROM_HERE
,
682 &RTCPeerConnectionHandler::Observer::OnIceConnectionChange
, this,
684 } else if (handler_
) {
685 handler_
->OnIceConnectionChange(new_state
);
689 void OnIceGatheringChange(
690 PeerConnectionInterface::IceGatheringState new_state
) override
{
691 if (!main_thread_
->BelongsToCurrentThread()) {
692 main_thread_
->PostTask(FROM_HERE
,
693 base::Bind(&RTCPeerConnectionHandler::Observer::OnIceGatheringChange
,
695 } else if (handler_
) {
696 handler_
->OnIceGatheringChange(new_state
);
700 void OnIceCandidate(const IceCandidateInterface
* candidate
) override
{
702 if (!candidate
->ToString(&sdp
)) {
703 NOTREACHED() << "OnIceCandidate: Could not get SDP string.";
707 main_thread_
->PostTask(FROM_HERE
,
708 base::Bind(&RTCPeerConnectionHandler::Observer::OnIceCandidateImpl
,
709 this, sdp
, candidate
->sdp_mid(), candidate
->sdp_mline_index(),
710 candidate
->candidate().component(),
711 candidate
->candidate().address().family()));
714 void OnAddStreamImpl(scoped_ptr
<RemoteMediaStreamImpl
> stream
) {
715 DCHECK(stream
->webkit_stream().extraData()) << "Initialization not done";
717 handler_
->OnAddStream(stream
.Pass());
720 void OnRemoveStreamImpl(const scoped_refptr
<MediaStreamInterface
>& stream
) {
722 handler_
->OnRemoveStream(stream
);
725 void OnDataChannelImpl(scoped_ptr
<RtcDataChannelHandler
> handler
) {
727 handler_
->OnDataChannel(handler
.Pass());
730 void OnIceCandidateImpl(const std::string
& sdp
, const std::string
& sdp_mid
,
731 int sdp_mline_index
, int component
, int address_family
) {
733 handler_
->OnIceCandidate(sdp
, sdp_mid
, sdp_mline_index
, component
,
739 const base::WeakPtr
<RTCPeerConnectionHandler
> handler_
;
740 const scoped_refptr
<base::SingleThreadTaskRunner
> main_thread_
;
743 RTCPeerConnectionHandler::RTCPeerConnectionHandler(
744 blink::WebRTCPeerConnectionHandlerClient
* client
,
745 PeerConnectionDependencyFactory
* dependency_factory
)
747 dependency_factory_(dependency_factory
),
748 weak_factory_(this) {
749 g_peer_connection_handlers
.Get().insert(this);
752 RTCPeerConnectionHandler::~RTCPeerConnectionHandler() {
753 DCHECK(thread_checker_
.CalledOnValidThread());
757 g_peer_connection_handlers
.Get().erase(this);
758 if (peer_connection_tracker_
)
759 peer_connection_tracker_
->UnregisterPeerConnection(this);
760 STLDeleteValues(&remote_streams_
);
762 UMA_HISTOGRAM_COUNTS_10000(
763 "WebRTC.NumDataChannelsPerPeerConnection", num_data_channels_created_
);
767 void RTCPeerConnectionHandler::DestructAllHandlers() {
768 std::set
<RTCPeerConnectionHandler
*> handlers(
769 g_peer_connection_handlers
.Get().begin(),
770 g_peer_connection_handlers
.Get().end());
771 for (auto handler
: handlers
) {
772 if (handler
->client_
)
773 handler
->client_
->releasePeerConnectionHandler();
778 void RTCPeerConnectionHandler::ConvertOfferOptionsToConstraints(
779 const blink::WebRTCOfferOptions
& options
,
780 RTCMediaConstraints
* output
) {
781 output
->AddMandatory(
782 webrtc::MediaConstraintsInterface::kOfferToReceiveAudio
,
783 options
.offerToReceiveAudio() > 0 ? "true" : "false",
786 output
->AddMandatory(
787 webrtc::MediaConstraintsInterface::kOfferToReceiveVideo
,
788 options
.offerToReceiveVideo() > 0 ? "true" : "false",
791 if (!options
.voiceActivityDetection()) {
792 output
->AddMandatory(
793 webrtc::MediaConstraintsInterface::kVoiceActivityDetection
,
798 if (options
.iceRestart()) {
799 output
->AddMandatory(
800 webrtc::MediaConstraintsInterface::kIceRestart
, "true", true);
804 void RTCPeerConnectionHandler::associateWithFrame(blink::WebFrame
* frame
) {
805 DCHECK(thread_checker_
.CalledOnValidThread());
810 bool RTCPeerConnectionHandler::initialize(
811 const blink::WebRTCConfiguration
& server_configuration
,
812 const blink::WebMediaConstraints
& options
) {
813 DCHECK(thread_checker_
.CalledOnValidThread());
816 peer_connection_tracker_
=
817 RenderThreadImpl::current()->peer_connection_tracker()->AsWeakPtr();
819 webrtc::PeerConnectionInterface::RTCConfiguration config
;
820 GetNativeRtcConfiguration(server_configuration
, &config
);
822 RTCMediaConstraints
constraints(options
);
824 peer_connection_observer_
= new Observer(weak_factory_
.GetWeakPtr());
825 native_peer_connection_
= dependency_factory_
->CreatePeerConnection(
826 config
, &constraints
, frame_
, peer_connection_observer_
.get());
828 if (!native_peer_connection_
.get()) {
829 LOG(ERROR
) << "Failed to initialize native PeerConnection.";
833 if (peer_connection_tracker_
) {
834 peer_connection_tracker_
->RegisterPeerConnection(
835 this, config
, constraints
, frame_
);
838 uma_observer_
= new rtc::RefCountedObject
<PeerConnectionUMAObserver
>();
839 native_peer_connection_
->RegisterUMAObserver(uma_observer_
.get());
843 bool RTCPeerConnectionHandler::InitializeForTest(
844 const blink::WebRTCConfiguration
& server_configuration
,
845 const blink::WebMediaConstraints
& options
,
846 const base::WeakPtr
<PeerConnectionTracker
>& peer_connection_tracker
) {
847 DCHECK(thread_checker_
.CalledOnValidThread());
848 webrtc::PeerConnectionInterface::RTCConfiguration config
;
849 GetNativeRtcConfiguration(server_configuration
, &config
);
851 peer_connection_observer_
= new Observer(weak_factory_
.GetWeakPtr());
852 RTCMediaConstraints
constraints(options
);
853 native_peer_connection_
= dependency_factory_
->CreatePeerConnection(
854 config
, &constraints
, NULL
, peer_connection_observer_
.get());
855 if (!native_peer_connection_
.get()) {
856 LOG(ERROR
) << "Failed to initialize native PeerConnection.";
859 peer_connection_tracker_
= peer_connection_tracker
;
863 void RTCPeerConnectionHandler::createOffer(
864 const blink::WebRTCSessionDescriptionRequest
& request
,
865 const blink::WebMediaConstraints
& options
) {
866 DCHECK(thread_checker_
.CalledOnValidThread());
867 TRACE_EVENT0("webrtc", "RTCPeerConnectionHandler::createOffer");
869 scoped_refptr
<CreateSessionDescriptionRequest
> description_request(
870 new rtc::RefCountedObject
<CreateSessionDescriptionRequest
>(
871 base::ThreadTaskRunnerHandle::Get(), request
,
872 weak_factory_
.GetWeakPtr(), peer_connection_tracker_
,
873 PeerConnectionTracker::ACTION_CREATE_OFFER
));
875 // TODO(tommi): Do this asynchronously via e.g. PostTaskAndReply.
876 RTCMediaConstraints
constraints(options
);
877 native_peer_connection_
->CreateOffer(description_request
.get(), &constraints
);
879 if (peer_connection_tracker_
)
880 peer_connection_tracker_
->TrackCreateOffer(this, constraints
);
883 void RTCPeerConnectionHandler::createOffer(
884 const blink::WebRTCSessionDescriptionRequest
& request
,
885 const blink::WebRTCOfferOptions
& options
) {
886 DCHECK(thread_checker_
.CalledOnValidThread());
887 TRACE_EVENT0("webrtc", "RTCPeerConnectionHandler::createOffer");
889 scoped_refptr
<CreateSessionDescriptionRequest
> description_request(
890 new rtc::RefCountedObject
<CreateSessionDescriptionRequest
>(
891 base::ThreadTaskRunnerHandle::Get(), request
,
892 weak_factory_
.GetWeakPtr(), peer_connection_tracker_
,
893 PeerConnectionTracker::ACTION_CREATE_OFFER
));
895 // TODO(tommi): Do this asynchronously via e.g. PostTaskAndReply.
896 RTCMediaConstraints constraints
;
897 ConvertOfferOptionsToConstraints(options
, &constraints
);
898 native_peer_connection_
->CreateOffer(description_request
.get(), &constraints
);
900 if (peer_connection_tracker_
)
901 peer_connection_tracker_
->TrackCreateOffer(this, constraints
);
904 void RTCPeerConnectionHandler::createAnswer(
905 const blink::WebRTCSessionDescriptionRequest
& request
,
906 const blink::WebMediaConstraints
& options
) {
907 DCHECK(thread_checker_
.CalledOnValidThread());
908 TRACE_EVENT0("webrtc", "RTCPeerConnectionHandler::createAnswer");
909 scoped_refptr
<CreateSessionDescriptionRequest
> description_request(
910 new rtc::RefCountedObject
<CreateSessionDescriptionRequest
>(
911 base::ThreadTaskRunnerHandle::Get(), request
,
912 weak_factory_
.GetWeakPtr(), peer_connection_tracker_
,
913 PeerConnectionTracker::ACTION_CREATE_ANSWER
));
914 // TODO(tommi): Do this asynchronously via e.g. PostTaskAndReply.
915 RTCMediaConstraints
constraints(options
);
916 native_peer_connection_
->CreateAnswer(description_request
.get(),
919 if (peer_connection_tracker_
)
920 peer_connection_tracker_
->TrackCreateAnswer(this, constraints
);
923 bool IsOfferOrAnswer(const webrtc::SessionDescriptionInterface
* native_desc
) {
925 return native_desc
->type() == "offer" || native_desc
->type() == "answer";
928 void RTCPeerConnectionHandler::setLocalDescription(
929 const blink::WebRTCVoidRequest
& request
,
930 const blink::WebRTCSessionDescription
& description
) {
931 DCHECK(thread_checker_
.CalledOnValidThread());
932 TRACE_EVENT0("webrtc", "RTCPeerConnectionHandler::setLocalDescription");
934 std::string sdp
= base::UTF16ToUTF8(base::StringPiece16(description
.sdp()));
936 base::UTF16ToUTF8(base::StringPiece16(description
.type()));
938 webrtc::SdpParseError error
;
939 // Since CreateNativeSessionDescription uses the dependency factory, we need
940 // to make this call on the current thread to be safe.
941 webrtc::SessionDescriptionInterface
* native_desc
=
942 CreateNativeSessionDescription(sdp
, type
, &error
);
944 std::string reason_str
= "Failed to parse SessionDescription. ";
945 reason_str
.append(error
.line
);
946 reason_str
.append(" ");
947 reason_str
.append(error
.description
);
948 LOG(ERROR
) << reason_str
;
949 request
.requestFailed(blink::WebString::fromUTF8(reason_str
));
953 if (peer_connection_tracker_
) {
954 peer_connection_tracker_
->TrackSetSessionDescription(
955 this, sdp
, type
, PeerConnectionTracker::SOURCE_LOCAL
);
958 if (!first_local_description_
&& IsOfferOrAnswer(native_desc
)) {
959 first_local_description_
.reset(new FirstSessionDescription(native_desc
));
960 if (first_remote_description_
) {
961 ReportFirstSessionDescriptions(
962 *first_local_description_
,
963 *first_remote_description_
);
967 scoped_refptr
<SetSessionDescriptionRequest
> set_request(
968 new rtc::RefCountedObject
<SetSessionDescriptionRequest
>(
969 base::ThreadTaskRunnerHandle::Get(), request
,
970 weak_factory_
.GetWeakPtr(), peer_connection_tracker_
,
971 PeerConnectionTracker::ACTION_SET_LOCAL_DESCRIPTION
));
973 signaling_thread()->PostTask(FROM_HERE
,
974 base::Bind(&RunClosureWithTrace
,
975 base::Bind(&webrtc::PeerConnectionInterface::SetLocalDescription
,
976 native_peer_connection_
, set_request
,
977 base::Unretained(native_desc
)),
978 "SetLocalDescription"));
981 void RTCPeerConnectionHandler::setRemoteDescription(
982 const blink::WebRTCVoidRequest
& request
,
983 const blink::WebRTCSessionDescription
& description
) {
984 DCHECK(thread_checker_
.CalledOnValidThread());
985 TRACE_EVENT0("webrtc", "RTCPeerConnectionHandler::setRemoteDescription");
986 std::string sdp
= base::UTF16ToUTF8(base::StringPiece16(description
.sdp()));
988 base::UTF16ToUTF8(base::StringPiece16(description
.type()));
990 webrtc::SdpParseError error
;
991 // Since CreateNativeSessionDescription uses the dependency factory, we need
992 // to make this call on the current thread to be safe.
993 webrtc::SessionDescriptionInterface
* native_desc
=
994 CreateNativeSessionDescription(sdp
, type
, &error
);
996 std::string reason_str
= "Failed to parse SessionDescription. ";
997 reason_str
.append(error
.line
);
998 reason_str
.append(" ");
999 reason_str
.append(error
.description
);
1000 LOG(ERROR
) << reason_str
;
1001 request
.requestFailed(blink::WebString::fromUTF8(reason_str
));
1005 if (peer_connection_tracker_
) {
1006 peer_connection_tracker_
->TrackSetSessionDescription(
1007 this, sdp
, type
, PeerConnectionTracker::SOURCE_REMOTE
);
1010 if (!first_remote_description_
&& IsOfferOrAnswer(native_desc
)) {
1011 first_remote_description_
.reset(new FirstSessionDescription(native_desc
));
1012 if (first_local_description_
) {
1013 ReportFirstSessionDescriptions(
1014 *first_local_description_
,
1015 *first_remote_description_
);
1019 scoped_refptr
<SetSessionDescriptionRequest
> set_request(
1020 new rtc::RefCountedObject
<SetSessionDescriptionRequest
>(
1021 base::ThreadTaskRunnerHandle::Get(), request
,
1022 weak_factory_
.GetWeakPtr(), peer_connection_tracker_
,
1023 PeerConnectionTracker::ACTION_SET_REMOTE_DESCRIPTION
));
1024 signaling_thread()->PostTask(FROM_HERE
,
1025 base::Bind(&RunClosureWithTrace
,
1026 base::Bind(&webrtc::PeerConnectionInterface::SetRemoteDescription
,
1027 native_peer_connection_
, set_request
,
1028 base::Unretained(native_desc
)),
1029 "SetRemoteDescription"));
1032 blink::WebRTCSessionDescription
1033 RTCPeerConnectionHandler::localDescription() {
1034 DCHECK(thread_checker_
.CalledOnValidThread());
1035 TRACE_EVENT0("webrtc", "RTCPeerConnectionHandler::localDescription");
1037 // Since local_description returns a pointer to a non-reference-counted object
1038 // that lives on the signaling thread, we cannot fetch a pointer to it and use
1039 // it directly here. Instead, we access the object completely on the signaling
1041 std::string sdp
, type
;
1042 base::Callback
<const webrtc::SessionDescriptionInterface
*()> description_cb
=
1043 base::Bind(&webrtc::PeerConnectionInterface::local_description
,
1044 native_peer_connection_
);
1045 RunSynchronousClosureOnSignalingThread(
1046 base::Bind(&GetSdpAndTypeFromSessionDescription
, description_cb
,
1047 base::Unretained(&sdp
), base::Unretained(&type
)),
1048 "localDescription");
1050 return CreateWebKitSessionDescription(sdp
, type
);
1053 blink::WebRTCSessionDescription
1054 RTCPeerConnectionHandler::remoteDescription() {
1055 DCHECK(thread_checker_
.CalledOnValidThread());
1056 TRACE_EVENT0("webrtc", "RTCPeerConnectionHandler::remoteDescription");
1057 // Since local_description returns a pointer to a non-reference-counted object
1058 // that lives on the signaling thread, we cannot fetch a pointer to it and use
1059 // it directly here. Instead, we access the object completely on the signaling
1061 std::string sdp
, type
;
1062 base::Callback
<const webrtc::SessionDescriptionInterface
*()> description_cb
=
1063 base::Bind(&webrtc::PeerConnectionInterface::remote_description
,
1064 native_peer_connection_
);
1065 RunSynchronousClosureOnSignalingThread(
1066 base::Bind(&GetSdpAndTypeFromSessionDescription
, description_cb
,
1067 base::Unretained(&sdp
), base::Unretained(&type
)),
1068 "remoteDescription");
1070 return CreateWebKitSessionDescription(sdp
, type
);
1073 bool RTCPeerConnectionHandler::updateICE(
1074 const blink::WebRTCConfiguration
& server_configuration
,
1075 const blink::WebMediaConstraints
& options
) {
1076 DCHECK(thread_checker_
.CalledOnValidThread());
1077 TRACE_EVENT0("webrtc", "RTCPeerConnectionHandler::updateICE");
1078 webrtc::PeerConnectionInterface::RTCConfiguration config
;
1079 GetNativeRtcConfiguration(server_configuration
, &config
);
1080 RTCMediaConstraints
constraints(options
);
1082 if (peer_connection_tracker_
)
1083 peer_connection_tracker_
->TrackUpdateIce(this, config
, constraints
);
1085 return native_peer_connection_
->UpdateIce(config
.servers
, &constraints
);
1088 bool RTCPeerConnectionHandler::addICECandidate(
1089 const blink::WebRTCVoidRequest
& request
,
1090 const blink::WebRTCICECandidate
& candidate
) {
1091 DCHECK(thread_checker_
.CalledOnValidThread());
1092 TRACE_EVENT0("webrtc", "RTCPeerConnectionHandler::addICECandidate");
1093 // Libjingle currently does not accept callbacks for addICECandidate.
1094 // For that reason we are going to call callbacks from here.
1096 // TODO(tommi): Instead of calling addICECandidate here, we can do a
1097 // PostTaskAndReply kind of a thing.
1098 bool result
= addICECandidate(candidate
);
1099 base::ThreadTaskRunnerHandle::Get()->PostTask(
1100 FROM_HERE
, base::Bind(&RTCPeerConnectionHandler::OnaddICECandidateResult
,
1101 weak_factory_
.GetWeakPtr(), request
, result
));
1102 // On failure callback will be triggered.
1106 bool RTCPeerConnectionHandler::addICECandidate(
1107 const blink::WebRTCICECandidate
& candidate
) {
1108 DCHECK(thread_checker_
.CalledOnValidThread());
1109 TRACE_EVENT0("webrtc", "RTCPeerConnectionHandler::addICECandidate");
1110 scoped_ptr
<webrtc::IceCandidateInterface
> native_candidate(
1111 dependency_factory_
->CreateIceCandidate(
1112 base::UTF16ToUTF8(base::StringPiece16(candidate
.sdpMid())),
1113 candidate
.sdpMLineIndex(),
1114 base::UTF16ToUTF8(base::StringPiece16(candidate
.candidate()))));
1115 bool return_value
= false;
1117 if (native_candidate
) {
1119 native_peer_connection_
->AddIceCandidate(native_candidate
.get());
1120 LOG_IF(ERROR
, !return_value
) << "Error processing ICE candidate.";
1122 LOG(ERROR
) << "Could not create native ICE candidate.";
1125 if (peer_connection_tracker_
) {
1126 peer_connection_tracker_
->TrackAddIceCandidate(
1127 this, candidate
, PeerConnectionTracker::SOURCE_REMOTE
, return_value
);
1129 return return_value
;
1132 void RTCPeerConnectionHandler::OnaddICECandidateResult(
1133 const blink::WebRTCVoidRequest
& webkit_request
, bool result
) {
1134 DCHECK(thread_checker_
.CalledOnValidThread());
1135 TRACE_EVENT0("webrtc", "RTCPeerConnectionHandler::OnaddICECandidateResult");
1137 // We don't have the actual error code from the libjingle, so for now
1138 // using a generic error string.
1139 return webkit_request
.requestFailed(
1140 base::UTF8ToUTF16("Error processing ICE candidate"));
1143 return webkit_request
.requestSucceeded();
1146 bool RTCPeerConnectionHandler::addStream(
1147 const blink::WebMediaStream
& stream
,
1148 const blink::WebMediaConstraints
& options
) {
1149 DCHECK(thread_checker_
.CalledOnValidThread());
1150 TRACE_EVENT0("webrtc", "RTCPeerConnectionHandler::addStream");
1151 for (ScopedVector
<WebRtcMediaStreamAdapter
>::iterator adapter_it
=
1152 local_streams_
.begin(); adapter_it
!= local_streams_
.end();
1154 if ((*adapter_it
)->IsEqual(stream
)) {
1155 DVLOG(1) << "RTCPeerConnectionHandler::addStream called with the same "
1156 << "stream twice. id=" << stream
.id().utf8();
1161 if (peer_connection_tracker_
) {
1162 peer_connection_tracker_
->TrackAddStream(
1163 this, stream
, PeerConnectionTracker::SOURCE_LOCAL
);
1166 PerSessionWebRTCAPIMetrics::GetInstance()->IncrementStreamCounter();
1168 WebRtcMediaStreamAdapter
* adapter
=
1169 new WebRtcMediaStreamAdapter(stream
, dependency_factory_
);
1170 local_streams_
.push_back(adapter
);
1172 webrtc::MediaStreamInterface
* webrtc_stream
= adapter
->webrtc_media_stream();
1173 track_metrics_
.AddStream(MediaStreamTrackMetrics::SENT_STREAM
,
1176 RTCMediaConstraints
constraints(options
);
1177 if (!constraints
.GetMandatory().empty() ||
1178 !constraints
.GetOptional().empty()) {
1179 // TODO(perkj): |mediaConstraints| is the name of the optional constraints
1180 // argument in RTCPeerConnection.idl. It has been removed from the spec and
1181 // should be removed from blink as well.
1183 << "mediaConstraints is not a supported argument to addStream.";
1186 return native_peer_connection_
->AddStream(webrtc_stream
);
1189 void RTCPeerConnectionHandler::removeStream(
1190 const blink::WebMediaStream
& stream
) {
1191 DCHECK(thread_checker_
.CalledOnValidThread());
1192 TRACE_EVENT0("webrtc", "RTCPeerConnectionHandler::removeStream");
1193 // Find the webrtc stream.
1194 scoped_refptr
<webrtc::MediaStreamInterface
> webrtc_stream
;
1195 for (ScopedVector
<WebRtcMediaStreamAdapter
>::iterator adapter_it
=
1196 local_streams_
.begin(); adapter_it
!= local_streams_
.end();
1198 if ((*adapter_it
)->IsEqual(stream
)) {
1199 webrtc_stream
= (*adapter_it
)->webrtc_media_stream();
1200 local_streams_
.erase(adapter_it
);
1204 DCHECK(webrtc_stream
.get());
1205 // TODO(tommi): Make this async (PostTaskAndReply).
1206 native_peer_connection_
->RemoveStream(webrtc_stream
.get());
1208 if (peer_connection_tracker_
) {
1209 peer_connection_tracker_
->TrackRemoveStream(
1210 this, stream
, PeerConnectionTracker::SOURCE_LOCAL
);
1212 PerSessionWebRTCAPIMetrics::GetInstance()->DecrementStreamCounter();
1213 track_metrics_
.RemoveStream(MediaStreamTrackMetrics::SENT_STREAM
,
1214 webrtc_stream
.get());
1217 void RTCPeerConnectionHandler::getStats(
1218 const blink::WebRTCStatsRequest
& request
) {
1219 DCHECK(thread_checker_
.CalledOnValidThread());
1220 scoped_refptr
<LocalRTCStatsRequest
> inner_request(
1221 new rtc::RefCountedObject
<LocalRTCStatsRequest
>(request
));
1222 getStats(inner_request
);
1225 void RTCPeerConnectionHandler::getStats(
1226 const scoped_refptr
<LocalRTCStatsRequest
>& request
) {
1227 DCHECK(thread_checker_
.CalledOnValidThread());
1228 TRACE_EVENT0("webrtc", "RTCPeerConnectionHandler::getStats");
1231 rtc::scoped_refptr
<webrtc::StatsObserver
> observer(
1232 new rtc::RefCountedObject
<StatsResponse
>(request
));
1234 std::string track_id
;
1235 blink::WebMediaStreamSource::Type track_type
=
1236 blink::WebMediaStreamSource::TypeAudio
;
1237 if (request
->hasSelector()) {
1238 track_type
= request
->component().source().type();
1239 track_id
= request
->component().id().utf8();
1242 GetStats(observer
, webrtc::PeerConnectionInterface::kStatsOutputLevelStandard
,
1243 track_id
, track_type
);
1246 // TODO(tommi): It's weird to have three {g|G}etStats methods. Clean this up.
1247 void RTCPeerConnectionHandler::GetStats(
1248 webrtc::StatsObserver
* observer
,
1249 webrtc::PeerConnectionInterface::StatsOutputLevel level
,
1250 const std::string
& track_id
,
1251 blink::WebMediaStreamSource::Type track_type
) {
1252 DCHECK(thread_checker_
.CalledOnValidThread());
1253 signaling_thread()->PostTask(FROM_HERE
,
1254 base::Bind(&GetStatsOnSignalingThread
, native_peer_connection_
, level
,
1255 make_scoped_refptr(observer
), track_id
, track_type
));
1258 void RTCPeerConnectionHandler::CloseClientPeerConnection() {
1259 DCHECK(thread_checker_
.CalledOnValidThread());
1261 client_
->closePeerConnection();
1264 blink::WebRTCDataChannelHandler
* RTCPeerConnectionHandler::createDataChannel(
1265 const blink::WebString
& label
, const blink::WebRTCDataChannelInit
& init
) {
1266 DCHECK(thread_checker_
.CalledOnValidThread());
1267 TRACE_EVENT0("webrtc", "RTCPeerConnectionHandler::createDataChannel");
1268 DVLOG(1) << "createDataChannel label "
1269 << base::UTF16ToUTF8(base::StringPiece16(label
));
1271 webrtc::DataChannelInit config
;
1272 // TODO(jiayl): remove the deprecated reliable field once Libjingle is updated
1274 config
.reliable
= false;
1275 config
.id
= init
.id
;
1276 config
.ordered
= init
.ordered
;
1277 config
.negotiated
= init
.negotiated
;
1278 config
.maxRetransmits
= init
.maxRetransmits
;
1279 config
.maxRetransmitTime
= init
.maxRetransmitTime
;
1280 config
.protocol
= base::UTF16ToUTF8(base::StringPiece16(init
.protocol
));
1282 rtc::scoped_refptr
<webrtc::DataChannelInterface
> webrtc_channel(
1283 native_peer_connection_
->CreateDataChannel(
1284 base::UTF16ToUTF8(base::StringPiece16(label
)), &config
));
1285 if (!webrtc_channel
) {
1286 DLOG(ERROR
) << "Could not create native data channel.";
1289 if (peer_connection_tracker_
) {
1290 peer_connection_tracker_
->TrackCreateDataChannel(
1291 this, webrtc_channel
.get(), PeerConnectionTracker::SOURCE_LOCAL
);
1294 ++num_data_channels_created_
;
1296 return new RtcDataChannelHandler(base::ThreadTaskRunnerHandle::Get(),
1300 blink::WebRTCDTMFSenderHandler
* RTCPeerConnectionHandler::createDTMFSender(
1301 const blink::WebMediaStreamTrack
& track
) {
1302 DCHECK(thread_checker_
.CalledOnValidThread());
1303 TRACE_EVENT0("webrtc", "RTCPeerConnectionHandler::createDTMFSender");
1304 DVLOG(1) << "createDTMFSender.";
1306 MediaStreamTrack
* native_track
= MediaStreamTrack::GetTrack(track
);
1307 if (!native_track
|| !native_track
->is_local_track() ||
1308 track
.source().type() != blink::WebMediaStreamSource::TypeAudio
) {
1309 DLOG(ERROR
) << "The DTMF sender requires a local audio track.";
1313 scoped_refptr
<webrtc::AudioTrackInterface
> audio_track
=
1314 native_track
->GetAudioAdapter();
1315 rtc::scoped_refptr
<webrtc::DtmfSenderInterface
> sender(
1316 native_peer_connection_
->CreateDtmfSender(audio_track
.get()));
1318 DLOG(ERROR
) << "Could not create native DTMF sender.";
1321 if (peer_connection_tracker_
)
1322 peer_connection_tracker_
->TrackCreateDTMFSender(this, track
);
1324 return new RtcDtmfSenderHandler(sender
);
1327 void RTCPeerConnectionHandler::stop() {
1328 DCHECK(thread_checker_
.CalledOnValidThread());
1329 DVLOG(1) << "RTCPeerConnectionHandler::stop";
1331 if (!client_
|| !native_peer_connection_
.get())
1332 return; // Already stopped.
1334 if (peer_connection_tracker_
)
1335 peer_connection_tracker_
->TrackStop(this);
1337 native_peer_connection_
->Close();
1339 // The client_ pointer is not considered valid after this point and no further
1340 // callbacks must be made.
1344 void RTCPeerConnectionHandler::OnSignalingChange(
1345 webrtc::PeerConnectionInterface::SignalingState new_state
) {
1346 DCHECK(thread_checker_
.CalledOnValidThread());
1347 TRACE_EVENT0("webrtc", "RTCPeerConnectionHandler::OnSignalingChange");
1349 blink::WebRTCPeerConnectionHandlerClient::SignalingState state
=
1350 GetWebKitSignalingState(new_state
);
1351 if (peer_connection_tracker_
)
1352 peer_connection_tracker_
->TrackSignalingStateChange(this, state
);
1354 client_
->didChangeSignalingState(state
);
1357 // Called any time the IceConnectionState changes
1358 void RTCPeerConnectionHandler::OnIceConnectionChange(
1359 webrtc::PeerConnectionInterface::IceConnectionState new_state
) {
1360 TRACE_EVENT0("webrtc", "RTCPeerConnectionHandler::OnIceConnectionChange");
1361 DCHECK(thread_checker_
.CalledOnValidThread());
1362 ReportICEState(new_state
);
1363 if (new_state
== webrtc::PeerConnectionInterface::kIceConnectionChecking
) {
1364 ice_connection_checking_start_
= base::TimeTicks::Now();
1365 } else if (new_state
==
1366 webrtc::PeerConnectionInterface::kIceConnectionConnected
) {
1367 // If the state becomes connected, send the time needed for PC to become
1368 // connected from checking to UMA. UMA data will help to know how much
1369 // time needed for PC to connect with remote peer.
1370 if (ice_connection_checking_start_
.is_null()) {
1371 // From UMA, we have observed a large number of calls falling into the
1372 // overflow buckets. One possibility is that the Checking is not signaled
1373 // before Connected. This is to guard against that situation to make the
1374 // metric more robust.
1375 UMA_HISTOGRAM_MEDIUM_TIMES("WebRTC.PeerConnection.TimeToConnect",
1378 UMA_HISTOGRAM_MEDIUM_TIMES(
1379 "WebRTC.PeerConnection.TimeToConnect",
1380 base::TimeTicks::Now() - ice_connection_checking_start_
);
1384 track_metrics_
.IceConnectionChange(new_state
);
1385 blink::WebRTCPeerConnectionHandlerClient::ICEConnectionState state
=
1386 GetWebKitIceConnectionState(new_state
);
1387 if (peer_connection_tracker_
)
1388 peer_connection_tracker_
->TrackIceConnectionStateChange(this, state
);
1390 client_
->didChangeICEConnectionState(state
);
1393 // Called any time the IceGatheringState changes
1394 void RTCPeerConnectionHandler::OnIceGatheringChange(
1395 webrtc::PeerConnectionInterface::IceGatheringState new_state
) {
1396 DCHECK(thread_checker_
.CalledOnValidThread());
1397 TRACE_EVENT0("webrtc", "RTCPeerConnectionHandler::OnIceGatheringChange");
1399 if (new_state
== webrtc::PeerConnectionInterface::kIceGatheringComplete
) {
1400 // If ICE gathering is completed, generate a NULL ICE candidate,
1401 // to signal end of candidates.
1403 blink::WebRTCICECandidate null_candidate
;
1404 client_
->didGenerateICECandidate(null_candidate
);
1407 UMA_HISTOGRAM_COUNTS_100("WebRTC.PeerConnection.IPv4LocalCandidates",
1408 num_local_candidates_ipv4_
);
1410 UMA_HISTOGRAM_COUNTS_100("WebRTC.PeerConnection.IPv6LocalCandidates",
1411 num_local_candidates_ipv6_
);
1412 } else if (new_state
==
1413 webrtc::PeerConnectionInterface::kIceGatheringGathering
) {
1414 // ICE restarts will change gathering state back to "gathering",
1415 // reset the counter.
1419 blink::WebRTCPeerConnectionHandlerClient::ICEGatheringState state
=
1420 GetWebKitIceGatheringState(new_state
);
1421 if (peer_connection_tracker_
)
1422 peer_connection_tracker_
->TrackIceGatheringStateChange(this, state
);
1424 client_
->didChangeICEGatheringState(state
);
1427 void RTCPeerConnectionHandler::OnRenegotiationNeeded() {
1428 DCHECK(thread_checker_
.CalledOnValidThread());
1429 TRACE_EVENT0("webrtc", "RTCPeerConnectionHandler::OnRenegotiationNeeded");
1430 if (peer_connection_tracker_
)
1431 peer_connection_tracker_
->TrackOnRenegotiationNeeded(this);
1433 client_
->negotiationNeeded();
1436 void RTCPeerConnectionHandler::OnAddStream(
1437 scoped_ptr
<RemoteMediaStreamImpl
> stream
) {
1438 DCHECK(thread_checker_
.CalledOnValidThread());
1439 DCHECK(remote_streams_
.find(stream
->webrtc_stream().get()) ==
1440 remote_streams_
.end());
1441 DCHECK(stream
->webkit_stream().extraData()) << "Initialization not done";
1442 TRACE_EVENT0("webrtc", "RTCPeerConnectionHandler::OnAddStreamImpl");
1444 // Ownership is with remote_streams_ now.
1445 RemoteMediaStreamImpl
* s
= stream
.release();
1446 remote_streams_
.insert(
1447 std::pair
<webrtc::MediaStreamInterface
*, RemoteMediaStreamImpl
*> (
1448 s
->webrtc_stream().get(), s
));
1450 if (peer_connection_tracker_
) {
1451 peer_connection_tracker_
->TrackAddStream(
1452 this, s
->webkit_stream(), PeerConnectionTracker::SOURCE_REMOTE
);
1455 PerSessionWebRTCAPIMetrics::GetInstance()->IncrementStreamCounter();
1457 track_metrics_
.AddStream(MediaStreamTrackMetrics::RECEIVED_STREAM
,
1458 s
->webrtc_stream().get());
1460 client_
->didAddRemoteStream(s
->webkit_stream());
1463 void RTCPeerConnectionHandler::OnRemoveStream(
1464 const scoped_refptr
<webrtc::MediaStreamInterface
>& stream
) {
1465 DCHECK(thread_checker_
.CalledOnValidThread());
1466 TRACE_EVENT0("webrtc", "RTCPeerConnectionHandler::OnRemoveStreamImpl");
1467 RemoteStreamMap::iterator it
= remote_streams_
.find(stream
.get());
1468 if (it
== remote_streams_
.end()) {
1469 NOTREACHED() << "Stream not found";
1473 track_metrics_
.RemoveStream(MediaStreamTrackMetrics::RECEIVED_STREAM
,
1475 PerSessionWebRTCAPIMetrics::GetInstance()->DecrementStreamCounter();
1477 scoped_ptr
<RemoteMediaStreamImpl
> remote_stream(it
->second
);
1478 const blink::WebMediaStream
& webkit_stream
= remote_stream
->webkit_stream();
1479 DCHECK(!webkit_stream
.isNull());
1480 remote_streams_
.erase(it
);
1482 if (peer_connection_tracker_
) {
1483 peer_connection_tracker_
->TrackRemoveStream(
1484 this, webkit_stream
, PeerConnectionTracker::SOURCE_REMOTE
);
1488 client_
->didRemoveRemoteStream(webkit_stream
);
1491 void RTCPeerConnectionHandler::OnDataChannel(
1492 scoped_ptr
<RtcDataChannelHandler
> handler
) {
1493 DCHECK(thread_checker_
.CalledOnValidThread());
1494 TRACE_EVENT0("webrtc", "RTCPeerConnectionHandler::OnDataChannelImpl");
1496 if (peer_connection_tracker_
) {
1497 peer_connection_tracker_
->TrackCreateDataChannel(
1498 this, handler
->channel().get(), PeerConnectionTracker::SOURCE_REMOTE
);
1502 client_
->didAddRemoteDataChannel(handler
.release());
1505 void RTCPeerConnectionHandler::OnIceCandidate(
1506 const std::string
& sdp
, const std::string
& sdp_mid
, int sdp_mline_index
,
1507 int component
, int address_family
) {
1508 DCHECK(thread_checker_
.CalledOnValidThread());
1509 TRACE_EVENT0("webrtc", "RTCPeerConnectionHandler::OnIceCandidateImpl");
1510 blink::WebRTCICECandidate web_candidate
;
1511 web_candidate
.initialize(base::UTF8ToUTF16(sdp
),
1512 base::UTF8ToUTF16(sdp_mid
),
1514 if (peer_connection_tracker_
) {
1515 peer_connection_tracker_
->TrackAddIceCandidate(
1516 this, web_candidate
, PeerConnectionTracker::SOURCE_LOCAL
, true);
1519 // Only the first m line's first component is tracked to avoid
1520 // miscounting when doing BUNDLE or rtcp mux.
1521 if (sdp_mline_index
== 0 && component
== 1) {
1522 if (address_family
== AF_INET
) {
1523 ++num_local_candidates_ipv4_
;
1524 } else if (address_family
== AF_INET6
) {
1525 ++num_local_candidates_ipv6_
;
1531 client_
->didGenerateICECandidate(web_candidate
);
1534 webrtc::SessionDescriptionInterface
*
1535 RTCPeerConnectionHandler::CreateNativeSessionDescription(
1536 const std::string
& sdp
, const std::string
& type
,
1537 webrtc::SdpParseError
* error
) {
1538 webrtc::SessionDescriptionInterface
* native_desc
=
1539 dependency_factory_
->CreateSessionDescription(type
, sdp
, error
);
1541 LOG_IF(ERROR
, !native_desc
) << "Failed to create native session description."
1542 << " Type: " << type
<< " SDP: " << sdp
;
1547 RTCPeerConnectionHandler::FirstSessionDescription::FirstSessionDescription(
1548 const webrtc::SessionDescriptionInterface
* sdesc
) {
1551 for (const auto& content
: sdesc
->description()->contents()) {
1552 if (content
.type
== cricket::NS_JINGLE_RTP
) {
1554 static_cast<cricket::MediaContentDescription
*>(content
.description
);
1555 audio
= audio
|| (mdesc
->type() == cricket::MEDIA_TYPE_AUDIO
);
1556 video
= video
|| (mdesc
->type() == cricket::MEDIA_TYPE_VIDEO
);
1557 rtcp_mux
= rtcp_mux
|| mdesc
->rtcp_mux();
1562 void RTCPeerConnectionHandler::ReportFirstSessionDescriptions(
1563 const FirstSessionDescription
& local
,
1564 const FirstSessionDescription
& remote
) {
1565 RtcpMux rtcp_mux
= RTCP_MUX_ENABLED
;
1566 if ((!local
.audio
&& !local
.video
) || (!remote
.audio
&& !remote
.video
)) {
1567 rtcp_mux
= RTCP_MUX_NO_MEDIA
;
1568 } else if (!local
.rtcp_mux
|| !remote
.rtcp_mux
) {
1569 rtcp_mux
= RTCP_MUX_DISABLED
;
1572 UMA_HISTOGRAM_ENUMERATION(
1573 "WebRTC.PeerConnection.RtcpMux", rtcp_mux
, RTCP_MUX_MAX
);
1575 // TODO(pthatcher): Reports stats about whether we have audio and
1579 scoped_refptr
<base::SingleThreadTaskRunner
>
1580 RTCPeerConnectionHandler::signaling_thread() const {
1581 DCHECK(thread_checker_
.CalledOnValidThread());
1582 return dependency_factory_
->GetWebRtcSignalingThread();
1585 void RTCPeerConnectionHandler::RunSynchronousClosureOnSignalingThread(
1586 const base::Closure
& closure
,
1587 const char* trace_event_name
) {
1588 DCHECK(thread_checker_
.CalledOnValidThread());
1589 scoped_refptr
<base::SingleThreadTaskRunner
> thread(signaling_thread());
1590 if (!thread
.get() || thread
->BelongsToCurrentThread()) {
1591 TRACE_EVENT0("webrtc", trace_event_name
);
1594 base::WaitableEvent
event(false, false);
1595 thread
->PostTask(FROM_HERE
,
1596 base::Bind(&RunSynchronousClosure
, closure
,
1597 base::Unretained(trace_event_name
),
1598 base::Unretained(&event
)));
1603 void RTCPeerConnectionHandler::ReportICEState(
1604 webrtc::PeerConnectionInterface::IceConnectionState new_state
) {
1605 DCHECK(thread_checker_
.CalledOnValidThread());
1606 if (ice_state_seen_
[new_state
])
1608 ice_state_seen_
[new_state
] = true;
1609 UMA_HISTOGRAM_ENUMERATION("WebRTC.PeerConnection.ConnectionState", new_state
,
1610 webrtc::PeerConnectionInterface::kIceConnectionMax
);
1613 void RTCPeerConnectionHandler::ResetUMAStats() {
1614 DCHECK(thread_checker_
.CalledOnValidThread());
1615 num_local_candidates_ipv6_
= 0;
1616 num_local_candidates_ipv4_
= 0;
1617 ice_connection_checking_start_
= base::TimeTicks();
1618 memset(ice_state_seen_
, 0, sizeof(ice_state_seen_
));
1620 } // namespace content