bb895c92f736888c77e4836caeded595c145576d
[WebKit-https.git] / Source / WebCore / Modules / mediastream / RTCPeerConnection.cpp
1 /*
2  * Copyright (C) 2012 Google Inc. All rights reserved.
3  * Copyright (C) 2013 Nokia Corporation and/or its subsidiary(-ies).
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer
13  *    in the documentation and/or other materials provided with the
14  *    distribution.
15  * 3. Neither the name of Google Inc. nor the names of its contributors
16  *    may be used to endorse or promote products derived from this
17  *    software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
31
32 #include "config.h"
33
34 #if ENABLE(MEDIA_STREAM)
35
36 #include "RTCPeerConnection.h"
37
38 #include "ArrayValue.h"
39 #include "Document.h"
40 #include "Event.h"
41 #include "ExceptionCode.h"
42 #include "Frame.h"
43 #include "FrameLoader.h"
44 #include "FrameLoaderClient.h"
45 #include "MediaConstraintsImpl.h"
46 #include "MediaStreamEvent.h"
47 #include "RTCConfiguration.h"
48 #include "RTCDTMFSender.h"
49 #include "RTCDataChannel.h"
50 #include "RTCDataChannelEvent.h"
51 #include "RTCDataChannelHandler.h"
52 #include "RTCIceCandidate.h"
53 #include "RTCIceCandidateDescriptor.h"
54 #include "RTCIceCandidateEvent.h"
55 #include "RTCPeerConnectionErrorCallback.h"
56 #include "RTCSessionDescription.h"
57 #include "RTCSessionDescriptionCallback.h"
58 #include "RTCSessionDescriptionDescriptor.h"
59 #include "RTCSessionDescriptionRequestImpl.h"
60 #include "RTCStatsCallback.h"
61 #include "RTCStatsRequestImpl.h"
62 #include "RTCVoidRequestImpl.h"
63 #include "ScriptExecutionContext.h"
64 #include "VoidCallback.h"
65 #include <wtf/Functional.h>
66 #include <wtf/MainThread.h>
67
68 namespace WebCore {
69
70 PassRefPtr<RTCConfiguration> RTCPeerConnection::parseConfiguration(const Dictionary& configuration, ExceptionCode& ec)
71 {
72     if (configuration.isUndefinedOrNull())
73         return nullptr;
74
75     ArrayValue iceServers;
76     bool ok = configuration.get("iceServers", iceServers);
77     if (!ok || iceServers.isUndefinedOrNull()) {
78         ec = TYPE_MISMATCH_ERR;
79         return nullptr;
80     }
81
82     size_t numberOfServers;
83     ok = iceServers.length(numberOfServers);
84     if (!ok) {
85         ec = TYPE_MISMATCH_ERR;
86         return nullptr;
87     }
88
89     RefPtr<RTCConfiguration> rtcConfiguration = RTCConfiguration::create();
90
91     for (size_t i = 0; i < numberOfServers; ++i) {
92         Dictionary iceServer;
93         ok = iceServers.get(i, iceServer);
94         if (!ok) {
95             ec = TYPE_MISMATCH_ERR;
96             return nullptr;
97         }
98
99         String urlString, credential, username;
100         ok = iceServer.get("url", urlString);
101         if (!ok) {
102             ec = TYPE_MISMATCH_ERR;
103             return nullptr;
104         }
105         URL url(URL(), urlString);
106         if (!url.isValid() || !(url.protocolIs("turn") || url.protocolIs("stun"))) {
107             ec = TYPE_MISMATCH_ERR;
108             return nullptr;
109         }
110
111         iceServer.get("credential", credential);
112         iceServer.get("username", username);
113
114         rtcConfiguration->appendServer(RTCIceServer::create(url, credential, username));
115     }
116
117     return rtcConfiguration.release();
118 }
119
120 PassRefPtr<RTCPeerConnection> RTCPeerConnection::create(ScriptExecutionContext& context, const Dictionary& rtcConfiguration, const Dictionary& mediaConstraints, ExceptionCode& ec)
121 {
122     RefPtr<RTCConfiguration> configuration = parseConfiguration(rtcConfiguration, ec);
123     if (ec)
124         return nullptr;
125
126     RefPtr<MediaConstraints> constraints = MediaConstraintsImpl::create(mediaConstraints, ec);
127     if (ec)
128         return nullptr;
129
130     RefPtr<RTCPeerConnection> peerConnection = adoptRef(new RTCPeerConnection(context, configuration.release(), constraints.release(), ec));
131     peerConnection->suspendIfNeeded();
132     if (ec)
133         return nullptr;
134
135     return peerConnection.release();
136 }
137
138 RTCPeerConnection::RTCPeerConnection(ScriptExecutionContext& context, PassRefPtr<RTCConfiguration> configuration, PassRefPtr<MediaConstraints> constraints, ExceptionCode& ec)
139     : ActiveDOMObject(&context)
140     , m_signalingState(SignalingStateStable)
141     , m_iceGatheringState(IceGatheringStateNew)
142     , m_iceConnectionState(IceConnectionStateNew)
143     , m_scheduledEventTimer(this, &RTCPeerConnection::scheduledEventTimerFired)
144     , m_stopped(false)
145 {
146     Document& document = toDocument(context);
147
148     if (!document.frame()) {
149         ec = NOT_SUPPORTED_ERR;
150         return;
151     }
152
153     m_peerHandler = RTCPeerConnectionHandler::create(this);
154     if (!m_peerHandler) {
155         ec = NOT_SUPPORTED_ERR;
156         return;
157     }
158
159     document.frame()->loader().client().dispatchWillStartUsingPeerConnectionHandler(m_peerHandler.get());
160
161     if (!m_peerHandler->initialize(configuration, constraints)) {
162         ec = NOT_SUPPORTED_ERR;
163         return;
164     }
165 }
166
167 RTCPeerConnection::~RTCPeerConnection()
168 {
169     stop();
170
171     for (auto stream = m_localStreams.begin(), end = m_localStreams.end(); stream != end; ++stream)
172         (*stream)->removeObserver(this);
173 }
174
175 void RTCPeerConnection::createOffer(PassRefPtr<RTCSessionDescriptionCallback> successCallback, PassRefPtr<RTCPeerConnectionErrorCallback> errorCallback, const Dictionary& mediaConstraints, ExceptionCode& ec)
176 {
177     if (m_signalingState == SignalingStateClosed) {
178         ec = INVALID_STATE_ERR;
179         return;
180     }
181
182     if (!successCallback) {
183         ec = TYPE_MISMATCH_ERR;
184         return;
185     }
186
187     RefPtr<MediaConstraints> constraints = MediaConstraintsImpl::create(mediaConstraints, ec);
188     if (ec)
189         return;
190
191     RefPtr<RTCSessionDescriptionRequestImpl> request = RTCSessionDescriptionRequestImpl::create(scriptExecutionContext(), successCallback, errorCallback);
192     m_peerHandler->createOffer(request.release(), constraints);
193 }
194
195 void RTCPeerConnection::createAnswer(PassRefPtr<RTCSessionDescriptionCallback> successCallback, PassRefPtr<RTCPeerConnectionErrorCallback> errorCallback, const Dictionary& mediaConstraints, ExceptionCode& ec)
196 {
197     if (m_signalingState == SignalingStateClosed) {
198         ec = INVALID_STATE_ERR;
199         return;
200     }
201
202     if (!successCallback) {
203         ec = TYPE_MISMATCH_ERR;
204         return;
205     }
206
207     RefPtr<MediaConstraints> constraints = MediaConstraintsImpl::create(mediaConstraints, ec);
208     if (ec)
209         return;
210
211     RefPtr<RTCSessionDescriptionRequestImpl> request = RTCSessionDescriptionRequestImpl::create(scriptExecutionContext(), successCallback, errorCallback);
212     m_peerHandler->createAnswer(request.release(), constraints.release());
213 }
214
215 bool RTCPeerConnection::checkStateForLocalDescription(RTCSessionDescription* localDescription)
216 {
217     if (localDescription->type() == "offer")
218         return m_signalingState == SignalingStateStable || m_signalingState == SignalingStateHaveLocalOffer;
219     if (localDescription->type() == "answer")
220         return m_signalingState == SignalingStateHaveRemoteOffer || m_signalingState == SignalingStateHaveLocalPrAnswer;
221     if (localDescription->type() == "pranswer")
222         return m_signalingState == SignalingStateHaveLocalPrAnswer || m_signalingState == SignalingStateHaveRemoteOffer;
223
224     return false;
225 }
226
227 bool RTCPeerConnection::checkStateForRemoteDescription(RTCSessionDescription* remoteDescription)
228 {
229     if (remoteDescription->type() == "offer")
230         return m_signalingState == SignalingStateStable || m_signalingState == SignalingStateHaveRemoteOffer;
231     if (remoteDescription->type() == "answer")
232         return m_signalingState == SignalingStateHaveLocalOffer || m_signalingState == SignalingStateHaveRemotePrAnswer;
233     if (remoteDescription->type() == "pranswer")
234         return m_signalingState == SignalingStateHaveRemotePrAnswer || m_signalingState == SignalingStateHaveLocalOffer;
235
236     return false;
237 }
238
239 void RTCPeerConnection::setLocalDescription(PassRefPtr<RTCSessionDescription> prpSessionDescription, PassRefPtr<VoidCallback> successCallback, PassRefPtr<RTCPeerConnectionErrorCallback> errorCallback, ExceptionCode& ec)
240 {
241     if (m_signalingState == SignalingStateClosed) {
242         ec = INVALID_STATE_ERR;
243         return;
244     }
245
246     RefPtr<RTCSessionDescription> sessionDescription = prpSessionDescription;
247     if (!sessionDescription) {
248         ec = TYPE_MISMATCH_ERR;
249         return;
250     }
251
252     if (!checkStateForLocalDescription(sessionDescription.get())) {
253         RefPtr<DOMError> error = DOMError::create(RTCPeerConnectionHandler::invalidSessionDescriptionErrorName());
254         callOnMainThread(bind(&RTCPeerConnectionErrorCallback::handleEvent, errorCallback.get(), error.release()));
255         return;
256     }
257
258     RefPtr<RTCVoidRequestImpl> request = RTCVoidRequestImpl::create(scriptExecutionContext(), successCallback, errorCallback);
259     m_peerHandler->setLocalDescription(request.release(), sessionDescription->descriptor());
260 }
261
262 PassRefPtr<RTCSessionDescription> RTCPeerConnection::localDescription(ExceptionCode& ec)
263 {
264     RefPtr<RTCSessionDescriptionDescriptor> descriptor = m_peerHandler->localDescription();
265     if (!descriptor) {
266         ec = INVALID_STATE_ERR;
267         return nullptr;
268     }
269
270     RefPtr<RTCSessionDescription> sessionDescription = RTCSessionDescription::create(descriptor.release());
271     return sessionDescription.release();
272 }
273
274 void RTCPeerConnection::setRemoteDescription(PassRefPtr<RTCSessionDescription> prpSessionDescription, PassRefPtr<VoidCallback> successCallback, PassRefPtr<RTCPeerConnectionErrorCallback> errorCallback, ExceptionCode& ec)
275 {
276     if (m_signalingState == SignalingStateClosed) {
277         ec = INVALID_STATE_ERR;
278         return;
279     }
280
281     RefPtr<RTCSessionDescription> sessionDescription = prpSessionDescription;
282     if (!sessionDescription) {
283         ec = TYPE_MISMATCH_ERR;
284         return;
285     }
286
287     if (!checkStateForRemoteDescription(sessionDescription.get())) {
288         RefPtr<DOMError> error = DOMError::create(RTCPeerConnectionHandler::invalidSessionDescriptionErrorName());
289         callOnMainThread(bind(&RTCPeerConnectionErrorCallback::handleEvent, errorCallback.get(), error.release()));
290         return;
291     }
292
293     RefPtr<RTCVoidRequestImpl> request = RTCVoidRequestImpl::create(scriptExecutionContext(), successCallback, errorCallback);
294     m_peerHandler->setRemoteDescription(request.release(), sessionDescription->descriptor());
295 }
296
297 PassRefPtr<RTCSessionDescription> RTCPeerConnection::remoteDescription(ExceptionCode& ec)
298 {
299     RefPtr<RTCSessionDescriptionDescriptor> descriptor = m_peerHandler->remoteDescription();
300     if (!descriptor) {
301         ec = INVALID_STATE_ERR;
302         return nullptr;
303     }
304
305     RefPtr<RTCSessionDescription> desc = RTCSessionDescription::create(descriptor.release());
306     return desc.release();
307 }
308
309 void RTCPeerConnection::updateIce(const Dictionary& rtcConfiguration, const Dictionary& mediaConstraints, ExceptionCode& ec)
310 {
311     if (m_signalingState == SignalingStateClosed) {
312         ec = INVALID_STATE_ERR;
313         return;
314     }
315
316     RefPtr<RTCConfiguration> configuration = parseConfiguration(rtcConfiguration, ec);
317     if (ec)
318         return;
319
320     RefPtr<MediaConstraints> constraints = MediaConstraintsImpl::create(mediaConstraints, ec);
321     if (ec)
322         return;
323
324     bool valid = m_peerHandler->updateIce(configuration, constraints);
325     if (!valid)
326         ec = SYNTAX_ERR;
327 }
328
329 void RTCPeerConnection::addIceCandidate(RTCIceCandidate* iceCandidate, PassRefPtr<VoidCallback> successCallback, PassRefPtr<RTCPeerConnectionErrorCallback> errorCallback, ExceptionCode& ec)
330 {
331     if (m_signalingState == SignalingStateClosed) {
332         ec = INVALID_STATE_ERR;
333         return;
334     }
335
336     if (!iceCandidate || !successCallback || !errorCallback) {
337         ec = TYPE_MISMATCH_ERR;
338         return;
339     }
340
341     RefPtr<RTCVoidRequestImpl> request = RTCVoidRequestImpl::create(scriptExecutionContext(), successCallback, errorCallback);
342
343     bool implemented = m_peerHandler->addIceCandidate(request.release(), iceCandidate->descriptor());
344     if (!implemented)
345         ec = SYNTAX_ERR;
346 }
347
348 String RTCPeerConnection::signalingState() const
349 {
350     switch (m_signalingState) {
351     case SignalingStateStable:
352         return ASCIILiteral("stable");
353     case SignalingStateHaveLocalOffer:
354         return ASCIILiteral("have-local-offer");
355     case SignalingStateHaveRemoteOffer:
356         return ASCIILiteral("have-remote-offer");
357     case SignalingStateHaveLocalPrAnswer:
358         return ASCIILiteral("have-local-pranswer");
359     case SignalingStateHaveRemotePrAnswer:
360         return ASCIILiteral("have-remote-pranswer");
361     case SignalingStateClosed:
362         return ASCIILiteral("closed");
363     }
364
365     ASSERT_NOT_REACHED();
366     return String();
367 }
368
369 String RTCPeerConnection::iceGatheringState() const
370 {
371     switch (m_iceGatheringState) {
372     case IceGatheringStateNew:
373         return ASCIILiteral("new");
374     case IceGatheringStateGathering:
375         return ASCIILiteral("gathering");
376     case IceGatheringStateComplete:
377         return ASCIILiteral("complete");
378     }
379
380     ASSERT_NOT_REACHED();
381     return String();
382 }
383
384 String RTCPeerConnection::iceConnectionState() const
385 {
386     switch (m_iceConnectionState) {
387     case IceConnectionStateNew:
388         return ASCIILiteral("new");
389     case IceConnectionStateChecking:
390         return ASCIILiteral("checking");
391     case IceConnectionStateConnected:
392         return ASCIILiteral("connected");
393     case IceConnectionStateCompleted:
394         return ASCIILiteral("completed");
395     case IceConnectionStateFailed:
396         return ASCIILiteral("failed");
397     case IceConnectionStateDisconnected:
398         return ASCIILiteral("disconnected");
399     case IceConnectionStateClosed:
400         return ASCIILiteral("closed");
401     }
402
403     ASSERT_NOT_REACHED();
404     return String();
405 }
406
407 void RTCPeerConnection::addStream(PassRefPtr<MediaStream> prpStream, const Dictionary& mediaConstraints, ExceptionCode& ec)
408 {
409     if (m_signalingState == SignalingStateClosed) {
410         ec = INVALID_STATE_ERR;
411         return;
412     }
413
414     RefPtr<MediaStream> stream = prpStream;
415     if (!stream) {
416         ec = TYPE_MISMATCH_ERR;
417         return;
418     }
419
420     if (m_localStreams.contains(stream))
421         return;
422
423     RefPtr<MediaConstraints> constraints = MediaConstraintsImpl::create(mediaConstraints, ec);
424     if (ec)
425         return;
426
427     bool valid = m_peerHandler->addStream(stream->privateStream(), constraints);
428     if (!valid)
429         ec = SYNTAX_ERR;
430     else {
431         m_localStreams.append(stream);
432         stream->addObserver(this);
433     }
434 }
435
436 void RTCPeerConnection::removeStream(PassRefPtr<MediaStream> prpStream, ExceptionCode& ec)
437 {
438     if (m_signalingState == SignalingStateClosed) {
439         ec = INVALID_STATE_ERR;
440         return;
441     }
442
443     if (!prpStream) {
444         ec = TYPE_MISMATCH_ERR;
445         return;
446     }
447
448     RefPtr<MediaStream> stream = prpStream;
449
450     size_t pos = m_localStreams.find(stream);
451     if (pos == notFound)
452         return;
453
454     m_localStreams.remove(pos);
455     stream->removeObserver(this);
456     m_peerHandler->removeStream(stream->privateStream());
457 }
458
459 MediaStreamVector RTCPeerConnection::getLocalStreams() const
460 {
461     return m_localStreams;
462 }
463
464 MediaStreamVector RTCPeerConnection::getRemoteStreams() const
465 {
466     return m_remoteStreams;
467 }
468
469 MediaStream* RTCPeerConnection::getStreamById(const String& streamId)
470 {
471     for (MediaStreamVector::iterator iter = m_localStreams.begin(); iter != m_localStreams.end(); ++iter) {
472         if ((*iter)->id() == streamId)
473             return iter->get();
474     }
475
476     for (MediaStreamVector::iterator iter = m_remoteStreams.begin(); iter != m_remoteStreams.end(); ++iter) {
477         if ((*iter)->id() == streamId)
478             return iter->get();
479     }
480
481     return nullptr;
482 }
483
484 void RTCPeerConnection::getStats(PassRefPtr<RTCStatsCallback> successCallback, PassRefPtr<MediaStreamTrack> selector)
485 {
486     RefPtr<RTCStatsRequestImpl> statsRequest = RTCStatsRequestImpl::create(scriptExecutionContext(), successCallback, selector);
487     // FIXME: Add passing selector as part of the statsRequest.
488     m_peerHandler->getStats(statsRequest.release());
489 }
490
491 PassRefPtr<RTCDataChannel> RTCPeerConnection::createDataChannel(String label, const Dictionary& options, ExceptionCode& ec)
492 {
493     if (m_signalingState == SignalingStateClosed) {
494         ec = INVALID_STATE_ERR;
495         return nullptr;
496     }
497
498     RefPtr<RTCDataChannel> channel = RTCDataChannel::create(scriptExecutionContext(), m_peerHandler.get(), label, options, ec);
499     if (ec)
500         return nullptr;
501
502     m_dataChannels.append(channel);
503     return channel.release();
504 }
505
506 bool RTCPeerConnection::hasLocalStreamWithTrackId(const String& trackId)
507 {
508     for (MediaStreamVector::iterator iter = m_localStreams.begin(); iter != m_localStreams.end(); ++iter) {
509         if ((*iter)->getTrackById(trackId))
510             return true;
511     }
512     return false;
513 }
514
515 PassRefPtr<RTCDTMFSender> RTCPeerConnection::createDTMFSender(PassRefPtr<MediaStreamTrack> prpTrack, ExceptionCode& ec)
516 {
517     if (m_signalingState == SignalingStateClosed) {
518         ec = INVALID_STATE_ERR;
519         return nullptr;
520     }
521
522     if (!prpTrack) {
523         ec = TypeError;
524         return nullptr;
525     }
526
527     RefPtr<MediaStreamTrack> track = prpTrack;
528
529     if (!hasLocalStreamWithTrackId(track->id())) {
530         ec = SYNTAX_ERR;
531         return nullptr;
532     }
533
534     RefPtr<RTCDTMFSender> dtmfSender = RTCDTMFSender::create(scriptExecutionContext(), m_peerHandler.get(), track.release(), ec);
535     if (ec)
536         return nullptr;
537     return dtmfSender.release();
538 }
539
540 void RTCPeerConnection::close(ExceptionCode& ec)
541 {
542     if (m_signalingState == SignalingStateClosed) {
543         ec = INVALID_STATE_ERR;
544         return;
545     }
546
547     m_peerHandler->stop();
548
549     changeIceConnectionState(IceConnectionStateClosed);
550     changeIceGatheringState(IceGatheringStateComplete);
551     changeSignalingState(SignalingStateClosed);
552 }
553
554 void RTCPeerConnection::negotiationNeeded()
555 {
556     scheduleDispatchEvent(Event::create(eventNames().negotiationneededEvent, false, false));
557 }
558
559 void RTCPeerConnection::didGenerateIceCandidate(PassRefPtr<RTCIceCandidateDescriptor> iceCandidateDescriptor)
560 {
561     ASSERT(scriptExecutionContext()->isContextThread());
562     if (!iceCandidateDescriptor)
563         scheduleDispatchEvent(RTCIceCandidateEvent::create(false, false, 0));
564     else {
565         RefPtr<RTCIceCandidate> iceCandidate = RTCIceCandidate::create(iceCandidateDescriptor);
566         scheduleDispatchEvent(RTCIceCandidateEvent::create(false, false, iceCandidate.release()));
567     }
568 }
569
570 void RTCPeerConnection::didChangeSignalingState(SignalingState newState)
571 {
572     ASSERT(scriptExecutionContext()->isContextThread());
573     changeSignalingState(newState);
574 }
575
576 void RTCPeerConnection::didChangeIceGatheringState(IceGatheringState newState)
577 {
578     ASSERT(scriptExecutionContext()->isContextThread());
579     changeIceGatheringState(newState);
580 }
581
582 void RTCPeerConnection::didChangeIceConnectionState(IceConnectionState newState)
583 {
584     ASSERT(scriptExecutionContext()->isContextThread());
585     changeIceConnectionState(newState);
586 }
587
588 void RTCPeerConnection::didAddRemoteStream(PassRefPtr<MediaStreamPrivate> privateStream)
589 {
590     ASSERT(scriptExecutionContext()->isContextThread());
591
592     if (m_signalingState == SignalingStateClosed)
593         return;
594
595     RefPtr<MediaStream> stream = MediaStream::create(*scriptExecutionContext(), privateStream);
596     m_remoteStreams.append(stream);
597
598     scheduleDispatchEvent(MediaStreamEvent::create(eventNames().addstreamEvent, false, false, stream.release()));
599 }
600
601 void RTCPeerConnection::didRemoveRemoteStream(MediaStreamPrivate* privateStream)
602 {
603     ASSERT(scriptExecutionContext()->isContextThread());
604     ASSERT(privateStream->client());
605
606     // FIXME: this class shouldn't know that the private stream client is a MediaStream!
607     RefPtr<MediaStream> stream = static_cast<MediaStream*>(privateStream->client());
608     stream->setEnded();
609
610     if (m_signalingState == SignalingStateClosed)
611         return;
612
613     size_t pos = m_remoteStreams.find(stream);
614     ASSERT(pos != notFound);
615     m_remoteStreams.remove(pos);
616
617     scheduleDispatchEvent(MediaStreamEvent::create(eventNames().removestreamEvent, false, false, stream.release()));
618 }
619
620 void RTCPeerConnection::didAddRemoteDataChannel(std::unique_ptr<RTCDataChannelHandler> handler)
621 {
622     ASSERT(scriptExecutionContext()->isContextThread());
623
624     if (m_signalingState == SignalingStateClosed)
625         return;
626
627     RefPtr<RTCDataChannel> channel = RTCDataChannel::create(scriptExecutionContext(), std::move(handler));
628     m_dataChannels.append(channel);
629
630     scheduleDispatchEvent(RTCDataChannelEvent::create(eventNames().datachannelEvent, false, false, channel.release()));
631 }
632
633 void RTCPeerConnection::stop()
634 {
635     if (m_stopped)
636         return;
637
638     m_stopped = true;
639     m_iceConnectionState = IceConnectionStateClosed;
640     m_signalingState = SignalingStateClosed;
641
642     Vector<RefPtr<RTCDataChannel>>::iterator i = m_dataChannels.begin();
643     for (; i != m_dataChannels.end(); ++i)
644         (*i)->stop();
645 }
646
647 void RTCPeerConnection::didAddOrRemoveTrack()
648 {
649     negotiationNeeded();
650 }
651
652 void RTCPeerConnection::changeSignalingState(SignalingState signalingState)
653 {
654     if (m_signalingState != SignalingStateClosed && m_signalingState != signalingState) {
655         m_signalingState = signalingState;
656         scheduleDispatchEvent(Event::create(eventNames().signalingstatechangeEvent, false, false));
657     }
658 }
659
660 void RTCPeerConnection::changeIceGatheringState(IceGatheringState iceGatheringState)
661 {
662     m_iceGatheringState = iceGatheringState;
663 }
664
665 void RTCPeerConnection::changeIceConnectionState(IceConnectionState iceConnectionState)
666 {
667     if (m_iceConnectionState != IceConnectionStateClosed && m_iceConnectionState != iceConnectionState) {
668         m_iceConnectionState = iceConnectionState;
669         scheduleDispatchEvent(Event::create(eventNames().iceconnectionstatechangeEvent, false, false));
670     }
671 }
672
673 void RTCPeerConnection::scheduleDispatchEvent(PassRefPtr<Event> event)
674 {
675     m_scheduledEvents.append(event);
676
677     if (!m_scheduledEventTimer.isActive())
678         m_scheduledEventTimer.startOneShot(0);
679 }
680
681 void RTCPeerConnection::scheduledEventTimerFired(Timer<RTCPeerConnection>*)
682 {
683     if (m_stopped)
684         return;
685
686     Vector<RefPtr<Event>> events;
687     events.swap(m_scheduledEvents);
688
689     Vector<RefPtr<Event>>::iterator it = events.begin();
690     for (; it != events.end(); ++it)
691         dispatchEvent((*it).release());
692
693     events.clear();
694 }
695
696 } // namespace WebCore
697
698 #endif // ENABLE(MEDIA_STREAM)