summaryrefslogtreecommitdiffstats
path: root/dom/media/tests/mochitest/test_enumerateDevices.html
blob: dd4db59d763fbac0692060de391b70585982a0e7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
<!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" });
/**
  Tests covering enumerateDevices API and deviceId constraint. Exercise code.
*/

async function mustSucceed(msg, f) {
  try {
    await f();
    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.");
    }
  }
}

var pushPrefs = (...p) => SpecialPowers.pushPrefEnv({set: p});
var gUM = c => navigator.mediaDevices.getUserMedia(c);

var validateDevice = ({kind, label, deviceId, groupId}) => {
  ok(kind == "videoinput" || kind == "audioinput", "Known device kind");
  is(deviceId.length, 44, "deviceId length id as expected for Firefox");
  ok(label.length !== undefined, "Device label: " + label);

  // TODO: s/todo_// once Bug 1213453 is fixed.
  todo_isnot(groupId, "", "groupId must be present.");
}

runTest(async () => {
  await pushPrefs(["media.navigator.streams.fake", true]);

  // Validate enumerated devices.

  let devices = await navigator.mediaDevices.enumerateDevices();
  ok(devices.length > 0, "At least one device found");
  let 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 (let device of devices) {
    validateDevice(device);
    // Test deviceId constraint
    let deviceId = device.deviceId;
    let constraints = (device.kind == "videoinput") ? { video: { deviceId } }
                                                    : { audio: { deviceId } };
    for (let track of (await gUM(constraints)).getTracks()) {
      is(typeof(track.label), "string", "Track label is a string");
      is(track.label, device.label, "Track label is the device label");
      track.stop();
    }
  }

  const unknownId = "unknown9qHr8B0JIbcHlbl9xR+jMbZZ8WyoPfpCXPfc=";

  // Check deviceId failure paths for video.

  await mustSucceed("unknown plain deviceId on video",
                    () => gUM({ video: { deviceId: unknownId } }));
  await mustSucceed("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/tests/mochitest/test_enumerateDevices_iframe.html";
  const origins = ["http://mochi.test:8888", "http://test1.mochi.test:8888"];
  info(window.location);

  let haveDevicesMap = new Promise(resolve => {
    let 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 => {
    let iframe = document.createElement("iframe");
    iframe.src = origin + path;
    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);
  is(differentOriginDevices.length, devices.length);
  [...sameOriginDevices, ...differentOriginDevices].forEach(d => validateDevice(d));

  for (let device of sameOriginDevices) {
    ok(devices.find(d => d.deviceId == device.deviceId),
       "Same origin deviceId for " + device.label + " must match");
  }
  for (let 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();
  ok(devices.length === 0, "No devices found");
});
</script>
</pre>
</body>
</html>