Is it possible to create a MediaStream containing instances of MediaStreamTrack from two different sources / elements?
Yes, you can do this using the MediaStream.addTrack() method.
But Firefox will only use the start-up paths of the stream in the Recorder until this error is fixed.
OP already knows how to get all this, but there is a reminder for future readers:
To get the videoStream track from the canvas, you can call the canvas.captureStream(framerate) method.
To get the audio stream from a video element, you can use the WebAudio API and the createMediaStreamDestination method. This will return a MediaStreamDestination node ( dest ) containing our audio stream. Then you need to connect the MediaElementSource created from your video element to this dest . If you need to add additional audio tracks to this stream, you must connect all these sources to dest .
Now that we have two streams: one for video canvas and one for audio, we can use canvasStream.addTrack(audioStream.getAudioTracks()[0]) immediately before initializing a new MediaRecorder(canvasStream) .
Here is a complete example that will only work now in Chrome and probably in Firefox when they fix the error:
var cStream, aStream, vid, recorder, analyser, dataArray, bufferLength, chunks = []; function clickHandler() { this.textContent = 'stop recording'; cStream = canvas.captureStream(30); cStream.addTrack(aStream.getAudioTracks()[0]); recorder = new MediaRecorder(cStream); recorder.start(); recorder.ondataavailable = saveChunks; recorder.onstop = exportStream; this.onclick = stopRecording; }; function exportStream(e) { if (chunks.length) { var blob = new Blob(chunks) var vidURL = URL.createObjectURL(blob); var vid = document.createElement('video'); vid.controls = true; vid.src = vidURL; vid.onend = function() { URL.revokeObjectURL(vidURL); } document.body.insertBefore(vid, canvas); } else { document.body.insertBefore(document.createTextNode('no data saved'), canvas); } } function saveChunks(e) { e.data.size && chunks.push(e.data); } function stopRecording() { vid.pause(); this.parentNode.removeChild(this); recorder.stop(); } function initAudioStream(evt) { var audioCtx = new AudioContext();
<canvas id="canvas" width="500" height="200"></canvas> <button id="rec" disabled>record</button>
Ps : since the FF team seems to take some time to fix the error, here is a quick solution to make it work with FF as well.
You can also mix two tracks using new MediaStream([track1, track2]) .
However, chrome is currently the prefix of this constructor, but since it supports addTrack , it really is not needed, and we can come up with something as ugly as
var mixedStream = 'MediaStream' in window ? new MediaStream([cStream.getVideoTracks()[0], aStream.getAudioTracks()[0]]) : cStream; recorder = new MediaRecorder(mixedStream);
Working violin for FF and chrome.
Kaiido
source share