| /* |
| * Copyright (C) 2011 Google Inc. All rights reserved. |
| * Copyright (C) 2011, 2015 Ericsson AB. All rights reserved. |
| * Copyright (C) 2013 Apple Inc. All rights reserved. |
| * Copyright (C) 2013 Nokia Corporation and/or its subsidiary(-ies). |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * |
| * 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 "MediaStreamTrack.h" |
| |
| #if ENABLE(MEDIA_STREAM) |
| |
| #include "AllAudioCapabilities.h" |
| #include "AllVideoCapabilities.h" |
| #include "Dictionary.h" |
| #include "Event.h" |
| #include "ExceptionCode.h" |
| #include "ExceptionCodePlaceholder.h" |
| #include "MediaConstraintsImpl.h" |
| #include "MediaSourceStates.h" |
| #include "MediaStream.h" |
| #include "MediaStreamPrivate.h" |
| #include "MediaTrackConstraints.h" |
| #include "NotImplemented.h" |
| #include "ScriptExecutionContext.h" |
| #include <wtf/Functional.h> |
| #include <wtf/NeverDestroyed.h> |
| |
| namespace WebCore { |
| |
| Ref<MediaStreamTrack> MediaStreamTrack::create(ScriptExecutionContext& context, MediaStreamTrackPrivate& privateTrack) |
| { |
| return adoptRef(*new MediaStreamTrack(context, privateTrack)); |
| } |
| |
| MediaStreamTrack::MediaStreamTrack(ScriptExecutionContext& context, MediaStreamTrackPrivate& privateTrack) |
| : RefCounted() |
| , ActiveDOMObject(&context) |
| , m_private(privateTrack) |
| { |
| suspendIfNeeded(); |
| |
| m_private->addObserver(*this); |
| } |
| |
| MediaStreamTrack::~MediaStreamTrack() |
| { |
| m_private->removeObserver(*this); |
| } |
| |
| const AtomicString& MediaStreamTrack::kind() const |
| { |
| 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_private->id(); |
| } |
| |
| const String& MediaStreamTrack::label() const |
| { |
| return m_private->label(); |
| } |
| |
| bool MediaStreamTrack::enabled() const |
| { |
| return m_private->enabled(); |
| } |
| |
| void MediaStreamTrack::setEnabled(bool enabled) |
| { |
| m_private->setEnabled(enabled); |
| } |
| |
| bool MediaStreamTrack::muted() const |
| { |
| return m_private->muted(); |
| } |
| |
| bool MediaStreamTrack::readonly() const |
| { |
| return m_private->readonly(); |
| } |
| |
| bool MediaStreamTrack::remote() const |
| { |
| return m_private->remote(); |
| } |
| |
| const AtomicString& MediaStreamTrack::readyState() const |
| { |
| static NeverDestroyed<AtomicString> endedState("ended", AtomicString::ConstructFromLiteral); |
| static NeverDestroyed<AtomicString> liveState("live", AtomicString::ConstructFromLiteral); |
| |
| return ended() ? endedState : liveState; |
| } |
| |
| bool MediaStreamTrack::ended() const |
| { |
| return m_ended || m_private->ended(); |
| } |
| |
| RefPtr<MediaStreamTrack> MediaStreamTrack::clone() |
| { |
| return MediaStreamTrack::create(*scriptExecutionContext(), *m_private->clone()); |
| } |
| |
| void MediaStreamTrack::stopProducingData() |
| { |
| // 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. |
| |
| // 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(); |
| } |
| |
| RefPtr<MediaTrackConstraints> MediaStreamTrack::getConstraints() const |
| { |
| // FIXME: https://bugs.webkit.org/show_bug.cgi?id=122428 |
| notImplemented(); |
| return 0; |
| } |
| |
| RefPtr<MediaSourceStates> MediaStreamTrack::states() const |
| { |
| return MediaSourceStates::create(m_private->states()); |
| } |
| |
| RefPtr<MediaStreamCapabilities> MediaStreamTrack::getCapabilities() const |
| { |
| // The source may be shared by multiple tracks, so its states is not necessarily |
| // in sync with the track state. A track that has ended always has a source |
| // type of "none". |
| RefPtr<RealtimeMediaSourceCapabilities> sourceCapabilities = m_private->capabilities(); |
| if (ended()) |
| sourceCapabilities->setSourceType(RealtimeMediaSourceStates::None); |
| |
| return MediaStreamCapabilities::create(sourceCapabilities.release()); |
| } |
| |
| void MediaStreamTrack::applyConstraints(const Dictionary& constraints) |
| { |
| m_constraints->initialize(constraints); |
| m_private->applyConstraints(*m_constraints); |
| } |
| |
| void MediaStreamTrack::applyConstraints(const MediaConstraints&) |
| { |
| // FIXME: apply the new constraints to the track |
| // https://bugs.webkit.org/show_bug.cgi?id=122428 |
| } |
| |
| void MediaStreamTrack::addObserver(MediaStreamTrack::Observer* observer) |
| { |
| m_observers.append(observer); |
| } |
| |
| void MediaStreamTrack::removeObserver(MediaStreamTrack::Observer* observer) |
| { |
| size_t pos = m_observers.find(observer); |
| if (pos != notFound) |
| m_observers.remove(pos); |
| } |
| |
| void MediaStreamTrack::trackEnded(MediaStreamTrackPrivate&) |
| { |
| // 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; |
| |
| // 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(MediaStreamTrackPrivate&) |
| { |
| if (scriptExecutionContext()->activeDOMObjectsAreSuspended() || scriptExecutionContext()->activeDOMObjectsAreStopped()) |
| return; |
| |
| AtomicString eventType = muted() ? eventNames().muteEvent : eventNames().unmuteEvent; |
| dispatchEvent(Event::create(eventType, false, false)); |
| |
| configureTrackRendering(); |
| } |
| |
| void MediaStreamTrack::trackStatesChanged(MediaStreamTrackPrivate&) |
| { |
| configureTrackRendering(); |
| } |
| |
| void MediaStreamTrack::trackEnabledChanged(MediaStreamTrackPrivate&) |
| { |
| configureTrackRendering(); |
| } |
| |
| void MediaStreamTrack::configureTrackRendering() |
| { |
| // 4.3.1 |
| // ... media from the source only flows when a MediaStreamTrack object is both unmuted and enabled |
| } |
| |
| void MediaStreamTrack::stop() |
| { |
| stopProducingData(); |
| } |
| |
| const char* MediaStreamTrack::activeDOMObjectName() const |
| { |
| return "MediaStreamTrack"; |
| } |
| |
| bool MediaStreamTrack::canSuspendForDocumentSuspension() const |
| { |
| // FIXME: We should try and do better here. |
| return false; |
| } |
| |
| AudioSourceProvider* MediaStreamTrack::audioSourceProvider() |
| { |
| return m_private->audioSourceProvider(); |
| } |
| |
| } // namespace WebCore |
| |
| #endif // ENABLE(MEDIA_STREAM) |