WebRTC Thread Model
Abstract |
WebRTC 线程模型 |
Authors |
Walter Fan |
Status |
v1.0 |
Updated |
2026-03-20 |
概述
WebRTC 的线程模型是其架构的核心,理解它是阅读源码的前提。 WebRTC 使用三个主要线程,每个线程有明确的职责边界和严格的调用规则。
┌──────────────────────────────────────────────────────┐
│ 应用层 (JavaScript / Native API) │
└──────────┬───────────────────────────────────────────┘
│ API 调用 & 回调
┌──────────▼───────────────────────────────────────────┐
│ Signaling Thread (信令线程) │
│ - PeerConnection 的 API 入口 │
│ - SDP 创建与解析 │
│ - Observer 回调 │
└──────┬──────────────────────────┬────────────────────┘
│ 同步调用 │ 同步调用
┌──────▼────────────┐ ┌───────▼─────────────────────┐
│ Worker Thread │ │ Network Thread │
│ (工作线程) │ │ (网络线程) │
│ │ │ │
│ - 编解码 │───►│ - ICE/DTLS/SRTP │
│ - 媒体处理 │ │ - Socket 读写 │
│ - 拥塞控制 │ │ - 数据收发 │
│ - 音频设备管理 │ │ - TURN 中继 │
└───────────────────┘ └──────────────────────────────┘
调用规则
WebRTC 对线程间调用有严格约束,违反会触发 RTC_DCHECK 断言:
调用方 |
可调用 |
说明 |
|---|---|---|
Signaling Thread |
Worker Thread |
同步调用(阻塞等待结果) |
Worker Thread |
Network Thread |
同步调用 |
Network Thread |
(无) |
不能被其他线程阻塞,也不能同步调用其他线程 |
任意线程 |
任意线程 |
可以异步 Post 消息(非阻塞) |
关键原则:Network Thread 永远不能被阻塞,因为它直接处理网络 I/O, 阻塞会导致丢包和连接超时。
核心类
Thread
rtc::Thread 是 WebRTC 的线程基类,内部维护一个消息队列(TaskQueue)。
class Thread : public TaskQueueBase {
public:
// 在目标线程上同步执行(阻塞当前线程)
template <typename Functor>
auto Invoke(const Location& posted_from, Functor&& functor);
// 在目标线程上异步执行(不阻塞)
void PostTask(absl::AnyInvocable<void() &&> task);
// 延迟执行
void PostDelayedTask(absl::AnyInvocable<void() &&> task,
TimeDelta delay);
// 启动线程消息循环
void Run();
// 停止线程
void Stop();
// 获取当前线程
static Thread* Current();
};
Invoke():跨线程同步调用,内部通过消息队列传递任务并等待完成PostTask():异步投递,不等待结果RTC_DCHECK_RUN_ON(thread):编译期+运行期检查当前是否在指定线程上
TaskQueue
TaskQueueBase 是更轻量的任务队列抽象,不一定绑定 OS 线程:
std::unique_ptr<TaskQueueFactory> CreateDefaultTaskQueueFactory() {
return CreateTaskQueueStdlibFactory();
}
WebRTC 内部很多模块使用 TaskQueue 而非直接使用 Thread, 以便在不同平台选择最优的实现(POSIX、Win32、stdlib)。
Dispatcher (事件分派)
Network Thread 内部使用事件驱动模型处理 Socket I/O:
class Dispatcher {
public:
virtual uint32_t GetRequestedEvents() = 0;
virtual void OnEvent(uint32_t ff, int err) = 0;
#if defined(WEBRTC_WIN)
virtual WSAEVENT GetWSAEvent() = 0;
virtual SOCKET GetSocket() = 0;
#elif defined(WEBRTC_POSIX)
virtual int GetDescriptor() = 0;
virtual bool IsDescriptorClosed() = 0;
#endif
};
Windows:使用
WSAEventSelect+WSAWaitForMultipleEventsPOSIX:使用
poll()或epoll()
线程安全注解
WebRTC 大量使用 Clang 线程安全注解来在编译期检测错误:
class VideoSendStream {
Mutex mutex_;
// 编译器检查:访问 config_ 前必须持有 mutex_
Config config_ RTC_GUARDED_BY(mutex_);
// 编译器检查:此方法只能在 worker_thread_ 上调用
void SetSource(...) RTC_RUN_ON(worker_thread_);
};
常用注解:
注解 |
含义 |
|---|---|
|
访问此变量前必须持有锁 |
|
此方法只能在指定线程上调用 |
|
运行时断言当前在指定线程上 |
|
调用此方法前必须持有锁 |
实际场景中的线程交互
以发送视频为例:
摄像头采集 (Capture Thread)
│
│ OnFrame() 回调
▼
Signaling Thread
│ 通过 VideoTrackSource 分发
▼
Worker Thread
│ VideoStreamEncoder::OnFrame()
│ → 编码 (可能在编码器自己的线程)
│ → PacedSender::EnqueuePackets()
▼
Network Thread (Pacer 线程)
│ → RTP 打包
│ → SRTP 加密
│ → Socket 发送
▼
网络
FAQ
如何创建 PeerConnectionFactory 并指定线程?
auto network_thread = rtc::Thread::CreateWithSocketServer();
network_thread->Start();
auto worker_thread = rtc::Thread::Create();
worker_thread->Start();
auto signaling_thread = rtc::Thread::Create();
signaling_thread->Start();
auto factory = webrtc::CreatePeerConnectionFactory(
network_thread.get(),
worker_thread.get(),
signaling_thread.get(),
/*default_adm=*/nullptr,
webrtc::CreateBuiltinAudioEncoderFactory(),
webrtc::CreateBuiltinAudioDecoderFactory(),
std::make_unique<webrtc::VideoEncoderFactoryTemplate<
webrtc::LibvpxVp8EncoderTemplateAdapter>>(),
std::make_unique<webrtc::VideoDecoderFactoryTemplate<
webrtc::LibvpxVp8DecoderTemplateAdapter>>(),
/*audio_mixer=*/nullptr,
/*audio_processing=*/nullptr);