Skip to content

feat(presets): add per-preset output device association#294

Open
dennislemennace wants to merge 1 commit into
Audio4Linux:masterfrom
dennislemennace:preset-output-device
Open

feat(presets): add per-preset output device association#294
dennislemennace wants to merge 1 commit into
Audio4Linux:masterfrom
dennislemennace:preset-output-device

Conversation

@dennislemennace
Copy link
Copy Markdown

What this does

Adds an opt-in "Remember output device" checkbox to the Presets panel. When checked at save time, the currently selected output device is stored alongside the preset. When that preset is later loaded — from the panel or the tray icon — the app automatically switches to that device, making profile switching a single action.

Default behaviour is completely unchanged: presets saved without the checkbox never affect the output device.

Implementation details

Storage — a new preset_devices.json sidecar file managed by PresetManager, structured as a JSON object mapping preset name → {deviceId, useDefault}. This mirrors the existing preset_rules.json pattern and deliberately keeps device names out of the portable .conf preset files, since they are machine-specific.

Apply pathapplyPresetDevice() sets AppConfig::AudioOutputDevice + AppConfig::AudioOutputUseDefault, which triggers a live device switch via PipewireAudioService::onAppConfigUpdated — the same path SettingsFragment uses when the user picks a device manually.

Feedback-loop guard — the existing onOutputDeviceChanged rule system loads presets in response to device changes. A _suppressDeviceApply flag prevents the loaded preset from firing another device change in that code path.

Rename/delete syncPresetManager::rename() and remove() keep _presetDevices in sync so stale entries don't accumulate.

PulseAudio — the new checkbox is hidden under #ifdef USE_PULSEAUDIO alongside the existing Rules button, since the PulseAudio device-switching path is stubbed (PulsePipelineManager hardcodes use_default_sink = true).

Files changed

  • src/data/PresetManager.h — new map, path helper, load/save/set/clear/has/apply declarations
  • src/data/PresetManager.cpp — full implementation + hooks in loadFromPath, rename, remove, onOutputDeviceChanged
  • src/interface/fragment/PresetFragment.uirememberDevice QCheckBox
  • src/interface/fragment/PresetFragment.cpp — checkbox wired to save/reflect state; hidden on PulseAudio

Lets a preset optionally remember which output device was active when it
was saved, and switch to that device automatically when the preset is
loaded — making profile switching a single action instead of two.

- PresetManager: new _presetDevices map (name → {deviceId, useDefault}),
  persisted in preset_devices.json alongside the existing preset_rules.json.
  setPresetDevice/clearPresetDevice/hasPresetDevice/applyPresetDevice API.
  applyPresetDevice() sets AppConfig::AudioOutputDevice +
  AudioOutputUseDefault, which triggers a live switch via
  PipewireAudioService::onAppConfigUpdated — the same path SettingsFragment
  uses. A _suppressDeviceApply guard prevents a feedback loop when a
  device-change rule fires and loads a preset via onOutputDeviceChanged.
  rename() and remove() keep the map in sync.
- PresetFragment: "Remember output device" checkbox (opt-in; default
  behaviour unchanged). Hidden on PulseAudio builds alongside the existing
  rules button, since the PulseAudio device-switch path is stubbed.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@dennislemennace
Copy link
Copy Markdown
Author

dennislemennace commented May 21, 2026

Hi, I am new to github and this is my first PR using LLM. This is a feature which is super convenient for my use case, which is having different profile presets for each device. This allows the output device to be saved with the preset if the checkbox is enabled. I have built and tested on Bazzite and seems to work well. Please consider approving this, and let me know if I can improve this PR in anyway! Thanks for the great software :)

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