20、性能监控:WebRTC Stats API、带宽估算、丢包率监控、延迟分析

做WebRTC多人视频会议,最怕什么?

画面卡成PPT,声音断断续续,用户直接摔手机走人。

我早期做的一个项目,上线第一天就被用户骂惨了。当时我天真地以为只要把视频流推出去就行,结果20人同时开摄像头,整个房间直接崩掉。后来我才意识到——没有性能监控的WebRTC应用,就像闭着眼睛开车

这一章,我们就来聊聊怎么把这双「眼睛」装上。

核心要点:WebRTC Stats API 是浏览器原生提供的性能数据接口,配合带宽估算、丢包率监控和延迟分析,能让你实时掌握每一路流的「健康状况」。

20.1 WebRTC Stats API:数据从哪来?

WebRTC 内部维护了一个统计信息仓库。你只需要调用 RTCPeerConnection.getStats(),就能拿到一个 RTCStatsReport 对象。

这个对象里包含什么?说白了,就是每一帧、每一个包、每一毫秒的详细记录。

// 获取统计信息
const stats = await peerConnection.getStats();

stats.forEach(report => {
  if (report.type === 'inbound-rtp') {
    console.log(`接收到的包数: ${report.packetsReceived}`);
    console.log(`丢包数: ${report.packetsLost}`);
    console.log(`抖动: ${report.jitter}`);
  }
});

我个人习惯把这段代码封装成一个定时任务,每秒拉一次数据。为什么是每秒?太频繁会影响性能,太稀疏又抓不到瞬时抖动。

小技巧:在 Chrome 浏览器中,打开 chrome://webrtc-internals 可以直接看到所有连接的实时统计。调试时非常有用。

20.2 带宽估算:别让视频「撑死」

带宽估算,说白了就是判断当前网络能扛多少数据。

WebRTC 内部有一个 GCC(Google Congestion Control) 算法,它会根据丢包率和延迟动态调整发送码率。但问题是,这个算法是黑盒的,你没法直接控制。

那怎么办?我们可以通过 Stats API 拿到估算结果。

// 获取带宽估算
stats.forEach(report => {
  if (report.type === 'candidate-pair' && report.state === 'succeeded') {
    console.log(`可用带宽: ${report.availableOutgoingBitrate} bps`);
    console.log(`往返时间: ${report.currentRoundTripTime} s`);
  }
});

我在项目中遇到过这样的情况:明明带宽足够,但视频质量还是很差。后来发现是 RTCRtpSender.setParameters() 里的编码参数没调对。你想想看,带宽估算给了你 2Mbps,但你编码器只输出 300kbps,那画面能好吗?

注意:availableOutgoingBitrate 是估算值,不是精确值。不要完全依赖它做决策,建议结合丢包率一起看。

20.3 丢包率监控:网络抖动的「晴雨表」

丢包率是衡量网络质量最直接的指标。WebRTC 默认使用 UDP,丢包是家常便饭。但丢包率超过 5%,视频就会出现明显卡顿。

怎么算丢包率?很简单:

// 计算丢包率
let previousPacketsReceived = 0;
let previousPacketsLost = 0;

function calculateLossRate(stats) {
  stats.forEach(report => {
    if (report.type === 'inbound-rtp') {
      const packetsReceived = report.packetsReceived;
      const packetsLost = report.packetsLost;
      
      const deltaReceived = packetsReceived - previousPacketsReceived;
      const deltaLost = packetsLost - previousPacketsLost;
      
      if (deltaReceived + deltaLost > 0) {
        const lossRate = deltaLost / (deltaReceived + deltaLost);
        console.log(`当前丢包率: ${(lossRate * 100).toFixed(2)}%`);
      }
      
      previousPacketsReceived = packetsReceived;
      previousPacketsLost = packetsLost;
    }
  });
}

嗯,这里要注意:丢包率是增量计算的。如果你直接用总数算,那永远都是累计值,看不出瞬时波动。

我曾经踩过一个坑:丢包率突然飙升到 30%,但画面居然没卡。后来查了半天才发现,是 Wi-Fi 信号不稳定导致大量重传,但 WebRTC 的 FEC(前向纠错)把丢包补回来了。所以,丢包率高了不一定卡,但卡了一定有丢包。

20.4 延迟分析:从端到端的「时间账」

延迟是视频会议体验的「隐形杀手」。超过 300ms 的延迟,对话就会开始「抢话」。

WebRTC 的延迟可以拆成三部分:

延迟类型 来源 典型值
网络延迟(RTT) 数据包在网络上往返的时间 20-100ms
抖动缓冲延迟 接收端为了平滑播放而缓存的数据 30-200ms
编解码延迟 编码和解码消耗的时间 10-50ms

RTT 可以直接从 Stats API 拿到:

// 获取 RTT
stats.forEach(report => {
  if (report.type === 'candidate-pair' && report.state === 'succeeded') {
    const rtt = report.currentRoundTripTime * 1000; // 转为毫秒
    console.log(`当前 RTT: ${rtt.toFixed(0)} ms`);
    
    if (rtt > 300) {
      console.warn('延迟过高,建议降低视频分辨率');
    }
  }
});

但抖动缓冲延迟和编解码延迟,Stats API 不直接提供。我一般用「端到端延迟」减去 RTT 来估算。怎么做?在发送端打一个时间戳,接收端收到后计算差值。

实战经验:如果 RTT 正常但用户还是觉得卡,多半是抖动缓冲在作怪。可以尝试调整 RTCRtpReceiverplayoutDelayHint 参数,降低缓冲深度来减少延迟。

20.5 综合监控面板:把数据可视化

光有数据还不够,你得让数据「说话」。我习惯在会议界面右上角放一个迷你监控面板,显示三个核心指标:

  • 带宽使用率:当前码率 / 估算带宽
  • 丢包率:实时增量丢包率
  • 延迟:RTT + 估算的端到端延迟

当某个指标超过阈值时,自动触发告警或自适应调整。比如丢包率超过 10%,自动把视频分辨率从 720p 降到 480p。

下面是我画的一张监控流程图,帮你理清整个逻辑:

WebRTC 性能监控流程图 getStats() 采集 解析 RTCStatsReport 带宽估算 丢包率监控 延迟分析 阈值判断 & 自适应调整 每秒循环一次,形成闭环监控

20.6 自适应策略:让会议自己「救自己」

监控的最终目的,是让系统自动做出调整。我总结了一套「阶梯式降级」策略:

  1. 轻度问题(丢包率 3-5%):开启 FEC,增加冗余包
  2. 中度问题(丢包率 5-10%):降低视频分辨率,从 720p 降到 480p
  3. 重度问题(丢包率 > 10%):关闭视频,只保留音频
  4. 极端情况(RTT > 500ms):切换为音频-only 模式,并提示用户检查网络

重要提醒:不要频繁切换编码参数。每次切换都会触发关键帧请求,导致短暂卡顿。我一般设置 5 秒的冷却时间。

说白了,性能监控不是让你盯着数字看,而是让系统具备「自我修复」的能力。你想想看,用户不会关心丢包率是 3% 还是 8%,他们只关心画面流不流畅、声音清不清晰。

这一章的内容就到这里。记住:没有监控的 WebRTC 应用,就像没有仪表盘的飞机。飞得再高,心里也没底。


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