WebRTC C++开发必须先初始化PeerConnectionFactory并传入四个有效线程指针,严格遵循Offer/Answer流程、手动管理ICE候选、自实现音视频采集与渲染,且所有操作须符合线程亲和性约束。

webrtc::PeerConnectionFactory 必须先初始化,否则后续所有 PeerConnection 创建都会失败——这是 C++ 环境下最常卡住的第一步。
WebRTC 的 C++ 原生开发不是“调个 API 就能跑”,它要求你亲手补全浏览器里自动完成的整条链路:媒体采集、编码、网络协商、信令中转、渲染输出。没有预设 UI,也没有自动摄像头访问权限弹窗,一切从线程和内存生命周期开始。
必须手动初始化线程与工厂对象
WebRTC C++ 的线程模型是硬性约束,不是可选项。你不能在主线程直接创建 PeerConnection,也不能复用任意线程执行回调。
-
webrtc::CreatePeerConnectionFactory要求传入四个线程指针:network_thread、worker_thread、signaling_thread和可选的default_adm(音频设备模块);缺一不可,且不能为nullptr - 推荐用
rtc::Thread::Create()创建专用线程,并显式Start();别试图用std::thread包装,WebRTC 内部依赖rtc::Thread的消息循环机制 - 工厂对象(
PeerConnectionFactoryInterface*)必须全程持有,不能局部创建后返回——它的析构会触发底层资源释放,导致后续PeerConnection崩溃 - Windows 下若用 WASAPI,还需额外调用
webrtc::CreateDefaultAudioDeviceModule并传入工厂构造参数,否则CreatePeerConnection可能静默失败
SDP 协商流程不能跳过 Offer/Answer 顺序
浏览器里看似自动的 createOffer → setLocalDescription → 发送 → 收到 offer → setRemoteDescription → createAnswer → setLocalDescription 流程,在 C++ 中每一步都得手写,且顺序错不得。
-
CreateOffer后必须立刻调用SetLocalDescription,否则OnIceCandidate不会触发;同理,收到远程offer后,必须先SetRemoteDescription,再调用CreateAnswer -
SetLocalDescription和SetRemoteDescription是异步操作,需监听SetSessionDescriptionObserver回调确认成功,不能假设调用即生效 - SDP 字符串必须完整传递,包括
a=msid、a=ssrc、a=fingerprint等字段;若用自定义信令 JSON 封装,注意转义换行符(\r\n),否则ParseSessionDescription会返回空指针 - 本地
offer中若未启用视频轨道,createOffer生成的 SDP 就不含videom-line,对端即使有摄像头也收不到视频流——要显式调用AddTrack并确保VideoTrackSource已启动
ICE 候选交换失败通常源于网络配置或回调时机
OnIceCandidate 回调不是“收集完才触发”,而是边收集边回调;而 AddIceCandidate 必须在 SetRemoteDescription 成功之后才能安全调用,否则直接返回 false。
- STUN 服务器地址必须带协议和端口,例如
"stun:stun.l.google.com:19302";写成"stun.l.google.com"或漏掉端口,PeerConnection会静默跳过该 candidate gathering - 若使用 TURN,务必确认凭证有效且服务器支持
transport=udp;C++ 端不自动 fallback 到 TCP,失败时仅记录日志,无异常抛出 -
AddIceCandidate接收的是webrtc::IceCandidateInterface*,不是原始字符串;需用webrtc::CreateIceCandidate解析字符串后再传入,否则崩溃 - Linux 下若启用了 IPv6 但网络不支持,
OnIceCandidate可能持续返回host类型 candidate 却无法连通;建议在PeerConnection配置中显式禁用:configuration.enable_ice_renomination = false;并设置rtc_configuration.type = webrtc::PeerConnectionInterface::kTurn强制走中继
音视频帧流动必须自己接管,没有“自动渲染”
JavaScript 里一个 video.srcObject = stream 就搞定的事,在 C++ 中要实现至少三个角色:数据源(VideoTrackSource)、传输通道(VideoTrack)、接收端(VideoSinkInterface)。
- 摄像头采集不能靠
getUserMedia,得用 OpenCV / V4L2 / AVFoundation 手动拉帧,再通过VideoTrackSource::OnFrame推给 WebRTC 编码器;注意帧率、时间戳、宽高必须匹配VideoEncoderConfig设置 - 渲染端必须实现
OnFrame回调,且不能在该回调里做耗时操作(如 OpenGL upload);建议用双缓冲队列 + 独立渲染线程消费 - 音频路径更敏感:
AudioDeviceModule的PlayoutDataIsAvailable和RecordedDataIsAvailable回调频率固定(通常 10ms 一帧),采样率/通道数/位深必须与AudioEncoder配置严格一致,否则静音或爆音 - 别忽略
webrtc::VideoEncoder的初始化失败——VP8 编码器在某些平台需显式调用SetFecEnabled(true)才能启用关键帧请求,否则远端可能长期黑屏
最容易被忽略的是线程亲和性:所有 VideoSinkInterface::OnFrame 回调都在 signaling_thread 上触发,但 OpenGL 渲染必须在主线程或专用渲染线程。你得自己加线程切换逻辑,而不是指望 WebRTC 自动帮你 dispatch。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











