зеркало из https://github.com/mozilla/gecko-dev.git
240 строки
8.1 KiB
C++
240 строки
8.1 KiB
C++
/* 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 "MediaTrackGraphImpl.h"
|
|
#include "MediaTrackListener.h"
|
|
#include "mozilla/Attributes.h"
|
|
#include "mozilla/Logging.h"
|
|
#include "mozilla/MathAlgorithms.h"
|
|
#include "mozilla/Unused.h"
|
|
#include "nsContentUtils.h"
|
|
#include "nsIAppShell.h"
|
|
#include "nsIObserver.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);
|
|
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);
|
|
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));
|
|
}
|
|
}
|
|
|
|
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(aTo - aFrom);
|
|
} 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_AUDIO_CALLBACK_COMMENT("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();
|
|
}
|
|
}
|
|
|
|
void ForwardedInputTrack::SetEnabledImpl(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::SetEnabledImpl(aMode);
|
|
}
|
|
|
|
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() {
|
|
nsTArray<RefPtr<DirectMediaTrackListener>> listeners(mOwnedDirectListeners);
|
|
for (const auto& listener : listeners) {
|
|
RemoveDirectListenerImpl(listener);
|
|
}
|
|
MOZ_DIAGNOSTIC_ASSERT(mOwnedDirectListeners.IsEmpty());
|
|
}
|
|
|
|
} // namespace mozilla
|