WebRTC源码线程-1

1、概述

本篇主要是简单介绍WebRTC中的线程,WebRTC源码对线程做了很多的封装。

1.1 WebRTC中线程的种类

1.1.1 信令线程

用于与应用层的交互,比如创建offer,answer,candidate等绝大多数的操作

1.1.2 工作线程

负责内部的处理逻辑,比如音视频编解码、采集、渲染这些操作,平滑处理,质量监测

1.1.3 网络线程

负责网络数据包的转发,工作线程对音视频数据进行编码后,发送编码后的音视频数据到网络。

从网络中接收音视频数据包,然后交给工作线程进行解码,丢包处理等操作

1.2 peerconnection_client

peerconnection_client一共创建了5个线程,分别为

主线程:windows中main函数的,处理窗口消息的线程

与信令服务器连接处理的线程:PhysicalSocketServer关联

信令线程:PhysicalSocketServer关联

工作线程:NullSocketServer关联

网络线程:PhysicalSocketServer关联

1.3 线程类关系图

1.4 线程类

复制代码
class RTC_LOCKABLE RTC_EXPORT Thread : public TaskQueueBase {
 public:
  explicit Thread(SocketServer* ss);
  SocketServer* socketserver();
  bool Start();
  virtual void Stop();
  virtual void Run();
  bool ProcessMessages(int cms);

 protected:
  void PostTaskImpl(absl::AnyInvocable<void() &&> task,
                    const PostTaskTraits& traits,
                    const Location& location) override;

 private:
  absl::AnyInvocable<void() &&> Get(int cmsWait);
  void Dispatch(absl::AnyInvocable<void() &&> task);


#if defined(WEBRTC_WIN)
  static DWORD WINAPI PreRun(LPVOID context);
#else
  static void* PreRun(void* pv);
#endif

  std::queue<absl::AnyInvocable<void() &&>> messages_ RTC_GUARDED_BY(mutex_);
  std::priority_queue<DelayedMessage> delayed_messages_ RTC_GUARDED_BY(mutex_);
  SocketServer* const ss_;
#if defined(WEBRTC_POSIX)
  pthread_t thread_ = 0;
#endif
#if defined(WEBRTC_WIN)
  HANDLE thread_ = nullptr;
  DWORD thread_id_ = 0;
#endif
};
  • 成员变量 thread_ 在不同平台有不同的实现,win下采用线程内核对象创建,linux下采用pthread创建
  • 成员变量 messages_ 相当于里面保存的是函数对象,只不过用absl库,我们可以把它当做是std::function函数对象
  • 线程之间通信,通过PostTask函数进行,相当于线程1需要执行的任务放入线程2的queue,然后线程2不断从queue读取任务执行,这样来进行通信

1.5 线程管理类

复制代码
class RTC_EXPORT ThreadManager {
 public:

  static ThreadManager* Instance();

  static void Add(Thread* message_queue);
  static void Remove(Thread* message_queue);
  
  Thread* CurrentThread();
  void SetCurrentThread(Thread* thread);

private:
  // This list contains all live Threads.
  std::vector<Thread*> message_queues_ RTC_GUARDED_BY(crit_);


#if defined(WEBRTC_POSIX)
  pthread_key_t key_;
#endif

#if defined(WEBRTC_WIN)
  const DWORD key_;
#endif
};

线程管理类ThreadManager用到一个技术点是线程本地存储(TLS),需要理解这个技术点,否则比较难读懂WebRTC源码中线程这块的代码。

1.5.1 线程本地化存储(TLS)

复制代码
#include <windows.h>
#include <stdio.h>

// 全局 TLS 索引
DWORD tlsIndex;

// 线程函数
DWORD WINAPI ThreadFunction(LPVOID lpParam) {
    int threadNum = *(int*)lpParam;
    char buffer[256];
    
    // 为当前线程设置 TLS 值
    sprintf_s(buffer, "线程 %d 的私有数据", threadNum);
    TlsSetValue(tlsIndex, strdup(buffer));  // 注意:使用 strdup 分配内存
    
    // 获取并打印当前线程ID和TLS值
    DWORD threadId = GetCurrentThreadId();
    char* data = (char*)TlsGetValue(tlsIndex);
    printf("线程 ID=%lu, 编号=%d, TLS 数据: %s\n", threadId, threadNum, data);
    
    // 清理分配的内存
    free(data);
    return 0;
}

int main() {
    // 分配 TLS 索引
    tlsIndex = TlsAlloc();
    if (tlsIndex == TLS_OUT_OF_INDEXES) {
        printf("TlsAlloc 失败,错误码: %d\n", GetLastError());
        return 1;
    }
    
    // 在主线程中设置并获取 TLS 值
    char mainBuffer[256];
    sprintf_s(mainBuffer, "主线程的私有数据");
    TlsSetValue(tlsIndex, strdup(mainBuffer));
    
    // 打印主线程ID和TLS值
    DWORD mainThreadId = GetCurrentThreadId();
    char* mainData = (char*)TlsGetValue(tlsIndex);
    printf("主线程 ID=%lu, TLS 数据: %s\n", mainThreadId, mainData);
    
    // 创建两个线程
    int thread1Num = 1;
    int thread2Num = 2;
    HANDLE hThread1 = CreateThread(NULL, 0, ThreadFunction, &thread1Num, 0, NULL);
    HANDLE hThread2 = CreateThread(NULL, 0, ThreadFunction, &thread2Num, 0, NULL);
    
    // 等待线程结束
    WaitForSingleObject(hThread1, INFINITE);
    WaitForSingleObject(hThread2, INFINITE);
    
    // 关闭线程句柄
    CloseHandle(hThread1);
    CloseHandle(hThread2);
    
    // 清理主线程分配的内存
    free(TlsGetValue(tlsIndex));
    
    // 释放 TLS 索引
    TlsFree(tlsIndex);
    
    return 0;
}

在每个线程中保存的value不一样,每个线程取出来的value就是不一样,通俗地说,假设我们有3个线程,分别为Thread1、Thread2、Thread3, 分别保存value为1、2、3,那么如果当前如果在Thread2运行的代码里面打印value,那么打印的就是2。通过这样的原理,假如当前是信令线程,通过ThreadManager的函数CurrentThread那么返回的就是信令线程,如果需要在网络线程中运行,则需要利用PostTask放入到网络线程中使用,我们可以看到WebRTC源码很多都是用这个来进行判断。

相关推荐
~央千澈~17 小时前
优雅草蜻蜓T语音会议系统私有化部署方案与RTC技术深度解析-优雅草卓伊凡|clam
webrtc·实时音视频·rtc
old-six-programmer2 天前
NAT 类型及 P2P 穿透
服务器·网络协议·webrtc·p2p·nat
大胡子大叔2 天前
webrtc-streamer视频流播放(rstp协议h264笔记)
笔记·webrtc·rtsp·webrtc-streamer
_可乐无糖3 天前
AWS WebRTC: 判断viewer端拉流是否稳定的算法
linux·服务器·webrtc·aws
却道天凉_好个秋3 天前
WebRTC(十三):信令服务器
webrtc
却道天凉_好个秋12 天前
WebRTC(七):媒体能力协商
webrtc
GetcharZp17 天前
告别“只闻其名”!一文带你深入浅出 WebRTC,并用 Go 搭建你的第一个实时应用
后端·webrtc
平行云17 天前
3分钟搭建LarkXR实时云渲染PaaS平台,实现各类3D/XR应用的一键推流
云原生·webrtc·xr·云渲染·虚幻引擎·实时云渲染·像素流送
却道天凉_好个秋18 天前
WebRTC(六):ICE协议
服务器·网络·webrtc
从后端到QT18 天前
WebRtc ICE 模块分析
webrtc