Skip to content

Commit 2502c7e

Browse files
kixelatedclaude
andauthored
Proggrers (#106)
Co-authored-by: Claude <noreply@anthropic.com>
1 parent 7a78a14 commit 2502c7e

3 files changed

Lines changed: 242 additions & 0 deletions

File tree

‎public/blog/update-00/bbb.png‎

382 KB
Loading

‎public/blog/update-00/globe.png‎

214 KB
Loading

‎src/pages/blog/update-00.mdx‎

Lines changed: 242 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,242 @@
1+
---
2+
layout: "@/layouts/global.astro"
3+
title: Update 00
4+
author: kixelated
5+
description: Update 00 notes
6+
cover: "/blog/update-00/bbb.png"
7+
date: 2026-06-25
8+
---
9+
10+
# Update 00
11+
12+
sup nerds.
13+
We now doing low-energy progress reports.
14+
15+
Here's a summary of stuff that changed in the last 4? months.
16+
IDK my brain is so fried from talking to Claude all day.
17+
18+
19+
## Hop-based Routing
20+
Now you can [connect relays to each other](https://doc.moq.dev/bin/relay/) however you desire.
21+
They'll gossip available broadcasts to each other and proxy any subscriptions automatically via the shortest path.
22+
23+
For example, I can host a relay in Denver and configure it with:
24+
```bash
25+
moq-relay --cluster-connect chicago.moq.dev --cluster-connect seattle.moq.dev ...
26+
```
27+
28+
Imagine relays are also configured to connect to their nearest neighbors.
29+
A subscription from a user in Europe, subscribing to a broadcast in Denver, might travel:\
30+
`Frankfurt -> London -> New York -> Chicago -> Denver`
31+
32+
At each hop, we deduplicate subscriptions.
33+
Which means at most only one copy of a track will ever be transmitted between two relays.
34+
35+
<figure>
36+
![bbb](/blog/update-00/globe.png)
37+
<figcaption>**SPOILER**: an upcoming marketing image</figcaption>
38+
</figure>
39+
40+
For context, the previous architecture was a mesh.
41+
Every relay would connect to every other relay, which would have resulted in:\
42+
`Frankfurt -> Denver` (oof)
43+
44+
Oh yeah and
45+
Your local relay (snug behind a firewall) can proxy all broadcasts to/from a public CDN:
46+
```bash
47+
moq-relay --cluster-connect https://cdn.moq.dev ...
48+
```
49+
50+
It'll work with any MoQ CDN that implements enough of the [`moq-transport`](https://datatracker.ietf.org/doc/draft-ietf-moq-transport/) spec (*cough* not Cloudflare yet *cough*).
51+
But you'll need `moq-lite-03+` to establish multiple connections, otherwise a cycle will ruin your day.
52+
53+
## Standards
54+
Speaking of standards, the IETF keeps marching forward, so I have to "support" every new draft version lul.
55+
56+
**Supported:**
57+
- [moq-transport](https://datatracker.ietf.org/doc/draft-ietf-moq-transport/) drafts 14-18.
58+
- [qmux](https://datatracker.ietf.org/doc/draft-nandakumar-moq-qmux-moqt/) drafts 00-01
59+
- [msf](https://datatracker.ietf.org/doc/draft-ietf-moq-msf/) drafts 00-01
60+
- [loc](https://datatracker.ietf.org/doc/draft-ietf-moq-loc/) draft 01
61+
62+
It takes forever to litigate every single addition/change in the IETF.
63+
I'm trying my best [to publish extensions](https://www.ietf.org/archive/id/draft-lcurley-moq-probe-00.html), but it's such a drain on my time.
64+
65+
So instead the moq.dev libraries **prefer to negotiate:**
66+
- moq-lite drafts 01-04
67+
- hang drafts 00-01
68+
69+
moq-lite-05 is coming SOON with more stuff.
70+
71+
72+
## Muxing
73+
My philosophy is that we should **not** transmit arbitrary media formats over MoQ.
74+
It's possible to [transmit TS over MoQ](https://www.ietf.org/archive/id/draft-gregoire-moq-msfts-00.html) verbatim, but then every player/subscriber needs to decode Transport Streams (gross).
75+
76+
Instead, [`moq-mux`](https://doc.moq.dev/lib/rs/crate/moq-mux.html) is our transmuxing layer.
77+
We can import/export other formats without re-encoding, preserving the intent but not the original structure.
78+
79+
[Here's the codecs we support](https://github.com/moq-dev/moq/tree/main/rs/moq-mux/src/codec):
80+
- H.264/H.265
81+
- AV1
82+
- VP8/VP9
83+
- Opus
84+
- AAC
85+
86+
[And the containers we support](https://github.com/moq-dev/moq/tree/main/rs/moq-mux/src/container):
87+
- fMP4/CMAF
88+
- FLV/RTMP
89+
- Matroska/WebM
90+
- HLS
91+
- LOC
92+
- TS
93+
94+
Going back to Transport Streams (gross) as an example.
95+
When you import a TS stream with `moq-mux`, we'll split A/V into MoQ tracks, but we'll also preserve "unknown" tracks with a special "ts" section.
96+
If you export the same stream to TS with `moq-mux`, we'll re-assemble the TS stream and reinsert the unknown tracks.
97+
98+
This is a **REALLY BIG DEAL** for broadcast TV.
99+
Your precious SCTE35 markers are preserved.
100+
ur welcome
101+
102+
## CLI
103+
Note that `moq-mux` is available as both a library and a CLI via [`moq-cli`](https://doc.moq.dev/bin/cli.html).
104+
105+
```bash
106+
# Publish: pipe in a MPEG-TS file
107+
ffmpeg -re -i input.ts -f mpegts - | \
108+
moq-cli publish --url https://cdn.moq.dev/anon --broadcast my-stream ts
109+
110+
# Subscribe: pull MPEG-TS back out and play it
111+
moq-cli subscribe --url https://cdn.moq.dev/anon --broadcast my-stream --format ts | \
112+
ffplay -
113+
```
114+
115+
You can download all of the moq binaries (`moq-relay`, `moq-token`, etc) from your favorite package manager:
116+
- Homebrew
117+
- .deb/.rpm
118+
- Docker
119+
- Nix
120+
- ???
121+
122+
Cool I guess?
123+
124+
125+
## JSON
126+
JSON isn't known for its efficiency.
127+
128+
[moq-json](https://github.com/moq-dev/moq/tree/main/rs/moq-json) (Rust) and [`@moq/json`](https://github.com/moq-dev/moq/tree/main/js/json) (Typescript) publish arbitrary JSON over MoQ tracks.
129+
The first frame in each group is a full snapshot, then subsequent frames are [JSON Merge Patch](https://datatracker.ietf.org/doc/html/rfc7396) deltas.
130+
We periodically make new groups so late joiners can catch up without having to download the entire stream.
131+
132+
We also stack [moq-flate](https://github.com/moq-dev/moq/tree/main/rs/moq-flate) (Rust) and [`@moq/flate`](https://github.com/moq-dev/moq/tree/main/js/flate) (Typescript) to add DEFLATE compression on top.
133+
Normally you would compress each frame individually, like a gzip file, but it turns out we can do significantly better by using `Z_SYNC_FLUSH`.
134+
Each subsequent frame *within the same group* can reuse the previous frames as a compression window, instead of starting from scratch.
135+
136+
Claude ran a benchmark over a synthetic stream of JSON sensor snapshots.
137+
The type of output you'd expect from a drone.
138+
139+
| Configuration | Bitrate saved |
140+
| ---------------------------------------- | ------------- |
141+
| DEFLATE per frame | 39% |
142+
| JSON Merge Patch | 58% |
143+
| JSON Merge Patch + DEFLATE per frame | 72% |
144+
| DEFLATE per group | 89% |
145+
| **JSON Merge Patch + DEFLATE per group** | **91%** |
146+
147+
I was surprised to see how important `Z_SYNC_FLUSH` is given it's not supported by the [browser implementation](https://developer.mozilla.org/en-US/docs/Web/API/Compression_Streams_API) and [is bugged](https://github.com/101arrowz/fflate/pull/286) in the most popular Javascript implementation.
148+
Really the main benefit of JSON Merge Patch is to save some CPU cycles.
149+
150+
## Backends
151+
We've used Quinn for the longest time, but now you can use other QUIC backends!
152+
Why? IDK different features and performance.
153+
154+
QUIC Backends (WebTransport + raw QUIC):
155+
- quinn
156+
- noq
157+
- quiche (Cloudflare)
158+
- iroh (p2p)
159+
160+
You can also use non-QUIC backends with Qmux!
161+
It emulates a QUIC connection, but over a reliable transport.
162+
We do suffer more from head-of-line blocking but sometimes it be like that.
163+
164+
Non-QUIC Backends (Qmux):
165+
- WebSocket
166+
- TLS
167+
- TCP
168+
- Unix domain sockets
169+
170+
For example, I'm using unix domain sockets (or TCP) to run localhost workers without paying the TLS/UDP overhead tax.
171+
It's still Media over QUIC even if QUIC is not used...
172+
173+
174+
## UI Polish
175+
Claude made the web UI look better.
176+
tfw an AI has better taste than me.
177+
178+
[Clone the repo](https://doc.moq.dev/setup/) and run `just dev` to see:
179+
180+
<figure>
181+
![bbb](/blog/update-00/bbb.png)
182+
<figcaption>he a sniffer</figcaption>
183+
</figure>
184+
185+
You can use the UI on your own site via the [web components](https://doc.moq.dev/bin/web.html):
186+
```html
187+
<script type="module">
188+
import "https://esm.sh/@moq/watch/element";
189+
import "https://esm.sh/@moq/publish/element";
190+
</script>
191+
192+
<moq-watch-ui>
193+
<moq-watch url="https://cdn.moq.dev/demo" name="bbb.hang">
194+
<canvas style="max-width: 100%; height: auto; margin: 0 auto; border-radius: 1rem;"></canvas>
195+
</moq-watch>
196+
</moq-watch-ui>
197+
```
198+
199+
There's also one for `<moq-publish>` which is equally slick.
200+
201+
## Polyglot (Alpha)
202+
We full [monorepo](https://github.com/moq-dev/moq) now.
203+
204+
`moq-ffi` uses Uniffi to generate async bindings for various languages.
205+
It's all the same Rust code under the hood, but IDK now you can use it on iOS/Android/whatever.
206+
207+
[MoQKit](https://fishjam.swmansion.com/blog/moq-boy-escaped-the-browser) uses it.
208+
neat
209+
210+
Supported:
211+
- [Swift](https://doc.moq.dev/lib/swift/)
212+
- [Kotlin](https://doc.moq.dev/lib/kt/)
213+
- [Python](https://doc.moq.dev/lib/py/)
214+
- [Go](https://doc.moq.dev/lib/go/) (wip)
215+
216+
I'm still working on more ergonomic bindings for each language, hence the (Alpha) tag.
217+
218+
Oh and don't worry, we still have [C support](https://doc.moq.dev/lib/c/) via [`libmoq`](https://doc.moq.dev/lib/rs/crate/libmoq.html).
219+
`moq-ffi` is for the async languages who don't want to deal with callbacks and APIs designed for dinosaurs.
220+
221+
222+
## Production Stuff
223+
I'm almost done spinning up a PAID MoQ CDN.
224+
It's like a week or two away, **GET HYPED**.
225+
226+
As part of that, I actually have to make sure everything is production-ready, which means focusing on the boring stuff like:
227+
- `mTLS`: relays can authorize via client certificates
228+
- `TLS`: cert reloading and custom root CAs
229+
230+
And more of the static configuration is now possible via a REST API.
231+
- `--auth-api`: authorize a user
232+
- `--cluster-connect-api`: discover neighboring relay nodes
233+
234+
And finally my favorite one, but it deserves its own blog post later:
235+
- `.stats`: deliver MoQ metrics over MoQ
236+
237+
## Conclusion
238+
I hope you enjoyed this low-energy update.
239+
Super low.
240+
241+
Written by [@kixelated](https://github.com/kixelated).
242+
![@kixelated](/blog/avatar.png)

0 commit comments

Comments
 (0)