In this blog post, we’ll develop a basic Sound Recorder application that is capable of recording audio and saving it into the local storage of an Android device using the MediaRecorder that is provided by the Android SDK.
The Android multimedia framework includes support for recording and playing audio. In this blog post, we’ll develop a basic Sound Recorder application that is capable of recording audio and saving it into the local storage of an Android device using the MediaRecorder that is provided by the Android SDK.
You will also learn how to request user-permissions in real-time and how to work with the local storage of an Android device.
Open Table of contents
First, we need to build the user interface of the Audio Recorder. It consists of a simple layout with 3 buttons which will be used to start, pause, resume and stop the recording.
xml version="1.0" encoding="utf-8"?> RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> TextView android:id="@+id/textview_sound_recorder_heading" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Sound Recorder" android:layout_centerHorizontal="true" android:textSize="32dp" android:textStyle="bold" android:textColor="#000" android:layout_marginTop="32dp" /> Button android:id="@+id/button_start_recording" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Start" android:layout_alignParentBottom="true" android:layout_marginLeft="32dp" android:layout_marginBottom="32dp" android:layout_centerVertical="true"/> Button android:id="@+id/button_pause_recording" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Pause" android:layout_alignParentBottom="true" android:layout_centerHorizontal="true" android:layout_marginBottom="32dp"/> Button android:id="@+id/button_stop_recording" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Stop" android:layout_alignParentBottom="true" android:layout_alignParentRight="true" android:layout_marginBottom="32dp" android:layout_marginRight="32dp"/> RelativeLayout>
After creating the UI we can almost start using the MediaRecorder to build our app. But first, we need to request the required permissions to record the audio and access the local storage. We can do that with some simple lines of code in our AndroidManifest.xml file.
uses-permission android:name="android.permission.RECORD_AUDIO"/> uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
We also need to check if the user has really enabled the permissions before we can use our MediaRecorder. We can do so in our MainActivity.kt file.
if (ContextCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED && ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) val permissions = arrayOf(android.Manifest.permission.RECORD_AUDIO, android.Manifest.permission.WRITE_EXTERNAL_STORAGE, android.Manifest.permission.READ_EXTERNAL_STORAGE) ActivityCompat.requestPermissions(this, permissions,0) >
Note: This lines of code will later be moved in the OnClickListener call of the start_recording button so we can make sure that the MediaRecorder will not be started without having the right permissions.
First, we need to add OnClickListeners to the buttons to make sure they react to user events. As I mentioned before the check for the right permissions will be added in the OnClickListener call of the start_recording button.
button_start_recording.setOnClickListener if (ContextCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED && ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) val permissions = arrayOf(android.Manifest.permission.RECORD_AUDIO, android.Manifest.permission.WRITE_EXTERNAL_STORAGE, android.Manifest.permission.READ_EXTERNAL_STORAGE) ActivityCompat.requestPermissions(this, permissions,0) > else startRecording() > > button_stop_recording.setOnClickListener stopRecording() > button_pause_recording.setOnClickListener pauseRecording() >
Next, we need to define a path for our output and start configuring our MediaRecorder.
private var output: String? = null private var mediaRecorder: MediaRecorder? = null private var state: Boolean = false private var recordingStopped: Boolean = false override fun onCreate(savedInstanceState: Bundle?) super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) output = Environment.getExternalStorageDirectory().absolutePath + "/recording.mp3" mediaRecorder = MediaRecorder() mediaRecorder?.setAudioSource(MediaRecorder.AudioSource.MIC) mediaRecorder?.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4) mediaRecorder?.setAudioEncoder(MediaRecorder.AudioEncoder.AAC) mediaRecorder?.setOutputFile(output) >
Here, we get the path to the root of our external storage and add our recording name and filetype to it. After that, we create our MediaRecorder object and define the audio source, audio encoder, output format and output file.
The code used to start the MediaRecorder is defined in the OnClickListener of the start_recording button.
private fun startRecording() try mediaRecorder?.prepare() mediaRecorder?.start() state = true Toast.makeText(this, "Recording started!", Toast.LENGTH_SHORT).show() > catch (e: IllegalStateException) e.printStackTrace() > catch (e: IOException) e.printStackTrace() > >
As you can see we need to call the prepare function before we can start the recording. We also embed it into a try-catch block to make sure the app won’t crash when the prepares function fails.
The OnClickListeners of the stop button is very similar to the one we defined above.
private fun stopRecording() if(state) mediaRecorder?.stop() mediaRecorder?.release() state = false >else Toast.makeText(this, "You are not recording right now!", Toast.LENGTH_SHORT).show() > >
Here we check if the MediaRecorder is currently running before we actually stop the recording because our app would crash if the stop method is called while the MediaRecorder isn’t recording. After that, we change the state variable to false to prevent the user from pressing the stop button again.
After that, we just need to define the OnClickListener for the pause/resume button.
@SuppressLint("RestrictedApi", "SetTextI18n") @TargetApi(Build.VERSION_CODES.N) private fun pauseRecording() if(state) if(!recordingStopped) Toast.makeText(this,"Stopped!", Toast.LENGTH_SHORT).show() mediaRecorder?.pause() recordingStopped = true button_pause_recording.text = "Resume" >else resumeRecording() > > > @SuppressLint("RestrictedApi", "SetTextI18n") @TargetApi(Build.VERSION_CODES.N) private fun resumeRecording() Toast.makeText(this,"Resume!", Toast.LENGTH_SHORT).show() mediaRecorder?.resume() button_pause_recording.text = "Pause" recordingStopped = false >
In these two methods we check if the MediaRecorder is running. If so we pause the recording and change the text of the button to resume. If clicked again the recording will resume from the point it left of.
Finally, we can start recording audio and listen to it by opening the recording.mp3 file that will be saved in our local storage.
Here you can get the complete source code for our basic Sound Recorder app:
package com.example.android.soundrecorder import android.Manifest import android.annotation.SuppressLint import android.annotation.TargetApi import android.content.pm.PackageManager import android.media.MediaRecorder import android.os.Build import android.support.v7.app.AppCompatActivity import android.os.Bundle import android.os.Environment import android.support.v4.app.ActivityCompat import android.support.v4.content.ContextCompat import android.widget.Toast import kotlinx.android.synthetic.main.activity_main.* import java.io.IOException class MainActivity : AppCompatActivity() private var output: String? = null private var mediaRecorder: MediaRecorder? = null private var state: Boolean = false private var recordingStopped: Boolean = false override fun onCreate(savedInstanceState: Bundle?) super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) mediaRecorder = MediaRecorder() output = Environment.getExternalStorageDirectory().absolutePath + "/recording.mp3" mediaRecorder?.setAudioSource(MediaRecorder.AudioSource.MIC) mediaRecorder?.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4) mediaRecorder?.setAudioEncoder(MediaRecorder.AudioEncoder.AAC) mediaRecorder?.setOutputFile(output) button_start_recording.setOnClickListener if (ContextCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED && ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) val permissions = arrayOf(android.Manifest.permission.RECORD_AUDIO, android.Manifest.permission.WRITE_EXTERNAL_STORAGE, android.Manifest.permission.READ_EXTERNAL_STORAGE) ActivityCompat.requestPermissions(this, permissions,0) > else startRecording() > > button_stop_recording.setOnClickListener stopRecording() > button_pause_recording.setOnClickListener pauseRecording() > > private fun startRecording() try mediaRecorder?.prepare() mediaRecorder?.start() state = true Toast.makeText(this, "Recording started!", Toast.LENGTH_SHORT).show() > catch (e: IllegalStateException) e.printStackTrace() > catch (e: IOException) e.printStackTrace() > > @SuppressLint("RestrictedApi", "SetTextI18n") @TargetApi(Build.VERSION_CODES.N) private fun pauseRecording() if(state) if(!recordingStopped) Toast.makeText(this,"Stopped!", Toast.LENGTH_SHORT).show() mediaRecorder?.pause() recordingStopped = true button_pause_recording.text = "Resume" >else resumeRecording() > > > @SuppressLint("RestrictedApi", "SetTextI18n") @TargetApi(Build.VERSION_CODES.N) private fun resumeRecording() Toast.makeText(this,"Resume!", Toast.LENGTH_SHORT).show() mediaRecorder?.resume() button_pause_recording.text = "Pause" recordingStopped = false > private fun stopRecording() if(state) mediaRecorder?.stop() mediaRecorder?.release() state = false >else Toast.makeText(this, "You are not recording right now!", Toast.LENGTH_SHORT).show() > > >
After recording you need to go into the local storage of your Android device to listen to your recordings. I’m just including it for the people who aren’t confident navigating in the local Android storage.
Now you should know how the MediaRecorder works, how you can request permission in real-time and why it is important to do so. You have also learned about the local storage of your Android device and how you store data in it.
A more complex version of this app which has some extra features like playing your recordings using the MediaPlayer is also available on my Github.
If you have found this useful, please consider recommending and sharing it with other fellow developers.
If you have any questions or critics, you can reach me in the comment section.