This example shows how to record a sound using the Android media APIs.
We import the classes and modules needed by our application. The most relevant classes are those from the android.media module.
from java.io import File, FileOutputStream from java.lang import Math, Runnable, Thread from java.nio import ByteBuffer from java.text import SimpleDateFormat from java.util import Date from android.app import Activity from android.media import AudioFormat, AudioRecord, MediaRecorder from android.os import Environment from android.view import View from android.widget import Button, LinearLayout, TextView
The AudioRecordActivity class is derived from the standard Activity class and represents the application. Android will create an instance of this class when the user runs it.
class AudioRecordActivity(Activity): __interfaces__ = [Runnable, View.OnClickListener]
The class implements the View.OnClickListener interface, declaring this
in the list of interfaces defined by the
Implementing this interface involves implementing the onClick method shown
The initialisation method simply calls the corresponding method in the base class.
def __init__(self): Activity.__init__(self) self.recording = False
The onCreate method calls the corresponding method in the base class to help set up the activity, and we set up the user interface.
def onCreate(self, bundle): Activity.onCreate(self, bundle)
We choose certain parameters for the audio data we want to record. If we cannot use these parameters, we simply return early and show no GUI. The parameters we use are 16-bit, little-endian, single channel (mono) audio, recorded with a sample rate of 44100 Hz.
encoding = AudioFormat.ENCODING_PCM_16BIT sampleRate = 44100 bufferSize = AudioRecord.getMinBufferSize(sampleRate, AudioFormat.CHANNEL_IN_MONO, encoding) if bufferSize == AudioRecord.ERROR_BAD_VALUE: return bufferSize = Math.max(bufferSize, sampleRate) self.audioBuffer = array(byte, bufferSize)
We create an AudioRecord instance, passing information about the sample data to ensure that it will be played correctly.
self.recorder = AudioRecord(MediaRecorder.AudioSource.MIC, sampleRate, AudioFormat.CHANNEL_IN_MONO, encoding, bufferSize) if self.recorder.getState() == AudioRecord.STATE_INITIALIZED:
We create a button with a "Play sound" label and register the activity as its listener for click callbacks.
self.button = Button(self) self.button.setText("Start recording") self.button.setOnClickListener(self)
We also create a text view to show the location of the last file written.
self.textView = TextView(self)
The button and text view are placed in a vertical layout which is used as the main content in the activity.
layout = LinearLayout(self) layout.setOrientation(layout.VERTICAL) layout.addView(self.button) layout.addView(self.textView) self.setContentView(layout)
The onClick method is called whenever the button defined above is clicked. If the activity was registered as a listener with other buttons then we would distinguish between them using the View object passed to this method.
def onClick(self, view): if not self.recording:
If we are not recording when the button is pressed then we create a file to write to, open an output stream to direct data to that file, and we start recording.
self.button.setText("Stop recording") self.file = self.createFile() self.stream = FileOutputStream(self.file) self.recorder.startRecording() self.recording = True
We also create a thread, passing the instance of this class to it as a Runnable for it to execute, and start it.
self.thread = Thread(self) self.thread.start() else:
Otherwise, we stop the recorder and interrupt the thread in order to stop processing audio data. We reset the button and print the name of the file we created to the TextView.
self.button.setText("Start recording") self.recorder.stop() self.recording = False self.thread.interrupt() self.textView.setText("Written " + self.file.getAbsolutePath())
As a Runnable, this class provides a run method that can be executed in another context, and we use a thread to ensure that this method is run in the background while the application continues to respond to the user in the foreground. The method reads data from the audio buffer and writes it to an output stream as long as the recording flag is set and the thread is running.
def run(self): while self.recording: size = self.recorder.read(self.audioBuffer, 0, len(self.audioBuffer)) if size > 0: self.stream.write(self.audioBuffer[0:size])
The final method is used to conveniently create a file in the device's external storage area, returning a File object if successful or None if not.
@args(File, ) def createFile(self): if Environment.getExternalStorageState() != Environment.MEDIA_MOUNTED: return None
If no external storage is mounted then return None immediately.
We obtain the directory on the external storage device that is used to store music.
storageDir = Environment.getExternalStoragePublicDirectory( Environment.DIRECTORY_MUSIC)
If possible, we create a subdirectory for this example, returning None to indicate failure.
subdir = File(storageDir, "AudioRecord") if not subdir.exists(): if not subdir.mkdirs(): return None
Finally, we use the SimpleDateFormat class to create a file name based on the current date, then use this to create a File object which we return.
dateString = SimpleDateFormat("yyyyMMdd_HHmmss").format(Date()) return File(subdir, dateString + ".raw")