Skip to content

fix(audio): apply sink volume via pactl for BlueZ sinks - #3407

Closed
li-yuanfei wants to merge 1 commit into
AvengeMedia:masterfrom
li-yuanfei:pr/bluetooth-sink-volume-upstream
Closed

li-yuanfei wants to merge 1 commit into
AvengeMedia:masterfrom
li-yuanfei:pr/bluetooth-sink-volume-upstream

Conversation

@li-yuanfei

Copy link
Copy Markdown
Contributor

Problem

On some Bluetooth (BlueZ/PipeWire) sinks, writing the QML volume property does not
reach the device — the UI slider moves, the OSD changes, but the actual sink volume
stays where it was. Those sinks only respond to pactl set-sink-volume.

Fix

Add AudioService.setSinkVolume(), which issues
pactl set-sink-volume <sink> <n>% and reports whether it handled the change.
setVolume() and adjustDefaultSinkVolume() try it first and fall back to the
existing property setter when no sink name is available.

The DankDash media dropdown and media player tab route their volume writes through
AudioService.setVolume() so every volume surface shares the same code path.

This follows existing precedent — AudioService already shells out to pactl
for sink enumeration and port switching (pactl list sinks, pactl set-sink-port).

Units

setSinkVolume() takes a percentage (0..sinkMaxVolume), matching the pactl
argument. The QML audio.volume property keeps its 0..1 fraction semantics, so
the fallback path still writes volume / 100.

Testing

  • make lint-qml — PASS (3 entrypoints)
  • make test-qml fails on this machine, but also fails on unmodified upstream
    master
    in the same environment, so it is not a regression from this change.

Verified manually on a BlueZ sink that previously ignored UI volume changes:
volume now tracks the slider.

Some BlueZ/PipeWire sinks do not reliably apply the QML volume property
setter, so volume changes made from the DMS UI were silently dropped on
those devices.

Add `AudioService.setSinkVolume()`, which issues
`pactl set-sink-volume <sink> <n>%` and reports whether it handled the
change. `setVolume()` and `adjustDefaultSinkVolume()` now try it first
and fall back to the existing property setter when no sink name is
available. The DankDash media dropdown and media player tab route their
volume writes through `AudioService.setVolume()` so every volume surface
shares the same path.

`setSinkVolume()` takes a percentage (matching `pactl`), while the QML
`audio.volume` property keeps its 0..1 fraction semantics.
@bbedward

Copy link
Copy Markdown
Collaborator

Pretty sure related to quickshell-mirror/quickshell#808

quickshell-mirror/quickshell#807

Using pactl as a workaround comes with other problems so I'd rather not do that

@bbedward

Copy link
Copy Markdown
Collaborator

Closing (because quickshell fix is preferred), as a workaround you can change your keybinds to use pactl/wpctl instead of dms volume commands though

@bbedward bbedward closed this Sep 15, 2026
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.

2 participants