ALSA Configure

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/pengfei240/article/details/79064301

0. 前言

本文主要介绍alsa-lib配置文件相关代码的分析内容。

1. 配置文件的路径

在alsa-lib中,函数 snd_config_topdir 用于获取配置文件的路径,有两个方法可以进行配置:

  1. 使用环境变量 ALSA_CONFIG_DIR 进行配置。
  2. 在生成configure时,使用 –with-configdir=dir 进行配置。

默认的路径为 $prefix/share/alsa

2. 相关文档

Configuration files

需要注意以下几点:

  • 数组可以等价于复合结构,alsa-lib的代码最终会把配置文件中的数组分解为等价的复合结构。比如:
a [
    "first"
    "second"
]
等价于
a {
    0  "first"
    1  "second"
}
  • “.”可以看做C++中的作用域符号。

  • 操作模式前缀符号:

“+”: 默认配置,如果节点不存在则create;如果节点存在且类型一致,则merge.
“-“: 如果节点存在且类型一致,则merge.
“?”: 如果节点已经存在则不要覆盖.
“!”: 覆盖,即不检查节点类型的条件下执行merge/create.

Runtime arguments in configuration files

alsa-lib支持运行时参数。

在代码中主要体现在函数 snd_config_expand 的实现上,其处理流程见下一节的橙色部分。该部分主要实现下面的功能:

  1. 解析当前的运行时参数所在的子树,并建立一个新的配置树
  2. 用新的子树以”!”模式覆盖原有的子配置树。

Runtime functions in configuration files

alsa-lib允许在运行时修改节点的配置,一些 snd_func_ 形式的內建函数用于实现该功能。

在代码中主要体现在函数 snd_config_expand 的实现上,该函数用于展开配置文件的参数和內建函数,其处理流程如下:

ALSA_snd_config_expand_Runtime

我们也可以在配置文件中配置自定义的內建函数,以扩展alsa-lib的功能。对应的,配置文件中需要增加相应的配置,如图中粉红色部分。

Hooks in configuration files

alsa-lib允许在运行时扩展节点的配置,在配置文件中通过 @hooks 数组进行配置。

在代码中主要体现在函数 snd_config_hooks 的实现上,该函数在更新配置树时被调用(调用场景可以参见对 snd_pcm_open 处理流程的分析),其自身的处理流程如下:

ALSA_snd_config_hooks_Activity

根据配置文件 alsa.conf 的默认配置,最终会调用函数 snd_config_hook_load 加载其它配置文件。

需要注意,配置节点被加载的位置是当前的hook节点位置,也就是说被加载的配置文件中的各个节点的绝对路径是需要加上根节点到hook节点的路径名称作为前缀的。比如:

# hook节点
cards.@hooks [
{
    ...
    func load_for_all_cards
    ...
}

# 被加载的HDA-Intel.conf文件的内容
HDA-Intel.pcm.default {
    ...
}

此时,该default节点的绝对路径为cards.HDA-Intel.pcm.default。

另外,我们也可以在配置文件中配置其它动态库和hook函数,这样在更新配置树时,这些自定义的函数依然会被 alsa-lib 自动调用,代码的例子可以参见:

增加hook函数

3. 主要代码的分析

解析配置文件的主要实现是 snd_config_update_ref,所有Device的open流程都会调用这个接口,它负责创建原始的配置树,并增加引用计数。

其核心代码是由下列函数完成,该函数负责更新配置信息:

int snd_config_update_r(snd_config_t **_top, snd_config_update_t **_update, const char *cfgs)
_top:返回更新后的配置信息
_update:返回已经更新过的配置文件属性
cfgs:本次需要更新的文件名
函数会将cfgs中的文件依次与_update中保存的该文件的属性进行对比(比如:最后修改时间,inode等),如果文件属性变化或者cfg是新的文件,则更新_top结构。

该函数的处理流程如下:

snd_config_update_r

最终,所有配置文件的信息会汇集成一个树型结构(多叉树)。

4. 配置树内部存储结构

配置树内部使用结构体 snd_config_t 记录配置节点的信息,多个节点的关联结构如下图所述:

Internal Config Structure

5. 配置树主要接口

Configuration Interface

配置文件的主要接口见上面的链接,有几个用的比较频繁的接口在这单独罗列如下:

函数名 功能
snd_config_update_r 更新并引用配置树,后序需要使用snd_config_unref解引用
snd_config_load 从输入对象中载入配置树
snd_config_search / snd_config_searchv 在配置树中搜索一个定义,在搜索过程中不展开
snd_config_search_definition 在配置树中展开搜索一个定义,包括别名,hooks,参数,內建函数
snd_config_expand 展开一个配置节点,包括参数和內建函数

6. 总结:

  1. ALSA配置文件的解析比较繁琐,大量用到了递归和迭代,不建议详细阅读这部分代码。我们只需要从接口函数处知道当前在做什么,操作之后子配置树是什么内容即可。
  2. 实在不清楚某个函数解析后的结果是什么,可以用下面的代码将配置树打印出来,这个代码在源文件中是以注释的形式存在的。
  3. 分析某个hook函数时一定要注意当前的节点位置,通过该函数加入的子配置树一般位于该hook函数的位置,也就是说新加入的节点名字前面有一定的前缀名。
#if 0   /* for debug purposes */
    {
        snd_output_t *out;
        snd_output_stdio_attach(&out, stderr, 0);
        snd_config_save(sconf, out);
        snd_output_close(out);
    }
#endif

猜你喜欢

转载自blog.csdn.net/pengfei240/article/details/79064301