| 1 | # budctl |
| 2 | |
| 3 | Control your wireless earbuds from Linux, without the vendor app: noise control, EQ, game mode, |
| 4 | touch controls, battery and more. There is a command-line tool, `budctl`, and a desktop app, |
| 5 | `budctl-gui`, both built on the same library. |
| 6 | |
| 7 | - No telemetry and no account. budctl talks to your buds over Bluetooth, through BlueZ. |
| 8 | - The settings live on the buds, so budctl works alongside the phone app. |
| 9 | |
| 10 | **Supported buds:** realme Buds T310. More are added as the author gets them. |
| 11 | |
| 12 | <p align="center"> |
| 13 | <img src="docs/screenshots/overview.png" width="560" alt="budctl-gui's Overview page: battery of each bud, noise control, and switches such as game mode and 3D sound"> |
| 14 | </p> |
| 15 | |
| 16 | ## Install |
| 17 | |
| 18 | You need Rust 1.88 or newer, BlueZ, and for the desktop app a Wayland desktop. |
| 19 | |
| 20 | ```sh |
| 21 | cargo install --path crates/budctl-cli # budctl |
| 22 | cargo install --path crates/budctl-gui # budctl-gui |
| 23 | cp contrib/budctl.desktop ~/.local/share/applications/ |
| 24 | ``` |
| 25 | |
| 26 | Pair the buds and connect them in your Bluetooth settings first. |
| 27 | |
| 28 | ## Command line |
| 29 | |
| 30 | ```sh |
| 31 | budctl list # paired buds, and whether budctl knows them |
| 32 | budctl status # battery, noise control, EQ, switches |
| 33 | budctl anc off|on|transparency # noise control |
| 34 | budctl anc light|medium|deep # noise cancelling, at this strength |
| 35 | budctl eq # the EQ presets, and the one in use |
| 36 | budctl eq deep-bass # select a preset |
| 37 | budctl eq custom-4 50=+3 16000=-2 # change bands of a custom preset (dB) |
| 38 | budctl eq new Gym # create a custom preset: flat, and put to use |
| 39 | budctl eq rename custom-4 "Gym mix" # rename a custom preset |
| 40 | budctl eq delete custom-4 # delete a custom preset |
| 41 | budctl game on|off # game mode (low latency) |
| 42 | budctl set bass-boost|spatial|wind|dual on|off |
| 43 | budctl dual # the phones and computers dual connection keeps |
| 44 | budctl bass 2 # bass level, -5 to +5 |
| 45 | budctl touch # what each tap and hold does |
| 46 | budctl touch left triple-tap previous # give a gesture an action (--dry-run first, if you like) |
| 47 | budctl touch cycle off anc # the modes a hold steps through |
| 48 | budctl find start --yes # ring the buds (loud: take them out of your ears) |
| 49 | budctl find stop |
| 50 | ``` |
| 51 | |
| 52 | - `--json` prints machine-readable output for scripts and status bars (`"schema": 1`). |
| 53 | - `--debug` hex-dumps every frame sent and received, on stderr. |
| 54 | - `--device <MAC>` picks the buds when more than one supported pair is connected. |
| 55 | |
| 56 | Exit codes: |
| 57 | |
| 58 | | Code | Meaning | |
| 59 | |---|---| |
| 60 | | 0 | success | |
| 61 | | 1 | usage error | |
| 62 | | 2 | buds not found or not connected | |
| 63 | | 3 | control channel busy | |
| 64 | | 4 | the buds rejected the command or did not answer | |
| 65 | |
| 66 | ## Desktop app |
| 67 | |
| 68 | `budctl-gui` has five pages: |
| 69 | |
| 70 | - **Overview:** battery, noise control and its strength, the switches, the bass level. |
| 71 | - **Equalizer:** the presets; create, rename and delete your own, and change their bands. |
| 72 | - **Gestures:** what each tap and hold does on each bud, and what a hold steps through. |
| 73 | - **Earbud settings:** dual connection and the devices it keeps, find my earbuds, firmware, audio codec. |
| 74 | - **App settings:** where the colors come from, the keys, the version. |
| 75 | |
| 76 | <table> |
| 77 | <tr> |
| 78 | <td valign="top"><img src="docs/screenshots/equalizer.png" alt="Equalizer: the built-in presets, a custom preset with its pencil and bin, and its six bands open below"></td> |
| 79 | <td valign="top"><img src="docs/screenshots/gestures.png" alt="Gestures: double tap, triple tap and hold for each bud, and the modes a hold steps through"></td> |
| 80 | </tr> |
| 81 | <tr> |
| 82 | <td valign="top"><img src="docs/screenshots/earbuds.png" alt="Earbud settings: the dual connection switch, the devices the buds keep, find my earbuds, firmware and codec"></td> |
| 83 | <td valign="top"><img src="docs/screenshots/keys.png" alt="The keys overlay, shown with ?"></td> |
| 84 | </tr> |
| 85 | </table> |
| 86 | |
| 87 | The screenshots show `--demo`'s made-up buds. |
| 88 | |
| 89 | The app connects when it needs to, and frees the buds' control channel 10 s after your last |
| 90 | change, so other apps can use it. A change shows "Saving…" until the buds confirm it. |
| 91 | |
| 92 | The mouse works everywhere. Vim-like keys work on top of it (press `?` in the window): |
| 93 | |
| 94 | | Keys | What they do | |
| 95 | |---|---| |
| 96 | | `j` `k`, arrows, Tab | move the cursor | |
| 97 | | `gg` `G` | first / last item | |
| 98 | | `h` `l` | previous / next choice, switch off / on; `l` opens a row's page | |
| 99 | | Enter, Space | toggle, step through the choices, or open | |
| 100 | | `J` `K`, Ctrl+Tab, `gt` `gT` | next / previous page | |
| 101 | | `1` … `5` | go to a page | |
| 102 | | `r` | read the buds again | |
| 103 | | Esc | hide the cursor | |
| 104 | | `q` | quit | |
| 105 | |
| 106 | The cursor shows only after you press a key, and the first key only shows it. |
| 107 | |
| 108 | **Colors:** a built-in dark palette with a red accent, or a [matugen](https://github.com/InioX/matugen) |
| 109 | palette: `--theme <file>`, else `~/.config/budctl/theme.json`. The file is JSON with these keys, all |
| 110 | optional: `bg`, `fg`, `primary`, `primaryFg`, `primaryContainer`, `secondary`, `surfaceLow`, |
| 111 | `surface`, `surfaceHigh`, `surfaceHighest`, `outlineVariant`, `surfaceVariantFg`, `err`. It is read |
| 112 | again whenever the window gets focus, so a new wallpaper's colors show up there too. |
| 113 | |
| 114 | Other options: `--demo` shows made-up buds without Bluetooth; `--debug` and `--device` work as in |
| 115 | the command-line tool. |
| 116 | |
| 117 | ## How it works |
| 118 | |
| 119 | budctl speaks the buds' own control protocol over an RFCOMM socket. What is known about it, and |
| 120 | how sure, is written down in [`docs/protocol/`](docs/protocol/): the |
| 121 | [transport](docs/protocol/transport.md) and the [realme Buds T310](docs/protocol/realme_t310.md). |
| 122 | |
| 123 | ## License |
| 124 | |
| 125 | GPL-3.0-or-later. See [LICENSE](LICENSE). |