Skip to content

Add player timing capabilities#69

Open
maximmaxim345 wants to merge 6 commits into
mainfrom
player-time-capabilities
Open

Add player timing capabilities#69
maximmaxim345 wants to merge 6 commits into
mainfrom
player-time-capabilities

Conversation

@maximmaxim345
Copy link
Copy Markdown
Member

@maximmaxim345 maximmaxim345 commented Feb 26, 2026

There were 2 major gaps in the player@v1 role this PR aims to solve:

  • There is no minimum buffer size for live streams and other real-time content, potentially causing buffer underruns depending on the server implementation.
  • Audio data could be sent immediately after starting a stream, causing the beginning of the audio to be cut off.

Both issues are resolved by adding required_lead_time_ms and min_buffer_ms to the client/state player object. The server is then responsible for ensuring that both constraints are respected.
Network latency can now also be factored into required_lead_time_ms and min_buffer_ms in real time, also allowing for high-latency clients (like a player on a mobile network) under changing network conditions.

Comment thread README.md Outdated
Comment thread README.md
Comment thread README.md
- `muted?`: boolean - mute state, must be included if 'mute' is in `supported_commands` from [`player@v1_support`](#client--server-clienthello-playerv1-support-object)
- `static_delay_ms`: integer - static delay in milliseconds (0-5000), always required for players
- `required_lead_time_ms`: integer - minimum startup lead time in milliseconds (e.g., codec init, decode warmup, audio backend buffering, DAC latency), always required for players. Measured from server transmit time of the start/restart trigger ([`stream/start`](#server--client-streamstart) or [`stream/clear`](#server--client-streamclear)) to the timestamp of the first subsequent audio chunk.
- `min_buffer_ms`: integer - requested minimum ongoing buffer duration in milliseconds during playback (primarily for live streams), used to absorb network jitter and ongoing decode/playback timing variance. Always required for players.
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.

I wonder if there is a way we can give guidance on how to calculate this (required_lead_time_ms gives very specific instructions). This is a harder one to do reliably I guess, but if we could describe a way to approach this then that would be good.

I believe we had previously discussed something like looking at the distribution of time message latencies and taking like the 95th percentile or something along those lines. I think we'll have to do some experiments to really see what is actually usable in practice.

The previous split implicitly required the buffer to grow after
stream/start, which is impossible for live sources. A single floor
of max(required_lead_time_ms, min_buffer_ms) + static_delay_ms
satisfies both startup lead and ongoing jitter buffering honestly.

Also drop the 'players must size buffer_capacity to fit min_buffer'
obligation (unknowable client-side for VBR codecs) and replace
'must keep buffer' with 'must schedule timestamps', matching the
server's actual lever.
Live sources cannot grow the queue after playback begins, so the
max(required_lead, min_buffer) + static floor must be honored upfront.
Buffered sources (file playback, prefetched streams) race ahead and
fill the queue past min_buffer naturally, so paying that wait at
startup is pure latency without jitter benefit. Make the relaxation
explicit so impls can use required_lead + static for buffered without
appearing non-compliant.
maximmaxim345 added a commit to Sendspin/aiosendspin that referenced this pull request May 29, 2026
…ms`) (#253)

Adds player-reported `required_lead_time_ms` and `min_buffer_ms` in
`client/state` so the server can size send-ahead per the player's
startup warmup and ongoing jitter needs, dynamic across `client/state`
updates and grouped via the max across members.

`PushStream` uses `max(required_lead, min_buffer) + static_delay` for
live sources and `required_lead + static_delay` for buffered
(`PushStream.set_live_source(...)`, default buffered) since a buffered
queue grows past `min_buffer` naturally after playback begins.

Implements:
- Sendspin/spec#69.
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.

3 participants