LiveKit Ingress
WebRTC is proving to be a versatile and scalable transport protocol both for media ingestion and delivery. However, some applications may require integrating with existing workflows or equipment that do not support WebRTC. Universal Ingress provides a way to send media that was generated using such workflows to a LiveKit room.
Capabilities
Universal Ingress is meant to be a versatile service supporting a variety of protocols, both using a push and pull model. Currently, the following protcols are supported:
- RTMP
- WHIP (https://datatracker.ietf.org/doc/draft-ietf-wish-whip/)
Supported Output
The Ingress service will automatically transcode the source media to ensure compatibility with WebRTC. It can publish multiple layers with Simulcast. The parameters of the different video layers can be defined at ingress creation time.
Documentation
Push workflow
To push media to the Ingress, the workflow goes like this:
- create an Ingress with
CreateIngressAPI (to livekit-server) CreateIngressreturns a URL that can be used to push media to- copy and paste the URL into your streaming workflow
- start the stream
- Ingress starts receiving data
- Ingress joins the LiveKit room and publishes transcoded media
Service Architecture
The Ingress service and the LiveKit server communicate over Redis. Redis is also used as storage for the Ingress session state. The Ingress service must also expose a public IP address for the publishing endpoint streamers will connect to. In a typical cluster setup, this IP address would be assigned to a load balancer that would forward incoming connection to an available Ingress service instance. The targeted Ingress instance will then validate the incoming request with the LiveKit server using Redis as RPC transport.
Config
The Ingress service takes a YAML config file:
# required fields
api_key: livekit server api key. LIVEKIT_API_KEY env can be used instead
api_secret: livekit server api secret. LIVEKIT_API_SECRET env can be used instead
ws_url: livekit server websocket url. LIVEKIT_WS_URL env can be used instead
redis:
address: must be the same redis address used by your livekit server
username: redis username
password: redis password
db: redis db
optional fields
health_port: if used, will open an http port for health checks
prometheus_port: port used to collect prometheus metrics. Used for autoscaling
log_level: debug, info, warn, or error (default info)
rtmp_port: port to listen to incoming RTMP connection on (default 1935)
whip_port: port to listen to incoming WHIP calls on (default 8080)
http_relay_port: port used to relay data from the main service process to the per ingress handler process (default 9090)
rtc_config: configuration for ICE and other RTC related settings, same settings livekit-server RTC configuration. Used for WHIP.
enable_udp_url_pull: allow URL pull ingresses to pull from udp:// urls (default false, see the security note below)
multicast_interface: network interface to join multicast groups on for UDP url pull. Empty lets the OS decide
optional gzip compression of psrpc bus payloads (see the compatibility note below)
psrpc:
compression:
# gzip level 1-9. 0, the default, disables compression
quality: 0
# payload bytes below which compression is skipped
threshold: 1024
# cap on an inbound payload after decompression, 0 for unlimited
max_decompressed_size: 0
cpu costs for various Ingress types with their default values
cpu_cost:
rtmp_cpu_cost: 2.0
whip_cpu_cost: 2.0
The config file can be added to a mounted volume with its location passed in the INGRESS_CONFIG_FILE env var, or its body can be passed in the INGRESS_CONFIG_BODY env var.
Security note on enable_udp_url_pull
> Only enable UDP url pull if you trust both the callers allowed to create ingresses and the network the
ingress handlers run on. Unlikehttp://andsrt://urls, audp://url doesn't make the handler
connect out to the url host: the handler binds a local socket on the address and port taken from the
url, and joins the multicast group if one is given. As a result, a caller creating a URL pull ingress
can:
> - Choose which local port the handler binds, potentially colliding with other services on the host.
- Have the handler ingest unauthenticated traffic. UDP is connectionless, so any host able to reach
that port can inject media into the session, or spoof the sender address to disrupt a legitimate feed.
- Have the handler join arbitrary multicast groups and republish whatever it receives into a LiveKit
room, using the ingress as a relay for streams on the handler's local network that the caller has no
direct access to.
Compatibility note on psrpc.compression
> Bus compression requires psrpc v0.7.6 or newer on every node sharing the Redis bus. An older peer
ignores the compression marker and tries to decode the gzipped bytes as the message payload, so the
message is dropped without an error. Enabling it is therefore a two-stage operator action: roll a
build with psrpc v0.7.6+ out to livekit-server, ingress, egress, SIP and any agent workers first,
then raise quality at the publishers. It is off by default.
>max_decompressed_sizeonly affects reading, so it can be set ahead ofquality.
In order for the LiveKit server to be able to create Ingress sessions, an ingress section must also be added to the livekit-server configuration:
ingress:
rtmp_base_url: RTMP url prefix pointing to the Ingress external IP address or load balancer
whip_base_url: WHIP url prefix pointing to the Ingress external IP address or load balancer
For instance:
ingress:
rtmp_base_url: rtmp://my.domain.com/x
whip_base_url: http://my.domain.com/w
A stream key will be appended to this prefix to generate the ingress session specific RTMP or WHIP publishing endpoint.
Using the Ingress service
RTMP and WHIP
The first step in order to use the Ingress service is to create an ingress session and associate it with a room. This can be done with any of the server SDKs or with the livekit-cli. The syntax with the livekit-cli is as follow:
livekit-cli create-ingress \
--request <path to Ingress creation request JSON file>
The request creation JSON file uses the following syntax:
{
"input_type": 0 for RTMP, 1 for WHIP
"name": Name of the Ingress,
"room_name": Name of the room to connect to,
"participant_identity": Unique identity for the room participant the Ingress service will connect as,
"participant_name": Name displayed in the room for the participant
}
On success, livekit-cli will return the unique id for the Ingress.
It is possible to get details on all created Ingress with the list-ingress command:
livekit-cli list-ingress
In particular, this will return the RTMP url WHIP endpoint to use to setup the encoder.
Running locally
Running natively
The Ingress service can be run natively on any platform supported by GStreamer.
##### Prerequisites
The Ingress service is built in Go. Go >= 1.18 is needed. The following GStreamer libraries and headers must be installed:
- gstreamer
- gst-plugins-base
- gst-plugins-good
- gst-plugins-bad
- gst-plugins-ugly
- gst-libav
mage bootstrap.
##### Building
Build the Ingress service by running:
mage build
##### Running the service
To run against a local LiveKit server, a redis server must be running locally. All servers must be configured to communicate over localhost. Create a file named
config.yaml with the following content:
log_level: debug
api_key: <your-api-key>
api_secret: <your-api-secret>
ws_url: ws://localhost:7880
redis:
address: localhost:6379
On MacOS, if GStreamer was installed using Homebrew, the following environment must be set in order to ensure that GStreamer can load all its plugins:
export DYLD_LIBRARY_PATH=/opt/homebrew/lib
Then to run the service:
ingress --config=config.yaml
If starting an Ingress fails with a GStreamer error such as
Failed to load libsoup library or no such element factory "souphttpsrc, try deleting your GStreamer plugin registry with:
`shell
rm -rf ~/.cache/gstreamer-1.0/
#### Running with Docker
To run against a local LiveKit server, a Redis server must be running locally. The Ingress service must be instructed to connect to LiveKit server and Redis on the host. The host network is accessible from within the container on IP:
- host.docker.internal on MacOS and Windows
- 172.17.0.1 on linux
Create a file named config.yaml with the following content:
yaml
log_level: debug
api_key:
api_secret:
ws_url: ws://host.docker.internal:7880 (or ws://172.17.0.1:7880 on linux)
redis:
address: host.docker.internal:6379 (or 172.17.0.1:6379 on linux)
In order to be able to use establish WHIP sessions over UDP, the container must be run with host networking enabled.
Then to run the service:
shell
docker run --rm \
-e INGRESS_CONFIG_BODY=" cat config.yaml" \
-p 1935:1935 \
-p 8080:8080 \
--network host \
livekit/ingress
``
| LiveKit Ecosystem | |
|---|---|
| Agents SDKs | Python · Node.js |
| LiveKit SDKs | Browser · Swift · Android · Flutter · React Native · Rust · Node.js · Python · Unity · Unity (WebGL) · ESP32 · C++ |
| Starter Apps | Python Agent · TypeScript Agent · React App · SwiftUI App · Android App · Flutter App · React Native App · Web Embed |
| UI Components | React · Android Compose · SwiftUI · Flutter |
| Server APIs | Node.js · Golang · Ruby · Java/Kotlin · Python · Rust · PHP (community) · .NET (community) |
| Resources | Docs · Docs MCP Server · CLI · LiveKit Cloud |
| LiveKit Server OSS | LiveKit server · Egress · Ingress · SIP |
| Community | Developer Community · Slack · X · YouTube |