Selective Forwarding Unit for the Gryt voice & video platform.
High-performance Go media server built with Pion WebRTC.
Forwards audio, camera and screen-share tracks, with RTCP relay and layer-aware SVC forwarding.
docker pull ghcr.io/gryt-chat/sfu:latest
docker run -p 5005:5005 -p 3478:3478/udp --env-file .env ghcr.io/gryt-chat/sfu:latestBrowse tags at ghcr.io/gryt-chat/sfu.
cp env.example .env
go run ./cmd/sfuStarts on http://localhost:5005.
Registered in preference order: H.264, VP9, VP8, AV1. H.264 goes first because it has the widest hardware-accelerated support across browsers and platforms, which matters more in practice than the compression the others win on.
Video is forwarded per temporal layer rather than whole. internal/svc reads the
dependency descriptor and drops packets above a receiver's subscribed layer, so a
client on a poor connection gets a lower frame rate instead of a stalled track.
See env.example for all options. Key variables:
Every variable the SFU reads, and nothing it doesn't:
| Variable | Default | Description |
|---|---|---|
SFU_PORT |
5005 |
HTTP/WebSocket port. PORT is read as a fallback |
STUN_SERVERS |
stun:stun.l.google.com:19302 |
Comma-separated STUN servers |
DISABLE_STUN |
false |
Stop discovering srflx candidates. Only safe with a direct, port-preserving path to the internet |
ICE_UDP_MUX_PORT |
3478 |
The one UDP port all media flows over |
AUDIO_TRANSPORT_PORT |
4433 |
UDP port for Gryt's own voice transport (WebTransport). Needs ICE_ADVERTISE_IP. 0 turns it off and clients stay on WebRTC |
AUDIO_UDP_PORT |
0 (off) |
UDP port for Gryt's native voice engine (plain UDP, encrypted per packet). Needs the transport above. Nothing uses it until the native apps ship |
ICE_ADVERTISE_IP |
— | Comma-separated IPs to advertise as host candidates, replacing the ones found on the interfaces |
MAX_PEERS |
200 |
How many peers may be connected at once |
SFU_PING_INTERVAL |
30 |
Seconds between WebSocket pings. 0 switches pinging and the read deadline off |
SFU_PONG_TIMEOUT |
90 |
Seconds a peer may say nothing before the SFU hangs up. Raised to two ping intervals if set lower |
SFU_CALL_ALONE_TIMEOUT |
120 |
Seconds one person may be the only one in a call before it ends. 0 leaves it up. Calls only — a voice channel is never ended for being quiet. Sent to clients in room_joined, and restarted by a still_here message |
SFU_MAX_INGEST_KBPS |
— | The most each peer should send this SFU, in kbps. Sent to clients in room_joined, and the engine keeps its video under it. Advisory: nothing is dropped for going over |
DEBUG |
true |
Room, connection and signaling logging. Defaults on when unset |
VERBOSE_LOG |
false |
RTP forwarding detail |
Full docs at docs.gryt.chat/docs/sfu:
- SFU Overview — architecture, track management, connection states
- Voice Debugging — troubleshooting audio issues
- Deployment — Docker Compose, Kubernetes
Please report bugs and request features in the main Gryt repository.
What sponsoring pays for, the tiers, and everyone who has sponsored: gryt.chat/sponsors. To sponsor: GitHub Sponsors.
The list itself lives in the Gryt README, in one place rather than ten, so it cannot fall out of step across repositories.