WebRTC Video
A live webcam preview built on the standard navigator.mediaDevices.getUserMedia({ video: true }) call. The resulting MediaStream is assigned to a <video> element’s srcObject — and that single line is the entire cross-platform surface. In the browser it lights up a real <video>; on GJS it flows through @gjsify/video’s VideoBridge into a GTK4 Gtk.Picture backed by GStreamer’s gtk4paintablesink.
What it exercises
Section titled “What it exercises”| Pillar | What it needs |
|---|---|
@gjsify/webrtc | navigator.mediaDevices.getUserMedia, MediaStream, MediaStreamTrack — capture via GStreamer’s pipewiresrc / pulsesrc / v4l2src fallback chain |
@gjsify/video | HTMLVideoElement.srcObject = MediaStream, VideoBridge → Gtk.Picture (gtk4paintablesink) |
@gjsify/webrtc-native | Vala bridges re-emitting GStreamer streaming-thread callbacks on the GLib main context |
gst-1.0 + gtk4paintablesink | The capture + paintable rendering path on GJS |
| Adwaita widgets (GJS) | Adw.ApplicationWindow + Adw.HeaderBar + Adw.ToolbarView hosting the bridge |
The shared video-demo.ts is six lines of business logic: request a stream, assign it to video.srcObject, log the result. Every line is standard Web platform API — nothing references @gjsify/* directly.
Prerequisites
Section titled “Prerequisites”- A webcam (or a virtual video device such as
v4l2loopback). - PipeWire or PulseAudio on the host for capture; the showcase falls back through
pipewiresrc→pulsesrc→v4l2srcautomatically.
Run it on GJS
Section titled “Run it on GJS”gjsify showcase webrtc-videoA GTK4 window opens with an Adw.ToolbarView whose body is the VideoBridge widget. Once getUserMedia resolves, the MediaStream is handed to the bridge and the GStreamer pipeline transitions to PLAYING — the picture appears in the GTK4 widget at the frame clock’s vsync. Close the window to release the camera (each MediaStreamTrack is stopped explicitly).
Run it in the browser
Section titled “Run it in the browser”import { mount } from '@gjsify/example-dom-webrtc-video/browser';mount(document.getElementById('app')!);Same code path — the browser’s native getUserMedia populates a real <video> element. The mount() handle exposes pause() / resume() / stop() so a host (slideshow, embed, parent app) can suspend status updates or release the webcam without unmounting the surrounding DOM.
Source
Section titled “Source”src/video-demo.ts— the sharedstartVideo(video, log)helper. Imports nothing platform-specific.src/gjs/gjs.ts— Adwaita window host wiring theVideoBridge.src/browser/browser.ts— exportsmount()for slideshow / website embedding.src/browser/browser-main.ts— standalone runner that callsmount(document.body)foryarn start:browser.
Why this showcase is non-trivial
Section titled “Why this showcase is non-trivial”MediaStream-as-srcObject is the only Web API that hands a live media handle from one subsystem (@gjsify/webrtc’s GStreamer capture) into another (@gjsify/video’s rendering bridge). Making the contract hold up requires:
getUserMediareturning a realMediaStreamwhoseMediaStreamTracks wrap actual GstWebRTC track sources — not just an empty shim.HTMLVideoElement.srcObjectsetter recognising aMediaStream(vs aBlob/URL string) and rerouting the underlying GStreamer pipeline to consume from the stream’s tracks instead of aplaybinsource.- Tee-multiplexing in
@gjsify/webrtcso the same capture source can fan out to both theVideoBridgepreview and (when added later) aRTCPeerConnectionsender without instantiating two cameras. - Lifecycle cleanup — when the consumer stops the tracks (
track.stop()), the GStreamer source must release the camera so a subsequentgetUserMediacall can re-acquire it.
If any of those layers misfires, the bridge stays black or the pipeline gets stuck in PAUSED. A live preview is the end-to-end proof.
Related
Section titled “Related”webrtc-loopback— sibling showcase that exercises the fullRTCPeerConnection+RTCDataChannelsurface (no media tracks).@gjsify/video— the bridge package that adapts<video>↔Gtk.Picture.refs/showtime/— GNOME’s video player, reference for theGtk.Picture+gtk4paintablesinkpattern.refs/webrtc-samples/— MDN / Google reference samples for the browser-sidegetUserMediacontract.- Bridge widgets pattern — how
VideoBridgeties a DOM element to a GTK4 widget.