Resolve client-facing spec gaps - #113
Merged
Merged
Conversation
maximmaxim345
force-pushed
the
fix/client-facing-1.0
branch
from
July 1, 2026 17:05
06fd614 to
df42e38
Compare
maximmaxim345
commented
Jul 1, 2026
maximmaxim345
commented
Jul 1, 2026
maximmaxim345
commented
Jul 1, 2026
maximmaxim345
force-pushed
the
fix/client-facing-1.0
branch
from
July 1, 2026 20:08
df42e38 to
5333d43
Compare
maximmaxim345
marked this pull request as ready for review
July 1, 2026 20:49
This was referenced Jul 2, 2026
kahrendt
reviewed
Jul 6, 2026
kahrendt
approved these changes
Jul 6, 2026
kahrendt
left a comment
Contributor
There was a problem hiding this comment.
Thanks, good clarifications!
maximmaxim345
added a commit
that referenced
this pull request
Jul 7, 2026
The remaining client-breaking change after #113: it replaces the `client/state` `state` enum (`synchronized` | `external_source`) with a boolean `available`. - `available: true` - operational and ready to participate; for a player or source this means its clock has converged. Formerly `synchronized`. - `available: false` - the client's output is in use by an external system. Formerly `external_source`. Pure terminology rename with no behavioral change. The group-leave behavior it builds on (the `available: false` then `available: true` flip, and the no-auto-rejoin rule) already landed in #113.
kahrendt
pushed a commit
that referenced
this pull request
Jul 13, 2026
The PR with server-implementation-breaking changes I mentioned in #113. Clients do not have to adjust anything for these; they tighten what a conforming server must do. Specifically: - Role activation: a server MUST NOT activate a role or version the client did not list in `supported_roles`. - Forward compatibility: servers (not just clients) MUST ignore unrecognized `payload` fields, and MUST NOT send fields the spec does not define. - `stream/request-format`: a request the server cannot honor is not an error; the stream continues in a configuration the client supports. For players, `stream/start` MUST use a format from the client's `supported_formats`, so the server can never start a stream the client cannot decode. - Reconnect backoff: after repeated consecutive Noise-handshake failures, the server SHOULD NOT keep auto-reconnecting until there is reason to expect success (operator re-initiates pairing, network conditions change). - Artwork late join: after an artwork `stream/start` (initial or post-reconnect), the server SHOULD immediately send the current image for each channel whose `source` is not `'none'`, so a client joining mid-track is not left blank until the next track change.
maximmaxim345
added a commit
to Sendspin/aiosendspin
that referenced
this pull request
Jul 14, 2026
A batch of protocol-conformance and correctness fixes. This PR doesn't include changes to encryption/authentication, that will follow in a later PR. ## Changes - **Adopt client/state `available` boolean.** Replace the client state enum with the spec's `available` boolean end to end: the SDK sends only `available`, the server tracks a boolean and notifies roles via `on_availability_changed`. A legacy `state` enum on the wire normalizes to `available`, with only `external_source` treated as unavailable so a client reporting an error is not ejected from its group. Spec: [#115](Sendspin/spec#115), [#113](Sendspin/spec#113). - **Stamp `server_transmitted` on stream lifecycle messages.** Add `server_transmitted` to `stream/start`, `stream/clear`, and `stream/end`, stamped at actual send time, matching `server/time`. Spec: [#106](Sendspin/spec#106). - **Floor send-ahead at `min_buffer`.** Live streams floor at `min_buffer + static` instead of extending to `required_lead` (which added latency a realtime queue cannot recover); buffered streams keep the `min_buffer` floor instead of dropping to `required_lead + static`. Spec: [#107](Sendspin/spec#107). - **Document `seek_relative` clamping** as the application's responsibility. Spec: [#103](Sendspin/spec#103). - **Track all unimplemented client roles**, not just spec-support families (controller/metadata/color and wholly-unknown families), still excluding `_`-prefixed custom roles. Spec: [#113](Sendspin/spec#113). - **Make server reconnect per-goodbye-reason and activity-aware.** Retry a server-initiated connection only on restart or concurrent_attempt; on a drop with no goodbye, assume restart when the connection was idle or carried playback, else treat it as a session end. Spec: [#113](Sendspin/spec#113), [#116](Sendspin/spec#116). - **Default the visualizer pitch feature off** (rides reserved binary type 21; kept as an opt-in extension). Spec: [#86](Sendspin/spec#86). - **Mask the beat downbeat bit** unless the role tracks downbeats. Spec: [#86](Sendspin/spec#86). - **Remember visualizer request-format when no stream is active** instead of starting a stream in response (which the spec forbids). Mirrors player/artwork. Spec: [#112](Sendspin/spec#112). - **Note peak-cadence deviation from spec** with a TODO (peak onset detection currently runs only at the periodic `rate_max` hop). Spec: [#86](Sendspin/spec#86). - **Hoist binary-type sets out of the per-frame dispatch path** (reuse module-level frozensets instead of rebuilding per binary frame). - **Reset `_stream_started` after the artwork deactivate stream/end**, matching the other stream roles.
This was referenced Jul 15, 2026
1 task
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.
This PR and one more (the
statetoavailablerename in #115) are the last client-breaking changes to the spec. There might be more if we hit issues with the newly added encryption support, but apart from that these two should cover everything I found.There are also some breaking changes I'm still working out, but those are strictly server-implementation breaking. Clients will not have to adjust anything.
Specifically, this PR addresses the following gaps:
client/goodbye: a client switching servers MUST send reasonanother_server, and clients SHOULD default toshutdownwhen the device is powering off or otherwise not coming back.pathTXT key is now REQUIRED (value still recommends/sendspin)._-prefixed role names SHOULD carry a vendor-specific prefix to avoid collisions.volume/mutedacross reboots is RECOMMENDED, and a server MUST NOT assume they are unchanged after a reconnect.codec_headeris specified as standard Base64 (the rest of the spec uses base64url), clarifying the existing encoding rather than changing the wire format.external_source: a client whose output is taken by a non-Sendspin activity reportsexternal_sourceonly when it will not yield (the server then cannot stream to it, sincestream/startis gated onsynchronized); a client that can be interrupted instead stayssynchronizedso the server can take over at any time.source@v1_support.supported_formats; a source declares its format per stream inclient_stream/startand the server accepts any format.payloadfields, and MUST NOT send fields the spec doesn't define for a message (beyond the_-prefixed application-specific role objects a message already permits). Undefined field names stay reserved to the spec, so a client can't squat on a name a later version might claim.stream/request-format: a player MUST only request a format listed in itssupported_formats, so a format request can never name something the client cannot decode.