Alsa-lib层,为不同的驱动提供统一的接口alsa API,简化了开发人员对于驱动层的调用开发。接口定义地址:
https://www.alsa-project.org/alsa-doc/alsa-lib/
关于asound.conf的配置,可以参考官网解释:
https://www.alsa-project.org/main/index.php/Asoundrc
详细的插件讲解,官网网址:
https://www.alsa-project.org/alsa-doc/alsa-lib/pcm_plugins.html
asound.conf配置文件,是alsa-lib的默认配置文件,路径在 /etc/,可以用来配置alsa库的一些附加功能。这个文件不是alsa库运行时所必须的,没有它alsa库也可以正常运行。asound.conf允许对声卡或者设备进行更高级的控制,提供访问alsa-lib中的pcm插件方法,允许你做更多的复杂的控制,比如可以把声卡组合成一个或者多声卡访问多个I/O。
ps:在usr/local/shar/alsa/中有一个文件叫---alsa.conf,asound.conf 这个文件在调用snd_pcm_open这个api函数时,会被加载同时解析。
在ALSA中,PCM插件扩展了PCM设备的功能和特性。插件可以自动处理诸如:命名设备、采样率转换、通道间的采样复制、写入文件、为多个输入/输出连接声卡/设备(不同步采样)、使用多通道声卡/设备等工作。
此插件直接与ALSA内核驱动程序通信,它是一种没有任何转换的原始通信。
pcm.name {
type hw # Kernel PCM
card INT/STR # Card name (string) or number (integer)
[device INT] # Device number (default 0)
[subdevice INT] # Subdevice number (default -1: first available)
[sync_ptr_ioctl BOOL] # Use SYNC_PTR ioctl rather than the direct mmap access for control structures
[nonblock BOOL] # Force non-blocking open mode
[format STR] # Restrict only to the given format
[channels INT] # Restrict only to the given channels
[rate INT] # Restrict only to the given rate
[chmap MAP] # Override channel maps; MAP is a string array
}
nonblock选项指定设备是否以非阻塞方式打开。注意此选项并不会更改读/写访问的阻塞行为。只影响打开设备时的阻塞行为。如果想保持与旧ALSA版本的兼容性,请关闭此选项。
下面是一个例子:
pcm.!default {
type hw
card 0
}
ctl.!default {
type hw
card 0
}
名字为default的声卡,指向card0,也就是hw:0,0,测试命令:aplay -D default test.wav
hw后面跟的数字是声卡号和设备号,可以用如下命令查看硬件支持声卡数:
cat /proc/asound/cards 或者 ls /dev/dns. (pcm0c
(capture), pcm0p
(playback))
在ALSA中,PCM插件扩展了PCM设备的功能和特性。插件可以自动处理诸如:命名设备、采样率转换、通道间的采样复制、写入文件、为多个输入/输出连接声卡/设备(不同步采样)、使用多通道声卡/设备等工作。要使用它们,开发者需要创建一个虚拟从属设备(slave device)。
pcm_slave.NAME {
pcm STR # PCM name
# or
pcm { } # PCM definition
format STR # Format or "unchanged"
channels INT # Count of channels or "unchanged" string
rate INT # Rate in Hz or "unchanged" string
period_time INT # Period time in us or "unchanged" string
buffer_time INT # Buffer time in us or "unchanged" string
}
一个最简单的slave用例:
pcm_slave.sltest {
pcm "hw:1,0"
}
在slave设备配置中加入采样率转换:
pcm_slave.sl2 {
pcm "hw:1,0"
rate 48000
}
pcm.rate_convert {
type rate
slave sl2
}
调用这个接口,44.1k的采样频率的音频将会转换为48khz输出。
可以用aplay命令测试创建的虚拟设备:
aplay -D rate_convert test.wav
上图的slave配置的另一种方式,两种方式等同:
pcm.rate_convert {
type rate
slave {
pcm "hw:1,0"
rate 48000
}
}
上面的用例用到了 Plugin: Rate
这个插件可以转换采样率,但是输入输出格式必须为线型。
pcm.name {
type rate # Rate PCM
slave STR # Slave name
# or
slave { # Slave definition
pcm STR # Slave PCM name
# or
pcm { } # Slave PCM definition
rate INT # Slave rate
[format STR] # Slave format
}
converter STR # optional
# or
converter [ STR1 STR2 ... ] # optional
# Converter type, default is taken from
# defaults.pcm.rate_converter
# or
converter { # optional
name STR # Convertor type
xxx yyy # optional convertor-specific configuration
}
}
此插件可以转换声道数和应用声音。转换声音这个我没有很明白,官网也没有给出具体的用例。
pcm.name {
type route # Route & Volume conversion PCM
slave STR # Slave name
# or
slave { # Slave definition
pcm STR # Slave PCM name
# or
pcm { } # Slave PCM definition
[format STR] # Slave format
[channels INT] # Slave channels
}
ttable { # Transfer table (bi-dimensional compound of cchannels * schannels numbers)
CCHANNEL {
SCHANNEL REAL # route value (0.0 - 1.0)
}
}
}
这个插件可以转换channels、rate和format,可以理解为是rate和Route & Volume的集合体。
pcm.name {
type plug # Automatic conversion PCM
slave STR # Slave name
# or
slave { # Slave definition
pcm STR # Slave PCM name
# or
pcm { } # Slave PCM definition
[format STR] # Slave format (default nearest) or "unchanged"
[channels INT] # Slave channels (default nearest) or "unchanged"
[rate INT] # Slave rate (default nearest) or "unchanged"
}
route_policy STR # route policy for automatic ttable generation
# STR can be 'default', 'average', 'copy', 'duplicate'
# average: result is average of input channels
# copy: only first channels are copied to destination
# duplicate: duplicate first set of channels
# default: copy policy, except for mono capture - sum
ttable { # Transfer table (bi-dimensional compound of cchannels * schannels numbers)
CCHANNEL {
SCHANNEL REAL # route value (0.0 - 1.0)
}
}
rate_converter STR # type of rate converter
# or
rate_converter [ STR1 STR2 ... ]
# type of rate converter
# default value is taken from defaults.pcm.rate_converter
}
看一下小例子:
pcm.nfbtout {
type plug
slave {
pcm "hw:1,0"
rate 8000
channels 2
}
}
有了一个本地的alsa插件,叫做dmix(直接混合)插件。它允许软件混合在一个易于使用的语法中,而不需要先安装/理解一个新的应用程序。但是需要注意的一点:The resolution for 32-bit mixing is only 24-bit. The low significant byte is filled with zeros. The extra 8 bits are used for the saturation.
注意,dmix插件不是基于客户机/服务器架构,而是直接写入声卡的dma缓冲区。一次可以运行的实例数量没有限制。
pcm.name {
type dmix # Direct mix
ipc_key INT # unique IPC key
ipc_key_add_uid BOOL # add current uid to unique IPC key
ipc_perm INT # IPC permissions (octal, default 0600)
hw_ptr_alignment STR # Slave application and hw pointer alignment type
# STR can be one of the below strings :
# no
# roundup
# rounddown
# auto (default)
slave STR
# or
slave { # Slave definition
pcm STR # slave PCM name
# or
pcm { } # slave PCM definition
format STR # format definition
rate INT # rate definition
channels INT
period_time INT # in usec
# or
period_size INT # in bytes
buffer_time INT # in usec
# or
buffer_size INT # in bytes
periods INT # when buffer_size or buffer_time is not specified
}
bindings { # note: this is client independent!!!
N INT # maps slave channel to client channel N
}
slowptr BOOL # slow but more precise pointer updates
}
ipc_key必须是整数形式的唯一ipc key。对于每个不同的dmix定义,这个数字必须是唯一的,因为共享内存是用这个key创建的。当ipc_key_add_uid设置为true时,uid值将添加到ipc_key设置中。这样可以避免同一个IPC密钥与不同用户同时发生冲突。
hw_ptr_alignment这个配置默认是auto,其他配置可以去上面贴的第三个网址中了解。
注意,dmix插件本身只支持单个配置。也就是说,它只支持固定rate(默认48000)、format(s16)、channels(2)和period_time (125000)。对于使用其它配置,开发者必须在从PCM定义中明确设置该值。
一个用例:
pcm.dmix_44 {
type dmix
ipc_key 321456 # any unique value
ipc_key_add_uid true
slave {
pcm "hw:0"
format S32_LE
rate 44100
}
}
可以利用这个配置的声卡播放一个48k 的音频:aplay -Dplug:dmix_44 foo_48k.wav
对于使用OSS仿真设备的dmix插件,必须将period和buffer sizes设置为2的幂次方。例如:
pcm.dmixoss {
type dmix
ipc_key 321456 # any unique value
ipc_key_add_uid true
slave {
pcm "hw:0"
period_time 0
period_size 1024 # must be power of 2
buffer_size 8192 # ditto
}
}
period_time必须为0,对于带有多通道IO的声卡,添加绑定也非常有用。(官网中的这句,我不是很明白),绑定的用例:
pcm.dmixoss {
...
bindings {
0 0 # map from 0 to 0
1 1 # map from 1 to 1
}
}
此插件将一个capture流拆分为多个。它的工作方式与dmix插件相反,从多个客户端同时读取共享捕获缓冲区。以下参数的含义与dmix插件几乎相同。
pcm.name {
type dsnoop # Direct snoop
ipc_key INT # unique IPC key
ipc_key_add_uid BOOL # add current uid to unique IPC key
ipc_perm INT # IPC permissions (octal, default 0600)
slave STR
# or
slave { # Slave definition
pcm STR # slave PCM name
# or
pcm { } # slave PCM definition
format STR # format definition
rate INT # rate definition
channels INT
period_time INT # in usec
# or
period_size INT # in bytes
buffer_time INT # in usec
# or
buffer_size INT # in bytes
periods INT # when buffer_size or buffer_time is not specified
}
bindings { # note: this is client independent!!!
N INT # maps slave channel to client channel N
}
slowptr BOOL # slow but more precise pointer updates
}