Skip to content

feat(audio): add output device selection in Settings > Audio#26

Merged
pythoninthegrass merged 3 commits intomainfrom
begin-backlog-task-268
Mar 10, 2026
Merged

feat(audio): add output device selection in Settings > Audio#26
pythoninthegrass merged 3 commits intomainfrom
begin-backlog-task-268

Conversation

@pythoninthegrass
Copy link
Collaborator

Enumerate available audio output devices via cpal (through rodio) and present them in a dropdown under Settings > Audio. Switching devices preserves current playback position by reloading the track on the new output stream. Selection persists in the Tauri settings store and restores on startup with fallback to system default.

Backend: AudioEngine::set_device(), list_output_devices(), two new Tauri commands (audio_list_devices, audio_set_device), DeviceListResponse type. Frontend: api/audio.js module, Audio nav section in settings view, select dropdown with Default + enumerated devices.

Tests: 10 new Rust unit tests, 6 new Playwright E2E tests.

Closes TASK-268

pythoninthegrass and others added 3 commits March 7, 2026 22:39
Enumerate available audio output devices via cpal (through rodio) and
present them in a dropdown under Settings > Audio. Switching devices
preserves current playback position by reloading the track on the new
output stream. Selection persists in the Tauri settings store and
restores on startup with fallback to system default.

Backend: AudioEngine::set_device(), list_output_devices(), two new Tauri
commands (audio_list_devices, audio_set_device), DeviceListResponse type.
Frontend: api/audio.js module, Audio nav section in settings view, select
dropdown with Default + enumerated devices.

Tests: 10 new Rust unit tests, 6 new Playwright E2E tests.

Closes TASK-268

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
On macOS CoreAudio, two simultaneous OutputStream instances targeting
the same physical device (e.g. switching from named "Mac Studio
Speakers" to "Default" which resolves to the same hardware) causes the
new stream to produce silence. Change stream field to Option<OutputStream>
so the old stream is fully released before opening the new one.

Both device paths (named and default) now use from_device().open_stream(),
and set_device() resolves the target cpal Device first, tears down the
old sink and stream, then creates the new stream.

Add 9 tests covering no-stream error handling (load, backward seek) and
device switch state preservation (stopped, paused, playing, volume,
failed switch, consecutive switches, post-switch load).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
# Conflicts:
#	app/frontend/js/api/index.js
#	crates/mt-tauri/src/lib.rs
@pythoninthegrass pythoninthegrass merged commit d5c9f35 into main Mar 10, 2026
4 checks passed
@pythoninthegrass pythoninthegrass deleted the begin-backlog-task-268 branch March 10, 2026 05:50
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