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

如何通过socket.io-stream和socket.io-client将Angular摄像头MediaStream传至NestJS后端

用socket.io-stream + socket.io-client实现Angular摄像头MediaStream到NestJS后端的传输

问题根源说明

你当前传递的mediaStream为空对象,是因为MediaStream是浏览器原生的复杂对象,包含不可序列化的轨道、状态等属性,直接放到普通对象里通过socket.io发送时,JSON序列化会自动丢弃无法处理的部分,最终得到空对象{}。必须用socket.io-stream专门处理二进制流传输,不能直接序列化MediaStream。


前端(Angular)实现步骤

1. 安装依赖

npm install socket.io-client socket.io-stream
npm install -D @types/socket.io-stream

2. 正确捕获摄像头MediaStream

确保你已经成功获取到摄像头流:

async getCameraStream(): Promise<MediaStream> {
  try {
    const stream = await navigator.mediaDevices.getUserMedia({
      video: true,
      audio: false // 需要音频可设为true
    });
    // 可选:绑定到video标签预览
    const videoEl = document.getElementById('camera-preview') as HTMLVideoElement;
    if (videoEl) videoEl.srcObject = stream;
    return stream;
  } catch (err) {
    console.error('摄像头流获取失败:', err);
    throw err;
  }
}

3. 用socket.io-stream发送流

不能直接传MediaStream对象,需要通过MediaRecorder将流切割为Blob块,再通过socket.io-stream传输,同时附带元数据:

import { io, Socket } from 'socket.io-client';
import * as ss from 'socket.io-stream';

// 初始化socket连接
private socket: Socket = io('http://你的NestJS后端地址');

async sendStream(mediaStream: MediaStream, participantId: string, roomName: string) {
  // 创建socket流实例
  const socketStream = ss.createStream();
  
  // 发送流+元数据
  ss(this.socket).emit('video-stream', socketStream, { participantId, roomName });
  
  // 将MediaStream转为可传输的Blob块
  const mediaRecorder = new MediaRecorder(mediaStream);
  mediaRecorder.ondataavailable = (event) => {
    if (event.data.size > 0) {
      socketStream.write(event.data);
    }
  };
  
  // 启动录制(100ms切片,可根据需求调整)
  mediaRecorder.start(100);
  
  // 断开连接时清理资源
  this.socket.on('disconnect', () => {
    mediaRecorder.stop();
    socketStream.end();
  });
}

后端(NestJS)实现步骤

1. 安装依赖

npm install @nestjs/platform-socket.io socket.io socket.io-stream

2. 创建SocketIO网关处理流

import { WebSocketGateway, WebSocketServer, SubscribeMessage } from '@nestjs/websockets';
import { Server } from 'socket.io';
import * as ss from 'socket.io-stream';
import * as fs from 'fs';

@WebSocketGateway({
  cors: {
    origin: 'http://你的Angular前端地址', // 允许前端跨域连接
    credentials: true
  }
})
export class VideoStreamGateway {
  @WebSocketServer()
  server: Server;

  @SubscribeMessage('video-stream')
  handleVideoStream(client: any, payload: any) {
    // payload[0]是前端传来的流,payload[1]是元数据
    const stream = payload[0];
    const { participantId, roomName } = payload[1];

    console.log(`收到用户${participantId}的流,房间:${roomName}`);

    // 示例1:将流保存到本地文件(格式为webm)
    const writeStream = fs.createWriteStream(`./${participantId}_${roomName}.webm`);
    stream.pipe(writeStream);

    // 示例2:转发给同一房间的其他客户端
    client.join(roomName);
    const broadcastStream = ss.createStream();
    stream.pipe(broadcastStream);
    this.server.to(roomName).emit('video-stream-broadcast', broadcastStream, { participantId });
  }
}

3. 注册网关到AppModule

import { Module } from '@nestjs/common';
import { VideoStreamGateway } from './video-stream.gateway';

@Module({
  providers: [VideoStreamGateway],
})
export class AppModule {}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 11:35:22