diff options
author | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
---|---|---|
committer | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
commit | 1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c (patch) | |
tree | 46dcd36c86e7fbc6e5df36deb463b33e9967a6f7 /Source/WebCore/platform/mediastream/openwebrtc | |
parent | 32761a6cee1d0dee366b885b7b9c777e67885688 (diff) | |
download | WebKitGtk-tarball-master.tar.gz |
webkitgtk-2.16.5HEADwebkitgtk-2.16.5master
Diffstat (limited to 'Source/WebCore/platform/mediastream/openwebrtc')
10 files changed, 1575 insertions, 0 deletions
diff --git a/Source/WebCore/platform/mediastream/openwebrtc/MediaEndpointOwr.cpp b/Source/WebCore/platform/mediastream/openwebrtc/MediaEndpointOwr.cpp new file mode 100644 index 000000000..44839d13a --- /dev/null +++ b/Source/WebCore/platform/mediastream/openwebrtc/MediaEndpointOwr.cpp @@ -0,0 +1,750 @@ +/* + * Copyright (C) 2015, 2016 Ericsson AB. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * 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(WEB_RTC) +#include "MediaEndpointOwr.h" + +#include "MediaEndpointSessionConfiguration.h" +#include "MediaPayload.h" +#include "NotImplemented.h" +#include "OpenWebRTCUtilities.h" +#include "PeerConnectionStates.h" +#include "RTCDataChannelHandler.h" +#include "RealtimeAudioSourceOwr.h" +#include "RealtimeVideoSourceOwr.h" +#include <owr/owr.h> +#include <owr/owr_audio_payload.h> +#include <owr/owr_crypto_utils.h> +#include <owr/owr_media_session.h> +#include <owr/owr_transport_agent.h> +#include <owr/owr_video_payload.h> +#include <wtf/text/CString.h> + +namespace WebCore { + +static void gotCandidate(OwrSession*, OwrCandidate*, MediaEndpointOwr*); +static void candidateGatheringDone(OwrSession*, MediaEndpointOwr*); +static void iceConnectionStateChange(OwrSession*, GParamSpec*, MediaEndpointOwr*); +static void gotIncomingSource(OwrMediaSession*, OwrMediaSource*, MediaEndpointOwr*); + +static const Vector<String> candidateTypes = { "host", "srflx", "prflx", "relay" }; +static const Vector<String> candidateTcpTypes = { "", "active", "passive", "so" }; +static const Vector<String> codecTypes = { "NONE", "PCMU", "PCMA", "OPUS", "H264", "VP8" }; + +static const char* helperServerRegEx = "(turns|turn|stun):([\\w\\.\\-]+|\\[[\\w\\:]+\\])(:\\d+)?(\\?.+)?"; + +static const unsigned short helperServerDefaultPort = 3478; +static const unsigned short candidateDefaultPort = 9; + +static std::unique_ptr<MediaEndpoint> createMediaEndpointOwr(MediaEndpointClient& client) +{ + return std::unique_ptr<MediaEndpoint>(new MediaEndpointOwr(client)); +} + +CreateMediaEndpoint MediaEndpoint::create = createMediaEndpointOwr; + +MediaEndpointOwr::MediaEndpointOwr(MediaEndpointClient& client) + : m_transportAgent(nullptr) + , m_client(client) + , m_numberOfReceivePreparedSessions(0) + , m_numberOfSendPreparedSessions(0) +{ + initializeOpenWebRTC(); + + GRegexCompileFlags compileFlags = G_REGEX_JAVASCRIPT_COMPAT; + GRegexMatchFlags matchFlags = static_cast<GRegexMatchFlags>(0); + m_helperServerRegEx = g_regex_new(helperServerRegEx, compileFlags, matchFlags, nullptr); +} + +MediaEndpointOwr::~MediaEndpointOwr() +{ + stop(); + + g_regex_unref(m_helperServerRegEx); +} + +void MediaEndpointOwr::setConfiguration(MediaEndpointConfiguration&& configuration) +{ + m_configuration = WTFMove(configuration); +} + +std::unique_ptr<RTCDataChannelHandler> MediaEndpointOwr::createDataChannelHandler(const String&, const RTCDataChannelInit&) +{ + // FIXME: Implement data channel. + ASSERT_NOT_REACHED(); + return nullptr; +} + +static void cryptoDataCallback(gchar* privateKey, gchar* certificate, gchar* fingerprint, gchar* fingerprintFunction, gpointer data) +{ + MediaEndpointOwr* mediaEndpoint = (MediaEndpointOwr*) data; + mediaEndpoint->dispatchDtlsFingerprint(g_strdup(privateKey), g_strdup(certificate), String(fingerprint), String(fingerprintFunction)); +} + +void MediaEndpointOwr::generateDtlsInfo() +{ + owr_crypto_create_crypto_data(cryptoDataCallback, this); +} + +MediaPayloadVector MediaEndpointOwr::getDefaultAudioPayloads() +{ + MediaPayloadVector payloads; + + // FIXME: This list should be based on what is available in the platform (bug: http://webkit.org/b/163723) + MediaPayload payload1; + payload1.type = 111; + payload1.encodingName = "OPUS"; + payload1.clockRate = 48000; + payload1.channels = 2; + payloads.append(WTFMove(payload1)); + + MediaPayload payload2; + payload2.type = 8; + payload2.encodingName = "PCMA"; + payload2.clockRate = 8000; + payload2.channels = 1; + payloads.append(WTFMove(payload2)); + + MediaPayload payload3; + payload3.type = 0; + payload3.encodingName = "PCMU"; + payload3.clockRate = 8000; + payload3.channels = 1; + payloads.append(WTFMove(payload3)); + + return payloads; +} + +MediaPayloadVector MediaEndpointOwr::getDefaultVideoPayloads() +{ + MediaPayloadVector payloads; + + // FIXME: This list should be based on what is available in the platform (bug: http://webkit.org/b/163723) + MediaPayload payload1; + payload1.type = 103; + payload1.encodingName = "H264"; + payload1.clockRate = 90000; + payload1.ccmfir = true; + payload1.nackpli = true; + payload1.addParameter("packetizationMode", 1); + payloads.append(WTFMove(payload1)); + + MediaPayload payload2; + payload2.type = 100; + payload2.encodingName = "VP8"; + payload2.clockRate = 90000; + payload2.ccmfir = true; + payload2.nackpli = true; + payload2.nack = true; + payloads.append(WTFMove(payload2)); + + MediaPayload payload3; + payload3.type = 120; + payload3.encodingName = "RTX"; + payload3.clockRate = 90000; + payload3.addParameter("apt", 100); + payload3.addParameter("rtxTime", 200); + payloads.append(WTFMove(payload3)); + + return payloads; +} + +static bool payloadsContainType(const Vector<const MediaPayload*>& payloads, unsigned payloadType) +{ + for (auto payload : payloads) { + ASSERT(payload); + if (payload->type == payloadType) + return true; + } + return false; +} + +MediaPayloadVector MediaEndpointOwr::filterPayloads(const MediaPayloadVector& remotePayloads, const MediaPayloadVector& defaultPayloads) +{ + Vector<const MediaPayload*> filteredPayloads; + + for (auto& remotePayload : remotePayloads) { + const MediaPayload* defaultPayload = nullptr; + for (auto& p : defaultPayloads) { + if (p.encodingName == remotePayload.encodingName.convertToASCIIUppercase()) { + defaultPayload = &p; + 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); + } + + MediaPayloadVector filteredAptPayloads; + + for (auto filteredPayload : filteredPayloads) { + if (filteredPayload->parameters.contains("apt") && (!payloadsContainType(filteredPayloads, filteredPayload->parameters.get("apt")))) + continue; + filteredAptPayloads.append(*filteredPayload); + } + + return filteredAptPayloads; +} + +MediaEndpoint::UpdateResult MediaEndpointOwr::updateReceiveConfiguration(MediaEndpointSessionConfiguration* configuration, bool isInitiator) +{ + Vector<TransceiverConfig> transceiverConfigs; + for (unsigned i = m_transceivers.size(); i < configuration->mediaDescriptions().size(); ++i) { + TransceiverConfig config; + config.type = SessionTypeMedia; + config.isDtlsClient = configuration->mediaDescriptions()[i].dtlsSetup == "active"; + config.mid = configuration->mediaDescriptions()[i].mid; + transceiverConfigs.append(WTFMove(config)); + } + + ensureTransportAgentAndTransceivers(isInitiator, transceiverConfigs); + + // Prepare the new sessions. + for (unsigned i = m_numberOfReceivePreparedSessions; i < m_transceivers.size(); ++i) { + OwrSession* session = m_transceivers[i]->session(); + prepareMediaSession(OWR_MEDIA_SESSION(session), &configuration->mediaDescriptions()[i], isInitiator); + owr_transport_agent_add_session(m_transportAgent, session); + } + + owr_transport_agent_start(m_transportAgent); + m_numberOfReceivePreparedSessions = m_transceivers.size(); + + return UpdateResult::Success; +} + +static const MediaPayload* findRtxPayload(const MediaPayloadVector& payloads, unsigned apt) +{ + for (auto& payload : payloads) { + if (payload.encodingName.convertToASCIIUppercase() == "RTX" && payload.parameters.contains("apt") + && (payload.parameters.get("apt") == apt)) + return &payload; + } + return nullptr; +} + +MediaEndpoint::UpdateResult MediaEndpointOwr::updateSendConfiguration(MediaEndpointSessionConfiguration* configuration, const RealtimeMediaSourceMap& sendSourceMap, bool isInitiator) +{ + Vector<TransceiverConfig> transceiverConfigs; + for (unsigned i = m_transceivers.size(); i < configuration->mediaDescriptions().size(); ++i) { + TransceiverConfig config; + config.type = SessionTypeMedia; + config.isDtlsClient = configuration->mediaDescriptions()[i].dtlsSetup != "active"; + config.mid = configuration->mediaDescriptions()[i].mid; + transceiverConfigs.append(WTFMove(config)); + } + + ensureTransportAgentAndTransceivers(isInitiator, transceiverConfigs); + + for (unsigned i = 0; i < m_transceivers.size(); ++i) { + auto* session = m_transceivers[i]->session(); + auto& 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 (!sendSourceMap.contains(mdesc.mid)) + continue; + + const MediaPayload* payload = nullptr; + for (auto& p : mdesc.payloads) { + if (p.encodingName.convertToASCIIUppercase() != "RTX") { + payload = &p; + break; + } + } + + if (!payload) + return UpdateResult::Failed; + + auto* rtxPayload = findRtxPayload(mdesc.payloads, payload->type); + auto* source = static_cast<RealtimeMediaSourceOwr*>(sendSourceMap.get(mdesc.mid)); + + ASSERT(codecTypes.find(payload->encodingName.convertToASCIIUppercase()) != notFound); + auto codecType = static_cast<OwrCodecType>(codecTypes.find(payload->encodingName.convertToASCIIUppercase())); + + 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()); + + // FIXME: Support for group-ssrc SDP line is missing. + const Vector<unsigned> receiveSsrcs = mdesc.ssrcs; + if (receiveSsrcs.size()) { + g_object_set(session, "receive-ssrc", receiveSsrcs[0], nullptr); + if (receiveSsrcs.size() == 2) + g_object_set(session, "receive-rtx-ssrc", receiveSsrcs[1], nullptr); + } + + m_numberOfSendPreparedSessions = i + 1; + } + + return UpdateResult::Success; +} + +void MediaEndpointOwr::addRemoteCandidate(const IceCandidate& candidate, const String& mid, const String& ufrag, const String& password) +{ + for (auto& transceiver : m_transceivers) { + if (transceiver->mid() == mid) { + internalAddRemoteCandidate(transceiver->session(), candidate, ufrag, password); + break; + } + } +} + +void MediaEndpointOwr::replaceMutedRemoteSourceMid(const String& oldMid, const String& newMid) +{ + RefPtr<RealtimeMediaSourceOwr> remoteSource = m_mutedRemoteSources.take(oldMid); + m_mutedRemoteSources.set(newMid, remoteSource); +} + +Ref<RealtimeMediaSource> MediaEndpointOwr::createMutedRemoteSource(const String& mid, RealtimeMediaSource::Type type) +{ + String name; + String id("not used"); + RefPtr<RealtimeMediaSourceOwr> source; + + switch (type) { + case RealtimeMediaSource::Audio: + name = "remote audio"; + source = adoptRef(new RealtimeAudioSourceOwr(nullptr, id, type, name)); + break; + case RealtimeMediaSource::Video: + name = "remote video"; + source = adoptRef(new RealtimeVideoSourceOwr(nullptr, id, type, name)); + break; + case RealtimeMediaSource::None: + ASSERT_NOT_REACHED(); + } + + m_mutedRemoteSources.set(mid, source); + + return *source; +} + +void MediaEndpointOwr::replaceSendSource(RealtimeMediaSource& newSource, const String& mid) +{ + UNUSED_PARAM(newSource); + UNUSED_PARAM(mid); + + // FIXME: We want to use owr_media_session_set_send_source here, but it doesn't work as intended. + // Issue tracked by OpenWebRTC bug: https://github.com/EricssonResearch/openwebrtc/issues/533 + + notImplemented(); +} + +void MediaEndpointOwr::stop() +{ + if (!m_transportAgent) + return; + + for (auto& transceiver : m_transceivers) + owr_media_session_set_send_source(OWR_MEDIA_SESSION(transceiver->session()), nullptr); + + g_object_unref(m_transportAgent); + m_transportAgent = nullptr; +} + +size_t MediaEndpointOwr::transceiverIndexForSession(OwrSession* session) const +{ + for (unsigned i = 0; i < m_transceivers.size(); ++i) { + if (m_transceivers[i]->session() == session) + return i; + } + + ASSERT_NOT_REACHED(); + return notFound; +} + +const String& MediaEndpointOwr::sessionMid(OwrSession* session) const +{ + size_t index = transceiverIndexForSession(session); + return m_transceivers[index]->mid(); +} + +OwrTransceiver* MediaEndpointOwr::matchTransceiverByMid(const String& mid) const +{ + for (auto& transceiver : m_transceivers) { + if (transceiver->mid() == mid) + return transceiver.get(); + } + return nullptr; +} + +void MediaEndpointOwr::dispatchNewIceCandidate(const String& mid, IceCandidate&& iceCandidate) +{ + m_client.gotIceCandidate(mid, WTFMove(iceCandidate)); +} + +void MediaEndpointOwr::dispatchGatheringDone(const String& mid) +{ + m_client.doneGatheringCandidates(mid); +} + +void MediaEndpointOwr::processIceTransportStateChange(OwrSession* session) +{ + OwrIceState owrIceState; + g_object_get(session, "ice-connection-state", &owrIceState, nullptr); + + OwrTransceiver& transceiver = *m_transceivers[transceiverIndexForSession(session)]; + if (owrIceState < transceiver.owrIceState()) + return; + + transceiver.setOwrIceState(owrIceState); + + // We cannot go to Completed if there may be more remote candidates. + if (owrIceState == OWR_ICE_STATE_READY && !transceiver.gotEndOfRemoteCandidates()) + return; + + MediaEndpoint::IceTransportState transportState; + switch (owrIceState) { + case OWR_ICE_STATE_CONNECTING: + transportState = MediaEndpoint::IceTransportState::Checking; + break; + case OWR_ICE_STATE_CONNECTED: + transportState = MediaEndpoint::IceTransportState::Connected; + break; + case OWR_ICE_STATE_READY: + transportState = MediaEndpoint::IceTransportState::Completed; + break; + case OWR_ICE_STATE_FAILED: + transportState = MediaEndpoint::IceTransportState::Failed; + break; + default: + return; + } + + m_client.iceTransportStateChanged(transceiver.mid(), transportState); +} + +void MediaEndpointOwr::dispatchDtlsFingerprint(gchar* privateKey, gchar* certificate, const String& fingerprint, const String& fingerprintFunction) +{ + m_dtlsPrivateKey = String(privateKey); + m_dtlsCertificate = String(certificate); + + g_free(privateKey); + g_free(certificate); + + m_client.gotDtlsFingerprint(fingerprint, fingerprintFunction); +} + +void MediaEndpointOwr::unmuteRemoteSource(const String& mid, OwrMediaSource* realSource) +{ + RefPtr<RealtimeMediaSourceOwr> remoteSource = m_mutedRemoteSources.take(mid); + if (!remoteSource) { + LOG_ERROR("Unable to find muted remote source."); + return; + } + + if (!remoteSource->stopped()) + remoteSource->swapOutShallowSource(*realSource); +} + +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::ice-connection-state", G_CALLBACK(iceConnectionStateChange), this); +} + +void MediaEndpointOwr::prepareMediaSession(OwrMediaSession* mediaSession, PeerMediaDescription* mediaDescription, bool isInitiator) +{ + prepareSession(OWR_SESSION(mediaSession), mediaDescription); + + bool useRtcpMux = !isInitiator && mediaDescription->rtcpMux; + g_object_set(mediaSession, "rtcp-mux", useRtcpMux, nullptr); + + if (!mediaDescription->cname.isEmpty() && mediaDescription->ssrcs.size()) { + g_object_set(mediaSession, "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.convertToASCIIUppercase() == "RTX") + continue; + + auto* rtxPayload = findRtxPayload(mediaDescription->payloads, payload.type); + + ASSERT(codecTypes.find(payload.encodingName) != notFound); + OwrCodecType codecType = static_cast<OwrCodecType>(codecTypes.find(payload.encodingName.convertToASCIIUppercase())); + + 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); + } +} + +struct HelperServerUrl { + String protocol; + String host; + unsigned short port; + String query; +}; + +static void parseHelperServerUrl(GRegex& regex, const URL& url, HelperServerUrl& outUrl) +{ + GMatchInfo* matchInfo; + + if (g_regex_match(®ex, url.string().ascii().data(), static_cast<GRegexMatchFlags>(0), &matchInfo)) { + gchar** matches = g_match_info_fetch_all(matchInfo); + gint matchCount = g_strv_length(matches); + + outUrl.protocol = matches[1]; + outUrl.host = matches[2][0] == '[' ? String(matches[2] + 1, strlen(matches[2]) - 2) // IPv6 + : matches[2]; + + outUrl.port = 0; + if (matchCount >= 4) { + String portString = String(matches[3] + 1); // Skip port colon + outUrl.port = portString.toUIntStrict(); + } + + if (matchCount == 5) + outUrl.query = String(matches[4] + 1); // Skip question mark + + g_strfreev(matches); + } + + g_match_info_free(matchInfo); +} + +void MediaEndpointOwr::ensureTransportAgentAndTransceivers(bool isInitiator, const Vector<TransceiverConfig>& transceiverConfigs) +{ + ASSERT(m_dtlsPrivateKey); + ASSERT(m_dtlsCertificate); + + if (!m_transportAgent) { + // FIXME: Handle SDP BUNDLE line from the remote source instead of falling back to balanced. + OwrBundlePolicyType bundlePolicy = OWR_BUNDLE_POLICY_TYPE_BALANCED; + + switch (m_configuration->bundlePolicy) { + case PeerConnectionStates::BundlePolicy::Balanced: + bundlePolicy = OWR_BUNDLE_POLICY_TYPE_BALANCED; + break; + case PeerConnectionStates::BundlePolicy::MaxCompat: + bundlePolicy = OWR_BUNDLE_POLICY_TYPE_MAX_COMPAT; + break; + case PeerConnectionStates::BundlePolicy::MaxBundle: + bundlePolicy = OWR_BUNDLE_POLICY_TYPE_MAX_BUNDLE; + break; + default: + ASSERT_NOT_REACHED(); + }; + + m_transportAgent = owr_transport_agent_new(false, bundlePolicy); + + ASSERT(m_configuration); + for (auto& server : m_configuration->iceServers) { + for (auto& webkitUrl : server.urls) { + HelperServerUrl url; + // WebKit's URL class can't handle ICE helper server urls properly + parseHelperServerUrl(*m_helperServerRegEx, webkitUrl, url); + + unsigned short port = url.port ? url.port : helperServerDefaultPort; + + if (url.protocol == "stun") { + owr_transport_agent_add_helper_server(m_transportAgent, OWR_HELPER_SERVER_TYPE_STUN, + url.host.ascii().data(), port, nullptr, nullptr); + + } else if (url.protocol == "turn") { + OwrHelperServerType serverType = url.query == "transport=tcp" ? OWR_HELPER_SERVER_TYPE_TURN_TCP + : OWR_HELPER_SERVER_TYPE_TURN_UDP; + + owr_transport_agent_add_helper_server(m_transportAgent, serverType, + url.host.ascii().data(), port, + server.username.ascii().data(), server.credential.ascii().data()); + } else if (url.protocol == "turns") { + owr_transport_agent_add_helper_server(m_transportAgent, OWR_HELPER_SERVER_TYPE_TURN_TLS, + url.host.ascii().data(), port, + server.username.ascii().data(), server.credential.ascii().data()); + } else + ASSERT_NOT_REACHED(); + } + } + } + + g_object_set(m_transportAgent, "ice-controlling-mode", isInitiator, nullptr); + + for (auto& config : transceiverConfigs) { + OwrSession* session = OWR_SESSION(owr_media_session_new(config.isDtlsClient)); + g_object_set(session, "dtls-certificate", m_dtlsCertificate.utf8().data(), + "dtls-key", m_dtlsPrivateKey.utf8().data(), + nullptr); + + m_transceivers.append(OwrTransceiver::create(config.mid, session)); + } +} + +void MediaEndpointOwr::internalAddRemoteCandidate(OwrSession* session, const 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); + + OwrCandidateType candidateType = static_cast<OwrCandidateType>(candidateTypes.find(candidate.type)); + OwrComponentType componentId = static_cast<OwrComponentType>(candidate.componentId); + OwrTransportType transportType; + + if (candidate.transport.convertToASCIIUppercase() == "UDP") + transportType = OWR_TRANSPORT_TYPE_UDP; + else { + ASSERT(candidateTcpTypes.find(candidate.tcpType) != notFound); + transportType = static_cast<OwrTransportType>(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()); + + IceCandidate iceCandidate; + iceCandidate.type = candidateTypes[candidateType]; + iceCandidate.foundation = foundation; + iceCandidate.componentId = componentId; + iceCandidate.priority = priority; + iceCandidate.address = address; + iceCandidate.port = port ? port : candidateDefaultPort; + + if (transportType == OWR_TRANSPORT_TYPE_UDP) + iceCandidate.transport = "UDP"; + else { + iceCandidate.transport = "TCP"; + iceCandidate.tcpType = candidateTcpTypes[transportType]; + } + + if (candidateType != OWR_CANDIDATE_TYPE_HOST) { + iceCandidate.relatedAddress = relatedAddress; + iceCandidate.relatedPort = relatedPort ? relatedPort : candidateDefaultPort; + } + + 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->sessionMid(session), WTFMove(iceCandidate)); + + g_free(foundation); + g_free(address); + g_free(relatedAddress); +} + +static void candidateGatheringDone(OwrSession* session, MediaEndpointOwr* mediaEndpoint) +{ + mediaEndpoint->dispatchGatheringDone(mediaEndpoint->sessionMid(session)); +} + +static void iceConnectionStateChange(OwrSession* session, GParamSpec*, MediaEndpointOwr* mediaEndpoint) +{ + mediaEndpoint->processIceTransportStateChange(session); +} + +static void gotIncomingSource(OwrMediaSession* mediaSession, OwrMediaSource* source, MediaEndpointOwr* mediaEndpoint) +{ + mediaEndpoint->unmuteRemoteSource(mediaEndpoint->sessionMid(OWR_SESSION(mediaSession)), source); +} + +} // namespace WebCore + +#endif // ENABLE(WEB_RTC) diff --git a/Source/WebCore/platform/mediastream/openwebrtc/MediaEndpointOwr.h b/Source/WebCore/platform/mediastream/openwebrtc/MediaEndpointOwr.h new file mode 100644 index 000000000..f31048c9e --- /dev/null +++ b/Source/WebCore/platform/mediastream/openwebrtc/MediaEndpointOwr.h @@ -0,0 +1,149 @@ +/* + * Copyright (C) 2015, 2016 Ericsson AB. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * 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. + */ + +#pragma once + +#if ENABLE(WEB_RTC) + +#include "MediaEndpoint.h" +#include <owr/owr_session.h> +#include <wtf/RefCounted.h> +#include <wtf/RefPtr.h> + +typedef struct _OwrMediaSession OwrMediaSession; +typedef struct _OwrMediaSource OwrMediaSource; +typedef struct _OwrTransportAgent OwrTransportAgent; + +namespace WebCore { + +class RealtimeMediaSourceOwr; +class RTCConfigurationPrivate; + +struct PeerMediaDescription; + +class OwrTransceiver : public RefCounted<OwrTransceiver> { +public: + static Ref<OwrTransceiver> create(const String& mid, OwrSession* session) + { + return adoptRef(*new OwrTransceiver(mid, session)); + } + virtual ~OwrTransceiver() { } + + const String& mid() const { return m_mid; } + OwrSession* session() const { return m_session; } + + OwrIceState owrIceState() const { return m_owrIceState; } + void setOwrIceState(OwrIceState state) { m_owrIceState = state; } + + bool gotEndOfRemoteCandidates() const { return m_gotEndOfRemoteCandidates; } + void markGotEndOfRemoteCandidates() { m_gotEndOfRemoteCandidates = true; } + +private: + OwrTransceiver(const String& mid, OwrSession* session) + : m_mid(mid) + , m_session(session) + { } + + String m_mid; + OwrSession* m_session; + + OwrIceState m_owrIceState { OWR_ICE_STATE_DISCONNECTED }; + bool m_gotEndOfRemoteCandidates { false }; +}; + +class MediaEndpointOwr : public MediaEndpoint { +public: + MediaEndpointOwr(MediaEndpointClient&); + ~MediaEndpointOwr(); + + void setConfiguration(MediaEndpointConfiguration&&) override; + + void generateDtlsInfo() override; + MediaPayloadVector getDefaultAudioPayloads() override; + MediaPayloadVector getDefaultVideoPayloads() override; + MediaPayloadVector filterPayloads(const MediaPayloadVector& remotePayloads, const MediaPayloadVector& defaultPayloads) override; + + UpdateResult updateReceiveConfiguration(MediaEndpointSessionConfiguration*, bool isInitiator) override; + UpdateResult updateSendConfiguration(MediaEndpointSessionConfiguration*, const RealtimeMediaSourceMap&, bool isInitiator) override; + + void addRemoteCandidate(const IceCandidate&, const String& mid, const String& ufrag, const String& password) override; + + Ref<RealtimeMediaSource> createMutedRemoteSource(const String& mid, RealtimeMediaSource::Type) override; + void replaceMutedRemoteSourceMid(const String&, const String&) final; + void replaceSendSource(RealtimeMediaSource&, const String& mid) override; + + void stop() override; + + size_t transceiverIndexForSession(OwrSession*) const; + const String& sessionMid(OwrSession*) const; + OwrTransceiver* matchTransceiverByMid(const String& mid) const; + + void dispatchNewIceCandidate(const String& mid, IceCandidate&&); + void dispatchGatheringDone(const String& mid); + void processIceTransportStateChange(OwrSession*); + void dispatchDtlsFingerprint(gchar* privateKey, gchar* certificate, const String& fingerprint, const String& fingerprintFunction); + void unmuteRemoteSource(const String& mid, OwrMediaSource*); + +private: + enum SessionType { SessionTypeMedia }; + + struct TransceiverConfig { + SessionType type; + bool isDtlsClient; + String mid; + }; + + std::unique_ptr<RTCDataChannelHandler> createDataChannelHandler(const String&, const RTCDataChannelInit&) final; + + void prepareSession(OwrSession*, PeerMediaDescription*); + void prepareMediaSession(OwrMediaSession*, PeerMediaDescription*, bool isInitiator); + + void ensureTransportAgentAndTransceivers(bool isInitiator, const Vector<TransceiverConfig>&); + void internalAddRemoteCandidate(OwrSession*, const IceCandidate&, const String& ufrag, const String& password); + + std::optional<MediaEndpointConfiguration> m_configuration; + GRegex* m_helperServerRegEx; + + OwrTransportAgent* m_transportAgent; + Vector<RefPtr<OwrTransceiver>> m_transceivers; + HashMap<String, RefPtr<RealtimeMediaSourceOwr>> m_mutedRemoteSources; + + MediaEndpointClient& m_client; + + unsigned m_numberOfReceivePreparedSessions; + unsigned m_numberOfSendPreparedSessions; + + String m_dtlsPrivateKey; + String m_dtlsCertificate; +}; + +} // namespace WebCore + +#endif // ENABLE(WEB_RTC) diff --git a/Source/WebCore/platform/mediastream/openwebrtc/OpenWebRTCUtilities.cpp b/Source/WebCore/platform/mediastream/openwebrtc/OpenWebRTCUtilities.cpp new file mode 100644 index 000000000..e4cfb59df --- /dev/null +++ b/Source/WebCore/platform/mediastream/openwebrtc/OpenWebRTCUtilities.cpp @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2015 Igalia S.L + * Copyright (C) 2015 Metrological + * + * 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 the copyright holder 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 + * HOLDER 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 USE(OPENWEBRTC) +#include "OpenWebRTCUtilities.h" + +#include <owr/owr.h> + +namespace WebCore { + +void initializeOpenWebRTC() +{ + static bool isInitialized = false; + if (isInitialized) + return; + + owr_init(g_main_context_default()); + isInitialized = true; +} + +} + +#endif // USE(OPENWEBRTC) diff --git a/Source/WebCore/platform/mediastream/openwebrtc/OpenWebRTCUtilities.h b/Source/WebCore/platform/mediastream/openwebrtc/OpenWebRTCUtilities.h new file mode 100644 index 000000000..bed474bbf --- /dev/null +++ b/Source/WebCore/platform/mediastream/openwebrtc/OpenWebRTCUtilities.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2015 Igalia S.L + * Copyright (C) 2015 Metrological + * + * 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 the copyright holder 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 + * HOLDER 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. + */ + + +namespace WebCore { + +void initializeOpenWebRTC(); + +} diff --git a/Source/WebCore/platform/mediastream/openwebrtc/RealtimeAudioSourceOwr.h b/Source/WebCore/platform/mediastream/openwebrtc/RealtimeAudioSourceOwr.h new file mode 100644 index 000000000..2349f051b --- /dev/null +++ b/Source/WebCore/platform/mediastream/openwebrtc/RealtimeAudioSourceOwr.h @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2015,2016 Igalia S.L + * Copyright (C) 2015 Metrological + * + * 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 the copyright holder 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 + * HOLDER 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. + */ + +#pragma once + +#if ENABLE(MEDIA_STREAM) && USE(OPENWEBRTC) + +#include "RealtimeMediaSourceOwr.h" + +namespace WebCore { + +class RealtimeAudioSourceOwr : public RealtimeMediaSourceOwr { +public: +RealtimeAudioSourceOwr(OwrMediaSource* mediaSource, const String& id, RealtimeMediaSource::Type type, const String& name) + : RealtimeMediaSourceOwr(mediaSource, id, type, name) + { + } + +RealtimeAudioSourceOwr(const String& id, RealtimeMediaSource::Type type, const String& name) + : RealtimeMediaSourceOwr(id, type, name) + { + } + + virtual ~RealtimeAudioSourceOwr() { } + + bool applySize(const IntSize&) final { return false; } + +protected: + void initializeSettings() final { + if (m_currentSettings.deviceId().isEmpty()) + m_currentSettings.setSupportedConstraits(supportedConstraints()); + + m_currentSettings.setDeviceId(id()); + } +}; + +} // namespace WebCore + +#endif // ENABLE(MEDIA_STREAM) && USE(OPENWEBRTC) diff --git a/Source/WebCore/platform/mediastream/openwebrtc/RealtimeMediaSourceCenterOwr.cpp b/Source/WebCore/platform/mediastream/openwebrtc/RealtimeMediaSourceCenterOwr.cpp new file mode 100644 index 000000000..f3e6f1fed --- /dev/null +++ b/Source/WebCore/platform/mediastream/openwebrtc/RealtimeMediaSourceCenterOwr.cpp @@ -0,0 +1,191 @@ +/* + * Copyright (C) 2011 Ericsson AB. All rights reserved. + * Copyright (C) 2012 Google Inc. All rights reserved. + * Copyright (C) 2015 Igalia S.L. All rights reserved. + * Copyright (C) 2015 Metrological. 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) && USE(OPENWEBRTC) +#include "RealtimeMediaSourceCenterOwr.h" + +#include "CaptureDevice.h" +#include "MediaStreamPrivate.h" +#include "NotImplemented.h" +#include "OpenWebRTCUtilities.h" +#include "RealtimeAudioSourceOwr.h" +#include "RealtimeMediaSourceCapabilities.h" +#include "RealtimeVideoSourceOwr.h" +#include "UUID.h" +#include <owr/owr.h> +#include <owr/owr_local.h> +#include <owr/owr_media_source.h> +#include <wtf/MainThread.h> +#include <wtf/NeverDestroyed.h> +#include <wtf/glib/GUniquePtr.h> +#include <wtf/text/CString.h> +#include <wtf/text/StringHash.h> + + +namespace WebCore { + +RealtimeMediaSourceCenter& RealtimeMediaSourceCenter::platformCenter() +{ + ASSERT(isMainThread()); + static NeverDestroyed<RealtimeMediaSourceCenterOwr> center; + return center; +} + +static void mediaSourcesAvailableCallback(GList* sources, gpointer userData) +{ + RealtimeMediaSourceCenterOwr* center = reinterpret_cast<RealtimeMediaSourceCenterOwr*>(userData); + center->mediaSourcesAvailable(sources); +} + +RealtimeMediaSourceCenterOwr::RealtimeMediaSourceCenterOwr() +{ + initializeOpenWebRTC(); +} + +RealtimeMediaSourceCenterOwr::~RealtimeMediaSourceCenterOwr() +{ +} + +void RealtimeMediaSourceCenterOwr::validateRequestConstraints(ValidConstraintsHandler validHandler, InvalidConstraintsHandler invalidHandler, const MediaConstraints& audioConstraints, const MediaConstraints& videoConstraints) +{ + m_validConstraintsHandler = WTFMove(validHandler); + m_invalidConstraintsHandler = WTFMove(invalidHandler); + + Vector<String> audioSources; + Vector<String> videoSources; + + // FIXME: Actually do constraints validation. The MediaConstraints + // need to comply with the available audio/video device(s) + // capabilities. See bug #123345. + if (audioConstraints.isValid()) + audioSources.append(String("audio")); + + if (videoConstraints.isValid()) + videoSources.append(String("video")); + + m_validConstraintsHandler(WTFMove(audioSources), WTFMove(videoSources)); + m_validConstraintsHandler = nullptr; + m_invalidConstraintsHandler = nullptr; +} + +void RealtimeMediaSourceCenterOwr::createMediaStream(NewMediaStreamHandler completionHandler, const String& audioDeviceID, const String& videoDeviceID, const MediaConstraints*, const MediaConstraints*) +{ + int types = OWR_MEDIA_TYPE_UNKNOWN; + + if (!audioDeviceID.isEmpty()) + types |= OWR_MEDIA_TYPE_AUDIO; + if (!videoDeviceID.isEmpty()) + types |= OWR_MEDIA_TYPE_VIDEO; + + m_completionHandler = completionHandler; + + owr_get_capture_sources(static_cast<OwrMediaType>(types), mediaSourcesAvailableCallback, this); +} + +Vector<CaptureDevice> RealtimeMediaSourceCenterOwr::getMediaStreamDevices() +{ + notImplemented(); + return Vector<CaptureDevice>(); +} + +void RealtimeMediaSourceCenterOwr::mediaSourcesAvailable(GList* sources) +{ + Vector<Ref<RealtimeMediaSource>> audioSources; + Vector<Ref<RealtimeMediaSource>> videoSources; + + for (auto item = sources; item; item = item->next) { + OwrMediaSource* source = OWR_MEDIA_SOURCE(item->data); + + GUniqueOutPtr<gchar> name; + OwrMediaType mediaType; + g_object_get(source, "media-type", &mediaType, "name", &name.outPtr(), NULL); + String sourceName(name.get()); + String id(createCanonicalUUIDString()); + + if (g_getenv("OWR_USE_TEST_SOURCES")) { + OwrSourceType sourceType = OWR_SOURCE_TYPE_UNKNOWN; + g_object_get(source, "type", &sourceType, NULL); + if (sourceType != OWR_SOURCE_TYPE_TEST) + continue; + } + + RealtimeMediaSource::Type mediaSourceType; + if (mediaType & OWR_MEDIA_TYPE_AUDIO) + mediaSourceType = RealtimeMediaSource::Audio; + else if (mediaType & OWR_MEDIA_TYPE_VIDEO) + mediaSourceType = RealtimeMediaSource::Video; + else { + mediaSourceType = RealtimeMediaSource::None; + ASSERT_NOT_REACHED(); + } + + RefPtr<RealtimeMediaSourceOwr> mediaSource; + if (mediaSourceType == RealtimeMediaSource::Audio) + mediaSource = adoptRef(new RealtimeAudioSourceOwr(source, id, mediaSourceType, sourceName)); + else + mediaSource = adoptRef(new RealtimeVideoSourceOwr(source, id, mediaSourceType, sourceName)); + + RealtimeMediaSourceOwrMap::iterator sourceIterator = m_sourceMap.find(id); + if (sourceIterator == m_sourceMap.end()) + m_sourceMap.add(id, mediaSource.copyRef()); + + if (mediaType & OWR_MEDIA_TYPE_AUDIO) + audioSources.append(mediaSource.releaseNonNull()); + else if (mediaType & OWR_MEDIA_TYPE_VIDEO) + videoSources.append(mediaSource.releaseNonNull()); + + } + + if (videoSources.isEmpty() && audioSources.isEmpty()) + m_completionHandler(nullptr); + else + m_completionHandler(MediaStreamPrivate::create(audioSources, videoSources)); + +} + +PassRefPtr<RealtimeMediaSource> RealtimeMediaSourceCenterOwr::firstSource(RealtimeMediaSource::Type type) +{ + for (auto iter = m_sourceMap.begin(); iter != m_sourceMap.end(); ++iter) { + RefPtr<RealtimeMediaSource> source = iter->value; + if (source->type() == type) + return source; + } + + return nullptr; +} + +} // namespace WebCore + +#endif // ENABLE(MEDIA_STREAM) && USE(OPENWEBRTC) diff --git a/Source/WebCore/platform/mediastream/openwebrtc/RealtimeMediaSourceCenterOwr.h b/Source/WebCore/platform/mediastream/openwebrtc/RealtimeMediaSourceCenterOwr.h new file mode 100644 index 000000000..6cdd7d5fe --- /dev/null +++ b/Source/WebCore/platform/mediastream/openwebrtc/RealtimeMediaSourceCenterOwr.h @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2011 Ericsson AB. All rights reserved. + * Copyright (C) 2012 Google Inc. All rights reserved. + * Copyright (C) 2015 Igalia S.L. All rights reserved. + * Copyright (C) 2015 Metrological. 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 RealtimeMediaSourceCenterOwr_h +#define RealtimeMediaSourceCenterOwr_h + +#if ENABLE(MEDIA_STREAM) && USE(OPENWEBRTC) + +#include "RealtimeMediaSourceCenter.h" + +#include "RealtimeMediaSourceOwr.h" +#include <wtf/PassRefPtr.h> + +namespace WebCore { + +class CaptureDevice; +class MediaStreamPrivate; +class RealtimeMediaSource; +class MediaStreamSourcesQueryClient; +class TrackSourceInfo; + +class RealtimeMediaSourceCenterOwr final : public RealtimeMediaSourceCenter { +public: + RealtimeMediaSourceCenterOwr(); + ~RealtimeMediaSourceCenterOwr(); + + void validateRequestConstraints(ValidConstraintsHandler validHandler, InvalidConstraintsHandler invalidHandler, const MediaConstraints& audioConstraints, const MediaConstraints& videoConstraints) final; + + void createMediaStream(NewMediaStreamHandler, const String& audioDeviceID, const String& videoDeviceID, const MediaConstraints* videoConstraints, const MediaConstraints* audioConstraints) final; + + Vector<CaptureDevice> getMediaStreamDevices() final; + + void mediaSourcesAvailable(GList* sources); + +private: + PassRefPtr<RealtimeMediaSource> firstSource(RealtimeMediaSource::Type); + RealtimeMediaSourceOwrMap m_sourceMap; + ValidConstraintsHandler m_validConstraintsHandler; + InvalidConstraintsHandler m_invalidConstraintsHandler; + NewMediaStreamHandler m_completionHandler; +}; + +} // namespace WebCore + +#endif // ENABLE(MEDIA_STREAM) && USE(OPENWEBRTC) + +#endif // RealtimeMediaSourceCenterOwr_h diff --git a/Source/WebCore/platform/mediastream/openwebrtc/RealtimeMediaSourceOwr.cpp b/Source/WebCore/platform/mediastream/openwebrtc/RealtimeMediaSourceOwr.cpp new file mode 100644 index 000000000..ee7499d38 --- /dev/null +++ b/Source/WebCore/platform/mediastream/openwebrtc/RealtimeMediaSourceOwr.cpp @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2016 Igalia S.L + * + * 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 the copyright holder 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 + * HOLDER 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) && USE(OPENWEBRTC) +#include "RealtimeMediaSourceOwr.h" + +namespace WebCore { + +const RealtimeMediaSourceSettings& RealtimeMediaSourceOwr::settings() const +{ + const_cast<RealtimeMediaSourceOwr&>(*this).initializeSettings(); + return m_currentSettings; +} + +RealtimeMediaSourceSupportedConstraints& RealtimeMediaSourceOwr::supportedConstraints() +{ + if (m_supportedConstraints.supportsDeviceId()) + return m_supportedConstraints; + + m_supportedConstraints.setSupportsDeviceId(true); + initializeSupportedConstraints(m_supportedConstraints); + + return m_supportedConstraints; +} + +} // namespace WebCore + +#endif // ENABLE(MEDIA_STREAM) && USE(OPENWEBRTC) diff --git a/Source/WebCore/platform/mediastream/openwebrtc/RealtimeMediaSourceOwr.h b/Source/WebCore/platform/mediastream/openwebrtc/RealtimeMediaSourceOwr.h new file mode 100644 index 000000000..a8f78e222 --- /dev/null +++ b/Source/WebCore/platform/mediastream/openwebrtc/RealtimeMediaSourceOwr.h @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2015 Igalia S.L + * Copyright (C) 2015 Metrological + * + * 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 the copyright holder 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 + * HOLDER 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 RealtimeMediaSourceOwr_h +#define RealtimeMediaSourceOwr_h + +#if ENABLE(MEDIA_STREAM) && USE(OPENWEBRTC) + +#include "GRefPtrGStreamer.h" +#include "RealtimeMediaSource.h" +#include <owr/owr_media_source.h> +#include <wtf/HashMap.h> +#include <wtf/RefPtr.h> +#include <wtf/text/WTFString.h> + +namespace WebCore { + +class RealtimeMediaSourceCapabilities; + +class RealtimeMediaSourceOwr : public RealtimeMediaSource { +public: +RealtimeMediaSourceOwr(OwrMediaSource* mediaSource, const String& id, RealtimeMediaSource::Type type, const String& name) + : RealtimeMediaSource(id, type, name) + , m_mediaSource(mediaSource) + { + if (!mediaSource) + m_muted = true; + } + +RealtimeMediaSourceOwr(const String& id, RealtimeMediaSource::Type type, const String& name) + : RealtimeMediaSource(id, type, name) + , m_mediaSource(nullptr) + { + } + + virtual ~RealtimeMediaSourceOwr() { } + + void swapOutShallowSource(OwrMediaSource& realSource) + { + m_mediaSource = &realSource; + setMuted(false); + } + + RefPtr<RealtimeMediaSourceCapabilities> capabilities() const override { return m_capabilities; } + const RealtimeMediaSourceSettings& settings() const override; + + OwrMediaSource* mediaSource() const { return m_mediaSource; } + +protected: + virtual void initializeSettings() { }; + virtual void initializeSupportedConstraints(RealtimeMediaSourceSupportedConstraints&) { }; + RealtimeMediaSourceSupportedConstraints& supportedConstraints(); + + RealtimeMediaSourceSettings m_currentSettings; + +private: + RealtimeMediaSourceSupportedConstraints m_supportedConstraints; + RefPtr<RealtimeMediaSourceCapabilities> m_capabilities; + OwrMediaSource* m_mediaSource; +}; + +typedef HashMap<String, RefPtr<RealtimeMediaSourceOwr>> RealtimeMediaSourceOwrMap; + +} // namespace WebCore + +#endif // ENABLE(MEDIA_STREAM) && USE(OPENWEBRTC) + +#endif // RealtimeMediaSourceOwr_h diff --git a/Source/WebCore/platform/mediastream/openwebrtc/RealtimeVideoSourceOwr.h b/Source/WebCore/platform/mediastream/openwebrtc/RealtimeVideoSourceOwr.h new file mode 100644 index 000000000..dc66a3e2b --- /dev/null +++ b/Source/WebCore/platform/mediastream/openwebrtc/RealtimeVideoSourceOwr.h @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2015,2016 Igalia S.L + * Copyright (C) 2015 Metrological + * + * 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 the copyright holder 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 + * HOLDER 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. + */ + +#pragma once + +#if ENABLE(MEDIA_STREAM) && USE(OPENWEBRTC) + +#include "RealtimeMediaSourceOwr.h" + +namespace WebCore { + +class RealtimeVideoSourceOwr : public RealtimeMediaSourceOwr { +public: +RealtimeVideoSourceOwr(OwrMediaSource* mediaSource, const String& id, RealtimeMediaSource::Type type, const String& name) + : RealtimeMediaSourceOwr(mediaSource, id, type, name) + { + } + +RealtimeVideoSourceOwr(const String& id, RealtimeMediaSource::Type type, const String& name) + : RealtimeMediaSourceOwr(id, type, name) + { + } + + virtual ~RealtimeVideoSourceOwr() { } + + bool applySize(const IntSize&) final { return true; } + +protected: + void initializeSettings() final { + if (m_currentSettings.deviceId().isEmpty()) + m_currentSettings.setSupportedConstraits(supportedConstraints()); + + m_currentSettings.setDeviceId(id()); + + m_currentSettings.setFrameRate(frameRate()); + m_currentSettings.setWidth(size().width()); + m_currentSettings.setHeight(size().height()); + } + + void initializeSupportedConstraints(RealtimeMediaSourceSupportedConstraints& supportedConstraints) final { + supportedConstraints.setSupportsFacingMode(RealtimeMediaSourceSettings::Unknown); + supportedConstraints.setSupportsWidth(true); + supportedConstraints.setSupportsHeight(true); + supportedConstraints.setSupportsAspectRatio(true); + supportedConstraints.setSupportsFrameRate(true); + } +}; + +} // namespace WebCore + +#endif // ENABLE(MEDIA_STREAM) && USE(OPENWEBRTC) |