ALSA project - the C library reference

Loading...
Searching...
No Matches
Control interface

Control interface is designed to access primitive controls. There is also an interface for notifying about control and structure changes.

# General overview

In Alsa, there are physical sound cards, such as USB headsets, and virtual sound cards, such as "pulse", which represents the PulseAudio Sound system. Each sound card offers a control interface, making its settings (e.g. volume knobs) available. The complete list of available control interfaces can be obtained using snd_device_name_hint(), giving -1 as card index and "ctl" as interface type. Each returned NAME hint identifies a control interface.

Sound cards have an ID (a string), an index (an int, sometimes called the "card number"), a name, a longname, a mixername and a "components" property. The file /proc/asound/cards lists most of these properties for physical sound cards. Virtual sound cards are not listed in that file. The format is:

    index [ID     ] Driver - name
            longname

Note that the mixername and components are not listed.

## Identifying and Opening Control Interfaces

To work with a control interface, is must be opened first, using snd_ctl_open(). This function takes the interface name.

For physical sound cards, the control interface can be identified using the string "hw:<index>" (e.g. `hw:2`). The NAME hint - which is "hw:CARD=<ID>" - can also be used. Further, its device file (something like `/dev/snd/controlC0`) is also acceptable. Either of them can be given to snd_ctl_open().

For virtual sound cards, the NAME hint is given to snd_ctl_open().

The functions snd_card_get_index(), snd_card_get_name() and snd_card_get_longname() can be used to find an identifying property when another one is already known.

# Elements

In ALSA control feature, each sound card can have control elements. The elements are managed according to below model.

- Element set
  - A set of elements with the same attribute (i.e. name, get/put operations). Some element sets can be added to a sound card by drivers in kernel and userspace applications.
- Element
  - A control element might be a master volume control, for example, or a read-only indicator, such as a sync status. An element has a type (e.g. SNDRV_CTL_ELEM_TYPE_INTEGER or SNDRV_CTL_ELEM_TYPE_BOOLEAN) and - depending on the type - min/max values, a step size, a set of possible values (for enums), etc.
- Member
  - An element usually includes one or more member(s) to have a value. For example, a stereo volume control element has two members (for left/right), while a mono volume has only one member. The member count can be obtained using snd_ctl_elem_info_get_count(). Elements of type "SNDRV_CTL_ELEM_TYPE_BYTES" or "SNDRV_CTL_ELEM_TYPE_IEC958" have no members at all (and thus no member count), they have just a single value. The members share the same properties (e.g. both volume control members have the same min/max values). The value of each member can be changed by both of userspace applications and drivers in kernel.

## Identifying Elements

Each element has the following identifying properties:

- The numid (a numeric identifier, assigned when the sound card is detected, constant while the sound card is kept connected)
- The interface type (e.g. MIXER, CARD or PCM)
- The device
- The subdevice
- Its name
- Its index

An element can be identified either by its short numid or by the full set of fields (interface type, device, subdevice, name, index). This set of fields is always the same (driver updates can change it, but in practice this is rare). The numid can change on each boot. In case of an USB sound card, the numid can also change when it is reconnected. The short numid is used to reduce the lookup time.

## Element Lists

An element list can be used to obtain a list of all elements of the sound card. The list contains generic information (e.g. how many elements the card has), and the identifying properties of the elements (numid, card, name, ...). See snd_ctl_elem_list_t to learn more about element lists.

## Working with Elements

It is possible to obtain information about an element using the snd_ctl_elem_info_*() functions. For enums, the allowed values can be obtained, for integers, the min/max values can be obtained, and so on. In addition, these functions can report the identifying properties. E.g. when the element is addressed using its numid, the functions complements the name, index, etc.

To access the members (i.e. values) of a control, use the snd_ctl_elem_value*() functions. These allow to get and set the actual values or settings. It is also possible to get and set the ID values (such as the numid or the name).

## Element Sets

The type of element set is one of integer, integer64, boolean, enumerators, bytes and IEC958 structure. This indicates the type of value for each member in elements included in the element set.

# Events

When the value of a member is changed, corresponding events are transferred to userspace applications. The applications should subscribe any events in advance.

# Supplemental data for elements in an element set

TLV feature is designed to transfer data in a shape of Type/Length/Value, between a driver and any userspace applications. The main purpose is to attach supplement information for elements to an element set; e.g. dB range.

At first, this feature was implemented to add pre-defined data readable to userspace applications. Soon, it was extended to handle several operations; read, write and command. The original implementation remains as the read operation. The command operation allows drivers to have own implementations against requests from userspace applications.

This feature was introduced to ALSA control feature in 2006, at commit c7a0708a2362, corresponding to a series of work for Linux kernel (42750b04c5ba and 8aa9b586e420).

There's no limitation about maximum size of the data, therefore it can be used to deliver quite large arbitrary data from userspace to in-kernel drivers via ALSA control character device. Focusing on this nature, as of 2016, some in-kernel implementations utilize this feature for I/O operations. This is against the original design.