Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Media over QUIC: Three Problems We Hit Building...

Avatar for d-mastui d-mastui
September 03, 2026
34

Media over QUIC: Three Problems We Hit Building a Relay

Avatar for d-mastui

d-mastui

September 03, 2026

Transcript

  1. Three problems we hit implementing Media over QUIC Daiki Matsui

    September 3, 2026 Video Tech Conference
  2. WebRTC, if you want low latency — Born in 2011

    to bring real-time communication to browsers — Sub-second latency; the de facto standard for video conferencing But... — Not built for large-scale delivery (no cheap CDN; you have to coordinate your own SFUs) — Deeper optimization means touching libwebrtc (hard)
  3. HLS/DASH, if you want scale — Born in 2009 to

    deliver live video over HTTP — Video is just files, so existing CDNs work as-is But... — Latency is seconds to tens of seconds — LL-HLS / LHLS have narrowed the gap, but still within HTTP
  4. Meanwhile, QUIC arrived and spread 2012 Google starts experiments 2021

    RFC 9000 — The protocol behind HTTP/3, running in production on CDNs worldwide — Rebuilds what TCP did, on top of UDP Legacy QUIC HTTP/1.1, HTTP/2 HTTP/3, WebTransport TLS QUIC (TLS built in) TCP UDP IP IP — Usable from the browser (WebTransport)
  5. So why not just send media over QUIC? Meta Twitch

    Cisco RUSH (2021) Warp (2022) QuicR (2022)
  6. That became Media over QUIC (MoQ) — A working group

    was set up at the IETF and standardization began — Defines a Pub/Sub protocol for carrying media over QUIC — Major streaming, conferencing and CDN companies are involved
  7. So we built one (nttcom/moq-wasm) — Implemented MoQ Transport from

    scratch in Rust — Supported both browser (TypeScript) and native (Rust) clients — Deployed the Relays on GCP
  8. We got stuck everywhere 1 Spec Tracking publish state across

    relays 2 Library Sharing one port for QUIC/WebTransport 3 Infra Load balancing with QUIC-LB
  9. Today's goal — Share what you can't get from the

    spec or blog posts: where you actually get stuck — Share what we chose at each point, and why → Even without building it yourself, you'll be able to say "this is where MoQ stands today"
  10. About me — Daiki Matsui (@mti_daiki) — Building the WebRTC

    Platform SkyWay at NTT DOCOMO BUSINESS — Network protocols / curiosity-driven development
  11. 1 Tracking publish state across relays 2 Sharing one port

    for QUIC/WebTransport 3 Load balancing with QUIC-LB
  12. Tracking publish state across relays Publisher and subscriber connect through

    a relay — The publisher publishes a Track * The diagrams are simplified (Namespace, control message details, and so on)
  13. Tracking publish state across relays Publisher and subscriber connect through

    a relay — The publisher publishes a Track — The relay learns about the Track * The diagrams are simplified (Namespace, control message details, and so on)
  14. Tracking publish state across relays Publisher and subscriber connect through

    a relay — The publisher publishes a Track — The relay learns about the Track — The subscriber subscribes to the Track * The diagrams are simplified (Namespace, control message details, and so on)
  15. Tracking publish state across relays Publisher and subscriber connect through

    a relay — The publisher publishes a Track — The relay learns about the Track — The subscriber subscribes to the Track — Data flows from the publisher to the subscriber * The diagrams are simplified (Namespace, control message details, and so on)
  16. Tracking publish state across relays But they don't always land

    on the same relay Where should this be forwarded? Knows about no Track → How do you know which relay holds which Track?
  17. Tracking publish state across relays Just record it somewhere (centralized

    approach) — When a broadcast starts, record “this Track is on relay A” — When a subscribe arrives, look it up and forward to relay A — It works and it is simple, but it becomes a SPOF, so it needs redundancy 1. record 3. look up 4. forward subscribe
  18. Tracking publish state across relays But the load piles up

    on the origin relay — Only “where the origin is” gets recorded — A relay that receives a subscribe connects straight to it — With 50 relays, the origin relay sends the same video 50 times Sends the same video once per relay
  19. Tracking publish state across relays What we want instead (multi-tier

    relays) — Relays in the middle receive it and copy it onward — The origin relay only has to send to its downstream relays
  20. Tracking publish state across relays So we should record the

    route? — Record “who is upstream” instead of “the origin is A” — A subscribe is forwarded upstream, and following it reaches the origin Store (route of a Track) (B's upstream is A) data But... — Who decides this route, and how? — Every time relays come and go, it has to be rebuilt subscribe
  21. Tracking publish state across relays Just tell your neighbours (decentralized

    approach) — Tell neighbours about a publication, and they tell theirs (any relay topology assumed) — Each relay records “which neighbour this publication came from” — When a subscribe arrives, forward it to the right neighbour → repeat, and it reaches the publisher has the track But... from A (hop 1) from A (hop 1) ✓ from B (hop 2) ✓ from D (hop 2) from E (hop 3) from C (hop 3) — It needs a custom protocol (MoQLite) — There is a lag before the information propagates
  22. Tracking publish state across relays What we chose Centralized approach

    moq-wasm (us) ◦ ◦ moq.dev Cloudflare Decentralized approach ◦ — The point of a PoC is to learn by running it. It is not the stage for building out scale — We understood the options, then picked the lightest one — At larger scale — multi-region, for instance — the call would be different
  23. 1 Tracking publish state across relays 2 Sharing one port

    for QUIC/WebTransport 3 Load balancing with QUIC-LB
  24. Sharing one port for QUIC/WebTransport Browsers can't use raw QUIC,

    only WebTransport — Non-browser clients (native) can use raw QUIC directly — Underneath, both are QUIC, so ALPN (which announces the protocol name at connect time) can tell them apart Handle as raw QUIC Browser Browser → No need for separate listening ports Handle as WebTransport (over HTTP/3)
  25. Sharing one port for QUIC/WebTransport raw QUIC first, WebTransport next

    — We implemented MoQ on top of raw QUIC Adopted quinn (the de facto QUIC implementation in Rust) — Then we moved on to WebTransport support Adopted wtransport (a WebTransport implementation built on quinn) → Same QUIC implementation (quinn), so sharing a port should be straightforward
  26. Sharing one port for QUIC/WebTransport There is no seam to

    hand a QUIC Connection through let server = quinn::Endpoint::server(config, addr)?; loop { let conn = server.accept().await?.await ?; match conn.alpn () { // handle as raw QUIC // handle as WebTransport b"moqt" b"h3" => { ... } => { let session = wtransport::from_quinn (conn)?; // ↑ no such API exists ... } } } → Not a protocol problem — a library API problem
  27. Sharing one port for QUIC/WebTransport Someone had already solved the

    same problem — Existing MoQ implementations must be hitting the same problem — moq.dev had built its own library to pair with quinn (web-transport-quinn) — We switched to web-transport-quinn as well, and can now accept both on one port → Implementing a new protocol can fall outside what existing libraries assume
  28. 1 Tracking publish state across relays 2 Sharing one port

    for QUIC/WebTransport 3 Load balancing with QUIC-LB
  29. Load balancing with QUIC-LB What we want to achieve —

    Clients should connect to the nearest region — Load should be spread across several machines within a region — Connections should survive an IP change (QUIC Connection Migration) Client Client Client Japa n United States Europe → Putting an LB in front is the obvious move — but what happens with QUIC?
  30. Load balancing with QUIC-LB An L7 LB terminates QUIC —

    L7 LBs assume HTTP, so raw QUIC can't be used — WebTransport over HTTP/3 works, but the LB terminates HTTP/3 — Between LB and relay it becomes HTTP/1.1 or HTTP/2, so QUIC is gone Client Terminated here → We want the LB to forward packets as they are, not terminate them
  31. Load balancing with QUIC-LB Then what about an L4 LB?

    — It forwards packets as they are, so client and relay connect over QUIC directly — But an ordinary L4 LB distributes by 5-tuple hash — When the IP changes (Wi-Fi → LTE, etc.) the target changes too, and packets reach a different relay Client 5-tuple hash ② When it switches to LTE Client 5-tuple hash Doesn't know this connection → We want distribution per connection, not per 5-tuple
  32. Load balancing with QUIC-LB QUIC-LB is what solves this —

    It distributes by the Connection ID inside the QUIC packet, not the 5-tuple — A draft is being developed at the IETF — Only AWS supports it (GCP and Azure do not) Client Looks at Connection ID ② Even when it switches to LTE Client Looks at Connection ID Arrives at the same relay → But our platform is GCP-based...
  33. Load balancing with QUIC-LB The options What you give up

    Cost Implement QUIC-LB ourselves — Hybrid AWS / GCP setup — Running two clouds Redirect approach — One extra RTT on connect, custom routing logic GeoDNS Load-aware distribution Relay IPs exposed directly, DNS ops as the fleet scales GCP L4 LB Connection Migration — Heavy to build and operate
  34. Load balancing with QUIC-LB What we chose — We gave

    up Connection Migration and adopted the GCP L4 LB — We chose shipping something that works over a more complete LB — The LB setup is independent of the application, so we can change it later → You want to get everything out of a new technology, but wait for what can wait
  35. Wrap-up 1 Spec Tracking publish state across relays 2 Library

    Sharing one port for QUIC/WebTransport 3 Infra Load balancing with QUIC-LB Centralized / decentralized → the implementer's call A new protocol can fall outside what existing libraries assume The ecosystem is not quite there yet If you take away “so this is where MoQ stands right now” from the spec, library and infrastructure angles, that is enough for me X: mti_daiki Mail: [email protected]