add_task(async function setupTestPrefs() {
await SpecialPowers.pushPrefEnv({
set: [
["media.captureStream.enabled", true],
// For mediaDevices and getUserMedia
["media.navigator.permission.disabled", true],
["media.devices.unfocused.enabled", true],
],
});
});
// When calling captureStream() on a media element, audio playback should still
// be output through the media pipeline's audio device. We verify this by
// checking the loopback stream.
add_task(async function testCaptureStreamAudioPlayout() {
if (!navigator.userAgent.includes("Linux")) {
ok(true, "audio loopback is only supported on Linux");
return;
}
if (!navigator.mediaDevices) {
ok(true, "No mediaDevices, then gUM cannot have been called either");
return;
}
info("creating and playing audio element");
const { ac, source, loopbackStream } = await setupLoopbackAudioGraph();
const audio = await createAndPlayAudio();
info("capturing the audio element's media stream");
const stream = audio.captureStream();
is(stream.getAudioTracks().length, 1, "captured stream has an audio track");
info("waiting for loopback audio to become audible");
const SILENCE_RMS_THRESHOLD = 0.0;
const AUDIBLE_RMS_THRESHOLD = 0.01;
let curRms = await waitForRmsOverThreshold(ac, source, AUDIBLE_RMS_THRESHOLD);
ok(curRms > 0.01, `Expected audible baseline RMS ${curRms}`);
audio.volume = 0.3;
info(`Lowering volume to ${audio.volume}`);
let tempAudibleThreshold = AUDIBLE_RMS_THRESHOLD * audio.volume;
curRms = await waitForRmsOverThreshold(ac, source, tempAudibleThreshold);
ok(curRms > tempAudibleThreshold,
`Expected non-silent RMS ${curRms} after volume=${audio.volume}`);
// When a MediaElementAudioSourceNode is created for a media element, audio
// output should be routed through the Web Audio graph, and the loopback stream
// should therefore be silent.
add_task(async function testMediaElementAudioSourceNodeAudioPlayout() {
if (!navigator.userAgent.includes("Linux")) {
ok(true, "audio loopback is only supported on Linux");
return;
}
if (!navigator.mediaDevices) {
ok(true, "No mediaDevices, then gUM cannot have been called either");
return;
}
info("connecting to a media element source node");
const srcElementNode = ac.createMediaElementSource(audio);
info("audio playback should now be routed through the Web Audio graph");
const SILENCE_RMS_THRESHOLD = 0.0;
const AUDIBLE_RMS_THRESHOLD = 0.01;
let curRms = await waitForRmsEqualToThreshold(ac, source, SILENCE_RMS_THRESHOLD);
is(curRms, SILENCE_RMS_THRESHOLD,
`Expected silent RMS ${curRms} for loopback stream`);
info("waiting for the Web Audio graph to produce audible sound");
curRms = await waitForRmsOverThreshold(ac, srcElementNode, AUDIBLE_RMS_THRESHOLD);
ok(curRms > AUDIBLE_RMS_THRESHOLD,
`Expected audible RMS ${curRms} from the graph`);
info("calling captureStream() on the media element");
const captured = audio.captureStream();
ok(!!captured.getTracks().length, "captureStream() returned tracks");
info("verifying the loopback stream remains silent after captureStream()");
curRms = await waitForRmsEqualToThreshold(ac, source, SILENCE_RMS_THRESHOLD);
is(curRms, SILENCE_RMS_THRESHOLD,
`Expected silent RMS ${curRms} for loopback stream`);
info("verifying the Web Audio graph still produces audible sound");
curRms = await waitForRmsOverThreshold(ac, srcElementNode, AUDIBLE_RMS_THRESHOLD);
ok(curRms > AUDIBLE_RMS_THRESHOLD,
`Expected audible RMS ${curRms} from the graph`);
async function waitForRmsPredicate(ac, src, threshold, predicate, timeoutMs = 10000) {
const start = performance.now();
while (true) {
const rms = await measureRMSOnceWithFreshScriptProcessor(ac, src);
if (predicate(rms)) {
return rms;
}
const elapsedTime = performance.now() - start;
if (elapsedTime > timeoutMs) {
throw new Error(`Timed out waitForRmsPredicate ${elapsedTime}`);
}
}
}
async function measureRMSOnceWithFreshScriptProcessor(ac, src) {
// Use a new ScriptProcessorNode for each measurement, so that an event does
// not contain samples from the past.
const sp = ac.createScriptProcessor(2048, 1, 1);
src.connect(sp);
sp.connect(ac.destination);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.