Recorderjs: Buffer is always empty

2k views Asked by At

I'm building a simple voice chat app. I decide to use NodeJS, but I can't understand why buffers are always empty.

I'm using https://github.com/mattdiamond/Recorderjs

My code looks like this:

var audio_context;
var recorder;

function startUserMedia(stream) {
    var input = audio_context.createMediaStreamSource(stream);    
    input.connect(audio_context.destination);    
    recorder = new Recorder(input);
}

function process() {
 recorder.record();

 setTimeout(function() {
    recorder.getBuffer(function(data) {
        console.log(data);
    });
 }, 3000);
}

window.onload = function init() {
try {
  window.AudioContext = window.AudioContext || window.webkitAudioContext;
  navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia;
  window.URL = window.URL || window.webkitURL;

  audio_context = new AudioContext;
} catch (e) {
    console.log(e);
}

navigator.getUserMedia({audio: true}, startUserMedia);

setTimeout(process, 1500); 
};

The problem is that when the getBuffer callback is executed data is always containing 2 empty arrays :(

1

There are 1 answers

8
kronion On

I changed your code in process a little bit to make it easier to see what is going on.

function process() {
  console.log('Entered process');
  console.log(recorder);
  recorder && recorder.record();

  setTimeout(function() {
    console.log('Trying to get buffer');
    recorder.stop();
    recorder.getBuffer(function(data) {
      console.log(data);
      createDownloadLink();
      recorder.clear();
    });
  }, 3000);
}

I also added one line to the beginning of startUserMedia:

console.log('Initializing');

When you visit the page, Chrome should ask you to allow the use of your microphone. If you allow the microphone to be used before 'Entered process' prints in your console, everything should work correctly. You'll see the message 'Initializing' along with the Recorder object followed by 'Entered process'. Your arrays won't be empty, and a player should appear on the page allowing you to listen to the recording.

However, if 'Entered process' prints in the console before 'Initializing' (meaning you didn't allow the use of the microphone quickly enough), you will get back two empty arrays. Notice that console.log(recorder) now returns 'undefined' rather than the Recorder object.

The function startUserMedia is a callback for navigator.getUserMedia, the function which tells the browser to prompt the user for permission to use a required media device (in this case your microphone). The callback is not executed until the user has given permission. The variable recorder is initialized in startUserMedia, so we must wait for the user to give permission before we can use the Recorder object's API. process, however, tries to record after a brief delay, regardless of whether or not permission has been given. This leads to the race condition described above.

Edit: You can, of course, give yourself more time to react by increasing setTimeout(process, 1500).

Two last notes:
1. Make sure you are using Chrome!
2. I added the lines recorder.stop() and recorder.clear() to process. Without these lines, you will find that the audio recorded when you first load the page is prepended to your next recording.