Bug 1338084 - delegate the SeekObject::HandleSeek() to the new SeekHanlder class; draft
authorKaku Kuo <kaku@mozilla.com>
Thu, 09 Feb 2017 17:06:01 +0800
changeset 481109 1ef907ab122ae291bd80ce7cc1b5425420e49b44
parent 480979 09b54d3b6af2d04688916040bcefdbcc00ae698b
child 545116 9d5f35eb1d6969021e78ffb7eafcb2b2df030290
push id44724
push userbmo:kaku@mozilla.com
push dateThu, 09 Feb 2017 09:06:26 +0000
bugs1338084
milestone54.0a1
Bug 1338084 - delegate the SeekObject::HandleSeek() to the new SeekHanlder class; MozReview-Commit-ID: J0iCHKTxSow
dom/media/MediaDecoderStateMachine.cpp
--- a/dom/media/MediaDecoderStateMachine.cpp
+++ b/dom/media/MediaDecoderStateMachine.cpp
@@ -179,16 +179,87 @@ static TimeDuration
 SuspendBackgroundVideoDelay()
 {
   return TimeDuration::FromMilliseconds(
     MediaPrefs::MDSMSuspendBackgroundVideoDelay());
 }
 
 class MediaDecoderStateMachine::StateObject
 {
+protected:
+  class SeekHandler
+  {
+  public:
+    SeekHandler(StateObject* aObject) : mObject(aObject), mMaster(aObject->mMaster) {}
+    virtual ~SeekHandler() {}
+    virtual RefPtr<MediaDecoder::SeekPromise> HandleSeek(SeekTarget aTarget) = 0;
+    virtual bool PendingSeekExist() const { return false; }
+    virtual void SwitchToSeekingState()
+    {
+      MOZ_DIAGNOSTIC_ASSERT(false, "Only switch to SeekingState with a pending SeekJob.");
+    }
+
+  protected:
+    using Master = MediaDecoderStateMachine;
+    State GetState() const { return mObject->GetState(); }
+    StateObject* mObject;
+    Master* mMaster;
+  };
+
+  class DefaultSeekHandler final : public SeekHandler
+  {
+  public:
+    DefaultSeekHandler(StateObject* aObject) : SeekHandler(aObject) {}
+    RefPtr<MediaDecoder::SeekPromise> HandleSeek(SeekTarget aTarget) override
+    {
+      SLOG("Changed state to SEEKING (to %lld)", aTarget.GetTime().ToMicroseconds());
+      SeekJob seekJob;
+      seekJob.mTarget = Some(aTarget);
+      return mObject->SetSeekingState(Move(seekJob), EventVisibility::Observable);
+    }
+  };
+
+  class RejectSeekHandler final : public SeekHandler
+  {
+  public:
+    RejectSeekHandler(StateObject* aObject) : SeekHandler(aObject) {}
+    RefPtr<MediaDecoder::SeekPromise> HandleSeek(SeekTarget aTarget) override
+    {
+      MOZ_DIAGNOSTIC_ASSERT(false, "Can't seek in this state.");
+      return MediaDecoder::SeekPromise::CreateAndReject(true, __func__);
+    }
+  };
+
+  class PendingSeekHandler final : public SeekHandler
+  {
+  public:
+    PendingSeekHandler(StateObject* aObject) : SeekHandler(aObject) {}
+    ~PendingSeekHandler() { mPendingSeek.RejectIfExists(__func__); }
+    RefPtr<MediaDecoder::SeekPromise> HandleSeek(SeekTarget aTarget) override
+    {
+      SLOG("Not Enough Data to seek at this stage, queuing seek");
+      mPendingSeek.RejectIfExists(__func__);
+      mPendingSeek.mTarget.emplace(aTarget);
+      return mPendingSeek.mPromise.Ensure(__func__);
+    }
+
+    bool PendingSeekExist() const override
+    {
+      return mPendingSeek.Exists();
+    }
+
+    virtual void SwitchToSeekingState() override
+    {
+      mObject->SetSeekingState(Move(mPendingSeek), EventVisibility::Observable);
+    }
+
+  private:
+    SeekJob mPendingSeek;
+  };
+
 public:
   virtual ~StateObject() { }
   virtual void Exit() { }   // Exit action.
   virtual void Step() { }   // Perform a 'cycle' of this state object.
   virtual State GetState() const = 0;
 
   // Event handlers for various events.
   virtual void HandleCDMProxyReady() { }
@@ -229,17 +300,20 @@ public:
   {
     Crash("Unexpected event!", __func__);
   }
   virtual void HandleEndOfVideo()
   {
     Crash("Unexpected event!", __func__);
   }
 
-  virtual RefPtr<MediaDecoder::SeekPromise> HandleSeek(SeekTarget aTarget);
+  virtual RefPtr<MediaDecoder::SeekPromise> HandleSeek(SeekTarget aTarget)
+  {
+    return mSeekHandler->HandleSeek(aTarget);
+  }
 
   virtual RefPtr<ShutdownPromise> HandleShutdown();
 
   virtual void HandleVideoSuspendTimeout() = 0;
 
   virtual void HandleResumeVideoDecoding();
 
   virtual void HandlePlayStateChanged(MediaDecoder::PlayState aPlayState) {}
@@ -262,17 +336,17 @@ private:
 protected:
   enum class EventVisibility : int8_t
   {
     Observable,
     Suppressed
   };
 
   using Master = MediaDecoderStateMachine;
-  explicit StateObject(Master* aPtr) : mMaster(aPtr) {}
+  explicit StateObject(Master* aPtr) : mMaster(aPtr), mSeekHandler(new DefaultSeekHandler(this)) {}
   TaskQueue* OwnerThread() const { return mMaster->mTaskQueue; }
   MediaResource* Resource() const { return mMaster->mResource; }
   MediaDecoderReaderWrapper* Reader() const { return mMaster->mReader; }
   const MediaInfo& Info() const { return mMaster->Info(); }
   bool IsExpectingMoreData() const
   {
     // We are expecting more data if either the resource states so, or if we
     // have a waiting promise pending (such as with non-MSE EME).
@@ -307,31 +381,36 @@ protected:
   }
 
   RefPtr<MediaDecoder::SeekPromise>
   SetSeekingState(SeekJob&& aSeekJob, EventVisibility aVisibility);
 
   // Take a raw pointer in order not to change the life cycle of MDSM.
   // It is guaranteed to be valid by MDSM.
   Master* mMaster;
+
+  UniquePtr<SeekHandler> mSeekHandler;
 };
 
 /**
  * Purpose: decode metadata like duration and dimensions of the media resource.
  *
  * Transition to other states when decoding metadata is done:
  *   SHUTDOWN if failing to decode metadata.
  *   WAIT_FOR_CDM if the media is encrypted and CDM is not available.
  *   DECODING_FIRSTFRAME otherwise.
  */
 class MediaDecoderStateMachine::DecodeMetadataState
   : public MediaDecoderStateMachine::StateObject
 {
 public:
-  explicit DecodeMetadataState(Master* aPtr) : StateObject(aPtr) { }
+  explicit DecodeMetadataState(Master* aPtr) : StateObject(aPtr)
+  {
+    mSeekHandler.reset(new RejectSeekHandler(this));
+  }
 
   void Enter()
   {
     MOZ_ASSERT(!mMaster->mVideoDecodeSuspended);
     MOZ_ASSERT(!mMetadataRequest.Exists());
     SLOG("Dispatching AsyncReadMetadata");
 
     // Set mode to METADATA since we are about to read metadata.
@@ -355,22 +434,16 @@ public:
     mMetadataRequest.DisconnectIfExists();
   }
 
   State GetState() const override
   {
     return DECODER_STATE_DECODING_METADATA;
   }
 
-  RefPtr<MediaDecoder::SeekPromise> HandleSeek(SeekTarget aTarget) override
-  {
-    MOZ_DIAGNOSTIC_ASSERT(false, "Can't seek while decoding metadata.");
-    return MediaDecoder::SeekPromise::CreateAndReject(true, __func__);
-  }
-
   void HandleVideoSuspendTimeout() override
   {
     // Do nothing since no decoders are created yet.
   }
 
   void HandleResumeVideoDecoding() override
   {
     // We never suspend video decoding in this state.
@@ -396,58 +469,43 @@ private:
  * Transition to other states when CDM is ready:
  *   SEEKING if any pending seek request.
  *   DECODING_FIRSTFRAME otherwise.
  */
 class MediaDecoderStateMachine::WaitForCDMState
   : public MediaDecoderStateMachine::StateObject
 {
 public:
-  explicit WaitForCDMState(Master* aPtr) : StateObject(aPtr) { }
+  explicit WaitForCDMState(Master* aPtr) : StateObject(aPtr)
+  {
+    mSeekHandler.reset(new PendingSeekHandler(this));
+  }
 
   void Enter()
   {
     MOZ_ASSERT(!mMaster->mVideoDecodeSuspended);
   }
 
-  void Exit() override
-  {
-    // mPendingSeek is either moved in HandleCDMProxyReady() or should be
-    // rejected here before transition to SHUTDOWN.
-    mPendingSeek.RejectIfExists(__func__);
-  }
-
   State GetState() const override
   {
     return DECODER_STATE_WAIT_FOR_CDM;
   }
 
   void HandleCDMProxyReady() override;
 
-  RefPtr<MediaDecoder::SeekPromise> HandleSeek(SeekTarget aTarget) override
-  {
-    SLOG("Not Enough Data to seek at this stage, queuing seek");
-    mPendingSeek.RejectIfExists(__func__);
-    mPendingSeek.mTarget.emplace(aTarget);
-    return mPendingSeek.mPromise.Ensure(__func__);
-  }
-
   void HandleVideoSuspendTimeout() override
   {
     // Do nothing since no decoders are created yet.
   }
 
   void HandleResumeVideoDecoding() override
   {
     // We never suspend video decoding in this state.
     MOZ_ASSERT(false, "Shouldn't have suspended video decoding.");
   }
-
-private:
-  SeekJob mPendingSeek;
 };
 
 /**
  * Purpose: release decoder resources to save memory and hardware resources.
  *
  * Transition to:
  *   SEEKING if any seek request or play state changes to PLAYING.
  */
@@ -512,27 +570,26 @@ private:
  *   SHUTDOWN if any decode error.
  *   SEEKING if any seek request.
  *   DECODING when the 'loadeddata' event is fired.
  */
 class MediaDecoderStateMachine::DecodingFirstFrameState
   : public MediaDecoderStateMachine::StateObject
 {
 public:
-  explicit DecodingFirstFrameState(Master* aPtr) : StateObject(aPtr) { }
+  explicit DecodingFirstFrameState(Master* aPtr) : StateObject(aPtr)
+  {
+    // Delay seek request until decoding first frames for non-MSE media.
+    if (!mMaster->mIsMSE) {
+      mSeekHandler.reset(new PendingSeekHandler(this));
+    }
+  }
 
   void Enter();
 
-  void Exit() override
-  {
-    // mPendingSeek is either moved in MaybeFinishDecodeFirstFrame()
-    // or should be rejected here before transition to SHUTDOWN.
-    mPendingSeek.RejectIfExists(__func__);
-  }
-
   State GetState() const override
   {
     return DECODER_STATE_DECODING_FIRSTFRAME;
   }
 
   void HandleAudioDecoded(MediaData* aAudio) override
   {
     mMaster->PushAudio(aAudio);
@@ -594,34 +651,21 @@ public:
   }
 
   void HandleResumeVideoDecoding() override
   {
     // We never suspend video decoding in this state.
     MOZ_ASSERT(false, "Shouldn't have suspended video decoding.");
   }
 
-  RefPtr<MediaDecoder::SeekPromise> HandleSeek(SeekTarget aTarget) override
-  {
-    if (mMaster->mIsMSE) {
-      return StateObject::HandleSeek(aTarget);
-    }
-    // Delay seek request until decoding first frames for non-MSE media.
-    SLOG("Not Enough Data to seek at this stage, queuing seek");
-    mPendingSeek.RejectIfExists(__func__);
-    mPendingSeek.mTarget.emplace(aTarget);
-    return mPendingSeek.mPromise.Ensure(__func__);
-  }
 
 private:
   // Notify FirstFrameLoaded if having decoded first frames and
   // transition to SEEKING if there is any pending seek, or DECODING otherwise.
   void MaybeFinishDecodeFirstFrame();
-
-  SeekJob mPendingSeek;
 };
 
 /**
  * Purpose: decode audio/video data for playback.
  *
  * Transition to:
  *   DORMANT if playback is paused for a while.
  *   SEEKING if any seek request.
@@ -1865,36 +1909,33 @@ private:
  *
  * Transition from:
  *   Any states other than SHUTDOWN.
  */
 class MediaDecoderStateMachine::ShutdownState
   : public MediaDecoderStateMachine::StateObject
 {
 public:
-  explicit ShutdownState(Master* aPtr) : StateObject(aPtr) { }
+  explicit ShutdownState(Master* aPtr) : StateObject(aPtr)
+  {
+    mSeekHandler.reset(new RejectSeekHandler(this));
+  }
 
   RefPtr<ShutdownPromise> Enter();
 
   void Exit() override
   {
     MOZ_DIAGNOSTIC_ASSERT(false, "Shouldn't escape the SHUTDOWN state.");
   }
 
   State GetState() const override
   {
     return DECODER_STATE_SHUTDOWN;
   }
 
-  RefPtr<MediaDecoder::SeekPromise> HandleSeek(SeekTarget aTarget) override
-  {
-    MOZ_DIAGNOSTIC_ASSERT(false, "Can't seek in shutdown state.");
-    return MediaDecoder::SeekPromise::CreateAndReject(true, __func__);
-  }
-
   RefPtr<ShutdownPromise> HandleShutdown() override
   {
     MOZ_DIAGNOSTIC_ASSERT(false, "Already shutting down.");
     return nullptr;
   }
 
   void HandleVideoSuspendTimeout() override
   {
@@ -1902,25 +1943,16 @@ public:
   }
 
   void HandleResumeVideoDecoding() override
   {
     MOZ_DIAGNOSTIC_ASSERT(false, "Already shutting down.");
   }
 };
 
-RefPtr<MediaDecoder::SeekPromise>
-MediaDecoderStateMachine::
-StateObject::HandleSeek(SeekTarget aTarget)
-{
-  SLOG("Changed state to SEEKING (to %lld)", aTarget.GetTime().ToMicroseconds());
-  SeekJob seekJob;
-  seekJob.mTarget = Some(aTarget);
-  return SetSeekingState(Move(seekJob), EventVisibility::Observable);
-}
 
 RefPtr<ShutdownPromise>
 MediaDecoderStateMachine::
 StateObject::HandleShutdown()
 {
   return SetState<ShutdownState>();
 }
 
@@ -2075,18 +2107,18 @@ DormantState::HandlePlayStateChanged(Med
     SetSeekingState(Move(mPendingSeek), EventVisibility::Suppressed);
   }
 }
 
 void
 MediaDecoderStateMachine::
 WaitForCDMState::HandleCDMProxyReady()
 {
-  if (mPendingSeek.Exists()) {
-    SetSeekingState(Move(mPendingSeek), EventVisibility::Observable);
+  if (mSeekHandler->PendingSeekExist()) {
+    mSeekHandler->SwitchToSeekingState();
   } else {
     SetState<DecodingFirstFrameState>();
   }
 }
 
 void
 MediaDecoderStateMachine::
 DecodingFirstFrameState::Enter()
@@ -2115,18 +2147,18 @@ DecodingFirstFrameState::MaybeFinishDeco
   MOZ_ASSERT(!mMaster->mSentFirstFrameLoadedEvent);
 
   if ((mMaster->IsAudioDecoding() && AudioQueue().GetSize() == 0)
       || (mMaster->IsVideoDecoding() && VideoQueue().GetSize() == 0)) {
     return;
   }
 
   mMaster->FinishDecodeFirstFrame();
-  if (mPendingSeek.Exists()) {
-    SetSeekingState(Move(mPendingSeek), EventVisibility::Observable);
+  if (mSeekHandler->PendingSeekExist()) {
+    mSeekHandler->SwitchToSeekingState();
   } else {
     SetState<DecodingState>();
   }
 }
 
 void
 MediaDecoderStateMachine::
 DecodingState::Enter()