Sensor Fun: Creating a simple audio recorder/player
May 2nd, 2010 by Micha KopsSound recording and playback is really simple using the MediaRecorder and MediaPlayer classes .. see the example below ..
Contents
Sample App
- First some layout .. a button to start/stop recording and a button to play the recorded stuff (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" > <TextView android:id="@+id/output" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="" /> <Button android:text="@+string/record" android:id="@+id/btRecord" android:layout_width="wrap_content" android:layout_height="wrap_content"></Button> <Button android:text="@+string/play" android:id="@+id/btPlay" android:layout_width="wrap_content" android:layout_height="wrap_content"></Button> </LinearLayout>
- Adjusting the externalized strings in the strings.xml
<?xml version="1.0" encoding="utf-8"?> <resources> <string name="app_name">Soundrecorder Tutorial</string> <string name="record">Record!</string> <string name="play">Play</string> </resources>
- Set permissions needed in the AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.hascode.android" android:versionCode="1" android:versionName="1.0"> <application android:icon="@drawable/icon" android:label="@string/app_name"> <activity android:name=".RecorderActivity" android:label="@string/app_name"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> <uses-sdk android:minSdkVersion="7" /> <uses-permission android:name="android.permission.RECORD_AUDIO"></uses-permission> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission> </manifest>
- Now the activity to bring in some action .. RecorderActivity.java
package com.hascode.android; import java.io.File; import java.io.IOException; import android.app.Activity; import android.media.MediaPlayer; import android.media.MediaRecorder; import android.os.Bundle; import android.os.Environment; import android.util.Log; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.TextView; public class RecorderActivity extends Activity { private static final String APP_TAG = "com.hascode.android.soundrecorder"; private MediaRecorder recorder = new MediaRecorder(); private MediaPlayer player = new MediaPlayer(); private Button btRecord; private Button btPlay; private TextView resultView; private boolean recording = false; private boolean playing = false; private File outfile = null; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); resultView = (TextView) findViewById(R.id.output); try { // the soundfile File storageDir = new File(Environment .getExternalStorageDirectory(), "com.hascode.recorder"); storageDir.mkdir(); Log.d(APP_TAG, "Storage directory set to " + storageDir); outfile = File.createTempFile("hascode", ".3gp", storageDir); // init recorder recorder.setAudioSource(MediaRecorder.AudioSource.MIC); recorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP); recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB); recorder.setOutputFile(outfile.getAbsolutePath()); // init player player.setDataSource(outfile.getAbsolutePath()); } catch (IOException e) { Log.w(APP_TAG, "File not accessible ", e); } catch (IllegalArgumentException e) { Log.w(APP_TAG, "Illegal argument ", e); } catch (IllegalStateException e) { Log.w(APP_TAG, "Illegal state, call reset/restore", e); } btRecord = (Button) findViewById(R.id.btRecord); btRecord.setOnClickListener(handleRecordClick); btPlay = (Button) findViewById(R.id.btPlay); btPlay.setOnClickListener(handlePlayClick); } private final OnClickListener handleRecordClick = new OnClickListener() { @Override public void onClick(View view) { if (!recording) { startRecord(); } else { stopRecord(); } } }; private final OnClickListener handlePlayClick = new OnClickListener() { @Override public void onClick(View view) { if (!playing) { startPlay(); } else { stopPlay(); } } }; private void startRecord() { Log.d(APP_TAG, "start recording.."); printResult("start recording.."); try { recorder.prepare(); recorder.start(); recording = true; } catch (IllegalStateException e) { Log .w(APP_TAG, "Invalid recorder state .. reset/release should have been called"); } catch (IOException e) { Log.w(APP_TAG, "Could not write to sd card"); } } private void stopRecord() { Log.d(APP_TAG, "stop recording.."); printResult("stop recording.."); recorder.stop(); recorder.reset(); recorder.release(); recording = false; } private void startPlay() { Log.d(APP_TAG, "starting playback.."); printResult("start playing.."); try { playing = true; player.prepare(); player.start(); } catch (IllegalStateException e) { Log.w(APP_TAG, "illegal state .. player should be reset"); } catch (IOException e) { Log.w(APP_TAG, "Could not write to sd card"); } } private void stopPlay() { Log.d(APP_TAG, "stopping playback.."); printResult("stop playing.."); player.stop(); player.reset(); player.release(); playing = false; } private void printResult(String result) { resultView.setText(result); } }
- Finally the app looks like this on my emulator
- Now play around with the recorder
How to connect a virtual sdcard to the emulator
- A SD Card is created using the android tool or the mksdcard tool
android create avd -n <youravd> -t <targetID> -c <size>[K|M] or: mksdcard <size> <file>
- Start the emulator with the param -sdcard /path/to/sdcard.img
- More information is available at the Android Developers Website
Troubleshooting
- In general use the logcat tool from the Android Debugging Bridge to look for debugging messages, exceptions, strack traces ..
# adb -s emulator-5554 shell logcat I/ActivityManager( 52): Displayed activity com.hascode.android/.RecorderActivity: I/ARMAssembler( 52): generated scanline__00000077:03545404_00000A04_00000000 [ 29 I/ARMAssembler( 52): generated scanline__00000177:03515104_00001A01_00000000 [ 73 D/com.hascode.android.soundrecorder( 198): start recording.. W/com.hascode.android.soundrecorder( 198): Could not write to sd card
- W/com.hascode.android.soundrecorder( 209): File not accessible – Check the permissions set for the directory you are trying to save the files to – more information is available at the Android Developers Website – also take a look in your AndroidManifest.xml and check if the permission WRITE_EXTERNAL_STORAGE is set:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>
- Using the Android Debugging Bridge it is possible to check the user permissions set in the emulator
adb -s emulator-5554 shell # ls -l sdcard d---rwxr-x system sdcard_rw 2010-05-02 14:50 LOST.DIR # ls -l sdcard/com.hascode.recorder ----rwxr-x system sdcard_rw 0 2010-05-02 15:33 hascode44433.3gp
- If you need a GUI – try the the Dalvik Debug Monitor Service by running ddms – screenshots below:
Resources
- IBM.com: Tapping into Android’s sensors
- MediaRecorder API
- Android Developers: Audio and Video
- Android Developers: SD Card Emulation
- Android Developers: SD Card Creation
- Android Developers: User Id’s and file access
Article Updates
- 2015-03-03: Table of contents and image captions added.
<uses-permission android:name=”android.permission.WRITE_EXTERNAL_STORAGE”></uses-permission>
October 4th, 2010 at 6:19 am
Hi thanks for providing the good tutorial for recording app
I make use of your code for recording i’m getting the errors as below, pls help me how to solve this errors ..
10-04 11:40:52.407: DEBUG/voicerecorder(1255): start recording..
10-04 11:40:52.574: ERROR/PVOMXEncNode(31): PVMFOMXEncNode-Audio_AMRNB::DoPrepare(): Got Component OMX.PV.amrencnb handle
10-04 11:48:17.900: ERROR/audio_input(31): unsupported parameter: x-pvmf/media-input-node/cap-config-interface;valtype=key_specific_value
10-04 11:48:17.910: ERROR/audio_input(31): VerifyAndSetParameter failed
Thank you
June 13th, 2012 at 5:33 am
Hi,
ur blog has been very helpful for me, but no where u have mentioned the code for the other part of ur interface(the dial button and arrow keys).
And for the above error i think the fault might be of not setting the class path right(cause it differs frm windows or ubunto) or the package is in-approprate.. correct me if i m wrong.