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>