Real-time mobile channels (WebSocket, SSE, push streams) deliver messages over an unreliable network: each one takes a different amount of time to arrive, so they can reach the phone out of the order they were sent. A jitter buffer is the standard fix used by VoIP, video calls and live chat clients — it holds arrivals briefly so they can be replayed in the correct sequence instead of showing them the instant each one lands.
on first arrival (seq s0, arrival A0):
playoutBase = A0 - s0·Δt + bufferDelay
target_playout(seq) = playoutBase + seq·Δt
at every scheduling tick:
while now ≥ target_playout(nextExpected):
if buffer has nextExpected: deliver it, nextExpected++
else: mark DROPPED (too late), nextExpected++ ← gap skip
The schedule is fixed the moment the very first message arrives, using the round-trip send interval Δt = 1 / send-rate. Every later message has a target playout time on that same clock. Increase the buffer delay and more out-of-order arrivals make their deadline (fewer red drops) at the cost of extra latency before anything is shown; shrink it and the app feels snappier but jittery messages get skipped as gaps.
- Send rate / jitter σ / loss — shape the network: how often messages are sent, how much their travel time varies (Gaussian spread), and what fraction never arrive at all.
- Playout buffer delay — the deliberate lag the receiver adds before replaying, trading responsiveness for order-correctness.
- A message that finally lands after its playout deadline has already passed is discarded on arrival — real-time delivery never rewinds to show something late.