通過插入的 USB 埠區分多個 USB 音效卡
我想要的是能夠始終如一地區分多個 USB 音效卡,通過它們插入的 USB 埠辨識它們,並使用這些知識在我的 Java 程序中的特定音效卡上播放聲音。
到目前為止,我停留在第一部分 - 通過 USB 埠辨識音效卡。
我做的第一件事是遵循這個問題中的建議,並使用 Udev 規則使用來自該站點的腳本為音效卡分配名稱
這些是我添加的 Udev 規則
KERNEL=="controlC[0-9]*", DRIVERS=="usb", PROGRAM="/usr/bin/alsa_name.pl %k", NAME="snd/%c{1}" KERNEL=="hwC[D0-9]*", DRIVERS=="usb", PROGRAM="/usr/bin/alsa_name.pl %k", NAME="snd/%c{1}" KERNEL=="midiC[D0-9]*", DRIVERS=="usb", PROGRAM="/usr/bin/alsa_name.pl %k", NAME="snd/%c{1}" KERNEL=="pcmC[D0-9cp]*", DRIVERS=="usb", PROGRAM="/usr/bin/alsa_name.pl %k", NAME="snd/%c{1}"
這些是內容
alsa_name.pl
use strict; use warnings; # my $alsaname = $ARGV[0]; #udev called us with this argument (%k) my $physdevpath = $ENV{PHYSDEVPATH}; #udev put this in our environment my $alsanum = "cucu"; #you can find the physdevpath of a device with "udevinfo -a -p $(udevinfo -q path -n /dev/snd/pcmC0D0c)" # # $physdevpath =~ s/.*\/([^\/]*)/$1/; #eliminate until last slash (/) $physdevpath =~ s/([^:]*):.*/$1/; #eliminate from colon (:) to end_of_line # if($physdevpath eq "1-1.3.1") { $alsanum="11"; } if($physdevpath eq "1-1.3.2") { $alsanum="12"; } if($physdevpath eq "1-1.3.3") { $alsanum="13"; } if($physdevpath eq "1-1.3.4") { $alsanum="14"; } # if($alsanum ne "cucu") { $alsaname=~ s/(.*)C([0-9]+)(.*)/$1C$alsanum$3/; } # print $alsaname; exit 0;
現在,當我插入我的 USB 音效卡並查看時,
/var/log/syslog
我發現它並不能完全正常工作:NAME="snd/%c{1}" ignored, kernel device nodes cannot be renamed; please fix it in /etc/udev/rules.d/99-com.rules:16
我試圖根據這個提供 Udev 規則的儲存庫修改我的 Udev 規則:
SUBSYSTEM!="sound", GOTO="my_usb_audio_end" ACTION!="add", GOTO="my_usb_audio_end" DEVPATH=="/devices/platform/soc/3f980000.usb/usb1/1-1/1-1.2/1-1.2:1.0/sound/card?", ATTR{id}="SPEAKER" DEVPATH=="/devices/platform/soc/3f980000.usb/usb1/1-1/1-1.3/1-1.3:1.0/sound/card?", ATTR{id}="HEADSET" LABEL="my_usb_audio_end"
所以我使用了我以前的腳本並修改了我的規則:
KERNEL=="pcmC[D0-9cp]*", DRIVERS=="usb", PROGRAM="/usr/bin/alsa_name.pl %k", ATTR{id}="snd/%c{1}
但現在
syslog
告訴我:error opening ATTR{some_very_long_id} for writing: Permission denied
我也試過這個答案並做到了
KERNEL=="pcmC[D0-9cp]*", DRIVERS=="usb", PROGRAM="/usr/bin/alsa_name.pl %k", SYMLINK+="snd/%c{1}
我沒有看到任何錯誤
syslog
,我認為這很好,但是當我列出帶有 的播放設備時aplay -l
,我看到的只是card 1: Device [USB Audio Device], device 0: USB Audio [USB Audio] Subdevices: 1/1 Subdevice #0: subdevice #0
並且沒有任何變化,無論我插入哪個 USB 埠。我在我的 Java 程序中也看不到有用/可區分的資訊,使用
AudioSystem.getMixerInfo()
我的方法是否正確,我只是遺漏了一些細節,或者這是完全錯誤的方向?
根據@meuh 的回答,我設法讓它發揮作用,儘管與我最初的計劃略有不同。
寫入
>/sys/devices/.../sound/card0/id
文件確實是要走的路,所以我為此編寫了一個小 bash 腳本#!/bin/bash for file in $(find /sys/devices/ -name id | grep sound | grep usb) do for fragment in $(echo $file | tr "/" "\n") do if [[ $fragment == *"1.2.1"* ]] then printf "%s" "EXT_B1" > "$file" fi if [[ $fragment == *"1.2.2"* ]] then printf "%s" "EXT_B2" > "$file" fi # etc done done
這部分 -
for fragment in $(echo $file | tr "/" "\n")
- 可能可以做得更優雅,但我不能只使用完整的文件路徑,因為我想使用任何音效卡並僅通過 USB 埠辨識它們,但目前我只有一個音效卡所以我可以’ t 檢查不同型號或供應商的路徑是否發生變化。因此,搜尋1.2.1
描述連接到我設備的特定 USB 埠的 USB 集線器的特定埠的模式等。我還沒有設法使用 udev 規則執行它 - 顯然你需要 root 訪問權限才能寫入
/sys/devices/...
(這是有道理的)但是儘管查看了幾個答案,我還是無法完成它 - 可能是因為我在 Raspberry 上執行 Raspbian Jessie Pi,可能是因為我對 Linux 不太了解。但是,我的案例不一定要求在連接設備時執行該腳本 - 只需在啟動時執行它就足夠了,所以最後一件事是使用
sudo crontab -e
並添加一行來編輯 crontab@reboot /path/to/my/script.sh
瞧,我可以使用 Java 程式碼訪問特定的 USB 音效卡
AudioSystem.getMixerInfo()
並使用播放聲音AudioSystem.getClip(mixerInfo)
你在正確的軌道上。udev 有很多可能出錯的地方。udev 規則
NAME="..."
不再起作用的原因是核心不再允許您以這種方式重命名設備。符號連結的創建與SYMLINK+=
一般工作有關,但我不知道 alsa 是否對它們感興趣。因此,我認為可能正確的解決方案是在標題為“辨識兩個相同的音頻設備”部分的連結文章中給出的建議。使用規則 with匹配設備,並為該設備提供唯一名稱,然後您將在或中找到該名稱。
DEVPATH==``ATTR{id}="ABC"``aplay -l``cat /proc/asound/cards
首先,手動嘗試相同的操作。我沒有任何 USB 音效卡,只有一個內置設備,所以如果我這樣做:
find /sys/devices/ -name id | grep sound
它列出了許多名為“id”的項目,但其中一些是目錄,唯一感興趣的文件是
/sys/devices/.../sound/card0/id
. 如果我cat
這個文件包含設備的名稱(“PCH”)。如果我將字元串寫入此偽文件,它會更改其名稱:sudo sh -c 'printf "%s" MYCARD >/sys/devices/.../sound/card0/id'
這可以在 的輸出中看到
aplay -l
。這就是你試圖用 udev 做的事情;sysfs偽文件id
是. 因此,在 udev 中,僅當您在正確的目錄中匹配時才有效,即在我的情況下。這就是 udev 規則說的原因(卡號可能會更改,因此它被萬用字元 glob 字元“?”替換)。card0``ATTR{id}=``/sys``/sys/devices/.../sound/card0``DEVPATH=="/sys/devices/.../sound/card?"
有關更完整的範例,請參閱連結的上述部分,該部分為您提供了完整的規則文件
85-my-usb-audio.rules
。