Bug 1467350 - Make HTMLMediaElement::mPaused Watchable and update Wakelock status via a watcher. r?jya draft
authorChris Pearce <cpearce@mozilla.com>
Mon, 21 May 2018 14:19:47 +1200
changeset 805071 51753bd83f4f452943d01c05a28fc972b07980a3
parent 804982 1ab062fd31db7d4367a479fedb350dc6fcee7a3f
push id112551
push userbmo:cpearce@mozilla.com
push dateThu, 07 Jun 2018 02:40:07 +0000
reviewersjya
bugs1467350
milestone62.0a1
Bug 1467350 - Make HTMLMediaElement::mPaused Watchable and update Wakelock status via a watcher. r?jya We currently observe changes to HTMLMediaElement::mPaused via a hand-rolled wrapper class. We can use use mozilla::Watchable<> and avoid rolling our own equivalent here. This also paves the way for using state watching on other observable state in HTMLMediaElement. MozReview-Commit-ID: 4lBlJiV15iG
dom/html/HTMLMediaElement.cpp
dom/html/HTMLMediaElement.h
--- a/dom/html/HTMLMediaElement.cpp
+++ b/dom/html/HTMLMediaElement.cpp
@@ -3879,29 +3879,32 @@ private:
   Phase mPhase = Phase::Init;
 };
 
 NS_IMPL_ISUPPORTS(HTMLMediaElement::ShutdownObserver, nsIObserver)
 
 HTMLMediaElement::HTMLMediaElement(
   already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo)
   : nsGenericHTMLElement(aNodeInfo)
+  , mWatchManager(this, OwnerDoc()->AbstractMainThreadFor(TaskCategory::Other))
   , mMainThreadEventTarget(OwnerDoc()->EventTargetFor(TaskCategory::Other))
   , mAbstractMainThread(OwnerDoc()->AbstractMainThreadFor(TaskCategory::Other))
   , mShutdownObserver(new ShutdownObserver)
   , mPlayed(new TimeRanges(ToSupports(OwnerDoc())))
-  , mPaused(true, *this)
+  , mPaused(true, "HTMLMediaElement::mPaused")
   , mErrorSink(new ErrorSink(this))
   , mAudioChannelWrapper(new AudioChannelAgentCallback(this))
 {
   MOZ_ASSERT(mMainThreadEventTarget);
   MOZ_ASSERT(mAbstractMainThread);
 
   DecoderDoctorLogger::LogConstruction(this);
 
+  mWatchManager.Watch(mPaused, &HTMLMediaElement::UpdateWakeLock);
+
   ErrorResult rv;
 
   double defaultVolume = Preferences::GetFloat("media.default_volume", 1.0);
   SetVolume(defaultVolume, rv);
 
   RegisterActivityObserver();
   NotifyOwnerDocumentActivityChanged();
 
@@ -4175,41 +4178,30 @@ HTMLMediaElement::PlayInternal(ErrorResu
 void
 HTMLMediaElement::MaybeDoLoad()
 {
   if (mNetworkState == NETWORK_EMPTY) {
     DoLoad();
   }
 }
 
-HTMLMediaElement::WakeLockBoolWrapper&
-HTMLMediaElement::WakeLockBoolWrapper::operator=(bool val)
-{
-  if (mValue == val) {
-    return *this;
-  }
-
-  mValue = val;
-  UpdateWakeLock();
-  return *this;
-}
-
-void
-HTMLMediaElement::WakeLockBoolWrapper::UpdateWakeLock()
+void
+HTMLMediaElement::UpdateWakeLock()
 {
   MOZ_ASSERT(NS_IsMainThread());
-
-  bool playing = !mValue;
+  // Ensure we have a wake lock if we're playing audibly. This ensures the
+  // device doesn't sleep while playing.
+  bool playing = !mPaused;
   bool isAudible =
-    mOuter.Volume() > 0.0 && !mOuter.mMuted && mOuter.mIsAudioTrackAudible;
-  // when playing audible media.
+    Volume() > 0.0 && !mMuted && mIsAudioTrackAudible;
+  // WakeLock when playing audible media.
   if (playing && isAudible) {
-    mOuter.WakeLockCreate();
+    WakeLockCreate();
   } else {
-    mOuter.WakeLockRelease();
+    WakeLockRelease();
   }
 }
 
 void
 HTMLMediaElement::WakeLockCreate()
 {
   if (!mWakeLock) {
     RefPtr<power::PowerManagerService> pmService =
@@ -7544,17 +7536,17 @@ HTMLMediaElement::SetAudibleState(bool a
 
 void
 HTMLMediaElement::NotifyAudioPlaybackChanged(AudibleChangedReasons aReason)
 {
   if (mAudioChannelWrapper) {
     mAudioChannelWrapper->NotifyAudioPlaybackChanged(aReason);
   }
   // only request wake lock for audible media.
-  mPaused.UpdateWakeLock();
+  UpdateWakeLock();
 }
 
 bool
 HTMLMediaElement::ShouldElementBePaused()
 {
   // Bfcached page or inactive document.
   if (!IsActive()) {
     return true;
--- a/dom/html/HTMLMediaElement.h
+++ b/dom/html/HTMLMediaElement.h
@@ -834,36 +834,17 @@ protected:
   class StreamListener;
   class StreamSizeListener;
   class ShutdownObserver;
 
   MediaDecoderOwner::NextFrameStatus NextFrameStatus();
 
   void SetDecoder(MediaDecoder* aDecoder);
 
-  class WakeLockBoolWrapper {
-  public:
-    WakeLockBoolWrapper(bool aVal, HTMLMediaElement& aOuter)
-      : mValue(aVal)
-      , mOuter(aOuter)
-    {}
-
-    ~WakeLockBoolWrapper() {};
-
-    MOZ_IMPLICIT operator bool() const { return mValue; }
-
-    WakeLockBoolWrapper& operator=(bool val);
-
-    bool operator !() const { return !mValue; }
-
-    void UpdateWakeLock();
-  private:
-    bool mValue;
-    HTMLMediaElement& mOuter;
-  };
+  void UpdateWakeLock();
 
   // Holds references to the DOM wrappers for the MediaStreams that we're
   // writing to.
   struct OutputMediaStream {
     OutputMediaStream();
     ~OutputMediaStream();
 
     RefPtr<DOMMediaStream> mStream;
@@ -891,18 +872,18 @@ protected:
 
   /**
    * Use this method to change the mNetworkState member, so required
    * actions will be taken during the transition.
    */
   void ChangeNetworkState(nsMediaNetworkState aState);
 
   /**
-   * These two methods are called by the WakeLockBoolWrapper when the wakelock
-   * has to be created or released.
+   * These two methods are called when mPaused is changed to ensure we have
+   * a wake lock active when we're playing audibly.
    */
   virtual void WakeLockCreate();
   virtual void WakeLockRelease();
   RefPtr<WakeLock> mWakeLock;
 
   /**
    * Logs a warning message to the web console to report various failures.
    * aMsg is the localized message identifier, aParams is the parameters to
@@ -1368,16 +1349,18 @@ protected:
   bool AttachNewMediaKeys();
   bool TryMakeAssociationWithCDM(CDMProxy* aProxy);
   void MakeAssociationWithCDMResolved();
   void SetCDMProxyFailure(const MediaResult& aResult);
   void ResetSetMediaKeysTempVariables();
 
   void PauseIfShouldNotBePlaying();
 
+  WatchManager<HTMLMediaElement> mWatchManager;
+
   // The current decoder. Load() has been called on this decoder.
   // At most one of mDecoder and mSrcStream can be non-null.
   RefPtr<MediaDecoder> mDecoder;
 
   // The DocGroup-specific nsISerialEventTarget of this HTML element on the main
   // thread.
   nsCOMPtr<nsISerialEventTarget> mMainThreadEventTarget;
 
@@ -1595,17 +1578,17 @@ protected:
   // start playing when loaded. The 'autoplay' attribute of the object
   // is a mirror of the HTML attribute. These are different from this
   // 'mAutoplaying' flag, which indicates whether the current playback
   // is a result of the autoplay attribute.
   bool mAutoplaying = true;
 
   // Playback of the video is paused either due to calling the
   // 'Pause' method, or playback not yet having started.
-  WakeLockBoolWrapper mPaused;
+  Watchable<bool> mPaused;
 
   // The following two fields are here for the private storage of the builtin
   // video controls, and control 'casting' of the video to external devices
   // (TVs, projectors etc.)
   // True if casting is currently allowed
   bool mAllowCasting = false;
   // True if currently casting this video
   bool mIsCasting = false;