Skip to content

Rename client state to a boolean available - #115

Merged
maximmaxim345 merged 1 commit into
mainfrom
fix/available-state
Jul 7, 2026
Merged

Rename client state to a boolean available#115
maximmaxim345 merged 1 commit into
mainfrom
fix/available-state

Conversation

@maximmaxim345

@maximmaxim345 maximmaxim345 commented Jul 2, 2026

Copy link
Copy Markdown
Member

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 6, 2026
This PR and one more (the `state` to `available` rename 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 reason
`another_server`, and clients SHOULD default to `shutdown` when the
device is powering off or otherwise not coming back.
- Discovery: the `path` TXT key is now REQUIRED (value still recommends
`/sendspin`).
- Pairing: the initial static PIN MUST be device-specific (e.g. randomly
generated and printed), never a fixed shared default.
- Custom roles: `_`-prefixed role names SHOULD carry a vendor-specific
prefix to avoid collisions.
- Player state: persisting `volume`/`muted` across reboots is
RECOMMENDED, and a server MUST NOT assume they are unchanged after a
reconnect.
- Streaming: `codec_header` is 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 reports `external_source` only when it will not yield (the
server then cannot stream to it, since `stream/start` is gated on
`synchronized`); a client that can be interrupted instead stays
`synchronized` so the server can take over at any time.
- Source role: dropped `source@v1_support.supported_formats`; a source
declares its format per stream in `client_stream/start` and the server
accepts any format.
- Forward compatibility: clients MUST ignore unrecognized `payload`
fields, 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
its `supported_formats`, so a format request can never name something
the client cannot decode.
Base automatically changed from fix/client-facing-1.0 to main July 6, 2026 18:52
@maximmaxim345
maximmaxim345 force-pushed the fix/available-state branch from 5b517e1 to feec536 Compare July 7, 2026 06:58
@maximmaxim345
maximmaxim345 marked this pull request as ready for review July 7, 2026 06:59

@kahrendt kahrendt left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good!

@maximmaxim345
maximmaxim345 merged commit e7cf66a into main Jul 7, 2026
@maximmaxim345
maximmaxim345 deleted the fix/available-state branch July 7, 2026 13:00
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.
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.

2 participants