Skip to content

fix: stabilize Windows recording preview#588

Merged
meiiie merged 2 commits into
mainfrom
fix/video-resolution-quality-preview-export
May 24, 2026
Merged

fix: stabilize Windows recording preview#588
meiiie merged 2 commits into
mainfrom
fix/video-resolution-quality-preview-export

Conversation

@meiiie
Copy link
Copy Markdown
Collaborator

@meiiie meiiie commented May 24, 2026

Summary

Fixes the Windows recording/editing regressions seen during local beta testing:

  • Raises native WGC helper bitrate based on capture resolution/FPS and updates the bundled helper manifest.
  • Adds a bounded timeout while waiting for native Windows capture shutdown so the recording HUD cannot hang forever when the helper stalls.
  • Keeps companion mic audio stable during editor refreshes instead of briefly removing the preview audio fallback.
  • Resets source-scoped editor state when opening a fresh recording without a project, preventing stale trim/clip/audio state from muting preview playback around the 18-19s mark.

Root Cause

The latest recording path can open the editor before background audio sidecars and session updates finish. During that refresh, the renderer could clear companion audio paths for the same source. Separately, when opening a new recording without a saved project, old source-scoped timeline state could survive long enough to affect playback and preview audio. The WGC helper also used a fixed bitrate that was too low for some higher-detail recordings.

Validation

  • User-tested local editor playback on recording-1779651005541.mp4; preview audio now continues past the previous 18-19s cutoff.
  • npm run build:windows-capture
  • npm test -- electron/ipc/recording/windows.test.ts electron/ipc/paths/binaries.test.ts src/lib/exporter/exportBitrate.test.ts src/lib/exporter/sourceTrackRoutingPolicy.test.ts src/lib/exporter/sourceAudioFallback.test.ts
  • npx tsc --noEmit --pretty false
  • npx biome check electron/ipc/recording/windows.ts electron/ipc/recording/windows.test.ts electron/native/bin/win32-x64/helpers-manifest.json src/components/video-editor/VideoEditor.tsx src/components/video-editor/audio/useSourceAudioFallback.ts --formatter-enabled=false
  • git diff --check
  • Verified wgc-capture.exe SHA256 matches helpers-manifest.json.

Note

npm run smoke:packaged-binaries was attempted but could not run locally because this checkout does not currently have a packaged release/app.asar.unpacked directory.

Summary by CodeRabbit

  • New Features

    • Improved screen recording quality with dynamic bitrate tuned to resolution and frame rate.
    • Editor now fully resets source-scoped timeline and audio state when starting a new project/session.
  • Bug Fixes

    • Improved window capture stop logic to avoid hangs, ensure proper cleanup, and surface clear timeout errors.
    • Prevent stale audio-fallback results when switching source files.
  • Tests

    • Added comprehensive tests for capture stop, timeout, error, and fallback behaviors.

Review Change Stack

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 24, 2026

📝 Walkthrough

Walkthrough

This PR centralizes Windows capture stop handling with a configurable timeout and single-settlement flow, adds tests for close/error/timeout cases, computes adaptive encoder bitrate and updates helper metadata, and clears source-scoped editor/audio-fallback state when switching sources.

Changes

Recording Pipeline Enhancements

Layer / File(s) Summary
Windows capture stop & tests
electron/ipc/recording/windows.ts, electron/ipc/recording/windows.test.ts
Refactors waitForWindowsCaptureStop to accept an optional timeout (default 45s), ensures a single settled resolution/rejection, attempts process termination on timeout, centralizes cleanup, and adds Vitest coverage for close (success/fallback), non‑zero exit rejection, emitted error rejection, and timeout-with-kill behavior.
Adaptive encoder bitrate & manifest
electron/native/wgc-capture/src/mf_encoder.cpp, electron/native/bin/win32-x64/helpers-manifest.json
Adds calculateScreenRecordingBitrate(width,height,fps), uses it to set MF_MT_AVG_BITRATE in MFEncoder::initialize, logs computed bitrate with resolution/fps, and updates wgc-capture helper manifest integrity/timestamp fields.
Audio fallback stale-state prevention
src/components/video-editor/audio/useSourceAudioFallback.ts
Adds useRef to track prior currentSourcePath and conditionally clears sourceAudioFallbackPaths and start-delay-by-path state when the source changes during in-flight fetch results or error handling.
Video editor source-scoped state reset
src/components/video-editor/VideoEditor.tsx
Adds resetSourceScopedEditorState callback to clear source-scoped timeline and editor state (layers, selections, audio settings, counters, history flags) and invokes it in multiple initial-load branches; updates effect dependencies.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested labels

Checked

Poem

🐰 A tiny hop, a tidy fix,
Timeouts guard the capture mix,
Bitrates scale to size and fps,
Editor clears the source-old mess,
Fresh audio paths now pass the test.

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Description check ⚠️ Warning The PR description covers the summary, root cause, and validation, but does not follow the required template with Description, Motivation, Type of Change, Related Issue(s), Screenshots/Video, Testing Guide, and Checklist sections. Restructure the description to follow the template format with all required sections including Type of Change (Bug Fix), Related Issue(s), Screenshots/Video, Testing Guide, and the provided Checklist.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title 'fix: stabilize Windows recording preview' accurately reflects the main objective of the PR, which is to address Windows recording/editing regressions and improve stability.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/video-resolution-quality-preview-export

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint skipped: no ESLint configuration detected in root package.json. To enable, add eslint to devDependencies.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
electron/ipc/recording/windows.test.ts (1)

28-59: 💤 Low value

Consider adding tests for fallback resolution and error event paths.

The current tests cover the primary scenarios (clean close with parsed path, timeout with kill). For more complete coverage, consider adding tests for:

  1. Resolution via windowsCaptureTargetPath fallback when code === 0 but no match in buffer
  2. Rejection on non-zero exit code
  3. Rejection when the process emits an error event

These would strengthen confidence in the edge case handling.

💡 Example additional test cases
it("resolves via windowsCaptureTargetPath when buffer has no match but exit is clean", async () => {
  const proc = new FakeCaptureProcess();
  setWindowsCaptureOutputBuffer("Some other output");
  setWindowsCaptureTargetPath("C:\\Recordly\\fallback.mp4");

  const stopped = waitForWindowsCaptureStop(
    proc as unknown as Parameters<typeof waitForWindowsCaptureStop>[0],
    1000,
  );
  proc.emit("close", 0);

  await expect(stopped).resolves.toBe("C:\\Recordly\\fallback.mp4");
});

it("rejects with buffer content on non-zero exit code", async () => {
  const proc = new FakeCaptureProcess();
  setWindowsCaptureOutputBuffer("Encoder error: insufficient memory");

  const stopped = waitForWindowsCaptureStop(
    proc as unknown as Parameters<typeof waitForWindowsCaptureStop>[0],
    1000,
  );
  proc.emit("close", 1);

  await expect(stopped).rejects.toThrow("Encoder error: insufficient memory");
});
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@electron/ipc/recording/windows.test.ts` around lines 28 - 59, Add three unit
tests to cover the missing edge cases for waitForWindowsCaptureStop: (1) a test
that sets setWindowsCaptureOutputBuffer to a non-matching string and
setWindowsCaptureTargetPath to a valid path, then emits proc.emit("close", 0)
and asserts the promise resolves to the fallback path; (2) a test that sets a
buffer containing an error message, emits proc.emit("close", nonZeroCode) and
asserts the promise rejects with that buffer content; and (3) a test that emits
an "error" event from the FakeCaptureProcess and asserts
waitForWindowsCaptureStop rejects; reuse FakeCaptureProcess,
setWindowsCaptureOutputBuffer, setWindowsCaptureTargetPath, and the same
Parameters<typeof waitForWindowsCaptureStop>[0] cast pattern as in the existing
tests.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/components/video-editor/VideoEditor.tsx`:
- Around line 2067-2091: The resetSourceScopedEditorState function clears all
region/ID state but doesn't clear the undo/redo stack held in editorHistoryRef,
allowing Undo to restore stale source data; update resetSourceScopedEditorState
to also reset editorHistoryRef.current to an empty/initial history object (and
any related pointers like historyIndex/currentSnapshot if present) so the
undo/redo history is cleared when switching sources — locate
resetSourceScopedEditorState and editorHistoryRef to make this change.

---

Nitpick comments:
In `@electron/ipc/recording/windows.test.ts`:
- Around line 28-59: Add three unit tests to cover the missing edge cases for
waitForWindowsCaptureStop: (1) a test that sets setWindowsCaptureOutputBuffer to
a non-matching string and setWindowsCaptureTargetPath to a valid path, then
emits proc.emit("close", 0) and asserts the promise resolves to the fallback
path; (2) a test that sets a buffer containing an error message, emits
proc.emit("close", nonZeroCode) and asserts the promise rejects with that buffer
content; and (3) a test that emits an "error" event from the FakeCaptureProcess
and asserts waitForWindowsCaptureStop rejects; reuse FakeCaptureProcess,
setWindowsCaptureOutputBuffer, setWindowsCaptureTargetPath, and the same
Parameters<typeof waitForWindowsCaptureStop>[0] cast pattern as in the existing
tests.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 614d4e4f-633d-4567-898a-d847938d2d6f

📥 Commits

Reviewing files that changed from the base of the PR and between ac2b393 and 5d3da14.

⛔ Files ignored due to path filters (1)
  • electron/native/bin/win32-x64/wgc-capture.exe is excluded by !**/*.exe
📒 Files selected for processing (6)
  • electron/ipc/recording/windows.test.ts
  • electron/ipc/recording/windows.ts
  • electron/native/bin/win32-x64/helpers-manifest.json
  • electron/native/wgc-capture/src/mf_encoder.cpp
  • src/components/video-editor/VideoEditor.tsx
  • src/components/video-editor/audio/useSourceAudioFallback.ts

Comment thread src/components/video-editor/VideoEditor.tsx Outdated
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/components/video-editor/VideoEditor.tsx (1)

2067-2094: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Clear the remaining source-scoped cursor state here too.

resetSourceScopedEditorState still leaves cursorTelemetry, cursorTelemetrySourcePath, and pendingFreshRecordingAutoSuggestTelemetryCountRef intact. After the fresh-recording branches swap videoPath, the preview and auto-suggest flow can keep using the previous source's telemetry until the async reload finishes, and the telemetry-count guard can suppress auto-suggest entirely if the next recording happens to have the same sample count.

Suggested fix
 const resetSourceScopedEditorState = useCallback(() => {
 	setZoomRegions([]);
 	setTrimRegions([]);
 	setClipRegions([]);
 	clipInitializedRef.current = false;
 	autoFullTrackClipIdRef.current = null;
 	autoFullTrackClipEndMsRef.current = null;
 	setSpeedRegions([]);
 	setAnnotationRegions([]);
 	setAudioRegions([]);
+	setCursorTelemetry([]);
+	setCursorTelemetrySourcePath(null);
 	setSourceAudioTrackSettingsByClip({});
 	setDefaultSourceAudioTrackSettings({});
 	setHasClipSourceAudio(false);
 	setAutoCaptions([]);
 	setAutoCaptionSettings((prev) => ({ ...prev, enabled: false }));
 	setSelectedZoomId(null);
 	setSelectedClipId(null);
 	setSelectedAnnotationId(null);
 	setSelectedAudioId(null);
 	nextZoomIdRef.current = 1;
 	nextClipIdRef.current = 1;
 	nextAudioIdRef.current = 1;
 	nextAnnotationIdRef.current = 1;
 	nextAnnotationZIndexRef.current = 1;
+	pendingFreshRecordingAutoSuggestTelemetryCountRef.current = 0;
+	autoSuggestedVideoPathRef.current = null;
 	resetEditorHistoryStack(editorHistoryRef.current);
 	applyingHistoryRef.current = false;
 	syncHistoryButtons();
 }, [syncHistoryButtons]);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/video-editor/VideoEditor.tsx` around lines 2067 - 2094,
resetSourceScopedEditorState currently does not clear cursor-related
source-scoped state, causing telemetry and auto-suggest guards to persist across
source swaps; update resetSourceScopedEditorState to also reset cursorTelemetry,
cursorTelemetrySourcePath, and pendingFreshRecordingAutoSuggestTelemetryCountRef
(e.g., set cursorTelemetry and cursorTelemetrySourcePath to null/undefined and
pendingFreshRecordingAutoSuggestTelemetryCountRef.current to 0) so the new
source starts with a clean cursor/telemetry state.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@src/components/video-editor/VideoEditor.tsx`:
- Around line 2067-2094: resetSourceScopedEditorState currently does not clear
cursor-related source-scoped state, causing telemetry and auto-suggest guards to
persist across source swaps; update resetSourceScopedEditorState to also reset
cursorTelemetry, cursorTelemetrySourcePath, and
pendingFreshRecordingAutoSuggestTelemetryCountRef (e.g., set cursorTelemetry and
cursorTelemetrySourcePath to null/undefined and
pendingFreshRecordingAutoSuggestTelemetryCountRef.current to 0) so the new
source starts with a clean cursor/telemetry state.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 6245bd0c-96f9-457d-b2c3-8ede34b530eb

📥 Commits

Reviewing files that changed from the base of the PR and between 5d3da14 and df95723.

📒 Files selected for processing (2)
  • electron/ipc/recording/windows.test.ts
  • src/components/video-editor/VideoEditor.tsx

@meiiie meiiie merged commit 18626e7 into main May 24, 2026
3 checks passed
@meiiie meiiie deleted the fix/video-resolution-quality-preview-export branch May 24, 2026 20:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant