Skip to content

Wake the Asahi mic mapper on PipeWire events instead of polling every 2 s - #403

Open
skuthus wants to merge 1 commit into
omacom:quattrofrom
skuthus:asahi-mic-map-events
Open

Wake the Asahi mic mapper on PipeWire events instead of polling every 2 s#403
skuthus wants to merge 1 commit into
omacom:quattrofrom
skuthus:asahi-mic-map-events

Conversation

@skuthus

@skuthus skuthus commented Sep 11, 2026

Copy link
Copy Markdown

omarchy-asahi-mic.service --watch re-ran pw-dump plus several pactl queries every 2 seconds, forever, on every Apple Silicon machine. Measured on a MacBook Pro 14" (M1 Max), Omarchy 4.0.3-1, nothing playing:

audio stack CPU over 10 s (pipewire + pipewire-pulse + wireplumber + mapper)
before 142 jiffies — 14.2% of a core, constantly
after 3 jiffies — 0.3%

The stack never idled because the poll kept it awake.

What changed — bin/omarchy-audio-asahi-mic-map (+110 / −13)

  1. supervise() sleeps on pactl subscribe and repairs only when something that can break the mapping happens: a sink, source, card or module appears or vanishes, a card or module changes, or the server changes (pipewire-pulse restart, default device switch).
  2. Stream and client events are ignored, and so are sink/source change events: every stream start and stop emits those, and the mapping depends only on node existence, links and defaults.
  3. A burst settles for 0.5 s so a hot-plug repairs once; a 5 s cap keeps a steady event stream from starving repair; a 10-minute backstop keeps the eventually-consistent behaviour the poll gave. That backstop is also what persists a gain change made between other events — the one thing that now waits up to 10 min instead of 2 s. omarchy-restart-audio --save-state still saves immediately.
  4. A lost subscription (pipewire-pulse not up yet, or restarted) repairs once and resubscribes after 2 s — the old cadence, only while there is nothing to subscribe to.
  5. SIGTERM unwinds through supervise so the subscriber child exits with the service.

Unit file, migration and the --save-state path are unchanged. supervise(operation, wait=None) keeps working for existing callers; the test injects wait.

Verified on hardware

  1. Idle: the numbers above.
  2. pactl load-module module-null-sink … → repair ran inside the settle window.
  3. pactl unload-module <omarchy_asahi_mic> → sink rebuilt after ~500 ms.
  4. paplay a 0.5 s clip → zero repairs triggered.
  5. kill -TERM the watcher → no pactl subscribe left behind.

Tests

test/shell.d/asahi-mic-map-test.sh passes. New coverage: wake on device event, wake on server change, no wake on stream events, settle cap, lost subscription, missing subscriber.

To review in 2 minutes

Read Subscription.wait() (25 lines). Everything else is plumbing.

🤖 Generated with Claude Code

https://claude.ai/code/session_01WHvo2RfghRcv7UoqFntuM9

--watch re-ran pw-dump and several pactl queries every 2 s, which kept
pipewire, pipewire-pulse and wireplumber awake around the clock: 14.2%
of a core on an idle M1 Max, 0.3% after. supervise() now sleeps on
pactl subscribe and repairs when a sink, source, card or module appears
or vanishes, a card or module changes, or the server does. Stream,
client and sink/source change events are ignored; bursts settle for
0.5 s with a 5 s cap; a 10-minute backstop keeps eventual consistency.
A lost subscription repairs once and resubscribes after 2 s. SIGTERM
unwinds through supervise so the subscriber exits with the service.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WHvo2RfghRcv7UoqFntuM9
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant