Membedakan beberapa kartu suara USB dengan port USB yang dicolokkan
Yang saya inginkan adalah dapat secara konsisten membedakan beberapa kartu suara USB, mengidentifikasinya dengan port USB yang dicolokkan dan menggunakan pengetahuan itu untuk memutar suara pada kartu suara tertentu dalam program Java saya.
Sejauh ini saya terjebak di bagian pertama - mengidentifikasi kartu suara dengan port USB.
Hal pertama yang saya lakukan adalah mengikuti saran dalam pertanyaan ini dan menggunakan aturan Udev untuk menetapkan nama ke kartu suara dengan skrip dari situs ini
Ini adalah aturan Udev yang saya tambahkan
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}"
dan ini adalah isi dari 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;
Sekarang, ketika saya mencolokkan kartu suara USB saya dan melihat /var/log/syslog
saya melihat bahwa itu tidak benar-benar berfungsi:
NAME="snd/%c{1}" ignored, kernel device nodes cannot be renamed; please fix it in /etc/udev/rules.d/99-com.rules:16
Saya mencoba mengubah aturan Udev saya berdasarkan repositori ini yang menyediakan aturan 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"
Jadi saya menggunakan skrip saya sebelumnya dan mengubah aturan saya:
KERNEL=="pcmC[D0-9cp]*", DRIVERS=="usb", PROGRAM="/usr/bin/alsa_name.pl %k", ATTR{id}="snd/%c{1}
tapi sekarang syslog
beri tahu saya:
error opening ATTR{some_very_long_id} for writing: Permission denied
Saya juga mencoba jawaban ini dan melakukannya
KERNEL=="pcmC[D0-9cp]*", DRIVERS=="usb", PROGRAM="/usr/bin/alsa_name.pl %k", SYMLINK+="snd/%c{1}
Saya tidak melihat kesalahan apa pun syslog
, yang menurut saya bagus, tetapi ketika saya mencantumkan perangkat pemutaran aplay -l
, yang saya lihat hanyalah
card 1: Device [USB Audio Device], device 0: USB Audio [USB Audio]
Subdevices: 1/1
Subdevice #0: subdevice #0
dan tidak ada yang berubah, sehubungan dengan port USB mana yang saya colokkan. Saya juga tidak melihat info yang berguna / dapat dibedakan dalam program Java saya menggunakan AudioSystem.getMixerInfo()
Apakah pendekatan saya benar dan saya hanya melewatkan beberapa detail, atau ini sepenuhnya salah arah?
Jawaban
Anda berada di jalur yang benar. Ada banyak hal yang bisa salah dengan udev. Alasan aturan udev dengan NAME="..."
tidak berfungsi lagi adalah karena kernel tidak lagi mengizinkan Anda untuk mengganti nama perangkat dengan cara ini. Penciptaan tautan simbolik dengan SYMLINK+=
pekerjaan secara umum, tetapi saya tidak tahu apakah alsa tertarik padanya.
Jadi saya pikir solusi yang mungkin benar adalah saran yang diberikan dalam artikel tertaut Anda di bagian berjudul Mengidentifikasi dua perangkat audio yang identik . Gunakan aturan dengan DEVPATH==
untuk mencocokkan perangkat, dan ATTR{id}="ABC"
untuk memberi nama unik pada perangkat itu yang kemudian akan Anda temukan di aplay -l
atau cat /proc/asound/cards
.
Pertama, coba hal yang sama secara manual. Saya tidak memiliki kartu suara usb tetapi hanya perangkat bawaan, jadi jika saya memilikinya:
find /sys/devices/ -name id | grep sound
itu mendaftar banyak item bernama "id", tetapi beberapa di antaranya adalah direktori, dan satu-satunya file yang menarik adalah /sys/devices/.../sound/card0/id
. Jika saya cat
file ini memegang nama perangkat ("PCH"). Jika saya menulis string ke dalam file semu ini, namanya berubah:
sudo sh -c 'printf "%s" MYCARD >/sys/devices/.../sound/card0/id'
dan ini terlihat pada keluaran aplay -l
. Inilah yang Anda coba lakukan dengan udev; pseudo-file sysfs id
adalah atribut dari card0
. Jadi di udev, ATTR{id}=
hanya berfungsi jika Anda telah mencocokkan di /sys
direktori yang benar , yaitu /sys/devices/.../sound/card0
dalam kasus saya. Inilah mengapa aturan udev mengatakan DEVPATH=="/sys/devices/.../sound/card?"
(nomor kartu dapat berubah sehingga diganti dengan karakter glob kartu liar "?").
Untuk contoh yang lebih lengkap, lihat bagian yang disebutkan di atas dari tautan yang memberi Anda file aturan lengkap 85-my-usb-audio.rules
.
Berdasarkan jawaban @ meuh, saya berhasil menjalankannya, meskipun sedikit berbeda dari yang saya rencanakan.
Menulis ke >/sys/devices/.../sound/card0/id
file memang cara yang harus dilakukan, jadi saya menulis sedikit skrip bash untuk tujuan itu
#!/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
Bagian ini - for fragment in $(echo $file | tr "/" "\n")
- mungkin bisa dilakukan dengan lebih elegan, tetapi saya tidak bisa hanya menggunakan jalur file lengkap, karena saya ingin menggunakan kartu suara apa pun dan mengidentifikasinya hanya melalui port USB, tetapi saat ini saya hanya memiliki satu kartu suara jadi saya bisa ' t periksa apakah jalur itu berubah untuk model atau vendor yang berbeda. Oleh karena itu mencari pola 1.2.1
dll menjelaskan port spesifik dari hub USB yang terhubung ke port USB spesifik perangkat saya.
Saya belum berhasil menjalankannya menggunakan aturan udev - tampaknya Anda memerlukan akses root untuk menulis /sys/devices/...
(yang masuk akal) tetapi meskipun melihat beberapa jawaban, saya tidak dapat menyelesaikannya - mungkin karena saya menjalankan Raspbian Jessie di Raspberry Pi, mungkin karena saya tidak tahu banyak tentang Linux.
Namun, kasus penggunaan saya tidak selalu mengharuskan skrip itu dijalankan saat menghubungkan perangkat - cukup menjalankannya saat boot sudah cukup, jadi hal terakhir yang diperlukan adalah mengedit crontab menggunakan sudo crontab -e
dan menambahkan baris
@reboot /path/to/my/script.sh
Dan voila , saya bisa mendapatkan akses kartu suara USB khusus dalam kode Java menggunakan AudioSystem.getMixerInfo()
dan memutar suara menggunakanAudioSystem.getClip(mixerInfo)