# RtpTransportControllerSend · 发送侧的神经中枢

> Call 持有的发送侧总控——它把拥塞控制、pacer、包路由、反馈适配捆在一起，是所有发送流共享这套机制的地方。这一章读 rtp_transport_controller_send.h，讲清它怎么承接 Transport-CC 反馈、驱动 GoogCC、并把码率决策分发下去。

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

# RtpTransportControllerSend · 发送侧的神经中枢

[`Call` 持有](https://daiw.org/manual/webrtc/call-object)的 **`RtpTransportControllerSend`**（`call/rtp_transport_controller_send.cc`），是**发送侧的神经中枢**——它把[第 5 部分讲的拥塞控制机制](https://daiw.org/manual/webrtc/congestion-control-overview)整合到一起，让一次通话的**所有发送流共享**这一套。第 5 部分讲的是算法，这一章讲它们**怎么被组织、接线**。

## 它捆着拥塞控制的一切

看 `rtp_transport_controller_send.h` 的 include，它持有的部件一目了然：

```cpp
// call/rtp_transport_controller_send.h(节选 include)
#include "modules/congestion_controller/rtp/control_handler.h"
#include "modules/congestion_controller/rtp/transport_feedback_adapter.h"
#include "modules/congestion_controller/rtp/transport_feedback_demuxer.h"
#include "modules/pacing/packet_router.h"
```

<Callout type="info">
  **`RtpTransportControllerSend` 是发送侧拥塞控制的“总装车间”——它把这几个部件接线成一个工作系统：**

  - **[GoogCC 网络控制器](https://daiw.org/manual/webrtc/congestion-control-overview)** —— 估带宽、出[目标码率](https://daiw.org/manual/webrtc/rate-control)的大脑。
  - **[pacer(PacedSender)](https://daiw.org/manual/webrtc/pacing)** —— 按节奏平滑发包的执行者。
  - **`PacketRouter`** —— 把 pacer 放行的包，**路由到正确的流的[发送器](https://daiw.org/manual/webrtc/rtp-sender)**（一次通话[多条流](https://daiw.org/manual/webrtc/transceivers)，得知道每个包归哪条）。
  - **`TransportFeedbackAdapter`** —— 把[收到的 Transport-CC 反馈](https://daiw.org/manual/webrtc/transport-cc)（每个包的到达时间）**翻译成 GoogCC 能吃的输入**（哪些包发了、何时发的、何时到的）。

  于是一个完整的闭环在这里合拢：[反馈进来](https://daiw.org/manual/webrtc/transport-cc) → `TransportFeedbackAdapter` 翻译 → GoogCC [估带宽出码率](https://daiw.org/manual/webrtc/rate-control) → 设 pacer 速率 + 通知[码率分配](https://daiw.org/manual/webrtc/bitrate-allocator) → pacer 放行包 → `PacketRouter` 分发到各流发送。**`RtpTransportControllerSend` 就是这个[第 5 部分闭环](https://daiw.org/manual/webrtc/rate-control)的物理载体**——算法散落在 `modules/congestion_controller`，而把它们组装成运转系统的，是这个类。
</Callout>

## 为什么“共享”很重要

关键点：**一次通话只有一个 `RtpTransportControllerSend`**，所有[发送流共享它](https://daiw.org/manual/webrtc/call-object)：

<Callout type="info">
  **拥塞控制必须是“全局一套”，不能每条流各估各的——因为[所有流共用同一条网络路径](https://daiw.org/manual/webrtc/jsep-transport-controller)，竞争的是**同一份带宽**。** 想想：如果音频流、视频流各自跑一套拥塞控制、各估各的带宽，它们会**互相误判**——视频估出 2Mbps 就发 2Mbps，音频也估出 2Mbps 也发，加起来 4Mbps 压垮了只有 2Mbps 的链路，然后两者都以为“是对方害的”而混乱。

  正确做法是 `RtpTransportControllerSend` **对整条通话估一个总带宽**（所有流的[反馈汇总](https://daiw.org/manual/webrtc/transport-cc)进一个 GoogCC），再由 [`BitrateAllocator` 把这个总量分给各流](https://daiw.org/manual/webrtc/bitrate-allocator)。**“统一估总量、再分配”**——这是[多流共享带宽](https://daiw.org/manual/webrtc/video-bitrate-allocation)的正确姿势。所以 `RtpTransportControllerSend` 必须是通话级的单例，站在所有流之上。这也是它归 [`Call` 而非某条流](https://daiw.org/manual/webrtc/call-object)持有的原因。
</Callout>

## PacketRouter：分发的枢纽

`PacketRouter`（`modules/pacing/packet_router.h`）值得单提——它是发送侧的**分发枢纽**：[pacer](https://daiw.org/manual/webrtc/pacing) 决定“现在放行一个包”，`PacketRouter` 负责“这个包该从哪条流的[发送器](https://daiw.org/manual/webrtc/rtp-sender)发出”。反过来，它也参与把[RTCP 反馈](https://daiw.org/manual/webrtc/rtcp-feedback)路由回对应的流。它是“通话级的 pacer / 拥塞控制”和“每条流的 [RTP 模块](https://daiw.org/manual/webrtc/rtp-rtcp-module)”之间的**多路复用 / 解复用点**——呼应了整个 WebRTC “[多条流挤一条传输](https://daiw.org/manual/webrtc/jsep-transport-controller)”的主题，这里是发送侧的那个“挤”与“分”的节点。

## 小结与下一章

**`RtpTransportControllerSend`**（[`Call` 持有](https://daiw.org/manual/webrtc/call-object)）是发送侧神经中枢，把[第 5 部分的拥塞控制](https://daiw.org/manual/webrtc/congestion-control-overview)组装成运转系统：持有 **[GoogCC](https://daiw.org/manual/webrtc/congestion-control-overview)**（估码率）、**[pacer](https://daiw.org/manual/webrtc/pacing)**（平滑发包）、**`PacketRouter`**（包路由到各流[发送器](https://daiw.org/manual/webrtc/rtp-sender)）、**`TransportFeedbackAdapter`**（把[Transport-CC 反馈](https://daiw.org/manual/webrtc/transport-cc)翻译成 GoogCC 输入）——[闭环在此合拢](https://daiw.org/manual/webrtc/rate-control)。它必须是**通话级单例**：所有流[共用一条路、竞争同一份带宽](https://daiw.org/manual/webrtc/jsep-transport-controller)，须**统一估总量**再[分配](https://daiw.org/manual/webrtc/bitrate-allocator)，不能各估各的。

估出的总带宽，怎么分给各条流？下一章看码率分配器。👉 [BitrateAllocator](https://daiw.org/manual/webrtc/bitrate-allocator)。

## 参考资料

- [1] libwebrtc 源码.`call/rtp_transport_controller_send.h` / `.cc`、`modules/congestion_controller/rtp/transport_feedback_adapter.h`、`modules/pacing/packet_router.h`。
- [2] 关联[第 5 部分拥塞控制](https://daiw.org/manual/webrtc/congestion-control-overview)、[Transport-CC](https://daiw.org/manual/webrtc/transport-cc)。
- [3] libwebrtc 源码.`api/transport/network_control.h`。
