From bf4c172ac03b8ad5cb9d422f974ae1ad0e5ca895 Mon Sep 17 00:00:00 2001 From: Felitendo Date: Thu, 24 Sep 2026 02:00:37 +0200 Subject: [PATCH] docs: cut the readme down, fold the details --- README.md | 172 +++++++++++++++--------------------------------------- 1 file changed, 46 insertions(+), 126 deletions(-) diff --git a/README.md b/README.md index 388e586..0f85049 100644 --- a/README.md +++ b/README.md @@ -4,15 +4,15 @@

bt-volume-step

-

Fixed volume steps for Bluetooth audio devices on PipeWire.

+

Clean volume steps for Bluetooth headphones and speakers.

- One press or swipe on your earbuds or speaker becomes one clean step on your volume slider. + One press or swipe on your device becomes one clean step on your volume slider.

- How to use | - Install | + Install | + How to use | Report a bug
@@ -20,158 +20,78 @@ Buy Me A Coffee

-## The problem +| | Volume after each swipe on AirPods Pro | +|---|---| +| Before | 6 · 13 · 19 · 25 · 31 · 38 · 44 · 50 ... | +| After | 5 · 10 · 15 · 20 · 25 · 30 · 35 · 40 ... | -Many Bluetooth devices carry a coarse internal volume grid. AirPods Pro expose -only 16 AVRCP steps, so every swipe on the stem moves the system volume by -6.25 %, and the on-screen display walks through - -``` -6 · 13 · 19 · 25 · 31 · 38 · 44 · 50 · 56 · 63 · 69 · 75 · 81 · 88 · 94 · 100 -``` - -instead of clean multiples of five. A speaker's volume buttons do the same -thing with whatever grid that speaker happens to use. - -This is not a desktop misconfiguration. KDE's own volume step is already -exactly 5 %. The grid lives in the device firmware, and it cannot be changed: -the device sends *absolute* volume values over AVRCP, not increments. - -## What this does - -`bt-volume-step` watches for device-initiated volume changes, takes only their -*direction* into account, and applies a clean step of its own instead. One -press or swipe on the device becomes one step on your desktop's grid. - -It works because such devices adopt a volume written back over AVRCP silently, -without reporting it, so there is no feedback loop. As a side effect the -device's internal position follows the corrected value, which keeps it from -running into the end of its own scale. - -## Requirements - -- PipeWire with `pactl` (`libpulse`) -- Python 3.9 or newer -- Optional: `kreadconfig6` (KDE Plasma) to follow the desktop's own step size -- Optional: `bluez-utils` for device names in `--show` - -## Installation - -### Arch Linux +## Install ```bash yay -S bt-volume-step -``` - -### From source - -```bash -sudo make install -``` - -`make install` honours `PREFIX` and `DESTDIR`; for a per-user install use -`make install PREFIX=$HOME/.local`. - -## Usage - -Enable it for your user session: - -```bash systemctl --user enable --now bt-volume-step ``` -That is the whole setup. Connect a Bluetooth device and use its volume -control. +Needs PipeWire and Python 3.9 or newer. -## Calibration +## How to use -The daemon measures each device's grid on its own. **While a device's grid is -unknown it does not intervene at all**, it only watches. Once the same jump -has repeated three times, that jump is accepted as the device step and -remembered, and corrections start from then on. In practice: press volume-up -three or four times on a new device and it is set up. - -Show what has been measured: +Connect your device and press volume up three or four times. Now it knows the device and every +step is clean. ```bash -bt-volume-step --show +bt-volume-step --show # what it measured +bt-volume-step --reset # forget it ``` -``` -file: /home/you/.local/state/bt-volume-step/devsteps.json - AirPods Pro (30_0E_43_04_52_19) = 6.25 % (16 steps) -``` +## More -Discard a measurement (all devices, or one MAC): +
+How it works -```bash -bt-volume-step --reset -bt-volume-step --reset 30_0E_43_04_52_19 -``` +Many Bluetooth devices only know a few volume steps (AirPods Pro: 16), and they send the volume as a +number, not as "up" or "down". bt-volume-step only looks at which way the volume moved and sets a +clean step of its own. The device takes that new volume without a word, so nothing fights back. -To keep the daemon from calibrating itself onto keyboard input, jumps that -match the desktop's own step size are excluded from measurement, as are jumps -below 1.5 % or above 20 %. A device whose grid happens to equal the desktop -step therefore never calibrates, and is left alone. +It only steps in once it has seen the same jump three times. Until then it just watches. -## Configuration +
-On KDE Plasma the step size comes from *System Settings → Audio → Volume step* -(`plasmaparc [General] VolumeStep`, read through `kreadconfig6` so KDE's -configuration cascade applies). Changes take effect within two seconds, with -no restart. On other desktops, or without `kreadconfig6`, it falls back to -5 %. +
+Settings -Everything can be overridden through the environment. Put these in a drop-in -(`systemctl --user edit bt-volume-step`): +On KDE Plasma the step comes from *System Settings → Audio → Volume step*, elsewhere it is 5 %. +To change more, use `systemctl --user edit bt-volume-step`: -| Variable | Effect | +| | | |---|---| -| `BT_VOL_STEP` | fixed step size in percent; ignores the desktop setting | -| `BT_VOL_DEVSTEP` | fixed device grid in percent; skips measurement | -| `BT_VOL_MAC` | only watch this device (MAC with `_` instead of `:`) | -| `BT_VOL_MAX` | upper limit in percent (default 100) | +| `BT_VOL_STEP` | Fixed step in percent | +| `BT_VOL_DEVSTEP` | Fixed device step, skips measuring | +| `BT_VOL_MAC` | Only this device (MAC with `_` instead of `:`) | +| `BT_VOL_MAX` | Highest volume in percent (default 100) | -The daemon handles several connected Bluetooth devices at once, keeping state -and calibration per device. +
-## Localisation +
+Limits -Messages follow `LC_ALL` / `LC_MESSAGES` / `LANG`. English and German are -included; other languages fall back to English. To add one, extend -`TRANSLATIONS` in the script. English strings are the keys. +- A volume change from somewhere else that happens to match one or two device steps can be read + as a swipe. +- Devices that report their volume back are not supported. Set a volume and check after a few + seconds with `pactl get-sink-volume`: if it moved on its own, this tool is not for that device. -## Limitations +
-**Foreign volume changes can be misread.** PipeWire events carry no -information about where a change came from, so a jump that happens to match -one or two device steps is indistinguishable from a button press. The daemon -accepts at most two steps per event to keep that window narrow, but it cannot -close it entirely. - -**Devices that report their volume back are not supported.** The approach -assumes a device accepts a written volume silently. One that echoes a snapped -value back would oscillate. To check, set a volume and watch it for a few -seconds: - -```bash -pactl set-sink-volume bluez_output.XX_XX_XX_XX_XX_XX.1 40% -sleep 5 && pactl get-sink-volume bluez_output.XX_XX_XX_XX_XX_XX.1 -``` - -If the value drifts on its own, this tool is the wrong approach; disabling -hardware volume (`bluez5.enable-hw-volume = false` in WirePlumber) is the -alternative, at the cost of the device's own control. - -## Tests +
+Build from source ```bash +sudo make install make check ``` -Covers the decision logic and the measurement, including simulated devices -with 8, 16 and 32 steps. +`make install PREFIX=$HOME/.local` works without root. -## License +
-BSD 3-Clause. See [LICENSE](LICENSE). +BSD 3-Clause.