feat(hardware): mute/mic-mute keyboard LED sync (steelbore-audio-led)#17
Merged
Conversation
On the T490s the mute (platform::mute) and mic-mute (platform::micmute)
keyboard LEDs stayed dark under Niri: the kernel audio-mute/audio-micmute
triggers follow the ALSA *hardware* mute, but PipeWire mutes the node in
*software*, so the hardware mute never flips. (CapsLock and FnLock already work
via the kernel input layer and the EC/thinkpad_acpi respectively.)
Add steelbore-audio-led (pkgs/steelbore-audio-led/, Rust + libpulse-binding): a
tiny event-driven daemon that subscribes to default sink/source mute changes and
writes the LED brightness nodes directly, so the LEDs track mute regardless of
how it was toggled (key, GUI, per-app). Single-threaded by design (inherently
serial workload); resilience delegated to systemd Restart=on-failure.
New module modules/hardware/audio-led.nix (steelbore.hardware.audioLed.enable):
- udev rule sets platform::{mute,micmute} trigger=none so the daemon owns the
LEDs (trigger is root-only; brightness is already input-group-writable via the
brightnessctl udev rule in modules/desktops/niri.nix).
- systemd *user* service running the daemon, ordered after pipewire/wireplumber/
pipewire-pulse.
Enabled on hosts/thinkpad. PRD.md §6.4 + TODO.md Phase 7 updated.
Verified: package builds; daemon connects to the live session; toggling mute via
wpctl drives both LEDs 1/0 end-to-end (mic + speaker).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
On the ThinkPad T490s, the mute (F1) and mic-mute (F4) keyboard LEDs stayed dark under Niri. The kernel
audio-mute/audio-micmutetriggers follow the ALSA hardware mute, but PipeWire mutes the node in software, so the hardware mute never flips and the LEDs never light. (CapsLock and FnLock already work — kernel input layer and EC/thinkpad_acpirespectively — so they need no changes.)Solution
A tiny Rust daemon,
steelbore-audio-led(pkgs/steelbore-audio-led/,libpulse-binding), that subscribes to default sink/source mute changes and writes the LEDbrightnessnodes directly — so the LEDs track mute no matter how it was toggled (key, GUI, per-app). Keybinds are unchanged.New module
modules/hardware/audio-led.nix(steelbore.hardware.audioLed.enable, enabled onhosts/thinkpad):platform::{mute,micmute}trigger=noneso the daemon owns the LEDs (thetriggerattr is root-only;brightnessis alreadyinput-group-writable via the brightnessctl udev rule inmodules/desktops/niri.nix).Restart=on-failure.Design: single-threaded (inherently serial workload — documented per Standard §3.2);
mimallocomitted (no alloc hot path); SPDX headers + Rust-guideline lints.Verification
nix buildof the toplevel — builds clean.wpctldrives both LEDs1/0(mic + speaker) ✅.Docs:
PRD.md§6.4,TODO.mdPhase 7.🤖 Generated with Claude Code