The Problem
Developers building live‑audio/video or AI‑driven multimodal experiences need a self‑hosted, production‑grade SFU that can be started, scaled, and extended without pulling in a monolithic stack. Maintaining real‑time media pipelines, participant routing, and credential handling is error‑prone and hard to test in isolation.
What This Does
The repository bundles four Go‑centric projects that together implement a WebRTC SFU server, routing layer, and supporting agents. The core server lives in cmd/server/ (main.go, commands.go) and wires together the packages under pkg/—most notably pkg/rtc/ (media tracks, participants, rooms) and pkg/routing/ (local‑router, Redis router, node stats). Configuration is read from a YAML file (config‑sample.yaml) and the binary can be run directly or via the provided Dockerfile.
How It Is Wired
Execution begins at cmd/server/main.go:123 → main. After a brief init (line 119) it calls startServer (line 247). startServer:
- Parses the YAML config (
pkg/config/config.go) – a filesystem read path (os.Open). - Validates TLS/JWT keys (
ValidateKeysinpkg/config/config.go) – another file read. - Instantiates a
localrouter.Start(pkg/routing/localrouter.go:128).
Start creates the routing graph used by every participant, then spawns the SFU (pkg/rtc/room.go, pkg/rtc/participant.go). The most‑used internal functions are:
recordInvocation– called from 347 places, making it a high‑impact change point.Load,ID,Store,Run,Add,Close– each referenced >50 times across the codebase.
The call graph shows recordInvocation as a hub; altering its signature ripples through >300 call sites. No circular import cycles were detected, but three files (pkg/rtc/participant.go, pkg/rtc/room.go, pkg/rtc/subscriptionmanager.go) each exceed 3 k lines, raising the blast radius for any modification.
External effects:
- Filesystem – config load (
os.ReadFile), key validation (os.Open). - Network –
Startperforms an outboundhttp.Get(e.g., health checks). - Subprocess –
mainmay invoke external commands viacmd.Run.
No database drivers appear in the static call graph, but several functions are marked as “reads or writes a database” by the analysis layer, suggesting future extensions.
How To Use It
# Clone the repo (use the exact URL)
git clone https://github.com/moses-y/livekit
cd livekit
# Build the server binary
go build -o livekit-server ./cmd/server
# Or build the Docker image (Dockerfile is present)
docker build -t livekit:local .
Configuration:
- Copy
config-sample.yamltoconfig.yaml. - Supply TLS cert/key paths and a JWT secret inside the file (the server validates them at startup).
Run:
# Binary
./livekit-server --config config.yaml
# Docker
docker run -p 7880:7880 -v $(pwd)/config.yaml:/app/config.yaml livekit:local
The server listens on the port defined in the config (default 7880) and advertises a REST endpoint for room/participant management.
Real‑World Use
A typical deployment places the LiveKit container behind a TURN server and a load balancer. An application creates a room via the REST API, obtains a JWT from the server (pkg/clientconfiguration), and the client SDKs (JS, iOS, Android) connect to the SFU for media exchange. Agents in pkg/agent/ can be added to the routing graph to inject AI processing (e.g., speech‑to‑text) into a live session.
Code Health & Issues
Measured static findings (high‑severity)
- Deep nesting – 45 files (e.g.,
pkg/rtc/mediatrack.go,pkg/rtc/participant_sdp.go) reach 8‑level indentation, making control flow hard to follow. - Duplicated code – 1 682 six‑line blocks repeated across ~340 files (e.g.,
bootstrap.sh,install-livekit.sh,cmd/server/*.go). - Oversized files – 14 files exceed 3 k lines (
pkg/rtc/participant.go,room.go,subscriptionmanager.go), increasing change impact.
Code‑health audit (GitHub‑Actions/Docker)
| Severity | Issue | Location |
|---|---|---|
| High | Pin third‑party GitHub Actions to commit SHA | .github/workflows/*.yaml (e.g., livekit/slack-notifier-action@main) |
| Medium | Pin Docker base image by digest | Dockerfile (uses golang:1.25-alpine) |
| Medium | Add dependency‑vulnerability scan to PRs | .github/workflows/buildtest.yaml (no scan step) |
| Medium | Set persist-credentials: false on checkout | .github/workflows/buildtest.yaml (checkout step) |
| Medium | Run container as non‑root user | Dockerfile (no USER directive) |
| Low | Define timeout-minutes for workflow jobs | .github/workflows/buildtest.yaml (jobs missing timeout) |
All other hygiene checks (tests, CI, licence, lockfile) are present.
The Bottom Line
LiveKit provides a mature, Go‑based SFU with a clear entry point and Docker support, but the codebase suffers from deep nesting, duplicated helpers, and several megafile hotspots that inflate change risk. It is suited for teams comfortable with Go who need a customizable real‑time media backend, provided they allocate effort to refactor the high‑impact modules and tighten the CI/CD supply chain.