Sensor Fun: Creating a simple audio recorder/player

May 2nd, 2010 by

Sound recording and playback is really simple using the MediaRecorder and MediaPlayer classes .. see the example below ..

 

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

    The Application in the Android 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:

    Debugging in DDMS

    File System

Resources

Article Updates

  • 2015-03-03: Table of contents and image captions added.
    <uses-permission android:name=”android.permission.WRITE_EXTERNAL_STORAGE”></uses-permission>

    Tags: , , , , ,

    2 Responses to “Sensor Fun: Creating a simple audio recorder/player”

    1. ravi Says:

      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

    2. Bharath Says:

      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.

    Search
    Categories