summaryrefslogtreecommitdiff
path: root/Source/WebCore/Modules/mediastream/libwebrtc
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
parent32761a6cee1d0dee366b885b7b9c777e67885688 (diff)
downloadWebKitGtk-tarball-master.tar.gz
Diffstat (limited to 'Source/WebCore/Modules/mediastream/libwebrtc')
-rw-r--r--Source/WebCore/Modules/mediastream/libwebrtc/LibWebRTCDataChannelHandler.cpp114
-rw-r--r--Source/WebCore/Modules/mediastream/libwebrtc/LibWebRTCDataChannelHandler.h61
-rw-r--r--Source/WebCore/Modules/mediastream/libwebrtc/LibWebRTCMediaEndpoint.cpp527
-rw-r--r--Source/WebCore/Modules/mediastream/libwebrtc/LibWebRTCMediaEndpoint.h175
-rw-r--r--Source/WebCore/Modules/mediastream/libwebrtc/LibWebRTCPeerConnectionBackend.cpp231
-rw-r--r--Source/WebCore/Modules/mediastream/libwebrtc/LibWebRTCPeerConnectionBackend.h97
6 files changed, 1205 insertions, 0 deletions
diff --git a/Source/WebCore/Modules/mediastream/libwebrtc/LibWebRTCDataChannelHandler.cpp b/Source/WebCore/Modules/mediastream/libwebrtc/LibWebRTCDataChannelHandler.cpp
new file mode 100644
index 000000000..564b6d1c8
--- /dev/null
+++ b/Source/WebCore/Modules/mediastream/libwebrtc/LibWebRTCDataChannelHandler.cpp
@@ -0,0 +1,114 @@
+/*
+ * 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 "LibWebRTCDataChannelHandler.h"
+
+#if USE(LIBWEBRTC)
+
+#include "RTCDataChannel.h"
+#include <wtf/MainThread.h>
+
+namespace WebCore {
+
+LibWebRTCDataChannelHandler::~LibWebRTCDataChannelHandler()
+{
+ if (m_client)
+ m_channel->UnregisterObserver();
+}
+
+void LibWebRTCDataChannelHandler::setClient(RTCDataChannelHandlerClient* client)
+{
+ m_client = client;
+ if (m_client)
+ m_channel->RegisterObserver(this);
+ else
+ m_channel->UnregisterObserver();
+}
+
+bool LibWebRTCDataChannelHandler::sendStringData(const String& text)
+{
+ return m_channel->Send({rtc::CopyOnWriteBuffer(text.utf8().data(), text.length()), false});
+}
+
+bool LibWebRTCDataChannelHandler::sendRawData(const char* data, size_t length)
+{
+ return m_channel->Send({rtc::CopyOnWriteBuffer(data, length), true});
+}
+
+void LibWebRTCDataChannelHandler::close()
+{
+ m_channel->Close();
+}
+
+void LibWebRTCDataChannelHandler::OnStateChange()
+{
+ RTCDataChannel::ReadyState state;
+ switch (m_channel->state()) {
+ case webrtc::DataChannelInterface::kConnecting:
+ state = RTCDataChannel::ReadyStateConnecting;
+ break;
+ case webrtc::DataChannelInterface::kOpen:
+ state = RTCDataChannel::ReadyStateOpen;
+ break;
+ case webrtc::DataChannelInterface::kClosing:
+ state = RTCDataChannel::ReadyStateClosing;
+ break;
+ case webrtc::DataChannelInterface::kClosed:
+ state = RTCDataChannel::ReadyStateClosed;
+ break;
+ }
+ ASSERT(m_client);
+ callOnMainThread([protectedClient = makeRef(*m_client), state] {
+ protectedClient->didChangeReadyState(state);
+ });
+}
+
+void LibWebRTCDataChannelHandler::OnMessage(const webrtc::DataBuffer& buffer)
+{
+ ASSERT(m_client);
+ std::unique_ptr<webrtc::DataBuffer> protectedBuffer(new webrtc::DataBuffer(buffer));
+ callOnMainThread([protectedClient = makeRef(*m_client), buffer = WTFMove(protectedBuffer)] {
+ // FIXME: Ensure this is correct by adding some tests with non-ASCII characters.
+ const char* data = reinterpret_cast<const char*>(buffer->data.data());
+ if (buffer->binary)
+ protectedClient->didReceiveRawData(data, buffer->size());
+ else
+ protectedClient->didReceiveStringData(String(data, buffer->size()));
+ });
+}
+
+void LibWebRTCDataChannelHandler::OnBufferedAmountChange(uint64_t previousAmount)
+{
+ if (previousAmount <= m_channel->buffered_amount())
+ return;
+ ASSERT(m_client);
+ callOnMainThread([protectedClient = makeRef(*m_client)] {
+ protectedClient->bufferedAmountIsDecreasing();
+ });
+}
+
+} // namespace WebCore
+
+#endif // USE(LIBWEBRTC)
diff --git a/Source/WebCore/Modules/mediastream/libwebrtc/LibWebRTCDataChannelHandler.h b/Source/WebCore/Modules/mediastream/libwebrtc/LibWebRTCDataChannelHandler.h
new file mode 100644
index 000000000..7cc3502b7
--- /dev/null
+++ b/Source/WebCore/Modules/mediastream/libwebrtc/LibWebRTCDataChannelHandler.h
@@ -0,0 +1,61 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#if USE(LIBWEBRTC)
+
+#include "LibWebRTCMacros.h"
+#include "RTCDataChannelHandler.h"
+#include <webrtc/api/datachannelinterface.h>
+
+namespace WebCore {
+
+class RTCDataChannelHandlerClient;
+
+class LibWebRTCDataChannelHandler final : public RTCDataChannelHandler, private webrtc::DataChannelObserver {
+public:
+ explicit LibWebRTCDataChannelHandler(rtc::scoped_refptr<webrtc::DataChannelInterface>&& channel) : m_channel(WTFMove(channel)) { ASSERT(m_channel); }
+ ~LibWebRTCDataChannelHandler();
+
+private:
+ // RTCDataChannelHandler API
+ void setClient(RTCDataChannelHandlerClient*) final;
+ bool sendStringData(const String&) final;
+ bool sendRawData(const char*, size_t) final;
+ void close() final;
+ size_t bufferedAmount() const final { return static_cast<size_t>(m_channel->buffered_amount()); }
+
+ // webrtc::DataChannelObserver API
+ void OnStateChange();
+ void OnMessage(const webrtc::DataBuffer&);
+ void OnBufferedAmountChange(uint64_t);
+
+ rtc::scoped_refptr<webrtc::DataChannelInterface> m_channel;
+ RTCDataChannelHandlerClient* m_client { nullptr };
+};
+
+} // namespace WebCore
+
+#endif // USE(LIBWEBRTC)
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)
diff --git a/Source/WebCore/Modules/mediastream/libwebrtc/LibWebRTCMediaEndpoint.h b/Source/WebCore/Modules/mediastream/libwebrtc/LibWebRTCMediaEndpoint.h
new file mode 100644
index 000000000..7b308e0b1
--- /dev/null
+++ b/Source/WebCore/Modules/mediastream/libwebrtc/LibWebRTCMediaEndpoint.h
@@ -0,0 +1,175 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#if USE(LIBWEBRTC)
+
+#include "LibWebRTCProvider.h"
+#include "PeerConnectionBackend.h"
+#include "RealtimeOutgoingAudioSource.h"
+#include "RealtimeOutgoingVideoSource.h"
+
+#include <webrtc/api/jsep.h>
+#include <webrtc/api/peerconnectionfactory.h>
+#include <webrtc/api/peerconnectioninterface.h>
+#include <webrtc/api/rtcstatscollector.h>
+
+#include <wtf/ThreadSafeRefCounted.h>
+
+namespace webrtc {
+class CreateSessionDescriptionObserver;
+class DataChannelInterface;
+class IceCandidateInterface;
+class MediaStreamInterface;
+class PeerConnectionObserver;
+class SessionDescriptionInterface;
+class SetSessionDescriptionObserver;
+}
+
+namespace WebCore {
+
+class LibWebRTCProvider;
+class LibWebRTCPeerConnectionBackend;
+class MediaStreamTrack;
+class RTCSessionDescription;
+
+class LibWebRTCMediaEndpoint : public ThreadSafeRefCounted<LibWebRTCMediaEndpoint>, private webrtc::PeerConnectionObserver {
+public:
+ static Ref<LibWebRTCMediaEndpoint> create(LibWebRTCPeerConnectionBackend& peerConnection, LibWebRTCProvider& client) { return adoptRef(*new LibWebRTCMediaEndpoint(peerConnection, client)); }
+ virtual ~LibWebRTCMediaEndpoint() { }
+
+ webrtc::PeerConnectionInterface& backend() const { ASSERT(m_backend); return *m_backend.get(); }
+ void doSetLocalDescription(RTCSessionDescription&);
+ void doSetRemoteDescription(RTCSessionDescription&);
+ void doCreateOffer();
+ void doCreateAnswer();
+ void getStats(MediaStreamTrack*, const DeferredPromise&);
+ std::unique_ptr<RTCDataChannelHandler> createDataChannel(const String&, const RTCDataChannelInit&);
+ bool addIceCandidate(webrtc::IceCandidateInterface& candidate) { return m_backend->AddIceCandidate(&candidate); }
+
+ void stop();
+ bool isStopped() const { return !m_backend; }
+
+ RefPtr<RTCSessionDescription> localDescription() const;
+ RefPtr<RTCSessionDescription> remoteDescription() const;
+
+private:
+ LibWebRTCMediaEndpoint(LibWebRTCPeerConnectionBackend&, LibWebRTCProvider&);
+
+ // webrtc::PeerConnectionObserver API
+ void OnSignalingChange(webrtc::PeerConnectionInterface::SignalingState) final;
+ void OnAddStream(rtc::scoped_refptr<webrtc::MediaStreamInterface>) final;
+ void OnRemoveStream(rtc::scoped_refptr<webrtc::MediaStreamInterface>) final;
+ void OnDataChannel(rtc::scoped_refptr<webrtc::DataChannelInterface>) final;
+ void OnRenegotiationNeeded() final;
+ void OnIceConnectionChange(webrtc::PeerConnectionInterface::IceConnectionState) final;
+ void OnIceGatheringChange(webrtc::PeerConnectionInterface::IceGatheringState) final;
+ void OnIceCandidate(const webrtc::IceCandidateInterface*) final;
+ void OnIceCandidatesRemoved(const std::vector<cricket::Candidate>&) final;
+
+ void createSessionDescriptionSucceeded(webrtc::SessionDescriptionInterface*);
+ void createSessionDescriptionFailed(const std::string&);
+ void setLocalSessionDescriptionSucceeded();
+ void setLocalSessionDescriptionFailed(const std::string&);
+ void setRemoteSessionDescriptionSucceeded();
+ void setRemoteSessionDescriptionFailed(const std::string&);
+ void addStream(webrtc::MediaStreamInterface&);
+ void addDataChannel(rtc::scoped_refptr<webrtc::DataChannelInterface>&&);
+
+ int AddRef() const { ref(); return static_cast<int>(refCount()); }
+ int Release() const { deref(); return static_cast<int>(refCount()); }
+
+ class CreateSessionDescriptionObserver final : public webrtc::CreateSessionDescriptionObserver {
+ public:
+ explicit CreateSessionDescriptionObserver(LibWebRTCMediaEndpoint &endpoint) : m_endpoint(endpoint) { }
+
+ void OnSuccess(webrtc::SessionDescriptionInterface* sessionDescription) final { m_endpoint.createSessionDescriptionSucceeded(sessionDescription); }
+ void OnFailure(const std::string& error) final { m_endpoint.createSessionDescriptionFailed(error); }
+
+ int AddRef() const { return m_endpoint.AddRef(); }
+ int Release() const { return m_endpoint.Release(); }
+
+ private:
+ LibWebRTCMediaEndpoint& m_endpoint;
+ };
+
+ class SetLocalSessionDescriptionObserver final : public webrtc::SetSessionDescriptionObserver {
+ public:
+ explicit SetLocalSessionDescriptionObserver(LibWebRTCMediaEndpoint &endpoint) : m_endpoint(endpoint) { }
+
+ void OnSuccess() final { m_endpoint.setLocalSessionDescriptionSucceeded(); }
+ void OnFailure(const std::string& error) final { m_endpoint.setLocalSessionDescriptionFailed(error); }
+
+ int AddRef() const { return m_endpoint.AddRef(); }
+ int Release() const { return m_endpoint.Release(); }
+
+ private:
+ LibWebRTCMediaEndpoint& m_endpoint;
+ };
+
+ class SetRemoteSessionDescriptionObserver final : public webrtc::SetSessionDescriptionObserver {
+ public:
+ explicit SetRemoteSessionDescriptionObserver(LibWebRTCMediaEndpoint &endpoint) : m_endpoint(endpoint) { }
+
+ void OnSuccess() final { m_endpoint.setRemoteSessionDescriptionSucceeded(); }
+ void OnFailure(const std::string& error) final { m_endpoint.setRemoteSessionDescriptionFailed(error); }
+
+ int AddRef() const { return m_endpoint.AddRef(); }
+ int Release() const { return m_endpoint.Release(); }
+
+ private:
+ LibWebRTCMediaEndpoint& m_endpoint;
+ };
+
+ class StatsCollector final : public webrtc::RTCStatsCollectorCallback {
+ public:
+ static rtc::scoped_refptr<StatsCollector> create(LibWebRTCMediaEndpoint& endpoint, const DeferredPromise& promise, MediaStreamTrack* track) { return new StatsCollector(endpoint, promise, track); }
+
+ int AddRef() const { return m_endpoint.AddRef(); }
+ int Release() const { return m_endpoint.Release(); }
+
+ private:
+ StatsCollector(LibWebRTCMediaEndpoint&, const DeferredPromise&, MediaStreamTrack*);
+
+ void OnStatsDelivered(const rtc::scoped_refptr<const webrtc::RTCStatsReport>&) final;
+
+ LibWebRTCMediaEndpoint& m_endpoint;
+ const DeferredPromise& m_promise;
+ String m_id;
+ };
+
+ LibWebRTCPeerConnectionBackend& m_peerConnectionBackend;
+ rtc::scoped_refptr<webrtc::PeerConnectionInterface> m_backend;
+
+ CreateSessionDescriptionObserver m_createSessionDescriptionObserver;
+ SetLocalSessionDescriptionObserver m_setLocalSessionDescriptionObserver;
+ SetRemoteSessionDescriptionObserver m_setRemoteSessionDescriptionObserver;
+
+ bool m_isInitiator { false };
+};
+
+} // namespace WebCore
+
+#endif // USE(LIBWEBRTC)
diff --git a/Source/WebCore/Modules/mediastream/libwebrtc/LibWebRTCPeerConnectionBackend.cpp b/Source/WebCore/Modules/mediastream/libwebrtc/LibWebRTCPeerConnectionBackend.cpp
new file mode 100644
index 000000000..c8a382c5b
--- /dev/null
+++ b/Source/WebCore/Modules/mediastream/libwebrtc/LibWebRTCPeerConnectionBackend.cpp
@@ -0,0 +1,231 @@
+/*
+ * 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 "LibWebRTCPeerConnectionBackend.h"
+
+#if USE(LIBWEBRTC)
+
+#include "Document.h"
+#include "IceCandidate.h"
+#include "JSRTCStatsReport.h"
+#include "LibWebRTCDataChannelHandler.h"
+#include "LibWebRTCMediaEndpoint.h"
+#include "MediaEndpointConfiguration.h"
+#include "Page.h"
+#include "RTCIceCandidate.h"
+#include "RTCPeerConnection.h"
+#include "RTCRtpReceiver.h"
+#include "RTCSessionDescription.h"
+#include "RealtimeIncomingAudioSource.h"
+#include "RealtimeIncomingVideoSource.h"
+
+namespace WebCore {
+
+static std::unique_ptr<PeerConnectionBackend> createLibWebRTCPeerConnectionBackend(RTCPeerConnection& peerConnection)
+{
+ return std::make_unique<LibWebRTCPeerConnectionBackend>(peerConnection);
+}
+
+CreatePeerConnectionBackend PeerConnectionBackend::create = createLibWebRTCPeerConnectionBackend;
+
+static inline LibWebRTCProvider& libWebRTCProvider(RTCPeerConnection& peerConnection)
+{
+ ASSERT(peerConnection.scriptExecutionContext()->isDocument());
+ auto* page = static_cast<Document*>(peerConnection.scriptExecutionContext())->page();
+ return page->libWebRTCProvider();
+}
+
+LibWebRTCPeerConnectionBackend::LibWebRTCPeerConnectionBackend(RTCPeerConnection& peerConnection)
+ : PeerConnectionBackend(peerConnection)
+ , m_endpoint(LibWebRTCMediaEndpoint::create(*this, libWebRTCProvider(peerConnection)))
+{
+}
+
+LibWebRTCPeerConnectionBackend::~LibWebRTCPeerConnectionBackend()
+{
+}
+
+static webrtc::PeerConnectionInterface::RTCConfiguration configurationFromMediaEndpointConfiguration(MediaEndpointConfiguration&& configuration)
+{
+ webrtc::PeerConnectionInterface::RTCConfiguration rtcConfiguration(webrtc::PeerConnectionInterface::RTCConfigurationType::kAggressive);
+
+ if (configuration.iceTransportPolicy == PeerConnectionStates::IceTransportPolicy::Relay)
+ rtcConfiguration.type = webrtc::PeerConnectionInterface::kRelay;
+
+ if (configuration.bundlePolicy == PeerConnectionStates::BundlePolicy::MaxBundle)
+ rtcConfiguration.bundle_policy = webrtc::PeerConnectionInterface::kBundlePolicyMaxBundle;
+ else if (configuration.bundlePolicy == PeerConnectionStates::BundlePolicy::MaxCompat)
+ rtcConfiguration.bundle_policy = webrtc::PeerConnectionInterface::kBundlePolicyMaxCompat;
+
+ for (auto& server : configuration.iceServers) {
+ webrtc::PeerConnectionInterface::IceServer iceServer;
+ iceServer.username = server.username.utf8().data();
+ iceServer.password = server.credential.utf8().data();
+ for (auto& url : server.urls)
+ iceServer.urls.push_back({ url.string().utf8().data() });
+ rtcConfiguration.servers.push_back(WTFMove(iceServer));
+ }
+
+ return rtcConfiguration;
+}
+
+void LibWebRTCPeerConnectionBackend::setConfiguration(MediaEndpointConfiguration&& configuration)
+{
+ m_endpoint->backend().SetConfiguration(configurationFromMediaEndpointConfiguration(WTFMove(configuration)));
+}
+
+void LibWebRTCPeerConnectionBackend::getStats(MediaStreamTrack* track, Ref<DeferredPromise>&& promise)
+{
+ if (m_endpoint->isStopped())
+ return;
+
+ auto& statsPromise = promise.get();
+ m_statsPromises.add(&statsPromise, WTFMove(promise));
+ m_endpoint->getStats(track, statsPromise);
+}
+
+void LibWebRTCPeerConnectionBackend::getStatsSucceeded(const DeferredPromise& promise, Ref<RTCStatsReport>&& report)
+{
+ auto statsPromise = m_statsPromises.take(&promise);
+ ASSERT(statsPromise);
+ statsPromise.value()->resolve<IDLInterface<RTCStatsReport>>(WTFMove(report));
+}
+
+void LibWebRTCPeerConnectionBackend::getStatsFailed(const DeferredPromise& promise, Exception&& exception)
+{
+ auto statsPromise = m_statsPromises.take(&promise);
+ ASSERT(statsPromise);
+ statsPromise.value()->reject(WTFMove(exception));
+}
+
+void LibWebRTCPeerConnectionBackend::doSetLocalDescription(RTCSessionDescription& description)
+{
+ m_endpoint->doSetLocalDescription(description);
+ if (!m_isLocalDescriptionSet) {
+ if (m_isRemoteDescriptionSet) {
+ while (m_pendingCandidates.size())
+ m_endpoint->addIceCandidate(*m_pendingCandidates.takeLast().release());
+ }
+ m_isLocalDescriptionSet = true;
+ }
+}
+
+void LibWebRTCPeerConnectionBackend::doSetRemoteDescription(RTCSessionDescription& description)
+{
+ m_endpoint->doSetRemoteDescription(description);
+ if (!m_isRemoteDescriptionSet) {
+ if (m_isLocalDescriptionSet) {
+ while (m_pendingCandidates.size())
+ m_endpoint->addIceCandidate(*m_pendingCandidates.takeLast().release());
+ }
+ m_isRemoteDescriptionSet = true;
+ }
+}
+
+void LibWebRTCPeerConnectionBackend::doCreateOffer(RTCOfferOptions&&)
+{
+ m_endpoint->doCreateOffer();
+}
+
+void LibWebRTCPeerConnectionBackend::doCreateAnswer(RTCAnswerOptions&&)
+{
+ if (!m_isRemoteDescriptionSet) {
+ createAnswerFailed(Exception { INVALID_STATE_ERR, "No remote description set" });
+ return;
+ }
+ m_endpoint->doCreateAnswer();
+}
+
+void LibWebRTCPeerConnectionBackend::doStop()
+{
+ m_endpoint->stop();
+}
+
+void LibWebRTCPeerConnectionBackend::doAddIceCandidate(RTCIceCandidate& candidate)
+{
+ if (!m_isRemoteDescriptionSet) {
+ addIceCandidateFailed(Exception { INVALID_STATE_ERR, "No remote description set" });
+ return;
+ }
+
+ webrtc::SdpParseError error;
+ int sdpMLineIndex = candidate.sdpMLineIndex() ? candidate.sdpMLineIndex().value() : 0;
+ std::unique_ptr<webrtc::IceCandidateInterface> rtcCandidate(webrtc::CreateIceCandidate(candidate.sdpMid().utf8().data(), sdpMLineIndex, candidate.candidate().utf8().data(), &error));
+
+ if (!rtcCandidate) {
+ String message(error.description.data(), error.description.size());
+ addIceCandidateFailed(Exception { OperationError, WTFMove(message) });
+ return;
+ }
+
+ // libwebrtc does not like that ice candidates are set before the description.
+ if (!m_isLocalDescriptionSet || !m_isRemoteDescriptionSet)
+ m_pendingCandidates.append(WTFMove(rtcCandidate));
+ else if (!m_endpoint->addIceCandidate(*rtcCandidate.get())) {
+ ASSERT_NOT_REACHED();
+ addIceCandidateFailed(Exception { OperationError, ASCIILiteral("Failed to apply the received candidate") });
+ return;
+ }
+ addIceCandidateSucceeded();
+}
+
+void LibWebRTCPeerConnectionBackend::addAudioSource(Ref<RealtimeOutgoingAudioSource>&& source)
+{
+ m_audioSources.append(WTFMove(source));
+}
+
+void LibWebRTCPeerConnectionBackend::addVideoSource(Ref<RealtimeOutgoingVideoSource>&& source)
+{
+ m_videoSources.append(WTFMove(source));
+}
+
+Ref<RTCRtpReceiver> LibWebRTCPeerConnectionBackend::createReceiver(const String&, const String& trackKind, const String& trackId)
+{
+ // FIXME: We need to create a source that will get fueled once we will receive OnAddStream.
+ // For the moment, we create an empty one.
+ auto remoteTrackPrivate = (trackKind == "audio") ? MediaStreamTrackPrivate::create(RealtimeIncomingAudioSource::create(nullptr, String(trackId))) : MediaStreamTrackPrivate::create(RealtimeIncomingVideoSource::create(nullptr, String(trackId)));
+ auto remoteTrack = MediaStreamTrack::create(*m_peerConnection.scriptExecutionContext(), WTFMove(remoteTrackPrivate));
+
+ return RTCRtpReceiver::create(WTFMove(remoteTrack));
+}
+
+std::unique_ptr<RTCDataChannelHandler> LibWebRTCPeerConnectionBackend::createDataChannelHandler(const String& label, const RTCDataChannelInit& options)
+{
+ return m_endpoint->createDataChannel(label, options);
+}
+
+RefPtr<RTCSessionDescription> LibWebRTCPeerConnectionBackend::localDescription() const
+{
+ return m_endpoint->localDescription();
+}
+
+RefPtr<RTCSessionDescription> LibWebRTCPeerConnectionBackend::remoteDescription() const
+{
+ return m_endpoint->remoteDescription();
+}
+
+} // namespace WebCore
+
+#endif // USE(LIBWEBRTC)
diff --git a/Source/WebCore/Modules/mediastream/libwebrtc/LibWebRTCPeerConnectionBackend.h b/Source/WebCore/Modules/mediastream/libwebrtc/LibWebRTCPeerConnectionBackend.h
new file mode 100644
index 000000000..f5b4c565f
--- /dev/null
+++ b/Source/WebCore/Modules/mediastream/libwebrtc/LibWebRTCPeerConnectionBackend.h
@@ -0,0 +1,97 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#if USE(LIBWEBRTC)
+
+#include "PeerConnectionBackend.h"
+#include <wtf/HashMap.h>
+
+namespace webrtc {
+class IceCandidateInterface;
+}
+
+namespace WebCore {
+
+class LibWebRTCMediaEndpoint;
+class RTCRtpReceiver;
+class RTCSessionDescription;
+class RTCstatsReport;
+class RealtimeOutgoingAudioSource;
+class RealtimeOutgoingVideoSource;
+
+class LibWebRTCPeerConnectionBackend final : public PeerConnectionBackend {
+public:
+ explicit LibWebRTCPeerConnectionBackend(RTCPeerConnection&);
+ ~LibWebRTCPeerConnectionBackend();
+
+private:
+ void doCreateOffer(RTCOfferOptions&&) final;
+ void doCreateAnswer(RTCAnswerOptions&&) final;
+ void doSetLocalDescription(RTCSessionDescription&) final;
+ void doSetRemoteDescription(RTCSessionDescription&) final;
+ void doAddIceCandidate(RTCIceCandidate&) final;
+ void doStop() final;
+ std::unique_ptr<RTCDataChannelHandler> createDataChannelHandler(const String&, const RTCDataChannelInit&) final;
+ void setConfiguration(MediaEndpointConfiguration&&) final;
+ void getStats(MediaStreamTrack*, Ref<DeferredPromise>&&) final;
+ Ref<RTCRtpReceiver> createReceiver(const String& transceiverMid, const String& trackKind, const String& trackId) final;
+
+ RefPtr<RTCSessionDescription> localDescription() const final;
+ RefPtr<RTCSessionDescription> currentLocalDescription() const final { return localDescription(); }
+ RefPtr<RTCSessionDescription> pendingLocalDescription() const final { return localDescription(); }
+
+ RefPtr<RTCSessionDescription> remoteDescription() const final;
+ RefPtr<RTCSessionDescription> currentRemoteDescription() const final { return remoteDescription(); }
+ RefPtr<RTCSessionDescription> pendingRemoteDescription() const final { return remoteDescription(); }
+
+ // FIXME: API to implement for real
+ Vector<RefPtr<MediaStream>> getRemoteStreams() const final { return { }; }
+ void replaceTrack(RTCRtpSender&, RefPtr<MediaStreamTrack>&&, DOMPromise<void>&&) final { }
+
+ void emulatePlatformEvent(const String&) final { }
+
+ friend LibWebRTCMediaEndpoint;
+ RTCPeerConnection& connection() { return m_peerConnection; }
+ void addAudioSource(Ref<RealtimeOutgoingAudioSource>&&);
+ void addVideoSource(Ref<RealtimeOutgoingVideoSource>&&);
+
+ void getStatsSucceeded(const DeferredPromise&, Ref<RTCStatsReport>&&);
+ void getStatsFailed(const DeferredPromise&, Exception&&);
+
+private:
+ Ref<LibWebRTCMediaEndpoint> m_endpoint;
+ bool m_isLocalDescriptionSet { false };
+ bool m_isRemoteDescriptionSet { false };
+
+ Vector<std::unique_ptr<webrtc::IceCandidateInterface>> m_pendingCandidates;
+ Vector<Ref<RealtimeOutgoingAudioSource>> m_audioSources;
+ Vector<Ref<RealtimeOutgoingVideoSource>> m_videoSources;
+ HashMap<const DeferredPromise*, Ref<DeferredPromise>> m_statsPromises;
+};
+
+} // namespace WebCore
+
+#endif // USE(LIBWEBRTC)