webrtc卡顿主因是ice路径未通、编码参数不当、采集约束不合理及统计盲区;需检查iceconnectionstate、调优setparameters、适配移动端constraints,并用getstats分析真实网络指标。

WebRTC 音视频卡顿,先看 RTCPeerConnection 的 ICE 连接状态
卡顿不一定是带宽问题,很多时候是连接根本没走通最优路径。打开浏览器控制台,检查 RTCPeerConnection.iceConnectionState 是否长期卡在 "checking" 或反复变 "disconnected" —— 这说明 NAT 穿透失败,流量被迫走 TURN 中继,延迟和丢包立刻上来。
- 用
pc.oniceconnectionstatechange监听状态变化,比只看ontrack更早发现问题 - 确保 STUN/TURN 服务器配置正确:
urls字段必须是数组,单个 URL 也要写成["stun:stun.l.google.com:19302"],不是字符串 - 本地开发时禁用防火墙或手动放行 UDP 端口(如 50000–65535),否则 Chrome 可能静默降级到 TCP 中继
音视频延迟高,RTCRtpSender.setParameters() 调参比换编码器更直接
很多人一上来就折腾 VP9 或 AV1,但实际 WebRTC 默认的 H.264 在大多数设备上更稳;真正拖慢首帧和增加抖动的,往往是发送端参数没调好。
-
encodings[0].maxBitrate设太低(如 500000)会导致编码器压帧、画面糊+卡顿;设太高(如 5000000)又可能触发拥塞控制频繁丢包 - 加
scaleResolutionDownBy: 2比直接降width/height更安全,避免分辨率突变导致重协商 - Chrome 115+ 支持
degradationPreference: "maintain-framerate",对屏幕共享场景比默认的"maintain-resolution"更抗卡顿
移动端卡顿严重?别忽略 getUserMedia 的约束条件陷阱
iOS Safari 和 Android Chrome 对摄像头权限、分辨率、帧率的实际支持差异极大,constraints 写得太“理想”会强制降级到软编码,CPU 占用飙升,直接卡死。
- 避免写
{ width: { ideal: 1280 }, height: { ideal: 720 } }—— iOS 可能 fallback 到 640×480 软编,改用{ width: { max: 1280 }, height: { max: 720 } } - Android 上显式加
frameRate: { max: 15 },否则部分厂商默认 30fps 但硬件不支持,导致采集线程阻塞 - 开启
echoCancellation: true时,iOS 会自动启用语音增强,CPU 升高;若只是语音通话,可关掉noiseSuppression减负
延迟测不准?用 RTCRtpReceiver.getStats() 看真实网络指标
靠 performance.now() 算端到端延迟误差太大,真正影响体验的是 jitter、pli、nack 重传次数这些底层指标,它们藏在 stats API 里。
立即学习“前端免费学习笔记(深入)”;
- 定期调用
receiver.getStats(),过滤出inbound-rtp类型,重点关注jitterBufferDelay(单位秒)和framesDropped -
roundTripTime是从 SDP offer/answer 里算出来的,仅反映信令层,不能代表音视频流 RTT;要看remote-inbound-rtp的roundTripTime - Chrome 的
googJitterBufferMs和 Firefox 的jitter数值含义不同,跨浏览器对比前先确认字段来源
WebRTC 卡顿问题往往不是单点故障,而是 ICE 路径、编码参数、采集约束、统计盲区这四块拼图没对齐。每块都容易被当成“别人的问题”跳过,结果调了三天才发现 TURN 服务器根本没返回 candidate。











