干货!干货!干货!在Linux下如何同时使用多个音频输出设备播放不同的音频
前言
最近在开发一个车辆系统音频播报的系统,项目的需求是需要选择多个声卡设备来进行播放不同的音频,在网上查了许多资料,历经大半个月终于搞定了,放出来给大家免费参考参考,【主要是看到某些博主居然要收费,心里不爽,话不多,直接上源码】。
声卡绑定配置
步骤一
本功能包基于的声卡是绿联:https://detail.tmall.com/item.htm?abbucket=12&id=559780789362&ns=1&spm=a21n57.1.0.0.748e523c5aANXB
本设备hidraw0、hidraw1为两个外接的USB声卡
查看声卡是否接入
lsusb
Bus 001 Device 003: ID 0c76:1676 JMTek, LLC. USB PnP Audio Device
Bus 001 Device 002: ID 0c76:1676 JMTek, LLC. USB PnP Audio Device
***
***
***
出现的两个外置USB声卡串口号是一样的,是因为厂家采用的串口芯片是一样的;所以不能用串口号来区分两张声卡,接下来我们采用的是利用端口号加路径的方式来区分并绑定设备。
ls /dev/*
hidraw0 hidraw1 hidraw3 hidraw4
查看串口以及端口信息,测试了发现没有USB串口独立的特征信息,所以无法从串口信息来识别, 唯一一个不变的3-3:1.0, 而这个实际上是代表电脑上这个USB口编号,也就是说只是连在这个USB端口上的串口都叫这个ID.
udevadm info /dev/hidraw*
P: /devices/pci0000:00/0000:00:14.0/usb1/1-3/1-3:1.3/0003:0C76:1676.0001/hidraw/hidraw0
N: hidraw0
L: 0
E: DEVPATH=/devices/pci0000:00/0000:00:14.0/usb1/1-3/1-3:1.3/0003:0C76:1676.0001/hidraw/hidraw0
E: DEVNAME=/dev/hidraw0
E: MAJOR=239
E: MINOR=0
E: SUBSYSTEM=hidraw
P: /devices/pci0000:00/0000:00:14.0/usb1/1-4/1-4:1.3/0003:0C76:1676.0002/hidraw/hidraw1
N: hidraw1
L: 0
E: DEVPATH=/devices/pci0000:00/0000:00:14.0/usb1/1-4/1-4:1.3/0003:0C76:1676.0002/hidraw/hidraw1
E: DEVNAME=/dev/hidraw1
E: MAJOR=239
E: MINOR=1
E: SUBSYSTEM=hidraw
查看声卡所接的USB端口对应的端口号方法
ll /sys/class/hidraw/hidraw*
lrwxrwxrwx 1 root root 0 9月 11 09:33 /sys/class/hidraw/hidraw0 -> ../../devices/pci0000:00/0000:00:14.0/usb1/1-3/1-3:1.3/0003:0C76:1676.0001/hidraw/hidraw0/
lrwxrwxrwx 1 root root 0 9月 11 09:33 /sys/class/hidraw/hidraw1 -> ../../devices/pci0000:00/0000:00:14.0/usb1/1-4/1-4:1.3/0003:0C76:1676.0002/hidraw/hidraw1/
lrwxrwxrwx 1 root root 0 9月 11 09:33 /sys/class/hidraw/hidraw2 -> ../../devices/pci0000:00/0000:00:14.0/usb1/1-7/1-7:1.2/0003:046D:C52B.0005/hidraw/hidraw2/
lrwxrwxrwx 1 root root 0 9月 11 09:33 /sys/class/hidraw/hidraw3 -> ../../devices/pci0000:00/0000:00:14.0/usb1/1-7/1-7:1.2/0003:046D:C52B.0005/0003:046D:404D.0006/hidraw/hidraw3/
绑定【USB端口号】KERNELS硬件端口号绑定
sudo gedit /etc/udev/rules.d/com_port.rules
根据自身情况,修改rules文件。
KERNELS表示硬件的USB接口名,不同编号,表示不同的usb接口.
其中,第一条代表连接到USB端口号为1-3:1.3的声卡对应的软链接文件为Speaker/Interior;第二条代表连接到USB端口号为1-4:1.3的声卡对应的软链接文件为Speaker/Exterior;然后保存并重启电脑。
SUBSYSTEM=="hidraw", SUBSYSTEMS=="usb", KERNELS=="1-3:1.3", MODE="0666", SYMLINK+="Interior_Speaker", OWNER="pixkit3", GROUP="root"
SUBSYSTEM=="hidraw", SUBSYSTEMS=="usb", KERNELS=="1-4:1.3", MODE="0666", SYMLINK+="Exterior_Speaker", OWNER="pixkit3", GROUP="root"
运行以下命令使修改立即生效
sudo udevadm trigger
查看是否软连接成功,运行以下命令查看USB设备名更改情况:
ls -l /dev |grep hidraw*
lrwxrwxrwx 1 root root 7 9月 11 11:15 Exterior_Speaker -> hidraw1
crw-rw-rw- 1 kit3 kit3 239, 0 9月 11 11:15 hidraw0
crw-rw-rw- 1 kit3 kit3 239, 1 9月 11 11:15 hidraw1
crw------- 1 root root 239, 2 9月 11 11:15 hidraw2
crw------- 1 root root 239, 3 9月 11 11:15 hidraw3
lrwxrwxrwx 1 root root 7 9月 11 11:15 Interior_Speaker -> hidraw0
如输出以上信息,表示已经软连接成功。
通过以上步骤,就把hidraw0取别名为Interior_Speaker,把hidraw1取别名为Exterior_Speaker,以后在程序里直接访问Interior_Speaker\Exterior_Speaker,就可以与这两个设备通信了。
特注意:只要是插到这个USB端口的串口都会被改为指定名,所以该方法只能将设备插入在指定的USB端口上。
步骤二
配置alsad的asound.conf文件,如果没有则自行新建一个asound.conf文件,把Interior_Speaker、Exterior_Speaker 映射到声卡0、声卡1上,具体在那个需要 aplay -l查看。
sudo gedit /etc/asound.conf
pcm.Interior_Speaker {
type hw
card 0
}
ctl.Interior_Speaker {
type hw
card 0
}
pcm.Exterior_Speaker {
type hw
card 1
}
ctl.Exterior_Speaker {
type hw
card 1
}
保存配置文件即可
查看系统声卡索引号
在输出的内容里面就有我们插入的两张声卡。
aplay -l or aplay -L
**** List of PLAYBACK Hardware Devices ****
card 0: Device_1 [USB PnP Audio Device], device 0: USB Audio [USB Audio]
Subdevices: 1/1
Subdevice #0: subdevice #0
card 1: Device [USB PnP Audio Device], device 0: USB Audio [USB Audio]
Subdevices: 1/1
Subdevice #0: subdevice #0
card 2: PCH [HDA Intel PCH], device 3: HDMI 0 [HDMI 0]
Subdevices: 1/1
安装 pavucontrol
sudo apt-get install pavucontrol # Debian/Ubuntu系统
按照下图所示进行设置
声卡绑定配置
步骤一
本功能包基于的声卡是绿联:https://detail.tmall.com/item.htm?abbucket=12&id=559780789362&ns=1&spm=a21n57.1.0.0.748e523c5aANXB
本设备hidraw0、hidraw1为两个外接的USB声卡
查看声卡是否接入
lsusb
Bus 001 Device 003: ID 0c76:1676 JMTek, LLC. USB PnP Audio Device
Bus 001 Device 002: ID 0c76:1676 JMTek, LLC. USB PnP Audio Device
***
***
***
出现的两个外置USB声卡串口号是一样的,是因为厂家采用的串口芯片是一样的;所以不能用串口号来区分两张声卡,接下来我们采用的是利用端口号加路径的方式来区分并绑定设备。
ls /dev/*
hidraw0 hidraw1 hidraw3 hidraw4
查看串口以及端口信息,测试了发现没有USB串口独立的特征信息,所以无法从串口信息来识别, 唯一一个不变的3-3:1.0, 而这个实际上是代表电脑上这个USB口编号,也就是说只是连在这个USB端口上的串口都叫这个ID.
udevadm info /dev/hidraw*
P: /devices/pci0000:00/0000:00:14.0/usb1/1-3/1-3:1.3/0003:0C76:1676.0001/hidraw/hidraw0
N: hidraw0
L: 0
E: DEVPATH=/devices/pci0000:00/0000:00:14.0/usb1/1-3/1-3:1.3/0003:0C76:1676.0001/hidraw/hidraw0
E: DEVNAME=/dev/hidraw0
E: MAJOR=239
E: MINOR=0
E: SUBSYSTEM=hidraw
P: /devices/pci0000:00/0000:00:14.0/usb1/1-4/1-4:1.3/0003:0C76:1676.0002/hidraw/hidraw1
N: hidraw1
L: 0
E: DEVPATH=/devices/pci0000:00/0000:00:14.0/usb1/1-4/1-4:1.3/0003:0C76:1676.0002/hidraw/hidraw1
E: DEVNAME=/dev/hidraw1
E: MAJOR=239
E: MINOR=1
E: SUBSYSTEM=hidraw
查看声卡所接的USB端口对应的端口号方法
ll /sys/class/hidraw/hidraw*
lrwxrwxrwx 1 root root 0 9月 11 09:33 /sys/class/hidraw/hidraw0 -> ../../devices/pci0000:00/0000:00:14.0/usb1/1-3/1-3:1.3/0003:0C76:1676.0001/hidraw/hidraw0/
lrwxrwxrwx 1 root root 0 9月 11 09:33 /sys/class/hidraw/hidraw1 -> ../../devices/pci0000:00/0000:00:14.0/usb1/1-4/1-4:1.3/0003:0C76:1676.0002/hidraw/hidraw1/
lrwxrwxrwx 1 root root 0 9月 11 09:33 /sys/class/hidraw/hidraw2 -> ../../devices/pci0000:00/0000:00:14.0/usb1/1-7/1-7:1.2/0003:046D:C52B.0005/hidraw/hidraw2/
lrwxrwxrwx 1 root root 0 9月 11 09:33 /sys/class/hidraw/hidraw3 -> ../../devices/pci0000:00/0000:00:14.0/usb1/1-7/1-7:1.2/0003:046D:C52B.0005/0003:046D:404D.0006/hidraw/hidraw3/
绑定【USB端口号】KERNELS硬件端口号绑定
sudo gedit /etc/udev/rules.d/com_port.rules
根据自身情况,修改rules文件。
KERNELS表示硬件的USB接口名,不同编号,表示不同的usb接口.
其中,第一条代表连接到USB端口号为1-3:1.3的声卡对应的软链接文件为Speaker/Interior;第二条代表连接到USB端口号为1-4:1.3的声卡对应的软链接文件为Speaker/Exterior;然后保存并重启电脑。
SUBSYSTEM=="hidraw", SUBSYSTEMS=="usb", KERNELS=="1-3:1.3", MODE="0666", SYMLINK+="Interior_Speaker", OWNER="pixkit3", GROUP="root"
SUBSYSTEM=="hidraw", SUBSYSTEMS=="usb", KERNELS=="1-4:1.3", MODE="0666", SYMLINK+="Exterior_Speaker", OWNER="pixkit3", GROUP="root"
运行以下命令使修改立即生效
sudo udevadm trigger
查看是否软连接成功,运行以下命令查看USB设备名更改情况:
ls -l /dev |grep hidraw*
lrwxrwxrwx 1 root root 7 9月 11 11:15 Exterior_Speaker -> hidraw1
crw-rw-rw- 1 pixkit3 pixkit3 239, 0 9月 11 11:15 hidraw0
crw-rw-rw- 1 pixkit3 pixkit3 239, 1 9月 11 11:15 hidraw1
crw------- 1 root root 239, 2 9月 11 11:15 hidraw2
crw------- 1 root root 239, 3 9月 11 11:15 hidraw3
lrwxrwxrwx 1 root root 7 9月 11 11:15 Interior_Speaker -> hidraw0
如输出以上信息,表示已经软连接成功。
通过以上步骤,就把hidraw0取别名为Interior_Speaker,把hidraw1取别名为Exterior_Speaker,以后在程序里直接访问Interior_Speaker\Exterior_Speaker,就可以与这两个设备通信了。
特注意:只要是插到这个USB端口的串口都会被改为指定名,所以该方法只能将设备插入在指定的USB端口上。
步骤二
配置alsad的asound.conf文件,如果没有则自行新建一个asound.conf文件,把Interior_Speaker、Exterior_Speaker 映射到声卡0、声卡1上,具体在那个需要 aplay -l查看。
sudo gedit /etc/asound.conf
pcm.Interior_Speaker {
type hw
card 0
}
ctl.Interior_Speaker {
type hw
card 0
}
pcm.Exterior_Speaker {
type hw
card 1
}
ctl.Exterior_Speaker {
type hw
card 1
}
保存配置文件即可,接下来查看系统声卡索引号
在输出的内容里面就有我们插入的两张声卡。
aplay -l or aplay -L
card 1: Device [USB PnP Audio Device], device 0: USB Audio [USB Audio]
Subdevices: 0/1
Subdevice #0: subdevice #0
card 2: Audio [iStore Audio], device 0: USB Audio [USB Audio]
Subdevices: 0/1
Subdevice #0: subdevice #0
安装 pavucontrol
sudo apt-get install pavucontrol # Debian/Ubuntu系统
按照下图所示进行设置
特别注意:设备上插入了两个USB声卡,所以下图显示有两个USB声卡设备,在Profile选项里选择输出类型;
在这里我USB声卡1选择的是Analog Stereo Output 做为音频的输出设备;声卡2选择的是Analog Stereo Duplex,因为声卡2上接了一个麦克风,不使用显卡所带的声卡,可以将HDA Nvidia关掉。
注意:
"Analog Stereo Duplex"是 PulseAudio 中的一个音频配置配置文件,用于表示同时支持音频输入(如麦克风)和音频输出(如扬声器或耳机)的声音配置。
"Analog Stereo Output" 这是标准的模拟立体声输出,通常用于连接到内置或外置扬声器的设备。
代码:
import pyaudio
import simpleaudio as sa
import wave
# 获取可用的声音设备列表
def list_audio_devices():
p = pyaudio.PyAudio()
info = p.get_host_api_info_by_index(0)
numdevices = info.get('deviceCount')
devices = []
for i in range(0, numdevices):
device_info = p.get_device_info_by_host_api_device_index(0, i)
device_name = device_info.get('name')
devices.append((i, device_name))
print(f"Device {i}: {device_info['name']}, Supported Sample Rates: {device_info['defaultSampleRate']}, Max Channels: {device_info['maxOutputChannels']}")
return devices
# 选择特定声卡并播放音频
def play_audio_on_device(audio_file, device_index):
try:
# 使用 PyAudio 控制音频输出设备
p = pyaudio.PyAudio()
wave_file = wave.open(audio_file, 'rb')
stream = p.open(output_device_index=device_index,
format=p.get_format_from_width(wave_file.getsampwidth()),
channels=wave_file.getnchannels(),
# rate=wave_file.getframerate(),
rate=48000, # 指定所需的采样率
output=True)
data = wave_file.readframes(1024)
# 从音频文件中读取数据并通过 PyAudio 输出到所选的声卡
while data:
stream.write(data)
data = wave_file.readframes(1024)
stream.stop_stream()
stream.close()
p.terminate()
except Exception as e:
print("播放音频出错:", str(e))
# 获取声卡列表并选择一个声卡(例如,选择第一个声卡)
audio_devices = list_audio_devices()
if len(audio_devices) > 1:
# 初始化声卡参数
selected_device_index_out = audio_devices[1][0] #音箱
selected_device_index_in = audio_devices[0][0] #耳机
# 播放音频文件(例如,'audio.wav')到所选声卡
audio_file_path_1 = '/home/src/vehicle/external/vehicle_voice_alert_system/src/vehicle_voice_alert_system/resource/sound/running_music.wav'
audio_file_path_2 = '/home/src/vehicle/external/vehicle_voice_alert_system/src/vehicle_voice_alert_system/resource/sound/stop.wav'
# 选择播放声卡
play_audio_on_device(audio_file_path_2, selected_device_index_in)
play_audio_on_device(audio_file_path_1, selected_device_index_out)
else:
print("没有找到可用的声卡")
总结
以上就是今天要讲的内容,本文仅仅简单介绍了主题文章使用,本着开源的精神加班熬夜给大伙儿谋福利,还望您动动手指点个赞👍