setSinkId-manual.https.html (6724B)
1 <!doctype html> 2 <html> 3 <head> 4 <title>Test setSinkId behavior with permissions / device changes</title> 5 <link rel="author" title="Dominique Hazael-Massieux" href="mailto:dom@w3.org"/> 6 <link rel="help" href="https://www.w3.org/TR/audio-output/#dom-htmlmediaelement-setsinkid"> 7 <meta name="timeout" content="long"> 8 9 </head> 10 <body> 11 <h1 class="instructions">Description</h1> 12 <p class="instructions">This test checks that <code>setSinkId</code> follows the algorithm, this includes manually checking the proper rendering on new output devices.</p> 13 <p class="instructions">When prompted to access microphones, please accept as this is the only current way to get permissions for associated output devices.</p> 14 <p class="instructions">For each authorized output device, check that selecting it makes the audio beat rendered on the corresponding device.</p> 15 <p>Available but unauthorized devices (only those for which we can gain permission can be selected):</p> 16 <ul id="available"></ul> 17 <p>Authorized devices:</p> 18 <ul id="authorized"></ul> 19 <audio controls id="beat" src="/media/sound_5.mp3" loop></audio> 20 21 <div id='log'></div> 22 <script src=/resources/testharness.js></script> 23 <script src=/resources/testharnessreport.js></script> 24 <script> 25 "use strict"; 26 27 const is_output = d => d.kind === "audiooutput"; 28 const by_id = (id) => d => d.groupId === id; 29 const is_input = d => d.kind === "audioinput"; 30 const audio = document.getElementById("beat"); 31 const available = document.getElementById("available"); 32 const authorized = document.getElementById("authorized"); 33 34 let outputList; 35 36 const selectDeviceTester = (t) => (e) => { 37 const groupId = e.target.dataset["groupid"]; 38 const device = outputList.find(by_id(groupId)); 39 if (audio.paused) audio.play(); 40 promise_test(pt => audio.setSinkId(device.deviceId).then(() => { 41 assert_equals(device.deviceId, audio.sinkId); 42 43 const pass = document.createElement("button"); 44 const fail = document.createElement("button"); 45 46 const result = (bool) => () => { 47 assert_true(bool, "Sound rendered on right device"); 48 fail.remove(); 49 pass.remove(); 50 audio.pause(); 51 e.target.checked = false; 52 e.target.disabled = true; 53 t.done(); 54 }; 55 56 pass.style.backgroundColor = "#0f0"; 57 pass.textContent = "\u2713 Sound plays on " + device.label; 58 pass.addEventListener("click", result(true)); 59 60 fail.style.backgroundColor = "#f00"; 61 fail.textContent = "\u274C Sound doesn't play on " + device.label; 62 fail.addEventListener("click", result(true)); 63 64 const container = e.target.parentNode.parentNode; 65 container.appendChild(pass); 66 container.appendChild(fail); 67 }), "setSinkId for " + device.label + " resolves"); 68 }; 69 70 const addAuthorizedDevice = (groupId) => { 71 const device = outputList.find(by_id(groupId)); 72 const async_t = async_test("Selecting output device " + device.label + " makes the audio rendered on the proper device"); 73 const li = document.createElement("li"); 74 const label = document.createElement("label"); 75 const input = document.createElement("input"); 76 input.type = "radio"; 77 input.name = "device"; 78 input.dataset["groupid"] = device.groupId; 79 input.addEventListener("change", selectDeviceTester(async_t)); 80 const span = document.createElement("span"); 81 span.textContent = device.label; 82 label.appendChild(input); 83 label.appendChild(span); 84 li.appendChild(label); 85 authorized.appendChild(li); 86 }; 87 88 const authorizeDeviceTester = (t) => (e) => { 89 const groupId = e.target.dataset["groupid"]; 90 navigator.mediaDevices.getUserMedia({audio: {groupId}}) 91 .then( () => { 92 addAuthorizedDevice(groupId); 93 t.done(); 94 }); 95 }; 96 97 promise_test(gum => 98 navigator.mediaDevices.getUserMedia({audio: true}).then( 99 () => { 100 promise_test(t => 101 navigator.mediaDevices.enumerateDevices().then(list => { 102 assert_not_equals(list.find(is_output), undefined, "media device list includes at least one audio output device"); 103 outputList = list.filter(is_output); 104 outputList.forEach(d => { 105 const li = document.createElement("li"); 106 assert_not_equals(d.label, "", "Audio Output Device Labels are available after permission grant"); 107 li.textContent = d.label; 108 // Check permission 109 promise_test(perm => navigator.permissions.query({name: "speaker", deviceId: d.deviceId}).then(({state}) => { 110 if (state === "granted") { 111 addAuthorizedDevice(d.groupId); 112 } else if (state === "prompt") { 113 const inp = list.find(inp => inp.kind === "audioinput" && inp.groupId === d.groupId); 114 if (inp || true) { 115 const async_t = async_test("Authorizing output devices via permission requests for microphones works"); 116 const button = document.createElement("button"); 117 button.textContent = "Authorize access"; 118 button.dataset["groupid"] = d.groupId; 119 button.addEventListener("click", async_t.step_func_done(authorizeDeviceTester(async_t))); 120 li.appendChild(button); 121 } 122 available.appendChild(li); 123 } 124 }, () => { 125 // if we can't query the permission, we assume it's granted :/ 126 addAuthorizedDevice(d.groupId); 127 }) 128 , "Query permission to use " + d.label); 129 }); 130 }), "List media devices"); 131 }), "Authorize mike access"); 132 </script>