tor-browser

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

test_getUserMedia_mediaStreamClone.html (11024B)


      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 "use strict";
     10 
     11 createHTML({
     12  title: "MediaStream.clone()",
     13  bug: "1208371"
     14 });
     15 
     16 runTest(async () => {
     17  await pushPrefs(
     18    ["media.getusermedia.camera.stop_on_disable.enabled", true],
     19    ["media.getusermedia.camera.stop_on_disable.delay_ms", 0],
     20    ["media.getusermedia.microphone.stop_on_disable.enabled", true],
     21    ["media.getusermedia.microphone.stop_on_disable.delay_ms", 0]);
     22 
     23  let gUMStream = await getUserMedia({audio: true, video: true});
     24  {
     25    info("Test clone()ing an audio/video gUM stream");
     26    let clone = gUMStream.clone();
     27 
     28    checkMediaStreamCloneAgainstOriginal(clone, gUMStream);
     29    checkMediaStreamTrackCloneAgainstOriginal(clone.getAudioTracks()[0],
     30                                              gUMStream.getAudioTracks()[0]);
     31    checkMediaStreamTrackCloneAgainstOriginal(clone.getVideoTracks()[0],
     32                                              gUMStream.getVideoTracks()[0]);
     33 
     34    isnot(clone.id.length, 0, "Stream clone should have an id string");
     35    isnot(clone.getAudioTracks()[0].id.length, 0,
     36          "Audio track clone should have an id string");
     37    isnot(clone.getVideoTracks()[0].id.length, 0,
     38          "Audio track clone should have an id string");
     39 
     40    info("Playing from track clones");
     41    let test = createMediaElement('video', 'testClonePlayback');
     42    let playback = new MediaStreamPlayback(test, clone);
     43    await playback.playMedia(false);
     44  }
     45 
     46  {
     47    info("Test addTrack()ing a video track to a stream without affecting its clone");
     48    let stream = new MediaStream(gUMStream.getVideoTracks());
     49    let otherStream = await getUserMedia({video: true});
     50    let track = stream.getTracks()[0];
     51    let otherTrack = otherStream.getTracks()[0];
     52 
     53    let streamClone = stream.clone();
     54    let trackClone = streamClone.getTracks()[0];
     55    checkMediaStreamContains(streamClone, [trackClone], "Initial clone");
     56 
     57    stream.addTrack(otherTrack);
     58    checkMediaStreamContains(stream, [track, otherTrack],
     59                             "Added video to original");
     60    checkMediaStreamContains(streamClone, [trackClone],
     61                             "Clone not affected");
     62 
     63    stream.removeTrack(track);
     64    streamClone.addTrack(track);
     65    checkMediaStreamContains(streamClone, [trackClone, track],
     66                             "Added video to clone");
     67    checkMediaStreamContains(stream, [otherTrack],
     68                             "Original not affected");
     69 
     70    // Not part of streamClone. Does not get stopped by the playback test.
     71    otherTrack.stop();
     72 
     73    let test = createMediaElement('video', 'testClonePlayback');
     74    let playback = new MediaStreamPlayback(test, streamClone);
     75    await playback.playMedia(false);
     76  }
     77 
     78  {
     79    info("Test cloning a stream into inception");
     80    let stream = gUMStream.clone()
     81    let clone = stream;
     82    let clones = Array(10).fill().map(() => clone = clone.clone());
     83    let inceptionClone = clones.pop();
     84    checkMediaStreamCloneAgainstOriginal(inceptionClone, stream);
     85    stream.getTracks().forEach(t => {
     86      stream.removeTrack(t);
     87      return inceptionClone.addTrack(t);
     88    });
     89    is(inceptionClone.getAudioTracks().length, 2,
     90       "The inception clone should contain the original audio track and a track clone");
     91    is(inceptionClone.getVideoTracks().length, 2,
     92       "The inception clone should contain the original video track and a track clone");
     93 
     94    let test = createMediaElement('video', 'testClonePlayback');
     95    let playback = new MediaStreamPlayback(test, inceptionClone);
     96    await playback.playMedia(false);
     97    clones.forEach(c => c.getTracks().forEach(t => t.stop()));
     98    stream.getTracks().forEach(t => t.stop());
     99  }
    100 
    101  {
    102    info("Test adding tracks from many stream clones to the original stream");
    103    let stream = gUMStream.clone();
    104 
    105    const LOOPS = 3;
    106    for (let i = 0; i < LOOPS; i++) {
    107      stream.clone().getTracks().forEach(t => stream.addTrack(t));
    108    }
    109    is(stream.getAudioTracks().length, Math.pow(2, LOOPS),
    110       "The original track should contain the original audio track and all the audio clones");
    111    is(stream.getVideoTracks().length, Math.pow(2, LOOPS),
    112       "The original track should contain the original video track and all the video clones");
    113    stream.getTracks().forEach(t1 => is(stream.getTracks()
    114                                              .filter(t2 => t1.id == t2.id)
    115                                              .length,
    116                                        1, "Each track should be unique"));
    117 
    118    let test = createMediaElement('video', 'testClonePlayback');
    119    let playback = new MediaStreamPlayback(test, stream);
    120    await playback.playMedia(false);
    121  }
    122 
    123  {
    124    info("Testing audio content routing with MediaStream.clone()");
    125    let ac = new AudioContext();
    126 
    127    let osc1kOriginal = createOscillatorStream(ac, 1000);
    128    let audioTrack1kOriginal = osc1kOriginal.getTracks()[0];
    129    let audioTrack1kClone = osc1kOriginal.clone().getTracks()[0];
    130 
    131    let osc5kOriginal = createOscillatorStream(ac, 5000);
    132    let audioTrack5kOriginal = osc5kOriginal.getTracks()[0];
    133    let audioTrack5kClone = osc5kOriginal.clone().getTracks()[0];
    134 
    135    info("Analysing audio output of original stream (1k + 5k)");
    136    let stream = new MediaStream();
    137    stream.addTrack(audioTrack1kOriginal);
    138    stream.addTrack(audioTrack5kOriginal);
    139 
    140    let analyser = new AudioStreamAnalyser(ac, stream);
    141    await analyser.waitForAnalysisSuccess(array =>
    142            array[analyser.binIndexForFrequency(50)] < 50 &&
    143            array[analyser.binIndexForFrequency(1000)] > 200 &&
    144            array[analyser.binIndexForFrequency(3000)] < 50 &&
    145            array[analyser.binIndexForFrequency(5000)] > 200 &&
    146            array[analyser.binIndexForFrequency(10000)] < 50);
    147 
    148    info("Waiting for original tracks to stop");
    149    stream.getTracks().forEach(t => t.stop());
    150    await analyser.waitForAnalysisSuccess(array =>
    151            array[analyser.binIndexForFrequency(50)] < 50 &&
    152            // WebAudioDestination streams do not handle stop()
    153            // XXX Should they? Plan to resolve that in bug 1208384.
    154            // array[analyser.binIndexForFrequency(1000)] < 50 &&
    155            array[analyser.binIndexForFrequency(3000)] < 50 &&
    156            // array[analyser.binIndexForFrequency(5000)] < 50 &&
    157            array[analyser.binIndexForFrequency(10000)] < 50);
    158    analyser.disconnect();
    159 
    160    info("Analysing audio output of stream clone (1k + 5k)");
    161    stream = new MediaStream();
    162    stream.addTrack(audioTrack1kClone);
    163    stream.addTrack(audioTrack5kClone);
    164 
    165    analyser = new AudioStreamAnalyser(ac, stream);
    166    await analyser.waitForAnalysisSuccess(array =>
    167            array[analyser.binIndexForFrequency(50)] < 50 &&
    168            array[analyser.binIndexForFrequency(1000)] > 200 &&
    169            array[analyser.binIndexForFrequency(3000)] < 50 &&
    170            array[analyser.binIndexForFrequency(5000)] > 200 &&
    171            array[analyser.binIndexForFrequency(10000)] < 50);
    172    analyser.disconnect();
    173 
    174    info("Analysing audio output of clone of clone (1k + 5k)");
    175    stream = new MediaStream([audioTrack1kClone, audioTrack5kClone]).clone();
    176 
    177    analyser = new AudioStreamAnalyser(ac, stream);
    178    await analyser.waitForAnalysisSuccess(array =>
    179            array[analyser.binIndexForFrequency(50)] < 50 &&
    180            array[analyser.binIndexForFrequency(1000)] > 200 &&
    181            array[analyser.binIndexForFrequency(3000)] < 50 &&
    182            array[analyser.binIndexForFrequency(5000)] > 200 &&
    183            array[analyser.binIndexForFrequency(10000)] < 50);
    184    analyser.disconnect();
    185 
    186    info("Analysing audio output of clone() + addTrack()ed tracks (1k + 5k)");
    187    stream = new MediaStream(new MediaStream([ audioTrack1kClone
    188                                             , audioTrack5kClone
    189                                             ]).clone().getTracks());
    190 
    191    analyser = new AudioStreamAnalyser(ac, stream);
    192    await analyser.waitForAnalysisSuccess(array =>
    193            array[analyser.binIndexForFrequency(50)] < 50 &&
    194            array[analyser.binIndexForFrequency(1000)] > 200 &&
    195            array[analyser.binIndexForFrequency(3000)] < 50 &&
    196            array[analyser.binIndexForFrequency(5000)] > 200 &&
    197            array[analyser.binIndexForFrequency(10000)] < 50);
    198    analyser.disconnect();
    199 
    200    info("Analysing audio output of clone()d tracks in original stream (1k) " +
    201         "and clone()d tracks in stream clone (5k)");
    202    stream = new MediaStream([audioTrack1kClone, audioTrack5kClone]);
    203    let streamClone = stream.clone();
    204 
    205    stream.getTracks().forEach(t => stream.removeTrack(t));
    206    stream.addTrack(streamClone.getTracks()[0]);
    207    streamClone.removeTrack(streamClone.getTracks()[0]);
    208 
    209    analyser = new AudioStreamAnalyser(ac, stream);
    210    await analyser.waitForAnalysisSuccess(array =>
    211            array[analyser.binIndexForFrequency(50)] < 50 &&
    212            array[analyser.binIndexForFrequency(1000)] > 200 &&
    213            array[analyser.binIndexForFrequency(3000)] < 50 &&
    214            array[analyser.binIndexForFrequency(5000)] < 50);
    215    analyser.disconnect();
    216 
    217    let cloneAnalyser = new AudioStreamAnalyser(ac, streamClone);
    218    await cloneAnalyser.waitForAnalysisSuccess(array =>
    219            array[cloneAnalyser.binIndexForFrequency(1000)] < 50 &&
    220            array[cloneAnalyser.binIndexForFrequency(3000)] < 50 &&
    221            array[cloneAnalyser.binIndexForFrequency(5000)] > 200 &&
    222            array[cloneAnalyser.binIndexForFrequency(10000)] < 50);
    223    cloneAnalyser.disconnect();
    224 
    225    info("Analysing audio output enabled and disabled tracks that don't affect each other");
    226    stream = new MediaStream([audioTrack1kClone, audioTrack5kClone]);
    227    let clone = stream.clone();
    228 
    229    stream.getTracks()[0].enabled = true;
    230    stream.getTracks()[1].enabled = false;
    231 
    232    clone.getTracks()[0].enabled = false;
    233    clone.getTracks()[1].enabled = true;
    234 
    235    analyser = new AudioStreamAnalyser(ac, stream);
    236    await analyser.waitForAnalysisSuccess(array =>
    237            array[analyser.binIndexForFrequency(50)] < 50 &&
    238            array[analyser.binIndexForFrequency(1000)] > 200 &&
    239            array[analyser.binIndexForFrequency(3000)] < 50 &&
    240            array[analyser.binIndexForFrequency(5000)] < 50);
    241    analyser.disconnect();
    242 
    243    cloneAnalyser = new AudioStreamAnalyser(ac, clone);
    244    await cloneAnalyser.waitForAnalysisSuccess(array =>
    245            array[cloneAnalyser.binIndexForFrequency(1000)] < 50 &&
    246            array[cloneAnalyser.binIndexForFrequency(3000)] < 50 &&
    247            array[cloneAnalyser.binIndexForFrequency(5000)] > 200 &&
    248            array[cloneAnalyser.binIndexForFrequency(10000)] < 50);
    249    cloneAnalyser.disconnect();
    250 
    251    // Restore original tracks
    252    stream.getTracks().forEach(t => t.enabled = true);
    253  }
    254 
    255  gUMStream.getTracks().forEach(t => t.stop());
    256 });
    257 </script>
    258 </pre>
    259 </body>
    260 </html>