Source code

Revision control

Copy as Markdown

Other Tools

Test Info:

/**
* This test is used for testing whether WebAudio can be started correctly in
* different scenarios, such as
* 1) site has existing 'autoplay-media' permission for allowing autoplay
* 2) site has existing 'autoplay-media' permission for blocking autoplay
* 3) site doesn't have permission, start audio context by calling resume() or
* AudioScheduledNode.start() after granting user activation.
*/
"use strict";
const { PermissionTestUtils } = ChromeUtils.importESModule(
);
const PAGE = GetTestWebBasedURL("file_empty.html");
function setup_test_preference() {
return SpecialPowers.pushPrefEnv({
set: [
["media.autoplay.default", SpecialPowers.Ci.nsIAutoplay.BLOCKED],
["media.autoplay.blocking_policy", 0],
["media.autoplay.block-event.enabled", true],
],
});
}
function createAudioContext() {
content.ac = new content.AudioContext();
const ac = content.ac;
ac.allowedToStart = new Promise(resolve => {
ac.addEventListener(
"statechange",
function () {
if (ac.state === "running") {
resolve();
}
},
{ once: true }
);
});
ac.notAllowedToStart = new Promise(resolve => {
ac.addEventListener(
"blocked",
function () {
resolve();
},
{ once: true }
);
});
}
async function checkIfAudioContextIsAllowedToStart(isAllowedToStart) {
const ac = content.ac;
if (isAllowedToStart) {
await ac.allowedToStart;
Assert.strictEqual(ac.state, "running", `AudioContext is running.`);
} else {
await ac.notAllowedToStart;
Assert.strictEqual(
ac.state,
"suspended",
`AudioContext is not started yet.`
);
}
}
async function resumeAudioContext(isAllowedToStart) {
const ac = content.ac;
const resumePromise = ac.resume();
const blockedPromise = new Promise(resolve => {
ac.addEventListener(
"blocked",
function () {
resolve();
},
{ once: true }
);
});
if (isAllowedToStart) {
await resumePromise;
ok(true, `successfully resume AudioContext.`);
} else {
await blockedPromise;
ok(true, `resume is blocked because AudioContext is not allowed to start.`);
}
}
function startAudioContext(method) {
const ac = content.ac;
if (method == "AudioContext") {
info(`using AudioContext.resume() to start AudioContext`);
ac.resume();
return;
}
info(`using ${method}.start() to start AudioContext`);
let node;
switch (method) {
case "AudioBufferSourceNode":
node = ac.createBufferSource();
break;
case "ConstantSourceNode":
node = ac.createConstantSource();
break;
case "OscillatorNode":
node = ac.createOscillator();
break;
default:
ok(false, "undefined AudioScheduledSourceNode type");
return;
}
node.connect(ac.destination);
node.start();
}
async function testAutoplayExistingPermission({ name, permission }) {
info(`- starting \"${name}\" -`);
const tab = await BrowserTestUtils.openNewForegroundTab(
window.gBrowser,
PAGE
);
const browser = tab.linkedBrowser;
info(`- set the 'autoplay-media' permission -`);
const promptShow = () =>
PopupNotifications.getNotification("autoplay-media", browser);
PermissionTestUtils.add(browser.currentURI, "autoplay-media", permission);
ok(!promptShow(), `should not be showing permission prompt yet`);
info(`- create audio context -`);
await SpecialPowers.spawn(browser, [], createAudioContext);
info(`- check AudioContext status -`);
const isAllowedToStart = permission === Services.perms.ALLOW_ACTION;
await SpecialPowers.spawn(
browser,
[isAllowedToStart],
checkIfAudioContextIsAllowedToStart
);
await SpecialPowers.spawn(browser, [isAllowedToStart], resumeAudioContext);
info(`- remove tab -`);
PermissionTestUtils.remove(browser.currentURI, "autoplay-media");
await BrowserTestUtils.removeTab(tab);
}
async function testAutoplayUnknownPermission({ name, method }) {
info(`- starting \"${name}\" -`);
const tab = await BrowserTestUtils.openNewForegroundTab(
window.gBrowser,
PAGE
);
const browser = tab.linkedBrowser;
info(`- set the 'autoplay-media' permission to UNKNOWN -`);
const promptShow = () =>
PopupNotifications.getNotification("autoplay-media", browser);
PermissionTestUtils.add(
browser.currentURI,
"autoplay-media",
Services.perms.UNKNOWN_ACTION
);
ok(!promptShow(), `should not be showing permission prompt yet`);
info(`- create AudioContext which should not start -`);
await SpecialPowers.spawn(browser, [], createAudioContext);
await SpecialPowers.spawn(
browser,
[false],
checkIfAudioContextIsAllowedToStart
);
info(`- simulate user activate the page -`);
await SpecialPowers.spawn(browser, [], () => {
content.document.notifyUserGestureActivation();
});
info(`- try to start AudioContext -`);
await SpecialPowers.spawn(browser, [method], startAudioContext);
info(`- check AudioContext status -`);
await SpecialPowers.spawn(
browser,
[true],
checkIfAudioContextIsAllowedToStart
);
await SpecialPowers.spawn(browser, [true], resumeAudioContext);
info(`- remove tab -`);
PermissionTestUtils.remove(browser.currentURI, "autoplay-media");
await BrowserTestUtils.removeTab(tab);
}
add_task(async function start_tests() {
info("- setup test preference -");
await setup_test_preference();
await testAutoplayExistingPermission({
name: "Prexisting allow permission",
permission: Services.perms.ALLOW_ACTION,
});
await testAutoplayExistingPermission({
name: "Prexisting block permission",
permission: Services.perms.DENY_ACTION,
});
const startMethods = [
"AudioContext",
"AudioBufferSourceNode",
"ConstantSourceNode",
"OscillatorNode",
];
for (let method of startMethods) {
await testAutoplayUnknownPermission({
name: "Unknown permission and start AudioContext after granting user activation",
method,
});
}
});