Android: Need to record mic input

40,705

Solution 1

To record and play back audio in (almost) real time you can start a separate thread and use an AudioRecord and an AudioTrack.

Just be careful with feedback. If the speakers are turned up loud enough on your device, the feedback can get pretty nasty pretty fast.

/*
 * Thread to manage live recording/playback of voice input from the device's microphone.
 */
private class Audio extends Thread
{ 
    private boolean stopped = false;

    /**
     * Give the thread high priority so that it's not canceled unexpectedly, and start it
     */
    private Audio()
    { 
        android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_URGENT_AUDIO);
        start();
    }

    @Override
    public void run()
    { 
        Log.i("Audio", "Running Audio Thread");
        AudioRecord recorder = null;
        AudioTrack track = null;
        short[][]   buffers  = new short[256][160];
        int ix = 0;

        /*
         * Initialize buffer to hold continuously recorded audio data, start recording, and start
         * playback.
         */
        try
        {
            int N = AudioRecord.getMinBufferSize(8000,AudioFormat.CHANNEL_IN_MONO,AudioFormat.ENCODING_PCM_16BIT);
            recorder = new AudioRecord(AudioSource.MIC, 8000, AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT, N*10);
            track = new AudioTrack(AudioManager.STREAM_MUSIC, 8000, 
                    AudioFormat.CHANNEL_OUT_MONO, AudioFormat.ENCODING_PCM_16BIT, N*10, AudioTrack.MODE_STREAM);
            recorder.startRecording();
            track.play();
            /*
             * Loops until something outside of this thread stops it.
             * Reads the data from the recorder and writes it to the audio track for playback.
             */
            while(!stopped)
            { 
                Log.i("Map", "Writing new data to buffer");
                short[] buffer = buffers[ix++ % buffers.length];
                N = recorder.read(buffer,0,buffer.length);
                track.write(buffer, 0, buffer.length);
            }
        }
        catch(Throwable x)
        { 
            Log.w("Audio", "Error reading voice audio", x);
        }
        /*
         * Frees the thread's resources after the loop completes so that it can be run again
         */
        finally
        { 
            recorder.stop();
            recorder.release();
            track.stop();
            track.release();
        }
    }

    /**
     * Called from outside of the thread in order to stop the recording/playback loop
     */
    private void close()
    { 
         stopped = true;
    }

}

EDIT

The audio is not really recording to a file. The AudioRecord object encodes the audio as 16 bit PCM data and places it in a buffer. Then the AudioTrack object reads the data from that buffer and plays it through the speakers. There is no file on the SD card that you will be able to access later.

You can't read and write a file from the SD card at the same time to get playback/preview in real time, so you have to use buffers.

Solution 2

Following permission in manifest is required to work properly:

<uses-permission android:name="android.permission.RECORD_AUDIO" ></uses-permission>

Also, 2d buffer array is not necessary. The logic of the code is valid even with just one buffer, like this:

short[] buffer = new short[160];
while (!stopped) {
    //Log.i("Map", "Writing new data to buffer");
    int n = recorder.read(buffer, 0, buffer.length);
    track.write(buffer, 0, n);
}
Share:
40,705
Erick
Author by

Erick

Updated on July 09, 2022

Comments

  • Erick
    Erick almost 2 years

    Is there a way to record mic input in android while it is being process for playback/preview in real time? I tried to use AudioRecord and AudioTrack to do this but the problem is that my device cannot play the recorded audio file. Actually, any android player application cannot play the recorded audio file.

    On the other hand, Using Media.Recorder to record generates a good recorded audio file that can be played by any player application. But the thing is that I cannot make a preview/palyback while recording the mic input in real time.

  • Erick
    Erick almost 13 years
    Thanks for your answer. I just have 1 question though, what is the recorded audio file format? is it wav, mp3, 3gp, or other audio format?
  • Erick
    Erick almost 13 years
    Umm..well actually, as I have stated in my question, I'm already using AudioRecord and AudioTrack and I am writing the buffered data to the SD Card. This data is what I am referring to as the recorded audio file on my question. My problem here is that this file cannot be played when by any player on my device. I think my question is that, how can I convert this PCM data to 3gp or other audio format?
  • theisenp
    theisenp almost 13 years
    Ok, it seems that I misunderstood your question. You want to be able to play the audio in real time AND record it for later playback? Then I would look into adding a WAV header to buffered PCM data you're getting from AudioRecord. There is a discussion of the problem here, as well as the source code to make it work.
  • Erick
    Erick almost 13 years
    Thanks! I'll look into in later! :)
  • owen gerig
    owen gerig about 12 years
    Im trying to use the audio data in a stream to a server. how do i get the audio data in real time with this class?
  • theisenp
    theisenp about 12 years
    I'm not sure what you mean. This class already does get audio in real time, that's the purpose of the AudioRecord object. The AudioSource.MIC argument in the constructor tells the object to read it's data from the microphone, and the call to recorder.read() inside of the loop retrieves audio data from the mic. The example in my answer plays the audio back in real time using an AudioTrack, but you could easily stream the data to a server instead. Does that answer your question?
  • owen gerig
    owen gerig about 12 years
    yes it does thank you. how would i stop this Audio.stop() crashes it. ALSO THANK YOU VERY MUCH THIS WORKS BEAUTIFULLY
  • shim
    shim about 11 years
    Why is buffers 2D? Also how would you update the UI in response to the audio data?
  • Raevik
    Raevik over 10 years
    Nice example. This is precisely what I was looking for. What I've noticed, though, is that it's still a bit choppy at times and the playback is MUCH quieter than the actual ambient volumes. Is this expected?
  • Narasimha
    Narasimha over 10 years
    good example.but only one issue continuously audio is playing how to resolve the issue ?please give any suggestion.
  • ChiefTwoPencils
    ChiefTwoPencils almost 10 years
    With "Nice code!" I guess you're talking to @theisenp?? I can understand why you'd want to do that considering the length, but it should be a comment or a unique answer to op. If the other post is deleted this post makes zero sense.
  • KitKat
    KitKat almost 10 years
    @ChiefTwoPencils Passive voice activated.
  • Nick
    Nick about 8 years
    This code still works, thanks! I have the same question as @BM. Although I'm wearing headphones there is still an audible echo.
  • boy
    boy over 7 years
    I have created another Audio class and called it from MainActivity, but stop function does not working. It is looping with while, any suggestion for that, thank you.
  • EsmaeelE
    EsmaeelE over 6 years
    @BM, I solved noise issue by inserting a hands free inside audio jack. this happens because of sensitivity of mobile microphone. any high amplitude noisy voice will amplify when its play from phone Speaker.