Skip to content

feat: cycle output device button action#1

Merged
PalmarHealer merged 3 commits into
mainfrom
feat/output-cycling
May 29, 2026
Merged

feat: cycle output device button action#1
PalmarHealer merged 3 commits into
mainfrom
feat/output-cycling

Conversation

@PalmarHealer

Copy link
Copy Markdown
Contributor

Summary

Adds a "Cycle output device" button action. On each press it switches the default audio endpoint to the next device in a configured list (wrapping). An empty list cycles through all active output endpoints.

This is the first of the planned controller features and validates the non-volume action plumbing end-to-end.

What changed

  • model: new ActionKind::CycleOutput; the action's property holds a newline-separated device list (empty = all).
  • events / actuator: button press emits Cmd::CycleOutput, applied off the UI thread via a new AudioBackend::cycle_output.
  • wasapi (Windows): switches the default endpoint via the undocumented IPolicyConfig COM interface, declared with the windows #[interface] macro (added windows-core as a direct dep so the macro's ::windows_core paths resolve, pinned to the same 0.58 windows re-exports). The current default is matched by stable device id, so duplicate friendly names (e.g. two identically-named LG monitors) still cycle correctly. find_device was refactored to share the name resolver (resolve_in).
  • pulse (Linux): cycle_output via pactl get/set-default-sink.
  • UI: the wizard picker became multi-select for this kind — rows toggle membership, the chosen set lives in the wizard property, and an empty selection is allowed (= all). The action's list label is derived at render time and joined with .

Testing

  • cargo build clean; cargo test 9 passed.
  • Manually verified on Windows: the default output correctly advances through the selected devices on each button press, including between two identically-named LG endpoints. Label renders correctly.

🤖 Generated with Claude Code

PalmarHealer and others added 3 commits May 29, 2026 08:55
Two endpoints can report the same friendly name (e.g. two monitors on
one GPU's NVIDIA audio). list_devices now appends " (2)", " (3)", … to
repeated names so each is shown and selectable; find_device parses the
suffix back to the Nth same-named endpoint. The first occurrence stays
bare, so already-saved configs keep resolving.

Also pin the Icon component to a fixed size. Without a max-width, a
layout gave it an implicit stretch factor of 1, so it ate row free
space and the centered glyph drifted off the right edge.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds a "Cycle output device" button action that switches the default
audio endpoint to the next device in a configured list on each press
(wrapping). An empty list cycles through all active outputs.

- model: new ActionKind::CycleOutput; property holds a newline-separated
  device list (empty = all).
- events/actuator: Cmd::CycleOutput dispatched on button press, applied
  off the UI thread via a new AudioBackend::cycle_output.
- wasapi: switch the default endpoint via the undocumented IPolicyConfig
  COM interface (declared with the windows #[interface] macro), matching
  the current default by stable device id so duplicate friendly names
  still cycle correctly. find_device refactored to share the name
  resolver (resolve_in).
- pulse: cycle_output via pactl get/set-default-sink.
- UI: multi-select picker in the wizard — rows toggle membership, the
  chosen set lives in the wizard property; empty selection is allowed.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The ⇄ (U+21C4) separator isn't in Inter and rendered as a tofu box.
Derive the action's secondary label at render time from the device
list, joined with → (U+2192), so it's correct without a stored display
and fixes already-saved actions without re-adding them.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@PalmarHealer PalmarHealer merged commit 1ab725b into main May 29, 2026
@PalmarHealer PalmarHealer deleted the feat/output-cycling branch May 29, 2026 09:39
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