Bug 943461. Part 13: Keep producing silence in AudioNodeStreams' mLastChunks even after they've finished r=padenot
authorRobert O'Callahan <robert@ocallahan.org>
Tue, 10 Dec 2013 13:49:03 +1300
changeset 162331 adc635735f62f4a3aabb845a43044679acff604a
parent 162330 76bf4bf3492623c86ed86b66e1c6abc3c0a0b3cc
child 162332 e911ac30c8c1f031852edf9a8550bd080b89308d
push idunknown
push userunknown
push dateunknown
reviewerspadenot
bugs943461
milestone29.0a1
Bug 943461. Part 13: Keep producing silence in AudioNodeStreams' mLastChunks even after they've finished r=padenot Without this the last before-finished audio block gets picked up by downstream ObtainInputBlock calls.
content/media/AudioNodeStream.cpp
content/media/MediaStreamGraph.cpp
content/media/MediaStreamGraph.h
content/media/TrackUnionStream.h
--- a/content/media/AudioNodeStream.cpp
+++ b/content/media/AudioNodeStream.cpp
@@ -264,18 +264,17 @@ AudioNodeStream::ObtainInputBlock(AudioC
   for (uint32_t i = 0; i < inputCount; ++i) {
     if (aPortIndex != mInputs[i]->InputNumber()) {
       // This input is connected to a different port
       continue;
     }
     MediaStream* s = mInputs[i]->GetSource();
     AudioNodeStream* a = static_cast<AudioNodeStream*>(s);
     MOZ_ASSERT(a == s->AsAudioNodeStream());
-    if (a->IsFinishedOnGraphThread() ||
-        a->IsAudioParamStream()) {
+    if (a->IsAudioParamStream()) {
       continue;
     }
 
     // It is possible for mLastChunks to be empty here, because `a` might be a
     // AudioNodeStream that has not been scheduled yet, because it is further
     // down the graph _but_ as a connection to this node. Because we enforce the
     // presence of at least one DelayNode, with at least one block of delay, and
     // because the output of a DelayNode when it has been fed less that
@@ -403,17 +402,17 @@ AudioNodeStream::ProduceOutput(GraphTime
 {
   EnsureTrack(AUDIO_TRACK, mSampleRate);
   // No more tracks will be coming
   mBuffer.AdvanceKnownTracksTime(STREAM_TIME_MAX);
 
   uint16_t outputCount = std::max(uint16_t(1), mEngine->OutputCount());
   mLastChunks.SetLength(outputCount);
 
-  if (mMuted) {
+  if (mMuted || IsFinishedOnGraphThread()) {
     for (uint16_t i = 0; i < outputCount; ++i) {
       mLastChunks[i].SetNull(WEBAUDIO_BLOCK_SIZE);
     }
   } else {
     for (uint16_t i = 0; i < outputCount; ++i) {
       mLastChunks[i].SetNull(0);
     }
 
--- a/content/media/MediaStreamGraph.cpp
+++ b/content/media/MediaStreamGraph.cpp
@@ -1184,17 +1184,17 @@ MediaStreamGraphImpl::RunThread()
     // Play stream contents.
     uint32_t audioStreamsActive = 0;
     bool allBlockedForever = true;
     // True when we've done ProduceOutput for all processed streams.
     bool doneAllProducing = false;
     // Figure out what each stream wants to do
     for (uint32_t i = 0; i < mStreams.Length(); ++i) {
       MediaStream* stream = mStreams[i];
-      if (!doneAllProducing && !stream->IsFinishedOnGraphThread()) {
+      if (!doneAllProducing) {
         ProcessedMediaStream* ps = stream->AsProcessedStream();
         if (ps) {
           AudioNodeStream* n = stream->AsAudioNodeStream();
           if (n) {
 #ifdef DEBUG
             // Verify that the sampling rate for all of the following streams is the same
             for (uint32_t j = i + 1; j < mStreams.Length(); ++j) {
               AudioNodeStream* nextStream = mStreams[j]->AsAudioNodeStream();
--- a/content/media/MediaStreamGraph.h
+++ b/content/media/MediaStreamGraph.h
@@ -954,17 +954,19 @@ public:
   }
   virtual void DestroyImpl();
   /**
    * This gets called after we've computed the blocking states for all
    * streams (mBlocked is up to date up to mStateComputedTime).
    * Also, we've produced output for all streams up to this one. If this stream
    * is not in a cycle, then all its source streams have produced data.
    * Generate output from aFrom to aTo.
-   * This is called only on streams that have not finished.
+   * This will be called on streams that have finished. Most stream types should
+   * just return immediately if IsFinishedOnGraphThread(), but some may wish to
+   * update internal state (see AudioNodeStream).
    * ProduceOutput is allowed to call FinishOnGraphThread only if ALLOW_FINISH
    * is in aFlags. (This flag will be set when aTo >= mStateComputedTime, i.e.
    * when we've producing the last block of data we need to produce.) Otherwise
    * we can get into a situation where we've determined the stream should not
    * block before mStateComputedTime, but the stream finishes before
    * mStateComputedTime, violating the invariant that finished streams are blocked.
    */
   enum {
--- a/content/media/TrackUnionStream.h
+++ b/content/media/TrackUnionStream.h
@@ -36,16 +36,19 @@ public:
         EndTrack(i);
         mTrackMap.RemoveElementAt(i);
       }
     }
     ProcessedMediaStream::RemoveInput(aPort);
   }
   virtual void ProduceOutput(GraphTime aFrom, GraphTime aTo, uint32_t aFlags) MOZ_OVERRIDE
   {
+    if (IsFinishedOnGraphThread()) {
+      return;
+    }
     nsAutoTArray<bool,8> mappedTracksFinished;
     nsAutoTArray<bool,8> mappedTracksWithMatchingInputTracks;
     for (uint32_t i = 0; i < mTrackMap.Length(); ++i) {
       mappedTracksFinished.AppendElement(true);
       mappedTracksWithMatchingInputTracks.AppendElement(false);
     }
     bool allFinished = true;
     bool allHaveCurrentData = true;