bricks/docs/cn/rtc.md
2025-10-12 17:59:59 +08:00

13 KiB
Raw Blame History

Bricks WebRTC 通信框架技术文档

本文档描述了 bricks 框架中用于实现点对点P2P实时音视频通信的核心模块包括

  • bricks.VideoBox:用于播放媒体流的视频组件。
  • bricks.Signaling:信令服务客户端,通过 WebSocket 与服务器通信。
  • bricks.RTCP2PConnect:基于 WebRTC 的 P2P 连接管理器。

1. bricks.VideoBox

一个封装了 <video> 元素的 JavaScript 组件,用于显示媒体流(如摄像头或屏幕共享流)。

类定义

class bricks.VideoBox extends bricks.JsWidget

方法

create()

创建并初始化 <video> DOM 元素,并设置自动播放和静音属性。

行为:

  • 创建 video 元素。
  • 设置 autoplaymuted 属性为 true

⚠️ 注意:由于现代浏览器的安全策略,autoplay 只能在用户交互后生效,且必须配合 muted 才能无提示播放。

get_stream() → MediaStream

获取当前绑定到该视频元素的媒体流。

返回值:

  • {MediaStream} 当前播放的媒体流对象。

set_stream(stream: MediaStream)

将指定的媒体流绑定到 <video> 元素上进行播放。

参数:

  • stream: {MediaStream} 要播放的媒体流。

行为:

  • stream 赋值给内部变量 this.stream
  • 设置 this.dom_element.srcObject = stream,触发视频播放。

2. bricks.Signaling

信令客户端类,负责与信令服务器建立 WebSocket 连接,处理登录、心跳、消息收发及会话分发。

构造函数

new bricks.Signaling(opts)

参数 opts

参数 类型 描述
signaling_url String WebSocket 信令服务器地址
info Object 客户端信息(如用户 ID、设备信息等在发送数据时附加为 msgfrom 字段
connect_opts Object 传递给后续连接模块的通用配置选项
onclose Function WebSocket 关闭时的回调函数
onopen Function WebSocket 成功打开时的回调函数(可选)
onlogin Function(onlinePeers) 登录成功后接收在线用户列表的回调
heartbeat_period Number 心跳周期(秒),若不设则不启用

属性

属性 类型 描述
socket WebSocket 当前 WebSocket 实例
peers Object 存储当前在线用户的映射表key: peer.id
sessions Object 已建立的会话记录(未使用)
handlers Object 每个会话 ID 对应的消息处理器
sessionhandlers Object 按会话类型注册的处理器构造函数
hb_task TaskHandle 心跳定时任务句柄(由 schedule_once 返回)
heartbeat_period Number 心跳间隔时间(秒)

方法

init_websocket()

初始化 WebSocket 连接:

  • 使用 bricks.app.get_session() 获取会话凭证作为子协议。
  • 绑定事件监听器:
    • onmessagesignaling_recvdata
    • onopenlogin
    • onclose / onerrorreconnect

reconnect()

WebSocket 断开后的处理逻辑:

  • 清除心跳任务。
  • 触发 onclose 回调。
  • 注意:当前未实现自动重连机制。

signaling_recvdata(event)

异步处理从 WebSocket 接收到的数据包。

流程:

  1. 解析 JSON 数据。
  2. 若包含 data.session,查找对应会话处理器:
    • 若首次收到,则根据 sessiontype 实例化对应的处理器类。
    • 注册该会话的 recvdata_handler
  3. 否则调用默认 recvdata_handler 处理全局消息。

add_handler(key, handler)

注册某个 sessionid 的消息处理器。

add_sessionhandler(sessiontype, handlerClass)

注册某种会话类型的处理器类(构造函数)。例如:

signaling.add_sessionhandler('p2p', bricks.RTCP2PConnect);

recvdata_handler(data)

默认消息处理器,处理非会话级消息。

支持的消息类型:

  • online: 更新在线用户列表,并触发 onlogin(online) 回调。

未处理其他消息类型时仅打印日志。

new_session(sessiontype, peer)

发起一个新的会话请求。

步骤:

  1. 查找 sessiontype 对应的处理器类。
  2. 生成唯一 sessionid
  3. 发送 { type: 'new_session', session } 到服务器。
  4. 创建处理器实例并注册其 recvdata_handler
  5. 返回处理器实例(通常是 RTCP2PConnect 实例)。

login()

向服务器发送登录请求。

行为:

  • 发送 { type: 'login' }
  • 如果设置了 heartbeat_period > 0,启动周期性心跳任务。

logout()

发送登出请求 { type: 'logout' }

send_data(d)

将对象序列化为 JSON 并通过 WebSocket 发送。

附加字段:

  • d.msgfrom = this.info(标识发送者)

socket_send(s)

直接发送原始字符串(底层接口,一般不推荐直接使用)。


3. bricks.RTCP2PConnect

WebRTC P2P 连接控制器,处理音视频通话和数据通道通信。

构造函数

new bricks.RTCP2PConnect(signaling, session, opts)

参数:

参数 类型 描述
signaling bricks.Signaling 信令客户端实例
session Object 会话元信息 { sessionid, sessiontype }
opts Object 配置项,见下表

opts 配置说明:

选项 类型 默认值 描述
ice_servers Array 必需 ICE 服务器配置STUN/TURN
peer_info Object 必需 对端用户信息(含 .id
auto_callaccept Boolean false 是否自动接受呼叫
media_options Object { video: true, audio: true } 媒体采集选项
data_connect Boolean false 是否启用数据通道
on_pc_connected(peer) Function - 连接建立成功回调
on_pc_disconnected(peer) Function - 连接断开回调
on_dc_open(dc) Function - 数据通道开启回调
on_dc_close(dc) Function - 数据通道关闭回调
on_dc_message(dc, data) Function - 收到数据通道消息回调

属性

属性 类型 描述
id String 本地唯一标识UUID
signaling Signaling 信令客户端引用
session Object 当前会话信息
requester Boolean 是否为主叫方
peers Object 所有远程连接的 PeerConnection 管理对象
signal_handlers Object 信令消息处理器映射
local_stream MediaStream 本地摄像头流
localVideo VideoBox 本地视频预览组件
local_screen MediaStream 屏幕共享流(可选)

核心方法

add_handler(type, f)

注册信令消息处理器(如 'offer', 'answer' 等)。

get_handler(type) → Function

获取指定类型的消息处理器。

p2pconnect(peer)

尝试与指定对端建立 P2P 连接。

流程:

  1. 获取本地媒体流(如果尚未获取)。
  2. 若已存在连接则跳过。
  3. 调用 createPeerConnection(peer) 创建新的 RTCPeerConnection

h_sessioncreated(data)

当会话创建完成时触发。

行为:

  • 自动调用 p2pconnect
  • 若有 peer_info,主动发送 callrequest 请求呼叫。

h_callrequest(data)

收到呼叫请求。

行为:

  • auto_callaccept === true(或硬编码为 true),自动响应:
    • 建立连接。
    • 发送 callaccepted 消息。

h_callaccepted(data)

对方接受呼叫。

行为:

  • 创建数据通道(如果启用)。
  • 发送 SDP Offer。

h_offer(data)

收到远程 Offer。

流程:

  1. 设置 remoteDescription
  2. 创建 Answer。
  3. 设置 localDescription
  4. 发送 Answer 回去。
  5. 如果不是主叫方,再发送一次 Offer可能存在设计问题需确认逻辑

h_answer(data)

收到远程 Answer。

行为:

  • 设置 remoteDescription

h_icecandidate(data)

收到 ICE 候选地址。

行为:

  • 添加到 RTCPeerConnection 中。

h_sessionquit(data)

收到会话结束通知。

行为:

  • 关闭对应 RTCPeerConnection

send_offer(peer, initial = false)

创建并发送 SDP Offer。

参数:

  • peer: 目标用户。
  • initial: 是否是首次呼叫(决定角色:requester / responser

流程:

  1. 创建 Offer。
  2. 设置 localDescription
  3. 通过信令发送 Offer。

send_candidate(peer, event)

ICE 候选事件触发时调用,转发候选地址给远端。

使用 bind(this, peer) 绑定上下文。

signaling_send(d)

封装信令消息,附带当前 session 信息后发送。

recvdata_handler(data)

统一入口处理所有信令消息:

  • 查找对应处理器并执行。
  • 未处理则输出警告日志。

连接状态监听

ice_statechange(peer, event)

ICE 连接状态变化时的日志输出。

connection_statechange(peer, event)

连接状态变化处理:

  • disconnected: 触发 peer_close()on_pc_disconnected 回调。
  • connected: 触发 on_pc_connected 回调。

数据通道DataChannel

dc_accepted(peer, event)

收到远程数据通道请求。

行为:

  • 保存 event.channel
  • 调用 dc_created() 初始化。

dc_created(peer, dc)

初始化数据通道事件监听器:

  • onmessagedatachannel_message
  • onopendatachannel_open
  • onclosedatachannel_close

datachannel_message(peer, event)

收到数据通道消息。

行为:

  • 触发 on_dc_message(dc, event.data) 回调。

datachannel_open/close(peer)

分别在数据通道打开/关闭时触发相应回调。

createDataChannel(peer)

主动创建数据通道(用于主叫方)。


媒体流控制

createPeerConnection(peer)

创建并配置 RTCPeerConnection 实例。

关键操作:

  • 使用传入的 iceServers
  • 添加本地媒体轨道(如有)。
  • 绑定以下事件:
    • onicecandidate
    • oniceconnectionstatechange
    • onconnectionstatechange
    • ondatachannel(注意:拼写错误应为 ondatachannel
    • ontrack → 将远端流绑定到 VideoBox

🛠️ Bug 提示:pc.ondatachanel 应为 pc.ondatachannel

changeLocalVideoStream(peer, new_stream)

动态更换本地视频流(如切换摄像头或屏幕共享)。

流程:

  1. 移除旧的视频 Track。
  2. 添加新流中的视频 Track。
  3. 重新发送 Offer 以更新协商。

getLocalStream()

获取本地摄像头和屏幕共享流。

行为:

  • 调用 getUserMedia(media_options) 获取摄像头流。
  • 调用 getDisplayMedia({ video: true }) 获取屏幕共享流(音频可选)。
  • 分别赋值给 this.local_streamthis.local_screen
  • 创建 localVideo 并绑定摄像头流用于预览。

🔐 权限提示:需要用户授权麦克风和摄像头权限。


peer_close(peer)

清理与指定对端的所有资源。

释放内容:

  • 停止所有接收/发送的媒体 Track。
  • 停止远端视频流。
  • 关闭数据通道和 RTCPeerConnection
  • 删除 peers 中的记录。
  • 若无剩余连接,停止本地流并从信令中注销会话处理器。

使用示例

// 初始化信令
var signaling = new bricks.Signaling({
    signaling_url: 'wss://example.com/signaling',
    info: { id: 'user123', name: 'Alice' },
    heartbeat_period: 30,
    onlogin: function(peers) {
        console.log('Online users:', peers);
    }
});

// 注册 P2P 处理器
signaling.add_sessionhandler('p2p', bricks.RTCP2PConnect);

// 登录(触发 login
signaling.login();

// 发起一个 P2P 会话
var p2p = signaling.new_session('p2p', { id: 'user456' });

注意事项与潜在问题

问题 描述 建议修复
ondatachanel 拼写错误 应为 ondatachannel 更正拼写
`auto_callaccept true`
newStream 变量名错误 changeLocalVideoStream 中误写为 newStream 改为 new_stream
缺少异常处理 多处 await 未包裹 try/catch 增加错误捕获
心跳任务未清除 schedule_once 可能导致内存泄漏 确保正确取消任务
未实现自动重连 reconnect() 仅触发回调 应加入延迟重试机制

总结

bricks 提供了一套完整的 WebRTC 信令与连接管理方案,具有以下特点:

模块化设计:分离信令、会话、连接逻辑
扩展性强:支持多种会话类型
易于集成:提供 VideoBox 等 UI 组件封装
⚠️ 需优化点:存在若干 bug 与安全限制需处理

适用于开发音视频会议、直播互动、远程协作等实时通信应用。