diff options
Diffstat (limited to 'Source/WebCore/Modules/mediastream')
155 files changed, 8683 insertions, 5004 deletions
diff --git a/Source/WebCore/Modules/mediastream/AllAudioCapabilities.h b/Source/WebCore/Modules/mediastream/AllAudioCapabilities.h deleted file mode 100644 index 532956479..000000000 --- a/Source/WebCore/Modules/mediastream/AllAudioCapabilities.h +++ /dev/null @@ -1,59 +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 AllAudioCapabilities_h -#define AllAudioCapabilities_h - -#if ENABLE(MEDIA_STREAM) - -#include "MediaStreamCapabilities.h" -#include "MediaStreamSourceCapabilities.h" -#include <wtf/text/WTFString.h> - -namespace WebCore { - -class CapabilityRange; -class MediaStreamSourceCapabilities; - -class AllAudioCapabilities : public MediaStreamCapabilities { -public: - static RefPtr<AllAudioCapabilities> create(PassRefPtr<MediaStreamSourceCapabilities> capabilities) - { - return adoptRef(new AllAudioCapabilities(capabilities)); - } - virtual ~AllAudioCapabilities() { } - -private: - explicit AllAudioCapabilities(PassRefPtr<MediaStreamSourceCapabilities> capabilities) - : MediaStreamCapabilities(capabilities) - { - } -}; - -} // namespace WebCore - -#endif // AllAudioCapabilities_h - -#endif diff --git a/Source/WebCore/Modules/mediastream/AllVideoCapabilities.h b/Source/WebCore/Modules/mediastream/AllVideoCapabilities.h deleted file mode 100644 index 667f214f3..000000000 --- a/Source/WebCore/Modules/mediastream/AllVideoCapabilities.h +++ /dev/null @@ -1,57 +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 AllVideoCapabilities_h -#define AllVideoCapabilities_h - -#if ENABLE(MEDIA_STREAM) - -#include "MediaStreamCapabilities.h" - -namespace WebCore { - -class CapabilityRange; -class MediaStreamSourceCapabilities; - -class AllVideoCapabilities : public MediaStreamCapabilities { -public: - static RefPtr<AllVideoCapabilities> create(PassRefPtr<MediaStreamSourceCapabilities> capabilities) - { - return adoptRef(new AllVideoCapabilities(capabilities)); - } - virtual ~AllVideoCapabilities() { } - -private: - explicit AllVideoCapabilities(PassRefPtr<MediaStreamSourceCapabilities> capabilities) - : MediaStreamCapabilities(capabilities) - { - } -}; - -} // namespace WebCore - -#endif // AllVideoCapabilities_h - -#endif diff --git a/Source/WebCore/Modules/mediastream/AllVideoCapabilities.idl b/Source/WebCore/Modules/mediastream/AllVideoCapabilities.idl deleted file mode 100644 index 515137cff..000000000 --- a/Source/WebCore/Modules/mediastream/AllVideoCapabilities.idl +++ /dev/null @@ -1,38 +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. - */ - -[ - NoInterfaceObject, - Conditional=MEDIA_STREAM, - JSGenerateToJSObject, -] interface AllVideoCapabilities : MediaStreamCapabilities { - readonly attribute DOMString[] sourceType; - readonly attribute DOMString[] sourceId; - readonly attribute CapabilityRange width; - readonly attribute CapabilityRange height; - readonly attribute CapabilityRange frameRate; - readonly attribute CapabilityRange aspectRatio; - readonly attribute DOMString[] facingMode; -}; diff --git a/Source/WebCore/Modules/mediastream/AudioStreamTrack.cpp b/Source/WebCore/Modules/mediastream/AudioStreamTrack.cpp deleted file mode 100644 index 101b09cb1..000000000 --- a/Source/WebCore/Modules/mediastream/AudioStreamTrack.cpp +++ /dev/null @@ -1,71 +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. - */ - -#include "config.h" - -#if ENABLE(MEDIA_STREAM) - -#include "AudioStreamTrack.h" - -#include "Dictionary.h" -#include "ScriptExecutionContext.h" -#include <wtf/NeverDestroyed.h> - -namespace WebCore { - -RefPtr<AudioStreamTrack> AudioStreamTrack::create(ScriptExecutionContext& context, const Dictionary& audioConstraints) -{ - return adoptRef(new AudioStreamTrack(context, *MediaStreamTrackPrivate::create(0), &audioConstraints)); -} - -RefPtr<AudioStreamTrack> AudioStreamTrack::create(ScriptExecutionContext& context, MediaStreamTrackPrivate& privateTrack) -{ - return adoptRef(new AudioStreamTrack(context, privateTrack, 0)); -} - -RefPtr<AudioStreamTrack> AudioStreamTrack::create(MediaStreamTrack& track) -{ - return adoptRef(new AudioStreamTrack(track)); -} - -AudioStreamTrack::AudioStreamTrack(ScriptExecutionContext& context, MediaStreamTrackPrivate& privateTrack, const Dictionary* audioConstraints) - : MediaStreamTrack(context, privateTrack, audioConstraints) -{ -} - -AudioStreamTrack::AudioStreamTrack(MediaStreamTrack& track) - : MediaStreamTrack(track) -{ -} - -const AtomicString& AudioStreamTrack::kind() const -{ - static NeverDestroyed<AtomicString> audioKind("audio", AtomicString::ConstructFromLiteral); - return audioKind; -} - -} // namespace WebCore - -#endif // ENABLE(MEDIA_STREAM) diff --git a/Source/WebCore/Modules/mediastream/AudioStreamTrack.h b/Source/WebCore/Modules/mediastream/AudioStreamTrack.h deleted file mode 100644 index 79346c38a..000000000 --- a/Source/WebCore/Modules/mediastream/AudioStreamTrack.h +++ /dev/null @@ -1,59 +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 AudioStreamTrack_h -#define AudioStreamTrack_h - -#if ENABLE(MEDIA_STREAM) - -#include "MediaStreamTrack.h" -#include <wtf/RefCounted.h> -#include <wtf/Vector.h> - -namespace WebCore { - -class MediaStreamSource; -class ScriptExecutionContext; - -class AudioStreamTrack final : public MediaStreamTrack { -public: - static RefPtr<AudioStreamTrack> create(ScriptExecutionContext&, const Dictionary&); - static RefPtr<AudioStreamTrack> create(ScriptExecutionContext&, MediaStreamTrackPrivate&); - static RefPtr<AudioStreamTrack> create(MediaStreamTrack&); - - virtual ~AudioStreamTrack() { } - - virtual const AtomicString& kind() const override; - -private: - AudioStreamTrack(ScriptExecutionContext&, MediaStreamTrackPrivate&, const Dictionary*); - explicit AudioStreamTrack(MediaStreamTrack&); -}; - -} // namespace WebCore - -#endif // ENABLE(MEDIA_STREAM) - -#endif // AudioStreamTrack_h diff --git a/Source/WebCore/Modules/mediastream/AudioStreamTrack.idl b/Source/WebCore/Modules/mediastream/AudioStreamTrack.idl deleted file mode 100644 index 2f6e5411a..000000000 --- a/Source/WebCore/Modules/mediastream/AudioStreamTrack.idl +++ /dev/null @@ -1,31 +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. - */ - -[ - Conditional=MEDIA_STREAM, - Constructor(optional Dictionary audioConstraints), - ConstructorCallWith=ScriptExecutionContext, -] interface AudioStreamTrack : MediaStreamTrack { -}; diff --git a/Source/WebCore/Modules/mediastream/CapabilityRange.cpp b/Source/WebCore/Modules/mediastream/CapabilityRange.cpp deleted file mode 100644 index 6c125a47d..000000000 --- a/Source/WebCore/Modules/mediastream/CapabilityRange.cpp +++ /dev/null @@ -1,92 +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, 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. - * - */ - -#include "config.h" - -#if ENABLE(MEDIA_STREAM) - -#include "CapabilityRange.h" - -#include "JSDOMBinding.h" -#include "MediaSourceStates.h" -#include <bindings/ScriptValue.h> -#include <interpreter/CallFrame.h> -#include <runtime/JSCJSValue.h> - -using namespace JSC; - -namespace WebCore { - -RefPtr<CapabilityRange> CapabilityRange::create(const MediaStreamSourceCapabilityRange& rangeInfo) -{ - return adoptRef(new CapabilityRange(rangeInfo)); -} - -CapabilityRange::CapabilityRange(const MediaStreamSourceCapabilityRange& rangeInfo) - : m_rangeInfo(rangeInfo) -{ -} - -static Deprecated::ScriptValue scriptValue(ExecState* exec, const MediaStreamSourceCapabilityRange::ValueUnion& value, MediaStreamSourceCapabilityRange::Type type) -{ - // NOTE: the spec says: - // ... an implementation should make a reasonable attempt to translate and scale the hardware's setting - // onto the mapping provided by this specification. If this is not possible due to the user agent's - // inability to retrieve a given capability from a source, then for CapabilityRange-typed capabilities, - // the min and max fields will not be present on the returned dictionary, and the supported field will be false. - // We don't do this currently because I don't know of an instance where it isn't possible to retrieve a source - // capability, but when we have to deal with this we will need to mark CapabilityRange.min and CapabilityRange.max as - // "Custom" and return jsUndefined() from the custom getter to support it. - - switch (type) { - case MediaStreamSourceCapabilityRange::Float: - return Deprecated::ScriptValue(exec->vm(), JSValue(value.asFloat)); - break; - case MediaStreamSourceCapabilityRange::ULong: - return Deprecated::ScriptValue(exec->vm(), JSValue(value.asULong)); - break; - case MediaStreamSourceCapabilityRange::Undefined: - return Deprecated::ScriptValue(exec->vm(), jsUndefined()); - break; - } - - ASSERT_NOT_REACHED(); - return Deprecated::ScriptValue(exec->vm(), jsUndefined()); -} - -Deprecated::ScriptValue CapabilityRange::min(ExecState* exec) const -{ - return scriptValue(exec, m_rangeInfo.min(), m_rangeInfo.type()); -} - -Deprecated::ScriptValue CapabilityRange::max(ExecState* exec) const -{ - return scriptValue(exec, m_rangeInfo.max(), m_rangeInfo.type()); -} - -} // namespace WebCore - -#endif diff --git a/Source/WebCore/Modules/mediastream/CapabilityRange.h b/Source/WebCore/Modules/mediastream/CapabilityRange.h deleted file mode 100644 index 905ae3f02..000000000 --- a/Source/WebCore/Modules/mediastream/CapabilityRange.h +++ /dev/null @@ -1,60 +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, 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 CapabilityRange_h -#define CapabilityRange_h - -#if ENABLE(MEDIA_STREAM) - -#include "MediaStreamSourceCapabilities.h" -#include "ScriptWrappable.h" -#include <bindings/ScriptValue.h> -#include <interpreter/CallFrame.h> -#include <wtf/RefCounted.h> - -namespace WebCore { - -class CapabilityRange : public RefCounted<CapabilityRange>, public ScriptWrappable { -public: - virtual ~CapabilityRange() { } - - static RefPtr<CapabilityRange> create(const MediaStreamSourceCapabilityRange&); - - Deprecated::ScriptValue min(JSC::ExecState*) const; - Deprecated::ScriptValue max(JSC::ExecState*) const; - bool supported() const { return m_rangeInfo.supported(); } - -private: - CapabilityRange(const MediaStreamSourceCapabilityRange&); - - MediaStreamSourceCapabilityRange m_rangeInfo; -}; - -} // namespace WebCore - -#endif // CapabilityRange_h - -#endif diff --git a/Source/WebCore/Modules/mediastream/CapabilityRange.idl b/Source/WebCore/Modules/mediastream/CapabilityRange.idl deleted file mode 100644 index 3dc6f13f0..000000000 --- a/Source/WebCore/Modules/mediastream/CapabilityRange.idl +++ /dev/null @@ -1,33 +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. - */ - -[ - NoInterfaceObject, - Conditional=MEDIA_STREAM, -] interface CapabilityRange { - [CallWith=ScriptState] readonly attribute any max; - [CallWith=ScriptState] readonly attribute any min; - readonly attribute boolean supported; -}; diff --git a/Source/WebCore/Modules/mediastream/DOMURLMediaStream.cpp b/Source/WebCore/Modules/mediastream/DOMURLMediaStream.cpp index 0eeed9c9f..69dc73042 100644 --- a/Source/WebCore/Modules/mediastream/DOMURLMediaStream.cpp +++ b/Source/WebCore/Modules/mediastream/DOMURLMediaStream.cpp @@ -40,13 +40,10 @@ namespace WebCore { -String DOMURLMediaStream::createObjectURL(ScriptExecutionContext* scriptExecutionContext, MediaStream* stream) +String DOMURLMediaStream::createObjectURL(ScriptExecutionContext& scriptExecutionContext, MediaStream& stream) { // Since WebWorkers cannot obtain Stream objects, we should be on the main thread. ASSERT(isMainThread()); - - if (!scriptExecutionContext || !stream) - return String(); return DOMURL::createPublicURL(scriptExecutionContext, stream); } diff --git a/Source/WebCore/Modules/mediastream/DOMURLMediaStream.h b/Source/WebCore/Modules/mediastream/DOMURLMediaStream.h index 3e2d8c905..560f621e5 100644 --- a/Source/WebCore/Modules/mediastream/DOMURLMediaStream.h +++ b/Source/WebCore/Modules/mediastream/DOMURLMediaStream.h @@ -28,8 +28,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef DOMURLMediaStream_h -#define DOMURLMediaStream_h +#pragma once #if ENABLE(MEDIA_STREAM) @@ -42,11 +41,9 @@ class ScriptExecutionContext; class DOMURLMediaStream { public: - static String createObjectURL(ScriptExecutionContext*, MediaStream*); + static String createObjectURL(ScriptExecutionContext&, MediaStream&); }; } // namespace WebCore #endif // ENABLE(MEDIA_STREAM) - -#endif // URLMediaStream_h diff --git a/Source/WebCore/Modules/mediastream/DOMURLMediaStream.idl b/Source/WebCore/Modules/mediastream/DOMURLMediaStream.idl index 77b689761..d40ce6749 100644 --- a/Source/WebCore/Modules/mediastream/DOMURLMediaStream.idl +++ b/Source/WebCore/Modules/mediastream/DOMURLMediaStream.idl @@ -31,5 +31,5 @@ Conditional=MEDIA_STREAM ] partial interface DOMURL { - [CallWith=ScriptExecutionContext,TreatReturnedNullStringAs=Null] static DOMString createObjectURL(MediaStream? stream); + [CallWith=ScriptExecutionContext] static DOMString createObjectURL(MediaStream stream); }; diff --git a/Source/WebCore/Modules/mediastream/RTCStatsResponse.idl b/Source/WebCore/Modules/mediastream/DoubleRange.h index 16634d741..84a46bd60 100644 --- a/Source/WebCore/Modules/mediastream/RTCStatsResponse.idl +++ b/Source/WebCore/Modules/mediastream/DoubleRange.h @@ -1,5 +1,5 @@ /* - * 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 @@ -22,10 +22,19 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -[ - NoInterfaceObject, - Conditional=MEDIA_STREAM, -] interface RTCStatsResponse { - sequence<RTCStatsReport> result(); - getter RTCStatsReport namedItem([Default=Undefined] optional DOMString name); +#pragma once + +#if ENABLE(MEDIA_STREAM) + +#include <wtf/Optional.h> + +namespace WebCore { + +struct DoubleRange { + std::optional<double> max; + std::optional<double> min; }; + +} + +#endif diff --git a/Source/WebCore/Modules/mediastream/RTCStatsCallback.idl b/Source/WebCore/Modules/mediastream/DoubleRange.idl index b32f43d2f..1ca3724e0 100644 --- a/Source/WebCore/Modules/mediastream/RTCStatsCallback.idl +++ b/Source/WebCore/Modules/mediastream/DoubleRange.idl @@ -1,5 +1,5 @@ /* - * 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 @@ -24,7 +24,8 @@ [ Conditional=MEDIA_STREAM, -] callback interface RTCStatsCallback { - boolean handleEvent(RTCStatsResponse response); + JSGenerateToJSObject, +] dictionary DoubleRange { + double max; + double min; }; - diff --git a/Source/WebCore/Modules/mediastream/HTMLMediaElementMediaStream.cpp b/Source/WebCore/Modules/mediastream/HTMLMediaElementMediaStream.cpp deleted file mode 100644 index 1dc905a57..000000000 --- a/Source/WebCore/Modules/mediastream/HTMLMediaElementMediaStream.cpp +++ /dev/null @@ -1,50 +0,0 @@ -/* - * 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. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``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 HOLDERS 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 "HTMLMediaElementMediaStream.h" - -#if ENABLE(MEDIA_STREAM) && ENABLE(VIDEO) - -#include "HTMLMediaElement.h" -#include "MediaStream.h" - -namespace WebCore { - -MediaStream* HTMLMediaElementMediaStream::srcObject(HTMLMediaElement* mediaElement, bool& isNull) -{ - ASSERT(mediaElement); - return mediaElement->srcObject(); -} - -void HTMLMediaElementMediaStream::setSrcObject(HTMLMediaElement* mediaElement, MediaStream* mediaStream) -{ - ASSERT(mediaElement); - mediaElement->setSrcObject(mediaStream); -} - -} // namespace WebCore - -#endif // ENABLE(MEDIA_STREAM) && ENABLE(VIDEO) diff --git a/Source/WebCore/Modules/mediastream/HTMLMediaElementMediaStream.h b/Source/WebCore/Modules/mediastream/HTMLMediaElementMediaStream.h deleted file mode 100644 index 41bf48418..000000000 --- a/Source/WebCore/Modules/mediastream/HTMLMediaElementMediaStream.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * 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. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``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 HOLDERS 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 HTMLMediaElementMediaStream_h -#define HTMLMediaElementMediaStream_h - -#if ENABLE(MEDIA_STREAM) && ENABLE(VIDEO) - -#include <wtf/PassRefPtr.h> - -namespace WebCore { - -class HTMLMediaElement; -class MediaStream; - -class HTMLMediaElementMediaStream { -public: - static MediaStream* srcObject(HTMLMediaElement*, bool& isNull); - static void setSrcObject(HTMLMediaElement*, MediaStream*); -}; - -} // namespace WebCore - -#endif // ENABLE(MEDIA_STREAM) && ENABLE(VIDEO) - -#endif // HTMLMediaElementMediaStream_h diff --git a/Source/WebCore/Modules/mediastream/HTMLMediaElementMediaStream.idl b/Source/WebCore/Modules/mediastream/HTMLMediaElementMediaStream.idl deleted file mode 100644 index a3ba17d67..000000000 --- a/Source/WebCore/Modules/mediastream/HTMLMediaElementMediaStream.idl +++ /dev/null @@ -1,33 +0,0 @@ -/* - * 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. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``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 HOLDERS OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -[ - Conditional=VIDEO&MEDIA_STREAM, -] partial interface HTMLMediaElement -{ -#if !defined(LANGUAGE_GOBJECT) || !LANGUAGE_GOBJECT - attribute MediaStream? srcObject; -#endif -}; diff --git a/Source/WebCore/Modules/mediastream/NavigatorUserMediaErrorCallback.idl b/Source/WebCore/Modules/mediastream/LongRange.h index e7754f18a..160ef86b6 100644 --- a/Source/WebCore/Modules/mediastream/NavigatorUserMediaErrorCallback.idl +++ b/Source/WebCore/Modules/mediastream/LongRange.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011 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 @@ -22,9 +22,19 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -[ - Conditional=MEDIA_STREAM, -] callback interface NavigatorUserMediaErrorCallback { - boolean handleEvent(NavigatorUserMediaError error); +#pragma once + +#if ENABLE(MEDIA_STREAM) + +#include <wtf/Optional.h> + +namespace WebCore { + +struct LongRange { + std::optional<int> max; + std::optional<int> min; }; +} + +#endif diff --git a/Source/WebCore/Modules/mediastream/NavigatorUserMediaSuccessCallback.idl b/Source/WebCore/Modules/mediastream/LongRange.idl index 3912797d3..69ba22410 100644 --- a/Source/WebCore/Modules/mediastream/NavigatorUserMediaSuccessCallback.idl +++ b/Source/WebCore/Modules/mediastream/LongRange.idl @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011 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 @@ -24,7 +24,8 @@ [ Conditional=MEDIA_STREAM, -] callback interface NavigatorUserMediaSuccessCallback { - boolean handleEvent(MediaStream stream); + JSGenerateToJSObject, +] dictionary LongRange { + long max; + long min; }; - diff --git a/Source/WebCore/Modules/mediastream/MediaConstraintsImpl.cpp b/Source/WebCore/Modules/mediastream/MediaConstraintsImpl.cpp index 10f812bda..f50f758be 100644 --- a/Source/WebCore/Modules/mediastream/MediaConstraintsImpl.cpp +++ b/Source/WebCore/Modules/mediastream/MediaConstraintsImpl.cpp @@ -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 @@ -34,126 +35,16 @@ #include "MediaConstraintsImpl.h" -#include "ArrayValue.h" -#include "Dictionary.h" -#include "ExceptionCode.h" -#include <wtf/HashMap.h> - namespace WebCore { -PassRefPtr<MediaConstraintsImpl> MediaConstraintsImpl::create(const Dictionary& constraints, ExceptionCode& ec) -{ - RefPtr<MediaConstraintsImpl> object = adoptRef(new MediaConstraintsImpl()); - if (!object->initialize(constraints)) { - ec = TYPE_MISMATCH_ERR; - return 0; - } - return object.release(); -} - -PassRefPtr<MediaConstraintsImpl> MediaConstraintsImpl::create() -{ - return adoptRef(new MediaConstraintsImpl()); -} - -bool MediaConstraintsImpl::initialize(const Dictionary& constraints) -{ - if (constraints.isUndefinedOrNull()) - return true; - - Vector<String> names; - constraints.getOwnPropertyNames(names); - - String mandatory = ASCIILiteral("mandatory"); - String optional = ASCIILiteral("optional"); - - for (Vector<String>::iterator it = names.begin(); it != names.end(); ++it) { - if (*it != mandatory && *it != optional) - return false; - } - - if (names.contains(mandatory)) { - Dictionary mandatoryConstraints; - bool ok = constraints.get(mandatory, mandatoryConstraints); - if (!ok || mandatoryConstraints.isUndefinedOrNull()) - return false; - - ok = mandatoryConstraints.getOwnPropertiesAsStringHashMap(m_mandatoryConstraints); - if (!ok) - return false; - } - - if (names.contains(optional)) { - ArrayValue optionalConstraints; - bool ok = constraints.get(optional, optionalConstraints); - if (!ok || optionalConstraints.isUndefinedOrNull()) - return false; - - size_t numberOfConstraints; - ok = optionalConstraints.length(numberOfConstraints); - if (!ok) - return false; - - for (size_t i = 0; i < numberOfConstraints; ++i) { - Dictionary constraint; - ok = optionalConstraints.get(i, constraint); - if (!ok || constraint.isUndefinedOrNull()) - return false; - Vector<String> localNames; - constraint.getOwnPropertyNames(localNames); - if (localNames.size() != 1) - return false; - String key = localNames[0]; - String value; - ok = constraint.get(key, value); - if (!ok) - return false; - m_optionalConstraints.append(MediaConstraint(key, value)); - } - } - - return true; -} - -MediaConstraintsImpl::~MediaConstraintsImpl() +Ref<MediaConstraintsImpl> MediaConstraintsImpl::create(MediaTrackConstraintSetMap&& mandatoryConstraints, Vector<MediaTrackConstraintSetMap>&& advancedConstraints, bool isValid) { + return adoptRef(*new MediaConstraintsImpl(WTFMove(mandatoryConstraints), WTFMove(advancedConstraints), isValid)); } -void MediaConstraintsImpl::getMandatoryConstraints(Vector<MediaConstraint>& constraints) const +Ref<MediaConstraintsImpl> MediaConstraintsImpl::create(const MediaConstraintsData& data) { - constraints.clear(); - HashMap<String, String>::const_iterator i = m_mandatoryConstraints.begin(); - for (; i != m_mandatoryConstraints.end(); ++i) - constraints.append(MediaConstraint(i->key, i->value)); -} - -void MediaConstraintsImpl::getOptionalConstraints(Vector<MediaConstraint>& constraints) const -{ - constraints.clear(); - constraints.appendRange(m_optionalConstraints.begin(), m_optionalConstraints.end()); -} - -bool MediaConstraintsImpl::getMandatoryConstraintValue(const String& name, String& value) const -{ - HashMap<String, String>::const_iterator i = m_mandatoryConstraints.find(name); - if (i == m_mandatoryConstraints.end()) - return false; - - value = i->value; - return true; -} - -bool MediaConstraintsImpl::getOptionalConstraintValue(const String& name, String& value) const -{ - Vector<MediaConstraint>::const_iterator i = m_optionalConstraints.begin(); - for (; i != m_optionalConstraints.end(); ++i) { - if (i->m_name == name) { - value = i->m_value; - return true; - } - } - - return false; + return adoptRef(*new MediaConstraintsImpl(data)); } } // namespace WebCore diff --git a/Source/WebCore/Modules/mediastream/MediaConstraintsImpl.h b/Source/WebCore/Modules/mediastream/MediaConstraintsImpl.h index eeb631ca3..fbee397cd 100644 --- a/Source/WebCore/Modules/mediastream/MediaConstraintsImpl.h +++ b/Source/WebCore/Modules/mediastream/MediaConstraintsImpl.h @@ -28,44 +28,56 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef MediaConstraintsImpl_h -#define MediaConstraintsImpl_h +#pragma once #if ENABLE(MEDIA_STREAM) #include "ExceptionBase.h" #include "MediaConstraints.h" -#include <wtf/HashMap.h> #include <wtf/Vector.h> namespace WebCore { -class Dictionary; -class MediaConstraintsImpl : public MediaConstraints { -public: - static PassRefPtr<MediaConstraintsImpl> create(); - static PassRefPtr<MediaConstraintsImpl> create(const Dictionary&, ExceptionCode&); +struct MediaConstraintsData { + MediaConstraintsData() = default; + MediaConstraintsData(MediaTrackConstraintSetMap&& mandatoryConstraints, Vector<MediaTrackConstraintSetMap>&& advancedConstraints, bool isValid) + : mandatoryConstraints(WTFMove(mandatoryConstraints)) + , advancedConstraints(WTFMove(advancedConstraints)) + , isValid(isValid) + { + } + + MediaTrackConstraintSetMap mandatoryConstraints; + Vector<MediaTrackConstraintSetMap> advancedConstraints; + bool isValid { false }; +}; - virtual ~MediaConstraintsImpl(); - bool initialize(const Dictionary&); +class MediaConstraintsImpl final : public MediaConstraints { +public: + static Ref<MediaConstraintsImpl> create(MediaTrackConstraintSetMap&& mandatoryConstraints, Vector<MediaTrackConstraintSetMap>&& advancedConstraints, bool isValid); + WEBCORE_EXPORT static Ref<MediaConstraintsImpl> create(const MediaConstraintsData&); - virtual void getMandatoryConstraints(Vector<MediaConstraint>&) const override; - virtual void getOptionalConstraints(Vector<MediaConstraint>&) const override; + MediaConstraintsImpl() = default; + virtual ~MediaConstraintsImpl() = default; - virtual bool getMandatoryConstraintValue(const String& name, String& value) const override; - virtual bool getOptionalConstraintValue(const String& name, String& value) const override; + const MediaTrackConstraintSetMap& mandatoryConstraints() const final { return m_data.mandatoryConstraints; } + const Vector<MediaTrackConstraintSetMap>& advancedConstraints() const final { return m_data.advancedConstraints; } + bool isValid() const final { return m_data.isValid; } + const MediaConstraintsData& data() const { return m_data; } private: - MediaConstraintsImpl() { } + MediaConstraintsImpl(MediaTrackConstraintSetMap&& mandatoryConstraints, Vector<MediaTrackConstraintSetMap>&& advancedConstraints, bool isValid) + : m_data({ WTFMove(mandatoryConstraints), WTFMove(advancedConstraints), isValid }) + { + } + explicit MediaConstraintsImpl(const MediaConstraintsData& data) + : m_data(data) + { + } - HashMap<String, String> m_mandatoryConstraints; - Vector<MediaConstraint> m_optionalConstraints; + MediaConstraintsData m_data; }; } // namespace WebCore #endif // ENABLE(MEDIA_STREAM) - -#endif // MediaConstraintsImpl_h - - diff --git a/Source/WebCore/Modules/mediastream/MediaTrackConstraint.cpp b/Source/WebCore/Modules/mediastream/MediaDeviceInfo.cpp index 453fcebc1..fe760d917 100644 --- a/Source/WebCore/Modules/mediastream/MediaTrackConstraint.cpp +++ b/Source/WebCore/Modules/mediastream/MediaDeviceInfo.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 Apple Inc. All rights reserved. + * 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 @@ -10,42 +10,38 @@ * 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 + * 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 * 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. - * + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "config.h" +#include "MediaDeviceInfo.h" #if ENABLE(MEDIA_STREAM) -#include "MediaTrackConstraint.h" - -using namespace JSC; - namespace WebCore { -RefPtr<MediaTrackConstraint> MediaTrackConstraint::create(const Dictionary& constraint) -{ - return adoptRef(new MediaTrackConstraint(constraint)); -} - -MediaTrackConstraint::MediaTrackConstraint(const Dictionary& constraint) - : m_constraint(constraint) +inline MediaDeviceInfo::MediaDeviceInfo(ScriptExecutionContext* context, const String& label, const String& deviceId, const String& groupId, Kind kind) + : ContextDestructionObserver(context) + , m_label(label) + , m_deviceId(deviceId) + , m_groupId(groupId) + , m_kind(kind) { } -MediaTrackConstraint::~MediaTrackConstraint() +Ref<MediaDeviceInfo> MediaDeviceInfo::create(ScriptExecutionContext* context, const String& label, const String& deviceId, const String& groupId, Kind kind) { + return adoptRef(*new MediaDeviceInfo(context, label, deviceId, groupId, kind)); } } // namespace WebCore diff --git a/Source/WebCore/Modules/mediastream/SourceInfo.h b/Source/WebCore/Modules/mediastream/MediaDeviceInfo.h index 23f162e37..fc6890433 100644 --- a/Source/WebCore/Modules/mediastream/SourceInfo.h +++ b/Source/WebCore/Modules/mediastream/MediaDeviceInfo.h @@ -1,6 +1,5 @@ /* - * Copyright (C) 2013 Google Inc. All rights reserved. - * Copyright (C) 2013 Apple Inc. All rights reserved. + * 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 @@ -11,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 GOOGLE 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 GOOGLE 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 @@ -24,36 +23,38 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef SourceInfo_h -#define SourceInfo_h +#pragma once #if ENABLE(MEDIA_STREAM) -#include "MediaStreamTrackSourcesRequestClient.h" +#include "ContextDestructionObserver.h" #include "ScriptWrappable.h" -#include <wtf/Forward.h> -#include <wtf/RefCounted.h> -#include <wtf/Vector.h> #include <wtf/text/WTFString.h> namespace WebCore { -class SourceInfo : public RefCounted<SourceInfo>, public ScriptWrappable { +class MediaDeviceInfo : public RefCounted<MediaDeviceInfo>, public ScriptWrappable, private ContextDestructionObserver { public: - static PassRefPtr<SourceInfo> create(PassRefPtr<TrackSourceInfo>); + enum class Kind { Audioinput, Audiooutput, Videoinput }; - const AtomicString& sourceId() const { return m_trackSourceInfo->id(); } - const AtomicString& label() const { return m_trackSourceInfo->label(); } - const AtomicString& kind() const; + static Ref<MediaDeviceInfo> create(ScriptExecutionContext*, const String&, const String&, const String&, Kind); + + const String& label() const { return m_label; } + const String& deviceId() const { return m_deviceId; } + const String& groupId() const { return m_groupId; } + Kind kind() const { return m_kind; } private: - SourceInfo(PassRefPtr<TrackSourceInfo>); + MediaDeviceInfo(ScriptExecutionContext*, const String&, const String&, const String&, Kind); - RefPtr<TrackSourceInfo> m_trackSourceInfo; + const String m_label; + const String m_deviceId; + const String m_groupId; + const Kind m_kind; }; -} // namespace WebCore +typedef Vector<RefPtr<MediaDeviceInfo>> MediaDeviceInfoVector; -#endif // SourceInfo_h +} #endif diff --git a/Source/WebCore/Modules/mediastream/MediaDeviceInfo.idl b/Source/WebCore/Modules/mediastream/MediaDeviceInfo.idl new file mode 100644 index 000000000..927cd7263 --- /dev/null +++ b/Source/WebCore/Modules/mediastream/MediaDeviceInfo.idl @@ -0,0 +1,42 @@ +/* +* 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 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 GOOGLE 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. +*/ + +[ + Conditional=MEDIA_STREAM, + Constructor(DOMString deviceId, DOMString label, DOMString groupId, MediaDeviceKind kind), + JSGenerateToJSObject, + NoInterfaceObject, +] interface MediaDeviceInfo { + readonly attribute DOMString deviceId; + readonly attribute DOMString groupId; + readonly attribute MediaDeviceKind kind; + readonly attribute DOMString label; +}; + +enum MediaDeviceKind { + "audioinput", + "audiooutput", + "videoinput" +}; diff --git a/Source/WebCore/Modules/mediastream/MediaDevices.cpp b/Source/WebCore/Modules/mediastream/MediaDevices.cpp new file mode 100644 index 000000000..db1ac33e0 --- /dev/null +++ b/Source/WebCore/Modules/mediastream/MediaDevices.cpp @@ -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. + */ + +#include "config.h" +#include "MediaDevices.h" + +#if ENABLE(MEDIA_STREAM) + +#include "Document.h" +#include "MediaConstraintsImpl.h" +#include "MediaDevicesRequest.h" +#include "MediaTrackSupportedConstraints.h" +#include "RealtimeMediaSourceCenter.h" +#include "UserMediaRequest.h" + +namespace WebCore { + +inline MediaDevices::MediaDevices(Document& document) + : ContextDestructionObserver(&document) +{ +} + +Ref<MediaDevices> MediaDevices::create(Document& document) +{ + return adoptRef(*new MediaDevices(document)); +} + +Document* MediaDevices::document() const +{ + return downcast<Document>(scriptExecutionContext()); +} + +static Ref<MediaConstraintsImpl> createMediaConstraintsImpl(const Variant<bool, MediaTrackConstraints>& constraints) +{ + return WTF::switchOn(constraints, + [&] (bool constraints) { + return MediaConstraintsImpl::create({ }, { }, constraints); + }, + [&] (const MediaTrackConstraints& constraints) { + return createMediaConstraintsImpl(constraints); + } + ); +} + +ExceptionOr<void> MediaDevices::getUserMedia(const StreamConstraints& constraints, Promise&& promise) const +{ + auto* document = this->document(); + if (!document) + return Exception { INVALID_STATE_ERR }; + return UserMediaRequest::start(*document, createMediaConstraintsImpl(constraints.audio), createMediaConstraintsImpl(constraints.video), WTFMove(promise)); +} + +void MediaDevices::enumerateDevices(EnumerateDevicesPromise&& promise) const +{ + auto* document = this->document(); + if (!document) + return; + MediaDevicesRequest::create(*document, WTFMove(promise))->start(); +} + +MediaTrackSupportedConstraints MediaDevices::getSupportedConstraints() +{ + auto& supported = RealtimeMediaSourceCenter::singleton().supportedConstraints(); + MediaTrackSupportedConstraints result; + result.width = supported.supportsWidth(); + result.height = supported.supportsHeight(); + result.aspectRatio = supported.supportsAspectRatio(); + result.frameRate = supported.supportsFrameRate(); + result.facingMode = supported.supportsFacingMode(); + result.volume = supported.supportsVolume(); + result.sampleRate = supported.supportsSampleRate(); + result.sampleSize = supported.supportsSampleSize(); + result.echoCancellation = supported.supportsEchoCancellation(); + result.deviceId = supported.supportsDeviceId(); + result.groupId = supported.supportsGroupId(); + return result; +} + +} // namespace WebCore + +#endif // ENABLE(MEDIA_STREAM) diff --git a/Source/WebCore/Modules/mediastream/RTCSessionDescriptionRequestImpl.h b/Source/WebCore/Modules/mediastream/MediaDevices.h index c5624b1c5..0d90d259d 100644 --- a/Source/WebCore/Modules/mediastream/RTCSessionDescriptionRequestImpl.h +++ b/Source/WebCore/Modules/mediastream/MediaDevices.h @@ -1,6 +1,6 @@ /* - * Copyright (C) 2012 Google Inc. All rights reserved. - * Copyright (C) 2013 Nokia Corporation and/or its subsidiary(-ies). + * Copyright (C) 2015 Ericsson AB. All rights reserved. + * 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 @@ -12,7 +12,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. * @@ -29,44 +29,43 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef RTCSessionDescriptionRequestImpl_h -#define RTCSessionDescriptionRequestImpl_h +#pragma once #if ENABLE(MEDIA_STREAM) -#include "ActiveDOMObject.h" -#include "RTCSessionDescriptionRequest.h" +#include "ExceptionOr.h" +#include "JSDOMPromise.h" +#include "MediaTrackConstraints.h" namespace WebCore { -class RTCPeerConnectionErrorCallback; -class RTCPeerConnection; -class RTCSessionDescriptionCallback; +class Document; +class MediaDeviceInfo; +class MediaStream; -class RTCSessionDescriptionRequestImpl : public RTCSessionDescriptionRequest, public ActiveDOMObject { -public: - static PassRefPtr<RTCSessionDescriptionRequestImpl> create(ScriptExecutionContext*, PassRefPtr<RTCSessionDescriptionCallback>, PassRefPtr<RTCPeerConnectionErrorCallback>); - virtual ~RTCSessionDescriptionRequestImpl(); +struct MediaTrackSupportedConstraints; - virtual void requestSucceeded(PassRefPtr<RTCSessionDescriptionDescriptor>) override; - virtual void requestFailed(const String& error) override; +class MediaDevices : public ScriptWrappable, public RefCounted<MediaDevices>, public ContextDestructionObserver { +public: + static Ref<MediaDevices> create(Document&); - // ActiveDOMObject - virtual void stop() override; + Document* document() const; -private: - RTCSessionDescriptionRequestImpl(ScriptExecutionContext*, PassRefPtr<RTCSessionDescriptionCallback>, PassRefPtr<RTCPeerConnectionErrorCallback>); + using Promise = DOMPromise<IDLInterface<MediaStream>>; + using EnumerateDevicesPromise = DOMPromise<IDLSequence<IDLInterface<MediaDeviceInfo>>>; - void clear(); + struct StreamConstraints { + Variant<bool, MediaTrackConstraints> video; + Variant<bool, MediaTrackConstraints> audio; + }; + ExceptionOr<void> getUserMedia(const StreamConstraints&, Promise&&) const; + void enumerateDevices(EnumerateDevicesPromise&&) const; + MediaTrackSupportedConstraints getSupportedConstraints(); - RefPtr<RTCSessionDescriptionCallback> m_successCallback; - RefPtr<RTCPeerConnectionErrorCallback> m_errorCallback; +private: + explicit MediaDevices(Document&); }; } // namespace WebCore #endif // ENABLE(MEDIA_STREAM) - -#endif // RTCSessionDescriptionRequestImpl_h - - diff --git a/Source/WebCore/Modules/mediastream/MediaDevices.idl b/Source/WebCore/Modules/mediastream/MediaDevices.idl new file mode 100644 index 000000000..0c0866295 --- /dev/null +++ b/Source/WebCore/Modules/mediastream/MediaDevices.idl @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2015 Ericsson AB. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of Ericsson nor the names of its contributors + * may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +[ + Conditional=MEDIA_STREAM, + NoInterfaceObject, +] interface MediaDevices { + MediaTrackSupportedConstraints getSupportedConstraints(); + + [PrivateIdentifier, PublicIdentifier] Promise<MediaStream> getUserMedia(optional MediaStreamConstraints constraints); + Promise<sequence<MediaDeviceInfo>> enumerateDevices(); +}; + +[ + Conditional=MEDIA_STREAM, +] dictionary MediaStreamConstraints { + (boolean or MediaTrackConstraints) video = false; + (boolean or MediaTrackConstraints) audio = false; +}; diff --git a/Source/WebCore/Modules/mediastream/MediaDevicesEnumerationRequest.cpp b/Source/WebCore/Modules/mediastream/MediaDevicesEnumerationRequest.cpp new file mode 100644 index 000000000..c89d43d79 --- /dev/null +++ b/Source/WebCore/Modules/mediastream/MediaDevicesEnumerationRequest.cpp @@ -0,0 +1,113 @@ +/* + * 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. + * + */ + +#include "config.h" +#include "MediaDevicesEnumerationRequest.h" + +#if ENABLE(MEDIA_STREAM) + +#include "CaptureDevice.h" +#include "Document.h" +#include "MainFrame.h" +#include "SecurityOrigin.h" +#include "UserMediaController.h" + +namespace WebCore { + +Ref<MediaDevicesEnumerationRequest> MediaDevicesEnumerationRequest::create(Document& document, CompletionHandler&& completionHandler) +{ + return adoptRef(*new MediaDevicesEnumerationRequest(document, WTFMove(completionHandler))); +} + +MediaDevicesEnumerationRequest::MediaDevicesEnumerationRequest(ScriptExecutionContext& context, CompletionHandler&& completionHandler) + : ContextDestructionObserver(&context) + , m_completionHandler(WTFMove(completionHandler)) +{ +} + +MediaDevicesEnumerationRequest::~MediaDevicesEnumerationRequest() +{ +} + +SecurityOrigin* MediaDevicesEnumerationRequest::userMediaDocumentOrigin() const +{ + if (!scriptExecutionContext()) + return nullptr; + + return scriptExecutionContext()->securityOrigin(); +} + +SecurityOrigin* MediaDevicesEnumerationRequest::topLevelDocumentOrigin() const +{ + if (!scriptExecutionContext()) + return nullptr; + + if (Frame* frame = downcast<Document>(*scriptExecutionContext()).frame()) { + if (frame->isMainFrame()) + return nullptr; + } + + return &scriptExecutionContext()->topOrigin(); +} + +void MediaDevicesEnumerationRequest::contextDestroyed() +{ + cancel(); + ContextDestructionObserver::contextDestroyed(); +} + +void MediaDevicesEnumerationRequest::start() +{ + ASSERT(scriptExecutionContext()); + + auto& document = downcast<Document>(*scriptExecutionContext()); + auto* controller = UserMediaController::from(document.page()); + if (!controller) + return; + + Ref<MediaDevicesEnumerationRequest> protectedThis(*this); + controller->enumerateMediaDevices(*this); +} + +void MediaDevicesEnumerationRequest::cancel() +{ + m_completionHandler = nullptr; +} + +void MediaDevicesEnumerationRequest::setDeviceInfo(const Vector<CaptureDevice>& deviceList, const String& deviceIdentifierHashSalt, bool originHasPersistentAccess) +{ + m_deviceList = deviceList; + m_deviceIdentifierHashSalt = deviceIdentifierHashSalt; + m_originHasPersistentAccess = originHasPersistentAccess; + + if (m_completionHandler) + m_completionHandler(m_deviceList, m_deviceIdentifierHashSalt, m_originHasPersistentAccess); + m_completionHandler = nullptr; +} + +} // namespace WebCore + +#endif // ENABLE(MEDIA_STREAM) diff --git a/Source/WebCore/Modules/mediastream/MediaDevicesEnumerationRequest.h b/Source/WebCore/Modules/mediastream/MediaDevicesEnumerationRequest.h new file mode 100644 index 000000000..ec4df0054 --- /dev/null +++ b/Source/WebCore/Modules/mediastream/MediaDevicesEnumerationRequest.h @@ -0,0 +1,71 @@ +/* + * 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 "ActiveDOMObject.h" +#include <functional> +#include <wtf/text/WTFString.h> + +namespace WebCore { + +class CaptureDevice; +class Document; +class SecurityOrigin; + +class MediaDevicesEnumerationRequest final : public ContextDestructionObserver, public RefCounted<MediaDevicesEnumerationRequest> { +public: + using CompletionHandler = std::function<void(const Vector<CaptureDevice>&, const String& deviceIdentifierHashSalt, bool originHasPersistentAccess)>; + + static Ref<MediaDevicesEnumerationRequest> create(Document&, CompletionHandler&&); + + virtual ~MediaDevicesEnumerationRequest(); + + void start(); + void cancel(); + + WEBCORE_EXPORT void setDeviceInfo(const Vector<CaptureDevice>&, const String& deviceIdentifierHashSalt, bool originHasPersistentAccess); + + WEBCORE_EXPORT SecurityOrigin* userMediaDocumentOrigin() const; + WEBCORE_EXPORT SecurityOrigin* topLevelDocumentOrigin() const; + +private: + MediaDevicesEnumerationRequest(ScriptExecutionContext&, CompletionHandler&&); + + // ContextDestructionObserver + void contextDestroyed() final; + + CompletionHandler m_completionHandler; + Vector<CaptureDevice> m_deviceList; + String m_deviceIdentifierHashSalt; + bool m_originHasPersistentAccess { false }; +}; + +} // namespace WebCore + +#endif // ENABLE(MEDIA_STREAM) diff --git a/Source/WebCore/Modules/mediastream/MediaDevicesRequest.cpp b/Source/WebCore/Modules/mediastream/MediaDevicesRequest.cpp new file mode 100644 index 000000000..4a0b3e19e --- /dev/null +++ b/Source/WebCore/Modules/mediastream/MediaDevicesRequest.cpp @@ -0,0 +1,153 @@ +/* + * 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. + * + */ + +#include "config.h" +#include "MediaDevicesRequest.h" + +#if ENABLE(MEDIA_STREAM) + +#include "CaptureDevice.h" +#include "Document.h" +#include "Frame.h" +#include "JSMediaDeviceInfo.h" +#include "MediaDevicesEnumerationRequest.h" +#include "SecurityOrigin.h" +#include "UserMediaController.h" +#include <wtf/MainThread.h> +#include <wtf/SHA1.h> + +namespace WebCore { + +inline MediaDevicesRequest::MediaDevicesRequest(Document& document, MediaDevices::EnumerateDevicesPromise&& promise) + : ContextDestructionObserver(&document) + , m_promise(WTFMove(promise)) +{ +} + +Ref<MediaDevicesRequest> MediaDevicesRequest::create(Document& document, MediaDevices::EnumerateDevicesPromise&& promise) +{ + return adoptRef(*new MediaDevicesRequest(document, WTFMove(promise))); +} + +MediaDevicesRequest::~MediaDevicesRequest() +{ + if (m_enumerationRequest) + m_enumerationRequest->cancel(); +} + +SecurityOrigin* MediaDevicesRequest::securityOrigin() const +{ + if (scriptExecutionContext()) + return scriptExecutionContext()->securityOrigin(); + + return nullptr; +} + +void MediaDevicesRequest::contextDestroyed() +{ + if (m_enumerationRequest) { + m_enumerationRequest->cancel(); + m_enumerationRequest = nullptr; + } + ContextDestructionObserver::contextDestroyed(); +} + +void MediaDevicesRequest::start() +{ + RefPtr<MediaDevicesRequest> protectedThis = this; + auto completion = [this, protectedThis = WTFMove(protectedThis)] (const Vector<CaptureDevice>& captureDevices, const String& deviceIdentifierHashSalt, bool originHasPersistentAccess) mutable { + + m_enumerationRequest = nullptr; + + if (!scriptExecutionContext()) + return; + + Document& document = downcast<Document>(*scriptExecutionContext()); + UserMediaController* controller = UserMediaController::from(document.page()); + if (!controller) + return; + + m_idHashSalt = deviceIdentifierHashSalt; + + Vector<RefPtr<MediaDeviceInfo>> devices; + for (auto& deviceInfo : captureDevices) { + auto label = emptyString(); + if (originHasPersistentAccess || document.hasHadActiveMediaStreamTrack()) + label = deviceInfo.label(); + + auto id = hashID(deviceInfo.persistentId()); + if (id.isEmpty()) + continue; + + auto groupId = hashID(deviceInfo.groupId()); + auto deviceType = deviceInfo.type() == CaptureDevice::DeviceType::Audio ? MediaDeviceInfo::Kind::Audioinput : MediaDeviceInfo::Kind::Videoinput; + devices.append(MediaDeviceInfo::create(scriptExecutionContext(), label, id, groupId, deviceType)); + } + + callOnMainThread([protectedThis = makeRef(*this), devices = WTFMove(devices)]() mutable { + protectedThis->m_promise.resolve(devices); + }); + }; + + m_enumerationRequest = MediaDevicesEnumerationRequest::create(*downcast<Document>(scriptExecutionContext()), WTFMove(completion)); + m_enumerationRequest->start(); +} + +static void hashString(SHA1& sha1, const String& string) +{ + if (string.isEmpty()) + return; + + if (string.is8Bit() && string.containsOnlyASCII()) { + const uint8_t nullByte = 0; + sha1.addBytes(string.characters8(), string.length()); + sha1.addBytes(&nullByte, 1); + return; + } + + auto utf8 = string.utf8(); + sha1.addBytes(reinterpret_cast<const uint8_t*>(utf8.data()), utf8.length() + 1); // Include terminating null byte. +} + +String MediaDevicesRequest::hashID(const String& id) +{ + if (id.isEmpty() || m_idHashSalt.isEmpty()) + return emptyString(); + + SHA1 sha1; + + hashString(sha1, id); + hashString(sha1, m_idHashSalt); + + SHA1::Digest digest; + sha1.computeHash(digest); + + return SHA1::hexDigest(digest).data(); +} + +} // namespace WebCore + +#endif // ENABLE(MEDIA_STREAM) diff --git a/Source/WebCore/Modules/mediastream/MediaTrackConstraint.h b/Source/WebCore/Modules/mediastream/MediaDevicesRequest.h index 2a93fc763..d47002fd9 100644 --- a/Source/WebCore/Modules/mediastream/MediaTrackConstraint.h +++ b/Source/WebCore/Modules/mediastream/MediaDevicesRequest.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 @@ -13,48 +13,53 @@ * 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 * 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. + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ -#ifndef MediaTrackConstraint_h -#define MediaTrackConstraint_h +#pragma once #if ENABLE(MEDIA_STREAM) -#include "Dictionary.h" -#include "ScriptWrappable.h" -#include <wtf/RefCounted.h> - -namespace Deprecated { -class ScriptValue; -} +#include "MediaDevices.h" namespace WebCore { -class MediaTrackConstraint : public RefCounted<MediaTrackConstraint>, public ScriptWrappable { +class Document; +class MediaDevicesEnumerationRequest; +class SecurityOrigin; + +class MediaDevicesRequest : public RefCounted<MediaDevicesRequest>, private ContextDestructionObserver { public: - static RefPtr<MediaTrackConstraint> create(const Dictionary&); + static Ref<MediaDevicesRequest> create(Document&, MediaDevices::EnumerateDevicesPromise&&); - virtual ~MediaTrackConstraint(); + virtual ~MediaDevicesRequest(); - const Dictionary& constraint() const { return m_constraint; } + void start(); + + SecurityOrigin* securityOrigin() const; private: - explicit MediaTrackConstraint(const Dictionary&); - - const Dictionary& m_constraint; + MediaDevicesRequest(Document&, MediaDevices::EnumerateDevicesPromise&&); + + void contextDestroyed() final; + + String hashID(const String&); + + MediaDevices::EnumerateDevicesPromise m_promise; + RefPtr<MediaDevicesRequest> m_protector; + RefPtr<MediaDevicesEnumerationRequest> m_enumerationRequest; + + String m_idHashSalt; }; } // namespace WebCore -#endif // MediaTrackConstraint_h - -#endif +#endif // ENABLE(MEDIA_STREAM) diff --git a/Source/WebCore/Modules/mediastream/MediaEndpointPeerConnection.cpp b/Source/WebCore/Modules/mediastream/MediaEndpointPeerConnection.cpp new file mode 100644 index 000000000..14ee0f5d3 --- /dev/null +++ b/Source/WebCore/Modules/mediastream/MediaEndpointPeerConnection.cpp @@ -0,0 +1,874 @@ +/* + * 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 "MediaEndpointPeerConnection.h" + +#include "EventNames.h" +#include "JSRTCSessionDescription.h" +#include "MediaEndpointSessionConfiguration.h" +#include "MediaEndpointSessionDescription.h" +#include "MediaStream.h" +#include "MediaStreamEvent.h" +#include "MediaStreamTrack.h" +#include "NotImplemented.h" +#include "PeerMediaDescription.h" +#include "RTCConfiguration.h" +#include "RTCIceCandidate.h" +#include "RTCIceCandidateEvent.h" +#include "RTCOfferAnswerOptions.h" +#include "RTCPeerConnection.h" +#include "RTCRtpTransceiver.h" +#include "RTCTrackEvent.h" +#include "SDPProcessor.h" +#include <wtf/MainThread.h> +#include <wtf/text/Base64.h> + +namespace WebCore { + +using namespace PeerConnection; +using namespace PeerConnectionStates; + +using MediaDescriptionVector = Vector<PeerMediaDescription>; +using RtpTransceiverVector = Vector<RefPtr<RTCRtpTransceiver>>; + +// We use base64 to generate the random strings so we need a size that avoids padding to get ice-chars. +static const size_t cnameSize = 18; +// Size range from 4 to 256 ice-chars defined in RFC 5245. +static const size_t iceUfragSize = 6; +// Size range from 22 to 256 ice-chars defined in RFC 5245. +static const size_t icePasswordSize = 24; + +#if !USE(LIBWEBRTC) +static std::unique_ptr<PeerConnectionBackend> createMediaEndpointPeerConnection(RTCPeerConnection& peerConnection) +{ + return std::unique_ptr<PeerConnectionBackend>(new MediaEndpointPeerConnection(peerConnection)); +} + +CreatePeerConnectionBackend PeerConnectionBackend::create = createMediaEndpointPeerConnection; +#endif + +static String randomString(size_t size) +{ + unsigned char randomValues[size]; + cryptographicallyRandomValues(randomValues, size); + return base64Encode(randomValues, size); +} + +MediaEndpointPeerConnection::MediaEndpointPeerConnection(RTCPeerConnection& peerConnection) + : PeerConnectionBackend(peerConnection) + , m_mediaEndpoint(MediaEndpoint::create(*this)) + , m_sdpProcessor(std::make_unique<SDPProcessor>(m_peerConnection.scriptExecutionContext())) + , m_cname(randomString(cnameSize)) + , m_iceUfrag(randomString(iceUfragSize)) + , m_icePassword(randomString(icePasswordSize)) +{ + ASSERT(m_mediaEndpoint); + + m_defaultAudioPayloads = m_mediaEndpoint->getDefaultAudioPayloads(); + m_defaultVideoPayloads = m_mediaEndpoint->getDefaultVideoPayloads(); + + // Tasks (see runTask()) will be deferred until we get the DTLS fingerprint. + m_mediaEndpoint->generateDtlsInfo(); +} + +static RTCRtpTransceiver* matchTransceiver(const RtpTransceiverVector& transceivers, const std::function<bool(RTCRtpTransceiver&)>& matchFunction) +{ + for (auto& transceiver : transceivers) { + if (matchFunction(*transceiver)) + return transceiver.get(); + } + return nullptr; +} + +static RTCRtpTransceiver* matchTransceiverByMid(const RtpTransceiverVector& transceivers, const String& mid) +{ + return matchTransceiver(transceivers, [&mid] (RTCRtpTransceiver& current) { + return current.mid() == mid; + }); +} + +static bool hasUnassociatedTransceivers(const RtpTransceiverVector& transceivers) +{ + return matchTransceiver(transceivers, [] (RTCRtpTransceiver& current) { + return current.mid().isNull() && !current.stopped(); + }); +} + +void MediaEndpointPeerConnection::runTask(Function<void ()>&& task) +{ + if (m_dtlsFingerprint.isNull()) { + // Only one task needs to be deferred since it will hold off any others until completed. + ASSERT(!m_initialDeferredTask); + m_initialDeferredTask = WTFMove(task); + } else + callOnMainThread(WTFMove(task)); +} + +void MediaEndpointPeerConnection::startRunningTasks() +{ + if (!m_initialDeferredTask) + return; + + m_initialDeferredTask(); + m_initialDeferredTask = nullptr; +} + +void MediaEndpointPeerConnection::doCreateOffer(RTCOfferOptions&& options) +{ + runTask([this, protectedOptions = WTFMove(options)]() mutable { + createOfferTask(protectedOptions); + }); +} + +void MediaEndpointPeerConnection::createOfferTask(const RTCOfferOptions&) +{ + ASSERT(!m_dtlsFingerprint.isEmpty()); + + MediaEndpointSessionDescription* localDescription = internalLocalDescription(); + RefPtr<MediaEndpointSessionConfiguration> configurationSnapshot = localDescription ? + localDescription->configuration()->clone() : MediaEndpointSessionConfiguration::create(); + + configurationSnapshot->setSessionVersion(m_sdpOfferSessionVersion++); + + auto transceivers = RtpTransceiverVector(m_peerConnection.getTransceivers()); + + // Remove any transceiver objects from transceivers that can be matched to an existing media description. + for (auto& mediaDescription : configurationSnapshot->mediaDescriptions()) { + if (!mediaDescription.port) { + // This media description should be recycled. + continue; + } + + RTCRtpTransceiver* transceiver = matchTransceiverByMid(transceivers, mediaDescription.mid); + if (!transceiver) + continue; + + mediaDescription.mode = transceiver->directionString(); + if (transceiver->hasSendingDirection()) { + auto& sender = transceiver->sender(); + + mediaDescription.mediaStreamId = sender.mediaStreamIds()[0]; + mediaDescription.mediaStreamTrackId = sender.trackId(); + } + + transceivers.removeFirst(transceiver); + } + + // Add media descriptions for remaining transceivers. + for (auto& transceiver : transceivers) { + PeerMediaDescription mediaDescription; + auto& sender = transceiver->sender(); + + mediaDescription.mode = transceiver->directionString(); + mediaDescription.mid = transceiver->provisionalMid(); + mediaDescription.mediaStreamId = sender.mediaStreamIds()[0]; + mediaDescription.type = sender.trackKind(); + mediaDescription.payloads = sender.trackKind() == "audio" ? m_defaultAudioPayloads : m_defaultVideoPayloads; + mediaDescription.dtlsFingerprintHashFunction = m_dtlsFingerprintFunction; + mediaDescription.dtlsFingerprint = m_dtlsFingerprint; + mediaDescription.cname = m_cname; + mediaDescription.addSsrc(cryptographicallyRandomNumber()); + mediaDescription.iceUfrag = m_iceUfrag; + mediaDescription.icePassword = m_icePassword; + + if (sender.track()) + mediaDescription.mediaStreamTrackId = sender.trackId(); + + configurationSnapshot->addMediaDescription(WTFMove(mediaDescription)); + } + + String sdp; + SDPProcessor::Result result = m_sdpProcessor->generate(*configurationSnapshot, sdp); + if (result != SDPProcessor::Result::Success) { + createOfferFailed(Exception { OperationError, "SDPProcessor internal error" }); + return; + } + createOfferSucceeded(WTFMove(sdp)); +} + +void MediaEndpointPeerConnection::doCreateAnswer(RTCAnswerOptions&& options) +{ + runTask([this, protectedOptions = WTFMove(options)]() mutable { + createAnswerTask(protectedOptions); + }); +} + +void MediaEndpointPeerConnection::createAnswerTask(const RTCAnswerOptions&) +{ + ASSERT(!m_dtlsFingerprint.isEmpty()); + + if (!internalRemoteDescription()) { + createAnswerFailed(Exception { INVALID_STATE_ERR, "No remote description set" }); + return; + } + + MediaEndpointSessionDescription* localDescription = internalLocalDescription(); + RefPtr<MediaEndpointSessionConfiguration> configurationSnapshot = localDescription ? + localDescription->configuration()->clone() : MediaEndpointSessionConfiguration::create(); + + configurationSnapshot->setSessionVersion(m_sdpAnswerSessionVersion++); + + auto transceivers = RtpTransceiverVector(m_peerConnection.getTransceivers()); + auto& remoteMediaDescriptions = internalRemoteDescription()->configuration()->mediaDescriptions(); + + for (unsigned i = 0; i < remoteMediaDescriptions.size(); ++i) { + auto& remoteMediaDescription = remoteMediaDescriptions[i]; + + auto* transceiver = matchTransceiverByMid(transceivers, remoteMediaDescription.mid); + if (!transceiver) { + LOG_ERROR("Could not find a matching transceiver for remote description while creating answer"); + continue; + } + + if (i >= configurationSnapshot->mediaDescriptions().size()) { + PeerMediaDescription newMediaDescription; + + auto& sender = transceiver->sender(); + if (sender.track()) { + if (sender.mediaStreamIds().size()) + newMediaDescription.mediaStreamId = sender.mediaStreamIds()[0]; + newMediaDescription.mediaStreamTrackId = sender.trackId(); + newMediaDescription.addSsrc(cryptographicallyRandomNumber()); + } + + newMediaDescription.mode = transceiver->directionString(); + newMediaDescription.type = remoteMediaDescription.type; + newMediaDescription.mid = remoteMediaDescription.mid; + newMediaDescription.dtlsSetup = remoteMediaDescription.dtlsSetup == "active" ? "passive" : "active"; + newMediaDescription.dtlsFingerprintHashFunction = m_dtlsFingerprintFunction; + newMediaDescription.dtlsFingerprint = m_dtlsFingerprint; + newMediaDescription.cname = m_cname; + newMediaDescription.iceUfrag = m_iceUfrag; + newMediaDescription.icePassword = m_icePassword; + + configurationSnapshot->addMediaDescription(WTFMove(newMediaDescription)); + } + + PeerMediaDescription& localMediaDescription = configurationSnapshot->mediaDescriptions()[i]; + + localMediaDescription.payloads = remoteMediaDescription.payloads; + localMediaDescription.rtcpMux = remoteMediaDescription.rtcpMux; + + if (!localMediaDescription.ssrcs.size()) + localMediaDescription.addSsrc(cryptographicallyRandomNumber()); + + if (localMediaDescription.dtlsSetup == "actpass") + localMediaDescription.dtlsSetup = "passive"; + + transceivers.removeFirst(transceiver); + } + + // Unassociated (non-stopped) transceivers need to be negotiated in a follow-up offer. + if (hasUnassociatedTransceivers(transceivers)) + markAsNeedingNegotiation(); + + String sdp; + SDPProcessor::Result result = m_sdpProcessor->generate(*configurationSnapshot, sdp); + if (result != SDPProcessor::Result::Success) { + createAnswerFailed(Exception { OperationError, "SDPProcessor internal error" }); + return; + } + createAnswerSucceeded(WTFMove(sdp)); +} + +static RealtimeMediaSourceMap createSourceMap(const MediaDescriptionVector& remoteMediaDescriptions, unsigned localMediaDescriptionCount, const RtpTransceiverVector& transceivers) +{ + RealtimeMediaSourceMap sourceMap; + + for (unsigned i = 0; i < remoteMediaDescriptions.size() && i < localMediaDescriptionCount; ++i) { + auto& remoteMediaDescription = remoteMediaDescriptions[i]; + if (remoteMediaDescription.type != "audio" && remoteMediaDescription.type != "video") + continue; + + RTCRtpTransceiver* transceiver = matchTransceiverByMid(transceivers, remoteMediaDescription.mid); + if (transceiver) { + if (transceiver->hasSendingDirection() && transceiver->sender().track()) + sourceMap.set(transceiver->mid(), &transceiver->sender().track()->source()); + } + } + + return sourceMap; +} + +void MediaEndpointPeerConnection::doSetLocalDescription(RTCSessionDescription& description) +{ + runTask([this, protectedDescription = RefPtr<RTCSessionDescription>(&description)]() mutable { + setLocalDescriptionTask(WTFMove(protectedDescription)); + }); +} + +void MediaEndpointPeerConnection::setLocalDescriptionTask(RefPtr<RTCSessionDescription>&& description) +{ + if (m_peerConnection.internalSignalingState() == SignalingState::Closed) + return; + + auto result = MediaEndpointSessionDescription::create(WTFMove(description), *m_sdpProcessor); + if (result.hasException()) { + setLocalDescriptionFailed(result.releaseException()); + return; + } + auto newDescription = result.releaseReturnValue(); + + const RtpTransceiverVector& transceivers = m_peerConnection.getTransceivers(); + const MediaDescriptionVector& mediaDescriptions = newDescription->configuration()->mediaDescriptions(); + MediaEndpointSessionDescription* localDescription = internalLocalDescription(); + unsigned previousNumberOfMediaDescriptions = localDescription ? localDescription->configuration()->mediaDescriptions().size() : 0; + bool hasNewMediaDescriptions = mediaDescriptions.size() > previousNumberOfMediaDescriptions; + bool isInitiator = newDescription->type() == RTCSessionDescription::SdpType::Offer; + + if (hasNewMediaDescriptions) { + MediaEndpoint::UpdateResult result = m_mediaEndpoint->updateReceiveConfiguration(newDescription->configuration(), isInitiator); + + if (result == MediaEndpoint::UpdateResult::SuccessWithIceRestart) { + if (m_peerConnection.internalIceGatheringState() != IceGatheringState::Gathering) + m_peerConnection.updateIceGatheringState(IceGatheringState::Gathering); + + if (m_peerConnection.internalIceConnectionState() != IceConnectionState::Completed) + m_peerConnection.updateIceConnectionState(IceConnectionState::Connected); + + LOG_ERROR("ICE restart is not implemented"); + notImplemented(); + + } else if (result == MediaEndpoint::UpdateResult::Failed) { + setLocalDescriptionFailed(Exception { OperationError, "Unable to apply session description" }); + return; + } + + // Associate media descriptions with transceivers (set provisional mid to 'final' mid). + for (auto& mediaDescription : mediaDescriptions) { + RTCRtpTransceiver* transceiver = matchTransceiver(transceivers, [&mediaDescription] (RTCRtpTransceiver& current) { + return current.provisionalMid() == mediaDescription.mid; + }); + if (transceiver) + transceiver->setMid(transceiver->provisionalMid()); + } + } + + if (internalRemoteDescription()) { + MediaEndpointSessionConfiguration* remoteConfiguration = internalRemoteDescription()->configuration(); + RealtimeMediaSourceMap sendSourceMap = createSourceMap(remoteConfiguration->mediaDescriptions(), mediaDescriptions.size(), transceivers); + + if (m_mediaEndpoint->updateSendConfiguration(remoteConfiguration, sendSourceMap, isInitiator) == MediaEndpoint::UpdateResult::Failed) { + setLocalDescriptionFailed(Exception { OperationError, "Unable to apply session description" }); + return; + } + } + + if (!hasUnassociatedTransceivers(transceivers)) + clearNegotiationNeededState(); + + SignalingState newSignalingState; + + // Update state and local descriptions according to setLocal/RemoteDescription processing model + switch (newDescription->type()) { + case RTCSessionDescription::SdpType::Offer: + m_pendingLocalDescription = WTFMove(newDescription); + newSignalingState = SignalingState::HaveLocalOffer; + break; + + case RTCSessionDescription::SdpType::Answer: + m_currentLocalDescription = WTFMove(newDescription); + m_currentRemoteDescription = m_pendingRemoteDescription; + m_pendingLocalDescription = nullptr; + m_pendingRemoteDescription = nullptr; + newSignalingState = SignalingState::Stable; + break; + + case RTCSessionDescription::SdpType::Rollback: + m_pendingLocalDescription = nullptr; + newSignalingState = SignalingState::Stable; + break; + + case RTCSessionDescription::SdpType::Pranswer: + m_pendingLocalDescription = WTFMove(newDescription); + newSignalingState = SignalingState::HaveLocalPrAnswer; + break; + } + + updateSignalingState(newSignalingState); + + if (m_peerConnection.internalIceGatheringState() == IceGatheringState::New && mediaDescriptions.size()) + m_peerConnection.updateIceGatheringState(IceGatheringState::Gathering); + + markAsNeedingNegotiation(); + setLocalDescriptionSucceeded(); +} + +RefPtr<RTCSessionDescription> MediaEndpointPeerConnection::localDescription() const +{ + return createRTCSessionDescription(internalLocalDescription()); +} + +RefPtr<RTCSessionDescription> MediaEndpointPeerConnection::currentLocalDescription() const +{ + return createRTCSessionDescription(m_currentLocalDescription.get()); +} + +RefPtr<RTCSessionDescription> MediaEndpointPeerConnection::pendingLocalDescription() const +{ + return createRTCSessionDescription(m_pendingLocalDescription.get()); +} + +void MediaEndpointPeerConnection::doSetRemoteDescription(RTCSessionDescription& description) +{ + runTask([this, protectedDescription = RefPtr<RTCSessionDescription>(&description)]() mutable { + setRemoteDescriptionTask(WTFMove(protectedDescription)); + }); +} + +void MediaEndpointPeerConnection::setRemoteDescriptionTask(RefPtr<RTCSessionDescription>&& description) +{ + auto result = MediaEndpointSessionDescription::create(WTFMove(description), *m_sdpProcessor); + if (result.hasException()) { + setRemoteDescriptionFailed(result.releaseException()); + return; + } + auto newDescription = result.releaseReturnValue(); + + auto& mediaDescriptions = newDescription->configuration()->mediaDescriptions(); + for (auto& mediaDescription : mediaDescriptions) { + if (mediaDescription.type != "audio" && mediaDescription.type != "video") + continue; + + mediaDescription.payloads = m_mediaEndpoint->filterPayloads(mediaDescription.payloads, mediaDescription.type == "audio" ? m_defaultAudioPayloads : m_defaultVideoPayloads); + } + + bool isInitiator = newDescription->type() == RTCSessionDescription::SdpType::Answer; + const RtpTransceiverVector& transceivers = m_peerConnection.getTransceivers(); + + RealtimeMediaSourceMap sendSourceMap; + if (internalLocalDescription()) + sendSourceMap = createSourceMap(mediaDescriptions, internalLocalDescription()->configuration()->mediaDescriptions().size(), transceivers); + + if (m_mediaEndpoint->updateSendConfiguration(newDescription->configuration(), sendSourceMap, isInitiator) == MediaEndpoint::UpdateResult::Failed) { + setRemoteDescriptionFailed(Exception { OperationError, "Unable to apply session description" }); + return; + } + + // One legacy MediaStreamEvent will be fired for every new MediaStream created as this remote description is set. + Vector<RefPtr<MediaStreamEvent>> legacyMediaStreamEvents; + + for (auto& mediaDescription : mediaDescriptions) { + RTCRtpTransceiver* transceiver = matchTransceiverByMid(transceivers, mediaDescription.mid); + if (!transceiver) { + bool receiveOnlyFlag = false; + + if (mediaDescription.mode == "sendrecv" || mediaDescription.mode == "recvonly") { + // Try to match an existing transceiver. + transceiver = matchTransceiver(transceivers, [&mediaDescription] (RTCRtpTransceiver& current) { + return !current.stopped() && current.mid().isNull() && current.sender().trackKind() == mediaDescription.type; + }); + + if (transceiver) { + // This transceiver was created locally with a provisional mid. Its real mid will now be set by the remote + // description so we need to update the mid of the transceiver's muted source to preserve the association. + transceiver->setMid(mediaDescription.mid); + m_mediaEndpoint->replaceMutedRemoteSourceMid(transceiver->provisionalMid(), mediaDescription.mid); + } else + receiveOnlyFlag = true; + } + + if (!transceiver) { + auto sender = RTCRtpSender::create(mediaDescription.type, Vector<String>(), m_peerConnection.senderClient()); + auto receiver = createReceiver(mediaDescription.mid, mediaDescription.type, mediaDescription.mediaStreamTrackId); + + auto newTransceiver = RTCRtpTransceiver::create(WTFMove(sender), WTFMove(receiver)); + newTransceiver->setMid(mediaDescription.mid); + if (receiveOnlyFlag) + newTransceiver->disableSendingDirection(); + + transceiver = newTransceiver.ptr(); + m_peerConnection.addTransceiver(WTFMove(newTransceiver)); + } + } + + if (mediaDescription.mode == "sendrecv" || mediaDescription.mode == "sendonly") { + auto& receiver = transceiver->receiver(); + if (receiver.isDispatched()) + continue; + receiver.setDispatched(true); + + Vector<String> mediaStreamIds; + if (!mediaDescription.mediaStreamId.isEmpty()) + mediaStreamIds.append(mediaDescription.mediaStreamId); + + // A remote track can be associated with 0..* MediaStreams. We create a new stream for + // a track in case of an unrecognized stream id, or just add the track if the stream + // already exists. + HashMap<String, RefPtr<MediaStream>> trackEventMediaStreams; + for (auto& id : mediaStreamIds) { + if (m_remoteStreamMap.contains(id)) { + RefPtr<MediaStream> stream = m_remoteStreamMap.get(id); + stream->addTrack(*receiver.track()); + trackEventMediaStreams.add(id, WTFMove(stream)); + } else { + auto newStream = MediaStream::create(*m_peerConnection.scriptExecutionContext(), MediaStreamTrackVector({ receiver.track() })); + m_remoteStreamMap.add(id, newStream.copyRef()); + legacyMediaStreamEvents.append(MediaStreamEvent::create(eventNames().addstreamEvent, false, false, newStream.copyRef())); + trackEventMediaStreams.add(id, WTFMove(newStream)); + } + } + + Vector<RefPtr<MediaStream>> streams; + copyValuesToVector(trackEventMediaStreams, streams); + + m_peerConnection.fireEvent(RTCTrackEvent::create(eventNames().trackEvent, false, false, + &receiver, receiver.track(), WTFMove(streams), transceiver)); + } + } + + // Fire legacy addstream events. + for (auto& event : legacyMediaStreamEvents) + m_peerConnection.fireEvent(*event); + + SignalingState newSignalingState; + + // Update state and local descriptions according to setLocal/RemoteDescription processing model + switch (newDescription->type()) { + case RTCSessionDescription::SdpType::Offer: + m_pendingRemoteDescription = WTFMove(newDescription); + newSignalingState = SignalingState::HaveRemoteOffer; + break; + + case RTCSessionDescription::SdpType::Answer: + m_currentRemoteDescription = WTFMove(newDescription); + m_currentLocalDescription = m_pendingLocalDescription; + m_pendingRemoteDescription = nullptr; + m_pendingLocalDescription = nullptr; + newSignalingState = SignalingState::Stable; + break; + + case RTCSessionDescription::SdpType::Rollback: + m_pendingRemoteDescription = nullptr; + newSignalingState = SignalingState::Stable; + break; + + case RTCSessionDescription::SdpType::Pranswer: + m_pendingRemoteDescription = WTFMove(newDescription); + newSignalingState = SignalingState::HaveRemotePrAnswer; + break; + } + + updateSignalingState(newSignalingState); + setRemoteDescriptionSucceeded(); +} + +RefPtr<RTCSessionDescription> MediaEndpointPeerConnection::remoteDescription() const +{ + return createRTCSessionDescription(internalRemoteDescription()); +} + +RefPtr<RTCSessionDescription> MediaEndpointPeerConnection::currentRemoteDescription() const +{ + return createRTCSessionDescription(m_currentRemoteDescription.get()); +} + +RefPtr<RTCSessionDescription> MediaEndpointPeerConnection::pendingRemoteDescription() const +{ + return createRTCSessionDescription(m_pendingRemoteDescription.get()); +} + +void MediaEndpointPeerConnection::setConfiguration(MediaEndpointConfiguration&& configuration) +{ + m_mediaEndpoint->setConfiguration(WTFMove(configuration)); +} + +void MediaEndpointPeerConnection::doAddIceCandidate(RTCIceCandidate& rtcCandidate) +{ + runTask([this, protectedCandidate = RefPtr<RTCIceCandidate>(&rtcCandidate)]() mutable { + addIceCandidateTask(*protectedCandidate); + }); +} + +void MediaEndpointPeerConnection::addIceCandidateTask(RTCIceCandidate& rtcCandidate) +{ + if (!internalRemoteDescription()) { + addIceCandidateFailed(Exception { INVALID_STATE_ERR, "No remote description set" }); + return; + } + + auto& remoteMediaDescriptions = internalRemoteDescription()->configuration()->mediaDescriptions(); + PeerMediaDescription* targetMediaDescription = nullptr; + + // When identifying the target media description, sdpMid takes precedence over sdpMLineIndex + // if both are present. + if (!rtcCandidate.sdpMid().isNull()) { + const String& mid = rtcCandidate.sdpMid(); + for (auto& description : remoteMediaDescriptions) { + if (description.mid == mid) { + targetMediaDescription = &description; + break; + } + } + + if (!targetMediaDescription) { + addIceCandidateFailed(Exception { OperationError, "sdpMid did not match any media description" }); + return; + } + } else if (rtcCandidate.sdpMLineIndex()) { + unsigned short sdpMLineIndex = rtcCandidate.sdpMLineIndex().value(); + if (sdpMLineIndex >= remoteMediaDescriptions.size()) { + addIceCandidateFailed(Exception { OperationError, "sdpMLineIndex is out of range" }); + return; + } + targetMediaDescription = &remoteMediaDescriptions[sdpMLineIndex]; + } else { + ASSERT_NOT_REACHED(); + return; + } + + auto result = m_sdpProcessor->parseCandidateLine(rtcCandidate.candidate()); + if (result.parsingStatus() != SDPProcessor::Result::Success) { + if (result.parsingStatus() == SDPProcessor::Result::ParseError) + addIceCandidateFailed(Exception { OperationError, "Invalid candidate content" }); + else + LOG_ERROR("SDPProcessor internal error"); + return; + } + + ASSERT(targetMediaDescription); + m_mediaEndpoint->addRemoteCandidate(result.candidate(), targetMediaDescription->mid, targetMediaDescription->iceUfrag, targetMediaDescription->icePassword); + + targetMediaDescription->addIceCandidate(WTFMove(result.candidate())); + + addIceCandidateSucceeded(); +} + +void MediaEndpointPeerConnection::getStats(MediaStreamTrack* track, Ref<DeferredPromise>&& promise) +{ + m_mediaEndpoint->getStats(track, WTFMove(promise)); +} + +Vector<RefPtr<MediaStream>> MediaEndpointPeerConnection::getRemoteStreams() const +{ + Vector<RefPtr<MediaStream>> remoteStreams; + copyValuesToVector(m_remoteStreamMap, remoteStreams); + return remoteStreams; +} + +Ref<RTCRtpReceiver> MediaEndpointPeerConnection::createReceiver(const String& transceiverMid, const String& trackKind, const String& trackId) +{ + RealtimeMediaSource::Type sourceType = trackKind == "audio" ? RealtimeMediaSource::Type::Audio : RealtimeMediaSource::Type::Video; + + // Create a muted remote source that will be unmuted once media starts arriving. + auto remoteSource = m_mediaEndpoint->createMutedRemoteSource(transceiverMid, sourceType); + auto remoteTrackPrivate = MediaStreamTrackPrivate::create(WTFMove(remoteSource), String(trackId)); + auto remoteTrack = MediaStreamTrack::create(*m_peerConnection.scriptExecutionContext(), WTFMove(remoteTrackPrivate)); + + return RTCRtpReceiver::create(WTFMove(remoteTrack)); +} + +std::unique_ptr<RTCDataChannelHandler> MediaEndpointPeerConnection::createDataChannelHandler(const String& label, const RTCDataChannelInit& options) +{ + return m_mediaEndpoint->createDataChannelHandler(label, options); +} + +void MediaEndpointPeerConnection::replaceTrack(RTCRtpSender& sender, RefPtr<MediaStreamTrack>&& withTrack, DOMPromise<void>&& promise) +{ + RTCRtpTransceiver* transceiver = matchTransceiver(m_peerConnection.getTransceivers(), [&sender] (RTCRtpTransceiver& current) { + return ¤t.sender() == &sender; + }); + ASSERT(transceiver); + + const String& mid = transceiver->mid(); + if (mid.isNull()) { + // Transceiver is not associated with a media description yet. + sender.setTrack(WTFMove(withTrack)); + promise.resolve(); + return; + } + + runTask([this, protectedSender = RefPtr<RTCRtpSender>(&sender), mid, protectedTrack = WTFMove(withTrack), protectedPromise = WTFMove(promise)]() mutable { + replaceTrackTask(*protectedSender, mid, WTFMove(protectedTrack), protectedPromise); + }); +} + +void MediaEndpointPeerConnection::replaceTrackTask(RTCRtpSender& sender, const String& mid, RefPtr<MediaStreamTrack>&& withTrack, DOMPromise<void>& promise) +{ + if (m_peerConnection.internalSignalingState() == SignalingState::Closed) + return; + + m_mediaEndpoint->replaceSendSource(withTrack->source(), mid); + + sender.setTrack(WTFMove(withTrack)); + promise.resolve(); +} + +void MediaEndpointPeerConnection::doStop() +{ + m_mediaEndpoint->stop(); +} + +void MediaEndpointPeerConnection::emulatePlatformEvent(const String& action) +{ + m_mediaEndpoint->emulatePlatformEvent(action); +} + +MediaEndpointSessionDescription* MediaEndpointPeerConnection::internalLocalDescription() const +{ + return m_pendingLocalDescription ? m_pendingLocalDescription.get() : m_currentLocalDescription.get(); +} + +MediaEndpointSessionDescription* MediaEndpointPeerConnection::internalRemoteDescription() const +{ + return m_pendingRemoteDescription ? m_pendingRemoteDescription.get() : m_currentRemoteDescription.get(); +} + +RefPtr<RTCSessionDescription> MediaEndpointPeerConnection::createRTCSessionDescription(MediaEndpointSessionDescription* description) const +{ + return description ? description->toRTCSessionDescription(*m_sdpProcessor) : nullptr; +} + +void MediaEndpointPeerConnection::gotDtlsFingerprint(const String& fingerprint, const String& fingerprintFunction) +{ + ASSERT(isMainThread()); + + m_dtlsFingerprint = fingerprint; + m_dtlsFingerprintFunction = fingerprintFunction; + + startRunningTasks(); +} + +void MediaEndpointPeerConnection::gotIceCandidate(const String& mid, IceCandidate&& candidate) +{ + ASSERT(isMainThread()); + + auto& mediaDescriptions = internalLocalDescription()->configuration()->mediaDescriptions(); + size_t mediaDescriptionIndex = notFound; + + for (size_t i = 0; i < mediaDescriptions.size(); ++i) { + if (mediaDescriptions[i].mid == mid) { + mediaDescriptionIndex = i; + break; + } + } + ASSERT(mediaDescriptionIndex != notFound); + + String candidateLine; + auto result = m_sdpProcessor->generateCandidateLine(candidate, candidateLine); + if (result != SDPProcessor::Result::Success) { + LOG_ERROR("SDPProcessor internal error"); + return; + } + + mediaDescriptions[mediaDescriptionIndex].addIceCandidate(WTFMove(candidate)); + + fireICECandidateEvent(RTCIceCandidate::create(candidateLine, mid, mediaDescriptionIndex)); +} + +void MediaEndpointPeerConnection::doneGatheringCandidates(const String& mid) +{ + ASSERT(isMainThread()); + + RtpTransceiverVector transceivers = RtpTransceiverVector(m_peerConnection.getTransceivers()); + RTCRtpTransceiver* notifyingTransceiver = matchTransceiverByMid(transceivers, mid); + ASSERT(notifyingTransceiver); + + notifyingTransceiver->iceTransport().setGatheringState(RTCIceTransport::GatheringState::Complete); + + // Don't notify the script if there are transceivers still gathering. + RTCRtpTransceiver* stillGatheringTransceiver = matchTransceiver(transceivers, [] (RTCRtpTransceiver& current) { + return !current.stopped() && !current.mid().isNull() + && current.iceTransport().gatheringState() != RTCIceTransport::GatheringState::Complete; + }); + if (!stillGatheringTransceiver) + PeerConnectionBackend::doneGatheringCandidates(); +} + +static RTCIceTransport::TransportState deriveAggregatedIceConnectionState(const Vector<RTCIceTransport::TransportState>& states) +{ + unsigned newCount = 0; + unsigned checkingCount = 0; + unsigned connectedCount = 0; + unsigned completedCount = 0; + unsigned failedCount = 0; + unsigned disconnectedCount = 0; + unsigned closedCount = 0; + + for (auto& state : states) { + switch (state) { + case RTCIceTransport::TransportState::New: ++newCount; break; + case RTCIceTransport::TransportState::Checking: ++checkingCount; break; + case RTCIceTransport::TransportState::Connected: ++connectedCount; break; + case RTCIceTransport::TransportState::Completed: ++completedCount; break; + case RTCIceTransport::TransportState::Failed: ++failedCount; break; + case RTCIceTransport::TransportState::Disconnected: ++disconnectedCount; break; + case RTCIceTransport::TransportState::Closed: ++closedCount; break; + } + } + + // The aggregated RTCIceConnectionState is derived from the RTCIceTransportState of all RTCIceTransports. + if ((newCount > 0 && !checkingCount && !failedCount && !disconnectedCount) || (closedCount == states.size())) + return RTCIceTransport::TransportState::New; + + if (checkingCount > 0 && !failedCount && !disconnectedCount) + return RTCIceTransport::TransportState::Checking; + + if ((connectedCount + completedCount + closedCount) == states.size() && connectedCount > 0) + return RTCIceTransport::TransportState::Connected; + + if ((completedCount + closedCount) == states.size() && completedCount > 0) + return RTCIceTransport::TransportState::Completed; + + if (failedCount > 0) + return RTCIceTransport::TransportState::Failed; + + if (disconnectedCount > 0) // Any failed caught above. + return RTCIceTransport::TransportState::Disconnected; + + ASSERT_NOT_REACHED(); + return RTCIceTransport::TransportState::New; +} + +void MediaEndpointPeerConnection::iceTransportStateChanged(const String& mid, MediaEndpoint::IceTransportState mediaEndpointIceTransportState) +{ + ASSERT(isMainThread()); + + RTCRtpTransceiver* transceiver = matchTransceiverByMid(m_peerConnection.getTransceivers(), mid); + ASSERT(transceiver); + + RTCIceTransport::TransportState transportState = static_cast<RTCIceTransport::TransportState>(mediaEndpointIceTransportState); + transceiver->iceTransport().setTransportState(transportState); + + // Determine if the script needs to be notified. + Vector<RTCIceTransport::TransportState> transportStates; + for (auto& transceiver : m_peerConnection.getTransceivers()) + transportStates.append(transceiver->iceTransport().transportState()); + + RTCIceTransport::TransportState derivedState = deriveAggregatedIceConnectionState(transportStates); + m_peerConnection.updateIceConnectionState(static_cast<IceConnectionState>(derivedState)); +} + +} // namespace WebCore + +#endif // ENABLE(WEB_RTC) diff --git a/Source/WebCore/Modules/mediastream/MediaEndpointPeerConnection.h b/Source/WebCore/Modules/mediastream/MediaEndpointPeerConnection.h new file mode 100644 index 000000000..01b37843d --- /dev/null +++ b/Source/WebCore/Modules/mediastream/MediaEndpointPeerConnection.h @@ -0,0 +1,132 @@ +/* + * 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 "PeerConnectionBackend.h" +#include "RTCSessionDescription.h" +#include <wtf/Function.h> + +namespace WebCore { + +class MediaEndpointSessionDescription; +class SDPProcessor; + +class MediaEndpointPeerConnection final : public PeerConnectionBackend, public MediaEndpointClient { +public: + WEBCORE_EXPORT explicit MediaEndpointPeerConnection(RTCPeerConnection&); + +private: + RefPtr<RTCSessionDescription> localDescription() const final; + RefPtr<RTCSessionDescription> currentLocalDescription() const final; + RefPtr<RTCSessionDescription> pendingLocalDescription() const final; + + RefPtr<RTCSessionDescription> remoteDescription() const final; + RefPtr<RTCSessionDescription> currentRemoteDescription() const final; + RefPtr<RTCSessionDescription> pendingRemoteDescription() const final; + + void setConfiguration(MediaEndpointConfiguration&&) final; + + void getStats(MediaStreamTrack*, Ref<DeferredPromise>&&) final; + + Vector<RefPtr<MediaStream>> getRemoteStreams() const final; + + Ref<RTCRtpReceiver> createReceiver(const String& transceiverMid, const String& trackKind, const String& trackId) final; + void replaceTrack(RTCRtpSender&, RefPtr<MediaStreamTrack>&&, DOMPromise<void>&&) final; + + void emulatePlatformEvent(const String& action) final; + + void runTask(Function<void ()>&&); + void startRunningTasks(); + + void doCreateOffer(RTCOfferOptions&&) final; + void doCreateAnswer(RTCAnswerOptions&&) final; + void doSetLocalDescription(RTCSessionDescription&) final; + void doSetRemoteDescription(RTCSessionDescription&) final; + void doAddIceCandidate(RTCIceCandidate&) final; + void doStop() final; + + void createOfferTask(const RTCOfferOptions&); + void createAnswerTask(const RTCAnswerOptions&); + + void setLocalDescriptionTask(RefPtr<RTCSessionDescription>&&); + void setRemoteDescriptionTask(RefPtr<RTCSessionDescription>&&); + + void addIceCandidateTask(RTCIceCandidate&); + + void replaceTrackTask(RTCRtpSender&, const String& mid, RefPtr<MediaStreamTrack>&&, DOMPromise<void>&); + + bool localDescriptionTypeValidForState(RTCSessionDescription::SdpType) const; + bool remoteDescriptionTypeValidForState(RTCSessionDescription::SdpType) const; + + MediaEndpointSessionDescription* internalLocalDescription() const; + MediaEndpointSessionDescription* internalRemoteDescription() const; + RefPtr<RTCSessionDescription> createRTCSessionDescription(MediaEndpointSessionDescription*) const; + + // MediaEndpointClient + void gotDtlsFingerprint(const String& fingerprint, const String& fingerprintFunction) final; + void gotIceCandidate(const String& mid, IceCandidate&&) final; + void doneGatheringCandidates(const String& mid) final; + void iceTransportStateChanged(const String& mid, MediaEndpoint::IceTransportState) final; + + std::unique_ptr<RTCDataChannelHandler> createDataChannelHandler(const String&, const RTCDataChannelInit&) final; + + std::unique_ptr<MediaEndpoint> m_mediaEndpoint; + + Function<void ()> m_initialDeferredTask; + + std::unique_ptr<SDPProcessor> m_sdpProcessor; + + Vector<MediaPayload> m_defaultAudioPayloads; + Vector<MediaPayload> m_defaultVideoPayloads; + + String m_cname; + String m_iceUfrag; + String m_icePassword; + String m_dtlsFingerprint; + String m_dtlsFingerprintFunction; + unsigned m_sdpOfferSessionVersion { 0 }; + unsigned m_sdpAnswerSessionVersion { 0 }; + + RefPtr<MediaEndpointSessionDescription> m_currentLocalDescription; + RefPtr<MediaEndpointSessionDescription> m_pendingLocalDescription; + + RefPtr<MediaEndpointSessionDescription> m_currentRemoteDescription; + RefPtr<MediaEndpointSessionDescription> m_pendingRemoteDescription; + + HashMap<String, RefPtr<MediaStream>> m_remoteStreamMap; +}; + +} // namespace WebCore + +#endif // ENABLE(WEB_RTC) diff --git a/Source/WebCore/Modules/mediastream/MediaEndpointSessionDescription.cpp b/Source/WebCore/Modules/mediastream/MediaEndpointSessionDescription.cpp new file mode 100644 index 000000000..ac5b2f0d8 --- /dev/null +++ b/Source/WebCore/Modules/mediastream/MediaEndpointSessionDescription.cpp @@ -0,0 +1,116 @@ +/* + * 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" +#include "MediaEndpointSessionDescription.h" + +#if ENABLE(WEB_RTC) + +#include "ExceptionCode.h" +#include "SDPProcessor.h" +#include <wtf/NeverDestroyed.h> + +namespace WebCore { + +#define STRING_FUNCTION(name) \ + static const String& name##String() \ + { \ + static NeverDestroyed<const String> name { ASCIILiteral(#name) }; \ + return name; \ + } + +STRING_FUNCTION(offer) +STRING_FUNCTION(pranswer) +STRING_FUNCTION(answer) +STRING_FUNCTION(rollback) + +Ref<MediaEndpointSessionDescription> MediaEndpointSessionDescription::create(RTCSessionDescription::SdpType type, RefPtr<MediaEndpointSessionConfiguration>&& configuration) +{ + return adoptRef(*new MediaEndpointSessionDescription(type, WTFMove(configuration), nullptr)); +} + +ExceptionOr<Ref<MediaEndpointSessionDescription>> MediaEndpointSessionDescription::create(RefPtr<RTCSessionDescription>&& rtcDescription, const SDPProcessor& sdpProcessor) +{ + RefPtr<MediaEndpointSessionConfiguration> configuration; + auto result = sdpProcessor.parse(rtcDescription->sdp(), configuration); + if (result != SDPProcessor::Result::Success) { + if (result == SDPProcessor::Result::ParseError) + return Exception { INVALID_ACCESS_ERR, ASCIILiteral("SDP content is invalid") }; + LOG_ERROR("SDPProcessor internal error"); + return Exception { ABORT_ERR, ASCIILiteral("Internal error") }; + } + return adoptRef(*new MediaEndpointSessionDescription(rtcDescription->type(), WTFMove(configuration), WTFMove(rtcDescription))); +} + +RefPtr<RTCSessionDescription> MediaEndpointSessionDescription::toRTCSessionDescription(const SDPProcessor& sdpProcessor) const +{ + String sdpString; + SDPProcessor::Result result = sdpProcessor.generate(*m_configuration, sdpString); + if (result != SDPProcessor::Result::Success) { + LOG_ERROR("SDPProcessor internal error"); + return nullptr; + } + + // If this object was created from an RTCSessionDescription, toRTCSessionDescription will return + // that same instance but with an updated sdp. It is used for RTCPeerConnection's description + // atributes (e.g. localDescription and pendingLocalDescription). + if (m_rtcDescription) { + m_rtcDescription->setSdp(sdpString); + return m_rtcDescription; + } + + return RTCSessionDescription::create(m_type, sdpString); +} + +const String& MediaEndpointSessionDescription::typeString() const +{ + switch (m_type) { + case RTCSessionDescription::SdpType::Offer: + return offerString(); + case RTCSessionDescription::SdpType::Pranswer: + return pranswerString(); + case RTCSessionDescription::SdpType::Answer: + return answerString(); + case RTCSessionDescription::SdpType::Rollback: + return rollbackString(); + } + + ASSERT_NOT_REACHED(); + return emptyString(); +} + +bool MediaEndpointSessionDescription::isLaterThan(MediaEndpointSessionDescription* other) const +{ + return !other || configuration()->sessionVersion() > other->configuration()->sessionVersion(); +} + +} // namespace WebCore + +#endif // ENABLE(WEB_RTC) diff --git a/Source/WebCore/Modules/mediastream/MediaEndpointSessionDescription.h b/Source/WebCore/Modules/mediastream/MediaEndpointSessionDescription.h new file mode 100644 index 000000000..60316ce58 --- /dev/null +++ b/Source/WebCore/Modules/mediastream/MediaEndpointSessionDescription.h @@ -0,0 +1,75 @@ +/* + * 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 "ExceptionOr.h" +#include "RTCSessionDescription.h" +#include <wtf/RefCounted.h> +#include <wtf/RefPtr.h> + +namespace WebCore { + +class MediaEndpointSessionConfiguration; +class SDPProcessor; +class DOMError; + +class MediaEndpointSessionDescription : public RefCounted<MediaEndpointSessionDescription> { +public: + static Ref<MediaEndpointSessionDescription> create(RTCSessionDescription::SdpType, RefPtr<MediaEndpointSessionConfiguration>&&); + static ExceptionOr<Ref<MediaEndpointSessionDescription>> create(RefPtr<RTCSessionDescription>&&, const SDPProcessor&); + virtual ~MediaEndpointSessionDescription() { } // FIXME: Why is this virtual? There are no other virtual functions in this class. + + RefPtr<RTCSessionDescription> toRTCSessionDescription(const SDPProcessor&) const; + + RTCSessionDescription::SdpType type() const { return m_type; } + const String& typeString() const; + MediaEndpointSessionConfiguration* configuration() const { return m_configuration.get(); } + + bool isLaterThan(MediaEndpointSessionDescription* other) const; + +private: + MediaEndpointSessionDescription(RTCSessionDescription::SdpType type, RefPtr<MediaEndpointSessionConfiguration>&& configuration, RefPtr<RTCSessionDescription>&& rtcDescription) + : m_type(type) + , m_configuration(configuration) + , m_rtcDescription(WTFMove(rtcDescription)) + { } + + RTCSessionDescription::SdpType m_type; + RefPtr<MediaEndpointSessionConfiguration> m_configuration; + + RefPtr<RTCSessionDescription> m_rtcDescription; +}; + +} // namespace WebCore + +#endif // ENABLE(WEB_RTC) diff --git a/Source/WebCore/Modules/mediastream/MediaSourceStates.cpp b/Source/WebCore/Modules/mediastream/MediaSourceStates.cpp deleted file mode 100644 index 6f7eff6e4..000000000 --- a/Source/WebCore/Modules/mediastream/MediaSourceStates.cpp +++ /dev/null @@ -1,59 +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. - */ - -#include "config.h" - -#if ENABLE(MEDIA_STREAM) - -#include "MediaSourceStates.h" - -#include <wtf/NeverDestroyed.h> - -namespace WebCore { - -RefPtr<MediaSourceStates> MediaSourceStates::create(const MediaStreamSourceStates& states) -{ - return adoptRef(new MediaSourceStates(states)); -} - -MediaSourceStates::MediaSourceStates(const MediaStreamSourceStates& states) - : m_sourceStates(states) -{ -} - -const AtomicString& MediaSourceStates::sourceType() const -{ - return MediaStreamSourceStates::sourceType(m_sourceStates.sourceType()); -} - -const AtomicString& MediaSourceStates::facingMode() const -{ - return MediaStreamSourceStates::facingMode(m_sourceStates.facingMode()); -} - - -} // namespace WebCore - -#endif diff --git a/Source/WebCore/Modules/mediastream/MediaSourceStates.h b/Source/WebCore/Modules/mediastream/MediaSourceStates.h deleted file mode 100644 index b0a4554e2..000000000 --- a/Source/WebCore/Modules/mediastream/MediaSourceStates.h +++ /dev/null @@ -1,63 +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 MediaSourceStates_h -#define MediaSourceStates_h - -#if ENABLE(MEDIA_STREAM) - -#include "MediaStreamSourceCapabilities.h" -#include "ScriptWrappable.h" -#include <wtf/Forward.h> -#include <wtf/RefCounted.h> - -namespace WebCore { - -class MediaSourceStates : public RefCounted<MediaSourceStates>, public ScriptWrappable { -public: - static RefPtr<MediaSourceStates> create(const MediaStreamSourceStates&); - - const AtomicString& sourceType() const; - const AtomicString& sourceId() const { return m_sourceStates.sourceId(); } - unsigned long width() const { return m_sourceStates.width(); } - unsigned long height() const { return m_sourceStates.height(); } - float frameRate() const { return m_sourceStates.frameRate(); } - float aspectRatio() const { return m_sourceStates.aspectRatio(); } - const AtomicString& facingMode() const; - unsigned long volume() const { return m_sourceStates.volume(); } - - bool hasVideoSource() const { return m_sourceStates.sourceType() == MediaStreamSourceStates::Camera; } - -private: - explicit MediaSourceStates(const MediaStreamSourceStates&); - - MediaStreamSourceStates m_sourceStates; -}; - -} // namespace WebCore - -#endif // MediaSourceStates_h - -#endif diff --git a/Source/WebCore/Modules/mediastream/MediaSourceStates.idl b/Source/WebCore/Modules/mediastream/MediaSourceStates.idl deleted file mode 100644 index 6ce9f7ef1..000000000 --- a/Source/WebCore/Modules/mediastream/MediaSourceStates.idl +++ /dev/null @@ -1,44 +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. - */ - -enum SourceTypeEnum { "none", "camera", "microphone" }; -enum VideoFacingModeEnum { "user", "environment", "left", "right" }; - -[ - Conditional=MEDIA_STREAM, - ImplementationLacksVTable, - NoInterfaceObject, -] interface MediaSourceStates { - readonly attribute SourceTypeEnum sourceType; - readonly attribute DOMString sourceId; - - [CustomGetter] readonly attribute unsigned long? width; - [CustomGetter] readonly attribute unsigned long? height; - [CustomGetter] readonly attribute float? frameRate; - [CustomGetter] readonly attribute float? aspectRatio; - [CustomGetter] readonly attribute VideoFacingModeEnum? facingMode; - [CustomGetter] readonly attribute unsigned long? volume; -}; - diff --git a/Source/WebCore/Modules/mediastream/MediaStream.cpp b/Source/WebCore/Modules/mediastream/MediaStream.cpp index 22ec3d4cc..dcacf8f82 100644 --- a/Source/WebCore/Modules/mediastream/MediaStream.cpp +++ b/Source/WebCore/Modules/mediastream/MediaStream.cpp @@ -1,7 +1,7 @@ /* * Copyright (C) 2011 Google Inc. All rights reserved. - * Copyright (C) 2011, 2012 Ericsson AB. All rights reserved. - * Copyright (C) 2013 Apple Inc. All rights reserved. + * Copyright (C) 2011, 2012, 2015 Ericsson AB. All rights reserved. + * Copyright (C) 2013-2016 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 @@ -30,356 +30,366 @@ #if ENABLE(MEDIA_STREAM) -#include "AudioStreamTrack.h" +#include "Document.h" #include "Event.h" -#include "ExceptionCode.h" -#include "MediaStreamCenter.h" +#include "EventNames.h" +#include "Logging.h" #include "MediaStreamRegistry.h" -#include "MediaStreamSource.h" #include "MediaStreamTrackEvent.h" -#include "VideoStreamTrack.h" -#include <wtf/NeverDestroyed.h> +#include "Page.h" +#include "RealtimeMediaSource.h" +#include "URL.h" namespace WebCore { -PassRefPtr<MediaStream> MediaStream::create(ScriptExecutionContext& context) +Ref<MediaStream> MediaStream::create(ScriptExecutionContext& context) { - return MediaStream::create(context, MediaStreamPrivate::create(Vector<RefPtr<MediaStreamSource>>(), Vector<RefPtr<MediaStreamSource>>())); + return MediaStream::create(context, MediaStreamPrivate::create(Vector<RefPtr<MediaStreamTrackPrivate>>())); } -PassRefPtr<MediaStream> MediaStream::create(ScriptExecutionContext& context, PassRefPtr<MediaStream> stream) +Ref<MediaStream> MediaStream::create(ScriptExecutionContext& context, MediaStream& stream) { - ASSERT(stream); - - Vector<RefPtr<MediaStreamTrackPrivate>> audioTracks; - Vector<RefPtr<MediaStreamTrackPrivate>> videoTracks; - - for (size_t i = 0; i < stream->m_audioTracks.size(); ++i) - audioTracks.append(&stream->m_audioTracks[i]->privateTrack()); - - for (size_t i = 0; i < stream->m_videoTracks.size(); ++i) - videoTracks.append(&stream->m_videoTracks[i]->privateTrack()); - - return MediaStream::create(context, MediaStreamPrivate::create(audioTracks, videoTracks)); + return adoptRef(*new MediaStream(context, stream.getTracks())); } -PassRefPtr<MediaStream> MediaStream::create(ScriptExecutionContext& context, const Vector<RefPtr<MediaStreamTrack>>& tracks) +Ref<MediaStream> MediaStream::create(ScriptExecutionContext& context, const MediaStreamTrackVector& tracks) { - Vector<RefPtr<MediaStreamTrackPrivate>> audioTracks; - Vector<RefPtr<MediaStreamTrackPrivate>> videoTracks; - - for (size_t i = 0; i < tracks.size(); ++i) { - if (tracks[i]->kind() == "audio") - audioTracks.append(&tracks[i]->privateTrack()); - else - videoTracks.append(&tracks[i]->privateTrack()); - } + return adoptRef(*new MediaStream(context, tracks)); +} - return MediaStream::create(context, MediaStreamPrivate::create(audioTracks, videoTracks)); +Ref<MediaStream> MediaStream::create(ScriptExecutionContext& context, RefPtr<MediaStreamPrivate>&& streamPrivate) +{ + return adoptRef(*new MediaStream(context, WTFMove(streamPrivate))); } -PassRefPtr<MediaStream> MediaStream::create(ScriptExecutionContext& context, PassRefPtr<MediaStreamPrivate> privateStream) +MediaStream::MediaStream(ScriptExecutionContext& context, const MediaStreamTrackVector& tracks) + : ContextDestructionObserver(&context) + , m_activityEventTimer(*this, &MediaStream::activityEventTimerFired) { - return adoptRef(new MediaStream(context, privateStream)); + // This constructor preserves MediaStreamTrack instances and must be used by calls originating + // from the JavaScript MediaStream constructor. + MediaStreamTrackPrivateVector trackPrivates; + trackPrivates.reserveCapacity(tracks.size()); + + for (auto& track : tracks) { + track->addObserver(*this); + m_trackSet.add(track->id(), track); + trackPrivates.append(&track->privateTrack()); + } + + m_private = MediaStreamPrivate::create(trackPrivates); + setIsActive(m_private->active()); + m_private->addObserver(*this); + MediaStreamRegistry::shared().registerStream(*this); + document()->addAudioProducer(this); } -MediaStream::MediaStream(ScriptExecutionContext& context, PassRefPtr<MediaStreamPrivate> privateStream) +MediaStream::MediaStream(ScriptExecutionContext& context, RefPtr<MediaStreamPrivate>&& streamPrivate) : ContextDestructionObserver(&context) - , m_private(privateStream) - , m_scheduledEventTimer(this, &MediaStream::scheduledEventTimerFired) + , m_private(streamPrivate) + , m_activityEventTimer(*this, &MediaStream::activityEventTimerFired) { ASSERT(m_private); - m_private->setClient(this); - - RefPtr<MediaStreamTrack> track; - size_t numberOfAudioTracks = m_private->numberOfAudioTracks(); - m_audioTracks.reserveCapacity(numberOfAudioTracks); - for (size_t i = 0; i < numberOfAudioTracks; i++) { - track = AudioStreamTrack::create(context, *m_private->audioTracks(i)); - track->addObserver(this); - m_audioTracks.append(track.release()); + setIsActive(m_private->active()); + m_private->addObserver(*this); + MediaStreamRegistry::shared().registerStream(*this); + + for (auto& trackPrivate : m_private->tracks()) { + auto track = MediaStreamTrack::create(context, *trackPrivate); + track->addObserver(*this); + m_trackSet.add(track->id(), WTFMove(track)); } + document()->addAudioProducer(this); +} - size_t numberOfVideoTracks = m_private->numberOfVideoTracks(); - m_videoTracks.reserveCapacity(numberOfVideoTracks); - for (size_t i = 0; i < numberOfVideoTracks; i++) { - track = VideoStreamTrack::create(context, *m_private->videoTracks(i)); - track->addObserver(this); - m_videoTracks.append(track.release()); +MediaStream::~MediaStream() +{ + // Set isActive to false immediately so an callbacks triggered by shutting down, e.g. + // mediaState(), are short circuited. + m_isActive = false; + MediaStreamRegistry::shared().unregisterStream(*this); + m_private->removeObserver(*this); + for (auto& track : m_trackSet.values()) + track->removeObserver(*this); + if (Document* document = this->document()) { + document->removeAudioProducer(this); + if (m_isWaitingUntilMediaCanStart) + document->removeMediaCanStartListener(this); } } -MediaStream::~MediaStream() +RefPtr<MediaStream> MediaStream::clone() { - m_private->setClient(0); + MediaStreamTrackVector clonedTracks; + clonedTracks.reserveCapacity(m_trackSet.size()); + + for (auto& track : m_trackSet.values()) + clonedTracks.append(track->clone()); + + return MediaStream::create(*scriptExecutionContext(), clonedTracks); } -bool MediaStream::ended() const +void MediaStream::addTrack(MediaStreamTrack& track) { - return m_private->ended(); + if (!internalAddTrack(track, StreamModifier::DomAPI)) + return; + + for (auto& observer : m_observers) + observer->didAddOrRemoveTrack(); } -void MediaStream::setEnded() +void MediaStream::removeTrack(MediaStreamTrack& track) { - if (ended()) + if (!internalRemoveTrack(track.id(), StreamModifier::DomAPI)) return; - m_private->setEnded(); + + for (auto& observer : m_observers) + observer->didAddOrRemoveTrack(); } -PassRefPtr<MediaStream> MediaStream::clone() +MediaStreamTrack* MediaStream::getTrackById(String id) { - Vector<RefPtr<MediaStreamTrack>> trackSet; + auto it = m_trackSet.find(id); + if (it != m_trackSet.end()) + return it->value.get(); - cloneMediaStreamTrackVector(trackSet, getAudioTracks()); - cloneMediaStreamTrackVector(trackSet, getVideoTracks()); - return MediaStream::create(*scriptExecutionContext(), trackSet); + return nullptr; } -void MediaStream::cloneMediaStreamTrackVector(Vector<RefPtr<MediaStreamTrack>>& destination, const Vector<RefPtr<MediaStreamTrack>>& source) +MediaStreamTrackVector MediaStream::getAudioTracks() const { - for (auto it = source.begin(), end = source.end(); it != end; ++it) - destination.append((*it)->clone()); + return trackVectorForType(RealtimeMediaSource::Audio); } -void MediaStream::addTrack(PassRefPtr<MediaStreamTrack> prpTrack, ExceptionCode& ec) +MediaStreamTrackVector MediaStream::getVideoTracks() const { - if (ended()) { - ec = INVALID_STATE_ERR; - return; - } + return trackVectorForType(RealtimeMediaSource::Video); +} - if (!prpTrack) { - ec = TYPE_MISMATCH_ERR; - return; - } +MediaStreamTrackVector MediaStream::getTracks() const +{ + MediaStreamTrackVector tracks; + tracks.reserveCapacity(m_trackSet.size()); + copyValuesToVector(m_trackSet, tracks); - if (addTrack(prpTrack)) { - for (auto observer = m_observers.begin(), end = m_observers.end(); observer != end; ++observer) - (*observer)->didAddOrRemoveTrack(); - } + return tracks; } -bool MediaStream::addTrack(PassRefPtr<MediaStreamTrack> prpTrack) +void MediaStream::contextDestroyed() { - // This is a common part used by addTrack called by JavaScript - // and addRemoteTrack and only addRemoteTrack must fire addtrack event - RefPtr<MediaStreamTrack> track = prpTrack; - if (getTrackById(track->id())) - return false; - - Vector<RefPtr<MediaStreamTrack>>* tracks = trackVectorForType(track->source()->type()); + ContextDestructionObserver::contextDestroyed(); +} - tracks->append(track); - track->addObserver(this); - m_private->addTrack(&track->privateTrack()); - return true; +void MediaStream::trackDidEnd() +{ + m_private->updateActiveState(MediaStreamPrivate::NotifyClientOption::Notify); } -void MediaStream::removeTrack(PassRefPtr<MediaStreamTrack> prpTrack, ExceptionCode& ec) +void MediaStream::activeStatusChanged() { - if (ended()) { - ec = INVALID_STATE_ERR; - return; - } + // Schedule the active state change and event dispatch since this callback may be called + // synchronously from the DOM API (e.g. as a result of addTrack()). + scheduleActiveStateChange(); +} - if (!prpTrack) { - ec = TYPE_MISMATCH_ERR; +void MediaStream::didAddTrack(MediaStreamTrackPrivate& trackPrivate) +{ + ScriptExecutionContext* context = scriptExecutionContext(); + if (!context) return; - } - if (removeTrack(prpTrack)) { - for (auto observer = m_observers.begin(), end = m_observers.end(); observer != end; ++observer) - (*observer)->didAddOrRemoveTrack(); - } + if (!getTrackById(trackPrivate.id())) + internalAddTrack(MediaStreamTrack::create(*context, trackPrivate), StreamModifier::Platform); } -bool MediaStream::removeTrack(PassRefPtr<MediaStreamTrack> prpTrack) +void MediaStream::didRemoveTrack(MediaStreamTrackPrivate& trackPrivate) { - // This is a common part used by removeTrack called by JavaScript - // and removeRemoteTrack and only removeRemoteTrack must fire removetrack event - RefPtr<MediaStreamTrack> track = prpTrack; - Vector<RefPtr<MediaStreamTrack>>* tracks = trackVectorForType(track->source()->type()); + internalRemoveTrack(trackPrivate.id(), StreamModifier::Platform); +} - size_t pos = tracks->find(track); - if (pos == notFound) +bool MediaStream::internalAddTrack(Ref<MediaStreamTrack>&& trackToAdd, StreamModifier streamModifier) +{ + auto result = m_trackSet.add(trackToAdd->id(), WTFMove(trackToAdd)); + if (!result.isNewEntry) return false; - tracks->remove(pos); - m_private->removeTrack(&track->privateTrack()); - // There can be other tracks using the same source in the same MediaStream, - // like when MediaStreamTrack::clone() is called, for instance. - // Spec says that a source can be shared, so we must assure that there is no - // other track using it. - if (!haveTrackWithSource(track->source())) - m_private->removeSource(track->source()); + ASSERT(result.iterator->value); + auto& track = *result.iterator->value; + track.addObserver(*this); - track->removeObserver(this); - if (!m_audioTracks.size() && !m_videoTracks.size()) - setEnded(); + if (streamModifier == StreamModifier::DomAPI) + m_private->addTrack(&track.privateTrack(), MediaStreamPrivate::NotifyClientOption::DontNotify); + else + dispatchEvent(MediaStreamTrackEvent::create(eventNames().addtrackEvent, false, false, &track)); return true; } -bool MediaStream::haveTrackWithSource(PassRefPtr<MediaStreamSource> source) +bool MediaStream::internalRemoveTrack(const String& trackId, StreamModifier streamModifier) { - if (source->type() == MediaStreamSource::Audio) { - for (auto it = m_audioTracks.begin(), end = m_audioTracks.end(); it != end; ++it) { - if ((*it)->source() == source.get()) - return true; - } + auto track = m_trackSet.take(trackId); + if (!track) return false; - } - for (auto it = m_videoTracks.begin(), end = m_videoTracks.end(); it != end; ++it) { - if ((*it)->source() == source.get()) - return true; - } + track->removeObserver(*this); + + if (streamModifier == StreamModifier::DomAPI) + m_private->removeTrack(track->privateTrack(), MediaStreamPrivate::NotifyClientOption::DontNotify); + else + dispatchEvent(MediaStreamTrackEvent::create(eventNames().removetrackEvent, false, false, WTFMove(track))); - return false; + return true; } -MediaStreamTrack* MediaStream::getTrackById(String id) +void MediaStream::setIsActive(bool active) { - for (auto it = m_audioTracks.begin(), end = m_audioTracks.end(); it != end; ++it) { - if ((*it)->id() == id) - return (*it).get(); - } - - for (auto it = m_videoTracks.begin(), end = m_videoTracks.end(); it != end; ++it) { - if ((*it)->id() == id) - return (*it).get(); - } + if (m_isActive == active) + return; - return nullptr; + m_isActive = active; + statusDidChange(); } -void MediaStream::trackDidEnd() +void MediaStream::mediaCanStart(Document& document) { - for (auto it = m_audioTracks.begin(), end = m_audioTracks.end(); it != end; ++it) { - if (!(*it)->ended()) - return; - } - for (auto it = m_videoTracks.begin(), end = m_videoTracks.end(); it != end; ++it) { - if (!(*it)->ended()) - return; + ASSERT_UNUSED(document, &document == this->document()); + ASSERT(m_isWaitingUntilMediaCanStart); + if (m_isWaitingUntilMediaCanStart) { + m_isWaitingUntilMediaCanStart = false; + startProducingData(); } - - setEnded(); } -void MediaStream::streamDidEnd() +void MediaStream::startProducingData() { - if (ended()) + Document* document = this->document(); + if (!document || !document->page()) return; - scheduleDispatchEvent(Event::create(eventNames().endedEvent, false, false)); -} + // If we can't start a load right away, start it later. + if (!document->page()->canStartMedia()) { + LOG(Media, "MediaStream::startProducingData(%p) - not allowed to start in background, waiting", this); + if (m_isWaitingUntilMediaCanStart) + return; -void MediaStream::contextDestroyed() -{ - ContextDestructionObserver::contextDestroyed(); + m_isWaitingUntilMediaCanStart = true; + document->addMediaCanStartListener(this); + return; + } + + m_private->startProducingData(); } -void MediaStream::addRemoteSource(MediaStreamSource* source) +void MediaStream::stopProducingData() { - ASSERT(source); - addRemoteTrack(MediaStreamTrackPrivate::create(source).get()); + m_private->stopProducingData(); } -void MediaStream::removeRemoteSource(MediaStreamSource* source) +void MediaStream::pageMutedStateDidChange() { - ASSERT(source); - if (ended()) + if (!m_isActive) return; - Vector<RefPtr<MediaStreamTrack>>* tracks = trackVectorForType(source->type()); - - for (int i = tracks->size() - 1; i >= 0; --i) { - if ((*tracks)[i]->source() != source) - continue; + Document* document = this->document(); + if (!document) + return; - RefPtr<MediaStreamTrack> track = (*tracks)[i]; - track->removeObserver(this); - tracks->remove(i); - m_private->removeTrack(&track->privateTrack()); - scheduleDispatchEvent(MediaStreamTrackEvent::create(eventNames().removetrackEvent, false, false, track.release())); - } + bool pageMuted = document->page()->isMediaCaptureMuted(); + if (m_externallyMuted == pageMuted) + return; - m_private->removeSource(source); + m_externallyMuted = pageMuted; + if (pageMuted) + stopProducingData(); + else + startProducingData(); } -void MediaStream::addRemoteTrack(MediaStreamTrackPrivate* privateTrack) +MediaProducer::MediaStateFlags MediaStream::mediaState() const { - ASSERT(privateTrack); - if (ended()) - return; + MediaStateFlags state = IsNotPlaying; - RefPtr<MediaStreamTrack> track; - switch (privateTrack->type()) { - case MediaStreamSource::Audio: - track = AudioStreamTrack::create(*scriptExecutionContext(), *privateTrack); - break; - case MediaStreamSource::Video: - track = VideoStreamTrack::create(*scriptExecutionContext(), *privateTrack); - break; - case MediaStreamSource::None: - ASSERT_NOT_REACHED(); - break; + if (!m_isActive) + return state; + + if (m_private->hasAudio()) { + state |= HasAudioOrVideo; + if (m_private->hasLocalAudioSource() && m_private->isProducingData()) + state |= HasActiveAudioCaptureDevice; } - if (!track) - return; + if (m_private->hasVideo()) { + state |= HasAudioOrVideo; + if (m_private->hasLocalVideoSource() && m_private->isProducingData()) + state |= HasActiveVideoCaptureDevice; + } - if (addTrack(track)) - scheduleDispatchEvent(MediaStreamTrackEvent::create(eventNames().addtrackEvent, false, false, track)); + return state; } -void MediaStream::removeRemoteTrack(MediaStreamTrackPrivate* privateTrack) +void MediaStream::statusDidChange() { - ASSERT(privateTrack); - if (ended()) - return; + if (Document* document = this->document()) { + if (m_isActive) + document->setHasActiveMediaStreamTrack(); + document->updateIsPlayingMedia(); + } +} - RefPtr<MediaStreamTrack> track = getTrackById(privateTrack->id()); - if (removeTrack(track)) - scheduleDispatchEvent(MediaStreamTrackEvent::create(eventNames().removetrackEvent, false, false, track.release())); +void MediaStream::characteristicsChanged() +{ + bool muted = m_private->muted(); + if (m_isMuted != muted) { + m_isMuted = muted; + statusDidChange(); + } } -void MediaStream::scheduleDispatchEvent(PassRefPtr<Event> event) +void MediaStream::scheduleActiveStateChange() { - m_scheduledEvents.append(event); + bool active = false; + for (auto& track : m_trackSet.values()) { + if (!track->ended()) { + active = true; + break; + } + } + + if (m_isActive == active) + return; + + setIsActive(active); + + const AtomicString& eventName = m_isActive ? eventNames().inactiveEvent : eventNames().activeEvent; + m_scheduledActivityEvents.append(Event::create(eventName, false, false)); - if (!m_scheduledEventTimer.isActive()) - m_scheduledEventTimer.startOneShot(0); + if (!m_activityEventTimer.isActive()) + m_activityEventTimer.startOneShot(0); } -void MediaStream::scheduledEventTimerFired(Timer<MediaStream>*) +void MediaStream::activityEventTimerFired() { - Vector<RefPtr<Event>> events; - events.swap(m_scheduledEvents); + Vector<Ref<Event>> events; + events.swap(m_scheduledActivityEvents); - for (auto it = events.begin(), end = events.end(); it != end; ++it) - dispatchEvent((*it).release()); - - events.clear(); + for (auto& event : events) + dispatchEvent(event); } URLRegistry& MediaStream::registry() const { - return MediaStreamRegistry::registry(); + return MediaStreamRegistry::shared(); } -Vector<RefPtr<MediaStreamTrack>>* MediaStream::trackVectorForType(MediaStreamSource::Type type) +MediaStreamTrackVector MediaStream::trackVectorForType(RealtimeMediaSource::Type filterType) const { - switch (type) { - case MediaStreamSource::Audio: - return &m_audioTracks; - case MediaStreamSource::Video: - return &m_videoTracks; - case MediaStreamSource::None: - ASSERT_NOT_REACHED(); + MediaStreamTrackVector tracks; + for (auto& track : m_trackSet.values()) { + if (track->source().type() == filterType) + tracks.append(track); } - return nullptr; + + return tracks; } void MediaStream::addObserver(MediaStream::Observer* observer) @@ -395,6 +405,11 @@ void MediaStream::removeObserver(MediaStream::Observer* observer) m_observers.remove(pos); } +Document* MediaStream::document() const +{ + return downcast<Document>(scriptExecutionContext()); +} + } // namespace WebCore #endif // ENABLE(MEDIA_STREAM) diff --git a/Source/WebCore/Modules/mediastream/MediaStream.h b/Source/WebCore/Modules/mediastream/MediaStream.h index 1791c2490..816d706a3 100644 --- a/Source/WebCore/Modules/mediastream/MediaStream.h +++ b/Source/WebCore/Modules/mediastream/MediaStream.h @@ -1,7 +1,7 @@ /* * Copyright (C) 2011 Google Inc. All rights reserved. - * Copyright (C) 2011 Ericsson AB. All rights reserved. - * Copyright (C) 2013 Apple Inc. All rights reserved. + * Copyright (C) 2011, 2015 Ericsson AB. All rights reserved. + * Copyright (C) 2013-2015 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 @@ -25,116 +25,140 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef MediaStream_h -#define MediaStream_h +#pragma once #if ENABLE(MEDIA_STREAM) #include "ContextDestructionObserver.h" #include "EventTarget.h" #include "ExceptionBase.h" +#include "MediaCanStartListener.h" +#include "MediaProducer.h" #include "MediaStreamPrivate.h" #include "MediaStreamTrack.h" #include "ScriptWrappable.h" #include "Timer.h" #include "URLRegistry.h" +#include <wtf/HashMap.h> #include <wtf/RefCounted.h> #include <wtf/RefPtr.h> namespace WebCore { -class MediaStreamCenter; - -class MediaStream final : public RefCounted<MediaStream>, public URLRegistrable, public ScriptWrappable, public MediaStreamPrivateClient, public EventTargetWithInlineData, public ContextDestructionObserver { +class Document; + +class MediaStream final + : public URLRegistrable + , public EventTargetWithInlineData + , public ContextDestructionObserver + , public MediaStreamTrack::Observer + , public MediaStreamPrivate::Observer + , private MediaProducer + , private MediaCanStartListener + , public RefCounted<MediaStream> { public: class Observer { public: + virtual ~Observer() { } virtual void didAddOrRemoveTrack() = 0; }; - static PassRefPtr<MediaStream> create(ScriptExecutionContext&); - static PassRefPtr<MediaStream> create(ScriptExecutionContext&, PassRefPtr<MediaStream>); - static PassRefPtr<MediaStream> create(ScriptExecutionContext&, const Vector<RefPtr<MediaStreamTrack>>&); - static PassRefPtr<MediaStream> create(ScriptExecutionContext&, PassRefPtr<MediaStreamPrivate>); + static Ref<MediaStream> create(ScriptExecutionContext&); + static Ref<MediaStream> create(ScriptExecutionContext&, MediaStream&); + static Ref<MediaStream> create(ScriptExecutionContext&, const MediaStreamTrackVector&); + static Ref<MediaStream> create(ScriptExecutionContext&, RefPtr<MediaStreamPrivate>&&); virtual ~MediaStream(); String id() const { return m_private->id(); } - void addTrack(PassRefPtr<MediaStreamTrack>, ExceptionCode&); - void removeTrack(PassRefPtr<MediaStreamTrack>, ExceptionCode&); + void addTrack(MediaStreamTrack&); + void removeTrack(MediaStreamTrack&); MediaStreamTrack* getTrackById(String); - Vector<RefPtr<MediaStreamTrack>> getAudioTracks() const { return m_audioTracks; } - Vector<RefPtr<MediaStreamTrack>> getVideoTracks() const { return m_videoTracks; } + MediaStreamTrackVector getAudioTracks() const; + MediaStreamTrackVector getVideoTracks() const; + MediaStreamTrackVector getTracks() const; - bool ended() const; - void setEnded(); - PassRefPtr<MediaStream> clone(); + RefPtr<MediaStream> clone(); - DEFINE_ATTRIBUTE_EVENT_LISTENER(ended); - DEFINE_ATTRIBUTE_EVENT_LISTENER(addtrack); - DEFINE_ATTRIBUTE_EVENT_LISTENER(removetrack); + bool active() const { return m_isActive; } + bool muted() const { return m_isMuted; } MediaStreamPrivate* privateStream() const { return m_private.get(); } + void startProducingData(); + void stopProducingData(); + // EventTarget - virtual EventTargetInterface eventTargetInterface() const final { return MediaStreamEventTargetInterfaceType; } - virtual ScriptExecutionContext* scriptExecutionContext() const final { return ContextDestructionObserver::scriptExecutionContext(); } + EventTargetInterface eventTargetInterface() const final { return MediaStreamEventTargetInterfaceType; } + ScriptExecutionContext* scriptExecutionContext() const final { return ContextDestructionObserver::scriptExecutionContext(); } using RefCounted<MediaStream>::ref; using RefCounted<MediaStream>::deref; // URLRegistrable - virtual URLRegistry& registry() const override; + URLRegistry& registry() const override; void addObserver(Observer*); void removeObserver(Observer*); protected: - MediaStream(ScriptExecutionContext&, PassRefPtr<MediaStreamPrivate>); + MediaStream(ScriptExecutionContext&, const MediaStreamTrackVector&); + MediaStream(ScriptExecutionContext&, RefPtr<MediaStreamPrivate>&&); // ContextDestructionObserver - virtual void contextDestroyed() override final; + void contextDestroyed() final; private: + enum class StreamModifier { DomAPI, Platform }; + // EventTarget - virtual void refEventTarget() override final { ref(); } - virtual void derefEventTarget() override final { deref(); } + void refEventTarget() final { ref(); } + void derefEventTarget() final { deref(); } + + // MediaStreamTrack::Observer + void trackDidEnd() final; + + // MediaStreamPrivate::Observer + void activeStatusChanged() final; + void didAddTrack(MediaStreamTrackPrivate&) final; + void didRemoveTrack(MediaStreamTrackPrivate&) final; + void characteristicsChanged() final; - // MediaStreamPrivateClient - virtual void trackDidEnd() override final; - virtual void streamDidEnd() override final; - virtual void addRemoteSource(MediaStreamSource*) override final; - virtual void removeRemoteSource(MediaStreamSource*) override final; - virtual void addRemoteTrack(MediaStreamTrackPrivate*) override final; - virtual void removeRemoteTrack(MediaStreamTrackPrivate*) override final; + // MediaProducer + void pageMutedStateDidChange() final; + MediaProducer::MediaStateFlags mediaState() const final; - bool removeTrack(PassRefPtr<MediaStreamTrack>); - bool addTrack(PassRefPtr<MediaStreamTrack>); + // MediaCanStartListener + void mediaCanStart(Document&) final; - bool haveTrackWithSource(PassRefPtr<MediaStreamSource>); + bool internalAddTrack(Ref<MediaStreamTrack>&&, StreamModifier); + bool internalRemoveTrack(const String&, StreamModifier); - void scheduleDispatchEvent(PassRefPtr<Event>); - void scheduledEventTimerFired(Timer<MediaStream>*); + void scheduleActiveStateChange(); + void activityEventTimerFired(); + void setIsActive(bool); + void statusDidChange(); - void cloneMediaStreamTrackVector(Vector<RefPtr<MediaStreamTrack>>&, const Vector<RefPtr<MediaStreamTrack>>&); + Document* document() const; - Vector<RefPtr<MediaStreamTrack>>* trackVectorForType(MediaStreamSource::Type); + MediaStreamTrackVector trackVectorForType(RealtimeMediaSource::Type) const; RefPtr<MediaStreamPrivate> m_private; - Vector<RefPtr<MediaStreamTrack>> m_audioTracks; - Vector<RefPtr<MediaStreamTrack>> m_videoTracks; - Timer<MediaStream> m_scheduledEventTimer; - Vector<RefPtr<Event>> m_scheduledEvents; + HashMap<String, RefPtr<MediaStreamTrack>> m_trackSet; + + Timer m_activityEventTimer; + Vector<Ref<Event>> m_scheduledActivityEvents; Vector<Observer*> m_observers; -}; -typedef Vector<RefPtr<MediaStream>> MediaStreamVector; + bool m_isActive { false }; + bool m_isMuted { true }; + bool m_externallyMuted { false }; + bool m_isWaitingUntilMediaCanStart { false }; +}; } // namespace WebCore #endif // ENABLE(MEDIA_STREAM) - -#endif // MediaStream_h diff --git a/Source/WebCore/Modules/mediastream/MediaStream.idl b/Source/WebCore/Modules/mediastream/MediaStream.idl index 8dd4c9419..7fa377b89 100644 --- a/Source/WebCore/Modules/mediastream/MediaStream.idl +++ b/Source/WebCore/Modules/mediastream/MediaStream.idl @@ -24,37 +24,31 @@ [ Conditional=MEDIA_STREAM, - EventTarget, Constructor, Constructor(MediaStream stream), - Constructor(MediaStreamTrack[] tracks), + Constructor(sequence<MediaStreamTrack> tracks), ConstructorCallWith=ScriptExecutionContext, - InterfaceName=webkitMediaStream, -] interface MediaStream { + PrivateIdentifier, + PublicIdentifier +] interface MediaStream : EventTarget { readonly attribute DOMString id; sequence<MediaStreamTrack> getAudioTracks(); sequence<MediaStreamTrack> getVideoTracks(); - - [RaisesException] void addTrack(MediaStreamTrack track); - [RaisesException] void removeTrack(MediaStreamTrack track); + [PrivateIdentifier, PublicIdentifier] sequence<MediaStreamTrack> getTracks(); MediaStreamTrack getTrackById(DOMString trackId); - MediaStream clone(); - readonly attribute boolean ended; + void addTrack(MediaStreamTrack track); + void removeTrack(MediaStreamTrack track); + + MediaStream clone(); - attribute EventListener onended; - attribute EventListener onaddtrack; - attribute EventListener onremovetrack; + readonly attribute boolean active; - // EventTarget interface - void addEventListener(DOMString type, - EventListener listener, - optional boolean useCapture); - void removeEventListener(DOMString type, - EventListener listener, - optional boolean useCapture); - [RaisesException] boolean dispatchEvent(Event event); + attribute EventHandler onactive; + attribute EventHandler oninactive; + attribute EventHandler onaddtrack; + attribute EventHandler onremovetrack; }; diff --git a/Source/WebCore/Modules/mediastream/MediaStreamCapabilities.cpp b/Source/WebCore/Modules/mediastream/MediaStreamCapabilities.cpp deleted file mode 100644 index ad7cead3f..000000000 --- a/Source/WebCore/Modules/mediastream/MediaStreamCapabilities.cpp +++ /dev/null @@ -1,142 +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. - */ - -#include "config.h" - -#if ENABLE(MEDIA_STREAM) - -#include "MediaStreamCapabilities.h" - -#include "AllAudioCapabilities.h" -#include "AllVideoCapabilities.h" -#include "CapabilityRange.h" -#include "MediaSourceStates.h" -#include "MediaStreamSourceCapabilities.h" - -namespace WebCore { - -RefPtr<MediaStreamCapabilities> MediaStreamCapabilities::create(PassRefPtr<MediaStreamSourceCapabilities> capabilities) -{ - if (capabilities->hasVideoSource()) - return AllVideoCapabilities::create(capabilities); - - return AllAudioCapabilities::create(capabilities); -} - -MediaStreamCapabilities::MediaStreamCapabilities(PassRefPtr<MediaStreamSourceCapabilities> capabilities) - : m_SourceCapabilities(capabilities) -{ -} - -Vector<String> MediaStreamCapabilities::sourceType() const -{ - ASSERT(m_SourceCapabilities->hasVideoSource()); - - size_t count = m_SourceCapabilities->sourceTypes().size(); - if (!count) - return Vector<String>(); - - const Vector<MediaStreamSourceStates::SourceType>& sourceTypes = m_SourceCapabilities->sourceTypes(); - Vector<String> capabilities; - capabilities.reserveCapacity(count); - - for (size_t i = 0; i < count; ++i) - capabilities.append(MediaStreamSourceStates::sourceType(sourceTypes[i])); - - return capabilities; -} - -Vector<String> MediaStreamCapabilities::sourceId() const -{ - size_t count = m_SourceCapabilities->sourceId().size(); - if (!count) - return Vector<String>(); - - const Vector<AtomicString>& sourceIds = m_SourceCapabilities->sourceId(); - Vector<String> capabilities; - capabilities.reserveCapacity(count); - - for (size_t i = 0; i < count; ++i) - capabilities.append(sourceIds[i]); - - return capabilities; -} - -Vector<String> MediaStreamCapabilities::facingMode() const -{ - ASSERT(m_SourceCapabilities->hasVideoSource()); - - size_t count = m_SourceCapabilities->facingModes().size(); - if (!count) - return Vector<String>(); - - const Vector<MediaStreamSourceStates::VideoFacingMode>& facingModes = m_SourceCapabilities->facingModes(); - Vector<String> capabilities; - capabilities.reserveCapacity(count); - - for (size_t i = 0; i < count; ++i) - capabilities.append(MediaStreamSourceStates::facingMode(facingModes[i])); - - return capabilities; -} - -RefPtr<CapabilityRange> MediaStreamCapabilities::width() const -{ - ASSERT(m_SourceCapabilities->hasVideoSource()); - - return CapabilityRange::create(m_SourceCapabilities->width()); -} - -RefPtr<CapabilityRange> MediaStreamCapabilities::height() const -{ - ASSERT(m_SourceCapabilities->hasVideoSource()); - - return CapabilityRange::create(m_SourceCapabilities->height()); -} - -RefPtr<CapabilityRange> MediaStreamCapabilities::frameRate() const -{ - ASSERT(m_SourceCapabilities->hasVideoSource()); - - return CapabilityRange::create(m_SourceCapabilities->frameRate()); -} - -RefPtr<CapabilityRange> MediaStreamCapabilities::aspectRatio() const -{ - ASSERT(m_SourceCapabilities->hasVideoSource()); - - return CapabilityRange::create(m_SourceCapabilities->aspectRatio()); -} - -RefPtr<CapabilityRange> MediaStreamCapabilities::volume() const -{ - ASSERT(!m_SourceCapabilities->hasVideoSource()); - - return CapabilityRange::create(m_SourceCapabilities->volume()); -} - -} // namespace WebCore - -#endif diff --git a/Source/WebCore/Modules/mediastream/MediaStreamCapabilities.h b/Source/WebCore/Modules/mediastream/MediaStreamCapabilities.h deleted file mode 100644 index 5ad3412ea..000000000 --- a/Source/WebCore/Modules/mediastream/MediaStreamCapabilities.h +++ /dev/null @@ -1,69 +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 MediaStreamCapabilities_h -#define MediaStreamCapabilities_h - -#if ENABLE(MEDIA_STREAM) - -#include "MediaStreamCapabilities.h" -#include "MediaStreamSourceCapabilities.h" -#include "ScriptWrappable.h" -#include <wtf/RefCounted.h> -#include <wtf/Vector.h> -#include <wtf/text/WTFString.h> - -namespace WebCore { - -class CapabilityRange; -class MediaStreamSourceCapabilities; - -class MediaStreamCapabilities : public RefCounted<MediaStreamCapabilities>, public ScriptWrappable { -public: - static RefPtr<MediaStreamCapabilities> create(PassRefPtr<MediaStreamSourceCapabilities>); - virtual ~MediaStreamCapabilities() { } - - virtual Vector<String> sourceType() const; - virtual Vector<String> sourceId() const; - virtual RefPtr<CapabilityRange> width() const; - virtual RefPtr<CapabilityRange> height() const; - virtual RefPtr<CapabilityRange> frameRate() const; - virtual RefPtr<CapabilityRange> aspectRatio() const; - virtual Vector<String> facingMode() const; - virtual RefPtr<CapabilityRange> volume() const; - - bool hasVideoSource() { return m_SourceCapabilities->hasVideoSource(); } - -protected: - explicit MediaStreamCapabilities(PassRefPtr<MediaStreamSourceCapabilities>); - - RefPtr<MediaStreamSourceCapabilities> m_SourceCapabilities; -}; - -} // namespace WebCore - -#endif // MediaStreamCapabilities_h - -#endif diff --git a/Source/WebCore/Modules/mediastream/MediaStreamCapabilities.idl b/Source/WebCore/Modules/mediastream/MediaStreamCapabilities.idl deleted file mode 100644 index dd71ccbf6..000000000 --- a/Source/WebCore/Modules/mediastream/MediaStreamCapabilities.idl +++ /dev/null @@ -1,33 +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. - */ - -[ - Conditional=MEDIA_STREAM, - NoInterfaceObject, - SkipVTableValidation, - CustomToJSObject, -] interface MediaStreamCapabilities { -}; - diff --git a/Source/WebCore/Modules/mediastream/MediaStreamEvent.cpp b/Source/WebCore/Modules/mediastream/MediaStreamEvent.cpp index 92f6bb14f..09584b2ba 100644 --- a/Source/WebCore/Modules/mediastream/MediaStreamEvent.cpp +++ b/Source/WebCore/Modules/mediastream/MediaStreamEvent.cpp @@ -25,45 +25,30 @@ #include "config.h" #include "MediaStreamEvent.h" -#if ENABLE(MEDIA_STREAM) +#if ENABLE(WEB_RTC) -#include "EventNames.h" #include "MediaStream.h" namespace WebCore { -MediaStreamEventInit::MediaStreamEventInit() - : stream(0) +Ref<MediaStreamEvent> MediaStreamEvent::create(const AtomicString& type, bool canBubble, bool cancelable, RefPtr<MediaStream>&& stream) { + return adoptRef(*new MediaStreamEvent(type, canBubble, cancelable, WTFMove(stream))); } -PassRefPtr<MediaStreamEvent> MediaStreamEvent::create() +Ref<MediaStreamEvent> MediaStreamEvent::create(const AtomicString& type, const Init& initializer, IsTrusted isTrusted) { - return adoptRef(new MediaStreamEvent); + return adoptRef(*new MediaStreamEvent(type, initializer, isTrusted)); } -PassRefPtr<MediaStreamEvent> MediaStreamEvent::create(const AtomicString& type, bool canBubble, bool cancelable, PassRefPtr<MediaStream> stream) -{ - return adoptRef(new MediaStreamEvent(type, canBubble, cancelable, stream)); -} - -PassRefPtr<MediaStreamEvent> MediaStreamEvent::create(const AtomicString& type, const MediaStreamEventInit& initializer) -{ - return adoptRef(new MediaStreamEvent(type, initializer)); -} - -MediaStreamEvent::MediaStreamEvent() -{ -} - -MediaStreamEvent::MediaStreamEvent(const AtomicString& type, bool canBubble, bool cancelable, PassRefPtr<MediaStream> stream) +MediaStreamEvent::MediaStreamEvent(const AtomicString& type, bool canBubble, bool cancelable, RefPtr<MediaStream>&& stream) : Event(type, canBubble, cancelable) - , m_stream(stream) + , m_stream(WTFMove(stream)) { } -MediaStreamEvent::MediaStreamEvent(const AtomicString& type, const MediaStreamEventInit& initializer) - : Event(type, initializer) +MediaStreamEvent::MediaStreamEvent(const AtomicString& type, const Init& initializer, IsTrusted isTrusted) + : Event(type, initializer, isTrusted) , m_stream(initializer.stream) { } @@ -84,5 +69,5 @@ EventInterface MediaStreamEvent::eventInterface() const } // namespace WebCore -#endif // ENABLE(MEDIA_STREAM) +#endif // ENABLE(WEB_RTC) diff --git a/Source/WebCore/Modules/mediastream/MediaStreamEvent.h b/Source/WebCore/Modules/mediastream/MediaStreamEvent.h index bad394e0a..f67c52952 100644 --- a/Source/WebCore/Modules/mediastream/MediaStreamEvent.h +++ b/Source/WebCore/Modules/mediastream/MediaStreamEvent.h @@ -22,10 +22,9 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef MediaStreamEvent_h -#define MediaStreamEvent_h +#pragma once -#if ENABLE(MEDIA_STREAM) +#if ENABLE(WEB_RTC) #include "Event.h" #include "MediaStream.h" @@ -33,34 +32,28 @@ namespace WebCore { -struct MediaStreamEventInit : public EventInit { - MediaStreamEventInit(); - - RefPtr<MediaStream> stream; -}; - class MediaStreamEvent : public Event { public: virtual ~MediaStreamEvent(); - static PassRefPtr<MediaStreamEvent> create(); - static PassRefPtr<MediaStreamEvent> create(const AtomicString& type, bool canBubble, bool cancelable, PassRefPtr<MediaStream>); - static PassRefPtr<MediaStreamEvent> create(const AtomicString& type, const MediaStreamEventInit& initializer); + static Ref<MediaStreamEvent> create(const AtomicString& type, bool canBubble, bool cancelable, RefPtr<MediaStream>&&); + + struct Init : EventInit { + RefPtr<MediaStream> stream; + }; + static Ref<MediaStreamEvent> create(const AtomicString& type, const Init& initializer, IsTrusted = IsTrusted::No); MediaStream* stream() const; virtual EventInterface eventInterface() const; private: - MediaStreamEvent(); - MediaStreamEvent(const AtomicString& type, bool canBubble, bool cancelable, PassRefPtr<MediaStream>); - MediaStreamEvent(const AtomicString& type, const MediaStreamEventInit&); + MediaStreamEvent(const AtomicString& type, bool canBubble, bool cancelable, RefPtr<MediaStream>&&); + MediaStreamEvent(const AtomicString& type, const Init&, IsTrusted); RefPtr<MediaStream> m_stream; }; } // namespace WebCore -#endif // ENABLE(MEDIA_STREAM) - -#endif // MediaStreamEvent_h +#endif // ENABLE(WEB_RTC) diff --git a/Source/WebCore/Modules/mediastream/MediaStreamEvent.idl b/Source/WebCore/Modules/mediastream/MediaStreamEvent.idl index b44729ca3..e4ffceb15 100644 --- a/Source/WebCore/Modules/mediastream/MediaStreamEvent.idl +++ b/Source/WebCore/Modules/mediastream/MediaStreamEvent.idl @@ -23,9 +23,13 @@ */ [ - Conditional=MEDIA_STREAM, - ConstructorTemplate=Event + Conditional=WEB_RTC, + Constructor(DOMString type, optional MediaStreamEventInit eventInitDict), + EnabledAtRuntime=MediaStream, ] interface MediaStreamEvent : Event { - [InitializedByEventConstructor] readonly attribute MediaStream stream; + readonly attribute MediaStream? stream; }; +dictionary MediaStreamEventInit : EventInit { + MediaStream? stream = null; +}; diff --git a/Source/WebCore/Modules/mediastream/MediaStreamRegistry.cpp b/Source/WebCore/Modules/mediastream/MediaStreamRegistry.cpp index 9a2eeb18e..843498657 100644 --- a/Source/WebCore/Modules/mediastream/MediaStreamRegistry.cpp +++ b/Source/WebCore/Modules/mediastream/MediaStreamRegistry.cpp @@ -28,25 +28,26 @@ #if ENABLE(MEDIA_STREAM) -#include "URL.h" #include "MediaStream.h" +#include "URL.h" #include <wtf/MainThread.h> +#include <wtf/NeverDestroyed.h> namespace WebCore { -MediaStreamRegistry& MediaStreamRegistry::registry() +MediaStreamRegistry& MediaStreamRegistry::shared() { // Since WebWorkers cannot obtain MediaSource objects, we should be on the main thread. ASSERT(isMainThread()); - DEFINE_STATIC_LOCAL(MediaStreamRegistry, instance, ()); + static NeverDestroyed<MediaStreamRegistry> instance; return instance; } -void MediaStreamRegistry::registerURL(SecurityOrigin*, const URL& url, URLRegistrable* stream) +void MediaStreamRegistry::registerURL(SecurityOrigin*, const URL& url, URLRegistrable& stream) { - ASSERT(&stream->registry() == this); + ASSERT(&stream.registry() == this); ASSERT(isMainThread()); - m_mediaStreams.set(url.string(), static_cast<MediaStream*>(stream)); + m_mediaStreams.set(url.string(), static_cast<MediaStream*>(&stream)); } void MediaStreamRegistry::unregisterURL(const URL& url) @@ -61,6 +62,45 @@ URLRegistrable* MediaStreamRegistry::lookup(const String& url) const return m_mediaStreams.get(url); } +MediaStreamRegistry::MediaStreamRegistry() +{ +} + +MediaStream* MediaStreamRegistry::lookUp(const URL& url) const +{ + return static_cast<MediaStream*>(lookup(url.string())); +} + +static Vector<MediaStream*>& mediaStreams() +{ + static NeverDestroyed<Vector<MediaStream*>> streams; + return streams; +} + +void MediaStreamRegistry::registerStream(MediaStream& stream) +{ + mediaStreams().append(&stream); +} + +void MediaStreamRegistry::unregisterStream(MediaStream& stream) +{ + Vector<MediaStream*>& allStreams = mediaStreams(); + size_t pos = allStreams.find(&stream); + if (pos != notFound) + allStreams.remove(pos); +} + +MediaStream* MediaStreamRegistry::lookUp(const MediaStreamPrivate& privateStream) const +{ + Vector<MediaStream*>& allStreams = mediaStreams(); + for (auto& stream : allStreams) { + if (stream->privateStream() == &privateStream) + return stream; + } + + return nullptr; +} + } // namespace WebCore #endif // ENABLE(MEDIA_STREAM) diff --git a/Source/WebCore/Modules/mediastream/MediaStreamRegistry.h b/Source/WebCore/Modules/mediastream/MediaStreamRegistry.h index cfea9f59e..7e23a1e2e 100644 --- a/Source/WebCore/Modules/mediastream/MediaStreamRegistry.h +++ b/Source/WebCore/Modules/mediastream/MediaStreamRegistry.h @@ -23,38 +23,44 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef MediaStreamRegistry_h -#define MediaStreamRegistry_h +#pragma once #if ENABLE(MEDIA_STREAM) #include "URLRegistry.h" #include <wtf/HashMap.h> -#include <wtf/PassRefPtr.h> #include <wtf/text/StringHash.h> namespace WebCore { -class URL; class MediaStream; +class MediaStreamPrivate; +class URL; class MediaStreamRegistry final : public URLRegistry { public: + friend class NeverDestroyed<MediaStreamRegistry>; + // Returns a single instance of MediaStreamRegistry. - static MediaStreamRegistry& registry(); + static MediaStreamRegistry& shared(); // Registers a blob URL referring to the specified stream data. - virtual void registerURL(SecurityOrigin*, const URL&, URLRegistrable*) override; - virtual void unregisterURL(const URL&) override; + void registerURL(SecurityOrigin*, const URL&, URLRegistrable&) override; + void unregisterURL(const URL&) override; - virtual URLRegistrable* lookup(const String&) const override; + URLRegistrable* lookup(const String&) const override; + + void registerStream(MediaStream&); + void unregisterStream(MediaStream&); + + MediaStream* lookUp(const URL&) const; + MediaStream* lookUp(const MediaStreamPrivate&) const; private: + MediaStreamRegistry(); HashMap<String, RefPtr<MediaStream>> m_mediaStreams; }; } // namespace WebCore #endif // ENABLE(MEDIA_STREAM) - -#endif // MediaStreamRegistry_h diff --git a/Source/WebCore/Modules/mediastream/MediaStreamTrack.cpp b/Source/WebCore/Modules/mediastream/MediaStreamTrack.cpp index 476dec103..96cc6298b 100644 --- a/Source/WebCore/Modules/mediastream/MediaStreamTrack.cpp +++ b/Source/WebCore/Modules/mediastream/MediaStreamTrack.cpp @@ -1,7 +1,7 @@ /* * Copyright (C) 2011 Google Inc. All rights reserved. - * Copyright (C) 2011 Ericsson AB. All rights reserved. - * Copyright (C) 2013 Apple Inc. All rights reserved. + * Copyright (C) 2011, 2015 Ericsson AB. All rights reserved. + * Copyright (C) 2013-2016 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 @@ -30,292 +30,345 @@ #if ENABLE(MEDIA_STREAM) -#include "AllAudioCapabilities.h" -#include "AllVideoCapabilities.h" -#include "AudioStreamTrack.h" -#include "Dictionary.h" #include "Event.h" -#include "ExceptionCode.h" -#include "ExceptionCodePlaceholder.h" +#include "EventNames.h" +#include "JSOverconstrainedError.h" #include "MediaConstraintsImpl.h" -#include "MediaSourceStates.h" #include "MediaStream.h" -#include "MediaStreamCenter.h" #include "MediaStreamPrivate.h" -#include "MediaStreamTrackSourcesCallback.h" -#include "MediaStreamTrackSourcesRequest.h" -#include "MediaTrackConstraints.h" #include "NotImplemented.h" -#include "VideoStreamTrack.h" -#include <wtf/Functional.h> +#include "OverconstrainedError.h" +#include "ScriptExecutionContext.h" #include <wtf/NeverDestroyed.h> namespace WebCore { -MediaStreamTrack::MediaStreamTrack(ScriptExecutionContext& context, MediaStreamTrackPrivate& privateTrack, const Dictionary* constraints) - : RefCounted() - , ActiveDOMObject(&context) - , m_privateTrack(privateTrack) - , m_eventDispatchScheduled(false) - , m_stoppingTrack(false) +Ref<MediaStreamTrack> MediaStreamTrack::create(ScriptExecutionContext& context, Ref<MediaStreamTrackPrivate>&& privateTrack) { - suspendIfNeeded(); - - m_privateTrack->setClient(this); - - if (constraints) - applyConstraints(*constraints); + return adoptRef(*new MediaStreamTrack(context, WTFMove(privateTrack))); } -MediaStreamTrack::MediaStreamTrack(MediaStreamTrack& other) - : RefCounted() - , ActiveDOMObject(other.scriptExecutionContext()) - , m_privateTrack(*other.privateTrack().clone()) - , m_eventDispatchScheduled(false) - , m_stoppingTrack(false) +MediaStreamTrack::MediaStreamTrack(ScriptExecutionContext& context, Ref<MediaStreamTrackPrivate>&& privateTrack) + : ActiveDOMObject(&context) + , m_private(WTFMove(privateTrack)) + , m_weakPtrFactory(this) { suspendIfNeeded(); - m_privateTrack->setClient(this); + m_private->addObserver(*this); } MediaStreamTrack::~MediaStreamTrack() { - m_privateTrack->setClient(nullptr); + m_private->removeObserver(*this); } -void MediaStreamTrack::setSource(PassRefPtr<MediaStreamSource> newSource) +const AtomicString& MediaStreamTrack::kind() const { - m_privateTrack->setSource(newSource); + static NeverDestroyed<AtomicString> audioKind("audio", AtomicString::ConstructFromLiteral); + static NeverDestroyed<AtomicString> videoKind("video", AtomicString::ConstructFromLiteral); + + if (m_private->type() == RealtimeMediaSource::Audio) + return audioKind; + return videoKind; } const String& MediaStreamTrack::id() const { - return m_privateTrack->id(); + return m_private->id(); } const String& MediaStreamTrack::label() const { - return m_privateTrack->label(); + return m_private->label(); } bool MediaStreamTrack::enabled() const { - return m_privateTrack->enabled(); + return m_private->enabled(); } void MediaStreamTrack::setEnabled(bool enabled) { - m_privateTrack->setEnabled(enabled); -} - -bool MediaStreamTrack::stopped() const -{ - return m_privateTrack->stopped(); + m_private->setEnabled(enabled); } bool MediaStreamTrack::muted() const { - return m_privateTrack->muted(); + return m_private->muted(); } bool MediaStreamTrack::readonly() const { - return m_privateTrack->readonly(); + return m_private->readonly(); } bool MediaStreamTrack::remote() const { - return m_privateTrack->remote(); + return m_private->remote(); } -const AtomicString& MediaStreamTrack::readyState() const +auto MediaStreamTrack::readyState() const -> State { - static NeverDestroyed<AtomicString> ended("ended", AtomicString::ConstructFromLiteral); - static NeverDestroyed<AtomicString> live("live", AtomicString::ConstructFromLiteral); - static NeverDestroyed<AtomicString> newState("new", AtomicString::ConstructFromLiteral); - - switch (m_privateTrack->readyState()) { - case MediaStreamSource::Live: - return live; - case MediaStreamSource::New: - return newState; - case MediaStreamSource::Ended: - return ended; - } - - ASSERT_NOT_REACHED(); - return emptyAtom; + return ended() ? State::Ended : State::Live; } -void MediaStreamTrack::getSources(ScriptExecutionContext* context, PassRefPtr<MediaStreamTrackSourcesCallback> callback, ExceptionCode& ec) +bool MediaStreamTrack::ended() const { - RefPtr<MediaStreamTrackSourcesRequest> request = MediaStreamTrackSourcesRequest::create(context, callback); - if (!MediaStreamCenter::shared().getMediaStreamTrackSources(request.release())) - ec = NOT_SUPPORTED_ERR; + return m_ended || m_private->ended(); } -RefPtr<MediaTrackConstraints> MediaStreamTrack::constraints() const +Ref<MediaStreamTrack> MediaStreamTrack::clone() { - // FIXME: https://bugs.webkit.org/show_bug.cgi?id=122428 - notImplemented(); - return 0; + return MediaStreamTrack::create(*scriptExecutionContext(), m_private->clone()); } -RefPtr<MediaSourceStates> MediaStreamTrack::states() const +void MediaStreamTrack::stopProducingData() { - return MediaSourceStates::create(m_privateTrack->states()); -} + // NOTE: this method is called when the "stop" method is called from JS, using + // the "ImplementedAs" IDL attribute. This is done because ActiveDOMObject requires + // a "stop" method. -RefPtr<MediaStreamCapabilities> MediaStreamTrack::capabilities() const -{ - // The source may be shared by multiple tracks, so its states is not necessarily - // in sync with the track state. A track that is new or has ended always has a source - // type of "none". - RefPtr<MediaStreamSourceCapabilities> sourceCapabilities = m_privateTrack->capabilities(); - MediaStreamSource::ReadyState readyState = m_privateTrack->readyState(); - if (readyState == MediaStreamSource::New || readyState == MediaStreamSource::Ended) - sourceCapabilities->setSourceType(MediaStreamSourceStates::None); - - return MediaStreamCapabilities::create(sourceCapabilities.release()); + // http://w3c.github.io/mediacapture-main/#widl-MediaStreamTrack-stop-void + // 4.3.3.2 Methods + // When a MediaStreamTrack object's stop() method is invoked, the User Agent must run following steps: + // 1. Let track be the current MediaStreamTrack object. + // 2. If track is sourced by a non-local source, then abort these steps. + if (remote() || ended()) + return; + + // 3. Notify track's source that track is ended so that the source may be stopped, unless other + // MediaStreamTrack objects depend on it. + // 4. Set track's readyState attribute to ended. + + // Set m_ended to true before telling the private to stop so we do not fire an 'ended' event. + m_ended = true; + + m_private->endTrack(); +} + +MediaStreamTrack::TrackSettings MediaStreamTrack::getSettings() const +{ + auto& settings = m_private->settings(); + TrackSettings result; + if (settings.supportsWidth()) + result.width = settings.width(); + if (settings.supportsHeight()) + result.height = settings.height(); + if (settings.supportsAspectRatio() && settings.aspectRatio()) // FIXME: Why the check for zero here? + result.aspectRatio = settings.aspectRatio(); + if (settings.supportsFrameRate()) + result.frameRate = settings.frameRate(); + if (settings.supportsFacingMode()) + result.facingMode = RealtimeMediaSourceSettings::facingMode(settings.facingMode()); + if (settings.supportsVolume()) + result.volume = settings.volume(); + if (settings.supportsSampleRate()) + result.sampleRate = settings.sampleRate(); + if (settings.supportsSampleSize()) + result.sampleSize = settings.sampleSize(); + if (settings.supportsEchoCancellation()) + result.echoCancellation = settings.echoCancellation(); + if (settings.supportsDeviceId()) + result.deviceId = settings.deviceId(); + if (settings.supportsGroupId()) + result.groupId = settings.groupId(); + return result; +} + +static DoubleRange capabilityDoubleRange(const CapabilityValueOrRange& value) +{ + DoubleRange range; + switch (value.type()) { + case CapabilityValueOrRange::Double: + range.min = value.value().asDouble; + range.max = range.min; + break; + case CapabilityValueOrRange::DoubleRange: + range.min = value.rangeMin().asDouble; + range.max = value.rangeMax().asDouble; + break; + case CapabilityValueOrRange::Undefined: + case CapabilityValueOrRange::ULong: + case CapabilityValueOrRange::ULongRange: + ASSERT_NOT_REACHED(); + } + return range; +} + +static LongRange capabilityIntRange(const CapabilityValueOrRange& value) +{ + LongRange range; + switch (value.type()) { + case CapabilityValueOrRange::ULong: + range.min = value.value().asInt; + range.max = range.min; + break; + case CapabilityValueOrRange::ULongRange: + range.min = value.rangeMin().asInt; + range.max = value.rangeMax().asInt; + break; + case CapabilityValueOrRange::Undefined: + case CapabilityValueOrRange::Double: + case CapabilityValueOrRange::DoubleRange: + ASSERT_NOT_REACHED(); + } + return range; } -void MediaStreamTrack::applyConstraints(const Dictionary& constraints) +static Vector<String> capabilityStringVector(const Vector<RealtimeMediaSourceSettings::VideoFacingMode>& modes) { - m_constraints->initialize(constraints); - m_privateTrack->applyConstraints(m_constraints); + Vector<String> result; + result.reserveCapacity(modes.size()); + for (auto& mode : modes) + result.uncheckedAppend(RealtimeMediaSourceSettings::facingMode(mode)); + return result; } -void MediaStreamTrack::applyConstraints(PassRefPtr<MediaConstraints>) +static Vector<bool> capabilityBooleanVector(RealtimeMediaSourceCapabilities::EchoCancellation cancellation) { - // FIXME: apply the new constraints to the track - // https://bugs.webkit.org/show_bug.cgi?id=122428 + Vector<bool> result; + result.reserveCapacity(2); + result.uncheckedAppend(true); + result.uncheckedAppend(cancellation == RealtimeMediaSourceCapabilities::EchoCancellation::ReadWrite); + return result; } -RefPtr<MediaStreamTrack> MediaStreamTrack::clone() +MediaStreamTrack::TrackCapabilities MediaStreamTrack::getCapabilities() const { - if (m_privateTrack->type() == MediaStreamSource::Audio) - return AudioStreamTrack::create(*this); - - return VideoStreamTrack::create(*this); + auto capabilities = m_private->capabilities(); + TrackCapabilities result; + if (capabilities->supportsWidth()) + result.width = capabilityIntRange(capabilities->width()); + if (capabilities->supportsHeight()) + result.height = capabilityIntRange(capabilities->height()); + if (capabilities->supportsAspectRatio()) + result.aspectRatio = capabilityDoubleRange(capabilities->aspectRatio()); + if (capabilities->supportsFrameRate()) + result.frameRate = capabilityDoubleRange(capabilities->frameRate()); + if (capabilities->supportsFacingMode()) + result.facingMode = capabilityStringVector(capabilities->facingMode()); + if (capabilities->supportsVolume()) + result.volume = capabilityDoubleRange(capabilities->volume()); + if (capabilities->supportsSampleRate()) + result.sampleRate = capabilityIntRange(capabilities->sampleRate()); + if (capabilities->supportsSampleSize()) + result.sampleSize = capabilityIntRange(capabilities->sampleSize()); + if (capabilities->supportsEchoCancellation()) + result.echoCancellation = capabilityBooleanVector(capabilities->echoCancellation()); + if (capabilities->supportsDeviceId()) + result.deviceId = capabilities->deviceId(); + if (capabilities->supportsGroupId()) + result.groupId = capabilities->groupId(); + return result; } -void MediaStreamTrack::stopProducingData() +static Ref<MediaConstraintsImpl> createMediaConstraintsImpl(const std::optional<MediaTrackConstraints>& constraints) { - // NOTE: this method is called when the "stop" method is called from JS, using - // the "ImplementedAs" IDL attribute. This is done because ActiveDOMObject requires - // a "stop" method. - - // The stop method should "Permanently stop the generation of data for track's source", but it - // should not post an 'ended' event. - m_stoppingTrack = true; - m_privateTrack->stop(MediaStreamTrackPrivate::StopTrackAndStopSource); - m_stoppingTrack = false; + if (!constraints) + return MediaConstraintsImpl::create({ }, { }, true); + return createMediaConstraintsImpl(constraints.value()); } -bool MediaStreamTrack::ended() const +void MediaStreamTrack::applyConstraints(const std::optional<MediaTrackConstraints>& constraints, DOMPromise<void>&& promise) { - return m_privateTrack->ended(); + m_promise = WTFMove(promise); + + auto weakThis = createWeakPtr(); + auto failureHandler = [weakThis] (const String& failedConstraint, const String& message) { + if (!weakThis || !weakThis->m_promise) + return; + weakThis->m_promise->rejectType<IDLInterface<OverconstrainedError>>(OverconstrainedError::create(failedConstraint, message).get()); + }; + auto successHandler = [weakThis, constraints] () { + if (!weakThis || !weakThis->m_promise) + return; + weakThis->m_promise->resolve(); + weakThis->m_constraints = constraints.value_or(MediaTrackConstraints { }); + }; + m_private->applyConstraints(createMediaConstraintsImpl(constraints), successHandler, failureHandler); } -void MediaStreamTrack::addObserver(MediaStreamTrack::Observer* observer) +void MediaStreamTrack::addObserver(Observer& observer) { - m_observers.append(observer); + m_observers.append(&observer); } -void MediaStreamTrack::removeObserver(MediaStreamTrack::Observer* observer) +void MediaStreamTrack::removeObserver(Observer& observer) { - size_t pos = m_observers.find(observer); - if (pos != notFound) - m_observers.remove(pos); + m_observers.removeFirst(&observer); } -void MediaStreamTrack::trackReadyStateChanged() +void MediaStreamTrack::trackEnded(MediaStreamTrackPrivate&) { - if (stopped()) + // http://w3c.github.io/mediacapture-main/#life-cycle + // When a MediaStreamTrack track ends for any reason other than the stop() method being invoked, the User Agent must queue a task that runs the following steps: + // 1. If the track's readyState attribute has the value ended already, then abort these steps. + if (m_ended) return; - MediaStreamSource::ReadyState readyState = m_privateTrack->readyState(); - if (readyState == MediaStreamSource::Live) - scheduleEventDispatch(Event::create(eventNames().startedEvent, false, false)); - else if (readyState == MediaStreamSource::Ended && !m_stoppingTrack) - scheduleEventDispatch(Event::create(eventNames().endedEvent, false, false)); + // 2. Set track's readyState attribute to ended. + m_ended = true; + + if (scriptExecutionContext()->activeDOMObjectsAreSuspended() || scriptExecutionContext()->activeDOMObjectsAreStopped()) + return; + + // 3. Notify track's source that track is ended so that the source may be stopped, unless other MediaStreamTrack objects depend on it. + // 4. Fire a simple event named ended at the object. + dispatchEvent(Event::create(eventNames().endedEvent, false, false)); + + for (auto& observer : m_observers) + observer->trackDidEnd(); configureTrackRendering(); } -void MediaStreamTrack::trackMutedChanged() +void MediaStreamTrack::trackMutedChanged(MediaStreamTrackPrivate&) { - if (stopped()) + if (scriptExecutionContext()->activeDOMObjectsAreSuspended() || scriptExecutionContext()->activeDOMObjectsAreStopped()) return; - if (muted()) - scheduleEventDispatch(Event::create(eventNames().muteEvent, false, false)); - else - scheduleEventDispatch(Event::create(eventNames().unmuteEvent, false, false)); + AtomicString eventType = muted() ? eventNames().muteEvent : eventNames().unmuteEvent; + dispatchEvent(Event::create(eventType, false, false)); configureTrackRendering(); } -void MediaStreamTrack::trackEnabledChanged() +void MediaStreamTrack::trackSettingsChanged(MediaStreamTrackPrivate&) { - if (stopped()) - return; + configureTrackRendering(); +} - setEnabled(m_privateTrack->enabled()); +void MediaStreamTrack::trackEnabledChanged(MediaStreamTrackPrivate&) +{ configureTrackRendering(); } void MediaStreamTrack::configureTrackRendering() { - if (stopped()) - return; - // 4.3.1 // ... media from the source only flows when a MediaStreamTrack object is both unmuted and enabled } -void MediaStreamTrack::trackDidEnd() +void MediaStreamTrack::stop() { - m_privateTrack->setReadyState(MediaStreamSource::Ended); - - for (Vector<Observer*>::iterator i = m_observers.begin(); i != m_observers.end(); ++i) - (*i)->trackDidEnd(); + stopProducingData(); } -void MediaStreamTrack::stop() +const char* MediaStreamTrack::activeDOMObjectName() const { - m_privateTrack->stop(MediaStreamTrackPrivate::StopTrackOnly); + return "MediaStreamTrack"; } -void MediaStreamTrack::scheduleEventDispatch(PassRefPtr<Event> event) +bool MediaStreamTrack::canSuspendForDocumentSuspension() const { - { - MutexLocker locker(m_mutex); - m_scheduledEvents.append(event); - if (m_eventDispatchScheduled) - return; - m_eventDispatchScheduled = true; - } - - callOnMainThread(bind(&MediaStreamTrack::dispatchQueuedEvents, this)); + // FIXME: We should try and do better here. + return false; } -void MediaStreamTrack::dispatchQueuedEvents() +AudioSourceProvider* MediaStreamTrack::audioSourceProvider() { - Vector<RefPtr<Event>> events; - { - MutexLocker locker(m_mutex); - m_eventDispatchScheduled = false; - events.swap(m_scheduledEvents); - } - if (!scriptExecutionContext()) - return; - - for (auto it = events.begin(); it != events.end(); ++it) - dispatchEvent((*it).release()); - - events.clear(); + return m_private->audioSourceProvider(); } } // namespace WebCore diff --git a/Source/WebCore/Modules/mediastream/MediaStreamTrack.h b/Source/WebCore/Modules/mediastream/MediaStreamTrack.h index 64ea32d3f..118728758 100644 --- a/Source/WebCore/Modules/mediastream/MediaStreamTrack.h +++ b/Source/WebCore/Modules/mediastream/MediaStreamTrack.h @@ -1,7 +1,7 @@ /* * Copyright (C) 2011 Google Inc. All rights reserved. - * Copyright (C) 2011 Ericsson AB. All rights reserved. - * Copyright (C) 2013 Apple Inc. All rights reserved. + * Copyright (C) 2011, 2015 Ericsson AB. All rights reserved. + * Copyright (C) 2013-2016 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 @@ -25,31 +25,25 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef MediaStreamTrack_h -#define MediaStreamTrack_h +#pragma once #if ENABLE(MEDIA_STREAM) #include "ActiveDOMObject.h" +#include "DoubleRange.h" #include "EventTarget.h" -#include "MediaStreamSource.h" +#include "JSDOMPromise.h" +#include "LongRange.h" #include "MediaStreamTrackPrivate.h" -#include "ScriptWrappable.h" -#include <wtf/RefCounted.h> -#include <wtf/RefPtr.h> -#include <wtf/Vector.h> -#include <wtf/text/WTFString.h> +#include "MediaTrackConstraints.h" namespace WebCore { -class Dictionary; -class MediaConstraintsImpl; -class MediaSourceStates; -class MediaStreamTrackSourcesCallback; -class MediaStreamCapabilities; -class MediaTrackConstraints; +class AudioSourceProvider; -class MediaStreamTrack : public RefCounted<MediaStreamTrack>, public ScriptWrappable, public ActiveDOMObject, public EventTargetWithInlineData, public MediaStreamTrackPrivateClient { +struct MediaTrackConstraints; + +class MediaStreamTrack final : public RefCounted<MediaStreamTrack>, public ActiveDOMObject, public EventTargetWithInlineData, private MediaStreamTrackPrivate::Observer { public: class Observer { public: @@ -57,9 +51,10 @@ public: virtual void trackDidEnd() = 0; }; + static Ref<MediaStreamTrack> create(ScriptExecutionContext&, Ref<MediaStreamTrackPrivate>&&); virtual ~MediaStreamTrack(); - virtual const AtomicString& kind() const = 0; + const AtomicString& kind() const; const String& id() const; const String& label() const; @@ -69,82 +64,96 @@ public: bool muted() const; bool readonly() const; bool remote() const; - bool stopped() const; - - const AtomicString& readyState() const; - static void getSources(ScriptExecutionContext*, PassRefPtr<MediaStreamTrackSourcesCallback>, ExceptionCode&); + enum class State { New, Live, Ended }; + State readyState() const; - RefPtr<MediaTrackConstraints> constraints() const; - RefPtr<MediaSourceStates> states() const; - RefPtr<MediaStreamCapabilities> capabilities() const; - void applyConstraints(const Dictionary&); - void applyConstraints(PassRefPtr<MediaConstraints>); + bool ended() const; - RefPtr<MediaStreamTrack> clone(); + Ref<MediaStreamTrack> clone(); void stopProducingData(); - DEFINE_ATTRIBUTE_EVENT_LISTENER(mute); - DEFINE_ATTRIBUTE_EVENT_LISTENER(unmute); - DEFINE_ATTRIBUTE_EVENT_LISTENER(started); - DEFINE_ATTRIBUTE_EVENT_LISTENER(ended); - DEFINE_ATTRIBUTE_EVENT_LISTENER(overconstrained); - - MediaStreamSource* source() const { return m_privateTrack->source(); } - MediaStreamTrackPrivate& privateTrack() { return m_privateTrack.get(); } - - bool ended() const; + struct TrackSettings { + std::optional<int> width; + std::optional<int> height; + std::optional<double> aspectRatio; + std::optional<double> frameRate; + String facingMode; + std::optional<double> volume; + std::optional<int> sampleRate; + std::optional<int> sampleSize; + std::optional<bool> echoCancellation; + String deviceId; + String groupId; + }; + TrackSettings getSettings() const; + + struct TrackCapabilities { + std::optional<LongRange> width; + std::optional<LongRange> height; + std::optional<DoubleRange> aspectRatio; + std::optional<DoubleRange> frameRate; + std::optional<Vector<String>> facingMode; + std::optional<DoubleRange> volume; + std::optional<LongRange> sampleRate; + std::optional<LongRange> sampleSize; + std::optional<Vector<bool>> echoCancellation; + String deviceId; + String groupId; + }; + TrackCapabilities getCapabilities() const; - void addObserver(Observer*); - void removeObserver(Observer*); + const MediaTrackConstraints& getConstraints() const { return m_constraints; } + void applyConstraints(const std::optional<MediaTrackConstraints>&, DOMPromise<void>&&); - // EventTarget - virtual EventTargetInterface eventTargetInterface() const override final { return MediaStreamTrackEventTargetInterfaceType; } - virtual ScriptExecutionContext* scriptExecutionContext() const override final { return ActiveDOMObject::scriptExecutionContext(); } + RealtimeMediaSource& source() { return m_private->source(); } + MediaStreamTrackPrivate& privateTrack() { return m_private.get(); } - using RefCounted<MediaStreamTrack>::ref; - using RefCounted<MediaStreamTrack>::deref; + AudioSourceProvider* audioSourceProvider(); -protected: - explicit MediaStreamTrack(MediaStreamTrack&); - MediaStreamTrack(ScriptExecutionContext&, MediaStreamTrackPrivate&, const Dictionary*); + void addObserver(Observer&); + void removeObserver(Observer&); - void setSource(PassRefPtr<MediaStreamSource>); + using RefCounted::ref; + using RefCounted::deref; private: + MediaStreamTrack(ScriptExecutionContext&, Ref<MediaStreamTrackPrivate>&&); + explicit MediaStreamTrack(MediaStreamTrack&); void configureTrackRendering(); - void trackDidEnd(); - void scheduleEventDispatch(PassRefPtr<Event>); - void dispatchQueuedEvents(); - // ActiveDOMObject - virtual void stop() override final; + // ActiveDOMObject API. + void stop() final; + const char* activeDOMObjectName() const final; + bool canSuspendForDocumentSuspension() const final; // EventTarget - virtual void refEventTarget() override final { ref(); } - virtual void derefEventTarget() override final { deref(); } + void refEventTarget() final { ref(); } + void derefEventTarget() final { deref(); } + EventTargetInterface eventTargetInterface() const final { return MediaStreamTrackEventTargetInterfaceType; } + ScriptExecutionContext* scriptExecutionContext() const final { return ActiveDOMObject::scriptExecutionContext(); } - // MediaStreamTrackPrivateClient - void trackReadyStateChanged(); - void trackMutedChanged(); - void trackEnabledChanged(); + // MediaStreamTrackPrivate::Observer + void trackEnded(MediaStreamTrackPrivate&) override; + void trackMutedChanged(MediaStreamTrackPrivate&) override; + void trackSettingsChanged(MediaStreamTrackPrivate&) override; + void trackEnabledChanged(MediaStreamTrackPrivate&) override; - Vector<RefPtr<Event>> m_scheduledEvents; - - RefPtr<MediaConstraintsImpl> m_constraints; - Mutex m_mutex; + WeakPtr<MediaStreamTrack> createWeakPtr() { return m_weakPtrFactory.createWeakPtr(); } Vector<Observer*> m_observers; + Ref<MediaStreamTrackPrivate> m_private; - Ref<MediaStreamTrackPrivate> m_privateTrack; - bool m_eventDispatchScheduled; + MediaTrackConstraints m_constraints; + std::optional<DOMPromise<void>> m_promise; + WeakPtrFactory<MediaStreamTrack> m_weakPtrFactory; - bool m_stoppingTrack; + bool m_ended { false }; }; +typedef Vector<RefPtr<MediaStreamTrack>> MediaStreamTrackVector; + } // namespace WebCore #endif // ENABLE(MEDIA_STREAM) - -#endif // MediaStreamTrack_h diff --git a/Source/WebCore/Modules/mediastream/MediaStreamTrack.idl b/Source/WebCore/Modules/mediastream/MediaStreamTrack.idl index 68d5fb91c..ac033019a 100644 --- a/Source/WebCore/Modules/mediastream/MediaStreamTrack.idl +++ b/Source/WebCore/Modules/mediastream/MediaStreamTrack.idl @@ -1,6 +1,6 @@ /* * Copyright (C) 2011 Google Inc. All rights reserved. - * Copyright (C) 2013 Apple Inc. All rights reserved. + * Copyright (C) 2013-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 @@ -26,45 +26,69 @@ enum MediaStreamTrackState { "new", "live", "ended" }; [ - Conditional=MEDIA_STREAM, - EventTarget, ActiveDOMObject, + Conditional=MEDIA_STREAM, + PrivateIdentifier, + PublicIdentifier, SkipVTableValidation, -] interface MediaStreamTrack { +] interface MediaStreamTrack : EventTarget { readonly attribute DOMString kind; readonly attribute DOMString id; readonly attribute DOMString label; - attribute boolean enabled; + attribute boolean enabled; readonly attribute boolean muted; - attribute EventListener onmute; - attribute EventListener onunmute; + attribute EventHandler onmute; + attribute EventHandler onunmute; readonly attribute boolean _readonly; readonly attribute boolean remote; readonly attribute MediaStreamTrackState readyState; - attribute EventListener onstarted; - attribute EventListener onended; - - [CallWith=ScriptExecutionContext, RaisesException] static void getSources(MediaStreamTrackSourcesCallback callback); - - MediaTrackConstraints constraints(); + attribute EventHandler onended; - MediaSourceStates states(); - - MediaStreamCapabilities capabilities(); // returns either AllVideoCapabilities or AllAudioCapabilities - - void applyConstraints(Dictionary constraints); - - attribute EventListener onoverconstrained; MediaStreamTrack clone(); [ImplementedAs=stopProducingData] void stop(); - // EventTarget interface - void addEventListener(DOMString type, - EventListener listener, - optional boolean useCapture); - void removeEventListener(DOMString type, - EventListener listener, - optional boolean useCapture); - [RaisesException] boolean dispatchEvent(Event event); + MediaTrackConstraints getConstraints(); + MediaTrackSettings getSettings(); + MediaTrackCapabilities getCapabilities(); + Promise<void> applyConstraints(optional MediaTrackConstraints constraints); + + attribute EventHandler onoverconstrained; }; +[ + Conditional=MEDIA_STREAM, + JSGenerateToJSObject, +] dictionary MediaTrackCapabilities { + LongRange width; + LongRange height; + DoubleRange aspectRatio; + DoubleRange frameRate; + sequence<DOMString> facingMode; + DoubleRange volume; + LongRange sampleRate; + LongRange sampleSize; + sequence<boolean> echoCancellation; + // FIXME: add latency + // FIXME: add channelCount + DOMString deviceId; + DOMString groupId; +}; + +[ + Conditional=MEDIA_STREAM, + JSGenerateToJSObject, +] dictionary MediaTrackSettings { + long width; + long height; + double aspectRatio; + double frameRate; + DOMString facingMode; + double volume; + long sampleRate; + long sampleSize; + boolean echoCancellation; + // FIXME: add latency + // FIXME: add channelCount + DOMString deviceId; + DOMString groupId; +}; diff --git a/Source/WebCore/Modules/mediastream/MediaStreamTrackEvent.cpp b/Source/WebCore/Modules/mediastream/MediaStreamTrackEvent.cpp index 6d884fc5a..de46e0bc2 100644 --- a/Source/WebCore/Modules/mediastream/MediaStreamTrackEvent.cpp +++ b/Source/WebCore/Modules/mediastream/MediaStreamTrackEvent.cpp @@ -27,43 +27,28 @@ #include "MediaStreamTrackEvent.h" -#include "EventNames.h" #include "MediaStreamTrack.h" namespace WebCore { -MediaStreamTrackEventInit::MediaStreamTrackEventInit() - : track(0) +Ref<MediaStreamTrackEvent> MediaStreamTrackEvent::create(const AtomicString& type, bool canBubble, bool cancelable, RefPtr<MediaStreamTrack>&& track) { + return adoptRef(*new MediaStreamTrackEvent(type, canBubble, cancelable, WTFMove(track))); } -PassRefPtr<MediaStreamTrackEvent> MediaStreamTrackEvent::create() +Ref<MediaStreamTrackEvent> MediaStreamTrackEvent::create(const AtomicString& type, const Init& initializer, IsTrusted isTrusted) { - return adoptRef(new MediaStreamTrackEvent); + return adoptRef(*new MediaStreamTrackEvent(type, initializer, isTrusted)); } -PassRefPtr<MediaStreamTrackEvent> MediaStreamTrackEvent::create(const AtomicString& type, bool canBubble, bool cancelable, PassRefPtr<MediaStreamTrack> track) -{ - return adoptRef(new MediaStreamTrackEvent(type, canBubble, cancelable, track)); -} - -PassRefPtr<MediaStreamTrackEvent> MediaStreamTrackEvent::create(const AtomicString& type, const MediaStreamTrackEventInit& initializer) -{ - return adoptRef(new MediaStreamTrackEvent(type, initializer)); -} - -MediaStreamTrackEvent::MediaStreamTrackEvent() -{ -} - -MediaStreamTrackEvent::MediaStreamTrackEvent(const AtomicString& type, bool canBubble, bool cancelable, PassRefPtr<MediaStreamTrack> track) +MediaStreamTrackEvent::MediaStreamTrackEvent(const AtomicString& type, bool canBubble, bool cancelable, RefPtr<MediaStreamTrack>&& track) : Event(type, canBubble, cancelable) - , m_track(track) + , m_track(WTFMove(track)) { } -MediaStreamTrackEvent::MediaStreamTrackEvent(const AtomicString& type, const MediaStreamTrackEventInit& initializer) - : Event(type, initializer) +MediaStreamTrackEvent::MediaStreamTrackEvent(const AtomicString& type, const Init& initializer, IsTrusted isTrusted) + : Event(type, initializer, isTrusted) , m_track(initializer.track) { } diff --git a/Source/WebCore/Modules/mediastream/MediaStreamTrackEvent.h b/Source/WebCore/Modules/mediastream/MediaStreamTrackEvent.h index b0818abb4..4101f49f8 100644 --- a/Source/WebCore/Modules/mediastream/MediaStreamTrackEvent.h +++ b/Source/WebCore/Modules/mediastream/MediaStreamTrackEvent.h @@ -22,8 +22,7 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef MediaStreamTrackEvent_h -#define MediaStreamTrackEvent_h +#pragma once #if ENABLE(MEDIA_STREAM) @@ -34,29 +33,25 @@ namespace WebCore { class MediaStreamTrack; -struct MediaStreamTrackEventInit : public EventInit { - MediaStreamTrackEventInit(); - - RefPtr<MediaStreamTrack> track; -}; - class MediaStreamTrackEvent : public Event { public: virtual ~MediaStreamTrackEvent(); - static PassRefPtr<MediaStreamTrackEvent> create(); - static PassRefPtr<MediaStreamTrackEvent> create(const AtomicString& type, bool canBubble, bool cancelable, PassRefPtr<MediaStreamTrack>); - static PassRefPtr<MediaStreamTrackEvent> create(const AtomicString& type, const MediaStreamTrackEventInit& initializer); + static Ref<MediaStreamTrackEvent> create(const AtomicString& type, bool canBubble, bool cancelable, RefPtr<MediaStreamTrack>&&); + + struct Init : EventInit { + RefPtr<MediaStreamTrack> track; + }; + static Ref<MediaStreamTrackEvent> create(const AtomicString& type, const Init&, IsTrusted = IsTrusted::No); MediaStreamTrack* track() const; // Event - virtual EventInterface eventInterface() const override; + EventInterface eventInterface() const override; private: - MediaStreamTrackEvent(); - MediaStreamTrackEvent(const AtomicString& type, bool canBubble, bool cancelable, PassRefPtr<MediaStreamTrack>); - MediaStreamTrackEvent(const AtomicString& type, const MediaStreamTrackEventInit&); + MediaStreamTrackEvent(const AtomicString& type, bool canBubble, bool cancelable, RefPtr<MediaStreamTrack>&&); + MediaStreamTrackEvent(const AtomicString& type, const Init&, IsTrusted); RefPtr<MediaStreamTrack> m_track; }; @@ -64,5 +59,3 @@ private: } // namespace WebCore #endif // ENABLE(MEDIA_STREAM) - -#endif // MediaStreamTrackEvent_h diff --git a/Source/WebCore/Modules/mediastream/MediaStreamTrackEvent.idl b/Source/WebCore/Modules/mediastream/MediaStreamTrackEvent.idl index 10d5f333f..26d9cca68 100644 --- a/Source/WebCore/Modules/mediastream/MediaStreamTrackEvent.idl +++ b/Source/WebCore/Modules/mediastream/MediaStreamTrackEvent.idl @@ -24,8 +24,11 @@ [ Conditional=MEDIA_STREAM, - ConstructorTemplate=Event + Constructor(DOMString type, MediaStreamTrackEventInit eventInitDict), ] interface MediaStreamTrackEvent : Event { - [InitializedByEventConstructor] readonly attribute MediaStreamTrack track; + readonly attribute MediaStreamTrack track; }; +dictionary MediaStreamTrackEventInit : EventInit { + required MediaStreamTrack track; +}; diff --git a/Source/WebCore/Modules/mediastream/MediaStreamTrackSourcesCallback.idl b/Source/WebCore/Modules/mediastream/MediaStreamTrackSourcesCallback.idl deleted file mode 100644 index 4c0593fcf..000000000 --- a/Source/WebCore/Modules/mediastream/MediaStreamTrackSourcesCallback.idl +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (C) 2013 Google Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY GOOGLE 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 GOOGLE 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. - */ - -[ - Conditional=MEDIA_STREAM, - NoInterfaceObject, -] callback interface MediaStreamTrackSourcesCallback { - boolean handleEvent(sequence<SourceInfo> sources); -}; - diff --git a/Source/WebCore/Modules/mediastream/MediaStreamTrackSourcesRequest.cpp b/Source/WebCore/Modules/mediastream/MediaStreamTrackSourcesRequest.cpp deleted file mode 100644 index 18b929a9e..000000000 --- a/Source/WebCore/Modules/mediastream/MediaStreamTrackSourcesRequest.cpp +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (C) 2013 Google Inc. All rights reserved. - * 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 GOOGLE 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 GOOGLE 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. - */ - -#include "config.h" -#include "MediaStreamTrackSourcesRequest.h" - -#if ENABLE(MEDIA_STREAM) - -#include "MediaStreamTrackSourcesCallback.h" -#include "ScriptExecutionContext.h" -#include "SecurityOrigin.h" -#include "SourceInfo.h" -#include <wtf/Functional.h> -#include <wtf/MainThread.h> - -namespace WebCore { - -PassRefPtr<MediaStreamTrackSourcesRequest> MediaStreamTrackSourcesRequest::create(ScriptExecutionContext* context, PassRefPtr<MediaStreamTrackSourcesCallback> callback) -{ - return adoptRef(new MediaStreamTrackSourcesRequest(context, callback)); -} - -MediaStreamTrackSourcesRequest::MediaStreamTrackSourcesRequest(ScriptExecutionContext* context, PassRefPtr<MediaStreamTrackSourcesCallback> callback) - : m_callback(callback) -{ - m_origin = context->securityOrigin()->toString(); -} - -void MediaStreamTrackSourcesRequest::didCompleteRequest(const Vector<RefPtr<TrackSourceInfo>>& requestSourceInfos) -{ - ASSERT(m_callback); - - for (size_t i = 0; i < requestSourceInfos.size(); ++i) - m_sourceInfos.append(SourceInfo::create(requestSourceInfos[i])); - - callOnMainThread(bind(&MediaStreamTrackSourcesRequest::callCompletionHandler, this)); -} - -void MediaStreamTrackSourcesRequest::callCompletionHandler() -{ - ASSERT(m_callback); - - m_callback->handleEvent(m_sourceInfos); - m_callback = nullptr; -} - -} // namespace WebCore - -#endif diff --git a/Source/WebCore/Modules/mediastream/MediaStreamTrackSourcesRequest.h b/Source/WebCore/Modules/mediastream/MediaStreamTrackSourcesRequest.h deleted file mode 100644 index 96599b436..000000000 --- a/Source/WebCore/Modules/mediastream/MediaStreamTrackSourcesRequest.h +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (C) 2013 Google Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY GOOGLE 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 GOOGLE 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 MediaStreamTrackSourcesRequest_h -#define MediaStreamTrackSourcesRequest_h - -#if ENABLE(MEDIA_STREAM) - -#include "MediaStreamTrackSourcesRequestClient.h" -#include "SourceInfo.h" -#include "Timer.h" -#include <wtf/RefPtr.h> -#include <wtf/text/WTFString.h> - -namespace WebCore { - -class MediaStreamTrackSourcesCallback; -class ScriptExecutionContext; - -class MediaStreamTrackSourcesRequest : public MediaStreamTrackSourcesRequestClient { -public: - static PassRefPtr<MediaStreamTrackSourcesRequest> create(ScriptExecutionContext*, PassRefPtr<MediaStreamTrackSourcesCallback>); - virtual ~MediaStreamTrackSourcesRequest() { } - -private: - MediaStreamTrackSourcesRequest(ScriptExecutionContext*, PassRefPtr<MediaStreamTrackSourcesCallback>); - - // MediaStreamTrackSourcesRequestClient - virtual const String& requestOrigin() const override { return m_origin; } - virtual void didCompleteRequest(const Vector<RefPtr<TrackSourceInfo>>&) override; - - void callCompletionHandler(); - - String m_origin; - RefPtr<MediaStreamTrackSourcesCallback> m_callback; - Vector<RefPtr<SourceInfo>> m_sourceInfos; -}; - -} // namespace WebCore - -#endif // MediaStreamTrackSourcesRequest_h - -#endif diff --git a/Source/WebCore/Modules/mediastream/MediaTrackConstraintSet.cpp b/Source/WebCore/Modules/mediastream/MediaTrackConstraintSet.cpp deleted file mode 100644 index a5aec90a5..000000000 --- a/Source/WebCore/Modules/mediastream/MediaTrackConstraintSet.cpp +++ /dev/null @@ -1,53 +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, 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. - * - */ - -#include "config.h" - -#if ENABLE(MEDIA_STREAM) - -#include "MediaTrackConstraintSet.h" - -using namespace JSC; - -namespace WebCore { - -RefPtr<MediaTrackConstraintSet> MediaTrackConstraintSet::create(const Dictionary& constraints) -{ - return adoptRef(new MediaTrackConstraintSet(constraints)); -} - -MediaTrackConstraintSet::MediaTrackConstraintSet(const Dictionary& constraints) - : m_constraints(constraints) -{ -} - -MediaTrackConstraintSet::~MediaTrackConstraintSet() -{ -} - -} // namespace WebCore - -#endif diff --git a/Source/WebCore/Modules/mediastream/MediaTrackConstraintSet.h b/Source/WebCore/Modules/mediastream/MediaTrackConstraintSet.h deleted file mode 100644 index b6978ae30..000000000 --- a/Source/WebCore/Modules/mediastream/MediaTrackConstraintSet.h +++ /dev/null @@ -1,56 +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, 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 MediaTrackConstraintSet_h -#define MediaTrackConstraintSet_h - -#if ENABLE(MEDIA_STREAM) - -#include "Dictionary.h" -#include "ScriptWrappable.h" -#include <wtf/RefCounted.h> - -namespace WebCore { - -class MediaTrackConstraintSet : public RefCounted<MediaTrackConstraintSet>, public ScriptWrappable { -public: - static RefPtr<MediaTrackConstraintSet> create(const Dictionary&); - - virtual ~MediaTrackConstraintSet(); - - const Dictionary& constraints() const { return m_constraints; } - -private: - explicit MediaTrackConstraintSet(const Dictionary&); - - const Dictionary& m_constraints; -}; - -} // namespace WebCore - -#endif // MediaTrackConstraintSet_h - -#endif diff --git a/Source/WebCore/Modules/mediastream/MediaTrackConstraintSet.idl b/Source/WebCore/Modules/mediastream/MediaTrackConstraintSet.idl deleted file mode 100644 index 82754c8c6..000000000 --- a/Source/WebCore/Modules/mediastream/MediaTrackConstraintSet.idl +++ /dev/null @@ -1,33 +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 GOOGLE 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 GOOGLE 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. - */ - -[ - Conditional=MEDIA_STREAM, - NoInterfaceObject, -] interface MediaTrackConstraintSet { - // FIXME: Not implemented. - // https://bugs.webkit.org/show_bug.cgi?id=121954 -}; - diff --git a/Source/WebCore/Modules/mediastream/MediaTrackConstraints.cpp b/Source/WebCore/Modules/mediastream/MediaTrackConstraints.cpp index 77b105448..c4c4cf122 100644 --- a/Source/WebCore/Modules/mediastream/MediaTrackConstraints.cpp +++ b/Source/WebCore/Modules/mediastream/MediaTrackConstraints.cpp @@ -1,67 +1,200 @@ /* - * Copyright (C) 2013 Apple 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 * 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 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. + * 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 "MediaTrackConstraints.h" #if ENABLE(MEDIA_STREAM) -#include "MediaTrackConstraints.h" +#include "MediaConstraintsImpl.h" -#include "MediaTrackConstraint.h" -#include "MediaTrackConstraintSet.h" -#include "NotImplemented.h" +namespace WebCore { -using namespace JSC; +enum class ConstraintSetType { Mandatory, Advanced }; -namespace WebCore { +static void set(MediaTrackConstraintSetMap& map, ConstraintSetType setType, const char* typeAsString, MediaConstraintType type, const ConstrainLong& value) +{ + IntConstraint constraint(typeAsString, type); + WTF::switchOn(value, + [&] (int integer) { + if (setType == ConstraintSetType::Mandatory) + constraint.setIdeal(integer); + else + constraint.setExact(integer); + }, + [&] (const ConstrainLongRange& range) { + if (range.min) + constraint.setMin(range.min.value()); + if (range.max) + constraint.setMax(range.max.value()); + if (range.exact) + constraint.setExact(range.exact.value()); + if (range.ideal) + constraint.setIdeal(range.ideal.value()); + } + ); + map.set(type, WTFMove(constraint)); +} + +static void set(MediaTrackConstraintSetMap& map, ConstraintSetType setType, const char* typeAsString, MediaConstraintType type, const ConstrainDouble& value) +{ + DoubleConstraint constraint(typeAsString, type); + WTF::switchOn(value, + [&] (double number) { + if (setType == ConstraintSetType::Mandatory) + constraint.setIdeal(number); + else + constraint.setExact(number); + }, + [&] (const ConstrainDoubleRange& range) { + if (range.min) + constraint.setMin(range.min.value()); + if (range.max) + constraint.setMax(range.max.value()); + if (range.exact) + constraint.setExact(range.exact.value()); + if (range.ideal) + constraint.setIdeal(range.ideal.value()); + } + ); + map.set(type, WTFMove(constraint)); +} -RefPtr<MediaTrackConstraints> MediaTrackConstraints::create(PassRefPtr<MediaConstraintsImpl> constraints) +static void set(MediaTrackConstraintSetMap& map, ConstraintSetType setType, const char* typeAsString, MediaConstraintType type, const ConstrainBoolean& value) { - return adoptRef(new MediaTrackConstraints(constraints)); + BooleanConstraint constraint(typeAsString, type); + WTF::switchOn(value, + [&] (bool boolean) { + if (setType == ConstraintSetType::Mandatory) + constraint.setIdeal(boolean); + else + constraint.setExact(boolean); + }, + [&] (const ConstrainBooleanParameters& parameters) { + if (parameters.exact) + constraint.setExact(parameters.exact.value()); + if (parameters.ideal) + constraint.setIdeal(parameters.ideal.value()); + } + ); + map.set(type, WTFMove(constraint)); } -MediaTrackConstraints::MediaTrackConstraints(PassRefPtr<MediaConstraintsImpl> constraints) - : m_constraints(constraints) +static void set(MediaTrackConstraintSetMap& map, ConstraintSetType setType, const char* typeAsString, MediaConstraintType type, const ConstrainDOMString& value) { + StringConstraint constraint(typeAsString, type); + WTF::switchOn(value, + [&] (const String& string) { + if (setType == ConstraintSetType::Mandatory) + constraint.appendIdeal(string); + else + constraint.appendExact(string); + }, + [&] (const Vector<String>& vector) { + if (setType == ConstraintSetType::Mandatory) { + for (auto& string : vector) + constraint.appendIdeal(string); + } else { + for (auto& string : vector) + constraint.appendExact(string); + } + }, + [&] (const ConstrainDOMStringParameters& parameters) { + if (parameters.exact) { + WTF::switchOn(parameters.exact.value(), + [&] (const String& string) { + constraint.appendExact(string); + }, + [&] (const Vector<String>& vector) { + for (auto& string : vector) + constraint.appendExact(string); + } + ); + } + if (parameters.ideal) { + WTF::switchOn(parameters.ideal.value(), + [&] (const String& string) { + constraint.appendIdeal(string); + }, + [&] (const Vector<String>& vector) { + for (auto& string : vector) + constraint.appendIdeal(string); + } + ); + } + } + ); + map.set(type, WTFMove(constraint)); } -Vector<PassRefPtr<MediaTrackConstraint>> MediaTrackConstraints::optional(bool) const +template<typename T> static inline void set(MediaTrackConstraintSetMap& map, ConstraintSetType setType, const char* typeAsString, MediaConstraintType type, const std::optional<T>& value) { - // https://bugs.webkit.org/show_bug.cgi?id=121954 - notImplemented(); - return Vector<PassRefPtr<MediaTrackConstraint>>(); + if (!value) + return; + set(map, setType, typeAsString, type, value.value()); } -RefPtr<MediaTrackConstraintSet> MediaTrackConstraints::mandatory(bool) const +static MediaTrackConstraintSetMap convertToInternalForm(ConstraintSetType setType, const MediaTrackConstraintSet& constraintSet) { - // https://bugs.webkit.org/show_bug.cgi?id=121954 - notImplemented(); - return nullptr; + MediaTrackConstraintSetMap result; + set(result, setType, "width", MediaConstraintType::Width, constraintSet.width); + set(result, setType, "height", MediaConstraintType::Height, constraintSet.height); + set(result, setType, "aspectRatio", MediaConstraintType::AspectRatio, constraintSet.aspectRatio); + set(result, setType, "frameRate", MediaConstraintType::FrameRate, constraintSet.frameRate); + set(result, setType, "facingMode", MediaConstraintType::FacingMode, constraintSet.facingMode); + set(result, setType, "volume", MediaConstraintType::Volume, constraintSet.volume); + set(result, setType, "sampleRate", MediaConstraintType::SampleRate, constraintSet.sampleRate); + set(result, setType, "sampleSize", MediaConstraintType::SampleSize, constraintSet.sampleSize); + set(result, setType, "echoCancellation", MediaConstraintType::EchoCancellation, constraintSet.echoCancellation); + // FIXME: add latency + // FIXME: add channelCount + set(result, setType, "deviceId", MediaConstraintType::DeviceId, constraintSet.deviceId); + set(result, setType, "groupId", MediaConstraintType::GroupId, constraintSet.groupId); + return result; } -} // namespace WebCore +static Vector<MediaTrackConstraintSetMap> convertAdvancedToInternalForm(const Vector<MediaTrackConstraintSet>& vector) +{ + Vector<MediaTrackConstraintSetMap> result; + result.reserveInitialCapacity(vector.size()); + for (auto& set : vector) + result.uncheckedAppend(convertToInternalForm(ConstraintSetType::Advanced, set)); + return result; +} + +static Vector<MediaTrackConstraintSetMap> convertAdvancedToInternalForm(const std::optional<Vector<MediaTrackConstraintSet>>& optionalVector) +{ + if (!optionalVector) + return { }; + return convertAdvancedToInternalForm(optionalVector.value()); +} + +Ref<MediaConstraintsImpl> createMediaConstraintsImpl(const MediaTrackConstraints& constraints) +{ + return MediaConstraintsImpl::create(convertToInternalForm(ConstraintSetType::Mandatory, constraints), convertAdvancedToInternalForm(constraints.advanced), true); +} + +} #endif diff --git a/Source/WebCore/Modules/mediastream/MediaTrackConstraints.h b/Source/WebCore/Modules/mediastream/MediaTrackConstraints.h index 95a8ccaff..3bccdaea0 100644 --- a/Source/WebCore/Modules/mediastream/MediaTrackConstraints.h +++ b/Source/WebCore/Modules/mediastream/MediaTrackConstraints.h @@ -1,60 +1,86 @@ /* - * Copyright (C) 2013 Apple 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 * 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 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. + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef MediaTrackConstraints_h -#define MediaTrackConstraints_h +#pragma once #if ENABLE(MEDIA_STREAM) -#include "MediaConstraintsImpl.h" -#include "ScriptWrappable.h" -#include <wtf/RefCounted.h> +#include "DoubleRange.h" +#include "LongRange.h" +#include <wtf/Variant.h> +#include <wtf/Vector.h> +#include <wtf/text/WTFString.h> namespace WebCore { -class MediaTrackConstraint; -class MediaTrackConstraintSet; +class MediaConstraintsImpl; -class MediaTrackConstraints : public RefCounted<MediaTrackConstraints>, public ScriptWrappable { -public: - virtual ~MediaTrackConstraints() { } +struct ConstrainBooleanParameters { + std::optional<bool> exact; + std::optional<bool> ideal; +}; - static RefPtr<MediaTrackConstraints> create(PassRefPtr<MediaConstraintsImpl>); +struct ConstrainDOMStringParameters { + std::optional<Variant<String, Vector<String>>> exact; + std::optional<Variant<String, Vector<String>>> ideal; +}; + +struct ConstrainDoubleRange : DoubleRange { + std::optional<double> exact; + std::optional<double> ideal; +}; - Vector<PassRefPtr<MediaTrackConstraint>> optional(bool) const; - RefPtr<MediaTrackConstraintSet> mandatory(bool) const; +struct ConstrainLongRange : LongRange { + std::optional<int> exact; + std::optional<int> ideal; +}; + +using ConstrainBoolean = Variant<bool, ConstrainBooleanParameters>; +using ConstrainDOMString = Variant<String, Vector<String>, ConstrainDOMStringParameters>; +using ConstrainDouble = Variant<double, ConstrainDoubleRange>; +using ConstrainLong = Variant<int, ConstrainLongRange>; + +struct MediaTrackConstraintSet { + std::optional<ConstrainLong> width; + std::optional<ConstrainLong> height; + std::optional<ConstrainDouble> aspectRatio; + std::optional<ConstrainDouble> frameRate; + std::optional<ConstrainDOMString> facingMode; + std::optional<ConstrainDouble> volume; + std::optional<ConstrainLong> sampleRate; + std::optional<ConstrainLong> sampleSize; + std::optional<ConstrainBoolean> echoCancellation; + std::optional<ConstrainDOMString> deviceId; + std::optional<ConstrainDOMString> groupId; +}; -private: - explicit MediaTrackConstraints(PassRefPtr<MediaConstraintsImpl>); - - RefPtr<MediaConstraintsImpl> m_constraints; +struct MediaTrackConstraints : MediaTrackConstraintSet { + std::optional<Vector<MediaTrackConstraintSet>> advanced; }; -} // namespace WebCore +Ref<MediaConstraintsImpl> createMediaConstraintsImpl(const MediaTrackConstraints&); -#endif // MediaTrackConstraints_h +} #endif diff --git a/Source/WebCore/Modules/mediastream/MediaTrackConstraints.idl b/Source/WebCore/Modules/mediastream/MediaTrackConstraints.idl index aab80d0aa..59b96bd37 100644 --- a/Source/WebCore/Modules/mediastream/MediaTrackConstraints.idl +++ b/Source/WebCore/Modules/mediastream/MediaTrackConstraints.idl @@ -1,33 +1,91 @@ /* - * Copyright (C) 2013 Apple 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 * 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. + * 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. + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ [ Conditional=MEDIA_STREAM, - NoInterfaceObject, -] interface MediaTrackConstraints { - readonly attribute MediaTrackConstraintSet? mandatory; - readonly attribute MediaTrackConstraint[]? optional; + JSGenerateToJSObject, +] dictionary MediaTrackConstraints : MediaTrackConstraintSet { + sequence<MediaTrackConstraintSet> advanced; }; +[ + Conditional=MEDIA_STREAM, + JSGenerateToJSObject, + ImplementedAs=MediaTrackConstraintSet +] dictionary MediaTrackConstraintSet { + ConstrainLong width; + ConstrainLong height; + ConstrainDouble aspectRatio; + ConstrainDouble frameRate; + ConstrainDOMString facingMode; + ConstrainDouble volume; + ConstrainLong sampleRate; + ConstrainLong sampleSize; + ConstrainBoolean echoCancellation; + // FIXME: add latency + // FIXME: add channelCount + ConstrainDOMString deviceId; + ConstrainDOMString groupId; +}; + +typedef (double or ConstrainDoubleRange) ConstrainDouble; +typedef (long or ConstrainLongRange) ConstrainLong; +typedef (boolean or ConstrainBooleanParameters) ConstrainBoolean; +typedef (DOMString or sequence<DOMString> or ConstrainDOMStringParameters) ConstrainDOMString; + +[ + Conditional=MEDIA_STREAM, + JSGenerateToJSObject, + ImplementedAs=ConstrainBooleanParameters +] dictionary ConstrainBooleanParameters { + boolean exact; + boolean ideal; +}; + +[ + Conditional=MEDIA_STREAM, + JSGenerateToJSObject, + ImplementedAs=ConstrainDOMStringParameters +] dictionary ConstrainDOMStringParameters { + (DOMString or sequence<DOMString>) exact; + (DOMString or sequence<DOMString>) ideal; +}; + +[ + Conditional=MEDIA_STREAM, + JSGenerateToJSObject, + ImplementedAs=ConstrainDoubleRange +] dictionary ConstrainDoubleRange : DoubleRange { + double exact; + double ideal; +}; + +[ + Conditional=MEDIA_STREAM, + JSGenerateToJSObject, + ImplementedAs=ConstrainLongRange +] dictionary ConstrainLongRange : LongRange { + long exact; + long ideal; +}; diff --git a/Source/WebCore/Modules/mediastream/MediaTrackSupportedConstraints.h b/Source/WebCore/Modules/mediastream/MediaTrackSupportedConstraints.h new file mode 100644 index 000000000..f8626b899 --- /dev/null +++ b/Source/WebCore/Modules/mediastream/MediaTrackSupportedConstraints.h @@ -0,0 +1,53 @@ +/* + * 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 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(MEDIA_STREAM) + +namespace WebCore { + +struct MediaTrackSupportedConstraints { + bool width; + bool height; + bool aspectRatio; + bool frameRate; + bool facingMode; + bool volume; + bool sampleRate; + bool sampleSize; + bool echoCancellation; + bool deviceId; + bool groupId; +}; + +} // namespace WebCore + +#endif // ENABLE(MEDIA_STREAM) diff --git a/Source/WebCore/Modules/mediastream/MediaTrackSupportedConstraints.idl b/Source/WebCore/Modules/mediastream/MediaTrackSupportedConstraints.idl new file mode 100644 index 000000000..586ec6990 --- /dev/null +++ b/Source/WebCore/Modules/mediastream/MediaTrackSupportedConstraints.idl @@ -0,0 +1,46 @@ +/* +* 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 Ericsson nor the names of its contributors +* may be used to endorse or promote products derived from this +* software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +[ + Conditional=MEDIA_STREAM, + JSGenerateToJSObject, +] dictionary MediaTrackSupportedConstraints { + boolean width = true; + boolean height = true; + boolean aspectRatio = true; + boolean frameRate = true; + boolean facingMode = true; + boolean volume = true; + boolean sampleRate = true; + boolean sampleSize = true; + boolean echoCancellation = true; + boolean deviceId = true; + boolean groupId = true; +}; diff --git a/Source/WebCore/Modules/mediastream/RTCVoidRequestImpl.cpp b/Source/WebCore/Modules/mediastream/NavigatorMediaDevices.cpp index 116115818..8a0f16ba6 100644 --- a/Source/WebCore/Modules/mediastream/RTCVoidRequestImpl.cpp +++ b/Source/WebCore/Modules/mediastream/NavigatorMediaDevices.cpp @@ -1,6 +1,5 @@ /* - * Copyright (C) 2012 Google Inc. All rights reserved. - * Copyright (C) 2013 Nokia Corporation and/or its subsidiary(-ies). + * Copyright (C) 2015 Ericsson AB. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -12,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. * @@ -30,61 +29,52 @@ */ #include "config.h" +#include "NavigatorMediaDevices.h" #if ENABLE(MEDIA_STREAM) -#include "RTCVoidRequestImpl.h" - -#include "DOMError.h" -#include "RTCPeerConnection.h" -#include "RTCPeerConnectionErrorCallback.h" -#include "VoidCallback.h" +#include "Document.h" +#include "Frame.h" +#include "MediaDevices.h" +#include "Navigator.h" namespace WebCore { -PassRefPtr<RTCVoidRequestImpl> RTCVoidRequestImpl::create(ScriptExecutionContext* context, PassRefPtr<VoidCallback> successCallback, PassRefPtr<RTCPeerConnectionErrorCallback> errorCallback) -{ - RefPtr<RTCVoidRequestImpl> request = adoptRef(new RTCVoidRequestImpl(context, successCallback, errorCallback)); - request->suspendIfNeeded(); - return request.release(); -} - -RTCVoidRequestImpl::RTCVoidRequestImpl(ScriptExecutionContext* context, PassRefPtr<VoidCallback> successCallback, PassRefPtr<RTCPeerConnectionErrorCallback> errorCallback) - : ActiveDOMObject(context) - , m_successCallback(successCallback) - , m_errorCallback(errorCallback) +NavigatorMediaDevices::NavigatorMediaDevices(Frame* frame) + : DOMWindowProperty(frame) { } -RTCVoidRequestImpl::~RTCVoidRequestImpl() +NavigatorMediaDevices::~NavigatorMediaDevices() { } -void RTCVoidRequestImpl::requestSucceeded() +NavigatorMediaDevices* NavigatorMediaDevices::from(Navigator* navigator) { - if (m_successCallback) - m_successCallback->handleEvent(); - - clear(); + NavigatorMediaDevices* supplement = static_cast<NavigatorMediaDevices*>(Supplement<Navigator>::from(navigator, supplementName())); + if (!supplement) { + auto newSupplement = std::make_unique<NavigatorMediaDevices>(navigator->frame()); + supplement = newSupplement.get(); + provideTo(navigator, supplementName(), WTFMove(newSupplement)); + } + return supplement; } -void RTCVoidRequestImpl::requestFailed(const String& error) +MediaDevices* NavigatorMediaDevices::mediaDevices(Navigator& navigator) { - if (m_errorCallback.get()) - m_errorCallback->handleEvent(DOMError::create(error).get()); - - clear(); + return NavigatorMediaDevices::from(&navigator)->mediaDevices(); } -void RTCVoidRequestImpl::stop() +MediaDevices* NavigatorMediaDevices::mediaDevices() const { - clear(); + if (!m_mediaDevices && frame()) + m_mediaDevices = MediaDevices::create(*frame()->document()); + return m_mediaDevices.get(); } -void RTCVoidRequestImpl::clear() +const char* NavigatorMediaDevices::supplementName() { - m_successCallback.clear(); - m_errorCallback.clear(); + return "NavigatorMediaDevices"; } } // namespace WebCore diff --git a/Source/WebCore/Modules/mediastream/RTCVoidRequestImpl.h b/Source/WebCore/Modules/mediastream/NavigatorMediaDevices.h index 3c3f34d48..677ddbbdf 100644 --- a/Source/WebCore/Modules/mediastream/RTCVoidRequestImpl.h +++ b/Source/WebCore/Modules/mediastream/NavigatorMediaDevices.h @@ -1,6 +1,5 @@ /* - * Copyright (C) 2012 Google Inc. All rights reserved. - * Copyright (C) 2013 Nokia Corporation and/or its subsidiary(-ies). + * Copyright (C) 2015 Ericsson AB. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -12,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. * @@ -29,43 +28,34 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef RTCVoidRequestImpl_h -#define RTCVoidRequestImpl_h +#pragma once #if ENABLE(MEDIA_STREAM) -#include "ActiveDOMObject.h" -#include "RTCVoidRequest.h" +#include "DOMWindowProperty.h" +#include "Supplementable.h" namespace WebCore { -class RTCPeerConnectionErrorCallback; -class VoidCallback; +class Frame; +class MediaDevices; +class Navigator; -class RTCVoidRequestImpl : public RTCVoidRequest, public ActiveDOMObject { +class NavigatorMediaDevices : public Supplement<Navigator>, public DOMWindowProperty { public: - static PassRefPtr<RTCVoidRequestImpl> create(ScriptExecutionContext*, PassRefPtr<VoidCallback>, PassRefPtr<RTCPeerConnectionErrorCallback>); - virtual ~RTCVoidRequestImpl(); + explicit NavigatorMediaDevices(Frame*); + virtual ~NavigatorMediaDevices(); + static NavigatorMediaDevices* from(Navigator*); - virtual void requestSucceeded(); - virtual void requestFailed(const String& error); - - // ActiveDOMObject - virtual void stop() override; + static MediaDevices* mediaDevices(Navigator&); + MediaDevices* mediaDevices() const; private: - RTCVoidRequestImpl(ScriptExecutionContext*, PassRefPtr<VoidCallback>, PassRefPtr<RTCPeerConnectionErrorCallback>); - - void clear(); + static const char* supplementName(); - RefPtr<VoidCallback> m_successCallback; - RefPtr<RTCPeerConnectionErrorCallback> m_errorCallback; + mutable RefPtr<MediaDevices> m_mediaDevices; }; } // namespace WebCore #endif // ENABLE(MEDIA_STREAM) - -#endif // RTCVoidRequestImpl_h - - diff --git a/Source/WebCore/Modules/mediastream/RTCSessionDescriptionCallback.idl b/Source/WebCore/Modules/mediastream/NavigatorMediaDevices.idl index 30ce08568..9c8e7849c 100644 --- a/Source/WebCore/Modules/mediastream/RTCSessionDescriptionCallback.idl +++ b/Source/WebCore/Modules/mediastream/NavigatorMediaDevices.idl @@ -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. * @@ -30,7 +30,7 @@ [ Conditional=MEDIA_STREAM, -] callback interface RTCSessionDescriptionCallback { - boolean handleEvent(RTCSessionDescription sdp); + EnabledAtRuntime=MediaStream, +] partial interface Navigator { + readonly attribute MediaDevices mediaDevices; }; - diff --git a/Source/WebCore/Modules/mediastream/NavigatorMediaStream.cpp b/Source/WebCore/Modules/mediastream/NavigatorMediaStream.cpp deleted file mode 100644 index c14bc10e1..000000000 --- a/Source/WebCore/Modules/mediastream/NavigatorMediaStream.cpp +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright (C) 2000 Harri Porten (porten@kde.org) - * Copyright (c) 2000 Daniel Molkentin (molkentin@kde.org) - * Copyright (c) 2000 Stefan Schimanski (schimmi@kde.org) - * Copyright (C) 2003, 2004, 2005, 2006 Apple Computer, Inc. - * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "config.h" -#include "NavigatorMediaStream.h" - -#if ENABLE(MEDIA_STREAM) - -#include "Dictionary.h" -#include "Document.h" -#include "ExceptionCode.h" -#include "Frame.h" -#include "Navigator.h" -#include "NavigatorUserMediaErrorCallback.h" -#include "NavigatorUserMediaSuccessCallback.h" -#include "Page.h" -#include "UserMediaController.h" -#include "UserMediaRequest.h" - -namespace WebCore { - -NavigatorMediaStream::NavigatorMediaStream() -{ -} - -NavigatorMediaStream::~NavigatorMediaStream() -{ -} - -void NavigatorMediaStream::webkitGetUserMedia(Navigator* navigator, const Dictionary& options, PassRefPtr<NavigatorUserMediaSuccessCallback> successCallback, PassRefPtr<NavigatorUserMediaErrorCallback> errorCallback, ExceptionCode& ec) -{ - if (!successCallback) - return; - - UserMediaController* userMedia = UserMediaController::from(navigator->frame() ? navigator->frame()->page() : 0); - if (!userMedia) { - ec = NOT_SUPPORTED_ERR; - return; - } - - RefPtr<UserMediaRequest> request = UserMediaRequest::create(navigator->frame()->document(), userMedia, options, successCallback, errorCallback, ec); - if (!request) { - ec = NOT_SUPPORTED_ERR; - return; - } - - request->start(); -} - -} // namespace WebCore - -#endif // ENABLE(MEDIA_STREAM) diff --git a/Source/WebCore/Modules/mediastream/NavigatorMediaStream.h b/Source/WebCore/Modules/mediastream/NavigatorMediaStream.h deleted file mode 100644 index 1bdf4de32..000000000 --- a/Source/WebCore/Modules/mediastream/NavigatorMediaStream.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public License - along with this library; see the file COPYING.LIB. If not, write to - the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. -*/ - -#ifndef NavigatorMediaStream_h -#define NavigatorMediaStream_h - -#if ENABLE(MEDIA_STREAM) - -#include <wtf/PassRefPtr.h> -#include <wtf/text/WTFString.h> - -namespace WebCore { - -class Dictionary; -class Navigator; -class NavigatorUserMediaErrorCallback; -class NavigatorUserMediaSuccessCallback; - -typedef int ExceptionCode; - -class NavigatorMediaStream { -public: - static void webkitGetUserMedia(Navigator*, const Dictionary&, PassRefPtr<NavigatorUserMediaSuccessCallback>, PassRefPtr<NavigatorUserMediaErrorCallback>, ExceptionCode&); - -private: - NavigatorMediaStream(); - ~NavigatorMediaStream(); -}; - -} // namespace WebCore - -#endif // ENABLE(MEDIA_STREAM) - -#endif // NavigatorMediaStream_h diff --git a/Source/WebCore/Modules/mediastream/NavigatorMediaStream.idl b/Source/WebCore/Modules/mediastream/NavigatorMediaStream.idl deleted file mode 100644 index 0cf230796..000000000 --- a/Source/WebCore/Modules/mediastream/NavigatorMediaStream.idl +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (C) 2012 Google Inc. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public License - * along with this library; see the file COPYING.LIB. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - -[ - Conditional=MEDIA_STREAM, -] partial interface Navigator { - [RaisesException] void webkitGetUserMedia(Dictionary options, - NavigatorUserMediaSuccessCallback successCallback, - optional NavigatorUserMediaErrorCallback errorCallback); -}; - diff --git a/Source/WebCore/Modules/mediastream/NavigatorUserMedia.idl b/Source/WebCore/Modules/mediastream/NavigatorUserMedia.idl new file mode 100644 index 000000000..85e32d318 --- /dev/null +++ b/Source/WebCore/Modules/mediastream/NavigatorUserMedia.idl @@ -0,0 +1,36 @@ +/* +* 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. +* 3. Neither the name of Ericsson nor the names of its contributors +* may be used to endorse or promote products derived from this +* software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +[ + Conditional=MEDIA_STREAM, + EnabledAtRuntime=MediaStream, +] partial interface Navigator { + [JSBuiltin] void getUserMedia(MediaStreamConstraints constraints, NavigatorUserMediaSuccessCallback successCallback, NavigatorUserMediaErrorCallback errorCallback); +}; diff --git a/Source/WebCore/Modules/mediastream/NavigatorUserMedia.js b/Source/WebCore/Modules/mediastream/NavigatorUserMedia.js new file mode 100644 index 000000000..d1417d78b --- /dev/null +++ b/Source/WebCore/Modules/mediastream/NavigatorUserMedia.js @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2015 Canon Inc. + * 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. ``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. + */ + +// @conditional=ENABLE(MEDIA_STREAM) + +function getUserMedia(options, successCallback, errorCallback) +{ + "use strict"; + + // FIXME: We should raise a DOM unsupported exception if there is no navigator and properly detect whether method is not called on a Navigator object. + if (!(this.mediaDevices && this.mediaDevices.@getUserMedia)) + throw @makeThisTypeError("Navigator", "getUserMedia"); + + if (arguments.length < 3) + @throwTypeError("Not enough arguments"); + + if (options !== @Object(options)) + @throwTypeError("Argument 1 (options) to Navigator.getUserMedia must be an object"); + + if (typeof successCallback !== "function") + @throwTypeError("Argument 2 ('successCallback') to Navigator.getUserMedia must be a function"); + if (typeof errorCallback !== "function") + @throwTypeError("Argument 3 ('errorCallback') to Navigator.getUserMedia must be a function"); + + this.mediaDevices.@getUserMedia(options).@then(successCallback, errorCallback); +} diff --git a/Source/WebCore/Modules/mediastream/NavigatorUserMediaError.cpp b/Source/WebCore/Modules/mediastream/NavigatorUserMediaError.cpp deleted file mode 100644 index 5ff494582..000000000 --- a/Source/WebCore/Modules/mediastream/NavigatorUserMediaError.cpp +++ /dev/null @@ -1,51 +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. - */ - -#include "config.h" - -#if ENABLE(MEDIA_STREAM) - -#include "NavigatorUserMediaError.h" - -#include <wtf/NeverDestroyed.h> - -namespace WebCore { - -const AtomicString& NavigatorUserMediaError::permissionDeniedErrorName() -{ - static NeverDestroyed<AtomicString> permissionDenied("PermissionDeniedError", AtomicString::ConstructFromLiteral); - return permissionDenied; -} - -const AtomicString& NavigatorUserMediaError::constraintNotSatisfiedErrorName() -{ - static NeverDestroyed<AtomicString> constraintNotSatisfied("ConstraintNotSatisfiedError", AtomicString::ConstructFromLiteral); - return constraintNotSatisfied; -} - -} // namespace WebCore - -#endif // ENABLE(MEDIA_STREAM) - diff --git a/Source/WebCore/Modules/mediastream/NavigatorUserMediaErrorCallback.h b/Source/WebCore/Modules/mediastream/NavigatorUserMediaErrorCallback.h deleted file mode 100644 index dd3c8b32b..000000000 --- a/Source/WebCore/Modules/mediastream/NavigatorUserMediaErrorCallback.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (C) 2011 Google Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef NavigatorUserMediaErrorCallback_h -#define NavigatorUserMediaErrorCallback_h - -#if ENABLE(MEDIA_STREAM) - -#include "NavigatorUserMediaError.h" -#include <wtf/RefCounted.h> - -namespace WebCore { - -class NavigatorUserMediaErrorCallback : public RefCounted<NavigatorUserMediaErrorCallback> { -public: - virtual ~NavigatorUserMediaErrorCallback() { } - virtual bool handleEvent(NavigatorUserMediaError*) = 0; -}; - -} // namespace WebCore - -#endif // ENABLE(MEDIA_STREAM) - -#endif // NavigatorUserMediaErrorCallback_h diff --git a/Source/WebCore/Modules/mediastream/NavigatorUserMediaSuccessCallback.h b/Source/WebCore/Modules/mediastream/NavigatorUserMediaSuccessCallback.h deleted file mode 100644 index 9f456eadc..000000000 --- a/Source/WebCore/Modules/mediastream/NavigatorUserMediaSuccessCallback.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (C) 2011 Google Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef NavigatorUserMediaSuccessCallback_h -#define NavigatorUserMediaSuccessCallback_h - -#if ENABLE(MEDIA_STREAM) - -#include <wtf/RefCounted.h> - -namespace WebCore { - -class MediaStream; - -class NavigatorUserMediaSuccessCallback : public RefCounted<NavigatorUserMediaSuccessCallback> { -public: - virtual ~NavigatorUserMediaSuccessCallback() { } - virtual bool handleEvent(MediaStream*) = 0; -}; - -} // namespace WebCore - -#endif // ENABLE(MEDIA_STREAM) - -#endif // NavigatorUserMediaSuccessCallback_h diff --git a/Source/WebCore/Modules/mediastream/OverconstrainedError.h b/Source/WebCore/Modules/mediastream/OverconstrainedError.h new file mode 100644 index 000000000..126ccb617 --- /dev/null +++ b/Source/WebCore/Modules/mediastream/OverconstrainedError.h @@ -0,0 +1,62 @@ +/* + * 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 Apple Inc. ("Apple") 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 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 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(MEDIA_STREAM) + +#include <wtf/RefCounted.h> +#include <wtf/text/WTFString.h> + +namespace WebCore { + +class OverconstrainedError : public RefCounted<OverconstrainedError> { +public: + static Ref<OverconstrainedError> create(const String& constraint, const String& message) + { + return adoptRef(*new OverconstrainedError(constraint, message)); + } + + String constraint() const { return m_constraint; } + String message() const { return m_message; } + +protected: + explicit OverconstrainedError(const String& constraint, const String& message) + : m_constraint(constraint) + , m_message(message) + { + } + +private: + String m_constraint; + String m_message; +}; + +} // namespace WebCore + +#endif diff --git a/Source/WebCore/Modules/mediastream/NavigatorUserMediaError.idl b/Source/WebCore/Modules/mediastream/OverconstrainedError.idl index de1030417..8c505c6a5 100644 --- a/Source/WebCore/Modules/mediastream/NavigatorUserMediaError.idl +++ b/Source/WebCore/Modules/mediastream/OverconstrainedError.idl @@ -1,33 +1,36 @@ /* - * Copyright (C) 2011 Google Inc. All rights reserved. - * Copyright (C) 2013 Apple 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 * 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 Apple Inc. ("Apple") 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 + * THIS SOFTWARE IS PROVIDED BY APPLE 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 + * DISCLAIMED. IN NO EVENT SHALL APPLE 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. + * 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. */ [ - NoInterfaceObject, + Constructor(optional DOMString constraint = "", optional DOMString message = ""), + ImplementationLacksVTable, Conditional=MEDIA_STREAM, - JSGenerateToJSObject, -] interface NavigatorUserMediaError : DOMError { - readonly attribute DOMString constraintName; +] exception OverconstrainedError { + readonly attribute DOMString message; + readonly attribute DOMString constraint; }; - diff --git a/Source/WebCore/Modules/mediastream/OverconstrainedErrorEvent.h b/Source/WebCore/Modules/mediastream/OverconstrainedErrorEvent.h new file mode 100644 index 000000000..9c4f39640 --- /dev/null +++ b/Source/WebCore/Modules/mediastream/OverconstrainedErrorEvent.h @@ -0,0 +1,77 @@ +/* + * 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 Apple Inc. ("Apple") 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 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 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(MEDIA_STREAM) + +#include "Event.h" +#include "OverconstrainedError.h" +#include <wtf/text/AtomicString.h> + +namespace WebCore { + +class OverconstrainedErrorEvent : public Event { +public: + virtual ~OverconstrainedErrorEvent() { } + + static Ref<OverconstrainedErrorEvent> create(const AtomicString& type, bool canBubble, bool cancelable, OverconstrainedError* error) + { + return adoptRef(*new OverconstrainedErrorEvent(type, canBubble, cancelable, error)); + } + + struct Init : EventInit { + RefPtr<OverconstrainedError> error; + }; + + static Ref<OverconstrainedErrorEvent> create(const AtomicString& type, const Init& initializer, IsTrusted isTrusted = IsTrusted::No) + { + return adoptRef(*new OverconstrainedErrorEvent(type, initializer, isTrusted)); + } + + OverconstrainedError* error() const { return m_error.get(); } + EventInterface eventInterface() const override { return OverconstrainedErrorEventInterfaceType; } + +private: + explicit OverconstrainedErrorEvent(const AtomicString& type, bool canBubble, bool cancelable, OverconstrainedError* error) + : Event(type, canBubble, cancelable) + , m_error(error) + { + } + OverconstrainedErrorEvent(const AtomicString& type, const Init& initializer, IsTrusted isTrusted) + : Event(type, initializer, isTrusted) + , m_error(initializer.error) + { + } + + RefPtr<OverconstrainedError> m_error; +}; + +} // namespace WebCore + +#endif // ENABLE(MEDIA_STREAM) diff --git a/Source/WebCore/Modules/mediastream/OverconstrainedErrorEvent.idl b/Source/WebCore/Modules/mediastream/OverconstrainedErrorEvent.idl new file mode 100644 index 000000000..ceddfa7f2 --- /dev/null +++ b/Source/WebCore/Modules/mediastream/OverconstrainedErrorEvent.idl @@ -0,0 +1,38 @@ +/* +* 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 Apple Inc. ("Apple") 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 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 OR ITS CONTRIBUTORS BE LIABLE FOR ANY +* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +[ + Conditional=MEDIA_STREAM, + Constructor(DOMString type, optional OverconstrainedErrorEventInit eventInitDict), +] interface OverconstrainedErrorEvent : Event { + readonly attribute OverconstrainedError? error; +}; + +dictionary OverconstrainedErrorEventInit : EventInit { + OverconstrainedError? error = null; +}; diff --git a/Source/WebCore/Modules/mediastream/PeerConnectionBackend.cpp b/Source/WebCore/Modules/mediastream/PeerConnectionBackend.cpp new file mode 100644 index 000000000..ba2d43fd2 --- /dev/null +++ b/Source/WebCore/Modules/mediastream/PeerConnectionBackend.cpp @@ -0,0 +1,312 @@ +/* + * Copyright (C) 2015 Ericsson AB. 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 + * 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 "PeerConnectionBackend.h" + +#if ENABLE(WEB_RTC) + +#include "EventNames.h" +#include "JSRTCSessionDescription.h" +#include "RTCIceCandidate.h" +#include "RTCIceCandidateEvent.h" +#include "RTCPeerConnection.h" + +namespace WebCore { + +void PeerConnectionBackend::createOffer(RTCOfferOptions&& options, PeerConnection::SessionDescriptionPromise&& promise) +{ + ASSERT(!m_offerAnswerPromise); + ASSERT(m_peerConnection.internalSignalingState() != PeerConnectionStates::SignalingState::Closed); + + m_offerAnswerPromise = WTFMove(promise); + doCreateOffer(WTFMove(options)); +} + +void PeerConnectionBackend::createOfferSucceeded(String&& sdp) +{ + ASSERT(isMainThread()); + + if (m_peerConnection.internalSignalingState() == PeerConnectionStates::SignalingState::Closed) + return; + + ASSERT(m_offerAnswerPromise); + m_offerAnswerPromise->resolve(RTCSessionDescription::create(RTCSessionDescription::SdpType::Offer, WTFMove(sdp))); + m_offerAnswerPromise = std::nullopt; +} + +void PeerConnectionBackend::createOfferFailed(Exception&& exception) +{ + ASSERT(isMainThread()); + + if (m_peerConnection.internalSignalingState() == PeerConnectionStates::SignalingState::Closed) + return; + + ASSERT(m_offerAnswerPromise); + m_offerAnswerPromise->reject(WTFMove(exception)); + m_offerAnswerPromise = std::nullopt; +} + +void PeerConnectionBackend::createAnswer(RTCAnswerOptions&& options, PeerConnection::SessionDescriptionPromise&& promise) +{ + ASSERT(!m_offerAnswerPromise); + ASSERT(m_peerConnection.internalSignalingState() != PeerConnectionStates::SignalingState::Closed); + + m_offerAnswerPromise = WTFMove(promise); + doCreateAnswer(WTFMove(options)); +} + +void PeerConnectionBackend::createAnswerSucceeded(String&& sdp) +{ + ASSERT(isMainThread()); + + if (m_peerConnection.internalSignalingState() == PeerConnectionStates::SignalingState::Closed) + return; + + ASSERT(m_offerAnswerPromise); + m_offerAnswerPromise->resolve(RTCSessionDescription::create(RTCSessionDescription::SdpType::Answer, WTFMove(sdp))); + m_offerAnswerPromise = std::nullopt; +} + +void PeerConnectionBackend::createAnswerFailed(Exception&& exception) +{ + ASSERT(isMainThread()); + + if (m_peerConnection.internalSignalingState() == PeerConnectionStates::SignalingState::Closed) + return; + + ASSERT(m_offerAnswerPromise); + m_offerAnswerPromise->reject(WTFMove(exception)); + m_offerAnswerPromise = std::nullopt; +} + +static inline bool isLocalDescriptionTypeValidForState(RTCSessionDescription::SdpType type, PeerConnectionStates::SignalingState state) +{ + switch (state) { + case PeerConnectionStates::SignalingState::Stable: + return type == RTCSessionDescription::SdpType::Offer; + case PeerConnectionStates::SignalingState::HaveLocalOffer: + return type == RTCSessionDescription::SdpType::Offer; + case PeerConnectionStates::SignalingState::HaveRemoteOffer: + return type == RTCSessionDescription::SdpType::Answer || type == RTCSessionDescription::SdpType::Pranswer; + case PeerConnectionStates::SignalingState::HaveLocalPrAnswer: + return type == RTCSessionDescription::SdpType::Answer || type == RTCSessionDescription::SdpType::Pranswer; + default: + return false; + }; + + ASSERT_NOT_REACHED(); + return false; +} + +void PeerConnectionBackend::setLocalDescription(RTCSessionDescription& sessionDescription, DOMPromise<void>&& promise) +{ + ASSERT(m_peerConnection.internalSignalingState() != PeerConnectionStates::SignalingState::Closed); + + if (!isLocalDescriptionTypeValidForState(sessionDescription.type(), m_peerConnection.internalSignalingState())) { + promise.reject(INVALID_STATE_ERR, "Description type incompatible with current signaling state"); + return; + } + + m_setDescriptionPromise = WTFMove(promise); + doSetLocalDescription(sessionDescription); +} + +void PeerConnectionBackend::setLocalDescriptionSucceeded() +{ + ASSERT(isMainThread()); + + if (m_peerConnection.internalSignalingState() == PeerConnectionStates::SignalingState::Closed) + return; + + ASSERT(m_setDescriptionPromise); + + m_setDescriptionPromise->resolve(); + m_setDescriptionPromise = std::nullopt; +} + +void PeerConnectionBackend::setLocalDescriptionFailed(Exception&& exception) +{ + ASSERT(isMainThread()); + + if (m_peerConnection.internalSignalingState() == PeerConnectionStates::SignalingState::Closed) + return; + + ASSERT(m_setDescriptionPromise); + + m_setDescriptionPromise->reject(WTFMove(exception)); + m_setDescriptionPromise = std::nullopt; +} + +static inline bool isRemoteDescriptionTypeValidForState(RTCSessionDescription::SdpType type, PeerConnectionStates::SignalingState state) +{ + switch (state) { + case PeerConnectionStates::SignalingState::Stable: + return type == RTCSessionDescription::SdpType::Offer; + case PeerConnectionStates::SignalingState::HaveLocalOffer: + return type == RTCSessionDescription::SdpType::Answer || type == RTCSessionDescription::SdpType::Pranswer; + case PeerConnectionStates::SignalingState::HaveRemoteOffer: + return type == RTCSessionDescription::SdpType::Offer; + case PeerConnectionStates::SignalingState::HaveRemotePrAnswer: + return type == RTCSessionDescription::SdpType::Answer || type == RTCSessionDescription::SdpType::Pranswer; + default: + return false; + }; + + ASSERT_NOT_REACHED(); + return false; +} + +void PeerConnectionBackend::setRemoteDescription(RTCSessionDescription& sessionDescription, DOMPromise<void>&& promise) +{ + ASSERT(m_peerConnection.internalSignalingState() != PeerConnectionStates::SignalingState::Closed); + + if (!isRemoteDescriptionTypeValidForState(sessionDescription.type(), m_peerConnection.internalSignalingState())) { + promise.reject(INVALID_STATE_ERR, "Description type incompatible with current signaling state"); + return; + } + + m_setDescriptionPromise = WTFMove(promise); + doSetRemoteDescription(sessionDescription); +} + +void PeerConnectionBackend::setRemoteDescriptionSucceeded() +{ + ASSERT(isMainThread()); + + if (m_peerConnection.internalSignalingState() == PeerConnectionStates::SignalingState::Closed) + return; + + ASSERT(m_setDescriptionPromise); + + m_setDescriptionPromise->resolve(); + m_setDescriptionPromise = std::nullopt; +} + +void PeerConnectionBackend::setRemoteDescriptionFailed(Exception&& exception) +{ + ASSERT(isMainThread()); + + if (m_peerConnection.internalSignalingState() == PeerConnectionStates::SignalingState::Closed) + return; + + ASSERT(m_setDescriptionPromise); + + m_setDescriptionPromise->reject(WTFMove(exception)); + m_setDescriptionPromise = std::nullopt; +} + +void PeerConnectionBackend::addIceCandidate(RTCIceCandidate& iceCandidate, DOMPromise<void>&& promise) +{ + ASSERT(m_peerConnection.internalSignalingState() != PeerConnectionStates::SignalingState::Closed); + + if (iceCandidate.sdpMid().isNull() && !iceCandidate.sdpMLineIndex()) { + promise.reject(Exception { TypeError, ASCIILiteral("Trying to add a candidate that is missing both sdpMid and sdpMLineIndex") }); + return; + } + m_addIceCandidatePromise = WTFMove(promise); + doAddIceCandidate(iceCandidate); +} + +void PeerConnectionBackend::addIceCandidateSucceeded() +{ + ASSERT(isMainThread()); + + if (m_peerConnection.internalSignalingState() == PeerConnectionStates::SignalingState::Closed) + return; + + // FIXME: Update remote description and set ICE connection state to checking if not already done so. + ASSERT(m_addIceCandidatePromise); + + m_addIceCandidatePromise->resolve(); + m_addIceCandidatePromise = std::nullopt; +} + +void PeerConnectionBackend::addIceCandidateFailed(Exception&& exception) +{ + ASSERT(isMainThread()); + if (m_peerConnection.internalSignalingState() == PeerConnectionStates::SignalingState::Closed) + return; + + ASSERT(m_addIceCandidatePromise); + + m_addIceCandidatePromise->reject(WTFMove(exception)); + m_addIceCandidatePromise = std::nullopt; +} + +void PeerConnectionBackend::fireICECandidateEvent(RefPtr<RTCIceCandidate>&& candidate) +{ + ASSERT(isMainThread()); + + m_peerConnection.fireEvent(RTCIceCandidateEvent::create(false, false, WTFMove(candidate))); +} + +void PeerConnectionBackend::doneGatheringCandidates() +{ + ASSERT(isMainThread()); + + m_peerConnection.fireEvent(RTCIceCandidateEvent::create(false, false, nullptr)); + m_peerConnection.updateIceGatheringState(PeerConnectionStates::IceGatheringState::Complete); +} + +void PeerConnectionBackend::updateSignalingState(PeerConnectionStates::SignalingState newSignalingState) +{ + ASSERT(isMainThread()); + + if (newSignalingState != m_peerConnection.internalSignalingState()) { + m_peerConnection.setSignalingState(newSignalingState); + m_peerConnection.fireEvent(Event::create(eventNames().signalingstatechangeEvent, false, false)); + } +} + +void PeerConnectionBackend::stop() +{ + m_offerAnswerPromise = std::nullopt; + m_setDescriptionPromise = std::nullopt; + m_addIceCandidatePromise = std::nullopt; + + doStop(); +} + +void PeerConnectionBackend::markAsNeedingNegotiation() +{ + if (m_negotiationNeeded) + return; + + m_negotiationNeeded = true; + + if (m_peerConnection.internalSignalingState() == PeerConnectionStates::SignalingState::Stable) + m_peerConnection.scheduleNegotiationNeededEvent(); +} + +} // namespace WebCore + +#endif // ENABLE(WEB_RTC) diff --git a/Source/WebCore/Modules/mediastream/PeerConnectionBackend.h b/Source/WebCore/Modules/mediastream/PeerConnectionBackend.h new file mode 100644 index 000000000..5df7db454 --- /dev/null +++ b/Source/WebCore/Modules/mediastream/PeerConnectionBackend.h @@ -0,0 +1,146 @@ +/* + * 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 "JSDOMPromise.h" +#include "PeerConnectionStates.h" + +namespace WebCore { + +class MediaStream; +class MediaStreamTrack; +class PeerConnectionBackend; +class RTCDataChannelHandler; +class RTCIceCandidate; +class RTCPeerConnection; +class RTCRtpReceiver; +class RTCRtpSender; +class RTCSessionDescription; +class RTCStatsReport; + +struct MediaEndpointConfiguration; +struct RTCAnswerOptions; +struct RTCDataChannelInit; +struct RTCOfferOptions; + +namespace PeerConnection { +using SessionDescriptionPromise = DOMPromise<IDLInterface<RTCSessionDescription>>; +using StatsPromise = DOMPromise<IDLInterface<RTCStatsReport>>; +} + +using CreatePeerConnectionBackend = std::unique_ptr<PeerConnectionBackend> (*)(RTCPeerConnection&); + +// FIXME: What is the value of this abstract class? There is only one concrete class derived from it. +class PeerConnectionBackend { +public: + WEBCORE_EXPORT static CreatePeerConnectionBackend create; + + PeerConnectionBackend(RTCPeerConnection& peerConnection) : m_peerConnection(peerConnection) { } + virtual ~PeerConnectionBackend() { } + + void createOffer(RTCOfferOptions&&, PeerConnection::SessionDescriptionPromise&&); + void createAnswer(RTCAnswerOptions&&, PeerConnection::SessionDescriptionPromise&&); + void setLocalDescription(RTCSessionDescription&, DOMPromise<void>&&); + void setRemoteDescription(RTCSessionDescription&, DOMPromise<void>&&); + void addIceCandidate(RTCIceCandidate&, DOMPromise<void>&&); + + virtual std::unique_ptr<RTCDataChannelHandler> createDataChannelHandler(const String&, const RTCDataChannelInit&) = 0; + + void stop(); + + virtual RefPtr<RTCSessionDescription> localDescription() const = 0; + virtual RefPtr<RTCSessionDescription> currentLocalDescription() const = 0; + virtual RefPtr<RTCSessionDescription> pendingLocalDescription() const = 0; + + virtual RefPtr<RTCSessionDescription> remoteDescription() const = 0; + virtual RefPtr<RTCSessionDescription> currentRemoteDescription() const = 0; + virtual RefPtr<RTCSessionDescription> pendingRemoteDescription() const = 0; + + virtual void setConfiguration(MediaEndpointConfiguration&&) = 0; + + virtual void getStats(MediaStreamTrack*, Ref<DeferredPromise>&&) = 0; + + virtual Vector<RefPtr<MediaStream>> getRemoteStreams() const = 0; + + virtual Ref<RTCRtpReceiver> createReceiver(const String& transceiverMid, const String& trackKind, const String& trackId) = 0; + virtual void replaceTrack(RTCRtpSender&, RefPtr<MediaStreamTrack>&&, DOMPromise<void>&&) = 0; + + void markAsNeedingNegotiation(); + bool isNegotiationNeeded() const { return m_negotiationNeeded; }; + void clearNegotiationNeededState() { m_negotiationNeeded = false; }; + + virtual void emulatePlatformEvent(const String& action) = 0; + +protected: + void fireICECandidateEvent(RefPtr<RTCIceCandidate>&&); + void doneGatheringCandidates(); + + void updateSignalingState(PeerConnectionStates::SignalingState); + + void createOfferSucceeded(String&&); + void createOfferFailed(Exception&&); + + void createAnswerSucceeded(String&&); + void createAnswerFailed(Exception&&); + + void setLocalDescriptionSucceeded(); + void setLocalDescriptionFailed(Exception&&); + + void setRemoteDescriptionSucceeded(); + void setRemoteDescriptionFailed(Exception&&); + + void addIceCandidateSucceeded(); + void addIceCandidateFailed(Exception&&); + +private: + virtual void doCreateOffer(RTCOfferOptions&&) = 0; + virtual void doCreateAnswer(RTCAnswerOptions&&) = 0; + virtual void doSetLocalDescription(RTCSessionDescription&) = 0; + virtual void doSetRemoteDescription(RTCSessionDescription&) = 0; + virtual void doAddIceCandidate(RTCIceCandidate&) = 0; + virtual void doStop() = 0; + +protected: + RTCPeerConnection& m_peerConnection; + +private: + std::optional<PeerConnection::SessionDescriptionPromise> m_offerAnswerPromise; + std::optional<DOMPromise<void>> m_setDescriptionPromise; + std::optional<DOMPromise<void>> m_addIceCandidatePromise; + + bool m_negotiationNeeded { false }; +}; + +} // namespace WebCore + +#endif // ENABLE(WEB_RTC) diff --git a/Source/WebCore/Modules/mediastream/RTCSessionDescriptionCallback.h b/Source/WebCore/Modules/mediastream/RTCConfiguration.h index 06ee071c4..2f06ea25a 100644 --- a/Source/WebCore/Modules/mediastream/RTCSessionDescriptionCallback.h +++ b/Source/WebCore/Modules/mediastream/RTCConfiguration.h @@ -28,25 +28,27 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef RTCSessionDescriptionCallback_h -#define RTCSessionDescriptionCallback_h +#pragma once -#if ENABLE(MEDIA_STREAM) +#if ENABLE(WEB_RTC) -#include <wtf/RefCounted.h> +#include "PeerConnectionStates.h" +#include "RTCIceServer.h" namespace WebCore { -class RTCSessionDescription; +using RTCIceTransportPolicy = PeerConnectionStates::IceTransportPolicy; +using RTCBundlePolicy = PeerConnectionStates::BundlePolicy; -class RTCSessionDescriptionCallback : public RefCounted<RTCSessionDescriptionCallback> { -public: - virtual ~RTCSessionDescriptionCallback() { } - virtual bool handleEvent(RTCSessionDescription*) = 0; +struct RTCConfiguration { + using IceTransportPolicy = RTCIceTransportPolicy; + using BundlePolicy = RTCBundlePolicy; + + std::optional<Vector<RTCIceServer>> iceServers; + IceTransportPolicy iceTransportPolicy; + BundlePolicy bundlePolicy; }; } // namespace WebCore -#endif // ENABLE(MEDIA_STREAM) - -#endif // RTCSessionDescriptionCallback_h +#endif // ENABLE(WEB_RTC) diff --git a/Source/WebCore/Modules/mediastream/AllAudioCapabilities.idl b/Source/WebCore/Modules/mediastream/RTCConfiguration.idl index dfb3a6e0c..3d2664dbc 100644 --- a/Source/WebCore/Modules/mediastream/AllAudioCapabilities.idl +++ b/Source/WebCore/Modules/mediastream/RTCConfiguration.idl @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 Apple Inc. All rights reserved. + * Copyright (C) 2014 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -10,24 +10,27 @@ * 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 * 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. + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +enum RTCIceTransportPolicy { "relay", "all" }; +enum RTCBundlePolicy { "balanced", "max-compat", "max-bundle" }; + [ - NoInterfaceObject, - Conditional=MEDIA_STREAM, + Conditional=WEB_RTC, JSGenerateToJSObject, -] interface AllAudioCapabilities : MediaStreamCapabilities { - readonly attribute DOMString[] sourceId; - readonly attribute CapabilityRange volume; +] dictionary RTCConfiguration { + sequence<RTCIceServer> iceServers; + RTCIceTransportPolicy iceTransportPolicy = "all"; + RTCBundlePolicy bundlePolicy = "balanced"; }; diff --git a/Source/WebCore/Modules/mediastream/RTCDTMFSender.cpp b/Source/WebCore/Modules/mediastream/RTCDTMFSender.cpp index 3167d9275..08eae7b70 100644 --- a/Source/WebCore/Modules/mediastream/RTCDTMFSender.cpp +++ b/Source/WebCore/Modules/mediastream/RTCDTMFSender.cpp @@ -24,50 +24,31 @@ */ #include "config.h" - -#if ENABLE(MEDIA_STREAM) - #include "RTCDTMFSender.h" -#include "ExceptionCode.h" +#if ENABLE(WEB_RTC) + #include "MediaStreamTrack.h" #include "RTCDTMFSenderHandler.h" #include "RTCDTMFToneChangeEvent.h" -#include "RTCPeerConnectionHandler.h" #include "ScriptExecutionContext.h" namespace WebCore { -static const long minToneDurationMs = 70; +static const long minToneDurationMs = 40; static const long defaultToneDurationMs = 100; static const long maxToneDurationMs = 6000; -static const long minInterToneGapMs = 50; -static const long defaultInterToneGapMs = 50; - -PassRefPtr<RTCDTMFSender> RTCDTMFSender::create(ScriptExecutionContext* context, RTCPeerConnectionHandler* peerConnectionHandler, PassRefPtr<MediaStreamTrack> prpTrack, ExceptionCode& ec) -{ - RefPtr<MediaStreamTrack> track = prpTrack; - std::unique_ptr<RTCDTMFSenderHandler> handler = peerConnectionHandler->createDTMFSender(track->source()); - if (!handler) { - ec = NOT_SUPPORTED_ERR; - return nullptr; - } - - RefPtr<RTCDTMFSender> dtmfSender = adoptRef(new RTCDTMFSender(context, track, std::move(handler))); - dtmfSender->suspendIfNeeded(); - return dtmfSender.release(); -} +static const long minInterToneGapMs = 30; +static const long defaultInterToneGapMs = 70; -RTCDTMFSender::RTCDTMFSender(ScriptExecutionContext* context, PassRefPtr<MediaStreamTrack> track, std::unique_ptr<RTCDTMFSenderHandler> handler) - : ActiveDOMObject(context) - , m_track(track) +RTCDTMFSender::RTCDTMFSender(ScriptExecutionContext& context, RefPtr<MediaStreamTrack>&& track) + : ActiveDOMObject(&context) + , m_track(WTFMove(track)) , m_duration(defaultToneDurationMs) , m_interToneGap(defaultInterToneGapMs) - , m_handler(std::move(handler)) , m_stopped(false) - , m_scheduledEventTimer(this, &RTCDTMFSender::scheduledEventTimerFired) + , m_scheduledEventTimer(*this, &RTCDTMFSender::scheduledEventTimerFired) { - m_handler->setClient(this); } RTCDTMFSender::~RTCDTMFSender() @@ -76,7 +57,7 @@ RTCDTMFSender::~RTCDTMFSender() bool RTCDTMFSender::canInsertDTMF() const { - return m_handler->canInsertDTMF(); + return false; } MediaStreamTrack* RTCDTMFSender::track() const @@ -86,41 +67,24 @@ MediaStreamTrack* RTCDTMFSender::track() const String RTCDTMFSender::toneBuffer() const { - return m_handler->currentToneBuffer(); + return { }; } -void RTCDTMFSender::insertDTMF(const String& tones, ExceptionCode& ec) +ExceptionOr<void> RTCDTMFSender::insertDTMF(const String&, std::optional<int> duration, std::optional<int> interToneGap) { - insertDTMF(tones, defaultToneDurationMs, defaultInterToneGapMs, ec); -} + if (!canInsertDTMF()) + return Exception { NOT_SUPPORTED_ERR }; -void RTCDTMFSender::insertDTMF(const String& tones, long duration, ExceptionCode& ec) -{ - insertDTMF(tones, duration, defaultInterToneGapMs, ec); -} + if (duration && (duration.value() > maxToneDurationMs || duration.value() < minToneDurationMs)) + return Exception { SYNTAX_ERR }; -void RTCDTMFSender::insertDTMF(const String& tones, long duration, long interToneGap, ExceptionCode& ec) -{ - if (!canInsertDTMF()) { - ec = NOT_SUPPORTED_ERR; - return; - } + if (interToneGap && interToneGap.value() < minInterToneGapMs) + return Exception { SYNTAX_ERR }; - if (duration > maxToneDurationMs || duration < minToneDurationMs) { - ec = SYNTAX_ERR; - return; - } - - if (interToneGap < minInterToneGapMs) { - ec = SYNTAX_ERR; - return; - } + m_duration = duration.value_or(defaultToneDurationMs); + m_interToneGap = interToneGap.value_or(defaultInterToneGapMs); - m_duration = duration; - m_interToneGap = interToneGap; - - if (!m_handler->insertDTMF(tones, m_duration, m_interToneGap)) - ec = SYNTAX_ERR; + return Exception { SYNTAX_ERR }; } void RTCDTMFSender::didPlayTone(const String& tone) @@ -131,30 +95,39 @@ void RTCDTMFSender::didPlayTone(const String& tone) void RTCDTMFSender::stop() { m_stopped = true; - m_handler->setClient(0); } -void RTCDTMFSender::scheduleDispatchEvent(PassRefPtr<Event> event) +const char* RTCDTMFSender::activeDOMObjectName() const +{ + return "RTCDTMFSender"; +} + +bool RTCDTMFSender::canSuspendForDocumentSuspension() const +{ + // FIXME: We should try and do better here. + return false; +} + +void RTCDTMFSender::scheduleDispatchEvent(Ref<Event>&& event) { - m_scheduledEvents.append(event); + m_scheduledEvents.append(WTFMove(event)); if (!m_scheduledEventTimer.isActive()) m_scheduledEventTimer.startOneShot(0); } -void RTCDTMFSender::scheduledEventTimerFired(Timer<RTCDTMFSender>*) +void RTCDTMFSender::scheduledEventTimerFired() { if (m_stopped) return; - Vector<RefPtr<Event>> events; + Vector<Ref<Event>> events; events.swap(m_scheduledEvents); - Vector<RefPtr<Event>>::iterator it = events.begin(); - for (; it != events.end(); ++it) - dispatchEvent((*it).release()); + for (auto& event : events) + dispatchEvent(event); } } // namespace WebCore -#endif // ENABLE(MEDIA_STREAM) +#endif // ENABLE(WEB_RTC) diff --git a/Source/WebCore/Modules/mediastream/RTCDTMFSender.h b/Source/WebCore/Modules/mediastream/RTCDTMFSender.h index 0e6b49d32..c67b3a164 100644 --- a/Source/WebCore/Modules/mediastream/RTCDTMFSender.h +++ b/Source/WebCore/Modules/mediastream/RTCDTMFSender.h @@ -23,78 +23,63 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef RTCDTMFSender_h -#define RTCDTMFSender_h +#pragma once -#if ENABLE(MEDIA_STREAM) +#if ENABLE(WEB_RTC) #include "ActiveDOMObject.h" #include "EventTarget.h" -#include "RTCDTMFSenderHandlerClient.h" +#include "ExceptionOr.h" #include "ScriptWrappable.h" #include "Timer.h" -#include <wtf/RefCounted.h> namespace WebCore { class MediaStreamTrack; -class RTCPeerConnectionHandler; -class RTCDTMFSenderHandler; -class RTCDTMFSender final : public RefCounted<RTCDTMFSender>, public ScriptWrappable, public EventTargetWithInlineData, public RTCDTMFSenderHandlerClient, public ActiveDOMObject { +class RTCDTMFSender final : public RefCounted<RTCDTMFSender>, public EventTargetWithInlineData, public ActiveDOMObject { public: - static PassRefPtr<RTCDTMFSender> create(ScriptExecutionContext*, RTCPeerConnectionHandler*, PassRefPtr<MediaStreamTrack>, ExceptionCode&); - ~RTCDTMFSender(); + virtual ~RTCDTMFSender(); bool canInsertDTMF() const; MediaStreamTrack* track() const; String toneBuffer() const; - long duration() const { return m_duration; } - long interToneGap() const { return m_interToneGap; } + int duration() const { return m_duration; } + int interToneGap() const { return m_interToneGap; } - void insertDTMF(const String& tones, ExceptionCode&); - void insertDTMF(const String& tones, long duration, ExceptionCode&); - void insertDTMF(const String& tones, long duration, long interToneGap, ExceptionCode&); + ExceptionOr<void> insertDTMF(const String& tones, std::optional<int> duration, std::optional<int> interToneGap); - DEFINE_ATTRIBUTE_EVENT_LISTENER(tonechange); + using RefCounted::ref; + using RefCounted::deref; - // EventTarget - virtual EventTargetInterface eventTargetInterface() const override { return RTCDTMFSenderEventTargetInterfaceType; } - virtual ScriptExecutionContext* scriptExecutionContext() const override { return ActiveDOMObject::scriptExecutionContext(); } - - // ActiveDOMObject - virtual void stop() override; +private: + RTCDTMFSender(ScriptExecutionContext&, RefPtr<MediaStreamTrack>&&); - using RefCounted<RTCDTMFSender>::ref; - using RefCounted<RTCDTMFSender>::deref; + void stop() final; + const char* activeDOMObjectName() const final; + bool canSuspendForDocumentSuspension() const final; -private: - RTCDTMFSender(ScriptExecutionContext*, PassRefPtr<MediaStreamTrack>, std::unique_ptr<RTCDTMFSenderHandler>); + EventTargetInterface eventTargetInterface() const final { return RTCDTMFSenderEventTargetInterfaceType; } + ScriptExecutionContext* scriptExecutionContext() const final { return ActiveDOMObject::scriptExecutionContext(); } - void scheduleDispatchEvent(PassRefPtr<Event>); - void scheduledEventTimerFired(Timer<RTCDTMFSender>*); + void refEventTarget() final { ref(); } + void derefEventTarget() final { deref(); } - // EventTarget - virtual void refEventTarget() override { ref(); } - virtual void derefEventTarget() override { deref(); } + void didPlayTone(const String&); - // RTCDTMFSenderHandlerClient - virtual void didPlayTone(const String&) override; + void scheduleDispatchEvent(Ref<Event>&&); + void scheduledEventTimerFired(); RefPtr<MediaStreamTrack> m_track; - long m_duration; - long m_interToneGap; - - std::unique_ptr<RTCDTMFSenderHandler> m_handler; + int m_duration; + int m_interToneGap; bool m_stopped; - Timer<RTCDTMFSender> m_scheduledEventTimer; - Vector<RefPtr<Event>> m_scheduledEvents; + Timer m_scheduledEventTimer; + Vector<Ref<Event>> m_scheduledEvents; }; } // namespace WebCore -#endif // ENABLE(MEDIA_STREAM) - -#endif // RTCDTMFSender_h +#endif // ENABLE(WEB_RTC) diff --git a/Source/WebCore/Modules/mediastream/RTCDTMFSender.idl b/Source/WebCore/Modules/mediastream/RTCDTMFSender.idl index f4fb77158..fea23bda9 100644 --- a/Source/WebCore/Modules/mediastream/RTCDTMFSender.idl +++ b/Source/WebCore/Modules/mediastream/RTCDTMFSender.idl @@ -24,27 +24,17 @@ */ [ - NoInterfaceObject, - Conditional=MEDIA_STREAM, ActiveDOMObject, - EventTarget, -] interface RTCDTMFSender { + Conditional=WEB_RTC, + NoInterfaceObject, +] interface RTCDTMFSender : EventTarget { readonly attribute boolean canInsertDTMF; readonly attribute MediaStreamTrack track; readonly attribute DOMString toneBuffer; readonly attribute long duration; readonly attribute long interToneGap; - [RaisesException] void insertDTMF(DOMString tones, optional long duration, optional long interToneGap); - - attribute EventListener ontonechange; + [MayThrowException] void insertDTMF(DOMString tones, optional long duration, optional long interToneGap); - // EventTarget interface - void addEventListener(DOMString type, - EventListener listener, - optional boolean useCapture); - void removeEventListener(DOMString type, - EventListener listener, - optional boolean useCapture); - [RaisesException] boolean dispatchEvent(Event event); + attribute EventHandler ontonechange; }; diff --git a/Source/WebCore/Modules/mediastream/RTCDTMFToneChangeEvent.cpp b/Source/WebCore/Modules/mediastream/RTCDTMFToneChangeEvent.cpp index 526ef2c6b..d6ff9fda8 100644 --- a/Source/WebCore/Modules/mediastream/RTCDTMFToneChangeEvent.cpp +++ b/Source/WebCore/Modules/mediastream/RTCDTMFToneChangeEvent.cpp @@ -26,30 +26,20 @@ #include "config.h" #include "RTCDTMFToneChangeEvent.h" -#if ENABLE(MEDIA_STREAM) +#if ENABLE(WEB_RTC) #include "EventNames.h" namespace WebCore { -PassRefPtr<RTCDTMFToneChangeEvent> RTCDTMFToneChangeEvent::create() +Ref<RTCDTMFToneChangeEvent> RTCDTMFToneChangeEvent::create(const String& tone) { - return adoptRef(new RTCDTMFToneChangeEvent); + return adoptRef(*new RTCDTMFToneChangeEvent(tone)); } -PassRefPtr<RTCDTMFToneChangeEvent> RTCDTMFToneChangeEvent::create(const String& tone) -{ - return adoptRef(new RTCDTMFToneChangeEvent(tone)); -} - -PassRefPtr<RTCDTMFToneChangeEvent> RTCDTMFToneChangeEvent::create(const AtomicString& type, const RTCDTMFToneChangeEventInit& initializer) -{ - ASSERT_UNUSED(type, type == eventNames().tonechangeEvent); - return adoptRef(new RTCDTMFToneChangeEvent(initializer)); -} - -RTCDTMFToneChangeEvent::RTCDTMFToneChangeEvent() +Ref<RTCDTMFToneChangeEvent> RTCDTMFToneChangeEvent::create(const AtomicString& type, const Init& initializer, IsTrusted isTrusted) { + return adoptRef(*new RTCDTMFToneChangeEvent(type, initializer, isTrusted)); } RTCDTMFToneChangeEvent::RTCDTMFToneChangeEvent(const String& tone) @@ -58,8 +48,8 @@ RTCDTMFToneChangeEvent::RTCDTMFToneChangeEvent(const String& tone) { } -RTCDTMFToneChangeEvent::RTCDTMFToneChangeEvent(const RTCDTMFToneChangeEventInit& initializer) - : Event(eventNames().tonechangeEvent, initializer) +RTCDTMFToneChangeEvent::RTCDTMFToneChangeEvent(const AtomicString& type, const Init& initializer, IsTrusted isTrusted) + : Event(type, initializer, isTrusted) , m_tone(initializer.tone) { } @@ -80,5 +70,5 @@ EventInterface RTCDTMFToneChangeEvent::eventInterface() const } // namespace WebCore -#endif // ENABLE(MEDIA_STREAM) +#endif // ENABLE(WEB_RTC) diff --git a/Source/WebCore/Modules/mediastream/RTCDTMFToneChangeEvent.h b/Source/WebCore/Modules/mediastream/RTCDTMFToneChangeEvent.h index 0693db694..112d529a5 100644 --- a/Source/WebCore/Modules/mediastream/RTCDTMFToneChangeEvent.h +++ b/Source/WebCore/Modules/mediastream/RTCDTMFToneChangeEvent.h @@ -23,42 +23,38 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef RTCDTMFToneChangeEvent_h -#define RTCDTMFToneChangeEvent_h +#pragma once -#if ENABLE(MEDIA_STREAM) +#if ENABLE(WEB_RTC) #include "Event.h" #include <wtf/text/AtomicString.h> namespace WebCore { -struct RTCDTMFToneChangeEventInit : public EventInit { - String tone; -}; - class RTCDTMFToneChangeEvent : public Event { public: virtual ~RTCDTMFToneChangeEvent(); - static PassRefPtr<RTCDTMFToneChangeEvent> create(); - static PassRefPtr<RTCDTMFToneChangeEvent> create(const String& tone); - static PassRefPtr<RTCDTMFToneChangeEvent> create(const AtomicString& type, const RTCDTMFToneChangeEventInit& initializer); + static Ref<RTCDTMFToneChangeEvent> create(const String& tone); + + struct Init : EventInit { + String tone; + }; + + static Ref<RTCDTMFToneChangeEvent> create(const AtomicString& type, const Init&, IsTrusted = IsTrusted::No); const String& tone() const; virtual EventInterface eventInterface() const; private: - RTCDTMFToneChangeEvent(); explicit RTCDTMFToneChangeEvent(const String& tone); - explicit RTCDTMFToneChangeEvent(const RTCDTMFToneChangeEventInit&); + RTCDTMFToneChangeEvent(const AtomicString& type, const Init&, IsTrusted); String m_tone; }; } // namespace WebCore -#endif // ENABLE(MEDIA_STREAM) - -#endif // RTCDTMFToneChangeEvent_h +#endif // ENABLE(WEB_RTC) diff --git a/Source/WebCore/Modules/mediastream/RTCDTMFToneChangeEvent.idl b/Source/WebCore/Modules/mediastream/RTCDTMFToneChangeEvent.idl index 1edebd33e..722df3cf7 100644 --- a/Source/WebCore/Modules/mediastream/RTCDTMFToneChangeEvent.idl +++ b/Source/WebCore/Modules/mediastream/RTCDTMFToneChangeEvent.idl @@ -24,9 +24,13 @@ */ [ - NoInterfaceObject, - Conditional=MEDIA_STREAM, - ConstructorTemplate=Event + Conditional=WEB_RTC, + Constructor(DOMString type, optional RTCDTMFToneChangeEventInit eventInitDict), + EnabledAtRuntime=PeerConnection, ] interface RTCDTMFToneChangeEvent : Event { - [InitializedByEventConstructor] readonly attribute DOMString tone; + readonly attribute DOMString tone; +}; + +dictionary RTCDTMFToneChangeEventInit : EventInit { + DOMString tone = ""; }; diff --git a/Source/WebCore/Modules/mediastream/RTCDataChannel.cpp b/Source/WebCore/Modules/mediastream/RTCDataChannel.cpp index 4e876bb7e..76723e4ee 100644 --- a/Source/WebCore/Modules/mediastream/RTCDataChannel.cpp +++ b/Source/WebCore/Modules/mediastream/RTCDataChannel.cpp @@ -23,18 +23,16 @@ */ #include "config.h" - -#if ENABLE(MEDIA_STREAM) - #include "RTCDataChannel.h" +#if ENABLE(WEB_RTC) + #include "Blob.h" -#include "Dictionary.h" #include "Event.h" +#include "EventNames.h" #include "ExceptionCode.h" #include "MessageEvent.h" #include "RTCDataChannelHandler.h" -#include "RTCPeerConnectionHandler.h" #include "ScriptExecutionContext.h" #include <runtime/ArrayBuffer.h> #include <runtime/ArrayBufferView.h> @@ -54,87 +52,30 @@ static const AtomicString& arraybufferKeyword() return arraybuffer; } -PassRefPtr<RTCDataChannel> RTCDataChannel::create(ScriptExecutionContext* context, RTCPeerConnectionHandler* peerConnectionHandler, const String& label, const Dictionary& options, ExceptionCode& ec) -{ - RTCDataChannelInit initData; - options.get("ordered", initData.ordered); - options.get("negotiated", initData.negotiated); - options.get("id", initData.id); - options.get("maxRetransmits", initData.maxRetransmits); - options.get("maxRetransmitTime", initData.maxRetransmitTime); - options.get("protocol", initData.protocol); - - std::unique_ptr<RTCDataChannelHandler> handler = peerConnectionHandler->createDataChannel(label, initData); - if (!handler) { - ec = NOT_SUPPORTED_ERR; - return nullptr; - } - return adoptRef(new RTCDataChannel(context, std::move(handler))); -} - -PassRefPtr<RTCDataChannel> RTCDataChannel::create(ScriptExecutionContext* context, std::unique_ptr<RTCDataChannelHandler> handler) +Ref<RTCDataChannel> RTCDataChannel::create(ScriptExecutionContext& context, std::unique_ptr<RTCDataChannelHandler>&& handler, String&& label, RTCDataChannelInit&& options) { ASSERT(handler); - return adoptRef(new RTCDataChannel(context, std::move(handler))); -} - -RTCDataChannel::RTCDataChannel(ScriptExecutionContext* context, std::unique_ptr<RTCDataChannelHandler> handler) - : m_scriptExecutionContext(context) - , m_handler(std::move(handler)) - , m_stopped(false) - , m_readyState(ReadyStateConnecting) - , m_binaryType(BinaryTypeArrayBuffer) - , m_scheduledEventTimer(this, &RTCDataChannel::scheduledEventTimerFired) -{ - m_handler->setClient(this); -} - -RTCDataChannel::~RTCDataChannel() -{ -} - -String RTCDataChannel::label() const -{ - return m_handler->label(); -} - -bool RTCDataChannel::ordered() const -{ - return m_handler->ordered(); -} - -unsigned short RTCDataChannel::maxRetransmitTime() const -{ - return m_handler->maxRetransmitTime(); -} - -unsigned short RTCDataChannel::maxRetransmits() const -{ -return m_handler->maxRetransmits(); -} - -String RTCDataChannel::protocol() const -{ - return m_handler->protocol(); -} - -bool RTCDataChannel::negotiated() const -{ - return m_handler->negotiated(); + auto channel = adoptRef(*new RTCDataChannel(context, WTFMove(handler), WTFMove(label), WTFMove(options))); + channel->m_handler->setClient(&channel.get()); + return channel; } -unsigned short RTCDataChannel::id() const +RTCDataChannel::RTCDataChannel(ScriptExecutionContext& context, std::unique_ptr<RTCDataChannelHandler>&& handler, String&& label, RTCDataChannelInit&& options) + : m_scriptExecutionContext(&context) + , m_handler(WTFMove(handler)) + , m_scheduledEventTimer(*this, &RTCDataChannel::scheduledEventTimerFired) + , m_label(WTFMove(label)) + , m_options(WTFMove(options)) { - return m_handler->id(); } -AtomicString RTCDataChannel::readyState() const +const AtomicString& RTCDataChannel::readyState() const { static NeverDestroyed<AtomicString> connectingState("connecting", AtomicString::ConstructFromLiteral); static NeverDestroyed<AtomicString> openState("open", AtomicString::ConstructFromLiteral); static NeverDestroyed<AtomicString> closingState("closing", AtomicString::ConstructFromLiteral); static NeverDestroyed<AtomicString> closedState("closed", AtomicString::ConstructFromLiteral); - + switch (m_readyState) { case ReadyStateConnecting: return connectingState; @@ -150,17 +91,17 @@ AtomicString RTCDataChannel::readyState() const return emptyAtom; } -unsigned long RTCDataChannel::bufferedAmount() const +size_t RTCDataChannel::bufferedAmount() const { return m_handler->bufferedAmount(); } -AtomicString RTCDataChannel::binaryType() const +const AtomicString& RTCDataChannel::binaryType() const { switch (m_binaryType) { - case BinaryTypeBlob: + case BinaryType::Blob: return blobKeyword(); - case BinaryTypeArrayBuffer: + case BinaryType::ArrayBuffer: return arraybufferKeyword(); } @@ -168,60 +109,58 @@ AtomicString RTCDataChannel::binaryType() const return emptyAtom; } -void RTCDataChannel::setBinaryType(const AtomicString& binaryType, ExceptionCode& ec) +ExceptionOr<void> RTCDataChannel::setBinaryType(const AtomicString& binaryType) { if (binaryType == blobKeyword()) - ec = NOT_SUPPORTED_ERR; - else if (binaryType == arraybufferKeyword()) - m_binaryType = BinaryTypeArrayBuffer; - else - ec = TYPE_MISMATCH_ERR; + return Exception { NOT_SUPPORTED_ERR }; + if (binaryType == arraybufferKeyword()) { + m_binaryType = BinaryType::ArrayBuffer; + return { }; + } + return Exception { TYPE_MISMATCH_ERR }; } -void RTCDataChannel::send(const String& data, ExceptionCode& ec) +ExceptionOr<void> RTCDataChannel::send(const String& data) { - if (m_readyState != ReadyStateOpen) { - ec = INVALID_STATE_ERR; - return; - } + if (m_readyState != ReadyStateOpen) + return Exception { INVALID_STATE_ERR }; if (!m_handler->sendStringData(data)) { // FIXME: Decide what the right exception here is. - ec = SYNTAX_ERR; + return Exception { SYNTAX_ERR }; } + + return { }; } -void RTCDataChannel::send(PassRefPtr<ArrayBuffer> prpData, ExceptionCode& ec) +ExceptionOr<void> RTCDataChannel::send(ArrayBuffer& data) { - if (m_readyState != ReadyStateOpen) { - ec = INVALID_STATE_ERR; - return; - } - - RefPtr<ArrayBuffer> data = prpData; + if (m_readyState != ReadyStateOpen) + return Exception { INVALID_STATE_ERR }; - size_t dataLength = data->byteLength(); + size_t dataLength = data.byteLength(); if (!dataLength) - return; + return { }; - const char* dataPointer = static_cast<const char*>(data->data()); + const char* dataPointer = static_cast<const char*>(data.data()); if (!m_handler->sendRawData(dataPointer, dataLength)) { // FIXME: Decide what the right exception here is. - ec = SYNTAX_ERR; + return Exception { SYNTAX_ERR }; } + + return { }; } -void RTCDataChannel::send(PassRefPtr<ArrayBufferView> data, ExceptionCode& ec) +ExceptionOr<void> RTCDataChannel::send(ArrayBufferView& data) { - RefPtr<ArrayBuffer> arrayBuffer(data->buffer()); - send(arrayBuffer.release(), ec); + return send(*data.unsharedBuffer()); } -void RTCDataChannel::send(PassRefPtr<Blob>, ExceptionCode& ec) +ExceptionOr<void> RTCDataChannel::send(Blob&) { - // FIXME: implement - ec = NOT_SUPPORTED_ERR; + // FIXME: Implement. + return Exception { NOT_SUPPORTED_ERR }; } void RTCDataChannel::close() @@ -264,14 +203,13 @@ void RTCDataChannel::didReceiveRawData(const char* data, size_t dataLength) if (m_stopped) return; - if (m_binaryType == BinaryTypeBlob) { + if (m_binaryType == BinaryType::Blob) { // FIXME: Implement. return; } - if (m_binaryType == BinaryTypeArrayBuffer) { - RefPtr<ArrayBuffer> buffer = ArrayBuffer::create(data, dataLength); - scheduleDispatchEvent(MessageEvent::create(buffer.release())); + if (m_binaryType == BinaryType::ArrayBuffer) { + scheduleDispatchEvent(MessageEvent::create(ArrayBuffer::create(data, dataLength))); return; } ASSERT_NOT_REACHED(); @@ -285,37 +223,43 @@ void RTCDataChannel::didDetectError() scheduleDispatchEvent(Event::create(eventNames().errorEvent, false, false)); } +void RTCDataChannel::bufferedAmountIsDecreasing() +{ + if (m_stopped) + return; + + if (bufferedAmount() <= m_bufferedAmountLowThreshold) + scheduleDispatchEvent(Event::create(eventNames().bufferedAmountLowThresholdEvent, false, false)); +} + void RTCDataChannel::stop() { m_stopped = true; m_readyState = ReadyStateClosed; - m_handler->setClient(0); - m_scriptExecutionContext = 0; + m_handler->setClient(nullptr); + m_scriptExecutionContext = nullptr; } -void RTCDataChannel::scheduleDispatchEvent(PassRefPtr<Event> event) +void RTCDataChannel::scheduleDispatchEvent(Ref<Event>&& event) { - m_scheduledEvents.append(event); + m_scheduledEvents.append(WTFMove(event)); if (!m_scheduledEventTimer.isActive()) m_scheduledEventTimer.startOneShot(0); } -void RTCDataChannel::scheduledEventTimerFired(Timer<RTCDataChannel>*) +void RTCDataChannel::scheduledEventTimerFired() { if (m_stopped) return; - Vector<RefPtr<Event>> events; + Vector<Ref<Event>> events; events.swap(m_scheduledEvents); - Vector<RefPtr<Event>>::iterator it = events.begin(); - for (; it != events.end(); ++it) - dispatchEvent((*it).release()); - - events.clear(); + for (auto& event : events) + dispatchEvent(event); } } // namespace WebCore -#endif // ENABLE(MEDIA_STREAM) +#endif // ENABLE(WEB_RTC) diff --git a/Source/WebCore/Modules/mediastream/RTCDataChannel.h b/Source/WebCore/Modules/mediastream/RTCDataChannel.h index 54a21d441..cd860f184 100644 --- a/Source/WebCore/Modules/mediastream/RTCDataChannel.h +++ b/Source/WebCore/Modules/mediastream/RTCDataChannel.h @@ -22,16 +22,17 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef RTCDataChannel_h -#define RTCDataChannel_h +#pragma once -#if ENABLE(MEDIA_STREAM) +#if ENABLE(WEB_RTC) +#include "Event.h" #include "EventTarget.h" +#include "ExceptionOr.h" +#include "RTCDataChannelHandler.h" #include "RTCDataChannelHandlerClient.h" #include "ScriptWrappable.h" #include "Timer.h" -#include <wtf/RefCounted.h> namespace JSC { class ArrayBuffer; @@ -41,85 +42,78 @@ namespace JSC { namespace WebCore { class Blob; -class Dictionary; -class RTCDataChannelHandler; class RTCPeerConnectionHandler; -class RTCDataChannel final : public RefCounted<RTCDataChannel>, public ScriptWrappable, public EventTargetWithInlineData, public RTCDataChannelHandlerClient { +class RTCDataChannel final : public RTCDataChannelHandlerClient, public EventTargetWithInlineData { public: - static PassRefPtr<RTCDataChannel> create(ScriptExecutionContext*, std::unique_ptr<RTCDataChannelHandler>); - static PassRefPtr<RTCDataChannel> create(ScriptExecutionContext*, RTCPeerConnectionHandler*, const String& , const Dictionary&, ExceptionCode&); - ~RTCDataChannel(); - - String label() const; - bool ordered() const; - unsigned short maxRetransmitTime() const; - unsigned short maxRetransmits() const; - String protocol() const; - bool negotiated() const; - unsigned short id() const; - AtomicString readyState() const; - unsigned long bufferedAmount() const; - - AtomicString binaryType() const; - void setBinaryType(const AtomicString&, ExceptionCode&); - - void send(const String&, ExceptionCode&); - void send(PassRefPtr<JSC::ArrayBuffer>, ExceptionCode&); - void send(PassRefPtr<JSC::ArrayBufferView>, ExceptionCode&); - void send(PassRefPtr<Blob>, ExceptionCode&); + static Ref<RTCDataChannel> create(ScriptExecutionContext&, std::unique_ptr<RTCDataChannelHandler>&&, String&&, RTCDataChannelInit&&); - void close(); + bool ordered() const { return m_options.ordered; } + unsigned short maxRetransmitTime() const { return m_options.maxRetransmitTime; } + unsigned short maxRetransmits() const { return m_options.maxRetransmits; } + String protocol() const { return m_options.protocol; } + bool negotiated() const { return m_options.negotiated; }; + unsigned short id() const { return m_options.id; }; - DEFINE_ATTRIBUTE_EVENT_LISTENER(open); - DEFINE_ATTRIBUTE_EVENT_LISTENER(error); - DEFINE_ATTRIBUTE_EVENT_LISTENER(close); - DEFINE_ATTRIBUTE_EVENT_LISTENER(message); + String label() const { return m_label; } + const AtomicString& readyState() const; + size_t bufferedAmount() const; + size_t bufferedAmountLowThreshold() const { return m_bufferedAmountLowThreshold; } + void setBufferedAmountLowThreshold(size_t value) { m_bufferedAmountLowThreshold = value; } - void stop(); + const AtomicString& binaryType() const; + ExceptionOr<void> setBinaryType(const AtomicString&); + + ExceptionOr<void> send(const String&); + ExceptionOr<void> send(JSC::ArrayBuffer&); + ExceptionOr<void> send(JSC::ArrayBufferView&); + ExceptionOr<void> send(Blob&); + + void close(); - // EventTarget - virtual EventTargetInterface eventTargetInterface() const override { return RTCDataChannelEventTargetInterfaceType; } - virtual ScriptExecutionContext* scriptExecutionContext() const override { return m_scriptExecutionContext; } + void stop(); - using RefCounted<RTCDataChannel>::ref; - using RefCounted<RTCDataChannel>::deref; + using RTCDataChannelHandlerClient::ref; + using RTCDataChannelHandlerClient::deref; private: - RTCDataChannel(ScriptExecutionContext*, std::unique_ptr<RTCDataChannelHandler>); + RTCDataChannel(ScriptExecutionContext&, std::unique_ptr<RTCDataChannelHandler>&&, String&&, RTCDataChannelInit&&); + + void scheduleDispatchEvent(Ref<Event>&&); + void scheduledEventTimerFired(); - void scheduleDispatchEvent(PassRefPtr<Event>); - void scheduledEventTimerFired(Timer<RTCDataChannel>*); + EventTargetInterface eventTargetInterface() const final { return RTCDataChannelEventTargetInterfaceType; } + ScriptExecutionContext* scriptExecutionContext() const final { return m_scriptExecutionContext; } - // EventTarget - virtual void refEventTarget() override { ref(); } - virtual void derefEventTarget() override { deref(); } + void refEventTarget() final { ref(); } + void derefEventTarget() final { deref(); } ScriptExecutionContext* m_scriptExecutionContext; - // RTCDataChannelHandlerClient - virtual void didChangeReadyState(ReadyState) override; - virtual void didReceiveStringData(const String&) override; - virtual void didReceiveRawData(const char*, size_t) override; - virtual void didDetectError() override; + // RTCDataChannelHandlerClient API + void didChangeReadyState(ReadyState) final; + void didReceiveStringData(const String&) final; + void didReceiveRawData(const char*, size_t) final; + void didDetectError() final; + void bufferedAmountIsDecreasing() final; std::unique_ptr<RTCDataChannelHandler> m_handler; - bool m_stopped; + bool m_stopped { false }; + + ReadyState m_readyState { ReadyStateConnecting }; - ReadyState m_readyState; - enum BinaryType { - BinaryTypeBlob, - BinaryTypeArrayBuffer - }; - BinaryType m_binaryType; + enum class BinaryType { Blob, ArrayBuffer }; + BinaryType m_binaryType { BinaryType::ArrayBuffer }; - Timer<RTCDataChannel> m_scheduledEventTimer; - Vector<RefPtr<Event>> m_scheduledEvents; + Timer m_scheduledEventTimer; + Vector<Ref<Event>> m_scheduledEvents; + + String m_label; + RTCDataChannelInit m_options; + size_t m_bufferedAmountLowThreshold { 0 }; }; } // namespace WebCore -#endif // ENABLE(MEDIA_STREAM) - -#endif // RTCDataChannel_h +#endif // ENABLE(WEB_RTC) diff --git a/Source/WebCore/Modules/mediastream/RTCDataChannel.idl b/Source/WebCore/Modules/mediastream/RTCDataChannel.idl index 19c24fa1b..e778c0f96 100644 --- a/Source/WebCore/Modules/mediastream/RTCDataChannel.idl +++ b/Source/WebCore/Modules/mediastream/RTCDataChannel.idl @@ -23,10 +23,9 @@ */ [ + Conditional=WEB_RTC, NoInterfaceObject, - Conditional=MEDIA_STREAM, - EventTarget, -] interface RTCDataChannel { +] interface RTCDataChannel : EventTarget { readonly attribute DOMString label; readonly attribute boolean ordered; readonly attribute unsigned short maxRetransmitTime; @@ -37,26 +36,17 @@ readonly attribute DOMString readyState; readonly attribute unsigned long bufferedAmount; - [SetterRaisesException] attribute DOMString binaryType; + [SetterMayThrowException] attribute DOMString binaryType; - [RaisesException] void send(ArrayBuffer data); - [RaisesException] void send(ArrayBufferView data); - [RaisesException] void send(Blob data); - [RaisesException] void send(DOMString data); + [MayThrowException] void send(ArrayBuffer data); + [MayThrowException] void send(ArrayBufferView data); + [MayThrowException] void send(Blob data); + [MayThrowException] void send(DOMString data); void close(); - attribute EventListener onopen; - attribute EventListener onerror; - attribute EventListener onclose; - attribute EventListener onmessage; - - // EventTarget interface - void addEventListener(DOMString type, - EventListener listener, - optional boolean useCapture); - void removeEventListener(DOMString type, - EventListener listener, - optional boolean useCapture); - [RaisesException] boolean dispatchEvent(Event event); + attribute EventHandler onopen; + attribute EventHandler onerror; + attribute EventHandler onclose; + attribute EventHandler onmessage; }; diff --git a/Source/WebCore/Modules/mediastream/RTCDataChannelEvent.cpp b/Source/WebCore/Modules/mediastream/RTCDataChannelEvent.cpp index 136581384..17f81aa34 100644 --- a/Source/WebCore/Modules/mediastream/RTCDataChannelEvent.cpp +++ b/Source/WebCore/Modules/mediastream/RTCDataChannelEvent.cpp @@ -25,41 +25,26 @@ #include "config.h" #include "RTCDataChannelEvent.h" -#if ENABLE(MEDIA_STREAM) +#if ENABLE(WEB_RTC) -#include "EventNames.h" #include "RTCDataChannel.h" namespace WebCore { -PassRefPtr<RTCDataChannelEvent> RTCDataChannelEvent::create() +Ref<RTCDataChannelEvent> RTCDataChannelEvent::create(const AtomicString& type, bool canBubble, bool cancelable, Ref<RTCDataChannel>&& channel) { - return adoptRef(new RTCDataChannelEvent); + return adoptRef(*new RTCDataChannelEvent(type, canBubble, cancelable, WTFMove(channel))); } -PassRefPtr<RTCDataChannelEvent> RTCDataChannelEvent::create(const AtomicString& type, bool canBubble, bool cancelable, PassRefPtr<RTCDataChannel> channel) -{ - return adoptRef(new RTCDataChannelEvent(type, canBubble, cancelable, channel)); -} - - -RTCDataChannelEvent::RTCDataChannelEvent() -{ -} - -RTCDataChannelEvent::RTCDataChannelEvent(const AtomicString& type, bool canBubble, bool cancelable, PassRefPtr<RTCDataChannel> channel) +RTCDataChannelEvent::RTCDataChannelEvent(const AtomicString& type, bool canBubble, bool cancelable, Ref<RTCDataChannel>&& channel) : Event(type, canBubble, cancelable) - , m_channel(channel) -{ -} - -RTCDataChannelEvent::~RTCDataChannelEvent() + , m_channel(WTFMove(channel)) { } -RTCDataChannel* RTCDataChannelEvent::channel() const +RTCDataChannel* RTCDataChannelEvent::channel() { - return m_channel.get(); + return m_channel.ptr(); } EventInterface RTCDataChannelEvent::eventInterface() const @@ -69,5 +54,5 @@ EventInterface RTCDataChannelEvent::eventInterface() const } // namespace WebCore -#endif // ENABLE(MEDIA_STREAM) +#endif // ENABLE(WEB_RTC) diff --git a/Source/WebCore/Modules/mediastream/RTCDataChannelEvent.h b/Source/WebCore/Modules/mediastream/RTCDataChannelEvent.h index 41b003610..5241e2790 100644 --- a/Source/WebCore/Modules/mediastream/RTCDataChannelEvent.h +++ b/Source/WebCore/Modules/mediastream/RTCDataChannelEvent.h @@ -22,10 +22,9 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef RTCDataChannelEvent_h -#define RTCDataChannelEvent_h +#pragma once -#if ENABLE(MEDIA_STREAM) +#if ENABLE(WEB_RTC) #include "Event.h" #include "RTCDataChannel.h" @@ -35,24 +34,18 @@ namespace WebCore { class RTCDataChannelEvent : public Event { public: - virtual ~RTCDataChannelEvent(); + static Ref<RTCDataChannelEvent> create(const AtomicString& type, bool canBubble, bool cancelable, Ref<RTCDataChannel>&&); - static PassRefPtr<RTCDataChannelEvent> create(); - static PassRefPtr<RTCDataChannelEvent> create(const AtomicString& type, bool canBubble, bool cancelable, PassRefPtr<RTCDataChannel>); - - RTCDataChannel* channel() const; + RTCDataChannel* channel(); virtual EventInterface eventInterface() const; private: - RTCDataChannelEvent(); - RTCDataChannelEvent(const AtomicString& type, bool canBubble, bool cancelable, PassRefPtr<RTCDataChannel>); + RTCDataChannelEvent(const AtomicString& type, bool canBubble, bool cancelable, Ref<RTCDataChannel>&&); - RefPtr<RTCDataChannel> m_channel; + Ref<RTCDataChannel> m_channel; }; } // namespace WebCore -#endif // ENABLE(MEDIA_STREAM) - -#endif // RTCDataChannelEvent_h +#endif // ENABLE(WEB_RTC) diff --git a/Source/WebCore/Modules/mediastream/RTCDataChannelEvent.idl b/Source/WebCore/Modules/mediastream/RTCDataChannelEvent.idl index 946337594..1dc11f986 100644 --- a/Source/WebCore/Modules/mediastream/RTCDataChannelEvent.idl +++ b/Source/WebCore/Modules/mediastream/RTCDataChannelEvent.idl @@ -24,7 +24,7 @@ [ NoInterfaceObject, - Conditional=MEDIA_STREAM, + Conditional=WEB_RTC, ] interface RTCDataChannelEvent : Event { readonly attribute RTCDataChannel channel; }; diff --git a/Source/WebCore/Modules/mediastream/RTCIceCandidate.cpp b/Source/WebCore/Modules/mediastream/RTCIceCandidate.cpp index 353e309dd..2c7e0d364 100644 --- a/Source/WebCore/Modules/mediastream/RTCIceCandidate.cpp +++ b/Source/WebCore/Modules/mediastream/RTCIceCandidate.cpp @@ -1,6 +1,7 @@ /* * Copyright (C) 2012 Google Inc. All rights reserved. * Copyright (C) 2013 Nokia Corporation and/or its subsidiary(-ies). + * Copyright (C) 2015, 2016 Ericsson AB. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -30,84 +31,34 @@ */ #include "config.h" - -#if ENABLE(MEDIA_STREAM) - #include "RTCIceCandidate.h" -#include "Dictionary.h" +#if ENABLE(WEB_RTC) + #include "ExceptionCode.h" -#include "RTCIceCandidateDescriptor.h" namespace WebCore { -PassRefPtr<RTCIceCandidate> RTCIceCandidate::create(const Dictionary& dictionary, ExceptionCode& ec) -{ - String candidate; - bool ok = dictionary.get("candidate", candidate); - if (ok && candidate.isEmpty()) { - ec = TYPE_MISMATCH_ERR; - return nullptr; - } - - String sdpMid; - ok = dictionary.get("sdpMid", sdpMid); - if (ok && sdpMid.isEmpty()) { - ec = TYPE_MISMATCH_ERR; - return nullptr; - } - - String tempLineIndex; - unsigned short sdpMLineIndex = 0; - // First we check if the property exists in the Dictionary. - ok = dictionary.get("sdpMLineIndex", tempLineIndex); - // Then we try to convert it to a number and check if it was successful. - if (ok) { - bool intConversionOk; - sdpMLineIndex = tempLineIndex.toUIntStrict(&intConversionOk); - if (!intConversionOk) { - ec = TYPE_MISMATCH_ERR; - return nullptr; - } - } - - return adoptRef(new RTCIceCandidate(RTCIceCandidateDescriptor::create(candidate, sdpMid, sdpMLineIndex))); -} - -PassRefPtr<RTCIceCandidate> RTCIceCandidate::create(PassRefPtr<RTCIceCandidateDescriptor> descriptor) -{ - return adoptRef(new RTCIceCandidate(descriptor)); -} - -RTCIceCandidate::RTCIceCandidate(PassRefPtr<RTCIceCandidateDescriptor> descriptor) - : m_descriptor(descriptor) -{ -} - -RTCIceCandidate::~RTCIceCandidate() -{ -} - -const String& RTCIceCandidate::candidate() const -{ - return m_descriptor->candidate(); -} - -const String& RTCIceCandidate::sdpMid() const +inline RTCIceCandidate::RTCIceCandidate(const String& candidate, const String& sdpMid, std::optional<unsigned short> sdpMLineIndex) + : m_candidate(candidate) + , m_sdpMid(sdpMid) + , m_sdpMLineIndex(sdpMLineIndex) { - return m_descriptor->sdpMid(); + ASSERT(!sdpMid.isNull() || sdpMLineIndex); } -unsigned short RTCIceCandidate::sdpMLineIndex() const +ExceptionOr<Ref<RTCIceCandidate>> RTCIceCandidate::create(const Init& dictionary) { - return m_descriptor->sdpMLineIndex(); + if (dictionary.sdpMid.isNull() && !dictionary.sdpMLineIndex) + return Exception { TypeError }; + return create(dictionary.candidate, dictionary.sdpMid, dictionary.sdpMLineIndex); } -RTCIceCandidateDescriptor* RTCIceCandidate::descriptor() +Ref<RTCIceCandidate> RTCIceCandidate::create(const String& candidate, const String& sdpMid, std::optional<unsigned short> sdpMLineIndex) { - return m_descriptor.get(); + return adoptRef(*new RTCIceCandidate(candidate, sdpMid, sdpMLineIndex)); } } // namespace WebCore -#endif // ENABLE(MEDIA_STREAM) +#endif // ENABLE(WEB_RTC) diff --git a/Source/WebCore/Modules/mediastream/RTCIceCandidate.h b/Source/WebCore/Modules/mediastream/RTCIceCandidate.h index 0dad25c27..2c665491d 100644 --- a/Source/WebCore/Modules/mediastream/RTCIceCandidate.h +++ b/Source/WebCore/Modules/mediastream/RTCIceCandidate.h @@ -28,43 +28,38 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef RTCIceCandidate_h -#define RTCIceCandidate_h +#pragma once -#if ENABLE(MEDIA_STREAM) +#if ENABLE(WEB_RTC) -#include "ExceptionBase.h" +#include "ExceptionOr.h" #include "ScriptWrappable.h" -#include <wtf/PassRefPtr.h> -#include <wtf/RefCounted.h> -#include <wtf/RefPtr.h> -#include <wtf/text/WTFString.h> namespace WebCore { -class Dictionary; -class RTCIceCandidateDescriptor; - class RTCIceCandidate : public RefCounted<RTCIceCandidate>, public ScriptWrappable { public: - static PassRefPtr<RTCIceCandidate> create(const Dictionary&, ExceptionCode&); - static PassRefPtr<RTCIceCandidate> create(PassRefPtr<RTCIceCandidateDescriptor>); - virtual ~RTCIceCandidate(); + struct Init { + String candidate; + String sdpMid; + std::optional<unsigned short> sdpMLineIndex; + }; - const String& candidate() const; - const String& sdpMid() const; - unsigned short sdpMLineIndex() const; + static ExceptionOr<Ref<RTCIceCandidate>> create(const Init&); + static Ref<RTCIceCandidate> create(const String& candidate, const String& sdpMid, std::optional<unsigned short> sdpMLineIndex); - RTCIceCandidateDescriptor* descriptor(); + const String& candidate() const { return m_candidate; } + const String& sdpMid() const { return m_sdpMid; } + std::optional<unsigned short> sdpMLineIndex() const { return m_sdpMLineIndex; } private: - explicit RTCIceCandidate(PassRefPtr<RTCIceCandidateDescriptor>); + RTCIceCandidate(const String& candidate, const String& sdpMid, std::optional<unsigned short> sdpMLineIndex); - RefPtr<RTCIceCandidateDescriptor> m_descriptor; + String m_candidate; + String m_sdpMid; + std::optional<unsigned short> m_sdpMLineIndex; }; } // namespace WebCore -#endif // ENABLE(MEDIA_STREAM) - -#endif // RTCIceCandidate_h +#endif // ENABLE(WEB_RTC) diff --git a/Source/WebCore/Modules/mediastream/RTCIceCandidate.idl b/Source/WebCore/Modules/mediastream/RTCIceCandidate.idl index 4fb49586d..49c74e15c 100644 --- a/Source/WebCore/Modules/mediastream/RTCIceCandidate.idl +++ b/Source/WebCore/Modules/mediastream/RTCIceCandidate.idl @@ -30,12 +30,23 @@ */ [ - Conditional=MEDIA_STREAM, - CustomConstructor(optional Dictionary dictionary), - ConstructorRaisesException + Conditional=WEB_RTC, + Constructor(RTCIceCandidateInit candidateInitDict), + ConstructorMayThrowException, + EnabledAtRuntime=PeerConnection, + ImplementationLacksVTable, + PrivateIdentifier, + PublicIdentifier ] interface RTCIceCandidate { readonly attribute DOMString candidate; - readonly attribute DOMString sdpMid; - readonly attribute unsigned short sdpMLineIndex; + readonly attribute DOMString? sdpMid; + readonly attribute unsigned short? sdpMLineIndex; + + serializer = {candidate, sdpMid, sdpMLineIndex}; }; +dictionary RTCIceCandidateInit { + required DOMString candidate; + DOMString? sdpMid = null; + unsigned short? sdpMLineIndex = null; +}; diff --git a/Source/WebCore/Modules/mediastream/RTCIceCandidateEvent.cpp b/Source/WebCore/Modules/mediastream/RTCIceCandidateEvent.cpp index 1c28e58e2..ba62fbbe1 100644 --- a/Source/WebCore/Modules/mediastream/RTCIceCandidateEvent.cpp +++ b/Source/WebCore/Modules/mediastream/RTCIceCandidateEvent.cpp @@ -24,7 +24,7 @@ #include "config.h" -#if ENABLE(MEDIA_STREAM) +#if ENABLE(WEB_RTC) #include "RTCIceCandidateEvent.h" @@ -33,23 +33,14 @@ namespace WebCore { -PassRefPtr<RTCIceCandidateEvent> RTCIceCandidateEvent::create() +Ref<RTCIceCandidateEvent> RTCIceCandidateEvent::create(bool canBubble, bool cancelable, RefPtr<RTCIceCandidate>&& candidate) { - return adoptRef(new RTCIceCandidateEvent); + return adoptRef(*new RTCIceCandidateEvent(canBubble, cancelable, WTFMove(candidate))); } -PassRefPtr<RTCIceCandidateEvent> RTCIceCandidateEvent::create(bool canBubble, bool cancelable, PassRefPtr<RTCIceCandidate> candidate) -{ - return adoptRef(new RTCIceCandidateEvent(canBubble, cancelable, candidate)); -} - -RTCIceCandidateEvent::RTCIceCandidateEvent() -{ -} - -RTCIceCandidateEvent::RTCIceCandidateEvent(bool canBubble, bool cancelable, PassRefPtr<RTCIceCandidate> candidate) +RTCIceCandidateEvent::RTCIceCandidateEvent(bool canBubble, bool cancelable, RefPtr<RTCIceCandidate>&& candidate) : Event(eventNames().icecandidateEvent, canBubble, cancelable) - , m_candidate(candidate) + , m_candidate(WTFMove(candidate)) { } @@ -69,5 +60,5 @@ EventInterface RTCIceCandidateEvent::eventInterface() const } // namespace WebCore -#endif // ENABLE(MEDIA_STREAM) +#endif // ENABLE(WEB_RTC) diff --git a/Source/WebCore/Modules/mediastream/RTCIceCandidateEvent.h b/Source/WebCore/Modules/mediastream/RTCIceCandidateEvent.h index 466636831..8d371d4ab 100644 --- a/Source/WebCore/Modules/mediastream/RTCIceCandidateEvent.h +++ b/Source/WebCore/Modules/mediastream/RTCIceCandidateEvent.h @@ -22,10 +22,9 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef RTCIceCandidateEvent_h -#define RTCIceCandidateEvent_h +#pragma once -#if ENABLE(MEDIA_STREAM) +#if ENABLE(WEB_RTC) #include "Event.h" #include <wtf/text/AtomicString.h> @@ -37,22 +36,18 @@ class RTCIceCandidateEvent : public Event { public: virtual ~RTCIceCandidateEvent(); - static PassRefPtr<RTCIceCandidateEvent> create(); - static PassRefPtr<RTCIceCandidateEvent> create(bool canBubble, bool cancelable, PassRefPtr<RTCIceCandidate>); + static Ref<RTCIceCandidateEvent> create(bool canBubble, bool cancelable, RefPtr<RTCIceCandidate>&&); RTCIceCandidate* candidate() const; virtual EventInterface eventInterface() const; private: - RTCIceCandidateEvent(); - RTCIceCandidateEvent(bool canBubble, bool cancelable, PassRefPtr<RTCIceCandidate>); + RTCIceCandidateEvent(bool canBubble, bool cancelable, RefPtr<RTCIceCandidate>&&); RefPtr<RTCIceCandidate> m_candidate; }; } // namespace WebCore -#endif // ENABLE(MEDIA_STREAM) - -#endif // RTCIceCandidateEvent_h +#endif // ENABLE(WEB_RTC) diff --git a/Source/WebCore/Modules/mediastream/RTCIceCandidateEvent.idl b/Source/WebCore/Modules/mediastream/RTCIceCandidateEvent.idl index 3fa06379d..ff00d5bd2 100644 --- a/Source/WebCore/Modules/mediastream/RTCIceCandidateEvent.idl +++ b/Source/WebCore/Modules/mediastream/RTCIceCandidateEvent.idl @@ -24,7 +24,7 @@ [ NoInterfaceObject, - Conditional=MEDIA_STREAM, + Conditional=WEB_RTC, ] interface RTCIceCandidateEvent : Event { readonly attribute RTCIceCandidate candidate; }; diff --git a/Source/WebCore/Modules/mediastream/VideoStreamTrack.idl b/Source/WebCore/Modules/mediastream/RTCIceServer.h index 65c763d79..b0b1798ea 100644 --- a/Source/WebCore/Modules/mediastream/VideoStreamTrack.idl +++ b/Source/WebCore/Modules/mediastream/RTCIceServer.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 Apple Inc. All rights reserved. + * Copyright (C) 2014 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -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,10 +23,22 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -[ - Conditional=MEDIA_STREAM, - ConstructorCallWith=ScriptExecutionContext, - Constructor(optional Dictionary videoConstraints), -] interface VideoStreamTrack : MediaStreamTrack { +#pragma once + +#if ENABLE(WEB_RTC) + +#include <wtf/Variant.h> +#include <wtf/Vector.h> +#include <wtf/text/WTFString.h> + +namespace WebCore { + +struct RTCIceServer { + Variant<String, Vector<String>> urls; + String credential; + String username; }; +} // namespace WebCore + +#endif // ENABLE(WEB_RTC) diff --git a/Source/WebCore/Modules/mediastream/MediaTrackConstraint.idl b/Source/WebCore/Modules/mediastream/RTCIceServer.idl index 54af7b920..b2529c664 100644 --- a/Source/WebCore/Modules/mediastream/MediaTrackConstraint.idl +++ b/Source/WebCore/Modules/mediastream/RTCIceServer.idl @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 Apple Inc. All rights reserved. + * Copyright (C) 2014 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -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 @@ -24,8 +24,10 @@ */ [ - Conditional=MEDIA_STREAM, - NoInterfaceObject, -] interface MediaTrackConstraint { + Conditional=WEB_RTC, + JSGenerateToJSObject, +] dictionary RTCIceServer { + required (DOMString or sequence<DOMString>) urls; + DOMString username; + DOMString credential; }; - diff --git a/Source/WebCore/Modules/mediastream/RTCIceTransport.h b/Source/WebCore/Modules/mediastream/RTCIceTransport.h new file mode 100644 index 000000000..45cf7ed84 --- /dev/null +++ b/Source/WebCore/Modules/mediastream/RTCIceTransport.h @@ -0,0 +1,69 @@ +/* + * Copyright (C) 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 "PeerConnectionStates.h" +#include "ScriptWrappable.h" +#include <wtf/RefCounted.h> +#include <wtf/RefPtr.h> + +namespace WebCore { + +class RTCIceTransport : public RefCounted<RTCIceTransport>, public ScriptWrappable { +public: + + using TransportState = PeerConnectionStates::IceTransportState; + using GatheringState = PeerConnectionStates::IceGatheringState; + + static Ref<RTCIceTransport> create() + { + return adoptRef(*new RTCIceTransport()); + } + virtual ~RTCIceTransport() { } + + TransportState transportState() const { return m_transportState; } + void setTransportState(TransportState state) { m_transportState = state; } + + GatheringState gatheringState() const { return m_gatheringState; } + void setGatheringState(GatheringState state) { m_gatheringState = state; } + +private: + RTCIceTransport() { }; + + TransportState m_transportState { TransportState::New }; + GatheringState m_gatheringState { GatheringState::New }; +}; + +} // namespace WebCore + +#endif // ENABLE(WEB_RTC) diff --git a/Source/WebCore/Modules/mediastream/MediaStreamTrackSourcesCallback.h b/Source/WebCore/Modules/mediastream/RTCOfferAnswerOptions.h index fcee4df8a..f42af80c3 100644 --- a/Source/WebCore/Modules/mediastream/MediaStreamTrackSourcesCallback.h +++ b/Source/WebCore/Modules/mediastream/RTCOfferAnswerOptions.h @@ -1,5 +1,6 @@ /* - * Copyright (C) 2013 Google Inc. All rights reserved. + * Copyright (C) 2014 Apple Inc. All rights reserved. + * Copyright (C) 2015 Ericsson AB. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -10,10 +11,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 GOOGLE 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 GOOGLE 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,24 +24,25 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef MediaStreamTrackSourcesCallback_h -#define MediaStreamTrackSourcesCallback_h +#pragma once -#if ENABLE(MEDIA_STREAM) - -#include "SourceInfo.h" -#include <wtf/RefCounted.h> +#if ENABLE(WEB_RTC) namespace WebCore { -class MediaStreamTrackSourcesCallback : public RefCounted<MediaStreamTrackSourcesCallback> { -public: - virtual ~MediaStreamTrackSourcesCallback() { } - virtual bool handleEvent(Vector<RefPtr<SourceInfo>>) = 0; +struct RTCOfferAnswerOptions { + bool voiceActivityDetection { true }; }; -} // namespace WebCore +struct RTCOfferOptions : RTCOfferAnswerOptions { + int64_t offerToReceiveVideo { 0 }; + int64_t offerToReceiveAudio { 0 }; + bool iceRestart { false }; +}; -#endif +struct RTCAnswerOptions : RTCOfferAnswerOptions { +}; + +} // namespace WebCore -#endif // MediaStreamTrackSourcesCallback_h +#endif // ENABLE(WEB_RTC) diff --git a/Source/WebCore/Modules/mediastream/RTCPeerConnection.cpp b/Source/WebCore/Modules/mediastream/RTCPeerConnection.cpp index bb895c92f..8e4dcb113 100644 --- a/Source/WebCore/Modules/mediastream/RTCPeerConnection.cpp +++ b/Source/WebCore/Modules/mediastream/RTCPeerConnection.cpp @@ -1,6 +1,7 @@ /* * Copyright (C) 2012 Google Inc. All rights reserved. * Copyright (C) 2013 Nokia Corporation and/or its subsidiary(-ies). + * Copyright (C) 2015, 2016 Ericsson AB. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -30,335 +31,278 @@ */ #include "config.h" - -#if ENABLE(MEDIA_STREAM) - #include "RTCPeerConnection.h" -#include "ArrayValue.h" +#if ENABLE(WEB_RTC) + #include "Document.h" #include "Event.h" -#include "ExceptionCode.h" +#include "EventNames.h" #include "Frame.h" -#include "FrameLoader.h" -#include "FrameLoaderClient.h" -#include "MediaConstraintsImpl.h" -#include "MediaStreamEvent.h" +#include "MediaEndpointConfiguration.h" +#include "MediaStream.h" +#include "MediaStreamTrack.h" #include "RTCConfiguration.h" -#include "RTCDTMFSender.h" #include "RTCDataChannel.h" -#include "RTCDataChannelEvent.h" -#include "RTCDataChannelHandler.h" #include "RTCIceCandidate.h" -#include "RTCIceCandidateDescriptor.h" #include "RTCIceCandidateEvent.h" -#include "RTCPeerConnectionErrorCallback.h" +#include "RTCOfferAnswerOptions.h" #include "RTCSessionDescription.h" -#include "RTCSessionDescriptionCallback.h" -#include "RTCSessionDescriptionDescriptor.h" -#include "RTCSessionDescriptionRequestImpl.h" -#include "RTCStatsCallback.h" -#include "RTCStatsRequestImpl.h" -#include "RTCVoidRequestImpl.h" -#include "ScriptExecutionContext.h" -#include "VoidCallback.h" -#include <wtf/Functional.h> +#include "RTCTrackEvent.h" +#include "UUID.h" #include <wtf/MainThread.h> +#include <wtf/text/Base64.h> namespace WebCore { -PassRefPtr<RTCConfiguration> RTCPeerConnection::parseConfiguration(const Dictionary& configuration, ExceptionCode& ec) -{ - if (configuration.isUndefinedOrNull()) - return nullptr; - - ArrayValue iceServers; - bool ok = configuration.get("iceServers", iceServers); - if (!ok || iceServers.isUndefinedOrNull()) { - ec = TYPE_MISMATCH_ERR; - return nullptr; - } +using namespace PeerConnection; +using namespace PeerConnectionStates; - size_t numberOfServers; - ok = iceServers.length(numberOfServers); - if (!ok) { - ec = TYPE_MISMATCH_ERR; - return nullptr; - } +Ref<RTCPeerConnection> RTCPeerConnection::create(ScriptExecutionContext& context) +{ + Ref<RTCPeerConnection> peerConnection = adoptRef(*new RTCPeerConnection(context)); + peerConnection->suspendIfNeeded(); - RefPtr<RTCConfiguration> rtcConfiguration = RTCConfiguration::create(); + return peerConnection; +} - for (size_t i = 0; i < numberOfServers; ++i) { - Dictionary iceServer; - ok = iceServers.get(i, iceServer); - if (!ok) { - ec = TYPE_MISMATCH_ERR; - return nullptr; - } +RTCPeerConnection::RTCPeerConnection(ScriptExecutionContext& context) + : ActiveDOMObject(&context) + , m_backend(PeerConnectionBackend::create(*this)) +{ +} - String urlString, credential, username; - ok = iceServer.get("url", urlString); - if (!ok) { - ec = TYPE_MISMATCH_ERR; - return nullptr; - } - URL url(URL(), urlString); - if (!url.isValid() || !(url.protocolIs("turn") || url.protocolIs("stun"))) { - ec = TYPE_MISMATCH_ERR; - return nullptr; - } +RTCPeerConnection::~RTCPeerConnection() +{ + stop(); +} - iceServer.get("credential", credential); - iceServer.get("username", username); +ExceptionOr<void> RTCPeerConnection::initializeWith(Document& document, RTCConfiguration&& configuration) +{ + if (!document.frame()) + return Exception { NOT_SUPPORTED_ERR }; - rtcConfiguration->appendServer(RTCIceServer::create(url, credential, username)); - } + if (!m_backend) + return Exception { NOT_SUPPORTED_ERR }; - return rtcConfiguration.release(); + return setConfiguration(WTFMove(configuration)); } -PassRefPtr<RTCPeerConnection> RTCPeerConnection::create(ScriptExecutionContext& context, const Dictionary& rtcConfiguration, const Dictionary& mediaConstraints, ExceptionCode& ec) +ExceptionOr<Ref<RTCRtpSender>> RTCPeerConnection::addTrack(Ref<MediaStreamTrack>&& track, const Vector<std::reference_wrapper<MediaStream>>& streams) { - RefPtr<RTCConfiguration> configuration = parseConfiguration(rtcConfiguration, ec); - if (ec) - return nullptr; + if (m_signalingState == SignalingState::Closed) + return Exception { INVALID_STATE_ERR }; - RefPtr<MediaConstraints> constraints = MediaConstraintsImpl::create(mediaConstraints, ec); - if (ec) - return nullptr; + // Require at least one stream until https://github.com/w3c/webrtc-pc/issues/288 is resolved + if (!streams.size()) + return Exception { NOT_SUPPORTED_ERR }; - RefPtr<RTCPeerConnection> peerConnection = adoptRef(new RTCPeerConnection(context, configuration.release(), constraints.release(), ec)); - peerConnection->suspendIfNeeded(); - if (ec) - return nullptr; + for (RTCRtpSender& sender : m_transceiverSet->senders()) { + if (sender.trackId() == track->id()) + return Exception { INVALID_ACCESS_ERR }; + } - return peerConnection.release(); -} + Vector<String> mediaStreamIds; + for (auto stream : streams) + mediaStreamIds.append(stream.get().id()); -RTCPeerConnection::RTCPeerConnection(ScriptExecutionContext& context, PassRefPtr<RTCConfiguration> configuration, PassRefPtr<MediaConstraints> constraints, ExceptionCode& ec) - : ActiveDOMObject(&context) - , m_signalingState(SignalingStateStable) - , m_iceGatheringState(IceGatheringStateNew) - , m_iceConnectionState(IceConnectionStateNew) - , m_scheduledEventTimer(this, &RTCPeerConnection::scheduledEventTimerFired) - , m_stopped(false) -{ - Document& document = toDocument(context); + RTCRtpSender* sender = nullptr; - if (!document.frame()) { - ec = NOT_SUPPORTED_ERR; - return; + // Reuse an existing sender with the same track kind if it has never been used to send before. + for (auto& transceiver : m_transceiverSet->list()) { + auto& existingSender = transceiver->sender(); + if (existingSender.trackKind() == track->kind() && existingSender.trackId().isNull() && !transceiver->hasSendingDirection()) { + existingSender.setTrack(WTFMove(track)); + existingSender.setMediaStreamIds(WTFMove(mediaStreamIds)); + transceiver->enableSendingDirection(); + sender = &existingSender; + break; + } } - m_peerHandler = RTCPeerConnectionHandler::create(this); - if (!m_peerHandler) { - ec = NOT_SUPPORTED_ERR; - return; - } + if (!sender) { + String transceiverMid = RTCRtpTransceiver::getNextMid(); + const String& trackKind = track->kind(); + String trackId = createCanonicalUUIDString(); - document.frame()->loader().client().dispatchWillStartUsingPeerConnectionHandler(m_peerHandler.get()); + auto newSender = RTCRtpSender::create(WTFMove(track), WTFMove(mediaStreamIds), *this); + auto receiver = m_backend->createReceiver(transceiverMid, trackKind, trackId); + auto transceiver = RTCRtpTransceiver::create(WTFMove(newSender), WTFMove(receiver)); - if (!m_peerHandler->initialize(configuration, constraints)) { - ec = NOT_SUPPORTED_ERR; - return; + // This transceiver is not yet associated with an m-line (null mid), but we need a + // provisional mid if the transceiver is used to create an offer. + transceiver->setProvisionalMid(transceiverMid); + + sender = &transceiver->sender(); + m_transceiverSet->append(WTFMove(transceiver)); } -} -RTCPeerConnection::~RTCPeerConnection() -{ - stop(); + m_backend->markAsNeedingNegotiation(); - for (auto stream = m_localStreams.begin(), end = m_localStreams.end(); stream != end; ++stream) - (*stream)->removeObserver(this); + return Ref<RTCRtpSender> { *sender }; } -void RTCPeerConnection::createOffer(PassRefPtr<RTCSessionDescriptionCallback> successCallback, PassRefPtr<RTCPeerConnectionErrorCallback> errorCallback, const Dictionary& mediaConstraints, ExceptionCode& ec) +ExceptionOr<void> RTCPeerConnection::removeTrack(RTCRtpSender& sender) { - if (m_signalingState == SignalingStateClosed) { - ec = INVALID_STATE_ERR; - return; - } + if (m_signalingState == SignalingState::Closed) + return Exception { INVALID_STATE_ERR }; - if (!successCallback) { - ec = TYPE_MISMATCH_ERR; - return; + bool shouldAbort = true; + for (RTCRtpSender& senderInSet : m_transceiverSet->senders()) { + if (&senderInSet == &sender) { + shouldAbort = sender.isStopped(); + break; + } } + if (shouldAbort) + return { }; - RefPtr<MediaConstraints> constraints = MediaConstraintsImpl::create(mediaConstraints, ec); - if (ec) - return; + sender.stop(); - RefPtr<RTCSessionDescriptionRequestImpl> request = RTCSessionDescriptionRequestImpl::create(scriptExecutionContext(), successCallback, errorCallback); - m_peerHandler->createOffer(request.release(), constraints); + m_backend->markAsNeedingNegotiation(); + return { }; } -void RTCPeerConnection::createAnswer(PassRefPtr<RTCSessionDescriptionCallback> successCallback, PassRefPtr<RTCPeerConnectionErrorCallback> errorCallback, const Dictionary& mediaConstraints, ExceptionCode& ec) +ExceptionOr<Ref<RTCRtpTransceiver>> RTCPeerConnection::addTransceiver(Ref<MediaStreamTrack>&& track, const RtpTransceiverInit& init) { - if (m_signalingState == SignalingStateClosed) { - ec = INVALID_STATE_ERR; - return; - } + if (m_signalingState == SignalingState::Closed) + return Exception { INVALID_STATE_ERR }; - if (!successCallback) { - ec = TYPE_MISMATCH_ERR; - return; - } + String transceiverMid = RTCRtpTransceiver::getNextMid(); + const String& trackKind = track->kind(); + const String& trackId = track->id(); - RefPtr<MediaConstraints> constraints = MediaConstraintsImpl::create(mediaConstraints, ec); - if (ec) - return; + auto sender = RTCRtpSender::create(WTFMove(track), Vector<String>(), *this); + auto receiver = m_backend->createReceiver(transceiverMid, trackKind, trackId); + auto transceiver = RTCRtpTransceiver::create(WTFMove(sender), WTFMove(receiver)); + transceiver->setProvisionalMid(transceiverMid); - RefPtr<RTCSessionDescriptionRequestImpl> request = RTCSessionDescriptionRequestImpl::create(scriptExecutionContext(), successCallback, errorCallback); - m_peerHandler->createAnswer(request.release(), constraints.release()); + completeAddTransceiver(transceiver, init); + return WTFMove(transceiver); } -bool RTCPeerConnection::checkStateForLocalDescription(RTCSessionDescription* localDescription) +ExceptionOr<Ref<RTCRtpTransceiver>> RTCPeerConnection::addTransceiver(const String& kind, const RtpTransceiverInit& init) { - if (localDescription->type() == "offer") - return m_signalingState == SignalingStateStable || m_signalingState == SignalingStateHaveLocalOffer; - if (localDescription->type() == "answer") - return m_signalingState == SignalingStateHaveRemoteOffer || m_signalingState == SignalingStateHaveLocalPrAnswer; - if (localDescription->type() == "pranswer") - return m_signalingState == SignalingStateHaveLocalPrAnswer || m_signalingState == SignalingStateHaveRemoteOffer; + if (m_signalingState == SignalingState::Closed) + return Exception { INVALID_STATE_ERR }; - return false; -} + if (kind != "audio" && kind != "video") + return Exception { TypeError }; -bool RTCPeerConnection::checkStateForRemoteDescription(RTCSessionDescription* remoteDescription) -{ - if (remoteDescription->type() == "offer") - return m_signalingState == SignalingStateStable || m_signalingState == SignalingStateHaveRemoteOffer; - if (remoteDescription->type() == "answer") - return m_signalingState == SignalingStateHaveLocalOffer || m_signalingState == SignalingStateHaveRemotePrAnswer; - if (remoteDescription->type() == "pranswer") - return m_signalingState == SignalingStateHaveRemotePrAnswer || m_signalingState == SignalingStateHaveLocalOffer; + String transceiverMid = RTCRtpTransceiver::getNextMid(); + String trackId = createCanonicalUUIDString(); - return false; + auto sender = RTCRtpSender::create(kind, Vector<String>(), *this); + auto receiver = m_backend->createReceiver(transceiverMid, kind, trackId); + auto transceiver = RTCRtpTransceiver::create(WTFMove(sender), WTFMove(receiver)); + transceiver->setProvisionalMid(transceiverMid); + + completeAddTransceiver(transceiver, init); + return WTFMove(transceiver); } -void RTCPeerConnection::setLocalDescription(PassRefPtr<RTCSessionDescription> prpSessionDescription, PassRefPtr<VoidCallback> successCallback, PassRefPtr<RTCPeerConnectionErrorCallback> errorCallback, ExceptionCode& ec) +void RTCPeerConnection::completeAddTransceiver(RTCRtpTransceiver& transceiver, const RtpTransceiverInit& init) { - if (m_signalingState == SignalingStateClosed) { - ec = INVALID_STATE_ERR; - return; - } + transceiver.setDirection(static_cast<RTCRtpTransceiver::Direction>(init.direction)); - RefPtr<RTCSessionDescription> sessionDescription = prpSessionDescription; - if (!sessionDescription) { - ec = TYPE_MISMATCH_ERR; - return; - } + m_transceiverSet->append(transceiver); + m_backend->markAsNeedingNegotiation(); +} - if (!checkStateForLocalDescription(sessionDescription.get())) { - RefPtr<DOMError> error = DOMError::create(RTCPeerConnectionHandler::invalidSessionDescriptionErrorName()); - callOnMainThread(bind(&RTCPeerConnectionErrorCallback::handleEvent, errorCallback.get(), error.release())); +void RTCPeerConnection::queuedCreateOffer(RTCOfferOptions&& options, SessionDescriptionPromise&& promise) +{ + if (m_signalingState == SignalingState::Closed) { + promise.reject(INVALID_STATE_ERR); return; } - RefPtr<RTCVoidRequestImpl> request = RTCVoidRequestImpl::create(scriptExecutionContext(), successCallback, errorCallback); - m_peerHandler->setLocalDescription(request.release(), sessionDescription->descriptor()); + m_backend->createOffer(WTFMove(options), WTFMove(promise)); } -PassRefPtr<RTCSessionDescription> RTCPeerConnection::localDescription(ExceptionCode& ec) +void RTCPeerConnection::queuedCreateAnswer(RTCAnswerOptions&& options, SessionDescriptionPromise&& promise) { - RefPtr<RTCSessionDescriptionDescriptor> descriptor = m_peerHandler->localDescription(); - if (!descriptor) { - ec = INVALID_STATE_ERR; - return nullptr; + if (m_signalingState == SignalingState::Closed) { + promise.reject(INVALID_STATE_ERR); + return; } - RefPtr<RTCSessionDescription> sessionDescription = RTCSessionDescription::create(descriptor.release()); - return sessionDescription.release(); + m_backend->createAnswer(WTFMove(options), WTFMove(promise)); } -void RTCPeerConnection::setRemoteDescription(PassRefPtr<RTCSessionDescription> prpSessionDescription, PassRefPtr<VoidCallback> successCallback, PassRefPtr<RTCPeerConnectionErrorCallback> errorCallback, ExceptionCode& ec) +void RTCPeerConnection::queuedSetLocalDescription(RTCSessionDescription& description, DOMPromise<void>&& promise) { - if (m_signalingState == SignalingStateClosed) { - ec = INVALID_STATE_ERR; + if (m_signalingState == SignalingState::Closed) { + promise.reject(INVALID_STATE_ERR); return; } - RefPtr<RTCSessionDescription> sessionDescription = prpSessionDescription; - if (!sessionDescription) { - ec = TYPE_MISMATCH_ERR; - return; - } - - if (!checkStateForRemoteDescription(sessionDescription.get())) { - RefPtr<DOMError> error = DOMError::create(RTCPeerConnectionHandler::invalidSessionDescriptionErrorName()); - callOnMainThread(bind(&RTCPeerConnectionErrorCallback::handleEvent, errorCallback.get(), error.release())); - return; - } + m_backend->setLocalDescription(description, WTFMove(promise)); +} - RefPtr<RTCVoidRequestImpl> request = RTCVoidRequestImpl::create(scriptExecutionContext(), successCallback, errorCallback); - m_peerHandler->setRemoteDescription(request.release(), sessionDescription->descriptor()); +RefPtr<RTCSessionDescription> RTCPeerConnection::localDescription() const +{ + return m_backend->localDescription(); } -PassRefPtr<RTCSessionDescription> RTCPeerConnection::remoteDescription(ExceptionCode& ec) +RefPtr<RTCSessionDescription> RTCPeerConnection::currentLocalDescription() const { - RefPtr<RTCSessionDescriptionDescriptor> descriptor = m_peerHandler->remoteDescription(); - if (!descriptor) { - ec = INVALID_STATE_ERR; - return nullptr; - } + return m_backend->currentLocalDescription(); +} - RefPtr<RTCSessionDescription> desc = RTCSessionDescription::create(descriptor.release()); - return desc.release(); +RefPtr<RTCSessionDescription> RTCPeerConnection::pendingLocalDescription() const +{ + return m_backend->pendingLocalDescription(); } -void RTCPeerConnection::updateIce(const Dictionary& rtcConfiguration, const Dictionary& mediaConstraints, ExceptionCode& ec) +void RTCPeerConnection::queuedSetRemoteDescription(RTCSessionDescription& description, DOMPromise<void>&& promise) { - if (m_signalingState == SignalingStateClosed) { - ec = INVALID_STATE_ERR; + if (m_signalingState == SignalingState::Closed) { + promise.reject(INVALID_STATE_ERR); return; } - RefPtr<RTCConfiguration> configuration = parseConfiguration(rtcConfiguration, ec); - if (ec) - return; + m_backend->setRemoteDescription(description, WTFMove(promise)); +} - RefPtr<MediaConstraints> constraints = MediaConstraintsImpl::create(mediaConstraints, ec); - if (ec) - return; +RefPtr<RTCSessionDescription> RTCPeerConnection::remoteDescription() const +{ + return m_backend->remoteDescription(); +} - bool valid = m_peerHandler->updateIce(configuration, constraints); - if (!valid) - ec = SYNTAX_ERR; +RefPtr<RTCSessionDescription> RTCPeerConnection::currentRemoteDescription() const +{ + return m_backend->currentRemoteDescription(); } -void RTCPeerConnection::addIceCandidate(RTCIceCandidate* iceCandidate, PassRefPtr<VoidCallback> successCallback, PassRefPtr<RTCPeerConnectionErrorCallback> errorCallback, ExceptionCode& ec) +RefPtr<RTCSessionDescription> RTCPeerConnection::pendingRemoteDescription() const { - if (m_signalingState == SignalingStateClosed) { - ec = INVALID_STATE_ERR; - return; - } + return m_backend->pendingRemoteDescription(); +} - if (!iceCandidate || !successCallback || !errorCallback) { - ec = TYPE_MISMATCH_ERR; +void RTCPeerConnection::queuedAddIceCandidate(RTCIceCandidate& rtcCandidate, DOMPromise<void>&& promise) +{ + if (m_signalingState == SignalingState::Closed) { + promise.reject(INVALID_STATE_ERR); return; } - RefPtr<RTCVoidRequestImpl> request = RTCVoidRequestImpl::create(scriptExecutionContext(), successCallback, errorCallback); - - bool implemented = m_peerHandler->addIceCandidate(request.release(), iceCandidate->descriptor()); - if (!implemented) - ec = SYNTAX_ERR; + m_backend->addIceCandidate(rtcCandidate, WTFMove(promise)); } String RTCPeerConnection::signalingState() const { switch (m_signalingState) { - case SignalingStateStable: + case SignalingState::Stable: return ASCIILiteral("stable"); - case SignalingStateHaveLocalOffer: + case SignalingState::HaveLocalOffer: return ASCIILiteral("have-local-offer"); - case SignalingStateHaveRemoteOffer: + case SignalingState::HaveRemoteOffer: return ASCIILiteral("have-remote-offer"); - case SignalingStateHaveLocalPrAnswer: + case SignalingState::HaveLocalPrAnswer: return ASCIILiteral("have-local-pranswer"); - case SignalingStateHaveRemotePrAnswer: + case SignalingState::HaveRemotePrAnswer: return ASCIILiteral("have-remote-pranswer"); - case SignalingStateClosed: + case SignalingState::Closed: return ASCIILiteral("closed"); } @@ -369,11 +313,11 @@ String RTCPeerConnection::signalingState() const String RTCPeerConnection::iceGatheringState() const { switch (m_iceGatheringState) { - case IceGatheringStateNew: + case IceGatheringState::New: return ASCIILiteral("new"); - case IceGatheringStateGathering: + case IceGatheringState::Gathering: return ASCIILiteral("gathering"); - case IceGatheringStateComplete: + case IceGatheringState::Complete: return ASCIILiteral("complete"); } @@ -384,19 +328,19 @@ String RTCPeerConnection::iceGatheringState() const String RTCPeerConnection::iceConnectionState() const { switch (m_iceConnectionState) { - case IceConnectionStateNew: + case IceConnectionState::New: return ASCIILiteral("new"); - case IceConnectionStateChecking: + case IceConnectionState::Checking: return ASCIILiteral("checking"); - case IceConnectionStateConnected: + case IceConnectionState::Connected: return ASCIILiteral("connected"); - case IceConnectionStateCompleted: + case IceConnectionState::Completed: return ASCIILiteral("completed"); - case IceConnectionStateFailed: + case IceConnectionState::Failed: return ASCIILiteral("failed"); - case IceConnectionStateDisconnected: + case IceConnectionState::Disconnected: return ASCIILiteral("disconnected"); - case IceConnectionStateClosed: + case IceConnectionState::Closed: return ASCIILiteral("closed"); } @@ -404,295 +348,145 @@ String RTCPeerConnection::iceConnectionState() const return String(); } -void RTCPeerConnection::addStream(PassRefPtr<MediaStream> prpStream, const Dictionary& mediaConstraints, ExceptionCode& ec) -{ - if (m_signalingState == SignalingStateClosed) { - ec = INVALID_STATE_ERR; - return; - } - - RefPtr<MediaStream> stream = prpStream; - if (!stream) { - ec = TYPE_MISMATCH_ERR; - return; - } - - if (m_localStreams.contains(stream)) - return; - - RefPtr<MediaConstraints> constraints = MediaConstraintsImpl::create(mediaConstraints, ec); - if (ec) - return; - - bool valid = m_peerHandler->addStream(stream->privateStream(), constraints); - if (!valid) - ec = SYNTAX_ERR; - else { - m_localStreams.append(stream); - stream->addObserver(this); - } -} - -void RTCPeerConnection::removeStream(PassRefPtr<MediaStream> prpStream, ExceptionCode& ec) -{ - if (m_signalingState == SignalingStateClosed) { - ec = INVALID_STATE_ERR; - return; - } - - if (!prpStream) { - ec = TYPE_MISMATCH_ERR; - return; - } - - RefPtr<MediaStream> stream = prpStream; - - size_t pos = m_localStreams.find(stream); - if (pos == notFound) - return; - - m_localStreams.remove(pos); - stream->removeObserver(this); - m_peerHandler->removeStream(stream->privateStream()); -} - -MediaStreamVector RTCPeerConnection::getLocalStreams() const -{ - return m_localStreams; -} - -MediaStreamVector RTCPeerConnection::getRemoteStreams() const -{ - return m_remoteStreams; -} - -MediaStream* RTCPeerConnection::getStreamById(const String& streamId) -{ - for (MediaStreamVector::iterator iter = m_localStreams.begin(); iter != m_localStreams.end(); ++iter) { - if ((*iter)->id() == streamId) - return iter->get(); - } - - for (MediaStreamVector::iterator iter = m_remoteStreams.begin(); iter != m_remoteStreams.end(); ++iter) { - if ((*iter)->id() == streamId) - return iter->get(); +ExceptionOr<void> RTCPeerConnection::setConfiguration(RTCConfiguration&& configuration) +{ + if (m_signalingState == SignalingState::Closed) + return Exception { INVALID_STATE_ERR }; + + Vector<MediaEndpointConfiguration::IceServerInfo> servers; + if (configuration.iceServers) { + servers.reserveInitialCapacity(configuration.iceServers->size()); + for (auto& server : configuration.iceServers.value()) { + Vector<URL> serverURLs; + WTF::switchOn(server.urls, + [&serverURLs] (const String& string) { + serverURLs.reserveInitialCapacity(1); + serverURLs.uncheckedAppend(URL { URL { }, string }); + }, + [&serverURLs] (const Vector<String>& vector) { + serverURLs.reserveInitialCapacity(vector.size()); + for (auto& string : vector) + serverURLs.uncheckedAppend(URL { URL { }, string }); + } + ); + for (auto& serverURL : serverURLs) { + if (!(serverURL.protocolIs("turn") || serverURL.protocolIs("turns") || serverURL.protocolIs("stun"))) + return Exception { INVALID_ACCESS_ERR }; + } + servers.uncheckedAppend({ WTFMove(serverURLs), server.credential, server.username }); + } } - return nullptr; + m_backend->setConfiguration({ WTFMove(servers), configuration.iceTransportPolicy, configuration.bundlePolicy }); + m_configuration = WTFMove(configuration); + return { }; } -void RTCPeerConnection::getStats(PassRefPtr<RTCStatsCallback> successCallback, PassRefPtr<MediaStreamTrack> selector) +void RTCPeerConnection::getStats(MediaStreamTrack* selector, Ref<DeferredPromise>&& promise) { - RefPtr<RTCStatsRequestImpl> statsRequest = RTCStatsRequestImpl::create(scriptExecutionContext(), successCallback, selector); - // FIXME: Add passing selector as part of the statsRequest. - m_peerHandler->getStats(statsRequest.release()); + m_backend->getStats(selector, WTFMove(promise)); } -PassRefPtr<RTCDataChannel> RTCPeerConnection::createDataChannel(String label, const Dictionary& options, ExceptionCode& ec) +ExceptionOr<Ref<RTCDataChannel>> RTCPeerConnection::createDataChannel(ScriptExecutionContext& context, String&& label, RTCDataChannelInit&& options) { - if (m_signalingState == SignalingStateClosed) { - ec = INVALID_STATE_ERR; - return nullptr; - } + if (m_signalingState == SignalingState::Closed) + return Exception { INVALID_STATE_ERR }; - RefPtr<RTCDataChannel> channel = RTCDataChannel::create(scriptExecutionContext(), m_peerHandler.get(), label, options, ec); - if (ec) - return nullptr; + // FIXME: Check options + auto channelHandler = m_backend->createDataChannelHandler(label, options); + if (!channelHandler) + return Exception { NOT_SUPPORTED_ERR }; - m_dataChannels.append(channel); - return channel.release(); + return RTCDataChannel::create(context, WTFMove(channelHandler), WTFMove(label), WTFMove(options)); } -bool RTCPeerConnection::hasLocalStreamWithTrackId(const String& trackId) +void RTCPeerConnection::close() { - for (MediaStreamVector::iterator iter = m_localStreams.begin(); iter != m_localStreams.end(); ++iter) { - if ((*iter)->getTrackById(trackId)) - return true; - } - return false; -} - -PassRefPtr<RTCDTMFSender> RTCPeerConnection::createDTMFSender(PassRefPtr<MediaStreamTrack> prpTrack, ExceptionCode& ec) -{ - if (m_signalingState == SignalingStateClosed) { - ec = INVALID_STATE_ERR; - return nullptr; - } - - if (!prpTrack) { - ec = TypeError; - return nullptr; - } - - RefPtr<MediaStreamTrack> track = prpTrack; - - if (!hasLocalStreamWithTrackId(track->id())) { - ec = SYNTAX_ERR; - return nullptr; - } - - RefPtr<RTCDTMFSender> dtmfSender = RTCDTMFSender::create(scriptExecutionContext(), m_peerHandler.get(), track.release(), ec); - if (ec) - return nullptr; - return dtmfSender.release(); -} - -void RTCPeerConnection::close(ExceptionCode& ec) -{ - if (m_signalingState == SignalingStateClosed) { - ec = INVALID_STATE_ERR; + if (m_signalingState == SignalingState::Closed) return; - } - m_peerHandler->stop(); + m_backend->stop(); - changeIceConnectionState(IceConnectionStateClosed); - changeIceGatheringState(IceGatheringStateComplete); - changeSignalingState(SignalingStateClosed); -} + m_iceConnectionState = IceConnectionState::Closed; + m_signalingState = SignalingState::Closed; -void RTCPeerConnection::negotiationNeeded() -{ - scheduleDispatchEvent(Event::create(eventNames().negotiationneededEvent, false, false)); -} - -void RTCPeerConnection::didGenerateIceCandidate(PassRefPtr<RTCIceCandidateDescriptor> iceCandidateDescriptor) -{ - ASSERT(scriptExecutionContext()->isContextThread()); - if (!iceCandidateDescriptor) - scheduleDispatchEvent(RTCIceCandidateEvent::create(false, false, 0)); - else { - RefPtr<RTCIceCandidate> iceCandidate = RTCIceCandidate::create(iceCandidateDescriptor); - scheduleDispatchEvent(RTCIceCandidateEvent::create(false, false, iceCandidate.release())); - } + for (RTCRtpSender& sender : m_transceiverSet->senders()) + sender.stop(); } -void RTCPeerConnection::didChangeSignalingState(SignalingState newState) +void RTCPeerConnection::emulatePlatformEvent(const String& action) { - ASSERT(scriptExecutionContext()->isContextThread()); - changeSignalingState(newState); + m_backend->emulatePlatformEvent(action); } -void RTCPeerConnection::didChangeIceGatheringState(IceGatheringState newState) +void RTCPeerConnection::stop() { - ASSERT(scriptExecutionContext()->isContextThread()); - changeIceGatheringState(newState); + close(); } -void RTCPeerConnection::didChangeIceConnectionState(IceConnectionState newState) +const char* RTCPeerConnection::activeDOMObjectName() const { - ASSERT(scriptExecutionContext()->isContextThread()); - changeIceConnectionState(newState); + return "RTCPeerConnection"; } -void RTCPeerConnection::didAddRemoteStream(PassRefPtr<MediaStreamPrivate> privateStream) +bool RTCPeerConnection::canSuspendForDocumentSuspension() const { - ASSERT(scriptExecutionContext()->isContextThread()); - - if (m_signalingState == SignalingStateClosed) - return; - - RefPtr<MediaStream> stream = MediaStream::create(*scriptExecutionContext(), privateStream); - m_remoteStreams.append(stream); - - scheduleDispatchEvent(MediaStreamEvent::create(eventNames().addstreamEvent, false, false, stream.release())); + // FIXME: We should try and do better here. + return false; } -void RTCPeerConnection::didRemoveRemoteStream(MediaStreamPrivate* privateStream) +void RTCPeerConnection::addTransceiver(Ref<RTCRtpTransceiver>&& transceiver) { - ASSERT(scriptExecutionContext()->isContextThread()); - ASSERT(privateStream->client()); - - // FIXME: this class shouldn't know that the private stream client is a MediaStream! - RefPtr<MediaStream> stream = static_cast<MediaStream*>(privateStream->client()); - stream->setEnded(); - - if (m_signalingState == SignalingStateClosed) - return; - - size_t pos = m_remoteStreams.find(stream); - ASSERT(pos != notFound); - m_remoteStreams.remove(pos); - - scheduleDispatchEvent(MediaStreamEvent::create(eventNames().removestreamEvent, false, false, stream.release())); + m_transceiverSet->append(WTFMove(transceiver)); } -void RTCPeerConnection::didAddRemoteDataChannel(std::unique_ptr<RTCDataChannelHandler> handler) +void RTCPeerConnection::setSignalingState(SignalingState newState) { - ASSERT(scriptExecutionContext()->isContextThread()); - - if (m_signalingState == SignalingStateClosed) - return; - - RefPtr<RTCDataChannel> channel = RTCDataChannel::create(scriptExecutionContext(), std::move(handler)); - m_dataChannels.append(channel); - - scheduleDispatchEvent(RTCDataChannelEvent::create(eventNames().datachannelEvent, false, false, channel.release())); + m_signalingState = newState; } -void RTCPeerConnection::stop() +void RTCPeerConnection::updateIceGatheringState(IceGatheringState newState) { - if (m_stopped) - return; - - m_stopped = true; - m_iceConnectionState = IceConnectionStateClosed; - m_signalingState = SignalingStateClosed; + scriptExecutionContext()->postTask([=](ScriptExecutionContext&) { + if (m_signalingState == SignalingState::Closed || m_iceGatheringState == newState) + return; - Vector<RefPtr<RTCDataChannel>>::iterator i = m_dataChannels.begin(); - for (; i != m_dataChannels.end(); ++i) - (*i)->stop(); + m_iceGatheringState = newState; + dispatchEvent(Event::create(eventNames().icegatheringstatechangeEvent, false, false)); + }); } -void RTCPeerConnection::didAddOrRemoveTrack() +void RTCPeerConnection::updateIceConnectionState(IceConnectionState newState) { - negotiationNeeded(); -} + scriptExecutionContext()->postTask([=](ScriptExecutionContext&) { + if (m_signalingState == SignalingState::Closed || m_iceConnectionState == newState) + return; -void RTCPeerConnection::changeSignalingState(SignalingState signalingState) -{ - if (m_signalingState != SignalingStateClosed && m_signalingState != signalingState) { - m_signalingState = signalingState; - scheduleDispatchEvent(Event::create(eventNames().signalingstatechangeEvent, false, false)); - } + m_iceConnectionState = newState; + dispatchEvent(Event::create(eventNames().iceconnectionstatechangeEvent, false, false)); + }); } -void RTCPeerConnection::changeIceGatheringState(IceGatheringState iceGatheringState) +void RTCPeerConnection::scheduleNegotiationNeededEvent() { - m_iceGatheringState = iceGatheringState; -} - -void RTCPeerConnection::changeIceConnectionState(IceConnectionState iceConnectionState) -{ - if (m_iceConnectionState != IceConnectionStateClosed && m_iceConnectionState != iceConnectionState) { - m_iceConnectionState = iceConnectionState; - scheduleDispatchEvent(Event::create(eventNames().iceconnectionstatechangeEvent, false, false)); - } + scriptExecutionContext()->postTask([=](ScriptExecutionContext&) { + if (m_backend->isNegotiationNeeded()) { + m_backend->clearNegotiationNeededState(); + dispatchEvent(Event::create(eventNames().negotiationneededEvent, false, false)); + } + }); } -void RTCPeerConnection::scheduleDispatchEvent(PassRefPtr<Event> event) +void RTCPeerConnection::fireEvent(Event& event) { - m_scheduledEvents.append(event); - - if (!m_scheduledEventTimer.isActive()) - m_scheduledEventTimer.startOneShot(0); + dispatchEvent(event); } -void RTCPeerConnection::scheduledEventTimerFired(Timer<RTCPeerConnection>*) +void RTCPeerConnection::replaceTrack(RTCRtpSender& sender, RefPtr<MediaStreamTrack>&& withTrack, DOMPromise<void>&& promise) { - if (m_stopped) - return; - - Vector<RefPtr<Event>> events; - events.swap(m_scheduledEvents); - - Vector<RefPtr<Event>>::iterator it = events.begin(); - for (; it != events.end(); ++it) - dispatchEvent((*it).release()); - - events.clear(); + m_backend->replaceTrack(sender, WTFMove(withTrack), WTFMove(promise)); } } // namespace WebCore -#endif // ENABLE(MEDIA_STREAM) +#endif // ENABLE(WEB_RTC) diff --git a/Source/WebCore/Modules/mediastream/RTCPeerConnection.h b/Source/WebCore/Modules/mediastream/RTCPeerConnection.h index 0d375be4c..a10aaeb4c 100644 --- a/Source/WebCore/Modules/mediastream/RTCPeerConnection.h +++ b/Source/WebCore/Modules/mediastream/RTCPeerConnection.h @@ -1,6 +1,7 @@ /* * Copyright (C) 2012 Google Inc. All rights reserved. * Copyright (C) 2013 Nokia Corporation and/or its subsidiary(-ies). + * Copyright (C) 2015 Ericsson AB. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -29,148 +30,142 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef RTCPeerConnection_h -#define RTCPeerConnection_h +#pragma once -#if ENABLE(MEDIA_STREAM) +#if ENABLE(WEB_RTC) #include "ActiveDOMObject.h" -#include "Dictionary.h" #include "EventTarget.h" -#include "ExceptionBase.h" #include "MediaStream.h" -#include "RTCIceCandidate.h" -#include "RTCPeerConnectionHandler.h" -#include "RTCPeerConnectionHandlerClient.h" -#include "ScriptWrappable.h" -#include "Timer.h" -#include <wtf/RefCounted.h> +#include "RTCConfiguration.h" +#include "RTCDataChannel.h" +#include "RTCOfferAnswerOptions.h" +#include "RTCRtpTransceiver.h" namespace WebCore { -class MediaConstraints; class MediaStreamTrack; -class RTCConfiguration; -class RTCDTMFSender; -class RTCDataChannel; +class PeerConnectionBackend; +class RTCIceCandidate; class RTCPeerConnectionErrorCallback; class RTCSessionDescription; -class RTCSessionDescriptionCallback; class RTCStatsCallback; -class VoidCallback; -class RTCPeerConnection final : public RefCounted<RTCPeerConnection>, public ScriptWrappable, public RTCPeerConnectionHandlerClient, public EventTargetWithInlineData, public ActiveDOMObject, public MediaStream::Observer { +class RTCPeerConnection final : public RefCounted<RTCPeerConnection>, public RTCRtpSenderClient, public EventTargetWithInlineData, public ActiveDOMObject { public: - static PassRefPtr<RTCPeerConnection> create(ScriptExecutionContext&, const Dictionary& rtcConfiguration, const Dictionary& mediaConstraints, ExceptionCode&); - ~RTCPeerConnection(); + static Ref<RTCPeerConnection> create(ScriptExecutionContext&); + virtual ~RTCPeerConnection(); - void createOffer(PassRefPtr<RTCSessionDescriptionCallback>, PassRefPtr<RTCPeerConnectionErrorCallback>, const Dictionary& mediaConstraints, ExceptionCode&); + using AnswerOptions = RTCAnswerOptions; + using DataChannelInit = RTCDataChannelInit; + using OfferAnswerOptions = RTCOfferAnswerOptions; + using OfferOptions = RTCOfferOptions; - void createAnswer(PassRefPtr<RTCSessionDescriptionCallback>, PassRefPtr<RTCPeerConnectionErrorCallback>, const Dictionary& mediaConstraints, ExceptionCode&); + ExceptionOr<void> initializeWith(Document&, RTCConfiguration&&); - void setLocalDescription(PassRefPtr<RTCSessionDescription>, PassRefPtr<VoidCallback>, PassRefPtr<RTCPeerConnectionErrorCallback>, ExceptionCode&); - PassRefPtr<RTCSessionDescription> localDescription(ExceptionCode&); + const Vector<std::reference_wrapper<RTCRtpSender>>& getSenders() const { return m_transceiverSet->senders(); } + const Vector<std::reference_wrapper<RTCRtpReceiver>>& getReceivers() const { return m_transceiverSet->receivers(); } + const Vector<RefPtr<RTCRtpTransceiver>>& getTransceivers() const { return m_transceiverSet->list(); } - void setRemoteDescription(PassRefPtr<RTCSessionDescription>, PassRefPtr<VoidCallback>, PassRefPtr<RTCPeerConnectionErrorCallback>, ExceptionCode&); - PassRefPtr<RTCSessionDescription> remoteDescription(ExceptionCode&); + // Part of legacy MediaStream-based API (mostly implemented as JS built-ins) + Vector<RefPtr<MediaStream>> getRemoteStreams() const { return m_backend->getRemoteStreams(); } - String signalingState() const; + ExceptionOr<Ref<RTCRtpSender>> addTrack(Ref<MediaStreamTrack>&&, const Vector<std::reference_wrapper<MediaStream>>&); + ExceptionOr<void> removeTrack(RTCRtpSender&); - void updateIce(const Dictionary& rtcConfiguration, const Dictionary& mediaConstraints, ExceptionCode&); + // This enum is mirrored in RTCRtpTransceiver.h + enum class RtpTransceiverDirection { Sendrecv, Sendonly, Recvonly, Inactive }; - void addIceCandidate(RTCIceCandidate*, PassRefPtr<VoidCallback>, PassRefPtr<RTCPeerConnectionErrorCallback>, ExceptionCode&); + struct RtpTransceiverInit { + RtpTransceiverDirection direction; + }; - String iceGatheringState() const; + ExceptionOr<Ref<RTCRtpTransceiver>> addTransceiver(Ref<MediaStreamTrack>&&, const RtpTransceiverInit&); + ExceptionOr<Ref<RTCRtpTransceiver>> addTransceiver(const String& kind, const RtpTransceiverInit&); - String iceConnectionState() const; + void queuedCreateOffer(RTCOfferOptions&&, PeerConnection::SessionDescriptionPromise&&); + void queuedCreateAnswer(RTCAnswerOptions&&, PeerConnection::SessionDescriptionPromise&&); - MediaStreamVector getLocalStreams() const; + void queuedSetLocalDescription(RTCSessionDescription&, DOMPromise<void>&&); + RefPtr<RTCSessionDescription> localDescription() const; + RefPtr<RTCSessionDescription> currentLocalDescription() const; + RefPtr<RTCSessionDescription> pendingLocalDescription() const; - MediaStreamVector getRemoteStreams() const; + void queuedSetRemoteDescription(RTCSessionDescription&, DOMPromise<void>&&); + RefPtr<RTCSessionDescription> remoteDescription() const; + RefPtr<RTCSessionDescription> currentRemoteDescription() const; + RefPtr<RTCSessionDescription> pendingRemoteDescription() const; - MediaStream* getStreamById(const String& streamId); + String signalingState() const; - void addStream(PassRefPtr<MediaStream>, const Dictionary& mediaConstraints, ExceptionCode&); + void queuedAddIceCandidate(RTCIceCandidate&, DOMPromise<void>&&); - void removeStream(PassRefPtr<MediaStream>, ExceptionCode&); + String iceGatheringState() const; + String iceConnectionState() const; - void getStats(PassRefPtr<RTCStatsCallback> successCallback, PassRefPtr<MediaStreamTrack> selector); + const RTCConfiguration& getConfiguration() const { return m_configuration; } + ExceptionOr<void> setConfiguration(RTCConfiguration&&); - PassRefPtr<RTCDataChannel> createDataChannel(String label, const Dictionary& dataChannelDict, ExceptionCode&); + void getStats(MediaStreamTrack*, Ref<DeferredPromise>&&); - PassRefPtr<RTCDTMFSender> createDTMFSender(PassRefPtr<MediaStreamTrack>, ExceptionCode&); + ExceptionOr<Ref<RTCDataChannel>> createDataChannel(ScriptExecutionContext&, String&&, RTCDataChannelInit&&); - void close(ExceptionCode&); + void close(); - DEFINE_ATTRIBUTE_EVENT_LISTENER(negotiationneeded); - DEFINE_ATTRIBUTE_EVENT_LISTENER(icecandidate); - DEFINE_ATTRIBUTE_EVENT_LISTENER(signalingstatechange); - DEFINE_ATTRIBUTE_EVENT_LISTENER(addstream); - DEFINE_ATTRIBUTE_EVENT_LISTENER(removestream); - DEFINE_ATTRIBUTE_EVENT_LISTENER(iceconnectionstatechange); - DEFINE_ATTRIBUTE_EVENT_LISTENER(datachannel); + // EventTarget + EventTargetInterface eventTargetInterface() const final { return RTCPeerConnectionEventTargetInterfaceType; } + ScriptExecutionContext* scriptExecutionContext() const final { return ActiveDOMObject::scriptExecutionContext(); } - // RTCPeerConnectionHandlerClient - virtual void negotiationNeeded() override; - virtual void didGenerateIceCandidate(PassRefPtr<RTCIceCandidateDescriptor>) override; - virtual void didChangeSignalingState(SignalingState) override; - virtual void didChangeIceGatheringState(IceGatheringState) override; - virtual void didChangeIceConnectionState(IceConnectionState) override; - virtual void didAddRemoteStream(PassRefPtr<MediaStreamPrivate>) override; - virtual void didRemoveRemoteStream(MediaStreamPrivate*) override; - virtual void didAddRemoteDataChannel(std::unique_ptr<RTCDataChannelHandler>) override; + using RefCounted::ref; + using RefCounted::deref; - // EventTarget - virtual EventTargetInterface eventTargetInterface() const override { return RTCPeerConnectionEventTargetInterfaceType; } - virtual ScriptExecutionContext* scriptExecutionContext() const override { return ActiveDOMObject::scriptExecutionContext(); } + // Used for testing with a mock + WEBCORE_EXPORT void emulatePlatformEvent(const String& action); - // ActiveDOMObject - virtual void stop() override; + // API used by PeerConnectionBackend and relatives + void addTransceiver(Ref<RTCRtpTransceiver>&&); + void setSignalingState(PeerConnectionStates::SignalingState); + void updateIceGatheringState(PeerConnectionStates::IceGatheringState); + void updateIceConnectionState(PeerConnectionStates::IceConnectionState); - // MediaStream::Observer - virtual void didAddOrRemoveTrack() override; + void scheduleNegotiationNeededEvent(); - using RefCounted<RTCPeerConnection>::ref; - using RefCounted<RTCPeerConnection>::deref; + RTCRtpSenderClient& senderClient() { return *this; } + void fireEvent(Event&); + PeerConnectionStates::SignalingState internalSignalingState() const { return m_signalingState; } + PeerConnectionStates::IceGatheringState internalIceGatheringState() const { return m_iceGatheringState; } + PeerConnectionStates::IceConnectionState internalIceConnectionState() const { return m_iceConnectionState; } private: - RTCPeerConnection(ScriptExecutionContext&, PassRefPtr<RTCConfiguration>, PassRefPtr<MediaConstraints>, ExceptionCode&); + RTCPeerConnection(ScriptExecutionContext&); - static PassRefPtr<RTCConfiguration> parseConfiguration(const Dictionary& configuration, ExceptionCode&); - void scheduleDispatchEvent(PassRefPtr<Event>); - void scheduledEventTimerFired(Timer<RTCPeerConnection>*); - bool hasLocalStreamWithTrackId(const String& trackId); + void completeAddTransceiver(RTCRtpTransceiver&, const RtpTransceiverInit&); // EventTarget implementation. - virtual void refEventTarget() override { ref(); } - virtual void derefEventTarget() override { deref(); } + void refEventTarget() final { ref(); } + void derefEventTarget() final { deref(); } - void changeSignalingState(SignalingState); - void changeIceGatheringState(IceGatheringState); - void changeIceConnectionState(IceConnectionState); + // ActiveDOMObject + void stop() final; + const char* activeDOMObjectName() const final; + bool canSuspendForDocumentSuspension() const final; - bool checkStateForLocalDescription(RTCSessionDescription*); - bool checkStateForRemoteDescription(RTCSessionDescription*); + // RTCRtpSenderClient + void replaceTrack(RTCRtpSender&, RefPtr<MediaStreamTrack>&&, DOMPromise<void>&&) final; - SignalingState m_signalingState; - IceGatheringState m_iceGatheringState; - IceConnectionState m_iceConnectionState; + PeerConnectionStates::SignalingState m_signalingState { PeerConnectionStates::SignalingState::Stable }; + PeerConnectionStates::IceGatheringState m_iceGatheringState { PeerConnectionStates::IceGatheringState::New }; + PeerConnectionStates::IceConnectionState m_iceConnectionState { PeerConnectionStates::IceConnectionState::New }; - MediaStreamVector m_localStreams; - MediaStreamVector m_remoteStreams; + std::unique_ptr<RtpTransceiverSet> m_transceiverSet { std::unique_ptr<RtpTransceiverSet>(new RtpTransceiverSet()) }; Vector<RefPtr<RTCDataChannel>> m_dataChannels; - std::unique_ptr<RTCPeerConnectionHandler> m_peerHandler; - - Timer<RTCPeerConnection> m_scheduledEventTimer; - Vector<RefPtr<Event>> m_scheduledEvents; + std::unique_ptr<PeerConnectionBackend> m_backend; - bool m_stopped; + RTCConfiguration m_configuration; }; } // namespace WebCore -#endif // ENABLE(MEDIA_STREAM) - -#endif // RTCPeerConnection_h +#endif // ENABLE(WEB_RTC) diff --git a/Source/WebCore/Modules/mediastream/RTCPeerConnection.idl b/Source/WebCore/Modules/mediastream/RTCPeerConnection.idl index 1d6017f65..9ad581351 100644 --- a/Source/WebCore/Modules/mediastream/RTCPeerConnection.idl +++ b/Source/WebCore/Modules/mediastream/RTCPeerConnection.idl @@ -1,6 +1,7 @@ /* * Copyright (C) 2012 Google Inc. All rights reserved. * Copyright (C) 2013 Nokia Corporation and/or its subsidiary(-ies). + * Copyright (C) 2015, 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 @@ -29,65 +30,126 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -[ - Conditional=MEDIA_STREAM, - ActiveDOMObject, - CustomConstructor(Dictionary rtcIceServers, optional Dictionary mediaConstraints), - ConstructorCallWith=ScriptExecutionContext, - ConstructorRaisesException, - ConstructorCallWith=ScriptExecutionContext, - EventTarget, - InterfaceName=webkitRTCPeerConnection, -] interface RTCPeerConnection { - [RaisesException] void createOffer(RTCSessionDescriptionCallback successCallback, [Default=Undefined] optional RTCPeerConnectionErrorCallback failureCallback, optional Dictionary mediaConstraints); +dictionary RTCOfferAnswerOptions { + boolean voiceActivityDetection = true; +}; + +dictionary RTCOfferOptions : RTCOfferAnswerOptions { + boolean iceRestart = false; +}; - [RaisesException] void createAnswer(RTCSessionDescriptionCallback successCallback, [Default=Undefined] optional RTCPeerConnectionErrorCallback failureCallback, optional Dictionary mediaConstraints); +dictionary RTCAnswerOptions : RTCOfferAnswerOptions { +}; - [RaisesException] void setLocalDescription(RTCSessionDescription description, [Default=Undefined] optional VoidCallback successCallback, [Default=Undefined] optional RTCPeerConnectionErrorCallback failureCallback); - [GetterRaisesException] readonly attribute RTCSessionDescription localDescription; +dictionary RTCDataChannelInit { + boolean ordered = true; + unsigned short maxRetransmitTime; + unsigned short maxRetransmits; + USVString protocol = ""; + boolean negotiated = false; + unsigned short id; +}; - [RaisesException] void setRemoteDescription(RTCSessionDescription description, [Default=Undefined] optional VoidCallback successCallback, [Default=Undefined] optional RTCPeerConnectionErrorCallback failureCallback); - [GetterRaisesException] readonly attribute RTCSessionDescription remoteDescription; +[ + ActiveDOMObject, + Conditional=WEB_RTC, + ConstructorCallWith=ScriptExecutionContext, + EnabledAtRuntime=PeerConnection, + ExportMacro=WEBCORE_EXPORT, + JSBuiltinConstructor, +] interface RTCPeerConnection : EventTarget { + // Private initializer + [PrivateIdentifier, CallWith=Document, MayThrowException] void initializeWith(RTCConfiguration configuration); + + // RTP Media API extensions + [PrivateIdentifier, PublicIdentifier] sequence<RTCRtpSender> getSenders(); + sequence<RTCRtpReceiver> getReceivers(); + sequence<RTCRtpTransceiver> getTransceivers(); + + [PrivateIdentifier, PublicIdentifier, MayThrowException] RTCRtpSender addTrack(MediaStreamTrack track, MediaStream... streams); + [PrivateIdentifier, PublicIdentifier, MayThrowException] void removeTrack(RTCRtpSender sender); + + [MayThrowException] RTCRtpTransceiver addTransceiver(MediaStreamTrack track, optional RTCRtpTransceiverInit init); + [MayThrowException] RTCRtpTransceiver addTransceiver(DOMString kind, optional RTCRtpTransceiverInit init); + + // Legacy MediaSream-based API (implemented on top of the RTP Media API) + [JSBuiltin] sequence<MediaStream> getLocalStreams(); + [PrivateIdentifier, PublicIdentifier] sequence<MediaStream> getRemoteStreams(); + [JSBuiltin] MediaStream getStreamById(DOMString streamId); + + [JSBuiltin] void addStream(MediaStream stream); + [JSBuiltin] void removeStream(MediaStream stream); + + [JSBuiltin] Promise<RTCSessionDescriptionInit> createOffer(optional RTCOfferOptions offerOptions); + // Legacy signature: Promise<void> createOffer(RTCSessionDescriptionCallback successCallback + // RTCPeerConnectionErrorCallback errorCallback, + // optional Dictionary offerOptions); + + [JSBuiltin] Promise<RTCSessionDescriptionInit> createAnswer(optional RTCAnswerOptions answerOptions); + // Legacy signature: Promise<void> createAnswer(RTCSessionDescriptionCallback successCallback + // RTCPeerConnectionErrorCallback errorCallback, + // optional Dictionary answerOptions); + + [JSBuiltin] Promise<void> setLocalDescription(RTCSessionDescription description); + // Legacy signature: Promise<void> setLocalDescription(RTCSessionDescription description + // VoidCallback successCallback, + // RTCPeerConnectionErrorCallback errorCallback); + + readonly attribute RTCSessionDescription localDescription; + readonly attribute RTCSessionDescription currentLocalDescription; + readonly attribute RTCSessionDescription pendingLocalDescription; + + [JSBuiltin] Promise<void> setRemoteDescription(RTCSessionDescription description); + // Legacy signature: Promise<void> setRemoteDescription(RTCSessionDescription description + // VoidCallback successCallback, + // RTCPeerConnectionErrorCallback errorCallback); + + readonly attribute RTCSessionDescription remoteDescription; + readonly attribute RTCSessionDescription currentRemoteDescription; + readonly attribute RTCSessionDescription pendingRemoteDescription; readonly attribute DOMString signalingState; - [RaisesException] void updateIce(optional Dictionary configuration, optional Dictionary mediaConstraints); - - [RaisesException] void addIceCandidate(RTCIceCandidate candidate, VoidCallback successCallback, RTCPeerConnectionErrorCallback failureCallback); + [JSBuiltin] Promise<void> addIceCandidate(RTCIceCandidate candidate); + // Legacy signature: Promise<void> addIceCandidate(RTCIceCandidate candidate + // VoidCallback successCallback, + // RTCPeerConnectionErrorCallback errorCallback); readonly attribute DOMString iceGatheringState; readonly attribute DOMString iceConnectionState; - sequence<MediaStream> getLocalStreams(); - sequence<MediaStream> getRemoteStreams(); - MediaStream getStreamById(DOMString streamId); - - [StrictTypeChecking, RaisesException] void addStream(MediaStream stream, optional Dictionary mediaConstraints); - [StrictTypeChecking, RaisesException] void removeStream(MediaStream stream); + RTCConfiguration getConfiguration(); + [MayThrowException] void setConfiguration(RTCConfiguration configuration); - void getStats(RTCStatsCallback successCallback, [Default=Undefined] optional MediaStreamTrack selector); + Promise<RTCStatsReport> getStats(optional MediaStreamTrack? selector = null); - [RaisesException] RTCDataChannel createDataChannel([TreatNullAs=NullString, TreatUndefinedAs=NullString] DOMString label, optional Dictionary options); + // Private API used to implement the overloaded operations above. Queued functions are called by + // runQueuedOperation() (defined in RTCPeerConnectionInternals.js). + [PrivateIdentifier] Promise<RTCSessionDescriptionInit> queuedCreateOffer(optional RTCOfferOptions offerOptions); + [PrivateIdentifier] Promise<RTCSessionDescriptionInit> queuedCreateAnswer(optional RTCAnswerOptions answerOptions); + [PrivateIdentifier] Promise<void> queuedSetLocalDescription(RTCSessionDescription description); + [PrivateIdentifier] Promise<void> queuedSetRemoteDescription(RTCSessionDescription description); + [PrivateIdentifier] Promise<void> queuedAddIceCandidate(RTCIceCandidate candidate); - [RaisesException] RTCDTMFSender createDTMFSender(MediaStreamTrack track); + [CallWith=ScriptExecutionContext, MayThrowException] RTCDataChannel createDataChannel([TreatNullAs=EmptyString] DOMString label, optional RTCDataChannelInit options); - [RaisesException] void close(); + void close(); - attribute EventListener onnegotiationneeded; - attribute EventListener onicecandidate; - attribute EventListener onsignalingstatechange; - attribute EventListener onaddstream; - attribute EventListener onremovestream; - attribute EventListener oniceconnectionstatechange; - attribute EventListener ondatachannel; + attribute EventHandler onnegotiationneeded; + attribute EventHandler onicecandidate; + attribute EventHandler onsignalingstatechange; + attribute EventHandler ontrack; + attribute EventHandler oniceconnectionstatechange; + attribute EventHandler onicegatheringstatechange; + attribute EventHandler ondatachannel; - // EventTarget interface - void addEventListener(DOMString type, - EventListener listener, - optional boolean useCapture); - void removeEventListener(DOMString type, - EventListener listener, - optional boolean useCapture); - [RaisesException] boolean dispatchEvent(Event event); + // Legacy event handler (MediaStream-based API) + attribute EventHandler onaddstream; }; +// This enum is mirrored in RTCRtpTransceiver.idl +enum RTCRtpTransceiverDirection { "sendrecv", "sendonly", "recvonly", "inactive" }; + +dictionary RTCRtpTransceiverInit { + RTCRtpTransceiverDirection direction = "sendrecv"; +}; diff --git a/Source/WebCore/Modules/mediastream/RTCPeerConnection.js b/Source/WebCore/Modules/mediastream/RTCPeerConnection.js new file mode 100644 index 000000000..2cb6a4036 --- /dev/null +++ b/Source/WebCore/Modules/mediastream/RTCPeerConnection.js @@ -0,0 +1,268 @@ +/* + * 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. + */ + +// @conditional=ENABLE(WEB_RTC) + +function initializeRTCPeerConnection(configuration) +{ + "use strict"; + + if (configuration == null) + configuration = {}; + else if (!@isObject(configuration)) + @throwTypeError("RTCPeerConnection argument must be a valid dictionary"); + + // FIXME: Handle errors in a better way than catching and re-throwing (http://webkit.org/b/158936) + try { + this.@initializeWith(configuration); + } catch (e) { + const message = e.name === "TypeMismatchError" ? "Invalid RTCPeerConnection constructor arguments" + : "Error creating RTCPeerConnection"; + @throwTypeError(message); + } + this.@operations = []; + this.@localStreams = []; + + return this; +} + +function getLocalStreams() +{ + "use strict"; + + if (!@isRTCPeerConnection(this)) + throw @makeThisTypeError("RTCPeerConnection", "getLocalStreams"); + + return this.@localStreams.slice(); +} + +function getStreamById(streamIdArg) +{ + "use strict"; + + if (!@isRTCPeerConnection(this)) + throw @makeThisTypeError("RTCPeerConnection", "getStreamById"); + + if (arguments.length < 1) + @throwTypeError("Not enough arguments"); + + const streamId = @String(streamIdArg); + + return this.@localStreams.find(stream => stream.id === streamId) + || this.@getRemoteStreams().find(stream => stream.id === streamId) + || null; +} + +function addStream(stream) +{ + "use strict"; + + if (!@isRTCPeerConnection(this)) + throw @makeThisTypeError("RTCPeerConnection", "addStream"); + + if (arguments.length < 1) + @throwTypeError("Not enough arguments"); + + if (!(stream instanceof @MediaStream)) + @throwTypeError("Argument 1 ('stream') to RTCPeerConnection.addStream must be an instance of MediaStream"); + + if (this.@localStreams.find(localStream => localStream.id === stream.id)) + return; + + this.@localStreams.@push(stream); + stream.@getTracks().forEach(track => this.@addTrack(track, stream)); +} + +function removeStream(stream) +{ + "use strict"; + + if (!@isRTCPeerConnection(this)) + throw @makeThisTypeError("RTCPeerConnection", "removeStream"); + + if (arguments.length < 1) + @throwTypeError("Not enough arguments"); + + if (!(stream instanceof @MediaStream)) + @throwTypeError("Argument 1 ('stream') to RTCPeerConnection.removeStream must be an instance of MediaStream"); + + const indexOfStreamToRemove = this.@localStreams.findIndex(localStream => localStream.id === stream.id); + if (indexOfStreamToRemove === -1) + return; + + const senders = this.@getSenders(); + this.@localStreams[indexOfStreamToRemove].@getTracks().forEach(track => { + const senderForTrack = senders.find(sender => sender.track && sender.track.id === track.id); + if (senderForTrack) + this.@removeTrack(senderForTrack); + }); + + this.@localStreams.splice(indexOfStreamToRemove, 1); +} + +function createOffer() +{ + "use strict"; + + if (!@isRTCPeerConnection(this)) + return @Promise.@reject(@makeThisTypeError("RTCPeerConnection", "createOffer")); + + const peerConnection = this; + + return @callbacksAndDictionaryOverload(arguments, "createOffer", function (options) { + // Promise mode + return @enqueueOperation(peerConnection, function () { + return peerConnection.@queuedCreateOffer(options); + }); + }, function (successCallback, errorCallback, options) { + // Legacy callbacks mode + @enqueueOperation(peerConnection, function () { + return peerConnection.@queuedCreateOffer(options).@then(successCallback, errorCallback); + }); + + return @Promise.@resolve(@undefined); + }); +} + +function createAnswer() +{ + "use strict"; + + if (!@isRTCPeerConnection(this)) + return @Promise.@reject(@makeThisTypeError("RTCPeerConnection", "createAnswer")); + + const peerConnection = this; + + return @callbacksAndDictionaryOverload(arguments, "createAnswer", function (options) { + // Promise mode + return @enqueueOperation(peerConnection, function () { + return peerConnection.@queuedCreateAnswer(options); + }); + }, function (successCallback, errorCallback, options) { + // Legacy callbacks mode + @enqueueOperation(peerConnection, function () { + return peerConnection.@queuedCreateAnswer(options).@then(successCallback, errorCallback); + }); + + return @Promise.@resolve(@undefined); + }); +} + +function setLocalDescription() +{ + "use strict"; + + if (!@isRTCPeerConnection(this)) + return @Promise.@reject(@makeThisTypeError("RTCPeerConnection", "setLocalDescription")); + + const peerConnection = this; + + // FIXME: According the spec, we should throw when receiving a RTCSessionDescription. + const objectInfo = { + "constructor": @RTCSessionDescription, + "argName": "description", + "argType": "RTCSessionDescription", + "maybeDictionary": "true" + }; + return @objectAndCallbacksOverload(arguments, "setLocalDescription", objectInfo, function (description) { + // Promise mode + return @enqueueOperation(peerConnection, function () { + return peerConnection.@queuedSetLocalDescription(description); + }); + }, function (description, successCallback, errorCallback) { + // Legacy callbacks mode + @enqueueOperation(peerConnection, function () { + return peerConnection.@queuedSetLocalDescription(description).@then(successCallback, errorCallback); + }); + + return @Promise.@resolve(@undefined); + }); +} + +function setRemoteDescription() +{ + "use strict"; + + if (!@isRTCPeerConnection(this)) + return @Promise.@reject(@makeThisTypeError("RTCPeerConnection", "setRemoteDescription")); + + const peerConnection = this; + + // FIXME: According the spec, we should throw when receiving a RTCSessionDescription. + const objectInfo = { + "constructor": @RTCSessionDescription, + "argName": "description", + "argType": "RTCSessionDescription", + "maybeDictionary": "true" + }; + return @objectAndCallbacksOverload(arguments, "setRemoteDescription", objectInfo, function (description) { + // Promise mode + return @enqueueOperation(peerConnection, function () { + return peerConnection.@queuedSetRemoteDescription(description); + }); + }, function (description, successCallback, errorCallback) { + // Legacy callbacks mode + @enqueueOperation(peerConnection, function () { + return peerConnection.@queuedSetRemoteDescription(description).@then(successCallback, errorCallback); + }); + + return @Promise.@resolve(@undefined); + }); +} + +function addIceCandidate() +{ + "use strict"; + + if (!@isRTCPeerConnection(this)) + return @Promise.@reject(@makeThisTypeError("RTCPeerConnection", "addIceCandidate")); + + const peerConnection = this; + + const objectInfo = { + "constructor": @RTCIceCandidate, + "argName": "candidate", + "argType": "RTCIceCandidate", + "maybeDictionary": "true" + }; + return @objectAndCallbacksOverload(arguments, "addIceCandidate", objectInfo, function (candidate) { + // Promise mode + return @enqueueOperation(peerConnection, function () { + return peerConnection.@queuedAddIceCandidate(candidate); + }); + }, function (candidate, successCallback, errorCallback) { + // Legacy callbacks mode + @enqueueOperation(peerConnection, function () { + return peerConnection.@queuedAddIceCandidate(candidate).@then(successCallback, errorCallback); + }); + + return @Promise.@resolve(@undefined); + }); +} diff --git a/Source/WebCore/Modules/mediastream/RTCPeerConnectionInternals.js b/Source/WebCore/Modules/mediastream/RTCPeerConnectionInternals.js new file mode 100644 index 000000000..498d4f886 --- /dev/null +++ b/Source/WebCore/Modules/mediastream/RTCPeerConnectionInternals.js @@ -0,0 +1,145 @@ +/* + * 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. + */ + +// @conditional=ENABLE(WEB_RTC) +// @internal + +// Operation queue as specified in section 4.3.1 (WebRTC 1.0) +function enqueueOperation(peerConnection, operation) +{ + "use strict"; + + const operations = peerConnection.@operations; + + function runNext() { + operations.@shift(); + if (operations.length) + operations[0](); + }; + + return new @Promise(function (resolve, reject) { + operations.@push(function() { + operation().@then(resolve, reject).@then(runNext, runNext); + }); + + if (operations.length == 1) + operations[0](); + }); +} + +function objectAndCallbacksOverload(args, functionName, objectInfo, promiseMode, legacyMode) +{ + "use strict"; + + let argsCount = args.length; + let objectArg = args[0]; + let objectArgOk = false; + + if (!argsCount) { + if (!objectInfo.defaultsToNull) + return @Promise.@reject(new @TypeError("Not enough arguments")); + + objectArg = null; + objectArgOk = true; + argsCount = 1; + } else { + const hasMatchingType = objectArg instanceof objectInfo.constructor; + if (hasMatchingType) + objectArgOk = true; + else if (objectInfo.defaultsToNull) + objectArgOk = objectArg === null || typeof objectArg === "undefined"; + else if (objectInfo.maybeDictionary) { + try { + objectArg = new objectInfo.constructor(objectArg); + objectArgOk = true; + } catch (e) { + objectArgOk = false; + } + } + } + + if (!objectArgOk) + return @Promise.@reject(new @TypeError(`Argument 1 ('${objectInfo.argName}') to RTCPeerConnection.${functionName} must be an instance of ${objectInfo.argType}`)); + + if (argsCount === 1) + return promiseMode(objectArg); + + // More than one argument: Legacy mode + if (argsCount < 3) + return @Promise.@reject(new @TypeError("Not enough arguments")); + + const successCallback = args[1]; + const errorCallback = args[2]; + + if (typeof successCallback !== "function") + return @Promise.@reject(new @TypeError(`Argument 2 ('successCallback') to RTCPeerConnection.${functionName} must be a function`)); + + if (typeof errorCallback !== "function") + return @Promise.@reject(new @TypeError(`Argument 3 ('errorCallback') to RTCPeerConnection.${functionName} must be a function`)); + + return legacyMode(objectArg, successCallback, errorCallback); +} + +function callbacksAndDictionaryOverload(args, functionName, promiseMode, legacyMode) +{ + "use strict"; + + if (args.length <= 1) { + // Zero or one arguments: Promise mode + const options = args[0]; + if (args.length && !@isDictionary(options)) + return @Promise.@reject(new @TypeError(`Argument 1 ('options') to RTCPeerConnection.${functionName} must be a dictionary`)); + + return promiseMode(options); + } + + // More than one argument: Legacy mode + const successCallback = args[0]; + const errorCallback = args[1]; + const options = args[2]; + + if (typeof successCallback !== "function") + return @Promise.@reject(new @TypeError(`Argument 1 ('successCallback') to RTCPeerConnection.${functionName} must be a function`)); + + if (typeof errorCallback !== "function") + return @Promise.@reject(new @TypeError(`Argument 2 ('errorCallback') to RTCPeerConnection.${functionName} must be a function`)); + + if (args.length > 2 && !@isDictionary(options)) + return @Promise.@reject(new @TypeError(`Argument 3 ('options') to RTCPeerConnection.${functionName} must be a dictionary`)); + + return legacyMode(successCallback, errorCallback, args[2]); +} + +function isRTCPeerConnection(connection) +{ + "use strict"; + + return @isObject(connection) && !!connection.@operations; +} diff --git a/Source/WebCore/Modules/mediastream/RTCPeerConnectionErrorCallback.h b/Source/WebCore/Modules/mediastream/RTCRtpReceiver.cpp index c2aecba0a..152e60270 100644 --- a/Source/WebCore/Modules/mediastream/RTCPeerConnectionErrorCallback.h +++ b/Source/WebCore/Modules/mediastream/RTCRtpReceiver.cpp @@ -1,14 +1,19 @@ /* - * 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. + * 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 @@ -23,24 +28,18 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef RTCPeerConnectionErrorCallback_h -#define RTCPeerConnectionErrorCallback_h - -#if ENABLE(MEDIA_STREAM) +#include "config.h" +#include "RTCRtpReceiver.h" -#include "DOMError.h" -#include <wtf/RefCounted.h> +#if ENABLE(WEB_RTC) namespace WebCore { -class RTCPeerConnectionErrorCallback : public RefCounted<RTCPeerConnectionErrorCallback> { -public: - virtual ~RTCPeerConnectionErrorCallback() { } - virtual bool handleEvent(DOMError*) = 0; -}; +RTCRtpReceiver::RTCRtpReceiver(Ref<MediaStreamTrack>&& track) + : RTCRtpSenderReceiverBase(WTFMove(track)) +{ +} } // namespace WebCore -#endif // ENABLE(MEDIA_STREAM) - -#endif // RTCPeerConnectionErrorCallback_h +#endif // ENABLE(WEB_RTC) diff --git a/Source/WebCore/Modules/mediastream/RTCRtpReceiver.h b/Source/WebCore/Modules/mediastream/RTCRtpReceiver.h new file mode 100644 index 000000000..ba787a63e --- /dev/null +++ b/Source/WebCore/Modules/mediastream/RTCRtpReceiver.h @@ -0,0 +1,57 @@ +/* + * 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 "RTCRtpSenderReceiverBase.h" + +namespace WebCore { + +class RTCRtpReceiver : public RTCRtpSenderReceiverBase { +public: + static Ref<RTCRtpReceiver> create(Ref<MediaStreamTrack>&& track) + { + return adoptRef(*new RTCRtpReceiver(WTFMove(track))); + } + + bool isDispatched() const { return m_isDispatched; } + void setDispatched(bool isDispatched) { m_isDispatched = isDispatched; } + +private: + explicit RTCRtpReceiver(Ref<MediaStreamTrack>&&); + + bool m_isDispatched { false }; +}; + +} // namespace WebCore + +#endif // ENABLE(WEB_RTC) diff --git a/Source/WebCore/Modules/mediastream/RTCPeerConnectionErrorCallback.idl b/Source/WebCore/Modules/mediastream/RTCRtpReceiver.idl index 4b87ad7ff..645ab3cbc 100644 --- a/Source/WebCore/Modules/mediastream/RTCPeerConnectionErrorCallback.idl +++ b/Source/WebCore/Modules/mediastream/RTCRtpReceiver.idl @@ -1,14 +1,19 @@ /* - * 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. + * 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 @@ -24,8 +29,8 @@ */ [ - Conditional=MEDIA_STREAM, -] callback interface RTCPeerConnectionErrorCallback { - boolean handleEvent(DOMError error); + Conditional=WEB_RTC, + EnabledAtRuntime=PeerConnection, +] interface RTCRtpReceiver { + readonly attribute MediaStreamTrack track; }; - diff --git a/Source/WebCore/Modules/mediastream/RTCRtpSender.cpp b/Source/WebCore/Modules/mediastream/RTCRtpSender.cpp new file mode 100644 index 000000000..53b6f2cd4 --- /dev/null +++ b/Source/WebCore/Modules/mediastream/RTCRtpSender.cpp @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2015 Ericsson AB. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of Ericsson nor the names of its contributors + * may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "RTCRtpSender.h" + +#if ENABLE(WEB_RTC) + +#include "ExceptionCode.h" + +namespace WebCore { + +Ref<RTCRtpSender> RTCRtpSender::create(Ref<MediaStreamTrack>&& track, Vector<String>&& mediaStreamIds, RTCRtpSenderClient& client) +{ + const String& trackKind = track->kind(); + return adoptRef(*new RTCRtpSender(WTFMove(track), trackKind, WTFMove(mediaStreamIds), client)); +} + +Ref<RTCRtpSender> RTCRtpSender::create(const String& trackKind, Vector<String>&& mediaStreamIds, RTCRtpSenderClient& client) +{ + return adoptRef(*new RTCRtpSender(nullptr, trackKind, WTFMove(mediaStreamIds), client)); +} + +RTCRtpSender::RTCRtpSender(RefPtr<MediaStreamTrack>&& track, const String& trackKind, Vector<String>&& mediaStreamIds, RTCRtpSenderClient& client) + : RTCRtpSenderReceiverBase() + , m_trackKind(trackKind) + , m_mediaStreamIds(WTFMove(mediaStreamIds)) + , m_client(&client) +{ + setTrack(WTFMove(track)); +} + +void RTCRtpSender::setTrack(RefPtr<MediaStreamTrack>&& track) +{ + // Save the id from the first non-null track set. That id will be used to negotiate the sender + // even if the track is replaced. + if (!m_track && track) + m_trackId = track->id(); + + m_track = WTFMove(track); +} + +ExceptionOr<void> RTCRtpSender::replaceTrack(Ref<MediaStreamTrack>&& withTrack, DOMPromise<void>&& promise) +{ + if (isStopped()) { + promise.reject(INVALID_STATE_ERR); + return { }; + } + + if (m_trackKind != withTrack->kind()) + return Exception { TypeError }; + + m_client->replaceTrack(*this, WTFMove(withTrack), WTFMove(promise)); + + return { }; +} + +} // namespace WebCore + +#endif // ENABLE(WEB_RTC) diff --git a/Source/WebCore/Modules/mediastream/RTCRtpSender.h b/Source/WebCore/Modules/mediastream/RTCRtpSender.h new file mode 100644 index 000000000..95bea8b7b --- /dev/null +++ b/Source/WebCore/Modules/mediastream/RTCRtpSender.h @@ -0,0 +1,75 @@ +/* + * 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 "PeerConnectionBackend.h" +#include "RTCRtpSenderReceiverBase.h" + +namespace WebCore { + +class RTCRtpSenderClient { +public: + virtual void replaceTrack(RTCRtpSender&, RefPtr<MediaStreamTrack>&&, DOMPromise<void>&&) = 0; + + virtual ~RTCRtpSenderClient() { } +}; + +class RTCRtpSender : public RTCRtpSenderReceiverBase { +public: + static Ref<RTCRtpSender> create(Ref<MediaStreamTrack>&&, Vector<String>&& mediaStreamIds, RTCRtpSenderClient&); + static Ref<RTCRtpSender> create(const String& trackKind, Vector<String>&& mediaStreamIds, RTCRtpSenderClient&); + + const String& trackId() const { return m_trackId; } + const String& trackKind() const { return m_trackKind; } + + const Vector<String>& mediaStreamIds() const { return m_mediaStreamIds; } + void setMediaStreamIds(Vector<String>&& mediaStreamIds) { m_mediaStreamIds = WTFMove(mediaStreamIds); } + + bool isStopped() const { return !m_client; } + void stop() { m_client = nullptr; } + void setTrack(RefPtr<MediaStreamTrack>&&); + + ExceptionOr<void> replaceTrack(Ref<MediaStreamTrack>&&, DOMPromise<void>&&); + +private: + RTCRtpSender(RefPtr<MediaStreamTrack>&&, const String& trackKind, Vector<String>&& mediaStreamIds, RTCRtpSenderClient&); + + String m_trackId; + String m_trackKind; + Vector<String> m_mediaStreamIds; + RTCRtpSenderClient* m_client; +}; + +} // namespace WebCore + +#endif // ENABLE(WEB_RTC) diff --git a/Source/WebCore/Modules/mediastream/RTCRtpSender.idl b/Source/WebCore/Modules/mediastream/RTCRtpSender.idl new file mode 100644 index 000000000..21f91fd8e --- /dev/null +++ b/Source/WebCore/Modules/mediastream/RTCRtpSender.idl @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2015 Ericsson AB. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of Ericsson nor the names of its contributors + * may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +[ + Conditional=WEB_RTC, + EnabledAtRuntime=PeerConnection, +] interface RTCRtpSender { + readonly attribute MediaStreamTrack? track; + + [MayThrowException] Promise<void> replaceTrack(MediaStreamTrack withTrack); +}; diff --git a/Source/WebCore/Modules/mediastream/RTCRtpSenderReceiverBase.h b/Source/WebCore/Modules/mediastream/RTCRtpSenderReceiverBase.h new file mode 100644 index 000000000..3dd219a26 --- /dev/null +++ b/Source/WebCore/Modules/mediastream/RTCRtpSenderReceiverBase.h @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2015 Ericsson AB. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of Ericsson nor the names of its contributors + * may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#if ENABLE(WEB_RTC) + +#include "MediaStreamTrack.h" +#include "ScriptWrappable.h" +#include <wtf/RefCounted.h> +#include <wtf/RefPtr.h> + +namespace WebCore { + +class MediaStreamTrack; + +class RTCRtpSenderReceiverBase : public RefCounted<RTCRtpSenderReceiverBase>, public ScriptWrappable { +public: + virtual ~RTCRtpSenderReceiverBase() = default; + + MediaStreamTrack* track() { return m_track.get(); } + +protected: + RTCRtpSenderReceiverBase() = default; + + RTCRtpSenderReceiverBase(Ref<MediaStreamTrack>&& track) + : m_track(WTFMove(track)) + { } + + RefPtr<MediaStreamTrack> m_track; +}; + +} // namespace WebCore + +#endif // ENABLE(WEB_RTC) diff --git a/Source/WebCore/Modules/mediastream/RTCRtpTransceiver.cpp b/Source/WebCore/Modules/mediastream/RTCRtpTransceiver.cpp new file mode 100644 index 000000000..733db7be0 --- /dev/null +++ b/Source/WebCore/Modules/mediastream/RTCRtpTransceiver.cpp @@ -0,0 +1,110 @@ +/* + * Copyright (C) 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" +#include "RTCRtpTransceiver.h" + +#if ENABLE(WEB_RTC) + +#include <wtf/NeverDestroyed.h> + +namespace WebCore { + +#define STRING_FUNCTION(name) \ + static const String& name##String() \ + { \ + static NeverDestroyed<const String> name { ASCIILiteral(#name) }; \ + return name; \ + } + +STRING_FUNCTION(sendrecv) +STRING_FUNCTION(sendonly) +STRING_FUNCTION(recvonly) +STRING_FUNCTION(inactive) + +String RTCRtpTransceiver::getNextMid() +{ + static unsigned mid = 0; + return String::number(++mid); +} + +RTCRtpTransceiver::RTCRtpTransceiver(Ref<RTCRtpSender>&& sender, Ref<RTCRtpReceiver>&& receiver) + : m_direction(Direction::Sendrecv) + , m_sender(WTFMove(sender)) + , m_receiver(WTFMove(receiver)) + , m_iceTransport(RTCIceTransport::create()) +{ +} + +const String& RTCRtpTransceiver::directionString() const +{ + switch (m_direction) { + case Direction::Sendrecv: return sendrecvString(); + case Direction::Sendonly: return sendonlyString(); + case Direction::Recvonly: return recvonlyString(); + case Direction::Inactive: return inactiveString(); + } + + ASSERT_NOT_REACHED(); + return inactiveString(); +} + +bool RTCRtpTransceiver::hasSendingDirection() const +{ + return m_direction == Direction::Sendrecv || m_direction == Direction::Sendonly; +} + +void RTCRtpTransceiver::enableSendingDirection() +{ + if (m_direction == Direction::Recvonly) + m_direction = Direction::Sendrecv; + else if (m_direction == Direction::Inactive) + m_direction = Direction::Sendonly; +} + +void RTCRtpTransceiver::disableSendingDirection() +{ + if (m_direction == Direction::Sendrecv) + m_direction = Direction::Recvonly; + else if (m_direction == Direction::Sendonly) + m_direction = Direction::Inactive; +} + +void RtpTransceiverSet::append(Ref<RTCRtpTransceiver>&& transceiver) +{ + m_senders.append(transceiver->sender()); + m_receivers.append(transceiver->receiver()); + + m_transceivers.append(WTFMove(transceiver)); +} + +} // namespace WebCore + +#endif // ENABLE(WEB_RTC) diff --git a/Source/WebCore/Modules/mediastream/RTCRtpTransceiver.h b/Source/WebCore/Modules/mediastream/RTCRtpTransceiver.h new file mode 100644 index 000000000..e000cb2c1 --- /dev/null +++ b/Source/WebCore/Modules/mediastream/RTCRtpTransceiver.h @@ -0,0 +1,113 @@ +/* + * Copyright (C) 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 "RTCIceTransport.h" +#include "RTCRtpReceiver.h" +#include "RTCRtpSender.h" +#include "ScriptWrappable.h" +#include <wtf/RefCounted.h> +#include <wtf/RefPtr.h> +#include <wtf/text/WTFString.h> + +namespace WebCore { + +class RTCRtpTransceiver : public RefCounted<RTCRtpTransceiver>, public ScriptWrappable { +public: + // This enum is mirrored in RTCPeerConnection.h + enum class Direction { Sendrecv, Sendonly, Recvonly, Inactive }; + + static Ref<RTCRtpTransceiver> create(Ref<RTCRtpSender>&& sender, Ref<RTCRtpReceiver>&& receiver) { return adoptRef(*new RTCRtpTransceiver(WTFMove(sender), WTFMove(receiver))); } + virtual ~RTCRtpTransceiver() { } + + bool hasSendingDirection() const; + void enableSendingDirection(); + void disableSendingDirection(); + + const String& directionString() const; + Direction direction() const { return m_direction; } + void setDirection(Direction direction) { m_direction = direction; } + + const String& provisionalMid() const { return m_provisionalMid; } + void setProvisionalMid(const String& provisionalMid) { m_provisionalMid = provisionalMid; } + + const String& mid() const { return m_mid; } + void setMid(const String& mid) { m_mid = mid; } + + RTCRtpSender& sender() { return m_sender.get(); } + RTCRtpReceiver& receiver() { return m_receiver.get(); } + + bool stopped() const { return m_stopped; } + void stop() { m_stopped = true; } + + // FIXME: Temporary solution to keep track of ICE states for this transceiver. Later, each + // sender and receiver will have up to two DTLS transports, which in turn will have an ICE + // transport each. + RTCIceTransport& iceTransport() { return m_iceTransport.get(); } + + static String getNextMid(); + +private: + RTCRtpTransceiver(Ref<RTCRtpSender>&&, Ref<RTCRtpReceiver>&&); + + String m_provisionalMid; + String m_mid; + + Direction m_direction; + + Ref<RTCRtpSender> m_sender; + Ref<RTCRtpReceiver> m_receiver; + + bool m_stopped { false }; + + Ref<RTCIceTransport> m_iceTransport; +}; + +class RtpTransceiverSet { +public: + const Vector<RefPtr<RTCRtpTransceiver>>& list() const { return m_transceivers; } + void append(Ref<RTCRtpTransceiver>&&); + + const Vector<std::reference_wrapper<RTCRtpSender>>& senders() const { return m_senders; } + const Vector<std::reference_wrapper<RTCRtpReceiver>>& receivers() const { return m_receivers; } + +private: + Vector<RefPtr<RTCRtpTransceiver>> m_transceivers; + + Vector<std::reference_wrapper<RTCRtpSender>> m_senders; + Vector<std::reference_wrapper<RTCRtpReceiver>> m_receivers; +}; + +} // namespace WebCore + +#endif // ENABLE(WEB_RTC) diff --git a/Source/WebCore/Modules/mediastream/RTCRtpTransceiver.idl b/Source/WebCore/Modules/mediastream/RTCRtpTransceiver.idl new file mode 100644 index 000000000..68cf1ea48 --- /dev/null +++ b/Source/WebCore/Modules/mediastream/RTCRtpTransceiver.idl @@ -0,0 +1,46 @@ +/* + * Copyright (C) 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. + */ + +[ + Conditional=WEB_RTC, + EnabledAtRuntime=PeerConnection, +] interface RTCRtpTransceiver { + readonly attribute DOMString? mid; + readonly attribute RTCRtpSender sender; + readonly attribute RTCRtpReceiver receiver; + readonly attribute boolean stopped; + readonly attribute RTCRtpTransceiverDirection direction; + + void setDirection(RTCRtpTransceiverDirection direction); + void stop(); +}; + +// This enum is mirrored in RTCPeerConnection.idl +enum RTCRtpTransceiverDirection { "sendrecv", "sendonly", "recvonly", "inactive" }; diff --git a/Source/WebCore/Modules/mediastream/RTCSessionDescription.cpp b/Source/WebCore/Modules/mediastream/RTCSessionDescription.cpp index 85bfb5c31..4dab0632b 100644 --- a/Source/WebCore/Modules/mediastream/RTCSessionDescription.cpp +++ b/Source/WebCore/Modules/mediastream/RTCSessionDescription.cpp @@ -30,84 +30,28 @@ */ #include "config.h" - -#if ENABLE(MEDIA_STREAM) - #include "RTCSessionDescription.h" -#include "Dictionary.h" -#include "ExceptionCode.h" -#include "RTCSessionDescriptionDescriptor.h" +#if ENABLE(WEB_RTC) namespace WebCore { -static bool verifyType(const String& type) -{ - return type == "offer" || type == "pranswer" || type == "answer"; -} - -PassRefPtr<RTCSessionDescription> RTCSessionDescription::create(const Dictionary& dictionary, ExceptionCode& ec) -{ - String type; - bool ok = dictionary.get("type", type); - if (ok && !verifyType(type)) { - ec = TYPE_MISMATCH_ERR; - return nullptr; - } - - String sdp; - ok = dictionary.get("sdp", sdp); - if (ok && sdp.isEmpty()) { - ec = TYPE_MISMATCH_ERR; - return nullptr; - } - - return adoptRef(new RTCSessionDescription(RTCSessionDescriptionDescriptor::create(type, sdp))); -} - -PassRefPtr<RTCSessionDescription> RTCSessionDescription::create(PassRefPtr<RTCSessionDescriptionDescriptor> descriptor) -{ - ASSERT(descriptor); - return adoptRef(new RTCSessionDescription(descriptor)); -} - -RTCSessionDescription::RTCSessionDescription(PassRefPtr<RTCSessionDescriptionDescriptor> descriptor) - : m_descriptor(descriptor) -{ -} - -RTCSessionDescription::~RTCSessionDescription() -{ -} - -const String& RTCSessionDescription::type() const -{ - return m_descriptor->type(); -} - -void RTCSessionDescription::setType(const String& type, ExceptionCode& ec) -{ - if (verifyType(type)) - m_descriptor->setType(type); - else - ec = TYPE_MISMATCH_ERR; -} - -const String& RTCSessionDescription::sdp() const +inline RTCSessionDescription::RTCSessionDescription(SdpType type, const String& sdp) + : m_type(type) + , m_sdp(sdp) { - return m_descriptor->sdp(); } -void RTCSessionDescription::setSdp(const String& sdp) +Ref<RTCSessionDescription> RTCSessionDescription::create(const Init& dictionary) { - m_descriptor->setSdp(sdp); + return create(dictionary.type, dictionary.sdp); } -RTCSessionDescriptionDescriptor* RTCSessionDescription::descriptor() +Ref<RTCSessionDescription> RTCSessionDescription::create(SdpType type, const String& sdp) { - return m_descriptor.get(); + return adoptRef(*new RTCSessionDescription(type, sdp)); } } // namespace WebCore -#endif // ENABLE(MEDIA_STREAM) +#endif // ENABLE(WEB_RTC) diff --git a/Source/WebCore/Modules/mediastream/RTCSessionDescription.h b/Source/WebCore/Modules/mediastream/RTCSessionDescription.h index fafe2b65a..df3fc6b7a 100644 --- a/Source/WebCore/Modules/mediastream/RTCSessionDescription.h +++ b/Source/WebCore/Modules/mediastream/RTCSessionDescription.h @@ -28,44 +28,38 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef RTCSessionDescription_h -#define RTCSessionDescription_h +#pragma once -#if ENABLE(MEDIA_STREAM) +#if ENABLE(WEB_RTC) -#include "ExceptionBase.h" +#include "ExceptionOr.h" #include "ScriptWrappable.h" -#include <wtf/PassRefPtr.h> -#include <wtf/RefCounted.h> -#include <wtf/text/WTFString.h> namespace WebCore { -class Dictionary; -class RTCSessionDescriptionDescriptor; - class RTCSessionDescription : public RefCounted<RTCSessionDescription>, public ScriptWrappable { public: - static PassRefPtr<RTCSessionDescription> create(const Dictionary&, ExceptionCode&); - static PassRefPtr<RTCSessionDescription> create(PassRefPtr<RTCSessionDescriptionDescriptor>); - virtual ~RTCSessionDescription(); + enum class SdpType { Offer, Pranswer, Answer, Rollback }; - const String& type() const; - void setType(const String&, ExceptionCode&); + struct Init { + SdpType type; + String sdp; + }; + static Ref<RTCSessionDescription> create(const Init&); + static Ref<RTCSessionDescription> create(SdpType, const String& sdp); - const String& sdp() const; - void setSdp(const String&); + SdpType type() const { return m_type; } - RTCSessionDescriptionDescriptor* descriptor(); + const String& sdp() const { return m_sdp; } + void setSdp(const String& sdp) { m_sdp = sdp; } private: - explicit RTCSessionDescription(PassRefPtr<RTCSessionDescriptionDescriptor>); + explicit RTCSessionDescription(SdpType, const String& sdp); - RefPtr<RTCSessionDescriptionDescriptor> m_descriptor; + SdpType m_type; + String m_sdp; }; } // namespace WebCore -#endif // ENABLE(MEDIA_STREAM) - -#endif // RTCSessionDescription_h +#endif // ENABLE(WEB_RTC) diff --git a/Source/WebCore/Modules/mediastream/RTCSessionDescription.idl b/Source/WebCore/Modules/mediastream/RTCSessionDescription.idl index e62998b16..27c6571ea 100644 --- a/Source/WebCore/Modules/mediastream/RTCSessionDescription.idl +++ b/Source/WebCore/Modules/mediastream/RTCSessionDescription.idl @@ -30,11 +30,22 @@ */ [ - Conditional=MEDIA_STREAM, - CustomConstructor(optional Dictionary dictionary), - ConstructorRaisesException + Conditional=WEB_RTC, + Constructor(RTCSessionDescriptionInit descriptionInitDict), + EnabledAtRuntime=PeerConnection, + ImplementationLacksVTable, + PrivateIdentifier, + PublicIdentifier, ] interface RTCSessionDescription { - [SetterRaisesException] attribute DOMString type; - attribute DOMString sdp; + [SetterMayThrowException] readonly attribute RTCSdpType type; + readonly attribute DOMString sdp; + + serializer = {type, sdp}; }; +enum RTCSdpType { "offer", "pranswer", "answer", "rollback" }; + +dictionary RTCSessionDescriptionInit { + required RTCSdpType type; + DOMString sdp = ""; +}; diff --git a/Source/WebCore/Modules/mediastream/RTCSessionDescriptionRequestImpl.cpp b/Source/WebCore/Modules/mediastream/RTCSessionDescriptionRequestImpl.cpp deleted file mode 100644 index 872a54e18..000000000 --- a/Source/WebCore/Modules/mediastream/RTCSessionDescriptionRequestImpl.cpp +++ /dev/null @@ -1,95 +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. - */ - -#include "config.h" - -#if ENABLE(MEDIA_STREAM) - -#include "RTCSessionDescriptionRequestImpl.h" - -#include "RTCPeerConnection.h" -#include "RTCPeerConnectionErrorCallback.h" -#include "RTCSessionDescription.h" -#include "RTCSessionDescriptionCallback.h" -#include "RTCSessionDescriptionDescriptor.h" - -namespace WebCore { - -PassRefPtr<RTCSessionDescriptionRequestImpl> RTCSessionDescriptionRequestImpl::create(ScriptExecutionContext* context, PassRefPtr<RTCSessionDescriptionCallback> successCallback, PassRefPtr<RTCPeerConnectionErrorCallback> errorCallback) -{ - RefPtr<RTCSessionDescriptionRequestImpl> request = adoptRef(new RTCSessionDescriptionRequestImpl(context, successCallback, errorCallback)); - request->suspendIfNeeded(); - return request.release(); -} - -RTCSessionDescriptionRequestImpl::RTCSessionDescriptionRequestImpl(ScriptExecutionContext* context, PassRefPtr<RTCSessionDescriptionCallback> successCallback, PassRefPtr<RTCPeerConnectionErrorCallback> errorCallback) - : ActiveDOMObject(context) - , m_successCallback(successCallback) - , m_errorCallback(errorCallback) -{ -} - -RTCSessionDescriptionRequestImpl::~RTCSessionDescriptionRequestImpl() -{ -} - -void RTCSessionDescriptionRequestImpl::requestSucceeded(PassRefPtr<RTCSessionDescriptionDescriptor> descriptor) -{ - if (m_successCallback) { - RefPtr<RTCSessionDescription> sessionDescription = RTCSessionDescription::create(descriptor); - m_successCallback->handleEvent(sessionDescription.get()); - } - - clear(); -} - -void RTCSessionDescriptionRequestImpl::requestFailed(const String& error) -{ - if (m_errorCallback) - m_errorCallback->handleEvent(DOMError::create(error).get()); - - clear(); -} - -void RTCSessionDescriptionRequestImpl::stop() -{ - clear(); -} - -void RTCSessionDescriptionRequestImpl::clear() -{ - m_successCallback.clear(); - m_errorCallback.clear(); -} - -} // namespace WebCore - -#endif // ENABLE(MEDIA_STREAM) diff --git a/Source/WebCore/Modules/mediastream/RTCStatsCallback.h b/Source/WebCore/Modules/mediastream/RTCStatsCallback.h deleted file mode 100644 index 419b82025..000000000 --- a/Source/WebCore/Modules/mediastream/RTCStatsCallback.h +++ /dev/null @@ -1,46 +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. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef RTCStatsCallback_h -#define RTCStatsCallback_h - -#if ENABLE(MEDIA_STREAM) - -#include <wtf/RefCounted.h> - -namespace WebCore { - -class RTCStatsResponse; - -class RTCStatsCallback : public RefCounted<RTCStatsCallback> { -public: - virtual ~RTCStatsCallback() { } - virtual bool handleEvent(RTCStatsResponse*) = 0; -}; - -} // namespace WebCore - -#endif // ENABLE(MEDIA_STREAM) - -#endif // RTCStatsCallback_h diff --git a/Source/WebCore/Modules/mediastream/RTCStatsReport.cpp b/Source/WebCore/Modules/mediastream/RTCStatsReport.cpp index 27937eba3..146415b89 100644 --- a/Source/WebCore/Modules/mediastream/RTCStatsReport.cpp +++ b/Source/WebCore/Modules/mediastream/RTCStatsReport.cpp @@ -24,51 +24,12 @@ */ #include "config.h" - -#if ENABLE(MEDIA_STREAM) - #include "RTCStatsReport.h" -#include <wtf/text/StringHash.h> +#if ENABLE(WEB_RTC) namespace WebCore { -PassRefPtr<RTCStatsReport> RTCStatsReport::create(const String& id, const String& type, double timestamp) -{ - return adoptRef(new RTCStatsReport(id, type, timestamp)); -} - -RTCStatsReport::RTCStatsReport(const String& id, const String& type, double timestamp) - : m_id(id) - , m_type(type) - , m_timestamp(timestamp) -{ -} - -Vector<String> RTCStatsReport::names() const -{ - Vector<String> result; - for (HashMap<String, String>::const_iterator it = m_stats.begin(); it != m_stats.end(); ++it) { - result.append(it->key); - } - return result; -} - -const PassRefPtr<RTCStatsReport> RTCStatsReport::local() -{ - return this; -} - -const PassRefPtr<RTCStatsReport> RTCStatsReport::remote() -{ - return this; -} - -void RTCStatsReport::addStatistic(const String& name, const String& value) -{ - m_stats.add(name, value); -} - } // namespace WebCore -#endif // ENABLE(MEDIA_STREAM) +#endif // ENABLE(WEB_RTC) diff --git a/Source/WebCore/Modules/mediastream/RTCStatsReport.h b/Source/WebCore/Modules/mediastream/RTCStatsReport.h index f7b8afe29..3f4918020 100644 --- a/Source/WebCore/Modules/mediastream/RTCStatsReport.h +++ b/Source/WebCore/Modules/mediastream/RTCStatsReport.h @@ -22,44 +22,19 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef RTCStatsReport_h -#define RTCStatsReport_h +#pragma once -#include "ScriptWrappable.h" -#include <wtf/HashMap.h> -#include <wtf/PassRefPtr.h> +#include <wtf/Ref.h> #include <wtf/RefCounted.h> -#include <wtf/Vector.h> -#include <wtf/text/WTFString.h> namespace WebCore { -class RTCStatsReport : public RefCounted<RTCStatsReport>, public ScriptWrappable { +class RTCStatsReport : public RefCounted<RTCStatsReport> { public: - static PassRefPtr<RTCStatsReport> create(const String& id, const String& type, double timestamp); - - double timestamp() const { return m_timestamp; } - String id() { return m_id; } - String type() { return m_type; } - String stat(const String& name) { return m_stats.get(name); } - Vector<String> names() const; - - // DEPRECATED - const PassRefPtr<RTCStatsReport> local(); - // DEPRECATED - const PassRefPtr<RTCStatsReport> remote(); - - void addStatistic(const String& name, const String& value); + static Ref<RTCStatsReport> create() { return adoptRef(*new RTCStatsReport); } private: - RTCStatsReport(const String& id, const String& type, double timestamp); - - String m_id; - String m_type; - double m_timestamp; - HashMap<String, String> m_stats; + RTCStatsReport() = default; }; } // namespace WebCore - -#endif // RTCStatsReport_h diff --git a/Source/WebCore/Modules/mediastream/RTCStatsReport.idl b/Source/WebCore/Modules/mediastream/RTCStatsReport.idl index aa04b7358..8452534b3 100644 --- a/Source/WebCore/Modules/mediastream/RTCStatsReport.idl +++ b/Source/WebCore/Modules/mediastream/RTCStatsReport.idl @@ -24,15 +24,9 @@ [ NoInterfaceObject, - Conditional=MEDIA_STREAM, + Conditional=WEB_RTC, ImplementationLacksVTable, ] interface RTCStatsReport { - readonly attribute Date timestamp; - readonly attribute DOMString id; - readonly attribute DOMString type; - DOMString stat(DOMString name); - sequence<DOMString> names(); - // DEPRECATED - fake for old RTCStatsElement object. - readonly attribute RTCStatsReport local; - readonly attribute RTCStatsReport remote; + // FIXME: Make it setlike + //readonly maplike<DOMString, object>; }; diff --git a/Source/WebCore/Modules/mediastream/RTCStatsRequestImpl.cpp b/Source/WebCore/Modules/mediastream/RTCStatsRequestImpl.cpp deleted file mode 100644 index 26456087c..000000000 --- a/Source/WebCore/Modules/mediastream/RTCStatsRequestImpl.cpp +++ /dev/null @@ -1,92 +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. - * - * 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" - -#if ENABLE(MEDIA_STREAM) - -#include "RTCStatsRequestImpl.h" - -#include "MediaStreamTrack.h" -#include "RTCStatsCallback.h" -#include "RTCStatsRequest.h" -#include "RTCStatsResponse.h" - -namespace WebCore { - -PassRefPtr<RTCStatsRequestImpl> RTCStatsRequestImpl::create(ScriptExecutionContext* context, PassRefPtr<RTCStatsCallback> callback, PassRefPtr<MediaStreamTrack> selector) -{ - RefPtr<RTCStatsRequestImpl> request = adoptRef(new RTCStatsRequestImpl(context, callback, selector)); - request->suspendIfNeeded(); - return request.release(); -} - -RTCStatsRequestImpl::RTCStatsRequestImpl(ScriptExecutionContext* context, PassRefPtr<RTCStatsCallback> callback, PassRefPtr<MediaStreamTrack> selector) - : ActiveDOMObject(context) - , m_successCallback(callback) - , m_track(selector) -{ -} - -RTCStatsRequestImpl::~RTCStatsRequestImpl() -{ -} - -PassRefPtr<RTCStatsResponseBase> RTCStatsRequestImpl::createResponse() -{ - return RTCStatsResponse::create(); -} - -bool RTCStatsRequestImpl::hasSelector() -{ - return m_track; -} - -MediaStreamTrack* RTCStatsRequestImpl::track() -{ - return m_track.get(); -} - -void RTCStatsRequestImpl::requestSucceeded(PassRefPtr<RTCStatsResponseBase> response) -{ - if (!m_successCallback) - return; - m_successCallback->handleEvent(static_cast<RTCStatsResponse*>(response.get())); - clear(); -} - -void RTCStatsRequestImpl::stop() -{ - clear(); -} - -void RTCStatsRequestImpl::clear() -{ - m_successCallback.clear(); -} - - -} // namespace WebCore - -#endif // ENABLE(MEDIA_STREAM) diff --git a/Source/WebCore/Modules/mediastream/RTCStatsRequestImpl.h b/Source/WebCore/Modules/mediastream/RTCStatsRequestImpl.h deleted file mode 100644 index b95f4503c..000000000 --- a/Source/WebCore/Modules/mediastream/RTCStatsRequestImpl.h +++ /dev/null @@ -1,68 +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. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef RTCStatsRequestImpl_h -#define RTCStatsRequestImpl_h - -#if ENABLE(MEDIA_STREAM) - -#include "ActiveDOMObject.h" -#include "RTCStatsRequest.h" -#include "RTCStatsResponse.h" -#include <wtf/PassRefPtr.h> -#include <wtf/RefCounted.h> -#include <wtf/text/WTFString.h> - -namespace WebCore { - -class RTCStatsCallback; - -class RTCStatsRequestImpl : public RTCStatsRequest, public ActiveDOMObject { -public: - static PassRefPtr<RTCStatsRequestImpl> create(ScriptExecutionContext*, PassRefPtr<RTCStatsCallback>, PassRefPtr<MediaStreamTrack>); - virtual ~RTCStatsRequestImpl(); - - virtual PassRefPtr<RTCStatsResponseBase> createResponse() override; - virtual bool hasSelector() override; - virtual MediaStreamTrack* track() override; - - virtual void requestSucceeded(PassRefPtr<RTCStatsResponseBase>) override; - - // ActiveDOMObject - virtual void stop() override; - -private: - RTCStatsRequestImpl(ScriptExecutionContext*, PassRefPtr<RTCStatsCallback>, PassRefPtr<MediaStreamTrack>); - - void clear(); - - RefPtr<RTCStatsCallback> m_successCallback; - RefPtr<MediaStreamTrack> m_track; -}; - -} // namespace WebCore - -#endif // ENABLE(MEDIA_STREAM) - -#endif // RTCStatsRequestImpl_h diff --git a/Source/WebCore/Modules/mediastream/RTCStatsResponse.cpp b/Source/WebCore/Modules/mediastream/RTCStatsResponse.cpp deleted file mode 100644 index c3b41fe19..000000000 --- a/Source/WebCore/Modules/mediastream/RTCStatsResponse.cpp +++ /dev/null @@ -1,69 +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. - * - * 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" - -#if ENABLE(MEDIA_STREAM) - -#include "RTCStatsResponse.h" - -namespace WebCore { - -PassRefPtr<RTCStatsResponse> RTCStatsResponse::create() -{ - return adoptRef(new RTCStatsResponse()); -} - -RTCStatsResponse::RTCStatsResponse() -{ -} - -PassRefPtr<RTCStatsReport> RTCStatsResponse::namedItem(const AtomicString& name) -{ - if (m_idmap.find(name) != m_idmap.end()) - return m_result[m_idmap.get(name)]; - return nullptr; -} - -bool RTCStatsResponse::canGetItemsForName(const AtomicString& name) -{ - return m_idmap.contains(name); -} - -size_t RTCStatsResponse::addReport(String id, String type, double timestamp) -{ - m_result.append(RTCStatsReport::create(id, type, timestamp)); - m_idmap.add(id, m_result.size() - 1); - return m_result.size() - 1; -} - -void RTCStatsResponse::addStatistic(size_t report, String name, String value) -{ - ASSERT_WITH_SECURITY_IMPLICATION(report < m_result.size()); - m_result[report]->addStatistic(name, value); -} - -} // namespace WebCore - -#endif // ENABLE(MEDIA_STREAM) diff --git a/Source/WebCore/Modules/mediastream/RTCStatsResponse.h b/Source/WebCore/Modules/mediastream/RTCStatsResponse.h deleted file mode 100644 index 30e89e4a1..000000000 --- a/Source/WebCore/Modules/mediastream/RTCStatsResponse.h +++ /dev/null @@ -1,63 +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. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef RTCStatsResponse_h -#define RTCStatsResponse_h - -#include "ActiveDOMObject.h" -#include "DOMError.h" -#include "DOMStringList.h" -#include "Event.h" -#include "EventListener.h" -#include "EventNames.h" -#include "EventTarget.h" -#include "MediaStreamTrack.h" -#include "RTCStatsReport.h" -#include "RTCStatsResponseBase.h" -#include "ScriptWrappable.h" -#include <wtf/HashMap.h> - -namespace WebCore { - -class RTCStatsResponse : public RTCStatsResponseBase, public ScriptWrappable { -public: - static PassRefPtr<RTCStatsResponse> create(); - - const Vector<RefPtr<RTCStatsReport>>& result() const { return m_result; }; - - PassRefPtr<RTCStatsReport> namedItem(const AtomicString&); - bool canGetItemsForName(const AtomicString&); - - virtual size_t addReport(String id, String type, double timestamp) override; - virtual void addStatistic(size_t report, String name, String value) override; - -private: - RTCStatsResponse(); - Vector<RefPtr<RTCStatsReport>> m_result; - HashMap<String, int> m_idmap; -}; - -} // namespace WebCore - -#endif // RTCStatsResponse_h diff --git a/Source/WebCore/Modules/mediastream/RTCTrackEvent.cpp b/Source/WebCore/Modules/mediastream/RTCTrackEvent.cpp new file mode 100644 index 000000000..c090157f3 --- /dev/null +++ b/Source/WebCore/Modules/mediastream/RTCTrackEvent.cpp @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2015 Ericsson AB. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of Ericsson nor the names of its contributors + * may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "RTCTrackEvent.h" + +#if ENABLE(WEB_RTC) + +#include "MediaStream.h" +#include "MediaStreamTrack.h" +#include "RTCRtpTransceiver.h" + +namespace WebCore { + +Ref<RTCTrackEvent> RTCTrackEvent::create(const AtomicString& type, bool canBubble, bool cancelable, RefPtr<RTCRtpReceiver>&& receiver, RefPtr<MediaStreamTrack>&& track, Vector<RefPtr<MediaStream>>&& streams, RefPtr<RTCRtpTransceiver>&& transceiver) +{ + return adoptRef(*new RTCTrackEvent(type, canBubble, cancelable, WTFMove(receiver), WTFMove(track), WTFMove(streams), WTFMove(transceiver))); +} + +Ref<RTCTrackEvent> RTCTrackEvent::create(const AtomicString& type, const Init& initializer, IsTrusted isTrusted) +{ + return adoptRef(*new RTCTrackEvent(type, initializer, isTrusted)); +} + +RTCTrackEvent::RTCTrackEvent(const AtomicString& type, bool canBubble, bool cancelable, RefPtr<RTCRtpReceiver>&& receiver, RefPtr<MediaStreamTrack>&& track, Vector<RefPtr<MediaStream>>&& streams, RefPtr<RTCRtpTransceiver>&& transceiver) + : Event(type, canBubble, cancelable) + , m_receiver(WTFMove(receiver)) + , m_track(WTFMove(track)) + , m_streams(WTFMove(streams)) + , m_transceiver(WTFMove(transceiver)) +{ +} + +RTCTrackEvent::RTCTrackEvent(const AtomicString& type, const Init& initializer, IsTrusted isTrusted) + : Event(type, initializer, isTrusted) + , m_receiver(initializer.receiver) + , m_track(initializer.track) + , m_streams(initializer.streams) + , m_transceiver(initializer.transceiver) +{ +} + +} // namespace WebCore + +#endif // ENABLE(WEB_RTC) diff --git a/Source/WebCore/Modules/mediastream/RTCTrackEvent.h b/Source/WebCore/Modules/mediastream/RTCTrackEvent.h new file mode 100644 index 000000000..3617cbd36 --- /dev/null +++ b/Source/WebCore/Modules/mediastream/RTCTrackEvent.h @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2015 Ericsson AB. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of Ericsson nor the names of its contributors + * may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#if ENABLE(WEB_RTC) + +#include "Event.h" +#include <wtf/text/AtomicString.h> + +namespace WebCore { + +class MediaStream; +class MediaStreamTrack; +class RTCRtpReceiver; +class RTCRtpTransceiver; + +typedef Vector<RefPtr<MediaStream>> MediaStreamArray; + +class RTCTrackEvent : public Event { +public: + static Ref<RTCTrackEvent> create(const AtomicString& type, bool canBubble, bool cancelable, RefPtr<RTCRtpReceiver>&&, RefPtr<MediaStreamTrack>&&, MediaStreamArray&&, RefPtr<RTCRtpTransceiver>&&); + + struct Init : EventInit { + RefPtr<RTCRtpReceiver> receiver; + RefPtr<MediaStreamTrack> track; + MediaStreamArray streams; + RefPtr<RTCRtpTransceiver> transceiver; + }; + static Ref<RTCTrackEvent> create(const AtomicString& type, const Init&, IsTrusted = IsTrusted::No); + + RTCRtpReceiver* receiver() const { return m_receiver.get(); } + MediaStreamTrack* track() const { return m_track.get(); } + const MediaStreamArray& streams() const { return m_streams; } + RTCRtpTransceiver* transceiver() const { return m_transceiver.get(); } + + virtual EventInterface eventInterface() const { return RTCTrackEventInterfaceType; } + +private: + RTCTrackEvent(const AtomicString& type, bool canBubble, bool cancelable, RefPtr<RTCRtpReceiver>&&, RefPtr<MediaStreamTrack>&&, MediaStreamArray&&, RefPtr<RTCRtpTransceiver>&&); + RTCTrackEvent(const AtomicString& type, const Init&, IsTrusted); + + RefPtr<RTCRtpReceiver> m_receiver; + RefPtr<MediaStreamTrack> m_track; + MediaStreamArray m_streams; + RefPtr<RTCRtpTransceiver> m_transceiver; +}; + +} // namespace WebCore + +#endif // ENABLE(WEB_RTC) diff --git a/Source/WebCore/Modules/mediastream/RTCTrackEvent.idl b/Source/WebCore/Modules/mediastream/RTCTrackEvent.idl new file mode 100644 index 000000000..04fe5558a --- /dev/null +++ b/Source/WebCore/Modules/mediastream/RTCTrackEvent.idl @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2015 Ericsson AB. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of Ericsson nor the names of its contributors + * may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +[ + Conditional=WEB_RTC, + Constructor(DOMString type, RTCTrackEventInit eventInitDict), + EnabledAtRuntime=PeerConnection, +] interface RTCTrackEvent : Event { + readonly attribute RTCRtpReceiver receiver; + readonly attribute MediaStreamTrack track; + readonly attribute FrozenArray<MediaStream> streams; + readonly attribute RTCRtpTransceiver transceiver; +}; + +dictionary RTCTrackEventInit : EventInit { + required RTCRtpReceiver receiver; + required MediaStreamTrack track; + sequence<MediaStream> streams = []; + required RTCRtpTransceiver transceiver; +}; diff --git a/Source/WebCore/Modules/mediastream/SDPProcessor.cpp b/Source/WebCore/Modules/mediastream/SDPProcessor.cpp new file mode 100644 index 000000000..9254fdc07 --- /dev/null +++ b/Source/WebCore/Modules/mediastream/SDPProcessor.cpp @@ -0,0 +1,547 @@ +/* + * Copyright (C) 2015, 2016 Ericsson AB. 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 + * 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 "SDPProcessor.h" + +#include "CommonVM.h" +#include "Document.h" +#include "Frame.h" +#include "SDPProcessorScriptResource.h" +#include "ScriptController.h" +#include "ScriptSourceCode.h" +#include "inspector/InspectorValues.h" +#include <bindings/ScriptObject.h> +#include <wtf/NeverDestroyed.h> + +using namespace Inspector; + +namespace WebCore { + +#define STRING_FUNCTION(name) \ + static const String& name##String() \ + { \ + static NeverDestroyed<const String> name { ASCIILiteral(#name) }; \ + return name; \ + } + +STRING_FUNCTION(address) +STRING_FUNCTION(apt) +STRING_FUNCTION(candidates) +STRING_FUNCTION(ccmfir) +STRING_FUNCTION(channels) +STRING_FUNCTION(clockRate) +STRING_FUNCTION(cname) +STRING_FUNCTION(componentId) +STRING_FUNCTION(dtls) +STRING_FUNCTION(encodingName) +STRING_FUNCTION(fingerprint) +STRING_FUNCTION(fingerprintHashFunction) +STRING_FUNCTION(foundation) +STRING_FUNCTION(ice) +STRING_FUNCTION(mediaDescriptions) +STRING_FUNCTION(mediaStreamId) +STRING_FUNCTION(mediaStreamTrackId) +STRING_FUNCTION(mid) +STRING_FUNCTION(mode) +STRING_FUNCTION(mux) +STRING_FUNCTION(nack) +STRING_FUNCTION(nackpli) +STRING_FUNCTION(originator) +STRING_FUNCTION(packetizationMode) +STRING_FUNCTION(parameters) +STRING_FUNCTION(password) +STRING_FUNCTION(payloads) +STRING_FUNCTION(port) +STRING_FUNCTION(priority) +STRING_FUNCTION(relatedAddress) +STRING_FUNCTION(relatedPort) +STRING_FUNCTION(rtcp) +STRING_FUNCTION(rtcpAddress) +STRING_FUNCTION(rtcpPort) +STRING_FUNCTION(rtxTime) +STRING_FUNCTION(sessionId) +STRING_FUNCTION(sessionVersion) +STRING_FUNCTION(setup) +STRING_FUNCTION(ssrcs) +STRING_FUNCTION(tcpType) +STRING_FUNCTION(transport) +STRING_FUNCTION(type) +STRING_FUNCTION(ufrag) + +SDPProcessor::SDPProcessor(ScriptExecutionContext* context) + : ContextDestructionObserver(context) +{ +} + +// Note that MediaEndpointSessionConfiguration is a "flatter" structure that the JSON representation. For +// example, the JSON representation has an "ice" object which collects a set of properties under a +// namespace. MediaEndpointSessionConfiguration has "ice"-prefixes on the corresponding properties. + +static RefPtr<InspectorObject> createCandidateObject(const IceCandidate& candidate) +{ + RefPtr<InspectorObject> candidateObject = InspectorObject::create(); + + candidateObject->setString(typeString(), candidate.type); + candidateObject->setString(foundationString(), candidate.foundation); + candidateObject->setInteger(componentIdString(), candidate.componentId); + candidateObject->setString(transportString(), candidate.transport); + candidateObject->setInteger(priorityString(), candidate.priority); + candidateObject->setString(addressString(), candidate.address); + candidateObject->setInteger(portString(), candidate.port); + if (!candidate.tcpType.isEmpty()) + candidateObject->setString(tcpTypeString(), candidate.tcpType); + if (candidate.type.convertToASCIIUppercase() != "HOST") { + candidateObject->setString(relatedAddressString(), candidate.relatedAddress); + candidateObject->setInteger(relatedPortString(), candidate.relatedPort); + } + + return candidateObject; +} + +static IceCandidate createCandidate(const InspectorObject& candidateObject) +{ + IceCandidate candidate; + String stringValue; + unsigned intValue; + + if (candidateObject.getString(typeString(), stringValue)) + candidate.type = stringValue; + + if (candidateObject.getString(foundationString(), stringValue)) + candidate.foundation = stringValue; + + if (candidateObject.getInteger(componentIdString(), intValue)) + candidate.componentId = intValue; + + if (candidateObject.getString(transportString(), stringValue)) + candidate.transport = stringValue; + + if (candidateObject.getInteger(priorityString(), intValue)) + candidate.priority = intValue; + + if (candidateObject.getString(addressString(), stringValue)) + candidate.address = stringValue; + + if (candidateObject.getInteger(portString(), intValue)) + candidate.port = intValue; + + if (candidateObject.getString(tcpTypeString(), stringValue)) + candidate.tcpType = stringValue; + + if (candidateObject.getString(relatedAddressString(), stringValue)) + candidate.relatedAddress = stringValue; + + if (candidateObject.getInteger(relatedPortString(), intValue)) + candidate.relatedPort = intValue; + + return candidate; +} + +static RefPtr<MediaEndpointSessionConfiguration> configurationFromJSON(const String& json) +{ + RefPtr<InspectorValue> value; + if (!InspectorValue::parseJSON(json, value)) + return nullptr; + + RefPtr<InspectorObject> object; + if (!value->asObject(object)) + return nullptr; + + RefPtr<MediaEndpointSessionConfiguration> configuration = MediaEndpointSessionConfiguration::create(); + + String stringValue; + unsigned intValue; + unsigned long longValue; + bool boolValue; + + RefPtr<InspectorObject> originatorObject = InspectorObject::create(); + if (object->getObject(originatorString(), originatorObject)) { + if (originatorObject->getInteger(sessionIdString(), longValue)) + configuration->setSessionId(longValue); + if (originatorObject->getInteger(sessionVersionString(), intValue)) + configuration->setSessionVersion(intValue); + } + + RefPtr<InspectorArray> mediaDescriptionsArray = InspectorArray::create(); + object->getArray(mediaDescriptionsString(), mediaDescriptionsArray); + + for (unsigned i = 0; i < mediaDescriptionsArray->length(); ++i) { + RefPtr<InspectorObject> mediaDescriptionObject = InspectorObject::create(); + mediaDescriptionsArray->get(i)->asObject(mediaDescriptionObject); + + PeerMediaDescription mediaDescription; + + if (mediaDescriptionObject->getString(typeString(), stringValue)) + mediaDescription.type = stringValue; + + if (mediaDescriptionObject->getInteger(portString(), intValue)) + mediaDescription.port = intValue; + + if (mediaDescriptionObject->getString(addressString(), stringValue)) + mediaDescription.address = stringValue; + + if (mediaDescriptionObject->getString(modeString(), stringValue)) + mediaDescription.mode = stringValue; + + if (mediaDescriptionObject->getString(midString(), stringValue)) + mediaDescription.mid = stringValue; + + RefPtr<InspectorArray> payloadsArray = InspectorArray::create(); + mediaDescriptionObject->getArray(payloadsString(), payloadsArray); + + for (unsigned j = 0; j < payloadsArray->length(); ++j) { + RefPtr<InspectorObject> payloadsObject = InspectorObject::create(); + payloadsArray->get(j)->asObject(payloadsObject); + + MediaPayload payload; + + if (payloadsObject->getInteger(typeString(), intValue)) + payload.type = intValue; + + if (payloadsObject->getString(encodingNameString(), stringValue)) + payload.encodingName = stringValue; + + if (payloadsObject->getInteger(clockRateString(), intValue)) + payload.clockRate = intValue; + + if (payloadsObject->getInteger(channelsString(), intValue)) + payload.channels = intValue; + + if (payloadsObject->getBoolean(ccmfirString(), boolValue)) + payload.ccmfir = boolValue; + + if (payloadsObject->getBoolean(nackpliString(), boolValue)) + payload.nackpli = boolValue; + + if (payloadsObject->getBoolean(nackString(), boolValue)) + payload.nack = boolValue; + + RefPtr<InspectorObject> parametersObject = InspectorObject::create(); + if (payloadsObject->getObject(parametersString(), parametersObject)) { + if (parametersObject->getInteger(packetizationModeString(), intValue)) + payload.addParameter("packetizationMode", intValue); + + if (parametersObject->getInteger(aptString(), intValue)) + payload.addParameter("apt", intValue); + + if (parametersObject->getInteger(rtxTimeString(), intValue)) + payload.addParameter("rtxTime", intValue); + } + + mediaDescription.addPayload(WTFMove(payload)); + } + + RefPtr<InspectorObject> rtcpObject = InspectorObject::create(); + if (mediaDescriptionObject->getObject(rtcpString(), rtcpObject)) { + if (rtcpObject->getBoolean(muxString(), boolValue)) + mediaDescription.rtcpMux = boolValue; + + if (rtcpObject->getString(rtcpAddressString(), stringValue)) + mediaDescription.rtcpAddress = stringValue; + + if (rtcpObject->getInteger(rtcpPortString(), intValue)) + mediaDescription.rtcpPort = intValue; + } + + if (mediaDescriptionObject->getString(mediaStreamIdString(), stringValue)) + mediaDescription.mediaStreamId = stringValue; + + if (mediaDescriptionObject->getString(mediaStreamTrackIdString(), stringValue)) + mediaDescription.mediaStreamTrackId = stringValue; + + RefPtr<InspectorObject> dtlsObject = InspectorObject::create(); + if (mediaDescriptionObject->getObject(dtlsString(), dtlsObject)) { + if (dtlsObject->getString(setupString(), stringValue)) + mediaDescription.dtlsSetup = stringValue; + + if (dtlsObject->getString(fingerprintHashFunctionString(), stringValue)) + mediaDescription.dtlsFingerprintHashFunction = stringValue; + + if (dtlsObject->getString(fingerprintString(), stringValue)) + mediaDescription.dtlsFingerprint = stringValue; + } + + RefPtr<InspectorArray> ssrcsArray = InspectorArray::create(); + mediaDescriptionObject->getArray(ssrcsString(), ssrcsArray); + + for (unsigned j = 0; j < ssrcsArray->length(); ++j) { + ssrcsArray->get(j)->asInteger(intValue); + mediaDescription.addSsrc(intValue); + } + + if (mediaDescriptionObject->getString(cnameString(), stringValue)) + mediaDescription.cname = stringValue; + + RefPtr<InspectorObject> iceObject = InspectorObject::create(); + if (mediaDescriptionObject->getObject(iceString(), iceObject)) { + if (iceObject->getString(ufragString(), stringValue)) + mediaDescription.iceUfrag = stringValue; + + if (iceObject->getString(passwordString(), stringValue)) + mediaDescription.icePassword = stringValue; + + RefPtr<InspectorArray> candidatesArray = InspectorArray::create(); + iceObject->getArray(candidatesString(), candidatesArray); + + for (unsigned j = 0; j < candidatesArray->length(); ++j) { + RefPtr<InspectorObject> candidateObject = InspectorObject::create(); + candidatesArray->get(j)->asObject(candidateObject); + + mediaDescription.addIceCandidate(createCandidate(*candidateObject)); + } + } + + configuration->addMediaDescription(WTFMove(mediaDescription)); + } + + return configuration; +} + +static std::optional<IceCandidate> iceCandidateFromJSON(const String& json) +{ + RefPtr<InspectorValue> value; + if (!InspectorValue::parseJSON(json, value)) + return std::nullopt; + + RefPtr<InspectorObject> candidateObject; + if (!value->asObject(candidateObject)) + return std::nullopt; + + return createCandidate(*candidateObject); +} + +static String configurationToJSON(const MediaEndpointSessionConfiguration& configuration) +{ + RefPtr<InspectorObject> object = InspectorObject::create(); + + RefPtr<InspectorObject> originatorObject = InspectorObject::create(); + originatorObject->setDouble(sessionIdString(), configuration.sessionId()); + originatorObject->setInteger(sessionVersionString(), configuration.sessionVersion()); + object->setObject(originatorString(), originatorObject); + + RefPtr<InspectorArray> mediaDescriptionsArray = InspectorArray::create(); + + for (const auto& mediaDescription : configuration.mediaDescriptions()) { + RefPtr<InspectorObject> mediaDescriptionObject = InspectorObject::create(); + + mediaDescriptionObject->setString(typeString(), mediaDescription.type); + mediaDescriptionObject->setInteger(portString(), mediaDescription.port); + mediaDescriptionObject->setString(addressString(), mediaDescription.address); + mediaDescriptionObject->setString(modeString(), mediaDescription.mode); + mediaDescriptionObject->setString(midString(), mediaDescription.mid); + + RefPtr<InspectorArray> payloadsArray = InspectorArray::create(); + + for (auto& payload : mediaDescription.payloads) { + RefPtr<InspectorObject> payloadObject = InspectorObject::create(); + + payloadObject->setInteger(typeString(), payload.type); + payloadObject->setString(encodingNameString(), payload.encodingName); + payloadObject->setInteger(clockRateString(), payload.clockRate); + payloadObject->setInteger(channelsString(), payload.channels); + payloadObject->setBoolean(ccmfirString(), payload.ccmfir); + payloadObject->setBoolean(nackpliString(), payload.nackpli); + payloadObject->setBoolean(nackString(), payload.nack); + + if (!payload.parameters.isEmpty()) { + RefPtr<InspectorObject> parametersObject = InspectorObject::create(); + + for (auto& name : payload.parameters.keys()) + parametersObject->setInteger(name, payload.parameters.get(name)); + + payloadObject->setObject(parametersString(), parametersObject); + } + + payloadsArray->pushObject(payloadObject); + } + mediaDescriptionObject->setArray(payloadsString(), payloadsArray); + + RefPtr<InspectorObject> rtcpObject = InspectorObject::create(); + rtcpObject->setBoolean(muxString(), mediaDescription.rtcpMux); + rtcpObject->setString(addressString(), mediaDescription.rtcpAddress); + rtcpObject->setInteger(portString(), mediaDescription.rtcpPort); + mediaDescriptionObject->setObject(rtcpString(), rtcpObject); + + mediaDescriptionObject->setString(mediaStreamIdString(), mediaDescription.mediaStreamId); + mediaDescriptionObject->setString(mediaStreamTrackIdString(), mediaDescription.mediaStreamTrackId); + + RefPtr<InspectorObject> dtlsObject = InspectorObject::create(); + dtlsObject->setString(setupString(), mediaDescription.dtlsSetup); + dtlsObject->setString(fingerprintHashFunctionString(), mediaDescription.dtlsFingerprintHashFunction); + dtlsObject->setString(fingerprintString(), mediaDescription.dtlsFingerprint); + mediaDescriptionObject->setObject(dtlsString(), dtlsObject); + + RefPtr<InspectorArray> ssrcsArray = InspectorArray::create(); + + for (auto ssrc : mediaDescription.ssrcs) + ssrcsArray->pushDouble(ssrc); + mediaDescriptionObject->setArray(ssrcsString(), ssrcsArray); + + mediaDescriptionObject->setString(cnameString(), mediaDescription.cname); + + RefPtr<InspectorObject> iceObject = InspectorObject::create(); + iceObject->setString(ufragString(), mediaDescription.iceUfrag); + iceObject->setString(passwordString(), mediaDescription.icePassword); + + RefPtr<InspectorArray> candidatesArray = InspectorArray::create(); + + for (auto& candidate : mediaDescription.iceCandidates) + candidatesArray->pushObject(createCandidateObject(candidate)); + + iceObject->setArray(candidatesString(), candidatesArray); + mediaDescriptionObject->setObject(iceString(), iceObject); + + mediaDescriptionsArray->pushObject(mediaDescriptionObject); + } + object->setArray(mediaDescriptionsString(), mediaDescriptionsArray); + + return object->toJSONString(); +} + +static String iceCandidateToJSON(const IceCandidate& candidate) +{ + return createCandidateObject(candidate)->toJSONString(); +} + +SDPProcessor::Result SDPProcessor::generate(const MediaEndpointSessionConfiguration& configuration, String& outSdpString) const +{ + String sdpString; + if (!callScript("generate", configurationToJSON(configuration), sdpString)) + return Result::InternalError; + + outSdpString = sdpString; + return Result::Success; +} + +SDPProcessor::Result SDPProcessor::parse(const String& sdp, RefPtr<MediaEndpointSessionConfiguration>& outConfiguration) const +{ + String scriptOutput; + if (!callScript("parse", sdp, scriptOutput)) + return Result::InternalError; + + if (scriptOutput == "ParseError") + return Result::ParseError; + + RefPtr<MediaEndpointSessionConfiguration> configuration = configurationFromJSON(scriptOutput); + if (!configuration) + return Result::InternalError; + + outConfiguration = configuration; + return Result::Success; +} + +SDPProcessor::Result SDPProcessor::generateCandidateLine(const IceCandidate& candidate, String& outCandidateLine) const +{ + String candidateLine; + if (!callScript("generateCandidateLine", iceCandidateToJSON(candidate), candidateLine)) + return Result::InternalError; + + outCandidateLine = candidateLine; + return Result::Success; +} + +SDPProcessor::ParsingResult SDPProcessor::parseCandidateLine(const String& candidateLine) const +{ + String scriptOutput; + if (!callScript("parseCandidateLine", candidateLine, scriptOutput)) + return { Result::InternalError }; + + if (scriptOutput == "ParseError") + return { Result::ParseError }; + + auto candidate = iceCandidateFromJSON(scriptOutput); + if (!candidate) + return { Result::InternalError }; + return { WTFMove(candidate.value()) }; +} + +bool SDPProcessor::callScript(const String& functionName, const String& argument, String& outResult) const +{ + if (!scriptExecutionContext()) + return false; + + Document* document = downcast<Document>(scriptExecutionContext()); + if (!document->frame()) + return false; + + if (!m_isolatedWorld) + m_isolatedWorld = DOMWrapperWorld::create(commonVM()); + + ScriptController& scriptController = document->frame()->script(); + JSDOMGlobalObject* globalObject = JSC::jsCast<JSDOMGlobalObject*>(scriptController.globalObject(*m_isolatedWorld)); + JSC::VM& vm = globalObject->vm(); + JSC::JSLockHolder lock(vm); + auto scope = DECLARE_CATCH_SCOPE(vm); + JSC::ExecState* exec = globalObject->globalExec(); + + JSC::JSValue probeFunctionValue = globalObject->get(exec, JSC::Identifier::fromString(exec, "generate")); + if (!probeFunctionValue.isFunction()) { + URL scriptURL; + scriptController.evaluateInWorld(ScriptSourceCode(SDPProcessorScriptResource::scriptString(), scriptURL), *m_isolatedWorld); + if (UNLIKELY(scope.exception())) { + scope.clearException(); + return false; + } + } + + JSC::JSValue functionValue = globalObject->get(exec, JSC::Identifier::fromString(exec, functionName)); + if (!functionValue.isFunction()) + return false; + + JSC::JSObject* function = functionValue.toObject(exec); + JSC::CallData callData; + JSC::CallType callType = function->methodTable()->getCallData(function, callData); + if (callType == JSC::CallType::None) + return false; + + JSC::MarkedArgumentBuffer argList; + argList.append(JSC::jsString(exec, argument)); + + JSC::JSValue result = JSC::call(exec, function, callType, callData, globalObject, argList); + if (UNLIKELY(scope.exception())) { + LOG_ERROR("SDPProcessor script threw in function %s", functionName.ascii().data()); + scope.clearException(); + return false; + } + + if (!result.isString()) + return false; + + outResult = asString(result)->value(exec); + return true; +} + +} // namespace WebCore + +#endif // ENABLE(WEB_RTC) diff --git a/Source/WebCore/Modules/mediastream/SDPProcessor.h b/Source/WebCore/Modules/mediastream/SDPProcessor.h new file mode 100644 index 000000000..ca61c9a92 --- /dev/null +++ b/Source/WebCore/Modules/mediastream/SDPProcessor.h @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2015 Ericsson AB. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of Ericsson nor the names of its contributors + * may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#if ENABLE(WEB_RTC) + +#include "ContextDestructionObserver.h" +#include "IceCandidate.h" +#include "MediaEndpointSessionConfiguration.h" +#include <wtf/RefPtr.h> +#include <wtf/Variant.h> +#include <wtf/text/WTFString.h> + +namespace WebCore { + +class DOMWrapperWorld; +class ScriptExecutionContext; + +class SDPProcessor : public ContextDestructionObserver { +public: + enum class Result { + Success = 1, + InternalError = 2, + ParseError = 3 + }; + + SDPProcessor(ScriptExecutionContext*); + + Result generate(const MediaEndpointSessionConfiguration&, String& outSdpString) const; + Result parse(const String& sdp, RefPtr<MediaEndpointSessionConfiguration>&) const; + + Result generateCandidateLine(const IceCandidate&, String& outCandidateLine) const; + + struct ParsingResult { + Variant<IceCandidate, Result> result; + + Result parsingStatus() const { return WTF::holds_alternative<IceCandidate>(result) ? Result::Success : WTF::get<SDPProcessor::Result>(result); } + IceCandidate& candidate() { return WTF::get<IceCandidate>(result); } + }; + ParsingResult parseCandidateLine(const String& candidateLine) const; + +private: + bool callScript(const String& functionName, const String& argument, String& outResult) const; + + mutable RefPtr<DOMWrapperWorld> m_isolatedWorld; +}; + +} // namespace WebCore + +#endif // ENABLE(WEB_RTC) diff --git a/Source/WebCore/Modules/mediastream/SourceInfo.cpp b/Source/WebCore/Modules/mediastream/SourceInfo.cpp deleted file mode 100644 index b116f2fd1..000000000 --- a/Source/WebCore/Modules/mediastream/SourceInfo.cpp +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (C) 2013 Google Inc. All rights reserved. - * 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 GOOGLE 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 GOOGLE 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. - */ - -#include "config.h" -#include "SourceInfo.h" - -#if ENABLE(MEDIA_STREAM) - -#include <wtf/NeverDestroyed.h> - -namespace WebCore { - -PassRefPtr<SourceInfo> SourceInfo::create(PassRefPtr<TrackSourceInfo> trackSourceInfo) -{ - return adoptRef(new SourceInfo(trackSourceInfo)); -} - -SourceInfo::SourceInfo(PassRefPtr<TrackSourceInfo> trackSourceInfo) - : m_trackSourceInfo(trackSourceInfo) -{ -} - -const AtomicString& SourceInfo::kind() const -{ - static NeverDestroyed<AtomicString> audioKind("audio", AtomicString::ConstructFromLiteral); - static NeverDestroyed<AtomicString> videoKind("video", AtomicString::ConstructFromLiteral); - - switch (m_trackSourceInfo->kind()) { - case TrackSourceInfo::Audio: - return audioKind; - case TrackSourceInfo::Video: - return videoKind; - } - - ASSERT_NOT_REACHED(); - return emptyAtom; -} - -} // namespace WebCore - -#endif diff --git a/Source/WebCore/Modules/mediastream/SourceInfo.idl b/Source/WebCore/Modules/mediastream/SourceInfo.idl deleted file mode 100644 index d238f2d06..000000000 --- a/Source/WebCore/Modules/mediastream/SourceInfo.idl +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (C) 2013 Google Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY GOOGLE 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 GOOGLE 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. - */ - -[ - ImplementationLacksVTable, - NoInterfaceObject, - Conditional=MEDIA_STREAM, -] interface SourceInfo { - readonly attribute DOMString sourceId; - readonly attribute DOMString kind; - readonly attribute DOMString label; -}; diff --git a/Source/WebCore/Modules/mediastream/UserMediaClient.h b/Source/WebCore/Modules/mediastream/UserMediaClient.h index b847c7867..f8627acec 100644 --- a/Source/WebCore/Modules/mediastream/UserMediaClient.h +++ b/Source/WebCore/Modules/mediastream/UserMediaClient.h @@ -1,5 +1,6 @@ /* * Copyright (C) 2011 Ericsson AB. 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,15 +29,13 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef UserMediaClient_h -#define UserMediaClient_h +#pragma once #if ENABLE(MEDIA_STREAM) -#include <wtf/PassRefPtr.h> - namespace WebCore { +class MediaDevicesEnumerationRequest; class Page; class UserMediaRequest; @@ -44,17 +43,18 @@ class UserMediaClient { public: virtual void pageDestroyed() = 0; - virtual void requestPermission(PassRefPtr<UserMediaRequest>) = 0; - virtual void cancelRequest(UserMediaRequest*) = 0; + virtual void requestUserMediaAccess(UserMediaRequest&) = 0; + virtual void cancelUserMediaAccessRequest(UserMediaRequest&) = 0; + + virtual void enumerateMediaDevices(MediaDevicesEnumerationRequest&) = 0; + virtual void cancelMediaDevicesEnumerationRequest(MediaDevicesEnumerationRequest&) = 0; protected: virtual ~UserMediaClient() { } }; -void provideUserMediaTo(Page*, UserMediaClient*); +WEBCORE_EXPORT void provideUserMediaTo(Page*, UserMediaClient*); } // namespace WebCore #endif // ENABLE(MEDIA_STREAM) - -#endif // UserMediaClient_h diff --git a/Source/WebCore/Modules/mediastream/UserMediaController.cpp b/Source/WebCore/Modules/mediastream/UserMediaController.cpp index d46d4bc39..1991e1fb2 100644 --- a/Source/WebCore/Modules/mediastream/UserMediaController.cpp +++ b/Source/WebCore/Modules/mediastream/UserMediaController.cpp @@ -44,14 +44,9 @@ UserMediaController::~UserMediaController() m_client->pageDestroyed(); } -PassOwnPtr<UserMediaController> UserMediaController::create(UserMediaClient* client) -{ - return adoptPtr(new UserMediaController(client)); -} - void provideUserMediaTo(Page* page, UserMediaClient* client) { - UserMediaController::provideTo(page, UserMediaController::supplementName(), UserMediaController::create(client)); + UserMediaController::provideTo(page, UserMediaController::supplementName(), std::make_unique<UserMediaController>(client)); } } // namespace WebCore diff --git a/Source/WebCore/Modules/mediastream/UserMediaController.h b/Source/WebCore/Modules/mediastream/UserMediaController.h index 4d15c981e..707fd8e40 100644 --- a/Source/WebCore/Modules/mediastream/UserMediaController.h +++ b/Source/WebCore/Modules/mediastream/UserMediaController.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 @@ -22,49 +23,56 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef UserMediaController_h -#define UserMediaController_h +#pragma once #if ENABLE(MEDIA_STREAM) #include "Page.h" #include "UserMediaClient.h" #include "UserMediaRequest.h" -#include <wtf/PassOwnPtr.h> namespace WebCore { class UserMediaController : public Supplement<Page> { public: + explicit UserMediaController(UserMediaClient*); ~UserMediaController(); UserMediaClient* client() const { return m_client; } - void requestPermission(PassRefPtr<UserMediaRequest>); - void cancelRequest(UserMediaRequest*); - static PassOwnPtr<UserMediaController> create(UserMediaClient*); - static const char* supplementName(); - static UserMediaController* from(Page* page) { return static_cast<UserMediaController*>(Supplement<Page>::from(page, supplementName())); } + void requestUserMediaAccess(UserMediaRequest&); + void cancelUserMediaAccessRequest(UserMediaRequest&); -protected: - explicit UserMediaController(UserMediaClient*); + void enumerateMediaDevices(MediaDevicesEnumerationRequest&); + void cancelMediaDevicesEnumerationRequest(MediaDevicesEnumerationRequest&); + + WEBCORE_EXPORT static const char* supplementName(); + static UserMediaController* from(Page* page) { return static_cast<UserMediaController*>(Supplement<Page>::from(page, supplementName())); } private: UserMediaClient* m_client; }; -inline void UserMediaController::requestPermission(PassRefPtr<UserMediaRequest> request) +inline void UserMediaController::requestUserMediaAccess(UserMediaRequest& request) +{ + m_client->requestUserMediaAccess(request); +} + +inline void UserMediaController::cancelUserMediaAccessRequest(UserMediaRequest& request) +{ + m_client->cancelUserMediaAccessRequest(request); +} + +inline void UserMediaController::enumerateMediaDevices(MediaDevicesEnumerationRequest& request) { - m_client->requestPermission(request); + m_client->enumerateMediaDevices(request); } -inline void UserMediaController::cancelRequest(UserMediaRequest* request) +inline void UserMediaController::cancelMediaDevicesEnumerationRequest(MediaDevicesEnumerationRequest& request) { - m_client->cancelRequest(request); + m_client->cancelMediaDevicesEnumerationRequest(request); } } // namespace WebCore #endif // ENABLE(MEDIA_STREAM) - -#endif // UserMediaController_h diff --git a/Source/WebCore/Modules/mediastream/UserMediaRequest.cpp b/Source/WebCore/Modules/mediastream/UserMediaRequest.cpp index e438d35a2..5df3e9896 100644 --- a/Source/WebCore/Modules/mediastream/UserMediaRequest.cpp +++ b/Source/WebCore/Modules/mediastream/UserMediaRequest.cpp @@ -1,7 +1,7 @@ /* * 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-2016 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 @@ -32,68 +32,44 @@ */ #include "config.h" +#include "UserMediaRequest.h" #if ENABLE(MEDIA_STREAM) -#include "UserMediaRequest.h" - -#include "Dictionary.h" #include "Document.h" +#include "DocumentLoader.h" #include "ExceptionCode.h" +#include "JSMediaStream.h" +#include "JSOverconstrainedError.h" +#include "MainFrame.h" #include "MediaConstraintsImpl.h" -#include "MediaStream.h" -#include "MediaStreamCenter.h" -#include "MediaStreamPrivate.h" -#include "SecurityOrigin.h" +#include "RealtimeMediaSourceCenter.h" +#include "Settings.h" #include "UserMediaController.h" -#include <wtf/Functional.h> -#include <wtf/MainThread.h> namespace WebCore { -static PassRefPtr<MediaConstraints> parseOptions(const Dictionary& options, const String& mediaType, ExceptionCode& ec) -{ - RefPtr<MediaConstraints> constraints; - - Dictionary constraintsDictionary; - bool ok = options.get(mediaType, constraintsDictionary); - if (ok && !constraintsDictionary.isUndefinedOrNull()) - constraints = MediaConstraintsImpl::create(constraintsDictionary, ec); - else { - bool mediaRequested = false; - options.get(mediaType, mediaRequested); - if (mediaRequested) - constraints = MediaConstraintsImpl::create(); - } - - return constraints.release(); -} - -PassRefPtr<UserMediaRequest> UserMediaRequest::create(ScriptExecutionContext* context, UserMediaController* controller, const Dictionary& options, PassRefPtr<NavigatorUserMediaSuccessCallback> successCallback, PassRefPtr<NavigatorUserMediaErrorCallback> errorCallback, ExceptionCode& ec) +ExceptionOr<void> UserMediaRequest::start(Document& document, Ref<MediaConstraintsImpl>&& audioConstraints, Ref<MediaConstraintsImpl>&& videoConstraints, DOMPromise<IDLInterface<MediaStream>>&& promise) { - ASSERT(successCallback); - - RefPtr<MediaConstraints> audioConstraints = parseOptions(options, AtomicString("audio", AtomicString::ConstructFromLiteral), ec); - if (ec) - return nullptr; + auto* userMedia = UserMediaController::from(document.page()); + if (!userMedia) + return Exception { NOT_SUPPORTED_ERR }; // FIXME: Why is it better to return an exception here instead of rejecting the promise as we do just below? - RefPtr<MediaConstraints> videoConstraints = parseOptions(options, AtomicString("video", AtomicString::ConstructFromLiteral), ec); - if (ec) - return nullptr; - - if (!audioConstraints && !videoConstraints) - return nullptr; + if (!audioConstraints->isValid() && !videoConstraints->isValid()) { + promise.reject(TypeError); + return { }; + } - return adoptRef(new UserMediaRequest(context, controller, audioConstraints.release(), videoConstraints.release(), successCallback, errorCallback)); + adoptRef(*new UserMediaRequest(document, *userMedia, WTFMove(audioConstraints), WTFMove(videoConstraints), WTFMove(promise)))->start(); + return { }; } -UserMediaRequest::UserMediaRequest(ScriptExecutionContext* context, UserMediaController* controller, PassRefPtr<MediaConstraints> audioConstraints, PassRefPtr<MediaConstraints> videoConstraints, PassRefPtr<NavigatorUserMediaSuccessCallback> successCallback, PassRefPtr<NavigatorUserMediaErrorCallback> errorCallback) - : ContextDestructionObserver(context) - , m_audioConstraints(audioConstraints) - , m_videoConstraints(videoConstraints) - , m_controller(controller) - , m_successCallback(successCallback) - , m_errorCallback(errorCallback) +UserMediaRequest::UserMediaRequest(Document& document, UserMediaController& controller, Ref<MediaConstraintsImpl>&& audioConstraints, Ref<MediaConstraintsImpl>&& videoConstraints, DOMPromise<IDLInterface<MediaStream>>&& promise) + : ContextDestructionObserver(&document) + , m_audioConstraints(WTFMove(audioConstraints)) + , m_videoConstraints(WTFMove(videoConstraints)) + , m_controller(&controller) + , m_promise(WTFMove(promise)) { } @@ -101,126 +77,158 @@ UserMediaRequest::~UserMediaRequest() { } -SecurityOrigin* UserMediaRequest::securityOrigin() const +SecurityOrigin* UserMediaRequest::userMediaDocumentOrigin() const { - if (m_scriptExecutionContext) - return m_scriptExecutionContext->securityOrigin(); - - return nullptr; -} - -void UserMediaRequest::start() -{ - // 1 - make sure the system is capable of supporting the audio and video constraints. We don't want to ask for - // user permission if the constraints can not be suported. - MediaStreamCenter::shared().validateRequestConstraints(this, m_audioConstraints, m_videoConstraints); + if (!m_scriptExecutionContext) + return nullptr; + return m_scriptExecutionContext->securityOrigin(); } - -void UserMediaRequest::constraintsValidated() +SecurityOrigin* UserMediaRequest::topLevelDocumentOrigin() const { - if (m_controller) - callOnMainThread(bind(&UserMediaRequest::requestPermission, this)); + if (!m_scriptExecutionContext) + return nullptr; + return &m_scriptExecutionContext->topOrigin(); } -void UserMediaRequest::requestPermission() +static bool isSecure(DocumentLoader& documentLoader) { - // 2 - The constraints are valid, ask the user for access to media. - if (m_controller) - m_controller->requestPermission(this); + auto& response = documentLoader.response(); + return response.url().protocolIs("https") + && response.certificateInfo() + && !response.certificateInfo()->containsNonRootSHA1SignedCertificate(); } -void UserMediaRequest::userMediaAccessGranted() +static bool canCallGetUserMedia(Document& document, String& errorMessage) { - callOnMainThread(bind(&UserMediaRequest::createMediaStream, this)); -} + bool requiresSecureConnection = document.settings().mediaCaptureRequiresSecureConnection(); + if (requiresSecureConnection && !isSecure(*document.loader())) { + errorMessage = "Trying to call getUserMedia from an insecure document."; + return false; + } -void UserMediaRequest::createMediaStream() -{ - // 3 - the user granted access, ask platform to create the media stream descriptors. - MediaStreamCenter::shared().createMediaStream(this, m_audioConstraints, m_videoConstraints); + auto& topDocument = document.topDocument(); + if (&document != &topDocument) { + auto& topOrigin = topDocument.topOrigin(); + + if (!document.securityOrigin().isSameSchemeHostPort(topOrigin)) { + errorMessage = "Trying to call getUserMedia from a document with a different security origin than its top-level frame."; + return false; + } + + for (auto* ancestorDocument = document.parentDocument(); ancestorDocument != &topDocument; ancestorDocument = ancestorDocument->parentDocument()) { + if (requiresSecureConnection && !isSecure(*ancestorDocument->loader())) { + errorMessage = "Trying to call getUserMedia from a document with an insecure parent frame."; + return false; + } + + if (!ancestorDocument->securityOrigin().isSameSchemeHostPort(topOrigin)) { + errorMessage = "Trying to call getUserMedia from a document with a different security origin than its top-level frame."; + return false; + } + } + } + + return true; } -void UserMediaRequest::userMediaAccessDenied() +void UserMediaRequest::start() { - failedToCreateStreamWithPermissionError(); -} + if (!m_scriptExecutionContext || !m_controller) { + deny(MediaAccessDenialReason::OtherFailure, emptyString()); + return; + } -void UserMediaRequest::constraintsInvalid(const String& constraintName) -{ - failedToCreateStreamWithConstraintsError(constraintName); -} + Document& document = downcast<Document>(*m_scriptExecutionContext); -void UserMediaRequest::didCreateStream(PassRefPtr<MediaStreamPrivate> privateStream) -{ - if (!m_scriptExecutionContext || !m_successCallback) + // 10.2 - 6.3 Optionally, e.g., based on a previously-established user preference, for security reasons, + // or due to platform limitations, jump to the step labeled Permission Failure below. + String errorMessage; + if (!canCallGetUserMedia(document, errorMessage)) { + deny(MediaAccessDenialReason::PermissionDenied, emptyString()); + document.domWindow()->printErrorMessage(errorMessage); return; + } - callOnMainThread(bind(&UserMediaRequest::callSuccessHandler, this, privateStream)); + m_controller->requestUserMediaAccess(*this); } -void UserMediaRequest::callSuccessHandler(PassRefPtr<MediaStreamPrivate> privateStream) +void UserMediaRequest::allow(const String& audioDeviceUID, const String& videoDeviceUID) { - // 4 - Create the MediaStream and pass it to the success callback. - ASSERT(m_successCallback); + m_allowedAudioDeviceUID = audioDeviceUID; + m_allowedVideoDeviceUID = videoDeviceUID; - RefPtr<MediaStream> stream = MediaStream::create(*m_scriptExecutionContext, privateStream); + RefPtr<UserMediaRequest> protectedThis = this; + RealtimeMediaSourceCenter::NewMediaStreamHandler callback = [this, protectedThis = WTFMove(protectedThis)](RefPtr<MediaStreamPrivate>&& privateStream) mutable { + if (!m_scriptExecutionContext) + return; - Vector<RefPtr<MediaStreamTrack>> tracks = stream->getAudioTracks(); - for (auto iter = tracks.begin(); iter != tracks.end(); ++iter) - (*iter)->applyConstraints(m_audioConstraints); + if (!privateStream) { + deny(MediaAccessDenialReason::HardwareError, emptyString()); + return; + } - tracks = stream->getVideoTracks(); - for (auto iter = tracks.begin(); iter != tracks.end(); ++iter) - (*iter)->applyConstraints(m_videoConstraints); - - m_successCallback->handleEvent(stream.get()); -} + auto stream = MediaStream::create(*m_scriptExecutionContext, WTFMove(privateStream)); + if (stream->getTracks().isEmpty()) { + deny(MediaAccessDenialReason::HardwareError, emptyString()); + return; + } -void UserMediaRequest::failedToCreateStreamWithConstraintsError(const String& constraintName) -{ - ASSERT(!constraintName.isEmpty()); - if (!m_scriptExecutionContext) - return; + for (auto& track : stream->getAudioTracks()) + track->source().startProducingData(); - if (!m_errorCallback) - return; + for (auto& track : stream->getVideoTracks()) + track->source().startProducingData(); + + m_promise.resolve(stream); + }; - RefPtr<NavigatorUserMediaError> error = NavigatorUserMediaError::create(NavigatorUserMediaError::constraintNotSatisfiedErrorName(), constraintName); - callOnMainThread(bind(&UserMediaRequest::callErrorHandler, this, error.release())); + RealtimeMediaSourceCenter::singleton().createMediaStream(WTFMove(callback), m_allowedAudioDeviceUID, m_allowedVideoDeviceUID, &m_audioConstraints.get(), &m_videoConstraints.get()); } -void UserMediaRequest::failedToCreateStreamWithPermissionError() +void UserMediaRequest::deny(MediaAccessDenialReason reason, const String& invalidConstraint) { if (!m_scriptExecutionContext) return; - if (!m_errorCallback) - return; - - RefPtr<NavigatorUserMediaError> error = NavigatorUserMediaError::create(NavigatorUserMediaError::permissionDeniedErrorName(), emptyString()); - callOnMainThread(bind(&UserMediaRequest::callErrorHandler, this, error.release())); -} - -void UserMediaRequest::callErrorHandler(PassRefPtr<NavigatorUserMediaError> prpError) -{ - RefPtr<NavigatorUserMediaError> error = prpError; - - ASSERT(error); - - m_errorCallback->handleEvent(error.get()); + switch (reason) { + case MediaAccessDenialReason::NoConstraints: + m_promise.reject(TypeError); + break; + case MediaAccessDenialReason::UserMediaDisabled: + m_promise.reject(SECURITY_ERR); + break; + case MediaAccessDenialReason::NoCaptureDevices: + m_promise.reject(NOT_FOUND_ERR); + break; + case MediaAccessDenialReason::InvalidConstraint: + m_promise.rejectType<IDLInterface<OverconstrainedError>>(OverconstrainedError::create(invalidConstraint, ASCIILiteral("Invalid constraint")).get()); + break; + case MediaAccessDenialReason::HardwareError: + m_promise.reject(NotReadableError); + break; + case MediaAccessDenialReason::OtherFailure: + m_promise.reject(ABORT_ERR); + break; + case MediaAccessDenialReason::PermissionDenied: + m_promise.reject(NotAllowedError); + break; + } } void UserMediaRequest::contextDestroyed() { - Ref<UserMediaRequest> protect(*this); - + ContextDestructionObserver::contextDestroyed(); + Ref<UserMediaRequest> protectedThis(*this); if (m_controller) { - m_controller->cancelRequest(this); - m_controller = 0; + m_controller->cancelUserMediaAccessRequest(*this); + m_controller = nullptr; } +} - ContextDestructionObserver::contextDestroyed(); +Document* UserMediaRequest::document() const +{ + return downcast<Document>(m_scriptExecutionContext); } } // namespace WebCore diff --git a/Source/WebCore/Modules/mediastream/UserMediaRequest.h b/Source/WebCore/Modules/mediastream/UserMediaRequest.h index 6ad20fe06..316fee154 100644 --- a/Source/WebCore/Modules/mediastream/UserMediaRequest.h +++ b/Source/WebCore/Modules/mediastream/UserMediaRequest.h @@ -1,6 +1,6 @@ /* * Copyright (C) 2011 Ericsson AB. All rights reserved. - * Copyright (C) 2013 Apple Inc. All rights reserved. + * Copyright (C) 2013-2016 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 @@ -30,71 +30,66 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef UserMediaRequest_h -#define UserMediaRequest_h +#pragma once #if ENABLE(MEDIA_STREAM) #include "ActiveDOMObject.h" -#include "MediaStreamCreationClient.h" -#include "MediaStreamSource.h" -#include "NavigatorUserMediaErrorCallback.h" -#include "NavigatorUserMediaSuccessCallback.h" -#include <wtf/PassRefPtr.h> -#include <wtf/RefCounted.h> -#include <wtf/text/WTFString.h> +#include "JSDOMPromise.h" namespace WebCore { -class Dictionary; -class Document; -class MediaConstraints; -class MediaStreamPrivate; -class UserMediaController; +class MediaConstraintsImpl; +class MediaStream; class SecurityOrigin; +class UserMediaController; -typedef int ExceptionCode; - -class UserMediaRequest : public MediaStreamCreationClient, public ContextDestructionObserver { +class UserMediaRequest : public RefCounted<UserMediaRequest>, private ContextDestructionObserver { public: - static PassRefPtr<UserMediaRequest> create(ScriptExecutionContext*, UserMediaController*, const Dictionary& options, PassRefPtr<NavigatorUserMediaSuccessCallback>, PassRefPtr<NavigatorUserMediaErrorCallback>, ExceptionCode&); - ~UserMediaRequest(); + static ExceptionOr<void> start(Document&, Ref<MediaConstraintsImpl>&& audioConstraints, Ref<MediaConstraintsImpl>&& videoConstraints, DOMPromise<IDLInterface<MediaStream>>&&); - SecurityOrigin* securityOrigin() const; + virtual ~UserMediaRequest(); void start(); - void userMediaAccessGranted(); - void userMediaAccessDenied(); -private: - UserMediaRequest(ScriptExecutionContext*, UserMediaController*, PassRefPtr<MediaConstraints> audioConstraints, PassRefPtr<MediaConstraints> videoConstraints, PassRefPtr<NavigatorUserMediaSuccessCallback>, PassRefPtr<NavigatorUserMediaErrorCallback>); + WEBCORE_EXPORT void setAllowedMediaDeviceUIDs(const String& audioDeviceUID, const String& videoDeviceUID); + WEBCORE_EXPORT void allow(const String& audioDeviceUID, const String& videoDeviceUID); + + enum MediaAccessDenialReason { NoConstraints, UserMediaDisabled, NoCaptureDevices, InvalidConstraint, HardwareError, PermissionDenied, OtherFailure }; + WEBCORE_EXPORT void deny(MediaAccessDenialReason, const String& invalidConstraint); + + const Vector<String>& audioDeviceUIDs() const { return m_audioDeviceUIDs; } + const Vector<String>& videoDeviceUIDs() const { return m_videoDeviceUIDs; } + + const MediaConstraintsImpl& audioConstraints() const { return m_audioConstraints; } + const MediaConstraintsImpl& videoConstraints() const { return m_videoConstraints; } - // MediaStreamCreationClient - virtual void constraintsValidated() override final; - virtual void constraintsInvalid(const String& constraintName) override final; - virtual void didCreateStream(PassRefPtr<MediaStreamPrivate>) override final; - virtual void failedToCreateStreamWithConstraintsError(const String& constraintName) override final; - virtual void failedToCreateStreamWithPermissionError() override final; + const String& allowedAudioDeviceUID() const { return m_allowedAudioDeviceUID; } + const String& allowedVideoDeviceUID() const { return m_allowedVideoDeviceUID; } - // ContextDestructionObserver - virtual void contextDestroyed() override final; + WEBCORE_EXPORT SecurityOrigin* userMediaDocumentOrigin() const; + WEBCORE_EXPORT SecurityOrigin* topLevelDocumentOrigin() const; + WEBCORE_EXPORT Document* document() const; + +private: + UserMediaRequest(Document&, UserMediaController&, Ref<MediaConstraintsImpl>&& audioConstraints, Ref<MediaConstraintsImpl>&& videoConstraints, DOMPromise<IDLInterface<MediaStream>>&&); + + void contextDestroyed() final; - void callSuccessHandler(PassRefPtr<MediaStreamPrivate>); - void callErrorHandler(PassRefPtr<NavigatorUserMediaError>); - void requestPermission(); - void createMediaStream(); + Ref<MediaConstraintsImpl> m_audioConstraints; + Ref<MediaConstraintsImpl> m_videoConstraints; - RefPtr<MediaConstraints> m_audioConstraints; - RefPtr<MediaConstraints> m_videoConstraints; + Vector<String> m_videoDeviceUIDs; + Vector<String> m_audioDeviceUIDs; - UserMediaController* m_controller; + String m_allowedVideoDeviceUID; + String m_allowedAudioDeviceUID; - RefPtr<NavigatorUserMediaSuccessCallback> m_successCallback; - RefPtr<NavigatorUserMediaErrorCallback> m_errorCallback; + UserMediaController* m_controller; + DOMPromise<IDLInterface<MediaStream>> m_promise; + RefPtr<UserMediaRequest> m_protector; }; } // namespace WebCore #endif // ENABLE(MEDIA_STREAM) - -#endif // UserMediaRequest_h diff --git a/Source/WebCore/Modules/mediastream/VideoStreamTrack.cpp b/Source/WebCore/Modules/mediastream/VideoStreamTrack.cpp deleted file mode 100644 index 2bd432d0e..000000000 --- a/Source/WebCore/Modules/mediastream/VideoStreamTrack.cpp +++ /dev/null @@ -1,71 +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. - */ - -#include "config.h" - -#if ENABLE(MEDIA_STREAM) - -#include "VideoStreamTrack.h" - -#include "Dictionary.h" -#include "ScriptExecutionContext.h" -#include <wtf/NeverDestroyed.h> - -namespace WebCore { - -RefPtr<VideoStreamTrack> VideoStreamTrack::create(ScriptExecutionContext& context, const Dictionary& videoConstraints) -{ - return adoptRef(new VideoStreamTrack(context, *MediaStreamTrackPrivate::create(0), &videoConstraints)); -} - -RefPtr<VideoStreamTrack> VideoStreamTrack::create(ScriptExecutionContext& context, MediaStreamTrackPrivate& privateTrack) -{ - return adoptRef(new VideoStreamTrack(context, privateTrack, 0)); -} - -RefPtr<VideoStreamTrack> VideoStreamTrack::create(MediaStreamTrack& track) -{ - return adoptRef(new VideoStreamTrack(track)); -} - -VideoStreamTrack::VideoStreamTrack(ScriptExecutionContext& context, MediaStreamTrackPrivate& privateTrack, const Dictionary* videoConstraints) - : MediaStreamTrack(context, privateTrack, videoConstraints) -{ -} - -VideoStreamTrack::VideoStreamTrack(MediaStreamTrack& track) - : MediaStreamTrack(track) -{ -} - -const AtomicString& VideoStreamTrack::kind() const -{ - static NeverDestroyed<AtomicString> videoKind("video", AtomicString::ConstructFromLiteral); - return videoKind; -} - -} // namespace WebCore - -#endif // ENABLE(MEDIA_STREAM) diff --git a/Source/WebCore/Modules/mediastream/VideoStreamTrack.h b/Source/WebCore/Modules/mediastream/VideoStreamTrack.h deleted file mode 100644 index 94d0aea2c..000000000 --- a/Source/WebCore/Modules/mediastream/VideoStreamTrack.h +++ /dev/null @@ -1,59 +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 VideoStreamTrack_h -#define VideoStreamTrack_h - -#if ENABLE(MEDIA_STREAM) - -#include "MediaStreamTrack.h" -#include <wtf/RefCounted.h> -#include <wtf/Vector.h> - -namespace WebCore { - -class MediaStreamSource; -class ScriptExecutionContext; - -class VideoStreamTrack final : public MediaStreamTrack { -public: - static RefPtr<VideoStreamTrack> create(ScriptExecutionContext&, const Dictionary&); - static RefPtr<VideoStreamTrack> create(ScriptExecutionContext&, MediaStreamTrackPrivate&); - static RefPtr<VideoStreamTrack> create(MediaStreamTrack&); - - virtual ~VideoStreamTrack() { } - - virtual const AtomicString& kind() const override; - -private: - VideoStreamTrack(ScriptExecutionContext&, MediaStreamTrackPrivate&, const Dictionary*); - explicit VideoStreamTrack(MediaStreamTrack&); -}; - -} // namespace WebCore - -#endif // ENABLE(MEDIA_STREAM) - -#endif // VideoStreamTrack_h diff --git a/Source/WebCore/Modules/mediastream/libwebrtc/LibWebRTCDataChannelHandler.cpp b/Source/WebCore/Modules/mediastream/libwebrtc/LibWebRTCDataChannelHandler.cpp new file mode 100644 index 000000000..564b6d1c8 --- /dev/null +++ b/Source/WebCore/Modules/mediastream/libwebrtc/LibWebRTCDataChannelHandler.cpp @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2017 Apple Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "LibWebRTCDataChannelHandler.h" + +#if USE(LIBWEBRTC) + +#include "RTCDataChannel.h" +#include <wtf/MainThread.h> + +namespace WebCore { + +LibWebRTCDataChannelHandler::~LibWebRTCDataChannelHandler() +{ + if (m_client) + m_channel->UnregisterObserver(); +} + +void LibWebRTCDataChannelHandler::setClient(RTCDataChannelHandlerClient* client) +{ + m_client = client; + if (m_client) + m_channel->RegisterObserver(this); + else + m_channel->UnregisterObserver(); +} + +bool LibWebRTCDataChannelHandler::sendStringData(const String& text) +{ + return m_channel->Send({rtc::CopyOnWriteBuffer(text.utf8().data(), text.length()), false}); +} + +bool LibWebRTCDataChannelHandler::sendRawData(const char* data, size_t length) +{ + return m_channel->Send({rtc::CopyOnWriteBuffer(data, length), true}); +} + +void LibWebRTCDataChannelHandler::close() +{ + m_channel->Close(); +} + +void LibWebRTCDataChannelHandler::OnStateChange() +{ + RTCDataChannel::ReadyState state; + switch (m_channel->state()) { + case webrtc::DataChannelInterface::kConnecting: + state = RTCDataChannel::ReadyStateConnecting; + break; + case webrtc::DataChannelInterface::kOpen: + state = RTCDataChannel::ReadyStateOpen; + break; + case webrtc::DataChannelInterface::kClosing: + state = RTCDataChannel::ReadyStateClosing; + break; + case webrtc::DataChannelInterface::kClosed: + state = RTCDataChannel::ReadyStateClosed; + break; + } + ASSERT(m_client); + callOnMainThread([protectedClient = makeRef(*m_client), state] { + protectedClient->didChangeReadyState(state); + }); +} + +void LibWebRTCDataChannelHandler::OnMessage(const webrtc::DataBuffer& buffer) +{ + ASSERT(m_client); + std::unique_ptr<webrtc::DataBuffer> protectedBuffer(new webrtc::DataBuffer(buffer)); + callOnMainThread([protectedClient = makeRef(*m_client), buffer = WTFMove(protectedBuffer)] { + // FIXME: Ensure this is correct by adding some tests with non-ASCII characters. + const char* data = reinterpret_cast<const char*>(buffer->data.data()); + if (buffer->binary) + protectedClient->didReceiveRawData(data, buffer->size()); + else + protectedClient->didReceiveStringData(String(data, buffer->size())); + }); +} + +void LibWebRTCDataChannelHandler::OnBufferedAmountChange(uint64_t previousAmount) +{ + if (previousAmount <= m_channel->buffered_amount()) + return; + ASSERT(m_client); + callOnMainThread([protectedClient = makeRef(*m_client)] { + protectedClient->bufferedAmountIsDecreasing(); + }); +} + +} // namespace WebCore + +#endif // USE(LIBWEBRTC) diff --git a/Source/WebCore/Modules/mediastream/NavigatorUserMediaError.h b/Source/WebCore/Modules/mediastream/libwebrtc/LibWebRTCDataChannelHandler.h index ea37871da..7cc3502b7 100644 --- a/Source/WebCore/Modules/mediastream/NavigatorUserMediaError.h +++ b/Source/WebCore/Modules/mediastream/libwebrtc/LibWebRTCDataChannelHandler.h @@ -1,6 +1,5 @@ /* - * Copyright (C) 2011 Google Inc. All rights reserved. - * Copyright (C) 2013 Apple Inc. All rights reserved. + * Copyright (C) 2017 Apple Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -23,43 +22,40 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef NavigatorUserMediaError_h -#define NavigatorUserMediaError_h +#pragma once -#include "DOMError.h" -#include <wtf/PassRefPtr.h> -#include <wtf/RefCounted.h> +#if USE(LIBWEBRTC) -#if ENABLE(MEDIA_STREAM) +#include "LibWebRTCMacros.h" +#include "RTCDataChannelHandler.h" +#include <webrtc/api/datachannelinterface.h> namespace WebCore { -class NavigatorUserMediaError : public DOMError { -public: - static PassRefPtr<NavigatorUserMediaError> create(const String& name, const String& constraintName) - { - return adoptRef(new NavigatorUserMediaError(name, constraintName)); - } - - virtual ~NavigatorUserMediaError() { } - - const String& constraintName() const { return m_constraintName; } +class RTCDataChannelHandlerClient; - static const AtomicString& permissionDeniedErrorName(); - static const AtomicString& constraintNotSatisfiedErrorName(); +class LibWebRTCDataChannelHandler final : public RTCDataChannelHandler, private webrtc::DataChannelObserver { +public: + explicit LibWebRTCDataChannelHandler(rtc::scoped_refptr<webrtc::DataChannelInterface>&& channel) : m_channel(WTFMove(channel)) { ASSERT(m_channel); } + ~LibWebRTCDataChannelHandler(); private: - NavigatorUserMediaError(const String& name, const String& constraintName) - : DOMError(name) - , m_constraintName(constraintName) - { - } - - String m_constraintName; + // RTCDataChannelHandler API + void setClient(RTCDataChannelHandlerClient*) final; + bool sendStringData(const String&) final; + bool sendRawData(const char*, size_t) final; + void close() final; + size_t bufferedAmount() const final { return static_cast<size_t>(m_channel->buffered_amount()); } + + // webrtc::DataChannelObserver API + void OnStateChange(); + void OnMessage(const webrtc::DataBuffer&); + void OnBufferedAmountChange(uint64_t); + + rtc::scoped_refptr<webrtc::DataChannelInterface> m_channel; + RTCDataChannelHandlerClient* m_client { nullptr }; }; } // namespace WebCore -#endif // ENABLE(MEDIA_STREAM) - -#endif // NavigatorUserMediaError_h +#endif // USE(LIBWEBRTC) diff --git a/Source/WebCore/Modules/mediastream/libwebrtc/LibWebRTCMediaEndpoint.cpp b/Source/WebCore/Modules/mediastream/libwebrtc/LibWebRTCMediaEndpoint.cpp new file mode 100644 index 000000000..e46c31c4e --- /dev/null +++ b/Source/WebCore/Modules/mediastream/libwebrtc/LibWebRTCMediaEndpoint.cpp @@ -0,0 +1,527 @@ +/* + * Copyright (C) 2017 Apple Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "LibWebRTCMediaEndpoint.h" + +#if USE(LIBWEBRTC) + +#include "EventNames.h" +#include "LibWebRTCDataChannelHandler.h" +#include "LibWebRTCPeerConnectionBackend.h" +#include "LibWebRTCProvider.h" +#include "MediaStreamEvent.h" +#include "NotImplemented.h" +#include "PlatformStrategies.h" +#include "RTCDataChannel.h" +#include "RTCDataChannelEvent.h" +#include "RTCIceCandidate.h" +#include "RTCPeerConnection.h" +#include "RTCSessionDescription.h" +#include "RTCTrackEvent.h" +#include "RealtimeIncomingAudioSource.h" +#include "RealtimeIncomingVideoSource.h" +#include <webrtc/api/peerconnectionfactory.h> +#include <webrtc/base/physicalsocketserver.h> +#include <webrtc/p2p/base/basicpacketsocketfactory.h> +#include <webrtc/p2p/client/basicportallocator.h> +#include <wtf/MainThread.h> + +#include "CoreMediaSoftLink.h" + +namespace WebCore { + +LibWebRTCMediaEndpoint::LibWebRTCMediaEndpoint(LibWebRTCPeerConnectionBackend& peerConnection, LibWebRTCProvider& client) + : m_peerConnectionBackend(peerConnection) + , m_backend(client.createPeerConnection(*this)) + , m_createSessionDescriptionObserver(*this) + , m_setLocalSessionDescriptionObserver(*this) + , m_setRemoteSessionDescriptionObserver(*this) +{ + ASSERT(m_backend); +} + +static inline const char* sessionDescriptionType(RTCSessionDescription::SdpType sdpType) +{ + switch (sdpType) { + case RTCSessionDescription::SdpType::Offer: + return "offer"; + case RTCSessionDescription::SdpType::Pranswer: + return "pranswer"; + case RTCSessionDescription::SdpType::Answer: + return "answer"; + case RTCSessionDescription::SdpType::Rollback: + return "rollback"; + } +} + +static inline RTCSessionDescription::SdpType fromSessionDescriptionType(const webrtc::SessionDescriptionInterface& description) +{ + auto type = description.type(); + if (type == webrtc::SessionDescriptionInterface::kOffer) + return RTCSessionDescription::SdpType::Offer; + if (type == webrtc::SessionDescriptionInterface::kAnswer) + return RTCSessionDescription::SdpType::Answer; + ASSERT(type == webrtc::SessionDescriptionInterface::kPrAnswer); + return RTCSessionDescription::SdpType::Pranswer; +} + +static inline RefPtr<RTCSessionDescription> fromSessionDescription(const webrtc::SessionDescriptionInterface* description) +{ + if (!description) + return nullptr; + + std::string sdp; + description->ToString(&sdp); + String sdpString(sdp.data(), sdp.size()); + + return RTCSessionDescription::create(fromSessionDescriptionType(*description), WTFMove(sdpString)); +} + +RefPtr<RTCSessionDescription> LibWebRTCMediaEndpoint::localDescription() const +{ + // FIXME: We might want to create a new object only if the session actually changed. + return fromSessionDescription(m_backend->local_description()); +} + +RefPtr<RTCSessionDescription> LibWebRTCMediaEndpoint::remoteDescription() const +{ + // FIXME: We might want to create a new object only if the session actually changed. + return fromSessionDescription(m_backend->remote_description()); +} + +void LibWebRTCMediaEndpoint::doSetLocalDescription(RTCSessionDescription& description) +{ + webrtc::SdpParseError error; + std::unique_ptr<webrtc::SessionDescriptionInterface> sessionDescription(webrtc::CreateSessionDescription(sessionDescriptionType(description.type()), description.sdp().utf8().data(), &error)); + + if (!sessionDescription) { + String errorMessage(error.description.data(), error.description.size()); + m_peerConnectionBackend.setLocalDescriptionFailed(Exception { OperationError, WTFMove(errorMessage) }); + return; + } + m_backend->SetLocalDescription(&m_setLocalSessionDescriptionObserver, sessionDescription.release()); +} + +void LibWebRTCMediaEndpoint::doSetRemoteDescription(RTCSessionDescription& description) +{ + webrtc::SdpParseError error; + std::unique_ptr<webrtc::SessionDescriptionInterface> sessionDescription(webrtc::CreateSessionDescription(sessionDescriptionType(description.type()), description.sdp().utf8().data(), &error)); + if (!sessionDescription) { + String errorMessage(error.description.data(), error.description.size()); + m_peerConnectionBackend.setRemoteDescriptionFailed(Exception { OperationError, WTFMove(errorMessage) }); + return; + } + m_backend->SetRemoteDescription(&m_setRemoteSessionDescriptionObserver, sessionDescription.release()); +} + +static inline std::string streamId(RTCPeerConnection& connection) +{ + auto& senders = connection.getSenders(); + if (senders.size()) { + for (RTCRtpSender& sender : senders) { + auto* track = sender.track(); + if (track) { + ASSERT(sender.mediaStreamIds().size() == 1); + return std::string(sender.mediaStreamIds().first().utf8().data()); + } + } + } + return "av_label"; +} + +void LibWebRTCMediaEndpoint::doCreateOffer() +{ + m_isInitiator = true; + auto& senders = m_peerConnectionBackend.connection().getSenders(); + if (senders.size()) { + // FIXME: We only support one stream for the moment. + auto stream = LibWebRTCProvider::factory().CreateLocalMediaStream(streamId(m_peerConnectionBackend.connection())); + for (RTCRtpSender& sender : senders) { + auto* track = sender.track(); + if (track) { + ASSERT(sender.mediaStreamIds().size() == 1); + auto& source = track->source(); + if (source.type() == RealtimeMediaSource::Audio) { + auto trackSource = RealtimeOutgoingAudioSource::create(source); + auto rtcTrack = LibWebRTCProvider::factory().CreateAudioTrack(track->id().utf8().data(), trackSource.ptr()); + trackSource->setTrack(rtc::scoped_refptr<webrtc::AudioTrackInterface>(rtcTrack)); + m_peerConnectionBackend.addAudioSource(WTFMove(trackSource)); + stream->AddTrack(WTFMove(rtcTrack)); + } else { + auto videoSource = RealtimeOutgoingVideoSource::create(source); + auto videoTrack = LibWebRTCProvider::factory().CreateVideoTrack(track->id().utf8().data(), videoSource.ptr()); + m_peerConnectionBackend.addVideoSource(WTFMove(videoSource)); + stream->AddTrack(WTFMove(videoTrack)); + } + } + } + m_backend->AddStream(stream); + } + m_backend->CreateOffer(&m_createSessionDescriptionObserver, nullptr); +} + +void LibWebRTCMediaEndpoint::doCreateAnswer() +{ + m_isInitiator = false; + + auto& senders = m_peerConnectionBackend.connection().getSenders(); + if (senders.size()) { + // FIXME: We only support one stream for the moment. + auto stream = LibWebRTCProvider::factory().CreateLocalMediaStream(streamId(m_peerConnectionBackend.connection())); + for (RTCRtpSender& sender : senders) { + auto* track = sender.track(); + if (track) { + ASSERT(sender.mediaStreamIds().size() == 1); + auto& source = track->source(); + if (source.type() == RealtimeMediaSource::Audio) { + auto trackSource = RealtimeOutgoingAudioSource::create(source); + auto rtcTrack = LibWebRTCProvider::factory().CreateAudioTrack(track->id().utf8().data(), trackSource.ptr()); + trackSource->setTrack(rtc::scoped_refptr<webrtc::AudioTrackInterface>(rtcTrack)); + m_peerConnectionBackend.addAudioSource(WTFMove(trackSource)); + stream->AddTrack(WTFMove(rtcTrack)); + } else { + auto videoSource = RealtimeOutgoingVideoSource::create(source); + auto videoTrack = LibWebRTCProvider::factory().CreateVideoTrack(track->id().utf8().data(), videoSource.ptr()); + m_peerConnectionBackend.addVideoSource(WTFMove(videoSource)); + stream->AddTrack(WTFMove(videoTrack)); + } + } + } + m_backend->AddStream(stream); + } + m_backend->CreateAnswer(&m_createSessionDescriptionObserver, nullptr); +} + +void LibWebRTCMediaEndpoint::getStats(MediaStreamTrack* track, const DeferredPromise& promise) +{ + m_backend->GetStats(StatsCollector::create(*this, promise, track).get()); +} + +LibWebRTCMediaEndpoint::StatsCollector::StatsCollector(LibWebRTCMediaEndpoint& endpoint, const DeferredPromise& promise, MediaStreamTrack* track) + : m_endpoint(endpoint) + , m_promise(promise) +{ + if (track) + m_id = track->id(); +} + +void LibWebRTCMediaEndpoint::StatsCollector::OnStatsDelivered(const rtc::scoped_refptr<const webrtc::RTCStatsReport>& report) +{ + callOnMainThread([protectedThis = rtc::scoped_refptr<LibWebRTCMediaEndpoint::StatsCollector>(this), report] { + if (protectedThis->m_endpoint.isStopped()) + return; + + // FIXME: Fulfill promise with the report + UNUSED_PARAM(report); + + protectedThis->m_endpoint.m_peerConnectionBackend.getStatsFailed(protectedThis->m_promise, Exception { TypeError, ASCIILiteral("Stats API is not yet implemented") }); + }); +} + +static PeerConnectionStates::SignalingState signalingState(webrtc::PeerConnectionInterface::SignalingState state) +{ + switch (state) { + case webrtc::PeerConnectionInterface::kStable: + return PeerConnectionStates::SignalingState::Stable; + case webrtc::PeerConnectionInterface::kHaveLocalOffer: + return PeerConnectionStates::SignalingState::HaveLocalOffer; + case webrtc::PeerConnectionInterface::kHaveLocalPrAnswer: + return PeerConnectionStates::SignalingState::HaveLocalPrAnswer; + case webrtc::PeerConnectionInterface::kHaveRemoteOffer: + return PeerConnectionStates::SignalingState::HaveRemoteOffer; + case webrtc::PeerConnectionInterface::kHaveRemotePrAnswer: + return PeerConnectionStates::SignalingState::HaveRemotePrAnswer; + case webrtc::PeerConnectionInterface::kClosed: + return PeerConnectionStates::SignalingState::Closed; + } +} + +void LibWebRTCMediaEndpoint::OnSignalingChange(webrtc::PeerConnectionInterface::SignalingState rtcState) +{ + auto state = signalingState(rtcState); + callOnMainThread([protectedThis = makeRef(*this), state] { + if (protectedThis->isStopped()) + return; + protectedThis->m_peerConnectionBackend.updateSignalingState(state); + }); +} + +static inline String trackId(webrtc::MediaStreamTrackInterface& videoTrack) +{ + return String(videoTrack.id().data(), videoTrack.id().size()); +} + +static inline Ref<MediaStreamTrack> createMediaStreamTrack(ScriptExecutionContext& context, Ref<RealtimeMediaSource>&& remoteSource) +{ + String trackId = remoteSource->id(); + return MediaStreamTrack::create(context, MediaStreamTrackPrivate::create(WTFMove(remoteSource), WTFMove(trackId))); +} + +void LibWebRTCMediaEndpoint::addStream(webrtc::MediaStreamInterface& stream) +{ + MediaStreamTrackVector tracks; + for (auto& videoTrack : stream.GetVideoTracks()) { + ASSERT(videoTrack); + String id = trackId(*videoTrack); + auto remoteSource = RealtimeIncomingVideoSource::create(WTFMove(videoTrack), WTFMove(id)); + tracks.append(createMediaStreamTrack(*m_peerConnectionBackend.connection().scriptExecutionContext(), WTFMove(remoteSource))); + } + for (auto& audioTrack : stream.GetAudioTracks()) { + ASSERT(audioTrack); + String id = trackId(*audioTrack); + auto remoteSource = RealtimeIncomingAudioSource::create(WTFMove(audioTrack), WTFMove(id)); + tracks.append(createMediaStreamTrack(*m_peerConnectionBackend.connection().scriptExecutionContext(), WTFMove(remoteSource))); + } + + auto newStream = MediaStream::create(*m_peerConnectionBackend.connection().scriptExecutionContext(), WTFMove(tracks)); + m_peerConnectionBackend.connection().fireEvent(MediaStreamEvent::create(eventNames().addstreamEvent, false, false, newStream.copyRef())); + + Vector<RefPtr<MediaStream>> streams; + streams.append(newStream.copyRef()); + for (auto& track : newStream->getTracks()) + m_peerConnectionBackend.connection().fireEvent(RTCTrackEvent::create(eventNames().trackEvent, false, false, nullptr, track.get(), Vector<RefPtr<MediaStream>>(streams), nullptr)); +} + +void LibWebRTCMediaEndpoint::OnAddStream(rtc::scoped_refptr<webrtc::MediaStreamInterface> stream) +{ + callOnMainThread([protectedThis = makeRef(*this), stream = WTFMove(stream)] { + if (protectedThis->isStopped()) + return; + ASSERT(stream); + protectedThis->addStream(*stream.get()); + }); +} + +void LibWebRTCMediaEndpoint::OnRemoveStream(rtc::scoped_refptr<webrtc::MediaStreamInterface>) +{ + notImplemented(); +} + +std::unique_ptr<RTCDataChannelHandler> LibWebRTCMediaEndpoint::createDataChannel(const String& label, const RTCDataChannelInit& options) +{ + webrtc::DataChannelInit init; + init.ordered = options.ordered; + init.maxRetransmitTime = options.maxRetransmitTime; + init.maxRetransmits = options.maxRetransmits; + init.protocol = options.protocol.utf8().data(); + init.negotiated = options.negotiated; + init.id = options.id; + + return std::make_unique<LibWebRTCDataChannelHandler>(m_backend->CreateDataChannel(label.utf8().data(), &init)); +} + +void LibWebRTCMediaEndpoint::addDataChannel(rtc::scoped_refptr<webrtc::DataChannelInterface>&& dataChannel) +{ + auto protocol = dataChannel->protocol(); + auto label = dataChannel->label(); + + RTCDataChannelInit init; + init.ordered = dataChannel->ordered(); + init.maxRetransmitTime = dataChannel->maxRetransmitTime(); + init.maxRetransmits = dataChannel->maxRetransmits(); + init.protocol = String(protocol.data(), protocol.size()); + init.negotiated = dataChannel->negotiated(); + init.id = dataChannel->id(); + + bool isOpened = dataChannel->state() == webrtc::DataChannelInterface::kOpen; + + auto handler = std::make_unique<LibWebRTCDataChannelHandler>(WTFMove(dataChannel)); + ASSERT(m_peerConnectionBackend.connection().scriptExecutionContext()); + auto channel = RTCDataChannel::create(*m_peerConnectionBackend.connection().scriptExecutionContext(), WTFMove(handler), String(label.data(), label.size()), WTFMove(init)); + + if (isOpened) { + callOnMainThread([channel = channel.copyRef()] { + // FIXME: We should be able to write channel->didChangeReadyState(...) + RTCDataChannelHandlerClient& client = channel.get(); + client.didChangeReadyState(RTCDataChannel::ReadyStateOpen); + }); + } + + m_peerConnectionBackend.connection().fireEvent(RTCDataChannelEvent::create(eventNames().datachannelEvent, false, false, WTFMove(channel))); +} + +void LibWebRTCMediaEndpoint::OnDataChannel(rtc::scoped_refptr<webrtc::DataChannelInterface> dataChannel) +{ + callOnMainThread([protectedThis = makeRef(*this), dataChannel = WTFMove(dataChannel)] { + if (protectedThis->isStopped()) + return; + protectedThis->addDataChannel(rtc::scoped_refptr<webrtc::DataChannelInterface>(dataChannel)); + }); +} + +void LibWebRTCMediaEndpoint::stop() +{ + ASSERT(m_backend); + m_backend->Close(); + m_backend = nullptr; +} + +void LibWebRTCMediaEndpoint::OnRenegotiationNeeded() +{ + callOnMainThread([protectedThis = makeRef(*this)] { + if (protectedThis->isStopped()) + return; + protectedThis->m_peerConnectionBackend.markAsNeedingNegotiation(); + }); +} + +static inline PeerConnectionStates::IceConnectionState iceConnectionState(webrtc::PeerConnectionInterface::IceConnectionState state) +{ + switch (state) { + case webrtc::PeerConnectionInterface::kIceConnectionNew: + return PeerConnectionStates::IceConnectionState::New; + case webrtc::PeerConnectionInterface::kIceConnectionChecking: + return PeerConnectionStates::IceConnectionState::Checking; + case webrtc::PeerConnectionInterface::kIceConnectionConnected: + return PeerConnectionStates::IceConnectionState::Connected; + case webrtc::PeerConnectionInterface::kIceConnectionCompleted: + return PeerConnectionStates::IceConnectionState::Completed; + case webrtc::PeerConnectionInterface::kIceConnectionFailed: + return PeerConnectionStates::IceConnectionState::Failed; + case webrtc::PeerConnectionInterface::kIceConnectionDisconnected: + return PeerConnectionStates::IceConnectionState::Disconnected; + case webrtc::PeerConnectionInterface::kIceConnectionClosed: + return PeerConnectionStates::IceConnectionState::Closed; + case webrtc::PeerConnectionInterface::kIceConnectionMax: + ASSERT_NOT_REACHED(); + return PeerConnectionStates::IceConnectionState::New; + } +} + +void LibWebRTCMediaEndpoint::OnIceConnectionChange(webrtc::PeerConnectionInterface::IceConnectionState state) +{ + auto connectionState = iceConnectionState(state); + callOnMainThread([protectedThis = makeRef(*this), connectionState] { + if (protectedThis->isStopped()) + return; + if (protectedThis->m_peerConnectionBackend.connection().internalIceConnectionState() != connectionState) + protectedThis->m_peerConnectionBackend.connection().updateIceConnectionState(connectionState); + }); +} + +void LibWebRTCMediaEndpoint::OnIceGatheringChange(webrtc::PeerConnectionInterface::IceGatheringState state) +{ + if (state == webrtc::PeerConnectionInterface::kIceGatheringComplete) { + callOnMainThread([protectedThis = makeRef(*this)] { + if (protectedThis->isStopped()) + return; + protectedThis->m_peerConnectionBackend.doneGatheringCandidates(); + }); + } +} + +void LibWebRTCMediaEndpoint::OnIceCandidate(const webrtc::IceCandidateInterface *rtcCandidate) +{ + ASSERT(rtcCandidate); + + std::string sdp; + rtcCandidate->ToString(&sdp); + String candidateSDP(sdp.data(), sdp.size()); + + auto mid = rtcCandidate->sdp_mid(); + String candidateMid(mid.data(), mid.size()); + + callOnMainThread([protectedThis = makeRef(*this), mid = WTFMove(candidateMid), sdp = WTFMove(candidateSDP)] { + if (protectedThis->isStopped()) + return; + protectedThis->m_peerConnectionBackend.fireICECandidateEvent(RTCIceCandidate::create(String(sdp), String(mid), 0)); + }); +} + +void LibWebRTCMediaEndpoint::OnIceCandidatesRemoved(const std::vector<cricket::Candidate>&) +{ + ASSERT_NOT_REACHED(); +} + +void LibWebRTCMediaEndpoint::createSessionDescriptionSucceeded(webrtc::SessionDescriptionInterface* description) +{ + std::string sdp; + description->ToString(&sdp); + String sdpString(sdp.data(), sdp.size()); + + callOnMainThread([protectedThis = makeRef(*this), sdp = WTFMove(sdpString)] { + if (protectedThis->isStopped()) + return; + if (protectedThis->m_isInitiator) + protectedThis->m_peerConnectionBackend.createOfferSucceeded(String(sdp)); + else + protectedThis->m_peerConnectionBackend.createAnswerSucceeded(String(sdp)); + }); +} + +void LibWebRTCMediaEndpoint::createSessionDescriptionFailed(const std::string& errorMessage) +{ + String error(errorMessage.data(), errorMessage.size()); + callOnMainThread([protectedThis = makeRef(*this), error = WTFMove(error)] { + if (protectedThis->isStopped()) + return; + if (protectedThis->m_isInitiator) + protectedThis->m_peerConnectionBackend.createOfferFailed(Exception { OperationError, String(error) }); + else + protectedThis->m_peerConnectionBackend.createAnswerFailed(Exception { OperationError, String(error) }); + }); +} + +void LibWebRTCMediaEndpoint::setLocalSessionDescriptionSucceeded() +{ + callOnMainThread([protectedThis = makeRef(*this)] { + if (protectedThis->isStopped()) + return; + protectedThis->m_peerConnectionBackend.setLocalDescriptionSucceeded(); + }); +} + +void LibWebRTCMediaEndpoint::setLocalSessionDescriptionFailed(const std::string& errorMessage) +{ + String error(errorMessage.data(), errorMessage.size()); + callOnMainThread([protectedThis = makeRef(*this), error = WTFMove(error)] { + if (protectedThis->isStopped()) + return; + protectedThis->m_peerConnectionBackend.setLocalDescriptionFailed(Exception { OperationError, String(error) }); + }); +} + +void LibWebRTCMediaEndpoint::setRemoteSessionDescriptionSucceeded() +{ + callOnMainThread([protectedThis = makeRef(*this)] { + if (protectedThis->isStopped()) + return; + protectedThis->m_peerConnectionBackend.setRemoteDescriptionSucceeded(); + }); +} + +void LibWebRTCMediaEndpoint::setRemoteSessionDescriptionFailed(const std::string& errorMessage) +{ + String error(errorMessage.data(), errorMessage.size()); + callOnMainThread([protectedThis = makeRef(*this), error = WTFMove(error)] { + if (protectedThis->isStopped()) + return; + protectedThis->m_peerConnectionBackend.setRemoteDescriptionFailed(Exception { OperationError, String(error) }); + }); +} + +} // namespace WebCore + +#endif // USE(LIBWEBRTC) diff --git a/Source/WebCore/Modules/mediastream/libwebrtc/LibWebRTCMediaEndpoint.h b/Source/WebCore/Modules/mediastream/libwebrtc/LibWebRTCMediaEndpoint.h new file mode 100644 index 000000000..7b308e0b1 --- /dev/null +++ b/Source/WebCore/Modules/mediastream/libwebrtc/LibWebRTCMediaEndpoint.h @@ -0,0 +1,175 @@ +/* + * Copyright (C) 2017 Apple Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#if USE(LIBWEBRTC) + +#include "LibWebRTCProvider.h" +#include "PeerConnectionBackend.h" +#include "RealtimeOutgoingAudioSource.h" +#include "RealtimeOutgoingVideoSource.h" + +#include <webrtc/api/jsep.h> +#include <webrtc/api/peerconnectionfactory.h> +#include <webrtc/api/peerconnectioninterface.h> +#include <webrtc/api/rtcstatscollector.h> + +#include <wtf/ThreadSafeRefCounted.h> + +namespace webrtc { +class CreateSessionDescriptionObserver; +class DataChannelInterface; +class IceCandidateInterface; +class MediaStreamInterface; +class PeerConnectionObserver; +class SessionDescriptionInterface; +class SetSessionDescriptionObserver; +} + +namespace WebCore { + +class LibWebRTCProvider; +class LibWebRTCPeerConnectionBackend; +class MediaStreamTrack; +class RTCSessionDescription; + +class LibWebRTCMediaEndpoint : public ThreadSafeRefCounted<LibWebRTCMediaEndpoint>, private webrtc::PeerConnectionObserver { +public: + static Ref<LibWebRTCMediaEndpoint> create(LibWebRTCPeerConnectionBackend& peerConnection, LibWebRTCProvider& client) { return adoptRef(*new LibWebRTCMediaEndpoint(peerConnection, client)); } + virtual ~LibWebRTCMediaEndpoint() { } + + webrtc::PeerConnectionInterface& backend() const { ASSERT(m_backend); return *m_backend.get(); } + void doSetLocalDescription(RTCSessionDescription&); + void doSetRemoteDescription(RTCSessionDescription&); + void doCreateOffer(); + void doCreateAnswer(); + void getStats(MediaStreamTrack*, const DeferredPromise&); + std::unique_ptr<RTCDataChannelHandler> createDataChannel(const String&, const RTCDataChannelInit&); + bool addIceCandidate(webrtc::IceCandidateInterface& candidate) { return m_backend->AddIceCandidate(&candidate); } + + void stop(); + bool isStopped() const { return !m_backend; } + + RefPtr<RTCSessionDescription> localDescription() const; + RefPtr<RTCSessionDescription> remoteDescription() const; + +private: + LibWebRTCMediaEndpoint(LibWebRTCPeerConnectionBackend&, LibWebRTCProvider&); + + // webrtc::PeerConnectionObserver API + void OnSignalingChange(webrtc::PeerConnectionInterface::SignalingState) final; + void OnAddStream(rtc::scoped_refptr<webrtc::MediaStreamInterface>) final; + void OnRemoveStream(rtc::scoped_refptr<webrtc::MediaStreamInterface>) final; + void OnDataChannel(rtc::scoped_refptr<webrtc::DataChannelInterface>) final; + void OnRenegotiationNeeded() final; + void OnIceConnectionChange(webrtc::PeerConnectionInterface::IceConnectionState) final; + void OnIceGatheringChange(webrtc::PeerConnectionInterface::IceGatheringState) final; + void OnIceCandidate(const webrtc::IceCandidateInterface*) final; + void OnIceCandidatesRemoved(const std::vector<cricket::Candidate>&) final; + + void createSessionDescriptionSucceeded(webrtc::SessionDescriptionInterface*); + void createSessionDescriptionFailed(const std::string&); + void setLocalSessionDescriptionSucceeded(); + void setLocalSessionDescriptionFailed(const std::string&); + void setRemoteSessionDescriptionSucceeded(); + void setRemoteSessionDescriptionFailed(const std::string&); + void addStream(webrtc::MediaStreamInterface&); + void addDataChannel(rtc::scoped_refptr<webrtc::DataChannelInterface>&&); + + int AddRef() const { ref(); return static_cast<int>(refCount()); } + int Release() const { deref(); return static_cast<int>(refCount()); } + + class CreateSessionDescriptionObserver final : public webrtc::CreateSessionDescriptionObserver { + public: + explicit CreateSessionDescriptionObserver(LibWebRTCMediaEndpoint &endpoint) : m_endpoint(endpoint) { } + + void OnSuccess(webrtc::SessionDescriptionInterface* sessionDescription) final { m_endpoint.createSessionDescriptionSucceeded(sessionDescription); } + void OnFailure(const std::string& error) final { m_endpoint.createSessionDescriptionFailed(error); } + + int AddRef() const { return m_endpoint.AddRef(); } + int Release() const { return m_endpoint.Release(); } + + private: + LibWebRTCMediaEndpoint& m_endpoint; + }; + + class SetLocalSessionDescriptionObserver final : public webrtc::SetSessionDescriptionObserver { + public: + explicit SetLocalSessionDescriptionObserver(LibWebRTCMediaEndpoint &endpoint) : m_endpoint(endpoint) { } + + void OnSuccess() final { m_endpoint.setLocalSessionDescriptionSucceeded(); } + void OnFailure(const std::string& error) final { m_endpoint.setLocalSessionDescriptionFailed(error); } + + int AddRef() const { return m_endpoint.AddRef(); } + int Release() const { return m_endpoint.Release(); } + + private: + LibWebRTCMediaEndpoint& m_endpoint; + }; + + class SetRemoteSessionDescriptionObserver final : public webrtc::SetSessionDescriptionObserver { + public: + explicit SetRemoteSessionDescriptionObserver(LibWebRTCMediaEndpoint &endpoint) : m_endpoint(endpoint) { } + + void OnSuccess() final { m_endpoint.setRemoteSessionDescriptionSucceeded(); } + void OnFailure(const std::string& error) final { m_endpoint.setRemoteSessionDescriptionFailed(error); } + + int AddRef() const { return m_endpoint.AddRef(); } + int Release() const { return m_endpoint.Release(); } + + private: + LibWebRTCMediaEndpoint& m_endpoint; + }; + + class StatsCollector final : public webrtc::RTCStatsCollectorCallback { + public: + static rtc::scoped_refptr<StatsCollector> create(LibWebRTCMediaEndpoint& endpoint, const DeferredPromise& promise, MediaStreamTrack* track) { return new StatsCollector(endpoint, promise, track); } + + int AddRef() const { return m_endpoint.AddRef(); } + int Release() const { return m_endpoint.Release(); } + + private: + StatsCollector(LibWebRTCMediaEndpoint&, const DeferredPromise&, MediaStreamTrack*); + + void OnStatsDelivered(const rtc::scoped_refptr<const webrtc::RTCStatsReport>&) final; + + LibWebRTCMediaEndpoint& m_endpoint; + const DeferredPromise& m_promise; + String m_id; + }; + + LibWebRTCPeerConnectionBackend& m_peerConnectionBackend; + rtc::scoped_refptr<webrtc::PeerConnectionInterface> m_backend; + + CreateSessionDescriptionObserver m_createSessionDescriptionObserver; + SetLocalSessionDescriptionObserver m_setLocalSessionDescriptionObserver; + SetRemoteSessionDescriptionObserver m_setRemoteSessionDescriptionObserver; + + bool m_isInitiator { false }; +}; + +} // namespace WebCore + +#endif // USE(LIBWEBRTC) diff --git a/Source/WebCore/Modules/mediastream/libwebrtc/LibWebRTCPeerConnectionBackend.cpp b/Source/WebCore/Modules/mediastream/libwebrtc/LibWebRTCPeerConnectionBackend.cpp new file mode 100644 index 000000000..c8a382c5b --- /dev/null +++ b/Source/WebCore/Modules/mediastream/libwebrtc/LibWebRTCPeerConnectionBackend.cpp @@ -0,0 +1,231 @@ +/* + * Copyright (C) 2017 Apple Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "LibWebRTCPeerConnectionBackend.h" + +#if USE(LIBWEBRTC) + +#include "Document.h" +#include "IceCandidate.h" +#include "JSRTCStatsReport.h" +#include "LibWebRTCDataChannelHandler.h" +#include "LibWebRTCMediaEndpoint.h" +#include "MediaEndpointConfiguration.h" +#include "Page.h" +#include "RTCIceCandidate.h" +#include "RTCPeerConnection.h" +#include "RTCRtpReceiver.h" +#include "RTCSessionDescription.h" +#include "RealtimeIncomingAudioSource.h" +#include "RealtimeIncomingVideoSource.h" + +namespace WebCore { + +static std::unique_ptr<PeerConnectionBackend> createLibWebRTCPeerConnectionBackend(RTCPeerConnection& peerConnection) +{ + return std::make_unique<LibWebRTCPeerConnectionBackend>(peerConnection); +} + +CreatePeerConnectionBackend PeerConnectionBackend::create = createLibWebRTCPeerConnectionBackend; + +static inline LibWebRTCProvider& libWebRTCProvider(RTCPeerConnection& peerConnection) +{ + ASSERT(peerConnection.scriptExecutionContext()->isDocument()); + auto* page = static_cast<Document*>(peerConnection.scriptExecutionContext())->page(); + return page->libWebRTCProvider(); +} + +LibWebRTCPeerConnectionBackend::LibWebRTCPeerConnectionBackend(RTCPeerConnection& peerConnection) + : PeerConnectionBackend(peerConnection) + , m_endpoint(LibWebRTCMediaEndpoint::create(*this, libWebRTCProvider(peerConnection))) +{ +} + +LibWebRTCPeerConnectionBackend::~LibWebRTCPeerConnectionBackend() +{ +} + +static webrtc::PeerConnectionInterface::RTCConfiguration configurationFromMediaEndpointConfiguration(MediaEndpointConfiguration&& configuration) +{ + webrtc::PeerConnectionInterface::RTCConfiguration rtcConfiguration(webrtc::PeerConnectionInterface::RTCConfigurationType::kAggressive); + + if (configuration.iceTransportPolicy == PeerConnectionStates::IceTransportPolicy::Relay) + rtcConfiguration.type = webrtc::PeerConnectionInterface::kRelay; + + if (configuration.bundlePolicy == PeerConnectionStates::BundlePolicy::MaxBundle) + rtcConfiguration.bundle_policy = webrtc::PeerConnectionInterface::kBundlePolicyMaxBundle; + else if (configuration.bundlePolicy == PeerConnectionStates::BundlePolicy::MaxCompat) + rtcConfiguration.bundle_policy = webrtc::PeerConnectionInterface::kBundlePolicyMaxCompat; + + for (auto& server : configuration.iceServers) { + webrtc::PeerConnectionInterface::IceServer iceServer; + iceServer.username = server.username.utf8().data(); + iceServer.password = server.credential.utf8().data(); + for (auto& url : server.urls) + iceServer.urls.push_back({ url.string().utf8().data() }); + rtcConfiguration.servers.push_back(WTFMove(iceServer)); + } + + return rtcConfiguration; +} + +void LibWebRTCPeerConnectionBackend::setConfiguration(MediaEndpointConfiguration&& configuration) +{ + m_endpoint->backend().SetConfiguration(configurationFromMediaEndpointConfiguration(WTFMove(configuration))); +} + +void LibWebRTCPeerConnectionBackend::getStats(MediaStreamTrack* track, Ref<DeferredPromise>&& promise) +{ + if (m_endpoint->isStopped()) + return; + + auto& statsPromise = promise.get(); + m_statsPromises.add(&statsPromise, WTFMove(promise)); + m_endpoint->getStats(track, statsPromise); +} + +void LibWebRTCPeerConnectionBackend::getStatsSucceeded(const DeferredPromise& promise, Ref<RTCStatsReport>&& report) +{ + auto statsPromise = m_statsPromises.take(&promise); + ASSERT(statsPromise); + statsPromise.value()->resolve<IDLInterface<RTCStatsReport>>(WTFMove(report)); +} + +void LibWebRTCPeerConnectionBackend::getStatsFailed(const DeferredPromise& promise, Exception&& exception) +{ + auto statsPromise = m_statsPromises.take(&promise); + ASSERT(statsPromise); + statsPromise.value()->reject(WTFMove(exception)); +} + +void LibWebRTCPeerConnectionBackend::doSetLocalDescription(RTCSessionDescription& description) +{ + m_endpoint->doSetLocalDescription(description); + if (!m_isLocalDescriptionSet) { + if (m_isRemoteDescriptionSet) { + while (m_pendingCandidates.size()) + m_endpoint->addIceCandidate(*m_pendingCandidates.takeLast().release()); + } + m_isLocalDescriptionSet = true; + } +} + +void LibWebRTCPeerConnectionBackend::doSetRemoteDescription(RTCSessionDescription& description) +{ + m_endpoint->doSetRemoteDescription(description); + if (!m_isRemoteDescriptionSet) { + if (m_isLocalDescriptionSet) { + while (m_pendingCandidates.size()) + m_endpoint->addIceCandidate(*m_pendingCandidates.takeLast().release()); + } + m_isRemoteDescriptionSet = true; + } +} + +void LibWebRTCPeerConnectionBackend::doCreateOffer(RTCOfferOptions&&) +{ + m_endpoint->doCreateOffer(); +} + +void LibWebRTCPeerConnectionBackend::doCreateAnswer(RTCAnswerOptions&&) +{ + if (!m_isRemoteDescriptionSet) { + createAnswerFailed(Exception { INVALID_STATE_ERR, "No remote description set" }); + return; + } + m_endpoint->doCreateAnswer(); +} + +void LibWebRTCPeerConnectionBackend::doStop() +{ + m_endpoint->stop(); +} + +void LibWebRTCPeerConnectionBackend::doAddIceCandidate(RTCIceCandidate& candidate) +{ + if (!m_isRemoteDescriptionSet) { + addIceCandidateFailed(Exception { INVALID_STATE_ERR, "No remote description set" }); + return; + } + + webrtc::SdpParseError error; + int sdpMLineIndex = candidate.sdpMLineIndex() ? candidate.sdpMLineIndex().value() : 0; + std::unique_ptr<webrtc::IceCandidateInterface> rtcCandidate(webrtc::CreateIceCandidate(candidate.sdpMid().utf8().data(), sdpMLineIndex, candidate.candidate().utf8().data(), &error)); + + if (!rtcCandidate) { + String message(error.description.data(), error.description.size()); + addIceCandidateFailed(Exception { OperationError, WTFMove(message) }); + return; + } + + // libwebrtc does not like that ice candidates are set before the description. + if (!m_isLocalDescriptionSet || !m_isRemoteDescriptionSet) + m_pendingCandidates.append(WTFMove(rtcCandidate)); + else if (!m_endpoint->addIceCandidate(*rtcCandidate.get())) { + ASSERT_NOT_REACHED(); + addIceCandidateFailed(Exception { OperationError, ASCIILiteral("Failed to apply the received candidate") }); + return; + } + addIceCandidateSucceeded(); +} + +void LibWebRTCPeerConnectionBackend::addAudioSource(Ref<RealtimeOutgoingAudioSource>&& source) +{ + m_audioSources.append(WTFMove(source)); +} + +void LibWebRTCPeerConnectionBackend::addVideoSource(Ref<RealtimeOutgoingVideoSource>&& source) +{ + m_videoSources.append(WTFMove(source)); +} + +Ref<RTCRtpReceiver> LibWebRTCPeerConnectionBackend::createReceiver(const String&, const String& trackKind, const String& trackId) +{ + // FIXME: We need to create a source that will get fueled once we will receive OnAddStream. + // For the moment, we create an empty one. + auto remoteTrackPrivate = (trackKind == "audio") ? MediaStreamTrackPrivate::create(RealtimeIncomingAudioSource::create(nullptr, String(trackId))) : MediaStreamTrackPrivate::create(RealtimeIncomingVideoSource::create(nullptr, String(trackId))); + auto remoteTrack = MediaStreamTrack::create(*m_peerConnection.scriptExecutionContext(), WTFMove(remoteTrackPrivate)); + + return RTCRtpReceiver::create(WTFMove(remoteTrack)); +} + +std::unique_ptr<RTCDataChannelHandler> LibWebRTCPeerConnectionBackend::createDataChannelHandler(const String& label, const RTCDataChannelInit& options) +{ + return m_endpoint->createDataChannel(label, options); +} + +RefPtr<RTCSessionDescription> LibWebRTCPeerConnectionBackend::localDescription() const +{ + return m_endpoint->localDescription(); +} + +RefPtr<RTCSessionDescription> LibWebRTCPeerConnectionBackend::remoteDescription() const +{ + return m_endpoint->remoteDescription(); +} + +} // namespace WebCore + +#endif // USE(LIBWEBRTC) diff --git a/Source/WebCore/Modules/mediastream/libwebrtc/LibWebRTCPeerConnectionBackend.h b/Source/WebCore/Modules/mediastream/libwebrtc/LibWebRTCPeerConnectionBackend.h new file mode 100644 index 000000000..f5b4c565f --- /dev/null +++ b/Source/WebCore/Modules/mediastream/libwebrtc/LibWebRTCPeerConnectionBackend.h @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2017 Apple Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#if USE(LIBWEBRTC) + +#include "PeerConnectionBackend.h" +#include <wtf/HashMap.h> + +namespace webrtc { +class IceCandidateInterface; +} + +namespace WebCore { + +class LibWebRTCMediaEndpoint; +class RTCRtpReceiver; +class RTCSessionDescription; +class RTCstatsReport; +class RealtimeOutgoingAudioSource; +class RealtimeOutgoingVideoSource; + +class LibWebRTCPeerConnectionBackend final : public PeerConnectionBackend { +public: + explicit LibWebRTCPeerConnectionBackend(RTCPeerConnection&); + ~LibWebRTCPeerConnectionBackend(); + +private: + void doCreateOffer(RTCOfferOptions&&) final; + void doCreateAnswer(RTCAnswerOptions&&) final; + void doSetLocalDescription(RTCSessionDescription&) final; + void doSetRemoteDescription(RTCSessionDescription&) final; + void doAddIceCandidate(RTCIceCandidate&) final; + void doStop() final; + std::unique_ptr<RTCDataChannelHandler> createDataChannelHandler(const String&, const RTCDataChannelInit&) final; + void setConfiguration(MediaEndpointConfiguration&&) final; + void getStats(MediaStreamTrack*, Ref<DeferredPromise>&&) final; + Ref<RTCRtpReceiver> createReceiver(const String& transceiverMid, const String& trackKind, const String& trackId) final; + + RefPtr<RTCSessionDescription> localDescription() const final; + RefPtr<RTCSessionDescription> currentLocalDescription() const final { return localDescription(); } + RefPtr<RTCSessionDescription> pendingLocalDescription() const final { return localDescription(); } + + RefPtr<RTCSessionDescription> remoteDescription() const final; + RefPtr<RTCSessionDescription> currentRemoteDescription() const final { return remoteDescription(); } + RefPtr<RTCSessionDescription> pendingRemoteDescription() const final { return remoteDescription(); } + + // FIXME: API to implement for real + Vector<RefPtr<MediaStream>> getRemoteStreams() const final { return { }; } + void replaceTrack(RTCRtpSender&, RefPtr<MediaStreamTrack>&&, DOMPromise<void>&&) final { } + + void emulatePlatformEvent(const String&) final { } + + friend LibWebRTCMediaEndpoint; + RTCPeerConnection& connection() { return m_peerConnection; } + void addAudioSource(Ref<RealtimeOutgoingAudioSource>&&); + void addVideoSource(Ref<RealtimeOutgoingVideoSource>&&); + + void getStatsSucceeded(const DeferredPromise&, Ref<RTCStatsReport>&&); + void getStatsFailed(const DeferredPromise&, Exception&&); + +private: + Ref<LibWebRTCMediaEndpoint> m_endpoint; + bool m_isLocalDescriptionSet { false }; + bool m_isRemoteDescriptionSet { false }; + + Vector<std::unique_ptr<webrtc::IceCandidateInterface>> m_pendingCandidates; + Vector<Ref<RealtimeOutgoingAudioSource>> m_audioSources; + Vector<Ref<RealtimeOutgoingVideoSource>> m_videoSources; + HashMap<const DeferredPromise*, Ref<DeferredPromise>> m_statsPromises; +}; + +} // namespace WebCore + +#endif // USE(LIBWEBRTC) diff --git a/Source/WebCore/Modules/mediastream/sdp.js b/Source/WebCore/Modules/mediastream/sdp.js new file mode 100644 index 000000000..ecd256070 --- /dev/null +++ b/Source/WebCore/Modules/mediastream/sdp.js @@ -0,0 +1,606 @@ +/* + * Copyright (C) 2014-2015 Ericsson AB. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +"use strict"; + +if (typeof(SDP) == "undefined") + var SDP = {}; + +(function () { + var regexps = { + "vline": "^v=([\\d]+).*$", + "oline": "^o=([\\w\\-@\\.]+) ([\\d]+) ([\\d]+) IN (IP[46]) ([\\d\\.a-f\\:]+).*$", + "sline": "^s=(.*)$", + "tline": "^t=([\\d]+) ([\\d]+).*$", + "cline": "^c=IN (IP[46]) ([\\d\\.a-f\\:]+).*$", + "msidsemantic": "^a=msid-semantic: *WMS .*$", + "mblock": "^m=(audio|video|application) ([\\d]+) ([A-Z/]+)([\\d ]*)$\\r?\\n", + "mode": "^a=(sendrecv|sendonly|recvonly|inactive).*$", + "mid": "^a=mid:([!#$%&'*+-.\\w]*).*$", + "rtpmap": "^a=rtpmap:${type} ([\\w\\-]+)/([\\d]+)/?([\\d]+)?.*$", + "fmtp": "^a=fmtp:${type} ([\\w\\-=; ]+).*$", + "param": "([\\w\\-]+)=([\\w\\-]+);?", + "nack": "^a=rtcp-fb:${type} nack$", + "nackpli": "^a=rtcp-fb:${type} nack pli$", + "ccmfir": "^a=rtcp-fb:${type} ccm fir$", + "ericscream": "^a=rtcp-fb:${type} ericscream$", + "rtcp": "^a=rtcp:([\\d]+)( IN (IP[46]) ([\\d\\.a-f\\:]+))?.*$", + "rtcpmux": "^a=rtcp-mux.*$", + "cname": "^a=ssrc:(\\d+) cname:([\\w+/\\-@\\.\\{\\}]+).*$", + "msid": "^a=(ssrc:\\d+ )?msid:([\\w+/\\-=]+) +([\\w+/\\-=]+).*$", + "ufrag": "^a=ice-ufrag:([\\w+/]*).*$", + "pwd": "^a=ice-pwd:([\\w+/]*).*$", + "candidate": "^a=candidate:(\\d+) (\\d) (UDP|TCP) ([\\d\\.]*) ([\\d\\.a-f\\:]*) (\\d*)" + + " typ ([a-z]*)( raddr ([\\d\\.a-f\\:]*) rport (\\d*))?" + + "( tcptype (active|passive|so))?.*$", + "fingerprint": "^a=fingerprint:(sha-1|sha-256) ([A-Fa-f\\d\:]+).*$", + "setup": "^a=setup:(actpass|active|passive).*$", + "sctpmap": "^a=sctpmap:${port} ([\\w\\-]+)( [\\d]+)?.*$" + }; + + var templates = { + "sdp": + "v=${version}\r\n" + + "o=${username} ${sessionId} ${sessionVersion} ${netType} ${addressType} ${address}\r\n" + + "s=${sessionName}\r\n" + + "t=${startTime} ${stopTime}\r\n" + + "${msidsemanticLine}", + + "msidsemantic": "a=msid-semantic:WMS ${mediaStreamIds}\r\n", + + "mblock": + "m=${type} ${port} ${protocol} ${fmt}\r\n" + + "c=${netType} ${addressType} ${address}\r\n" + + "${rtcpLine}" + + "${rtcpMuxLine}" + + "a=${mode}\r\n" + + "${midLine}" + + "${rtpMapLines}" + + "${fmtpLines}" + + "${nackLines}" + + "${nackpliLines}" + + "${ccmfirLines}" + + "${ericScreamLines}" + + "${cnameLines}" + + "${msidLines}" + + "${iceCredentialLines}" + + "${candidateLines}" + + "${dtlsFingerprintLine}" + + "${dtlsSetupLine}" + + "${sctpmapLine}", + + "rtcp": "a=rtcp:${port}${[ ]netType}${[ ]addressType}${[ ]address}\r\n", + "rtcpMux": "a=rtcp-mux\r\n", + "mid": "a=mid:${mid}\r\n", + + "rtpMap": "a=rtpmap:${type} ${encodingName}/${clockRate}${[/]channels}\r\n", + "fmtp": "a=fmtp:${type} ${parameters}\r\n", + "nack": "a=rtcp-fb:${type} nack\r\n", + "nackpli": "a=rtcp-fb:${type} nack pli\r\n", + "ccmfir": "a=rtcp-fb:${type} ccm fir\r\n", + "ericscream": "a=rtcp-fb:${type} ericscream\r\n", + + "cname": "a=ssrc:${ssrc} cname:${cname}\r\n", + "msid": "a=msid:${mediaStreamId} ${mediaStreamTrackId}\r\n", + + "iceCredentials": + "a=ice-ufrag:${ufrag}\r\n" + + "a=ice-pwd:${password}\r\n", + + "candidate": + "a=candidate:${foundation} ${componentId} ${transport} ${priority} ${address} ${port}" + + " typ ${type}${[ raddr ]relatedAddress}${[ rport ]relatedPort}${[ tcptype ]tcpType}\r\n", + + "dtlsFingerprint": "a=fingerprint:${fingerprintHashFunction} ${fingerprint}\r\n", + "dtlsSetup": "a=setup:${setup}\r\n", + + "sctpmap": "a=sctpmap:${port} ${app}${[ ]streams}\r\n" + }; + + function match(data, pattern, flags, alt) { + var r = new RegExp(pattern, flags); + return data.match(r) || alt && alt.match(r) || null; + } + + function addDefaults(obj, defaults) { + for (var p in defaults) { + if (!defaults.hasOwnProperty(p)) + continue; + if (typeof(obj[p]) == "undefined") + obj[p] = defaults[p]; + } + } + + function fillTemplate(template, info) { + var text = template; + for (var p in info) { + if (!info.hasOwnProperty(p)) + continue; + var r = new RegExp("\\${(\\[[^\\]]+\\])?" + p + "(\\[[^\\]]+\\])?}"); + text = text.replace(r, function (_, prefix, suffix) { + if (!info[p] && info[p] != 0) + return ""; + prefix = prefix ? prefix.substr(1, prefix.length - 2) : ""; + suffix = suffix ? suffix.substr(1, suffix.length - 2) : ""; + return prefix + info[p] + suffix; + }); + } + return text; + } + + SDP.parse = function (sdpText) { + sdpText = new String(sdpText); + var sdpObj = {}; + var parts = sdpText.split(new RegExp(regexps.mblock, "m")) || [sdpText]; + var sblock = parts.shift(); + var version = parseInt((match(sblock, regexps.vline, "m") || [])[1]); + if (!isNaN(version)) + sdpObj.version = version; + var originator = match(sblock, regexps.oline, "m");; + if (originator) { + sdpObj.originator = { + "username": originator[1], + "sessionId": originator[2], + "sessionVersion": parseInt(originator[3]), + "netType": "IN", + "addressType": originator[4], + "address": originator[5] + }; + } + var sessionName = match(sblock, regexps.sline, "m"); + if (sessionName) + sdpObj.sessionName = sessionName[1]; + var sessionTime = match(sblock, regexps.tline, "m"); + if (sessionTime) { + sdpObj.startTime = parseInt(sessionTime[1]); + sdpObj.stopTime = parseInt(sessionTime[2]); + } + var hasMediaStreamId = !!match(sblock, regexps.msidsemantic, "m"); + sdpObj.mediaDescriptions = []; + + for (var i = 0; i < parts.length; i += 5) { + var mediaDescription = { + "type": parts[i], + "port": parseInt(parts[i + 1]), + "protocol": parts[i + 2], + }; + var fmt = parts[i + 3].replace(/^[\s\uFEFF\xA0]+/, '') + .split(/ +/) + .map(function (x) { + return parseInt(x); + }); + var mblock = parts[i + 4]; + + var connection = match(mblock, regexps.cline, "m", sblock); + if (connection) { + mediaDescription.netType = "IN"; + mediaDescription.addressType = connection[1]; + mediaDescription.address = connection[2]; + } + var mode = match(mblock, regexps.mode, "m", sblock); + if (mode) + mediaDescription.mode = mode[1]; + + var mid = match(mblock, regexps.mid, "m", sblock); + if (mid) + mediaDescription.mid = mid[1]; + + var payloadTypes = []; + if (match(mediaDescription.protocol, "(UDP/TLS)?RTP/S?AVPF?")) { + mediaDescription.payloads = []; + payloadTypes = fmt; + } + payloadTypes.forEach(function (payloadType) { + var payload = { "type": payloadType }; + var rtpmapLine = fillTemplate(regexps.rtpmap, payload); + var rtpmap = match(mblock, rtpmapLine, "m"); + if (rtpmap) { + payload.encodingName = rtpmap[1]; + payload.clockRate = parseInt(rtpmap[2]); + if (mediaDescription.type == "audio") + payload.channels = parseInt(rtpmap[3]) || 1; + else if (mediaDescription.type == "video") { + var nackLine = fillTemplate(regexps.nack, payload); + payload.nack = !!match(mblock, nackLine, "m"); + var nackpliLine = fillTemplate(regexps.nackpli, payload); + payload.nackpli = !!match(mblock, nackpliLine, "m"); + var ccmfirLine = fillTemplate(regexps.ccmfir, payload); + payload.ccmfir = !!match(mblock, ccmfirLine, "m"); + var ericScreamLine = fillTemplate(regexps.ericscream, payload); + payload.ericscream = !!match(mblock, ericScreamLine, "m"); + } + } else if (payloadType == 0 || payloadType == 8) { + payload.encodingName = payloadType == 8 ? "PCMA" : "PCMU"; + payload.clockRate = 8000; + payload.channels = 1; + } + var fmtpLine = fillTemplate(regexps.fmtp, payload); + var fmtp = match(mblock, fmtpLine, "m"); + if (fmtp) { + payload.parameters = {}; + fmtp[1].replace(new RegExp(regexps.param, "g"), + function(_, key, value) { + key = key.replace(/-([a-z])/g, function (_, c) { + return c.toUpperCase(); + }); + payload.parameters[key] = isNaN(+value) ? value : +value; + }); + } + mediaDescription.payloads.push(payload); + }); + + var rtcp = match(mblock, regexps.rtcp, "m"); + if (rtcp) { + mediaDescription.rtcp = { + "netType": "IN", + "port": parseInt(rtcp[1]) + }; + if (rtcp[2]) { + mediaDescription.rtcp.addressType = rtcp[3]; + mediaDescription.rtcp.address = rtcp[4]; + } + } + var rtcpmux = match(mblock, regexps.rtcpmux, "m", sblock); + if (rtcpmux) { + if (!mediaDescription.rtcp) + mediaDescription.rtcp = {}; + mediaDescription.rtcp.mux = true; + } + + var cnameLines = match(mblock, regexps.cname, "mg"); + if (cnameLines) { + mediaDescription.ssrcs = []; + cnameLines.forEach(function (line) { + var cname = match(line, regexps.cname, "m"); + mediaDescription.ssrcs.push(parseInt(cname[1])); + if (!mediaDescription.cname) + mediaDescription.cname = cname[2]; + }); + } + + if (hasMediaStreamId) { + var msid = match(mblock, regexps.msid, "m"); + if (msid) { + mediaDescription.mediaStreamId = msid[2]; + mediaDescription.mediaStreamTrackId = msid[3]; + } + } + + var ufrag = match(mblock, regexps.ufrag, "m", sblock); + var pwd = match(mblock, regexps.pwd, "m", sblock); + if (ufrag && pwd) { + mediaDescription.ice = { + "ufrag": ufrag[1], + "password": pwd[1] + }; + } + var candidateLines = match(mblock, regexps.candidate, "mig"); + if (candidateLines) { + if (!mediaDescription.ice) + mediaDescription.ice = {}; + mediaDescription.ice.candidates = []; + candidateLines.forEach(function (line) { + var candidateLine = match(line, regexps.candidate, "mi"); + var candidate = { + "foundation": candidateLine[1], + "componentId": parseInt(candidateLine[2]), + "transport": candidateLine[3].toUpperCase(), + "priority": parseInt(candidateLine[4]), + "address": candidateLine[5], + "port": parseInt(candidateLine[6]), + "type": candidateLine[7] + }; + if (candidateLine[9]) + candidate.relatedAddress = candidateLine[9]; + if (!isNaN(candidateLine[10])) + candidate.relatedPort = parseInt(candidateLine[10]); + if (candidateLine[12]) + candidate.tcpType = candidateLine[12]; + else if (candidate.transport == "TCP") { + if (candidate.port == 0 || candidate.port == 9) { + candidate.tcpType = "active"; + candidate.port = 9; + } else { + return; + } + } + mediaDescription.ice.candidates.push(candidate); + }); + } + + var fingerprint = match(mblock, regexps.fingerprint, "mi", sblock); + if (fingerprint) { + mediaDescription.dtls = { + "fingerprintHashFunction": fingerprint[1].toLowerCase(), + "fingerprint": fingerprint[2].toUpperCase() + }; + } + var setup = match(mblock, regexps.setup, "m", sblock); + if (setup) { + if (!mediaDescription.dtls) + mediaDescription.dtls = {}; + mediaDescription.dtls.setup = setup[1]; + } + + if (mediaDescription.protocol == "DTLS/SCTP") { + mediaDescription.sctp = { + "port": fmt[0] + }; + var sctpmapLine = fillTemplate(regexps.sctpmap, mediaDescription.sctp); + var sctpmap = match(mblock, sctpmapLine, "m"); + if (sctpmap) { + mediaDescription.sctp.app = sctpmap[1]; + if (sctpmap[2]) + mediaDescription.sctp.streams = parseInt(sctpmap[2]); + } + } + + sdpObj.mediaDescriptions.push(mediaDescription); + } + + return sdpObj; + }; + + SDP.generate = function (sdpObj) { + sdpObj = JSON.parse(JSON.stringify(sdpObj)); + addDefaults(sdpObj, { + "version": 0, + "originator": {}, + "sessionName": "-", + "startTime": 0, + "stopTime": 0, + "mediaDescriptions": [] + }); + addDefaults(sdpObj.originator, { + "username": "-", + "sessionId": "" + Math.floor((Math.random() + +new Date()) * 1e6), + "sessionVersion": 1, + "netType": "IN", + "addressType": "IP4", + "address": "127.0.0.1" + }); + var sdpText = fillTemplate(templates.sdp, sdpObj); + sdpText = fillTemplate(sdpText, sdpObj.originator); + + var msidsemanticLine = ""; + var mediaStreamIds = []; + sdpObj.mediaDescriptions.forEach(function (mdesc) { + if (mdesc.mediaStreamId && mdesc.mediaStreamTrackId + && mediaStreamIds.indexOf(mdesc.mediaStreamId) == -1) + mediaStreamIds.push(mdesc.mediaStreamId); + }); + if (mediaStreamIds.length) { + var msidsemanticLine = fillTemplate(templates.msidsemantic, + { "mediaStreamIds": mediaStreamIds.join(" ") }); + } + sdpText = fillTemplate(sdpText, { "msidsemanticLine": msidsemanticLine }); + + sdpObj.mediaDescriptions.forEach(function (mediaDescription) { + addDefaults(mediaDescription, { + "port": 9, + "protocol": "UDP/TLS/RTP/SAVPF", + "netType": "IN", + "addressType": "IP4", + "address": "0.0.0.0", + "mode": "sendrecv", + "payloads": [], + "rtcp": {} + }); + var mblock = fillTemplate(templates.mblock, mediaDescription); + + var midInfo = {"midLine": ""}; + if (mediaDescription.mid) + midInfo.midLine = fillTemplate(templates.mid, mediaDescription); + mblock = fillTemplate(mblock, midInfo); + + var payloadInfo = {"rtpMapLines": "", "fmtpLines": "", "nackLines": "", + "nackpliLines": "", "ccmfirLines": "", "ericScreamLines": ""}; + mediaDescription.payloads.forEach(function (payload) { + if (payloadInfo.fmt) + payloadInfo.fmt += " " + payload.type; + else + payloadInfo.fmt = payload.type; + if (!payload.channels || payload.channels == 1) + payload.channels = null; + payloadInfo.rtpMapLines += fillTemplate(templates.rtpMap, payload); + if (payload.parameters) { + var fmtpInfo = { "type": payload.type, "parameters": "" }; + for (var p in payload.parameters) { + var param = p.replace(/([A-Z])([a-z])/g, function (_, a, b) { + return "-" + a.toLowerCase() + b; + }); + if (fmtpInfo.parameters) + fmtpInfo.parameters += ";"; + fmtpInfo.parameters += param + "=" + payload.parameters[p]; + } + payloadInfo.fmtpLines += fillTemplate(templates.fmtp, fmtpInfo); + } + if (payload.nack) + payloadInfo.nackLines += fillTemplate(templates.nack, payload); + if (payload.nackpli) + payloadInfo.nackpliLines += fillTemplate(templates.nackpli, payload); + if (payload.ccmfir) + payloadInfo.ccmfirLines += fillTemplate(templates.ccmfir, payload); + if (payload.ericscream) + payloadInfo.ericScreamLines += fillTemplate(templates.ericscream, payload); + }); + mblock = fillTemplate(mblock, payloadInfo); + + var rtcpInfo = {"rtcpLine": "", "rtcpMuxLine": ""}; + if (mediaDescription.rtcp.port) { + addDefaults(mediaDescription.rtcp, { + "netType": "IN", + "addressType": "IP4", + "address": "" + }); + if (!mediaDescription.rtcp.address) + mediaDescription.rtcp.netType = mediaDescription.rtcp.addressType = ""; + rtcpInfo.rtcpLine = fillTemplate(templates.rtcp, mediaDescription.rtcp); + } + if (mediaDescription.rtcp.mux) + rtcpInfo.rtcpMuxLine = templates.rtcpMux; + mblock = fillTemplate(mblock, rtcpInfo); + + var srcAttributeLines = { "cnameLines": "", "msidLines": "" }; + var srcAttributes = { + "cname": mediaDescription.cname, + "mediaStreamId": mediaDescription.mediaStreamId, + "mediaStreamTrackId": mediaDescription.mediaStreamTrackId + }; + if (mediaDescription.cname && mediaDescription.ssrcs) { + mediaDescription.ssrcs.forEach(function (ssrc) { + srcAttributes.ssrc = ssrc; + srcAttributeLines.cnameLines += fillTemplate(templates.cname, srcAttributes); + if (mediaDescription.mediaStreamId && mediaDescription.mediaStreamTrackId) + srcAttributeLines.msidLines += fillTemplate(templates.msid, srcAttributes); + }); + } else if (mediaDescription.mediaStreamId && mediaDescription.mediaStreamTrackId) { + srcAttributes.ssrc = null; + srcAttributeLines.msidLines += fillTemplate(templates.msid, srcAttributes); + } + mblock = fillTemplate(mblock, srcAttributeLines); + + var iceInfo = {"iceCredentialLines": "", "candidateLines": ""}; + if (mediaDescription.ice) { + iceInfo.iceCredentialLines = fillTemplate(templates.iceCredentials, + mediaDescription.ice); + if (mediaDescription.ice.candidates) { + mediaDescription.ice.candidates.forEach(function (candidate) { + addDefaults(candidate, { + "relatedAddress": null, + "relatedPort": null, + "tcpType": null + }); + iceInfo.candidateLines += fillTemplate(templates.candidate, candidate); + }); + } + } + mblock = fillTemplate(mblock, iceInfo); + + var dtlsInfo = { "dtlsFingerprintLine": "", "dtlsSetupLine": "" }; + if (mediaDescription.dtls) { + if (mediaDescription.dtls.fingerprint) { + dtlsInfo.dtlsFingerprintLine = fillTemplate(templates.dtlsFingerprint, + mediaDescription.dtls); + } + addDefaults(mediaDescription.dtls, {"setup": "actpass"}); + dtlsInfo.dtlsSetupLine = fillTemplate(templates.dtlsSetup, mediaDescription.dtls); + } + mblock = fillTemplate(mblock, dtlsInfo); + + var sctpInfo = {"sctpmapLine": "", "fmt": ""}; + if (mediaDescription.sctp) { + addDefaults(mediaDescription.sctp, {"streams": null}); + sctpInfo.sctpmapLine = fillTemplate(templates.sctpmap, mediaDescription.sctp); + sctpInfo.fmt = mediaDescription.sctp.port; + } + mblock = fillTemplate(mblock, sctpInfo); + + sdpText += mblock; + }); + + return sdpText; + }; + + SDP.generateCandidateLine = function (candidateObj) { + addDefaults(candidateObj, { + "relatedAddress": null, + "relatedPort": null, + "tcpType": null + }); + + return fillTemplate(templates.candidate, candidateObj); + }; + + var expectedProperties = { + "session": [ "version", "originator", "sessionName", "startTime", "stopTime" ], + "mline": [ "type", "port", "protocol", "mode", "payloads", "rtcp", "dtls", "ice" ], + "mlineSubObjects": { + "rtcp": [ "mux" ], + "ice": [ "ufrag", "password" ], + "dtls": [ "setup", "fingerprintHashFunction", "fingerprint" ] + } + }; + + function hasAllProperties(object, properties) { + var missing = properties.filter(function (property) { + return !object.hasOwnProperty(property); + }); + + return !missing.length; + } + + SDP.verifyObject = function (sdpObj) { + if (!hasAllProperties(sdpObj, expectedProperties.session)) + return false; + + for (var i = 0; i < sdpObj.mediaDescriptions.length; i++) { + var mediaDescription = sdpObj.mediaDescriptions[i]; + + if (!hasAllProperties(mediaDescription, expectedProperties.mline)) + return false; + + for (var p in expectedProperties.mlineSubObjects) { + if (!hasAllProperties(mediaDescription[p], expectedProperties.mlineSubObjects[p])) + return false; + } + } + + return true; + }; + +})(); + +function generate(json) { + var object = JSON.parse(json); + return SDP.generate(object); +} + +function parse(sdp) { + var object = SDP.parse(sdp); + + if (!SDP.verifyObject(object)) + return "ParseError"; + + return JSON.stringify(object); +} + +function generateCandidateLine(json) { + var candidate = JSON.parse(json); + return SDP.generateCandidateLine(candidate).substr(2); +} + +function parseCandidateLine(candidateLine) { + var mdesc = SDP.parse("m=application 0 NONE\r\na=" + candidateLine + "\r\n").mediaDescriptions[0]; + if (!mdesc.ice) + return "ParseError"; + + return JSON.stringify(mdesc.ice.candidates[0]); +} + +if (typeof(module) != "undefined" && typeof(exports) != "undefined") + module.exports = SDP; |