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