NAME | SYNOPSIS | OVERVIEW | AUDIO FORMATS | DESCRIPTION | IOCTLS | MACROS | CODE EXAMPLES | ERRORS | FILES | ATTRIBUTES | SEE ALSO | BUGS
#include <sys/mixer.h>
The audio mixer extends the audio(7I) interface, allowing more then one process to play or record audio at the same time. Understanding the audio(7I) interface thoroughly is a prerequisite to understanding the mixer(7I) interface.
It is possible to disable the mixing function and return to 100% backward compatibility with the audio(7I) interface. These two modes of operation are referred to the mixer mode and the compatible mode. This is done by editing the audio driver's .conf file and then unloading and reloading the driver, or using the mixerctl(1) command.
The audio mixer supports the new multi-stream Codecs that have become available recently. Examples of these Codecs are the Crystal Semiconductor 4410/4422 and the Aureal 8820/8830. These devices have DSP engines on them that provide a great many features, such as sample rate conversion. Therefore each play/record channel is mapped to an individual channel straight into the Codec and the audio mixer doesn't do any sample rate or encoding conversion, as described below. However, the programming interfaces remain the same and applications cannot tell the difference between a multi-stream Codec and a traditional Codec.
The audio_info_t structure allows the application to set the size of the play and record buffer size. As in the audio(7i) interface, the audio mixer doesn't support changing the play buffer. This is because the audio driver takes sound samples as they are needed, regardless of how many are delivered with each write. However, the record side does use the buffer size. When buffer size bytes are captured by the audio driver then that many bytes are sent to the application to read.
See the audio(7I) manual page for a brief discussion on audio formats. The audio mixer must convert all audio formats to a common format in order to mix the various audio streams. The following describes how the audio mixer deals with these different components.
As defined in audio(7I), the initial sample rate when /dev/audio is opened is 8KHz.
In mixer mode the audio mixer always configures the Codec for the highest possible sample rate for both record and play. This ensures that none of the audio streams need to be low pass filtered, which is almost as compute intensive as up sampling. The result is that high sample rate audio streams aren't degraded by filtering.
Sample rate conversion can be a compute intensive operation, depending on the number of channel's and the devices sample rate. For example, an 8KHz signal is easy to convert to 48KHz. Requiring a low cost up sampling by 6. However, converting from 44.1KHz to 48KHz is very compute intensive given that it must be up sampled by 160 and then down sampled by 147, in order to use integer multipliers. (Remember, we only get integers in the kernel.) Therefore, applications can greatly reduce the impact of sample rate conversion by carefully picking their sample rate. The least impact is to use the highest sample rate the device supports, as there isn't any sample rate conversion necessary. The next best is to have the applications do it's own sample rate conversion, where it can take advantage of floating point and accelerated instructions, like VIS and MMX. This is followed by small up and down sampling integers.
In compatible mode the audio mixer programs the Codec to the sample rate set by the application. Therefore it doesn't incur any sample rate conversion overhead. If the Codec cannot support different play and record sample rates then the AUDIO_SETINFO ioctl(2) will fail.
As defined in audio(7I), the initial encoding and precision when /dev/audio is opened is 8-bit mu-Law (as in the Greek letter mu).
In mixer mode the audio mixer supports the following formats in the following precisions.
Encoding | Precision | Channels |
Signed Linear PCM | 16-bit | Mono or Stereo |
Unsigned Linear PCM | 8-bit | Mono or Stereo |
mu-Law | 8-bit | Mono or Stereo |
A-Law | 8-bit | Mono or Stereo |
The audio mixer converts all audio streams to Linear PCM before mixing. After mixing it is converted to the best format the audio mixer can configure the Codec for. This conversion process is not compute intensive, therefore audio applications can choose whichever encoding best meets the needs of the application.
In compatibility mode the audio mixer sets the Codec to the encoding and precision set by the application. If the Codec cannot support different play and record encodings or precisions then the AUDIO_SETINFO ioctl(2) will fail.
As defined in audio(7I), the initial number of channels when /dev/audio is opened is 1, mono. Most Codecs play or record mono audio on the left channel.
In mixer mode the audio mixer sets the Codec to the maximum number of channels supported. If a mono signal is played or recorded it is mixed only on the first channel, which is usually the left channel, and silence is mixed on all other channels.
In compatible mode the audio mixer sets the Codec to the number of channels set by the application. If the Codec cannot support a different number of play and record channels then the AUDIO_SETINFO ioctl(2) will fail.
The device /dev/audio is a device driver that dispatches audio requests to the appropriate underlying audio personality module. The audio driver is implemented as a STREAMS driver. In order to record audio input, applications open(2) the /dev/audio device and read data from it using the read(2) system call. Similarly, sound data is queued to the audio output port by using the write(2) system call. Device configuration is performed using the ioctl(2) interface.
In mixer mode the the audio device is no longer treated as an exclusive resource. However, each process may open the audio device once, unless it has made an AUDIO_MIXER_MULTIPLE_OPEN ioctl(2). See below for more details.
Each open() will complete as long as there are channels available to be allocated. When there are no longer any channels available to allocate the following happens:
if either the O_NDELAY or O_NONBLOCK flag are set in the open() oflag argument, then -1 is immediately returned, with errno set to EBUSY.
if neither the O_NDELAY nor the O_NONBLOCK flag are set, then open() hangs until a channel becomes available or a signal is delivered to the process, in which case a -1 is returned with errno set to EINTR.
Upon the initial open() of the audio channel, the audio mixer will reset the data format of the audio channel to the default state of 8-bit, 8Khz, mono mu-Law data (as in the Greek letter mu). If the audio device doesn't support this configuration then it tells the audio mixer what the initial configuration should be. Therefor audio applications should explicitly set the encoding characteristics to match the audio data requirements, rather than depend on the default configuration.
In compatible mode the audio mixer behaves exactly as described in the audio(7I) manual page. See that manual page for details.
The read() system call copies data from the system buffers to the application. Ordinarily, read() blocks until the user buffer is filled. The I_NREAD ioctl (see streamio(7I)) may be used to determine the amount of data that may be read without blocking. The device may alternatively be set to a non-blocking mode, in which case read() completes immediately, but may return fewer bytes than requested. Refer to the read(2) manual page for a complete description of this behavior.
When the audio device is opened with read access, the device driver immediately starts buffering audio input data. Since this consumes system resources, processes that do not record audio data should open the device write-only (O_WRONLY).
The transfer of input data to STREAMS buffers may be paused (or resumed) by using the AUDIO_SETINFO ioctl to set (or clear) the record.pause flag in the audio information structure, see audio(7I). All unread input data in the STREAMS queue may be discarded by using the I_FLUSH STREAMS ioctl (see streamio(7I)). When changing record parameters, the input stream should be paused and flushed before the change, and resumed afterward. Otherwise, subsequent reads may return samples in the old format followed by samples in the new format.
Input data can accumulate in STREAMS buffers very quickly. For example, by default it will accumulate at 8000 bytes per second for 8-bit, 8 KHz, mono, mu-Law data (as in the Greek letter mu). If the device is configured for 16-bit linear or higher sample rates, it will accumulate even faster. If the application that consumes the data cannot keep up with this data rate, the STREAMS queue may become full. When this occurs, the record.error flag is set in the audio information structure and input sampling ceases until there is room in the input queue for additional data. In such cases, the input data stream contains a discontinuity. For this reason, audio recording applications should open the audio device when they are prepared to begin reading data, rather than at the start of extensive initialization.
The write() system call copies data from an applications buffer to the STREAMS output queue. Ordinarily, write() blocks until the entire user buffer is transferred. The device may alternatively be set to a non-blocking mode, in which case write() completes immediately, but may have transferred fewer bytes than requested (see write(2)).
Although write() returns when the data is successfully queued, the actual completion of audio output may take considerably longer. The AUDIO_DRAIN ioctl may be issued to allow an application to block until all of the queued output data has been played. Alternatively, a process may request asynchronous notification of output completion by writing a zero-length buffer (end-of-file record) to the output stream. When such a buffer has been processed, the play.eof flag in the audio information structure (see below) is incremented.
The final close(2) of the file descriptor hangs until audio output has drained. If a signal interrupts the close() , or if the process exits without closing the device, any remaining data queued for audio output is flushed and the device is closed immediately.
The conversion of output data may be paused (or resumed) by using the AUDIO_SETINFO ioctl to set (or clear) the play.pause flag in the audio information structure. Queued output data may be discarded by using the I_FLUSH STREAMS ioctl.
Output data will be played from the STREAMS buffers at a default rate of 8000 bytes per second for mu-Law (as in the Greek letter mu) or A-Law data (faster for 16-bit linear data or higher sampling rates). If the output queue becomes empty, the play.error flag is set in the audio information structure and output is stopped until additional data is written. If an application attempts to write a number of bytes that is not a multiple of the current sample frame size, an error will be generated and the data will be thrown away. However, additional writes are allowed.
The I_SETSIG STREAMS ioctl enables asynchronous notification,
through the SIGPOLL
signal, of
input and output ready conditions. The O_NONBLOCK flag may be set using the F_SETFL fcntl(2)
to enable non-blocking read() and write()
requests. This is normally sufficient for applications to maintain an audio
stream in the background.
It is sometimes convenient to have an application, such as a volume control panel, modify certain characteristics of the audio device while it is being used by an unrelated process. The /dev/audioctl pseudo-device is provided for this purpose. Any number of processes may open /dev/audioctl simultaneously. However, read() and write() system calls are ignored by /dev/audioctl.
Note: The audio control device name is constructed by appending the letters "ctl" to the path name of the audio device.
Applications that open the audio control pseudo-device may request
asynchronous notification of changes in the state of the audio device by
setting the S_MSG flag in an I_SETSIG STREAMS ioctl. Such processes receive a SIGPOLL
signal when any of the following events
occur:
An AUDIO_SETINFO, AUDIO_MIXERCTL_SETINFO, AUDIO_MIXERCTL_SET_CHINFO, or AUDIO_MIXERCTL_SET_MODE ioctl () has altered the device state.
An input overflow or output underflow has occurred.
An end-of-file record (zero-length buffer) has been processed on output.
An open() or close() of /dev/audio has altered the device state.
An external event (such as speakerbox volume control) has altered the device state.
The audio mixer implements all the ioctl()s defined in audio(7I) and uses the audio_prinfo_t, audio_info_t, and the audio_device_t structures. See audio(7I) for details on these ioctl()s and structures. It also uses two new data structures, defined here.
See audio_support(7I) for a list of ioctls which are common to all audio devices.
typedef struct am_control { audio_info_t dev_info; /* the audio device's state */ int8_t ch_open[1]; /* variable sized array of open chs */ } am_control_t;
See CODE EXAMPLES for example code on how to use this structure and the related macro, AUDIO_MIXER_CTL_STRUCT_SIZE(num_ch).
The following structure is used by the AUDIO_MIXER_GET_SAMPLE_RATES ioctl to get a list of all the supported sample rates.
typedef struct am_sample_rates { uint_t type; /* play or capture */ uint_t flags; uint_t num_samp_rates; /* number of elements in samp_rates[] */ uint_t samp_rates[1]; /* variable sized array of sample rates */ } am_sample_rates_t; #define AUDIO_PLAY 0 /* type */ #define AUDIO_RECORD 1 #define MIXER_SR_LIMITS 0x00000001 /* flags */
See CODE EXAMPLES for example code on how to use this structure and the related macro, AUDIO_MIXER_SAMP_RATES_STRUCT_SIZE(num_srs).
When in mixer mode the audio_info_t structure's sw_features_enabled field will have AM_MIXER set. When in compatibility mode the AM_MIXER bit will be cleared.
The following are the defines for the sw_features and the sw_features_enabled fields.
#define AM_MIXER 0x00000001 /* mixer is present/enabled */
All of the streamio(7I) ioctl commands may be issued for the /dev/audio and /dev/audioctl devices. I_SETSIG ioctl may be issued for /dev/audioctl to enable the notification of audio status changes, as described above.
Except for AUDIO_MIXER_GET_SAMPLE_RATE, AUDIO_MIXERCTL_GET_MODE, and AUDIO_MIXERCTL_SET_MODE, these ioctl()s are valid only in mixer mode. Using them in compatible mode will cause an EINVAL error to be returned.
The argument is ignored. This command allows an individual process to open /dev/audio more then once for play or record. This feature is useful for mixing panels that may be controlling multiple audio streams.
The argument is ignored. This command returns /dev/audio back into an exclusive access device on per process basis after an AUDIO_MIXER_MULTIPLE_OPEN ioctl() has been executed. This ioctl() will fail if more than one play or record stream is open.
The argument is a pointer to an am_sample_rates_t structure. This command gets a list of supported sample rates for either play or capture for the mode the audio mixer is in. It is legal for the supported sample rates to be different for mixer mode vs compatible mode. The type field must be set to either AUDIO_PLAY or AUDIO_RECORD to get a list of either play or capture sample rates, respectively. Setting both is an error. The num_samp_rates field is set to the number of sample rates that the samp_rates[] array may hold. When the ioctl returns, num_samp_rates will be set either to the number of sample rates in the array samp_rates[], or the total number of sample rates available if more then the array can hold. In the former case there are num_samp_rates valid sample rates in the array. In the later case all the elements of the array have valid sample rates, but there are more available. The size of the array should be increased to get all available sample rates. If the flags field has MIXER_SR_LIMITS flag set then the return sample rates are the lowest and the highest sample rate possible, with all sample rates in between being legal. Some Codecs that have DSP engines on them have this capability.
The argument is a pointer to a am_control_t structure. This command gets device and channel state information. The dev_info field contains the state of the hardware device. It provides a convenient way to determine the hardware's state. The ch_open array is used to specify which channels are open and which are closed. Open channels are non-zero, while closed channels are set to zero, where the channel number corresponds to the array index. The number of elements in the ch_open array may change over time. Therefore a macro is provided to allocate the correct amount of space. Below is a code segment which shows how this should be done.
The argument is a pointer to a am_control_t structure. This command sets the device state, but cannot modify any channel's state. The dev_info field is used to set the device state. However, there are sever limitations. Only the gain, balance, port and pause for play and record and monitor_gain and output_muted may be modified. The other fields cannot be modified as this would interfere with how the audio mixer programs the audio device. The ch_open array is not used when setting the audio device and may be set to a size of one.
The argument is a pointer to an audio_channel_t structure. This command gets a channel's state information. The ch_number field must be set before making the ioctl() call in order for the audio mixer to determine which channel to get information on. When the ioctl() returns the pid field should be checked. If it is set to 0 the rest of the data in the audio_channel_t structure is invalid because the channel is not allocated. The dev_type field describes the type of channel and the info pointer points to a buffer where the audio_info_t structure for the audio channel is populated.
The argument is a pointer to an audio_channel_t structure. This command sets a channel's state information. The ch_number field must be set before making the ioctl() call in order for the to determine which channel to set. When the ioctl() returns the pid will contain the process ID of the process that has the channel open and dev_type will contain the type of the device. If pid is 0 (zero), then the channel is not open. The info pointer points to an audio_info_t structure, which is used to program the state of the channel.
The argument is a pointer to an integer that contains the audio mixer mode when it returns. It will be set to either AM_MIXER_MODE or AM_COMPAT_MODE.
The argument is a pointer to an integer that contains the audio mixer mode to be set and it must be set to either AM_MIXER_MODE or AM_COMPAT_MODE. The audio mixer may be set to mixer mode at any time. However, it may be set to compatible mode only when there is a single read/write open within one process, or a single read process and a single write process. Otherwise the ioctl() will fail. Because the Codec is being reprogrammed to a different data format, it is possible there may be brief pause or burst of noise when the mode changes. This is normal. It may be eliminated by pausing the input and output or by closing all streams before changing modes. The mixerctl(1) command may be used to change the audio mixer's mode.
The following macro is used to determine how large an am_control_t structure is when it points to an audio_info_t structure.
AUDIO_MIXER_CTL_STRUCT_SIZE(num_ch)
Where num_ch is the number of channels the device supports. The number of channels can be determined using the AUDIO_GET_NUM_CHS ioctl().
This macro is used when allocating an am_sample_rates_t structure.
AUDIO_MIXER_SAMP_RATES_STRUCT_SIZE(num_srs)
Where num_srs is the number of samples rates requested.
audio_channel_t ch; audio_info_t info; am_control_t *ctl; int num; err = ioctl(audio_fd, AUDIO_GET_NUM_CHS, &num); ctl = (am_control_t *)malloc(AUDIO_MIXER_CTL_STRUCT_SIZE(num)); err = ioctl(audio_fd, AUDIO_MIXERCTL_GETINFO, ctl); ch->info = &info; ch->info_size = sizeof (audio_info_t); for (i = 0; i < num; i++) { if (ctl->ch_open[i] != 0) { ch.ch_number = i; if (ioctl(audio_fd, AUDIO_MIXERCTL_GET_CHINFO, &ch) < 0) { printf(""Channel #%d isn't an audio/audioctl device, 1); } else { printf("Ch# %d, PID = %d, Type = %s\n", i, ch->pid, ch->type); } } }
The following code demonstrates how to use the AUDIO_MIXER_GET_SAMPLE_RATES ioctl to get the number of supported play sample rates. It also shows how to deal with allocating a samp_rates[] array that is too small
#define LARGE_NUMBER 10000; am_sample_rates_t *sr; int num; for (num = 4; num < LARGE_NUMBER; num += 2) { sr = (am_sample_rates_t *)malloc(AUDIO_MIXER_SAMP_RATES_STRUCT_SIZE(num)); sr->num_samp_rates = num; sr->type = AUDIO_PLAY; err = ioctl(audio_fd, AUDIO_MIXER_GET_SAMPLE_RATES, sr); if (sr->num_samp_rates <= num) { break; } free(sr); } (void) printf("Supported play sample rates:\n"); for (i = 0; i < sr->num_samp_rates; i++) { (void) printf(" %d\n", sr->samp_rates[i]); }
An open() will fail if:
The requested play or record access is busy and either the O_NDELAY or O_NONBLOCK flag was set in the open() request.
Memory was not available to be allocated for the channel.
The requested play or record access is busy and a signal interrupted the open() request.
There has been an error opening the device. An error message is printed on the console explaining the failure.
An ioctl() will fail if:
The parameter changes requested in the AUDIO_SETINFO ioctl could not be made because another process has the device open and is using a different format.
The ioctl() was interrupted by a signal.
The parameter changes requested in the AUDIO_SETINFO ioctl are invalid or are not supported by the device.
There has been an error with the ioctl(). An error message is printed on the console explaining the failure.
The ioctl() failed because memory couldn't be allocated.
The audio mixer is in compatible mode and one of the new ioctl()s was used. They are supported only in mixer mode.
The physical audio device names are system dependent and are rarely used by programmers. The programmer should use the generic device names listed below.
symbolic link to the system's primary audio device
symbolic link to the control device for /dev/audio
first audio device in the system
audio control device for /dev/sound/0
additional audio devices
audio control device for /dev/sound/x
See attributes(5) for a description of the following attributes:
ATTRIBUTE TYPE | ATTRIBUTE VALUE |
Architecture | SPARC |
Availability | SUNWaudd, SUNWauddx, SUNWaudh |
Stability Level | Evolving |
mixerctl(1), close(2), fcntl(2), ioctl(2), open(2), poll(2), read(2), write(2), system(4), audiocs(7D), audio_support(7I) streamio(7I)
Due to a feature of the STREAMS implementation, programs that are terminated or exit without
closing the audio device may hang for a short period
while audio output drains. In general, programs that produce audio output
should catch the SIGINT
signal
and flush the output stream before exiting.
NAME | SYNOPSIS | OVERVIEW | AUDIO FORMATS | DESCRIPTION | IOCTLS | MACROS | CODE EXAMPLES | ERRORS | FILES | ATTRIBUTES | SEE ALSO | BUGS