Source code

Revision control

Copy as Markdown

Other Tools

Test Info:

<!DOCTYPE HTML>
<html>
<head>
<script src="mediaStreamPlayback.js"></script>
</head>
<body>
<pre id="test">
<script type="application/javascript">
createHTML({ title: "Run enumerateDevices code", bug: "1046245" });
/**
This is a modified copy of test_enumerateDevices.html testing the
enumerateDevices() legacy version and deviceId constraint.
*/
async function mustSucceedWithStream(msg, f) {
try {
const stream = await f();
for (const track of stream.getTracks()) {
track.stop();
}
ok(true, msg + " must succeed");
} catch (e) {
is(e.name, null, msg + " must succeed: " + e.message);
}
}
async function mustFailWith(msg, reason, constraint, f) {
try {
await f();
ok(false, msg + " must fail");
} catch(e) {
is(e.name, reason, msg + " must fail: " + e.message);
if (constraint) {
is(e.constraint, constraint, msg + " must fail w/correct constraint.");
}
}
}
const gUM = c => navigator.mediaDevices.getUserMedia(c);
const kinds = ["videoinput", "audioinput", "audiooutput"];
function validateDevice({kind, label, deviceId, groupId}) {
ok(kinds.includes(kind), "Known device kind");
is(deviceId.length, 44, "deviceId length id as expected for Firefox");
ok(label.length !== undefined, "Device label: " + label);
isnot(groupId, "", "groupId must be present.");
}
runTest(async () => {
await pushPrefs(["media.navigator.streams.fake", true],
["media.devices.enumerate.legacy.enabled", true]);
// Validate enumerated devices before gUM (legacy).
let devices = await navigator.mediaDevices.enumerateDevices();
ok(devices.length, "At least one device found");
const jsoned = JSON.parse(JSON.stringify(devices));
is(jsoned[0].kind, devices[0].kind, "kind survived serializer");
is(jsoned[0].deviceId, devices[0].deviceId, "deviceId survived serializer");
for (const device of devices) {
validateDevice(device);
if (device.kind == "audiooutput") continue;
is(device.label, "", "Device label is empty");
// Test deviceId constraint
let deviceId = device.deviceId;
let constraints = (device.kind == "videoinput") ? { video: { deviceId } }
: { audio: { deviceId } };
let namedDevices;
for (const track of (await gUM(constraints)).getTracks()) {
is(typeof(track.label), "string", "Track label is a string");
isnot(track.label.length, 0, "Track label is not empty");
if (!namedDevices) {
namedDevices = await navigator.mediaDevices.enumerateDevices();
}
const namedDevice = namedDevices.find(d => d.deviceId == device.deviceId);
is(track.label, namedDevice.label, "Track label is the device label");
track.stop();
}
}
const unknownId = "unknown9qHr8B0JIbcHlbl9xR+jMbZZ8WyoPfpCXPfc=";
// Check deviceId failure paths for video.
await mustSucceedWithStream("unknown plain deviceId on video",
() => gUM({ video: { deviceId: unknownId } }));
await mustSucceedWithStream("unknown plain deviceId on audio",
() => gUM({ audio: { deviceId: unknownId } }));
await mustFailWith("unknown exact deviceId on video",
"OverconstrainedError", "deviceId",
() => gUM({ video: { deviceId: { exact: unknownId } } }));
await mustFailWith("unknown exact deviceId on audio",
"OverconstrainedError", "deviceId",
() => gUM({ audio: { deviceId: { exact: unknownId } } }));
// Check that deviceIds are stable for same origin and differ across origins.
const path = "/tests/dom/media/webrtc/tests/mochitests/test_enumerateDevices_iframe_pre_gum.html";
info(window.location);
const haveDevicesMap = new Promise(resolve => {
const map = new Map();
window.addEventListener("message", ({origin, data}) => {
ok(origins.includes(origin), "Got message from expected origin");
map.set(origin, JSON.parse(data));
if (map.size < origins.length) return;
resolve(map);
});
});
await Promise.all(origins.map(origin => {
const iframe = document.createElement("iframe");
iframe.src = origin + path;
iframe.allow = "camera;microphone;speaker-selection";
info(iframe.src);
document.documentElement.appendChild(iframe);
return new Promise(resolve => iframe.onload = resolve);
}));
let devicesMap = await haveDevicesMap;
let [sameOriginDevices, differentOriginDevices] = origins.map(o => devicesMap.get(o));
is(sameOriginDevices.length, devices.length, "same origin same devices");
is(differentOriginDevices.length, devices.length, "cross origin same devices");
[...sameOriginDevices, ...differentOriginDevices].forEach(d => validateDevice(d));
for (const device of sameOriginDevices) {
ok(devices.find(d => d.deviceId == device.deviceId),
"Same origin deviceId for " + device.label + " must match");
}
for (const device of differentOriginDevices) {
ok(!devices.find(d => d.deviceId == device.deviceId),
"Different origin deviceId for " + device.label + " must be different");
}
// Check the special case of no devices found.
await pushPrefs(["media.navigator.streams.fake", false],
["media.audio_loopback_dev", "none"],
["media.video_loopback_dev", "none"]);
devices = await navigator.mediaDevices.enumerateDevices();
is(devices.length, 0, "No devices");
});
</script>
</pre>
</body>
</html>