oday's wireless handsets are veritable multimedia powerhouses; sporting more I/O options than the average desktop PC a mere decade ago. Because all users are comfortable talking to a wireless handset (it is, after all, first and foremost a phone!), having the ability to capture audio paves the way for a wide variety of applications, including voice command and speech recognition, audio note-taking, and multi-user chat and messaging in either stand-alone applications or integrated as part of a larger application. Qualcomm BREW makes it easy to capture audio, either as an audio recording you can package up, replay, and send to a remote server, or in real time by directly accessing the handset's vocoder. This article shows you both methods and arms you with the information you need to know to select which path is right for you.
Using the IMedia Interface to Capture Audio
The IMedia interfacewhich was covered in in the recent article "Playing Multimedia Using BREW's IMedia"not only plays media, but can record media as well. Using the IMedia interface, you can capture audio to a file for storage, playback, and transmission to other hosts. The interface supports a variety of audio formats including PCM, although most handsets currently only support QCELP. (QCELP is a highly optimized format used by the CDMA network itself, and is very well suited for recording the human voice for playback to the human ear, but may not be suitable for other applications that require little or no compression artifacts.) By definition, you can't use the IMedia interface to directly capture audio off the microphone in real-time; to do this, you use the IVocoder interface, which is the subject of the next section.
Using the IMedia interface to record audio is simple:
- Select an appropriate subclass of IMedia based on the desired format for the captured audio (for example, AEECLSID_MEDIAQCP) and create an instance of the interface.
- Set the IMedia instance's callback so that the instance can pass information about the media back to your application using IMEDIA_RegisterNotify.
- Configure any recording options using IMEDIA_SetParm.
- Begin and control media recording, using handset or programmatic events (key presses, game actions, or so forth) to trigger IMedia methods such as IMEDIA_Record, IMEDIA_Pause, IMEDIA_Resume, and IMEDIA_Stop.
- Monitor the values sent to your application callback for information such as errors or the termination of recording and handle those notifications appropriately.
- When recording is complete, release the IMedia instance and any other resources you've consumed.
Setup of an IMedia interface for recording is the same as for playback:
char szFilename = "record.qcp";
ISHELL_CreateInstance(pIShell, AEECLSID_MEDIAQCP, (void **)&pMe->pIMedia);
sMediaData.clsData = MMD_FILE_NAME;
sMediaData.pData = (void *)&szFilename;
sMediaData.dwSize = 0;
IMEDIA_RegisterNotify(pMe->pIMedia, (*PFNMEDIANOTIFY)IMediaEventHandler, pMe);
This code creates an IMedia instance and sets the file name for the resulting audio recording using IMEDIA_SetMediaData
. Finally, it registers a callback the IMedia instance invokes to notify your application when its state changes. Don't forget to set the PL_FILE
privilege in your application's Module Information File, because IMedia will be interacting with the file system.
You can use the callback to update the user interface for events such as the beginning or ending of recording. The structure of the media callback is well-documented, or you can consult my previous article on IMedia for an example.
Starting and stopping recording can be done programmatically or as a result of a key event; you simply need to call IMEDIA_Record to begin recording and IMEDIA_Stop to end recording. (If you'd like to pause and resume recording, simply use IMEDIA_Pause and IMEDIA_Resume.) The only argument these methods take is the IMedia instance you've created and initialized:
// Someplace in an event handler…
pMe->bRecording = FALSE;
IMEDIA_Stop( pMe->pIMedia );
pMe->bRecording = TRUE;
IMEDIA_Recording( pMe->pIMedia );
if (pMe->bRecording && !pMe ->bPaused )
pMe ->bPaused = TRUE;
pMe ->bPaused = FALSE;
Of course, you should accompany changes in application state (like a change from recording to paused) with user interface changes, such as showing an icon when recording is paused. While it's tempting to do this in the same place where you trigger the changes in the IMedia object's state, it’s actually better to do it in the callback you register with your IMedia object. Doing this ensures that the user interface will only change once the state change for the IMedia object has taken place, and that the user interface cannot get out of sync with the object's state.
Once recording is finished, you must clean up the IMedia object. To do this, first clear the callback registration and then simply release the object:
IMEDIA_RegisterNotify(pThis->pIMedia, NULL, NULL);
Clearing the callback isn't strictly necessary, but given the asynchronous nature of the IMedia implementation, it's a good idea.
Once you've recorded the sound file, you're free to do with it as you choose, of course, from sending it to a server, keeping it on the local file system, or analyzing it for features for speech recognition or other purposes.