Pause native screen capture across platforms

This commit is contained in:
webadderall
2026-03-18 18:36:25 +11:00
parent d5f14f9b16
commit de1074cdff
13 changed files with 378 additions and 42 deletions
+45 -3
View File
@@ -97,6 +97,36 @@ function resumeRecording(
return false;
}
async function pauseNativeRecording(
webcamRecorder?: ReturnType<typeof createMockMediaRecorder> | null,
result: { success: boolean } = { success: true },
): Promise<boolean> {
if (!result.success) {
return false;
}
if (webcamRecorder?.state === "recording") {
webcamRecorder.pause();
}
return true;
}
async function resumeNativeRecording(
webcamRecorder?: ReturnType<typeof createMockMediaRecorder> | null,
result: { success: boolean } = { success: true },
): Promise<boolean> {
if (!result.success) {
return false;
}
if (webcamRecorder?.state === "paused") {
webcamRecorder.resume();
}
return true;
}
function cancelRecording(
recorder: ReturnType<typeof createMockMediaRecorder>,
isNativeRecording: boolean,
@@ -413,18 +443,30 @@ describe("useScreenRecorder state machine", () => {
expect(webcam.state).toBe("inactive");
});
it("native recording: webcam pauses/resumes while screen keeps capturing", () => {
it("native recording pauses webcam only after native pause succeeds", async () => {
const webcam = createMockMediaRecorder("recording");
pauseRecording(recorder, true, false, true, webcam);
const pausedResult = await pauseNativeRecording(webcam);
expect(pausedResult).toBe(true);
expect(webcam.state).toBe("paused");
expect(recorder.pause).not.toHaveBeenCalled();
resumeRecording(recorder, true, true, true, webcam);
const resumedResult = await resumeNativeRecording(webcam);
expect(resumedResult).toBe(true);
expect(webcam.state).toBe("recording");
expect(recorder.resume).not.toHaveBeenCalled();
});
it("native recording leaves webcam state alone when native pause fails", async () => {
const webcam = createMockMediaRecorder("recording");
const pausedResult = await pauseNativeRecording(webcam, { success: false });
expect(pausedResult).toBe(false);
expect(webcam.state).toBe("recording");
expect(webcam.pause).not.toHaveBeenCalled();
});
it("cancel discards both screen and webcam recordings", () => {
const webcam = createMockMediaRecorder("recording");
const chunks = { current: [new Blob(["screen"])] };
+24 -9
View File
@@ -751,11 +751,18 @@ export function useScreenRecorder(): UseScreenRecorderReturn {
const pauseRecording = useCallback(() => {
if (!recording || paused) return;
if (nativeScreenRecording.current) {
// Native captures cannot truly pause, but we pause the timer/UI and webcam
if (webcamRecorder.current?.state === "recording") {
webcamRecorder.current.pause();
}
setPaused(true);
void (async () => {
const result = await window.electronAPI.pauseNativeScreenRecording();
if (!result.success) {
console.error("Failed to pause native screen recording:", result.error ?? result.message);
return;
}
if (webcamRecorder.current?.state === "recording") {
webcamRecorder.current.pause();
}
setPaused(true);
})();
return;
}
if (mediaRecorder.current?.state === "recording") {
@@ -770,10 +777,18 @@ export function useScreenRecorder(): UseScreenRecorderReturn {
const resumeRecording = useCallback(() => {
if (!recording || !paused) return;
if (nativeScreenRecording.current) {
if (webcamRecorder.current?.state === "paused") {
webcamRecorder.current.resume();
}
setPaused(false);
void (async () => {
const result = await window.electronAPI.resumeNativeScreenRecording();
if (!result.success) {
console.error("Failed to resume native screen recording:", result.error ?? result.message);
return;
}
if (webcamRecorder.current?.state === "paused") {
webcamRecorder.current.resume();
}
setPaused(false);
})();
return;
}
if (mediaRecorder.current?.state === "paused") {