Mi aplicación Java para Android necesita grabar datos de audio en la memoria RAM y procesarlos. Es por eso que utilizo la clase "AudioRecord" y no la "MediaRecorder" (graba solo en el archivo).Android: problema de la clase AudioRecord: la devolución de llamada nunca se llama
Hasta ahora, utilicé un sondeo de bucle ocupado con "read()" para los datos de audio. esto ha estado funcionando hasta ahora, pero bloquea demasiado la CPU. Entre dos sondeos, puse el hilo en modo de suspensión para evitar el uso de la CPU al 100%. Sin embargo, esta no es realmente una solución limpia, ya que el tiempo de reposo es no garantizado y debe restar un tiempo de seguridad para no perder fragmentos de audio . Esto no es óptimo para la CPU. Necesito tantos ciclos de CPU libres como sea posible para un hilo en paralelo.
Ahora implementé la grabación usando "OnRecordPositionUpdateListener". Esto se ve muy prometedor y la forma correcta de hacerlo de acuerdo con los SDK Docs. Todo parece funcionar (abrir el dispositivo de audio, leer() los datos, etc.) pero nunca se llama al Listner.
¿Alguien sabe por qué?
Información: Estoy trabajando con un dispositivo real, no debajo del emulador. La grabación utilizando un bucle de ocupado funciona básicamente (sin embargo, no saturando). Solo el Callback Listener nunca se llama.
Aquí hay un fragmento de mi código fuente:
public class myApplication extends Activity {
/* audio recording */
private static final int AUDIO_SAMPLE_FREQ = 16000;
private static final int AUDIO_BUFFER_BYTESIZE = AUDIO_SAMPLE_FREQ * 2 * 3; // = 3000ms
private static final int AUDIO_BUFFER_SAMPLEREAD_SIZE = AUDIO_SAMPLE_FREQ/10 * 2; // = 200ms
private short[] mAudioBuffer = null; // audio buffer
private int mSamplesRead; // how many samples are recently read
private AudioRecord mAudioRecorder; // Audio Recorder
...
private OnRecordPositionUpdateListener mRecordListener = new OnRecordPositionUpdateListener() {
public void onPeriodicNotification(AudioRecord recorder) {
mSamplesRead = recorder.read(mAudioBuffer, 0, AUDIO_BUFFER_SAMPLEREAD_SIZE);
if (mSamplesRead > 0) {
// do something here...
}
}
public void onMarkerReached(AudioRecord recorder) {
Error("What? Hu!? Where am I?");
}
};
...
public void onCreate(Bundle savedInstanceState) {
try {
mAudioRecorder = new AudioRecord(
android.media.MediaRecorder.AudioSource.MIC,
AUDIO_SAMPLE_FREQ,
AudioFormat.CHANNEL_CONFIGURATION_MONO,
AudioFormat.ENCODING_PCM_16BIT,
AUDIO_BUFFER_BYTESIZE);
} catch (Exception e) {
Error("Unable to init audio recording!");
}
mAudioBuffer = new short[AUDIO_BUFFER_SAMPLEREAD_SIZE];
mAudioRecorder.setPositionNotificationPeriod(AUDIO_BUFFER_SAMPLEREAD_SIZE);
mAudioRecorder.setRecordPositionUpdateListener(mRecordListener);
mAudioRecorder.startRecording();
/* test if I can read anything at all... (and yes, this here works!) */
mSamplesRead = mAudioRecorder.read(mAudioBuffer, 0, AUDIO_BUFFER_SAMPLEREAD_SIZE);
}
}
Gracias, lo explicaste bien. – chaimp
su respuesta es muy útil. Le agradecería mucho si pudiera aclararme sobre cómo leer correctamente la transmisión de entrada en vivo desde un micrófono. Un bucle while constante parece inapropiado ya que bloquearía todo el proceso, ¿verdad? Pensé que las devoluciones de llamada estaban allí como una solución, pero a juzgar por su respuesta, no lo son. Gracias. – Tom
El ciclo while constante para leer datos de audio debe estar en un hilo separado. Ciertamente no puedes usar el hilo principal para leer audio. Las devoluciones de llamada se dispararían cuando se haya recopilado una cantidad adecuada de datos de audio. Podría poner la lógica de procesamiento en el bucle de lectura, o podría usar las devoluciones de llamada para activar el procesamiento en el búfer que acaba de leer.El bloque de lecturas, pero solo dentro de ese hilo, por lo que debería estar bien. –