summaryrefslogtreecommitdiff
path: root/Source/WebCore/Modules/mediastream/libwebrtc/LibWebRTCMediaEndpoint.cpp
diff options
context:
space:
mode:
authorLorry Tar Creator <lorry-tar-importer@lorry>2017-06-27 06:07:23 +0000
committerLorry Tar Creator <lorry-tar-importer@lorry>2017-06-27 06:07:23 +0000
commit1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c (patch)
tree46dcd36c86e7fbc6e5df36deb463b33e9967a6f7 /Source/WebCore/Modules/mediastream/libwebrtc/LibWebRTCMediaEndpoint.cpp
parent32761a6cee1d0dee366b885b7b9c777e67885688 (diff)
downloadWebKitGtk-tarball-master.tar.gz
Diffstat (limited to 'Source/WebCore/Modules/mediastream/libwebrtc/LibWebRTCMediaEndpoint.cpp')
-rw-r--r--Source/WebCore/Modules/mediastream/libwebrtc/LibWebRTCMediaEndpoint.cpp527
1 files changed, 527 insertions, 0 deletions
diff --git a/Source/WebCore/Modules/mediastream/libwebrtc/LibWebRTCMediaEndpoint.cpp b/Source/WebCore/Modules/mediastream/libwebrtc/LibWebRTCMediaEndpoint.cpp
new file mode 100644
index 000000000..e46c31c4e
--- /dev/null
+++ b/Source/WebCore/Modules/mediastream/libwebrtc/LibWebRTCMediaEndpoint.cpp
@@ -0,0 +1,527 @@
+/*
+ * Copyright (C) 2017 Apple Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "LibWebRTCMediaEndpoint.h"
+
+#if USE(LIBWEBRTC)
+
+#include "EventNames.h"
+#include "LibWebRTCDataChannelHandler.h"
+#include "LibWebRTCPeerConnectionBackend.h"
+#include "LibWebRTCProvider.h"
+#include "MediaStreamEvent.h"
+#include "NotImplemented.h"
+#include "PlatformStrategies.h"
+#include "RTCDataChannel.h"
+#include "RTCDataChannelEvent.h"
+#include "RTCIceCandidate.h"
+#include "RTCPeerConnection.h"
+#include "RTCSessionDescription.h"
+#include "RTCTrackEvent.h"
+#include "RealtimeIncomingAudioSource.h"
+#include "RealtimeIncomingVideoSource.h"
+#include <webrtc/api/peerconnectionfactory.h>
+#include <webrtc/base/physicalsocketserver.h>
+#include <webrtc/p2p/base/basicpacketsocketfactory.h>
+#include <webrtc/p2p/client/basicportallocator.h>
+#include <wtf/MainThread.h>
+
+#include "CoreMediaSoftLink.h"
+
+namespace WebCore {
+
+LibWebRTCMediaEndpoint::LibWebRTCMediaEndpoint(LibWebRTCPeerConnectionBackend& peerConnection, LibWebRTCProvider& client)
+ : m_peerConnectionBackend(peerConnection)
+ , m_backend(client.createPeerConnection(*this))
+ , m_createSessionDescriptionObserver(*this)
+ , m_setLocalSessionDescriptionObserver(*this)
+ , m_setRemoteSessionDescriptionObserver(*this)
+{
+ ASSERT(m_backend);
+}
+
+static inline const char* sessionDescriptionType(RTCSessionDescription::SdpType sdpType)
+{
+ switch (sdpType) {
+ case RTCSessionDescription::SdpType::Offer:
+ return "offer";
+ case RTCSessionDescription::SdpType::Pranswer:
+ return "pranswer";
+ case RTCSessionDescription::SdpType::Answer:
+ return "answer";
+ case RTCSessionDescription::SdpType::Rollback:
+ return "rollback";
+ }
+}
+
+static inline RTCSessionDescription::SdpType fromSessionDescriptionType(const webrtc::SessionDescriptionInterface& description)
+{
+ auto type = description.type();
+ if (type == webrtc::SessionDescriptionInterface::kOffer)
+ return RTCSessionDescription::SdpType::Offer;
+ if (type == webrtc::SessionDescriptionInterface::kAnswer)
+ return RTCSessionDescription::SdpType::Answer;
+ ASSERT(type == webrtc::SessionDescriptionInterface::kPrAnswer);
+ return RTCSessionDescription::SdpType::Pranswer;
+}
+
+static inline RefPtr<RTCSessionDescription> fromSessionDescription(const webrtc::SessionDescriptionInterface* description)
+{
+ if (!description)
+ return nullptr;
+
+ std::string sdp;
+ description->ToString(&sdp);
+ String sdpString(sdp.data(), sdp.size());
+
+ return RTCSessionDescription::create(fromSessionDescriptionType(*description), WTFMove(sdpString));
+}
+
+RefPtr<RTCSessionDescription> LibWebRTCMediaEndpoint::localDescription() const
+{
+ // FIXME: We might want to create a new object only if the session actually changed.
+ return fromSessionDescription(m_backend->local_description());
+}
+
+RefPtr<RTCSessionDescription> LibWebRTCMediaEndpoint::remoteDescription() const
+{
+ // FIXME: We might want to create a new object only if the session actually changed.
+ return fromSessionDescription(m_backend->remote_description());
+}
+
+void LibWebRTCMediaEndpoint::doSetLocalDescription(RTCSessionDescription& description)
+{
+ webrtc::SdpParseError error;
+ std::unique_ptr<webrtc::SessionDescriptionInterface> sessionDescription(webrtc::CreateSessionDescription(sessionDescriptionType(description.type()), description.sdp().utf8().data(), &error));
+
+ if (!sessionDescription) {
+ String errorMessage(error.description.data(), error.description.size());
+ m_peerConnectionBackend.setLocalDescriptionFailed(Exception { OperationError, WTFMove(errorMessage) });
+ return;
+ }
+ m_backend->SetLocalDescription(&m_setLocalSessionDescriptionObserver, sessionDescription.release());
+}
+
+void LibWebRTCMediaEndpoint::doSetRemoteDescription(RTCSessionDescription& description)
+{
+ webrtc::SdpParseError error;
+ std::unique_ptr<webrtc::SessionDescriptionInterface> sessionDescription(webrtc::CreateSessionDescription(sessionDescriptionType(description.type()), description.sdp().utf8().data(), &error));
+ if (!sessionDescription) {
+ String errorMessage(error.description.data(), error.description.size());
+ m_peerConnectionBackend.setRemoteDescriptionFailed(Exception { OperationError, WTFMove(errorMessage) });
+ return;
+ }
+ m_backend->SetRemoteDescription(&m_setRemoteSessionDescriptionObserver, sessionDescription.release());
+}
+
+static inline std::string streamId(RTCPeerConnection& connection)
+{
+ auto& senders = connection.getSenders();
+ if (senders.size()) {
+ for (RTCRtpSender& sender : senders) {
+ auto* track = sender.track();
+ if (track) {
+ ASSERT(sender.mediaStreamIds().size() == 1);
+ return std::string(sender.mediaStreamIds().first().utf8().data());
+ }
+ }
+ }
+ return "av_label";
+}
+
+void LibWebRTCMediaEndpoint::doCreateOffer()
+{
+ m_isInitiator = true;
+ auto& senders = m_peerConnectionBackend.connection().getSenders();
+ if (senders.size()) {
+ // FIXME: We only support one stream for the moment.
+ auto stream = LibWebRTCProvider::factory().CreateLocalMediaStream(streamId(m_peerConnectionBackend.connection()));
+ for (RTCRtpSender& sender : senders) {
+ auto* track = sender.track();
+ if (track) {
+ ASSERT(sender.mediaStreamIds().size() == 1);
+ auto& source = track->source();
+ if (source.type() == RealtimeMediaSource::Audio) {
+ auto trackSource = RealtimeOutgoingAudioSource::create(source);
+ auto rtcTrack = LibWebRTCProvider::factory().CreateAudioTrack(track->id().utf8().data(), trackSource.ptr());
+ trackSource->setTrack(rtc::scoped_refptr<webrtc::AudioTrackInterface>(rtcTrack));
+ m_peerConnectionBackend.addAudioSource(WTFMove(trackSource));
+ stream->AddTrack(WTFMove(rtcTrack));
+ } else {
+ auto videoSource = RealtimeOutgoingVideoSource::create(source);
+ auto videoTrack = LibWebRTCProvider::factory().CreateVideoTrack(track->id().utf8().data(), videoSource.ptr());
+ m_peerConnectionBackend.addVideoSource(WTFMove(videoSource));
+ stream->AddTrack(WTFMove(videoTrack));
+ }
+ }
+ }
+ m_backend->AddStream(stream);
+ }
+ m_backend->CreateOffer(&m_createSessionDescriptionObserver, nullptr);
+}
+
+void LibWebRTCMediaEndpoint::doCreateAnswer()
+{
+ m_isInitiator = false;
+
+ auto& senders = m_peerConnectionBackend.connection().getSenders();
+ if (senders.size()) {
+ // FIXME: We only support one stream for the moment.
+ auto stream = LibWebRTCProvider::factory().CreateLocalMediaStream(streamId(m_peerConnectionBackend.connection()));
+ for (RTCRtpSender& sender : senders) {
+ auto* track = sender.track();
+ if (track) {
+ ASSERT(sender.mediaStreamIds().size() == 1);
+ auto& source = track->source();
+ if (source.type() == RealtimeMediaSource::Audio) {
+ auto trackSource = RealtimeOutgoingAudioSource::create(source);
+ auto rtcTrack = LibWebRTCProvider::factory().CreateAudioTrack(track->id().utf8().data(), trackSource.ptr());
+ trackSource->setTrack(rtc::scoped_refptr<webrtc::AudioTrackInterface>(rtcTrack));
+ m_peerConnectionBackend.addAudioSource(WTFMove(trackSource));
+ stream->AddTrack(WTFMove(rtcTrack));
+ } else {
+ auto videoSource = RealtimeOutgoingVideoSource::create(source);
+ auto videoTrack = LibWebRTCProvider::factory().CreateVideoTrack(track->id().utf8().data(), videoSource.ptr());
+ m_peerConnectionBackend.addVideoSource(WTFMove(videoSource));
+ stream->AddTrack(WTFMove(videoTrack));
+ }
+ }
+ }
+ m_backend->AddStream(stream);
+ }
+ m_backend->CreateAnswer(&m_createSessionDescriptionObserver, nullptr);
+}
+
+void LibWebRTCMediaEndpoint::getStats(MediaStreamTrack* track, const DeferredPromise& promise)
+{
+ m_backend->GetStats(StatsCollector::create(*this, promise, track).get());
+}
+
+LibWebRTCMediaEndpoint::StatsCollector::StatsCollector(LibWebRTCMediaEndpoint& endpoint, const DeferredPromise& promise, MediaStreamTrack* track)
+ : m_endpoint(endpoint)
+ , m_promise(promise)
+{
+ if (track)
+ m_id = track->id();
+}
+
+void LibWebRTCMediaEndpoint::StatsCollector::OnStatsDelivered(const rtc::scoped_refptr<const webrtc::RTCStatsReport>& report)
+{
+ callOnMainThread([protectedThis = rtc::scoped_refptr<LibWebRTCMediaEndpoint::StatsCollector>(this), report] {
+ if (protectedThis->m_endpoint.isStopped())
+ return;
+
+ // FIXME: Fulfill promise with the report
+ UNUSED_PARAM(report);
+
+ protectedThis->m_endpoint.m_peerConnectionBackend.getStatsFailed(protectedThis->m_promise, Exception { TypeError, ASCIILiteral("Stats API is not yet implemented") });
+ });
+}
+
+static PeerConnectionStates::SignalingState signalingState(webrtc::PeerConnectionInterface::SignalingState state)
+{
+ switch (state) {
+ case webrtc::PeerConnectionInterface::kStable:
+ return PeerConnectionStates::SignalingState::Stable;
+ case webrtc::PeerConnectionInterface::kHaveLocalOffer:
+ return PeerConnectionStates::SignalingState::HaveLocalOffer;
+ case webrtc::PeerConnectionInterface::kHaveLocalPrAnswer:
+ return PeerConnectionStates::SignalingState::HaveLocalPrAnswer;
+ case webrtc::PeerConnectionInterface::kHaveRemoteOffer:
+ return PeerConnectionStates::SignalingState::HaveRemoteOffer;
+ case webrtc::PeerConnectionInterface::kHaveRemotePrAnswer:
+ return PeerConnectionStates::SignalingState::HaveRemotePrAnswer;
+ case webrtc::PeerConnectionInterface::kClosed:
+ return PeerConnectionStates::SignalingState::Closed;
+ }
+}
+
+void LibWebRTCMediaEndpoint::OnSignalingChange(webrtc::PeerConnectionInterface::SignalingState rtcState)
+{
+ auto state = signalingState(rtcState);
+ callOnMainThread([protectedThis = makeRef(*this), state] {
+ if (protectedThis->isStopped())
+ return;
+ protectedThis->m_peerConnectionBackend.updateSignalingState(state);
+ });
+}
+
+static inline String trackId(webrtc::MediaStreamTrackInterface& videoTrack)
+{
+ return String(videoTrack.id().data(), videoTrack.id().size());
+}
+
+static inline Ref<MediaStreamTrack> createMediaStreamTrack(ScriptExecutionContext& context, Ref<RealtimeMediaSource>&& remoteSource)
+{
+ String trackId = remoteSource->id();
+ return MediaStreamTrack::create(context, MediaStreamTrackPrivate::create(WTFMove(remoteSource), WTFMove(trackId)));
+}
+
+void LibWebRTCMediaEndpoint::addStream(webrtc::MediaStreamInterface& stream)
+{
+ MediaStreamTrackVector tracks;
+ for (auto& videoTrack : stream.GetVideoTracks()) {
+ ASSERT(videoTrack);
+ String id = trackId(*videoTrack);
+ auto remoteSource = RealtimeIncomingVideoSource::create(WTFMove(videoTrack), WTFMove(id));
+ tracks.append(createMediaStreamTrack(*m_peerConnectionBackend.connection().scriptExecutionContext(), WTFMove(remoteSource)));
+ }
+ for (auto& audioTrack : stream.GetAudioTracks()) {
+ ASSERT(audioTrack);
+ String id = trackId(*audioTrack);
+ auto remoteSource = RealtimeIncomingAudioSource::create(WTFMove(audioTrack), WTFMove(id));
+ tracks.append(createMediaStreamTrack(*m_peerConnectionBackend.connection().scriptExecutionContext(), WTFMove(remoteSource)));
+ }
+
+ auto newStream = MediaStream::create(*m_peerConnectionBackend.connection().scriptExecutionContext(), WTFMove(tracks));
+ m_peerConnectionBackend.connection().fireEvent(MediaStreamEvent::create(eventNames().addstreamEvent, false, false, newStream.copyRef()));
+
+ Vector<RefPtr<MediaStream>> streams;
+ streams.append(newStream.copyRef());
+ for (auto& track : newStream->getTracks())
+ m_peerConnectionBackend.connection().fireEvent(RTCTrackEvent::create(eventNames().trackEvent, false, false, nullptr, track.get(), Vector<RefPtr<MediaStream>>(streams), nullptr));
+}
+
+void LibWebRTCMediaEndpoint::OnAddStream(rtc::scoped_refptr<webrtc::MediaStreamInterface> stream)
+{
+ callOnMainThread([protectedThis = makeRef(*this), stream = WTFMove(stream)] {
+ if (protectedThis->isStopped())
+ return;
+ ASSERT(stream);
+ protectedThis->addStream(*stream.get());
+ });
+}
+
+void LibWebRTCMediaEndpoint::OnRemoveStream(rtc::scoped_refptr<webrtc::MediaStreamInterface>)
+{
+ notImplemented();
+}
+
+std::unique_ptr<RTCDataChannelHandler> LibWebRTCMediaEndpoint::createDataChannel(const String& label, const RTCDataChannelInit& options)
+{
+ webrtc::DataChannelInit init;
+ init.ordered = options.ordered;
+ init.maxRetransmitTime = options.maxRetransmitTime;
+ init.maxRetransmits = options.maxRetransmits;
+ init.protocol = options.protocol.utf8().data();
+ init.negotiated = options.negotiated;
+ init.id = options.id;
+
+ return std::make_unique<LibWebRTCDataChannelHandler>(m_backend->CreateDataChannel(label.utf8().data(), &init));
+}
+
+void LibWebRTCMediaEndpoint::addDataChannel(rtc::scoped_refptr<webrtc::DataChannelInterface>&& dataChannel)
+{
+ auto protocol = dataChannel->protocol();
+ auto label = dataChannel->label();
+
+ RTCDataChannelInit init;
+ init.ordered = dataChannel->ordered();
+ init.maxRetransmitTime = dataChannel->maxRetransmitTime();
+ init.maxRetransmits = dataChannel->maxRetransmits();
+ init.protocol = String(protocol.data(), protocol.size());
+ init.negotiated = dataChannel->negotiated();
+ init.id = dataChannel->id();
+
+ bool isOpened = dataChannel->state() == webrtc::DataChannelInterface::kOpen;
+
+ auto handler = std::make_unique<LibWebRTCDataChannelHandler>(WTFMove(dataChannel));
+ ASSERT(m_peerConnectionBackend.connection().scriptExecutionContext());
+ auto channel = RTCDataChannel::create(*m_peerConnectionBackend.connection().scriptExecutionContext(), WTFMove(handler), String(label.data(), label.size()), WTFMove(init));
+
+ if (isOpened) {
+ callOnMainThread([channel = channel.copyRef()] {
+ // FIXME: We should be able to write channel->didChangeReadyState(...)
+ RTCDataChannelHandlerClient& client = channel.get();
+ client.didChangeReadyState(RTCDataChannel::ReadyStateOpen);
+ });
+ }
+
+ m_peerConnectionBackend.connection().fireEvent(RTCDataChannelEvent::create(eventNames().datachannelEvent, false, false, WTFMove(channel)));
+}
+
+void LibWebRTCMediaEndpoint::OnDataChannel(rtc::scoped_refptr<webrtc::DataChannelInterface> dataChannel)
+{
+ callOnMainThread([protectedThis = makeRef(*this), dataChannel = WTFMove(dataChannel)] {
+ if (protectedThis->isStopped())
+ return;
+ protectedThis->addDataChannel(rtc::scoped_refptr<webrtc::DataChannelInterface>(dataChannel));
+ });
+}
+
+void LibWebRTCMediaEndpoint::stop()
+{
+ ASSERT(m_backend);
+ m_backend->Close();
+ m_backend = nullptr;
+}
+
+void LibWebRTCMediaEndpoint::OnRenegotiationNeeded()
+{
+ callOnMainThread([protectedThis = makeRef(*this)] {
+ if (protectedThis->isStopped())
+ return;
+ protectedThis->m_peerConnectionBackend.markAsNeedingNegotiation();
+ });
+}
+
+static inline PeerConnectionStates::IceConnectionState iceConnectionState(webrtc::PeerConnectionInterface::IceConnectionState state)
+{
+ switch (state) {
+ case webrtc::PeerConnectionInterface::kIceConnectionNew:
+ return PeerConnectionStates::IceConnectionState::New;
+ case webrtc::PeerConnectionInterface::kIceConnectionChecking:
+ return PeerConnectionStates::IceConnectionState::Checking;
+ case webrtc::PeerConnectionInterface::kIceConnectionConnected:
+ return PeerConnectionStates::IceConnectionState::Connected;
+ case webrtc::PeerConnectionInterface::kIceConnectionCompleted:
+ return PeerConnectionStates::IceConnectionState::Completed;
+ case webrtc::PeerConnectionInterface::kIceConnectionFailed:
+ return PeerConnectionStates::IceConnectionState::Failed;
+ case webrtc::PeerConnectionInterface::kIceConnectionDisconnected:
+ return PeerConnectionStates::IceConnectionState::Disconnected;
+ case webrtc::PeerConnectionInterface::kIceConnectionClosed:
+ return PeerConnectionStates::IceConnectionState::Closed;
+ case webrtc::PeerConnectionInterface::kIceConnectionMax:
+ ASSERT_NOT_REACHED();
+ return PeerConnectionStates::IceConnectionState::New;
+ }
+}
+
+void LibWebRTCMediaEndpoint::OnIceConnectionChange(webrtc::PeerConnectionInterface::IceConnectionState state)
+{
+ auto connectionState = iceConnectionState(state);
+ callOnMainThread([protectedThis = makeRef(*this), connectionState] {
+ if (protectedThis->isStopped())
+ return;
+ if (protectedThis->m_peerConnectionBackend.connection().internalIceConnectionState() != connectionState)
+ protectedThis->m_peerConnectionBackend.connection().updateIceConnectionState(connectionState);
+ });
+}
+
+void LibWebRTCMediaEndpoint::OnIceGatheringChange(webrtc::PeerConnectionInterface::IceGatheringState state)
+{
+ if (state == webrtc::PeerConnectionInterface::kIceGatheringComplete) {
+ callOnMainThread([protectedThis = makeRef(*this)] {
+ if (protectedThis->isStopped())
+ return;
+ protectedThis->m_peerConnectionBackend.doneGatheringCandidates();
+ });
+ }
+}
+
+void LibWebRTCMediaEndpoint::OnIceCandidate(const webrtc::IceCandidateInterface *rtcCandidate)
+{
+ ASSERT(rtcCandidate);
+
+ std::string sdp;
+ rtcCandidate->ToString(&sdp);
+ String candidateSDP(sdp.data(), sdp.size());
+
+ auto mid = rtcCandidate->sdp_mid();
+ String candidateMid(mid.data(), mid.size());
+
+ callOnMainThread([protectedThis = makeRef(*this), mid = WTFMove(candidateMid), sdp = WTFMove(candidateSDP)] {
+ if (protectedThis->isStopped())
+ return;
+ protectedThis->m_peerConnectionBackend.fireICECandidateEvent(RTCIceCandidate::create(String(sdp), String(mid), 0));
+ });
+}
+
+void LibWebRTCMediaEndpoint::OnIceCandidatesRemoved(const std::vector<cricket::Candidate>&)
+{
+ ASSERT_NOT_REACHED();
+}
+
+void LibWebRTCMediaEndpoint::createSessionDescriptionSucceeded(webrtc::SessionDescriptionInterface* description)
+{
+ std::string sdp;
+ description->ToString(&sdp);
+ String sdpString(sdp.data(), sdp.size());
+
+ callOnMainThread([protectedThis = makeRef(*this), sdp = WTFMove(sdpString)] {
+ if (protectedThis->isStopped())
+ return;
+ if (protectedThis->m_isInitiator)
+ protectedThis->m_peerConnectionBackend.createOfferSucceeded(String(sdp));
+ else
+ protectedThis->m_peerConnectionBackend.createAnswerSucceeded(String(sdp));
+ });
+}
+
+void LibWebRTCMediaEndpoint::createSessionDescriptionFailed(const std::string& errorMessage)
+{
+ String error(errorMessage.data(), errorMessage.size());
+ callOnMainThread([protectedThis = makeRef(*this), error = WTFMove(error)] {
+ if (protectedThis->isStopped())
+ return;
+ if (protectedThis->m_isInitiator)
+ protectedThis->m_peerConnectionBackend.createOfferFailed(Exception { OperationError, String(error) });
+ else
+ protectedThis->m_peerConnectionBackend.createAnswerFailed(Exception { OperationError, String(error) });
+ });
+}
+
+void LibWebRTCMediaEndpoint::setLocalSessionDescriptionSucceeded()
+{
+ callOnMainThread([protectedThis = makeRef(*this)] {
+ if (protectedThis->isStopped())
+ return;
+ protectedThis->m_peerConnectionBackend.setLocalDescriptionSucceeded();
+ });
+}
+
+void LibWebRTCMediaEndpoint::setLocalSessionDescriptionFailed(const std::string& errorMessage)
+{
+ String error(errorMessage.data(), errorMessage.size());
+ callOnMainThread([protectedThis = makeRef(*this), error = WTFMove(error)] {
+ if (protectedThis->isStopped())
+ return;
+ protectedThis->m_peerConnectionBackend.setLocalDescriptionFailed(Exception { OperationError, String(error) });
+ });
+}
+
+void LibWebRTCMediaEndpoint::setRemoteSessionDescriptionSucceeded()
+{
+ callOnMainThread([protectedThis = makeRef(*this)] {
+ if (protectedThis->isStopped())
+ return;
+ protectedThis->m_peerConnectionBackend.setRemoteDescriptionSucceeded();
+ });
+}
+
+void LibWebRTCMediaEndpoint::setRemoteSessionDescriptionFailed(const std::string& errorMessage)
+{
+ String error(errorMessage.data(), errorMessage.size());
+ callOnMainThread([protectedThis = makeRef(*this), error = WTFMove(error)] {
+ if (protectedThis->isStopped())
+ return;
+ protectedThis->m_peerConnectionBackend.setRemoteDescriptionFailed(Exception { OperationError, String(error) });
+ });
+}
+
+} // namespace WebCore
+
+#endif // USE(LIBWEBRTC)