Search code examples
androidaudiorecording

Android AudioRecording losing last few seconds of audio


Simple audio recorder code loses last seconds of audio.

Using the AudioRecord class I have reduced my troubles to a very simple case.

A start button, a stop button, and a thread that reads from the AudioRecord object and writes to a file.

It works well, but over a number of devices the last three seconds of the audio is not written to the file unless I continue to record audio for 3 seconds after the user presses the stop button.

I am using 44100 mono 16 bit mode.

Devices are Nexus something running 5.x and Samsung S4 running 5.0.1.

The bad case:

press start button, run thread (.start()) , press stop button. .stop() .release() call .sync() on file. last three seconds of audio does not make it to file.

The good case:

press start, run thread, (.start() press stop. continuing with the recording thread for 3 second, then call .stop() .release() call .sync() on file. all expected data is in the file.

The start button calls the following runnable, and the stop button sets recording = 0 which causes the thread to finish up.

(I removed all the try blocks to improve readability)

AudioRecord Setup

int minAudioBufferSizeInBytes = AudioRecord.getMinBufferSize( 44100, AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT);

mAudioRecorder = new AudioRecord(MediaRecorder.AudioSource.MIC, 44100, AudioFormat.CHANNEL_IN_MONO,  AudioFormat.ENCODING_PCM_16BIT , 4 * minAudioBufferSizeInBytes);

int mFileBufferSizeInBytes = 8 * minAudioBufferSizeInBytes;

recording = 1;

Record Thread (a runnable)

mAudioRecorder.startRecording();
while (recording == 1) {
readsize = mAudioRecorder.read(audiodata, 0, mFileBufferSizeInBytes/2);
if (readsize != AudioRecord.ERROR_INVALID_OPERATION && mAudioRecordFos != null) {
    mAudioRecordFos.write(audiodata,0,readsize); // File Output Stream
}
}
if (mRecorderRunOn > 0) {   // RunOn time in milliseconds
Log.d(TAG, "AudioRecord record reading on for " + mRecorderRunOn + "ms ");
long readon_ts = System.currentTimeMillis() + mRecorderRunOn;

while (System.currentTimeMillis() < readon_ts) {
    readsize = mAudioRecorder.read(audiodata, 0, mFileBufferSizeInBytes/2);
    if (readsize>0) {
    mAudioRecordFos.write(bytes,0,readsize); // File Output Stream
    }
}
}

mAudioRecordFos.getFD().sync();

mAudioRecorder.stop();
mAudioRecorder.release();

In another version I continued to read after calling .stop() until it reported no more data, but that version did not change the amount of lost data.


Solution

  • I am sorry to say the code in my OP works perfectly. It turns out the problem existed in my playback mechanism. I reduced the number of unknowns by using adb to extract the audio from the phone and then used alsa aplay to play the recording.

    I had thought I had checked that several times, but yet another pass through the testing identified the problem..

    Basically

    adb pull /storage/extSdCard/6178190842925110523
    aplay -r 48000 -c 1 -f S16_LE 6178190842925110523
    

    identified the problem as not in the record side of the code.