2

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 :(

Deepsy
  • 3,769
  • 7
  • 39
  • 71
  • From picture you included in answer, there is a message _“Resource interpreted as script but transferred with MIME type text/plain.”_. You have to correctly configure your server, see answers from [Chrome says “Resource interpreted as script but transferred with MIME type text/plain.”, what gives?](http://stackoverflow.com/questions/3467404/chrome-says-resource-interpreted-as-script-but-transferred-with-mime-type-text) – Anto Jurković Dec 11 '13 at 09:29
  • Sadly this wasn't the problem. – Deepsy Dec 11 '13 at 11:42

1 Answers1

1

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.

kronion
  • 711
  • 4
  • 14
  • To make him life easier I suggest to increase timeout in the line which calls `process` function: `setTimeout(process, 1500); ` so he has more time to react. If he is not fast enough, `recorder` will be undefined. – Anto Jurković Dec 10 '13 at 12:14
  • http://i.imgur.com/8L7LyUb.png I do everything as you wrote, but still I'm getting empty buffers for some reason. My code looks like http://pastebin.com/xPC8rHJ6 – Deepsy Dec 10 '13 at 18:52
  • Can you go into `recorder.js` and make these changes at line 22? `this.node.onaudioprocess = function(e){ console.log('here'); /* Add this */ if (!recording) return; console.log('good!); /* This too */ worker.postMessage({` Let me know what results you see. You should see pairs of 'here' and 'good' every time audio is processed. Of course, you do have a microphone connected, right? – kronion Dec 11 '13 at 03:27
  • This is my current code: http://pastebin.com/ynVE5E4y, I did the changes you said and I'm not getting here or good for some reason..Yes I have microphone connected and when I open the page I'm hearing myself – Deepsy Dec 11 '13 at 11:42
  • Does the provided example work for you? What happens if you use the provided record and stop buttons instead of `process`? My guess right now is that the `onaudioprocess` event handler isn't firing, but I'm not sure why. – kronion Dec 11 '13 at 19:49
  • @kronion seems the onaudioprocess isn't firing, I even tried http://pastebin.com/FfK6H3xT, I just get initializing :( – Deepsy Dec 15 '13 at 00:15
  • @Deepsy unless you have an outdated version of Chrome I'm not sure why its web audio API wouldn't work... I think you should go ahead and see what happens if you run the provided example `example_simple_exportwav.html`. If it doesn't work, your browser is certainly the problem. – kronion Dec 15 '13 at 04:34
  • well I tried example_simple_exportwav.html and still not working ;/ seems my browser is the issue, but I'm using the lastest chrome http://i.imgur.com/mnn4pGc.png – Deepsy Dec 16 '13 at 02:45