Bug 1393336 - Remove WaitForCDM state from MDSM. draft
authorKilik Kuo <kikuo@mozilla.com>
Fri, 25 Aug 2017 17:11:14 +0800
changeset 653992 5031e7124c5842ce28d8dab8e01fae6c1e9eca6f
parent 642916 1d042bcb2632ea6a38fa08dbe21a6e8a0ee46961
child 728464 7b0f149e7741260bcc4c3437e991c0412127b586
push id76464
push userkikuo@mozilla.com
push dateMon, 28 Aug 2017 07:59:16 +0000
bugs1393336
milestone57.0a1
Bug 1393336 - Remove WaitForCDM state from MDSM. MozReview-Commit-ID: 7XofvBZTerH
dom/media/MediaDecoder.cpp
dom/media/MediaDecoder.h
dom/media/MediaDecoderStateMachine.cpp
dom/media/MediaDecoderStateMachine.h
dom/media/MediaFormatReader.cpp
--- a/dom/media/MediaDecoder.cpp
+++ b/dom/media/MediaDecoder.cpp
@@ -357,17 +357,16 @@ MediaDecoder::IsInfinite() const
   name(mOwner->AbstractMainThread(), val, "MediaDecoder::" #name " (Mirror)")
 #define INIT_CANONICAL(name, val) \
   name(mOwner->AbstractMainThread(), val, "MediaDecoder::" #name " (Canonical)")
 
 MediaDecoder::MediaDecoder(MediaDecoderInit& aInit)
   : mWatchManager(this, aInit.mOwner->AbstractMainThread())
   , mLogicalPosition(0.0)
   , mDuration(std::numeric_limits<double>::quiet_NaN())
-  , mCDMProxyPromise(mCDMProxyPromiseHolder.Ensure(__func__))
   , mOwner(aInit.mOwner)
   , mAbstractMainThread(aInit.mOwner->AbstractMainThread())
   , mFrameStats(new FrameStatistics())
   , mVideoFrameContainer(aInit.mOwner->GetVideoFrameContainer())
   , mPinnedForSeek(false)
   , mAudioChannel(aInit.mAudioChannel)
   , mMinimizePreroll(aInit.mMinimizePreroll)
   , mFiredMetadataLoaded(false)
@@ -435,18 +434,16 @@ MediaDecoder::Shutdown()
   MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
   AbstractThread::AutoEnter context(AbstractMainThread());
 
   UnpinForSeek();
 
   // Unwatch all watch targets to prevent further notifications.
   mWatchManager.Shutdown();
 
-  mCDMProxyPromiseHolder.RejectIfExists(true, __func__);
-
   DiscardOngoingSeekIfExists();
 
   // This changes the decoder state to SHUTDOWN and does other things
   // necessary to unblock the state machine thread if it's blocked, so
   // the asynchronous shutdown in nsDestroyStateMachine won't deadlock.
   if (mDecoderStateMachine) {
     mTimedMetadataListener.Disconnect();
     mMetadataLoadedListener.Disconnect();
@@ -1446,29 +1443,28 @@ MediaDecoder::CanPlayThrough()
   bool val = CanPlayThroughImpl();
   if (val != mCanPlayThrough) {
     mCanPlayThrough = val;
     mDecoderStateMachine->DispatchCanPlayThrough(val);
   }
   return val;
 }
 
-RefPtr<MediaDecoder::CDMProxyPromise>
-MediaDecoder::RequestCDMProxy() const
-{
-  return mCDMProxyPromise;
-}
-
 void
 MediaDecoder::SetCDMProxy(CDMProxy* aProxy)
 {
   MOZ_ASSERT(NS_IsMainThread());
-  MOZ_ASSERT(aProxy);
-
-  mCDMProxyPromiseHolder.ResolveIfExists(aProxy, __func__);
+  RefPtr<CDMProxy> proxy = aProxy;
+  RefPtr<MediaFormatReader> reader = mReader;
+  nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction(
+    "MediaFormatReader::SetCDMProxy",
+    [reader, proxy]() {
+    reader->SetCDMProxy(proxy);
+    });
+  mReader->OwnerThread()->Dispatch(r.forget());
 }
 
 bool
 MediaDecoder::IsOpusEnabled()
 {
   return Preferences::GetBool("media.opus.enabled");
 }
 
--- a/dom/media/MediaDecoder.h
+++ b/dom/media/MediaDecoder.h
@@ -373,24 +373,16 @@ private:
 
   MediaDecoderOwner* GetOwner() const;
 
   AbstractThread* AbstractMainThread() const
   {
     return mAbstractMainThread;
   }
 
-  typedef MozPromise<RefPtr<CDMProxy>, bool /* aIgnored */,
-                     /* IsExclusive = */ true>
-    CDMProxyPromise;
-
-  // Resolved when a CDMProxy is available and the capabilities are known or
-  // rejected when this decoder is about to shut down.
-  RefPtr<CDMProxyPromise> RequestCDMProxy() const;
-
   void SetCDMProxy(CDMProxy* aProxy);
 
   void EnsureTelemetryReported();
 
   static bool IsOggEnabled();
   static bool IsOpusEnabled();
   static bool IsWaveEnabled();
   static bool IsWebMEnabled();
@@ -525,19 +517,16 @@ private:
   // call methods of this object from other threads. Its internal data
   // is synchronised on a monitor. The lifetime of this object is
   // after mPlayState is LOADING and before mPlayState is SHUTDOWN. It
   // is safe to access it during this period.
   //
   // Explicitly prievate to force access via accessors.
   RefPtr<MediaDecoderStateMachine> mDecoderStateMachine;
 
-  MozPromiseHolder<CDMProxyPromise> mCDMProxyPromiseHolder;
-  RefPtr<CDMProxyPromise> mCDMProxyPromise;
-
 protected:
   void NotifyDataArrivedInternal();
   void DiscardOngoingSeekIfExists();
   virtual void CallSeek(const SeekTarget& aTarget);
 
   // Called to notify fetching media data is in progress.
   // Called on the main thread only.
   virtual void DownloadProgressed();
--- a/dom/media/MediaDecoderStateMachine.cpp
+++ b/dom/media/MediaDecoderStateMachine.cpp
@@ -174,17 +174,16 @@ class MediaDecoderStateMachine::StateObj
 {
 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() { }
   virtual void HandleAudioCaptured() { }
   virtual void HandleAudioDecoded(AudioData* aAudio)
   {
     Crash("Unexpected event!", __func__);
   }
   virtual void HandleVideoDecoded(VideoData* aVideo, TimeStamp aDecodeStart)
   {
     Crash("Unexpected event!", __func__);
@@ -321,17 +320,16 @@ protected:
   Master* mMaster;
 };
 
 /**
  * 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) { }
 
@@ -387,68 +385,16 @@ private:
     SLOGW("Decode metadata failed, shutting down decoder");
     mMaster->DecodeError(aError);
   }
 
   MozPromiseRequestHolder<MediaFormatReader::MetadataPromise> mMetadataRequest;
 };
 
 /**
- * Purpose: wait for the CDM to start decoding.
- *
- * 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) { }
-
-  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(const TimeUnit&) 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.
  */
 class MediaDecoderStateMachine::DormantState
   : public MediaDecoderStateMachine::StateObject
 {
@@ -2254,50 +2200,32 @@ DecodeMetadataState::OnMetadataRead(Meta
 
   MOZ_ASSERT(mMaster->mDuration.Ref().isSome());
 
   mMaster->mMetadataLoadedEvent.Notify(
     Move(aMetadata.mInfo),
     Move(aMetadata.mTags),
     MediaDecoderEventVisibility::Observable);
 
-  if (Info().IsEncrypted() && !mMaster->mCDMProxy) {
-    // 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>();
-  } else {
-    SetState<DecodingFirstFrameState>();
-  }
+  SetState<DecodingFirstFrameState>();
 }
 
 void
 MediaDecoderStateMachine::
 DormantState::HandlePlayStateChanged(MediaDecoder::PlayState aPlayState)
 {
   if (aPlayState == MediaDecoder::PLAY_STATE_PLAYING) {
     // Exit dormant when the user wants to play.
-    MOZ_ASSERT(!Info().IsEncrypted() || mMaster->mCDMProxy);
     MOZ_ASSERT(mMaster->mSentFirstFrameLoadedEvent);
     SetSeekingState(Move(mPendingSeek), EventVisibility::Suppressed);
   }
 }
 
 void
 MediaDecoderStateMachine::
-WaitForCDMState::HandleCDMProxyReady()
-{
-  if (mPendingSeek.Exists()) {
-    SetSeekingState(Move(mPendingSeek), EventVisibility::Observable);
-  } else {
-    SetState<DecodingFirstFrameState>();
-  }
-}
-
-void
-MediaDecoderStateMachine::
 DecodingFirstFrameState::Enter()
 {
   // Transition to DECODING if we've decoded first frames.
   if (mMaster->mSentFirstFrameLoadedEvent) {
     SetState<DecodingState>();
     return;
   }
 
@@ -2637,18 +2565,16 @@ ShutdownState::Enter()
   auto master = mMaster;
 
   master->mDelayedScheduler.Reset();
 
   // Shutdown happens while decode timer is active, we need to disconnect and
   // dispose of the timer.
   master->CancelSuspendTimer();
 
-  master->mCDMProxyPromise.DisconnectIfExists();
-
   if (master->IsPlaying()) {
     master->StopPlayback();
   }
 
   master->mAudioDataRequest.DisconnectIfExists();
   master->mVideoDataRequest.DisconnectIfExists();
   master->mAudioWaitRequest.DisconnectIfExists();
   master->mVideoWaitRequest.DisconnectIfExists();
@@ -2930,22 +2856,16 @@ nsresult MediaDecoderStateMachine::Init(
 
   mMetadataManager.Connect(mReader->TimedMetadataEvent(), OwnerThread());
 
   mOnMediaNotSeekable = mReader->OnMediaNotSeekable().Connect(
     OwnerThread(), this, &MediaDecoderStateMachine::SetMediaNotSeekable);
 
   mMediaSink = CreateMediaSink(mAudioCaptured);
 
-  aDecoder->RequestCDMProxy()->Then(
-    OwnerThread(), __func__, this,
-    &MediaDecoderStateMachine::OnCDMProxyReady,
-    &MediaDecoderStateMachine::OnCDMProxyNotReady)
-  ->Track(mCDMProxyPromise);
-
   nsresult rv = mReader->Init();
   NS_ENSURE_SUCCESS(rv, rv);
 
   mReader->SetCanonicalDuration(&mDuration);
 
   return NS_OK;
 }
 
@@ -3036,17 +2956,16 @@ MediaDecoderStateMachine::UpdatePlayback
   }
 }
 
 /* static */ const char*
 MediaDecoderStateMachine::ToStateStr(State aState)
 {
   switch (aState) {
     case DECODER_STATE_DECODING_METADATA:   return "DECODING_METADATA";
-    case DECODER_STATE_WAIT_FOR_CDM:        return "WAIT_FOR_CDM";
     case DECODER_STATE_DORMANT:             return "DORMANT";
     case DECODER_STATE_DECODING_FIRSTFRAME: return "DECODING_FIRSTFRAME";
     case DECODER_STATE_DECODING:            return "DECODING";
     case DECODER_STATE_SEEKING:             return "SEEKING";
     case DECODER_STATE_BUFFERING:           return "BUFFERING";
     case DECODER_STATE_COMPLETED:           return "COMPLETED";
     case DECODER_STATE_SHUTDOWN:            return "SHUTDOWN";
     default: MOZ_ASSERT_UNREACHABLE("Invalid state.");
@@ -3780,33 +3699,16 @@ void MediaDecoderStateMachine::OnMediaSi
   }
 
   // Otherwise notify media decoder/element about this error for it makes
   // no sense to play an audio-only file without sound output.
   DecodeError(MediaResult(NS_ERROR_DOM_MEDIA_MEDIASINK_ERR, __func__));
 }
 
 void
-MediaDecoderStateMachine::OnCDMProxyReady(RefPtr<CDMProxy> aProxy)
-{
-  MOZ_ASSERT(OnTaskQueue());
-  mCDMProxyPromise.Complete();
-  mCDMProxy = aProxy;
-  mReader->SetCDMProxy(aProxy);
-  mStateObj->HandleCDMProxyReady();
-}
-
-void
-MediaDecoderStateMachine::OnCDMProxyNotReady()
-{
-  MOZ_ASSERT(OnTaskQueue());
-  mCDMProxyPromise.Complete();
-}
-
-void
 MediaDecoderStateMachine::SetAudioCaptured(bool aCaptured)
 {
   MOZ_ASSERT(OnTaskQueue());
 
   if (aCaptured == mAudioCaptured) {
     return;
   }
 
--- a/dom/media/MediaDecoderStateMachine.h
+++ b/dom/media/MediaDecoderStateMachine.h
@@ -158,17 +158,16 @@ public:
   MediaDecoderStateMachine(MediaDecoder* aDecoder, MediaFormatReader* aReader);
 
   nsresult Init(MediaDecoder* aDecoder);
 
   // Enumeration for the valid decoding states
   enum State
   {
     DECODER_STATE_DECODING_METADATA,
-    DECODER_STATE_WAIT_FOR_CDM,
     DECODER_STATE_DORMANT,
     DECODER_STATE_DECODING_FIRSTFRAME,
     DECODER_STATE_DECODING,
     DECODER_STATE_SEEKING,
     DECODER_STATE_BUFFERING,
     DECODER_STATE_COMPLETED,
     DECODER_STATE_SHUTDOWN
   };
@@ -253,17 +252,16 @@ public:
   size_t SizeOfAudioQueue() const;
 
   // Sets the video decode mode. Used by the suspend-video-decoder feature.
   void SetVideoDecodeMode(VideoDecodeMode aMode);
 
 private:
   class StateObject;
   class DecodeMetadataState;
-  class WaitForCDMState;
   class DormantState;
   class DecodingFirstFrameState;
   class DecodingState;
   class SeekingState;
   class AccurateSeekingState;
   class NextFrameSeekingState;
   class NextFrameSeekingFromDormantState;
   class VideoOnlySeekingState;
@@ -655,21 +653,16 @@ private:
   MediaEventProducerExc<nsAutoPtr<MediaInfo>,
                         MediaDecoderEventVisibility> mFirstFrameLoadedEvent;
 
   MediaEventProducer<MediaEventType> mOnPlaybackEvent;
   MediaEventProducer<MediaResult> mOnPlaybackErrorEvent;
 
   MediaEventProducer<DecoderDoctorEvent> mOnDecoderDoctorEvent;
 
-  void OnCDMProxyReady(RefPtr<CDMProxy> aProxy);
-  void OnCDMProxyNotReady();
-  RefPtr<CDMProxy> mCDMProxy;
-  MozPromiseRequestHolder<MediaDecoder::CDMProxyPromise> mCDMProxyPromise;
-
   const bool mIsMSE;
 
 private:
   // The buffered range. Mirrored from the decoder thread.
   Mirror<media::TimeIntervals> mBuffered;
 
   // The current play state, mirrored from the main thread.
   Mirror<MediaDecoder::PlayState> mPlayState;
--- a/dom/media/MediaFormatReader.cpp
+++ b/dom/media/MediaFormatReader.cpp
@@ -1233,16 +1233,22 @@ void
 MediaFormatReader::SetCDMProxy(CDMProxy* aProxy)
 {
   RefPtr<CDMProxy> proxy = aProxy;
   RefPtr<MediaFormatReader> self = this;
   nsCOMPtr<nsIRunnable> r =
     NS_NewRunnableFunction("MediaFormatReader::SetCDMProxy", [=]() {
       MOZ_ASSERT(self->OnTaskQueue());
       self->mCDMProxy = proxy;
+      if (HasAudio()) {
+        self->ScheduleUpdate(TrackInfo::kAudioTrack);
+      }
+      if (HasVideo()) {
+        self->ScheduleUpdate(TrackInfo::kVideoTrack);
+      }
     });
   OwnerThread()->Dispatch(r.forget());
 }
 
 bool
 MediaFormatReader::IsWaitingOnCDMResource()
 {
   MOZ_ASSERT(OnTaskQueue());
@@ -2337,16 +2343,22 @@ MediaFormatReader::Update(TrackType aTra
        decoder.mFlushing,
        decoder.mDescription,
        uint32_t(decoder.mOutput.Length()),
        decoder.mWaitingForData,
        decoder.mDemuxEOS,
        int32_t(decoder.mDrainState),
        decoder.mLastStreamSourceID);
 
+  if (IsWaitingOnCDMResource()) {
+    // If the content is encrypted, MFR won't start to create decoder until
+    // CDMProxy is set.
+    return;
+  }
+
   if ((decoder.mWaitingForData
        && (!decoder.mTimeThreshold || decoder.mTimeThreshold.ref().mWaiting))
       || (decoder.mWaitingForKey && decoder.mDecodeRequest.Exists())) {
     // Nothing more we can do at present.
     LOGV("Still waiting for data or key.");
     return;
   }