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-pairavailableOutgoingBitrate拿到。

带宽估计低了,视频会自动降分辨率。带宽估计高了,视频会变清晰。如果你发现用户视频一直模糊,先看看这个值是不是被压得太低了。

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 可视化展示

数据有了,怎么展示?我习惯用折线图展示趋势,用仪表盘展示当前值。

下面是我画的一张核心监控流程图,帮你理清数据流转:

WebRTC 网络质量监控数据流 getStats() 采样 RTCStatsReport 解析关键指标 丢包率 packetsLost / total RTT currentRoundTripTime 抖动 jitter 带宽估计 availableBitrate 阈值判断 → 告警触发 → 自适应调整(降码率/切线路) 监控面板展示 / 日志上报 / 用户提示

14.3.4 自适应策略

监控不是目的,目的是让通话质量更好。我一般会根据监控数据做自适应调整:

  • 丢包率 > 5%:主动降低视频码率,开启FEC(前向纠错)
  • RTT > 300ms:增大抖动缓冲,减少音视频同步的紧耦合
  • 带宽 < 300kbps:降分辨率到360p以下,甚至关掉视频只留音频
  • 抖动 > 40ms:增大音频抖动缓冲,避免声音变调

注意:自适应调整不要太激进。我见过一个项目,丢包率一高就降码率,降完发现丢包率更高了——因为降码率导致编码器切换,产生了更多瞬时数据。建议加一个「冷却时间」,比如调整后至少等5秒再判断。

14.4 总结

WebRTC的统计与监控,说白了就是三件事:采样、分析、响应。

getStats()给了你数据,你得知道怎么看丢包率、RTT、抖动、带宽这些关键指标。然后根据阈值做告警和自适应调整。

我个人习惯在项目初期就把监控体系搭好,不然后面出了问题全靠猜,那太被动了。你想想看,用户说「卡了」,你打开监控面板一看——哦,丢包率15%,RTT 500ms。问题在哪,一目了然。

嗯,这一章就到这里。记住:没有数据就没有优化,没有监控就没有质量。


公众号:蓝海资料掘金营,微信deep3321