diff options
Diffstat (limited to 'toolkit/content/tests/browser/browser_media_wakelock_webaudio.js')
-rw-r--r-- | toolkit/content/tests/browser/browser_media_wakelock_webaudio.js | 127 |
1 files changed, 127 insertions, 0 deletions
diff --git a/toolkit/content/tests/browser/browser_media_wakelock_webaudio.js b/toolkit/content/tests/browser/browser_media_wakelock_webaudio.js new file mode 100644 index 0000000000..7c40b5fe1a --- /dev/null +++ b/toolkit/content/tests/browser/browser_media_wakelock_webaudio.js @@ -0,0 +1,127 @@ +/** + * Test if wakelock can be required correctly when we play web audio. The + * wakelock should only be required when web audio is audible. + */ + +const AUDIO_WAKELOCK_NAME = "audio-playing"; +const VIDEO_WAKELOCK_NAME = "video-playing"; + +add_task(async function testCheckAudioWakelockWhenChangeTabVisibility() { + await checkWakelockWhenChangeTabVisibility({ + description: "playing audible web audio", + needLock: true, + }); + await checkWakelockWhenChangeTabVisibility({ + description: "suspended web audio", + additionalParams: { + suspend: true, + }, + needLock: false, + }); +}); + +add_task( + async function testBrieflyAudibleAudioContextReleasesAudioWakeLockWhenInaudible() { + const tab = await BrowserTestUtils.openNewForegroundTab( + window.gBrowser, + "about:blank" + ); + + info(`make a short noise on web audio`); + await Promise.all([ + // As the sound would only happen for a really short period, calling + // checking wakelock first helps to ensure that we won't miss that moment. + waitForExpectedWakeLockState(AUDIO_WAKELOCK_NAME, { + needLock: true, + isForegroundLock: true, + }), + createWebAudioDocument(tab, { stopTimeOffset: 0.1 }), + ]); + await ensureNeverAcquireVideoWakelock(); + + info(`audio wakelock should be released after web audio becomes silent`); + await waitForExpectedWakeLockState(AUDIO_WAKELOCK_NAME, false, { + needLock: false, + }); + await ensureNeverAcquireVideoWakelock(); + + await BrowserTestUtils.removeTab(tab); + } +); + +/** + * Following are helper functions. + */ +async function checkWakelockWhenChangeTabVisibility({ + description, + additionalParams, + needLock, + elementIdForEnteringPIPMode, +}) { + const originalTab = gBrowser.selectedTab; + info(`start a new tab for '${description}'`); + const mediaTab = await BrowserTestUtils.openNewForegroundTab( + window.gBrowser, + "about:blank" + ); + await createWebAudioDocument(mediaTab, additionalParams); + await waitForExpectedWakeLockState(AUDIO_WAKELOCK_NAME, { + needLock, + isForegroundLock: true, + }); + await ensureNeverAcquireVideoWakelock(); + + info(`switch media tab to background`); + await BrowserTestUtils.switchTab(window.gBrowser, originalTab); + await waitForExpectedWakeLockState(AUDIO_WAKELOCK_NAME, { + needLock, + isForegroundLock: false, + }); + await ensureNeverAcquireVideoWakelock(); + + info(`switch media tab to foreground again`); + await BrowserTestUtils.switchTab(window.gBrowser, mediaTab); + await waitForExpectedWakeLockState(AUDIO_WAKELOCK_NAME, { + needLock, + isForegroundLock: true, + }); + await ensureNeverAcquireVideoWakelock(); + + info(`remove media tab`); + BrowserTestUtils.removeTab(mediaTab); +} + +function createWebAudioDocument(tab, { stopTimeOffset, suspend } = {}) { + return SpecialPowers.spawn( + tab.linkedBrowser, + [suspend, stopTimeOffset], + async (suspend, stopTimeOffset) => { + // Create an oscillatorNode to produce sound. + content.ac = new content.AudioContext(); + const ac = content.ac; + const dest = ac.destination; + const source = new content.OscillatorNode(ac); + source.start(ac.currentTime); + source.connect(dest); + + if (stopTimeOffset) { + source.stop(ac.currentTime + 0.1); + } + + if (suspend) { + await content.ac.suspend(); + } else { + while (ac.state != "running") { + info(`wait until AudioContext starts running`); + await new Promise(r => (ac.onstatechange = r)); + } + info("AudioContext is running"); + } + } + ); +} + +function ensureNeverAcquireVideoWakelock() { + // Web audio won't play any video, we never need video wakelock. + return waitForExpectedWakeLockState(VIDEO_WAKELOCK_NAME, { needLock: false }); +} |