Multicam PR4: synced photo capture - #202
Closed
darioalessandro wants to merge 1 commit into
Closed
Conversation
Schedule-at-timestamp synced stills across the rig, behind ENABLE_MULTICAM. Wire (additive, same evolution pattern): - ScheduledCapture (action 26): director -> camera, carrying the shutter instant in the camera's own SyncClock domain (director applied the offset), the shared director-clock anchor (the alignment key stamped into each clip), capture id / session id, and the camera's 1-based index. - CameraStateResponse gains capture_id_echo for the ack. RemoteCmd ScheduledCapture / ScheduledCaptureAck, both dispatch switches, round-trips. Camera side (SessionCoordinator, single-cam untouched): - On ScheduledCapture: ack (or nack if the fire time is > 1s past) immediately, then schedule the shutter. The delay runs OFF the actor and only enqueues FireScheduledCapture, so the capture is pulled by the message pump in order and never races a state transition (the flagged concern). The photo saves locally as today, additionally stamped with CaptureSyncMetadata: EXIF UserComment JSON + DateTimeOriginal/SubSec, and a shared RS_<sess>_<cap>_cam<k> originalFilename so any editor can group and align the angles. A stamping failure never costs the user the photo. Director side (MulticamController): - capturePhoto(): picks fireAt = now + 150ms, sends per-camera ScheduledCapture with fireAt + lane.offset to every linked multicam lane; if any offset is missing, falls back to a plain TakePic fan-out under the same shot id. Aggregate state capturingPhoto(captureId, acksRemaining); best-effort policy — per-lane 3s ack timeout marks a silent camera failed; returns to monitoring when all lanes acked/nacked/timed out. Per-lane outcome (captured/failed) surfaced to the tile badge. UI: the MulticamView shutter (reusing the 1:1 ShutterButton + activity ring) fires capturePhoto(); tiles show a captured/failed badge. Tests: serialization round-trips; MulticamControllerTests (per-lane offsets => different fire instants, non-multicam lane excluded, ack aggregation, timeout completion, fallback); camera-side (past-fire nack, valid fire acks immediately then pulls the shutter). Full suite green (677 tests). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Contributor
📊 Test Coverage Report✅ 665/677 tests passed · ⏭️ 12 skipped
🎥 Capture & session core
📁 Full report — 94 files
Generated from |
Member
Author
|
Consolidated into the single feature PR per Dario's request: #203 (branch kept, not deleted). |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stacked on PR3. Schedule-at-timestamp synced stills across the rig, all behind
ENABLE_MULTICAM(off).Wire (additive)
ScheduledCapture(action 26): director → camera. Carries the shutter instant in the camera's own SyncClock domain (director already applied the per-camera offset), the shared director-clock anchor (identical across all cameras — the alignment key stamped into each clip), capture id / session id, and the camera's 1-based index.CameraStateResponsegainscapture_id_echofor the ack.RemoteCmd.ScheduledCapture/ScheduledCaptureAck, both dispatch switches (incl. the test-local one — the PR2 gotcha), round-trip tests.Camera side (
SessionCoordinator, single-cam untouched)On
ScheduledCapture: ack immediately (or nack if the fire time is > 1s past), then schedule the shutter. The delay runs off the actor and only enqueuesFireScheduledCapture, so the capture is pulled by the message pump in order — never racing a state transition (the concern the brief flagged). The photo saves locally as today, additionally stamped withCaptureSyncMetadata: EXIFUserCommentJSON +DateTimeOriginal/SubSec, under a sharedRS_<sess>_<cap>_cam<k>originalFilename. A stamping failure never costs the user the photo.Director side (
MulticamController)capturePhoto()picksfireAt = now + 150msand sends per-cameraScheduledCapturewithfireAt + lane.offsetto every linked multicam lane; if any offset is missing, it falls back to a plainTakePicfan-out under the same shot id. AggregatecapturingPhoto(captureId, acksRemaining); best-effort — a per-lane 3s ack timeout marks a silent camera failed; returns to monitoring when all lanes resolve. Per-lane outcome (captured/failed) surfaced as a tile badge.UI
The
MulticamViewshutter (reusing the 1:1ShutterButton+ activity ring) firescapturePhoto().Tests
Serialization round-trips;
MulticamControllerTests(per-lane offsets → different fire instants, non-multicam lane excluded, ack aggregation, timeout completion, fallback-to-TakePic); camera-side (past-fire nack; valid fire acks immediately then pulls the shutter). Full suite green — 677 tests.Decisions / deviations
capture_fire_at_camera_clock_ms(camera domain, for scheduling) andcapture_anchor_ms(director domain, the shared alignment key). The camera can't recover the director-domain anchor from the camera-domain fire time (it doesn't know its own offset), so the anchor is sent explicitly. The metadata's per-camera offset/RTT fields are stamped 0 on the camera (diagnostics only; the anchor is the real key).TakePicAck/TakePicRespso the same ack machinery resolves both scheduled and fallback shots.🤖 Generated with Claude Code