Saturday, February 15, 2014
10:33 AM

HOWTO: Switch to HDMI audio out automatically on Linux

First things first, this is not a tutorial for getting your audio working over your HDMI if it isn't already. This assumes you already have audio over HDMI working via PulseAudio, but currently have to manually assign the new output after attaching your HDMI cable.

TL/DR

If you are using a Debian based distro and don't care about the details of how this works, then you can simply install the .deb file I've prepared here. After that finishes installing you should be good to go - attach your HDMI cable and the system should automatically switch from playing over the speakers/headphones to piping audio over the HDMI.

The Details or How we make things work on not Debian

How this works is a combination of PulseAudio, Bash, and a little bit of udev.

First things first, we need a bash script that with switch between PulseAudio outputs for us. Save the following bit of code to /usr/bin/hdmi_sound_toggle :


#!/bin/bash
# Switches between soundcards when run. All streams are moved to the new default sound-card.

# $totalsc: Number of sound cards available
totalsc=$(pacmd "list-sinks" | grep card: | wc -l) # total of sound cards: $totalsc
if [ $totalsc -le 1 ]; then # Check whether there are actually multiple cards available
exit
fi
# $scindex: The Pulseaudio index of the current default sound card
scindex=$(pacmd list-sinks | awk '$1 == "*" && $2 == "index:" {print $3}')
# $cards: A list of card Pulseaudio indexes
cards=$(pacmd list-sinks | sed 's|*||' | awk '$1 == "index:" {print $2}')
PICKNEXTCARD=1 # Is true when the previous card is default
count=0 # count of number of iterations
for CARD in $cards; do
if [ $PICKNEXTCARD == 1 ]; then
# $nextsc: The pulseaudio index of the next sound card (to be switched to)
nextsc=$CARD
PICKNEXTCARD=0
# $nextind: The numerical index (1 to totalsc) of the next card
nextind=$count
fi
if [ $CARD == $scindex ]; then # Choose the next card as default
PICKNEXTCARD=1
fi
count=$((count+1))
done
pacmd "set-default-sink $nextsc" # switch default sound card to next

# $inputs: A list of currently playing inputs
inputs=$(pacmd list-sink-inputs | awk '$1 == "index:" {print $2}')
for INPUT in $inputs; do # Move all current inputs to the new default sound card
pacmd move-sink-input $INPUT $nextsc
done
exit
Make our script executable with the command:

sudo chmod +x /usr/bin/hdmi_sound_toggle

Before moving on, confirm the script works as intended. While your HDMI cable is active run the command hdmi_sound_toggle and you should start hearing sound pipe out of the HDMI output.

Next, because PulseAudio is almost always run as a user level daemon, we need something that will move all users' Pulse sessions over to the new output when the HDMI is attached/detached. To do this we create the script /usr/bin/hdmi_sound_toggle_all with the contents:

#!/bin/bash

for dir in /home/*/
do
dir=${dir%*/}
sudo -u ${dir##*/} /usr/bin/hdmi_sound_toggle
done
Make this script executable as well:

sudo chmod +x /usr/bin/hdmi_sound_toggle_all

Confirm this script works as well, it needs to be run as root though, so run sudo hdmi_sound_toggle_all while your HDMI is attached - it should switch your output.

Finally, we need to create a udev rule that triggers our scripts when an HDMI cable is attached/detached. To do this we create the file /lib/udev/rules.d/hdmi_sound.rules with the contents:

SUBSYSTEM=="drm", ACTION=="change", RUN+="/usr/bin/hdmi_sound_toggle_all"
Note that having the full file path in the execute part is important. So if you placed your scripts somewhere other than /usr/bin like I recommended above - adjust this part accordingly.

You should be good to go, enjoy having audio over your HDMI happen automatically like it should by default. Have any questions, feel free to post a comment below and I'll do my best to help.

~Jeff Hoogland

0 comments:

Post a Comment