Bug 938022. Part 5: Add aCurrentTime parameter to MediaStreamListener::NotifyOutput and fire notifications when the MediaStreamGraph is in a good state. r=padenot
authorRobert O'Callahan <robert@ocallahan.org>
Tue, 26 Nov 2013 00:59:49 +1300
changeset 172832 184ed18485c746b05f7c0201bc375a956e97bc71
parent 172831 3f0a7db5211e1d929cc06246992c5cfdd2e9bead
child 172833 b3af7dbf540f5f2b88d0d3a49721f5655d166919
push id3224
push userlsblakk@mozilla.com
push dateTue, 04 Feb 2014 01:06:49 +0000
treeherdermozilla-beta@60c04d0987f1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerspadenot
bugs938022
milestone28.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 938022. Part 5: Add aCurrentTime parameter to MediaStreamListener::NotifyOutput and fire notifications when the MediaStreamGraph is in a good state. r=padenot
content/html/content/src/HTMLMediaElement.cpp
content/media/MediaStreamGraph.cpp
content/media/MediaStreamGraph.h
--- a/content/html/content/src/HTMLMediaElement.cpp
+++ b/content/html/content/src/HTMLMediaElement.cpp
@@ -2702,17 +2702,18 @@ public:
   }
   virtual void NotifyHasCurrentData(MediaStreamGraph* aGraph) MOZ_OVERRIDE
   {
     MutexAutoLock lock(mMutex);
     nsCOMPtr<nsIRunnable> event =
       NS_NewRunnableMethod(this, &StreamListener::DoNotifyHaveCurrentData);
     aGraph->DispatchToMainThreadAfterStreamStateUpdate(event.forget());
   }
-  virtual void NotifyOutput(MediaStreamGraph* aGraph) MOZ_OVERRIDE
+  virtual void NotifyOutput(MediaStreamGraph* aGraph,
+                            GraphTime aCurrentTime) MOZ_OVERRIDE
   {
     MutexAutoLock lock(mMutex);
     if (mPendingNotifyOutput)
       return;
     mPendingNotifyOutput = true;
     nsCOMPtr<nsIRunnable> event =
       NS_NewRunnableMethod(this, &StreamListener::DoNotifyOutput);
     aGraph->DispatchToMainThreadAfterStreamStateUpdate(event.forget());
--- a/content/media/MediaStreamGraph.cpp
+++ b/content/media/MediaStreamGraph.cpp
@@ -354,16 +354,18 @@ MediaStreamGraphImpl::UpdateCurrentTime(
     NS_ASSERTION(prevCurrentTime == nextCurrentTime, "Time can't go backwards!");
     // This could happen due to low clock resolution, maybe?
     STREAM_LOG(PR_LOG_DEBUG, ("Time did not advance"));
     // There's not much left to do here, but the code below that notifies
     // listeners that streams have ended still needs to run.
   }
 
   nsTArray<MediaStream*> streamsReadyToFinish;
+  nsAutoTArray<bool,800> streamHasOutput;
+  streamHasOutput.SetLength(mStreams.Length());
   for (uint32_t i = 0; i < mStreams.Length(); ++i) {
     MediaStream* stream = mStreams[i];
 
     // Calculate blocked time and fire Blocked/Unblocked events
     GraphTime blockedTime = 0;
     GraphTime t = prevCurrentTime;
     while (t < nextCurrentTime) {
       GraphTime end;
@@ -382,34 +384,40 @@ MediaStreamGraphImpl::UpdateCurrentTime(
       t = end;
     }
 
     stream->AdvanceTimeVaryingValuesToCurrentTime(nextCurrentTime, blockedTime);
     // Advance mBlocked last so that implementations of
     // AdvanceTimeVaryingValuesToCurrentTime can rely on the value of mBlocked.
     stream->mBlocked.AdvanceCurrentTime(nextCurrentTime);
 
-    if (blockedTime < nextCurrentTime - prevCurrentTime) {
-      for (uint32_t i = 0; i < stream->mListeners.Length(); ++i) {
-        MediaStreamListener* l = stream->mListeners[i];
-        l->NotifyOutput(this);
-      }
-    }
+    streamHasOutput[i] = blockedTime < nextCurrentTime - prevCurrentTime;
 
     if (stream->mFinished && !stream->mNotifiedFinished) {
       streamsReadyToFinish.AppendElement(stream);
     }
     STREAM_LOG(PR_LOG_DEBUG+1, ("MediaStream %p bufferStartTime=%f blockedTime=%f",
                                 stream, MediaTimeToSeconds(stream->mBufferStartTime),
                                 MediaTimeToSeconds(blockedTime)));
   }
 
   mCurrentTime = nextCurrentTime;
 
-  // Do this after setting mCurrentTime so that StreamTimeToGraphTime works properly.
+  // Do these after setting mCurrentTime so that StreamTimeToGraphTime works properly.
+  for (uint32_t i = 0; i < streamHasOutput.Length(); ++i) {
+    if (!streamHasOutput[i]) {
+      continue;
+    }
+    MediaStream* stream = mStreams[i];
+    for (uint32_t j = 0; j < stream->mListeners.Length(); ++j) {
+      MediaStreamListener* l = stream->mListeners[j];
+      l->NotifyOutput(this, mCurrentTime);
+    }
+  }
+
   for (uint32_t i = 0; i < streamsReadyToFinish.Length(); ++i) {
     MediaStream* stream = streamsReadyToFinish[i];
     if (StreamTimeToGraphTime(stream, stream->GetBufferEnd()) <= mCurrentTime) {
       stream->mNotifiedFinished = true;
       stream->mLastPlayedVideoFrame.SetNull();
       for (uint32_t j = 0; j < stream->mListeners.Length(); ++j) {
         MediaStreamListener* l = stream->mListeners[j];
         l->NotifyFinished(this);
--- a/content/media/MediaStreamGraph.h
+++ b/content/media/MediaStreamGraph.h
@@ -133,19 +133,21 @@ public:
    * Notify that the stream has data in each track
    * for the stream's current time. Once this state becomes true, it will
    * always be true since we block stream time from progressing to times where
    * there isn't data in each track.
    */
   virtual void NotifyHasCurrentData(MediaStreamGraph* aGraph) {}
 
   /**
-   * Notify that the stream output is advancing.
+   * Notify that the stream output is advancing. aCurrentTime is the graph's
+   * current time. MediaStream::GraphTimeToStreamTime can be used to get the
+   * stream time.
    */
-  virtual void NotifyOutput(MediaStreamGraph* aGraph) {}
+  virtual void NotifyOutput(MediaStreamGraph* aGraph, GraphTime aCurrentTime) {}
 
   /**
    * Notify that the stream finished.
    */
   virtual void NotifyFinished(MediaStreamGraph* aGraph) {}
 
   /**
    * Notify that your listener has been removed, either due to RemoveListener(),