14、WebRTC的统计与监控:getStats API、关键统计指标解析、网络质量监控实践
做WebRTC开发,最怕什么?
我最怕用户说「卡了」,然后我两眼一抹黑,啥数据都没有。
你想想看,音视频通话出了问题,没有统计数据,你连问题出在哪都不知道。是网络丢包?是编码器挂了?还是对端接收能力不行?
这一章,我们就来聊聊WebRTC的统计与监控。说白了,就是怎么给通话过程装上「仪表盘」,让你能实时看到网络状态、媒体质量、传输延迟这些关键指标。
14.1 getStats API:你的数据探针
WebRTC内置了一套非常强大的统计接口——getStats()。我个人习惯叫它「数据探针」,因为它能深入到PeerConnection的各个角落,把底层数据捞出来。
用法其实很简单:
const pc = new RTCPeerConnection(configuration);
// 获取所有统计信息
const stats = await pc.getStats();
stats.forEach(report => {
console.log(report.type, report);
});
嗯,这里要注意:getStats()返回的是一个Map结构,每个条目是一个RTCStatsReport对象。每个对象都有一个type字段,标识这条数据是什么类型。
核心类型一览:
inbound-rtp— 接收端的RTP流统计outbound-rtp— 发送端的RTP流统计candidate-pair— ICE候选对的连接质量local-candidate/remote-candidate— 本地/远端候选地址track— 媒体轨道的统计transport— 传输层的统计
我在项目中遇到过一个问题:有同事只调了一次getStats(),然后拿数据去分析,发现丢包率是0%。他以为网络很好,结果用户一直在骂。为什么?因为getStats()是瞬时快照,你得持续采样才能看到真实情况。
我的建议:用setInterval每1~2秒调一次getStats(),把数据存下来做时间序列分析。这样你才能看到趋势,而不是孤立的点。
14.2 关键统计指标解析
数据捞出来了,怎么看?我挑几个最常用的指标,一个一个说。
14.2.1 丢包率(Packet Loss)
这是最直观的指标。丢包率高了,视频就会花屏、卡顿。
从inbound-rtp里拿:
const inboundStats = stats.get(reportId);
const packetsLost = inboundStats.packetsLost;
const packetsReceived = inboundStats.packetsReceived;
const totalPackets = packetsLost + packetsReceived;
const lossRate = totalPackets > 0 ? packetsLost / totalPackets : 0;
丢包率超过5%,用户基本就能感知到卡顿了。超过10%,通话质量会严重下降。
注意:丢包率是累计值。如果你只取一次快照,看到的是从通话开始到现在的总丢包率。要算「瞬时丢包率」,你得取两次快照做差值。
14.2.2 往返时延(RTT)
RTT就是数据从你到对端再回来的时间。它直接影响通话的实时性。
从candidate-pair里拿:
const pairStats = stats.get(pairId);
const rtt = pairStats.currentRoundTripTime; // 单位:秒
RTT在100ms以内,体验很好。超过300ms,对话就会开始有延迟感。超过500ms,基本没法正常交流了。
我记得有一次线上问题,用户说「我说完话对方要等两秒才回应」。我一看RTT数据,好家伙,800ms。后来发现是用户连了一个跨洋的VPN,绕路了。
14.2.3 抖动(Jitter)
抖动是网络延迟的变化程度。抖动大,音频会变声,视频会一跳一跳的。
从inbound-rtp里拿:
const jitter = inboundStats.jitter; // 单位:秒
抖动超过30ms,用户就能感觉到音频不自然了。超过50ms,基本就需要做抖动缓冲了。
14.2.4 带宽估计(Available Bandwidth)
WebRTC内部有一个带宽估计器,它会根据网络状况动态调整码率。这个值可以从candidate-pair的availableOutgoingBitrate拿到。
带宽估计低了,视频会自动降分辨率。带宽估计高了,视频会变清晰。如果你发现用户视频一直模糊,先看看这个值是不是被压得太低了。
14.3 网络质量监控实践
理论说完了,我们来点实战的。我一般会在项目中搭一个简单的监控面板,实时展示这些指标。
14.3.1 采样与上报
前端每2秒采样一次,把关键指标打包上报到后端:
function sampleStats(pc) {
return pc.getStats().then(stats => {
const report = {
timestamp: Date.now(),
lossRate: 0,
rtt: 0,
jitter: 0,
bitrate: 0
};
stats.forEach(stat => {
if (stat.type === 'inbound-rtp' && stat.kind === 'video') {
const total = stat.packetsLost + stat.packetsReceived;
report.lossRate = total > 0 ? stat.packetsLost / total : 0;
report.jitter = stat.jitter;
}
if (stat.type === 'candidate-pair' && stat.nominated) {
report.rtt = stat.currentRoundTripTime;
report.bitrate = stat.availableOutgoingBitrate || 0;
}
});
return report;
});
}
// 每2秒采样一次
setInterval(async () => {
const data = await sampleStats(pc);
// 上报到后端或展示在面板上
console.log(data);
}, 2000);
14.3.2 阈值告警
光采样还不够,你得知道什么时候该报警。我一般设这么几个阈值:
| 指标 | 警告阈值 | 严重阈值 | 建议动作 |
|---|---|---|---|
| 丢包率 | > 3% | > 8% | 降低码率 / 切换线路 |
| RTT | > 200ms | > 400ms | 检查路由 / 更换节点 |
| 抖动 | > 20ms | > 40ms | 增大抖动缓冲 |
| 带宽 | < 500kbps | < 200kbps | 降分辨率 / 关视频 |
避坑指南:我曾经在告警逻辑里写死了阈值,结果用户反馈说「我网络挺好的,你们老报警」。后来发现不同场景阈值应该不一样——视频会议和直播的容忍度完全不同。建议把阈值做成可配置的。
14.3.3 可视化展示
数据有了,怎么展示?我习惯用折线图展示趋势,用仪表盘展示当前值。
下面是我画的一张核心监控流程图,帮你理清数据流转:
14.3.4 自适应策略
监控不是目的,目的是让通话质量更好。我一般会根据监控数据做自适应调整:
- 丢包率 > 5%:主动降低视频码率,开启FEC(前向纠错)
- RTT > 300ms:增大抖动缓冲,减少音视频同步的紧耦合
- 带宽 < 300kbps:降分辨率到360p以下,甚至关掉视频只留音频
- 抖动 > 40ms:增大音频抖动缓冲,避免声音变调
注意:自适应调整不要太激进。我见过一个项目,丢包率一高就降码率,降完发现丢包率更高了——因为降码率导致编码器切换,产生了更多瞬时数据。建议加一个「冷却时间」,比如调整后至少等5秒再判断。
14.4 总结
WebRTC的统计与监控,说白了就是三件事:采样、分析、响应。
getStats()给了你数据,你得知道怎么看丢包率、RTT、抖动、带宽这些关键指标。然后根据阈值做告警和自适应调整。
我个人习惯在项目初期就把监控体系搭好,不然后面出了问题全靠猜,那太被动了。你想想看,用户说「卡了」,你打开监控面板一看——哦,丢包率15%,RTT 500ms。问题在哪,一目了然。
嗯,这一章就到这里。记住:没有数据就没有优化,没有监控就没有质量。
公众号:蓝海资料掘金营,微信deep3321