내가 원하는 것은 여러 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가 이에 관심이 있는지는 알 수 없습니다.
그래서 아마도 올바른 해결책은 귀하에게 주어진 제안이라고 생각합니다.링크된 기사제목에두 개의 동일한 오디오 장치 식별. 규칙을 사용하여 DEVPATH==
장치를 일치시키고 또는 에서 찾을 ATTR{id}="ABC"
수 있는 고유한 이름을 장치에 지정합니다 .aplay -l
cat /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 규칙을 사용하여 실행하지 못했습니다. 분명히 쓰기 위해서는 루트 액세스 권한이 필요하지만 /sys/devices/...
(말이 됩니다) 몇 가지 답변을 보았음에도 불구하고 완료하지 못했습니다. 아마도 실행 중이기 때문일 수 있습니다. Raspberry Jessie Pi의 Raspbian, 아마도 Linux에 대해 잘 모르기 때문일 수도 있습니다.
그러나 내 사용 사례에서는 장치가 연결될 때 스크립트를 실행할 필요가 없습니다. 시작 시 스크립트를 실행하는 것만으로도 충분하므로 마지막으로 해야 할 일은 다음을 sudo crontab -e
사용하여 crontab을 편집하는 것입니다.
@reboot /path/to/my/script.sh
그리고바라보다, Java 코드를 사용하여 특정 USB 사운드 카드에 액세스 AudioSystem.getMixerInfo()
하고 다음을 사용하여 사운드를 재생할 수 있습니다.AudioSystem.getClip(mixerInfo)