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