USERNAME PASSWORD LOST PASSWORD? REGISTER
"A Complete Mobile Application Development Environment"
Advertisement

Downloads
Documentation
Forums
Blog
Press
Bug Tracking
Creator IDs
Contact Us




Audio Subsystem PDF Print E-mail

The ACCESS Linux Platform audio subsystem is designed for files that are already decoded, such as WAV files with PCM data. It works with audio streams; you have the option of writing your own encoder and decoder that work with raw data streams. In this case you can use an audio stream to transfer the encoded or decoded data.

The audio subsystem supports recording and playback within the confines outlined above. For more complex operations, including working with other audio formats and audio combined with video, you'll want to use a Media Session. See Chapter 2, "Media Session," for details.

Architecture ^TOP^

The ACCESS Linux Platform audio subsystem divided into three major components: the Audio Manager, the Audio Device Manager, and the ALSA driver. Figure 3.1 illustrates the design of the audio subsystem.

Figure 3.1  Audio subsystem architecture

Note that in a phone product based on dual-core or dual-chip technology, there are some audio streams that are not generated by the application processor. For example, the phone call voice stream comes from the modem chip. Or, an FM radio stream would come from a separate FM chip. Although such streams are externally generated, they are controlled by the Audio Manager as if they were generated by the application processor, allowing audio routing and conflict resolution rules to be applied correctly. See Appendix , "The Routing Table," for more on the routing table and its rules.

Audio Manager ^TOP^

The Audio Manager is a Linux daemon that is launched at system startup. It implements the API requests for audio support. Using a routing table it determines which device to output sounds to (speaker, headphones, Bluetooth headset, etc.) based upon the current device configuration.

The Audio Manager includes a shared library, libalp_audiomgr.so, that is used by developers making API calls to manage various aspects of sound in their application.

Audio Device Manager ^TOP^

The Audio Device Manager is itself divided into two sections: a daemon which is used to listen the status of audio devices such as headphones, and Bluetooth accessories; and the Audio Device Library, which is a set of device operation functions which are called by the Audio Manager.

The Audio Device Library is a set of abstract interfaces based on the ALSA library. It provides full operation of audio device functions such as PCM data write and read, volume setting, PCM format setting, router control, query functions for audio device status, and so on. The daemon listens for device status notifications from the ALSA driver and transfers them to the Audio Manager. Communication between the daemon and ALSA driver uses Netlink-connector; the socket IPC mechanism is used between the Audio Manager and the device daemon.

ALSA Driver ^TOP^

ALSA stands for Advanced Linux Sound Architecture. It is a suite of hardware drivers, libraries and utilities which provide audio and MIDI functionality for the Linux operating system. ALSA is an open-source effort; the official web site of the ALSA project is: http://www.alsa-project.org/.

The ALSA driver provides the interface between the audio subsystem components and ALSA itself.

The Routing Table ^TOP^

Additional logic is built into the Audio Manager through the use of a device-specific routing table. This table, constructed by the device manufacturer, contains a series of instructions (or "rules") for directing sound based on a number of factors including:

  • device status, such as whether or not a given audio peripheral is plugged in
  • conditions, or states. For instance, whether or not a phone call is currently active. A condition might have a physical correspondence—say, to indicate the position of a "ringer off" switch.
  • the type of sound you are requesting.
  • the preferred behavior when sound is disabled.

Based on the above factors, the Audio Router uses rules in the routing table to determine which output device each audio stream should be directed to, and which volume setting to respect. Under certain conditions, the table determines when it's appropriate to mute, attenuate, or stop entirely the requested sound. For instance, if a stream of a given type is playing and another stream of the same type is started, depending upon how the device manufacturer has set up the routing table,

  • the two streams may be mixed, so that the user hears both at the requested stream volume levels,
  • the two streams may be mixed, but one of them may have its volume attenuated so that the other takes priority,
  • the first stream may be muted so that only the second stream is heard,
  • the first stream may be stopped altogether, so that only the second stream is heard.

As conditions and device status change, streams are automatically re-routed as necessary. If, for instance, the user is listening to an MP3 file through the built-in speaker, and they plug in a set of headphones, the sound will be redirected from the speaker to the headphones (assuming that the appropriate routing table rules are in place). If the user is listening to an MP3 file and a phone call comes in, the MP3 playback might be paused for the duration of the call, and resumed when the call terminates (again, depending upon how the device manufacturer has configured the routing table). Rules can be set so that if the user has no way to hear music playback, the stream is automatically halted—this to conserve battery power. If, due to changing device status or conditions the Audio Manager is forced to step in and affect your audio stream—by halting it, by muting it, or by attenuating it, for instance—or if the path from the audio source to its final destination changes, the Audio Manager broadcasts a notification that allows you to take any necessary action. Details of these notifications and how you can register to receive them is documented in "Handling Outside Events." To obtain a list of all routing destinations in the path, see the reference documentation for the alp_snd_get_current_routepath() function.

Because of the routing table, you don't generally direct sound to or from a specific output device. Rather, you simply inform the Audio Manager of your sound stream type, and the Audio Manager, after consulting the routing table and considering the current situation, directs the sound to the appropriate device. See "Opening an Audio Object" for specifics on specifying the sound stream type.

Using the Audio Manager Library ^TOP^

Applications needing to process audio that is already decoded should use the Audio Manager APIs rather than create a media session. Examples of when to use the Audio Manager include handling WAV files containing PCM data, data streams decoded through a media session, and incoming voice from a telephone call.

Be aware that the Audio Manager is also used behind the scenes by other components, such as a media session requiring audio output.

Audio Manager Headers and Libraries ^TOP^

The Audio Manager is distinct from the ACCESS Linux Platform Multimedia library. The file libalp_audiomgr.so is the client-side portion of the Audio Manager library. It should be included in your makefile, along with the rest of the libraries you will be linking against (add alp_audiomgr to the list of included libraries).

The header file used with audio is media_audiomgr.h. It defines the structures, constants and API declarations related to audio. To use this file add the following line to your code:


#include <alp/media_audiomgr.h> 

Note that if you are mixing Audio Manager calls in with media session calls then you will need to include the media session header files in your application. See "Media Session Headers and Libraries."

Playing and Recording Audio ^TOP^

The code in Listing 3.1 is a simple command-line program that plays back raw audio using the Audio Manager APIs. Recording is an analogous operation although instead of calling alp_snd_write() you would call alp_snd_read(), and instead of initiating the operation by passing ALP_SND_CTL_PLAY to alp_snd_ioctl(), you would instead pass ALP_SND_CTL_RECORD. But the basic structure of the program applies whether your are recording or playing audio.

Listing 3.1  Simple audio playback example


#include <gtk/gtk.h>				// GTK/GDK/GLib declarations 
#include <glade/glade.h>			// libglade declarations 
#include <alp/alp.h>				// ACCESS Linux Platform declarations 
#include <alp/media_audiomgr.h> 
#include <pthread.h> 
#include <fcntl.h> 
#include <signal.h> 
 
#include "myapp.h					"// Application specific declarations 
 
#define APP_GLADE_FILE "app.glade" 
 
 
int snd_fd; 
int play_end = 0; 
 
static void *handle = NULL; 
 
ssize_t safe_read(int fd, void *buf, size_t count){ 
	ssize_t result = 0, res; 
	 
	while (count > 0) { 
		if ((res = read(fd, buf, count)) == 0) 
			break; 
		if (res < 0) 
			return result > 0 ? result : res; 
		count -= res; 
		result += res; 
		buf = (char *)buf + res; 
	} 
	 
	return result; 
} 
 
#define BLOCK_SIZE 1024 
 
void play_thread(void){ 
	int len; 
	unsigned char *pbuf; 
	 
	pbuf = (unsigned char *) malloc(BLOCK_SIZE); 
	 
	while ((len = safe_read(snd_fd, pbuf, BLOCK_SIZE)) > 0) { 
		if(alp_snd_write(handle, pbuf, len) != ALP_STATUS_SND_OK) { 
			printf("alp_snd_write error\n"); 
			break; 
		} 
	} 
	 
	printf("play_thread exit\n"); 
	 
	free(pbuf); 
	 
	play_end = 1; 
} 
 
 
int player_init(char *pathToAudio) { 
	unsigned int i; 
	int ret; 
	pthread_t play_id; 
	AlpSndPcmFmt format; 
	 
	if ((snd_fd = open(pathToAudio, O_RDONLY, 0)) == -1) { 
		perror(pathToAudio); 
		exit(EXIT_FAILURE); 
	} 
	 
	alp_snd_open(&handle, "audio_out", ALP_SND_MODE_PLAYBACK); 
	format.bits = 8; 
	format.channels = 1; 
	format.rate = 24000; 
	alp_snd_ioctl(handle, ALP_SND_SET_FORMAT, &format); 
	 
	ret = pthread_create(&play_id, NULL, (void *)play_thread, NULL); 
	 
	if (ret != 0) { 
		printf("create pthread error\n"); 
		alp_snd_close(handle); 
		return -1; 
	} 
	 
	alp_snd_ioctl(handle, ALP_SND_CTL_PLAY, NULL); 
	 
	return 0; 
} 
 
 
APP_EXTERNC  
void on_play_button_clicked(GtkWidget *button, gpointer userdata) 
{ 
    alp_snd_ioctl(handle, ALP_SND_CTL_PLAY, NULL); 
} 
 
APP_EXTERNC  
void on_stop_button_clicked(GtkWidget *button, gpointer userdata) 
{ 
    alp_snd_ioctl(handle, ALP_SND_CTL_STOP, NULL); 
} 
 
APP_EXTERNC  
void on_pause_button_clicked(GtkWidget *button, gpointer userdata) 
{ 
    alp_snd_ioctl(handle, ALP_SND_CTL_PAUSE, NULL); 
} 
 
/*! 
 * Standard application exit handler. 
 */ 
static void onExitApp(gpointer userdata) 
{ 
    alp_snd_close(handle); 
 
	gtk_main_quit(); 
} 
 
int alp_main(int argc, char *argv[]) 
{ 
	GladeXML *glade; 
	g_print(">>> Entered %s ===\n", __DATE__ " " __TIME__); 
 
	// Register exit handler 
	alp_app_add_exit_handler(onExitApp, NULL); 
 
	// Init GTK 
	gtk_init(&argc, &argv); 
 
	glade = alp_bundle_acquire_glade_xml(APP_GLADE_FILE, NULL); 
 
	// Activate Glade signal handlers 
	glade_xml_signal_autoconnect(glade); 
 
	player_init("/var/home/audio/test.wav"); 
	 
	// Run the user interface 
	gtk_main();						 
 
	g_print("<<< Exit\n"); 
	return 0; 
} 

The Audio Manager works with raw data streams: data streams that are not encoded. Media files that do not require decoding, such as a WAV file, contain PCM data. The data in these files is already uncompressed and can be read directly into an audio stream without needing a decoder.

If you are working with data that is, or needs to be, encoded, let the Media Engine process your audio by using its Media Session APIs. The Media Engine loads the appropriate codec for you, and using the Audio Manager it creates a raw data stream (using the "audio_out" stream type) behind the scenes.

Opening an Audio Object ^TOP^

If you chose to work directly with raw data you will first need to open an audio object (equivalent to an audio stream; the terms are essentially interchangeable) with alp_snd_open(). The parameters to this function are:

  • A pointer to a void pointer, which serves as the "handle" that links the various Audio Manager calls together. When calling any of the other Audio Manager functions (except for alp_snd_notify()), pass the void pointer as the first parameter.
  • A C string containing the sound stream type. Valid strings are defined in the routing table, and thus can vary from device to device. See "Platform-Defined Sound Stream Types," below, for a listing of the standard sound stream types defined for the platform by ACCESS.
  • The final parameter indicates the mode: either ALP_SND_MODE_PLAYBACK or ALP_SND_MODE_RECORD.

Once you have successfully opened your audio stream you can either read sound bytes from the stream or write sound bytes to the stream, depending upon whether you opened the stream for recording or for playback.

Platform-Defined Sound Stream Types

The standard output stream types supported by the platform are:

button_sounds
Sounds that are played when a button is pressed.
audio_out
Most audio, including that produced by a media player. The Media Engine sends its audio through a stream of this type.
phone_call
Ring tones.
system_sounds
System sounds that can't be classified into one of the other listed sound stream types.
alerts
Sounds used to get the user's attention.
alarm
Sounds that are generated when an alarm is triggered.
message
"New Message" sound, such as would be played when an SMS or MMS message is received.
camera_sound
Shutter sound, or the sound that might be played to signify the start of a recording session.
power_sound
Power on/off sound.
game_sound
Sounds produced by games.
DTMF
DTMF (telephone dialing) sounds.

In addition to the above, which are all used when producing sounds, the following two input stream types are defined by the platform, for use when recording:

voice_record
Audio recording, typically from a microphone.
phone_record
Recording of telephone calls.

Specifying the Audio Format ^TOP^

After opening the audio object, but before you being to play or record, you need to set the audio format. The format consists of three values:

Bits per sample
8, 16, or 24
Channels
1 or 2
Sample rate
8000, 11025, 16000, 22050, 24000, 32000, 44100, and 48000

Allocate an AlpSndPcmFmt structure, set the values as appropriate for your application, and then use the ioctl function, as shown here:


AlpSndPcmFmt format; 
 
format.bits = 8; 
format.channels = 1; 
format.rate = 24000; 
alp_snd_ioctl(handle, ALP_SND_SET_FORMAT, &format); 


IMPORTANT: You must set the audio format before attempting to play or record. The audio object does not have a default format.

Playing Audio ^TOP^

To play raw data to a specific device, first open the audio object in ALP_SND_MODE_PLAYBACK mode. Next, as was shown in Listing 3.1, spawn a thread that, in a loop, reads the PCM data from the source file and sends it to the Audio Manager by calling alp_snd_write(). Finally, initiate playback with:

alp_snd_ioctl(&handle, ALP_SND_CTL_PLAY, NULL);

You can control playback by sending the audio object ALP_SND_CTL_PAUSE and ALP_SND_CTL_STOP commands in addition to the "play" command.

Recording Audio ^TOP^

To record, first open an audio object in ALP_SND_MODE_RECORD mode, and specify the device from which the audio is to be recorded, such as the microphone device. Next, create a thread that, in a loop, uses alp_snd_read() to read the audio PCM data and then writes the data to the desired location. Finally, initiate recording with:

alp_snd_ioctl(&handle, ALP_SND_CTL_PLAY, NULL);

You can control the recording session by sending the audio object ALP_SND_CTL_PAUSE and ALP_SND_CTL_STOP commands in addition to the "play" command.


NOTE: While your application is processing the buffer, the device driver continues to buffer incoming data.

Closing the Audio Object ^TOP^

Once your application has finished playing or recording you must close the audio object with alp_snd_close(). The only parameter to this function is the void pointer returned when the audio object was opened.

Playing System Sounds ^TOP^

The audio subsystem provides two convenience functions for playing system sounds. One function plays based upon the name of the sound, and the other plays the sound from a specified file. Both of these functions are exposed in alp/media_session.h.

Playing a System Sound by Name ^TOP^

If you want to play the system sound designated for a particular function—the sound that is normally played when the user performs an illegal operation, say—use alp_media_session_syssnd_play(). This function takes one of the ALP_SYS_SOUND_... values defined in alp/media_defs.h indicating the type of sound to be played. Because you are specifying the sound by its function, rather than by giving a specific path to a sound file, choices the user makes in designating particular sounds to be played for particular functions are honored by your application. Thus, for instance, if the user has specified that the crowing of a rooster is to be played whenever an alarm is triggered, that sound will be played if your application plays the ALP_SYS_SOUND_ALARM sound.

Table 3.1 lists the currently defined system sound values.

Table 3.1  Standard system sounds  

Constant

Description

ALP_SYS_SOUND_ALARM

The alarm sound.

ALP_SYS_SOUND_CAL_REMINDER

Calendar reminder sound.

ALP_SYS_SOUND_CALL_CONNECT

The sound that is played when a phone call is connected.

ALP_SYS_SOUND_CALL_DISCONNECT

The sound that is played when a phone call is disconnected.

ALP_SYS_SOUND_CAMERA_SHUTTER

The sound that is played when a photograph is taken with the camera.

ALP_SYS_SOUND_CAMERA_ZOOM

The camera zoom sound.

ALP_SYS_SOUND_CONFIRMATION

The standard system "confirmation" sound.

ALP_SYS_SOUND_DEFAULT_RING

The default ring tone.

ALP_SYS_SOUND_DELETED

The standard system "delete" sound.

ALP_SYS_SOUND_ERROR

The standard system error sound.

ALP_SYS_SOUND_IRDA_CONNECT

The sound that indicates a successful connection using IRDA.

ALP_SYS_SOUND_IRDA_DISCONNECT

The sound that indicates that an IRDA connection has been terminated.

ALP_SYS_SOUND_LOW_BATTERY

The low battery sound.

ALP_SYS_SOUND_MESSAGE_SENT

The sound that is played when a message is sent.

ALP_SYS_SOUND_NET_FAIL

The sound that is played to indicate that the network connection has failed.

ALP_SYS_SOUND_NEW_AMMS

The sound that is played when a new AMMS message is received.

ALP_SYS_SOUND_NEW_EMAIL

The sound that is played when a new email message is received.

ALP_SYS_SOUND_NEW_MMS

The sound that is played when a new MMS message is received.

ALP_SYS_SOUND_NEW_SMS

The sound that is played when a new SMS message is received.

ALP_SYS_SOUND_SAVED

The standard system "file saved" sound.

ALP_SYS_SOUND_SOFTKEY_CLICK

The soft keyboard key click sound.

ALP_SYS_SOUND_USB_CONNECT

The sound that indicates that a USB device has been connected.

ALP_SYS_SOUND_USB_DISCONNECT

The sound that indicates that a USB device has been disconnected.

ALP_SYS_SOUND_USER_ATTENTION

The sound that is played to get the user's attention.

ALP_SYS_SOUND_WARNING

Standard system warning sound.

In addition to the sound to be played, you also need to specify the audio stream through which the sound should be played, plus the volume level. The audio stream is a C string; valid strings are defined in the routing table, and thus can vary from device to device. Typically you would use "system_sounds" for system sounds, but certain sounds may be more appropriately played through one of the other stream types; see "Platform-Defined Sound Stream Types" for a list of the more common ones.

The volume level is an integer value that ranges from 0 to 7.

Calling this function is a simple matter, as shown here:


alp_media_session_syssnd_play(ALP_SYS_SOUND_SOFTKEY_CLICK,
    "system_sounds", 7); 

The first time you call either of the alp_media_session_syssnd_play... functions the function will initialize the audio subsystem and play the sound. Subsequent calls do not require the initialization step. This means that for the first call, there is a small delay before the sound is played. If minimizing this delay is important for your application, call alp_media_session_syssnd_init() earlier in your application; this initializes the audio subsystem so that it needn't be initialized when the first sound is played.

High-Performance Sounds

By calling alp_media_session_syssnd_init() before the first use of alp_media_session_syssnd_play(), you can reduce the delay between the call and when the sound is actually heard to about 0.1 seconds. In certain instances—largely when playing sounds to signify that a hardware or software button has been pressed—even this is too long of a delay. For these situations, the Audio Manager has a similar function that does nearly the same thing, although it operates much faster. alp_snd_syssnd_play()—the function that corresponds to alp_media_session_syssnd_play()—also takes a string identifying the sound, a stream identifier, and a volume level. However:

  • The set of "system sounds" that this function will play is much smaller.
  • The volume level you supply to this function should range from 0 to 100 (as opposed to from 0 to 7 for the Media Session equivalent of this function).

You should also supply an appropriate stream identifier depending upon the system sound you are playing.

Table 3.2 lists the system sounds that can be played with this function, and the recommended stream type to use when playing each sound.

Table 3.2  alp_snd_syssnd_play() supported sounds and recommended stream types

Sound

Stream Type

Description

ALP_SND_ATTENTION

system_sounds

Attention sound.

ALP_SND_CAMERA_SHUTTER

camera_sound

Sound of the camera taking a picture.

ALP_SND_CAMERA_ZOOM

zoom_sound

Sound of the camera zooming in or out.

ALP_SND_DELETED

system_sounds

Sound confirming that data has been deleted.

ALP_SND_ERROR

system_sounds

Sound of an error, which may have been caused by the user.

ALP_SND_KEY

button_sounds

The sound that is produced when a key on the software keyboard is pressed.

ALP_SND_SAVED

system_sounds

Sound confirming that data has been saved.

ALP_SND_WARNING

alarm

"Danger" sound, indicating that something bad could possibly happen.

Playing a System Sound File ^TOP^

Instead of playing the user- or system-designated sound for a particular function, as was described in "Playing a System Sound by Name," if you instead need to play the sound stored in a specific system sound file, use alp_media_session_syssnd_play_file() instead. This function takes as its first argument the absolute path to a system sound file (system sound files are typically found in /usr/share/sounds/system/ or /usr/share/sounds/ringtones/).

As with alp_media_session_syssnd_play(), you also need to specify the audio stream through which the sound should be played, plus the volume level. The audio stream is a C string; valid strings are defined in the routing table, and thus can vary from device to device. For most true system sounds you would use "system_sounds", but certain sounds may be more appropriately played through one of the other stream types. See "Platform-Defined Sound Stream Types" for a list of the more common ones.

The volume level is an integer value that ranges from 0 to 7.

The following shows how you can use this function to play the contents of a system sound file:


alp_media_session_syssnd_play_file(
    "/usr/share/sounds/system/Low_Battery.mp3",
    "system_sounds", 7); 

The first time you call either of the alp_media_session_syssnd_play... functions the function will initialize the audio subsystem and play the sound. Subsequent calls do not require the initialization step. This means that for the first call, there is a small delay before the sound is played. If minimizing this delay is important for your application, call alp_media_session_syssnd_init() earlier in your application; this initializes the audio subsystem so that it needn't be initialized when the first sound is played.

High-Performance Sounds

By calling alp_media_session_syssnd_init() before your first call to alp_media_session_syssnd_play_file(), you can reduce the delay between the call and when the sound is actually heard to about 0.1 seconds. In certain instances—largely when playing sounds to signify that a hardware or software button has been pressed—even this is too long of a delay. For these situations, the Audio Manager has a similar function that does much the same thing, although it operates much faster. alp_snd_syssnd_play_file()—the function that corresponds to alp_media_session_syssnd_play_file()—also takes an absolute path to the file containing the sound to be played, a stream identifier, and a volume level. However:

  • The specified file must be in WAV format (the alp_media_session_syssnd_play_file() function supports a wide range of formats).
  • The volume level you supply to this function should range from 0 to 100 (as opposed to from 0 to 7 for the Media Session equivalent of this function).

You should also supply an appropriate stream identifier depending upon the system sound you are playing. See "Platform-Defined Sound Stream Types" for the most common stream types.

Managing Volume Levels ^TOP^

Most applications don't need to manipulate volume levels themselves, relying instead upon the built-in facilities of the device (dedicated volume keys, volume settings in Preferences, etc.) to enable the user to adjust the volume level as desired. For those applications that do need to get or set volume levels, the remainder of this section describes the volume control mechanism built in to ACCESS Linux Platform.

Volume Control Architecture ^TOP^

As shown in Figure 3.2, the volume of an audio stream can be altered at any of four points between where it originates and where it is eventually output. For PCM audio controlled or produced by the Audio Manager, the actual volume of the sound that is heard by the end user is the product of these four volume levels. So, for example,

  • If all four volume levels are set to 100, the sound is heard at full volume (1.0x1.0x1.0x1.0=1.0, or 100%).
  • If three of the four volume levels are set to 100 and one of them is set to 50, the sound is heard at half volume (0.5x1.0x1.0x1.0=0.5, or 50%).
  • If two of the four volume levels are set to 50, and the other two are set to 100, the sound is heard at one-quarter volume (0.5x0.5x1.0x1.0=0.25, or 25%).
  • If any one of the volume levels is set to zero, no sound is heard.

All volume levels are intially set to 100.

Figure 3.2  Audio Manager volume controls

Although there are four volume levels, applications can only affect two of them: "Stream Volume" and "Stream Class Volume".

Stream Volume

This is the volume level for an individual stream. Because each stream's volume level can be set independently, you can adjust the relative volume of multiple streams, making one quieter or louder than another. You set the volume of a particular stream by calling alp_snd_ioctl(..., ALP_SND_SET_VOLUME, ...) and passing the handle for the stream. Similarly, you can obtain a stream's current volume level with alp_snd_ioctl (..., ALP_SND_GET_VOLUME, ...).

Stream volume levels initially default to 100. If you want to preserve volume levels across invocations of your application, you'll need to save the stream's volume level using a mechanism such as the Settings Service and restore it when your application is started.

Be aware that on many devices when two streams of the same class are playing at the same time, their sound is mixed (with the independently set volume levels of the two streams determining how well one stream can be heard relative to the other). The device manufacturer, however, has the option to construct the routing table such that only one stream of a given class will be played at one time: when the second stream is started, the currently playing stream is stopped. You can register a callback function so that you are notified when your streams are stopped: use alp_snd_callback_register() to register a function of type AlpSndCallBack.

This same callback is invoked whenever the stream is muted or the volume is changed. As well, it is invoked whenever the stream's playback status is changed (that is, when it is stopped, started, or paused). Finally, it is called for recording sessions when recording begins. See the AlpSndActionType enum in the API reference documentation for the complete list of action values.

Stream Class Volume

Each audio stream type, or class, has an associated volume level. (See "Platform-Defined Sound Stream Types" for a list of common stream types.) Altering a stream class's volume level affects the volume level of those streams of that type without affecting the volume of streams of other types. For instance, if you raise the volume of the "audio_out" class, sounds produced by a media player (or any other application using Media Engine to play content that contains audio data) will become louder, while the volume of other sounds—such as ring tones or alarms—will remain unchanged.

Certain stream class volume levels can be adjusted by the user using a preference panel: typically, "phone_call", "alerts", "system_sounds", and "button_sounds". If needed, you can also adjust these and other stream class volume levels programmatically.

To change the volume level for a given stream class, simply set up an AlpSndNotifyStru structure with the stream class name and desired volume level, and then call alp_snd_notify(), as shown in Listing 3.2.

Listing 3.2  Altering a stream class volume level


AlpSndNotifyStru alpSndNotify; 
 
strcpy(alpSndNotify.keyid, "audio_out"); 
alpSndNotify.val = volumelevel;    // from 0 to 100 
alp_snd_notify(&alpSndNotify, ALP_SND_NOTIFY_VOLUME, 1); 

Stream class volume levels initially default to 100. The operating system maintains a record of certain class volume levels ("phone_call", "alerts", "system_sounds", and "button_sounds") using the Settings Service, restoring them whenever the device is restarted. Because this is done by the operating system, however, and not the Audio Manager, if you alter one of these stream class volume levels and want it similarly preserved, you'll need to update the appropriate settings yourself. Typically you do this each time you alter the volume level (rather than doing it when your application exits), as is shown in Listing 3.3.

Listing 3.3  Setting the Alert volume


// Set the volume level 
strcpy(alpSndNotify.keyid, g_strrstr(ALP_PREFS_VOLUME_ALERTS, "/") + 1); 
alpSndNotify.val = volumelevel; 
alp_snd_notify(&alpSndNotify, ALP_SND_NOTIFY_VOLUME, 1); 
 
// now store the new volume level in the global setting 
// Note that "context" is returned when the settings service is opened with a 
// call to alp_settings_open() 
ret = alp_settings_set_key_int_value(context, ALP_PREFS_VOLUME_ALERTS, volumelevel); 

Master Volume

As illustrated in Figure 3.2, the master volume is a "global" volume control that affects all streams simultaneously. Because the master volume affects such a wide range of sound sources—from ring tones to alarms to multimedia audio—applications should avoid altering it. Many devices will have dedicated volume keys that allow the user to raise or lower the master volume level.

If, in the unlikely event you need to affect the master volume level, you would do so as shown in Listing 3.4.

Listing 3.4  Setting the master volume level


AlpSndNotifyStru alpSndNotify; 
 
strcpy(alpSndNotify.keyid, "mastervolume"); 
alpSndNotify.val = volumelevel;    // from 0 to 100 
alp_snd_notify(&alpSndNotify, ALP_SND_NOTIFY_VOLUME, 1); 

Because the master volume level is maintained by the operating system using the Settings Service, you can check its level by querying the value of the ALP_PREFS_VOLUME_MASTERVOLUME setting.


NOTE: The Settings Service simply maintains a copy of the current volume levels; changing the value of this setting will not affect the master volume level.

Device Volume

The Audio Manager has a provision for setting the volume level of each separate output (or input) device independently. However, applications cannot count on a particular stream always being routed to or from a particular device, since as conditions change (for instance, when the user plugs in a headset or when a phone call is received) the audio router may redirect various streams depending upon the rules set forth in the routing table. The device volume levels are best left to the system, allowing the user to, for instance, adjust the relative volume of the speaker and headphones so that listening levels are equally comfortable through either.

Other Volume Settings

The diagram on on page 41 shows a somewhat simplified view of the way sound flows through the various volume controls on its way from source to destination. In reality, there are a couple of other ways that an audio stream's volume can be affected.

Threshold Volume

Threshold volume limits enable automatic control and management of audio surges to guard against hearing damage. For example, a limit can be set when on headphone volume, so that no matter how loud the sound is playing through a speaker, when the headphones are plugged in the volume won't exceed the threshold volume limit. Threshold volume limits are set on a per-device-basis by the device manufacturer; they cannot be set by application developers.

Attenuation Volume

Attenuation volume levels are designed to handle the case when two sounds are playing and one needs to be clearly heard above the other. For instance, if you are listening to music and a phone call is received, the "audio_out" stream's volume can be attenuated so that the ring tone can be clearly heard. As with the threshold volume limits, attenuation volume levels are set by the device manufacturer and may vary from one device to another. These levels cannot be altered by application developers.

Silent Mode

In certain rare circumstances it can be useful to mute the sounds coming from the device. The Audio Manager has an "intelligent" mute capability that suppresses all sounds except those that the device manufacturer has decided must always be heard (for instance, in some countries it is required that a camera shutter sound always be audible when a picture is taken).

Listing 3.5 shows how to mute the device. Set alp_sndNotify.val to FALSE to disable silent mode and re-enable the playing of sounds.

Listing 3.5  Enabling silent mode


AlpSndNotifyStru alpSndNotify; 
 
strcpy(alpSndNotify.keyid, "silent_mode"); 
alpSndNotify.val = TRUE;    // mutes the device 
alp_snd_notify(&alpSndNotify, ALP_SND_NOTIFY_VOLUME, 1); 

Keeping the Audio Manager Informed ^TOP^

"Managing Volume Levels" discussed, among other things, the use of the alp_snd_notify() function to request that the Audio Manager change the volume level for an entire class of audio stream. You can also use this function to keep the Audio Manager apprised of audio device status changes and changes in conditions that may trigger rules within the routing table. Note that this is normally taken care of for you by the system; applications rarely if ever use alp_snd_notify() to do other than change audio stream class volume levels.

Changes in Device Status ^TOP^

If your application is in the unique position to know about a change in the presence of an audio input or output device (such as a microphone or Bluetooth headset, for instance), you'll want to let the Audio Manager know about that change. This requires that you know the name of the device as it is used in the routing table. Then, you simply allocate and fill out an AlpSndNotifyStru structure and pass it to alp_snd_notify(), as is shown in Listing 3.6.

Listing 3.6  Registering a change in device status


AlpSndNotifyStru notify; 
int err; 
	 
strcpy(notify.keyid, "BT-headphone"); 
notify.val = 1;   // 1=present, 0=absent 
err = alp_snd_notify(&notify, ALP_SND_NOTIFY_DEVPRESENT, 1); 

Normally, the ACCESS Linux Platform device knows about these types of state changes, so that applications need not track and register the presence or absence of the various audio input/output devices.

Changes in Condition ^TOP^

Rules are constructed not only based upon the presence or absence of physical devices (a microphone, a Bluetooth headset, or an FM radio, for example), but also upon predefined conditions. A condition might have a physical correspondence--say, to indicate the position of a "ringer off" switch. Or, a condition can indicate a certain state. An example of this might be "In an active voice call". Here, too, ACCESS Linux Platform usually takes care of tracking condition changes and letting the audio router know about those changes. But if there is a condition of which the operating system is unaware, and your application is in a position to know about it, it should use alp_snd_notify() to inform the audio router of the change. Or, if you need to simulate a particular condition, providing that you know the name of the condition as it is defined in the routing table, you can use this technique to do so.

Listing 3.7 shows how you would inform the audio router of a condition change. Note that this particular example registers two condition changes with a single call. In this case, it tells the audio router that we are no longer in the state where we are dialing and waiting for the call to be answered ("in-outgoing-call" mode) but are now in the state where the call has been received and is active ("in-active-voicecall" mode).

Listing 3.7  Registering a condition change


AlpSndNotifyStru snd_notify[2]; 
 
memset(&snd_notify, 0, sizeof(snd_notify)); 
 
strncpy((char *)&snd_notify[0].keyid, 
	(char *)"in-outgoing-call", strlen("in-outgoing-call")); 
snd_notify[0].val = 0; 
 
strncpy((char *)&snd_notify[1].keyid, 
	(char *)"in-active-voicecall", 
	strlen("in-active-voicecall")); 
snd_notify[1].val = 1; 
 
alp_snd_notify(snd_notify, ALP_SND_NOTIFY_CONDITION, 2); 

Handling Outside Events ^TOP^

Although an application is generally aware of the current state of any stream it has created, in certain circumstances the Audio Manager can affect that stream. For example, if the device is configured to allow only one stream of a given class to play at a time (only the device manufacturer can so configure a device), a running stream will be terminated by the Audio Manager if another stream of that same class is started. Or, while the stream is playing, the user could do something to affect the stream—for instance, they could plug in a headset, causing the audio to be redirected to that headset. Or, if conditions change such that the user has no way to hear the stream, the Audio Manager may, depending upon rules in the routing table, stop the stream to conserve battery power.

Because any of these things could be of interest to your application, the Audio Manager broadcasts notifications if and when they occur, allowing your application to take appropriate action.

Handling a Change in Stream Status ^TOP^

So that your application can be made aware when your stream is stopped, started, or has its volume muted or attenuated by the Audio Manager, the Audio Manager allows you to register for a notification that is broadcast whenever such things happen. The AlpSndActionType enum defines the actions about which your application will be informed through this notification:


enum AlpSndActionType { 
	ALP_SND_ACTION_PLAY, 
	ALP_SND_ACTION_RECORD, 
	ALP_SND_ACTION_PAUSE, 
	ALP_SND_ACTION_STOP, 
	ALP_SND_ACTION_MUTE, 
	ALP_SND_ACTION_ATTENUATE, 
	ALP_SND_ACTION_NULL 
} 

Register for the ALP_NOTIFY_EVENT_AUDIO_ACTION_CHANGE notification as you would any other:


alp_notify_register(ALP_NOTIFY_EVENT_AUDIO_ACTION_CHANGE,
    on_notify, NULL, ALP_NOTIFY_PRIORITY_NORMAL, 0);  

Your notification handler will be passed an AlpSndNotifyActionchangeStru structure, which contains three important pieces of information: the current action, the previous action, and the ID of the process that controls the affected stream. This last is particularly important, since your handler will receive audio state change notifications for every stream that is currently running, not just your own. If, as is typical, you are only concerned about state changes in your own stream(s), check the supplied PID against your own to ensure that the notification applies to the stream(s) you control.

Listing 3.8 illustrates a simple notification handler that terminates the application if its stream is stopped for any reason.

Listing 3.8  Handling a stream state change notification


alp_status_t on_notify(AlpSndNotifyActionChangeStru *details){ 
	if(details->pid == getpid()) { 
		switch(details->cur_action) { 
			case ALP_SND_ACTION_STOP: 
				my_exit_handler(NULL); 
				break; 
			default: 
				break; 
		} 
	} 
 
	return ALP_STATUS_OK; 
} 

Handling a Stream Redirection ^TOP^

When something happens that causes the input or output of an active audio stream to be redirected to a different input or output device, the Audio Manager sends out a notification so that interested parties can stay informed. This ALP_NOTIFY_EVENT_AUDIO_ROUTE_CHANGE ("/alp/audio_route/change") notification is accompanied by an AlpSndNotifyPathChangeStru structure, which has two members: a comma-separate list of destination (or "sink") element IDs, and a single source element ID. The list of destination element IDs details the chain of elements through which the audio passes after leaving the source, up through its final destination.

Register for the ALP_NOTIFY_EVENT_AUDIO_ROUTE_CHANGE notification as you would any other:


alp_notify_register(ALP_NOTIFY_EVENT_AUDIO_ROUTE_CHANGE,
    on_notify, NULL, ALP_NOTIFY_PRIORITY_NORMAL, 0);  

Note that you can obtain the current route path of a specified stream type (which varies according to the current sound device status and the routing rules defined in the routing table), even if the stream is not active in the Audio Manager server, by calling alp_snd_get_current_routepath(). Pass a C string containing the sound stream type for the first parameter (see "Platform-Defined Sound Stream Types"). The second parameter is used to pass back a string of all routing destinations, separated by commas.

 

Add as favourites (35) | Quote this article on your site | Views: 534

Comments (1)
RSS comments
1. Written by This e-mail address is being protected from spam bots, you need JavaScript enabled to view it on 08-07-2008 13:36 - Guest
 
 
 

Write Comment
  • Please keep the topic of messages relevant to the subject of the article.
  • Personal verbal attacks will be deleted.
  • Please don't use comments to plug your web site. Such material will be removed.
  • Just ensure to *Refresh* your browser for a new security code to be displayed prior to clicking on the 'Send' button.
  • Keep in mind that the above process only applies if you simply entered the wrong security code.
Name:
E-mail
Homepage
Title:
BBCode:Web AddressEmail AddressBold TextItalic TextUnderlined TextQuoteCodeOpen ListList ItemClose List
Comment:



Code:* Code
I wish to be contacted by email regarding additional comments

Powered by AkoComment Tweaked Special Edition v.1.4.6
AkoComment © Copyright 2004 by Arthur Konze - www.mamboportal.com
All right reserved

 


© 2008 ACCESS Developer Network    |    Joomla! is Free Software released under the GNU/GPL License.    |    ACCESS Global Website
Events Support Community Platforms Home