From 653260522de1bee07488bab6720e5b741926187d Mon Sep 17 00:00:00 2001 From: Chris Uthe Date: Thu, 15 Oct 2026 18:32:20 -0500 Subject: [PATCH] Cut the 0.4.0 release --- CMakeLists.txt | 2 +- docs/release-notes/0.4.0.md | 68 +++++++++++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+), 1 deletion(-) create mode 100644 docs/release-notes/0.4.0.md diff --git a/CMakeLists.txt b/CMakeLists.txt index ffdefa7..250ad26 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,7 @@ cmake_minimum_required(VERSION 3.16) project(sendspin-cpp-cli - VERSION 0.3.0 + VERSION 0.4.0 DESCRIPTION "Headless CLI/daemon Sendspin audio player" HOMEPAGE_URL "https://github.com/Sendspin/sendspin-cpp" LANGUAGES CXX diff --git a/docs/release-notes/0.4.0.md b/docs/release-notes/0.4.0.md new file mode 100644 index 0000000..4e78827 --- /dev/null +++ b/docs/release-notes/0.4.0.md @@ -0,0 +1,68 @@ +### Breaking changes + +- **The player speaks Sendspin 1.0.0-rc1, and every connection is encrypted.** A server must + speak rc1 too (aiosendspin 10 or later); an older one cannot connect at all. Every player gets + a new identity, the public key of a keypair generated on first run, so a server sees a new + player and its stored volume and grouping do not carry over. A server must pair with the + player before it can play, unless the player runs with `--allow-unpaired`. `--id` and `id =` + are refused with a pointer at `status`, which gains `client id:` and `trust:` lines near the + top and prints `output delay:` where it printed `static delay:`. In the state file, + `static-delay-ms` and `last-server-hash` become `blob-*` keys, automatically and one way: an + older binary reading the new file loses the delay. `SENDSPIN_CLIENT_ID` in hooks is now + always set, to the key-derived id. (#72, #81, #83) + +### New features + +- **Pairing from the terminal.** `sendspin-cli pair-token` prints the token to paste into a + server, and the player logs it once at startup until a server is paired, to the terminal or + journal but never to a `--logfile`. When a server asks to pair with a code, the player logs + the 6-digit code and shows it in `status`; `--pairing-code <8 digits>` / `pairing-code =` + replaces it with a fixed one, best kept in the config file. `sendspin-cli pair confirm` and + `pair cancel` answer an attempt that is waiting, and `status` carries a `pairing:` line, with + `pairing code:` and `pairing window:` while they apply. (#73) +- **`--input :` streams a microphone or line-in to the server** through the + source role, on ALSA, CoreAudio (macOS asks for microphone permission on first use), + PipeWire, PulseAudio and PortAudio, with `tone` and `null` for a device-less test. `-l` lists + capture devices alongside outputs, and `status` shows an `input:` line while one is + configured. (#74, #75, #76, #84) +- **`--input loopback[:]` streams what this host is playing.** On PipeWire and + PulseAudio it captures a sink's monitor, the player's own output included; on macOS 14.2 and + later it captures through a process tap that leaves the player's own playback out, and + refuses a tap that cannot. (#85, #86) +- **`--fixed-volume` for an output whose level is set elsewhere**, such as a line-out into an + amplifier. The player plays at full gain, unmuted, and offers the server neither volume nor + mute, so a server's volume slider for it disappears rather than silently doing nothing. A + volume remembered in the state file is kept but ignored, with one log line saying so, and + returns once the flag is dropped. `status` prints `player volume: 100 (fixed; the server + cannot set it)`. (#88) +- **`--output-delay` is the name for what `--static-delay` set**, and `output-delay =` in a + config file likewise. The old flag and key are still accepted. (#72) + +### Fixed issues + +- **`-o null` and `-o stdout` no longer drop the connection a second into every stream.** + Neither sink reported playback, so the player never left its startup priming: the first + chunk stayed held, every chunk after it queued behind it, the inbound ring filled and the + library closed the connection, which the server reopened in a loop. Both sinks now report + what they consume against a virtual clock, so each chunk is released as it arrives. (#89) +- **Volume scaling at 16 and 32 bits on big-endian hosts.** Any gain other than unity played + as noise on MIPS under OpenWrt, because those two paths read and wrote samples at native + width; they now assemble little-endian bytes as the 24-bit path already did. (#77) +- **`--help` no longer lists `--id`**, which rc1 refuses; `--state-dir` gains the advice that + two players on one host need separate state directories, or they share one identity. (#83) + +### Under the hood + +- **sendspin-cpp is pinned to `v0.9.5`**, and the deprecated `pairing_window_supported` + assignment is gone, since the library ignores it and the CLI already answers the pairing + window with `pair confirm|cancel`. Upstream changes that reach the player with the pin: the + player's quota is released at `stream/clear` and `stream/end`, `client/hello` goes out only + after `server/hello` arrives, the network provider is polled only from the main loop, Opus + is decoded at 16 bits whatever `stream/start` says, Opus PCM stays little-endian on + big-endian hosts, and a hard sync is measured from now after the sink starves. (#81) +- **CI runs a big-endian MIPS job**, cross-compiling the volume code and running it under + QEMU, so the scaling fix above cannot regress unnoticed. (#77) +- **PortAudio and CoreAudio device lookup is shared between sink and source**, so `-l`, `-o` + and `--input` resolve a device the same way on each backend. (#75, #84) + +**Full changelog:** https://github.com/@REPO@/compare/v0.3.0...@TAG@