зеркало из 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 AnalyserNode::mChunks has only null chunks, then there is no need
|
||||
// to send further null chunks.
|
||||
if (mChunksToProcess == 0) {
|
||||
if (mChunksToProcess <= 0) {
|
||||
if (mChunksToProcess != INT32_MIN) {
|
||||
mChunksToProcess = INT32_MIN;
|
||||
aStream->CheckForInactive();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -85,7 +89,7 @@ public:
|
|||
|
||||
virtual bool IsActive() const override
|
||||
{
|
||||
return mChunksToProcess != 0;
|
||||
return mChunksToProcess != INT32_MIN;
|
||||
}
|
||||
|
||||
virtual size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const override
|
||||
|
@ -93,7 +97,7 @@ public:
|
|||
return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
|
||||
}
|
||||
|
||||
size_t mChunksToProcess = 0;
|
||||
int32_t mChunksToProcess = INT32_MIN;
|
||||
};
|
||||
|
||||
AnalyserNode::AnalyserNode(AudioContext* aContext)
|
||||
|
|
|
@ -111,7 +111,11 @@ public:
|
|||
virtual void SetInt32Parameter(uint32_t aIndex, int32_t aParam) override
|
||||
{
|
||||
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:
|
||||
MOZ_ASSERT(aParam >= 0);
|
||||
if (mBufferPosition == 0) {
|
||||
|
|
|
@ -309,8 +309,10 @@ public:
|
|||
* 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
|
||||
* exactly WEBAUDIO_BLOCK_SIZE samples.
|
||||
* *aFinished is set to false by the caller. If the callee sets it to true,
|
||||
* we'll finish the stream and not call this again.
|
||||
* *aFinished is set to false by the caller. The callee must not set this to
|
||||
* 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,
|
||||
const AudioBlock& aInput,
|
||||
|
|
|
@ -34,6 +34,7 @@ AudioNodeStream::AudioNodeStream(AudioNodeEngine* aEngine,
|
|||
mSampleRate(aSampleRate),
|
||||
mFlags(aFlags),
|
||||
mNumberOfInputChannels(2),
|
||||
mIsActive(aEngine->IsActive()),
|
||||
mMarkAsFinishedAfterThisBlock(false),
|
||||
mAudioParamStream(false),
|
||||
mPassThrough(false)
|
||||
|
@ -49,6 +50,7 @@ AudioNodeStream::AudioNodeStream(AudioNodeEngine* aEngine,
|
|||
|
||||
AudioNodeStream::~AudioNodeStream()
|
||||
{
|
||||
MOZ_ASSERT(mActiveInputCount == 0);
|
||||
MOZ_COUNT_DTOR(AudioNodeStream);
|
||||
}
|
||||
|
||||
|
@ -520,7 +522,14 @@ AudioNodeStream::ProcessInput(GraphTime aFrom, GraphTime aTo, uint32_t aFlags)
|
|||
uint16_t outputCount = mLastChunks.Length();
|
||||
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();
|
||||
for (uint16_t i = 0; i < outputCount; ++i) {
|
||||
mLastChunks[i].SetNull(WEBAUDIO_BLOCK_SIZE);
|
||||
|
@ -549,6 +558,7 @@ AudioNodeStream::ProcessInput(GraphTime aFrom, GraphTime aTo, uint32_t aFlags)
|
|||
}
|
||||
if (finished) {
|
||||
mMarkAsFinishedAfterThisBlock = true;
|
||||
CheckForInactive();
|
||||
}
|
||||
|
||||
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(mLastChunks.Length() == 1);
|
||||
|
||||
if (mFinished) {
|
||||
if (!mIsActive) {
|
||||
mLastChunks[0].SetNull(WEBAUDIO_BLOCK_SIZE);
|
||||
} else {
|
||||
mEngine->ProduceBlockBeforeInput(&mLastChunks[0]);
|
||||
|
@ -684,4 +694,88 @@ AudioNodeStream::DestinationTimeFromTicks(AudioNodeStream* aDestination,
|
|||
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
|
||||
|
|
|
@ -106,6 +106,8 @@ public:
|
|||
}
|
||||
|
||||
virtual AudioNodeStream* AsAudioNodeStream() override { return this; }
|
||||
virtual void AddInput(MediaInputPort* aPort) override;
|
||||
virtual void RemoveInput(MediaInputPort* aPort) override;
|
||||
|
||||
// Graph thread only
|
||||
void SetStreamTimeParameterImpl(uint32_t aIndex, MediaStream* aRelativeToStream,
|
||||
|
@ -165,6 +167,22 @@ public:
|
|||
void SizeOfAudioNodesIncludingThis(MallocSizeOf aMallocSizeOf,
|
||||
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:
|
||||
virtual void DestroyImpl() override;
|
||||
|
@ -180,6 +198,8 @@ protected:
|
|||
|
||||
uint32_t ComputedNumberOfChannels(uint32_t aInputChannelCount);
|
||||
void ObtainInputBlock(AudioBlock& aTmpChunk, uint32_t aPortIndex);
|
||||
void IncrementActiveInputCount();
|
||||
void DecrementActiveInputCount();
|
||||
|
||||
// The engine that will generate output for this node.
|
||||
nsAutoPtr<AudioNodeEngine> mEngine;
|
||||
|
@ -192,11 +212,16 @@ protected:
|
|||
const TrackRate mSampleRate;
|
||||
// Whether this is an internal or external stream
|
||||
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.
|
||||
uint32_t mNumberOfInputChannels;
|
||||
// The mixing modes
|
||||
ChannelCountMode mChannelCountMode;
|
||||
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
|
||||
// as the current time range has been computed block by block.
|
||||
bool mMarkAsFinishedAfterThisBlock;
|
||||
|
|
|
@ -155,6 +155,7 @@ public:
|
|||
if (!hasTail) {
|
||||
if (!mBiquads.IsEmpty()) {
|
||||
mBiquads.Clear();
|
||||
aStream->CheckForInactive();
|
||||
|
||||
nsRefPtr<PlayingRefChangeHandler> refchanged =
|
||||
new PlayingRefChangeHandler(aStream, PlayingRefChangeHandler::RELEASE);
|
||||
|
|
|
@ -120,6 +120,7 @@ public:
|
|||
} else {
|
||||
if (mLeftOverData != INT32_MIN) {
|
||||
mLeftOverData = INT32_MIN;
|
||||
aStream->CheckForInactive();
|
||||
nsRefPtr<PlayingRefChanged> refchanged =
|
||||
new PlayingRefChanged(aStream, PlayingRefChanged::RELEASE);
|
||||
aStream->Graph()->
|
||||
|
|
|
@ -96,6 +96,8 @@ public:
|
|||
} else {
|
||||
if (mLeftOverData != INT32_MIN) {
|
||||
mLeftOverData = INT32_MIN;
|
||||
aStream->CheckForInactive();
|
||||
|
||||
// Delete our buffered data now we no longer need it
|
||||
mBuffer.Reset();
|
||||
|
||||
|
@ -104,7 +106,7 @@ public:
|
|||
aStream->Graph()->
|
||||
DispatchToMainThreadAfterStreamStateUpdate(refchanged.forget());
|
||||
}
|
||||
*aOutput = aInput;
|
||||
aOutput->SetNull(WEBAUDIO_BLOCK_SIZE);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -81,7 +81,10 @@ public:
|
|||
virtual void SetStreamTimeParameter(uint32_t aIndex, StreamTime aParam) override
|
||||
{
|
||||
switch (aIndex) {
|
||||
case START: mStart = aParam; break;
|
||||
case START:
|
||||
mStart = aParam;
|
||||
mSource->SetActive();
|
||||
break;
|
||||
case STOP: mStop = aParam; break;
|
||||
default:
|
||||
NS_ERROR("Bad OscillatorNodeEngine StreamTimeParameter");
|
||||
|
|
|
@ -149,6 +149,7 @@ public:
|
|||
} else {
|
||||
if (mLeftOverData != INT_MIN) {
|
||||
mLeftOverData = INT_MIN;
|
||||
aStream->CheckForInactive();
|
||||
mHRTFPanner->reset();
|
||||
|
||||
nsRefPtr<PlayingRefChangeHandler> refchanged =
|
||||
|
@ -156,7 +157,7 @@ public:
|
|||
aStream->Graph()->
|
||||
DispatchToMainThreadAfterStreamStateUpdate(refchanged.forget());
|
||||
}
|
||||
*aOutput = aInput;
|
||||
aOutput->SetNull(WEBAUDIO_BLOCK_SIZE);
|
||||
return;
|
||||
}
|
||||
} else if (mPanningModelFunction == &PannerNodeEngine::HRTFPanningFunction) {
|
||||
|
|
Загрузка…
Ссылка в новой задаче