• 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 #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