зеркало из https://github.com/mozilla/gecko-dev.git
117 строки
3.6 KiB
HTML
117 строки
3.6 KiB
HTML
<!DOCTYPE HTML>
|
|
<html>
|
|
<meta charset="utf-8">
|
|
<head>
|
|
<title>Test that MediaStreamAudioSourceNode and its input MediaStream stays alive while there are active tracks</title>
|
|
<script src="/tests/SimpleTest/SimpleTest.js"></script>
|
|
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
|
</head>
|
|
<body>
|
|
<pre id="test">
|
|
<script class="testbody" type="text/javascript">
|
|
SimpleTest.waitForExplicitFinish();
|
|
SimpleTest.requestFlakyTimeout("gUM and WebAudio data is async to main thread. " +
|
|
"We need a timeout to see that something does " +
|
|
"NOT happen to data.");
|
|
|
|
let context = new AudioContext();
|
|
let analyser = context.createAnalyser();
|
|
|
|
function wait(millis, resolveWithThis) {
|
|
return new Promise(resolve => setTimeout(() => resolve(resolveWithThis), millis));
|
|
}
|
|
|
|
function binIndexForFrequency(frequency) {
|
|
return 1 + Math.round(frequency * analyser.fftSize / context.sampleRate);
|
|
}
|
|
|
|
function waitForAudio(analysisFunction, cancelPromise) {
|
|
let data = new Uint8Array(analyser.frequencyBinCount);
|
|
let cancelled = false;
|
|
let cancelledMsg = "";
|
|
cancelPromise.then(msg => {
|
|
cancelled = true;
|
|
cancelledMsg = msg;
|
|
});
|
|
return new Promise((resolve, reject) => {
|
|
let loop = () => {
|
|
analyser.getByteFrequencyData(data);
|
|
if (cancelled) {
|
|
reject(new Error("waitForAudio cancelled: " + cancelledMsg));
|
|
return;
|
|
}
|
|
if (analysisFunction(data)) {
|
|
resolve();
|
|
return;
|
|
}
|
|
requestAnimationFrame(loop);
|
|
};
|
|
loop();
|
|
});
|
|
}
|
|
|
|
async function test(sourceNode) {
|
|
try {
|
|
await analyser.connect(context.destination);
|
|
|
|
ok(true, "Waiting for audio to pass through the analyser")
|
|
await waitForAudio(arr => arr[binIndexForFrequency(1000)] > 200,
|
|
wait(60000, "Timeout waiting for audio"));
|
|
|
|
ok(true, "Audio was detected by the analyser. Forcing CC.");
|
|
SpecialPowers.forceCC();
|
|
SpecialPowers.forceGC();
|
|
SpecialPowers.forceCC();
|
|
SpecialPowers.forceGC();
|
|
|
|
info("Checking that GC didn't destroy the stream or source node");
|
|
await waitForAudio(arr => arr[binIndexForFrequency(1000)] < 50,
|
|
wait(5000, "Timeout waiting for GC (timeout OK)"))
|
|
.then(() => Promise.reject("Audio stopped unexpectedly"),
|
|
() => Promise.resolve());
|
|
|
|
ok(true, "Audio is still flowing");
|
|
} catch(e) {
|
|
ok(false, "Error executing test: " + e + (e.stack ? "\n" + e.stack : ""));
|
|
SimpleTest.finish();
|
|
}
|
|
}
|
|
|
|
(async function() {
|
|
try {
|
|
await SpecialPowers.pushPrefEnv({
|
|
set: [
|
|
// This test expects the fake audio device, specifically for the tones
|
|
// it outputs. Explicitly disable the audio loopback device and enable
|
|
// fake streams.
|
|
['media.audio_loopback_dev', ''],
|
|
['media.navigator.streams.fake', true],
|
|
['media.navigator.permission.disabled', true]
|
|
]
|
|
});
|
|
|
|
// Test stream source GC
|
|
let stream = await navigator.mediaDevices.getUserMedia({audio: true});
|
|
let source = context.createMediaStreamSource(stream);
|
|
stream = null;
|
|
source.connect(analyser);
|
|
await test(source);
|
|
|
|
// Test track source GC
|
|
stream = await navigator.mediaDevices.getUserMedia({audio: true});
|
|
source = context.createMediaStreamTrackSource(stream.getAudioTracks()[0]);
|
|
stream = null;
|
|
source.connect(analyser);
|
|
await test(source);
|
|
} catch(e) {
|
|
ok(false, `Error executing test: ${e}${e.stack ? "\n" + e.stack : ""}`);
|
|
} finally {
|
|
context.close();
|
|
SimpleTest.finish();
|
|
}
|
|
})();
|
|
</script>
|
|
</pre>
|
|
</body>
|
|
</html>
|