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