Files
webRtc/WebApp/client/public/onebyone/code-structure.md
2026-04-25 21:09:45 +08:00

459 lines
15 KiB
Markdown
Raw 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.
# onebyone 模块代码调用结构图
> 本文档基于优化后的代码自动生成,反映当前实际架构。
---
## 3.1 文件依赖关系图
```mermaid
graph TD
main[main.js] --> store[store.js]
main --> renderer[renderer.js]
main --> utils[utils.js]
main --> chatmsg[chatmessage.js]
store --> models[models.js]
store --> utils
store --> chatmsg
store --> signaling[../../module/signaling.js]
store --> rs[../../module/renderstreaming.js]
store --> config[../js/config.js]
renderer --> utils
renderer --> models
renderer --> chatmsg
renderer -.-> store
chatmsg --> utils
chatmsg --> store
chatmsg --> models
connect[connect/connect.js] --> store
connect --> utils
endcall[endcall/endcall.js] --> utils
index[index.html] --> main
connectHtml[connect/connect.html] --> connect
endcallHtml[endcall/endcall.html] --> endcall
style utils fill:#e1f5fe
style models fill:#e1f5fe
style signaling fill:#fff3e0
style rs fill:#fff3e0
style config fill:#fff3e0
```
**图例说明**
- 蓝色:内部工具/数据模块
- 橙色外部依赖模块signaling.js、renderstreaming.js、config.js
---
## 3.2 核心调用链
### 通话初始化流程
```mermaid
sequenceDiagram
autonumber
participant Browser
participant main as main.js
participant store as store.js
participant render as renderer.js
participant RS as RenderStreaming
participant Sig as Signaling
Browser->>main: DOMContentLoaded
main->>main: 检查 localStorage.connectionId
alt 无连接ID
main->>Browser: 跳转 connect/connect.html
else 有连接ID
main->>render: new UIRenderer(store)
render->>store: subscribe(render)
main->>store: joinCall(connectionId)
store->>store: init()
store->>store: setupConfig() / getServerConfig()
store->>store: loadUserSettings()
store->>store: getLocalStream()
store->>Browser: getUserMedia(MEDIA_CONSTRAINTS)
Browser-->>store: MediaStream
store->>store: notify(LOCAL_STREAM_OBTAINED)
store->>store: notify(LOCAL_MEDIA_CHANGE x2)
store->>store: emitMediaStateChange()
main->>store: setUp(connectionId)
store->>store: _createSignalingAndRTC()
store->>Sig: new WebSocketSignaling() / new Signaling()
store->>RS: new RenderStreaming(signaling, config)
store->>store: _registerCallbacks()
store->>store: _startConnection()
store->>RS: start()
store->>RS: createConnection(connectionId)
RS-->>store: onConnect(role, participantId)
store->>store: notify(CALL_STATUS_CHANGE, ongoing)
store->>store: sendMessage(user-info)
store->>store: emitMediaStateChange()
main->>main: bindDomEvents()
end
```
### 媒体控制流程
```mermaid
sequenceDiagram
autonumber
participant User
participant main as main.js
participant store as store.js
participant render as renderer.js
participant RS as RenderStreaming
participant Remote as 远端
User->>main: 点击 toggleMute / toggleVideo
main->>store: updateLocalMedia(type, value)
alt 开启视频
store->>Browser: getUserMedia(VIDEO_ONLY_CONSTRAINT)
Browser-->>store: newVideoTrack
store->>RS: replaceTrack / addTransceiver
store->>store: notify(LOCAL_STREAM_OBTAINED)
store->>store: notify(LOCAL_MEDIA_CHANGE, video=true)
store->>store: emitMediaStateChange()
else 关闭视频
store->>store: track.stop()
store->>store: notify(LOCAL_MEDIA_CHANGE, video=false)
store->>store: emitMediaStateChange()
else 切换音频
store->>store: track.enabled = value
store->>store: notify(LOCAL_MEDIA_CHANGE, audio=value)
store->>store: emitMediaStateChange()
end
store->>render: notify(USER_LIST_UPDATE)
render->>render: renderUserList()
render->>render: renderControlButtons()
render->>render: renderLocalVideo()
store->>RS: sendMessage(media-state-changed)
RS->>Remote: WebSocket 信令
Remote-->>store: onMessage(media-state-changed)
store->>store: updateRemoteMedia()
store->>render: notify(REMOTE_MEDIA_CHANGE)
render->>render: renderRemoteVideo()
render->>render: renderUserList()
render->>render: renderParticipantVideoPlaceholder()
```
### 消息发送流程
```mermaid
sequenceDiagram
autonumber
participant User
participant chat as chatmessage.js
participant store as store.js
participant render as renderer.js
participant RS as RenderStreaming
participant Remote as 远端
User->>chat: 输入消息 / 回车
chat->>chat: sendMessage()
chat->>chat: addMessage() 本地
chat->>chat: notify(NEW_MESSAGE)
render->>render: renderMessageState(NEW_MESSAGE)
render->>render: renderChatMessages()
render->>render: renderUnreadCount()
chat->>store: getRenderStreaming()
chat->>RS: sendMessage(chat-message)
RS->>Remote: WebSocket 信令
Remote-->>chat: handleChatMessage(data)
chat->>chat: addMessage() 远端
chat->>chat: notify(NEW_MESSAGE)
render->>render: renderMessageState(NEW_MESSAGE)
render->>render: renderChatMessages()
render->>render: renderUnreadCount()
User->>chat: 点击 toggleSidebar()
chat->>chat: notify(SIDEBAR_TOGGLE)
render->>render: renderMessageState(SIDEBAR_TOGGLE)
render->>render: renderSidebar()
```
### Participant 管理流程
```mermaid
sequenceDiagram
autonumber
participant store as store.js
participant render as renderer.js
participant RS as RenderStreaming
participant Remote as 远端Participant
Note over RS,Remote: 新 Participant 加入
RS-->>store: onParticipantJoined(participantId)
store->>store: 初始化 participant 默认信息
store->>store: notify(PARTICIPANTS_UPDATE)
store->>RS: broadcastParticipantsList()
render->>render: renderUserList()
render->>render: syncParticipantTileNames()
Note over RS,Remote: Participant 离开
RS-->>store: onParticipantLeft(participantId)
store->>store: 清理 remoteStreams / participants
store->>store: notify(PARTICIPANT_LEFT)
store->>store: notify(PARTICIPANTS_UPDATE)
store->>RS: broadcastParticipantsList()
render->>render: renderParticipantLeft()
render->>render: renderUserList()
Note over RS,Remote: 成员列表同步
RS-->>store: onMessage(participants-sync)
store->>store: 过滤自身条目 -> state.participants
store->>store: notify(PARTICIPANTS_UPDATE)
render->>render: renderUserList()
render->>render: syncParticipantTileNames()
```
---
## 3.3 状态变化流转图
### Store -> Renderer 状态流转
```mermaid
graph LR
subgraph StoreNotify[store.js notify 类型]
A[INIT]
B[LOCAL_STREAM_OBTAINED]
C[LOCAL_MEDIA_CHANGE]
D[REMOTE_STREAM_OBTAINED]
E[REMOTE_MEDIA_CHANGE]
F[USER_LIST_UPDATE]
G[PARTICIPANTS_UPDATE]
H[NETWORK_CHANGE]
I[CALL_STATUS_CHANGE]
J[CALL_ENDED]
K[PARTICIPANT_LEFT]
L[DURATION_UPDATE]
end
subgraph RenderMethod[renderer.js 渲染方法]
RM1[renderRemoteVideo]
RM2[renderLocalVideo]
RM3[renderLocalStream]
RM4[renderRemoteStream]
RM5[renderControlButtons]
RM6[renderUserList]
RM7[renderNetworkStatus]
RM8[renderCallStatus]
RM9[renderCallEnded]
RM10[renderParticipantLeft]
RM11[renderCallDuration]
RM12[renderHeader]
RM13[renderParticipantVideoPlaceholder]
RM14[syncParticipantTileNames]
end
A --> RM1 & RM2 & RM5 & RM6 & RM12
B --> RM3 & RM2
C --> RM5 & RM2 & RM6
D --> RM4
E --> RM1 & RM6 & RM13
F --> RM6
G --> RM6 & RM14
H --> RM7
I --> RM8
J --> RM9
K --> RM10
L --> RM11
```
### chatMessage -> Renderer 状态流转
```mermaid
graph LR
subgraph ChatNotify[chatmessage.js notify 类型]
N[NEW_MESSAGE]
S[SIDEBAR_TOGGLE]
end
subgraph MsgRender[renderer.js 消息渲染]
MR1[renderChatMessages]
MR2[renderUnreadCount]
MR3[renderSidebar]
end
N --> MR1 & MR2
S --> MR3 & MR2
```
---
## 3.4 各模块导出函数清单
### main.js
| 导出 | 类型 | 说明 |
|------|------|------|
| store | 变量 | 重新导出 store 单例,供外部调试使用 |
**内部全局函数(绑定到 window**
| 函数 | 说明 |
|------|------|
| toggleSidebar | 切换侧边栏显示 |
| toggleMute | 切换麦克风状态 |
| toggleVideo | 切换摄像头状态 |
| toggleLocalVideo | 本地视频悬停控制 |
| toggleRecording | 切换录屏状态 |
| endCall | 显示结束通话确认对话框 |
| cancelEndCall | 取消结束通话 |
| confirmEndCall | 确认结束通话,调用 store.endCall() |
| showCallRequest | 显示通话请求弹窗 |
| rejectCall | 拒绝通话请求 |
| acceptCall | 接受通话请求,初始化通话 |
### store.js (CallStateManager 类 / store 单例)
| 方法 | 说明 |
|------|------|
| subscribe(callback) | 订阅状态变化 |
| notify(changes) | 通知所有监听器 |
| init() | 初始化配置、用户设置、本地流 |
| loadUserSettings() | 从 localStorage 加载用户设置 |
| setupConfig() | 获取服务器配置WebSocket 模式) |
| getLocalStream() | 获取本地摄像头媒体流 |
| updateLocalMedia(mediaType, value) | 更新本地媒体状态(音频/视频/录屏) |
| _createSignalingAndRTC(connectionId) | 创建信令和 RTC 实例 |
| setUp(connectionId) | 设置 WebRTC 连接入口 |
| _registerCallbacks() | 注册所有 WebRTC 回调 |
| _startConnection(connectionId) | 启动连接和检测 |
| hangUp() | 挂断连接,清理资源 |
| sendMessage(type, data) | 通过 RenderStreaming 发送消息 |
| broadcastParticipantsList() | Host 端广播成员列表 |
| setCodecPreferences(participantId) | 设置 H264 编解码器偏好 |
| updateRemoteMedia(mediaState, participantId) | 更新远端媒体状态 |
| updateRemoteUserStatus(status) | 更新远端用户在线状态 |
| updateRemoteUserNetworkQuality(q) | 更新远端网络质量 |
| endCall() | 用户主动结束通话入口 |
| joinCall(connectionId) | 加入通话 |
| createCall() | 创建通话 |
| detectNetworkQuality() | 基于 WebRTC stats 检测网络质量 |
| startActivityDetection(stream, opts) | 启动音频活动检测VAD |
| startNetworkQualityDetection() | 启动定时网络质量检测 |
| stopNetworkQualityDetection() | 停止网络质量检测 |
| emitMediaStateChange() | 发送媒体状态变化信令 |
| showStatsMessage() | 显示并定时输出 WebRTC 统计信息 |
| clearStatsMessage() | 清除统计定时器 |
| getState / getLocalUser / getRemoteUser / getConnectionId / getRenderStreaming | Getter 方法 |
### renderer.js (UIRenderer 类)
| 方法 | 说明 |
|------|------|
| constructor(stateManager) | 构造函数,订阅 store 和 chatMessage |
| render(state, changes) | 核心渲染分发器,根据 changes.type 路由 |
| renderMessageState(msgState, changes) | 消息状态渲染分发器 |
| renderCallStatus(status) | 渲染通话状态(连接中覆盖层) |
| renderHeader(session) | 渲染头部信息 |
| renderHeaderTitle() | 渲染标题(含 connectionId |
| renderCallDuration(duration) | 渲染通话时长 |
| renderRemoteVideo(remoteUser) | 渲染远端视频和占位符 |
| renderHeaderNetworkStatus(q) | 渲染头部网络质量文本 |
| renderLocalVideo(localUser, stream) | 渲染本地视频和占位符 |
| renderLocalStream(stream) | 将本地流绑定到 video 元素 |
| renderRemoteStream(stream, id, isHost) | 远端流渲染分发 |
| renderParticipantStream(stream, id) | Host 端多 participant 视频网格渲染 |
| renderParticipantVideoPlaceholder(id, show) | 精准更新 participant tile 占位背景 |
| syncParticipantTileNames(participants) | 同步所有 tile 名称标签 |
| updateParticipantTileName(id, name) | 更新指定 tile 名称 |
| renderSingleRemoteStream(stream) | Participant 端单路远端视频渲染 |
| renderLocalUserStatus(localUser) | 渲染本地用户媒体状态文本 |
| renderUserList(local, remote, participants) | 渲染侧边栏用户列表(支持多 participant |
| createUserEntry(options) | 创建通用用户条目 DOM |
| getVideoResolution(track) | 获取视频轨道分辨率 |
| adjustVideoSize(video, resolution) | 调整视频元素尺寸 |
| renderControlButtons(mediaState) | 渲染底部控制按钮状态 |
| renderChatMessages(messages) | 渲染聊天消息列表 |
| createMessageElement(message) | 创建单条消息 DOM |
| renderUnreadCount(count) | 渲染未读消息角标 |
| renderSidebar(isOpen) | 渲染侧边栏显隐 |
| renderNetworkStatus(quality) | 渲染网络状态提示 |
| updateHeaderNetworkIndicator(q) | 更新头部网络指示器颜色 |
| renderCallEnded() | 渲染通话结束,跳转 endcall 页面 |
| renderParticipantLeft(id) | 清理 participant tile |
| getStatusText / getNetworkQualityText | 状态/质量文本映射 |
| destroy() | 销毁,取消订阅 |
### chatmessage.js
| 导出函数 | 说明 |
|----------|------|
| subscribe(callback) | 订阅消息状态变化 |
| addMessage(message) | 添加消息到列表 |
| sendChatMessage(message) | 通过 RenderStreaming 发送聊天消息 |
| handleChatMessage(data) | 处理接收到的聊天消息 |
| toggleSidebar() | 切换侧边栏,重置未读数 |
| getMessageState() | 获取当前消息状态 |
| sendMessage() | 用户发送消息入口(文本) |
| handleChatSubmit(event) | 回车发送处理 |
| openImagePicker() | 打开图片选择器 |
| handleImageUpload(event) | 处理图片上传(限制 5MB |
| sendImageMessage(url, fileName) | 发送图片消息 |
| bindMessageEvents() | 绑定消息相关 DOM 事件到 window |
### utils.js
| 导出函数 | 说明 |
|----------|------|
| formatTime(seconds) | 格式化为 MM:SS |
| formatTimestamp(timestamp) | 格式化为 HH:MM |
| generateId() | 生成随机唯一 ID |
| showNotification(message, duration) | 显示顶部通知 |
| toggleElement(element, show) | 切换元素显隐hidden 类) |
| toggleButtonState(button, active) | 切换按钮图标状态 |
### models.js
| 导出 | 类型 | 说明 |
|------|------|------|
| mockCallSession | 常量对象 | 默认通话会话数据结构(含 localUser / remoteUser |
| mockMessages | 常量数组 | 默认聊天消息数组(含系统消息) |
### connect/connect.js
| 全局函数 | 说明 |
|----------|------|
| joinCall() | 读取输入框 connectionId保存并跳转 |
| createCall() | 生成随机 connectionId保存并跳转 |
| getAllConnectionIds() | 从服务器获取所有连接 ID 列表 |
| displayConnectionIds(ids) | 渲染连接 ID 列表到 DOM |
| selectConnectionId(id) | 选择指定 ID 填充输入框 |
| saveSettings() | 保存用户设置到 localStorage |
| handleAvatarUpload(event) | 上传头像(限制 2MB |
| copyUserId() | 复制用户 ID 到剪贴板 |
| toggleSettingsMenu() | 切换设置菜单显隐 |
### endcall/endcall.js
| 全局函数 | 说明 |
|----------|------|
| reconnectCall() | 重新连接,跳转 index.html |
| leaveCall() | 清除 connectionId跳转 connect.html |
---
## 附录:页面跳转关系
```mermaid
graph LR
connect[connect/connect.html] -->|joinCall / createCall| index[index.html]
index -->|endCall| endcall[endcall/endcall.html]
endcall -->|reconnectCall| index
endcall -->|leaveCall| connect
index -->|无 connectionId| connect
```