Bug 1334825 - part 1: relax setTimeout throttling in background tabs when audio is playing by media element. r?bkelly
MozReview-Commit-ID: A2i1g9qA0kP
--- 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();
};