Bug 1300956. Part 1 - Add declarations of the state objects of MDSM. Also implement DecodeMetadataState. draft
authorJW Wang <jwwang@mozilla.com>
Tue, 06 Sep 2016 11:01:57 +0800
changeset 411520 3b3dafc50923ecccc72df5a5186e7d2e1cc7a712
parent 411418 6724fb8e33263e539cba8ce108577e86b3a83b2e
child 411521 aeb66600ae0c3d39e7b8ff257771a5b14fb16026
push id28915
push userjwwang@mozilla.com
push dateThu, 08 Sep 2016 07:23:46 +0000
bugs1300956
milestone51.0a1
Bug 1300956. Part 1 - Add declarations of the state objects of MDSM. Also implement DecodeMetadataState. MozReview-Commit-ID: BRyi409rmn5
dom/media/MediaDecoderStateMachine.cpp
dom/media/MediaDecoderStateMachine.h
--- a/dom/media/MediaDecoderStateMachine.cpp
+++ b/dom/media/MediaDecoderStateMachine.cpp
@@ -199,16 +199,51 @@ static void InitVideoQueuePrefs() {
 // decoding is suspended.
 static TimeDuration
 SuspendBackgroundVideoDelay()
 {
   return TimeDuration::FromMilliseconds(
     MediaPrefs::MDSMSuspendBackgroundVideoDelay());
 }
 
+class MediaDecoderStateMachine::StateObject
+{
+public:
+  virtual ~StateObject() {}
+  virtual void Enter() {}; // Entry action.
+  virtual void Exit() {};  // Exit action.
+  virtual void Step() {}   // Perform a 'cycle' of this state object.
+  virtual State GetState() const = 0;
+
+protected:
+  using Master = MediaDecoderStateMachine;
+  explicit StateObject(Master* aPtr) : mMaster(aPtr) {}
+
+  // Take a raw pointer in order not to change the life cycle of MDSM.
+  // It is guaranteed to be valid by MDSM.
+  Master* mMaster;
+};
+
+class MediaDecoderStateMachine::DecodeMetadataState
+  : public MediaDecoderStateMachine::StateObject
+{
+public:
+  explicit DecodeMetadataState(Master* aPtr) : StateObject(aPtr) {}
+
+  void Enter() override
+  {
+    mMaster->ReadMetadata();
+  }
+
+  State GetState() const override
+  {
+    return DECODER_STATE_DECODING_METADATA;
+  }
+};
+
 #define INIT_WATCHABLE(name, val) \
   name(val, "MediaDecoderStateMachine::" #name)
 #define INIT_MIRROR(name, val) \
   name(mTaskQueue, val, "MediaDecoderStateMachine::" #name " (Mirror)")
 #define INIT_CANONICAL(name, val) \
   name(mTaskQueue, val, "MediaDecoderStateMachine::" #name " (Canonical)")
 
 MediaDecoderStateMachine::MediaDecoderStateMachine(MediaDecoder* aDecoder,
@@ -218,16 +253,17 @@ MediaDecoderStateMachine::MediaDecoderSt
   mVideoFrameContainer(aDecoder->GetVideoFrameContainer()),
   mAudioChannel(aDecoder->GetAudioChannel()),
   mTaskQueue(new TaskQueue(GetMediaThreadPool(MediaThreadType::PLAYBACK),
                            /* aSupportsTailDispatch = */ true)),
   mWatchManager(this, mTaskQueue),
   mDispatchedStateMachine(false),
   mDelayedScheduler(mTaskQueue),
   INIT_WATCHABLE(mState, DECODER_STATE_DECODING_METADATA),
+  mStateObj(new DecodeMetadataState(this)),
   mCurrentFrameID(0),
   INIT_WATCHABLE(mObservedDuration, TimeUnit()),
   mFragmentEndTime(-1),
   mReader(new MediaDecoderReaderWrapper(mTaskQueue, aReader)),
   mDecodedAudioEndTime(0),
   mDecodedVideoEndTime(0),
   mPlaybackRate(1.0),
   mLowAudioThresholdUsecs(detail::LOW_AUDIO_USECS),
@@ -1060,43 +1096,64 @@ MediaDecoderStateMachine::SetState(State
   if (mState == aState) {
     return;
   }
 
   DECODER_LOG("MDSM state: %s -> %s", ToStateStr(), ToStateStr(aState));
 
   ExitState();
   mState = aState;
+
+  switch (mState) {
+    case DECODER_STATE_DECODING_METADATA:
+      mStateObj = MakeUnique<DecodeMetadataState>(this);
+      break;
+    default:
+      mStateObj = nullptr;
+      break;
+  }
+
   EnterState();
 }
 
 void
 MediaDecoderStateMachine::ExitState()
 {
   MOZ_ASSERT(OnTaskQueue());
+
+  if (mStateObj) {
+    MOZ_ASSERT(mState == mStateObj->GetState());
+    mStateObj->Exit();
+    return;
+  }
+
   switch (mState) {
     case DECODER_STATE_COMPLETED:
       mSentPlaybackEndedEvent = false;
       break;
     case DECODER_STATE_SHUTDOWN:
       MOZ_DIAGNOSTIC_ASSERT(false, "Shouldn't escape the SHUTDOWN state.");
       break;
     default:
       break;
   }
 }
 
 void
 MediaDecoderStateMachine::EnterState()
 {
   MOZ_ASSERT(OnTaskQueue());
+
+  if (mStateObj) {
+    MOZ_ASSERT(mState == mStateObj->GetState());
+    mStateObj->Enter();
+    return;
+  }
+
   switch (mState) {
-    case DECODER_STATE_DECODING_METADATA:
-      ReadMetadata();
-      break;
     case DECODER_STATE_DORMANT:
       DiscardSeekTaskIfExist();
       if (IsPlaying()) {
         StopPlayback();
       }
       Reset();
       mReader->ReleaseResources();
       break;
@@ -2258,16 +2315,21 @@ MediaDecoderStateMachine::FinishShutdown
 void
 MediaDecoderStateMachine::RunStateMachine()
 {
   MOZ_ASSERT(OnTaskQueue());
 
   mDelayedScheduler.Reset(); // Must happen on state machine task queue.
   mDispatchedStateMachine = false;
 
+  if (mStateObj) {
+    mStateObj->Step();
+    return;
+  }
+
   switch (mState) {
     case DECODER_STATE_DECODING:
       StepDecoding();
       return;
     case DECODER_STATE_BUFFERING:
       StepBuffering();
       return;
     case DECODER_STATE_COMPLETED:
--- a/dom/media/MediaDecoderStateMachine.h
+++ b/dom/media/MediaDecoderStateMachine.h
@@ -246,16 +246,27 @@ public:
   MediaEventSource<MediaEventType>&
   OnPlaybackEvent() { return mOnPlaybackEvent; }
 
   size_t SizeOfVideoQueue() const;
 
   size_t SizeOfAudioQueue() const;
 
 private:
+  class StateObject;
+  class DecodeMetadataState;
+  class WaitForCDMState;
+  class DormantState;
+  class DecodingFirstFrameState;
+  class DecodingState;
+  class SeekingState;
+  class BufferingState;
+  class CompletedState;
+  class ShutdownState;
+
   static const char* ToStateStr(State aState);
   const char* ToStateStr();
 
   // Functions used by assertions to ensure we're calling things
   // on the appropriate threads.
   bool OnTaskQueue() const;
 
   // Initialization that needs to happen on the task queue. This is the first
@@ -598,16 +609,18 @@ private:
   // Queue of video frames. This queue is threadsafe, and is accessed from
   // the decoder, state machine, and main threads.
   MediaQueue<MediaData> mVideoQueue;
 
   // The decoder monitor must be obtained before modifying this state.
   // Accessed on state machine, audio, main, and AV thread.
   Watchable<State> mState;
 
+  UniquePtr<StateObject> mStateObj;
+
   // Time that buffering started. Used for buffering timeout and only
   // accessed on the state machine thread. This is null while we're not
   // buffering.
   TimeStamp mBufferingStart;
 
   media::TimeUnit Duration() const { MOZ_ASSERT(OnTaskQueue()); return mDuration.Ref().ref(); }
 
   // Recomputes the canonical duration from various sources.