[JSC tests] Skip slow tests on Watch S3 and Watch S4
[WebKit-https.git] / Source / WebCore / Modules / mediastream / libwebrtc / LibWebRTCPeerConnectionBackend.cpp
1 /*
2  * Copyright (C) 2017-2018 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 "LibWebRTCDataChannelHandler.h"
33 #include "LibWebRTCMediaEndpoint.h"
34 #include "LibWebRTCRtpReceiverBackend.h"
35 #include "LibWebRTCRtpSenderBackend.h"
36 #include "LibWebRTCRtpTransceiverBackend.h"
37 #include "MediaEndpointConfiguration.h"
38 #include "Page.h"
39 #include "RTCIceCandidate.h"
40 #include "RTCPeerConnection.h"
41 #include "RTCRtpCapabilities.h"
42 #include "RTCRtpReceiver.h"
43 #include "RTCSessionDescription.h"
44 #include "RealtimeIncomingAudioSource.h"
45 #include "RealtimeIncomingVideoSource.h"
46 #include "RealtimeOutgoingAudioSource.h"
47 #include "RealtimeOutgoingVideoSource.h"
48 #include "Settings.h"
49
50 namespace WebCore {
51
52 static std::unique_ptr<PeerConnectionBackend> createLibWebRTCPeerConnectionBackend(RTCPeerConnection& peerConnection)
53 {
54     if (!LibWebRTCProvider::webRTCAvailable())
55         return nullptr;
56
57     auto* page = downcast<Document>(*peerConnection.scriptExecutionContext()).page();
58     if (!page)
59         return nullptr;
60
61     page->libWebRTCProvider().setEnableWebRTCEncryption(page->settings().webRTCEncryptionEnabled());
62
63     return makeUnique<LibWebRTCPeerConnectionBackend>(peerConnection, page->libWebRTCProvider());
64 }
65
66 CreatePeerConnectionBackend PeerConnectionBackend::create = createLibWebRTCPeerConnectionBackend;
67
68 Optional<RTCRtpCapabilities> PeerConnectionBackend::receiverCapabilities(ScriptExecutionContext& context, const String& kind)
69 {
70     auto* page = downcast<Document>(context).page();
71     if (!page)
72         return { };
73     return page->libWebRTCProvider().receiverCapabilities(kind);
74 }
75
76 Optional<RTCRtpCapabilities> PeerConnectionBackend::senderCapabilities(ScriptExecutionContext& context, const String& kind)
77 {
78     auto* page = downcast<Document>(context).page();
79     if (!page)
80         return { };
81     return page->libWebRTCProvider().senderCapabilities(kind);
82 }
83
84 LibWebRTCPeerConnectionBackend::LibWebRTCPeerConnectionBackend(RTCPeerConnection& peerConnection, LibWebRTCProvider& provider)
85     : PeerConnectionBackend(peerConnection)
86     , m_endpoint(LibWebRTCMediaEndpoint::create(*this, provider))
87 {
88 }
89
90 LibWebRTCPeerConnectionBackend::~LibWebRTCPeerConnectionBackend() = default;
91
92 void LibWebRTCPeerConnectionBackend::suspend()
93 {
94     m_endpoint->suspend();
95 }
96
97 void LibWebRTCPeerConnectionBackend::resume()
98 {
99     m_endpoint->resume();
100 }
101
102 static inline webrtc::PeerConnectionInterface::BundlePolicy bundlePolicyfromConfiguration(const MediaEndpointConfiguration& configuration)
103 {
104     switch (configuration.bundlePolicy) {
105     case RTCBundlePolicy::MaxCompat:
106         return webrtc::PeerConnectionInterface::kBundlePolicyMaxCompat;
107     case RTCBundlePolicy::MaxBundle:
108         return webrtc::PeerConnectionInterface::kBundlePolicyMaxBundle;
109     case RTCBundlePolicy::Balanced:
110         return webrtc::PeerConnectionInterface::kBundlePolicyBalanced;
111     }
112
113     ASSERT_NOT_REACHED();
114     return webrtc::PeerConnectionInterface::kBundlePolicyMaxCompat;
115 }
116
117 static inline webrtc::PeerConnectionInterface::RtcpMuxPolicy rtcpMuxPolicyfromConfiguration(const MediaEndpointConfiguration& configuration)
118 {
119     switch (configuration.rtcpMuxPolicy) {
120     case RTCPMuxPolicy::Negotiate:
121         return webrtc::PeerConnectionInterface::kRtcpMuxPolicyNegotiate;
122     case RTCPMuxPolicy::Require:
123         return webrtc::PeerConnectionInterface::kRtcpMuxPolicyRequire;
124     }
125
126     ASSERT_NOT_REACHED();
127     return webrtc::PeerConnectionInterface::kRtcpMuxPolicyRequire;
128 }
129
130 static inline webrtc::PeerConnectionInterface::IceTransportsType iceTransportPolicyfromConfiguration(const MediaEndpointConfiguration& configuration)
131 {
132     switch (configuration.iceTransportPolicy) {
133     case RTCIceTransportPolicy::Relay:
134         return webrtc::PeerConnectionInterface::kRelay;
135     case RTCIceTransportPolicy::All:
136         return webrtc::PeerConnectionInterface::kAll;
137     }
138
139     ASSERT_NOT_REACHED();
140     return webrtc::PeerConnectionInterface::kNone;
141 }
142
143 static webrtc::PeerConnectionInterface::RTCConfiguration configurationFromMediaEndpointConfiguration(MediaEndpointConfiguration&& configuration)
144 {
145     webrtc::PeerConnectionInterface::RTCConfiguration rtcConfiguration;
146
147     rtcConfiguration.type = iceTransportPolicyfromConfiguration(configuration);
148     rtcConfiguration.bundle_policy = bundlePolicyfromConfiguration(configuration);
149     rtcConfiguration.rtcp_mux_policy = rtcpMuxPolicyfromConfiguration(configuration);
150
151     for (auto& server : configuration.iceServers) {
152         webrtc::PeerConnectionInterface::IceServer iceServer;
153         iceServer.username = server.username.utf8().data();
154         iceServer.password = server.credential.utf8().data();
155         for (auto& url : server.urls)
156             iceServer.urls.push_back({ url.string().utf8().data() });
157         rtcConfiguration.servers.push_back(WTFMove(iceServer));
158     }
159
160     rtcConfiguration.set_cpu_adaptation(false);
161     // FIXME: Activate ice candidate pool size once it no longer bothers test bots.
162     // rtcConfiguration.ice_candidate_pool_size = configuration.iceCandidatePoolSize;
163
164     for (auto& pem : configuration.certificates) {
165         rtcConfiguration.certificates.push_back(rtc::RTCCertificate::FromPEM(rtc::RTCCertificatePEM {
166             pem.privateKey.utf8().data(), pem.certificate.utf8().data()
167         }));
168     }
169
170     return rtcConfiguration;
171 }
172
173 bool LibWebRTCPeerConnectionBackend::setConfiguration(MediaEndpointConfiguration&& configuration)
174 {
175     auto* page = downcast<Document>(*m_peerConnection.scriptExecutionContext()).page();
176     if (!page)
177         return false;
178
179     return m_endpoint->setConfiguration(page->libWebRTCProvider(), configurationFromMediaEndpointConfiguration(WTFMove(configuration)));
180 }
181
182 void LibWebRTCPeerConnectionBackend::getStats(Ref<DeferredPromise>&& promise)
183 {
184     m_endpoint->getStats(WTFMove(promise));
185 }
186
187 static inline LibWebRTCRtpSenderBackend& backendFromRTPSender(RTCRtpSender& sender)
188 {
189     ASSERT(!sender.isStopped());
190     return static_cast<LibWebRTCRtpSenderBackend&>(*sender.backend());
191 }
192
193 void LibWebRTCPeerConnectionBackend::getStats(RTCRtpSender& sender, Ref<DeferredPromise>&& promise)
194 {
195     webrtc::RtpSenderInterface* rtcSender = sender.backend() ? backendFromRTPSender(sender).rtcSender() : nullptr;
196
197     if (!rtcSender) {
198         m_endpoint->getStats(WTFMove(promise));
199         return;
200     }
201     m_endpoint->getStats(*rtcSender, WTFMove(promise));
202 }
203
204 void LibWebRTCPeerConnectionBackend::getStats(RTCRtpReceiver& receiver, Ref<DeferredPromise>&& promise)
205 {
206     webrtc::RtpReceiverInterface* rtcReceiver = receiver.backend() ? static_cast<LibWebRTCRtpReceiverBackend*>(receiver.backend())->rtcReceiver() : nullptr;
207
208     if (!rtcReceiver) {
209         m_endpoint->getStats(WTFMove(promise));
210         return;
211     }
212     m_endpoint->getStats(*rtcReceiver, WTFMove(promise));
213 }
214
215 void LibWebRTCPeerConnectionBackend::doSetLocalDescription(RTCSessionDescription& description)
216 {
217     m_endpoint->doSetLocalDescription(description);
218     if (!m_isLocalDescriptionSet) {
219         if (m_isRemoteDescriptionSet) {
220             for (auto& candidate : m_pendingCandidates)
221                 m_endpoint->addIceCandidate(*candidate);
222             m_pendingCandidates.clear();
223         }
224         m_isLocalDescriptionSet = true;
225     }
226 }
227
228 void LibWebRTCPeerConnectionBackend::doSetRemoteDescription(RTCSessionDescription& description)
229 {
230     m_endpoint->doSetRemoteDescription(description);
231     if (!m_isRemoteDescriptionSet) {
232         if (m_isLocalDescriptionSet) {
233             for (auto& candidate : m_pendingCandidates)
234                 m_endpoint->addIceCandidate(*candidate);
235         }
236         m_isRemoteDescriptionSet = true;
237     }
238 }
239
240 void LibWebRTCPeerConnectionBackend::doCreateOffer(RTCOfferOptions&& options)
241 {
242     m_endpoint->doCreateOffer(options);
243 }
244
245 void LibWebRTCPeerConnectionBackend::doCreateAnswer(RTCAnswerOptions&&)
246 {
247     if (!m_isRemoteDescriptionSet) {
248         createAnswerFailed(Exception { InvalidStateError, "No remote description set" });
249         return;
250     }
251     m_endpoint->doCreateAnswer();
252 }
253
254 void LibWebRTCPeerConnectionBackend::doStop()
255 {
256     m_endpoint->stop();
257     m_pendingReceivers.clear();
258 }
259
260 void LibWebRTCPeerConnectionBackend::doAddIceCandidate(RTCIceCandidate& candidate)
261 {
262     webrtc::SdpParseError error;
263     int sdpMLineIndex = candidate.sdpMLineIndex() ? candidate.sdpMLineIndex().value() : 0;
264     std::unique_ptr<webrtc::IceCandidateInterface> rtcCandidate(webrtc::CreateIceCandidate(candidate.sdpMid().utf8().data(), sdpMLineIndex, candidate.candidate().utf8().data(), &error));
265
266     if (!rtcCandidate) {
267         addIceCandidateFailed(Exception { OperationError, String::fromUTF8(error.description.data(), error.description.length()) });
268         return;
269     }
270
271     // libwebrtc does not like that ice candidates are set before the description.
272     if (!m_isLocalDescriptionSet || !m_isRemoteDescriptionSet)
273         m_pendingCandidates.append(WTFMove(rtcCandidate));
274     else if (!m_endpoint->addIceCandidate(*rtcCandidate.get())) {
275         ASSERT_NOT_REACHED();
276         addIceCandidateFailed(Exception { OperationError, "Failed to apply the received candidate"_s });
277         return;
278     }
279     addIceCandidateSucceeded();
280 }
281
282 Ref<RTCRtpReceiver> LibWebRTCPeerConnectionBackend::createReceiverForSource(Ref<RealtimeMediaSource>&& source, std::unique_ptr<RTCRtpReceiverBackend>&& backend)
283 {
284     auto& document = downcast<Document>(*m_peerConnection.scriptExecutionContext());
285     auto trackID = source->persistentID();
286     auto remoteTrackPrivate = MediaStreamTrackPrivate::create(document.logger(), WTFMove(source), WTFMove(trackID));
287     auto remoteTrack = MediaStreamTrack::create(document, WTFMove(remoteTrackPrivate));
288
289     return RTCRtpReceiver::create(*this, WTFMove(remoteTrack), WTFMove(backend));
290 }
291
292 static inline Ref<RealtimeMediaSource> createEmptySource(const String& trackKind, String&& trackId)
293 {
294     // FIXME: trackKind should be an enumeration
295     if (trackKind == "audio")
296         return RealtimeIncomingAudioSource::create(nullptr, WTFMove(trackId));
297     ASSERT(trackKind == "video");
298     return RealtimeIncomingVideoSource::create(nullptr, WTFMove(trackId));
299 }
300
301 Ref<RTCRtpReceiver> LibWebRTCPeerConnectionBackend::createReceiver(const String& trackKind, const String& trackId)
302 {
303     auto receiver = createReceiverForSource(createEmptySource(trackKind, String(trackId)), nullptr);
304     m_pendingReceivers.append(receiver.copyRef());
305     return receiver;
306 }
307
308 LibWebRTCPeerConnectionBackend::VideoReceiver LibWebRTCPeerConnectionBackend::videoReceiver(String&& trackId)
309 {
310     // FIXME: Add to Vector a utility routine for that take-or-create pattern.
311     // FIXME: We should be selecting the receiver based on track id.
312     for (size_t cptr = 0; cptr < m_pendingReceivers.size(); ++cptr) {
313         if (m_pendingReceivers[cptr]->track().source().type() == RealtimeMediaSource::Type::Video) {
314             Ref<RTCRtpReceiver> receiver = m_pendingReceivers[cptr].copyRef();
315             m_pendingReceivers.remove(cptr);
316             Ref<RealtimeIncomingVideoSource> source = static_cast<RealtimeIncomingVideoSource&>(receiver->track().source());
317             return { WTFMove(receiver), WTFMove(source) };
318         }
319     }
320     auto source = RealtimeIncomingVideoSource::create(nullptr, WTFMove(trackId));
321     auto receiver = createReceiverForSource(source.copyRef(), nullptr);
322
323     auto senderBackend = makeUnique<LibWebRTCRtpSenderBackend>(*this, nullptr);
324     auto transceiver = RTCRtpTransceiver::create(RTCRtpSender::create(*this, "video"_s, { }, WTFMove(senderBackend)), receiver.copyRef(), nullptr);
325     transceiver->disableSendingDirection();
326     m_peerConnection.addTransceiver(WTFMove(transceiver));
327
328     return { WTFMove(receiver), WTFMove(source) };
329 }
330
331 LibWebRTCPeerConnectionBackend::AudioReceiver LibWebRTCPeerConnectionBackend::audioReceiver(String&& trackId)
332 {
333     // FIXME: Add to Vector a utility routine for that take-or-create pattern.
334     // FIXME: We should be selecting the receiver based on track id.
335     for (size_t cptr = 0; cptr < m_pendingReceivers.size(); ++cptr) {
336         if (m_pendingReceivers[cptr]->track().source().type() == RealtimeMediaSource::Type::Audio) {
337             Ref<RTCRtpReceiver> receiver = m_pendingReceivers[cptr].copyRef();
338             m_pendingReceivers.remove(cptr);
339             Ref<RealtimeIncomingAudioSource> source = static_cast<RealtimeIncomingAudioSource&>(receiver->track().source());
340             return { WTFMove(receiver), WTFMove(source) };
341         }
342     }
343     auto source = RealtimeIncomingAudioSource::create(nullptr, WTFMove(trackId));
344     auto receiver = createReceiverForSource(source.copyRef(), nullptr);
345
346     auto senderBackend = makeUnique<LibWebRTCRtpSenderBackend>(*this, nullptr);
347     auto transceiver = RTCRtpTransceiver::create(RTCRtpSender::create(*this, "audio"_s, { }, WTFMove(senderBackend)), receiver.copyRef(), nullptr);
348     transceiver->disableSendingDirection();
349     m_peerConnection.addTransceiver(WTFMove(transceiver));
350
351     return { WTFMove(receiver), WTFMove(source) };
352 }
353
354 std::unique_ptr<RTCDataChannelHandler> LibWebRTCPeerConnectionBackend::createDataChannelHandler(const String& label, const RTCDataChannelInit& options)
355 {
356     return m_endpoint->createDataChannel(label, options);
357 }
358
359 RefPtr<RTCSessionDescription> LibWebRTCPeerConnectionBackend::currentLocalDescription() const
360 {
361     auto description = m_endpoint->currentLocalDescription();
362     if (description)
363         description->setSdp(filterSDP(String(description->sdp())));
364     return description;
365 }
366
367 RefPtr<RTCSessionDescription> LibWebRTCPeerConnectionBackend::currentRemoteDescription() const
368 {
369     return m_endpoint->currentRemoteDescription();
370 }
371
372 RefPtr<RTCSessionDescription> LibWebRTCPeerConnectionBackend::pendingLocalDescription() const
373 {
374     auto description = m_endpoint->pendingLocalDescription();
375     if (description)
376         description->setSdp(filterSDP(String(description->sdp())));
377     return description;
378 }
379
380 RefPtr<RTCSessionDescription> LibWebRTCPeerConnectionBackend::pendingRemoteDescription() const
381 {
382     return m_endpoint->pendingRemoteDescription();
383 }
384
385 RefPtr<RTCSessionDescription> LibWebRTCPeerConnectionBackend::localDescription() const
386 {
387     auto description = m_endpoint->localDescription();
388     if (description)
389         description->setSdp(filterSDP(String(description->sdp())));
390     return description;
391 }
392
393 RefPtr<RTCSessionDescription> LibWebRTCPeerConnectionBackend::remoteDescription() const
394 {
395     return m_endpoint->remoteDescription();
396 }
397
398 static inline RefPtr<RTCRtpSender> findExistingSender(const Vector<RefPtr<RTCRtpTransceiver>>& transceivers, LibWebRTCRtpSenderBackend& senderBackend)
399 {
400     ASSERT(senderBackend.rtcSender());
401     for (auto& transceiver : transceivers) {
402         auto& sender = transceiver->sender();
403         if (!sender.isStopped() && senderBackend.rtcSender() == backendFromRTPSender(sender).rtcSender())
404             return makeRef(sender);
405     }
406     return nullptr;
407 }
408
409 ExceptionOr<Ref<RTCRtpSender>> LibWebRTCPeerConnectionBackend::addTrack(MediaStreamTrack& track, Vector<String>&& mediaStreamIds)
410 {
411     auto senderBackend = makeUnique<LibWebRTCRtpSenderBackend>(*this, nullptr);
412     if (!m_endpoint->addTrack(*senderBackend, track, mediaStreamIds))
413         return Exception { TypeError, "Unable to add track"_s };
414
415     if (auto sender = findExistingSender(m_peerConnection.currentTransceivers(), *senderBackend)) {
416         backendFromRTPSender(*sender).takeSource(*senderBackend);
417         sender->setTrack(makeRef(track));
418         sender->setMediaStreamIds(WTFMove(mediaStreamIds));
419         return sender.releaseNonNull();
420     }
421
422     auto transceiverBackend = m_endpoint->transceiverBackendFromSender(*senderBackend);
423
424     auto sender = RTCRtpSender::create(*this, makeRef(track), WTFMove(mediaStreamIds), WTFMove(senderBackend));
425     auto receiver = createReceiverForSource(createEmptySource(track.kind(), createCanonicalUUIDString()), transceiverBackend->createReceiverBackend());
426     auto transceiver = RTCRtpTransceiver::create(sender.copyRef(), WTFMove(receiver), WTFMove(transceiverBackend));
427     m_peerConnection.addInternalTransceiver(WTFMove(transceiver));
428     return sender;
429 }
430
431 template<typename T>
432 ExceptionOr<Ref<RTCRtpTransceiver>> LibWebRTCPeerConnectionBackend::addTransceiverFromTrackOrKind(T&& trackOrKind, const RTCRtpTransceiverInit& init)
433 {
434     auto backends = m_endpoint->addTransceiver(trackOrKind, init);
435     if (!backends)
436         return Exception { InvalidAccessError, "Unable to add transceiver"_s };
437
438     auto sender = RTCRtpSender::create(*this, WTFMove(trackOrKind), Vector<String> { }, WTFMove(backends->senderBackend));
439     auto receiver = createReceiverForSource(createEmptySource(sender->trackKind(), createCanonicalUUIDString()), WTFMove(backends->receiverBackend));
440     auto transceiver = RTCRtpTransceiver::create(WTFMove(sender), WTFMove(receiver), WTFMove(backends->transceiverBackend));
441     m_peerConnection.addInternalTransceiver(transceiver.copyRef());
442     return transceiver;
443 }
444
445 ExceptionOr<Ref<RTCRtpTransceiver>> LibWebRTCPeerConnectionBackend::addTransceiver(const String& trackKind, const RTCRtpTransceiverInit& init)
446 {
447     return addTransceiverFromTrackOrKind(String { trackKind }, init);
448 }
449
450 ExceptionOr<Ref<RTCRtpTransceiver>> LibWebRTCPeerConnectionBackend::addTransceiver(Ref<MediaStreamTrack>&& track, const RTCRtpTransceiverInit& init)
451 {
452     return addTransceiverFromTrackOrKind(WTFMove(track), init);
453 }
454
455 void LibWebRTCPeerConnectionBackend::setSenderSourceFromTrack(LibWebRTCRtpSenderBackend& sender, MediaStreamTrack& track)
456 {
457     m_endpoint->setSenderSourceFromTrack(sender, track);
458 }
459
460 static inline LibWebRTCRtpTransceiverBackend& backendFromRTPTransceiver(RTCRtpTransceiver& transceiver)
461 {
462     return static_cast<LibWebRTCRtpTransceiverBackend&>(*transceiver.backend());
463 }
464
465 RTCRtpTransceiver* LibWebRTCPeerConnectionBackend::existingTransceiver(WTF::Function<bool(LibWebRTCRtpTransceiverBackend&)>&& matchingFunction)
466 {
467     for (auto& transceiver : m_peerConnection.currentTransceivers()) {
468         if (matchingFunction(backendFromRTPTransceiver(*transceiver)))
469             return transceiver.get();
470     }
471     return nullptr;
472 }
473
474 RTCRtpTransceiver& LibWebRTCPeerConnectionBackend::newRemoteTransceiver(std::unique_ptr<LibWebRTCRtpTransceiverBackend>&& transceiverBackend, Ref<RealtimeMediaSource>&& receiverSource)
475 {
476     auto sender = RTCRtpSender::create(*this, receiverSource->type() == RealtimeMediaSource::Type::Audio ? "audio"_s : "video"_s, Vector<String> { }, transceiverBackend->createSenderBackend(*this, nullptr));
477     auto receiver = createReceiverForSource(WTFMove(receiverSource), transceiverBackend->createReceiverBackend());
478     auto transceiver = RTCRtpTransceiver::create(WTFMove(sender), WTFMove(receiver), WTFMove(transceiverBackend));
479     m_peerConnection.addInternalTransceiver(transceiver.copyRef());
480     return transceiver.get();
481 }
482
483 Ref<RTCRtpTransceiver> LibWebRTCPeerConnectionBackend::completeAddTransceiver(Ref<RTCRtpSender>&& sender, const RTCRtpTransceiverInit& init, const String& trackId, const String& trackKind)
484 {
485     auto transceiver = RTCRtpTransceiver::create(WTFMove(sender), createReceiver(trackKind, trackId), nullptr);
486
487     transceiver->setDirection(init.direction);
488
489     m_peerConnection.addInternalTransceiver(transceiver.copyRef());
490     return transceiver;
491 }
492
493 void LibWebRTCPeerConnectionBackend::collectTransceivers()
494 {
495     m_endpoint->collectTransceivers();
496 }
497
498 void LibWebRTCPeerConnectionBackend::removeTrack(RTCRtpSender& sender)
499 {
500     m_endpoint->removeTrack(backendFromRTPSender(sender));
501 }
502
503 void LibWebRTCPeerConnectionBackend::applyRotationForOutgoingVideoSources()
504 {
505     for (auto& transceiver : m_peerConnection.currentTransceivers()) {
506         if (!transceiver->sender().isStopped()) {
507             if (auto* videoSource = backendFromRTPSender(transceiver->sender()).videoSource())
508                 videoSource->setApplyRotation(true);
509         }
510     }
511 }
512
513 } // namespace WebCore
514
515 #endif // USE(LIBWEBRTC)