Bug 1171330: P16. Use ProxyMediaCall and remove need for monitor. r=cajbir
authorJean-Yves Avenard <jyavenard@mozilla.com>
Thu, 11 Jun 2015 16:33:10 +1000
changeset 248280 7b2f7c764372e174cf2353af6e18abc31e95e9c7
parent 248279 cb28ba1d607b32cc4598d08e63f5875143758cda
child 248281 299c650797f243228100f9d6693ae05bb0d776c0
push id28893
push userkwierso@gmail.com
push dateFri, 12 Jun 2015 00:02:58 +0000
treeherderautoland@8cf9d3e497f9 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerscajbir
bugs1171330
milestone41.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 1171330: P16. Use ProxyMediaCall and remove need for monitor. r=cajbir
dom/media/mediasource/TrackBuffersManager.cpp
dom/media/mediasource/TrackBuffersManager.h
--- a/dom/media/mediasource/TrackBuffersManager.cpp
+++ b/dom/media/mediasource/TrackBuffersManager.cpp
@@ -54,54 +54,63 @@ TrackBuffersManager::TrackBuffersManager
   MOZ_ASSERT(NS_IsMainThread(), "Must be instanciated on the main thread");
 }
 
 bool
 TrackBuffersManager::AppendData(MediaLargeByteBuffer* aData,
                                 TimeUnit aTimestampOffset)
 {
   MOZ_ASSERT(NS_IsMainThread());
-  MonitorAutoLock mon(mMonitor);
   MSE_DEBUG("Appending %lld bytes", aData->Length());
-  mIncomingBuffers.AppendElement(IncomingBuffer(aData, aTimestampOffset));
+
   mEnded = false;
+  nsCOMPtr<nsIRunnable> task =
+    NS_NewRunnableMethodWithArg<IncomingBuffer>(
+      this, &TrackBuffersManager::AppendIncomingBuffer,
+      IncomingBuffer(aData, aTimestampOffset));
+  GetTaskQueue()->Dispatch(task.forget());
   return true;
 }
 
+void
+TrackBuffersManager::AppendIncomingBuffer(IncomingBuffer aData)
+{
+  MOZ_ASSERT(OnTaskQueue());
+  mIncomingBuffers.AppendElement(aData);
+}
+
 nsRefPtr<TrackBuffersManager::AppendPromise>
 TrackBuffersManager::BufferAppend()
 {
   MOZ_ASSERT(NS_IsMainThread());
-  MOZ_ASSERT(mAppendPromise.IsEmpty());
-  nsRefPtr<AppendPromise> p = mAppendPromise.Ensure(__func__);
+  MSE_DEBUG("");
 
-  nsCOMPtr<nsIRunnable> task =
-    NS_NewRunnableMethod(this, &TrackBuffersManager::InitSegmentParserLoop);
-  GetTaskQueue()->Dispatch(task.forget());
-
-  return p;
+  return ProxyMediaCall(GetTaskQueue(), this,
+                        __func__, &TrackBuffersManager::InitSegmentParserLoop);
 }
 
 // Abort any pending AppendData.
 // We don't really care about really aborting our inner loop as by spec the
 // process is happening asynchronously, as such where and when we would abort is
 // non-deterministic. The SourceBuffer also makes sure BufferAppend
 // isn't called should the appendBuffer be immediately aborted.
 void
 TrackBuffersManager::AbortAppendData()
 {
   MOZ_ASSERT(NS_IsMainThread());
-  mAppendPromise.RejectIfExists(NS_ERROR_ABORT, __func__);
+  MSE_DEBUG("");
+
+  mAbort = true;
 }
 
 void
 TrackBuffersManager::ResetParserState()
 {
   MOZ_ASSERT(NS_IsMainThread());
-  MOZ_ASSERT(mAppendPromise.IsEmpty(), "AbortAppendData must have been called");
+  MSE_DEBUG("");
 
   // 1. If the append state equals PARSING_MEDIA_SEGMENT and the input buffer contains some complete coded frames, then run the coded frame processing algorithm until all of these complete coded frames have been processed.
   if (mAppendState == AppendState::PARSING_MEDIA_SEGMENT) {
     nsCOMPtr<nsIRunnable> task =
       NS_NewRunnableMethod(this, &TrackBuffersManager::FinishCodedFrameProcessing);
     GetTaskQueue()->Dispatch(task.forget());
   } else {
     nsCOMPtr<nsIRunnable> task =
@@ -109,25 +118,23 @@ TrackBuffersManager::ResetParserState()
     GetTaskQueue()->Dispatch(task.forget());
   }
 }
 
 nsRefPtr<TrackBuffersManager::RangeRemovalPromise>
 TrackBuffersManager::RangeRemoval(TimeUnit aStart, TimeUnit aEnd)
 {
   MOZ_ASSERT(NS_IsMainThread());
+  MSE_DEBUG("From %.2f to %.2f", aStart.ToSeconds(), aEnd.ToSeconds());
+
   mEnded = false;
 
-  nsRefPtr<RangeRemovalPromise> p = mRangeRemovalPromise.Ensure(__func__);
-
-  nsCOMPtr<nsIRunnable> task =
-  NS_NewRunnableMethodWithArg<TimeInterval>(
-    this, &TrackBuffersManager::CodedFrameRemoval, TimeInterval(aStart, aEnd));
-  GetTaskQueue()->Dispatch(task.forget());
-  return p;
+  return ProxyMediaCall(GetTaskQueue(), this, __func__,
+                        &TrackBuffersManager::CodedFrameRemovalWithPromise,
+                        TimeInterval(aStart, aEnd));
 }
 
 TrackBuffersManager::EvictDataResult
 TrackBuffersManager::EvictData(TimeUnit aPlaybackTime,
                                uint32_t aThreshold,
                                TimeUnit* aBufferStartTime)
 {
   MOZ_ASSERT(NS_IsMainThread());
@@ -147,19 +154,19 @@ TrackBuffersManager::EvictData(TimeUnit 
   return EvictDataResult::NO_DATA_EVICTED;
 }
 
 void
 TrackBuffersManager::EvictBefore(TimeUnit aTime)
 {
   MOZ_ASSERT(NS_IsMainThread());
   nsCOMPtr<nsIRunnable> task =
-  NS_NewRunnableMethodWithArg<TimeInterval>(
-    this, &TrackBuffersManager::CodedFrameRemoval,
-    TimeInterval(TimeUnit::FromSeconds(0), aTime));
+    NS_NewRunnableMethodWithArg<TimeInterval>(
+      this, &TrackBuffersManager::CodedFrameRemoval,
+      TimeInterval(TimeUnit::FromSeconds(0), aTime));
   GetTaskQueue()->Dispatch(task.forget());
 }
 
 media::TimeIntervals
 TrackBuffersManager::Buffered()
 {
   MonitorAutoLock mon(mMonitor);
   // http://w3c.github.io/media-source/index.html#widl-SourceBuffer-buffered
@@ -204,24 +211,23 @@ TrackBuffersManager::Ended()
 {
   mEnded = true;
 }
 
 void
 TrackBuffersManager::Detach()
 {
   MOZ_ASSERT(NS_IsMainThread());
-  MOZ_ASSERT(mAppendPromise.IsEmpty(), "Abort wasn't called");
-  // Abort any pending promises.
-  mRangeRemovalPromise.ResolveIfExists(false, __func__);
+  MSE_DEBUG("");
+
   // Clear our sourcebuffer
   nsCOMPtr<nsIRunnable> task =
-  NS_NewRunnableMethodWithArg<TimeInterval>(
-    this, &TrackBuffersManager::CodedFrameRemoval,
-    TimeInterval(TimeUnit::FromSeconds(0), TimeUnit::FromInfinity()));
+    NS_NewRunnableMethodWithArg<TimeInterval>(
+      this, &TrackBuffersManager::CodedFrameRemoval,
+      TimeInterval(TimeUnit::FromSeconds(0), TimeUnit::FromInfinity()));
   GetTaskQueue()->Dispatch(task.forget());
 }
 
 #if defined(DEBUG)
 void
 TrackBuffersManager::Dump(const char* aPath)
 {
 
@@ -245,16 +251,17 @@ TrackBuffersManager::FinishCodedFramePro
 
   CompleteResetParserState();
 }
 
 void
 TrackBuffersManager::CompleteResetParserState()
 {
   MOZ_ASSERT(OnTaskQueue());
+  MOZ_ASSERT(mAppendPromise.IsEmpty());
 
   for (auto track : GetTracksList()) {
     // 2. Unset the last decode timestamp on all track buffers.
     track->mLastDecodeTimestamp.reset();
     // 3. Unset the last frame duration on all track buffers.
     track->mLastFrameDuration.reset();
     // 4. Unset the highest end timestamp on all track buffers.
     track->mHighestEndTimestamp.reset();
@@ -356,28 +363,36 @@ TrackBuffersManager::DoEvictData(const T
   }
   if (lastKeyFrameIndex < buffer.Length()) {
     CodedFrameRemoval(
       TimeInterval(TimeUnit::FromMicroseconds(buffer[lastKeyFrameIndex+1]->mTime),
                    TimeUnit::FromInfinity()));
   }
 }
 
-void
+nsRefPtr<TrackBuffersManager::RangeRemovalPromise>
+TrackBuffersManager::CodedFrameRemovalWithPromise(TimeInterval aInterval)
+{
+  MOZ_ASSERT(OnTaskQueue());
+  bool rv = CodedFrameRemoval(aInterval);
+  return RangeRemovalPromise::CreateAndResolve(rv, __func__);
+}
+
+bool
 TrackBuffersManager::CodedFrameRemoval(TimeInterval aInterval)
 {
+  MOZ_ASSERT(OnTaskQueue());
+  MOZ_ASSERT(mAppendPromise.IsEmpty(), "Logic error: Append in progress");
   MSE_DEBUG("From %.2fs to %.2f",
             aInterval.mStart.ToSeconds(), aInterval.mEnd.ToSeconds());
 
   double mediaSourceDuration = mParentDecoder->GetMediaSourceDuration();
   if (IsNaN(mediaSourceDuration)) {
     MSE_DEBUG("Nothing to remove, aborting");
-    MonitorAutoLock mon(mMonitor);
-    mRangeRemovalPromise.ResolveIfExists(false, __func__);
-    return;
+    return false;
   }
   TimeUnit duration{TimeUnit::FromSeconds(mediaSourceDuration)};
 
   MSE_DEBUG("duration:%.2f", duration.ToSeconds());
   if (HasAudio()) {
     MSE_DEBUG("before video ranges=%s",
               DumpTimeRanges(mVideoTracks.mBufferedRanges).get());
   }
@@ -386,16 +401,18 @@ TrackBuffersManager::CodedFrameRemoval(T
               DumpTimeRanges(mAudioTracks.mBufferedRanges).get());
   }
 
   // 1. Let start be the starting presentation timestamp for the removal range.
   TimeUnit start = aInterval.mStart;
   // 2. Let end be the end presentation timestamp for the removal range.
   TimeUnit end = aInterval.mEnd;
 
+  bool dataRemoved = false;
+
   // 3. For each track buffer in this source buffer, run the following steps:
   for (auto track : GetTracksList()) {
     MSE_DEBUGV("Processing %s track", track->mInfo->mMimeType.get());
     // 1. Let remove end timestamp be the current value of duration
     // See bug: https://www.w3.org/Bugs/Public/show_bug.cgi?id=28727
     TimeUnit removeEndTimestamp = std::max(duration, track->mBufferedRanges.GetEnd());
 
     // 2. If this track buffer has a random access point timestamp that is greater than or equal to end,
@@ -440,16 +457,17 @@ TrackBuffersManager::CodedFrameRemoval(T
           break;
         }
         removedInterval = removedInterval.Span(
           TimeInterval(TimeUnit::FromMicroseconds(frame->mTime),
                        TimeUnit::FromMicroseconds(frame->mTime + frame->mDuration)));
         track->mSizeBuffer -= sizeof(*frame) + frame->mSize;
         data.RemoveElementAt(i);
       }
+      dataRemoved = true;
     }
     track->mBufferedRanges -= removedInterval;
 
     // 5. If this object is in activeSourceBuffers, the current playback position
     // is greater than or equal to start and less than the remove end timestamp,
     // and HTMLMediaElement.readyState is greater than HAVE_METADATA, then set the
     // HTMLMediaElement.readyState attribute to HAVE_METADATA and stall playback.
     // This will be done by the MDSM during playback.
@@ -471,24 +489,31 @@ TrackBuffersManager::CodedFrameRemoval(T
   if (HasVideo()) {
     MSE_DEBUG("after audio ranges=%s",
               DumpTimeRanges(mAudioTracks.mBufferedRanges).get());
   }
 
   // Update our reported total size.
   mSizeSourceBuffer = mVideoTracks.mSizeBuffer + mAudioTracks.mSizeBuffer;
 
-  mRangeRemovalPromise.ResolveIfExists(true, __func__);
+  return dataRemoved;
 }
 
-void
+nsRefPtr<TrackBuffersManager::AppendPromise>
 TrackBuffersManager::InitSegmentParserLoop()
 {
+  MOZ_ASSERT(OnTaskQueue());
+
+  MOZ_ASSERT(mAppendPromise.IsEmpty());
+  nsRefPtr<AppendPromise> p = mAppendPromise.Ensure(__func__);
+
   AppendIncomingBuffers();
   SegmentParserLoop();
+
+  return p;
 }
 
 void
 TrackBuffersManager::AppendIncomingBuffers()
 {
   MOZ_ASSERT(OnTaskQueue());
   MonitorAutoLock mon(mMonitor);
   for (auto& incomingBuffer : mIncomingBuffers) {
--- a/dom/media/mediasource/TrackBuffersManager.h
+++ b/dom/media/mediasource/TrackBuffersManager.h
@@ -79,44 +79,50 @@ public:
   }
 
 #if defined(DEBUG)
   void Dump(const char* aPath) override;
 #endif
 
 private:
   virtual ~TrackBuffersManager();
-  void InitSegmentParserLoop();
+  // All following functions run on the taskqueue.
+  nsRefPtr<AppendPromise> InitSegmentParserLoop();
   void ScheduleSegmentParserLoop();
   void SegmentParserLoop();
   void AppendIncomingBuffers();
   void InitializationSegmentReceived();
   void CreateDemuxerforMIMEType();
   void NeedMoreData();
   void RejectAppend(nsresult aRejectValue, const char* aName);
   // Will return a promise that will be resolved once all frames of the current
   // media segment have been processed.
   nsRefPtr<CodedFrameProcessingPromise> CodedFrameProcessing();
+  void CompleteCodedFrameProcessing();
   // Called by ResetParserState. Complete parsing the input buffer for the
-  // current media segment
+  // current media segment.
   void FinishCodedFrameProcessing();
-  void CompleteCodedFrameProcessing();
   void CompleteResetParserState();
-  void CodedFrameRemoval(TimeInterval aInterval);
+  nsRefPtr<RangeRemovalPromise> CodedFrameRemovalWithPromise(TimeInterval aInterval);
+  bool CodedFrameRemoval(TimeInterval aInterval);
   void SetAppendState(AppendState aAppendState);
 
   bool HasVideo() const
   {
     return mVideoTracks.mNumTracks > 0;
   }
   bool HasAudio() const
   {
     return mAudioTracks.mNumTracks > 0;
   }
 
+  typedef Pair<nsRefPtr<MediaLargeByteBuffer>, TimeUnit> IncomingBuffer;
+  void AppendIncomingBuffer(IncomingBuffer aData);
+  nsTArray<IncomingBuffer> mIncomingBuffers;
+
   // The input buffer as per http://w3c.github.io/media-source/index.html#sourcebuffer-input-buffer
   nsRefPtr<MediaLargeByteBuffer> mInputBuffer;
   // The current append state as per https://w3c.github.io/media-source/#sourcebuffer-append-state
   // Accessed on both the main thread and the task queue.
   Atomic<AppendState> mAppendState;
   // Buffer full flag as per https://w3c.github.io/media-source/#sourcebuffer-buffer-full-flag.
   // Accessed on both the main thread and the task queue.
   // TODO: Unused for now.
@@ -210,19 +216,17 @@ private:
     uint32_t mSizeBuffer;
     // TrackInfo of the first metadata received.
     UniquePtr<TrackInfo> mInfo;
   };
   bool ProcessFrame(MediaRawData* aSample, TrackData& aTrackData);
   MediaPromiseRequestHolder<CodedFrameProcessingPromise> mProcessingRequest;
   MediaPromiseHolder<CodedFrameProcessingPromise> mProcessingPromise;
 
-  // SourceBuffer media promise (resolved on the main thread)
   MediaPromiseHolder<AppendPromise> mAppendPromise;
-  MediaPromiseHolder<RangeRemovalPromise> mRangeRemovalPromise;
 
   // Trackbuffers definition.
   nsTArray<TrackData*> GetTracksList();
   TrackData& GetTracksData(TrackType aTrack)
   {
     switch(aTrack) {
       case TrackType::kVideoTrack:
         return mVideoTracks;
@@ -257,18 +261,16 @@ private:
   // Set to true if mediasource state changed to ended.
   Atomic<bool> mEnded;
 
   // Global size of this source buffer content.
   Atomic<int64_t> mSizeSourceBuffer;
 
   // Monitor to protect following objects accessed across multipple threads.
   mutable Monitor mMonitor;
-  typedef Pair<nsRefPtr<MediaLargeByteBuffer>, TimeUnit> IncomingBuffer;
-  nsTArray<IncomingBuffer> mIncomingBuffers;
   // Stable audio and video track time ranges.
   TimeIntervals mVideoBufferedRanges;
   TimeIntervals mAudioBufferedRanges;
   // MediaInfo of the first init segment read.
   MediaInfo mInfo;
 };
 
 } // namespace mozilla