Conversation
…bKitGTK FD-leak loop On Linux/WebKitGTK, event-driven enumerateDevices() re-enumeration feeds a self-sustaining loop: every enumeration starts a fresh GStreamer device monitor whose startup re-announces known devices as devicechange, and each cycle leaks FDs in the WebKitWebProcess until EMFILE kills it. Remove both amplifiers: input enumeration becomes demand-driven (mic picker open, once after getUserMedia), the avatar-capture listener is gone, and the loop-safe cpal output listener is debounced with an identical-list skip. Adds a falsifiable regression test and docs/linux-media-device-enumeration-loop.md (diagnosis, falsification, stopgap, hardware validation). Signed-off-by: Jan Dado <jan@dado.cz>
🔐 Codex Security Review
|
Signed-off-by: Jan Dado <jan@dado.cz>
…n\n\nStandalone MiniBrowser testing (WebKitGTK 2.52.6) shows enumeration-only and\nenumerate-with-live-capture loops are leak-free with single-init capture\nmachinery; the reproducible defect is per-getUserMedia-cycle FD leakage\n(~1 fd/cycle). Updates the root-cause attribution and falsification\ninterpretation, and adds the Bug 325151 amendment note. Signed-off-by: Jan Dado <jan@dado.cz>
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
On Linux, Buzz Desktop crashes on its own after launch on machines with a
webcam: the WebKitWebProcess leaks file descriptors until EMFILE and GLib
aborts it (
Creating pipes for GWakeup: Too many open files). The driver is afeedback loop:
useAudioDevices(mounted app-wide viaHuddleProvider) andAnimatedAvatarCapturere-enumeratenavigator.mediaDeviceson everydevicechangeevent, and WebKitGTK starts a fresh GStreamerGstDeviceMonitorper
enumerateDevices()call — whose startup re-announces already-knowndevices as
devicechange— so the loop feeds itself while each cycle leaksFDs in the web process.
This PR makes enumeration strictly demand-driven:
useAudioDevices.ts— no mount-time enumeration and nodevicechangelistener; a single serialized
refreshAudioDevices()(in-flight guard makesoverlapping calls await; an unchanged
audioinputlist does not updateReact state).
(
MicControlsonOpenChange→onPickerOpen, wired throughHuddleBarand
HuddleProfileControl), and one refresh runs aftergetUserMediasucceeds in huddle start/join (device labels only become readable once
capture permission is granted). Companion windows mirror the audio-owning
window's list, so their refresh is a no-op.
AnimatedAvatarCapture.tsx—devicechangelistener removed; enumeratesonce when the capture UI opens and on camera-source switches.
HuddleContextkeepsits
devicechangehandler but gains a ~1 s trailing debounce and anidentical-list skip so residual re-announcement storms cannot spam the Rust
backend (hardware-validated to produce no enumeration churn; kept defensive).
Full diagnosis, falsification experiment (libcamera plugin removed → FD leak
persists → engine is WebKitGTK, libcamera was the amplifier), stopgap, and
hardware validation:
docs/linux-media-device-enumeration-loop.md.Related issue
Fixes #7865.
Alternative to #4171, which throttles the same loop (2 s throttle + 30 s
backoff) but keeps it event-driven; its own description concedes the internal
WebKitGTK probe loop and per-enumeration FD leak remain ("on a broken-camera
machine the app would still crash, just later"). This change removes the
app-side amplifier entirely — no recurring trigger of any kind — and adds a
regression test that fails if event-driven enumeration returns. Happy to
coordinate with #4171's author; the surviving pieces there (throttle) become
unnecessary under this approach.
Upstream: the per-enumeration re-announcement and FD leak themselves are
WebKitGTK behavior — filed as Bug 325151: https://bugs.webkit.org/show_bug.cgi?id=325151.
Testing
New regression test
desktop/src/features/huddle/lib/useAudioDevices.test.mjsbinds the production hook and reproduces the pathology (every
enumerateDevices()schedules adevicechangeafter resolving). Asserts:zero enumerations at mount, zero enumerations from simulated
re-announcement storms, overlapping refreshes serialize into one
enumeration, unchanged lists do not re-render, failed enumeration keeps the
previous list. Reintroducing a
devicechange-fed enumeration fails it.cd desktop && pnpm check && pnpm typecheck && pnpm test— green.just ci— green.Hardware validation on the affected machine (2026-09-23, v0.5.24 AppImage,
direct launch so firejail's
--novideocannot mask the bug):Adding cameralinesBehavior change to flag for review: device lists refresh when the mic
picker opens / on huddle start-join instead of on hotplug events — on all
platforms, not just Linux. Chosen deliberately: the loop hazard is
WebKitGTK-specific, platform-sniffing adds complexity, and WKWebView's
mediaDevicesis unreliable anyway (Huddle mediaDevices access crashes the whole app when navigator.mediaDevices is undefined #3118). Interactive checks (mic pickerlists devices, huddle join works, avatar capture enumerates when opened)
pass on the validated machine.