author | Michael Layzell <michael@thelayzells.com> |
Fri, 06 May 2016 15:08:58 -0400 | |
changeset 300981 | f9a2e3de2a4afa13f1741ee61b5ef317915c531c |
parent 300980 | 18b3c95f1a38ca9246b877a46c38723731a38885 |
child 300982 | b764ee0f465e45476a80af3e434b5a0861cb2a36 |
push id | 30324 |
push user | cbook@mozilla.com |
push date | Wed, 08 Jun 2016 09:58:15 +0000 |
treeherder | mozilla-central@f8ad071a6e14 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | bkelly |
bugs | 1181073 |
milestone | 50.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
|
--- a/dom/base/nsGlobalWindow.cpp +++ b/dom/base/nsGlobalWindow.cpp @@ -302,16 +302,26 @@ int32_t gTimeoutCnt // The default shortest interval/timeout we permit #define DEFAULT_MIN_TIMEOUT_VALUE 4 // 4ms #define DEFAULT_MIN_BACKGROUND_TIMEOUT_VALUE 1000 // 1000ms 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; + } + } + } return std::max(isBackground ? gMinBackgroundTimeoutValue : gMinTimeoutValue, 0); } // The number of nested timeouts before we start clamping. HTML5 says 1, WebKit // uses 5. #define DOM_CLAMP_TIMEOUT_NESTING_LEVEL 5
--- a/dom/media/webaudio/AudioContext.cpp +++ b/dom/media/webaudio/AudioContext.cpp @@ -691,16 +691,22 @@ AudioContext::UpdatePannerSource() } uint32_t AudioContext::MaxChannelCount() const { return mIsOffline ? mNumberOfChannels : CubebUtils::MaxNumberOfChannels(); } +uint32_t +AudioContext::ActiveNodeCount() const +{ + return mActiveNodes.Count(); +} + MediaStreamGraph* AudioContext::Graph() const { return Destination()->Stream()->Graph(); } MediaStream* AudioContext::DestinationStream() const
--- a/dom/media/webaudio/AudioContext.h +++ b/dom/media/webaudio/AudioContext.h @@ -295,16 +295,18 @@ public: void UnregisterActiveNode(AudioNode* aNode); void UnregisterAudioBufferSourceNode(AudioBufferSourceNode* aNode); void UnregisterPannerNode(PannerNode* aNode); void UpdatePannerSource(); uint32_t MaxChannelCount() const; + uint32_t ActiveNodeCount() const; + void Mute() const; void Unmute() const; JSObject* GetGlobalJSObject() const; AudioChannel MozAudioChannelType() const; AudioChannel TestAudioChannelInAudioNodeStream();
--- a/dom/media/webaudio/moz.build +++ b/dom/media/webaudio/moz.build @@ -11,16 +11,20 @@ DIRS += ['blink'] TEST_DIRS += ['compiledtest'] MOCHITEST_MANIFESTS += [ 'test/blink/mochitest.ini', 'test/mochitest.ini', ] +BROWSER_CHROME_MANIFESTS += [ + 'test/browser.ini', +] + TEST_HARNESS_FILES.testing.mochitest.tests.dom.media.webaudio.test.blink += [ 'test/blink/audio-testing.js', 'test/blink/convolution-testing.js', 'test/blink/panner-model-testing.js', ] EXPORTS += [ 'AlignedTArray.h',
new file mode 100644 --- /dev/null +++ b/dom/media/webaudio/test/browser.ini @@ -0,0 +1,1 @@ +[browser_bug1181073.js] \ No newline at end of file
new file mode 100644 --- /dev/null +++ b/dom/media/webaudio/test/browser_bug1181073.js @@ -0,0 +1,65 @@ +add_task(function*() { + // Make the min_background_timeout_value very high to avoid problems on slow machines + yield new Promise(resolve => SpecialPowers.pushPrefEnv({ + 'set': [['dom.min_background_timeout_value', 3000]] + }, resolve)); + + let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, "https://example.com"); + let browser = gBrowser.selectedBrowser; + + // Make the tab a background tab, so that setInterval will be throttled. + yield BrowserTestUtils.openNewForegroundTab(gBrowser); + + 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); + }); + }); + + ok(time > 2000, "Interval is throttled with no webaudio (" + time + " ms)"); + + 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(browser.contentWindow, resolve)); + + 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(); +});