Bug 1291741 - Relax setTimeout throttling in background tabs when an AudioContext is present, rather than only when audio is playing, r=bkelly

This commit is contained in:
Michael Layzell 2016-08-04 13:53:11 -04:00
parent 9e29edc5a4
commit 2513a13f51
2 changed files with 33 additions and 76 deletions

View File

@ -304,17 +304,10 @@ static int32_t gMinTimeoutValue;
static int32_t gMinBackgroundTimeoutValue;
inline int32_t
nsGlobalWindow::DOMMinTimeoutValue() const {
bool isBackground = !mOuterWindow || mOuterWindow->IsBackground();
if (isBackground) {
// Don't use the background timeout value when there are audio contexts with
// active nodes, so that background audio can keep running smoothly.
for (const AudioContext* ctx : mAudioContexts) {
if (ctx->ActiveNodeCount() > 0) {
isBackground = false;
break;
}
}
}
// Don't use the background timeout value when there are audio contexts
// present, so that baackground audio can keep running smoothly. (bug 1181073)
bool isBackground = mAudioContexts.IsEmpty() &&
(!mOuterWindow || mOuterWindow->IsBackground());
return
std::max(isBackground ? gMinBackgroundTimeoutValue : gMinTimeoutValue, 0);
}

View File

@ -4,73 +4,37 @@ add_task(function*() {
'set': [['dom.min_background_timeout_value', 3000]]
}, resolve));
let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, "https://example.com");
let browser = gBrowser.selectedBrowser;
// Make a new tab, and put it in the background
yield BrowserTestUtils.withNewTab("about:blank", function*(browser) {
yield BrowserTestUtils.withNewTab("about:blank", function*() {
let time = yield ContentTask.spawn(browser, null, function () {
return new Promise(resolve => {
let start = content.performance.now();
let id = content.window.setInterval(function() {
let end = content.performance.now();
content.window.clearInterval(id);
resolve(end - start);
}, 0);
});
});
// Make the tab a background tab, so that setInterval will be throttled.
yield BrowserTestUtils.openNewForegroundTab(gBrowser);
ok(time > 2000, "Interval is throttled with no webaudio (" + time + " ms)");
let time = yield ContentTask.spawn(browser, null, function () {
return new Promise(resolve => {
let start = content.performance.now();
let id = content.window.setInterval(function() {
let end = content.performance.now();
content.window.clearInterval(id);
resolve(end - start);
}, 0);
time = yield ContentTask.spawn(browser, null, function () {
return new Promise(resolve => {
// Create an audio context, and save it on the window so it doesn't get GCed
content.window._audioCtx = new content.window.AudioContext();
let start = content.performance.now();
let id = content.window.setInterval(function() {
let end = content.performance.now();
content.window.clearInterval(id);
resolve(end - start);
}, 0);
});
});
ok(time < 1000, "Interval is not throttled with an audio context present (" + time + " ms)");
});
});
ok(time > 2000, "Interval is throttled with no webaudio (" + time + " ms)");
// Set up a listener for the oscillator's demise
let oscillatorDemisePromise = ContentTask.spawn(browser, null, function() {
return new Promise(resolve => {
let observer = () => resolve();
// Record the observer on the content object so we can throw it out later
content.__bug1181073_observer = observer;
Services.obs.addObserver(observer, "webaudio-node-demise", false);
});
});
time = yield ContentTask.spawn(browser, null, function () {
return new Promise(resolve => {
// Start playing audio, save it on the window so it doesn't get GCed
let audioCtx = content.window.audioCtx = new content.window.AudioContext();
let oscillator = audioCtx.createOscillator();
oscillator.type = 'square';
oscillator.frequency.value = 3000;
oscillator.start();
let start = content.performance.now();
let id = content.window.setInterval(function() {
let end = content.performance.now();
content.window.clearInterval(id);
oscillator.stop();
resolve(end - start);
}, 0);
});
});
ok(time < 1000, "Interval is not throttled with audio playing (" + time + " ms)");
// Destroy the oscillator, but not the audio context
yield new Promise(resolve => SpecialPowers.exactGC(resolve));
yield oscillatorDemisePromise;
time = yield ContentTask.spawn(browser, null, function () {
return new Promise(resolve => {
let start = content.performance.now();
let id = content.window.setInterval(function() {
let end = content.performance.now();
content.window.clearInterval(id);
resolve(end - start);
}, 0);
});
});
ok(time > 2000, "Interval is throttled with audio stopped (" + time + " ms)");
while (gBrowser.tabs.length > 1)
gBrowser.removeCurrentTab();
});