# BitrateAllocator · 总带宽分给各条流

> 拥塞控制估出一个总带宽，BitrateAllocator 把它分给各条发送流——音频优先保住，视频拿剩下的。这一章读 call/bitrate_allocator.h：流作为 observer 注册、带 min/max 约束，分配器如何在总量变化时重新分配。

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

# BitrateAllocator · 总带宽分给各条流

[`RtpTransportControllerSend` 估出了一个通话的总带宽](https://daiw.org/manual/webrtc/rtp-transport-controller-send)，但一次通话有[多条发送流](https://daiw.org/manual/webrtc/transceivers)（音频、视频、[联播多档](https://daiw.org/manual/webrtc/simulcast-svc)）。这个总量**怎么分给它们**？是 **`BitrateAllocator`**（`call/bitrate_allocator.cc`）的活。[视频码率分配那章](https://daiw.org/manual/webrtc/video-bitrate-allocation)讲了“流内分层”，这一章讲更上一级——“**流间分配**”。

## 流注册为 observer

`BitrateAllocator` 用观察者模式工作（`call/bitrate_allocator.h`）：

```cpp
// call/bitrate_allocator.h(节选)
class BitrateAllocatorObserver {
  // 分配变化时被回调:OnBitrateUpdated(分到的码率, ...)
};
struct MediaStreamAllocationConfig {
  // 这条流的约束:min_bitrate, max_bitrate, priority, 能否被暂停...
};
void AddObserver(BitrateAllocatorObserver* observer, MediaStreamAllocationConfig config);
```

<Callout type="info">
  **每条发送流把自己注册为 `BitrateAllocator` 的 observer，并声明约束（`MediaStreamAllocationConfig`：最小 / 最大码率、优先级）；分配器据[总带宽](https://daiw.org/manual/webrtc/rtp-transport-controller-send)和这些约束，给每条流分一份，通过回调 `OnBitrateUpdated` 通知它。** 流拿到分配后，就[通过 `SetRates` 告诉编码器“编到这个码率”](https://daiw.org/manual/webrtc/video-encoder-abstraction)。约束的意义：

  - **`min_bitrate`** —— 这条流**至少**要这么多才有意义（低于就没法编 / 干脆暂停）。
  - **`max_bitrate`** —— 这条流**最多**用这么多（再多也没用，如视频分辨率上限）。
  - **优先级** —— 分配时谁先吃饱。

  于是分配是一个“**带约束的分配问题**”：总量有限，每条流有 min/max/优先级，分配器要合理地切这块蛋糕。这和[视频流内的层分配](https://daiw.org/manual/webrtc/video-bitrate-allocation)是嵌套的两级——`BitrateAllocator` 先在**流间**分（音频 vs 视频），视频流拿到份额后，[`VideoBitrateAllocator` 再在层间分](https://daiw.org/manual/webrtc/video-bitrate-allocation)。
</Callout>

## 音频优先：核心原则

分配的核心原则，[视频码率分配那章](https://daiw.org/manual/webrtc/video-bitrate-allocation)已强调过，这里落到实处：

<Callout type="info">
  **`BitrateAllocator` **先喂饱音频**（音频的 [min_bitrate](https://daiw.org/manual/webrtc/bitrate-allocator) 优先满足），剩下的才给视频——因为[声音比画面重要](https://daiw.org/manual/webrtc/video-bitrate-allocation)。** 音频码率需求低（[几十 kbps 的 Opus](https://daiw.org/manual/webrtc/audio-codecs)就够），所以“死保音频”代价很小，却保住了通话最关键的部分。带宽极度紧张时：先满足音频的 min → 剩下的给视频（可能[视频降到很低甚至暂停某些档](https://daiw.org/manual/webrtc/video-bitrate-allocation)）。带宽宽裕时：音频吃饱后，富余的[大头给视频](https://daiw.org/manual/webrtc/video-bitrate-allocation)提画质。这个“保听觉、让视觉”的排序，是[WebRTC 资源分配的价值观](https://daiw.org/manual/webrtc/video-bitrate-allocation)，在 `BitrateAllocator` 这里是硬编码的分配逻辑。
</Callout>

## 动态：总量一变就重分

分配不是一次性的——它**随[总带宽](https://daiw.org/manual/webrtc/rtp-transport-controller-send)实时变**：

- [拥塞控制](https://daiw.org/manual/webrtc/rate-control)估出的总带宽变了（[网络好转 / 恶化](https://daiw.org/manual/webrtc/delay-based-bwe)），`BitrateAllocator` 就**重新分配**，通过 `OnBitrateUpdated` 通知各流新的份额。
- 流的增减（[协商加了 / 撤了一路媒体](https://daiw.org/manual/webrtc/offer-answer-handler)），也触发重分。

于是完整的码率传导链是：[Transport-CC 反馈](https://daiw.org/manual/webrtc/transport-cc) → [GoogCC 估总带宽](https://daiw.org/manual/webrtc/congestion-control-overview) → **`BitrateAllocator` 分到各流** → 各流 [`SetRates` 到编码器](https://daiw.org/manual/webrtc/video-encoder-abstraction) → [编码器调画质](https://daiw.org/manual/webrtc/rate-control)。`BitrateAllocator` 是这条链上“**总量 → 每流**”的关键一环。

```mermaid
flowchart TD
    CC["RtpTransportControllerSend:GoogCC 估出总带宽"] --> BA["BitrateAllocator"]
    BA -->|"先喂饱(min)"| AUD["音频流(优先)"]
    BA -->|"剩下给"| VID["视频流"]
    VID --> VBA["VideoBitrateAllocator:再分到各层(第 6 部分)"]
    AUD -->|"SetRates"| AENC["Opus 编码器"]
    VBA -->|"SetRates"| VENC["视频编码器"]
```

## 小结与下一章

**`BitrateAllocator`** 把[通话总带宽](https://daiw.org/manual/webrtc/rtp-transport-controller-send)分给各**发送流**（比[视频流内层分配](https://daiw.org/manual/webrtc/video-bitrate-allocation)高一级）。流注册为 **observer** 并声明 **`MediaStreamAllocationConfig`**（min/max 码率、优先级），分配器据总量和约束分份、`OnBitrateUpdated` 通知。核心原则**音频优先**（先喂饱音频 min，剩下给视频——[声音比画面重要](https://daiw.org/manual/webrtc/video-bitrate-allocation)，音频需求低故代价小）。分配**随总带宽动态重分**。它是“[总量 → 每流](https://daiw.org/manual/webrtc/rate-control)”传导的关键一环。

流的编解码，靠**媒体引擎**把[编解码器](https://daiw.org/manual/webrtc/video-encoder-abstraction)接进来。下一章看 `WebRtcVoiceEngine` / `WebRtcVideoEngine`。👉 [媒体引擎](https://daiw.org/manual/webrtc/media-engine)。

## 参考资料

- [1] libwebrtc 源码.`call/bitrate_allocator.h` / `.cc`（`BitrateAllocatorObserver`、`MediaStreamAllocationConfig`、`AddObserver`）。
- [2] 关联[视频码率分配](https://daiw.org/manual/webrtc/video-bitrate-allocation)（嵌套的流内分配）、[拥塞控制码率](https://daiw.org/manual/webrtc/rate-control)。
- [3] libwebrtc 源码.`call/rtp_transport_controller_send.cc`（驱动分配）。
