xref: /third_party/alsa-lib/src/ucm/ucm_confdoc.h (revision d5ac70f0)
1/*
2 *  This library is free software; you can redistribute it and/or
3 *  modify it under the terms of the GNU Lesser General Public
4 *  License as published by the Free Software Foundation; either
5 *  version 2 of the License, or (at your option) any later version.
6 *
7 *  This library is distributed in the hope that it will be useful,
8 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
9 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
10 *  Lesser General Public License for more details.
11 *
12 *  You should have received a copy of the GNU Lesser General Public
13 *  License along with this library; if not, write to the Free Software
14 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
15 *
16 *  Support for the verb/device/modifier core logic and API,
17 *  command line tool and file parser was kindly sponsored by
18 *  Texas Instruments Inc.
19 *  Support for multiple active modifiers and devices,
20 *  transition sequences, multiple client access and user defined use
21 *  cases was kindly sponsored by Wolfson Microelectronics PLC.
22 *
23 *  Copyright (C) 2021 Red Hat Inc.
24 *  Authors: Jaroslav Kysela <perex@perex.cz>
25 */
26
27/**
28 *  \defgroup ucm_conf Use Case Configuration
29 *  The ALSA Use Case Configuration.
30 *  See \ref Usecase_conf page for more details.
31 *  \{
32 */
33
34/*! \page Usecase_conf ALSA Use Case Configuration
35
36The use case configuration files use \ref conf syntax to define the
37static configuration tree. This tree is evaluated (modified) at runtime
38according the conditions and dynamic variables in the configuration tree.
39The result is parsed and exported to the applications using \ref ucm API.
40
41### Configuration directory and main filename lookup
42
43The lookup paths are describen in *ucm.conf* file. The configuration
44structure looks like:
45
46~~~{.html}
47UseCasePath.path1 {
48  Directory "conf.virt.d"
49  File "${OpenName}.conf"
50}
51UseCasePath.path2 {
52  Directory "external"
53  File "${OpenName}.conf"
54}
55~~~
56
57### UCM main configuration file
58
59Each sound card has a master sound card file that lists all the supported
60use case verbs for that sound card. i.e.:
61
62~~~{.html}
63# Example master file for blah sound card
64# By Joe Blogs <joe@bloggs.org>
65
66Syntax 6
67
68# Use Case name for user interface
69Comment "Nice Abstracted Soundcard"
70
71# The file is divided into Use case sections. One section per use case verb.
72
73SectionUseCase."Voice Call" {
74  File "voice_call_blah"
75  Comment "Make a voice phone call."
76}
77
78SectionUseCase."HiFi" {
79  File "hifi_blah"
80  Comment "Play and record HiFi quality Music."
81}
82
83# Define Value defaults
84
85ValueDefaults {
86  PlaybackChannels 4
87  CaptureChannels 4
88}
89
90# Define boot / initialization sequence
91# This sequence is skipped, when the soundcard was already configured by system
92# (alsactl configuration was already created). The purpose is to not alter
93# ALSA card controls which may be modified by user after initial settings.
94
95BootSequence [
96  cset "name='Master Playback Switch',index=2 0,0"
97  cset "name='Master Playback Volume',index=2 25,25"
98  msleep 50
99  cset "name='Master Playback Switch',index=2 1,1"
100  cset "name='Master Playback Volume',index=2 50,50"
101]
102
103# Define fixed boot sequence
104# This sequence is always executed on boot (hotplug).
105
106FixedBootSequence [
107  cset "name='Something to toggle' toggle"
108]
109~~~
110
111### UCM verb configuration file
112
113The verb configuration file defines devices, modifier and initialization sequences.
114It is something like a sound profile.
115
116~~~{.html}
117# Example Use case verb section for Voice call blah
118# By Joe Blogs <joe@blogs.com>
119
120# verb global section
121
122SectionVerb {
123
124  # enable and disable sequences are compulsory
125  EnableSequence [
126    disdevall ""	# run DisableSequence for all devices
127  ]
128
129  DisableSequence [
130    cset "name='Power Save' on"
131  ]
132
133  # Optional transition verb
134  TransitionSequence."ToCaseName" [
135    disdevall ""	# run DisableSequence for all devices
136    msleep 1
137  ]
138
139  # Optional TQ and device values
140  Value {
141    TQ HiFi
142    PlaybackChannels 6
143  }
144}
145
146# Each device is described in new section. N devices are allowed
147
148SectionDevice."Headphones" {
149
150  SupportedDevice [
151    "x"
152    "y"
153  ]
154
155  # or (not both)
156
157  ConflictingDevice [
158    "x"
159    "y"
160  ]
161
162  EnableSequence [
163    ...
164  ]
165
166  DisableSequence [
167    ...
168  ]
169
170  TransitionSequence."ToDevice" [
171    ...
172  ]
173
174  Value {
175    PlaybackVolume "name='Master Playback Volume',index=2"
176    PlaybackSwitch "name='Master Playback Switch',index=2"
177    PlaybackPCM "hw:${CardId},4"
178  }
179}
180
181# Each modifier is described in new section. N modifiers are allowed
182
183SectionModifier."Capture Voice" {
184  Comment "Record voice call"
185
186  SupportedDevice [
187    "x"
188    "y"
189  ]
190
191  # or (not both)
192
193  ConflictingDevice [
194    "x"
195    "y"
196  ]
197
198  EnableSequence [
199    ...
200  ]
201
202  DisableSequence [
203    ...
204  ]
205
206  TransitionSequence."ToModifierName" [
207    ...
208  ]
209
210  # Optional TQ and ALSA PCMs
211  Value {
212    TQ Voice
213    CapturePCM "hw:${CardId},11"
214    PlaybackMixerElem "Master"
215    PlaybackVolume "name='Master Playback Volume',index=2"
216    PlaybackSwitch "name='Master Playback Switch',index=2"
217  }
218}
219~~~
220
221### Sequence graphs
222
223\image html ucm-seq-verb.svg
224\image html ucm-seq-device.svg
225
226### Sequence commands
227
228Command name   | Description
229---------------|----------------------------------------------
230enadev2 ARG    | execute device enable sequence
231disdev2 ARG    | execute device disable sequence
232disdevall ""   | execute device disable sequence for all devices in verb
233cdev ARG       | ALSA control device name for snd_ctl_open()
234cset ARG       | ALSA control set - snd_ctl_ascii_elem_id_parse() + snd_ctl_ascii_value_parse()
235cset-new ARG   | Create new ALSA user control element - snd_ctl_ascii_elem_id_parse() + description
236ctl-remove ARG | Remove ALSA user control element - snd_ctl_ascii_elem_id_parse()
237sysw ARG       | write to sysfs tree
238usleep ARG     | sleep for specified amount of microseconds
239msleep ARG     | sleep for specified amount of milliseconds
240exec ARG       | execute a specific command (without shell - *man execv*)
241shell ARG      | execute a specific command (using shell - *man system*)
242cfg-save ARG   | save LibraryConfig to a file
243
244~~~{.html}
245# Examples
246cset "name='PCM Playback Volue',index=2 99"
247cset-new "name='Bool2' type=bool,count=2 1,0"
248cset-new "name='Enum' type=enum,labels='L1;L2;L3' 'L2'"
249ctl-remove "name='Bool2'"
250sysw "-/class/sound/ctl-led/speaker/card${CardNumber}/attach:Speaker Channel Switch"
251usleep 10
252exec "/bin/echo hello"
253shell "set"
254cfg-save "/tmp/test.conf:+pcm"
255~~~
256
257### Naming (devices, verbs)
258
259See the SND_USE_CASE_VERB constains like #SND_USE_CASE_VERB_HIFI for the full list of known verbs.
260
261See the SND_USE_CASE_DEV constants like #SND_USE_CASE_DEV_SPEAKER for the full list of known devices.
262If multiple devices with the same name exists, the number suffixes should
263be added to these names like HDMI1,HDMI2,HDMI3 etc. No number gaps are
264allowed. The names with numbers must be continuous. It is allowed to put
265a whitespace between name and index (like 'Line 1') for the better
266readability. The device names 'Line 1' and 'Line1' are equal for
267this purpose.
268
269If EnableSequence/DisableSequence controls independent paths in the hardware
270it is also recommended to split playback and capture UCM devices and use
271the number suffixes. Example use case: Use the integrated microphone
272in the laptop instead the microphone in headphones.
273
274The preference of the devices is determined by the priority value (higher value = higher priority).
275
276See the SND_USE_CASE_MOD constants like #SND_USE_CASE_MOD_ECHO_REF for the full list of known modifiers.
277
278### Boot (alsactl)
279
280The *FixedBootSequence* is executed at each boot. The *BootSequence* is executed only
281if the card's configuration is missing. The purpose is to let the users modify the
282configuration like volumes or switches. The alsactl ensures the persistency (store
283the state of the controls to the /var tree and loads the previous state in the next
284boot).
285
286\image html ucm-seq-boot.svg
287
288### Device volume
289
290It is expected that the applications handle the volume settings. It is not recommended
291to set the fixed values for the volume settings in the Enable / Disable sequences for
292verbs or devices, if the device exports the hardware volume (MixerElem or Volume/Switch
293values). The default volume settings should be set in the *BootSequence*. The purpose
294for this scheme is to allow users to override defaults using the alsactl sound card
295state management.
296
297Checklist:
298
2991. Set default volume in BootSequence
3002. Verb's EnableSequence should ensure that all devices are turned off (mixer paths)
301   to avoid simultaneous device use - the previous state is unknown (see *disdevall*
302   and *disdev2* commands or create a new custom command sequence)
303
304\image html ucm-volume.svg
305
306### Dynamic configuration tree
307
308The evaluation order may look a bit different from the user perspective.
309At first, the standard alsa-lib configuration tree is parsed. All other
310layers on top are working with this tree. It may shift / move the configuration
311blocks from the configuration files as they are placed to the tree internally.
312
313~~~{.html}
314Example configuration       | Parsed static tree      | Identical static tree
315----------------------------+-------------------------+-------------------------------
316If.1 {                      | If {                    | If.1.True.Define.VAR "A"
317  True.Define.VAR "A"       |   1.True.Define.VAR "A" | If.2.True.Define.VAR "C"
318}                           |   2.True.Define.VAR "C" | Define.VAR "B"
319Define.VAR "B"              | }                       |
320If.2 {                      | Define.VAR "B"          |
321  True.Define.VAR "C"       |                         |
322}                           |                         |
323~~~
324
325Even if one or both conditions are evaluated as true, the variable _VAR_ will
326be evaluated always as **B** because the first _If_ block was before the non-nested
327_Define_ . The second _If_ block was appended to the first _If_ block (before
328_Define_ in the configuration tree) in the text configuration parser.
329
330
331### Syntax
332
333Unless described, the syntax version 4 is used.
334
335~~~
336Syntax 4
337~~~
338
339
340### Include
341
342There are two ways to include other configuration files.
343
344#### Static include
345
346The static include is inherited from the standard alsa-lib configuration
347syntax. It can be placed anywhere in the configuration files. The search
348path is composed from the root alsa configuration path (usually
349_/usr/share/alsa_) and _ucm2_ directory.
350
351~~~{.html}
352<some/path/file.conf>        # include file using the search path
353</absolute/path/file.conf>   # include file using the absolute path
354~~~
355
356#### Lazy include
357
358The lazy include is evaluated at runtime. The root path is the ucm2
359tree. The absolute include appends the ucm2 absolute path to the
360specified path. The relative include is relative to the file which
361contains the _Include_ configuration block.
362
363~~~{.html}
364Include.id1.File "/some/path/file.conf"  # absolute include (in the ucm2 tree)
365Include.id2.File "subdir/file.conf"      # relative include to the current configuration directory (UseCasePath)
366~~~
367
368### Configuration tree evaluation
369
370The evaluation of the static configuration tree is proceed in
371the specific order (see table bellow). When the dynamic configuration
372tree changes, the evaluation sequence is restarted to evaluate
373all possible changes (new *Define* or *Include* or *If* blocks).
374
375Evaluation order   | Configuration block | Evaluation restart
376------------------:|---------------------|--------------------
3771                  | Define              | No
3782                  | Include             | Yes
3793                  | If                  | Yes
380
381
382### Substitutions
383
384The dynamic tree identifiers and assigned values in the configuration tree are
385substituted. The substitutes strings are in the table bellow.
386
387Substituted string   | Value
388---------------------|---------------------
389${OpenName}          | Original UCM card name (passed to snd_use_case_mgr_open())
390${ConfLibDir}        | Library top-level configuration directory (e.g. /usr/share/alsa)
391${ConfTopDir}        | Top-level UCM configuration directory (e.g. /usr/share/alsa/ucm2)
392${ConfDir}           | Card's UCM configuration directory (e.g. /usr/share/alsa/ucm2/conf.d/USB-Audio)
393${ConfName}          | Configuration name (e.g. USB-Audio.conf)
394${CardNumber}        | Real ALSA card number (or empty string for the virtual UCM card)
395${CardId}            | ALSA card identifier (see snd_ctl_card_info_get_id())
396${CardDriver}        | ALSA card driver (see snd_ctl_card_info_get_driver())
397${CardName}          | ALSA card name (see snd_ctl_card_info_get_name())
398${CardLongName}      | ALSA card long name (see snd_ctl_card_info_get_longname())
399${CardComponents}    | ALSA card components (see snd_ctl_card_info_get_components())
400${env:\<str\>}         | Environment variable \<str\>
401${sys:\<str\>}         | Contents of sysfs file \<str\>
402${var:\<str\>}         | UCM parser variable (set using a _Define_ block)
403${eval:\<str\>}        | Evaluate expression like *($var+2)/3* [**Syntax 5**]
404${find-card:\<str\>}   | Find a card - see _Find card substitution_ section
405${find-device:\<str\>} | Find a device - see _Find device substitution_ section
406
407#### Special whole string substitution
408
409Substituted string   | Value
410---------------------|---------------------
411${evali:\<str\>}       | Evaluate expression like *($var+2)/3* [**Syntax 6**]; target node will be integer; substituted only in the LibraryConfig subtree
412
413#### Find card substitution
414
415This substitutions finds the ALSA card and returns the appropriate identifier or
416the card number (see return argument).
417
418Usage example:
419
420~~~{.html}
421${find-card:field=name,regex='^acp$',return=number}
422~~~
423
424Arguments:
425
426Argument             | Description
427---------------------|-----------------------
428return               | return value type (id, number), id is the default
429field                | field for the lookup (id, driver, name, longname, mixername, components)
430regex                | regex string for the field match
431
432#### Find device substitution
433
434Usage example:
435
436~~~{.html}
437${find-device:type=pcm,field=name,regex='DMIC'}
438~~~
439
440Arguments:
441
442Argument             | Description
443---------------------|-----------------------
444type                 | device type (pcm)
445stream               | stream type (playback, capture), playback is default
446field                | field for the lookup (id, name, subname)
447regex                | regex string for the field match
448
449
450### Variable defines
451
452The variables can be defined and altered with the *Define* or *DefineRegex* blocks.
453The *Define* block looks like:
454
455~~~{.html}
456Define {
457  variable1 "a"
458  variable2 "b"
459}
460~~~
461
462The *DefineRegex* allows substring extraction like:
463
464~~~{.html}
465DefineRegex.rval {
466  Regex "(hello)|(regex)"
467  String "hello, it's my regex"
468}
469~~~
470
471The result will be stored to variables *rval1* as *hello* and *rval2* as *regex* (every matched
472substrings are stored to a separate variable with the sequence number postfix.
473
474Variables can be substituted using the `${var:rval1}` reference for example.
475
476### Macros
477
478Macros were added for *Syntax* version *6*. The *DefineMacro* defines new
479macro like:
480
481~~~{.html}
482DefineMacro.macro1 {
483  Define.a "${var:__arg1}"
484  Define.b "${var:__other}"
485  # Device or any other block may be defined here...
486}
487~~~
488
489The arguments in the macro are refered as the variables with the double
490underscore name prefix (like *__variable*). The configuration block in
491the DefineMacro subtree is always evaluated (including arguments and variables)
492at the time of the instantiation.
493
494The macros can be instantiated (expanded) using:
495
496~~~{.html}
497# short version
498Macro.id1.macro1 "arg1='something 1',other='other x'"
499
500# long version
501Macro.id1.macro1 {
502  arg1 'something 1'
503  other 'other x'
504}
505~~~
506
507The second identifier (in example as *id1*) must be unique, but the contents
508is ignored. It just differentiate the items in the subtree (allowing multiple
509instances for one macro).
510
511### Conditions
512
513The configuration tree evaluation supports the conditions - *If* blocks. Each *If* blocks
514must define a *Condition* block and *True* or *False* blocks or both. The *True* or *False*
515blocks will be merged to the parent tree (where the *If* block is defined) when
516the *Condition* is evaluated.
517
518Example:
519
520~~~{.html}
521If.uniqueid {
522  Condition {
523    Type String
524    Haystack "abcd"
525    Needle "a"
526  }
527  True {
528    Define.a a
529    define.b b
530  }
531}
532~~~
533
534#### True (Type AlwaysTrue)
535
536Execute only *True* block. It may be used to change the evaluation order as
537explained in the *Configuration Tree* paragraph.
538
539#### String is empty (Type String)
540
541Field                | Description
542---------------------|-----------------------
543Empty                | string
544
545#### Strings are equal (Type String)
546
547Field                | Description
548---------------------|-----------------------
549String1              | string
550String2              | substring in string
551
552#### Substring is present (Type String)
553
554Field                | Description
555---------------------|-----------------------
556Haystack             | string
557Needle               | substring in string
558
559#### Regex match (Type RegexMatch)
560
561Field                | Description
562---------------------|-----------------------
563String               | string
564Regex                | regex expression (extended posix, ignore case)
565
566#### ALSA control element exists (Type ControlExists)
567
568Field                | Description
569---------------------|-----------------------
570Device               | ALSA control device (see snd_ctl_open())
571Control              | control in ASCII (parsed using snd_ctl_ascii_elem_id_parse())
572ControlEnum	     | value for the enum control (optional)
573
574Example:
575
576~~~{.html}
577If.fmic {
578  Condition {
579    Type ControlExists
580    Control "name='Front Mic Playback Switch'"
581  }
582  True {
583    ...
584  }
585}
586~~~
587
588### Variants
589
590To avoid duplication of the many configuration files for the cases with
591minimal configuration changes, there is the variant extension. Variants were
592added for *Syntax* version *6*.
593
594The bellow example will create two verbs - "HiFi" and "HiFi 7.1" with
595the different playback channels (2 and 8) for the "Speaker" device.
596
597Example (main configuration file):
598
599~~~{.html}
600SectionUseCase."HiFi" {
601  File "HiFi.conf"
602  Variant."HiFi" {
603    Comment "HiFi"
604  }
605  Variant."HiFi 7+1" {
606    Comment "HiFi 7.1"
607  }
608}
609~~~
610
611Example (verb configuration file - HiFi.conf):
612
613~~~{.html}
614SectionDevice."Speaker" {
615  Value {
616    PlaybackChannels 2
617  }
618  Variant."HiFi 7+1".Value {
619    PlaybackChannels 8
620  }
621}
622~~~
623
624*/
625
626/**
627 \}
628 */
629