Skip to content

Instantly share code, notes, and snippets.

@pgillet
Forked from kbravh/README.md
Last active October 3, 2024 07:01
Show Gist options
  • Save pgillet/534041a0f2ae1ae94aff2e74bf6096f1 to your computer and use it in GitHub Desktop.
Save pgillet/534041a0f2ae1ae94aff2e74bf6096f1 to your computer and use it in GitHub Desktop.
Switch audio output devices on Linux

Audio Output Switcher

This script will cycle to the next available audio output device. It can be tied to a hotkey to easily be triggered. This is handy, for example, for swapping between HDMI audio and headphones.

Install

  1. Download the audio-device-switch.sh script and place it in /usr/local/bin.
  2. Make the script executable: sudo chmod 755 /usr/local/bin/audio-device-switch.sh.
  3. Open the Keyboard Shortcuts settings page, add a new shortcut, tell it to execute audio-device-switch.sh, and set up your shortcut!
  4. Install the notify-send library if you want to see a popup notification when the audio device switches: sudo apt install libnotify-bin.

Customizations

Feel free to modify this script and make it your own. Some ideas for customization:

Different icon in the notification

Line 45 of the script calls notify-send with the -i flag which defines which icon is displayed. Stock icons are found in:

  • /usr/share/icons/gnome/32x32
  • /usr/share/notify-osd/icons/

Or, a custom icon file can be provided.

More details about the audio device

Line 41 fetches the output device names using the pacmd list-sinks command and filters out the alsa.name property. You could pull another property, such as the device.description.

Acknowledgements

This is a more modern, robust rewrite of tsvetan's solution on the Ubuntu forums.

#!/bin/bash
# Grab a count of how many audio sinks we have
sink_count=$(pacmd list-sinks | grep -c "index:[[:space:]][[:digit:]]")
# Create an array of the actual sink IDs
sinks=()
mapfile -t sinks < <(pacmd list-sinks | grep 'index:[[:space:]][[:digit:]]' | sed -n -e 's/.*index:[[:space:]]\([[:digit:]]\)/\1/p')
# Get the ID of the active sink
active_sink=$(pacmd list-sinks | sed -n -e 's/[[:space:]]*\*[[:space:]]index:[[:space:]]\([[:digit:]]\)/\1/p')
# Get the ID of the last sink in the array
final_sink=${sinks[$((sink_count - 1 ))]}
# Find the index of the active sink
for index in "${!sinks[@]}"; do
if [[ "${sinks[$index]}" == "$active_sink" ]]; then
active_sink_index=$index
fi
done
# Default to the first sink in the list
next_sink=${sinks[0]}
next_sink_index=0
# If we're not at the end of the list, move up the list
if [[ $active_sink -ne $final_sink ]] ; then
next_sink_index=$(( active_sink_index + 1))
next_sink=${sinks[$next_sink_index]}
fi
#change the default sink
pacmd "set-default-sink ${next_sink}"
#move all inputs to the new sink
for app in $(pacmd list-sink-inputs | sed -n -e 's/index:[[:space:]]\([[:digit:]]\)/\1/p');
do
pacmd "move-sink-input $app $next_sink"
done
# Create a list of the sink descriptions
sink_descriptions=()
mapfile -t sink_descriptions < <(pacmd list-sinks | sed -n -e 's/.*alsa.name[[:space:]]=[[:space:]]"\(.*\)"/\1/p')
# Find the index that matches our new active sink
for sink_index in "${!sink_descriptions[@]}"; do
if [[ "$sink_index" == "$next_sink_index" ]] ; then
notify-send -i audio-volume-high "Sound output switched to ${sink_descriptions[$sink_index]}"
exit
fi
done
@bmarinb
Copy link

bmarinb commented Oct 11, 2022

Great!
I needed to change line 41 in order to get device descriptions (from this thread)
mapfile -t sink_descriptions < <(pacmd list-sinks | grep -Pzo "\* index(.*\n)*" | sed \$d | grep -e "device.description" | cut -f2 -d\")
Also, notifications only showed in some cases, which I fixed by changing line 46 to
if [[ "$sink_index" -le "$next_sink_index" ]] ; then

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment