# 客户端示例 **本文档引用的文件** - [client/public/index.html](file://client/public/index.html) - [client/public/bidirectional/index.html](file://client/public/bidirectional/index.html) - [client/public/bidirectional/js/main.js](file://client/public/bidirectional/js/main.js) - [client/public/bidirectional/js/sendvideo.js](file://client/public/bidirectional/js/sendvideo.js) - [client/public/receiver/index.html](file://client/public/receiver/index.html) - [client/public/receiver/js/main.js](file://client/public/receiver/js/main.js) - [client/public/multiplay/index.html](file://client/public/multiplay/index.html) - [client/public/multiplay/js/main.js](file://client/public/multiplay/js/main.js) - [client/public/onebyone/index.html](file://client/public/onebyone/index.html) - [client/public/onebyone/main.js](file://client/public/onebyone/main.js) - [client/public/onebyone/store.js](file://client/public/onebyone/store.js) - [client/public/onebyone/renderer.js](file://client/public/onebyone/renderer.js) - [client/public/onebyone/chatmessage.js](file://client/public/onebyone/chatmessage.js) - [client/public/onebyone/utils.js](file://client/public/onebyone/utils.js) - [client/public/videoplayer/index.html](file://client/public/videoplayer/index.html) - [client/public/videoplayer/js/main.js](file://client/public/videoplayer/js/main.js) - [client/public/videoplayer/js/video-player.js](file://client/public/videoplayer/js/video-player.js) - [client/public/videoplayer/js/register-events.js](file://client/public/videoplayer/js/register-events.js) - [client/public/js/config.js](file://client/public/js/config.js) - [client/public/js/icesettings.js](file://client/public/js/icesettings.js) - [client/public/js/stats.js](file://client/public/js/stats.js) - [client/public/js/videoplayer.js](file://client/public/js/videoplayer.js) - [client/src/sender.js](file://client/src/sender.js) - [client/src/signaling.js](file://client/src/signaling.js) - [client/src/peer.js](file://client/src/peer.js) ## 目录 1. [简介](#简介) 2. [项目结构](#项目结构) 3. [核心组件](#核心组件) 4. [架构总览](#架构总览) 5. [详细组件分析](#详细组件分析) 6. [依赖关系分析](#依赖关系分析) 7. [性能考量](#性能考量) 8. [故障排查指南](#故障排查指南) 9. [结论](#结论) 10. [附录](#附录) ## 简介 本仓库提供一套基于 WebRTC 的客户端示例系统,涵盖以下典型场景: - 双向视频通信:本地采集音视频,同时接收远端流,适合需要双向互动的场景。 - 单向视频接收(广播):仅接收来自服务器的渲染流,适合“观看者”场景。 - 多客户端播放(Guest 模式):多个客户端可共同观看同一渲染流。 - 视频播放器控制(WebBrowserInput):在浏览器中接收 Unity 渲染的摄像头画面,并通过数据通道将输入事件回传给服务器。 这些示例统一采用模块化架构,通过信令层协调连接建立、媒体轨道处理与 UI 渲染,便于集成到自有项目中作为参考或基线。 ## 项目结构 客户端示例主要分为两部分: - public 目录:各示例页面及其资源(HTML/CSS/JS),每个示例独立运行。 - src 目录:通用的输入遥测、信令与 Peer 连接封装,供示例复用。 ```mermaid graph TB subgraph "示例页面" BI["双向示例
bidirectional/index.html"] RCV["接收示例
receiver/index.html"] MP["多播放示例
multiplay/index.html"] VP["播放器示例
videoplayer/index.html"] OB1["一对一通话示例
onebyone/index.html"] end subgraph "公共脚本" CFG["配置与ICE
js/config.js, js/icesettings.js"] STATS["统计信息
js/stats.js"] VID["视频播放器抽象
js/videoplayer.js"] end subgraph "核心模块" SIG["信令层
src/signaling.js"] PEER["Peer连接封装
src/peer.js"] SENDER["输入遥测发送器
src/sender.js"] end BI --- CFG RCV --- CFG MP --- CFG VP --- CFG OB1 --- CFG BI --- SIG RCV --- SIG MP --- SIG VP --- SIG OB1 --- SIG BI --- PEER RCV --- PEER MP --- PEER VP --- PEER OB1 --- PEER VP --- SENDER VP --- VID ``` 图表来源 - [client/public/bidirectional/index.html:1-84](file://client/public/bidirectional/index.html#L1-L84) - [client/public/receiver/index.html:1-54](file://client/public/receiver/index.html#L1-L54) - [client/public/multiplay/index.html:1-54](file://client/public/multiplay/index.html#L1-L54) - [client/public/videoplayer/index.html:1-38](file://client/public/videoplayer/index.html#L1-L38) - [client/public/onebyone/index.html:1-615](file://client/public/onebyone/index.html#L1-L615) - [client/public/js/config.js](file://client/public/js/config.js) - [client/public/js/icesettings.js](file://client/public/js/icesettings.js) - [client/public/js/stats.js](file://client/public/js/stats.js) - [client/public/js/videoplayer.js](file://client/public/js/videoplayer.js) - [client/src/signaling.js:1-292](file://client/src/signaling.js#L1-L292) - [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) 章节来源 - [client/public/index.html:1-78](file://client/public/index.html#L1-L78) ## 核心组件 - 配置与 ICE 管理:负责读取服务器配置、选择信令协议(HTTP 或 WebSocket)、管理 STUN/TURN 列表。 - 信令层:封装 HTTP 与 WebSocket 两种信令方式,统一发布/订阅事件,屏蔽连接细节。 - Peer 封装:对 RTCPeerConnection 的封装,处理 offer/answer、ICE 候选、轨道事件与统计。 - 输入遥测:将鼠标、键盘、手柄、触摸等输入事件序列化并通过数据通道发送至服务器。 - 视频播放器抽象:统一视频元素创建、缩放、全屏、输入事件注册等行为。 章节来源 - [client/public/js/config.js](file://client/public/js/config.js) - [client/public/js/icesettings.js](file://client/public/js/icesettings.js) - [client/src/signaling.js:1-292](file://client/src/signaling.js#L1-L292) - [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) - [client/public/js/videoplayer.js](file://client/public/js/videoplayer.js) ## 架构总览 所有示例均遵循相同的控制流:初始化配置 → 选择信令 → 建立连接 → 添加媒体轨道 → 渲染远端流 → 统计与错误处理。 ```mermaid sequenceDiagram participant UI as "示例页面" participant CFG as "配置/ICE" participant SIG as "信令层(HTTP/WebSocket)" participant PEER as "Peer封装" participant REM as "远端Peer" UI->>CFG : 读取服务器配置/ICE服务器 UI->>SIG : start()/连接信令 UI->>PEER : start()/createConnection(id) PEER->>SIG : 发布offer/answer/candidate SIG-->>PEER : 下发offer/answer/candidate PEER->>PEER : setLocal/RemoteDescription PEER->>PEER : addIceCandidate PEER-->>UI : onTrack/onDataChannel UI->>UI : 渲染远端流/注册输入事件 ``` 图表来源 - [client/public/bidirectional/js/main.js:146-184](file://client/public/bidirectional/js/main.js#L146-L184) - [client/public/receiver/js/main.js:75-88](file://client/public/receiver/js/main.js#L75-L88) - [client/public/multiplay/js/main.js:82-95](file://client/public/multiplay/js/main.js#L82-L95) - [client/src/signaling.js:30-97](file://client/src/signaling.js#L30-L97) - [client/src/peer.js:57-82](file://client/src/peer.js#L57-L82) ## 详细组件分析 ### 双向视频通信(Bidirectional) - 功能要点 - 本地采集音视频,选择设备与分辨率,支持自定义宽高。 - 建立 WebRTC 连接,添加本地轨道为 sendonly,接收远端轨道并渲染。 - 支持编解码器偏好设置,按秒输出统计信息,显示本地/远端分辨率。 - 提示:Public 模式不工作,需在 Private 模式下运行。 - 关键流程 - 设备枚举与分辨率选择 - 连接建立与轨道添加 - 编解码器偏好设置 - 统计信息轮询与展示 - UI 交互 - 开始采集 → 设置连接 → 挂断清理 - 编解码器选择禁用/启用 - 本地/远端视频统计显示 ```mermaid sequenceDiagram participant UI as "双向页面" participant SV as "SendVideo" participant RS as "RenderStreaming" participant SIG as "信令(HTTP/WebSocket)" participant PC as "Peer封装" UI->>SV : startLocalVideo(设备, 分辨率) UI->>RS : start()/createConnection(id) RS->>PC : onConnect回调 PC->>PC : addTransceiver(本地轨道, direction='sendonly') PC->>SIG : 发布offer/answer/candidate SIG-->>PC : 下发offer/answer/candidate PC-->>UI : onTrack(远端轨道) UI->>SV : addRemoteTrack(渲染) UI->>PC : setCodecPreferences(可选) UI->>UI : 每秒统计展示 ``` 图表来源 - [client/public/bidirectional/js/main.js:112-184](file://client/public/bidirectional/js/main.js#L112-L184) - [client/public/bidirectional/js/sendvideo.js](file://client/public/bidirectional/js/sendvideo.js) - [client/src/signaling.js:152-292](file://client/src/signaling.js#L152-L292) - [client/src/peer.js:108-130](file://client/src/peer.js#L108-L130) 章节来源 - [client/public/bidirectional/index.html:1-84](file://client/public/bidirectional/index.html#L1-L84) - [client/public/bidirectional/js/main.js:1-383](file://client/public/bidirectional/js/main.js#L1-L383) ### 单向视频接收(Receiver) - 功能要点 - 点击播放按钮后创建视频播放器,建立连接并接收渲染流。 - 支持编解码器偏好设置,提供光标锁定到播放器区域的选项。 - 断开连接时清理播放器与统计信息,恢复播放按钮。 - 关键流程 - 点击播放 → 创建播放器 → 建立连接 → onTrack 添加轨道 → 输入通道设置 - 断开时清理并重置 UI ```mermaid sequenceDiagram participant UI as "接收页面" participant VP as "VideoPlayer" participant RS as "RenderStreaming" participant SIG as "信令(HTTP/WebSocket)" UI->>VP : createPlayer(容器, 锁定选项) UI->>RS : start()/createConnection() RS->>SIG : 发布/订阅信令 SIG-->>RS : offer/answer/candidate RS-->>UI : onTrack -> VP.addTrack UI->>VP : setupInput(数据通道) UI->>UI : 统计展示/断开清理 ``` 图表来源 - [client/public/receiver/js/main.js:67-108](file://client/public/receiver/js/main.js#L67-L108) - [client/public/js/videoplayer.js](file://client/public/js/videoplayer.js) - [client/src/signaling.js:30-97](file://client/src/signaling.js#L30-L97) 章节来源 - [client/public/receiver/index.html:1-54](file://client/public/receiver/index.html#L1-L54) - [client/public/receiver/js/main.js:1-186](file://client/public/receiver/js/main.js#L1-L186) ### 多客户端播放(Multiplay) - 功能要点 - 与接收示例类似,但额外创建名为 "multiplay" 的数据通道,用于多客户端标签同步等场景。 - 打开通道后延时发送一条包含类型与参数的消息,演示数据通道的使用。 - 关键流程 - 建立连接 → 创建 "input" 与 "multiplay" 数据通道 → onOpenMultiplayChannel 发送消息 ```mermaid sequenceDiagram participant UI as "多播放页面" participant VP as "VideoPlayer" participant RS as "RenderStreaming" participant DC as "数据通道(input/multiplay)" UI->>VP : createPlayer(容器, 锁定选项) UI->>RS : start()/createConnection() RS-->>UI : onConnect UI->>DC : createDataChannel("input") UI->>DC : createDataChannel("multiplay") DC-->>UI : onopen UI->>DC : send({type, argument}) UI->>UI : 统计展示/断开清理 ``` 图表来源 - [client/public/multiplay/js/main.js:97-125](file://client/public/multiplay/js/main.js#L97-L125) - [client/public/js/videoplayer.js](file://client/public/js/videoplayer.js) - [client/src/signaling.js:243-290](file://client/src/signaling.js#L243-L290) 章节来源 - [client/public/multiplay/index.html:1-54](file://client/public/multiplay/index.html#L1-L54) - [client/public/multiplay/js/main.js:1-204](file://client/public/multiplay/js/main.js#L1-L204) ### 视频播放器控制(WebBrowserInput) - 功能要点 - 点击播放后创建主视频与缩略图元素,注册游戏手柄、键盘、鼠标事件。 - 通过数据通道将点击事件与输入事件发送至服务器,实现“在浏览器中操作 Unity 摄像头”的效果。 - 支持全屏切换与自动尺寸调整。 - 关键流程 - 点击播放 → 创建元素 → setupConnection → 注册事件 → 发送输入事件 ```mermaid sequenceDiagram participant UI as "播放器页面" participant VP as "VideoPlayer" participant SE as "输入遥测(sender)" participant SIG as "信令(HTTP/WebSocket)" UI->>VP : setupConnection(使用WebSocket?) UI->>SE : registerGamepad/Keyboard/Mouse SE->>SIG : 通过数据通道发送事件 UI->>UI : 全屏切换/尺寸调整 ``` 图表来源 - [client/public/videoplayer/js/main.js:49-142](file://client/public/videoplayer/js/main.js#L49-L142) - [client/public/videoplayer/js/video-player.js](file://client/public/videoplayer/js/video-player.js) - [client/public/videoplayer/js/register-events.js](file://client/public/videoplayer/js/register-events.js) - [client/src/sender.js:14-209](file://client/src/sender.js#L14-L209) 章节来源 - [client/public/videoplayer/index.html:1-38](file://client/public/videoplayer/index.html#L1-L38) - [client/public/videoplayer/js/main.js:1-157](file://client/public/videoplayer/js/main.js#L1-L157) ### 一对一视频通话(One-by-one) - 功能要点 - 使用模块化架构:store 管理状态,renderer 负责 UI 渲染,chatmessage 管理聊天,utils 提供工具函数。 - 支持媒体状态切换(音频/视频/录制)、分辨率切换、侧边栏与通知、通话请求弹窗等。 - 通过 API 与 WebSocket 事件驱动 UI 更新与业务流程。 - 关键流程 - 页面加载 → 读取本地连接ID → joinCall → setUp → 绑定事件 → 渲染头部标题 ```mermaid sequenceDiagram participant Page as "一对一页面" participant Store as "状态管理(store)" participant Renderer as "UI渲染(renderer)" participant Chat as "聊天(chatmessage)" participant Utils as "工具(utils)" Page->>Store : joinCall(connectionId) Page->>Store : setUp(connectionId) Page->>Renderer : renderHeaderTitle() Page->>Page : 绑定DOM事件/快捷键 Page->>Chat : bindMessageEvents() Page->>Utils : showNotification(...) ``` 图表来源 - [client/public/onebyone/main.js:179-212](file://client/public/onebyone/main.js#L179-L212) - [client/public/onebyone/store.js](file://client/public/onebyone/store.js) - [client/public/onebyone/renderer.js](file://client/public/onebyone/renderer.js) - [client/public/onebyone/chatmessage.js](file://client/public/onebyone/chatmessage.js) - [client/public/onebyone/utils.js](file://client/public/onebyone/utils.js) 章节来源 - [client/public/onebyone/index.html:1-615](file://client/public/onebyone/index.html#L1-L615) - [client/public/onebyone/main.js:1-216](file://client/public/onebyone/main.js#L1-L216) ## 依赖关系分析 - 示例页面依赖公共配置与 ICE 设置,以及核心模块(信令、Peer、输入遥测、视频播放器抽象)。 - 一对一通话示例采用分层模块(store/renderer/chat/utils),降低耦合度,提升可维护性。 - 信令层同时支持 HTTP 与 WebSocket,通过统一事件接口屏蔽差异。 ```mermaid graph LR BI["双向示例"] --> CFG["配置/ICE"] RCV["接收示例"] --> CFG MP["多播放示例"] --> CFG VP["播放器示例"] --> CFG OB1["一对一示例"] --> CFG BI --> SIG["信令(HTTP/WebSocket)"] RCV --> SIG MP --> SIG VP --> SIG OB1 --> SIG BI --> PEER["Peer封装"] RCV --> PEER MP --> PEER VP --> PEER OB1 --> PEER VP --> SENDER["输入遥测(sender)"] VP --> VID["视频播放器抽象"] ``` 图表来源 - [client/public/js/config.js](file://client/public/js/config.js) - [client/public/js/icesettings.js](file://client/public/js/icesettings.js) - [client/src/signaling.js:1-292](file://client/src/signaling.js#L1-L292) - [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) - [client/public/js/videoplayer.js](file://client/public/js/videoplayer.js) 章节来源 - [client/public/js/config.js](file://client/public/js/config.js) - [client/src/signaling.js:1-292](file://client/src/signaling.js#L1-L292) - [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) ## 性能考量 - 分辨率与编解码器 - 示例提供多种预设分辨率,支持自定义分辨率;可通过编解码器偏好减少带宽占用。 - 建议根据网络状况动态调整分辨率与编解码器,避免过高码率导致卡顿。 - 统计信息 - 每秒轮询统计信息,可用于监控丢包、延迟与分辨率变化,便于前端提示与自动调节。 - 输入事件 - 输入遥测通过数据通道发送,建议合并事件与节流发送,降低信令压力。 - 全屏与缩放 - 全屏切换与窗口 resize 时及时调整视频尺寸,避免重绘开销过大。 ## 故障排查指南 - Public/Private 模式限制 - 双向示例在 Public 模式下不工作;接收/多播放示例在 Private 模式下不工作。请根据示例页面警告提示切换模式。 - 信令协议选择 - 若使用 WebSocket 信令,请确保服务端已正确配置;若使用 HTTP 信令,请确认会话创建与轮询接口可用。 - ICE 服务器 - 若无法建立连接,检查 STUN/TURN 服务器配置与网络策略;可在页面 ICE 配置区添加/移除/重置服务器。 - 编解码器不支持 - 部分浏览器不支持设置编解码器偏好;若出现相关提示,请降级处理或更换浏览器。 - 断线与重连 - ICE 失败会触发断开事件;示例会在断开时清理资源并提示消息。请检查网络稳定性与防火墙设置。 章节来源 - [client/public/bidirectional/js/main.js:99-105](file://client/public/bidirectional/js/main.js#L99-L105) - [client/public/receiver/js/main.js:48-54](file://client/public/receiver/js/main.js#L48-L54) - [client/public/multiplay/js/main.js:55-61](file://client/public/multiplay/js/main.js#L55-L61) - [client/public/js/icesettings.js](file://client/public/js/icesettings.js) - [client/src/signaling.js:30-97](file://client/src/signaling.js#L30-L97) ## 结论 该客户端示例系统提供了从基础接收、双向通信到复杂输入遥测与 UI 管理的完整参考。其模块化设计与统一的信令抽象,使得开发者可以快速将示例中的关键模式(如连接建立、媒体轨道处理、数据通道输入、UI 渲染与状态管理)集成到自有项目中,并根据业务需求扩展功能。 ## 附录 - 快速开始 - 在浏览器中打开示例页面,根据页面提示选择模式(Public/Private)。 - 如需使用 TURN,请在 ICE 配置区添加 STUN/TURN 服务器。 - 对于需要输入控制的场景,确保数据通道可用且已注册相应事件。 - 集成建议 - 将公共配置与 ICE 设置抽取为独立模块,便于跨示例共享。 - 将信令层抽象为统一接口,支持 HTTP 与 WebSocket 两种实现。 - 将 Peer 封装与视频播放器抽象作为通用组件,按需组合到不同示例中。 - 对于复杂 UI(如一对一通话),采用分层模块(store/renderer/chat/utils)组织代码,提升可维护性。