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 Syntax 6
67 
68 # Use Case name for user interface
69 Comment "Nice Abstracted Soundcard"
70 
71 # The file is divided into Use case sections. One section per use case verb.
72 
73 SectionUseCase."Voice Call" {
74   File "voice_call_blah"
75   Comment "Make a voice phone call."
76 }
77 
78 SectionUseCase."HiFi" {
79   File "hifi_blah"
80   Comment "Play and record HiFi quality Music."
81 }
82 
83 # Define Value defaults
84 
85 ValueDefaults {
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 
95 BootSequence [
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 
106 FixedBootSequence [
107   cset "name='Something to toggle' toggle"
108 ]
109 ~~~
110 
111 ### UCM verb configuration file
112 
113 The verb configuration file defines devices, modifier and initialization sequences.
114 It 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 
122 SectionVerb {
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 
148 SectionDevice."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 
183 SectionModifier."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 
228 Command name   | Description
229 ---------------|----------------------------------------------
230 enadev2 ARG    | execute device enable sequence
231 disdev2 ARG    | execute device disable sequence
232 disdevall ""   | execute device disable sequence for all devices in verb
233 cdev ARG       | ALSA control device name for snd_ctl_open()
234 cset ARG       | ALSA control set - snd_ctl_ascii_elem_id_parse() + snd_ctl_ascii_value_parse()
235 cset-new ARG   | Create new ALSA user control element - snd_ctl_ascii_elem_id_parse() + description
236 ctl-remove ARG | Remove ALSA user control element - snd_ctl_ascii_elem_id_parse()
237 sysw ARG       | write to sysfs tree
238 usleep ARG     | sleep for specified amount of microseconds
239 msleep ARG     | sleep for specified amount of milliseconds
240 exec ARG       | execute a specific command (without shell - *man execv*)
241 shell ARG      | execute a specific command (using shell - *man system*)
242 cfg-save ARG   | save LibraryConfig to a file
243 
244 ~~~{.html}
245 # Examples
246 cset "name='PCM Playback Volue',index=2 99"
247 cset-new "name='Bool2' type=bool,count=2 1,0"
248 cset-new "name='Enum' type=enum,labels='L1;L2;L3' 'L2'"
249 ctl-remove "name='Bool2'"
250 sysw "-/class/sound/ctl-led/speaker/card${CardNumber}/attach:Speaker Channel Switch"
251 usleep 10
252 exec "/bin/echo hello"
253 shell "set"
254 cfg-save "/tmp/test.conf:+pcm"
255 ~~~
256 
257 ### Naming (devices, verbs)
258 
259 See the SND_USE_CASE_VERB constains like #SND_USE_CASE_VERB_HIFI for the full list of known verbs.
260 
261 See the SND_USE_CASE_DEV constants like #SND_USE_CASE_DEV_SPEAKER for the full list of known devices.
262 If multiple devices with the same name exists, the number suffixes should
263 be added to these names like HDMI1,HDMI2,HDMI3 etc. No number gaps are
264 allowed. The names with numbers must be continuous. It is allowed to put
265 a whitespace between name and index (like 'Line 1') for the better
266 readability. The device names 'Line 1' and 'Line1' are equal for
267 this purpose.
268 
269 If EnableSequence/DisableSequence controls independent paths in the hardware
270 it is also recommended to split playback and capture UCM devices and use
271 the number suffixes. Example use case: Use the integrated microphone
272 in the laptop instead the microphone in headphones.
273 
274 The preference of the devices is determined by the priority value (higher value = higher priority).
275 
276 See 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 
280 The *FixedBootSequence* is executed at each boot. The *BootSequence* is executed only
281 if the card's configuration is missing. The purpose is to let the users modify the
282 configuration like volumes or switches. The alsactl ensures the persistency (store
283 the state of the controls to the /var tree and loads the previous state in the next
284 boot).
285 
286 \image html ucm-seq-boot.svg
287 
288 ### Device volume
289 
290 It is expected that the applications handle the volume settings. It is not recommended
291 to set the fixed values for the volume settings in the Enable / Disable sequences for
292 verbs or devices, if the device exports the hardware volume (MixerElem or Volume/Switch
293 values). The default volume settings should be set in the *BootSequence*. The purpose
294 for this scheme is to allow users to override defaults using the alsactl sound card
295 state management.
296 
297 Checklist:
298 
299 1. Set default volume in BootSequence
300 2. 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 
308 The evaluation order may look a bit different from the user perspective.
309 At first, the standard alsa-lib configuration tree is parsed. All other
310 layers on top are working with this tree. It may shift / move the configuration
311 blocks from the configuration files as they are placed to the tree internally.
312 
313 ~~~{.html}
314 Example configuration       | Parsed static tree      | Identical static tree
315 ----------------------------+-------------------------+-------------------------------
316 If.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"
319 Define.VAR "B"              | }                       |
320 If.2 {                      | Define.VAR "B"          |
321   True.Define.VAR "C"       |                         |
322 }                           |                         |
323 ~~~
324 
325 Even if one or both conditions are evaluated as true, the variable _VAR_ will
326 be 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 
333 Unless described, the syntax version 4 is used.
334 
335 ~~~
336 Syntax 4
337 ~~~
338 
339 
340 ### Include
341 
342 There are two ways to include other configuration files.
343 
344 #### Static include
345 
346 The static include is inherited from the standard alsa-lib configuration
347 syntax. It can be placed anywhere in the configuration files. The search
348 path 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 
358 The lazy include is evaluated at runtime. The root path is the ucm2
359 tree. The absolute include appends the ucm2 absolute path to the
360 specified path. The relative include is relative to the file which
361 contains the _Include_ configuration block.
362 
363 ~~~{.html}
364 Include.id1.File "/some/path/file.conf"  # absolute include (in the ucm2 tree)
365 Include.id2.File "subdir/file.conf"      # relative include to the current configuration directory (UseCasePath)
366 ~~~
367 
368 ### Configuration tree evaluation
369 
370 The evaluation of the static configuration tree is proceed in
371 the specific order (see table bellow). When the dynamic configuration
372 tree changes, the evaluation sequence is restarted to evaluate
373 all possible changes (new *Define* or *Include* or *If* blocks).
374 
375 Evaluation order   | Configuration block | Evaluation restart
376 ------------------:|---------------------|--------------------
377 1                  | Define              | No
378 2                  | Include             | Yes
379 3                  | If                  | Yes
380 
381 
382 ### Substitutions
383 
384 The dynamic tree identifiers and assigned values in the configuration tree are
385 substituted. The substitutes strings are in the table bellow.
386 
387 Substituted 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 
409 Substituted 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 
415 This substitutions finds the ALSA card and returns the appropriate identifier or
416 the card number (see return argument).
417 
418 Usage example:
419 
420 ~~~{.html}
421 ${find-card:field=name,regex='^acp$',return=number}
422 ~~~
423 
424 Arguments:
425 
426 Argument             | Description
427 ---------------------|-----------------------
428 return               | return value type (id, number), id is the default
429 field                | field for the lookup (id, driver, name, longname, mixername, components)
430 regex                | regex string for the field match
431 
432 #### Find device substitution
433 
434 Usage example:
435 
436 ~~~{.html}
437 ${find-device:type=pcm,field=name,regex='DMIC'}
438 ~~~
439 
440 Arguments:
441 
442 Argument             | Description
443 ---------------------|-----------------------
444 type                 | device type (pcm)
445 stream               | stream type (playback, capture), playback is default
446 field                | field for the lookup (id, name, subname)
447 regex                | regex string for the field match
448 
449 
450 ### Variable defines
451 
452 The variables can be defined and altered with the *Define* or *DefineRegex* blocks.
453 The *Define* block looks like:
454 
455 ~~~{.html}
456 Define {
457   variable1 "a"
458   variable2 "b"
459 }
460 ~~~
461 
462 The *DefineRegex* allows substring extraction like:
463 
464 ~~~{.html}
465 DefineRegex.rval {
466   Regex "(hello)|(regex)"
467   String "hello, it's my regex"
468 }
469 ~~~
470 
471 The result will be stored to variables *rval1* as *hello* and *rval2* as *regex* (every matched
472 substrings are stored to a separate variable with the sequence number postfix.
473 
474 Variables can be substituted using the `${var:rval1}` reference for example.
475 
476 ### Macros
477 
478 Macros were added for *Syntax* version *6*. The *DefineMacro* defines new
479 macro like:
480 
481 ~~~{.html}
482 DefineMacro.macro1 {
483   Define.a "${var:__arg1}"
484   Define.b "${var:__other}"
485   # Device or any other block may be defined here...
486 }
487 ~~~
488 
489 The arguments in the macro are refered as the variables with the double
490 underscore name prefix (like *__variable*). The configuration block in
491 the DefineMacro subtree is always evaluated (including arguments and variables)
492 at the time of the instantiation.
493 
494 The macros can be instantiated (expanded) using:
495 
496 ~~~{.html}
497 # short version
498 Macro.id1.macro1 "arg1='something 1',other='other x'"
499 
500 # long version
501 Macro.id1.macro1 {
502   arg1 'something 1'
503   other 'other x'
504 }
505 ~~~
506 
507 The second identifier (in example as *id1*) must be unique, but the contents
508 is ignored. It just differentiate the items in the subtree (allowing multiple
509 instances for one macro).
510 
511 ### Conditions
512 
513 The configuration tree evaluation supports the conditions - *If* blocks. Each *If* blocks
514 must define a *Condition* block and *True* or *False* blocks or both. The *True* or *False*
515 blocks will be merged to the parent tree (where the *If* block is defined) when
516 the *Condition* is evaluated.
517 
518 Example:
519 
520 ~~~{.html}
521 If.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 
536 Execute only *True* block. It may be used to change the evaluation order as
537 explained in the *Configuration Tree* paragraph.
538 
539 #### String is empty (Type String)
540 
541 Field                | Description
542 ---------------------|-----------------------
543 Empty                | string
544 
545 #### Strings are equal (Type String)
546 
547 Field                | Description
548 ---------------------|-----------------------
549 String1              | string
550 String2              | substring in string
551 
552 #### Substring is present (Type String)
553 
554 Field                | Description
555 ---------------------|-----------------------
556 Haystack             | string
557 Needle               | substring in string
558 
559 #### Regex match (Type RegexMatch)
560 
561 Field                | Description
562 ---------------------|-----------------------
563 String               | string
564 Regex                | regex expression (extended posix, ignore case)
565 
566 #### ALSA control element exists (Type ControlExists)
567 
568 Field                | Description
569 ---------------------|-----------------------
570 Device               | ALSA control device (see snd_ctl_open())
571 Control              | control in ASCII (parsed using snd_ctl_ascii_elem_id_parse())
572 ControlEnum	     | value for the enum control (optional)
573 
574 Example:
575 
576 ~~~{.html}
577 If.fmic {
578   Condition {
579     Type ControlExists
580     Control "name='Front Mic Playback Switch'"
581   }
582   True {
583     ...
584   }
585 }
586 ~~~
587 
588 ### Variants
589 
590 To avoid duplication of the many configuration files for the cases with
591 minimal configuration changes, there is the variant extension. Variants were
592 added for *Syntax* version *6*.
593 
594 The bellow example will create two verbs - "HiFi" and "HiFi 7.1" with
595 the different playback channels (2 and 8) for the "Speaker" device.
596 
597 Example (main configuration file):
598 
599 ~~~{.html}
600 SectionUseCase."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 
611 Example (verb configuration file - HiFi.conf):
612 
613 ~~~{.html}
614 SectionDevice."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