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