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

437 lines
18 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>
**本文引用的文件**
- [models.js](file://client/public/onebyone/models.js)
- [store.js](file://client/public/onebyone/store.js)
- [renderer.js](file://client/public/onebyone/renderer.js)
- [connect.js](file://client/public/onebyone/connect/connect.js)
- [endcall.js](file://client/public/onebyone/endcall/endcall.js)
- [chatmessage.js](file://client/public/onebyone/chatmessage.js)
- [utils.js](file://client/public/onebyone/utils.js)
- [main.js](file://client/public/onebyone/main.js)
- [index.html](file://client/public/onebyone/index.html)
- [connect.html](file://client/public/onebyone/connect/connect.html)
- [config.js](file://client/public/js/config.js)
- [icesettings.js](file://client/public/js/icesettings.js)
</cite>
## 目录
1. [简介](#简介)
2. [项目结构](#项目结构)
3. [核心组件](#核心组件)
4. [架构总览](#架构总览)
5. [详细组件分析](#详细组件分析)
6. [依赖关系分析](#依赖关系分析)
7. [性能考量](#性能考量)
8. [故障排查指南](#故障排查指南)
9. [结论](#结论)
10. [附录](#附录)
## 简介
本项目是一对一视频通话示例,基于浏览器 WebRTC 技术实现点对点P2P视频通话包含连接建立、媒体协商、通话管理、聊天消息与用户界面等完整功能。本文档将深入解析代码架构涵盖数据模型、状态管理、视图渲染、连接流程与通话结束处理并提供扩展、定制与集成建议。
## 项目结构
客户端采用模块化组织,核心目录与文件如下:
- onebyone 目录:一对一通话主界面与相关模块
- models.js数据模型定义
- store.js状态管理与 WebRTC 会话控制
- renderer.js视图渲染器负责将状态映射到 DOM
- main.js应用入口绑定事件与初始化
- index.html主界面 HTML 模板
- connect/:连接界面
- connect.html初始连接界面
- connect.js连接界面逻辑
- endcall/:通话结束界面
- endcall.html结束界面
- endcall.js结束逻辑
- chatmessage.js聊天消息模块
- utils.js工具函数
- public/js通用配置与 ICE 设置
- config.js获取服务器配置与 RTC 配置
- icesettings.jsICE 服务器配置持久化与读取
```mermaid
graph TB
subgraph "客户端(onebyone)"
A["index.html<br/>主界面"]
B["main.js<br/>入口与事件绑定"]
C["store.js<br/>状态管理/WebRTC"]
D["renderer.js<br/>视图渲染"]
E["models.js<br/>数据模型"]
F["chatmessage.js<br/>聊天消息"]
G["utils.js<br/>工具函数"]
H["connect/connect.html<br/>连接界面"]
I["connect/connect.js<br/>连接逻辑"]
J["endcall/endcall.js<br/>结束逻辑"]
end
subgraph "公共配置"
K["config.js<br/>服务器/RTC配置"]
L["icesettings.js<br/>ICE服务器持久化"]
end
A --> B
B --> C
B --> D
B --> F
C --> D
C --> F
C --> E
C --> K
K --> L
H --> I
A --> J
```
图表来源
- [index.html](file://client/public/onebyone/index.html)
- [main.js](file://client/public/onebyone/main.js)
- [store.js](file://client/public/onebyone/store.js)
- [renderer.js](file://client/public/onebyone/renderer.js)
- [models.js](file://client/public/onebyone/models.js)
- [chatmessage.js](file://client/public/onebyone/chatmessage.js)
- [utils.js](file://client/public/onebyone/utils.js)
- [connect/connect.html](file://client/public/onebyone/connect/connect.html)
- [connect/connect.js](file://client/public/onebyone/connect/connect.js)
- [endcall/endcall.js](file://client/public/onebyone/endcall/endcall.js)
- [config.js](file://client/public/js/config.js)
- [icesettings.js](file://client/public/js/icesettings.js)
章节来源
- [index.html](file://client/public/onebyone/index.html)
- [main.js](file://client/public/onebyone/main.js)
- [store.js](file://client/public/onebyone/store.js)
- [renderer.js](file://client/public/onebyone/renderer.js)
- [models.js](file://client/public/onebyone/models.js)
- [chatmessage.js](file://client/public/onebyone/chatmessage.js)
- [utils.js](file://client/public/onebyone/utils.js)
- [connect/connect.html](file://client/public/onebyone/connect/connect.html)
- [connect/connect.js](file://client/public/onebyone/connect/connect.js)
- [endcall/endcall.js](file://client/public/onebyone/endcall/endcall.js)
- [config.js](file://client/public/js/config.js)
- [icesettings.js](file://client/public/js/icesettings.js)
## 核心组件
- 数据模型models.js
- 定义通话会话、本地/远端用户、媒体状态、聊天消息等类型与模拟数据
- 状态管理store.js
- 使用简单观察者模式管理应用状态,封装 WebRTC 连接、媒体轨道、编解码器偏好、编码参数、网络质量检测、音频活动检测、消息广播等
- 视图渲染renderer.js
- 将状态映射到 DOM支持多参与者网格、占位符、占位符切换、分辨率自适应、网络质量指示等
- 连接界面connect/connect.js
- 提供创建/加入通话、连接 ID 列表浏览、用户设置头像、昵称、ID、头像上传等功能
- 通话结束界面endcall/endcall.js
- 提供重新连接与离开选项
- 聊天消息chatmessage.js
- 负责消息的发送、接收、显示、未读计数与侧边栏切换
- 工具函数utils.js
- 时间格式化、通知、元素显示/隐藏、按钮状态切换等
- 应用入口main.js
- 初始化渲染器、绑定 DOM 事件、键盘快捷键、挂断确认对话框等
章节来源
- [models.js](file://client/public/onebyone/models.js)
- [store.js](file://client/public/onebyone/store.js)
- [renderer.js](file://client/public/onebyone/renderer.js)
- [connect/connect.js](file://client/public/onebyone/connect/connect.js)
- [endcall/endcall.js](file://client/public/onebyone/endcall/endcall.js)
- [chatmessage.js](file://client/public/onebyone/chatmessage.js)
- [utils.js](file://client/public/onebyone/utils.js)
- [main.js](file://client/public/onebyone/main.js)
## 架构总览
整体采用“状态驱动”的架构store.js 维护核心状态renderer.js 响应状态变化更新 UIWebRTC 通过 RenderStreaming 实例进行媒体协商与传输;聊天消息通过 WebSocket 或信令通道传递;配置通过 config.js 与 icesettings.js 提供 STUN/TURN 与媒体约束。
```mermaid
sequenceDiagram
participant U as "用户"
participant M as "main.js"
participant S as "store.js"
participant R as "renderer.js"
participant RS as "RenderStreaming(WebRTC)"
participant WS as "WebSocket/信令"
U->>M : 打开主界面
M->>S : 初始化并加入通话
S->>RS : 创建连接并启动
RS-->>S : 连接建立回调
S->>R : 通知 CALL_STATUS_CHANGE/ONGOING
S->>WS : 发送 user-info / media-state-changed
WS-->>S : 接收 chat-message / media-state-changed / user-info
S->>R : 通知 REMOTE_STREAM_OBTAINED / USER_LIST_UPDATE
R-->>U : 渲染远端视频/用户列表/网络质量
```
图表来源
- [main.js](file://client/public/onebyone/main.js)
- [store.js](file://client/public/onebyone/store.js)
- [renderer.js](file://client/public/onebyone/renderer.js)
## 详细组件分析
### 数据模型models.js
- 类型定义
- CallSession通话会话包含通话类型、状态、起始时间、时长、加密标志、本地/远端用户信息
- LocalUser/RemoteUser用户信息含媒体状态与网络质量
- MediaState音频/视频/屏幕共享/录屏/说话检测状态
- ChatMessage消息结构含发送者信息、内容、类型、时间戳与是否自已发送
- 模拟数据
- 提供 mockCallSession 与 mockMessages便于开发调试与演示
章节来源
- [models.js](file://client/public/onebyone/models.js)
### 状态管理store.js
- 核心职责
- 初始化与本地媒体流获取、媒体状态变更、WebRTC 连接建立与回调注册
- 编解码器偏好设置、视频编码参数动态调整、分辨率切换
- 网络质量检测、音频活动检测、统计信息输出
- 聊天消息广播、用户信息同步、成员列表广播
- 通话结束处理(挂断、清理、通知)
- 关键流程
- 连接建立_createSignalingAndRTC -> setUp -> _registerCallbacks -> _startConnection
- 媒体协商onNewPeer/addTransceiver/setCodecPreferences/setVideoEncodingParameters
- 状态通知notify -> renderer 渲染
- 媒体状态变化emitMediaStateChange -> WebSocket 广播
- 网络质量detectNetworkQuality -> 综合丢包率/抖动/RTT 评估
- 音频活动startActivityDetection -> VAD 检测
- 设计要点
- 观察者模式subscribe/notify 解耦状态与 UI
- 可扩展性:编解码器与编码参数策略可按平台能力扩展
- 容错性:轨道替换、占位符延迟通知、分辨率回退
```mermaid
classDiagram
class CallStateManager {
+state
+listeners
+init()
+setUp(connectionId)
+updateLocalMedia(type, value)
+hangUp()
+broadcastParticipantsList()
+setCodecPreferences(participantId)
+setVideoEncodingParameters(participantId)
+changeResolution(width, height)
+emitMediaStateChange()
+detectNetworkQuality()
+startActivityDetection(stream, options)
+showStatsMessage()
}
class UIRenderer {
+render(state, changes)
+renderRemoteStream(stream, connectionId, isHost)
+renderUserList(localUser, remoteUser, participants)
}
CallStateManager --> UIRenderer : "通知状态变化"
```
图表来源
- [store.js](file://client/public/onebyone/store.js)
- [renderer.js](file://client/public/onebyone/renderer.js)
章节来源
- [store.js](file://client/public/onebyone/store.js)
### 视图渲染renderer.js
- 渲染策略
- 基于变化类型分派渲染INIT、DURATION_UPDATE、LOCAL_MEDIA_CHANGE、REMOTE_STREAM_OBTAINED、REMOTE_MEDIA_CHANGE、USER_LIST_UPDATE、NETWORK_CHANGE、CALL_STATUS_CHANGE、CALL_ENDED、PARTICIPANT_LEFT、RESOLUTION_CHANGED
- 支持多参与者网格Host 端与单路远端视频Participant 端)
- 占位符与占位符切换:音频先到、视频后到时延迟通知,避免黑屏
- 网络质量指示:根据远端网络质量更新头部与侧边栏
- 分辨率自适应:监听视频轨道 resize 事件调整显示尺寸
- 交互与事件
- 绑定事件监听器(由 main.js 绑定),响应按钮与快捷键
- 侧边栏开关与未读计数联动
章节来源
- [renderer.js](file://client/public/onebyone/renderer.js)
- [index.html](file://client/public/onebyone/index.html)
### 连接建立connect/connect.js
- 功能
- 加入通话:校验连接 ID保存到本地存储跳转主界面
- 创建通话:生成随机连接 ID保存并跳转主界面
- 浏览连接 ID调用 /signaling/connection-ids 获取列表并展示
- 用户设置:昵称、头像、用户 ID支持头像上传/api/upload/avatar
- 交互
- 输入框回车触发加入
- 选择连接 ID 自动填充
- 设置菜单外点击关闭
章节来源
- [connect/connect.js](file://client/public/onebyone/connect/connect.js)
- [connect/connect.html](file://client/public/onebyone/connect/connect.html)
### 通话结束处理endcall/endcall.js
- 功能
- 重新连接:跳转主界面
- 离开:清除本地连接 ID回到连接界面
- 交互
- 页面加载时显示断开连接信息(连接 ID 与时间)
章节来源
- [endcall/endcall.js](file://client/public/onebyone/endcall/endcall.js)
### 聊天消息chatmessage.js
- 功能
- 消息状态管理:消息列表、未读计数、侧边栏开关
- 发送消息:构造消息对象,通过 store 发送到远端
- 接收消息handleChatMessage -> addMessage -> 通知 UI
- 图片消息:限制大小、读取为 DataURL、发送文件消息
- 未读通知:侧边栏关闭时累加未读,打开时清零
- 事件绑定
- sendMessage/handleChatSubmit/openImagePicker/handleImageUpload
章节来源
- [chatmessage.js](file://client/public/onebyone/chatmessage.js)
### 工具函数utils.js
- 功能
- formatTime/formatTimestamp时间格式化
- generateId生成唯一 ID
- showNotification通知组件显示与隐藏
- toggleElement/toggleButtonState元素与按钮状态切换
章节来源
- [utils.js](file://client/public/onebyone/utils.js)
### 应用入口main.js
- 功能
- 初始化渲染器与聊天模块
- 绑定 DOM 事件:静音/视频切换、录屏、更多选项、分辨率切换、结束通话确认
- 键盘快捷键Space 静音、Ctrl+V 切换视频
- 接收通话请求弹窗:接受/拒绝
- 页面加载后检查连接 ID初始化并启动 WebRTC 连接
- 交互
- 对话框事件绑定、更多选项菜单外点击关闭
章节来源
- [main.js](file://client/public/onebyone/main.js)
- [index.html](file://client/public/onebyone/index.html)
## 依赖关系分析
- 模块依赖
- main.js 依赖 store、renderer、chatmessage、utils
- store.js 依赖 models、config、icesettings、chatmessage、utils
- renderer.js 依赖 models、chatmessage、utils、store
- connect/connect.js 依赖 utils
- endcall/endcall.js 依赖 utils
- config.js 依赖 icesettings.js
- 外部依赖
- WebRTC APIgetUserMedia、RTCPeerConnection、RTCRtpTransceiver
- WebSocket/信令通道(用于媒体状态、用户信息、聊天消息、参与者列表同步)
- 服务器接口:/config、/api/upload/avatar、/signaling/connection-ids
```mermaid
graph LR
main_js["main.js"] --> store_js["store.js"]
main_js --> renderer_js["renderer.js"]
main_js --> chat_js["chatmessage.js"]
store_js --> models_js["models.js"]
store_js --> config_js["config.js"]
store_js --> chat_js
renderer_js --> models_js
renderer_js --> chat_js
renderer_js --> utils_js["utils.js"]
store_js --> utils_js
connect_js["connect/connect.js"] --> utils_js
endcall_js["endcall/endcall.js"] --> utils_js
config_js --> icesettings_js["icesettings.js"]
```
图表来源
- [main.js](file://client/public/onebyone/main.js)
- [store.js](file://client/public/onebyone/store.js)
- [renderer.js](file://client/public/onebyone/renderer.js)
- [models.js](file://client/public/onebyone/models.js)
- [chatmessage.js](file://client/public/onebyone/chatmessage.js)
- [utils.js](file://client/public/onebyone/utils.js)
- [connect/connect.js](file://client/public/onebyone/connect/connect.js)
- [endcall/endcall.js](file://client/public/onebyone/endcall/endcall.js)
- [config.js](file://client/public/js/config.js)
- [icesettings.js](file://client/public/js/icesettings.js)
章节来源
- [main.js](file://client/public/onebyone/main.js)
- [store.js](file://client/public/onebyone/store.js)
- [renderer.js](file://client/public/onebyone/renderer.js)
- [models.js](file://client/public/onebyone/models.js)
- [chatmessage.js](file://client/public/onebyone/chatmessage.js)
- [utils.js](file://client/public/onebyone/utils.js)
- [connect/connect.js](file://client/public/onebyone/connect/connect.js)
- [endcall/endcall.js](file://client/public/onebyone/endcall/endcall.js)
- [config.js](file://client/public/js/config.js)
- [icesettings.js](file://client/public/js/icesettings.js)
## 性能考量
- 媒体轨道管理
- 音频先到、视频后到时延迟通知,避免黑屏与频繁 UI 刷新
- 替换视频轨道时保留音频轨道,减少资源开销
- 编解码器与编码参数
- 优先选择 AV1/VP9回退 H264提升压缩效率
- 根据采集分辨率动态设置最大比特率,平衡画质与带宽
- 网络质量检测
- 丢包率、抖动、RTT 综合评估,定期更新网络质量指示
- 统计信息
- 定时输出视频/音频统计,便于诊断与优化
- 分辨率切换
- 使用 applyConstraints 实时调整,避免重新获取流
章节来源
- [store.js](file://client/public/onebyone/store.js)
- [renderer.js](file://client/public/onebyone/renderer.js)
## 故障排查指南
- 无法获取本地媒体流
- 检查 getUserMedia 权限与约束;若失败,保持媒体状态关闭并通知 UI
- 远端视频黑屏
- 确认音频轨道先到时的延迟通知逻辑;检查轨道是否正确添加到 MediaStream
- 连接状态异常
- 检查 onConnect/onDisconnect 回调;确认信令通道正常
- 媒体状态不同步
- 确认 emitMediaStateChange 是否被调用;检查 onMessage 中 media-state-changed 分发
- 网络质量指示不更新
- 确认 startNetworkQualityDetection 是否启动;检查 detectNetworkQuality 统计字段
- 头像上传失败
- 检查文件类型与大小限制;确认 /api/upload/avatar 接口可用
章节来源
- [store.js](file://client/public/onebyone/store.js)
- [renderer.js](file://client/public/onebyone/renderer.js)
- [connect/connect.js](file://client/public/onebyone/connect/connect.js)
## 结论
本示例通过清晰的模块划分与状态驱动架构,实现了稳定的一对一视频通话体验。其关键优势在于:
- 状态与 UI 解耦,易于扩展与维护
- 完整的媒体协商与网络质量处理
- 丰富的聊天与用户信息同步机制
- 友好的用户界面与交互体验
建议在生产环境中进一步完善:
- 使用成熟的状态管理库(如 Redux/Pinia替代简易观察者模式
- 增强错误处理与重连机制
- 集成更多媒体能力检测与自适应策略
- 优化统计信息展示与告警机制
## 附录
### 开发指南:扩展与定制
- 扩展聊天功能
- 新增消息类型:在 ChatMessage 类型中扩展 type 字段,更新 chatmessage.js 的发送/接收逻辑
- 文件上传:参考 handleImageUpload 的流程,扩展更多文件类型与大小限制
- 自定义界面
- 修改 index.html 的布局与样式,注意与 renderer.js 的 DOM 选择器保持一致
- 新增控制按钮:在 main.js 绑定事件并在 store 中实现对应逻辑
- 集成其他服务
- 服务器配置:通过 /config 接口返回 useWebSocket 等配置store.js 中据此选择 WebSocketSignaling 或 Signaling
- ICE 服务器:通过 icesettings.js 的持久化配置,支持多 STUN/TURN 服务器
- WebRTC 优化
- 编解码器与编码参数:根据设备能力动态调整,提升兼容性与画质
- 分辨率与帧率:结合网络状况动态调整,保证流畅度
章节来源
- [models.js](file://client/public/onebyone/models.js)
- [store.js](file://client/public/onebyone/store.js)
- [renderer.js](file://client/public/onebyone/renderer.js)
- [chatmessage.js](file://client/public/onebyone/chatmessage.js)
- [config.js](file://client/public/js/config.js)
- [icesettings.js](file://client/public/js/icesettings.js)