diff options
Diffstat (limited to 'Source/WebCore/platform/mediastream')
66 files changed, 6466 insertions, 1387 deletions
diff --git a/Source/WebCore/platform/mediastream/AudioTrackPrivateMediaStream.h b/Source/WebCore/platform/mediastream/AudioTrackPrivateMediaStream.h new file mode 100644 index 000000000..f3e1c3dc0 --- /dev/null +++ b/Source/WebCore/platform/mediastream/AudioTrackPrivateMediaStream.h @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2015-2017 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. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#if ENABLE(VIDEO_TRACK) && ENABLE(MEDIA_STREAM) + +#include "AudioTrackPrivate.h" +#include "MediaStreamTrackPrivate.h" + +namespace WebCore { + +class AudioTrackPrivateMediaStream : public AudioTrackPrivate { + WTF_MAKE_NONCOPYABLE(AudioTrackPrivateMediaStream) +public: + static RefPtr<AudioTrackPrivateMediaStream> create(MediaStreamTrackPrivate& streamTrack) + { + return adoptRef(*new AudioTrackPrivateMediaStream(streamTrack)); + } + + Kind kind() const override { return Kind::Main; } + AtomicString id() const override { return m_id; } + AtomicString label() const override { return m_label; } + AtomicString language() const override { return emptyAtom; } + int trackIndex() const override { return m_index; } + + void setTrackIndex(int index) { m_index = index; } + + MediaStreamTrackPrivate& streamTrack() { return m_streamTrack.get(); } + + MediaTime timelineOffset() const { return m_timelineOffset; } + void setTimelineOffset(const MediaTime& offset) { m_timelineOffset = offset; } + +protected: + AudioTrackPrivateMediaStream(MediaStreamTrackPrivate& track) + : m_streamTrack(track) + , m_id(track.id()) + , m_label(track.label()) + , m_timelineOffset(MediaTime::invalidTime()) + { + } + + Ref<MediaStreamTrackPrivate> m_streamTrack; + AtomicString m_id; + AtomicString m_label; + int m_index { 0 }; + MediaTime m_timelineOffset; +}; + +} + +#endif // ENABLE(VIDEO_TRACK) && ENABLE(MEDIA_STREAM) diff --git a/Source/WebCore/platform/mediastream/CaptureDevice.h b/Source/WebCore/platform/mediastream/CaptureDevice.h new file mode 100644 index 000000000..86152bf7e --- /dev/null +++ b/Source/WebCore/platform/mediastream/CaptureDevice.h @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2016 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. + */ + +#pragma once + +#if ENABLE(MEDIA_STREAM) + +#include <wtf/text/WTFString.h> + +namespace WebCore { + +class CaptureDevice { +public: + enum class DeviceType { Unknown, Audio, Video }; + + CaptureDevice(const String& persistentId, DeviceType type, const String& label, const String& groupId = emptyString()) + : m_persistentId(persistentId) + , m_type(type) + , m_label(label) + , m_groupId(groupId) + { + } + + CaptureDevice() = default; + + const String& persistentId() const { return m_persistentId; } + void setPersistentId(const String& id) { m_persistentId = id; } + + const String& label() const { return m_label; } + void setLabel(const String& label) { m_label = label; } + + const String& groupId() const { return m_groupId; } + void setGroupId(const String& id) { m_groupId = id; } + + DeviceType type() const { return m_type; } + void setType(DeviceType type) { m_type = type; } + + bool enabled() const { return m_enabled; } + void setEnabled(bool enabled) { m_enabled = enabled; } +private: + String m_persistentId; + DeviceType m_type { DeviceType::Unknown }; + String m_label; + String m_groupId; + bool m_enabled { false }; +}; + +} // namespace WebCore + +#endif // ENABLE(MEDIA_STREAM) diff --git a/Source/WebCore/platform/mediastream/CaptureDeviceManager.cpp b/Source/WebCore/platform/mediastream/CaptureDeviceManager.cpp new file mode 100644 index 000000000..19fe3a02f --- /dev/null +++ b/Source/WebCore/platform/mediastream/CaptureDeviceManager.cpp @@ -0,0 +1,124 @@ +/* + * Copyright (C) 2015-2016 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. + */ + +#import "config.h" +#import "CaptureDeviceManager.h" + +#if ENABLE(MEDIA_STREAM) + +#import "Logging.h" +#import "MediaConstraints.h" +#import "RealtimeMediaSource.h" +#import "RealtimeMediaSourceCenter.h" +#import "RealtimeMediaSourceSettings.h" +#import "UUID.h" +#import <wtf/MainThread.h> +#import <wtf/NeverDestroyed.h> +#import <wtf/text/StringHash.h> + +using namespace WebCore; + +CaptureDeviceManager::~CaptureDeviceManager() +{ +} + +Vector<CaptureDevice> CaptureDeviceManager::getSourcesInfo() +{ + Vector<CaptureDevice> sourcesInfo; + for (auto captureDevice : captureDevices()) { + if (!captureDevice.enabled() || captureDevice.type() == CaptureDevice::DeviceType::Unknown) + continue; + + sourcesInfo.append(captureDevice); + } + LOG(Media, "CaptureDeviceManager::getSourcesInfo(%p), found %zu active devices", this, sourcesInfo.size()); + return sourcesInfo; +} + +bool CaptureDeviceManager::captureDeviceFromDeviceID(const String& captureDeviceID, CaptureDevice& foundDevice) +{ + for (auto& device : captureDevices()) { + if (device.persistentId() == captureDeviceID) { + foundDevice = device; + return true; + } + } + + return false; +} + +Vector<String> CaptureDeviceManager::bestSourcesForTypeAndConstraints(RealtimeMediaSource::Type type, const MediaConstraints& constraints, String& invalidConstraint) +{ + Vector<RefPtr<RealtimeMediaSource>> bestSources; + + struct { + bool operator()(RefPtr<RealtimeMediaSource> a, RefPtr<RealtimeMediaSource> b) + { + return a->fitnessScore() < b->fitnessScore(); + } + } sortBasedOnFitnessScore; + + CaptureDevice::DeviceType deviceType = type == RealtimeMediaSource::Video ? CaptureDevice::DeviceType::Video : CaptureDevice::DeviceType::Audio; + for (auto& captureDevice : captureDevices()) { + if (!captureDevice.enabled() || captureDevice.type() != deviceType) + continue; + + if (auto captureSource = createMediaSourceForCaptureDeviceWithConstraints(captureDevice, &constraints, invalidConstraint)) + bestSources.append(captureSource.leakRef()); + } + + Vector<String> sourceUIDs; + if (bestSources.isEmpty()) + return sourceUIDs; + + sourceUIDs.reserveInitialCapacity(bestSources.size()); + std::sort(bestSources.begin(), bestSources.end(), sortBasedOnFitnessScore); + for (auto& device : bestSources) + sourceUIDs.uncheckedAppend(device->persistentID()); + + return sourceUIDs; +} + +RefPtr<RealtimeMediaSource> CaptureDeviceManager::sourceWithUID(const String& deviceUID, RealtimeMediaSource::Type type, const MediaConstraints* constraints, String& invalidConstraint) +{ + for (auto& captureDevice : captureDevices()) { + if (type == RealtimeMediaSource::None) + continue; + + CaptureDevice::DeviceType deviceType = type == RealtimeMediaSource::Video ? CaptureDevice::DeviceType::Video : CaptureDevice::DeviceType::Audio; + if (captureDevice.persistentId() != deviceUID || captureDevice.type() != deviceType) + continue; + + if (!captureDevice.enabled()) + continue; + + if (auto mediaSource = createMediaSourceForCaptureDeviceWithConstraints(captureDevice, constraints, invalidConstraint)) + return mediaSource; + } + + return nullptr; +} + +#endif // ENABLE(MEDIA_STREAM) diff --git a/Source/WebCore/platform/mediastream/MediaStreamCreationClient.h b/Source/WebCore/platform/mediastream/CaptureDeviceManager.h index 22aa49714..5d40099f3 100644 --- a/Source/WebCore/platform/mediastream/MediaStreamCreationClient.h +++ b/Source/WebCore/platform/mediastream/CaptureDeviceManager.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 Apple Inc. All rights reserved. + * Copyright (C) 2015-2016 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -10,10 +10,10 @@ * 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 COMPUTER, INC. ``AS IS'' AND ANY + * 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 COMPUTER, INC. OR + * 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 @@ -23,31 +23,30 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef MediaStreamCreationClient_h -#define MediaStreamCreationClient_h +#pragma once #if ENABLE(MEDIA_STREAM) -#include "MediaStreamSource.h" -#include <wtf/PassRefPtr.h> -#include <wtf/RefCounted.h> +#include "CaptureDevice.h" +#include "RealtimeMediaSource.h" namespace WebCore { -class MediaStreamCreationClient : public RefCounted<MediaStreamCreationClient> { +class CaptureDeviceManager { public: - virtual ~MediaStreamCreationClient() { } + virtual Vector<CaptureDevice>& captureDevices() = 0; + virtual void refreshCaptureDevices() { } + virtual Vector<CaptureDevice> getSourcesInfo(); + virtual Vector<String> bestSourcesForTypeAndConstraints(RealtimeMediaSource::Type, const MediaConstraints&, String&); + virtual RefPtr<RealtimeMediaSource> sourceWithUID(const String&, RealtimeMediaSource::Type, const MediaConstraints*, String&); - virtual void constraintsValidated() = 0; - virtual void constraintsInvalid(const String& constraintName) = 0; +protected: + virtual ~CaptureDeviceManager(); + virtual RefPtr<RealtimeMediaSource> createMediaSourceForCaptureDeviceWithConstraints(const CaptureDevice&, const MediaConstraints*, String&) = 0; - virtual void didCreateStream(PassRefPtr<MediaStreamPrivate>) = 0; - virtual void failedToCreateStreamWithConstraintsError(const String& constraintName) = 0; - virtual void failedToCreateStreamWithPermissionError() = 0; + bool captureDeviceFromDeviceID(const String& captureDeviceID, CaptureDevice& source); }; } // namespace WebCore #endif // ENABLE(MEDIA_STREAM) - -#endif // MediaStreamCreationClient_h diff --git a/Source/WebCore/platform/mediastream/MediaStreamCenter.h b/Source/WebCore/platform/mediastream/IceCandidate.h index 7d540b94d..2b28c375b 100644 --- a/Source/WebCore/platform/mediastream/MediaStreamCenter.h +++ b/Source/WebCore/platform/mediastream/IceCandidate.h @@ -1,6 +1,5 @@ /* - * Copyright (C) 2011 Ericsson AB. All rights reserved. - * Copyright (C) 2012 Google 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 @@ -29,43 +28,41 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef MediaStreamCenter_h -#define MediaStreamCenter_h +#pragma once -#if ENABLE(MEDIA_STREAM) +#if ENABLE(WEB_RTC) -#include "MediaStreamSource.h" -#include <wtf/PassRefPtr.h> #include <wtf/text/WTFString.h> namespace WebCore { -class MediaConstraints; -class MediaStreamCreationClient; -class MediaStreamSourceStates; -class MediaStreamTrackSourcesRequestClient; +struct IceCandidate { + String type; + String foundation; + unsigned componentId { 0 }; + String transport; + unsigned long priority { 0 }; + String address; + unsigned port { 0 }; + String tcpType; + String relatedAddress; + unsigned relatedPort { 0 }; -class MediaStreamCenter { -public: - virtual ~MediaStreamCenter(); - - static MediaStreamCenter& shared(); - static void setSharedStreamCenter(MediaStreamCenter*); - - virtual void validateRequestConstraints(PassRefPtr<MediaStreamCreationClient>, PassRefPtr<MediaConstraints> audioConstraints, PassRefPtr<MediaConstraints> videoConstraints) = 0; - - virtual void createMediaStream(PassRefPtr<MediaStreamCreationClient>, PassRefPtr<MediaConstraints> audioConstraints, PassRefPtr<MediaConstraints> videoConstraints) = 0; - - virtual bool getMediaStreamTrackSources(PassRefPtr<MediaStreamTrackSourcesRequestClient>) = 0; - -protected: - MediaStreamCenter(); - - static MediaStreamCenter& platformCenter(); + IceCandidate() = default; + IceCandidate(String&& type, String&& foundation, unsigned componentId, String&& transport, unsigned long priority, String&& address, unsigned port, String&& tcpType, String&& relatedAddress, unsigned relatedPort) + : type(WTFMove(type)) + , foundation(WTFMove(foundation)) + , componentId(componentId) + , transport(WTFMove(transport)) + , priority(priority) + , address(WTFMove(address)) + , port(port) + , tcpType(WTFMove(tcpType)) + , relatedAddress(WTFMove(relatedAddress)) + , relatedPort(relatedPort) + { } }; } // namespace WebCore -#endif // ENABLE(MEDIA_STREAM) - -#endif // MediaStreamCenter_h +#endif // ENABLE(WEB_RTC) diff --git a/Source/WebCore/platform/mediastream/MediaConstraints.cpp b/Source/WebCore/platform/mediastream/MediaConstraints.cpp new file mode 100644 index 000000000..2805dce99 --- /dev/null +++ b/Source/WebCore/platform/mediastream/MediaConstraints.cpp @@ -0,0 +1,345 @@ +/* + * Copyright (C) 2016 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. + * 3. Neither the name of Google Inc. 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 "MediaConstraints.h" + +#if ENABLE(MEDIA_STREAM) +#include "RealtimeMediaSourceCenter.h" +#include "RealtimeMediaSourceSupportedConstraints.h" +#include <wtf/StdLibExtras.h> + +namespace WebCore { + +const String& StringConstraint::find(std::function<bool(const String&)> filter) const +{ + for (auto& constraint : m_exact) { + if (filter(constraint)) + return constraint; + } + + for (auto& constraint : m_ideal) { + if (filter(constraint)) + return constraint; + } + + return emptyString(); +} + +double StringConstraint::fitnessDistance(const String& value) const +{ + // https://w3c.github.io/mediacapture-main/#dfn-applyconstraints + + // 1. If the constraint is not supported by the browser, the fitness distance is 0. + if (isEmpty()) + return 0; + + // 2. If the constraint is required ('min', 'max', or 'exact'), and the settings + // dictionary's value for the constraint does not satisfy the constraint, the + // fitness distance is positive infinity. + if (!m_exact.isEmpty() && m_exact.find(value) == notFound) + return std::numeric_limits<double>::infinity(); + + // 3. If no ideal value is specified, the fitness distance is 0. + if (m_exact.isEmpty()) + return 0; + + // 5. For all string and enum non-required constraints (deviceId, groupId, facingMode, + // echoCancellation), the fitness distance is the result of the formula + // (actual == ideal) ? 0 : 1 + return m_ideal.find(value) != notFound ? 0 : 1; +} + +double StringConstraint::fitnessDistance(const Vector<String>& values) const +{ + if (isEmpty()) + return 0; + + double minimumDistance = std::numeric_limits<double>::infinity(); + for (auto& value : values) + minimumDistance = std::min(minimumDistance, fitnessDistance(value)); + + return minimumDistance; +} + +void StringConstraint::merge(const MediaConstraint& other) +{ + ASSERT(other.isString()); + const StringConstraint& typedOther = downcast<StringConstraint>(other); + + if (typedOther.isEmpty()) + return; + + Vector<String> values; + if (typedOther.getExact(values)) { + if (m_exact.isEmpty()) + m_exact = values; + else { + for (auto& value : values) { + if (m_exact.find(value) == notFound) + m_exact.append(value); + } + } + } + + if (typedOther.getIdeal(values)) { + if (m_ideal.isEmpty()) + m_ideal = values; + else { + for (auto& value : values) { + if (m_ideal.find(value) == notFound) + m_ideal.append(value); + } + } + } +} + +void FlattenedConstraint::set(const MediaConstraint& constraint) +{ + for (auto& variant : m_variants) { + if (variant.constraintType() == constraint.constraintType()) + return; + } + + append(constraint); +} + +void FlattenedConstraint::merge(const MediaConstraint& constraint) +{ + for (auto& variant : *this) { + if (variant.constraintType() != constraint.constraintType()) + continue; + + switch (variant.dataType()) { + case MediaConstraint::DataType::Integer: + ASSERT(constraint.isInt()); + downcast<const IntConstraint>(variant).merge(downcast<const IntConstraint>(constraint)); + return; + case MediaConstraint::DataType::Double: + ASSERT(constraint.isDouble()); + downcast<const DoubleConstraint>(variant).merge(downcast<const DoubleConstraint>(constraint)); + return; + case MediaConstraint::DataType::Boolean: + ASSERT(constraint.isBoolean()); + downcast<const BooleanConstraint>(variant).merge(downcast<const BooleanConstraint>(constraint)); + return; + case MediaConstraint::DataType::String: + ASSERT(constraint.isString()); + downcast<const StringConstraint>(variant).merge(downcast<const StringConstraint>(constraint)); + return; + case MediaConstraint::DataType::None: + ASSERT_NOT_REACHED(); + return; + } + } + + append(constraint); +} + +void FlattenedConstraint::append(const MediaConstraint& constraint) +{ +#ifndef NDEBUG + ++m_generation; +#endif + + m_variants.append(ConstraintHolder::create(constraint)); +} + +const MediaConstraint* FlattenedConstraint::find(MediaConstraintType type) const +{ + for (auto& variant : m_variants) { + if (variant.constraintType() == type) + return &variant.constraint(); + } + + return nullptr; +} + +void MediaTrackConstraintSetMap::forEach(std::function<void(const MediaConstraint&)> callback) const +{ + filter([callback] (const MediaConstraint& constraint) mutable { + callback(constraint); + return false; + }); +} + +void MediaTrackConstraintSetMap::filter(std::function<bool(const MediaConstraint&)> callback) const +{ + if (m_width && !m_width->isEmpty() && callback(*m_width)) + return; + if (m_height && !m_height->isEmpty() && callback(*m_height)) + return; + if (m_sampleRate && !m_sampleRate->isEmpty() && callback(*m_sampleRate)) + return; + if (m_sampleSize && !m_sampleSize->isEmpty() && callback(*m_sampleSize)) + return; + + if (m_aspectRatio && !m_aspectRatio->isEmpty() && callback(*m_aspectRatio)) + return; + if (m_frameRate && !m_frameRate->isEmpty() && callback(*m_frameRate)) + return; + if (m_volume && !m_volume->isEmpty() && callback(*m_volume)) + return; + + if (m_echoCancellation && !m_echoCancellation->isEmpty() && callback(*m_echoCancellation)) + return; + + if (m_facingMode && !m_facingMode->isEmpty() && callback(*m_facingMode)) + return; + if (m_deviceId && !m_deviceId->isEmpty() && callback(*m_deviceId)) + return; + if (m_groupId && !m_groupId->isEmpty() && callback(*m_groupId)) + return; +} + +void MediaTrackConstraintSetMap::set(MediaConstraintType constraintType, std::optional<IntConstraint>&& constraint) +{ + switch (constraintType) { + case MediaConstraintType::Width: + m_width = WTFMove(constraint); + break; + case MediaConstraintType::Height: + m_height = WTFMove(constraint); + break; + case MediaConstraintType::SampleRate: + m_sampleRate = WTFMove(constraint); + break; + case MediaConstraintType::SampleSize: + m_sampleSize = WTFMove(constraint); + break; + + case MediaConstraintType::AspectRatio: + case MediaConstraintType::FrameRate: + case MediaConstraintType::Volume: + case MediaConstraintType::EchoCancellation: + case MediaConstraintType::FacingMode: + case MediaConstraintType::DeviceId: + case MediaConstraintType::GroupId: + case MediaConstraintType::Unknown: + ASSERT_NOT_REACHED(); + break; + } +} + +void MediaTrackConstraintSetMap::set(MediaConstraintType constraintType, std::optional<DoubleConstraint>&& constraint) +{ + switch (constraintType) { + case MediaConstraintType::AspectRatio: + m_aspectRatio = WTFMove(constraint); + break; + case MediaConstraintType::FrameRate: + m_frameRate = WTFMove(constraint); + break; + case MediaConstraintType::Volume: + m_volume = WTFMove(constraint); + break; + + case MediaConstraintType::Width: + case MediaConstraintType::Height: + case MediaConstraintType::SampleRate: + case MediaConstraintType::SampleSize: + case MediaConstraintType::EchoCancellation: + case MediaConstraintType::FacingMode: + case MediaConstraintType::DeviceId: + case MediaConstraintType::GroupId: + case MediaConstraintType::Unknown: + ASSERT_NOT_REACHED(); + break; + } +} + +void MediaTrackConstraintSetMap::set(MediaConstraintType constraintType, std::optional<BooleanConstraint>&& constraint) +{ + switch (constraintType) { + case MediaConstraintType::EchoCancellation: + m_echoCancellation = WTFMove(constraint); + break; + + case MediaConstraintType::Width: + case MediaConstraintType::Height: + case MediaConstraintType::SampleRate: + case MediaConstraintType::SampleSize: + case MediaConstraintType::AspectRatio: + case MediaConstraintType::FrameRate: + case MediaConstraintType::Volume: + case MediaConstraintType::FacingMode: + case MediaConstraintType::DeviceId: + case MediaConstraintType::GroupId: + case MediaConstraintType::Unknown: + ASSERT_NOT_REACHED(); + break; + } +} + +void MediaTrackConstraintSetMap::set(MediaConstraintType constraintType, std::optional<StringConstraint>&& constraint) +{ + switch (constraintType) { + case MediaConstraintType::FacingMode: + m_facingMode = WTFMove(constraint); + break; + case MediaConstraintType::DeviceId: + m_deviceId = WTFMove(constraint); + break; + case MediaConstraintType::GroupId: + m_groupId = WTFMove(constraint); + break; + + case MediaConstraintType::Width: + case MediaConstraintType::Height: + case MediaConstraintType::SampleRate: + case MediaConstraintType::SampleSize: + case MediaConstraintType::AspectRatio: + case MediaConstraintType::FrameRate: + case MediaConstraintType::Volume: + case MediaConstraintType::EchoCancellation: + case MediaConstraintType::Unknown: + ASSERT_NOT_REACHED(); + break; + } +} + +size_t MediaTrackConstraintSetMap::size() const +{ + size_t count = 0; + forEach([&count] (const MediaConstraint&) mutable { + ++count; + }); + + return count; +} + +bool MediaTrackConstraintSetMap::isEmpty() const +{ + return !size(); +} + +} + +#endif // ENABLE(MEDIA_STREAM) diff --git a/Source/WebCore/platform/mediastream/MediaConstraints.h b/Source/WebCore/platform/mediastream/MediaConstraints.h index 5141c228d..899837457 100644 --- a/Source/WebCore/platform/mediastream/MediaConstraints.h +++ b/Source/WebCore/platform/mediastream/MediaConstraints.h @@ -1,5 +1,6 @@ /* * Copyright (C) 2012 Google Inc. All rights reserved. + * Copyright (C) 2016 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -28,36 +29,787 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef MediaConstraints_h -#define MediaConstraints_h +#pragma once #if ENABLE(MEDIA_STREAM) -#include <wtf/RefCounted.h> -#include <wtf/text/WTFString.h> +#include "RealtimeMediaSourceSupportedConstraints.h" +#include <cstdlib> namespace WebCore { -struct MediaConstraint { - MediaConstraint(String name, String value) +class MediaConstraint { +public: + enum class DataType { None, Integer, Double, Boolean, String }; + + bool isInt() const { return m_dataType == DataType::Integer; } + bool isDouble() const { return m_dataType == DataType::Double; } + bool isBoolean() const { return m_dataType == DataType::Boolean; } + bool isString() const { return m_dataType == DataType::String; } + + DataType dataType() const { return m_dataType; } + MediaConstraintType constraintType() const { return m_constraintType; } + const String& name() const { return m_name; } + + template <class Encoder> void encode(Encoder& encoder) const + { + encoder.encodeEnum(m_constraintType); + encoder << m_name; + encoder.encodeEnum(m_dataType); + } + + template <class Decoder> static bool decode(Decoder& decoder, MediaConstraint& constraint) + { + if (!decoder.decodeEnum(constraint.m_constraintType)) + return false; + + if (!decoder.decode(constraint.m_name)) + return false; + + if (!decoder.decodeEnum(constraint.m_dataType)) + return false; + + return true; + } + +protected: + MediaConstraint(const String& name, MediaConstraintType constraintType, DataType dataType) : m_name(name) - , m_value(value) + , m_constraintType(constraintType) + , m_dataType(dataType) { } + MediaConstraint() = default; + ~MediaConstraint() = default; + +private: String m_name; - String m_value; + MediaConstraintType m_constraintType { MediaConstraintType::Unknown }; + DataType m_dataType { DataType::None }; +}; + +template<class ValueType> +class NumericConstraint : public MediaConstraint { +public: + void setMin(ValueType value) { m_min = value; } + void setMax(ValueType value) { m_max = value; } + void setExact(ValueType value) { m_exact = value; } + void setIdeal(ValueType value) { m_ideal = value; } + + bool getMin(ValueType& min) const + { + if (!m_min) + return false; + + min = m_min.value(); + return true; + } + + bool getMax(ValueType& max) const + { + if (!m_max) + return false; + + max = m_max.value(); + return true; + } + + bool getExact(ValueType& exact) const + { + if (!m_exact) + return false; + + exact = m_exact.value(); + return true; + } + + bool getIdeal(ValueType& ideal) const + { + if (!m_ideal) + return false; + + ideal = m_ideal.value(); + return true; + } + + bool nearlyEqual(double a, double b) const + { + // Don't require strict equality when comparing constraints, or many floating point constraint values, + // e.g. "aspectRatio: 1.333", will never match. + const double epsilon = 0.00001; + return std::abs(a - b) <= epsilon; + } + + double fitnessDistance(ValueType rangeMin, ValueType rangeMax) const + { + // https://w3c.github.io/mediacapture-main/#dfn-applyconstraints + // 1. If the constraint is not supported by the browser, the fitness distance is 0. + if (isEmpty()) + return 0; + + // 2. If the constraint is required ('min', 'max', or 'exact'), and the settings + // dictionary's value for the constraint does not satisfy the constraint, the + // fitness distance is positive infinity. + bool valid = validForRange(rangeMin, rangeMax); + if (m_exact) { + if (valid && m_min && m_exact.value() < m_min.value()) + valid = false; + if (valid && m_max && m_exact.value() > m_max.value()) + valid = false; + if (!valid) + return std::numeric_limits<double>::infinity(); + } + + if (m_min) { + if (valid && m_max && m_min.value() > m_max.value()) + valid = false; + if (!valid) + return std::numeric_limits<double>::infinity(); + } + + if (m_max) { + if (valid && m_min && m_max.value() < m_min.value()) + valid = false; + if (!valid) + return std::numeric_limits<double>::infinity(); + } + + // 3. If no ideal value is specified, the fitness distance is 0. + if (!m_ideal) + return 0; + + // 4. For all positive numeric non-required constraints (such as height, width, frameRate, + // aspectRatio, sampleRate and sampleSize), the fitness distance is the result of the formula + // + // (actual == ideal) ? 0 : |actual - ideal| / max(|actual|,|ideal|) + ValueType ideal = m_ideal.value(); + if (ideal >= rangeMin && ideal <= rangeMax) + return 0; + + ideal = ideal > std::max(rangeMin, rangeMax) ? rangeMax : rangeMin; + return static_cast<double>(std::abs(ideal - m_ideal.value())) / std::max(std::abs(ideal), std::abs(m_ideal.value())); + } + + bool validForRange(ValueType rangeMin, ValueType rangeMax) const + { + if (isEmpty()) + return false; + + if (m_exact) { + const ValueType exact = m_exact.value(); + if (exact < rangeMin && !nearlyEqual(exact, rangeMin)) + return false; + if (exact > rangeMax && !nearlyEqual(exact, rangeMax)) + return false; + } + + if (m_min) { + const ValueType constraintMin = m_min.value(); + if (constraintMin > rangeMax && !nearlyEqual(constraintMin, rangeMax)) + return false; + } + + if (m_max) { + const ValueType constraintMax = m_max.value(); + if (constraintMax < rangeMin && !nearlyEqual(constraintMax, rangeMin)) + return false; + } + + return true; + } + + ValueType find(std::function<bool(ValueType)> function) const + { + if (m_min && function(m_min.value())) + return m_min.value(); + + if (m_max && function(m_max.value())) + return m_max.value(); + + if (m_exact && function(m_exact.value())) + return m_exact.value(); + + if (m_ideal && function(m_ideal.value())) + return m_ideal.value(); + + return 0; + } + + ValueType valueForCapabilityRange(ValueType current, ValueType capabilityMin, ValueType capabilityMax) const + { + ValueType value; + ValueType min = capabilityMin; + ValueType max = capabilityMax; + + if (m_exact) { + ASSERT(validForRange(capabilityMin, capabilityMax)); + return m_exact.value(); + } + + if (m_min) { + value = m_min.value(); + ASSERT(validForRange(value, capabilityMax)); + if (value > min) + min = value; + + // If there is no ideal, don't change if minimum is smaller than current. + if (!m_ideal && value < current) + value = current; + } + + if (m_max) { + value = m_max.value(); + ASSERT(validForRange(capabilityMin, value)); + if (value < max) + max = value; + } + + if (m_ideal) + value = std::max(min, std::min(max, m_ideal.value())); + + return value; + } + + bool isEmpty() const { return !m_min && !m_max && !m_exact && !m_ideal; } + bool isMandatory() const { return m_min || m_max || m_exact; } + + template <class Encoder> void encode(Encoder& encoder) const + { + MediaConstraint::encode(encoder); + + encoder << m_min; + encoder << m_max; + encoder << m_exact; + encoder << m_ideal; + } + + template <class Decoder> static bool decode(Decoder& decoder, NumericConstraint& constraint) + { + if (!MediaConstraint::decode(decoder, constraint)) + return false; + + if (!decoder.decode(constraint.m_min)) + return false; + if (!decoder.decode(constraint.m_max)) + return false; + if (!decoder.decode(constraint.m_exact)) + return false; + if (!decoder.decode(constraint.m_ideal)) + return false; + + return true; + } + +protected: + NumericConstraint(const String& name, MediaConstraintType type, DataType dataType) + : MediaConstraint(name, type, dataType) + { + } + + NumericConstraint() = default; + + void innerMerge(const NumericConstraint& other) + { + if (other.isEmpty()) + return; + + ValueType value; + if (other.getExact(value)) + m_exact = value; + + if (other.getMin(value)) + m_min = value; + + if (other.getMax(value)) + m_max = value; + + // https://w3c.github.io/mediacapture-main/#constrainable-interface + // When processing advanced constraints: + // ... the User Agent must attempt to apply, individually, any 'ideal' constraints or + // a constraint given as a bare value for the property. Of these properties, it must + // satisfy the largest number that it can, in any order. + if (other.getIdeal(value)) { + if (!m_ideal || value > m_ideal.value()) + m_ideal = value; + } + } + + std::optional<ValueType> m_min; + std::optional<ValueType> m_max; + std::optional<ValueType> m_exact; + std::optional<ValueType> m_ideal; +}; + +class IntConstraint final : public NumericConstraint<int> { +public: + IntConstraint(const String& name, MediaConstraintType type) + : NumericConstraint<int>(name, type, DataType::Integer) + { + } + + IntConstraint() = default; + + void merge(const MediaConstraint& other) + { + ASSERT(other.isInt()); + NumericConstraint::innerMerge(downcast<const IntConstraint>(other)); + } +}; + +class DoubleConstraint final : public NumericConstraint<double> { +public: + DoubleConstraint(const String& name, MediaConstraintType type) + : NumericConstraint<double>(name, type, DataType::Double) + { + } + + DoubleConstraint() = default; + + void merge(const MediaConstraint& other) + { + ASSERT(other.isDouble()); + NumericConstraint::innerMerge(downcast<DoubleConstraint>(other)); + } +}; + +class BooleanConstraint final : public MediaConstraint { +public: + BooleanConstraint(const String& name, MediaConstraintType type) + : MediaConstraint(name, type, DataType::Boolean) + { + } + + BooleanConstraint() = default; + + void setExact(bool value) { m_exact = value; } + void setIdeal(bool value) { m_ideal = value; } + + bool getExact(bool& exact) const + { + if (!m_exact) + return false; + + exact = m_exact.value(); + return true; + } + + bool getIdeal(bool& ideal) const + { + if (!m_ideal) + return false; + + ideal = m_ideal.value(); + return true; + } + + double fitnessDistance(bool value) const + { + // https://w3c.github.io/mediacapture-main/#dfn-applyconstraints + // 1. If the constraint is not supported by the browser, the fitness distance is 0. + if (isEmpty()) + return 0; + + // 2. If the constraint is required ('min', 'max', or 'exact'), and the settings + // dictionary's value for the constraint does not satisfy the constraint, the + // fitness distance is positive infinity. + if (m_exact && value != m_exact.value()) + return std::numeric_limits<double>::infinity(); + + // 3. If no ideal value is specified, the fitness distance is 0. + if (!m_ideal || m_ideal.value() == value) + return 0; + + // 5. For all string and enum non-required constraints (deviceId, groupId, facingMode, + // echoCancellation), the fitness distance is the result of the formula + // (actual == ideal) ? 0 : 1 + return 1; + } + + void merge(const MediaConstraint& other) + { + ASSERT(other.isBoolean()); + const BooleanConstraint& typedOther = downcast<BooleanConstraint>(other); + + if (typedOther.isEmpty()) + return; + + bool value; + if (typedOther.getExact(value)) + m_exact = value; + + if (typedOther.getIdeal(value)) { + if (!m_ideal || (value && !m_ideal.value())) + m_ideal = value; + } + } + + bool isEmpty() const { return !m_exact && !m_ideal; }; + bool isMandatory() const { return bool(m_exact); } + + template <class Encoder> void encode(Encoder& encoder) const + { + MediaConstraint::encode(encoder); + encoder << m_exact; + encoder << m_ideal; + } + + template <class Decoder> static bool decode(Decoder& decoder, BooleanConstraint& constraint) + { + if (!MediaConstraint::decode(decoder, constraint)) + return false; + + if (!decoder.decode(constraint.m_exact)) + return false; + if (!decoder.decode(constraint.m_ideal)) + return false; + + return true; + } + +private: + std::optional<bool> m_exact; + std::optional<bool> m_ideal; +}; + +class StringConstraint : public MediaConstraint { +public: + StringConstraint(const String& name, MediaConstraintType type) + : MediaConstraint(name, type, DataType::String) + { + } + + StringConstraint() = default; + + void setExact(const String& value) + { + m_exact.clear(); + m_exact.append(value); + } + + void appendExact(const String& value) + { + m_exact.append(value); + } + + void setIdeal(const String& value) + { + m_ideal.clear(); + m_ideal.append(value); + } + + void appendIdeal(const String& value) + { + m_ideal.append(value); + } + + bool getExact(Vector<String>& exact) const + { + if (!m_exact.isEmpty()) + return false; + + exact = m_exact; + return true; + } + + bool getIdeal(Vector<String>& ideal) const + { + if (!m_ideal.isEmpty()) + return false; + + ideal = m_ideal; + return true; + } + + double fitnessDistance(const String&) const; + double fitnessDistance(const Vector<String>&) const; + + const String& find(std::function<bool(const String&)>) const; + + bool isEmpty() const { return m_exact.isEmpty() && m_ideal.isEmpty(); } + bool isMandatory() const { return !m_exact.isEmpty(); } + WEBCORE_EXPORT void merge(const MediaConstraint&); + + template <class Encoder> void encode(Encoder& encoder) const + { + MediaConstraint::encode(encoder); + + encoder << m_exact; + encoder << m_ideal; + } + + template <class Decoder> static bool decode(Decoder& decoder, StringConstraint& constraint) + { + if (!MediaConstraint::decode(decoder, constraint)) + return false; + + if (!decoder.decode(constraint.m_exact)) + return false; + if (!decoder.decode(constraint.m_ideal)) + return false; + + return true; + } + +private: + Vector<String> m_exact; + Vector<String> m_ideal; +}; + +class UnknownConstraint final : public MediaConstraint { +public: + UnknownConstraint(const String& name, MediaConstraintType type) + : MediaConstraint(name, type, DataType::None) + { + } + +private: + bool isEmpty() const { return true; } + bool isMandatory() const { return false; } + void merge(const MediaConstraint&) { } +}; + +class MediaTrackConstraintSetMap { +public: + WEBCORE_EXPORT void forEach(std::function<void(const MediaConstraint&)>) const; + void filter(std::function<bool(const MediaConstraint&)>) const; + bool isEmpty() const; + WEBCORE_EXPORT size_t size() const; + + WEBCORE_EXPORT void set(MediaConstraintType, std::optional<IntConstraint>&&); + WEBCORE_EXPORT void set(MediaConstraintType, std::optional<DoubleConstraint>&&); + WEBCORE_EXPORT void set(MediaConstraintType, std::optional<BooleanConstraint>&&); + WEBCORE_EXPORT void set(MediaConstraintType, std::optional<StringConstraint>&&); + + std::optional<IntConstraint> width() const { return m_width; } + std::optional<IntConstraint> height() const { return m_height; } + std::optional<IntConstraint> sampleRate() const { return m_sampleRate; } + std::optional<IntConstraint> sampleSize() const { return m_sampleSize; } + + std::optional<DoubleConstraint> aspectRatio() const { return m_aspectRatio; } + std::optional<DoubleConstraint> frameRate() const { return m_frameRate; } + std::optional<DoubleConstraint> volume() const { return m_volume; } + + std::optional<BooleanConstraint> echoCancellation() const { return m_echoCancellation; } + + std::optional<StringConstraint> facingMode() const { return m_facingMode; } + std::optional<StringConstraint> deviceId() const { return m_deviceId; } + std::optional<StringConstraint> groupId() const { return m_groupId; } + + template <class Encoder> void encode(Encoder& encoder) const + { + encoder << m_width; + encoder << m_height; + encoder << m_sampleRate; + encoder << m_sampleSize; + + encoder << m_aspectRatio; + encoder << m_frameRate; + encoder << m_volume; + + encoder << m_echoCancellation; + + encoder << m_facingMode; + encoder << m_deviceId; + encoder << m_groupId; + } + + template <class Decoder> static bool decode(Decoder& decoder, MediaTrackConstraintSetMap& map) + { + if (!decoder.decode(map.m_width)) + return false; + if (!decoder.decode(map.m_height)) + return false; + if (!decoder.decode(map.m_sampleRate)) + return false; + if (!decoder.decode(map.m_sampleSize)) + return false; + + if (!decoder.decode(map.m_aspectRatio)) + return false; + if (!decoder.decode(map.m_frameRate)) + return false; + if (!decoder.decode(map.m_volume)) + return false; + + if (!decoder.decode(map.m_echoCancellation)) + return false; + + if (!decoder.decode(map.m_facingMode)) + return false; + if (!decoder.decode(map.m_deviceId)) + return false; + if (!decoder.decode(map.m_groupId)) + return false; + + return true; + } + +private: + std::optional<IntConstraint> m_width; + std::optional<IntConstraint> m_height; + std::optional<IntConstraint> m_sampleRate; + std::optional<IntConstraint> m_sampleSize; + + std::optional<DoubleConstraint> m_aspectRatio; + std::optional<DoubleConstraint> m_frameRate; + std::optional<DoubleConstraint> m_volume; + + std::optional<BooleanConstraint> m_echoCancellation; + + std::optional<StringConstraint> m_facingMode; + std::optional<StringConstraint> m_deviceId; + std::optional<StringConstraint> m_groupId; +}; + +class FlattenedConstraint { +public: + + void set(const MediaConstraint&); + void merge(const MediaConstraint&); + void append(const MediaConstraint&); + const MediaConstraint* find(MediaConstraintType) const; + bool isEmpty() const { return m_variants.isEmpty(); } + + class iterator { + public: + iterator(const FlattenedConstraint* constraint, size_t index) + : m_constraint(constraint) + , m_index(index) +#ifndef NDEBUG + , m_generation(constraint->m_generation) +#endif + { + } + + MediaConstraint& operator*() const + { + return m_constraint->m_variants.at(m_index).constraint(); + } + + iterator& operator++() + { +#ifndef NDEBUG + ASSERT(m_generation == m_constraint->m_generation); +#endif + m_index++; + return *this; + } + + bool operator==(const iterator& other) const { return m_index == other.m_index; } + bool operator!=(const iterator& other) const { return !(*this == other); } + + private: + const FlattenedConstraint* m_constraint { nullptr }; + size_t m_index { 0 }; +#ifndef NDEBUG + int m_generation { 0 }; +#endif + }; + + const iterator begin() const { return iterator(this, 0); } + const iterator end() const { return iterator(this, m_variants.size()); } + +private: + class ConstraintHolder { + public: + static ConstraintHolder create(const MediaConstraint& value) { return ConstraintHolder(value); } + + ~ConstraintHolder() + { + if (m_value.asRaw) { + switch (dataType()) { + case MediaConstraint::DataType::Integer: + delete m_value.asInteger; + break; + case MediaConstraint::DataType::Double: + delete m_value.asDouble; + break; + case MediaConstraint::DataType::Boolean: + delete m_value.asBoolean; + break; + case MediaConstraint::DataType::String: + delete m_value.asString; + break; + case MediaConstraint::DataType::None: + ASSERT_NOT_REACHED(); + break; + } + } +#ifndef NDEBUG + m_value.asRaw = reinterpret_cast<MediaConstraint*>(0xbbadbeef); +#endif + } + + ConstraintHolder(ConstraintHolder&& other) + { + switch (other.dataType()) { + case MediaConstraint::DataType::Integer: + m_value.asInteger = std::exchange(other.m_value.asInteger, nullptr); + break; + case MediaConstraint::DataType::Double: + m_value.asDouble = std::exchange(other.m_value.asDouble, nullptr); + break; + case MediaConstraint::DataType::Boolean: + m_value.asBoolean = std::exchange(other.m_value.asBoolean, nullptr); + break; + case MediaConstraint::DataType::String: + m_value.asString = std::exchange(other.m_value.asString, nullptr); + break; + case MediaConstraint::DataType::None: + ASSERT_NOT_REACHED(); + break; + } + } + + MediaConstraint& constraint() const { return *m_value.asRaw; } + MediaConstraint::DataType dataType() const { return constraint().dataType(); } + MediaConstraintType constraintType() const { return constraint().constraintType(); } + + private: + explicit ConstraintHolder(const MediaConstraint& value) + { + switch (value.dataType()) { + case MediaConstraint::DataType::Integer: + m_value.asInteger = new IntConstraint(downcast<const IntConstraint>(value)); + break; + case MediaConstraint::DataType::Double: + m_value.asDouble = new DoubleConstraint(downcast<DoubleConstraint>(value)); + break; + case MediaConstraint::DataType::Boolean: + m_value.asBoolean = new BooleanConstraint(downcast<BooleanConstraint>(value)); + break; + case MediaConstraint::DataType::String: + m_value.asString = new StringConstraint(downcast<StringConstraint>(value)); + break; + case MediaConstraint::DataType::None: + ASSERT_NOT_REACHED(); + break; + } + } + + union { + MediaConstraint* asRaw; + IntConstraint* asInteger; + DoubleConstraint* asDouble; + BooleanConstraint* asBoolean; + StringConstraint* asString; + } m_value; + }; + + Vector<ConstraintHolder> m_variants; +#ifndef NDEBUG + int m_generation { 0 }; +#endif }; class MediaConstraints : public RefCounted<MediaConstraints> { public: virtual ~MediaConstraints() { } - virtual void getMandatoryConstraints(Vector<MediaConstraint>&) const = 0; - virtual void getOptionalConstraints(Vector<MediaConstraint>&) const = 0; - - virtual bool getMandatoryConstraintValue(const String& name, String& value) const = 0; - virtual bool getOptionalConstraintValue(const String& name, String& value) const = 0; + virtual const MediaTrackConstraintSetMap& mandatoryConstraints() const = 0; + virtual const Vector<MediaTrackConstraintSetMap>& advancedConstraints() const = 0; + virtual bool isValid() const = 0; protected: MediaConstraints() { } @@ -65,6 +817,14 @@ protected: } // namespace WebCore -#endif // ENABLE(MEDIA_STREAM) +#define SPECIALIZE_TYPE_TRAITS_MEDIACONSTRAINT(ConstraintType, predicate) \ +SPECIALIZE_TYPE_TRAITS_BEGIN(WebCore::ConstraintType) \ +static bool isType(const WebCore::MediaConstraint& constraint) { return constraint.predicate; } \ +SPECIALIZE_TYPE_TRAITS_END() + +SPECIALIZE_TYPE_TRAITS_MEDIACONSTRAINT(IntConstraint, isInt()) +SPECIALIZE_TYPE_TRAITS_MEDIACONSTRAINT(DoubleConstraint, isDouble()) +SPECIALIZE_TYPE_TRAITS_MEDIACONSTRAINT(StringConstraint, isString()) +SPECIALIZE_TYPE_TRAITS_MEDIACONSTRAINT(BooleanConstraint, isBoolean()) -#endif // MediaConstraints_h +#endif // ENABLE(MEDIA_STREAM) diff --git a/Source/WebCore/platform/mediastream/MediaEndpoint.cpp b/Source/WebCore/platform/mediastream/MediaEndpoint.cpp new file mode 100644 index 000000000..02dfddb62 --- /dev/null +++ b/Source/WebCore/platform/mediastream/MediaEndpoint.cpp @@ -0,0 +1,86 @@ +/* + * 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(WEB_RTC) +#include "MediaEndpoint.h" + +#include "MediaPayload.h" +#include "RTCDataChannelHandler.h" +#include "RealtimeMediaSource.h" + +namespace WebCore { + +class EmptyRealtimeMediaSource final : public RealtimeMediaSource { +public: + static Ref<EmptyRealtimeMediaSource> create() { return adoptRef(*new EmptyRealtimeMediaSource()); } + +private: + EmptyRealtimeMediaSource() : RealtimeMediaSource(emptyString(), RealtimeMediaSource::None, emptyString()) { } + + RefPtr<RealtimeMediaSourceCapabilities> capabilities() const final { return nullptr; } + const RealtimeMediaSourceSettings& settings() const final { return m_sourceSettings; } + + RealtimeMediaSourceSettings m_sourceSettings; +}; + +class EmptyMediaEndpoint final : public MediaEndpoint { +private: + void setConfiguration(MediaEndpointConfiguration&&) final { } + + void generateDtlsInfo() final { } + MediaPayloadVector getDefaultAudioPayloads() final { return MediaPayloadVector(); } + MediaPayloadVector getDefaultVideoPayloads() final { return MediaPayloadVector(); } + MediaPayloadVector filterPayloads(const MediaPayloadVector&, const MediaPayloadVector&) final { return MediaPayloadVector(); } + + UpdateResult updateReceiveConfiguration(MediaEndpointSessionConfiguration*, bool) final { return UpdateResult::Failed; } + UpdateResult updateSendConfiguration(MediaEndpointSessionConfiguration*, const RealtimeMediaSourceMap&, bool) final { return UpdateResult::Failed; } + + void addRemoteCandidate(const IceCandidate&, const String&, const String&, const String&) final { } + + Ref<RealtimeMediaSource> createMutedRemoteSource(const String&, RealtimeMediaSource::Type) final { return EmptyRealtimeMediaSource::create(); } + void replaceSendSource(RealtimeMediaSource&, const String&) final { } + void replaceMutedRemoteSourceMid(const String&, const String&) final { }; + + std::unique_ptr<RTCDataChannelHandler> createDataChannelHandler(const String&, const RTCDataChannelInit&) final { return nullptr; } + void stop() final { } +}; + +static std::unique_ptr<MediaEndpoint> createMediaEndpoint(MediaEndpointClient&) +{ + return std::make_unique<EmptyMediaEndpoint>(); +} + +CreateMediaEndpoint MediaEndpoint::create = createMediaEndpoint; + +} // namespace WebCore + +#endif // ENABLE(WEB_RTC) diff --git a/Source/WebCore/platform/mediastream/MediaEndpoint.h b/Source/WebCore/platform/mediastream/MediaEndpoint.h new file mode 100644 index 000000000..94bbe1036 --- /dev/null +++ b/Source/WebCore/platform/mediastream/MediaEndpoint.h @@ -0,0 +1,108 @@ +/* + * 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. + */ + +#pragma once + +#if ENABLE(WEB_RTC) + +#include "MediaEndpointConfiguration.h" +#include "PeerConnectionBackend.h" +#include "RealtimeMediaSource.h" +#include <wtf/HashMap.h> +#include <wtf/text/WTFString.h> + +namespace WebCore { + +class MediaEndpoint; +class MediaEndpointClient; +class MediaEndpointSessionConfiguration; +class MediaStreamTrack; +class RTCDataChannelHandler; +class RealtimeMediaSource; + +struct IceCandidate; +struct MediaPayload; +struct RTCDataChannelInit; + +typedef std::unique_ptr<MediaEndpoint> (*CreateMediaEndpoint)(MediaEndpointClient&); +typedef Vector<MediaPayload> MediaPayloadVector; +typedef HashMap<String, RealtimeMediaSource*> RealtimeMediaSourceMap; + +class MediaEndpoint { +public: + WEBCORE_EXPORT static CreateMediaEndpoint create; + virtual ~MediaEndpoint() { } + + enum class UpdateResult { + Success, + SuccessWithIceRestart, + Failed + }; + + using IceTransportState = PeerConnectionStates::IceTransportState; + + virtual void setConfiguration(MediaEndpointConfiguration&&) = 0; + + virtual void generateDtlsInfo() = 0; + virtual MediaPayloadVector getDefaultAudioPayloads() = 0; + virtual MediaPayloadVector getDefaultVideoPayloads() = 0; + virtual MediaPayloadVector filterPayloads(const MediaPayloadVector& remotePayloads, const MediaPayloadVector& defaultPayloads) = 0; + + virtual UpdateResult updateReceiveConfiguration(MediaEndpointSessionConfiguration*, bool isInitiator) = 0; + virtual UpdateResult updateSendConfiguration(MediaEndpointSessionConfiguration*, const RealtimeMediaSourceMap&, bool isInitiator) = 0; + + virtual void addRemoteCandidate(const IceCandidate&, const String& mid, const String& ufrag, const String& password) = 0; + + virtual Ref<RealtimeMediaSource> createMutedRemoteSource(const String& mid, RealtimeMediaSource::Type) = 0; + virtual void replaceSendSource(RealtimeMediaSource&, const String& mid) = 0; + virtual void replaceMutedRemoteSourceMid(const String& oldMid, const String& newMid) = 0; + + virtual std::unique_ptr<RTCDataChannelHandler> createDataChannelHandler(const String&, const RTCDataChannelInit&) = 0; + + virtual void stop() = 0; + + virtual void emulatePlatformEvent(const String&) { }; + + virtual void getStats(MediaStreamTrack*, PeerConnection::StatsPromise&& promise) { promise.reject(NOT_SUPPORTED_ERR); } +}; + +class MediaEndpointClient { +public: + virtual void gotDtlsFingerprint(const String& fingerprint, const String& fingerprintFunction) = 0; + virtual void gotIceCandidate(const String& mid, IceCandidate&&) = 0; + virtual void doneGatheringCandidates(const String& mid) = 0; + virtual void iceTransportStateChanged(const String& mid, MediaEndpoint::IceTransportState) = 0; + + virtual ~MediaEndpointClient() { } +}; + +} // namespace WebCore + +#endif // ENABLE(WEB_RTC) diff --git a/Source/WebCore/platform/mediastream/MediaEndpointConfiguration.cpp b/Source/WebCore/platform/mediastream/MediaEndpointConfiguration.cpp new file mode 100644 index 000000000..c2da344aa --- /dev/null +++ b/Source/WebCore/platform/mediastream/MediaEndpointConfiguration.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 "MediaEndpointConfiguration.h" + +#if ENABLE(WEB_RTC) + +namespace WebCore { + +MediaEndpointConfiguration::MediaEndpointConfiguration(Vector<IceServerInfo>&& iceServers, IceTransportPolicy iceTransportPolicy, BundlePolicy bundlePolicy) + : iceServers(WTFMove(iceServers)) + , iceTransportPolicy(iceTransportPolicy) + , bundlePolicy(bundlePolicy) +{ +} + +MediaEndpointConfiguration::IceServerInfo::IceServerInfo(Vector<URL>&& urls, const String& credential, const String& username) + : urls(WTFMove(urls)) + , credential(credential) + , username(username) +{ +} + +} // namespace WebCore + +#endif // ENABLE(WEB_RTC) diff --git a/Source/WebCore/platform/mediastream/gstreamer/MediaStreamCenterGStreamer.h b/Source/WebCore/platform/mediastream/MediaEndpointConfiguration.h index a70e0019e..5b74a26a3 100644 --- a/Source/WebCore/platform/mediastream/gstreamer/MediaStreamCenterGStreamer.h +++ b/Source/WebCore/platform/mediastream/MediaEndpointConfiguration.h @@ -1,6 +1,5 @@ /* - * Copyright (C) 2011 Ericsson AB. All rights reserved. - * Copyright (C) 2012 Google 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 @@ -29,34 +28,37 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef MediaStreamCenterGStreamer_h -#define MediaStreamCenterGStreamer_h +#pragma once -#if ENABLE(MEDIA_STREAM) +#if ENABLE(WEB_RTC) -#include "MediaStreamCenter.h" - -#include <wtf/PassRefPtr.h> +#include "PeerConnectionStates.h" +#include "URL.h" +#include <wtf/Vector.h> #include <wtf/text/WTFString.h> namespace WebCore { -class MediaStreamPrivate; -class MediaStreamSource; -class MediaStreamSourcesQueryClient; +struct MediaEndpointConfiguration { + // FIXME: We might be able to remove these constructors once all compilers can handle without it (see https://bugs.webkit.org/show_bug.cgi?id=163255#c15) + struct IceServerInfo { + Vector<URL> urls; + String credential; + String username; + + IceServerInfo(Vector<URL>&&, const String&, const String&); + }; -class MediaStreamCenterGStreamer : public MediaStreamCenter { -public: - MediaStreamCenterGStreamer(); - ~MediaStreamCenterGStreamer(); + using IceTransportPolicy = PeerConnectionStates::IceTransportPolicy; + using BundlePolicy = PeerConnectionStates::BundlePolicy; - virtual void validateRequestConstraints(PassRefPtr<MediaStreamCreationClient>, PassRefPtr<MediaConstraints> audioConstraints, PassRefPtr<MediaConstraints> videoConstraints); - virtual void createMediaStream(PassRefPtr<MediaStreamCreationClient>, PassRefPtr<MediaConstraints> audioConstraints, PassRefPtr<MediaConstraints> videoConstraints); - virtual bool getMediaStreamTrackSources(PassRefPtr<MediaStreamTrackSourcesRequestClient>) override; + MediaEndpointConfiguration(Vector<IceServerInfo>&&, IceTransportPolicy, BundlePolicy); + + Vector<IceServerInfo> iceServers; + IceTransportPolicy iceTransportPolicy; + BundlePolicy bundlePolicy; }; } // namespace WebCore -#endif // ENABLE(MEDIA_STREAM) - -#endif // MediaStreamCenterGStreamer_h +#endif // ENABLE(WEB_RTC) diff --git a/Source/WebCore/platform/mediastream/MediaEndpointSessionConfiguration.h b/Source/WebCore/platform/mediastream/MediaEndpointSessionConfiguration.h new file mode 100644 index 000000000..293cc82ee --- /dev/null +++ b/Source/WebCore/platform/mediastream/MediaEndpointSessionConfiguration.h @@ -0,0 +1,86 @@ +/* + * 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 MediaEndpointSessionConfiguration_h +#define MediaEndpointSessionConfiguration_h + +#if ENABLE(WEB_RTC) + +#include "PeerMediaDescription.h" +#include <wtf/CryptographicallyRandomNumber.h> + +namespace WebCore { + +class MediaEndpointSessionConfiguration : public RefCounted<MediaEndpointSessionConfiguration> { +public: + static RefPtr<MediaEndpointSessionConfiguration> create() + { + return adoptRef(new MediaEndpointSessionConfiguration()); + } + virtual ~MediaEndpointSessionConfiguration() { } + + 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; } + + Vector<PeerMediaDescription>& mediaDescriptions() { return m_mediaDescriptions; } + const Vector<PeerMediaDescription>& mediaDescriptions() const { return m_mediaDescriptions; } + void addMediaDescription(PeerMediaDescription&& description) { m_mediaDescriptions.append(WTFMove(description)); } + + RefPtr<MediaEndpointSessionConfiguration> clone() const + { + RefPtr<MediaEndpointSessionConfiguration> copy = create(); + copy->m_sessionId = m_sessionId; + copy->m_sessionVersion = m_sessionVersion; + copy->m_mediaDescriptions = m_mediaDescriptions; + + return copy; + } + +private: + MediaEndpointSessionConfiguration() + { + m_sessionId = cryptographicallyRandomNumber(); + m_sessionId = m_sessionId << 32 | cryptographicallyRandomNumber(); + } + + uint64_t m_sessionId; + unsigned m_sessionVersion { 0 }; + + Vector<PeerMediaDescription> m_mediaDescriptions; +}; + +} // namespace WebCore + +#endif // ENABLE(WEB_RTC) + +#endif // MediaEndpointSessionConfiguration_h diff --git a/Source/WebCore/platform/mediastream/MediaPayload.h b/Source/WebCore/platform/mediastream/MediaPayload.h new file mode 100644 index 000000000..1229e108e --- /dev/null +++ b/Source/WebCore/platform/mediastream/MediaPayload.h @@ -0,0 +1,61 @@ +/* + * 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. + */ + +#pragma once + +#if ENABLE(WEB_RTC) + +#include <wtf/HashMap.h> +#include <wtf/text/StringHash.h> + +namespace WebCore { + +struct MediaPayload { +public: + void addParameter(const String& name, unsigned value) { parameters.set(name, value); } + + unsigned type { 0 }; + String encodingName; + unsigned clockRate { 0 }; + + // audio + unsigned channels { 0 }; + + // video + bool ccmfir { false }; + bool nackpli { false }; + bool nack { false }; + + HashMap<String, unsigned> parameters; +}; + +} // namespace WebCore + +#endif // ENABLE(WEB_RTC) diff --git a/Source/WebCore/platform/mediastream/MediaStreamConstraintsValidationClient.h b/Source/WebCore/platform/mediastream/MediaStreamConstraintsValidationClient.h index 578705867..973c9eee1 100644 --- a/Source/WebCore/platform/mediastream/MediaStreamConstraintsValidationClient.h +++ b/Source/WebCore/platform/mediastream/MediaStreamConstraintsValidationClient.h @@ -10,10 +10,10 @@ * 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 COMPUTER, INC. ``AS IS'' AND ANY + * 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 COMPUTER, INC. OR + * 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 @@ -28,8 +28,7 @@ #if ENABLE(MEDIA_STREAM) -#include "MediaStreamSource.h" -#include <wtf/PassRefPtr.h> +#include "RealtimeMediaSource.h" #include <wtf/RefCounted.h> namespace WebCore { diff --git a/Source/WebCore/platform/mediastream/MediaStreamPrivate.cpp b/Source/WebCore/platform/mediastream/MediaStreamPrivate.cpp index e7140ad23..21c0769a6 100644 --- a/Source/WebCore/platform/mediastream/MediaStreamPrivate.cpp +++ b/Source/WebCore/platform/mediastream/MediaStreamPrivate.cpp @@ -1,7 +1,8 @@ /* - * Copyright (C) 2011 Ericsson AB. All rights reserved. + * Copyright (C) 2011, 2015 Ericsson AB. All rights reserved. * Copyright (C) 2013 Google Inc. All rights reserved. * Copyright (C) 2013 Nokia Corporation and/or its subsidiary(-ies). + * Copyright (C) 2015 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 @@ -31,174 +32,292 @@ */ #include "config.h" +#include "MediaStreamPrivate.h" #if ENABLE(MEDIA_STREAM) -#include "MediaStreamPrivate.h" - -#include "MediaStreamCenter.h" +#include "GraphicsContext.h" +#include "IntRect.h" #include "UUID.h" +#include <wtf/MainThread.h> #include <wtf/RefCounted.h> #include <wtf/Vector.h> namespace WebCore { -PassRefPtr<MediaStreamPrivate> MediaStreamPrivate::create(const Vector<RefPtr<MediaStreamSource>>& audioSources, const Vector<RefPtr<MediaStreamSource>>& videoSources) +Ref<MediaStreamPrivate> MediaStreamPrivate::create(const Vector<Ref<RealtimeMediaSource>>& audioSources, const Vector<Ref<RealtimeMediaSource>>& videoSources) { - return adoptRef(new MediaStreamPrivate(createCanonicalUUIDString(), audioSources, videoSources)); + MediaStreamTrackPrivateVector tracks; + tracks.reserveInitialCapacity(audioSources.size() + videoSources.size()); + + for (auto& source : audioSources) + tracks.uncheckedAppend(MediaStreamTrackPrivate::create(source.copyRef())); + + for (auto& source : videoSources) + tracks.uncheckedAppend(MediaStreamTrackPrivate::create(source.copyRef())); + + return MediaStreamPrivate::create(tracks); } -PassRefPtr<MediaStreamPrivate> MediaStreamPrivate::create(const Vector<RefPtr<MediaStreamTrackPrivate>>& audioPrivateTracks, const Vector<RefPtr<MediaStreamTrackPrivate>>& videoPrivateTracks) +Ref<MediaStreamPrivate> MediaStreamPrivate::create(const MediaStreamTrackPrivateVector& tracks) { - return adoptRef(new MediaStreamPrivate(createCanonicalUUIDString(), audioPrivateTracks, videoPrivateTracks)); + return adoptRef(*new MediaStreamPrivate(createCanonicalUUIDString(), tracks)); } -void MediaStreamPrivate::addSource(PassRefPtr<MediaStreamSource> prpSource) +MediaStreamPrivate::MediaStreamPrivate(const String& id, const MediaStreamTrackPrivateVector& tracks) + : m_weakPtrFactory(this) + , m_id(id) { - RefPtr<MediaStreamSource> source = prpSource; - switch (source->type()) { - case MediaStreamSource::Audio: - if (m_audioStreamSources.find(source) == notFound) - m_audioStreamSources.append(source); - break; - case MediaStreamSource::Video: - if (m_videoStreamSources.find(source) == notFound) - m_videoStreamSources.append(source); - break; - case MediaStreamSource::None: - ASSERT_NOT_REACHED(); - break; + ASSERT(!m_id.isEmpty()); + + for (auto& track : tracks) { + track->addObserver(*this); + m_trackSet.add(track->id(), track); } + + updateActiveState(NotifyClientOption::DontNotify); } -void MediaStreamPrivate::removeSource(PassRefPtr<MediaStreamSource> source) +MediaStreamPrivate::~MediaStreamPrivate() { - size_t pos = notFound; - switch (source->type()) { - case MediaStreamSource::Audio: - pos = m_audioStreamSources.find(source); - if (pos == notFound) - return; - m_audioStreamSources.remove(pos); - break; - case MediaStreamSource::Video: - pos = m_videoStreamSources.find(source); - if (pos == notFound) - return; - m_videoStreamSources.remove(pos); - break; - case MediaStreamSource::None: - ASSERT_NOT_REACHED(); - break; + for (auto& track : m_trackSet.values()) + track->removeObserver(*this); +} + +void MediaStreamPrivate::addObserver(MediaStreamPrivate::Observer& observer) +{ + m_observers.append(&observer); +} + +void MediaStreamPrivate::removeObserver(MediaStreamPrivate::Observer& observer) +{ + size_t pos = m_observers.find(&observer); + if (pos != notFound) + m_observers.remove(pos); +} + +MediaStreamTrackPrivateVector MediaStreamPrivate::tracks() const +{ + MediaStreamTrackPrivateVector tracks; + tracks.reserveCapacity(m_trackSet.size()); + copyValuesToVector(m_trackSet, tracks); + + return tracks; +} + +void MediaStreamPrivate::updateActiveState(NotifyClientOption notifyClientOption) +{ + bool newActiveState = false; + for (auto& track : m_trackSet.values()) { + if (!track->ended()) { + newActiveState = true; + break; + } + } + + updateActiveVideoTrack(); + + // A stream is active if it has at least one un-ended track. + if (newActiveState == m_isActive) + return; + + m_isActive = newActiveState; + + if (notifyClientOption == NotifyClientOption::Notify) { + for (auto& observer : m_observers) + observer->activeStatusChanged(); } } -void MediaStreamPrivate::addRemoteSource(MediaStreamSource* source) +void MediaStreamPrivate::addTrack(RefPtr<MediaStreamTrackPrivate>&& track, NotifyClientOption notifyClientOption) { - if (m_client) - m_client->addRemoteSource(source); - else - addSource(source); + if (m_trackSet.contains(track->id())) + return; + + track->addObserver(*this); + m_trackSet.add(track->id(), track); + + if (notifyClientOption == NotifyClientOption::Notify) { + for (auto& observer : m_observers) + observer->didAddTrack(*track.get()); + } + + updateActiveState(notifyClientOption); } -void MediaStreamPrivate::removeRemoteSource(MediaStreamSource* source) +void MediaStreamPrivate::removeTrack(MediaStreamTrackPrivate& track, NotifyClientOption notifyClientOption) { - if (m_client) - m_client->removeRemoteSource(source); - else - removeSource(source); + if (!m_trackSet.remove(track.id())) + return; + + track.removeObserver(*this); + + if (notifyClientOption == NotifyClientOption::Notify) { + for (auto& observer : m_observers) + observer->didRemoveTrack(track); + } + + updateActiveState(NotifyClientOption::Notify); } -void MediaStreamPrivate::addRemoteTrack(MediaStreamTrackPrivate* track) +void MediaStreamPrivate::startProducingData() { - if (m_client) - m_client->addRemoteTrack(track); - else - addTrack(track); + for (auto& track : m_trackSet.values()) + track->startProducingData(); } -void MediaStreamPrivate::removeRemoteTrack(MediaStreamTrackPrivate* track) +void MediaStreamPrivate::stopProducingData() { - if (m_client) - m_client->removeRemoteTrack(track); - else - removeTrack(track); + for (auto& track : m_trackSet.values()) + track->stopProducingData(); } -MediaStreamPrivate::MediaStreamPrivate(const String& id, const Vector<RefPtr<MediaStreamSource>>& audioSources, const Vector<RefPtr<MediaStreamSource>>& videoSources) - : m_client(0) - , m_id(id) - , m_ended(false) +bool MediaStreamPrivate::isProducingData() const { - ASSERT(m_id.length()); - for (size_t i = 0; i < audioSources.size(); i++) - addTrack(MediaStreamTrackPrivate::create(audioSources[i])); + for (auto& track : m_trackSet.values()) { + if (track->isProducingData()) + return true; + } + return false; +} - for (size_t i = 0; i < videoSources.size(); i++) - addTrack(MediaStreamTrackPrivate::create(videoSources[i])); +bool MediaStreamPrivate::hasVideo() const +{ + for (auto& track : m_trackSet.values()) { + if (track->type() == RealtimeMediaSource::Type::Video && track->enabled() && !track->ended()) + return true; + } + return false; +} - unsigned providedSourcesSize = audioSources.size() + videoSources.size(); - unsigned tracksSize = m_audioPrivateTracks.size() + m_videoPrivateTracks.size(); - // If sources were provided and no track was added to the MediaStreamPrivate's tracks, this means - // that the tracks were all ended - if (providedSourcesSize > 0 && !tracksSize) - m_ended = true; +bool MediaStreamPrivate::hasAudio() const +{ + for (auto& track : m_trackSet.values()) { + if (track->type() == RealtimeMediaSource::Type::Audio && track->enabled() && !track->ended()) + return true; + } + return false; } -MediaStreamPrivate::MediaStreamPrivate(const String& id, const Vector<RefPtr<MediaStreamTrackPrivate>>& audioPrivateTracks, const Vector<RefPtr<MediaStreamTrackPrivate>>& videoPrivateTracks) - : m_client(0) - , m_id(id) - , m_ended(false) +bool MediaStreamPrivate::hasLocalVideoSource() const { - ASSERT(m_id.length()); - for (size_t i = 0; i < audioPrivateTracks.size(); i++) - addTrack(audioPrivateTracks[i]); + for (auto& track : m_trackSet.values()) { + if (track->type() == RealtimeMediaSource::Type::Video && !track->remote()) + return true; + } + return false; +} - for (size_t i = 0; i < videoPrivateTracks.size(); i++) - addTrack(videoPrivateTracks[i]); +bool MediaStreamPrivate::hasLocalAudioSource() const +{ + for (auto& track : m_trackSet.values()) { + if (track->type() == RealtimeMediaSource::Type::Audio && !track->remote()) + return true; + } + return false; +} - unsigned providedTracksSize = audioPrivateTracks.size() + videoPrivateTracks.size(); - unsigned tracksSize = m_audioPrivateTracks.size() + m_videoPrivateTracks.size(); - // If tracks were provided and no one was added to the MediaStreamPrivate's tracks, this means - // that the tracks were all ended - if (providedTracksSize > 0 && !tracksSize) - m_ended = true; +bool MediaStreamPrivate::muted() const +{ + for (auto& track : m_trackSet.values()) { + if (!track->muted()) + return false; + } + return true; } -void MediaStreamPrivate::setEnded() +FloatSize MediaStreamPrivate::intrinsicSize() const { - if (m_client) - m_client->streamDidEnd(); + FloatSize size; + + if (m_activeVideoTrack) { + const RealtimeMediaSourceSettings& setting = m_activeVideoTrack->settings(); + size.setWidth(setting.width()); + size.setHeight(setting.height()); + } - m_ended = true; + return size; } -void MediaStreamPrivate::addTrack(PassRefPtr<MediaStreamTrackPrivate> prpTrack) +void MediaStreamPrivate::paintCurrentFrameInContext(GraphicsContext& context, const FloatRect& rect) { - RefPtr<MediaStreamTrackPrivate> track = prpTrack; - if (track->ended()) + if (context.paintingDisabled()) return; - Vector<RefPtr<MediaStreamTrackPrivate>>& tracks = track->type() == MediaStreamSource::Audio ? m_audioPrivateTracks : m_videoPrivateTracks; + if (active() && m_activeVideoTrack) + m_activeVideoTrack->paintCurrentFrameInContext(context, rect); + else { + GraphicsContextStateSaver stateSaver(context); + context.translate(rect.x(), rect.y() + rect.height()); + context.scale(FloatSize(1, -1)); + IntRect paintRect(IntPoint(0, 0), IntSize(rect.width(), rect.height())); + context.fillRect(paintRect, Color::black); + } +} - size_t pos = tracks.find(track); - if (pos != notFound) - return; +RefPtr<Image> MediaStreamPrivate::currentFrameImage() +{ + if (!active() || !m_activeVideoTrack) + return nullptr; - tracks.append(track); - if (track->source()) - addSource(track->source()); + return m_activeVideoTrack->source().currentFrameImage(); } -void MediaStreamPrivate::removeTrack(PassRefPtr<MediaStreamTrackPrivate> track) +void MediaStreamPrivate::updateActiveVideoTrack() { - Vector<RefPtr<MediaStreamTrackPrivate>>& tracks = track->type() == MediaStreamSource::Audio ? m_audioPrivateTracks : m_videoPrivateTracks; + m_activeVideoTrack = nullptr; + for (auto& track : m_trackSet.values()) { + if (!track->ended() && track->type() == RealtimeMediaSource::Type::Video) { + m_activeVideoTrack = track.get(); + break; + } + } +} - size_t pos = tracks.find(track); - if (pos == notFound) - return; +void MediaStreamPrivate::characteristicsChanged() +{ + for (auto& observer : m_observers) + observer->characteristicsChanged(); +} + +void MediaStreamPrivate::trackMutedChanged(MediaStreamTrackPrivate&) +{ + scheduleDeferredTask([this] { + characteristicsChanged(); + }); +} + +void MediaStreamPrivate::trackSettingsChanged(MediaStreamTrackPrivate&) +{ + characteristicsChanged(); +} + +void MediaStreamPrivate::trackEnabledChanged(MediaStreamTrackPrivate&) +{ + updateActiveVideoTrack(); + + scheduleDeferredTask([this] { + characteristicsChanged(); + }); +} + +void MediaStreamPrivate::trackEnded(MediaStreamTrackPrivate&) +{ + scheduleDeferredTask([this] { + updateActiveState(NotifyClientOption::Notify); + characteristicsChanged(); + }); +} + +void MediaStreamPrivate::scheduleDeferredTask(Function<void ()>&& function) +{ + ASSERT(function); + callOnMainThread([weakThis = createWeakPtr(), function = WTFMove(function)] { + if (!weakThis) + return; - tracks.remove(pos); + function(); + }); } } // namespace WebCore diff --git a/Source/WebCore/platform/mediastream/MediaStreamPrivate.h b/Source/WebCore/platform/mediastream/MediaStreamPrivate.h index f1617aa4c..a4596ff59 100644 --- a/Source/WebCore/platform/mediastream/MediaStreamPrivate.h +++ b/Source/WebCore/platform/mediastream/MediaStreamPrivate.h @@ -1,7 +1,8 @@ /* - * Copyright (C) 2011 Ericsson AB. All rights reserved. + * Copyright (C) 2011, 2015 Ericsson AB. All rights reserved. * Copyright (C) 2012 Google Inc. All rights reserved. * Copyright (C) 2013 Nokia Corporation and/or its subsidiary(-ies). + * Copyright (C) 2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -35,78 +36,107 @@ #if ENABLE(MEDIA_STREAM) -#include "MediaStreamSource.h" +#include "FloatSize.h" #include "MediaStreamTrack.h" #include "MediaStreamTrackPrivate.h" +#include <wtf/Function.h> +#include <wtf/HashMap.h> +#include <wtf/MediaTime.h> #include <wtf/RefCounted.h> +#include <wtf/RefPtr.h> #include <wtf/Vector.h> +#include <wtf/WeakPtr.h> + +#if USE(GSTREAMER) +#include "GRefPtrGStreamer.h" +#include <owr/owr_gst_video_renderer.h> +#endif namespace WebCore { -class MediaStreamTrackPrivate; +class MediaStream; -class MediaStreamPrivateClient : public MediaStreamTrack::Observer { +class MediaStreamPrivate : public MediaStreamTrackPrivate::Observer, public RefCounted<MediaStreamPrivate> { public: - virtual ~MediaStreamPrivateClient() { } + class Observer { + public: + virtual ~Observer() { } - virtual void streamDidEnd() = 0; - virtual void addRemoteSource(MediaStreamSource*) = 0; - virtual void removeRemoteSource(MediaStreamSource*) = 0; - virtual void addRemoteTrack(MediaStreamTrackPrivate*) = 0; - virtual void removeRemoteTrack(MediaStreamTrackPrivate*) = 0; -}; + virtual void characteristicsChanged() { } + virtual void activeStatusChanged() { } + virtual void didAddTrack(MediaStreamTrackPrivate&) { } + virtual void didRemoveTrack(MediaStreamTrackPrivate&) { } + }; -class MediaStreamPrivate : public RefCounted<MediaStreamPrivate> { -public: - static PassRefPtr<MediaStreamPrivate> create(const Vector<RefPtr<MediaStreamSource>>& audioSources, const Vector<RefPtr<MediaStreamSource>>& videoSources); - static PassRefPtr<MediaStreamPrivate> create(const Vector<RefPtr<MediaStreamTrackPrivate>>& audioPrivateTracks, const Vector<RefPtr<MediaStreamTrackPrivate>>& videoPrivateTracks); + static Ref<MediaStreamPrivate> create(const Vector<Ref<RealtimeMediaSource>>& audioSources, const Vector<Ref<RealtimeMediaSource>>& videoSources); + static Ref<MediaStreamPrivate> create(const MediaStreamTrackPrivateVector&); - virtual ~MediaStreamPrivate() { } + virtual ~MediaStreamPrivate(); - MediaStreamPrivateClient* client() const { return m_client; } - void setClient(MediaStreamPrivateClient* client) { m_client = client; } + enum class NotifyClientOption { Notify, DontNotify }; + + void addObserver(Observer&); + void removeObserver(Observer&); String id() const { return m_id; } - unsigned numberOfAudioSources() const { return m_audioStreamSources.size(); } - MediaStreamSource* audioSources(unsigned index) const { return m_audioStreamSources[index].get(); } + MediaStreamTrackPrivateVector tracks() const; + MediaStreamTrackPrivate* activeVideoTrack() { return m_activeVideoTrack; } + + bool active() const { return m_isActive; } + void updateActiveState(NotifyClientOption); - unsigned numberOfVideoSources() const { return m_videoStreamSources.size(); } - MediaStreamSource* videoSources(unsigned index) const { return m_videoStreamSources[index].get(); } + void addTrack(RefPtr<MediaStreamTrackPrivate>&&, NotifyClientOption = NotifyClientOption::Notify); + void removeTrack(MediaStreamTrackPrivate&, NotifyClientOption = NotifyClientOption::Notify); - unsigned numberOfAudioTracks() const { return m_audioPrivateTracks.size(); } - MediaStreamTrackPrivate* audioTracks(unsigned index) const { return m_audioPrivateTracks[index].get(); } + void startProducingData(); + void stopProducingData(); + bool isProducingData() const; - unsigned numberOfVideoTracks() const { return m_videoPrivateTracks.size(); } - MediaStreamTrackPrivate* videoTracks(unsigned index) const { return m_videoPrivateTracks[index].get(); } + RefPtr<Image> currentFrameImage(); + void paintCurrentFrameInContext(GraphicsContext&, const FloatRect&); - void addSource(PassRefPtr<MediaStreamSource>); - void removeSource(PassRefPtr<MediaStreamSource>); + bool hasVideo() const; + bool hasAudio() const; + bool muted() const; - void addRemoteSource(MediaStreamSource*); - void removeRemoteSource(MediaStreamSource*); + bool hasLocalVideoSource() const; + bool hasLocalAudioSource() const; - bool ended() const { return m_ended; } - void setEnded(); + FloatSize intrinsicSize() const; - void addTrack(PassRefPtr<MediaStreamTrackPrivate>); - void removeTrack(PassRefPtr<MediaStreamTrackPrivate>); + WeakPtr<MediaStreamPrivate> createWeakPtr() { return m_weakPtrFactory.createWeakPtr(); } - void addRemoteTrack(MediaStreamTrackPrivate*); - void removeRemoteTrack(MediaStreamTrackPrivate*); +#if USE(GSTREAMER) + void setVideoRenderer(OwrGstVideoRenderer* renderer, GstElement* sink) { m_gstVideoRenderer = renderer; m_gstVideoSinkElement = sink; } + GRefPtr<GstElement> getVideoSinkElement() const { return m_gstVideoSinkElement; } + GRefPtr<OwrGstVideoRenderer> getVideoRenderer() const { return m_gstVideoRenderer; } private: - MediaStreamPrivate(const String& id, const Vector<RefPtr<MediaStreamSource>>& audioSources, const Vector<RefPtr<MediaStreamSource>>& videoSources); - MediaStreamPrivate(const String& id, const Vector<RefPtr<MediaStreamTrackPrivate>>& audioPrivateTracks, const Vector<RefPtr<MediaStreamTrackPrivate>>& videoPrivateTracks); + GRefPtr<GstElement> m_gstVideoSinkElement; + GRefPtr<OwrGstVideoRenderer> m_gstVideoRenderer; +#endif - MediaStreamPrivateClient* m_client; - String m_id; - Vector<RefPtr<MediaStreamSource>> m_audioStreamSources; - Vector<RefPtr<MediaStreamSource>> m_videoStreamSources; +private: + MediaStreamPrivate(const String&, const MediaStreamTrackPrivateVector&); + + // MediaStreamTrackPrivate::Observer + void trackEnded(MediaStreamTrackPrivate&) override; + void trackMutedChanged(MediaStreamTrackPrivate&) override; + void trackSettingsChanged(MediaStreamTrackPrivate&) override; + void trackEnabledChanged(MediaStreamTrackPrivate&) override; + + void characteristicsChanged(); + void updateActiveVideoTrack(); - Vector<RefPtr<MediaStreamTrackPrivate>> m_audioPrivateTracks; - Vector<RefPtr<MediaStreamTrackPrivate>> m_videoPrivateTracks; - bool m_ended; + void scheduleDeferredTask(Function<void ()>&&); + + WeakPtrFactory<MediaStreamPrivate> m_weakPtrFactory; + Vector<Observer*> m_observers; + String m_id; + MediaStreamTrackPrivate* m_activeVideoTrack { nullptr }; + HashMap<String, RefPtr<MediaStreamTrackPrivate>> m_trackSet; + bool m_isActive { false }; }; typedef Vector<RefPtr<MediaStreamPrivate>> MediaStreamPrivateVector; diff --git a/Source/WebCore/platform/mediastream/MediaStreamSource.cpp b/Source/WebCore/platform/mediastream/MediaStreamSource.cpp deleted file mode 100644 index ce089e623..000000000 --- a/Source/WebCore/platform/mediastream/MediaStreamSource.cpp +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Copyright (C) 2012 Google Inc. All rights reserved. - * Copyright (C) 2013 Apple Inc. All rights reserved. - * Copyright (C) 2013 Nokia Corporation and/or its subsidiary(-ies). - * - * 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 Google Inc. 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 "MediaStreamSource.h" - -#include "MediaStreamCenter.h" -#include "MediaStreamSourceCapabilities.h" -#include "UUID.h" - -namespace WebCore { - -MediaStreamSource::MediaStreamSource(const String& id, Type type, const String& name) - : m_id(id) - , m_type(type) - , m_name(name) - , m_readyState(New) - , m_enabled(true) - , m_muted(false) - , m_readonly(false) - , m_remote(false) -{ - if (!m_id.isEmpty()) - return; - - m_id = createCanonicalUUIDString(); -} - -void MediaStreamSource::reset() -{ - m_readyState = New; - m_enabled = true; - m_muted = false; - m_readonly = false; - m_remote = false; -} - -void MediaStreamSource::setReadyState(ReadyState readyState) -{ - if (m_readyState == Ended || m_readyState == readyState) - return; - - m_readyState = readyState; - for (auto observer = m_observers.begin(); observer != m_observers.end(); ++observer) - (*observer)->sourceReadyStateChanged(); - - if (m_readyState == Live) { - startProducingData(); - return; - } - - // There are no more consumers of this source's data, shut it down as appropriate. - if (m_readyState == Ended) - stopProducingData(); -} - -void MediaStreamSource::addObserver(MediaStreamSource::Observer* observer) -{ - m_observers.append(observer); -} - -void MediaStreamSource::removeObserver(MediaStreamSource::Observer* observer) -{ - size_t pos = m_observers.find(observer); - if (pos != notFound) - m_observers.remove(pos); - - if (!m_observers.size()) - stop(); -} - -void MediaStreamSource::setMuted(bool muted) -{ - if (m_muted == muted) - return; - - m_muted = muted; - - if (m_readyState == Ended) - return; - - for (auto observer = m_observers.begin(); observer != m_observers.end(); ++observer) - (*observer)->sourceMutedChanged(); -} - -void MediaStreamSource::setEnabled(bool enabled) -{ - if (!enabled) { - // Don't disable the source unless all observers are disabled. - for (auto observer = m_observers.begin(); observer != m_observers.end(); ++observer) { - if ((*observer)->observerIsEnabled()) - return; - } - } - - if (m_enabled == enabled) - return; - - m_enabled = enabled; - - if (m_readyState == Ended) - return; - - if (!enabled) - stopProducingData(); - else - startProducingData(); - - for (auto observer = m_observers.begin(); observer != m_observers.end(); ++observer) - (*observer)->sourceEnabledChanged(); -} - -bool MediaStreamSource::readonly() const -{ - return m_readonly; -} - -void MediaStreamSource::stop() -{ - // This is called from the track.stop() method, which should "Permanently stop the generation of data - // for track's source", so go straight to ended. This will notify any other tracks using this source - // that it is no longer available. - setReadyState(Ended); -} - -} // namespace WebCore - -#endif // ENABLE(MEDIA_STREAM) diff --git a/Source/WebCore/platform/mediastream/MediaStreamSource.h b/Source/WebCore/platform/mediastream/MediaStreamSource.h deleted file mode 100644 index d6655725c..000000000 --- a/Source/WebCore/platform/mediastream/MediaStreamSource.h +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Copyright (C) 2011 Ericsson AB. All rights reserved. - * Copyright (C) 2012 Google Inc. All rights reserved. - * Copyright (C) 2013 Apple Inc. All rights reserved. - * Copyright (C) 2013 Nokia Corporation and/or its subsidiary(-ies). - * - * 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 MediaStreamSource_h -#define MediaStreamSource_h - -#if ENABLE(MEDIA_STREAM) - -#include "MediaConstraints.h" -#include "MediaStreamSourceCapabilities.h" -#include <wtf/RefCounted.h> -#include <wtf/Vector.h> -#include <wtf/text/WTFString.h> - -namespace WebCore { - -class AudioBus; -class MediaConstraints; -class MediaStreamPrivate; -class MediaStreamSourceStates; - -class MediaStreamSource : public RefCounted<MediaStreamSource> { -public: - class Observer { - public: - virtual ~Observer() { } - - // Source state changes. - virtual void sourceReadyStateChanged() = 0; - virtual void sourceMutedChanged() = 0; - virtual void sourceEnabledChanged() = 0; - - // Observer state queries. - virtual bool observerIsEnabled() = 0; - }; - - virtual ~MediaStreamSource() { } - - bool isAudioStreamSource() const { return type() == Audio; } - virtual bool useIDForTrackID() const { return false; } - - const String& id() const { return m_id; } - - enum Type { None, Audio, Video }; - Type type() const { return m_type; } - - virtual const String& name() const { return m_name; } - virtual void setName(const String& name) { m_name = name; } - - virtual RefPtr<MediaStreamSourceCapabilities> capabilities() const = 0; - virtual const MediaStreamSourceStates& states() = 0; - - enum ReadyState { New = 0, Live = 1, Ended = 2 }; - virtual ReadyState readyState() const { return m_readyState; } - virtual void setReadyState(ReadyState); - - virtual bool enabled() const { return m_enabled; } - virtual void setEnabled(bool); - - virtual bool muted() const { return m_muted; } - virtual void setMuted(bool); - - virtual bool readonly() const; - virtual void setReadonly(bool readonly) { m_readonly = readonly; } - - virtual bool remote() const { return m_remote; } - virtual void setRemote(bool remote) { m_remote = remote; } - - void addObserver(Observer*); - void removeObserver(Observer*); - - virtual void startProducingData() { } - virtual void stopProducingData() { } - - void stop(); - - void reset(); - -protected: - MediaStreamSource(const String& id, Type, const String& name); - -private: - String m_id; - Type m_type; - String m_name; - ReadyState m_readyState; - Vector<Observer*> m_observers; - - bool m_enabled; - bool m_muted; - bool m_readonly; - bool m_remote; -}; - -} // namespace WebCore - -#endif // ENABLE(MEDIA_STREAM) - -#endif // MediaStreamSource_h diff --git a/Source/WebCore/platform/mediastream/MediaStreamSourceCapabilities.h b/Source/WebCore/platform/mediastream/MediaStreamSourceCapabilities.h deleted file mode 100644 index 64b0c4f0c..000000000 --- a/Source/WebCore/platform/mediastream/MediaStreamSourceCapabilities.h +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Copyright (C) 2013 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 COMPUTER, 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 COMPUTER, 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 MediaStreamSourceCapabilities_h -#define MediaStreamSourceCapabilities_h - -#if ENABLE(MEDIA_STREAM) - -#include "MediaStreamSourceStates.h" -#include <wtf/RefCounted.h> -#include <wtf/Vector.h> -#include <wtf/text/AtomicString.h> - -namespace WebCore { - -class MediaStreamSourceCapabilityRange { -public: - - MediaStreamSourceCapabilityRange(float min, float max, bool supported = true) - : m_type(Float) - { - m_min.asFloat = min; - m_max.asFloat = max; - m_supported = supported; - } - - MediaStreamSourceCapabilityRange(unsigned long min, unsigned long max, bool supported = true) - : m_type(ULong) - { - m_min.asULong = min; - m_max.asULong = max; - m_supported = supported; - } - - MediaStreamSourceCapabilityRange() - { - m_type = Undefined; - m_min.asULong = 0; - m_max.asULong = 0; - m_supported = false; - } - - enum Type { Undefined, Float, ULong }; - - union ValueUnion { - unsigned long asULong; - float asFloat; - }; - - const ValueUnion& min() const { return m_min; } - const ValueUnion& max() const { return m_max; } - Type type() const { return m_type; } - bool supported() const { return m_supported; } - -private: - ValueUnion m_min; - ValueUnion m_max; - Type m_type; - bool m_supported; -}; - -class MediaStreamSourceCapabilities : public RefCounted<MediaStreamSourceCapabilities> { -public: - static PassRefPtr<MediaStreamSourceCapabilities> create() - { - return adoptRef(new MediaStreamSourceCapabilities()); - } - - ~MediaStreamSourceCapabilities() { } - - const Vector<MediaStreamSourceStates::SourceType>& sourceTypes() { return m_sourceType; } - void setSourceType(MediaStreamSourceStates::SourceType sourceType) { m_sourceType.resizeToFit(1); addSourceType(sourceType); } - void addSourceType(MediaStreamSourceStates::SourceType sourceType) - { - if (sourceType == MediaStreamSourceStates::Camera) - m_videoSource = true; - m_sourceType.append(sourceType); - } - - const Vector<AtomicString>& sourceId() { return m_sourceId; } - void setSourceId(const AtomicString& id) { m_sourceId.reserveCapacity(1); m_sourceId.insert(0, id); } - - const Vector<MediaStreamSourceStates::VideoFacingMode>& facingModes() { return m_facingMode; } - void addFacingMode(MediaStreamSourceStates::VideoFacingMode mode) { m_facingMode.append(mode); } - - const MediaStreamSourceCapabilityRange& width() { return m_width; } - void setWidthRange(const MediaStreamSourceCapabilityRange& width) { m_width = width; } - - const MediaStreamSourceCapabilityRange& height() { return m_height; } - void setHeightRange(const MediaStreamSourceCapabilityRange& height) { m_height = height; } - - const MediaStreamSourceCapabilityRange& frameRate() { return m_frameRate; } - void setFrameRateRange(const MediaStreamSourceCapabilityRange& frameRate) { m_frameRate = frameRate; } - - const MediaStreamSourceCapabilityRange& aspectRatio() { return m_aspectRatio; } - void setAspectRatioRange(const MediaStreamSourceCapabilityRange& aspectRatio) { m_aspectRatio = aspectRatio; } - - const MediaStreamSourceCapabilityRange& volume() { return m_volume; } - void setVolumeRange(const MediaStreamSourceCapabilityRange& volume) { m_volume = volume; } - - bool hasVideoSource() { return m_videoSource; } - void setHasVideoSource(bool isVideo) { m_videoSource = isVideo;; } - -private: - MediaStreamSourceCapabilities() - : m_videoSource(false) - { - } - - Vector<AtomicString> m_sourceId; - Vector<MediaStreamSourceStates::SourceType> m_sourceType; - Vector<MediaStreamSourceStates::VideoFacingMode> m_facingMode; - - MediaStreamSourceCapabilityRange m_width; - MediaStreamSourceCapabilityRange m_height; - MediaStreamSourceCapabilityRange m_frameRate; - MediaStreamSourceCapabilityRange m_aspectRatio; - MediaStreamSourceCapabilityRange m_volume; - - bool m_videoSource; -}; - -} // namespace WebCore - -#endif // MediaStreamSourceCapabilities_h - -#endif diff --git a/Source/WebCore/platform/mediastream/MediaStreamTrackPrivate.cpp b/Source/WebCore/platform/mediastream/MediaStreamTrackPrivate.cpp index 6a86181b8..736c6f4c5 100644 --- a/Source/WebCore/platform/mediastream/MediaStreamTrackPrivate.cpp +++ b/Source/WebCore/platform/mediastream/MediaStreamTrackPrivate.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 @@ -24,263 +25,192 @@ */ #include "config.h" +#include "MediaStreamTrackPrivate.h" #if ENABLE(MEDIA_STREAM) -#include "MediaStreamTrackPrivate.h" - -#include "MediaSourceStates.h" -#include "MediaStreamCapabilities.h" -#include "NotImplemented.h" +#include "AudioSourceProvider.h" +#include "GraphicsContext.h" +#include "IntRect.h" #include "UUID.h" -#include <wtf/NeverDestroyed.h> namespace WebCore { -PassRefPtr<MediaStreamTrackPrivate> MediaStreamTrackPrivate::create(PassRefPtr<MediaStreamSource> source) +Ref<MediaStreamTrackPrivate> MediaStreamTrackPrivate::create(Ref<RealtimeMediaSource>&& source) { - return adoptRef(new MediaStreamTrackPrivate(source)); + return adoptRef(*new MediaStreamTrackPrivate(WTFMove(source), createCanonicalUUIDString())); } -MediaStreamTrackPrivate::MediaStreamTrackPrivate(const MediaStreamTrackPrivate& other) - : RefCounted() - , m_client(nullptr) +Ref<MediaStreamTrackPrivate> MediaStreamTrackPrivate::create(Ref<RealtimeMediaSource>&& source, String&& id) { - m_ignoreMutations = true; - m_id = createCanonicalUUIDString(); - setSource(other.source()); - m_readyState = other.readyState(); - m_muted = other.muted(); - m_enabled = other.enabled(); - m_stopped = other.stopped(); - m_ignoreMutations = false; + return adoptRef(*new MediaStreamTrackPrivate(WTFMove(source), WTFMove(id))); } -MediaStreamTrackPrivate::MediaStreamTrackPrivate(PassRefPtr<MediaStreamSource> source) - : m_source(nullptr) - , m_client(nullptr) - , m_readyState(MediaStreamSource::New) - , m_muted(false) - , m_enabled(true) - , m_stopped(false) +MediaStreamTrackPrivate::MediaStreamTrackPrivate(Ref<RealtimeMediaSource>&& source, String&& id) + : m_source(WTFMove(source)) + , m_id(WTFMove(id)) + , m_isEnabled(true) + , m_isEnded(false) { - m_ignoreMutations = true; - setSource(source); - m_ignoreMutations = false; + m_source->addObserver(*this); } MediaStreamTrackPrivate::~MediaStreamTrackPrivate() { - if (m_source) - m_source->removeObserver(this); + m_source->removeObserver(*this); } -void MediaStreamTrackPrivate::setSource(PassRefPtr<MediaStreamSource> source) +void MediaStreamTrackPrivate::addObserver(MediaStreamTrackPrivate::Observer& observer) { - if (m_source) - m_source->removeObserver(this); - - m_source = source; - - if (!m_source) - return; - - setMuted(m_source->muted()); - setReadyState(m_source->readyState()); - if (m_source) - m_source->addObserver(this); + m_observers.append(&observer); } -const String& MediaStreamTrackPrivate::id() const +void MediaStreamTrackPrivate::removeObserver(MediaStreamTrackPrivate::Observer& observer) { - if (!m_id.isEmpty()) - return m_id; - - // The spec says: - // Unless a MediaStreamTrack object is created as a part a of special purpose algorithm that - // specifies how the track id must be initialized, the user agent must generate a globally - // unique identifier string and initialize the object's id attribute to that string. - if (m_source && m_source->useIDForTrackID()) - return m_source->id(); - - m_id = createCanonicalUUIDString(); - return m_id; + size_t pos = m_observers.find(&observer); + if (pos != notFound) + m_observers.remove(pos); } const String& MediaStreamTrackPrivate::label() const { - if (m_source) - return m_source->name(); - - return emptyString(); -} - -bool MediaStreamTrackPrivate::ended() const -{ - return m_stopped || (m_source && m_source->readyState() == MediaStreamSource::Ended); + return m_source->name(); } bool MediaStreamTrackPrivate::muted() const { - if (m_stopped || !m_source) - return false; - return m_source->muted(); } -void MediaStreamTrackPrivate::setMuted(bool muted) -{ - if (m_muted == muted) - return; - - m_muted = muted; - - if (!m_client || m_ignoreMutations) - return; - - m_client->trackMutedChanged(); -} - bool MediaStreamTrackPrivate::readonly() const { - if (m_stopped || !m_source) - return true; - return m_source->readonly(); } bool MediaStreamTrackPrivate::remote() const { - if (!m_source) - return false; - return m_source->remote(); } void MediaStreamTrackPrivate::setEnabled(bool enabled) { - if (m_stopped || m_enabled == enabled) + if (m_isEnabled == enabled) return; - // 4.3.3.1 - // ... after a MediaStreamTrack is disassociated from its track, its enabled attribute still - // changes value when set; it just doesn't do anything with that new value. - m_enabled = enabled; - - if (m_source) - m_source->setEnabled(enabled); + // Always update the enabled state regardless of the track being ended. + m_isEnabled = enabled; - if (!m_client || m_ignoreMutations) - return; + m_source->setEnabled(enabled); - m_client->trackEnabledChanged(); + for (auto& observer : m_observers) + observer->trackEnabledChanged(*this); } -void MediaStreamTrackPrivate::stop(StopBehavior stopSource) +void MediaStreamTrackPrivate::endTrack() { - if (m_stopped) + if (m_isEnded) return; - if (stopSource == StopTrackAndStopSource && m_source) - m_source->stop(); + // Set m_isEnded to true before telling the source it can stop, so if this is the + // only track using the source and it does stop, we will only call each observer's + // trackEnded method once. + m_isEnded = true; - setReadyState(MediaStreamSource::Ended); - m_stopped = true; + m_source->requestStop(this); + + for (auto& observer : m_observers) + observer->trackEnded(*this); } -MediaStreamSource::ReadyState MediaStreamTrackPrivate::readyState() const +Ref<MediaStreamTrackPrivate> MediaStreamTrackPrivate::clone() { - if (m_stopped) - return MediaStreamSource::Ended; + auto clonedMediaStreamTrackPrivate = create(m_source.copyRef()); + clonedMediaStreamTrackPrivate->m_isEnabled = this->m_isEnabled; + clonedMediaStreamTrackPrivate->m_isEnded = this->m_isEnded; - return m_readyState; + return clonedMediaStreamTrackPrivate; } -void MediaStreamTrackPrivate::setReadyState(MediaStreamSource::ReadyState state) +RealtimeMediaSource::Type MediaStreamTrackPrivate::type() const { - if (m_readyState == MediaStreamSource::Ended || m_readyState == state) - return; - - MediaStreamSource::ReadyState oldState = m_readyState; - m_readyState = state; - - if (!m_client || m_ignoreMutations) - return; - - if ((m_readyState == MediaStreamSource::Live && oldState == MediaStreamSource::New) || m_readyState == MediaStreamSource::Ended) - m_client->trackReadyStateChanged(); + return m_source->type(); } -RefPtr<MediaStreamTrackPrivate> MediaStreamTrackPrivate::clone() +const RealtimeMediaSourceSettings& MediaStreamTrackPrivate::settings() const { - return adoptRef(new MediaStreamTrackPrivate(*this)); + return m_source->settings(); } - -RefPtr<MediaConstraints> MediaStreamTrackPrivate::constraints() const +RefPtr<RealtimeMediaSourceCapabilities> MediaStreamTrackPrivate::capabilities() const { - return m_constraints; + return m_source->capabilities(); } -const MediaStreamSourceStates& MediaStreamTrackPrivate::states() const +void MediaStreamTrackPrivate::paintCurrentFrameInContext(GraphicsContext& context, const FloatRect& rect) { - if (!m_source) { - DEFINE_STATIC_LOCAL(const MediaStreamSourceStates, noState, ()); - return noState; + if (context.paintingDisabled() || m_source->type() != RealtimeMediaSource::Type::Video || ended()) + return; + + if (!m_source->muted()) + m_source->paintCurrentFrameInContext(context, rect); + else { + GraphicsContextStateSaver stateSaver(context); + context.translate(rect.x(), rect.y() + rect.height()); + IntRect paintRect(IntPoint(0, 0), IntSize(rect.width(), rect.height())); + context.fillRect(paintRect, Color::black); } - - return m_source->states(); } -MediaStreamSource::Type MediaStreamTrackPrivate::type() const +void MediaStreamTrackPrivate::applyConstraints(const MediaConstraints& constraints, RealtimeMediaSource::SuccessHandler successHandler, RealtimeMediaSource::FailureHandler failureHandler) { - if (!m_source) - return MediaStreamSource::None; + m_source->applyConstraints(constraints, successHandler, failureHandler); +} - return m_source->type(); +AudioSourceProvider* MediaStreamTrackPrivate::audioSourceProvider() +{ + return m_source->audioSourceProvider(); } -RefPtr<MediaStreamSourceCapabilities> MediaStreamTrackPrivate::capabilities() const +void MediaStreamTrackPrivate::sourceStopped() { - if (!m_source) - return 0; + if (m_isEnded) + return; - return m_source->capabilities(); + m_isEnded = true; + + for (auto& observer : m_observers) + observer->trackEnded(*this); } -void MediaStreamTrackPrivate::applyConstraints(PassRefPtr<MediaConstraints>) +void MediaStreamTrackPrivate::sourceMutedChanged() { - // FIXME: apply the new constraints to the track - // https://bugs.webkit.org/show_bug.cgi?id=122428 + for (auto& observer : m_observers) + observer->trackMutedChanged(*this); } -void MediaStreamTrackPrivate::sourceReadyStateChanged() +void MediaStreamTrackPrivate::sourceEnabledChanged() { - if (stopped()) - return; - - setReadyState(m_source->readyState()); + for (auto& observer : m_observers) + observer->trackEnabledChanged(*this); } -void MediaStreamTrackPrivate::sourceMutedChanged() +void MediaStreamTrackPrivate::sourceSettingsChanged() { - if (stopped()) - return; - - setMuted(m_source->muted()); + for (auto& observer : m_observers) + observer->trackSettingsChanged(*this); } -void MediaStreamTrackPrivate::sourceEnabledChanged() +bool MediaStreamTrackPrivate::preventSourceFromStopping() { - if (stopped()) - return; - - setEnabled(m_source->enabled()); + // Do not allow the source to stop if we are still using it. + return !m_isEnded; } -bool MediaStreamTrackPrivate::observerIsEnabled() +void MediaStreamTrackPrivate::videoSampleAvailable(MediaSample& mediaSample) { - return enabled(); + mediaSample.setTrackID(id()); + for (auto& observer : m_observers) + observer->sampleBufferUpdated(*this, mediaSample); } } // namespace WebCore diff --git a/Source/WebCore/platform/mediastream/MediaStreamTrackPrivate.h b/Source/WebCore/platform/mediastream/MediaStreamTrackPrivate.h index 5ea7a10b3..ca0d7c17d 100644 --- a/Source/WebCore/platform/mediastream/MediaStreamTrackPrivate.h +++ b/Source/WebCore/platform/mediastream/MediaStreamTrackPrivate.h @@ -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 @@ -23,101 +24,95 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef MediaStreamTrackPrivate_h -#define MediaStreamTrackPrivate_h +#pragma once #if ENABLE(MEDIA_STREAM) -#include "MediaStreamSource.h" -#include <wtf/PassRefPtr.h> -#include <wtf/RefCounted.h> -#include <wtf/text/AtomicString.h> +#include "RealtimeMediaSource.h" namespace WebCore { -class MediaSourceStates; -class MediaStreamSourceCapabilities; +class AudioSourceProvider; +class GraphicsContext; +class MediaSample; +class RealtimeMediaSourceCapabilities; -class MediaStreamTrackPrivateClient { +class MediaStreamTrackPrivate : public RefCounted<MediaStreamTrackPrivate>, public RealtimeMediaSource::Observer { public: - virtual ~MediaStreamTrackPrivateClient() { } + class Observer { + public: + virtual ~Observer() { } - virtual void trackReadyStateChanged() = 0; - virtual void trackMutedChanged() = 0; - virtual void trackEnabledChanged() = 0; -}; + virtual void trackEnded(MediaStreamTrackPrivate&) = 0; + virtual void trackMutedChanged(MediaStreamTrackPrivate&) = 0; + virtual void trackSettingsChanged(MediaStreamTrackPrivate&) = 0; + virtual void trackEnabledChanged(MediaStreamTrackPrivate&) = 0; + virtual void sampleBufferUpdated(MediaStreamTrackPrivate&, MediaSample&) { }; + }; -class MediaStreamTrackPrivate : public RefCounted<MediaStreamTrackPrivate>, public MediaStreamSource::Observer { -public: - static PassRefPtr<MediaStreamTrackPrivate> create(PassRefPtr<MediaStreamSource>); + static Ref<MediaStreamTrackPrivate> create(Ref<RealtimeMediaSource>&&); + static Ref<MediaStreamTrackPrivate> create(Ref<RealtimeMediaSource>&&, String&& id); virtual ~MediaStreamTrackPrivate(); - const String& id() const; + const String& id() const { return m_id; } const String& label() const; - bool ended() const; + bool ended() const { return m_isEnded; } + + void startProducingData() { m_source->startProducingData(); } + void stopProducingData() { m_source->stopProducingData(); } + bool isProducingData() { return m_source->isProducingData(); } bool muted() const; - void setMuted(bool); + void setMuted(bool muted) { m_source->setMuted(muted); } bool readonly() const; bool remote() const; - bool enabled() const { return m_enabled; } + bool enabled() const { return m_isEnabled; } void setEnabled(bool); - void setReadyState(MediaStreamSource::ReadyState); - MediaStreamSource::ReadyState readyState() const; + Ref<MediaStreamTrackPrivate> clone(); - RefPtr<MediaStreamTrackPrivate> clone(); + RealtimeMediaSource& source() { return m_source.get(); } + RealtimeMediaSource::Type type() const; - MediaStreamSource* source() const { return m_source.get(); } - void setSource(PassRefPtr<MediaStreamSource>); + void endTrack(); - enum StopBehavior { StopTrackAndStopSource, StopTrackOnly }; - void stop(StopBehavior); - bool stopped() const { return m_stopped; } - - void setClient(MediaStreamTrackPrivateClient* client) { m_client = client; } + void addObserver(Observer&); + void removeObserver(Observer&); - MediaStreamSource::Type type() const; + const RealtimeMediaSourceSettings& settings() const; + RefPtr<RealtimeMediaSourceCapabilities> capabilities() const; - const MediaStreamSourceStates& states() const; - RefPtr<MediaStreamSourceCapabilities> capabilities() const; + void applyConstraints(const MediaConstraints&, RealtimeMediaSource::SuccessHandler, RealtimeMediaSource::FailureHandler); - RefPtr<MediaConstraints> constraints() const; - void applyConstraints(PassRefPtr<MediaConstraints>); + AudioSourceProvider* audioSourceProvider(); - void configureTrackRendering(); - -protected: - explicit MediaStreamTrackPrivate(const MediaStreamTrackPrivate&); - MediaStreamTrackPrivate(PassRefPtr<MediaStreamSource>); + void paintCurrentFrameInContext(GraphicsContext&, const FloatRect&); private: - MediaStreamTrackPrivateClient* client() const { return m_client; } - - // MediaStreamSourceObserver - virtual void sourceReadyStateChanged() override final; - virtual void sourceMutedChanged() override final; - virtual void sourceEnabledChanged() override final; - virtual bool observerIsEnabled() override final; - - RefPtr<MediaStreamSource> m_source; - MediaStreamTrackPrivateClient* m_client; - RefPtr<MediaConstraints> m_constraints; - MediaStreamSource::ReadyState m_readyState; - mutable String m_id; - - bool m_muted; - bool m_enabled; - bool m_stopped; - bool m_ignoreMutations; + MediaStreamTrackPrivate(Ref<RealtimeMediaSource>&&, String&& id); + + // RealtimeMediaSourceObserver + void sourceStopped() final; + void sourceMutedChanged() final; + void sourceEnabledChanged() final; + void sourceSettingsChanged() final; + bool preventSourceFromStopping() final; + void videoSampleAvailable(MediaSample&) final; + + Vector<Observer*> m_observers; + Ref<RealtimeMediaSource> m_source; + + String m_id; + bool m_isEnabled; + bool m_isEnded; }; +typedef Vector<RefPtr<MediaStreamTrackPrivate>> MediaStreamTrackPrivateVector; + } // namespace WebCore #endif // ENABLE(MEDIA_STREAM) - -#endif // MediaStreamTrackPrivate_h diff --git a/Source/WebCore/platform/mediastream/MediaStreamTrackSourcesRequestClient.h b/Source/WebCore/platform/mediastream/MediaStreamTrackSourcesRequestClient.h deleted file mode 100644 index a006df46d..000000000 --- a/Source/WebCore/platform/mediastream/MediaStreamTrackSourcesRequestClient.h +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright (C) 2013 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 COMPUTER, 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 COMPUTER, 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 MediaStreamTrackSourcesRequestClient_h -#define MediaStreamTrackSourcesRequestClient_h - -#if ENABLE(MEDIA_STREAM) - -#include <wtf/PassRefPtr.h> -#include <wtf/RefCounted.h> -#include <wtf/text/AtomicString.h> - -namespace WebCore { - -class TrackSourceInfo : public RefCounted<TrackSourceInfo> { -public: - enum SourceKind { Audio, Video }; - - static PassRefPtr<TrackSourceInfo> create(const AtomicString& id, SourceKind kind, const AtomicString& label) - { - return adoptRef(new TrackSourceInfo(id, kind, label)); - } - - const AtomicString& id() const { return m_id; } - const AtomicString& label() const { return m_label; } - SourceKind kind() const { return m_kind; } - -private: - TrackSourceInfo(const AtomicString& id, SourceKind kind, const AtomicString& label) - : m_id(id) - , m_kind(kind) - , m_label(label) - { - } - - AtomicString m_id; - SourceKind m_kind; - AtomicString m_label; -}; - -class MediaStreamTrackSourcesRequestClient : public RefCounted<MediaStreamTrackSourcesRequestClient> { -public: - virtual ~MediaStreamTrackSourcesRequestClient() { } - - virtual const String& requestOrigin() const = 0; - virtual void didCompleteRequest(const Vector<RefPtr<TrackSourceInfo>>&) = 0; - -}; - -} // namespace WebCore - -#endif // ENABLE(MEDIA_STREAM) - -#endif // MediaStreamTrackSourcesRequestClient_h diff --git a/Source/WebCore/platform/mediastream/PeerConnectionStates.h b/Source/WebCore/platform/mediastream/PeerConnectionStates.h new file mode 100644 index 000000000..8a7124070 --- /dev/null +++ b/Source/WebCore/platform/mediastream/PeerConnectionStates.h @@ -0,0 +1,89 @@ +/* + * 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) + +namespace WebCore { + +namespace PeerConnectionStates { + +enum class SignalingState { + Stable = 1, + HaveLocalOffer = 2, + HaveRemoteOffer = 3, + HaveLocalPrAnswer = 4, + HaveRemotePrAnswer = 5, + Closed = 6 +}; + +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 +}; + +enum class IceTransportState { + New = 1, + Checking = 2, + Connected = 3, + Completed = 4, + Failed = 5, + Disconnected = 6, + Closed = 7 +}; + +enum class IceTransportPolicy { + Relay, + All +}; + +enum class BundlePolicy { + Balanced, + MaxCompat, + MaxBundle +}; + +} + +} // namespace WebCore + +#endif // ENABLE(WEB_RTC) diff --git a/Source/WebCore/platform/mediastream/PeerMediaDescription.h b/Source/WebCore/platform/mediastream/PeerMediaDescription.h new file mode 100644 index 000000000..157dc8a29 --- /dev/null +++ b/Source/WebCore/platform/mediastream/PeerMediaDescription.h @@ -0,0 +1,77 @@ +/* + * 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. + */ + +#pragma once + +#if ENABLE(WEB_RTC) + +#include "IceCandidate.h" +#include "MediaPayload.h" +#include "RealtimeMediaSource.h" +#include <wtf/Vector.h> + +namespace WebCore { + +struct PeerMediaDescription { + void addPayload(MediaPayload&& payload) { payloads.append(WTFMove(payload)); } + void addSsrc(unsigned ssrc) { ssrcs.append(ssrc); } + void clearSsrcs() { ssrcs.clear(); } + void addIceCandidate(IceCandidate&& candidate) { iceCandidates.append(WTFMove(candidate)); } + + String type; + unsigned short port { 9 }; + String address { "0.0.0.0" }; + String mode { ASCIILiteral { "sendrecv" } }; + String mid; + + Vector<MediaPayload> payloads; + + bool rtcpMux { true }; + String rtcpAddress; + unsigned short rtcpPort { 0 }; + + String mediaStreamId; + String mediaStreamTrackId; + + String dtlsSetup { "actpass" }; + String dtlsFingerprintHashFunction; + String dtlsFingerprint; + + Vector<unsigned> ssrcs; + String cname; + + String iceUfrag; + String icePassword; + Vector<IceCandidate> iceCandidates; +}; + +} // namespace WebCore + +#endif // ENABLE(WEB_RTC) diff --git a/Source/WebCore/platform/mediastream/RTCConfiguration.h b/Source/WebCore/platform/mediastream/RTCConfiguration.h deleted file mode 100644 index 73c4cfcf0..000000000 --- a/Source/WebCore/platform/mediastream/RTCConfiguration.h +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright (C) 2012 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. - * 3. Neither the name of Google Inc. 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 RTCConfiguration_h -#define RTCConfiguration_h - -#if ENABLE(MEDIA_STREAM) - -#include "URL.h" -#include <wtf/PassRefPtr.h> -#include <wtf/RefCounted.h> -#include <wtf/Vector.h> -#include <wtf/text/WTFString.h> - -namespace WebCore { - -class RTCIceServer : public RefCounted<RTCIceServer> { -public: - static PassRefPtr<RTCIceServer> create(const URL& uri, const String& credential, const String& username) - { - return adoptRef(new RTCIceServer(uri, credential, username)); - } - virtual ~RTCIceServer() { } - - const URL& uri() { return m_uri; } - const String& credential() { return m_credential; } - const String& username() { return m_username; } - -private: - RTCIceServer(const URL& uri, const String& credential, const String& username) - : m_uri(uri) - , m_credential(credential) - , m_username(username) - { - } - - URL m_uri; - String m_credential; - String m_username; -}; - -class RTCConfiguration : public RefCounted<RTCConfiguration> { -public: - static PassRefPtr<RTCConfiguration> create() { return adoptRef(new RTCConfiguration()); } - virtual ~RTCConfiguration() { } - - void appendServer(PassRefPtr<RTCIceServer> server) { m_servers.append(server); } - size_t numberOfServers() { return m_servers.size(); } - RTCIceServer* server(size_t index) { return m_servers[index].get(); } - - private: - RTCConfiguration() { } - - Vector<RefPtr<RTCIceServer>> m_servers; -}; - -} // namespace WebCore - -#endif // ENABLE(MEDIA_STREAM) - -#endif // RTCConfiguration_h diff --git a/Source/WebCore/platform/mediastream/RTCDTMFSenderHandler.h b/Source/WebCore/platform/mediastream/RTCDTMFSenderHandler.h index b96aa8f3c..1733cf2a2 100644 --- a/Source/WebCore/platform/mediastream/RTCDTMFSenderHandler.h +++ b/Source/WebCore/platform/mediastream/RTCDTMFSenderHandler.h @@ -26,7 +26,7 @@ #ifndef RTCDTMFSenderHandler_h #define RTCDTMFSenderHandler_h -#if ENABLE(MEDIA_STREAM) +#if ENABLE(WEB_RTC) #include <wtf/text/WTFString.h> @@ -48,6 +48,6 @@ public: } // namespace WebCore -#endif // ENABLE(MEDIA_STREAM) +#endif // ENABLE(WEB_RTC) #endif // RTCDTMFSenderHandler_h diff --git a/Source/WebCore/platform/mediastream/RTCDTMFSenderHandlerClient.h b/Source/WebCore/platform/mediastream/RTCDTMFSenderHandlerClient.h index 17c47154f..32f18e5c1 100644 --- a/Source/WebCore/platform/mediastream/RTCDTMFSenderHandlerClient.h +++ b/Source/WebCore/platform/mediastream/RTCDTMFSenderHandlerClient.h @@ -26,7 +26,7 @@ #ifndef RTCDTMFSenderHandlerClient_h #define RTCDTMFSenderHandlerClient_h -#if ENABLE(MEDIA_STREAM) +#if ENABLE(WEB_RTC) namespace WebCore { @@ -39,6 +39,6 @@ public: } // namespace WebCore -#endif // ENABLE(MEDIA_STREAM) +#endif // ENABLE(WEB_RTC) #endif // RTCDTMFSenderHandlerClient_h diff --git a/Source/WebCore/platform/mediastream/RTCDataChannelHandler.h b/Source/WebCore/platform/mediastream/RTCDataChannelHandler.h index 74bd11fb1..e4655dd30 100644 --- a/Source/WebCore/platform/mediastream/RTCDataChannelHandler.h +++ b/Source/WebCore/platform/mediastream/RTCDataChannelHandler.h @@ -22,15 +22,23 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef RTCDataChannelHandler_h -#define RTCDataChannelHandler_h +#pragma once -#if ENABLE(MEDIA_STREAM) +#if ENABLE(WEB_RTC) #include <wtf/text/WTFString.h> namespace WebCore { +struct RTCDataChannelInit { + bool ordered { true }; + int maxRetransmitTime { -1 }; + int maxRetransmits { -1 }; + String protocol; + bool negotiated { false }; + int id { -1 }; +}; + class RTCDataChannelHandlerClient; class RTCDataChannelHandler { @@ -39,22 +47,13 @@ public: virtual void setClient(RTCDataChannelHandlerClient*) = 0; - virtual String label() = 0; - virtual bool ordered() = 0; - virtual unsigned short maxRetransmitTime() = 0; - virtual unsigned short maxRetransmits() = 0; - virtual String protocol() = 0; - virtual bool negotiated() = 0; - virtual unsigned short id() = 0; - virtual unsigned long bufferedAmount() = 0; - virtual bool sendStringData(const String&) = 0; virtual bool sendRawData(const char*, size_t) = 0; virtual void close() = 0; + + virtual size_t bufferedAmount() const = 0; }; } // namespace WebCore -#endif // ENABLE(MEDIA_STREAM) - -#endif // RTCDataChannelHandler_h +#endif // ENABLE(WEB_RTC) diff --git a/Source/WebCore/platform/mediastream/RTCDataChannelHandlerClient.h b/Source/WebCore/platform/mediastream/RTCDataChannelHandlerClient.h index 288ee16f3..981316d14 100644 --- a/Source/WebCore/platform/mediastream/RTCDataChannelHandlerClient.h +++ b/Source/WebCore/platform/mediastream/RTCDataChannelHandlerClient.h @@ -22,16 +22,16 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef RTCDataChannelHandlerClient_h -#define RTCDataChannelHandlerClient_h +#pragma once -#if ENABLE(MEDIA_STREAM) +#if ENABLE(WEB_RTC) +#include <wtf/ThreadSafeRefCounted.h> #include <wtf/text/WTFString.h> namespace WebCore { -class RTCDataChannelHandlerClient { +class RTCDataChannelHandlerClient : public ThreadSafeRefCounted<RTCDataChannelHandlerClient> { public: enum ReadyState { ReadyStateConnecting = 0, @@ -46,10 +46,9 @@ public: virtual void didReceiveStringData(const String&) = 0; virtual void didReceiveRawData(const char*, size_t) = 0; virtual void didDetectError() = 0; + virtual void bufferedAmountIsDecreasing() = 0; }; } // namespace WebCore -#endif // ENABLE(MEDIA_STREAM) - -#endif // RTCDataChannelHandlerClient_h +#endif // ENABLE(WEB_RTC) diff --git a/Source/WebCore/platform/mediastream/RTCIceCandidateDescriptor.cpp b/Source/WebCore/platform/mediastream/RTCIceCandidateDescriptor.cpp index 34bb4bece..7f7538eed 100644 --- a/Source/WebCore/platform/mediastream/RTCIceCandidateDescriptor.cpp +++ b/Source/WebCore/platform/mediastream/RTCIceCandidateDescriptor.cpp @@ -30,7 +30,7 @@ #include "config.h" -#if ENABLE(MEDIA_STREAM) +#if ENABLE(WEB_RTC) #include "RTCIceCandidateDescriptor.h" @@ -54,4 +54,4 @@ RTCIceCandidateDescriptor::~RTCIceCandidateDescriptor() } // namespace WebCore -#endif // ENABLE(MEDIA_STREAM) +#endif // ENABLE(WEB_RTC) diff --git a/Source/WebCore/platform/mediastream/RTCIceCandidateDescriptor.h b/Source/WebCore/platform/mediastream/RTCIceCandidateDescriptor.h index f5123a3fc..64cf7ac8c 100644 --- a/Source/WebCore/platform/mediastream/RTCIceCandidateDescriptor.h +++ b/Source/WebCore/platform/mediastream/RTCIceCandidateDescriptor.h @@ -31,7 +31,7 @@ #ifndef RTCIceCandidateDescriptor_h #define RTCIceCandidateDescriptor_h -#if ENABLE(MEDIA_STREAM) +#if ENABLE(WEB_RTC) #include <wtf/PassRefPtr.h> #include <wtf/RefCounted.h> @@ -58,6 +58,6 @@ private: } // namespace WebCore -#endif // ENABLE(MEDIA_STREAM) +#endif // ENABLE(WEB_RTC) #endif // RTCIceCandidateDescriptor_h diff --git a/Source/WebCore/platform/mediastream/RTCPeerConnectionHandler.cpp b/Source/WebCore/platform/mediastream/RTCPeerConnectionHandler.cpp deleted file mode 100644 index 8f36b60e5..000000000 --- a/Source/WebCore/platform/mediastream/RTCPeerConnectionHandler.cpp +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright (C) 2012 Google Inc. All rights reserved. - * Copyright (C) 2013 Nokia Corporation and/or its subsidiary(-ies). - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * 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. - * * Neither the name of Google Inc. 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 "RTCPeerConnectionHandler.h" - -#include <wtf/NeverDestroyed.h> - -namespace WebCore { -class RTCPeerConnectionHandlerClient; - -static std::unique_ptr<RTCPeerConnectionHandler> createHandler(RTCPeerConnectionHandlerClient*) -{ - return nullptr; -} - -CreatePeerConnectionHandler RTCPeerConnectionHandler::create = createHandler; - -const AtomicString& RTCPeerConnectionHandler::incompatibleConstraintsErrorName() -{ - static NeverDestroyed<AtomicString> incompatibleConstraints("IncompatibleConstraintsError", AtomicString::ConstructFromLiteral); - return incompatibleConstraints; -} - -const AtomicString& RTCPeerConnectionHandler::invalidSessionDescriptionErrorName() -{ - static NeverDestroyed<AtomicString> invalidSessionDescription("InvalidSessionDescriptionError", AtomicString::ConstructFromLiteral); - return invalidSessionDescription; -} - -const AtomicString& RTCPeerConnectionHandler::incompatibleSessionDescriptionErrorName() -{ - static NeverDestroyed<AtomicString> incompatibleSessionDescription("IncompatibleSessionDescriptionError", AtomicString::ConstructFromLiteral); - return incompatibleSessionDescription; -} - -const AtomicString& RTCPeerConnectionHandler::internalErrorName() -{ - static NeverDestroyed<AtomicString> internal("InternalError", AtomicString::ConstructFromLiteral); - return internal; -} - -} // namespace WebCore - -#endif // ENABLE(MEDIA_STREAM) diff --git a/Source/WebCore/platform/mediastream/RTCPeerConnectionHandler.h b/Source/WebCore/platform/mediastream/RTCPeerConnectionHandler.h deleted file mode 100644 index 954acb9a3..000000000 --- a/Source/WebCore/platform/mediastream/RTCPeerConnectionHandler.h +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright (C) 2012 Google Inc. All rights reserved. - * Copyright (C) 2013 Nokia Corporation and/or its subsidiary(-ies). - * - * 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 Google Inc. 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 RTCPeerConnectionHandler_h -#define RTCPeerConnectionHandler_h - -#if ENABLE(MEDIA_STREAM) - -#include "MediaStreamPrivate.h" -#include <wtf/PassRefPtr.h> - -namespace WebCore { - -class MediaConstraints; -class MediaStreamSource; -class RTCConfiguration; -class RTCDTMFSenderHandler; -class RTCDataChannelHandler; -class RTCIceCandidateDescriptor; -class RTCPeerConnectionHandler; -class RTCPeerConnectionHandlerClient; -class RTCSessionDescriptionDescriptor; -class RTCSessionDescriptionRequest; -class RTCStatsRequest; -class RTCVoidRequest; - -struct RTCDataChannelInit { -public: - RTCDataChannelInit() - : ordered(true) - , maxRetransmitTime(-1) - , maxRetransmits(-1) - , negotiated(false) - , id(-1) { } - bool ordered; - int maxRetransmitTime; - int maxRetransmits; - String protocol; - bool negotiated; - int id; -}; - -typedef std::unique_ptr<RTCPeerConnectionHandler> (*CreatePeerConnectionHandler)(RTCPeerConnectionHandlerClient*); - -class RTCPeerConnectionHandler { -public: - static CreatePeerConnectionHandler create; - virtual ~RTCPeerConnectionHandler() { } - - static const AtomicString& incompatibleConstraintsErrorName(); - static const AtomicString& invalidSessionDescriptionErrorName(); - static const AtomicString& incompatibleSessionDescriptionErrorName(); - static const AtomicString& internalErrorName(); - - virtual bool initialize(PassRefPtr<RTCConfiguration>, PassRefPtr<MediaConstraints>) = 0; - - virtual void createOffer(PassRefPtr<RTCSessionDescriptionRequest>, PassRefPtr<MediaConstraints>) = 0; - virtual void createAnswer(PassRefPtr<RTCSessionDescriptionRequest>, PassRefPtr<MediaConstraints>) = 0; - virtual void setLocalDescription(PassRefPtr<RTCVoidRequest>, PassRefPtr<RTCSessionDescriptionDescriptor>) = 0; - virtual void setRemoteDescription(PassRefPtr<RTCVoidRequest>, PassRefPtr<RTCSessionDescriptionDescriptor>) = 0; - virtual PassRefPtr<RTCSessionDescriptionDescriptor> localDescription() = 0; - virtual PassRefPtr<RTCSessionDescriptionDescriptor> remoteDescription() = 0; - virtual bool updateIce(PassRefPtr<RTCConfiguration>, PassRefPtr<MediaConstraints>) = 0; - virtual bool addIceCandidate(PassRefPtr<RTCVoidRequest>, PassRefPtr<RTCIceCandidateDescriptor>) = 0; - virtual bool addStream(PassRefPtr<MediaStreamPrivate>, PassRefPtr<MediaConstraints>) = 0; - virtual void removeStream(PassRefPtr<MediaStreamPrivate>) = 0; - virtual void getStats(PassRefPtr<RTCStatsRequest>) = 0; - virtual std::unique_ptr<RTCDataChannelHandler> createDataChannel(const String& label, const RTCDataChannelInit&) = 0; - virtual std::unique_ptr<RTCDTMFSenderHandler> createDTMFSender(PassRefPtr<MediaStreamSource>) = 0; - virtual void stop() = 0; -}; - -} // namespace WebCore - -#endif // ENABLE(MEDIA_STREAM) - -#endif // RTCPeerConnectionHandler_h diff --git a/Source/WebCore/platform/mediastream/RTCPeerConnectionHandlerClient.h b/Source/WebCore/platform/mediastream/RTCPeerConnectionHandlerClient.h index e2ed35bce..16b763b17 100644 --- a/Source/WebCore/platform/mediastream/RTCPeerConnectionHandlerClient.h +++ b/Source/WebCore/platform/mediastream/RTCPeerConnectionHandlerClient.h @@ -31,7 +31,7 @@ #ifndef RTCPeerConnectionHandlerClient_h #define RTCPeerConnectionHandlerClient_h -#if ENABLE(MEDIA_STREAM) +#if ENABLE(WEB_RTC) #include <wtf/PassRefPtr.h> @@ -82,6 +82,6 @@ public: } // namespace WebCore -#endif // ENABLE(MEDIA_STREAM) +#endif // ENABLE(WEB_RTC) #endif // RTCPeerConnectionHandlerClient_h diff --git a/Source/WebCore/platform/mediastream/RTCSessionDescriptionDescriptor.cpp b/Source/WebCore/platform/mediastream/RTCSessionDescriptionDescriptor.cpp index 9178676b1..493219ef0 100644 --- a/Source/WebCore/platform/mediastream/RTCSessionDescriptionDescriptor.cpp +++ b/Source/WebCore/platform/mediastream/RTCSessionDescriptionDescriptor.cpp @@ -30,7 +30,7 @@ #include "config.h" -#if ENABLE(MEDIA_STREAM) +#if ENABLE(WEB_RTC) #include "RTCSessionDescriptionDescriptor.h" @@ -53,4 +53,4 @@ RTCSessionDescriptionDescriptor::~RTCSessionDescriptionDescriptor() } // namespace WebCore -#endif // ENABLE(MEDIA_STREAM) +#endif // ENABLE(WEB_RTC) diff --git a/Source/WebCore/platform/mediastream/RTCSessionDescriptionDescriptor.h b/Source/WebCore/platform/mediastream/RTCSessionDescriptionDescriptor.h index 523c27fa1..95d845ec9 100644 --- a/Source/WebCore/platform/mediastream/RTCSessionDescriptionDescriptor.h +++ b/Source/WebCore/platform/mediastream/RTCSessionDescriptionDescriptor.h @@ -31,7 +31,7 @@ #ifndef RTCSessionDescriptionDescriptor_h #define RTCSessionDescriptionDescriptor_h -#if ENABLE(MEDIA_STREAM) +#if ENABLE(WEB_RTC) #include <wtf/PassRefPtr.h> #include <wtf/RefCounted.h> @@ -59,6 +59,6 @@ private: } // namespace WebCore -#endif // ENABLE(MEDIA_STREAM) +#endif // ENABLE(WEB_RTC) #endif // RTCSessionDescriptionDescriptor_h diff --git a/Source/WebCore/platform/mediastream/RTCSessionDescriptionRequest.h b/Source/WebCore/platform/mediastream/RTCSessionDescriptionRequest.h index f198e8405..107f4ba58 100644 --- a/Source/WebCore/platform/mediastream/RTCSessionDescriptionRequest.h +++ b/Source/WebCore/platform/mediastream/RTCSessionDescriptionRequest.h @@ -31,7 +31,7 @@ #ifndef RTCSessionDescriptionRequest_h #define RTCSessionDescriptionRequest_h -#if ENABLE(MEDIA_STREAM) +#if ENABLE(WEB_RTC) #include <wtf/PassRefPtr.h> #include <wtf/RefCounted.h> @@ -66,6 +66,6 @@ private: } // namespace WebCore -#endif // ENABLE(MEDIA_STREAM) +#endif // ENABLE(WEB_RTC) #endif // RTCSessionDescriptionRequest_h diff --git a/Source/WebCore/platform/mediastream/RTCVoidRequest.h b/Source/WebCore/platform/mediastream/RTCVoidRequest.h index 8f64f7693..470e4c002 100644 --- a/Source/WebCore/platform/mediastream/RTCVoidRequest.h +++ b/Source/WebCore/platform/mediastream/RTCVoidRequest.h @@ -31,11 +31,9 @@ #ifndef RTCVoidRequest_h #define RTCVoidRequest_h -#if ENABLE(MEDIA_STREAM) +#if ENABLE(WEB_RTC) -#include <wtf/PassRefPtr.h> #include <wtf/RefCounted.h> -#include <wtf/RefPtr.h> #include <wtf/text/WTFString.h> namespace WebCore { @@ -53,6 +51,6 @@ protected: } // namespace WebCore -#endif // ENABLE(MEDIA_STREAM) +#endif // ENABLE(WEB_RTC) #endif // RTCVoidRequest_h diff --git a/Source/WebCore/platform/mediastream/RealtimeMediaSource.cpp b/Source/WebCore/platform/mediastream/RealtimeMediaSource.cpp new file mode 100644 index 000000000..d0bd028dd --- /dev/null +++ b/Source/WebCore/platform/mediastream/RealtimeMediaSource.cpp @@ -0,0 +1,783 @@ +/* + * Copyright (C) 2012 Google Inc. All rights reserved. + * Copyright (C) 2013-2016 Apple 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 Google Inc. 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 "RealtimeMediaSource.h" + +#include "MediaConstraints.h" +#include "NotImplemented.h" +#include "RealtimeMediaSourceCapabilities.h" +#include "UUID.h" +#include <wtf/MainThread.h> +#include <wtf/text/StringHash.h> + +namespace WebCore { + +RealtimeMediaSource::RealtimeMediaSource(const String& id, Type type, const String& name) + : m_weakPtrFactory(this) + , m_id(id) + , m_type(type) + , m_name(name) +{ + // FIXME(147205): Need to implement fitness score for constraints + + if (m_id.isEmpty()) + m_id = createCanonicalUUIDString(); + m_persistentID = m_id; + m_suppressNotifications = false; +} + +void RealtimeMediaSource::reset() +{ + m_stopped = false; + m_muted = false; + m_readonly = false; + m_remote = false; +} + +void RealtimeMediaSource::addObserver(RealtimeMediaSource::Observer& observer) +{ + m_observers.append(&observer); +} + +void RealtimeMediaSource::removeObserver(RealtimeMediaSource::Observer& observer) +{ + m_observers.removeFirstMatching([&observer](auto* anObserver) { + return anObserver == &observer; + }); + + if (!m_observers.size()) + stop(); +} + +void RealtimeMediaSource::setMuted(bool muted) +{ + if (m_stopped || m_muted == muted) + return; + + m_muted = muted; + + if (stopped()) + return; + + for (auto& observer : m_observers) + observer->sourceMutedChanged(); +} + +void RealtimeMediaSource::setEnabled(bool enabled) +{ + if (m_stopped || m_enabled == enabled) + return; + + m_enabled = enabled; + + if (m_stopped) + return; + + for (auto& observer : m_observers) + observer->sourceEnabledChanged(); +} + +void RealtimeMediaSource::settingsDidChange() +{ + ASSERT(isMainThread()); + + if (m_pendingSettingsDidChangeNotification || m_suppressNotifications) + return; + + m_pendingSettingsDidChangeNotification = true; + + scheduleDeferredTask([this] { + m_pendingSettingsDidChangeNotification = false; + for (auto& observer : m_observers) + observer->sourceSettingsChanged(); + }); +} + +void RealtimeMediaSource::videoSampleAvailable(MediaSample& mediaSample) +{ + ASSERT(isMainThread()); + for (const auto& observer : m_observers) + observer->videoSampleAvailable(mediaSample); +} + +void RealtimeMediaSource::audioSamplesAvailable(const MediaTime& time, const PlatformAudioData& audioData, const AudioStreamDescription& description, size_t numberOfFrames) +{ + for (const auto& observer : m_observers) + observer->audioSamplesAvailable(time, audioData, description, numberOfFrames); +} + +bool RealtimeMediaSource::readonly() const +{ + return m_readonly; +} + +void RealtimeMediaSource::stop(Observer* callingObserver) +{ + if (stopped()) + return; + + m_stopped = true; + + for (const auto& observer : m_observers) { + if (observer != callingObserver) + observer->sourceStopped(); + } + + stopProducingData(); +} + +void RealtimeMediaSource::requestStop(Observer* callingObserver) +{ + if (stopped()) + return; + + for (const auto& observer : m_observers) { + if (observer->preventSourceFromStopping()) + return; + } + stop(callingObserver); +} + +bool RealtimeMediaSource::supportsSizeAndFrameRate(std::optional<int>, std::optional<int>, std::optional<double>) +{ + // The size and frame rate are within the capability limits, so they are supported. + return true; +} + +bool RealtimeMediaSource::supportsSizeAndFrameRate(std::optional<IntConstraint> widthConstraint, std::optional<IntConstraint> heightConstraint, std::optional<DoubleConstraint> frameRateConstraint, String& badConstraint) +{ + if (!widthConstraint && !heightConstraint && !frameRateConstraint) + return true; + + ASSERT(this->capabilities()); + RealtimeMediaSourceCapabilities& capabilities = *this->capabilities(); + + std::optional<int> width; + if (widthConstraint && capabilities.supportsWidth()) { + if (std::isinf(fitnessDistance(*widthConstraint))) { + badConstraint = widthConstraint->name(); + return false; + } + + auto range = capabilities.width(); + width = widthConstraint->valueForCapabilityRange(size().width(), range.rangeMin().asInt, range.rangeMax().asInt); + } + + std::optional<int> height; + if (heightConstraint && capabilities.supportsHeight()) { + if (std::isinf(fitnessDistance(*heightConstraint))) { + badConstraint = heightConstraint->name(); + return false; + } + + auto range = capabilities.height(); + height = heightConstraint->valueForCapabilityRange(size().height(), range.rangeMin().asInt, range.rangeMax().asInt); + } + + std::optional<double> frameRate; + if (frameRateConstraint && capabilities.supportsFrameRate()) { + if (std::isinf(fitnessDistance(*frameRateConstraint))) { + badConstraint = frameRateConstraint->name(); + return false; + } + + auto range = capabilities.frameRate(); + frameRate = frameRateConstraint->valueForCapabilityRange(this->frameRate(), range.rangeMin().asDouble, range.rangeMax().asDouble); + } + + // Each of the values is supported individually, see if they all can be applied at the same time. + if (!supportsSizeAndFrameRate(WTFMove(width), WTFMove(height), WTFMove(frameRate))) { + if (widthConstraint) + badConstraint = widthConstraint->name(); + else if (heightConstraint) + badConstraint = heightConstraint->name(); + else + badConstraint = frameRateConstraint->name(); + return false; + } + + return true; +} + +double RealtimeMediaSource::fitnessDistance(const MediaConstraint& constraint) +{ + ASSERT(this->capabilities()); + RealtimeMediaSourceCapabilities& capabilities = *this->capabilities(); + + switch (constraint.constraintType()) { + case MediaConstraintType::Width: { + ASSERT(constraint.isInt()); + if (!capabilities.supportsWidth()) + return 0; + + auto range = capabilities.width(); + return downcast<IntConstraint>(constraint).fitnessDistance(range.rangeMin().asInt, range.rangeMax().asInt); + break; + } + + case MediaConstraintType::Height: { + ASSERT(constraint.isInt()); + if (!capabilities.supportsHeight()) + return 0; + + auto range = capabilities.height(); + return downcast<IntConstraint>(constraint).fitnessDistance(range.rangeMin().asInt, range.rangeMax().asInt); + break; + } + + case MediaConstraintType::FrameRate: { + ASSERT(constraint.isDouble()); + if (!capabilities.supportsFrameRate()) + return 0; + + auto range = capabilities.frameRate(); + return downcast<DoubleConstraint>(constraint).fitnessDistance(range.rangeMin().asDouble, range.rangeMax().asDouble); + break; + } + + case MediaConstraintType::AspectRatio: { + ASSERT(constraint.isDouble()); + if (!capabilities.supportsAspectRatio()) + return 0; + + auto range = capabilities.aspectRatio(); + return downcast<DoubleConstraint>(constraint).fitnessDistance(range.rangeMin().asDouble, range.rangeMax().asDouble); + break; + } + + case MediaConstraintType::Volume: { + ASSERT(constraint.isDouble()); + if (!capabilities.supportsVolume()) + return 0; + + auto range = capabilities.volume(); + return downcast<DoubleConstraint>(constraint).fitnessDistance(range.rangeMin().asDouble, range.rangeMax().asDouble); + break; + } + + case MediaConstraintType::SampleRate: { + ASSERT(constraint.isInt()); + if (!capabilities.supportsSampleRate()) + return 0; + + auto range = capabilities.sampleRate(); + return downcast<IntConstraint>(constraint).fitnessDistance(range.rangeMin().asInt, range.rangeMax().asInt); + break; + } + + case MediaConstraintType::SampleSize: { + ASSERT(constraint.isInt()); + if (!capabilities.supportsSampleSize()) + return 0; + + auto range = capabilities.sampleSize(); + return downcast<IntConstraint>(constraint).fitnessDistance(range.rangeMin().asInt, range.rangeMax().asInt); + break; + } + + case MediaConstraintType::FacingMode: { + ASSERT(constraint.isString()); + if (!capabilities.supportsFacingMode()) + return 0; + + auto& modes = capabilities.facingMode(); + Vector<String> supportedModes; + supportedModes.reserveInitialCapacity(modes.size()); + for (auto& mode : modes) + supportedModes.uncheckedAppend(RealtimeMediaSourceSettings::facingMode(mode)); + return downcast<StringConstraint>(constraint).fitnessDistance(supportedModes); + break; + } + + case MediaConstraintType::EchoCancellation: { + ASSERT(constraint.isBoolean()); + if (!capabilities.supportsEchoCancellation()) + return 0; + + bool echoCancellationReadWrite = capabilities.echoCancellation() == RealtimeMediaSourceCapabilities::EchoCancellation::ReadWrite; + return downcast<BooleanConstraint>(constraint).fitnessDistance(echoCancellationReadWrite); + break; + } + + case MediaConstraintType::DeviceId: { + ASSERT(constraint.isString()); + if (!capabilities.supportsDeviceId()) + return 0; + + return downcast<StringConstraint>(constraint).fitnessDistance(m_id); + break; + } + + case MediaConstraintType::GroupId: { + ASSERT(constraint.isString()); + if (!capabilities.supportsDeviceId()) + return 0; + + return downcast<StringConstraint>(constraint).fitnessDistance(settings().groupId()); + break; + } + + case MediaConstraintType::Unknown: + // Unknown (or unsupported) constraints should be ignored. + break; + } + + return 0; +} + +template <typename ValueType> +static void applyNumericConstraint(const NumericConstraint<ValueType>& constraint, ValueType current, ValueType capabilityMin, ValueType capabilityMax, RealtimeMediaSource* source, void (RealtimeMediaSource::*applier)(ValueType)) +{ + ValueType value = constraint.valueForCapabilityRange(current, capabilityMin, capabilityMax); + if (value != current) + (source->*applier)(value); +} + +void RealtimeMediaSource::applySizeAndFrameRate(std::optional<int> width, std::optional<int> height, std::optional<double> frameRate) +{ + if (width) + setWidth(width.value()); + if (height) + setHeight(height.value()); + if (frameRate) + setFrameRate(frameRate.value()); +} + +void RealtimeMediaSource::applyConstraint(const MediaConstraint& constraint) +{ + RealtimeMediaSourceCapabilities& capabilities = *this->capabilities(); + switch (constraint.constraintType()) { + case MediaConstraintType::Width: { + ASSERT(constraint.isInt()); + if (!capabilities.supportsWidth()) + return; + + auto range = capabilities.width(); + applyNumericConstraint(downcast<IntConstraint>(constraint), size().width(), range.rangeMin().asInt, range.rangeMax().asInt, this, &RealtimeMediaSource::setWidth); + break; + } + + case MediaConstraintType::Height: { + ASSERT(constraint.isInt()); + if (!capabilities.supportsHeight()) + return; + + auto range = capabilities.height(); + applyNumericConstraint(downcast<IntConstraint>(constraint), size().height(), range.rangeMin().asInt, range.rangeMax().asInt, this, &RealtimeMediaSource::setHeight); + break; + } + + case MediaConstraintType::FrameRate: { + ASSERT(constraint.isDouble()); + if (!capabilities.supportsFrameRate()) + return; + + auto range = capabilities.frameRate(); + applyNumericConstraint(downcast<DoubleConstraint>(constraint), frameRate(), range.rangeMin().asDouble, range.rangeMax().asDouble, this, &RealtimeMediaSource::setFrameRate); + break; + } + + case MediaConstraintType::AspectRatio: { + ASSERT(constraint.isDouble()); + if (!capabilities.supportsAspectRatio()) + return; + + auto range = capabilities.aspectRatio(); + applyNumericConstraint(downcast<DoubleConstraint>(constraint), aspectRatio(), range.rangeMin().asDouble, range.rangeMax().asDouble, this, &RealtimeMediaSource::setAspectRatio); + break; + } + + case MediaConstraintType::Volume: { + ASSERT(constraint.isDouble()); + if (!capabilities.supportsVolume()) + return; + + auto range = capabilities.volume(); + applyNumericConstraint(downcast<DoubleConstraint>(constraint), volume(), range.rangeMin().asDouble, range.rangeMax().asDouble, this, &RealtimeMediaSource::setVolume); + break; + } + + case MediaConstraintType::SampleRate: { + ASSERT(constraint.isInt()); + if (!capabilities.supportsSampleRate()) + return; + + auto range = capabilities.sampleRate(); + applyNumericConstraint(downcast<IntConstraint>(constraint), sampleRate(), range.rangeMin().asInt, range.rangeMax().asInt, this, &RealtimeMediaSource::setSampleRate); + break; + } + + case MediaConstraintType::SampleSize: { + ASSERT(constraint.isInt()); + if (!capabilities.supportsSampleSize()) + return; + + auto range = capabilities.sampleSize(); + applyNumericConstraint(downcast<IntConstraint>(constraint), sampleSize(), range.rangeMin().asInt, range.rangeMax().asInt, this, &RealtimeMediaSource::setSampleSize); + break; + } + + case MediaConstraintType::EchoCancellation: { + ASSERT(constraint.isBoolean()); + if (!capabilities.supportsEchoCancellation()) + return; + + bool setting; + const BooleanConstraint& boolConstraint = downcast<BooleanConstraint>(constraint); + if (boolConstraint.getExact(setting) || boolConstraint.getIdeal(setting)) + setEchoCancellation(setting); + break; + } + + case MediaConstraintType::FacingMode: { + ASSERT(constraint.isString()); + if (!capabilities.supportsFacingMode()) + return; + + auto& supportedModes = capabilities.facingMode(); + auto filter = [supportedModes](const String& modeString) { + auto mode = RealtimeMediaSourceSettings::videoFacingModeEnum(modeString); + for (auto& supportedMode : supportedModes) { + if (mode == supportedMode) + return true; + } + return false; + }; + + auto modeString = downcast<StringConstraint>(constraint).find(filter); + if (!modeString.isEmpty()) + setFacingMode(RealtimeMediaSourceSettings::videoFacingModeEnum(modeString)); + break; + } + + case MediaConstraintType::DeviceId: + case MediaConstraintType::GroupId: + ASSERT(constraint.isString()); + // There is nothing to do here, neither can be changed. + break; + + case MediaConstraintType::Unknown: + break; + } +} + +bool RealtimeMediaSource::selectSettings(const MediaConstraints& constraints, FlattenedConstraint& candidates, String& failedConstraint) +{ + // https://w3c.github.io/mediacapture-main/#dfn-selectsettings + // + // 1. Each constraint specifies one or more values (or a range of values) for its property. + // A property may appear more than once in the list of 'advanced' ConstraintSets. If an + // empty object or list has been given as the value for a constraint, it must be interpreted + // as if the constraint were not specified (in other words, an empty constraint == no constraint). + // + // Note that unknown properties are discarded by WebIDL, which means that unknown/unsupported required + // constraints will silently disappear. To avoid this being a surprise, application authors are + // expected to first use the getSupportedConstraints() method as shown in the Examples below. + + // 2. Let object be the ConstrainablePattern object on which this algorithm is applied. Let copy be an + // unconstrained copy of object (i.e., copy should behave as if it were object with all ConstraintSets + // removed.) + + // 3. For every possible settings dictionary of copy compute its fitness distance, treating bare values of + // properties as ideal values. Let candidates be the set of settings dictionaries for which the fitness + // distance is finite. + + failedConstraint = emptyString(); + + // Check width, height, and frame rate separately, because while they may be supported individually the combination may not be supported. + if (!supportsSizeAndFrameRate(constraints.mandatoryConstraints().width(), constraints.mandatoryConstraints().height(), constraints.mandatoryConstraints().frameRate(), failedConstraint)) + return false; + + constraints.mandatoryConstraints().filter([&](const MediaConstraint& constraint) { + if (constraint.constraintType() == MediaConstraintType::Width || constraint.constraintType() == MediaConstraintType::Height || constraint.constraintType() == MediaConstraintType::FrameRate) { + candidates.set(constraint); + return false; + } + + if (std::isinf(fitnessDistance(constraint))) { + failedConstraint = constraint.name(); + return true; + } + + candidates.set(constraint); + return false; + }); + + if (!failedConstraint.isEmpty()) + return false; + + // 4. If candidates is empty, return undefined as the result of the SelectSettings() algorithm. + if (candidates.isEmpty()) + return true; + + // 5. Iterate over the 'advanced' ConstraintSets in newConstraints in the order in which they were specified. + // For each ConstraintSet: + + // 5.1 compute the fitness distance between it and each settings dictionary in candidates, treating bare + // values of properties as exact. + Vector<std::pair<double, MediaTrackConstraintSetMap>> supportedConstraints; + double minimumDistance = std::numeric_limits<double>::infinity(); + + for (const auto& advancedConstraint : constraints.advancedConstraints()) { + double constraintDistance = 0; + bool supported = false; + + advancedConstraint.forEach([&](const MediaConstraint& constraint) { + double distance = fitnessDistance(constraint); + constraintDistance += distance; + if (!std::isinf(distance)) + supported = true; + }); + + if (constraintDistance < minimumDistance) + minimumDistance = constraintDistance; + + // 5.2 If the fitness distance is finite for one or more settings dictionaries in candidates, keep those + // settings dictionaries in candidates, discarding others. + // If the fitness distance is infinite for all settings dictionaries in candidates, ignore this ConstraintSet. + if (supported) + supportedConstraints.append({constraintDistance, advancedConstraint}); + } + + // 6. Select one settings dictionary from candidates, and return it as the result of the SelectSettings() algorithm. + // The UA should use the one with the smallest fitness distance, as calculated in step 3. + if (!std::isinf(minimumDistance)) { + supportedConstraints.removeAllMatching([&](const std::pair<double, MediaTrackConstraintSetMap>& pair) -> bool { + return pair.first > minimumDistance; + }); + + if (!supportedConstraints.isEmpty()) { + auto& advancedConstraint = supportedConstraints[0].second; + advancedConstraint.forEach([&](const MediaConstraint& constraint) { + candidates.merge(constraint); + }); + } + } + + return true; +} + +bool RealtimeMediaSource::supportsConstraints(const MediaConstraints& constraints, String& invalidConstraint) +{ + ASSERT(constraints.isValid()); + + FlattenedConstraint candidates; + if (!selectSettings(constraints, candidates, invalidConstraint)) + return false; + + return true; +} + +void RealtimeMediaSource::applyConstraints(const FlattenedConstraint& constraints) +{ + if (constraints.isEmpty()) + return; + + beginConfiguration(); + + RealtimeMediaSourceCapabilities& capabilities = *this->capabilities(); + + std::optional<int> width; + if (const MediaConstraint* constraint = constraints.find(MediaConstraintType::Width)) { + ASSERT(constraint->isInt()); + if (capabilities.supportsWidth()) { + auto range = capabilities.width(); + width = downcast<IntConstraint>(*constraint).valueForCapabilityRange(size().width(), range.rangeMin().asInt, range.rangeMax().asInt); + } + } + + std::optional<int> height; + if (const MediaConstraint* constraint = constraints.find(MediaConstraintType::Height)) { + ASSERT(constraint->isInt()); + if (capabilities.supportsHeight()) { + auto range = capabilities.height(); + height = downcast<IntConstraint>(*constraint).valueForCapabilityRange(size().height(), range.rangeMin().asInt, range.rangeMax().asInt); + } + } + + std::optional<double> frameRate; + if (const MediaConstraint* constraint = constraints.find(MediaConstraintType::FrameRate)) { + ASSERT(constraint->isDouble()); + if (capabilities.supportsFrameRate()) { + auto range = capabilities.frameRate(); + frameRate = downcast<DoubleConstraint>(*constraint).valueForCapabilityRange(this->frameRate(), range.rangeMin().asDouble, range.rangeMax().asDouble); + } + } + if (width || height || frameRate) + applySizeAndFrameRate(WTFMove(width), WTFMove(height), WTFMove(frameRate)); + + for (auto& variant : constraints) { + if (variant.constraintType() == MediaConstraintType::Width || variant.constraintType() == MediaConstraintType::Height || variant.constraintType() == MediaConstraintType::FrameRate) + continue; + + applyConstraint(variant); + } + + commitConfiguration(); +} + +std::optional<std::pair<String, String>> RealtimeMediaSource::applyConstraints(const MediaConstraints& constraints) +{ + ASSERT(constraints.isValid()); + + FlattenedConstraint candidates; + String failedConstraint; + if (!selectSettings(constraints, candidates, failedConstraint)) + return { { failedConstraint, ASCIILiteral("Constraint not supported") } }; + + applyConstraints(candidates); + return std::nullopt; +} + +void RealtimeMediaSource::applyConstraints(const MediaConstraints& constraints, SuccessHandler successHandler, FailureHandler failureHandler) +{ + auto result = applyConstraints(constraints); + if (!result && successHandler) + successHandler(); + else if (result && failureHandler) + failureHandler(result.value().first, result.value().second); +} + +void RealtimeMediaSource::setWidth(int width) +{ + if (width == m_size.width()) + return; + + int height = m_aspectRatio ? width / m_aspectRatio : m_size.height(); + if (!applySize(IntSize(width, height))) + return; + + m_size.setWidth(width); + if (m_aspectRatio) + m_size.setHeight(width / m_aspectRatio); + + settingsDidChange(); +} + +void RealtimeMediaSource::setHeight(int height) +{ + if (height == m_size.height()) + return; + + int width = m_aspectRatio ? height * m_aspectRatio : m_size.width(); + if (!applySize(IntSize(width, height))) + return; + + if (m_aspectRatio) + m_size.setWidth(width); + m_size.setHeight(height); + + settingsDidChange(); +} + +void RealtimeMediaSource::setFrameRate(double rate) +{ + if (m_frameRate == rate || !applyFrameRate(rate)) + return; + + m_frameRate = rate; + settingsDidChange(); +} + +void RealtimeMediaSource::setAspectRatio(double ratio) +{ + if (m_aspectRatio == ratio || !applyAspectRatio(ratio)) + return; + + m_aspectRatio = ratio; + m_size.setHeight(m_size.width() / ratio); + settingsDidChange(); +} + +void RealtimeMediaSource::setFacingMode(RealtimeMediaSourceSettings::VideoFacingMode mode) +{ + if (m_facingMode == mode || !applyFacingMode(mode)) + return; + + m_facingMode = mode; + settingsDidChange(); +} + +void RealtimeMediaSource::setVolume(double volume) +{ + if (m_volume == volume || !applyVolume(volume)) + return; + + m_volume = volume; + settingsDidChange(); +} + +void RealtimeMediaSource::setSampleRate(int rate) +{ + if (m_sampleRate == rate || !applySampleRate(rate)) + return; + + m_sampleRate = rate; + settingsDidChange(); +} + +void RealtimeMediaSource::setSampleSize(int size) +{ + if (m_sampleSize == size || !applySampleSize(size)) + return; + + m_sampleSize = size; + settingsDidChange(); +} + +void RealtimeMediaSource::setEchoCancellation(bool echoCancellation) +{ + if (m_echoCancellation == echoCancellation || !applyEchoCancellation(echoCancellation)) + return; + + m_echoCancellation = echoCancellation; + settingsDidChange(); +} + +void RealtimeMediaSource::scheduleDeferredTask(std::function<void()>&& function) +{ + ASSERT(function); + callOnMainThread([weakThis = createWeakPtr(), function = WTFMove(function)] { + if (!weakThis) + return; + + function(); + }); +} + +} // namespace WebCore + +#endif // ENABLE(MEDIA_STREAM) diff --git a/Source/WebCore/platform/mediastream/RealtimeMediaSource.h b/Source/WebCore/platform/mediastream/RealtimeMediaSource.h new file mode 100644 index 000000000..29d3d8327 --- /dev/null +++ b/Source/WebCore/platform/mediastream/RealtimeMediaSource.h @@ -0,0 +1,229 @@ +/* + * Copyright (C) 2011 Ericsson AB. All rights reserved. + * Copyright (C) 2012 Google Inc. All rights reserved. + * Copyright (C) 2013 Apple Inc. All rights reserved. + * Copyright (C) 2013 Nokia Corporation and/or its subsidiary(-ies). + * + * 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 RealtimeMediaSource_h +#define RealtimeMediaSource_h + +#if ENABLE(MEDIA_STREAM) + +#include "AudioSourceProvider.h" +#include "Image.h" +#include "MediaConstraints.h" +#include "MediaSample.h" +#include "PlatformLayer.h" +#include "RealtimeMediaSourceCapabilities.h" +#include <wtf/RefCounted.h> +#include <wtf/Vector.h> +#include <wtf/WeakPtr.h> +#include <wtf/text/WTFString.h> + +namespace WTF { +class MediaTime; +} + +namespace WebCore { + +class AudioStreamDescription; +class FloatRect; +class GraphicsContext; +class MediaStreamPrivate; +class PlatformAudioData; +class RealtimeMediaSourceSettings; + +class RealtimeMediaSource : public RefCounted<RealtimeMediaSource> { +public: + class Observer { + public: + virtual ~Observer() { } + + // Source state changes. + virtual void sourceStopped() { } + virtual void sourceMutedChanged() { } + virtual void sourceEnabledChanged() { } + virtual void sourceSettingsChanged() { } + + // Observer state queries. + virtual bool preventSourceFromStopping() { return false; } + + // Called on the main thread. + virtual void videoSampleAvailable(MediaSample&) { } + + // May be called on a background thread. + virtual void audioSamplesAvailable(const MediaTime&, const PlatformAudioData&, const AudioStreamDescription&, size_t /*numberOfFrames*/) { } + }; + + virtual ~RealtimeMediaSource() { } + + const String& id() const { return m_id; } + + const String& persistentID() const { return m_persistentID; } + virtual void setPersistentID(const String& persistentID) { m_persistentID = persistentID; } + + enum Type { None, Audio, Video }; + Type type() const { return m_type; } + + virtual const String& name() const { return m_name; } + virtual void setName(const String& name) { m_name = name; } + + virtual unsigned fitnessScore() const { return m_fitnessScore; } + virtual void setFitnessScore(const unsigned fitnessScore) { m_fitnessScore = fitnessScore; } + + virtual RefPtr<RealtimeMediaSourceCapabilities> capabilities() const = 0; + virtual const RealtimeMediaSourceSettings& settings() const = 0; + + using SuccessHandler = std::function<void()>; + using FailureHandler = std::function<void(const String& badConstraint, const String& errorString)>; + void applyConstraints(const MediaConstraints&, SuccessHandler, FailureHandler); + std::optional<std::pair<String, String>> applyConstraints(const MediaConstraints&); + + virtual bool supportsConstraints(const MediaConstraints&, String&); + + virtual void settingsDidChange(); + + void videoSampleAvailable(MediaSample&); + void audioSamplesAvailable(const MediaTime&, const PlatformAudioData&, const AudioStreamDescription&, size_t); + + bool stopped() const { return m_stopped; } + + virtual bool muted() const { return m_muted; } + virtual void setMuted(bool); + + virtual bool enabled() const { return m_enabled; } + virtual void setEnabled(bool); + + virtual bool readonly() const; + virtual void setReadonly(bool readonly) { m_readonly = readonly; } + + virtual bool remote() const { return m_remote; } + virtual void setRemote(bool remote) { m_remote = remote; } + + void addObserver(Observer&); + void removeObserver(Observer&); + + virtual void startProducingData() { } + virtual void stopProducingData() { } + virtual bool isProducingData() const { return false; } + + void stop(Observer* callingObserver = nullptr); + void requestStop(Observer* callingObserver = nullptr); + + virtual void reset(); + + virtual AudioSourceProvider* audioSourceProvider() { return nullptr; } + + virtual RefPtr<Image> currentFrameImage() { return nullptr; } + virtual void paintCurrentFrameInContext(GraphicsContext&, const FloatRect&) { } + + void setWidth(int); + void setHeight(int); + const IntSize& size() const { return m_size; } + virtual bool applySize(const IntSize&) { return false; } + + double frameRate() const { return m_frameRate; } + void setFrameRate(double); + virtual bool applyFrameRate(double) { return false; } + + double aspectRatio() const { return m_aspectRatio; } + void setAspectRatio(double); + virtual bool applyAspectRatio(double) { return false; } + + RealtimeMediaSourceSettings::VideoFacingMode facingMode() const { return m_facingMode; } + void setFacingMode(RealtimeMediaSourceSettings::VideoFacingMode); + virtual bool applyFacingMode(RealtimeMediaSourceSettings::VideoFacingMode) { return false; } + + double volume() const { return m_volume; } + void setVolume(double); + virtual bool applyVolume(double) { return false; } + + int sampleRate() const { return m_sampleRate; } + void setSampleRate(int); + virtual bool applySampleRate(int) { return false; } + + int sampleSize() const { return m_sampleSize; } + void setSampleSize(int); + virtual bool applySampleSize(int) { return false; } + + bool echoCancellation() const { return m_echoCancellation; } + void setEchoCancellation(bool); + virtual bool applyEchoCancellation(bool) { return false; } + +protected: + RealtimeMediaSource(const String& id, Type, const String& name); + + void scheduleDeferredTask(std::function<void()>&&); + + virtual void beginConfiguration() { } + virtual void commitConfiguration() { } + + virtual bool selectSettings(const MediaConstraints&, FlattenedConstraint&, String&); + virtual double fitnessDistance(const MediaConstraint&); + virtual bool supportsSizeAndFrameRate(std::optional<IntConstraint> width, std::optional<IntConstraint> height, std::optional<DoubleConstraint>, String&); + virtual bool supportsSizeAndFrameRate(std::optional<int> width, std::optional<int> height, std::optional<double>); + virtual void applyConstraint(const MediaConstraint&); + virtual void applyConstraints(const FlattenedConstraint&); + virtual void applySizeAndFrameRate(std::optional<int> width, std::optional<int> height, std::optional<double>); + + bool m_muted { false }; + bool m_enabled { true }; + +private: + WeakPtr<RealtimeMediaSource> createWeakPtr() { return m_weakPtrFactory.createWeakPtr(); } + + WeakPtrFactory<RealtimeMediaSource> m_weakPtrFactory; + String m_id; + String m_persistentID; + Type m_type; + String m_name; + Vector<Observer*> m_observers; + IntSize m_size; + double m_frameRate { 30 }; + double m_aspectRatio { 0 }; + double m_volume { 1 }; + double m_sampleRate { 0 }; + double m_sampleSize { 0 }; + unsigned m_fitnessScore { 0 }; + RealtimeMediaSourceSettings::VideoFacingMode m_facingMode { RealtimeMediaSourceSettings::User}; + + bool m_echoCancellation { false }; + bool m_stopped { false }; + bool m_readonly { false }; + bool m_remote { false }; + bool m_pendingSettingsDidChangeNotification { false }; + bool m_suppressNotifications { true }; +}; + +} // namespace WebCore + +#endif // ENABLE(MEDIA_STREAM) + +#endif // RealtimeMediaSource_h diff --git a/Source/WebCore/platform/mediastream/RealtimeMediaSourceCapabilities.h b/Source/WebCore/platform/mediastream/RealtimeMediaSourceCapabilities.h new file mode 100644 index 000000000..2f22d4894 --- /dev/null +++ b/Source/WebCore/platform/mediastream/RealtimeMediaSourceCapabilities.h @@ -0,0 +1,192 @@ +/* + * Copyright (C) 2013 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 RealtimeMediaSourceCapabilities_h +#define RealtimeMediaSourceCapabilities_h + +#if ENABLE(MEDIA_STREAM) + +#include "RealtimeMediaSourceSettings.h" +#include <wtf/RefCounted.h> +#include <wtf/Vector.h> +#include <wtf/text/AtomicString.h> + +namespace WebCore { + +class CapabilityValueOrRange { +public: + + enum Type { + Undefined, + Double, + ULong, + DoubleRange, + ULongRange, + }; + Type type() const { return m_type; } + + union ValueUnion { + int asInt; + double asDouble; + }; + + CapabilityValueOrRange() + : m_type(Undefined) + { + } + + CapabilityValueOrRange(double value) + : m_type(Double) + { + m_minOrValue.asDouble = value; + } + + CapabilityValueOrRange(int value) + : m_type(ULong) + { + m_minOrValue.asInt = value; + } + + CapabilityValueOrRange(double min, double max) + : m_type(DoubleRange) + { + m_minOrValue.asDouble = min; + m_max.asDouble = max; + } + + CapabilityValueOrRange(int min, int max) + : m_type(ULongRange) + { + m_minOrValue.asInt = min; + m_max.asInt = max; + } + + const ValueUnion& rangeMin() const + { + ASSERT(m_type == DoubleRange || m_type == ULongRange); + return m_minOrValue; + } + + const ValueUnion& rangeMax() const + { + ASSERT(m_type == DoubleRange || m_type == ULongRange); + return m_max; + } + + const ValueUnion& value() const + { + ASSERT(m_type == Double || m_type == ULong); + return m_minOrValue; + } + +private: + ValueUnion m_minOrValue; + ValueUnion m_max; + Type m_type; +}; + +class RealtimeMediaSourceCapabilities : public RefCounted<RealtimeMediaSourceCapabilities> { +public: + static PassRefPtr<RealtimeMediaSourceCapabilities> create(const RealtimeMediaSourceSupportedConstraints& supportedConstraints) + { + return adoptRef(new RealtimeMediaSourceCapabilities(supportedConstraints)); + } + + ~RealtimeMediaSourceCapabilities() { } + + bool supportsWidth() const { return m_supportedConstraints.supportsWidth(); } + const CapabilityValueOrRange& width() { return m_width; } + void setWidth(const CapabilityValueOrRange& width) { m_width = width; } + + bool supportsHeight() const { return m_supportedConstraints.supportsHeight(); } + const CapabilityValueOrRange& height() { return m_height; } + void setHeight(const CapabilityValueOrRange& height) { m_height = height; } + + bool supportsFrameRate() const { return m_supportedConstraints.supportsFrameRate(); } + const CapabilityValueOrRange& frameRate() { return m_frameRate; } + void setFrameRate(const CapabilityValueOrRange& frameRate) { m_frameRate = frameRate; } + + bool supportsFacingMode() const { return m_supportedConstraints.supportsFacingMode(); } + const Vector<RealtimeMediaSourceSettings::VideoFacingMode>& facingMode() { return m_facingMode; } + void addFacingMode(RealtimeMediaSourceSettings::VideoFacingMode mode) { m_facingMode.append(mode); } + + bool supportsAspectRatio() const { return m_supportedConstraints.supportsAspectRatio(); } + const CapabilityValueOrRange& aspectRatio() { return m_aspectRatio; } + void setAspectRatio(const CapabilityValueOrRange& aspectRatio) { m_aspectRatio = aspectRatio; } + + bool supportsVolume() const { return m_supportedConstraints.supportsVolume(); } + const CapabilityValueOrRange& volume() { return m_volume; } + void setVolume(const CapabilityValueOrRange& volume) { m_volume = volume; } + + bool supportsSampleRate() const { return m_supportedConstraints.supportsSampleRate(); } + const CapabilityValueOrRange& sampleRate() { return m_sampleRate; } + void setSampleRate(const CapabilityValueOrRange& sampleRate) { m_sampleRate = sampleRate; } + + bool supportsSampleSize() const { return m_supportedConstraints.supportsSampleSize(); } + const CapabilityValueOrRange& sampleSize() { return m_sampleSize; } + void setSampleSize(const CapabilityValueOrRange& sampleSize) { m_sampleSize = sampleSize; } + + enum class EchoCancellation { + ReadOnly = 0, + ReadWrite = 1, + }; + bool supportsEchoCancellation() const { return m_supportedConstraints.supportsEchoCancellation(); } + EchoCancellation echoCancellation() { return m_echoCancellation; } + void setEchoCancellation(EchoCancellation echoCancellation) { m_echoCancellation = echoCancellation; } + + bool supportsDeviceId() const { return m_supportedConstraints.supportsDeviceId(); } + const AtomicString& deviceId() { return m_deviceId; } + void setDeviceId(const AtomicString& id) { m_deviceId = id; } + + bool supportsGroupId() const { return m_supportedConstraints.supportsGroupId(); } + const AtomicString& groupId() { return m_groupId; } + void setGroupId(const AtomicString& id) { m_groupId = id; } + +private: + RealtimeMediaSourceCapabilities(const RealtimeMediaSourceSupportedConstraints& supportedConstraints) + : m_supportedConstraints(supportedConstraints) + { + } + + CapabilityValueOrRange m_width; + CapabilityValueOrRange m_height; + CapabilityValueOrRange m_aspectRatio; + CapabilityValueOrRange m_frameRate; + Vector<RealtimeMediaSourceSettings::VideoFacingMode> m_facingMode; + CapabilityValueOrRange m_volume; + CapabilityValueOrRange m_sampleRate; + CapabilityValueOrRange m_sampleSize; + EchoCancellation m_echoCancellation; + AtomicString m_deviceId; + AtomicString m_groupId; + + const RealtimeMediaSourceSupportedConstraints& m_supportedConstraints; +}; + +} // namespace WebCore + +#endif // RealtimeMediaSourceCapabilities_h + +#endif diff --git a/Source/WebCore/platform/mediastream/MediaStreamCenter.cpp b/Source/WebCore/platform/mediastream/RealtimeMediaSourceCenter.cpp index 389138c9b..236f65654 100644 --- a/Source/WebCore/platform/mediastream/MediaStreamCenter.cpp +++ b/Source/WebCore/platform/mediastream/RealtimeMediaSourceCenter.cpp @@ -32,38 +32,37 @@ #include "config.h" #if ENABLE(MEDIA_STREAM) - -#include "MediaStreamCenter.h" +#include "RealtimeMediaSourceCenter.h" #include "MediaStreamPrivate.h" namespace WebCore { -static MediaStreamCenter*& mediaStreamCenterOverride() +static RealtimeMediaSourceCenter*& mediaStreamCenterOverride() { - static MediaStreamCenter* override; + static RealtimeMediaSourceCenter* override; return override; } -MediaStreamCenter& MediaStreamCenter::shared() +RealtimeMediaSourceCenter& RealtimeMediaSourceCenter::singleton() { - MediaStreamCenter* override = mediaStreamCenterOverride(); + RealtimeMediaSourceCenter* override = mediaStreamCenterOverride(); if (override) return *override; - return MediaStreamCenter::platformCenter(); + return RealtimeMediaSourceCenter::platformCenter(); } -void MediaStreamCenter::setSharedStreamCenter(MediaStreamCenter* center) +void RealtimeMediaSourceCenter::setSharedStreamCenterOverride(RealtimeMediaSourceCenter* center) { mediaStreamCenterOverride() = center; } -MediaStreamCenter::MediaStreamCenter() +RealtimeMediaSourceCenter::RealtimeMediaSourceCenter() { } -MediaStreamCenter::~MediaStreamCenter() +RealtimeMediaSourceCenter::~RealtimeMediaSourceCenter() { } diff --git a/Source/WebCore/platform/mediastream/RealtimeMediaSourceCenter.h b/Source/WebCore/platform/mediastream/RealtimeMediaSourceCenter.h new file mode 100644 index 000000000..81e8f434d --- /dev/null +++ b/Source/WebCore/platform/mediastream/RealtimeMediaSourceCenter.h @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2011 Ericsson AB. All rights reserved. + * Copyright (C) 2012 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. + * 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 RealtimeMediaSourceCenter_h +#define RealtimeMediaSourceCenter_h + +#if ENABLE(MEDIA_STREAM) + +#include "RealtimeMediaSource.h" +#include "RealtimeMediaSourceSupportedConstraints.h" +#include <wtf/PassRefPtr.h> +#include <wtf/text/WTFString.h> + +namespace WebCore { + +class CaptureDevice; +class MediaConstraints; +class RealtimeMediaSourceSettings; +class RealtimeMediaSourceSupportedConstraints; +class TrackSourceInfo; + +class RealtimeMediaSourceCenter { +public: + virtual ~RealtimeMediaSourceCenter(); + + WEBCORE_EXPORT static RealtimeMediaSourceCenter& singleton(); + static void setSharedStreamCenterOverride(RealtimeMediaSourceCenter*); + + using ValidConstraintsHandler = std::function<void(const Vector<String>&& audioDeviceUIDs, const Vector<String>&& videoDeviceUIDs)>; + using InvalidConstraintsHandler = std::function<void(const String& invalidConstraint)>; + virtual void validateRequestConstraints(ValidConstraintsHandler, InvalidConstraintsHandler, const MediaConstraints& audioConstraints, const MediaConstraints& videoConstraints) = 0; + + using NewMediaStreamHandler = std::function<void(RefPtr<MediaStreamPrivate>&&)>; + virtual void createMediaStream(NewMediaStreamHandler, const String& audioDeviceID, const String& videoDeviceID, const MediaConstraints* audioConstraints, const MediaConstraints* videoConstraints) = 0; + + virtual Vector<CaptureDevice> getMediaStreamDevices() = 0; + + virtual const RealtimeMediaSourceSupportedConstraints& supportedConstraints() { return m_supportedConstraints; } + +protected: + RealtimeMediaSourceCenter(); + + static RealtimeMediaSourceCenter& platformCenter(); + RealtimeMediaSourceSupportedConstraints m_supportedConstraints; +}; + +} // namespace WebCore + +#endif // ENABLE(MEDIA_STREAM) + +#endif // RealtimeMediaSourceCenter_h diff --git a/Source/WebCore/platform/mediastream/MediaStreamSourceStates.cpp b/Source/WebCore/platform/mediastream/RealtimeMediaSourceSettings.cpp index 04e4ce3ce..7872901ef 100644 --- a/Source/WebCore/platform/mediastream/MediaStreamSourceStates.cpp +++ b/Source/WebCore/platform/mediastream/RealtimeMediaSourceSettings.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 Apple Inc. All rights reserved. + * Copyright (C) 2013-2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -31,30 +31,47 @@ #include "config.h" #if ENABLE(MEDIA_STREAM) - -#include "MediaStreamSourceStates.h" +#include "RealtimeMediaSourceSettings.h" #include <wtf/NeverDestroyed.h> namespace WebCore { -const AtomicString& MediaStreamSourceStates::facingMode(MediaStreamSourceStates::VideoFacingMode mode) +static const AtomicString& userFacing() { static NeverDestroyed<AtomicString> userFacing("user", AtomicString::ConstructFromLiteral); + return userFacing; +} +static const AtomicString& environmentFacing() +{ static NeverDestroyed<AtomicString> environmentFacing("environment", AtomicString::ConstructFromLiteral); + return environmentFacing; +} + +static const AtomicString& leftFacing() +{ static NeverDestroyed<AtomicString> leftFacing("left", AtomicString::ConstructFromLiteral); + return leftFacing; +} + +static const AtomicString& rightFacing() +{ static NeverDestroyed<AtomicString> rightFacing("right", AtomicString::ConstructFromLiteral); - + return rightFacing; +} + +const AtomicString& RealtimeMediaSourceSettings::facingMode(RealtimeMediaSourceSettings::VideoFacingMode mode) +{ switch (mode) { - case MediaStreamSourceStates::User: - return userFacing; - case MediaStreamSourceStates::Environment: - return environmentFacing; - case MediaStreamSourceStates::Left: - return leftFacing; - case MediaStreamSourceStates::Right: - return rightFacing; - case MediaStreamSourceStates::Unknown: + case RealtimeMediaSourceSettings::User: + return userFacing(); + case RealtimeMediaSourceSettings::Environment: + return environmentFacing(); + case RealtimeMediaSourceSettings::Left: + return leftFacing(); + case RealtimeMediaSourceSettings::Right: + return rightFacing(); + case RealtimeMediaSourceSettings::Unknown: return emptyAtom; } @@ -62,23 +79,18 @@ const AtomicString& MediaStreamSourceStates::facingMode(MediaStreamSourceStates: return emptyAtom; } -const AtomicString& MediaStreamSourceStates::sourceType(MediaStreamSourceStates::SourceType sourceType) +RealtimeMediaSourceSettings::VideoFacingMode RealtimeMediaSourceSettings::videoFacingModeEnum(const String& mode) { - static NeverDestroyed<AtomicString> none("none", AtomicString::ConstructFromLiteral); - static NeverDestroyed<AtomicString> camera("camera", AtomicString::ConstructFromLiteral); - static NeverDestroyed<AtomicString> microphone("microphone", AtomicString::ConstructFromLiteral); - - switch (sourceType) { - case MediaStreamSourceStates::None: - return none; - case MediaStreamSourceStates::Camera: - return camera; - case MediaStreamSourceStates::Microphone: - return microphone; - } - - ASSERT_NOT_REACHED(); - return emptyAtom; + if (mode == userFacing()) + return RealtimeMediaSourceSettings::User; + if (mode == environmentFacing()) + return RealtimeMediaSourceSettings::Environment; + if (mode == leftFacing()) + return RealtimeMediaSourceSettings::Left; + if (mode == rightFacing()) + return RealtimeMediaSourceSettings::Right; + + return RealtimeMediaSourceSettings::Unknown; } } // namespace WebCore diff --git a/Source/WebCore/platform/mediastream/RealtimeMediaSourceSettings.h b/Source/WebCore/platform/mediastream/RealtimeMediaSourceSettings.h new file mode 100644 index 000000000..7b5dc717c --- /dev/null +++ b/Source/WebCore/platform/mediastream/RealtimeMediaSourceSettings.h @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2013-2015 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 RealtimeMediaSourceSettings_h +#define RealtimeMediaSourceSettings_h + +#if ENABLE(MEDIA_STREAM) + +#include "RealtimeMediaSourceSupportedConstraints.h" +#include <wtf/RefCounted.h> +#include <wtf/Vector.h> +#include <wtf/text/AtomicString.h> + +namespace WebCore { + +class RealtimeMediaSourceSettings { +public: + enum SourceType { None, Camera, Microphone }; + enum VideoFacingMode { Unknown, User, Environment, Left, Right }; + + static const AtomicString& facingMode(RealtimeMediaSourceSettings::VideoFacingMode); + + static RealtimeMediaSourceSettings::VideoFacingMode videoFacingModeEnum(const String&); + + explicit RealtimeMediaSourceSettings() + { + } + + bool supportsWidth() const { return m_supportedConstraints.supportsWidth(); } + unsigned long width() const { return m_width; } + void setWidth(unsigned long width) { m_width = width; } + + bool supportsHeight() const { return m_supportedConstraints.supportsHeight(); } + unsigned long height() const { return m_height; } + void setHeight(unsigned long height) { m_height = height; } + + bool supportsAspectRatio() const { return m_supportedConstraints.supportsAspectRatio(); } + float aspectRatio() const { return m_aspectRatio; } + void setAspectRatio(float aspectRatio) { m_aspectRatio = aspectRatio; } + + bool supportsFrameRate() const { return m_supportedConstraints.supportsFrameRate(); } + float frameRate() const { return m_frameRate; } + void setFrameRate(float frameRate) { m_frameRate = frameRate; } + + bool supportsFacingMode() const { return m_supportedConstraints.supportsFacingMode(); } + VideoFacingMode facingMode() const { return m_facingMode; } + void setFacingMode(VideoFacingMode facingMode) { m_facingMode = facingMode; } + + bool supportsVolume() const { return m_supportedConstraints.supportsVolume(); } + double volume() const { return m_volume; } + void setVolume(double volume) { m_volume = volume; } + + bool supportsSampleRate() const { return m_supportedConstraints.supportsSampleRate(); } + unsigned long sampleRate() const { return m_sampleRate; } + void setSampleRate(unsigned long sampleRate) { m_sampleRate = sampleRate; } + + bool supportsSampleSize() const { return m_supportedConstraints.supportsSampleSize(); } + unsigned long sampleSize() const { return m_sampleSize; } + void setSampleSize(unsigned long sampleSize) { m_sampleSize = sampleSize; } + + bool supportsEchoCancellation() const { return m_supportedConstraints.supportsEchoCancellation(); } + bool echoCancellation() const { return m_echoCancellation; } + void setEchoCancellation(bool echoCancellation) { m_echoCancellation = echoCancellation; } + + bool supportsDeviceId() const { return m_supportedConstraints.supportsDeviceId(); } + const AtomicString& deviceId() const { return m_deviceId; } + void setDeviceId(const AtomicString& deviceId) { m_deviceId = deviceId; } + + bool supportsGroupId() const { return m_supportedConstraints.supportsGroupId(); } + const AtomicString& groupId() const { return m_groupId; } + void setGroupId(const AtomicString& groupId) { m_groupId = groupId; } + + void setSupportedConstraits(const RealtimeMediaSourceSupportedConstraints& supportedConstraints) { m_supportedConstraints = supportedConstraints; } + +private: + unsigned long m_width { 0 }; + unsigned long m_height { 0 }; + float m_aspectRatio { 0 }; + float m_frameRate { 0 }; + VideoFacingMode m_facingMode { Unknown }; + double m_volume { 0 }; + unsigned long m_sampleRate { 0 }; + unsigned long m_sampleSize { 0 }; + bool m_echoCancellation { 0 }; + + AtomicString m_deviceId; + AtomicString m_groupId; + + RealtimeMediaSourceSupportedConstraints m_supportedConstraints; +}; + +} // namespace WebCore + +#endif // RealtimeMediaSourceSettings_h + +#endif diff --git a/Source/WebCore/platform/mediastream/RealtimeMediaSourceSupportedConstraints.cpp b/Source/WebCore/platform/mediastream/RealtimeMediaSourceSupportedConstraints.cpp new file mode 100644 index 000000000..73775a0f2 --- /dev/null +++ b/Source/WebCore/platform/mediastream/RealtimeMediaSourceSupportedConstraints.cpp @@ -0,0 +1,139 @@ +/* + * Copyright (C) 2015 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 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 "RealtimeMediaSourceSupportedConstraints.h" + +#if ENABLE(MEDIA_STREAM) + +#include <wtf/HashMap.h> +#include <wtf/NeverDestroyed.h> +#include <wtf/text/AtomicString.h> +#include <wtf/text/AtomicStringHash.h> + +namespace WebCore { + +const AtomicString& RealtimeMediaSourceSupportedConstraints::nameForConstraint(MediaConstraintType constraint) +{ + static NeverDestroyed<AtomicString> unknownConstraintName(emptyString()); + static NeverDestroyed<AtomicString> widthConstraintName("width"); + static NeverDestroyed<AtomicString> heightConstraintName("height"); + static NeverDestroyed<AtomicString> aspectRatioConstraintName("aspectRatio"); + static NeverDestroyed<AtomicString> frameRateConstraintName("frameRate"); + static NeverDestroyed<AtomicString> facingModeConstraintName("facingMode"); + static NeverDestroyed<AtomicString> volumeConstraintName("volume"); + static NeverDestroyed<AtomicString> sampleRateConstraintName("sampleRate"); + static NeverDestroyed<AtomicString> sampleSizeConstraintName("sampleSize"); + static NeverDestroyed<AtomicString> echoCancellationConstraintName("echoCancellation"); + static NeverDestroyed<AtomicString> deviceIdConstraintName("deviceId"); + static NeverDestroyed<AtomicString> groupIdConstraintName("groupId"); + switch (constraint) { + case MediaConstraintType::Unknown: + return unknownConstraintName; + case MediaConstraintType::Width: + return widthConstraintName; + case MediaConstraintType::Height: + return heightConstraintName; + case MediaConstraintType::AspectRatio: + return aspectRatioConstraintName; + case MediaConstraintType::FrameRate: + return frameRateConstraintName; + case MediaConstraintType::FacingMode: + return facingModeConstraintName; + case MediaConstraintType::Volume: + return volumeConstraintName; + case MediaConstraintType::SampleRate: + return sampleRateConstraintName; + case MediaConstraintType::SampleSize: + return sampleSizeConstraintName; + case MediaConstraintType::EchoCancellation: + return echoCancellationConstraintName; + case MediaConstraintType::DeviceId: + return deviceIdConstraintName; + case MediaConstraintType::GroupId: + return groupIdConstraintName; + } + + ASSERT_NOT_REACHED(); + return emptyAtom; +} + +MediaConstraintType RealtimeMediaSourceSupportedConstraints::constraintFromName(const String& constraintName) +{ + static NeverDestroyed<HashMap<AtomicString, MediaConstraintType>> nameToConstraintMap; + HashMap<AtomicString, MediaConstraintType>& nameToConstraintMapValue = nameToConstraintMap.get(); + if (!nameToConstraintMapValue.size()) { + nameToConstraintMapValue.add("width", MediaConstraintType::Width); + nameToConstraintMapValue.add("height", MediaConstraintType::Height); + nameToConstraintMapValue.add("aspectRatio", MediaConstraintType::AspectRatio); + nameToConstraintMapValue.add("frameRate", MediaConstraintType::FrameRate); + nameToConstraintMapValue.add("facingMode", MediaConstraintType::FacingMode); + nameToConstraintMapValue.add("volume", MediaConstraintType::Volume); + nameToConstraintMapValue.add("sampleRate", MediaConstraintType::SampleRate); + nameToConstraintMapValue.add("sampleSize", MediaConstraintType::SampleSize); + nameToConstraintMapValue.add("echoCancellation", MediaConstraintType::EchoCancellation); + nameToConstraintMapValue.add("deviceId", MediaConstraintType::DeviceId); + nameToConstraintMapValue.add("groupId", MediaConstraintType::GroupId); + } + auto iter = nameToConstraintMapValue.find(constraintName); + return iter == nameToConstraintMapValue.end() ? MediaConstraintType::Unknown : iter->value; +} + +bool RealtimeMediaSourceSupportedConstraints::supportsConstraint(MediaConstraintType constraint) const +{ + switch (constraint) { + case MediaConstraintType::Unknown: + return false; + case MediaConstraintType::Width: + return supportsWidth(); + case MediaConstraintType::Height: + return supportsHeight(); + case MediaConstraintType::AspectRatio: + return supportsAspectRatio(); + case MediaConstraintType::FrameRate: + return supportsFrameRate(); + case MediaConstraintType::FacingMode: + return supportsFacingMode(); + case MediaConstraintType::Volume: + return supportsVolume(); + case MediaConstraintType::SampleRate: + return supportsSampleRate(); + case MediaConstraintType::SampleSize: + return supportsSampleSize(); + case MediaConstraintType::EchoCancellation: + return supportsEchoCancellation(); + case MediaConstraintType::DeviceId: + return supportsDeviceId(); + case MediaConstraintType::GroupId: + return supportsGroupId(); + } + + ASSERT_NOT_REACHED(); + return false; +} + +} // namespace WebCore + +#endif // ENABLE(MEDIA_STREAM) diff --git a/Source/WebCore/platform/mediastream/RealtimeMediaSourceSupportedConstraints.h b/Source/WebCore/platform/mediastream/RealtimeMediaSourceSupportedConstraints.h new file mode 100644 index 000000000..bfb54e6d6 --- /dev/null +++ b/Source/WebCore/platform/mediastream/RealtimeMediaSourceSupportedConstraints.h @@ -0,0 +1,117 @@ +/* + * Copyright (C) 2015 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. + * 3. Neither the name of Google Inc. 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 RealtimeMediaSourceSupportedConstraints_h +#define RealtimeMediaSourceSupportedConstraints_h + +#if ENABLE(MEDIA_STREAM) + +#include <wtf/text/WTFString.h> + +namespace WebCore { + +enum class MediaConstraintType { + Unknown, + Width, + Height, + AspectRatio, + FrameRate, + FacingMode, + Volume, + SampleRate, + SampleSize, + EchoCancellation, + DeviceId, + GroupId +}; + +class RealtimeMediaSourceSupportedConstraints { +public: + RealtimeMediaSourceSupportedConstraints() + { + } + + bool supportsWidth() const { return m_supportsWidth; } + void setSupportsWidth(bool value) { m_supportsWidth = value; } + + bool supportsHeight() const { return m_supportsHeight; } + void setSupportsHeight(bool value) { m_supportsHeight = value; } + + bool supportsAspectRatio() const { return m_supportsAspectRatio; } + void setSupportsAspectRatio(bool value) { m_supportsAspectRatio = value; } + + bool supportsFrameRate() const { return m_supportsFrameRate; } + void setSupportsFrameRate(bool value) { m_supportsFrameRate = value; } + + bool supportsFacingMode() const { return m_supportsFacingMode; } + void setSupportsFacingMode(bool value) { m_supportsFacingMode = value; } + + bool supportsVolume() const { return m_supportsVolume; } + void setSupportsVolume(bool value) { m_supportsVolume = value; } + + bool supportsSampleRate() const { return m_supportsSampleRate; } + void setSupportsSampleRate(bool value) { m_supportsSampleRate = value; } + + bool supportsSampleSize() const { return m_supportsSampleSize; } + void setSupportsSampleSize(bool value) { m_supportsSampleSize = value; } + + bool supportsEchoCancellation() const { return m_supportsEchoCancellation; } + void setSupportsEchoCancellation(bool value) { m_supportsEchoCancellation = value; } + + bool supportsDeviceId() const { return m_supportsDeviceId; } + void setSupportsDeviceId(bool value) { m_supportsDeviceId = value; } + + bool supportsGroupId() const { return m_supportsGroupId; } + void setSupportsGroupId(bool value) { m_supportsGroupId = value; } + + bool supportsConstraint(MediaConstraintType) const; + + static const AtomicString& nameForConstraint(MediaConstraintType); + static MediaConstraintType constraintFromName(const String&); + +private: + bool m_supportsWidth { false }; + bool m_supportsHeight { false }; + bool m_supportsAspectRatio { false }; + bool m_supportsFrameRate { false }; + bool m_supportsFacingMode { false }; + bool m_supportsVolume { false }; + bool m_supportsSampleRate { false }; + bool m_supportsSampleSize { false }; + bool m_supportsEchoCancellation { false }; + bool m_supportsDeviceId { false }; + bool m_supportsGroupId { false }; +}; + +} // namespace WebCore + +#endif // ENABLE(MEDIA_STREAM) + +#endif // RealtimeMediaSourceSupportedConstraints_h diff --git a/Source/WebCore/platform/mediastream/SDPProcessorScriptResource.cpp b/Source/WebCore/platform/mediastream/SDPProcessorScriptResource.cpp new file mode 100644 index 000000000..669ed2a76 --- /dev/null +++ b/Source/WebCore/platform/mediastream/SDPProcessorScriptResource.cpp @@ -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. + */ + +#include "config.h" + +#if ENABLE(WEB_RTC) +#include "SDPProcessorScriptResource.h" + +#include "SDPProcessorScriptsData.h" +#include <wtf/NeverDestroyed.h> + +namespace WebCore { + +namespace SDPProcessorScriptResource { + +const String& scriptString() +{ + static NeverDestroyed<const String> script(sdpJavaScript, sizeof(sdpJavaScript)); + return script; +} + +} // namespace SDPProcessorScriptResource + +} // namespace WebCore + +#endif // ENABLE(WEB_RTC) diff --git a/Source/WebCore/platform/mediastream/RTCStatsRequest.h b/Source/WebCore/platform/mediastream/SDPProcessorScriptResource.h index b53dcf1a7..cb5443bb0 100644 --- a/Source/WebCore/platform/mediastream/RTCStatsRequest.h +++ b/Source/WebCore/platform/mediastream/SDPProcessorScriptResource.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 Google 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 @@ -11,7 +11,7 @@ * 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 Google Inc. nor the names of its contributors + * 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. * @@ -28,35 +28,23 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef RTCStatsRequest_h -#define RTCStatsRequest_h +#ifndef SDPProcessorScriptResource_h +#define SDPProcessorScriptResource_h -#if ENABLE(MEDIA_STREAM) +#if ENABLE(WEB_RTC) -#include <wtf/PassRefPtr.h> -#include <wtf/RefCounted.h> #include <wtf/text/WTFString.h> namespace WebCore { -class MediaStreamTrack; -class RTCStatsResponseBase; +namespace SDPProcessorScriptResource { -class RTCStatsRequest : public RefCounted<RTCStatsRequest> { -public: - virtual ~RTCStatsRequest() { } +const String& scriptString(); - virtual PassRefPtr<RTCStatsResponseBase> createResponse() = 0; - virtual bool hasSelector() = 0; - virtual MediaStreamTrack* track() = 0; - virtual void requestSucceeded(PassRefPtr<RTCStatsResponseBase>) = 0; - -protected: - RTCStatsRequest() { } -}; +} // namespace SDPProcessorScriptResource } // namespace WebCore -#endif // ENABLE(MEDIA_STREAM) +#endif // ENABLE(WEB_RTC) -#endif // RTCStatsRequest_h +#endif // SDPProcessorScriptResource_h diff --git a/Source/WebCore/platform/mediastream/VideoTrackPrivateMediaStream.h b/Source/WebCore/platform/mediastream/VideoTrackPrivateMediaStream.h new file mode 100644 index 000000000..19a6b66ac --- /dev/null +++ b/Source/WebCore/platform/mediastream/VideoTrackPrivateMediaStream.h @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2015-2017 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. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#if ENABLE(VIDEO_TRACK) && ENABLE(MEDIA_STREAM) + +#include "MediaStreamTrackPrivate.h" +#include "VideoTrackPrivate.h" + +namespace WebCore { + +class VideoTrackPrivateMediaStream final : public VideoTrackPrivate { + WTF_MAKE_NONCOPYABLE(VideoTrackPrivateMediaStream) +public: + static RefPtr<VideoTrackPrivateMediaStream> create(MediaStreamTrackPrivate& streamTrack) + { + return adoptRef(*new VideoTrackPrivateMediaStream(streamTrack)); + } + + void setTrackIndex(int index) { m_index = index; } + + MediaStreamTrackPrivate& streamTrack() { return m_streamTrack.get(); } + + MediaTime timelineOffset() const { return m_timelineOffset; } + void setTimelineOffset(const MediaTime& offset) { m_timelineOffset = offset; } + +private: + VideoTrackPrivateMediaStream(MediaStreamTrackPrivate& track) + : m_streamTrack(track) + , m_id(track.id()) + , m_label(track.label()) + , m_timelineOffset(MediaTime::invalidTime()) + { + } + + Kind kind() const final { return Kind::Main; } + AtomicString id() const final { return m_id; } + AtomicString label() const final { return m_label; } + AtomicString language() const final { return emptyAtom; } + int trackIndex() const final { return m_index; } + + Ref<MediaStreamTrackPrivate> m_streamTrack; + AtomicString m_id; + AtomicString m_label; + int m_index { 0 }; + MediaTime m_timelineOffset; +}; + +} + +#endif // ENABLE(VIDEO_TRACK) && ENABLE(MEDIA_STREAM) diff --git a/Source/WebCore/platform/mediastream/libwebrtc/LibWebRTCAudioFormat.h b/Source/WebCore/platform/mediastream/libwebrtc/LibWebRTCAudioFormat.h new file mode 100644 index 000000000..e49107f10 --- /dev/null +++ b/Source/WebCore/platform/mediastream/libwebrtc/LibWebRTCAudioFormat.h @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2017 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. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#if USE(LIBWEBRTC) + +namespace WebCore { + +namespace LibWebRTCAudioFormat { + +static const size_t sampleRate = 48000; +static const size_t chunkSampleCount = 480; +static const size_t sampleSize = 16; +static const size_t sampleByteSize = 2; +static const bool isFloat = false; +static const bool isBigEndian = false; +static const bool isNonInterleaved = false; + +} + +} // namespace WebCore + +#endif // USE(LIBWEBRTC) diff --git a/Source/WebCore/platform/mediastream/libwebrtc/LibWebRTCAudioModule.cpp b/Source/WebCore/platform/mediastream/libwebrtc/LibWebRTCAudioModule.cpp new file mode 100644 index 000000000..8ba6f4333 --- /dev/null +++ b/Source/WebCore/platform/mediastream/libwebrtc/LibWebRTCAudioModule.cpp @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2017 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. 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 "LibWebRTCAudioModule.h" + +#if USE(LIBWEBRTC) + +namespace WebCore { + +LibWebRTCAudioModule::LibWebRTCAudioModule() + : m_audioTaskRunner(rtc::Thread::Create()) +{ + m_audioTaskRunner->Start(); +} + +int32_t LibWebRTCAudioModule::RegisterAudioCallback(webrtc::AudioTransport* audioTransport) +{ + m_audioTransport = audioTransport; + return 0; +} + +void LibWebRTCAudioModule::OnMessage(rtc::Message* message) +{ + ASSERT_UNUSED(message, message->message_id == 1); + StartPlayoutOnAudioThread(); +} + +int32_t LibWebRTCAudioModule::StartPlayout() +{ + if (!m_isPlaying && m_audioTaskRunner) { + m_audioTaskRunner->Post(RTC_FROM_HERE, this, 1); + m_isPlaying = true; + } + return 0; +} + +int32_t LibWebRTCAudioModule::StopPlayout() +{ + if (m_isPlaying) + m_isPlaying = false; + return 0; +} + +// libwebrtc uses 10ms frames. +const unsigned samplingRate = 48000; +const unsigned frameLengthMs = 10; +const unsigned samplesPerFrame = samplingRate * frameLengthMs / 1000; +const unsigned pollSamples = 5; +const unsigned pollInterval = 5 * frameLengthMs; +const unsigned channels = 2; +const unsigned bytesPerSample = 2; + +void LibWebRTCAudioModule::StartPlayoutOnAudioThread() +{ + while (true) { + PollFromSource(); + m_audioTaskRunner->SleepMs(pollInterval); + if (!m_isPlaying) + return; + } +} + +void LibWebRTCAudioModule::PollFromSource() +{ + if (!m_audioTransport) + return; + + for (unsigned i = 0; i < pollSamples; i++) { + int64_t elapsedTime = -1; + int64_t ntpTime = -1; + char data[(bytesPerSample * channels * samplesPerFrame)]; + m_audioTransport->PullRenderData(bytesPerSample * 8, samplingRate, channels, samplesPerFrame, data, &elapsedTime, &ntpTime); + } +} + +} // namespace WebCore + +#endif // USE(LIBWEBRTC) diff --git a/Source/WebCore/platform/mediastream/libwebrtc/LibWebRTCAudioModule.h b/Source/WebCore/platform/mediastream/libwebrtc/LibWebRTCAudioModule.h new file mode 100644 index 000000000..95988609d --- /dev/null +++ b/Source/WebCore/platform/mediastream/libwebrtc/LibWebRTCAudioModule.h @@ -0,0 +1,162 @@ +/* + * Copyright (C) 2017 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. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#if USE(LIBWEBRTC) + +#include "LibWebRTCMacros.h" +#include <webrtc/base/messagehandler.h> +#include <webrtc/base/thread.h> +#include <webrtc/modules/audio_device/include/audio_device.h> + +namespace WebCore { + +// LibWebRTCAudioModule is pulling streamed data to ensure audio data is passed to the audio track. +class LibWebRTCAudioModule final : public webrtc::AudioDeviceModule, private rtc::MessageHandler { +public: + LibWebRTCAudioModule(); + +private: + template<typename U> U shouldNotBeCalled(U value) const + { + ASSERT_NOT_REACHED(); + return value; + } + + int32_t AddRef() const final { return 1; } + int32_t Release() const final { return 1; } + void OnMessage(rtc::Message*); + + // webrtc::AudioDeviceModule API + int32_t StartPlayout() final; + int32_t StopPlayout() final; + int32_t RegisterAudioCallback(webrtc::AudioTransport*) final; + bool Playing() const final { return m_isPlaying; } + + int64_t TimeUntilNextProcess() final { return std::numeric_limits<int64_t>::max(); } + void Process() final { } + int32_t ActiveAudioLayer(AudioLayer*) const final { return shouldNotBeCalled(-1); } + ErrorCode LastError() const final { return kAdmErrNone; } + int32_t RegisterEventObserver(webrtc::AudioDeviceObserver*) final { return 0; } + int32_t Init() final { return 0; } + int32_t Terminate() final { return 0; } + bool Initialized() const final { return true; } + int16_t PlayoutDevices() final { return 0; } + int16_t RecordingDevices() final { return 0; } + int32_t PlayoutDeviceName(uint16_t, char[webrtc::kAdmMaxDeviceNameSize], char[webrtc::kAdmMaxGuidSize]) final { return 0; } + int32_t RecordingDeviceName(uint16_t, char[webrtc::kAdmMaxDeviceNameSize], char[webrtc::kAdmMaxGuidSize]) final { return 0; } + int32_t SetPlayoutDevice(uint16_t) final { return 0; } + int32_t SetPlayoutDevice(WindowsDeviceType) final { return 0; } + int32_t SetRecordingDevice(uint16_t) final { return 0; } + int32_t SetRecordingDevice(WindowsDeviceType) final { return 0; } + int32_t PlayoutIsAvailable(bool*) final { return shouldNotBeCalled(-1); } + int32_t InitPlayout() final { return 0; } + bool PlayoutIsInitialized() const final { return true; } + int32_t RecordingIsAvailable(bool*) final { return shouldNotBeCalled(-1); } + int32_t InitRecording() final { return 0; } + bool RecordingIsInitialized() const final { return false; } + int32_t StartRecording() final { return 0; } + int32_t StopRecording() final { return 0; } + bool Recording() const final { return 0; } + int32_t SetAGC(bool) final { return 0; } + bool AGC() const final { return shouldNotBeCalled(0); } + int32_t SetWaveOutVolume(uint16_t, uint16_t) final { return shouldNotBeCalled(-1); } + int32_t WaveOutVolume(uint16_t*, uint16_t*) const final { return shouldNotBeCalled(-1); } + int32_t InitSpeaker() final { return 0; } + bool SpeakerIsInitialized() const final { return false; } + int32_t InitMicrophone() final { return 0; } + bool MicrophoneIsInitialized() const final { return false; } + int32_t SpeakerVolumeIsAvailable(bool*) final { return shouldNotBeCalled(-1); } + int32_t SetSpeakerVolume(uint32_t) final { return shouldNotBeCalled(-1); } + int32_t SpeakerVolume(uint32_t*) const final { return shouldNotBeCalled(-1); } + int32_t MaxSpeakerVolume(uint32_t*) const final { return shouldNotBeCalled(-1); } + int32_t MinSpeakerVolume(uint32_t*) const final { return shouldNotBeCalled(-1); } + int32_t SpeakerVolumeStepSize(uint16_t*) const final { return shouldNotBeCalled(-1); } + int32_t MicrophoneVolumeIsAvailable(bool*) final { return shouldNotBeCalled(-1); } + int32_t SetMicrophoneVolume(uint32_t) final { return shouldNotBeCalled(-1); } + int32_t MicrophoneVolume(uint32_t*) const final { return shouldNotBeCalled(-1); } + int32_t MaxMicrophoneVolume(uint32_t*) const final { return shouldNotBeCalled(-1); } + int32_t MinMicrophoneVolume(uint32_t*) const final { return shouldNotBeCalled(-1); } + int32_t MicrophoneVolumeStepSize(uint16_t*) const final { return shouldNotBeCalled(-1); } + int32_t SpeakerMuteIsAvailable(bool*) final { return shouldNotBeCalled(-1); } + int32_t SetSpeakerMute(bool) final { return shouldNotBeCalled(-1); } + int32_t SpeakerMute(bool*) const final { return shouldNotBeCalled(-1); } + int32_t MicrophoneMuteIsAvailable(bool*) final { return shouldNotBeCalled(-1); } + int32_t SetMicrophoneMute(bool) final { return shouldNotBeCalled(-1); } + int32_t MicrophoneMute(bool*) const final { return shouldNotBeCalled(-1); } + int32_t MicrophoneBoostIsAvailable(bool*) final { return shouldNotBeCalled(-1); } + int32_t SetMicrophoneBoost(bool) final { return shouldNotBeCalled(-1); } + int32_t MicrophoneBoost(bool*) const final { return shouldNotBeCalled(-1); } + int32_t StereoPlayoutIsAvailable(bool* available) const final { *available = false; return 0; } + int32_t SetStereoPlayout(bool) final { return 0; } + int32_t StereoPlayout(bool*) const final { return shouldNotBeCalled(-1); } + int32_t StereoRecordingIsAvailable(bool* available) const final { *available = false; return 0; } + int32_t SetStereoRecording(bool) final { return 0; } + int32_t StereoRecording(bool*) const final { return shouldNotBeCalled(-1); } + int32_t SetRecordingChannel(const ChannelType) final { return 0; } + int32_t RecordingChannel(ChannelType*) const final { return shouldNotBeCalled(-1); } + int32_t SetPlayoutBuffer(const BufferType, uint16_t) final { return shouldNotBeCalled(-1); } + int32_t PlayoutBuffer(BufferType*, uint16_t*) const final { return shouldNotBeCalled(-1); } + int32_t PlayoutDelay(uint16_t* delay) const final { *delay = 0; return 0; } + int32_t RecordingDelay(uint16_t*) const final { return shouldNotBeCalled(-1); } + int32_t CPULoad(uint16_t*) const final { return shouldNotBeCalled(-1); } + int32_t StartRawOutputFileRecording(const char[webrtc::kAdmMaxFileNameSize]) final { return shouldNotBeCalled(-1); } + int32_t StopRawOutputFileRecording() final { return shouldNotBeCalled(-1); } + int32_t StartRawInputFileRecording(const char[webrtc::kAdmMaxFileNameSize]) final { return shouldNotBeCalled(-1); } + int32_t StopRawInputFileRecording() final { return shouldNotBeCalled(-1); } + int32_t SetRecordingSampleRate(const uint32_t) final { return shouldNotBeCalled(-1); } + int32_t RecordingSampleRate(uint32_t*) const final { return shouldNotBeCalled(-1); } + int32_t SetPlayoutSampleRate(const uint32_t) final { return shouldNotBeCalled(-1); } + int32_t PlayoutSampleRate(uint32_t*) const final { return shouldNotBeCalled(-1); } + int32_t ResetAudioDevice() final { return shouldNotBeCalled(-1); } + int32_t SetLoudspeakerStatus(bool) final { return shouldNotBeCalled(-1); } + int32_t GetLoudspeakerStatus(bool*) const final { return shouldNotBeCalled(-1); } + bool BuiltInAECIsAvailable() const final { return false; } + bool BuiltInAGCIsAvailable() const final { return false; } + bool BuiltInNSIsAvailable() const final { return false; } + int32_t EnableBuiltInAEC(bool) final { return shouldNotBeCalled(-1); } + int32_t EnableBuiltInAGC(bool) final { return shouldNotBeCalled(-1); } + int32_t EnableBuiltInNS(bool) final { return shouldNotBeCalled(-1); } + +#if defined(WEBRTC_IOS) + int GetPlayoutAudioParameters(webrtc::AudioParameters*) const final { return shouldNotBeCalled(-1); } + int GetRecordAudioParameters(webrtc::AudioParameters*) const final { return shouldNotBeCalled(-1); } +#endif + +private: + void StartPlayoutOnAudioThread(); + + void PollFromSource(); + + std::unique_ptr<rtc::Thread> m_audioTaskRunner; + + bool m_isPlaying = false; + webrtc::AudioTransport* m_audioTransport = nullptr; +}; + +} // namespace WebCore + +#endif // USE(LIBWEBRTC) diff --git a/Source/WebCore/platform/mediastream/libwebrtc/LibWebRTCMacros.h b/Source/WebCore/platform/mediastream/libwebrtc/LibWebRTCMacros.h new file mode 100644 index 000000000..982d94be5 --- /dev/null +++ b/Source/WebCore/platform/mediastream/libwebrtc/LibWebRTCMacros.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2017 Apple Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted, provided that the following conditions + * are required to be 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 Apple Inc. 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 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. AND ITS CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#if USE(LIBWEBRTC) + +#if PLATFORM(IOS) +#define WEBRTC_IOS +#endif + +#if PLATFORM(MAC) +#define WEBRTC_MAC +#endif + +#define WEBRTC_POSIX 1 +#define _COMMON_INCLUDED_ + +#endif // USE(LIBWEBRTC) diff --git a/Source/WebCore/platform/mediastream/libwebrtc/LibWebRTCProvider.cpp b/Source/WebCore/platform/mediastream/libwebrtc/LibWebRTCProvider.cpp new file mode 100644 index 000000000..0095c517f --- /dev/null +++ b/Source/WebCore/platform/mediastream/libwebrtc/LibWebRTCProvider.cpp @@ -0,0 +1,160 @@ +/* + * Copyright (C) 2017 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. 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 "LibWebRTCProvider.h" + +#if USE(LIBWEBRTC) + +#include "LibWebRTCAudioModule.h" +#include <webrtc/api/peerconnectionfactory.h> +#include <webrtc/api/peerconnectionfactoryproxy.h> +#include <webrtc/base/physicalsocketserver.h> +#include <webrtc/p2p/client/basicportallocator.h> +#include <webrtc/sdk/objc/Framework/Classes/videotoolboxvideocodecfactory.h> +#include <wtf/Function.h> +#include <wtf/NeverDestroyed.h> + +namespace WebCore { + +struct PeerConnectionFactoryAndThreads : public rtc::MessageHandler { + std::unique_ptr<LibWebRTCAudioModule> audioDeviceModule; + std::unique_ptr<rtc::Thread> networkThread; + std::unique_ptr<rtc::Thread> signalingThread; + rtc::scoped_refptr<webrtc::PeerConnectionFactoryInterface> factory; + bool networkThreadWithSocketServer { false }; +private: + void OnMessage(rtc::Message*); +}; + +static inline PeerConnectionFactoryAndThreads& staticFactoryAndThreads() +{ + static NeverDestroyed<PeerConnectionFactoryAndThreads> factoryAndThreads; + return factoryAndThreads.get(); +} + +struct ThreadMessageData : public rtc::MessageData { + ThreadMessageData(Function<void()>&& callback) + : callback(WTFMove(callback)) + { } + Function<void()> callback; +}; + +void PeerConnectionFactoryAndThreads::OnMessage(rtc::Message* message) +{ + ASSERT(message->message_id == 1); + static_cast<ThreadMessageData*>(message->pdata)->callback(); +} + +void LibWebRTCProvider::callOnWebRTCNetworkThread(Function<void()>&& callback) +{ + PeerConnectionFactoryAndThreads& threads = staticFactoryAndThreads(); + threads.networkThread->Post(RTC_FROM_HERE, &threads, 1, new ThreadMessageData(WTFMove(callback))); +} + +void LibWebRTCProvider::callOnWebRTCSignalingThread(Function<void()>&& callback) +{ + PeerConnectionFactoryAndThreads& threads = staticFactoryAndThreads(); + threads.signalingThread->Post(RTC_FROM_HERE, &threads, 1, new ThreadMessageData(WTFMove(callback))); +} + +static void initializePeerConnectionFactoryAndThreads() +{ + auto& factoryAndThreads = staticFactoryAndThreads(); + + ASSERT(!factoryAndThreads.factory); + + auto thread = rtc::Thread::Create(); + factoryAndThreads.networkThread = factoryAndThreads.networkThreadWithSocketServer ? rtc::Thread::CreateWithSocketServer() : rtc::Thread::Create(); + bool result = factoryAndThreads.networkThread->Start(); + ASSERT_UNUSED(result, result); + + factoryAndThreads.signalingThread = rtc::Thread::Create(); + result = factoryAndThreads.signalingThread->Start(); + ASSERT(result); + + factoryAndThreads.audioDeviceModule = std::make_unique<LibWebRTCAudioModule>(); + + factoryAndThreads.factory = webrtc::CreatePeerConnectionFactory(factoryAndThreads.networkThread.get(), factoryAndThreads.networkThread.get(), factoryAndThreads.signalingThread.get(), factoryAndThreads.audioDeviceModule.get(), new webrtc::VideoToolboxVideoEncoderFactory(), new webrtc::VideoToolboxVideoDecoderFactory()); + + ASSERT(factoryAndThreads.factory); +} + +webrtc::PeerConnectionFactoryInterface& LibWebRTCProvider::factory() +{ + if (!staticFactoryAndThreads().factory) + initializePeerConnectionFactoryAndThreads(); + return *staticFactoryAndThreads().factory; +} + +void LibWebRTCProvider::setPeerConnectionFactory(rtc::scoped_refptr<webrtc::PeerConnectionFactoryInterface>&& factory) +{ + if (!staticFactoryAndThreads().factory) + initializePeerConnectionFactoryAndThreads(); + + staticFactoryAndThreads().factory = webrtc::PeerConnectionFactoryProxy::Create(staticFactoryAndThreads().signalingThread.get(), WTFMove(factory)); +} + +static rtc::scoped_refptr<webrtc::PeerConnectionInterface> createActualPeerConnection(webrtc::PeerConnectionObserver& observer, std::unique_ptr<cricket::BasicPortAllocator>&& portAllocator) +{ + ASSERT(staticFactoryAndThreads().factory); + + webrtc::PeerConnectionInterface::RTCConfiguration config; + // FIXME: Add a default configuration. + return staticFactoryAndThreads().factory->CreatePeerConnection(config, WTFMove(portAllocator), nullptr, &observer); +} + +rtc::scoped_refptr<webrtc::PeerConnectionInterface> LibWebRTCProvider::createPeerConnection(webrtc::PeerConnectionObserver& observer) +{ + // Default WK1 implementation. + auto& factoryAndThreads = staticFactoryAndThreads(); + if (!factoryAndThreads.factory) { + staticFactoryAndThreads().networkThreadWithSocketServer = true; + initializePeerConnectionFactoryAndThreads(); + } + ASSERT(staticFactoryAndThreads().networkThreadWithSocketServer); + + return createActualPeerConnection(observer, nullptr); +} + +rtc::scoped_refptr<webrtc::PeerConnectionInterface> LibWebRTCProvider::createPeerConnection(webrtc::PeerConnectionObserver& observer, rtc::NetworkManager& networkManager, rtc::PacketSocketFactory& packetSocketFactory) +{ + ASSERT(!staticFactoryAndThreads().networkThreadWithSocketServer); + + auto& factoryAndThreads = staticFactoryAndThreads(); + if (!factoryAndThreads.factory) + initializePeerConnectionFactoryAndThreads(); + + std::unique_ptr<cricket::BasicPortAllocator> portAllocator; + staticFactoryAndThreads().signalingThread->Invoke<void>(RTC_FROM_HERE, [&]() { + portAllocator.reset(new cricket::BasicPortAllocator(&networkManager, &packetSocketFactory)); + }); + + return createActualPeerConnection(observer, WTFMove(portAllocator)); +} + +} // namespace WebCore + +#endif // USE(LIBWEBRTC) diff --git a/Source/WebCore/platform/mediastream/libwebrtc/LibWebRTCProvider.h b/Source/WebCore/platform/mediastream/libwebrtc/LibWebRTCProvider.h new file mode 100644 index 000000000..dca1c2275 --- /dev/null +++ b/Source/WebCore/platform/mediastream/libwebrtc/LibWebRTCProvider.h @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2017 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. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include "LibWebRTCMacros.h" +#include <wtf/Forward.h> + +#if USE(LIBWEBRTC) + +#include <webrtc/api/peerconnectioninterface.h> +#include <webrtc/base/scoped_ref_ptr.h> + +namespace rtc { +class NetworkManager; +class PacketSocketFactory; +} + +namespace webrtc { +class PeerConnectionFactoryInterface; +} +#endif + +namespace WebCore { + +class WEBCORE_EXPORT LibWebRTCProvider { +public: + LibWebRTCProvider() = default; + virtual ~LibWebRTCProvider() = default; + +#if USE(LIBWEBRTC) + WEBCORE_EXPORT virtual rtc::scoped_refptr<webrtc::PeerConnectionInterface> createPeerConnection(webrtc::PeerConnectionObserver&); + + // FIXME: Make these methods not static. + static WEBCORE_EXPORT void callOnWebRTCNetworkThread(Function<void()>&&); + static WEBCORE_EXPORT void callOnWebRTCSignalingThread(Function<void()>&&); + static WEBCORE_EXPORT webrtc::PeerConnectionFactoryInterface& factory(); + // Used for mock testing + static void setPeerConnectionFactory(rtc::scoped_refptr<webrtc::PeerConnectionFactoryInterface>&&); + +protected: + WEBCORE_EXPORT rtc::scoped_refptr<webrtc::PeerConnectionInterface> createPeerConnection(webrtc::PeerConnectionObserver&, rtc::NetworkManager&, rtc::PacketSocketFactory&); +#endif +}; + +} // namespace WebCore 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/gstreamer/MediaStreamCenterGStreamer.cpp b/Source/WebCore/platform/mediastream/openwebrtc/RealtimeMediaSourceCenterOwr.h index 5e4f34e84..6cdd7d5fe 100644 --- a/Source/WebCore/platform/mediastream/gstreamer/MediaStreamCenterGStreamer.cpp +++ b/Source/WebCore/platform/mediastream/openwebrtc/RealtimeMediaSourceCenterOwr.h @@ -1,6 +1,8 @@ /* * 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 @@ -29,52 +31,47 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "config.h" +#ifndef RealtimeMediaSourceCenterOwr_h +#define RealtimeMediaSourceCenterOwr_h -#if ENABLE(MEDIA_STREAM) +#if ENABLE(MEDIA_STREAM) && USE(OPENWEBRTC) -#include "MediaStreamCenterGStreamer.h" +#include "RealtimeMediaSourceCenter.h" -#include "MediaStreamCreationClient.h" -#include "MediaStreamPrivate.h" -#include "MediaStreamSourceCapabilities.h" -#include "MediaStreamTrackSourcesRequestClient.h" -#include "NotImplemented.h" -#include <wtf/MainThread.h> +#include "RealtimeMediaSourceOwr.h" +#include <wtf/PassRefPtr.h> namespace WebCore { -MediaStreamCenter& MediaStreamCenter::platformCenter() -{ - ASSERT(isMainThread()); - DEFINE_STATIC_LOCAL(MediaStreamCenterGStreamer, center, ()); - return center; -} +class CaptureDevice; +class MediaStreamPrivate; +class RealtimeMediaSource; +class MediaStreamSourcesQueryClient; +class TrackSourceInfo; -MediaStreamCenterGStreamer::MediaStreamCenterGStreamer() -{ -} +class RealtimeMediaSourceCenterOwr final : public RealtimeMediaSourceCenter { +public: + RealtimeMediaSourceCenterOwr(); + ~RealtimeMediaSourceCenterOwr(); -MediaStreamCenterGStreamer::~MediaStreamCenterGStreamer() -{ -} + void validateRequestConstraints(ValidConstraintsHandler validHandler, InvalidConstraintsHandler invalidHandler, const MediaConstraints& audioConstraints, const MediaConstraints& videoConstraints) final; -void MediaStreamCenterGStreamer::validateRequestConstraints(PassRefPtr<MediaStreamCreationClient>, PassRefPtr<MediaConstraints>, PassRefPtr<MediaConstraints>) -{ - notImplemented(); -} - -void MediaStreamCenterGStreamer::createMediaStream(PassRefPtr<MediaStreamCreationClient>, PassRefPtr<MediaConstraints>, PassRefPtr<MediaConstraints>) -{ - notImplemented(); -} + void createMediaStream(NewMediaStreamHandler, const String& audioDeviceID, const String& videoDeviceID, const MediaConstraints* videoConstraints, const MediaConstraints* audioConstraints) final; -bool MediaStreamCenterGStreamer::getMediaStreamTrackSources(PassRefPtr<MediaStreamTrackSourcesRequestClient>) -{ - notImplemented(); - return false; -} + 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) +#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) |