Skip to content

Pin sendspin-cpp to 90cbd808 and stamp audio on the client clock - #94

Merged
chrisuthe merged 1 commit into
mainfrom
chore/bump-sendspin-cpp
Oct 21, 2026
Merged

chrisuthe merged 1 commit into
mainfrom
chore/bump-sendspin-cpp

Conversation

@chrisuthe

Copy link
Copy Markdown
Member

Why

sendspin-cpp #208 reads the host clock from CLOCK_MONOTONIC_RAW on Linux. steady_clock there is CLOCK_MONOTONIC, which NTP slews, so while the time daemon corrects the system clock the measured server offset moves faster than the time filter follows and playback hard-corrects. aiosendspin already timestamps on the raw clock.

That change only helps if the timestamps we hand the library are on the same clock. Ours were not: every backend stamped notify_audio_played() and write_audio() from its own steady_clock helper. Bumping the pin alone would have put the two in different domains, which drift apart with every slew.

What

  • Pin SENDSPIN_GIT_TAG to 90cbd808 (the #208 merge), as Move to sendspin-cpp rc1: encryption on, unpaired access opt-in #72 did before v0.9.5. Re-pin to v0.10.0 once it is tagged.
  • Every sink and source (ALSA, CoreAudio, null, PipeWire, PortAudio, PulseAudio) drops its file-local now_us() and reads the library's static SendspinClient::now_us(). All of them already stamp as "now ± a latency the backend measured", so only the base changes.
  • PipeWire source: it used pw_time::now as an absolute time on our clock. It now measures that reading's age on CLOCK_MONOTONIC and carries it onto the client clock, the way the CoreAudio backends carry mHostTime across.

macOS is unchanged in behaviour: the library keeps steady_clock off Linux.

Deadlines, timeouts and scheduling still use steady_clock; they never reach the library.

Testing

  • Ubuntu 24.04 container, all Linux backends (ALSA, PortAudio, PulseAudio, PipeWire, dns_sd) with -DSENDSPIN_CLI_WERROR=ON: builds clean, 540/540 tests pass. --version reports sendspin-cpp 90cbd808….
  • scripts/format.sh --check with clang-format 20.1.8.
  • CoreAudio paths compile only on macOS; left to CI.
  • Not yet field-tested on hardware. The case to watch is a Linux host whose time daemon is slewing (e.g. systemd-timesyncd's initial sync): sync should hold where it used to hard-correct.

Known gap, from upstream: with -o pulse the player can still lose sync after such a correction, because PulseAudio's own timing runs on CLOCK_MONOTONIC.

sendspin-cpp #208 moves the library's clock to CLOCK_MONOTONIC_RAW on Linux,
so an NTP slew no longer drags the measured server offset. Every timestamp we
hand it -- notify_audio_played() from the sinks, write_audio() from the
sources -- must be on that clock too, so each backend now reads
SendspinClient::now_us() instead of its own steady_clock helper. The PipeWire
source translated pw_time::now as if it were ours; it now carries that
reading's age on CLOCK_MONOTONIC across instead.

Pinned to the commit until v0.10.0 is tagged.
@chrisuthe
chrisuthe merged commit 7c7f5e0 into main Oct 21, 2026
19 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant