Bug 1245463: [MSE] P3. When abort() is called, wait until the current appendBuffer completes. r?gerald draft
authorJean-Yves Avenard <jyavenard@mozilla.com>
Fri, 12 Feb 2016 00:55:55 +1100
changeset 330472 a1fb52608a34d56b47e36d455fcfdb687d9357ec
parent 330471 c500afe1cccc7d9e3326bb43be58c97ffd8d03b6
child 330473 bd8c88e8266c6363331e7096d0ba38fd862c1420
push id10767
push userbmo:jyavenard@mozilla.com
push dateThu, 11 Feb 2016 22:50:03 +0000
reviewersgerald
bugs1245463, 1239983
milestone47.0a1
Bug 1245463: [MSE] P3. When abort() is called, wait until the current appendBuffer completes. r?gerald The W3C spec indicates that while everything in MSE is asynchronous, the abort() command is to interrupt the current segment parser loop and have the reset parser loop synchronously completes the frames present in the input buffer. This causes a fundamental issue that abort() will never result in a deterministic outcome as the segment parser loop may be in different condition. We used to really attempt to abort the current operation, however there could have been a race in the order in which tasks were queued. As such, we now simply wait for the current appendBuffer to complete. This also simplifies the code greatly, as we don't need to worry about pending concurrent appendBuffer. The actually happens to be similar to the Chromium behavior. Similar to bug 1239983, we strongly assert should a segment parser loop be running when it must have completed. MozReview-Commit-ID: 9772PLQEozf
dom/media/mediasource/SourceBuffer.cpp
dom/media/mediasource/SourceBuffer.h
dom/media/mediasource/SourceBufferContentManager.h
dom/media/mediasource/TrackBuffersManager.cpp
dom/media/mediasource/TrackBuffersManager.h
--- a/dom/media/mediasource/SourceBuffer.cpp
+++ b/dom/media/mediasource/SourceBuffer.cpp
@@ -34,37 +34,16 @@ extern mozilla::LogModule* GetMediaSourc
 #define MSE_API(arg, ...) MOZ_LOG(GetMediaSourceAPILog(), mozilla::LogLevel::Debug, ("SourceBuffer(%p:%s)::%s: " arg, this, mType.get(), __func__, ##__VA_ARGS__))
 
 namespace mozilla {
 
 using media::TimeUnit;
 
 namespace dom {
 
-class BufferAppendRunnable : public nsRunnable {
-public:
-  BufferAppendRunnable(SourceBuffer* aSourceBuffer,
-                       uint32_t aUpdateID)
-  : mSourceBuffer(aSourceBuffer)
-  , mUpdateID(aUpdateID)
-  {
-  }
-
-  NS_IMETHOD Run() override final {
-
-    mSourceBuffer->BufferAppend(mUpdateID);
-
-    return NS_OK;
-  }
-
-private:
-  RefPtr<SourceBuffer> mSourceBuffer;
-  uint32_t mUpdateID;
-};
-
 void
 SourceBuffer::SetMode(SourceBufferAppendMode aMode, ErrorResult& aRv)
 {
   typedef mozilla::SourceBufferContentManager::AppendState AppendState;
 
   MOZ_ASSERT(NS_IsMainThread());
   MSE_API("SetMode(aMode=%d)", aMode);
   if (!IsAttached() || mUpdating) {
@@ -221,20 +200,23 @@ SourceBuffer::Abort(ErrorResult& aRv)
   mAttributes->SetAppendWindowStart(0);
   mAttributes->SetAppendWindowEnd(PositiveInfinity<double>());
 }
 
 void
 SourceBuffer::AbortBufferAppend()
 {
   if (mUpdating) {
-    mPendingAppend.DisconnectIfExists();
-    // TODO: Abort stream append loop algorithms.
-    // cancel any pending buffer append.
-    mContentManager->AbortAppendData();
+    if (mPendingAppend.Exists()) {
+      mPendingAppend.Disconnect();
+      mContentManager->AbortAppendData();
+      // Some data may have been added by the Segment Parser Loop.
+      // Check if we need to update the duration.
+      CheckEndTime();
+    }
     AbortUpdating();
   }
 }
 
 void
 SourceBuffer::Remove(double aStart, double aEnd, ErrorResult& aRv)
 {
   MOZ_ASSERT(NS_IsMainThread());
@@ -304,17 +286,16 @@ SourceBuffer::Ended()
   mMediaSource->GetDecoder()->NotifyDataArrived();
 }
 
 SourceBuffer::SourceBuffer(MediaSource* aMediaSource, const nsACString& aType)
   : DOMEventTargetHelper(aMediaSource->GetParentObject())
   , mMediaSource(aMediaSource)
   , mUpdating(false)
   , mActive(false)
-  , mUpdateID(0)
   , mType(aType)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aMediaSource);
   mEvictionThreshold = Preferences::GetUint("media.mediasource.eviction_threshold",
                                             100 * (1 << 20));
   bool generateTimestamps = false;
   if (aType.LowerCaseEqualsLiteral("audio/mpeg") ||
@@ -376,43 +357,37 @@ SourceBuffer::QueueAsyncSimpleEvent(cons
 }
 
 void
 SourceBuffer::StartUpdating()
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(!mUpdating);
   mUpdating = true;
-  mUpdateID++;
   QueueAsyncSimpleEvent("updatestart");
 }
 
 void
 SourceBuffer::StopUpdating()
 {
   MOZ_ASSERT(NS_IsMainThread());
   if (!mUpdating) {
-    // The buffer append algorithm has been interrupted by abort().
-    //
-    // If the sequence appendBuffer(), abort(), appendBuffer() occurs before
-    // the first StopUpdating() runnable runs, then a second StopUpdating()
-    // runnable will be scheduled, but still only one (the first) will queue
-    // events.
+    // The buffer append or range removal algorithm  has been interrupted by
+    // abort().
     return;
   }
   mUpdating = false;
   QueueAsyncSimpleEvent("update");
   QueueAsyncSimpleEvent("updateend");
 }
 
 void
 SourceBuffer::AbortUpdating()
 {
   MOZ_ASSERT(NS_IsMainThread());
-  MOZ_ASSERT(mUpdating);
   mUpdating = false;
   QueueAsyncSimpleEvent("abort");
   QueueAsyncSimpleEvent("updateend");
 }
 
 void
 SourceBuffer::CheckEndTime()
 {
@@ -433,50 +408,37 @@ SourceBuffer::AppendData(const uint8_t* 
   RefPtr<MediaByteBuffer> data = PrepareAppend(aData, aLength, aRv);
   if (!data) {
     return;
   }
   mContentManager->AppendData(data, mAttributes->GetTimestampOffset());
 
   StartUpdating();
 
-  nsCOMPtr<nsIRunnable> task = new BufferAppendRunnable(this, mUpdateID);
-  NS_DispatchToMainThread(task);
+  BufferAppend();
 }
 
 void
-SourceBuffer::BufferAppend(uint32_t aUpdateID)
+SourceBuffer::BufferAppend()
 {
-  if (!mUpdating || aUpdateID != mUpdateID) {
-    // The buffer append algorithm has been interrupted by abort().
-    //
-    // If the sequence appendBuffer(), abort(), appendBuffer() occurs before
-    // the first StopUpdating() runnable runs, then a second StopUpdating()
-    // runnable will be scheduled, but still only one (the first) will queue
-    // events.
-    return;
-  }
-
+  MOZ_ASSERT(mUpdating);
   MOZ_ASSERT(mMediaSource);
   MOZ_ASSERT(!mPendingAppend.Exists());
 
   mPendingAppend.Begin(mContentManager->BufferAppend()
                        ->Then(AbstractThread::MainThread(), __func__, this,
                               &SourceBuffer::AppendDataCompletedWithSuccess,
                               &SourceBuffer::AppendDataErrored));
 }
 
 void
 SourceBuffer::AppendDataCompletedWithSuccess(bool aHasActiveTracks)
 {
+  MOZ_ASSERT(mUpdating);
   mPendingAppend.Complete();
-  if (!mUpdating) {
-    // The buffer append algorithm has been interrupted by abort().
-    return;
-  }
 
   if (aHasActiveTracks) {
     if (!mActive) {
       mActive = true;
       mMediaSource->SourceBufferIsActive(this);
     }
   }
   if (mActive) {
@@ -489,36 +451,35 @@ SourceBuffer::AppendDataCompletedWithSuc
   CheckEndTime();
 
   StopUpdating();
 }
 
 void
 SourceBuffer::AppendDataErrored(nsresult aError)
 {
+  MOZ_ASSERT(mUpdating);
   mPendingAppend.Complete();
+
   switch (aError) {
     case NS_ERROR_ABORT:
       // Nothing further to do as the trackbuffer has been shutdown.
       // or append was aborted and abort() has handled all the events.
       break;
     default:
       AppendError(true);
       break;
   }
 }
 
 void
 SourceBuffer::AppendError(bool aDecoderError)
 {
   MOZ_ASSERT(NS_IsMainThread());
-  if (!mUpdating) {
-    // The buffer append algorithm has been interrupted by abort().
-    return;
-  }
+
   mContentManager->ResetParserState();
 
   mUpdating = false;
 
   QueueAsyncSimpleEvent("error");
   QueueAsyncSimpleEvent("updateend");
 
   if (aDecoderError) {
--- a/dom/media/mediasource/SourceBuffer.h
+++ b/dom/media/mediasource/SourceBuffer.h
@@ -233,17 +233,17 @@ private:
 
   // If the media segment contains data beyond the current duration,
   // then run the duration change algorithm with new duration set to the
   // maximum of the current duration and the group end timestamp.
   void CheckEndTime();
 
   // Shared implementation of AppendBuffer overloads.
   void AppendData(const uint8_t* aData, uint32_t aLength, ErrorResult& aRv);
-  void BufferAppend(uint32_t aAppendID);
+  void BufferAppend();
 
   // Implement the "Append Error Algorithm".
   // Will call endOfStream() with "decode" error if aDecodeError is true.
   // 3.5.3 Append Error Algorithm
   // http://w3c.github.io/media-source/#sourcebuffer-append-error
   void AppendError(bool aDecoderError);
 
   // Implements the "Prepare Append Algorithm". Returns MediaByteBuffer object
@@ -261,21 +261,16 @@ private:
 
   RefPtr<SourceBufferContentManager> mContentManager;
   RefPtr<SourceBufferAttributes> mAttributes;
 
   bool mUpdating;
 
   mozilla::Atomic<bool> mActive;
 
-  // Each time mUpdating is set to true, mUpdateID will be incremented.
-  // This allows for a queued AppendData task to identify if it was earlier
-  // aborted and another AppendData queued.
-  uint32_t mUpdateID;
-
   MozPromiseRequestHolder<SourceBufferContentManager::AppendPromise> mPendingAppend;
   const nsCString mType;
 
   RefPtr<TimeRanges> mBuffered;
 };
 
 } // namespace dom
 
--- a/dom/media/mediasource/SourceBufferContentManager.h
+++ b/dom/media/mediasource/SourceBufferContentManager.h
@@ -103,19 +103,15 @@ public:
   {
     return AppendState::WAITING_FOR_SEGMENT;
   }
 
   virtual void SetGroupStartTimestamp(const media::TimeUnit& aGroupStartTimestamp) {}
   virtual void RestartGroupStartTimestamp() {}
   virtual media::TimeUnit GroupEndTimestamp() = 0;
 
-#if defined(DEBUG)
-  virtual void Dump(const char* aPath) { }
-#endif
-
 protected:
   virtual ~SourceBufferContentManager() { }
 };
 
 } // namespace mozilla
 
 #endif /* MOZILLA_SOURCEBUFFERCONTENTMANAGER_H_ */
--- a/dom/media/mediasource/TrackBuffersManager.cpp
+++ b/dom/media/mediasource/TrackBuffersManager.cpp
@@ -91,25 +91,24 @@ TrackBuffersManager::TrackBuffersManager
   , mAppendState(AppendState::WAITING_FOR_SEGMENT)
   , mBufferFull(false)
   , mFirstInitializationSegmentReceived(false)
   , mNewMediaSegmentStarted(false)
   , mActiveTrack(false)
   , mType(aType)
   , mParser(ContainerParser::CreateForMIMEType(aType))
   , mProcessedInput(0)
-  , mAppendRunning(false)
   , mTaskQueue(aParentDecoder->GetDemuxer()->GetTaskQueue())
   , mSourceBufferAttributes(aAttributes)
   , mParentDecoder(new nsMainThreadPtrHolder<MediaSourceDecoder>(aParentDecoder, false /* strict */))
-  , mAbort(false)
   , mEvictionThreshold(Preferences::GetUint("media.mediasource.eviction_threshold",
                                             100 * (1 << 20)))
   , mEvictionOccurred(false)
   , mMonitor("TrackBuffersManager")
+  , mAppendRunning(false)
 {
   MOZ_ASSERT(NS_IsMainThread(), "Must be instanciated on the main thread");
 }
 
 TrackBuffersManager::~TrackBuffersManager()
 {
   ShutdownDemuxers();
 }
@@ -130,51 +129,51 @@ TrackBuffersManager::AppendData(MediaByt
   return true;
 }
 
 void
 TrackBuffersManager::AppendIncomingBuffer(IncomingBuffer aData)
 {
   MOZ_ASSERT(OnTaskQueue());
   mIncomingBuffers.AppendElement(aData);
-  mAbort = false;
 }
 
 RefPtr<TrackBuffersManager::AppendPromise>
 TrackBuffersManager::BufferAppend()
 {
   MOZ_ASSERT(NS_IsMainThread());
   MSE_DEBUG("");
 
+  mAppendRunning = true;
   return InvokeAsync(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.
-// We do however want to ensure that no new task will be dispatched on our task
-// queue and only let the current one finish its job. For this we set mAbort
-// to true.
+// The MSE spec requires that we abort the current SegmentParserLoop
+// which is then followed by a call to ResetParserState.
+// However due to our asynchronous design this causes inherent difficulities.
+// As the spec behaviour is non deterministic anyway, we instead wait until the
+// current AppendData has completed its run.
 void
 TrackBuffersManager::AbortAppendData()
 {
   MOZ_ASSERT(NS_IsMainThread());
   MSE_DEBUG("");
 
-  mAbort = true;
+  MonitorAutoLock mon(mMonitor);
+  while (mAppendRunning) {
+    mon.Wait();
+  }
 }
 
 void
 TrackBuffersManager::ResetParserState()
 {
   MOZ_ASSERT(NS_IsMainThread());
-  MOZ_ASSERT(!mAppendRunning, "AbortAppendData must have been called");
+  MOZ_RELEASE_ASSERT(!mAppendRunning, "Append is running, abort 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 {
@@ -297,30 +296,16 @@ TrackBuffersManager::Ended()
   mEnded = true;
 }
 
 void
 TrackBuffersManager::Detach()
 {
   MOZ_ASSERT(NS_IsMainThread());
   MSE_DEBUG("");
-
-  // Abort pending operations if any.
-  AbortAppendData();
-
-  RefPtr<TrackBuffersManager> self = this;
-  nsCOMPtr<nsIRunnable> task =
-    NS_NewRunnableFunction([self] () {
-      // Clear our sourcebuffer
-      self->CodedFrameRemoval(TimeInterval(TimeUnit::FromSeconds(0),
-                                           TimeUnit::FromInfinity()));
-      self->mProcessingPromise.RejectIfExists(NS_ERROR_ABORT, __func__);
-      self->mAppendPromise.RejectIfExists(NS_ERROR_ABORT, __func__);
-    });
-  GetTaskQueue()->Dispatch(task.forget());
 }
 
 #if defined(DEBUG)
 void
 TrackBuffersManager::Dump(const char* aPath)
 {
 
 }
@@ -343,17 +328,17 @@ TrackBuffersManager::FinishCodedFramePro
 
   CompleteResetParserState();
 }
 
 void
 TrackBuffersManager::CompleteResetParserState()
 {
   MOZ_ASSERT(OnTaskQueue());
-  MOZ_ASSERT(!mAppendRunning);
+  MOZ_RELEASE_ASSERT(!mAppendRunning);
   MSE_DEBUG("");
 
   for (auto& track : GetTracksList()) {
     // 2. Unset the last decode timestamp on all track buffers.
     // 3. Unset the last frame duration on all track buffers.
     // 4. Unset the highest end timestamp on all track buffers.
     // 5. Set the need random access point flag on all track buffers to true.
     track->ResetAppendState();
@@ -581,18 +566,19 @@ TrackBuffersManager::UpdateBufferedRange
 
   mOfficialGroupEndTimestamp = mGroupEndTimestamp;
 }
 
 RefPtr<TrackBuffersManager::AppendPromise>
 TrackBuffersManager::InitSegmentParserLoop()
 {
   MOZ_ASSERT(OnTaskQueue());
+  MOZ_RELEASE_ASSERT(mAppendPromise.IsEmpty());
+  MSE_DEBUG("");
 
-  MOZ_ASSERT(mAppendPromise.IsEmpty() && !mAppendRunning);
   RefPtr<AppendPromise> p = mAppendPromise.Ensure(__func__);
 
   AppendIncomingBuffers();
   SegmentParserLoop();
 
   return p;
 }
 
@@ -616,16 +602,17 @@ TrackBuffersManager::AppendIncomingBuffe
     TimeInterval(TimeUnit::FromSeconds(mSourceBufferAttributes->GetAppendWindowStart()),
                  TimeUnit::FromSeconds(mSourceBufferAttributes->GetAppendWindowEnd()));
 }
 
 void
 TrackBuffersManager::SegmentParserLoop()
 {
   MOZ_ASSERT(OnTaskQueue());
+
   while (true) {
     // 1. If the input buffer is empty, then jump to the need more data step below.
     if (!mInputBuffer || mInputBuffer->IsEmpty()) {
       NeedMoreData();
       return;
     }
     // 2. If the input buffer contains bytes that violate the SourceBuffer
     // byte stream format specification, then run the append error algorithm with
@@ -719,17 +706,17 @@ TrackBuffersManager::SegmentParserLoop()
       }
 
       // 3. If the input buffer contains one or more complete coded frames, then run the coded frame processing algorithm.
       RefPtr<TrackBuffersManager> self = this;
       mProcessingRequest.Begin(CodedFrameProcessing()
           ->Then(GetTaskQueue(), __func__,
                  [self] (bool aNeedMoreData) {
                    self->mProcessingRequest.Complete();
-                   if (aNeedMoreData || self->mAbort) {
+                   if (aNeedMoreData) {
                      self->NeedMoreData();
                    } else {
                      self->ScheduleSegmentParserLoop();
                    }
                  },
                  [self] (nsresult aRejectValue) {
                    self->mProcessingRequest.Complete();
                    self->RejectAppend(aRejectValue, __func__);
@@ -738,29 +725,33 @@ TrackBuffersManager::SegmentParserLoop()
     }
   }
 }
 
 void
 TrackBuffersManager::NeedMoreData()
 {
   MSE_DEBUG("");
-  if (!mAbort) {
-    RestoreCachedVariables();
-  }
+  RestoreCachedVariables();
+  mAppendPromise.ResolveIfExists(mActiveTrack, __func__);
+  // Wake-up any pending Abort()
+  MonitorAutoLock mon(mMonitor);
   mAppendRunning = false;
-  mAppendPromise.ResolveIfExists(mActiveTrack, __func__);
+  mon.NotifyAll();
 }
 
 void
 TrackBuffersManager::RejectAppend(nsresult aRejectValue, const char* aName)
 {
   MSE_DEBUG("rv=%d", aRejectValue);
+  mAppendPromise.RejectIfExists(aRejectValue, aName);
+  // Wake-up any pending Abort()
+  MonitorAutoLock mon(mMonitor);
   mAppendRunning = false;
-  mAppendPromise.RejectIfExists(aRejectValue, aName);
+  mon.NotifyAll();
 }
 
 void
 TrackBuffersManager::ScheduleSegmentParserLoop()
 {
   nsCOMPtr<nsIRunnable> task =
     NS_NewRunnableMethod(this, &TrackBuffersManager::SegmentParserLoop);
   GetTaskQueue()->Dispatch(task.forget());
@@ -826,22 +817,17 @@ TrackBuffersManager::ResetDemuxingState(
                              &TrackBuffersManager::OnDemuxerResetDone,
                              &TrackBuffersManager::OnDemuxerInitFailed));
 }
 
 void
 TrackBuffersManager::OnDemuxerResetDone(nsresult)
 {
   MOZ_ASSERT(OnTaskQueue());
-  MSE_DEBUG("mAbort:%d", static_cast<bool>(mAbort));
   mDemuxerInitRequest.Complete();
-  if (mAbort) {
-    RejectAppend(NS_ERROR_ABORT, __func__);
-    return;
-  }
   // mInputDemuxer shouldn't have been destroyed while a demuxer init/reset
   // request was being processed. See bug 1239983.
   MOZ_DIAGNOSTIC_ASSERT(mInputDemuxer);
 
   // Recreate track demuxers.
   uint32_t numVideos = mInputDemuxer->GetNumberTracks(TrackInfo::kVideoTrack);
   if (numVideos) {
     // We currently only handle the first video track.
@@ -903,23 +889,18 @@ TrackBuffersManager::InitializationSegme
                              &TrackBuffersManager::OnDemuxerInitDone,
                              &TrackBuffersManager::OnDemuxerInitFailed));
 }
 
 void
 TrackBuffersManager::OnDemuxerInitDone(nsresult)
 {
   MOZ_ASSERT(OnTaskQueue());
-  MSE_DEBUG("mAbort:%d", static_cast<bool>(mAbort));
   mDemuxerInitRequest.Complete();
 
-  if (mAbort) {
-    RejectAppend(NS_ERROR_ABORT, __func__);
-    return;
-  }
   // mInputDemuxer shouldn't have been destroyed while a demuxer init/reset
   // request was being processed. See bug 1239983.
   MOZ_DIAGNOSTIC_ASSERT(mInputDemuxer);
 
   MediaInfo info;
 
   uint32_t numVideos = mInputDemuxer->GetNumberTracks(TrackInfo::kVideoTrack);
   if (numVideos) {
@@ -1169,19 +1150,18 @@ TrackBuffersManager::CodedFrameProcessin
   return p;
 }
 
 void
 TrackBuffersManager::OnDemuxFailed(TrackType aTrack,
                                    DemuxerFailureReason aFailure)
 {
   MOZ_ASSERT(OnTaskQueue());
-  MSE_DEBUG("Failed to demux %s, failure:%d mAbort:%d",
-            aTrack == TrackType::kVideoTrack ? "video" : "audio",
-            aFailure, static_cast<bool>(mAbort));
+  MSE_DEBUG("Failed to demux %s, failure:%d",
+            aTrack == TrackType::kVideoTrack ? "video" : "audio", aFailure);
   switch (aFailure) {
     case DemuxerFailureReason::END_OF_STREAM:
     case DemuxerFailureReason::WAITING_FOR_DATA:
       if (aTrack == TrackType::kVideoTrack) {
         DoDemuxAudio();
       } else {
         CompleteCodedFrameProcessing();
       }
@@ -1198,25 +1178,20 @@ TrackBuffersManager::OnDemuxFailed(Track
       break;
   }
 }
 
 void
 TrackBuffersManager::DoDemuxVideo()
 {
   MOZ_ASSERT(OnTaskQueue());
-  MSE_DEBUG("mAbort:%d", static_cast<bool>(mAbort));
   if (!HasVideo()) {
     DoDemuxAudio();
     return;
   }
-  if (mAbort) {
-    RejectProcessing(NS_ERROR_ABORT, __func__);
-    return;
-  }
   mVideoTracks.mDemuxRequest.Begin(mVideoTracks.mDemuxer->GetSamples(-1)
                              ->Then(GetTaskQueue(), __func__, this,
                                     &TrackBuffersManager::OnVideoDemuxCompleted,
                                     &TrackBuffersManager::OnVideoDemuxFailed));
 }
 
 void
 TrackBuffersManager::OnVideoDemuxCompleted(RefPtr<MediaTrackDemuxer::SamplesHolder> aSamples)
@@ -1227,25 +1202,20 @@ TrackBuffersManager::OnVideoDemuxComplet
   mVideoTracks.mQueuedSamples.AppendElements(aSamples->mSamples);
   DoDemuxAudio();
 }
 
 void
 TrackBuffersManager::DoDemuxAudio()
 {
   MOZ_ASSERT(OnTaskQueue());
-  MSE_DEBUG("mAbort:%d", static_cast<bool>(mAbort));
   if (!HasAudio()) {
     CompleteCodedFrameProcessing();
     return;
   }
-  if (mAbort) {
-    RejectProcessing(NS_ERROR_ABORT, __func__);
-    return;
-  }
   mAudioTracks.mDemuxRequest.Begin(mAudioTracks.mDemuxer->GetSamples(-1)
                              ->Then(GetTaskQueue(), __func__, this,
                                     &TrackBuffersManager::OnAudioDemuxCompleted,
                                     &TrackBuffersManager::OnAudioDemuxFailed));
 }
 
 void
 TrackBuffersManager::OnAudioDemuxCompleted(RefPtr<MediaTrackDemuxer::SamplesHolder> aSamples)
@@ -1256,17 +1226,16 @@ TrackBuffersManager::OnAudioDemuxComplet
   mAudioTracks.mQueuedSamples.AppendElements(aSamples->mSamples);
   CompleteCodedFrameProcessing();
 }
 
 void
 TrackBuffersManager::CompleteCodedFrameProcessing()
 {
   MOZ_ASSERT(OnTaskQueue());
-  MSE_DEBUG("mAbort:%d", static_cast<bool>(mAbort));
 
   // 1. For each coded frame in the media segment run the following steps:
   // Coded Frame Processing steps 1.1 to 1.21.
   ProcessFrames(mVideoTracks.mQueuedSamples, mVideoTracks);
   mVideoTracks.mQueuedSamples.Clear();
 
 #if defined(DEBUG)
   if (HasVideo()) {
@@ -1327,32 +1296,22 @@ TrackBuffersManager::CompleteCodedFrameP
 
   // 8. Jump to the loop top step above.
   ResolveProcessing(false, __func__);
 }
 
 void
 TrackBuffersManager::RejectProcessing(nsresult aRejectValue, const char* aName)
 {
-  if (mAbort) {
-    // mAppendPromise will be resolved immediately upon mProcessingPromise
-    // completing.
-    mAppendRunning = false;
-  }
   mProcessingPromise.RejectIfExists(aRejectValue, __func__);
 }
 
 void
 TrackBuffersManager::ResolveProcessing(bool aResolveValue, const char* aName)
 {
-  if (mAbort) {
-    // mAppendPromise will be resolved immediately upon mProcessingPromise
-    // completing.
-    mAppendRunning = false;
-  }
   mProcessingPromise.ResolveIfExists(aResolveValue, __func__);
 }
 
 void
 TrackBuffersManager::CheckSequenceDiscontinuity(const TimeUnit& aPresentationTime)
 {
   if (mSourceBufferAttributes->GetAppendMode() == SourceBufferAppendMode::Sequence &&
       mGroupStartTimestamp.isSome()) {
--- a/dom/media/mediasource/TrackBuffersManager.h
+++ b/dom/media/mediasource/TrackBuffersManager.h
@@ -305,20 +305,16 @@ private:
                            const media::TimeInterval& aInterval);
   void UpdateBufferedRanges();
   void RejectProcessing(nsresult aRejectValue, const char* aName);
   void ResolveProcessing(bool aResolveValue, const char* aName);
   MozPromiseRequestHolder<CodedFrameProcessingPromise> mProcessingRequest;
   MozPromiseHolder<CodedFrameProcessingPromise> mProcessingPromise;
 
   MozPromiseHolder<AppendPromise> mAppendPromise;
-  // Set to true while SegmentParserLoop is running. This is used for diagnostic
-  // purposes only. We can't rely on mAppendPromise to be empty as it is only
-  // cleared in a follow up task.
-  bool mAppendRunning;
 
   // Trackbuffers definition.
   nsTArray<TrackData*> GetTracksList();
   TrackData& GetTracksData(TrackType aTrack)
   {
     switch(aTrack) {
       case TrackType::kVideoTrack:
         return mVideoTracks;
@@ -344,28 +340,29 @@ private:
   media::TimeUnit mTimestampOffset;
   media::TimeUnit mLastTimestampOffset;
   void RestoreCachedVariables();
 
   // Strong references to external objects.
   RefPtr<dom::SourceBufferAttributes> mSourceBufferAttributes;
   nsMainThreadPtrHandle<MediaSourceDecoder> mParentDecoder;
 
-  // Set to true if abort was called.
-  Atomic<bool> mAbort;
   // Set to true if mediasource state changed to ended.
   Atomic<bool> mEnded;
 
   // Global size of this source buffer content.
   Atomic<int64_t> mSizeSourceBuffer;
   uint32_t mEvictionThreshold;
   Atomic<bool> mEvictionOccurred;
 
   // Monitor to protect following objects accessed across multipple threads.
+  // mMonitor is also notified if the value of mAppendRunning becomes false.
   mutable Monitor mMonitor;
+  // Set to true while SegmentParserLoop is running.
+  Atomic<bool> mAppendRunning;
   // Stable audio and video track time ranges.
   media::TimeIntervals mVideoBufferedRanges;
   media::TimeIntervals mAudioBufferedRanges;
   media::TimeUnit mOfficialGroupEndTimestamp;
   // MediaInfo of the first init segment read.
   MediaInfo mInfo;
 };