# 速率统计 · RateStatistics 滑动窗口测速率

> 「当前码率是多少」这个问题在 WebRTC 里被问了无数次——pacer、带宽估计、统计报告都要。这一章读 rate_statistics.h，讲清 RateStatistics 这个滑动窗口速率估计器怎么工作，以及为什么「测速率」这么个小工具值得单独一个类。

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

# 速率统计 · RateStatistics 滑动窗口测速率

“现在发送码率多少？”“刚才收进来多少 kbps？”——这类问题在 WebRTC 里被问了无数次：[pacer 要知道自己发多快](https://daiw.org/manual/webrtc/pacing)、[带宽估计要测进出码率](https://daiw.org/manual/webrtc/delay-based-bwe)、[stats 要报告比特率](https://daiw.org/manual/webrtc/stats-collector)。测速率听着简单，做对却有讲究，WebRTC 为它专设了一个类：`RateStatistics`。这是第 10 部分的最后一个零件。

## “测速率”没那么简单

朴素做法：“总字节数 ÷ 总时间”。但这给的是**从头到now的平均**，对[实时系统毫无用处](https://daiw.org/manual/webrtc/rate-control)——我们要的是“**最近这一小段**的速率”（比如最近 1 秒），它才反映当前网络 / 编码的真实状态。

<Callout type="info">
  **实时系统要的是“**瞬时”速率**——最近一个**滑动窗口**（如 1 秒）内的速率，而不是从开始到现在的累计平均。窗口要随时间**滑动**：新数据进来、老数据（超出窗口的）淘汰。** 为什么必须是滑动窗口？

  - **反映当下** —— [码率一直在变](https://daiw.org/manual/webrtc/rate-control)（网络波动、[画面复杂度变化](https://daiw.org/manual/webrtc/video-bitrate-allocation)），只有“最近一段”的速率对[决策](https://daiw.org/manual/webrtc/delay-based-bwe)有意义。累计平均会被很久以前的数据拖累，反应迟钝。
  - **要平滑** —— 但也不能只看最后一个包（太抖）。窗口是“[既反映当下、又足够平滑](https://daiw.org/manual/webrtc/delay-based-bwe)”的折中，窗口越大越平滑但越迟钝，越小越灵敏但越抖。
  - **要高效** —— 每来一个包就重算整段太慢，得增量维护。

  `RateStatistics` 就是把这件“看似简单、细节不少”的事**做对、并封装成可复用的一个类**——[整个 WebRTC 凡是要测速率的地方都用它](https://daiw.org/manual/webrtc/pacing)，不必各自重造。
</Callout>

## RateStatistics 的接口

看它的接口（真实源码 `rate_statistics.h`），很直观：

```cpp
// rate_statistics.h(节选,真实源码)
class RateStatistics {
 public:
  // max_window_size_ms:窗口最大长度;scale:换算系数(如 8000 把 字节/ms 变 bps)
  RateStatistics(int64_t max_window_size_ms, float scale);

  void Update(int64_t count, int64_t now_ms);       // 在 now_ms 时刻,新增 count(如字节数)
  std::optional<int64_t> Rate(int64_t now_ms) const; // 取 now_ms 时刻的当前速率
  bool SetWindowSize(int64_t window_size_ms, int64_t now_ms);  // 动态调窗口
};
```

用法就三步：每来一批数据 `Update(字节数, 现在)`，想知道速率时 `Rate(现在)`，需要更灵敏 / 更平滑时 `SetWindowSize`。内部维护一个按时间排列的**桶**结构，`Update` 往当前时刻的桶加计数、`Rate` 把窗口内所有桶求和再除以窗口时长乘 `scale`，并**丢弃超出窗口的老桶**——滑动就是这么实现的。

<Callout type="info">
  **`scale` 参数是个贴心设计：它把“原始计数 / 毫秒”换算成你想要的单位。** 传 `count` 为字节数、要 bps 结果时，`scale = 8000`（× 8 变 bit、× 1000 因为 ms→s）。这样 `Rate()` 直接返回 bps，调用方不用自己换算——又一次[类型 / 单位上的体贴](https://daiw.org/manual/webrtc/units)。返回 `std::optional` 是因为**窗口内数据太少时速率无意义**（测不准），此时返回空，提示调用方“还没法给出可靠估计”。
</Callout>

## 它在系统里无处不在

`RateStatistics` 是那种“不起眼但到处都在”的基础件：

```mermaid
flowchart LR
    RS["RateStatistics(滑动窗口测速率)"] --> P["pacer:测实际发送码率"]
    RS --> BWE["带宽估计:测进出码率"]
    RS --> STAT["stats:报告 bitrate"]
    RS --> AUD["音频:测各种速率指标"]
```

- [pacer](https://daiw.org/manual/webrtc/pacing) 用它测“[我实际发出去多快](https://daiw.org/manual/webrtc/pacing)”，好对齐[目标码率](https://daiw.org/manual/webrtc/rate-control)。
- [带宽估计](https://daiw.org/manual/webrtc/delay-based-bwe)用它测“[接收 / 发送码率](https://daiw.org/manual/webrtc/transport-cc)”，作为[估计的输入](https://daiw.org/manual/webrtc/loss-based-bwe)。
- [统计模块](https://daiw.org/manual/webrtc/stats-collector)用它算[报告给应用的各种 bitrate](https://daiw.org/manual/webrtc/stats-collector)。

一个小类，服务了[码率传导链](https://daiw.org/manual/webrtc/rate-control)的多个环节。这正是 [`rtc_base` 的价值](https://daiw.org/manual/webrtc/rtc-base-overview)：把[反复出现的通用需求](https://daiw.org/manual/webrtc/rtc-base-overview)（“测最近一段的速率”）做对一次、到处复用。

## 小结与下一章

**`RateStatistics`**（`rate_statistics.h`）是 WebRTC 的**滑动窗口速率估计器**。它解决“测**瞬时**速率”这个[实时系统的高频需求](https://daiw.org/manual/webrtc/rate-control)：不是从头到now的累计平均，而是**最近一个窗口**内的速率，窗口随时间滑动（新数据进、[老数据淘汰](https://daiw.org/manual/webrtc/rate-statistics)）——在“反映当下”与“足够平滑”间折中。接口简单：`Update(count, now)` 加数据、`Rate(now)` 取速率、`SetWindowSize` 调灵敏度，`scale` 参数[自动换算单位](https://daiw.org/manual/webrtc/units)，数据太少时返回 `optional` 空值。它服务于 [pacer](https://daiw.org/manual/webrtc/pacing)、[BWE](https://daiw.org/manual/webrtc/delay-based-bwe)、[stats](https://daiw.org/manual/webrtc/stats-collector) 等多处——[通用件复用](https://daiw.org/manual/webrtc/rtc-base-overview)的典范。

第 10 部分的地基零件到此看完。下一章为这一部分收尾，并展望后面的观测与平台集成。👉 [第 10 部分回顾](https://daiw.org/manual/webrtc/rtc-base-recap)。

## 参考资料

- [1] libwebrtc 源码.`rtc_base/rate_statistics.h` / `.cc`（`Update`、`Rate`、`SetWindowSize`、`scale`）。
- [2] 关联[pacing](https://daiw.org/manual/webrtc/pacing)、[延迟带宽估计](https://daiw.org/manual/webrtc/delay-based-bwe)、[统计收集](https://daiw.org/manual/webrtc/stats-collector)。
- [3] libwebrtc 源码.`rtc_base/rate_tracker.h`（相关的速率跟踪工具）。
