Mixer programming |
Introduction |
Most sound cards have some kind of mixer which can be used for adjusting
volumes. OSS API defines a device file (/dev/mixer) which can
be used to access mixer functions of the card. It is possible that there
are more than one mixers if there are several sound cards installed on
the system. Actually mixer device files are numbered (/dev/mixer0, /dev/mixer1,
...) and /dev/mixer is just a symbolic link to one of these device
files. Usually the link points to /dev/mixer0 but user has freedom
to assign the link differently).
The mixer API of OSS is based on channels. A mixer channel is a numbered object which represents a physical control/slider of the mixer. Each of the channels have independently adjustable value which may vary between 0 (off) and 100 (maximum volume). Most of the channels are stereo controls so it is possible to set value for both stereo channels separately which permits implementation of balance. The mixer API contains few ioctl calls for setting an getting values of these mixer channels. In addition to volumes the mixer API also controls selection of recording source(s). With most sound cards it is possible to record simultaneously only from one source while few cards (PAS16) allow several recording sources to be active at the same time. After boot the microphone input is usually selected as the recording source (there is no guarantee that this is always true).
The third class of mixer ioctl calls are functions used for querying capabilities of the mixer. With these calls it is possible to check which mixer channels are actually present and which of them can be used as input sources.
|
|||
Types of mixer programs |
The mixer API of OSS permits writing of generic mixer programs which
work with almost any sound cards. This is possible only if the program
uses query functions of this API to check capabilities of the device before
trying to use it.
It is also possible to design a mixer so that it works best with a particular sound card. In this way it is easier to design a nicely looking GUI which matches the hardware properly. Also in this case it is a good idea to check that the required mixer channels are actually present by using the query ioctl functions defined below. In this case you should indicate clearly in the documentation of the program that it requires a particular sound card. |
|||
Mixer channels |
The mixer channels have an unique number between 0 and 30. soundcard.h
defines some mnemonic names for the channels. Note that these are
the current ones. New ones could be added in the future.
The macro SOUND_MIXER_NRDEVICES gives the number of channels known when this version of soundcard.h was written. Any program should not try to access channels greater or equal than SOUND_MIXER_NRDEVICES. The following channels are currently known by the driver:
|
|||
Querying capabilities of the mixer |
The mixer interface of OSS driver has been designed so that it is possible
to compile a mixer program on one system and to use it on another system
with different hardware setup. This is possible only if the mixer program
follows some guidelines. It has to query for the hardware configuration
before making any other actions with the mixer interface. It is not dangerous
if the program tries just to change volume of a channel without making
the query since the ioctl call returns an error if there is something wrong
with the config. However if a mixer programs shows the complete list of
channels even if there is no mixer, the user will get confused. The following
ioctl calls give the program a way to determine the current setup.
Using mixer query interfaceAll query functions of the mixer API return a bitmask in an integer variable passed as an argument to the ioctl call. The following code fragment shows the generic method used in the calls defined in next chapters.int mask; if (ioctl(mixer_fd, SOUND_MIXER_READ_xxxx, &mask) == -1) {No mixer available - Handle "gracefully"}It is important to note that any ioctl call of the mixer API may return "errno==ENXIO" if no mixer is present (it is always possible to open /dev/mixer0 even when no mixer is available). Meaning of the bits of the mask are defined in later sections. Testing the bit corresponding a mixer channel can be done using expression "mask & (1 << channel_no)". The channel_no may be one of the SOUND_MIXER_ macrose defined earlier (####insert pointer here) or an integer value between 0 and SOUND_MIXER_NRDEVICES. The later alternative is usefull when writing a mixer that dynamically adapts to capabilities of any card. Checking available mixer channels (SOUND_MIXER_READ_DEVMASK)SOUND_MIXER_READ_DEVMASK returns a bitmask in the variable pointed by the argument (mask in this case). To see if a particular mixer channel is supported you need to test if the bit corresponding the channel number is set. Any attempt to access undefined mixer channels using channel specific ioctl calls will return an error (errno==EINVAL).Checking available recording devices (SOUND_MIXER_READ_RECMASK)SOUND_MIXER_READ_RECMASK returns a bitmask where each bit represents a mixer channels. Only the channels having their bit set may be used as a recording channel.Checking if a device is mono or stereo (SOUND_MIXER_READ_STEREODEVS)Most mixer devices have stereo capability so it is possible to set volumes independently for both the left and the right stereo channel of the mixer channel. However some devices are mono only and just volume of the left stereo channel is defined for them. ioctl call SOUND_MIXER_READ_STEREODEVS returns a bitmask where a 1 bit tells that the corresponding channels is stereo. A mixer program should use this information to deciding if it should draw sliders for both stereo channels or not. Having a stereo control displayed for a mono channel is not a big error but it may confuse user in some cases.Checking general capabilities of a mixer (SOUND_MIXER_READ_CAPS)The ioctl call SOUND_MIXER_READ_CAPS returns a bitmask which describes general capabilities of a mixer. These capabilities are not related to any particular mixer channel. Currently just one mixer capability is defined. Bit SOUND_CAP_EXCL_INPUT is set to 1 if only one mixer channel can be selected as recording at the same time. If the bit is 0 then it is possible to have several recording devices selected at the same time. Actually checking this bit is not important since the difference between these alternatives is handled by the ioctl call used for selecting the recording channel. |
|||
Naming of mixer channels |
####Incomplete section
soundcard.h defines also two sets of printable names for the channels. These name should be used when labeling or naming the mixer channels by application programs. The macro SOUND_DEVICE_LABELS contains a list of printable strings which can be used for example to label the sliders for the channels. You could access the names by defining a variable as: For example labels[SOUND_MIXER_VOLUME] contains a textual label for the main volume channel. The macro SOUND_DEVICE_NAMES is similar but it contains names to be used for example when parsing command lines etc. The names in this macro don't contain blancs or capital letters. |
|||
Meaning of volume levels |
OSS driver accepts volumes between 0 and 100. The 0 means off and the
100 means maximum.
Most of the mixers have 3 to 8 bits for the volume and the driver scales between the local and hardware defined volume. Since this scaling is not accurate, the application should be careful when using the volume returned by the ioctl calls. If the application writes the volume and reads it back, the returned volume is usually slightly different (smaller) than the requested one. If the write-read sequence is repeated several times, the volume slides to zero even if the application makes no changes itself. It is recommended that the application reads the volume just during initialization and ignores the volume returned later. Note! The MIXERWRITE returns the modified volume in the argument after call. A temporary variable should be used as the argument. Otherwise the volume will slide down on each access. Getting and setting volumes (SOUND_MIXER_READ/SOUND_MIXER_WRITE)An application program can read and/or write volume of a device by calling ioctl functions SOUND_MIXER_READ(chn) and SOUND_MIXER_WRITE(chn). The mixer channel is given as the chn argument to the macro. The channel number may be one of the channel identifiers defined in soundcard.h or an integer between 0 and SOUND_MIXER_NRDEVICES. For example the following call reads current volunme of microphone input:int vol; if (ioctl(mixer_fd, SOUND_MIXER_READ(SOUND_MIXER_MIC), &vol)==-1) /* An undefined mixer channel was accessed */The program should check if an error was returned from the ioctl call. The driver will return an error if the mixer channel is not known or if there is no mixer at all. (Programs should not blindly terminate if this call returns an error). The volume for both stereo channels are returned in the same int variable. The least significant byte gives volume for the left channel and the next 8 bits for the for the right channel. The upper 16 bits are undefined and should be ingnored. For mono devices just the left channel value is valid (the right channel value is set to the left channel value by the driver). The volume setting can be altered by using ioctl SOUND_MIXER_WRITE. It works just like SOUND_MIXER_READ but in addition it alters the actual "hardware" volume of the channel. Note that this call also returns the new volume in the variable passed as an argument to the ioctl call. In some cases the value may be slightly different than the value passed to the call. |
|||
Selecting the recording sources |
OSS driver has two calls for selecting recording sources. In addition
the SOUND_MIXER_READ_RECMASK returns the devices which can be
used as recording devices.
The SOUND_MIXER_READ_RECSRC returns a bitmask having a bit set for each of the currently active recording sources. The default is currently mic in but the application should not assume this. The recording source could have been changed after boot. The SOUND_MIXER_WRITE_RECSRC can be used to alter the recording source selection. If no bits are on, the mic input will be used. The SB Pro allows just one active input source at the same time. The driver has a simple expert system to handle invalid recording source selections. A mixer program should always check the recording mask after changing it. It should also update the display if the returned mask is something else than the requested one. |