diff options
author | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
---|---|---|
committer | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
commit | 1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c (patch) | |
tree | 46dcd36c86e7fbc6e5df36deb463b33e9967a6f7 /Source/WebCore/Modules/mediastream/RTCPeerConnection.cpp | |
parent | 32761a6cee1d0dee366b885b7b9c777e67885688 (diff) | |
download | WebKitGtk-tarball-master.tar.gz |
webkitgtk-2.16.5HEADwebkitgtk-2.16.5master
Diffstat (limited to 'Source/WebCore/Modules/mediastream/RTCPeerConnection.cpp')
-rw-r--r-- | Source/WebCore/Modules/mediastream/RTCPeerConnection.cpp | 736 |
1 files changed, 265 insertions, 471 deletions
diff --git a/Source/WebCore/Modules/mediastream/RTCPeerConnection.cpp b/Source/WebCore/Modules/mediastream/RTCPeerConnection.cpp index bb895c92f..8e4dcb113 100644 --- a/Source/WebCore/Modules/mediastream/RTCPeerConnection.cpp +++ b/Source/WebCore/Modules/mediastream/RTCPeerConnection.cpp @@ -1,6 +1,7 @@ /* * Copyright (C) 2012 Google Inc. All rights reserved. * Copyright (C) 2013 Nokia Corporation and/or its subsidiary(-ies). + * Copyright (C) 2015, 2016 Ericsson AB. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -30,335 +31,278 @@ */ #include "config.h" - -#if ENABLE(MEDIA_STREAM) - #include "RTCPeerConnection.h" -#include "ArrayValue.h" +#if ENABLE(WEB_RTC) + #include "Document.h" #include "Event.h" -#include "ExceptionCode.h" +#include "EventNames.h" #include "Frame.h" -#include "FrameLoader.h" -#include "FrameLoaderClient.h" -#include "MediaConstraintsImpl.h" -#include "MediaStreamEvent.h" +#include "MediaEndpointConfiguration.h" +#include "MediaStream.h" +#include "MediaStreamTrack.h" #include "RTCConfiguration.h" -#include "RTCDTMFSender.h" #include "RTCDataChannel.h" -#include "RTCDataChannelEvent.h" -#include "RTCDataChannelHandler.h" #include "RTCIceCandidate.h" -#include "RTCIceCandidateDescriptor.h" #include "RTCIceCandidateEvent.h" -#include "RTCPeerConnectionErrorCallback.h" +#include "RTCOfferAnswerOptions.h" #include "RTCSessionDescription.h" -#include "RTCSessionDescriptionCallback.h" -#include "RTCSessionDescriptionDescriptor.h" -#include "RTCSessionDescriptionRequestImpl.h" -#include "RTCStatsCallback.h" -#include "RTCStatsRequestImpl.h" -#include "RTCVoidRequestImpl.h" -#include "ScriptExecutionContext.h" -#include "VoidCallback.h" -#include <wtf/Functional.h> +#include "RTCTrackEvent.h" +#include "UUID.h" #include <wtf/MainThread.h> +#include <wtf/text/Base64.h> namespace WebCore { -PassRefPtr<RTCConfiguration> RTCPeerConnection::parseConfiguration(const Dictionary& configuration, ExceptionCode& ec) -{ - if (configuration.isUndefinedOrNull()) - return nullptr; - - ArrayValue iceServers; - bool ok = configuration.get("iceServers", iceServers); - if (!ok || iceServers.isUndefinedOrNull()) { - ec = TYPE_MISMATCH_ERR; - return nullptr; - } +using namespace PeerConnection; +using namespace PeerConnectionStates; - size_t numberOfServers; - ok = iceServers.length(numberOfServers); - if (!ok) { - ec = TYPE_MISMATCH_ERR; - return nullptr; - } +Ref<RTCPeerConnection> RTCPeerConnection::create(ScriptExecutionContext& context) +{ + Ref<RTCPeerConnection> peerConnection = adoptRef(*new RTCPeerConnection(context)); + peerConnection->suspendIfNeeded(); - RefPtr<RTCConfiguration> rtcConfiguration = RTCConfiguration::create(); + return peerConnection; +} - for (size_t i = 0; i < numberOfServers; ++i) { - Dictionary iceServer; - ok = iceServers.get(i, iceServer); - if (!ok) { - ec = TYPE_MISMATCH_ERR; - return nullptr; - } +RTCPeerConnection::RTCPeerConnection(ScriptExecutionContext& context) + : ActiveDOMObject(&context) + , m_backend(PeerConnectionBackend::create(*this)) +{ +} - String urlString, credential, username; - ok = iceServer.get("url", urlString); - if (!ok) { - ec = TYPE_MISMATCH_ERR; - return nullptr; - } - URL url(URL(), urlString); - if (!url.isValid() || !(url.protocolIs("turn") || url.protocolIs("stun"))) { - ec = TYPE_MISMATCH_ERR; - return nullptr; - } +RTCPeerConnection::~RTCPeerConnection() +{ + stop(); +} - iceServer.get("credential", credential); - iceServer.get("username", username); +ExceptionOr<void> RTCPeerConnection::initializeWith(Document& document, RTCConfiguration&& configuration) +{ + if (!document.frame()) + return Exception { NOT_SUPPORTED_ERR }; - rtcConfiguration->appendServer(RTCIceServer::create(url, credential, username)); - } + if (!m_backend) + return Exception { NOT_SUPPORTED_ERR }; - return rtcConfiguration.release(); + return setConfiguration(WTFMove(configuration)); } -PassRefPtr<RTCPeerConnection> RTCPeerConnection::create(ScriptExecutionContext& context, const Dictionary& rtcConfiguration, const Dictionary& mediaConstraints, ExceptionCode& ec) +ExceptionOr<Ref<RTCRtpSender>> RTCPeerConnection::addTrack(Ref<MediaStreamTrack>&& track, const Vector<std::reference_wrapper<MediaStream>>& streams) { - RefPtr<RTCConfiguration> configuration = parseConfiguration(rtcConfiguration, ec); - if (ec) - return nullptr; + if (m_signalingState == SignalingState::Closed) + return Exception { INVALID_STATE_ERR }; - RefPtr<MediaConstraints> constraints = MediaConstraintsImpl::create(mediaConstraints, ec); - if (ec) - return nullptr; + // Require at least one stream until https://github.com/w3c/webrtc-pc/issues/288 is resolved + if (!streams.size()) + return Exception { NOT_SUPPORTED_ERR }; - RefPtr<RTCPeerConnection> peerConnection = adoptRef(new RTCPeerConnection(context, configuration.release(), constraints.release(), ec)); - peerConnection->suspendIfNeeded(); - if (ec) - return nullptr; + for (RTCRtpSender& sender : m_transceiverSet->senders()) { + if (sender.trackId() == track->id()) + return Exception { INVALID_ACCESS_ERR }; + } - return peerConnection.release(); -} + Vector<String> mediaStreamIds; + for (auto stream : streams) + mediaStreamIds.append(stream.get().id()); -RTCPeerConnection::RTCPeerConnection(ScriptExecutionContext& context, PassRefPtr<RTCConfiguration> configuration, PassRefPtr<MediaConstraints> constraints, ExceptionCode& ec) - : ActiveDOMObject(&context) - , m_signalingState(SignalingStateStable) - , m_iceGatheringState(IceGatheringStateNew) - , m_iceConnectionState(IceConnectionStateNew) - , m_scheduledEventTimer(this, &RTCPeerConnection::scheduledEventTimerFired) - , m_stopped(false) -{ - Document& document = toDocument(context); + RTCRtpSender* sender = nullptr; - if (!document.frame()) { - ec = NOT_SUPPORTED_ERR; - return; + // Reuse an existing sender with the same track kind if it has never been used to send before. + for (auto& transceiver : m_transceiverSet->list()) { + auto& existingSender = transceiver->sender(); + if (existingSender.trackKind() == track->kind() && existingSender.trackId().isNull() && !transceiver->hasSendingDirection()) { + existingSender.setTrack(WTFMove(track)); + existingSender.setMediaStreamIds(WTFMove(mediaStreamIds)); + transceiver->enableSendingDirection(); + sender = &existingSender; + break; + } } - m_peerHandler = RTCPeerConnectionHandler::create(this); - if (!m_peerHandler) { - ec = NOT_SUPPORTED_ERR; - return; - } + if (!sender) { + String transceiverMid = RTCRtpTransceiver::getNextMid(); + const String& trackKind = track->kind(); + String trackId = createCanonicalUUIDString(); - document.frame()->loader().client().dispatchWillStartUsingPeerConnectionHandler(m_peerHandler.get()); + auto newSender = RTCRtpSender::create(WTFMove(track), WTFMove(mediaStreamIds), *this); + auto receiver = m_backend->createReceiver(transceiverMid, trackKind, trackId); + auto transceiver = RTCRtpTransceiver::create(WTFMove(newSender), WTFMove(receiver)); - if (!m_peerHandler->initialize(configuration, constraints)) { - ec = NOT_SUPPORTED_ERR; - return; + // This transceiver is not yet associated with an m-line (null mid), but we need a + // provisional mid if the transceiver is used to create an offer. + transceiver->setProvisionalMid(transceiverMid); + + sender = &transceiver->sender(); + m_transceiverSet->append(WTFMove(transceiver)); } -} -RTCPeerConnection::~RTCPeerConnection() -{ - stop(); + m_backend->markAsNeedingNegotiation(); - for (auto stream = m_localStreams.begin(), end = m_localStreams.end(); stream != end; ++stream) - (*stream)->removeObserver(this); + return Ref<RTCRtpSender> { *sender }; } -void RTCPeerConnection::createOffer(PassRefPtr<RTCSessionDescriptionCallback> successCallback, PassRefPtr<RTCPeerConnectionErrorCallback> errorCallback, const Dictionary& mediaConstraints, ExceptionCode& ec) +ExceptionOr<void> RTCPeerConnection::removeTrack(RTCRtpSender& sender) { - if (m_signalingState == SignalingStateClosed) { - ec = INVALID_STATE_ERR; - return; - } + if (m_signalingState == SignalingState::Closed) + return Exception { INVALID_STATE_ERR }; - if (!successCallback) { - ec = TYPE_MISMATCH_ERR; - return; + bool shouldAbort = true; + for (RTCRtpSender& senderInSet : m_transceiverSet->senders()) { + if (&senderInSet == &sender) { + shouldAbort = sender.isStopped(); + break; + } } + if (shouldAbort) + return { }; - RefPtr<MediaConstraints> constraints = MediaConstraintsImpl::create(mediaConstraints, ec); - if (ec) - return; + sender.stop(); - RefPtr<RTCSessionDescriptionRequestImpl> request = RTCSessionDescriptionRequestImpl::create(scriptExecutionContext(), successCallback, errorCallback); - m_peerHandler->createOffer(request.release(), constraints); + m_backend->markAsNeedingNegotiation(); + return { }; } -void RTCPeerConnection::createAnswer(PassRefPtr<RTCSessionDescriptionCallback> successCallback, PassRefPtr<RTCPeerConnectionErrorCallback> errorCallback, const Dictionary& mediaConstraints, ExceptionCode& ec) +ExceptionOr<Ref<RTCRtpTransceiver>> RTCPeerConnection::addTransceiver(Ref<MediaStreamTrack>&& track, const RtpTransceiverInit& init) { - if (m_signalingState == SignalingStateClosed) { - ec = INVALID_STATE_ERR; - return; - } + if (m_signalingState == SignalingState::Closed) + return Exception { INVALID_STATE_ERR }; - if (!successCallback) { - ec = TYPE_MISMATCH_ERR; - return; - } + String transceiverMid = RTCRtpTransceiver::getNextMid(); + const String& trackKind = track->kind(); + const String& trackId = track->id(); - RefPtr<MediaConstraints> constraints = MediaConstraintsImpl::create(mediaConstraints, ec); - if (ec) - return; + auto sender = RTCRtpSender::create(WTFMove(track), Vector<String>(), *this); + auto receiver = m_backend->createReceiver(transceiverMid, trackKind, trackId); + auto transceiver = RTCRtpTransceiver::create(WTFMove(sender), WTFMove(receiver)); + transceiver->setProvisionalMid(transceiverMid); - RefPtr<RTCSessionDescriptionRequestImpl> request = RTCSessionDescriptionRequestImpl::create(scriptExecutionContext(), successCallback, errorCallback); - m_peerHandler->createAnswer(request.release(), constraints.release()); + completeAddTransceiver(transceiver, init); + return WTFMove(transceiver); } -bool RTCPeerConnection::checkStateForLocalDescription(RTCSessionDescription* localDescription) +ExceptionOr<Ref<RTCRtpTransceiver>> RTCPeerConnection::addTransceiver(const String& kind, const RtpTransceiverInit& init) { - if (localDescription->type() == "offer") - return m_signalingState == SignalingStateStable || m_signalingState == SignalingStateHaveLocalOffer; - if (localDescription->type() == "answer") - return m_signalingState == SignalingStateHaveRemoteOffer || m_signalingState == SignalingStateHaveLocalPrAnswer; - if (localDescription->type() == "pranswer") - return m_signalingState == SignalingStateHaveLocalPrAnswer || m_signalingState == SignalingStateHaveRemoteOffer; + if (m_signalingState == SignalingState::Closed) + return Exception { INVALID_STATE_ERR }; - return false; -} + if (kind != "audio" && kind != "video") + return Exception { TypeError }; -bool RTCPeerConnection::checkStateForRemoteDescription(RTCSessionDescription* remoteDescription) -{ - if (remoteDescription->type() == "offer") - return m_signalingState == SignalingStateStable || m_signalingState == SignalingStateHaveRemoteOffer; - if (remoteDescription->type() == "answer") - return m_signalingState == SignalingStateHaveLocalOffer || m_signalingState == SignalingStateHaveRemotePrAnswer; - if (remoteDescription->type() == "pranswer") - return m_signalingState == SignalingStateHaveRemotePrAnswer || m_signalingState == SignalingStateHaveLocalOffer; + String transceiverMid = RTCRtpTransceiver::getNextMid(); + String trackId = createCanonicalUUIDString(); - return false; + auto sender = RTCRtpSender::create(kind, Vector<String>(), *this); + auto receiver = m_backend->createReceiver(transceiverMid, kind, trackId); + auto transceiver = RTCRtpTransceiver::create(WTFMove(sender), WTFMove(receiver)); + transceiver->setProvisionalMid(transceiverMid); + + completeAddTransceiver(transceiver, init); + return WTFMove(transceiver); } -void RTCPeerConnection::setLocalDescription(PassRefPtr<RTCSessionDescription> prpSessionDescription, PassRefPtr<VoidCallback> successCallback, PassRefPtr<RTCPeerConnectionErrorCallback> errorCallback, ExceptionCode& ec) +void RTCPeerConnection::completeAddTransceiver(RTCRtpTransceiver& transceiver, const RtpTransceiverInit& init) { - if (m_signalingState == SignalingStateClosed) { - ec = INVALID_STATE_ERR; - return; - } + transceiver.setDirection(static_cast<RTCRtpTransceiver::Direction>(init.direction)); - RefPtr<RTCSessionDescription> sessionDescription = prpSessionDescription; - if (!sessionDescription) { - ec = TYPE_MISMATCH_ERR; - return; - } + m_transceiverSet->append(transceiver); + m_backend->markAsNeedingNegotiation(); +} - if (!checkStateForLocalDescription(sessionDescription.get())) { - RefPtr<DOMError> error = DOMError::create(RTCPeerConnectionHandler::invalidSessionDescriptionErrorName()); - callOnMainThread(bind(&RTCPeerConnectionErrorCallback::handleEvent, errorCallback.get(), error.release())); +void RTCPeerConnection::queuedCreateOffer(RTCOfferOptions&& options, SessionDescriptionPromise&& promise) +{ + if (m_signalingState == SignalingState::Closed) { + promise.reject(INVALID_STATE_ERR); return; } - RefPtr<RTCVoidRequestImpl> request = RTCVoidRequestImpl::create(scriptExecutionContext(), successCallback, errorCallback); - m_peerHandler->setLocalDescription(request.release(), sessionDescription->descriptor()); + m_backend->createOffer(WTFMove(options), WTFMove(promise)); } -PassRefPtr<RTCSessionDescription> RTCPeerConnection::localDescription(ExceptionCode& ec) +void RTCPeerConnection::queuedCreateAnswer(RTCAnswerOptions&& options, SessionDescriptionPromise&& promise) { - RefPtr<RTCSessionDescriptionDescriptor> descriptor = m_peerHandler->localDescription(); - if (!descriptor) { - ec = INVALID_STATE_ERR; - return nullptr; + if (m_signalingState == SignalingState::Closed) { + promise.reject(INVALID_STATE_ERR); + return; } - RefPtr<RTCSessionDescription> sessionDescription = RTCSessionDescription::create(descriptor.release()); - return sessionDescription.release(); + m_backend->createAnswer(WTFMove(options), WTFMove(promise)); } -void RTCPeerConnection::setRemoteDescription(PassRefPtr<RTCSessionDescription> prpSessionDescription, PassRefPtr<VoidCallback> successCallback, PassRefPtr<RTCPeerConnectionErrorCallback> errorCallback, ExceptionCode& ec) +void RTCPeerConnection::queuedSetLocalDescription(RTCSessionDescription& description, DOMPromise<void>&& promise) { - if (m_signalingState == SignalingStateClosed) { - ec = INVALID_STATE_ERR; + if (m_signalingState == SignalingState::Closed) { + promise.reject(INVALID_STATE_ERR); return; } - RefPtr<RTCSessionDescription> sessionDescription = prpSessionDescription; - if (!sessionDescription) { - ec = TYPE_MISMATCH_ERR; - return; - } - - if (!checkStateForRemoteDescription(sessionDescription.get())) { - RefPtr<DOMError> error = DOMError::create(RTCPeerConnectionHandler::invalidSessionDescriptionErrorName()); - callOnMainThread(bind(&RTCPeerConnectionErrorCallback::handleEvent, errorCallback.get(), error.release())); - return; - } + m_backend->setLocalDescription(description, WTFMove(promise)); +} - RefPtr<RTCVoidRequestImpl> request = RTCVoidRequestImpl::create(scriptExecutionContext(), successCallback, errorCallback); - m_peerHandler->setRemoteDescription(request.release(), sessionDescription->descriptor()); +RefPtr<RTCSessionDescription> RTCPeerConnection::localDescription() const +{ + return m_backend->localDescription(); } -PassRefPtr<RTCSessionDescription> RTCPeerConnection::remoteDescription(ExceptionCode& ec) +RefPtr<RTCSessionDescription> RTCPeerConnection::currentLocalDescription() const { - RefPtr<RTCSessionDescriptionDescriptor> descriptor = m_peerHandler->remoteDescription(); - if (!descriptor) { - ec = INVALID_STATE_ERR; - return nullptr; - } + return m_backend->currentLocalDescription(); +} - RefPtr<RTCSessionDescription> desc = RTCSessionDescription::create(descriptor.release()); - return desc.release(); +RefPtr<RTCSessionDescription> RTCPeerConnection::pendingLocalDescription() const +{ + return m_backend->pendingLocalDescription(); } -void RTCPeerConnection::updateIce(const Dictionary& rtcConfiguration, const Dictionary& mediaConstraints, ExceptionCode& ec) +void RTCPeerConnection::queuedSetRemoteDescription(RTCSessionDescription& description, DOMPromise<void>&& promise) { - if (m_signalingState == SignalingStateClosed) { - ec = INVALID_STATE_ERR; + if (m_signalingState == SignalingState::Closed) { + promise.reject(INVALID_STATE_ERR); return; } - RefPtr<RTCConfiguration> configuration = parseConfiguration(rtcConfiguration, ec); - if (ec) - return; + m_backend->setRemoteDescription(description, WTFMove(promise)); +} - RefPtr<MediaConstraints> constraints = MediaConstraintsImpl::create(mediaConstraints, ec); - if (ec) - return; +RefPtr<RTCSessionDescription> RTCPeerConnection::remoteDescription() const +{ + return m_backend->remoteDescription(); +} - bool valid = m_peerHandler->updateIce(configuration, constraints); - if (!valid) - ec = SYNTAX_ERR; +RefPtr<RTCSessionDescription> RTCPeerConnection::currentRemoteDescription() const +{ + return m_backend->currentRemoteDescription(); } -void RTCPeerConnection::addIceCandidate(RTCIceCandidate* iceCandidate, PassRefPtr<VoidCallback> successCallback, PassRefPtr<RTCPeerConnectionErrorCallback> errorCallback, ExceptionCode& ec) +RefPtr<RTCSessionDescription> RTCPeerConnection::pendingRemoteDescription() const { - if (m_signalingState == SignalingStateClosed) { - ec = INVALID_STATE_ERR; - return; - } + return m_backend->pendingRemoteDescription(); +} - if (!iceCandidate || !successCallback || !errorCallback) { - ec = TYPE_MISMATCH_ERR; +void RTCPeerConnection::queuedAddIceCandidate(RTCIceCandidate& rtcCandidate, DOMPromise<void>&& promise) +{ + if (m_signalingState == SignalingState::Closed) { + promise.reject(INVALID_STATE_ERR); return; } - RefPtr<RTCVoidRequestImpl> request = RTCVoidRequestImpl::create(scriptExecutionContext(), successCallback, errorCallback); - - bool implemented = m_peerHandler->addIceCandidate(request.release(), iceCandidate->descriptor()); - if (!implemented) - ec = SYNTAX_ERR; + m_backend->addIceCandidate(rtcCandidate, WTFMove(promise)); } String RTCPeerConnection::signalingState() const { switch (m_signalingState) { - case SignalingStateStable: + case SignalingState::Stable: return ASCIILiteral("stable"); - case SignalingStateHaveLocalOffer: + case SignalingState::HaveLocalOffer: return ASCIILiteral("have-local-offer"); - case SignalingStateHaveRemoteOffer: + case SignalingState::HaveRemoteOffer: return ASCIILiteral("have-remote-offer"); - case SignalingStateHaveLocalPrAnswer: + case SignalingState::HaveLocalPrAnswer: return ASCIILiteral("have-local-pranswer"); - case SignalingStateHaveRemotePrAnswer: + case SignalingState::HaveRemotePrAnswer: return ASCIILiteral("have-remote-pranswer"); - case SignalingStateClosed: + case SignalingState::Closed: return ASCIILiteral("closed"); } @@ -369,11 +313,11 @@ String RTCPeerConnection::signalingState() const String RTCPeerConnection::iceGatheringState() const { switch (m_iceGatheringState) { - case IceGatheringStateNew: + case IceGatheringState::New: return ASCIILiteral("new"); - case IceGatheringStateGathering: + case IceGatheringState::Gathering: return ASCIILiteral("gathering"); - case IceGatheringStateComplete: + case IceGatheringState::Complete: return ASCIILiteral("complete"); } @@ -384,19 +328,19 @@ String RTCPeerConnection::iceGatheringState() const String RTCPeerConnection::iceConnectionState() const { switch (m_iceConnectionState) { - case IceConnectionStateNew: + case IceConnectionState::New: return ASCIILiteral("new"); - case IceConnectionStateChecking: + case IceConnectionState::Checking: return ASCIILiteral("checking"); - case IceConnectionStateConnected: + case IceConnectionState::Connected: return ASCIILiteral("connected"); - case IceConnectionStateCompleted: + case IceConnectionState::Completed: return ASCIILiteral("completed"); - case IceConnectionStateFailed: + case IceConnectionState::Failed: return ASCIILiteral("failed"); - case IceConnectionStateDisconnected: + case IceConnectionState::Disconnected: return ASCIILiteral("disconnected"); - case IceConnectionStateClosed: + case IceConnectionState::Closed: return ASCIILiteral("closed"); } @@ -404,295 +348,145 @@ String RTCPeerConnection::iceConnectionState() const return String(); } -void RTCPeerConnection::addStream(PassRefPtr<MediaStream> prpStream, const Dictionary& mediaConstraints, ExceptionCode& ec) -{ - if (m_signalingState == SignalingStateClosed) { - ec = INVALID_STATE_ERR; - return; - } - - RefPtr<MediaStream> stream = prpStream; - if (!stream) { - ec = TYPE_MISMATCH_ERR; - return; - } - - if (m_localStreams.contains(stream)) - return; - - RefPtr<MediaConstraints> constraints = MediaConstraintsImpl::create(mediaConstraints, ec); - if (ec) - return; - - bool valid = m_peerHandler->addStream(stream->privateStream(), constraints); - if (!valid) - ec = SYNTAX_ERR; - else { - m_localStreams.append(stream); - stream->addObserver(this); - } -} - -void RTCPeerConnection::removeStream(PassRefPtr<MediaStream> prpStream, ExceptionCode& ec) -{ - if (m_signalingState == SignalingStateClosed) { - ec = INVALID_STATE_ERR; - return; - } - - if (!prpStream) { - ec = TYPE_MISMATCH_ERR; - return; - } - - RefPtr<MediaStream> stream = prpStream; - - size_t pos = m_localStreams.find(stream); - if (pos == notFound) - return; - - m_localStreams.remove(pos); - stream->removeObserver(this); - m_peerHandler->removeStream(stream->privateStream()); -} - -MediaStreamVector RTCPeerConnection::getLocalStreams() const -{ - return m_localStreams; -} - -MediaStreamVector RTCPeerConnection::getRemoteStreams() const -{ - return m_remoteStreams; -} - -MediaStream* RTCPeerConnection::getStreamById(const String& streamId) -{ - for (MediaStreamVector::iterator iter = m_localStreams.begin(); iter != m_localStreams.end(); ++iter) { - if ((*iter)->id() == streamId) - return iter->get(); - } - - for (MediaStreamVector::iterator iter = m_remoteStreams.begin(); iter != m_remoteStreams.end(); ++iter) { - if ((*iter)->id() == streamId) - return iter->get(); +ExceptionOr<void> RTCPeerConnection::setConfiguration(RTCConfiguration&& configuration) +{ + if (m_signalingState == SignalingState::Closed) + return Exception { INVALID_STATE_ERR }; + + Vector<MediaEndpointConfiguration::IceServerInfo> servers; + if (configuration.iceServers) { + servers.reserveInitialCapacity(configuration.iceServers->size()); + for (auto& server : configuration.iceServers.value()) { + Vector<URL> serverURLs; + WTF::switchOn(server.urls, + [&serverURLs] (const String& string) { + serverURLs.reserveInitialCapacity(1); + serverURLs.uncheckedAppend(URL { URL { }, string }); + }, + [&serverURLs] (const Vector<String>& vector) { + serverURLs.reserveInitialCapacity(vector.size()); + for (auto& string : vector) + serverURLs.uncheckedAppend(URL { URL { }, string }); + } + ); + for (auto& serverURL : serverURLs) { + if (!(serverURL.protocolIs("turn") || serverURL.protocolIs("turns") || serverURL.protocolIs("stun"))) + return Exception { INVALID_ACCESS_ERR }; + } + servers.uncheckedAppend({ WTFMove(serverURLs), server.credential, server.username }); + } } - return nullptr; + m_backend->setConfiguration({ WTFMove(servers), configuration.iceTransportPolicy, configuration.bundlePolicy }); + m_configuration = WTFMove(configuration); + return { }; } -void RTCPeerConnection::getStats(PassRefPtr<RTCStatsCallback> successCallback, PassRefPtr<MediaStreamTrack> selector) +void RTCPeerConnection::getStats(MediaStreamTrack* selector, Ref<DeferredPromise>&& promise) { - RefPtr<RTCStatsRequestImpl> statsRequest = RTCStatsRequestImpl::create(scriptExecutionContext(), successCallback, selector); - // FIXME: Add passing selector as part of the statsRequest. - m_peerHandler->getStats(statsRequest.release()); + m_backend->getStats(selector, WTFMove(promise)); } -PassRefPtr<RTCDataChannel> RTCPeerConnection::createDataChannel(String label, const Dictionary& options, ExceptionCode& ec) +ExceptionOr<Ref<RTCDataChannel>> RTCPeerConnection::createDataChannel(ScriptExecutionContext& context, String&& label, RTCDataChannelInit&& options) { - if (m_signalingState == SignalingStateClosed) { - ec = INVALID_STATE_ERR; - return nullptr; - } + if (m_signalingState == SignalingState::Closed) + return Exception { INVALID_STATE_ERR }; - RefPtr<RTCDataChannel> channel = RTCDataChannel::create(scriptExecutionContext(), m_peerHandler.get(), label, options, ec); - if (ec) - return nullptr; + // FIXME: Check options + auto channelHandler = m_backend->createDataChannelHandler(label, options); + if (!channelHandler) + return Exception { NOT_SUPPORTED_ERR }; - m_dataChannels.append(channel); - return channel.release(); + return RTCDataChannel::create(context, WTFMove(channelHandler), WTFMove(label), WTFMove(options)); } -bool RTCPeerConnection::hasLocalStreamWithTrackId(const String& trackId) +void RTCPeerConnection::close() { - for (MediaStreamVector::iterator iter = m_localStreams.begin(); iter != m_localStreams.end(); ++iter) { - if ((*iter)->getTrackById(trackId)) - return true; - } - return false; -} - -PassRefPtr<RTCDTMFSender> RTCPeerConnection::createDTMFSender(PassRefPtr<MediaStreamTrack> prpTrack, ExceptionCode& ec) -{ - if (m_signalingState == SignalingStateClosed) { - ec = INVALID_STATE_ERR; - return nullptr; - } - - if (!prpTrack) { - ec = TypeError; - return nullptr; - } - - RefPtr<MediaStreamTrack> track = prpTrack; - - if (!hasLocalStreamWithTrackId(track->id())) { - ec = SYNTAX_ERR; - return nullptr; - } - - RefPtr<RTCDTMFSender> dtmfSender = RTCDTMFSender::create(scriptExecutionContext(), m_peerHandler.get(), track.release(), ec); - if (ec) - return nullptr; - return dtmfSender.release(); -} - -void RTCPeerConnection::close(ExceptionCode& ec) -{ - if (m_signalingState == SignalingStateClosed) { - ec = INVALID_STATE_ERR; + if (m_signalingState == SignalingState::Closed) return; - } - m_peerHandler->stop(); + m_backend->stop(); - changeIceConnectionState(IceConnectionStateClosed); - changeIceGatheringState(IceGatheringStateComplete); - changeSignalingState(SignalingStateClosed); -} + m_iceConnectionState = IceConnectionState::Closed; + m_signalingState = SignalingState::Closed; -void RTCPeerConnection::negotiationNeeded() -{ - scheduleDispatchEvent(Event::create(eventNames().negotiationneededEvent, false, false)); -} - -void RTCPeerConnection::didGenerateIceCandidate(PassRefPtr<RTCIceCandidateDescriptor> iceCandidateDescriptor) -{ - ASSERT(scriptExecutionContext()->isContextThread()); - if (!iceCandidateDescriptor) - scheduleDispatchEvent(RTCIceCandidateEvent::create(false, false, 0)); - else { - RefPtr<RTCIceCandidate> iceCandidate = RTCIceCandidate::create(iceCandidateDescriptor); - scheduleDispatchEvent(RTCIceCandidateEvent::create(false, false, iceCandidate.release())); - } + for (RTCRtpSender& sender : m_transceiverSet->senders()) + sender.stop(); } -void RTCPeerConnection::didChangeSignalingState(SignalingState newState) +void RTCPeerConnection::emulatePlatformEvent(const String& action) { - ASSERT(scriptExecutionContext()->isContextThread()); - changeSignalingState(newState); + m_backend->emulatePlatformEvent(action); } -void RTCPeerConnection::didChangeIceGatheringState(IceGatheringState newState) +void RTCPeerConnection::stop() { - ASSERT(scriptExecutionContext()->isContextThread()); - changeIceGatheringState(newState); + close(); } -void RTCPeerConnection::didChangeIceConnectionState(IceConnectionState newState) +const char* RTCPeerConnection::activeDOMObjectName() const { - ASSERT(scriptExecutionContext()->isContextThread()); - changeIceConnectionState(newState); + return "RTCPeerConnection"; } -void RTCPeerConnection::didAddRemoteStream(PassRefPtr<MediaStreamPrivate> privateStream) +bool RTCPeerConnection::canSuspendForDocumentSuspension() const { - ASSERT(scriptExecutionContext()->isContextThread()); - - if (m_signalingState == SignalingStateClosed) - return; - - RefPtr<MediaStream> stream = MediaStream::create(*scriptExecutionContext(), privateStream); - m_remoteStreams.append(stream); - - scheduleDispatchEvent(MediaStreamEvent::create(eventNames().addstreamEvent, false, false, stream.release())); + // FIXME: We should try and do better here. + return false; } -void RTCPeerConnection::didRemoveRemoteStream(MediaStreamPrivate* privateStream) +void RTCPeerConnection::addTransceiver(Ref<RTCRtpTransceiver>&& transceiver) { - ASSERT(scriptExecutionContext()->isContextThread()); - ASSERT(privateStream->client()); - - // FIXME: this class shouldn't know that the private stream client is a MediaStream! - RefPtr<MediaStream> stream = static_cast<MediaStream*>(privateStream->client()); - stream->setEnded(); - - if (m_signalingState == SignalingStateClosed) - return; - - size_t pos = m_remoteStreams.find(stream); - ASSERT(pos != notFound); - m_remoteStreams.remove(pos); - - scheduleDispatchEvent(MediaStreamEvent::create(eventNames().removestreamEvent, false, false, stream.release())); + m_transceiverSet->append(WTFMove(transceiver)); } -void RTCPeerConnection::didAddRemoteDataChannel(std::unique_ptr<RTCDataChannelHandler> handler) +void RTCPeerConnection::setSignalingState(SignalingState newState) { - ASSERT(scriptExecutionContext()->isContextThread()); - - if (m_signalingState == SignalingStateClosed) - return; - - RefPtr<RTCDataChannel> channel = RTCDataChannel::create(scriptExecutionContext(), std::move(handler)); - m_dataChannels.append(channel); - - scheduleDispatchEvent(RTCDataChannelEvent::create(eventNames().datachannelEvent, false, false, channel.release())); + m_signalingState = newState; } -void RTCPeerConnection::stop() +void RTCPeerConnection::updateIceGatheringState(IceGatheringState newState) { - if (m_stopped) - return; - - m_stopped = true; - m_iceConnectionState = IceConnectionStateClosed; - m_signalingState = SignalingStateClosed; + scriptExecutionContext()->postTask([=](ScriptExecutionContext&) { + if (m_signalingState == SignalingState::Closed || m_iceGatheringState == newState) + return; - Vector<RefPtr<RTCDataChannel>>::iterator i = m_dataChannels.begin(); - for (; i != m_dataChannels.end(); ++i) - (*i)->stop(); + m_iceGatheringState = newState; + dispatchEvent(Event::create(eventNames().icegatheringstatechangeEvent, false, false)); + }); } -void RTCPeerConnection::didAddOrRemoveTrack() +void RTCPeerConnection::updateIceConnectionState(IceConnectionState newState) { - negotiationNeeded(); -} + scriptExecutionContext()->postTask([=](ScriptExecutionContext&) { + if (m_signalingState == SignalingState::Closed || m_iceConnectionState == newState) + return; -void RTCPeerConnection::changeSignalingState(SignalingState signalingState) -{ - if (m_signalingState != SignalingStateClosed && m_signalingState != signalingState) { - m_signalingState = signalingState; - scheduleDispatchEvent(Event::create(eventNames().signalingstatechangeEvent, false, false)); - } + m_iceConnectionState = newState; + dispatchEvent(Event::create(eventNames().iceconnectionstatechangeEvent, false, false)); + }); } -void RTCPeerConnection::changeIceGatheringState(IceGatheringState iceGatheringState) +void RTCPeerConnection::scheduleNegotiationNeededEvent() { - m_iceGatheringState = iceGatheringState; -} - -void RTCPeerConnection::changeIceConnectionState(IceConnectionState iceConnectionState) -{ - if (m_iceConnectionState != IceConnectionStateClosed && m_iceConnectionState != iceConnectionState) { - m_iceConnectionState = iceConnectionState; - scheduleDispatchEvent(Event::create(eventNames().iceconnectionstatechangeEvent, false, false)); - } + scriptExecutionContext()->postTask([=](ScriptExecutionContext&) { + if (m_backend->isNegotiationNeeded()) { + m_backend->clearNegotiationNeededState(); + dispatchEvent(Event::create(eventNames().negotiationneededEvent, false, false)); + } + }); } -void RTCPeerConnection::scheduleDispatchEvent(PassRefPtr<Event> event) +void RTCPeerConnection::fireEvent(Event& event) { - m_scheduledEvents.append(event); - - if (!m_scheduledEventTimer.isActive()) - m_scheduledEventTimer.startOneShot(0); + dispatchEvent(event); } -void RTCPeerConnection::scheduledEventTimerFired(Timer<RTCPeerConnection>*) +void RTCPeerConnection::replaceTrack(RTCRtpSender& sender, RefPtr<MediaStreamTrack>&& withTrack, DOMPromise<void>&& promise) { - if (m_stopped) - return; - - Vector<RefPtr<Event>> events; - events.swap(m_scheduledEvents); - - Vector<RefPtr<Event>>::iterator it = events.begin(); - for (; it != events.end(); ++it) - dispatchEvent((*it).release()); - - events.clear(); + m_backend->replaceTrack(sender, WTFMove(withTrack), WTFMove(promise)); } } // namespace WebCore -#endif // ENABLE(MEDIA_STREAM) +#endif // ENABLE(WEB_RTC) |