Bug 1404997 - P15. Move MSG::FinishStream logic to MediaStream. r?padenot draft
authorJean-Yves Avenard <jyavenard@mozilla.com>
Thu, 07 Dec 2017 16:12:19 +0100
changeset 712535 064013ea0b78add5d22c892d3a401c31614bc878
parent 712534 2bb883a08610c25c0deb2a12f007a22c1ed00121
child 712536 79903fd09cec285b0eb998527076d27d8abf94a4
push id93357
push userbmo:jyavenard@mozilla.com
push dateSun, 17 Dec 2017 09:29:04 +0000
reviewerspadenot
bugs1404997
milestone59.0a1
Bug 1404997 - P15. Move MSG::FinishStream logic to MediaStream. r?padenot It is good practice for the MSG to now know the implementation details of the MediaStream. Additionally, this will allow to make a thread-safe version later., MozReview-Commit-ID: CTacCLSeKRP
dom/media/MediaStreamGraph.cpp
dom/media/MediaStreamGraph.h
dom/media/MediaStreamGraphImpl.h
--- a/dom/media/MediaStreamGraph.cpp
+++ b/dom/media/MediaStreamGraph.cpp
@@ -68,41 +68,16 @@ MediaStreamGraphImpl::~MediaStreamGraphI
 {
   MOZ_ASSERT(mStreams.IsEmpty() && mSuspendedStreams.IsEmpty(),
              "All streams should have been destroyed by messages from the main thread");
   LOG(LogLevel::Debug, ("MediaStreamGraph %p destroyed", this));
   LOG(LogLevel::Debug, ("MediaStreamGraphImpl::~MediaStreamGraphImpl"));
 }
 
 void
-MediaStreamGraphImpl::FinishStream(MediaStream* aStream)
-{
-  MOZ_ASSERT(OnGraphThreadOrNotRunning());
-  if (aStream->mFinished)
-    return;
-  LOG(LogLevel::Debug, ("MediaStream %p will finish", aStream));
-#ifdef DEBUG
-  for (StreamTracks::TrackIter track(aStream->mTracks);
-         !track.IsEnded(); track.Next()) {
-    if (!track->IsEnded()) {
-      LOG(LogLevel::Error,
-          ("MediaStream %p will finish, but track %d has not ended.",
-           aStream,
-           track->GetID()));
-      NS_ASSERTION(false, "Finished stream cannot contain live track");
-    }
-  }
-#endif
-  aStream->mFinished = true;
-  aStream->mTracks.AdvanceKnownTracksTime(STREAM_TIME_MAX);
-
-  SetStreamOrderDirty();
-}
-
-void
 MediaStreamGraphImpl::AddStreamGraphThread(MediaStream* aStream)
 {
   MOZ_ASSERT(OnGraphThreadOrNotRunning());
   aStream->mTracksStartTime = mProcessedTime;
 
   if (aStream->AsSourceStream()) {
     SourceMediaStream* source = aStream->AsSourceStream();
     TimeStamp currentTimeStamp = CurrentDriver()->GetCurrentTimeStamp();
@@ -167,28 +142,16 @@ MediaStreamGraphImpl::RemoveStreamGraphT
       ("Removed media stream %p from graph %p, count %zu",
        aStream,
        this,
        mStreams.Length()));
 
   NS_RELEASE(aStream); // probably destroying it
 }
 
-void
-MediaStreamGraphImpl::ExtractPendingInput(SourceMediaStream* aStream,
-                                          GraphTime aDesiredUpToTime,
-                                          bool* aEnsureNextIteration)
-{
-  MOZ_ASSERT(OnGraphThread());
-
-  if (aStream->ExtractPendingInput(aDesiredUpToTime, aEnsureNextIteration)) {
-    FinishStream(aStream);
-  }
-}
-
 StreamTime
 MediaStreamGraphImpl::GraphTimeToStreamTimeWithBlocking(const MediaStream* aStream,
                                                         GraphTime aTime) const
 {
   MOZ_ASSERT(aTime <= mStateComputedTime,
              "Don't ask about times where we haven't made blocking decisions yet");
   return std::max<StreamTime>(0,
       std::min(aTime, aStream->mStartBlocking) - aStream->mTracksStartTime);
@@ -1183,17 +1146,17 @@ MediaStreamGraphImpl::UpdateGraph(GraphT
 
   UpdateStreamOrder();
 
   bool ensureNextIteration = false;
 
   // Grab pending stream input and compute blocking time
   for (MediaStream* stream : mStreams) {
     if (SourceMediaStream* is = stream->AsSourceStream()) {
-      ExtractPendingInput(is, aEndBlockingDecisions, &ensureNextIteration);
+      is->ExtractPendingInput(aEndBlockingDecisions, &ensureNextIteration);
     }
 
     if (stream->mFinished) {
       // The stream's not suspended, and since it's finished, underruns won't
       // stop it playing out. So there's no blocking other than what we impose
       // here.
       GraphTime endTime = stream->GetStreamTracks().GetAllTracksEnd() +
           stream->mTracksStartTime;
@@ -1957,17 +1920,37 @@ StreamTime
 MediaStream::GraphTimeToStreamTimeWithBlocking(GraphTime aTime) const
 {
   return GraphImpl()->GraphTimeToStreamTimeWithBlocking(this, aTime);
 }
 
 void
 MediaStream::FinishOnGraphThread()
 {
-  GraphImpl()->FinishStream(this);
+  if (mFinished) {
+    return;
+  }
+  LOG(LogLevel::Debug, ("MediaStream %p will finish", this));
+#ifdef DEBUG
+  for (StreamTracks::TrackIter track(mTracks); !track.IsEnded(); track.Next()) {
+    if (!track->IsEnded()) {
+      LOG(LogLevel::Error,
+          ("MediaStream %p will finish, but track %d has not ended.",
+           this,
+           track->GetID()));
+      NS_ASSERTION(false, "Finished stream cannot contain live track");
+    }
+  }
+#endif
+  mFinished = true;
+  mTracks.AdvanceKnownTracksTime(STREAM_TIME_MAX);
+
+  // Let the MSG knows that this stream can be destroyed if necessary to avoid
+  // unnecessarily processing it in the future.
+  GraphImpl()->SetStreamOrderDirty();
 }
 
 StreamTracks::Track*
 MediaStream::FindTrack(TrackID aID) const
 {
   return mTracks.FindTrack(aID);
 }
 
@@ -2705,17 +2688,17 @@ SourceMediaStream::SetPullEnabled(bool a
 {
   MutexAutoLock lock(mMutex);
   mPullEnabled = aEnabled;
   if (mPullEnabled && GraphImpl()) {
     GraphImpl()->EnsureNextIteration();
   }
 }
 
-bool
+void
 SourceMediaStream::ExtractPendingInput(StreamTime aDesiredUpToTime,
                                        bool* aEnsureNextIteration)
 {
   MutexAutoLock lock(mMutex);
   if (mPullEnabled && !mFinished && !mListeners.IsEmpty()) {
     // Compute how much stream time we'll need assuming we don't block
     // the stream at all.
     StreamTime t = GraphTimeToStreamTime(aDesiredUpToTime);
@@ -2866,17 +2849,19 @@ SourceMediaStream::ExtractPendingInput(S
   if (!mFinished) {
     mTracks.AdvanceKnownTracksTime(mUpdateKnownTracksTime);
   }
 
   if (mTracks.GetEnd() > 0) {
     mHasCurrentData = true;
   }
 
-  return finished;
+  if (finished) {
+    FinishOnGraphThread();
+  }
 }
 
 void
 SourceMediaStream::AddTrackInternal(TrackID aID, TrackRate aRate, StreamTime aStart,
                                     MediaSegment* aSegment, uint32_t aFlags)
 {
   MutexAutoLock lock(mMutex);
   nsTArray<TrackData> *track_data = (aFlags & ADDTRACK_QUEUED) ?
@@ -3482,17 +3467,17 @@ void
 ProcessedMediaStream::QueueFinish()
 {
   class Message : public ControlMessage {
   public:
     explicit Message(ProcessedMediaStream* aStream)
       : ControlMessage(aStream) {}
     void Run() override
     {
-      mStream->GraphImpl()->FinishStream(mStream);
+      mStream->FinishOnGraphThread();
     }
   };
   GraphImpl()->AppendMessage(MakeUnique<Message>(this));
 }
 
 void
 ProcessedMediaStream::QueueSetAutofinish(bool aAutofinish)
 {
--- a/dom/media/MediaStreamGraph.h
+++ b/dom/media/MediaStreamGraph.h
@@ -500,17 +500,17 @@ public:
    * Convert stream time to graph time. This assumes there is no blocking time
    * to take account of, which is always true except between a stream
    * having its blocking time calculated in UpdateGraph and its blocking time
    * taken account of in UpdateCurrentTimeForStreams.
    */
   GraphTime StreamTimeToGraphTime(StreamTime aTime) const;
 
   bool IsFinishedOnGraphThread() const { return mFinished; }
-  void FinishOnGraphThread();
+  virtual void FinishOnGraphThread();
 
   bool HasCurrentData() const { return mHasCurrentData; }
 
   /**
    * Find track by track id.
    */
   StreamTracks::Track* FindTrack(TrackID aID) const;
 
@@ -621,16 +621,17 @@ protected:
    * Number of outstanding suspend operations on this stream. Stream is
    * suspended when this is > 0.
    */
   int32_t mSuspendedCount;
 
   /**
    * When true, this means the stream will be finished once all
    * buffered data has been consumed.
+   * Only accessed on the graph thread
    */
   bool mFinished;
   /**
    * When true, mFinished is true and we've played all the data in this stream
    * and fired NotifyFinished notifications.
    */
   bool mNotifiedFinished;
   /**
@@ -694,19 +695,18 @@ public:
    * MediaStreamGraph control loop. Pulling is initially disabled.
    * Due to unavoidable race conditions, after a call to SetPullEnabled(false)
    * it is still possible for a NotifyPull to occur.
    */
   void SetPullEnabled(bool aEnabled);
 
   /**
    * Extract any state updates pending in the stream, and apply them.
-   * Returns true if the stream is now finished.
    */
-  bool ExtractPendingInput(StreamTime aDesiredUpToTime,
+  void ExtractPendingInput(StreamTime aDesiredUpToTime,
                            bool* aEnsureNextIteration);
 
   /**
    * These add/remove DirectListeners, which allow bypassing the graph and any
    * synchronization delays for e.g. PeerConnection, which wants the data ASAP
    * and lets the far-end handle sync and playout timing.
    */
   void NotifyListenersEventImpl(MediaStreamGraphEvent aEvent);
@@ -759,16 +759,17 @@ public:
    * Ignored if the track does not exist.
    */
   void EndTrack(TrackID aID);
   /**
    * Indicate that no tracks will be added starting before time aKnownTime.
    * aKnownTime must be >= its value at the last call to AdvanceKnownTracksTime.
    */
   void AdvanceKnownTracksTime(StreamTime aKnownTime);
+  void AdvanceKnownTracksTimeWithLockHeld(StreamTime aKnownTime);
   /**
    * Indicate that this stream should enter the "finished" state. All tracks
    * must have been ended via EndTrack. The finish time of the stream is
    * when all tracks have ended.
    */
   void FinishPendingWithLockHeld();
   void FinishPending()
   {
--- a/dom/media/MediaStreamGraphImpl.h
+++ b/dom/media/MediaStreamGraphImpl.h
@@ -274,22 +274,16 @@ public:
     mMonitor.AssertCurrentThreadOwns();
     mFrontMessageQueue.SwapElements(mBackMessageQueue);
   }
   /**
    * Do all the processing and play the audio and video, from
    * mProcessedTime to mStateComputedTime.
    */
   void Process();
-  /**
-   * Extract any state updates pending in aStream, and apply them.
-   */
-  void ExtractPendingInput(SourceMediaStream* aStream,
-                           GraphTime aDesiredUpToTime,
-                           bool* aEnsureNextIteration);
 
   /**
    * For use during ProcessedMediaStream::ProcessInput() or
    * MediaStreamListener callbacks, when graph state cannot be changed.
    * Schedules |aMessage| to run after processing, at a time when graph state
    * can be changed.  Graph thread.
    */
   void RunMessageAfterProcessing(UniquePtr<ControlMessage> aMessage);
@@ -389,17 +383,16 @@ public:
    */
   void OpenAudioInputImpl(int aID,
                           AudioDataListener *aListener);
   virtual nsresult OpenAudioInput(int aID,
                                   AudioDataListener *aListener) override;
   void CloseAudioInputImpl(AudioDataListener *aListener);
   virtual void CloseAudioInput(AudioDataListener *aListener) override;
 
-  void FinishStream(MediaStream* aStream);
   /**
    * Compute how much stream data we would like to buffer for aStream.
    */
   StreamTime GetDesiredBufferEnd(MediaStream* aStream);
   /**
    * Returns true when there are no active streams.
    */
   bool IsEmpty() const