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

Angular12通过Socket.io发摄像头流到Node.js为空对象怎么解决

问题根因

  • Socket.io 传输数据时默认会做JSON序列化,而MediaStream是浏览器提供的宿主对象,不属于可序列化的基础数据类型,直接塞进Socket.io的事件参数里会被序列化为空对象,服务端自然拿不到内容。
  • 另外音视频流本身数据量极大,也不适合通过Socket.io走服务端中转的方式传输,正确的做法是用WebRTC做点对点音视频传输,Socket.io只负责传输WebRTC的建连信令即可。

具体实现方案

1. 调整客户端发送逻辑,仅传信令数据

不要把MediaStream放到Socket.io的事件参数里,先把获取到的本地流存在全局变量中,只传输用户标识、通话相关的信令字段:

toggleVideoCall(){
  this.toggleVideo = false;
  
  let mediaDevices = navigator.mediaDevices;
  mediaDevices.getUserMedia({
    video: true,
    audio: true
  })
  .then((stream:MediaStream)=>{
    this.addMyVideo(stream);
    // 本地流存在全局变量,后续WebRTC建连会用到
    this.localStream = stream;
    console.log(stream);
    // 仅传输信令字段,不要带stream
    this.socket.emit("call", {
      callerName: this.myname,
      callerId: this.myId,
      recieverName: this.userToCall.username,
      reciever: this.userToCall._id
    });
  })
  .catch(alert)
}

2. 服务端补充WebRTC信令转发逻辑

现有转发call事件的逻辑可以保留,额外新增三个WebRTC建连必须的信令转发即可,流内容全程不会经过服务端:

io.on("connection", (socket) => {
  socket.on("call", (data)=>{
    console.log(data)
    io.emit("pickCall", data);
  })
  // 新增WebRTC核心信令的转发逻辑
  socket.on("offer", data => io.to(data.targetId).emit("offer", data))
  socket.on("answer", data => io.to(data.targetId).emit("answer", data))
  socket.on("iceCandidate", data => io.to(data.targetId).emit("iceCandidate", data))
})

3. 两端实现WebRTC建连逻辑

主叫收到被叫的接听响应后创建RTCPeerConnection实例,把本地流添加到实例中,生成offer信令通过Socket.io发给被叫;被叫收到offer后也创建RTCPeerConnection实例,添加本地流后生成answer回传给主叫,两端交换ICE候选完成建连后,就可以直接从RTCPeerConnection的回调中拿到对方的音视频流。

注意事项

  • 如果需要支持跨内网通话,需要额外部署STUN/TURN服务器保证WebRTC可以完成内网穿透。
  • 不要尝试把MediaStream转成Blob/ArrayBuffer后通过Socket.io传输,这种方式延迟极高,完全达不到实时音视频通话的要求。

内容的提问来源于stack exchange,提问作者Mr.EmD

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.09 05:54:03