Live777 Core (liveion)
A Pure Single SFU Server for WebRTC.
WHIP / WHEP protocols are supported by default. When built with the rtsp feature, liveion can also act as an RTSP server: push media in via ANNOUNCE/RECORD and pull media out via DESCRIBE/PLAY.
a core SFU server, If you need a single server, use this
Current support codecs
| protocol | video codecs | audio codecs |
|---|---|---|
WHIP | AV1, VP9, VP8, H265, H264 | Opus, G722 |
WHEP | AV1, VP9, VP8, H265, H264 | Opus, G722 |
RTSP | AV1, VP9, VP8, H265, H264 | Opus, G722 |
Current client support
| Application | AV1 | VP9 | VP8 | H265 | H264 | OPUS | G722 |
|---|---|---|---|---|---|---|---|
Browser whip | ⭐ | ⭐ | ⭐ | ⭐ | ⭐ | ⭐ | ⭐ |
Browser whep | ⭐ | ⭐ | ⭐ | ⭐ | ⭐ | ⭐ | ⭐ |
Gstreamer whip | ⭐ | ⭐ | ⭐ | ⭐ | ⭐ | ⭐ | ⭐ |
Gstreamer whep | 📺 2 | ⭐ | ⭐ | ⭐ | ⭐ | ⭐ | ⭐ |
Gstreamer whipinto | 📺 1 | ⭐ | ⭐ | ⭐ | ⭐ | 📺 1 | ⭐ |
Gstreamer whepfrom | 📺 2 | ⭐ | ⭐ | ⭐ | ⭐ | ⭐ | ⭐ |
FFmpeg whipinto | 💩 | ⭐ | ⭐ | ⭐ | ⭐ | ⭐ | ⭐ |
FFmpeg whepfrom | 💩 | ⭐ | ⭐ | ⭐ | ⭐ | ⭐ | ⭐ |
VLC whipinto | 💩 | 💩 | ⭐ | ⭐ | ⭐ | ⭐ | 💩 |
VLC whepfrom | 💩 | 💩 | ⭐ | ⭐ | ⭐ | ⭐ | 💩 |
OBS Studio whip | 📺 3 | 💩 | 💩 | ⭐ | ⭐ | ⭐ | 💩 |
- ⭐ It's working
- 💩 Don't support
- 💡 I don't know, No testing
- 📺 Note have some problem
- Working, But Browser can't player this video, Gstreamer to Gstreamer is working
- I don't know why av1 and whep error
- OBS av1 codec can't play
Authentication
No Authentication
DANGER
No Authentication is Default
If no set any about [auth] section in configuration file, There will no authentication
Bearer token
Static HTTP bearer token is super admin access, you should use in develop, test, debug or cluster manager
# WHIP/WHEP auth token
# Headers["Authorization"] = "Bearer {token}"
[auth]
# static JWT token, superadmin, debuggger can use this token
tokens = ["live777"]JWT(JSON Web Token)
Use this authentication, the token include access, you can control stream, publish, subscribe...
# WHIP/WHEP auth token
# Headers["Authorization"] = "Bearer {token}"
[auth]
# JSON WEB TOKEN secret
secret = "<jwt_secret>"Cascade
What is cascade?
Very large cluster
live777 Cascade have two mode:
cascade-pullcascade-push
Static cascade-pull (WHEP source)
cascade-pull can also be declared as a static stream input instead of an API call. Build with the source-whep feature and add a whep:// source to a provisioned stream; it behaves like any other configured source (on_demand start/stop, reconnect, RTCP keyframe feedback):
[[stream.cam1.sources]]
url = "whep://edge-0:7777/whep/cam1"
# With Bearer auth:
# url = "whep://token@edge-0:7777/whep/cam1"When this source is used with on_demand = true, live777 waits at least 35000ms for the upstream WHEP source to become ready, even if on_demand_start_timeout_ms is lower. This covers cold upstream on-demand pulls that may spend the WHEP HTTP request timeout before delivering media.
The outgoing WHEP peer gathers ICE candidates using the server's own [[ice_servers]] configuration and binds the UDP sockets from [webrtc] ice_udp_addrs (no hardcoded STUN server).
Chained on-demand pulls work one hop deep by default: this source's WHEP HTTP request waits up to 40000ms for the answer, covering an upstream that itself holds subscribes for up to 35000ms (an on-demand WHEP source). Deeper chains need their budgets aligned per deployment. Stopping this source (e.g. when the last subscriber leaves an on_demand stream) may wait out an in-flight WHEP HTTP request, bounded by that same 40000ms timeout.
Static cascade-push (WHIP target)
cascade-push can also be declared as a static stream output instead of an API call. Build with the target-whip feature and add a whip:// target to a provisioned stream:
[[stream.cam1.targets]]
url = "whip://edge-1:7777/whip/cam1"
# With Bearer auth:
# url = "whip://token@edge-1:7777/whip/cam1"The push is media-driven: it is established when the stream gains a publisher (WHIP or a configured source) and torn down when the publisher goes away, so the downstream node sees ordinary publisher attach/detach cycles and its own auto_delete_*/on-demand strategies keep working. A configured target on an on_demand stream acts as standing demand: its sources are (re)started whenever the stream has neither a publisher nor a push session, so the relay recovers on its own once an unreachable downstream is back. A lost session (downstream close, ICE failure, provisioned-stream reset) is re-established with exponential backoff (5s doubling, 60s cap) — the same pacing bounds the on-demand source restarts, at roughly one attempt per minute.
DataChannel Forward
NOTE: About
createDataChannel()
- Live777 Don't support
label,createDataChannel(label)thislabelis not used- Live777 Don't support
negotiated,{ id: 42, negotiated: true }this don't support
RTSP Server
Build with the rtsp feature to expose an RTSP server alongside WHIP/WHEP:
cargo build --release --bin live777 --features rtspConfigure the listen URL in live777.toml. When credentials are present in the URL, Digest authentication is enabled automatically:
[rtsp]
# No auth:
listen = "0.0.0.0:8554"
# With Digest auth:
# listen = "rtsp://admin:secret@0.0.0.0:8554"The same port handles both directions:
- Push media into a stream:
rtsp://host:8554/{stream_id}(ANNOUNCE+RECORD) - Pull media from a stream:
rtsp://host:8554/{stream_id}(DESCRIBE+PLAY)
Both UDP and TCP (RTP/AVP/TCP) transports are supported. The first URL path segment is used as the liveion stream identifier.
Stream Hooks
Live777 can run external scripts on stream lifecycle events: stream creation/deletion, and publish start/stop (a WHIP/cascade publisher attaching, or a configured source starting/stopping). A typical use is on-demand source activation for devices live777 cannot drive directly: a hook starts a capture device / hardware encoder when media is actually wanted, and stops it when the last consumer leaves to save resources.
Built-in alternative: configured sources (
[[stream.<name>.sources]]) supporton_demand = true, which starts/stops the camera or RTSP pull automatically with subscriber presence — no scripts needed. See livehal — Provisioned streams and on-demand sources.
Which events signal "someone is watching"? For provisioned streams (any
[stream.<name>]entry)stream-createdfires once at startup, so it cannot drive power control — usepublish-started/publish-stoppedinstead. Configured sources report their start/stop as publish events with the session idvirtual-source. For dynamic streams (auto_create_whep),stream-createdstill coincides with first use.
# Global hooks, run for every stream.
[hooks]
timeout_ms = 5000 # per-script timeout, 0 disables
on_error = "stop" # "stop" skips the remaining hooks of the same event;
# "continue" runs them anyway
on_stream_created = ["/etc/live777/hooks/notify.sh"]
on_stream_deleted = ["/etc/live777/hooks/notify.sh", "/etc/live777/hooks/cleanup.sh"]
on_publish_started = ["/etc/live777/hooks/camera-power.sh"]
on_publish_stopped = ["/etc/live777/hooks/camera-power.sh"]
# Per-stream hooks, run after the global ones.
[stream.cam1.hooks]
on_stream_created = ["/etc/live777/hooks/cam1-created.sh"]
on_stream_deleted = ["/etc/live777/hooks/cam1-deleted.sh"]
on_publish_started = ["/etc/live777/hooks/cam1-power-on.sh"]
on_publish_stopped = ["/etc/live777/hooks/cam1-power-off.sh"]Execution guarantees:
- Hooks of one event run sequentially: global first, then per-stream, in configured order.
- Events are processed in a single FIFO queue — all hooks of an earlier event finish before any hook of a later event starts, so a stream's
stream-createdhooks always complete before itsstream-deletedhooks begin. - A failed script (non-zero exit, spawn error, timeout kill) is logged and handled per
on_error; it never affects later events or the server.
Scripts are executed directly (no shell) and receive the event metadata both as argv and as environment variables:
| argv | env | value |
|---|---|---|
$1 | LIVE777_EVENT | stream-created / stream-deleted / publish-started / publish-stopped |
$2 | LIVE777_STREAM | stream name |
$3 (deleted/stopped only) | LIVE777_REASON | stream-deleted: api-deleted / publish-leave-timeout / subscribe-leave-timeout / orphaned / reset; publish-stopped: peer-closed / api-deleted / idle-timeout |
| — | LIVE777_SESSION | (publish events only) publisher session id; virtual-source for configured sources |
Notes:
- Scripts should return quickly after initiating their work (e.g. launch an encoder in the background). A blocked script blocks the whole hook queue.
- Make scripts idempotent: a
stream-deletedhook also runs when the publisher itself died (publish-leave-timeout), so stop scripts must tolerate an already-stopped device. - For on-demand sources, combine with
[strategy] auto_create_whep = trueand a generousauto_delete_whep(e.g.30000) so brief subscriber flapping does not cycle the hardware. Per-stream overrides live under[stream.<name>.strategy]. Streams configured withon_demand = truealready debounce viaon_demand_close_after_ms. - No hooks fire on server shutdown (no
stream-deletedevents are emitted then).