ドキュメント — 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):
- 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'sgstreamer1-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) orintel-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.
- Debian / Ubuntu / Mint:
- Docker (when the native way is incomplete): Docker Engine running and usable without sudo (
sudo usermod -aG docker $USER, then log in again). The imagejumphp/webrtc-gst:<hash>is built fromdocker/Dockerfilethe 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,~/.Xauthorityand/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, splitjumphp/jumphp-webrtcbytools/extensions-publish.sh/ thev*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()), soTcp-style code can run peer to peer; relay aJumPHP\Net\NetSessionroom 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).