tor-browser

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

test_autoplay_policy_web_audio_AudioParamStream.html (5670B)


      1 <!DOCTYPE HTML>
      2 <html>
      3 <head>
      4  <title>Autoplay policy test : suspend/resume the AudioParam's stream</title>
      5  <script src="/tests/SimpleTest/SimpleTest.js"></script>
      6  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
      7  <script type="text/javascript" src="manifest.js"></script>
      8 </head>
      9 <body>
     10 <script>
     11 
     12 /**
     13 * This test is used to ensure the AudioParam's stream can be suspended/resumed
     14 * by AudioContext.
     15 */
     16 
     17 SimpleTest.waitForExplicitFinish();
     18 
     19 (async function testSuspendAndResumeAudioParamStreams() {
     20  await setupTestPreferences();
     21 
     22  info(`- create the AudioContext -`);
     23  createAudioContext();
     24 
     25  info(`- the AudioContext is not allowed to start in beginning -`);
     26  await audioContextShouldBeBlocked();
     27 
     28  info(`- connect AudioScheduledSourceNode to the AudioParam and start AudioScheduledSourceNode, the AudioParam's stream should be suspended in the beginning -`)
     29  let audioParamsArr = await connectAudioScheduledSourceNodeToAudioParams();
     30 
     31  info(`- the AudioContext and the AudioParam's stream should be resumed -`);
     32  await audioContextAndAudioParamStreamsShouldBeResumed(audioParamsArr);
     33 
     34  info(`- suspend the AudioContext which should also suspend the AudioParam's stream -`);
     35  await suspendAudioContextAndAudioParamStreams(audioParamsArr);
     36 
     37  endTest();
     38 })();
     39 
     40 /**
     41 * Test utility functions
     42 */
     43 
     44 function setupTestPreferences() {
     45  return SpecialPowers.pushPrefEnv({"set": [
     46    ["media.autoplay.default", SpecialPowers.Ci.nsIAutoplay.BLOCKED],
     47    ["media.autoplay.blocking_policy", 0],
     48    ["media.autoplay.block-event.enabled", true],
     49  ]});
     50 }
     51 
     52 function createAudioContext() {
     53  /* global ac */
     54  window.ac = new AudioContext();
     55 
     56  ac.allowedToStart = new Promise(resolve => {
     57    ac.addEventListener("statechange", function() {
     58      if (ac.state === "running") {
     59        resolve();
     60      }
     61    }, {once: true});
     62  });
     63 
     64  ac.notAllowedToStart = new Promise(resolve => {
     65    ac.addEventListener("blocked", async function() {
     66      resolve();
     67    }, {once: true});
     68  });
     69 }
     70 
     71 async function audioContextShouldBeBlocked() {
     72  await ac.notAllowedToStart;
     73  is(ac.state, "suspended", `AudioContext is blocked.`);
     74 }
     75 
     76 function createAudioParams(nodeType) {
     77  switch (nodeType) {
     78    case "audioBufferSource": {
     79      let buffer = ac.createBufferSource();
     80      return [buffer.playbackRate, buffer.detune];
     81    }
     82    case "biquadFilter": {
     83      let bf = ac.createBiquadFilter();
     84      return [bf.frequency, bf.detune, bf.Q, bf.gain];
     85    }
     86    case "constantSource": {
     87      return [ac.createConstantSource().offset];
     88    }
     89    case "dynamicsCompressor": {
     90      let dc = ac.createDynamicsCompressor();
     91      return [dc.threshold, dc.knee, dc.ratio, dc.attack, dc.release];
     92    }
     93    case "delay": {
     94      return [ac.createDelay(5.0).delayTime];
     95    }
     96    case "gain": {
     97      return [ac.createGain().gain];
     98    }
     99    case "oscillator": {
    100      let osc = ac.createOscillator();
    101      return [osc.frequency, osc.detune];
    102    }
    103    case "panner": {
    104      let panner = ac.createPanner();
    105      return [panner.positionX, panner.positionY, panner.positionZ,
    106              panner.orientationX, panner.orientationY, panner.orientationZ];
    107    }
    108    case "stereoPanner": {
    109      return [ac.createStereoPanner().pan];
    110    }
    111    default: {
    112      ok(false, `non-defined node type ${nodeType}.`);
    113      return [];
    114    }
    115  }
    116 }
    117 
    118 function createAudioParamArrWithName(nodeType) {
    119  let audioParamsArr = createAudioParams(nodeType);
    120  for (let audioParam of audioParamsArr) {
    121    audioParam.name = nodeType;
    122  }
    123  return audioParamsArr;
    124 }
    125 
    126 function createAllAudioParamsFromDifferentAudioNode() {
    127  const NodesWithAudioParam =
    128    ["audioBufferSource", "biquadFilter", "constantSource", "delay",
    129     "dynamicsCompressor", "gain", "oscillator", "panner", "stereoPanner"];
    130  let audioParamsArr = [];
    131  for (let nodeType of NodesWithAudioParam) {
    132    audioParamsArr = audioParamsArr.concat(createAudioParamArrWithName(nodeType));
    133  }
    134  ok(audioParamsArr.length >= NodesWithAudioParam.length,
    135     `Length of AudioParam array (${audioParamsArr.length}) is longer than the "
    136     "length of node type array (${NodesWithAudioParam.length}).`);
    137  return audioParamsArr;
    138 }
    139 
    140 function connectAudioScheduledSourceNodeToAudioParams() {
    141  let osc = ac.createOscillator();
    142  let audioParamsArr = createAllAudioParamsFromDifferentAudioNode();
    143  for (let audioParam of audioParamsArr) {
    144    osc.connect(audioParam);
    145    ok(SpecialPowers.wrap(audioParam).isTrackSuspended,
    146      `(${audioParam.name}) audioParam's stream has been suspended.`);
    147  }
    148 
    149  // simulate user gesture in order to start video.
    150  SpecialPowers.wrap(document).notifyUserGestureActivation();
    151  osc.start();
    152  return audioParamsArr;
    153 }
    154 
    155 async function audioContextAndAudioParamStreamsShouldBeResumed(audioParamsArr) {
    156  await ac.allowedToStart;
    157  is(ac.state, "running", `AudioContext is allowed to start.`);
    158  for (let audioParam of audioParamsArr) {
    159    ok(!SpecialPowers.wrap(audioParam).isTrackSuspended,
    160       `(${audioParam.name}) audioParam's stream has been resumed.`);;
    161  }
    162 }
    163 
    164 async function suspendAudioContextAndAudioParamStreams(audioParamsArr) {
    165  await ac.suspend();
    166  is(ac.state, "suspended", `AudioContext is suspended.`);
    167  for (let audioParam of audioParamsArr) {
    168    ok(SpecialPowers.wrap(audioParam).isTrackSuspended,
    169       `(${audioParam.name}) audioParam's stream has been suspended.`);;
    170  }
    171 }
    172 
    173 function endTest() {
    174  // reset the activation flag in order not to interfere following test in the
    175  // verify mode which would run the test using same document couple times.
    176  SpecialPowers.wrap(document).clearUserGestureActivation();
    177  SimpleTest.finish();
    178 }
    179 
    180 </script>