Files
webRtc/WebApp/client/public/onebyone/code-structure.md

459 lines
15 KiB
Markdown
Raw Normal View History

2026-04-25 21:09:45 +08:00
# 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
```