Skip to content

Share cameras between apps through PipeWire and name whatever still locks one - #11053

Open
allenmabraham wants to merge 2 commits into
omacom:quattrofrom
allenmabraham:pipewire-camera-sharing
Open

Share cameras between apps through PipeWire and name whatever still locks one#11053
allenmabraham wants to merge 2 commits into
omacom:quattrofrom
allenmabraham:pipewire-camera-sharing

Conversation

@allenmabraham

@allenmabraham allenmabraham commented Sep 9, 2026

Copy link
Copy Markdown

A V4L2 camera streams to one process at a time. Start a call in Slack, then open a meeting in Chrome, and Chrome reports it has no camera, with nothing to say why. It reads like broken hardware, so people reboot instead of closing the app that holds it.

Chromium can take cameras through the org.freedesktop.portal.Camera portal instead, where PipeWire opens the device once and fans the frames out to every client. This enables WebRtcPipeWireCamera (chrome://flags/#enable-webrtc-pipewire-camera) in the shipped Chromium flags file, and a migration adds it to every browser flags file already copied from it, on the existing --enable-features line since Chromium keeps only the last one it is given.

Whatever still takes a camera over V4L2 locks the rest of the desktop out, so a new user service says so. omarchy-camera-watch follows camera opens on /dev and names any process of this user with a /dev/video* node mapped, as a critical toast: "Camera locked by slack — slack took Elgato Facecam 4K over V4L2, so every other app gets no camera, or a black one, until it lets go. Chromium and Electron apps can share a camera through PipeWire instead: start them with --enable-features=WebRtcPipeWireCamera." A node that is merely open (enumeration, format probing) is ignored; only mapped buffers mean a running stream, and PipeWire's own node is skipped as the shared path. One toast per program every five minutes, and OMARCHY_CAMERA_WATCH_IGNORE mutes one by regex. Electron apps such as Slack bundle their own Chromium and never read the flags files, which is why the toast names the flag rather than Omarchy setting it for them.

The unit is enabled at first run and by migration, and installed to /usr/lib/systemd/user by omacom/omarchy-pkgs#371, which belongs right behind this: omarchy-settings-dev builds the quattro tip, so that line needs the unit here first, and first-run enables every shipped unit in one call, so a unit missing from that path fails the whole call the way it did for the crash watcher (omacom/omarchy-pkgs#140). config-test.sh asserts the install.

Validation, on a desktop with an Elgato Facecam 4K, pipewire 1.6.8, wireplumber 0.5.17 and xdg-desktop-portal 1.22.1 with the gtk backend serving Access. Two Chromium 152 instances with the flag, in separate profiles, asked for the camera at the same time: both got a live "Elgato Facecam 4K (V4L2)" track at 640x480, PipeWire showed two stream links out of the one camera node, and /dev/video0 was held by pipewire alone. The portal's AccessCamera resolved as allowed for a host app, logging the parent-window warning from #8843 without it blocking, and answered in under a second on every later call. With the flag off, Chromium held the device itself, and an instance with the flag started afterwards got a track that rendered 0 frames in 4 seconds against 121 for the holder, which is the failure the toast is for; the watcher announced "Camera locked by chromium" as that stream started and forgot it on release. The migration ran against a temporary $HOME with flags files in every shape (existing line, none, empty value, already present, no trailing newline) and is idempotent. ./test/all passes except the tests that need an omarchy-iso checkout or a single-screen shell, which fail the same way on quattro.

🤖 Generated with Claude Code

allenmabraham and others added 2 commits September 9, 2026 15:51
A V4L2 camera streams to one process at a time, so a call in Slack leaves
Chrome reporting no camera at all. With WebRtcPipeWireCamera, Chromium
takes the camera through the portal and PipeWire opens the device once
and fans the frames out to every client. Existing browser flags files
get the feature on their --enable-features line through a migration.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01G7WrCNgrPvtXzrYpC1pioy
The app that lost the camera only says "no camera", which reads like
broken hardware and sends people rebooting. omarchy-camera-watch follows
camera opens on /dev and names any process of this user streaming from a
/dev/video node directly, as a critical toast that says who to close and
which flag lets Chromium and Electron apps share the camera instead.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01G7WrCNgrPvtXzrYpC1pioy
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