1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
|
<!DOCTYPE HTML>
<html>
<head>
<script src="mediaStreamPlayback.js"></script>
</head>
<body>
<pre id="test">
<script type="application/javascript">
createHTML({
title: "Test changing sink and muting before the MediaStream is set",
bug: "1651049",
visible: true
});
let getOutputDeviceId = async () => {
let devices = await navigator.mediaDevices.enumerateDevices();
let audios = devices.filter(d => d.kind == "audiooutput");
ok(audios.length, "One or more output devices found.");
return audios[0].deviceId;
}
let verifyAudioTone = async (ac, stream, freq) => {
const toneAnalyser = new AudioStreamAnalyser(ac, stream);
return toneAnalyser.waitForAnalysisSuccess(array => {
const lowerFreq = freq / 2;
const upperFreq = freq + 1000;
const lowerMag = array[toneAnalyser.binIndexForFrequency(lowerFreq)];
const freqMag = array[toneAnalyser.binIndexForFrequency(freq)];
const upperMag = array[toneAnalyser.binIndexForFrequency(upperFreq)];
info("Audio tone expected. "
+ lowerFreq + ": " + lowerMag + ", "
+ freq + ": " + freqMag + ", "
+ upperFreq + ": " + upperMag);
return lowerMag < 50 && freqMag > 200 && upperMag < 50;
});
}
let verifyNoAudioTone = async (ac, stream, freq) => {
const toneAnalyser = new AudioStreamAnalyser(ac, stream);
// repeat check 100 times to make sure that it is muted.
let retryCnt = 0;
return toneAnalyser.waitForAnalysisSuccess(array => {
const lowerFreq = freq / 2;
const upperFreq = freq + 1000;
const lowerMag = array[toneAnalyser.binIndexForFrequency(lowerFreq)];
const freqMag = array[toneAnalyser.binIndexForFrequency(freq)];
const upperMag = array[toneAnalyser.binIndexForFrequency(upperFreq)];
info("No audio tone expected. "
+ lowerFreq + ": " + lowerMag + ", "
+ freq + ": " + freqMag + ", "
+ upperFreq + ": " + upperMag);
return lowerMag == 0 && freqMag == 0 && upperMag == 0 && ++retryCnt == 100;
});
}
runTest(async () => {
let audioDevice = SpecialPowers.getCharPref("media.audio_loopback_dev", "");
if (!audioDevice) {
todo(false, "No loopback device set by framework. Try --use-test-media-devices");
return;
}
await pushPrefs(["media.setsinkid.enabled", true]);
// Implicitly expose the loopback device sink by opening the source in the
// same group.
const verifyStream = await getUserMedia({audio: true});
// We gonna test our tone, stop the auto created one.
DefaultLoopbackTone.stop();
let sinkId = await getOutputDeviceId();
isnot(sinkId, "", "SinkId is not null");
let audioElement = createMediaElement('audio', 'audioElement');
audioElement.muted = true;
await audioElement.setSinkId(sinkId);
isnot(audioElement.sinkId, "", "sinkId property of the element is not null");
// The test stream is a sine tone of 1000 Hz
let ac = new AudioContext();
const frequency = 2000;
let stream = createOscillatorStream(ac, frequency);
await verifyAudioTone(ac, stream, frequency);
audioElement.srcObject = stream;
audioElement.play();
// Verify the silent output using the loopback device.
await verifyNoAudioTone(ac, verifyStream, frequency);
info("output is muted");
// Clean up
audioElement.pause();
audioElement.srcObject = null;
verifyStream.getTracks()[0].stop();
});
</script>
</pre>
</body>
</html>
|