tor-browser

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

test_getUserMedia_audioConstraints_concurrentIframes.html (6471B)


      1 <!DOCTYPE HTML>
      2 <html>
      3 <head>
      4  <script type="application/javascript" src="mediaStreamPlayback.js"></script>
      5 </head>
      6 <body>
      7 <pre id="test">
      8 <script type="application/javascript">
      9 createHTML({
     10  title: "getUserMedia in multiple iframes with different constraints",
     11  bug: "1404977"
     12 });
     13 /**
     14  * Verify that we can successfully call getUserMedia for the same device in
     15  * multiple iframes concurrently. This is checked by creating a number of
     16  * iframes and performing a separate getUserMedia call in each. We verify the
     17  * stream returned by that call has the same constraints as requested both
     18  * immediately after the call and after all gUM calls have been made. The test
     19  * then verifies the streams can be played.
     20  */
     21 runTest(async function() {
     22  // Compare constraints and return a string with the differences in
     23  // echoCancellation, autoGainControl, and noiseSuppression. The string
     24  // will be empty if there are no differences.
     25  function getConstraintDifferenceString(constraints, otherConstraints) {
     26    let diffString = "";
     27    if (constraints.echoCancellation != otherConstraints.echoCancellation) {
     28      diffString += "echoCancellation different: " +
     29                    `${constraints.echoCancellation} != ${otherConstraints.echoCancellation}, `;
     30    }
     31    if (constraints.autoGainControl != otherConstraints.autoGainControl) {
     32      diffString += "autoGainControl different: " +
     33                    `${constraints.autoGainControl} != ${otherConstraints.autoGainControl}, `;
     34    }
     35    if (constraints.noiseSuppression != otherConstraints.noiseSuppression) {
     36      diffString += "noiseSuppression different: " +
     37                    `${constraints.noiseSuppression} != ${otherConstraints.noiseSuppression}, `;
     38    }
     39    // Replace trailing comma and space if any
     40    return diffString.replace(/, $/, "");
     41  }
     42 
     43  // We need a real device to get a MediaEngine supporting constraints
     44  let audioDevice = SpecialPowers.getCharPref("media.audio_loopback_dev", "");
     45  if (!audioDevice) {
     46    todo(false, "No device set by framework. Try --use-test-media-devices");
     47    return;
     48  }
     49 
     50  let egn = (e, g, n) => ({
     51    echoCancellation: e,
     52    autoGainControl: g,
     53    noiseSuppression: n
     54  });
     55 
     56  let allConstraintCombinations = [
     57    egn(false, false, false),
     58    egn(true,  false, false),
     59    egn(false, true,  false),
     60    egn(false, false, true),
     61    egn(true,  true,  false),
     62    egn(true,  false, true),
     63    egn(false, true,  true),
     64    egn(true,  true,  true),
     65  ];
     66 
     67  // TODO: We would like to be able to perform an arbitrary number of gUM calls
     68  // at once, but issues with pulse and audio IPC mean on some systems we're
     69  // limited to as few as 2 concurrent calls. To avoid issues we chunk test runs
     70  // to only two calls at a time. The while, splice and GC lines can be removed,
     71  // the extra scope removed and allConstraintCombinations can be renamed to
     72  // constraintCombinations once this issue is resolved. See bug 1480489.
     73  while (allConstraintCombinations.length) {
     74    {
     75      let constraintCombinations = allConstraintCombinations.splice(0, 2);
     76      // Array to store objects that associate information used in our test such as
     77      // constraints, iframes, gum streams, and various promises.
     78      let testCases = [];
     79 
     80      for (let constraints of constraintCombinations) {
     81        let testCase = {requestedConstraints: constraints};
     82        // Provide an id for logging, labeling related elements.
     83        testCase.id = `testCase.` +
     84                      `e=${constraints.echoCancellation}.` +
     85                      `g=${constraints.noiseSuppression}.` +
     86                      `n=${constraints.noiseSuppression}`;
     87        testCases.push(testCase);
     88        testCase.iframe = document.createElement("iframe");
     89        testCase.iframeLoadedPromise = new Promise((resolve, reject) => {
     90          testCase.iframe.onload = () => { resolve(); };
     91        });
     92        document.body.appendChild(testCase.iframe);
     93      }
     94      is(testCases.length,
     95        constraintCombinations.length,
     96        "Should have created a testcase for each constraint");
     97 
     98      // Wait for all iframes to be loaded
     99      await Promise.all(testCases.map(tc => tc.iframeLoadedPromise));
    100 
    101      // One by one see if we can grab a gUM stream per iframe
    102      for (let testCase of testCases) {
    103        // Use normal gUM rather than our test helper as the test harness was
    104        // not made to be used inside iframes.
    105        testCase.gumStream =
    106          await testCase.iframe.contentWindow.navigator.mediaDevices.getUserMedia({audio: testCase.requestedConstraints})
    107          .catch(e => Promise.reject(`getUserMedia calls should not fail! Failed at ${testCase.id} with: ${e}!`));
    108        let differenceString = getConstraintDifferenceString(
    109          testCase.requestedConstraints,
    110          testCase.gumStream.getAudioTracks()[0].getSettings());
    111        ok(!differenceString,
    112          `gUM stream for ${testCase.id} should have the same constraints as were ` +
    113          `requested from gUM. Differences: ${differenceString}`);
    114      }
    115 
    116      // Once all streams are collected, make sure the constraints haven't been
    117      // mutated by another gUM call.
    118      for (let testCase of testCases) {
    119        let differenceString = getConstraintDifferenceString(
    120          testCase.requestedConstraints,
    121          testCase.gumStream.getAudioTracks()[0].getSettings());
    122        ok(!differenceString,
    123          `gUM stream for ${testCase.id} should not have had constraints altered after ` +
    124          `all gUM calls are done. Differences: ${differenceString}`);
    125      }
    126 
    127      // We do not currently have tests to verify the behaviour of the different
    128      // constraints. Once we do we should do further verification here. See
    129      // bug 1406372, bug 1406376, and bug 1406377.
    130 
    131      for (let testCase of testCases) {
    132        let testAudio = createMediaElement("audio", `testAudio.${testCase.id}`);
    133        let playback = new MediaStreamPlayback(testAudio, testCase.gumStream);
    134        await playback.playMediaWithoutStoppingTracks(false);
    135      }
    136 
    137      // Stop the tracks for each stream, we left them running above via
    138      // playMediaWithoutStoppingTracks to make sure they can play concurrently.
    139      for (let testCase of testCases) {
    140        testCase.gumStream.getTracks().map(t => t.stop());
    141        document.body.removeChild(testCase.iframe);
    142      }
    143    }
    144    await new Promise(r => SpecialPowers.exactGC(r));
    145  }
    146 });
    147 </script>
    148 </pre>
    149 </body>
    150 </html>