用于从有序列表中选择 PulseAudio 接收器并使用其名称作为命令输入的脚本

用于从有序列表中选择 PulseAudio 接收器并使用其名称作为命令输入的脚本

我希望编写一个 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 可用的蓝牙音频设备列表,格式如下:

  1. 用维T1L
  2. JBL GO 2
  3. (...)

此类设备的列表及其 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.txtpacmd 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]}]}..."

我还添加了一些输入验证,以便菜单只接受有效数字。

相关内容