alsa-lib的alsa.conf
alsa-lib的alsa.conf
最近看alsa系统,发现在alsa第一层借口下会有一层配置层,第一层接口通过配置参数调用动态库中指定的函数。这些函数才会去真正操作音频设备节点。
据说alsa.conf功能很强大,现在遇到的问题是,这个中间层对继续梳理alsa上层的调用过程造成了一些麻烦。所以,在这里吧alsa.conf相关的内容整理一哈。
alsa.conf结构和处理过程
alsa.conf主要用来保存一些变量的值。为了完成这个功能,alsa.conf中有三种变量compound(符合类型),string和integer。其中数组也是一种compound,func是作为string出现的,之后在内部进行扩展解释。
alsa.conf最终被解释为一棵树,它的节点是struct _snd_config结构,三种类型的变量都用此结构表示。
struct _snd_config {
char *id; //节点名
snd_config_type_t type; //节点类型
union {
long integer;
long long integer64;
char *string;
double real;
const void *ptr;
struct {
struct list_head fields; //作为compound时的子节点链表
int join;
} compound;
} u;
struct list_head list; //将会链如父节点链表中
snd_config_t *parent;
int hop;
};
如下为compound类型外部的赋值语句(在配置文件中第一次出现对该变量的赋值):
defaults.namehint.showall off
赋值语句格式是 var value(变量+space+值)。这里的值是一个字符串。首先构造一个id为defaults,type为compound类型的node(每个node都是struct _snd_config结构),namehint下一个compound节点,并且是defaults的子节点,showall是compound namehint的子节点,它是string类型的,它的值是off。
下面是整数类型的赋值
defaults.ctl.card 0
defaults是刚才构造的compound节点,添加新的ctl compound节点到defaults节点中,card是ctl下的integer类型的节点,它的值为0。
下面这种形式的赋值是一种引用,但是在构造时,就是简单的字符串赋值
defaults.pcm.dmix.card defaults.pcm.card
card是string类型的节点,它的值是字符串defaults.pcm.card. 综上,string和integer类型的节点一定是叶子节点。
运行是构造的节点连接结构如下图
常见的compound结构如下,在pcm compound节点下,用标准方式构造hw compound节点。
pcm.hw {
@args [ CARD DEV SUBDEV ]//参数数组,得到@args compound,下面有id为0,值为CARD的string节点等
@args.CARD { //@args compound节点下有CARD compound节点
type string
default {
@func getenv //特殊字符串节点
vars [
ALSA_PCM_CARD
ALSA_CARD
]
default {
@func refer
name defaults.pcm.card
}
}
}
@args.DEV {
type integer
default {
@func igetenv
vars [
ALSA_PCM_DEVICE
]
default {
@func refer
name defaults.pcm.device
}
}
}
@args.SUBDEV {
type integer
default {
@func refer
name defaults.pcm.subdevice
}
}
type hw
card $CARD //字符串节点,它的值引用参数CARD
device $DEV
subdevice $SUBDEV
hint {
show {
@func refer
name defaults.namehint.extended
}
description "Direct hardware device without any conversions"
}
}
pcm.hw节点在运行过程中会被展开,最终得到展开后的节点。
hw {
type hw
card card_val
device dev_val
subdevice subdev_val
hint {
show show_val
description "Direct hardware device without any conversions"
}
}
card_val, dev_val和subdev_val根据@args获得,show_val由函数展开获得。
函数展开时如下
default {
@func refer
name defaults.pcm.card
}
展开时会调用snd_func_refer函数,根据name的值deaults.pcm.card,搜索全局获得对应的实际值返回作为default的值default_val.
变为
default {
@func getenv
vars [
ALSA_PCM_CARD
ALSA_CARD
]
default default_val
}
接下来调用snd_func_getenv函数,使用getenv获取vars中所列的两个环境变量,若都为空,则返回default的值作为最外层的default_val. 若有一个不为空,则返回值做为最外层的default_val.
此时根据@args的信息生成新的节点subs
subs {
CARD {
type string
default default_val
}
DEV {
type integer
default default_val
}
SUBDEV {
type integer
default default_val
}
}
根据展开得到的新节点信息,hw就被展开为最后的形式。
继续添加中。。。。。。。。。。