Source code

Revision control

Copy as Markdown

Other Tools

Test Info: Warnings

// Verify that the MediaController onaudiblechange event fires when different
// types of audio sources (HTMLMediaElement, Web Audio, Web Speech) start and
// stop producing sound in a tab.
const PAGE =
const testVideoId = "video";
add_task(async function setupTestingPref() {
await SpecialPowers.pushPrefEnv({
set: [
["media.mediacontrol.testingevents.enabled", true],
["dom.audiocontext.testing", true],
["media.webspeech.synth.enabled", true],
],
});
});
/**
* Assert that onaudiblechange fires in the expected sequence:
* 1. call startFn() -> controller becomes audible
* 2. call stopFn() -> controller becomes inaudible
*/
async function testAudibleChangeSequence(tab, startFn, stopFn) {
const controller = tab.linkedBrowser.browsingContext.mediaController;
ok(!controller.isAudible, "controller starts inaudible");
const audiblePromise = new Promise(resolve => {
controller.addEventListener("audiblechange", resolve, { once: true });
});
await startFn();
await audiblePromise;
ok(true, "controller became audible after source starts");
const inaudiblePromise = new Promise(resolve => {
if (!controller.isAudible) {
resolve();
return;
}
controller.addEventListener("audiblechange", function handler() {
if (!controller.isAudible) {
controller.removeEventListener("audiblechange", handler);
resolve();
}
});
});
await stopFn();
await inaudiblePromise;
ok(!controller.isAudible, "controller is inaudible after source stops");
}
add_task(async function testAudibleChangeEventFiredForMediaElement() {
info("open media page");
const tab = await createLoadedTabWrapper(PAGE);
await testAudibleChangeSequence(
tab,
() =>
SpecialPowers.spawn(tab.linkedBrowser, [testVideoId], async id => {
await content.document.getElementById(id).play();
}),
() =>
SpecialPowers.spawn(tab.linkedBrowser, [testVideoId], async id => {
content.document.getElementById(id).pause();
})
);
await tab.close();
});
add_task(async function testAudibleChangeEventFiredForWebAudio() {
info("open a tab");
const tab = await createLoadedTabWrapper(PAGE, { needCheck: false });
await testAudibleChangeSequence(
tab,
() =>
SpecialPowers.spawn(tab.linkedBrowser, [], async () => {
content.ac = new content.AudioContext();
const oscillator = content.ac.createOscillator();
oscillator.connect(content.ac.destination);
oscillator.start();
if (content.ac.state !== "running") {
await content.ac.resume();
}
}),
() =>
SpecialPowers.spawn(tab.linkedBrowser, [], async () => {
await content.ac.close();
})
);
await tab.close();
});
add_task(async function testAudibleChangeEventFiredForWebSpeech() {
info("open a tab");
const tab = await createLoadedTabWrapper(PAGE, { needCheck: false });
await testAudibleChangeSequence(
tab,
() =>
SpecialPowers.spawn(tab.linkedBrowser, [], () => {
const utterance = new content.SpeechSynthesisUtterance("audible test");
// Pin to the test fake-synth voice that fires "start" but never
// auto-fires "end" (eSuppressEnd in nsFakeSynthServices.cpp). This
// keeps the utterance reliably audible across all platforms — the
// default voices on some CI runners either fire start+end back-to-back
// (FakeSynth's default) or never fire start at all.
utterance.lang = "it-IT-noend";
content.speechSynthesis.speak(utterance);
}),
() =>
SpecialPowers.spawn(tab.linkedBrowser, [], () => {
content.speechSynthesis.cancel();
})
);
await tab.close();
});