Upgrade notes
What this platform upgrade changes for an existing integration, and what to do about each change.
The relays move to the next upstream MoQ release, and the versioned management API ships. Most integrations need nothing; read the sections for what you use. Library API changes, such as Rust and JavaScript renames, are in the upstream upgrade guide.
HLS segments
HLS and recordings number segments on a grid the publisher declares once per broadcast: the catalog's media.join.interval, its longest GOP. The catalog's root archive field and the per-rendition hls record tracks are gone, and the root clock moves to media.clock:
json
"media": { "clock": { ... }, "join": { "interval": 2000 } }- A publisher whose catalog declares no
media.join.intervalstill streams live over MoQ, but HLS answers 404 for the broadcast, and a recording captures nothing. Publishers built onhangor@moq/hang, including@moq/publishand themoqCLI, declare it from the upstream release that ships with this upgrade, measuring the GOP over the first group when the encoder doesn't state it. A catalog with the old rootarchive,clock, orhlsrecords still parses, and the CDN ignores those fields. - RTMP, SRT, and WHIP ingest declare it.
- A segment is the smallest whole multiple of the interval that is at least a second long. Every rendition shares the grid's segment numbers.
WebSocket
A WebSocket connection must offer a QMux subprotocol, such as qmux-01.moq-lite-06 or a bare qmux-01. An upgrade request that offers none, or only the legacy webtransport one, gets HTTP 400. Current @moq/lite, @moq/net, and moq CLI releases already offer one; upgrade a client that predates QMux.
MoQ clients
The CDN speaks the new upstream wire. These changes reach MoQ clients through it; the upstream upgrade guide has the details.
- The CDN accepts moq-transport drafts 18, 20, and 22, and refuses drafts 14 to 17, 19, and 21 at the handshake. Connect on draft 18, 20, or 22, or on moq-lite.
- On moq-transport draft 18, the answer to a whole-group
FETCHnames the group fetched instead of the one after it. A client on an oldermoq-net, such as themoqCLI or a binding built on it, can reject the answer. Upgrade it, or connect on draft 22, which is unchanged. See themoq-netguide. moq-lite-07-wipchanged its wire again without a new ALPN. A client that offers it explicitly negotiates it with the CDN, so it has to run the upstream release that ships with this upgrade, or leave it out and connect onmoq-lite-06, the default.- A subscription resumes on a new route, for example after a relay drains or fails over, only when every link the route crosses carries the publisher's instance: moq-lite-07. A moq-lite-06 or moq-transport link names each announcement afresh, so over a moq-lite-06 publisher or viewer, the default for current clients, the move used to be seamless and is now a restart: the broadcast ends and starts again, and the player requests it again. RTMP, SRT, and WHIP ingest name their instance, so for them only the viewer's protocol matters.
- A publisher that reconnects, or another one taking its broadcast path over, starts a new run of the broadcast. A subscription already open stays on the old run until the old run's route goes, so a player has to request the broadcast again to reach the new run. Players that watch announcements do this: the path's announcement is a
Restarton moq-lite-07, and an end then a start on moq-lite-06. ARestartof a prefix announcement covers every broadcast served through that prefix, but not one with a more specific announcement of its own.@moq/watchand the dashboard's Rust sample follow both; its JS, Go, and Kotlin samples follow lite-06 End/Start. C sample replacement support and lite-07 support in the other samples wait on upstream SDK releases. A player that ignores announcements, such as an IETF moq-transport player, and RTMP, SRT, and WHEP playback keep the old run until its route goes; reconnect to switch. - SRT ingest carries SCTE-35, KLV, subtitles, and the other MPEG-TS streams it doesn't decode as data tracks. A break in one, such as a clock jump the encoder flags, is now a group of one empty object instead of a skipped group, and a reader on an older
hang,@moq/hang, ormoqCLI fails to decode it. Upgrade data-track readers to the upstream release that ships with this upgrade.
Ending a broadcast
A broadcast that ends cleanly stays up for 30 seconds, so a viewer who arrives late still gets its tail. A clean end is an RTMP unpublish, a WHIP DELETE, or an SRT stream that ends or goes silent. A dropped RTMP connection or a WHIP peer that disconnects still ends at once.
The broadcast.ended webhook fires when the 30 seconds are up, so it arrives about 30 seconds later than before.
Timestamp rewinds
SRT ingest ends when a stream's timestamps jump backward, for example when an encoder loops a file or resets its clock without reconnecting. The CDN used to shift the timeline forward and carry on. Reconnect the encoder after a timestamp reset. RTMP ingest already ended on a rewind.
Playback latency
- SRT playback runs at least 1 second behind its source, and about 2 seconds behind an RTMP, WHIP, or browser source, so a receiver's decoder buffer has room to fill. It used to run a few hundred milliseconds behind.
- RTMP playback drops frames older than 500 milliseconds by default, down from 2 seconds. Add
?latency=<ms>to the play URL to buffer more.
HLS
Media playlist and segment URLs now carry the publisher's instance, as in /hls/<project>/<broadcast>/@<instance>/video/hd/media.m3u8. master.m3u8 keeps its URL. Start every player from master.m3u8 and don't store the URLs it lists.
A player that was mid-stream during the upgrade can get a 404 for a media playlist or segment. Reload master.m3u8 to recover. hls.js and Safari report this as a fatal error instead of reloading on their own, so handle the error by reloading the source.
A broadcast whose publisher instance did not reach the edge gets 409 Conflict for every HLS URL, master.m3u8 included. RTMP, SRT, and WHIP ingest always carry one, and MoQ publishers do on moq-lite-07. A moq-lite-06 or IETF moq-transport publisher loses HLS until it offers moq-lite-07. While the upgrade rolls out, even a publisher on moq-lite-07 can get 409 from an edge other than the one it connects to.
Tokens and paths
- Tokens that use the older
put/getclaims are checked likepublish/subscribetokens, by the relay and by recording playback and S3 access. A claim other thanroot,put,get,publish,subscribe,exp,iat,nbf,iss,sub, orjtiis refused,nbfis enforced, and a token that mixesput/getwithpublish/subscribeis refused. Drop extra claims from tokens you sign yourself. - A recording playback or S3 token's
rootmust name the project: its pid, its current name, or a name it was recently renamed from. A token with an emptyrootis refused there. - A URL may carry
jwt=once. A second one is refused: 403 for a MoQ connection, 400 for HLS, and a rejected connect for RTMP. For RTMP, put the token in the URL or in the stream key, not both. - A broadcast path with an empty segment, such as
a//bor the trailing slash indemo/, or a.or..segment, is refused for publishers and viewers. - WHIP and WHEP
DELETEneeds the token that created the session, as?jwt=or anAuthorization: Bearerheader. A session created without a token can't be deleted; it ends when the peer disconnects. - If your project uses an auth endpoint, the request it receives names a WebTransport session
"transport": "webtransport"instead of"quic". Upgrade endpoints built on@moq/authto 0.2.3 or later before the relay upgrade. An endpoint that checkstransportagainst a fixed list, includingmoq auth serve, must also accept the new value or it refuses browser viewers.
Billing
- HTTP
/fetchreads are billed as delivery, at the same rate as the same data read over MoQ. They weren't billed before. See pricing. - Recording uploads into your own bucket are billed as recording delivery, at $0.02/GB like recording playback, and draw on the free delivery allowance. They used to be billed as recording, at $0.01/GB, and drew on the archive allowance. Recordings kept in our bucket still cost $0.01/GB to record.
- A monthly spend cap now stops traffic once it's reached: new connections and playback are refused, and running sessions end at their next check. It lifts when you raise or remove the cap, or when the next month starts. Reaching it used to send a notice only.
- An account without a payment method already shared one free allowance across its projects on the bill. The limits now count it the same way: the connection limit at twice the allowance and the recording limit at the allowance both include usage from every project on the account, so a newer project can reach them sooner.
Recordings
- Recordings made before the upgrade are no longer listed, playable, or billed. Their objects expire with their retention.
- A recording ID is now
<broadcast path>/<instance>. A UUID ID from before the upgrade names nothing. - A publisher that restarts under the same route instance continues the recording it started, at any age, as its next generation. A restart under a new instance, or over a link that carries none, starts a new recording. Conflicting or backwards media under a reused instance ends that generation with an error. The recording keeps the latest diagnostic from its retained generations; media recorded before the error still plays.
- A recording that is running during the upgrade may stop early.
Management API
GET /projects/:slug/public now requires read access to the project; it used to answer anyone.
This upgrade adds the versioned /v1 API, account tokens, and the CLI. Later /v1 changes follow the versioning policy, and every deprecation is listed in the deprecation ledger.