tor-browser

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

audiocontext-sinkid-state-change.https.html (3613B)


      1 <!DOCTYPE html>
      2 <head>
      3 <title>Test AudioContext.setSinkId() state change</title>
      4 </head>
      5 <script src=/resources/testharness.js></script>
      6 <script src=/resources/testharnessreport.js></script>
      7 <script>
      8 "use strict";
      9 
     10 let outputDeviceList = null;
     11 let firstDeviceId = null;
     12 
     13 // Setup: Get permission via getUserMedia() and a list of audio output devices.
     14 promise_setup(async t => {
     15  await navigator.mediaDevices.getUserMedia({ audio: true });
     16  const deviceList = await navigator.mediaDevices.enumerateDevices();
     17  outputDeviceList =
     18      deviceList.filter(({kind}) => kind === 'audiooutput');
     19  assert_greater_than(outputDeviceList.length, 1,
     20                      'the system must have more than 1 device.');
     21  firstDeviceId = outputDeviceList[1].deviceId;
     22 }, 'Get permission via getUserMedia() and a list of audio output devices.');
     23 
     24 // Test the sink change when from a suspended context.
     25 promise_test(async t => {
     26  let events = [];
     27  const audioContext = new AudioContext();
     28  await audioContext.suspend();
     29 
     30  // Step 6. Set wasRunning to false if the [[rendering thread state]] on the
     31  // AudioContext is "suspended".
     32  assert_equals(audioContext.state, 'suspended');
     33 
     34  // Step 11.5. Fire an event named sinkchange at the associated AudioContext.
     35  audioContext.onsinkchange = t.step_func(() => {
     36    events.push('sinkchange');
     37    assert_equals(audioContext.sinkId, firstDeviceId);
     38  });
     39 
     40  await audioContext.setSinkId(firstDeviceId);
     41  assert_equals(events[0], 'sinkchange');
     42  t.done();
     43 }, 'Calling setSinkId() on a suspended AudioContext should fire only sink ' +
     44   'change events.');
     45 
     46 // Test the sink change on a running AudioContext.
     47 promise_test(async t => {
     48  let events = [];
     49  let silentSinkOption = {type: 'none'};
     50  const audioContext = new AudioContext();
     51 
     52  // Make sure the context is "running". This also will fire a state change
     53  // event upon resolution.
     54  await audioContext.resume();
     55 
     56  return new Promise(async resolve => {
     57 
     58    function eventCheckpoint() {
     59      // We're expecting 4 events from AudioContext.
     60      if (events.length === 4) {
     61        // The initial context state was "running".
     62        assert_equals(events[0], 'statechange:running');
     63        assert_equals(events[1], 'statechange:suspended');
     64        assert_equals(events[2], 'sinkchange');
     65        assert_equals(events[3], 'statechange:running');
     66        resolve();
     67      }
     68    }
     69 
     70    // This is to catch a sink change event:
     71    // - Step 11.5. Fire an event named sinkchange at the associated
     72    //   AudioContext.
     73    audioContext.onsinkchange = t.step_func(() => {
     74      assert_equals(audioContext.sinkId.type, silentSinkOption.type);
     75      events.push('sinkchange');
     76      eventCheckpoint();
     77    });
     78 
     79    // The following event handler will catch 3 state change events:
     80    // - The initial 'running' state change.
     81    // - Step 9.2.1. Set the state attribute of the AudioContext to "suspended".
     82    //   Fire an event named statechange at the associated AudioContext.
     83    // - Step 12.2. Set the state attribute of the AudioContext to "running".
     84    //   Fire an event named statechange at the associated AudioContext.
     85    audioContext.onstatechange = async () => {
     86      events.push(`statechange:${audioContext.state}`);
     87      eventCheckpoint();
     88    };
     89 
     90    // To trigger a series of state changes, we need a device change. The
     91    // context started with the default device, and this call changes it to a
     92    // silent sink.
     93    audioContext.setSinkId(silentSinkOption);
     94  });
     95 }, 'Calling setSinkId() on a running AudioContext should fire both state ' +
     96   'and sink change events.');
     97 </script>
     98 </html>