# RtpDemuxer 与接收侧分流 · 一条流上的包各归各家

> BUNDLE 把多条流挤进一条传输，收到一个 RTP 包，怎么知道它属于哪条接收流？这就是 RtpDemuxer 的活。这一章讲清接收侧怎么按 SSRC、mid、payload type 把包分流到正确的接收器，以及帧变换钩子在接收管线的位置。收尾第 4 部分。

- 作者：David（道雾轩）
- 专栏：音视频与 WebRTC 详解（https://daiw.org/manual/webrtc.md）
- 最后更新：2026-07-14
- 原文：https://daiw.org/manual/webrtc/rtp-demuxer
- 转载与引用：请注明出处并附原文链接（https://daiw.org/about/copyright）

# RtpDemuxer 与接收侧分流 · 一条流上的包各归各家

第 4 部分前面都在讲**发送**和**反馈**。收尾这章看**接收侧**的第一道关：[BUNDLE](https://daiw.org/manual/webrtc/jsep-transport-controller) 把多条流（你的音频、视频、对方的……）全挤进[一条传输](https://daiw.org/manual/webrtc/jsep-transport-controller)，那收到一个 [RTP 包](https://daiw.org/manual/webrtc/rtp-packet)，怎么知道它该交给哪条接收流处理？这就是**分流（demux）** 的活，由 **`RtpDemuxer`** 负责。

## 问题：一条路，多条流

[SRTP 解密](https://daiw.org/manual/webrtc/srtp-encryption)后，一个 RTP 包到了接收侧。但 [BUNDLE](https://daiw.org/manual/webrtc/jsep-transport-controller) 下，这条传输上跑着好几条逻辑流，每条对应一个 [`RtpReceiver` / 接收流](https://daiw.org/manual/webrtc/transceivers)。包得**准确送到它所属的那条**——送错了，音频包喂给视频解码器，就乱套了。`RtpDemuxer`（`modules/rtp_rtcp/source/rtp_demuxer.h` 一类）就是这个「分拣员」。

## 靠什么分：SSRC、mid、payload type

<Callout type="info">
  **`RtpDemuxer` 按包里的标识，把它路由到注册好的接收器（sink）。主要的分流依据有三个：**

  - **[SSRC](https://daiw.org/manual/webrtc/rtp-packet)** —— 最直接：每条流一个唯一 SSRC，按 SSRC 对号入座。但有个时序难题：有时**包比[信令](https://daiw.org/manual/webrtc/call-lifecycle)先到**——你还没从 [SDP](https://daiw.org/manual/webrtc/sdp-and-jsep) 得知「SSRC=X 属于哪条流」，包就来了。
  - **[mid 头扩展](https://daiw.org/manual/webrtc/rtp-header-extensions)** —— 救上面的场：包里直接带着 [mid](https://daiw.org/manual/webrtc/transceivers)（属于哪条 [m-line](https://daiw.org/manual/webrtc/transceivers)），不必等信令告知 SSRC 归属，**收到就能分流**。这正是 [mid 头扩展存在的意义](https://daiw.org/manual/webrtc/rtp-header-extensions)。
  - **[payload type](https://daiw.org/manual/webrtc/payload-types)** —— 辅助依据（某些场景下用 PT 帮助判断）。

  `RtpDemuxer` 综合这些，把每个包送给对的 sink（`RtpPacketSinkInterface`）。上层的 `RtpStreamReceiverController` 负责登记「哪个 SSRC/mid 对应哪个 sink」——[协商](https://daiw.org/manual/webrtc/offer-answer-handler)出一条新接收流，就注册一个 sink；流没了就注销。**分流的规则，是协商结果在接收侧的落地。**
</Callout>

## 分流之后：接收流水线

包被分到正确的接收器后，它进入这条流的**接收流水线**（具体见[第 6/7 部分](https://daiw.org/manual/webrtc/source-map)）：

```mermaid
flowchart TD
    NET["ICE 收包"] --> SRTP["SRTP 解密(第 3 部分)"]
    SRTP --> DEMUX["RtpDemuxer:按 SSRC/mid 分流"]
    DEMUX --> R1["接收流 A(视频)→ 抖动缓冲 → 组帧 → 解码"]
    DEMUX --> R2["接收流 B(音频)→ NetEq → 解码"]
    DEMUX --> RTCP["RTCP 包 → 各流的 RtcpReceiver(第 4 部分)"]
```

分流是接收侧的**第一个岔路口**：媒体包各归各的[视频](https://daiw.org/manual/webrtc/source-map) / [音频管线](https://daiw.org/manual/webrtc/source-map)，[RTCP 反馈包](https://daiw.org/manual/webrtc/rtcp-feedback)则回到各流的 [`RtcpReceiver`](https://daiw.org/manual/webrtc/rtp-rtcp-module) 去驱动[重传](https://daiw.org/manual/webrtc/nack-rtx) / [码率](https://daiw.org/manual/webrtc/source-map)决策。

## 接收侧的帧变换钩子

顺带交代一个[前面 SFrame 那章](https://daiw.org/manual/webrtc/sframe)提过的钩子。接收管线上，「解包后、解码前」有一个可插拔的位置——**帧变换器（frame transformer）**，对应 [`FrameTransformerInterface`](https://daiw.org/manual/webrtc/sframe) / 接收侧的 [`FrameDecryptorInterface`](https://daiw.org/manual/webrtc/sframe)。浏览器的 **Insertable Streams(Encoded Transform)** API 就在这里暴露：应用能拿到「刚组好、还没解码的帧」，做自定义处理——最典型的就是 [SFrame 端到端解密](https://daiw.org/manual/webrtc/sframe)。它和发送侧的 [`FrameEncryptor`](https://daiw.org/manual/webrtc/sframe) 对称，一个在编码后加密、一个在解码前解密，把[端到端加密](https://daiw.org/manual/webrtc/sframe)干净地嵌进收发管线。

## 小结与第 4 部分完整回顾

**`RtpDemuxer`** 是接收侧的分拣员：[BUNDLE](https://daiw.org/manual/webrtc/jsep-transport-controller) 下一条传输多条流，它按 **[SSRC](https://daiw.org/manual/webrtc/rtp-packet) / [mid 头扩展](https://daiw.org/manual/webrtc/rtp-header-extensions) / [PT](https://daiw.org/manual/webrtc/payload-types)** 把每个包路由到正确的接收器（sink），规则由 `RtpStreamReceiverController` 按[协商结果](https://daiw.org/manual/webrtc/offer-answer-handler)登记。分流后媒体各入[视频 / 音频管线](https://daiw.org/manual/webrtc/source-map)、RTCP 各回 [`RtcpReceiver`](https://daiw.org/manual/webrtc/rtp-rtcp-module)。接收管线上还有**帧变换钩子**（[Insertable Streams](https://daiw.org/manual/webrtc/sframe)），供 [SFrame 解密](https://daiw.org/manual/webrtc/sframe)等。

至此，**第 4 部分「RTP/RTCP」全部讲完**——从[包结构](https://daiw.org/manual/webrtc/rtp-packet)到发送、反馈、可靠性（[NACK](https://daiw.org/manual/webrtc/nack-rtx)/[FEC](https://daiw.org/manual/webrtc/fec)）、[带宽反馈](https://daiw.org/manual/webrtc/transport-cc)、再到接收分流，媒体在安全通道上的**传输机制**已经完整。但一个核心问题只开了头：**到底该发多快？** [Transport-CC](https://daiw.org/manual/webrtc/transport-cc) 给了信号，而消费这个信号、算出目标码率、平滑发包的，是**拥塞控制**。第 5 部分进入 `modules/congestion_controller/`。👉 第 5 部分即将展开。

## 参考资料

- [1] libwebrtc 源码.`modules/rtp_rtcp/source/rtp_demuxer.h`、`call/rtp_stream_receiver_controller.h`、`api/rtp_packet_sink_interface.h`。
- [2] libwebrtc 源码.`api/frame_transformer_interface.h`（帧变换钩子）。
- [3] IETF RFC 8843「BUNDLE」；W3C「WebRTC Encoded Transform」。
