DXR is a code search and navigation tool aimed at making sense of large projects. It supports full-text and regex searches as well as structural queries.

Mercurial (9b7cd94eaf0a)

VCS Links

Line Code
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
<!doctype html>
<html>
<head>
<title>Test setSinkId behavior with permissions / device changes</title>
<link rel="author" title="Dominique Hazael-Massieux" href="mailto:dom@w3.org"/>
<link rel="help" href="https://www.w3.org/TR/audio-output/#dom-htmlmediaelement-setsinkid">
<meta name="timeout" content="long">

</head>
<body>
<h1 class="instructions">Description</h1>
<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>
<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>
<p class="instructions">For each authorized output device, check that selecting it makes the audio beat rendered on the corresponding device.</p>
<p>Available but unauthorized devices (only those for which we can gain permission can be selected):</p>
<ul id="available"></ul>
<p>Authorized  devices:</p>
<ul id="authorized"></ul>
<audio controls id="beat" src="/media/sound_5.mp3" loop></audio>

<div id='log'></div>
<script src=/resources/testharness.js></script>
<script src=/resources/testharnessreport.js></script>
<script>
"use strict";

const is_output = d => d.kind === "audiooutput";
const by_id = (id) => d => d.groupId === id;
const is_input = d => d.kind === "audioinput";
const audio = document.getElementById("beat");
const available = document.getElementById("available");
const authorized = document.getElementById("authorized");

let outputList;

const selectDeviceTester = (t) => (e) => {
    const groupId = e.target.dataset["groupid"];
    const device = outputList.find(by_id(groupId));
    if (audio.paused) audio.play();
    promise_test(pt => audio.setSinkId(device.deviceId).then(() => {
        assert_equals(device.deviceId, audio.sinkId);

        const pass = document.createElement("button");
        const fail = document.createElement("button");

        const result = (bool) => () => {
            assert_true(bool, "Sound rendered on right device");
            fail.remove();
            pass.remove();
            audio.pause();
            e.target.checked = false;
            e.target.disabled = true;
            t.done();
        };

        pass.style.backgroundColor = "#0f0";
        pass.textContent = "\u2713 Sound plays on " + device.label;
        pass.addEventListener("click", result(true));

        fail.style.backgroundColor = "#f00";
        fail.textContent = "\u274C Sound doesn't play on " + device.label;
        fail.addEventListener("click", result(true));

        const container = e.target.parentNode.parentNode;
        container.appendChild(pass);
        container.appendChild(fail);
    }), "setSinkId for " + device.label + " resolves");
};

const addAuthorizedDevice = (groupId) => {
    const device = outputList.find(by_id(groupId));
    const async_t = async_test("Selecting output device " + device.label + " makes the audio rendered on the proper device");
    const li = document.createElement("li");
    const label = document.createElement("label");
    const input = document.createElement("input");
    input.type = "radio";
    input.name = "device";
    input.dataset["groupid"] = device.groupId;
    input.addEventListener("change", selectDeviceTester(async_t));
    const span = document.createElement("span");
    span.textContent = device.label;
    label.appendChild(input);
    label.appendChild(span);
    li.appendChild(label);
    authorized.appendChild(li);
};

const authorizeDeviceTester = (t) => (e) => {
    const groupId = e.target.dataset["groupid"];
    navigator.mediaDevices.getUserMedia({audio: {groupId}})
        .then( () => {
            addAuthorizedDevice(groupId);
            t.done();
        });
};

promise_test(gum =>
             navigator.mediaDevices.getUserMedia({audio: true}).then(
                 () => {
                     promise_test(t =>
                                  navigator.mediaDevices.enumerateDevices().then(list => {
                                      assert_not_equals(list.find(is_output), undefined, "media device list includes at least one audio output device");
                                      outputList = list.filter(is_output);
                                      outputList.forEach(d => {
                                          const li = document.createElement("li");
                                          assert_not_equals(d.label, "", "Audio Output Device Labels are available after permission grant");
                                          li.textContent = d.label;
                                          // Check permission
                                          promise_test(perm => navigator.permissions.query({name: "speaker", deviceId: d.deviceId}).then(({state}) => {
                                              if (state === "granted") {
                                                  addAuthorizedDevice(d.groupId);
                                              } else if (state === "prompt") {
                                                  const inp = list.find(inp => inp.kind === "audioinput" && inp.groupId === d.groupId);
                                                  if (inp || true) {
                                                      const async_t = async_test("Authorizing output devices via permission requests for microphones works");
                                                      const button = document.createElement("button");
                                                      button.textContent = "Authorize access";
                                                      button.dataset["groupid"] = d.groupId;
                                                      button.addEventListener("click", async_t.step_func_done(authorizeDeviceTester(async_t)));
                                                      li.appendChild(button);
                                                  }
                                                  available.appendChild(li);
                                              }
                                          }, () => {
                                                           // if we can't query the permission, we assume it's granted :/
                                                           addAuthorizedDevice(d.groupId);
                                                       })
                                                       , "Query permission to use " + d.label);
                                      });
                                  }), "List media devices");
                 }), "Authorize mike access");
</script>