# 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 ```