Set HDMI sound output automatically on connect/disconnect
For the benefit of people who stumble upon this question - Salem's solution almost worked for me in 13.04, I ended up gathering bits and pieces from all around the web, I think the deal breaker for me was the lack of the environment variable PULSE_SERVER
Here is my full solution, which is basically repeating Salem's solution with the few missing pieces. I also redid it as a shell script (despite my love for Python) because I was afraid at first that my Python script is running into import path issues:
(same as Salem's answer) Create a file /etc/udev/rules.d/hdmi_sound.rules
as root with the content:
SUBSYSTEM=="drm", ACTION=="change", RUN+="/usr/local/bin/hdmi_sound_toggle"
Create a file /usr/local/bin/hdmi_sound_toggle
as root with the content:
#!/bin/sh
USER_NAME=`who | grep "(:0)" | cut -f 1 -d ' '`
USER_ID=`id -u $USER_NAME`
HDMI_STATUS=`cat /sys/class/drm/card0/*HDMI*/status`
export PULSE_SERVER="unix:/run/user/"$USER_ID"/pulse/native"
if [ $HDMI_STATUS = "connected" ]
then
sudo -u $USER_NAME pactl --server $PULSE_SERVER set-card-profile 0 output:hdmi-stereo+input:analog-stereo
else
sudo -u $USER_NAME pactl --server $PULSE_SERVER set-card-profile 0 output:analog-stereo+input:analog-stereo
fi
Then make it executable with chmod 0755 /usr/local/bin/hdmi_sound_toggle
I tried to make this script as generic as possible, but you still might need to change some lines, such as the HDMI_STATUS file path or the profiles used. You can see a list of profiles by running pactl list cards
and looking under Profiles.
Note that the script failed for me when I removed the keyword "export" when setting PULSE_SERVER, I think pactl is looking for the env variable
Don't forget to reload your udev rules: sudo udevadm control --reload-rules
Update this script is updated for 14.04. Before that, you would use USER_NAME instead of USER_ID everywhere
I finally managed to make this work using udev
. So if someone wants the same behavior here are the steps:
First we need to create a file /etc/udev/rules.d/hdmi_sound.rules
with the following content:
SUBSYSTEM=="drm", ACTION=="change", RUN+="/usr/local/bin/hdmi_sound_toggle"
this will make udev
execute the script hdmi_sound_toggle
every time there is a change in HDMI connection. That script must have execution permission and the contents are as follows:
#!/usr/bin/env python
import subprocess
from syslog import syslog
def output(cmd):
return subprocess.check_output(cmd, shell=True)
# the following variables may need some modification.
user = "my_username"
card = "/sys/class/drm/card0"
dev_speaker = "output:analog-stereo+input:analog-stereo"
dev_hdmi = "output:hdmi-stereo+input:analog-stereo"
#
interfaces = output("ls {0}".format(card), ).split("\n")
vga = filter(lambda x: "VGA" in x, interfaces)[0]
hdmi = filter(lambda x: "HDMI" in x, interfaces)[0]
syslog("HDMI connection was changed!")
hdmi_connected = output("cat {0}/{1}/status".format(card,hdmi)).startswith("connected")
title = "HDMI was {0}".format("connected" if hdmi_connected else "disconnected")
message = "Audio output has changed to {opt}.".format(opt = "HDMI" if hdmi_connected else "built-in speakers")
cmd = "sudo -u " + user + " /usr/bin/pactl set-card-profile 0 " + (dev_hdmi if hdmi_connected else dev_speaker)
syslog("HDMI was connected." if hdmi_connected else "HDMI was disconnected.")
try:
a = output(cmd)
output("sudo -u {0} notify-send \"{1}\" \"{2}\"".format(user, title, message))
syslog("Audio output changed.")
except Exception as ex:
syslog("Error changing output device: " + str(ex))
Probably this can be easily made in bash, but as my main language is python I used it. Everything works except the notification: it doesn't show up, I really don't know why. If someone knows how to fix it please say something.
Note: the names of script/udev rule can be changed, but you need to use the full path.
Based on Salem's answer and daniel's answer
I took Salem's answer and daniel's answer and made some necessary changes, their solution didn't worked for me out of the box:
(similar as Salem's answer).
Create a file /etc/udev/rules.d/hdmi_sound.rules
as root with the content:
SUBSYSTEM=="drm", RUN+="/usr/local/bin/hdmi_sound_toggle"
Note ACTION=="change",
is missing !
Create a file /usr/local/bin/hdmi_sound_toggle
as root with the content:
#!/bin/sh
USER_NAME=`who | grep "(:0)" | cut -f 1 -d ' '| sort -u`
USER_ID=`id -u $USER_NAME`
HDMI_STATUS=`cat /sys/class/drm/card0/*HDMI*/status`
export PULSE_SERVER="unix:/run/user/"$USER_ID"/pulse/native"
if [ $HDMI_STATUS = "connected" ]
then
sudo -u $USER_NAME pactl --server $PULSE_SERVER set-card-profile 0 output:hdmi-stereo+input:analog-stereo
else
sudo -u $USER_NAME pactl --server $PULSE_SERVER set-card-profile 0 output:analog-stereo+input:analog-stereo
fi
Note USER_NAME=who | grep "(:0)" | cut -f 1 -d ' '| sort -u
I added | sort -u
because otherwise it came back with elemer elemer elemer
--my username 3 times.
Then make it executable with chmod 0755 /usr/local/bin/hdmi_sound_toggle
Don't forget to reload your udev rules: sudo udevadm control --reload-rules
Important this script is updated for 14.04. Before that, you would use USER_NAME instead of USER_ID everywhere
Credits: Salem and daniel.