2015-12-28 15 views
18

Nella mia app per Android, mi piacerebbe prendere un po 'di audio dal microfono dello smartphone e riprodurlo immediatamente, dal vivo, come un microfono, senza ritardi. Attualmente sto pensando di utilizzare le classi AudioRecord e AudioTrack (da quello che ho letto), ma non sono abbastanza sicuro su come procedere.Ingresso e uscita audio immediato Android

Ho controllato alcune altre domande su Stack Overflow ma non rispondono esattamente a ciò che vorrei fare. E la maggior parte sono del 2012.

Quindi, come posso utilizzare queste classi per l'input e l'output audio simultaneamente?

ANCHE: ho dato un'occhiata al MediaRecorder API, ma da quello che ho letto, che richiede di salvare l'audio in un file, che io non voglio fare. Può essere tweeked per soddisfare le mie esigenze? O sto meglio usando solo AudioRecord?

Grazie

EDIT:

Ecco il mio codice aggiornato seguito come @Pradip Pramanick suggerito:

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(); 
       } 
      } 
     } 
    }); 

sto ottenendo un Illegal State Exception | Start failed: -38. Ma sto chiamando microphone.start dopo il microphone.prepare ... Quale sembra essere il problema? Ho cercato altri thread che dicevano che ci potrebbero essere altre app in background usando il microfono. Ho cercato il mio dispositivo: Moto X Play (terza generazione) e non ne ho trovato nessuno. (Ho persino disattivato il riconoscimento vocale "Ok Google", ma l'errore continuava a venire).

ERRORE LOG:

Ecco il log-gatto che mostra gli errori più recenti:

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 

L'eccezione IO sembra essere al player.setDataSource(filename), la variabile nome del file è una stringa: Environment.getExternalStorageDirectory().getAbsolutePath() + "\voice.3gp"

+0

Puoi dire perché vuoi farlo? –

+0

@ ste-fu Sto solo provando qualcosa. Sai come farlo? – SynerFlow

+1

Dovrebbe essere in grado di trasferire flussi come questo http://stackoverflow.com/questions/5381969/android-how-to-record-mp3-radio-audio-stream/5384161#5384161. Forse con un piccolo buffer anche. Mi chiedo solo perché davvero - e se dovessi subire un discreto feedback audio se lo facessi. –

risposta

3

Per quanto posso pensare si può fare in un modo molto semplice. Non l'ho provato, ma ci provi. Penso che funzionerà:

Creare due thread uno per registrare un altro per la riproduzione. Supponiamo che i thread siano TRecord e TPlay.

Nel metodo run di TRecord fare questo:

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(); 
} 

Ed metodo run di TPlay fare questo:

public void run() { 
MediaPlayer mPlayer = null; 
mPlayer = new MediaPlayer(); 
     try { 
      mPlayer.setDataSource(mFileName); 
      mPlayer.prepare(); 
      mPlayer.start(); 
     } catch (IOException e) { 
      //todo 
     } 
} 

Ora in mainactivity sufficiente creare due thread. Innanzitutto avvia il thread TRecord e poi Tplay. Provalo.

qui è il codice per estensione del file:

mFileName = Environment.getExternalStorageDirectory().getAbsolutePath(); 
mFileName += "/audiorecordtest.3gp"; 
+0

Ciao, qual è il nomeFile in questo caso? È un file predefinito? Inoltre, mi piacerebbe sbarazzarmi del file dopo che ho finito di parlare. Come si può fare? – SynerFlow

+0

Inoltre, quale dovrebbe essere l'estensione del file in questo caso? Potresti includere il codice che imposta il file di output/origine dati? – SynerFlow

+0

ok l'ho modificato. –

2

Questo è in realtà davvero difficile su Android. Google ha un ottimo (ma leggermente lungo) video che spiega i problemi.

Hanno anche a page explaining their latency testing methods and benchmarks per vari dispositivi.

Essenzialmente, Android non può eseguire l'audio a latenza zero, tuttavia non c'è nulla che impedisca ai partner hardware di aggiungere l'hardware e le estensioni della piattaforma necessarie per farlo.

0

provare questo. Non ho eseguito questo.

 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(); 
+0

Fa parte di uno dei miei progetti precedenti e funziona perfettamente. È necessario assemblarlo correttamente e inizializzare variabili come frequenza di campionamento 44100, ecc. :) – kAmol

+0

Quindi, funziona. Ma la voce è molto pacchiana ed estremamente strana. Qualche ragione per cui questo potrebbe accadere? Inoltre, quanto è 'BytesPerElement'? – SynerFlow

+0

Prova la frequenza di campionamento 44100 e 'RECORDER_AUDIO_ENCODING = AudioFormat.ENCODING_PCM_16BIT'. Spero tu abbia considerato buffersize = 'AudioRecord.getMinBufferSize (RECORDER_SAMPLERATE, RECORDER_CHANNELS, RECORDER_AUDIO_ENCODING)' Se funziona, non dimenticare di contrassegnare come risposta. :) – kAmol

Problemi correlati