Search code examples
androidaudiorecord

AudioRecord buffer size


I initialize my AudioRecord instance as follows:

// TODO: remember to add RECORD_AUDIO permission
int audioSource = MediaRecorder.AudioSource.MIC;

// TODO: I should consider Nyquist frequency and tell the user if her device can correctly detect frequencies in the range of her instrument
int sampleRateInHz = getDeviceSampleRate(context);

int channelConfig = AudioFormat.CHANNEL_IN_MONO;
int audioFormat = AudioFormat.ENCODING_PCM_16BIT;

// TODO: bufferSizeInBytes should be set according to minimum detectable frequency in order to have at least three periods
int bufferSizeInBytes = AudioRecord.getMinBufferSize(sampleRateInHz, channelConfig, audioFormat);

AudioRecord audioRecord = new AudioRecord(audioSource, sampleRateInHz, channelConfig, audioFormat, bufferSizeInBytes);

Here are my questions:

  • I have to read shorts from the buffer because I specified ENCODING_PCM_16BIT. Is it correct?
  • If minimum buffer size in bytes is 1000 I'll have 500 shorts. So if I need 4096 samples I have to set bufferSizeInBytes to 8192. Is it correct?

Thanks.


Solution

  • I have to read shorts from the buffer because I specified ENCODING_PCM_16BIT. Is it correct?

    You should, but you don't necessarily have to. You may read the samples into a byte[], but it's up to you to handle the endianness when converting the bytes to shorts.

    If minimum buffer size in bytes is 1000 I'll have 500 shorts. So if I need 4096 samples I have to set bufferSizeInBytes to 8192. Is it correct?

    Actually, no.

    The minimum buffer size is the very minimum size that an AudioRecord instance will accept. It's like a threshold. AudioRecord constructor documentation says:

    Using values smaller than getMinBufferSize() will result in an initialization failure.

    In some cases you may want to use a buffer size bigger than the minimum. AudioRecord.getMinBufferSize() documentation` says:

    Note that this size doesn't guarantee a smooth recording under load, and higher values should be chosen according to the expected frequency at which the AudioRecord instance will be polled for new data.

    Here's an algorithm for reading 4096 16-bit samples:

    ByteArrayOutputStream mainBuffer = new ByteArrayOutputStream();
    
    int minimumBufferSize = AudioRecord.getMinBufferSize(...);
    
    byte[] readBuffer = new byte[minimumBufferSize];
    
    AudioRecord recorder = new AudioRecord(..., minimumBufferSize);
    
    recorder.startRecording();
    
    while (mainBuffer.size() < 8192) {
    
        // read() is a blocking call
        int bytesRead = recorder.read(readBuffer, 0, minimumBufferSize);
    
        mainBuffer.write(readBuffer, 0, bytesRead);
    }
    
    recorder.stop();
    
    recorder.release();