• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
36 The use case configuration files use \ref conf syntax to define the
37 static configuration tree. This tree is evaluated (modified) at runtime
38 according the conditions and dynamic variables in the configuration tree.
39 The result is parsed and exported to the applications using \ref ucm API.
40 
41 ### Configuration directory and main filename lookup
42 
43 The lookup paths are describen in *ucm.conf* file. The configuration
44 structure looks like:
45 
46 ~~~{.html}
47 UseCasePath.path1 {
48   Directory "conf.virt.d"
49   File "${OpenName}.conf"
50 }
51 UseCasePath.path2 {
52   Directory "external"
53   File "${OpenName}.conf"
54 }
55 ~~~
56 
57 ### UCM main configuration file
58 
59 Each sound card has a master sound card file that lists all the supported
60 use 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 
66 # Use Case name for user interface
67 Comment "Nice Abstracted Soundcard"
68 
69 # The file is divided into Use case sections. One section per use case verb.
70 
71 SectionUseCase."Voice Call" {
72   File "voice_call_blah"
73   Comment "Make a voice phone call."
74 }
75 
76 SectionUseCase."HiFi" {
77   File "hifi_blah"
78   Comment "Play and record HiFi quality Music."
79 }
80 
81 # Define Value defaults
82 
83 ValueDefaults {
84   PlaybackChannels 4
85   CaptureChannels 4
86 }
87 
88 # Define boot / initialization sequence
89 # This sequence is skipped, when the soundcard was already configured by system
90 # (alsactl configuration was already created). The purpose is to not alter
91 # ALSA card controls which may be modified by user after initial settings.
92 
93 BootSequence [
94   cset "name='My control' on"
95 ]
96 
97 # Define fixed boot sequence
98 # This sequence is always executed on boot (hotplug).
99 
100 FixedBootSequence [
101   cset "name='Something to toggle' toggle"
102 ]
103 ~~~
104 
105 ### UCM verb configuration file
106 
107 The verb configuration file defines devices, modifier and initialization sequences.
108 It is something like a sound profile.
109 
110 ~~~{.html}
111 # Example Use case verb section for Voice call blah
112 # By Joe Blogs <joe@blogs.com>
113 
114 # verb global section
115 
116 SectionVerb {
117 
118   # enable and disable sequences are compulsory
119   EnableSequence [
120     cset "name='Master Playback Switch',index=2 0,0"
121     cset "name='Master Playback Volume',index=2 25,25"
122     msleep 50
123     cset "name='Master Playback Switch',index=2 1,1"
124     cset "name='Master Playback Volume',index=2 50,50"
125   ]
126 
127   DisableSequence [
128     cset "name='Master Playback Switch',index=2 0,0"
129     cset "name='Master Playback Volume',index=2 25,25"
130     msleep 50
131     cset "name='Master Playback Switch',index=2 1,1"
132     cset "name='Master Playback Volume',index=2 50,50"
133   ]
134 
135   # Optional transition verb
136   TransitionSequence."ToCaseName" [
137     msleep 1
138   ]
139 
140   # Optional TQ and device values
141   Value {
142     TQ HiFi
143     PlaybackChannels 6
144   }
145 }
146 
147 # Each device is described in new section. N devices are allowed
148 
149 SectionDevice."Headphones" {
150 
151   SupportedDevice [
152     "x"
153     "y"
154   ]
155 
156   # or (not both)
157 
158   ConflictingDevice [
159     "x"
160     "y"
161   ]
162 
163   EnableSequence [
164     ...
165   ]
166 
167   DisableSequence [
168     ...
169   ]
170 
171   TransitionSequence."ToDevice" [
172     ...
173   ]
174 
175   Value {
176     PlaybackVolume "name='Master Playback Volume',index=2"
177     PlaybackSwitch "name='Master Playback Switch',index=2"
178     PlaybackPCM "hw:${CardId},4"
179   }
180 }
181 
182 # Each modifier is described in new section. N modifiers are allowed
183 
184 SectionModifier."Capture Voice" {
185   Comment "Record voice call"
186 
187   SupportedDevice [
188     "x"
189     "y"
190   ]
191 
192   # or (not both)
193 
194   ConflictingDevice [
195     "x"
196     "y"
197   ]
198 
199   EnableSequence [
200     ...
201   ]
202 
203   DisableSequence [
204     ...
205   ]
206 
207   TransitionSequence."ToModifierName" [
208     ...
209   ]
210 
211   # Optional TQ and ALSA PCMs
212   Value {
213     TQ Voice
214     CapturePCM "hw:${CardId},11"
215     PlaybackVolume "name='Master Playback Volume',index=2"
216     PlaybackSwitch "name='Master Playback Switch',index=2"
217   }
218 }
219 ~~~
220 
221 ### Sequence commands
222 
223 Command name   | Description
224 ---------------|----------------------------------------------
225 cdev ARG       | ALSA control device name for snd_ctl_open()
226 cset ARG       | ALSA control set - snd_ctl_ascii_elem_id_parse() + snd_ctl_ascii_value_parse()
227 cset-new ARG   | Create new ALSA user control element - snd_ctl_ascii_elem_id_parse() + description
228 ctl-remove ARG | Remove ALSA user control element - snd_ctl_ascii_elem_id_parse()
229 sysw ARG       | write to sysfs tree
230 usleep ARG     | sleep for specified amount of microseconds
231 msleep ARG     | sleep for specified amount of milliseconds
232 exec ARG       | execute a specific command (without shell - *man execv*)
233 shell ARG      | execute a specific command (using shell - *man system*)
234 cfg-save ARG   | save LibraryConfig to a file
235 
236 ~~~{.html}
237 # Examples
238 cset "name='PCM Playback Volue',index=2 99"
239 cset-new "name='Bool2' type=bool,count=2 1,0"
240 cset-new "name='Enum' type=enum,labels='L1;L2;L3' 'L2'"
241 ctl-remove "name='Bool2'"
242 sysw "-/class/sound/ctl-led/speaker/card${CardNumber}/attach:Speaker Channel Switch"
243 usleep 10
244 exec "/bin/echo hello"
245 shell "set"
246 cfg-save "/tmp/test.conf:+pcm"
247 ~~~
248 
249 ### Naming (devices, verbs)
250 
251 See the SND_USE_CASE_VERB constains like #SND_USE_CASE_VERB_HIFI for the full list of known verbs.
252 
253 See the SND_USE_CASE_DEV constants like #SND_USE_CASE_DEV_SPEAKER for the full list of known devices.
254 If multiple devices with the same name exists, the number suffixes should
255 be added to these names like HDMI1,HDMI2,HDMI3 etc. No number gaps are
256 allowed. The names with numbers must be continuous. It is allowed to put
257 a whitespace between name and index (like 'Line 1') for the better
258 readability. The device names 'Line 1' and 'Line1' are equal for
259 this purpose.
260 
261 If EnableSequence/DisableSequence controls independent paths in the hardware
262 it is also recommended to split playback and capture UCM devices and use
263 the number suffixes. Example use case: Use the integrated microphone
264 in the laptop instead the microphone in headphones.
265 
266 The preference of the devices is determined by the priority value (higher value = higher priority).
267 
268 See the SND_USE_CASE_MOD constants like #SND_USE_CASE_MOD_ECHO_REF for the full list of known modifiers.
269 
270 ### Boot (alsactl)
271 
272 The *FixedBootSequence* is executed at each boot. The *BootSequence* is executed only
273 if the card's configuration is missing. The purpose is to let the users modify the
274 configuration like volumes or switches. The alsactl ensures the persistency (store
275 the state of the controls to the /var tree and loads the previous state in the next
276 boot).
277 
278 ### Device volume
279 
280 It is expected that the applications handle the volume settings. It is not recommended
281 to set the fixed values for the volume settings to the Enable / Disable sequences for
282 verbs or devices, if the device exports the hardware volume (MixerElem or Volume/Switch
283 values). The default volume settings should be set in the *BootSequence*.
284 
285 ### Dynamic configuration tree
286 
287 The evaluation order may look a bit different from the user perspective.
288 At first, the standard alsa-lib configuration tree is parsed. All other
289 layers on top are working with this tree. It may shift / move the configuration
290 blocks from the configuration files as they are placed to the tree internally.
291 
292 ~~~{.html}
293 Example configuration       | Parsed static tree      | Identical static tree
294 ----------------------------+-------------------------+-------------------------------
295 If.1 {                      | If {                    | If.1.True.Define.VAR "A"
296   True.Define.VAR "A"       |   1.True.Define.VAR "A" | If.2.True.Define.VAR "C"
297 }                           |   2.True.Define.VAR "C" | Define.VAR "B"
298 Define.VAR "B"              | }                       |
299 If.2 {                      | Define.VAR "B"          |
300   True.Define.VAR "C"       |                         |
301 }                           |                         |
302 ~~~
303 
304 Even if one or both conditions are evaluated as true, the variable _VAR_ will
305 be evaluated always as **B** because the first _If_ block was before the non-nested
306 _Define_ . The second _If_ block was appended to the first _If_ block (before
307 _Define_ in the configuration tree) in the text configuration parser.
308 
309 
310 ### Syntax
311 
312 Unless described, the syntax version 4 is used.
313 
314 ~~~
315 Syntax 4
316 ~~~
317 
318 
319 ### Include
320 
321 There are two ways to include other configuration files.
322 
323 #### Static include
324 
325 The static include is inherited from the standard alsa-lib configuration
326 syntax. It can be placed anywhere in the configuration files. The search
327 path is composed from the root alsa configuration path (usually
328 _/usr/share/alsa_) and _ucm2_ directory.
329 
330 ~~~{.html}
331 <some/path/file.conf>        # include file using the search path
332 </absolute/path/file.conf>   # include file using the absolute path
333 ~~~
334 
335 #### Lazy include
336 
337 The lazy include is evaluated at runtime. The root path is the ucm2
338 tree. The absolute include appends the ucm2 absolute path to the
339 specified path. The relative include is relative to the file which
340 contains the _Include_ configuration block.
341 
342 ~~~{.html}
343 Include.id1.File "/some/path/file.conf"  # absolute include (in the ucm2 tree)
344 Include.id2.File "subdir/file.conf"      # relative include to the current configuration directory (UseCasePath)
345 ~~~
346 
347 ### Configuration tree evaluation
348 
349 The evaluation of the static configuration tree is proceed in
350 the specific order (see table bellow). When the dynamic configuration
351 tree changes, the evaluation sequence is restarted to evaluate
352 all possible changes (new *Define* or *Include* or *If* blocks).
353 
354 Evaluation order   | Configuration block | Evaluation restart
355 ------------------:|---------------------|--------------------
356 1                  | Define              | No
357 2                  | Include             | Yes
358 3                  | If                  | Yes
359 
360 
361 ### Substitutions
362 
363 The dynamic tree identifiers and assigned values in the configuration tree are
364 substituted. The substitutes strings are in the table bellow.
365 
366 Substituted string   | Value
367 ---------------------|---------------------
368 ${OpenName}          | Original UCM card name (passed to snd_use_case_mgr_open())
369 ${ConfLibDir}        | Library top-level configuration directory (e.g. /usr/share/alsa)
370 ${ConfTopDir}        | Top-level UCM configuration directory (e.g. /usr/share/alsa/ucm2)
371 ${ConfDir}           | Card's UCM configuration directory (e.g. /usr/share/alsa/ucm2/conf.d/USB-Audio)
372 ${ConfName}          | Configuration name (e.g. USB-Audio.conf)
373 ${CardNumber}        | Real ALSA card number (or empty string for the virtual UCM card)
374 ${CardId}            | ALSA card identifier (see snd_ctl_card_info_get_id())
375 ${CardDriver}        | ALSA card driver (see snd_ctl_card_info_get_driver())
376 ${CardName}          | ALSA card name (see snd_ctl_card_info_get_name())
377 ${CardLongName}      | ALSA card long name (see snd_ctl_card_info_get_longname())
378 ${CardComponents}    | ALSA card components (see snd_ctl_card_info_get_components())
379 ${env:<str>}         | Environment variable <str>
380 ${sys:<str>}         | Contents of sysfs file <str>
381 ${var:<str>}         | UCM parser variable (set using a _Define_ block)
382 ${eval:<str>}        | Evaluate expression like *($var+2)/3* [**Syntax 5**]
383 ${find-card:<str>}   | Find a card - see _Find card substitution_ section
384 ${find-device:<str>} | Find a device - see _Find device substitution_ section
385 
386 #### Find card substitution
387 
388 This substitutions finds the ALSA card and returns the appropriate identifier or
389 the card number (see return argument).
390 
391 Usage example:
392 
393 ~~~{.html}
394 ${find-card:field=name,regex='^acp$',return=number}
395 ~~~
396 
397 Arguments:
398 
399 Argument             | Description
400 ---------------------|-----------------------
401 return               | return value type (id, number), id is the default
402 field                | field for the lookup (id, driver, name, longname, mixername, components)
403 regex                | regex string for the field match
404 
405 #### Find device substitution
406 
407 Usage example:
408 
409 ~~~{.html}
410 ${find-device:type=pcm,field=name,regex='DMIC'}
411 ~~~
412 
413 Arguments:
414 
415 Argument             | Description
416 ---------------------|-----------------------
417 type                 | device type (pcm)
418 stream               | stream type (playback, capture), playback is default
419 field                | field for the lookup (id, name, subname)
420 regex                | regex string for the field match
421 
422 
423 ### Variable defines
424 
425 The variables can be defined and altered with the *Define* or *DefineRegex* blocks.
426 The *Define* block looks like:
427 
428 ~~~{.html}
429 Define {
430   variable1 "a"
431   variable2 "b"
432 }
433 ~~~
434 
435 The *DefineRegex* allows substring extraction like:
436 
437 ~~~{.html}
438 DefineRegex.rval {
439   Regex "(hello)|(regex)"
440   String "hello, it's my regex"
441 }
442 ~~~
443 
444 The result will be stored to variables *rval1* as *hello* and *rval2* as *regex* (every matched
445 substrings are stored to a separate variable with the sequence number postfix.
446 
447 Variables can be substituted using the `${var:rval1}` reference for example.
448 
449 ### Conditions
450 
451 The configuration tree evaluation supports the conditions - *If* blocks. Each *If* blocks
452 must define a *Condition* block and *True* or *False* blocks or both. The *True* or *False*
453 blocks will be merged to the parent tree (where the *If* block is defined) when
454 the *Condition* is evaluated.
455 
456 Example:
457 
458 ~~~{.html}
459 If.uniqueid {
460   Condition {
461     Type String
462     Haystack "abcd"
463     Needle "a"
464   }
465   True {
466     Define.a a
467     define.b b
468   }
469 }
470 ~~~
471 
472 #### True (Type AlwaysTrue)
473 
474 Execute only *True* block. It may be used to change the evaluation order as
475 explained in the *Configuration Tree* paragraph.
476 
477 #### String is empty (Type String)
478 
479 Field                | Description
480 ---------------------|-----------------------
481 Empty                | string
482 
483 #### Strings are equal (Type String)
484 
485 Field                | Description
486 ---------------------|-----------------------
487 String1              | string
488 String2              | substring in string
489 
490 #### Substring is present (Type String)
491 
492 Field                | Description
493 ---------------------|-----------------------
494 Haystack             | string
495 Needle               | substring in string
496 
497 #### Regex match (Type RegexMatch)
498 
499 Field                | Description
500 ---------------------|-----------------------
501 String               | string
502 Regex                | regex expression (extended posix, ignore case)
503 
504 #### ALSA control element exists (Type ControlExists)
505 
506 Field                | Description
507 ---------------------|-----------------------
508 Device               | ALSA control device (see snd_ctl_open())
509 Control              | control in ASCII (parsed using snd_ctl_ascii_elem_id_parse())
510 ControlEnum	     | value for the enum control (optional)
511 
512 Example:
513 
514 ~~~{.html}
515 If.fmic {
516   Condition {
517     Type ControlExists
518     Control "name='Front Mic Playback Switch'"
519   }
520   True {
521     ...
522   }
523 }
524 ~~~
525 
526 
527 */
528 
529 /**
530  \}
531  */
532