зеркало из https://github.com/mozilla/gecko-dev.git
bug 1205540 account for active inputs and skip processing when streams are inactive r=padenot
--HG-- extra : rebase_source : ad55142a54728e7ed2dab8edefbe87547e09d85a
This commit is contained in:
Родитель
985811fe37
Коммит
abcc44d6d5
|
@ -68,7 +68,11 @@ public:
|
||||||
if (aInput.IsNull()) {
|
if (aInput.IsNull()) {
|
||||||
// If AnalyserNode::mChunks has only null chunks, then there is no need
|
// If AnalyserNode::mChunks has only null chunks, then there is no need
|
||||||
// to send further null chunks.
|
// to send further null chunks.
|
||||||
if (mChunksToProcess == 0) {
|
if (mChunksToProcess <= 0) {
|
||||||
|
if (mChunksToProcess != INT32_MIN) {
|
||||||
|
mChunksToProcess = INT32_MIN;
|
||||||
|
aStream->CheckForInactive();
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -85,7 +89,7 @@ public:
|
||||||
|
|
||||||
virtual bool IsActive() const override
|
virtual bool IsActive() const override
|
||||||
{
|
{
|
||||||
return mChunksToProcess != 0;
|
return mChunksToProcess != INT32_MIN;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const override
|
virtual size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const override
|
||||||
|
@ -93,7 +97,7 @@ public:
|
||||||
return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
|
return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t mChunksToProcess = 0;
|
int32_t mChunksToProcess = INT32_MIN;
|
||||||
};
|
};
|
||||||
|
|
||||||
AnalyserNode::AnalyserNode(AudioContext* aContext)
|
AnalyserNode::AnalyserNode(AudioContext* aContext)
|
||||||
|
|
|
@ -111,7 +111,11 @@ public:
|
||||||
virtual void SetInt32Parameter(uint32_t aIndex, int32_t aParam) override
|
virtual void SetInt32Parameter(uint32_t aIndex, int32_t aParam) override
|
||||||
{
|
{
|
||||||
switch (aIndex) {
|
switch (aIndex) {
|
||||||
case AudioBufferSourceNode::SAMPLE_RATE: mBufferSampleRate = aParam; break;
|
case AudioBufferSourceNode::SAMPLE_RATE:
|
||||||
|
MOZ_ASSERT(aParam > 0);
|
||||||
|
mBufferSampleRate = aParam;
|
||||||
|
mSource->SetActive();
|
||||||
|
break;
|
||||||
case AudioBufferSourceNode::BUFFERSTART:
|
case AudioBufferSourceNode::BUFFERSTART:
|
||||||
MOZ_ASSERT(aParam >= 0);
|
MOZ_ASSERT(aParam >= 0);
|
||||||
if (mBufferPosition == 0) {
|
if (mBufferPosition == 0) {
|
||||||
|
|
|
@ -309,8 +309,10 @@ public:
|
||||||
* aInput is guaranteed to have float sample format (if it has samples at all)
|
* aInput is guaranteed to have float sample format (if it has samples at all)
|
||||||
* and to have been resampled to the sampling rate for the stream, and to have
|
* and to have been resampled to the sampling rate for the stream, and to have
|
||||||
* exactly WEBAUDIO_BLOCK_SIZE samples.
|
* exactly WEBAUDIO_BLOCK_SIZE samples.
|
||||||
* *aFinished is set to false by the caller. If the callee sets it to true,
|
* *aFinished is set to false by the caller. The callee must not set this to
|
||||||
* we'll finish the stream and not call this again.
|
* true unless silent output is produced. If set to true, we'll finish the
|
||||||
|
* stream, consider this input inactive on any downstream nodes, and not
|
||||||
|
* call this again.
|
||||||
*/
|
*/
|
||||||
virtual void ProcessBlock(AudioNodeStream* aStream,
|
virtual void ProcessBlock(AudioNodeStream* aStream,
|
||||||
const AudioBlock& aInput,
|
const AudioBlock& aInput,
|
||||||
|
|
|
@ -34,6 +34,7 @@ AudioNodeStream::AudioNodeStream(AudioNodeEngine* aEngine,
|
||||||
mSampleRate(aSampleRate),
|
mSampleRate(aSampleRate),
|
||||||
mFlags(aFlags),
|
mFlags(aFlags),
|
||||||
mNumberOfInputChannels(2),
|
mNumberOfInputChannels(2),
|
||||||
|
mIsActive(aEngine->IsActive()),
|
||||||
mMarkAsFinishedAfterThisBlock(false),
|
mMarkAsFinishedAfterThisBlock(false),
|
||||||
mAudioParamStream(false),
|
mAudioParamStream(false),
|
||||||
mPassThrough(false)
|
mPassThrough(false)
|
||||||
|
@ -49,6 +50,7 @@ AudioNodeStream::AudioNodeStream(AudioNodeEngine* aEngine,
|
||||||
|
|
||||||
AudioNodeStream::~AudioNodeStream()
|
AudioNodeStream::~AudioNodeStream()
|
||||||
{
|
{
|
||||||
|
MOZ_ASSERT(mActiveInputCount == 0);
|
||||||
MOZ_COUNT_DTOR(AudioNodeStream);
|
MOZ_COUNT_DTOR(AudioNodeStream);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -520,7 +522,14 @@ AudioNodeStream::ProcessInput(GraphTime aFrom, GraphTime aTo, uint32_t aFlags)
|
||||||
uint16_t outputCount = mLastChunks.Length();
|
uint16_t outputCount = mLastChunks.Length();
|
||||||
MOZ_ASSERT(outputCount == std::max(uint16_t(1), mEngine->OutputCount()));
|
MOZ_ASSERT(outputCount == std::max(uint16_t(1), mEngine->OutputCount()));
|
||||||
|
|
||||||
if (mFinished || InMutedCycle()) {
|
if (!mIsActive) {
|
||||||
|
// mLastChunks are already null.
|
||||||
|
#ifdef DEBUG
|
||||||
|
for (const auto& chunk : mLastChunks) {
|
||||||
|
MOZ_ASSERT(chunk.IsNull());
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
} else if (InMutedCycle()) {
|
||||||
mInputChunks.Clear();
|
mInputChunks.Clear();
|
||||||
for (uint16_t i = 0; i < outputCount; ++i) {
|
for (uint16_t i = 0; i < outputCount; ++i) {
|
||||||
mLastChunks[i].SetNull(WEBAUDIO_BLOCK_SIZE);
|
mLastChunks[i].SetNull(WEBAUDIO_BLOCK_SIZE);
|
||||||
|
@ -549,6 +558,7 @@ AudioNodeStream::ProcessInput(GraphTime aFrom, GraphTime aTo, uint32_t aFlags)
|
||||||
}
|
}
|
||||||
if (finished) {
|
if (finished) {
|
||||||
mMarkAsFinishedAfterThisBlock = true;
|
mMarkAsFinishedAfterThisBlock = true;
|
||||||
|
CheckForInactive();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mDisabledTrackIDs.Contains(static_cast<TrackID>(AUDIO_TRACK))) {
|
if (mDisabledTrackIDs.Contains(static_cast<TrackID>(AUDIO_TRACK))) {
|
||||||
|
@ -579,7 +589,7 @@ AudioNodeStream::ProduceOutputBeforeInput(GraphTime aFrom)
|
||||||
MOZ_ASSERT(!InMutedCycle(), "DelayNodes should break cycles");
|
MOZ_ASSERT(!InMutedCycle(), "DelayNodes should break cycles");
|
||||||
MOZ_ASSERT(mLastChunks.Length() == 1);
|
MOZ_ASSERT(mLastChunks.Length() == 1);
|
||||||
|
|
||||||
if (mFinished) {
|
if (!mIsActive) {
|
||||||
mLastChunks[0].SetNull(WEBAUDIO_BLOCK_SIZE);
|
mLastChunks[0].SetNull(WEBAUDIO_BLOCK_SIZE);
|
||||||
} else {
|
} else {
|
||||||
mEngine->ProduceBlockBeforeInput(&mLastChunks[0]);
|
mEngine->ProduceBlockBeforeInput(&mLastChunks[0]);
|
||||||
|
@ -684,4 +694,88 @@ AudioNodeStream::DestinationTimeFromTicks(AudioNodeStream* aDestination,
|
||||||
return StreamTimeToSeconds(destinationTime);
|
return StreamTimeToSeconds(destinationTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
AudioNodeStream::AddInput(MediaInputPort* aPort)
|
||||||
|
{
|
||||||
|
ProcessedMediaStream::AddInput(aPort);
|
||||||
|
AudioNodeStream* ns = aPort->GetSource()->AsAudioNodeStream();
|
||||||
|
// Streams that are not AudioNodeStreams are considered active.
|
||||||
|
if (!ns || (ns->mIsActive && !ns->IsAudioParamStream())) {
|
||||||
|
IncrementActiveInputCount();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void
|
||||||
|
AudioNodeStream::RemoveInput(MediaInputPort* aPort)
|
||||||
|
{
|
||||||
|
ProcessedMediaStream::RemoveInput(aPort);
|
||||||
|
AudioNodeStream* ns = aPort->GetSource()->AsAudioNodeStream();
|
||||||
|
// Streams that are not AudioNodeStreams are considered active.
|
||||||
|
if (!ns || (ns->mIsActive && !ns->IsAudioParamStream())) {
|
||||||
|
DecrementActiveInputCount();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
AudioNodeStream::SetActive()
|
||||||
|
{
|
||||||
|
if (mIsActive || mMarkAsFinishedAfterThisBlock) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mIsActive = true;
|
||||||
|
if (IsAudioParamStream()) {
|
||||||
|
// Consumers merely influence stream order.
|
||||||
|
// They do not read from the stream.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto& consumer : mConsumers) {
|
||||||
|
AudioNodeStream* ns = consumer->GetDestination()->AsAudioNodeStream();
|
||||||
|
if (ns) {
|
||||||
|
ns->IncrementActiveInputCount();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
AudioNodeStream::CheckForInactive()
|
||||||
|
{
|
||||||
|
if (((mActiveInputCount > 0 || mEngine->IsActive()) &&
|
||||||
|
!mMarkAsFinishedAfterThisBlock) ||
|
||||||
|
!mIsActive) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mIsActive = false;
|
||||||
|
mInputChunks.Clear(); // not required for foreseeable future
|
||||||
|
for (auto& chunk : mLastChunks) {
|
||||||
|
chunk.SetNull(WEBAUDIO_BLOCK_SIZE);
|
||||||
|
}
|
||||||
|
if (IsAudioParamStream()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto& consumer : mConsumers) {
|
||||||
|
AudioNodeStream* ns = consumer->GetDestination()->AsAudioNodeStream();
|
||||||
|
if (ns) {
|
||||||
|
ns->DecrementActiveInputCount();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
AudioNodeStream::IncrementActiveInputCount()
|
||||||
|
{
|
||||||
|
++mActiveInputCount;
|
||||||
|
SetActive();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
AudioNodeStream::DecrementActiveInputCount()
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(mActiveInputCount > 0);
|
||||||
|
--mActiveInputCount;
|
||||||
|
CheckForInactive();
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace mozilla
|
} // namespace mozilla
|
||||||
|
|
|
@ -106,6 +106,8 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual AudioNodeStream* AsAudioNodeStream() override { return this; }
|
virtual AudioNodeStream* AsAudioNodeStream() override { return this; }
|
||||||
|
virtual void AddInput(MediaInputPort* aPort) override;
|
||||||
|
virtual void RemoveInput(MediaInputPort* aPort) override;
|
||||||
|
|
||||||
// Graph thread only
|
// Graph thread only
|
||||||
void SetStreamTimeParameterImpl(uint32_t aIndex, MediaStream* aRelativeToStream,
|
void SetStreamTimeParameterImpl(uint32_t aIndex, MediaStream* aRelativeToStream,
|
||||||
|
@ -165,6 +167,22 @@ public:
|
||||||
void SizeOfAudioNodesIncludingThis(MallocSizeOf aMallocSizeOf,
|
void SizeOfAudioNodesIncludingThis(MallocSizeOf aMallocSizeOf,
|
||||||
AudioNodeSizes& aUsage) const;
|
AudioNodeSizes& aUsage) const;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* SetActive() is called when either an active input is added or the engine
|
||||||
|
* for a source node transitions from inactive to active. This is not
|
||||||
|
* called from engines for processing nodes because they only become active
|
||||||
|
* when there are active input streams, in which case this stream is already
|
||||||
|
* active.
|
||||||
|
*/
|
||||||
|
void SetActive();
|
||||||
|
/*
|
||||||
|
* CheckForInactive() is called when the engine transitions from active to
|
||||||
|
* inactive, or an active input is removed, or the stream finishes. If the
|
||||||
|
* stream is now inactive, then mInputChunks will be cleared and mLastChunks
|
||||||
|
* will be set to null. ProcessBlock() will not be called on the engine
|
||||||
|
* again until SetActive() is called.
|
||||||
|
*/
|
||||||
|
void CheckForInactive();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void DestroyImpl() override;
|
virtual void DestroyImpl() override;
|
||||||
|
@ -180,6 +198,8 @@ protected:
|
||||||
|
|
||||||
uint32_t ComputedNumberOfChannels(uint32_t aInputChannelCount);
|
uint32_t ComputedNumberOfChannels(uint32_t aInputChannelCount);
|
||||||
void ObtainInputBlock(AudioBlock& aTmpChunk, uint32_t aPortIndex);
|
void ObtainInputBlock(AudioBlock& aTmpChunk, uint32_t aPortIndex);
|
||||||
|
void IncrementActiveInputCount();
|
||||||
|
void DecrementActiveInputCount();
|
||||||
|
|
||||||
// The engine that will generate output for this node.
|
// The engine that will generate output for this node.
|
||||||
nsAutoPtr<AudioNodeEngine> mEngine;
|
nsAutoPtr<AudioNodeEngine> mEngine;
|
||||||
|
@ -192,11 +212,16 @@ protected:
|
||||||
const TrackRate mSampleRate;
|
const TrackRate mSampleRate;
|
||||||
// Whether this is an internal or external stream
|
// Whether this is an internal or external stream
|
||||||
const Flags mFlags;
|
const Flags mFlags;
|
||||||
|
// The number of input streams that may provide non-silent input.
|
||||||
|
uint32_t mActiveInputCount = 0;
|
||||||
// The number of input channels that this stream requires. 0 means don't care.
|
// The number of input channels that this stream requires. 0 means don't care.
|
||||||
uint32_t mNumberOfInputChannels;
|
uint32_t mNumberOfInputChannels;
|
||||||
// The mixing modes
|
// The mixing modes
|
||||||
ChannelCountMode mChannelCountMode;
|
ChannelCountMode mChannelCountMode;
|
||||||
ChannelInterpretation mChannelInterpretation;
|
ChannelInterpretation mChannelInterpretation;
|
||||||
|
// Streams are considered active if the stream has not finished and either
|
||||||
|
// the engine is active or there are active input streams.
|
||||||
|
bool mIsActive;
|
||||||
// Whether the stream should be marked as finished as soon
|
// Whether the stream should be marked as finished as soon
|
||||||
// as the current time range has been computed block by block.
|
// as the current time range has been computed block by block.
|
||||||
bool mMarkAsFinishedAfterThisBlock;
|
bool mMarkAsFinishedAfterThisBlock;
|
||||||
|
|
|
@ -155,6 +155,7 @@ public:
|
||||||
if (!hasTail) {
|
if (!hasTail) {
|
||||||
if (!mBiquads.IsEmpty()) {
|
if (!mBiquads.IsEmpty()) {
|
||||||
mBiquads.Clear();
|
mBiquads.Clear();
|
||||||
|
aStream->CheckForInactive();
|
||||||
|
|
||||||
nsRefPtr<PlayingRefChangeHandler> refchanged =
|
nsRefPtr<PlayingRefChangeHandler> refchanged =
|
||||||
new PlayingRefChangeHandler(aStream, PlayingRefChangeHandler::RELEASE);
|
new PlayingRefChangeHandler(aStream, PlayingRefChangeHandler::RELEASE);
|
||||||
|
|
|
@ -120,6 +120,7 @@ public:
|
||||||
} else {
|
} else {
|
||||||
if (mLeftOverData != INT32_MIN) {
|
if (mLeftOverData != INT32_MIN) {
|
||||||
mLeftOverData = INT32_MIN;
|
mLeftOverData = INT32_MIN;
|
||||||
|
aStream->CheckForInactive();
|
||||||
nsRefPtr<PlayingRefChanged> refchanged =
|
nsRefPtr<PlayingRefChanged> refchanged =
|
||||||
new PlayingRefChanged(aStream, PlayingRefChanged::RELEASE);
|
new PlayingRefChanged(aStream, PlayingRefChanged::RELEASE);
|
||||||
aStream->Graph()->
|
aStream->Graph()->
|
||||||
|
|
|
@ -96,6 +96,8 @@ public:
|
||||||
} else {
|
} else {
|
||||||
if (mLeftOverData != INT32_MIN) {
|
if (mLeftOverData != INT32_MIN) {
|
||||||
mLeftOverData = INT32_MIN;
|
mLeftOverData = INT32_MIN;
|
||||||
|
aStream->CheckForInactive();
|
||||||
|
|
||||||
// Delete our buffered data now we no longer need it
|
// Delete our buffered data now we no longer need it
|
||||||
mBuffer.Reset();
|
mBuffer.Reset();
|
||||||
|
|
||||||
|
@ -104,7 +106,7 @@ public:
|
||||||
aStream->Graph()->
|
aStream->Graph()->
|
||||||
DispatchToMainThreadAfterStreamStateUpdate(refchanged.forget());
|
DispatchToMainThreadAfterStreamStateUpdate(refchanged.forget());
|
||||||
}
|
}
|
||||||
*aOutput = aInput;
|
aOutput->SetNull(WEBAUDIO_BLOCK_SIZE);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -81,7 +81,10 @@ public:
|
||||||
virtual void SetStreamTimeParameter(uint32_t aIndex, StreamTime aParam) override
|
virtual void SetStreamTimeParameter(uint32_t aIndex, StreamTime aParam) override
|
||||||
{
|
{
|
||||||
switch (aIndex) {
|
switch (aIndex) {
|
||||||
case START: mStart = aParam; break;
|
case START:
|
||||||
|
mStart = aParam;
|
||||||
|
mSource->SetActive();
|
||||||
|
break;
|
||||||
case STOP: mStop = aParam; break;
|
case STOP: mStop = aParam; break;
|
||||||
default:
|
default:
|
||||||
NS_ERROR("Bad OscillatorNodeEngine StreamTimeParameter");
|
NS_ERROR("Bad OscillatorNodeEngine StreamTimeParameter");
|
||||||
|
|
|
@ -149,6 +149,7 @@ public:
|
||||||
} else {
|
} else {
|
||||||
if (mLeftOverData != INT_MIN) {
|
if (mLeftOverData != INT_MIN) {
|
||||||
mLeftOverData = INT_MIN;
|
mLeftOverData = INT_MIN;
|
||||||
|
aStream->CheckForInactive();
|
||||||
mHRTFPanner->reset();
|
mHRTFPanner->reset();
|
||||||
|
|
||||||
nsRefPtr<PlayingRefChangeHandler> refchanged =
|
nsRefPtr<PlayingRefChangeHandler> refchanged =
|
||||||
|
@ -156,7 +157,7 @@ public:
|
||||||
aStream->Graph()->
|
aStream->Graph()->
|
||||||
DispatchToMainThreadAfterStreamStateUpdate(refchanged.forget());
|
DispatchToMainThreadAfterStreamStateUpdate(refchanged.forget());
|
||||||
}
|
}
|
||||||
*aOutput = aInput;
|
aOutput->SetNull(WEBAUDIO_BLOCK_SIZE);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else if (mPanningModelFunction == &PannerNodeEngine::HRTFPanningFunction) {
|
} else if (mPanningModelFunction == &PannerNodeEngine::HRTFPanningFunction) {
|
||||||
|
|
Загрузка…
Ссылка в новой задаче