166 lines
5.3 KiB
JavaScript
166 lines
5.3 KiB
JavaScript
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
/*
|
|
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.");
|
|
}
|
|
|
|
// Validate enumerated devices before gUM (legacy).
|
|
|
|
async function testLegacyEnumerateDevices() {
|
|
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";
|
|
const origins = ["https://example.com", "https://test1.example.com"];
|
|
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();
|
|
devices = devices.filter(({ kind }) => kind != "audiooutput");
|
|
is(devices.length, 0, "No devices");
|
|
}
|