Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AudioRecord - how to get data in to buffer?

Tags:

android

buffer

I' m having some issues using AudioRecord class. I want to store recorded data in a buffer, but I' m not sure what is the proper way to achieve that. I went through great number of examples, but most of them were comlicated and representing many different approaches. I' m looking for simple one or simple explanation.

Here are my audio settings for my project:

int audioSource = AudioSource.MIC;
int sampleRateInHz = 8000;
int channelConfig = AudioFormat.CHANNEL_IN_MONO;
int audioFormat = AudioFormat.ENCODING_PCM_16BIT;
int bufferSizeInBytes = AudioRecord.getMinBufferSize(sampleRateInHz, channelConfig, audioFormat);

short[] buffer = new short[bufferSizeInBytes];

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

I' m trying to create a Recording function:

public void Recording() {
    audioRecorder.startRecording();
    ...
    audioRecorder.stop();
    audioRecorder.release();
}

I know that I' m supposed to use .read(short[] audioData, int offsetInShorts, int sizeInShorts) function. And here my problems start. I' m not sure how audioData buffer works - I assume function puts recorded samples into the audioData. What happens if it completely filled with data? It starts rewriting from the earliest position? If it does I believe I have to copy all collected samples somwhere else. It raises another question - how can I check if .read(...) function buffer is already full? Do I need to measure time and copy buffer content or there is another way to reach that? Also do I need to create a thread for whole recording operation?

Sorry for asking so many questions in one topic :)

like image 574
Arxas Avatar asked Nov 21 '12 11:11

Arxas


1 Answers

Answer to your questions ::

recorder.read(...) does not necessarily read any data at all. You should probably rewrite that loop to pause for a short while (e.g., 50ms) between calls to read. It should also not queue the buffer until the buffer has data. Also, since the buffer may not be full, you probably need to use a data structure that maintains a count of the number of bytes. A ByteBuffer comes to mind as a good candidate. You can stuff bytes into it in the read loop and when it gets full enough, queue it for transmission and start another one.

offcourse you need to create a thread for looping it. as shown in below code.

Here's a modified version of the recording loop that does proper error checking. It uses a Queue<ByteBuffer> instead of a Queue<byte[]>:

private void startRecording() {

    recorder.startRecording();
    isRecording = true;
    recordingThread = new Thread(new Runnable() {

        @Override
        public void run() {
            bData = ByteBuffer.allocate(BufferElements);
            bbarray = new byte[bData.remaining()];
            bData.get(bbarray);
            while (isRecording) {

                int result = recorder.read(bbarray, 0, BufferElements);
                System.out.println("READ DATA");
                if (result > 0) {
                    qArray.add(bData);

                    --your stuffs--
                    bData = ByteBuffer.allocate(BufferElements);
                } else if (result == AudioRecord.ERROR_INVALID_OPERATION) {
                    Log.e("Recording", "Invalid operation error");
                    break;
                } else if (result == AudioRecord.ERROR_BAD_VALUE) {
                    Log.e("Recording", "Bad value error");
                    break;
                } else if (result == AudioRecord.ERROR) {
                    Log.e("Recording", "Unknown error");
                    break;
                }
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    break;
                }
            }
        }
    }, "AudioRecorder Thread");
    recordingThread.start();
}

Of course, somewhere you'll need to call recorder.startRecording() or you won't get any data.

for working sample look at this example.

like image 107
Rahul Baradia Avatar answered Oct 13 '22 20:10

Rahul Baradia