webrtc peerconnection_client 介绍

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 接口,用于接收来自不同模块的异步回调:

  1. webrtc::PeerConnectionObserver: 接收 WebRTC 连接状态、ICE 候选、媒体轨道变化等事件。

  2. PeerConnectionClientObserver: 接收信令服务器事件(如登录成功、对端连接、收到信令消息)。

  3. 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 引擎和信令客户端:

  1. 发起连接 (Offer):

• 当用户调用 ConnectToPeer() 时,Conductor 调用 peer_connection_->CreateOffer()。

• 回调 OnSuccess(SessionDescriptionInterface* desc) 被触发。

• 在 OnSuccess 中,设置本地描述 (SetLocalDescription),并将 SDP Offer 序列化为 JSON,通过 SendMessage() 发给信令服务器。

  1. 接收连接 (Answer):

• 当 OnMessageFromPeer() 收到对端的 Offer 时,Conductor 解析 JSON,创建 SessionDescription,调用 SetRemoteDescription。

• 然后调用 CreateAnswer()。

• 在 OnSuccess 中,设置本地描述,并将 SDP Answer 发回给对端。

  1. 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)

  1. 调用 Connect(server, port, client_name)。

  2. 启动异步 DNS 解析 (AsyncResolver)。

  3. 解析成功后,创建 control_socket_ 并连接到服务器。

  4. 连接成功后 (OnConnect),发送 HTTP POST 请求进行登录(包含客户端名称)。

  5. 服务器返回 HTTP 200 OK 及分配的唯一 ID (my_id_)。

  6. 登录成功后,立即发起 hanging_get_ 连接,开始监听服务器通知。

  7. 触发 callback_->OnSignedIn()。

2.2.2. 发送信令 (SendToPeer)

  1. 上层调用 SendToPeer(peer_id, json_message)。

  2. 构造 HTTP POST 请求,目标地址为 /message?peer_id=<id>。

  3. 通过 control_socket_ 发送数据。

  4. 服务器响应后,触发 callback_->OnMessageSent(err)。

2.2.3. 接收信令 (OnHangingGetRead)

  1. hanging_get_ socket 接收到服务器推送的数据。

  2. 解析 HTTP 响应体。

  3. 根据内容类型区分事件:

• 如果是 peer 列表更新:解析并调用 OnPeerConnected 或 OnPeerDisconnected。

• 如果是消息:提取 peer_id 和消息内容,调用 OnMessageFromPeer。

  1. 关键步骤:处理完当前数据后,必须立即关闭当前的 hanging_get_ 并发起一个新的 Hanging GET 请求,以继续监听后续事件。

2.2.4. 登出 (SignOut)

  1. 发送 HTTP POST 请求到 /sign_out。

  2. 关闭 control_socket_ 和 hanging_get_。

  3. 重置状态为 NOT_CONNECTED。

  4. 触发 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 引擎异步调用:

  1. 格式转换:WebRTC 内部通常使用 I420 (YUV) 格式存储视频以节省带宽。Windows GDI 无法直接高效绘制 YUV。因此,OnFrame 内部通常会调用 libyuv 库(如 libyuv::I420ToARGB)将 YUV 数据转换为 ARGB (RGB32) 格式。

  2. 加锁写入:

• 调用 Lock() 进入临界区。

• 将转换后的 RGB 数据复制到 image_ 缓冲区。

• 更新 bmi_ 中的宽高信息(如果分辨率发生变化)。

• 调用 Unlock() 退出临界区。

  1. 触发重绘:

• 数据更新后,通常需要通知 Windows 窗口进行重绘。

• 在示例代码中,这通常通过 PostMessage(wnd_, WM_PAINT, ...) 或自定义消息来实现,让主线程在空闲时调用 OnPaint 从 image_ 读取数据并吹到屏幕上。