Add iceCandidatePoolSize to RTCConfiguration
[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()
69 {
70 }
71
72 static webrtc::PeerConnectionInterface::RTCConfiguration configurationFromMediaEndpointConfiguration(MediaEndpointConfiguration&& configuration)
73 {
74     webrtc::PeerConnectionInterface::RTCConfiguration rtcConfiguration;
75
76     if (configuration.iceTransportPolicy == RTCIceTransportPolicy::Relay)
77         rtcConfiguration.type = webrtc::PeerConnectionInterface::kRelay;
78
79     // FIXME: Support PeerConnectionStates::BundlePolicy::MaxBundle.
80     // LibWebRTC does not like it and will fail to set any configuration field otherwise.
81     // See https://bugs.webkit.org/show_bug.cgi?id=169389.
82
83     if (configuration.bundlePolicy == RTCBundlePolicy::MaxCompat)
84         rtcConfiguration.bundle_policy = webrtc::PeerConnectionInterface::kBundlePolicyMaxCompat;
85
86     for (auto& server : configuration.iceServers) {
87         webrtc::PeerConnectionInterface::IceServer iceServer;
88         iceServer.username = server.username.utf8().data();
89         iceServer.password = server.credential.utf8().data();
90         for (auto& url : server.urls)
91             iceServer.urls.push_back({ url.string().utf8().data() });
92         rtcConfiguration.servers.push_back(WTFMove(iceServer));
93     }
94
95     rtcConfiguration.ice_candidate_pool_size = configuration.iceCandidatePoolSize;
96
97     return rtcConfiguration;
98 }
99
100 void LibWebRTCPeerConnectionBackend::setConfiguration(MediaEndpointConfiguration&& configuration)
101 {
102     m_endpoint->backend().SetConfiguration(configurationFromMediaEndpointConfiguration(WTFMove(configuration)));
103 }
104
105 void LibWebRTCPeerConnectionBackend::getStats(MediaStreamTrack* track, Ref<DeferredPromise>&& promise)
106 {
107     if (m_endpoint->isStopped())
108         return;
109
110     auto& statsPromise = promise.get();
111     m_statsPromises.add(&statsPromise, WTFMove(promise));
112     m_endpoint->getStats(track, statsPromise);
113 }
114
115 void LibWebRTCPeerConnectionBackend::getStatsSucceeded(const DeferredPromise& promise, Ref<RTCStatsReport>&& report)
116 {
117     auto statsPromise = m_statsPromises.take(&promise);
118     ASSERT(statsPromise);
119     statsPromise.value()->resolve<IDLInterface<RTCStatsReport>>(WTFMove(report));
120 }
121
122 void LibWebRTCPeerConnectionBackend::getStatsFailed(const DeferredPromise& promise, Exception&& exception)
123 {
124     auto statsPromise = m_statsPromises.take(&promise);
125     ASSERT(statsPromise);
126     statsPromise.value()->reject(WTFMove(exception));
127 }
128
129 void LibWebRTCPeerConnectionBackend::doSetLocalDescription(RTCSessionDescription& description)
130 {
131     m_endpoint->doSetLocalDescription(description);
132     if (!m_isLocalDescriptionSet) {
133         if (m_isRemoteDescriptionSet) {
134             while (m_pendingCandidates.size())
135                 m_endpoint->addIceCandidate(*m_pendingCandidates.takeLast().release());
136         }
137         m_isLocalDescriptionSet = true;
138     }
139 }
140
141 void LibWebRTCPeerConnectionBackend::doSetRemoteDescription(RTCSessionDescription& description)
142 {
143     m_endpoint->doSetRemoteDescription(description);
144     if (!m_isRemoteDescriptionSet) {
145         if (m_isLocalDescriptionSet) {
146             while (m_pendingCandidates.size())
147                 m_endpoint->addIceCandidate(*m_pendingCandidates.takeLast().release());
148         }
149         m_isRemoteDescriptionSet = true;
150     }
151 }
152
153 void LibWebRTCPeerConnectionBackend::doCreateOffer(RTCOfferOptions&&)
154 {
155     m_endpoint->doCreateOffer();
156 }
157
158 void LibWebRTCPeerConnectionBackend::doCreateAnswer(RTCAnswerOptions&&)
159 {
160     if (!m_isRemoteDescriptionSet) {
161         createAnswerFailed(Exception { INVALID_STATE_ERR, "No remote description set" });
162         return;
163     }
164     m_endpoint->doCreateAnswer();
165 }
166
167 void LibWebRTCPeerConnectionBackend::doStop()
168 {
169     for (auto& source : m_audioSources)
170         source->stop();
171     for (auto& source : m_videoSources)
172         source->stop();
173
174     m_endpoint->stop();
175
176     m_remoteStreams.clear();
177     m_pendingReceivers.clear();
178 }
179
180 void LibWebRTCPeerConnectionBackend::doAddIceCandidate(RTCIceCandidate& candidate)
181 {
182     webrtc::SdpParseError error;
183     int sdpMLineIndex = candidate.sdpMLineIndex() ? candidate.sdpMLineIndex().value() : 0;
184     std::unique_ptr<webrtc::IceCandidateInterface> rtcCandidate(webrtc::CreateIceCandidate(candidate.sdpMid().utf8().data(), sdpMLineIndex, candidate.candidate().utf8().data(), &error));
185
186     if (!rtcCandidate) {
187         String message(error.description.data(), error.description.size());
188         addIceCandidateFailed(Exception { OperationError, WTFMove(message) });
189         return;
190     }
191
192     // libwebrtc does not like that ice candidates are set before the description.
193     if (!m_isLocalDescriptionSet || !m_isRemoteDescriptionSet)
194         m_pendingCandidates.append(WTFMove(rtcCandidate));
195     else if (!m_endpoint->addIceCandidate(*rtcCandidate.get())) {
196         ASSERT_NOT_REACHED();
197         addIceCandidateFailed(Exception { OperationError, ASCIILiteral("Failed to apply the received candidate") });
198         return;
199     }
200     addIceCandidateSucceeded();
201 }
202
203 void LibWebRTCPeerConnectionBackend::addAudioSource(Ref<RealtimeOutgoingAudioSource>&& source)
204 {
205     m_audioSources.append(WTFMove(source));
206 }
207
208 void LibWebRTCPeerConnectionBackend::addVideoSource(Ref<RealtimeOutgoingVideoSource>&& source)
209 {
210     m_videoSources.append(WTFMove(source));
211 }
212
213 static inline Ref<RTCRtpReceiver> createReceiverForSource(ScriptExecutionContext& context, Ref<RealtimeMediaSource>&& source)
214 {
215     auto remoteTrackPrivate = MediaStreamTrackPrivate::create(WTFMove(source));
216     auto remoteTrack = MediaStreamTrack::create(context, WTFMove(remoteTrackPrivate));
217
218     return RTCRtpReceiver::create(WTFMove(remoteTrack));
219 }
220
221 static inline Ref<RealtimeMediaSource> createEmptySource(const String& trackKind, String&& trackId)
222 {
223     // FIXME: trackKind should be an enumeration
224     if (trackKind == "audio")
225         return RealtimeIncomingAudioSource::create(nullptr, WTFMove(trackId));
226     ASSERT(trackKind == "video");
227     return RealtimeIncomingVideoSource::create(nullptr, WTFMove(trackId));
228 }
229
230 Ref<RTCRtpReceiver> LibWebRTCPeerConnectionBackend::createReceiver(const String&, const String& trackKind, const String& trackId)
231 {
232     auto receiver = createReceiverForSource(*m_peerConnection.scriptExecutionContext(), createEmptySource(trackKind, String(trackId)));
233     m_pendingReceivers.append(receiver.copyRef());
234     return receiver;
235 }
236
237 LibWebRTCPeerConnectionBackend::VideoReceiver LibWebRTCPeerConnectionBackend::videoReceiver(String&& trackId)
238 {
239     // FIXME: Add to Vector a utility routine for that take-or-create pattern.
240     // FIXME: We should be selecting the receiver based on track id.
241     for (size_t cptr = 0; cptr < m_pendingReceivers.size(); ++cptr) {
242         if (m_pendingReceivers[cptr]->track()->source().type() == RealtimeMediaSource::Type::Video) {
243             Ref<RTCRtpReceiver> receiver = m_pendingReceivers[cptr].copyRef();
244             m_pendingReceivers.remove(cptr);
245             Ref<RealtimeIncomingVideoSource> source = static_cast<RealtimeIncomingVideoSource&>(receiver->track()->source());
246             return { WTFMove(receiver), WTFMove(source) };
247         }
248     }
249     auto source = RealtimeIncomingVideoSource::create(nullptr, WTFMove(trackId));
250     auto receiver = createReceiverForSource(*m_peerConnection.scriptExecutionContext(), source.copyRef());
251     return { WTFMove(receiver), WTFMove(source) };
252 }
253
254 LibWebRTCPeerConnectionBackend::AudioReceiver LibWebRTCPeerConnectionBackend::audioReceiver(String&& trackId)
255 {
256     // FIXME: Add to Vector a utility routine for that take-or-create pattern.
257     // FIXME: We should be selecting the receiver based on track id.
258     for (size_t cptr = 0; cptr < m_pendingReceivers.size(); ++cptr) {
259         if (m_pendingReceivers[cptr]->track()->source().type() == RealtimeMediaSource::Type::Audio) {
260             Ref<RTCRtpReceiver> receiver = m_pendingReceivers[cptr].copyRef();
261             m_pendingReceivers.remove(cptr);
262             Ref<RealtimeIncomingAudioSource> source = static_cast<RealtimeIncomingAudioSource&>(receiver->track()->source());
263             return { WTFMove(receiver), WTFMove(source) };
264         }
265     }
266     auto source = RealtimeIncomingAudioSource::create(nullptr, WTFMove(trackId));
267     auto receiver = createReceiverForSource(*m_peerConnection.scriptExecutionContext(), source.copyRef());
268     return { WTFMove(receiver), WTFMove(source) };
269 }
270
271 std::unique_ptr<RTCDataChannelHandler> LibWebRTCPeerConnectionBackend::createDataChannelHandler(const String& label, const RTCDataChannelInit& options)
272 {
273     return m_endpoint->createDataChannel(label, options);
274 }
275
276 RefPtr<RTCSessionDescription> LibWebRTCPeerConnectionBackend::currentLocalDescription() const
277 {
278     return m_endpoint->currentLocalDescription();
279 }
280
281 RefPtr<RTCSessionDescription> LibWebRTCPeerConnectionBackend::currentRemoteDescription() const
282 {
283     return m_endpoint->currentRemoteDescription();
284 }
285
286 RefPtr<RTCSessionDescription> LibWebRTCPeerConnectionBackend::pendingLocalDescription() const
287 {
288     return m_endpoint->pendingLocalDescription();
289 }
290
291 RefPtr<RTCSessionDescription> LibWebRTCPeerConnectionBackend::pendingRemoteDescription() const
292 {
293     return m_endpoint->pendingRemoteDescription();
294 }
295
296 RefPtr<RTCSessionDescription> LibWebRTCPeerConnectionBackend::localDescription() const
297 {
298     return m_endpoint->localDescription();
299 }
300
301 RefPtr<RTCSessionDescription> LibWebRTCPeerConnectionBackend::remoteDescription() const
302 {
303     return m_endpoint->remoteDescription();
304 }
305
306 void LibWebRTCPeerConnectionBackend::notifyAddedTrack(RTCRtpSender& sender)
307 {
308     ASSERT(sender.track());
309     m_endpoint->addTrack(*sender.track(), sender.mediaStreamIds());
310 }
311
312 void LibWebRTCPeerConnectionBackend::removeRemoteStream(MediaStream* mediaStream)
313 {
314     m_remoteStreams.removeFirstMatching([mediaStream](const auto& item) {
315         return item.get() == mediaStream;
316     });
317 }
318
319 void LibWebRTCPeerConnectionBackend::addRemoteStream(Ref<MediaStream>&& mediaStream)
320 {
321     m_remoteStreams.append(WTFMove(mediaStream));
322 }
323
324 } // namespace WebCore
325
326 #endif // USE(LIBWEBRTC)