I got a new old laptop
This laptop is rather “old” compared to today’s new and shiny hardware but ticks all the cases for me.
- It was cheap (for me, it was surplus from a company)
- It has a nice processor
11th Gen Intel(R) Core(TM) i7-11850H @ 2.50GHz
- It has plenty of RAM (16G and a free slot)
- This or a pretty similar model is Ubuntu Certified (this means a team in Ubuntu took the time to check every release of their system to work on these and even made changes to their oem kernel to accomodate the quirks brought in from Lenovo being too liberal with the interpretation of the standards)
Live USB
The Ubuntu Live Image is gorgeous and works out of the box with everything my laptop has to offer (23.10 at the time of writting this). Now, this is where the fun begin.
My laptop has a mute key tha has a led, the led is on when the laptop is muted, it has the same in the microphone mute one.
This works flawlessly on the live image but once installed only the mic mute light works.
Now: I did rip off snapd
from Ubuntu so I might have disturbed the normal flow of things.
After reading a bit, I could not understand why this did not work, the kernel mechanism that makes it work is there and I can even trigger the led by hand:
# This turns on the led
echo 1 | sudo tee /sys/class/leds/platform\:\:mute/brightness
I spent a few hours trying various fixes and trying to understand what was different in the live image without success, the people putting together that image are way smarted than I am.
The cheap solution
Turns out you can subscribe to pulse audio and listen for events so I wrote a small systemd daemon to turn on/off the led.
For this I first had to add an udev rule to make it writeable without sudo.
I placed this file in /etc/udev/rules.d/99-mute_led.rules
ACTION=="add", SUBSYSTEM=="leds", KERNEL=="platform::mute", RUN+="/bin/chmod a+w /sys/class/leds/%k/brightness"
Then I wrote a python script that did the pulse subscription, I used a handy library
requirements.txt
pulsectl==23.5.2
#!/usr/bin/env python
import time
from pulsectl import Pulse, PulseLoopStop
# This is the name for my laptop, a Thinkpad X1 Extreme Gen 4
SINK_NAME="alsa_output.pci-0000_00_1f.3-platform-skl_hda_dsp_generic.HiFi__hw_sofhdadsp__sink"
def get_sink_number(pulse):
"""
return the index for the sink we care about
"""
return pulse.get_sink_by_name(SINK_NAME).index
def set_led_brightness(sink_number, is_muted):
"""
set the status of the led according to the mute status
"""
# Determine the LED brightness value based on mute status
brightness = 0 if not is_muted else 1
with open('/sys/class/leds/platform::mute/brightness', 'w') as led:
led.write(f'{brightness}')
def main():
with Pulse("mute-led-listener") as pulse:
sink_number = get_sink_number(pulse)
def mute_button(ev):
"""
callback to be invoked every time an event matches the set match
we only raise a loop stop exception to trigger the event loop to
exit, we cannot perform pulse operations while the loop is running.
"""
if ev.index == sink_number:
raise PulseLoopStop
pulse.event_mask_set("sink")
pulse.event_callback_set(mute_button)
while True:
# Lock until we have an event match.
pulse.event_listen()
# Get mute status for our sink
is_muted = pulse.get_sink_by_name(SINK_NAME).mute == 1
# Set LED brightness based on mute status
set_led_brightness(sink_number, is_muted)
# Then we will begin the listener again and only trigger next time button is pressed
if __name__ == "__main__":
main()
Note: Check if the name of the device works with you, you can check this using pactl
tool.
And tied it all together with a systemd daemon
$HOME/.local/share/systemd/user/led-control.service
# $HOME/.local/share/systemd/user/led-control.service
[Unit]
Description=LED Control Service
[Service]
Type=simple
ExecStart=/home/hduran/vimconfig/thinkpad/venv/bin/python /home/hduran/vimconfig/thinkpad/mute_led_helper.py
[Install]
WantedBy=default.target
Note: The python path is a bit odd because I created a virtualenv for this (you should do the same if you want to install this package, not install system wide)
After this you need to run:
systemctl --user enable led-control.service
systemctl --user start led-control.service