Repository navigation
Define where receive timestamps are taken - #298
Merged
Merged
Conversation
A message's receive time is when its last byte arrived at the transport, taken as close to that arrival as the transport permits and never after application-level queueing, decryption, or parsing. This replaces the send_ahead arrival rule that stamped after AEAD decryption, and covers the time-sync receive times that were previously unspecified.
kahrendt
marked this pull request as ready for review
October 7, 2026 13:15
kahrendt
added a commit
to Sendspin/sendspin-cpp
that referenced
this pull request
Oct 7, 2026
A message's receive time is when its last byte arrived at the transport. Every inbound message now gets the completion stamp, which the transports pass to `end_inbound_message()` / `end_inbound_fragment()`; `begin_inbound_message()` no longer takes a stamp, and the ESP httpd handler-entry stamp is gone. Measured on an ESP32 httpd connection: the completion stamp is ~140 us later than the old handler-entry stamp for a `server/time` reply (a fixed ~70 us offset shift, which GPS ground-truth runs show moves the observed bias in the right direction) and 1 to 5 ms later for an audio chunk, with rare stalls of tens of ms under load. Under ring pressure the httpd stamp also includes any wait for ring space. - No ring header change. - Host (IXWebSocket) delivers whole messages, so both stamps are the same there. Testing: host ASan + TSan, esp32s3 build. New table test covers each route (ring, fallback, multi-frame into either). Not run on hardware. Implements Sendspin/spec#298
1 of 9 tasks
maximmaxim345
added a commit
to Sendspin/aiosendspin
that referenced
this pull request
Oct 8, 2026
# What does this implement/fix? <!-- Quick description and explanation of changes. --> The server took `server_received` for `client/time`, and the client took its receive time for `server/time`, only after Noise decryption and JSON parsing. This added a variable processing delay to every time sync sample on encrypted connections. Both are now taken when aiohttp returns the WebSocket message, using the final fragment of a fragmented message, through a new `EncryptedWebSocket.receive_timed()`. The player's audio `arrival` time is left for a follow-up, since aiosendspin doesn't take it itself. **Related issue or spec PR (if applicable):** - Sendspin/spec#298 ## Types of changes <!-- Tick exactly one box. CI (.github/workflows/pr-labels.yaml) applies the matching label, and the release notes use it to sort this change. --> - [x] Bugfix (non-breaking change which fixes an issue): `bugfix` - [ ] New feature (non-breaking change which adds functionality): `new-feature` - [ ] Enhancement to an existing feature: `enhancement` - [ ] Breaking change (changes the public API or the protocol in a way that is not backwards compatible): `breaking-change` - [ ] Refactor (no behavior change): `refactor` - [ ] Documentation only: `documentation` - [ ] Maintenance / chore: `maintenance` - [ ] CI / workflow change: `ci` - [ ] Dependencies bump: `dependencies`
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The spec did not say where
server_receivedor the client'sserver/timereceive time are taken, and it required thesend_aheadarrival time to be taken after AEAD decryption. Queueing and decryption between the socket and the application add variable delay to all three. On an ESP32 (sendspin-cpp, httpd path), decryption alone costs 1–2.6 ms per audio chunk, and queueing adds tails up to 1.8 ms.A message's receive time is now when its last byte arrived at the transport (for a fragmented message, the last byte of its final fragment). Receivers SHOULD take it as close to that arrival as their transport permits and MUST NOT take it after application-level queueing, decryption, or parsing. Using the last byte keeps the
send_aheaddelay sample covering the chunk's full transfer: on the ESP32, multi-segment audio chunks took 0.5–6 ms between the first and last byte, with stalls up to 160 ms.Breaking change
Receivers that take receive times after decryption or parsing no longer comply.
aiosendspin needs changes: the server stamps
server_receivedafter decryption, and the client stamps itsserver/timereceive time after decryption and JSON parsing. Both need to move to before decryption.sendspin-cpp already stamps time-sync receipt at the transport, before queueing and decryption. Its stamp is taken at the start of a frame, so it will need an adjustment to take a completion stamp for large messages once it measures
send_aheaddelay formin_buffer_ms.I accept the Contributor License Agreement for this contribution.