Handle IDLPromise<> properly
[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 "Logging.h"
44 #include "MediaEndpointConfiguration.h"
45 #include "MediaStream.h"
46 #include "MediaStreamTrack.h"
47 #include "Page.h"
48 #include "RTCConfiguration.h"
49 #include "RTCController.h"
50 #include "RTCDataChannel.h"
51 #include "RTCIceCandidate.h"
52 #include "RTCPeerConnectionIceEvent.h"
53 #include "RTCSessionDescription.h"
54 #include "RTCTrackEvent.h"
55 #include <wtf/MainThread.h>
56 #include <wtf/UUID.h>
57 #include <wtf/text/Base64.h>
58
59 namespace WebCore {
60
61 using namespace PeerConnection;
62
63 Ref<RTCPeerConnection> RTCPeerConnection::create(ScriptExecutionContext& context)
64 {
65     Ref<RTCPeerConnection> peerConnection = adoptRef(*new RTCPeerConnection(context));
66     peerConnection->suspendIfNeeded();
67     // RTCPeerConnection may send events at about any time during its lifetime.
68     // Let's make it uncollectable until the pc is closed by JS or the page stops it.
69     if (!peerConnection->isClosed()) {
70         peerConnection->setPendingActivity(peerConnection.ptr());
71
72         auto* page = downcast<Document>(context).page();
73         peerConnection->registerToController(page->rtcController());
74     }
75     return peerConnection;
76 }
77
78 RTCPeerConnection::RTCPeerConnection(ScriptExecutionContext& context)
79     : ActiveDOMObject(&context)
80     , m_backend(PeerConnectionBackend::create(*this))
81 {
82     if (!m_backend)
83         m_connectionState = RTCPeerConnectionState::Closed;
84 }
85
86 RTCPeerConnection::~RTCPeerConnection()
87 {
88     unregisterFromController();
89     stop();
90 }
91
92 ExceptionOr<void> RTCPeerConnection::initializeWith(Document& document, RTCConfiguration&& configuration)
93 {
94     if (!document.frame())
95         return Exception { NOT_SUPPORTED_ERR };
96
97     if (!m_backend)
98         return Exception { NOT_SUPPORTED_ERR };
99
100     return setConfiguration(WTFMove(configuration));
101 }
102
103 ExceptionOr<Ref<RTCRtpSender>> RTCPeerConnection::addTrack(Ref<MediaStreamTrack>&& track, const Vector<std::reference_wrapper<MediaStream>>& streams)
104 {
105     if (isClosed())
106         return Exception { INVALID_STATE_ERR };
107
108     for (RTCRtpSender& sender : m_transceiverSet->senders()) {
109         if (sender.trackId() == track->id())
110             return Exception { INVALID_ACCESS_ERR };
111     }
112
113     Vector<String> mediaStreamIds;
114     for (auto stream : streams)
115         mediaStreamIds.append(stream.get().id());
116
117     RTCRtpSender* sender = nullptr;
118
119     // Reuse an existing sender with the same track kind if it has never been used to send before.
120     for (auto& transceiver : m_transceiverSet->list()) {
121         auto& existingSender = transceiver->sender();
122         if (existingSender.trackKind() == track->kind() && existingSender.trackId().isNull() && !transceiver->hasSendingDirection()) {
123             existingSender.setTrack(WTFMove(track));
124             existingSender.setMediaStreamIds(WTFMove(mediaStreamIds));
125             transceiver->enableSendingDirection();
126             sender = &existingSender;
127             
128             break;
129         }
130     }
131
132     if (!sender) {
133         String transceiverMid = RTCRtpTransceiver::getNextMid();
134         const String& trackKind = track->kind();
135         String trackId = createCanonicalUUIDString();
136
137         auto newSender = RTCRtpSender::create(WTFMove(track), WTFMove(mediaStreamIds), *this);
138         auto receiver = m_backend->createReceiver(transceiverMid, trackKind, trackId);
139         auto transceiver = RTCRtpTransceiver::create(WTFMove(newSender), WTFMove(receiver));
140
141         // This transceiver is not yet associated with an m-line (null mid), but we need a
142         // provisional mid if the transceiver is used to create an offer.
143         transceiver->setProvisionalMid(transceiverMid);
144
145         sender = &transceiver->sender();
146         m_transceiverSet->append(WTFMove(transceiver));
147     }
148
149 #if !USE(LIBWEBRTC)
150     m_backend->markAsNeedingNegotiation();
151 #endif
152
153     m_backend->notifyAddedTrack(*sender);
154     return Ref<RTCRtpSender> { *sender };
155 }
156
157 ExceptionOr<void> RTCPeerConnection::removeTrack(RTCRtpSender& sender)
158 {
159     if (isClosed())
160         return Exception { INVALID_STATE_ERR };
161
162     bool shouldAbort = true;
163     for (RTCRtpSender& senderInSet : m_transceiverSet->senders()) {
164         if (&senderInSet == &sender) {
165             shouldAbort = sender.isStopped();
166             break;
167         }
168     }
169     if (shouldAbort)
170         return { };
171
172     sender.stop();
173
174     m_backend->notifyRemovedTrack(sender);
175 #if !USE(LIBWEBRTC)
176     m_backend->markAsNeedingNegotiation();
177 #endif
178     return { };
179 }
180
181 ExceptionOr<Ref<RTCRtpTransceiver>> RTCPeerConnection::addTransceiver(AddTransceiverTrackOrKind&& withTrack, const RTCRtpTransceiverInit& init)
182 {
183     if (WTF::holds_alternative<String>(withTrack)) {
184         const String& kind = WTF::get<String>(withTrack);
185         if (kind != "audio" && kind != "video")
186             return Exception { TypeError };
187
188         auto sender = RTCRtpSender::create(String(kind), Vector<String>(), *this);
189         return completeAddTransceiver(WTFMove(sender), init, createCanonicalUUIDString(), kind);
190     }
191
192     Ref<MediaStreamTrack> track = WTF::get<RefPtr<MediaStreamTrack>>(withTrack).releaseNonNull();
193     const String& trackId = track->id();
194     const String& trackKind = track->kind();
195
196     auto sender = RTCRtpSender::create(WTFMove(track), Vector<String>(), *this);
197     return completeAddTransceiver(WTFMove(sender), init, trackId, trackKind);
198 }
199
200 Ref<RTCRtpTransceiver> RTCPeerConnection::completeAddTransceiver(Ref<RTCRtpSender>&& sender, const RTCRtpTransceiverInit& init, const String& trackId, const String& trackKind)
201 {
202     String transceiverMid = RTCRtpTransceiver::getNextMid();
203     auto transceiver = RTCRtpTransceiver::create(WTFMove(sender), m_backend->createReceiver(transceiverMid, trackKind, trackId));
204
205     transceiver->setProvisionalMid(transceiverMid);
206     transceiver->setDirection(init.direction);
207
208     m_transceiverSet->append(transceiver.copyRef());
209 #if !USE(LIBWEBRTC)
210     m_backend->markAsNeedingNegotiation();
211 #endif
212     return transceiver;
213 }
214
215 void RTCPeerConnection::queuedCreateOffer(RTCOfferOptions&& options, SessionDescriptionPromise&& promise)
216 {
217     LOG(WebRTC, "Creating offer\n");
218     if (isClosed()) {
219         promise.reject(INVALID_STATE_ERR);
220         return;
221     }
222
223     m_backend->createOffer(WTFMove(options), WTFMove(promise));
224 }
225
226 void RTCPeerConnection::queuedCreateAnswer(RTCAnswerOptions&& options, SessionDescriptionPromise&& promise)
227 {
228     LOG(WebRTC, "Creating answer\n");
229     if (isClosed()) {
230         promise.reject(INVALID_STATE_ERR);
231         return;
232     }
233
234     m_backend->createAnswer(WTFMove(options), WTFMove(promise));
235 }
236
237 void RTCPeerConnection::queuedSetLocalDescription(RTCSessionDescription& description, DOMPromiseDeferred<void>&& promise)
238 {
239     LOG(WebRTC, "Setting local description:\n%s\n", description.sdp().utf8().data());
240     if (isClosed()) {
241         promise.reject(INVALID_STATE_ERR);
242         return;
243     }
244
245     m_backend->setLocalDescription(description, WTFMove(promise));
246 }
247
248 RefPtr<RTCSessionDescription> RTCPeerConnection::localDescription() const
249 {
250     return m_backend->localDescription();
251 }
252
253 RefPtr<RTCSessionDescription> RTCPeerConnection::currentLocalDescription() const
254 {
255     return m_backend->currentLocalDescription();
256 }
257
258 RefPtr<RTCSessionDescription> RTCPeerConnection::pendingLocalDescription() const
259 {
260     return m_backend->pendingLocalDescription();
261 }
262
263 void RTCPeerConnection::queuedSetRemoteDescription(RTCSessionDescription& description, DOMPromiseDeferred<void>&& promise)
264 {
265     LOG(WebRTC, "Setting remote description:\n%s\n", description.sdp().utf8().data());
266
267     if (isClosed()) {
268         promise.reject(INVALID_STATE_ERR);
269         return;
270     }
271     m_backend->setRemoteDescription(description, WTFMove(promise));
272 }
273
274 RefPtr<RTCSessionDescription> RTCPeerConnection::remoteDescription() const
275 {
276     return m_backend->remoteDescription();
277 }
278
279 RefPtr<RTCSessionDescription> RTCPeerConnection::currentRemoteDescription() const
280 {
281     return m_backend->currentRemoteDescription();
282 }
283
284 RefPtr<RTCSessionDescription> RTCPeerConnection::pendingRemoteDescription() const
285 {
286     return m_backend->pendingRemoteDescription();
287 }
288
289 void RTCPeerConnection::queuedAddIceCandidate(RTCIceCandidate* rtcCandidate, DOMPromiseDeferred<void>&& promise)
290 {
291     LOG(WebRTC, "Received ice candidate:\n%s\n", rtcCandidate ? rtcCandidate->candidate().utf8().data() : "null");
292
293     if (isClosed()) {
294         promise.reject(INVALID_STATE_ERR);
295         return;
296     }
297
298     m_backend->addIceCandidate(rtcCandidate, WTFMove(promise));
299 }
300
301 ExceptionOr<void> RTCPeerConnection::setConfiguration(RTCConfiguration&& configuration)
302 {
303     if (isClosed())
304         return Exception { INVALID_STATE_ERR };
305
306     Vector<MediaEndpointConfiguration::IceServerInfo> servers;
307     if (configuration.iceServers) {
308         servers.reserveInitialCapacity(configuration.iceServers->size());
309         for (auto& server : configuration.iceServers.value()) {
310             Vector<URL> serverURLs;
311             WTF::switchOn(server.urls,
312                 [&serverURLs] (const String& string) {
313                     serverURLs.reserveInitialCapacity(1);
314                     serverURLs.uncheckedAppend(URL { URL { }, string });
315                 },
316                 [&serverURLs] (const Vector<String>& vector) {
317                     serverURLs.reserveInitialCapacity(vector.size());
318                     for (auto& string : vector)
319                         serverURLs.uncheckedAppend(URL { URL { }, string });
320                 }
321             );
322             for (auto& serverURL : serverURLs) {
323                 if (!(serverURL.protocolIs("turn") || serverURL.protocolIs("turns") || serverURL.protocolIs("stun")))
324                     return Exception { INVALID_ACCESS_ERR };
325             }
326             servers.uncheckedAppend({ WTFMove(serverURLs), server.credential, server.username });
327         }
328     }
329
330     m_backend->setConfiguration({ WTFMove(servers), configuration.iceTransportPolicy, configuration.bundlePolicy, configuration.iceCandidatePoolSize });
331     m_configuration = WTFMove(configuration);
332     return { };
333 }
334
335 void RTCPeerConnection::getStats(MediaStreamTrack* selector, Ref<DeferredPromise>&& promise)
336 {
337     m_backend->getStats(selector, WTFMove(promise));
338 }
339
340 ExceptionOr<Ref<RTCDataChannel>> RTCPeerConnection::createDataChannel(ScriptExecutionContext& context, String&& label, RTCDataChannelInit&& options)
341 {
342     if (isClosed())
343         return Exception { INVALID_STATE_ERR };
344
345     if (options.negotiated && !options.negotiated.value() && (label.length() > 65535 || options.protocol.length() > 65535))
346         return Exception { TypeError };
347
348     if (options.maxPacketLifeTime && options.maxRetransmits)
349         return Exception { TypeError };
350
351     if (options.id && options.id.value() > 65534)
352         return Exception { TypeError };
353     
354     auto channelHandler = m_backend->createDataChannelHandler(label, options);
355     if (!channelHandler)
356         return Exception { NOT_SUPPORTED_ERR };
357
358     return RTCDataChannel::create(context, WTFMove(channelHandler), WTFMove(label), WTFMove(options));
359 }
360
361 bool RTCPeerConnection::doClose()
362 {
363     if (isClosed())
364         return false;
365
366     m_connectionState = RTCPeerConnectionState::Closed;
367     m_iceConnectionState = RTCIceConnectionState::Closed;
368
369     for (RTCRtpReceiver& receiver : m_transceiverSet->receivers())
370         receiver.stop();
371
372     for (RTCRtpSender& sender : m_transceiverSet->senders())
373         sender.stop();
374
375     return true;
376 }
377
378 void RTCPeerConnection::close()
379 {
380     if (!doClose())
381         return;
382
383     updateConnectionState();
384     scriptExecutionContext()->postTask([protectedThis = makeRef(*this)](ScriptExecutionContext&) {
385         protectedThis->doStop();
386     });
387 }
388
389 void RTCPeerConnection::emulatePlatformEvent(const String& action)
390 {
391     m_backend->emulatePlatformEvent(action);
392 }
393
394 void RTCPeerConnection::stop()
395 {
396     if (!doClose())
397         return;
398
399     doStop();
400 }
401
402 void RTCPeerConnection::doStop()
403 {
404     if (m_isStopped)
405         return;
406
407     m_isStopped = true;
408
409     m_backend->stop();
410
411     unsetPendingActivity(this);
412 }
413
414 void RTCPeerConnection::registerToController(RTCController& controller)
415 {
416     m_controller = &controller;
417     m_controller->add(*this);
418 }
419
420 void RTCPeerConnection::unregisterFromController()
421 {
422     if (m_controller)
423         m_controller->remove(*this);
424 }
425
426 const char* RTCPeerConnection::activeDOMObjectName() const
427 {
428     return "RTCPeerConnection";
429 }
430
431 bool RTCPeerConnection::canSuspendForDocumentSuspension() const
432 {
433     // FIXME: We should try and do better here.
434     return false;
435 }
436
437 void RTCPeerConnection::addTransceiver(Ref<RTCRtpTransceiver>&& transceiver)
438 {
439     m_transceiverSet->append(WTFMove(transceiver));
440 }
441
442 void RTCPeerConnection::setSignalingState(RTCSignalingState newState)
443 {
444     m_signalingState = newState;
445 }
446
447 void RTCPeerConnection::updateIceGatheringState(RTCIceGatheringState newState)
448 {
449     scriptExecutionContext()->postTask([protectedThis = makeRef(*this), newState](ScriptExecutionContext&) {
450         if (protectedThis->isClosed() || protectedThis->m_iceGatheringState == newState)
451             return;
452
453         protectedThis->m_iceGatheringState = newState;
454         protectedThis->dispatchEvent(Event::create(eventNames().icegatheringstatechangeEvent, false, false));
455         protectedThis->updateConnectionState();
456     });
457 }
458
459 void RTCPeerConnection::updateIceConnectionState(RTCIceConnectionState newState)
460 {
461     scriptExecutionContext()->postTask([protectedThis = makeRef(*this), newState](ScriptExecutionContext&) {
462         if (protectedThis->isClosed() || protectedThis->m_iceConnectionState == newState)
463             return;
464
465         protectedThis->m_iceConnectionState = newState;
466         protectedThis->dispatchEvent(Event::create(eventNames().iceconnectionstatechangeEvent, false, false));
467         protectedThis->updateConnectionState();
468     });
469 }
470
471 void RTCPeerConnection::updateConnectionState()
472 {
473     RTCPeerConnectionState state;
474
475     // FIXME: In case m_iceGatheringState is RTCIceGatheringState::Gathering, and m_iceConnectionState is Closed, we should have the connection state be Closed.
476     if (m_iceConnectionState == RTCIceConnectionState::New && m_iceGatheringState == RTCIceGatheringState::New)
477         state = RTCPeerConnectionState::New;
478     else if (m_iceConnectionState == RTCIceConnectionState::Checking || m_iceGatheringState == RTCIceGatheringState::Gathering)
479         state = RTCPeerConnectionState::Connecting;
480     else if ((m_iceConnectionState == RTCIceConnectionState::Completed || m_iceConnectionState == RTCIceConnectionState::Connected) && m_iceGatheringState == RTCIceGatheringState::Complete)
481         state = RTCPeerConnectionState::Connected;
482     else if (m_iceConnectionState == RTCIceConnectionState::Disconnected)
483         state = RTCPeerConnectionState::Disconnected;
484     else if (m_iceConnectionState == RTCIceConnectionState::Failed)
485         state = RTCPeerConnectionState::Failed;
486     else if (m_iceConnectionState == RTCIceConnectionState::Closed)
487         state = RTCPeerConnectionState::Closed;
488     else
489         return;
490
491     if (state == m_connectionState)
492         return;
493
494     m_connectionState = state;
495     dispatchEvent(Event::create(eventNames().connectionstatechangeEvent, false, false));
496 }
497
498 void RTCPeerConnection::scheduleNegotiationNeededEvent()
499 {
500     scriptExecutionContext()->postTask([protectedThis = makeRef(*this)](ScriptExecutionContext&) {
501         if (protectedThis->isClosed())
502             return;
503         if (!protectedThis->m_backend->isNegotiationNeeded())
504             return;
505         protectedThis->m_backend->clearNegotiationNeededState();
506         protectedThis->dispatchEvent(Event::create(eventNames().negotiationneededEvent, false, false));
507     });
508 }
509
510 void RTCPeerConnection::fireEvent(Event& event)
511 {
512     dispatchEvent(event);
513 }
514
515 void RTCPeerConnection::enqueueReplaceTrackTask(RTCRtpSender& sender, Ref<MediaStreamTrack>&& withTrack, DOMPromiseDeferred<void>&& promise)
516 {
517     scriptExecutionContext()->postTask([protectedSender = makeRef(sender), promise = WTFMove(promise), withTrack = WTFMove(withTrack)](ScriptExecutionContext&) mutable {
518         protectedSender->setTrack(WTFMove(withTrack));
519         promise.resolve();
520     });
521 }
522
523 void RTCPeerConnection::replaceTrack(RTCRtpSender& sender, RefPtr<MediaStreamTrack>&& withTrack, DOMPromiseDeferred<void>&& promise)
524 {
525     if (!withTrack) {
526         scriptExecutionContext()->postTask([protectedSender = makeRef(sender), promise = WTFMove(promise)](ScriptExecutionContext&) mutable {
527             protectedSender->setTrackToNull();
528             promise.resolve();
529         });
530         return;
531     }
532     
533     if (!sender.track()) {
534         enqueueReplaceTrackTask(sender, withTrack.releaseNonNull(), WTFMove(promise));
535         return;
536     }
537
538     m_backend->replaceTrack(sender, withTrack.releaseNonNull(), WTFMove(promise));
539 }
540
541 RTCRtpParameters RTCPeerConnection::getParameters(RTCRtpSender& sender) const
542 {
543     return m_backend->getParameters(sender);
544 }
545
546 } // namespace WebCore
547
548 #endif // ENABLE(WEB_RTC)