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:
Karl Tomlinson 2015-09-18 00:03:00 +12:00
Родитель 985811fe37
Коммит abcc44d6d5
10 изменённых файлов: 148 добавлений и 11 удалений

Просмотреть файл

@ -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) {