The use case configuration files use
Configuration files syntax to define the static configuration tree. This tree is evaluated (modified) at runtime according the conditions and dynamic variables in the configuration tree. The result is parsed and exported to the applications using
Use Case Interface API.
Configuration directory and main filename lookup
The lookup paths are describen in
ucm.conf file. The configuration structure looks like:
2 Directory "conf.virt.d"
3 File "${OpenName}.conf"
7 File "${OpenName}.conf"
UCM main configuration file
Each sound card has a master sound card file that lists all the supported use case verbs for that sound card. i.e.:
1 # Example master file for blah sound card
2 # By Joe Blogs <joe@bloggs.org>
6 # Use Case name for user interface
7 Comment "Nice Abstracted Soundcard"
9 # The file is divided into Use case sections. One section per use case verb.
11 SectionUseCase."Voice Call" {
12 File "voice_call_blah"
13 Comment "Make a voice phone call."
16 SectionUseCase."HiFi" {
18 Comment "Play and record HiFi quality Music."
21 # Since Syntax 8, you can also use Config to specify configuration inline
22 # instead of referencing an external file. Only one of File or Config can be used.
24 SectionUseCase."Inline Example" {
25 Comment "Example with inline configuration"
29 cset "name='Power Save' off"
32 cset "name='Power Save' on"
35 SectionDevice."Speaker" {
37 cset "name='Speaker Switch' on"
40 cset "name='Speaker Switch' off"
46 # Define Value defaults
53 # Define boot / initialization sequence
54 # This sequence is skipped, when the soundcard was already configured by system
55 # (alsactl configuration was already created). The purpose is to not alter
56 # ALSA card controls which may be modified by user after initial settings.
59 cset "name='Master Playback Switch',index=2 0,0"
60 cset "name='Master Playback Volume',index=2 25,25"
62 cset "name='Master Playback Switch',index=2 1,1"
63 cset "name='Master Playback Volume',index=2 50,50"
66 # Define fixed boot sequence
67 # This sequence is always executed on boot (hotplug).
70 cset "name='Something to toggle' toggle"
UCM verb configuration file
The verb configuration file defines devices, modifier and initialization sequences. It is something like a sound profile.
1 # Example Use case verb section for Voice call blah
2 # By Joe Blogs <joe@blogs.com>
8 # enable and disable sequences are compulsory
10 disdevall "" # run DisableSequence for all devices
14 cset "name='Power Save' on"
17 # Optional transition verb
18 TransitionSequence."ToCaseName" [
19 disdevall "" # run DisableSequence for all devices
23 # Optional TQ and device values
30 # Each device is described in new section. N devices are allowed
32 SectionDevice."Headphones" {
54 TransitionSequence."ToDevice" [
59 PlaybackVolume "name='Master Playback Volume',index=2"
60 PlaybackSwitch "name='Master Playback Switch',index=2"
61 PlaybackPCM "hw:${CardId},4"
65 # Each modifier is described in new section. N modifiers are allowed
67 SectionModifier."Capture Voice" {
68 Comment "Record voice call"
90 TransitionSequence."ToModifierName" [
94 # Optional TQ and ALSA PCMs
97 CapturePCM "hw:${CardId},11"
98 PlaybackMixerElem "Master"
99 PlaybackVolume "name='Master Playback Volume',index=2"
100 PlaybackSwitch "name='Master Playback Switch',index=2"
Sequence graphs
Sequence commands
| Command name | Description |
| enadev2 ARG | execute device enable sequence |
| disdev2 ARG | execute device disable sequence |
| disdevall "" | execute device disable sequence for all devices in verb |
| cdev ARG | ALSA control device name for snd_ctl_open() |
| cset ARG | ALSA control set - snd_ctl_ascii_elem_id_parse() + snd_ctl_ascii_value_parse() |
| cset-new ARG | Create new ALSA user control element - snd_ctl_ascii_elem_id_parse() + description |
| ctl-remove ARG | Remove ALSA user control element - snd_ctl_ascii_elem_id_parse() |
| sysw ARG | write to sysfs tree |
| usleep ARG | sleep for specified amount of microseconds |
| msleep ARG | sleep for specified amount of milliseconds |
| exec ARG | execute a specific command (without shell - man execv) |
| shell ARG | execute a specific command (using shell - man system) |
| cfg-save ARG | save LibraryConfig to a file |
2 cset "name='PCM Playback Volue',index=2 99"
3 cset-new "name='Bool2' type=bool,count=2 1,0"
4 cset-new "name='Enum' type=enum,labels='L1;L2;L3' 'L2'"
5 ctl-remove "name='Bool2'"
6 sysw "-/class/sound/ctl-led/speaker/card${CardNumber}/attach:Speaker Channel Switch"
10 cfg-save "/tmp/test.conf:+pcm"
Naming (devices, verbs)
See the SND_USE_CASE_VERB constains like
SND_USE_CASE_VERB_HIFI for the full list of known verbs.See the SND_USE_CASE_DEV constants like
SND_USE_CASE_DEV_SPEAKER for the full list of known devices. If multiple devices with the same name exists, the number suffixes should be added to these names like HDMI1,HDMI2,HDMI3 etc. No number gaps are allowed. The names with numbers must be continuous. It is allowed to put a whitespace between name and index (like 'Line 1') for the better readability. The device names 'Line 1' and 'Line1' are equal for this purpose.
Automatic device index assignment (Syntax 8+)
Starting with
Syntax 8, device names can include a colon (':') character to enable automatic device index assignment. When a device name contains a colon, the UCM parser will automatically assign an available numeric index and remove everything after and including the colon character.The automatic assignment ensures that the generated device name is unique within the verb by finding the first available index starting from 1. If a name conflict is detected, the index is automatically incremented until a unique name is found (up to index 99).This feature is particularly useful for dynamically creating multiple instances of similar devices without manually managing index numbers. The text after the colon is required and serves as a descriptive identifier in the source configuration to help distinguish between devices, but is not part of the final device name.Example - Automatic HDMI device indexing:
1 SectionDevice."HDMI:primary" {
2 Comment "First HDMI output (will become HDMI1)"
4 cset "name='HDMI Switch' on"
7 PlaybackPCM "hw:${CardId},3"
11 SectionDevice."HDMI:secondary" {
12 Comment "Second HDMI output (will become HDMI2)"
14 cset "name='HDMI2 Switch' on"
17 PlaybackPCM "hw:${CardId},7"
Example - Automatic Line device indexing with descriptive identifiers:
1 SectionDevice."Line:front" {
2 Comment "Front line input (will become Line1)"
4 cset "name='Front Line In Switch' on"
7 CapturePCM "hw:${CardId},0"
11 SectionDevice."Line:rear" {
12 Comment "Rear line input (will become Line2)"
14 cset "name='Rear Line In Switch' on"
17 CapturePCM "hw:${CardId},1"
Example - Mixed manual and automatic indexing:
1 # Manually named device
2 SectionDevice."Speaker" {
3 Comment "Main speaker output"
5 cset "name='Speaker Switch' on"
9 # Auto-indexed devices with descriptive identifiers
10 SectionDevice."Mic:digital" {
11 Comment "Digital microphone (will become Mic1)"
13 cset "name='Digital Mic Switch' on"
16 CapturePCM "hw:${CardId},2"
20 SectionDevice."Mic:headphone" {
21 Comment "Headphone microphone (will become Mic2)"
23 cset "name='Headphone Mic Switch' on"
26 CapturePCM "hw:${CardId},3"
If EnableSequence/DisableSequence controls independent paths in the hardware it is also recommended to split playback and capture UCM devices and use the number suffixes. Example use case: Use the integrated microphone in the laptop instead the microphone in headphones.The preference of the devices is determined by the priority value (higher value = higher priority).
Device ordering (Syntax 8+)
Starting with
Syntax 8, devices are automatically sorted based on their priority values. The sorting is performed at the end of device management processing, after device renaming and index assignment.The priority key selection order is:
- Priority - If this value exists, use it as the sorting key
- PlaybackPriority - If Priority doesn't exist but PlaybackPriority exists, use it
- CapturePriority - If neither Priority nor PlaybackPriority exist, use CapturePriority
- Fallback - If no priority value is defined, use the device name for alphabetical sorting
Devices are sorted in
descending order of priority (higher priority values appear first in the device list). When two devices have the same priority value, they are sorted alphabetically by device name.Example - Device priority ordering:
1 SectionDevice."Speaker" {
2 Comment "Internal speaker"
4 cset "name='Speaker Switch' on"
8 PlaybackPCM "hw:${CardId},0"
12 SectionDevice."Headphones" {
13 Comment "Headphone jack"
15 cset "name='Headphone Switch' on"
19 PlaybackPCM "hw:${CardId},1"
23 SectionDevice."HDMI" {
26 cset "name='HDMI Switch' on"
30 PlaybackPCM "hw:${CardId},3"
In this example, the device list will be ordered as: Headphones (200), HDMI (150), Speaker (100).See the SND_USE_CASE_MOD constants like
SND_USE_CASE_MOD_ECHO_REF for the full list of known modifiers.
Boot (alsactl)
The
FixedBootSequence is executed at each boot. The
BootSequence is executed only if the card's configuration is missing. The purpose is to let the users modify the configuration like volumes or switches. The alsactl ensures the persistency (store the state of the controls to the /var tree and loads the previous state in the next boot).
Boot Synchronization (Syntax 8+)
The
BootCardGroup value in
ValueGlobals allows multiple sound cards to coordinate their boot sequences. This value is detected at boot (alsactl/udev/systemd) time. Boot tools can provide boot synchronization information through a control element named 'Boot' with 64-bit integer type. When present, the UCM library uses this control element to coordinate initialization timing.The 'Boot' control element contains:
- index 0: Boot time in CLOCK_MONOTONIC_RAW (seconds)
- index 1: Restore time in CLOCK_MONOTONIC_RAW (seconds)
- index 2: Primary card number (identifies also group)
The UCM open call waits until the boot timeout has passed or until restore state is notified through the synchronization Boot element. The timeout defaults to 30 seconds and can be customized using 'BootCardSyncTime' in 'ValueGlobals' (maximum 240 seconds).If the 'Boot' control element is not present, no boot synchronization is performed.Other cards in the group (primary card number is different) will have the "Linked" value set to "1", allowing UCM configuration files to detect and handle secondary cards appropriately.Example configuration:
2 BootCardGroup "amd-acp"
3 BootCardSyncTime 10 # seconds
Device volume
It is expected that the applications handle the volume settings. It is not recommended to set the fixed values for the volume settings in the Enable / Disable sequences for verbs or devices, if the device exports the hardware volume (MixerElem or Volume/Switch values). The default volume settings should be set in the
BootSequence. The purpose for this scheme is to allow users to override defaults using the alsactl sound card state management.Checklist:
- Set default volume in BootSequence
- Verb's EnableSequence should ensure that all devices are turned off (mixer paths) to avoid simultaneous device use - the previous state is unknown (see disdevall and disdev2 commands or create a new custom command sequence)
Dynamic configuration tree
The evaluation order may look a bit different from the user perspective. At first, the standard alsa-lib configuration tree is parsed. All other layers on top are working with this tree. It may shift / move the configuration blocks from the configuration files as they are placed to the tree internally.
1 Example configuration | Parsed static tree | Identical static tree
2 ----------------------------+-------------------------+-------------------------------
3 If.1 { | If { | If.1.True.Define.VAR "A"
4 True.Define.VAR "A" | 1.True.Define.VAR "A" | If.2.True.Define.VAR "C"
5 } | 2.True.Define.VAR "C" | Define.VAR "B"
7 If.2 { | Define.VAR "B" |
8 True.Define.VAR "C" | |
Even if one or both conditions are evaluated as true, the variable
VAR will be evaluated always as
B because the first
If block was before the non-nested
Define . The second
If block was appended to the first
If block (before
Define in the configuration tree) in the text configuration parser.
Syntax
Unless described, the syntax version 4 is used.
Include
There are two ways to include other configuration files.
Static include
The static include is inherited from the standard alsa-lib configuration syntax. It can be placed anywhere in the configuration files. The search path is composed from the root alsa configuration path (usually _/usr/share/alsa_) and
ucm2 directory.
1 <some/path/file.conf> # include file using the search path
2 </absolute/path/file.conf> # include file using the absolute path
Lazy include
The lazy include is evaluated at runtime. The root path is the ucm2 tree. The absolute include appends the ucm2 absolute path to the specified path. The relative include is relative to the file which contains the
Include configuration block.
1 Include.id1.File "/some/path/file.conf" # absolute include (in the ucm2 tree)
2 Include.id2.File "subdir/file.conf" # relative include to the current configuration directory (UseCasePath)
Configuration tree evaluation
The evaluation of the static configuration tree is proceed in the specific order (see table bellow). When the dynamic configuration tree changes, the evaluation sequence is restarted to evaluate all possible changes (new
Define or
Include or
If blocks).
| Evaluation order | Configuration block | Evaluation restart |
| 1 | Define | No |
| 2 | Include | Yes |
| 3 | Variant | Yes |
| 4 | Macro | Yes |
| 5 | Repeat | Yes |
| 6 | If | Yes |
Substitutions
The dynamic tree identifiers and assigned values in the configuration tree are substituted. The substitutes strings are in the table bellow.
| Substituted string | Value |
| ${LibCaps} | Library capabilities (string like 'a*b*c') [Syntax 8] |
| ${OpenName} | Original UCM card name (passed to snd_use_case_mgr_open()) |
| ${ConfLibDir} | Library top-level configuration directory (e.g. /usr/share/alsa) |
| ${ConfTopDir} | Top-level UCM configuration directory (e.g. /usr/share/alsa/ucm2) |
| ${ConfDir} | Card's UCM configuration directory (e.g. /usr/share/alsa/ucm2/conf.d/USB-Audio) |
| ${ConfName} | Configuration name (e.g. USB-Audio.conf) |
| ${CardNumber} | Real ALSA card number (or empty string for the virtual UCM card) |
| ${CardId} | ALSA card identifier (see snd_ctl_card_info_get_id()) |
| ${CardDriver} | ALSA card driver (see snd_ctl_card_info_get_driver()) |
| ${CardName} | ALSA card name (see snd_ctl_card_info_get_name()) |
| ${CardLongName} | ALSA card long name (see snd_ctl_card_info_get_longname()) |
| ${CardComponents} | ALSA card components (see snd_ctl_card_info_get_components()) |
| ${env:<str>} | Environment variable <str> |
| ${sys:<str>} | Contents of sysfs file <str> |
| ${sys-card:<str>} | Contents of sysfs file in /sys/class/sound/card? tree [Syntax 8] |
| ${var:<str>} | UCM parser variable (set using a Define block) |
| ${eval:<str>} | Evaluate expression like *($var+2)/3* [Syntax 5] |
| ${find-card:<str>} | Find a card - see Find card substitution section |
| ${find-device:<str>} | Find a device - see Find device substitution section |
| ${info-card:<str>} | Get card information - see Card info substitution section [Syntax 9] |
General note: If two dollars '$$' instead one dolar '$' are used for the substitution identification, the error is ignored (e.g. file does not exists in sysfs tree).Note for var substitution: If the first characters is minus ('-') the empty string is substituted when the variable is not defined.Note for sys and sys-card substitutions: since syntax 8, there is also extension to fetch data from given range with the optional conversion to hexadecimal format when the source file has binary contents.Example - fetch bytes from positions 0x10..0x15 (6 bytes):
1 Define.Bytes1 "${sys-card:[type=hex,pos=0x10,size=6]device/../descriptors}"
Example - fetch one byte from position 0x22:
1 Define.Bytes2 "${sys-card:[type=hex,pos=0x22]device/../descriptors}"
Replace
type=hex with
type=ascii or omit this variable settings to work with ASCII characters.
Library capabilities
None at the moment. The list will grow after
Syntax 8 (library 1.2.14).
Special whole string substitution
| Substituted string | Value |
| ${evali:<str>} | Evaluate expression like *($var+2)/3* [Syntax 6]; target node will be integer; substituted only in the LibraryConfig subtree |
Find card substitution
This substitutions finds the ALSA card and returns the appropriate identifier or the card number (see return argument).Usage example:
1 ${find-card:field=name,regex='^acp$',return=number}
2 ${find-card:field=$FieldName,regex=$Pattern,return=number}
Arguments:
| Argument | Description |
| return | return value type (id, number), id is the default |
| field | field for the lookup (id, driver, name, longname, mixername, components) or variable name ($var) [Syntax 9] |
| regex | regex string for the field match or variable name ($var) [Syntax 9] |
Find device substitution
Usage example:
1 ${find-device:type=pcm,field=name,regex='DMIC'}
2 ${find-device:type=$DevType,stream=$StreamType,field=$FieldName,regex=$Pattern}
Arguments:
| Argument | Description |
| type | device type (pcm) or variable name ($var) [Syntax 9] |
| stream | stream type (playback, capture), playback is default; variable name ($var) supported in Syntax 9 |
| field | field for the lookup (id, name, subname) or variable name ($var) [Syntax 9] |
| regex | regex string for the field match or variable name ($var) [Syntax 9] |
Card info substitution
This substitution retrieves information about a specific ALSA card by card number or card ID and returns the requested field value.Usage examples:
1 ${info-card:card=0,field=name}
2 ${info-card:card=acp,field=driver}
3 ${info-card:card=PCH,field=longname}
4 ${info-card:card=$MyCard,field=$MyField}
Arguments:
| Argument | Description |
| card | card number (integer), card ID (string), or variable name ($var) |
| field | field to retrieve (number, id, driver, name, longname, mixername, components) or variable name ($var) |
The card parameter can be either a card number (e.g., 0, 1, 2), a card ID string (e.g., "PCH", "acp", "Intel"), or a variable name prefixed with $ (e.g., $CardId).The field parameter specifies which card information to return or can be a variable name prefixed with $ (e.g., $FieldName):
- number: Card number (integer as string)
- id: Card identifier
- driver: Card driver name
- name: Card short name
- longname: Card long name
- mixername: Mixer name
- components: Card components
Variable defines
The variables can be defined and altered with the
Define or
DefineRegex blocks. The
Define block looks like:
The
DefineRegex allows substring extraction using regular expressions (POSIX extended regex). It can match patterns in strings and extract matched substrings into UCM variables.
DefineRegex Structure
2 String "text to match against"
| Field | Description |
| String | The input string to match the regex pattern against |
| Regex | POSIX extended regular expression pattern |
| Flags | Optional regex flags (see below) |
| Scheme | Matching scheme: "first" (default) or "all" [Syntax 9] |
Regex Flags
The Flags field is optional and accepts the following characters:
| Flag | Description |
| e | Extended POSIX regex (REG_EXTENDED) - default recommended |
| i | Case-insensitive matching (REG_ICASE) |
| s | Report only success/fail (REG_NOSUB) |
| n | Newline-sensitive matching (REG_NEWLINE) |
Multiple flags can be combined, e.g., "ei" for extended and case-insensitive.
Matching Schemes
Scheme "first"** (default): Matches the pattern once and extracts capture groupsThe variables created are:
name - the full matched string
name1 - first capture group (parentheses in regex)
name2 - second capture group
nameN - Nth capture group
Example with "first" scheme:
3 Regex "hw:([0-9]+),([0-9]+)"
This creates variables:
The variables created are:
nameN - Nth full match (N starts at 1)
nameN_1 - Nth match, first capture group
nameN_2 - Nth match, second capture group
nameN_M - Nth match, Mth capture group
Example with "all" scheme:
2 String "device1 device2 device3"
This creates variables:
devices1 = "device1" (first full match)
devices1_1 = "1" (first match, capture group 1)
devices2 = "device2" (second full match)
devices2_1 = "2" (second match, capture group 1)
devices3 = "device3" (third full match)
devices3_1 = "3" (third match, capture group 1)
Practical Examples
Extract USB device vendor and product IDs:
2 String "${sys:bus/usb/devices/1-1/uevent}"
3 Regex "PRODUCT=([0-9a-f]+)/([0-9a-f]+)"
7 # Creates: usbids (full match), usbids1 (vendor), usbids2 (product)
Parse multiple key=value pairs:
2 String "rate=48000,channels=2,format=S16_LE"
3 Regex "([a-z]+)=([^,]+)"
7 # Creates: params1="rate=48000", params1_1="rate", params1_2="48000"
8 # params2="channels=2", params2_1="channels", params2_2="2"
9 # params3="format=S16_LE", params3_1="format", params3_2="S16_LE"
Extract text components:
2 String "USB Audio Device Model XYZ123"
3 Regex "([A-Z]+).*Model ([A-Z0-9]+)"
7 # Creates: model (full match), model1="USB", model2="XYZ123"
Variables can be substituted using
${var:name} reference. For example, to use the extracted card number:
PlaybackPCM "hw:${var:hwdev1},0"Macros
Macros were added for
Syntax version
6. The
DefineMacro defines new macro like:
2 Define.a "${var:__arg1}"
3 Define.b "${var:__other}"
4 # Device or any other block may be defined here...
The arguments in the macro are refered as the variables with the double underscore name prefix (like *__variable*). The configuration block in the DefineMacro subtree is always evaluated (including arguments and variables) at the time of the instantiation. Argument string substitutions (for multiple macro call levels) were added in
Syntax version
7.The macros can be instantiated (expanded) using:
2 Macro.id1.macro1 "arg1='something 1',other='other x'"
The second identifier (in example as
id1) must be unique, but the contents is ignored. It just differentiate the items in the subtree (allowing multiple instances for one macro).
Conditions
The configuration tree evaluation supports the conditions -
If blocks. Each
If blocks must define a
Condition block and
True or
False blocks or both. The
True or
False blocks will be merged to the parent tree (where the
If block is defined) when the
Condition is evaluated.Starting with
Syntax version
8,
If blocks can also include
Prepend and
Append configuration blocks. These blocks are always merged to the parent tree, independent of the condition evaluation result:
- Prepend block is merged before the condition result (True or False block)
- Append block is merged after the condition result (True or False block)
- Both Prepend and Append can be specified simultaneously
- When Prepend or Append is present, the Condition directive can be omitted
Example:
Example with Prepend and Append (
Syntax version
8+):
3 Define.before "prepended"
9 Define.middle "conditional"
12 Define.after "appended"
Example with Prepend/Append only (no Condition,
Syntax version
8+):
3 Define.x "always executed"
6 Define.y "also always executed"
True (Type AlwaysTrue)
Execute only
True block. It may be used to change the evaluation order as explained in the
Configuration Tree paragraph.
String is empty (Type String)
| Field | Description |
| Empty | string |
Strings are equal (Type String)
| Field | Description |
| String1 | string |
| String2 | substring in string |
Substring is present (Type String)
| Field | Description |
| Haystack | string |
| Needle | substring in string |
Regex match (Type RegexMatch)
| Field | Description |
| String | string |
| Regex | regex expression (extended posix, ignore case) |
Path is present (Type Path)
| Field | Description |
| Path | path (filename) |
| Mode | exist,read,write,exec |
Note: Substitution for Path and Mode fields were added in Syntax version 7.
ALSA control element exists (Type ControlExists)
Example:
4 Control "name='Front Mic Playback Switch'"
Integer comparison (Type Integer)
| Field | Description |
| Operation | comparison operator (==, !=, <, >, <=, >=) |
| Value1 | first integer value (string converted to long long) |
| Value2 | second integer value (string converted to long long) |
Note: Integer condition is supported in Syntax version 9+.Example:
5 Value1 "${var:channels}"
Variants
To avoid duplication of the many configuration files for the cases with minimal configuration changes, there is the variant extension. Variants were added for
Syntax version
6.The bellow example will create two verbs - "HiFi" and "HiFi 7.1" with the different playback channels (2 and 8) for the "Speaker" device.Example (main configuration file):
1 SectionUseCase."HiFi" {
Example (verb configuration file - HiFi.conf):
1 SectionDevice."Speaker" {
5 Variant."HiFi 7+1".Value {
Device Variants
Starting with
Syntax 8, devices can define variants using the
DeviceVariant block. Device variants provide a convenient way to define multiple related devices with different configurations (such as different channel counts) in a single device definition.When a device name contains a colon (':') character and the device configuration includes DeviceVariant* blocks, the UCM parser handles variant configuration in two ways:
- Primary device configuration: If the text after the colon (variant label) matches a variant identifier in the DeviceVariant block, that variant's configuration is merged with the primary device configuration before parsing. This allows the primary device to inherit base configuration while overriding specific values from the variant.
- Additional variant devices: The UCM parser automatically creates multiple distinct UCM devices:
- The base device (with the name specified in the Device or SectionDevice block)
- One additional device for each DeviceVariant block
Each variant device name is constructed by combining the base device name with the variant identifier. Variant devices are automatically added to the base device's conflicting device list, since these configurations are mutually exclusive (e.g., you cannot use 2.0, 5.1, and 7.1 speaker configurations simultaneously).Example - Speaker with multiple channel configurations:
5 DeviceVariant."5.1".Value {
8 DeviceVariant."7.1".Value {
This configuration creates three UCM devices:
- Speaker:2.0 - 2 playback channels (base device)
- Speaker:5.1 - 6 playback channels (variant)
- Speaker:7.1 - 8 playback channels (variant)
The variant devices (
Speaker:5.1 and
Speaker:7.1) inherit all configuration from the base device and override only the values specified in their
DeviceVariant block. The devices are automatically marked as conflicting with each other.Example - HDMI output with different sample rates:
1 SectionDevice."HDMI:LowRate" {
2 Comment "HDMI output - standard rate"
4 cset "name='HDMI Switch' on"
7 PlaybackPCM "hw:${CardId},3"
10 DeviceVariant."HighRate" {
11 Comment "HDMI output - high sample rate"
This creates two devices:
HDMI:LowRate (48kHz) and
HDMI:HighRate (192kHz).
Repetitive Pattern Substitution
Starting with
Syntax 9, the UCM configuration supports the
Repeat block for generating repetitive configuration patterns. This feature allows you to apply a configuration block multiple times with different variable values, reducing duplication in configuration files.The
Repeat block contains two main components:
- Pattern: Defines the iteration pattern (how many times to repeat and what values to use)
- Apply: The configuration block to be applied on each iteration
Pattern Types
The
Pattern block supports two types:
Integer and
Array.Integer Pattern**: Iterates over a range of integer values
10 ... configuration using ${var:ChannelNum} ...
Fields for Integer pattern:
- Variable: Name of the variable to substitute (without ${var:} prefix)
- Type: Must be "Integer"
- First: Starting value (integer)
- Last: Ending value (integer)
- Step: Increment value (integer, default 1)
The iteration supports reverse order automatically when First is greater than Last.Array Pattern**: Iterates over a list of string values
12 ... configuration using ${var:DevName} ...
Fields for Array pattern:
- Variable: Name of the variable to substitute (without ${var:} prefix)
- Type: Must be "Array"
Array: A compound node containing string values to iterate over
String Pattern**: Pattern can also be specified as a string that will be parsed as a configuration block. This allows for dynamic pattern generation.
9 ... configuration using ${var:Index} ...
Complete Example
Example using Integer pattern to create multiple similar control settings:
10 cset "name='PCM Channel ${var:ch} Volume' 100%"
This generates 8 cset commands for channels 0 through 7.Example using Array pattern for different device configurations:
12 SectionDevice."${var:output}" {
13 Comment "${var:output} Output"
15 cset "name='${var:output} Switch' on"
This creates three SectionDevice blocks for Speaker, Headphones, and LineOut.