Use "= default" to denote default constructor or destructor
[WebKit-https.git] / Source / WebCore / Modules / mediastream / libwebrtc / LibWebRTCPeerConnectionBackend.cpp
1 /*
2  * Copyright (C) 2017 Apple Inc.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1.  Redistributions of source code must retain the above copyright
8  *     notice, this list of conditions and the following disclaimer.
9  * 2.  Redistributions in binary form must reproduce the above copyright
10  *     notice, this list of conditions and the following disclaimer in the
11  *     documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
15  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
16  * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
17  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
19  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
20  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
22  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23  */
24
25 #include "config.h"
26 #include "LibWebRTCPeerConnectionBackend.h"
27
28 #if USE(LIBWEBRTC)
29
30 #include "Document.h"
31 #include "IceCandidate.h"
32 #include "JSRTCStatsReport.h"
33 #include "LibWebRTCDataChannelHandler.h"
34 #include "LibWebRTCMediaEndpoint.h"
35 #include "MediaEndpointConfiguration.h"
36 #include "Page.h"
37 #include "RTCIceCandidate.h"
38 #include "RTCPeerConnection.h"
39 #include "RTCRtpReceiver.h"
40 #include "RTCSessionDescription.h"
41 #include "RealtimeIncomingAudioSource.h"
42 #include "RealtimeIncomingVideoSource.h"
43
44 namespace WebCore {
45
46 static std::unique_ptr<PeerConnectionBackend> createLibWebRTCPeerConnectionBackend(RTCPeerConnection& peerConnection)
47 {
48     if (!LibWebRTCProvider::webRTCAvailable())
49         return nullptr;
50     return std::make_unique<LibWebRTCPeerConnectionBackend>(peerConnection);
51 }
52
53 CreatePeerConnectionBackend PeerConnectionBackend::create = createLibWebRTCPeerConnectionBackend;
54
55 static inline LibWebRTCProvider& libWebRTCProvider(RTCPeerConnection& peerConnection)
56 {
57     ASSERT(peerConnection.scriptExecutionContext()->isDocument());
58     auto* page = static_cast<Document*>(peerConnection.scriptExecutionContext())->page();
59     return page->libWebRTCProvider();
60 }
61
62 LibWebRTCPeerConnectionBackend::LibWebRTCPeerConnectionBackend(RTCPeerConnection& peerConnection)
63     : PeerConnectionBackend(peerConnection)
64     , m_endpoint(LibWebRTCMediaEndpoint::create(*this, libWebRTCProvider(peerConnection)))
65 {
66 }
67
68 LibWebRTCPeerConnectionBackend::~LibWebRTCPeerConnectionBackend() = default;
69
70 static inline webrtc::PeerConnectionInterface::BundlePolicy bundlePolicyfromConfiguration(const MediaEndpointConfiguration& configuration)
71 {
72     switch (configuration.bundlePolicy) {
73     case RTCBundlePolicy::MaxCompat:
74         return webrtc::PeerConnectionInterface::kBundlePolicyMaxCompat;
75     case RTCBundlePolicy::MaxBundle:
76         return webrtc::PeerConnectionInterface::kBundlePolicyMaxBundle;
77     case RTCBundlePolicy::Balanced:
78         return webrtc::PeerConnectionInterface::kBundlePolicyBalanced;
79     }
80 }
81
82 static inline webrtc::PeerConnectionInterface::IceTransportsType iceTransportPolicyfromConfiguration(const MediaEndpointConfiguration& configuration)
83 {
84     switch (configuration.iceTransportPolicy) {
85     case RTCIceTransportPolicy::Relay:
86         return webrtc::PeerConnectionInterface::kRelay;
87     case RTCIceTransportPolicy::All:
88         return webrtc::PeerConnectionInterface::kAll;
89     }
90 }
91
92 static webrtc::PeerConnectionInterface::RTCConfiguration configurationFromMediaEndpointConfiguration(MediaEndpointConfiguration&& configuration)
93 {
94     webrtc::PeerConnectionInterface::RTCConfiguration rtcConfiguration;
95
96     rtcConfiguration.type = iceTransportPolicyfromConfiguration(configuration);
97     rtcConfiguration.bundle_policy = bundlePolicyfromConfiguration(configuration);
98
99     for (auto& server : configuration.iceServers) {
100         webrtc::PeerConnectionInterface::IceServer iceServer;
101         iceServer.username = server.username.utf8().data();
102         iceServer.password = server.credential.utf8().data();
103         for (auto& url : server.urls)
104             iceServer.urls.push_back({ url.string().utf8().data() });
105         rtcConfiguration.servers.push_back(WTFMove(iceServer));
106     }
107
108     rtcConfiguration.set_cpu_adaptation(false);
109     // FIXME: Activate ice candidate pool size once it no longer bothers test bots.
110     // rtcConfiguration.ice_candidate_pool_size = configuration.iceCandidatePoolSize;
111
112     return rtcConfiguration;
113 }
114
115 bool LibWebRTCPeerConnectionBackend::setConfiguration(MediaEndpointConfiguration&& configuration)
116 {
117     return m_endpoint->setConfiguration(libWebRTCProvider(m_peerConnection), configurationFromMediaEndpointConfiguration(WTFMove(configuration)));
118 }
119
120 void LibWebRTCPeerConnectionBackend::getStats(MediaStreamTrack* track, Ref<DeferredPromise>&& promise)
121 {
122     if (m_endpoint->isStopped())
123         return;
124
125     auto& statsPromise = promise.get();
126     m_statsPromises.add(&statsPromise, WTFMove(promise));
127     m_endpoint->getStats(track, statsPromise);
128 }
129
130 void LibWebRTCPeerConnectionBackend::getStatsSucceeded(const DeferredPromise& promise, Ref<RTCStatsReport>&& report)
131 {
132     auto statsPromise = m_statsPromises.take(&promise);
133     ASSERT(statsPromise);
134     statsPromise.value()->resolve<IDLInterface<RTCStatsReport>>(WTFMove(report));
135 }
136
137 void LibWebRTCPeerConnectionBackend::getStatsFailed(const DeferredPromise& promise, Exception&& exception)
138 {
139     auto statsPromise = m_statsPromises.take(&promise);
140     ASSERT(statsPromise);
141     statsPromise.value()->reject(WTFMove(exception));
142 }
143
144 void LibWebRTCPeerConnectionBackend::doSetLocalDescription(RTCSessionDescription& description)
145 {
146     m_endpoint->doSetLocalDescription(description);
147     if (!m_isLocalDescriptionSet) {
148         if (m_isRemoteDescriptionSet) {
149             while (m_pendingCandidates.size())
150                 m_endpoint->addIceCandidate(*m_pendingCandidates.takeLast().release());
151         }
152         m_isLocalDescriptionSet = true;
153     }
154 }
155
156 void LibWebRTCPeerConnectionBackend::doSetRemoteDescription(RTCSessionDescription& description)
157 {
158     m_endpoint->doSetRemoteDescription(description);
159     if (!m_isRemoteDescriptionSet) {
160         if (m_isLocalDescriptionSet) {
161             while (m_pendingCandidates.size())
162                 m_endpoint->addIceCandidate(*m_pendingCandidates.takeLast().release());
163         }
164         m_isRemoteDescriptionSet = true;
165     }
166 }
167
168 void LibWebRTCPeerConnectionBackend::doCreateOffer(RTCOfferOptions&& options)
169 {
170     m_endpoint->doCreateOffer(options);
171 }
172
173 void LibWebRTCPeerConnectionBackend::doCreateAnswer(RTCAnswerOptions&&)
174 {
175     if (!m_isRemoteDescriptionSet) {
176         createAnswerFailed(Exception { InvalidStateError, "No remote description set" });
177         return;
178     }
179     m_endpoint->doCreateAnswer();
180 }
181
182 void LibWebRTCPeerConnectionBackend::doStop()
183 {
184     for (auto& source : m_audioSources)
185         source->stop();
186     for (auto& source : m_videoSources)
187         source->stop();
188
189     m_endpoint->stop();
190
191     m_remoteStreams.clear();
192     m_pendingReceivers.clear();
193 }
194
195 void LibWebRTCPeerConnectionBackend::doAddIceCandidate(RTCIceCandidate& candidate)
196 {
197     webrtc::SdpParseError error;
198     int sdpMLineIndex = candidate.sdpMLineIndex() ? candidate.sdpMLineIndex().value() : 0;
199     std::unique_ptr<webrtc::IceCandidateInterface> rtcCandidate(webrtc::CreateIceCandidate(candidate.sdpMid().utf8().data(), sdpMLineIndex, candidate.candidate().utf8().data(), &error));
200
201     if (!rtcCandidate) {
202         String message(error.description.data(), error.description.size());
203         addIceCandidateFailed(Exception { OperationError, WTFMove(message) });
204         return;
205     }
206
207     // libwebrtc does not like that ice candidates are set before the description.
208     if (!m_isLocalDescriptionSet || !m_isRemoteDescriptionSet)
209         m_pendingCandidates.append(WTFMove(rtcCandidate));
210     else if (!m_endpoint->addIceCandidate(*rtcCandidate.get())) {
211         ASSERT_NOT_REACHED();
212         addIceCandidateFailed(Exception { OperationError, ASCIILiteral("Failed to apply the received candidate") });
213         return;
214     }
215     addIceCandidateSucceeded();
216 }
217
218 void LibWebRTCPeerConnectionBackend::addAudioSource(Ref<RealtimeOutgoingAudioSource>&& source)
219 {
220     m_audioSources.append(WTFMove(source));
221 }
222
223 void LibWebRTCPeerConnectionBackend::addVideoSource(Ref<RealtimeOutgoingVideoSource>&& source)
224 {
225     m_videoSources.append(WTFMove(source));
226 }
227
228 static inline Ref<RTCRtpReceiver> createReceiverForSource(ScriptExecutionContext& context, Ref<RealtimeMediaSource>&& source)
229 {
230     String id = source->id();
231     auto remoteTrackPrivate = MediaStreamTrackPrivate::create(WTFMove(source), WTFMove(id));
232     auto remoteTrack = MediaStreamTrack::create(context, WTFMove(remoteTrackPrivate));
233
234     return RTCRtpReceiver::create(WTFMove(remoteTrack));
235 }
236
237 static inline Ref<RealtimeMediaSource> createEmptySource(const String& trackKind, String&& trackId)
238 {
239     // FIXME: trackKind should be an enumeration
240     if (trackKind == "audio")
241         return RealtimeIncomingAudioSource::create(nullptr, WTFMove(trackId));
242     ASSERT(trackKind == "video");
243     return RealtimeIncomingVideoSource::create(nullptr, WTFMove(trackId));
244 }
245
246 Ref<RTCRtpReceiver> LibWebRTCPeerConnectionBackend::createReceiver(const String&, const String& trackKind, const String& trackId)
247 {
248     auto receiver = createReceiverForSource(*m_peerConnection.scriptExecutionContext(), createEmptySource(trackKind, String(trackId)));
249     m_pendingReceivers.append(receiver.copyRef());
250     return receiver;
251 }
252
253 LibWebRTCPeerConnectionBackend::VideoReceiver LibWebRTCPeerConnectionBackend::videoReceiver(String&& trackId)
254 {
255     // FIXME: Add to Vector a utility routine for that take-or-create pattern.
256     // FIXME: We should be selecting the receiver based on track id.
257     for (size_t cptr = 0; cptr < m_pendingReceivers.size(); ++cptr) {
258         if (m_pendingReceivers[cptr]->track()->source().type() == RealtimeMediaSource::Type::Video) {
259             Ref<RTCRtpReceiver> receiver = m_pendingReceivers[cptr].copyRef();
260             m_pendingReceivers.remove(cptr);
261             Ref<RealtimeIncomingVideoSource> source = static_cast<RealtimeIncomingVideoSource&>(receiver->track()->source());
262             return { WTFMove(receiver), WTFMove(source) };
263         }
264     }
265     auto source = RealtimeIncomingVideoSource::create(nullptr, WTFMove(trackId));
266     auto receiver = createReceiverForSource(*m_peerConnection.scriptExecutionContext(), source.copyRef());
267
268     auto transceiver = RTCRtpTransceiver::create(RTCRtpSender::create("video", { }, m_peerConnection), receiver.copyRef());
269     transceiver->disableSendingDirection();
270     m_peerConnection.addTransceiver(WTFMove(transceiver));
271
272     return { WTFMove(receiver), WTFMove(source) };
273 }
274
275 LibWebRTCPeerConnectionBackend::AudioReceiver LibWebRTCPeerConnectionBackend::audioReceiver(String&& trackId)
276 {
277     // FIXME: Add to Vector a utility routine for that take-or-create pattern.
278     // FIXME: We should be selecting the receiver based on track id.
279     for (size_t cptr = 0; cptr < m_pendingReceivers.size(); ++cptr) {
280         if (m_pendingReceivers[cptr]->track()->source().type() == RealtimeMediaSource::Type::Audio) {
281             Ref<RTCRtpReceiver> receiver = m_pendingReceivers[cptr].copyRef();
282             m_pendingReceivers.remove(cptr);
283             Ref<RealtimeIncomingAudioSource> source = static_cast<RealtimeIncomingAudioSource&>(receiver->track()->source());
284             return { WTFMove(receiver), WTFMove(source) };
285         }
286     }
287     auto source = RealtimeIncomingAudioSource::create(nullptr, WTFMove(trackId));
288     auto receiver = createReceiverForSource(*m_peerConnection.scriptExecutionContext(), source.copyRef());
289
290     auto transceiver = RTCRtpTransceiver::create(RTCRtpSender::create("audio", { }, m_peerConnection), receiver.copyRef());
291     transceiver->disableSendingDirection();
292     m_peerConnection.addTransceiver(WTFMove(transceiver));
293
294     return { WTFMove(receiver), WTFMove(source) };
295 }
296
297 std::unique_ptr<RTCDataChannelHandler> LibWebRTCPeerConnectionBackend::createDataChannelHandler(const String& label, const RTCDataChannelInit& options)
298 {
299     return m_endpoint->createDataChannel(label, options);
300 }
301
302 RefPtr<RTCSessionDescription> LibWebRTCPeerConnectionBackend::currentLocalDescription() const
303 {
304     auto description = m_endpoint->currentLocalDescription();
305     if (description)
306         description->setSdp(filterSDP(String(description->sdp())));
307     return description;
308 }
309
310 RefPtr<RTCSessionDescription> LibWebRTCPeerConnectionBackend::currentRemoteDescription() const
311 {
312     return m_endpoint->currentRemoteDescription();
313 }
314
315 RefPtr<RTCSessionDescription> LibWebRTCPeerConnectionBackend::pendingLocalDescription() const
316 {
317     auto description = m_endpoint->pendingLocalDescription();
318     if (description)
319         description->setSdp(filterSDP(String(description->sdp())));
320     return description;
321 }
322
323 RefPtr<RTCSessionDescription> LibWebRTCPeerConnectionBackend::pendingRemoteDescription() const
324 {
325     return m_endpoint->pendingRemoteDescription();
326 }
327
328 RefPtr<RTCSessionDescription> LibWebRTCPeerConnectionBackend::localDescription() const
329 {
330     auto description = m_endpoint->localDescription();
331     if (description)
332         description->setSdp(filterSDP(String(description->sdp())));
333     return description;
334 }
335
336 RefPtr<RTCSessionDescription> LibWebRTCPeerConnectionBackend::remoteDescription() const
337 {
338     return m_endpoint->remoteDescription();
339 }
340
341 void LibWebRTCPeerConnectionBackend::notifyAddedTrack(RTCRtpSender& sender)
342 {
343     ASSERT(sender.track());
344     m_endpoint->addTrack(sender, *sender.track(), sender.mediaStreamIds());
345 }
346
347 void LibWebRTCPeerConnectionBackend::notifyRemovedTrack(RTCRtpSender& sender)
348 {
349     m_endpoint->removeTrack(sender);
350 }
351
352 void LibWebRTCPeerConnectionBackend::removeRemoteStream(MediaStream* mediaStream)
353 {
354     m_remoteStreams.removeFirstMatching([mediaStream](const auto& item) {
355         return item.get() == mediaStream;
356     });
357 }
358
359 void LibWebRTCPeerConnectionBackend::addRemoteStream(Ref<MediaStream>&& mediaStream)
360 {
361     m_remoteStreams.append(WTFMove(mediaStream));
362 }
363
364 void LibWebRTCPeerConnectionBackend::replaceTrack(RTCRtpSender& sender, Ref<MediaStreamTrack>&& track, DOMPromiseDeferred<void>&& promise)
365 {
366     ASSERT(sender.track());
367     auto* currentTrack = sender.track();
368
369     ASSERT(currentTrack->source().type() == track->source().type());
370     switch (currentTrack->source().type()) {
371     case RealtimeMediaSource::Type::None:
372         ASSERT_NOT_REACHED();
373         promise.reject(InvalidModificationError);
374         break;
375     case RealtimeMediaSource::Type::Audio: {
376         for (auto& audioSource : m_audioSources) {
377             if (&audioSource->source() == &currentTrack->privateTrack()) {
378                 if (!audioSource->setSource(track->privateTrack())) {
379                     promise.reject(InvalidModificationError);
380                     return;
381                 }
382                 connection().enqueueReplaceTrackTask(sender, WTFMove(track), WTFMove(promise));
383                 return;
384             }
385         }
386         promise.reject(InvalidModificationError);
387         break;
388     }
389     case RealtimeMediaSource::Type::Video: {
390         for (auto& videoSource : m_videoSources) {
391             if (&videoSource->source() == &currentTrack->privateTrack()) {
392                 if (!videoSource->setSource(track->privateTrack())) {
393                     promise.reject(InvalidModificationError);
394                     return;
395                 }
396                 connection().enqueueReplaceTrackTask(sender, WTFMove(track), WTFMove(promise));
397                 return;
398             }
399         }
400         promise.reject(InvalidModificationError);
401         break;
402     }
403     }
404 }
405
406 RTCRtpParameters LibWebRTCPeerConnectionBackend::getParameters(RTCRtpSender& sender) const
407 {
408     return m_endpoint->getRTCRtpSenderParameters(sender);
409 }
410
411 void LibWebRTCPeerConnectionBackend::applyRotationForOutgoingVideoSources()
412 {
413     for (auto& source : m_videoSources)
414         source->setApplyRotation(true);
415 }
416
417 } // namespace WebCore
418
419 #endif // USE(LIBWEBRTC)