Skip to content

Video recording failures hang both devices instead of erroring #158

Description

@darioalessandro

Found while fixing the Mac-as-camera recording hang (PR #157). That bug's root cause is fixed, but the three things that turned a settings rejection into a permanent two-device freeze are all still present. The next stop-side failure — from any cause — will hang exactly the same way.

Three silent-failure amplifiers, in the order they bite:

1. configureAudioForRecording reports success when it failed

RemoteCam/CaptureEngine.swift:213-219

if captureSession.canAddInput(audioDeviceInput) {
    captureSession.addInput(audioDeviceInput)
} else {
    print("Could not add audio device input to the session")   // ← prints, then falls through
}
if captureSession.canAddOutput(audioDataOutput) { ... }        // ← no else at all
...
return true                                                     // ← unconditional

RecordingPipeline.swift:107's guard self.configureAudio(...) therefore passes, and the deliberate MicrophoneAccessDenied bail-out at :107-114 never fires. Fix: return false when the input or the output can't be added. That alone routes it to the already-wired clean failure (error ack + "Unable to record audio" alert).

2. stopRecording silently drops the whole protocol

RemoteCam/RecordingPipeline.swift:147

if self.recordingWillBeStopped || !self.isRecordingStorage {
    return          // no finishWriting, no StopRecordingVideoResp, no error, no log
}

The guard conflates two different states. Split them:

  • recordingWillBeStopped → a stop is in flight, ignore (correct today).
  • !isRecordingStorage with recordingWillBeStarted == true → the start never completed. Tear down the pending writer, clear recordingWillBeStarted (today it stays true forever, poisoning every future startRecording via the guard at :97), and emit StopRecordingVideoResp(error:) so the monitor unblocks.

Also guard the assetWriter? optional-chain at :157: a nil writer means the completion never runs and recordingWillBeStopped stays true forever — the same permanent poison. Never call finishWriting on a .unknown-status writer (it throws).

3. .monitorWaitingForVideo is the only monitor wait state with no timeout

RemoteCam/SessionCoordinator.swift:1540

Every other wait state arms a scheduleTimeout (:1187, :1200, :1209, :1229, :1258, :1507), and the watch path recovers from the identical underlying no-op via :1739/:1753. The multipeer path is the outlier.

⚠️ A flat 10s would break large transfers, which legitimately take minutes. Needs to be transfer-aware: arm until the transfer starts, then rely on progress.

Why it matters

Any one of these alone is survivable. Together they convert any recording-side failure into both devices hanging forever with no error and no log. Worth fixing as one PR.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions