headroom/README.md

130 lines
4.4 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# headroom
Automatic loudness and per-app volume control for PipeWire, in Rust.
Headroom puts a per-application audio safety net between noisy sources
(browsers, voice chat, random video) and your speakers, while leaving
the things you *don't* want compressed (music players, games, DAWs)
untouched.
- **Hard 0.1 dBTP ceiling on the processed route**, with proper
inter-sample-peak handling, enforced inline so the contract holds
regardless of control-plane state. Streams routed `bypass` ride the
real sink directly and are not in scope of the contract — that's the
trade-off that makes the per-app exclusion useful.
- **Per-app exclusion** with profile-driven rules.
- **Layer A per-app level control** (peak + RMS detector → smoothed
`channelVolumes` writes) for taming individual streams without
touching the bus path. Zero added signal-path latency; safe to use
on bypass-routed streams.
- **Single binary** daemon + CLI, controlled over a Unix-domain socket
with a documented JSON wire protocol (see [`IPC.md`](IPC.md)).
- **First-party Rust crate** (`headroom-client`) for programmatic use;
third-party clients (Qt panels, status bars, …) target the wire
protocol directly.
- **Live profile reload** — edit a TOML file in
`$XDG_CONFIG_HOME/headroom/profiles/` and the daemon picks up
changes within ~500 ms; the audio thread doesn't glitch.
See [`PLAN.md`](PLAN.md) for the full design and roadmap.
## Status
Alpha. The signal chain (AGC, compressor, two-tier limiter, Layer A
per-app), the routing engine (explicit-link enforcement, sink hotplug,
sticky default sink), the IPC server with topic subscriptions, the
`headroom monitor` TUI, and live profile reload all work end-to-end.
Packaging exposes a systemd user unit and Nix modules. What's missing
is real-world soak time on multi-rate / Bluetooth setups and other
distros' init systems.
## Installing
### Nix (flake)
This repo is a flake; the daemon plus its systemd user unit and the
canonical profiles are exposed as a package.
```sh
nix run github:atagen/headroom -- daemon # one-shot run
nix profile install github:atagen/headroom # add to $PATH
```
For **Home Manager**, add the flake as an input and enable the module:
```nix
{
inputs.headroom.url = "github:atagen/headroom";
# In your Home Manager configuration:
imports = [ inputs.headroom.homeModules.default ];
services.headroom.enable = true;
}
```
The module symlinks the shipped profiles into
`$XDG_CONFIG_HOME/headroom/profiles/`, drops the systemd user unit
into the user's services dir, and the unit starts after PipeWire and
WirePlumber come up. `services.headroom.extraProfiles` lets you add
your own.
For **NixOS** (system-wide binary install + systemd-user discovery):
```nix
{
inputs.headroom.url = "github:atagen/headroom";
# In your NixOS configuration:
imports = [ inputs.headroom.nixosModules.default ];
programs.headroom.enable = true;
}
```
Then any user can `systemctl --user enable --now headroom`.
### Other distros (manual)
```sh
cargo install --path crates/headroom-cli # or: cargo build --release
# Profiles
mkdir -p ~/.config/headroom/profiles
cp profiles/*.toml ~/.config/headroom/profiles/
# systemd user unit (edit the ExecStart path to point at your binary)
install -Dm644 contrib/systemd/headroom.service \
~/.config/systemd/user/headroom.service
sed -i "s|@bindir@|$(dirname "$(command -v headroom)")|" \
~/.config/systemd/user/headroom.service
systemctl --user daemon-reload
systemctl --user enable --now headroom
```
## Usage
Once the daemon is running:
```sh
headroom status # JSON snapshot — sinks, streams, active profile
headroom profile list # available profiles
headroom profile use night # activate one
headroom monitor # full-screen TUI (bus gauges + per-stream)
headroom monitor --json meters # line-delimited JSON, for scripting
headroom route set firefox processed
headroom set compressor.threshold_db -28
headroom bypass on # kill switch — straight to the real sink
```
See `headroom --help` for the full surface.
## Building
```sh
nix develop # toolchain + pipewire dev libs + helpers
cargo build # iterate
cargo test --workspace
nix build # final packaged headroom binary
```
## License
GPL-3.0-or-later for the daemon and CLI. `headroom-dsp` and `headroom-ipc`
are MPL-2.0 so they can be reused by non-GPL plugin hosts and clients.