webrtc连接卡在iceconnectionstate="checking"的根本原因是ice协商未通,需确保stun服务器配置正确、onicecandidate每次触发都完整发送候选、信令通道真正送达offer/answer且顺序无误。

直接用原生 WebRTC 写通路极容易卡在 iceConnectionState = "checking" 或远程视频黑屏,根本原因是信令没到位、安全上下文缺失、或媒体流绑定方式错误——不是代码写得不对,而是漏掉了几个硬性前提。
getUserMedia 权限被静默拒绝的常见原因
浏览器不报错但 navigator.mediaDevices 为 undefined,或调用 getUserMedia() 后直接进 catch 报 NotAllowedError,基本锁定环境问题:
- 页面通过
file://协议打开:必须改用http://localhost或 HTTPS 服务启动 - 生产环境用了 HTTP 域名:现代浏览器(Chrome、Edge、Safari)会直接禁用
getUserMedia,不弹提示框,也不触发then - 移动端未加
playsinline和autoplay属性:<video autoplay playsinline></video>缺一不可,否则 iOS Safari 会强制全屏且不播 - 约束对象写成
{ video: true }但麦克风被系统禁用:部分浏览器(如 Firefox)会因音频权限失败连带拒绝整个请求,建议显式设audio: false排查
RTCPeerConnection 连接卡在 checking 的排查重点
看到 iceConnectionState 长时间停在 "checking",说明 ICE 协商根本没跑通,不是 SDP 生成错了,而是网络路径不通:
-
iceServers至少配一个可用 STUN 地址,例如{ urls: "stun:stun.l.google.com:19302" };只写"stun:"或缺端口会失败 -
onicecandidate事件里必须每次拿到event.candidate就发给对方,不能只发第一个;候选地址是分批生成的,漏掉就可能缺 TURN 中继路径 - 信令通道没真正送达:本地双标签页测试时,常忘了手动复制粘贴
offer和answer,导致setRemoteDescription()根本没执行 - 检查
chrome://webrtc-internals页面,搜索failed或timeout,能快速区分是 STUN 不通还是防火墙拦截
远程视频不显示的典型绑定错误
本地视频能播,远程一直黑屏,90% 是流没绑对地方:
- 监听
ontrack,不是已废弃的onaddstream;后者在 Chrome 72+、Firefox 68+ 已移除 -
ontrack触发时,取event.streams[0]赋给remoteVideo.srcObject,不要用URL.createObjectURL() - 如果用了
addTrack()添加轨道,ontrack会按轨道触发多次,需注意是否覆盖了前一次赋值 - 确保
remoteVideo元素已挂载且未被 CSS 隐藏(比如display: none或visibility: hidden)
要不要自己实现信令服务器
WebRTC 本身不定义信令协议,只管 P2P 媒体传输,所以“点对点”不等于“不需要服务器”:
- 开发阶段可用两个标签页 + 手动复制粘贴 SDP 模拟信令,但仅限验证逻辑
- 真实场景必须有服务端中转:WebSocket 最常用,也可用 Socket.IO、HTTP POST 或甚至 Firebase Realtime DB
- 千万别把 offer/answer 存在 localStorage 或 URL 参数里传——这无法支持多用户、无状态、也无法处理重连
- 如果只是验证可行性,用
https://webrtc.github.io/samples/src/content/peerconnection/pc1/官方 demo 对比行为更高效
最易被忽略的是:信令交换必须严格按顺序完成(offer → setRemote → answer → setRemote),且每一步都依赖上一步成功;任何环节异步丢失或异常吞掉,连接就永远卡住,而控制台未必报错。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











