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
--- 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;
};