# WebRTC 实现 **本文引用的文件** - [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) ## 目录 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 应用
src/index.ts"] B["HTTP 信令路由
src/signaling.ts"] C["WebSocket 处理器
src/class/websockethandler.ts"] D["HTTP 处理器
src/class/httphandler.ts"] end subgraph "前端" E["RenderStreaming 控制器
client/src/renderstreaming.js"] F["PeerConnection 管理
client/src/peer.js"] G["信令客户端(HTTP/WebSocket)
client/src/signaling.js"] H["输入远程控制链路
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/* 接口,支持会话管理与消息聚合 - WebSocket:connect/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)