Summary. iPhone 17 Pro Max + Blackmagic Camera ProDock, genlock BNC in from a generator confirmed at a true 30.00 fps. follow(_:videoFrameDuration:delegate:) reaches .activeSync in ~2 s. On one unit the lock then holds for 10+ minutes. On a second unit, same binary and same reference, it detaches 6 s to ~4 min after lock: .activeSync → .ready with input.externalSyncDevice == nil, no runtime error and no delegate error. Calling follow() again on the still-running session is rejected with -11800 every time, while unfollowExternalSyncDevice() plus a stopRunning()/startRunning() bounce recovers reliably.
I am not looking for a fix. I want to know whether my call sequence is wrong, whether this transition is expected, and how a shipping app should be structured around it.
Questions
Is re-following a running session supported? Is the unfollow + bounce the intended reset sequence, or is there a lighter-weight way to clear whatever state the -11800 is keyed on? And once detached, is re-acquisition entirely the app's responsibility, or is the system expected to re-calibrate on its own while the reference is present?
Is a hard detach a legal outcome for an already-calibrated input? The documentation describes .freeRunSync as the hold-over when a locked input loses sync. Is that hold-over guaranteed, or must an app also handle .activeSync → .ready with a nil externalSyncDevice?
Is anything in my call sequence wrong (code in a reply below), and is polling input.externalSyncDevice the right signal to key recovery on, or is there a supported notification for detach?
Setup. Video-only AVCaptureSession: one .builtInWideAngleCamera input, one AVCaptureVideoDataOutput. No multi-cam, no depth output, no synchronizer, no audio. Both frame durations set to CMTime(1, 30) before the input is created, never rewritten while a follow is live.
Device A (iOS 26.0.1) holds: 601 s and 956 s runs, zero detaches. Device B (26.3.1, then 26.5.2) has 39 drops across 6 logs. The ProDock, cable and generator were swapped between units; the failure followed the phone. Caveat: n=2, and unit and OS build vary together.
The detach. No AVCaptureSessionRuntimeError and no delegate error (-11892 has never been observed here, so this is not the documented frame-duration-mismatch path). The session keeps running and delivering frames. Status is .ready, not .unavailable — the ProDock stays enumerated, the reference unchanged. No confirmed drop has passed through .freeRunSync.
PTS ground truth, independent of the follow state: while locked, every frame PTS sits exactly on the 1/30 grid, zero drift. At the drop there is exactly one teardown gap, 238–337 ms across 8 runs, after which the clock free-runs at ~30.013 fps (444 ppm) and never returns to the grid.
On -11800. It surfaces through AVCaptureSessionRuntimeErrorNotification. The bounce recovers 3/3, with no activeFormat change. Caveat: -11800 is AVErrorUnknown and I see it in unrelated cases too, so I do not assume it is specific to retained follow state.
Ruled out. Exposure duration — a run at ≤ 16.67 ms, within the recommendation in the follow() documentation, still drops. Reference drift — zero, by microsecond PTS. Accessory chain — full swap; the failure followed the phone. Another client — Final Cut Camera holds genlock on the fragile unit with the same ProDock and reference. Load and resolution — load changes time-to-drop, not whether it drops; with recording and audio off it still drops, and Device B drops at both 12 MP and 1080p.
Code and supporting logs are in replies below; the length limit would not take them inline. Per-frame PTS CSVs, raw status logs, and a minimal Xcode project that still drops are available on request.
Prior art read: forums/thread/799739 and thread/804594 — neither covers post-lock detach or re-acquisition.
2
0
309