我有幾個業餘無線電,透過 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