tor-browser

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

test_getUserMedia_audioCapture.html (4837B)


      1 <!DOCTYPE HTML>
      2 <html>
      3 <head>
      4  <title>Test AudioCapture </title>
      5  <script type="application/javascript" src="mediaStreamPlayback.js"></script>
      6 </head>
      7 <body>
      8 <pre id="test">
      9 <script>
     10 
     11 (async () => {
     12  await createHTML({
     13    bug: "1156472",
     14    title: "Test AudioCapture with regular HTMLMediaElement, AudioContext, " +
     15           "and HTMLMediaElement playing a MediaStream",
     16    visible: true
     17  });
     18 
     19  await runTestWhenReady(async () => {
     20    // Reduce noise for when --use-test-media-devices is not in use.
     21    await SpecialPowers.pushPrefEnv({ set: [[ "media.volume_scale", "0.0" ]] });
     22    /**
     23     * Get two HTMLMediaElements:
     24     * - One playing a sine tone from a blob (of an opus file created on the fly)
     25     * - One being the output for an AudioContext's OscillatorNode, connected to
     26     *   a MediaSourceDestinationNode.
     27     *
     28     * Also, use the AudioContext playing through its AudioDestinationNode another
     29     * tone, using another OscillatorNode.
     30     *
     31     * Capture the output of the document, feed that back into the AudioContext,
     32     * with an AnalyserNode, and check the frequency content to make sure we
     33     * have recorded the three sources.
     34     *
     35     * The three sine tones have frequencies far apart from each other, so that we
     36     * can check that the spectrum of the capture stream contains three
     37     * components with a high magnitude.
     38     */
     39    const decodedTone = createMediaElement("audio", "decodedTone");
     40    decodedTone.muted = false;
     41    const decodedToneMuted = createMediaElement("audio", "decodedToneMuted");
     42    const acTone = createMediaElement("audio", "audioContextTone");
     43    acTone.muted = false;
     44    const acToneMuted = createMediaElement("audio", "audioContextToneMuted");
     45    const micTone = createMediaElement("audio", "audioContextTone");
     46    micTone.muted = false;
     47    const ac = new AudioContext();
     48    const constraints = {audio: {mediaSource: "audioCapture"}};
     49    const stream = await getUserMedia(constraints);
     50    const analyser = new AudioStreamAnalyser(ac, stream);
     51 
     52    const osc200 = ac.createOscillator();
     53    osc200.frequency.value = analyser.frequencyForBinIndex(200);
     54    const osc250 = ac.createOscillator();
     55    osc250.frequency.value = analyser.frequencyForBinIndex(250);
     56    const oscThroughAudioDestinationNode = ac.createOscillator();
     57    oscThroughAudioDestinationNode.frequency.value =
     58      analyser.frequencyForBinIndex(100);
     59    const msDest200 = ac.createMediaStreamDestination();
     60    const msDest250 = ac.createMediaStreamDestination();
     61 
     62    osc200.connect(msDest200);
     63    osc250.connect(msDest250);
     64    oscThroughAudioDestinationNode.connect(ac.destination);
     65 
     66    acTone.srcObject = msDest200.stream;
     67    acToneMuted.srcObject = msDest250.stream;
     68 
     69    // The fake microphone uses signed 16-bit audio data:
     70    await SpecialPowers.pushPrefEnv({ set: [
     71      [
     72        "media.navigator.audio.fake_frequency",
     73        analyser.frequencyForBinIndex(300)
     74      ]
     75    ]});
     76    const micStream = await navigator.mediaDevices.getUserMedia({
     77      'audio': true, 'fake': true
     78    });
     79    micTone.srcObject = micStream;
     80 
     81    decodedTone.src = "/tests/dom/media/test/sin-441-1s-44100.flac";
     82    decodedToneMuted.src = "/tests/dom/media/test/sin-441-1s-44100.flac";
     83    decodedTone.preservesPitch = false;
     84    decodedToneMuted.preservesPitch = false;
     85    decodedTone.playbackRate = analyser.frequencyForBinIndex(20) / 441;
     86    ok(decodedTone.playbackRate >= 1/16, "within firefox min playback rate");
     87    decodedToneMuted.playbackRate = analyser.frequencyForBinIndex(40) / 441;
     88    ok(decodedToneMuted.playbackRate <= 16, "within firefox max playback rate");
     89    osc200.start();
     90    osc250.start();
     91    oscThroughAudioDestinationNode.start();
     92    decodedTone.loop = true;
     93    decodedToneMuted.loop = true;
     94    decodedTone.play();
     95    decodedToneMuted.play();
     96    acTone.play();
     97    acToneMuted.play();
     98 
     99    let frequencyBytes;
    100    try {
    101      analyser.enableDebugCanvas();
    102      await analyser.waitForAnalysisSuccess(array => {
    103        // We want to find three frequency components here.
    104        // Frequencies are logarithmic. Also make sure we have low
    105        // energy in between, not just a flat white noise.
    106        if (array[10]  == 0 &&
    107            array[20]  == 255 &&
    108            array[40]  == 0 &&
    109            array[70]  == 0 &&
    110            array[100] == 255 &&
    111            array[150] == 0 &&
    112            array[200] == 255 &&
    113            array[300] >  240) {
    114          frequencyBytes = new Uint8Array(array);
    115          return true;
    116        }
    117        return false;
    118      });
    119    } finally {
    120      await ac.close();
    121      for (let t of [...stream.getTracks(), ...micStream.getTracks()]) {
    122        t.stop();
    123      }
    124    }
    125    todo(frequencyBytes[250] < 50, "muted MediaStream srcObject - bug 1864067");
    126  });
    127 })();
    128 </script>
    129 </pre>
    130 </body>
    131 </html>