Play Back audio from mic in real Time

android, audio, buffer

Solution

This works for me:

boolean isRecording = false;
AudioManager am = null;
AudioRecord record = null;
AudioTrack track = null;

@Override
protected void onCreate(Bundle savedInstanceState)
{
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    setVolumeControlStream(AudioManager.MODE_IN_COMMUNICATION);

    initRecordAndTrack();

    am = (AudioManager) this.getSystemService(Context.AUDIO_SERVICE);
    am.setSpeakerphoneOn(true);

    (new Thread()
    {
        @Override
        public void run()
        {
            recordAndPlay();
        }
    }).start();

    Button startButton = (Button) findViewById(R.id.start_button);
    startButton.setOnClickListener(new OnClickListener()
    {
        @Override
        public void onClick(View v)
        {
            if (!isRecording)
            {
                startRecordAndPlay();
            }
        }
    });
    Button stopButton = (Button) findViewById(R.id.stop_button);
    stopButton.setOnClickListener(new OnClickListener()
    {
        @Override
        public void onClick(View v)
        {
            if (isRecording)
            {
                stopRecordAndPlay();
            }
        }
    });
}

private void initRecordAndTrack()
{
    int min = AudioRecord.getMinBufferSize(8000, AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT);
    record = new AudioRecord(MediaRecorder.AudioSource.VOICE_COMMUNICATION, 8000, AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT,
                             min);
    if (AcousticEchoCanceler.isAvailable())
    {
        AcousticEchoCanceler echoCancler = AcousticEchoCanceler.create(record.getAudioSessionId());
        echoCancler.setEnabled(true);
    }
    int maxJitter = AudioTrack.getMinBufferSize(8000, AudioFormat.CHANNEL_OUT_MONO, AudioFormat.ENCODING_PCM_16BIT);
    track = new AudioTrack(AudioManager.MODE_IN_COMMUNICATION, 8000, AudioFormat.CHANNEL_OUT_MONO, AudioFormat.ENCODING_PCM_16BIT, maxJitter,
                           AudioTrack.MODE_STREAM);
}

private void recordAndPlay()
{
    short[] lin = new short[1024];
    int num = 0;
    am.setMode(AudioManager.MODE_IN_COMMUNICATION);
    while (true)
    {
        if (isRecording)
        {
            num = record.read(lin, 0, 1024);
            track.write(lin, 0, num);
        }
    }
}

private void startRecordAndPlay()
{
    record.startRecording();
    track.play();
    isRecording = true;
}

private void stopRecordAndPlay()
{
    record.stop();
    track.pause();
    isRecording = false;
}

You also need two buttons in your `activity_main` layout with the id `start_button` and `stop_button`.

This sample also contains an EchoCanceler!

Good luck!

Problem

I have a function , that records audio, and stores it into a file. This is what is looks like: ``` private void startRecord(){ File file = new File(Environment.getExternalStorageDirectory(), "test.pcm"); int sampleFreq = (Integer)spFrequency.getSelectedItem(); try { file.createNewFile(); OutputStream outputStream = new FileOutputStream(file); BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(outputStream); DataOutputStream dataOutputStream = new DataOutputStream(bufferedOutputStream); int minBufferSize = AudioRecord.getMinBufferSize(sampleFreq, AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT); short[] audioData = new short[minBufferSize]; AudioRecord audioRecord = new AudioRecord(MediaRecorder.AudioSource.MIC, sampleFreq, AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT, minBufferSize); audioRecord.startRecording(); while(recording){ int numberOfShort = audioRecord.read(audioData, 0, minBufferSize); for(int i = 0; i < numberOfShort; i++){ dataOutputStream.writeShort(audioData[i]); } } audioRecord.stop(); dataOutputStream.close(); } catch (IOException e) { e.printStackTrace(); } } ``` I have another function, called playrecord , that plays back this recorded audio: ``` void playRecord(){ File file = new File(Environment.getExternalStorageDirectory(), "test.pcm"); int shortSizeInBytes = Short.SIZE/Byte.SIZE; int bufferSizeInBytes = (int)(file.length()/shortSizeInBytes); short[] audioData = new short[bufferSizeInBytes]; try { InputStream inputStream = new FileInputStream(file); BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream); DataInputStream dataInputStream = new DataInputStream(bufferedInputStream); int i = 0; while(dataInputStream.available() > 0){ audioData[i] = dataInputStream.readShort(); i++; } dataInputStream.close(); int sampleFreq = (Integer)spFrequency.getSelectedItem(); AudioTrack audioTrack = new AudioTrack( AudioManager.STREAM_MUSIC, sampleFreq, AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT, bufferSizeInBytes, AudioTrack.MODE_STREAM); audioTrack.play(); audioTrack.write(audioData, 0, bufferSizeInBytes); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } ``` These two functions work fine independently. If I call startRecord() , and then call playRecord, I am able to hear the audio. But what I want to do is, play back the sound in REAL TIME , i.e. as soon as I start recording, I want the audio to play. What should I do to achieve that ?

Original source