Remove the Timer parameters from timer callbacks
[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 "MediaStreamEvent.h"
46 #include "RTCConfiguration.h"
47 #include "RTCDTMFSender.h"
48 #include "RTCDataChannel.h"
49 #include "RTCDataChannelEvent.h"
50 #include "RTCDataChannelHandler.h"
51 #include "RTCIceCandidate.h"
52 #include "RTCIceCandidateDescriptor.h"
53 #include "RTCIceCandidateEvent.h"
54 #include "RTCOfferAnswerOptions.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/MainThread.h>
66
67 namespace WebCore {
68
69 static bool validateIceServerURL(const String& iceURL)
70 {
71     URL url(URL(), iceURL);
72     if (url.isEmpty() || !url.isValid() || !(url.protocolIs("turn") || url.protocolIs("stun")))
73         return false;
74
75     return true;
76 }
77
78 static ExceptionCode processIceServer(const Dictionary& iceServer, RTCConfiguration* rtcConfiguration)
79 {
80     String credential, username;
81     iceServer.get("credential", credential);
82     iceServer.get("username", username);
83
84     // Spec says that "urls" can be either a string or a sequence, so we must check for both.
85     Vector<String> urlsList;
86     String urlString;
87     iceServer.get("urls", urlString);
88     // This is the only way to check if "urls" is a sequence or a string. If we try to convert
89     // to a sequence and it fails (in case it is a string), an exception will be set and the
90     // RTCPeerConnection will fail.
91     // So we convert to a string always, which converts a sequence to a string in the format: "foo, bar, ..",
92     // then checking for a comma in the string assures that a string was a sequence and then we convert
93     // it to a sequence safely.
94     if (urlString.isEmpty())
95         return INVALID_ACCESS_ERR;
96
97     if (urlString.find(',') != notFound && iceServer.get("urls", urlsList) && urlsList.size()) {
98         for (auto iter = urlsList.begin(); iter != urlsList.end(); ++iter) {
99             if (!validateIceServerURL(*iter))
100                 return INVALID_ACCESS_ERR;
101         }
102     } else {
103         if (!validateIceServerURL(urlString))
104             return INVALID_ACCESS_ERR;
105
106         urlsList.append(urlString);
107     }
108
109     rtcConfiguration->appendServer(RTCIceServer::create(urlsList, credential, username));
110     return 0;
111 }
112
113 PassRefPtr<RTCConfiguration> RTCPeerConnection::parseConfiguration(const Dictionary& configuration, ExceptionCode& ec)
114 {
115     if (configuration.isUndefinedOrNull())
116         return nullptr;
117
118     ArrayValue iceServers;
119     bool ok = configuration.get("iceServers", iceServers);
120     if (!ok || iceServers.isUndefinedOrNull()) {
121         ec = TYPE_MISMATCH_ERR;
122         return nullptr;
123     }
124
125     size_t numberOfServers;
126     ok = iceServers.length(numberOfServers);
127     if (!ok || !numberOfServers) {
128         ec = !ok ? TYPE_MISMATCH_ERR : INVALID_ACCESS_ERR;
129         return nullptr;
130     }
131
132     String iceTransports;
133     String requestIdentity;
134     configuration.get("iceTransports", iceTransports);
135     configuration.get("requestIdentity", requestIdentity);
136
137     RefPtr<RTCConfiguration> rtcConfiguration = RTCConfiguration::create();
138
139     rtcConfiguration->setIceTransports(iceTransports);
140     rtcConfiguration->setRequestIdentity(requestIdentity);
141
142     for (size_t i = 0; i < numberOfServers; ++i) {
143         Dictionary iceServer;
144         ok = iceServers.get(i, iceServer);
145         if (!ok) {
146             ec = TYPE_MISMATCH_ERR;
147             return nullptr;
148         }
149
150         ec = processIceServer(iceServer, rtcConfiguration.get());
151         if (ec)
152             return nullptr;
153     }
154
155     return rtcConfiguration.release();
156 }
157
158 PassRefPtr<RTCPeerConnection> RTCPeerConnection::create(ScriptExecutionContext& context, const Dictionary& rtcConfiguration, ExceptionCode& ec)
159 {
160     RefPtr<RTCConfiguration> configuration = parseConfiguration(rtcConfiguration, ec);
161     if (ec)
162         return nullptr;
163
164     RefPtr<RTCPeerConnection> peerConnection = adoptRef(new RTCPeerConnection(context, configuration.release(), ec));
165     peerConnection->suspendIfNeeded();
166     if (ec)
167         return nullptr;
168
169     return peerConnection.release();
170 }
171
172 RTCPeerConnection::RTCPeerConnection(ScriptExecutionContext& context, PassRefPtr<RTCConfiguration> configuration, ExceptionCode& ec)
173     : ActiveDOMObject(&context)
174     , m_signalingState(SignalingStateStable)
175     , m_iceGatheringState(IceGatheringStateNew)
176     , m_iceConnectionState(IceConnectionStateNew)
177     , m_scheduledEventtimer(*this, &RTCPeerConnection::scheduledEventTimerFired)
178     , m_configuration(configuration)
179     , m_stopped(false)
180 {
181     Document& document = downcast<Document>(context);
182
183     if (!document.frame()) {
184         ec = NOT_SUPPORTED_ERR;
185         return;
186     }
187
188     m_peerHandler = RTCPeerConnectionHandler::create(this);
189     if (!m_peerHandler) {
190         ec = NOT_SUPPORTED_ERR;
191         return;
192     }
193
194     document.frame()->loader().client().dispatchWillStartUsingPeerConnectionHandler(m_peerHandler.get());
195
196     if (!m_peerHandler->initialize(m_configuration->privateConfiguration())) {
197         ec = NOT_SUPPORTED_ERR;
198         return;
199     }
200 }
201
202 RTCPeerConnection::~RTCPeerConnection()
203 {
204     stop();
205
206     for (auto stream = m_localStreams.begin(), end = m_localStreams.end(); stream != end; ++stream)
207         (*stream)->removeObserver(this);
208 }
209
210 void RTCPeerConnection::createOffer(PassRefPtr<RTCSessionDescriptionCallback> successCallback, PassRefPtr<RTCPeerConnectionErrorCallback> errorCallback, const Dictionary& offerOptions, ExceptionCode& ec)
211 {
212     if (m_signalingState == SignalingStateClosed) {
213         ec = INVALID_STATE_ERR;
214         return;
215     }
216
217     if (!successCallback) {
218         ec = TYPE_MISMATCH_ERR;
219         return;
220     }
221
222     RefPtr<RTCOfferOptions> options = RTCOfferOptions::create(offerOptions, ec);
223     if (ec) {
224         callOnMainThread([=] {
225             RefPtr<DOMError> error = DOMError::create("Invalid createOffer argument.");
226             errorCallback->handleEvent(error.get());
227         });
228         return;
229     }
230
231     RefPtr<RTCSessionDescriptionRequestImpl> request = RTCSessionDescriptionRequestImpl::create(scriptExecutionContext(), successCallback, errorCallback);
232     m_peerHandler->createOffer(request.release(), options->privateOfferOptions());
233 }
234
235 void RTCPeerConnection::createAnswer(PassRefPtr<RTCSessionDescriptionCallback> successCallback, PassRefPtr<RTCPeerConnectionErrorCallback> errorCallback, const Dictionary& answerOptions, ExceptionCode& ec)
236 {
237     if (m_signalingState == SignalingStateClosed) {
238         ec = INVALID_STATE_ERR;
239         return;
240     }
241
242     if (!successCallback) {
243         ec = TYPE_MISMATCH_ERR;
244         return;
245     }
246
247     RefPtr<RTCOfferAnswerOptions> options = RTCOfferAnswerOptions::create(answerOptions, ec);
248     if (ec) {
249         callOnMainThread([=] {
250             RefPtr<DOMError> error = DOMError::create("Invalid createAnswer argument.");
251             errorCallback->handleEvent(error.get());
252         });
253         return;
254     }
255
256     RefPtr<RTCSessionDescriptionRequestImpl> request = RTCSessionDescriptionRequestImpl::create(scriptExecutionContext(), successCallback, errorCallback);
257     m_peerHandler->createAnswer(request.release(), options->privateOfferAnswerOptions());
258 }
259
260 bool RTCPeerConnection::checkStateForLocalDescription(RTCSessionDescription* localDescription)
261 {
262     if (localDescription->type() == "offer")
263         return m_signalingState == SignalingStateStable || m_signalingState == SignalingStateHaveLocalOffer;
264     if (localDescription->type() == "answer")
265         return m_signalingState == SignalingStateHaveRemoteOffer || m_signalingState == SignalingStateHaveLocalPrAnswer;
266     if (localDescription->type() == "pranswer")
267         return m_signalingState == SignalingStateHaveLocalPrAnswer || m_signalingState == SignalingStateHaveRemoteOffer;
268
269     return false;
270 }
271
272 bool RTCPeerConnection::checkStateForRemoteDescription(RTCSessionDescription* remoteDescription)
273 {
274     if (remoteDescription->type() == "offer")
275         return m_signalingState == SignalingStateStable || m_signalingState == SignalingStateHaveRemoteOffer;
276     if (remoteDescription->type() == "answer")
277         return m_signalingState == SignalingStateHaveLocalOffer || m_signalingState == SignalingStateHaveRemotePrAnswer;
278     if (remoteDescription->type() == "pranswer")
279         return m_signalingState == SignalingStateHaveRemotePrAnswer || m_signalingState == SignalingStateHaveLocalOffer;
280
281     return false;
282 }
283
284 void RTCPeerConnection::setLocalDescription(PassRefPtr<RTCSessionDescription> prpSessionDescription, PassRefPtr<VoidCallback> successCallback, PassRefPtr<RTCPeerConnectionErrorCallback> errorCallback, ExceptionCode& ec)
285 {
286     if (m_signalingState == SignalingStateClosed) {
287         ec = INVALID_STATE_ERR;
288         return;
289     }
290
291     RefPtr<RTCSessionDescription> sessionDescription = prpSessionDescription;
292     if (!sessionDescription) {
293         ec = TYPE_MISMATCH_ERR;
294         return;
295     }
296
297     if (!checkStateForLocalDescription(sessionDescription.get())) {
298         callOnMainThread([=] {
299             RefPtr<DOMError> error = DOMError::create(RTCPeerConnectionHandler::invalidSessionDescriptionErrorName());
300             errorCallback->handleEvent(error.get());
301         });
302         return;
303     }
304
305     RefPtr<RTCVoidRequestImpl> request = RTCVoidRequestImpl::create(scriptExecutionContext(), successCallback, errorCallback);
306     m_peerHandler->setLocalDescription(request.release(), sessionDescription->descriptor());
307 }
308
309 PassRefPtr<RTCSessionDescription> RTCPeerConnection::localDescription(ExceptionCode& ec)
310 {
311     RefPtr<RTCSessionDescriptionDescriptor> descriptor = m_peerHandler->localDescription();
312     if (!descriptor) {
313         ec = INVALID_STATE_ERR;
314         return nullptr;
315     }
316
317     RefPtr<RTCSessionDescription> sessionDescription = RTCSessionDescription::create(descriptor.release());
318     return sessionDescription.release();
319 }
320
321 void RTCPeerConnection::setRemoteDescription(PassRefPtr<RTCSessionDescription> prpSessionDescription, PassRefPtr<VoidCallback> successCallback, PassRefPtr<RTCPeerConnectionErrorCallback> errorCallback, ExceptionCode& ec)
322 {
323     if (m_signalingState == SignalingStateClosed) {
324         ec = INVALID_STATE_ERR;
325         return;
326     }
327
328     RefPtr<RTCSessionDescription> sessionDescription = prpSessionDescription;
329     if (!sessionDescription) {
330         ec = TYPE_MISMATCH_ERR;
331         return;
332     }
333
334     if (!checkStateForRemoteDescription(sessionDescription.get())) {
335         callOnMainThread([=] {
336             RefPtr<DOMError> error = DOMError::create(RTCPeerConnectionHandler::invalidSessionDescriptionErrorName());
337             errorCallback->handleEvent(error.get());
338         });
339         return;
340     }
341
342     RefPtr<RTCVoidRequestImpl> request = RTCVoidRequestImpl::create(scriptExecutionContext(), successCallback, errorCallback);
343     m_peerHandler->setRemoteDescription(request.release(), sessionDescription->descriptor());
344 }
345
346 PassRefPtr<RTCSessionDescription> RTCPeerConnection::remoteDescription(ExceptionCode& ec)
347 {
348     RefPtr<RTCSessionDescriptionDescriptor> descriptor = m_peerHandler->remoteDescription();
349     if (!descriptor) {
350         ec = INVALID_STATE_ERR;
351         return nullptr;
352     }
353
354     RefPtr<RTCSessionDescription> desc = RTCSessionDescription::create(descriptor.release());
355     return desc.release();
356 }
357
358 void RTCPeerConnection::updateIce(const Dictionary& rtcConfiguration, ExceptionCode& ec)
359 {
360     if (m_signalingState == SignalingStateClosed) {
361         ec = INVALID_STATE_ERR;
362         return;
363     }
364
365     m_configuration = parseConfiguration(rtcConfiguration, ec);
366     if (ec)
367         return;
368
369     bool valid = m_peerHandler->updateIce(m_configuration->privateConfiguration());
370     if (!valid)
371         ec = SYNTAX_ERR;
372 }
373
374 void RTCPeerConnection::addIceCandidate(RTCIceCandidate* iceCandidate, PassRefPtr<VoidCallback> successCallback, PassRefPtr<RTCPeerConnectionErrorCallback> errorCallback, ExceptionCode& ec)
375 {
376     if (m_signalingState == SignalingStateClosed) {
377         ec = INVALID_STATE_ERR;
378         return;
379     }
380
381     if (!iceCandidate || !successCallback || !errorCallback) {
382         ec = TYPE_MISMATCH_ERR;
383         return;
384     }
385
386     RefPtr<RTCVoidRequestImpl> request = RTCVoidRequestImpl::create(scriptExecutionContext(), successCallback, errorCallback);
387
388     bool implemented = m_peerHandler->addIceCandidate(request.release(), iceCandidate->descriptor());
389     if (!implemented)
390         ec = SYNTAX_ERR;
391 }
392
393 String RTCPeerConnection::signalingState() const
394 {
395     switch (m_signalingState) {
396     case SignalingStateStable:
397         return ASCIILiteral("stable");
398     case SignalingStateHaveLocalOffer:
399         return ASCIILiteral("have-local-offer");
400     case SignalingStateHaveRemoteOffer:
401         return ASCIILiteral("have-remote-offer");
402     case SignalingStateHaveLocalPrAnswer:
403         return ASCIILiteral("have-local-pranswer");
404     case SignalingStateHaveRemotePrAnswer:
405         return ASCIILiteral("have-remote-pranswer");
406     case SignalingStateClosed:
407         return ASCIILiteral("closed");
408     }
409
410     ASSERT_NOT_REACHED();
411     return String();
412 }
413
414 String RTCPeerConnection::iceGatheringState() const
415 {
416     switch (m_iceGatheringState) {
417     case IceGatheringStateNew:
418         return ASCIILiteral("new");
419     case IceGatheringStateGathering:
420         return ASCIILiteral("gathering");
421     case IceGatheringStateComplete:
422         return ASCIILiteral("complete");
423     }
424
425     ASSERT_NOT_REACHED();
426     return String();
427 }
428
429 String RTCPeerConnection::iceConnectionState() const
430 {
431     switch (m_iceConnectionState) {
432     case IceConnectionStateNew:
433         return ASCIILiteral("new");
434     case IceConnectionStateChecking:
435         return ASCIILiteral("checking");
436     case IceConnectionStateConnected:
437         return ASCIILiteral("connected");
438     case IceConnectionStateCompleted:
439         return ASCIILiteral("completed");
440     case IceConnectionStateFailed:
441         return ASCIILiteral("failed");
442     case IceConnectionStateDisconnected:
443         return ASCIILiteral("disconnected");
444     case IceConnectionStateClosed:
445         return ASCIILiteral("closed");
446     }
447
448     ASSERT_NOT_REACHED();
449     return String();
450 }
451
452 void RTCPeerConnection::addStream(PassRefPtr<MediaStream> prpStream, ExceptionCode& ec)
453 {
454     if (m_signalingState == SignalingStateClosed) {
455         ec = INVALID_STATE_ERR;
456         return;
457     }
458
459     RefPtr<MediaStream> stream = prpStream;
460     if (!stream) {
461         ec = TYPE_MISMATCH_ERR;
462         return;
463     }
464
465     if (m_localStreams.contains(stream))
466         return;
467
468     bool valid = m_peerHandler->addStream(stream->privateStream());
469     if (!valid)
470         ec = SYNTAX_ERR;
471     else {
472         m_localStreams.append(stream);
473         stream->addObserver(this);
474     }
475 }
476
477 void RTCPeerConnection::removeStream(PassRefPtr<MediaStream> prpStream, ExceptionCode& ec)
478 {
479     if (m_signalingState == SignalingStateClosed) {
480         ec = INVALID_STATE_ERR;
481         return;
482     }
483
484     if (!prpStream) {
485         ec = TYPE_MISMATCH_ERR;
486         return;
487     }
488
489     RefPtr<MediaStream> stream = prpStream;
490
491     size_t pos = m_localStreams.find(stream);
492     if (pos == notFound)
493         return;
494
495     m_localStreams.remove(pos);
496     stream->removeObserver(this);
497     m_peerHandler->removeStream(stream->privateStream());
498 }
499
500 RTCConfiguration* RTCPeerConnection::getConfiguration() const
501 {
502     return m_configuration.get();
503 }
504
505 Vector<RefPtr<MediaStream>> RTCPeerConnection::getLocalStreams() const
506 {
507     return m_localStreams;
508 }
509
510 Vector<RefPtr<MediaStream>> RTCPeerConnection::getRemoteStreams() const
511 {
512     return m_remoteStreams;
513 }
514
515 MediaStream* RTCPeerConnection::getStreamById(const String& streamId)
516 {
517     for (auto iter = m_localStreams.begin(); iter != m_localStreams.end(); ++iter) {
518         if ((*iter)->id() == streamId)
519             return iter->get();
520     }
521
522     for (auto iter = m_remoteStreams.begin(); iter != m_remoteStreams.end(); ++iter) {
523         if ((*iter)->id() == streamId)
524             return iter->get();
525     }
526
527     return nullptr;
528 }
529
530 void RTCPeerConnection::getStats(PassRefPtr<RTCStatsCallback> successCallback, PassRefPtr<RTCPeerConnectionErrorCallback> errorCallback, PassRefPtr<MediaStreamTrack> selector)
531 {
532     RefPtr<RTCStatsRequestImpl> statsRequest = RTCStatsRequestImpl::create(scriptExecutionContext(), successCallback, errorCallback, &selector->privateTrack());
533     // FIXME: Add passing selector as part of the statsRequest.
534     m_peerHandler->getStats(statsRequest.release());
535 }
536
537 PassRefPtr<RTCDataChannel> RTCPeerConnection::createDataChannel(String label, const Dictionary& options, ExceptionCode& ec)
538 {
539     if (m_signalingState == SignalingStateClosed) {
540         ec = INVALID_STATE_ERR;
541         return nullptr;
542     }
543
544     RefPtr<RTCDataChannel> channel = RTCDataChannel::create(scriptExecutionContext(), m_peerHandler.get(), label, options, ec);
545     if (ec)
546         return nullptr;
547
548     m_dataChannels.append(channel);
549     return channel.release();
550 }
551
552 bool RTCPeerConnection::hasLocalStreamWithTrackId(const String& trackId)
553 {
554     for (auto iter = m_localStreams.begin(); iter != m_localStreams.end(); ++iter) {
555         if ((*iter)->getTrackById(trackId))
556             return true;
557     }
558     return false;
559 }
560
561 PassRefPtr<RTCDTMFSender> RTCPeerConnection::createDTMFSender(PassRefPtr<MediaStreamTrack> prpTrack, ExceptionCode& ec)
562 {
563     if (m_signalingState == SignalingStateClosed) {
564         ec = INVALID_STATE_ERR;
565         return nullptr;
566     }
567
568     if (!prpTrack) {
569         ec = TypeError;
570         return nullptr;
571     }
572
573     RefPtr<MediaStreamTrack> track = prpTrack;
574
575     if (!hasLocalStreamWithTrackId(track->id())) {
576         ec = SYNTAX_ERR;
577         return nullptr;
578     }
579
580     RefPtr<RTCDTMFSender> dtmfSender = RTCDTMFSender::create(scriptExecutionContext(), m_peerHandler.get(), track.release(), ec);
581     if (ec)
582         return nullptr;
583     return dtmfSender.release();
584 }
585
586 void RTCPeerConnection::close(ExceptionCode& ec)
587 {
588     if (m_signalingState == SignalingStateClosed) {
589         ec = INVALID_STATE_ERR;
590         return;
591     }
592
593     m_peerHandler->stop();
594
595     changeIceConnectionState(IceConnectionStateClosed);
596     changeIceGatheringState(IceGatheringStateComplete);
597     changeSignalingState(SignalingStateClosed);
598 }
599
600 void RTCPeerConnection::negotiationNeeded()
601 {
602     scheduleDispatchEvent(Event::create(eventNames().negotiationneededEvent, false, false));
603 }
604
605 void RTCPeerConnection::didGenerateIceCandidate(PassRefPtr<RTCIceCandidateDescriptor> iceCandidateDescriptor)
606 {
607     ASSERT(scriptExecutionContext()->isContextThread());
608     if (!iceCandidateDescriptor)
609         scheduleDispatchEvent(RTCIceCandidateEvent::create(false, false, 0));
610     else {
611         RefPtr<RTCIceCandidate> iceCandidate = RTCIceCandidate::create(iceCandidateDescriptor);
612         scheduleDispatchEvent(RTCIceCandidateEvent::create(false, false, iceCandidate.release()));
613     }
614 }
615
616 void RTCPeerConnection::didChangeSignalingState(SignalingState newState)
617 {
618     ASSERT(scriptExecutionContext()->isContextThread());
619     changeSignalingState(newState);
620 }
621
622 void RTCPeerConnection::didChangeIceGatheringState(IceGatheringState newState)
623 {
624     ASSERT(scriptExecutionContext()->isContextThread());
625     changeIceGatheringState(newState);
626 }
627
628 void RTCPeerConnection::didChangeIceConnectionState(IceConnectionState newState)
629 {
630     ASSERT(scriptExecutionContext()->isContextThread());
631     changeIceConnectionState(newState);
632 }
633
634 void RTCPeerConnection::didAddRemoteStream(PassRefPtr<MediaStreamPrivate> privateStream)
635 {
636     ASSERT(scriptExecutionContext()->isContextThread());
637
638     if (m_signalingState == SignalingStateClosed)
639         return;
640
641     RefPtr<MediaStream> stream = MediaStream::create(*scriptExecutionContext(), privateStream);
642     m_remoteStreams.append(stream);
643
644     scheduleDispatchEvent(MediaStreamEvent::create(eventNames().addstreamEvent, false, false, stream.release()));
645 }
646
647 void RTCPeerConnection::didRemoveRemoteStream(MediaStreamPrivate* privateStream)
648 {
649     ASSERT(scriptExecutionContext()->isContextThread());
650     ASSERT(privateStream->client());
651
652     // FIXME: this class shouldn't know that the private stream client is a MediaStream!
653     RefPtr<MediaStream> stream = static_cast<MediaStream*>(privateStream->client());
654     stream->setActive(false);
655
656     if (m_signalingState == SignalingStateClosed)
657         return;
658
659     size_t pos = m_remoteStreams.find(stream);
660     ASSERT(pos != notFound);
661     m_remoteStreams.remove(pos);
662
663     scheduleDispatchEvent(MediaStreamEvent::create(eventNames().removestreamEvent, false, false, stream.release()));
664 }
665
666 void RTCPeerConnection::didAddRemoteDataChannel(std::unique_ptr<RTCDataChannelHandler> handler)
667 {
668     ASSERT(scriptExecutionContext()->isContextThread());
669
670     if (m_signalingState == SignalingStateClosed)
671         return;
672
673     RefPtr<RTCDataChannel> channel = RTCDataChannel::create(scriptExecutionContext(), WTF::move(handler));
674     m_dataChannels.append(channel);
675
676     scheduleDispatchEvent(RTCDataChannelEvent::create(eventNames().datachannelEvent, false, false, channel.release()));
677 }
678
679 void RTCPeerConnection::stop()
680 {
681     if (m_stopped)
682         return;
683
684     m_stopped = true;
685     m_iceConnectionState = IceConnectionStateClosed;
686     m_signalingState = SignalingStateClosed;
687
688     Vector<RefPtr<RTCDataChannel>>::iterator i = m_dataChannels.begin();
689     for (; i != m_dataChannels.end(); ++i)
690         (*i)->stop();
691 }
692
693 void RTCPeerConnection::didAddOrRemoveTrack()
694 {
695     negotiationNeeded();
696 }
697
698 void RTCPeerConnection::changeSignalingState(SignalingState signalingState)
699 {
700     if (m_signalingState != SignalingStateClosed && m_signalingState != signalingState) {
701         m_signalingState = signalingState;
702         scheduleDispatchEvent(Event::create(eventNames().signalingstatechangeEvent, false, false));
703     }
704 }
705
706 void RTCPeerConnection::changeIceGatheringState(IceGatheringState iceGatheringState)
707 {
708     m_iceGatheringState = iceGatheringState;
709 }
710
711 void RTCPeerConnection::changeIceConnectionState(IceConnectionState iceConnectionState)
712 {
713     if (m_iceConnectionState != IceConnectionStateClosed && m_iceConnectionState != iceConnectionState) {
714         m_iceConnectionState = iceConnectionState;
715         scheduleDispatchEvent(Event::create(eventNames().iceconnectionstatechangeEvent, false, false));
716     }
717 }
718
719 void RTCPeerConnection::scheduleDispatchEvent(PassRefPtr<Event> event)
720 {
721     m_scheduledEvents.append(event);
722
723     if (!m_scheduledEventTimer.isActive())
724         m_scheduledEventTimer.startOneShot(0);
725 }
726
727 void RTCPeerConnection::scheduledEventTimerFired()
728 {
729     if (m_stopped)
730         return;
731
732     Vector<RefPtr<Event>> events;
733     events.swap(m_scheduledEvents);
734
735     Vector<RefPtr<Event>>::iterator it = events.begin();
736     for (; it != events.end(); ++it)
737         dispatchEvent((*it).release());
738
739     events.clear();
740 }
741
742 } // namespace WebCore
743
744 #endif // ENABLE(MEDIA_STREAM)