Skip to content

[Bug]: v1.8.0 native Windows recorder still hangs on stop; next attempt says capture is not running #252

Description

@Seb1900

Search existing issues

  • I searched the existing issues.

This appears to be a regression or an incomplete fix related to #34 and #115. Both issues are closed, and #115 was linked to fixes in #119 and #123, but the failure still reproduces with the packaged v1.8.0 Windows helper.

Describe the bug

On OpenScreen v1.8.0 for Windows, stopping a native Windows screen recording hangs for about one minute and then shows:

Timed out waiting for native Windows capture to stop

The output MP4 remains 0 bytes and the editor does not open normally.

After that timeout, clicking Record again shows a second error:

Native Windows capture is not running.

The second message appears to be a follow-on state error: the native helper is no longer considered active by the main process, while the renderer still retains the previous native recording state.

Expected behavior

Clicking Stop should make the native helper process the stdin stop command, finalize the MP4, emit recording-stopped, exit promptly, clear all recording state, and open the editor.

If native capture fails, the application should clear the stale recording state so that a subsequent recording attempt can start normally.

To Reproduce

  1. Install and run OpenScreen v1.8.0 on Windows 10.
  2. Select a display source and start recording.
  3. Wait a few seconds.
  4. Click Stop.
  5. Wait approximately one minute.
  6. Observe Timed out waiting for native Windows capture to stop.
  7. Observe that the generated MP4 is 0 bytes.
  8. Click Record again.
  9. Observe Native Windows capture is not running.

The failure persists after closing remote-control applications.

Direct helper reproduction and log

I also reproduced the failure by launching the packaged v1.8.0 wgc-capture.exe directly with display capture, default encoder selection, and system audio, microphone, webcam, and cursor capture disabled.

The helper started successfully. I sent stop\n three seconds after recording-started. It was still running 12 seconds later and had to be terminated for cleanup.

[stdout] {"event":"ready","schemaVersion":2}
[stdout] {"event":"cursor-capture","schemaVersion":2,"requested":false,"applied":false}
[stdout] {"event":"encoder-selection","schemaVersion":2,"video":"default","preferSoftwareEncoder":false}
[stdout] {"event":"cursor-capture","schemaVersion":2,"requested":false,"applied":false}
[stdout] {"event":"recording-started","schemaVersion":2}
Recording started
[diagnostic] sending stop
[diagnostic] helper still running 12s after expected stop; terminating for cleanup

{
  "started": true,
  "stopSent": true,
  "exitedWithoutWatchdog": false,
  "elapsedAfterStopMs": 14852,
  "outputBytes": 0,
  "hasStopTiming": false
}

No [stop-timing] line was emitted. This indicates that the main thread did not reach the first cleanup step after the stop wait. The hang occurs before microphone, loopback, webcam, video-writer, WGC-session, or encoder-finalization cleanup is logged.

OpenScreen did not create a dedicated application log containing this failure on this machine. Chromium LevelDB log files were present, but they did not contain useful OpenScreen recording diagnostics. The direct helper output above is the relevant diagnostic log.

Possible cause

PR #119 moved the potentially blocking IMFSinkWriter::WriteSample call outside the shared frame mutex, and #123 bounded the video-writer condition-variable wait. However, the main stop path still waits while acquiring the same shared frame mutex:

std::unique_lock lock(mutex);
control.cv.wait(lock, [&] {
    return control.stopRequested.load();
});

That mutex is still used by the WGC frame callback around CopyResource and by the video writer around frame capture/GPU readback. A slow or blocked GPU copy/readback, or repeated lock reacquisition by frame-producing threads, can still prevent the main thread from acquiring the mutex after stopRequested becomes true.

The affected machine has multiple physical and virtual display adapters:

  • AMD Radeon(TM) Graphics
  • NVIDIA GeForce RTX 5070 Ti
  • Todesk Virtual Display Adapter 16.44.2.509
  • GameViewer Virtual Display Adapter 15.6.5.199

The virtual display drivers or multi-GPU scheduling may increase the likelihood of WGC/D3D copy or readback stalls. This remains a suspected trigger; the helper-level reproduction confirms that the problem is below the React UI.

A possible structural fix is to use a separate mutex/condition variable for stop control, independent from the frame-state mutex. Since stopRequested is atomic, the main stop waiter should not need to acquire a mutex that can be held by GPU frame work.

The second error can likely be prevented independently by clearing the renderer's active native recording state whenever native stop times out or the stop IPC call fails.

Verified workaround

Disabling native Windows WGC capture and using the existing Electron getDisplayMedia + MediaRecorder fallback avoids the issue on this machine.

Two consecutive test recordings stopped in approximately 0.39 seconds and 0.28 seconds. Both generated non-empty, valid H.264 WebM files, opened in the editor, and allowed another recording to start.

Screenshots

The two observed toast messages are:

  1. Timed out waiting for native Windows capture to stop, with helper output ending at Recording started.
  2. Native Windows capture is not running.

OS

Windows

OS Version

Windows 10 Pro 22H2, version 10.0.19045, build 19045, 64-bit

Device Type

Desktop

Additional context

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions