Bug 909187: Part 1-Refactor MediaStreamTrack disabling so we can call it directly and access from other threads r=roc a=akeybl
authorRandell Jesup <rjesup@jesup.org>
Mon, 26 Aug 2013 02:07:17 -0400
changeset 153984 b558ce6a721755730d8df2c7fc557462159fee68
parent 153983 801b193e5ee16dec6849f6a0a3a200f1d4f08262
child 153985 e203add2f0eba319bffe56b74e7079ff217a78b3
push id2859
push userakeybl@mozilla.com
push dateMon, 16 Sep 2013 19:14:59 +0000
treeherdermozilla-beta@87d3c51cd2bf [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersroc, akeybl
bugs909187
milestone25.0a2
Bug 909187: Part 1-Refactor MediaStreamTrack disabling so we can call it directly and access from other threads r=roc a=akeybl
content/media/MediaSegment.h
content/media/MediaStreamGraph.cpp
content/media/MediaStreamGraph.h
content/media/VideoSegment.h
--- a/content/media/MediaSegment.h
+++ b/content/media/MediaSegment.h
@@ -96,16 +96,20 @@ public:
    * Insert aDuration of null data at the start of the segment.
    */
   virtual void InsertNullDataAtStart(TrackTicks aDuration) = 0;
   /**
    * Insert aDuration of null data at the end of the segment.
    */
   virtual void AppendNullData(TrackTicks aDuration) = 0;
   /**
+   * Replace contents with disabled data of the same duration
+   */
+  virtual void ReplaceWithDisabled() = 0;
+  /**
    * Remove all contents, setting duration to 0.
    */
   virtual void Clear() = 0;
 
 protected:
   MediaSegment(Type aType) : mDuration(0), mType(aType)
   {
     MOZ_COUNT_CTOR(MediaSegment);
@@ -185,16 +189,25 @@ public:
     }
     if (!mChunks.IsEmpty() && mChunks[mChunks.Length() - 1].IsNull()) {
       mChunks[mChunks.Length() - 1].mDuration += aDuration;
     } else {
       mChunks.AppendElement()->SetNull(aDuration);
     }
     mDuration += aDuration;
   }
+  virtual void ReplaceWithDisabled()
+  {
+    if (GetType() != AUDIO) {
+      MOZ_CRASH("Disabling unknown segment type");
+    }
+    TrackTicks duration = GetDuration();
+    Clear();
+    AppendNullData(duration);
+  }
   virtual void Clear()
   {
     mDuration = 0;
     mChunks.Clear();
   }
 
   class ChunkIterator {
   public:
--- a/content/media/MediaStreamGraph.cpp
+++ b/content/media/MediaStreamGraph.cpp
@@ -1907,39 +1907,25 @@ MediaStream::SetTrackEnabled(TrackID aTr
     }
     TrackID mTrackID;
     bool mEnabled;
   };
   GraphImpl()->AppendMessage(new Message(this, aTrackID, aEnabled));
 }
 
 void
-MediaStream::ApplyTrackDisabling(TrackID aTrackID, MediaSegment* aSegment)
+MediaStream::ApplyTrackDisabling(TrackID aTrackID, MediaSegment* aSegment, MediaSegment* aRawSegment)
 {
+  // mMutex must be owned here if this is a SourceMediaStream
   if (!mDisabledTrackIDs.Contains(aTrackID)) {
     return;
   }
-
-  switch (aSegment->GetType()) {
-  case MediaSegment::AUDIO: {
-    TrackTicks duration = aSegment->GetDuration();
-    aSegment->Clear();
-    aSegment->AppendNullData(duration);
-    break;
-  }
-  case MediaSegment::VIDEO: {
-    for (VideoSegment::ChunkIterator i(*static_cast<VideoSegment*>(aSegment));
-         !i.IsEnded(); i.Next()) {
-      VideoChunk& chunk = *i;
-      chunk.SetForceBlack(true);
-    }
-    break;
-  }
-  default:
-    MOZ_CRASH("Unknown track type");
+  aSegment->ReplaceWithDisabled();
+  if (aRawSegment) {
+    aRawSegment->ReplaceWithDisabled();
   }
 }
 
 void
 SourceMediaStream::DestroyImpl()
 {
   {
     MutexAutoLock lock(mMutex);
@@ -1985,16 +1971,20 @@ SourceMediaStream::AppendToTrack(TrackID
     TrackData *track = FindDataForTrack(aID);
     if (track) {
       // Data goes into mData, and on the next iteration of the MSG moves
       // into the track's segment after NotifyQueuedTrackChanges().  This adds
       // 0-10ms of delay before data gets to direct listeners.
       // Indirect listeners (via subsequent TrackUnion nodes) are synced to
       // playout time, and so can be delayed by buffering.
 
+      // Apply track disabling before notifying any consumers directly
+      // or inserting into the graph
+      ApplyTrackDisabling(aID, aSegment, aRawSegment);
+
       // Must notify first, since AppendFrom() will empty out aSegment
       NotifyDirectConsumers(track, aRawSegment ? aRawSegment : aSegment);
       track->mData->AppendFrom(aSegment); // note: aSegment is now dead
       appended = true;
     } else {
       aSegment->Clear();
     }
   }
--- a/content/media/MediaStreamGraph.h
+++ b/content/media/MediaStreamGraph.h
@@ -454,17 +454,17 @@ public:
    * Identify which graph update index we are currently processing.
    */
   int64_t GetProcessingGraphUpdateIndex();
 
   bool HasCurrentData() { return mHasCurrentData; }
 
   StreamBuffer::Track* EnsureTrack(TrackID aTrack, TrackRate aSampleRate);
 
-  void ApplyTrackDisabling(TrackID aTrackID, MediaSegment* aSegment);
+  void ApplyTrackDisabling(TrackID aTrackID, MediaSegment* aSegment, MediaSegment* aRawSegment = nullptr);
 
   DOMMediaStream* GetWrapper()
   {
     NS_ASSERTION(NS_IsMainThread(), "Only use DOMMediaStream on main thread");
     return mWrapper;
   }
 
   // Return true if the main thread needs to observe updates from this stream.
@@ -674,16 +674,21 @@ public:
    */
   void FinishWithLockHeld();
   void Finish()
     {
       MutexAutoLock lock(mMutex);
       FinishWithLockHeld();
     }
 
+  // Overriding allows us to hold the mMutex lock while changing the track enable status
+  void SetTrackEnabledImpl(TrackID aTrackID, bool aEnabled) {
+    MutexAutoLock lock(mMutex);
+    MediaStream::SetTrackEnabledImpl(aTrackID, aEnabled);
+  }
 
   /**
    * End all tracks and Finish() this stream.  Used to voluntarily revoke access
    * to a LocalMediaStream.
    */
   void EndAllTrackAndFinish();
 
   // XXX need a Reset API
--- a/content/media/VideoSegment.h
+++ b/content/media/VideoSegment.h
@@ -102,16 +102,24 @@ public:
     if (!c) {
       return nullptr;
     }
     if (aStart) {
       *aStart = mDuration - c->mDuration;
     }
     return &c->mFrame;
   }
+  // Override default impl
+  virtual void ReplaceWithDisabled() MOZ_OVERRIDE {
+    for (ChunkIterator i(*this);
+         !i.IsEnded(); i.Next()) {
+      VideoChunk& chunk = *i;
+      chunk.SetForceBlack(true);
+    }
+  }
 
   // Segment-generic methods not in MediaSegmentBase
   static Type StaticType() { return VIDEO; }
 };
 
 }
 
 #endif /* MOZILLA_VIDEOSEGMENT_H_ */