summaryrefslogtreecommitdiffstats
path: root/dom/media/webrtc/tests/mochitests/test_setSinkId-echoCancellation.html
diff options
context:
space:
mode:
Diffstat (limited to 'dom/media/webrtc/tests/mochitests/test_setSinkId-echoCancellation.html')
-rw-r--r--dom/media/webrtc/tests/mochitests/test_setSinkId-echoCancellation.html110
1 files changed, 110 insertions, 0 deletions
diff --git a/dom/media/webrtc/tests/mochitests/test_setSinkId-echoCancellation.html b/dom/media/webrtc/tests/mochitests/test_setSinkId-echoCancellation.html
new file mode 100644
index 0000000000..fa13b72bfb
--- /dev/null
+++ b/dom/media/webrtc/tests/mochitests/test_setSinkId-echoCancellation.html
@@ -0,0 +1,110 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<title></title>
+<script src="mediaStreamPlayback.js"></script>
+</head>
+<script>
+"use strict";
+
+createHTML({
+ title: "Test echoCancellation with setSinkId()",
+ bug: "1849108",
+ visible: true,
+});
+/**
+This test captures audio from a loopback device to test echo cancellation.
+ **/
+runTest(async () => {
+ await SpecialPowers.pushPrefEnv({set: [
+ // skip selectAudioOutput/getUserMedia permission prompt
+ ["media.navigator.permission.disabled", true],
+ // enumerateDevices() without focus
+ ["media.devices.unfocused.enabled", true],
+ ]});
+
+ const ac = new AudioContext();
+ const dest = new MediaStreamAudioDestinationNode(ac);
+ const gain = new GainNode(ac, {gain: 0.5});
+ gain.connect(dest);
+ // Use a couple of triangle waves for audio with some bandwidth.
+ // Pick incommensurable frequencies so that the audio is aperiodic.
+ // Perhaps that might help the AEC determine the delay.
+ const osc1 =
+ new OscillatorNode(ac, {type: "triangle", frequency: 200});
+ const osc2 =
+ new OscillatorNode(ac, {type: "triangle", frequency: Math.PI * 100});
+ osc1.connect(gain);
+ osc2.connect(gain);
+ osc1.start();
+ osc2.start();
+ const audio = new Audio();
+ audio.srcObject = dest.stream;
+ audio.controls = true;
+ document.body.appendChild(audio);
+
+ // The loopback device is currenly only available on Linux.
+ let loopbackInputLabel =
+ SpecialPowers.getCharPref("media.audio_loopback_dev", "");
+ if (!navigator.userAgent.includes("Linux")) {
+ todo_isnot(loopbackInputLabel, "", "audio_loopback_dev");
+ return;
+ }
+ isnot(loopbackInputLabel, "",
+ "audio_loopback_dev. Use --use-test-media-devices.");
+
+ const loopbackStream = await navigator.mediaDevices.getUserMedia({ audio: {
+ echoCancellation: false,
+ autoGainControl: false,
+ noiseSuppression: false,
+ }});
+ is(loopbackStream.getTracks()[0].label, loopbackInputLabel,
+ "loopback track label");
+
+ // Check that the loopback stream contains silence now.
+ const loopbackNode = ac.createMediaStreamSource(loopbackStream);
+ const processor1 = ac.createScriptProcessor(4096, 1, 0);
+ loopbackNode.connect(processor1);
+ const {inputBuffer} = await new Promise(r => processor1.onaudioprocess = r);
+ loopbackNode.disconnect();
+ is(inputBuffer.getChannelData(0).find(value => value != 0.0), undefined,
+ "should have silence in loopback input");
+
+ // Find the loopback output device
+ const devices = await navigator.mediaDevices.enumerateDevices();
+ let loopbackOutputLabel =
+ SpecialPowers.getCharPref("media.cubeb.output_device", "");
+ const outputDeviceInfo = devices.find(
+ ({kind, label}) => kind == "audiooutput" && label == loopbackOutputLabel
+ );
+ ok(outputDeviceInfo, `found "${loopbackOutputLabel}"`);
+
+ await audio.setSinkId(outputDeviceInfo.deviceId);
+ await audio.play();
+
+ const analyser = new AudioStreamAnalyser(ac, loopbackStream);
+ const bin1 = analyser.binIndexForFrequency(osc1.frequency.value);
+ const bin2 = analyser.binIndexForFrequency(osc2.frequency.value);
+ try {
+ analyser.enableDebugCanvas();
+ // Check for audio with AEC.
+ await analyser.waitForAnalysisSuccess(array => {
+ return array[bin1] > 200 && array[bin2] > 200;
+ });
+
+ // Check echo cancellation.
+ await loopbackStream.getTracks()[0].applyConstraints({
+ echoCancellation: true,
+ autoGainControl: false,
+ noiseSuppression: false,
+ });
+ await analyser.waitForAnalysisSuccess(array => {
+ return !array.find(bin => bin > 50);
+ });
+ } finally {
+ await ac.close();
+ loopbackStream.getTracks()[0].stop();
+ }
+});
+</script>
+</html>