Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 38 additions & 4 deletions dmenu_audioswitch_prev
Original file line number Diff line number Diff line change
@@ -1,23 +1,57 @@
#!/usr/bin/env bash
# Set audio sinks before using!
# `pactl list sinks` if on pulseaudio.
# `wpctl status` if on pipewire

set_source() { \
local SINK_NAME=$1
if systemctl --user is-active pipewire; then
wpctl set-default $SINK_NAME
elif systemctl --user is-active pulseaudio; then
pacmd set-default-sink $SINK_NAME &
else
notify-send "No audio system detected. Please ensure PipeWire or PulseAudio is running."
return 1
fi
}

enable_and_connect() {
local B_NAME=$1
if [ "$(bluetoothctl show | awk '/Powered/ {print $2}')" == "no" ]; then
notify-send "Enabling Bluetooth..."
bluetoothctl power on > /dev/null
fi
local DEVICE_INDEX="$(bluetoothctl devices | cut -d ' ' -f3- | grep -nFx "$B_NAME" | cut -d ':' -f1)"
if [ -z "$DEVICE_INDEX" ]; then
notify-send "Device not found: $B_NAME"
return 1
fi
local DEVICE="$(bluetoothctl devices | head -n"$DEVICE_INDEX" | tail -n1 | cut -d ' ' -f2)"
if bluetoothctl info "$DEVICE" | grep -q "Connected: no"; then
bluetoothctl connect $DEVICE > /dev/null
fi
}

headphones () { \
pacmd set-default-sink "SET SINK NAME" &
set_source "SET SINK NAME OR DEVICE ID"
notify-send -h string:bgcolor:#a3be8c "Audio switched to headphones!"
}

speakers () { \
pacmd set-default-sink "SET SINK NAME" &
set_source "SET SINK NAME OR DEVICE ID"
notify-send -h string:bgcolor:#bf616a "Audio switched to speakers!"
}

bluetooth () { \
pacmd set-default-sink "SET SINK NAME" &
enable_and_connect "DEVICE NAME"
set_source "SET SINK NAME OR DEVICE ID"
# the source ID will change every time you connect a bluetooth device, so you may need to change this often
# might need to do a function to get the source ID or name dynamically

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe find a workaround for this? is this only a problem for pipewire users?

Copy link
Author

@Haletran Haletran Jun 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have found a workaround for this, just need to test on both audio server. And no its for both audio server not only pipewire (the id change everytime I disabled bluetooth and re-enable it)

Here is the workaround to get the id:

get_sink_number() {
  local DEVICE_NAME="$1"

  if systemctl --user is-active pipewire >/dev/null 2>&1; then
    wpctl status | awk -v target="$DEVICE_NAME" '/Sinks:/, /Sink endpoints:/ {
      if ($2 == "*") {
        if ($4 == target) print $3
      } else {
        if ($3 == target) print $2
      }
    }' | tr -d '.'
  
  elif systemctl --user is-active pulseaudio >/dev/null 2>&1; then
    pactl list sinks | awk -v dev="$DEVICE_NAME" '
      /Sink #/ { sink = substr($2, 2) }
      $0 ~ dev { print sink; exit }
    '
  else
    notify-send "No audio system detected. Please ensure PipeWire or PulseAudio is running."
    return 1
  fi
}

And here how I plan to use it :

bluetooth () { \
  enable_and_connect "WH-1000XM4"
  local sink_num=$(get_sink_number "WH-1000XM4")
  set_source "$sink_num"
  notify-send  -h string:bgcolor:#88c0d0 "Audio switched to bluetooth!"
}

notify-send -h string:bgcolor:#88c0d0 "Audio switched to bluetooth!"
}

choosespeakers() { \
# If the script is not rendering in dmenu, remove the `-c` flag from dmenu commands.
choice=$(printf "Headphones\\nSpeakers\\nBluetooth" | dmenu -c -l 3 -i -p "Choose output: ")
case "$choice" in
Headphones) headphones;;
Expand All @@ -26,4 +60,4 @@ choosespeakers() { \
esac
}

choosespeakers
choosespeakers