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

15 KiB
Raw Blame History

onebyone 模块代码调用结构图

本文档基于优化后的代码自动生成,反映当前实际架构。


3.1 文件依赖关系图

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 核心调用链

通话初始化流程

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

媒体控制流程

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()

消息发送流程

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 管理流程

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 状态流转

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 状态流转

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

附录:页面跳转关系

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