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>