统计的收集 · 跨线程汇集成一份报告
getStats 这一次调用看着简单,背后却要从多条线程上的多个子系统各取一部分指标、合并成一份报告,还要缓存以防频繁调用。这一章读 rtc_stats_collector.h,讲清 RTCStatsCollector 的异步收集、分线程产出、合并与缓存机制。
统计的收集 · 跨线程汇集成一份报告
上一章看了 RTCStatsReport 的结构。但这份报告从哪来?getStats() 看着是一次简单调用,背后却是一次跨多线程、从多个子系统取数、合并、缓存的复杂协作。这一章看 RTCStatsCollector 怎么干这活——它也把第 10 部分的线程模型照进了现实。
为什么收集是异步的
先看接口(真实源码 rtc_stats_collector.h):
// rtc_stats_collector.h(节选,真实源码)
class RTCStatsCollector {
// 注意:不是"返回报告",而是"传入回调,报告好了再回调你"
void GetStatsReport(scoped_refptr<RTCStatsCollectorCallback> callback);
// ... Produce*_s 系列:分别产出各类 stats
};GetStatsReport 是异步回调式的(传 callback、不同步返回),因为一份完整报告的数据散落在不同线程上**——必须去各条线程“取回属于它的那部分”,没法在调用线程当场凑齐。** 回想第 10 部分的铁律:每份数据归属某条线程,只能在那条线程访问。而一份 stats 报告要的数据偏偏来自三条线程:
- ICE candidate / candidate-pair / transport 指标 —— 归 network 线程。
- 收发流的编解码 / 帧率 / 码率指标 —— 归 worker 线程(
Call那边)。 - 数据通道 / PeerConnection 级信息 —— 归 signaling 线程。
于是收集必然是“分头去各线程取、再合并”的异步过程——这就是它回调式、而非同步返回的原因。API 的异步形状,是底层线程模型的直接后果(又一个“地基塑造上层”的例子)。
分线程产出、再合并
读源码会看到一系列 Produce*_s 方法(_s = signaling 线程那部分),各管一类 stats:
// rtc_stats_collector.h(节选,真实源码)
void ProduceCertificateStats_s(...); // 证书
void ProduceDataChannelStats_s(...); // 数据通道
void ProduceIceCandidateAndPairStats_s(...);// ICE 候选与路径
void ProduceMediaSourceStats_s(...); // 媒体源
void ProducePeerConnectionStats_s(...); // PC 级
void ProduceRTPStreamStats_s(...); // 收发 RTP 流
// ...以及在 network / worker 线程上收集的对应部分收集流程大致是:
各线程各自产出“自己那部分 stats”(在数据的归属线程上安全地读),再汇总成一份完整的 RTCStatsReport,最后回调给应用。这正是第 10 部分“数据归属线程 + PostTask 跨线程”的一次完整实战:不加锁,而是把收集任务派发到每份数据所在的线程。
缓存:防止频繁调用压垮系统
一个重要细节:报告会缓存一小段时间(真实源码注释 reports are cached for cache_lifetime_ ms):
和第 1 部分的 StatsCollector 呼应
第 1 部分介绍 PeerConnection 组件时,RTCStatsCollector 作为其中一员出过场——那时说它“负责 getStats”。这一章补齐了细节:它不是简单地读几个变量,而是一个跨线程的收集协调器,把散落三处的指标安全汇集成 W3C 标准报告。它是控制面组件,但要伸手到媒体面(worker)和网络面(network)取数——因此天然是异步的。
小结与下一章
getStats() 背后是 RTCStatsCollector 的一次跨线程收集:它异步回调式工作(GetStatsReport(callback)),因为报告数据散落在 network / worker / signaling 三线程,必须各去归属线程取回、再合并——一系列 Produce*_s 方法分头产出各类 stats,汇总成一份 RTCStatsReport。这是第 10 部分“数据归属线程 + PostTask”纪律的实战,也解释了 getStats 为何是异步 API。报告缓存 cache_lifetime_ 毫秒,避免频繁调用反复触发昂贵收集。
快照支柱看完了。下一章转向另一支柱——黑匣子 RtcEventLog。👉 RtcEventLog 事件日志。
参考资料
- [1] libwebrtc 源码.
pc/rtc_stats_collector.h/.cc(GetStatsReport、Produce*_s、缓存)。 - [2] 关联第 1 部分统计收集器、第 10 部分线程模型、RTCStatsReport。
- [3] W3C getStats 标准。