按照要求,adapter中作为适配层,方法由上层约束,因此这里作为组装中心,里面的私有方法会在后续列出来。

一、主要实现的上层方法

初始化和销毁方法

create(params: { appkey: string; appID?: number })

调用处理逻辑流程:

  • 接收参数:appkey(必填)和 appID(可选)

  • 执行完整清理:调用 _fullCleanup() 确保干净状态

  • 参数处理:appID = params.appID || parseInt(params.appkey)

  • 设置服务器地址:_server = ""

  • 调用SDK创建:_zego.create({ appID, server })

  • 异常处理:捕获并重新抛出错误

destroy()

调用处理逻辑流程:

  • 移除事件监听器:调用 _offListener()

  • 清理所有流:遍历 _streams Map,调用 _destroyStream() 停止流并清理轨道

  • 清空数据结构:_streams.clear() 和 _streamIds.clear()

  • 退出房间:_zego.leaveRoom()

  • 登出大厅:_zego.logoutHall()

2. 房间管理方法

enterRoom()

调用处理逻辑流程:

  • 获取登录令牌:调用 _getHallToken() 从服务器获取token

  • 构建登录用户信息:{ userID: RTCCont.accid, userName: RTCCont.accid }

  • 配置登录参数:loginConfig 包含设备信息、应用ID、服务器地址等

  • 执行登录:_zego.loginHall(loginToken, loginUser, loginConfig)

  • 进入房间:_zego.enterRoom(RTCCont.roomId, 0)

  • 添加事件监听:调用 _addListener()

exitRoom()

调用处理逻辑流程:

  • 直接调用:_zego.leaveRoom()

  • 返回Promise结果

3. 本地流管理方法

previewLocalStream(config)

调用处理逻辑流程:

  • 构建Zego配置:zegoConfig 对象

  • 处理视频轨道:如果 config.videoTrack 存在,使用自定义轨道;否则配置摄像头参数

  • 设备配置:处理 cameraId、microphoneId 等设备选择

  • 视频质量配置:调用 _convertVideoProfile() 处理分辨率设置

  • 创建流:_zego.createStream(zegoConfig)

  • 保存流信息:存储到 _streams Map,key为 userId_streamType

  • 渲染到DOM:调用 _renderStreamToView() 显示视频

  • 设备枚举:获取并记录使用的摄像头和麦克风ID到 RTCCont

publishLocalStream()

调用处理逻辑流程:

  • 获取本地流:调用 _getLocalStream() 获取主流

  • 生成流ID:使用 _generateId() 创建唯一标识

  • 开始推流:_zego.startPublishingStream(streamId, localStream)

  • 更新流信息:保存 streamId 到 _streamIds Map

  • 返回推流结果

updateLocalStream(config)

调用处理逻辑流程:

  • 获取本地流:验证流是否存在

  • 处理视频轨道替换:移除旧轨道,添加新轨道(用于水印功能)

  • 处理音频轨道替换:类似视频轨道处理

  • 更新推流:如果存在 streamId,先停止再重新开始推流

  • 更新本地渲染:调用 _renderStreamToView() 刷新显示

  • 更新音视频状态:调用 mutePublishStreamVideo() 和 mutePublishStreamAudio()

stopLocalStream()

调用处理逻辑流程:

  • 获取主流:通过 streamKey 获取本地主流

  • 销毁流:调用 _destroyStream() 停止推流并销毁

  • 停止轨道:遍历 stream.getTracks() 调用 track.stop()

  • 清理数据结构:从 _streams 和 _streamIds 中删除

  • 清理屏幕共享:调用 _cleanupScreenStream()

4. 远端流管理方法

startRemoteVideo(config: RemoteVideoConfig)

调用处理逻辑流程:

  • 解析参数:{ userId, streamType, view, option }

  • 获取流:通过 streamKey 从 _streams 获取已拉取的流

  • 验证流存在:如果流不存在,抛出错误提示等待 REMOTE_VIDEO_AVAILABLE 事件

  • 渲染到DOM:调用 _renderStreamToView() 显示远端视频

  • 配置显示选项:处理 mirror、fillMode 等显示参数

stopRemoteVideo(config: StopRemoteVideoConfig)

调用处理逻辑流程:

  • 获取流信息:通过 userId 和 streamType 构建 streamKey

  • 获取流ID:从 _streamIds 获取对应的 streamId

  • 停止拉流:调用 _zego.stopPlayingStream(streamId)

  • 清理数据:从 _streams 和 _streamIds 中删除

5. 屏幕共享方法

startScreenShare(config)

调用处理逻辑流程:

  • 构建屏幕配置:zegoScreenConfig 包含音频和视频质量设置

  • 处理视频质量:调用 _convertVideoProfile() 处理分辨率配置

  • 创建屏幕流:_zego.createStream({ screen: zegoScreenConfig })

  • 生成流ID:使用 _generateId() 创建屏幕共享流ID

  • 开始推流:_zego.startPublishingStream(streamId, stream)

  • 保存流信息:存储到 _streams 和 _streamIds

  • 渲染到DOM:如果提供 view,调用 _renderStreamToView()

stopScreenShare()

调用处理逻辑流程:

  • 调用清理方法:_cleanupScreenStream()

  • 返回成功结果

updateScreenShare(config)

调用处理逻辑流程:

  • 先停止:调用 stopScreenShare()

  • 重新开始:调用 startScreenShare(config)

  • 返回结果

6. 设备管理方法

getCameraList()

调用处理逻辑流程:

  • 调用SDK:_zego.enumDevices()

  • 处理摄像头列表:映射设备信息为统一格式

  • 返回格式:{ deviceId, label } 数组

getMicrophoneList()

调用处理逻辑流程:

  • 调用SDK:_zego.enumDevices()

  • 处理麦克风列表:映射设备信息为统一格式

  • 返回格式:{ deviceId, label } 数组

getSpeakerList()

调用处理逻辑流程:

  • 调用SDK:_zego.enumDevices()

  • 处理扬声器列表:映射设备信息为统一格式

  • 返回格式:{ deviceId, label } 数组

7. 轨道获取方法

getVideoTrack()

调用处理逻辑流程:

  • 获取本地流:调用 _getLocalStream()

  • 提取视频轨道:localStream?.getVideoTracks()[0]

  • 返回轨道或null

getAudioTrack()

调用处理逻辑流程:

  • 获取本地流:调用 _getLocalStream()

  • 提取音频轨道:localStream?.getAudioTracks()[0]

  • 返回轨道或null

8. 功能支持检查

isSupported()

  • 检查WebRTC支持:!!navigator.mediaDevices?.getUserMedia

  • 检查Zego SDK支持:!!(window as any).ZegoExpressEngine

  • 综合判断:两个条件都满足才支持

  • 返回标准响应格式

二、私有成员变量

核心SDK实例

_zego: ZegoSDK - Zego SDK的封装实例,负责与底层SDK交互

服务器配置

_server: string - 存储Zego服务器地址,用于登录和连接

事件管理

_emitter: EventEmitter - 事件发射器,用于统一管理自定义事件

流管理数据结构

  • _streams: Map<string, MediaStream> - 流对象映射表,key格式为”userId_streamType”,value为MediaStream对象

  • _streamIds: Map<string, string> - 流ID映射表,key格式为”userId_streamType”,value为Zego SDK的streamId

事件监听器引用

_listeners - 存储绑定的事件监听器引用,用于在清理时正确移除监听器

三、私有方法

流管理相关

_destroyStream(streamKey: string, isLocal: boolean)

作用和设计思路:

  • 统一处理流的销毁逻辑,区分本地流和远端流

  • 本地流:调用 stopPublishingStream() 停止推流,然后 destroyStream() 销毁

  • 远端流:调用 stopPlayingStream() 停止拉流

  • 设计思路:通过 isLocal 参数区分处理方式,避免重复代码

_fullCleanup()

作用和设计思路:

  • 在初始化前执行完整清理,确保系统处于干净状态

  • 遍历所有流进行销毁,停止所有轨道,清空数据结构

  • 移除所有事件监听器

  • 设计思路:防止重复初始化导致的状态混乱和内存泄漏

_getStreamKey(userId: string, streamType: string)

作用和设计思路:

  • 生成统一的流标识符,格式为”userId_streamType”

  • 用于在Map中快速定位和管理流对象

  • 设计思路:使用统一的命名规范,便于流的管理和查找

_getLocalStream()

作用和设计思路:

  • 获取当前用户的本地主流

  • 通过固定的streamKey从_streams中获取

  • 设计思路:封装获取本地流的逻辑,提供统一的访问接口

配置转换相关

_convertVideoProfile(profile: string, cameraConfig: any)

作用和设计思路:

  • 将标准视频分辨率配置转换为Zego SDK的配置参数

  • 支持Zego原生档位(240p/480p/720p)和自定义档位(档位4)

  • 提供标准分辨率映射表,支持120p到4K的配置

  • 设计思路:统一不同厂商的配置格式,提供标准化的分辨率配置接口

渲染相关

_renderStreamToView(stream: MediaStream, view: string | HTMLElement, options)

作用和设计思路:

  • 将MediaStream渲染到指定的DOM容器中

  • 支持字符串ID和HTMLElement对象两种view参数

  • 处理视频元素的属性设置:autoplay、muted、playsInline等

  • 支持镜像显示和填充模式配置

  • 设计思路:封装视频渲染逻辑,提供统一的显示接口,支持多种显示选项

事件处理相关

_onRoomStreamUpdate(roomID, updateType, streamList, extendedData)

作用和设计思路:

  • 处理房间流状态更新事件,包括流新增和删除

  • ADD类型:自动拉取新流,保存到_streams,触发REMOTE_VIDEO_AVAILABLE事件

  • DELETE类型:停止拉流,清理数据,触发REMOTE_VIDEO_UNAVAILABLE事件

  • 通过streamId判断流类型(主流或屏幕共享流)

  • 设计思路:实现自动流管理,减少上层调用复杂度

_onRoomUserUpdate(roomID, updateType, userList)

作用和设计思路:

  • 处理用户进出房间事件

  • ADD类型:触发REMOTE_USER_ENTER事件

  • DELETE类型:触发REMOTE_USER_EXIT事件

  • 设计思路:统一用户状态管理,提供标准的事件通知

_onScreenShareStopped(mediaStream)

作用和设计思路:

  • 处理用户主动停止屏幕共享的事件

  • 清理屏幕共享流数据

  • 触发SCREEN_SHARE_STOPPED事件

  • 设计思路:处理用户主动操作,确保状态同步

工具方法

_generateId(…parts)

作用和设计思路:

  • 统一的ID生成器,将多个部分组合成唯一标识符

  • 过滤null值,使用下划线连接

  • 设计思路:提供统一的ID生成规范,确保标识符的唯一性和可读性

_getHallToken()

作用和设计思路:

  • 从服务器获取大厅登录所需的token

  • 构建请求参数:timestamp、app_id、user_name等

  • 发送POST请求到token服务器

  • 设计思路:封装token获取逻辑,提供统一的认证接口

handleSdkCall(sdkMethod, successMsg)

作用和设计思路:

  • 统一的SDK调用错误处理方法

  • 执行SDK方法,捕获异常并转换为标准响应格式

  • 返回APICommonResponse格式的结果

  • 设计思路:统一错误处理,提供一致的API响应格式

_cleanupScreenStream(emitEvent: boolean)

作用和设计思路:

  • 专门清理屏幕共享流的方法

  • 销毁流、停止轨道、清理数据

  • 可选择是否触发SCREEN_SHARE_STOPPED事件

  • 设计思路:封装屏幕共享流的清理逻辑,支持不同的清理场景

四、核心内容总结

核心功能实现流程

1. 初始化流程

create() → _fullCleanup() → _zego.create() → 设置_server

2. 进入房间流程

enterRoom() → _getHallToken() → _zego.loginHall() → _zego.enterRoom() → _addListener()

3. 本地流发布流程

previewLocalStream() → _zego.createStream() → 保存到_streams → _renderStreamToView()
publishLocalStream() → _generateId() → _zego.startPublishingStream() → 保存streamId

4. 远端流播放流程

_onRoomStreamUpdate(ADD) → _zego.startPlayingStream() → 保存到_streams → 触发REMOTE_VIDEO_AVAILABLE
startRemoteVideo() → 从_streams获取流 → _renderStreamToView()

5. 屏幕共享流程

startScreenShare() → _zego.createStream({screen}) → _zego.startPublishingStream() → 保存流信息

关键参数处理

流标识符管理

  • streamKey格式:“userId_streamType”(如:“user123_main”、“user123_sub”)

  • streamType类型:“main”(主流)、“sub”(屏幕共享流)

  • streamId生成:“stream_userId_streamType_timestamp”

视频配置转换

  • Zego原生档位:240p(1)、480p(2)、720p(3)

  • 自定义档位:档位4,支持width/height/frameRate/bitrate配置

  • 标准分辨率映射:120p到4K的完整配置表

事件系统设计

  • 标准事件名:统一的事件命名规范,如”remote-user-enter”

  • 事件数据格式:包含userId、streamId、streamType等关键信息

  • 自动流管理:通过事件自动处理流的拉取和清理

错误处理机制

  • 统一响应格式:APICommonResponse包含success、code、msg、data字段

  • 异常捕获:所有SDK调用都通过handleSdkCall包装

  • 状态清理:确保异常情况下的资源正确释放

本地流的详细流程

用户调用

previewLocalStream()  ────────┐
  │                           │ 
  ├─ createStream()           │ [1] 创建流
  ├─ _getStreamKey()          │     生成key: "user123_main"
  └─ _streams.set()           │ [2] 存入Map(streamID为空)

publishLocalStream()  ────────┤
  │                           │
  ├─ _getLocalStream()        │ [3] 从Map读取
  │   └─ _streams.get()       │
  ├─ startPublishingStream()  │ [4] SDK推流,生成真实streamID
  └─ _streams.set()           │ [5] 更新Map(填入streamID)

updateLocalStream()  ─────────┤
  └─ _getLocalStream()        │ [6] 读取流进行操作
      └─ _streams.get()       │

stopLocalStream()  ───────────┤
  ├─ _streams.get()           │ [7] 读取并停止
  └─ _streams.delete()        │ [8] 从Map移除

屏幕共享流的详细流程

startScreenShare()

  ├─ createStream({ screen })   [1] 创建屏幕流
  ├─ _getStreamKey(accid, "sub") 
  │   └─ 生成key: "user123_sub"
  └─ _streams.set()              [2] 存入Map,key用"sub"表示辅流

stopScreenShare()
  └─ _cleanupScreenStream()
      ├─ _streams.get()          [3] 读取
      └─ _streams.delete()       [4] 移除

远端流的详细流程

SDK触发事件

_onRoomStreamUpdate(updateType="ADD", streamList)

  ├─ for each streamInfo:
  │   ├─ 判断streamType            [1] 通过streamID识别流类型
  │   │   └─ streamID.includes("_screen_") ? "sub" : "main"
  │   │
  │   ├─ startPlayingStream()      [2] SDK自动拉流
  │   │
  │   ├─ _getStreamKey(userId, streamType)
  │   │   └─ 生成key: "remoteUser_main"
  │   │
  │   └─ _streams.set()            [3] 存入Map(isLocal=false)

  └─ emit REMOTE_VIDEO_AVAILABLE   [4] 通知业务层

业务层调用

startRemoteVideo({ userId, streamType, view })

  ├─ _getStreamKey()               [5] 生成查询key
  ├─ _streams.get()                [6] 从Map取出已拉取的流
  └─ _renderStreamToView()         [7] 渲染到DOM

stopRemoteVideo()
  ├─ _streams.get()                [8] 读取
  ├─ stopPlayingStream()           [9] 停止拉流
  └─ _streams.delete()             [10] 移除

设计流程:

SDK事件驱动 → Adapter自动拉流 → 存入流池 → 触发业务事件 → 业务层被动渲染