# webrtc_sfu **Repository Path**: NativeBase/webrtc_sfu ## Basic Information - **Project Name**: webrtc_sfu - **Description**: 使用webrtc和mediasoup 实现群聊视频通话(多对多通话)APP、H5之间都需要支持相互通话。 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: main - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 1 - **Forks**: 0 - **Created**: 2025-05-05 - **Last Updated**: 2025-08-12 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # WebRTC和Mediasoup多对多视频通话系统 ## 项目概述 本项目是一个基于WebRTC和Mediasoup实现的多对多视频通话系统,支持Web和移动端互通。系统采用SFU(选择性转发单元)架构模式,通过Mediasoup实现高效的多对多视频通话。 ### 核心功能 - 多对多视频通话(群聊) - Web和APP端互通 - 九宫格视频布局 - 静音、扬声器切换,关闭视频等功能 - 房间管理(创建、销毁、加入、离开) - 网络连接稳定性维护 - 动态调整视频质量 ### 技术栈 - **Web前端(client)**:HTML5 + CSS3 + TS + Vite + Vue3 + socket.io-client + mediasoup-client - **APP端(RtcApp)**:React Native 0.72.5 + TS + socket.io-client + react-native-webrtc + mediasoup-client - **服务端(server)**:Node.js + Express + Socket.io + TS + Mediasoup ## 系统架构设计 ### 1. 整体架构 整个系统采用前后端分离的架构,分为三个主要部分: 1. **Web前端(client)**:基于Vue3+Vite+TS的H5应用 2. **APP端(RtcApp)**:基于React Native的移动应用 3. **服务端(server)**:基于Node.js+Express+Socket.io+Mediasoup的信令和媒体服务器 系统采用SFU(选择性转发单元)架构模式,通过Mediasoup实现高效的多对多视频通话。 ### 2. 通信流程 ``` +--------+ 信令(Socket.io) +--------+ 信令(Socket.io) +--------+ | Web端 |<------------------->| 服务端 |<------------------->| APP端 | +--------+ +--------+ +--------+ | | | | 媒体流(WebRTC/RTP) | 媒体流(WebRTC/RTP) | +------------------------------>|<------------------------------+ | +------------+ | Mediasoup | | (SFU服务器) | +------------+ ``` ### 3. 详细模块设计 #### 3.1 服务端设计 服务端需要实现以下核心功能: 1. **信令服务**:基于Socket.io实现 2. **媒体服务**:基于Mediasoup实现 3. **房间管理**:创建、销毁、加入、离开房间 4. **用户管理**:用户在线状态管理 5. **异常处理**:网络中断重连、错误处理 服务端目录结构: ``` server/ ├── src/ │ ├── config/ # 配置文件 │ ├── controllers/ # 控制器 │ ├── middlewares/ # 中间件 │ ├── models/ # 数据模型 │ ├── routes/ # 路由 │ ├── services/ # 业务逻辑 │ │ ├── room.ts # 房间管理 │ │ ├── user.ts # 用户管理 │ │ └── media.ts # 媒体处理 │ ├── utils/ # 工具函数 │ ├── socket/ # Socket.io处理 │ │ ├── handlers/ # 事件处理器 │ │ └── index.ts # Socket主入口 │ ├── mediasoup/ # Mediasoup相关 │ │ ├── router.ts # 媒体路由 │ │ ├── worker.ts # Worker管理 │ │ └── transport.ts # 传输管理 │ └── app.ts # 应用入口 ├── package.json # 依赖管理 └── tsconfig.json # TS配置 ``` #### 3.2 Web前端设计 Web前端需要实现以下核心功能: 1. **用户界面**:九宫格视频布局、控制按钮 2. **媒体处理**:获取本地媒体、处理远程媒体 3. **信令通信**:与服务端进行信令交换 4. **状态管理**:管理房间和用户状态 Web前端目录结构: ``` client/ ├── public/ # 静态资源 ├── src/ │ ├── assets/ # 资源文件 │ ├── components/ # 组件 │ │ ├── VideoGrid.vue # 视频网格组件 │ │ ├── Controls.vue # 控制按钮组件 │ │ └── ... │ ├── views/ # 页面 │ │ ├── Home.vue # 首页 │ │ ├── Room.vue # 房间页面 │ │ └── ... │ ├── services/ # 服务 │ │ ├── socket.ts # Socket.io客户端 │ │ └── mediasoup.ts # Mediasoup客户端 │ ├── utils/ # 工具函数 │ ├── store/ # 状态管理 │ ├── router/ # 路由 │ ├── App.vue # 根组件 │ └── main.ts # 入口文件 ├── package.json # 依赖管理 ├── vite.config.ts # Vite配置 └── tsconfig.json # TS配置 ``` #### 3.3 APP端设计 APP端需要实现与Web前端类似的功能,但需要适配移动端特性: 1. **用户界面**:适配移动端的九宫格视频布局、控制按钮 2. **媒体处理**:获取本地媒体、处理远程媒体,前后摄像头切换 3. **信令通信**:与服务端进行信令交换 4. **状态管理**:管理房间和用户状态 5. **设备适配**:适配不同移动设备 APP端目录结构: ``` RtcApp/ ├── src/ │ ├── assets/ # 资源文件 │ ├── components/ # 组件 │ │ ├── VideoGrid.tsx # 视频网格组件 │ │ ├── Controls.tsx # 控制按钮组件 │ │ └── ... │ ├── screens/ # 页面 │ │ ├── HomeScreen.tsx # 首页 │ │ ├── RoomScreen.tsx # 房间页面 │ │ └── ... │ ├── services/ # 服务 │ │ ├── socket.ts # Socket.io客户端 │ │ └── mediasoup.ts # Mediasoup客户端 │ ├── utils/ # 工具函数 │ ├── store/ # 状态管理 │ ├── navigation/ # 导航 │ └── App.tsx # 根组件 ├── package.json # 依赖管理 └── tsconfig.json # TS配置 ``` ### 4. 关键技术实现 #### 4.1 房间管理 服务端需要维护房间状态,包括: - 房间ID - 房间类型(持久化/临时) - 最大人数限制 - 当前成员列表 - 房间创建时间 - 房间状态(活跃/关闭) #### 4.2 媒体处理 使用Mediasoup实现SFU模式的媒体处理: - Worker管理:创建和管理Mediasoup Worker - Router管理:为每个房间创建Router - Transport管理:为每个用户创建WebRtcTransport - Producer管理:管理用户的音视频Producer - Consumer管理:管理用户的音视频Consumer #### 4.3 信令交换 使用Socket.io实现信令交换,主要事件包括: - 房间事件:创建、加入、离开、关闭 - 媒体事件:SDP交换、ICE候选交换 - 状态事件:用户状态、设备状态 - 控制事件:静音、关闭视频、踢出成员等 #### 4.4 网络适应性 实现网络状况自适应: - 带宽估计:实时估计可用带宽 - 动态调整:根据网络状况调整视频分辨率和帧率 - 自动重连:网络中断后自动重连 ### 5. 实现路线图 建议按照以下步骤实现系统: 1. **基础架构搭建**: - 服务端Express+Socket.io框架搭建 - Web前端Vue3+Vite框架搭建 - APP端React Native框架搭建 2. **核心功能实现**: - 服务端Mediasoup集成 - 房间管理实现 - 基础信令交换实现 3. **客户端功能实现**: - 媒体获取和展示 - 九宫格布局实现 - 基础控制功能实现 4. **高级功能实现**: - 网络适应性 - 异常处理 - 主播控制功能 5. **测试和优化**: - 功能测试 - 性能测试 - 兼容性测试 ### 6. 关键依赖包 ### 7. 技术挑战与解决方案 1. **跨平台兼容性** - 挑战:确保Web和APP端都能正常工作 - 解决方案:抽象公共逻辑,针对不同平台做适配 2. **网络稳定性** - 挑战:保持在不稳定网络下的连接 - 解决方案:实现ICE重启、DTLS重新协商、自动重连机制 3. **媒体质量** - 挑战:在不同网络条件下保持良好的媒体质量 - 解决方案:实现自适应比特率控制、动态分辨率调整 4. **资源消耗** - 挑战:多人视频会议资源消耗大 - 解决方案:使用SFU模式减轻客户端负担,服务端做好资源管理 ### 8. 后续扩展建议 1. **录制功能**:添加服务端录制功能,保存通话内容 2. **屏幕共享**:实现屏幕共享功能 3. **聊天功能**:添加文字聊天功能 4. **白板功能**:添加协作白板功能 5. **用户认证**:添加用户认证和权限管理 6. **数据统计**:添加通话质量和使用情况统计 ## SFU 模块详细文档 ### 1. 概述 SFU (Selective Forwarding Unit) 模块是一个基于 mediasoup 的 WebRTC 服务器实现,用于处理多方音视频通信。该模块采用了 SFU 架构,相比于 MCU (Multipoint Control Unit),SFU 不进行媒体流的混合处理,而是选择性地将媒体流从发送者转发到接收者,大大降低了服务器的计算负担。 #### 1.1 生产者和消费者概念 在 WebRTC SFU 架构中,生产者和消费者是两个核心概念,它们决定了媒体流的传输方式。 ##### 生产者 (Producer) 生产者代表从客户端发送到服务器的媒体流。 - **定义**:生产者是一个对象,表示客户端通过 WebRTC 传输向服务器发送的音频或视频轨道。 - **功能**: - 将客户端的本地媒体流(如摄像头视频、麦克风音频)发送到服务器 - 控制媒体流的参数,如编码质量、比特率等 - 可以被暂停和恢复 - **创建过程**: - 客户端获取本地媒体流(getUserMedia) - 创建发送传输(createSendTransport) - 通过发送传输创建生产者(produce),将媒体轨道发送到服务器 - **实际应用**:当用户打开摄像头或麦克风时,会创建相应的生产者,将媒体流发送到服务器。 ##### 消费者 (Consumer) 消费者代表从服务器接收的媒体流。 - **定义**:消费者是一个对象,表示客户端通过 WebRTC 传输从服务器接收的其他用户的音频或视频轨道。 - **功能**: - 接收其他用户的媒体流 - 控制接收的媒体流参数 - 可以被暂停和恢复 - **创建过程**: - 客户端创建接收传输(createRecvTransport) - 当有新的生产者可用时,客户端通过接收传输创建消费者(consume) - 消费者将远程媒体流添加到客户端的媒体元素中(如 video 标签) - **实际应用**:当房间中有其他用户打开摄像头或麦克风时,当前用户会创建相应的消费者来接收和显示这些媒体流。 ##### 在 SFU 架构中的工作方式 在 SFU 架构中: 1. 每个参与者都会为自己的音视频创建生产者,发送到服务器 2. 服务器不混合这些媒体流,而是选择性地将它们转发给其他参与者 3. 每个参与者为其他人的每个媒体流创建消费者 4. 这样,每个参与者可以独立控制接收哪些媒体流,以及如何显示它们 例如,在一个有 3 人的会议中: - 用户 A 创建音频和视频生产者(2个) - 用户 B 和 C 各自为 A 的音频和视频创建消费者(共4个) - 同样,B 和 C 也创建自己的生产者,其他人创建相应的消费者 ### 2. 系统架构 #### 2.1 目录结构 ``` /sfu ├── config/ # 配置文件 │ └── index.ts # 主配置文件 ├── mediasoup/ # mediasoup 相关实现 │ ├── worker.ts # Worker 管理 │ ├── router.ts # Router 管理 │ └── transport.ts # Transport 管理 ├── models/ # 数据模型 │ └── Room.ts # 房间模型 ├── services/ # 业务服务 │ ├── media.ts # 媒体服务 │ ├── room.ts # 房间服务 │ └── user.ts # 用户服务 └── socket/ # Socket 通信 ├── handlers/ # 事件处理器 │ ├── media.ts # 媒体事件处理 │ └── room.ts # 房间事件处理 └── index.ts # Socket 服务初始化 ``` #### 2.2 核心组件 1. **Worker**: mediasoup 的工作进程,负责处理媒体流的传输。 2. **Router**: 媒体路由器,负责在同一个房间内的参与者之间路由媒体。 3. **Transport**: 传输层,负责在客户端和服务器之间建立安全的媒体传输通道。 4. **Producer**: 媒体生产者,代表用户发送的媒体流。 5. **Consumer**: 媒体消费者,代表用户接收的媒体流。 ### 3. 详细模块说明 #### 3.1 配置模块 (config) 提供系统全局配置,包括: - **服务器配置**:端口、CORS 设置等 - **Mediasoup 配置**: - Worker 数量和设置 - Router 媒体编解码器配置 - WebRTC 传输设置 - **房间配置**:最大人数、默认房间类型等 #### 3.2 Mediasoup 模块 ##### 3.2.1 worker.ts **功能**:管理 mediasoup Worker 进程池,采用轮询方式分配 Worker。 **主要方法**: - `init()`: 初始化指定数量的 Worker 进程 - `getNextWorker()`: 获取下一个可用的 Worker(轮询方式) - `closeAll()`: 关闭所有 Worker 进程 ##### 3.2.2 router.ts **功能**:管理每个房间的 Router 实例,Router 负责房间内的媒体路由。 **主要方法**: - `createRouter(roomId)`: 为房间创建 Router - `getRouter(roomId)`: 获取房间的 Router - `closeRouter(roomId)`: 关闭房间的 Router ##### 3.2.3 transport.ts **功能**:管理 WebRTC 传输,包括生产者和消费者的创建和管理。 **主要方法**: - `createWebRtcTransport(roomId, userId, direction)`: 创建 WebRTC 传输 - `getTransport(roomId, userId, transportId)`: 获取传输实例 - `createProducer(roomId, userId, transportId, rtpParameters, kind)`: 创建媒体生产者 - `createConsumer(roomId, consumerId, producerId, transportId, rtpCapabilities)`: 创建媒体消费者 - `closeRoomTransports(roomId)`: 关闭房间的所有传输 - `closeUserTransports(roomId, userId)`: 关闭用户的所有传输 #### 3.3 模型模块 (models) ##### 3.3.1 Room.ts **功能**:定义房间模型及相关操作。 **主要接口和类**: - `RoomType`: 房间类型('temporary' | 'persistent') - `RoomStatus`: 房间状态('active' | 'closed') - `RoomMember`: 房间成员接口 - `IRoom`: 房间接口 - `Room`: 房间实现类 **主要方法**: - `addMember(id, name, isHost)`: 添加成员 - `removeMember(id)`: 移除成员 - `getMember(id)`: 获取成员 - `isEmpty()`: 检查房间是否为空 - `isFull()`: 检查房间是否已满 - `close()`: 关闭房间 #### 3.4 服务模块 (services) ##### 3.4.1 room.ts **功能**:提供房间管理服务,包括创建、加入、离开房间等操作。 **主要方法**: - `createRoom(name, hostId, type, maxPeers)`: 创建房间 - `getRoom(roomId)`: 获取房间 - `getActiveRooms()`: 获取所有活跃房间 - `joinRoom(roomId, userId)`: 加入房间 - `leaveRoom(roomId, userId)`: 离开房间 - `closeRoom(roomId)`: 关闭房间 - `getRoomPeers(roomId)`: 获取房间内的用户 - `isUserInRoom(roomId, userId)`: 检查用户是否在房间内 - `getUserRoom(userId)`: 获取用户所在的房间 - `startCleanupTask()`: 启动房间清理定时任务 - `cleanupRooms()`: 清理空闲房间 ##### 3.4.2 user.ts **功能**:提供用户管理服务,包括用户创建、状态管理等。 **主要方法**: - `createUser(id, name, socketId)`: 创建用户 - `getUser(userId)`: 获取用户 - `getUserBySocketId(socketId)`: 通过 Socket ID 获取用户 - `updateUserStatus(userId, online)`: 更新用户状态 - `updateUserDevice(userId, deviceInfo)`: 更新用户设备状态 - `joinRoom(userId, roomId)`: 用户加入房间 - `leaveRoom(userId)`: 用户离开房间 ##### 3.4.3 media.ts **功能**:提供媒体服务,包括媒体流的创建、管理和传输。 **主要方法**: - `initRoom(roomId)`: 初始化房间的媒体服务 - `getRouter(roomId)`: 获取房间的 Router - `getRtpCapabilities(roomId)`: 获取 Router 的 RTP 能力 - `createTransport(roomId, userId, direction)`: 创建 WebRTC 传输 - `connectTransport(roomId, userId, transportId, dtlsParameters)`: 连接传输 - `createProducer(roomId, userId, transportId, kind, rtpParameters)`: 创建生产者 - `createConsumer(roomId, consumerId, producerId, transportId, rtpCapabilities)`: 创建消费者 - `resumeConsumer(roomId, userId, transportId, consumerId)`: 恢复消费者 - `pauseProducer(roomId, userId, producerId, pause)`: 暂停/恢复生产者 - `closeRoom(roomId)`: 关闭房间的媒体服务 - `userLeaveRoom(roomId, userId)`: 处理用户离开房间的媒体清理 #### 3.5 Socket 模块 (socket) ##### 3.5.1 index.ts **功能**:初始化 Socket.IO 服务,处理连接和断开连接事件,注册事件处理器。 **主要流程**: 1. 创建 Socket.IO 服务器实例 2. 配置 CORS 和其他选项 3. 监听客户端连接事件 4. 注册房间和媒体事件处理器 5. 处理设备状态更新和断开连接事件 ##### 3.5.2 handlers/room.ts **功能**:处理房间相关的 Socket 事件。 **主要事件处理及参数**: 功能:提供房间管理服务,包括创建、加入、离开房间等操作。 主要方法: - `iceCandidate`:处理 ICE 候选者 - **客户端发送参数**: ```typescript { roomId: string; // 房间ID userId: string; // 发送者用户ID targetUserId: string; // 目标用户ID candidate: RTCIceCandidateInit; // ICE候选者信息 } ``` - **服务端响应**: ```typescript { success: boolean; // 是否成功 error?: string; // 错误信息(如果失败) } ``` - **服务端广播**:向目标用户发送 ```typescript { userId: string; // 发送者用户ID candidate: RTCIceCandidateInit; // ICE候选者信息 } ``` - `offer`:处理 Offer - **客户端发送参数**: ```typescript { roomId: string; // 房间ID userId: string; // 发送者用户ID targetUserId: string; // 目标用户ID sdp: string; // SDP Offer内容 } ``` - **服务端响应**: ```typescript { success: boolean; // 是否成功 error?: string; // 错误信息(如果失败) } ``` - **服务端广播**:向目标用户发送 ```typescript { userId: string; // 发送者用户ID sdp: string; // SDP Offer内容 } ``` - `answer`:处理 Answer - **客户端发送参数**: ```typescript { roomId: string; // 房间ID userId: string; // 发送者用户ID targetUserId: string; // 目标用户ID sdp: string; // SDP Answer内容 } ``` - **服务端响应**: ```typescript { success: boolean; // 是否成功 error?: string; // 错误信息(如果失败) } ``` - **服务端广播**:向目标用户发送 ```typescript { userId: string; // 发送者用户ID sdp: string; // SDP Answer内容 } ``` - `checkRoom`:检查房间是否存在 - **客户端发送参数**: ```typescript { roomId: string; // 要检查的房间ID } ``` - **服务端响应**: ```typescript { success: boolean; // 房间是否存在且有效 error?: string; // 错误信息(如果失败) room?: { // 房间信息(如果成功) id: string; // 房间ID name: string; // 房间名称 type: string; // 房间类型 maxPeers: number; // 最大人数 currentPeers: number; // 当前人数 hostId: string; // 房主 ID } } ``` - `getRoomUsers`:获取房间用户列表 - **客户端发送参数**: ```typescript { roomId: string; // 房间ID } ``` - **服务端响应**: ```typescript { success: boolean; // 是否成功 error?: string; // 错误信息(如果失败) users: Array<{ // 用户列表 id: string; // 用户ID name: string; // 用户名 }> } ``` - `getRooms`:获取所有活跃房间 - **客户端发送参数**:无特定参数 - **服务端响应**: ```typescript { success: boolean; // 是否成功 rooms: Array<{ // 房间列表 id: string; // 房间ID name: string; // 房间名称 peers: number; // 当前用户数 maxPeers: number; // 最大用户数 type: string; // 房间类型 }> } ``` - `joinRoom`:加入房间 - **客户端发送参数**: ```typescript { roomId: string; // 要加入的房间ID userName: string; // 用户名 userId?: string; // 用户ID(可选,如果没有则服务器生成) } ``` - **服务端响应**: ```typescript { success: boolean; // 是否成功 error?: string; // 错误信息(如果失败) room?: { // 房间信息(如果成功) id: string; // 房间ID name: string; // 房间名称 type: string; // 房间类型 maxPeers: number; // 最大人数 users: Array<{ // 房间内的用户 id: string; // 用户ID name: string; // 用户名 }> } userId: string; // 分配给用户的ID } ``` - **服务端广播**:向房间内其他用户发送 ```typescript { userId: string; // 新加入的用户ID userName: string; // 新加入的用户名 } ``` - `leaveRoom`:离开房间 - **客户端发送参数**: ```typescript { roomId: string; // 要离开的房间ID userId: string; // 用户ID } ``` - **服务端响应**: ```typescript { success: boolean; // 是否成功 error?: string; // 错误信息(如果失败) } ``` - **服务端广播**:向房间内其他用户发送 ```typescript { userId: string; // 离开的用户ID } ``` ##### 3.5.3 handlers/media.ts **功能**:处理媒体相关的 Socket 事件。 **主要事件处理及参数**: - `getRtpCapabilities`:获取 Router 的 RTP 能力 - **客户端发送参数**: ```typescript { roomId: string; // 房间ID } ``` - **服务端响应**: ```typescript { success: boolean; // 是否成功 error?: string; // 错误信息(如果失败) rtpCapabilities?: mediasoup.types.RtpCapabilities; // Router 的 RTP 能力 } ``` - `createSendTransport`:创建发送传输 - **客户端发送参数**: ```typescript { roomId: string; // 房间ID userId: string; // 用户ID } ``` - **服务端响应**: ```typescript { success: boolean; // 是否成功 error?: string; // 错误信息(如果失败) transportOptions?: { // 传输选项(如果成功) id: string; // 传输ID iceParameters: mediasoup.types.IceParameters; // ICE参数 iceCandidates: mediasoup.types.IceCandidate[]; // ICE候选者 dtlsParameters: mediasoup.types.DtlsParameters; // DTLS参数 } } ``` - `createRecvTransport`:创建接收传输 - **客户端发送参数**: ```typescript { roomId: string; // 房间ID userId: string; // 用户ID } ``` - **服务端响应**: ```typescript { success: boolean; // 是否成功 error?: string; // 错误信息(如果失败) transportOptions?: { // 传输选项(如果成功) id: string; // 传输ID iceParameters: mediasoup.types.IceParameters; // ICE参数 iceCandidates: mediasoup.types.IceCandidate[]; // ICE候选者 dtlsParameters: mediasoup.types.DtlsParameters; // DTLS参数 } } ``` - `connectTransport`:连接传输 - **客户端发送参数**: ```typescript { roomId: string; // 房间ID userId: string; // 用户ID transportId: string; // 传输ID dtlsParameters: mediasoup.types.DtlsParameters; // DTLS参数 } ``` - **服务端响应**: ```typescript { success: boolean; // 是否成功 error?: string; // 错误信息(如果失败) } ``` - `produce`:创建生产者 - **客户端发送参数**: ```typescript { roomId: string; // 房间ID userId: string; // 用户ID transportId: string; // 传输ID kind: 'audio' | 'video'; // 媒体类型 rtpParameters: mediasoup.types.RtpParameters; // RTP参数 } ``` - **服务端响应**: ```typescript { success: boolean; // 是否成功 error?: string; // 错误信息(如果失败) id?: string; // 生产者ID(如果成功) } ``` - **服务端广播**:向房间内其他用户发送 ```typescript { producerId: string; // 生产者ID userId: string; // 生产者所属用户ID kind: 'audio' | 'video'; // 媒体类型 } ``` - `consume`:创建消费者 - **客户端发送参数**: ```typescript { roomId: string; // 房间ID userId: string; // 用户ID transportId: string; // 传输ID producerId: string; // 要消费的生产者ID rtpCapabilities: mediasoup.types.RtpCapabilities; // 客户端的 RTP 能力 } ``` - **服务端响应**: ```typescript { success: boolean; // 是否成功 error?: string; // 错误信息(如果失败) consumerOptions?: { // 消费者选项(如果成功) id: string; // 消费者ID kind: mediasoup.types.MediaKind; // 媒体类型 rtpParameters: mediasoup.types.RtpParameters; // RTP参数 producerId: string; // 生产者ID producerUserId: string; // 生产者所属用户ID } } ``` - `resumeConsumer`:恢复消费者 - **客户端发送参数**: ```typescript { roomId: string; // 房间ID userId: string; // 用户ID transportId: string; // 传输ID consumerId: string; // 消费者ID } ``` - **服务端响应**: ```typescript { success: boolean; // 是否成功 error?: string; // 错误信息(如果失败) } ``` - `pauseProducer`:暂停/恢复生产者 - **客户端发送参数**: ```typescript { roomId: string; // 房间ID userId: string; // 用户ID producerId: string; // 生产者ID pause: boolean; // true 表示暂停,false 表示恢复 } ``` - **服务端响应**: ```typescript { success: boolean; // 是否成功 error?: string; // 错误信息(如果失败) } ``` - **服务端广播**:向房间内其他用户发送 ```typescript { producerId: string; // 生产者ID userId: string; // 生产者所属用户ID paused: boolean; // 是否暂停 } ``` ### 4. 完整通信流程 #### 4.1 加入房间流程 1. 客户端发送 `joinRoom` 事件,提供房间 ID、用户名和用户 ID 2. 服务器验证房间是否存在,如果不存在则创建 3. 用户加入房间,服务器初始化房间的媒体服务(如果尚未初始化) 4. 服务器通知房间内其他用户有新用户加入 5. 服务器返回房间信息和 RTP 能力给新用户 #### 4.2 媒体通信流程 1. **获取 RTP 能力**: - 客户端发送 `getRtpCapabilities` 事件 - 服务器返回 Router 的 RTP 能力 2. **创建发送传输**: - 客户端发送 `createSendTransport` 事件 - 服务器创建发送传输并返回传输选项 3. **创建接收传输**: - 客户端发送 `createRecvTransport` 事件 - 服务器创建接收传输并返回传输选项 4. **连接传输**: - 客户端发送 `connectTransport` 事件,提供 DTLS 参数 - 服务器连接传输 5. **创建生产者**: - 客户端发送 `produce` 事件,提供媒体类型和 RTP 参数 - 服务器创建生产者并通知房间内其他用户有新的生产者 - 其他用户可以选择消费这个生产者的媒体流 6. **创建消费者**: - 客户端发送 `consume` 事件,指定要消费的生产者 ID - 服务器创建消费者并返回消费者选项 - 客户端接收消费者选项并开始接收媒体流 7. **恢复消费者**: - 客户端发送 `resumeConsumer` 事件 - 服务器恢复消费者,开始媒体流传输 #### 4.3 离开房间流程 1. 客户端发送 `leaveRoom` 事件或断开连接 2. 服务器从房间中移除用户 3. 关闭用户的所有媒体传输 4. 通知房间内其他用户有用户离开 5. 如果房间为空且是临时房间,则关闭房间 ### 5. 客户端集成指南 #### 5.1 必要的客户端事件 客户端需要实现以下事件处理: **发送事件**: - `joinRoom`: 加入房间 - `getRtpCapabilities`: 获取 RTP 能力 - `createSendTransport`: 创建发送传输 - `createRecvTransport`: 创建接收传输 - `connectTransport`: 连接传输 - `produce`: 创建生产者 - `consume`: 创建消费者 - `resumeConsumer`: 恢复消费者 **接收事件**: - `userJoined`: 用户加入 - `userLeft`: 用户离开 - `newProducer`: 新的生产者 - `producerClosed`: 生产者关闭 - `userDeviceUpdated`: 用户设备状态更新