diff options
Diffstat (limited to 'dom/media/ForwardedInputTrack.cpp')
-rw-r--r-- | dom/media/ForwardedInputTrack.cpp | 291 |
1 files changed, 291 insertions, 0 deletions
diff --git a/dom/media/ForwardedInputTrack.cpp b/dom/media/ForwardedInputTrack.cpp new file mode 100644 index 0000000000..2f71f0e12a --- /dev/null +++ b/dom/media/ForwardedInputTrack.cpp @@ -0,0 +1,291 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "ForwardedInputTrack.h" + +#include <algorithm> +#include "AudioChannelService.h" +#include "AudioNodeEngine.h" +#include "AudioNodeExternalInputTrack.h" +#include "AudioNodeTrack.h" +#include "AudioSegment.h" +#include "DOMMediaStream.h" +#include "GeckoProfiler.h" +#include "ImageContainer.h" +#include "MediaTrackGraph.h" +#include "mozilla/Attributes.h" +#include "mozilla/Logging.h" +#include "mozilla/MathAlgorithms.h" +#include "mozilla/Unused.h" +#include "nsContentUtils.h" +#include "nsPrintfCString.h" +#include "nsServiceManagerUtils.h" +#include "nsWidgetsCID.h" +#include "prerror.h" +#include "Tracing.h" +#include "VideoSegment.h" +#include "webaudio/MediaStreamAudioDestinationNode.h" + +using namespace mozilla::layers; +using namespace mozilla::dom; +using namespace mozilla::gfx; + +namespace mozilla { + +#ifdef TRACK_LOG +# undef TRACK_LOG +#endif + +LazyLogModule gForwardedInputTrackLog("ForwardedInputTrack"); +#define TRACK_LOG(type, msg) MOZ_LOG(gForwardedInputTrackLog, type, msg) + +ForwardedInputTrack::ForwardedInputTrack(TrackRate aSampleRate, + MediaSegment::Type aType) + : ProcessedMediaTrack( + aSampleRate, aType, + aType == MediaSegment::AUDIO + ? static_cast<MediaSegment*>(new AudioSegment()) + : static_cast<MediaSegment*>(new VideoSegment())) {} + +void ForwardedInputTrack::AddInput(MediaInputPort* aPort) { + SetInput(aPort); + ProcessedMediaTrack::AddInput(aPort); +} + +void ForwardedInputTrack::RemoveInput(MediaInputPort* aPort) { + TRACK_LOG(LogLevel::Debug, + ("ForwardedInputTrack %p removing input %p", this, aPort)); + MOZ_ASSERT(aPort == mInputPort); + + for (const auto& listener : mOwnedDirectListeners) { + MediaTrack* source = mInputPort->GetSource(); + TRACK_LOG(LogLevel::Debug, + ("ForwardedInputTrack %p removing direct listener " + "%p. Forwarding to input track %p.", + this, listener.get(), aPort->GetSource())); + source->RemoveDirectListenerImpl(listener); + } + + DisabledTrackMode oldMode = CombinedDisabledMode(); + mInputDisabledMode = DisabledTrackMode::ENABLED; + NotifyIfDisabledModeChangedFrom(oldMode); + + mInputPort = nullptr; + ProcessedMediaTrack::RemoveInput(aPort); +} + +void ForwardedInputTrack::SetInput(MediaInputPort* aPort) { + MOZ_ASSERT(aPort); + MOZ_ASSERT(aPort->GetSource()); + MOZ_ASSERT(aPort->GetSource()->GetData()); + MOZ_ASSERT(!mInputPort); + MOZ_ASSERT(mInputDisabledMode == DisabledTrackMode::ENABLED); + + mInputPort = aPort; + + for (const auto& listener : mOwnedDirectListeners) { + MediaTrack* source = mInputPort->GetSource(); + TRACK_LOG(LogLevel::Debug, ("ForwardedInputTrack %p adding direct listener " + "%p. Forwarding to input track %p.", + this, listener.get(), aPort->GetSource())); + source->AddDirectListenerImpl(do_AddRef(listener)); + } + + DisabledTrackMode oldMode = CombinedDisabledMode(); + mInputDisabledMode = mInputPort->GetSource()->CombinedDisabledMode(); + NotifyIfDisabledModeChangedFrom(oldMode); +} + +void ForwardedInputTrack::ProcessInputImpl(MediaTrack* aSource, + MediaSegment* aSegment, + GraphTime aFrom, GraphTime aTo, + uint32_t aFlags) { + GraphTime next; + for (GraphTime t = aFrom; t < aTo; t = next) { + MediaInputPort::InputInterval interval = + MediaInputPort::GetNextInputInterval(mInputPort, t); + interval.mEnd = std::min(interval.mEnd, aTo); + + const bool inputEnded = + !aSource || + (aSource->Ended() && + aSource->GetEnd() <= + aSource->GraphTimeToTrackTimeWithBlocking(interval.mEnd)); + + TrackTime ticks = interval.mEnd - interval.mStart; + next = interval.mEnd; + + if (interval.mStart >= interval.mEnd) { + break; + } + + if (inputEnded) { + if (mAutoend && (aFlags & ALLOW_END)) { + mEnded = true; + break; + } + aSegment->AppendNullData(ticks); + TRACK_LOG(LogLevel::Verbose, + ("ForwardedInputTrack %p appending %lld ticks " + "of null data (ended input)", + this, (long long)ticks)); + } else if (interval.mInputIsBlocked) { + aSegment->AppendNullData(ticks); + TRACK_LOG(LogLevel::Verbose, + ("ForwardedInputTrack %p appending %lld ticks " + "of null data (blocked input)", + this, (long long)ticks)); + } else if (InMutedCycle()) { + aSegment->AppendNullData(ticks); + } else if (aSource->IsSuspended()) { + aSegment->AppendNullData(ticks); + } else { + MOZ_ASSERT(GetEnd() == GraphTimeToTrackTimeWithBlocking(interval.mStart), + "Samples missing"); + TrackTime inputStart = + aSource->GraphTimeToTrackTimeWithBlocking(interval.mStart); + TrackTime inputEnd = + aSource->GraphTimeToTrackTimeWithBlocking(interval.mEnd); + aSegment->AppendSlice(*aSource->GetData(), inputStart, inputEnd); + } + ApplyTrackDisabling(aSegment); + for (const auto& listener : mTrackListeners) { + listener->NotifyQueuedChanges(Graph(), GetEnd(), *aSegment); + } + mSegment->AppendFrom(aSegment); + } +} + +void ForwardedInputTrack::ProcessInput(GraphTime aFrom, GraphTime aTo, + uint32_t aFlags) { + TRACE_COMMENT("ForwardedInputTrack::ProcessInput", "ForwardedInputTrack %p", + this); + if (mEnded) { + return; + } + + MediaInputPort* input = mInputPort; + MediaTrack* source = input ? input->GetSource() : nullptr; + if (mType == MediaSegment::AUDIO) { + AudioSegment audio; + ProcessInputImpl(source, &audio, aFrom, aTo, aFlags); + } else if (mType == MediaSegment::VIDEO) { + VideoSegment video; + ProcessInputImpl(source, &video, aFrom, aTo, aFlags); + } else { + MOZ_CRASH("Unknown segment type"); + } + + if (mEnded) { + RemoveAllDirectListenersImpl(); + } +} + +DisabledTrackMode ForwardedInputTrack::CombinedDisabledMode() const { + if (mDisabledMode == DisabledTrackMode::SILENCE_BLACK || + mInputDisabledMode == DisabledTrackMode::SILENCE_BLACK) { + return DisabledTrackMode::SILENCE_BLACK; + } + if (mDisabledMode == DisabledTrackMode::SILENCE_FREEZE || + mInputDisabledMode == DisabledTrackMode::SILENCE_FREEZE) { + return DisabledTrackMode::SILENCE_FREEZE; + } + return DisabledTrackMode::ENABLED; +} + +void ForwardedInputTrack::SetDisabledTrackModeImpl(DisabledTrackMode aMode) { + bool enabled = aMode == DisabledTrackMode::ENABLED; + TRACK_LOG(LogLevel::Info, ("ForwardedInputTrack %p was explicitly %s", this, + enabled ? "enabled" : "disabled")); + for (DirectMediaTrackListener* listener : mOwnedDirectListeners) { + DisabledTrackMode oldMode = mDisabledMode; + bool oldEnabled = oldMode == DisabledTrackMode::ENABLED; + if (!oldEnabled && enabled) { + TRACK_LOG(LogLevel::Debug, ("ForwardedInputTrack %p setting " + "direct listener enabled", + this)); + listener->DecreaseDisabled(oldMode); + } else if (oldEnabled && !enabled) { + TRACK_LOG(LogLevel::Debug, ("ForwardedInputTrack %p setting " + "direct listener disabled", + this)); + listener->IncreaseDisabled(aMode); + } + } + MediaTrack::SetDisabledTrackModeImpl(aMode); +} + +void ForwardedInputTrack::OnInputDisabledModeChanged( + DisabledTrackMode aInputMode) { + MOZ_ASSERT(mInputs.Length() == 1); + MOZ_ASSERT(mInputs[0]->GetSource()); + DisabledTrackMode oldMode = CombinedDisabledMode(); + if (mInputDisabledMode == DisabledTrackMode::SILENCE_BLACK && + aInputMode == DisabledTrackMode::SILENCE_FREEZE) { + // Don't allow demoting from SILENCE_BLACK to SILENCE_FREEZE. Frames will + // remain black so we shouldn't notify that the track got enabled. + aInputMode = DisabledTrackMode::SILENCE_BLACK; + } + mInputDisabledMode = aInputMode; + NotifyIfDisabledModeChangedFrom(oldMode); +} + +uint32_t ForwardedInputTrack::NumberOfChannels() const { + MOZ_DIAGNOSTIC_ASSERT(mSegment->GetType() == MediaSegment::AUDIO); + if (!mInputPort || !mInputPort->GetSource()) { + return GetData<AudioSegment>()->MaxChannelCount(); + } + return mInputPort->GetSource()->NumberOfChannels(); +} + +void ForwardedInputTrack::AddDirectListenerImpl( + already_AddRefed<DirectMediaTrackListener> aListener) { + RefPtr<DirectMediaTrackListener> listener = aListener; + mOwnedDirectListeners.AppendElement(listener); + + DisabledTrackMode currentMode = mDisabledMode; + if (currentMode != DisabledTrackMode::ENABLED) { + listener->IncreaseDisabled(currentMode); + } + + if (mInputPort) { + MediaTrack* source = mInputPort->GetSource(); + TRACK_LOG(LogLevel::Debug, ("ForwardedInputTrack %p adding direct listener " + "%p. Forwarding to input track %p.", + this, listener.get(), source)); + source->AddDirectListenerImpl(listener.forget()); + } +} + +void ForwardedInputTrack::RemoveDirectListenerImpl( + DirectMediaTrackListener* aListener) { + for (size_t i = 0; i < mOwnedDirectListeners.Length(); ++i) { + if (mOwnedDirectListeners[i] == aListener) { + TRACK_LOG(LogLevel::Debug, + ("ForwardedInputTrack %p removing direct listener %p", this, + aListener)); + DisabledTrackMode currentMode = mDisabledMode; + if (currentMode != DisabledTrackMode::ENABLED) { + // Reset the listener's state. + aListener->DecreaseDisabled(currentMode); + } + mOwnedDirectListeners.RemoveElementAt(i); + break; + } + } + if (mInputPort) { + // Forward to the input + MediaTrack* source = mInputPort->GetSource(); + source->RemoveDirectListenerImpl(aListener); + } +} + +void ForwardedInputTrack::RemoveAllDirectListenersImpl() { + for (const auto& listener : mOwnedDirectListeners.Clone()) { + RemoveDirectListenerImpl(listener); + } + MOZ_DIAGNOSTIC_ASSERT(mOwnedDirectListeners.IsEmpty()); +} + +} // namespace mozilla |