webrtc支持p2p传输,但需满足三条件:正确addtrack()、配置有效iceservers(含stun/turn)、完整交换ice候选;任一缺失均导致黑屏或iceconnectionstate卡住。

ontrack 不触发、iceConnectionState 卡在 "checking" 或直接变成 "failed" —— 这不是 WebRTC 不行,是连接根本没打穿。
为什么你的 RTCPeerConnection 没建立真正的 P2P?
WebRTC 的“点对点”只针对媒体流,但建立这条路径需要三件事同时成立:- 双方都正确调用
addTrack()(或旧式addStream(),已废弃),且流里有有效轨道(stream.getTracks().length > 0) -
RTCPeerConnection初始化时传入了可用的iceServers,至少含一个 STUN;纯局域网可省略,但一旦跨 NAT 就必须有 - ICE 候选地址真正交换完成:
onicecandidate触发后,你得把e.candidate发给对方,并确保对方调用了addIceCandidate();漏掉任意一个候选,尤其 host candidate 之后的 srflx 或 relay,就可能卡住
onicecandidate,或后端信令服务丢弃了 type="candidate" 消息;又或者对方收到 candidate 后没做 JSON.parse() 就直接传给 addIceCandidate(),导致抛错静默失败。
ontrack 死活不触发?先查这三处
ontrack 是远端流到达的唯一可靠信号,不触发基本等于媒体通道没通:
- 确认远端是否真的调用了
addTrack():很多 demo 只处理本地流,忘了把 stream 加进 peerConnection - 检查
pc.remoteDescription是否已设置:必须在收到 offer/answer 后调用setRemoteDescription(),否则即使 candidate 全部到位,也不会触发 track - 浏览器策略限制:非 HTTPS 或非 localhost 环境下,
getUserMedia()会拒绝,导致本地无流 → 远端无 track 可发;Chrome 123+ 对http://127.0.0.1也开始收紧,建议统一用https://localhost
setRemoteDescription() 成功后,手动执行 pc.getReceivers().forEach(r => console.log(r.track?.kind)),如果有 track 输出,说明接收器已就位,问题出在 video 元素赋值或 mute 属性上。
STUN/TURN 配置写错,P2P 就是空谈
iceServers 不是摆设,写错格式或地址不可达,ICE 就永远卡在 gathering:
- STUN 地址必须是
urls字段,不是url(常见拼写错误):{ urls: 'stun:stun.l.google.com:19302' }✅,{ url: '...' }❌ - 多个服务器要写成数组:
iceServers: [{ urls: 'stun:...' }, { urls: 'turn:...', username: 'u', credential: 'p' }] - TURN 必须带认证信息,且
credential 类型是 string;若用短期凭证,需动态更新,不能硬编码过期值 - 开发阶段可用公共 STUN,但上线必须换自有或商用服务;
stun:stun1.l.google.com:19302等地址近年响应不稳定,建议备用至少两个
chrome://webrtc-internals,筛选你的 RTCPeerConnection,点开 “Stats” 标签页,看 iceCandidatePair 的 state 是否为 succeeded,nominated 是否为 true —— 这才是 P2P 真正跑起来的铁证。
真正卡住的地方,往往不是协议多复杂,而是 candidate 漏发了一条、setRemoteDescription() 忘加 await 导致 race condition、或者信令消息被 JSON 序列化时丢了 candidate 字段。这些细节不打印日志根本看不见。前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











