Note that there are some explanatory texts on larger screens.

plurals
  1. POLive Audio Recording and Playing in Android and Thread & callback handling
    text
    copied!<p>I want to record the live audio and play it.As far as UI is concerned the app just has three buttons:one for start recording and streaming it, one for playing a pre recorded file and the last one for stopping the current task(recording / playing). For that purpose I have used <strong>AudioRecord</strong> and <strong>AudioTrack</strong> classes for recording and playing respectively. My Program looks like....</p> <p>/** * @author amit * */</p> <pre><code>public class AudioRecorder extends Activity { private String LOG_TAG = null; /* variables which are required to generate and manage the UI of the App */ // private RecordButton mRecordButton = null; private Button recordBtn, stopBtn, playBtn; /* * variables which are required for the actual functioning of the recording * and playing */ private AudioRecord recorder = null; private AudioTrack player = null; private AudioManager audioManager = null; private int recorderBufSize, recordingSampleRate; private int trackBufSize; private short[] audioData; private boolean isRecording = false, isPlaying = false; private Thread startRecThread; private AudioRecord.OnRecordPositionUpdateListener posUpdateListener; /** * constructor method for initializing the variables */ public AudioRecorder() { super(); LOG_TAG = "Constructor"; recorderBufSize = recordingSampleRate = trackBufSize = 0; // init function will initialize all the necessary variables ... init(); if (recorder != null &amp;&amp; player != null) { Log.e(LOG_TAG, "recorder and player initialized"); audioData = new short[recorderBufSize / 2]; // since we r reading shorts } else { Log.e(LOG_TAG, "Problem inside init function "); } posUpdateListener = new AudioRecord.OnRecordPositionUpdateListener() { int numShortsRead = 0; @Override public void onPeriodicNotification(AudioRecord rec) { // TODO Auto-generated method stub // String LOG_TAG = Thread.currentThread().getName(); // Log.e(LOG_TAG, "inside position listener"); audioData = new short[recorderBufSize / 2]; // divide by 2 since now we are reading shorts numShortsRead = rec.read(audioData, 0, audioData.length); player.write(audioData, 0, numShortsRead); } @Override public void onMarkerReached(AudioRecord recorder) { // TODO Auto-generated method stub Log.e(LOG_TAG, "Marker Reached"); } }; // listener will be called every time 160 frames are reached recorder.setPositionNotificationPeriod(160); recorder.setRecordPositionUpdateListener(posUpdateListener); Log.e(LOG_TAG, "inside constructor"); } private void init() { LOG_TAG = "initFunc"; // int[] mSampleRates = new int[] { 8000, 11025, 22050, 44100 }; short audioFormat = AudioFormat.ENCODING_PCM_16BIT; // for (int rate : mSampleRates) { this.recordingSampleRate = AudioTrack.getNativeOutputSampleRate(AudioManager.STREAM_MUSIC); try { // Log.d(LOG_TAG, "Attempting rate " + rate + "Hz, bits: " + // audioFormat); int bufrSize = AudioRecord.getMinBufferSize(this.recordingSampleRate, AudioFormat.CHANNEL_IN_MONO, audioFormat); // lets find out the minimum required size for AudioTrack int audioTrackBufSize = AudioTrack.getMinBufferSize(this.recordingSampleRate, AudioFormat.CHANNEL_OUT_MONO, audioFormat); if (bufrSize != AudioRecord.ERROR_BAD_VALUE &amp;&amp; bufrSize != AudioRecord.ERROR) { // check if we can instantiate and have a success if(audioTrackBufSize &gt;= bufrSize){ this.recorderBufSize = audioTrackBufSize; }else{ this.recorderBufSize = bufrSize; } AudioRecord rec = new AudioRecord( MediaRecorder.AudioSource.DEFAULT, this.recordingSampleRate, AudioFormat.CHANNEL_IN_MONO, audioFormat, this.recorderBufSize); if (rec != null &amp;&amp; rec.getState() == AudioRecord.STATE_INITIALIZED) { // storing variables for future use . . . // this.recordingSampleRate = rate; // this.recorderBufSize = bufrSize; Log.e(LOG_TAG, "Returning..(rate:channelConfig:audioFormat:recorderBufSize)" + this.recordingSampleRate + ":" + AudioFormat.CHANNEL_IN_MONO + ":" + audioFormat + ":" + this.recorderBufSize); // Now create an instance of the AudioTrack // int audioTrackBufSize = AudioTrack.getMinBufferSize(rate, // AudioFormat.CHANNEL_OUT_MONO, audioFormat); Log.e(LOG_TAG, "Audio Record / Track / Final buf size :" + bufrSize + "/ " +audioTrackBufSize + "/ "+this.recorderBufSize); this.player = new AudioTrack(AudioManager.STREAM_MUSIC, this.recordingSampleRate, AudioFormat.CHANNEL_OUT_MONO, audioFormat, this.recorderBufSize, AudioTrack.MODE_STREAM); this.recorder = rec; this.player.stop(); this.player.flush(); this.player.setPlaybackRate(this.recordingSampleRate); return; } } } catch (IllegalArgumentException e) { Log.d(LOG_TAG, this.recordingSampleRate + "Exception, keep trying.", e); } catch (Exception e) { Log.e(LOG_TAG, this.recordingSampleRate + "Some Exception!!", e); } // for loop for channel config ended here. . . . // for loop for audioFormat ended here. . . // }// for loop for sampleRate return; } private void startPlaying() { LOG_TAG = "startPlaying"; Log.e(LOG_TAG, "start Playing"); } private void stopPlaying() { LOG_TAG = "stopPlaying"; Log.e(LOG_TAG, "stop Playing"); } private void startRecording() { LOG_TAG = "startRecording"; /* start a separate recording thread from here . . . */ startRecThread = new Thread() { @Override public void run() { // TODO Auto-generated method stub android.os.Process .setThreadPriority(android.os.Process.THREAD_PRIORITY_URGENT_AUDIO); // String LOG_TAG = Thread.currentThread().getName(); if(recorder.getRecordingState() != AudioRecord.RECORDSTATE_RECORDING){ recorder.startRecording(); } // Log.e(LOG_TAG, "running" +recorder.getRecordingState()); while (recorder.getRecordingState() == AudioRecord.RECORDSTATE_RECORDING) { recorder.read(audioData, 0, audioData.length); try { Thread.sleep(1000); // sleep for 2s } catch (InterruptedException e) { // TODO Auto-generated catch block Log.e("run Method", "recorder thread is interrupted"); e.printStackTrace(); } } } }; setVolumeControlStream(AudioManager.STREAM_MUSIC); audioManager.setSpeakerphoneOn(false); player.flush(); player.play(); startRecThread.start(); Log.e(LOG_TAG, "start Recording"); } private void stopRecording() { LOG_TAG = "stopRecording"; recorder.stop(); if (startRecThread != null &amp;&amp; startRecThread.isAlive()) { startRecThread.destroy(); startRecThread = null; } player.stop(); player.flush(); Log.e(LOG_TAG, "stop Recording"); } private void stop() { if (isRecording) { isRecording = false; stopRecording(); } if (isPlaying) { isPlaying = false; stopPlaying(); } recordBtn.setEnabled(true); playBtn.setEnabled(true); } @Override public void onCreate(Bundle icicle) { super.onCreate(icicle); LOG_TAG = "onCreate"; // Log.e(LOG_TAG, "Create Called"); // getting the audio service audioManager = (AudioManager) getSystemService(AUDIO_SERVICE); LinearLayout ll = new LinearLayout(this); // creating Buttons one by one . . . . // button to start the recording process recordBtn = new Button(this); recordBtn.setText("Record"); recordBtn.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub recordBtn.setEnabled(false); playBtn.setEnabled(false); isRecording = true; startRecording(); } }); // single button to stop recording and playing as applicable stopBtn = new Button(this); stopBtn.setText("Stop"); stopBtn.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub stop(); } }); // button to play the recorded sound playBtn = new Button(this); playBtn.setText("Play"); playBtn.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub // reverse the isPlaying isPlaying = true; recordBtn.setEnabled(false); playBtn.setEnabled(false); startPlaying(); } }); ll.addView(recordBtn, new LinearLayout.LayoutParams( ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT, 1)); ll.addView(playBtn, new LinearLayout.LayoutParams( ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT, 1)); ll.addView(stopBtn, new LinearLayout.LayoutParams( ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT, 1)); setContentView(ll); } @Override protected void onDestroy() { // Clean up code . .. super.onDestroy(); if (recorder != null) recorder.release(); if (startRecThread!=null &amp;&amp; startRecThread.isAlive()) startRecThread.destroy(); if (recorder != null) recorder.release(); if (player != null) player.release(); startRecThread = null; recorder = null; player = null; recordBtn = null; stopBtn = null; playBtn = null; audioData = null; System.gc(); } } </code></pre> <p>As you might see that <code>startPlaying()</code> and <code>stopPlaying()</code> functions are not yet implemented so lets not talk about them. Currently I am just trying to record and play.When I run the program It plays the recorded audio but the audio appears coming from a distance. Another problem is that <strong>UI thread of the app hangs though I have a separate thread for reading the Audio</strong> . Please help....</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload