tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

test_enumerateDevices.html (5286B)


      1 <!DOCTYPE HTML>
      2 <html>
      3 <head>
      4  <script src="mediaStreamPlayback.js"></script>
      5 </head>
      6 <body>
      7 <pre id="test">
      8 <script type="application/javascript">
      9 createHTML({ title: "Run enumerateDevices code", bug: "1046245" });
     10 /**
     11  Tests covering enumerateDevices API and deviceId constraint. Exercise code.
     12 */
     13 
     14 async function mustSucceedWithStream(msg, f) {
     15  try {
     16    const stream = await f();
     17    for (const track of stream.getTracks()) {
     18      track.stop();
     19    }
     20    ok(true, msg + " must succeed");
     21  } catch (e) {
     22    is(e.name, null, msg + " must succeed: " + e.message);
     23  }
     24 }
     25 
     26 async function mustFailWith(msg, reason, constraint, f) {
     27  try {
     28    await f();
     29    ok(false, msg + " must fail");
     30  } catch(e) {
     31    is(e.name, reason, msg + " must fail: " + e.message);
     32    if (constraint) {
     33      is(e.constraint, constraint, msg + " must fail w/correct constraint.");
     34    }
     35  }
     36 }
     37 
     38 const gUM = c => navigator.mediaDevices.getUserMedia(c);
     39 
     40 const kinds = ["videoinput", "audioinput", "audiooutput"];
     41 
     42 function validateDevice({kind, label, deviceId, groupId}) {
     43  ok(kinds.includes(kind), "Known device kind");
     44  is(deviceId.length, 44, "deviceId length id as expected for Firefox");
     45  ok(label.length !== undefined, "Device label: " + label);
     46  isnot(groupId, "", "groupId must be present.");
     47 }
     48 
     49 runTest(async () => {
     50  await pushPrefs(["media.navigator.streams.fake", true]);
     51 
     52  // Validate enumerated devices after gUM.
     53  for (const track of (await gUM({video: true, audio: true})).getTracks()) {
     54    track.stop();
     55  }
     56 
     57  let devices = await navigator.mediaDevices.enumerateDevices();
     58  ok(devices.length, "At least one device found");
     59  const jsoned = JSON.parse(JSON.stringify(devices));
     60  is(jsoned[0].kind, devices[0].kind, "kind survived serializer");
     61  is(jsoned[0].deviceId, devices[0].deviceId, "deviceId survived serializer");
     62  for (const device of devices) {
     63    validateDevice(device);
     64    if (device.kind == "audiooutput") continue;
     65    // Test deviceId constraint
     66    let deviceId = device.deviceId;
     67    let constraints = (device.kind == "videoinput") ? { video: { deviceId } }
     68                                                    : { audio: { deviceId } };
     69    for (const track of (await gUM(constraints)).getTracks()) {
     70      is(typeof(track.label), "string", "Track label is a string");
     71      is(track.label, device.label, "Track label is the device label");
     72      track.stop();
     73    }
     74  }
     75 
     76  const unknownId = "unknown9qHr8B0JIbcHlbl9xR+jMbZZ8WyoPfpCXPfc=";
     77 
     78  // Check deviceId failure paths for video.
     79 
     80  await mustSucceedWithStream("unknown plain deviceId on video",
     81                              () => gUM({ video: { deviceId: unknownId } }));
     82  await mustSucceedWithStream("unknown plain deviceId on audio",
     83                              () => gUM({ audio: { deviceId: unknownId } }));
     84  await mustFailWith("unknown exact deviceId on video",
     85                     "OverconstrainedError", "deviceId",
     86                     () => gUM({ video: { deviceId: { exact: unknownId } } }));
     87  await mustFailWith("unknown exact deviceId on audio",
     88                     "OverconstrainedError", "deviceId",
     89                     () => gUM({ audio: { deviceId: { exact: unknownId } } }));
     90 
     91  // Check that deviceIds are stable for same origin and differ across origins.
     92 
     93  const path = "/tests/dom/media/webrtc/tests/mochitests/test_enumerateDevices_iframe.html";
     94  const origins = ["https://example.com", "https://test1.example.com"];
     95  info(window.location);
     96 
     97  const haveDevicesMap = new Promise(resolve => {
     98    const map = new Map();
     99    window.addEventListener("message", ({origin, data}) => {
    100      ok(origins.includes(origin), "Got message from expected origin");
    101      map.set(origin, JSON.parse(data));
    102      if (map.size < origins.length) return;
    103      resolve(map);
    104    });
    105  });
    106 
    107  await Promise.all(origins.map(origin => {
    108    const iframe = document.createElement("iframe");
    109    iframe.src = origin + path;
    110    iframe.allow = "camera;microphone;speaker-selection";
    111    info(iframe.src);
    112    document.documentElement.appendChild(iframe);
    113    return new Promise(resolve => iframe.onload = resolve);
    114  }));
    115  let devicesMap = await haveDevicesMap;
    116  let [sameOriginDevices, differentOriginDevices] = origins.map(o => devicesMap.get(o));
    117 
    118  is(sameOriginDevices.length, devices.length, "same origin same devices");
    119  is(differentOriginDevices.length, devices.length, "cross origin same devices");
    120  [...sameOriginDevices, ...differentOriginDevices].forEach(d => validateDevice(d));
    121 
    122  for (const device of sameOriginDevices) {
    123    ok(devices.find(d => d.deviceId == device.deviceId),
    124       "Same origin deviceId for " + device.label + " must match");
    125  }
    126  for (const device of differentOriginDevices) {
    127    ok(!devices.find(d => d.deviceId == device.deviceId),
    128         "Different origin deviceId for " + device.label + " must be different");
    129  }
    130 
    131  // Check the special case of no devices found.
    132  await pushPrefs(["media.navigator.streams.fake", false],
    133                  ["media.audio_loopback_dev", "none"],
    134                  ["media.video_loopback_dev", "none"]);
    135  devices = await navigator.mediaDevices.enumerateDevices();
    136  devices = devices.filter(({kind}) => kind != "audiooutput");
    137  is(devices.length, 0, "No devices");
    138 });
    139 </script>
    140 </pre>
    141 </body>
    142 </html>