WebRTC Video
A live webcam preview built on navigator.mediaDevices.getUserMedia({ video: true }), with the resulting MediaStream assigned to a <video> element’s srcObject.
That single assignment is all the platform-specific code there is. In a browser it lights up a real <video>. On GJS it flows through @gjsify/video’s VideoBridge into a GTK 4 Gtk.Picture fed by GStreamer’s gtk4paintablesink. Live media crosses from capture to display without your code knowing which platform it is on.
The shared module is about ten lines:
export async function startVideo(video: HTMLVideoElement, log: LogFn = console.log): Promise<MediaStream> { log('Requesting webcam...'); const stream = await navigator.mediaDevices.getUserMedia({ video: true, audio: false }); log(`Got MediaStream with ${stream.getVideoTracks().length} video track(s)`); video.srcObject = stream; log('Video playing'); return stream;}Get set up
Section titled “Get set up”This showcase is not in the gjsify showcase catalog. It needs a camera and an extra GStreamer plugin, so it runs from a checkout of the gjsify repo instead.
You need:
- GJS 1.86 with GTK 4.
gtk4paintablesinkfrom gst-plugins-rs:sudo dnf install gstreamer1-plugin-gtk4on Fedora,sudo apt install gstreamer1.0-gtk4on Ubuntu and Debian. Confirm withgst-inspect-1.0 gtk4paintablesink.- A webcam, or a virtual device such as
v4l2loopback, plus PipeWire or PulseAudio.
gjsify system-check reports GJS and the optional GStreamer pieces.
Run it on GJS
Section titled “Run it on GJS”It builds two bundles, --app gjs and --app browser, and no --app node one, because the capture side is a GStreamer pipeline reached through a typelib. From showcases/dom/webrtc-video/:
gjsify run build # gjs + browser bundles and the assetsgjsify run start # opens the GTK 4 windowA GTK 4 window opens with an Adw.ToolbarView whose body is the VideoBridge widget. Once getUserMedia resolves, the stream is handed to the bridge, the GStreamer pipeline goes to PLAYING, and the picture appears. Closing the window quits the main loop and the process exits, which frees the camera.
@gjsify/webrtc picks a capture source by trying pipewiresrc, then v4l2src, then autovideosrc. If none of them exist it falls back to videotestsrc, so SMPTE colour bars instead of your face means no real device was found.
Run it in the browser
Section titled “Run it in the browser”gjsify run start:browser # serves dist/ on localhost:8080The browser build uses the browser’s own getUserMedia and a real <video> element.
To embed it in a page of your own, import mount() from src/browser/browser.ts. The package is private and not published to npm, so there is no @gjsify/example-dom-webrtc-video/browser specifier to import. Copy the file, or point at your checkout.
const handle = mount(container, { title: 'Webcam' });
handle.pause(); // stop status updates, keep the stream runninghandle.resume();handle.stop(); // release the webcam and remove the DOMWhat it uses
Section titled “What it uses”| Package | What it needs |
|---|---|
@gjsify/webrtc | navigator.mediaDevices.getUserMedia, MediaStream, MediaStreamTrack, and the GStreamer capture source behind them |
@gjsify/video | HTMLVideoElement.srcObject, and VideoBridge rendering into a Gtk.Picture |
@gjsify/webrtc-native | The Vala bridge that moves GStreamer’s streaming-thread callbacks onto the GLib main context |
gst-1.0, gtk4paintablesink | Capture and paintable rendering on GJS |
| Libadwaita | Adw.ApplicationWindow, Adw.HeaderBar and Adw.ToolbarView around the bridge |
In a longer-lived app, call track.stop() on each track when you are done with the preview. That releases the GStreamer source so a later getUserMedia call can acquire the camera again. The showcase gets away without it because closing its window ends the process; the browser build’s handle.stop() shows the explicit version.
Copy the structure
Section titled “Copy the structure”src/video-demo.tsisstartVideo(video, log), shown above. No platform imports.src/gjs/gjs.tsis the Adwaita window wiring theVideoBridge.src/browser/browser.tsexportsmount();browser-main.tsruns it full-page.
Related
Section titled “Related”webrtc-loopbackis the data half of the same stack: peer connections and a data channel, no media.- Bridge widgets shows how
VideoBridgeties a<video>element to a GTK 4 widget, alongside the canvas, WebGL and iframe bridges. - Web API packages lists what
@gjsify/webrtccovers.