338 lines
12 KiB
Markdown
338 lines
12 KiB
Markdown
# ALSA UCM Configurations
|
||
|
||
此文档介绍了 alsa-ucm-aw-configs 中 UCM 配置文件的语法及约定
|
||
|
||
## 目录结构
|
||
|
||
UCM 配置文件放置在 ucm_configs 目录下, 按芯片级方案名字分类 (astar, azalea, ...);
|
||
在芯片级方案目录下, 按板级方案分类 (astar-dm, astar-parrot, ...), 并有一个 Default
|
||
目录用于放置该芯片级方案默认的配置文件
|
||
|
||
alsa-ucm-aw-configs 在编译时, 会根据当前芯片级方案的名字将对应目录下的配置文件拷
|
||
贝到小机端的 /usr/share/alsa/ucm 目录; 若当前芯片级方案的配置文件不存在, 则会拷贝
|
||
Default 目录下的默认配置文件
|
||
|
||
```
|
||
ucm_configs
|
||
├── astar
|
||
│ ├── astar-dm
|
||
│ │ ├── AC108
|
||
│ │ │ ├── AC108.conf
|
||
│ │ │ └── Record.conf
|
||
│ │ └── audiocodec
|
||
│ │ ├── audiocodec.conf
|
||
│ │ └── Play.conf
|
||
│ ├── astar-parrot
|
||
│ │ └── audiocodec
|
||
│ │ ├── audiocodec.conf
|
||
│ │ ├── Play.conf
|
||
│ │ └── Record.conf
|
||
│ └── Default
|
||
│ └── audiocodec
|
||
│ ├── audiocodec.conf
|
||
│ ├── Play.conf
|
||
│ └── Record.conf
|
||
└── azalea
|
||
├── azalea-m2ultra
|
||
│ └── audiocodec
|
||
│ ├── audiocodec.conf
|
||
│ ├── Play.conf
|
||
│ └── Record.conf
|
||
└── Default
|
||
└── audiocodec
|
||
├── audiocodec.conf
|
||
├── Play.conf
|
||
└── Record.conf
|
||
```
|
||
|
||
## UCM 配置文件
|
||
|
||
一份完整的 UCM 配置文件包括以下内容: card, verb, device, modifier (可选). 想要使
|
||
用某个 ALSA 设备并配置它的控件, 需要指定 1 个 card + 1 个 verb + 1 个或以上的
|
||
device + 0 个或以上的 modifier.
|
||
|
||
### card
|
||
|
||
表示声卡, 每个 card 单独一个目录, 每个方案需要包含一个或以上的 card, 如 astar-dm
|
||
下的 "AC108" 和 "audiocodec" 分别为两个不同的 card
|
||
|
||
### verb
|
||
|
||
表示使用案例 (use case), 表明某个特定的使用场景, 每个 card 需要包含一个或以上的
|
||
verb, 如 astar-parrot 的 audiocodec 下有 "Play" 和 "Record" 两个 verb
|
||
|
||
ALSA 官方默认定义有一些 verb 的名字, 如 "HiFi", "Voice", 但为了 Tina 平台下不同
|
||
方案的统一, **不推荐** 使用这些名字, 而应遵循后面的 verb 的命名约定
|
||
|
||
### device
|
||
|
||
表示设备, 如 "Headphone", "Speaker" 等, 每个 verb 需要包含一个或以上的 device,
|
||
其可用的命名请参考后面的 device 的命名约定
|
||
|
||
### modifier
|
||
|
||
表示修饰, 是对某个设备使用时附加的一些设置, 使同一个 verb 下的同一个 device 可以
|
||
有不同的使用效果, 如 "PlayTone", "PlayMusic" 等. modifier 并不是必须的, 每一个
|
||
verb 可以包含零至多个 modifier. 其可用的命名并无限制, 只要遵循通用命名约定
|
||
即可
|
||
|
||
## 语法
|
||
|
||
以 ucm_configs/DEMO/Default 目录下的配置文件为例
|
||
|
||
### 定义 card
|
||
|
||
新建一个目录, 并在该目录中新建一个与该目录同名的 .conf 文件, 如目录 *democard*
|
||
及其中的 *democard.conf* 就定义了一个名为 `democard` 的 card
|
||
|
||
*democard.conf* :
|
||
```
|
||
Comment "Comment on democard"
|
||
|
||
SectionUseCase."Play" {
|
||
File "Play.conf"
|
||
}
|
||
|
||
ValueDefaults {
|
||
Card "hw:demo"
|
||
Foobar "value of Foobar in democard"
|
||
}
|
||
```
|
||
|
||
- 开头的 `Comment` 关键字是对这个 card 的注释
|
||
- `SectionUseCase` 关键字用于定义 verb, 上述例子中定义了名为 `Play` 的 verb, 其
|
||
详细内容位于文件 *Play.conf* 中
|
||
- `ValueDefaults` 关键字用于定义 card 级别的变量值, 上述例子中定义的 `Foobar` 和
|
||
`Card` 变量的有效作用域为该 card 及其以下的 verb, device 和 modifier. 可在 verb,
|
||
device 或 modifier 中定义同名变量来覆盖这些变量的值
|
||
|
||
### 定义 verb
|
||
|
||
如上所述, 在 democard 这个 card 的定义中, 通过 *democard.conf* 定义了名为 `Play`
|
||
的 verb, 此时需要创建 *Play.conf* 文件以描述 `Play` 的详细内容
|
||
|
||
*Play.conf* 中 verb 相关的部分:
|
||
```
|
||
SectionVerb {
|
||
Commnent "Comment on verb Play"
|
||
|
||
EnableSequence [
|
||
cdev "hw:demo"
|
||
|
||
cset "name='Play Switch' 1"
|
||
|
||
]
|
||
|
||
DisableSequence [
|
||
cdev "hw:foobar"
|
||
|
||
cset "name='Play Switch' 0"
|
||
]
|
||
|
||
Value {
|
||
Foobar "Value of Foobar in verb Play"
|
||
}
|
||
}
|
||
```
|
||
|
||
- `SectionVerb` 关键字中的就是 `Play` 这个 verb 的内容
|
||
- `Comment` 关键字是对这个 verb 的注释
|
||
- `EnableSequence` 指使能这个 verb 时的操作, `cdev` 指定控件对应的 ALSA 虚拟设备
|
||
名字, `cset` 指定需要操作的控件名字和它的值; `DisableSequence` 与 `EnableSequence`
|
||
类似, 指失能这个 verb 时的操作
|
||
(**注意** : 由于 ALSA UCM 自身的缺陷, `DisableSequence` 中的内容实际无法执行, 因此
|
||
**不推荐** 在 `SectionVerb` 中使用 `EnableSequence` 和 `DisableSequence` 关键字,
|
||
而应该把相关的使能和失能操作放到具体的 device 或 modifier 内容中; 另外,
|
||
`EnableSequence` 和 `DisableSequence` 使用的是 **方括号 [ ]** 而不是大括号 { })
|
||
- `Value` 关键字定义了 verb 级别的变量值, 其有效作用域为该 verb 以及其下的 device
|
||
和 modifier. 此处中的 `Foobar` 变量的值覆盖了 *democard.conf* 中 `ValueDefaults`
|
||
处定义的同名变量的值
|
||
|
||
### 定义 device
|
||
|
||
device 的定义也在 *Play.conf* 文件中, 通过 `SectionDevice` 关键字指定
|
||
|
||
*Play.conf* 中 device 相关的内容:
|
||
```
|
||
SectionDevice."Headphone" {
|
||
Comment "Comment on device Headphone"
|
||
|
||
EnableSequence [
|
||
cdev "hw:demo"
|
||
|
||
cset "name='Headphone Switch' 1"
|
||
|
||
]
|
||
|
||
DisableSequence [
|
||
cdev "hw:foobar"
|
||
|
||
cset "name='Headphone Switch' 0"
|
||
]
|
||
|
||
Value {
|
||
Foobar "Value of Foobar in device Headphone"
|
||
}
|
||
}
|
||
```
|
||
|
||
- `SectionDevice` 关键字用于定义 device, 此处定义了一个名为 `Headphone` 的 device
|
||
- `Comment`, `EnableSequence` 和 `DisableSequence` 关键字与 `SectionVerb` 中含义
|
||
相同 (不同之处在于 `SectionDevice` 中的 `EnableSequence` 和 `DisableSequence` 都
|
||
是可被实际执行的)
|
||
- `Value` 关键字定义 device 级别的变量值, 其有效作用域为该 device. 此处定义的
|
||
`Foobar` 变量的值覆盖了 `SectionVerb` 中同名变量的值
|
||
|
||
### 定义 modifier
|
||
|
||
除了使用的是 `SectionModifier` 关键字, modifier 的定义与 device 的类似. `Value`
|
||
关键字定义的变量值作用域为该 modifier, 会覆盖 `SectionVerb` 中同名变量的值
|
||
|
||
*Play.conf* 中 modifier 相关的内容:
|
||
```
|
||
SectionModifier."PlayTone" {
|
||
Comment "Comment on modifier PlayTone"
|
||
|
||
EnableSequence [
|
||
cdev "hw:demo"
|
||
|
||
cset "name='PlayTone Switch' 1"
|
||
|
||
]
|
||
|
||
DisableSequence [
|
||
cdev "hw:foobar"
|
||
|
||
cset "name='PlayTone Switch' 0"
|
||
]
|
||
|
||
Value {
|
||
Foobar "Value of Foobar in modifier PlayTone"
|
||
}
|
||
}
|
||
```
|
||
|
||
### 注释
|
||
|
||
UCM 配置文件中 `#` 符号后的内容会被认为是注释
|
||
``` conf
|
||
# This is a comment
|
||
SectionUseCase."Play" {
|
||
File "Play.conf"
|
||
}
|
||
```
|
||
|
||
## 约定
|
||
|
||
为了保持 Tina 中不同方案下配置文件的统一, 有如下的约定:
|
||
|
||
### 通用命名约定
|
||
|
||
除了 card 和某些特定的 Value 的名字外, 其余自定义的名字均采用 **驼峰命名法**, 如
|
||
`LineIn`, `PlayTone`, `MicToHeadphone`, ... 名字中不包含空格, 下划线, 短横线等字
|
||
符
|
||
|
||
对于某些原本是全字母大写或部分字母大写的单词, 更倾向于将它们视作一个单词而仅
|
||
大写其首字母, 如: 使用 `Dmic` 而非 `DMIC`, `I2s` 而非 `I2S`, `AdcChannels` 而非
|
||
`ADCChannels`
|
||
|
||
### card
|
||
|
||
1. 全志 SoC 内置 codec 的名字统一使用 `audiocodec`
|
||
2. 内置 codec 以外的其他 card 的名字按照实际情况而定, 除了不能包含空格外并无额外
|
||
限制
|
||
3. 在 `ValueDefaults` 中需要定义变量 `Card` 指定对应的 ALSA 虚拟设备声卡名字
|
||
(不能使用数字编号, 而应该把声卡的名字写出来, 如 `hw:audiocodec`, `hw:sndcodec`)
|
||
|
||
### verb
|
||
|
||
1. verb 的命名遵循通用命名约定
|
||
2. 如无特殊情况, 推荐 verb 统一使用 `Play` , `Record` 和 `Call` 三个名字. `Play`
|
||
包含用于播放的设备, 如 `Headphone`, `Speaker` 等; `Record` 包含用于录
|
||
制的设备, 如 `Mic`, `LineIn` 等; `Call` 则包含兼有播放和录制功能的设备, 如
|
||
`Bluetooth`, `Headset` 等
|
||
3. **不推荐** 在 `SectionVerb` 中定义 `EnableSequence` 和 `DisableSequence`, 除非
|
||
只存在使能操作而不存在失能操作
|
||
|
||
### device
|
||
|
||
1. device 的命名遵循通用命名约定
|
||
2. 在一般情况下, 推荐使用以下的名字, 若无合适的再自行定义
|
||
> - Headphone
|
||
> - Headset
|
||
> - Speaker
|
||
> - Mic
|
||
> - LineIn
|
||
> - LineOut
|
||
> - PhoneIn
|
||
> - PhoneOut
|
||
> - Bluetooth
|
||
> - Spdif
|
||
> - Hdmi
|
||
3. 若某一个 verb 中存在多个同类型的设备, 可在 device 名字后面加编号区分 (编号不
|
||
一定需要从 1 开始, 可以根据实际情况而定), 然后在 `SectionVerb` 的 `Value` 中定义
|
||
`xxxNumber` 和 `xxxNames` 分别说明这种同类型设备的数量和名字, 名字之间用空格隔开
|
||
(如实际存在两个麦克风 MIC2 和 MIC3, 可以定义 `Mic2` 和 `Mic3` 两个 device, 并在
|
||
`SectionVerb` 的 `Value` 中定义 `MicNumber "2"` 和 `MicNames "Mic2 Mic3"`)
|
||
4. 有时候会有多个设备联合使用的情况, 对此没有硬性的命名约定, 对于某些情况推荐以下
|
||
命名:
|
||
> - 普通情况下多个设备联合使用, 使用 *序数词+设备* 的命名, 如 `TwoMics`, `FourMics`
|
||
> - 特定的设备需要对应特定的操作, 如 "MIC1 录制左声道, MIC2 录制右声道" 可命名为
|
||
> `Mic1LeftMic2Right`
|
||
> - 特定的设备数量与特定的通道数, 如两个麦克风可能分别用于录制两声道或四声道的不
|
||
> 同场景下, 可命名为 `TwoMicsTwoChs` 和 `TwoMicsFourChs` 以区分 (`Chs` 为 `Channels`
|
||
> 的缩写)
|
||
5. 若定义了多个设备联合使用的 device, 需要有它们各自本身的 device 定义. 例如定义
|
||
了 `TwoMics` 对应 MIC1 和 MIC2 的联合使用, 则需要分别定义 `Mic1` 和 `Mic2` 来提供
|
||
调节音量等操作的接口 (因为麦克风统一使用 `CaptureVolume` 变量作为音量控制的接口,
|
||
在当中不能同时定义多个设备的音量)
|
||
|
||
### modifier
|
||
|
||
除了需要遵循通用命名约定外, modifier 的命名由配置文件的编写者自行决定
|
||
|
||
### Value
|
||
|
||
推荐优先使用以下变量的命名, 若无合适的再自行定义 (自定义的名字应遵循通用命名约定)
|
||
|
||
- `Card` : 需要在 card 的 `ValueDefaults` 中定义, 用于指定该 card 对应的 ALSA 虚
|
||
拟声卡设备的名字 (不能使用数字编号, 而应该把具体的名字写出来), 如:
|
||
```
|
||
ValueDefaults {
|
||
Card "hw:audiocodec"
|
||
}
|
||
```
|
||
- `PlaybackPCM` , `CapturePCM` : 在 verb, device 或 modifier 中用于指定具体的 PCM
|
||
设备, 如 `PlaybackPCM "hw:audiocodec,0"` (这两个变量的名字沿用了 ALSA 官方的名字,
|
||
因此没遵循本文档的通用命名约定)
|
||
- `PlaybackVolume` , `CaptureVolume` : 指定音量控件的名字及其默认值, 格式为: "控
|
||
件ID 默认值", 如 `PlaybackVolume "name='Headphone Volume' 40"`
|
||
- `PlaybackVolumeMin` , `PlaybackVolumeMax` , `CaptureVolumeMin` , `CaptureVolumeMax` :
|
||
指定音量数值的有效范围, 需要在定义了 `PlaybackVolume` 或 `CaptureVolume` 的同时
|
||
定义, 如:
|
||
```
|
||
Value {
|
||
PlaybackVolume "name='Headphone Volume' 40"
|
||
PlaybackVolumeMin "0"
|
||
PlaybackVolumeMax "63"
|
||
}
|
||
```
|
||
- `PlaybackRate` , `CaptureRate` : 表明支持的特定采样率, 如
|
||
`PlaybackRate "16000 32000"` 表明仅支持 16000Hz 和 32000Hz 的采样率播放
|
||
- `PlaybackChannels` , `CaptureChannels` : 表明支持的特定通道数, 如
|
||
`PlaybackChannels "2 4"` 表明仅支持两通道或四通道播放
|
||
- `PlaybackFormat` , `CaptureFormat` : 表明支持的特定格式, 语法与 *aplay* 和
|
||
*arecord* 中 "-f" 选项的参数相同, 如 `PlaybackFormat "S16_LE S32_LE"` 表明仅支持
|
||
S16_LE 和 S32_LE 的格式播放
|
||
|
||
## 其他
|
||
|
||
### 顺序
|
||
|
||
(与 [interfaces.md](./interfaces.md) 中的 "默认使用案例 API" 相关联)
|
||
|
||
verb, device 和 modifier 的顺序是根据配置文件中的先后位置决定的, 因此在编写配置文
|
||
件时, 尽量将想要默认使用的项放在前面, 保证 alsa-ucm-aw 中的程序能优先选中它们
|
||
|
||
card 则是按照文件名的先后顺序排列, 除了修改名字外, 无法直接规定其顺序
|