Modernize RTCPeerConnection handling of pendingActivity
[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 "JSRTCPeerConnection.h"
44 #include "Logging.h"
45 #include "MediaEndpointConfiguration.h"
46 #include "MediaStream.h"
47 #include "MediaStreamTrack.h"
48 #include "Page.h"
49 #include "RTCConfiguration.h"
50 #include "RTCController.h"
51 #include "RTCDataChannel.h"
52 #include "RTCIceCandidate.h"
53 #include "RTCPeerConnectionIceEvent.h"
54 #include "RTCSessionDescription.h"
55 #include "RTCTrackEvent.h"
56 #include <wtf/CryptographicallyRandomNumber.h>
57 #include <wtf/MainThread.h>
58 #include <wtf/UUID.h>
59 #include <wtf/text/Base64.h>
60
61 namespace WebCore {
62
63 using namespace PeerConnection;
64
65 Ref<RTCPeerConnection> RTCPeerConnection::create(ScriptExecutionContext& context)
66 {
67     Ref<RTCPeerConnection> peerConnection = adoptRef(*new RTCPeerConnection(context));
68     peerConnection->suspendIfNeeded();
69     // RTCPeerConnection may send events at about any time during its lifetime.
70     // Let's make it uncollectable until the pc is closed by JS or the page stops it.
71     if (!peerConnection->isClosed()) {
72         peerConnection->m_pendingActivity = peerConnection->makePendingActivity(peerConnection.get());
73         if (auto* page = downcast<Document>(context).page())
74             peerConnection->registerToController(page->rtcController());
75     }
76     return peerConnection;
77 }
78
79 RTCPeerConnection::RTCPeerConnection(ScriptExecutionContext& context)
80     : ActiveDOMObject(&context)
81 #if !RELEASE_LOG_DISABLED
82     , m_logger(downcast<Document>(context).logger())
83     , m_logIdentifier(reinterpret_cast<const void*>(cryptographicallyRandomNumber()))
84 #endif
85     , m_backend(PeerConnectionBackend::create(*this))
86 {
87     ALWAYS_LOG(LOGIDENTIFIER);
88     if (!m_backend)
89         m_connectionState = RTCPeerConnectionState::Closed;
90 }
91
92 RTCPeerConnection::~RTCPeerConnection()
93 {
94     ALWAYS_LOG(LOGIDENTIFIER);
95     unregisterFromController();
96     stop();
97 }
98
99 ExceptionOr<void> RTCPeerConnection::initializeWith(Document& document, RTCConfiguration&& configuration)
100 {
101     if (!document.frame())
102         return Exception { NotSupportedError };
103
104     if (!m_backend)
105         return Exception { NotSupportedError };
106
107     return initializeConfiguration(WTFMove(configuration));
108 }
109
110 ExceptionOr<Ref<RTCRtpSender>> RTCPeerConnection::addTrack(Ref<MediaStreamTrack>&& track, const Vector<std::reference_wrapper<MediaStream>>& streams)
111 {
112     INFO_LOG(LOGIDENTIFIER);
113
114     if (isClosed())
115         return Exception { InvalidStateError };
116
117     for (RTCRtpSender& sender : m_transceiverSet->senders()) {
118         if (sender.trackId() == track->id())
119             return Exception { InvalidAccessError };
120     }
121
122     Vector<String> mediaStreamIds;
123     for (auto stream : streams)
124         mediaStreamIds.append(stream.get().id());
125
126     return m_backend->addTrack(track.get(), WTFMove(mediaStreamIds));
127 }
128
129 ExceptionOr<void> RTCPeerConnection::removeTrack(RTCRtpSender& sender)
130 {
131     INFO_LOG(LOGIDENTIFIER);
132
133     if (isClosed())
134         return Exception { InvalidStateError, "RTCPeerConnection is closed"_s };
135
136     if (!sender.isCreatedBy(*m_backend))
137         return Exception { InvalidAccessError, "RTCPeerConnection did not create the given sender"_s };
138
139     bool shouldAbort = true;
140     RTCRtpTransceiver* senderTransceiver = nullptr;
141     for (auto& transceiver : m_transceiverSet->list()) {
142         if (&sender == &transceiver->sender()) {
143             senderTransceiver = transceiver.get();
144             shouldAbort = sender.isStopped() || !sender.track();
145             break;
146         }
147     }
148     if (shouldAbort)
149         return { };
150
151     sender.setTrackToNull();
152     senderTransceiver->disableSendingDirection();
153     m_backend->removeTrack(sender);
154     return { };
155 }
156
157 ExceptionOr<Ref<RTCRtpTransceiver>> RTCPeerConnection::addTransceiver(AddTransceiverTrackOrKind&& withTrack, const RTCRtpTransceiverInit& init)
158 {
159     INFO_LOG(LOGIDENTIFIER);
160
161     if (WTF::holds_alternative<String>(withTrack)) {
162         const String& kind = WTF::get<String>(withTrack);
163         if (kind != "audio"_s && kind != "video"_s)
164             return Exception { TypeError };
165
166         if (isClosed())
167             return Exception { InvalidStateError };
168
169         return m_backend->addTransceiver(kind, init);
170     }
171
172     if (isClosed())
173         return Exception { InvalidStateError };
174
175     auto track = WTF::get<RefPtr<MediaStreamTrack>>(withTrack).releaseNonNull();
176     return m_backend->addTransceiver(WTFMove(track), init);
177 }
178
179 void RTCPeerConnection::queuedCreateOffer(RTCOfferOptions&& options, SessionDescriptionPromise&& promise)
180 {
181     ALWAYS_LOG(LOGIDENTIFIER);
182     if (isClosed()) {
183         promise.reject(InvalidStateError);
184         return;
185     }
186
187     m_backend->createOffer(WTFMove(options), WTFMove(promise));
188 }
189
190 void RTCPeerConnection::queuedCreateAnswer(RTCAnswerOptions&& options, SessionDescriptionPromise&& promise)
191 {
192     ALWAYS_LOG(LOGIDENTIFIER);
193     if (isClosed()) {
194         promise.reject(InvalidStateError);
195         return;
196     }
197
198     m_backend->createAnswer(WTFMove(options), WTFMove(promise));
199 }
200
201 void RTCPeerConnection::queuedSetLocalDescription(RTCSessionDescription& description, DOMPromiseDeferred<void>&& promise)
202 {
203     ALWAYS_LOG(LOGIDENTIFIER, "Setting local description to:\n", description.sdp());
204     if (isClosed()) {
205         promise.reject(InvalidStateError);
206         return;
207     }
208
209     m_backend->setLocalDescription(description, WTFMove(promise));
210 }
211
212 RefPtr<RTCSessionDescription> RTCPeerConnection::localDescription() const
213 {
214     return m_backend->localDescription();
215 }
216
217 RefPtr<RTCSessionDescription> RTCPeerConnection::currentLocalDescription() const
218 {
219     return m_backend->currentLocalDescription();
220 }
221
222 RefPtr<RTCSessionDescription> RTCPeerConnection::pendingLocalDescription() const
223 {
224     return m_backend->pendingLocalDescription();
225 }
226
227 void RTCPeerConnection::queuedSetRemoteDescription(RTCSessionDescription& description, DOMPromiseDeferred<void>&& promise)
228 {
229     ALWAYS_LOG(LOGIDENTIFIER, "Setting remote description to:\n", description.sdp());
230
231     if (isClosed()) {
232         promise.reject(InvalidStateError);
233         return;
234     }
235     m_backend->setRemoteDescription(description, WTFMove(promise));
236 }
237
238 RefPtr<RTCSessionDescription> RTCPeerConnection::remoteDescription() const
239 {
240     return m_backend->remoteDescription();
241 }
242
243 RefPtr<RTCSessionDescription> RTCPeerConnection::currentRemoteDescription() const
244 {
245     return m_backend->currentRemoteDescription();
246 }
247
248 RefPtr<RTCSessionDescription> RTCPeerConnection::pendingRemoteDescription() const
249 {
250     return m_backend->pendingRemoteDescription();
251 }
252
253 void RTCPeerConnection::queuedAddIceCandidate(RTCIceCandidate* rtcCandidate, DOMPromiseDeferred<void>&& promise)
254 {
255     ALWAYS_LOG(LOGIDENTIFIER, "Received ice candidate:\n", rtcCandidate ? rtcCandidate->candidate() : "null");
256
257     if (isClosed()) {
258         promise.reject(InvalidStateError);
259         return;
260     }
261
262     m_backend->addIceCandidate(rtcCandidate, WTFMove(promise));
263 }
264
265 // Implementation of https://w3c.github.io/webrtc-pc/#set-pc-configuration
266 static inline ExceptionOr<Vector<MediaEndpointConfiguration::IceServerInfo>> iceServersFromConfiguration(RTCConfiguration& newConfiguration, const RTCConfiguration* existingConfiguration, bool isLocalDescriptionSet)
267 {
268     if (existingConfiguration && newConfiguration.bundlePolicy != existingConfiguration->bundlePolicy)
269         return Exception { InvalidModificationError, "BundlePolicy does not match existing policy" };
270
271     if (existingConfiguration && newConfiguration.rtcpMuxPolicy != existingConfiguration->rtcpMuxPolicy)
272         return Exception { InvalidModificationError, "RTCPMuxPolicy does not match existing policy" };
273
274     if (existingConfiguration && newConfiguration.iceCandidatePoolSize != existingConfiguration->iceCandidatePoolSize && isLocalDescriptionSet)
275         return Exception { InvalidModificationError, "IceTransportPolicy pool size does not match existing pool size" };
276
277     Vector<MediaEndpointConfiguration::IceServerInfo> servers;
278     if (newConfiguration.iceServers) {
279         servers.reserveInitialCapacity(newConfiguration.iceServers->size());
280         for (auto& server : newConfiguration.iceServers.value()) {
281             Vector<URL> serverURLs;
282             WTF::switchOn(server.urls, [&serverURLs] (const String& string) {
283                 serverURLs.reserveInitialCapacity(1);
284                 serverURLs.uncheckedAppend(URL { URL { }, string });
285             }, [&serverURLs] (const Vector<String>& vector) {
286                 serverURLs.reserveInitialCapacity(vector.size());
287                 for (auto& string : vector)
288                     serverURLs.uncheckedAppend(URL { URL { }, string });
289             });
290             for (auto& serverURL : serverURLs) {
291                 if (serverURL.isNull())
292                     return Exception { TypeError, "Bad ICE server URL" };
293                 if (serverURL.protocolIs("turn") || serverURL.protocolIs("turns")) {
294                     if (server.credential.isNull() || server.username.isNull())
295                         return Exception { InvalidAccessError, "TURN/TURNS server requires both username and credential" };
296                 } else if (!serverURL.protocolIs("stun"))
297                     return Exception { NotSupportedError, "ICE server protocol not supported" };
298             }
299             if (serverURLs.size())
300                 servers.uncheckedAppend({ WTFMove(serverURLs), server.credential, server.username });
301         }
302     }
303     return WTFMove(servers);
304 }
305
306 ExceptionOr<Vector<MediaEndpointConfiguration::CertificatePEM>> RTCPeerConnection::certificatesFromConfiguration(const RTCConfiguration& configuration)
307 {
308     auto currentMilliSeconds = WallTime::now().secondsSinceEpoch().milliseconds();
309     auto& origin = downcast<Document>(*scriptExecutionContext()).securityOrigin();
310
311     Vector<MediaEndpointConfiguration::CertificatePEM> certificates;
312     certificates.reserveInitialCapacity(configuration.certificates.size());
313     for (auto& certificate : configuration.certificates) {
314         if (!originsMatch(origin, certificate->origin()))
315             return Exception { InvalidAccessError, "Certificate does not have a valid origin" };
316
317         if (currentMilliSeconds > certificate->expires())
318             return Exception { InvalidAccessError, "Certificate has expired"_s };
319
320         certificates.uncheckedAppend(MediaEndpointConfiguration::CertificatePEM { certificate->pemCertificate(), certificate->pemPrivateKey(), });
321     }
322     return WTFMove(certificates);
323 }
324
325 ExceptionOr<void> RTCPeerConnection::initializeConfiguration(RTCConfiguration&& configuration)
326 {
327     INFO_LOG(LOGIDENTIFIER);
328
329     auto servers = iceServersFromConfiguration(configuration, nullptr, false);
330     if (servers.hasException())
331         return servers.releaseException();
332
333     auto certificates = certificatesFromConfiguration(configuration);
334     if (certificates.hasException())
335         return certificates.releaseException();
336
337     if (!m_backend->setConfiguration({ servers.releaseReturnValue(), configuration.iceTransportPolicy, configuration.bundlePolicy, configuration.rtcpMuxPolicy, configuration.iceCandidatePoolSize, certificates.releaseReturnValue() }))
338         return Exception { InvalidAccessError, "Bad Configuration Parameters" };
339
340     m_configuration = WTFMove(configuration);
341     return { };
342 }
343
344 ExceptionOr<void> RTCPeerConnection::setConfiguration(RTCConfiguration&& configuration)
345 {
346     if (isClosed())
347         return Exception { InvalidStateError };
348
349     INFO_LOG(LOGIDENTIFIER);
350
351     auto servers = iceServersFromConfiguration(configuration, &m_configuration, m_backend->isLocalDescriptionSet());
352     if (servers.hasException())
353         return servers.releaseException();
354
355     if (configuration.certificates.size()) {
356         if (configuration.certificates.size() != m_configuration.certificates.size())
357             return Exception { InvalidModificationError, "Certificates parameters are different" };
358
359         for (auto& certificate : configuration.certificates) {
360             bool isThere = m_configuration.certificates.findMatching([&certificate](const auto& item) {
361                 return item.get() == certificate.get();
362             }) != notFound;
363             if (!isThere)
364                 return Exception { InvalidModificationError, "A certificate given in constructor is not present" };
365         }
366     }
367
368     if (!m_backend->setConfiguration({ servers.releaseReturnValue(), configuration.iceTransportPolicy, configuration.bundlePolicy, configuration.rtcpMuxPolicy, configuration.iceCandidatePoolSize, { } }))
369         return Exception { InvalidAccessError, "Bad Configuration Parameters" };
370
371     m_configuration = WTFMove(configuration);
372     return { };
373 }
374
375 void RTCPeerConnection::getStats(MediaStreamTrack* selector, Ref<DeferredPromise>&& promise)
376 {
377     if (selector) {
378         for (auto& transceiver : m_transceiverSet->list()) {
379             if (transceiver->sender().track() == selector) {
380                 m_backend->getStats(transceiver->sender(), WTFMove(promise));
381                 return;
382             }
383             if (&transceiver->receiver().track() == selector) {
384                 m_backend->getStats(transceiver->receiver(), WTFMove(promise));
385                 return;
386             }
387         }
388     }
389     m_backend->getStats(WTFMove(promise));
390 }
391
392 ExceptionOr<Ref<RTCDataChannel>> RTCPeerConnection::createDataChannel(ScriptExecutionContext& context, String&& label, RTCDataChannelInit&& options)
393 {
394     ALWAYS_LOG(LOGIDENTIFIER);
395
396     if (isClosed())
397         return Exception { InvalidStateError };
398
399     if (options.negotiated && !options.negotiated.value() && (label.length() > 65535 || options.protocol.length() > 65535))
400         return Exception { TypeError };
401
402     if (options.maxPacketLifeTime && options.maxRetransmits)
403         return Exception { TypeError };
404
405     if (options.id && options.id.value() > 65534)
406         return Exception { TypeError };
407     
408     auto channelHandler = m_backend->createDataChannelHandler(label, options);
409     if (!channelHandler)
410         return Exception { NotSupportedError };
411
412     return RTCDataChannel::create(context, WTFMove(channelHandler), WTFMove(label), WTFMove(options));
413 }
414
415 bool RTCPeerConnection::doClose()
416 {
417     if (isClosed())
418         return false;
419
420     m_connectionState = RTCPeerConnectionState::Closed;
421     m_iceConnectionState = RTCIceConnectionState::Closed;
422     m_signalingState = RTCSignalingState::Closed;
423
424     for (auto& transceiver : m_transceiverSet->list()) {
425         transceiver->stop();
426         transceiver->sender().stop();
427         transceiver->receiver().stop();
428     }
429
430     return true;
431 }
432
433 void RTCPeerConnection::close()
434 {
435     if (!doClose())
436         return;
437
438     updateConnectionState();
439     ASSERT(isClosed());
440     scriptExecutionContext()->postTask([protectedThis = makeRef(*this)](ScriptExecutionContext&) {
441         protectedThis->doStop();
442     });
443 }
444
445 void RTCPeerConnection::emulatePlatformEvent(const String& action)
446 {
447     m_backend->emulatePlatformEvent(action);
448 }
449
450 void RTCPeerConnection::stop()
451 {
452     if (!doClose())
453         return;
454
455     doStop();
456 }
457
458 void RTCPeerConnection::doStop()
459 {
460     if (m_isStopped)
461         return;
462
463     m_isStopped = true;
464
465     m_backend->stop();
466     m_pendingActivity = nullptr;
467 }
468
469 void RTCPeerConnection::registerToController(RTCController& controller)
470 {
471     m_controller = &controller;
472     m_controller->add(*this);
473 }
474
475 void RTCPeerConnection::unregisterFromController()
476 {
477     if (m_controller)
478         m_controller->remove(*this);
479 }
480
481 const char* RTCPeerConnection::activeDOMObjectName() const
482 {
483     return "RTCPeerConnection";
484 }
485
486 bool RTCPeerConnection::canSuspendForDocumentSuspension() const
487 {
488     return !hasPendingActivity();
489 }
490
491 bool RTCPeerConnection::hasPendingActivity() const
492 {
493     return !m_isStopped;
494 }
495
496 void RTCPeerConnection::addTransceiver(Ref<RTCRtpTransceiver>&& transceiver)
497 {
498     INFO_LOG(LOGIDENTIFIER);
499     m_transceiverSet->append(WTFMove(transceiver));
500 }
501
502 void RTCPeerConnection::setSignalingState(RTCSignalingState newState)
503 {
504     ALWAYS_LOG(LOGIDENTIFIER, newState);
505     m_signalingState = newState;
506 }
507
508 void RTCPeerConnection::updateIceGatheringState(RTCIceGatheringState newState)
509 {
510     ALWAYS_LOG(LOGIDENTIFIER, newState);
511
512     scriptExecutionContext()->postTask([protectedThis = makeRef(*this), newState](ScriptExecutionContext&) {
513         if (protectedThis->isClosed() || protectedThis->m_iceGatheringState == newState)
514             return;
515
516         protectedThis->m_iceGatheringState = newState;
517         protectedThis->dispatchEvent(Event::create(eventNames().icegatheringstatechangeEvent, Event::CanBubble::No, Event::IsCancelable::No));
518         protectedThis->updateConnectionState();
519     });
520 }
521
522 void RTCPeerConnection::updateIceConnectionState(RTCIceConnectionState newState)
523 {
524     ALWAYS_LOG(LOGIDENTIFIER, newState);
525
526     scriptExecutionContext()->postTask([protectedThis = makeRef(*this), newState](ScriptExecutionContext&) {
527         if (protectedThis->isClosed() || protectedThis->m_iceConnectionState == newState)
528             return;
529
530         protectedThis->m_iceConnectionState = newState;
531         protectedThis->dispatchEvent(Event::create(eventNames().iceconnectionstatechangeEvent, Event::CanBubble::No, Event::IsCancelable::No));
532         protectedThis->updateConnectionState();
533     });
534 }
535
536 void RTCPeerConnection::updateConnectionState()
537 {
538     RTCPeerConnectionState state;
539
540     if (m_iceConnectionState == RTCIceConnectionState::Closed)
541         state = RTCPeerConnectionState::Closed;
542     else if (m_iceConnectionState == RTCIceConnectionState::Disconnected)
543         state = RTCPeerConnectionState::Disconnected;
544     else if (m_iceConnectionState == RTCIceConnectionState::Failed)
545         state = RTCPeerConnectionState::Failed;
546     else if (m_iceConnectionState == RTCIceConnectionState::New && m_iceGatheringState == RTCIceGatheringState::New)
547         state = RTCPeerConnectionState::New;
548     else if (m_iceConnectionState == RTCIceConnectionState::Checking || m_iceGatheringState == RTCIceGatheringState::Gathering)
549         state = RTCPeerConnectionState::Connecting;
550     else if ((m_iceConnectionState == RTCIceConnectionState::Completed || m_iceConnectionState == RTCIceConnectionState::Connected) && m_iceGatheringState == RTCIceGatheringState::Complete)
551         state = RTCPeerConnectionState::Connected;
552     else
553         return;
554
555     if (state == m_connectionState)
556         return;
557
558     INFO_LOG(LOGIDENTIFIER, "state changed from: " , m_connectionState, " to ", state);
559
560     m_connectionState = state;
561     dispatchEvent(Event::create(eventNames().connectionstatechangeEvent, Event::CanBubble::No, Event::IsCancelable::No));
562 }
563
564 void RTCPeerConnection::scheduleNegotiationNeededEvent()
565 {
566     scriptExecutionContext()->postTask([protectedThis = makeRef(*this)](ScriptExecutionContext&) {
567         if (protectedThis->isClosed())
568             return;
569         if (!protectedThis->m_backend->isNegotiationNeeded())
570             return;
571         protectedThis->m_backend->clearNegotiationNeededState();
572         protectedThis->dispatchEvent(Event::create(eventNames().negotiationneededEvent, Event::CanBubble::No, Event::IsCancelable::No));
573     });
574 }
575
576 void RTCPeerConnection::fireEvent(Event& event)
577 {
578     dispatchEvent(event);
579 }
580
581 void RTCPeerConnection::dispatchEvent(Event& event)
582 {
583     DEBUG_LOG(LOGIDENTIFIER, "dispatching '", event.type(), "'");
584     EventTarget::dispatchEvent(event);
585 }
586
587 static inline ExceptionOr<PeerConnectionBackend::CertificateInformation> certificateTypeFromAlgorithmIdentifier(JSC::ExecState& state, RTCPeerConnection::AlgorithmIdentifier&& algorithmIdentifier)
588 {
589     if (WTF::holds_alternative<String>(algorithmIdentifier))
590         return Exception { NotSupportedError, "Algorithm is not supported"_s };
591
592     auto& value = WTF::get<JSC::Strong<JSC::JSObject>>(algorithmIdentifier);
593
594     JSC::VM& vm = state.vm();
595     auto scope = DECLARE_CATCH_SCOPE(vm);
596
597     auto parameters = convertDictionary<RTCPeerConnection::CertificateParameters>(state, value.get());
598     if (UNLIKELY(scope.exception())) {
599         scope.clearException();
600         return Exception { TypeError, "Unable to read certificate parameters"_s };
601     }
602
603     if (parameters.expires && *parameters.expires < 0)
604         return Exception { TypeError, "Expire value is invalid"_s };
605
606     if (parameters.name == "RSASSA-PKCS1-v1_5"_s) {
607         if (!parameters.hash.isNull() && parameters.hash != "SHA-256"_s)
608             return Exception { NotSupportedError, "Only SHA-256 is supported for RSASSA-PKCS1-v1_5"_s };
609
610         auto result = PeerConnectionBackend::CertificateInformation::RSASSA_PKCS1_v1_5();
611         if (parameters.modulusLength && parameters.publicExponent) {
612             int publicExponent = 0;
613             int value = 1;
614             for (unsigned counter = 0; counter < parameters.publicExponent->byteLength(); ++counter) {
615                 publicExponent += parameters.publicExponent->data()[counter] * value;
616                 value <<= 8;
617             }
618
619             result.rsaParameters = PeerConnectionBackend::CertificateInformation::RSA { *parameters.modulusLength, publicExponent };
620         }
621         result.expires = parameters.expires;
622         return WTFMove(result);
623     }
624     if (parameters.name == "ECDSA"_s && parameters.namedCurve == "P-256"_s) {
625         auto result = PeerConnectionBackend::CertificateInformation::ECDSA_P256();
626         result.expires = parameters.expires;
627         return WTFMove(result);
628     }
629
630     return Exception { NotSupportedError, "Algorithm is not supported"_s };
631 }
632
633 void RTCPeerConnection::generateCertificate(JSC::ExecState& state, AlgorithmIdentifier&& algorithmIdentifier, DOMPromiseDeferred<IDLInterface<RTCCertificate>>&& promise)
634 {
635     auto parameters = certificateTypeFromAlgorithmIdentifier(state, WTFMove(algorithmIdentifier));
636     if (parameters.hasException()) {
637         promise.reject(parameters.releaseException());
638         return;
639     }
640     auto& document = downcast<Document>(*JSC::jsCast<JSDOMGlobalObject*>(state.lexicalGlobalObject())->scriptExecutionContext());
641     PeerConnectionBackend::generateCertificate(document, parameters.returnValue(), WTFMove(promise));
642 }
643
644 const Vector<std::reference_wrapper<RTCRtpSender>>& RTCPeerConnection::getSenders() const
645 {
646     m_backend->collectTransceivers();
647     return m_transceiverSet->senders();
648 }
649
650 const Vector<std::reference_wrapper<RTCRtpReceiver>>& RTCPeerConnection::getReceivers() const
651 {
652     m_backend->collectTransceivers();
653     return m_transceiverSet->receivers();
654 }
655
656 const Vector<RefPtr<RTCRtpTransceiver>>& RTCPeerConnection::getTransceivers() const
657 {
658     m_backend->collectTransceivers();
659     return m_transceiverSet->list();
660 }
661
662 #if !RELEASE_LOG_DISABLED
663 WTFLogChannel& RTCPeerConnection::logChannel() const
664 {
665     return LogWebRTC;
666 }
667 #endif
668
669 } // namespace WebCore
670
671 #endif // ENABLE(WEB_RTC)