연결된 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()
내 접근 방식이 정확하고 세부 사항이 누락되었거나 완전히 잘못된 방향입니까?
답변
당신은 올바른 길을 가고 있습니다. udev에 문제가 될 수있는 많은 것들이 있습니다. udev 규칙이 NAME="..."
더 이상 작동하지 않는 이유 는 커널이 더 이상 이런 방식으로 장치 이름을 바꿀 수 없기 때문입니다. SYMLINK+=
일반적 으로 작업 과의 상징적 연결을 생성 하지만 alsa가 그것에 관심이 있는지 모르겠습니다.
따라서 올바른 해결책은 두 개의 동일한 오디오 장치 식별 섹션에서 링크 된 기사 에 제공된 조언이라고 생각합니다 . 규칙을 사용 하여 장치를 일치시키고 또는 에서 찾을 수있는 해당 장치에 고유 한 이름을 제공합니다 .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
은의 속성 입니다 card0
. 따라서 udev에서는 ATTR{id}=
올바른 /sys
디렉토리, 즉 /sys/devices/.../sound/card0
제 경우에 일치하는 경우에만 작동합니다 . 이것이 udev 규칙이 말하는 이유입니다 DEVPATH=="/sys/devices/.../sound/card?"
(카드 번호가 변경 될 수 있으므로 와일드 카드 glob 문자 "?"로 대체 됨).
보다 완전한 예는 전체 규칙 파일을 제공하는 링크의 위에서 언급 한 섹션을 참조하십시오 85-my-usb-audio.rules
.
@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 규칙을 사용하여 실행하지 못했습니다-분명히 쓰기 위해 루트 액세스 권한이 필요 /sys/devices/...
하지만 여러 답변을 살펴 보았지만 완료 할 수 없었습니다-아마도 Raspberry에서 Raspbian Jessie를 실행하고 있기 때문일 수 있습니다 Pi, 아마도 Linux에 대해 잘 모르기 때문일 것입니다.
그러나 내 사용 사례는 장치를 연결할 때 스크립트를 실행해야하는 것은 아닙니다. 부팅시 실행하는 것만으로도 충분하므로 마지막으로 필요한 것은 crontab을 사용하여 편집 sudo crontab -e
하고 줄을 추가하는 것입니다.
@reboot /path/to/my/script.sh
그리고 짜잔 , 나는 사용하여 Java 코드에서 특정 USB 사운드 카드에 액세스하고 다음을 사용하여 AudioSystem.getMixerInfo()
사운드를 재생할 수 있습니다.AudioSystem.getClip(mixerInfo)