![]() |
![]() |
![]() |
The Mixer is responsible for controlling the analog portions of a soundcard. Specifically, this involves mixing or combining multiple analog sound sources for output and input. The Neutrino Audio API allows control of these operations by the manipulation of basic mixer elements. Several element types exist in the specification, but the most useful are:
The API also defines mixer groups that are logical collections of elements that allow for a more abstracted control of the mixer. For example, we can manipulate the "CD" group to increase the volume, mute it, and also select the "CD" source for recording. Although it's possible to access and control all mixer elements directly, most applications will just control groups.
To control a group, an application has to
The following code fragment from the wave.c example in the appendix demonstrates how to do this:
if ((rtn = snd_mixer_open (&mixer_handle, card, setup.mixer_device)) < 0) { fprintf (stderr, "snd_mixer_open failed: %s\n", snd_strerror (rtn)); return -1; } ... if (snd_mixer_group_read (mixer_handle, &group) < 0) fprintf (stderr, "snd_mixer_group_read failed: %s\n", snd_strerror (rtn)); ... if (snd_mixer_group_write (mixer_handle, &group) < 0) fprintf (stderr, "snd_mixer_group_write failed: %s\n", snd_strerror (rtn)); ... rtn = snd_mixer_close (mixer_handle);
typedef struct { int32_t type; int8_t name[32]; int32_t index; } snd_mixer_gid_t; typedef struct snd_mixer_group_s { snd_mixer_gid_t gid; uint32_t caps; uint32_t channels; int32_t min, max; union { int32_t values[32]; struct { int32_t front_left; int32_t front_right; int32_t front_center; int32_t rear_left; int32_t rear_right; int32_t woofer; } names; } volume; uint32_t mute; uint32_t capture; } snd_mixer_group_t;
The group is identified by the gid structure. It must be set before calling snd_mixer_group_read(). The members of the structure include:
One problem with mixer groups is to find the one that's controlling the data that you're playing out of the PCM device. The PCM API function, snd_pcm_plugin_setup(), is useful because it returns the mixer device number (there can be more than one mixer per soundcard), and the group that best controls the PCM data. The group returned may be one of:
The rule is: the lowest supported group is returned by snd_pcm_plugin_setup(), but some soundcard hardware may not support subchannel controls. To resolve this, use the setup structure to set a pointer to where you want the group identification stored. The mixer device number used to open the mixer is returned. The following code fragment from the wave.c example in the appendix demonstrates how to do this:
memset (&setup, 0, sizeof (setup)); setup.channel = SND_PCM_CHANNEL_PLAYBACK; setup.mixer_gid = &group.gid; if ((rtn = snd_pcm_plugin_setup (pcm_handle, &setup)) < 0) fprintf (stderr, "snd_pcm_plugin_setup failed: %s\n", snd_strerror (rtn));
Many applications may attempt to control a mixer group concurrently. As a result, it's essential that all applications are notified of any changes. This is how mixer events are used:
An example of these callbacks is the "group changed callback" that's called whenever a change to a group is made. If an application makes a change it doesn't receive a group change event notification, but all other applications do!
Here's a short example of how this works:
int mixer_update () { snd_mixer_callbacks_t callbacks; memset(&callbacks, 0, sizeof(callbacks)); callbacks.group = mixer_callback_group; snd_mixer_read (mixer_handle, &callbacks); return (0); } static void mixer_callback_group (void *private_data, int cmd, snd_mixer_gid_t *gid) { switch (cmd) { case SND_MIXER_READ_GROUP_VALUE: if( strcmp(gid->name, group.gid.name)==0 && gid->index==group.gid.index) // read the changed group if (snd_mixer_group_read (mixer_handle, &group) < 0) fprintf (stderr, "snd_mixer_group_read failed: %s\n", snd_strerror (rtn)); break; } }
![]() |
Mixer events are queued for every opened mixer handle, so your application must clear these events using snd_mixer_read(). Failure to do so, results in all snd_mixer_group_write(). calls failing. |
![]() |
![]() |
![]() |