2013-05-07 15:59:16 +04:00
|
|
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/
|
|
|
|
/* 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/. */
|
|
|
|
|
2019-10-02 13:23:02 +03:00
|
|
|
#include "AudioNodeTrack.h"
|
2013-05-07 15:59:16 +04:00
|
|
|
|
2019-10-02 13:23:02 +03:00
|
|
|
#include "MediaTrackGraphImpl.h"
|
|
|
|
#include "MediaTrackListener.h"
|
2013-05-07 15:59:16 +04:00
|
|
|
#include "AudioNodeEngine.h"
|
|
|
|
#include "ThreeDPoint.h"
|
2013-09-06 00:25:17 +04:00
|
|
|
#include "AudioChannelFormat.h"
|
|
|
|
#include "AudioParamTimeline.h"
|
2014-01-15 15:08:20 +04:00
|
|
|
#include "AudioContext.h"
|
2015-09-16 07:31:12 +03:00
|
|
|
#include "nsMathUtils.h"
|
2017-08-08 06:38:02 +03:00
|
|
|
#include "AlignmentUtils.h"
|
2019-09-02 15:58:40 +03:00
|
|
|
#include "blink/Reverb.h"
|
2013-05-07 15:59:16 +04:00
|
|
|
|
|
|
|
using namespace mozilla::dom;
|
|
|
|
|
|
|
|
namespace mozilla {
|
|
|
|
|
|
|
|
/**
|
2019-10-02 13:23:02 +03:00
|
|
|
* An AudioNodeTrack produces a single audio track with ID
|
2013-10-08 22:20:33 +04:00
|
|
|
* AUDIO_TRACK. This track has rate AudioContext::sIdealAudioRate
|
2013-05-24 21:09:29 +04:00
|
|
|
* for regular audio contexts, and the rate requested by the web content
|
|
|
|
* for offline audio contexts.
|
2013-05-07 15:59:16 +04:00
|
|
|
* Each chunk in the track is a single block of WEBAUDIO_BLOCK_SIZE samples.
|
2013-05-21 23:17:47 +04:00
|
|
|
* Note: This must be a different value than MEDIA_STREAM_DEST_TRACK_ID
|
2013-05-07 15:59:16 +04:00
|
|
|
*/
|
|
|
|
|
2019-10-02 13:23:02 +03:00
|
|
|
AudioNodeTrack::AudioNodeTrack(AudioNodeEngine* aEngine, Flags aFlags,
|
|
|
|
TrackRate aSampleRate)
|
|
|
|
: ProcessedMediaTrack(
|
2019-10-02 13:22:53 +03:00
|
|
|
aSampleRate, MediaSegment::AUDIO,
|
|
|
|
(aFlags & EXTERNAL_OUTPUT) ? new AudioSegment() : nullptr),
|
2017-06-29 21:30:57 +03:00
|
|
|
mEngine(aEngine),
|
|
|
|
mFlags(aFlags),
|
|
|
|
mNumberOfInputChannels(2),
|
|
|
|
mIsActive(aEngine->IsActive()),
|
2019-10-02 13:22:53 +03:00
|
|
|
mMarkAsEndedAfterThisBlock(false),
|
2019-10-02 13:23:02 +03:00
|
|
|
mAudioParamTrack(false),
|
2017-06-29 21:30:57 +03:00
|
|
|
mPassThrough(false) {
|
2014-11-20 22:41:18 +03:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2015-10-23 01:38:11 +03:00
|
|
|
mSuspendedCount = !(mIsActive || mFlags & EXTERNAL_OUTPUT);
|
2014-11-20 22:41:18 +03:00
|
|
|
mChannelCountMode = ChannelCountMode::Max;
|
|
|
|
mChannelInterpretation = ChannelInterpretation::Speakers;
|
2014-11-18 06:22:45 +03:00
|
|
|
mLastChunks.SetLength(std::max(uint16_t(1), mEngine->OutputCount()));
|
2019-10-02 13:23:02 +03:00
|
|
|
MOZ_COUNT_CTOR(AudioNodeTrack);
|
2014-11-20 22:41:18 +03:00
|
|
|
}
|
|
|
|
|
2019-10-02 13:23:02 +03:00
|
|
|
AudioNodeTrack::~AudioNodeTrack() {
|
2015-09-17 15:03:00 +03:00
|
|
|
MOZ_ASSERT(mActiveInputCount == 0);
|
2019-10-02 13:23:02 +03:00
|
|
|
MOZ_COUNT_DTOR(AudioNodeTrack);
|
2013-05-07 15:59:16 +04:00
|
|
|
}
|
|
|
|
|
2019-10-02 13:23:02 +03:00
|
|
|
void AudioNodeTrack::NotifyForcedShutdown() { mEngine->NotifyForcedShutdown(); }
|
2019-06-14 18:04:48 +03:00
|
|
|
|
2019-10-02 13:23:02 +03:00
|
|
|
void AudioNodeTrack::DestroyImpl() {
|
2015-09-10 06:13:45 +03:00
|
|
|
// These are graph thread objects, so clean up on graph thread.
|
|
|
|
mInputChunks.Clear();
|
|
|
|
mLastChunks.Clear();
|
|
|
|
|
2019-10-02 13:23:02 +03:00
|
|
|
ProcessedMediaTrack::DestroyImpl();
|
2015-09-10 06:13:45 +03:00
|
|
|
}
|
|
|
|
|
2019-02-26 01:05:29 +03:00
|
|
|
/* static */
|
2019-10-02 13:23:02 +03:00
|
|
|
already_AddRefed<AudioNodeTrack> AudioNodeTrack::Create(
|
2015-09-08 16:22:16 +03:00
|
|
|
AudioContext* aCtx, AudioNodeEngine* aEngine, Flags aFlags,
|
2019-10-02 13:23:02 +03:00
|
|
|
MediaTrackGraph* aGraph) {
|
2015-08-12 02:26:24 +03:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2016-09-05 18:25:41 +03:00
|
|
|
MOZ_RELEASE_ASSERT(aGraph);
|
2015-08-12 02:26:24 +03:00
|
|
|
|
2019-10-02 13:23:02 +03:00
|
|
|
// MediaRecorders use an AudioNodeTrack, but no AudioNode
|
2015-08-12 02:26:24 +03:00
|
|
|
AudioNode* node = aEngine->NodeMainThread();
|
|
|
|
|
2019-10-02 13:23:02 +03:00
|
|
|
RefPtr<AudioNodeTrack> track =
|
|
|
|
new AudioNodeTrack(aEngine, aFlags, aGraph->GraphRate());
|
2015-09-16 07:15:21 +03:00
|
|
|
if (node) {
|
2019-10-02 13:23:02 +03:00
|
|
|
track->SetChannelMixingParametersImpl(node->ChannelCount(),
|
|
|
|
node->ChannelCountModeValue(),
|
|
|
|
node->ChannelInterpretationValue());
|
2015-08-12 02:26:24 +03:00
|
|
|
}
|
2020-06-12 03:50:34 +03:00
|
|
|
// All realtime tracks are initially suspended.
|
|
|
|
// ApplyAudioContextOperation() is used to start tracks so that a new track
|
|
|
|
// will not be started before the existing tracks, which may be awaiting an
|
|
|
|
// AudioCallbackDriver to resume.
|
|
|
|
bool isRealtime = !aCtx->IsOffline();
|
|
|
|
track->mSuspendedCount += isRealtime;
|
2019-10-02 13:23:02 +03:00
|
|
|
aGraph->AddTrack(track);
|
2020-06-12 03:50:34 +03:00
|
|
|
if (isRealtime && !aCtx->ShouldSuspendNewTrack()) {
|
|
|
|
nsTArray<RefPtr<mozilla::MediaTrack>> tracks;
|
|
|
|
tracks.AppendElement(track);
|
2020-10-29 14:05:41 +03:00
|
|
|
aGraph->ApplyAudioContextOperation(aCtx->DestinationTrack(),
|
|
|
|
std::move(tracks),
|
2020-06-12 03:50:34 +03:00
|
|
|
AudioContextOperation::Resume);
|
|
|
|
}
|
2019-10-02 13:23:02 +03:00
|
|
|
return track.forget();
|
2015-08-12 02:26:24 +03:00
|
|
|
}
|
|
|
|
|
2019-10-02 13:23:02 +03:00
|
|
|
size_t AudioNodeTrack::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const {
|
2014-04-13 22:08:10 +04:00
|
|
|
size_t amount = 0;
|
|
|
|
|
|
|
|
// Not reported:
|
|
|
|
// - mEngine
|
|
|
|
|
2019-10-02 13:23:02 +03:00
|
|
|
amount += ProcessedMediaTrack::SizeOfExcludingThis(aMallocSizeOf);
|
2015-07-29 09:24:24 +03:00
|
|
|
amount += mLastChunks.ShallowSizeOfExcludingThis(aMallocSizeOf);
|
2014-04-13 22:08:10 +04:00
|
|
|
for (size_t i = 0; i < mLastChunks.Length(); i++) {
|
|
|
|
// NB: This is currently unshared only as there are instances of
|
|
|
|
// double reporting in DMD otherwise.
|
|
|
|
amount += mLastChunks[i].SizeOfExcludingThisIfUnshared(aMallocSizeOf);
|
|
|
|
}
|
|
|
|
|
|
|
|
return amount;
|
|
|
|
}
|
|
|
|
|
2019-10-02 13:23:02 +03:00
|
|
|
size_t AudioNodeTrack::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const {
|
2014-04-13 22:08:10 +04:00
|
|
|
return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
|
|
|
|
}
|
|
|
|
|
2019-10-02 13:23:02 +03:00
|
|
|
void AudioNodeTrack::SizeOfAudioNodesIncludingThis(
|
2014-04-13 22:08:10 +04:00
|
|
|
MallocSizeOf aMallocSizeOf, AudioNodeSizes& aUsage) const {
|
2019-10-02 13:23:02 +03:00
|
|
|
// Explicitly separate out the track memory.
|
|
|
|
aUsage.mTrack = SizeOfIncludingThis(aMallocSizeOf);
|
2014-04-13 22:08:10 +04:00
|
|
|
|
|
|
|
if (mEngine) {
|
|
|
|
// This will fill out the rest of |aUsage|.
|
|
|
|
mEngine->SizeOfIncludingThis(aMallocSizeOf, aUsage);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-10-02 13:23:02 +03:00
|
|
|
void AudioNodeTrack::SetTrackTimeParameter(uint32_t aIndex,
|
|
|
|
AudioContext* aContext,
|
|
|
|
double aTrackTime) {
|
2015-04-28 09:42:00 +03:00
|
|
|
class Message final : public ControlMessage {
|
2013-05-07 15:59:16 +04:00
|
|
|
public:
|
2019-10-02 13:23:02 +03:00
|
|
|
Message(AudioNodeTrack* aTrack, uint32_t aIndex,
|
|
|
|
MediaTrack* aRelativeToTrack, double aTrackTime)
|
|
|
|
: ControlMessage(aTrack),
|
|
|
|
mTrackTime(aTrackTime),
|
|
|
|
mRelativeToTrack(aRelativeToTrack),
|
2015-04-28 09:42:00 +03:00
|
|
|
mIndex(aIndex) {}
|
2016-01-18 06:22:51 +03:00
|
|
|
void Run() override {
|
2019-10-02 13:23:02 +03:00
|
|
|
static_cast<AudioNodeTrack*>(mTrack)->SetTrackTimeParameterImpl(
|
|
|
|
mIndex, mRelativeToTrack, mTrackTime);
|
2013-05-07 15:59:16 +04:00
|
|
|
}
|
2019-10-02 13:23:02 +03:00
|
|
|
double mTrackTime;
|
|
|
|
MediaTrack* MOZ_UNSAFE_REF(
|
2017-06-15 18:51:28 +03:00
|
|
|
"ControlMessages are processed in order. This \
|
2019-10-02 13:23:02 +03:00
|
|
|
destination track is not yet destroyed. Its (future) destroy message will be \
|
|
|
|
processed after this message.") mRelativeToTrack;
|
2013-05-07 15:59:16 +04:00
|
|
|
uint32_t mIndex;
|
|
|
|
};
|
|
|
|
|
2016-01-21 00:14:33 +03:00
|
|
|
GraphImpl()->AppendMessage(MakeUnique<Message>(
|
2019-10-02 13:23:02 +03:00
|
|
|
this, aIndex, aContext->DestinationTrack(), aTrackTime));
|
2013-05-07 15:59:16 +04:00
|
|
|
}
|
|
|
|
|
2019-10-02 13:23:02 +03:00
|
|
|
void AudioNodeTrack::SetTrackTimeParameterImpl(uint32_t aIndex,
|
|
|
|
MediaTrack* aRelativeToTrack,
|
|
|
|
double aTrackTime) {
|
|
|
|
TrackTime ticks = aRelativeToTrack->SecondsToNearestTrackTime(aTrackTime);
|
|
|
|
mEngine->SetTrackTimeParameter(aIndex, ticks);
|
2013-05-07 15:59:16 +04:00
|
|
|
}
|
|
|
|
|
2019-10-02 13:23:02 +03:00
|
|
|
void AudioNodeTrack::SetDoubleParameter(uint32_t aIndex, double aValue) {
|
2015-04-28 09:42:00 +03:00
|
|
|
class Message final : public ControlMessage {
|
2013-05-07 15:59:16 +04:00
|
|
|
public:
|
2019-10-02 13:23:02 +03:00
|
|
|
Message(AudioNodeTrack* aTrack, uint32_t aIndex, double aValue)
|
|
|
|
: ControlMessage(aTrack), mValue(aValue), mIndex(aIndex) {}
|
2016-01-18 06:22:51 +03:00
|
|
|
void Run() override {
|
2019-10-02 13:23:02 +03:00
|
|
|
static_cast<AudioNodeTrack*>(mTrack)->Engine()->SetDoubleParameter(
|
2013-05-07 15:59:16 +04:00
|
|
|
mIndex, mValue);
|
|
|
|
}
|
|
|
|
double mValue;
|
|
|
|
uint32_t mIndex;
|
|
|
|
};
|
|
|
|
|
2016-01-21 00:14:33 +03:00
|
|
|
GraphImpl()->AppendMessage(MakeUnique<Message>(this, aIndex, aValue));
|
2013-05-07 15:59:16 +04:00
|
|
|
}
|
|
|
|
|
2019-10-02 13:23:02 +03:00
|
|
|
void AudioNodeTrack::SetInt32Parameter(uint32_t aIndex, int32_t aValue) {
|
2015-04-28 09:42:00 +03:00
|
|
|
class Message final : public ControlMessage {
|
2013-05-07 15:59:16 +04:00
|
|
|
public:
|
2019-10-02 13:23:02 +03:00
|
|
|
Message(AudioNodeTrack* aTrack, uint32_t aIndex, int32_t aValue)
|
|
|
|
: ControlMessage(aTrack), mValue(aValue), mIndex(aIndex) {}
|
2016-01-18 06:22:51 +03:00
|
|
|
void Run() override {
|
2019-10-02 13:23:02 +03:00
|
|
|
static_cast<AudioNodeTrack*>(mTrack)->Engine()->SetInt32Parameter(mIndex,
|
|
|
|
mValue);
|
2013-05-07 15:59:16 +04:00
|
|
|
}
|
|
|
|
int32_t mValue;
|
|
|
|
uint32_t mIndex;
|
|
|
|
};
|
|
|
|
|
2016-01-21 00:14:33 +03:00
|
|
|
GraphImpl()->AppendMessage(MakeUnique<Message>(this, aIndex, aValue));
|
2013-05-07 15:59:16 +04:00
|
|
|
}
|
|
|
|
|
2019-10-02 13:23:02 +03:00
|
|
|
void AudioNodeTrack::SendTimelineEvent(uint32_t aIndex,
|
|
|
|
const AudioTimelineEvent& aEvent) {
|
2015-04-28 09:42:00 +03:00
|
|
|
class Message final : public ControlMessage {
|
2013-05-07 15:59:16 +04:00
|
|
|
public:
|
2019-10-02 13:23:02 +03:00
|
|
|
Message(AudioNodeTrack* aTrack, uint32_t aIndex,
|
2015-09-25 16:57:55 +03:00
|
|
|
const AudioTimelineEvent& aEvent)
|
2019-10-02 13:23:02 +03:00
|
|
|
: ControlMessage(aTrack),
|
2015-09-25 16:57:55 +03:00
|
|
|
mEvent(aEvent),
|
2019-10-02 13:23:02 +03:00
|
|
|
mSampleRate(aTrack->mSampleRate),
|
2015-04-28 09:42:00 +03:00
|
|
|
mIndex(aIndex) {}
|
2016-01-18 06:22:51 +03:00
|
|
|
void Run() override {
|
2019-10-02 13:23:02 +03:00
|
|
|
static_cast<AudioNodeTrack*>(mTrack)->Engine()->RecvTimelineEvent(mIndex,
|
|
|
|
mEvent);
|
2013-05-07 15:59:16 +04:00
|
|
|
}
|
2015-09-25 16:57:55 +03:00
|
|
|
AudioTimelineEvent mEvent;
|
2013-05-24 21:10:08 +04:00
|
|
|
TrackRate mSampleRate;
|
2013-05-07 15:59:16 +04:00
|
|
|
uint32_t mIndex;
|
|
|
|
};
|
2016-01-21 00:14:33 +03:00
|
|
|
GraphImpl()->AppendMessage(MakeUnique<Message>(this, aIndex, aEvent));
|
2013-05-07 15:59:16 +04:00
|
|
|
}
|
|
|
|
|
2019-10-02 13:23:02 +03:00
|
|
|
void AudioNodeTrack::SetBuffer(AudioChunk&& aBuffer) {
|
2017-08-01 11:04:56 +03:00
|
|
|
class Message final : public ControlMessage {
|
|
|
|
public:
|
2019-10-02 13:23:02 +03:00
|
|
|
Message(AudioNodeTrack* aTrack, AudioChunk&& aBuffer)
|
|
|
|
: ControlMessage(aTrack), mBuffer(aBuffer) {}
|
2017-08-01 11:04:56 +03:00
|
|
|
void Run() override {
|
2019-10-02 13:23:02 +03:00
|
|
|
static_cast<AudioNodeTrack*>(mTrack)->Engine()->SetBuffer(
|
2018-05-30 22:15:35 +03:00
|
|
|
std::move(mBuffer));
|
2017-08-01 11:04:56 +03:00
|
|
|
}
|
|
|
|
AudioChunk mBuffer;
|
|
|
|
};
|
|
|
|
|
2018-05-30 22:15:35 +03:00
|
|
|
GraphImpl()->AppendMessage(MakeUnique<Message>(this, std::move(aBuffer)));
|
2017-08-01 11:04:56 +03:00
|
|
|
}
|
|
|
|
|
2019-10-02 13:23:02 +03:00
|
|
|
void AudioNodeTrack::SetReverb(WebCore::Reverb* aReverb,
|
|
|
|
uint32_t aImpulseChannelCount) {
|
2019-09-02 15:58:40 +03:00
|
|
|
class Message final : public ControlMessage {
|
|
|
|
public:
|
2019-10-02 13:23:02 +03:00
|
|
|
Message(AudioNodeTrack* aTrack, WebCore::Reverb* aReverb,
|
2019-10-02 13:22:55 +03:00
|
|
|
uint32_t aImpulseChannelCount)
|
2019-10-02 13:23:02 +03:00
|
|
|
: ControlMessage(aTrack),
|
2019-10-02 13:22:55 +03:00
|
|
|
mReverb(aReverb),
|
|
|
|
mImpulseChanelCount(aImpulseChannelCount) {}
|
2019-09-02 15:58:40 +03:00
|
|
|
void Run() override {
|
2019-10-02 13:23:02 +03:00
|
|
|
static_cast<AudioNodeTrack*>(mTrack)->Engine()->SetReverb(
|
2020-02-22 01:44:00 +03:00
|
|
|
mReverb.release(), mImpulseChanelCount);
|
2019-09-02 15:58:40 +03:00
|
|
|
}
|
2020-02-22 01:44:00 +03:00
|
|
|
UniquePtr<WebCore::Reverb> mReverb;
|
2019-09-02 15:58:40 +03:00
|
|
|
uint32_t mImpulseChanelCount;
|
|
|
|
};
|
|
|
|
|
2019-10-02 13:22:55 +03:00
|
|
|
GraphImpl()->AppendMessage(
|
|
|
|
MakeUnique<Message>(this, aReverb, aImpulseChannelCount));
|
2019-09-02 15:58:40 +03:00
|
|
|
}
|
|
|
|
|
2020-08-04 14:27:07 +03:00
|
|
|
void AudioNodeTrack::SetRawArrayData(nsTArray<float>&& aData) {
|
2015-04-28 09:42:00 +03:00
|
|
|
class Message final : public ControlMessage {
|
2013-05-14 08:12:30 +04:00
|
|
|
public:
|
2020-08-04 14:27:07 +03:00
|
|
|
Message(AudioNodeTrack* aTrack, nsTArray<float>&& aData)
|
|
|
|
: ControlMessage(aTrack), mData(std::move(aData)) {}
|
2016-01-18 06:22:51 +03:00
|
|
|
void Run() override {
|
2020-08-04 14:27:07 +03:00
|
|
|
static_cast<AudioNodeTrack*>(mTrack)->Engine()->SetRawArrayData(
|
|
|
|
std::move(mData));
|
2013-05-14 08:12:30 +04:00
|
|
|
}
|
|
|
|
nsTArray<float> mData;
|
|
|
|
};
|
|
|
|
|
2020-08-04 14:27:07 +03:00
|
|
|
GraphImpl()->AppendMessage(MakeUnique<Message>(this, std::move(aData)));
|
2013-05-14 08:12:30 +04:00
|
|
|
}
|
|
|
|
|
2019-10-02 13:23:02 +03:00
|
|
|
void AudioNodeTrack::SetChannelMixingParameters(
|
2013-05-07 15:59:16 +04:00
|
|
|
uint32_t aNumberOfChannels, ChannelCountMode aChannelCountMode,
|
|
|
|
ChannelInterpretation aChannelInterpretation) {
|
2015-04-28 09:42:00 +03:00
|
|
|
class Message final : public ControlMessage {
|
2013-05-07 15:59:16 +04:00
|
|
|
public:
|
2019-10-02 13:23:02 +03:00
|
|
|
Message(AudioNodeTrack* aTrack, uint32_t aNumberOfChannels,
|
2013-05-07 15:59:16 +04:00
|
|
|
ChannelCountMode aChannelCountMode,
|
|
|
|
ChannelInterpretation aChannelInterpretation)
|
2019-10-02 13:23:02 +03:00
|
|
|
: ControlMessage(aTrack),
|
2013-05-07 15:59:16 +04:00
|
|
|
mNumberOfChannels(aNumberOfChannels),
|
|
|
|
mChannelCountMode(aChannelCountMode),
|
|
|
|
mChannelInterpretation(aChannelInterpretation) {}
|
2016-01-18 06:22:51 +03:00
|
|
|
void Run() override {
|
2019-10-02 13:23:02 +03:00
|
|
|
static_cast<AudioNodeTrack*>(mTrack)->SetChannelMixingParametersImpl(
|
2013-05-07 15:59:16 +04:00
|
|
|
mNumberOfChannels, mChannelCountMode, mChannelInterpretation);
|
|
|
|
}
|
|
|
|
uint32_t mNumberOfChannels;
|
|
|
|
ChannelCountMode mChannelCountMode;
|
|
|
|
ChannelInterpretation mChannelInterpretation;
|
|
|
|
};
|
|
|
|
|
2016-01-21 00:14:33 +03:00
|
|
|
GraphImpl()->AppendMessage(MakeUnique<Message>(
|
|
|
|
this, aNumberOfChannels, aChannelCountMode, aChannelInterpretation));
|
2013-05-07 15:59:16 +04:00
|
|
|
}
|
|
|
|
|
2019-10-02 13:23:02 +03:00
|
|
|
void AudioNodeTrack::SetPassThrough(bool aPassThrough) {
|
2015-04-28 09:42:00 +03:00
|
|
|
class Message final : public ControlMessage {
|
2014-08-19 04:12:50 +04:00
|
|
|
public:
|
2019-10-02 13:23:02 +03:00
|
|
|
Message(AudioNodeTrack* aTrack, bool aPassThrough)
|
|
|
|
: ControlMessage(aTrack), mPassThrough(aPassThrough) {}
|
2016-01-18 06:22:51 +03:00
|
|
|
void Run() override {
|
2019-10-02 13:23:02 +03:00
|
|
|
static_cast<AudioNodeTrack*>(mTrack)->mPassThrough = mPassThrough;
|
2014-08-19 04:12:50 +04:00
|
|
|
}
|
|
|
|
bool mPassThrough;
|
|
|
|
};
|
|
|
|
|
2016-01-21 00:14:33 +03:00
|
|
|
GraphImpl()->AppendMessage(MakeUnique<Message>(this, aPassThrough));
|
2014-08-19 04:12:50 +04:00
|
|
|
}
|
|
|
|
|
2019-10-02 13:23:02 +03:00
|
|
|
void AudioNodeTrack::SendRunnable(already_AddRefed<nsIRunnable> aRunnable) {
|
2018-12-20 10:58:13 +03:00
|
|
|
class Message final : public ControlMessage {
|
|
|
|
public:
|
2019-10-02 13:23:02 +03:00
|
|
|
Message(MediaTrack* aTrack, already_AddRefed<nsIRunnable> aRunnable)
|
|
|
|
: ControlMessage(aTrack), mRunnable(aRunnable) {}
|
2018-12-20 10:58:13 +03:00
|
|
|
void Run() override { mRunnable->Run(); }
|
|
|
|
|
|
|
|
private:
|
|
|
|
nsCOMPtr<nsIRunnable> mRunnable;
|
|
|
|
};
|
|
|
|
|
|
|
|
GraphImpl()->AppendMessage(MakeUnique<Message>(this, std::move(aRunnable)));
|
|
|
|
}
|
|
|
|
|
2019-10-02 13:23:02 +03:00
|
|
|
void AudioNodeTrack::SetChannelMixingParametersImpl(
|
2013-05-07 15:59:16 +04:00
|
|
|
uint32_t aNumberOfChannels, ChannelCountMode aChannelCountMode,
|
|
|
|
ChannelInterpretation aChannelInterpretation) {
|
|
|
|
mNumberOfInputChannels = aNumberOfChannels;
|
2013-05-06 23:28:13 +04:00
|
|
|
mChannelCountMode = aChannelCountMode;
|
|
|
|
mChannelInterpretation = aChannelInterpretation;
|
2013-05-07 15:59:16 +04:00
|
|
|
}
|
|
|
|
|
2019-10-02 13:23:02 +03:00
|
|
|
uint32_t AudioNodeTrack::ComputedNumberOfChannels(uint32_t aInputChannelCount) {
|
2013-07-24 14:11:35 +04:00
|
|
|
switch (mChannelCountMode) {
|
|
|
|
case ChannelCountMode::Explicit:
|
|
|
|
// Disregard the channel count we've calculated from inputs, and just use
|
|
|
|
// mNumberOfInputChannels.
|
|
|
|
return mNumberOfInputChannels;
|
|
|
|
case ChannelCountMode::Clamped_max:
|
|
|
|
// Clamp the computed output channel count to mNumberOfInputChannels.
|
|
|
|
return std::min(aInputChannelCount, mNumberOfInputChannels);
|
|
|
|
default:
|
|
|
|
case ChannelCountMode::Max:
|
|
|
|
// Nothing to do here, just shut up the compiler warning.
|
|
|
|
return aInputChannelCount;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-11-19 21:22:55 +03:00
|
|
|
uint32_t AudioNodeTrack::NumberOfChannels() const {
|
|
|
|
MOZ_ASSERT(GraphImpl()->OnGraphThread());
|
|
|
|
|
|
|
|
return mNumberOfInputChannels;
|
|
|
|
}
|
|
|
|
|
2019-10-02 13:23:02 +03:00
|
|
|
class AudioNodeTrack::AdvanceAndResumeMessage final : public ControlMessage {
|
2015-09-23 10:05:46 +03:00
|
|
|
public:
|
2019-10-02 13:23:02 +03:00
|
|
|
AdvanceAndResumeMessage(AudioNodeTrack* aTrack, TrackTime aAdvance)
|
|
|
|
: ControlMessage(aTrack), mAdvance(aAdvance) {}
|
2016-01-18 06:22:51 +03:00
|
|
|
void Run() override {
|
2019-10-02 13:23:02 +03:00
|
|
|
auto ns = static_cast<AudioNodeTrack*>(mTrack);
|
2019-10-02 13:22:53 +03:00
|
|
|
ns->mStartTime -= mAdvance;
|
|
|
|
ns->mSegment->AppendNullData(mAdvance);
|
2020-05-27 11:34:13 +03:00
|
|
|
ns->DecrementSuspendCount();
|
2015-09-23 10:05:46 +03:00
|
|
|
}
|
2018-11-19 16:25:37 +03:00
|
|
|
|
2015-09-23 10:05:46 +03:00
|
|
|
private:
|
2019-10-02 13:23:02 +03:00
|
|
|
TrackTime mAdvance;
|
2015-09-23 10:05:46 +03:00
|
|
|
};
|
|
|
|
|
2019-10-02 13:23:02 +03:00
|
|
|
void AudioNodeTrack::AdvanceAndResume(TrackTime aAdvance) {
|
2015-09-23 10:05:46 +03:00
|
|
|
mMainThreadCurrentTime += aAdvance;
|
2016-01-21 00:14:33 +03:00
|
|
|
GraphImpl()->AppendMessage(
|
|
|
|
MakeUnique<AdvanceAndResumeMessage>(this, aAdvance));
|
2015-09-23 10:05:46 +03:00
|
|
|
}
|
|
|
|
|
2019-10-02 13:23:02 +03:00
|
|
|
void AudioNodeTrack::ObtainInputBlock(AudioBlock& aTmpChunk,
|
|
|
|
uint32_t aPortIndex) {
|
2013-05-07 15:59:16 +04:00
|
|
|
uint32_t inputCount = mInputs.Length();
|
|
|
|
uint32_t outputChannelCount = 1;
|
2016-02-02 18:36:30 +03:00
|
|
|
AutoTArray<const AudioBlock*, 250> inputChunks;
|
2013-05-07 15:59:16 +04:00
|
|
|
for (uint32_t i = 0; i < inputCount; ++i) {
|
|
|
|
if (aPortIndex != mInputs[i]->InputNumber()) {
|
|
|
|
// This input is connected to a different port
|
|
|
|
continue;
|
|
|
|
}
|
2019-10-02 13:23:02 +03:00
|
|
|
MediaTrack* t = mInputs[i]->GetSource();
|
|
|
|
AudioNodeTrack* a = static_cast<AudioNodeTrack*>(t);
|
|
|
|
MOZ_ASSERT(a == t->AsAudioNodeTrack());
|
|
|
|
if (a->IsAudioParamTrack()) {
|
2013-05-07 15:59:16 +04:00
|
|
|
continue;
|
|
|
|
}
|
2013-08-26 21:19:36 +04:00
|
|
|
|
2015-09-03 10:01:50 +03:00
|
|
|
const AudioBlock* chunk = &a->mLastChunks[mInputs[i]->OutputNumber()];
|
2013-05-07 15:59:16 +04:00
|
|
|
MOZ_ASSERT(chunk);
|
2013-08-16 18:42:50 +04:00
|
|
|
if (chunk->IsNull() || chunk->mChannelData.IsEmpty()) {
|
2013-05-07 15:59:16 +04:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
inputChunks.AppendElement(chunk);
|
|
|
|
outputChannelCount =
|
2015-09-03 08:30:16 +03:00
|
|
|
GetAudioChannelsSuperset(outputChannelCount, chunk->ChannelCount());
|
2013-05-07 15:59:16 +04:00
|
|
|
}
|
|
|
|
|
2014-04-01 01:26:02 +04:00
|
|
|
outputChannelCount = ComputedNumberOfChannels(outputChannelCount);
|
2013-05-07 15:59:16 +04:00
|
|
|
|
|
|
|
uint32_t inputChunkCount = inputChunks.Length();
|
2013-05-08 07:31:55 +04:00
|
|
|
if (inputChunkCount == 0 ||
|
2015-09-03 08:30:16 +03:00
|
|
|
(inputChunkCount == 1 && inputChunks[0]->ChannelCount() == 0)) {
|
2013-05-07 15:59:16 +04:00
|
|
|
aTmpChunk.SetNull(WEBAUDIO_BLOCK_SIZE);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (inputChunkCount == 1 &&
|
2015-09-03 08:30:16 +03:00
|
|
|
inputChunks[0]->ChannelCount() == outputChannelCount) {
|
2013-05-07 15:59:16 +04:00
|
|
|
aTmpChunk = *inputChunks[0];
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-05-29 15:40:14 +04:00
|
|
|
if (outputChannelCount == 0) {
|
|
|
|
aTmpChunk.SetNull(WEBAUDIO_BLOCK_SIZE);
|
|
|
|
return;
|
|
|
|
}
|
2013-05-23 15:46:20 +04:00
|
|
|
|
2015-09-03 10:01:50 +03:00
|
|
|
aTmpChunk.AllocateChannels(outputChannelCount);
|
2016-05-17 22:47:56 +03:00
|
|
|
DownmixBufferType downmixBuffer;
|
|
|
|
ASSERT_ALIGNED16(downmixBuffer.Elements());
|
2013-05-07 15:59:16 +04:00
|
|
|
|
|
|
|
for (uint32_t i = 0; i < inputChunkCount; ++i) {
|
2013-07-24 14:11:35 +04:00
|
|
|
AccumulateInputChunk(i, *inputChunks[i], &aTmpChunk, &downmixBuffer);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-10-02 13:23:02 +03:00
|
|
|
void AudioNodeTrack::AccumulateInputChunk(uint32_t aInputIndex,
|
|
|
|
const AudioBlock& aChunk,
|
|
|
|
AudioBlock* aBlock,
|
|
|
|
DownmixBufferType* aDownmixBuffer) {
|
2016-02-02 18:36:30 +03:00
|
|
|
AutoTArray<const float*, GUESS_AUDIO_CHANNELS> channels;
|
2015-09-03 08:30:16 +03:00
|
|
|
UpMixDownMixChunk(&aChunk, aBlock->ChannelCount(), channels, *aDownmixBuffer);
|
2013-07-24 14:11:35 +04:00
|
|
|
|
|
|
|
for (uint32_t c = 0; c < channels.Length(); ++c) {
|
|
|
|
const float* inputData = static_cast<const float*>(channels[c]);
|
2015-07-22 08:59:21 +03:00
|
|
|
float* outputData = aBlock->ChannelFloatsForWrite(c);
|
2013-07-24 14:11:35 +04:00
|
|
|
if (inputData) {
|
|
|
|
if (aInputIndex == 0) {
|
|
|
|
AudioBlockCopyChannelWithScale(inputData, aChunk.mVolume, outputData);
|
2013-05-07 15:59:16 +04:00
|
|
|
} else {
|
2013-07-24 14:11:35 +04:00
|
|
|
AudioBlockAddChannelWithScale(inputData, aChunk.mVolume, outputData);
|
2013-05-07 15:59:16 +04:00
|
|
|
}
|
2013-07-24 14:11:35 +04:00
|
|
|
} else {
|
|
|
|
if (aInputIndex == 0) {
|
|
|
|
PodZero(outputData, WEBAUDIO_BLOCK_SIZE);
|
2013-05-07 15:59:16 +04:00
|
|
|
}
|
|
|
|
}
|
2013-07-24 14:11:35 +04:00
|
|
|
}
|
|
|
|
}
|
2013-05-07 15:59:16 +04:00
|
|
|
|
2019-10-02 13:23:02 +03:00
|
|
|
void AudioNodeTrack::UpMixDownMixChunk(const AudioBlock* aChunk,
|
|
|
|
uint32_t aOutputChannelCount,
|
|
|
|
nsTArray<const float*>& aOutputChannels,
|
|
|
|
DownmixBufferType& aDownmixBuffer) {
|
2015-09-03 08:30:16 +03:00
|
|
|
for (uint32_t i = 0; i < aChunk->ChannelCount(); i++) {
|
2015-07-29 19:36:47 +03:00
|
|
|
aOutputChannels.AppendElement(
|
|
|
|
static_cast<const float*>(aChunk->mChannelData[i]));
|
|
|
|
}
|
2013-07-24 14:11:35 +04:00
|
|
|
if (aOutputChannels.Length() < aOutputChannelCount) {
|
|
|
|
if (mChannelInterpretation == ChannelInterpretation::Speakers) {
|
2015-09-05 02:01:54 +03:00
|
|
|
AudioChannelsUpMix<float>(&aOutputChannels, aOutputChannelCount, nullptr);
|
2013-07-24 14:11:35 +04:00
|
|
|
NS_ASSERTION(aOutputChannelCount == aOutputChannels.Length(),
|
|
|
|
"We called GetAudioChannelsSuperset to avoid this");
|
|
|
|
} else {
|
|
|
|
// Fill up the remaining aOutputChannels by zeros
|
|
|
|
for (uint32_t j = aOutputChannels.Length(); j < aOutputChannelCount;
|
|
|
|
++j) {
|
2015-09-05 02:01:54 +03:00
|
|
|
aOutputChannels.AppendElement(nullptr);
|
2013-07-24 14:11:35 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if (aOutputChannels.Length() > aOutputChannelCount) {
|
|
|
|
if (mChannelInterpretation == ChannelInterpretation::Speakers) {
|
2016-02-02 18:36:30 +03:00
|
|
|
AutoTArray<float*, GUESS_AUDIO_CHANNELS> outputChannels;
|
2013-07-24 14:11:35 +04:00
|
|
|
outputChannels.SetLength(aOutputChannelCount);
|
|
|
|
aDownmixBuffer.SetLength(aOutputChannelCount * WEBAUDIO_BLOCK_SIZE);
|
|
|
|
for (uint32_t j = 0; j < aOutputChannelCount; ++j) {
|
|
|
|
outputChannels[j] = &aDownmixBuffer[j * WEBAUDIO_BLOCK_SIZE];
|
|
|
|
}
|
|
|
|
|
|
|
|
AudioChannelsDownMix(aOutputChannels, outputChannels.Elements(),
|
|
|
|
aOutputChannelCount, WEBAUDIO_BLOCK_SIZE);
|
|
|
|
|
|
|
|
aOutputChannels.SetLength(aOutputChannelCount);
|
|
|
|
for (uint32_t j = 0; j < aOutputChannels.Length(); ++j) {
|
|
|
|
aOutputChannels[j] = outputChannels[j];
|
2013-05-07 15:59:16 +04:00
|
|
|
}
|
2013-07-24 14:11:35 +04:00
|
|
|
} else {
|
|
|
|
// Drop the remaining aOutputChannels
|
2020-06-08 11:50:15 +03:00
|
|
|
aOutputChannels.RemoveLastElements(aOutputChannels.Length() -
|
|
|
|
aOutputChannelCount);
|
2013-05-07 15:59:16 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-10-02 13:23:02 +03:00
|
|
|
// The MediaTrackGraph guarantees that this is actually one block, for
|
|
|
|
// AudioNodeTracks.
|
|
|
|
void AudioNodeTrack::ProcessInput(GraphTime aFrom, GraphTime aTo,
|
|
|
|
uint32_t aFlags) {
|
2014-11-18 06:22:45 +03:00
|
|
|
uint16_t outputCount = mLastChunks.Length();
|
|
|
|
MOZ_ASSERT(outputCount == std::max(uint16_t(1), mEngine->OutputCount()));
|
2013-05-07 15:59:16 +04:00
|
|
|
|
2015-09-17 15:03:00 +03:00
|
|
|
if (!mIsActive) {
|
|
|
|
// mLastChunks are already null.
|
|
|
|
#ifdef DEBUG
|
|
|
|
for (const auto& chunk : mLastChunks) {
|
|
|
|
MOZ_ASSERT(chunk.IsNull());
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
} else if (InMutedCycle()) {
|
2015-08-20 09:41:25 +03:00
|
|
|
mInputChunks.Clear();
|
2013-05-24 06:36:20 +04:00
|
|
|
for (uint16_t i = 0; i < outputCount; ++i) {
|
|
|
|
mLastChunks[i].SetNull(WEBAUDIO_BLOCK_SIZE);
|
|
|
|
}
|
2013-05-07 15:59:16 +04:00
|
|
|
} else {
|
|
|
|
// We need to generate at least one input
|
|
|
|
uint16_t maxInputs = std::max(uint16_t(1), mEngine->InputCount());
|
2015-08-20 09:41:25 +03:00
|
|
|
mInputChunks.SetLength(maxInputs);
|
2013-05-07 15:59:16 +04:00
|
|
|
for (uint16_t i = 0; i < maxInputs; ++i) {
|
2015-08-20 09:41:25 +03:00
|
|
|
ObtainInputBlock(mInputChunks[i], i);
|
2013-05-07 15:59:16 +04:00
|
|
|
}
|
|
|
|
bool finished = false;
|
2014-08-19 04:12:50 +04:00
|
|
|
if (mPassThrough) {
|
|
|
|
MOZ_ASSERT(outputCount == 1,
|
|
|
|
"For now, we only support nodes that have one output port");
|
2015-08-20 09:41:25 +03:00
|
|
|
mLastChunks[0] = mInputChunks[0];
|
2013-05-07 15:59:16 +04:00
|
|
|
} else {
|
2014-11-18 06:22:45 +03:00
|
|
|
if (maxInputs <= 1 && outputCount <= 1) {
|
2015-09-18 08:05:25 +03:00
|
|
|
mEngine->ProcessBlock(this, aFrom, mInputChunks[0], &mLastChunks[0],
|
|
|
|
&finished);
|
2014-08-19 04:12:50 +04:00
|
|
|
} else {
|
2020-01-15 17:44:39 +03:00
|
|
|
mEngine->ProcessBlocksOnPorts(
|
2020-08-07 10:49:47 +03:00
|
|
|
this, aFrom, Span(mInputChunks.Elements(), mEngine->InputCount()),
|
|
|
|
Span(mLastChunks.Elements(), mEngine->OutputCount()), &finished);
|
2014-08-19 04:12:50 +04:00
|
|
|
}
|
2013-05-07 15:59:16 +04:00
|
|
|
}
|
2013-12-12 16:33:01 +04:00
|
|
|
for (uint16_t i = 0; i < outputCount; ++i) {
|
|
|
|
NS_ASSERTION(mLastChunks[i].GetDuration() == WEBAUDIO_BLOCK_SIZE,
|
|
|
|
"Invalid WebAudio chunk size");
|
|
|
|
}
|
2013-05-07 15:59:16 +04:00
|
|
|
if (finished) {
|
2019-10-02 13:22:53 +03:00
|
|
|
mMarkAsEndedAfterThisBlock = true;
|
2015-10-22 23:37:45 +03:00
|
|
|
if (mIsActive) {
|
|
|
|
ScheduleCheckForInactive();
|
|
|
|
}
|
2013-05-07 15:59:16 +04:00
|
|
|
}
|
|
|
|
|
2019-10-02 13:22:53 +03:00
|
|
|
if (mDisabledMode != DisabledTrackMode::ENABLED) {
|
2014-01-15 14:07:30 +04:00
|
|
|
for (uint32_t i = 0; i < outputCount; ++i) {
|
|
|
|
mLastChunks[i].SetNull(WEBAUDIO_BLOCK_SIZE);
|
|
|
|
}
|
2013-05-30 08:44:43 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-10-02 13:22:53 +03:00
|
|
|
if (!mEnded) {
|
2015-09-04 08:40:30 +03:00
|
|
|
// Don't output anything while finished
|
2015-09-18 08:07:40 +03:00
|
|
|
if (mFlags & EXTERNAL_OUTPUT) {
|
|
|
|
AdvanceOutputSegment();
|
|
|
|
}
|
2019-10-02 13:22:53 +03:00
|
|
|
if (mMarkAsEndedAfterThisBlock && (aFlags & ALLOW_END)) {
|
2019-10-02 13:23:02 +03:00
|
|
|
// This track was ended the last time that we looked at it, and all
|
|
|
|
// of the depending tracks have ended their output as well, so now
|
|
|
|
// it's time to mark this track as ended.
|
2019-10-02 13:22:53 +03:00
|
|
|
mEnded = true;
|
2013-12-06 00:23:57 +04:00
|
|
|
}
|
|
|
|
}
|
2013-07-24 14:11:35 +04:00
|
|
|
}
|
|
|
|
|
2019-10-02 13:23:02 +03:00
|
|
|
void AudioNodeTrack::ProduceOutputBeforeInput(GraphTime aFrom) {
|
2014-07-17 04:55:55 +04:00
|
|
|
MOZ_ASSERT(mEngine->AsDelayNodeEngine());
|
|
|
|
MOZ_ASSERT(mEngine->OutputCount() == 1,
|
|
|
|
"DelayNodeEngine output count should be 1");
|
|
|
|
MOZ_ASSERT(!InMutedCycle(), "DelayNodes should break cycles");
|
2014-11-18 06:22:45 +03:00
|
|
|
MOZ_ASSERT(mLastChunks.Length() == 1);
|
2014-07-17 04:55:55 +04:00
|
|
|
|
2015-09-17 15:03:00 +03:00
|
|
|
if (!mIsActive) {
|
2014-07-17 04:55:55 +04:00
|
|
|
mLastChunks[0].SetNull(WEBAUDIO_BLOCK_SIZE);
|
|
|
|
} else {
|
2015-09-29 04:39:28 +03:00
|
|
|
mEngine->ProduceBlockBeforeInput(this, aFrom, &mLastChunks[0]);
|
2014-07-17 04:55:55 +04:00
|
|
|
NS_ASSERTION(mLastChunks[0].GetDuration() == WEBAUDIO_BLOCK_SIZE,
|
|
|
|
"Invalid WebAudio chunk size");
|
2019-10-02 13:22:53 +03:00
|
|
|
if (mDisabledMode != DisabledTrackMode::ENABLED) {
|
2014-07-17 04:55:55 +04:00
|
|
|
mLastChunks[0].SetNull(WEBAUDIO_BLOCK_SIZE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-10-02 13:23:02 +03:00
|
|
|
void AudioNodeTrack::AdvanceOutputSegment() {
|
2019-10-02 13:22:53 +03:00
|
|
|
AudioSegment* segment = GetData<AudioSegment>();
|
2013-07-24 14:11:35 +04:00
|
|
|
|
2016-11-17 12:19:12 +03:00
|
|
|
AudioChunk copyChunk = *mLastChunks[0].AsMutableChunk();
|
|
|
|
AudioSegment tmpSegment;
|
|
|
|
tmpSegment.AppendAndConsumeChunk(©Chunk);
|
2013-05-07 15:59:16 +04:00
|
|
|
|
2019-10-02 13:22:53 +03:00
|
|
|
for (const auto& l : mTrackListeners) {
|
2019-10-02 13:23:02 +03:00
|
|
|
// Notify MediaTrackListeners.
|
2019-10-02 13:22:53 +03:00
|
|
|
l->NotifyQueuedChanges(Graph(), segment->GetDuration(), tmpSegment);
|
2016-11-17 12:19:12 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
if (mLastChunks[0].IsNull()) {
|
|
|
|
segment->AppendNullData(tmpSegment.GetDuration());
|
|
|
|
} else {
|
|
|
|
segment->AppendFrom(&tmpSegment);
|
|
|
|
}
|
2013-05-07 15:59:16 +04:00
|
|
|
}
|
|
|
|
|
2019-10-02 13:23:02 +03:00
|
|
|
void AudioNodeTrack::AddInput(MediaInputPort* aPort) {
|
|
|
|
ProcessedMediaTrack::AddInput(aPort);
|
|
|
|
AudioNodeTrack* ns = aPort->GetSource()->AsAudioNodeTrack();
|
|
|
|
// Tracks that are not AudioNodeTracks are considered active.
|
|
|
|
if (!ns || (ns->mIsActive && !ns->IsAudioParamTrack())) {
|
2015-09-17 15:03:00 +03:00
|
|
|
IncrementActiveInputCount();
|
|
|
|
}
|
|
|
|
}
|
2019-10-02 13:23:02 +03:00
|
|
|
void AudioNodeTrack::RemoveInput(MediaInputPort* aPort) {
|
|
|
|
ProcessedMediaTrack::RemoveInput(aPort);
|
|
|
|
AudioNodeTrack* ns = aPort->GetSource()->AsAudioNodeTrack();
|
|
|
|
// Tracks that are not AudioNodeTracks are considered active.
|
|
|
|
if (!ns || (ns->mIsActive && !ns->IsAudioParamTrack())) {
|
2015-09-17 15:03:00 +03:00
|
|
|
DecrementActiveInputCount();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-10-02 13:23:02 +03:00
|
|
|
void AudioNodeTrack::SetActive() {
|
2019-10-02 13:22:53 +03:00
|
|
|
if (mIsActive || mMarkAsEndedAfterThisBlock) {
|
2015-09-17 15:03:00 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
mIsActive = true;
|
2015-10-23 01:38:11 +03:00
|
|
|
if (!(mFlags & EXTERNAL_OUTPUT)) {
|
2020-05-27 11:34:13 +03:00
|
|
|
DecrementSuspendCount();
|
2015-10-23 01:38:11 +03:00
|
|
|
}
|
2019-10-02 13:23:02 +03:00
|
|
|
if (IsAudioParamTrack()) {
|
|
|
|
// Consumers merely influence track order.
|
|
|
|
// They do not read from the track.
|
2015-09-17 15:03:00 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (const auto& consumer : mConsumers) {
|
2019-10-02 13:23:02 +03:00
|
|
|
AudioNodeTrack* ns = consumer->GetDestination()->AsAudioNodeTrack();
|
2015-09-17 15:03:00 +03:00
|
|
|
if (ns) {
|
|
|
|
ns->IncrementActiveInputCount();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-10-02 13:23:02 +03:00
|
|
|
class AudioNodeTrack::CheckForInactiveMessage final : public ControlMessage {
|
2015-10-22 23:37:45 +03:00
|
|
|
public:
|
2019-10-02 13:23:02 +03:00
|
|
|
explicit CheckForInactiveMessage(AudioNodeTrack* aTrack)
|
|
|
|
: ControlMessage(aTrack) {}
|
2016-01-18 06:22:51 +03:00
|
|
|
void Run() override {
|
2019-10-02 13:23:02 +03:00
|
|
|
auto ns = static_cast<AudioNodeTrack*>(mTrack);
|
2015-10-22 23:37:45 +03:00
|
|
|
ns->CheckForInactive();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2019-10-02 13:23:02 +03:00
|
|
|
void AudioNodeTrack::ScheduleCheckForInactive() {
|
2019-10-02 13:22:53 +03:00
|
|
|
if (mActiveInputCount > 0 && !mMarkAsEndedAfterThisBlock) {
|
2015-10-22 23:37:45 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-01-21 00:14:33 +03:00
|
|
|
auto message = MakeUnique<CheckForInactiveMessage>(this);
|
2018-05-30 22:15:35 +03:00
|
|
|
GraphImpl()->RunMessageAfterProcessing(std::move(message));
|
2015-10-22 23:37:45 +03:00
|
|
|
}
|
|
|
|
|
2019-10-02 13:23:02 +03:00
|
|
|
void AudioNodeTrack::CheckForInactive() {
|
2015-09-17 15:03:00 +03:00
|
|
|
if (((mActiveInputCount > 0 || mEngine->IsActive()) &&
|
2019-10-02 13:22:53 +03:00
|
|
|
!mMarkAsEndedAfterThisBlock) ||
|
2015-09-17 15:03:00 +03:00
|
|
|
!mIsActive) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
mIsActive = false;
|
|
|
|
mInputChunks.Clear(); // not required for foreseeable future
|
|
|
|
for (auto& chunk : mLastChunks) {
|
|
|
|
chunk.SetNull(WEBAUDIO_BLOCK_SIZE);
|
|
|
|
}
|
2015-10-23 01:38:11 +03:00
|
|
|
if (!(mFlags & EXTERNAL_OUTPUT)) {
|
2020-05-27 11:34:13 +03:00
|
|
|
IncrementSuspendCount();
|
2015-10-23 01:38:11 +03:00
|
|
|
}
|
2019-10-02 13:23:02 +03:00
|
|
|
if (IsAudioParamTrack()) {
|
2015-09-17 15:03:00 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (const auto& consumer : mConsumers) {
|
2019-10-02 13:23:02 +03:00
|
|
|
AudioNodeTrack* ns = consumer->GetDestination()->AsAudioNodeTrack();
|
2015-09-17 15:03:00 +03:00
|
|
|
if (ns) {
|
|
|
|
ns->DecrementActiveInputCount();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-10-02 13:23:02 +03:00
|
|
|
void AudioNodeTrack::IncrementActiveInputCount() {
|
2015-09-17 15:03:00 +03:00
|
|
|
++mActiveInputCount;
|
|
|
|
SetActive();
|
|
|
|
}
|
|
|
|
|
2019-10-02 13:23:02 +03:00
|
|
|
void AudioNodeTrack::DecrementActiveInputCount() {
|
2015-09-17 15:03:00 +03:00
|
|
|
MOZ_ASSERT(mActiveInputCount > 0);
|
|
|
|
--mActiveInputCount;
|
|
|
|
CheckForInactive();
|
|
|
|
}
|
|
|
|
|
2015-07-13 18:25:42 +03:00
|
|
|
} // namespace mozilla
|