<!DOCTYPE HTML> <html> <head> <script type="application/javascript" src="mediaStreamPlayback.js"></script> </head> <body> <pre id="test"> <script type="application/javascript"> "use strict"; createHTML({ title: "MediaStreamTrack.clone()", bug: "1208371" }); var testSingleTrackClonePlayback = constraints => getUserMedia(constraints).then(stream => { info("Test clone()ing an " + constraints + " gUM track"); var track = stream.getTracks()[0]; var clone = track.clone(); checkMediaStreamTrackCloneAgainstOriginal(clone, track); info("Stopping original track"); track.stop(); info("Creating new stream for clone"); var cloneStream = new MediaStream([clone]); checkMediaStreamContains(cloneStream, [clone]); info("Testing playback of track clone"); var test = createMediaElement('video', 'testClonePlayback'); var playback = new MediaStreamPlayback(test, cloneStream); return playback.playMedia(false); }); runTest(() => Promise.resolve() .then(() => testSingleTrackClonePlayback({audio: true})) .then(() => testSingleTrackClonePlayback({video: true})) .then(() => getUserMedia({video: true})).then(stream => { info("Test cloning a track into inception"); var track = stream.getTracks()[0]; var clone = track; var clones = Array(10).fill().map(() => clone = clone.clone()); var inceptionClone = clones.pop(); checkMediaStreamTrackCloneAgainstOriginal(inceptionClone, track); var cloneStream = new MediaStream(); cloneStream.addTrack(inceptionClone); // cloneStream is now essentially the same as stream.clone(); checkMediaStreamCloneAgainstOriginal(cloneStream, stream); var test = createMediaElement('video', 'testClonePlayback'); var playback = new MediaStreamPlayback(test, cloneStream); return playback.playMedia(false).then(() => { info("Testing that clones of ended tracks are ended"); cloneStream.clone().getTracks().forEach(t => is(t.readyState, "ended", "Track " + t.id + " should be ended")); }) .then(() => { clones.forEach(t => t.stop()); track.stop(); }); }) .then(() => getUserMedia({audio: true, video: true})).then(stream => { info("Test adding many track clones to the original stream"); const LOOPS = 3; for (var i = 0; i < LOOPS; i++) { stream.getTracks().forEach(t => stream.addTrack(t.clone())); } is(stream.getVideoTracks().length, Math.pow(2, LOOPS), "The original track should contain the original video track and all the video clones"); stream.getTracks().forEach(t1 => is(stream.getTracks() .filter(t2 => t1.id == t2.id) .length, 1, "Each track should be unique")); var test = createMediaElement('video', 'testClonePlayback'); var playback = new MediaStreamPlayback(test, stream); return playback.playMedia(false); }) .then(() => { info("Testing audio content routing with MediaStreamTrack.clone()"); var ac = new AudioContext(); var osc1kOriginal = createOscillatorStream(ac, 1000); var audioTrack1kOriginal = osc1kOriginal.getTracks()[0]; var audioTrack1kClone = audioTrack1kOriginal.clone(); var osc5kOriginal = createOscillatorStream(ac, 5000); var audioTrack5kOriginal = osc5kOriginal.getTracks()[0]; var audioTrack5kClone = audioTrack5kOriginal.clone(); return Promise.resolve().then(() => { info("Analysing audio output enabled and disabled tracks that don't affect each other"); audioTrack1kOriginal.enabled = true; audioTrack5kOriginal.enabled = false; audioTrack1kClone.enabled = false; audioTrack5kClone.enabled = true; var analyser = new AudioStreamAnalyser(ac, new MediaStream([audioTrack1kOriginal, audioTrack5kOriginal])); return analyser.waitForAnalysisSuccess(array => array[analyser.binIndexForFrequency(50)] < 50 && array[analyser.binIndexForFrequency(1000)] > 200 && array[analyser.binIndexForFrequency(3000)] < 50 && array[analyser.binIndexForFrequency(5000)] < 50) .then(() => analyser.disconnect()) .then(() => { var cloneAnalyser = new AudioStreamAnalyser(ac, new MediaStream([audioTrack1kClone, audioTrack5kClone])); return cloneAnalyser.waitForAnalysisSuccess(array => array[cloneAnalyser.binIndexForFrequency(1000)] < 50 && array[cloneAnalyser.binIndexForFrequency(3000)] < 50 && array[cloneAnalyser.binIndexForFrequency(5000)] > 200 && array[cloneAnalyser.binIndexForFrequency(10000)] < 50) .then(() => cloneAnalyser.disconnect()); }) // Restore original tracks .then(() => [audioTrack1kOriginal, audioTrack5kOriginal, audioTrack1kClone, audioTrack5kClone].forEach(t => t.enabled = true)); }).then(() => { info("Analysing audio output of 1k original and 5k clone."); var stream = new MediaStream(); stream.addTrack(audioTrack1kOriginal); stream.addTrack(audioTrack5kClone); var analyser = new AudioStreamAnalyser(ac, stream); return analyser.waitForAnalysisSuccess(array => array[analyser.binIndexForFrequency(50)] < 50 && array[analyser.binIndexForFrequency(1000)] > 200 && array[analyser.binIndexForFrequency(3000)] < 50 && array[analyser.binIndexForFrequency(5000)] > 200 && array[analyser.binIndexForFrequency(10000)] < 50) .then(() => { info("Waiting for tracks to stop"); stream.getTracks().forEach(t => t.stop()); return analyser.waitForAnalysisSuccess(array => array[analyser.binIndexForFrequency(50)] < 50 && array[analyser.binIndexForFrequency(1000)] < 50 && array[analyser.binIndexForFrequency(3000)] < 50 && array[analyser.binIndexForFrequency(5000)] < 50 && array[analyser.binIndexForFrequency(10000)] < 50); }).then(() => analyser.disconnect()); }).then(() => { info("Analysing audio output of clones of clones (1kx2 + 5kx4)"); var stream = new MediaStream([audioTrack1kClone.clone(), audioTrack5kOriginal.clone().clone().clone().clone()]); var analyser = new AudioStreamAnalyser(ac, stream); return analyser.waitForAnalysisSuccess(array => array[analyser.binIndexForFrequency(50)] < 50 && array[analyser.binIndexForFrequency(1000)] > 200 && array[analyser.binIndexForFrequency(3000)] < 50 && array[analyser.binIndexForFrequency(5000)] > 200 && array[analyser.binIndexForFrequency(10000)] < 50) .then(() => analyser.disconnect()); }); })); </script> </pre> </body> </html>