Android AudioRecord - Won't Initialize 2nd time
Asked Answered
Q

5

14

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?

Quaggy answered 28/2, 2011 at 8:41 Comment(3)
I'm really wondering why no one have any answers, is it because you guys can't recreate the problem, or because people just can't be bothered to help, or ?Quaggy
For those of you stumbling upon this, make sure you have the record permission!Aporia
@Aporia if you dont have the record permission then it wont even initialize the first time as my question title clearly states :) But yes if someone only have the problem with first initialization attempt then they should check their permissions in AndroidManifest.xmlQuaggy
R
12

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.

Raynata answered 13/4, 2011 at 1:44 Comment(1)
+1 For me, I needed the onCancelled() method of an AsyncTask, but I don't know how I'd have got to the bottom of the issue without this. Thanks. :)Callisto
E
6

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;
    }
}
Ekaterinburg answered 25/7, 2011 at 7:5 Comment(1)
Which value do you give requiredSamples in your particular case?Blida
Q
1

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.

Quaggy answered 7/3, 2011 at 13:41 Comment(4)
You should try it the way Jordan did it. I do it like that aswell, and it works just fine...Redbird
Dont have the implementation anymore, but yeah if he reproduced it, and solved it, im secure enough in it to give him a correct answer, thanks for bringing it to my attention.Quaggy
I must say that setting it to null is a bit over the top, after you call release(), the GC should automatically clean it up for you at some time, so you are free to re-initialise it.Redbird
I think I was trying to make a point, but good feedback. Corrected. :)Raynata
A
0

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

Arrestment answered 2/3, 2011 at 21:41 Comment(1)
Stop is only for stopping a running recording. But Release also has a try-catch to call stop, though release is releasing resources, not stop. As far as i have looked through the class. Else thanks.Quaggy
S
0

My AudioRecord didn't initialize because it was static

Sexual answered 24/7, 2019 at 10:15 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.