Skip to content

fix(recorder): camera flip no longer kills the record button or drops the H.264 pin (iOS) - #154

Merged
morepriyam merged 2 commits into
mainfrom
fix/flip-dead-record-button
Aug 8, 2026
Merged

fix(recorder): camera flip no longer kills the record button or drops the H.264 pin (iOS)#154
morepriyam merged 2 commits into
mainfrom
fix/flip-dead-record-button

Conversation

@morepriyam

@morepriyam morepriyam commented Aug 8, 2026

Copy link
Copy Markdown
Collaborator

Fixes the TestFlight build 31 regression: flipping the camera on iOS permanently killed the record button, and (silently) dropped the H.264 codec pin for all post-flip clips. Full root-cause analysis in #153.

The one-line version

#150 correctly stopped gating the mic on cameraReady — but that gate flip was what made a camera flip rebuild the video output and restart the session. Two behaviors were secretly riding that accidental restart, and build 31 (main @ 82e3b95, first build with #150) exposed both.

Changes

  1. flipCamera()'s cameraReady reset is now Android-only. It exists for CameraX's torch-mid-rebind crash (Android parity: first device-testing wave — recorder fixes, call detection, release hygiene #133), and CameraX re-fires onStarted per bind so it re-arms there. On iOS the flip is an input swap inside beginConfiguration/commitConfiguration on a running session — didStartRunningNotification never fires (verified in HybridCameraSession.swift: the listener maps to that notification, and start() early-returns on isRunning), so the reset could never re-arm and permanently disabled the record gestures. iOS's zoom/torch props already bind ungated (ba7647b), so the reset served no purpose there. This mirrors the existing platform scoping pattern.

  2. The H.264 pin re-applies per connection, not per output instance. Natively the codec lands per-connection (output.setOutputSettings(settings, for: connection)), and every reconfigure — flip, enableAudio rebuild — forms a new connection, killing the pin. The pin effect now keys on a connection epoch bumped from <Camera onConfigured> (VisionCamera's documented "connections are formed" hook), which fires after the new connection exists — the only ordering that can't lose the pin to an async reconfigure landing later. The existing bounded retry still rides any residual race; fail-open behavior (worst case: one HEVC clip) is unchanged.

Verification

Fixes #153

…264 per connection epoch

Two regressions from one root: #150 removed the accidental session restart
a camera flip used to trigger (the flip's cameraReady reset flipped
micWanted, rebuilding the video output and restarting the session), and
two behaviors were riding it.

1. On iOS, flipCamera()'s setCameraReady(false) never re-armed: onStarted
   maps to AVCaptureSession.didStartRunningNotification, and an iOS device
   swap runs inside beginConfiguration/commitConfiguration on a RUNNING
   session - the notification never fires (start() even early-returns on
   isRunning). Record gestures (enabled: cameraReady && ...) died
   permanently; flipping back couldn't recover. The reset exists solely
   for CameraX (#133 torch-mid-rebind crash) and CameraX re-fires
   onStarted per bind, so it is now Android-only - mirroring the existing
   platform scoping of the zoom/torch prop gates (ba7647b).

2. The H.264 pin is applied per-connection natively
   (output.setOutputSettings(settings, for: connection)), and a flip forms
   a new connection - the pin died with the old one and the effect, keyed
   on output identity, never re-applied: post-flip clips silently recorded
   HEVC. The pin now re-keys on a connection epoch bumped from
   <Camera onConfigured> (fires after connections are formed on every
   reconfigure: cold open, enableAudio rebuild, flip), so it re-lands on
   the new connection with the existing bounded retry riding any race.

Repro'd on TestFlight 2.0.0 (31) = main @ 82e3b95, the first build
containing #150.

Fixes #153
Copilot AI lite review requested due to automatic review settings August 8, 2026 23:17

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes an iOS recorder regression where flipping the camera could permanently disable recording interactions and silently revert post-flip clips to HEVC by ensuring iOS flip no longer relies on a cameraReady reset and by re-applying the H.264 codec pin per newly formed video connection.

Changes:

  • Makes flipCamera()’s cameraReady reset Android-scoped to avoid permanently disabling record gestures on iOS.
  • Re-keys the iOS H.264 pin logic from “video output identity” to a “connection epoch” bumped via <Camera onConfigured>.
  • Wires a new onSessionConfigured callback from the recorder hook into the <Camera onConfigured> event.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
src/features/recorder/use-recorder.ts Adds connection-epoch-based H.264 pinning and scopes cameraReady reset during camera flips.
src/app/recorder.tsx Wires <Camera onConfigured> to the recorder hook to bump the connection epoch after reconfigures.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread src/features/recorder/use-recorder.ts Outdated
…but iOS"

The guard exists for CameraX; any other platform would inherit iOS's
stuck-cameraReady failure mode from a reset that never re-arms.
Addresses review on #154.
Copilot AI review requested due to automatic review settings August 8, 2026 23:25

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated no new comments.

Suppressed comments (1)

src/features/recorder/use-recorder.ts:557

  • onSessionConfigured always bumps connectionEpoch, even on non-iOS platforms where connectionEpoch is never read (the pin effect is iOS-only). This introduces extra state updates/renders on Android (and any other platform) every time VisionCamera emits onConfigured, without any functional benefit.
    onCameraReady: () => setCameraReady(true),
    // Wire to <Camera onConfigured>: fires whenever the session's connections are (re)formed —
    // cold open, enableAudio output rebuild, camera flip. Bumping the epoch re-arms the H.264
    // pin for the NEW video connection (the codec is applied per-connection natively, so it
    // dies with the old one on every reconfigure).
    onSessionConfigured: () => setConnectionEpoch((prev) => prev + 1),

@morepriyam
morepriyam merged commit 6793eeb into main Aug 8, 2026
1 check passed
morepriyam added a commit that referenced this pull request Aug 8, 2026
morepriyam added a commit that referenced this pull request Aug 12, 2026
…but iOS"

The guard exists for CameraX; any other platform would inherit iOS's
stuck-cameraReady failure mode from a reset that never re-arms.
Addresses review on #154.
morepriyam added a commit that referenced this pull request Aug 12, 2026
fix(recorder): camera flip no longer kills the record button or drops the H.264 pin (iOS)
@morepriyam morepriyam moved this to Done in Scrum Team Jerry Aug 14, 2026
@morepriyam morepriyam self-assigned this Aug 14, 2026
@github-project-automation github-project-automation Bot moved this from Ready to Done in Scrum Team Jerry Aug 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

recorder(iOS): camera flip permanently disables the record button; H.264 pin silently lost per flip (regression from #150, TestFlight build 31)

2 participants