2 * Copyright (C) 2017-2018 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
26 #include "LibWebRTCMediaEndpoint.h"
30 #include "EventNames.h"
31 #include "JSRTCStatsReport.h"
32 #include "LibWebRTCDataChannelHandler.h"
33 #include "LibWebRTCPeerConnectionBackend.h"
34 #include "LibWebRTCProvider.h"
35 #include "LibWebRTCRtpReceiverBackend.h"
36 #include "LibWebRTCRtpSenderBackend.h"
37 #include "LibWebRTCRtpTransceiverBackend.h"
38 #include "LibWebRTCStatsCollector.h"
39 #include "LibWebRTCUtils.h"
41 #include "NotImplemented.h"
42 #include "Performance.h"
43 #include "PlatformStrategies.h"
44 #include "RTCDataChannel.h"
45 #include "RTCDataChannelEvent.h"
46 #include "RTCOfferOptions.h"
47 #include "RTCPeerConnection.h"
48 #include "RTCSessionDescription.h"
49 #include "RTCStatsReport.h"
50 #include "RTCTrackEvent.h"
51 #include "RealtimeIncomingAudioSource.h"
52 #include "RealtimeIncomingVideoSource.h"
53 #include "RealtimeOutgoingAudioSource.h"
54 #include "RealtimeOutgoingVideoSource.h"
55 #include "RuntimeEnabledFeatures.h"
56 #include <webrtc/rtc_base/physicalsocketserver.h>
57 #include <webrtc/p2p/base/basicpacketsocketfactory.h>
58 #include <webrtc/p2p/client/basicportallocator.h>
59 #include <webrtc/pc/peerconnectionfactory.h>
60 #include <webrtc/system_wrappers/include/field_trial.h>
61 #include <wtf/MainThread.h>
65 LibWebRTCMediaEndpoint::LibWebRTCMediaEndpoint(LibWebRTCPeerConnectionBackend& peerConnection, LibWebRTCProvider& client)
66 : m_peerConnectionBackend(peerConnection)
67 , m_peerConnectionFactory(*client.factory())
68 , m_createSessionDescriptionObserver(*this)
69 , m_setLocalSessionDescriptionObserver(*this)
70 , m_setRemoteSessionDescriptionObserver(*this)
71 , m_statsLogTimer(*this, &LibWebRTCMediaEndpoint::gatherStatsForLogging)
72 #if !RELEASE_LOG_DISABLED
73 , m_logger(peerConnection.logger())
74 , m_logIdentifier(peerConnection.logIdentifier())
77 ASSERT(isMainThread());
78 ASSERT(client.factory());
80 if (RuntimeEnabledFeatures::sharedFeatures().webRTCH264SimulcastEnabled())
81 webrtc::field_trial::InitFieldTrialsFromString("WebRTC-H264Simulcast/Enabled/");
84 bool LibWebRTCMediaEndpoint::setConfiguration(LibWebRTCProvider& client, webrtc::PeerConnectionInterface::RTCConfiguration&& configuration)
86 if (RuntimeEnabledFeatures::sharedFeatures().webRTCUnifiedPlanEnabled())
87 configuration.sdp_semantics = webrtc::SdpSemantics::kUnifiedPlan;
90 m_backend = client.createPeerConnection(*this, WTFMove(configuration));
93 auto oldConfiguration = m_backend->GetConfiguration();
94 configuration.certificates = oldConfiguration.certificates;
95 return m_backend->SetConfiguration(WTFMove(configuration));
98 static inline const char* sessionDescriptionType(RTCSdpType sdpType)
101 case RTCSdpType::Offer:
103 case RTCSdpType::Pranswer:
105 case RTCSdpType::Answer:
107 case RTCSdpType::Rollback:
111 ASSERT_NOT_REACHED();
115 static inline RTCSdpType fromSessionDescriptionType(const webrtc::SessionDescriptionInterface& description)
117 auto type = description.type();
118 if (type == webrtc::SessionDescriptionInterface::kOffer)
119 return RTCSdpType::Offer;
120 if (type == webrtc::SessionDescriptionInterface::kAnswer)
121 return RTCSdpType::Answer;
122 ASSERT(type == webrtc::SessionDescriptionInterface::kPrAnswer);
123 return RTCSdpType::Pranswer;
126 static inline RefPtr<RTCSessionDescription> fromSessionDescription(const webrtc::SessionDescriptionInterface* description)
132 description->ToString(&sdp);
134 return RTCSessionDescription::create(fromSessionDescriptionType(*description), fromStdString(sdp));
137 // FIXME: We might want to create a new object only if the session actually changed for all description getters.
138 RefPtr<RTCSessionDescription> LibWebRTCMediaEndpoint::currentLocalDescription() const
140 return m_backend ? fromSessionDescription(m_backend->current_local_description()) : nullptr;
143 RefPtr<RTCSessionDescription> LibWebRTCMediaEndpoint::currentRemoteDescription() const
145 return m_backend ? fromSessionDescription(m_backend->current_remote_description()) : nullptr;
148 RefPtr<RTCSessionDescription> LibWebRTCMediaEndpoint::pendingLocalDescription() const
150 return m_backend ? fromSessionDescription(m_backend->pending_local_description()) : nullptr;
153 RefPtr<RTCSessionDescription> LibWebRTCMediaEndpoint::pendingRemoteDescription() const
155 return m_backend ? fromSessionDescription(m_backend->pending_remote_description()) : nullptr;
158 RefPtr<RTCSessionDescription> LibWebRTCMediaEndpoint::localDescription() const
160 return m_backend ? fromSessionDescription(m_backend->local_description()) : nullptr;
163 RefPtr<RTCSessionDescription> LibWebRTCMediaEndpoint::remoteDescription() const
165 return m_backend ? fromSessionDescription(m_backend->remote_description()) : nullptr;
168 void LibWebRTCMediaEndpoint::doSetLocalDescription(RTCSessionDescription& description)
172 webrtc::SdpParseError error;
173 std::unique_ptr<webrtc::SessionDescriptionInterface> sessionDescription(webrtc::CreateSessionDescription(sessionDescriptionType(description.type()), description.sdp().utf8().data(), &error));
175 if (!sessionDescription) {
176 m_peerConnectionBackend.setLocalDescriptionFailed(Exception { OperationError, fromStdString(error.description) });
180 // FIXME: See https://bugs.webkit.org/show_bug.cgi?id=173783. Remove this test once fixed at LibWebRTC level.
181 if (description.type() == RTCSdpType::Answer && !m_backend->pending_remote_description()) {
182 m_peerConnectionBackend.setLocalDescriptionFailed(Exception { InvalidStateError, "Failed to set local answer sdp: no pending remote description."_s });
186 m_backend->SetLocalDescription(&m_setLocalSessionDescriptionObserver, sessionDescription.release());
189 void LibWebRTCMediaEndpoint::doSetRemoteDescription(RTCSessionDescription& description)
193 webrtc::SdpParseError error;
194 std::unique_ptr<webrtc::SessionDescriptionInterface> sessionDescription(webrtc::CreateSessionDescription(sessionDescriptionType(description.type()), description.sdp().utf8().data(), &error));
195 if (!sessionDescription) {
196 m_peerConnectionBackend.setRemoteDescriptionFailed(Exception { SyntaxError, fromStdString(error.description) });
199 m_backend->SetRemoteDescription(&m_setRemoteSessionDescriptionObserver, sessionDescription.release());
204 bool LibWebRTCMediaEndpoint::addTrack(LibWebRTCRtpSenderBackend& sender, MediaStreamTrack& track, const Vector<String>& mediaStreamIds)
208 if (!RuntimeEnabledFeatures::sharedFeatures().webRTCUnifiedPlanEnabled()) {
209 String mediaStreamId = mediaStreamIds.isEmpty() ? createCanonicalUUIDString() : mediaStreamIds[0];
210 m_localStreams.ensure(mediaStreamId, [&] {
211 auto mediaStream = m_peerConnectionFactory.CreateLocalMediaStream(mediaStreamId.utf8().data());
212 m_backend->AddStream(mediaStream);
217 LibWebRTCRtpSenderBackend::Source source;
218 rtc::scoped_refptr<webrtc::MediaStreamTrackInterface> rtcTrack;
219 switch (track.privateTrack().type()) {
220 case RealtimeMediaSource::Type::Audio: {
221 auto audioSource = RealtimeOutgoingAudioSource::create(track.privateTrack());
222 rtcTrack = m_peerConnectionFactory.CreateAudioTrack(track.id().utf8().data(), audioSource.ptr());
223 source = WTFMove(audioSource);
226 case RealtimeMediaSource::Type::Video: {
227 auto videoSource = RealtimeOutgoingVideoSource::create(track.privateTrack());
228 rtcTrack = m_peerConnectionFactory.CreateVideoTrack(track.id().utf8().data(), videoSource.ptr());
229 source = WTFMove(videoSource);
232 case RealtimeMediaSource::Type::None:
233 ASSERT_NOT_REACHED();
237 sender.setSource(WTFMove(source));
238 if (auto rtpSender = sender.rtcSender()) {
239 rtpSender->SetTrack(rtcTrack.get());
243 std::vector<std::string> ids;
244 for (auto& id : mediaStreamIds)
245 ids.push_back(id.utf8().data());
247 auto newRTPSender = m_backend->AddTrack(rtcTrack.get(), WTFMove(ids));
248 if (!newRTPSender.ok())
250 sender.setRTCSender(newRTPSender.MoveValue());
254 void LibWebRTCMediaEndpoint::removeTrack(LibWebRTCRtpSenderBackend& sender)
257 m_backend->RemoveTrack(sender.rtcSender());
260 void LibWebRTCMediaEndpoint::doCreateOffer(const RTCOfferOptions& options)
264 m_isInitiator = true;
265 webrtc::PeerConnectionInterface::RTCOfferAnswerOptions rtcOptions;
266 rtcOptions.ice_restart = options.iceRestart;
267 rtcOptions.voice_activity_detection = options.voiceActivityDetection;
269 if (!RuntimeEnabledFeatures::sharedFeatures().webRTCUnifiedPlanEnabled()) {
270 if (m_peerConnectionBackend.shouldOfferAllowToReceive("audio"_s))
271 rtcOptions.offer_to_receive_audio = webrtc::PeerConnectionInterface::RTCOfferAnswerOptions::kOfferToReceiveMediaTrue;
272 if (m_peerConnectionBackend.shouldOfferAllowToReceive("video"_s))
273 rtcOptions.offer_to_receive_video = webrtc::PeerConnectionInterface::RTCOfferAnswerOptions::kOfferToReceiveMediaTrue;
275 m_backend->CreateOffer(&m_createSessionDescriptionObserver, rtcOptions);
278 void LibWebRTCMediaEndpoint::doCreateAnswer()
282 m_isInitiator = false;
283 m_backend->CreateAnswer(&m_createSessionDescriptionObserver, { });
286 void LibWebRTCMediaEndpoint::getStats(Ref<DeferredPromise>&& promise, WTF::Function<void(rtc::scoped_refptr<LibWebRTCStatsCollector>&&)>&& getStatsFunction)
288 auto collector = LibWebRTCStatsCollector::create([promise = WTFMove(promise), protectedThis = makeRef(*this)](auto&& report) mutable {
289 ASSERT(isMainThread());
290 if (protectedThis->isStopped() || !report)
293 promise->resolve<IDLInterface<RTCStatsReport>>(report.releaseNonNull());
296 LibWebRTCProvider::callOnWebRTCSignalingThread([getStatsFunction = WTFMove(getStatsFunction), collector = WTFMove(collector)]() mutable {
297 getStatsFunction(WTFMove(collector));
301 void LibWebRTCMediaEndpoint::getStats(Ref<DeferredPromise>&& promise)
303 getStats(WTFMove(promise), [this](auto&& collector) {
305 m_backend->GetStats(WTFMove(collector));
309 void LibWebRTCMediaEndpoint::getStats(webrtc::RtpReceiverInterface& receiver, Ref<DeferredPromise>&& promise)
311 getStats(WTFMove(promise), [this, receiver = rtc::scoped_refptr<webrtc::RtpReceiverInterface>(&receiver)](auto&& collector) mutable {
313 m_backend->GetStats(WTFMove(receiver), WTFMove(collector));
317 void LibWebRTCMediaEndpoint::getStats(webrtc::RtpSenderInterface& sender, Ref<DeferredPromise>&& promise)
319 getStats(WTFMove(promise), [this, sender = rtc::scoped_refptr<webrtc::RtpSenderInterface>(&sender)](auto&& collector) mutable {
321 m_backend->GetStats(WTFMove(sender), WTFMove(collector));
325 static RTCSignalingState signalingState(webrtc::PeerConnectionInterface::SignalingState state)
328 case webrtc::PeerConnectionInterface::kStable:
329 return RTCSignalingState::Stable;
330 case webrtc::PeerConnectionInterface::kHaveLocalOffer:
331 return RTCSignalingState::HaveLocalOffer;
332 case webrtc::PeerConnectionInterface::kHaveLocalPrAnswer:
333 return RTCSignalingState::HaveLocalPranswer;
334 case webrtc::PeerConnectionInterface::kHaveRemoteOffer:
335 return RTCSignalingState::HaveRemoteOffer;
336 case webrtc::PeerConnectionInterface::kHaveRemotePrAnswer:
337 return RTCSignalingState::HaveRemotePranswer;
338 case webrtc::PeerConnectionInterface::kClosed:
339 return RTCSignalingState::Stable;
342 ASSERT_NOT_REACHED();
343 return RTCSignalingState::Stable;
346 void LibWebRTCMediaEndpoint::OnSignalingChange(webrtc::PeerConnectionInterface::SignalingState rtcState)
348 auto state = signalingState(rtcState);
349 callOnMainThread([protectedThis = makeRef(*this), state] {
350 if (protectedThis->isStopped())
352 protectedThis->m_peerConnectionBackend.updateSignalingState(state);
356 MediaStream& LibWebRTCMediaEndpoint::mediaStreamFromRTCStream(webrtc::MediaStreamInterface& rtcStream)
358 auto label = fromStdString(rtcStream.id());
359 auto mediaStream = m_remoteStreamsById.ensure(label, [label, this]() mutable {
360 return MediaStream::create(*m_peerConnectionBackend.connection().scriptExecutionContext(), MediaStreamPrivate::create({ }, WTFMove(label)));
362 return *mediaStream.iterator->value;
365 void LibWebRTCMediaEndpoint::addRemoteStream(webrtc::MediaStreamInterface&)
369 void LibWebRTCMediaEndpoint::addRemoteTrack(rtc::scoped_refptr<webrtc::RtpReceiverInterface>&& rtcReceiver, const std::vector<rtc::scoped_refptr<webrtc::MediaStreamInterface>>& rtcStreams)
372 RefPtr<RTCRtpReceiver> receiver;
373 RefPtr<RealtimeMediaSource> remoteSource;
375 auto* rtcTrack = rtcReceiver->track().get();
377 switch (rtcReceiver->media_type()) {
378 case cricket::MEDIA_TYPE_DATA:
380 case cricket::MEDIA_TYPE_AUDIO: {
381 rtc::scoped_refptr<webrtc::AudioTrackInterface> audioTrack = static_cast<webrtc::AudioTrackInterface*>(rtcTrack);
382 auto audioReceiver = m_peerConnectionBackend.audioReceiver(fromStdString(rtcTrack->id()));
384 receiver = WTFMove(audioReceiver.receiver);
385 audioReceiver.source->setSourceTrack(WTFMove(audioTrack));
388 case cricket::MEDIA_TYPE_VIDEO: {
389 rtc::scoped_refptr<webrtc::VideoTrackInterface> videoTrack = static_cast<webrtc::VideoTrackInterface*>(rtcTrack);
390 auto videoReceiver = m_peerConnectionBackend.videoReceiver(fromStdString(rtcTrack->id()));
392 receiver = WTFMove(videoReceiver.receiver);
393 videoReceiver.source->setSourceTrack(WTFMove(videoTrack));
398 receiver->setBackend(std::make_unique<LibWebRTCRtpReceiverBackend>(WTFMove(rtcReceiver)));
399 auto& track = receiver->track();
400 fireTrackEvent(receiver.releaseNonNull(), track, rtcStreams, nullptr);
403 void LibWebRTCMediaEndpoint::fireTrackEvent(Ref<RTCRtpReceiver>&& receiver, Ref<MediaStreamTrack>&& track, const std::vector<rtc::scoped_refptr<webrtc::MediaStreamInterface>>& rtcStreams, RefPtr<RTCRtpTransceiver>&& transceiver)
405 Vector<RefPtr<MediaStream>> streams;
406 for (auto& rtcStream : rtcStreams) {
407 auto& mediaStream = mediaStreamFromRTCStream(*rtcStream.get());
408 streams.append(&mediaStream);
409 mediaStream.addTrackFromPlatform(track.get());
411 auto streamIds = WTF::map(streams, [](auto& stream) -> String {
414 m_remoteStreamsFromRemoteTrack.add(track.ptr(), WTFMove(streamIds));
416 m_peerConnectionBackend.connection().fireEvent(RTCTrackEvent::create(eventNames().trackEvent,
417 Event::CanBubble::No, Event::IsCancelable::No, WTFMove(receiver), WTFMove(track), WTFMove(streams), WTFMove(transceiver)));
420 static inline void setExistingReceiverSourceTrack(RealtimeMediaSource& existingSource, webrtc::RtpReceiverInterface& rtcReceiver)
422 switch (rtcReceiver.media_type()) {
423 case cricket::MEDIA_TYPE_AUDIO: {
424 ASSERT(existingSource.type() == RealtimeMediaSource::Type::Audio);
425 rtc::scoped_refptr<webrtc::AudioTrackInterface> audioTrack = static_cast<webrtc::AudioTrackInterface*>(rtcReceiver.track().get());
426 downcast<RealtimeIncomingAudioSource>(existingSource).setSourceTrack(WTFMove(audioTrack));
429 case cricket::MEDIA_TYPE_VIDEO: {
430 ASSERT(existingSource.type() == RealtimeMediaSource::Type::Video);
431 rtc::scoped_refptr<webrtc::VideoTrackInterface> videoTrack = static_cast<webrtc::VideoTrackInterface*>(rtcReceiver.track().get());
432 downcast<RealtimeIncomingVideoSource>(existingSource).setSourceTrack(WTFMove(videoTrack));
435 case cricket::MEDIA_TYPE_DATA:
436 ASSERT_NOT_REACHED();
441 static inline RefPtr<RealtimeMediaSource> sourceFromNewReceiver(webrtc::RtpReceiverInterface& rtcReceiver)
443 auto rtcTrack = rtcReceiver.track();
444 switch (rtcReceiver.media_type()) {
445 case cricket::MEDIA_TYPE_DATA:
447 case cricket::MEDIA_TYPE_AUDIO: {
448 rtc::scoped_refptr<webrtc::AudioTrackInterface> audioTrack = static_cast<webrtc::AudioTrackInterface*>(rtcTrack.get());
449 return RealtimeIncomingAudioSource::create(WTFMove(audioTrack), fromStdString(rtcTrack->id()));
451 case cricket::MEDIA_TYPE_VIDEO: {
452 rtc::scoped_refptr<webrtc::VideoTrackInterface> videoTrack = static_cast<webrtc::VideoTrackInterface*>(rtcTrack.get());
453 return RealtimeIncomingVideoSource::create(WTFMove(videoTrack), fromStdString(rtcTrack->id()));
457 RELEASE_ASSERT_NOT_REACHED();
460 void LibWebRTCMediaEndpoint::collectTransceivers()
465 if (!RuntimeEnabledFeatures::sharedFeatures().webRTCUnifiedPlanEnabled())
468 for (auto& rtcTransceiver : m_backend->GetTransceivers()) {
469 auto* existingTransceiver = m_peerConnectionBackend.existingTransceiver([&](auto& transceiverBackend) {
470 return rtcTransceiver.get() == transceiverBackend.rtcTransceiver();
472 if (existingTransceiver)
475 auto rtcReceiver = rtcTransceiver->receiver();
476 auto source = sourceFromNewReceiver(*rtcReceiver);
480 m_peerConnectionBackend.newRemoteTransceiver(std::make_unique<LibWebRTCRtpTransceiverBackend>(WTFMove(rtcTransceiver)), source.releaseNonNull());
484 void LibWebRTCMediaEndpoint::newTransceiver(rtc::scoped_refptr<webrtc::RtpTransceiverInterface>&& rtcTransceiver)
486 auto* transceiver = m_peerConnectionBackend.existingTransceiver([&](auto& transceiverBackend) {
487 return rtcTransceiver.get() == transceiverBackend.rtcTransceiver();
490 auto rtcReceiver = rtcTransceiver->receiver();
491 setExistingReceiverSourceTrack(transceiver->receiver().track().source(), *rtcReceiver);
492 fireTrackEvent(makeRef(transceiver->receiver()), transceiver->receiver().track(), rtcReceiver->streams(), makeRef(*transceiver));
496 auto rtcReceiver = rtcTransceiver->receiver();
497 auto source = sourceFromNewReceiver(*rtcReceiver);
501 auto& newTransceiver = m_peerConnectionBackend.newRemoteTransceiver(std::make_unique<LibWebRTCRtpTransceiverBackend>(WTFMove(rtcTransceiver)), source.releaseNonNull());
503 fireTrackEvent(makeRef(newTransceiver.receiver()), newTransceiver.receiver().track(), rtcReceiver->streams(), makeRef(newTransceiver));
506 void LibWebRTCMediaEndpoint::removeRemoteTrack(rtc::scoped_refptr<webrtc::RtpReceiverInterface>&& receiver)
508 // FIXME: Support plan B code path.
509 if (!RuntimeEnabledFeatures::sharedFeatures().webRTCUnifiedPlanEnabled())
512 auto* transceiver = m_peerConnectionBackend.existingTransceiver([&receiver](auto& transceiverBackend) {
513 auto* rtcTransceiver = transceiverBackend.rtcTransceiver();
514 return rtcTransceiver && receiver.get() == rtcTransceiver->receiver().get();
519 auto& track = transceiver->receiver().track();
521 for (auto& id : m_remoteStreamsFromRemoteTrack.get(&track)) {
522 if (auto stream = m_remoteStreamsById.get(id))
523 stream->privateStream().removeTrack(track.privateTrack(), MediaStreamPrivate::NotifyClientOption::Notify);
526 track.source().setMuted(true);
530 std::optional<LibWebRTCMediaEndpoint::Backends> LibWebRTCMediaEndpoint::createTransceiverBackends(T&& trackOrKind, const RTCRtpTransceiverInit& init, LibWebRTCRtpSenderBackend::Source&& source)
532 auto result = m_backend->AddTransceiver(WTFMove(trackOrKind), fromRtpTransceiverInit(init));
536 auto transceiver = std::make_unique<LibWebRTCRtpTransceiverBackend>(result.MoveValue());
537 return LibWebRTCMediaEndpoint::Backends { transceiver->createSenderBackend(m_peerConnectionBackend, WTFMove(source)), transceiver->createReceiverBackend(), WTFMove(transceiver) };
540 std::optional<LibWebRTCMediaEndpoint::Backends> LibWebRTCMediaEndpoint::addTransceiver(const String& trackKind, const RTCRtpTransceiverInit& init)
542 auto type = trackKind == "audio" ? cricket::MediaType::MEDIA_TYPE_AUDIO : cricket::MediaType::MEDIA_TYPE_VIDEO;
543 return createTransceiverBackends(type, init, nullptr);
546 std::pair<LibWebRTCRtpSenderBackend::Source, rtc::scoped_refptr<webrtc::MediaStreamTrackInterface>> LibWebRTCMediaEndpoint::createSourceAndRTCTrack(MediaStreamTrack& track)
548 LibWebRTCRtpSenderBackend::Source source;
549 rtc::scoped_refptr<webrtc::MediaStreamTrackInterface> rtcTrack;
550 switch (track.privateTrack().type()) {
551 case RealtimeMediaSource::Type::None:
552 ASSERT_NOT_REACHED();
554 case RealtimeMediaSource::Type::Audio: {
555 auto audioSource = RealtimeOutgoingAudioSource::create(track.privateTrack());
556 rtcTrack = m_peerConnectionFactory.CreateAudioTrack(track.id().utf8().data(), audioSource.ptr());
557 source = WTFMove(audioSource);
560 case RealtimeMediaSource::Type::Video: {
561 auto videoSource = RealtimeOutgoingVideoSource::create(track.privateTrack());
562 rtcTrack = m_peerConnectionFactory.CreateVideoTrack(track.id().utf8().data(), videoSource.ptr());
563 source = WTFMove(videoSource);
567 return std::make_pair(WTFMove(source), WTFMove(rtcTrack));
570 std::optional<LibWebRTCMediaEndpoint::Backends> LibWebRTCMediaEndpoint::addTransceiver(MediaStreamTrack& track, const RTCRtpTransceiverInit& init)
572 auto sourceAndTrack = createSourceAndRTCTrack(track);
573 return createTransceiverBackends(WTFMove(sourceAndTrack.second), init, WTFMove(sourceAndTrack.first));
576 void LibWebRTCMediaEndpoint::setSenderSourceFromTrack(LibWebRTCRtpSenderBackend& sender, MediaStreamTrack& track)
578 auto sourceAndTrack = createSourceAndRTCTrack(track);
579 sender.setSource(WTFMove(sourceAndTrack.first));
580 sender.rtcSender()->SetTrack(WTFMove(sourceAndTrack.second));
583 std::unique_ptr<LibWebRTCRtpTransceiverBackend> LibWebRTCMediaEndpoint::transceiverBackendFromSender(LibWebRTCRtpSenderBackend& backend)
585 for (auto& transceiver : m_backend->GetTransceivers()) {
586 if (transceiver->sender().get() == backend.rtcSender())
587 return std::make_unique<LibWebRTCRtpTransceiverBackend>(rtc::scoped_refptr<webrtc::RtpTransceiverInterface>(transceiver));
593 void LibWebRTCMediaEndpoint::removeRemoteStream(webrtc::MediaStreamInterface& rtcStream)
595 bool removed = m_remoteStreamsById.remove(fromStdString(rtcStream.id()));
596 ASSERT_UNUSED(removed, removed);
599 void LibWebRTCMediaEndpoint::OnAddStream(rtc::scoped_refptr<webrtc::MediaStreamInterface> stream)
601 callOnMainThread([protectedThis = makeRef(*this), stream = WTFMove(stream)] {
602 if (protectedThis->isStopped())
605 protectedThis->addRemoteStream(*stream.get());
609 void LibWebRTCMediaEndpoint::OnRemoveStream(rtc::scoped_refptr<webrtc::MediaStreamInterface> stream)
611 callOnMainThread([protectedThis = makeRef(*this), stream = WTFMove(stream)] {
612 if (protectedThis->isStopped())
615 protectedThis->removeRemoteStream(*stream.get());
619 void LibWebRTCMediaEndpoint::OnAddTrack(rtc::scoped_refptr<webrtc::RtpReceiverInterface> receiver, const std::vector<rtc::scoped_refptr<webrtc::MediaStreamInterface>>& streams)
621 if (RuntimeEnabledFeatures::sharedFeatures().webRTCUnifiedPlanEnabled())
624 callOnMainThread([protectedThis = makeRef(*this), receiver = WTFMove(receiver), streams]() mutable {
625 if (protectedThis->isStopped())
627 protectedThis->addRemoteTrack(WTFMove(receiver), streams);
631 void LibWebRTCMediaEndpoint::OnTrack(rtc::scoped_refptr<webrtc::RtpTransceiverInterface> transceiver)
633 if (!RuntimeEnabledFeatures::sharedFeatures().webRTCUnifiedPlanEnabled())
636 callOnMainThread([protectedThis = makeRef(*this), transceiver = WTFMove(transceiver)]() mutable {
637 if (protectedThis->isStopped())
639 protectedThis->newTransceiver(WTFMove(transceiver));
643 void LibWebRTCMediaEndpoint::OnRemoveTrack(rtc::scoped_refptr<webrtc::RtpReceiverInterface> receiver)
645 callOnMainThread([protectedThis = makeRef(*this), receiver = WTFMove(receiver)]() mutable {
646 if (protectedThis->isStopped())
648 protectedThis->removeRemoteTrack(WTFMove(receiver));
652 std::unique_ptr<RTCDataChannelHandler> LibWebRTCMediaEndpoint::createDataChannel(const String& label, const RTCDataChannelInit& options)
654 auto init = LibWebRTCDataChannelHandler::fromRTCDataChannelInit(options);
655 auto channel = m_backend->CreateDataChannel(label.utf8().data(), &init);
656 return channel ? std::make_unique<LibWebRTCDataChannelHandler>(WTFMove(channel)) : nullptr;
659 void LibWebRTCMediaEndpoint::OnDataChannel(rtc::scoped_refptr<webrtc::DataChannelInterface> dataChannel)
661 callOnMainThread([protectedThis = makeRef(*this), dataChannel = WTFMove(dataChannel)]() mutable {
662 if (protectedThis->isStopped())
664 auto& connection = protectedThis->m_peerConnectionBackend.connection();
665 connection.fireEvent(LibWebRTCDataChannelHandler::channelEvent(*connection.scriptExecutionContext(), WTFMove(dataChannel)));
669 void LibWebRTCMediaEndpoint::stop()
678 m_remoteStreamsById.clear();
679 m_remoteStreamsFromRemoteTrack.clear();
682 void LibWebRTCMediaEndpoint::OnRenegotiationNeeded()
684 callOnMainThread([protectedThis = makeRef(*this)] {
685 if (protectedThis->isStopped())
687 protectedThis->m_peerConnectionBackend.markAsNeedingNegotiation();
691 static inline RTCIceConnectionState toRTCIceConnectionState(webrtc::PeerConnectionInterface::IceConnectionState state)
694 case webrtc::PeerConnectionInterface::kIceConnectionNew:
695 return RTCIceConnectionState::New;
696 case webrtc::PeerConnectionInterface::kIceConnectionChecking:
697 return RTCIceConnectionState::Checking;
698 case webrtc::PeerConnectionInterface::kIceConnectionConnected:
699 return RTCIceConnectionState::Connected;
700 case webrtc::PeerConnectionInterface::kIceConnectionCompleted:
701 return RTCIceConnectionState::Completed;
702 case webrtc::PeerConnectionInterface::kIceConnectionFailed:
703 return RTCIceConnectionState::Failed;
704 case webrtc::PeerConnectionInterface::kIceConnectionDisconnected:
705 return RTCIceConnectionState::Disconnected;
706 case webrtc::PeerConnectionInterface::kIceConnectionClosed:
707 return RTCIceConnectionState::Closed;
708 case webrtc::PeerConnectionInterface::kIceConnectionMax:
712 ASSERT_NOT_REACHED();
713 return RTCIceConnectionState::New;
716 void LibWebRTCMediaEndpoint::OnIceConnectionChange(webrtc::PeerConnectionInterface::IceConnectionState state)
718 auto connectionState = toRTCIceConnectionState(state);
719 callOnMainThread([protectedThis = makeRef(*this), connectionState] {
720 if (protectedThis->isStopped())
722 if (protectedThis->m_peerConnectionBackend.connection().iceConnectionState() != connectionState)
723 protectedThis->m_peerConnectionBackend.connection().updateIceConnectionState(connectionState);
727 void LibWebRTCMediaEndpoint::OnIceGatheringChange(webrtc::PeerConnectionInterface::IceGatheringState state)
729 callOnMainThread([protectedThis = makeRef(*this), state] {
730 if (protectedThis->isStopped())
732 if (state == webrtc::PeerConnectionInterface::kIceGatheringComplete)
733 protectedThis->m_peerConnectionBackend.doneGatheringCandidates();
734 else if (state == webrtc::PeerConnectionInterface::kIceGatheringGathering)
735 protectedThis->m_peerConnectionBackend.connection().updateIceGatheringState(RTCIceGatheringState::Gathering);
739 void LibWebRTCMediaEndpoint::OnIceCandidate(const webrtc::IceCandidateInterface *rtcCandidate)
741 ASSERT(rtcCandidate);
744 rtcCandidate->ToString(&sdp);
746 auto sdpMLineIndex = safeCast<unsigned short>(rtcCandidate->sdp_mline_index());
748 callOnMainThread([protectedThis = makeRef(*this), mid = fromStdString(rtcCandidate->sdp_mid()), sdp = fromStdString(sdp), sdpMLineIndex, url = fromStdString(rtcCandidate->server_url())]() mutable {
749 if (protectedThis->isStopped())
751 protectedThis->m_peerConnectionBackend.newICECandidate(WTFMove(sdp), WTFMove(mid), sdpMLineIndex, WTFMove(url));
755 void LibWebRTCMediaEndpoint::OnIceCandidatesRemoved(const std::vector<cricket::Candidate>&)
757 ASSERT_NOT_REACHED();
760 void LibWebRTCMediaEndpoint::createSessionDescriptionSucceeded(std::unique_ptr<webrtc::SessionDescriptionInterface>&& description)
763 description->ToString(&sdp);
765 callOnMainThread([protectedThis = makeRef(*this), sdp = fromStdString(sdp)]() mutable {
766 if (protectedThis->isStopped())
768 if (protectedThis->m_isInitiator)
769 protectedThis->m_peerConnectionBackend.createOfferSucceeded(WTFMove(sdp));
771 protectedThis->m_peerConnectionBackend.createAnswerSucceeded(WTFMove(sdp));
775 void LibWebRTCMediaEndpoint::createSessionDescriptionFailed(ExceptionCode errorCode, const char* errorMessage)
777 callOnMainThread([protectedThis = makeRef(*this), errorCode, errorMessage = String(errorMessage)] () mutable {
778 if (protectedThis->isStopped())
780 if (protectedThis->m_isInitiator)
781 protectedThis->m_peerConnectionBackend.createOfferFailed(Exception { errorCode, WTFMove(errorMessage) });
783 protectedThis->m_peerConnectionBackend.createAnswerFailed(Exception { errorCode, WTFMove(errorMessage) });
787 void LibWebRTCMediaEndpoint::setLocalSessionDescriptionSucceeded()
789 callOnMainThread([protectedThis = makeRef(*this)] {
790 if (protectedThis->isStopped())
792 protectedThis->m_peerConnectionBackend.setLocalDescriptionSucceeded();
796 void LibWebRTCMediaEndpoint::setLocalSessionDescriptionFailed(ExceptionCode errorCode, const char* errorMessage)
798 callOnMainThread([protectedThis = makeRef(*this), errorCode, errorMessage = String(errorMessage)] () mutable {
799 if (protectedThis->isStopped())
801 protectedThis->m_peerConnectionBackend.setLocalDescriptionFailed(Exception { errorCode, WTFMove(errorMessage) });
805 void LibWebRTCMediaEndpoint::setRemoteSessionDescriptionSucceeded()
807 callOnMainThread([protectedThis = makeRef(*this)] {
808 if (protectedThis->isStopped())
810 protectedThis->m_peerConnectionBackend.setRemoteDescriptionSucceeded();
814 void LibWebRTCMediaEndpoint::setRemoteSessionDescriptionFailed(ExceptionCode errorCode, const char* errorMessage)
816 callOnMainThread([protectedThis = makeRef(*this), errorCode, errorMessage = String(errorMessage)] () mutable {
817 if (protectedThis->isStopped())
819 protectedThis->m_peerConnectionBackend.setRemoteDescriptionFailed(Exception { errorCode, WTFMove(errorMessage) });
823 void LibWebRTCMediaEndpoint::gatherStatsForLogging()
825 LibWebRTCProvider::callOnWebRTCSignalingThread([protectedThis = makeRef(*this)] {
826 if (protectedThis->m_backend)
827 protectedThis->m_backend->GetStats(protectedThis.ptr());
831 class RTCStatsLogger {
833 explicit RTCStatsLogger(const webrtc::RTCStats& stats)
838 String toJSONString() const { return String(m_stats.ToJson().c_str()); }
841 const webrtc::RTCStats& m_stats;
844 void LibWebRTCMediaEndpoint::OnStatsDelivered(const rtc::scoped_refptr<const webrtc::RTCStatsReport>& report)
846 #if !RELEASE_LOG_DISABLED
847 int64_t timestamp = report->timestamp_us();
848 if (!m_statsFirstDeliveredTimestamp)
849 m_statsFirstDeliveredTimestamp = timestamp;
851 callOnMainThread([protectedThis = makeRef(*this), this, timestamp, report] {
852 if (m_statsLogTimer.repeatInterval() != statsLogInterval(timestamp)) {
853 m_statsLogTimer.stop();
854 m_statsLogTimer.startRepeating(statsLogInterval(timestamp));
857 for (auto iterator = report->begin(); iterator != report->end(); ++iterator)
858 ALWAYS_LOG(Logger::LogSiteIdentifier("LibWebRTCMediaEndpoint", "OnStatsDelivered", logIdentifier()), RTCStatsLogger { *iterator });
861 UNUSED_PARAM(report);
865 void LibWebRTCMediaEndpoint::startLoggingStats()
867 #if !RELEASE_LOG_DISABLED
868 if (m_statsLogTimer.isActive())
869 m_statsLogTimer.stop();
870 m_statsLogTimer.startRepeating(statsLogInterval(0));
874 void LibWebRTCMediaEndpoint::stopLoggingStats()
876 m_statsLogTimer.stop();
879 #if !RELEASE_LOG_DISABLED
880 WTFLogChannel& LibWebRTCMediaEndpoint::logChannel() const
885 Seconds LibWebRTCMediaEndpoint::statsLogInterval(int64_t reportTimestamp) const
887 if (logger().willLog(logChannel(), WTFLogLevelInfo))
890 if (reportTimestamp - m_statsFirstDeliveredTimestamp > 15000000)
897 } // namespace WebCore
901 template<typename Type>
905 struct LogArgument<WebCore::RTCStatsLogger> {
906 static String toString(const WebCore::RTCStatsLogger& logger)
908 return String(logger.toJSONString());
915 #endif // USE(LIBWEBRTC)