UK

← Webrtc

Документація — Webrtc

WebRTC (jumphp/webrtc)

Peer-to-peer connections between players (or computers) from PHP: data channels (text, binary; reliable or like UDP), and on the desktop a computer's screen as a low-latency video with remote mouse and keyboard. One API; the backend depends on where the game runs:

Where Backend What it is
browser (WebAssembly) browser the page's RTCPeerConnection (engine page module jumphp-webrtc.js, bridge messages webrtc)
desktop, Linux native GStreamer webrtcbin as a sidecar process (bin/webrtc-gst.py): the computer's python3 + GStreamer, else Docker
elsewhere / headless tests none every peer gets an error event ("not available"): draw a message, never crash

$webrtc->backendName(), $webrtc->isSupported().

Use

use JumPHP\WebRtc\{WebRtc, Peer, DataChannel, Signaling};

public function __construct(private WebRtc $webrtc) {}

public function enter(array $params = []): void
{
    $this->peer = $this->webrtc->peer();                       // ['stun' => 'stun:host:port', 'turn' => 'turn://user:pass@host:port']
    Signaling::overNet($params['net'], $this->peer, $params['peer']);   // or: $peer->on('signal', ...) + $peer->signal($s) through your own channel
    $this->pos = $this->peer->channel('pos', ordered: false, retransmits: 0);
    $this->pos->on('message', fn (string $m, bool $binary) => ...);
    $this->peer->on('state', fn (string $s) => ...);              // new | connecting | connected | disconnected | failed | closed
    $this->peer->on('channel', fn (DataChannel $c) => ...);        // a channel the other side opened
    $this->peer->on('error', fn (string $e) => ...);
    if ($params['host']) $this->peer->offer();                  // only ONE side offers
}

public function exit(): void { $this->webrtc->closeAll(); }

DataChannel: send(string), sendBinary(string), sendJson(array), isOpen(), label; events open, message (data, binary), close. Channels are made before offer() (they are part of the offer).

Screen (desktop, Linux X11): $peer->screen(['fps' => 60, 'kbps' => 8000, 'width' => 1920, 'encoder' => 'auto', 'input' => true]) before offer(). The other side gets a video track and an input channel (messages: doc/sidecar.md).

project.yaml

webrtc:
  stun: "stun:stun.l.google.com:19302"     # '' = local network only (no public address asked)

Without a TURN server, two players behind strict NATs (some mobile networks, companies) may not connect: give turn to peer().

Desktop requirements (what to install when something is missing)

The browser backend needs nothing (every current browser has WebRTC). The desktop backend is a sidecar program; today it runs on Linux with an X11 session only (a Wayland session: log in with "GNOME on Xorg" / "Plasma (X11)", or see the TODO). Two ways, picked by itself (WebRtc::isSupported(), Sidecar::probe() says which one and why not):

  1. Native (lowest latency, starts at once): python3 + GStreamer with webrtcbin, libnice and ximagesrc, and libXtst for the input.
    • Debian / Ubuntu / Mint: sudo apt install python3-gi gir1.2-gstreamer-1.0 gir1.2-gst-plugins-base-1.0 gir1.2-gst-plugins-bad-1.0 gstreamer1.0-plugins-base gstreamer1.0-plugins-good gstreamer1.0-plugins-bad gstreamer1.0-plugins-ugly gstreamer1.0-nice gstreamer1.0-x libxtst6
    • Fedora: sudo dnf install python3-gobject gstreamer1-plugins-base gstreamer1-plugins-good gstreamer1-plugins-bad-free gstreamer1-plugins-bad-free-extras gstreamer1-plugins-ugly-free libnice-gstreamer1 libXtst (x264: RPM Fusion's gstreamer1-plugins-ugly)
    • Arch: sudo pacman -S python-gobject gst-plugins-base gst-plugins-good gst-plugins-bad gst-plugins-ugly gst-plugin-va libnice libxtst
    • Hardware encoding (optional, less CPU): AMD / Intel mesa-va-drivers (Debian) / mesa-va-drivers-freeworld (Fedora, RPM Fusion) or intel-media-va-driver; NVIDIA: the proprietary driver (nvenc is in plugins-bad). Without them x264 (plugins-ugly) or openh264 encode on the CPU.
    • Check: python3 -c 'import gi; gi.require_version("Gst","1.0"); from gi.repository import Gst; Gst.init(None); print([e for e in ("webrtcbin","nicesrc","ximagesrc","x264enc","vah264enc") if not Gst.ElementFactory.find(e)])' prints the missing ones.
  2. Docker (when the native way is incomplete): Docker Engine running and usable without sudo (sudo usermod -aG docker $USER, then log in again). The image jumphp/webrtc-gst:<hash> is built from docker/Dockerfile the first time (a few minutes, in the background, needs the network once), run with --network host --ipc host (ICE sees the LAN, XShm works), the X11 socket, ~/.Xauthority and /dev/dri.
Symptom Fix
"python3 with GStreamer (python3-gi) not found" and no Docker install the native packages above (or Docker)
"GStreamer elements missing: nicesrc" gstreamer1.0-nice (Fedora libnice-gstreamer1, Arch libnice)
black video through Docker the container needs --ipc host (the Sidecar adds it); an old image: docker rmi jumphp/webrtc-gst:<tag>
black video, native the monitor is asleep (DPMS) or a Wayland session (ximagesrc only sees XWayland windows)
"cannot open display" DISPLAY not set for the IDE, or xhost +SI:localuser:$USER for the Docker way without ~/.Xauthority
no input on the PC libxtst6 missing (native)
the phone never connects outside the LAN strict NAT (mobile carrier, company): a TURN server (turn of peer()), see TODO

Example game

games/webrtc-demo (playable at https://jumphp.net/webrtc-demo, 14 languages): two peers on one screen (PING / PONG with the round trip, a cursor over an unreliable channel) and a star-catching duel peer to peer, against a bot (a second peer of the game) or online (signals through the relay).

Samples

Sample Shows
LoopbackSample two peers in one game connected to each other: Space sends a PING through a data channel, the other answers PONG
OnlineSample two players meet on the relay (LobbyScene quick match), signal through it, then send their positions peer to peer

TODO

  • Packagist: published as jumphp/webrtc (v0.5.53, split jumphp/jumphp-webrtc by tools/extensions-publish.sh / the v* tags); the IDE still carries a copy in its code updates (src/Bundled/webrtc) until every installed IDE has a full release with it in vendor/.
  • Network: TCP-like streams and a socket API over a data channel ($peer->stream()), so Tcp-style code can run peer to peer; relay a JumPHP\Net\NetSession room over WebRTC (mesh up to N players, host authority) with automatic fallback to the relay.
  • Audio only: microphone / sound tracks (voice chat between players), $peer->audio(); the desktop's sound in the screen stream (PulseAudio / PipeWire source, Opus).
  • File transfer: $peer->sendFile($path) / on('file') in chunks with progress, resume and a checksum, back-pressure (bufferedAmount).
  • Video: camera tracks; the browser's getDisplayMedia() as a screen source (the browser backend sends a screen too); receive video in PHP (a texture).
  • Screen: Wayland (PipeWire portal), Windows (Desktop Duplication + Media Foundation H.264) and macOS (ScreenCaptureKit + VideoToolbox) sidecars; several monitors (pick one); adaptive bitrate from RTCP / the viewer's stats; clipboard both ways; cursor shape as metadata.
  • Hardware encoders: tune VA-API (AMD / Intel) and NVENC (constant quality, intra refresh instead of key frames); check them on more GPUs.
  • Connectivity: a TURN server for jumphp.net (coturn, short-lived credentials from the playground API); ICE restart when the network changes.
  • Desktop backend without Docker or python: a Rust sidecar (webrtc-rs) shipped with the Tauri runtime, for Windows / macOS.
  • Stats: $peer->stats() (RTT, bitrate, path: LAN / internet / TURN).

Webrtc Посібник