I am trying to get audio data from the microphone. I have achieved this by using the AudioRecord
class which fills a buffer with type shorts.
Eventually I would like to graph this buffer so that I get an oscilloscope like display (realtime information). The problem is that if I want to display a value (say in text) then I need a different thread to update the UI. Currently I'm doing this by using an AsyncTask
and updating the UI with AsyncTasks.publishProgress()
. So far I haven't been very successful and would like to know if I'm on the right track? Are handles a better way to go? Is there anyone out there who has done something similar before, and if so what method worked for you? Also, is it at all possible to simply poll the microphone?
Here is my code. It is meant to output every read sample from the MIC. It appears to do this at an acceptable rate but occasionally displays a zero. Why?
package com.ss.audioacquireapp3;
import android.app.Activity;
import android.content.Context;
import android.media.AudioFormat;
import android.media.AudioRecord;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.widget.TextView;
public class AudioAcquireApp3Activity extends Activity
{
//Properties (AsyncTask)
protected TextView _percentField;
protected InitTask _initTask;
//Properties (MIC)
public AudioRecord audioRecord;
public int mSamplesRead; //how many samples read
public int recordingState;
public int buffersizebytes;
public int channelConfiguration = AudioFormat.CHANNEL_IN_MONO;
public int audioEncoding = AudioFormat.ENCODING_PCM_16BIT;
public static short[] buffer; //+-32767
public static final int SAMPPERSEC = 44100; //samp per sec 8000, 11025, 22050 44100 or 48000
@Override
public void onCreate( Bundle savedInstanceState )
{
super.onCreate(savedInstanceState);
setContentView( R.layout.main );
_percentField = ( TextView ) findViewById( R.id.percent_field );
buffersizebytes = AudioRecord.getMinBufferSize(SAMPPERSEC,channelConfiguration,audioEncoding); //4096 on ion
buffer = new short[buffersizebytes];
audioRecord = new AudioRecord(android.media.MediaRecorder.AudioSource.MIC,SAMPPERSEC,channelConfiguration,audioEncoding,buffersizebytes); //constructor
_initTask = new InitTask();
_initTask.execute( this );
}
/**
* sub-class of AsyncTask
*/
protected class InitTask extends AsyncTask<Context, Integer, String>
{
// -- run intensive processes here
// -- notice that the datatype of the first param in the class definition matches the param passed to this method
// -- and that the datatype of the last param in the class definition matches the return type of this method
@Override
protected String doInBackground( Context... params )
{
//-- on every iteration
//-- runs a while loop that causes the thread to sleep for 50 milliseconds
//-- publishes the progress - calls the onProgressUpdate handler defined below
//-- and increments the counter variable i by one
//int i = 0;
audioRecord.startRecording();
while( true )
{
try{
mSamplesRead = audioRecord.read(buffer, 0, buffersizebytes);
int amp;
for(int i = 0; i < buffersizebytes - 1; i++){
amp = (int)buffer[i];
publishProgress( amp );
}
} catch( Exception e ){
}
}
}
// -- gets called just before thread begins
@Override
protected void onPreExecute()
{
//Log.i( "makemachine", "onPreExecute()" );
super.onPreExecute();
}
// -- called from the publish progress
// -- notice that the datatype of the second param gets passed to this method
@Override
protected void onProgressUpdate(Integer... values)
{
super.onProgressUpdate(values);
//Log.i( "makemachine", "onProgressUpdate(): " + String.valueOf( values[0] ) );
_percentField.setText( String.valueOf(values[0]) );
}
// -- called as soon as doInBackground method completes
// -- notice that the third param gets passed to this method
@Override
protected void onPostExecute( String result )
{
super.onPostExecute(result);
//Log.i( "makemachine", "onPostExecute(): " + result );
}
}
}
And here is main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:gravity="center_vertical|center_horizontal"
>
<TextView android:id="@+id/percent_field"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"/>
</LinearLayout>
Note that you need to add this to AndroidManifest.xml
<uses-permission android:name="android.permission.RECORD_AUDIO" />
I am running this on a LG Optimus Black. Please help me make this code as efficient as possible.
Activity.runOnUiThread(Runnable action)
. See Activity
class javadoc for details.AudioRecord
is a good way to go, when recording micrphone. Here is a link to example implementation, which reads frequency of recorded audio live: http://www.anddev.org/novice-tutorials-f8/get-frequency-data-from-microphone-in-real-time-t16774.htmlHope this helps.