Android AudioRecord - Won't Initialize 2nd time

13.4k views Asked by At

Hej, im currently trying to get AudioRecord to work. Because I need it in a bigger project. But it seems to mess up a lot. I have been trying alot of things, so I went back to basic when I traced this bug. I am using my Samsung Galaxy S as my debugdevice.

My problem is, first time after a reboot of my device I can initialize the AudioRecord object I create without problems. But the second time I run it, it won't initialize the AudioRecord object. I have tried several frequencies, fyi.

Here is my code:

package android.audiorecordtest;

import android.app.Activity;
import android.media.AudioFormat;
import android.media.AudioRecord;
import android.media.MediaRecorder;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;

public class AudioRecordTest extends Activity {

    int frequency;
    AudioRecord audRec;
    TextView txtVw;

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        txtVw = (TextView) findViewById(R.id.txtVw);


        frequency=8000;
        int bufferSize=(AudioRecord.getMinBufferSize(frequency, AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT))*2;
        if (bufferSize>0) {
            audRec = new AudioRecord(MediaRecorder.AudioSource.MIC, frequency, AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT, bufferSize);
                int status = audRec.getState();
        if (status == AudioRecord.STATE_INITIALIZED) {
            txtVw.setText("Initialized" + frequency);
        } else {
            txtVw.setText("Not Initialized i=" + frequency);
        }
        }

After a few hours of looking through logcat information i found this event

    02-28 10:46:37.048: DEBUG/dalvikvm(4477): GC_EXPLICIT freed 1801 objects / 98944 bytes in 97ms
02-28 10:46:37.048: VERBOSE/AudioRecord(4477): stop

Which seems to "release the native hold on the AudioRecord. So i tried doing an override of finalize with my Audiorecord object.release(). This didnt work though.. Anyone have any idea?

5

There are 5 answers

1
Jordan On BEST ANSWER

I was able to reproduce your problem (on a Samsung phone). I added an onDestroy() method releasing the record:

@Override
public void onDestroy() { 
    super.onDestroy();
    System.out.println("OnDestroy");
    audRec.release();
}

After adding this, the audioRecord seems to initialize correctly every time the activity is started.

1
Brian On

You should try to call audRec.stop() to release the resource.

4
Anders Metnik On

To Answer my own question, the only way i found it doable to use AudioRecord, is to never have it as an global variable, dont know why, but it seems it won't let you release the resources of the instance correctly if you do so.

1
AudioBubble On

I had the same problem, usually the audRec.release() helps indeed, but if you need to stop and start several times the following code is more robust. Plus, I had an issue that the recording took place in a separate thread and Android sometimes kills threads when running for a long time. So take a look at this code, it makes sure the recording is held even when the other thread is dead and upon the following audRec.start() it stops and releases:

import android.media.AudioFormat;
import android.media.AudioRecord;
import android.media.MediaRecorder; 

public class RecorderSingleton {

    private static final int FREQUENCY = 16000;

    public static RecorderSingleton instance = new RecorderSingleton();
    private AudioRecord recordInstance = null;
    private int bufferSize;

    private RecorderSingleton() {
        bufferSize = AudioRecord.getMinBufferSize(FREQUENCY, AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT);
    }

    public boolean init() {
        recordInstance = new AudioRecord(MediaRecorder.AudioSource.MIC, FREQUENCY, AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT, bufferSize);
        if (recordInstance.getState() == AudioRecord.STATE_UNINITIALIZED) {
            return false;
        }
        return true;
    }

    public int getBufferSize() {
        return bufferSize;
    }
    public boolean start() {
        if (recordInstance != null && recordInstance.getState() != AudioRecord.STATE_UNINITIALIZED) {
            if (recordInstance.getRecordingState() != AudioRecord.RECORDSTATE_STOPPED) {
                recordInstance.stop();
            }
            recordInstance.release();
        }
        if (!init()) {
            return false;
        }
        recordInstance.startRecording();
        return true;
    }

    public int read(short[] tempBuffer) {
        if (recordInstance == null) {
            return AudioRecord.ERROR_INVALID_OPERATION;
        }
        int ret = recordInstance.read(tempBuffer, 0, bufferSize);
        return ret;
    }

    public void stop() {
        if (recordInstance == null) {
            return;
        }
        recordInstance.stop();
        recordInstance.release();
    }
}

Then if you have a recorder thread you can use it as follows:

import android.media.AudioRecord;

public class Recorder implements Runnable {
    private int requiredSamples;
    private int takenSamples = 0;
    private boolean cancelled = false;

    public void run() {

        // We're important...
        android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_URGENT_AUDIO);

        int bufferRead = 0;
        int bufferSize = RecorderSingleton.instance.getBufferSize();
        short[] tempBuffer = new short[bufferSize];
        if (!RecorderSingleton.instance.start()) {
            return;
        }
        try {
            Log.d(RoomieConstants.LOG_TAG, "Recorder Started");
            while (takenSamples < requiredSamples && !cancelled) {
                bufferRead = RecorderSingleton.instance.read(tempBuffer);
                if (bufferRead == AudioRecord.ERROR_INVALID_OPERATION) {
                    throw new IllegalStateException("read() returned AudioRecord.ERROR_INVALID_OPERATION");
                } else if (bufferRead == AudioRecord.ERROR_BAD_VALUE) {
                    throw new IllegalStateException("read() returned AudioRecord.ERROR_BAD_VALUE");
                }
                takenSamples += bufferRead;
                // do something with the samples ...
                // ...
                // ...
            }
        } finally {
            // Close resources...
            stop();
        }
    }

    public void stop() {
        RecorderSingleton.instance.stop();
    }

    public void cancel() {
        cancelled  = true;
    }
}
0
Саша Серегин On

My AudioRecord didn't initialize because it was static