Search code examples
androidwavaudio-recordingpcmbitrate

Change Bitrate of AudioRecord on Android


How can on Android the bits per sample be changed from 16 bit to 8 bit (or other bitrates) in a AudioRecord object when recording in wav format?

This doesn't work (as discussed for example here: Using AudioRecord with 8-bit encoding in android):

private static int RECORDER_AUDIO_ENCODING = 
         AudioFormat.ENCODING_PCM_8BIT; -->ERROR: Invalid Audio Format.
bufferSize = AudioRecord.getMinBufferSize(RECORDER_SAMPLERATE,RECORDER_CHANNELS,
         RECORDER_AUDIO_ENCODING);
recorder = new AudioRecord(MediaRecorder.AudioSource.MIC,RECORDER_SAMPLERATE, 
         RECORDER_CHANNELS,RECORDER_AUDIO_ENCODING, bufferSize);

With the header:

private void WriteWaveFileHeader(
        FileOutputStream out, long totalAudioLen,
        long totalDataLen, long longSampleRate, int channels,
        long byteRate) throws IOException {

        byte[] header = new byte[44];

        header[0] = 'R';  // RIFF/WAVE header
        ...header content...
        header[32] = (byte) (2 * 16 / 8);  // block align
        header[33] = 0;
        header[34] = (byte)RECORDER_BPP;  // bits per sample, set to 8
        ...header content...

        out.write(header, 0, 44);
    }

Solution

  • You need to record 16 Bit samples by using AudioFormat.ENCODING_PCM_16BIT because 8 Bit encoding is not generally working on Android devices.

    Then convert your 16 Bit buffer to 8 Bit on the fly prior to writing it into a wave sound file. But because 8 Bit wave files use unsigned integers (0-255) with silence being 128 instead of 0, my suggested conversion corrects for that. The following is just a code skeleton:

    // Your source above already defined a value for bufferSize and the recorder object
    sampleBufferShorts = new short[bufferSize];
    sampleBufferBytes = new short[bufferSize];
    int numberOfShortsRead = recorder.read(samleBufferShorts, 0, bufferSize);
    if (numberOfShortsRead != ERROR_INVALID_OPERATION && numberOfShortsRead != ERROR_BAD_VALUE) {
        for (int i = 0 ; i < numberOfShortsRead ; ++i)
            sampleBufferBytes[i] = (byte)((sampleBufferShorts[i]>>8)+128);
    }
    

    See https://stackoverflow.com/a/18777515/1986583 for a useful explanation why additional dithering would improve the resulting quality.