diff --git a/Source/WebCore/CMakeLists.txt b/Source/WebCore/CMakeLists.txt index 7c511f56228be..2746db43ea782 100644 --- a/Source/WebCore/CMakeLists.txt +++ b/Source/WebCore/CMakeLists.txt @@ -227,7 +227,6 @@ set(WebCore_NON_SVG_IDL_FILES Modules/mediastream/MediaSourceStates.idl Modules/mediastream/MediaStream.idl Modules/mediastream/MediaStreamCapabilities.idl - Modules/mediastream/MediaStreamEvent.idl Modules/mediastream/MediaStreamTrack.idl Modules/mediastream/MediaStreamTrackEvent.idl Modules/mediastream/MediaStreamTrackSourcesCallback.idl @@ -249,11 +248,14 @@ set(WebCore_NON_SVG_IDL_FILES Modules/mediastream/RTCIceServer.idl Modules/mediastream/RTCPeerConnection.idl Modules/mediastream/RTCPeerConnectionErrorCallback.idl + Modules/mediastream/RTCRtpReceiver.idl + Modules/mediastream/RTCRtpSender.idl Modules/mediastream/RTCSessionDescription.idl Modules/mediastream/RTCSessionDescriptionCallback.idl Modules/mediastream/RTCStatsCallback.idl Modules/mediastream/RTCStatsReport.idl Modules/mediastream/RTCStatsResponse.idl + Modules/mediastream/RTCTrackEvent.idl Modules/mediastream/SourceInfo.idl Modules/navigatorcontentutils/NavigatorContentUtils.idl @@ -891,10 +893,10 @@ set(WebCore_SOURCES Modules/mediastream/MediaConstraintsImpl.cpp Modules/mediastream/MediaDeviceInfo.cpp Modules/mediastream/MediaDevices.cpp + Modules/mediastream/MediaEndpointPeerConnection.cpp Modules/mediastream/MediaSourceStates.cpp Modules/mediastream/MediaStream.cpp Modules/mediastream/MediaStreamCapabilities.cpp - Modules/mediastream/MediaStreamEvent.cpp Modules/mediastream/MediaStreamRegistry.cpp Modules/mediastream/MediaStreamTrack.cpp Modules/mediastream/MediaStreamTrackEvent.cpp @@ -904,6 +906,7 @@ set(WebCore_SOURCES Modules/mediastream/MediaTrackConstraints.cpp Modules/mediastream/NavigatorMediaDevices.cpp Modules/mediastream/NavigatorUserMediaError.cpp + Modules/mediastream/RTCConfiguration.cpp Modules/mediastream/RTCDTMFSender.cpp Modules/mediastream/RTCDTMFToneChangeEvent.cpp Modules/mediastream/RTCDataChannel.cpp @@ -912,16 +915,23 @@ set(WebCore_SOURCES Modules/mediastream/RTCIceCandidateEvent.cpp Modules/mediastream/RTCOfferAnswerOptions.cpp Modules/mediastream/RTCPeerConnection.cpp + Modules/mediastream/RTCRtpReceiver.cpp + Modules/mediastream/RTCRtpSender.cpp + Modules/mediastream/RTCRtpSenderReceiverBase.cpp Modules/mediastream/RTCSessionDescription.cpp - Modules/mediastream/RTCSessionDescriptionRequestImpl.cpp + # Modules/mediastream/RTCSessionDescriptionRequestImpl.cpp Modules/mediastream/RTCStatsReport.cpp Modules/mediastream/RTCStatsRequestImpl.cpp Modules/mediastream/RTCStatsResponse.cpp + Modules/mediastream/RTCTrackEvent.cpp Modules/mediastream/RTCVoidRequestImpl.cpp Modules/mediastream/SourceInfo.cpp Modules/mediastream/UserMediaController.cpp Modules/mediastream/UserMediaRequest.cpp + + + Modules/navigatorcontentutils/NavigatorContentUtils.cpp Modules/notifications/DOMWindowNotifications.cpp @@ -2228,6 +2238,8 @@ set(WebCore_SOURCES platform/graphics/transforms/TranslateTransformOperation.cpp platform/mediastream/MediaDevicesPrivate.cpp + platform/mediastream/MediaEndpointConfigurationConversions.cpp + platform/mediastream/MediaEndpointInit.cpp platform/mediastream/MediaStreamPrivate.cpp platform/mediastream/MediaStreamTrackPrivate.cpp platform/mediastream/RTCIceCandidateDescriptor.cpp diff --git a/Source/WebCore/DerivedSources.make b/Source/WebCore/DerivedSources.make index 91cc6226aa677..51a457aa4b4ca 100644 --- a/Source/WebCore/DerivedSources.make +++ b/Source/WebCore/DerivedSources.make @@ -149,6 +149,8 @@ NON_SVG_BINDING_IDLS = \ $(WebCore)/Modules/mediastream/RTCIceServer.idl \ $(WebCore)/Modules/mediastream/RTCPeerConnection.idl \ $(WebCore)/Modules/mediastream/RTCPeerConnectionErrorCallback.idl \ + $(WebCore)/Modules/mediastream/RTCRtpReceiver.idl \ + $(WebCore)/Modules/mediastream/RTCRtpSender.idl \ $(WebCore)/Modules/mediastream/RTCSessionDescription.idl \ $(WebCore)/Modules/mediastream/RTCSessionDescriptionCallback.idl \ $(WebCore)/Modules/mediastream/RTCStatsCallback.idl \ diff --git a/Source/WebCore/Modules/mediastream/MediaEndpointPeerConnection.cpp b/Source/WebCore/Modules/mediastream/MediaEndpointPeerConnection.cpp new file mode 100644 index 0000000000000..a40709221c870 --- /dev/null +++ b/Source/WebCore/Modules/mediastream/MediaEndpointPeerConnection.cpp @@ -0,0 +1,735 @@ +/* + * Copyright (C) 2015 Ericsson AB. All rights reserved. + * + * 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. + * 3. Neither the name of Ericsson nor the names of its contributors + * may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT + * OWNER OR 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" + +#if ENABLE(MEDIA_STREAM) +#include "MediaEndpointPeerConnection.h" + +#include "CryptoDigest.h" +#include "DOMError.h" +#include "MediaEndpointConfigurationConversions.h" +#include "MediaStreamTrack.h" +#include "PeerConnectionBackend.h" +#include "PeerMediaDescription.h" +#include "RTCConfiguration.h" +#include "RTCIceCandidate.h" +#include "RTCIceCandidateEvent.h" +#include "RTCOfferAnswerOptions.h" +#include "RTCSessionDescription.h" +#include "RTCRtpReceiver.h" +#include "RTCRtpSender.h" +#include "RTCTrackEvent.h" +#include "UUID.h" +#include + +// FIXME: Headers for sdp.js supported SDP conversion is kept on the side for now +#include "Document.h" +#include "Frame.h" +#include "JSDOMWindow.h" +#include "ScriptController.h" +#include "ScriptGlobalObject.h" +#include "ScriptSourceCode.h" +#include "SDPScriptResource.h" +#include + +namespace WebCore { + +using namespace PeerConnectionStates; + +static std::unique_ptr createMediaEndpointPeerConnection(PeerConnectionBackendClient* client) +{ + return std::unique_ptr(new MediaEndpointPeerConnection(client)); +} + +CreatePeerConnectionBackend PeerConnectionBackend::create = createMediaEndpointPeerConnection; + +static String randomString(size_t length) +{ + const size_t size = ceil(length * 3 / 4); + unsigned char randomValues[size]; + cryptographicallyRandomValues(randomValues, size); + return base64Encode(randomValues, size); +} + +static RefPtr createMediaEndpointInit(RTCConfiguration& rtcConfig) +{ + Vector> iceServers; + for (auto& server : rtcConfig.iceServers()) + iceServers.append(IceServerInfo::create(server->urls(), server->credential(), server->username())); + + return MediaEndpointInit::create(iceServers, rtcConfig.iceTransportPolicy(), rtcConfig.bundlePolicy()); +} + +MediaEndpointPeerConnection::MediaEndpointPeerConnection(PeerConnectionBackendClient* client) + : m_client(client) + , m_cname(randomString(16)) + , m_iceUfrag(randomString(4)) + , m_icePassword(randomString(22)) +{ + m_mediaEndpoint = MediaEndpoint::create(this); + ASSERT(m_mediaEndpoint); +} + +MediaEndpointPeerConnection::~MediaEndpointPeerConnection() +{ +} + +static RefPtr takeFirstSenderOfType(Vector>& senders, const String& type) +{ + for (unsigned i = 0; i < senders.size(); ++i) { + if (senders[i]->track()->kind() == type) { + RefPtr sender = senders[i]; + senders.remove(i); + return sender; + } + } + return nullptr; +} + +// FIXME: This information should be fetched from the platform +static Vector> createDefaultPayloads(const String& type) +{ + Vector> payloads; + RefPtr payload; + + if (type == "audio") { + payload = MediaPayload::create(); + payload->setType(111); + payload->setEncodingName("OPUS"); + payload->setClockRate(48000); + payload->setChannels(2); + payloads.append(payload); + + payload = MediaPayload::create(); + payload->setType(8); + payload->setEncodingName("PCMA"); + payload->setClockRate(8000); + payload->setChannels(1); + payloads.append(payload); + + payload = MediaPayload::create(); + payload->setType(0); + payload->setEncodingName("PCMU"); + payload->setClockRate(8000); + payload->setChannels(1); + payloads.append(payload); + } else { + // payload = MediaPayload::create(); + // payload->setType(103); + // payload->setEncodingName("H264"); + // payload->setClockRate(90000); + // payload->setCcmfir(true); + // payload->setNackpli(true); + // payload->addParameter("packetizationMode", 1); + // payloads.append(payload); + + payload = MediaPayload::create(); + payload->setType(100); + payload->setEncodingName("VP8"); + payload->setClockRate(90000); + payload->setCcmfir(true); + payload->setNackpli(true); + payload->setNack(true); + payloads.append(payload); + + payload = MediaPayload::create(); + payload->setType(120); + payload->setEncodingName("RTX"); + payload->setClockRate(90000); + payload->addParameter("apt", 100); + payload->addParameter("rtxTime", 200); + payloads.append(payload); + } + + return payloads; +} + +static void updateMediaDescriptionsWithSenders(const Vector>& mediaDescriptions, Vector>& senders) +{ + // Remove any sender(s) from the senders list that already have their tracks represented by a media + // description. Mark media descriptions that don't have a sender/track (anymore) as "available". + for (auto& mdesc : mediaDescriptions) { + const String& mdescTrackId = mdesc->mediaStreamTrackId(); + bool foundSender = senders.removeFirstMatching([mdescTrackId](const RefPtr& sender) -> bool { + return sender->track()->id() == mdescTrackId; + }); + if (!foundSender) { + mdesc->setMediaStreamId(emptyString()); + mdesc->setMediaStreamTrackId(emptyString()); + mdesc->clearSsrcs(); + } + } + + // Remove any sender(s) from the senders list that can be matched (by track type) to an "available" + // media description. Mark media descriptions that don't get matched with a sender as receive only. + for (auto& mdesc : mediaDescriptions) { + if (mdesc->mediaStreamTrackId() != emptyString()) + continue; + + RefPtr sender = takeFirstSenderOfType(senders, mdesc->type()); + if (sender) { + // FIXME: what else needs to be updated to reuse a media description? + mdesc->setMediaStreamId(sender->mediaStreamId()); + mdesc->setMediaStreamTrackId(sender->track()->id()); + mdesc->addSsrc(cryptographicallyRandomNumber()); + mdesc->setMode("sendrecv"); + } else + mdesc->setMode("recvonly"); + } +} + +void MediaEndpointPeerConnection::enqueueOperation(std::function operation) +{ + m_operationsQueue.append(operation); + if (m_operationsQueue.size() == 1) + callOnMainThread(m_operationsQueue[0]); +} + +void MediaEndpointPeerConnection::completeQueuedOperation() +{ + m_operationsQueue.remove(0); + if (!m_operationsQueue.isEmpty()) + callOnMainThread(m_operationsQueue[0]); +} + +void MediaEndpointPeerConnection::createOffer(const RefPtr& options, OfferAnswerResolveCallback resolveCallback, RejectCallback rejectCallback) +{ + RefPtr protectedOptions = options; + enqueueOperation([this, protectedOptions, resolveCallback, rejectCallback]() { + queuedCreateOffer(protectedOptions, resolveCallback, rejectCallback); + }); +} + +void MediaEndpointPeerConnection::queuedCreateOffer(const RefPtr& options, OfferAnswerResolveCallback resolveCallback, RejectCallback) +{ + RefPtr configurationSnapshot = m_localConfiguration ? + MediaEndpointConfigurationConversions::fromJSON(MediaEndpointConfigurationConversions::toJSON(m_localConfiguration.get())) : MediaEndpointConfiguration::create(); + + Vector> senders = m_client->getSenders(); + updateMediaDescriptionsWithSenders(configurationSnapshot->mediaDescriptions(), senders); + + // Add media descriptions for remaining senders. + for (auto& sender : senders) { + RefPtr mediaDescription = PeerMediaDescription::create(); + MediaStreamTrack* track = sender->track(); + + mediaDescription->setMediaStreamId(sender->mediaStreamId()); + mediaDescription->setMediaStreamTrackId(track->id()); + mediaDescription->setType(track->kind()); + mediaDescription->setMode("sendrecv"); + mediaDescription->setPayloads(createDefaultPayloads(track->kind())); + mediaDescription->setRtcpMux(true); + mediaDescription->setDtlsSetup("actpass"); + mediaDescription->setCname(m_cname); + mediaDescription->addSsrc(cryptographicallyRandomNumber()); + mediaDescription->setIceUfrag(m_iceUfrag); + mediaDescription->setIcePassword(m_icePassword); + + configurationSnapshot->addMediaDescription(WTF::move(mediaDescription)); + } + + int extraMediaDescriptionCount = options->offerToReceiveAudio() + options->offerToReceiveVideo(); + for (int i = 0; i < extraMediaDescriptionCount; ++i) { + String type = i < options->offerToReceiveAudio() ? "audio" : "video"; + RefPtr mediaDescription = PeerMediaDescription::create(); + + mediaDescription->setType(type); + mediaDescription->setMode("recvonly"); + mediaDescription->setPayloads(createDefaultPayloads(type)); + mediaDescription->setRtcpMux(true); + mediaDescription->setDtlsSetup("actpass"); + mediaDescription->setIceUfrag(m_iceUfrag); + mediaDescription->setIcePassword(m_icePassword); + + configurationSnapshot->addMediaDescription(WTF::move(mediaDescription)); + } + + String json = MediaEndpointConfigurationConversions::toJSON(configurationSnapshot.get()); + RefPtr offer = RTCSessionDescription::create("offer", toSDP(json)); + + resolveCallback(*offer); + completeQueuedOperation(); +} + +void MediaEndpointPeerConnection::createAnswer(const RefPtr& options, OfferAnswerResolveCallback resolveCallback, RejectCallback rejectCallback) +{ + RefPtr protectedOptions = options; + enqueueOperation([this, protectedOptions, resolveCallback, rejectCallback]() { + queuedCreateAnswer(protectedOptions, resolveCallback, rejectCallback); + }); +} + +void MediaEndpointPeerConnection::queuedCreateAnswer(const RefPtr&, OfferAnswerResolveCallback resolveCallback, RejectCallback) +{ + RefPtr configurationSnapshot = m_localConfiguration ? + MediaEndpointConfigurationConversions::fromJSON(MediaEndpointConfigurationConversions::toJSON(m_localConfiguration.get())) : MediaEndpointConfiguration::create(); + + for (unsigned i = 0; i < m_remoteConfiguration->mediaDescriptions().size(); ++i) { + RefPtr remoteMediaDescription = m_remoteConfiguration->mediaDescriptions()[i]; + RefPtr localMediaDescription; + + if (i < configurationSnapshot->mediaDescriptions().size()) + localMediaDescription = configurationSnapshot->mediaDescriptions()[i]; + else { + localMediaDescription = PeerMediaDescription::create(); + localMediaDescription->setType(remoteMediaDescription->type()); + localMediaDescription->setDtlsSetup(remoteMediaDescription->dtlsSetup() == "active" ? "passive" : "active"); + localMediaDescription->setCname(m_cname); + localMediaDescription->setIceUfrag(m_iceUfrag); + localMediaDescription->setIcePassword(m_icePassword); + + configurationSnapshot->addMediaDescription(localMediaDescription.copyRef()); + } + + localMediaDescription->setPayloads(remoteMediaDescription->payloads()); + + localMediaDescription->setRtcpMux(remoteMediaDescription->rtcpMux()); + + if (!localMediaDescription->ssrcs().size()) + localMediaDescription->addSsrc(cryptographicallyRandomNumber()); + + if (localMediaDescription->dtlsSetup() == "actpass") + localMediaDescription->setDtlsSetup("passive"); + } + + Vector> senders = m_client->getSenders(); + updateMediaDescriptionsWithSenders(configurationSnapshot->mediaDescriptions(), senders); + + String json = MediaEndpointConfigurationConversions::toJSON(configurationSnapshot.get()); + RefPtr answer = RTCSessionDescription::create("answer", toSDP(json)); + + resolveCallback(*answer); + completeQueuedOperation(); +} + +void MediaEndpointPeerConnection::setLocalDescription(RTCSessionDescription* description, PeerConnectionStates::SignalingState targetState, VoidResolveCallback resolveCallback, RejectCallback rejectCallback) +{ + RefPtr protectedDescription = description; + enqueueOperation([this, protectedDescription, targetState, resolveCallback, rejectCallback]() { + queuedSetLocalDescription(protectedDescription.get(), targetState, resolveCallback, rejectCallback); + }); +} + +void MediaEndpointPeerConnection::queuedSetLocalDescription(RTCSessionDescription* description, PeerConnectionStates::SignalingState targetState, VoidResolveCallback resolveCallback, RejectCallback rejectCallback) +{ + unsigned previousNumberOfMediaDescriptions = m_localConfiguration ? m_localConfiguration->mediaDescriptions().size() : 0; + + String json = fromSDP(description->sdp()); + m_localConfiguration = MediaEndpointConfigurationConversions::fromJSON(json); + m_localConfigurationType = description->type(); + + if (!m_localConfiguration) { + // FIXME: Error type? + RefPtr error = DOMError::create("InvalidSessionDescriptionError (unable to parse description)"); + rejectCallback(*error); + completeQueuedOperation(); + return; + } + + bool hasNewMediaDescriptions = m_localConfiguration->mediaDescriptions().size() > previousNumberOfMediaDescriptions; + bool isInitiator = m_localConfigurationType == "offer"; + + m_resolveSetLocalDescription = [this, targetState, resolveCallback]() mutable { + m_client->changeSignalingState(targetState); + resolveCallback(); + completeQueuedOperation(); + }; + + if (hasNewMediaDescriptions) + m_mediaEndpoint->prepareToReceive(m_localConfiguration.get(), isInitiator); + + if (m_remoteConfiguration) + m_mediaEndpoint->prepareToSend(m_remoteConfiguration.get(), isInitiator); +} + +RefPtr MediaEndpointPeerConnection::localDescription() const +{ + if (!m_localConfiguration) + return nullptr; + + String json = MediaEndpointConfigurationConversions::toJSON(m_localConfiguration.get()); + return RTCSessionDescription::create(m_localConfigurationType, toSDP(json)); +} + +static Vector> filterPayloads(const Vector>& remotePayloads, const String& type) +{ + Vector> defaultPayloads = createDefaultPayloads(type); + Vector> filteredPayloads; + + for (auto& remotePayload : remotePayloads) { + MediaPayload* defaultPayload = nullptr; + for (auto& p : defaultPayloads) { + if (p->encodingName() == remotePayload->encodingName().upper()) { + defaultPayload = p.get(); + break; + } + } + if (!defaultPayload) + continue; + + if (defaultPayload->parameters().contains("packetizationMode") && remotePayload->parameters().contains("packetizationMode") + && (defaultPayload->parameters().get("packetizationMode") != defaultPayload->parameters().get("packetizationMode"))) + continue; + + filteredPayloads.append(remotePayload); + } + + return filteredPayloads; +} + +void MediaEndpointPeerConnection::setRemoteDescription(RTCSessionDescription* description, PeerConnectionStates::SignalingState targetState, VoidResolveCallback resolveCallback, RejectCallback rejectCallback) +{ + RefPtr protectedDescription = description; + enqueueOperation([this, protectedDescription, targetState, resolveCallback, rejectCallback]() { + queuedSetRemoteDescription(protectedDescription.get(), targetState, resolveCallback, rejectCallback); + }); +} + +void MediaEndpointPeerConnection::queuedSetRemoteDescription(RTCSessionDescription* description, PeerConnectionStates::SignalingState targetState, VoidResolveCallback resolveCallback, RejectCallback rejectCallback) +{ + String json = fromSDP(description->sdp()); + m_remoteConfiguration = MediaEndpointConfigurationConversions::fromJSON(json); + m_remoteConfigurationType = description->type(); + + if (!m_remoteConfiguration) { + // FIXME: Error type? + RefPtr error = DOMError::create("InvalidSessionDescriptionError (unable to parse description)"); + rejectCallback(*error); + completeQueuedOperation(); + return; + } + + Vector> senders = m_client->getSenders(); + + for (auto& mediaDescription : m_remoteConfiguration->mediaDescriptions()) { + if (mediaDescription->type() != "audio" && mediaDescription->type() != "video") + continue; + + mediaDescription->setPayloads(filterPayloads(mediaDescription->payloads(), mediaDescription->type())); + + RefPtr sender = takeFirstSenderOfType(senders, mediaDescription->type()); + if (sender) + mediaDescription->setSource(sender->track()->source()); + } + + bool isInitiator = m_remoteConfigurationType == "answer"; + m_mediaEndpoint->prepareToSend(m_remoteConfiguration.get(), isInitiator); + + // FIXME: event firing task should update state + m_client->changeSignalingState(targetState); + + resolveCallback(); + completeQueuedOperation(); +} + +RefPtr MediaEndpointPeerConnection::remoteDescription() const +{ + if (!m_remoteConfiguration) + return nullptr; + + String json = MediaEndpointConfigurationConversions::toJSON(m_remoteConfiguration.get()); + return RTCSessionDescription::create(m_remoteConfigurationType, toSDP(json)); +} + +void MediaEndpointPeerConnection::setConfiguration(RTCConfiguration& configuration) +{ + // FIXME: updateIce() might be renamed to setConfiguration(). It's also possible + // that its current behavior with update deltas will change. + m_mediaEndpoint->setConfiguration(createMediaEndpointInit(configuration)); +} + +void MediaEndpointPeerConnection::addIceCandidate(RTCIceCandidate* rtcCandidate, VoidResolveCallback resolveCallback, RejectCallback rejectCallback) +{ + RefPtr protectedCandidate = rtcCandidate; + enqueueOperation([this, protectedCandidate, resolveCallback, rejectCallback]() { + queuedAddIceCandidate(protectedCandidate.get(), resolveCallback, rejectCallback); + }); +} + +void MediaEndpointPeerConnection::queuedAddIceCandidate(RTCIceCandidate* rtcCandidate, VoidResolveCallback resolveCallback, RejectCallback rejectCallback) +{ + String json = iceCandidateFromSDP(rtcCandidate->candidate()); + RefPtr candidate = MediaEndpointConfigurationConversions::iceCandidateFromJSON(json); + if (!candidate) { + // FIXME: Error type? + RefPtr error = DOMError::create("SyntaxError (malformed candidate)"); + rejectCallback(*error); + completeQueuedOperation(); + return; + } + + unsigned mdescIndex = rtcCandidate->sdpMLineIndex(); + if (mdescIndex >= m_remoteConfiguration->mediaDescriptions().size()) { + // FIXME: Error type? + RefPtr error = DOMError::create("InvalidSdpMlineIndex (sdpMLineIndex out of range"); + rejectCallback(*error); + completeQueuedOperation(); + return; + } + + PeerMediaDescription& mdesc = *m_remoteConfiguration->mediaDescriptions()[mdescIndex]; + mdesc.addIceCandidate(candidate.copyRef()); + + m_mediaEndpoint->addRemoteCandidate(*candidate, mdescIndex, mdesc.iceUfrag(), mdesc.icePassword()); + + resolveCallback(); + completeQueuedOperation(); +} + +void MediaEndpointPeerConnection::stop() +{ + m_mediaEndpoint->stop(); +} + +bool MediaEndpointPeerConnection::isLocalConfigurationComplete() const +{ + for (auto& mdesc : m_localConfiguration->mediaDescriptions()) { + if (mdesc->dtlsFingerprint().isEmpty()) + return false; + // Test: No trickle + if (!mdesc->iceCandidateGatheringDone()) + return false; + } + + return true; +} + +MediaEndpointPeerConnection::ResolveSetLocalDescriptionResult MediaEndpointPeerConnection::maybeResolveSetLocalDescription() +{ + if (!m_resolveSetLocalDescription) { + ASSERT(isLocalConfigurationComplete()); + return SetLocalDescriptionAlreadyResolved; + } + + if (isLocalConfigurationComplete()) { + m_resolveSetLocalDescription(); + m_resolveSetLocalDescription = nullptr; + return SetLocalDescriptionResolvedSuccessfully; + } + + return LocalConfigurationIncomplete; +} + +void MediaEndpointPeerConnection::maybeDispatchGatheringDone() +{ + if (!isLocalConfigurationComplete()) + return; + + for (auto& mdesc : m_localConfiguration->mediaDescriptions()) { + if (!mdesc->iceCandidateGatheringDone()) + return; + } + + m_client->scheduleDispatchEvent(RTCIceCandidateEvent::create(false, false, nullptr)); +} + +void MediaEndpointPeerConnection::gotDtlsCertificate(unsigned mdescIndex, const String& certificate) +{ + Vector certificateRows; + Vector der; + + der.reserveCapacity(certificate.length() * 3/4 + 2); + certificate.split("\n", certificateRows); + + for (auto& row : certificateRows) { + if (row.startsWith("-----")) + continue; + + Vector decodedRow; + if (!base64Decode(row, decodedRow, Base64FailOnInvalidCharacterOrExcessPadding)) { + ASSERT_NOT_REACHED(); + return; + } + der.appendVector(decodedRow); + } + + std::unique_ptr digest = CryptoDigest::create(CryptoAlgorithmIdentifier::SHA_256); + if (!digest) { + ASSERT_NOT_REACHED(); + return; + } + + digest->addBytes(der.data(), der.size()); + Vector fingerprintVector = digest->computeHash(); + + StringBuilder fingerprint; + for (unsigned i = 0; i < fingerprintVector.size(); ++i) + fingerprint.append(String::format(i ? ":%02X" : "%02X", fingerprintVector[i])); + + m_localConfiguration->mediaDescriptions()[mdescIndex]->setDtlsFingerprintHashFunction("sha-256"); + m_localConfiguration->mediaDescriptions()[mdescIndex]->setDtlsFingerprint(fingerprint.toString()); + + if (maybeResolveSetLocalDescription() == SetLocalDescriptionResolvedSuccessfully) + maybeDispatchGatheringDone(); +} + +void MediaEndpointPeerConnection::gotIceCandidate(unsigned mdescIndex, RefPtr&& candidate) +{ + printf("-> gotIceCandidate()\n"); + + ASSERT(scriptExecutionContext()->isContextThread()); + + PeerMediaDescription& mdesc = *m_localConfiguration->mediaDescriptions()[mdescIndex]; + mdesc.addIceCandidate(candidate.copyRef()); + + if (!candidate->address().contains(':')) { // not IPv6 + if (candidate->componentId() == 1) { // RTP + if (mdesc.address().isEmpty() || mdesc.address() == "0.0.0.0") { + mdesc.setAddress(candidate->address()); + mdesc.setPort(candidate->port()); + } + } else { // RTCP + if (mdesc.rtcpAddress().isEmpty() || !mdesc.rtcpPort()) { + mdesc.setRtcpAddress(candidate->address()); + mdesc.setRtcpPort(candidate->port()); + } + } + } + + ResolveSetLocalDescriptionResult result = maybeResolveSetLocalDescription(); + if (result == SetLocalDescriptionResolvedSuccessfully) + maybeDispatchGatheringDone(); + else if (result == SetLocalDescriptionAlreadyResolved) { + String candidateString = MediaEndpointConfigurationConversions::iceCandidateToJSON(candidate.get()); + String sdpFragment = iceCandidateToSDP(candidateString); + RefPtr iceCandidate = RTCIceCandidate::create(sdpFragment, "", mdescIndex); + m_client->scheduleDispatchEvent(RTCIceCandidateEvent::create(false, false, WTF::move(iceCandidate))); + } +} + +void MediaEndpointPeerConnection::doneGatheringCandidates(unsigned mdescIndex) +{ + printf("-> doneGatheringCandidates()\n"); + + ASSERT(scriptExecutionContext()->isContextThread()); + + m_localConfiguration->mediaDescriptions()[mdescIndex]->setIceCandidateGatheringDone(true); + // Test: No trickle + maybeResolveSetLocalDescription(); + maybeDispatchGatheringDone(); +} + +void MediaEndpointPeerConnection::gotRemoteSource(unsigned mdescIndex, RefPtr&& source) +{ + if (m_client->internalSignalingState() == SignalingState::Closed) + return; + + if (mdescIndex >= m_remoteConfiguration->mediaDescriptions().size()) { + printf("Warning: No remote configuration for incoming source.\n"); + return; + } + + PeerMediaDescription& mediaDescription = *m_remoteConfiguration->mediaDescriptions()[mdescIndex]; + String trackId = mediaDescription.mediaStreamTrackId(); + + if (trackId.isEmpty()) { + // Non WebRTC media description (e.g. legacy) + trackId = createCanonicalUUIDString(); + } + + // FIXME: track should be set to muted (not supported yet) + // FIXME: MediaStream handling not implemented + + RefPtr trackPrivate = MediaStreamTrackPrivate::create(WTF::move(source), trackId); + RefPtr track = MediaStreamTrack::create(*m_client->context(), *trackPrivate); + RefPtr receiver = RTCRtpReceiver::create(track.copyRef()); + + m_client->scheduleDispatchEvent(RTCTrackEvent::create(eventNames().trackEvent, false, false, WTF::move(receiver), WTF::move(track))); +} + +String MediaEndpointPeerConnection::toSDP(const String& json) const +{ + return sdpConversion("toSDP", json); +} + +String MediaEndpointPeerConnection::fromSDP(const String& sdp) const +{ + return sdpConversion("fromSDP", sdp); +} + +String MediaEndpointPeerConnection::iceCandidateToSDP(const String& json) const +{ + return sdpConversion("iceCandidateToSDP", json); +} + +String MediaEndpointPeerConnection::iceCandidateFromSDP(const String& sdpFragment) const +{ + return sdpConversion("iceCandidateFromSDP", sdpFragment); +} + +String MediaEndpointPeerConnection::sdpConversion(const String& functionName, const String& argument) const +{ + Document* document = downcast(m_client->context()); + + if (!m_isolatedWorld) + m_isolatedWorld = DOMWrapperWorld::create(JSDOMWindow::commonVM()); + + ScriptController& scriptController = document->frame()->script(); + JSDOMGlobalObject* globalObject = JSC::jsCast(scriptController.globalObject(*m_isolatedWorld)); + JSC::ExecState* exec = globalObject->globalExec(); + JSC::JSLockHolder lock(exec); + + JSC::JSValue probeFunctionValue = globalObject->get(exec, JSC::Identifier::fromString(exec, "toSDP")); + if (!probeFunctionValue.isFunction()) { + URL scriptURL; + scriptController.evaluateInWorld(ScriptSourceCode(SDPScriptResource::getString(), scriptURL), *m_isolatedWorld); + if (exec->hadException()) { + exec->clearException(); + return emptyString(); + } + } + + JSC::JSValue functionValue = globalObject->get(exec, JSC::Identifier::fromString(exec, functionName)); + if (!functionValue.isFunction()) + return emptyString(); + + JSC::JSObject* function = functionValue.toObject(exec); + JSC::CallData callData; + JSC::CallType callType = function->methodTable()->getCallData(function, callData); + if (callType == JSC::CallTypeNone) + return emptyString(); + + JSC::MarkedArgumentBuffer argList; + argList.append(JSC::jsString(exec, argument)); + + JSC::JSValue result = JSC::call(exec, function, callType, callData, globalObject, argList); + if (exec->hadException()) { + printf("sdpConversion: js function (%s) threw\n", functionName.ascii().data()); + exec->clearException(); + return emptyString(); + } + + return result.isString() ? result.getString(exec) : emptyString(); +} + +} // namespace WebCore + +#endif // ENABLE(MEDIA_STREAM) diff --git a/Source/WebCore/Modules/mediastream/MediaEndpointPeerConnection.h b/Source/WebCore/Modules/mediastream/MediaEndpointPeerConnection.h new file mode 100644 index 0000000000000..eccce661f0a66 --- /dev/null +++ b/Source/WebCore/Modules/mediastream/MediaEndpointPeerConnection.h @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2015 Ericsson AB. All rights reserved. + * + * 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. + * 3. Neither the name of Ericsson nor the names of its contributors + * may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT + * OWNER OR 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. + */ + +#ifndef MediaEndpointPeerConnection_h +#define MediaEndpointPeerConnection_h + +#if ENABLE(MEDIA_STREAM) + +#include "MediaEndpoint.h" +#include "MediaEndpointConfiguration.h" +#include "PeerConnectionBackend.h" +#include +#include + +namespace WebCore { + +class DOMWrapperWorld; + +class MediaEndpointPeerConnection : public PeerConnectionBackend, public MediaEndpointClient { +public: + MediaEndpointPeerConnection(PeerConnectionBackendClient*); + ~MediaEndpointPeerConnection(); + + void createOffer(const RefPtr&, OfferAnswerResolveCallback, RejectCallback) override; + void createAnswer(const RefPtr&, OfferAnswerResolveCallback, RejectCallback) override; + + void setLocalDescription(RTCSessionDescription*, PeerConnectionStates::SignalingState targetState, VoidResolveCallback, RejectCallback) override; + RefPtr localDescription() const override; + + void setRemoteDescription(RTCSessionDescription*, PeerConnectionStates::SignalingState targetState, VoidResolveCallback, RejectCallback) override; + RefPtr remoteDescription() const override; + + void setConfiguration(RTCConfiguration&) override; + void addIceCandidate(RTCIceCandidate*, VoidResolveCallback, RejectCallback) override; + + void stop() override; + +private: + enum ResolveSetLocalDescriptionResult { + LocalConfigurationIncomplete, + SetLocalDescriptionResolvedSuccessfully, + SetLocalDescriptionAlreadyResolved + }; + + void enqueueOperation(std::function); + void completeQueuedOperation(); + + void queuedCreateOffer(const RefPtr&, OfferAnswerResolveCallback, RejectCallback); + void queuedCreateAnswer(const RefPtr&, OfferAnswerResolveCallback, RejectCallback); + + void queuedSetLocalDescription(RTCSessionDescription*, PeerConnectionStates::SignalingState targetState, VoidResolveCallback, RejectCallback); + void queuedSetRemoteDescription(RTCSessionDescription*, PeerConnectionStates::SignalingState targetState, VoidResolveCallback, RejectCallback); + + void queuedAddIceCandidate(RTCIceCandidate*, VoidResolveCallback, RejectCallback); + + bool isLocalConfigurationComplete() const; + ResolveSetLocalDescriptionResult maybeResolveSetLocalDescription(); + void maybeDispatchGatheringDone(); + + // MediaEndpointClient + virtual void gotDtlsCertificate(unsigned mdescIndex, const String& certificate) override; + virtual void gotIceCandidate(unsigned mdescIndex, RefPtr&&) override; + virtual void doneGatheringCandidates(unsigned mdescIndex) override; + virtual void gotRemoteSource(unsigned mdescIndex, RefPtr&&) override; + + String toSDP(const String& json) const; + String fromSDP(const String& sdp) const; + String iceCandidateToSDP(const String& json) const; + String iceCandidateFromSDP(const String& sdpFragment) const; + String sdpConversion(const String& functionName, const String& argument) const; + + PeerConnectionBackendClient* m_client; + std::unique_ptr m_mediaEndpoint; + + Vector> m_operationsQueue; + + mutable RefPtr m_isolatedWorld; + + String m_cname; + String m_iceUfrag; + String m_icePassword; + + RefPtr m_localConfiguration; + RefPtr m_remoteConfiguration; + + String m_localConfigurationType; + String m_remoteConfigurationType; + + std::function m_resolveSetLocalDescription; + + RefPtr m_configuration; +}; + +} // namespace WebCore + +#endif // ENABLE(MEDIA_STREAM) + +#endif // MediaEndpointPeerConnection_h diff --git a/Source/WebCore/Modules/mediastream/MediaStream.idl b/Source/WebCore/Modules/mediastream/MediaStream.idl index 60222852121a6..1e2172393a1a4 100644 --- a/Source/WebCore/Modules/mediastream/MediaStream.idl +++ b/Source/WebCore/Modules/mediastream/MediaStream.idl @@ -29,6 +29,7 @@ Constructor(MediaStream stream), Constructor(MediaStreamTrack[] tracks), ConstructorCallWith=ScriptExecutionContext, + InterfaceName=webkitMediaStream, ] interface MediaStream { readonly attribute DOMString id; @@ -36,6 +37,7 @@ sequence getAudioTracks(); sequence getVideoTracks(); sequence getTracks(); + MediaStreamTrack getTrackById(DOMString trackId); void addTrack(MediaStreamTrack track); diff --git a/Source/WebCore/Modules/mediastream/MediaStreamEvent.cpp b/Source/WebCore/Modules/mediastream/MediaStreamEvent.cpp deleted file mode 100644 index ed7c23e53fd74..0000000000000 --- a/Source/WebCore/Modules/mediastream/MediaStreamEvent.cpp +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright (C) 2011 Google Inc. All rights reserved. - * - * 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 "MediaStreamEvent.h" - -#if ENABLE(MEDIA_STREAM) - -#include "EventNames.h" -#include "MediaStream.h" - -namespace WebCore { - -MediaStreamEventInit::MediaStreamEventInit() - : stream(nullptr) -{ -} - -Ref MediaStreamEvent::create() -{ - return adoptRef(*new MediaStreamEvent); -} - -Ref MediaStreamEvent::create(const AtomicString& type, bool canBubble, bool cancelable, PassRefPtr stream) -{ - return adoptRef(*new MediaStreamEvent(type, canBubble, cancelable, stream)); -} - -Ref MediaStreamEvent::create(const AtomicString& type, const MediaStreamEventInit& initializer) -{ - return adoptRef(*new MediaStreamEvent(type, initializer)); -} - -MediaStreamEvent::MediaStreamEvent() -{ -} - -MediaStreamEvent::MediaStreamEvent(const AtomicString& type, bool canBubble, bool cancelable, PassRefPtr stream) - : Event(type, canBubble, cancelable) - , m_stream(stream) -{ -} - -MediaStreamEvent::MediaStreamEvent(const AtomicString& type, const MediaStreamEventInit& initializer) - : Event(type, initializer) - , m_stream(initializer.stream) -{ -} - -MediaStreamEvent::~MediaStreamEvent() -{ -} - -MediaStream* MediaStreamEvent::stream() const -{ - return m_stream.get(); -} - -EventInterface MediaStreamEvent::eventInterface() const -{ - return MediaStreamEventInterfaceType; -} - -} // namespace WebCore - -#endif // ENABLE(MEDIA_STREAM) - diff --git a/Source/WebCore/Modules/mediastream/MediaStreamEvent.h b/Source/WebCore/Modules/mediastream/MediaStreamEvent.h deleted file mode 100644 index b61520e526eb7..0000000000000 --- a/Source/WebCore/Modules/mediastream/MediaStreamEvent.h +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (C) 2011 Google Inc. All rights reserved. - * - * 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. - */ - -#ifndef MediaStreamEvent_h -#define MediaStreamEvent_h - -#if ENABLE(MEDIA_STREAM) - -#include "Event.h" -#include "MediaStream.h" -#include - -namespace WebCore { - -struct MediaStreamEventInit : public EventInit { - MediaStreamEventInit(); - - RefPtr stream; -}; - -class MediaStreamEvent : public Event { -public: - virtual ~MediaStreamEvent(); - - static Ref create(); - static Ref create(const AtomicString& type, bool canBubble, bool cancelable, PassRefPtr); - static Ref create(const AtomicString& type, const MediaStreamEventInit& initializer); - - MediaStream* stream() const; - - virtual EventInterface eventInterface() const; - -private: - MediaStreamEvent(); - MediaStreamEvent(const AtomicString& type, bool canBubble, bool cancelable, PassRefPtr); - MediaStreamEvent(const AtomicString& type, const MediaStreamEventInit&); - - RefPtr m_stream; -}; - -} // namespace WebCore - -#endif // ENABLE(MEDIA_STREAM) - -#endif // MediaStreamEvent_h diff --git a/Source/WebCore/Modules/mediastream/MediaStreamEvent.idl b/Source/WebCore/Modules/mediastream/MediaStreamEvent.idl deleted file mode 100644 index b44729ca3cbd1..0000000000000 --- a/Source/WebCore/Modules/mediastream/MediaStreamEvent.idl +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (C) 2011 Google Inc. All rights reserved. - * - * 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. - */ - -[ - Conditional=MEDIA_STREAM, - ConstructorTemplate=Event -] interface MediaStreamEvent : Event { - [InitializedByEventConstructor] readonly attribute MediaStream stream; -}; - diff --git a/Source/WebCore/Modules/mediastream/PeerConnectionBackend.cpp b/Source/WebCore/Modules/mediastream/PeerConnectionBackend.cpp new file mode 100644 index 0000000000000..8900efc18e206 --- /dev/null +++ b/Source/WebCore/Modules/mediastream/PeerConnectionBackend.cpp @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2015 Ericsson AB. All rights reserved. + * + * 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. + * 3. Neither the name of Ericsson nor the names of its contributors + * may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT + * OWNER OR 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" + +#if ENABLE(MEDIA_STREAM) +#include "PeerConnectionBackend.h" + +namespace WebCore { + +static std::unique_ptr createPeerConnectionBackend(PeerConnectionBackendClient*) +{ + return nullptr; +} + +CreatePeerConnectionBackend PeerConnectionBackend::create = createPeerConnectionBackend; + +} // namespace WebCore + +#endif // ENABLE(MEDIA_STREAM) diff --git a/Source/WebCore/Modules/mediastream/PeerConnectionBackend.h b/Source/WebCore/Modules/mediastream/PeerConnectionBackend.h new file mode 100644 index 0000000000000..cbf714573975a --- /dev/null +++ b/Source/WebCore/Modules/mediastream/PeerConnectionBackend.h @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2015 Ericsson AB. All rights reserved. + * + * 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. + * 3. Neither the name of Ericsson nor the names of its contributors + * may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT + * OWNER OR 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. + */ + +#ifndef PeerConnectionBackend_h +#define PeerConnectionBackend_h + +#if ENABLE(MEDIA_STREAM) + +#include "PeerConnectionStates.h" + +namespace WebCore { + +class DOMError; +class Event; +class PeerConnectionBackend; +class RTCAnswerOptions; +class RTCConfiguration; +class RTCIceCandidate; +class RTCOfferOptions; +class RTCRtpSender; +class RTCSessionDescription; +class ScriptExecutionContext; + +class PeerConnectionBackendClient { +public: + virtual Vector> getSenders() const = 0; + virtual void scheduleDispatchEvent(PassRefPtr) = 0; + + virtual void changeSignalingState(PeerConnectionStates::SignalingState) = 0; + virtual void changeIceGatheringState(PeerConnectionStates::IceGatheringState) = 0; + virtual void changeIceConnectionState(PeerConnectionStates::IceConnectionState) = 0; + + virtual ScriptExecutionContext* context() const = 0; + virtual PeerConnectionStates::SignalingState internalSignalingState() const = 0; + + virtual ~PeerConnectionBackendClient() { } +}; + +typedef std::unique_ptr (*CreatePeerConnectionBackend)(PeerConnectionBackendClient*); + +class PeerConnectionBackend { +public: + WEBCORE_EXPORT static CreatePeerConnectionBackend create; + virtual ~PeerConnectionBackend() { } + + typedef std::function OfferAnswerResolveCallback; + typedef std::function VoidResolveCallback; + typedef std::function RejectCallback; + + virtual void createOffer(const RefPtr&, OfferAnswerResolveCallback, RejectCallback) = 0; + virtual void createAnswer(const RefPtr&, OfferAnswerResolveCallback, RejectCallback) = 0; + + virtual void setLocalDescription(RTCSessionDescription*, PeerConnectionStates::SignalingState targetState, VoidResolveCallback, RejectCallback) = 0; + virtual RefPtr localDescription() const = 0; + + virtual void setRemoteDescription(RTCSessionDescription*, PeerConnectionStates::SignalingState targetState, VoidResolveCallback, RejectCallback) = 0; + virtual RefPtr remoteDescription() const = 0; + + virtual void setConfiguration(RTCConfiguration&) = 0; + virtual void addIceCandidate(RTCIceCandidate*, VoidResolveCallback, RejectCallback) = 0; + + virtual void stop() = 0; +}; + +} // namespace WebCore + +#endif // ENABLE(MEDIA_STREAM) + +#endif // PeerConnectionBackend_h diff --git a/Source/WebCore/Modules/mediastream/PeerConnectionStates.h b/Source/WebCore/Modules/mediastream/PeerConnectionStates.h new file mode 100644 index 0000000000000..df2956d4dd071 --- /dev/null +++ b/Source/WebCore/Modules/mediastream/PeerConnectionStates.h @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2015 Ericsson AB. All rights reserved. + * + * 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. + * 3. Neither the name of Ericsson nor the names of its contributors + * may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT + * OWNER OR 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. + */ + +#ifndef PeerConnectionStates_h +#define PeerConnectionStates_h + +#if ENABLE(MEDIA_STREAM) + +namespace WebCore { + +namespace PeerConnectionStates { + +enum class SignalingState { + Stable = 1, + HaveLocalOffer = 2, + HaveRemoteOffer = 3, + HaveLocalPrAnswer = 4, + HaveRemotePrAnswer = 5, + Closed = 6, + Invalid = 7 +}; + +enum class IceConnectionState { + New = 1, + Checking = 2, + Connected = 3, + Completed = 4, + Failed = 5, + Disconnected = 6, + Closed = 7 +}; + +enum class IceGatheringState { + New = 1, + Gathering = 2, + Complete = 3 +}; + +} + +} // namespace WebCore + +#endif // ENABLE(MEDIA_STREAM) + +#endif // PeerConnectionStates_h diff --git a/Source/WebCore/Modules/mediastream/RTCConfiguration.cpp b/Source/WebCore/Modules/mediastream/RTCConfiguration.cpp new file mode 100644 index 0000000000000..c16bb3fcc4a70 --- /dev/null +++ b/Source/WebCore/Modules/mediastream/RTCConfiguration.cpp @@ -0,0 +1,165 @@ +/* + * Copyright (C) 2012 Google Inc. All rights reserved. + * Copyright (C) 2013 Nokia Corporation and/or its subsidiary(-ies). + * Copyright (C) 2015 Ericsson AB. All rights reserved. + * + * 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. + * 3. Neither the name of Ericsson nor the names of its contributors + * may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT + * OWNER OR 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 "RTCConfiguration.h" + +#if ENABLE(MEDIA_STREAM) + +#include "ArrayValue.h" +#include "Dictionary.h" +#include "ExceptionCode.h" +#include "URL.h" + +namespace WebCore { + +static bool validateIceServerURL(const String& iceURL) +{ + URL url(URL(), iceURL); + if (url.isEmpty() || !url.isValid() || !(url.protocolIs("turn") || url.protocolIs("stun"))) + return false; + + return true; +} + +static RefPtr parseIceServer(const Dictionary& iceServer, ExceptionCode& ec) +{ + String credential, username; + iceServer.get("credential", credential); + iceServer.get("username", username); + + // Spec says that "urls" can be either a string or a sequence, so we must check for both. + Vector urlsList; + String urlString; + iceServer.get("urls", urlString); + // This is the only way to check if "urls" is a sequence or a string. If we try to convert + // to a sequence and it fails (in case it is a string), an exception will be set and the + // RTCPeerConnection will fail. + // So we convert to a string always, which converts a sequence to a string in the format: "foo, bar, ..", + // then checking for a comma in the string assures that a string was a sequence and then we convert + // it to a sequence safely. + if (urlString.isEmpty()) { + ec = INVALID_ACCESS_ERR; + return nullptr; + } + + if (urlString.find(',') != notFound && iceServer.get("urls", urlsList) && urlsList.size()) { + for (auto iter = urlsList.begin(); iter != urlsList.end(); ++iter) { + if (!validateIceServerURL(*iter)) { + ec = INVALID_ACCESS_ERR; + return nullptr; + } + } + } else { + if (!validateIceServerURL(urlString)) { + ec = INVALID_ACCESS_ERR; + return nullptr; + } + + urlsList.append(urlString); + } + + return RTCIceServer::create(urlsList, credential, username); +} + +RefPtr RTCConfiguration::create(const Dictionary& configuration, ExceptionCode& ec) +{ + if (configuration.isUndefinedOrNull()) + return nullptr; + + RefPtr rtcConfiguration = adoptRef(new RTCConfiguration()); + rtcConfiguration->initialize(configuration, ec); + if (ec) + return nullptr; + + return rtcConfiguration; +} + +RTCConfiguration::RTCConfiguration() + : m_iceTransportPolicy("all") + , m_bundlePolicy("balanced") +{ +} + +void RTCConfiguration::initialize(const Dictionary& configuration, ExceptionCode& ec) +{ + ArrayValue iceServers; + bool ok = configuration.get("iceServers", iceServers); + if (!ok || iceServers.isUndefinedOrNull()) { + ec = TYPE_MISMATCH_ERR; + return; + } + + size_t numberOfServers; + ok = iceServers.length(numberOfServers); + if (!ok || !numberOfServers) { + ec = !ok ? TYPE_MISMATCH_ERR : INVALID_ACCESS_ERR; + return; + } + + for (size_t i = 0; i < numberOfServers; ++i) { + Dictionary iceServerDict; + ok = iceServers.get(i, iceServerDict); + if (!ok) { + ec = TYPE_MISMATCH_ERR; + return; + } + + RefPtr iceServer = parseIceServer(iceServerDict, ec); + if (!iceServer) + return; + + m_iceServers.append(WTF::move(iceServer)); + } + + String iceTransportPolicy; + if (configuration.get("iceTransportPolicy", iceTransportPolicy)) { + if (iceTransportPolicy == "none" || iceTransportPolicy == "relay" || iceTransportPolicy == "all") + m_iceTransportPolicy = iceTransportPolicy; + else { + ec = TypeError; + return; + } + } + + String bundlePolicy; + if (configuration.get("bundlePolicy", bundlePolicy)) { + if (bundlePolicy == "balanced" || bundlePolicy == "max-compat" || bundlePolicy == "max-bundle") + m_bundlePolicy = bundlePolicy; + else + ec = TypeError; + } +} + +} // namespace WebCore + +#endif // ENABLE(MEDIA_STREAM) diff --git a/Source/WebCore/Modules/mediastream/RTCConfiguration.h b/Source/WebCore/Modules/mediastream/RTCConfiguration.h index 637d4d9cbbabb..004963d2d5482 100644 --- a/Source/WebCore/Modules/mediastream/RTCConfiguration.h +++ b/Source/WebCore/Modules/mediastream/RTCConfiguration.h @@ -33,55 +33,35 @@ #if ENABLE(MEDIA_STREAM) -#include "RTCConfigurationPrivate.h" #include "RTCIceServer.h" -#include #include +#include #include #include namespace WebCore { +class Dictionary; + +typedef int ExceptionCode; + class RTCConfiguration : public RefCounted { public: - static Ref create() { return adoptRef(*new RTCConfiguration()); } + static RefPtr create(const Dictionary& configuration, ExceptionCode&); virtual ~RTCConfiguration() { } - void appendServer(PassRefPtr server) { m_private->appendServer(server->privateServer()); } - size_t numberOfServers() { return m_private->numberOfServers(); } - PassRefPtr server(size_t index) - { - RTCIceServerPrivate* server = m_private->server(index); - if (!server) - return nullptr; - - return RTCIceServer::create(server); - } - - const String& iceTransports() const { return m_private->iceTransports(); } - void setIceTransports(const String& iceTransports) { m_private->setIceTransports(iceTransports); } - - const String& requestIdentity() const { return m_private->requestIdentity(); } - void setRequestIdentity(const String& requestIdentity) { m_private->setRequestIdentity(requestIdentity); } - - Vector> iceServers() const - { - Vector> servers; - for (auto& server : m_private->iceServers()) - servers.append(RTCIceServer::create(server)); - - return servers; - } - - RTCConfigurationPrivate* privateConfiguration() { return m_private.get(); } + const String& iceTransportPolicy() const { return m_iceTransportPolicy; } + const String& bundlePolicy() const { return m_bundlePolicy; } + Vector> iceServers() const { return m_iceServers; } private: - RTCConfiguration() - : m_private(RTCConfigurationPrivate::create()) - { - } + RTCConfiguration(); + + void initialize(const Dictionary& configuration, ExceptionCode&); - RefPtr m_private; + Vector> m_iceServers; + String m_iceTransportPolicy; + String m_bundlePolicy; }; } // namespace WebCore diff --git a/Source/WebCore/Modules/mediastream/RTCConfiguration.idl b/Source/WebCore/Modules/mediastream/RTCConfiguration.idl index 046830b0cf5a7..a2776d8466a30 100644 --- a/Source/WebCore/Modules/mediastream/RTCConfiguration.idl +++ b/Source/WebCore/Modules/mediastream/RTCConfiguration.idl @@ -23,14 +23,14 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -enum RTCIceTransportsEnum { "none", "relay", "all" }; -enum RTCIdentityOptionEnum { "yes", "no", "ifconfigured" }; +enum RTCIceTransportPolicyEnum { "none", "relay", "all" }; +enum RTCBundlePolicyEnum { "balanced", "max-compat", "max-bundle" }; [ Conditional=MEDIA_STREAM, NoInterfaceObject, ] interface RTCConfiguration { readonly attribute RTCIceServer[] iceServers; - readonly attribute RTCIceTransportsEnum iceTransports; - readonly attribute RTCIdentityOptionEnum requestIdentity; + readonly attribute RTCIceTransportPolicyEnum iceTransportPolicy; + readonly attribute RTCBundlePolicyEnum bundlePolicy; }; diff --git a/Source/WebCore/Modules/mediastream/RTCIceCandidate.cpp b/Source/WebCore/Modules/mediastream/RTCIceCandidate.cpp index b29189f40c140..d30a214b48787 100644 --- a/Source/WebCore/Modules/mediastream/RTCIceCandidate.cpp +++ b/Source/WebCore/Modules/mediastream/RTCIceCandidate.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 Ericsson AB. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -37,7 +38,6 @@ #include "Dictionary.h" #include "ExceptionCode.h" -#include "RTCIceCandidateDescriptor.h" namespace WebCore { @@ -71,16 +71,18 @@ RefPtr RTCIceCandidate::create(const Dictionary& dictionary, Ex } } - return adoptRef(*new RTCIceCandidate(RTCIceCandidateDescriptor::create(candidate, sdpMid, sdpMLineIndex))); + return adoptRef(new RTCIceCandidate(candidate, sdpMid, sdpMLineIndex)); } -Ref RTCIceCandidate::create(PassRefPtr descriptor) +Ref RTCIceCandidate::create(const String& candidate, const String& sdpMid, unsigned short sdpMLineIndex) { - return adoptRef(*new RTCIceCandidate(descriptor)); + return adoptRef(*new RTCIceCandidate(candidate, sdpMid, sdpMLineIndex)); } -RTCIceCandidate::RTCIceCandidate(PassRefPtr descriptor) - : m_descriptor(descriptor) +RTCIceCandidate::RTCIceCandidate(const String& candidate, const String& sdpMid, unsigned short sdpMLineIndex) + : m_candidate(candidate) + , m_sdpMid(sdpMid) + , m_sdpMLineIndex(sdpMLineIndex) { } @@ -90,22 +92,33 @@ RTCIceCandidate::~RTCIceCandidate() const String& RTCIceCandidate::candidate() const { - return m_descriptor->candidate(); + return m_candidate; } +void RTCIceCandidate::setCandidate(const String& candidate) +{ + m_candidate = candidate; +} + + const String& RTCIceCandidate::sdpMid() const { - return m_descriptor->sdpMid(); + return m_sdpMid; +} + +void RTCIceCandidate::setSdpMid(const String& sdpMid) +{ + m_sdpMid = sdpMid; } unsigned short RTCIceCandidate::sdpMLineIndex() const { - return m_descriptor->sdpMLineIndex(); + return m_sdpMLineIndex; } -RTCIceCandidateDescriptor* RTCIceCandidate::descriptor() +void RTCIceCandidate::setSdpMLineIndex(unsigned short sdpMLineIndex) { - return m_descriptor.get(); + m_sdpMLineIndex = sdpMLineIndex; } } // namespace WebCore diff --git a/Source/WebCore/Modules/mediastream/RTCIceCandidate.h b/Source/WebCore/Modules/mediastream/RTCIceCandidate.h index 65fa3baca53f2..1778452b02f5f 100644 --- a/Source/WebCore/Modules/mediastream/RTCIceCandidate.h +++ b/Source/WebCore/Modules/mediastream/RTCIceCandidate.h @@ -35,7 +35,6 @@ #include "ExceptionBase.h" #include "ScriptWrappable.h" -#include #include #include #include @@ -48,19 +47,24 @@ class RTCIceCandidateDescriptor; class RTCIceCandidate : public RefCounted, public ScriptWrappable { public: static RefPtr create(const Dictionary&, ExceptionCode&); - static Ref create(PassRefPtr); + static Ref create(const String& candidate, const String& sdpMid, unsigned short sdpMLineIndex); virtual ~RTCIceCandidate(); const String& candidate() const; + void setCandidate(const String&); + const String& sdpMid() const; - unsigned short sdpMLineIndex() const; + void setSdpMid(const String&); - RTCIceCandidateDescriptor* descriptor(); + unsigned short sdpMLineIndex() const; + void setSdpMLineIndex(unsigned short); private: - explicit RTCIceCandidate(PassRefPtr); + explicit RTCIceCandidate(const String& candidate, const String& sdpMid, unsigned short sdpMLineIndex); - RefPtr m_descriptor; + String m_candidate; + String m_sdpMid; + unsigned short m_sdpMLineIndex; }; } // namespace WebCore diff --git a/Source/WebCore/Modules/mediastream/RTCIceCandidate.idl b/Source/WebCore/Modules/mediastream/RTCIceCandidate.idl index 4fb49586d1520..8e6238def91e1 100644 --- a/Source/WebCore/Modules/mediastream/RTCIceCandidate.idl +++ b/Source/WebCore/Modules/mediastream/RTCIceCandidate.idl @@ -34,8 +34,8 @@ CustomConstructor(optional Dictionary dictionary), ConstructorRaisesException ] interface RTCIceCandidate { - readonly attribute DOMString candidate; - readonly attribute DOMString sdpMid; - readonly attribute unsigned short sdpMLineIndex; + attribute DOMString candidate; + attribute DOMString sdpMid; + attribute unsigned short sdpMLineIndex; }; diff --git a/Source/WebCore/Modules/mediastream/RTCIceCandidateEvent.cpp b/Source/WebCore/Modules/mediastream/RTCIceCandidateEvent.cpp index 178c5e02f3a26..b58ddf7b62f72 100644 --- a/Source/WebCore/Modules/mediastream/RTCIceCandidateEvent.cpp +++ b/Source/WebCore/Modules/mediastream/RTCIceCandidateEvent.cpp @@ -38,18 +38,18 @@ Ref RTCIceCandidateEvent::create() return adoptRef(*new RTCIceCandidateEvent); } -Ref RTCIceCandidateEvent::create(bool canBubble, bool cancelable, PassRefPtr candidate) +Ref RTCIceCandidateEvent::create(bool canBubble, bool cancelable, RefPtr&& candidate) { - return adoptRef(*new RTCIceCandidateEvent(canBubble, cancelable, candidate)); + return adoptRef(*new RTCIceCandidateEvent(canBubble, cancelable, WTF::move(candidate))); } RTCIceCandidateEvent::RTCIceCandidateEvent() { } -RTCIceCandidateEvent::RTCIceCandidateEvent(bool canBubble, bool cancelable, PassRefPtr candidate) +RTCIceCandidateEvent::RTCIceCandidateEvent(bool canBubble, bool cancelable, RefPtr&& candidate) : Event(eventNames().icecandidateEvent, canBubble, cancelable) - , m_candidate(candidate) + , m_candidate(WTF::move(candidate)) { } diff --git a/Source/WebCore/Modules/mediastream/RTCIceCandidateEvent.h b/Source/WebCore/Modules/mediastream/RTCIceCandidateEvent.h index df90ac08d263a..e0a804d515b83 100644 --- a/Source/WebCore/Modules/mediastream/RTCIceCandidateEvent.h +++ b/Source/WebCore/Modules/mediastream/RTCIceCandidateEvent.h @@ -38,7 +38,7 @@ class RTCIceCandidateEvent : public Event { virtual ~RTCIceCandidateEvent(); static Ref create(); - static Ref create(bool canBubble, bool cancelable, PassRefPtr); + static Ref create(bool canBubble, bool cancelable, RefPtr&&); RTCIceCandidate* candidate() const; @@ -46,7 +46,7 @@ class RTCIceCandidateEvent : public Event { private: RTCIceCandidateEvent(); - RTCIceCandidateEvent(bool canBubble, bool cancelable, PassRefPtr); + RTCIceCandidateEvent(bool canBubble, bool cancelable, RefPtr&&); RefPtr m_candidate; }; diff --git a/Source/WebCore/Modules/mediastream/RTCIceServer.h b/Source/WebCore/Modules/mediastream/RTCIceServer.h index 4218d2b17b711..5ba0d0dbd54f5 100644 --- a/Source/WebCore/Modules/mediastream/RTCIceServer.h +++ b/Source/WebCore/Modules/mediastream/RTCIceServer.h @@ -28,7 +28,6 @@ #if ENABLE(MEDIA_STREAM) -#include "RTCIceServerPrivate.h" #include #include #include @@ -42,31 +41,22 @@ class RTCIceServer : public RefCounted { { return adoptRef(*new RTCIceServer(urls, credential, username)); } - - static Ref create(PassRefPtr server) - { - return adoptRef(*new RTCIceServer(server)); - } - virtual ~RTCIceServer() { } - const Vector& urls() { return m_private->urls(); } - const String& credential() { return m_private->credential(); } - const String& username() { return m_private->username(); } - RTCIceServerPrivate* privateServer() { return m_private.get(); } + const Vector& urls() const { return m_urls; } + const String& credential() const { return m_credential; } + const String& username() const { return m_username; } private: RTCIceServer(const Vector& urls, const String& credential, const String& username) - : m_private(RTCIceServerPrivate::create(urls, credential, username)) - { - } - - RTCIceServer(PassRefPtr server) - : m_private(server) - { - } + : m_urls(urls) + , m_credential(credential) + , m_username(username) + { } - RefPtr m_private; + Vector m_urls; + String m_credential; + String m_username; }; } // namespace WebCore diff --git a/Source/WebCore/Modules/mediastream/RTCOfferAnswerOptions.cpp b/Source/WebCore/Modules/mediastream/RTCOfferAnswerOptions.cpp index ef0aa6de833e0..5432ef085fe86 100644 --- a/Source/WebCore/Modules/mediastream/RTCOfferAnswerOptions.cpp +++ b/Source/WebCore/Modules/mediastream/RTCOfferAnswerOptions.cpp @@ -1,5 +1,6 @@ /* * Copyright (C) 2014 Apple Inc. All rights reserved. + * Copyright (C) 2015 Ericsson AB. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -32,30 +33,17 @@ namespace WebCore { -RefPtr RTCOfferAnswerOptions::create(const Dictionary& options, ExceptionCode& ec) +RTCOfferAnswerOptions::RTCOfferAnswerOptions() + : m_voiceActivityDetection(true) { - RefPtr offerAnswerOptions = adoptRef(new RTCOfferAnswerOptions()); - String requestIdentity; - if (!offerAnswerOptions->initialize(options)) { - // FIXME: https://webkit.org/b/129800 - // According to the spec, the error is going to be defined yet, so let's use TYPE_MISMATCH_ERR for now. - ec = TYPE_MISMATCH_ERR; - return nullptr; - } - - return offerAnswerOptions; } bool RTCOfferAnswerOptions::initialize(const Dictionary& options) { - if (!m_private) - m_private = RTCOfferAnswerOptionsPrivate::create(); - - String requestIdentity; - if (!options.isUndefinedOrNull() && (!options.get("requestIdentity", requestIdentity) || requestIdentity.isEmpty())) - return false; + bool voiceActivityDetection; + if (options.get("voiceActivityDetection", voiceActivityDetection)) + m_voiceActivityDetection = voiceActivityDetection; - m_private->setRequestIdentity(requestIdentity); return true; } @@ -72,47 +60,64 @@ RefPtr RTCOfferOptions::create(const Dictionary& options, Excep return offerOptions; } -bool RTCOfferOptions::initialize(const Dictionary& options) +RTCOfferOptions::RTCOfferOptions() + : m_offerToReceiveVideo(0) + , m_offerToReceiveAudio(0) + , m_iceRestart(false) { - RefPtr optionsPrivate = RTCOfferOptionsPrivate::create(); - m_private = optionsPrivate; +} +bool RTCOfferOptions::initialize(const Dictionary& options) +{ if (options.isUndefinedOrNull()) return true; - if (!RTCOfferAnswerOptions::initialize(options)) - return false; - - String offerToReceiveVideoStr; + String stringValue; + int64_t intConversionResult; bool numberConversionSuccess; - if (!options.get("offerToReceiveVideo", offerToReceiveVideoStr)) - return false; - - int64_t intConversionResult = offerToReceiveVideoStr.toInt64Strict(&numberConversionSuccess); - if (!numberConversionSuccess) - return false; - optionsPrivate->setOfferToReceiveVideo(intConversionResult); + if (options.get("offerToReceiveVideo", stringValue)) { + intConversionResult = stringValue.toInt64Strict(&numberConversionSuccess); + if (!numberConversionSuccess) + return false; - String offerToReceiveAudioStr; - if (!options.get("offerToReceiveAudio", offerToReceiveAudioStr)) - return false; - - intConversionResult = offerToReceiveAudioStr.toInt64Strict(&numberConversionSuccess); - if (!numberConversionSuccess) - return false; + m_offerToReceiveVideo = intConversionResult; + } - optionsPrivate->setOfferToReceiveAudio(intConversionResult); + if (options.get("offerToReceiveAudio", stringValue)) { + intConversionResult = stringValue.toInt64Strict(&numberConversionSuccess); + if (!numberConversionSuccess) + return false; - bool voiceActivityDetection; - if (options.get("voiceActivityDetection", voiceActivityDetection)) - optionsPrivate->setVoiceActivityDetection(voiceActivityDetection); + m_offerToReceiveAudio = intConversionResult; + } bool iceRestart; if (options.get("iceRestart", iceRestart)) - optionsPrivate->setIceRestart(iceRestart); + m_iceRestart = iceRestart; - return true; + return RTCOfferAnswerOptions::initialize(options); +} + +RefPtr RTCAnswerOptions::create(const Dictionary& options, ExceptionCode& ec) +{ + RefPtr offerOptions = adoptRef(new RTCAnswerOptions()); + if (!offerOptions->initialize(options)) { + // FIXME: https://webkit.org/b/129800 + // According to the spec, the error is going to be defined yet, so let's use TYPE_MISMATCH_ERR for now. + ec = TYPE_MISMATCH_ERR; + return nullptr; + } + + return offerOptions; +} + +bool RTCAnswerOptions::initialize(const Dictionary& options) +{ + if (options.isUndefinedOrNull()) + return true; + + return RTCOfferAnswerOptions::initialize(options); } } // namespace WebCore diff --git a/Source/WebCore/Modules/mediastream/RTCOfferAnswerOptions.h b/Source/WebCore/Modules/mediastream/RTCOfferAnswerOptions.h index 5f3ae1fa33a01..91bf571d1ed04 100644 --- a/Source/WebCore/Modules/mediastream/RTCOfferAnswerOptions.h +++ b/Source/WebCore/Modules/mediastream/RTCOfferAnswerOptions.h @@ -1,5 +1,6 @@ /* * Copyright (C) 2014 Apple Inc. All rights reserved. + * Copyright (C) 2015 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,45 +31,55 @@ #include "Dictionary.h" #include "ExceptionCode.h" -#include "RTCOfferAnswerOptionsPrivate.h" -#include +#include #include namespace WebCore { class Dictionary; +// FIXME: The WebRTC spec (as of 2015-04-13) only has a RTCOfferOptions, but a pending pull request +// reintroduces RTCOfferAnswerOptions as a common base for RTCOfferOptions and RTCAnswerOptions. +// This feature needs to be updated accordingly when that discussion is resolved. class RTCOfferAnswerOptions : public RefCounted { public: - static RefPtr create(const Dictionary&, ExceptionCode&); - - const String& requestIdentity() const { return m_private->requestIdentity(); } - RTCOfferAnswerOptionsPrivate* privateOfferAnswerOptions() const { return m_private.get(); } - virtual ~RTCOfferAnswerOptions() { } + bool voiceActivityDetection() const { return m_voiceActivityDetection; } + protected: virtual bool initialize(const Dictionary&); - RTCOfferAnswerOptions() { } + RTCOfferAnswerOptions(); - RefPtr m_private; + bool m_voiceActivityDetection; }; class RTCOfferOptions : public RTCOfferAnswerOptions { public: static RefPtr create(const Dictionary&, ExceptionCode&); + virtual ~RTCOfferOptions() { } - int64_t offerToReceiveVideo() const { return privateOfferOptions()->offerToReceiveVideo(); } - int64_t offerToReceiveAudio() const { return privateOfferOptions()->offerToReceiveAudio(); } - bool voiceActivityDetection() const { return privateOfferOptions()->voiceActivityDetection(); } - bool iceRestart() const { return privateOfferOptions()->iceRestart(); } - RTCOfferOptionsPrivate* privateOfferOptions() const { return static_cast(m_private.get()); } + int64_t offerToReceiveVideo() const { return m_offerToReceiveVideo; } + int64_t offerToReceiveAudio() const { return m_offerToReceiveAudio; } + bool iceRestart() const { return m_iceRestart; } - virtual ~RTCOfferOptions() { } +private: + virtual bool initialize(const Dictionary&) override; + RTCOfferOptions(); + + int64_t m_offerToReceiveVideo; + int64_t m_offerToReceiveAudio; + bool m_iceRestart; +}; + +class RTCAnswerOptions : public RTCOfferAnswerOptions { +public: + static RefPtr create(const Dictionary&, ExceptionCode&); + virtual ~RTCAnswerOptions() { } private: virtual bool initialize(const Dictionary&) override; - RTCOfferOptions() { } + RTCAnswerOptions() { } }; } // namespace WebCore diff --git a/Source/WebCore/Modules/mediastream/RTCPeerConnection.cpp b/Source/WebCore/Modules/mediastream/RTCPeerConnection.cpp index 8fd6934068ba3..3c8efe0ef7fb0 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 Ericsson AB. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -35,149 +36,59 @@ #include "RTCPeerConnection.h" -#include "ArrayValue.h" +#include "DOMError.h" #include "Document.h" #include "Event.h" #include "ExceptionCode.h" #include "Frame.h" -#include "FrameLoader.h" -#include "FrameLoaderClient.h" -#include "MediaStreamEvent.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 "RTCOfferAnswerOptions.h" -#include "RTCPeerConnectionErrorCallback.h" +#include "RTCRtpReceiver.h" +#include "RTCRtpSender.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 "RTCTrackEvent.h" #include +#include namespace WebCore { -static bool validateIceServerURL(const String& iceURL) -{ - URL url(URL(), iceURL); - if (url.isEmpty() || !url.isValid() || !(url.protocolIs("turn") || url.protocolIs("stun"))) - return false; - - return true; -} - -static ExceptionCode processIceServer(const Dictionary& iceServer, RTCConfiguration* rtcConfiguration) -{ - String credential, username; - iceServer.get("credential", credential); - iceServer.get("username", username); - - // Spec says that "urls" can be either a string or a sequence, so we must check for both. - Vector urlsList; - String urlString; - iceServer.get("urls", urlString); - // This is the only way to check if "urls" is a sequence or a string. If we try to convert - // to a sequence and it fails (in case it is a string), an exception will be set and the - // RTCPeerConnection will fail. - // So we convert to a string always, which converts a sequence to a string in the format: "foo, bar, ..", - // then checking for a comma in the string assures that a string was a sequence and then we convert - // it to a sequence safely. - if (urlString.isEmpty()) - return INVALID_ACCESS_ERR; - - if (urlString.find(',') != notFound && iceServer.get("urls", urlsList) && urlsList.size()) { - for (auto& url : urlsList) { - if (!validateIceServerURL(url)) - return INVALID_ACCESS_ERR; - } - } else { - if (!validateIceServerURL(urlString)) - return INVALID_ACCESS_ERR; - - urlsList.append(urlString); - } - - rtcConfiguration->appendServer(RTCIceServer::create(urlsList, credential, username)); - return 0; -} - -RefPtr 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; - } - - size_t numberOfServers; - ok = iceServers.length(numberOfServers); - if (!ok || !numberOfServers) { - ec = !ok ? TYPE_MISMATCH_ERR : INVALID_ACCESS_ERR; - return nullptr; - } - - String iceTransports; - String requestIdentity; - configuration.get("iceTransports", iceTransports); - configuration.get("requestIdentity", requestIdentity); - - RefPtr rtcConfiguration = RTCConfiguration::create(); - - rtcConfiguration->setIceTransports(iceTransports); - rtcConfiguration->setRequestIdentity(requestIdentity); - - for (size_t i = 0; i < numberOfServers; ++i) { - Dictionary iceServer; - ok = iceServers.get(i, iceServer); - if (!ok) { - ec = TYPE_MISMATCH_ERR; - return nullptr; - } - - ec = processIceServer(iceServer, rtcConfiguration.get()); - if (ec) - return nullptr; - } - - return rtcConfiguration; -} +using namespace PeerConnectionStates; RefPtr RTCPeerConnection::create(ScriptExecutionContext& context, const Dictionary& rtcConfiguration, ExceptionCode& ec) { - RefPtr configuration = parseConfiguration(rtcConfiguration, ec); + printf("-> RTCConfiguration::create\n"); + + RefPtr configuration = RTCConfiguration::create(rtcConfiguration, ec); if (ec) return nullptr; + printf("RTCPeerConnection: config was ok\n"); + RefPtr peerConnection = adoptRef(new RTCPeerConnection(context, configuration.release(), ec)); peerConnection->suspendIfNeeded(); if (ec) return nullptr; - return peerConnection.release(); + printf("RTCPeerConnection: before release\n"); + return peerConnection; } RTCPeerConnection::RTCPeerConnection(ScriptExecutionContext& context, PassRefPtr configuration, ExceptionCode& ec) : ActiveDOMObject(&context) - , m_signalingState(SignalingStateStable) - , m_iceGatheringState(IceGatheringStateNew) - , m_iceConnectionState(IceConnectionStateNew) + , m_signalingState(SignalingState::Stable) + , m_iceGatheringState(IceGatheringState::New) + , m_iceConnectionState(IceConnectionState::New) , m_scheduledEventTimer(*this, &RTCPeerConnection::scheduledEventTimerFired) , m_configuration(configuration) , m_stopped(false) { + printf("-> RTCConfiguration::RTCConfiguration\n"); + Document& document = downcast(context); if (!document.frame()) { @@ -185,226 +96,216 @@ RTCPeerConnection::RTCPeerConnection(ScriptExecutionContext& context, PassRefPtr return; } - m_peerHandler = RTCPeerConnectionHandler::create(this); - if (!m_peerHandler) { + m_backend = PeerConnectionBackend::create(this); + if (!m_backend) { ec = NOT_SUPPORTED_ERR; return; } - document.frame()->loader().client().dispatchWillStartUsingPeerConnectionHandler(m_peerHandler.get()); - - if (!m_peerHandler->initialize(m_configuration->privateConfiguration())) { - ec = NOT_SUPPORTED_ERR; - return; - } + m_backend->setConfiguration(*m_configuration); } RTCPeerConnection::~RTCPeerConnection() { stop(); +} + +Vector> RTCPeerConnection::getSenders() const +{ + Vector> senders; + for (auto& sender : m_senderSet.values()) + senders.append(sender); + + return senders; +} - for (auto& localStream : m_localStreams) - localStream->removeObserver(this); +Vector> RTCPeerConnection::getReceivers() const +{ + Vector> receivers; + for (auto& receiver : m_receiverSet.values()) + receivers.append(receiver); + + return receivers; } -void RTCPeerConnection::createOffer(PassRefPtr successCallback, PassRefPtr errorCallback, const Dictionary& offerOptions, ExceptionCode& ec) +RefPtr RTCPeerConnection::addTrack(RefPtr&& track, const MediaStream* stream, ExceptionCode& ec) { - if (m_signalingState == SignalingStateClosed) { + if (m_signalingState == SignalingState::Closed) { ec = INVALID_STATE_ERR; - return; + return nullptr; } - if (!successCallback) { - ec = TYPE_MISMATCH_ERR; - return; + if (m_senderSet.contains(track->id())) { + // FIXME: Spec says InvalidParameter + ec = INVALID_MODIFICATION_ERR; + return nullptr; } - RefPtr options = RTCOfferOptions::create(offerOptions, ec); - if (ec) { - callOnMainThread([=] { - RefPtr error = DOMError::create("Invalid createOffer argument."); - errorCallback->handleEvent(error.get()); - }); - return; - } + RefPtr sender = RTCRtpSender::create(WTF::move(track), stream->id()); + m_senderSet.add(track->id(), sender); - RefPtr request = RTCSessionDescriptionRequestImpl::create(scriptExecutionContext(), successCallback, errorCallback); - m_peerHandler->createOffer(request.release(), options->privateOfferOptions()); + return sender; } -void RTCPeerConnection::createAnswer(PassRefPtr successCallback, PassRefPtr errorCallback, const Dictionary& answerOptions, ExceptionCode& ec) +void RTCPeerConnection::removeTrack(RTCRtpSender* sender, ExceptionCode& ec) { - if (m_signalingState == SignalingStateClosed) { + if (m_signalingState == SignalingState::Closed) { ec = INVALID_STATE_ERR; return; } - if (!successCallback) { - ec = TYPE_MISMATCH_ERR; + if (!m_senderSet.remove(sender->track()->id())) + return; + + // FIXME: Mark connection as needing negotiation. +} + +void RTCPeerConnection::createOffer(const Dictionary& offerOptions, OfferAnswerResolveCallback resolveCallback, RejectCallback rejectCallback) +{ + if (m_signalingState == SignalingState::Closed) { + RefPtr error = DOMError::create("InvalidStateError"); + rejectCallback(*error); return; } - RefPtr options = RTCOfferAnswerOptions::create(answerOptions, ec); + ExceptionCode ec = 0; + RefPtr options = RTCOfferOptions::create(offerOptions, ec); if (ec) { - callOnMainThread([=] { - RefPtr error = DOMError::create("Invalid createAnswer argument."); - errorCallback->handleEvent(error.get()); - }); + RefPtr error = DOMError::create("Invalid createOffer argument."); + rejectCallback(*error); return; } - RefPtr request = RTCSessionDescriptionRequestImpl::create(scriptExecutionContext(), successCallback, errorCallback); - m_peerHandler->createAnswer(request.release(), options->privateOfferAnswerOptions()); + m_backend->createOffer(options, resolveCallback, rejectCallback); } -bool RTCPeerConnection::checkStateForLocalDescription(RTCSessionDescription* localDescription) +void RTCPeerConnection::createAnswer(const Dictionary& answerOptions, OfferAnswerResolveCallback resolveCallback, RejectCallback rejectCallback) { - 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) { + RefPtr error = DOMError::create("InvalidStateError"); + rejectCallback(*error); + return; + } - return false; -} + ExceptionCode ec = 0; + RefPtr options = RTCAnswerOptions::create(answerOptions, ec); + if (ec) { + RefPtr error = DOMError::create("Invalid createAnswer argument."); + rejectCallback(*error); + return; + } -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; + if (!remoteDescription()) { + // FIXME: Error type? + RefPtr error = DOMError::create("InvalidStateError (no remote description)"); + rejectCallback(*error); + return; + } - return false; + m_backend->createAnswer(options, resolveCallback, rejectCallback); } -void RTCPeerConnection::setLocalDescription(PassRefPtr prpSessionDescription, PassRefPtr successCallback, PassRefPtr errorCallback, ExceptionCode& ec) +void RTCPeerConnection::setLocalDescription(RTCSessionDescription* description, VoidResolveCallback resolveCallback, RejectCallback rejectCallback) { - if (m_signalingState == SignalingStateClosed) { - ec = INVALID_STATE_ERR; + if (m_signalingState == SignalingState::Closed) { + RefPtr error = DOMError::create("InvalidStateError"); + rejectCallback(*error); return; } - RefPtr sessionDescription = prpSessionDescription; - if (!sessionDescription) { - ec = TYPE_MISMATCH_ERR; - return; - } + DescriptionType descriptionType = parseDescriptionType(description->type()); - if (!checkStateForLocalDescription(sessionDescription.get())) { - callOnMainThread([=] { - RefPtr error = DOMError::create(RTCPeerConnectionHandler::invalidSessionDescriptionErrorName()); - errorCallback->handleEvent(error.get()); - }); + SignalingState targetState = targetSignalingState(SetterTypeLocal, descriptionType); + if (targetState == SignalingState::Invalid) { + // FIXME: Error type? + RefPtr error = DOMError::create("InvalidSessionDescriptionError"); + rejectCallback(*error); return; } - RefPtr request = RTCVoidRequestImpl::create(scriptExecutionContext(), successCallback, errorCallback); - m_peerHandler->setLocalDescription(request.release(), sessionDescription->descriptor()); + m_backend->setLocalDescription(description, targetState, resolveCallback, rejectCallback); } -PassRefPtr RTCPeerConnection::localDescription(ExceptionCode& ec) +RefPtr RTCPeerConnection::localDescription() const { - RefPtr descriptor = m_peerHandler->localDescription(); - if (!descriptor) { - ec = INVALID_STATE_ERR; - return nullptr; - } - - RefPtr sessionDescription = RTCSessionDescription::create(descriptor.release()); - return sessionDescription.release(); + return m_backend->localDescription(); } -void RTCPeerConnection::setRemoteDescription(PassRefPtr prpSessionDescription, PassRefPtr successCallback, PassRefPtr errorCallback, ExceptionCode& ec) +void RTCPeerConnection::setRemoteDescription(RTCSessionDescription* description, VoidResolveCallback resolveCallback, RejectCallback rejectCallback) { - if (m_signalingState == SignalingStateClosed) { - ec = INVALID_STATE_ERR; + if (m_signalingState == SignalingState::Closed) { + RefPtr error = DOMError::create("InvalidStateError"); + rejectCallback(*error); return; } - RefPtr sessionDescription = prpSessionDescription; - if (!sessionDescription) { - ec = TYPE_MISMATCH_ERR; - return; - } + DescriptionType descriptionType = parseDescriptionType(description->type()); - if (!checkStateForRemoteDescription(sessionDescription.get())) { - callOnMainThread([=] { - RefPtr error = DOMError::create(RTCPeerConnectionHandler::invalidSessionDescriptionErrorName()); - errorCallback->handleEvent(error.get()); - }); + SignalingState targetState = targetSignalingState(SetterTypeRemote, descriptionType); + if (targetState == SignalingState::Invalid) { + // FIXME: Error type? + RefPtr error = DOMError::create("InvalidSessionDescriptionError"); + rejectCallback(*error); return; } - RefPtr request = RTCVoidRequestImpl::create(scriptExecutionContext(), successCallback, errorCallback); - m_peerHandler->setRemoteDescription(request.release(), sessionDescription->descriptor()); + m_backend->setRemoteDescription(description, targetState, resolveCallback, rejectCallback); } -PassRefPtr RTCPeerConnection::remoteDescription(ExceptionCode& ec) +RefPtr RTCPeerConnection::remoteDescription() const { - RefPtr descriptor = m_peerHandler->remoteDescription(); - if (!descriptor) { - ec = INVALID_STATE_ERR; - return nullptr; - } - - RefPtr desc = RTCSessionDescription::create(descriptor.release()); - return desc.release(); + return m_backend->remoteDescription(); } void RTCPeerConnection::updateIce(const Dictionary& rtcConfiguration, ExceptionCode& ec) { - if (m_signalingState == SignalingStateClosed) { + if (m_signalingState == SignalingState::Closed) { ec = INVALID_STATE_ERR; return; } - m_configuration = parseConfiguration(rtcConfiguration, ec); + m_configuration = RTCConfiguration::create(rtcConfiguration, ec); if (ec) return; - bool valid = m_peerHandler->updateIce(m_configuration->privateConfiguration()); - if (!valid) - ec = SYNTAX_ERR; + m_backend->setConfiguration(*m_configuration); } -void RTCPeerConnection::addIceCandidate(RTCIceCandidate* iceCandidate, PassRefPtr successCallback, PassRefPtr errorCallback, ExceptionCode& ec) +void RTCPeerConnection::addIceCandidate(RTCIceCandidate* rtcCandidate, VoidResolveCallback resolveCallback, RejectCallback rejectCallback) { - if (m_signalingState == SignalingStateClosed) { - ec = INVALID_STATE_ERR; + if (m_signalingState == SignalingState::Closed) { + RefPtr error = DOMError::create("InvalidStateError"); + rejectCallback(*error); return; } - if (!iceCandidate || !successCallback || !errorCallback) { - ec = TYPE_MISMATCH_ERR; + if (!remoteDescription()) { + // FIXME: Error type? + RefPtr error = DOMError::create("InvalidStateError (no remote description)"); + rejectCallback(*error); return; } - RefPtr request = RTCVoidRequestImpl::create(scriptExecutionContext(), successCallback, errorCallback); - - bool implemented = m_peerHandler->addIceCandidate(request.release(), iceCandidate->descriptor()); - if (!implemented) - ec = SYNTAX_ERR; + m_backend->addIceCandidate(rtcCandidate, resolveCallback, rejectCallback); } 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"); + case SignalingState::Invalid: + break; } ASSERT_NOT_REACHED(); @@ -414,11 +315,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"); } @@ -429,19 +330,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"); } @@ -449,230 +350,31 @@ String RTCPeerConnection::iceConnectionState() const return String(); } -void RTCPeerConnection::addStream(PassRefPtr prpStream, ExceptionCode& ec) -{ - if (m_signalingState == SignalingStateClosed) { - ec = INVALID_STATE_ERR; - return; - } - - RefPtr stream = prpStream; - if (!stream) { - ec = TYPE_MISMATCH_ERR; - return; - } - - if (m_localStreams.contains(stream)) - return; - - bool valid = m_peerHandler->addStream(stream->privateStream()); - if (!valid) - ec = SYNTAX_ERR; - else { - m_localStreams.append(stream); - stream->addObserver(this); - } -} - -void RTCPeerConnection::removeStream(PassRefPtr prpStream, ExceptionCode& ec) -{ - if (m_signalingState == SignalingStateClosed) { - ec = INVALID_STATE_ERR; - return; - } - - if (!prpStream) { - ec = TYPE_MISMATCH_ERR; - return; - } - - RefPtr 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()); -} - RTCConfiguration* RTCPeerConnection::getConfiguration() const { return m_configuration.get(); } -Vector> RTCPeerConnection::getLocalStreams() const -{ - return m_localStreams; -} - -Vector> RTCPeerConnection::getRemoteStreams() const -{ - return m_remoteStreams; -} - -MediaStream* RTCPeerConnection::getStreamById(const String& streamId) -{ - for (auto& localStream : m_localStreams) { - if (localStream->id() == streamId) - return localStream.get(); - } - - for (auto& remoteStream : m_remoteStreams) { - if (remoteStream->id() == streamId) - return remoteStream.get(); - } - - return nullptr; -} - -void RTCPeerConnection::getStats(PassRefPtr successCallback, PassRefPtr errorCallback, PassRefPtr selector) +void RTCPeerConnection::getStats(PassRefPtr, PassRefPtr, PassRefPtr) { - RefPtr statsRequest = RTCStatsRequestImpl::create(scriptExecutionContext(), successCallback, errorCallback, &selector->privateTrack()); - // FIXME: Add passing selector as part of the statsRequest. - m_peerHandler->getStats(statsRequest.release()); } -PassRefPtr RTCPeerConnection::createDataChannel(String label, const Dictionary& options, ExceptionCode& ec) +PassRefPtr RTCPeerConnection::createDataChannel(String, const Dictionary&, ExceptionCode& ec) { - if (m_signalingState == SignalingStateClosed) { + if (m_signalingState == SignalingState::Closed) { ec = INVALID_STATE_ERR; return nullptr; } - RefPtr channel = RTCDataChannel::create(scriptExecutionContext(), m_peerHandler.get(), label, options, ec); - if (ec) - return nullptr; - - m_dataChannels.append(channel); - return channel.release(); -} - -bool RTCPeerConnection::hasLocalStreamWithTrackId(const String& trackId) -{ - for (auto& localStream : m_localStreams) { - if (localStream->getTrackById(trackId)) - return true; - } - return false; -} - -PassRefPtr RTCPeerConnection::createDTMFSender(PassRefPtr prpTrack, ExceptionCode& ec) -{ - if (m_signalingState == SignalingStateClosed) { - ec = INVALID_STATE_ERR; - return nullptr; - } - - if (!prpTrack) { - ec = TypeError; - return nullptr; - } - - RefPtr track = prpTrack; - - if (!hasLocalStreamWithTrackId(track->id())) { - ec = SYNTAX_ERR; - return nullptr; - } - - RefPtr 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; - return; - } - - m_peerHandler->stop(); - - changeIceConnectionState(IceConnectionStateClosed); - changeIceGatheringState(IceGatheringStateComplete); - changeSignalingState(SignalingStateClosed); -} - -void RTCPeerConnection::negotiationNeeded() -{ - scheduleDispatchEvent(Event::create(eventNames().negotiationneededEvent, false, false)); -} - -void RTCPeerConnection::didGenerateIceCandidate(PassRefPtr iceCandidateDescriptor) -{ - ASSERT(scriptExecutionContext()->isContextThread()); - if (!iceCandidateDescriptor) - scheduleDispatchEvent(RTCIceCandidateEvent::create(false, false, 0)); - else { - RefPtr iceCandidate = RTCIceCandidate::create(iceCandidateDescriptor); - scheduleDispatchEvent(RTCIceCandidateEvent::create(false, false, iceCandidate.release())); - } -} - -void RTCPeerConnection::didChangeSignalingState(SignalingState newState) -{ - ASSERT(scriptExecutionContext()->isContextThread()); - changeSignalingState(newState); -} - -void RTCPeerConnection::didChangeIceGatheringState(IceGatheringState newState) -{ - ASSERT(scriptExecutionContext()->isContextThread()); - changeIceGatheringState(newState); -} - -void RTCPeerConnection::didChangeIceConnectionState(IceConnectionState newState) -{ - ASSERT(scriptExecutionContext()->isContextThread()); - changeIceConnectionState(newState); -} - -void RTCPeerConnection::didAddRemoteStream(PassRefPtr privateStream) -{ - ASSERT(scriptExecutionContext()->isContextThread()); - - if (m_signalingState == SignalingStateClosed) - return; - - RefPtr stream = MediaStream::create(*scriptExecutionContext(), privateStream); - m_remoteStreams.append(stream); - - scheduleDispatchEvent(MediaStreamEvent::create(eventNames().addstreamEvent, false, false, stream.release())); -} - -void RTCPeerConnection::didRemoveRemoteStream(MediaStreamPrivate* privateStream) -{ - ASSERT(scriptExecutionContext()->isContextThread()); - ASSERT(privateStream->client()); - - // FIXME: this class shouldn't know that the private stream client is a MediaStream! - RefPtr stream = static_cast(privateStream->client()); - - 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())); + return nullptr; } -void RTCPeerConnection::didAddRemoteDataChannel(std::unique_ptr handler) +void RTCPeerConnection::close() { - ASSERT(scriptExecutionContext()->isContextThread()); - - if (m_signalingState == SignalingStateClosed) + if (m_signalingState == SignalingState::Closed) return; - RefPtr channel = RTCDataChannel::create(scriptExecutionContext(), WTF::move(handler)); - m_dataChannels.append(channel); - - scheduleDispatchEvent(RTCDataChannelEvent::create(eventNames().datachannelEvent, false, false, channel.release())); + m_signalingState = SignalingState::Closed; } void RTCPeerConnection::stop() @@ -681,11 +383,47 @@ void RTCPeerConnection::stop() return; m_stopped = true; - m_iceConnectionState = IceConnectionStateClosed; - m_signalingState = SignalingStateClosed; + m_iceConnectionState = IceConnectionState::Closed; + m_signalingState = SignalingState::Closed; +} - for (auto& channel : m_dataChannels) - channel->stop(); +SignalingState RTCPeerConnection::targetSignalingState(SetterType setter, DescriptionType description) const +{ + // "map" describing the valid state transitions + switch (m_signalingState) { + case SignalingState::Stable: + if (setter == SetterTypeLocal && description == DescriptionTypeOffer) + return SignalingState::HaveLocalOffer; + if (setter == SetterTypeRemote && description == DescriptionTypeOffer) + return SignalingState::HaveRemoteOffer; + break; + case SignalingState::HaveLocalOffer: + if (setter == SetterTypeLocal && description == DescriptionTypeOffer) + return SignalingState::HaveLocalOffer; + if (setter == SetterTypeRemote && description == DescriptionTypeAnswer) + return SignalingState::Stable; + break; + case SignalingState::HaveRemoteOffer: + if (setter == SetterTypeLocal && description == DescriptionTypeAnswer) + return SignalingState::Stable; + if (setter == SetterTypeRemote && description == DescriptionTypeOffer) + return SignalingState::HaveRemoteOffer; + break; + default: + break; + }; + return SignalingState::Invalid; +} + +RTCPeerConnection::DescriptionType RTCPeerConnection::parseDescriptionType(const String& typeName) const +{ + if (typeName == "offer") + return DescriptionTypeOffer; + if (typeName == "pranswer") + return DescriptionTypePranswer; + + ASSERT(typeName == "answer"); + return DescriptionTypeAnswer; } const char* RTCPeerConnection::activeDOMObjectName() const @@ -699,14 +437,9 @@ bool RTCPeerConnection::canSuspendForPageCache() const return false; } -void RTCPeerConnection::didAddOrRemoveTrack() -{ - negotiationNeeded(); -} - void RTCPeerConnection::changeSignalingState(SignalingState signalingState) { - if (m_signalingState != SignalingStateClosed && m_signalingState != signalingState) { + if (m_signalingState != SignalingState::Closed && m_signalingState != signalingState) { m_signalingState = signalingState; scheduleDispatchEvent(Event::create(eventNames().signalingstatechangeEvent, false, false)); } @@ -719,7 +452,7 @@ void RTCPeerConnection::changeIceGatheringState(IceGatheringState iceGatheringSt void RTCPeerConnection::changeIceConnectionState(IceConnectionState iceConnectionState) { - if (m_iceConnectionState != IceConnectionStateClosed && m_iceConnectionState != iceConnectionState) { + if (m_iceConnectionState != IceConnectionState::Closed && m_iceConnectionState != iceConnectionState) { m_iceConnectionState = iceConnectionState; scheduleDispatchEvent(Event::create(eventNames().iceconnectionstatechangeEvent, false, false)); } @@ -741,8 +474,9 @@ void RTCPeerConnection::scheduledEventTimerFired() Vector> events; events.swap(m_scheduledEvents); - for (auto& event : events) - dispatchEvent(event.release()); + Vector>::iterator it = events.begin(); + for (; it != events.end(); ++it) + dispatchEvent((*it).release()); events.clear(); } diff --git a/Source/WebCore/Modules/mediastream/RTCPeerConnection.h b/Source/WebCore/Modules/mediastream/RTCPeerConnection.h index 52dc7930b0426..0129ad57560eb 100644 --- a/Source/WebCore/Modules/mediastream/RTCPeerConnection.h +++ b/Source/WebCore/Modules/mediastream/RTCPeerConnection.h @@ -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 Ericsson AB. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -37,99 +38,98 @@ #include "ActiveDOMObject.h" #include "Dictionary.h" #include "EventTarget.h" -#include "ExceptionBase.h" -#include "MediaStream.h" -#include "RTCIceCandidate.h" -#include "RTCPeerConnectionHandler.h" -#include "RTCPeerConnectionHandlerClient.h" +#include "PeerConnectionBackend.h" #include "ScriptWrappable.h" #include "Timer.h" +#include #include namespace WebCore { +class MediaStream; class MediaStreamTrack; +class PeerConnectionBackend; class RTCConfiguration; -class RTCDTMFSender; class RTCDataChannel; +class RTCIceCandidate; class RTCPeerConnectionErrorCallback; +class RTCRtpReceiver; +class RTCRtpSender; class RTCSessionDescription; -class RTCSessionDescriptionCallback; class RTCStatsCallback; -class VoidCallback; -class RTCPeerConnection final : public RefCounted, public ScriptWrappable, public RTCPeerConnectionHandlerClient, public EventTargetWithInlineData, public ActiveDOMObject, public MediaStream::Observer { +class RTCPeerConnection final : public RefCounted, public ScriptWrappable, public PeerConnectionBackendClient, public EventTargetWithInlineData, public ActiveDOMObject { public: static RefPtr create(ScriptExecutionContext&, const Dictionary& rtcConfiguration, ExceptionCode&); ~RTCPeerConnection(); - void createOffer(PassRefPtr, PassRefPtr, const Dictionary& offerOptions, ExceptionCode&); + typedef std::function OfferAnswerResolveCallback; + typedef std::function VoidResolveCallback; + typedef std::function RejectCallback; - void createAnswer(PassRefPtr, PassRefPtr, const Dictionary& answerOptions, ExceptionCode&); + Vector> getSenders() const; + Vector> getReceivers() const; - void setLocalDescription(PassRefPtr, PassRefPtr, PassRefPtr, ExceptionCode&); - PassRefPtr localDescription(ExceptionCode&); + RefPtr addTrack(RefPtr&&, const MediaStream* stream, ExceptionCode&); + void removeTrack(RTCRtpSender*, ExceptionCode&); - void setRemoteDescription(PassRefPtr, PassRefPtr, PassRefPtr, ExceptionCode&); - PassRefPtr remoteDescription(ExceptionCode&); + void createOffer(const Dictionary& offerOptions, OfferAnswerResolveCallback, RejectCallback); + void createAnswer(const Dictionary& answerOptions, OfferAnswerResolveCallback, RejectCallback); + + void setLocalDescription(RTCSessionDescription*, VoidResolveCallback, RejectCallback); + RefPtr localDescription() const; + + void setRemoteDescription(RTCSessionDescription*, VoidResolveCallback, RejectCallback); + RefPtr remoteDescription() const; String signalingState() const; void updateIce(const Dictionary& rtcConfiguration, ExceptionCode&); - - void addIceCandidate(RTCIceCandidate*, PassRefPtr, PassRefPtr, ExceptionCode&); + void addIceCandidate(RTCIceCandidate*, VoidResolveCallback, RejectCallback); String iceGatheringState() const; - String iceConnectionState() const; RTCConfiguration* getConfiguration() const; - Vector> getLocalStreams() const; - - Vector> getRemoteStreams() const; - - MediaStream* getStreamById(const String& streamId); - - void addStream(PassRefPtr, ExceptionCode&); - - void removeStream(PassRefPtr, ExceptionCode&); - void getStats(PassRefPtr successCallback, PassRefPtr, PassRefPtr selector); PassRefPtr createDataChannel(String label, const Dictionary& dataChannelDict, ExceptionCode&); - PassRefPtr createDTMFSender(PassRefPtr, ExceptionCode&); - - void close(ExceptionCode&); - - // RTCPeerConnectionHandlerClient - virtual void negotiationNeeded() override; - virtual void didGenerateIceCandidate(PassRefPtr) override; - virtual void didChangeSignalingState(SignalingState) override; - virtual void didChangeIceGatheringState(IceGatheringState) override; - virtual void didChangeIceConnectionState(IceConnectionState) override; - virtual void didAddRemoteStream(PassRefPtr) override; - virtual void didRemoveRemoteStream(MediaStreamPrivate*) override; - virtual void didAddRemoteDataChannel(std::unique_ptr) override; + void close(); // EventTarget virtual EventTargetInterface eventTargetInterface() const override { return RTCPeerConnectionEventTargetInterfaceType; } virtual ScriptExecutionContext* scriptExecutionContext() const override { return ActiveDOMObject::scriptExecutionContext(); } - // MediaStream::Observer - virtual void didAddOrRemoveTrack() override; - using RefCounted::ref; using RefCounted::deref; private: + enum SetterType { + SetterTypeLocal = 1, + SetterTypeRemote = 2 + }; + + enum DescriptionType { + DescriptionTypeOffer = 1, + DescriptionTypePranswer = 2, + DescriptionTypeAnswer = 3 + }; + RTCPeerConnection(ScriptExecutionContext&, PassRefPtr, ExceptionCode&); - static RefPtr parseConfiguration(const Dictionary& configuration, ExceptionCode&); + PeerConnectionStates::SignalingState targetSignalingState(SetterType, DescriptionType) const; + DescriptionType parseDescriptionType(const String& typeName) const; + + enum ResolveSetLocalDescriptionResult { + LocalConfigurationIncomplete, + SetLocalDescriptionResolvedSuccessfully, + SetLocalDescriptionAlreadyResolved + }; + void scheduleDispatchEvent(PassRefPtr); void scheduledEventTimerFired(); - bool hasLocalStreamWithTrackId(const String& trackId); // EventTarget implementation. virtual void refEventTarget() override { ref(); } @@ -140,23 +140,24 @@ class RTCPeerConnection final : public RefCounted, public Scr const char* activeDOMObjectName() const override; bool canSuspendForPageCache() const override; - void changeSignalingState(SignalingState); - void changeIceGatheringState(IceGatheringState); - void changeIceConnectionState(IceConnectionState); + void changeSignalingState(PeerConnectionStates::SignalingState); + void changeIceGatheringState(PeerConnectionStates::IceGatheringState); + void changeIceConnectionState(PeerConnectionStates::IceConnectionState); - bool checkStateForLocalDescription(RTCSessionDescription*); - bool checkStateForRemoteDescription(RTCSessionDescription*); + // PeerConnectionBackendClient + ScriptExecutionContext* context() const override { return scriptExecutionContext(); }; + PeerConnectionStates::SignalingState internalSignalingState() const { return m_signalingState; } - SignalingState m_signalingState; - IceGatheringState m_iceGatheringState; - IceConnectionState m_iceConnectionState; + PeerConnectionStates::SignalingState m_signalingState; + PeerConnectionStates::IceGatheringState m_iceGatheringState; + PeerConnectionStates::IceConnectionState m_iceConnectionState; - Vector> m_localStreams; - Vector> m_remoteStreams; + HashMap> m_senderSet; + HashMap> m_receiverSet; Vector> m_dataChannels; - std::unique_ptr m_peerHandler; + std::unique_ptr m_backend; Timer m_scheduledEventTimer; Vector> m_scheduledEvents; diff --git a/Source/WebCore/Modules/mediastream/RTCPeerConnection.idl b/Source/WebCore/Modules/mediastream/RTCPeerConnection.idl index 8b2207e9fac53..0394126c89065 100644 --- a/Source/WebCore/Modules/mediastream/RTCPeerConnection.idl +++ b/Source/WebCore/Modules/mediastream/RTCPeerConnection.idl @@ -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 Ericsson AB. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -35,51 +36,44 @@ CustomConstructor(Dictionary rtcConfiguration), ConstructorCallWith=ScriptExecutionContext, ConstructorRaisesException, - ConstructorCallWith=ScriptExecutionContext, EventTarget, InterfaceName=webkitRTCPeerConnection, ] interface RTCPeerConnection { - [RaisesException] void createOffer(RTCSessionDescriptionCallback successCallback, RTCPeerConnectionErrorCallback failureCallback, optional Dictionary offerOptions); - [RaisesException] void createAnswer(RTCSessionDescriptionCallback successCallback, RTCPeerConnectionErrorCallback failureCallback, optional Dictionary answerOptions); + [Custom, RaisesException] Promise createOffer(optional Dictionary offerOptions); + [Custom, RaisesException] Promise createAnswer(optional Dictionary answerOptions); + + sequence getSenders(); - [RaisesException] void setLocalDescription(RTCSessionDescription description, VoidCallback successCallback, RTCPeerConnectionErrorCallback failureCallback); - [GetterRaisesException] readonly attribute RTCSessionDescription localDescription; + [StrictTypeChecking, RaisesException] RTCRtpSender addTrack(MediaStreamTrack track, MediaStream stream); + [StrictTypeChecking, RaisesException] void removeTrack(RTCRtpSender sender); - [RaisesException] void setRemoteDescription(RTCSessionDescription description, VoidCallback successCallback, RTCPeerConnectionErrorCallback failureCallback); - [GetterRaisesException] readonly attribute RTCSessionDescription remoteDescription; + [Custom, RaisesException] Promise setLocalDescription(RTCSessionDescription description); + readonly attribute RTCSessionDescription localDescription; + + [Custom, RaisesException] Promise setRemoteDescription(RTCSessionDescription description); + readonly attribute RTCSessionDescription remoteDescription; readonly attribute DOMString signalingState; [RaisesException] void updateIce(Dictionary configuration); - - [RaisesException] void addIceCandidate(RTCIceCandidate candidate, VoidCallback successCallback, RTCPeerConnectionErrorCallback failureCallback); + [Custom, RaisesException] Promise addIceCandidate(RTCIceCandidate candidate); readonly attribute DOMString iceGatheringState; readonly attribute DOMString iceConnectionState; - sequence getLocalStreams(); - sequence getRemoteStreams(); - MediaStream getStreamById(DOMString streamId); - RTCConfiguration getConfiguration(); - [StrictTypeChecking, RaisesException] void addStream(MediaStream stream); - [StrictTypeChecking, RaisesException] void removeStream(MediaStream stream); - void getStats(RTCStatsCallback successCallback, RTCPeerConnectionErrorCallback failureCallback, [Default=Undefined] optional MediaStreamTrack selector); [RaisesException] RTCDataChannel createDataChannel([TreatNullAs=NullString, TreatUndefinedAs=NullString] DOMString label, optional Dictionary options); - [RaisesException] RTCDTMFSender createDTMFSender(MediaStreamTrack track); - - [RaisesException] void close(); + void close(); attribute EventHandler onnegotiationneeded; attribute EventHandler onicecandidate; attribute EventHandler onsignalingstatechange; - attribute EventHandler onaddstream; - attribute EventHandler onremovestream; + attribute EventHandler ontrack; attribute EventHandler oniceconnectionstatechange; attribute EventHandler ondatachannel; diff --git a/Source/WebCore/Modules/mediastream/RTCRtpReceiver.cpp b/Source/WebCore/Modules/mediastream/RTCRtpReceiver.cpp new file mode 100644 index 0000000000000..710a7edd219f3 --- /dev/null +++ b/Source/WebCore/Modules/mediastream/RTCRtpReceiver.cpp @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2015 Ericsson AB. All rights reserved. + * + * 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. + * 3. Neither the name of Ericsson nor the names of its contributors + * may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT + * OWNER OR 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 "RTCRtpReceiver.h" + +#if ENABLE(MEDIA_STREAM) + +namespace WebCore { + +Ref RTCRtpReceiver::create(RefPtr&& track) +{ + return adoptRef(*new RTCRtpReceiver(WTF::move(track))); +} + +RTCRtpReceiver::RTCRtpReceiver(RefPtr&& track) + : RTCRtpSenderReceiverBase(WTF::move(track)) +{ +} + +RTCRtpReceiver::~RTCRtpReceiver() +{ +} + +} // namespace WebCore + +#endif // ENABLE(MEDIA_STREAM) diff --git a/Source/WebCore/Modules/mediastream/RTCRtpReceiver.h b/Source/WebCore/Modules/mediastream/RTCRtpReceiver.h new file mode 100644 index 0000000000000..520930aa43d5b --- /dev/null +++ b/Source/WebCore/Modules/mediastream/RTCRtpReceiver.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2015 Ericsson AB. All rights reserved. + * + * 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. + * 3. Neither the name of Ericsson nor the names of its contributors + * may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT + * OWNER OR 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. + */ + +#ifndef RTCRtpReceiver_h +#define RTCRtpReceiver_h + +#if ENABLE(MEDIA_STREAM) + +#include "RTCRtpSenderReceiverBase.h" + +namespace WebCore { + +class RTCRtpReceiver : public RTCRtpSenderReceiverBase { +public: + static Ref create(RefPtr&&); + virtual ~RTCRtpReceiver(); + +private: + RTCRtpReceiver(RefPtr&&); +}; + +} // namespace WebCore + +#endif // ENABLE(MEDIA_STREAM) + +#endif // RTCRtpReceiver_h diff --git a/Source/WebCore/Modules/mediastream/RTCRtpReceiver.idl b/Source/WebCore/Modules/mediastream/RTCRtpReceiver.idl new file mode 100644 index 0000000000000..bd97c6993d48e --- /dev/null +++ b/Source/WebCore/Modules/mediastream/RTCRtpReceiver.idl @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2015 Ericsson AB. All rights reserved. + * + * 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. + * 3. Neither the name of Ericsson nor the names of its contributors + * may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT + * OWNER OR 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. + */ + +[ + Conditional=MEDIA_STREAM +] interface RTCRtpReceiver { + readonly attribute MediaStreamTrack track; +}; diff --git a/Source/WebCore/Modules/mediastream/RTCRtpSender.cpp b/Source/WebCore/Modules/mediastream/RTCRtpSender.cpp new file mode 100644 index 0000000000000..4720945f0e033 --- /dev/null +++ b/Source/WebCore/Modules/mediastream/RTCRtpSender.cpp @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2015 Ericsson AB. All rights reserved. + * + * 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. + * 3. Neither the name of Ericsson nor the names of its contributors + * may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT + * OWNER OR 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 "RTCRtpSender.h" + +#if ENABLE(MEDIA_STREAM) + +namespace WebCore { + +Ref RTCRtpSender::create(RefPtr&& track, const String& mediaStreamId) +{ + return adoptRef(*new RTCRtpSender(WTF::move(track), mediaStreamId)); +} + +RTCRtpSender::RTCRtpSender(RefPtr&& track, const String& mediaStreamId) + : RTCRtpSenderReceiverBase(WTF::move(track)) + , m_mediaStreamId(mediaStreamId) +{ +} + +RTCRtpSender::~RTCRtpSender() +{ +} + +} // namespace WebCore + +#endif // ENABLE(MEDIA_STREAM) diff --git a/Source/WebCore/Modules/mediastream/RTCRtpSender.h b/Source/WebCore/Modules/mediastream/RTCRtpSender.h new file mode 100644 index 0000000000000..df1081b7daaeb --- /dev/null +++ b/Source/WebCore/Modules/mediastream/RTCRtpSender.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2015 Ericsson AB. All rights reserved. + * + * 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. + * 3. Neither the name of Ericsson nor the names of its contributors + * may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT + * OWNER OR 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. + */ + +#ifndef RTCRtpSender_h +#define RTCRtpSender_h + +#if ENABLE(MEDIA_STREAM) + +#include "RTCRtpSenderReceiverBase.h" +#include + +namespace WebCore { + +class RTCRtpSender : public RTCRtpSenderReceiverBase { +public: + static Ref create(RefPtr&&, const String& mediaStreamId); + virtual ~RTCRtpSender(); + + const String& mediaStreamId() const { return m_mediaStreamId; } + +private: + RTCRtpSender(RefPtr&&, const String& mediaStreamId); + + String m_mediaStreamId; +}; + +} // namespace WebCore + +#endif // ENABLE(MEDIA_STREAM) + +#endif // RTCRtpSender_h diff --git a/Source/WebCore/Modules/mediastream/RTCRtpSender.idl b/Source/WebCore/Modules/mediastream/RTCRtpSender.idl new file mode 100644 index 0000000000000..8cb275537173b --- /dev/null +++ b/Source/WebCore/Modules/mediastream/RTCRtpSender.idl @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2015 Ericsson AB. All rights reserved. + * + * 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. + * 3. Neither the name of Ericsson nor the names of its contributors + * may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT + * OWNER OR 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. + */ + +[ + Conditional=MEDIA_STREAM +] interface RTCRtpSender { + readonly attribute MediaStreamTrack track; +}; diff --git a/Source/WebCore/Modules/mediastream/RTCRtpSenderReceiverBase.cpp b/Source/WebCore/Modules/mediastream/RTCRtpSenderReceiverBase.cpp new file mode 100644 index 0000000000000..90a2f19ae57ab --- /dev/null +++ b/Source/WebCore/Modules/mediastream/RTCRtpSenderReceiverBase.cpp @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2015 Ericsson AB. All rights reserved. + * + * 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. + * 3. Neither the name of Ericsson nor the names of its contributors + * may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT + * OWNER OR 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 "RTCRtpSenderReceiverBase.h" + +#if ENABLE(MEDIA_STREAM) + +#include "MediaStreamTrack.h" + +namespace WebCore { + +RTCRtpSenderReceiverBase::RTCRtpSenderReceiverBase(RefPtr&& track) + : m_track(track) +{ +} + +RTCRtpSenderReceiverBase::~RTCRtpSenderReceiverBase() +{ +} + +MediaStreamTrack* RTCRtpSenderReceiverBase::track() const +{ + return m_track.get(); +} + +} // namespace WebCore + +#endif // ENABLE(MEDIA_STREAM) diff --git a/Source/WebCore/Modules/mediastream/RTCRtpSenderReceiverBase.h b/Source/WebCore/Modules/mediastream/RTCRtpSenderReceiverBase.h new file mode 100644 index 0000000000000..e52da1157ddc8 --- /dev/null +++ b/Source/WebCore/Modules/mediastream/RTCRtpSenderReceiverBase.h @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2015 Ericsson AB. All rights reserved. + * + * 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. + * 3. Neither the name of Ericsson nor the names of its contributors + * may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT + * OWNER OR 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. + */ + +#ifndef RTCRtpSenderReceiverBase_h +#define RTCRtpSenderReceiverBase_h + +#if ENABLE(MEDIA_STREAM) + +#include "ScriptWrappable.h" +#include +#include + +namespace WebCore { + +class MediaStreamTrack; + +class RTCRtpSenderReceiverBase : public RefCounted, public ScriptWrappable { +public: + virtual ~RTCRtpSenderReceiverBase(); + + MediaStreamTrack* track() const; + +protected: + RTCRtpSenderReceiverBase(RefPtr&&); + + RefPtr m_track; +}; + +} // namespace WebCore + +#endif // ENABLE(MEDIA_STREAM) + +#endif // RTCRtpSenderReceiverBase_h diff --git a/Source/WebCore/Modules/mediastream/RTCSessionDescription.cpp b/Source/WebCore/Modules/mediastream/RTCSessionDescription.cpp index dd913111e8416..7f38bf578999a 100644 --- a/Source/WebCore/Modules/mediastream/RTCSessionDescription.cpp +++ b/Source/WebCore/Modules/mediastream/RTCSessionDescription.cpp @@ -65,13 +65,18 @@ RefPtr RTCSessionDescription::create(const Dictionary& di return adoptRef(*new RTCSessionDescription(RTCSessionDescriptionDescriptor::create(type, sdp))); } -RefPtr RTCSessionDescription::create(PassRefPtr descriptor) +RefPtr RTCSessionDescription::create(RefPtr descriptor) { ASSERT(descriptor); return adoptRef(*new RTCSessionDescription(descriptor)); } -RTCSessionDescription::RTCSessionDescription(PassRefPtr descriptor) +Ref RTCSessionDescription::create(const String& type, const String& sdp) +{ + return adoptRef(*new RTCSessionDescription(RTCSessionDescriptionDescriptor::create(type, sdp))); +} + +RTCSessionDescription::RTCSessionDescription(RefPtr descriptor) : m_descriptor(descriptor) { } diff --git a/Source/WebCore/Modules/mediastream/RTCSessionDescription.h b/Source/WebCore/Modules/mediastream/RTCSessionDescription.h index bcb335416bfa5..31c44062ae8df 100644 --- a/Source/WebCore/Modules/mediastream/RTCSessionDescription.h +++ b/Source/WebCore/Modules/mediastream/RTCSessionDescription.h @@ -35,8 +35,8 @@ #include "ExceptionBase.h" #include "ScriptWrappable.h" -#include #include +#include #include namespace WebCore { @@ -47,7 +47,8 @@ class RTCSessionDescriptionDescriptor; class RTCSessionDescription : public RefCounted, public ScriptWrappable { public: static RefPtr create(const Dictionary&, ExceptionCode&); - static RefPtr create(PassRefPtr); + static RefPtr create(RefPtr); + static Ref create(const String& type, const String& sdp); virtual ~RTCSessionDescription(); const String& type() const; @@ -59,7 +60,8 @@ class RTCSessionDescription : public RefCounted, public S RTCSessionDescriptionDescriptor* descriptor(); private: - explicit RTCSessionDescription(PassRefPtr); + explicit RTCSessionDescription(RefPtr); + explicit RTCSessionDescription(const String& type, const String& sdp); RefPtr m_descriptor; }; diff --git a/Source/WebCore/Modules/mediastream/RTCTrackEvent.cpp b/Source/WebCore/Modules/mediastream/RTCTrackEvent.cpp new file mode 100644 index 0000000000000..ce611ad29b2d9 --- /dev/null +++ b/Source/WebCore/Modules/mediastream/RTCTrackEvent.cpp @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2015 Ericsson AB. All rights reserved. + * + * 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. + * 3. Neither the name of Ericsson nor the names of its contributors + * may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT + * OWNER OR 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 "RTCTrackEvent.h" + +#if ENABLE(MEDIA_STREAM) + +#include "EventNames.h" +#include "MediaStreamTrack.h" +#include "RTCRtpReceiver.h" + +namespace WebCore { + +RTCTrackEventInit::RTCTrackEventInit() + : receiver(nullptr) + , track(nullptr) +{ +} + +Ref RTCTrackEvent::create() +{ + return adoptRef(*new RTCTrackEvent); +} + +Ref RTCTrackEvent::create(const AtomicString& type, bool canBubble, bool cancelable, RefPtr&& receiver, RefPtr&& track) +{ + return adoptRef(*new RTCTrackEvent(type, canBubble, cancelable, WTF::move(receiver), WTF::move(track))); +} + +Ref RTCTrackEvent::create(const AtomicString& type, const RTCTrackEventInit& initializer) +{ + return adoptRef(*new RTCTrackEvent(type, initializer)); +} + +RTCTrackEvent::RTCTrackEvent() +{ +} + +RTCTrackEvent::RTCTrackEvent(const AtomicString& type, bool canBubble, bool cancelable, RefPtr&& receiver, RefPtr&& track) + : Event(type, canBubble, cancelable) + , m_receiver(receiver) + , m_track(track) +{ +} + +RTCTrackEvent::RTCTrackEvent(const AtomicString& type, const RTCTrackEventInit& initializer) + : Event(type, initializer) + , m_receiver(initializer.receiver) + , m_track(initializer.track) +{ +} + +RTCTrackEvent::~RTCTrackEvent() +{ +} + +} // namespace WebCore + +#endif // ENABLE(MEDIA_STREAM) + diff --git a/Source/WebCore/Modules/mediastream/RTCTrackEvent.h b/Source/WebCore/Modules/mediastream/RTCTrackEvent.h new file mode 100644 index 0000000000000..b83e42056a0aa --- /dev/null +++ b/Source/WebCore/Modules/mediastream/RTCTrackEvent.h @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2015 Ericsson AB. All rights reserved. + * + * 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. + * 3. Neither the name of Ericsson nor the names of its contributors + * may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT + * OWNER OR 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. + */ + +#ifndef RTCTrackEvent_h +#define RTCTrackEvent_h + +#if ENABLE(MEDIA_STREAM) + +#include "Event.h" +// #include "MediaStreamTrack.h" +#include + +namespace WebCore { + +class MediaStreamTrack; +class RTCRtpReceiver; + +struct RTCTrackEventInit : public EventInit { + RTCTrackEventInit(); + + RefPtr receiver; + RefPtr track; +}; + +class RTCTrackEvent : public Event { +public: + virtual ~RTCTrackEvent(); + + static Ref create(); + static Ref create(const AtomicString& type, bool canBubble, bool cancelable, RefPtr&&, RefPtr&&); + static Ref create(const AtomicString& type, const RTCTrackEventInit&); + + RTCRtpReceiver* receiver() const { return m_receiver.get(); } + MediaStreamTrack* track() const { return m_track.get(); } + + virtual EventInterface eventInterface() const { return RTCTrackEventInterfaceType; } + +private: + RTCTrackEvent(); + RTCTrackEvent(const AtomicString& type, bool canBubble, bool cancelable, RefPtr&&, RefPtr&&); + RTCTrackEvent(const AtomicString& type, const RTCTrackEventInit&); + + RefPtr m_receiver; + RefPtr m_track; +}; + +} // namespace WebCore + +#endif // ENABLE(MEDIA_STREAM) + +#endif // RTCTrackEvent_h diff --git a/Source/WebCore/Modules/mediastream/RTCTrackEvent.idl b/Source/WebCore/Modules/mediastream/RTCTrackEvent.idl new file mode 100644 index 0000000000000..c8cbe00188b6e --- /dev/null +++ b/Source/WebCore/Modules/mediastream/RTCTrackEvent.idl @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2015 Ericsson AB. All rights reserved. + * + * 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. + * 3. Neither the name of Ericsson nor the names of its contributors + * may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT + * OWNER OR 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. + */ + +[ + Conditional=MEDIA_STREAM, + ConstructorTemplate=Event +] interface RTCTrackEvent : Event { + [InitializedByEventConstructor] readonly attribute RTCRtpReceiver receiver; + [InitializedByEventConstructor] readonly attribute MediaStreamTrack track; +}; + diff --git a/Source/WebCore/PlatformGTK.cmake b/Source/WebCore/PlatformGTK.cmake index bcba2c49e7e24..ee26c32984275 100644 --- a/Source/WebCore/PlatformGTK.cmake +++ b/Source/WebCore/PlatformGTK.cmake @@ -131,6 +131,7 @@ list(APPEND WebCore_SOURCES platform/graphics/gstreamer/InbandTextTrackPrivateGStreamer.cpp platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp platform/graphics/gstreamer/MediaPlayerPrivateGStreamerBase.cpp + platform/graphics/gstreamer/MediaPlayerPrivateGStreamerOwr.cpp platform/graphics/gstreamer/MediaSourceGStreamer.cpp platform/graphics/gstreamer/SourceBufferPrivateGStreamer.cpp platform/graphics/gstreamer/TextCombinerGStreamer.cpp @@ -187,6 +188,7 @@ list(APPEND WebCore_SOURCES platform/linux/GamepadDeviceLinux.cpp platform/linux/MemoryPressureHandlerLinux.cpp + platform/mediastream/openwebrtc/MediaEndpointOwr.cpp platform/mediastream/openwebrtc/OpenWebRTCUtilities.cpp platform/mediastream/openwebrtc/RealtimeMediaSourceCenterOwr.cpp diff --git a/Source/WebCore/PlatformWPE.cmake b/Source/WebCore/PlatformWPE.cmake index c797bf447724f..346351903338c 100644 --- a/Source/WebCore/PlatformWPE.cmake +++ b/Source/WebCore/PlatformWPE.cmake @@ -33,6 +33,7 @@ list(APPEND WebCore_INCLUDE_DIRECTORIES "${WEBCORE_DIR}/platform/graphics/opentype" "${WEBCORE_DIR}/platform/graphics/wayland" "${WEBCORE_DIR}/platform/linux" + "${WEBCORE_DIR}/platform/mediastream" "${WEBCORE_DIR}/platform/mediastream/openwebrtc" "${WEBCORE_DIR}/platform/mock/mediasource" "${WEBCORE_DIR}/platform/network/soup" @@ -129,8 +130,6 @@ list(APPEND WebCore_SOURCES platform/image-decoders/webp/WEBPImageDecoder.cpp platform/image-encoders/JPEGImageEncoder.cpp platform/linux/MemoryPressureHandlerLinux.cpp - platform/mediastream/openwebrtc/OpenWebRTCUtilities.cpp - platform/mediastream/openwebrtc/RealtimeMediaSourceCenterOwr.cpp platform/network/soup/AuthenticationChallengeSoup.cpp platform/network/soup/CertificateInfo.cpp platform/network/soup/CookieJarSoup.cpp @@ -388,3 +387,18 @@ if ((ENABLE_ENCRYPTED_MEDIA OR ENABLE_ENCRYPTED_MEDIA_V2) AND ENABLE_DXDRM) ) endif () endif () + +if (ENABLE_MEDIA_STREAM) + list(APPEND WebCore_SYSTEM_INCLUDE_DIRECTORIES + ${OPENWEBRTC_INCLUDE_DIRS} + ) + list(APPEND WebCore_LIBRARIES + ${OPENWEBRTC_LIBRARIES} + ) + list(APPEND WebCore_SOURCES + platform/graphics/gstreamer/MediaPlayerPrivateGStreamerOwr.cpp + platform/mediastream/openwebrtc/MediaEndpointOwr.cpp + platform/mediastream/openwebrtc/OpenWebRTCUtilities.cpp + platform/mediastream/openwebrtc/RealtimeMediaSourceCenterOwr.cpp + ) +endif () diff --git a/Source/WebCore/bindings/js/JSDictionary.cpp b/Source/WebCore/bindings/js/JSDictionary.cpp index f67c23485ff44..97ab014c34f81 100644 --- a/Source/WebCore/bindings/js/JSDictionary.cpp +++ b/Source/WebCore/bindings/js/JSDictionary.cpp @@ -50,6 +50,7 @@ #if ENABLE(MEDIA_STREAM) #include "JSMediaStream.h" #include "JSMediaStreamTrack.h" +#include "JSRTCRtpReceiver.h" #endif #if ENABLE(GAMEPAD) @@ -236,6 +237,11 @@ void JSDictionary::convertValue(JSC::ExecState*, JSC::JSValue value, RefPtr& result) +{ + result = JSRTCRtpReceiver::toWrapped(value); +} #endif #if ENABLE(FONT_LOAD_EVENTS) diff --git a/Source/WebCore/bindings/js/JSDictionary.h b/Source/WebCore/bindings/js/JSDictionary.h index 9b6eb65fc8f1d..f58fbf70b6b55 100644 --- a/Source/WebCore/bindings/js/JSDictionary.h +++ b/Source/WebCore/bindings/js/JSDictionary.h @@ -50,6 +50,7 @@ class Gamepad; class MediaKeyError; class MediaStream; class MediaStreamTrack; +class RTCRtpReceiver; class Node; class SerializedScriptValue; class Storage; @@ -128,6 +129,7 @@ class JSDictionary { #if ENABLE(MEDIA_STREAM) static void convertValue(JSC::ExecState*, JSC::JSValue, RefPtr& result); static void convertValue(JSC::ExecState*, JSC::JSValue, RefPtr& result); + static void convertValue(JSC::ExecState*, JSC::JSValue, RefPtr& result); #endif #if ENABLE(FONT_LOAD_EVENTS) static void convertValue(JSC::ExecState*, JSC::JSValue, RefPtr& result); diff --git a/Source/WebCore/bindings/js/JSRTCPeerConnectionCustom.cpp b/Source/WebCore/bindings/js/JSRTCPeerConnectionCustom.cpp index e5fe2aa154604..279d1b3b9bbc6 100644 --- a/Source/WebCore/bindings/js/JSRTCPeerConnectionCustom.cpp +++ b/Source/WebCore/bindings/js/JSRTCPeerConnectionCustom.cpp @@ -1,5 +1,6 @@ /* * Copyright (C) 2013 Nokia Corporation and/or its subsidiary(-ies). + * Copyright (C) 2015 Ericsson AB. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -26,11 +27,18 @@ #include "config.h" #if ENABLE(MEDIA_STREAM) - #include "JSRTCPeerConnection.h" +#include "Dictionary.h" #include "ExceptionCode.h" #include "JSDOMBinding.h" +#include "JSDOMError.h" +#include "JSDOMPromise.h" +#include "JSRTCIceCandidate.h" +#include "JSRTCPeerConnectionErrorCallback.h" +#include "JSRTCSessionDescription.h" +#include "JSRTCSessionDescriptionCallback.h" +#include "JSVoidCallback.h" using namespace JSC; @@ -69,6 +77,180 @@ EncodedJSValue JSC_HOST_CALL constructJSRTCPeerConnection(ExecState* exec) return JSValue::encode(CREATE_DOM_WRAPPER(jsConstructor->globalObject(), RTCPeerConnection, peerConnection.get())); } +static JSValue createOfferOrAnswer(RTCPeerConnection& impl, void (RTCPeerConnection::*implFunction)(const Dictionary&, RTCPeerConnection::OfferAnswerResolveCallback, RTCPeerConnection::RejectCallback), JSDOMGlobalObject* globalObject, ExecState* exec) +{ + Dictionary options; + + if (exec->argumentCount() > 1 && exec->argument(0).isFunction() && exec->argument(1).isFunction()) { + // legacy callbacks mode + if (exec->argumentCount() > 2) { + options = Dictionary(exec, exec->argument(2)); + if (!options.isObject()) { + throwVMError(exec, createTypeError(exec, "Third argument must be a valid Dictionary")); + return jsUndefined(); + } + } + + RefPtr sessionDescriptionCallback = JSRTCSessionDescriptionCallback::create(asObject(exec->argument(0)), globalObject); + RefPtr errorCallback = JSRTCPeerConnectionErrorCallback::create(asObject(exec->argument(1)), globalObject); + + RefPtr protectedImpl = &impl; + auto resolveCallback = [protectedImpl, sessionDescriptionCallback](RTCSessionDescription& description) mutable { + RefPtr protectedDescription = &description; + protectedImpl->scriptExecutionContext()->postTask([sessionDescriptionCallback, protectedDescription](ScriptExecutionContext&) mutable { + sessionDescriptionCallback->handleEvent(protectedDescription.get()); + }); + }; + auto rejectCallback = [protectedImpl, errorCallback](DOMError& error) mutable { + RefPtr protectedError = &error; + protectedImpl->scriptExecutionContext()->postTask([errorCallback, protectedError](ScriptExecutionContext&) mutable { + errorCallback->handleEvent(protectedError.get()); + }); + }; + + (impl.*implFunction)(options, WTF::move(resolveCallback), WTF::move(rejectCallback)); + + return jsUndefined(); + } + + // Promised-based mode + if (exec->argumentCount()) { + options = Dictionary(exec, exec->argument(0)); + if (!options.isObject()) { + throwVMError(exec, createTypeError(exec, "First argument must be a valid Dictionary")); + return jsUndefined(); + } + } + + JSPromiseDeferred* promiseDeferred = JSPromiseDeferred::create(exec, globalObject); + DeferredWrapper wrapper(exec, globalObject, promiseDeferred); + + auto resolveCallback = [wrapper](RTCSessionDescription &description) mutable { + wrapper.resolve(&description); + }; + auto rejectCallback = [wrapper](DOMError& error) mutable { + wrapper.reject(&error); + }; + + (impl.*implFunction)(options, WTF::move(resolveCallback), WTF::move(rejectCallback)); + + return promiseDeferred->promise(); +} + +JSValue JSRTCPeerConnection::createOffer(ExecState* exec) +{ + return createOfferOrAnswer(impl(), &RTCPeerConnection::createOffer, globalObject(), exec); +} + +JSValue JSRTCPeerConnection::createAnswer(ExecState* exec) +{ + return createOfferOrAnswer(impl(), &RTCPeerConnection::createAnswer, globalObject(), exec); +} + +static JSValue setLocalOrRemoteDescription(RTCPeerConnection& impl, void (RTCPeerConnection::*implFunction)(RTCSessionDescription*, RTCPeerConnection::VoidResolveCallback, RTCPeerConnection::RejectCallback), JSDOMGlobalObject* globalObject, ExecState* exec) +{ + RefPtr description = JSRTCSessionDescription::toWrapped(exec->argument(0)); + if (!description) { + throwVMError(exec, createTypeError(exec, "First argument must be a RTCSessionDescription")); + return jsUndefined(); + } + + if (exec->argumentCount() > 2 && exec->argument(1).isFunction() && exec->argument(2).isFunction()) { + // legacy callbacks mode + RefPtr voidCallback = JSVoidCallback::create(asObject(exec->argument(1)), globalObject); + RefPtr errorCallback = JSRTCPeerConnectionErrorCallback::create(asObject(exec->argument(2)), globalObject); + + RefPtr protectedImpl = &impl; + auto resolveCallback = [protectedImpl, voidCallback]() mutable { + protectedImpl->scriptExecutionContext()->postTask([voidCallback](ScriptExecutionContext&) mutable { + voidCallback->handleEvent(); + }); + }; + auto rejectCallback = [protectedImpl, errorCallback](DOMError& error) mutable { + RefPtr protectedError = &error; + protectedImpl->scriptExecutionContext()->postTask([errorCallback, protectedError](ScriptExecutionContext&) mutable { + errorCallback->handleEvent(protectedError.get()); + }); + }; + + (impl.*implFunction)(description.get() , WTF::move(resolveCallback), WTF::move(rejectCallback)); + + return jsUndefined(); + } + + // Promised-based mode + JSPromiseDeferred* promiseDeferred = JSPromiseDeferred::create(exec, globalObject); + DeferredWrapper wrapper(exec, globalObject, promiseDeferred); + + auto resolveCallback = [wrapper]() mutable { + wrapper.resolve(false); + }; + auto rejectCallback = [wrapper](DOMError& error) mutable { + wrapper.reject(&error); + }; + + (impl.*implFunction)(description.get(), WTF::move(resolveCallback), WTF::move(rejectCallback)); + + return promiseDeferred->promise(); +} + +JSValue JSRTCPeerConnection::setLocalDescription(ExecState* exec) +{ + return setLocalOrRemoteDescription(impl(), &RTCPeerConnection::setLocalDescription, globalObject(), exec); +} + +JSValue JSRTCPeerConnection::setRemoteDescription(ExecState* exec) +{ + return setLocalOrRemoteDescription(impl(), &RTCPeerConnection::setRemoteDescription, globalObject(), exec); +} + +JSValue JSRTCPeerConnection::addIceCandidate(ExecState* exec) +{ + RefPtr candidate = JSRTCIceCandidate::toWrapped(exec->argument(0)); + if (!candidate) { + throwVMError(exec, createTypeError(exec, "First argument must be a RTCIceCandidate")); + return jsUndefined(); + } + + if (exec->argumentCount() > 2 && exec->argument(1).isFunction() && exec->argument(2).isFunction()) { + // legacy callbacks mode + RefPtr voidCallback = JSVoidCallback::create(asObject(exec->argument(1)), globalObject()); + RefPtr errorCallback = JSRTCPeerConnectionErrorCallback::create(asObject(exec->argument(2)), globalObject()); + + RefPtr protectedImpl = &impl(); + auto resolveCallback = [protectedImpl, voidCallback]() mutable { + protectedImpl->scriptExecutionContext()->postTask([voidCallback](ScriptExecutionContext&) mutable { + voidCallback->handleEvent(); + }); + }; + auto rejectCallback = [protectedImpl, errorCallback](DOMError& error) mutable { + RefPtr protectedError = &error; + protectedImpl->scriptExecutionContext()->postTask([errorCallback, protectedError](ScriptExecutionContext&) mutable { + errorCallback->handleEvent(protectedError.get()); + }); + }; + + impl().addIceCandidate(candidate.get() , WTF::move(resolveCallback), WTF::move(rejectCallback)); + + return jsUndefined(); + } + + // Promised-based mode + JSPromiseDeferred* promiseDeferred = JSPromiseDeferred::create(exec, globalObject()); + DeferredWrapper wrapper(exec, globalObject(), promiseDeferred); + + auto resolveCallback = [wrapper]() mutable { + wrapper.resolve(false); + }; + auto rejectCallback = [wrapper](DOMError& error) mutable { + wrapper.reject(&error); + }; + + impl().addIceCandidate(candidate.get(), WTF::move(resolveCallback), WTF::move(rejectCallback)); + + return promiseDeferred->promise(); +} + } // namespace WebCore #endif // ENABLE(MEDIA_STREAM) diff --git a/Source/WebCore/dom/EventNames.h b/Source/WebCore/dom/EventNames.h index c856bb2e3977a..874b7ebf14c63 100644 --- a/Source/WebCore/dom/EventNames.h +++ b/Source/WebCore/dom/EventNames.h @@ -43,7 +43,6 @@ namespace WebCore { macro(abort) \ macro(active) \ macro(addsourcebuffer) \ - macro(addstream) \ macro(addtrack) \ macro(animationend) \ macro(animationiteration) \ @@ -166,7 +165,6 @@ namespace WebCore { macro(ratechange) \ macro(readystatechange) \ macro(removesourcebuffer) \ - macro(removestream) \ macro(removetrack) \ macro(reset) \ macro(resize) \ @@ -205,6 +203,7 @@ namespace WebCore { macro(touchend) \ macro(touchmove) \ macro(touchstart) \ + macro(track) \ macro(transitionend) \ macro(unload) \ macro(unmute) \ diff --git a/Source/WebCore/dom/EventNames.in b/Source/WebCore/dom/EventNames.in index c74f685877644..28b164c4ba126 100644 --- a/Source/WebCore/dom/EventNames.in +++ b/Source/WebCore/dom/EventNames.in @@ -33,11 +33,11 @@ WheelEvent XMLHttpRequestProgressEvent AudioProcessingEvent conditional=WEB_AUDIO OfflineAudioCompletionEvent conditional=WEB_AUDIO -MediaStreamEvent conditional=MEDIA_STREAM MediaStreamTrackEvent conditional=MEDIA_STREAM RTCIceCandidateEvent conditional=MEDIA_STREAM RTCDataChannelEvent conditional=MEDIA_STREAM RTCDTMFToneChangeEvent conditional=MEDIA_STREAM +RTCTrackEvent conditional=MEDIA_STREAM SpeechSynthesisEvent conditional=SPEECH_SYNTHESIS WebGLContextEvent conditional=WEBGL StorageEvent diff --git a/Source/WebCore/html/HTMLMediaElement.cpp b/Source/WebCore/html/HTMLMediaElement.cpp index 7490619f1aebe..0f95208a975c4 100644 --- a/Source/WebCore/html/HTMLMediaElement.cpp +++ b/Source/WebCore/html/HTMLMediaElement.cpp @@ -128,6 +128,7 @@ #endif #if ENABLE(MEDIA_STREAM) +#include "DOMURL.h" #include "MediaStream.h" #include "MediaStreamRegistry.h" #endif @@ -884,6 +885,7 @@ void HTMLMediaElement::setSrcObject(MediaStream* mediaStream) // https://bugs.webkit.org/show_bug.cgi?id=124896 m_mediaStreamSrcObject = mediaStream; + setSrc(DOMURL::createPublicURL(ActiveDOMObject::scriptExecutionContext(), mediaStream)); } #endif @@ -1310,9 +1312,11 @@ void HTMLMediaElement::loadResource(const URL& initialURL, ContentType& contentT } else #endif #if ENABLE(MEDIA_STREAM) - if (m_mediaStreamSrcObject) - m_player->load(m_mediaStreamSrcObject->privateStream()); - else + if (!m_mediaStreamSrcObject && url.protocolIs(mediaSourceBlobProtocol)) + m_mediaStreamSrcObject = static_cast(MediaStreamRegistry::registry().lookup(url.string())); + if (m_mediaStreamSrcObject) + m_player->load(m_mediaStreamSrcObject->privateStream()); + else #endif if (!m_player->load(url, contentType, keySystem)) mediaLoadingFailed(MediaPlayer::FormatError); diff --git a/Source/WebCore/platform/graphics/ANGLEWebKitBridge.h b/Source/WebCore/platform/graphics/ANGLEWebKitBridge.h index 96f3f7936b29b..77acee409de4f 100644 --- a/Source/WebCore/platform/graphics/ANGLEWebKitBridge.h +++ b/Source/WebCore/platform/graphics/ANGLEWebKitBridge.h @@ -43,6 +43,7 @@ #endif #endif + #if !PLATFORM(GTK) && !PLATFORM(EFL) && !PLATFORM(WPE) && !PLATFORM(WIN) && !defined(BUILDING_WITH_CMAKE) #include "ANGLE/ShaderLang.h" #elif PLATFORM(WIN) && !defined(BUILDING_WITH_CMAKE) diff --git a/Source/WebCore/platform/graphics/MediaPlayer.cpp b/Source/WebCore/platform/graphics/MediaPlayer.cpp index 8021129189887..d29ff7d9c3df1 100644 --- a/Source/WebCore/platform/graphics/MediaPlayer.cpp +++ b/Source/WebCore/platform/graphics/MediaPlayer.cpp @@ -53,6 +53,9 @@ #if USE(GSTREAMER) #include "MediaPlayerPrivateGStreamer.h" +#if ENABLE(MEDIA_STREAM) && USE(OPENWEBRTC) +#include "MediaPlayerPrivateGStreamerOwr.h" +#endif #define PlatformMediaEngineClassName MediaPlayerPrivateGStreamer #endif @@ -194,6 +197,11 @@ static void buildMediaEnginesVector() MediaPlayerPrivateQTKit::registerMediaEngine(addMediaEngine); #endif + +#if ENABLE(MEDIA_STREAM) && USE(GSTREAMER) && USE(OPENWEBRTC) + MediaPlayerPrivateGStreamerOwr::registerMediaEngine(addMediaEngine); +#endif + #if defined(PlatformMediaEngineClassName) PlatformMediaEngineClassName::registerMediaEngine(addMediaEngine); #endif diff --git a/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamerOwr.cpp b/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamerOwr.cpp new file mode 100644 index 0000000000000..ffb01e5510071 --- /dev/null +++ b/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamerOwr.cpp @@ -0,0 +1,320 @@ +/* + * Copyright (C) 2012 Collabora Ltd. All rights reserved. + * Copyright (C) 2014, 2015 Igalia S.L. All rights reserved. + * Copyright (C) 2015 Metrological All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + + +#include "config.h" + +#if ENABLE(MEDIA_STREAM) && USE(GSTREAMER) && USE(OPENWEBRTC) +#include "MediaPlayerPrivateGStreamerOwr.h" + +#include "GStreamerUtilities.h" +#include "MediaPlayer.h" +#include "MediaStreamPrivate.h" +#include "NotImplemented.h" +#include "RealtimeMediaSourceOwr.h" +#include "URL.h" +#include +#include +#include +#include +#include + +GST_DEBUG_CATEGORY(webkit_openwebrtc_debug); +#define GST_CAT_DEFAULT webkit_openwebrtc_debug + +namespace WebCore { + +MediaPlayerPrivateGStreamerOwr::MediaPlayerPrivateGStreamerOwr(MediaPlayer* player) + : MediaPlayerPrivateGStreamerBase(player) + , m_paused(true) + , m_stopped(true) +{ + if (isAvailable()) { + LOG_MEDIA_MESSAGE("Creating Stream media player"); + + createVideoSink(); + createGSTAudioSinkBin(); + } +} + +MediaPlayerPrivateGStreamerOwr::~MediaPlayerPrivateGStreamerOwr() +{ + LOG_MEDIA_MESSAGE("Destructing"); + + stop(); +} + +void MediaPlayerPrivateGStreamerOwr::play() +{ + LOG_MEDIA_MESSAGE("Play"); + + if (!m_streamPrivate || !m_streamPrivate->active()) { + m_readyState = MediaPlayer::HaveNothing; + loadingFailed(MediaPlayer::Empty); + return; + } + + m_paused = false; + internalLoad(); +} + +void MediaPlayerPrivateGStreamerOwr::pause() +{ + LOG_MEDIA_MESSAGE("Pause"); + m_paused = true; + stop(); +} + +bool MediaPlayerPrivateGStreamerOwr::hasVideo() const +{ + return m_videoSource; +} + +bool MediaPlayerPrivateGStreamerOwr::hasAudio() const +{ + return m_audioSource; +} + +float MediaPlayerPrivateGStreamerOwr::currentTime() const +{ + gint64 position = GST_CLOCK_TIME_NONE; + GstQuery* query= gst_query_new_position(GST_FORMAT_TIME); + + if (m_videoSource && gst_element_query(m_videoSink.get(), query)) + gst_query_parse_position(query, 0, &position); + else if (m_audioSource && gst_element_query(m_audioSink.get(), query)) + gst_query_parse_position(query, 0, &position); + + float result = 0.0f; + if (static_cast(position) != GST_CLOCK_TIME_NONE) + result = static_cast(position) / GST_SECOND; + + LOG_MEDIA_MESSAGE("Position %" GST_TIME_FORMAT, GST_TIME_ARGS(position)); + gst_query_unref(query); + + return result; +} + +void MediaPlayerPrivateGStreamerOwr::load(const String &url) +{ + notImplemented(); +} + +void MediaPlayerPrivateGStreamerOwr::load(MediaStreamPrivate& streamPrivate) +{ + if (!initializeGStreamer()) + return; + + LOG_MEDIA_MESSAGE("Loading MediaStreamPrivate %p", &streamPrivate); + + m_streamPrivate = &streamPrivate; + if (!m_streamPrivate || !m_streamPrivate->active()) { + loadingFailed(MediaPlayer::NetworkError); + return; + } + + m_readyState = MediaPlayer::HaveNothing; + m_networkState = MediaPlayer::Loading; + m_player->networkStateChanged(); + m_player->readyStateChanged(); + + if (!internalLoad()) + return; + + // If the stream contains video, wait for first video frame before setting + // HaveEnoughData + if (!hasVideo()) + m_readyState = MediaPlayer::HaveEnoughData; + + m_player->readyStateChanged(); + +} + +void MediaPlayerPrivateGStreamerOwr::loadingFailed(MediaPlayer::NetworkState error) +{ + + if (m_networkState != error) { + m_networkState = error; + m_player->networkStateChanged(); + } + if (m_readyState != MediaPlayer::HaveNothing) { + m_readyState = MediaPlayer::HaveNothing; + m_player->readyStateChanged(); + } +} + +bool MediaPlayerPrivateGStreamerOwr::didLoadingProgress() const +{ + return true; +} + +bool MediaPlayerPrivateGStreamerOwr::internalLoad() +{ + if (!m_stopped) + return false; + + m_stopped = false; + if (!m_streamPrivate || !m_streamPrivate->active()) { + loadingFailed(MediaPlayer::NetworkError); + return false; + } + + LOG_MEDIA_MESSAGE("Connecting to live stream, descriptor: %p", m_streamPrivate.get()); + + for (auto track : m_streamPrivate->tracks()) { + if (!track->enabled()) { + LOG_MEDIA_MESSAGE("Track %s disabled", track->label().ascii().data()); + continue; + } + + RealtimeMediaSourceOwr* source = reinterpret_cast(track->source()); + OwrMediaSource* mediaSource = OWR_MEDIA_SOURCE(source->mediaSource()); + + if (track->type() == RealtimeMediaSource::Audio) { + if (m_audioSource && (m_audioSource.get() == source)) + g_object_set(m_audioRenderer, "disabled", FALSE, nullptr); + + owr_media_renderer_set_source(OWR_MEDIA_RENDERER(m_audioRenderer), mediaSource); + m_audioSource = source; + source->addObserver(this); + } else if (track->type() == RealtimeMediaSource::Video) { + if (m_videoSource && (m_videoSource.get() == source)) + g_object_set(m_videoRenderer, "disabled", FALSE, nullptr); + // + // FIXME: Fixate video resolution to HD for now. + // + g_object_set(m_videoRenderer, "width", 1280, "height", 720, "max-framerate", 30.0, NULL); + + owr_media_renderer_set_source(OWR_MEDIA_RENDERER(m_videoRenderer), mediaSource); + m_videoSource = source; + source->addObserver(this); + } else + ASSERT_NOT_REACHED(); + } + + m_readyState = MediaPlayer::HaveEnoughData; + m_player->readyStateChanged(); + return true; +} + +void MediaPlayerPrivateGStreamerOwr::stop() +{ + if (m_stopped) + return; + + m_stopped = true; + if (m_audioSource) { + LOG_MEDIA_MESSAGE("Stop: disconnecting audio"); + g_object_set(m_audioRenderer, "disabled", TRUE, nullptr); + } + if (m_videoSource) { + LOG_MEDIA_MESSAGE("Stop: disconnecting video"); + g_object_set(m_videoRenderer, "disabled", TRUE, nullptr); + } +} + +void MediaPlayerPrivateGStreamerOwr::registerMediaEngine(MediaEngineRegistrar registrar) +{ + if (isAvailable()) { + registrar([](MediaPlayer* player) { + return std::make_unique(player); + }, getSupportedTypes, supportsType, 0, 0, 0, 0); + } +} + +void MediaPlayerPrivateGStreamerOwr::getSupportedTypes(HashSet& types) +{ + // FIXME +} + +MediaPlayer::SupportsType MediaPlayerPrivateGStreamerOwr::supportsType(const MediaEngineSupportParameters& parameters) +{ + // FIXME + return MediaPlayer::IsNotSupported; +} + +bool MediaPlayerPrivateGStreamerOwr::isAvailable() +{ + if (!initializeGStreamer()) + return false; + + static bool debugRegistered = false; + if (!debugRegistered) { + GST_DEBUG_CATEGORY_INIT(webkit_openwebrtc_debug, "webkitowrplayer", 0, "WebKit OpenWebRTC player"); + debugRegistered = true; + } + + return true; +} + +void MediaPlayerPrivateGStreamerOwr::createGSTAudioSinkBin() +{ + ASSERT(!m_audioSink); + LOG_MEDIA_MESSAGE("Creating audio sink"); + // FIXME: volume/mute support + + GRefPtr sink = gst_element_factory_make("autoaudiosink", 0); + GstStateChangeReturn stateChangeResult = gst_element_set_state(sink.get(), GST_STATE_READY); + GstChildProxy* childProxy = GST_CHILD_PROXY(sink.get()); + m_audioSink = adoptGRef(GST_ELEMENT(gst_child_proxy_get_child_by_index(childProxy, 0))); + gst_element_set_state(sink.get(), GST_STATE_NULL); + + m_audioRenderer = owr_gst_audio_renderer_new(m_audioSink.get()); +} + +void MediaPlayerPrivateGStreamerOwr::sourceStopped() +{ + LOG_MEDIA_MESSAGE("Source stopped"); + + if (!m_streamPrivate || !m_streamPrivate->active()) + stop(); + + for (auto track : m_streamPrivate->tracks()) { + RealtimeMediaSourceOwr* source = reinterpret_cast(track->source()); + if (track->enabled()) + continue; + if (source == m_audioSource) + g_object_set(m_audioRenderer, "disabled", TRUE, nullptr); + else if (source == m_videoSource) + g_object_set(m_videoRenderer, "disabled", TRUE, nullptr); + } +} + +void MediaPlayerPrivateGStreamerOwr::sourceMutedChanged() +{ + LOG_MEDIA_MESSAGE("Source muted state changed"); +} + +bool MediaPlayerPrivateGStreamerOwr::preventSourceFromStopping() +{ + LOG_MEDIA_MESSAGE("Prevent source from stopping"); + return false; +} + +GstElement* MediaPlayerPrivateGStreamerOwr::createVideoSink() +{ + GstElement* sink = MediaPlayerPrivateGStreamerBase::createVideoSink(); + m_videoRenderer = owr_gst_video_renderer_new(sink); + return nullptr; +} + +} // namespace WebCore + +#endif // ENABLE(MEDIA_STREAM) && USE(GSTREAMER) && USE(OPENWEBRTC) diff --git a/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamerOwr.h b/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamerOwr.h new file mode 100644 index 0000000000000..fc7c96a84fe71 --- /dev/null +++ b/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamerOwr.h @@ -0,0 +1,117 @@ +/* + * Copyright (C) 2015 Igalia S.L. All rights reserved. + * Copyright (C) 2015 Metrological. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef MediaPlayerPrivateGStreamerOwr_h +#define MediaPlayerPrivateGStreamerOwr_h + +#if ENABLE(MEDIA_STREAM) && USE(GSTREAMER) && USE(OPENWEBRTC) + +#include "MediaPlayerPrivateGStreamerBase.h" +#include "RealtimeMediaSource.h" + +typedef struct _OwrGstVideoRenderer OwrGstVideoRenderer; +typedef struct _OwrGstAudioRenderer OwrGstAudioRenderer; + +namespace WebCore { + +class MediaStreamPrivate; +class RealtimeMediaSourceOwr; +class URL; + +class MediaPlayerPrivateGStreamerOwr : public MediaPlayerPrivateGStreamerBase, private RealtimeMediaSource::Observer { +public: + explicit MediaPlayerPrivateGStreamerOwr(MediaPlayer*); + ~MediaPlayerPrivateGStreamerOwr(); + + static void registerMediaEngine(MediaEngineRegistrar); + virtual String engineDescription() const { return "OpenWebRTC"; } + + virtual void load(const String&); +#if ENABLE(MEDIA_SOURCE) + virtual void load(const String&, MediaSourcePrivateClient*) { } +#endif + virtual void load(MediaStreamPrivate&); + virtual void cancelLoad() { } + + virtual void prepareToPlay() { } + void play(); + void pause(); + + bool hasVideo() const; + bool hasAudio() const; + + virtual float duration() const { return 0; } + + virtual float currentTime() const; + virtual void seek(float) { } + virtual bool seeking() const { return false; } + + virtual void setRate(float) { } + virtual void setPreservesPitch(bool) { } + virtual bool paused() const { return m_paused; } + + virtual bool hasClosedCaptions() const { return false; } + virtual void setClosedCaptionsVisible(bool) { }; + + virtual float maxTimeSeekable() const { return 0; } + virtual std::unique_ptr buffered() const { return std::make_unique(); } + bool didLoadingProgress() const; + + virtual unsigned long long totalBytes() const { return 0; } + virtual unsigned bytesLoaded() const { return 0; } + + virtual bool canLoadPoster() const { return false; } + virtual void setPoster(const String&) { } + + virtual bool isLiveStream() const { return true; } + + // RealtimeMediaSource::Observer implementation + virtual void sourceStopped() override final; + virtual void sourceMutedChanged() override final; + virtual bool preventSourceFromStopping() override final; + +protected: + virtual GstElement* createVideoSink(); + +private: + static void getSupportedTypes(HashSet&); + static MediaPlayer::SupportsType supportsType(const MediaEngineSupportParameters&); + static bool isAvailable(); + void createGSTAudioSinkBin(); + void loadingFailed(MediaPlayer::NetworkState error); + bool internalLoad(); + void stop(); + virtual GstElement* audioSink() const { return m_audioSink.get(); } + +private: + bool m_paused; + bool m_stopped; + RefPtr m_videoSource; + RefPtr m_audioSource; + GRefPtr m_audioSink; + RefPtr m_streamPrivate; + OwrGstVideoRenderer* m_videoRenderer; + OwrGstAudioRenderer* m_audioRenderer; +}; + +} // namespace WebCore + +#endif // ENABLE(MEDIA_STREAM) && USE(GSTREAMER) && USE(OPENWEBRTC) + +#endif // MediaPlayerPrivateGStreamerOwr_h diff --git a/Source/WebCore/platform/graphics/texmap/GraphicsLayerTextureMapper.cpp b/Source/WebCore/platform/graphics/texmap/GraphicsLayerTextureMapper.cpp index a7392d32bcac0..da068468685ad 100644 --- a/Source/WebCore/platform/graphics/texmap/GraphicsLayerTextureMapper.cpp +++ b/Source/WebCore/platform/graphics/texmap/GraphicsLayerTextureMapper.cpp @@ -409,9 +409,6 @@ void GraphicsLayerTextureMapper::setDebugBorder(const Color& color, float width) void GraphicsLayerTextureMapper::commitLayerChanges() { - if (m_animations.hasRunningAnimations()) - client().notifyFlushBeforeDisplayRefresh(this); - if (m_changeMask == NoChanges) return; @@ -605,9 +602,6 @@ void GraphicsLayerTextureMapper::removeAnimation(const String& animationName) bool GraphicsLayerTextureMapper::setFilters(const FilterOperations& filters) { - if (m_filters == filters) - return true; - TextureMapper* textureMapper = m_layer.textureMapper(); if (!textureMapper) return false; diff --git a/Source/WebCore/platform/mediastream/IceCandidate.h b/Source/WebCore/platform/mediastream/IceCandidate.h new file mode 100644 index 0000000000000..0a7f99b7f9e95 --- /dev/null +++ b/Source/WebCore/platform/mediastream/IceCandidate.h @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2015 Ericsson AB. All rights reserved. + * + * 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. + * 3. Neither the name of Ericsson nor the names of its contributors + * may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT + * OWNER OR 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. + */ + +#ifndef IceCandidate_h +#define IceCandidate_h + +#if ENABLE(MEDIA_STREAM) + +#include +#include +#include + +namespace WebCore { + +class IceCandidate : public RefCounted { +public: + static RefPtr create() + { + return adoptRef(new IceCandidate()); + } + virtual ~IceCandidate() { } + + const String& type() const { return m_type; } + void setType(const String& type) { m_type = type; } + + const String& foundation() const { return m_foundation; } + void setFoundation(const String& foundation) { m_foundation = foundation; } + + unsigned componentId() const { return m_componentId; } + void setComponentId(unsigned componentId) { m_componentId = componentId; } + + const String& transport() const { return m_transport; } + void setTransport(const String& transport) { m_transport = transport; } + + int priority() const { return m_priority; } + void setPriority(int priority) { m_priority = priority; } + + const String& address() const { return m_address; } + void setAddress(const String& address) { m_address = address; } + + unsigned port() const { return m_port; } + void setPort(unsigned port) { m_port = port; } + + const String& tcpType() const { return m_tcpType; } + void setTcpType(const String& tcpType) { m_tcpType = tcpType; } + + const String& relatedAddress() const { return m_relatedAddress; } + void setRelatedAddress(const String& relatedAddress) { m_relatedAddress = relatedAddress; } + + unsigned relatedPort() const { return m_relatedPort; } + void setRelatedPort(unsigned relatedPort) { m_relatedPort = relatedPort; } + +private: + IceCandidate() + : m_componentId(0) + , m_priority(0) + , m_port(0) + , m_relatedPort(0) + { } + + String m_type; + String m_foundation; + unsigned m_componentId; + String m_transport; + int m_priority; + String m_address; + unsigned m_port; + String m_tcpType; + String m_relatedAddress; + unsigned m_relatedPort; +}; + +} // namespace WebCore + +#endif // ENABLE(MEDIA_STREAM) + +#endif // IceCandidate_h diff --git a/Source/WebCore/platform/mediastream/MediaEndpoint.cpp b/Source/WebCore/platform/mediastream/MediaEndpoint.cpp new file mode 100644 index 0000000000000..e1f5d7e438f32 --- /dev/null +++ b/Source/WebCore/platform/mediastream/MediaEndpoint.cpp @@ -0,0 +1,21 @@ +/* + * + */ + +#include "config.h" + +#if ENABLE(MEDIA_STREAM) +#include "MediaEndpoint.h" + +namespace WebCore { + +static std::unique_ptr createMediaEndpoint(MediaEndpointClient*) +{ + return nullptr; +} + +CreateMediaEndpoint MediaEndpoint::create = createMediaEndpoint; + +} // namespace WebCore + +#endif // ENABLE(MEDIA_STREAM) diff --git a/Source/WebCore/platform/mediastream/MediaEndpoint.h b/Source/WebCore/platform/mediastream/MediaEndpoint.h new file mode 100644 index 0000000000000..377625c3d6322 --- /dev/null +++ b/Source/WebCore/platform/mediastream/MediaEndpoint.h @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2015 Ericsson AB. All rights reserved. + * + * 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. + * 3. Neither the name of Ericsson nor the names of its contributors + * may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT + * OWNER OR 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. + */ + +#ifndef MediaEndpoint_h +#define MediaEndpoint_h + +#if ENABLE(MEDIA_STREAM) + +// #include "RTCConfigurationPrivate.h" +#include "MediaEndpointInit.h" +#include + +namespace WebCore { + +class IceCandidate; +class MediaEndpoint; +class MediaEndpointConfiguration; +class RealtimeMediaSource; + +class MediaEndpointClient { +public: + virtual void gotDtlsCertificate(unsigned mdescIndex, const String& certificate) = 0; + virtual void gotIceCandidate(unsigned mdescIndex, RefPtr&&) = 0; + virtual void doneGatheringCandidates(unsigned mdescIndex) = 0; + virtual void gotRemoteSource(unsigned mdescIndex, RefPtr&&) = 0; + + virtual ~MediaEndpointClient() { } +}; + +typedef std::unique_ptr (*CreateMediaEndpoint)(MediaEndpointClient*); + +class MediaEndpoint { +public: + WEBCORE_EXPORT static CreateMediaEndpoint create; + virtual ~MediaEndpoint() { } + + // FIMXE: look over naming + virtual void setConfiguration(RefPtr&&) = 0; + + virtual void prepareToReceive(MediaEndpointConfiguration*, bool isInitiator) = 0; + virtual void prepareToSend(MediaEndpointConfiguration*, bool isInitiator) = 0; + + virtual void addRemoteCandidate(IceCandidate&, unsigned mdescIndex, const String& ufrag, const String& password) = 0; + + virtual void stop() = 0; +}; + +} // namespace WebCore + +#endif // ENABLE(MEDIA_STREAM) + +#endif // MediaEndpoint_h diff --git a/Source/WebCore/platform/mediastream/MediaEndpointConfiguration.h b/Source/WebCore/platform/mediastream/MediaEndpointConfiguration.h new file mode 100644 index 0000000000000..f216c7042b660 --- /dev/null +++ b/Source/WebCore/platform/mediastream/MediaEndpointConfiguration.h @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2015 Ericsson AB. All rights reserved. + * + * 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. + * 3. Neither the name of Ericsson nor the names of its contributors + * may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT + * OWNER OR 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. + */ + +#ifndef MediaEndpointConfiguration_h +#define MediaEndpointConfiguration_h + +#if ENABLE(MEDIA_STREAM) + +#include "PeerMediaDescription.h" +#include + +namespace WebCore { + +class MediaEndpointConfiguration : public RefCounted { +public: + static RefPtr create() + { + return adoptRef(new MediaEndpointConfiguration()); + } + virtual ~MediaEndpointConfiguration() { } + + uint64_t sessionId() const { return m_sessionId; } + void setSessionId(uint64_t sessionId) { m_sessionId = sessionId; } + + unsigned sessionVersion() const { return m_sessionVersion; } + void setSessionVersion(unsigned sessionVersion) { m_sessionVersion = sessionVersion; } + + const Vector>& mediaDescriptions() const { return m_mediaDescriptions; } + void addMediaDescription(RefPtr&& description) { m_mediaDescriptions.append(WTF::move(description)); } + +private: + MediaEndpointConfiguration() + : m_sessionId(cryptographicallyRandomNumber()) // FIXME: should be 64 bits + , m_sessionVersion(0) + { } + + uint64_t m_sessionId; + unsigned m_sessionVersion; + + Vector> m_mediaDescriptions; +}; + +} // namespace WebCore + +#endif // ENABLE(MEDIA_STREAM) + +#endif // MediaEndpointConfiguration_h diff --git a/Source/WebCore/platform/mediastream/MediaEndpointConfigurationConversions.cpp b/Source/WebCore/platform/mediastream/MediaEndpointConfigurationConversions.cpp new file mode 100644 index 0000000000000..f36f893067ae8 --- /dev/null +++ b/Source/WebCore/platform/mediastream/MediaEndpointConfigurationConversions.cpp @@ -0,0 +1,375 @@ +/* + * Copyright (C) 2015 Ericsson AB. All rights reserved. + * + * 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. + * 3. Neither the name of Ericsson nor the names of its contributors + * may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT + * OWNER OR 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" + +#if ENABLE(MEDIA_STREAM) +#include "MediaEndpointConfigurationConversions.h" + +#include "inspector/InspectorValues.h" + +using namespace JSC; +using namespace Inspector; + +namespace WebCore { + +namespace MediaEndpointConfigurationConversions { + +// Note that MediaEndpointConfiguration is a "flatter" structure that the JSON representation. For +// example, the JSON representation has an "ice" object which collects a set of properties under a +// namespace. MediaEndpointConfiguration has "ice"-prefixes on the corresponding properties. + +static RefPtr createCandidateObject(IceCandidate* candidate) +{ + RefPtr candidateObject = InspectorObject::create(); + + candidateObject->setString(ASCIILiteral("type"), candidate->type()); + candidateObject->setString(ASCIILiteral("foundation"), candidate->foundation()); + candidateObject->setInteger(ASCIILiteral("componentId"), candidate->componentId()); + candidateObject->setString(ASCIILiteral("transport"), candidate->transport()); + candidateObject->setInteger(ASCIILiteral("priority"), candidate->priority()); + candidateObject->setString(ASCIILiteral("address"), candidate->address()); + candidateObject->setInteger(ASCIILiteral("port"), candidate->port()); + if (!candidate->tcpType().isEmpty()) + candidateObject->setString(ASCIILiteral("tcpType"), candidate->tcpType()); + if (candidate->type().upper() != "HOST") { + candidateObject->setString(ASCIILiteral("relatedAddress"), candidate->relatedAddress()); + candidateObject->setInteger(ASCIILiteral("relatedPort"), candidate->relatedPort()); + } + + return candidateObject; +} + +static RefPtr createCandidate(InspectorObject* candidateObject) +{ + RefPtr candidate = IceCandidate::create(); + String stringValue; + unsigned intValue; + + if (candidateObject->getString(ASCIILiteral("type"), stringValue)) + candidate->setType(stringValue); + + if (candidateObject->getString(ASCIILiteral("foundation"), stringValue)) + candidate->setFoundation(stringValue); + + if (candidateObject->getInteger(ASCIILiteral("componentId"), intValue)) + candidate->setComponentId(intValue); + + if (candidateObject->getString(ASCIILiteral("transport"), stringValue)) + candidate->setTransport(stringValue); + + if (candidateObject->getInteger(ASCIILiteral("priority"), intValue)) + candidate->setPriority(intValue); + + if (candidateObject->getString(ASCIILiteral("address"), stringValue)) + candidate->setAddress(stringValue); + + if (candidateObject->getInteger(ASCIILiteral("port"), intValue)) + candidate->setPort(intValue); + + if (candidateObject->getString(ASCIILiteral("tcpType"), stringValue)) + candidate->setTcpType(stringValue); + + if (candidateObject->getString(ASCIILiteral("relatedAddress"), stringValue)) + candidate->setRelatedAddress(stringValue); + + if (candidateObject->getInteger(ASCIILiteral("relatedPort"), intValue)) + candidate->setRelatedPort(intValue); + + return candidate; +} + +RefPtr fromJSON(const String& json) +{ + RefPtr value; + if (!InspectorValue::parseJSON(json, value)) + return nullptr; + + RefPtr object; + if (!value->asObject(object)) + return nullptr; + + RefPtr configuration = MediaEndpointConfiguration::create(); + + String stringValue; + unsigned intValue; + unsigned long longValue; + bool boolValue; + + RefPtr originatorObject = InspectorObject::create(); + if (object->getObject(ASCIILiteral("originator"), originatorObject)) { + if (originatorObject->getInteger(ASCIILiteral("sessionId"), longValue)) + configuration->setSessionId(longValue); + if (originatorObject->getInteger(ASCIILiteral("sessionVersion"), intValue)) + configuration->setSessionVersion(intValue); + } + + RefPtr mediaDescriptionsArray = InspectorArray::create(); + object->getArray(ASCIILiteral("mediaDescriptions"), mediaDescriptionsArray); + + for (unsigned i = 0; i < mediaDescriptionsArray->length(); ++i) { + RefPtr mdescObject = InspectorObject::create(); + mediaDescriptionsArray->get(i)->asObject(mdescObject); + + RefPtr mdesc = PeerMediaDescription::create(); + + if (mdescObject->getString(ASCIILiteral("type"), stringValue)) + mdesc->setType(stringValue); + + if (mdescObject->getInteger(ASCIILiteral("port"), intValue)) + mdesc->setPort(intValue); + + if (mdescObject->getString(ASCIILiteral("address"), stringValue)) + mdesc->setAddress(stringValue); + + if (mdescObject->getString(ASCIILiteral("mode"), stringValue)) + mdesc->setMode(stringValue); + + RefPtr payloadsArray = InspectorArray::create(); + mdescObject->getArray(ASCIILiteral("payloads"), payloadsArray); + + for (unsigned j = 0; j < payloadsArray->length(); ++j) { + RefPtr payloadsObject = InspectorObject::create(); + payloadsArray->get(j)->asObject(payloadsObject); + + RefPtr payload = MediaPayload::create(); + + if (payloadsObject->getInteger(ASCIILiteral("type"), intValue)) + payload->setType(intValue); + + if (payloadsObject->getString(ASCIILiteral("encodingName"), stringValue)) + payload->setEncodingName(stringValue); + + if (payloadsObject->getInteger(ASCIILiteral("clockRate"), intValue)) + payload->setClockRate(intValue); + + if (payloadsObject->getInteger(ASCIILiteral("channels"), intValue)) + payload->setChannels(intValue); + + if (payloadsObject->getBoolean(ASCIILiteral("ccmfir"), boolValue)) + payload->setCcmfir(boolValue); + + if (payloadsObject->getBoolean(ASCIILiteral("nackpli"), boolValue)) + payload->setNackpli(boolValue); + + if (payloadsObject->getBoolean(ASCIILiteral("nack"), boolValue)) + payload->setNack(boolValue); + + RefPtr parametersObject = InspectorObject::create(); + if (payloadsObject->getObject(ASCIILiteral("parameters"), parametersObject)) { + if (parametersObject->getInteger(ASCIILiteral("packetizationMode"), intValue)) + payload->addParameter("packetizationMode", intValue); + + if (parametersObject->getInteger(ASCIILiteral("apt"), intValue)) + payload->addParameter("apt", intValue); + + if (parametersObject->getInteger(ASCIILiteral("rtxTime"), intValue)) + payload->addParameter("rtxTime", intValue); + } + + mdesc->addPayload(WTF::move(payload)); + } + + RefPtr rtcpObject = InspectorObject::create(); + if (mdescObject->getObject(ASCIILiteral("rtcp"), rtcpObject)) { + if (rtcpObject->getBoolean(ASCIILiteral("mux"), boolValue)) + mdesc->setRtcpMux(boolValue); + + if (rtcpObject->getString(ASCIILiteral("rtcpAddress"), stringValue)) + mdesc->setRtcpAddress(stringValue); + + if (rtcpObject->getInteger(ASCIILiteral("rtcpPort"), intValue)) + mdesc->setRtcpPort(intValue); + } + + if (mdescObject->getString(ASCIILiteral("mediaStreamId"), stringValue)) + mdesc->setMediaStreamId(stringValue); + + if (mdescObject->getString(ASCIILiteral("mediaStreamTrackId"), stringValue)) + mdesc->setMediaStreamTrackId(stringValue); + + RefPtr dtlsObject = InspectorObject::create(); + if (mdescObject->getObject(ASCIILiteral("dtls"), dtlsObject)) { + if (dtlsObject->getString(ASCIILiteral("setup"), stringValue)) + mdesc->setDtlsSetup(stringValue); + + if (dtlsObject->getString(ASCIILiteral("fingerprintHashFunction"), stringValue)) + mdesc->setDtlsFingerprintHashFunction(stringValue); + + if (dtlsObject->getString(ASCIILiteral("fingerprint"), stringValue)) + mdesc->setDtlsFingerprint(stringValue); + } + + RefPtr ssrcsArray = InspectorArray::create(); + mdescObject->getArray(ASCIILiteral("ssrcs"), ssrcsArray); + + for (unsigned j = 0; j < ssrcsArray->length(); ++j) { + ssrcsArray->get(j)->asInteger(intValue); + mdesc->addSsrc(intValue); + } + + if (mdescObject->getString(ASCIILiteral("cname"), stringValue)) + mdesc->setCname(stringValue); + + RefPtr iceObject = InspectorObject::create(); + if (mdescObject->getObject(ASCIILiteral("ice"), iceObject)) { + if (iceObject->getString(ASCIILiteral("ufrag"), stringValue)) + mdesc->setIceUfrag(stringValue); + + if (iceObject->getString(ASCIILiteral("password"), stringValue)) + mdesc->setIcePassword(stringValue); + + RefPtr candidatesArray = InspectorArray::create(); + iceObject->getArray(ASCIILiteral("candidates"), candidatesArray); + + for (unsigned j = 0; j < candidatesArray->length(); ++j) { + RefPtr candidateObject = InspectorObject::create(); + candidatesArray->get(j)->asObject(candidateObject); + + mdesc->addIceCandidate(createCandidate(candidateObject.get())); + } + } + + configuration->addMediaDescription(WTF::move(mdesc)); + } + + return configuration; +} + +RefPtr iceCandidateFromJSON(const String& json) +{ + RefPtr value; + if (!InspectorValue::parseJSON(json, value)) + return nullptr; + + RefPtr candidateObject; + if (!value->asObject(candidateObject)) + return nullptr; + + return createCandidate(candidateObject.get()); +} + +String toJSON(MediaEndpointConfiguration* configuration) +{ + RefPtr object = InspectorObject::create(); + + RefPtr originatorObject = InspectorObject::create(); + originatorObject->setDouble(ASCIILiteral("sessionId"), configuration->sessionId()); + originatorObject->setInteger(ASCIILiteral("sessionVersion"), configuration->sessionVersion()); + object->setObject(ASCIILiteral("originator"), originatorObject); + + RefPtr mediaDescriptionsArray = InspectorArray::create(); + + for (const RefPtr& mdesc : configuration->mediaDescriptions()) { + RefPtr mdescObject = InspectorObject::create(); + + mdescObject->setString(ASCIILiteral("type"), mdesc->type()); + mdescObject->setInteger(ASCIILiteral("port"), mdesc->port()); + mdescObject->setString(ASCIILiteral("address"), mdesc->address()); + mdescObject->setString(ASCIILiteral("mode"), mdesc->mode()); + + RefPtr payloadsArray = InspectorArray::create(); + + for (RefPtr payload : mdesc->payloads()) { + RefPtr payloadObject = InspectorObject::create(); + + payloadObject->setInteger(ASCIILiteral("type"), payload->type()); + payloadObject->setString(ASCIILiteral("encodingName"), payload->encodingName()); + payloadObject->setInteger(ASCIILiteral("clockRate"), payload->clockRate()); + payloadObject->setInteger(ASCIILiteral("channels"), payload->channels()); + payloadObject->setBoolean(ASCIILiteral("ccmfir"), payload->ccmfir()); + payloadObject->setBoolean(ASCIILiteral("nackpli"), payload->nackpli()); + payloadObject->setBoolean(ASCIILiteral("nack"), payload->nack()); + + if (!payload->parameters().isEmpty()) { + RefPtr parametersObject = InspectorObject::create(); + + for (auto& name : payload->parameters().keys()) + parametersObject->setInteger(name, payload->parameters().get(name)); + + payloadObject->setObject(ASCIILiteral("parameters"), parametersObject); + } + + payloadsArray->pushObject(payloadObject); + } + mdescObject->setArray(ASCIILiteral("payloads"), payloadsArray); + + RefPtr rtcpObject = InspectorObject::create(); + rtcpObject->setBoolean(ASCIILiteral("mux"), mdesc->rtcpMux()); + rtcpObject->setString(ASCIILiteral("address"), mdesc->rtcpAddress()); + rtcpObject->setInteger(ASCIILiteral("port"), mdesc->rtcpPort()); + mdescObject->setObject(ASCIILiteral("rtcp"), rtcpObject); + + mdescObject->setString(ASCIILiteral("mediaStreamId"), mdesc->mediaStreamId()); + mdescObject->setString(ASCIILiteral("mediaStreamTrackId"), mdesc->mediaStreamTrackId()); + + RefPtr dtlsObject = InspectorObject::create(); + dtlsObject->setString(ASCIILiteral("setup"), mdesc->dtlsSetup()); + dtlsObject->setString(ASCIILiteral("fingerprintHashFunction"), mdesc->dtlsFingerprintHashFunction()); + dtlsObject->setString(ASCIILiteral("fingerprint"), mdesc->dtlsFingerprint()); + mdescObject->setObject(ASCIILiteral("dtls"), dtlsObject); + + RefPtr ssrcsArray = InspectorArray::create(); + + for (auto ssrc : mdesc->ssrcs()) + ssrcsArray->pushDouble(ssrc); + mdescObject->setArray(ASCIILiteral("ssrcs"), ssrcsArray); + + mdescObject->setString(ASCIILiteral("cname"), mdesc->cname()); + + RefPtr iceObject = InspectorObject::create(); + iceObject->setString(ASCIILiteral("ufrag"), mdesc->iceUfrag()); + iceObject->setString(ASCIILiteral("password"), mdesc->icePassword()); + + RefPtr candidatesArray = InspectorArray::create(); + + for (RefPtr candidate : mdesc->iceCandidates()) + candidatesArray->pushObject(createCandidateObject(candidate.get())); + + iceObject->setArray(ASCIILiteral("candidates"), candidatesArray); + mdescObject->setObject(ASCIILiteral("ice"), iceObject); + + mediaDescriptionsArray->pushObject(mdescObject); + } + object->setArray(ASCIILiteral("mediaDescriptions"), mediaDescriptionsArray); + + return object->toJSONString(); +} + +String iceCandidateToJSON(IceCandidate* candidate) +{ + return createCandidateObject(candidate)->toJSONString(); +} + +} + +} // namespace WebCore + +#endif // ENABLE(MEDIA_STREAM) diff --git a/Source/WebCore/platform/mediastream/MediaEndpointConfigurationConversions.h b/Source/WebCore/platform/mediastream/MediaEndpointConfigurationConversions.h new file mode 100644 index 0000000000000..a1499ebdde397 --- /dev/null +++ b/Source/WebCore/platform/mediastream/MediaEndpointConfigurationConversions.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2015 Ericsson AB. All rights reserved. + * + * 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. + * 3. Neither the name of Ericsson nor the names of its contributors + * may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT + * OWNER OR 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. + */ + +#ifndef MediaEndpointConfigurationConversions_h +#define MediaEndpointConfigurationConversions_h + +#if ENABLE(MEDIA_STREAM) + +#include "MediaEndpointConfiguration.h" + +namespace WebCore { + +namespace MediaEndpointConfigurationConversions { + +RefPtr fromJSON(const String&); +String toJSON(MediaEndpointConfiguration*); + +RefPtr iceCandidateFromJSON(const String&); +String iceCandidateToJSON(IceCandidate*); + +} + +} // namespace WebCore + +#endif // ENABLE(MEDIA_STREAM) + +#endif // MediaEndpointConfigurationConversions_h diff --git a/Source/WebCore/platform/mediastream/MediaEndpointInit.cpp b/Source/WebCore/platform/mediastream/MediaEndpointInit.cpp new file mode 100644 index 0000000000000..37a30d3d05fdd --- /dev/null +++ b/Source/WebCore/platform/mediastream/MediaEndpointInit.cpp @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2015 Ericsson AB. All rights reserved. + * + * 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. + * 3. Neither the name of Ericsson nor the names of its contributors + * may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT + * OWNER OR 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 "MediaEndpointInit.h" + +#if ENABLE(MEDIA_STREAM) + +namespace WebCore { + +MediaEndpointInit::MediaEndpointInit(Vector>& iceServers, const String& iceTransportPolicy, const String& bundlePolicy) + : m_iceServers(iceServers) +{ + if (iceTransportPolicy == "none") + m_iceTransportPolicy = IceTransportPolicyNone; + else if (iceTransportPolicy == "relay") + m_iceTransportPolicy = IceTransportPolicyRelay; + else if (iceTransportPolicy == "all") + m_iceTransportPolicy = IceTransportPolicyAll; + else + ASSERT_NOT_REACHED(); + + if (bundlePolicy == "balanced") + m_bundlePolicy = BundlePolicyBalanced; + else if (bundlePolicy == "max-compat") + m_bundlePolicy = BundlePolicyMaxCompat; + else if (bundlePolicy == "max-bundle") + m_bundlePolicy = BundlePolicyMaxBundle; + else + ASSERT_NOT_REACHED(); +} + +} // namespace WebCore + +#endif // ENABLE(MEDIA_STREAM) diff --git a/Source/WebCore/platform/mediastream/MediaEndpointInit.h b/Source/WebCore/platform/mediastream/MediaEndpointInit.h new file mode 100644 index 0000000000000..6c1ddbdeeaf1e --- /dev/null +++ b/Source/WebCore/platform/mediastream/MediaEndpointInit.h @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2015 Ericsson AB. All rights reserved. + * + * 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. + * 3. Neither the name of Ericsson nor the names of its contributors + * may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT + * OWNER OR 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. + */ + +#ifndef MediaEndpointInit_h +#define MediaEndpointInit_h + +#if ENABLE(MEDIA_STREAM) + +#include +#include +#include +#include + +namespace WebCore { + +class IceServerInfo : public RefCounted { +public: + static RefPtr create(const Vector& urls, const String& credential, const String& username) + { + return adoptRef(new IceServerInfo(urls, credential, username)); + } + virtual ~IceServerInfo() { } + + const Vector& urls() const { return m_urls; } + const String& credential() const { return m_credential; } + const String& username() const { return m_username; } + +private: + IceServerInfo(const Vector& urls, const String& credential, const String& username) + : m_urls(urls) + , m_credential(credential) + , m_username(username) + { } + + Vector m_urls; + String m_credential; + String m_username; +}; + +class MediaEndpointInit : public RefCounted { +public: + static RefPtr create(Vector>& iceServers, const String& iceTransportPolicy, const String& bundlePolicy) + { + return adoptRef(new MediaEndpointInit(iceServers, iceTransportPolicy, bundlePolicy)); + } + + enum IceTransportPolicy { + IceTransportPolicyNone, + IceTransportPolicyRelay, + IceTransportPolicyAll + }; + + enum BundlePolicy { + BundlePolicyBalanced, + BundlePolicyMaxCompat, + BundlePolicyMaxBundle + }; + + const Vector>& iceServers() const { return m_iceServers; } + IceTransportPolicy iceTransportPolicy() const { return m_iceTransportPolicy; } + BundlePolicy bundlePolicy() const { return m_bundlePolicy; } + +private: + MediaEndpointInit(Vector>&, const String& iceTransportPolicy, const String& bundlePolicy); + + Vector> m_iceServers; + IceTransportPolicy m_iceTransportPolicy; + BundlePolicy m_bundlePolicy; +}; + +} // namespace WebCore + +#endif // ENABLE(MEDIA_STREAM) + +#endif // MediaEndpointInit_h diff --git a/Source/WebCore/platform/mediastream/MediaPayload.h b/Source/WebCore/platform/mediastream/MediaPayload.h new file mode 100644 index 0000000000000..32f615509be56 --- /dev/null +++ b/Source/WebCore/platform/mediastream/MediaPayload.h @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2015 Ericsson AB. All rights reserved. + * + * 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. + * 3. Neither the name of Ericsson nor the names of its contributors + * may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT + * OWNER OR 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. + */ + +#ifndef MediaPayload_h +#define MediaPayload_h + +#if ENABLE(MEDIA_STREAM) + +#include +#include +#include +#include + +namespace WebCore { + +class MediaPayload : public RefCounted { +public: + static RefPtr create() + { + return adoptRef(new MediaPayload()); + } + virtual ~MediaPayload() { } + + unsigned type() const { return m_type; } + void setType(unsigned type) { m_type = type; } + + const String& encodingName() const { return m_encodingName; } + void setEncodingName(const String & encodingName) { m_encodingName = encodingName; } + + unsigned clockRate() const { return m_clockRate; } + void setClockRate(unsigned clockRate) { m_clockRate = clockRate; } + + unsigned channels() const { return m_channels; } + void setChannels(unsigned channels) { m_channels = channels; } + + bool ccmfir() const { return m_ccmfir; } + void setCcmfir(bool ccmfir) { m_ccmfir = ccmfir; } + + bool nackpli() const { return m_nackpli; } + void setNackpli(bool nackpli) { m_nackpli = nackpli; } + + bool nack() const { return m_nack; } + void setNack(bool nack) { m_nack = nack; } + + const HashMap& parameters() const { return m_parameters; } + void addParameter(const String& name, unsigned value) { m_parameters.set(name, value); } + +private: + MediaPayload() + : m_type(0) + , m_clockRate(0) + , m_channels(0) + , m_ccmfir(false) + , m_nackpli(false) + , m_nack(false) + { } + + unsigned m_type; + String m_encodingName; + unsigned m_clockRate; + + // audio + unsigned m_channels; + + // video + bool m_ccmfir; + bool m_nackpli; + bool m_nack; + + HashMap m_parameters; +}; + +} // namespace WebCore + +#endif // ENABLE(MEDIA_STREAM) + +#endif // MediaPayload_h diff --git a/Source/WebCore/platform/mediastream/PeerMediaDescription.h b/Source/WebCore/platform/mediastream/PeerMediaDescription.h new file mode 100644 index 0000000000000..27f5700d785e1 --- /dev/null +++ b/Source/WebCore/platform/mediastream/PeerMediaDescription.h @@ -0,0 +1,156 @@ +/* + * Copyright (C) 2015 Ericsson AB. All rights reserved. + * + * 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. + * 3. Neither the name of Ericsson nor the names of its contributors + * may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT + * OWNER OR 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. + */ + +#ifndef PeerMediaDescription_h +#define PeerMediaDescription_h + +#if ENABLE(MEDIA_STREAM) + +#include "IceCandidate.h" +#include "MediaPayload.h" +#include "RealtimeMediaSource.h" +#include +#include + +namespace WebCore { + +class PeerMediaDescription : public RefCounted { +public: + static RefPtr create() + { + return adoptRef(new PeerMediaDescription()); + } + virtual ~PeerMediaDescription() { } + + const String& type() const { return m_type; } + void setType(const String& type) { m_type = type; } + + unsigned short port() const { return m_port; } + void setPort(unsigned short port) { m_port = port; } + + const String& address() const { return m_address; } + void setAddress(const String& address) { m_address = address; } + + const String& mode() const { return m_mode; } + void setMode(const String& mode) { m_mode = mode; } + + const Vector>& payloads() const { return m_payloads; } + void addPayload(RefPtr&& payload) { m_payloads.append(WTF::move(payload)); } + void setPayloads(Vector>&& payloads) { m_payloads = payloads; } + void setPayloads(const Vector>& payloads) { m_payloads = payloads; } + + bool rtcpMux() const { return m_rtcpMux; } + void setRtcpMux(bool rtcpMux) { m_rtcpMux = rtcpMux; } + + const String& rtcpAddress() const { return m_rtcpAddress; } + void setRtcpAddress(const String& rtcpAddress) { m_rtcpAddress = rtcpAddress; } + + unsigned short rtcpPort() const { return m_rtcpPort; } + void setRtcpPort(unsigned short rtcpPort) { m_rtcpPort = rtcpPort; } + + const String& mediaStreamId() const { return m_mediaStreamId; } + void setMediaStreamId(const String& mediaStreamId) { m_mediaStreamId = mediaStreamId; } + + const String& mediaStreamTrackId() const { return m_mediaStreamTrackId; } + void setMediaStreamTrackId(const String& mediaStreamTrackId) { m_mediaStreamTrackId = mediaStreamTrackId; } + + const String& dtlsSetup() const { return m_dtlsSetup; } + void setDtlsSetup(const String& dtlsSetup) { m_dtlsSetup = dtlsSetup; } + + const String& dtlsFingerprintHashFunction() const { return m_dtlsFingerprintHashFunction; } + void setDtlsFingerprintHashFunction(const String& dtlsFingerprintHashFunction) { m_dtlsFingerprintHashFunction = dtlsFingerprintHashFunction; } + + const String& dtlsFingerprint() const { return m_dtlsFingerprint; } + void setDtlsFingerprint(const String& dtlsFingerprint) { m_dtlsFingerprint = dtlsFingerprint; } + + const String& cname() const { return m_cname; } + void setCname(const String& cname) { m_cname = cname; } + + const Vector& ssrcs() const { return m_ssrcs; } + void addSsrc(unsigned ssrc) { m_ssrcs.append(ssrc); } + void clearSsrcs() { m_ssrcs.clear(); } + + const String& iceUfrag() const { return m_iceUfrag; } + void setIceUfrag(const String& iceUfrag) { m_iceUfrag = iceUfrag; } + + const String& icePassword() const { return m_icePassword; } + void setIcePassword(const String& icePassword) { m_icePassword = icePassword; } + + const Vector>& iceCandidates() const { return m_iceCandidates; } + void addIceCandidate(RefPtr&& candidate) { m_iceCandidates.append(WTF::move(candidate)); } + + bool iceCandidateGatheringDone() const { return m_iceCandidateGatheringDone; } + void setIceCandidateGatheringDone(bool iceCandidateGatheringDone) { m_iceCandidateGatheringDone = iceCandidateGatheringDone; } + + RealtimeMediaSource* source() const { return m_source.get(); } + void setSource(RefPtr&& source) { m_source = source; } + +private: + PeerMediaDescription() + : m_port(0) + , m_rtcpMux(false) + , m_iceCandidateGatheringDone(false) + , m_source(nullptr) + { } + + String m_type; + unsigned short m_port; + String m_address; + String m_mode; + + Vector> m_payloads; + + bool m_rtcpMux; + String m_rtcpAddress; + unsigned short m_rtcpPort; + + String m_mediaStreamId; + String m_mediaStreamTrackId; + + String m_dtlsSetup; + String m_dtlsFingerprintHashFunction; + String m_dtlsFingerprint; + + Vector m_ssrcs; + String m_cname; + + String m_iceUfrag; + String m_icePassword; + Vector> m_iceCandidates; + bool m_iceCandidateGatheringDone; + + RefPtr m_source; +}; + +} // namespace WebCore + +#endif // ENABLE(MEDIA_STREAM) + +#endif // PeerMediaDescription_h diff --git a/Source/WebCore/platform/mediastream/RTCConfigurationPrivate.h b/Source/WebCore/platform/mediastream/RTCConfigurationPrivate.h deleted file mode 100644 index 8a1354c843a6e..0000000000000 --- a/Source/WebCore/platform/mediastream/RTCConfigurationPrivate.h +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (C) 2014 Apple Inc. All rights reserved. - * - * 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. ``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 - * 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. - */ - -#ifndef RTCConfigurationPrivate_h -#define RTCConfigurationPrivate_h - -#if ENABLE(MEDIA_STREAM) - -#include "RTCIceServerPrivate.h" -#include -#include -#include -#include - -namespace WebCore { - -class RTCConfigurationPrivate : public RefCounted { -public: - static PassRefPtr create() { return adoptRef(new RTCConfigurationPrivate()); } - virtual ~RTCConfigurationPrivate() { } - - void appendServer(PassRefPtr server) { m_privateServers.append(server); } - size_t numberOfServers() { return m_privateServers.size(); } - RTCIceServerPrivate* server(size_t index) { return m_privateServers[index].get(); } - - const String& iceTransports() const { return m_iceTransports; } - void setIceTransports(const String& iceTransports) - { - if (iceTransports == "none" || iceTransports == "relay" || iceTransports == "all") - m_iceTransports = iceTransports; - } - - const String& requestIdentity() const { return m_requestIdentity; } - void setRequestIdentity(const String& requestIdentity) - { - if (requestIdentity == "yes" || requestIdentity == "no" || requestIdentity == "ifconfigured") - m_requestIdentity = requestIdentity; - } - - Vector> iceServers() const { return m_privateServers; } - -private: - RTCConfigurationPrivate() - : m_iceTransports("all") - , m_requestIdentity("ifconfigured") - { - } - - Vector> m_privateServers; - String m_iceTransports; - String m_requestIdentity; -}; - -} // namespace WebCore - -#endif // ENABLE(MEDIA_STREAM) - -#endif // RTCConfigurationPrivate_h diff --git a/Source/WebCore/platform/mediastream/RTCIceServerPrivate.h b/Source/WebCore/platform/mediastream/RTCIceServerPrivate.h deleted file mode 100644 index 9bd8019b09cb8..0000000000000 --- a/Source/WebCore/platform/mediastream/RTCIceServerPrivate.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (C) 2014 Apple Inc. All rights reserved. - * - * 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. ``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 - * 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. - */ - -#ifndef RTCIceServerPrivate_h -#define RTCIceServerPrivate_h - -#if ENABLE(MEDIA_STREAM) - -#include -#include -#include -#include - -namespace WebCore { - -class RTCIceServerPrivate : public RefCounted { -public: - static PassRefPtr create(const Vector& urls, const String& credential, const String& username) - { - return adoptRef(new RTCIceServerPrivate(urls, credential, username)); - } - virtual ~RTCIceServerPrivate() { } - - const Vector& urls() { return m_urls; } - const String& credential() { return m_credential; } - const String& username() { return m_username; } - -private: - RTCIceServerPrivate(const Vector& urls, const String& credential, const String& username) - : m_urls(urls) - , m_credential(credential) - , m_username(username) - { - } - - Vector m_urls; - String m_credential; - String m_username; -}; - -} // namespace WebCore - -#endif // ENABLE(MEDIA_STREAM) - -#endif // RTCIceServerPrivate_h diff --git a/Source/WebCore/platform/mediastream/RTCOfferAnswerOptionsPrivate.h b/Source/WebCore/platform/mediastream/RTCOfferAnswerOptionsPrivate.h deleted file mode 100644 index 21e283e282bad..0000000000000 --- a/Source/WebCore/platform/mediastream/RTCOfferAnswerOptionsPrivate.h +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright (C) 2014 Apple Inc. All rights reserved. - * - * 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. ``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 - * 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. - */ - -#ifndef RTCOfferAnswerOptionsPrivate_h -#define RTCOfferAnswerOptionsPrivate_h - -#if ENABLE(MEDIA_STREAM) - -#include -#include -#include - -namespace WebCore { - -static bool validateRequestIdentity(const String& value) -{ - return value == "yes" || value == "no" || value == "ifconfigured"; -} - -class RTCOfferAnswerOptionsPrivate : public RefCounted { -public: - static PassRefPtr create() - { - return adoptRef(new RTCOfferAnswerOptionsPrivate()); - } - - const String& requestIdentity() const { return m_requestIdentity; } - void setRequestIdentity(const String& requestIdentity) - { - if (!validateRequestIdentity(requestIdentity)) - return; - - m_requestIdentity = requestIdentity; - } - - virtual ~RTCOfferAnswerOptionsPrivate() { } - -protected: - RTCOfferAnswerOptionsPrivate() - : m_requestIdentity("ifconfigured") - { - } - -private: - String m_requestIdentity; -}; - -class RTCOfferOptionsPrivate : public RTCOfferAnswerOptionsPrivate { -public: - static PassRefPtr create() - { - return adoptRef(new RTCOfferOptionsPrivate()); - } - - int64_t offerToReceiveVideo() const { return m_offerToReceiveVideo; } - void setOfferToReceiveVideo(int64_t offerToReceiveVideo) { m_offerToReceiveVideo = offerToReceiveVideo; } - int64_t offerToReceiveAudio() const { return m_offerToReceiveAudio; } - void setOfferToReceiveAudio(int64_t offerToReceiveAudio) { m_offerToReceiveAudio = offerToReceiveAudio; } - bool voiceActivityDetection() const { return m_voiceActivityDetection; } - void setVoiceActivityDetection(bool voiceActivityDetection) { m_voiceActivityDetection = voiceActivityDetection; } - bool iceRestart() const { return m_iceRestart; } - void setIceRestart(bool iceRestart) { m_iceRestart = iceRestart; } - - virtual ~RTCOfferOptionsPrivate() { } - -private: - RTCOfferOptionsPrivate() - : RTCOfferAnswerOptionsPrivate() - , m_offerToReceiveVideo(0) - , m_offerToReceiveAudio(0) - , m_voiceActivityDetection(true) - , m_iceRestart(false) - { - } - - int64_t m_offerToReceiveVideo; - int64_t m_offerToReceiveAudio; - bool m_voiceActivityDetection; - bool m_iceRestart; -}; - -} // namespace WebCore - -#endif // ENABLE(MEDIA_STREAM) - -#endif // RTCOfferAnswerOptionsPrivate_h diff --git a/Source/WebCore/platform/mediastream/SDPScriptResource.h b/Source/WebCore/platform/mediastream/SDPScriptResource.h new file mode 100644 index 0000000000000..aac4f3090b922 --- /dev/null +++ b/Source/WebCore/platform/mediastream/SDPScriptResource.h @@ -0,0 +1,593 @@ +/* + * Copyright (C) 2015 Ericsson AB. All rights reserved. + * + * 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. + * 3. Neither the name of Ericsson nor the names of its contributors + * may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT + * OWNER OR 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. + */ + +#ifndef SDPScriptResource_h +#define SDPScriptResource_h + +#if ENABLE(MEDIA_STREAM) + + +namespace WebCore { + +namespace SDPScriptResource { + +const char* script = "/*\ + * Copyright (C) 2014-2015 Ericsson AB. All rights reserved.\ + *\ + * 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 THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT\ + * OWNER OR 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.\ + */\ +\ +\"use strict\";\ +\ +if (typeof(SDP) == \"undefined\")\ + var SDP = {};\ +\ +(function () {\ + var regexps = {\ + \"vline\": \"^v=([\\\\d]+).*$\",\ + \"oline\": \"^o=([\\\\w\\\\-@\\\\.]+) ([\\\\d]+) ([\\\\d]+) IN (IP[46]) ([\\\\d\\\\.a-f\\\\:]+).*$\",\ + \"sline\": \"^s=(.*)$\",\ + \"tline\": \"^t=([\\\\d]+) ([\\\\d]+).*$\",\ + \"cline\": \"^c=IN (IP[46]) ([\\\\d\\\\.a-f\\\\:]+).*$\",\ + \"msidsemantic\": \"^a=msid-semantic: *WMS .*$\",\ + \"mblock\": \"^m=(audio|video|application) ([\\\\d]+) ([A-Z/]+)([\\\\d ]*)$\\\\r?\\\\n\",\ + \"mode\": \"^a=(sendrecv|sendonly|recvonly|inactive).*$\",\ + \"rtpmap\": \"^a=rtpmap:${type} ([\\\\w\\\\-]+)/([\\\\d]+)/?([\\\\d]+)?.*$\",\ + \"fmtp\": \"^a=fmtp:${type} ([\\\\w\\\\-=;]+).*$\",\ + \"param\": \"([\\\\w\\\\-]+)=([\\\\w\\\\-]+);?\",\ + \"nack\": \"^a=rtcp-fb:${type} nack$\",\ + \"nackpli\": \"^a=rtcp-fb:${type} nack pli$\",\ + \"ccmfir\": \"^a=rtcp-fb:${type} ccm fir$\",\ + \"rtcp\": \"^a=rtcp:([\\\\d]+)( IN (IP[46]) ([\\\\d\\\\.a-f\\\\:]+))?.*$\",\ + \"rtcpmux\": \"^a=rtcp-mux.*$\",\ + \"cname\": \"^a=ssrc:(\\\\d+) cname:([\\\\w+/\\\\-@\\\\.]+).*$\",\ + \"msid\": \"^a=(ssrc:\\\\d+ )?msid:([\\\\w+/\\\\-=]+) +([\\\\w+/\\\\-=]+).*$\",\ + \"ufrag\": \"^a=ice-ufrag:([\\\\w+/]*).*$\",\ + \"pwd\": \"^a=ice-pwd:([\\\\w+/]*).*$\",\ + \"candidate\": \"^a=candidate:(\\\\d+) (\\\\d) (UDP|TCP) ([\\\\d\\\\.]*) ([\\\\d\\\\.a-f\\\\:]*) (\\\\d*)\" +\ + \" typ ([a-z]*)( raddr ([\\\\d\\\\.a-f\\\\:]*) rport (\\\\d*))?\" +\ + \"( tcptype (active|passive|so))?.*$\",\ + \"fingerprint\": \"^a=fingerprint:(sha-1|sha-256) ([A-Fa-f\\\\d\\:]+).*$\",\ + \"setup\": \"^a=setup:(actpass|active|passive).*$\",\ + \"sctpmap\": \"^a=sctpmap:${port} ([\\\\w\\\\-]+)( [\\\\d]+)?.*$\"\ + };\ +\ + var templates = {\ + \"sdp\":\ + \"v=${version}\\r\\n\" +\ + \"o=${username} ${sessionId} ${sessionVersion} ${netType} ${addressType} ${address}\\r\\n\" +\ + \"s=${sessionName}\\r\\n\" +\ + \"t=${startTime} ${stopTime}\\r\\n\" +\ + \"${msidsemanticLine}\",\ +\ + \"msidsemantic\": \"a=msid-semantic:WMS ${mediaStreamIds}\\r\\n\",\ +\ + \"mblock\":\ + \"m=${type} ${port} ${protocol} ${fmt}\\r\\n\" +\ + \"c=${netType} ${addressType} ${address}\\r\\n\" +\ + \"${rtcpLine}\" +\ + \"${rtcpMuxLine}\" +\ + \"a=${mode}\\r\\n\" +\ + \"${rtpMapLines}\" +\ + \"${fmtpLines}\" +\ + \"${nackLines}\" +\ + \"${nackpliLines}\" +\ + \"${ccmfirLines}\" +\ + \"${cnameLines}\" +\ + \"${msidLines}\" +\ + \"${iceCredentialLines}\" +\ + \"${candidateLines}\" +\ + \"${dtlsFingerprintLine}\" +\ + \"${dtlsSetupLine}\" +\ + \"${sctpmapLine}\",\ +\ + \"rtcp\": \"a=rtcp:${port}${[ ]netType}${[ ]addressType}${[ ]address}\\r\\n\",\ + \"rtcpMux\": \"a=rtcp-mux\\r\\n\",\ +\ + \"rtpMap\": \"a=rtpmap:${type} ${encodingName}/${clockRate}${[/]channels}\\r\\n\",\ + \"fmtp\": \"a=fmtp:${type} ${parameters}\\r\\n\",\ + \"nack\": \"a=rtcp-fb:${type} nack\\r\\n\",\ + \"nackpli\": \"a=rtcp-fb:${type} nack pli\\r\\n\",\ + \"ccmfir\": \"a=rtcp-fb:${type} ccm fir\\r\\n\",\ +\ + \"cname\": \"a=ssrc:${ssrc} cname:${cname}\\r\\n\",\ + \"msid\": \"a=${[ssrc:]ssrc[ ]}msid:${mediaStreamId} ${mediaStreamTrackId}\\r\\n\",\ +\ + \"iceCredentials\":\ + \"a=ice-ufrag:${ufrag}\\r\\n\" +\ + \"a=ice-pwd:${password}\\r\\n\",\ +\ + \"candidate\":\ + \"a=candidate:${foundation} ${componentId} ${transport} ${priority} ${address} ${port}\" +\ + \" typ ${type}${[ raddr ]relatedAddress}${[ rport ]relatedPort}${[ tcptype ]tcpType}\\r\\n\",\ +\ + \"dtlsFingerprint\": \"a=fingerprint:${fingerprintHashFunction} ${fingerprint}\\r\\n\",\ + \"dtlsSetup\": \"a=setup:${setup}\\r\\n\",\ +\ + \"sctpmap\": \"a=sctpmap:${port} ${app}${[ ]streams}\\r\\n\"\ + };\ +\ + function match(data, pattern, flags, alt) {\ + var r = new RegExp(pattern, flags);\ + return data.match(r) || alt && alt.match(r) || null;\ + }\ +\ + function addDefaults(obj, defaults) {\ + for (var p in defaults) {\ + if (!defaults.hasOwnProperty(p))\ + continue;\ + if (typeof(obj[p]) == \"undefined\")\ + obj[p] = defaults[p];\ + }\ + }\ +\ + function fillTemplate(template, info) {\ + var text = template;\ + for (var p in info) {\ + if (!info.hasOwnProperty(p))\ + continue;\ + var r = new RegExp(\"\\\\${(\\\\[[^\\\\]]+\\\\])?\" + p + \"(\\\\[[^\\\\]]+\\\\])?}\");\ + text = text.replace(r, function (_, prefix, suffix) {\ + if (!info[p] && info[p] != 0)\ + return \"\";\ + prefix = prefix ? prefix.substr(1, prefix.length - 2) : \"\";\ + suffix = suffix ? suffix.substr(1, suffix.length - 2) : \"\";\ + return prefix + info[p] + suffix;\ + });\ + }\ + return text;\ + }\ +\ + SDP.parse = function (sdpText) {\ + sdpText = new String(sdpText);\ + var sdpObj = {};\ + var parts = sdpText.split(new RegExp(regexps.mblock, \"m\")) || [sdpText];\ + var sblock = parts.shift();\ + var version = parseInt((match(sblock, regexps.vline, \"m\") || [])[1]);\ + if (!isNaN(version))\ + sdpObj.version = version;\ + var originator = match(sblock, regexps.oline, \"m\");;\ + if (originator) {\ + sdpObj.originator = {\ + \"username\": originator[1],\ + \"sessionId\": originator[2],\ + \"sessionVersion\": parseInt(originator[3]),\ + \"netType\": \"IN\",\ + \"addressType\": originator[4],\ + \"address\": originator[5]\ + };\ + }\ + var sessionName = match(sblock, regexps.sline, \"m\");\ + if (sessionName)\ + sdpObj.sessionName = sessionName[1];\ + var sessionTime = match(sblock, regexps.tline, \"m\");\ + if (sessionTime) {\ + sdpObj.startTime = parseInt(sessionTime[1]);\ + sdpObj.stopTime = parseInt(sessionTime[2]);\ + }\ + var hasMediaStreamId = !!match(sblock, regexps.msidsemantic, \"m\");\ + sdpObj.mediaDescriptions = [];\ +\ + for (var i = 0; i < parts.length; i += 5) {\ + var mediaDescription = {\ + \"type\": parts[i],\ + \"port\": parts[i + 1],\ + \"protocol\": parts[i + 2],\ + };\ + var fmt = parts[i + 3].replace(/^[\\s\\uFEFF\\xA0]+/, '')\ + .split(/ +/)\ + .map(function (x) {\ + return parseInt(x);\ + });\ + var mblock = parts[i + 4];\ +\ + var connection = match(mblock, regexps.cline, \"m\", sblock);\ + if (connection) {\ + mediaDescription.netType = \"IN\";\ + mediaDescription.addressType = connection[1];\ + mediaDescription.address = connection[2];\ + }\ + var mode = match(mblock, regexps.mode, \"m\", sblock);\ + if (mode)\ + mediaDescription.mode = mode[1];\ +\ + var payloadTypes = [];\ + if (match(mediaDescription.protocol, \"RTP/S?AVPF?\")) {\ + mediaDescription.payloads = [];\ + payloadTypes = fmt;\ + }\ + payloadTypes.forEach(function (payloadType) {\ + var payload = { \"type\": payloadType };\ + var rtpmapLine = fillTemplate(regexps.rtpmap, payload);\ + var rtpmap = match(mblock, rtpmapLine, \"m\");\ + if (rtpmap) {\ + payload.encodingName = rtpmap[1];\ + payload.clockRate = parseInt(rtpmap[2]);\ + if (mediaDescription.type == \"audio\")\ + payload.channels = parseInt(rtpmap[3]) || 1;\ + else if (mediaDescription.type == \"video\") {\ + var nackLine = fillTemplate(regexps.nack, payload);\ + payload.nack = !!match(mblock, nackLine, \"m\");\ + var nackpliLine = fillTemplate(regexps.nackpli, payload);\ + payload.nackpli = !!match(mblock, nackpliLine, \"m\");\ + var ccmfirLine = fillTemplate(regexps.ccmfir, payload);\ + payload.ccmfir = !!match(mblock, ccmfirLine, \"m\");\ + }\ + } else if (payloadType == 0 || payloadType == 8) {\ + payload.encodingName = payloadType == 8 ? \"PCMA\" : \"PCMU\";\ + payload.clockRate = 8000;\ + payload.channels = 1;\ + }\ + var fmtpLine = fillTemplate(regexps.fmtp, payload);\ + var fmtp = match(mblock, fmtpLine, \"m\");\ + if (fmtp) {\ + payload.parameters = {};\ + fmtp[1].replace(new RegExp(regexps.param, \"g\"),\ + function(_, key, value) {\ + key = key.replace(/-([a-z])/g, function (_, c) {\ + return c.toUpperCase();\ + });\ + payload.parameters[key] = isNaN(+value) ? value : +value;\ + });\ + }\ + mediaDescription.payloads.push(payload);\ + });\ +\ + var rtcp = match(mblock, regexps.rtcp, \"m\");\ + if (rtcp) {\ + mediaDescription.rtcp = {\ + \"netType\": \"IN\",\ + \"port\": parseInt(rtcp[1])\ + };\ + if (rtcp[2]) {\ + mediaDescription.rtcp.addressType = rtcp[3];\ + mediaDescription.rtcp.address = rtcp[4];\ + }\ + }\ + var rtcpmux = match(mblock, regexps.rtcpmux, \"m\", sblock);\ + if (rtcpmux) {\ + if (!mediaDescription.rtcp)\ + mediaDescription.rtcp = {};\ + mediaDescription.rtcp.mux = true;\ + }\ +\ + var cnameLines = match(mblock, regexps.cname, \"mg\");\ + if (cnameLines) {\ + mediaDescription.ssrcs = [];\ + cnameLines.forEach(function (line) {\ + var cname = match(line, regexps.cname, \"m\");\ + mediaDescription.ssrcs.push(parseInt(cname[1]));\ + if (!mediaDescription.cname)\ + mediaDescription.cname = cname[2];\ + });\ + }\ +\ + if (hasMediaStreamId) {\ + var msid = match(mblock, regexps.msid, \"m\");\ + if (msid) {\ + mediaDescription.mediaStreamId = msid[2];\ + mediaDescription.mediaStreamTrackId = msid[3];\ + }\ + }\ +\ + var ufrag = match(mblock, regexps.ufrag, \"m\", sblock);\ + var pwd = match(mblock, regexps.pwd, \"m\", sblock);\ + if (ufrag && pwd) {\ + mediaDescription.ice = {\ + \"ufrag\": ufrag[1],\ + \"password\": pwd[1]\ + };\ + }\ + var candidateLines = match(mblock, regexps.candidate, \"mig\");\ + if (candidateLines) {\ + if (!mediaDescription.ice)\ + mediaDescription.ice = {};\ + mediaDescription.ice.candidates = [];\ + candidateLines.forEach(function (line) {\ + var candidateLine = match(line, regexps.candidate, \"mi\");\ + var candidate = {\ + \"foundation\": candidateLine[1],\ + \"componentId\": parseInt(candidateLine[2]),\ + \"transport\": candidateLine[3].toUpperCase(),\ + \"priority\": parseInt(candidateLine[4]),\ + \"address\": candidateLine[5],\ + \"port\": parseInt(candidateLine[6]),\ + \"type\": candidateLine[7]\ + };\ + if (candidateLine[9])\ + candidate.relatedAddress = candidateLine[9];\ + if (!isNaN(candidateLine[10]))\ + candidate.relatedPort = parseInt(candidateLine[10]);\ + if (candidateLine[12])\ + candidate.tcpType = candidateLine[12];\ + else if (candidate.transport == \"TCP\") {\ + if (candidate.port == 0 || candidate.port == 9) {\ + candidate.tcpType = \"active\";\ + candidate.port = 9;\ + } else {\ + return;\ + }\ + }\ + mediaDescription.ice.candidates.push(candidate);\ + });\ + }\ +\ + var fingerprint = match(mblock, regexps.fingerprint, \"mi\", sblock);\ + if (fingerprint) {\ + mediaDescription.dtls = {\ + \"fingerprintHashFunction\": fingerprint[1].toLowerCase(),\ + \"fingerprint\": fingerprint[2].toUpperCase()\ + };\ + }\ + var setup = match(mblock, regexps.setup, \"m\", sblock);\ + if (setup) {\ + if (!mediaDescription.dtls)\ + mediaDescription.dtls = {};\ + mediaDescription.dtls.setup = setup[1];\ + }\ +\ + if (mediaDescription.protocol == \"DTLS/SCTP\") {\ + mediaDescription.sctp = {\ + \"port\": fmt[0]\ + };\ + var sctpmapLine = fillTemplate(regexps.sctpmap, mediaDescription.sctp);\ + var sctpmap = match(mblock, sctpmapLine, \"m\");\ + if (sctpmap) {\ + mediaDescription.sctp.app = sctpmap[1];\ + if (sctpmap[2])\ + mediaDescription.sctp.streams = parseInt(sctpmap[2]);\ + }\ + }\ +\ + sdpObj.mediaDescriptions.push(mediaDescription);\ + }\ +\ + return sdpObj;\ + };\ +\ + SDP.generate = function (sdpObj) {\ + sdpObj = JSON.parse(JSON.stringify(sdpObj));\ + addDefaults(sdpObj, {\ + \"version\": 0,\ + \"originator\": {},\ + \"sessionName\": \"-\",\ + \"startTime\": 0,\ + \"stopTime\": 0,\ + \"mediaDescriptions\": []\ + });\ + addDefaults(sdpObj.originator, {\ + \"username\": \"-\",\ + \"sessionId\": \"\" + Math.floor((Math.random() + +new Date()) * 1e6),\ + \"sessionVersion\": 1,\ + \"netType\": \"IN\",\ + \"addressType\": \"IP4\",\ + \"address\": \"127.0.0.1\"\ + });\ + var sdpText = fillTemplate(templates.sdp, sdpObj);\ + sdpText = fillTemplate(sdpText, sdpObj.originator);\ +\ + var msidsemanticLine = \"\";\ + var mediaStreamIds = [];\ + sdpObj.mediaDescriptions.forEach(function (mdesc) {\ + if (mdesc.mediaStreamId && mdesc.mediaStreamTrackId\ + && mediaStreamIds.indexOf(mdesc.mediaStreamId) == -1)\ + mediaStreamIds.push(mdesc.mediaStreamId);\ + });\ + if (mediaStreamIds.length) {\ + var msidsemanticLine = fillTemplate(templates.msidsemantic,\ + { \"mediaStreamIds\": mediaStreamIds.join(\" \") });\ + }\ + sdpText = fillTemplate(sdpText, { \"msidsemanticLine\": msidsemanticLine });\ +\ + sdpObj.mediaDescriptions.forEach(function (mediaDescription) {\ + addDefaults(mediaDescription, {\ + \"port\": 1,\ + \"protocol\": \"RTP/SAVPF\",\ + \"netType\": \"IN\",\ + \"addressType\": \"IP4\",\ + \"address\": \"0.0.0.0\",\ + \"mode\": \"sendrecv\",\ + \"payloads\": [],\ + \"rtcp\": {}\ + });\ + var mblock = fillTemplate(templates.mblock, mediaDescription);\ +\ + var payloadInfo = {\"rtpMapLines\": \"\", \"fmtpLines\": \"\", \"nackLines\": \"\",\ + \"nackpliLines\": \"\", \"ccmfirLines\": \"\"};\ + mediaDescription.payloads.forEach(function (payload) {\ + if (payloadInfo.fmt)\ + payloadInfo.fmt += \" \" + payload.type;\ + else\ + payloadInfo.fmt = payload.type;\ + if (!payload.channels || payload.channels == 1)\ + payload.channels = null;\ + payloadInfo.rtpMapLines += fillTemplate(templates.rtpMap, payload);\ + if (payload.parameters) {\ + var fmtpInfo = { \"type\": payload.type, \"parameters\": \"\" };\ + for (var p in payload.parameters) {\ + var param = p.replace(/([A-Z])([a-z])/g, function (_, a, b) {\ + return \"-\" + a.toLowerCase() + b;\ + });\ + if (fmtpInfo.parameters)\ + fmtpInfo.parameters += \";\";\ + fmtpInfo.parameters += param + \"=\" + payload.parameters[p];\ + }\ + payloadInfo.fmtpLines += fillTemplate(templates.fmtp, fmtpInfo);\ + }\ + if (payload.nack)\ + payloadInfo.nackLines += fillTemplate(templates.nack, payload);\ + if (payload.nackpli)\ + payloadInfo.nackpliLines += fillTemplate(templates.nackpli, payload);\ + if (payload.ccmfir)\ + payloadInfo.ccmfirLines += fillTemplate(templates.ccmfir, payload);\ + });\ + mblock = fillTemplate(mblock, payloadInfo);\ +\ + var rtcpInfo = {\"rtcpLine\": \"\", \"rtcpMuxLine\": \"\"};\ + if (mediaDescription.rtcp.port) {\ + addDefaults(mediaDescription.rtcp, {\ + \"netType\": \"IN\",\ + \"addressType\": \"IP4\",\ + \"address\": \"\"\ + });\ + if (!mediaDescription.rtcp.address)\ + mediaDescription.rtcp.netType = mediaDescription.rtcp.addressType = \"\";\ + rtcpInfo.rtcpLine = fillTemplate(templates.rtcp, mediaDescription.rtcp);\ + }\ + if (mediaDescription.rtcp.mux)\ + rtcpInfo.rtcpMuxLine = templates.rtcpMux;\ + mblock = fillTemplate(mblock, rtcpInfo);\ +\ + var srcAttributeLines = { \"cnameLines\": \"\", \"msidLines\": \"\" };\ + var srcAttributes = {\ + \"cname\": mediaDescription.cname,\ + \"mediaStreamId\": mediaDescription.mediaStreamId,\ + \"mediaStreamTrackId\": mediaDescription.mediaStreamTrackId\ + };\ + if (mediaDescription.cname && mediaDescription.ssrcs) {\ + mediaDescription.ssrcs.forEach(function (ssrc) {\ + srcAttributes.ssrc = ssrc;\ + srcAttributeLines.cnameLines += fillTemplate(templates.cname, srcAttributes);\ + if (mediaDescription.mediaStreamId && mediaDescription.mediaStreamTrackId)\ + srcAttributeLines.msidLines += fillTemplate(templates.msid, srcAttributes);\ + });\ + } else if (mediaDescription.mediaStreamId && mediaDescription.mediaStreamTrackId) {\ + srcAttributes.ssrc = null;\ + srcAttributeLines.msidLines += fillTemplate(templates.msid, srcAttributes);\ + }\ + mblock = fillTemplate(mblock, srcAttributeLines);\ +\ + var iceInfo = {\"iceCredentialLines\": \"\", \"candidateLines\": \"\"};\ + if (mediaDescription.ice) {\ + iceInfo.iceCredentialLines = fillTemplate(templates.iceCredentials,\ + mediaDescription.ice);\ + if (mediaDescription.ice.candidates) {\ + mediaDescription.ice.candidates.forEach(function (candidate) {\ + addDefaults(candidate, {\ + \"relatedAddress\": null,\ + \"relatedPort\": null,\ + \"tcpType\": null\ + });\ + iceInfo.candidateLines += fillTemplate(templates.candidate, candidate);\ + });\ + }\ + }\ + mblock = fillTemplate(mblock, iceInfo);\ +\ + var dtlsInfo = { \"dtlsFingerprintLine\": \"\", \"dtlsSetupLine\": \"\" };\ + if (mediaDescription.dtls) {\ + if (mediaDescription.dtls.fingerprint) {\ + dtlsInfo.dtlsFingerprintLine = fillTemplate(templates.dtlsFingerprint,\ + mediaDescription.dtls);\ + }\ + addDefaults(mediaDescription.dtls, {\"setup\": \"actpass\"});\ + dtlsInfo.dtlsSetupLine = fillTemplate(templates.dtlsSetup, mediaDescription.dtls);\ + }\ + mblock = fillTemplate(mblock, dtlsInfo);\ +\ + var sctpInfo = {\"sctpmapLine\": \"\", \"fmt\": \"\"};\ + if (mediaDescription.sctp) {\ + addDefaults(mediaDescription.sctp, {\"streams\": null});\ + sctpInfo.sctpmapLine = fillTemplate(templates.sctpmap, mediaDescription.sctp);\ + sctpInfo.fmt = mediaDescription.sctp.port;\ + }\ + mblock = fillTemplate(mblock, sctpInfo);\ +\ + sdpText += mblock;\ + });\ +\ + return sdpText;\ + };\ +\ + SDP.generateCandidateLine = function (candidateObj) {\ + addDefaults(candidateObj, {\ + \"relatedAddress\": null,\ + \"relatedPort\": null,\ + \"tcpType\": null\ + });\ + \ + return fillTemplate(templates.candidate, candidateObj);\ + };\ +\ +})();\ +\ +function toSDP(json) {\ + var object = JSON.parse(json);\ + return SDP.generate(object);\ +}\ +\ +function fromSDP(sdp) {\ + var object = SDP.parse(sdp);\ + return JSON.stringify(object);\ +}\ +\ +function iceCandidateToSDP(json) {\ + var candidate = JSON.parse(json);\ + return SDP.generateCandidateLine(candidate).substr(2);\ +}\ +\ +function iceCandidateFromSDP(sdpFragment) {\ + var iceInfo = SDP.parse(\"m=application 0 NONE\\r\\na=\" + sdpFragment + \"\\r\\n\").mediaDescriptions[0].ice;\ + return JSON.stringify(iceInfo.candidates[0]);\ +}"; + +String getString() +{ + return String(script); +} + +} + +} // namespace WebCore + +#endif // ENABLE(MEDIA_STREAM) + +#endif // SDPScriptResource_h diff --git a/Source/WebCore/platform/mediastream/openwebrtc/MediaEndpointOwr.cpp b/Source/WebCore/platform/mediastream/openwebrtc/MediaEndpointOwr.cpp new file mode 100644 index 0000000000000..4f041d4989eeb --- /dev/null +++ b/Source/WebCore/platform/mediastream/openwebrtc/MediaEndpointOwr.cpp @@ -0,0 +1,417 @@ +/* + * Copyright (C) 2015 Ericsson AB. All rights reserved. + * + * 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. + * 3. Neither the name of Ericsson nor the names of its contributors + * may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT + * OWNER OR 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" + +#if ENABLE(MEDIA_STREAM) +#include "MediaEndpointOwr.h" + +#include "MediaEndpointConfiguration.h" +#include "OpenWebRTCUtilities.h" +#include "RealtimeMediaSourceOwr.h" +#include +#include +#include +#include + +namespace WebCore { + +static void gotCandidate(OwrSession*, OwrCandidate*, MediaEndpointOwr*); +static void candidateGatheringDone(OwrSession*, MediaEndpointOwr*); +static void gotDtlsCertificate(OwrSession*, GParamSpec*, MediaEndpointOwr*); +static void gotIncomingSource(OwrMediaSession*, OwrMediaSource*, MediaEndpointOwr*); + +static const Vector candidateTypes = { "host", "srflx", "prflx", "relay" }; +static const Vector candidateTcpTypes = { "", "active", "passive", "so" }; +static const Vector codecTypes = { "NONE", "PCMU", "PCMA", "OPUS", "H264", "VP8" }; + +static std::unique_ptr createMediaEndpointOwr(MediaEndpointClient* client) +{ + return std::unique_ptr(new MediaEndpointOwr(client)); +} + +CreateMediaEndpoint MediaEndpoint::create = createMediaEndpointOwr; + +MediaEndpointOwr::MediaEndpointOwr(MediaEndpointClient* client) + : m_transportAgent(nullptr) + , m_client(client) + , m_numberOfReceivePreparedSessions(0) + , m_numberOfSendPreparedSessions(0) +{ + initializeOpenWebRTC(); +} + +MediaEndpointOwr::~MediaEndpointOwr() +{ + if (m_transportAgent) + g_object_unref(m_transportAgent); +} + +void MediaEndpointOwr::setConfiguration(RefPtr&& configuration) +{ + m_configuration = configuration; +} + +void MediaEndpointOwr::prepareToReceive(MediaEndpointConfiguration* configuration, bool isInitiator) +{ + Vector sessionConfigs; + for (unsigned i = m_sessions.size(); i < configuration->mediaDescriptions().size(); ++i) { + SessionConfig config; + config.type = SessionTypeMedia; + config.isDtlsClient = configuration->mediaDescriptions()[i]->dtlsSetup() == "active"; + sessionConfigs.append(WTF::move(config)); + } + + ensureTransportAgentAndSessions(isInitiator, sessionConfigs); + + // Prepare the new sessions. + for (unsigned i = m_numberOfReceivePreparedSessions; i < m_sessions.size(); ++i) { + prepareMediaSession(OWR_MEDIA_SESSION(m_sessions[i]), configuration->mediaDescriptions()[i].get(), isInitiator); + owr_transport_agent_add_session(m_transportAgent, m_sessions[i]); + } + + m_numberOfReceivePreparedSessions = m_sessions.size(); +} + +static RefPtr findRtxPayload(Vector> payloads, unsigned apt) +{ + for (auto& payload : payloads) { + if (payload->encodingName().upper() == "RTX" && payload->parameters().contains("apt") + && (payload->parameters().get("apt") == apt)) + return payload; + } + return nullptr; +} + +void MediaEndpointOwr::prepareToSend(MediaEndpointConfiguration* configuration, bool isInitiator) +{ + Vector sessionConfigs; + for (unsigned i = m_sessions.size(); i < configuration->mediaDescriptions().size(); ++i) { + SessionConfig config; + config.type = SessionTypeMedia; + config.isDtlsClient = configuration->mediaDescriptions()[i]->dtlsSetup() != "active"; + sessionConfigs.append(WTF::move(config)); + } + + ensureTransportAgentAndSessions(isInitiator, sessionConfigs); + + for (unsigned i = 0; i < m_sessions.size(); ++i) { + if (i >= configuration->mediaDescriptions().size()) + printf("prepareToSend: BAD missing configuration element for %d\n", i); + + OwrSession* session = m_sessions[i]; + PeerMediaDescription& mdesc = *configuration->mediaDescriptions()[i]; + + if (mdesc.type() == "audio" || mdesc.type() == "video") + g_object_set(session, "rtcp-mux", mdesc.rtcpMux(), nullptr); + + if (mdesc.iceCandidates().size()) { + for (auto& candidate : mdesc.iceCandidates()) + internalAddRemoteCandidate(session, *candidate, mdesc.iceUfrag(), mdesc.icePassword()); + } + + if (i < m_numberOfSendPreparedSessions) + continue; + + if (!mdesc.source()) + continue; + + MediaPayload* payload = nullptr; + for (auto& p : mdesc.payloads()) { + if (p->encodingName().upper() != "RTX") { + payload = p.get(); + break; + } + } + + if (!payload) { + printf("prepareToSend: no payloads\n"); + return; + } + + RefPtr rtxPayload = findRtxPayload(mdesc.payloads(), payload->type()); + RealtimeMediaSourceOwr* source = static_cast(mdesc.source()); + + ASSERT(codecTypes.find(payload->encodingName().upper()) != notFound); + OwrCodecType codecType = static_cast(codecTypes.find(payload->encodingName().upper())); + + OwrPayload* sendPayload; + if (mdesc.type() == "audio") + sendPayload = owr_audio_payload_new(codecType, payload->type(), payload->clockRate(), payload->channels()); + else { + sendPayload = owr_video_payload_new(codecType, payload->type(), payload->clockRate(), payload->ccmfir(), payload->nackpli()); + g_object_set(sendPayload, "rtx-payload-type", rtxPayload ? rtxPayload->type() : -1, + "rtx-time", rtxPayload && rtxPayload->parameters().contains("rtxTime") ? rtxPayload->parameters().get("rtxTime") : 0, nullptr); + } + + owr_media_session_set_send_payload(OWR_MEDIA_SESSION(session), sendPayload); + owr_media_session_set_send_source(OWR_MEDIA_SESSION(session), source->mediaSource()); + + m_numberOfSendPreparedSessions = i + 1; + } +} + +void MediaEndpointOwr::addRemoteCandidate(IceCandidate& candidate, unsigned mdescIndex, const String& ufrag, const String& password) +{ + internalAddRemoteCandidate(m_sessions[mdescIndex], candidate, ufrag, password); +} + +void MediaEndpointOwr::stop() +{ + printf("MediaEndpointOwr::stop\n"); +} + +unsigned MediaEndpointOwr::sessionIndex(OwrSession* session) const +{ + unsigned index = m_sessions.find(session); + ASSERT(index != notFound); + return index; +} + +void MediaEndpointOwr::dispatchNewIceCandidate(unsigned sessionIndex, RefPtr&& iceCandidate) +{ + m_client->gotIceCandidate(sessionIndex, WTF::move(iceCandidate)); +} + +void MediaEndpointOwr::dispatchGatheringDone(unsigned sessionIndex) +{ + m_client->doneGatheringCandidates(sessionIndex); +} + +void MediaEndpointOwr::dispatchDtlsCertificate(unsigned sessionIndex, const String& certificate) +{ + m_client->gotDtlsCertificate(sessionIndex, certificate); +} + +void MediaEndpointOwr::dispatchRemoteSource(unsigned sessionIndex, RefPtr&& source) +{ + m_client->gotRemoteSource(sessionIndex, WTF::move(source)); +} + +void MediaEndpointOwr::prepareSession(OwrSession* session, PeerMediaDescription* mediaDescription) +{ + g_object_set_data_full(G_OBJECT(session), "ice-ufrag", g_strdup(mediaDescription->iceUfrag().ascii().data()), g_free); + g_object_set_data_full(G_OBJECT(session), "ice-password", g_strdup(mediaDescription->icePassword().ascii().data()), g_free); + + g_signal_connect(session, "on-new-candidate", G_CALLBACK(gotCandidate), this); + g_signal_connect(session, "on-candidate-gathering-done", G_CALLBACK(candidateGatheringDone), this); + g_signal_connect(session, "notify::dtls-certificate", G_CALLBACK(gotDtlsCertificate), this); +} + +void MediaEndpointOwr::prepareMediaSession(OwrMediaSession* mediaSession, PeerMediaDescription* mediaDescription, bool isInitiator) +{ + prepareSession(OWR_SESSION(mediaSession), mediaDescription); + + bool useRtpMux = !isInitiator && mediaDescription->rtcpMux(); + g_object_set(mediaSession, "rtcp-mux", useRtpMux, + "cname", mediaDescription->cname().ascii().data(), + "send-ssrc", mediaDescription->ssrcs()[0], + nullptr); + + g_signal_connect(mediaSession, "on-incoming-source", G_CALLBACK(gotIncomingSource), this); + + for (auto& payload : mediaDescription->payloads()) { + if (payload->encodingName().upper() == "RTX") + continue; + + RefPtr rtxPayload = findRtxPayload(mediaDescription->payloads(), payload->type()); + + ASSERT(codecTypes.find(payload->encodingName()) != notFound); + OwrCodecType codecType = static_cast(codecTypes.find(payload->encodingName())); + + OwrPayload* receivePayload; + if (mediaDescription->type() == "audio") + receivePayload = owr_audio_payload_new(codecType, payload->type(), payload->clockRate(), payload->channels()); + else { + receivePayload = owr_video_payload_new(codecType, payload->type(), payload->clockRate(), payload->ccmfir(), payload->nackpli()); + g_object_set(receivePayload, "rtx-payload-type", rtxPayload ? rtxPayload->type() : -1, + "rtx-time", rtxPayload && rtxPayload->parameters().contains("rtxTime") ? rtxPayload->parameters().get("rtxTime") : 0, nullptr); + } + + owr_media_session_add_receive_payload(mediaSession, receivePayload); + } +} + +void MediaEndpointOwr::ensureTransportAgentAndSessions(bool isInitiator, const Vector& sessionConfigs) +{ + if (!m_transportAgent) { + m_transportAgent = owr_transport_agent_new(false); + + for (auto& server : m_configuration->iceServers()) { + // FIXME: parse url type and port + owr_transport_agent_add_helper_server(m_transportAgent, OWR_HELPER_SERVER_TYPE_STUN, + server->urls()[0].ascii().data(), 3478, nullptr, nullptr); + } + } + + g_object_set(m_transportAgent, "ice-controlling-mode", isInitiator, nullptr); + + for (auto& config : sessionConfigs) + m_sessions.append(OWR_SESSION(owr_media_session_new(config.isDtlsClient))); +} + +void MediaEndpointOwr::internalAddRemoteCandidate(OwrSession* session, IceCandidate& candidate, const String& ufrag, const String& password) +{ + gboolean rtcpMux; + g_object_get(session, "rtcp-mux", &rtcpMux, nullptr); + + if (rtcpMux && candidate.componentId() == OWR_COMPONENT_TYPE_RTCP) + return; + + ASSERT(candidateTypes.find(candidate.type()) != notFound); + printf("ASSERT: %d\n", (candidateTypes.find(candidate.type()) != notFound)); + + OwrCandidateType candidateType = static_cast(candidateTypes.find(candidate.type())); + OwrComponentType componentId = static_cast(candidate.componentId()); + OwrTransportType transportType; + + if (candidate.transport().upper() == "UDP") + transportType = OWR_TRANSPORT_TYPE_UDP; + else { + ASSERT(candidateTcpTypes.find(candidate.tcpType()) != notFound); + printf("ASSERT: %d\n", (candidateTcpTypes.find(candidate.tcpType()) != notFound)); + transportType = static_cast(candidateTcpTypes.find(candidate.tcpType())); + } + + OwrCandidate* owrCandidate = owr_candidate_new(candidateType, componentId); + g_object_set(owrCandidate, "transport-type", transportType, + "address", candidate.address().ascii().data(), + "port", candidate.port(), + "base-address", candidate.relatedAddress().ascii().data(), + "base-port", candidate.relatedPort(), + "priority", candidate.priority(), + "foundation", candidate.foundation().ascii().data(), + "ufrag", ufrag.ascii().data(), + "password", password.ascii().data(), + nullptr); + + owr_session_add_remote_candidate(session, owrCandidate); +} + +static void gotCandidate(OwrSession* session, OwrCandidate* candidate, MediaEndpointOwr* mediaEndpoint) +{ + OwrCandidateType candidateType; + gchar* foundation; + OwrComponentType componentId; + OwrTransportType transportType; + gint priority; + gchar* address; + guint port; + gchar* relatedAddress; + guint relatedPort; + + g_object_get(candidate, "type", &candidateType, + "foundation", &foundation, + "component-type", &componentId, + "transport-type", &transportType, + "priority", &priority, + "address", &address, + "port", &port, + "base-address", &relatedAddress, + "base-port", &relatedPort, + nullptr); + + ASSERT(candidateType >= 0 && candidateType < candidateTypes.size()); + ASSERT(transportType >= 0 && transportType < candidateTcpTypes.size()); + + RefPtr iceCandidate = IceCandidate::create(); + iceCandidate->setType(candidateTypes[candidateType]); + iceCandidate->setFoundation(foundation); + iceCandidate->setComponentId(componentId); + iceCandidate->setPriority(priority); + iceCandidate->setAddress(address); + iceCandidate->setPort(port ? port : 9); + + if (transportType == OWR_TRANSPORT_TYPE_UDP) + iceCandidate->setTransport("UDP"); + else { + iceCandidate->setTransport("TCP"); + iceCandidate->setTcpType(candidateTcpTypes[transportType]); + } + + if (candidateType != OWR_CANDIDATE_TYPE_HOST) { + iceCandidate->setRelatedAddress(relatedAddress); + iceCandidate->setRelatedPort(relatedPort ? relatedPort : 9); + } + + g_object_set(G_OBJECT(candidate), "ufrag", g_object_get_data(G_OBJECT(session), "ice-ufrag"), + "password", g_object_get_data(G_OBJECT(session), "ice-password"), + nullptr); + + mediaEndpoint->dispatchNewIceCandidate(mediaEndpoint->sessionIndex(session), WTF::move(iceCandidate)); + + g_free(foundation); + g_free(address); + g_free(relatedAddress); +} + +static void candidateGatheringDone(OwrSession* session, MediaEndpointOwr* mediaEndpoint) +{ + mediaEndpoint->dispatchGatheringDone(mediaEndpoint->sessionIndex(session)); +} + +static void gotDtlsCertificate(OwrSession* session, GParamSpec*, MediaEndpointOwr* mediaEndpoint) +{ + gchar* pem; + g_object_get(session, "dtls-certificate", &pem, nullptr); + + String certificate(pem); + g_free(pem); + + mediaEndpoint->dispatchDtlsCertificate(mediaEndpoint->sessionIndex(session), certificate); +} + +static void gotIncomingSource(OwrMediaSession* mediaSession, OwrMediaSource* source, MediaEndpointOwr* mediaEndpoint) +{ + String name; + String id("not used"); + OwrMediaType mediaType; + + g_object_get(source, "media-type", &mediaType, nullptr); + + RealtimeMediaSource::Type sourceType; + if (mediaType == OWR_MEDIA_TYPE_AUDIO) { + sourceType = RealtimeMediaSource::Audio; + name = "remote audio"; + } + else if (mediaType == OWR_MEDIA_TYPE_VIDEO) { + sourceType = RealtimeMediaSource::Video; + name = "remote video"; + } + else + ASSERT_NOT_REACHED(); + + RefPtr mediaSource = adoptRef(new RealtimeMediaSourceOwr(source, id, sourceType, name)); + mediaEndpoint->dispatchRemoteSource(mediaEndpoint->sessionIndex(OWR_SESSION(mediaSession)), WTF::move(mediaSource)); +} + +} // namespace WebCore + +#endif // ENABLE(MEDIA_STREAM) diff --git a/Source/WebCore/platform/mediastream/openwebrtc/MediaEndpointOwr.h b/Source/WebCore/platform/mediastream/openwebrtc/MediaEndpointOwr.h new file mode 100644 index 0000000000000..de226431faa73 --- /dev/null +++ b/Source/WebCore/platform/mediastream/openwebrtc/MediaEndpointOwr.h @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2015 Ericsson AB. All rights reserved. + * + * 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. + * 3. Neither the name of Ericsson nor the names of its contributors + * may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT + * OWNER OR 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. + */ + +#ifndef MediaEndpointOwr_h +#define MediaEndpointOwr_h + +#if ENABLE(MEDIA_STREAM) + +#include "MediaEndpoint.h" +#include +#include + +namespace WebCore { + +class PeerMediaDescription; +class RTCConfigurationPrivate; + +class MediaEndpointOwr : public MediaEndpoint { +public: + MediaEndpointOwr(MediaEndpointClient*); + ~MediaEndpointOwr(); + + virtual void setConfiguration(RefPtr&&) override; + + virtual void prepareToReceive(MediaEndpointConfiguration*, bool isInitiator) override; + virtual void prepareToSend(MediaEndpointConfiguration*, bool isInitiator) override; + + virtual void addRemoteCandidate(IceCandidate&, unsigned mdescIndex, const String& ufrag, const String& password) override; + + virtual void stop() override; + + unsigned sessionIndex(OwrSession*) const; + + void dispatchNewIceCandidate(unsigned sessionIndex, RefPtr&&); + void dispatchGatheringDone(unsigned sessionIndex); + void dispatchDtlsCertificate(unsigned sessionIndex, const String& certificate); + void dispatchRemoteSource(unsigned sessionIndex, RefPtr&&); + +private: + enum SessionType { SessionTypeMedia }; + + struct SessionConfig { + SessionType type; + bool isDtlsClient; + }; + + void prepareSession(OwrSession*, PeerMediaDescription*); + void prepareMediaSession(OwrMediaSession*, PeerMediaDescription*, bool isInitiator); + + void ensureTransportAgentAndSessions(bool isInitiator, const Vector& sessionConfigs); + void internalAddRemoteCandidate(OwrSession*, IceCandidate&, const String& ufrag, const String& password); + + RefPtr m_configuration; + + OwrTransportAgent* m_transportAgent; + Vector m_sessions; + + MediaEndpointClient* m_client; + + unsigned m_numberOfReceivePreparedSessions; + unsigned m_numberOfSendPreparedSessions; +}; + +} // namespace WebCore + +#endif // ENABLE(MEDIA_STREAM) + +#endif // MediaEndpointOwr_h diff --git a/Source/WebCore/platform/mediastream/openwebrtc/OpenWebRTCUtilities.cpp b/Source/WebCore/platform/mediastream/openwebrtc/OpenWebRTCUtilities.cpp index e82a7356844bd..e4cfb59df501d 100644 --- a/Source/WebCore/platform/mediastream/openwebrtc/OpenWebRTCUtilities.cpp +++ b/Source/WebCore/platform/mediastream/openwebrtc/OpenWebRTCUtilities.cpp @@ -44,7 +44,12 @@ namespace WebCore { void initializeOpenWebRTC() { + static bool isInitialized = false; + if (isInitialized) + return; + owr_init(g_main_context_default()); + isInitialized = true; } } diff --git a/Source/WebCore/platform/mediastream/openwebrtc/RealtimeMediaSourceCenterOwr.cpp b/Source/WebCore/platform/mediastream/openwebrtc/RealtimeMediaSourceCenterOwr.cpp index 87a77526d0347..9261771a9188a 100644 --- a/Source/WebCore/platform/mediastream/openwebrtc/RealtimeMediaSourceCenterOwr.cpp +++ b/Source/WebCore/platform/mediastream/openwebrtc/RealtimeMediaSourceCenterOwr.cpp @@ -72,6 +72,15 @@ static void mediaSourcesAvailableCallback(GList* sources, gpointer userData) RealtimeMediaSourceCenterOwr::RealtimeMediaSourceCenterOwr() { initializeOpenWebRTC(); + + // Temporary solution to hint about preferred device names. + char* preferredSourceName = getenv("WEBKIT_AUDIO_SOURCE_NAME"); + if (preferredSourceName) + m_preferredAudioSourceName = String(preferredSourceName); + + preferredSourceName = getenv("WEBKIT_VIDEO_SOURCE_NAME"); + if (preferredSourceName) + m_preferredVideoSourceName = String(preferredSourceName); } RealtimeMediaSourceCenterOwr::~RealtimeMediaSourceCenterOwr() @@ -112,7 +121,7 @@ void RealtimeMediaSourceCenterOwr::createMediaStream(PassRefPtr audioSource = firstSource(RealtimeMediaSource::Audio); + RefPtr audioSource = selectSource(RealtimeMediaSource::Audio); if (audioSource) { audioSource->reset(); audioSources.append(audioSource.release()); @@ -122,7 +131,7 @@ void RealtimeMediaSourceCenterOwr::createMediaStream(PassRefPtr videoSource = firstSource(RealtimeMediaSource::Video); + RefPtr videoSource = selectSource(RealtimeMediaSource::Video); if (videoSource) { videoSource->reset(); videoSources.append(videoSource.release()); @@ -164,22 +173,28 @@ void RealtimeMediaSourceCenterOwr::mediaSourcesAvailable(GList* sources) RealtimeMediaSourceOwrMap::iterator sourceIterator = m_sourceMap.find(id); if (sourceIterator == m_sourceMap.end()) m_sourceMap.add(id, mediaSource); - } // TODO: Make sure contraints are actually validated by checking source types. m_client->constraintsValidated(Vector>(), Vector>()); } -PassRefPtr RealtimeMediaSourceCenterOwr::firstSource(RealtimeMediaSource::Type type) +PassRefPtr RealtimeMediaSourceCenterOwr::selectSource(RealtimeMediaSource::Type type) { + RefPtr selectedSource = nullptr; + const String& preferredSourceName = type == RealtimeMediaSource::Audio ? m_preferredAudioSourceName : m_preferredVideoSourceName; + for (auto iter = m_sourceMap.begin(); iter != m_sourceMap.end(); ++iter) { RefPtr source = iter->value; - if (source->type() == type) - return source; + bool foundPreferred = source->name() == preferredSourceName; + if (source->type() == type && (!selectedSource || foundPreferred)) { + selectedSource = source; + if (foundPreferred) + break; + } } - return nullptr; + return selectedSource; } RefPtr RealtimeMediaSourceCenterOwr::sourceWithUID(const String& UID, RealtimeMediaSource::Type, MediaConstraints*) diff --git a/Source/WebCore/platform/mediastream/openwebrtc/RealtimeMediaSourceCenterOwr.h b/Source/WebCore/platform/mediastream/openwebrtc/RealtimeMediaSourceCenterOwr.h index 1e37e41cb05e9..b51ef4c1422b0 100644 --- a/Source/WebCore/platform/mediastream/openwebrtc/RealtimeMediaSourceCenterOwr.h +++ b/Source/WebCore/platform/mediastream/openwebrtc/RealtimeMediaSourceCenterOwr.h @@ -61,9 +61,12 @@ class RealtimeMediaSourceCenterOwr final : public RealtimeMediaSourceCenter { RefPtr sourceWithUID(const String&, RealtimeMediaSource::Type, MediaConstraints*) override; private: - PassRefPtr firstSource(RealtimeMediaSource::Type); + PassRefPtr selectSource(RealtimeMediaSource::Type); RealtimeMediaSourceOwrMap m_sourceMap; RefPtr m_client; + + String m_preferredAudioSourceName; + String m_preferredVideoSourceName; }; } // namespace WebCore diff --git a/Source/WebKit2/CMakeLists.txt b/Source/WebKit2/CMakeLists.txt index 352b97d3e58de..56d6910b3dec2 100644 --- a/Source/WebKit2/CMakeLists.txt +++ b/Source/WebKit2/CMakeLists.txt @@ -554,8 +554,6 @@ set(WebKit2_SOURCES WebProcess/MediaCache/WebMediaCacheManager.cpp - WebProcess/MediaStream/UserMediaPermissionRequestManager.cpp - WebProcess/Network/NetworkProcessConnection.cpp WebProcess/Network/WebResourceLoadScheduler.cpp WebProcess/Network/WebResourceLoader.cpp diff --git a/Source/WebKit2/PlatformEfl.cmake b/Source/WebKit2/PlatformEfl.cmake index d1dc895e931fa..e2a6f174d9ba9 100644 --- a/Source/WebKit2/PlatformEfl.cmake +++ b/Source/WebKit2/PlatformEfl.cmake @@ -195,6 +195,8 @@ list(APPEND WebKit2_SOURCES WebProcess/InjectedBundle/efl/InjectedBundleEfl.cpp WebProcess/MediaCache/WebMediaKeyStorageManager.cpp + + WebProcess/MediaStream/UserMediaPermissionRequestManager.cpp WebProcess/Plugins/Netscape/unix/PluginProxyUnix.cpp diff --git a/Source/WebKit2/PlatformGTK.cmake b/Source/WebKit2/PlatformGTK.cmake index b5bedecb34186..e264ad97c25fe 100644 --- a/Source/WebKit2/PlatformGTK.cmake +++ b/Source/WebKit2/PlatformGTK.cmake @@ -329,6 +329,8 @@ list(APPEND WebKit2_SOURCES WebProcess/MediaCache/WebMediaKeyStorageManager.cpp + WebProcess/MediaStream/UserMediaPermissionRequestManager.cpp + WebProcess/Plugins/Netscape/unix/PluginProxyUnix.cpp WebProcess/Plugins/Netscape/x11/NetscapePluginX11.cpp diff --git a/Source/WebKit2/PlatformWPE.cmake b/Source/WebKit2/PlatformWPE.cmake index 2437d0470409a..c0a8f2d37a52f 100644 --- a/Source/WebKit2/PlatformWPE.cmake +++ b/Source/WebKit2/PlatformWPE.cmake @@ -94,6 +94,7 @@ list(APPEND WebKit2_SOURCES WebProcess/Cookies/soup/WebKitSoupCookieJarSqlite.cpp WebProcess/InjectedBundle/wpe/InjectedBundleWPE.cpp WebProcess/MediaCache/WebMediaKeyStorageManager.cpp + WebProcess/MediaStream/wpe/UserMediaPermissionRequestManagerWPE.cpp WebProcess/WebCoreSupport/soup/WebFrameNetworkingContext.cpp WebProcess/WebCoreSupport/wpe/WebContextMenuClientWPE.cpp WebProcess/WebCoreSupport/wpe/WebEditorClientWPE.cpp diff --git a/Source/WebKit2/WebProcess/MediaStream/wpe/UserMediaPermissionRequestManagerWPE.cpp b/Source/WebKit2/WebProcess/MediaStream/wpe/UserMediaPermissionRequestManagerWPE.cpp new file mode 100644 index 0000000000000..3130489457cc4 --- /dev/null +++ b/Source/WebKit2/WebProcess/MediaStream/wpe/UserMediaPermissionRequestManagerWPE.cpp @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2014 Igalia S.L. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "config.h" +#include "UserMediaPermissionRequestManager.h" + +#if ENABLE(MEDIA_STREAM) + +#include "WebCoreArgumentCoders.h" +#include "WebFrame.h" +#include "WebPage.h" +#include "WebPageProxyMessages.h" +#include +#include +#include +#include + +#include +#include "NotImplemented.h" + +using namespace WebCore; + +namespace WebKit { + +static uint64_t generateRequestID() +{ + static uint64_t uniqueRequestID = 1; + return uniqueRequestID++; +} + +UserMediaPermissionRequestManager::UserMediaPermissionRequestManager(WebPage& page) + : m_page(page) +{ +} + +void UserMediaPermissionRequestManager::startRequest(UserMediaRequest& request) +{ + /* + * FIX_ME: + * The user permission request dialog is not supported by WPE, so + * there for check some environment variables to contol the grant + * process. + */ + String deviceUIDAudio = emptyString(); + String deviceUIDVideo = emptyString(); + + if (g_getenv("WPE_WEBRTC_GRANT_PERMISSION")){ + /* + * FIX_ME: Temporary solution. + */ + char* deviceUID = getenv("WEBKIT_AUDIO_SOURCE_NAME"); + if (deviceUID) { + deviceUIDAudio = String(deviceUID); + } + + deviceUID = getenv("WEBKIT_VIDEO_SOURCE_NAME"); + if (deviceUID) { + deviceUIDVideo = String(deviceUID); + } + + request.userMediaAccessGranted(deviceUIDVideo, deviceUIDAudio); + } + else { + request.userMediaAccessDenied(); + } +} + +void UserMediaPermissionRequestManager::cancelRequest(UserMediaRequest& request) +{ + uint64_t requestID = m_requestToIDMap.take(&request); + if (!requestID) + return; + m_idToRequestMap.remove(requestID); +} + +void UserMediaPermissionRequestManager::didReceiveUserMediaPermissionDecision(uint64_t userMediaID, bool allowed, const String& deviceUIDVideo, const String& deviceUIDAudio) +{ + notImplemented(); +} + +} // namespace WebKit + +#endif // ENABLE(MEDIA_STREAM) diff --git a/Source/cmake/FindOpenWebRTC.cmake b/Source/cmake/FindOpenWebRTC.cmake index 2fface0b660a5..f5a3a216bc17e 100644 --- a/Source/cmake/FindOpenWebRTC.cmake +++ b/Source/cmake/FindOpenWebRTC.cmake @@ -30,20 +30,37 @@ # ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. find_package(PkgConfig) -pkg_check_modules(OPENWEBRTC openwebrtc-0.1 openwebrtc-gst-0.1) +pkg_check_modules(OPENWEBRTC openwebrtc-0.3 openwebrtc-gst-0.3) -set(VERSION_OK TRUE) -if (OPENWEBRTC_VERSION) - if (OPENWEBRTC_FIND_VERSION_EXACT) - if (NOT("${OPENWEBRTC_FIND_VERSION}" VERSION_EQUAL "${OPENWEBRTC_VERSION}")) - set(VERSION_OK FALSE) - endif () - else () - if ("${OPENWEBRTC_VERSION}" VERSION_LESS "${OPENWEBRTC_FIND_VERSION}") - set(VERSION_OK FALSE) +if ("${OPENWEBRTC_FOUND}") + find_path( + OWR_INCLUDE_DIR + NAMES owr.h + HINTS ${OPENWEBRTC_INCLUDE_DIRS} + PATH_SUFFIXES owr + ) + list(APPEND OPENWEBRTC_INCLUDE_DIRS "${OWR_INCLUDE_DIR}" ) + + find_path( + OWR_GST_INCLUDE_DIR + NAMES gst.h + HINTS ${OPENWEBRTC_INCLUDE_DIRS} + PATH_SUFFIXES gst + ) + list(APPEND OPENWEBRTC_INCLUDE_DIRS "${OWR_GST_INCLUDE_DIR}" ) + set(VERSION_OK TRUE) + if (OPENWEBRTC_VERSION) + if (OPENWEBRTC_FIND_VERSION_EXACT) + if (NOT("${PC_OPENWEBRTC_FIND_VERSION}" VERSION_EQUAL "${OPENWEBRTC_VERSION}")) + set(VERSION_OK FALSE) + endif () + else () + if ("${OPENWEBRTC_VERSION}" VERSION_LESS "${OPENWEBRTC_FIND_VERSION}") + set(VERSION_OK FALSE) + endif () endif () endif () endif () include(FindPackageHandleStandardArgs) -FIND_PACKAGE_HANDLE_STANDARD_ARGS(OPENWEBRTC DEFAULT_MSG OPENWEBRTC_INCLUDE_DIRS OPENWEBRTC_LIBRARIES VERSION_OK) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(OPENWEBRTC DEFAULT_MSG OPENWEBRTC_FOUND OPENWEBRTC_LIBRARIES OPENWEBRTC_INCLUDE_DIRS VERSION_OK) diff --git a/Source/cmake/OptionsWPE.cmake b/Source/cmake/OptionsWPE.cmake index 776a434e9aab0..91cd8dc6c8a3d 100644 --- a/Source/cmake/OptionsWPE.cmake +++ b/Source/cmake/OptionsWPE.cmake @@ -62,7 +62,6 @@ find_package(ICU REQUIRED) find_package(Threads REQUIRED) find_package(ZLIB REQUIRED) find_package(GLIB 2.40.0 REQUIRED COMPONENTS gio gobject gthread gmodule) - find_package(Cairo 1.10.2 REQUIRED) find_package(CairoGL 1.10.2 REQUIRED COMPONENTS cairo-egl) find_package(Fontconfig 2.8.0 REQUIRED) @@ -76,12 +75,11 @@ find_package(PNG REQUIRED) find_package(Sqlite REQUIRED) find_package(Wayland 1.6.0 REQUIRED) find_package(WebP REQUIRED) - find_package(OpenGLES2 REQUIRED) find_package(EGL REQUIRED) find_package(WaylandEGL REQUIRED) - find_package(Athol 0.1) + if (ATHOL_FOUND) set(ENABLE_ATHOL_SHELL ON) else () @@ -91,6 +89,14 @@ else () endif () endif () +if (ENABLE_MEDIA_STREAM) + find_package(OpenWebRTC REQUIRED) + if (NOT OPENWEBRTC_FOUND) + message(FATAL_ERROR "OpenWebRTC is needed for ENABLE_MEDIA_STREAM") + endif () + add_definitions(-DUSE_OPENWEBRTC) +endif () + if (ENABLE_SUBTLE_CRYPTO) find_package(GnuTLS 3.0.0) if (NOT GNUTLS_FOUND) diff --git a/Tools/gtk/jhbuild.modules b/Tools/gtk/jhbuild.modules index 5bf05dd82c358..ed67ef8e74483 100644 --- a/Tools/gtk/jhbuild.modules +++ b/Tools/gtk/jhbuild.modules @@ -24,6 +24,8 @@ + + @@ -62,6 +64,8 @@ href="http://download.savannah.gnu.org/releases/"/> + + + + + + + + + + + + + + + + - + + - - - + + - - + - + + + - - - + + - + + @@ -378,14 +391,19 @@ - + - + + + + + @@ -393,7 +411,7 @@ - +