Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MediaStreamRecorder doesn't fire the ondataavailable event

I am using an open source JavaScript library MediaStreamRecorder to record audio and video webRTC calls in Mozilla Firefox and Google Chrome.

The calls are recording successfully but I am facing the following issue.

If I use the time interval of 1 second (1000ms) in multiStreamRecorder.start() then multiStreamRecorder.ondataavailable event doesn't fire. And that's why No error or No log in console.

But, if I use the time interval of 1.5 seconds (1500ms) or greater, it fires the multiStreamRecorder.ondataavailable event and everything works perfectly fine. (Only in Video Case)

I want to keep the interval to 1 second (1000ms) only.

var ws;

function start() {

    ws = new WebSocket("wss://xyz/");

    ws.onopen = function () {
        console.log("WebSocket has been opened!");
    };

    ws.onmessage = function (message) {
        console.log("A messsage is received from WebSocket Server.", message);
    };

    ws.onclose = function (e) {
        console.log('WebSocket is closed. Reconnection will be attempted in 5 second.', e.reason);
        setTimeout(function () {
            start();
        }, 5000);
    };

    ws.onerror = function (err) {
        console.error('WebSocket encountered an error: ', err.message, 'Closing WebSocket');
        ws.close();
    };

}

start();


function startRecording(localStream, remoteStream) {

    if (localStream != null && remoteStream != null) {

        multiStreamRecorder = new MultiStreamRecorder([localStream, remoteStream], "video/webm");
        multiStreamRecorder.mimeType = "video/webm";

        multiStreamRecorder.ondataavailable = function (blob) {

            console.log("sending blob to websocket server", blob);
            ws.send(blob);

        };

        // It doesn't work with the 1000ms time interval
        multiStreamRecorder.start(1500);

    }
    else{
        console.error("One or more streams are null.");
    }

}
like image 485
Suhaib Janjua Avatar asked Apr 17 '17 13:04

Suhaib Janjua


2 Answers

I suspect one second is not enough time for the camera stream to warm up. While you can attach a recorder to a stream instantly, it doesn't appear to be ready for play/recording in zero time.

Video elements have .onloadedmetadata to let you wait for data to be ready; recorders do not.

You can make one though (use https fiddle for Chrome):

var haveLoadedMetadata = stream => {
  let preview = document.createElement("video");
  preview.srcObject = stream;
  return new Promise(resolve => preview.onloadedmetadata = resolve); 
};

var start = ms => navigator.mediaDevices.getUserMedia({video: true})
  .then(stream => haveLoadedMetadata(stream)
    .then(() => record(stream, ms))
    .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);

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;
<button onclick="start(1000)">Record 1 second!</button>
<div id="div"></div><br>
<video id="video" height="120" width="160" autoplay></video>
<a id="link"></a>

(Both Chrome and Firefox implement MediaRecorder directly, so I've answered using that).

like image 175
jib Avatar answered Oct 24 '22 09:10

jib


I had a similar problem. it didnt fired ondataavailable event unless i started recording and stopped several times. After 2 days found out that problem was my microphone drivers :). It probably keeps trying microphone so it takes few seconds till it figure out that it doesnt work. Once set audio to false all works perfectly. Just no sound lol.

like image 28
Igor Mizak Avatar answered Oct 24 '22 11:10

Igor Mizak