Skip to main content

Jitter Buffer Integration in NanoPing Transport

Most video players use a jitter buffer to smooth out network delays and avoid stuttering. It holds incoming frames and delivers them to the decoder at a fixed interval (e.g. every 30 ms), which under normal conditions yields a smooth experience.

Why Move the Jitter Buffer into the Transport?

For real-time or low-latency scenarios (e.g. teleoperation, safety-critical systems), a standalone jitter buffer can actually waste precious milliseconds that would be better spent on packet repair. NanoPing’s solution is to integrate the jitter buffer logic directly into the transport protocol. This lets us:

  • Maintain smooth playout (same as a traditional jitter buffer)

  • Simultaneously repair lost packets before delivery

  • Honor a strict latency budget by discarding frames older than the deadline

NanoPing's Transport Raft

NanoPing's transport protocol Raft configures the in-transport jitter buffer with the jitter_buffer field on each real-time stream.

timeout defines the stream latency deadline in milliseconds. Packets older than this deadline are discarded. A timeout of 0 disables symbol expiry in Raft. jitter_buffer defines how long a decoded packet waits before it can be delivered to the application, also in milliseconds.

Raft always preserves in-order delivery. If the next packet in order has been decoded, it is delivered once its measured symbol latency reaches jitter_buffer. If the next packet is missing, it blocks later packets until it is recovered or until it reaches timeout and is skipped.

SettingBehavior
jitter_buffer unsetUses timeout as the jitter buffer. This matches the old timeout-based delivery behavior.
jitter_buffer: 0Delivers decoded packets as soon as they are next in order. This minimizes added buffering latency while still preserving packet order.
0 < jitter_buffer < timeoutHolds decoded packets for the configured buffer duration, leaving the remaining latency budget for packet recovery before timeout.

jitter_buffer must be between 0 and timeout, inclusive. A value larger than timeout is rejected by Raft because the buffer would exceed the stream's latency budget.

See also Raft Stream Configuration.

The setting applies only to the stream where it is configured. It does not propagate to the peer automatically, so configure the sender and receiver streams independently when both directions need explicit behavior.

In this example we stream H.264 video via GStreamer over a network with:

  • Link latency: 50 ms

  • Packet-loss rate: ~5%

  • Latency budget: 300 ms (frames delayed beyond this are dropped)

ClipBehavior
Raw UDPChoppy playback, no reordering or loss recovery
NanoPing (jitter_buffer: 0)Better loss recovery, but uneven playout
NanoPing (integrated jitter buffer)Smooth, in-order playback and on-the-fly packet repair within the 300 ms deadline