peerconnection_client模块是webrtc的客户端程序,该模块集成了webrtc的音视频设备获取,音视频编解码和协议传输模块。主要包括PeerConnectionClient、Conductor和VideoRenderer三个主要类。
一、Conductor 类介绍
cpp
//Conductor类是WebRTC示例的核心控制器,继承多个观察者接口。
// 它管理PeerConnection生命周期,处理信令、ICE候选及媒体流事件,
// 并协调UI与对等连接客户端,实现登录、连接 peers 及消息收发等功能。
class Conductor : public webrtc::PeerConnectionObserver,
public webrtc::CreateSessionDescriptionObserver,
public PeerConnectionClientObserver,
public MainWndCallback
Conductor 类是 WebRTC C++ 示例程序(peerconnection_client)中的核心控制器。它充当了"大脑"的角色,负责协调底层 WebRTC 引擎、信令服务器通信以及用户界面(UI)之间的交互。该类通过继承多个观察者接口,将异步事件统一处理,实现了从登录、建立连接到媒体流传输的完整生命周期管理。
1.1 实现核心原理介绍
• 使用中介者模式 (Mediator):
Conductor 解耦了 PeerConnectionClient(信令/网络)、MainWindow(UI)和 webrtc::PeerConnectionInterface(WebRTC 核心)。
• 使用观察者模式 (Observer):
实现了三个主要的 Observer 接口,用于接收来自不同模块的异步回调:
-
webrtc::PeerConnectionObserver: 接收 WebRTC 连接状态、ICE 候选、媒体轨道变化等事件。
-
PeerConnectionClientObserver: 接收信令服务器事件(如登录成功、对端连接、收到信令消息)。
-
MainWndCallback: 接收 UI 操作事件(如点击连接、断开、登录)。
1.2 主要功能介绍
1.2.1 连接初始化与管理
1 InitializePeerConnection() / CreatePeerConnection(bool dtls):
• 创建 PeerConnectionFactory。
• 配置 RTCConfiguration(包括 STUN/TURN 服务器)。
• 创建 PeerConnection 实例并注册自身为 Observer (this)。
2 AddTracks():
• 创建本地音频和视频轨道(从摄像头/麦克风捕获)。
• 通过 peer_connection_->AddTrack() 将本地媒体流添加到连接中,以便发送给对端。
3 DeletePeerConnection():
• 清理资源,关闭连接,重置状态。
1.2.2. 信令交换流程 (SDP & ICE)
这是 WebRTC 建立连接的关键步骤,Conductor 在此处桥接了 WebRTC 引擎和信令客户端:
- 发起连接 (Offer):
• 当用户调用 ConnectToPeer() 时,Conductor 调用 peer_connection_->CreateOffer()。
• 回调 OnSuccess(SessionDescriptionInterface* desc) 被触发。
• 在 OnSuccess 中,设置本地描述 (SetLocalDescription),并将 SDP Offer 序列化为 JSON,通过 SendMessage() 发给信令服务器。
- 接收连接 (Answer):
• 当 OnMessageFromPeer() 收到对端的 Offer 时,Conductor 解析 JSON,创建 SessionDescription,调用 SetRemoteDescription。
• 然后调用 CreateAnswer()。
• 在 OnSuccess 中,设置本地描述,并将 SDP Answer 发回给对端。
- ICE 候选交换:
• 当 WebRTC 引擎收集到新的 ICE 候选时,触发 OnIceCandidate()。
• Conductor 将候选信息序列化并通过信令通道发送给对端。
• 反之,收到对端 ICE 候选时,调用 peer_connection_->AddIceCandidate()。
1.2.3. 媒体流处理
1 OnAddTrack():
• 当对端添加媒体轨道时触发。
• Conductor 获取远程轨道,并将其绑定到 UI 窗口 (main_wnd_) 进行渲染显示。
2 OnRemoveTrack():
• 当对端移除轨道时,更新 UI 停止渲染。
1.2.4. UI 与线程调度
1 UIThreadCallback(int msg_id, void* data):
• WebRTC 的核心运行在非 UI 线程(网络线程、工作线程)。
• 当需要在 UI 上显示状态或视频时,必须切换回 UI 线程。
• 该方法作为入口,根据 msg_id(如 NEW_TRACK_ADDED, PEER_CONNECTION_CLOSED)执行具体的 UI 更新逻辑。
二、PeerConnectionClient类介绍
cpp
//该类实 ,处理消息收发、解析HTTP响应及 peer 列表。
// 继承 MessageHandler 处理异步事件,并通过 Observer 回调通知上层应用状态变化。
class PeerConnectionClient : public sigslot::has_slots<>,
public rtc::MessageHandler {
2.1 核心功能
• 信令传输层:负责将 JSON 格式的信令数据(SDP Offer/Answer, ICE Candidates)通过 TCP socket 发送给服务器或其他 Peer。
• 状态管理器:维护客户端与信令服务器的连接状态(如登录中、已连接、登出中等)。
• 事件通知者:通过 PeerConnectionClientObserver 接口将网络事件(如收到消息、对端上线/下线)通知给上层控制器。
2,2 主要工作流程
2.2.1. 连接与登录 (Connect -> DoConnect)
-
调用 Connect(server, port, client_name)。
-
启动异步 DNS 解析 (AsyncResolver)。
-
解析成功后,创建 control_socket_ 并连接到服务器。
-
连接成功后 (OnConnect),发送 HTTP POST 请求进行登录(包含客户端名称)。
-
服务器返回 HTTP 200 OK 及分配的唯一 ID (my_id_)。
-
登录成功后,立即发起 hanging_get_ 连接,开始监听服务器通知。
-
触发 callback_->OnSignedIn()。
2.2.2. 发送信令 (SendToPeer)
-
上层调用 SendToPeer(peer_id, json_message)。
-
构造 HTTP POST 请求,目标地址为 /message?peer_id=<id>。
-
通过 control_socket_ 发送数据。
-
服务器响应后,触发 callback_->OnMessageSent(err)。
2.2.3. 接收信令 (OnHangingGetRead)
-
hanging_get_ socket 接收到服务器推送的数据。
-
解析 HTTP 响应体。
-
根据内容类型区分事件:
• 如果是 peer 列表更新:解析并调用 OnPeerConnected 或 OnPeerDisconnected。
• 如果是消息:提取 peer_id 和消息内容,调用 OnMessageFromPeer。
- 关键步骤:处理完当前数据后,必须立即关闭当前的 hanging_get_ 并发起一个新的 Hanging GET 请求,以继续监听后续事件。
2.2.4. 登出 (SignOut)
-
发送 HTTP POST 请求到 /sign_out。
-
关闭 control_socket_ 和 hanging_get_。
-
重置状态为 NOT_CONNECTED。
-
触发 callback_->OnDisconnected()。
3,PeerConnection数据交互时序图

• Conductor 拥有 PeerConnectionClient 实例。
• Conductor 实现 PeerConnectionClientObserver 接口。
• 当 PeerConnectionClient 收到 OnMessageFromPeer 时,Conductor 会解析 JSON,提取 SDP 或 ICE 候选,并交给 webrtc::PeerConnectionInterface 处理。
• 当 webrtc::PeerConnectionInterface 生成 SDP 或 ICE 候选时,Conductor 将其序列化为 JSON,调用 PeerConnectionClient::SendToPeer 发送出去。
三、VideoRenderer类介绍
cpp
//获取的视频帧渲染类,继承自VideoSinkInterface,重写了OnFrame方法,在其中进行视频帧的处理和渲染。
class VideoRenderer : public rtc::VideoSinkInterface<webrtc::VideoFrame>
VideoRenderer 是 MainWnd 类的一个内部嵌套类,它是 WebRTC 视频流在 Windows 平台上渲染到窗口的核心组件。它的主要作用是将 WebRTC 解码后的原始视频帧(webrtc::VideoFrame)转换为 Windows GDI 可以显示的位图格式,并绘制到指定的窗口句柄(HWND)上。
3.1 视频核心角色
1 继承关系:public rtc::VideoSinkInterface<webrtc::VideoFrame>
• 这是 WebRTC 的标准接口,用于接收视频帧。
• 当 webrtc::VideoTrack 有新的视频帧可用时,它会自动调用注册了的 Sink 的 OnFrame 方法。
2 职责:作为观察者,被动接收视频数据,负责格式转换和内存管理,不主动拉取数据。
3.2 显示时序图
下图是windows显示图像的整个时序图,当webrtcEngin模块收到视频流后,解析出对应的YUV格式,转换为RGB后, 会发送到UI的窗口句柄上,然后通过windows的GDI显示相关图像

OnFrame(const webrtc::VideoFrame& frame)
这是最核心的方法,由 WebRTC 引擎异步调用:
-
格式转换:WebRTC 内部通常使用 I420 (YUV) 格式存储视频以节省带宽。Windows GDI 无法直接高效绘制 YUV。因此,OnFrame 内部通常会调用 libyuv 库(如 libyuv::I420ToARGB)将 YUV 数据转换为 ARGB (RGB32) 格式。
-
加锁写入:
• 调用 Lock() 进入临界区。
• 将转换后的 RGB 数据复制到 image_ 缓冲区。
• 更新 bmi_ 中的宽高信息(如果分辨率发生变化)。
• 调用 Unlock() 退出临界区。
- 触发重绘:
• 数据更新后,通常需要通知 Windows 窗口进行重绘。
• 在示例代码中,这通常通过 PostMessage(wnd_, WM_PAINT, ...) 或自定义消息来实现,让主线程在空闲时调用 OnPaint 从 image_ 读取数据并吹到屏幕上。