在实时音视频应用里,了解当前通话质量不能只靠用户主观反馈。WebRTC本身提供了一套标准的统计接口,同时也存在多种补充或替代的采集思路。理解这些方法的底层机制和适用边界,能帮我们在不同业务场景下做出合理的技术选型。

一、WebRTC原生统计接口getStats
WebRTC规范中的RTCPeerConnection对象带有一个名为getStats的方法,它是官方推荐的统计数据采集入口。调用该方法会返回一个Promise,解析后得到一个包含多个报告条目的Map结构,每个条目描述某个媒体流、轨道或候选地址的瞬时状态。
这些报告条目通过id相互关联,类型包括inbound-rtp、outbound-rtp、candidate-pair、remote-inbound-rtp等。比如inbound-rtp里能看到接收端的丢包数、抖动和码率,outbound-rtp则反映发送端的帧率与字节数。由于浏览器实现差异,部分字段名称在不同版本中并不完全一致,解析时最好做兼容处理。
const pc = new RTCPeerConnection();
// 假设已经完成了信令交换与媒体添加
async function collectStats() {
const stats = await pc.getStats();
stats.forEach(report => {
if (report.type === 'inbound-rtp' && report.kind === 'video') {
console.log('视频接收丢包:', report.packetsLost);
console.log('视频抖动:', report.jitter);
}
});
}
setInterval(collectStats, 1000);
上面这段代码每秒拉取一次统计并输出视频接收端的丢包与抖动。实际项目中通常不会直接打印,而是将数据格式化后上报到监控服务。使用getStats的优点是零额外依赖、数据最贴近真实传输层;缺点是高频调用会带来一定主线程开销,且原始结构啰嗦,需要自行封装。
另外,getStats是端上接口,如果用户终端是老旧WebView或非常规浏览器,可能存在支持不全的问题。因此在关键业务里,往往还要配合心跳或降级逻辑,避免统计模块本身成为稳定性隐患。
二、基于rtcstats的增强方案
rtcstats是一套开源的WebRTC统计收集思路,核心做法是在页面中注入一个拦截层,将getStats的返回以及部分内部事件持续发送到指定服务端。它相当于在原生接口外面包了一层管道,让统计数据脱离终端散点,集中成时序日志。
这种方案的价值在于排障。当线上用户反馈通话模糊时,工程师可以直接在后台按session id拉出完整统计曲线,而不需要用户配合抓包。rtcstats通常包含一个前端SDK和一个接收服务,前端SDK会定时调用getStats并把结果POST出去。
// 伪代码:rtcstats风格的上报封装
function startRtcStats(pc, uploadUrl) {
setInterval(async () => {
const report = await pc.getStats();
const payload = {};
report.forEach(item => { payload[item.id] = item; });
navigator.sendBeacon(uploadUrl, JSON.stringify(payload));
}, 2000);
}
相比裸用getStats,rtcstats类方案降低了排障门槛,也方便做跨用户对比。但它的本质是getStats的搬运工,并没有解决底层兼容性问题,而且引入上报逻辑后要注意控制频率,防止占用过多上行带宽。
三、服务端旁路采集替代思路
当终端环境过于复杂、无法保证getStats稳定工作时,可以从服务端媒体服务器入手。以Janus、Medooze这类SFU为例,它们自身维护着每条媒体流的处理状态,并能通过事件或内部接口暴露丢包、转发延迟等信息。
这种旁路采集不依赖终端浏览器,对于混合终端接入的场景尤其友好。比如在会议系统里,即便某位用户用的是被裁剪过的嵌入式浏览器,只要媒体走了服务端,就能拿到基础质量数据。代价是看不到纯端到端的最后一公里表现,且需要部署和维护媒体服务器。
| 方案 | 数据精度 | 端上开销 | 适用场景 |
|---|---|---|---|
| 原生getStats | 高(端到端) | 中 | 现代浏览器应用 |
| rtcstats封装 | 高(同原生) | 中偏高 | 需集中排障的Web项目 |
| 服务端旁路 | 中(服务端视角) | 低 | 异构终端、SFU架构 |
上表简单对比了三类思路。实际架构中它们并非互斥,不少团队会采用端上getStats加服务端校验的双轨方式,既保留细节又补足覆盖盲区。
四、自研轻量埋点作为补充
除了上述方案,还可以在应用层自行埋点。例如在每次negotiation成功、轨道静音、ICE重连时记录一次事件,再结合业务指标如通话时长、画面冻结次数,形成一套更贴近产品体验的统计。
这类数据虽然不属于WebRTC协议统计,但往往比底层丢包数更能说明用户感受。实现上只需在关键回调里调用已有上报通道,无需额外轮询,对性能影响很小。
pc.oniceconnectionstatechange = () => {
trackEvent('ice_state', pc.iceConnectionState);
};
function trackEvent(name, value) {
// 复用业务埋点接口,例如:
// navigator.sendBeacon('https://log.ipipp.com/report', JSON.stringify({name, value}));
}
自研埋点的最大优势是灵活,可以和告警规则直接绑定。不过它不能替代getStats的量化能力,更适合作为质量大盘里的体验维度补充。
五、选型与落地建议
如果产品只面向桌面现代浏览器,直接封装getStats并控制采集频率是最简洁的路径。若需要长期运营和线上追查,建议在getStats之上加一层rtcstats式上报,把数据落盘。
对于包含移动端WebView、小程序或老旧终端的场景,应尽早引入服务端媒体服务器的旁路统计,避免端上数据缺失导致质量黑盒。同时用轻量埋点覆盖业务体验,让技术统计和产品指标互相印证,才能构建出可信的实时音视频质量体系。
WebRTCgetStatsstats_monitoring修改时间:2026-08-02 08:21:31