順序付きリストからPulseAudioリスナーを選択し、その名前をコマンド入力として使用するスクリプト

順序付きリストからPulseAudioリスナーを選択し、その名前をコマンド入力として使用するスクリプト

オーディオソースとBluetoothデバイスの間にPulseAudioループバックデバイスを生成するbashスクリプトを作成したいと思います。

(コンテキスト - スキップできます)

オーディオソースは、次の方法で生成されます。

モジュールのロード モジュール-jackdbus-検知チャネル = 2 sing_name = jack_bt_eq_outink_client_name = "PulseAudio - Bluetooth レシーバー" source_name = jack_bt_in source_client_name = "PulseAudio - Bluetooth ソース" connect = false

#(旧バージョン - 15.0より前)
#load-module module-jack-sinkink_name=jack_bt_eq_out client_name="PulseAudio - Bluetooth レシーバー" チャネル=2 connect=false
#load-module module-jack-source source_name=jack_bt_in client_name="PulseAudio - Bluetooth ソース" チャネル=2 connect=false

上に示すように、オーディオ受信機も生成される。目標は、ジャックのイコライザーを通過してオーディオソースに出力し、再生のためにオーディオを実際のBluetoothハードウェアにリダイレクトすることです。

カラのスクリーンショット

これまでのところ、私のスクリプト(関連部分)は次のとおりです。

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で利用可能なBluetoothオーディオデバイスのリストを次の形式でユーザーに表示することです。

  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リストにレンダリングする方法がわかりません。とにかくリスナー名を取得するには、2番目のコマンドが必要です。これは不安定で理想的ではありません。具体的には、クエリ間でデバイスが切断される可能性があるため、単一のコマンドを使用してデバイスエイリアスと対応する受信者名を取得して配列に保存したいと思います。

答え1

bashに組み込まれた正規表現を使用してこれを行う方法は次のとおりです。cat sinks.txt次に置き換えて、selectステートメントにコマンドを追加するだけですpacmd list-sinkspacmd load-module ...

#!/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]}]}..."

また、メニューに有効な数字のみを許可するように、いくつかの入力検証も追加しました。

関連情報