Media over QUIC #
Streamplace nodes hand live streams to each other over
moq-lite
(draft 06). The implementation is pkg/moq; the node's listener and the
segment-bus publisher are pkg/api/moq.go; the pull side is the
websocketrep replicator, which prefers an origin's MoQ URL over its
websocket when one is advertised.
Wire convention #
The payload is MUXL and nothing else.
| moq-lite | Streamplace |
|---|---|
| broadcast path | the streamer's DID (did:plc:...) |
track source |
the stream's signed source segments |
track renditions |
the rendition addenda the ingest node mints (media.RenditionsChannel) |
| group | one segment (one GoP) |
| frame | the bare canonical MUXL segment, the bytes bus.Seg.Muxl carries |
| timescale | 1000; a frame's timestamp is the publish time in Unix milliseconds |
A subscriber validates every source frame with MediaManager.ValidateMP4,
exactly as the websocket path does, and verifies every rendition addendum
with muxl verify. A frame that is not MUXL fails validation and ends the
session; the publisher side refuses to send a segment that does not lead
with a uuid box at all.
Subscriptions start at the live edge: the publisher primes a new subscriber
with the last few segments, like place.stream.live.subscribeSegments.
Every group is served whole, in order, on its own QUIC stream; FETCH and
PROBE are refused, and nothing is sent as a datagram.
Bindings #
One UDP port serves both bindings, selected by ALPN:
- raw QUIC with ALPN
moq-lite-06(moqt://host:port), which the SETUP Path parameter carries the URL's path and query over; - WebTransport over HTTP/3 (
https://host:port/<any path>), withmoq-lite-06negotiated as the WebTransport subprotocol. This is the binding a browser uses.
Configuration #
| Flag | Env | Default | Meaning |
|---|---|---|---|
--moq-addr |
SP_MOQ_ADDR |
:38443 |
UDP listen address; empty disables the listener. |
--moq-url |
SP_MOQ_URL |
Override for the advertised moqt:// URL (default: --server-host on --moq-addr's port). |
The listener terminates TLS itself, even on a node behind an HTTPS proxy:
- with
--secure, it serves the node's certificate (ACME or--tls-cert/--tls-key); - otherwise it mints a self-signed ECDSA certificate, valid for two weeks
and rotated weekly (the limits a browser puts on a pinned certificate),
and advertises its SHA-256 as the
certhashquery parameter of the MoQ URL. A subscriber pins exactly that certificate.
Discovery #
The advertised URL travels two ways, like the websocket URL:
- the
moqURLfield of the streamer'splace.stream.broadcast.originrecord on the firehose; - the
moq_urlcolumn of the station's sharedbroadcast_originstable, written by the ingest node on every local segment, so nodes sharing a statedb find each other without a relay.