Bug 1264694: [MSE] P1. Ensure we only add source buffer tasks on the task queue. r?jwwang draft
authorJean-Yves Avenard <jyavenard@mozilla.com>
Tue, 17 May 2016 17:15:45 +0800
changeset 368117 b1c5ac279be43013a68135a65597c69742a75f88
parent 367613 74ce462a6070ce62b38011400c86d5cbc21df9ad
child 368118 e9173964a9fd55c80c30923264ccc49094c0bbde
push id18433
push userbmo:jyavenard@mozilla.com
push dateWed, 18 May 2016 02:57:01 +0000
reviewersjwwang
bugs1264694
milestone49.0a1
Bug 1264694: [MSE] P1. Ensure we only add source buffer tasks on the task queue. r?jwwang This ensures that the tasks are processed in the expected order. MozReview-Commit-ID: JPxlwReZ4Az
dom/media/mediasource/TrackBuffersManager.cpp
dom/media/mediasource/TrackBuffersManager.h
--- a/dom/media/mediasource/TrackBuffersManager.cpp
+++ b/dom/media/mediasource/TrackBuffersManager.cpp
@@ -133,78 +133,88 @@ TrackBuffersManager::AppendData(MediaByt
 }
 
 RefPtr<TrackBuffersManager::AppendPromise>
 TrackBuffersManager::DoAppendData(RefPtr<MediaByteBuffer> aData,
                                   SourceBufferAttributes aAttributes)
 {
   RefPtr<AppendBufferTask> task = new AppendBufferTask(aData, aAttributes);
   RefPtr<AppendPromise> p = task->mPromise.Ensure(__func__);
-  mQueue.Push(task);
-
-  ProcessTasks();
+  QueueTask(task);
 
   return p;
 }
 
 void
+TrackBuffersManager::QueueTask(SourceBufferTask* aTask)
+{
+  if (!OnTaskQueue()) {
+    GetTaskQueue()->Dispatch(NewRunnableMethod<RefPtr<SourceBufferTask>>(
+      this, &TrackBuffersManager::QueueTask, aTask));
+    return;
+  }
+  MOZ_ASSERT(OnTaskQueue());
+  mQueue.Push(aTask);
+  ProcessTasks();
+}
+
+void
 TrackBuffersManager::ProcessTasks()
 {
+  MOZ_ASSERT(OnTaskQueue());
   typedef SourceBufferTask::Type Type;
 
   if (mDetached) {
     return;
   }
 
-  if (OnTaskQueue()) {
-    if (mCurrentTask) {
-      // Already have a task pending. ProcessTask will be scheduled once the
-      // current task complete.
-      return;
-    }
-    RefPtr<SourceBufferTask> task = mQueue.Pop();
-    if (!task) {
-      // nothing to do.
-      return;
+  if (mCurrentTask) {
+    // Already have a task pending. ProcessTask will be scheduled once the
+    // current task complete.
+    return;
+  }
+  RefPtr<SourceBufferTask> task = mQueue.Pop();
+  if (!task) {
+    // nothing to do.
+    return;
+  }
+  switch (task->GetType()) {
+    case Type::AppendBuffer:
+      mCurrentTask = task;
+      if (!mInputBuffer) {
+        mInputBuffer = task->As<AppendBufferTask>()->mBuffer;
+      } else if (!mInputBuffer->AppendElements(*task->As<AppendBufferTask>()->mBuffer, fallible)) {
+        RejectAppend(NS_ERROR_OUT_OF_MEMORY, __func__);
+        return;
+      }
+      mSourceBufferAttributes =
+        MakeUnique<SourceBufferAttributes>(task->As<AppendBufferTask>()->mAttributes);
+      mAppendWindow =
+        TimeInterval(TimeUnit::FromSeconds(mSourceBufferAttributes->GetAppendWindowStart()),
+                     TimeUnit::FromSeconds(mSourceBufferAttributes->GetAppendWindowEnd()));
+      ScheduleSegmentParserLoop();
+      break;
+    case Type::RangeRemoval:
+    {
+      bool rv = CodedFrameRemoval(task->As<RangeRemovalTask>()->mRange);
+      task->As<RangeRemovalTask>()->mPromise.Resolve(rv, __func__);
+      break;
     }
-    switch (task->GetType()) {
-      case Type::AppendBuffer:
-        mCurrentTask = task;
-        if (!mInputBuffer) {
-          mInputBuffer = task->As<AppendBufferTask>()->mBuffer;
-        } else if (!mInputBuffer->AppendElements(*task->As<AppendBufferTask>()->mBuffer, fallible)) {
-          RejectAppend(NS_ERROR_OUT_OF_MEMORY, __func__);
-          return;
-        }
-        mSourceBufferAttributes =
-          MakeUnique<SourceBufferAttributes>(task->As<AppendBufferTask>()->mAttributes);
-        mAppendWindow =
-          TimeInterval(TimeUnit::FromSeconds(mSourceBufferAttributes->GetAppendWindowStart()),
-                       TimeUnit::FromSeconds(mSourceBufferAttributes->GetAppendWindowEnd()));
-        ScheduleSegmentParserLoop();
-        break;
-      case Type::RangeRemoval:
-      {
-        bool rv = CodedFrameRemoval(task->As<RangeRemovalTask>()->mRange);
-        task->As<RangeRemovalTask>()->mPromise.Resolve(rv, __func__);
-        break;
-      }
-      case Type::EvictData:
-        DoEvictData(task->As<EvictDataTask>()->mPlaybackTime,
-                    task->As<EvictDataTask>()->mSizeToEvict);
-        break;
-      case Type::Abort:
-        // not handled yet, and probably never.
-        break;
-      case Type::Reset:
-        CompleteResetParserState();
-        break;
-      default:
-        NS_WARNING("Invalid Task");
-    }
+    case Type::EvictData:
+      DoEvictData(task->As<EvictDataTask>()->mPlaybackTime,
+                  task->As<EvictDataTask>()->mSizeToEvict);
+      break;
+    case Type::Abort:
+      // not handled yet, and probably never.
+      break;
+    case Type::Reset:
+      CompleteResetParserState();
+      break;
+    default:
+      NS_WARNING("Invalid Task");
   }
   GetTaskQueue()->Dispatch(NewRunnableMethod(this, &TrackBuffersManager::ProcessTasks));
 }
 
 // A PromiseHolder will assert upon destruction if it has a pending promise
 // that hasn't been completed. It is possible that a task didn't get processed
 // due to the owning SourceBuffer having shutdown.
 // We resolve/reject all pending promises and remove all pending tasks from the
@@ -248,34 +258,30 @@ TrackBuffersManager::CancelAllTasks()
 // As the spec behaviour is non deterministic anyway, we instead process all
 // pending frames found in the input buffer.
 void
 TrackBuffersManager::AbortAppendData()
 {
   MOZ_ASSERT(NS_IsMainThread());
   MSE_DEBUG("");
 
-  RefPtr<AbortTask> task = new AbortTask();
-  mQueue.Push(task);
-  ProcessTasks();
+  QueueTask(new AbortTask());
 }
 
 void
 TrackBuffersManager::ResetParserState(SourceBufferAttributes& aAttributes)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MSE_DEBUG("");
 
   // Spec states:
   // 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.
   // However, we will wait until all coded frames have been processed regardless
   // of the value of append state.
-  RefPtr<ResetTask> task = new ResetTask();
-  mQueue.Push(task);
-  ProcessTasks();
+  QueueTask(new ResetTask());
 
   // ResetParserState has some synchronous steps that much be performed now.
   // The remaining steps will be performed once the ResetTask gets executed.
 
   // 6. If the mode attribute equals "sequence", then set the group start timestamp to the group end timestamp
   if (aAttributes.GetAppendMode() == SourceBufferAppendMode::Sequence) {
     aAttributes.SetGroupStartTimestamp(aAttributes.GetGroupEndTimestamp());
   }
@@ -319,19 +325,17 @@ TrackBuffersManager::EvictData(const Tim
   }
 
   if (mBufferFull && mEvictionOccurred) {
     return EvictDataResult::BUFFER_FULL;
   }
 
   MSE_DEBUG("Reaching our size limit, schedule eviction of %lld bytes", toEvict);
 
-  RefPtr<EvictDataTask> task = new EvictDataTask(aPlaybackTime, toEvict);
-  mQueue.Push(task);
-  ProcessTasks();
+  QueueTask(new EvictDataTask(aPlaybackTime, toEvict));
 
   return EvictDataResult::NO_DATA_EVICTED;
 }
 
 TimeIntervals
 TrackBuffersManager::Buffered()
 {
   MSE_DEBUG("");
@@ -517,18 +521,18 @@ TrackBuffersManager::DoEvictData(const T
 
 RefPtr<TrackBuffersManager::RangeRemovalPromise>
 TrackBuffersManager::CodedFrameRemovalWithPromise(TimeInterval aInterval)
 {
   MOZ_ASSERT(OnTaskQueue());
 
   RefPtr<RangeRemovalTask> task = new RangeRemovalTask(aInterval);
   RefPtr<RangeRemovalPromise> p = task->mPromise.Ensure(__func__);
-  mQueue.Push(task);
-  ProcessTasks();
+  QueueTask(task);
+
   return p;
 }
 
 bool
 TrackBuffersManager::CodedFrameRemoval(TimeInterval aInterval)
 {
   MOZ_ASSERT(OnTaskQueue());
   MSE_DEBUG("From %.2fs to %.2f",
--- a/dom/media/mediasource/TrackBuffersManager.h
+++ b/dom/media/mediasource/TrackBuffersManager.h
@@ -373,16 +373,17 @@ private:
   bool OnTaskQueue()
   {
     return !GetTaskQueue() || GetTaskQueue()->IsCurrentThreadIn();
   }
   RefPtr<AutoTaskQueue> mTaskQueue;
 
   // SourceBuffer Queues and running context.
   SourceBufferTaskQueue mQueue;
+  void QueueTask(SourceBufferTask* aTask);
   void ProcessTasks();
   void CancelAllTasks();
   // Set if the TrackBuffersManager is currently processing a task.
   // At this stage, this task is always a AppendBufferTask.
   RefPtr<SourceBufferTask> mCurrentTask;
   // Current SourceBuffer state for ongoing task.
   // Its content is returned to the SourceBuffer once the AppendBufferTask has
   // completed.