You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Node.js与React客户端P2P连接无法触发iceCandidate及ontrack事件

问题排查与修复方案

核心问题:RTSP转WebRTC推流时,PeerConnection的onicecandidate和客户端ontrack事件未触发,根源在于媒体轨道未正确关联到PeerConnection,且SDP无媒体描述导致ICE流程未启动。

关键问题点及修复

1. 服务器端媒体轨道未加入MediaStream

你创建了videoTrack但未将其添加到videoStream中,导致videoStream.getTracks()为空,PeerConnection无媒体轨道可传输,自然不会触发ICE候选和媒体轨道事件。

修改服务器代码:

const videoStream = new MediaStream()
const videoSource = new RTCVideoSource()
const videoTrack = videoSource.createTrack()
videoStream.addTrack(videoTrack) // 新增:将轨道加入流

2. SDP缺少媒体描述(m-line)

从你提供的Offer和Answer SDP可见,无任何媒体相关的m=行,这是因为PeerConnection没有媒体轨道,不会生成对应SDP内容,ICE候选也不会被收集。修复上述第1点后,生成的SDP会自动包含视频媒体的m-line,ICE流程将正常启动。

3. Socket广播方式错误

服务器端用socketIoServer.emit('toClient', ...)会向所有连接客户端发送消息,应改为向当前连接的客户端发送,避免多客户端冲突:

修改服务器fromClientCb函数及Socket逻辑:

// 保存当前连接的socket
let currentSocket = null;

socketIoServer.on('connect', (socket) => {
  console.log('connected')
  currentSocket = socket;
  socket.on('fromClient', (message) => fromClientCb(message, socket))
})

// 调整回调函数,传入当前socket
const fromClientCb = async (message, socket) => {
  if (message.offer) {
    console.log(message.offer)
    await pc.setRemoteDescription(message.offer)
    const answer = await pc.createAnswer()
    console.log({answer})
    await pc.setLocalDescription(answer)

    socket.emit('toClient', {answer}) // 用当前socket发送响应
  }

  if (message.iceCandidate) {
    console.log({iceCandidate: message.iceCandidate})
    await pc.addIceCandidate(message.iceCandidate) // 加上await确保异步操作完成
  }
}

// 修改onicecandidate事件,仅向当前客户端发送候选
pc.onicecandidate = (event) => {
  console.log('onicecandidate', event)
  if (event.candidate && currentSocket) {
    currentSocket.emit('toClient', {iceCandidate: event.candidate})
  }
}

4. FFmpeg参数错误,无法正确解码为I420格式

当前FFmpeg参数用-c copy直接复制流,输出的是MPEG-TS封装视频,不是原始I420帧,videoSource.onFrame无法正确处理。需修改参数解码为原始YUV420P格式:

修改FFmpeg启动参数:

const ffmpeg = spawn('ffmpeg', [
  '-i', rtspUrl,
  '-f', 'rawvideo',
  '-pix_fmt', 'yuv420p', // 指定输出格式为YUV420P(即I420)
  '-s', `${width}x${height}`, // 确保分辨率匹配
  'pipe:1'
])

5. 客户端PeerConnection事件监听优化

客户端onicecandidate会在event.candidate为null时触发(表示ICE收集完成),可添加判断避免发送空候选:

peer.onicecandidate = (event) => {
  if (event.candidate) { // 仅发送非空候选
    console.log('onicecandidate', {event})
    socketRef.current.emit('fromClient', {iceCandidate: event.candidate})
  }
}

验证步骤

  1. 重启服务器,查看FFmpeg stderr输出确认RTSP流拉取正常
  2. 启动React客户端,检查控制台是否打印onicecandidate日志
  3. 确认服务器端收到ICE候选,且自身onicecandidate事件触发并发送给客户端
  4. 客户端ontrack事件触发后,视频应能正常播放

内容的提问来源于stack exchange,提问作者OrganLover

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 15:35:01