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.
@@ -20,158 +20,78 @@
-## 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.