Bug 1334825 - part 1: relax setTimeout throttling in background tabs when audio is playing by media element. r?bkelly draft
authorJohn Lin <jolin@mozilla.com>
Fri, 10 Feb 2017 10:59:24 +0800
changeset 481643 dfe7ef81f0bb140cfa755ab2039b56507fc8eab5
parent 481595 25a94c1047e793ef096d8556fa3c26dd72bd37d7
child 481644 2c747e94f9530fc508e598484d99067c006f055c
push id44891
push userbmo:jolin@mozilla.com
push dateFri, 10 Feb 2017 08:51:17 +0000
reviewersbkelly
bugs1334825
milestone54.0a1
Bug 1334825 - part 1: relax setTimeout throttling in background tabs when audio is playing by media element. r?bkelly MozReview-Commit-ID: A2i1g9qA0kP
dom/base/TimeoutManager.cpp
dom/base/nsGlobalWindow.cpp
dom/base/nsPIDOMWindow.h
--- a/dom/base/TimeoutManager.cpp
+++ b/dom/base/TimeoutManager.cpp
@@ -30,18 +30,19 @@ static int32_t gMinBackgroundTimeoutValu
 static int32_t gMinTrackingTimeoutValue = 0;
 static int32_t gMinTrackingBackgroundTimeoutValue = 0;
 static bool    gAnnotateTrackingChannels = false;
 int32_t
 TimeoutManager::DOMMinTimeoutValue(bool aIsTracking) const {
   // First apply any back pressure delay that might be in effect.
   int32_t value = std::max(mBackPressureDelayMS, 0);
   // Don't use the background timeout value when there are audio contexts
-  // present, so that background audio can keep running smoothly. (bug 1181073)
-  bool isBackground = !mWindow.AsInner()->HasAudioContexts() &&
+  // present or element playing audio, so that background audio can keep running smoothly.
+  // (bug 1181073, 1334825)
+  bool isBackground = !mWindow.AsInner()->HasAudioContextsOrPlayingElements() &&
     mWindow.IsBackgroundInternal();
   auto minValue = aIsTracking ? (isBackground ? gMinTrackingBackgroundTimeoutValue
                                               : gMinTrackingTimeoutValue)
                               : (isBackground ? gMinBackgroundTimeoutValue
                                               : gMinTimeoutValue);
   return std::max(minValue, value);
 }
 
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -1890,16 +1890,18 @@ nsGlobalWindow::CleanUp()
 
   CleanupCachedXBLHandlers(this);
 
   for (uint32_t i = 0; i < mAudioContexts.Length(); ++i) {
     mAudioContexts[i]->Shutdown();
   }
   mAudioContexts.Clear();
 
+  mPlayingElements.Clear();
+
   if (mIdleTimer) {
     mIdleTimer->Cancel();
     mIdleTimer = nullptr;
   }
 
   mServiceWorkerRegistrationTable.Clear();
 }
 
@@ -2009,16 +2011,18 @@ nsGlobalWindow::FreeInnerObjects()
 
   CleanupCachedXBLHandlers(this);
 
   for (uint32_t i = 0; i < mAudioContexts.Length(); ++i) {
     mAudioContexts[i]->Shutdown();
   }
   mAudioContexts.Clear();
 
+  mPlayingElements.Clear();
+
   DisableGamepadUpdates();
   mHasGamepad = false;
   mGamepads.Clear();
   DisableVRUpdates();
   mHasVREvents = false;
   mVRDisplays.Clear();
 }
 
@@ -3961,16 +3965,32 @@ void
 nsPIDOMWindowInner::RemoveAudioContext(AudioContext* aAudioContext)
 {
   MOZ_ASSERT(IsInnerWindow());
 
   mAudioContexts.RemoveElement(aAudioContext);
 }
 
 void
+nsPIDOMWindowInner::AddPlayingElement(HTMLMediaElement* aElement)
+{
+  MOZ_ASSERT(IsInnerWindow());
+
+  mPlayingElements.AppendElement(aElement);
+}
+
+void
+nsPIDOMWindowInner::RemovePlayingElement(HTMLMediaElement* aElement)
+{
+  MOZ_ASSERT(IsInnerWindow());
+
+  mPlayingElements.RemoveElement(aElement);
+}
+
+void
 nsPIDOMWindowInner::MuteAudioContexts()
 {
   MOZ_ASSERT(IsInnerWindow());
 
   for (uint32_t i = 0; i < mAudioContexts.Length(); ++i) {
     if (!mAudioContexts[i]->IsOffline()) {
       mAudioContexts[i]->Mute();
     }
@@ -4147,19 +4167,19 @@ nsPIDOMWindowInner::Thaw()
 
 void
 nsPIDOMWindowInner::SyncStateFromParentWindow()
 {
   nsGlobalWindow::Cast(this)->SyncStateFromParentWindow();
 }
 
 bool
-nsPIDOMWindowInner::HasAudioContexts() const
-{
-  return !mAudioContexts.IsEmpty();
+nsPIDOMWindowInner::HasAudioContextsOrPlayingElements() const
+{
+  return !(mAudioContexts.IsEmpty() && mPlayingElements.IsEmpty());
 }
 
 mozilla::dom::TimeoutManager&
 nsPIDOMWindowInner::TimeoutManager()
 {
   return *mTimeoutManager;
 }
 
--- a/dom/base/nsPIDOMWindow.h
+++ b/dom/base/nsPIDOMWindow.h
@@ -39,16 +39,17 @@ class nsPIWindowRoot;
 class nsXBLPrototypeHandler;
 
 typedef uint32_t SuspendTypes;
 
 namespace mozilla {
 class ThrottledEventQueue;
 namespace dom {
 class AudioContext;
+class HTMLMediaElement;
 class DocGroup;
 class TabGroup;
 class Element;
 class Performance;
 class ServiceWorkerRegistration;
 class Timeout;
 class TimeoutManager;
 class CustomElementRegistry;
@@ -713,16 +714,19 @@ protected:
 
   // the element within the document that is currently focused when this
   // window is active
   nsCOMPtr<nsIContent> mFocusedNode;
 
   // The AudioContexts created for the current document, if any.
   nsTArray<mozilla::dom::AudioContext*> mAudioContexts; // Weak
 
+  // The media elements playing audio.
+  nsTArray<mozilla::dom::HTMLMediaElement*> mPlayingElements; // Weak
+
   // This is present both on outer and inner windows.
   RefPtr<mozilla::dom::TabGroup> mTabGroup;
 
   // A unique (as long as our 64-bit counter doesn't roll over) id for
   // this window.
   uint64_t mWindowID;
 
   // This is only used by the inner window. Set to true once we've sent
@@ -768,16 +772,19 @@ public:
   // keep the same document active but create a new window.
   inline bool HasActiveDocument();
 
   bool AddAudioContext(mozilla::dom::AudioContext* aAudioContext);
   void RemoveAudioContext(mozilla::dom::AudioContext* aAudioContext);
   void MuteAudioContexts();
   void UnmuteAudioContexts();
 
+  void AddPlayingElement(mozilla::dom::HTMLMediaElement* aElement);
+  void RemovePlayingElement(mozilla::dom::HTMLMediaElement* aElement);
+
   bool GetAudioCaptured() const;
   nsresult SetAudioCapture(bool aCapture);
 
   already_AddRefed<mozilla::dom::ServiceWorkerRegistration>
     GetServiceWorkerRegistration(const nsAString& aScope);
   void InvalidateServiceWorkerRegistration(const nsAString& aScope);
 
   mozilla::dom::Performance* GetPerformance();
@@ -873,17 +880,17 @@ public:
   // calls.
   void Freeze();
   void Thaw();
 
   // Apply the parent window's suspend, freeze, and modal state to the current
   // window.
   void SyncStateFromParentWindow();
 
-  bool HasAudioContexts() const;
+  bool HasAudioContextsOrPlayingElements() const;
 
   mozilla::dom::TimeoutManager& TimeoutManager();
 
   bool IsRunningTimeout();
 
 protected:
   void CreatePerformanceObjectIfNeeded();
 };