diff --git a/dom/media/MediaDecoderStateMachine.cpp b/dom/media/MediaDecoderStateMachine.cpp index 04ae9f3a79e9..3e09708cd8e6 100644 --- a/dom/media/MediaDecoderStateMachine.cpp +++ b/dom/media/MediaDecoderStateMachine.cpp @@ -430,8 +430,10 @@ class MediaDecoderStateMachine::DormantState public: explicit DormantState(Master* aPtr) : StateObject(aPtr) {} - void Enter() + void Enter(SeekJob aPendingSeek) { + MOZ_ASSERT(!mMaster->mQueuedSeek.Exists()); + mPendingSeek = Move(aPendingSeek); if (mMaster->IsPlaying()) { mMaster->StopPlayback(); } @@ -439,6 +441,12 @@ public: mMaster->mReader->ReleaseResources(); } + void Exit() override + { + // Transfer the seek job so it is available to the next state. + mMaster->mQueuedSeek = Move(mPendingSeek); + } + State GetState() const override { return DECODER_STATE_DORMANT; @@ -449,9 +457,9 @@ public: RefPtr HandleSeek(SeekTarget aTarget) override { SLOG("Not Enough Data to seek at this stage, queuing seek"); - mMaster->mQueuedSeek.RejectIfExists(__func__); - mMaster->mQueuedSeek.mTarget = aTarget; - return mMaster->mQueuedSeek.mPromise.Ensure(__func__); + mPendingSeek.RejectIfExists(__func__); + mPendingSeek.mTarget = aTarget; + return mPendingSeek.mPromise.Ensure(__func__); } void HandleVideoSuspendTimeout() override @@ -463,6 +471,9 @@ public: { // Do nothing since we won't resume decoding until exiting dormant. } + +private: + SeekJob mPendingSeek; }; /** @@ -1109,15 +1120,18 @@ StateObject::HandleDormant(bool aDormant) if (!aDormant) { return true; } - mMaster->mQueuedSeek.mTarget = - SeekTarget(mMaster->mCurrentPosition, - SeekTarget::Accurate, - MediaDecoderEventVisibility::Suppressed); + // This member function is inherited by DecodingState, BufferingState and + // CompletedState which can handle seek immediately without queuing a seek. + // Therefore mQueuedSeek must be empty here. + MOZ_ASSERT(!mMaster->mQueuedSeek.Exists()); + SeekJob seekJob; + seekJob.mTarget = SeekTarget(mMaster->mCurrentPosition, + SeekTarget::Accurate, + MediaDecoderEventVisibility::Suppressed); // SeekJob asserts |mTarget.IsValid() == !mPromise.IsEmpty()| so we // need to create the promise even it is not used at all. - RefPtr unused = - mMaster->mQueuedSeek.mPromise.Ensure(__func__); - SetState(); + RefPtr unused = seekJob.mPromise.Ensure(__func__); + SetState(Move(seekJob)); return true; } @@ -1257,7 +1271,7 @@ DecodeMetadataState::OnMetadataRead(MetadataHolder* aMetadata) // to become available so that we can build the correct decryptor/decoder. SetState(mPendingDormant); } else if (mPendingDormant) { - SetState(); + SetState(SeekJob{}); } else { SetState(); } @@ -1287,7 +1301,8 @@ MediaDecoderStateMachine:: WaitForCDMState::HandleCDMProxyReady() { if (mPendingDormant) { - SetState(); + SeekJob seekJob = Move(mPendingSeek); + SetState(Move(seekJob)); } else { SetState(); } @@ -1353,7 +1368,8 @@ DecodingFirstFrameState::HandleDormant(bool aDormant) // and don't overwrite it. // 2. if mQueuedSeek is empty, there is no need to seek when exiting // the dormant state for we are at position 0. - SetState(); + SeekJob seekJob = Move(mMaster->mQueuedSeek); + SetState(Move(seekJob)); } return true; } @@ -1487,8 +1503,8 @@ SeekingState::HandleDormant(bool aDormant) mSeekJob.mTarget.SetType(SeekTarget::Accurate); mSeekJob.mTarget.SetVideoOnly(false); } - mMaster->mQueuedSeek = Move(mSeekJob); - SetState(); + SeekJob seekJob = Move(mSeekJob); + SetState(Move(seekJob)); return true; }