1

I'm using Recorder.js to record audio from Google Chrome desktop and mobile browsers. In my specific use case I need to record exactly 3 seconds of audio, starting and ending at a specific time.

Now I know that when recording audio, your soundcard cannot work in realtime due to hardware delays, so there is always a memory buffer which allows you to keep up recording without hearing jumps/stutters.

Recorder.js allows you to configure the bufferLen variable exactly for this, while sampleRate is taken automatically from the audio context object. Here is a simplified version of how it works:

var context = new AudioContext();
var recorder;
navigator.getUserMedia({audio: true}, function(stream) {
    recorder = new Recorder(context.createMediaStreamSource(stream), {
        bufferLen: 4096
    });
});

function recordLoop() {
    recorder.record();
    window.setTimeout(function () {
        recorder.stop();
    }, 3000);
}

The issue i'm facing is that record() does not offset for the buffer latency and neither does stop(). So instead of getting a three second sound, it's 2.97 seconds and the start is cut off.

This means my recordings don't start in the same place, and also when I loop them, the loops are different lengths depending on your device latency!!

There are two potentially solutions I see here:

  • Adjust Recorder.js code to offset the buffer automatically against your start/stop times (maybe add new startSync/stopSync functions)
  • Calculate the latency and create two offset timers to start and stop Recorder.js at the correct points in time.

I'm trying solution 2, because solution 1 requires knowledge of buffer arrays which I don't have :( I believe the calculation for latency is:

var bufferSize = 4096;
var sampleRate = 44100
var latency = (bufferSize / sampleRate) * 2; // 0.18575963718820862 secs

However when I run these calculations in a real test I get:

var duration = 2.972154195011338 secs
var latency = 0.18575963718820862 secs
var total = duration + latency // 3.1579138321995464 secs

Something isn't right, it doesn't make 3 seconds and it's beginning to confuse me now! I've created a working fork of Recorder.js demo with a log:

http://kmturley.github.io/Recorderjs/

Any help would be greatly appreciated. Thanks!

Kim T
  • 5,770
  • 1
  • 52
  • 79
  • Have updated my code example with a working version. However it would be nicer to add this as a feature to Recorder.js – Kim T Feb 11 '15 at 04:07

1 Answers1

2

I'm a bit confused by your concern for the latency. Yes, it's true that the minimum possible latency is going to be the related to the length of the buffer but there are many other latencies involved. In any case, the latency has nothing to do with the recording duration, which seems to me to be what your question is about.

If you want to record an exactly 3 second long buffer at 44100 that is 44100*3=132,300 samples. The buffer size is 4096 samples and the system is only going to record an even multiple of that number. Given that the closest you are going to get is to record either 32 or 33 complete buffers. This gives either 131072 (2.97 seconds) or 135168 (3.065 seconds) samples.

You have a couple options here.

  • Choose a buffer length that evenly divides the sample rate. e.g. 11025. You can then record exactly 12 buffers.
  • Record slightly longer than the 3.0 seconds you need and then throw the extra 2868 samples away.
jaket
  • 9,140
  • 2
  • 25
  • 44
  • If I try and use a custom buffer size it gives an error "Uncaught IndexSizeError: Failed to execute 'createScriptProcessor' on 'AudioContext': buffer size (4410) must be a power of two between 256 and 16384." going to try the second suggestion now! – Kim T Feb 11 '15 at 03:01
  • Nice that worked. Have update my code example here: http://kmturley.github.io/Recorderjs/ however I'm thinking it's more efficient to add this as an option to Recorder.js than do it externally. I tried adding a setLength method to set the recording length, but this throws errors :( – Kim T Feb 11 '15 at 04:07
  • Got this working with a new Recorder.js option called maxLength: https://github.com/kmturley/Recorderjs I have sent a pull request to the libraries owner too. Thanks for your help! – Kim T Feb 12 '15 at 03:21