複数のUSBサウンドカードが接続されているUSBポートで区別

複数の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()

私のアプローチが正確で、いくつかの詳細がありませんか?それとも完全に間違った方向ですか?

答え1

あなたは正しい道を行っています。 udevには問題が発生する可能性があるものがたくさんあります。 udevルールが機能しなくなった理由NAME="..."は、カーネルがこのようにデバイス名を変更することを許可していないためです。シンボリックリンクの生成は通常仕事に関連していますが、SYMLINK+=alsaがそれに興味があるかどうかはわかりません。

だから、おそらく正しい解決策はあなたに与えられた提案だと思います。リンクされた記事タイトルに2つの同じオーディオデバイスを識別する。ルールを使用してDEVPATH==デバイスを一致させ、またはで見つけることができるATTR{id}="ABC"一意の名前をデバイスに割り当てます。aplay -lcat /proc/asound/cards

まず、同じ作業を手動で試してください。 USBサウンドカードはなく、内蔵デバイスのみですので、次のようにしてください。

find /sys/devices/ -name id | grep sound

「id」という名前の多くの項目がリストされていますが、その一部はディレクトリであり、一意です。文書興味深いのは、このファイルを作成するとデバイス名(「PCH」)が保存されること/sys/devices/.../sound/card0/idですcat。この擬似ファイルに文字列を書き込むと名前が変更されます。

sudo sh -c 'printf "%s" MYCARD >/sys/devices/.../sound/card0/id'

これはの出力で見ることができますaplay -l。これがudevでやりたいことです。 sysfs擬似ファイルidは次のとおりです。プロパティcard0。したがって、udevはATTR{id}=一致が正しいディレクトリにある場合にのみ機能します。私の場合は/sysそうです。/sys/devices/.../sound/card0これがudevルールが言う理由ですDEVPATH=="/sys/devices/.../sound/card?"(カード番号は変更される可能性があるため、ワイルドカード「?」に置き換えられます)。

より完全な例については、ルールファイル全体を提供するリンクの上記のセクションを参照してください85-my-usb-audio.rules

答え2

@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ポートを通じてのみ認識しますが、現在はサウンドカードが1つしかないため、モデルやメーカーによって経路が変わるかどうかは確認できません。だから1.2.1私のデバイスなどの特定のUSBポートに接続されているUSBハブの特定のポートを説明するパターンを検索します。

まだudevルールを使用して実行できませんでした。明らかに書くにはrootアクセス権が必要ですが /sys/devices/...(言います)、いくつかの答えを見たにもかかわらず完了できませんでした。それはおそらく実行中だからです。 Raspberry Jessie PiのRaspbianは、おそらくLinuxについてよく知らないからです。

しかし、私のユースケースでは、デバイスが接続されたときにスクリプトを実行する必要はありません。起動時にスクリプトを実行するだけで十分なので、最後にすべきことは、次のようにsudo crontab -ecrontabを編集することです。

@reboot /path/to/my/script.sh

そしてバラより、Javaコードを使用して特定のUSBサウンドカードにアクセスし、AudioSystem.getMixerInfo()以下を使用してサウンドを再生できます。AudioSystem.getClip(mixerInfo)

関連情報