• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
33 #include "modules/mediastream/RTCPeerConnection.h"
34 
35 #include "bindings/v8/ArrayValue.h"
36 #include "bindings/v8/ExceptionMessages.h"
37 #include "bindings/v8/ExceptionState.h"
38 #include "core/dom/Document.h"
39 #include "core/dom/ExceptionCode.h"
40 #include "core/dom/ExecutionContext.h"
41 #include "core/frame/LocalFrame.h"
42 #include "core/html/VoidCallback.h"
43 #include "core/loader/FrameLoader.h"
44 #include "core/loader/FrameLoaderClient.h"
45 #include "modules/mediastream/MediaConstraintsImpl.h"
46 #include "modules/mediastream/MediaStreamEvent.h"
47 #include "modules/mediastream/RTCDTMFSender.h"
48 #include "modules/mediastream/RTCDataChannel.h"
49 #include "modules/mediastream/RTCDataChannelEvent.h"
50 #include "modules/mediastream/RTCErrorCallback.h"
51 #include "modules/mediastream/RTCIceCandidateEvent.h"
52 #include "modules/mediastream/RTCSessionDescription.h"
53 #include "modules/mediastream/RTCSessionDescriptionCallback.h"
54 #include "modules/mediastream/RTCSessionDescriptionRequestImpl.h"
55 #include "modules/mediastream/RTCStatsCallback.h"
56 #include "modules/mediastream/RTCStatsRequestImpl.h"
57 #include "modules/mediastream/RTCVoidRequestImpl.h"
58 #include "platform/mediastream/RTCConfiguration.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/WebRTCSessionDescription.h"
66 #include "public/platform/WebRTCSessionDescriptionRequest.h"
67 #include "public/platform/WebRTCStatsRequest.h"
68 #include "public/platform/WebRTCVoidRequest.h"
69 
70 namespace WebCore {
71 
72 namespace {
73 
throwExceptionIfSignalingStateClosed(RTCPeerConnection::SignalingState state,ExceptionState & exceptionState)74 static bool throwExceptionIfSignalingStateClosed(RTCPeerConnection::SignalingState state, ExceptionState& exceptionState)
75 {
76     if (state == RTCPeerConnection::SignalingStateClosed) {
77         exceptionState.throwDOMException(InvalidStateError, "The RTCPeerConnection's signalingState is 'closed'.");
78         return true;
79     }
80 
81     return false;
82 }
83 
84 } // namespace
85 
parseConfiguration(const Dictionary & configuration,ExceptionState & exceptionState)86 PassRefPtr<RTCConfiguration> RTCPeerConnection::parseConfiguration(const Dictionary& configuration, ExceptionState& exceptionState)
87 {
88     if (configuration.isUndefinedOrNull())
89         return nullptr;
90 
91     ArrayValue iceServers;
92     bool ok = configuration.get("iceServers", iceServers);
93     if (!ok || iceServers.isUndefinedOrNull()) {
94         exceptionState.throwTypeError("Malformed RTCConfiguration");
95         return nullptr;
96     }
97 
98     size_t numberOfServers;
99     ok = iceServers.length(numberOfServers);
100     if (!ok) {
101         exceptionState.throwTypeError("Malformed RTCConfiguration");
102         return nullptr;
103     }
104 
105     RefPtr<RTCConfiguration> rtcConfiguration = RTCConfiguration::create();
106 
107     for (size_t i = 0; i < numberOfServers; ++i) {
108         Dictionary iceServer;
109         ok = iceServers.get(i, iceServer);
110         if (!ok) {
111             exceptionState.throwTypeError("Malformed RTCIceServer");
112             return nullptr;
113         }
114 
115         Vector<String> names;
116         iceServer.getOwnPropertyNames(names);
117 
118         Vector<String> urlStrings;
119         if (names.contains("urls")) {
120             if (!iceServer.get("urls", urlStrings) || !urlStrings.size()) {
121                 String urlString;
122                 if (iceServer.get("urls", urlString)) {
123                     urlStrings.append(urlString);
124                 } else {
125                     exceptionState.throwTypeError("Malformed RTCIceServer");
126                     return nullptr;
127                 }
128             }
129         } else if (names.contains("url")) {
130             String urlString;
131             if (iceServer.get("url", urlString)) {
132                 urlStrings.append(urlString);
133             } else {
134                 exceptionState.throwTypeError("Malformed RTCIceServer");
135                 return nullptr;
136             }
137         } else {
138             exceptionState.throwTypeError("Malformed RTCIceServer");
139             return nullptr;
140         }
141 
142         String username, credential;
143         iceServer.get("username", username);
144         iceServer.get("credential", credential);
145 
146         for (Vector<String>::iterator iter = urlStrings.begin(); iter != urlStrings.end(); ++iter) {
147             KURL url(KURL(), *iter);
148             if (!url.isValid() || !(url.protocolIs("turn") || url.protocolIs("turns") || url.protocolIs("stun"))) {
149                 exceptionState.throwTypeError("Malformed URL");
150                 return nullptr;
151             }
152 
153             rtcConfiguration->appendServer(RTCIceServer::create(url, username, credential));
154         }
155     }
156 
157     return rtcConfiguration.release();
158 }
159 
create(ExecutionContext * context,const Dictionary & rtcConfiguration,const Dictionary & mediaConstraints,ExceptionState & exceptionState)160 PassRefPtrWillBeRawPtr<RTCPeerConnection> RTCPeerConnection::create(ExecutionContext* context, const Dictionary& rtcConfiguration, const Dictionary& mediaConstraints, ExceptionState& exceptionState)
161 {
162     RefPtr<RTCConfiguration> configuration = parseConfiguration(rtcConfiguration, exceptionState);
163     if (exceptionState.hadException())
164         return nullptr;
165 
166     blink::WebMediaConstraints constraints = MediaConstraintsImpl::create(mediaConstraints, exceptionState);
167     if (exceptionState.hadException())
168         return nullptr;
169 
170     RefPtrWillBeRawPtr<RTCPeerConnection> peerConnection = adoptRefWillBeRefCountedGarbageCollected(new RTCPeerConnection(context, configuration.release(), constraints, exceptionState));
171     peerConnection->suspendIfNeeded();
172     if (exceptionState.hadException())
173         return nullptr;
174 
175     return peerConnection.release();
176 }
177 
RTCPeerConnection(ExecutionContext * context,PassRefPtr<RTCConfiguration> configuration,blink::WebMediaConstraints constraints,ExceptionState & exceptionState)178 RTCPeerConnection::RTCPeerConnection(ExecutionContext* context, PassRefPtr<RTCConfiguration> configuration, blink::WebMediaConstraints constraints, ExceptionState& exceptionState)
179     : ActiveDOMObject(context)
180     , m_signalingState(SignalingStateStable)
181     , m_iceGatheringState(ICEGatheringStateNew)
182     , m_iceConnectionState(ICEConnectionStateNew)
183     , m_dispatchScheduledEventRunner(this, &RTCPeerConnection::dispatchScheduledEvent)
184     , m_stopped(false)
185     , m_closed(false)
186 {
187     ScriptWrappable::init(this);
188     Document* document = toDocument(executionContext());
189 
190     // If we fail, set |m_closed| and |m_stopped| to true, to avoid hitting the assert in the destructor.
191 
192     if (!document->frame()) {
193         m_closed = true;
194         m_stopped = true;
195         exceptionState.throwDOMException(NotSupportedError, "PeerConnections may not be created in detached documents.");
196         return;
197     }
198 
199     m_peerHandler = adoptPtr(blink::Platform::current()->createRTCPeerConnectionHandler(this));
200     if (!m_peerHandler) {
201         m_closed = true;
202         m_stopped = true;
203         exceptionState.throwDOMException(NotSupportedError, "No PeerConnection handler can be created, perhaps WebRTC is disabled?");
204         return;
205     }
206 
207     document->frame()->loader().client()->dispatchWillStartUsingPeerConnectionHandler(m_peerHandler.get());
208 
209     if (!m_peerHandler->initialize(configuration, constraints)) {
210         m_closed = true;
211         m_stopped = true;
212         exceptionState.throwDOMException(NotSupportedError, "Failed to initialize native PeerConnection.");
213         return;
214     }
215 }
216 
~RTCPeerConnection()217 RTCPeerConnection::~RTCPeerConnection()
218 {
219     // This checks that close() or stop() is called before the destructor.
220     // We are assuming that a wrapper is always created when RTCPeerConnection is created.
221     ASSERT(m_closed || m_stopped);
222 
223 #if !ENABLE(OILPAN)
224     stop();
225 #endif
226 }
227 
createOffer(PassOwnPtr<RTCSessionDescriptionCallback> successCallback,PassOwnPtr<RTCErrorCallback> errorCallback,const Dictionary & mediaConstraints,ExceptionState & exceptionState)228 void RTCPeerConnection::createOffer(PassOwnPtr<RTCSessionDescriptionCallback> successCallback, PassOwnPtr<RTCErrorCallback> errorCallback, const Dictionary& mediaConstraints, ExceptionState& exceptionState)
229 {
230     if (throwExceptionIfSignalingStateClosed(m_signalingState, exceptionState))
231         return;
232 
233     ASSERT(successCallback);
234 
235     blink::WebMediaConstraints constraints = MediaConstraintsImpl::create(mediaConstraints, exceptionState);
236     if (exceptionState.hadException())
237         return;
238 
239     RefPtr<RTCSessionDescriptionRequest> request = RTCSessionDescriptionRequestImpl::create(executionContext(), this, successCallback, errorCallback);
240     m_peerHandler->createOffer(request.release(), constraints);
241 }
242 
createAnswer(PassOwnPtr<RTCSessionDescriptionCallback> successCallback,PassOwnPtr<RTCErrorCallback> errorCallback,const Dictionary & mediaConstraints,ExceptionState & exceptionState)243 void RTCPeerConnection::createAnswer(PassOwnPtr<RTCSessionDescriptionCallback> successCallback, PassOwnPtr<RTCErrorCallback> errorCallback, const Dictionary& mediaConstraints, ExceptionState& exceptionState)
244 {
245     if (throwExceptionIfSignalingStateClosed(m_signalingState, exceptionState))
246         return;
247 
248     ASSERT(successCallback);
249 
250     blink::WebMediaConstraints constraints = MediaConstraintsImpl::create(mediaConstraints, exceptionState);
251     if (exceptionState.hadException())
252         return;
253 
254     RefPtr<RTCSessionDescriptionRequest> request = RTCSessionDescriptionRequestImpl::create(executionContext(), this, successCallback, errorCallback);
255     m_peerHandler->createAnswer(request.release(), constraints);
256 }
257 
setLocalDescription(PassRefPtrWillBeRawPtr<RTCSessionDescription> prpSessionDescription,PassOwnPtr<VoidCallback> successCallback,PassOwnPtr<RTCErrorCallback> errorCallback,ExceptionState & exceptionState)258 void RTCPeerConnection::setLocalDescription(PassRefPtrWillBeRawPtr<RTCSessionDescription> prpSessionDescription, PassOwnPtr<VoidCallback> successCallback, PassOwnPtr<RTCErrorCallback> errorCallback, ExceptionState& exceptionState)
259 {
260     if (throwExceptionIfSignalingStateClosed(m_signalingState, exceptionState))
261         return;
262 
263     RefPtrWillBeRawPtr<RTCSessionDescription> sessionDescription = prpSessionDescription;
264     if (!sessionDescription) {
265         exceptionState.throwDOMException(TypeMismatchError, ExceptionMessages::argumentNullOrIncorrectType(1, "RTCSessionDescription"));
266         return;
267     }
268 
269     RefPtr<RTCVoidRequest> request = RTCVoidRequestImpl::create(executionContext(), this, successCallback, errorCallback);
270     m_peerHandler->setLocalDescription(request.release(), sessionDescription->webSessionDescription());
271 }
272 
localDescription(ExceptionState & exceptionState)273 PassRefPtrWillBeRawPtr<RTCSessionDescription> RTCPeerConnection::localDescription(ExceptionState& exceptionState)
274 {
275     blink::WebRTCSessionDescription webSessionDescription = m_peerHandler->localDescription();
276     if (webSessionDescription.isNull())
277         return nullptr;
278 
279     return RTCSessionDescription::create(webSessionDescription);
280 }
281 
setRemoteDescription(PassRefPtrWillBeRawPtr<RTCSessionDescription> prpSessionDescription,PassOwnPtr<VoidCallback> successCallback,PassOwnPtr<RTCErrorCallback> errorCallback,ExceptionState & exceptionState)282 void RTCPeerConnection::setRemoteDescription(PassRefPtrWillBeRawPtr<RTCSessionDescription> prpSessionDescription, PassOwnPtr<VoidCallback> successCallback, PassOwnPtr<RTCErrorCallback> errorCallback, ExceptionState& exceptionState)
283 {
284     if (throwExceptionIfSignalingStateClosed(m_signalingState, exceptionState))
285         return;
286 
287     RefPtrWillBeRawPtr<RTCSessionDescription> sessionDescription = prpSessionDescription;
288     if (!sessionDescription) {
289         exceptionState.throwDOMException(TypeMismatchError, ExceptionMessages::argumentNullOrIncorrectType(1, "RTCSessionDescription"));
290         return;
291     }
292 
293     RefPtr<RTCVoidRequest> request = RTCVoidRequestImpl::create(executionContext(), this, successCallback, errorCallback);
294     m_peerHandler->setRemoteDescription(request.release(), sessionDescription->webSessionDescription());
295 }
296 
remoteDescription(ExceptionState & exceptionState)297 PassRefPtrWillBeRawPtr<RTCSessionDescription> RTCPeerConnection::remoteDescription(ExceptionState& exceptionState)
298 {
299     blink::WebRTCSessionDescription webSessionDescription = m_peerHandler->remoteDescription();
300     if (webSessionDescription.isNull())
301         return nullptr;
302 
303     return RTCSessionDescription::create(webSessionDescription);
304 }
305 
updateIce(const Dictionary & rtcConfiguration,const Dictionary & mediaConstraints,ExceptionState & exceptionState)306 void RTCPeerConnection::updateIce(const Dictionary& rtcConfiguration, const Dictionary& mediaConstraints, ExceptionState& exceptionState)
307 {
308     if (throwExceptionIfSignalingStateClosed(m_signalingState, exceptionState))
309         return;
310 
311     RefPtr<RTCConfiguration> configuration = parseConfiguration(rtcConfiguration, exceptionState);
312     if (exceptionState.hadException())
313         return;
314 
315     blink::WebMediaConstraints constraints = MediaConstraintsImpl::create(mediaConstraints, exceptionState);
316     if (exceptionState.hadException())
317         return;
318 
319     bool valid = m_peerHandler->updateICE(configuration.release(), constraints);
320     if (!valid)
321         exceptionState.throwDOMException(SyntaxError, "Could not update the ICE Agent with the given configuration.");
322 }
323 
addIceCandidate(RTCIceCandidate * iceCandidate,ExceptionState & exceptionState)324 void RTCPeerConnection::addIceCandidate(RTCIceCandidate* iceCandidate, ExceptionState& exceptionState)
325 {
326     if (throwExceptionIfSignalingStateClosed(m_signalingState, exceptionState))
327         return;
328 
329     if (!iceCandidate) {
330         exceptionState.throwDOMException(TypeMismatchError, ExceptionMessages::argumentNullOrIncorrectType(1, "RTCIceCandidate"));
331         return;
332     }
333 
334     bool valid = m_peerHandler->addICECandidate(iceCandidate->webCandidate());
335     if (!valid)
336         exceptionState.throwDOMException(SyntaxError, "The ICE candidate could not be added.");
337 }
338 
addIceCandidate(RTCIceCandidate * iceCandidate,PassOwnPtr<VoidCallback> successCallback,PassOwnPtr<RTCErrorCallback> errorCallback,ExceptionState & exceptionState)339 void RTCPeerConnection::addIceCandidate(RTCIceCandidate* iceCandidate, PassOwnPtr<VoidCallback> successCallback, PassOwnPtr<RTCErrorCallback> errorCallback, ExceptionState& exceptionState)
340 {
341     if (throwExceptionIfSignalingStateClosed(m_signalingState, exceptionState))
342         return;
343 
344     if (!iceCandidate) {
345         exceptionState.throwDOMException(TypeMismatchError, ExceptionMessages::argumentNullOrIncorrectType(1, "RTCIceCandidate"));
346         return;
347     }
348     ASSERT(successCallback);
349     ASSERT(errorCallback);
350 
351     RefPtr<RTCVoidRequest> request = RTCVoidRequestImpl::create(executionContext(), this, successCallback, errorCallback);
352 
353     bool implemented = m_peerHandler->addICECandidate(request.release(), iceCandidate->webCandidate());
354     if (!implemented) {
355         exceptionState.throwDOMException(NotSupportedError, "This method is not yet implemented.");
356     }
357 }
358 
signalingState() const359 String RTCPeerConnection::signalingState() const
360 {
361     switch (m_signalingState) {
362     case SignalingStateStable:
363         return "stable";
364     case SignalingStateHaveLocalOffer:
365         return "have-local-offer";
366     case SignalingStateHaveRemoteOffer:
367         return "have-remote-offer";
368     case SignalingStateHaveLocalPrAnswer:
369         return "have-local-pranswer";
370     case SignalingStateHaveRemotePrAnswer:
371         return "have-remote-pranswer";
372     case SignalingStateClosed:
373         return "closed";
374     }
375 
376     ASSERT_NOT_REACHED();
377     return String();
378 }
379 
iceGatheringState() const380 String RTCPeerConnection::iceGatheringState() const
381 {
382     switch (m_iceGatheringState) {
383     case ICEGatheringStateNew:
384         return "new";
385     case ICEGatheringStateGathering:
386         return "gathering";
387     case ICEGatheringStateComplete:
388         return "complete";
389     }
390 
391     ASSERT_NOT_REACHED();
392     return String();
393 }
394 
iceConnectionState() const395 String RTCPeerConnection::iceConnectionState() const
396 {
397     switch (m_iceConnectionState) {
398     case ICEConnectionStateNew:
399         return "new";
400     case ICEConnectionStateChecking:
401         return "checking";
402     case ICEConnectionStateConnected:
403         return "connected";
404     case ICEConnectionStateCompleted:
405         return "completed";
406     case ICEConnectionStateFailed:
407         return "failed";
408     case ICEConnectionStateDisconnected:
409         return "disconnected";
410     case ICEConnectionStateClosed:
411         return "closed";
412     }
413 
414     ASSERT_NOT_REACHED();
415     return String();
416 }
417 
addStream(PassRefPtrWillBeRawPtr<MediaStream> prpStream,const Dictionary & mediaConstraints,ExceptionState & exceptionState)418 void RTCPeerConnection::addStream(PassRefPtrWillBeRawPtr<MediaStream> prpStream, const Dictionary& mediaConstraints, ExceptionState& exceptionState)
419 {
420     if (throwExceptionIfSignalingStateClosed(m_signalingState, exceptionState))
421         return;
422 
423     RefPtrWillBeRawPtr<MediaStream> stream = prpStream;
424     if (!stream) {
425         exceptionState.throwDOMException(TypeMismatchError, ExceptionMessages::argumentNullOrIncorrectType(1, "MediaStream"));
426         return;
427     }
428 
429     if (m_localStreams.contains(stream))
430         return;
431 
432     blink::WebMediaConstraints constraints = MediaConstraintsImpl::create(mediaConstraints, exceptionState);
433     if (exceptionState.hadException())
434         return;
435 
436     m_localStreams.append(stream);
437 
438     bool valid = m_peerHandler->addStream(stream->descriptor(), constraints);
439     if (!valid)
440         exceptionState.throwDOMException(SyntaxError, "Unable to add the provided stream.");
441 }
442 
removeStream(PassRefPtrWillBeRawPtr<MediaStream> prpStream,ExceptionState & exceptionState)443 void RTCPeerConnection::removeStream(PassRefPtrWillBeRawPtr<MediaStream> prpStream, ExceptionState& exceptionState)
444 {
445     if (throwExceptionIfSignalingStateClosed(m_signalingState, exceptionState))
446         return;
447 
448     if (!prpStream) {
449         exceptionState.throwDOMException(TypeMismatchError, ExceptionMessages::argumentNullOrIncorrectType(1, "MediaStream"));
450         return;
451     }
452 
453     RefPtrWillBeRawPtr<MediaStream> stream = prpStream;
454 
455     size_t pos = m_localStreams.find(stream);
456     if (pos == kNotFound)
457         return;
458 
459     m_localStreams.remove(pos);
460 
461     m_peerHandler->removeStream(stream->descriptor());
462 }
463 
getLocalStreams() const464 MediaStreamVector RTCPeerConnection::getLocalStreams() const
465 {
466     return m_localStreams;
467 }
468 
getRemoteStreams() const469 MediaStreamVector RTCPeerConnection::getRemoteStreams() const
470 {
471     return m_remoteStreams;
472 }
473 
getStreamById(const String & streamId)474 MediaStream* RTCPeerConnection::getStreamById(const String& streamId)
475 {
476     for (MediaStreamVector::iterator iter = m_localStreams.begin(); iter != m_localStreams.end(); ++iter) {
477         if ((*iter)->id() == streamId)
478             return iter->get();
479     }
480 
481     for (MediaStreamVector::iterator iter = m_remoteStreams.begin(); iter != m_remoteStreams.end(); ++iter) {
482         if ((*iter)->id() == streamId)
483             return iter->get();
484     }
485 
486     return 0;
487 }
488 
getStats(PassOwnPtr<RTCStatsCallback> successCallback,PassRefPtr<MediaStreamTrack> selector)489 void RTCPeerConnection::getStats(PassOwnPtr<RTCStatsCallback> successCallback, PassRefPtr<MediaStreamTrack> selector)
490 {
491     RefPtr<RTCStatsRequest> statsRequest = RTCStatsRequestImpl::create(executionContext(), this, successCallback, selector);
492     // FIXME: Add passing selector as part of the statsRequest.
493     m_peerHandler->getStats(statsRequest.release());
494 }
495 
createDataChannel(String label,const Dictionary & options,ExceptionState & exceptionState)496 PassRefPtrWillBeRawPtr<RTCDataChannel> RTCPeerConnection::createDataChannel(String label, const Dictionary& options, ExceptionState& exceptionState)
497 {
498     if (throwExceptionIfSignalingStateClosed(m_signalingState, exceptionState))
499         return nullptr;
500 
501     blink::WebRTCDataChannelInit init;
502     options.get("ordered", init.ordered);
503     options.get("negotiated", init.negotiated);
504 
505     unsigned short value = 0;
506     if (options.get("id", value))
507         init.id = value;
508     if (options.get("maxRetransmits", value))
509         init.maxRetransmits = value;
510     if (options.get("maxRetransmitTime", value))
511         init.maxRetransmitTime = value;
512 
513     String protocolString;
514     options.get("protocol", protocolString);
515     init.protocol = protocolString;
516 
517     RefPtrWillBeRawPtr<RTCDataChannel> channel = RTCDataChannel::create(executionContext(), this, m_peerHandler.get(), label, init, exceptionState);
518     if (exceptionState.hadException())
519         return nullptr;
520     m_dataChannels.append(channel);
521     return channel.release();
522 }
523 
hasLocalStreamWithTrackId(const String & trackId)524 bool RTCPeerConnection::hasLocalStreamWithTrackId(const String& trackId)
525 {
526     for (MediaStreamVector::iterator iter = m_localStreams.begin(); iter != m_localStreams.end(); ++iter) {
527         if ((*iter)->getTrackById(trackId))
528             return true;
529     }
530     return false;
531 }
532 
createDTMFSender(PassRefPtrWillBeRawPtr<MediaStreamTrack> prpTrack,ExceptionState & exceptionState)533 PassRefPtrWillBeRawPtr<RTCDTMFSender> RTCPeerConnection::createDTMFSender(PassRefPtrWillBeRawPtr<MediaStreamTrack> prpTrack, ExceptionState& exceptionState)
534 {
535     if (throwExceptionIfSignalingStateClosed(m_signalingState, exceptionState))
536         return nullptr;
537 
538     if (!prpTrack) {
539         exceptionState.throwTypeError(ExceptionMessages::argumentNullOrIncorrectType(1, "MediaStreamTrack"));
540         return nullptr;
541     }
542 
543     RefPtrWillBeRawPtr<MediaStreamTrack> track = prpTrack;
544 
545     if (!hasLocalStreamWithTrackId(track->id())) {
546         exceptionState.throwDOMException(SyntaxError, "No local stream is available for the track provided.");
547         return nullptr;
548     }
549 
550     RefPtrWillBeRawPtr<RTCDTMFSender> dtmfSender = RTCDTMFSender::create(executionContext(), m_peerHandler.get(), track.release(), exceptionState);
551     if (exceptionState.hadException())
552         return nullptr;
553     return dtmfSender.release();
554 }
555 
close(ExceptionState & exceptionState)556 void RTCPeerConnection::close(ExceptionState& exceptionState)
557 {
558     if (throwExceptionIfSignalingStateClosed(m_signalingState, exceptionState))
559         return;
560 
561     m_peerHandler->stop();
562     m_closed = true;
563 
564     changeIceConnectionState(ICEConnectionStateClosed);
565     changeIceGatheringState(ICEGatheringStateComplete);
566     changeSignalingState(SignalingStateClosed);
567 }
568 
negotiationNeeded()569 void RTCPeerConnection::negotiationNeeded()
570 {
571     ASSERT(!m_closed);
572     scheduleDispatchEvent(Event::create(EventTypeNames::negotiationneeded));
573 }
574 
didGenerateICECandidate(const blink::WebRTCICECandidate & webCandidate)575 void RTCPeerConnection::didGenerateICECandidate(const blink::WebRTCICECandidate& webCandidate)
576 {
577     ASSERT(!m_closed);
578     ASSERT(executionContext()->isContextThread());
579     if (webCandidate.isNull())
580         scheduleDispatchEvent(RTCIceCandidateEvent::create(false, false, nullptr));
581     else {
582         RefPtrWillBeRawPtr<RTCIceCandidate> iceCandidate = RTCIceCandidate::create(webCandidate);
583         scheduleDispatchEvent(RTCIceCandidateEvent::create(false, false, iceCandidate.release()));
584     }
585 }
586 
didChangeSignalingState(SignalingState newState)587 void RTCPeerConnection::didChangeSignalingState(SignalingState newState)
588 {
589     ASSERT(!m_closed);
590     ASSERT(executionContext()->isContextThread());
591     changeSignalingState(newState);
592 }
593 
didChangeICEGatheringState(ICEGatheringState newState)594 void RTCPeerConnection::didChangeICEGatheringState(ICEGatheringState newState)
595 {
596     ASSERT(!m_closed);
597     ASSERT(executionContext()->isContextThread());
598     changeIceGatheringState(newState);
599 }
600 
didChangeICEConnectionState(ICEConnectionState newState)601 void RTCPeerConnection::didChangeICEConnectionState(ICEConnectionState newState)
602 {
603     ASSERT(!m_closed);
604     ASSERT(executionContext()->isContextThread());
605     changeIceConnectionState(newState);
606 }
607 
didAddRemoteStream(const blink::WebMediaStream & remoteStream)608 void RTCPeerConnection::didAddRemoteStream(const blink::WebMediaStream& remoteStream)
609 {
610     ASSERT(!m_closed);
611     ASSERT(executionContext()->isContextThread());
612 
613     if (m_signalingState == SignalingStateClosed)
614         return;
615 
616     RefPtrWillBeRawPtr<MediaStream> stream = MediaStream::create(executionContext(), remoteStream);
617     m_remoteStreams.append(stream);
618 
619     scheduleDispatchEvent(MediaStreamEvent::create(EventTypeNames::addstream, false, false, stream.release()));
620 }
621 
didRemoveRemoteStream(const blink::WebMediaStream & remoteStream)622 void RTCPeerConnection::didRemoveRemoteStream(const blink::WebMediaStream& remoteStream)
623 {
624     ASSERT(!m_closed);
625     ASSERT(executionContext()->isContextThread());
626 
627     MediaStreamDescriptor* streamDescriptor = remoteStream;
628     ASSERT(streamDescriptor->client());
629 
630     RefPtrWillBeRawPtr<MediaStream> stream = static_cast<MediaStream*>(streamDescriptor->client());
631     stream->streamEnded();
632 
633     if (m_signalingState == SignalingStateClosed)
634         return;
635 
636     size_t pos = m_remoteStreams.find(stream);
637     ASSERT(pos != kNotFound);
638     m_remoteStreams.remove(pos);
639 
640     scheduleDispatchEvent(MediaStreamEvent::create(EventTypeNames::removestream, false, false, stream.release()));
641 }
642 
didAddRemoteDataChannel(blink::WebRTCDataChannelHandler * handler)643 void RTCPeerConnection::didAddRemoteDataChannel(blink::WebRTCDataChannelHandler* handler)
644 {
645     ASSERT(!m_closed);
646     ASSERT(executionContext()->isContextThread());
647 
648     if (m_signalingState == SignalingStateClosed)
649         return;
650 
651     RefPtrWillBeRawPtr<RTCDataChannel> channel = RTCDataChannel::create(executionContext(), this, adoptPtr(handler));
652     m_dataChannels.append(channel);
653 
654     scheduleDispatchEvent(RTCDataChannelEvent::create(EventTypeNames::datachannel, false, false, channel.release()));
655 }
656 
releasePeerConnectionHandler()657 void RTCPeerConnection::releasePeerConnectionHandler()
658 {
659     stop();
660 }
661 
interfaceName() const662 const AtomicString& RTCPeerConnection::interfaceName() const
663 {
664     return EventTargetNames::RTCPeerConnection;
665 }
666 
executionContext() const667 ExecutionContext* RTCPeerConnection::executionContext() const
668 {
669     return ActiveDOMObject::executionContext();
670 }
671 
suspend()672 void RTCPeerConnection::suspend()
673 {
674     m_dispatchScheduledEventRunner.suspend();
675 }
676 
resume()677 void RTCPeerConnection::resume()
678 {
679     m_dispatchScheduledEventRunner.resume();
680 }
681 
stop()682 void RTCPeerConnection::stop()
683 {
684     if (m_stopped)
685         return;
686 
687     m_stopped = true;
688     m_iceConnectionState = ICEConnectionStateClosed;
689     m_signalingState = SignalingStateClosed;
690 
691     WillBeHeapVector<RefPtrWillBeMember<RTCDataChannel> >::iterator i = m_dataChannels.begin();
692     for (; i != m_dataChannels.end(); ++i)
693         (*i)->stop();
694     m_dataChannels.clear();
695 
696     m_dispatchScheduledEventRunner.stop();
697 
698     m_peerHandler.clear();
699 }
700 
changeSignalingState(SignalingState signalingState)701 void RTCPeerConnection::changeSignalingState(SignalingState signalingState)
702 {
703     if (m_signalingState != SignalingStateClosed && m_signalingState != signalingState) {
704         m_signalingState = signalingState;
705         scheduleDispatchEvent(Event::create(EventTypeNames::signalingstatechange));
706     }
707 }
708 
changeIceGatheringState(ICEGatheringState iceGatheringState)709 void RTCPeerConnection::changeIceGatheringState(ICEGatheringState iceGatheringState)
710 {
711     m_iceGatheringState = iceGatheringState;
712 }
713 
changeIceConnectionState(ICEConnectionState iceConnectionState)714 void RTCPeerConnection::changeIceConnectionState(ICEConnectionState iceConnectionState)
715 {
716     if (m_iceConnectionState != ICEConnectionStateClosed && m_iceConnectionState != iceConnectionState) {
717         m_iceConnectionState = iceConnectionState;
718         scheduleDispatchEvent(Event::create(EventTypeNames::iceconnectionstatechange));
719     }
720 }
721 
scheduleDispatchEvent(PassRefPtrWillBeRawPtr<Event> event)722 void RTCPeerConnection::scheduleDispatchEvent(PassRefPtrWillBeRawPtr<Event> event)
723 {
724     m_scheduledEvents.append(event);
725 
726     m_dispatchScheduledEventRunner.runAsync();
727 }
728 
dispatchScheduledEvent()729 void RTCPeerConnection::dispatchScheduledEvent()
730 {
731     if (m_stopped)
732         return;
733 
734     WillBeHeapVector<RefPtrWillBeMember<Event> > events;
735     events.swap(m_scheduledEvents);
736 
737     WillBeHeapVector<RefPtrWillBeMember<Event> >::iterator it = events.begin();
738     for (; it != events.end(); ++it)
739         dispatchEvent((*it).release());
740 
741     events.clear();
742 }
743 
trace(Visitor * visitor)744 void RTCPeerConnection::trace(Visitor* visitor)
745 {
746     visitor->trace(m_localStreams);
747     visitor->trace(m_remoteStreams);
748     visitor->trace(m_dataChannels);
749     visitor->trace(m_scheduledEvents);
750     EventTargetWithInlineData::trace(visitor);
751 }
752 
753 } // namespace WebCore
754