streams data flow

Streams data flow: ingest (RTMP/SRT/WHIP/TUS2) → transcode → CMAF over MoQT → signed playback to browsers and native SDKs.

Broadcast live video to any number of viewers, and serve the same content on demand. Push once from any encoder or the browser. The stream fans out to thousands of viewers with sub-second latency. Browsers play it natively over WebTransport. Native SDKs subscribe to the same stream. To let a person watch, give them a short-lived signed playback URL. That URL is the auth, and the relay enforces it for you. You work with two surfaces:
  • Streams manages your live inputs, signing keys, API keys, assets, and analytics over plain HTTPS. It is stateless request/response.
  • BroadcastPublisher + BroadcastViewer move CMAF segments over a persistent MoQT (Media over QUIC Transport) connection.

Live broadcast

Push once and fan out to thousands. Glass-to-glass is sub-second on a warm path.

VOD

Resumable uploads via TUS2, packaged to CMAF, and played from the same catalog that the live path uses.

Four ingest protocols

RTMP, SRT, WHIP (WebRTC-HTTP ingest), and TUS2. Pick the protocol that your encoder or browser already uses.

Signed playback

Mint a JWT-bearing playback URL. The relay checks it inside the subscribe handler. The URL is the auth.

When to use it

Use streams when one producer feeds many consumers and you want adaptive, buffered media rather than a tight interactive loop:
  • Live events, sports, town halls, product launches, IRL streaming.
  • Low-latency “watch parties” where every viewer needs the same timeline.
  • VOD libraries built from the same packaging pipeline as your live streams.
  • Embedded playback in a browser without a separate plugin. WebTransport is the playback path.
If you need a bidirectional, per-participant audio loop (a call), use Voice. If you need typed pub/sub of small messages, use Data.

Ingest

The publish side accepts four ingest protocols. Each live input declares its ingest kind (rtmp, srt, whip, or fmp4). VOD uses TUS2.
Classic encoder ingest (OBS, hardware encoders, mobile broadcasters). Point the encoder at the RTMP endpoint and authenticate with the per-input stream key. The engine ingests, transcodes, and CMAF-packages on the fly.
The browser BroadcastPublisher in the SDK is a WHIP-style alternative. It fragments a MediaStream to CMAF in the page and sends each fragment as a MoQT object. For server-class contribution, prefer RTMP/SRT/WHIP into the engine. Let the transcoder do the packaging.

Wire model

The SDK connects over one of two URL paths, both of which resolve to the same MoQT namespace on the relay:
/publish/… and /playback/… are URL paths, not namespaces. The relay’s stream resolver maps them to stream/<org>/<id>. VOD reuses the same stream/<org>/… namespace, so live and on-demand playback are uniform. The broadcast capability tag is media.broadcast. The relay writes a per-broadcast analytics row keyed on that tag.

The catalog

Every stream carries a catalog (a subset of draft-ietf-moq-catalog) that declares its tracks: name, RFC 6381 codec string, and (for VOD) the CMAF init segment. A live input publishes the catalog in-band on the .catalog track. Thus the catalog can update mid-stream (a rendition added, a codec switched). VOD ships the catalog as catalog.json over HTTPS. The viewer parses the catalog. It opens a MediaSource buffer per track and feeds CMAF segments into it.

Lanes & QoS

Streams use MoQT’s group/object model. Each CMAF fragment is one MoQT object. An init/keyframe fragment opens a new group, so a late joiner can start at a group boundary. Objects carry a priority. The init segment is highest priority, because it must arrive before media decodes. Media segments follow. Under loss, the relay drops by priority and group age. It does not block the whole stream. This is buffered, adaptive delivery, not a frame-perfect interactive lane.

Codecs & packaging

  • Video: H.264/AVC (avc1.*) on the broad-compatibility path. The catalog declares the codec string per track.
  • Audio: Opus or AAC (mp4a.40.2).
  • Container: CMAF / fragmented MP4 (fMP4): ftyp+moov init segment, then moof+mdat media fragments. The viewer feeds them directly into the browser’s MediaSource.
  • Fallback: LL-HLS (Low-Latency HLS) over HTTPS for environments where WebTransport is not available. The CMAF segments are the same bytes. Only the delivery framing changes.

Signed playback (JWT)

A short-lived JWT authorizes playback. The JWT is minted from one of the org’s signing keys (Ed25519 by default, RS256 optional). The control plane returns a playback URL with the token already attached as ?tok=. The relay checks the JWT inside the SUBSCRIBE handler. A bad or expired token closes the session with auth_failed. The server clamps tokens (30 s – 24 h, default 1 h). Re-mint and re-open before expiry to keep long viewers alive.
The API returns the cleartext stream key for a live input once, at create() / rotateStreamKey(). The control plane stores only a hash and will never return the key again. Capture and store the key the moment the API returns it.

How it works

A million-viewer fan-out costs you, the publisher, exactly one upload. It does not cost one copy per viewer. The relay mesh does the fan-out. One QUIC connection multiplexes every track. The relay replicates each group out to subscribers at the edge.
Latency stays low because the data plane skips per-hop copies. It runs on a shard-per-core reactor with a kernel-bypass NIC fast path, io_uring for async I/O, and lock-free mcache / dcache rings that move packets between cores without contention.