【DAPDM 三】--- Audio paths 与 asound.conf

罗鸿畴
2023-12-01


通过配置好asound.conf,上层则可打开asound.conf中定义的虚拟设备,而自动选择相应的音频通道。
这是asound.conf很重要的一个作用,从这方面来说,并不是跟dapm完全没关系。

三、Audio paths 与 asound.conf

3.1 认识 asound.conf 和 .asoundrc

做alsa的基本都能体会到alsa-lib的复杂与强大,而alsa-lib的强大正是从asound.conf与.asoundrc等配置文件体现出来。
alsa驱动开发只是一个方面,而真正想随心所欲的配置音频设备,asound.conf与.asoundrc的掌握是必不可少的。
所幸,这方面的资料还是比较丰富,所需了解的知识点基本都能从官网上找到文档甚至example。

http://www.alsa-project.org/alsa-doc/alsa-lib/pcm_plugins.html
https://alsa.opensrc.org/

重要: https://alsa.opensrc.org/Asoundrc


.asoundrc 和 /etc/asound.conf 是 alsa 驱动的配置文件,这两个文件不是alsa 正常工作所必须要的文件。

这两个文件最主要的作用还是用于配置 audio 虚拟设备的功能。

The main use of these two configuration files is to add functionality 
such as routing and sample-rate conversion. 

It allows you to create "virtual devices" that pre or post-process audio streams. 

Any properly written ALSA program can use these virtual devices 
as though they were normal devices.

主要件用是 客制化声卡配置。

One is to create a personalized configuration for a soundcard.
This is useful if you have a 32-channel soundcard and want to reserve 5 channels permanently for recording the drums.
For example, you could create a new PCM called “drumrec” that is always mapped to the same five inputs.
The .asoundrc file is quite complicated. You may find it simpler to use the dmix plugin.

Lastly similar .asoundrc files are used internally by ALSA to “map” standard things,
for example, to connect “default” to “plughw:0” (this too could be overridden). The configuration is in the file /usr/share/alsa/alsa.conf

If you’re happy with how your card is working, there’s no need to use an .asoundrc. There is also not much use in taking an .asoundrc for a 10-channel soundcard and hoping to get more out of a 2-channel (stereo) soundcard.
But if you want or have to customize the behaviour of a soundcard to be different from the standard setting, an .asoundrc is essential.


3.1.1 创建声卡别名(虚拟声卡)

格式如下:

pcm.NAME {
    type hw # Kernel PCM
    card INT/STR # Card name or number
    [device] INT # Device number (default 0)
    [subdevice] INT # Subdevice number, -1 first available (default -1)
    mmap_emulation BOOL # enable mmap emulation for ro/wo devices
}

Here is another example which gives the first soundcard an alias:
Now you can access this card by the alias “ens1371”.

pcm.ens1371 {
    type hw
    card 0
    device 0
}

aplay -D ens1371 test.wav

3.1.2 创建一个虚拟子设备

示例一、

pcm_slave.sltest {
    pcm ens1371
}

pcm_slave.sl2 {
    pcm ens1371
    rate 44100
}

pcm.rate_convert {
    type rate
    slave sl2
}

Now you can use this newly created (virtual) device by:

aplay -D rate_convert test.wav

示例二、

pcm_slave.sl3 {
    pcm ens1371
    format S16_LE
    channels 1
    rate 16000
}
pcm.complex_convert {
    type plug
Here, the controls "Wave Surround Playback Volume" and "EMU10K1 PCM Send Volume" are set to the given values when this pcm is accessed. Since these controls take multi-dimensional values, the value field is written as an array. When preserve is true, the old values are saved and restored when the pcm is closed. The lock means that the control is locked during this pcm is opened, and cannot be changed by others. When optional is set, no error is returned but ignored even if the specified control doesn't exist.    slave sl3
}

By calling it with:

aplay -vD complex_convert test.wav

3.2 配置 audio path

首先我们先看看plugin中hooks: https://blog.csdn.net/azloong/article/details/6384249

This plugin is used to call some ‘hook’ function when this plugin is opened, modified or closed. Typically, it is used to change control values for a certain state specially for the PCM (see the example below).

# Hook arguments definition
hook_args.NAME {
    ...         # Arbitrary arguments
}
# PCM hook type
pcm_hook_type.NAME {
    [lib STR]       # Library file (default libasound.so)
    [install STR]       # Install function (default _snd_pcm_hook_NAME_install)
}
# PCM hook definition
pcm_hook.NAME {
    type STR        # PCM Hook type (see pcm_hook_type)
    [args STR]      # Arguments for install function (see hook_args)
    # or
    [args { }]      # Arguments for install function
}
# PCM hook plugin
pcm.NAME {
    type hooks      # PCM with hooks
    slave STR       # Slave name
    # or
    slave {         # Slave definition
        pcm STR     # Slave PCM name
        # or
        pcm { }     # Slave PCM definition
    }
    hooks {
        ID STR      # Hook name (see pcm_hook)
        # or
        ID { }      # Hook definition (see pcm_hook)
    }
}

Example:
hooks.0 {
    type ctl_elems
    hook_args [
        {
            name "Wave Surround Playback Volume"
            preserve true
            lock true
            optional true
            value [ 0 0 ]
        }
        {
            name "EMU10K1 PCM Send Volume"
            index { @func private_pcm_subdevice }
            lock true
            value [ 0 0 0 0 0 0 255 0 0 0 0 255 ]
        }
    ]
}

Here, the controls “Wave Surround Playback Volume” and “EMU10K1 PCM Send Volume” are set to the given values when this pcm is accessed. Since these controls take multi-dimensional values, the value field is written as an array. When preserve is true, the old values are saved and restored when the pcm is closed. The lock means that the control is locked during this pcm is opened, and cannot be changed by others. When optional is set, no error is returned but ignored even if the specified control doesn’t exist.


我们可以定义一个名为NAME的hook plugin,在这个plugin中,我们可以操作之前提到的dapm kcontrol,达到音频通道切换的目的。

另外注意:
When preserve is true, the old values are saved and restored when the pcm is closed.
当preserve设置为true时,则该pcm关闭时,kcontrol会恢复到之前的值.

The lock means that the control is locked during this pcm is opened, and cannot be changed by others.
当lock设置为true时,则在该pcm打开期间,kcontrol的值不会被其他的pcm改变.

When optional is set, no error is returned but ignored even if the specified control doesn’t exist.
当optional设置为true时,则指定的kcontrol不存在时不会返回错误.


3.3 示范配置

以《【DAPDM 二】— Audio paths 与 DAPM Kcontrol》的红色线路为例,
在Android平台上写一个linein录音直送到SPK输出的hooks plugin:

pcm.AndroidPlayback_Speaker_normal {
	type hooks 
	slave.pcm { 
		type hw 
		card 0 
		device 0 
	} 
	hooks.0 { 
		type ctl_elems 
		hook_args [
			{ 
				name 'Left Input PGA Switch' 
				value true 
			}
			{ 
				name 'Left Input PGA LINPUT1 Switch' 
				preserve true   // 关闭时,kcontrol 配置自动恢复
				lock true		// 打开期间,kcontrol 配置不会被其他 pcm 修改
				value true 
			}
			{ 
				name 'Left Input Mixer Input PGA Switch'
				preserve true	// 关闭时,kcontrol 配置自动恢复
				lock true 		// 打开期间,kcontrol 配置不会被其他 pcm 修改
				value true 
			}
			{ 
				name 'Left Output Mixer Left Input Mixer Switch'
				preserve true	// 关闭时,kcontrol 配置自动恢复
				lock true 		// 打开期间,kcontrol 配置不会被其他 pcm 修改
				value true 
			}
			{ 
				name 'LINEOUT1 Switch' 
				value true 
			}
		] 
	}
}

把这个 asound.conf 放到 /etc 目录下,再启动 Android 可以做这个测试,应该可以听到 Line in 输入的录音信号直接在 SPK 上输出。

Android的三种模式:normal、ringtone和incall,这些模式的音频通道切换也是可以通过这样配置asound.conf实现的。

Date: 20190923-11:23

 类似资料: