0c186818c31212ac2bfa0419c941a17d595d5f0d
[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  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer
14  *    in the documentation and/or other materials provided with the
15  *    distribution.
16  * 3. Neither the name of Google Inc. nor the names of its contributors
17  *    may be used to endorse or promote products derived from this
18  *    software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32
33 #include "config.h"
34
35 #if ENABLE(WEB_RTC)
36
37 #include "RTCPeerConnection.h"
38
39 #include "Document.h"
40 #include "Event.h"
41 #include "ExceptionCode.h"
42 #include "Frame.h"
43 #include "MediaStream.h"
44 #include "MediaStreamTrack.h"
45 #include "RTCConfiguration.h"
46 #include "RTCDataChannel.h"
47 #include "RTCIceCandidate.h"
48 #include "RTCIceCandidateEvent.h"
49 #include "RTCOfferAnswerOptions.h"
50 #include "RTCSessionDescription.h"
51 #include "RTCTrackEvent.h"
52 #include "UUID.h"
53 #include <wtf/MainThread.h>
54 #include <wtf/text/Base64.h>
55
56 namespace WebCore {
57
58 using namespace PeerConnection;
59 using namespace PeerConnectionStates;
60
61 RefPtr<RTCPeerConnection> RTCPeerConnection::create(ScriptExecutionContext& context, const Dictionary& rtcConfiguration, ExceptionCode& ec)
62 {
63     RefPtr<RTCConfiguration> configuration = RTCConfiguration::create(rtcConfiguration, ec);
64     if (ec)
65         return nullptr;
66
67     RefPtr<RTCPeerConnection> peerConnection = adoptRef(new RTCPeerConnection(context, WTFMove(configuration), ec));
68     peerConnection->suspendIfNeeded();
69     if (ec)
70         return nullptr;
71
72     return peerConnection;
73 }
74
75 RTCPeerConnection::RTCPeerConnection(ScriptExecutionContext& context, RefPtr<RTCConfiguration>&& configuration, ExceptionCode& ec)
76     : ActiveDOMObject(&context)
77     , m_signalingState(SignalingState::Stable)
78     , m_iceGatheringState(IceGatheringState::New)
79     , m_iceConnectionState(IceConnectionState::New)
80     , m_configuration(WTFMove(configuration))
81 {
82     Document& document = downcast<Document>(context);
83
84     if (!document.frame()) {
85         ec = NOT_SUPPORTED_ERR;
86         return;
87     }
88
89     m_backend = PeerConnectionBackend::create(this);
90     if (!m_backend) {
91         ec = NOT_SUPPORTED_ERR;
92         return;
93     }
94
95     m_backend->setConfiguration(*m_configuration);
96 }
97
98 RTCPeerConnection::~RTCPeerConnection()
99 {
100     stop();
101 }
102
103 RefPtr<RTCRtpSender> RTCPeerConnection::addTrack(Ref<MediaStreamTrack>&& track, Vector<MediaStream*> streams, ExceptionCode& ec)
104 {
105     if (m_signalingState == SignalingState::Closed) {
106         ec = INVALID_STATE_ERR;
107         return nullptr;
108     }
109
110     // Require at least one stream until https://github.com/w3c/webrtc-pc/issues/288 is resolved
111     if (!streams.size()) {
112         ec = NOT_SUPPORTED_ERR;
113         return nullptr;
114     }
115
116     for (auto& sender : m_transceiverSet->getSenders()) {
117         if (sender->trackId() == track->id()) {
118             // FIXME: Spec says InvalidParameter
119             ec = INVALID_MODIFICATION_ERR;
120             return nullptr;
121         }
122     }
123
124     Vector<String> mediaStreamIds;
125     for (auto stream : streams)
126         mediaStreamIds.append(stream->id());
127
128     RTCRtpSender* sender = nullptr;
129
130     // Reuse an existing sender with the same track kind if it has never been used to send before.
131     for (auto& transceiver : m_transceiverSet->list()) {
132         RTCRtpSender& existingSender = *transceiver->sender();
133         if (existingSender.trackKind() == track->kind() && existingSender.trackId().isNull() && !transceiver->hasSendingDirection()) {
134             existingSender.setTrack(WTFMove(track));
135             existingSender.setMediaStreamIds(WTFMove(mediaStreamIds));
136             transceiver->enableSendingDirection();
137             sender = &existingSender;
138             break;
139         }
140     }
141
142     if (!sender) {
143         String transceiverMid = RTCRtpTransceiver::getNextMid();
144         const String& trackKind = track->kind();
145         String trackId = createCanonicalUUIDString();
146
147         auto newSender = RTCRtpSender::create(WTFMove(track), WTFMove(mediaStreamIds), *this);
148         auto receiver = m_backend->createReceiver(transceiverMid, trackKind, trackId);
149         auto transceiver = RTCRtpTransceiver::create(WTFMove(newSender), WTFMove(receiver));
150
151         // This transceiver is not yet associated with an m-line (null mid), but we need a
152         // provisional mid if the transceiver is used to create an offer.
153         transceiver->setProvisionalMid(transceiverMid);
154
155         sender = transceiver->sender();
156         m_transceiverSet->append(WTFMove(transceiver));
157     }
158
159     m_backend->markAsNeedingNegotiation();
160
161     return sender;
162 }
163
164 void RTCPeerConnection::removeTrack(RTCRtpSender& sender, ExceptionCode& ec)
165 {
166     if (m_signalingState == SignalingState::Closed) {
167         ec = INVALID_STATE_ERR;
168         return;
169     }
170
171     if (!m_transceiverSet->getSenders().contains(&sender))
172         return;
173
174     sender.stop();
175
176     m_backend->markAsNeedingNegotiation();
177 }
178
179 RefPtr<RTCRtpTransceiver> RTCPeerConnection::addTransceiver(Ref<MediaStreamTrack>&& track, const RtpTransceiverInit& init, ExceptionCode& ec)
180 {
181     if (m_signalingState == SignalingState::Closed) {
182         ec = INVALID_STATE_ERR;
183         return nullptr;
184     }
185
186     String transceiverMid = RTCRtpTransceiver::getNextMid();
187     const String& trackKind = track->kind();
188     const String& trackId = track->id();
189
190     auto sender = RTCRtpSender::create(WTFMove(track), Vector<String>(), *this);
191     auto receiver = m_backend->createReceiver(transceiverMid, trackKind, trackId);
192     auto transceiver = RTCRtpTransceiver::create(WTFMove(sender), WTFMove(receiver));
193     transceiver->setProvisionalMid(transceiverMid);
194
195     return completeAddTransceiver(WTFMove(transceiver), init);
196 }
197
198 RefPtr<RTCRtpTransceiver> RTCPeerConnection::addTransceiver(const String& kind, const RtpTransceiverInit& init, ExceptionCode& ec)
199 {
200     if (m_signalingState == SignalingState::Closed) {
201         ec = INVALID_STATE_ERR;
202         return nullptr;
203     }
204
205     if (kind != "audio" && kind != "video") {
206         ec = TypeError;
207         return nullptr;
208     }
209
210     String transceiverMid = RTCRtpTransceiver::getNextMid();
211     String trackId = createCanonicalUUIDString();
212
213     auto sender = RTCRtpSender::create(kind, Vector<String>(), *this);
214     auto receiver = m_backend->createReceiver(transceiverMid, kind, trackId);
215     auto transceiver = RTCRtpTransceiver::create(WTFMove(sender), WTFMove(receiver));
216     transceiver->setProvisionalMid(transceiverMid);
217
218     return completeAddTransceiver(WTFMove(transceiver), init);
219 }
220
221 RefPtr<RTCRtpTransceiver> RTCPeerConnection::completeAddTransceiver(Ref<RTCRtpTransceiver>&& transceiver, const RtpTransceiverInit& init)
222 {
223     transceiver->setDirection(static_cast<RTCRtpTransceiver::Direction>(init.direction));
224
225     m_transceiverSet->append(transceiver.copyRef());
226     m_backend->markAsNeedingNegotiation();
227
228     return WTFMove(transceiver);
229 }
230
231 void RTCPeerConnection::queuedCreateOffer(const Dictionary& offerOptions, SessionDescriptionPromise&& promise)
232 {
233     if (m_signalingState == SignalingState::Closed) {
234         promise.reject(INVALID_STATE_ERR);
235         return;
236     }
237
238     ExceptionCode ec = 0;
239     RefPtr<RTCOfferOptions> options = RTCOfferOptions::create(offerOptions, ec);
240     if (ec) {
241         promise.reject(OperationError, "Invalid createOffer argument");
242         return;
243     }
244     ASSERT(options);
245
246     m_backend->createOffer(*options, WTFMove(promise));
247 }
248
249 void RTCPeerConnection::queuedCreateAnswer(const Dictionary& answerOptions, SessionDescriptionPromise&& promise)
250 {
251     if (m_signalingState == SignalingState::Closed) {
252         promise.reject(INVALID_STATE_ERR);
253         return;
254     }
255
256     ExceptionCode ec = 0;
257     RefPtr<RTCAnswerOptions> options = RTCAnswerOptions::create(answerOptions, ec);
258     if (ec) {
259         promise.reject(OperationError, "Invalid createAnswer argument");
260         return;
261     }
262
263     m_backend->createAnswer(*options, WTFMove(promise));
264 }
265
266 void RTCPeerConnection::queuedSetLocalDescription(RTCSessionDescription& description, PeerConnection::VoidPromise&& promise)
267 {
268     if (m_signalingState == SignalingState::Closed) {
269         promise.reject(INVALID_STATE_ERR);
270         return;
271     }
272
273     m_backend->setLocalDescription(description, WTFMove(promise));
274 }
275
276 RefPtr<RTCSessionDescription> RTCPeerConnection::localDescription() const
277 {
278     return m_backend->localDescription();
279 }
280
281 RefPtr<RTCSessionDescription> RTCPeerConnection::currentLocalDescription() const
282 {
283     return m_backend->currentLocalDescription();
284 }
285
286 RefPtr<RTCSessionDescription> RTCPeerConnection::pendingLocalDescription() const
287 {
288     return m_backend->pendingLocalDescription();
289 }
290
291 void RTCPeerConnection::queuedSetRemoteDescription(RTCSessionDescription& description, PeerConnection::VoidPromise&& promise)
292 {
293     if (m_signalingState == SignalingState::Closed) {
294         promise.reject(INVALID_STATE_ERR);
295         return;
296     }
297
298     m_backend->setRemoteDescription(description, WTFMove(promise));
299 }
300
301 RefPtr<RTCSessionDescription> RTCPeerConnection::remoteDescription() const
302 {
303     return m_backend->remoteDescription();
304 }
305
306 RefPtr<RTCSessionDescription> RTCPeerConnection::currentRemoteDescription() const
307 {
308     return m_backend->currentRemoteDescription();
309 }
310
311 RefPtr<RTCSessionDescription> RTCPeerConnection::pendingRemoteDescription() const
312 {
313     return m_backend->pendingRemoteDescription();
314 }
315
316 void RTCPeerConnection::queuedAddIceCandidate(RTCIceCandidate& rtcCandidate, VoidPromise&& promise)
317 {
318     if (m_signalingState == SignalingState::Closed) {
319         promise.reject(INVALID_STATE_ERR);
320         return;
321     }
322
323     m_backend->addIceCandidate(rtcCandidate, WTFMove(promise));
324 }
325
326 String RTCPeerConnection::signalingState() const
327 {
328     switch (m_signalingState) {
329     case SignalingState::Stable:
330         return ASCIILiteral("stable");
331     case SignalingState::HaveLocalOffer:
332         return ASCIILiteral("have-local-offer");
333     case SignalingState::HaveRemoteOffer:
334         return ASCIILiteral("have-remote-offer");
335     case SignalingState::HaveLocalPrAnswer:
336         return ASCIILiteral("have-local-pranswer");
337     case SignalingState::HaveRemotePrAnswer:
338         return ASCIILiteral("have-remote-pranswer");
339     case SignalingState::Closed:
340         return ASCIILiteral("closed");
341     }
342
343     ASSERT_NOT_REACHED();
344     return String();
345 }
346
347 String RTCPeerConnection::iceGatheringState() const
348 {
349     switch (m_iceGatheringState) {
350     case IceGatheringState::New:
351         return ASCIILiteral("new");
352     case IceGatheringState::Gathering:
353         return ASCIILiteral("gathering");
354     case IceGatheringState::Complete:
355         return ASCIILiteral("complete");
356     }
357
358     ASSERT_NOT_REACHED();
359     return String();
360 }
361
362 String RTCPeerConnection::iceConnectionState() const
363 {
364     switch (m_iceConnectionState) {
365     case IceConnectionState::New:
366         return ASCIILiteral("new");
367     case IceConnectionState::Checking:
368         return ASCIILiteral("checking");
369     case IceConnectionState::Connected:
370         return ASCIILiteral("connected");
371     case IceConnectionState::Completed:
372         return ASCIILiteral("completed");
373     case IceConnectionState::Failed:
374         return ASCIILiteral("failed");
375     case IceConnectionState::Disconnected:
376         return ASCIILiteral("disconnected");
377     case IceConnectionState::Closed:
378         return ASCIILiteral("closed");
379     }
380
381     ASSERT_NOT_REACHED();
382     return String();
383 }
384
385 RTCConfiguration* RTCPeerConnection::getConfiguration() const
386 {
387     return m_configuration.get();
388 }
389
390 void RTCPeerConnection::setConfiguration(const Dictionary& configuration, ExceptionCode& ec)
391 {
392     if (configuration.isUndefinedOrNull()) {
393         ec = TypeError;
394         return;
395     }
396
397     if (m_signalingState == SignalingState::Closed) {
398         ec = INVALID_STATE_ERR;
399         return;
400     }
401
402     RefPtr<RTCConfiguration> newConfiguration = RTCConfiguration::create(configuration, ec);
403     if (ec)
404         return;
405
406     m_configuration = WTFMove(newConfiguration);
407     m_backend->setConfiguration(*m_configuration);
408 }
409
410 void RTCPeerConnection::privateGetStats(MediaStreamTrack* selector, PeerConnection::StatsPromise&& promise)
411 {
412     m_backend->getStats(selector, WTFMove(promise));
413 }
414
415 RefPtr<RTCDataChannel> RTCPeerConnection::createDataChannel(String, const Dictionary&, ExceptionCode& ec)
416 {
417     if (m_signalingState == SignalingState::Closed) {
418         ec = INVALID_STATE_ERR;
419         return nullptr;
420     }
421
422     return nullptr;
423 }
424
425 void RTCPeerConnection::close()
426 {
427     if (m_signalingState == SignalingState::Closed)
428         return;
429
430     m_backend->stop();
431
432     m_iceConnectionState = IceConnectionState::Closed;
433     m_signalingState = SignalingState::Closed;
434
435     for (auto& sender : m_transceiverSet->getSenders())
436         sender->stop();
437 }
438
439 void RTCPeerConnection::stop()
440 {
441     close();
442 }
443
444 const char* RTCPeerConnection::activeDOMObjectName() const
445 {
446     return "RTCPeerConnection";
447 }
448
449 bool RTCPeerConnection::canSuspendForDocumentSuspension() const
450 {
451     // FIXME: We should try and do better here.
452     return false;
453 }
454
455 void RTCPeerConnection::addTransceiver(RefPtr<RTCRtpTransceiver>&& transceiver)
456 {
457     m_transceiverSet->append(WTFMove(transceiver));
458 }
459
460 void RTCPeerConnection::setSignalingState(SignalingState newState)
461 {
462     m_signalingState = newState;
463 }
464
465 void RTCPeerConnection::updateIceGatheringState(IceGatheringState newState)
466 {
467     scriptExecutionContext()->postTask([=](ScriptExecutionContext&) {
468         m_iceGatheringState = newState;
469
470         dispatchEvent(Event::create(eventNames().icegatheringstatechangeEvent, false, false));
471     });
472 }
473
474 void RTCPeerConnection::updateIceConnectionState(IceConnectionState newState)
475 {
476     scriptExecutionContext()->postTask([=](ScriptExecutionContext&) {
477         m_iceConnectionState = newState;
478
479         dispatchEvent(Event::create(eventNames().iceconnectionstatechangeEvent, false, false));
480     });
481 }
482
483 void RTCPeerConnection::scheduleNegotiationNeededEvent()
484 {
485     scriptExecutionContext()->postTask([=](ScriptExecutionContext&) {
486         if (m_backend->isNegotiationNeeded()) {
487             dispatchEvent(Event::create(eventNames().negotiationneededEvent, false, false));
488             m_backend->clearNegotiationNeededState();
489         }
490     });
491 }
492
493 void RTCPeerConnection::fireEvent(Event& event)
494 {
495     dispatchEvent(event);
496 }
497
498 void RTCPeerConnection::replaceTrack(RTCRtpSender& sender, RefPtr<MediaStreamTrack>&& withTrack, PeerConnection::VoidPromise&& promise)
499 {
500     m_backend->replaceTrack(sender, WTFMove(withTrack), WTFMove(promise));
501 }
502
503 } // namespace WebCore
504
505 #endif // ENABLE(WEB_RTC)