Android AudioRecord - Won't Initialize 2nd tim

2020-02-26 06:31发布

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条回答
戒情不戒烟
2楼-- · 2020-02-26 06:45

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.

查看更多
欢心
3楼-- · 2020-02-26 06:47

My AudioRecord didn't initialize because it was static

查看更多
对你真心纯属浪费
4楼-- · 2020-02-26 06:51

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.

查看更多
神经病院院长
5楼-- · 2020-02-26 06:59

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

查看更多
爱情/是我丢掉的垃圾
6楼-- · 2020-02-26 07:01

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;
    }
}
查看更多
登录 后发表回答