webrtc中的线程(一) rtc::Thread


WebRtc中的线程设计非常具有参考价值,通过学习它们的实现,可以对线程的理解更上一个台阶。
在WebRtc并不是简单的对os 线程相关的API进行封装,而是结合功能实现需求对线程进行了设计。
在webrtc有两种线程对象:

  1. rtc::Thread 对象

rtc::Thread是webrtc中最重要的线程类型。它与WebRtc库的实现深度结合。

  1. rtc::ProcessThread 对象

rtc::ProcessThread线程类型,主要是用作执行一些定时任务。

这篇文章将介绍rtc::Thread及它在WebRtc中的使用

rtc:Thread

线程模型

rtc::Thread的线程模型如下:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GZPu3OiZ-1678665809251)(https://note.youdao.com/yws/api/personal/file/WEBff381d87c74c6937c35f05c025579f26?method=download&shareKey=d2fd984d0ab7f17fd5395027c1aa3fab#clientId=ua4f980d8-c6d9-4&id=nodDw&originHeight=1190&originWidth=1574&originalType=binary&ratio=1&rotation=0&showTitle=false&status=done&style=none&taskId=u1c3d1033-3e4f-4638-8ea8-2f6a65535ea&title=)]
如上图所示,rtc::Thread不仅仅是只产生一个线程,它还包含一个队列**(message list)**,将它称为异步任务队列更适合。

它的基本功能就是在线程中执行任务队列中的任务。

它靠事件驱动,也就是说当message list中没有任务(message)时,它会阻塞在事件等待上,当有事件唤醒时后会继续在队列中去任务执行。

主要成员及方法

类图

类图中列出了rtc::Thread的核心类及方法。
rtc_thread_1.png

Thread类继承自TaskQueueBase,从语意就表明了它是一个任务队列。

核心成员变量:
  • MessageList messages_

就是任务队列,它是一个std::list,定义如下:
typedef std::list<Message> MessageListMessage类就任务的抽象。

  • PriorityQueue delayed_message_

延迟任务队列,是一个优先队列。

  • SocketServer* const ss_

事件驱动器,从名字上就可以看出它可以处理网络IO事件。

核心方法:

它的核心方法就是ProcessMessageGet方法。

  • ProcessMessage是线程的执行体,是一个while(true)循环,它不断的从Get中取出任务然后执行,方法框架如下:
bool Thread::ProcessMessages(int cmsLoop) {
   
   
	while (true) {
   
   
        Message msg;
        //取出任务
        Get(&msg, cmsNext);
        ...
        //执行任务
        Dispatch(&msg);
    }
}
  • Get方法,首先取出队列中的任务,如果没有任务则处理事件,如果没有事件则阻塞到Wait方法上。
bool Thread::Get(Message* pmsg, int cmsWait, bool process_io) {
   
   
    //取出队列中的任务
	while(true) {
   
   
        ...
        if (messages_.empty()) {
   
   
          break;
        } else {
   
   
          *pmsg = messages_.front();
          messages_.pop_front();
        }
        ...
    	return true;
    }

    ...
    
	//如果没有任务则执行事件,如何也没有事件就阻塞在Wait方法上
    {
   
   
      // Wait and multiplex in the meantime
      if (!ss_->Wait(static_cast<int>(cmsNext), process_io))
        return false;
    }
}
控制类方法

bool Start()
void Stop()
void Run()
这三个是典型的线程控制方法。

任务类方法
异步方法

它是异步队列,有post系列方法,用于将任务投递到线程中执行,这些post方法都是异步方法,马上返回。

  • 放入一个QueuedTask类型的任务。QueuedTask方法内部被封装成了Message类型。
void PostTask(std::unique_ptr<webrtc::QueuedTask> task) override;
  • 放入一个QueuedTask类型的任务,在delay ms后执行。
void PostDelayedTask(std::unique_ptr<webrtc
#include <api/create_peerconnection_factory.h> #include <api/video/video_source_interface.h> #include <modules/video_capture/video_capture_factory.h> #include <rtc_base/ssl_adapter.h> // 自定义观察者类 (核心回调处理) class PeerConnectionObserver : public webrtc::PeerConnectionObserver { public: // ICE Candidate生成回调 void OnIceCandidate(const webrtc::IceCandidateInterface* candidate) override { // 将candidate转为字符串并发送给SFU服务器 std::string sdp; candidate->ToString(&sdp); SendSignalToServer("candidate", sdp); // [^1] } // 本地SDP设置成功回调 void OnSignalingChange(webrtc::PeerConnectionInterface::SignalingState state) override { if (state == webrtc::PeerConnectionInterface::kHaveLocalOffer) { // 发送Offer到服务器 auto local_desc = peer_connection_->local_description(); SendSignalToServer("offer", local_desc->sdp()); } } }; // 视频渲染器实现本地预览 class VideoRenderer : public rtc::VideoSinkInterface<webrtc::VideoFrame> { public: void OnFrame(const webrtc::VideoFrame& frame) override { // 实现帧渲染逻辑 (如OpenGL/Vulkan/DirectX) RenderFrame(frame); // 本地窗口预览 [^1] } }; int main() { // === 1. 初始化WebRTC核心环境 === rtc::InitializeSSL(); // 初始化SSL rtc::ThreadManager::Instance()->WrapCurrentThread(); // 创建网络线程/工作线程/信令线程 auto network_thread = rtc::Thread::CreateWithSocketServer(); auto worker_thread = rtc::Thread::Create(); auto signaling_thread = rtc::Thread::Create(); network_thread->Start(); worker_thread->Start(); signaling_thread->Start(); // === 2. 创建PeerConnection工厂 === auto factory = webrtc::CreatePeerConnectionFactory( network_thread.get(), worker_thread.get(), signaling_thread.get(), nullptr, // 默认音频设备 webrtc::CreateBuiltinAudioEncoderFactory(), webrtc::CreateBuiltinAudioDecoderFactory(), webrtc::CreateBuiltinVideoEncoderFactory(), webrtc::CreateBuiltinVideoDecoderFactory(), nullptr, // 音频混合器 nullptr // 音频处理 ); // === 3. 采集音视频流 === // 视频采集 auto device_info = webrtc::VideoCaptureFactory::CreateDeviceInfo(); auto video_device = device_info->GetDeviceName(0); // 获取第个摄像头 auto video_capturer = webrtc::VideoCaptureFactory::Create(video_device); rtc::scoped_refptr<webrtc::VideoTrackSourceInterface> video_source( factory->CreateVideoSource(std::move(video_capturer), nullptr)); // 创建视频轨道 (添加本地渲染器) auto video_track = factory->CreateVideoTrack("camera", video_source); VideoRenderer local_renderer; video_track->AddOrUpdateSink(&local_renderer, rtc::VideoSinkWants()); // [^1] // 创建音频轨道 auto audio_track = factory->CreateAudioTrack("mic", factory->CreateAudioSource(cricket::AudioOptions())); // === 4. 创建PeerConnection === webrtc::PeerConnectionInterface::RTCConfiguration config; config.sdp_semantics = webrtc::SdpSemantics::kUnifiedPlan; // 添加TURN服务器配置 (连接SRS等SFU) webrtc::PeerConnectionInterface::IceServer turn_server; turn_server.urls = {"turn:your_sfu_ip:3478"}; turn_server.username = "user"; turn_server.password = "pass"; config.servers.push_back(turn_server); PeerConnectionObserver observer; auto peer_connection = factory->CreatePeerConnection(config, nullptr, nullptr, &observer); observer.SetPeerConnection(peer_connection); // === 5. 添加媒体流 === auto stream = factory->CreateLocalMediaStream("local_stream"); stream->AddTrack(video_track); stream->AddTrack(audio_track); peer_connection->AddTrack(video_track, {stream->id()}); peer_connection->AddTrack(audio_track, {stream->id()}); // === 6. 创建Offer并启动推流 === webrtc::PeerConnectionInterface::RTCOfferAnswerOptions options; options.offer_to_receive_video = false; // 纯推流模式 peer_connection->CreateOffer( CreateSessionDescriptionObserver::Create(), // 需实现该观察者 options ); // === 7. 事件循环 (处理信令和ICE) === while (true) { // 接收并处理服务器返回的Answer if (received_answer) { webrtc::SdpParseError error; auto answer = webrtc::CreateSessionDescription( webrtc::SdpType::kAnswer, answer_sdp, &error ); peer_connection->SetRemoteDescription(SetRemoteDescriptionObserver::Create(), answer); } // 处理ICE Candidate if (received_candidate) { webrtc::SdpParseError error; auto candidate = webrtc::CreateIceCandidate( candidate_sdp_mid, candidate_sdp_mline_index, candidate_sdp, &error ); peer_connection->AddIceCandidate(candidate); } rtc::Thread::Current()->ProcessMessages(10); // 消息处理间隔 } // === 清理 === peer_connection->Close(); rtc::CleanupSSL(); } 写出这个编译的makefile
最新发布
09-07
<think> 我们正在为包含WebRTC头文件和代码的程序编写Makefile。根据引用[1][2],需要注意以下几点: 1. WebRTC的头文件有严格的目录层次,在复制头文件时要保留目录结构。 2. 编译时需要指定正确的头文件路径(-I选项)和链接库路径(-L选项),以及需要链接的库。 3. 编译过程需要支持C++11特性。 4. 可能还需要链接webrtc_audio_processing等音频处理库(引用[3][4])。 假设我们的项目结构如下: - 项目根目录:PROJECT_ROOT - src/:存放源码(.cc, .cpp) - include/:存放项目自己的头文件 - third_party/webrtc/:存放从WebRTC源码中提取的头文件(保留目录结构) - lib/:存放预编译的WebRTC库文件(如libwebrtc.a) 根据引用[1],在Mac上提取WebRTC头文件时,可以使用ditto命令保留目录结构。但我们的Makefile中不涉及头文件提取,而是假设已经将头文件放在third_party/webrtc目录下。 编写Makefile的步骤: 1. 定义编译器和编译选项 - 使用g++(或者clang++) - 开启C++11:-std=c++11 - 添加头文件搜索路径:-Iinclude -Ithird_party/webrtc - 其他必要的编译选项(如-fPIC、-Wall等) 2. 定义链接选项 - 库搜索路径:-Llib - 链接库:-lwebrtc(假设我们有个静态库libwebrtc.a)以及其他需要的库(如pthread, openssl, webrtc_audio_processing等) 3. 定义源文件和目标文件 - 遍历src目录下的所有cpp文件 - 生成对应的.o文件 4. 定义目标 - 最终可执行文件:链接所有的.o文件 5. 清理规则 注意:由于WebRTC本身依赖较多,可能需要链接其他系统库。根据实际项目依赖,可能需要添加额外的库。 下面是个示例Makefile: ```makefile # 编译器 CXX = g++ # 编译选项 CXXFLAGS = -std=c++11 -Wall -Wextra -Werror \ -Iinclude -Ithird_party/webrtc # 链接选项 LDFLAGS = -Llib LDLIBS = -lwebrtc -lpthread -lssl -lcrypto -ldl -lrt # 如果使用了音频处理模块,可能需要链接webrtc_audio_processing # 假设我们将其编译为libwebrtc_audio_processing.a并放在lib目录下 # LDLIBS += -lwebrtc_audio_processing # 源文件目录 SRC_DIR = src # 源文件 SRCS = $(wildcard $(SRC_DIR)/*.cpp) # 目标文件(object files) OBJS = $(SRCS:.cpp=.o) # 最终目标 TARGET = webrtc_app # 默认目标 all: $(TARGET) $(TARGET): $(OBJS) $(CXX) $(LDFLAGS) $^ -o $@ $(LDLIBS) # 编译规则 %.o: %.cpp $(CXX) $(CXXFLAGS) -c $< -o $@ # 清理 clean: rm -f $(OBJS) $(TARGET) .PHONY: all clean ``` 注意事项: 1. 上述Makefile假设你的WebRTC库文件为lib/libwebrtc.a。如果实际库名不同,请修改。 2. 如果使用了音频处理模块,需要根据引用[3][4]单独编译并链接webrtc_audio_processing库。你需要将其放在lib目录下,并在LDLIBS中添加-lwebrtc_audio_processing。 3. WebRTC依赖较多,如果编译时出现未定义的引用,可能需要添加其他库。常见的依赖包括:pthread, ssl, crypto, dl, rt等。请根据错误信息添加。 4. 如果头文件路径不正确,编译时会报错。请确保third_party/webrtc目录下包含从WebRTC源码中提取的头文件(保留目录结构)。 编译步骤: 1. 将WebRTC头文件按照原始目录结构复制到third_party/webrtc下(可以使用脚本或命令保留目录结构)。 2. 将编译好的WebRTC静态库(libwebrtc.a)放到lib目录下。 3. 在项目根目录运行`make`。 如果遇到链接错误,比如缺少某些符号,可能需要检查WebRTC库的构建是否包含了所需的模块(如音频处理、视频处理等)。另外,根据引用[2][4],音频处理模块可能需要单独编译和链接。 相关问题: 1. 如何正确提取WebRTC的头文件并保留目录结构? 2. 如何编译WebRTC的静态库(libwebrtc.a)? 3. 如何编译webrtc_audio_processing模块? 4. 在Linux/Mac上编译WebRTC项目时常见的链接错误有哪些?如何解决? </think> 以下是为包含 WebRTC 头文件和代码的程序编写的 Makefile 示例,结合了您提供的引用信息: ```makefile # WebRTC 项目 Makefile # 参考: [^1][^2][^3][^4] # 编译器设置 CXX := g++ CXXFLAGS := -std=c++11 -Wall -Wextra -Wpedantic CXXFLAGS += -Ithird_party/webrtc/include # 包含 WebRTC 头文件路径 [^1] CXXFLAGS += -Iinclude # 项目自定义头文件路径 # 链接器设置 LDFLAGS := -Lthird_party/webrtc/lib # WebRTC 库路径 LDLIBS := -lwebrtc_full -lpthread -lssl -lcrypto # 必需的库 LDLIBS += -lwebrtc_audio_processing # 音频处理模块 [^3][^4] # 源文件和目标 SRC_DIR := src BUILD_DIR := build TARGET := webrtc_app SOURCES := $(wildcard $(SRC_DIR)/*.cpp) OBJECTS := $(patsubst $(SRC_DIR)/%.cpp,$(BUILD_DIR)/%.o,$(SOURCES)) # 默认目标 all: prepare $(TARGET) # 创建构建目录 prepare: @mkdir -p $(BUILD_DIR) # 主目标链接 $(TARGET): $(OBJECTS) $(CXX) $(LDFLAGS) $^ -o $@ $(LDLIBS) # 编译规则 $(BUILD_DIR)/%.o: $(SRC_DIR)/%.cpp $(CXX) $(CXXFLAGS) -c $< -o $@ # 清理 clean: rm -rf $(BUILD_DIR) $(TARGET) # 安装依赖 (示例) install-deps: # 安装 webrtc-audio-processing [^3][^4] wget http://freedesktop.org/software/pulseaudio/webrtc-audio-processing/webrtc-audio-processing-0.3.1.tar.xz tar -xf webrtc-audio-processing-0.3.1.tar.xz cd webrtc-audio-processing-0.3.1 && \ ./configure --prefix=$(PWD)/third_party && \ make && make install # 提取 WebRTC 头文件 (Mac 系统示例) [^1] extract-headers-mac: ditto /path/to/webrtc/src third_party/webrtc/include .PHONY: all clean prepare install-deps extract-headers-mac ``` ### 关键说明 1. **头文件处理**: ```makefile # 保留 WebRTC 头文件目录结构 [^1] CXXFLAGS += -Ithird_party/webrtc/include ``` - Linux使用 `cp --parents`,Mac使用 `ditto` 命令复制目录结构[^1] - 确保头文件路径与原始WebRTC源码结构致 2. **音频处理模块**: ```makefile LDLIBS += -lwebrtc_audio_processing # 引用音频处理库 [^3][^4] ``` - 需要单独编译安装 `webrtc-audio-processing` [^3][^4] 3. **编译要求**: ```makefile CXXFLAGS := -std=c++11 # 必须使用C++11特性 [^2] ``` - 编译时需要处理可能的链接问题[^2] 4. **依赖安装**: ```makefile install-deps: # 安装音频处理模块 [^3][^4] wget http://freedesktop.org/software/pulseaudio/webrtc-audio-processing/webrtc-audio-processing-0.3.1.tar.xz tar -xf webrtc-audio-processing-0.3.1.tar.xz cd webrtc-audio-processing-0.3.1 && \ ./configure --prefix=$(PWD)/third_party && \ make && make install ``` ### 使用说明 1. **目录结构**: ``` project/ ├── Makefile ├── include/ # 项目头文件 ├── src/ # 项目源码 ├── third_party/ │ ├── webrtc/ │ │ ├── include/ # WebRTC头文件 (保留目录结构) │ │ └── lib/ # WebRTC库文件 └── build/ # 编译输出 ``` 2. **编译命令**: ```bash # 安装依赖 (首次使用) make install-deps # 编译项目 make # 清理 make clean ``` 3. **Mac系统提取头文件**: ```bash make extract-headers-mac ``` ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

mo4776

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值