Skip to content

sendspin-cli 0.4.0

Latest

Choose a tag to compare

@github-actions github-actions released this 15 Oct 23:51
· 3 commits to main since this release
45ff8b0

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 <backend>:<device> 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[:<sink|device>] 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: v0.3.0...v0.4.0

What this build is

sendspin-cli 0.4.0. The version of the sendspin-cpp library it is linked against
is pinned at build time and printed on the second line of sendspin-cli --version,
alongside this one on the first.

Installing, verifying SHA256SUMS and the macOS Gatekeeper situation are in the
wiki — Installation,
or Getting Started on a Raspberry Pi
for the two 32-bit ARM archives. Each archive also carries its own BUILD-INFO.txt,
with the install command already filled in for its platform.

The macOS binary and the .pkg around it are unsigned — ad-hoc signed, which is
the minimum an arm64 Mach-O needs to execute at all, and carries no developer identity
— so Gatekeeper refuses them until you say otherwise. Said here rather than only behind
a link because it is worth knowing before you download; what to do about it is under
the macOS installation guide.

  • README — what it is, how to run
    it, and how to contribute
  • Contributors — development,
    testing, CI, and release guidance
  • Roadmap — what shipped and
    what is owed, item by item