Skip to content

Playback

Every live stream is available two ways at once, from the same ingest. You do not choose at publish time.

WebRTC (WHEP)HLS
LatencyTypically under a secondSeveral seconds
ReachModern browsersEverything, including smart TVs
Best forAuctions, betting, anything where the audience talks backScale, and long-tail devices
http://your-host:9001/watch/<application>/<stream>

Public and unauthenticated, meant to be shared. It prefers WebRTC and falls back to HLS. If the broadcast ends, the page says so and reconnects on its own if it starts again.

http://your-host:9001/live/<application>/<stream>/playlist.m3u8

A standard media playlist. Segment length and how much of the live window is retained are set in [hls].

Ad breaks appear as discontinuities, which conforming players handle without special support.

Jadarit speaks WHEP. POST an SDP offer and play the answer:

POST /api/v1/apps/<application>/streams/<stream>/whep
Content-Type: application/sdp
const pc = new RTCPeerConnection();
pc.addTransceiver('video', { direction: 'recvonly' });
pc.addTransceiver('audio', { direction: 'recvonly' });
const offer = await pc.createOffer();
await pc.setLocalDescription(offer);
const res = await fetch(
`/api/v1/apps/${app}/streams/${stream}/whep`,
{ method: 'POST', headers: { 'Content-Type': 'application/sdp' }, body: offer.sdp },
);
await pc.setRemoteDescription({ type: 'answer', sdp: await res.text() });

WebRTC media is UDP and does not travel over an HTTP reverse proxy or a Cloudflare Tunnel. To reach viewers outside your network you need:

  • public_ip set, so the server advertises a reachable ICE candidate
  • a fixed udp_port_min/udp_port_max range, forwarded on your router

Both are in [webrtc]. Leaving the range at 0/0 uses ephemeral ports, which works on a LAN and nowhere else.