PulseAudio's default behavior when disconnecting Bluetooth devices can be frustrating. When your Bluetooth headphones disconnect, PulseAudio automatically switches to another available sink - but not necessarily the one you want (like your laptop speakers).
This solution uses udev rules to automatically switch audio devices when Bluetooth connects/disconnects:
- When Bluetooth headphones connect -> Set them as default input/output
- When Bluetooth headphones disconnect -> Force specific fallback devices (e.g., laptop speakers)
- Create a udev rule at
/etc/udev/rules.d/99-bluetooth.rules
:
ACTION=="add", SUBSYSTEM=="input", ATTRS{phys}=="XX:XX:XX:XX:XX:XX", RUN+="/path/to/set-pulse-audio-defaults.sh --connect"
ACTION=="remove", SUBSYSTEM=="input", ATTRS{phys}=="XX:XX:XX:XX:XX:XX", RUN+="/path/to/set-pulse-audio-defaults.sh --disconnect"
- Save the script below as
set-pulse-audio-defaults.sh
and make it executable:
BT_SINK="bluez_output.AC_12_2F_7B_D4_E3.1"
BT_SOURCE="bluez_input.AC:12:2F:7B:D4:E3"
BACKUP_SINK="alsa_output.pci-0000_00_1f.3-platform-skl_hda_dsp_generic.HiFi__Headphones__sink"
BACKUP_SOURCE="alsa_input.pci-0000_00_1f.3-platform-skl_hda_dsp_generic.HiFi__Mic1__source"
PULSE_RUNTIME_DIR="/run/user/1000/pulse" # Default, will be overwritten if XDG is set.
USER="mike"
LOG_FILE="/dev/null"
# LOG_FILE="/tmp/udev.log" # For troubleshooting
# Parse command line arguments
case "$1" in
--connect)
PULSE_SINK="$BT_SINK"
PULSE_SOURCE="$BT_SOURCE"
sleep 2
;;
--disconnect)
PULSE_SINK="$BACKUP_SINK"
PULSE_SOURCE="$BACKUP_SOURCE"
;;
*)
echo "Usage: $0 [--connect|--disconnect]"
exit 1
;;
esac
# Get XDG_RUNTIME_DIR if available
if [[ -n "$XDG_RUNTIME_DIR" ]]; then
PULSE_RUNTIME_DIR="$XDG_RUNTIME_DIR/pulse"
fi
# Check if PulseAudio socket exists
if [[ -S "$PULSE_RUNTIME_DIR/native" ]]; then
date "+%Y-%m-%d %H:%M:%S - Udev: setting default to $PULSE_SINK" >>"$LOG_FILE"
sudo -u "$USER" PULSE_RUNTIME_PATH="$PULSE_RUNTIME_DIR" /usr/bin/pactl set-default-sink "$PULSE_SINK" >>"$LOG_FILE" 2>&1
sudo -u "$USER" PULSE_RUNTIME_PATH="$PULSE_RUNTIME_DIR" /usr/bin/pactl set-default-source "$PULSE_SOURCE" >>"$LOG_FILE" 2>&1
else
date "+%Y-%m-%d %H:%M:%S - PulseAudio socket not found for user $USER" >>"$LOG_FILE"
echo "PulseAudio socket not found at $PULSE_RUNTIME_DIR/native" >>"$LOG_FILE"
fi
exit 0
- Reload udev rules:
sudo udevadm control --reload-rules
- To get your Bluetooth device's MAC address and other udev properties:
udevadm monitor --property
- To list available PulseAudio sinks and sources:
pactl list sinks short
pactl list sources short
pactl get-default-sink
Update these variables in the script to match your system:
BT_SINK
: Your Bluetooth headphones' sink nameBT_SOURCE
: Your Bluetooth headphones' source nameBACKUP_SINK
: Your preferred fallback output deviceBACKUP_SOURCE
: Your preferred fallback input deviceUSER
: Your system username
For troubleshooting, uncomment the alternate LOG_FILE
line to enable logging.