• 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/ExceptionState.h"
37 #include "core/dom/Document.h"
38 #include "core/events/Event.h"
39 #include "core/dom/ExceptionCode.h"
40 #include "core/dom/ExecutionContext.h"
41 #include "core/html/VoidCallback.h"
42 #include "core/loader/FrameLoader.h"
43 #include "core/loader/FrameLoaderClient.h"
44 #include "core/frame/Frame.h"
45 #include "core/platform/mediastream/RTCDataChannelHandler.h"
46 #include "modules/mediastream/MediaConstraintsImpl.h"
47 #include "modules/mediastream/MediaStreamEvent.h"
48 #include "modules/mediastream/RTCDTMFSender.h"
49 #include "modules/mediastream/RTCDataChannel.h"
50 #include "modules/mediastream/RTCDataChannelEvent.h"
51 #include "modules/mediastream/RTCErrorCallback.h"
52 #include "modules/mediastream/RTCIceCandidateEvent.h"
53 #include "modules/mediastream/RTCSessionDescription.h"
54 #include "modules/mediastream/RTCSessionDescriptionCallback.h"
55 #include "modules/mediastream/RTCSessionDescriptionRequestImpl.h"
56 #include "modules/mediastream/RTCStatsCallback.h"
57 #include "modules/mediastream/RTCStatsRequestImpl.h"
58 #include "modules/mediastream/RTCVoidRequestImpl.h"
59 #include "platform/mediastream/RTCConfiguration.h"
60 #include "public/platform/WebRTCDataChannelInit.h"
61 #include "public/platform/WebRTCICECandidate.h"
62 #include "public/platform/WebRTCSessionDescription.h"
63 
64 namespace WebCore {
65 
parseConfiguration(const Dictionary & configuration,ExceptionState & exceptionState)66 PassRefPtr<RTCConfiguration> RTCPeerConnection::parseConfiguration(const Dictionary& configuration, ExceptionState& exceptionState)
67 {
68     if (configuration.isUndefinedOrNull())
69         return 0;
70 
71     ArrayValue iceServers;
72     bool ok = configuration.get("iceServers", iceServers);
73     if (!ok || iceServers.isUndefinedOrNull()) {
74         exceptionState.throwUninformativeAndGenericDOMException(TypeMismatchError);
75         return 0;
76     }
77 
78     size_t numberOfServers;
79     ok = iceServers.length(numberOfServers);
80     if (!ok) {
81         exceptionState.throwUninformativeAndGenericDOMException(TypeMismatchError);
82         return 0;
83     }
84 
85     RefPtr<RTCConfiguration> rtcConfiguration = RTCConfiguration::create();
86 
87     for (size_t i = 0; i < numberOfServers; ++i) {
88         Dictionary iceServer;
89         ok = iceServers.get(i, iceServer);
90         if (!ok) {
91             exceptionState.throwUninformativeAndGenericDOMException(TypeMismatchError);
92             return 0;
93         }
94 
95         String urlString, username, credential;
96         ok = iceServer.get("url", urlString);
97         if (!ok) {
98             exceptionState.throwUninformativeAndGenericDOMException(TypeMismatchError);
99             return 0;
100         }
101         KURL url(KURL(), urlString);
102         if (!url.isValid() || !(url.protocolIs("turn") || url.protocolIs("turns") || url.protocolIs("stun"))) {
103             exceptionState.throwUninformativeAndGenericDOMException(TypeMismatchError);
104             return 0;
105         }
106 
107         iceServer.get("username", username);
108         iceServer.get("credential", credential);
109 
110         rtcConfiguration->appendServer(RTCIceServer::create(url, username, credential));
111     }
112 
113     return rtcConfiguration.release();
114 }
115 
create(ExecutionContext * context,const Dictionary & rtcConfiguration,const Dictionary & mediaConstraints,ExceptionState & exceptionState)116 PassRefPtr<RTCPeerConnection> RTCPeerConnection::create(ExecutionContext* context, const Dictionary& rtcConfiguration, const Dictionary& mediaConstraints, ExceptionState& exceptionState)
117 {
118     RefPtr<RTCConfiguration> configuration = parseConfiguration(rtcConfiguration, exceptionState);
119     if (exceptionState.hadException())
120         return 0;
121 
122     RefPtr<MediaConstraints> constraints = MediaConstraintsImpl::create(mediaConstraints, exceptionState);
123     if (exceptionState.hadException())
124         return 0;
125 
126     RefPtr<RTCPeerConnection> peerConnection = adoptRef(new RTCPeerConnection(context, configuration.release(), constraints.release(), exceptionState));
127     peerConnection->suspendIfNeeded();
128     if (exceptionState.hadException())
129         return 0;
130 
131     return peerConnection.release();
132 }
133 
RTCPeerConnection(ExecutionContext * context,PassRefPtr<RTCConfiguration> configuration,PassRefPtr<MediaConstraints> constraints,ExceptionState & exceptionState)134 RTCPeerConnection::RTCPeerConnection(ExecutionContext* context, PassRefPtr<RTCConfiguration> configuration, PassRefPtr<MediaConstraints> constraints, ExceptionState& exceptionState)
135     : ActiveDOMObject(context)
136     , m_signalingState(SignalingStateStable)
137     , m_iceGatheringState(IceGatheringStateNew)
138     , m_iceConnectionState(IceConnectionStateNew)
139     , m_dispatchScheduledEventRunner(this, &RTCPeerConnection::dispatchScheduledEvent)
140     , m_stopped(false)
141 {
142     ScriptWrappable::init(this);
143     Document* document = toDocument(executionContext());
144 
145     if (!document->frame()) {
146         exceptionState.throwUninformativeAndGenericDOMException(NotSupportedError);
147         return;
148     }
149 
150     m_peerHandler = RTCPeerConnectionHandler::create(this);
151     if (!m_peerHandler) {
152         exceptionState.throwUninformativeAndGenericDOMException(NotSupportedError);
153         return;
154     }
155 
156     document->frame()->loader().client()->dispatchWillStartUsingPeerConnectionHandler(m_peerHandler.get());
157 
158     if (!m_peerHandler->initialize(configuration, constraints)) {
159         exceptionState.throwUninformativeAndGenericDOMException(NotSupportedError);
160         return;
161     }
162 }
163 
~RTCPeerConnection()164 RTCPeerConnection::~RTCPeerConnection()
165 {
166     stop();
167 }
168 
createOffer(PassOwnPtr<RTCSessionDescriptionCallback> successCallback,PassOwnPtr<RTCErrorCallback> errorCallback,const Dictionary & mediaConstraints,ExceptionState & exceptionState)169 void RTCPeerConnection::createOffer(PassOwnPtr<RTCSessionDescriptionCallback> successCallback, PassOwnPtr<RTCErrorCallback> errorCallback, const Dictionary& mediaConstraints, ExceptionState& exceptionState)
170 {
171     if (m_signalingState == SignalingStateClosed) {
172         exceptionState.throwUninformativeAndGenericDOMException(InvalidStateError);
173         return;
174     }
175 
176     if (!successCallback) {
177         exceptionState.throwUninformativeAndGenericDOMException(TypeMismatchError);
178         return;
179     }
180 
181     RefPtr<MediaConstraints> constraints = MediaConstraintsImpl::create(mediaConstraints, exceptionState);
182     if (exceptionState.hadException())
183         return;
184 
185     RefPtr<RTCSessionDescriptionRequestImpl> request = RTCSessionDescriptionRequestImpl::create(executionContext(), successCallback, errorCallback);
186     m_peerHandler->createOffer(request.release(), constraints);
187 }
188 
createAnswer(PassOwnPtr<RTCSessionDescriptionCallback> successCallback,PassOwnPtr<RTCErrorCallback> errorCallback,const Dictionary & mediaConstraints,ExceptionState & exceptionState)189 void RTCPeerConnection::createAnswer(PassOwnPtr<RTCSessionDescriptionCallback> successCallback, PassOwnPtr<RTCErrorCallback> errorCallback, const Dictionary& mediaConstraints, ExceptionState& exceptionState)
190 {
191     if (m_signalingState == SignalingStateClosed) {
192         exceptionState.throwUninformativeAndGenericDOMException(InvalidStateError);
193         return;
194     }
195 
196     if (!successCallback) {
197         exceptionState.throwUninformativeAndGenericDOMException(TypeMismatchError);
198         return;
199     }
200 
201     RefPtr<MediaConstraints> constraints = MediaConstraintsImpl::create(mediaConstraints, exceptionState);
202     if (exceptionState.hadException())
203         return;
204 
205     RefPtr<RTCSessionDescriptionRequestImpl> request = RTCSessionDescriptionRequestImpl::create(executionContext(), successCallback, errorCallback);
206     m_peerHandler->createAnswer(request.release(), constraints.release());
207 }
208 
setLocalDescription(PassRefPtr<RTCSessionDescription> prpSessionDescription,PassOwnPtr<VoidCallback> successCallback,PassOwnPtr<RTCErrorCallback> errorCallback,ExceptionState & exceptionState)209 void RTCPeerConnection::setLocalDescription(PassRefPtr<RTCSessionDescription> prpSessionDescription, PassOwnPtr<VoidCallback> successCallback, PassOwnPtr<RTCErrorCallback> errorCallback, ExceptionState& exceptionState)
210 {
211     if (m_signalingState == SignalingStateClosed) {
212         exceptionState.throwUninformativeAndGenericDOMException(InvalidStateError);
213         return;
214     }
215 
216     RefPtr<RTCSessionDescription> sessionDescription = prpSessionDescription;
217     if (!sessionDescription) {
218         exceptionState.throwUninformativeAndGenericDOMException(TypeMismatchError);
219         return;
220     }
221 
222     RefPtr<RTCVoidRequestImpl> request = RTCVoidRequestImpl::create(executionContext(), successCallback, errorCallback);
223     m_peerHandler->setLocalDescription(request.release(), sessionDescription->webSessionDescription());
224 }
225 
localDescription(ExceptionState & exceptionState)226 PassRefPtr<RTCSessionDescription> RTCPeerConnection::localDescription(ExceptionState& exceptionState)
227 {
228     blink::WebRTCSessionDescription webSessionDescription = m_peerHandler->localDescription();
229     if (webSessionDescription.isNull())
230         return 0;
231 
232     RefPtr<RTCSessionDescription> sessionDescription = RTCSessionDescription::create(webSessionDescription);
233     return sessionDescription.release();
234 }
235 
setRemoteDescription(PassRefPtr<RTCSessionDescription> prpSessionDescription,PassOwnPtr<VoidCallback> successCallback,PassOwnPtr<RTCErrorCallback> errorCallback,ExceptionState & exceptionState)236 void RTCPeerConnection::setRemoteDescription(PassRefPtr<RTCSessionDescription> prpSessionDescription, PassOwnPtr<VoidCallback> successCallback, PassOwnPtr<RTCErrorCallback> errorCallback, ExceptionState& exceptionState)
237 {
238     if (m_signalingState == SignalingStateClosed) {
239         exceptionState.throwUninformativeAndGenericDOMException(InvalidStateError);
240         return;
241     }
242 
243     RefPtr<RTCSessionDescription> sessionDescription = prpSessionDescription;
244     if (!sessionDescription) {
245         exceptionState.throwUninformativeAndGenericDOMException(TypeMismatchError);
246         return;
247     }
248 
249     RefPtr<RTCVoidRequestImpl> request = RTCVoidRequestImpl::create(executionContext(), successCallback, errorCallback);
250     m_peerHandler->setRemoteDescription(request.release(), sessionDescription->webSessionDescription());
251 }
252 
remoteDescription(ExceptionState & exceptionState)253 PassRefPtr<RTCSessionDescription> RTCPeerConnection::remoteDescription(ExceptionState& exceptionState)
254 {
255     blink::WebRTCSessionDescription webSessionDescription = m_peerHandler->remoteDescription();
256     if (webSessionDescription.isNull())
257         return 0;
258 
259     RefPtr<RTCSessionDescription> desc = RTCSessionDescription::create(webSessionDescription);
260     return desc.release();
261 }
262 
updateIce(const Dictionary & rtcConfiguration,const Dictionary & mediaConstraints,ExceptionState & exceptionState)263 void RTCPeerConnection::updateIce(const Dictionary& rtcConfiguration, const Dictionary& mediaConstraints, ExceptionState& exceptionState)
264 {
265     if (m_signalingState == SignalingStateClosed) {
266         exceptionState.throwUninformativeAndGenericDOMException(InvalidStateError);
267         return;
268     }
269 
270     RefPtr<RTCConfiguration> configuration = parseConfiguration(rtcConfiguration, exceptionState);
271     if (exceptionState.hadException())
272         return;
273 
274     RefPtr<MediaConstraints> constraints = MediaConstraintsImpl::create(mediaConstraints, exceptionState);
275     if (exceptionState.hadException())
276         return;
277 
278     bool valid = m_peerHandler->updateIce(configuration, constraints);
279     if (!valid)
280         exceptionState.throwUninformativeAndGenericDOMException(SyntaxError);
281 }
282 
addIceCandidate(RTCIceCandidate * iceCandidate,ExceptionState & exceptionState)283 void RTCPeerConnection::addIceCandidate(RTCIceCandidate* iceCandidate, ExceptionState& exceptionState)
284 {
285     if (m_signalingState == SignalingStateClosed) {
286         exceptionState.throwUninformativeAndGenericDOMException(InvalidStateError);
287         return;
288     }
289 
290     if (!iceCandidate) {
291         exceptionState.throwUninformativeAndGenericDOMException(TypeMismatchError);
292         return;
293     }
294 
295     bool valid = m_peerHandler->addIceCandidate(iceCandidate->webCandidate());
296     if (!valid)
297         exceptionState.throwUninformativeAndGenericDOMException(SyntaxError);
298 }
299 
addIceCandidate(RTCIceCandidate * iceCandidate,PassOwnPtr<VoidCallback> successCallback,PassOwnPtr<RTCErrorCallback> errorCallback,ExceptionState & exceptionState)300 void RTCPeerConnection::addIceCandidate(RTCIceCandidate* iceCandidate, PassOwnPtr<VoidCallback> successCallback, PassOwnPtr<RTCErrorCallback> errorCallback, ExceptionState& exceptionState)
301 {
302     if (m_signalingState == SignalingStateClosed) {
303         exceptionState.throwUninformativeAndGenericDOMException(InvalidStateError);
304         return;
305     }
306 
307     if (!iceCandidate || !successCallback || !errorCallback) {
308         exceptionState.throwUninformativeAndGenericDOMException(TypeMismatchError);
309         return;
310     }
311 
312     RefPtr<RTCVoidRequestImpl> request = RTCVoidRequestImpl::create(executionContext(), successCallback, errorCallback);
313 
314     bool implemented = m_peerHandler->addIceCandidate(request.release(), iceCandidate->webCandidate());
315     if (!implemented)
316         exceptionState.throwUninformativeAndGenericDOMException(NotSupportedError);
317 }
318 
signalingState() const319 String RTCPeerConnection::signalingState() const
320 {
321     switch (m_signalingState) {
322     case SignalingStateStable:
323         return "stable";
324     case SignalingStateHaveLocalOffer:
325         return "have-local-offer";
326     case SignalingStateHaveRemoteOffer:
327         return "have-remote-offer";
328     case SignalingStateHaveLocalPrAnswer:
329         return "have-local-pranswer";
330     case SignalingStateHaveRemotePrAnswer:
331         return "have-remote-pranswer";
332     case SignalingStateClosed:
333         return "closed";
334     }
335 
336     ASSERT_NOT_REACHED();
337     return String();
338 }
339 
iceGatheringState() const340 String RTCPeerConnection::iceGatheringState() const
341 {
342     switch (m_iceGatheringState) {
343     case IceGatheringStateNew:
344         return "new";
345     case IceGatheringStateGathering:
346         return "gathering";
347     case IceGatheringStateComplete:
348         return "complete";
349     }
350 
351     ASSERT_NOT_REACHED();
352     return String();
353 }
354 
iceConnectionState() const355 String RTCPeerConnection::iceConnectionState() const
356 {
357     switch (m_iceConnectionState) {
358     case IceConnectionStateNew:
359         return "new";
360     case IceConnectionStateChecking:
361         return "checking";
362     case IceConnectionStateConnected:
363         return "connected";
364     case IceConnectionStateCompleted:
365         return "completed";
366     case IceConnectionStateFailed:
367         return "failed";
368     case IceConnectionStateDisconnected:
369         return "disconnected";
370     case IceConnectionStateClosed:
371         return "closed";
372     }
373 
374     ASSERT_NOT_REACHED();
375     return String();
376 }
377 
addStream(PassRefPtr<MediaStream> prpStream,const Dictionary & mediaConstraints,ExceptionState & exceptionState)378 void RTCPeerConnection::addStream(PassRefPtr<MediaStream> prpStream, const Dictionary& mediaConstraints, ExceptionState& exceptionState)
379 {
380     if (m_signalingState == SignalingStateClosed) {
381         exceptionState.throwUninformativeAndGenericDOMException(InvalidStateError);
382         return;
383     }
384 
385     RefPtr<MediaStream> stream = prpStream;
386     if (!stream) {
387         exceptionState.throwUninformativeAndGenericDOMException(TypeMismatchError);
388         return;
389     }
390 
391     if (m_localStreams.contains(stream))
392         return;
393 
394     RefPtr<MediaConstraints> constraints = MediaConstraintsImpl::create(mediaConstraints, exceptionState);
395     if (exceptionState.hadException())
396         return;
397 
398     m_localStreams.append(stream);
399 
400     bool valid = m_peerHandler->addStream(stream->descriptor(), constraints);
401     if (!valid)
402         exceptionState.throwUninformativeAndGenericDOMException(SyntaxError);
403 }
404 
removeStream(PassRefPtr<MediaStream> prpStream,ExceptionState & exceptionState)405 void RTCPeerConnection::removeStream(PassRefPtr<MediaStream> prpStream, ExceptionState& exceptionState)
406 {
407     if (m_signalingState == SignalingStateClosed) {
408         exceptionState.throwUninformativeAndGenericDOMException(InvalidStateError);
409         return;
410     }
411 
412     if (!prpStream) {
413         exceptionState.throwUninformativeAndGenericDOMException(TypeMismatchError);
414         return;
415     }
416 
417     RefPtr<MediaStream> stream = prpStream;
418 
419     size_t pos = m_localStreams.find(stream);
420     if (pos == kNotFound)
421         return;
422 
423     m_localStreams.remove(pos);
424 
425     m_peerHandler->removeStream(stream->descriptor());
426 }
427 
getLocalStreams() const428 MediaStreamVector RTCPeerConnection::getLocalStreams() const
429 {
430     return m_localStreams;
431 }
432 
getRemoteStreams() const433 MediaStreamVector RTCPeerConnection::getRemoteStreams() const
434 {
435     return m_remoteStreams;
436 }
437 
getStreamById(const String & streamId)438 MediaStream* RTCPeerConnection::getStreamById(const String& streamId)
439 {
440     for (MediaStreamVector::iterator iter = m_localStreams.begin(); iter != m_localStreams.end(); ++iter) {
441         if ((*iter)->id() == streamId)
442             return iter->get();
443     }
444 
445     for (MediaStreamVector::iterator iter = m_remoteStreams.begin(); iter != m_remoteStreams.end(); ++iter) {
446         if ((*iter)->id() == streamId)
447             return iter->get();
448     }
449 
450     return 0;
451 }
452 
getStats(PassOwnPtr<RTCStatsCallback> successCallback,PassRefPtr<MediaStreamTrack> selector)453 void RTCPeerConnection::getStats(PassOwnPtr<RTCStatsCallback> successCallback, PassRefPtr<MediaStreamTrack> selector)
454 {
455     RefPtr<RTCStatsRequestImpl> statsRequest = RTCStatsRequestImpl::create(executionContext(), successCallback, selector);
456     // FIXME: Add passing selector as part of the statsRequest.
457     m_peerHandler->getStats(statsRequest.release());
458 }
459 
createDataChannel(String label,const Dictionary & options,ExceptionState & exceptionState)460 PassRefPtr<RTCDataChannel> RTCPeerConnection::createDataChannel(String label, const Dictionary& options, ExceptionState& exceptionState)
461 {
462     if (m_signalingState == SignalingStateClosed) {
463         exceptionState.throwUninformativeAndGenericDOMException(InvalidStateError);
464         return 0;
465     }
466 
467     blink::WebRTCDataChannelInit init;
468     options.get("ordered", init.ordered);
469     options.get("negotiated", init.negotiated);
470 
471     unsigned short value = 0;
472     if (options.get("id", value))
473         init.id = value;
474     if (options.get("maxRetransmits", value))
475         init.maxRetransmits = value;
476     if (options.get("maxRetransmitTime", value))
477         init.maxRetransmitTime = value;
478 
479     String protocolString;
480     options.get("protocol", protocolString);
481     init.protocol = protocolString;
482 
483     RefPtr<RTCDataChannel> channel = RTCDataChannel::create(executionContext(), m_peerHandler.get(), label, init, exceptionState);
484     if (exceptionState.hadException())
485         return 0;
486     m_dataChannels.append(channel);
487     return channel.release();
488 }
489 
hasLocalStreamWithTrackId(const String & trackId)490 bool RTCPeerConnection::hasLocalStreamWithTrackId(const String& trackId)
491 {
492     for (MediaStreamVector::iterator iter = m_localStreams.begin(); iter != m_localStreams.end(); ++iter) {
493         if ((*iter)->getTrackById(trackId))
494             return true;
495     }
496     return false;
497 }
498 
createDTMFSender(PassRefPtr<MediaStreamTrack> prpTrack,ExceptionState & exceptionState)499 PassRefPtr<RTCDTMFSender> RTCPeerConnection::createDTMFSender(PassRefPtr<MediaStreamTrack> prpTrack, ExceptionState& exceptionState)
500 {
501     if (m_signalingState == SignalingStateClosed) {
502         exceptionState.throwUninformativeAndGenericDOMException(InvalidStateError);
503         return 0;
504     }
505 
506     if (!prpTrack) {
507         exceptionState.throwUninformativeAndGenericTypeError();
508         return 0;
509     }
510 
511     RefPtr<MediaStreamTrack> track = prpTrack;
512 
513     if (!hasLocalStreamWithTrackId(track->id())) {
514         exceptionState.throwUninformativeAndGenericDOMException(SyntaxError);
515         return 0;
516     }
517 
518     RefPtr<RTCDTMFSender> dtmfSender = RTCDTMFSender::create(executionContext(), m_peerHandler.get(), track.release(), exceptionState);
519     if (exceptionState.hadException())
520         return 0;
521     return dtmfSender.release();
522 }
523 
close(ExceptionState & exceptionState)524 void RTCPeerConnection::close(ExceptionState& exceptionState)
525 {
526     if (m_signalingState == SignalingStateClosed) {
527         exceptionState.throwUninformativeAndGenericDOMException(InvalidStateError);
528         return;
529     }
530 
531     m_peerHandler->stop();
532 
533     changeIceConnectionState(IceConnectionStateClosed);
534     changeIceGatheringState(IceGatheringStateComplete);
535     changeSignalingState(SignalingStateClosed);
536 }
537 
negotiationNeeded()538 void RTCPeerConnection::negotiationNeeded()
539 {
540     scheduleDispatchEvent(Event::create(EventTypeNames::negotiationneeded));
541 }
542 
didGenerateIceCandidate(blink::WebRTCICECandidate webCandidate)543 void RTCPeerConnection::didGenerateIceCandidate(blink::WebRTCICECandidate webCandidate)
544 {
545     ASSERT(executionContext()->isContextThread());
546     if (webCandidate.isNull())
547         scheduleDispatchEvent(RTCIceCandidateEvent::create(false, false, 0));
548     else {
549         RefPtr<RTCIceCandidate> iceCandidate = RTCIceCandidate::create(webCandidate);
550         scheduleDispatchEvent(RTCIceCandidateEvent::create(false, false, iceCandidate.release()));
551     }
552 }
553 
didChangeSignalingState(SignalingState newState)554 void RTCPeerConnection::didChangeSignalingState(SignalingState newState)
555 {
556     ASSERT(executionContext()->isContextThread());
557     changeSignalingState(newState);
558 }
559 
didChangeIceGatheringState(IceGatheringState newState)560 void RTCPeerConnection::didChangeIceGatheringState(IceGatheringState newState)
561 {
562     ASSERT(executionContext()->isContextThread());
563     changeIceGatheringState(newState);
564 }
565 
didChangeIceConnectionState(IceConnectionState newState)566 void RTCPeerConnection::didChangeIceConnectionState(IceConnectionState newState)
567 {
568     ASSERT(executionContext()->isContextThread());
569     changeIceConnectionState(newState);
570 }
571 
didAddRemoteStream(PassRefPtr<MediaStreamDescriptor> streamDescriptor)572 void RTCPeerConnection::didAddRemoteStream(PassRefPtr<MediaStreamDescriptor> streamDescriptor)
573 {
574     ASSERT(executionContext()->isContextThread());
575 
576     if (m_signalingState == SignalingStateClosed)
577         return;
578 
579     RefPtr<MediaStream> stream = MediaStream::create(executionContext(), streamDescriptor);
580     m_remoteStreams.append(stream);
581 
582     scheduleDispatchEvent(MediaStreamEvent::create(EventTypeNames::addstream, false, false, stream.release()));
583 }
584 
didRemoveRemoteStream(MediaStreamDescriptor * streamDescriptor)585 void RTCPeerConnection::didRemoveRemoteStream(MediaStreamDescriptor* streamDescriptor)
586 {
587     ASSERT(executionContext()->isContextThread());
588     ASSERT(streamDescriptor->client());
589 
590     RefPtr<MediaStream> stream = static_cast<MediaStream*>(streamDescriptor->client());
591     stream->streamEnded();
592 
593     if (m_signalingState == SignalingStateClosed)
594         return;
595 
596     size_t pos = m_remoteStreams.find(stream);
597     ASSERT(pos != kNotFound);
598     m_remoteStreams.remove(pos);
599 
600     scheduleDispatchEvent(MediaStreamEvent::create(EventTypeNames::removestream, false, false, stream.release()));
601 }
602 
didAddRemoteDataChannel(PassOwnPtr<RTCDataChannelHandler> handler)603 void RTCPeerConnection::didAddRemoteDataChannel(PassOwnPtr<RTCDataChannelHandler> handler)
604 {
605     ASSERT(executionContext()->isContextThread());
606 
607     if (m_signalingState == SignalingStateClosed)
608         return;
609 
610     RefPtr<RTCDataChannel> channel = RTCDataChannel::create(executionContext(), handler);
611     m_dataChannels.append(channel);
612 
613     scheduleDispatchEvent(RTCDataChannelEvent::create(EventTypeNames::datachannel, false, false, channel.release()));
614 }
615 
interfaceName() const616 const AtomicString& RTCPeerConnection::interfaceName() const
617 {
618     return EventTargetNames::RTCPeerConnection;
619 }
620 
executionContext() const621 ExecutionContext* RTCPeerConnection::executionContext() const
622 {
623     return ActiveDOMObject::executionContext();
624 }
625 
suspend()626 void RTCPeerConnection::suspend()
627 {
628     m_dispatchScheduledEventRunner.suspend();
629 }
630 
resume()631 void RTCPeerConnection::resume()
632 {
633     m_dispatchScheduledEventRunner.resume();
634 }
635 
stop()636 void RTCPeerConnection::stop()
637 {
638     if (m_stopped)
639         return;
640 
641     m_stopped = true;
642     m_iceConnectionState = IceConnectionStateClosed;
643     m_signalingState = SignalingStateClosed;
644 
645     Vector<RefPtr<RTCDataChannel> >::iterator i = m_dataChannels.begin();
646     for (; i != m_dataChannels.end(); ++i)
647         (*i)->stop();
648 
649     m_dispatchScheduledEventRunner.stop();
650 }
651 
changeSignalingState(SignalingState signalingState)652 void RTCPeerConnection::changeSignalingState(SignalingState signalingState)
653 {
654     if (m_signalingState != SignalingStateClosed && m_signalingState != signalingState) {
655         m_signalingState = signalingState;
656         scheduleDispatchEvent(Event::create(EventTypeNames::signalingstatechange));
657     }
658 }
659 
changeIceGatheringState(IceGatheringState iceGatheringState)660 void RTCPeerConnection::changeIceGatheringState(IceGatheringState iceGatheringState)
661 {
662     m_iceGatheringState = iceGatheringState;
663 }
664 
changeIceConnectionState(IceConnectionState iceConnectionState)665 void RTCPeerConnection::changeIceConnectionState(IceConnectionState iceConnectionState)
666 {
667     if (m_iceConnectionState != IceConnectionStateClosed && m_iceConnectionState != iceConnectionState) {
668         m_iceConnectionState = iceConnectionState;
669         scheduleDispatchEvent(Event::create(EventTypeNames::iceconnectionstatechange));
670     }
671 }
672 
scheduleDispatchEvent(PassRefPtr<Event> event)673 void RTCPeerConnection::scheduleDispatchEvent(PassRefPtr<Event> event)
674 {
675     m_scheduledEvents.append(event);
676 
677     m_dispatchScheduledEventRunner.runAsync();
678 }
679 
dispatchScheduledEvent()680 void RTCPeerConnection::dispatchScheduledEvent()
681 {
682     if (m_stopped)
683         return;
684 
685     Vector<RefPtr<Event> > events;
686     events.swap(m_scheduledEvents);
687 
688     Vector<RefPtr<Event> >::iterator it = events.begin();
689     for (; it != events.end(); ++it)
690         dispatchEvent((*it).release());
691 
692     events.clear();
693 }
694 
695 } // namespace WebCore
696