#!/usr/bin/env bash # This script toggles state between a few of my audio cables: # combine sink -> default_output | hyperx_output # clementine sink -> combine sink | default_output # The script also outputs a symbol indicating which configuration is active. # Usecase: My USB-C headset is a different sink than the one in the laptop; sometimes I want to have audio over the headset, sometimes through the laptop. # Output symbols # SYMBOLS=("neither" "co^!cl" "cl^!co" "both") SYMBOLS=("󰴸 " "󰝚 " "󰓃 " "󰋋 ") # The sinks to test against DEFAULT_SINKS=("bluez_output_internal.0A_E6_E0_F9_F1_BE.1" "alsa_output.pci-0000_06_00.6.analog-stereo" "bluez_output.20_18_5B_F0_FC_4A.1" "bluez_output.0A_E6_E0_F9_F1_BE.1" "bluez_output.0A_E6_E0_F9_F1_BE" "bluez_output.0A:E6:E0:F9:F1:BE") USB_C_SINK="alsa_output.usb-HP__Inc_HyperX_Cloud_III_Wireless_0000000000000000-00.analog-stereo" COMBINE_SINK="combine" # awkcommand - a little complicated, but basically tests if the DEFAULT_SINK is connected to the clementine sink (adding +2 if so) or the combine sink (adding +1). This gives a numerical mapping for all 4 states im interested in: # 0: neither combine,clementine are attached to usb_c_sink # 1: only combine is attached to usb_c_sink # 2: only clementine is attached to usb_c_sink # 3: both combine,clementine are attached to usb_c_sink read -r -d "" awkcommand << EOF /$USB_C_SINK:playback_FL/,/$USB_C_SINK:playback_FR/ { if (\$2 == "combine:monitor_FL") { state += 1 } } /$COMBINE_SINK:playback_FL/,/$COMBINE_SINK:playback_FR/ { if (\$2 == "clementine:monitor_FL") { state += 2 } } END { printf "%d\n", state } EOF # Attaches a single sink to a specific source function attach() { echo "attaching $1 to $2" pw-link "$1":monitor_FL "$2":playback_FL pw-link "$1":monitor_FR "$2":playback_FR } # Attaches an array of sinks to a specific source. # $1 = source (pw monitor) # $2 = list of sinks to attach function attachArray() { name=$2[@] a=("${!name}") for sink in "${a[@]}"; do attach "$1" "$sink" done } # Detaches a single sink from a specific source function detach() { echo "detaching $1 from $2" pw-link -d "$1":monitor_FL "$2":playback_FL pw-link -d "$1":monitor_FR "$2":playback_FR } # Detaches an array of sinks to a specific source. # $1 = source (pw monitor) # $2 = list of sinks to attach function detachArray() { name=$2[@] a=("${!name}") for sink in "${a[@]}"; do detach "$1" "$sink" done } state=$(pw-link -li | awk "$awkcommand") IFS=$'\n' # actually toggle iff we have a $1 telling us to if [[ "$1" == "toggle" ]];then case "$2" in "clementine") if [[ $state -eq 2 || $state -eq 3 ]]; then detach "clementine" "$COMBINE_SINK" attachArray "clementine" "DEFAULT_SINKS" state=$((state-2)) else detachArray "clementine" "DEFAULT_SINKS" attach "clementine" "$COMBINE_SINK" state=$((state+2)) fi ;; "combine") if [[ $state -eq 1 || $state -eq 3 ]]; then detach "combine" "$USB_C_SINK" attachArray "combine" "DEFAULT_SINKS" state=$((state-1)) else detachArray "combine" "DEFAULT_SINKS" attach "combine" "$USB_C_SINK" state=$((state+1)) fi ;; *) echo "Unknown option: '$2'" ;; esac fi echo "${SYMBOLS[$state]}"