WebRTC的RTCPeerConnection状态一直停留在new不变化,该如何排查?
WebRTC连接失败问题排查与修复
核心问题
- 缺失传输载体绑定:RTCPeerConnection 必须绑定至少一个音视频轨或者DataChannel数据通道,才会触发后续的连接建立流程,无传输内容时连接会一直停留在
new状态。 - 未实现ICE候选交换逻辑:SDP交换仅完成媒体能力协商,还需要交换双方的网络地址、端口等ICE候选信息才能建立实际的网络连接,当前代码完全没有处理候选收集和交换逻辑。
- 服务端PeerConnection实例生命周期错误:服务端每次收到
/testing请求都新建RTCPeerConnection实例,且未存储实例,后续的ICE候选交互找不到对应的连接对象,无法完成协商。 - 客户端变量作用域隐患:如果
pc变量未做持久化存储,异步逻辑执行完毕后可能被垃圾回收,导致定时器访问的实例异常。
修复方案
客户端代码修改
import React from 'react' import axios from 'axios' function App() { // 用useRef持久化存储pc实例,避免被回收 const pcRef = React.useRef(null) React.useEffect(() => { pcRef.current = new RTCPeerConnection() // 1. 创建DataChannel,触发连接建立流程 pcRef.current.createDataChannel('test-channel') // 2. 监听本地ICE候选,收集后上报服务端 pcRef.current.onicecandidate = (e) => { if (e.candidate) { axios.post('http://localhost:3000/ice', { candidate: e.candidate }) } } (async () => { const offer = await pcRef.current.createOffer() await pcRef.current.setLocalDescription(offer) const { data } = await axios.post('http://localhost:3000/testing', { sdp: pcRef.current.localDescription }) await pcRef.current.setRemoteDescription(data.sdp) // 3. 添加服务端返回的ICE候选 data.candidates.forEach(cand => pcRef.current.addIceCandidate(cand)) })() const timer = setInterval(() => { if (pcRef.current) { console.log(pcRef.current.connectionState) } }, 2222) // 组件卸载时清理定时器 return () => clearInterval(timer) }, []) return <div>WebRTC测试</div> }
服务端代码修改
const webrtc = require('wrtc') // 测试用全局存储pc实例和候选,生产环境请按用户标识关联存储 let pc = null let pendingCandidates = [] server.post('/testing', async function (req, res) { const { sdp } = req.body pc = new webrtc.RTCPeerConnection() // 监听客户端创建的数据通道 pc.ondatachannel = (e) => { console.log('数据通道建立成功', e.channel) } // 收集服务端ICE候选 pc.onicecandidate = (e) => { if (e.candidate) { pendingCandidates.push(e.candidate) } } await pc.setRemoteDescription(sdp) const answer = await pc.createAnswer() await pc.setLocalDescription(answer) // 返回answer和暂存的服务端候选 res.status(200).json({ sdp: pc.localDescription, candidates: pendingCandidates }) pendingCandidates = [] }) // 新增接口接收客户端ICE候选 server.post('/ice', async function (req, res) { const { candidate } = req.body if (pc && candidate) { await pc.addIceCandidate(new webrtc.RTCIceCandidate(candidate)) } res.sendStatus(200) })
本地测试无需额外配置STUN/TURN服务器,修改完成后即可正常看到连接状态变为connected。
内容的提问来源于stack exchange,提问作者Hypothesis
相关产品推荐
相关产品推荐

