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