Skip to content

Instantly share code, notes, and snippets.

@jacobmoroni
Last active February 2, 2022 22:03
Show Gist options
  • Save jacobmoroni/4de5d99691da1bae2ae89b3d61ebbe09 to your computer and use it in GitHub Desktop.
Save jacobmoroni/4de5d99691da1bae2ae89b3d61ebbe09 to your computer and use it in GitHub Desktop.
Keep internal speakers selected when plugged into dock/ crash course on udev rules

Setting up audio stuff for Ubuntu 20

I am trying to setup my computer to use default speaker and microphone when plugged into my dock because it doesnt have speakers and it drives me crazy to set it each time.

One simple solution is to edit the /etc/pulse/default.pa file and comment out the lines that make it automatically switch to whatever is plugged in. These are the lines to comment out (lines 36-38 for me)

.ifexists module-switch-on-connect.so
load-module module-switch-on-connect
.endif

The problem is this disables it always, but I only want it disabled for my dock

So here is another attempt:

To see current speaker options: pactl list short sinks

Will return something like this:

0	alsa_output.pci-0000_01_00.1.hdmi-stereo-extra4	module-alsa-card.c	s16le 2ch 44100Hz	SUSPENDED
1	alsa_output.usb-Lenovo_ThinkPad_Thunderbolt_3_Dock_USB_Audio_000000000000-00.analog-stereo	module-alsa-card.c	s16le 2ch 44100Hz	SUSPENDED
2	alsa_output.pci-0000_00_1f.3.analog-stereo	module-alsa-card.c	s16le 2ch 48000Hz	SUSPENDED

To set the speaker option (This is an example to set it to internal speaker) will likely differ per computer: pactl set-default-sink alsa_output.pci-0000_00_1f.3.analog-stereo

To see current microphone options: pactl list short sources

Will return something like this:

0	alsa_output.pci-0000_01_00.1.hdmi-stereo-extra4.monitor	module-alsa-card.c	s16le 2ch 44100HzSUSPENDED
1	alsa_output.usb-Lenovo_ThinkPad_Thunderbolt_3_Dock_USB_Audio_000000000000-00.analog-stereo.monitor	module-alsa-card.c	s16le 2ch 44100Hz	SUSPENDED
2	alsa_input.usb-Lenovo_ThinkPad_Thunderbolt_3_Dock_USB_Audio_000000000000-00.mono-fallback	module-alsa-card.c	s16le 1ch 44100Hz	SUSPENDED
3	alsa_output.pci-0000_00_1f.3.analog-stereo.monitor	module-alsa-card.c	s16le 2ch 48000HzSUSPENDED
4	alsa_input.pci-0000_00_1f.3.analog-stereo	module-alsa-card.c	s16le 2ch 48000Hz	SUSPENDED

To set microphone option (This is an example to set it to internal microphone) will likely differ per computer: pactl set-default-source alsa_input.pci-0000_00_1f.3.analog-stereo

Then lets move to udev stuff. First we need to figure out what we want to capture. running udevadm monitor --udev --property will capture udev events and print them to the screen and you can go through and see what happened so you can capture it. I wanted to capture a sound card event so I searched through the print out after running it for sound and found this event

UDEV  [2081.044657] add      /devices/pci0000:00/0000:00:1c.0/0000:04:00.0/0000:05:04.0/0000:2d:00.0/0000:2e:02.0/0000:2f:00.0/usb7/7-2/7-2.1/7-2.1.1/7-2.1.1.4/7-2.1.1.4:1.0/sound/card2/pcmC2D0c (sound)
ACTION=add
DEVPATH=/devices/pci0000:00/0000:00:1c.0/0000:04:00.0/0000:05:04.0/0000:2d:00.0/0000:2e:02.0/0000:2f:00.0/usb7/7-2/7-2.1/7-2.1.1/7-2.1.1.4/7-2.1.1.4:1.0/sound/card2/pcmC2D0c
SUBSYSTEM=sound
DEVNAME=/dev/snd/pcmC2D0c
DEVTYPE=pcm
SEQNUM=7239
USEC_INITIALIZED=2081044536
MAJOR=116
MINOR=16
TAGS=:uaccess:

I did a bit more research and wanted to specifically capture the ThinkPad Dock so I searched for that and found this event:

UDEV  [2081.102542] add      /devices/pci0000:00/0000:00:1c.0/0000:04:00.0/0000:05:04.0/0000:2d:00.0/0000:2e:02.0/0000:2f:00.0/usb7/7-2/7-2.1/7-2.1.1/7-2.1.1.4/7-2.1.1.4:1.0/sound/card2/controlC2 (sound)
ACTION=add
DEVPATH=/devices/pci0000:00/0000:00:1c.0/0000:04:00.0/0000:05:04.0/0000:2d:00.0/0000:2e:02.0/0000:2f:00.0/usb7/7-2/7-2.1/7-2.1.1/7-2.1.1.4/7-2.1.1.4:1.0/sound/card2/controlC2
SUBSYSTEM=sound
DEVNAME=/dev/snd/controlC2
SEQNUM=7240
USEC_INITIALIZED=2081045442
ID_VENDOR=Lenovo
ID_VENDOR_ENC=Lenovo
ID_VENDOR_ID=17ef
ID_MODEL=ThinkPad_Thunderbolt_3_Dock_USB_Audio
ID_MODEL_ENC=ThinkPad\x20Thunderbolt\x203\x20Dock\x20USB\x20Audio
ID_MODEL_ID=3083
ID_REVISION=0083
ID_SERIAL=Lenovo_ThinkPad_Thunderbolt_3_Dock_USB_Audio_000000000000
ID_SERIAL_SHORT=000000000000
ID_TYPE=audio
ID_BUS=usb
ID_USB_INTERFACES=:010100:010200:030000:
ID_USB_INTERFACE_NUM=00
ID_USB_DRIVER=snd-usb-audio
ID_PATH=pci-0000:2f:00.0-usb-0:2.1.1.4:1.0
ID_PATH_TAG=pci-0000_2f_00_0-usb-0_2_1_1_4_1_0
MAJOR=116
MINOR=17
DEVLINKS=/dev/snd/by-id/usb-Lenovo_ThinkPad_Thunderbolt_3_Dock_USB_Audio_000000000000-00 /dev/snd/by-path/pci-0000:2f:00.0-usb-0:2.1.1.4:1.0
TAGS=:uaccess:

These provide the necessary information to create a udev rule to capture that event

create a rules file /etc/rules.d/95-dock-connect.rules -the number at the beginning of the file sets the order of the rules running from what I gather. I think the higher it is, the later rule to run.) I set it to 95 because the pulseaudio rule is a 90 and we need this to run after that -the actual name (between the number and the .rules) doesnt matter so name it what you want -probably the .rules does matter

in that file you can add some rules. Here are a couple examples:

SUBSYSTEM=="usb", ACTION=="add", ENV{DEVTYPE}=="usb_device",  RUN+="/bin/device_added.sh"
SUBSYSTEM=="usb", ACTION=="remove", ENV{DEVTYPE}=="usb_device", RUN+="/bin/device_removed.sh"
SUBSYSTEM=="sound", ACTION=="add", ENV{DEVTYPE}=="pcm", RUN+="/bin/sound_added.sh"
KERNEL=="controlC2", SUBSYSTEM=="sound", ACTION=="add", RUN+="/bin/thinkpad_dock_added.sh"

So those are capturing the event that happens with SUBSYSTEM ACTION and DEVTYPE and then when that triggers it runs the script after the RUN+

The first 2 are examples of a USB plugging and unplugging, the 3rd one is capturing the addition of a "pcm" devtype in the sound subsystem. And the last one is capturing the DEVNAME of the sound card controlC2 which is where the thinkpad sound was showing up. (KERNEL== matches with DEVNAME) So that is the trigger I wanted.

after changing a rule you can reload all the rules with this command sudo udevadm control --reload

Then we just need to write the script to handle the event: above we said that it will be in /bin/thinkpad_dock_added.sh

a quick and dirty way to test if you have it right is to put something like this in the file

#!/bin/bash
echo "thinkpad device added at $(date)" >>/home/jacobolson/testing.log

Then plug it in and see if that echo statement shows up in testing.log (or whatever you want to name it)

After verifying that it was correct, I just want to set up the sound how I want it when this is plugged in: final version of the script file /bin/thinkpad_dock_added.sh

#!/bin/bash
sleep 30
if [[ $(pactl list short sinks | grep "Lenovo_ThinkPad_Thunderbolt_3_Dock_USB_Audio") ]]; then
  eval $(pactl set-default-sink alsa_output.pci-0000_00_1f.3.analog-stereo) 
  eval $(pactl set-default-source alsa_input.pci-0000_00_1f.3.analog-stereo) 
fi

And the final version of the rules file: /etc/udev/rules.d/95-dock-connected.rules

KERNEL=="controlC2", SUBSYSTEM=="sound", ACTION=="add", RUN+="/bin/thinkpad_dock_added.sh"

Once that file is written, dont forget to make it executable and reload the udev rules

bada-bing bada-boom!

Here are some of the sites I used to make this. Here for a deeper dive if needed

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