getStats 与 RTCStatsReport · 标准化的指标快照
getStats 返回的 RTCStatsReport 是一份 W3C 标准化的指标快照——一堆带 id/type/timestamp 的 RTCStats 字典。这一章读 stats/ 源码,讲清这个数据模型、几个最有用的标准 stats 类型(inbound/outbound-rtp、candidate-pair、transport),以及怎么用它们读出通话质量。
getStats 与 RTCStatsReport · 标准化的指标快照
上一章说 getStats 是“快照”。这一章看这份快照的结构——它不是随便一堆数字,而是一套 W3C 标准化的数据模型。理解它,你就能从任何 WebRTC 应用(甚至 chrome://webrtc-internals)读出通话质量。
RTCStatsReport:一份 id → 指标 的字典集合
getStats() 返回一个 RTCStatsReport。看它的接口(真实源码 stats/rtc_stats_report.h):
// stats/rtc_stats_report.h(节选,真实源码)
class RTCStatsReport final {
static scoped_refptr<RTCStatsReport> Create(Timestamp timestamp);
Timestamp timestamp() const; // 这份快照的时刻
void AddStats(std::unique_ptr<const RTCStats> stats);
const RTCStats* Get(const std::string& id) const; // 按 id 查
ConstIterator begin() const; // 可遍历所有 stats
std::string ToJson() const; // 导出 JSON
};RTCStatsReport 是“某一刻整通电话的所有指标”的集合——内部是一堆 RTCStats 对象,每个有唯一 id,可按 id 查、可遍历、可 ToJson 导出。它是引用计数的(scoped_refptr),带一个统一的 timestamp(整份快照的时刻)。 而每个 RTCStats 是一条“某个对象的指标记录”(真实源码 stats/rtc_stats.h):
class RTCStats {
const std::string& id() const; // 唯一标识,如 "RTCInboundRTPVideoStream_..."
Timestamp timestamp() const; // 这条记录的时刻
virtual const char* type() const; // 类型名,如 "inbound-rtp"
std::vector<Attribute> Attributes() const; // 这条记录的所有字段
};于是数据模型是两层:一份报告(RTCStatsReport)装着许多条记录(RTCStats),每条记录有 id/type/timestamp 和一组具体字段。这个结构W3C 标准化了——所有浏览器的 getStats() 都返回这个形状,字段名也标准,所以监控代码可跨浏览器复用。
几个最有用的标准类型
type() 决定这条记录讲的是“哪个对象”。源码 stats/rtcstats_objects.h 定义了全部标准类型(对应 W3C 规范),下面几个是排障时最常看的:
| type | 类(源码) | 讲什么 | 关键字段 |
|---|---|---|---|
inbound-rtp | RTCInboundRtpStreamStats | 收到的一路流 | packetsLost、jitter、framesDecoded、frameWidth/Height |
outbound-rtp | RTCOutboundRtpStreamStats | 发出的一路流 | bytesSent、framesEncoded、targetBitrate、qualityLimitationReason |
remote-inbound-rtp | RTCRemoteInboundRtpStreamStats | 对端收我的情况(经 RTCP) | roundTripTime、packetsLost、jitter |
candidate-pair | RTCIceCandidatePairStats | 选中的 ICE 路径 | currentRoundTripTime、availableOutgoingBitrate、state |
transport | RTCTransportStats | DTLS/传输层 | bytesSent/Received、dtlsState、selectedCandidatePairId |
codec | RTCCodecStats | 用了哪个编解码器 | mimeType、clockRate、payloadType |
这几个类型就能拼出一通电话的“体检报告”:
- 画质 / 音质怎么样 ——
inbound-rtp的framesDecoded、frameWidth/Height、jitter(解码帧率、分辨率、抖动)。 - 丢包多不多 ——
inbound-rtp.packetsLost/remote-inbound-rtp.packetsLost(收发两侧的丢包)。 - 延迟多大 ——
candidate-pair.currentRoundTripTime/remote-inbound-rtp.roundTripTime(RTT)。 - 带宽够不够 ——
outbound-rtp.targetBitrate(拥塞控制给的目标码率)、candidate-pair.availableOutgoingBitrate。 - 为什么画质被限 ——
outbound-rtp.qualityLimitationReason(cpu/bandwidth/none——是 CPU 顶不住还是带宽不够,直接告诉你)。 - 走的什么路径 ——
transport+candidate-pair看是 直连还是 TURN 中继、DTLS 是否连上。
这些字段名不是 WebRTC 私有的,而是 W3C 标准——你在 chrome://webrtc-internals 里看到的、在任何 WebRTC 监控 SaaS 里看到的,都是它们。读懂这张表,就读懂了绝大多数 WebRTC 质量监控。
stats 之间靠 id 互相引用
一个精妙处:各条 RTCStats 通过 id 互相引用,拼成一张关系图。例如 outbound-rtp 有个 codecId 字段,指向某条 codec 记录的 id;candidate-pair 有 localCandidateId/remoteCandidateId 指向 ICE candidate 记录;transport 有 selectedCandidatePairId。于是从“我发的这路视频”能顺着 id 查到“它用什么编解码器、走哪条 ICE 路径、经哪个 DTLS 传输”。RTCStatsReport::Get(id) 就是用来跟着这些引用跳转的。这张 id 关系图让快照不只是孤立数字,而是能还原“谁连着谁”的结构。
小结与下一章
getStats() 返回 RTCStatsReport——一份 W3C 标准化的指标快照:内部是许多条 RTCStats,每条有 id/type/timestamp 和一组标准字段,可按 id 查、遍历、ToJson。最有用的类型:inbound-rtp/outbound-rtp(收发流的帧率、丢包、目标码率、qualityLimitationReason)、remote-inbound-rtp(RTT)、candidate-pair(ICE 路径、RTT、可用带宽)、transport、codec。各条 stats 通过 id 互相引用成关系图。读懂这套,就读懂了 chrome://webrtc-internals 和大多数质量监控。
这些指标从各子系统怎么汇集成一份报告?下一章看收集机制。👉 统计的收集。
参考资料
- [1] libwebrtc 源码.
stats/rtc_stats_report.h、stats/rtc_stats.h、stats/rtcstats_objects.h(全部标准类型)。 - [2] W3C「Identifiers for WebRTC's Statistics API」(标准字段定义)。
- [3] 关联第 1 部分统计收集器、RTCP 报告。