0x00 Context
QUIC 协议作为 HTTP/3 的底层协议已经得到了广泛的支持。其在现代网络中的表现明显优于 TCP 已经是行业共识。基于 QUIC 进行媒体转发也逐渐被各 CDN 厂商接受,IETF 成立了 moq-wg 小组,旨在定义基于 QUIC 进行媒体转发的标准协议。
0x01 Intro
Media Over QUIC Transport (MOQT) 是针对 QUIC 协议进行优化的协议,可直接通过 QUIC 或 WebTransport 进行媒体传播。MOQT 利用 发布/订阅 工作流程,其中媒体生产者发布数据以响应来自多个端点的订阅请求。MOQT 支持具有不同弹性和延迟(实时、交互式)需求的广泛用例,而不会影响与内容交付网络相关的可扩展性和成本效益。
MOQT 是一种通用协议,旨在与多种 MoQ 流格式配合使用。这些 MoQ 流格式定义了内容如何编码、打包和映射到 MOQT 对象,以及发现和订阅的策略。
1.1. 动机
MOQT 的开发是由多个领域的目标驱动的,特别是延迟、QUIC 的稳定性、工作流程效率和中继支持。
- 延迟:HTTP Adaptive Streaming (HAS) 已成功实现规模化,但通常会以延迟为代价。延迟对于纠正可变的网络吞吐量是必要的。理想情况下,直播内容的消费比特率与其生成时的比特率相同。端到端延迟将是固定的,并且仅受编码和传输延迟的影响。不幸的是,网络的吞吐量是可变的,这主要是由于拥塞。尝试以高于网络支持的比特率传输编码的内容会导致从生产者到消费者的路径上出现排队。协议检测和响应队列的速度决定了总体延迟。基于 TCP 的协议很简单,但检测拥塞速度很慢,并且会受到队头阻塞的影响。直接利用 UDP 的协议可以避免排队,但应用程序则负责分段、拥塞控制、重传、接收器反馈、重组等复杂性。MOQT 的目标之一是实现这两个领域的最佳效果:利用 QUIC 的功能创建一种简单而灵活的低延迟协议,可以快速检测和响应拥塞。
- 基于 QUIC:QUIC 流的并行特性可以在面对丢失时提供改进。MOQT 的目标是设计一种流协议,以利用并行 QUIC 流提供的传输优势以及灵活的丢失恢复选项。通过 HTTP/3 将 QUIC 应用到 HAS 尚未产生吞吐量的普遍改进。造成这种情况的原因之一是,沿单个 QUIC 流发送段仍然会导致发生队头阻塞。
- 普遍性:当前互联网传送的媒体具有针对摄取进行优化的协议以及针对分发进行优化的单独协议。分发链中的这种协议转换需要重新打包媒体内容的中间源。虽然专业化有其好处,但不必重新打包内容也能提高效率。MOQT 的一个目标是开发一个可用于从贡献到分发的传输的单一协议。一个相关的目标是能够支持现有的编码和打包模式,以实现向后兼容性以及与已建立的内容准备生态系统的互操作性。
- 中继:协议成功的一个不可或缺的特征是其大规模传输媒体的能力。当可以利用独立于发布者和订阅者的第三方网络来转发内容时,可以实现最大的规模。这些中继必须缓存内容以提高分发效率,同时路由内容并确定性地响应多租户网络中的拥塞。MOQT 的目标是将中继视为协议的一等公民,并确保对象的结构使得分发所需的信息可供中继使用,同时媒体内容本身保持不透明和私密。
1.2 对象模型
MOQT 具有数据的分层对象模型,由 Object / Group / Track 组成。
- Object:Object 是 MOQT 的基本数据单元。Object 由两部分组成:元数据和有效负载,元数据包含了 Object 的序列信息、索引信息等;中继不会对 Object 得有效负载进行 组合/拆分/修改;
- Group:Group 介于 Track 和 Object 之间,一组 Object 被称为 Group,类似于视频中 GOP 和音频中 Page 的概念,主要作为订阅 Track 时的索引单位。
- Track:Track 是由 Group 组成的序列。Track namespace 和 Track name 共同组成了 Track 的唯一索引方式。
1.3 会话模型
- 会话建立:可以通过 QUIC 或者 WebTransport 直接建立会话连接。如果使用 QUIC 或 WebTransport over HTTP/3 则必须支持 QUIC-DATAGRAM 能力。同时 MOQT 中虽然没有定义其他的传输协议用于传输,但是推荐在应用层考虑提供 fallback 协议用于备选。
- 定义了 MOQT 的 URI 表示:
moq-URI = "moqt" "://" authority path-abempty [ "?" query ]
- 定义了 ALPN:
moq-00
- 定义了 MOQT 的 URI 表示:
- 会话协商:通过
CLIENT_SETUP
和SERVER_SETUP
完成版本和拓展的协商,类似于 QUIC 复用 TLS 中的 CLIENT_HELLO/SERVER_HELLO 机制。 - 会话初始化:由发起连接的客户端发起双向控制流用于交换协商信息,并在交换协商信息后传输控制信息,控制信息不得在其他 Stream 中传输。
- 会话终止:通过底层协议终止会话,QUIC 中使用
CONNECTION_CLOSE
WebTransport 中使用CLOSE_WEBTRANSPORT_SESSION
,并定义了会话终止时的 error message。 - 会话迁移:MOQT 通过
GOAWAY
控制消息中携带迁移信息的方式来实现会话迁移,来避免服务关闭或重启导致的会话终止问题。
1.4 传输优先级和拥塞响应
TODO.
1.5 中继模式
- Subscriber Interactions:订阅者通过
SUBSCRIBE
控制消息进行订阅; - Publisher Interactions:发布者通过
ANNOUNCE
控制信息进行发布; - Congestion Response: TODO.
- Relay Object Handling:
- 不得对转发的 Object 有效负载进行修改/合并/拆分;
- 出于延迟考虑,允许转发未接收完整的 Object;
- 出于延迟考虑,允许乱序转发 Object;
1.6 消息类型
ID | Messages |
---|---|
0x0 | OBJECT_STREAM |
0x1 | OBJECT_DATAGRAM |
0x3 | SUBSCRIBE |
0x4 | SUBSCRIBE_OK |
0x5 | SUBSCRIBE_ERROR |
0x6 | ANNOUNCE |
0x7 | ANNOUNCE_OK |
0x8 | ANNOUNCE_ERROR |
0x9 | UNANNOUNCE |
0xA | UNSUBSCRIBE |
0xB | SUBSCRIBE_DONE |
0xC | ANNOUNCE_CANCEL |
0x10 | GOAWAY |
0x40 | CLIENT_SETUP |
0x41 | SERVER_SETUP |
0x50 | STREAM_HEADER_TRACK |
0x51 | STREAM_HEADER_GROUP |
0x02 Comment
- 协议有待完善。拥塞响应部分为 TODO 状态。通过 issues 可以看出,MOQT 还有一些细节需要详细定义或改进。
- 生态有待完善。除了作为服务端的 CDN 厂商广泛支持外, FFmpeg/Gstreamer/OBS 等推拉流工具的支持也尤为关键。
0x03 Awesome
Project Name | Link | Language |
---|---|---|
quiche | https://github.com/google/quiche/tree/main/quiche/quic/moqt | C++ |
moqtransport | https://github.com/mengelbart/moqtransport | Golang |
moq-rs | https://github.com/kixelated/moq-rs | Rust |
0x04 Version Difference
01. draft-00 >> draft-01
- TODO
01. draft-01 >> draft-02
- TODO
02. draft-02 >> draft-03
SUBSCRIBE_OK
中增加 Largest Group 和 Object ID 信息;- 取消 DATAGRAME_PREFERRED;
SUBSCRIBE_FIN
和SUBSCRIBE_RST
信令合并入SUBSCRIBE_DONE
;SUBSCRIBE_DONE
中允许 Final Group/Object 为空;- 增加
ANNOUNCE_CANCEL