分类: LINUX
2012-01-07 10:25:00
Configuring ALSA
Configuration files
Configuration files serve to define ALSA devices. Without these definitions, you could not use any of the features of ALSA — play no sound, adjust no mixer, nada. Still, you do not need to write a configuration file to simply play and record sound. The "built-in" configuration file alsa.conf contains definitions of devices which allow that, and much more besides (see above). But if you have special requirements, or if you experience trouble, you might still want to add definitions of your own.
ALSA supports three tiers of configuration files. The first is alsa.conf, which is located in ALSA's data directory, usually /usr/share/alsa. This directory and its subdirectories may contain further configuration files which are sound card and plugin specific. They are included by alsa.conf depending on the sound cards present. The files in this directory are considered built-in and are not to be changed by the user or the system adminstrator.
The other two configuration files are also included by alsa.conf. The system-wide configuration is stored in /etc/asoundrc. Users can store their own configuration in the file .asoundrc in their home directory. All configuration files are parsed every time an ALSA device is opened. So changes take effect immediately, and it is not necessary to restart anything.
All configuration files share the same format, which is described in the next section.
Basic configuration file format
ALSA configuration files contain hierarchically structured parameter-value pairs. The top-level branches of the hierarchy correspond to the interfaces which ALSA offers. An interface consists of a set of ALSA API functions which allow to open a device, do whatever the interface is for, and close the device. The different interfaces have different purposes. For example, aplay and other players use the pcm interface, the program alsactl uses the ctl (control) interface, amixer uses the mixer interface, amidi the rawmidi interface and so on. (In fact most of them also use the ctl interface, at least for some features.) To create a device to be used by one of these programs, you have to define it for the corresponding interface.
The examples which I give will mostly concern the pcm interface, both because it is probably the most important and because I have almost exclusively messed around with it. (PCM stands for pulse code modulation and refers to digitised sound expressed as a stream of sample values.) Besides, the command aplay -L allows you to list all definitions in the pcm interface, which is a nice cross-check. Other interfaces are ctl (control, for controlling hardware mixers and other settings), seq (sequencer), hwdep (hardware dependent features), mixer (abstracted mixer control), and rawmidi (MIDI data I/O). The second level of the hierarchy consists of the names of ALSA devices which can be used with the particular interface in whose subtree they reside.
Let's have an example. Imagine you want to create an ALSA PCM device which accesses your first sound card and does format conversion as needed. (Ignore for now that you could do that with the device "plughw:0,0".) The plugin which handles automatic format conversion is the plug plugin. The new PCM device is created by putting the following lines into your asoundrc:
pcm.plug0 {
type plug
slave {
pcm "hw:0,0"
}
}
What this means is the following: There shall be a new device "plug0" accessible via the pcm interface. Data output on this device shall be handled by the plug plugin. The plugin uses as a slave the PCM device hw:0,0. This device definition was written in the way which is most common. However, ALSA allows some freedom in the syntax. For instance, it is allowed to put an equals sign between a parameters name and its value, and a comma or a semicolon between consecutive parameter assignments. So we could also have written:
pcm.plug0 = {
type= plug;
slave= {
pcm= "hw:0,0";
},
};
As you can see, the two compounds enclosed in curly braces are really the "values" of the parameter names preceding them, and our name for the new PCM device is a freely selectable parameter name. Even the last parameter assignment in a compound may be followed by a comma or semicolon. It should now also be clear why the slace PCM device had to be enclosed in quotes: Otherwise the comma would have been misinterpreted and led to an error message.
There are further freedoms in the syntax which we have not touched yet. It concerns compounds. The names of sub-parameters of compounds may be given either in a dot notation or in braces. The first notation was chosed above for the name of our new device, which is just a parameter in the compound pcm. The second was used for all its sub-parameters. Furthermore, the syntax of the configuration files is not line-oriented — line breaks can be inserted anywhere but are treated as white space. So the same device definition as above could also have been written in one of the two following forms:
pcm {
plug0 {
type plug slave { pcm "hw:0,0" }
}
}
or
pcm.plug0.type= plug; pcm.plug0.slave.pcm= "hw:0,0"
Now I have given you an idea of the structure of ALSA configuration files, let us have a word about the remaining basics. Parameter names seem to be made up of letters, numbers and underscores (I say this from trial and error, as it seems to be documented nowhere). Parameter values which contain characters other than letters, numbers and underscores should probably be quoted. Both parameter names and values are case sensitive. Comments in configuration files start with "#" and extend up to the end of the line. They seem to be allowed pretty much anywhere, even between a parameter's name and value.
Rather than giving the slave explicitly, we could have used a symbolic slave definition above. Then our definition of plug0 would have looked like this:
pcm_slave.slave0 {
pcm "hw:0,0"
}
pcm.plug0 {
type plug
slave slave0
}
This explicit slave definition looks pointless here, but it may have its use in some cases. One can restrict a device's hardware parameter space in the process of creating a slave, for instance to force playback on all available channels and with the maximum sampling rate. (Not that it makes any sense to force resampling by the plug plugin.) Then our slave definition would look like this:
pcm_slave.slave0 {
pcm "hw:0,0"
channels 6
rate 96000
}
If the same slave was used in multiple device definitions, one could save some typing by putting these restrictions into a separate slave definition instead of every slave compound.
Another simple feature of configuration files are aliases. They are simply a parameter assignment of an existing device name to the alias. Both are part of the same interface, and the interface name is not repeated in the value of the alias. (Please note that in some texts about the asoundrc, the word "alias" is used erroneously for any device definition.) An example with our plug0 device:
pcm.alias_plug0= plug0
(not pcm.alias_plug0= pcm.plug0) You cannot define aliases for ALSA devices with arguments (see below).
Now we have covered the basics, you might want to read the web pages here and here as well as the file pcm_plugins.html in the ALSA library's doxygen documentation (on the web here), which provide many examples.
Advanced configuration file features
Overriding parameters and parameter data types
If you have read other documents about the asoundrc, you may have learnt that you can redefine ALSA's default device with a line like the following:
pcm.!default { type hw card 0 }
You may also have read that the exclamation sign causes the previous definition of pcm.default to be overridden. This syntax can be used with any configuration file assignment. Let's have a closer look at it to see how ALSA's configuration really works. Normal assignments add a leaf (and, if needed, branches) to the tree structure which contains all parameters. If this leaf (parameter) already exists, its value will indeed be overwritten. So if you put the following in your asoundrc, the default sound card will be the second, not the first:
pcm.!default { type hw card 0 }
pcm.default.card 1
So what is the exclamation mark needed for? If you remove it from the first definition of default, you will receive an error message to the effect that default is not a compound. Obviously, parameters come in several data types, and that type cannot be changed by a mere assignment. By overriding a parameter with "!", you can change its type. (The data type is not to be confused with the "type" subparameter of a device definition.) The exclamation mark causes the parameter and all its sub-parameters to be removed before it is created anew. (So don't ever write something like "!pcm..." — this would presumably erase all definitions in the pcm interface.)
With a little experimentation, one can find out that aliases are in fact parameters of type string which contain as their value the name of the PCM device they refer to. pcm.default is defined as an alias in alsa.conf, necessitating the use of the exclamation mark if it is to be replaced by a compound definition.
Similarly to the exclamation mark, other prefix characters can be used to qualify a parameter assignment. A question mark causes an assignment to be ignored if a previous value for the same parameter exists. (If you try to assign a subparameter of something which is not a compound, such as pcm.default.?card without a previous forced redefinition of pcm.default, you will still get an error.) So the following:
pcm.?default { type hw card 1 }
defines the first device of the second sound card as the default device, but only if no default device has been defined previously (say, in a system-wide configuration file).
The remaining two prefix characters are + and –. Both require the assignment to respect the type of any earlier assignment/creation of the respective parameter. The plus sign prefix gives the default behaviour of creating a new parameter when necessary and can therefore be left out. The minus sign causes an error when trying to assign a parameter which did not previously exist.
Parametrised device definitions
In the section about plugins we have encountered a lot of ALSA devices which require arguments given after a colon following the device name and separated by commas. As I already mentioned above, these devices and the plugins behind them are actually quite different things, but devices can be viewed as wrappers round the plugins. In the basic configuration section we have defined a device using the plug plugin. The predefined devices we encountered in the plugin section differ from this simple device in that they are generic. The plughw device can be used for any sound card and (hardware) device, because one can give the card and device numbers as arguments after the colon. Though all parametrised devices are defined in alsa.conf and the ALSA documenation does not document their syntax, you can also define such devices of your own.
Let's have a look at an abbreviated form of the definition of the plughw device in alsa.conf:
plughw {
@args [ CARD DEV SUBDEV ]
@args.CARD {
type string
}
@args.DEV {
type integer
}
@args.SUBDEV {
type integer
}
type plug
slave.pcm {
type hw
card $CARD
device $DEV
subdevice $SUBDEV
}
}
The first line in the definition of the plughw compound is the declaration of its argument list. This is a data type which is new to us: an array. Its elements can also be assigned one by one:
plughw {
@args.0 CARD
@args.1 DEV
@args.2 SUBDEV
...
As in the assignment of compounds, an equals sign can optionally be inserted, both in the collective and the element assignment. The following lines in the definition of plughw define the data type of each argument. (Apparently the value of each array element now serves as the name of a subparameter, which is highly interesting from a formal languages point of view. ;) ) In the original definition of plughw, the compounds defining the arguments also contain default definitions which use the @func keyword to call certain functions. If you are interested in that, have a look at alsa.conf.
Then follows the actual definition of the new PCM device. It strongly resembles the definitions we have seen so far, except that the constant parameter values are replaced by arguments referenced by their name preceded by a dollar sign. To get an idea of the possibilities generic ALSA devices offer, you are encouraged to look at alsa.conf, where many are defined.
There are two ways to use such a generic device. Its arguments can be given either in sequence starting with the first, or in any order as assignments to the argument name. Both "hw:1,0" and "hw:DEV=0,CARD=1" refer to the first device on the second sound card. For reasons I do not entirely understand, a parametrised device is not allowed in all circumstances where a non-parametrised device would be. The following is legal:
pcm.hw0 { type hw card 0 device 0 }
pcm.alias0 hw0
But this is not:
pcm.alias0 "hw:0,0"
If you want to learn about yet more advanced features of the ALSA asoundrc, have a look at asoundrc.txt in the doc directory of the ALSA library sources. It says something there about servers and references to (possibly external) libraries which I have not taken the time to check out. Up to you.