Multi-Display Sync

XiboPlayer is the only Xibo player with cross-device synchronization. Multiple screens — same machine or across a LAN — stay in perfect sync: coordinated layout transitions, synchronized video start, and automatic follower discovery.

Two Sync Modes

Mirror Mode (default)

All displays show the same layout at the same time. The lead decides which layout to show and all followers load the same content.

Use case: multiple screens in a lobby, retail store, or airport — all showing identical content with perfectly synchronized transitions.

Lead shows layout 42 ──→ Follower 1 shows layout 42
                     ──→ Follower 2 shows layout 42
                     ──→ Follower 3 shows layout 42

Wall Mode (with layoutMap)

Each display shows a different layout per position, but transitions are coordinated by the lead. This is how you build a video wall where each screen shows a portion of a larger composition.

You design individual layouts for each screen position in the CMS, then map them in the follower's config:

Lead shows layout 42 ──→ Follower 1 maps 42 → 101 (top-right)
                     ──→ Follower 2 maps 42 → 102 (bottom-left)
                     ──→ Follower 3 maps 42 → 103 (bottom-right)

Follower config.json (sync.layoutMap):

{
  "cmsUrl": "https://cms.example.com",
  "cmsKey": "yourKey",
  "displayName": "lobby-top-right",
  "sync": {
    "layoutMap": {
      "42": 101,
      "43": 105,
      "44": 109
    }
  }
}

Each key is the lead's layout ID, each value is this display's corresponding layout ID. If a layout isn't in the map, the display falls back to mirror mode for that layout.

How to set up a video wall:

  1. In the CMS, design N layouts (one per screen position) — e.g., layout 42 (lead/top-left), 101 (top-right), 102 (bottom-left), 103 (bottom-right)
  2. Schedule layout 42 on the lead — it drives the timing
  3. Schedule layouts 101, 102, 103 on followers so they're downloaded (or rely on the lead's schedule to push them via RequiredFiles)
  4. Add sync.layoutMap to each follower's config.json
  5. All screens transition at the same moment, each showing its position-specific content

How It Works

                    Lead Player (Screen 1)
                    ┌────────────────────────┐
                    │  SyncManager (lead)     │
                    │  ┌──────────────────┐   │
                    │  │  Proxy Server    │   │
                    │  │  ┌────────────┐  │   │
                    │  │  │ Sync Relay │  │   │
                    │  │  │  /sync WS  │  │   │
                    │  │  └─────┬──────┘  │   │
                    │  └────────┼──────────┘   │
                    └───────────┼──────────────┘
                                │
              ┌─────────────────┼─────────────────┐
              │ WebSocket       │ WebSocket        │ WebSocket
              ▼                 ▼                  ▼
    ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
    │  Follower 1     │ │  Follower 2     │ │  Follower 3     │
    │  (Screen 2)     │ │  (Screen 3)     │ │  (Screen 4)     │
    │  SyncManager    │ │  SyncManager    │ │  SyncManager    │
    └─────────────────┘ └─────────────────┘ └─────────────────┘

The lead player orchestrates layout transitions. Its proxy server includes a built-in WebSocket relay — followers connect to it over the LAN, no additional infrastructure needed.

Two Transport Layers

TransportScopeUse CaseHow
BroadcastChannelSame machineMultiple tabs or windows on one deviceBrowser-native API, zero config
WebSocket relayCross-device LANSeparate devices on the same networkConnects to lead's proxy at /sync

The transport is auto-selected based on configuration. If relayUrl is set, WebSocket is used; otherwise BroadcastChannel.

Group Isolation

When multiple display groups share the same relay server, group isolation ensures messages stay within their group. Each display declares its sync group on connect, and the relay only broadcasts to peers in the same group.

Relay Server (port 9590)
├── Group "lobby"
│   ├── lobby-lead (Screen 1)
│   ├── lobby-left (Screen 2)
│   └── lobby-right (Screen 3)
│
└── Group "cafeteria"
    ├── cafe-lead (Screen 4)
    └── cafe-right (Screen 5)

A layout change on lobby-lead reaches lobby-left and lobby-right but never cafe-lead or cafe-right.

Backward compatible: Displays that don't declare a group fall back to broadcast-to-all behavior.

Sync Protocol

Lead                              Follower(s)
────                              ──────────
layout-change(layoutId, showAt)  →  receives, loads layout (or mapped layout)
                                 ←  layout-ready(layoutId, displayId)
(waits for all followers ready)
layout-show(layoutId)            →  shows layout simultaneously
video-start(layoutId, regionId)  →  unpauses video simultaneously
  • Heartbeat: every 5s, each node broadcasts its presence. The lead tracks active followers.
  • Stale detection: if a follower goes silent for 15s, it's excluded from the ready-wait.
  • Ready timeout: the lead waits up to 10s for followers, then proceeds without unresponsive ones.
  • Stats delegation: followers send their stats/logs to the lead, which submits them to the CMS on their behalf.

Configuration Examples

Same-machine sync (two tabs)

No special config needed. Open the player in two browser tabs — BroadcastChannel handles sync automatically. Both tabs show the same content (mirror mode).

Cross-device mirrored displays (3 screens on LAN)

Lead player (config.json on 192.168.1.100):

{
  "cmsUrl": "https://cms.example.com",
  "cmsKey": "yourKey",
  "displayName": "lobby-lead",
  "serverPort": 8765
}

The lead's sync group is set by the CMS via RegisterDisplay. The proxy server at :8765/sync acts as the relay.

Follower 1 (config.json on 192.168.1.101):

{
  "cmsUrl": "https://cms.example.com",
  "cmsKey": "yourKey",
  "displayName": "lobby-left"
}

All three screens show the same content with synchronized transitions.

Video wall (2x2 grid, position-specific content)

Lead (top-left) — normal config, runs the schedule:

{
  "displayName": "wall-top-left",
  "serverPort": 8765
}

Follower (top-right) — maps lead layouts to its position:

{
  "displayName": "wall-top-right",
  "sync": {
    "layoutMap": {
      "42": 101,
      "43": 105
    }
  }
}

Follower (bottom-left):

{
  "displayName": "wall-bottom-left",
  "sync": {
    "layoutMap": {
      "42": 102,
      "43": 106
    }
  }
}

Follower (bottom-right):

{
  "displayName": "wall-bottom-right",
  "sync": {
    "layoutMap": {
      "42": 103,
      "43": 107
    }
  }
}

When the lead transitions from layout 42 to layout 43, all four screens transition simultaneously — each to its own position-specific layout.

Standalone relay server

For large deployments, run a dedicated relay instead of using the lead's proxy:

# Install
npm install @xiboplayer/proxy

# Run standalone relay
npx xiboplayer-relay --port=9590

Or with the RPM package:

xiboplayer-relay --port=9590

The relay is a lightweight WebSocket hub (~100 lines) with no CMS dependency. It handles group isolation, heartbeat monitoring, and stale client cleanup.

Multiple display groups, one relay

Configure each group's displays with the same syncGroup in the CMS. The relay isolates messages by group automatically:

Group "lobby"    → syncGroup: "lobby"    → relay at relay.lan:9590
Group "cafeteria"→ syncGroup: "cafeteria"→ relay at relay.lan:9590

Features

  • Mirror mode — all screens show the same layout (default)
  • Wall mode — each screen shows a position-specific layout via layoutMap
  • Coordinated layout transitions — all screens change layout simultaneously
  • <8ms sync precision — measured across 4 Chromium displays on LAN
  • 12 choreography effects — dramatic cascading transitions across the wall (v0.7.0)
  • Token-authenticated relay — shared CMS key secures WebSocket connections (v0.7.0)
  • Synchronized video start — videos unpause at the same moment across all screens
  • Automatic follower discovery — heartbeat-based, no manual registration
  • Stats delegation — followers route stats/logs through the lead to the CMS
  • Group isolation — multiple display groups share one relay via syncGroupId (v0.7.0)
  • Offline LAN sync — persisted config enables sync without CMS connectivity (v0.7.0)
  • Auto-reconnect — exponential backoff (1s to 30s) with automatic group re-join
  • Graceful degradation — lead proceeds after timeout if a follower is unresponsive
  • Transport-agnostic — same SyncManager API for BroadcastChannel and WebSocket
  • Works on Electron and Chromium — both kiosk platforms fully tested (v0.7.0)

Choreography Effects (v0.7.0)

When displays transition between layouts, choreography controls the cascade pattern. Each display shows the new layout at a staggered time based on its grid position.

EffectDescription
simultaneousAll displays switch at once (no stagger)
wave-rightSweep left → right
wave-leftSweep right → left
wave-downSweep top → bottom
wave-upSweep bottom → top
diagonal-tlCascade from top-left corner
diagonal-trCascade from top-right corner
diagonal-blCascade from bottom-left corner
diagonal-brCascade from bottom-right corner
center-outCenter displays first, edges last
outside-inEdges first, center last
randomRandom delay per display

Example: 2×2 grid with diagonal-tl at 200ms stagger:

┌──────┬──────┐
│ 0ms  │200ms │
├──────┼──────┤
│200ms │400ms │
└──────┴──────┘

Configure per display in config.json:

{
  "sync": {
    "topology": { "x": 0, "y": 0, "orientation": 0 },
    "choreography": "diagonal-tl",
    "staggerMs": 200,
    "gridCols": 2,
    "gridRows": 2
  }
}

Comparison with Other Players

FeatureXibo Windows v4Xibo XLRArexiboXiboPlayer
Same-machine syncNoBroadcastChannelNoBroadcastChannel
Cross-device syncZeroMQNoNoWebSocket relay
Sync precision~50-100msN/AN/A<8ms
Choreography effectsNoneNoneNone12 effects
Mirror modeYesYes (same-tab)NoYes (LAN + same-machine)
Wall modeYesNoNoPosition-specific layouts
Group isolationYesN/AN/AsyncGroupId routing
Token authNoN/AN/ACMS key auth
Offline LAN syncNoNoNoPersisted config
Standalone relayNoN/AN/Axiboplayer-relay CLI
Stats delegationNoYes (BC only)NoYes (BC + WebSocket)
Auto-reconnectNoN/AN/AExponential backoff
Video start syncYesNoNoCoordinated unpause
PlatformWindows onlyBrowser (Chrome)AndroidAny (Electron, Chromium, Android, webOS)
Firewall friendlyZeroMQ portsN/AN/AUses existing HTTP port

XiboPlayer is the most capable Xibo player for multi-display deployments. It's the only player with choreography effects, sub-10ms sync precision, token auth, and cross-platform support.

Architecture

The sync system is split across two SDK packages:

  • @xiboplayer/syncSyncManager (protocol logic), BroadcastChannelTransport, WebSocketTransport
  • @xiboplayer/proxyattachSyncRelay() (server-side relay), xiboplayer-relay CLI

The transport interface is pluggable:

interface SyncTransport {
  send(msg: object): void;
  onMessage(callback: (msg: object) => void): void;
  close(): void;
  readonly connected: boolean;
}

Custom transports (e.g., WebRTC for ultra-low-latency) can be injected via the transport constructor option.