fixed recording workflow on ubuntu
ai gen description: Root cause 1 — The mandatory constraint removal (most critical)
In Electron 29+ / Chromium 116+, the old getUserMedia format with a mandatory: {} wrapper was removed. The capture worker was still using it:
video: { mandatory: { chromeMediaSource: 'desktop', ... } } // broke in Electron 29+
This caused getUserMedia to throw in the worker, which sent a stream-error back to the main process, which fell back to the frame loop. Fix: flat constraint format with no mandatory wrapper.
Root cause 2 — Frame loop spammed getSources() every 200ms
Once the stream backend failed, the fallback frame loop called desktopCapturer.getSources() 5× per second. On Linux via the XDG portal, each getSources() call is a new permission request → dialog every few seconds. Fix: on Linux without click capture, don't fall back to the frame loop at all — just let interval/hotkey captures take individual fresh shots.
Root cause 3 — Interval/hotkey captures bypassed the stream backend
Even when the stream backend is running, sessionCapture('interval') went straight to shoot() → grab() → getSources(). Fix: non-click triggers now pull a buffered frame from the stream backend's ring buffer (sampled every 100ms), completely avoiding getSources().
Root cause 4 — Stream backend never started on Wayland
The earlier fix made recorderWanted = false on Wayland, so the stream backend never even started. Fix: recorderWanted is now true whenever stream capture is enabled (the default), regardless of whether click detection is available.
Safety net — setPermissionCheckHandler
Electron 29+ requires an explicit permission grant for display-capture in renderer windows. Added a handler that grants all permissions (safe for a fully local/offline app like StepForge).
Windows is completely unaffected — the constraint fix is Electron-version level (affects both platforms the same), and all the Linux-specific frame-loop guards only fire when clickCaptureAvailable() returns false, which only happens on Wayland.
This commit is contained in:
@@ -68,22 +68,18 @@
|
||||
};
|
||||
streams.set(key, state);
|
||||
try {
|
||||
// The chromeMediaSource constraint set is Electron's documented bridge
|
||||
// from a desktopCapturer source id to a live media stream.
|
||||
// The chromeMediaSource constraint is Electron's bridge from a
|
||||
// desktopCapturer source id to a live media stream. The legacy
|
||||
// `mandatory` wrapper was removed in Electron 29 (Chromium 116+);
|
||||
// constraints must now be flat (no mandatory/optional nesting).
|
||||
state.media = await navigator.mediaDevices.getUserMedia({
|
||||
audio: false,
|
||||
video: {
|
||||
mandatory: {
|
||||
chromeMediaSource: 'desktop',
|
||||
chromeMediaSourceId: cmd.sourceId,
|
||||
minWidth: physWidth,
|
||||
maxWidth: physWidth,
|
||||
minHeight: physHeight,
|
||||
maxHeight: physHeight,
|
||||
// No maxFrameRate: sampling cadence is controlled by the setInterval
|
||||
// timer below, so the actual capture rate is always sampleMs-driven
|
||||
// regardless of display refresh rate or power mode.
|
||||
},
|
||||
chromeMediaSource: 'desktop',
|
||||
chromeMediaSourceId: cmd.sourceId,
|
||||
// Sampling cadence is controlled by the setInterval timer, so the
|
||||
// actual capture rate is sampleMs-driven regardless of display
|
||||
// refresh rate. Resolution is driven by the source itself.
|
||||
},
|
||||
});
|
||||
const video = document.createElement('video');
|
||||
|
||||
Reference in New Issue
Block a user