← hakaru Apps

PeerClock

Peer-equal P2P clock synchronization for Apple devices. No server. No master. ±2ms precision.

Swift 6.0 iOS 17+ / macOS 14+ Open Source MIT License

The Problem

Before PeerClock

No way to synchronize clocks between iPhones on a local network. NTP libraries need an internet server. P2P frameworks don't do clock sync. Multi-device apps are stuck with ±100ms guesswork.

With PeerClock

All devices agree on "now" within ±2ms. No internet. No server. No master device. Every peer runs the same 5 lines of code.

What PeerClock Does

±2ms Clock Sync

NTP-inspired 4-timestamp exchange with best-half filtering across 40 measurements

Peer-Equal

No master, no slave. Coordinator auto-elected by smallest UUID, invisible to your app

📡

Generic Commands

Send/broadcast any command. PeerClock routes it — your app defines the semantics

📋

Status Sharing

Push/pull peer status with debounce and generation-based deduplication

🎯

Event Scheduling

Schedule actions to fire simultaneously on all devices with ±2ms precision

💔

Heartbeat Monitor

3-state connection health: connected → degraded → disconnected

🔄

Transport Failover

Automatic WiFi → MultipeerConnectivity fallback when network changes

🧪

Zero Dependencies

Pure Swift. Foundation + Network.framework only. No third-party libraries

Quick Start

1 Add Dependency

Package.swift
dependencies: [ .package(url: "https://github.com/hakaru/PeerClock.git", from: "0.2.0") ]

2 Sync Clocks

Swift
import PeerClock let clock = PeerClock() try await clock.start() // Synchronized time — agrees across all devices ±2ms let timestamp = clock.now

3 Send Commands

Swift
// Broadcast to all peers try await clock.broadcast( Command(type: "com.myapp.record.start") ) // Receive for await (sender, command) in clock.commands { handleCommand(command, from: sender) }

4 Schedule Simultaneous Actions

Swift
// Fire on all devices at the same time (±2ms) let fireTime = clock.now + 3_000_000_000 // 3 seconds from now let handle = try await clock.schedule(atSyncedTime: fireTime) { startRecording() }

Architecture

PeerClock (Facade — all peers equal, no roles) │ ├── Transport reliable + unreliable channels │ ├── WiFiTransport Network.framework (UDP + TCP) │ ├── MultipeerTransport MPC fallback │ ├── FailoverTransport Auto WiFi → MPC │ └── MockTransport In-memory (testing) │ ├── ClockSync NTP-inspired 4-timestamp exchange │ ├── NTPSyncEngine 40 measurements, best-half filtering │ ├── DriftMonitor Jump detection (>10ms → re-sync) │ └── BackoffController Dynamic interval [5→30s] │ ├── Command / Status / Heartbeat / EventScheduler └── Wire Binary protocol (5-byte header)

How Clock Sync Works

PeerClock uses an NTP-inspired 4-timestamp protocol:

Peer A (follower) Peer B (coordinator) │ │ │── SYNC_REQUEST [t0] ──────>│ │ t1 = receive time │ t2 = send time │<── SYNC_RESPONSE [t0,t1,t2]│ │ t3 = receive time │ │ │ offset = ((t1 - t0) + (t2 - t3)) / 2

Precision Budget

Error Source Raw Error Mitigation Residual
Wi-Fi UDP jitter1–10msBest-half filtering~1–2ms
Crystal oscillator drift50ppmPeriodic re-sync<0.25ms
iOS scheduling<1msmach_continuous_time<1ms
Total±2ms

What PeerClock Does NOT Do

Use Cases

🎤

Multi-Device Recording

Start recording on multiple iPhones simultaneously with sample-accurate alignment

🎥

Multi-Camera Video

Synchronize timecode across devices for post-production editing

🎵

Synchronized Playback

Play audio/video in perfect sync across a room of devices

📱

Device Fleet Management

Monitor battery, storage, and state across connected devices in real-time

Get Started

Open source, zero dependencies, MIT licensed. 127 tests passing.