Bug 1311872. Part 3 - enter dormant when being paused for a while. r=cpearce,jya
authorJW Wang <jwwang@mozilla.com>
Thu, 20 Oct 2016 14:45:05 +0800
changeset 363632 80ee79d7a32a5bc2f811f067e6f63e72f71eb14c
parent 363631 1ed409c6df2f34d65febea744539e9a22901e1f1
child 363633 159aabd71aaae58c90bdb3fe5058a8426a5d26dc
push id6795
push userjlund@mozilla.com
push dateMon, 23 Jan 2017 14:19:46 +0000
treeherdermozilla-beta@76101b503191 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerscpearce, jya
bugs1311872
milestone52.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1311872. Part 3 - enter dormant when being paused for a while. r=cpearce,jya MozReview-Commit-ID: HJjhFebQ8WI
dom/media/MediaDecoderStateMachine.cpp
dom/media/MediaPrefs.h
modules/libpref/init/all.js
--- a/dom/media/MediaDecoderStateMachine.cpp
+++ b/dom/media/MediaDecoderStateMachine.cpp
@@ -557,26 +557,31 @@ private:
  *   SHUTDOWN if any decode error.
  *   BUFFERING if playback can't continue due to lack of decoded data.
  *   COMPLETED when having decoded all audio/video data.
  */
 class MediaDecoderStateMachine::DecodingState
   : public MediaDecoderStateMachine::StateObject
 {
 public:
-  explicit DecodingState(Master* aPtr) : StateObject(aPtr) {}
+  explicit DecodingState(Master* aPtr)
+    : StateObject(aPtr)
+    , mDormantTimer(OwnerThread())
+  {
+  }
 
   void Enter();
 
   void Exit() override
   {
     if (!mDecodeStartTime.IsNull()) {
       TimeDuration decodeDuration = TimeStamp::Now() - mDecodeStartTime;
       SLOG("Exiting DECODING, decoded for %.3lfs", decodeDuration.ToSeconds());
     }
+    mDormantTimer.Reset();
   }
 
   void Step() override
   {
     if (mMaster->mPlayState != MediaDecoder::PLAY_STATE_PLAYING &&
         mMaster->IsPlaying()) {
       // We're playing, but the element/decoder is in paused state. Stop
       // playing!
@@ -645,16 +650,22 @@ public:
   }
 
   void HandlePlayStateChanged(MediaDecoder::PlayState aPlayState) override
   {
     if (aPlayState == MediaDecoder::PLAY_STATE_PLAYING) {
       // Schedule Step() to check if we can start playback.
       mMaster->ScheduleStateMachine();
     }
+
+    if (aPlayState == MediaDecoder::PLAY_STATE_PAUSED) {
+      StartDormantTimer();
+    } else {
+      mDormantTimer.Reset();
+    }
   }
 
   void DumpDebugInfo() override
   {
     SDUMP("mIsPrerolling=%d", mIsPrerolling);
   }
 
 private:
@@ -711,27 +722,54 @@ private:
         (DonePrerollingAudio() || Reader()->IsWaitingAudioData()) &&
         (DonePrerollingVideo() || Reader()->IsWaitingVideoData())) {
       mIsPrerolling = false;
       // Check if we can start playback.
       mMaster->ScheduleStateMachine();
     }
   }
 
+  void StartDormantTimer()
+  {
+    auto timeout = MediaPrefs::DormantOnPauseTimeout();
+    if (timeout < 0) {
+      // Disabled when timeout is negative.
+      return;
+    } else if (timeout == 0) {
+      // Enter dormant immediately without scheduling a timer.
+      HandleDormant(true);
+      return;
+    }
+
+    TimeStamp target = TimeStamp::Now() +
+      TimeDuration::FromMilliseconds(timeout);
+
+    mDormantTimer.Ensure(target,
+      [this] () {
+        mDormantTimer.CompleteRequest();
+        HandleDormant(true);
+      }, [this] () {
+        mDormantTimer.CompleteRequest();
+      });
+  }
+
   // Time at which we started decoding.
   TimeStamp mDecodeStartTime;
 
   // When we start decoding (either for the first time, or after a pause)
   // we may be low on decoded data. We don't want our "low data" logic to
   // kick in and decide that we're low on decoded data because the download
   // can't keep up with the decode, and cause us to pause playback. So we
   // have a "preroll" stage, where we ignore the results of our "low data"
   // logic during the first few frames of our decode. This occurs during
   // playback.
   bool mIsPrerolling = true;
+
+  // Fired when playback is paused for a while to enter dormant.
+  DelayedScheduler mDormantTimer;
 };
 
 /**
  * Purpose: seek to a particular new playback position.
  *
  * Transition to:
  *   DORMANT if any dormant request.
  *   SEEKING if any new seek request.
@@ -1437,16 +1475,21 @@ DecodingState::Enter()
   mDecodeStartTime = TimeStamp::Now();
 
   MaybeStopPrerolling();
 
   // Ensure that we've got tasks enqueued to decode data if we need to.
   mMaster->DispatchDecodeTasksIfNeeded();
 
   mMaster->ScheduleStateMachine();
+
+  // Will enter dormant when playback is paused for a while.
+  if (mMaster->mPlayState == MediaDecoder::PLAY_STATE_PAUSED) {
+    StartDormantTimer();
+  }
 }
 
 RefPtr<MediaDecoder::SeekPromise>
 MediaDecoderStateMachine::
 DecodingState::HandleSeek(SeekTarget aTarget)
 {
   SLOG("Changed state to SEEKING (to %lld)", aTarget.GetTime().ToMicroseconds());
   SeekJob seekJob;
--- a/dom/media/MediaPrefs.h
+++ b/dom/media/MediaPrefs.h
@@ -131,16 +131,17 @@ private:
   DECL_MEDIA_PREF("media.decoder.fuzzing.dont-delay-inputexhausted", PDMFuzzingDelayInputExhausted, bool, true);
   DECL_MEDIA_PREF("media.gmp.decoder.enabled",                PDMGMPEnabled, bool, true);
   DECL_MEDIA_PREF("media.gmp.decoder.aac",                    GMPAACPreferred, uint32_t, 0);
   DECL_MEDIA_PREF("media.gmp.decoder.h264",                   GMPH264Preferred, uint32_t, 0);
 
   // MediaDecoderStateMachine
   DECL_MEDIA_PREF("media.suspend-bkgnd-video.enabled",        MDSMSuspendBackgroundVideoEnabled, bool, false);
   DECL_MEDIA_PREF("media.suspend-bkgnd-video.delay-ms",       MDSMSuspendBackgroundVideoDelay, AtomicUint32, SUSPEND_BACKGROUND_VIDEO_DELAY_MS);
+  DECL_MEDIA_PREF("media.dormant-on-pause-timeout-ms",        DormantOnPauseTimeout, int32_t, 5000);
 
   // WebSpeech
   DECL_MEDIA_PREF("media.webspeech.synth.force_global_queue", WebSpeechForceGlobal, bool, false);
   DECL_MEDIA_PREF("media.webspeech.test.enable",              WebSpeechTestEnabled, bool, false);
   DECL_MEDIA_PREF("media.webspeech.test.fake_fsm_events",     WebSpeechFakeFSMEvents, bool, false);
   DECL_MEDIA_PREF(TEST_PREFERENCE_FAKE_RECOGNITION_SERVICE,   WebSpeechFakeRecognitionService, bool, false);
   DECL_MEDIA_PREF("media.webspeech.recognition.enable",       WebSpeechRecognitionEnabled, bool, false);
   DECL_MEDIA_PREF("media.webspeech.recognition.force_enable", WebSpeechRecognitionForceEnabled, bool, false);
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -306,16 +306,23 @@ pref("mathml.scale_stretchy_operators.en
 
 // Disable MediaError.message.
 #ifdef RELEASE_OR_BETA
 pref("dom.MediaError.message.enabled", false);
 #else
 pref("dom.MediaError.message.enabled", true);
 #endif
 
+// Enabled on nightly only until we fix mochitest failures.
+#ifdef NIGHTLY_BUILD
+pref("media.dormant-on-pause-timeout-ms", 5000);
+#else
+pref("media.dormant-on-pause-timeout-ms", -1);
+#endif
+
 // Media cache size in kilobytes
 pref("media.cache_size", 512000);
 // When a network connection is suspended, don't resume it until the
 // amount of buffered data falls below this threshold (in seconds).
 pref("media.cache_resume_threshold", 999999);
 // Stop reading ahead when our buffered data is this many seconds ahead
 // of the current playback position. This limit can stop us from using arbitrary
 // amounts of network bandwidth prefetching huge videos.