The Cookie Machine - Click here to drag window

DUMMY TEXT - Real text set in assets/js/theCookieMachine.js

If you can read me, I'm broken!

Views: 11,487β€…    Votes:  9β€…
Tags: 16.04   sound   pulseaudio   alsa   hdmi  
Link: πŸ” See Original Answer on Ask Ubuntu ⧉ πŸ”—

URL: https://askubuntu.com/q/854079
Title: Switch between internal and HDMI speakers automatically
ID: /2016/11/27/Switch-between-internal-and-HDMI-speakers-automatically
Created: November 27, 2016    Edited:  February 8, 2017
Upload: April 8, 2024    Layout:  post
TOC: false    Navigation:  true    Copy to clipboard:  false


Skip

Background

I had a similar problem during suspend/resume when sound would switch from HDMI TV to laptop speakers. Upon resume sound would stay on Laptop speakers and I would have to manually reset output device to TV in System Settings -> Sound.

This was one of my first annoying experiences with upgrade from Ubuntu 14.04 to 16.04 and the root was upgrade to PulseAudio 8 that comes with 16.04 LTS

After much searching I created a script called TV-sound. Although I don’t plug and unplug the TV like yourself, I did some google searches and create a variation of the script to work in your situation. I’ve tested it and it works.

Step 1: Create script to switch audio between connected devices

We’ll create a script called hotplugtv which udev calls. This same script can be called in many places though. For example, during testing I used it in lock-screen-timer where sound reverted back to Laptop during screen lock.

cd /usr/local/bin
sudo touch hotplugtv
sudo chmod +x hotplugtv
gksu gedit hotplugtv

When the editor opens with a blank screen, copy and paste the following into it:

#! /bin/bash

# NAME: hotplugtv
# PATH: /usr/local/bin
# DESC: Update pulseaudio output device when HDMI TV plugged / unplugged
# CALL: called from /etc/udev/rules.d/99-monitor-hotplug.rules
# DATE: Created Nov 26, 2016.
# NOTE: logs output using log-file
# UPDT: Dec 14, 2016 - Sometimes /sys/class/drm/card0 & sometimes /sys/class/drm/card1
#       so use /sys/class/dmcard* instead.

if [[ $(cat /sys/class/drm/card*-HDMI-A-1/status | grep -Ec "^connected") -eq 1 ]]; then
#        log-file "HDMI TV connected" ~/bin/log-hotplugtv;
        /bin/sleep 2;
        export PULSE_RUNTIME_PATH="/run/user/1000/pulse/";
        sudo -u rick -E pacmd set-card-profile 0 output:hdmi-stereo;
else
#        log-file "HDMI TV disconnected" ~/bin/log-hotplugtv;
        export PULSE_RUNTIME_PATH="/run/user/1000/pulse/";
        sudo -u rick -E pacmd set-card-profile 0 output:analog-stereo;
fi

exit 0

You will need to replace the two occurrences of rick with your own user id, ie UTF-8, etc.

I know this can be more professional with user name automatically set to a bash variable but I’m not that skilled yet :( Anyway, save the file and exit gedit.

Top ToS Skip

Step 2: Create udev rules

udev monitors hotplug events when you plug in and unplug your HDMI monitor. Type the following to create a new rule.

cd /etc/udev/rules.d
sudo cp 70-persistent-net.rules 99-hotplugtv.rules
gksu gedit 99-hotplugtv.rules

NOTE: If the file 70-persistent-net.rules doesn’t exist in your directory copy any other file there. We don’t need the file contents, just the file permissions to ensure ours are the same.

The editor will show a bunch of irrelevant text, highlight it and delete it. Then highlight the code below and paste it into the editor:

# NAME: 99-hotplugtv.rules
# PATH: /etc/udev/rules.d
# DESC: Update pulseaudio output device when HDMI TV plugged / unplugged
# CALL: automatically called on system events
# DATE: Created Nov 26, 2016.
# NOTE: in future may requre systemd service hooks

ACTION=="change", SUBSYSTEM=="drm", ENV{HOTPLUG}=="1", RUN+="/usr/local/bin/hotplugtv"

Save the file and exit.

To enable the rule (without rebooting) we need to reload udev:

sudo udevadm control --reload-rules

Now you can plug and unplug your HDMI monitor / TV and the sound switches appropriately.

Top ToS Skip

Caveat

On my system the sound automatically reverts to the Laptop speakers when HDMI is unplugged. On your system it did not. Further enhancements to the code may be required if sound doesn’t go to your Laptop speakers when HDMI is unplugged. Please reply via comment below how things work / don’t work out.

Quick testing in CLI

You can quickly test the code at the terminal by using:

    export PULSE_RUNTIME_PATH="/run/user/1000/pulse/";
        sudo -u rick -E pacmd set-card-profile 0 output:hdmi-stereo;
        sudo -u rick -E pacmd set-card-profile 0 output:analog-stereo;

Top ToS Skip

Deciphering your device name within PulseAudio

The code below uses the same command twice. Once when the sound is set to external HDMI TV. A second time when the sound is set to the Laptop’s built in speakers. Each time you see the name PulseAudio uses:

$ pacmd list-sinks | grep -e 'name:' -e 'index'
  * index: 28
	name: <alsa_output.pci-0000_00_1b.0.hdmi-stereo>
───────────────────────────────────────────────────────────────────────────────
$ pacmd list-sinks | grep -e 'name:' -e 'index'
  * index: 30
	name: <alsa_output.pci-0000_00_1b.0.analog-stereo>

Top ToS Skip

When you have multiple sound cards

Use the command aplay -l to see if you have cards greater than number 0. If so you will need to use appropriate card number in your scripts. For example:

$ aplay -l
**** List of PLAYBACK Hardware Devices ****
card 0: PCH [HDA Intel PCH], device 0: 92HD91BXX Analog [92HD91BXX Analog]
  Subdevices: 1/1
  Subdevice #0: subdevice #0
card 0: PCH [HDA Intel PCH], device 3: HDMI 0 [HDMI 0]
  Subdevices: 0/1
  Subdevice #0: subdevice #0

In the above example all card numbers are 0 with different output sources. If you have USB speakers they can have a different card number than 0.

Top ToS Skip

Edit December 2, 2016

For some unknown reason the script was broken today. Above code used to read: β€œ$(cat /sys/class/drm/card0-HDMI-A-1/status” but I had to change card0 to card1 and the code above has been revised as such. I can’t explain what changed on my system other than regular Ubuntu updates since November 26, 2016.

Edit December 14, 2016

Above code needed to be switched again back to: β€œ$(cat /sys/class/drm/card0-HDMI-A-1/status”. Instead of revising code between card0 and card1 depending on boot, revise program to reference card* to capture both scenarios.

Top ToS
⇧ Do I need to remove Grub when converting from Ubuntu server to desktop? How to detect processor correct temperature in conky  β‡©