Files
2026-05-16 13:24:02 +08:00

439 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.
# 项目概述
<cite>
**本文档引用的文件**
- [src/index.ts](file://src/index.ts)
- [src/server.ts](file://src/server.ts)
- [src/websocket.ts](file://src/websocket.ts)
- [src/class/websockethandler.ts](file://src/class/websockethandler.ts)
- [src/class/httphandler.ts](file://src/class/httphandler.ts)
- [src/signaling.ts](file://src/signaling.ts)
- [client/public/bidirectional/js/main.js](file://client/public/bidirectional/js/main.js)
- [client/public/onebyone/main.js](file://client/public/onebyone/main.js)
- [client/src/peer.js](file://client/src/peer.js)
- [client/src/sender.js](file://client/src/sender.js)
- [package.json](file://package.json)
- [client/package.json](file://client/package.json)
- [src/log.ts](file://src/log.ts)
- [src/class/options.ts](file://src/class/options.ts)
</cite>
## 目录
1. [简介](#简介)
2. [项目结构](#项目结构)
3. [核心组件](#核心组件)
4. [架构总览](#架构总览)
5. [详细组件分析](#详细组件分析)
6. [依赖分析](#依赖分析)
7. [性能考虑](#性能考虑)
8. [故障排查指南](#故障排查指南)
9. [结论](#结论)
10. [附录](#附录)
## 简介
Video Socket Server 是一个基于 WebRTC 的实时双向视频通信服务端与前端示例项目支持两种信令模式WebSocket 与 HTTP 轮询)与两种通信模式(公共模式与私有模式)。项目旨在为 Unity Render Streaming、远程视频监控、在线教育等场景提供低延迟、高可靠性的视频传输基础设施。
- 核心目标
- 提供稳定可靠的 WebRTC 信令与媒体转发能力
- 支持公共模式(广播式)与私有模式(点对点/一对多)
- 提供 WebSocket 与 HTTP 两种信令通道,适配不同网络环境
- 提供丰富的前端示例,覆盖双向视频通话、一对一通话、输入遥测等
- 技术定位
- 后端Node.js + TypeScript + Express.js
- 前端:原生 JavaScriptES Modules结合 WebRTC API
- 协议WebSocketws:// 或 wss://)与 HTTP RESTful 接口
- 数据结构Offer/Answer 与 ICE Candidate 的信令封装
- 主要应用场景
- Unity Render Streaming通过 WebRTC 实现远端渲染画面的低延迟传输
- 远程视频监控:支持多路摄像头与回放控制
- 在线教育:支持课堂互动、屏幕共享与聊天
**章节来源**
- [src/index.ts:13-109](file://src/index.ts#L13-L109)
- [src/server.ts:14-90](file://src/server.ts#L14-L90)
## 项目结构
项目采用前后端分离的组织方式:
- 后端src服务启动、HTTP 路由、WebSocket 信令、日志与配置
- 前端client静态资源与示例页面包含多个演示场景双向视频、一对一通话、输入遥测等
```mermaid
graph TB
subgraph "后端(src)"
IDX["入口: index.ts"]
SRV["HTTP服务: server.ts"]
WS["WebSocket信令: websocket.ts"]
WSH["WS处理器: class/websockethandler.ts"]
HTH["HTTP处理器: class/httphandler.ts"]
SIG["信令路由: signaling.ts"]
LOG["日志: log.ts"]
OPT["配置: class/options.ts"]
end
subgraph "前端(client)"
PUB["静态资源: public/*"]
SRC["模块: src/*"]
end
IDX --> SRV
SRV --> SIG
SRV --> PUB
SRV --> SRC
SRV --> WS
WS --> WSH
SIG --> HTH
IDX --> LOG
IDX --> OPT
```
**图表来源**
- [src/index.ts:13-109](file://src/index.ts#L13-L109)
- [src/server.ts:14-90](file://src/server.ts#L14-L90)
- [src/websocket.ts:6-118](file://src/websocket.ts#L6-L118)
- [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)
- [src/signaling.ts:1-25](file://src/signaling.ts#L1-L25)
**章节来源**
- [package.json:1-60](file://package.json#L1-L60)
- [client/package.json:1-19](file://client/package.json#L1-L19)
## 核心组件
- 服务入口与启动
- 解析命令行参数,创建 HTTP/HTTPS 服务器,根据配置选择信令模式
- 启动 WebSocket 信令或 HTTP 轮询信令
- HTTP 服务与静态资源
- 提供 /config 接口返回运行配置(是否使用 WebSocket、启动模式、日志级别
- 提供 /signaling 路由,挂载 HTTP 信令处理器
- 提供静态页面与模块资源,首页自动指向 client/public/index.html
- WebSocket 信令
- 监听连接、消息、关闭事件解析多种信令类型connect/disconnect/offer/answer/candidate/broadcast/ping/pong/call-request/on-message
- 将消息分派至 WS 处理器进行业务逻辑处理
- WS 处理器1对多/私有模式)
- 维护连接组host 与 participants支持广播与定向转发
- 处理 offer/answer/candidate 的路由与转发,支持 participantId 标识
- HTTP 信令处理器HTTP 轮询)
- 提供会话管理与连接管理接口,支持轮询获取信令消息
- 支持超时会话清理与断开连接记录
- 日志与配置
- 可配置日志级别,统一输出格式
- Options 接口定义运行参数(端口、证书、信令类型、通信模式、日志级别)
**章节来源**
- [src/index.ts:13-109](file://src/index.ts#L13-L109)
- [src/server.ts:14-90](file://src/server.ts#L14-L90)
- [src/websocket.ts:6-118](file://src/websocket.ts#L6-L118)
- [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)
- [src/signaling.ts:1-25](file://src/signaling.ts#L1-L25)
- [src/log.ts:1-51](file://src/log.ts#L1-L51)
- [src/class/options.ts:1-10](file://src/class/options.ts#L1-L10)
## 架构总览
系统采用“HTTP 服务 + WebSocket/HTTP 信令”的双信令架构,支持公共模式与私有模式两种通信策略。
```mermaid
graph TB
subgraph "客户端"
FE1["双向视频示例<br/>bidirectional/main.js"]
FE2["一对一通话示例<br/>onebyone/main.js"]
PEER["Peer类<br/>peer.js"]
SEND["输入遥测Sender<br/>sender.js"]
end
subgraph "服务端"
HTTP["HTTP服务<br/>server.ts"]
WS["WebSocket信令<br/>websocket.ts"]
WSH["WS处理器<br/>websockethandler.ts"]
HTH["HTTP处理器<br/>httphandler.ts"]
SIG["信令路由<br/>signaling.ts"]
end
FE1 --> |WebSocket/HTTP| HTTP
FE2 --> |WebSocket/HTTP| HTTP
HTTP --> SIG
HTTP --> WS
WS --> WSH
SIG --> HTH
FE1 --> PEER
FE2 --> PEER
FE1 --> SEND
```
**图表来源**
- [src/server.ts:14-90](file://src/server.ts#L14-L90)
- [src/websocket.ts:6-118](file://src/websocket.ts#L6-L118)
- [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)
- [src/signaling.ts:1-25](file://src/signaling.ts#L1-L25)
- [client/public/bidirectional/js/main.js:1-383](file://client/public/bidirectional/js/main.js#L1-L383)
- [client/public/onebyone/main.js:1-216](file://client/public/onebyone/main.js#L1-L216)
- [client/src/peer.js:1-188](file://client/src/peer.js#L1-L188)
- [client/src/sender.js:1-209](file://client/src/sender.js#L1-L209)
## 详细组件分析
### WebSocket 信令流程(序列图)
展示客户端通过 WebSocket 发送/接收信令的典型流程。
```mermaid
sequenceDiagram
participant C as "客户端"
participant WS as "WebSocket服务器"
participant H as "WS处理器"
C->>WS : "connect" 连接建立
WS->>H : "onConnect(connectionId)"
H-->>C : "connect" {connectionId, role, participantId}
C->>WS : "offer" {connectionId, sdp}
WS->>H : "onOffer(ws, message)"
H-->>C : "offer" 转发/广播
C->>WS : "answer" {connectionId, sdp}
WS->>H : "onAnswer(ws, message)"
H-->>C : "answer" 转发/广播
C->>WS : "candidate" {connectionId, candidate, sdpMLineIndex, sdpMid}
WS->>H : "onCandidate(ws, message)"
H-->>C : "candidate" 转发/广播
C->>WS : "disconnect" {connectionId}
WS->>H : "onDisconnect(ws, connectionId)"
H-->>C : "disconnect" 通知
```
**图表来源**
- [src/websocket.ts:65-114](file://src/websocket.ts#L65-L114)
- [src/class/websockethandler.ts:145-206](file://src/class/websockethandler.ts#L145-L206)
- [src/class/websockethandler.ts:214-338](file://src/class/websockethandler.ts#L214-L338)
- [src/class/websockethandler.ts:309-338](file://src/class/websockethandler.ts#L309-L338)
**章节来源**
- [src/websocket.ts:6-118](file://src/websocket.ts#L6-L118)
- [src/class/websockethandler.ts:1-479](file://src/class/websockethandler.ts#L1-L479)
### HTTP 信令轮询流程(序列图)
展示客户端通过 HTTP 轮询获取信令消息的流程。
```mermaid
sequenceDiagram
participant C as "客户端"
participant S as "HTTP服务"
participant R as "信令路由"
participant H as "HTTP处理器"
C->>S : "PUT /signaling" 创建会话
S->>R : "路由到 httphandler"
R->>H : "createSession()"
H-->>C : "{sessionId}"
C->>S : "PUT /signaling/connection" {connectionId}
S->>R : "路由到 httphandler"
R->>H : "createConnection()"
H-->>C : "{connectionId, polite}"
loop 轮询
C->>S : "GET /signaling/offer?fromtime=..."
S->>R : "路由到 httphandler"
R->>H : "getOffer(fromtime)"
H-->>C : "{offers}"
end
C->>S : "POST /signaling/offer" {sdp}
S->>R : "路由到 httphandler"
R->>H : "postOffer()"
H-->>C : "OK"
C->>S : "DELETE /signaling" 删除会话
S->>R : "路由到 httphandler"
R->>H : "deleteSession()"
H-->>C : "200"
```
**图表来源**
- [src/server.ts:25-89](file://src/server.ts#L25-L89)
- [src/signaling.ts:6-24](file://src/signaling.ts#L6-L24)
- [src/class/httphandler.ts:661-696](file://src/class/httphandler.ts#L661-L696)
- [src/class/httphandler.ts:268-318](file://src/class/httphandler.ts#L268-L318)
- [src/class/httphandler.ts:492-501](file://src/class/httphandler.ts#L492-L501)
- [src/class/httphandler.ts:549-558](file://src/class/httphandler.ts#L549-L558)
**章节来源**
- [src/server.ts:14-90](file://src/server.ts#L14-L90)
- [src/signaling.ts:1-25](file://src/signaling.ts#L1-L25)
- [src/class/httphandler.ts:1-800](file://src/class/httphandler.ts#L1-L800)
### 前端组件与 WebRTC 集成
- 双向视频示例bidirectional
- 通过 RenderStreaming 管理连接,动态选择 WebSocket 或 HTTP 信令
- 使用 Peer 类封装 RTCPeerConnection 生命周期与事件
- 使用 Sender 类实现鼠标/键盘/手柄/触摸的输入遥测与数据通道发送
- 一对一通话示例onebyone
- 基于 store/UIRenderer 的状态管理与 UI 渲染
- 支持通话请求、接听/拒接、媒体切换、录制控制等
```mermaid
classDiagram
class Peer {
+connectionId
+polite
+pc
+ontrack()
+ondatachannel()
+onicecandidate()
+onnegotiationneeded()
+getTransceivers()
+addTrack()
+addTransceiver()
+createDataChannel()
+getStats()
+onGotDescription()
+onGotCandidate()
}
class Sender {
+devices
+addMouse()
+addKeyboard()
+addGamepad()
+addTouchscreen()
+_queueStateEvent()
+_queueTextEvent()
}
class Observer {
+channel
+onNext(message)
}
Sender --> Observer : "通过数据通道发送"
Peer --> Sender : "配合输入遥测"
```
**图表来源**
- [client/src/peer.js:3-188](file://client/src/peer.js#L3-L188)
- [client/src/sender.js:14-209](file://client/src/sender.js#L14-L209)
**章节来源**
- [client/public/bidirectional/js/main.js:1-383](file://client/public/bidirectional/js/main.js#L1-L383)
- [client/public/onebyone/main.js:1-216](file://client/public/onebyone/main.js#L1-L216)
- [client/src/peer.js:1-188](file://client/src/peer.js#L1-L188)
- [client/src/sender.js:1-209](file://client/src/sender.js#L1-L209)
### 通信模式与连接组(流程图)
展示私有模式下的连接组管理与消息转发逻辑。
```mermaid
flowchart TD
Start(["进入 onConnect"]) --> CheckPrivate{"是否私有模式?"}
CheckPrivate --> |否| Public["公共模式: 创建连接组(若无)"]
CheckPrivate --> |是| Private["私有模式: host/参与者管理"]
Public --> BroadcastOffer["广播 offer 给其他客户端"]
Private --> HostCheck{"是否已有 host?"}
HostCheck --> |否| CreateHost["创建 host 并标记为 polite=false"]
HostCheck --> |是| AddParticipant["添加为 participant 并通知 host"]
OfferRoute{"消息来源角色"} --> |host| ToParticipants["转发给所有 participants"]
OfferRoute --> |participant| ToHost["转发给 host"]
AnswerRoute{"消息来源角色"} --> |host| ToTarget["转发给指定 participant"]
AnswerRoute --> |participant| ToHost2["转发给 host"]
CandidateRoute{"消息来源角色"} --> |host| ToParticipants2["转发给所有 participants"]
CandidateRoute --> |participant| ToHost3["转发给 host"]
```
**图表来源**
- [src/class/websockethandler.ts:145-206](file://src/class/websockethandler.ts#L145-L206)
- [src/class/websockethandler.ts:214-338](file://src/class/websockethandler.ts#L214-L338)
- [src/class/websockethandler.ts:309-338](file://src/class/websockethandler.ts#L309-L338)
**章节来源**
- [src/class/websockethandler.ts:1-479](file://src/class/websockethandler.ts#L1-L479)
## 依赖分析
- 后端依赖
- expressHTTP 服务框架
- wsWebSocket 服务器
- morganHTTP 访问日志
- cors/multer跨域与文件上传
- uuid会话 ID 生成
- commander命令行参数解析
- 前端依赖
- Jest开发单元测试
- ESLint开发代码规范
- 浏览器原生 WebRTC API
```mermaid
graph LR
P["package.json"] --> E["express"]
P --> W["ws"]
P --> M["morgan"]
P --> C["cors"]
P --> U["uuid"]
P --> CMD["commander"]
CP["client/package.json"] --> J["jest"]
CP --> ESL["eslint"]
```
**图表来源**
- [package.json:14-46](file://package.json#L14-L46)
- [client/package.json:9-18](file://client/package.json#L9-L18)
**章节来源**
- [package.json:1-60](file://package.json#L1-L60)
- [client/package.json:1-19](file://client/package.json#L1-L19)
## 性能考虑
- 信令模式选择
- WebSocket低延迟、高吞吐适合实时交互
- HTTP 轮询:兼容性更好,适合受限网络或代理环境
- 通信模式选择
- 私有模式host 与 participants 明确分离,便于控制与扩展
- 公共模式:广播式转发,适合简单场景但需注意带宽与 CPU 开销
- 日志与监控
- 可配置日志级别,避免生产环境过度输出
- 建议结合浏览器 WebRTC 统计 API 与服务端日志进行性能分析
- 媒体参数
- 合理设置分辨率、帧率与编解码器偏好,平衡画质与延迟
[本节为通用指导,无需具体文件分析]
## 故障排查指南
- 启动与证书
- HTTPS 启用需提供 server.key 与 server.cert可通过命令行参数指定路径
- 若证书缺失,服务将以 HTTP 方式启动
- 信令类型校验
- 仅支持 websocket 与 http 两种类型;非法值会被重置为 websocket
- WebSocket 心跳与断开
- 服务器内置心跳检测ping/pong长时间无活动将触发断开
- 客户端需正确处理断开事件并清理资源
- HTTP 会话超时
- 会话在指定时间内无请求将被清理,避免内存泄漏
- 客户端应定期轮询或及时释放会话
**章节来源**
- [src/index.ts:75-82](file://src/index.ts#L75-L82)
- [src/websocket.ts:95-113](file://src/websocket.ts#L95-L113)
- [src/class/httphandler.ts:218-232](file://src/class/httphandler.ts#L218-L232)
- [src/log.ts:1-51](file://src/log.ts#L1-L51)
## 结论
Video Socket Server 提供了完整的 WebRTC 信令与媒体传输方案,具备灵活的信令与通信模式选择、清晰的前后端分离架构,以及丰富的前端示例。通过合理配置与优化,可在多种实际场景中实现高质量的实时视频通信。
[本节为总结性内容,无需具体文件分析]
## 附录
- 快速启动
- 开发模式:执行脚本 dev启动 HTTPS 服务,监听指定端口
- 生产模式:构建后运行 build/index.js或使用打包工具
- 常用接口
- GET /config获取运行配置
- GET /signaling/connection-ids获取所有连接 ID
- PUT /signaling创建会话
- PUT /signaling/connection创建连接
- GET /signaling/offer|answer|candidate轮询获取信令
- POST /signaling/offer|answer|candidate推送信令
- DELETE /signaling删除会话
**章节来源**
- [src/server.ts:25-89](file://src/server.ts#L25-L89)
- [src/signaling.ts:6-24](file://src/signaling.ts#L6-L24)
- [package.json:5-12](file://package.json#L5-L12)