How can we mix canvas stream with audio stream using mediaRecorder [duplicate]
Asked Answered
S

1

6

I have a canvas stream using canvas.captureStream(). I have another video stream from webrtc video call. Now i want to mix canvas stream with audio tracks of the video stream.How can i do that?

Superman answered 12/10, 2016 at 6:41 Comment(0)
E
4

Use the MediaStream constructor available in Firefox and Chrome 56, to combine tracks into a new stream:

let stream = new MediaStream([videoTrack, audioTrack]);

The following works for me in Firefox (Use https fiddle in Chrome, though it errors on recording):

navigator.mediaDevices.getUserMedia({audio: true})
  .then(stream => record(new MediaStream([stream.getTracks()[0],
                                          whiteNoise().getTracks()[0]]), 5000)
    .then(recording => {
      stop(stream);
      video.src = link.href = URL.createObjectURL(new Blob(recording));
      link.download = "recording.webm";
      link.innerHTML = "Download recording";
      log("Playing "+ recording[0].type +" recording:");
    })
    .catch(log))
  .catch(log);

var whiteNoise = () => {
  let ctx = canvas.getContext('2d');
  ctx.fillRect(0, 0, canvas.width, canvas.height);
  let p = ctx.getImageData(0, 0, canvas.width, canvas.height);
  requestAnimationFrame(function draw(){
    for (var i = 0; i < p.data.length; i++) {
      p.data[i++] = p.data[i++] = p.data[i++] = Math.random() * 255;
    }
    ctx.putImageData(p, 0, 0);
    requestAnimationFrame(draw);
  });
  return canvas.captureStream(60);
}

var record = (stream, ms) => {
  var rec = new MediaRecorder(stream), data = [];
  rec.ondataavailable = e => data.push(e.data);
  rec.start();
  log(rec.state + " for "+ (ms / 1000) +" seconds...");
  var stopped = new Promise((y, n) =>
      (rec.onstop = y, rec.onerror = e => n(e.error || e.name)));
  return Promise.all([stopped, wait(ms).then(_ => rec.stop())]).then(_ => data);
};

var stop = stream => stream.getTracks().forEach(track => track.stop());
var wait = ms => new Promise(resolve => setTimeout(resolve, ms));
var log = msg => div.innerHTML += "<br>" + msg;
<div id="div"></div><br>
<canvas id="canvas" width="160" height="120" hidden></canvas>
<video id="video" width="160" height="120" autoplay></video>
<a id="link"></a>
Eviaevict answered 13/10, 2016 at 4:30 Comment(3)
Shouldn't the correct way be by using MediaStream.addTrack ? (Even if it doesn't work in FF.) Also, Chrome still prefixes MediaStream constructor.Tillich
@Tillich They're both correct. The constructor works for me in Chrome Canary without the chrome://flags/#enable-experimental-web-platform-features flag, though something in the recording fails. Hope both browsers fix their bugs soon.Eviaevict
Yes it's unprefixed in canary 56, but in stable 53, you still need to call new webkitMediaStream(). I made an ugly worakround to handle both browsers at the end of this dupe. And yes, there are still a lot of bugs in both UAs...Tillich

© 2022 - 2024 — McMap. All rights reserved.