我希望编写一个 bash 脚本,用于在音频源和蓝牙设备之间创建 PulseAudio 环回设备。
(上下文 - 可跳过)
音频源是通过以下方式创建的:
加载模块 module-jackdbus-detect 通道 = 2 sink_name = jack_bt_eq_out sink_client_name =“PulseAudio - 蓝牙接收器” source_name = jack_bt_in source_client_name =“PulseAudio - 蓝牙源” connect = false #(旧版 - 15.0 之前) #load-module module-jack-sink sink_name=jack_bt_eq_out client_name="PulseAudio - 蓝牙接收器"channels=2 connect=false #load-module module-jack-source source_name=jack_bt_in client_name="PulseAudio - 蓝牙源"channels=2 connect=false从上面可以看出,还创建了一个音频接收器。目的是让它通过 Jack 中的均衡器,输出到音频源,然后我将音频重定向到实际的蓝牙硬件进行播放。
到目前为止,我的脚本(相关部分)为:
echo "Device must be connected...";
echo "Choose a device:";
## WIP
# (present device list - 'bluez.alias')
# (wait for input)
# (assign 'sink_name'- without enclosing <>)
pacmd load-module module-loopback source=jack_bt_in sink=[TODO:sink_name] rate=48000 sink_dont_move=true latency_msec=240 max_latency_msec=250;
我想要做的是向用户展示 PulseAudio 可用的蓝牙音频设备列表,格式如下:
- 用维T1L
- JBL GO 2
- (...)
此类设备的列表及其 PulseAudio 接收器名称可以通过以下方式获取:
$ pacmd list-sinks | grep "bluez"
name: <bluez_sink.00_00_00_00_0D_91.a2dp_sink>
driver: <module-bluez5-device.c>
card: 8 <bluez_card.00_00_00_00_0D_91>
device.api = "bluez"
bluez.path = "/org/bluez/hci0/dev_00_00_00_00_0D_91"
bluez.class = "0x240404"
bluez.alias = "AWEI T1L"
name: <bluez_sink.F8_5C_7D_15_1D_47.a2dp_sink>
driver: <module-bluez5-device.c>
card: 9 <bluez_card.F8_5C_7D_15_1D_47>
device.api = "bluez"
bluez.path = "/org/bluez/hci0/dev_F8_5C_7D_15_1D_47"
bluez.class = "0x200414"
bluez.alias = "JBL GO 2"
问题是:如何解析上述命令的输出,以便获取bluez.alias
(用于显示)和接收器名称的值,剥离包围<
和>
字符,以便正确加载“模块环回”?
到目前为止,我可以使用 获取设备列表pacmd list-sinks | grep "bluez.alias" | cut -d \" -f 2
,但不确定如何将它们呈现在有序列表中;并且无论如何都需要第二个命令来获取接收器名称。这是脆弱且不理想的,特别是因为设备可能在查询之间断开连接;因此,我想使用单个命令获取设备别名及其接收器名称,并将其存储到数组中。
答案1
以下是如何使用 bash 的内置正则表达式来完成此操作。您只需替换cat sinks.txt
为pacmd list-sinks
,并将pacmd load-module ...
命令添加到 select 语句中。
#!/bin/bash
set -eu
aliases=()
declare -A mapping
while read -r line; do
if [[ $line =~ ^name:' <'([^>]*)'>' ]]; then
name=${BASH_REMATCH[1]}
elif [[ $line =~ ^bluez.alias' = "'([^\"]*)'"' ]]; then
aliases+=("${BASH_REMATCH[1]}")
mapping[${BASH_REMATCH[1]}]=$name
fi
done < <(cat sinks.txt)
PS3="Select device: "
select alias in "${aliases[@]}"; do
echo "Connecting sink ${mapping[$alias]}..."
break
done
如果设备别名可以以随机顺序呈现,则不需要别名数组,但我认为顺序很重要。
对于自定义菜单格式,请将 select 语句替换为以下内容:
while :; do
for ((i = 0; i < ${#aliases[@]}; ++i)); do
printf "%s. %s\n" "$((i+1))" "${aliases[i]}"
done
read -p 'Select device: '
[[ $REPLY != *[^0-9]* && $REPLY -gt 0 && $REPLY -le ${#aliases[@]} ]] && break
echo "Invalid choice."
done
echo "Connecting sink ${mapping[${aliases[REPLY-1]}]}..."
我还添加了一些输入验证,以便菜单只接受有效数字。