published 10/8/2024
Fork
The IETF process is a long burn. I’ve flown out to 8 in-person meetings, attended at least 30 remote meetings, left hundreds of comments on issues/PRs, and even authored the original transport draft. I have spent so much of my limited time on this planet working on this endeavor.
Unfortunately, this is the end of my involvement. I think the MoQ working group will produce something in 3-5 years, but it’s not something that I plan to use. I’m going to focus on my own MoQ fork in the short-term, even if standardization is the “correct” long-term direction.
What Happened?
The core MoQ group consists of 5 people from Cisco and ~5 people from CDN companies. This dynamic has meant that 99% of the focus has been on layer that Cisco could use and CDNs could sell to them: MoqTransport.
Unfortunately, the media layer (the M in MoQ) has become an after-thought. There’s interest in standardizing something but nobody intends to implement it. So instead, the transport has become overly generic and worse: molded around Cisco’s proprietary stack. And they have some bizarre requirements.
A concrete example: sequential IDs.
Every sane internet transport over lossy networks use sequential IDs: TCP, RTP, QUIC, etc.
The idea is that receiver can detect gaps caused by loss by inspecting sequence numbers.
For example, after receiving packets 7 8 10
, a receiver knows that packet 9
is still in flight, eventually giving up if it takes too long.
However, the Cisco folks insist that sequence numbers are arbitrary application data that can have both implicit AND explicit gaps.
To borrow Javascript terminology: packet 9 could be marked as null
(exists but empty), undefined
(never existed), or pending
(still in flight).
This is a problem because a player and CDN can’t tell the difference between undefined
and pending
.
In the previous example, if the application just decided to skip 9
for the luls (undefined
), now every downstream (CDN and player) has to explicitly query “is there a hole in my buffer?” even when there is zero packet loss.
This may seem like a trivial transport detail, but it’s one of many infuriating debates that have lasted years and will never be resolved while the current WG dynamics exist. The worst part is that we still don’t know why this requirement exists despite constant probing, making it extra impossible to argue against or provide alternatives. There’s no need to compromise or debate when the working group is stacked.
The current protocol can only be described as obtuse. When a user asks how to use MoQ, I don’t have an answer except for: ”it depends”. The transport draft has become so abstracted and optional, with few reliable properties. It’s a Temo Swiss Army Knife; capable of doing everything badly instead of the one thing it should focus on: live media.
And to be clear, this isn’t Cisco’s fault. They have the right intentions and some of them are frankly brilliant (shoutout to Cullen, Mo, Christian). However, the power dynamics in the MoQ working group are broken until there are other stakeholders who actually care about media.
What Now?
I still love the idea of using QUIC to deliver media. Suddenly WebRTC is no longer a requirement when WebCodecs and WebTransport are combined. And I also love the concept behind MoqTransport: A generic transport for media-like applications, fixing many of the scaling issues with WebRTC.
To this end, I’ve created:
- 🍴MoqTransfork: A simple way to transport media-like content without a specific encoding. It should be implemented by generic servers, such as a CDN
- 🎏 Karp: A thin layer on top of 🍴MoqTransfork capable of mutliple quality/latency targets. It should be implemented by generic media clients, such as VLC and OBS. Final name TBD.
I swear there used to be fork emoji.
The demos on this site use both of course, but I still need to update a lot of documentation and fix any new bugs.
New Release
I’ve been working on this fork for a while now. I didn’t want to release it until there was a critical mass of reasons to hard fork, so it’s become a grab-bag of new features all getting merged at the same time.
- Experimental WASM player
- New clustering protocol (using MoqTransfork!)
- CMAF -> Karp transmuxing
- Broadcast discovery
- Simpler (but more powerful) API
And let’s not forget the existing features that have been migrated over:
- Rust library
- Typescript library (web)
- Gstreamer plugin
- ffmpeg integration
- Relay server
- GCP infrastructure
The combined Rust+JS changes currently clock in at +8,602 -16,457 lines (…including this blog post). I know line counts are a terrible metric, but it’s a testiment to how annoying MoqTransport is to both use and implement, especially considering we were using an old and half-implemented draft (version 4*).
And yes, this is a hard fork. If you want to stick with the IETF standard, that’s fine but you gotta hit the fork button too.
What’s Next?
I’m going to continue investing all of my free time (and hopefully some of my professional time) into MoQ. But the time that would have been spent arguing to be better spent actually implementing cool shit: the next step is a conferencing demo.
I would highly encourage that anyone else do the same. If you’re an individual, startup, or a massive company alike, I would recommend that you don’t block on the IETF. It’s a great organization, but standards are an intentionally slow process designed by committee and all of the baggage that entails.
I think MoQ needs to move faster. Use the tech that is available today (ex. WebTransport + WebCodecs) instead of a promised standard. You can always hit me up on Discord if you want to use MoQ and crave more advice. I can’t promise that it will be good advice though.