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
--- 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.