Tighten up some of the drag state machine logic
[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  * Copyright (C) 2015, 2016 Ericsson AB. All rights reserved.
5  * Copyright (C) 2017 Apple Inc. All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer
15  *    in the documentation and/or other materials provided with the
16  *    distribution.
17  * 3. Neither the name of Google Inc. nor the names of its contributors
18  *    may be used to endorse or promote products derived from this
19  *    software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33
34 #include "config.h"
35 #include "RTCPeerConnection.h"
36
37 #if ENABLE(WEB_RTC)
38
39 #include "Document.h"
40 #include "Event.h"
41 #include "EventNames.h"
42 #include "Frame.h"
43 #include "JSDOMPromiseDeferred.h"
44 #include "JSRTCPeerConnection.h"
45 #include "Logging.h"
46 #include "MediaEndpointConfiguration.h"
47 #include "MediaStream.h"
48 #include "MediaStreamTrack.h"
49 #include "Page.h"
50 #include "RTCConfiguration.h"
51 #include "RTCController.h"
52 #include "RTCDataChannel.h"
53 #include "RTCIceCandidate.h"
54 #include "RTCPeerConnectionIceEvent.h"
55 #include "RTCSessionDescription.h"
56 #include "Settings.h"
57 #include <wtf/CryptographicallyRandomNumber.h>
58 #include <wtf/IsoMallocInlines.h>
59 #include <wtf/MainThread.h>
60 #include <wtf/UUID.h>
61 #include <wtf/text/Base64.h>
62
63 namespace WebCore {
64
65 using namespace PeerConnection;
66
67 WTF_MAKE_ISO_ALLOCATED_IMPL(RTCPeerConnection);
68
69 Ref<RTCPeerConnection> RTCPeerConnection::create(ScriptExecutionContext& context)
70 {
71     auto& document = downcast<Document>(context);
72     auto peerConnection = adoptRef(*new RTCPeerConnection(document));
73     peerConnection->suspendIfNeeded();
74     if (!peerConnection->isClosed()) {
75         if (auto* page = document.page()) {
76             peerConnection->registerToController(page->rtcController());
77             page->libWebRTCProvider().setEnableLogging(!page->sessionID().isEphemeral());
78         }
79     }
80     return peerConnection;
81 }
82
83 RTCPeerConnection::RTCPeerConnection(Document& document)
84     : ActiveDOMObject(document)
85 #if !RELEASE_LOG_DISABLED
86     , m_logger(document.logger())
87     , m_logIdentifier(reinterpret_cast<const void*>(cryptographicallyRandomNumber()))
88 #endif
89     , m_backend(PeerConnectionBackend::create(*this))
90 {
91     ALWAYS_LOG(LOGIDENTIFIER);
92
93 #if !RELEASE_LOG_DISABLED
94     auto* page = document.page();
95     if (page && !page->settings().webRTCEncryptionEnabled())
96         ALWAYS_LOG(LOGIDENTIFIER, "encryption is disabled");
97 #endif
98
99     if (!m_backend)
100         m_connectionState = RTCPeerConnectionState::Closed;
101 }
102
103 RTCPeerConnection::~RTCPeerConnection()
104 {
105     ALWAYS_LOG(LOGIDENTIFIER);
106     unregisterFromController();
107     stop();
108 }
109
110 ExceptionOr<void> RTCPeerConnection::initializeWith(Document& document, RTCConfiguration&& configuration)
111 {
112     if (!document.frame())
113         return Exception { NotSupportedError };
114
115     if (!m_backend)
116         return Exception { NotSupportedError };
117
118     return initializeConfiguration(WTFMove(configuration));
119 }
120
121 ExceptionOr<Ref<RTCRtpSender>> RTCPeerConnection::addTrack(Ref<MediaStreamTrack>&& track, const Vector<std::reference_wrapper<MediaStream>>& streams)
122 {
123     INFO_LOG(LOGIDENTIFIER);
124
125     if (isClosed())
126         return Exception { InvalidStateError };
127
128     for (auto& transceiver : m_transceiverSet->list()) {
129         if (transceiver->sender().trackId() == track->id())
130             return Exception { InvalidAccessError };
131     }
132
133     Vector<String> mediaStreamIds;
134     for (auto stream : streams)
135         mediaStreamIds.append(stream.get().id());
136
137     return m_backend->addTrack(track.get(), WTFMove(mediaStreamIds));
138 }
139
140 ExceptionOr<void> RTCPeerConnection::removeTrack(RTCRtpSender& sender)
141 {
142     INFO_LOG(LOGIDENTIFIER);
143
144     if (isClosed())
145         return Exception { InvalidStateError, "RTCPeerConnection is closed"_s };
146
147     if (!sender.isCreatedBy(*m_backend))
148         return Exception { InvalidAccessError, "RTCPeerConnection did not create the given sender"_s };
149
150     bool shouldAbort = true;
151     RTCRtpTransceiver* senderTransceiver = nullptr;
152     for (auto& transceiver : m_transceiverSet->list()) {
153         if (&sender == &transceiver->sender()) {
154             senderTransceiver = transceiver.get();
155             shouldAbort = sender.isStopped() || !sender.track();
156             break;
157         }
158     }
159     if (shouldAbort)
160         return { };
161
162     sender.setTrackToNull();
163     senderTransceiver->disableSendingDirection();
164     m_backend->removeTrack(sender);
165     return { };
166 }
167
168 ExceptionOr<Ref<RTCRtpTransceiver>> RTCPeerConnection::addTransceiver(AddTransceiverTrackOrKind&& withTrack, const RTCRtpTransceiverInit& init)
169 {
170     INFO_LOG(LOGIDENTIFIER);
171
172     if (WTF::holds_alternative<String>(withTrack)) {
173         const String& kind = WTF::get<String>(withTrack);
174         if (kind != "audio"_s && kind != "video"_s)
175             return Exception { TypeError };
176
177         if (isClosed())
178             return Exception { InvalidStateError };
179
180         return m_backend->addTransceiver(kind, init);
181     }
182
183     if (isClosed())
184         return Exception { InvalidStateError };
185
186     auto track = WTF::get<RefPtr<MediaStreamTrack>>(withTrack).releaseNonNull();
187     return m_backend->addTransceiver(WTFMove(track), init);
188 }
189
190 void RTCPeerConnection::queuedCreateOffer(RTCOfferOptions&& options, SessionDescriptionPromise&& promise)
191 {
192     ALWAYS_LOG(LOGIDENTIFIER);
193     if (isClosed()) {
194         promise.reject(InvalidStateError);
195         return;
196     }
197
198     addPendingPromise(promise);
199     m_backend->createOffer(WTFMove(options), WTFMove(promise));
200 }
201
202 void RTCPeerConnection::queuedCreateAnswer(RTCAnswerOptions&& options, SessionDescriptionPromise&& promise)
203 {
204     ALWAYS_LOG(LOGIDENTIFIER);
205     if (isClosed()) {
206         promise.reject(InvalidStateError);
207         return;
208     }
209
210     addPendingPromise(promise);
211     m_backend->createAnswer(WTFMove(options), WTFMove(promise));
212 }
213
214 void RTCPeerConnection::queuedSetLocalDescription(RTCSessionDescription& description, DOMPromiseDeferred<void>&& promise)
215 {
216     ALWAYS_LOG(LOGIDENTIFIER, "Setting local description to:\n", description.sdp());
217     if (isClosed()) {
218         promise.reject(InvalidStateError);
219         return;
220     }
221
222     addPendingPromise(promise);
223     m_backend->setLocalDescription(description, WTFMove(promise));
224 }
225
226 RefPtr<RTCSessionDescription> RTCPeerConnection::localDescription() const
227 {
228     return m_backend->localDescription();
229 }
230
231 RefPtr<RTCSessionDescription> RTCPeerConnection::currentLocalDescription() const
232 {
233     return m_backend->currentLocalDescription();
234 }
235
236 RefPtr<RTCSessionDescription> RTCPeerConnection::pendingLocalDescription() const
237 {
238     return m_backend->pendingLocalDescription();
239 }
240
241 void RTCPeerConnection::queuedSetRemoteDescription(RTCSessionDescription& description, DOMPromiseDeferred<void>&& promise)
242 {
243     ALWAYS_LOG(LOGIDENTIFIER, "Setting remote description to:\n", description.sdp());
244
245     if (isClosed()) {
246         promise.reject(InvalidStateError);
247         return;
248     }
249     addPendingPromise(promise);
250     m_backend->setRemoteDescription(description, WTFMove(promise));
251 }
252
253 RefPtr<RTCSessionDescription> RTCPeerConnection::remoteDescription() const
254 {
255     return m_backend->remoteDescription();
256 }
257
258 RefPtr<RTCSessionDescription> RTCPeerConnection::currentRemoteDescription() const
259 {
260     return m_backend->currentRemoteDescription();
261 }
262
263 RefPtr<RTCSessionDescription> RTCPeerConnection::pendingRemoteDescription() const
264 {
265     return m_backend->pendingRemoteDescription();
266 }
267
268 void RTCPeerConnection::queuedAddIceCandidate(RTCIceCandidate* rtcCandidate, DOMPromiseDeferred<void>&& promise)
269 {
270     ALWAYS_LOG(LOGIDENTIFIER, "Received ice candidate:\n", rtcCandidate ? rtcCandidate->candidate() : "null");
271
272     if (isClosed()) {
273         promise.reject(InvalidStateError);
274         return;
275     }
276
277     addPendingPromise(promise);
278     m_backend->addIceCandidate(rtcCandidate, WTFMove(promise));
279 }
280
281 // Implementation of https://w3c.github.io/webrtc-pc/#set-pc-configuration
282 static inline ExceptionOr<Vector<MediaEndpointConfiguration::IceServerInfo>> iceServersFromConfiguration(RTCConfiguration& newConfiguration, const RTCConfiguration* existingConfiguration, bool isLocalDescriptionSet)
283 {
284     if (existingConfiguration && newConfiguration.bundlePolicy != existingConfiguration->bundlePolicy)
285         return Exception { InvalidModificationError, "BundlePolicy does not match existing policy" };
286
287     if (existingConfiguration && newConfiguration.rtcpMuxPolicy != existingConfiguration->rtcpMuxPolicy)
288         return Exception { InvalidModificationError, "RTCPMuxPolicy does not match existing policy" };
289
290     if (existingConfiguration && newConfiguration.iceCandidatePoolSize != existingConfiguration->iceCandidatePoolSize && isLocalDescriptionSet)
291         return Exception { InvalidModificationError, "IceTransportPolicy pool size does not match existing pool size" };
292
293     Vector<MediaEndpointConfiguration::IceServerInfo> servers;
294     if (newConfiguration.iceServers) {
295         servers.reserveInitialCapacity(newConfiguration.iceServers->size());
296         for (auto& server : newConfiguration.iceServers.value()) {
297             Vector<URL> serverURLs;
298             WTF::switchOn(server.urls, [&serverURLs] (const String& string) {
299                 serverURLs.reserveInitialCapacity(1);
300                 serverURLs.uncheckedAppend(URL { URL { }, string });
301             }, [&serverURLs] (const Vector<String>& vector) {
302                 serverURLs.reserveInitialCapacity(vector.size());
303                 for (auto& string : vector)
304                     serverURLs.uncheckedAppend(URL { URL { }, string });
305             });
306             for (auto& serverURL : serverURLs) {
307                 if (serverURL.isNull())
308                     return Exception { TypeError, "Bad ICE server URL" };
309                 if (serverURL.protocolIs("turn") || serverURL.protocolIs("turns")) {
310                     if (server.credential.isNull() || server.username.isNull())
311                         return Exception { InvalidAccessError, "TURN/TURNS server requires both username and credential" };
312                 } else if (!serverURL.protocolIs("stun"))
313                     return Exception { NotSupportedError, "ICE server protocol not supported" };
314             }
315             if (serverURLs.size())
316                 servers.uncheckedAppend({ WTFMove(serverURLs), server.credential, server.username });
317         }
318     }
319     return servers;
320 }
321
322 ExceptionOr<Vector<MediaEndpointConfiguration::CertificatePEM>> RTCPeerConnection::certificatesFromConfiguration(const RTCConfiguration& configuration)
323 {
324     auto currentMilliSeconds = WallTime::now().secondsSinceEpoch().milliseconds();
325     auto& origin = document()->securityOrigin();
326
327     Vector<MediaEndpointConfiguration::CertificatePEM> certificates;
328     certificates.reserveInitialCapacity(configuration.certificates.size());
329     for (auto& certificate : configuration.certificates) {
330         if (!origin.isSameOriginAs(certificate->origin()))
331             return Exception { InvalidAccessError, "Certificate does not have a valid origin" };
332
333         if (currentMilliSeconds > certificate->expires())
334             return Exception { InvalidAccessError, "Certificate has expired"_s };
335
336         certificates.uncheckedAppend(MediaEndpointConfiguration::CertificatePEM { certificate->pemCertificate(), certificate->pemPrivateKey(), });
337     }
338     return certificates;
339 }
340
341 ExceptionOr<void> RTCPeerConnection::initializeConfiguration(RTCConfiguration&& configuration)
342 {
343     INFO_LOG(LOGIDENTIFIER);
344
345     auto servers = iceServersFromConfiguration(configuration, nullptr, false);
346     if (servers.hasException())
347         return servers.releaseException();
348
349     auto certificates = certificatesFromConfiguration(configuration);
350     if (certificates.hasException())
351         return certificates.releaseException();
352
353     if (!m_backend->setConfiguration({ servers.releaseReturnValue(), configuration.iceTransportPolicy, configuration.bundlePolicy, configuration.rtcpMuxPolicy, configuration.iceCandidatePoolSize, certificates.releaseReturnValue() }))
354         return Exception { InvalidAccessError, "Bad Configuration Parameters" };
355
356     m_configuration = WTFMove(configuration);
357     return { };
358 }
359
360 ExceptionOr<void> RTCPeerConnection::setConfiguration(RTCConfiguration&& configuration)
361 {
362     if (isClosed())
363         return Exception { InvalidStateError };
364
365     INFO_LOG(LOGIDENTIFIER);
366
367     auto servers = iceServersFromConfiguration(configuration, &m_configuration, m_backend->isLocalDescriptionSet());
368     if (servers.hasException())
369         return servers.releaseException();
370
371     if (configuration.certificates.size()) {
372         if (configuration.certificates.size() != m_configuration.certificates.size())
373             return Exception { InvalidModificationError, "Certificates parameters are different" };
374
375         for (auto& certificate : configuration.certificates) {
376             bool isThere = m_configuration.certificates.findMatching([&certificate](const auto& item) {
377                 return item.get() == certificate.get();
378             }) != notFound;
379             if (!isThere)
380                 return Exception { InvalidModificationError, "A certificate given in constructor is not present" };
381         }
382     }
383
384     if (!m_backend->setConfiguration({ servers.releaseReturnValue(), configuration.iceTransportPolicy, configuration.bundlePolicy, configuration.rtcpMuxPolicy, configuration.iceCandidatePoolSize, { } }))
385         return Exception { InvalidAccessError, "Bad Configuration Parameters" };
386
387     m_configuration = WTFMove(configuration);
388     return { };
389 }
390
391 void RTCPeerConnection::getStats(MediaStreamTrack* selector, Ref<DeferredPromise>&& promise)
392 {
393     if (selector) {
394         for (auto& transceiver : m_transceiverSet->list()) {
395             if (transceiver->sender().track() == selector) {
396                 m_backend->getStats(transceiver->sender(), WTFMove(promise));
397                 return;
398             }
399             if (&transceiver->receiver().track() == selector) {
400                 m_backend->getStats(transceiver->receiver(), WTFMove(promise));
401                 return;
402             }
403         }
404     }
405     addPendingPromise(promise.get());
406     m_backend->getStats(WTFMove(promise));
407 }
408
409 ExceptionOr<Ref<RTCDataChannel>> RTCPeerConnection::createDataChannel(String&& label, RTCDataChannelInit&& options)
410 {
411     ALWAYS_LOG(LOGIDENTIFIER);
412
413     if (isClosed())
414         return Exception { InvalidStateError };
415
416     if (options.negotiated && !options.negotiated.value() && (label.length() > 65535 || options.protocol.length() > 65535))
417         return Exception { TypeError };
418
419     if (options.maxPacketLifeTime && options.maxRetransmits)
420         return Exception { TypeError };
421
422     if (options.id && options.id.value() > 65534)
423         return Exception { TypeError };
424     
425     auto channelHandler = m_backend->createDataChannelHandler(label, options);
426     if (!channelHandler)
427         return Exception { NotSupportedError };
428
429     return RTCDataChannel::create(*document(), WTFMove(channelHandler), WTFMove(label), WTFMove(options));
430 }
431
432 bool RTCPeerConnection::doClose()
433 {
434     if (isClosed())
435         return false;
436
437     m_shouldDelayTasks = false;
438     m_connectionState = RTCPeerConnectionState::Closed;
439     m_iceConnectionState = RTCIceConnectionState::Closed;
440     m_signalingState = RTCSignalingState::Closed;
441
442     for (auto& transceiver : m_transceiverSet->list()) {
443         transceiver->stop();
444         transceiver->sender().stop();
445         transceiver->receiver().stop();
446     }
447
448     return true;
449 }
450
451 void RTCPeerConnection::close()
452 {
453     if (!doClose())
454         return;
455
456     updateConnectionState();
457     ASSERT(isClosed());
458     m_backend->close();
459 }
460
461 void RTCPeerConnection::emulatePlatformEvent(const String& action)
462 {
463     m_backend->emulatePlatformEvent(action);
464 }
465
466 void RTCPeerConnection::stop()
467 {
468     doClose();
469     doStop();
470 }
471
472 void RTCPeerConnection::doStop()
473 {
474     if (m_isStopped)
475         return;
476
477     m_isStopped = true;
478     if (m_backend)
479         m_backend->stop();
480 }
481
482 void RTCPeerConnection::registerToController(RTCController& controller)
483 {
484     m_controller = &controller;
485     m_controller->add(*this);
486 }
487
488 void RTCPeerConnection::unregisterFromController()
489 {
490     if (m_controller)
491         m_controller->remove(*this);
492 }
493
494 const char* RTCPeerConnection::activeDOMObjectName() const
495 {
496     return "RTCPeerConnection";
497 }
498
499 void RTCPeerConnection::suspend(ReasonForSuspension reason)
500 {
501     if (reason != ReasonForSuspension::BackForwardCache)
502         return;
503
504     m_shouldDelayTasks = true;
505     m_backend->suspend();
506 }
507
508 void RTCPeerConnection::resume()
509 {
510     if (!m_shouldDelayTasks)
511         return;
512
513     m_shouldDelayTasks = false;
514     m_backend->resume();
515
516     scriptExecutionContext()->postTask([this, protectedThis = makeRef(*this)](auto&) {
517         if (m_isStopped || m_shouldDelayTasks)
518             return;
519
520         auto tasks = WTFMove(m_pendingTasks);
521         for (auto& task : tasks)
522             task();
523     });
524 }
525
526 bool RTCPeerConnection::hasPendingActivity() const
527 {
528     if (m_isStopped)
529         return false;
530
531     // This returns true if we have pending promises to be resolved.
532     if (ActiveDOMObject::hasPendingActivity())
533         return true;
534
535     // As long as the connection is not stopped and it has event listeners, it may dispatch events.
536     return hasEventListeners();
537 }
538
539 void RTCPeerConnection::addTransceiver(Ref<RTCRtpTransceiver>&& transceiver)
540 {
541     INFO_LOG(LOGIDENTIFIER);
542     m_transceiverSet->append(WTFMove(transceiver));
543 }
544
545 void RTCPeerConnection::setSignalingState(RTCSignalingState newState)
546 {
547     ALWAYS_LOG(LOGIDENTIFIER, newState);
548     m_signalingState = newState;
549 }
550
551 void RTCPeerConnection::updateIceGatheringState(RTCIceGatheringState newState)
552 {
553     ALWAYS_LOG(LOGIDENTIFIER, newState);
554
555     scriptExecutionContext()->postTask([protectedThis = makeRef(*this), newState](ScriptExecutionContext&) {
556         if (protectedThis->isClosed() || protectedThis->m_iceGatheringState == newState)
557             return;
558
559         protectedThis->m_iceGatheringState = newState;
560         protectedThis->dispatchEventWhenFeasible(Event::create(eventNames().icegatheringstatechangeEvent, Event::CanBubble::No, Event::IsCancelable::No));
561         protectedThis->updateConnectionState();
562     });
563 }
564
565 void RTCPeerConnection::updateIceConnectionState(RTCIceConnectionState newState)
566 {
567     ALWAYS_LOG(LOGIDENTIFIER, newState);
568
569     scriptExecutionContext()->postTask([protectedThis = makeRef(*this), newState](ScriptExecutionContext&) {
570         if (protectedThis->isClosed() || protectedThis->m_iceConnectionState == newState)
571             return;
572
573         protectedThis->m_iceConnectionState = newState;
574         protectedThis->dispatchEventWhenFeasible(Event::create(eventNames().iceconnectionstatechangeEvent, Event::CanBubble::No, Event::IsCancelable::No));
575         protectedThis->updateConnectionState();
576     });
577 }
578
579 void RTCPeerConnection::updateConnectionState()
580 {
581     RTCPeerConnectionState state;
582
583     if (m_iceConnectionState == RTCIceConnectionState::Closed)
584         state = RTCPeerConnectionState::Closed;
585     else if (m_iceConnectionState == RTCIceConnectionState::Disconnected)
586         state = RTCPeerConnectionState::Disconnected;
587     else if (m_iceConnectionState == RTCIceConnectionState::Failed)
588         state = RTCPeerConnectionState::Failed;
589     else if (m_iceConnectionState == RTCIceConnectionState::New && m_iceGatheringState == RTCIceGatheringState::New)
590         state = RTCPeerConnectionState::New;
591     else if (m_iceConnectionState == RTCIceConnectionState::Checking || m_iceGatheringState == RTCIceGatheringState::Gathering)
592         state = RTCPeerConnectionState::Connecting;
593     else if ((m_iceConnectionState == RTCIceConnectionState::Completed || m_iceConnectionState == RTCIceConnectionState::Connected) && m_iceGatheringState == RTCIceGatheringState::Complete)
594         state = RTCPeerConnectionState::Connected;
595     else
596         return;
597
598     if (state == m_connectionState)
599         return;
600
601     INFO_LOG(LOGIDENTIFIER, "state changed from: " , m_connectionState, " to ", state);
602
603     m_connectionState = state;
604     dispatchEventWhenFeasible(Event::create(eventNames().connectionstatechangeEvent, Event::CanBubble::No, Event::IsCancelable::No));
605 }
606
607 void RTCPeerConnection::scheduleNegotiationNeededEvent()
608 {
609     scriptExecutionContext()->postTask([protectedThis = makeRef(*this)](ScriptExecutionContext&) {
610         if (protectedThis->isClosed())
611             return;
612         if (!protectedThis->m_backend->isNegotiationNeeded())
613             return;
614         protectedThis->m_backend->clearNegotiationNeededState();
615         protectedThis->dispatchEventWhenFeasible(Event::create(eventNames().negotiationneededEvent, Event::CanBubble::No, Event::IsCancelable::No));
616     });
617 }
618
619 void RTCPeerConnection::doTask(Function<void()>&& task)
620 {
621     if (m_shouldDelayTasks || !m_pendingTasks.isEmpty()) {
622         m_pendingTasks.append(WTFMove(task));
623         return;
624     }
625     task();
626 }
627
628 void RTCPeerConnection::dispatchEventWhenFeasible(Ref<Event>&& event)
629 {
630     doTask([this, event = WTFMove(event)] {
631         dispatchEvent(event);
632     });
633 }
634
635 void RTCPeerConnection::dispatchEvent(Event& event)
636 {
637     INFO_LOG(LOGIDENTIFIER, "dispatching '", event.type(), "'");
638     EventTarget::dispatchEvent(event);
639 }
640
641 static inline ExceptionOr<PeerConnectionBackend::CertificateInformation> certificateTypeFromAlgorithmIdentifier(JSC::JSGlobalObject& lexicalGlobalObject, RTCPeerConnection::AlgorithmIdentifier&& algorithmIdentifier)
642 {
643     if (WTF::holds_alternative<String>(algorithmIdentifier))
644         return Exception { NotSupportedError, "Algorithm is not supported"_s };
645
646     auto& value = WTF::get<JSC::Strong<JSC::JSObject>>(algorithmIdentifier);
647
648     JSC::VM& vm = lexicalGlobalObject.vm();
649     auto scope = DECLARE_CATCH_SCOPE(vm);
650
651     auto parameters = convertDictionary<RTCPeerConnection::CertificateParameters>(lexicalGlobalObject, value.get());
652     if (UNLIKELY(scope.exception())) {
653         scope.clearException();
654         return Exception { TypeError, "Unable to read certificate parameters"_s };
655     }
656
657     if (parameters.expires && *parameters.expires < 0)
658         return Exception { TypeError, "Expire value is invalid"_s };
659
660     if (parameters.name == "RSASSA-PKCS1-v1_5"_s) {
661         if (!parameters.hash.isNull() && parameters.hash != "SHA-256"_s)
662             return Exception { NotSupportedError, "Only SHA-256 is supported for RSASSA-PKCS1-v1_5"_s };
663
664         auto result = PeerConnectionBackend::CertificateInformation::RSASSA_PKCS1_v1_5();
665         if (parameters.modulusLength && parameters.publicExponent) {
666             int publicExponent = 0;
667             int value = 1;
668             for (unsigned counter = 0; counter < parameters.publicExponent->byteLength(); ++counter) {
669                 publicExponent += parameters.publicExponent->data()[counter] * value;
670                 value <<= 8;
671             }
672
673             result.rsaParameters = PeerConnectionBackend::CertificateInformation::RSA { *parameters.modulusLength, publicExponent };
674         }
675         result.expires = parameters.expires;
676         return result;
677     }
678     if (parameters.name == "ECDSA"_s && parameters.namedCurve == "P-256"_s) {
679         auto result = PeerConnectionBackend::CertificateInformation::ECDSA_P256();
680         result.expires = parameters.expires;
681         return result;
682     }
683
684     return Exception { NotSupportedError, "Algorithm is not supported"_s };
685 }
686
687 void RTCPeerConnection::generateCertificate(JSC::JSGlobalObject& lexicalGlobalObject, AlgorithmIdentifier&& algorithmIdentifier, DOMPromiseDeferred<IDLInterface<RTCCertificate>>&& promise)
688 {
689     auto parameters = certificateTypeFromAlgorithmIdentifier(lexicalGlobalObject, WTFMove(algorithmIdentifier));
690     if (parameters.hasException()) {
691         promise.reject(parameters.releaseException());
692         return;
693     }
694     auto& document = downcast<Document>(*JSC::jsCast<JSDOMGlobalObject*>(&lexicalGlobalObject)->scriptExecutionContext());
695     PeerConnectionBackend::generateCertificate(document, parameters.returnValue(), WTFMove(promise));
696 }
697
698 Vector<std::reference_wrapper<RTCRtpSender>> RTCPeerConnection::getSenders() const
699 {
700     m_backend->collectTransceivers();
701     return m_transceiverSet->senders();
702 }
703
704 Vector<std::reference_wrapper<RTCRtpReceiver>> RTCPeerConnection::getReceivers() const
705 {
706     m_backend->collectTransceivers();
707     return m_transceiverSet->receivers();
708 }
709
710 const Vector<RefPtr<RTCRtpTransceiver>>& RTCPeerConnection::getTransceivers() const
711 {
712     m_backend->collectTransceivers();
713     return m_transceiverSet->list();
714 }
715
716 Document* RTCPeerConnection::document()
717 {
718     return downcast<Document>(scriptExecutionContext());
719 }
720
721 #if !RELEASE_LOG_DISABLED
722 WTFLogChannel& RTCPeerConnection::logChannel() const
723 {
724     return LogWebRTC;
725 }
726 #endif
727
728 } // namespace WebCore
729
730 #endif // ENABLE(WEB_RTC)