Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / content / renderer / media / rtc_peer_connection_handler.cc
blob181838af564e9d0086921219e6c6eebed4a4e011
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"
7 #include <string>
8 #include <utility>
9 #include <vector>
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;
53 namespace content {
54 namespace {
56 // Used to back histogram value of "WebRTC.PeerConnection.RtcpMux",
57 // so treat as append-only.
58 enum RtcpMux {
59 RTCP_MUX_DISABLED,
60 RTCP_MUX_ENABLED,
61 RTCP_MUX_NO_MEDIA,
62 RTCP_MUX_MAX
65 // Converter functions from libjingle types to WebKit types.
66 blink::WebRTCPeerConnectionHandlerClient::ICEGatheringState
67 GetWebKitIceGatheringState(
68 webrtc::PeerConnectionInterface::IceGatheringState state) {
69 using blink::WebRTCPeerConnectionHandlerClient;
70 switch (state) {
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;
77 default:
78 NOTREACHED();
79 return WebRTCPeerConnectionHandlerClient::ICEGatheringStateNew;
83 blink::WebRTCPeerConnectionHandlerClient::ICEConnectionState
84 GetWebKitIceConnectionState(
85 webrtc::PeerConnectionInterface::IceConnectionState ice_state) {
86 using blink::WebRTCPeerConnectionHandlerClient;
87 switch (ice_state) {
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;
102 default:
103 NOTREACHED();
104 return WebRTCPeerConnectionHandlerClient::ICEConnectionStateClosed;
108 blink::WebRTCPeerConnectionHandlerClient::SignalingState
109 GetWebKitSignalingState(webrtc::PeerConnectionInterface::SignalingState state) {
110 using blink::WebRTCPeerConnectionHandlerClient;
111 switch (state) {
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:
121 return
122 WebRTCPeerConnectionHandlerClient::SignalingStateHaveRemotePrAnswer;
123 case webrtc::PeerConnectionInterface::kClosed:
124 return WebRTCPeerConnectionHandlerClient::SignalingStateClosed;
125 default:
126 NOTREACHED();
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));
135 return description;
138 blink::WebRTCSessionDescription
139 CreateWebKitSessionDescription(
140 const webrtc::SessionDescriptionInterface* native_desc) {
141 if (!native_desc) {
142 LOG(ERROR) << "Native session description is null.";
143 return blink::WebRTCSessionDescription();
146 std::string sdp;
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);
158 closure.Run();
161 void RunSynchronousClosure(const base::Closure& closure,
162 const char* trace_event_name,
163 base::WaitableEvent* event) {
165 TRACE_EVENT0("webrtc", trace_event_name);
166 closure.Run();
168 event->Signal();
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();
177 if (description) {
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 DCHECK_EQ(webrtc_config->enable_localhost_ice_candidate, false);
190 // When we don't have WebRTCConfiguration, treat it as a special case where we
191 // should generate local host candidate. This will only be honored if
192 // enable_multiple_routes is disabled.
193 if (blink_config.isNull()) {
194 webrtc_config->enable_localhost_ice_candidate = true;
195 return;
198 if (blink_config.iceServers().isNull()) {
199 // Same as when iceServers is undefined or unspecified.
200 webrtc_config->enable_localhost_ice_candidate = true;
201 } else {
202 for (size_t i = 0; i < blink_config.iceServers().numberOfServers(); ++i) {
203 webrtc::PeerConnectionInterface::IceServer server;
204 const blink::WebRTCICEServer& webkit_server =
205 blink_config.iceServers().server(i);
206 server.username =
207 base::UTF16ToUTF8(base::StringPiece16(webkit_server.username()));
208 server.password =
209 base::UTF16ToUTF8(base::StringPiece16(webkit_server.credential()));
210 server.uri = webkit_server.uri().spec();
211 webrtc_config->servers.push_back(server);
215 switch (blink_config.iceTransports()) {
216 case blink::WebRTCIceTransportsNone:
217 webrtc_config->type = webrtc::PeerConnectionInterface::kNone;
218 break;
219 case blink::WebRTCIceTransportsRelay:
220 webrtc_config->type = webrtc::PeerConnectionInterface::kRelay;
221 break;
222 case blink::WebRTCIceTransportsAll:
223 webrtc_config->type = webrtc::PeerConnectionInterface::kAll;
224 break;
225 default:
226 NOTREACHED();
229 switch (blink_config.bundlePolicy()) {
230 case blink::WebRTCBundlePolicyBalanced:
231 webrtc_config->bundle_policy =
232 webrtc::PeerConnectionInterface::kBundlePolicyBalanced;
233 break;
234 case blink::WebRTCBundlePolicyMaxBundle:
235 webrtc_config->bundle_policy =
236 webrtc::PeerConnectionInterface::kBundlePolicyMaxBundle;
237 break;
238 case blink::WebRTCBundlePolicyMaxCompat:
239 webrtc_config->bundle_policy =
240 webrtc::PeerConnectionInterface::kBundlePolicyMaxCompat;
241 break;
242 default:
243 NOTREACHED();
246 switch (blink_config.rtcpMuxPolicy()) {
247 case blink::WebRTCRtcpMuxPolicyNegotiate:
248 webrtc_config->rtcp_mux_policy =
249 webrtc::PeerConnectionInterface::kRtcpMuxPolicyNegotiate;
250 break;
251 case blink::WebRTCRtcpMuxPolicyRequire:
252 webrtc_config->rtcp_mux_policy =
253 webrtc::PeerConnectionInterface::kRtcpMuxPolicyRequire;
254 break;
255 default:
256 NOTREACHED();
260 class SessionDescriptionRequestTracker {
261 public:
262 SessionDescriptionRequestTracker(
263 const base::WeakPtr<RTCPeerConnectionHandler>& handler,
264 const base::WeakPtr<PeerConnectionTracker>& tracker,
265 PeerConnectionTracker::Action action)
266 : handler_(handler), tracker_(tracker), action_(action) {}
268 void TrackOnSuccess(const webrtc::SessionDescriptionInterface* desc) {
269 DCHECK(thread_checker_.CalledOnValidThread());
270 if (tracker_ && handler_) {
271 std::string value;
272 if (desc) {
273 desc->ToString(&value);
274 value = "type: " + desc->type() + ", sdp: " + value;
276 tracker_->TrackSessionDescriptionCallback(
277 handler_.get(), action_, "OnSuccess", value);
281 void TrackOnFailure(const std::string& error) {
282 DCHECK(thread_checker_.CalledOnValidThread());
283 if (handler_ && tracker_) {
284 tracker_->TrackSessionDescriptionCallback(
285 handler_.get(), action_, "OnFailure", error);
289 private:
290 const base::WeakPtr<RTCPeerConnectionHandler> handler_;
291 const base::WeakPtr<PeerConnectionTracker> tracker_;
292 PeerConnectionTracker::Action action_;
293 base::ThreadChecker thread_checker_;
296 // Class mapping responses from calls to libjingle CreateOffer/Answer and
297 // the blink::WebRTCSessionDescriptionRequest.
298 class CreateSessionDescriptionRequest
299 : public webrtc::CreateSessionDescriptionObserver {
300 public:
301 explicit CreateSessionDescriptionRequest(
302 const scoped_refptr<base::SingleThreadTaskRunner>& main_thread,
303 const blink::WebRTCSessionDescriptionRequest& request,
304 const base::WeakPtr<RTCPeerConnectionHandler>& handler,
305 const base::WeakPtr<PeerConnectionTracker>& tracker,
306 PeerConnectionTracker::Action action)
307 : main_thread_(main_thread),
308 webkit_request_(request),
309 tracker_(handler, tracker, action) {
312 void OnSuccess(webrtc::SessionDescriptionInterface* desc) override {
313 if (!main_thread_->BelongsToCurrentThread()) {
314 main_thread_->PostTask(FROM_HERE,
315 base::Bind(&CreateSessionDescriptionRequest::OnSuccess, this, desc));
316 return;
319 tracker_.TrackOnSuccess(desc);
320 webkit_request_.requestSucceeded(CreateWebKitSessionDescription(desc));
321 webkit_request_.reset();
322 delete desc;
324 void OnFailure(const std::string& error) override {
325 if (!main_thread_->BelongsToCurrentThread()) {
326 main_thread_->PostTask(FROM_HERE,
327 base::Bind(&CreateSessionDescriptionRequest::OnFailure, this, error));
328 return;
331 tracker_.TrackOnFailure(error);
332 webkit_request_.requestFailed(base::UTF8ToUTF16(error));
333 webkit_request_.reset();
336 protected:
337 ~CreateSessionDescriptionRequest() override {
338 CHECK(webkit_request_.isNull());
341 const scoped_refptr<base::SingleThreadTaskRunner> main_thread_;
342 blink::WebRTCSessionDescriptionRequest webkit_request_;
343 SessionDescriptionRequestTracker tracker_;
346 // Class mapping responses from calls to libjingle
347 // SetLocalDescription/SetRemoteDescription and a blink::WebRTCVoidRequest.
348 class SetSessionDescriptionRequest
349 : public webrtc::SetSessionDescriptionObserver {
350 public:
351 explicit SetSessionDescriptionRequest(
352 const scoped_refptr<base::SingleThreadTaskRunner>& main_thread,
353 const blink::WebRTCVoidRequest& request,
354 const base::WeakPtr<RTCPeerConnectionHandler>& handler,
355 const base::WeakPtr<PeerConnectionTracker>& tracker,
356 PeerConnectionTracker::Action action)
357 : main_thread_(main_thread),
358 webkit_request_(request),
359 tracker_(handler, tracker, action) {
362 void OnSuccess() override {
363 if (!main_thread_->BelongsToCurrentThread()) {
364 main_thread_->PostTask(FROM_HERE,
365 base::Bind(&SetSessionDescriptionRequest::OnSuccess, this));
366 return;
368 tracker_.TrackOnSuccess(NULL);
369 webkit_request_.requestSucceeded();
370 webkit_request_.reset();
372 void OnFailure(const std::string& error) override {
373 if (!main_thread_->BelongsToCurrentThread()) {
374 main_thread_->PostTask(FROM_HERE,
375 base::Bind(&SetSessionDescriptionRequest::OnFailure, this, error));
376 return;
378 tracker_.TrackOnFailure(error);
379 webkit_request_.requestFailed(base::UTF8ToUTF16(error));
380 webkit_request_.reset();
383 protected:
384 ~SetSessionDescriptionRequest() override {
385 DCHECK(webkit_request_.isNull());
388 private:
389 const scoped_refptr<base::SingleThreadTaskRunner> main_thread_;
390 blink::WebRTCVoidRequest webkit_request_;
391 SessionDescriptionRequestTracker tracker_;
394 // Class mapping responses from calls to libjingle
395 // GetStats into a blink::WebRTCStatsCallback.
396 class StatsResponse : public webrtc::StatsObserver {
397 public:
398 explicit StatsResponse(const scoped_refptr<LocalRTCStatsRequest>& request)
399 : request_(request.get()),
400 main_thread_(base::ThreadTaskRunnerHandle::Get()) {
401 // Measure the overall time it takes to satisfy a getStats request.
402 TRACE_EVENT_ASYNC_BEGIN0("webrtc", "getStats_Native", this);
403 signaling_thread_checker_.DetachFromThread();
406 void OnComplete(const StatsReports& reports) override {
407 DCHECK(signaling_thread_checker_.CalledOnValidThread());
408 TRACE_EVENT0("webrtc", "StatsResponse::OnComplete");
409 // We can't use webkit objects directly since they use a single threaded
410 // heap allocator.
411 std::vector<Report*>* report_copies = new std::vector<Report*>();
412 report_copies->reserve(reports.size());
413 for (auto* r : reports)
414 report_copies->push_back(new Report(r));
416 main_thread_->PostTaskAndReply(FROM_HERE,
417 base::Bind(&StatsResponse::DeliverCallback, this,
418 base::Unretained(report_copies)),
419 base::Bind(&StatsResponse::DeleteReports,
420 base::Unretained(report_copies)));
423 private:
424 struct Report {
425 Report(const StatsReport* report)
426 : thread_checker(), id(report->id()->ToString()),
427 type(report->TypeToString()), timestamp(report->timestamp()),
428 values(report->values()) {
431 ~Report() {
432 // Since the values vector holds pointers to const objects that are bound
433 // to the signaling thread, they must be released on the same thread.
434 DCHECK(thread_checker.CalledOnValidThread());
437 const base::ThreadChecker thread_checker;
438 const std::string id, type;
439 const double timestamp;
440 const StatsReport::Values values;
443 static void DeleteReports(std::vector<Report*>* reports) {
444 TRACE_EVENT0("webrtc", "StatsResponse::DeleteReports");
445 for (auto* p : *reports)
446 delete p;
447 delete reports;
450 void DeliverCallback(const std::vector<Report*>* reports) {
451 DCHECK(main_thread_->BelongsToCurrentThread());
452 TRACE_EVENT0("webrtc", "StatsResponse::DeliverCallback");
454 rtc::scoped_refptr<LocalRTCStatsResponse> response(
455 request_->createResponse().get());
456 for (const auto* report : *reports) {
457 if (report->values.size() > 0)
458 AddReport(response.get(), *report);
461 // Record the getStats operation as done before calling into Blink so that
462 // we don't skew the perf measurements of the native code with whatever the
463 // callback might be doing.
464 TRACE_EVENT_ASYNC_END0("webrtc", "getStats_Native", this);
465 request_->requestSucceeded(response);
466 request_ = nullptr; // must be freed on the main thread.
469 void AddReport(LocalRTCStatsResponse* response, const Report& report) {
470 int idx = response->addReport(blink::WebString::fromUTF8(report.id),
471 blink::WebString::fromUTF8(report.type),
472 report.timestamp);
473 blink::WebString name, value_str;
474 for (const auto& value : report.values) {
475 const StatsReport::ValuePtr& v = value.second;
476 name = blink::WebString::fromUTF8(value.second->display_name());
478 if (v->type() == StatsReport::Value::kString)
479 value_str = blink::WebString::fromUTF8(v->string_val());
480 if (v->type() == StatsReport::Value::kStaticString)
481 value_str = blink::WebString::fromUTF8(v->static_string_val());
482 else
483 value_str = blink::WebString::fromUTF8(v->ToString());
485 response->addStatistic(idx, name, value_str);
489 rtc::scoped_refptr<LocalRTCStatsRequest> request_;
490 const scoped_refptr<base::SingleThreadTaskRunner> main_thread_;
491 base::ThreadChecker signaling_thread_checker_;
494 void GetStatsOnSignalingThread(
495 const scoped_refptr<webrtc::PeerConnectionInterface>& pc,
496 webrtc::PeerConnectionInterface::StatsOutputLevel level,
497 const scoped_refptr<webrtc::StatsObserver>& observer,
498 const std::string track_id, blink::WebMediaStreamSource::Type track_type) {
499 TRACE_EVENT0("webrtc", "GetStatsOnSignalingThread");
501 scoped_refptr<webrtc::MediaStreamTrackInterface> track;
502 if (!track_id.empty()) {
503 if (track_type == blink::WebMediaStreamSource::TypeAudio) {
504 track = pc->local_streams()->FindAudioTrack(track_id);
505 if (!track.get())
506 track = pc->remote_streams()->FindAudioTrack(track_id);
507 } else {
508 DCHECK_EQ(blink::WebMediaStreamSource::TypeVideo, track_type);
509 track = pc->local_streams()->FindVideoTrack(track_id);
510 if (!track.get())
511 track = pc->remote_streams()->FindVideoTrack(track_id);
514 if (!track.get()) {
515 DVLOG(1) << "GetStats: Track not found.";
516 observer->OnComplete(StatsReports());
517 return;
521 if (!pc->GetStats(observer.get(), track.get(), level)) {
522 DVLOG(1) << "GetStats failed.";
523 observer->OnComplete(StatsReports());
527 class PeerConnectionUMAObserver : public webrtc::UMAObserver {
528 public:
529 PeerConnectionUMAObserver() {}
530 ~PeerConnectionUMAObserver() override {}
531 void IncrementEnumCounter(webrtc::PeerConnectionEnumCounterType counter_type,
532 int counter,
533 int counter_max) override {
534 switch (counter_type) {
535 case webrtc::kEnumCounterAddressFamily:
536 UMA_HISTOGRAM_ENUMERATION("WebRTC.PeerConnection.IPMetrics", counter,
537 counter_max);
538 break;
539 case webrtc::kEnumCounterIceCandidatePairTypeUdp:
540 UMA_HISTOGRAM_ENUMERATION("WebRTC.PeerConnection.CandidatePairType_UDP",
541 counter, counter_max);
542 break;
543 case webrtc::kEnumCounterIceCandidatePairTypeTcp:
544 UMA_HISTOGRAM_ENUMERATION("WebRTC.PeerConnection.CandidatePairType_TCP",
545 counter, counter_max);
546 break;
547 default:
548 // The default clause is expected to reach when new enum types are
549 // added.
550 break;
554 void AddHistogramSample(webrtc::PeerConnectionUMAMetricsName type,
555 int value) override {
556 // Runs on libjingle's signaling thread.
557 switch (type) {
558 case webrtc::kTimeToConnect:
559 UMA_HISTOGRAM_MEDIUM_TIMES(
560 "WebRTC.PeerConnection.TimeToConnect",
561 base::TimeDelta::FromMilliseconds(value));
562 break;
563 case webrtc::kNetworkInterfaces_IPv4:
564 UMA_HISTOGRAM_COUNTS_100("WebRTC.PeerConnection.IPv4Interfaces",
565 value);
566 break;
567 case webrtc::kNetworkInterfaces_IPv6:
568 UMA_HISTOGRAM_COUNTS_100("WebRTC.PeerConnection.IPv6Interfaces",
569 value);
570 break;
571 default:
572 // The default clause is expected to reach when new enum types are
573 // added.
574 break;
579 base::LazyInstance<std::set<RTCPeerConnectionHandler*> >::Leaky
580 g_peer_connection_handlers = LAZY_INSTANCE_INITIALIZER;
582 } // namespace
584 // Implementation of LocalRTCStatsRequest.
585 LocalRTCStatsRequest::LocalRTCStatsRequest(blink::WebRTCStatsRequest impl)
586 : impl_(impl) {
589 LocalRTCStatsRequest::LocalRTCStatsRequest() {}
590 LocalRTCStatsRequest::~LocalRTCStatsRequest() {}
592 bool LocalRTCStatsRequest::hasSelector() const {
593 return impl_.hasSelector();
596 blink::WebMediaStreamTrack LocalRTCStatsRequest::component() const {
597 return impl_.component();
600 scoped_refptr<LocalRTCStatsResponse> LocalRTCStatsRequest::createResponse() {
601 return scoped_refptr<LocalRTCStatsResponse>(
602 new rtc::RefCountedObject<LocalRTCStatsResponse>(impl_.createResponse()));
605 void LocalRTCStatsRequest::requestSucceeded(
606 const LocalRTCStatsResponse* response) {
607 impl_.requestSucceeded(response->webKitStatsResponse());
610 // Implementation of LocalRTCStatsResponse.
611 blink::WebRTCStatsResponse LocalRTCStatsResponse::webKitStatsResponse() const {
612 return impl_;
615 size_t LocalRTCStatsResponse::addReport(blink::WebString type,
616 blink::WebString id,
617 double timestamp) {
618 return impl_.addReport(type, id, timestamp);
621 void LocalRTCStatsResponse::addStatistic(size_t report,
622 blink::WebString name,
623 blink::WebString value) {
624 impl_.addStatistic(report, name, value);
627 // Receives notifications from a PeerConnection object about state changes,
628 // track addition/removal etc. The callbacks we receive here come on the
629 // signaling thread, so this class takes care of delivering them to an
630 // RTCPeerConnectionHandler instance on the main thread.
631 // In order to do safe PostTask-ing, the class is reference counted and
632 // checks for the existence of the RTCPeerConnectionHandler instance before
633 // delivering callbacks on the main thread.
634 class RTCPeerConnectionHandler::Observer
635 : public base::RefCountedThreadSafe<RTCPeerConnectionHandler::Observer>,
636 public PeerConnectionObserver {
637 public:
638 Observer(const base::WeakPtr<RTCPeerConnectionHandler>& handler)
639 : handler_(handler), main_thread_(base::ThreadTaskRunnerHandle::Get()) {}
641 protected:
642 friend class base::RefCountedThreadSafe<RTCPeerConnectionHandler::Observer>;
643 virtual ~Observer() {}
645 void OnSignalingChange(
646 PeerConnectionInterface::SignalingState new_state) override {
647 if (!main_thread_->BelongsToCurrentThread()) {
648 main_thread_->PostTask(FROM_HERE,
649 base::Bind(&RTCPeerConnectionHandler::Observer::OnSignalingChange,
650 this, new_state));
651 } else if (handler_) {
652 handler_->OnSignalingChange(new_state);
656 void OnAddStream(MediaStreamInterface* stream) override {
657 DCHECK(stream);
658 scoped_ptr<RemoteMediaStreamImpl> remote_stream(
659 new RemoteMediaStreamImpl(main_thread_, stream));
661 // The webkit object owned by RemoteMediaStreamImpl, will be initialized
662 // asynchronously and the posted task will execude after that initialization
663 // is done.
664 main_thread_->PostTask(FROM_HERE,
665 base::Bind(&RTCPeerConnectionHandler::Observer::OnAddStreamImpl,
666 this, base::Passed(&remote_stream)));
669 void OnRemoveStream(MediaStreamInterface* stream) override {
670 main_thread_->PostTask(FROM_HERE,
671 base::Bind(&RTCPeerConnectionHandler::Observer::OnRemoveStreamImpl,
672 this, make_scoped_refptr(stream)));
675 void OnDataChannel(DataChannelInterface* data_channel) override {
676 scoped_ptr<RtcDataChannelHandler> handler(
677 new RtcDataChannelHandler(main_thread_, data_channel));
678 main_thread_->PostTask(FROM_HERE,
679 base::Bind(&RTCPeerConnectionHandler::Observer::OnDataChannelImpl,
680 this, base::Passed(&handler)));
683 void OnRenegotiationNeeded() override {
684 if (!main_thread_->BelongsToCurrentThread()) {
685 main_thread_->PostTask(FROM_HERE,
686 base::Bind(&RTCPeerConnectionHandler::Observer::OnRenegotiationNeeded,
687 this));
688 } else if (handler_) {
689 handler_->OnRenegotiationNeeded();
693 void OnIceConnectionChange(
694 PeerConnectionInterface::IceConnectionState new_state) override {
695 if (!main_thread_->BelongsToCurrentThread()) {
696 main_thread_->PostTask(FROM_HERE,
697 base::Bind(
698 &RTCPeerConnectionHandler::Observer::OnIceConnectionChange, this,
699 new_state));
700 } else if (handler_) {
701 handler_->OnIceConnectionChange(new_state);
705 void OnIceGatheringChange(
706 PeerConnectionInterface::IceGatheringState new_state) override {
707 if (!main_thread_->BelongsToCurrentThread()) {
708 main_thread_->PostTask(FROM_HERE,
709 base::Bind(&RTCPeerConnectionHandler::Observer::OnIceGatheringChange,
710 this, new_state));
711 } else if (handler_) {
712 handler_->OnIceGatheringChange(new_state);
716 void OnIceCandidate(const IceCandidateInterface* candidate) override {
717 std::string sdp;
718 if (!candidate->ToString(&sdp)) {
719 NOTREACHED() << "OnIceCandidate: Could not get SDP string.";
720 return;
723 main_thread_->PostTask(FROM_HERE,
724 base::Bind(&RTCPeerConnectionHandler::Observer::OnIceCandidateImpl,
725 this, sdp, candidate->sdp_mid(), candidate->sdp_mline_index(),
726 candidate->candidate().component(),
727 candidate->candidate().address().family()));
730 void OnAddStreamImpl(scoped_ptr<RemoteMediaStreamImpl> stream) {
731 DCHECK(stream->webkit_stream().extraData()) << "Initialization not done";
732 if (handler_)
733 handler_->OnAddStream(stream.Pass());
736 void OnRemoveStreamImpl(const scoped_refptr<MediaStreamInterface>& stream) {
737 if (handler_)
738 handler_->OnRemoveStream(stream);
741 void OnDataChannelImpl(scoped_ptr<RtcDataChannelHandler> handler) {
742 if (handler_)
743 handler_->OnDataChannel(handler.Pass());
746 void OnIceCandidateImpl(const std::string& sdp, const std::string& sdp_mid,
747 int sdp_mline_index, int component, int address_family) {
748 if (handler_) {
749 handler_->OnIceCandidate(sdp, sdp_mid, sdp_mline_index, component,
750 address_family);
754 private:
755 const base::WeakPtr<RTCPeerConnectionHandler> handler_;
756 const scoped_refptr<base::SingleThreadTaskRunner> main_thread_;
759 RTCPeerConnectionHandler::RTCPeerConnectionHandler(
760 blink::WebRTCPeerConnectionHandlerClient* client,
761 PeerConnectionDependencyFactory* dependency_factory)
762 : client_(client),
763 dependency_factory_(dependency_factory),
764 weak_factory_(this) {
765 g_peer_connection_handlers.Get().insert(this);
768 RTCPeerConnectionHandler::~RTCPeerConnectionHandler() {
769 DCHECK(thread_checker_.CalledOnValidThread());
771 stop();
773 g_peer_connection_handlers.Get().erase(this);
774 if (peer_connection_tracker_)
775 peer_connection_tracker_->UnregisterPeerConnection(this);
776 STLDeleteValues(&remote_streams_);
778 UMA_HISTOGRAM_COUNTS_10000(
779 "WebRTC.NumDataChannelsPerPeerConnection", num_data_channels_created_);
782 // static
783 void RTCPeerConnectionHandler::DestructAllHandlers() {
784 std::set<RTCPeerConnectionHandler*> handlers(
785 g_peer_connection_handlers.Get().begin(),
786 g_peer_connection_handlers.Get().end());
787 for (auto handler : handlers) {
788 if (handler->client_)
789 handler->client_->releasePeerConnectionHandler();
793 // static
794 void RTCPeerConnectionHandler::ConvertOfferOptionsToConstraints(
795 const blink::WebRTCOfferOptions& options,
796 RTCMediaConstraints* output) {
797 output->AddMandatory(
798 webrtc::MediaConstraintsInterface::kOfferToReceiveAudio,
799 options.offerToReceiveAudio() > 0 ? "true" : "false",
800 true);
802 output->AddMandatory(
803 webrtc::MediaConstraintsInterface::kOfferToReceiveVideo,
804 options.offerToReceiveVideo() > 0 ? "true" : "false",
805 true);
807 if (!options.voiceActivityDetection()) {
808 output->AddMandatory(
809 webrtc::MediaConstraintsInterface::kVoiceActivityDetection,
810 "false",
811 true);
814 if (options.iceRestart()) {
815 output->AddMandatory(
816 webrtc::MediaConstraintsInterface::kIceRestart, "true", true);
820 void RTCPeerConnectionHandler::associateWithFrame(blink::WebFrame* frame) {
821 DCHECK(thread_checker_.CalledOnValidThread());
822 DCHECK(frame);
823 frame_ = frame;
826 bool RTCPeerConnectionHandler::initialize(
827 const blink::WebRTCConfiguration& server_configuration,
828 const blink::WebMediaConstraints& options) {
829 DCHECK(thread_checker_.CalledOnValidThread());
830 DCHECK(frame_);
832 peer_connection_tracker_ =
833 RenderThreadImpl::current()->peer_connection_tracker()->AsWeakPtr();
835 webrtc::PeerConnectionInterface::RTCConfiguration config;
836 GetNativeRtcConfiguration(server_configuration, &config);
838 RTCMediaConstraints constraints(options);
840 peer_connection_observer_ = new Observer(weak_factory_.GetWeakPtr());
841 native_peer_connection_ = dependency_factory_->CreatePeerConnection(
842 config, &constraints, frame_, peer_connection_observer_.get());
844 if (!native_peer_connection_.get()) {
845 LOG(ERROR) << "Failed to initialize native PeerConnection.";
846 return false;
849 if (peer_connection_tracker_) {
850 peer_connection_tracker_->RegisterPeerConnection(
851 this, config, constraints, frame_);
854 uma_observer_ = new rtc::RefCountedObject<PeerConnectionUMAObserver>();
855 native_peer_connection_->RegisterUMAObserver(uma_observer_.get());
856 return true;
859 bool RTCPeerConnectionHandler::InitializeForTest(
860 const blink::WebRTCConfiguration& server_configuration,
861 const blink::WebMediaConstraints& options,
862 const base::WeakPtr<PeerConnectionTracker>& peer_connection_tracker) {
863 DCHECK(thread_checker_.CalledOnValidThread());
864 webrtc::PeerConnectionInterface::RTCConfiguration config;
865 GetNativeRtcConfiguration(server_configuration, &config);
867 peer_connection_observer_ = new Observer(weak_factory_.GetWeakPtr());
868 RTCMediaConstraints constraints(options);
869 native_peer_connection_ = dependency_factory_->CreatePeerConnection(
870 config, &constraints, NULL, peer_connection_observer_.get());
871 if (!native_peer_connection_.get()) {
872 LOG(ERROR) << "Failed to initialize native PeerConnection.";
873 return false;
875 peer_connection_tracker_ = peer_connection_tracker;
876 return true;
879 void RTCPeerConnectionHandler::createOffer(
880 const blink::WebRTCSessionDescriptionRequest& request,
881 const blink::WebMediaConstraints& options) {
882 DCHECK(thread_checker_.CalledOnValidThread());
883 TRACE_EVENT0("webrtc", "RTCPeerConnectionHandler::createOffer");
885 scoped_refptr<CreateSessionDescriptionRequest> description_request(
886 new rtc::RefCountedObject<CreateSessionDescriptionRequest>(
887 base::ThreadTaskRunnerHandle::Get(), request,
888 weak_factory_.GetWeakPtr(), peer_connection_tracker_,
889 PeerConnectionTracker::ACTION_CREATE_OFFER));
891 // TODO(tommi): Do this asynchronously via e.g. PostTaskAndReply.
892 RTCMediaConstraints constraints(options);
893 native_peer_connection_->CreateOffer(description_request.get(), &constraints);
895 if (peer_connection_tracker_)
896 peer_connection_tracker_->TrackCreateOffer(this, constraints);
899 void RTCPeerConnectionHandler::createOffer(
900 const blink::WebRTCSessionDescriptionRequest& request,
901 const blink::WebRTCOfferOptions& options) {
902 DCHECK(thread_checker_.CalledOnValidThread());
903 TRACE_EVENT0("webrtc", "RTCPeerConnectionHandler::createOffer");
905 scoped_refptr<CreateSessionDescriptionRequest> description_request(
906 new rtc::RefCountedObject<CreateSessionDescriptionRequest>(
907 base::ThreadTaskRunnerHandle::Get(), request,
908 weak_factory_.GetWeakPtr(), peer_connection_tracker_,
909 PeerConnectionTracker::ACTION_CREATE_OFFER));
911 // TODO(tommi): Do this asynchronously via e.g. PostTaskAndReply.
912 RTCMediaConstraints constraints;
913 ConvertOfferOptionsToConstraints(options, &constraints);
914 native_peer_connection_->CreateOffer(description_request.get(), &constraints);
916 if (peer_connection_tracker_)
917 peer_connection_tracker_->TrackCreateOffer(this, constraints);
920 void RTCPeerConnectionHandler::createAnswer(
921 const blink::WebRTCSessionDescriptionRequest& request,
922 const blink::WebMediaConstraints& options) {
923 DCHECK(thread_checker_.CalledOnValidThread());
924 TRACE_EVENT0("webrtc", "RTCPeerConnectionHandler::createAnswer");
925 scoped_refptr<CreateSessionDescriptionRequest> description_request(
926 new rtc::RefCountedObject<CreateSessionDescriptionRequest>(
927 base::ThreadTaskRunnerHandle::Get(), request,
928 weak_factory_.GetWeakPtr(), peer_connection_tracker_,
929 PeerConnectionTracker::ACTION_CREATE_ANSWER));
930 // TODO(tommi): Do this asynchronously via e.g. PostTaskAndReply.
931 RTCMediaConstraints constraints(options);
932 native_peer_connection_->CreateAnswer(description_request.get(),
933 &constraints);
935 if (peer_connection_tracker_)
936 peer_connection_tracker_->TrackCreateAnswer(this, constraints);
939 bool IsOfferOrAnswer(const webrtc::SessionDescriptionInterface* native_desc) {
940 DCHECK(native_desc);
941 return native_desc->type() == "offer" || native_desc->type() == "answer";
944 void RTCPeerConnectionHandler::setLocalDescription(
945 const blink::WebRTCVoidRequest& request,
946 const blink::WebRTCSessionDescription& description) {
947 DCHECK(thread_checker_.CalledOnValidThread());
948 TRACE_EVENT0("webrtc", "RTCPeerConnectionHandler::setLocalDescription");
950 std::string sdp = base::UTF16ToUTF8(base::StringPiece16(description.sdp()));
951 std::string type =
952 base::UTF16ToUTF8(base::StringPiece16(description.type()));
954 webrtc::SdpParseError error;
955 // Since CreateNativeSessionDescription uses the dependency factory, we need
956 // to make this call on the current thread to be safe.
957 webrtc::SessionDescriptionInterface* native_desc =
958 CreateNativeSessionDescription(sdp, type, &error);
959 if (!native_desc) {
960 std::string reason_str = "Failed to parse SessionDescription. ";
961 reason_str.append(error.line);
962 reason_str.append(" ");
963 reason_str.append(error.description);
964 LOG(ERROR) << reason_str;
965 request.requestFailed(blink::WebString::fromUTF8(reason_str));
966 return;
969 if (peer_connection_tracker_) {
970 peer_connection_tracker_->TrackSetSessionDescription(
971 this, sdp, type, PeerConnectionTracker::SOURCE_LOCAL);
974 if (!first_local_description_ && IsOfferOrAnswer(native_desc)) {
975 first_local_description_.reset(new FirstSessionDescription(native_desc));
976 if (first_remote_description_) {
977 ReportFirstSessionDescriptions(
978 *first_local_description_,
979 *first_remote_description_);
983 scoped_refptr<SetSessionDescriptionRequest> set_request(
984 new rtc::RefCountedObject<SetSessionDescriptionRequest>(
985 base::ThreadTaskRunnerHandle::Get(), request,
986 weak_factory_.GetWeakPtr(), peer_connection_tracker_,
987 PeerConnectionTracker::ACTION_SET_LOCAL_DESCRIPTION));
989 signaling_thread()->PostTask(FROM_HERE,
990 base::Bind(&RunClosureWithTrace,
991 base::Bind(&webrtc::PeerConnectionInterface::SetLocalDescription,
992 native_peer_connection_, set_request,
993 base::Unretained(native_desc)),
994 "SetLocalDescription"));
997 void RTCPeerConnectionHandler::setRemoteDescription(
998 const blink::WebRTCVoidRequest& request,
999 const blink::WebRTCSessionDescription& description) {
1000 DCHECK(thread_checker_.CalledOnValidThread());
1001 TRACE_EVENT0("webrtc", "RTCPeerConnectionHandler::setRemoteDescription");
1002 std::string sdp = base::UTF16ToUTF8(base::StringPiece16(description.sdp()));
1003 std::string type =
1004 base::UTF16ToUTF8(base::StringPiece16(description.type()));
1006 webrtc::SdpParseError error;
1007 // Since CreateNativeSessionDescription uses the dependency factory, we need
1008 // to make this call on the current thread to be safe.
1009 webrtc::SessionDescriptionInterface* native_desc =
1010 CreateNativeSessionDescription(sdp, type, &error);
1011 if (!native_desc) {
1012 std::string reason_str = "Failed to parse SessionDescription. ";
1013 reason_str.append(error.line);
1014 reason_str.append(" ");
1015 reason_str.append(error.description);
1016 LOG(ERROR) << reason_str;
1017 request.requestFailed(blink::WebString::fromUTF8(reason_str));
1018 return;
1021 if (peer_connection_tracker_) {
1022 peer_connection_tracker_->TrackSetSessionDescription(
1023 this, sdp, type, PeerConnectionTracker::SOURCE_REMOTE);
1026 if (!first_remote_description_ && IsOfferOrAnswer(native_desc)) {
1027 first_remote_description_.reset(new FirstSessionDescription(native_desc));
1028 if (first_local_description_) {
1029 ReportFirstSessionDescriptions(
1030 *first_local_description_,
1031 *first_remote_description_);
1035 scoped_refptr<SetSessionDescriptionRequest> set_request(
1036 new rtc::RefCountedObject<SetSessionDescriptionRequest>(
1037 base::ThreadTaskRunnerHandle::Get(), request,
1038 weak_factory_.GetWeakPtr(), peer_connection_tracker_,
1039 PeerConnectionTracker::ACTION_SET_REMOTE_DESCRIPTION));
1040 signaling_thread()->PostTask(FROM_HERE,
1041 base::Bind(&RunClosureWithTrace,
1042 base::Bind(&webrtc::PeerConnectionInterface::SetRemoteDescription,
1043 native_peer_connection_, set_request,
1044 base::Unretained(native_desc)),
1045 "SetRemoteDescription"));
1048 blink::WebRTCSessionDescription
1049 RTCPeerConnectionHandler::localDescription() {
1050 DCHECK(thread_checker_.CalledOnValidThread());
1051 TRACE_EVENT0("webrtc", "RTCPeerConnectionHandler::localDescription");
1053 // Since local_description returns a pointer to a non-reference-counted object
1054 // that lives on the signaling thread, we cannot fetch a pointer to it and use
1055 // it directly here. Instead, we access the object completely on the signaling
1056 // thread.
1057 std::string sdp, type;
1058 base::Callback<const webrtc::SessionDescriptionInterface*()> description_cb =
1059 base::Bind(&webrtc::PeerConnectionInterface::local_description,
1060 native_peer_connection_);
1061 RunSynchronousClosureOnSignalingThread(
1062 base::Bind(&GetSdpAndTypeFromSessionDescription, description_cb,
1063 base::Unretained(&sdp), base::Unretained(&type)),
1064 "localDescription");
1066 return CreateWebKitSessionDescription(sdp, type);
1069 blink::WebRTCSessionDescription
1070 RTCPeerConnectionHandler::remoteDescription() {
1071 DCHECK(thread_checker_.CalledOnValidThread());
1072 TRACE_EVENT0("webrtc", "RTCPeerConnectionHandler::remoteDescription");
1073 // Since local_description returns a pointer to a non-reference-counted object
1074 // that lives on the signaling thread, we cannot fetch a pointer to it and use
1075 // it directly here. Instead, we access the object completely on the signaling
1076 // thread.
1077 std::string sdp, type;
1078 base::Callback<const webrtc::SessionDescriptionInterface*()> description_cb =
1079 base::Bind(&webrtc::PeerConnectionInterface::remote_description,
1080 native_peer_connection_);
1081 RunSynchronousClosureOnSignalingThread(
1082 base::Bind(&GetSdpAndTypeFromSessionDescription, description_cb,
1083 base::Unretained(&sdp), base::Unretained(&type)),
1084 "remoteDescription");
1086 return CreateWebKitSessionDescription(sdp, type);
1089 bool RTCPeerConnectionHandler::updateICE(
1090 const blink::WebRTCConfiguration& server_configuration,
1091 const blink::WebMediaConstraints& options) {
1092 DCHECK(thread_checker_.CalledOnValidThread());
1093 TRACE_EVENT0("webrtc", "RTCPeerConnectionHandler::updateICE");
1094 webrtc::PeerConnectionInterface::RTCConfiguration config;
1095 GetNativeRtcConfiguration(server_configuration, &config);
1096 RTCMediaConstraints constraints(options);
1098 if (peer_connection_tracker_)
1099 peer_connection_tracker_->TrackUpdateIce(this, config, constraints);
1101 return native_peer_connection_->UpdateIce(config.servers, &constraints);
1104 bool RTCPeerConnectionHandler::addICECandidate(
1105 const blink::WebRTCVoidRequest& request,
1106 const blink::WebRTCICECandidate& candidate) {
1107 DCHECK(thread_checker_.CalledOnValidThread());
1108 TRACE_EVENT0("webrtc", "RTCPeerConnectionHandler::addICECandidate");
1109 // Libjingle currently does not accept callbacks for addICECandidate.
1110 // For that reason we are going to call callbacks from here.
1112 // TODO(tommi): Instead of calling addICECandidate here, we can do a
1113 // PostTaskAndReply kind of a thing.
1114 bool result = addICECandidate(candidate);
1115 base::ThreadTaskRunnerHandle::Get()->PostTask(
1116 FROM_HERE, base::Bind(&RTCPeerConnectionHandler::OnaddICECandidateResult,
1117 weak_factory_.GetWeakPtr(), request, result));
1118 // On failure callback will be triggered.
1119 return true;
1122 bool RTCPeerConnectionHandler::addICECandidate(
1123 const blink::WebRTCICECandidate& candidate) {
1124 DCHECK(thread_checker_.CalledOnValidThread());
1125 TRACE_EVENT0("webrtc", "RTCPeerConnectionHandler::addICECandidate");
1126 scoped_ptr<webrtc::IceCandidateInterface> native_candidate(
1127 dependency_factory_->CreateIceCandidate(
1128 base::UTF16ToUTF8(base::StringPiece16(candidate.sdpMid())),
1129 candidate.sdpMLineIndex(),
1130 base::UTF16ToUTF8(base::StringPiece16(candidate.candidate()))));
1131 bool return_value = false;
1133 if (native_candidate) {
1134 return_value =
1135 native_peer_connection_->AddIceCandidate(native_candidate.get());
1136 LOG_IF(ERROR, !return_value) << "Error processing ICE candidate.";
1137 } else {
1138 LOG(ERROR) << "Could not create native ICE candidate.";
1141 if (peer_connection_tracker_) {
1142 peer_connection_tracker_->TrackAddIceCandidate(
1143 this, candidate, PeerConnectionTracker::SOURCE_REMOTE, return_value);
1145 return return_value;
1148 void RTCPeerConnectionHandler::OnaddICECandidateResult(
1149 const blink::WebRTCVoidRequest& webkit_request, bool result) {
1150 DCHECK(thread_checker_.CalledOnValidThread());
1151 TRACE_EVENT0("webrtc", "RTCPeerConnectionHandler::OnaddICECandidateResult");
1152 if (!result) {
1153 // We don't have the actual error code from the libjingle, so for now
1154 // using a generic error string.
1155 return webkit_request.requestFailed(
1156 base::UTF8ToUTF16("Error processing ICE candidate"));
1159 return webkit_request.requestSucceeded();
1162 bool RTCPeerConnectionHandler::addStream(
1163 const blink::WebMediaStream& stream,
1164 const blink::WebMediaConstraints& options) {
1165 DCHECK(thread_checker_.CalledOnValidThread());
1166 TRACE_EVENT0("webrtc", "RTCPeerConnectionHandler::addStream");
1167 for (ScopedVector<WebRtcMediaStreamAdapter>::iterator adapter_it =
1168 local_streams_.begin(); adapter_it != local_streams_.end();
1169 ++adapter_it) {
1170 if ((*adapter_it)->IsEqual(stream)) {
1171 DVLOG(1) << "RTCPeerConnectionHandler::addStream called with the same "
1172 << "stream twice. id=" << stream.id().utf8();
1173 return false;
1177 if (peer_connection_tracker_) {
1178 peer_connection_tracker_->TrackAddStream(
1179 this, stream, PeerConnectionTracker::SOURCE_LOCAL);
1182 PerSessionWebRTCAPIMetrics::GetInstance()->IncrementStreamCounter();
1184 WebRtcMediaStreamAdapter* adapter =
1185 new WebRtcMediaStreamAdapter(stream, dependency_factory_);
1186 local_streams_.push_back(adapter);
1188 webrtc::MediaStreamInterface* webrtc_stream = adapter->webrtc_media_stream();
1189 track_metrics_.AddStream(MediaStreamTrackMetrics::SENT_STREAM,
1190 webrtc_stream);
1192 RTCMediaConstraints constraints(options);
1193 if (!constraints.GetMandatory().empty() ||
1194 !constraints.GetOptional().empty()) {
1195 // TODO(perkj): |mediaConstraints| is the name of the optional constraints
1196 // argument in RTCPeerConnection.idl. It has been removed from the spec and
1197 // should be removed from blink as well.
1198 LOG(WARNING)
1199 << "mediaConstraints is not a supported argument to addStream.";
1202 return native_peer_connection_->AddStream(webrtc_stream);
1205 void RTCPeerConnectionHandler::removeStream(
1206 const blink::WebMediaStream& stream) {
1207 DCHECK(thread_checker_.CalledOnValidThread());
1208 TRACE_EVENT0("webrtc", "RTCPeerConnectionHandler::removeStream");
1209 // Find the webrtc stream.
1210 scoped_refptr<webrtc::MediaStreamInterface> webrtc_stream;
1211 for (ScopedVector<WebRtcMediaStreamAdapter>::iterator adapter_it =
1212 local_streams_.begin(); adapter_it != local_streams_.end();
1213 ++adapter_it) {
1214 if ((*adapter_it)->IsEqual(stream)) {
1215 webrtc_stream = (*adapter_it)->webrtc_media_stream();
1216 local_streams_.erase(adapter_it);
1217 break;
1220 DCHECK(webrtc_stream.get());
1221 // TODO(tommi): Make this async (PostTaskAndReply).
1222 native_peer_connection_->RemoveStream(webrtc_stream.get());
1224 if (peer_connection_tracker_) {
1225 peer_connection_tracker_->TrackRemoveStream(
1226 this, stream, PeerConnectionTracker::SOURCE_LOCAL);
1228 PerSessionWebRTCAPIMetrics::GetInstance()->DecrementStreamCounter();
1229 track_metrics_.RemoveStream(MediaStreamTrackMetrics::SENT_STREAM,
1230 webrtc_stream.get());
1233 void RTCPeerConnectionHandler::getStats(
1234 const blink::WebRTCStatsRequest& request) {
1235 DCHECK(thread_checker_.CalledOnValidThread());
1236 scoped_refptr<LocalRTCStatsRequest> inner_request(
1237 new rtc::RefCountedObject<LocalRTCStatsRequest>(request));
1238 getStats(inner_request);
1241 void RTCPeerConnectionHandler::getStats(
1242 const scoped_refptr<LocalRTCStatsRequest>& request) {
1243 DCHECK(thread_checker_.CalledOnValidThread());
1244 TRACE_EVENT0("webrtc", "RTCPeerConnectionHandler::getStats");
1247 rtc::scoped_refptr<webrtc::StatsObserver> observer(
1248 new rtc::RefCountedObject<StatsResponse>(request));
1250 std::string track_id;
1251 blink::WebMediaStreamSource::Type track_type =
1252 blink::WebMediaStreamSource::TypeAudio;
1253 if (request->hasSelector()) {
1254 track_type = request->component().source().type();
1255 track_id = request->component().id().utf8();
1258 GetStats(observer, webrtc::PeerConnectionInterface::kStatsOutputLevelStandard,
1259 track_id, track_type);
1262 // TODO(tommi): It's weird to have three {g|G}etStats methods. Clean this up.
1263 void RTCPeerConnectionHandler::GetStats(
1264 webrtc::StatsObserver* observer,
1265 webrtc::PeerConnectionInterface::StatsOutputLevel level,
1266 const std::string& track_id,
1267 blink::WebMediaStreamSource::Type track_type) {
1268 DCHECK(thread_checker_.CalledOnValidThread());
1269 signaling_thread()->PostTask(FROM_HERE,
1270 base::Bind(&GetStatsOnSignalingThread, native_peer_connection_, level,
1271 make_scoped_refptr(observer), track_id, track_type));
1274 void RTCPeerConnectionHandler::CloseClientPeerConnection() {
1275 DCHECK(thread_checker_.CalledOnValidThread());
1276 if (client_)
1277 client_->closePeerConnection();
1280 blink::WebRTCDataChannelHandler* RTCPeerConnectionHandler::createDataChannel(
1281 const blink::WebString& label, const blink::WebRTCDataChannelInit& init) {
1282 DCHECK(thread_checker_.CalledOnValidThread());
1283 TRACE_EVENT0("webrtc", "RTCPeerConnectionHandler::createDataChannel");
1284 DVLOG(1) << "createDataChannel label "
1285 << base::UTF16ToUTF8(base::StringPiece16(label));
1287 webrtc::DataChannelInit config;
1288 // TODO(jiayl): remove the deprecated reliable field once Libjingle is updated
1289 // to handle that.
1290 config.reliable = false;
1291 config.id = init.id;
1292 config.ordered = init.ordered;
1293 config.negotiated = init.negotiated;
1294 config.maxRetransmits = init.maxRetransmits;
1295 config.maxRetransmitTime = init.maxRetransmitTime;
1296 config.protocol = base::UTF16ToUTF8(base::StringPiece16(init.protocol));
1298 rtc::scoped_refptr<webrtc::DataChannelInterface> webrtc_channel(
1299 native_peer_connection_->CreateDataChannel(
1300 base::UTF16ToUTF8(base::StringPiece16(label)), &config));
1301 if (!webrtc_channel) {
1302 DLOG(ERROR) << "Could not create native data channel.";
1303 return NULL;
1305 if (peer_connection_tracker_) {
1306 peer_connection_tracker_->TrackCreateDataChannel(
1307 this, webrtc_channel.get(), PeerConnectionTracker::SOURCE_LOCAL);
1310 ++num_data_channels_created_;
1312 return new RtcDataChannelHandler(base::ThreadTaskRunnerHandle::Get(),
1313 webrtc_channel);
1316 blink::WebRTCDTMFSenderHandler* RTCPeerConnectionHandler::createDTMFSender(
1317 const blink::WebMediaStreamTrack& track) {
1318 DCHECK(thread_checker_.CalledOnValidThread());
1319 TRACE_EVENT0("webrtc", "RTCPeerConnectionHandler::createDTMFSender");
1320 DVLOG(1) << "createDTMFSender.";
1322 MediaStreamTrack* native_track = MediaStreamTrack::GetTrack(track);
1323 if (!native_track || !native_track->is_local_track() ||
1324 track.source().type() != blink::WebMediaStreamSource::TypeAudio) {
1325 DLOG(ERROR) << "The DTMF sender requires a local audio track.";
1326 return nullptr;
1329 scoped_refptr<webrtc::AudioTrackInterface> audio_track =
1330 native_track->GetAudioAdapter();
1331 rtc::scoped_refptr<webrtc::DtmfSenderInterface> sender(
1332 native_peer_connection_->CreateDtmfSender(audio_track.get()));
1333 if (!sender) {
1334 DLOG(ERROR) << "Could not create native DTMF sender.";
1335 return nullptr;
1337 if (peer_connection_tracker_)
1338 peer_connection_tracker_->TrackCreateDTMFSender(this, track);
1340 return new RtcDtmfSenderHandler(sender);
1343 void RTCPeerConnectionHandler::stop() {
1344 DCHECK(thread_checker_.CalledOnValidThread());
1345 DVLOG(1) << "RTCPeerConnectionHandler::stop";
1347 if (!client_ || !native_peer_connection_.get())
1348 return; // Already stopped.
1350 if (peer_connection_tracker_)
1351 peer_connection_tracker_->TrackStop(this);
1353 native_peer_connection_->Close();
1355 // The client_ pointer is not considered valid after this point and no further
1356 // callbacks must be made.
1357 client_ = nullptr;
1360 void RTCPeerConnectionHandler::OnSignalingChange(
1361 webrtc::PeerConnectionInterface::SignalingState new_state) {
1362 DCHECK(thread_checker_.CalledOnValidThread());
1363 TRACE_EVENT0("webrtc", "RTCPeerConnectionHandler::OnSignalingChange");
1365 blink::WebRTCPeerConnectionHandlerClient::SignalingState state =
1366 GetWebKitSignalingState(new_state);
1367 if (peer_connection_tracker_)
1368 peer_connection_tracker_->TrackSignalingStateChange(this, state);
1369 if (client_)
1370 client_->didChangeSignalingState(state);
1373 // Called any time the IceConnectionState changes
1374 void RTCPeerConnectionHandler::OnIceConnectionChange(
1375 webrtc::PeerConnectionInterface::IceConnectionState new_state) {
1376 TRACE_EVENT0("webrtc", "RTCPeerConnectionHandler::OnIceConnectionChange");
1377 DCHECK(thread_checker_.CalledOnValidThread());
1378 ReportICEState(new_state);
1379 if (new_state == webrtc::PeerConnectionInterface::kIceConnectionChecking) {
1380 ice_connection_checking_start_ = base::TimeTicks::Now();
1381 } else if (new_state ==
1382 webrtc::PeerConnectionInterface::kIceConnectionConnected) {
1383 // If the state becomes connected, send the time needed for PC to become
1384 // connected from checking to UMA. UMA data will help to know how much
1385 // time needed for PC to connect with remote peer.
1386 if (ice_connection_checking_start_.is_null()) {
1387 // From UMA, we have observed a large number of calls falling into the
1388 // overflow buckets. One possibility is that the Checking is not signaled
1389 // before Connected. This is to guard against that situation to make the
1390 // metric more robust.
1391 UMA_HISTOGRAM_MEDIUM_TIMES("WebRTC.PeerConnection.TimeToConnect",
1392 base::TimeDelta());
1393 } else {
1394 UMA_HISTOGRAM_MEDIUM_TIMES(
1395 "WebRTC.PeerConnection.TimeToConnect",
1396 base::TimeTicks::Now() - ice_connection_checking_start_);
1400 track_metrics_.IceConnectionChange(new_state);
1401 blink::WebRTCPeerConnectionHandlerClient::ICEConnectionState state =
1402 GetWebKitIceConnectionState(new_state);
1403 if (peer_connection_tracker_)
1404 peer_connection_tracker_->TrackIceConnectionStateChange(this, state);
1405 if(client_)
1406 client_->didChangeICEConnectionState(state);
1409 // Called any time the IceGatheringState changes
1410 void RTCPeerConnectionHandler::OnIceGatheringChange(
1411 webrtc::PeerConnectionInterface::IceGatheringState new_state) {
1412 DCHECK(thread_checker_.CalledOnValidThread());
1413 TRACE_EVENT0("webrtc", "RTCPeerConnectionHandler::OnIceGatheringChange");
1415 if (new_state == webrtc::PeerConnectionInterface::kIceGatheringComplete) {
1416 // If ICE gathering is completed, generate a NULL ICE candidate,
1417 // to signal end of candidates.
1418 if (client_) {
1419 blink::WebRTCICECandidate null_candidate;
1420 client_->didGenerateICECandidate(null_candidate);
1423 UMA_HISTOGRAM_COUNTS_100("WebRTC.PeerConnection.IPv4LocalCandidates",
1424 num_local_candidates_ipv4_);
1426 UMA_HISTOGRAM_COUNTS_100("WebRTC.PeerConnection.IPv6LocalCandidates",
1427 num_local_candidates_ipv6_);
1428 } else if (new_state ==
1429 webrtc::PeerConnectionInterface::kIceGatheringGathering) {
1430 // ICE restarts will change gathering state back to "gathering",
1431 // reset the counter.
1432 ResetUMAStats();
1435 blink::WebRTCPeerConnectionHandlerClient::ICEGatheringState state =
1436 GetWebKitIceGatheringState(new_state);
1437 if (peer_connection_tracker_)
1438 peer_connection_tracker_->TrackIceGatheringStateChange(this, state);
1439 if (client_)
1440 client_->didChangeICEGatheringState(state);
1443 void RTCPeerConnectionHandler::OnRenegotiationNeeded() {
1444 DCHECK(thread_checker_.CalledOnValidThread());
1445 TRACE_EVENT0("webrtc", "RTCPeerConnectionHandler::OnRenegotiationNeeded");
1446 if (peer_connection_tracker_)
1447 peer_connection_tracker_->TrackOnRenegotiationNeeded(this);
1448 if (client_)
1449 client_->negotiationNeeded();
1452 void RTCPeerConnectionHandler::OnAddStream(
1453 scoped_ptr<RemoteMediaStreamImpl> stream) {
1454 DCHECK(thread_checker_.CalledOnValidThread());
1455 DCHECK(remote_streams_.find(stream->webrtc_stream().get()) ==
1456 remote_streams_.end());
1457 DCHECK(stream->webkit_stream().extraData()) << "Initialization not done";
1458 TRACE_EVENT0("webrtc", "RTCPeerConnectionHandler::OnAddStreamImpl");
1460 // Ownership is with remote_streams_ now.
1461 RemoteMediaStreamImpl* s = stream.release();
1462 remote_streams_.insert(
1463 std::pair<webrtc::MediaStreamInterface*, RemoteMediaStreamImpl*> (
1464 s->webrtc_stream().get(), s));
1466 if (peer_connection_tracker_) {
1467 peer_connection_tracker_->TrackAddStream(
1468 this, s->webkit_stream(), PeerConnectionTracker::SOURCE_REMOTE);
1471 PerSessionWebRTCAPIMetrics::GetInstance()->IncrementStreamCounter();
1473 track_metrics_.AddStream(MediaStreamTrackMetrics::RECEIVED_STREAM,
1474 s->webrtc_stream().get());
1475 if (client_)
1476 client_->didAddRemoteStream(s->webkit_stream());
1479 void RTCPeerConnectionHandler::OnRemoveStream(
1480 const scoped_refptr<webrtc::MediaStreamInterface>& stream) {
1481 DCHECK(thread_checker_.CalledOnValidThread());
1482 TRACE_EVENT0("webrtc", "RTCPeerConnectionHandler::OnRemoveStreamImpl");
1483 RemoteStreamMap::iterator it = remote_streams_.find(stream.get());
1484 if (it == remote_streams_.end()) {
1485 NOTREACHED() << "Stream not found";
1486 return;
1489 track_metrics_.RemoveStream(MediaStreamTrackMetrics::RECEIVED_STREAM,
1490 stream.get());
1491 PerSessionWebRTCAPIMetrics::GetInstance()->DecrementStreamCounter();
1493 scoped_ptr<RemoteMediaStreamImpl> remote_stream(it->second);
1494 const blink::WebMediaStream& webkit_stream = remote_stream->webkit_stream();
1495 DCHECK(!webkit_stream.isNull());
1496 remote_streams_.erase(it);
1498 if (peer_connection_tracker_) {
1499 peer_connection_tracker_->TrackRemoveStream(
1500 this, webkit_stream, PeerConnectionTracker::SOURCE_REMOTE);
1503 if (client_)
1504 client_->didRemoveRemoteStream(webkit_stream);
1507 void RTCPeerConnectionHandler::OnDataChannel(
1508 scoped_ptr<RtcDataChannelHandler> handler) {
1509 DCHECK(thread_checker_.CalledOnValidThread());
1510 TRACE_EVENT0("webrtc", "RTCPeerConnectionHandler::OnDataChannelImpl");
1512 if (peer_connection_tracker_) {
1513 peer_connection_tracker_->TrackCreateDataChannel(
1514 this, handler->channel().get(), PeerConnectionTracker::SOURCE_REMOTE);
1517 if (client_)
1518 client_->didAddRemoteDataChannel(handler.release());
1521 void RTCPeerConnectionHandler::OnIceCandidate(
1522 const std::string& sdp, const std::string& sdp_mid, int sdp_mline_index,
1523 int component, int address_family) {
1524 DCHECK(thread_checker_.CalledOnValidThread());
1525 TRACE_EVENT0("webrtc", "RTCPeerConnectionHandler::OnIceCandidateImpl");
1526 blink::WebRTCICECandidate web_candidate;
1527 web_candidate.initialize(base::UTF8ToUTF16(sdp),
1528 base::UTF8ToUTF16(sdp_mid),
1529 sdp_mline_index);
1530 if (peer_connection_tracker_) {
1531 peer_connection_tracker_->TrackAddIceCandidate(
1532 this, web_candidate, PeerConnectionTracker::SOURCE_LOCAL, true);
1535 // Only the first m line's first component is tracked to avoid
1536 // miscounting when doing BUNDLE or rtcp mux.
1537 if (sdp_mline_index == 0 && component == 1) {
1538 if (address_family == AF_INET) {
1539 ++num_local_candidates_ipv4_;
1540 } else if (address_family == AF_INET6) {
1541 ++num_local_candidates_ipv6_;
1542 } else {
1543 NOTREACHED();
1546 if (client_)
1547 client_->didGenerateICECandidate(web_candidate);
1550 webrtc::SessionDescriptionInterface*
1551 RTCPeerConnectionHandler::CreateNativeSessionDescription(
1552 const std::string& sdp, const std::string& type,
1553 webrtc::SdpParseError* error) {
1554 webrtc::SessionDescriptionInterface* native_desc =
1555 dependency_factory_->CreateSessionDescription(type, sdp, error);
1557 LOG_IF(ERROR, !native_desc) << "Failed to create native session description."
1558 << " Type: " << type << " SDP: " << sdp;
1560 return native_desc;
1563 RTCPeerConnectionHandler::FirstSessionDescription::FirstSessionDescription(
1564 const webrtc::SessionDescriptionInterface* sdesc) {
1565 DCHECK(sdesc);
1567 for (const auto& content : sdesc->description()->contents()) {
1568 if (content.type == cricket::NS_JINGLE_RTP) {
1569 const auto* mdesc =
1570 static_cast<cricket::MediaContentDescription*>(content.description);
1571 audio = audio || (mdesc->type() == cricket::MEDIA_TYPE_AUDIO);
1572 video = video || (mdesc->type() == cricket::MEDIA_TYPE_VIDEO);
1573 rtcp_mux = rtcp_mux || mdesc->rtcp_mux();
1578 void RTCPeerConnectionHandler::ReportFirstSessionDescriptions(
1579 const FirstSessionDescription& local,
1580 const FirstSessionDescription& remote) {
1581 RtcpMux rtcp_mux = RTCP_MUX_ENABLED;
1582 if ((!local.audio && !local.video) || (!remote.audio && !remote.video)) {
1583 rtcp_mux = RTCP_MUX_NO_MEDIA;
1584 } else if (!local.rtcp_mux || !remote.rtcp_mux) {
1585 rtcp_mux = RTCP_MUX_DISABLED;
1588 UMA_HISTOGRAM_ENUMERATION(
1589 "WebRTC.PeerConnection.RtcpMux", rtcp_mux, RTCP_MUX_MAX);
1591 // TODO(pthatcher): Reports stats about whether we have audio and
1592 // video or not.
1595 scoped_refptr<base::SingleThreadTaskRunner>
1596 RTCPeerConnectionHandler::signaling_thread() const {
1597 DCHECK(thread_checker_.CalledOnValidThread());
1598 return dependency_factory_->GetWebRtcSignalingThread();
1601 void RTCPeerConnectionHandler::RunSynchronousClosureOnSignalingThread(
1602 const base::Closure& closure,
1603 const char* trace_event_name) {
1604 DCHECK(thread_checker_.CalledOnValidThread());
1605 scoped_refptr<base::SingleThreadTaskRunner> thread(signaling_thread());
1606 if (!thread.get() || thread->BelongsToCurrentThread()) {
1607 TRACE_EVENT0("webrtc", trace_event_name);
1608 closure.Run();
1609 } else {
1610 base::WaitableEvent event(false, false);
1611 thread->PostTask(FROM_HERE,
1612 base::Bind(&RunSynchronousClosure, closure,
1613 base::Unretained(trace_event_name),
1614 base::Unretained(&event)));
1615 event.Wait();
1619 void RTCPeerConnectionHandler::ReportICEState(
1620 webrtc::PeerConnectionInterface::IceConnectionState new_state) {
1621 DCHECK(thread_checker_.CalledOnValidThread());
1622 if (ice_state_seen_[new_state])
1623 return;
1624 ice_state_seen_[new_state] = true;
1625 UMA_HISTOGRAM_ENUMERATION("WebRTC.PeerConnection.ConnectionState", new_state,
1626 webrtc::PeerConnectionInterface::kIceConnectionMax);
1629 void RTCPeerConnectionHandler::ResetUMAStats() {
1630 DCHECK(thread_checker_.CalledOnValidThread());
1631 num_local_candidates_ipv6_ = 0;
1632 num_local_candidates_ipv4_ = 0;
1633 ice_connection_checking_start_ = base::TimeTicks();
1634 memset(ice_state_seen_, 0, sizeof(ice_state_seen_));
1636 } // namespace content