Sound and Power: follow volume and brightness changes made elsewhere #42

Merged
Breadway merged 1 commit from fix/live-sound-brightness into main 2026-10-02 12:22:50 +08:00
Owner

The Sound page read PipeWire state once on mount, so volume keys, the bar OSD or another mixer left it stale and the next drag jumped from the old value. Power had the same pattern for brightness (checked by reading the code: it also read once).

Sound. New watch_sound command starts a single pactl subscribe watcher per process (restarts itself if PipeWire or pactl goes away) and emits a coalesced sound-changed event (150 ms) for change/new/remove on sink, source, server and sink-input; card, client and module chatter is ignored (is_relevant_event, 3 unit tests). The Sound page invokes it on mount and re-reads on each event.

Power. New get_brightness command; the page polls it every 2 s while the window is visible, and refreshes battery readings roughly every 10 s.

No fighting the user. liveGate (frontend/src/lib/liveGate.ts, liveGate.test.mjs): an external read never replaces a slider that is being dragged or was moved in the last 700 ms (the read-back echo of the user's own change); a blocked Sound read is retried after 800 ms so nothing is lost.

Manual test checklist (UI not run, by instruction)

  1. Open Sound, run wpctl set-volume @DEFAULT_AUDIO_SINK@ 0.77 (or press a volume key): the slider and percentage follow within a fraction of a second.
  2. Drag the slider while pressing volume keys: the slider is not yanked from under the pointer.
  3. Plug in headphones / change the default device elsewhere: the device list and "In use" mark follow.
  4. Open Power & battery, press a brightness key: the slider follows within about 2 s.

Verification: npm run check (0 errors, 0 warnings), npm run build, node --experimental-strip-types frontend/src/lib/liveGate.test.mjs, cargo fmt --all -- --check, cargo clippy --all-targets --locked -- -D warnings, cargo test --locked (78 passed).

Closes BSET-31

The Sound page read PipeWire state once on mount, so volume keys, the bar OSD or another mixer left it stale and the next drag jumped from the old value. Power had the same pattern for brightness (checked by reading the code: it also read once). **Sound.** New `watch_sound` command starts a single `pactl subscribe` watcher per process (restarts itself if PipeWire or pactl goes away) and emits a coalesced `sound-changed` event (150 ms) for `change/new/remove` on `sink`, `source`, `server` and `sink-input`; card, client and module chatter is ignored (`is_relevant_event`, 3 unit tests). The Sound page invokes it on mount and re-reads on each event. **Power.** New `get_brightness` command; the page polls it every 2 s while the window is visible, and refreshes battery readings roughly every 10 s. **No fighting the user.** `liveGate` (`frontend/src/lib/liveGate.ts`, `liveGate.test.mjs`): an external read never replaces a slider that is being dragged or was moved in the last 700 ms (the read-back echo of the user's own change); a blocked Sound read is retried after 800 ms so nothing is lost. **Manual test checklist (UI not run, by instruction)** 1. Open Sound, run `wpctl set-volume @DEFAULT_AUDIO_SINK@ 0.77` (or press a volume key): the slider and percentage follow within a fraction of a second. 2. Drag the slider while pressing volume keys: the slider is not yanked from under the pointer. 3. Plug in headphones / change the default device elsewhere: the device list and "In use" mark follow. 4. Open Power & battery, press a brightness key: the slider follows within about 2 s. Verification: `npm run check` (0 errors, 0 warnings), `npm run build`, `node --experimental-strip-types frontend/src/lib/liveGate.test.mjs`, `cargo fmt --all -- --check`, `cargo clippy --all-targets --locked -- -D warnings`, `cargo test --locked` (78 passed). Closes BSET-31
fix(sound,power): keep volume and brightness in sync with external changes
All checks were successful
check / check (push) Successful in 2m12s
72e4affb9c
The Sound page read state once on mount, so volume keys, the bar or another
mixer left it stale and the next drag jumped from the old value. Power did the
same for brightness.

- sound.rs: watch_sound starts one 'pactl subscribe' watcher per process and
  emits a coalesced 'sound-changed' event for sink, source, server and
  sink-input changes; the Sound page re-reads on each event.
- power.rs: get_brightness is a cheap poll target; the Power page polls it
  every 2 s while visible (and refreshes battery readings every ~10 s).
- liveGate: a read never replaces a slider that is being dragged or was just
  moved, so the page cannot fight the user; unit tested.
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
Breadway/bos-settings!42
No description provided.