Android AudioRecord class - quickly launches a live microphone, sets up a callback function

I want to record sound from a microphone and access it for possible playback in almost real time. I'm not sure how to use the Android AudioRecord class to record some mic sound and have quick access to it.

For the AudioRecord class, the official website says: "the application polls the AudioRecord object in time," and "the size of the buffer being filled determines the length of the record before exceeding the unread data." He later suggested that frequent polling should use a larger buffer. They never show sample code.

One example that I saw in the book uses the AudioRecord class to continuously read a buffer recently filled with live microphone sound, and then the application writes this data to an SD file. The pseudocode looks something like this:

set up AudioRecord object with buffer size and recording format info set up a file and an output stream myAudioRecord.startRecording(); while(isRecording) { // myBuffer is being filled with fresh audio read audio data into myBuffer send contents of myBuffer to SD file } myAudioRecord.stop(); 

How this code synchronizes its reading with writing speed is unclear - is the logical "isRecording" ordered and ordered elsewhere? It seems that this code can be read too often or too rarely, depending on how long it takes to read and write.

The doc site also says that the AudioRecord class has a nested class called OnRecordPositionUpdateListener, which is defined as an interface. The information tells you that somehow you specify the period during which you want to be notified of the progress of the recording, and the name of your event handler, and the call is automatically made for your event handler at a specified frequency. I think the structure in the pseudocode will be something like -

 set target of period update message = myListener set period to be about every 250 ms other code myListener() { if(record button was recently tapped) handle message that another 250 ms of fresh audio is available ie, read it and send it somewhere ) 

I need to find a specific code that allows me to capture and process microphone sound with a delay of less than 500 ms. Android offers another class called MediaRecorder, but it doesn’t support streaming, and I might want to stream live microphone audio over a Wi-Fi network in near real time. Where can I find some specific examples?

+60
java android android-hardware audiorecord
Dec 24 '10 at 8:48
source share
4 answers

After experimenting batches with notifications and a bunch of other methods, I settled on this code:

 private class AudioIn extends Thread { private boolean stopped = false; private AudioIn() { start(); } @Override public void run() { android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_URGENT_AUDIO); AudioRecord recorder = null; short[][] buffers = new short[256][160]; int ix = 0; try { // ... initialise 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); recorder.startRecording(); // ... loop while(!stopped) { short[] buffer = buffers[ix++ % buffers.length]; N = recorder.read(buffer,0,buffer.length); //process is what you will do with the data...not defined here process(buffer); } } catch(Throwable x) { Log.w(TAG,"Error reading voice audio",x); } finally { close(); } } private void close() { stopped = true; } } 

So far, he has been working pretty confidently on the half-dozen Android phones I've tried it on.

+31
Jan 28 2018-11-11T00:
source share

I wonder if you can combine these answers as follows ...

Use setPositionNotificationPeriod (160) before the while loop. This should trigger a callback every time 160 frames are read. Instead of calling a process (buffer) inside a thread that performs a read loop, call the process (buffer) from the callback. Use a variable to keep track of the last read buffer so that you process the correct one. As now, you block reading, then you don't read while you work. I think it would be better to separate the two.

+19
Jan 29 '11 at 2:01
source share

Here is the code you should use OnRecordPositionUpdateListener and Notification Period.

I noticed that in practice it does not send a notification sequentially at the same time, I want, but it is close enough.

About detectAfterEvery :

The detectEvery size should be large enough to hold only the amount of data that you want. Thus, for this example, we have a sampling frequency of 44100 Hz, which means that we want 44100 samples per second. By setting setPositionNotificationPeriod to 44100, the code informs Android of the callback after it has written 44100 samples, which is approximately every 1 second.

Full code here :

  final int sampleRate = 44100; int bufferSize = AudioRecord.getMinBufferSize(sampleRate, AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT); //aim for 1 second int detectAfterEvery = (int)((float)sampleRate * 1.0f); if (detectAfterEvery > bufferSize) { Log.w(TAG, "Increasing buffer to hold enough samples " + detectAfterEvery + " was: " + bufferSize); bufferSize = detectAfterEvery; } recorder = new AudioRecord(AudioSource.MIC, sampleRate, AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT, bufferSize); recorder.setPositionNotificationPeriod(detectAfterEvery); final short[] audioData = new short[bufferSize]; final int finalBufferSize = bufferSize; OnRecordPositionUpdateListener positionUpdater = new OnRecordPositionUpdateListener() { @Override public void onPeriodicNotification(AudioRecord recorder) { Date d = new Date(); //it should be every 1 second, but it is actually, "about every 1 second" //like 1073, 919, 1001, 1185, 1204 milliseconds of time. Log.d(TAG, "periodic notification " + d.toLocaleString() + " mili " + d.getTime()); recorder.read(audioData, 0, finalBufferSize); //do something amazing with audio data } @Override public void onMarkerReached(AudioRecord recorder) { Log.d(TAG, "marker reached"); } }; recorder.setRecordPositionUpdateListener(positionUpdater); Log.d(TAG, "start recording, bufferSize: " + bufferSize); recorder.startRecording(); //remember to still have a read loop otherwise the listener won't trigger while (continueRecording) { recorder.read(audioData, 0, bufferSize); } 
+11
Jan 27 '12 at 10:33
source share
 private int freq =8000; private AudioRecord audioRecord = null; private Thread Rthread = null; private AudioManager audioManager=null; private AudioTrack audioTrack=null; byte[] buffer = new byte[freq]; //call this method at start button protected void Start() { loopback(); } protected void loopback() { android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_URGENT_AUDIO); final int bufferSize = AudioRecord.getMinBufferSize(freq, AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT); audioRecord = new AudioRecord(MediaRecorder.AudioSource.MIC, freq, AudioFormat.CHANNEL_CONFIGURATION_MONO, MediaRecorder.AudioEncoder.AMR_NB, bufferSize); audioTrack = new AudioTrack(AudioManager.ROUTE_HEADSET, freq, AudioFormat.CHANNEL_CONFIGURATION_MONO, MediaRecorder.AudioEncoder.AMR_NB, bufferSize, AudioTrack.MODE_STREAM); audioTrack.setPlaybackRate(freq); final byte[] buffer = new byte[bufferSize]; audioRecord.startRecording(); Log.i(LOG_TAG, "Audio Recording started"); audioTrack.play(); Log.i(LOG_TAG, "Audio Playing started"); Rthread = new Thread(new Runnable() { public void run() { while (true) { try { audioRecord.read(buffer, 0, bufferSize); audioTrack.write(buffer, 0, buffer.length); } catch (Throwable t) { Log.e("Error", "Read write failed"); t.printStackTrace(); } } } }); Rthread.start(); } 

It plays back recorded sound with a delay of less than 100 ms.

+2
Jul 26 2018-12-12T00:
source share



All Articles