Bug 1345403 part 4 - Clean up suspend timer canceling; r?jwwang draft
authorKaku Kuo <kaku@mozilla.com>
Wed, 08 Mar 2017 21:28:01 +0800
changeset 497392 c83c34d4b9b8984628b7df5af0e0bf58d80e947e
parent 497391 dd17e717d4753bbafdecbe8df0ea27fce2537e71
child 497393 c5c4911b892f0125f1a5621ae327b044b960d83d
push id48886
push userbmo:kaku@mozilla.com
push dateMon, 13 Mar 2017 08:40:05 +0000
reviewersjwwang
bugs1345403
milestone55.0a1
Bug 1345403 part 4 - Clean up suspend timer canceling; r?jwwang MozReview-Commit-ID: LuNmrtDl4BR
dom/media/MediaDecoder.cpp
dom/media/MediaDecoderStateMachine.cpp
dom/media/MediaDecoderStateMachine.h
--- a/dom/media/MediaDecoder.cpp
+++ b/dom/media/MediaDecoder.cpp
@@ -572,16 +572,21 @@ MediaDecoder::OnPlaybackEvent(MediaEvent
       Invalidate();
       break;
     case MediaEventType::EnterVideoSuspend:
       GetOwner()->DispatchAsyncEvent(NS_LITERAL_STRING("mozentervideosuspend"));
       break;
     case MediaEventType::ExitVideoSuspend:
       GetOwner()->DispatchAsyncEvent(NS_LITERAL_STRING("mozexitvideosuspend"));
       break;
+    case MediaEventType::StartVideoSuspendTimer:
+      GetOwner()->DispatchAsyncEvent(NS_LITERAL_STRING("mozstartvideosuspendtimer"));
+      break;
+    case MediaEventType::CancelVideoSuspendTimer:
+      GetOwner()->DispatchAsyncEvent(NS_LITERAL_STRING("mozcancelvideosuspendtimer"));
   }
 }
 
 void
 MediaDecoder::OnPlaybackErrorEvent(const MediaResult& aError)
 {
   DecodeError(aError);
 }
--- a/dom/media/MediaDecoderStateMachine.cpp
+++ b/dom/media/MediaDecoderStateMachine.cpp
@@ -2515,17 +2515,17 @@ ShutdownState::Enter()
 {
   auto master = mMaster;
 
   master->mIsShutdown = true;
   master->mDelayedScheduler.Reset();
 
   // Shutdown happens while decode timer is active, we need to disconnect and
   // dispose of the timer.
-  master->mVideoDecodeSuspendTimer.Reset();
+  master->CancelSuspendTimer();
 
   master->mCDMProxyPromise.DisconnectIfExists();
 
   if (master->IsPlaying()) {
     master->StopPlayback();
   }
 
   master->mAudioDataRequest.DisconnectIfExists();
@@ -2695,16 +2695,18 @@ MediaDecoderStateMachine::Initialization
                       &MediaDecoderStateMachine::RecomputeDuration);
   mWatchManager.Watch(mPlayState, &MediaDecoderStateMachine::PlayStateChanged);
 
   if (MediaPrefs::MDSMSuspendBackgroundVideoEnabled()) {
     mIsVisible.Connect(aDecoder->CanonicalIsVisible());
     mHasSuspendTaint.Connect(aDecoder->CanonicalHasSuspendTaint());
     mWatchManager.Watch(mIsVisible,
                         &MediaDecoderStateMachine::VisibilityChanged);
+    mWatchManager.Watch(mHasSuspendTaint,
+                        &MediaDecoderStateMachine::SuspendTaintChanged);
   }
 
   MOZ_ASSERT(!mStateObj);
   auto* s = new DecodeMetadataState(this);
   mStateObj.reset(s);
   s->Enter();
 }
 
@@ -3009,17 +3011,17 @@ MediaDecoderStateMachine::Shutdown()
   return mStateObj->HandleShutdown();
 }
 
 void MediaDecoderStateMachine::PlayStateChanged()
 {
   MOZ_ASSERT(OnTaskQueue());
 
   if (mPlayState != MediaDecoder::PLAY_STATE_PLAYING) {
-    mVideoDecodeSuspendTimer.Reset();
+    CancelSuspendTimer();
   } else if (mMinimizePreroll) {
     // Once we start playing, we don't want to minimize our prerolling, as we
     // assume the user is likely to want to keep playing in future. This needs
     // to happen before we invoke StartDecoding().
     mMinimizePreroll = false;
   }
 
   mStateObj->HandlePlayStateChanged(mPlayState);
@@ -3033,25 +3035,39 @@ void MediaDecoderStateMachine::Visibilit
 
   // Start timer to trigger suspended decoding state when going invisible.
   if (!mIsVisible) {
     TimeStamp target = TimeStamp::Now() + SuspendBackgroundVideoDelay();
 
     RefPtr<MediaDecoderStateMachine> self = this;
     mVideoDecodeSuspendTimer.Ensure(target,
                                     [=]() { self->OnSuspendTimerResolved(); },
-                                    [=]() { self->OnSuspendTimerRejected(); });
+                                    [] () { MOZ_DIAGNOSTIC_ASSERT(false); });
+    mOnPlaybackEvent.Notify(MediaEventType::StartVideoSuspendTimer);
     return;
   }
 
   // Resuming from suspended decoding
 
   // If suspend timer exists, destroy it.
-  mVideoDecodeSuspendTimer.Reset();
-
+  CancelSuspendTimer();
+
+  if (mVideoDecodeSuspended) {
+    mStateObj->HandleResumeVideoDecoding();
+  }
+}
+
+void MediaDecoderStateMachine::SuspendTaintChanged()
+{
+  MOZ_ASSERT(OnTaskQueue());
+  MOZ_ASSERT(mHasSuspendTaint); // Suspend taint is only ever set.
+
+  CancelSuspendTimer();
+
+  // Resume from suspended decoding.
   if (mVideoDecodeSuspended) {
     mStateObj->HandleResumeVideoDecoding();
   }
 }
 
 void MediaDecoderStateMachine::BufferedRangeUpdated()
 {
   MOZ_ASSERT(OnTaskQueue());
@@ -3904,19 +3920,23 @@ void
 MediaDecoderStateMachine::OnSuspendTimerResolved()
 {
   DECODER_LOG("OnSuspendTimerResolved");
   mVideoDecodeSuspendTimer.CompleteRequest();
   mStateObj->HandleVideoSuspendTimeout();
 }
 
 void
-MediaDecoderStateMachine::OnSuspendTimerRejected()
+MediaDecoderStateMachine::CancelSuspendTimer()
 {
-  DECODER_LOG("OnSuspendTimerRejected");
+  DECODER_LOG("CancelSuspendTimer: State: %s, Timer.IsScheduled: %c",
+              ToStateStr(mStateObj->GetState()),
+              mVideoDecodeSuspendTimer.IsScheduled() ? 'T' : 'F');
   MOZ_ASSERT(OnTaskQueue());
-  MOZ_ASSERT(!mVideoDecodeSuspended);
-  mVideoDecodeSuspendTimer.CompleteRequest();
+  if (mVideoDecodeSuspendTimer.IsScheduled()) {
+    mOnPlaybackEvent.Notify(MediaEventType::CancelVideoSuspendTimer);
+  }
+  mVideoDecodeSuspendTimer.Reset();
 }
 
 } // namespace mozilla
 
 #undef NS_DispatchToMainThread
--- a/dom/media/MediaDecoderStateMachine.h
+++ b/dom/media/MediaDecoderStateMachine.h
@@ -117,17 +117,19 @@ extern LazyLogModule gMediaSampleLog;
 enum class MediaEventType : int8_t
 {
   PlaybackStarted,
   PlaybackStopped,
   PlaybackEnded,
   SeekStarted,
   Invalidate,
   EnterVideoSuspend,
-  ExitVideoSuspend
+  ExitVideoSuspend,
+  StartVideoSuspendTimer,
+  CancelVideoSuspendTimer
 };
 
 /*
   The state machine class. This manages the decoding and seeking in the
   MediaDecoderReader on the decode task queue, and A/V sync on the shared
   state machine thread, and controls the audio "push" thread.
 
   All internal state is synchronised via the decoder monitor. State changes
@@ -389,16 +391,19 @@ protected:
   void StartMediaSink();
 
   // Notification method invoked when mPlayState changes.
   void PlayStateChanged();
 
   // Notification method invoked when mIsVisible changes.
   void VisibilityChanged();
 
+  // Notification method invoked when mHasSuspendTaint changes.
+  void SuspendTaintChanged();
+
   // Sets internal state which causes playback of media to pause.
   // The decoder monitor must be held.
   void StopPlayback();
 
   // If the conditions are right, sets internal state which causes playback
   // of media to begin or resume.
   // Must be called with the decode monitor held.
   void MaybeStartPlayback();
@@ -606,17 +611,17 @@ private:
   MozPromiseRequestHolder<MediaDataPromise> mVideoDataRequest;
   MozPromiseRequestHolder<WaitForDataPromise> mAudioWaitRequest;
   MozPromiseRequestHolder<WaitForDataPromise> mVideoWaitRequest;
 
   const char* AudioRequestStatus() const;
   const char* VideoRequestStatus() const;
 
   void OnSuspendTimerResolved();
-  void OnSuspendTimerRejected();
+  void CancelSuspendTimer();
 
   // True if we shouldn't play our audio (but still write it to any capturing
   // streams). When this is true, the audio thread will never start again after
   // it has stopped.
   bool mAudioCaptured;
 
   // True if all audio frames are already rendered.
   bool mAudioCompleted = false;