Skip to content

Multicam clock sync: ClockSyncPing/Pong + ClockOffsetEstimator - #200

Closed
darioalessandro wants to merge 1 commit into
multicam-pr1-seamsfrom
multicam-pr2-clocksync
Closed

Multicam clock sync: ClockSyncPing/Pong + ClockOffsetEstimator#200
darioalessandro wants to merge 1 commit into
multicam-pr1-seamsfrom
multicam-pr2-clocksync

Conversation

@darioalessandro

Copy link
Copy Markdown
Member

PR2 of the multicam plan (stacked on #199). The synced-shutter foundation.

  • ClockSyncPing (new action, appended-field schema evolution) carries the director's monotonic clock; the camera answers with an echoed t0 + its own clock at receipt.
  • Pings are answered in the nonisolated delegate callback — off the actor inbox — so state-machine queueing can't smear the timestamp; the pong targets the pinging peer only (tested).
  • ClockOffsetEstimator: pure, min-RTT-of-5 NTP-style window; offset = cameraClock − (t0 + rtt/2); rejects pong-before-ping; reset() on background/reconnect. Unit-tested including the rtt/2 error bound.

Inert until a director sends pings (gated on supports_multicam). Full suite green.

🤖 Generated with Claude Code

PR2 of the multicam plan. The synced-shutter foundation: the director will
schedule captures on each camera's own clock, which needs a measured
per-camera offset.

- Wire: ClockSyncPing (action 25, carries director clock at send) answered
  with a CameraStateResponse echoing t0 plus the camera clock at receipt.
  Appended-field schema evolution; round-trip tested. Only ever sent to
  peers advertising supports_multicam.
- The camera answers pings in the nonisolated delegate callback, off the
  actor inbox, so queued state-machine work cannot smear the timestamp
  (same pacing precedent as frame acks). Pong is addressed to the pinging
  peer only.
- ClockOffsetEstimator: pure NTP-style min-RTT-of-5 window; offset =
  cameraClock − (t0 + rtt/2); rejects stale pongs; reset() for
  background/reconnect invalidation. SyncClock supplies the monotonic ms
  clock both sides read.

Inert in production until a director sends pings. Full suite green.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

📊 Test Coverage Report

643/655 tests passed · ⏭️ 12 skipped

Metric Coverage
App code (excl. generated + vendored Theater) █████████░░░░░░░░░░░ 44.8% 🔴
Whole target █████████░░░░░░░░░░░ 46.1% 🔴

🎥 Capture & session core

File Coverage Lines
CaptureEngine.swift ██░░░░░░░░░░░░░░░░░░ 10.7% 164/1532 🔴
RecordingPipeline.swift ████████████░░░░░░░░ 59.7% 284/476 🟡
FrameStreamingCoordinator.swift ░░░░░░░░░░░░░░░░░░░░ 0.0% 0/124 🔴
FrameStreamer.swift ██████████████░░░░░░ 69.2% 72/104 🟡
RemoteCmdFlatBuffers.swift ███████████████████░ 96.2% 1227/1276 🟢
📁 Full report — 89 files
File Coverage Lines
CountdownTimer.swift ████████████████████ 100.0% 48/48 🟢
JPEGFrameEncoder.swift ████████████████████ 100.0% 12/12 🟢
CameraPreviewMode.swift ████████████████████ 100.0% 13/13 🟢
AppActivityMonitor.swift ████████████████████ 100.0% 31/31 🟢
AppTheme.swift ████████████████████ 100.0% 33/33 🟢
Messages.swift ████████████████████ 100.0% 7/7 🟢
DebugLog.swift ████████████████████ 100.0% 2/2 🟢
ZoomScale.swift ████████████████████ 100.0% 76/76 🟢
MonitorChrome.swift ████████████████████ 100.0% 56/56 🟢
ClockOffsetEstimator.swift ████████████████████ 100.0% 24/24 🟢
StreamingConfig.swift ████████████████████ 100.0% 34/34 🟢
MultipeerMessages.swift ████████████████████ 100.0% 12/12 🟢
Locked.swift ████████████████████ 100.0% 19/19 🟢
ScannerLobby.swift ████████████████████ 100.0% 5/5 🟢
CaptureSyncMetadata.swift ████████████████████ 100.0% 32/32 🟢
FrameCreditWindow.swift ████████████████████ 100.0% 9/9 🟢
AppDelegate.swift ████████████████████ 100.0% 17/17 🟢
HEICFrameEncoder.swift ████████████████████ 100.0% 17/17 🟢
PeerCompatibility.swift ████████████████████ 100.0% 42/42 🟢
DeviceScannerViewModel.swift ████████████████████ 99.1% 112/113 🟢
FrameSender.swift ████████████████████ 98.4% 187/190 🟢
FocusPointMapping.swift ████████████████████ 97.6% 40/41 🟢
RemoteCmdFlatBuffers.swift ███████████████████░ 96.2% 1227/1276 🟢
RemoteCmds.swift ███████████████████░ 96.0% 311/324 🟢
WatchSharedTypes.swift ███████████████████░ 94.0% 236/251 🟢
WatchPreviewStreamer.swift ███████████████████░ 93.6% 44/47 🟢
VP9FrameEncoder.swift ███████████████████░ 92.7% 153/165 🟢
WelcomeView.swift ██████████████████░░ 89.3% 492/551 🟢
VideoTransferProgressView.swift █████████████████░░░ 84.0% 295/351 🟢
UIImage+gif.swift █████████████████░░░ 83.2% 129/155 🟢
UIAlertController.swift █████████████████░░░ 83.0% 44/53 🟢
CameraDeviceDescriptor.swift ████████████████░░░░ 81.0% 34/42 🟢
CameraProgressOverlayView.swift ████████████████░░░░ 78.5% 186/237 🟡
MonitorView.swift ███████████████░░░░░ 76.8% 1178/1534 🟡
FlatBufferSchemas_generated.swift (excluded from app-code metric) ███████████████░░░░░ 76.0% 759/999 🟡
RolePickerView.swift ███████████████░░░░░ 75.4% 306/406 🟡
RecordingTimer.swift ███████████████░░░░░ 73.5% 61/83 🟡
CameraRecordingTimerView.swift ███████████████░░░░░ 73.4% 127/173 🟡
WelcomeViewModel.swift ███████████████░░░░░ 73.3% 96/131 🟡
SettingsViewModel.swift ██████████████░░░░░░ 70.9% 90/127 🟡
DeviceScannerView.swift ██████████████░░░░░░ 70.3% 1132/1611 🟡
SessionCoordinator.swift ██████████████░░░░░░ 70.1% 1751/2499 🟡
FrameStreamer.swift ██████████████░░░░░░ 69.2% 72/104 🟡
MonitorPresenter.swift █████████████░░░░░░░ 65.3% 154/236 🟡
WelcomeViewController.swift █████████████░░░░░░░ 64.1% 41/64 🟡
UIAlertPresenter.swift ████████████░░░░░░░░ 60.5% 26/43 🟡
RecordingPipeline.swift ████████████░░░░░░░░ 59.7% 284/476 🟡
MediaProcessors.swift ████████████░░░░░░░░ 58.3% 7/12 🟡
StoreManager.swift ███████████░░░░░░░░░ 53.2% 75/141 🟡
UICmds.swift ██████████░░░░░░░░░░ 50.0% 96/192 🟡
CameraViewModel.swift ██████████░░░░░░░░░░ 49.6% 126/254 🔴
ZoomPill.swift ██████████░░░░░░░░░░ 49.4% 168/340 🔴
UIViewController+SwiftUIHosting.swift ██████████░░░░░░░░░░ 48.4% 15/31 🔴
FrameCodecs.swift ██████████░░░░░░░░░░ 48.1% 25/52 🔴
FrameStreamReceiver.swift █████████░░░░░░░░░░░ 46.3% 238/514 🔴
SceneDelegate.swift █████████░░░░░░░░░░░ 45.8% 11/24 🔴
MonitorViewModel.swift █████████░░░░░░░░░░░ 44.1% 186/422 🔴
PurchaseManaging.swift ████████░░░░░░░░░░░░ 42.0% 21/50 🔴
HEVCFrameEncoder.swift ████████░░░░░░░░░░░░ 40.1% 93/232 🔴
MonitorViewController.swift ███████░░░░░░░░░░░░░ 37.3% 84/225 🔴
EnumExtensions.swift ███████░░░░░░░░░░░░░ 33.9% 40/118 🔴
CameraScreenView.swift ██████░░░░░░░░░░░░░░ 28.5% 148/520 🔴
DeviceScannerViewController.swift ██████░░░░░░░░░░░░░░ 28.1% 107/381 🔴
WatchSessionManager.swift ████░░░░░░░░░░░░░░░░ 20.8% 37/178 🔴
SoundManager.swift ████░░░░░░░░░░░░░░░░ 20.0% 4/20 🔴
MonitorViewController+SwiftUI.swift ███░░░░░░░░░░░░░░░░░ 14.4% 67/465 🔴
CaptureEngine.swift ██░░░░░░░░░░░░░░░░░░ 10.7% 164/1532 🔴
SwiftConstants.swift ██░░░░░░░░░░░░░░░░░░ 10.3% 6/58 🔴
RolePickerController.swift ██░░░░░░░░░░░░░░░░░░ 10.2% 23/226 🔴
PeerLinkStatus.swift █░░░░░░░░░░░░░░░░░░░ 7.1% 10/141 🔴
WatchRemoteCameraController.swift █░░░░░░░░░░░░░░░░░░░ 3.2% 9/279 🔴
CameraPermissionsView.swift ░░░░░░░░░░░░░░░░░░░░ 0.0% 0/640 🔴
CameraHostController.swift ░░░░░░░░░░░░░░░░░░░░ 0.0% 0/197 🔴
RemoteShutterHelpView.swift ░░░░░░░░░░░░░░░░░░░░ 0.0% 0/1373 🔴
CameraPermissionErrorView.swift ░░░░░░░░░░░░░░░░░░░░ 0.0% 0/416 🔴
PhotosAccessDeniedView.swift ░░░░░░░░░░░░░░░░░░░░ 0.0% 0/606 🔴
FrameStreamingCoordinator.swift ░░░░░░░░░░░░░░░░░░░░ 0.0% 0/124 🔴
MicrophonePermissionPromptView.swift ░░░░░░░░░░░░░░░░░░░░ 0.0% 0/347 🔴
SettingsView.swift ░░░░░░░░░░░░░░░░░░░░ 0.0% 0/760 🔴
Photos.swift ░░░░░░░░░░░░░░░░░░░░ 0.0% 0/12 🔴
LocalNetworkPermissionView.swift ░░░░░░░░░░░░░░░░░░░░ 0.0% 0/747 🔴
OrientationUtils.swift ░░░░░░░░░░░░░░░░░░░░ 0.0% 0/18 🔴
PermissionManager.swift ░░░░░░░░░░░░░░░░░░░░ 0.0% 0/159 🔴
PhotosAccessHelper.swift ░░░░░░░░░░░░░░░░░░░░ 0.0% 0/324 🔴
CameraRig.swift ░░░░░░░░░░░░░░░░░░░░ 0.0% 0/574 🔴
StreamLog.swift ░░░░░░░░░░░░░░░░░░░░ 0.0% 0/1 🔴
MultipeerService.swift ░░░░░░░░░░░░░░░░░░░░ 0.0% 0/116 🔴
Data+MD5.swift ░░░░░░░░░░░░░░░░░░░░ 0.0% 0/4 🔴
CameraCountdownTorch.swift ░░░░░░░░░░░░░░░░░░░░ 0.0% 0/61 🔴

Generated from 19b5be2 · workflow run

@darioalessandro

Copy link
Copy Markdown
Member Author

Consolidated into the single feature PR per Dario's request: #203 (branch kept, not deleted).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant