tor-browser

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

audiocontext-sinkid-setsinkid.https.html (4923B)


      1 <!DOCTYPE html>
      2 <head>
      3 <title>Test AudioContext.setSinkId() method</title>
      4 </head>
      5 <script src=/resources/testharness.js></script>
      6 <script src=/resources/testharnessreport.js></script>
      7 <script>
      8 "use strict";
      9 
     10 const audioContext = new AudioContext();
     11 let outputDeviceList = null;
     12 let firstDeviceId = null;
     13 
     14 // Setup: Get permission via getUserMedia() and a list of audio output devices.
     15 promise_setup(async t => {
     16  await navigator.mediaDevices.getUserMedia({ audio: true });
     17  const deviceList = await navigator.mediaDevices.enumerateDevices();
     18  outputDeviceList =
     19      deviceList.filter(({kind}) => kind === 'audiooutput');
     20  assert_greater_than(outputDeviceList.length, 1,
     21                      'the system must have more than 1 device.');
     22  firstDeviceId = outputDeviceList[1].deviceId;
     23 }, 'Get permission via getUserMedia() and a list of audio output devices.');
     24 
     25 
     26 // 1.2.3. AudioContext.setSinkId() method
     27 // https://webaudio.github.io/web-audio-api/#dom-audiocontext-setsinkid-domstring-or-audiosinkoptions-sinkid
     28 
     29 promise_test(async t => {
     30  t.step(() => {
     31    // The default value of `sinkId` is the empty string.
     32    assert_equals(audioContext.sinkId, '');
     33  });
     34  t.done();
     35 }, 'setSinkId() with a valid device identifier should succeeded.');
     36 
     37 promise_test(async t => {
     38  // Change to the first non-default device in the list.
     39  await audioContext.setSinkId(firstDeviceId);
     40  t.step(() => {
     41    // If both `sinkId` and [[sink ID]] are a type of DOMString, and they are
     42    // equal to each other, resolve the promise immediately.
     43    assert_equals(typeof audioContext.sinkId, 'string');
     44    assert_equals(audioContext.sinkId, firstDeviceId);
     45  });
     46  return audioContext.setSinkId(firstDeviceId);
     47 }, 'setSinkId() with the same sink ID should resolve immediately.');
     48 
     49 promise_test(async t => {
     50  // If sinkId is a type of AudioSinkOptions and [[sink ID]] is a type of
     51  // AudioSinkInfo, and type in sinkId and type in [[sink ID]] are equal,
     52  // resolve the promise immediately.
     53  await audioContext.setSinkId({type: 'none'});
     54  t.step(() => {
     55    assert_equals(typeof audioContext.sinkId, 'object');
     56    assert_equals(audioContext.sinkId.type, 'none');
     57  });
     58  return audioContext.setSinkId({type: 'none'});
     59 }, 'setSinkId() with the same AudioSinkOptions.type value should resolve ' +
     60   'immediately.');
     61 
     62 // 1.2.4. Validating sinkId
     63 // https://webaudio.github.io/web-audio-api/#validating-sink-identifier
     64 
     65 // Step 3. If document is not allowed to use the feature identified by
     66 // "speaker-selection", return a new DOMException whose name is
     67 // "NotAllowedError".
     68 // TODO: Due to the lack of implementation, this step is not tested.
     69 
     70 // The wrong AudioSinkOption.type should cause a TypeError.
     71 promise_test(t =>
     72    promise_rejects_js(t, TypeError,
     73                       audioContext.setSinkId({type: 'something_else'})),
     74    'setSinkId() should fail with TypeError on an invalid ' +
     75    'AudioSinkOptions.type value.');
     76 
     77 // Step 4. If sinkId is a type of DOMString but it is not equal to the empty
     78 // string or it does not match any audio output device identified by the result
     79 // that would be provided by enumerateDevices(), return a new DOMException whose
     80 // name is "NotFoundError".
     81 promise_test(t =>
     82    promise_rejects_dom(t, 'NotFoundError',
     83                        audioContext.setSinkId('some_random_device_id')),
     84    'setSinkId() should fail with NotFoundError on an invalid device ' +
     85    'identifier.');
     86 
     87 // setSinkId invoked from closed AudioContext should throw InvalidStateError
     88 // DOMException.
     89 promise_test(async t => {
     90  await audioContext.close();
     91  t.step(() => {
     92    assert_equals(audioContext.state, 'closed');
     93  });
     94  promise_rejects_dom(t, 'InvalidStateError',
     95                      audioContext.setSinkId('some_random_device_id'))
     96 },'setSinkId() should fail with InvalidStateError when calling from a' +
     97  'stopped AudioContext');
     98 
     99 // setSinkId invoked from detached document should throw InvalidStateError
    100 // DOMException.
    101 promise_test(async t => {
    102  const iframe = document.createElementNS("http://www.w3.org/1999/xhtml", "iframe");
    103  document.body.appendChild(iframe);
    104  let iframeAudioContext = new iframe.contentWindow.AudioContext();
    105  document.body.removeChild(iframe);
    106  promise_rejects_dom(t, 'InvalidStateError',
    107                      iframeAudioContext.setSinkId('some_random_device_id'));
    108 },'setSinkId() should fail with InvalidStateError when calling from a' +
    109  'detached document');
    110 
    111 // Pending setSinkId() promises should be rejected with a
    112 // DOMException of InvalidStateError when the context is closed.
    113 // See: crbug.com/1408376
    114 promise_test(async t => {
    115  const audioContext = new AudioContext();
    116  promise_rejects_dom(t, 'InvalidStateError',
    117                      audioContext.setSinkId('some_random_device_id'));
    118  await audioContext.close();
    119 },'pending setSinkId() should be rejected with InvalidStateError when' +
    120  'AudioContext is closed');
    121 </script>
    122 </html>