Bug 836599 - Part 8: Add a non-realtime media graph API to produce a given number of ticks; r=roc
authorEhsan Akhgari <ehsan@mozilla.com>
Thu, 16 May 2013 19:30:41 -0400
changeset 139301 eccb855886ad36600ddb00051cac5b0e1732af3b
parent 139300 39b03fde453a5847f2df81b0ede9b78900e2d8b5
child 139302 b67a43c241c55b1d5143709741b1a46c9dc8cb8d
push id3911
push userakeybl@mozilla.com
push dateMon, 24 Jun 2013 20:17:26 +0000
treeherdermozilla-aurora@7e26ca8db92b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersroc
bugs836599
milestone24.0a1
Bug 836599 - Part 8: Add a non-realtime media graph API to produce a given number of ticks; r=roc
content/media/MediaStreamGraph.cpp
content/media/MediaStreamGraph.h
content/media/MediaStreamGraphImpl.h
--- a/content/media/MediaStreamGraph.cpp
+++ b/content/media/MediaStreamGraph.cpp
@@ -948,16 +948,25 @@ MediaStreamGraphImpl::RunThread()
   nsTArray<MessageBlock> messageQueue;
   {
     MonitorAutoLock lock(mMonitor);
     messageQueue.SwapElements(mMessageQueue);
   }
   NS_ASSERTION(!messageQueue.IsEmpty(),
                "Shouldn't have started a graph with empty message queue!");
 
+  uint32_t ticksProcessed = 0;
+  if (!mRealtime) {
+    NS_ASSERTION(!mNonRealtimeIsRunning,
+                 "We should not be running in non-realtime mode already");
+    NS_ASSERTION(mNonRealtimeTicksToProcess,
+                 "We should have a non-zero number of ticks to process");
+    mNonRealtimeIsRunning = true;
+  }
+
   for (;;) {
     // Update mCurrentTime to the min of the playing audio times, or using the
     // wall-clock time change if no audio is playing.
     UpdateCurrentTime();
 
     // Calculate independent action times for each batch of messages (each
     // batch corresponding to an event loop task). This isolates the performance
     // of different scripts to some extent.
@@ -1027,16 +1036,23 @@ MediaStreamGraphImpl::RunThread()
       if (is) {
         UpdateBufferSufficiencyState(is);
       }
       GraphTime end;
       if (!stream->mBlocked.GetAt(mCurrentTime, &end) || end < GRAPH_TIME_MAX) {
         allBlockedForever = false;
       }
     }
+    if (!mRealtime) {
+      ticksProcessed += TimeToTicksRoundDown(IdealAudioRate(), mStateComputedTime - prevComputedTime);
+      // Terminate processing if we've produce enough non-realtime ticks.
+      if (ticksProcessed >= mNonRealtimeTicksToProcess) {
+        break;
+      }
+    }
     if (ensureNextIteration || !allBlockedForever || audioStreamsActive > 0) {
       EnsureNextIteration();
     }
 
     // Send updates to the main thread and wait for the next control loop
     // iteration.
     {
       MonitorAutoLock lock(mMonitor);
@@ -1077,16 +1093,20 @@ MediaStreamGraphImpl::RunThread()
                                (TimeStamp::Now() - now).ToSeconds()));
         }
       }
       mWaitState = WAITSTATE_RUNNING;
       mNeedAnotherIteration = false;
       messageQueue.SwapElements(mMessageQueue);
     }
   }
+
+  if (!mRealtime) {
+    mNonRealtimeIsRunning = false;
+  }
 }
 
 void
 MediaStreamGraphImpl::ApplyStreamUpdate(StreamUpdate* aUpdate)
 {
   mMonitor.AssertCurrentThreadOwns();
 
   MediaStream* stream = aUpdate->mStream;
@@ -1365,17 +1385,21 @@ MediaStreamGraphImpl::AppendMessage(Cont
         gGraph = nullptr;
         delete this;
       }
     }
     return;
   }
 
   mCurrentTaskMessageQueue.AppendElement(aMessage);
-  EnsureRunInStableState();
+  // Do not start running the non-realtime graph unless processing has
+  // explicitly started.
+  if (mRealtime || mNonRealtimeProcessing) {
+    EnsureRunInStableState();
+  }
 }
 
 void
 MediaStream::Init()
 {
   MediaStreamGraphImpl* graph = GraphImpl();
   mBlocked.SetAtAndAfter(graph->mCurrentTime, true);
   mExplicitBlockerCount.SetAtAndAfter(graph->mCurrentTime, true);
@@ -1953,22 +1977,25 @@ static const int32_t INITIAL_CURRENT_TIM
 MediaStreamGraphImpl::MediaStreamGraphImpl(bool aRealtime)
   : mCurrentTime(INITIAL_CURRENT_TIME)
   , mStateComputedTime(INITIAL_CURRENT_TIME)
   , mProcessingGraphUpdateIndex(0)
   , mPortCount(0)
   , mMonitor("MediaStreamGraphImpl")
   , mLifecycleState(LIFECYCLE_THREAD_NOT_STARTED)
   , mWaitState(WAITSTATE_RUNNING)
+  , mNonRealtimeTicksToProcess(0)
   , mNeedAnotherIteration(false)
   , mForceShutDown(false)
   , mPostedRunInStableStateEvent(false)
+  , mNonRealtimeIsRunning(false)
   , mDetectedNotRunning(false)
   , mPostedRunInStableState(false)
   , mRealtime(aRealtime)
+  , mNonRealtimeProcessing(false)
 {
 #ifdef PR_LOGGING
   if (!gMediaStreamGraphLog) {
     gMediaStreamGraphLog = PR_NewLogModule("MediaStreamGraph");
   }
 #endif
 
   mCurrentTimeStamp = mInitialTimeStamp = TimeStamp::Now();
@@ -2066,9 +2093,24 @@ MediaStreamGraph::CreateAudioNodeStream(
     stream->SetChannelMixingParametersImpl(aEngine->NodeMainThread()->ChannelCount(),
                                            aEngine->NodeMainThread()->ChannelCountModeValue(),
                                            aEngine->NodeMainThread()->ChannelInterpretationValue());
   }
   graph->AppendMessage(new CreateMessage(stream));
   return stream;
 }
 
+void
+MediaStreamGraph::StartNonRealtimeProcessing(uint32_t aTicksToProcess)
+{
+  NS_ASSERTION(NS_IsMainThread(), "main thread only");
+
+  MediaStreamGraphImpl* graph = static_cast<MediaStreamGraphImpl*>(this);
+  NS_ASSERTION(!graph->mRealtime, "non-realtime only");
+
+  if (graph->mNonRealtimeProcessing)
+    return;
+  graph->mNonRealtimeTicksToProcess = aTicksToProcess;
+  graph->mNonRealtimeProcessing = true;
+  graph->EnsureRunInStableState();
 }
+
+}
--- a/content/media/MediaStreamGraph.h
+++ b/content/media/MediaStreamGraph.h
@@ -934,16 +934,20 @@ public:
   AudioNodeStream* CreateAudioNodeStream(AudioNodeEngine* aEngine,
                                          AudioNodeStreamKind aKind);
   /**
    * Returns the number of graph updates sent. This can be used to track
    * whether a given update has been processed by the graph thread and reflected
    * in main-thread stream state.
    */
   int64_t GetCurrentGraphUpdateIndex() { return mGraphUpdatesSent; }
+  /**
+   * Start processing non-realtime for a specific number of ticks.
+   */
+  void StartNonRealtimeProcessing(uint32_t aTicksToProcess);
 
   /**
    * Media graph thread only.
    * Dispatches a runnable that will run on the main thread after all
    * main-thread stream state has been next updated.
    * Should only be called during MediaStreamListener callbacks.
    */
   void DispatchToMainThreadAfterStreamStateUpdate(already_AddRefed<nsIRunnable> aRunnable)
--- a/content/media/MediaStreamGraphImpl.h
+++ b/content/media/MediaStreamGraphImpl.h
@@ -476,28 +476,39 @@ public:
     // RunThread() is paused indefinitely waiting for something to change
     WAITSTATE_WAITING_INDEFINITELY,
     // Something has signaled RunThread() to wake up immediately,
     // but it hasn't done so yet
     WAITSTATE_WAKING_UP
   };
   WaitState mWaitState;
   /**
+   * How many non-realtime ticks the graph should process.
+   */
+  uint32_t mNonRealtimeTicksToProcess;
+  /**
    * True when another iteration of the control loop is required.
    */
   bool mNeedAnotherIteration;
   /**
    * True when we need to do a forced shutdown during application shutdown.
    */
   bool mForceShutDown;
   /**
    * True when we have posted an event to the main thread to run
    * RunInStableState() and the event hasn't run yet.
    */
   bool mPostedRunInStableStateEvent;
+  /**
+   * True when the non-realtime graph thread is processing, as a result of
+   * a request from the main thread.  When processing is finished, we post
+   * a message to the main thread in order to set mNonRealtimeProcessing
+   * back to false.
+   */
+  bool mNonRealtimeIsRunning;
 
   // Main thread only
 
   /**
    * Messages posted by the current event loop task. These are forwarded to
    * the media graph thread during RunInStableState. We can't forward them
    * immediately because we want all messages between stable states to be
    * processed as an atomic batch.
@@ -514,13 +525,18 @@ public:
    * RunInStableState at the next stable state.
    */
   bool mPostedRunInStableState;
   /**
    * True when processing real-time audio/video.  False when processing non-realtime
    * audio.
    */
   bool mRealtime;
+  /**
+   * True when a non-realtime MediaStreamGraph has started to process input.  This
+   * value is only accessed on the main thread.
+   */
+  bool mNonRealtimeProcessing;
 };
 
 }
 
 #endif /* MEDIASTREAMGRAPHIMPL_H_ */