Tunas Akara
Back to Blog

Frame-Synchronized Playback Across Multiple Screens

by RayhanUpdated 6 min read
signagesynchronizationvideoandroidoperations
Frame-Synchronized Playback Across Multiple Screens

Frame-Synchronized Playback Across Multiple Screens

A video wall is nine screens pretending to be one. Mirrored signage is the same content on twenty screens down a corridor. Both make the same demand: every device must agree on what time it is and which frame belongs at that time.

Get it slightly wrong and a customer walking past sees the same ad stuttering out of phase — the visual equivalent of a band that can't keep tempo. In the signage platforms I've built, synchronization is a session protocol, not a clock setting.

NTP is necessary, not sufficient

The reflex answer is "just use NTP." Do use it — but understand what it buys. NTP gets system clocks within a few tens of milliseconds on a decent LAN.

Playback, though, doesn't start when the clock says so. It starts when the decoder is primed, the buffer is filled, and the display pipeline flushes. Two devices with perfectly agreeing clocks can still put the first frame on glass 300 ms apart. Clock sync solves what time is it. It says nothing about when does the frame appear. You need both.

Sync sessions: a master clock and a start barrier

The structure that works is a sync session coordinated by the server (or an elected master on the LAN):

Loading diagram…

Each device measures its offset to the master clock and reports ready — and ready must mean something strict: media fully downloaded, first frame decoded, pipeline paused at zero. When every participant is ready, the server broadcasts a start timestamp comfortably in the future, devices acknowledge, and each converts the master-clock time into its own local time using its measured offset. Everyone begins together.

One unglamorous detail carries a lot of weight: give every session a generation sequence, seeded so it never repeats across server restarts. A stale client holding an old sequence must not be able to ack into a new session and corrupt its start. Versioned sessions make late messages simply ignorable.

Correct drift by rate, never by seeking

Started together is not the end. Consumer decoders drift. Devices report playback position as telemetry, and the coordinator compares each against the master timeline.

The wrong response to a 40 ms error is seeking — a visible jump, a dropped frame, an audio pop, on a screen customers are looking at. The right response is rate adjustment: play at 100.5% or 99.5% speed until the error closes, then return to normal. Half a percent is imperceptible. The correction dissolves instead of appearing.

Reserve the hard resync for two cases only: position error beyond a large threshold, and index drift — a device playing the wrong item entirely. For that case, a clean scheduled restart beats any amount of rate nudging.

Preloading and buffer discipline

Streaming-and-hoping has no place here. Content is downloaded to disk before it's ever eligible to play; the ready barrier enforces it. Decoder warm-up — decode the first frame, hold paused — moves the most variable part of startup latency to before the start signal, where it costs nothing.

Fixed, known buffer sizes across the fleet matter more than large ones. Identical devices with identical settings drift together, and a correction loop tuned once works everywhere. Mixed hardware in one wall multiplies every tolerance.

Rejoining after a reboot

Screens reboot — power cuts, OTA updates, the watchdog doing its job. The rejoin rule: the wall never waits.

A returning device asks the server for the current session state — sequence, current item, master timeline position — preloads that item, enters playback at the computed position, and rate-corrects the residual error over the next seconds. Its neighbors never pause, never restart. A sync design that requires stopping the session to admit a member fails on the first power flicker.

When "close enough" is fine

Tolerance is a budget, and it depends on geometry. Mirrored screens on separate walls: a few tens of milliseconds is invisible, since nobody sees both screens in one glance. Add audio and the budget tightens, because ears catch echo before eyes catch offset.

Bezel-to-bezel video walls are the strict case: one frame — 16 ms at 60 fps — shows as a tear across the seam. Identical hardware, identical decoder settings, and tight correction thresholds are mandatory here. Engineering the strict case for a corridor of mirrored screens is wasted budget; know which wall you're building.

The takeaway

Synchronized playback is layered: NTP for clocks, a ready barrier for starts, rate adjustment for drift, preloading for predictability, and a rejoin path that never stops the show.

The fleet-management context these players live in is covered in running Android TV signage fleets, and the transport carrying the sync messages is the usual choice discussed in MQTT vs WebSocket for real-time IoT.

Related Posts

Building something similar?

IoT Backend & Multi-Protocol Integration

Backends that ingest device telemetry across MQTT, WebSocket, Modbus, and BLE, and normalize it into reliable real-time dashboards.

See how I can help