Bug 1189506. Simplify blocking calculations based on the observation that once a stream starts blocking in a given processing interval, it must stay blocked. r=karlt
authorRobert O'Callahan <robert@ocallahan.org>
Wed, 16 Sep 2015 16:17:30 +1200
changeset 295498 ed6d421cfc32f5124544bc75ed05d441112bf11a
parent 295497 45bbd595ac1830991fd87812a3753b13762caa3d
child 295499 63e927ca87fb0aa80432d11ee90389e9cb2313d4
push id5245
push userraliiev@mozilla.com
push dateThu, 29 Oct 2015 11:30:51 +0000
treeherdermozilla-beta@dac831dc1bd0 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskarlt
bugs1189506
milestone43.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1189506. Simplify blocking calculations based on the observation that once a stream starts blocking in a given processing interval, it must stay blocked. r=karlt
dom/media/MediaStreamGraph.cpp
dom/media/MediaStreamGraphImpl.h
--- a/dom/media/MediaStreamGraph.cpp
+++ b/dom/media/MediaStreamGraph.cpp
@@ -394,60 +394,40 @@ MediaStreamGraphImpl::UpdateCurrentTimeF
 
     if (stream->mFinished && !stream->mNotifiedFinished) {
       StreamReadyToFinish(stream);
     }
 
   }
 }
 
-bool
-MediaStreamGraphImpl::WillUnderrun(MediaStream* aStream, GraphTime aTime,
-                                   GraphTime aEndBlockingDecisions, GraphTime* aEnd)
+GraphTime
+MediaStreamGraphImpl::WillUnderrun(MediaStream* aStream,
+                                   GraphTime aEndBlockingDecisions)
 {
   // Finished streams can't underrun. ProcessedMediaStreams also can't cause
   // underrun currently, since we'll always be able to produce data for them
   // unless they block on some other stream.
   if (aStream->mFinished || aStream->AsProcessedStream()) {
-    return false;
+    return aEndBlockingDecisions;
   }
   GraphTime bufferEnd =
     StreamTimeToGraphTime(aStream, aStream->GetBufferEnd(),
                           INCLUDE_TRAILING_BLOCKED_INTERVAL);
 #ifdef DEBUG
   if (bufferEnd < mProcessedTime) {
     STREAM_LOG(LogLevel::Error, ("MediaStream %p underrun, "
                               "bufferEnd %f < mProcessedTime %f (%lld < %lld), Streamtime %lld",
                               aStream, MediaTimeToSeconds(bufferEnd), MediaTimeToSeconds(mProcessedTime),
                               bufferEnd, mProcessedTime, aStream->GetBufferEnd()));
     aStream->DumpTrackInfo();
     NS_ASSERTION(bufferEnd >= mProcessedTime, "Buffer underran");
   }
 #endif
-  // We should block after bufferEnd.
-  if (bufferEnd <= aTime) {
-    STREAM_LOG(LogLevel::Verbose, ("MediaStream %p will block due to data underrun at %ld, "
-                                "bufferEnd %ld",
-                                aStream, aTime, bufferEnd));
-    return true;
-  }
-  // We should keep blocking if we're currently blocked and we don't have
-  // data all the way through to aEndBlockingDecisions. If we don't have
-  // data all the way through to aEndBlockingDecisions, we'll block soon,
-  // but we might as well remain unblocked and play the data we've got while
-  // we can.
-  if (bufferEnd < aEndBlockingDecisions && aStream->mBlocked.GetBefore(aTime)) {
-    STREAM_LOG(LogLevel::Verbose, ("MediaStream %p will block due to speculative data underrun, "
-                                "bufferEnd %f (end at %ld)",
-                                aStream, MediaTimeToSeconds(bufferEnd), bufferEnd));
-    return true;
-  }
-  // Reconsider decisions at bufferEnd
-  *aEnd = std::min(*aEnd, bufferEnd);
-  return false;
+  return std::min(bufferEnd, aEndBlockingDecisions);
 }
 
 void
 MediaStreamGraphImpl::MarkConsumed(MediaStream* aStream)
 {
   if (aStream->mIsConsumed) {
     return;
   }
@@ -710,79 +690,59 @@ MediaStreamGraphImpl::UpdateStreamOrder(
 }
 
 void
 MediaStreamGraphImpl::RecomputeBlocking(GraphTime aEndBlockingDecisions)
 {
   STREAM_LOG(LogLevel::Verbose, ("Media graph %p computing blocking for time %f",
                               this, MediaTimeToSeconds(mStateComputedTime)));
   for (MediaStream* stream : AllStreams()) {
-    GraphTime end;
-    for (GraphTime t = mStateComputedTime;
-         t < aEndBlockingDecisions; t = end) {
-      end = GRAPH_TIME_MAX;
-      RecomputeBlockingAt(stream, t, aEndBlockingDecisions, &end);
-    }
+    GraphTime blockTime =
+      ComputeStreamBlockTime(stream, mStateComputedTime, aEndBlockingDecisions);
+    stream->mBlocked.SetAtAndAfter(mStateComputedTime, false);
+    stream->mBlocked.SetAtAndAfter(blockTime, true);
   }
   STREAM_LOG(LogLevel::Verbose, ("Media graph %p computed blocking for interval %f to %f",
                               this, MediaTimeToSeconds(mStateComputedTime),
                               MediaTimeToSeconds(aEndBlockingDecisions)));
 
   MOZ_ASSERT(aEndBlockingDecisions >= mProcessedTime);
   // The next state computed time can be the same as the previous: it
   // means the driver would be have been blocking indefinitly, but the graph has
   // been woken up right after having been to sleep.
   MOZ_ASSERT(aEndBlockingDecisions >= mStateComputedTime);
   mStateComputedTime = aEndBlockingDecisions;
 }
 
-void
-MediaStreamGraphImpl::RecomputeBlockingAt(MediaStream* aStream,
-                                          GraphTime aTime,
-                                          GraphTime aEndBlockingDecisions,
-                                          GraphTime* aEnd)
+GraphTime
+MediaStreamGraphImpl::ComputeStreamBlockTime(MediaStream* aStream,
+                                             GraphTime aTime,
+                                             GraphTime aEndBlockingDecisions)
 {
-  bool block = false;
-
-  do {
-    if (aStream->mFinished) {
-      GraphTime endTime = StreamTimeToGraphTime(aStream,
-          aStream->GetStreamBuffer().GetAllTracksEnd());
-      if (endTime <= aTime) {
-        STREAM_LOG(LogLevel::Verbose, ("MediaStream %p is blocked due to being finished", aStream));
-        // We'll block indefinitely
-        block = true;
-        *aEnd = std::min(*aEnd, aEndBlockingDecisions);
-        continue;
-      } else {
-        STREAM_LOG(LogLevel::Verbose, ("MediaStream %p is finished, but not blocked yet (end at %f, with blocking at %f)",
-            aStream, MediaTimeToSeconds(aStream->GetBufferEnd()),
-            MediaTimeToSeconds(endTime)));
-        *aEnd = std::min(*aEnd, endTime);
-      }
+  if (aStream->mFinished) {
+    GraphTime endTime = StreamTimeToGraphTime(aStream,
+        aStream->GetStreamBuffer().GetAllTracksEnd());
+    if (endTime <= aTime) {
+      STREAM_LOG(LogLevel::Verbose, ("MediaStream %p is blocked due to being finished", aStream));
+      return aTime;
+    } else {
+      STREAM_LOG(LogLevel::Verbose, ("MediaStream %p is finished, but not blocked yet (end at %f, with blocking at %f)",
+          aStream, MediaTimeToSeconds(aStream->GetBufferEnd()),
+          MediaTimeToSeconds(endTime)));
+      // Data can't be added to a finished stream, so underruns are irrelevant.
+      return std::min(endTime, aEndBlockingDecisions);
     }
-
-    if (aStream->IsSuspended()) {
-      STREAM_LOG(LogLevel::Verbose, ("MediaStream %p is blocked due to being suspended", aStream));
-      block = true;
-      continue;
-    }
-
-    bool underrun = WillUnderrun(aStream, aTime, aEndBlockingDecisions, aEnd);
-    if (underrun) {
-      // We'll block indefinitely
-      block = true;
-      *aEnd = std::min(*aEnd, aEndBlockingDecisions);
-      continue;
-    }
-  } while (false);
-
-  NS_ASSERTION(*aEnd > aTime, "Failed to advance!");
-
-  aStream->mBlocked.SetAtAndAfter(aTime, block);
+  }
+
+  if (aStream->IsSuspended()) {
+    STREAM_LOG(LogLevel::Verbose, ("MediaStream %p is blocked due to being suspended", aStream));
+    return aTime;
+  }
+
+  return WillUnderrun(aStream, aEndBlockingDecisions);
 }
 
 void
 MediaStreamGraphImpl::NotifyHasCurrentData(MediaStream* aStream)
 {
   if (!aStream->mNotifiedHasCurrentData && aStream->mHasCurrentData) {
     for (uint32_t j = 0; j < aStream->mListeners.Length(); ++j) {
       MediaStreamListener* l = aStream->mListeners[j];
--- a/dom/media/MediaStreamGraphImpl.h
+++ b/dom/media/MediaStreamGraphImpl.h
@@ -305,42 +305,40 @@ public:
   void RecomputeBlocking(GraphTime aEndBlockingDecisions);
 
   /**
    * Recompute blocking for the streams in aStreams for the interval starting at aTime.
    * If this results in decisions that need to be revisited at some point
    * in the future, *aEnd will be reduced to the first time in the future to
    * recompute those decisions.
    */
-  void RecomputeBlockingAt(MediaStream* aStream,
-                           GraphTime aTime, GraphTime aEndBlockingDecisions,
-                           GraphTime* aEnd);
+  GraphTime ComputeStreamBlockTime(MediaStream* aStream,
+                                   GraphTime aTime,
+                                   GraphTime aEndBlockingDecisions);
   /**
    * Returns smallest value of t such that t is a multiple of
    * WEBAUDIO_BLOCK_SIZE and t > aTime.
    */
   GraphTime RoundUpToNextAudioBlock(GraphTime aTime);
   /**
    * Produce data for all streams >= aStreamIndex for the given time interval.
    * Advances block by block, each iteration producing data for all streams
    * for a single block.
    * This is called whenever we have an AudioNodeStream in the graph.
    */
   void ProduceDataForStreamsBlockByBlock(uint32_t aStreamIndex,
                                          TrackRate aSampleRate,
                                          GraphTime aFrom,
                                          GraphTime aTo);
   /**
-   * Returns true if aStream will underrun at aTime for its own playback.
-   * aEndBlockingDecisions is when we plan to stop making blocking decisions.
-   * *aEnd will be reduced to the first time in the future to recompute these
-   * decisions.
+   * If aStream will underrun between aTime, and aEndBlockingDecisions, returns
+   * the time at which the underrun will start. Otherwise return
+   * aEndBlockingDecisions.
    */
-  bool WillUnderrun(MediaStream* aStream, GraphTime aTime,
-                    GraphTime aEndBlockingDecisions, GraphTime* aEnd);
+  GraphTime WillUnderrun(MediaStream* aStream, GraphTime aEndBlockingDecisions);
 
   /**
    * Given a graph time aTime, convert it to a stream time taking into
    * account the time during which aStream is scheduled to be blocked.
    */
   StreamTime GraphTimeToStreamTime(MediaStream* aStream, GraphTime aTime);
   /**
    * Given a graph time aTime, convert it to a stream time taking into