This article applies to the following:
- BlackBerry® Device Software 4.2 and later
- BlackBerry smartphones based on Java® technology
BlackBerry Device Software 4.2 implemented Java Specification Request (JSR) 135 Mobile Media API (MMAPI). This allows BlackBerry smartphone applications to record and play back multimedia content.
The BlackBerry smartphone supports audio recording using two different formats, Adaptive Multi-Rate (AMR) and 8kHz mono-16-bit Pulse Code Modulation (PCM). The default encoding used by the BlackBerry smartphone is AMR.
Note: BlackBerry Device Software 4.6 also supports Global System for Mobile communications® (GSM®) 6.10 and BlackBerry Device Software 4.7 supports Qualcomm Code Excited Linear Prediction (QCELP).
The encoding to be used is specified in the string passed to the Manager.createPlayer(String locator) method. The following table shows a list of supported locator strings.
| String | Resulting Format | Minimum BlackBerry Device Software requirement |
|---|---|---|
capture://audio |
AMR | 4.2 |
capture://audio?encoding=amr or capture://audio?encoding=audio/amr |
AMR | 4.2 |
capture://audio?encoding=pcm or capture://audio?encoding=audio/basic |
PCM | 4.2 |
capture://audio?encoding=gsm orcapture://audio?encoding=x-gsm |
GSM | 4.6 |
capture://audio?encoding=qcelp |
QCELP | 4.7 |
Note: The PCM format is not supported by BlackBerry smartphones that operate on the Code Division Multiple Access (CDMA) network.
The following code sample demonstrates how to record audio using JSR 135 on a BlackBerry smartphone. The sample encapsulates this in a thread that can be added to your application.
final class VoiceNotesRecorderThread extends Thread
{
private Player _player;
private RecordControl _rcontrol;
private ByteArrayOutputStream _output;
private byte _data[];
VoiceNotesRecorderThread() {}
private int getSize()
{
return (_output != null ? _output.size() : 0);
}
private byte[] getVoiceNote()
{
return _data;
}
public void run() {
try {
// Create a Player that captures live audio.
_player = Manager.createPlayer("capture://audio");
_player.realize();
// Get the RecordControl, set the record stream,
_rcontrol = (RecordControl)_player.getControl("RecordControl");
//Create a ByteArrayOutputStream to capture the audio stream.
_output = new ByteArrayOutputStream();
_rcontrol.setRecordStream(_output);
_rcontrol.startRecord();
_player.start();
} catch (final Exception e) {
UiApplication.getUiApplication().invokeAndWait(new Runnable() {
public void run() {
Dialog.inform(e.toString());
}
});
}
}
public void stop() {
try {
//Stop recording, capture data from the OutputStream,
//close the OutputStream and player.
_rcontrol.commit();
_data = _output.toByteArray();
_output.close();
_player.close();
} catch (Exception e) {
synchronized (UiApplication.getEventLock()) {
Dialog.inform(e.toString());
}
}
}
}
Recording in PCM format provides only raw mono PCM at 8000Hz. This format can be played back on a BlackBerry device, however to play it back on other devices such as a PC, it must be wrapped in a WAV container. This is easy to do, and in fact:
import java.io.ByteArrayOutputStream;
import java.io.IOException;
public class WavHeaderAppender {
public static final int WAV_HEADER_SIZE = 44;
private static final byte[] RIFF = {0x52, 0x49, 0x46, 0x46}; // RIFF
private static final byte[] WAVE = {0x57, 0x41, 0x56, 0x45}; // WAVE
private static final byte[] FMT_ = {0x66, 0x6D, 0x74, 0x20}; // fmt_
private static final byte[] DATA = {0x64, 0x61, 0x74, 0x61}; // DATA
private static final int BlackBerryWavChannels = 1;
private static final int BlackBerryWavSampleRate = 8000;
private static final int BlackBerryWavBitsPerSample = 16;
private static final int BlackBerryWavBytesPerSecond = (BlackBerryWavSampleRate * BlackBerryWavChannels) * (BlackBerryWavBitsPerSample / 8);
private static final int BlackBerryWavBlockAlign = BlackBerryWavChannels * (BlackBerryWavBitsPerSample / 8);
/**
* Append a generic WAV header to BlackBerry-recorded raw PCM data.
*
* @param pcmData the pcm data to append to
* @return the byte[] the same array as pcmData, but with 44 bytes of header data pre-pended
* @throws IOException
*/
public static byte[] appendWavHeader(byte[] pcmData) throws IOException {
return WavHeaderAppender.appendWavHeader(BlackBerryWavCha nnels, BlackBerryWavSampleRate, BlackBerryWavBytesPerSecond, BlackBerryWavBlockAlign, BlackBerryWavBitsPerSample, pcmData );
}
/**
* Append a generic wav header to specific raw PCM data.
*
* @param channels the number of channels
* @param sampleRate the sample rate
* @param bytesPerSecond the bytes per second of audio
* @param blockAlign the block align (sample size)
* @param bitsPerSample the number of bits per sample
* @param pcmData the actual pcm sample data
* @return the byte[] the same array as pcmData, but with 44 bytes of header data pre-pended
* @throws IOException Signals that an I/O exception has occurred.
*/
public static byte[] appendWavHeader(int channels, int sampleRate, int bytesPerSecond, int blockAlign, int bitsPerSample, byte[] pcmData ) throws IOException {
int size = pcmData.length;
ByteArrayOutputStream output = new ByteArrayOutputStream(WAV_HEADER_SIZE + size);
// RIFF Header
output.write( RIFF, 0, RIFF.length );
// Size
DataParserUtilities.writeUnsignedIntLittleEndian( size + 36, output );
// WAVE Header
output.write( WAVE, 0, WAVE.length );
// FMT_ chunk
output.write( FMT_, 0, FMT_.length );
DataParserUtilities.writeUnsignedIntLittleEndian( 16, output ); // fmt_ size, 16 = Audio Format PCM
DataParserUtilities.writeUnsignedShortLittleEndian ( 1 , output); // audio formaat, 1 = PCM no compression
DataParserUtilities.writeUnsignedShortLittleEndian ( channels , output);
DataParserUtilities.writeUnsignedIntLittleEndian( sampleRate, output );
DataParserUtilities.writeUnsignedIntLittleEndian( bytesPerSecond, output );
DataParserUtilities.writeUnsignedShortLittleEndian ( blockAlign, output );
DataParserUtilities.writeUnsignedShortLittleEndian ( bitsPerSample, output );
// data chunk
output.write( DATA, 0, DATA.length );
DataParserUtilities.writeUnsignedIntLittleEndian( size, output );
// Raw PCM data
output.write( pcmData, 0, size );
return output.toByteArray();
}
}
This code relies on a DataParserUtilites class, both the above WavHeaderAppender and the DataParserUtility java files can be found here.