1 /*
2 * Copyright (C) 2012 Google Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer
12 * in the documentation and/or other materials provided with the
13 * distribution.
14 * 3. Neither the name of Google Inc. nor the names of its contributors
15 * may be used to endorse or promote products derived from this
16 * software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31 #include "config.h"
32 #include "modules/mediastream/RTCPeerConnection.h"
33
34 #include "bindings/core/v8/ArrayValue.h"
35 #include "bindings/core/v8/ExceptionMessages.h"
36 #include "bindings/core/v8/ExceptionState.h"
37 #include "core/dom/Document.h"
38 #include "core/dom/ExceptionCode.h"
39 #include "core/dom/ExecutionContext.h"
40 #include "core/frame/LocalFrame.h"
41 #include "core/html/VoidCallback.h"
42 #include "core/loader/FrameLoader.h"
43 #include "core/loader/FrameLoaderClient.h"
44 #include "modules/mediastream/MediaConstraintsImpl.h"
45 #include "modules/mediastream/MediaStreamEvent.h"
46 #include "modules/mediastream/RTCDTMFSender.h"
47 #include "modules/mediastream/RTCDataChannel.h"
48 #include "modules/mediastream/RTCDataChannelEvent.h"
49 #include "modules/mediastream/RTCErrorCallback.h"
50 #include "modules/mediastream/RTCIceCandidateEvent.h"
51 #include "modules/mediastream/RTCSessionDescription.h"
52 #include "modules/mediastream/RTCSessionDescriptionCallback.h"
53 #include "modules/mediastream/RTCSessionDescriptionRequestImpl.h"
54 #include "modules/mediastream/RTCStatsCallback.h"
55 #include "modules/mediastream/RTCStatsRequestImpl.h"
56 #include "modules/mediastream/RTCVoidRequestImpl.h"
57 #include "platform/mediastream/RTCConfiguration.h"
58 #include "platform/mediastream/RTCOfferOptions.h"
59 #include "public/platform/Platform.h"
60 #include "public/platform/WebMediaStream.h"
61 #include "public/platform/WebRTCConfiguration.h"
62 #include "public/platform/WebRTCDataChannelHandler.h"
63 #include "public/platform/WebRTCDataChannelInit.h"
64 #include "public/platform/WebRTCICECandidate.h"
65 #include "public/platform/WebRTCOfferOptions.h"
66 #include "public/platform/WebRTCSessionDescription.h"
67 #include "public/platform/WebRTCSessionDescriptionRequest.h"
68 #include "public/platform/WebRTCStatsRequest.h"
69 #include "public/platform/WebRTCVoidRequest.h"
70
71 namespace blink {
72
73 namespace {
74
throwExceptionIfSignalingStateClosed(RTCPeerConnection::SignalingState state,ExceptionState & exceptionState)75 static bool throwExceptionIfSignalingStateClosed(RTCPeerConnection::SignalingState state, ExceptionState& exceptionState)
76 {
77 if (state == RTCPeerConnection::SignalingStateClosed) {
78 exceptionState.throwDOMException(InvalidStateError, "The RTCPeerConnection's signalingState is 'closed'.");
79 return true;
80 }
81
82 return false;
83 }
84
85 } // namespace
86
parseConfiguration(const Dictionary & configuration,ExceptionState & exceptionState)87 RTCConfiguration* RTCPeerConnection::parseConfiguration(const Dictionary& configuration, ExceptionState& exceptionState)
88 {
89 if (configuration.isUndefinedOrNull())
90 return 0;
91
92 RTCIceTransports iceTransports = RTCIceTransportsAll;
93 String iceTransportsString;
94 if (DictionaryHelper::get(configuration, "iceTransports", iceTransportsString)) {
95 if (iceTransportsString == "none") {
96 iceTransports = RTCIceTransportsNone;
97 } else if (iceTransportsString == "relay") {
98 iceTransports = RTCIceTransportsRelay;
99 } else if (iceTransportsString != "all") {
100 exceptionState.throwTypeError("Malformed RTCIceTransports");
101 return 0;
102 }
103 }
104
105 ArrayValue iceServers;
106 bool ok = DictionaryHelper::get(configuration, "iceServers", iceServers);
107 if (!ok || iceServers.isUndefinedOrNull()) {
108 exceptionState.throwTypeError("Malformed RTCConfiguration");
109 return 0;
110 }
111
112 size_t numberOfServers;
113 ok = iceServers.length(numberOfServers);
114 if (!ok) {
115 exceptionState.throwTypeError("Malformed RTCConfiguration");
116 return 0;
117 }
118
119 RTCConfiguration* rtcConfiguration = RTCConfiguration::create();
120 rtcConfiguration->setIceTransports(iceTransports);
121
122 for (size_t i = 0; i < numberOfServers; ++i) {
123 Dictionary iceServer;
124 ok = iceServers.get(i, iceServer);
125 if (!ok) {
126 exceptionState.throwTypeError("Malformed RTCIceServer");
127 return 0;
128 }
129
130 Vector<String> names;
131 iceServer.getOwnPropertyNames(names);
132
133 Vector<String> urlStrings;
134 if (names.contains("urls")) {
135 if (!DictionaryHelper::get(iceServer, "urls", urlStrings) || !urlStrings.size()) {
136 String urlString;
137 if (DictionaryHelper::get(iceServer, "urls", urlString)) {
138 urlStrings.append(urlString);
139 } else {
140 exceptionState.throwTypeError("Malformed RTCIceServer");
141 return 0;
142 }
143 }
144 } else if (names.contains("url")) {
145 String urlString;
146 if (DictionaryHelper::get(iceServer, "url", urlString)) {
147 urlStrings.append(urlString);
148 } else {
149 exceptionState.throwTypeError("Malformed RTCIceServer");
150 return 0;
151 }
152 } else {
153 exceptionState.throwTypeError("Malformed RTCIceServer");
154 return 0;
155 }
156
157 String username, credential;
158 DictionaryHelper::get(iceServer, "username", username);
159 DictionaryHelper::get(iceServer, "credential", credential);
160
161 for (Vector<String>::iterator iter = urlStrings.begin(); iter != urlStrings.end(); ++iter) {
162 KURL url(KURL(), *iter);
163 if (!url.isValid() || !(url.protocolIs("turn") || url.protocolIs("turns") || url.protocolIs("stun"))) {
164 exceptionState.throwTypeError("Malformed URL");
165 return 0;
166 }
167
168 rtcConfiguration->appendServer(RTCIceServer::create(url, username, credential));
169 }
170 }
171
172 return rtcConfiguration;
173 }
174
parseOfferOptions(const Dictionary & options,ExceptionState & exceptionState)175 RTCOfferOptions* RTCPeerConnection::parseOfferOptions(const Dictionary& options, ExceptionState& exceptionState)
176 {
177 if (options.isUndefinedOrNull())
178 return 0;
179
180 Vector<String> propertyNames;
181 options.getOwnPropertyNames(propertyNames);
182
183 // Treat |options| as MediaConstraints if it is empty or has "optional" or "mandatory" properties for compatibility.
184 // TODO(jiayl): remove constraints when RTCOfferOptions reaches Stable and client code is ready.
185 if (propertyNames.isEmpty() || propertyNames.contains("optional") || propertyNames.contains("mandatory"))
186 return 0;
187
188 int32_t offerToReceiveVideo = -1;
189 int32_t offerToReceiveAudio = -1;
190 bool voiceActivityDetection = true;
191 bool iceRestart = false;
192
193 if (DictionaryHelper::get(options, "offerToReceiveVideo", offerToReceiveVideo) && offerToReceiveVideo < 0) {
194 exceptionState.throwTypeError("Invalid offerToReceiveVideo");
195 return 0;
196 }
197
198 if (DictionaryHelper::get(options, "offerToReceiveAudio", offerToReceiveAudio) && offerToReceiveAudio < 0) {
199 exceptionState.throwTypeError("Invalid offerToReceiveAudio");
200 return 0;
201 }
202
203 DictionaryHelper::get(options, "voiceActivityDetection", voiceActivityDetection);
204 DictionaryHelper::get(options, "iceRestart", iceRestart);
205
206 RTCOfferOptions* rtcOfferOptions = RTCOfferOptions::create(offerToReceiveVideo, offerToReceiveAudio, voiceActivityDetection, iceRestart);
207 return rtcOfferOptions;
208 }
209
create(ExecutionContext * context,const Dictionary & rtcConfiguration,const Dictionary & mediaConstraints,ExceptionState & exceptionState)210 RTCPeerConnection* RTCPeerConnection::create(ExecutionContext* context, const Dictionary& rtcConfiguration, const Dictionary& mediaConstraints, ExceptionState& exceptionState)
211 {
212 RTCConfiguration* configuration = parseConfiguration(rtcConfiguration, exceptionState);
213 if (exceptionState.hadException())
214 return 0;
215
216 WebMediaConstraints constraints = MediaConstraintsImpl::create(mediaConstraints, exceptionState);
217 if (exceptionState.hadException())
218 return 0;
219
220 RTCPeerConnection* peerConnection = adoptRefCountedGarbageCollectedWillBeNoop(new RTCPeerConnection(context, configuration, constraints, exceptionState));
221 peerConnection->suspendIfNeeded();
222 if (exceptionState.hadException())
223 return 0;
224
225 return peerConnection;
226 }
227
RTCPeerConnection(ExecutionContext * context,RTCConfiguration * configuration,WebMediaConstraints constraints,ExceptionState & exceptionState)228 RTCPeerConnection::RTCPeerConnection(ExecutionContext* context, RTCConfiguration* configuration, WebMediaConstraints constraints, ExceptionState& exceptionState)
229 : ActiveDOMObject(context)
230 , m_signalingState(SignalingStateStable)
231 , m_iceGatheringState(ICEGatheringStateNew)
232 , m_iceConnectionState(ICEConnectionStateNew)
233 , m_dispatchScheduledEventRunner(this, &RTCPeerConnection::dispatchScheduledEvent)
234 , m_stopped(false)
235 , m_closed(false)
236 {
237 Document* document = toDocument(executionContext());
238
239 // If we fail, set |m_closed| and |m_stopped| to true, to avoid hitting the assert in the destructor.
240
241 if (!document->frame()) {
242 m_closed = true;
243 m_stopped = true;
244 exceptionState.throwDOMException(NotSupportedError, "PeerConnections may not be created in detached documents.");
245 return;
246 }
247
248 m_peerHandler = adoptPtr(Platform::current()->createRTCPeerConnectionHandler(this));
249 if (!m_peerHandler) {
250 m_closed = true;
251 m_stopped = true;
252 exceptionState.throwDOMException(NotSupportedError, "No PeerConnection handler can be created, perhaps WebRTC is disabled?");
253 return;
254 }
255
256 document->frame()->loader().client()->dispatchWillStartUsingPeerConnectionHandler(m_peerHandler.get());
257
258 if (!m_peerHandler->initialize(configuration, constraints)) {
259 m_closed = true;
260 m_stopped = true;
261 exceptionState.throwDOMException(NotSupportedError, "Failed to initialize native PeerConnection.");
262 return;
263 }
264 }
265
~RTCPeerConnection()266 RTCPeerConnection::~RTCPeerConnection()
267 {
268 // This checks that close() or stop() is called before the destructor.
269 // We are assuming that a wrapper is always created when RTCPeerConnection is created.
270 ASSERT(m_closed || m_stopped);
271 }
272
createOffer(RTCSessionDescriptionCallback * successCallback,RTCErrorCallback * errorCallback,const Dictionary & rtcOfferOptions,ExceptionState & exceptionState)273 void RTCPeerConnection::createOffer(RTCSessionDescriptionCallback* successCallback, RTCErrorCallback* errorCallback, const Dictionary& rtcOfferOptions, ExceptionState& exceptionState)
274 {
275 if (throwExceptionIfSignalingStateClosed(m_signalingState, exceptionState))
276 return;
277
278 ASSERT(successCallback);
279
280 RTCOfferOptions* offerOptions = parseOfferOptions(rtcOfferOptions, exceptionState);
281 if (exceptionState.hadException())
282 return;
283
284 RTCSessionDescriptionRequest* request = RTCSessionDescriptionRequestImpl::create(executionContext(), this, successCallback, errorCallback);
285
286 if (offerOptions) {
287 m_peerHandler->createOffer(request, offerOptions);
288 } else {
289 WebMediaConstraints constraints = MediaConstraintsImpl::create(rtcOfferOptions, exceptionState);
290 if (exceptionState.hadException())
291 return;
292
293 m_peerHandler->createOffer(request, constraints);
294 }
295 }
296
createAnswer(RTCSessionDescriptionCallback * successCallback,RTCErrorCallback * errorCallback,const Dictionary & mediaConstraints,ExceptionState & exceptionState)297 void RTCPeerConnection::createAnswer(RTCSessionDescriptionCallback* successCallback, RTCErrorCallback* errorCallback, const Dictionary& mediaConstraints, ExceptionState& exceptionState)
298 {
299 if (throwExceptionIfSignalingStateClosed(m_signalingState, exceptionState))
300 return;
301
302 ASSERT(successCallback);
303
304 WebMediaConstraints constraints = MediaConstraintsImpl::create(mediaConstraints, exceptionState);
305 if (exceptionState.hadException())
306 return;
307
308 RTCSessionDescriptionRequest* request = RTCSessionDescriptionRequestImpl::create(executionContext(), this, successCallback, errorCallback);
309 m_peerHandler->createAnswer(request, constraints);
310 }
311
setLocalDescription(RTCSessionDescription * sessionDescription,VoidCallback * successCallback,RTCErrorCallback * errorCallback,ExceptionState & exceptionState)312 void RTCPeerConnection::setLocalDescription(RTCSessionDescription* sessionDescription, VoidCallback* successCallback, RTCErrorCallback* errorCallback, ExceptionState& exceptionState)
313 {
314 if (throwExceptionIfSignalingStateClosed(m_signalingState, exceptionState))
315 return;
316
317 if (!sessionDescription) {
318 exceptionState.throwDOMException(TypeMismatchError, ExceptionMessages::argumentNullOrIncorrectType(1, "RTCSessionDescription"));
319 return;
320 }
321
322 RTCVoidRequest* request = RTCVoidRequestImpl::create(executionContext(), this, successCallback, errorCallback);
323 m_peerHandler->setLocalDescription(request, sessionDescription->webSessionDescription());
324 }
325
localDescription(ExceptionState & exceptionState)326 RTCSessionDescription* RTCPeerConnection::localDescription(ExceptionState& exceptionState)
327 {
328 WebRTCSessionDescription webSessionDescription = m_peerHandler->localDescription();
329 if (webSessionDescription.isNull())
330 return nullptr;
331
332 return RTCSessionDescription::create(webSessionDescription);
333 }
334
setRemoteDescription(RTCSessionDescription * sessionDescription,VoidCallback * successCallback,RTCErrorCallback * errorCallback,ExceptionState & exceptionState)335 void RTCPeerConnection::setRemoteDescription(RTCSessionDescription* sessionDescription, VoidCallback* successCallback, RTCErrorCallback* errorCallback, ExceptionState& exceptionState)
336 {
337 if (throwExceptionIfSignalingStateClosed(m_signalingState, exceptionState))
338 return;
339
340 if (!sessionDescription) {
341 exceptionState.throwDOMException(TypeMismatchError, ExceptionMessages::argumentNullOrIncorrectType(1, "RTCSessionDescription"));
342 return;
343 }
344
345 RTCVoidRequest* request = RTCVoidRequestImpl::create(executionContext(), this, successCallback, errorCallback);
346 m_peerHandler->setRemoteDescription(request, sessionDescription->webSessionDescription());
347 }
348
remoteDescription(ExceptionState & exceptionState)349 RTCSessionDescription* RTCPeerConnection::remoteDescription(ExceptionState& exceptionState)
350 {
351 WebRTCSessionDescription webSessionDescription = m_peerHandler->remoteDescription();
352 if (webSessionDescription.isNull())
353 return nullptr;
354
355 return RTCSessionDescription::create(webSessionDescription);
356 }
357
updateIce(const Dictionary & rtcConfiguration,const Dictionary & mediaConstraints,ExceptionState & exceptionState)358 void RTCPeerConnection::updateIce(const Dictionary& rtcConfiguration, const Dictionary& mediaConstraints, ExceptionState& exceptionState)
359 {
360 if (throwExceptionIfSignalingStateClosed(m_signalingState, exceptionState))
361 return;
362
363 RTCConfiguration* configuration = parseConfiguration(rtcConfiguration, exceptionState);
364 if (exceptionState.hadException())
365 return;
366
367 WebMediaConstraints constraints = MediaConstraintsImpl::create(mediaConstraints, exceptionState);
368 if (exceptionState.hadException())
369 return;
370
371 bool valid = m_peerHandler->updateICE(configuration, constraints);
372 if (!valid)
373 exceptionState.throwDOMException(SyntaxError, "Could not update the ICE Agent with the given configuration.");
374 }
375
addIceCandidate(RTCIceCandidate * iceCandidate,ExceptionState & exceptionState)376 void RTCPeerConnection::addIceCandidate(RTCIceCandidate* iceCandidate, ExceptionState& exceptionState)
377 {
378 if (throwExceptionIfSignalingStateClosed(m_signalingState, exceptionState))
379 return;
380
381 if (!iceCandidate) {
382 exceptionState.throwDOMException(TypeMismatchError, ExceptionMessages::argumentNullOrIncorrectType(1, "RTCIceCandidate"));
383 return;
384 }
385
386 bool valid = m_peerHandler->addICECandidate(iceCandidate->webCandidate());
387 if (!valid)
388 exceptionState.throwDOMException(SyntaxError, "The ICE candidate could not be added.");
389 }
390
addIceCandidate(RTCIceCandidate * iceCandidate,VoidCallback * successCallback,RTCErrorCallback * errorCallback,ExceptionState & exceptionState)391 void RTCPeerConnection::addIceCandidate(RTCIceCandidate* iceCandidate, VoidCallback* successCallback, RTCErrorCallback* errorCallback, ExceptionState& exceptionState)
392 {
393 if (throwExceptionIfSignalingStateClosed(m_signalingState, exceptionState))
394 return;
395
396 if (!iceCandidate) {
397 exceptionState.throwDOMException(TypeMismatchError, ExceptionMessages::argumentNullOrIncorrectType(1, "RTCIceCandidate"));
398 return;
399 }
400 ASSERT(successCallback);
401 ASSERT(errorCallback);
402
403 RTCVoidRequest* request = RTCVoidRequestImpl::create(executionContext(), this, successCallback, errorCallback);
404
405 bool implemented = m_peerHandler->addICECandidate(request, iceCandidate->webCandidate());
406 if (!implemented) {
407 exceptionState.throwDOMException(NotSupportedError, "This method is not yet implemented.");
408 }
409 }
410
signalingState() const411 String RTCPeerConnection::signalingState() const
412 {
413 switch (m_signalingState) {
414 case SignalingStateStable:
415 return "stable";
416 case SignalingStateHaveLocalOffer:
417 return "have-local-offer";
418 case SignalingStateHaveRemoteOffer:
419 return "have-remote-offer";
420 case SignalingStateHaveLocalPrAnswer:
421 return "have-local-pranswer";
422 case SignalingStateHaveRemotePrAnswer:
423 return "have-remote-pranswer";
424 case SignalingStateClosed:
425 return "closed";
426 }
427
428 ASSERT_NOT_REACHED();
429 return String();
430 }
431
iceGatheringState() const432 String RTCPeerConnection::iceGatheringState() const
433 {
434 switch (m_iceGatheringState) {
435 case ICEGatheringStateNew:
436 return "new";
437 case ICEGatheringStateGathering:
438 return "gathering";
439 case ICEGatheringStateComplete:
440 return "complete";
441 }
442
443 ASSERT_NOT_REACHED();
444 return String();
445 }
446
iceConnectionState() const447 String RTCPeerConnection::iceConnectionState() const
448 {
449 switch (m_iceConnectionState) {
450 case ICEConnectionStateNew:
451 return "new";
452 case ICEConnectionStateChecking:
453 return "checking";
454 case ICEConnectionStateConnected:
455 return "connected";
456 case ICEConnectionStateCompleted:
457 return "completed";
458 case ICEConnectionStateFailed:
459 return "failed";
460 case ICEConnectionStateDisconnected:
461 return "disconnected";
462 case ICEConnectionStateClosed:
463 return "closed";
464 }
465
466 ASSERT_NOT_REACHED();
467 return String();
468 }
469
addStream(MediaStream * stream,const Dictionary & mediaConstraints,ExceptionState & exceptionState)470 void RTCPeerConnection::addStream(MediaStream* stream, const Dictionary& mediaConstraints, ExceptionState& exceptionState)
471 {
472 if (throwExceptionIfSignalingStateClosed(m_signalingState, exceptionState))
473 return;
474
475 if (!stream) {
476 exceptionState.throwDOMException(TypeMismatchError, ExceptionMessages::argumentNullOrIncorrectType(1, "MediaStream"));
477 return;
478 }
479
480 if (m_localStreams.contains(stream))
481 return;
482
483 WebMediaConstraints constraints = MediaConstraintsImpl::create(mediaConstraints, exceptionState);
484 if (exceptionState.hadException())
485 return;
486
487 m_localStreams.append(stream);
488
489 bool valid = m_peerHandler->addStream(stream->descriptor(), constraints);
490 if (!valid)
491 exceptionState.throwDOMException(SyntaxError, "Unable to add the provided stream.");
492 }
493
removeStream(MediaStream * stream,ExceptionState & exceptionState)494 void RTCPeerConnection::removeStream(MediaStream* stream, ExceptionState& exceptionState)
495 {
496 if (throwExceptionIfSignalingStateClosed(m_signalingState, exceptionState))
497 return;
498
499 if (!stream) {
500 exceptionState.throwDOMException(TypeMismatchError, ExceptionMessages::argumentNullOrIncorrectType(1, "MediaStream"));
501 return;
502 }
503
504 size_t pos = m_localStreams.find(stream);
505 if (pos == kNotFound)
506 return;
507
508 m_localStreams.remove(pos);
509
510 m_peerHandler->removeStream(stream->descriptor());
511 }
512
getLocalStreams() const513 MediaStreamVector RTCPeerConnection::getLocalStreams() const
514 {
515 return m_localStreams;
516 }
517
getRemoteStreams() const518 MediaStreamVector RTCPeerConnection::getRemoteStreams() const
519 {
520 return m_remoteStreams;
521 }
522
getStreamById(const String & streamId)523 MediaStream* RTCPeerConnection::getStreamById(const String& streamId)
524 {
525 for (MediaStreamVector::iterator iter = m_localStreams.begin(); iter != m_localStreams.end(); ++iter) {
526 if ((*iter)->id() == streamId)
527 return iter->get();
528 }
529
530 for (MediaStreamVector::iterator iter = m_remoteStreams.begin(); iter != m_remoteStreams.end(); ++iter) {
531 if ((*iter)->id() == streamId)
532 return iter->get();
533 }
534
535 return 0;
536 }
537
getStats(RTCStatsCallback * successCallback,MediaStreamTrack * selector)538 void RTCPeerConnection::getStats(RTCStatsCallback* successCallback, MediaStreamTrack* selector)
539 {
540 RTCStatsRequest* statsRequest = RTCStatsRequestImpl::create(executionContext(), this, successCallback, selector);
541 // FIXME: Add passing selector as part of the statsRequest.
542 m_peerHandler->getStats(statsRequest);
543 }
544
createDataChannel(String label,const Dictionary & options,ExceptionState & exceptionState)545 RTCDataChannel* RTCPeerConnection::createDataChannel(String label, const Dictionary& options, ExceptionState& exceptionState)
546 {
547 if (throwExceptionIfSignalingStateClosed(m_signalingState, exceptionState))
548 return nullptr;
549
550 WebRTCDataChannelInit init;
551 DictionaryHelper::get(options, "ordered", init.ordered);
552 DictionaryHelper::get(options, "negotiated", init.negotiated);
553
554 unsigned short value = 0;
555 if (DictionaryHelper::get(options, "id", value))
556 init.id = value;
557 if (DictionaryHelper::get(options, "maxRetransmits", value))
558 init.maxRetransmits = value;
559 if (DictionaryHelper::get(options, "maxRetransmitTime", value))
560 init.maxRetransmitTime = value;
561
562 String protocolString;
563 DictionaryHelper::get(options, "protocol", protocolString);
564 init.protocol = protocolString;
565
566 RTCDataChannel* channel = RTCDataChannel::create(executionContext(), this, m_peerHandler.get(), label, init, exceptionState);
567 if (exceptionState.hadException())
568 return nullptr;
569 m_dataChannels.append(channel);
570 return channel;
571 }
572
hasLocalStreamWithTrackId(const String & trackId)573 bool RTCPeerConnection::hasLocalStreamWithTrackId(const String& trackId)
574 {
575 for (MediaStreamVector::iterator iter = m_localStreams.begin(); iter != m_localStreams.end(); ++iter) {
576 if ((*iter)->getTrackById(trackId))
577 return true;
578 }
579 return false;
580 }
581
createDTMFSender(MediaStreamTrack * track,ExceptionState & exceptionState)582 RTCDTMFSender* RTCPeerConnection::createDTMFSender(MediaStreamTrack* track, ExceptionState& exceptionState)
583 {
584 if (throwExceptionIfSignalingStateClosed(m_signalingState, exceptionState))
585 return nullptr;
586
587 if (!track) {
588 exceptionState.throwTypeError(ExceptionMessages::argumentNullOrIncorrectType(1, "MediaStreamTrack"));
589 return nullptr;
590 }
591
592 if (!hasLocalStreamWithTrackId(track->id())) {
593 exceptionState.throwDOMException(SyntaxError, "No local stream is available for the track provided.");
594 return nullptr;
595 }
596
597 RTCDTMFSender* dtmfSender = RTCDTMFSender::create(executionContext(), m_peerHandler.get(), track, exceptionState);
598 if (exceptionState.hadException())
599 return nullptr;
600 return dtmfSender;
601 }
602
close(ExceptionState & exceptionState)603 void RTCPeerConnection::close(ExceptionState& exceptionState)
604 {
605 if (throwExceptionIfSignalingStateClosed(m_signalingState, exceptionState))
606 return;
607
608 closeInternal();
609 }
610
negotiationNeeded()611 void RTCPeerConnection::negotiationNeeded()
612 {
613 ASSERT(!m_closed);
614 scheduleDispatchEvent(Event::create(EventTypeNames::negotiationneeded));
615 }
616
didGenerateICECandidate(const WebRTCICECandidate & webCandidate)617 void RTCPeerConnection::didGenerateICECandidate(const WebRTCICECandidate& webCandidate)
618 {
619 ASSERT(!m_closed);
620 ASSERT(executionContext()->isContextThread());
621 if (webCandidate.isNull())
622 scheduleDispatchEvent(RTCIceCandidateEvent::create(false, false, nullptr));
623 else {
624 RTCIceCandidate* iceCandidate = RTCIceCandidate::create(webCandidate);
625 scheduleDispatchEvent(RTCIceCandidateEvent::create(false, false, iceCandidate));
626 }
627 }
628
didChangeSignalingState(SignalingState newState)629 void RTCPeerConnection::didChangeSignalingState(SignalingState newState)
630 {
631 ASSERT(!m_closed);
632 ASSERT(executionContext()->isContextThread());
633 changeSignalingState(newState);
634 }
635
didChangeICEGatheringState(ICEGatheringState newState)636 void RTCPeerConnection::didChangeICEGatheringState(ICEGatheringState newState)
637 {
638 ASSERT(!m_closed);
639 ASSERT(executionContext()->isContextThread());
640 changeIceGatheringState(newState);
641 }
642
didChangeICEConnectionState(ICEConnectionState newState)643 void RTCPeerConnection::didChangeICEConnectionState(ICEConnectionState newState)
644 {
645 ASSERT(!m_closed);
646 ASSERT(executionContext()->isContextThread());
647 changeIceConnectionState(newState);
648 }
649
didAddRemoteStream(const WebMediaStream & remoteStream)650 void RTCPeerConnection::didAddRemoteStream(const WebMediaStream& remoteStream)
651 {
652 ASSERT(!m_closed);
653 ASSERT(executionContext()->isContextThread());
654
655 if (m_signalingState == SignalingStateClosed)
656 return;
657
658 MediaStream* stream = MediaStream::create(executionContext(), remoteStream);
659 m_remoteStreams.append(stream);
660
661 scheduleDispatchEvent(MediaStreamEvent::create(EventTypeNames::addstream, false, false, stream));
662 }
663
didRemoveRemoteStream(const WebMediaStream & remoteStream)664 void RTCPeerConnection::didRemoveRemoteStream(const WebMediaStream& remoteStream)
665 {
666 ASSERT(!m_closed);
667 ASSERT(executionContext()->isContextThread());
668
669 MediaStreamDescriptor* streamDescriptor = remoteStream;
670 ASSERT(streamDescriptor->client());
671
672 MediaStream* stream = static_cast<MediaStream*>(streamDescriptor->client());
673 stream->streamEnded();
674
675 if (m_signalingState == SignalingStateClosed)
676 return;
677
678 size_t pos = m_remoteStreams.find(stream);
679 ASSERT(pos != kNotFound);
680 m_remoteStreams.remove(pos);
681
682 scheduleDispatchEvent(MediaStreamEvent::create(EventTypeNames::removestream, false, false, stream));
683 }
684
didAddRemoteDataChannel(WebRTCDataChannelHandler * handler)685 void RTCPeerConnection::didAddRemoteDataChannel(WebRTCDataChannelHandler* handler)
686 {
687 ASSERT(!m_closed);
688 ASSERT(executionContext()->isContextThread());
689
690 if (m_signalingState == SignalingStateClosed)
691 return;
692
693 RTCDataChannel* channel = RTCDataChannel::create(executionContext(), this, adoptPtr(handler));
694 m_dataChannels.append(channel);
695
696 scheduleDispatchEvent(RTCDataChannelEvent::create(EventTypeNames::datachannel, false, false, channel));
697 }
698
releasePeerConnectionHandler()699 void RTCPeerConnection::releasePeerConnectionHandler()
700 {
701 stop();
702 }
703
closePeerConnection()704 void RTCPeerConnection::closePeerConnection()
705 {
706 ASSERT(m_signalingState != RTCPeerConnection::SignalingStateClosed);
707 closeInternal();
708 }
709
interfaceName() const710 const AtomicString& RTCPeerConnection::interfaceName() const
711 {
712 return EventTargetNames::RTCPeerConnection;
713 }
714
executionContext() const715 ExecutionContext* RTCPeerConnection::executionContext() const
716 {
717 return ActiveDOMObject::executionContext();
718 }
719
suspend()720 void RTCPeerConnection::suspend()
721 {
722 m_dispatchScheduledEventRunner.suspend();
723 }
724
resume()725 void RTCPeerConnection::resume()
726 {
727 m_dispatchScheduledEventRunner.resume();
728 }
729
stop()730 void RTCPeerConnection::stop()
731 {
732 if (m_stopped)
733 return;
734
735 m_stopped = true;
736 m_iceConnectionState = ICEConnectionStateClosed;
737 m_signalingState = SignalingStateClosed;
738
739 HeapVector<Member<RTCDataChannel> >::iterator i = m_dataChannels.begin();
740 for (; i != m_dataChannels.end(); ++i)
741 (*i)->stop();
742 m_dataChannels.clear();
743
744 m_dispatchScheduledEventRunner.stop();
745
746 m_peerHandler.clear();
747 }
748
changeSignalingState(SignalingState signalingState)749 void RTCPeerConnection::changeSignalingState(SignalingState signalingState)
750 {
751 if (m_signalingState != SignalingStateClosed && m_signalingState != signalingState) {
752 m_signalingState = signalingState;
753 scheduleDispatchEvent(Event::create(EventTypeNames::signalingstatechange));
754 }
755 }
756
changeIceGatheringState(ICEGatheringState iceGatheringState)757 void RTCPeerConnection::changeIceGatheringState(ICEGatheringState iceGatheringState)
758 {
759 m_iceGatheringState = iceGatheringState;
760 }
761
changeIceConnectionState(ICEConnectionState iceConnectionState)762 void RTCPeerConnection::changeIceConnectionState(ICEConnectionState iceConnectionState)
763 {
764 if (m_iceConnectionState != ICEConnectionStateClosed && m_iceConnectionState != iceConnectionState) {
765 m_iceConnectionState = iceConnectionState;
766 scheduleDispatchEvent(Event::create(EventTypeNames::iceconnectionstatechange));
767 }
768 }
769
closeInternal()770 void RTCPeerConnection::closeInternal()
771 {
772 ASSERT(m_signalingState != RTCPeerConnection::SignalingStateClosed);
773 m_peerHandler->stop();
774 m_closed = true;
775
776 changeIceConnectionState(ICEConnectionStateClosed);
777 changeIceGatheringState(ICEGatheringStateComplete);
778 changeSignalingState(SignalingStateClosed);
779 }
780
scheduleDispatchEvent(PassRefPtrWillBeRawPtr<Event> event)781 void RTCPeerConnection::scheduleDispatchEvent(PassRefPtrWillBeRawPtr<Event> event)
782 {
783 m_scheduledEvents.append(event);
784
785 m_dispatchScheduledEventRunner.runAsync();
786 }
787
dispatchScheduledEvent()788 void RTCPeerConnection::dispatchScheduledEvent()
789 {
790 if (m_stopped)
791 return;
792
793 WillBeHeapVector<RefPtrWillBeMember<Event> > events;
794 events.swap(m_scheduledEvents);
795
796 WillBeHeapVector<RefPtrWillBeMember<Event> >::iterator it = events.begin();
797 for (; it != events.end(); ++it)
798 dispatchEvent((*it).release());
799
800 events.clear();
801 }
802
trace(Visitor * visitor)803 void RTCPeerConnection::trace(Visitor* visitor)
804 {
805 visitor->trace(m_localStreams);
806 visitor->trace(m_remoteStreams);
807 visitor->trace(m_dataChannels);
808 #if ENABLE(OILPAN)
809 visitor->trace(m_scheduledEvents);
810 #endif
811 EventTargetWithInlineData::trace(visitor);
812 }
813
814 } // namespace blink
815