如何通过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
相关产品推荐
相关产品推荐

