我有几个业余无线电,通过 USB 连接到我的 Linux 计算机。收音机将自己呈现为声卡,并且如下所示:
$ aplay -l
[...]
card 1: CODEC [USB Audio CODEC], device 0: USB Audio [USB Audio]
Subdevices: 1/1
Subdevice #0: subdevice #0
card 2: CODEC_1 [USB Audio CODEC], device 0: USB Audio [USB Audio]
Subdevices: 1/1
Subdevice #0: subdevice #0
$ arecord -l
**** List of CAPTURE Hardware Devices ****
card 1: CODEC [USB Audio CODEC], device 0: USB Audio [USB Audio]
Subdevices: 1/1
Subdevice #0: subdevice #0
card 2: CODEC_1 [USB Audio CODEC], device 0: USB Audio [USB Audio]
Subdevices: 0/1
Subdevice #0: subdevice #0
它们在 USB 上显示为:
$ lsusb | grep Audio
$ lsusb | grep Aud
Bus 001 Device 102: ID 08bb:2901 Texas Instruments PCM2901 Audio Codec
Bus 001 Device 099: ID 08bb:2901 Texas Instruments PCM2901 Audio Codec
这里的问题是我有一个软件想要与其中之一交谈,但它不知道是哪一个。该软件(js8call 和 wsjtx)仅允许我从下拉列表中选择名称,并记住所选的名称。
此下拉列表中的名称是:
alsa_input.usb-Burr-Brown_from_TI_USB_Audio_CODEC-00.analog-stereo
alsa_input.usb-Burr-Brown_from_TI_USB_Audio_CODEC-00.analog-stereo.2
其他软件(例如direwolf)需要设备采用“plughw:2,0”格式,而其他无线电是“plughw:1,0”。
但哪个是哪个并不一致。这取决于 Linux 何时检测到它们,在最好的情况下是我插入它们的顺序,在正常情况下,这是一个竞争条件,因为两者都插入并使用相同的电源,所以它们在当我打开电源的同时。
那么,如何让 Linux 以一致的方式命名这两个声音设备,以便每次碰巧以不同的顺序检测到它们时,我都不必编辑配置文件并更改 UI 中的设置?
答案1
下拉列表中的名称类似于 PulseAudio 源名称:请参阅pacmd dump
。它们将包括 USB 声音设备的序列号,该序列号在标准 USB 设备描述符中(请参阅 参考资料lsusb -d 08bb:2901 -v | grep iSerial
)。如果无线电设备没有可被 Linux 检测到的唯一标识符,那么让它们的命名保持一致可能会很困难。
PulseAudio 名称似乎是根据属性生成的ID_ID
,请查看udevadm info -q property -p /sys/class/sound/card<N>
相关<N>
声音设备的编号(从 开始card0
)。
您也许能够制定一个自定义 udev 规则,该规则使用例如ID_PATH
属性来根据无线电所插入的物理 USB 端口来识别无线电,并ENV{ID_ID}
根据该属性调整属性以允许唯一标识每个无线电的接口。
plughw:N,0
.asoundrc
// names是ALSA/etc/alsa/conf.d
设备名,参见arecord -L
(注大写L)。该N
数字等于 udev 属性ATTR{number}
,可通过 udevadm info -q all -a -p /sys/class/sound/card<N>
.
plughw:CARD=<name>,DEV=0
如果操作系统版本不太旧,您也许可以使用类似的名称。该<name>
部分基于 udev 属性ATTR{id}
,可通过udevadm info -q all -a -p /sys/class/sound/card<N>
.
是否可以通过 udev 规则修改ATTR{number}
或ATTR{id}
属性似乎取决于您的系统具有哪个版本的 udev:较新版本的 udev 似乎比旧版本更严格,或者可能较新的系统具有更复杂的 udev 规则集,而我只是没有没有找到正确的设置方法。
udev 规则的顺序很重要:您可能需要研究 Linux 发行版的现有 udev 规则,以了解是否应该设置自己的规则来激活前或者后发行版的标准规则,以便您的规则真正生效。旧发行版过去将所有 udev 规则放在一个目录中:现代发行版/etc/udev/rules.d/
用于本地自定义,而系统标准规则位于[/usr]/lib/udev/rules.d/
.
/etc/udev/rules.d/
在现代发行版中,如果系统标准规则目录中和系统标准规则目录中都存在同名规则文件,则该文件/etc/udev/rules.d/
将覆盖相应的标准文件,因此您永远不需要修改标准规则目录中的任何文件。 . 因此您的自定义设置也不会被软件包更新覆盖。
作为 ALSA 的替代解决方案,如果您发现无法修改所需的 udev 属性,您可以让 udev/etc/alsa/conf.d/*.conf
为您生成一个系统范围的文件,该文件在通过一些合适的 udev 属性识别您的无线电后定义合适的自定义 ALSA 设备名称。
ALSA 文档有一个旧示例,介绍如何通过连接的 USB 端口将 ALSA 设备编号分配给 USB 设备:
https://alsa.opensrc.org/Udev#A_working_example
它相当复杂,需要编译一个小程序来充当 udev 助手,并且旨在处理音频输出而不是输入设备,但它应该是一个可行的起点。它还包括一些您不需要的功能,即设置一个包含所有插入的 USB 声音设备的组合输出设备。
答案2
id
最简单的解决方案是根据 USB 路径覆盖该属性。
似乎简单的解决方案是将其放入/etc/udev/rules.d/99-myrules.conf
:
SUBSYSTEM=="sound",KERNELS=="1-1.4.4:1.0",ATTR{id}="CODEC_7300"
SUBSYSTEM=="sound",KERNELS=="1-1.3.4:1.0",ATTR{id}="CODEC_9700"
取KERNELS
from udevadm info -ap /sys/class/sound/controlC2
,其中2
是声卡的索引。
上面是简短的答案,并针对带有公开 ID 的下拉列表的程序解决了这个问题。
其他线程上的好问题和答案:
虽然这并没有设置一致的 ALSA 声卡编号,但它确实可以很明显地看出哪个是哪个。每aplay -l
:
**** List of PLAYBACK Hardware Devices ****
[...]
card 2: CODEC_7300 [USB Audio CODEC], device 0: USB Audio [USB Audio]
Subdevices: 1/1
Subdevice #0: subdevice #0
card 3: CODEC_9700 [USB Audio CODEC], device 0: USB Audio [USB Audio]
Subdevices: 1/1
Subdevice #0: subdevice #0
如果您想更进一步并获得一致的 ALSA 编号,您可以创建一组符号链接。例如
KERNEL=="controlC[0-9]*", DRIVERS=="usb", PROGRAM="/usr/bin/alsa_name.sh %k", SYMLINK+="%c"
KERNEL=="hwC[D0-9]*", DRIVERS=="usb", PROGRAM="/usr/bin/alsa_name.sh %k", SYMLINK+="%c"
KERNEL=="midiC[D0-9]*", DRIVERS=="usb", PROGRAM="/usr/bin/alsa_name.sh %k", SYMLINK+="%c"
KERNEL=="pcmC[D0-9cp]*", DRIVERS=="usb", PROGRAM="/usr/bin/alsa_name.sh %k", SYMLINK+="%c"
并有一个脚本来检查路径并返回合适的名称。例如
#!/bin/bash
NAME="$1"
if echo "$DEVPATH" | grep 1-1.4; then
NAME="$(echo "$NAME" | sed -r 's/(.*)C([0-9]+)(.*)/\1C11\3/')"
fi
if echo "$DEVPATH" | grep 1-1.3; then
NAME="$(echo "$NAME" | sed -r 's/(.*)C([0-9]+)(.*)/\1C12\3/')"
fi
exec echo "snd/$NAME"
然后您可以创建一个一致的 PulseAudio 设备,如下所示:
N=11
DEV="radio-7300"
pacmd load-module module-alsa-card \
device_id="${N}" name="${DEV}" \
card_name="alsa_card.platform-${DEV}_audio" \
namereg_fail=false tsched=no fixed_latency_range=no \
ignore_dB=no deferred_volume=yes use_ucm=yes \
card_properties="module-udev-detect.discovered=1"
pacmd suspend-sink alsa_output.${DEV}.analog-stereo no
pacmd suspend-source alsa_input.${DEV}.analog-stereo no