programacion - Entrada y salida de audio inmediata para Android
manual programacion android español pdf (3)
Esto es realmente muy difícil en Android. Los propios Google tienen un video muy bueno (pero un poco largo) que explica los problemas.
También tienen una página que explica sus métodos de prueba de latencia y puntos de referencia para varios dispositivos.
Esencialmente, Android no puede reproducir audio de latencia cero, sin embargo, no hay nada que impida que los socios de hardware agreguen las extensiones de plataforma y hardware necesarias para hacerlo.
En mi aplicación de Android, me gustaría captar algo de audio del micrófono del teléfono inteligente y reproducirlo de inmediato, en vivo, como un micrófono, sin demora. Actualmente estoy pensando en usar las clases AudioRecord
y AudioTrack
(de lo que he leído), pero no estoy muy seguro de cómo proceder.
Revisé algunas otras preguntas en Stack Overflow pero no responden exactamente a lo que me gustaría hacer. Y la mayoría son de 2012.
Entonces, ¿cómo puedo usar estas clases para ingresar y emitir audio simultáneamente?
TAMBIÉN: eché un vistazo a la MediaRecorder API
, pero por lo que leí, eso requiere que guarde el audio en un archivo, lo que no quiero hacer. ¿Se puede ajustar para cumplir mis requisitos? ¿O estoy mejor usando AudioRecord
?
Gracias
EDITAR:
Aquí está mi código actualizado a continuación como sugirió @Pradip Pramanick:
final Thread record = new Thread(new Runnable() {
@Override
public void run() {
while (!Thread.interrupted()) {
MediaRecorder microphone = new MediaRecorder();
microphone.setAudioSource(MediaRecorder.AudioSource.MIC);
microphone.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
microphone.setOutputFile(filename);
microphone.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
try {
microphone.prepare();
} catch (IOException e) {
e.printStackTrace();
}
microphone.start();
}
}
});
final Thread play = new Thread(new Runnable() {
@Override
public void run() {
while (!Thread.interrupted()) {
player = new MediaPlayer();
try {
player.setDataSource(filename);
player.prepare();
player.start();
} catch (IOException e) {
e.printStackTrace();
}
}
}
});
Estoy recibiendo una Illegal State Exception | Start failed: -38
Illegal State Exception | Start failed: -38
. Pero estoy llamando a microphone.start
after microphone.prepare
... ¿Cuál parece ser el problema? Busqué en otros hilos que decían que podría haber otras aplicaciones de fondo usando el micrófono. Busqué en mi dispositivo: Moto X Play (3ª generación) y no encontré ninguno. (Incluso desactivé el reconocimiento de voz "Ok Google", pero el error siguió apareciendo).
REGISTRO DE ERRORES:
Aquí está el log-cat mostrando los errores más recientes:
01-31 09:37:21.064 344-3339/? E/MediaPlayerService: offset error
01-31 09:37:21.065 1835-1922/com.synerflow.testapp E/MediaPlayer: Unable to create media player
01-31 09:37:21.065 1835-1922/com.synerflow.testapp I/Player: player.prepare() has failed
01-31 09:37:21.065 1835-1922/com.synerflow.testapp W/System.err: java.io.IOException: setDataSourceFD failed.: status=0x80000000
La excepción IO parece estar en player.setDataSource(filename)
, la variable de nombre de archivo es una cadena: Environment.getExternalStorageDirectory().getAbsolutePath() + "/voice.3gp"
Hasta donde puedo pensar, se puede hacer de una manera muy simple. No lo he probado, pero tú lo intentas. Creo que funcionará:
Crea dos hilos uno para grabar otro para jugar. Digamos que los hilos son TRecord y TPlay.
En el método de ejecución de TRecord haz esto:
public void run(){
MediaRecorder mRecorder = null;
mRecorder = new MediaRecorder();
mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
mRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
mRecorder.setOutputFile(mFileName);
mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
try {
mRecorder.prepare();
} catch (IOException e) {
//todo
}
mRecorder.start();
}
Y es el método de ejecución de TPlay hacer esto:
public void run() {
MediaPlayer mPlayer = null;
mPlayer = new MediaPlayer();
try {
mPlayer.setDataSource(mFileName);
mPlayer.prepare();
mPlayer.start();
} catch (IOException e) {
//todo
}
}
Ahora en mainactivity simplemente crea dos hilos. Primero inicia el hilo TRecord luego Tplay. Intentalo.
Aquí está el código para la extensión de archivo:
mFileName = Environment.getExternalStorageDirectory().getAbsolutePath();
mFileName += "/audiorecordtest.3gp";
prueba esto. No he corrido esto.
recorder = new AudioRecord(MediaRecorder.AudioSource.MIC,
RECORDER_SAMPLERATE, RECORDER_CHANNELS,
RECORDER_AUDIO_ENCODING, bufferSize * BytesPerElement);
recorder.startRecording();
isRecording = true;
recordingThread = new Thread(new Runnable() {
public void run() {
try {
int intSize = android.media.AudioTrack.getMinBufferSize(RECORDER_SAMPLERATE,AudioFormat.CHANNEL_OUT_MONO , RECORDER_AUDIO_ENCODING);
byte[] sData = new byte[bufferSize];
AudioTrack at = new AudioTrack(AudioManager.STREAM_MUSIC, RECORDER_SAMPLERATE, AudioFormat.CHANNEL_OUT_MONO, RECORDER_AUDIO_ENCODING, intSize, AudioTrack.MODE_STREAM);
while(isRecording){
recorder.read(sData, 0, bufferSize); //isRecording = false; onStop button
if (at!=null) {
at.play();
// Write the byte array to the track
at.write(sData, 0, sData.length);
at.stop();
at.release();
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}, "AudioRecorder Thread");
recordingThread.start();