Repository navigation
[Bug]: macOS native capture silently discards the webcam track on long recordings #253
Description
Search existing issues
- I have searched the existing issues
Describe the bug
On the macOS native capture path the webcam is buffered entirely in memory and only written at finalize. Past ~2 GB the finalize step throws, the error is swallowed, and the session is saved screen-only. No toast, no failure state — the editor opens normally with the camera track simply absent.
A 23-minute take (webcam at BITRATE_BASE 18 Mbps ≈ 2.9 GB) lost the webcam. Shorter takes in the same app session saved fine.
Cause, current on main:
1. The native path builds the webcam handle with no fileName, selecting buffering — nothing reaches disk during capture:
// src/hooks/useScreenRecorder.ts:1323
nativeWebcamRecorder = createRecorderHandle(webcamStream.current, {
mimeType: selectMimeType(),
videoBitsPerSecond: BITRATE_BASE,
});// src/hooks/recorderHandle.ts:43
let mode: "pending" | "streaming" | "buffering" = fileName ? "pending" : "buffering";The legacy path at useScreenRecorder.ts:1771 passes the filename and streams to disk, so it is unaffected.
2. Finalize flattens the whole recording into one ArrayBuffer for IPC:
// src/hooks/useScreenRecorder.ts:605-613
const fixedWebcamBlob = await fixWebmDuration(webcamBlob, duration + webcamHeadStartMs);
return { videoData: await fixedWebcamBlob.arrayBuffer(), ... };
} catch (error) {
console.error("Failed to finalize native macOS webcam recording:", error);
return undefined;
}3. undefined makes the guard at :639 skip attachNativeMacWebcamRecording, so the session is written with no webcamVideoPath. Only console.error fires; the user is never told.
Expected behavior
Stream the webcam to disk on the native path as the legacy path already does. Failing that, surface a toast when the webcam fails to attach — silently discarding a completed take is the worst available outcome.
To Reproduce
- macOS, webcam enabled, start a recording (native capture).
- Record 20+ minutes.
- Stop.
- Editor opens with screen + audio, no camera, no error.
Screenshots
No response
OS
macOS
OS Version
macOS 26.5.2
Browser
None
Device Type
Laptop
Additional context
Session file written for the failed take:
{ "screenVideoPath": ".../recording-<id>.mp4", "createdAt": <id>, "cursorCaptureMode": "editable-overlay" }versus a short take from the same app session:
{ "screenVideoPath": ".../recording-<id>.mp4", "webcamVideoPath": ".../recording-<id>-webcam.webm", ... }The camera streamed for the full take — macOS cameracaptured, recording ran 09:29:54–09:52:56:
09:28:53.592 -[CMIOExtensionProvider startStreamForClientID:streamID:reply:]
09:52:56.942 -[CMIOExtensionProvider stopStreamForClientID:streamID:reply:]
The main process crossed the 2 GB file-backed write threshold mid-recording, consistent with Chromium paging the buffered blob to blob_storage:
Event: disk writes
Writes: 2149.48 MB of file backed memory dirtied over 1564 seconds,
exceeding limit of 24.86 KB per second over 86400 seconds
Same machine, same webcam, one app session:
| Take | Webcam file |
|---|---|
| 6.4s | 6 MB |
| 7.6s | 9 MB |
| 176.8s | 267 MB |
| 196.8s | 277 MB |
| 1381.5s | none |
Observed on 1.7.0; the code paths above are current on main. Plausibly the same root cause as #41 — "something failed but it was silent".
Activity
fix(recording): stream the native webcam to disk instead of losing it
fix(recording): stream the native webcam to disk instead of losing it