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 | |
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 | return std::make_unique<LibWebRTCPeerConnectionBackend>(peerConnection, page->libWebRTCProvider()); |
62 | } |
63 | |
64 | CreatePeerConnectionBackend PeerConnectionBackend::create = createLibWebRTCPeerConnectionBackend; |
65 | |
66 | Optional<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 | |
74 | Optional<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 | |
82 | LibWebRTCPeerConnectionBackend::LibWebRTCPeerConnectionBackend(RTCPeerConnection& peerConnection, LibWebRTCProvider& provider) |
83 | : PeerConnectionBackend(peerConnection) |
84 | , m_endpoint(LibWebRTCMediaEndpoint::create(*this, provider)) |
85 | { |
86 | } |
87 | |
88 | LibWebRTCPeerConnectionBackend::~LibWebRTCPeerConnectionBackend() = default; |
89 | |
90 | static 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 | |
105 | static 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 | |
118 | static 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 | |
131 | static 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 | |
161 | bool 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 | |
170 | void LibWebRTCPeerConnectionBackend::getStats(Ref<DeferredPromise>&& promise) |
171 | { |
172 | m_endpoint->getStats(WTFMove(promise)); |
173 | } |
174 | |
175 | static inline LibWebRTCRtpSenderBackend& backendFromRTPSender(RTCRtpSender& sender) |
176 | { |
177 | ASSERT(!sender.isStopped()); |
178 | return static_cast<LibWebRTCRtpSenderBackend&>(*sender.backend()); |
179 | } |
180 | |
181 | void 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 | |
192 | void 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 | |
203 | void 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 | |
216 | void 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 | |
228 | void LibWebRTCPeerConnectionBackend::doCreateOffer(RTCOfferOptions&& options) |
229 | { |
230 | m_endpoint->doCreateOffer(options); |
231 | } |
232 | |
233 | void 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 | |
242 | void LibWebRTCPeerConnectionBackend::doStop() |
243 | { |
244 | m_endpoint->stop(); |
245 | m_pendingReceivers.clear(); |
246 | } |
247 | |
248 | void 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 | |
270 | Ref<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 | |
279 | static 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 | |
288 | Ref<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 | |
295 | LibWebRTCPeerConnectionBackend::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 | |
318 | LibWebRTCPeerConnectionBackend::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 | |
341 | std::unique_ptr<RTCDataChannelHandler> LibWebRTCPeerConnectionBackend::createDataChannelHandler(const String& label, const RTCDataChannelInit& options) |
342 | { |
343 | return m_endpoint->createDataChannel(label, options); |
344 | } |
345 | |
346 | RefPtr<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 | |
354 | RefPtr<RTCSessionDescription> LibWebRTCPeerConnectionBackend::currentRemoteDescription() const |
355 | { |
356 | return m_endpoint->currentRemoteDescription(); |
357 | } |
358 | |
359 | RefPtr<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 | |
367 | RefPtr<RTCSessionDescription> LibWebRTCPeerConnectionBackend::pendingRemoteDescription() const |
368 | { |
369 | return m_endpoint->pendingRemoteDescription(); |
370 | } |
371 | |
372 | RefPtr<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 | |
380 | RefPtr<RTCSessionDescription> LibWebRTCPeerConnectionBackend::remoteDescription() const |
381 | { |
382 | return m_endpoint->remoteDescription(); |
383 | } |
384 | |
385 | static 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 | |
396 | ExceptionOr<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 | |
452 | template<typename T> |
453 | ExceptionOr<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 | |
466 | ExceptionOr<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 | |
476 | ExceptionOr<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 | |
490 | void LibWebRTCPeerConnectionBackend::setSenderSourceFromTrack(LibWebRTCRtpSenderBackend& sender, MediaStreamTrack& track) |
491 | { |
492 | m_endpoint->setSenderSourceFromTrack(sender, track); |
493 | } |
494 | |
495 | static inline LibWebRTCRtpTransceiverBackend& backendFromRTPTransceiver(RTCRtpTransceiver& transceiver) |
496 | { |
497 | return static_cast<LibWebRTCRtpTransceiverBackend&>(*transceiver.backend()); |
498 | } |
499 | |
500 | RTCRtpTransceiver* 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 | |
509 | RTCRtpTransceiver& 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 | |
518 | Ref<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 | |
528 | void LibWebRTCPeerConnectionBackend::collectTransceivers() |
529 | { |
530 | m_endpoint->collectTransceivers(); |
531 | } |
532 | |
533 | void LibWebRTCPeerConnectionBackend::removeTrack(RTCRtpSender& sender) |
534 | { |
535 | m_endpoint->removeTrack(backendFromRTPSender(sender)); |
536 | } |
537 | |
538 | void 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 | |
548 | bool 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 | |