tor-browser

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

testLegacyEnumerateDevices.js (5474B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 /*
      5  This is a modified copy of test_enumerateDevices.html testing the
      6  enumerateDevices() legacy version and deviceId constraint.
      7 */
      8 
      9 async function mustSucceedWithStream(msg, f) {
     10  try {
     11    const stream = await f();
     12    for (const track of stream.getTracks()) {
     13      track.stop();
     14    }
     15    ok(true, msg + " must succeed");
     16  } catch (e) {
     17    is(e.name, null, msg + " must succeed: " + e.message);
     18  }
     19 }
     20 
     21 async function mustFailWith(msg, reason, constraint, f) {
     22  try {
     23    await f();
     24    ok(false, msg + " must fail");
     25  } catch (e) {
     26    is(e.name, reason, msg + " must fail: " + e.message);
     27    if (constraint) {
     28      is(e.constraint, constraint, msg + " must fail w/correct constraint.");
     29    }
     30  }
     31 }
     32 
     33 const gUM = c => navigator.mediaDevices.getUserMedia(c);
     34 
     35 const kinds = ["videoinput", "audioinput", "audiooutput"];
     36 
     37 function validateDevice({ kind, label, deviceId, groupId }) {
     38  ok(kinds.includes(kind), "Known device kind");
     39  is(deviceId.length, 44, "deviceId length id as expected for Firefox");
     40  ok(label.length !== undefined, "Device label: " + label);
     41  isnot(groupId, "", "groupId must be present.");
     42 }
     43 
     44 // Validate enumerated devices before gUM (legacy).
     45 
     46 async function testLegacyEnumerateDevices() {
     47  let devices = await navigator.mediaDevices.enumerateDevices();
     48  ok(devices.length, "At least one device found");
     49  const jsoned = JSON.parse(JSON.stringify(devices));
     50  is(jsoned[0].kind, devices[0].kind, "kind survived serializer");
     51  is(jsoned[0].deviceId, devices[0].deviceId, "deviceId survived serializer");
     52  for (const device of devices) {
     53    validateDevice(device);
     54    if (device.kind == "audiooutput") {
     55      continue;
     56    }
     57    is(device.label, "", "Device label is empty");
     58    // Test deviceId constraint
     59    let deviceId = device.deviceId;
     60    let constraints =
     61      device.kind == "videoinput"
     62        ? { video: { deviceId } }
     63        : { audio: { deviceId } };
     64    let namedDevices;
     65    for (const track of (await gUM(constraints)).getTracks()) {
     66      is(typeof track.label, "string", "Track label is a string");
     67      isnot(track.label.length, 0, "Track label is not empty");
     68      if (!namedDevices) {
     69        namedDevices = await navigator.mediaDevices.enumerateDevices();
     70      }
     71      const namedDevice = namedDevices.find(d => d.deviceId == device.deviceId);
     72      is(track.label, namedDevice.label, "Track label is the device label");
     73      track.stop();
     74    }
     75  }
     76 
     77  const unknownId = "unknown9qHr8B0JIbcHlbl9xR+jMbZZ8WyoPfpCXPfc=";
     78 
     79  // Check deviceId failure paths for video.
     80 
     81  await mustSucceedWithStream("unknown plain deviceId on video", () =>
     82    gUM({ video: { deviceId: unknownId } })
     83  );
     84  await mustSucceedWithStream("unknown plain deviceId on audio", () =>
     85    gUM({ audio: { deviceId: unknownId } })
     86  );
     87  await mustFailWith(
     88    "unknown exact deviceId on video",
     89    "OverconstrainedError",
     90    "deviceId",
     91    () => gUM({ video: { deviceId: { exact: unknownId } } })
     92  );
     93  await mustFailWith(
     94    "unknown exact deviceId on audio",
     95    "OverconstrainedError",
     96    "deviceId",
     97    () => gUM({ audio: { deviceId: { exact: unknownId } } })
     98  );
     99 
    100  // Check that deviceIds are stable for same origin and differ across origins.
    101 
    102  const path =
    103    "/tests/dom/media/webrtc/tests/mochitests/test_enumerateDevices_iframe_pre_gum.html";
    104  const origins = ["https://example.com", "https://test1.example.com"];
    105  info(window.location);
    106 
    107  const haveDevicesMap = new Promise(resolve => {
    108    const map = new Map();
    109    window.addEventListener("message", ({ origin, data }) => {
    110      ok(origins.includes(origin), "Got message from expected origin");
    111      map.set(origin, JSON.parse(data));
    112      if (map.size < origins.length) {
    113        return;
    114      }
    115      resolve(map);
    116    });
    117  });
    118 
    119  await Promise.all(
    120    origins.map(origin => {
    121      const iframe = document.createElement("iframe");
    122      iframe.src = origin + path;
    123      iframe.allow = "camera;microphone;speaker-selection";
    124      info(iframe.src);
    125      document.documentElement.appendChild(iframe);
    126      return new Promise(resolve => (iframe.onload = resolve));
    127    })
    128  );
    129  let devicesMap = await haveDevicesMap;
    130  let [sameOriginDevices, differentOriginDevices] = origins.map(o =>
    131    devicesMap.get(o)
    132  );
    133 
    134  is(sameOriginDevices.length, devices.length, "same origin same devices");
    135  is(
    136    differentOriginDevices.length,
    137    devices.length,
    138    "cross origin same devices"
    139  );
    140  [...sameOriginDevices, ...differentOriginDevices].forEach(d =>
    141    validateDevice(d)
    142  );
    143 
    144  for (const device of sameOriginDevices) {
    145    ok(
    146      devices.find(d => d.deviceId == device.deviceId),
    147      "Same origin deviceId for " + device.label + " must match"
    148    );
    149  }
    150  for (const device of differentOriginDevices) {
    151    ok(
    152      !devices.find(d => d.deviceId == device.deviceId),
    153      "Different origin deviceId for " + device.label + " must be different"
    154    );
    155  }
    156 
    157  // Check the special case of no devices found.
    158  await pushPrefs(
    159    ["media.navigator.streams.fake", false],
    160    ["media.audio_loopback_dev", "none"],
    161    ["media.video_loopback_dev", "none"]
    162  );
    163  devices = await navigator.mediaDevices.enumerateDevices();
    164  devices = devices.filter(({ kind }) => kind != "audiooutput");
    165  is(devices.length, 0, "No devices");
    166 }