the playout buffer
Picture a water wheel that must turn at a perfectly steady speed, fed by a hose whose pressure keeps surging and sagging. If you piped the hose straight onto the wheel, it would lurch. Instead you let the water collect in a small tank first, and draw from the tank at a constant rate — the tank absorbs the surges. The playout buffer is that tank for arriving media: a short queue on the receiver where packets land as they arrive (unevenly, thanks to jitter), and from which the player draws at a smooth, constant rate.
It works by deliberately delaying playback. When media starts arriving, the receiver does not play the first packet immediately; it waits a chosen amount — say 60 milliseconds — accumulating a small reserve. Then it begins playing on a fixed schedule, so packet number n is played at its timestamp plus that fixed offset. As long as a packet shows up before its scheduled play time, jitter is invisible: the buffer had a cushion to draw from. The size of that cushion is the central trade-off. A bigger buffer hides more jitter but adds more delay to every word; a smaller buffer feels snappier but lets late packets miss their slot, which then counts as loss. Some systems adapt the buffer size as measured jitter rises and falls.
Why it matters: the playout buffer is the single most important client-side trick in real-time media, and it embodies a deep trade-off — you spend a little delay to buy a lot of smoothness. For stored streaming, where delay barely matters, the buffer can be huge (seconds). For a live conversation, where every millisecond of delay hurts, it must stay tiny (tens of milliseconds), which is why conversational media is so much harder. A packet that arrives after its scheduled playout moment is useless and is simply dropped — so the buffer does not eliminate loss, it converts excessive lateness into loss, which loss concealment then tries to hide.
A receiver sets a 60-millisecond playout buffer. A packet timestamped for play at 1000 milliseconds arrives at 1040 — within budget, played smoothly. A later packet timestamped for 1200 does not arrive until 1280, past its 1260 deadline; it is discarded as if lost, and concealment fills the 20-millisecond gap.
The buffer hides on-time-enough packets; packets past their deadline become loss.
The playout buffer trades delay for smoothness — it cannot give you both. Sizing it is a tug-of-war: too small and late packets are lost; too large and the conversation feels laggy.