This commit is contained in:
2026-05-16 13:24:02 +08:00
parent eae60714b4
commit 6c13817527
42 changed files with 15921 additions and 0 deletions

View File

@@ -0,0 +1,367 @@
# 渲染流处理
<cite>
**本文引用的文件**
- [client/src/renderstreaming.js](file://client/src/renderstreaming.js)
- [client/src/peer.js](file://client/src/peer.js)
- [client/src/signaling.js](file://client/src/signaling.js)
- [client/src/logger.js](file://client/src/logger.js)
- [client/src/inputdevice.js](file://client/src/inputdevice.js)
- [client/src/inputremoting.js](file://client/src/inputremoting.js)
- [client/src/pointercorrect.js](file://client/src/pointercorrect.js)
- [client/src/gamepadhandler.js](file://client/src/gamepadhandler.js)
- [client/src/sender.js](file://client/src/sender.js)
- [client/test/renderstreaming.test.js](file://client/test/renderstreaming.test.js)
- [client/test/peerconnection.test.js](file://client/test/peerconnection.test.js)
- [client/public/onebyone/renderer.js](file://client/public/onebyone/renderer.js)
- [src/index.ts](file://src/index.ts)
- [package.json](file://package.json)
</cite>
## 目录
1. [引言](#引言)
2. [项目结构](#项目结构)
3. [核心组件](#核心组件)
4. [架构总览](#架构总览)
5. [详细组件分析](#详细组件分析)
6. [依赖关系分析](#依赖关系分析)
7. [性能考量](#性能考量)
8. [故障排查指南](#故障排查指南)
9. [结论](#结论)
10. [附录](#附录)
## 引言
本文件聚焦“渲染流处理”模块,系统性阐述媒体流的接收、解码与显示全链路,涵盖 WebRTC 媒体流的信令与协商、轨道管理、渲染管线、性能优化与调试方法。文档面向不同技术背景读者,既提供高层架构视图,也包含代码级细节与可视化图表,帮助快速定位问题并进行针对性优化。
## 项目结构
该项目由前端渲染与后端服务两部分组成:
- 前端 client负责渲染、输入遥测、WebRTC 信令与协商、媒体轨道管理与显示。
- 后端 src基于 Express 的服务端入口,启动 HTTP/HTTPS 服务器并按需启用 WebSocket 信令。
```mermaid
graph TB
subgraph "前端 client"
RS["RenderStreaming<br/>渲染流编排"]
PEER["Peer<br/>RTCPeerConnection 封装"]
SIG["Signaling<br/>HTTP/WebSocket 信令"]
RENDER["Renderer<br/>UI 渲染器"]
INPUT["Input Remoting<br/>输入事件打包"]
end
subgraph "后端 src"
APP["Express 应用"]
WS["WebSocket 信令服务"]
end
RS --> PEER
RS --> SIG
RENDER --> RS
INPUT --> SIG
SIG --> WS
APP --> WS
```
图表来源
- [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/public/onebyone/renderer.js:28-800](file://client/public/onebyone/renderer.js#L28-L800)
- [src/index.ts:13-109](file://src/index.ts#L13-L109)
章节来源
- [src/index.ts:13-109](file://src/index.ts#L13-L109)
- [package.json:1-60](file://package.json#L1-L60)
## 核心组件
- 渲染流编排RenderStreaming
- 负责连接生命周期管理、主机/参与方模式、多 peer 管理、事件转发与统计查询。
- RTCPeerConnection 封装Peer
- 提供 SDP 协商、ICE 候选、轨道增删、统计数据查询与断连检测。
- 信令Signaling
- 支持 HTTP 轮询与 WebSocket 两种模式,封装 offer/answer/candidate/on-message 等事件。
- 输入遥测Input Remoting
- 将鼠标、键盘、触摸、手柄等输入事件序列化并通过数据通道传输。
- 渲染器Renderer
- 将状态映射到 DOM负责视频流显示、占位符切换、分辨率适配与网络质量指示。
章节来源
- [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/inputremoting.js:1-300](file://client/src/inputremoting.js#L1-L300)
- [client/public/onebyone/renderer.js:28-800](file://client/public/onebyone/renderer.js#L28-L800)
## 架构总览
渲染流处理采用“信令驱动 + PeerConnection 协商 + 轨道渲染”的分层架构。前端通过 Signaling 与后端建立连接,随后在 RenderStreaming 中完成主机/参与方角色下的 peer 管理与事件路由Peer 负责 SDP 与 ICE 流程Renderer 负责将媒体轨道映射到页面元素。
```mermaid
sequenceDiagram
participant UI as "页面/UI"
participant RS as "RenderStreaming"
participant SIG as "Signaling(HTTP/WebSocket)"
participant PC as "Peer(RTCPeerConnection)"
participant REN as "Renderer"
UI->>RS : 创建连接/发起协商
RS->>SIG : createConnection()
SIG-->>RS : connect(connectId, role)
RS->>PC : _preparePeerConnection()
UI->>RS : addTrack()/createDataChannel()
RS->>PC : addTrack()/createDataChannel()
PC-->>RS : onnegotiationneeded -> setLocalDescription()
PC-->>SIG : sendoffer(sdp)
SIG-->>RS : offer
RS->>PC : onGotDescription(offer)
PC-->>PC : setRemoteDescription()
PC-->>PC : setLocalDescription() -> answer
PC-->>SIG : sendanswer(sdp)
SIG-->>RS : answer
RS->>PC : onGotDescription(answer)
PC-->>UI : ontrack -> trackevent
RS-->>REN : onTrackEvent(data)
REN-->>UI : 设置 video.srcObject / 占位符切换
```
图表来源
- [client/src/renderstreaming.js:40-130](file://client/src/renderstreaming.js#L40-L130)
- [client/src/peer.js:57-173](file://client/src/peer.js#L57-L173)
- [client/src/signaling.js:30-149](file://client/src/signaling.js#L30-L149)
- [client/public/onebyone/renderer.js:397-604](file://client/public/onebyone/renderer.js#L397-L604)
## 详细组件分析
### 渲染流编排RenderStreaming
- 角色与连接
- 主机host维护多个 participantId -> Peer 的映射,按需创建/复用 peer。
- 参与方participant单一 peer连接建立后立即协商。
- 事件路由
- 将底层 Peer 的 trackevent/adddatachannel/offer/answer 等事件透传给上层回调。
- 统计与通道
- 提供 getStats、createDataChannel、addTrack/addTransceiver 等能力,支持按 participantId 路由。
```mermaid
classDiagram
class RenderStreaming {
+onConnect()
+onDisconnect()
+onGotOffer()
+onGotAnswer()
+onTrackEvent()
+onAddChannel()
+onMessage()
+onParticipantLeft()
+onParticipantJoined()
+onNewPeer()
+createConnection()
+deleteConnection()
+getStats()
+createDataChannel()
+addTrack()
+addTransceiver()
+getTransceivers()
+sendMessage()
+start()
+stop()
}
class Peer {
+addEventListener()
+close()
+getTransceivers()
+addTrack()
+addTransceiver()
+createDataChannel()
+getStats()
+onGotDescription()
+onGotCandidate()
}
RenderStreaming --> Peer : "管理/路由"
```
图表来源
- [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/renderstreaming.js:11-317](file://client/src/renderstreaming.js#L11-L317)
### RTCPeerConnection 封装Peer
- 协商流程
- onnegotiationneeded 自动生成 offer 并通过事件上报;收到远端 offer 后 setRemoteDescription再 setLocalDescription 生成 answer。
- ICE 候选
- onicecandidate 上报候选,支持轮询重发 offer 以应对网络抖动。
- 断连检测
- iceConnectionState=failed 触发 disconnect 事件。
```mermaid
flowchart TD
Start(["开始"]) --> Negotiation["onNegotiationNeeded"]
Negotiation --> SetL["setLocalDescription() 生成 offer"]
SetL --> SendOffer["dispatchEvent('sendoffer')"]
SendOffer --> RecvOffer["收到远端 offer"]
RecvOffer --> SetR["setRemoteDescription(offer)"]
SetR --> SetL2["setLocalDescription() 生成 answer"]
SetL2 --> SendAnswer["dispatchEvent('sendanswer')"]
SendAnswer --> RecvAnswer["收到远端 answer"]
RecvAnswer --> Stable["signalingState=stable"]
Stable --> Track["ontrack -> trackevent"]
Track --> End(["结束"])
```
图表来源
- [client/src/peer.js:57-173](file://client/src/peer.js#L57-L173)
章节来源
- [client/src/peer.js:3-188](file://client/src/peer.js#L3-L188)
### 信令Signaling
- HTTP 轮询
- start() 循环拉取消息队列,分发 connect/disconnect/offer/answer/candidate/on-message。
- WebSocket
- WebSocketSignaling 通过 ws/wss 通道推送消息,支持广播与多参与方路由。
```mermaid
sequenceDiagram
participant RS as "RenderStreaming"
participant HTTP as "Signaling(HTTP)"
participant WS as "WebSocketSignaling"
RS->>HTTP : PUT /signaling/connection
HTTP-->>RS : connect(connectId, polite)
RS->>HTTP : POST /signaling/offer|answer|candidate
HTTP-->>RS : 轮询返回消息
RS->>WS : createConnection/sendOffer...
WS-->>RS : offer/answer/candidate/on-message
```
图表来源
- [client/src/signaling.js:30-149](file://client/src/signaling.js#L30-L149)
- [client/src/signaling.js:230-291](file://client/src/signaling.js#L230-L291)
章节来源
- [client/src/signaling.js:3-292](file://client/src/signaling.js#L3-L292)
### 输入遥测与渲染Input Remoting + Renderer
- 输入遥测
- Sender 负责捕获鼠标/键盘/触摸/手柄事件,通过 PointerCorrector 校正坐标,打包为 StateEvent/TextEvent经 RTCDataChannel 发送。
- 渲染器
- Renderer 将状态映射到 DOM设置 video.srcObject、占位符切换、分辨率适配、网络质量指示与用户列表。
```mermaid
sequenceDiagram
participant UI as "页面"
participant SEN as "Sender"
participant IR as "InputRemoting"
participant SIG as "Signaling"
participant REN as "Renderer"
UI->>SEN : 鼠标/键盘/触摸/手柄事件
SEN->>IR : StateEvent/TextEvent
IR->>SIG : RTCDataChannel 发送
SIG-->>UI : on-message 回传可选
UI->>REN : 状态变更
REN-->>UI : 设置 video.srcObject / 占位符
```
图表来源
- [client/src/sender.js:14-188](file://client/src/sender.js#L14-L188)
- [client/src/inputremoting.js:63-169](file://client/src/inputremoting.js#L63-L169)
- [client/public/onebyone/renderer.js:397-604](file://client/public/onebyone/renderer.js#L397-L604)
章节来源
- [client/src/inputdevice.js:1-719](file://client/src/inputdevice.js#L1-L719)
- [client/src/inputremoting.js:1-300](file://client/src/inputremoting.js#L1-L300)
- [client/src/pointercorrect.js:1-125](file://client/src/pointercorrect.js#L1-L125)
- [client/src/sender.js:14-188](file://client/src/sender.js#L14-L188)
- [client/public/onebyone/renderer.js:28-800](file://client/public/onebyone/renderer.js#L28-L800)
## 依赖关系分析
- 前端依赖
- RenderStreaming 依赖 Peer 与 SignalingPeer 依赖浏览器 WebRTC APIRenderer 依赖 DOM 与媒体轨道。
- 后端依赖
- Express 应用启动,按配置选择 WebSocket 或 HTTP 信令;日志与选项解析来自独立模块。
```mermaid
graph LR
RS["RenderStreaming"] --> PEER["Peer"]
RS --> SIG["Signaling"]
PEER --> BR["浏览器 WebRTC API"]
SIG --> WS["WebSocket 服务"]
REN["Renderer"] --> DOM["DOM/VideoElement"]
APP["Express 应用"] --> WS
```
图表来源
- [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/public/onebyone/renderer.js:28-800](file://client/public/onebyone/renderer.js#L28-L800)
- [src/index.ts:13-109](file://src/index.ts#L13-L109)
章节来源
- [src/index.ts:13-109](file://src/index.ts#L13-L109)
- [package.json:14-46](file://package.json#L14-L46)
## 性能考量
- 缓冲与丢帧
- 使用 ontrack 事件及时设置 video.srcObject避免重复赋值导致的播放中断监听视频轨道 resize 事件动态调整显示尺寸。
- 延迟控制
- 通过 WebSocket 信令降低 HTTP 轮询延迟Peer 内部定时重发 offer提升握手成功率。
- 带宽与质量
- 通过 getStats 获取 ICE/媒体统计,结合 Renderer 的网络质量指示,辅助进行自适应策略(例如降分辨率/帧率)。
- 渲染优化
- 使用 object-fit 与容器宽高比计算,减少重绘;仅在必要时切换占位符,避免频繁 DOM 更新。
章节来源
- [client/public/onebyone/renderer.js:575-604](file://client/public/onebyone/renderer.js#L575-L604)
- [client/src/peer.js:75-82](file://client/src/peer.js#L75-L82)
- [client/src/peer.js:124-130](file://client/src/peer.js#L124-L130)
## 故障排查指南
- 无法建立连接
- 检查 Signaling.start() 是否成功;确认 connect/disconnect 事件是否触发;核对 sessionId 与连接 ID。
- 协商失败
- 关注 Peer 的 onnegotiationneeded 与 offer/answer 流程;确认 ignoreOffer 条件与 signalingState。
- ICE 候选异常
- 核验 onicecandidate 事件是否上报;确认 addIceCandidate 的调用时机与错误日志。
- 渲染无画面
- 检查 video.srcObject 是否设置;确认 trackevent 是否到达;关注占位符切换逻辑。
- 日志与调试
- 使用 Logger.enable() 开启调试输出;通过 getStats 输出详细统计信息。
章节来源
- [client/src/signaling.js:30-91](file://client/src/signaling.js#L30-L91)
- [client/src/peer.js:57-173](file://client/src/peer.js#L57-L173)
- [client/src/logger.js:1-30](file://client/src/logger.js#L1-L30)
- [client/public/onebyone/renderer.js:397-406](file://client/public/onebyone/renderer.js#L397-L406)
## 结论
本模块以 RenderStreaming 为核心,串联信令、协商与渲染三大环节,形成稳定高效的 WebRTC 渲染流处理框架。通过清晰的事件路由、完善的统计接口与直观的 UI 渲染器,既能满足多参与方场景,也能在复杂网络条件下保持良好的用户体验。建议在生产环境中结合 getStats 实施自适应策略,并持续优化渲染器的 DOM 更新频率与媒体轨道处理路径。
## 附录
### 渲染流配置与参数
- 分辨率与帧率
- 通过视频轨道的 getSettings 获取 width/height在渲染器中根据宽高比调整显示尺寸。
- 编码参数
- 通过 MediaStreamConstraints 与 RTCPeerConnection 的配置对象传递;具体编码参数取决于浏览器与对端支持。
- 数据通道
- 使用 createDataChannel 发送输入事件;注意通道状态与 readyState。
章节来源
- [client/public/onebyone/renderer.js:781-791](file://client/public/onebyone/renderer.js#L781-L791)
- [client/src/peer.js:116-122](file://client/src/peer.js#L116-L122)
### 媒体轨道管理
- 音频/视频分离
- addTrack/addTransceiver 支持分别添加音频与视频轨道Renderer 依据轨道数量决定占位符与播放行为。
- 质量自适应
- 结合 getStats 的比特率、丢包与 RTT 指标,动态调整轨道方向或发送参数。
章节来源
- [client/src/peer.js:100-114](file://client/src/peer.js#L100-L114)
- [client/public/onebyone/renderer.js:575-604](file://client/public/onebyone/renderer.js#L575-L604)
### 事件处理与调试示例(路径指引)
- 渲染流事件
- [client/test/renderstreaming.test.js:78-133](file://client/test/renderstreaming.test.js#L78-L133)
- Peer 协商事件
- [client/test/peerconnection.test.js:43-104](file://client/test/peerconnection.test.js#L43-L104)
- 输入事件打包
- [client/src/inputremoting.js:138-141](file://client/src/inputremoting.js#L138-L141)
- 视频渲染设置
- [client/public/onebyone/renderer.js:397-406](file://client/public/onebyone/renderer.js#L397-L406)