Bug 1308147. Part 2 - add DormantState::mPendingSeek to store a pending seek job. draft
authorJW Wang <jwwang@mozilla.com>
Wed, 19 Oct 2016 15:35:29 +0800
changeset 428541 041d7bf9e8937897b219a77193bc1783b6a78661
parent 428540 9406c03a712a76e79beaf98549d6ddcf939004f9
child 428542 6dacb53128be4693604d42b501a172e9ea03ccfb
push id33335
push userjwwang@mozilla.com
push dateMon, 24 Oct 2016 07:05:42 +0000
bugs1308147
milestone52.0a1
Bug 1308147. Part 2 - add DormantState::mPendingSeek to store a pending seek job. MozReview-Commit-ID: oySkHWuYo3
dom/media/MediaDecoderStateMachine.cpp
--- a/dom/media/MediaDecoderStateMachine.cpp
+++ b/dom/media/MediaDecoderStateMachine.cpp
@@ -425,49 +425,60 @@ private:
  *   DECODING_FIRSTFRAME when being asked to exit dormant.
  */
 class MediaDecoderStateMachine::DormantState
   : public MediaDecoderStateMachine::StateObject
 {
 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();
     }
     mMaster->Reset();
     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;
   }
 
   bool HandleDormant(bool aDormant) override;
 
   RefPtr<MediaDecoder::SeekPromise> 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
   {
     // Do nothing since we've released decoders in Enter().
   }
 
   void HandleResumeVideoDecoding() override
   {
     // Do nothing since we won't resume decoding until exiting dormant.
   }
+
+private:
+  SeekJob mPendingSeek;
 };
 
 /**
  * Purpose: decode the 1st audio and video frames to fire the 'loadeddata' event.
  *
  * Transition to:
  *   DORMANT if any dormant request.
  *   SHUTDOWN if any decode error.
@@ -1104,25 +1115,28 @@ public:
 
 bool
 MediaDecoderStateMachine::
 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<MediaDecoder::SeekPromise> unused =
-    mMaster->mQueuedSeek.mPromise.Ensure(__func__);
-  SetState<DormantState>();
+  RefPtr<MediaDecoder::SeekPromise> unused = seekJob.mPromise.Ensure(__func__);
+  SetState<DormantState>(Move(seekJob));
   return true;
 }
 
 RefPtr<ShutdownPromise>
 MediaDecoderStateMachine::
 StateObject::HandleShutdown()
 {
   return SetState<ShutdownState>();
@@ -1252,17 +1266,17 @@ DecodeMetadataState::OnMetadataRead(Meta
     mMaster->EnqueueLoadedMetadataEvent();
   }
 
   if (waitingForCDM) {
     // Metadata parsing was successful but we're still waiting for CDM caps
     // to become available so that we can build the correct decryptor/decoder.
     SetState<WaitForCDMState>(mPendingDormant);
   } else if (mPendingDormant) {
-    SetState<DormantState>();
+    SetState<DormantState>(SeekJob{});
   } else {
     SetState<DecodingFirstFrameState>();
   }
 }
 
 bool
 MediaDecoderStateMachine::
 WaitForCDMState::HandleDormant(bool aDormant)
@@ -1282,17 +1296,18 @@ DormantState::HandleDormant(bool aDorman
   return true;
 }
 
 bool
 MediaDecoderStateMachine::
 WaitForCDMState::HandleCDMProxyReady()
 {
   if (mPendingDormant) {
-    SetState<DormantState>();
+    SeekJob seekJob = Move(mPendingSeek);
+    SetState<DormantState>(Move(seekJob));
   } else {
     SetState<DecodingFirstFrameState>();
   }
   return true;
 }
 
 void
 MediaDecoderStateMachine::
@@ -1348,17 +1363,18 @@ MediaDecoderStateMachine::
 DecodingFirstFrameState::HandleDormant(bool aDormant)
 {
   if (aDormant) {
     // Don't store mQueuedSeek because:
     // 1. if mQueuedSeek is not empty, respect the latest seek request
     //    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<DormantState>();
+    SeekJob seekJob = Move(mMaster->mQueuedSeek);
+    SetState<DormantState>(Move(seekJob));
   }
   return true;
 }
 
 void
 MediaDecoderStateMachine::
 DecodingFirstFrameState::MaybeFinishDecodeFirstFrame()
 {
@@ -1482,18 +1498,18 @@ SeekingState::HandleDormant(bool aDorman
   // Because both audio and video decoders are going to be reset in this
   // method later, we treat a VideoOnly seek task as a normal Accurate
   // seek task so that while it is resumed, both audio and video playback
   // are handled.
   if (mSeekJob.mTarget.IsVideoOnly()) {
     mSeekJob.mTarget.SetType(SeekTarget::Accurate);
     mSeekJob.mTarget.SetVideoOnly(false);
   }
-  mMaster->mQueuedSeek = Move(mSeekJob);
-  SetState<DormantState>();
+  SeekJob seekJob = Move(mSeekJob);
+  SetState<DormantState>(Move(seekJob));
   return true;
 }
 
 RefPtr<MediaDecoder::SeekPromise>
 MediaDecoderStateMachine::
 SeekingState::HandleSeek(SeekTarget aTarget)
 {
   mMaster->mQueuedSeek.RejectIfExists(__func__);