Files
video_socket-server/.qoder/repowiki/zh/content/WebRTC 实现/WebRTC 实现.md
2026-05-16 13:37:04 +08:00

361 lines
16 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# WebRTC 实现
<cite>
**本文引用的文件**
- [src/index.ts](file://src/index.ts)
- [src/signaling.ts](file://src/signaling.ts)
- [src/class/websockethandler.ts](file://src/class/websockethandler.ts)
- [src/class/httphandler.ts](file://src/class/httphandler.ts)
- [client/src/peer.js](file://client/src/peer.js)
- [client/src/renderstreaming.js](file://client/src/renderstreaming.js)
- [client/src/signaling.js](file://client/src/signaling.js)
- [client/src/inputremoting.js](file://client/src/inputremoting.js)
- [client/src/inputdevice.js](file://client/src/inputdevice.js)
- [client/src/sender.js](file://client/src/sender.js)
- [client/src/logger.js](file://client/src/logger.js)
- [src/log.ts](file://src/log.ts)
- [package.json](file://package.json)
- [client/test/peerconnection.test.js](file://client/test/peerconnection.test.js)
- [client/test/inputremoting.test.js](file://client/test/inputremoting.test.js)
</cite>
## 目录
1. [简介](#简介)
2. [项目结构](#项目结构)
3. [核心组件](#核心组件)
4. [架构总览](#架构总览)
5. [详细组件分析](#详细组件分析)
6. [依赖关系分析](#依赖关系分析)
7. [性能考虑](#性能考虑)
8. [故障排查指南](#故障排查指南)
9. [结论](#结论)
10. [附录](#附录)
## 简介
本项目是一个基于 WebRTC 的远程渲染与输入控制解决方案,涵盖以下能力:
- PeerConnection 管理与控制:连接建立、媒体协商、连接状态监控
- 输入设备远程控制:鼠标、键盘、触摸屏、手柄事件的采集、编码与转发
- 渲染流处理:媒体流接收、解码与显示
- 信令客户端HTTP 轮询与 WebSocket 两种信令协议,消息路由与广播
- 性能优化与最佳实践:连接稳定性、资源管理、事件驱动架构
- 测试与调试:单元测试覆盖、日志与调试开关
## 项目结构
后端采用 TypeScript + Express + WebSocket前端采用原生 JavaScript核心模块分布如下
- 后端入口与配置启动参数解析、HTTPS/HTTP 选择、WebSocket 信令服务初始化
- 信令路由HTTP 轮询接口与 WebSocket 通道
- 信令处理器WebSocket 与 HTTP 两类处理器,负责消息分发、连接组管理、广播
- 前端渲染与信令RenderStreaming 控制器、PeerConnection 管理、输入远程控制链路
- 输入系统:设备抽象、事件状态编码、消息打包与发送观察者
```mermaid
graph TB
subgraph "后端"
A["Express 应用<br/>src/index.ts"]
B["HTTP 信令路由<br/>src/signaling.ts"]
C["WebSocket 处理器<br/>src/class/websockethandler.ts"]
D["HTTP 处理器<br/>src/class/httphandler.ts"]
end
subgraph "前端"
E["RenderStreaming 控制器<br/>client/src/renderstreaming.js"]
F["PeerConnection 管理<br/>client/src/peer.js"]
G["信令客户端(HTTP/WebSocket)<br/>client/src/signaling.js"]
H["输入远程控制链路<br/>client/src/sender.js + inputremoting.js + inputdevice.js"]
end
A --> B
A --> C
A --> D
E --> F
E --> G
E --> H
```
**图表来源**
- [src/index.ts:13-109](file://src/index.ts#L13-L109)
- [src/signaling.ts:1-25](file://src/signaling.ts#L1-L25)
- [src/class/websockethandler.ts:1-479](file://src/class/websockethandler.ts#L1-L479)
- [src/class/httphandler.ts:1-800](file://src/class/httphandler.ts#L1-L800)
- [client/src/renderstreaming.js:11-317](file://client/src/renderstreaming.js#L11-L317)
- [client/src/peer.js:3-188](file://client/src/peer.js#L3-L188)
- [client/src/signaling.js:3-292](file://client/src/signaling.js#L3-L292)
- [client/src/sender.js:14-209](file://client/src/sender.js#L14-L209)
- [client/src/inputremoting.js:9-300](file://client/src/inputremoting.js#L9-L300)
- [client/src/inputdevice.js:40-719](file://client/src/inputdevice.js#L40-L719)
**章节来源**
- [src/index.ts:13-109](file://src/index.ts#L13-L109)
- [src/signaling.ts:1-25](file://src/signaling.ts#L1-L25)
- [src/class/websockethandler.ts:1-479](file://src/class/websockethandler.ts#L1-L479)
- [src/class/httphandler.ts:1-800](file://src/class/httphandler.ts#L1-L800)
- [client/src/renderstreaming.js:11-317](file://client/src/renderstreaming.js#L11-L317)
- [client/src/peer.js:3-188](file://client/src/peer.js#L3-L188)
- [client/src/signaling.js:3-292](file://client/src/signaling.js#L3-L292)
- [client/src/sender.js:14-209](file://client/src/sender.js#L14-L209)
- [client/src/inputremoting.js:9-300](file://client/src/inputremoting.js#L9-L300)
- [client/src/inputdevice.js:40-719](file://client/src/inputdevice.js#L40-L719)
## 核心组件
- 后端启动与配置命令行参数解析、HTTPS/HTTP 选择、WebSocket 信令服务启动
- 信令路由与中间件HTTP 路由定义、会话校验中间件、消息聚合接口
- WebSocket 与 HTTP 处理器:连接组管理、消息广播、参与者加入/离开、心跳与超时
- 前端渲染控制器连接生命周期管理、Offer/Answer/Candidate 分发、统计与数据通道
- PeerConnection 管理SDP 描述协商、ICE 候选收集与注入、事件派发
- 输入远程控制:设备事件采集、状态编码、消息打包与发送观察者
- 日志系统:前后端日志级别控制与格式化输出
**章节来源**
- [src/index.ts:13-109](file://src/index.ts#L13-L109)
- [src/signaling.ts:6-24](file://src/signaling.ts#L6-L24)
- [src/class/websockethandler.ts:10-137](file://src/class/websockethandler.ts#L10-L137)
- [src/class/httphandler.ts:128-145](file://src/class/httphandler.ts#L128-L145)
- [client/src/renderstreaming.js:11-317](file://client/src/renderstreaming.js#L11-L317)
- [client/src/peer.js:3-188](file://client/src/peer.js#L3-L188)
- [client/src/inputremoting.js:9-300](file://client/src/inputremoting.js#L9-L300)
- [client/src/inputdevice.js:40-719](file://client/src/inputdevice.js#L40-L719)
- [client/src/logger.js:1-30](file://client/src/logger.js#L1-L30)
- [src/log.ts:1-51](file://src/log.ts#L1-L51)
## 架构总览
系统采用“前端渲染 + 后端信令 + 媒体直连”的架构:
- 前端通过 HTTP 或 WebSocket 与后端进行信令交互,完成连接建立与媒体协商
- 媒体流在浏览器间直接传输,信令仅传递 SDP 与 ICE 候选
- 输入事件在前端采集后编码并通过 RTCDataChannel 或自定义消息通道发送至远端
```mermaid
sequenceDiagram
participant Host as "主机(Host)"
participant Server as "信令服务器"
participant Participant as "参与者(Participant)"
Host->>Server : "创建会话/连接"
Note over Host,Server : "HTTP/WebSocket 信令握手"
Host->>Server : "发送 Offer"
Server-->>Participant : "转发 Offer"
Participant->>Server : "发送 Answer"
Server-->>Host : "转发 Answer"
Host->>Server : "发送 ICE Candidate"
Server-->>Participant : "转发 Candidate"
Participant->>Server : "发送 ICE Candidate"
Server-->>Host : "转发 Candidate"
Note over Host,Participant : "媒体流直连传输"
```
**图表来源**
- [src/class/websockethandler.ts:145-338](file://src/class/websockethandler.ts#L145-L338)
- [src/class/httphandler.ts:492-641](file://src/class/httphandler.ts#L492-L641)
- [client/src/renderstreaming.js:72-147](file://client/src/renderstreaming.js#L72-L147)
**章节来源**
- [src/class/websockethandler.ts:145-338](file://src/class/websockethandler.ts#L145-L338)
- [src/class/httphandler.ts:492-641](file://src/class/httphandler.ts#L492-L641)
- [client/src/renderstreaming.js:72-147](file://client/src/renderstreaming.js#L72-L147)
## 详细组件分析
### PeerConnection 管理与控制
- 事件绑定track、datachannel、icecandidate、negotiationneeded、signalingstatechange、iceconnectionstatechange、icegatheringstatechange
- 协商流程:在 negotiationneeded 触发时设置本地描述并派发 offer收到远端 offer 后设置远端描述并生成 answer
- ICE 候选:收集到候选时派发候选事件,等待远端注入
- 状态监控:失败时派发 disconnect 事件,便于上层重连或降级
- 统计与控制:支持 getStats、addTrack/addTransceiver、createDataChannel 等
```mermaid
sequenceDiagram
participant Peer as "Peer(前端)"
participant Signaling as "信令客户端"
participant Remote as "远端Peer"
Peer->>Peer : "negotiationneeded 触发"
Peer->>Peer : "setLocalDescription()"
Peer-->>Signaling : "派发 sendoffer"
Signaling-->>Remote : "发送 Offer"
Remote->>Remote : "setRemoteDescription(Offer)"
Remote->>Remote : "setLocalDescription(Answer)"
Remote-->>Signaling : "派发 sendanswer"
Signaling-->>Peer : "发送 Answer"
Peer->>Peer : "setRemoteDescription(Answer)"
Peer-->>Peer : "触发 negotiated 事件"
```
**图表来源**
- [client/src/peer.js:37-173](file://client/src/peer.js#L37-L173)
- [client/src/renderstreaming.js:72-130](file://client/src/renderstreaming.js#L72-L130)
**章节来源**
- [client/src/peer.js:3-188](file://client/src/peer.js#L3-L188)
- [client/src/renderstreaming.js:72-130](file://client/src/renderstreaming.js#L72-L130)
- [client/test/peerconnection.test.js:1-251](file://client/test/peerconnection.test.js#L1-L251)
### 输入设备远程控制
- 设备抽象Mouse、Keyboard、Touchscreen、Gamepad 四类设备,统一状态接口
- 事件采集:鼠标/键盘/触摸/手柄事件监听与状态更新
- 状态编码:各设备状态转为二进制缓冲区,包含格式标识、尺寸、数据
- 消息打包StateEvent/TextEvent 包装基础事件与状态数据
- 发送链路InputRemoting 订阅观察者,将消息序列化后通过 RTCDataChannel 或自定义通道发送
```mermaid
flowchart TD
Start(["用户输入事件"]) --> Queue["设备队列更新状态"]
Queue --> Encode["编码为 IInputState 缓冲区"]
Encode --> Wrap["包装为 StateEvent/TextEvent"]
Wrap --> Pack["封装为 Message(含 participant_id/type/length/data)"]
Pack --> Send["通过观察者发送(如 RTCDataChannel)"]
Send --> End(["远端接收并应用"])
```
**图表来源**
- [client/src/inputdevice.js:91-719](file://client/src/inputdevice.js#L91-L719)
- [client/src/inputremoting.js:63-300](file://client/src/inputremoting.js#L63-L300)
- [client/src/sender.js:14-209](file://client/src/sender.js#L14-L209)
**章节来源**
- [client/src/inputdevice.js:91-719](file://client/src/inputdevice.js#L91-L719)
- [client/src/inputremoting.js:63-300](file://client/src/inputremoting.js#L63-L300)
- [client/src/sender.js:14-209](file://client/src/sender.js#L14-L209)
- [client/test/inputremoting.test.js:1-132](file://client/test/inputremoting.test.js#L1-L132)
### 渲染流处理
- 渲染控制器:根据角色(host/participant)创建/复用 Peer订阅 trackevent/adddatachannel/onmessage 等事件
- 媒体流接收trackevent 中获取远端媒体轨道,绑定到视频元素进行播放
- 数据通道adddatachannel 事件用于建立输入控制通道或其他应用通道
- 统计与诊断getStats 接口用于网络质量与传输指标观测
```mermaid
sequenceDiagram
participant RS as "RenderStreaming"
participant Peer as "Peer"
participant Video as "视频元素"
RS->>Peer : "创建/复用 Peer 并绑定事件"
Peer-->>RS : "trackevent(媒体轨道)"
RS->>Video : "设置 srcObject 为媒体流"
Peer-->>RS : "adddatachannel(数据通道)"
RS->>RS : "getStats() 收集统计信息"
```
**图表来源**
- [client/src/renderstreaming.js:212-250](file://client/src/renderstreaming.js#L212-L250)
- [client/src/peer.js:21-28](file://client/src/peer.js#L21-L28)
**章节来源**
- [client/src/renderstreaming.js:11-317](file://client/src/renderstreaming.js#L11-L317)
- [client/src/peer.js:21-28](file://client/src/peer.js#L21-L28)
### 信令客户端实现
- HTTP 轮询:定时拉取消息,解析类型并派发事件
- WebSocket长连接消息类型丰富支持广播与参与者路由
- 会话管理:创建/删除会话、连接管理、消息聚合
- 参与者模型:私有模式下 host 与多个 participants支持按 participantId 路由
```mermaid
classDiagram
class Signaling {
+start()
+stop()
+createConnection()
+deleteConnection()
+sendOffer()
+sendAnswer()
+sendCandidate()
+getAll()
}
class WebSocketSignaling {
+start()
+stop()
+createConnection()
+deleteConnection()
+sendOffer()
+sendAnswer()
+sendCandidate()
+sendMessage()
}
Signaling <|-- WebSocketSignaling
```
**图表来源**
- [client/src/signaling.js:3-292](file://client/src/signaling.js#L3-L292)
**章节来源**
- [client/src/signaling.js:3-292](file://client/src/signaling.js#L3-L292)
- [src/class/httphandler.ts:492-641](file://src/class/httphandler.ts#L492-L641)
- [src/class/websockethandler.ts:145-338](file://src/class/websockethandler.ts#L145-L338)
## 依赖关系分析
- 后端依赖Express、ws、uuid、swagger-ui-express 等
- 前端依赖:浏览器原生 WebRTC API、RTCDataChannel、EventTarget、Fetch/WebSocket
- 日志:前后端独立日志模块,支持级别控制与格式化输出
```mermaid
graph LR
Pkg["package.json 依赖声明"] --> Express["express"]
Pkg --> WS["ws"]
Pkg --> UUID["uuid"]
Pkg --> Swagger["swagger-ui-express"]
Front["前端模块"] --> WebRTC["WebRTC API"]
Front --> FetchWS["Fetch/WebSocket"]
LogB["后端日志(src/log.ts)"] --> ConsoleB["控制台输出"]
LogF["前端日志(client/src/logger.js)"] --> ConsoleF["控制台输出"]
```
**图表来源**
- [package.json:14-46](file://package.json#L14-L46)
- [src/log.ts:1-51](file://src/log.ts#L1-L51)
- [client/src/logger.js:1-30](file://client/src/logger.js#L1-L30)
**章节来源**
- [package.json:14-46](file://package.json#L14-L46)
- [src/log.ts:1-51](file://src/log.ts#L1-L51)
- [client/src/logger.js:1-30](file://client/src/logger.js#L1-L30)
## 性能考虑
- 连接稳定性
- 使用轮询重发 Offer 以应对网络抖动,避免长时间无响应
- ICE 候选收集完成后及时注入,减少连接建立延迟
- 媒体协商
- 优先使用匹配编解码器,减少转码开销
- 合理设置带宽限制与回退策略
- 输入事件
- 状态事件合并发送,降低消息频率
- 使用二进制消息格式,减少序列化成本
- 信令
- WebSocket 模式优于 HTTP 轮询,降低延迟与 CPU 开销
- 私有模式下按 participantId 路由,避免广播风暴
- 资源管理
- 及时关闭 PeerConnection 与数据通道
- 监控统计指标,动态调整分辨率与帧率
[本节为通用指导,无需具体文件分析]
## 故障排查指南
- 日志启用
- 前端:调用日志模块的 enable/disable 控制输出
- 后端:通过命令行参数设置日志级别
- 常见问题定位
- 连接失败:检查 signaling 事件派发与路由,确认 Offer/Answer/Candidate 是否正确传递
- ICE 失败:查看 iceconnectionstatechange/disconnect 事件,确认候选注入与防火墙/NAT 配置
- 输入无响应:确认 RTCDataChannel 已打开,消息格式与 participantId 正确
- 单元测试
- PeerConnection 行为验证:添加/移除轨道、发送 Offer/Answer、ICE 候选注入
- 输入系统:设备消息打包、事件编码、观察者发送
**章节来源**
- [client/src/logger.js:1-30](file://client/src/logger.js#L1-L30)
- [src/log.ts:1-51](file://src/log.ts#L1-L51)
- [client/test/peerconnection.test.js:1-251](file://client/test/peerconnection.test.js#L1-L251)
- [client/test/inputremoting.test.js:1-132](file://client/test/inputremoting.test.js#L1-L132)
## 结论
本实现提供了完整的 WebRTC 远程渲染与输入控制方案,具备清晰的模块划分与可扩展性。通过事件驱动与观察者模式,前端渲染控制器与输入系统能够高效协作;后端信令处理器支持私有与公共两种模式,满足不同场景需求。配合完善的日志与测试体系,便于维护与优化。
[本节为总结,无需具体文件分析]
## 附录
- 启动参数与脚本
- 开发模式ts-node 启动,支持 HTTPS/HTTP 与私有/公共模式切换
- 生产模式:构建后运行,支持证书文件与端口配置
- API 与消息类型
- HTTP 轮询:/signaling/* 接口,支持会话管理与消息聚合
- WebSocketconnect/disconnect/offer/answer/candidate/on-message/participant-joined/participant-left/broadcast 等
**章节来源**
- [src/index.ts:16-82](file://src/index.ts#L16-L82)
- [package.json:5-12](file://package.json#L5-L12)
- [src/signaling.ts:6-24](file://src/signaling.ts#L6-L24)
- [src/class/websockethandler.ts:145-473](file://src/class/websockethandler.ts#L145-L473)