Android AudioRecord - не инициализируется 2 раза
Привет, я сейчас пытаюсь заставить AudioRecord работать. Потому что мне это нужно в большем проекте. Но, похоже, это сильно испортило. Я много чего пробовал, поэтому вернулся к основам, когда отследил эту ошибку. Я использую свой Samsung Galaxy S в качестве устройства отладки.
Моя проблема в том, что в первый раз после перезагрузки моего устройства я могу без проблем инициализировать объект AudioRecord, который я создаю. Но во второй раз я не буду инициализировать объект AudioRecord. Я пробовал несколько частот, к вашему сведению.
Вот мой код:
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);
}
}
После нескольких часов просмотра информации logcat я нашел это событие
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
Который, кажется, "освобождает родное удержание AudioRecord. Поэтому я попытался сделать переопределение finalize с моим объектом Audiorecord object.release(). Хотя это не сработало... У кого-нибудь есть идеи?"
4 ответа
Я смог воспроизвести вашу проблему (на телефоне Samsung). Я добавил метод onDestroy() для освобождения записи:
@Override
public void onDestroy() {
super.onDestroy();
System.out.println("OnDestroy");
audRec.release();
}
После добавления этого audioRecord, кажется, правильно инициализируется каждый раз, когда начинается действие.
У меня была такая же проблема, обычно audRec.release() действительно помогает, но если вам нужно остановиться и запустить несколько раз, следующий код будет более надежным. Кроме того, у меня была проблема, что запись происходила в отдельном потоке, и Android иногда убивал потоки при длительной работе. Итак, взгляните на этот код, он гарантирует, что запись удерживается даже тогда, когда другой поток мертв, и после следующего audRec.start() останавливается и освобождает:
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();
}
}
Тогда, если у вас есть записывающий поток, вы можете использовать его следующим образом:
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;
}
}
Чтобы ответить на мой собственный вопрос, единственный способ, который я счел возможным использовать AudioRecord, - это никогда не иметь его в качестве глобальной переменной, не знаю почему, но, похоже, он не позволит вам правильно освободить ресурсы экземпляра, если вы это сделаете так.
Вы должны попытаться вызвать audRec.stop(), чтобы освободить ресурс.
Моя AudioRecord не инициализировалась, потому что была статической