Mobility

Rock and roll with Android's media recorder

What does Bon Jovi have to do with Android coding? Find out in this media recorder tutorial by William J. Francis.

I have a son who is turning fourteen in a few weeks. He is every bit as much into gadgets and in particular Android phones as me; however, we don't always see eye to eye on what is "cool." Take for instance the app Songify — my son loves it, and he cranks out half a dozen "songs" on the car ride from the house to the grocery. And he's not alone in his obsession. The app currently touts over a million downloads in Google Play.

If you're not familiar with the premise of the app, the tag line says it all: "turn speech into music." Just don't set your internal bar too high for the resulting "music." It's entertaining — let's leave it at that. With the immense popularity in the last 30 days of Songify and similar apps, I've seen a new surge of questions in the Android forums related to recording voice, so I figured what better subject to tackle this week in my post. You can follow along step by step tutorial, or download and import the entire project.

1. Start a new Android project in Eclipse. Target Android 1.6 or higher. Be sure to change the startup activity name to Main.java.

2. Add a couple of permissions to the manifest. We require access to the SD file system, as well as the media recorder.

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>

<manifest xmlns:android="http://schemas.android.com/apk/res/android"

package="com.authorwjf.voice_rec"

android:versionCode="1"

android:versionName="1.0" >
<uses-sdk android:minSdkVersion="4" />
 <uses-permission android:name="android.permission.RECORD_AUDIO" />

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

<application

android:icon="@drawable/ic_launcher"

android:label="@string/app_name" >

<activity

android:name=".Main"

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>
</manifest>

3. Create a simple table layout in the /res/layout folder. The UI for our demo consists of two buttons and a label.

Main.xml
<?xml version="1.0" encoding="utf-8"?>

<TableLayout xmlns:android="http://schemas.android.com/apk/res/android"

android:layout_width="fill_parent"

android:layout_height="fill_parent"

android:stretchColumns="*">

<TableRow>

<TextView

android:layout_width="fill_parent"

android:layout_height="wrap_content"

android:text="Voice Recorder Demo"

android:layout_span="2"

android:layout_gravity="center"

android:padding="12dip"/>

</TableRow>

<TableRow>

<Button

android:layout_width="fill_parent"

android:layout_height="wrap_content"

android:id="@+id/record_button"

android:text="record" android:layout_margin="12dip"/>

<Button

android:layout_width="fill_parent"

android:layout_height="wrap_content"

android:id="@+id/play_back_button"

android:text="play" android:layout_margin="12dip"/>

</TableRow>

</TableLayout>

4. We are ready for the /src/Main.java file. Let's start by declaring some class level variables and wiring up our buttons in the on create override.

Main.java
package com.authorwjf.voice_rec;
import android.app.Activity;
import android.media.MediaPlayer;
import android.media.MediaRecorder;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.Toast;
public class Main extends Activity implements OnClickListener {
MediaRecorder mRecorder = new MediaRecorder();
MediaPlayer mPlayer = new MediaPlayer();
boolean isRecording = false;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

setContentView(R.layout.main);

findViewById(R.id.play_back_button).setOnClickListener(this); findViewById(R.id.record_button).setOnClickListener(this); }
}

5. We have come to the heart of our code — the on-click handler. This is where we will do the recording and the playback.

Main.java

@Override

public void onClick(View v) {

mPlayer.stop();

switch (v.getId()) { case R.id.play_back_button: if (!isRecording && !mPlayer.isPlaying()) { try {

mPlayer.reset();

mPlayer.setDataSource("/sdcard/audio_demo.3gp");

mPlayer.prepare();

mPlayer.start();

} catch (Exception e) { Toast.makeText(this, "Error playing back audio.",Toast.LENGTH_SHORT).show();

}

}

break; case R.id.record_button: if (isRecording) { isRecording = false;

((Button)(findViewById(R.id.record_button))).setText("record");

mRecorder.reset();

} else { try {

mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);

mRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);

mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);

mRecorder.setOutputFile("/sdcard/audio_demo.3gp");

mRecorder.prepare();

mRecorder.start();

((Button)(findViewById(R.id.record_button))).setText("stop");

isRecording = true; } catch (Exception e) { Toast.makeText(this, "Error starting recorder.",Toast.LENGTH_SHORT).show(); }
}
break;

}

}

6. We need to handle cleaning up our media recorder and playback objects when the activity gets destroyed — this keeps the app from crashing or leaking resources. Note: The app doesn't attempt to continue recording through an orientation change.

Main.java

@Override

public void onDestroy() { if (isRecording) { Toast.makeText(this, "Recorder stopped.",Toast.LENGTH_SHORT).show();

mRecorder.stop();

}

mRecorder.release();

mPlayer.stop();

mPlayer.release();

super.onDestroy(); }

The app should be ready to take for a spin. Since voice recording isn't supported on the emulator, you'll need to run the demo on an actual device. Operation is self-evident: say something and then play it back (Figure A).

Figure A

Pretty easy, right? And best of all, I'm sure it will provide you with hours of entertainment. I've already recorded an a capella rendition of Bon Jovi's "Dead or Alive" for our next family outing to the grocery.

About

William J Francis began programming computers at age eleven. Specializing in embedded and mobile platforms, he has more than 20 years of professional software engineering under his belt, including a four year stint in the US Army's Military Intellige...

Editor's Picks