tor-browser

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

audiocontext-sinkid-constructor.https.html (4969B)


      1 <!DOCTYPE html>
      2 <head>
      3 <title>Test AudioContext constructor with sinkId options</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 navigator.mediaDevices.getUserMedia({audio: true}).then(() => {
     14  navigator.mediaDevices.enumerateDevices().then((deviceList) => {
     15    outputDeviceList =
     16        deviceList.filter(({kind}) => kind === 'audiooutput');
     17    assert_greater_than(outputDeviceList.length, 1,
     18                        'the system must have more than 1 device.');
     19    firstDeviceId = outputDeviceList[1].deviceId;
     20 
     21    // Run async tests concurrently.
     22    async_test(t => testDefaultSinkId(t),
     23               'Setting sinkId to the empty string at construction should ' +
     24               'succeed.');
     25    async_test(t => testValidSinkId(t),
     26               'Setting sinkId with a valid device identifier at ' +
     27               'construction should succeed.');
     28    async_test(t => testAudioSinkOptions(t),
     29               'Setting sinkId with an AudioSinkOptions at construction ' +
     30               'should succeed.');
     31    async_test(t => testOnErrorWrongType(t),
     32               'Invalid sinkId argument with a wrong type should throw '+
     33               'an appropriate exception.');
     34    async_test(t => testOnErrorWrongId(t),
     35               'Invalid sinkId argument with a wrong ID should dispatch ' +
     36               'an onerror event.')
     37  });
     38 });
     39 
     40 // 1.2.1. AudioContext constructor
     41 // https://webaudio.github.io/web-audio-api/#AudioContext-constructors
     42 
     43 // Step 10.1.1. If sinkId is equal to [[sink ID]], abort these substeps.
     44 const testDefaultSinkId = (t) => {
     45  // The initial `sinkId` is the empty string. This will cause the same value
     46  // check.
     47  const audioContext = new AudioContext({sinkId: ''});
     48  audioContext.addEventListener('statechange', () => {
     49    t.step(() => {
     50      assert_equals(audioContext.sinkId, '');
     51      assert_equals(audioContext.state, 'running');
     52    });
     53    audioContext.close();
     54    t.done();
     55  }, {once: true});
     56 };
     57 
     58 // Step 10.1.2~3: See "Validating sinkId" tests below.
     59 
     60 // Step 10.1.4. If sinkId is a type of DOMString, set [[sink ID]] to sinkId and
     61 // abort these substeps.
     62 const testValidSinkId = (t) => {
     63  const audioContext = new AudioContext({sinkId: firstDeviceId});
     64  audioContext.addEventListener('statechange', () => {
     65    t.step(() => {
     66      assert_true(audioContext.sinkId === firstDeviceId,
     67                  'the context sinkId should match the given sinkId.');
     68    });
     69    audioContext.close();
     70    t.done();
     71  }, {once: true});
     72  t.step_timeout(t.unreached_func('onstatechange not fired or assert failed'),
     73                 100);
     74 };
     75 
     76 // Step 10.1.5. If sinkId is a type of AudioSinkOptions, set [[sink ID]] to a
     77 // new instance of AudioSinkInfo created with the value of type of sinkId.
     78 const testAudioSinkOptions = (t) => {
     79  const audioContext = new AudioContext({sinkId: {type: 'none'}});
     80  // The only signal we can use for the sinkId change after construction is
     81  // `statechange` event.
     82  audioContext.addEventListener('statechange', () => {
     83    t.step(() => {
     84      assert_equals(typeof audioContext.sinkId, 'object');
     85      assert_equals(audioContext.sinkId.type, 'none');
     86    });
     87    audioContext.close();
     88    t.done();
     89  }, {once: true});
     90  t.step_timeout(t.unreached_func('onstatechange not fired or assert failed'),
     91                 100);
     92 };
     93 
     94 // 1.2.4. Validating sinkId
     95 // https://webaudio.github.io/web-audio-api/#validating-sink-identifier
     96 
     97 // Step 3. If document is not allowed to use the feature identified by
     98 // "speaker-selection", return false.
     99 // TODO(https://crbug.com/1380872): Due to the lack of "speaker-selection"
    100 // implementation, a test for such step does not exist yet.
    101 
    102 const testOnErrorWrongType = (t) => {
    103  t.step(() => {
    104    // The wrong AudioSinkOption.type should cause a TypeError. This exception
    105    // is thrown at the IDL validation level.
    106    assert_throws_js(TypeError, () => {
    107      const audioContext = new AudioContext({sinkId: {type: 'something_else'}});
    108      audioContext.close();
    109    }, 'An invalid AudioSinkOptions.type value should throw a TypeError ' +
    110     'exception.');
    111  });
    112  t.done();
    113 };
    114 
    115 // Step 4. If sinkIdArg is a type of DOMString but it is not equal to the
    116 // empty string or it does not match any audio output device identified by
    117 // the result that would be provided by enumerateDevices(), return false.
    118 //
    119 // When validation returns a false value, the context dispatches an onerror
    120 // event.
    121 const testOnErrorWrongId = (t) => {
    122  // An invalid device ID should dispatch an onerror event.
    123  const audioContext = new AudioContext({sinkId: 'some_random_device_id'});
    124  audioContext.addEventListener('error', () => {
    125    audioContext.close();
    126    t.done();
    127  }, {once: true});
    128  t.step_timeout(t.unreached_func('onerror not fired on invalid device ID'),
    129                 100);
    130 };
    131 </script>
    132 </html>