Bug 1436523 - Update dom/media/tests/mochitest tests to better handle loopback devices. r=achronop

With changes giving loopback devices higher precedence in testing, various tests
in dom/media/tests/mochitest have been updated to accommodate this. Many tests
just worked, but some require tweaks, or to explicitly request fake devices.

Also update webaudio's test_mediaStreamAudioSourceNodeGC test to explicitly use
fake devices. This test does not have the loopback tone exposed to it in JS, so
is unabel to adjust the loopback tone to suit its needs.

Various tests are updated to set fake device prefs instead of requesting via
gUM to move away from non-standard behaviour per bug 1436424.

MozReview-Commit-ID: 5GAVZFzF2hq

--HG--
extra : rebase_source : 27f39e3573eda321025ce0739e1d5f4101fc5d12
This commit is contained in:
Bryce Van Dyk 2018-02-26 12:20:40 -05:00
Родитель 898975f341
Коммит da98dea96a
12 изменённых файлов: 120 добавлений и 70 удалений

Просмотреть файл

@ -61,9 +61,9 @@ function testMultipleFingerprints() {
(e => ok(false, 'error in ' + msg + ': ' + (e => ok(false, 'error in ' + msg + ': ' +
(e.message ? (e.message + '\n' + e.stack) : e))); (e.message ? (e.message + '\n' + e.stack) : e)));
navigator.mediaDevices.getUserMedia({ audio: true, fake: true }) navigator.mediaDevices.getUserMedia({ audio: true })
.then(stream => { .then(stream => {
ok(stream, 'Got fake stream'); ok(stream, 'Got test stream');
pcDouble.addStream(stream); pcDouble.addStream(stream);
return pcDouble.createOffer(); return pcDouble.createOffer();
}) })
@ -104,7 +104,17 @@ function testMultipleFingerprints() {
SimpleTest.waitForExplicitFinish(); SimpleTest.waitForExplicitFinish();
SpecialPowers.pushPrefEnv({ SpecialPowers.pushPrefEnv({
set: [ [ 'media.peerconnection.identity.enabled', true ] ] set: [
[ 'media.peerconnection.identity.enabled', true ],
// Disable permission to skip prompt when on platforms the use loopback
// test devices (these would normally trigger a prompt).
[ 'media.navigator.permission.disabled', true ],
// Since this test doesn't include head.js or pc.js, we need to set the fake
// device pref manually. On platforms where loopback devices are used they
// should still take precedence, however on some platforms no prefs would
// be set and the test would fail.
[ 'media.navigator.streams.fake', true ]
]
}, testMultipleFingerprints); }, testMultipleFingerprints);
</script> </script>
</body> </body>

Просмотреть файл

@ -48,10 +48,10 @@ var tests = [
constraints: { }, constraints: { },
error: "TypeError" }, error: "TypeError" },
{ message: "Triggering mock failure in default video device fails", { message: "Triggering mock failure in default video device fails",
constraints: { video: { deviceId: 'bad device' }, fake: true }, constraints: { video: { deviceId: 'bad device' } },
error: "NotReadableError" }, error: "NotReadableError" },
{ message: "Triggering mock failure in default audio device fails", { message: "Triggering mock failure in default audio device fails",
constraints: { audio: { deviceId: 'bad device' }, fake: true }, constraints: { audio: { deviceId: 'bad device' } },
error: "NotReadableError" }, error: "NotReadableError" },
{ message: "Success-path: optional video facingMode + audio ignoring facingMode", { message: "Success-path: optional video facingMode + audio ignoring facingMode",
constraints: { audio: { mediaSource: 'microphone', constraints: { audio: { mediaSource: 'microphone',
@ -101,7 +101,13 @@ var mustFailWith = (msg, reason, constraint, f) =>
* test by verifying that the right resolution and rejection is fired. * test by verifying that the right resolution and rejection is fired.
*/ */
runTest(() => Promise.resolve() runTest(() => pushPrefs(
// This test expects fake devices, particularly for the 'triggering mock
// failure *' steps. So explicitly disable loopback and setup fakes
['media.audio_loopback_dev', ''],
['media.video_loopback_dev', ''],
['media.navigator.streams.fake', true]
)
.then(() => { .then(() => {
// Check supported constraints first. // Check supported constraints first.
var dict = navigator.mediaDevices.getSupportedConstraints(); var dict = navigator.mediaDevices.getSupportedConstraints();

Просмотреть файл

@ -20,8 +20,15 @@ var captureStreamElement;
const pausedTimeout = 1000; const pausedTimeout = 1000;
let h; let h;
runTest(() => getUserMedia({video: true, fake: true}) runTest(async () => {
.then(stream => { try {
await pushPrefs(
// This test expects fake video devices, as it expects captured frames to
// shift over time, which is not currently provided by loopback devices
['media.video_loopback_dev', ''],
['media.navigator.streams.fake', true]);
let stream = await getUserMedia({video: true});
h = new VideoStreamHelper(); h = new VideoStreamHelper();
gUMVideoElement = gUMVideoElement =
createMediaElement("video", "gUMVideo"); createMediaElement("video", "gUMVideo");
@ -42,51 +49,40 @@ runTest(() => getUserMedia({video: true, fake: true})
let osc = createOscillatorStream(new AudioContext(), 1000); let osc = createOscillatorStream(new AudioContext(), 1000);
captureStreamElement.srcObject.addTrack(osc.getTracks()[0]); captureStreamElement.srcObject.addTrack(osc.getTracks()[0]);
return h.checkVideoPlaying(captureStreamElement); await h.checkVideoPlaying(captureStreamElement);
})
.then(() => {
info("Video flowing. Pausing."); info("Video flowing. Pausing.");
gUMVideoElement.pause(); gUMVideoElement.pause();
await h.checkVideoPaused(captureStreamElement, { time: pausedTimeout });
return h.checkVideoPaused(captureStreamElement, { time: pausedTimeout });
})
.then(() => {
info("Video stopped flowing. Playing."); info("Video stopped flowing. Playing.");
gUMVideoElement.play(); gUMVideoElement.play();
await h.checkVideoPlaying(captureStreamElement);
return h.checkVideoPlaying(captureStreamElement);
})
.then(() => {
info("Video flowing. Removing source."); info("Video flowing. Removing source.");
var stream = gUMVideoElement.srcObject; stream = gUMVideoElement.srcObject;
gUMVideoElement.srcObject = null; gUMVideoElement.srcObject = null;
await h.checkVideoPaused(captureStreamElement, { time: pausedTimeout });
return h.checkVideoPaused(captureStreamElement, { time: pausedTimeout })
.then(() => stream);
})
.then(stream => {
info("Video stopped flowing. Setting source."); info("Video stopped flowing. Setting source.");
gUMVideoElement.srcObject = stream; gUMVideoElement.srcObject = stream;
return h.checkVideoPlaying(captureStreamElement); await h.checkVideoPlaying(captureStreamElement);
})
.then(() => {
info("Video flowing. Changing source by track manipulation. Remove first."); info("Video flowing. Changing source by track manipulation. Remove first.");
var track = gUMVideoElement.srcObject.getTracks()[0]; let track = gUMVideoElement.srcObject.getTracks()[0];
gUMVideoElement.srcObject.removeTrack(track); gUMVideoElement.srcObject.removeTrack(track);
return h.checkVideoPaused(captureStreamElement, { time: pausedTimeout }) await h.checkVideoPaused(captureStreamElement, { time: pausedTimeout });
.then(() => track);
})
.then(track => {
info("Video paused. Changing source by track manipulation. Add first."); info("Video paused. Changing source by track manipulation. Add first.");
gUMVideoElement.srcObject.addTrack(track); gUMVideoElement.srcObject.addTrack(track);
gUMVideoElement.play(); gUMVideoElement.play();
return h.checkVideoPlaying(captureStreamElement); await h.checkVideoPlaying(captureStreamElement);
})
.then(() => {
gUMVideoElement.srcObject.getTracks().forEach(t => t.stop()); gUMVideoElement.srcObject.getTracks().forEach(t => t.stop());
ok(true, "Test passed."); ok(true, "Test passed.");
}) } catch (e) {
.catch(e => ok(false, "Test failed: " + e + (e.stack ? "\n" + e.stack : "")))); ok(false, "Test failed: " + e + (e.stack ? "\n" + e.stack : ""));
}
});
</script> </script>
</pre> </pre>

Просмотреть файл

@ -12,16 +12,20 @@
title: "Renegotiation: add second video stream" title: "Renegotiation: add second video stream"
}); });
runNetworkTest(function (options) { runNetworkTest(async function (options) {
// Use fake video here since the native fake device on linux doesn't
// change color as needed by checkVideoPlaying() below.
await pushPrefs(
['media.video_loopback_dev', ''],
['media.navigator.streams.fake', true]);
const test = new PeerConnectionTest(options); const test = new PeerConnectionTest(options);
addRenegotiation(test.chain, addRenegotiation(test.chain,
[ [
function PC_LOCAL_ADD_SECOND_STREAM(test) { function PC_LOCAL_ADD_SECOND_STREAM(test) {
test.setMediaConstraints([{video: true}, {video: true}], test.setMediaConstraints([{video: true}, {video: true}],
[{video: true}]); [{video: true}]);
// Use fake:true here since the native fake device on linux doesn't return test.pcLocal.getAllUserMediaAndAddStreams([{video: true}]);
// change color as needed by checkVideoPlaying() below.
return test.pcLocal.getAllUserMediaAndAddStreams([{video: true, fake: true}]);
}, },
], ],
[ [

Просмотреть файл

@ -12,7 +12,13 @@
title: "Renegotiation: add second video stream, no bundle" title: "Renegotiation: add second video stream, no bundle"
}); });
runNetworkTest(function (options = {}) { runNetworkTest(async function (options = {}) {
// Use fake video here since the native fake device on linux doesn't
// change color as needed by checkVideoPlaying() below.
await pushPrefs(
['media.video_loopback_dev', ''],
['media.navigator.streams.fake', true]);
options.bundle = false; options.bundle = false;
const test = new PeerConnectionTest(options); const test = new PeerConnectionTest(options);
addRenegotiation(test.chain, addRenegotiation(test.chain,
@ -23,9 +29,7 @@
// Since this is a NoBundle variant, adding a track will cause us to // Since this is a NoBundle variant, adding a track will cause us to
// go back to checking. // go back to checking.
test.pcLocal.expectIceChecking(); test.pcLocal.expectIceChecking();
// Use fake:true here since the native fake device on linux doesn't return test.pcLocal.getAllUserMediaAndAddStreams([{video: true}]);
// change color as needed by checkVideoPlaying() below.
return test.pcLocal.getAllUserMediaAndAddStreams([{video: true, fake: true}]);
}, },
function PC_REMOTE_EXPECT_ICE_CHECKING(test) { function PC_REMOTE_EXPECT_ICE_CHECKING(test) {
test.pcRemote.expectIceChecking(); test.pcRemote.expectIceChecking();
@ -42,7 +46,7 @@
] ]
); );
test.setMediaConstraints([{video: true, fake: true}], [{video: true}]); test.setMediaConstraints([{video: true}], [{video: true}]);
test.run(); test.run();
}); });
</script> </script>

Просмотреть файл

@ -20,7 +20,7 @@
options.opus = codec == "opus"; options.opus = codec == "opus";
let test = new PeerConnectionTest(options); let test = new PeerConnectionTest(options);
test.setMediaConstraints([{audio: true, fake: true}], []); test.setMediaConstraints([{audio: true}], []);
test.chain.insertBefore("PC_LOCAL_SET_LOCAL_DESCRIPTION", [ test.chain.insertBefore("PC_LOCAL_SET_LOCAL_DESCRIPTION", [
function PC_LOCAL_FILTER_OUT_CODECS() { function PC_LOCAL_FILTER_OUT_CODECS() {

Просмотреть файл

@ -12,7 +12,13 @@
title: "Renegotiation: remove then add video track" title: "Renegotiation: remove then add video track"
}); });
runNetworkTest(function (options) { runNetworkTest(async function (options) {
// Use fake video here since the native fake device on linux doesn't
// change color as needed by checkVideoPlaying() below.
await pushPrefs(
['media.video_loopback_dev', ''],
['media.navigator.streams.fake', true]);
const test = new PeerConnectionTest(options); const test = new PeerConnectionTest(options);
const helper = new VideoStreamHelper(); const helper = new VideoStreamHelper();
var originalTrack; var originalTrack;
@ -33,9 +39,7 @@
return test.pcLocal.removeSender(0); return test.pcLocal.removeSender(0);
}, },
function PC_LOCAL_ADD_VIDEO_TRACK(test) { function PC_LOCAL_ADD_VIDEO_TRACK(test) {
// Use fake:true here since the native fake device on linux doesn't return test.pcLocal.getAllUserMediaAndAddStreams([{video: true}]);
// change color as needed by checkVideoPlaying() below.
return test.pcLocal.getAllUserMediaAndAddStreams([{video: true, fake: true}]);
}, },
], ],
[ [

Просмотреть файл

@ -12,7 +12,13 @@
title: "Renegotiation: remove then add video track, no bundle" title: "Renegotiation: remove then add video track, no bundle"
}); });
runNetworkTest(function (options) { runNetworkTest(async function (options) {
// Use fake video here since the native fake device on linux doesn't
// change color as needed by checkVideoPlaying() below.
await pushPrefs(
['media.video_loopback_dev', ''],
['media.navigator.streams.fake', true]);
options = options || { }; options = options || { };
options.bundle = false; options.bundle = false;
const test = new PeerConnectionTest(options); const test = new PeerConnectionTest(options);
@ -35,7 +41,7 @@
function PC_LOCAL_ADD_VIDEO_TRACK(test) { function PC_LOCAL_ADD_VIDEO_TRACK(test) {
// Use fake:true here since the native fake device on linux doesn't // Use fake:true here since the native fake device on linux doesn't
// change color as needed by checkVideoPlaying() below. // change color as needed by checkVideoPlaying() below.
return test.pcLocal.getAllUserMediaAndAddStreams([{video: true, fake: true}]); return test.pcLocal.getAllUserMediaAndAddStreams([{video: true}]);
}, },
function PC_LOCAL_EXPECT_ICE_CHECKING(test) { function PC_LOCAL_EXPECT_ICE_CHECKING(test) {
test.pcLocal.expectIceChecking(); test.pcLocal.expectIceChecking();

Просмотреть файл

@ -19,7 +19,12 @@ runNetworkTest(async () => {
["media.getusermedia.camera.stop_on_disable.enabled", true], ["media.getusermedia.camera.stop_on_disable.enabled", true],
["media.getusermedia.camera.stop_on_disable.delay_ms", 0], ["media.getusermedia.camera.stop_on_disable.delay_ms", 0],
["media.getusermedia.microphone.stop_on_disable.enabled", true], ["media.getusermedia.microphone.stop_on_disable.enabled", true],
["media.getusermedia.microphone.stop_on_disable.delay_ms", 0]); ["media.getusermedia.microphone.stop_on_disable.delay_ms", 0],
// Always use fake tracks since we depend on video to be somewhat green and
// audio to have a large 1000Hz component (or 440Hz if using fake devices).
['media.audio_loopback_dev', ''],
['media.video_loopback_dev', ''],
['media.navigator.streams.fake', true]);
test.setMediaConstraints([{audio: true, video: true}], []); test.setMediaConstraints([{audio: true, video: true}], []);
test.chain.append([ test.chain.append([

Просмотреть файл

@ -19,7 +19,11 @@ runNetworkTest(async () => {
["media.getusermedia.camera.stop_on_disable.enabled", true], ["media.getusermedia.camera.stop_on_disable.enabled", true],
["media.getusermedia.camera.stop_on_disable.delay_ms", 0], ["media.getusermedia.camera.stop_on_disable.delay_ms", 0],
["media.getusermedia.microphone.stop_on_disable.enabled", true], ["media.getusermedia.microphone.stop_on_disable.enabled", true],
["media.getusermedia.microphone.stop_on_disable.delay_ms", 0]); ["media.getusermedia.microphone.stop_on_disable.delay_ms", 0],
// Always use fake tracks since we depend on audio to have a large 1000Hz
// component.
['media.audio_loopback_dev', ''],
['media.navigator.streams.fake', true]);
var originalStream; var originalStream;
var localVideoOriginal; var localVideoOriginal;

Просмотреть файл

@ -14,7 +14,7 @@
async function testVideoCodec(options = {}, codec) { async function testVideoCodec(options = {}, codec) {
let test = new PeerConnectionTest(options); let test = new PeerConnectionTest(options);
test.setMediaConstraints([{video: true, fake: true}], []); test.setMediaConstraints([{video: true}], []);
test.chain.insertBefore("PC_LOCAL_SET_LOCAL_DESCRIPTION", [ test.chain.insertBefore("PC_LOCAL_SET_LOCAL_DESCRIPTION", [
function PC_LOCAL_FILTER_OUT_CODECS() { function PC_LOCAL_FILTER_OUT_CODECS() {
@ -72,6 +72,11 @@
]; ];
runNetworkTest(async (options) => { runNetworkTest(async (options) => {
// This test expects the video being captured will change color. Use fake
// video device as loopback does not currently change.
await pushPrefs(
['media.video_loopback_dev', ''],
['media.navigator.streams.fake', true]);
for (let codec of codecs) { for (let codec of codecs) {
info(`Testing video for codec ${codec.name}`); info(`Testing video for codec ${codec.name}`);
try { try {

Просмотреть файл

@ -50,19 +50,26 @@ function waitForAudio(analysisFunction, cancelPromise) {
}); });
} }
navigator.mediaDevices.getUserMedia({audio: true, fake: true}) SpecialPowers.pushPrefEnv({
.then(stream => { 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]
]
}).then(async () => {
try {
let stream = await navigator.mediaDevices.getUserMedia({audio: true});
stream.onended = () => ended = true; stream.onended = () => ended = true;
let source = context.createMediaStreamSource(stream); let source = context.createMediaStreamSource(stream);
source.connect(analyser); source.connect(analyser);
analyser.connect(context.destination); await analyser.connect(context.destination);
})
.then(() => {
ok(true, "Waiting for audio to pass through the analyser") ok(true, "Waiting for audio to pass through the analyser")
return waitForAudio(arr => arr[binIndexForFrequency(1000)] > 200, await waitForAudio(arr => arr[binIndexForFrequency(1000)] > 200,
wait(60000, "Timeout waiting for audio")); wait(60000, "Timeout waiting for audio"));
})
.then(() => {
ok(true, "Audio was detected by the analyser. Forcing CC."); ok(true, "Audio was detected by the analyser. Forcing CC.");
SpecialPowers.forceCC(); SpecialPowers.forceCC();
SpecialPowers.forceGC(); SpecialPowers.forceGC();
@ -70,19 +77,18 @@ navigator.mediaDevices.getUserMedia({audio: true, fake: true})
SpecialPowers.forceGC(); SpecialPowers.forceGC();
info("Checking that GC didn't destroy the stream or source node"); info("Checking that GC didn't destroy the stream or source node");
return waitForAudio(arr => arr[binIndexForFrequency(1000)] < 50, await waitForAudio(arr => arr[binIndexForFrequency(1000)] < 50,
wait(5000, "Timeout waiting for GC (timeout OK)")) wait(5000, "Timeout waiting for GC (timeout OK)"))
.then(() => Promise.reject("Audio stopped unexpectedly"), .then(() => Promise.reject("Audio stopped unexpectedly"),
() => Promise.resolve()); () => Promise.resolve());
})
.then(() => {
ok(true, "Audio is still flowing"); ok(true, "Audio is still flowing");
SimpleTest.finish(); SimpleTest.finish();
}) } catch(e) {
.catch(e => {
ok(false, "Error executing test: " + e + (e.stack ? "\n" + e.stack : "")); ok(false, "Error executing test: " + e + (e.stack ? "\n" + e.stack : ""));
SimpleTest.finish(); SimpleTest.finish();
}); }
});
</script> </script>
</pre> </pre>
</body> </body>