webrtc中的线程

参考:https://juejin.cn/post/6844904041835659277#comment

文章目录

创建Thread对象:

  • Thread继承MessageQueue

  • Thread提供两个静态方法,分别用来创建带socket和不带socket的线程:

    static std::unique_ptr CreateWithSocketServer();

    static std::unique_ptr Create();

Thread的Run()函数中:

复制代码
void Thread::Run() {
	ProcessMessages(kForever); //wgj 调用Thread的Start方法时,会调用Thread::ProcessMessages方法。

}

bool Thread::ProcessMessages(int cmsLoop) {
  // Using ProcessMessages with a custom clock for testing and a time greater
  // than 0 doesn't work, since it's not guaranteed to advance the custom
  // clock's time, and may get stuck in an infinite loop.
  RTC_DCHECK(GetClockForTesting() == nullptr || cmsLoop == 0 ||
             cmsLoop == kForever);
  int64_t msEnd = (kForever == cmsLoop) ? 0 : TimeAfter(cmsLoop);
  int cmsNext = cmsLoop;

  while (true) {
#if defined(WEBRTC_MAC)
    ScopedAutoReleasePool pool;
#endif
    Message msg;
    if (!Get(&msg, cmsNext))//wgj 获取消息
      return !IsQuitting();
    Dispatch(&msg);//分发消息

    if (cmsLoop != kForever) {
      cmsNext = static_cast<int>(TimeUntil(msEnd));
      if (cmsNext < 0)
        return true;
    }
  }
}

bool MessageQueue::Get(Message* pmsg, int cmsWait, bool process_io) {

// Pull a message off the message queue, if available.
        if (msgq_.empty()) {
          break;
        } else {
          *pmsg = msgq_.front();
          msgq_.pop_front(); //从消息队列中 拿一条消息出来
        }



 {
      // Wait and multiplex in the meantime
      if (!ss_->Wait(static_cast<int>(cmsNext), process_io)) //Get方法很关键,它获取消息队列中的message,如果MessageQueue有SocketServer对象,调用Wait方法,执行IO的读写操作。[此处可能是普通事件或者socket事件]
        return false;
    }

void MessageQueue::Dispatch(Message* pmsg) {
  TRACE_EVENT2("webrtc", "MessageQueue::Dispatch", "src_file_and_line",
               pmsg->posted_from.file_and_line(), "src_func",
               pmsg->posted_from.function_name());
  int64_t start_time = TimeMillis();
  pmsg->phandler->OnMessage(pmsg);//wgj 注意pmsg->phandler  回调函数:MessageHandler的OnMessage方法
  int64_t end_time = TimeMillis();
  int64_t diff = TimeDiff(end_time, start_time);
  if (diff >= kSlowDispatchLoggingThreshold) {
    RTC_LOG(LS_INFO) << "Message took " << diff
                     << "ms to dispatch. Posted from: "
                     << pmsg->posted_from.ToString();
  }
}

NullSocketServer中的事件:

linux:

关于wait()函数:在NullSocketServer中:

使用pthread_cond_wait条件变量,而在

void NullSocketServer::WakeUp() {

event_.Set();

}

中使用pthread_cond_signal();

windows:

而在windows上使用:

WaitForSingleObject和SetEvent

PhysicalSocketServer中的事件:

在PhysicalSocketServer构造函数中,包含普通事件和socket事件:

复制代码
PhysicalSocketServer::PhysicalSocketServer() : fWait_(false) {
#if defined(WEBRTC_USE_EPOLL)
  // Since Linux 2.6.8, the size argument is ignored, but must be greater than
  // zero. Before that the size served as hint to the kernel for the amount of
  // space to initially allocate in internal data structures.
  epoll_fd_ = epoll_create(FD_SETSIZE);
  if (epoll_fd_ == -1) {
    // Not an error, will fall back to "select" below.
    RTC_LOG_E(LS_WARNING, EN, errno) << "epoll_create";
    epoll_fd_ = INVALID_SOCKET;
  }
#endif
  signal_wakeup_ = new Signaler(this, &fWait_); //wgj 普通事件 用于处理:消息队列
#if defined(WEBRTC_WIN)
  socket_ev_ = WSACreateEvent();//wgj windows中的socket事件 用于处理:socket
#endif
}

在linux中的普通事件:

复制代码
#if defined(WEBRTC_POSIX)
class EventDispatcher : public Dispatcher {
 public:
  EventDispatcher(PhysicalSocketServer* ss) : ss_(ss), fSignaled_(false) {
    if (pipe(afd_) < 0) //wgj afd_是个有名管道
      RTC_LOG(LERROR) << "pipe failed";
    ss_->Add(this);
  }

 virtual void Signal() {
    CritScope cs(&crit_);
    if (!fSignaled_) {
      const uint8_t b[1] = {0};
      const ssize_t res = write(afd_[1], b, sizeof(b)); //wgj PhysicalSocketServer中有一个信号量Signaler(一个pipe),也被epoll管理。当有message加入消息队列时(一个List),信号量发送1个字节的数据,触发epoll的读事件,让线程继续运行。
      RTC_DCHECK_EQ(1, res);
      fSignaled_ = true;
    }
  }

windows中的普通事件:

复制代码
class EventDispatcher : public Dispatcher {
 public:
  EventDispatcher(PhysicalSocketServer* ss) : ss_(ss) {
    hev_ = WSACreateEvent(); //wgj 用于处理:消息队列
    if (hev_) {
      ss_->Add(this);
    }
  }

  virtual void Signal() {
    if (hev_ != nullptr)
      WSASetEvent(hev_);
  }

Wait()函数:

Windows中:

复制代码
#if defined(WEBRTC_WIN)
bool PhysicalSocketServer::Wait(int cmsWait, bool process_io) {
  int64_t cmsTotal = cmsWait;
  int64_t cmsElapsed = 0;
  int64_t msStart = Time();

  fWait_ = true;
  while (fWait_) {
    std::vector<WSAEVENT> events; //所有事件
    std::vector<Dispatcher*> event_owners; //只有普通事件

    events.push_back(socket_ev_);

    {
      CritScope cr(&crit_);
      // TODO(jbauch): Support re-entrant waiting.
      RTC_DCHECK(!processing_dispatchers_);

      // Calling "CheckSignalClose" might remove a closed dispatcher from the
      // set. This must be deferred to prevent invalidating the iterator.
      processing_dispatchers_ = true;
      for (Dispatcher* disp : dispatchers_) {
        if (!process_io && (disp != signal_wakeup_))
          continue;
        SOCKET s = disp->GetSocket();
        if (disp->CheckSignalClose()) {
          // We just signalled close, don't poll this socket
        } else if (s != INVALID_SOCKET) {
          WSAEventSelect(s, events[0],//wgj socket事件
                         FlagsToEvents(disp->GetRequestedEvents()));
        } else {
          events.push_back(disp->GetWSAEvent());//普通事件
          event_owners.push_back(disp);
        }
      }

      processing_dispatchers_ = false;
      // Process deferred dispatchers that have been added/removed while the
      // events were handled above.
      AddRemovePendingDispatchers();
    }

    // Which is shorter, the delay wait or the asked wait?

    int64_t cmsNext;
    if (cmsWait == kForever) {
      cmsNext = cmsWait;
    } else {
      cmsNext = std::max<int64_t>(0, cmsTotal - cmsElapsed);
    }

    // Wait for one of the events to signal
    DWORD dw =
        WSAWaitForMultipleEvents(static_cast<DWORD>(events.size()), &events[0],//wgj 类似WaitForMultipleObjects()
                                 false, static_cast<DWORD>(cmsNext), false);

    if (dw == WSA_WAIT_FAILED) {
      // Failed?
      // TODO(pthatcher): need a better strategy than this!
      WSAGetLastError();
      RTC_NOTREACHED();
      return false;
    } else if (dw == WSA_WAIT_TIMEOUT) {
      // Timeout?
      return true;
    } else {
      // Figure out which one it is and call it
      CritScope cr(&crit_);
      int index = dw - WSA_WAIT_EVENT_0;
      if (index > 0) {//普通事件
        --index;  // The first event is the socket event
        Dispatcher* disp = event_owners[index];
        // The dispatcher could have been removed while waiting for events.
        if (dispatchers_.find(disp) != dispatchers_.end()) {
          disp->OnPreEvent(0);
          disp->OnEvent(0, 0);
        }
      } else if (process_io) {//socket事件
        processing_dispatchers_ = true;
        for (Dispatcher* disp : dispatchers_) {
          SOCKET s = disp->GetSocket();
          if (s == INVALID_SOCKET)
            continue;

          WSANETWORKEVENTS wsaEvents;
          int err = WSAEnumNetworkEvents(s, events[0], &wsaEvents); //注意:此处是涉及socket的部分
          if (err == 0) {
            {
              if ((wsaEvents.lNetworkEvents & FD_READ) &&
                  wsaEvents.iErrorCode[FD_READ_BIT] != 0) {
                RTC_LOG(WARNING)
                    << "PhysicalSocketServer got FD_READ_BIT error "
                    << wsaEvents.iErrorCode[FD_READ_BIT];
              }
              if ((wsaEvents.lNetworkEvents & FD_WRITE) &&
                  wsaEvents.iErrorCode[FD_WRITE_BIT] != 0) {
                RTC_LOG(WARNING)
                    << "PhysicalSocketServer got FD_WRITE_BIT error "
                    << wsaEvents.iErrorCode[FD_WRITE_BIT];
              }
              if ((wsaEvents.lNetworkEvents & FD_CONNECT) &&
                  wsaEvents.iErrorCode[FD_CONNECT_BIT] != 0) {
                RTC_LOG(WARNING)
                    << "PhysicalSocketServer got FD_CONNECT_BIT error "
                    << wsaEvents.iErrorCode[FD_CONNECT_BIT];
              }
              if ((wsaEvents.lNetworkEvents & FD_ACCEPT) &&
                  wsaEvents.iErrorCode[FD_ACCEPT_BIT] != 0) {
                RTC_LOG(WARNING)
                    << "PhysicalSocketServer got FD_ACCEPT_BIT error "
                    << wsaEvents.iErrorCode[FD_ACCEPT_BIT];
              }
              if ((wsaEvents.lNetworkEvents & FD_CLOSE) &&
                  wsaEvents.iErrorCode[FD_CLOSE_BIT] != 0) {
                RTC_LOG(WARNING)
                    << "PhysicalSocketServer got FD_CLOSE_BIT error "
                    << wsaEvents.iErrorCode[FD_CLOSE_BIT];
              }
            }
            uint32_t ff = 0;
            int errcode = 0;
            if (wsaEvents.lNetworkEvents & FD_READ)
              ff |= DE_READ;
            if (wsaEvents.lNetworkEvents & FD_WRITE)
              ff |= DE_WRITE;
            if (wsaEvents.lNetworkEvents & FD_CONNECT) {
              if (wsaEvents.iErrorCode[FD_CONNECT_BIT] == 0) {
                ff |= DE_CONNECT;
              } else {
                ff |= DE_CLOSE;
                errcode = wsaEvents.iErrorCode[FD_CONNECT_BIT];
              }
            }
            if (wsaEvents.lNetworkEvents & FD_ACCEPT)
              ff |= DE_ACCEPT;
            if (wsaEvents.lNetworkEvents & FD_CLOSE) {
              ff |= DE_CLOSE;
              errcode = wsaEvents.iErrorCode[FD_CLOSE_BIT];
            }
            if (ff != 0) {
              disp->OnPreEvent(ff);
              disp->OnEvent(ff, errcode); //注意:此处是涉及socket的部分
            }
          }
        }

        processing_dispatchers_ = false;
        // Process deferred dispatchers that have been added/removed while the
        // events were handled above.
        AddRemovePendingDispatchers();
      }

      // Reset the network event until new activity occurs
      WSAResetEvent(socket_ev_);
    }

    // Break?
    if (!fWait_)
      break;
    cmsElapsed = TimeSince(msStart);
    if ((cmsWait != kForever) && (cmsElapsed >= cmsWait)) {
      break;
    }
  }

  // Done
  return true;
}
#endif  // WEBRTC_WIN

Linux中:

复制代码
bool PhysicalSocketServer::Wait(int cmsWait, bool process_io) {
else if (epoll_fd_ != INVALID_SOCKET) {
    return WaitEpoll(cmsWait);//wgj epoll
    
  
bool PhysicalSocketServer::WaitEpoll(int cmsWait) {
    int n = epoll_wait(epoll_fd_, &epoll_events_[0],
                       static_cast<int>(epoll_events_.size()),
                       static_cast<int>(tvWait)); //wgj

什么时候唤醒线程?[此处指的是普通队列事件,socket事件的唤醒是看不到的]

复制代码
MessageQueue::Post方法也很重要,用于向消息队列中添加消息。
struct Message {
  Message()
      : phandler(nullptr), message_id(0), pdata(nullptr), ts_sensitive(0) {}
  inline bool Match(MessageHandler* handler, uint32_t id) const {
    return (handler == nullptr || handler == phandler) &&
           (id == MQID_ANY || id == message_id);
  }
  Location posted_from;
  MessageHandler* phandler;
  uint32_t message_id;
  MessageData* pdata;
  int64_t ts_sensitive;
};

void MessageQueue::Post(const Location& posted_from,
                        MessageHandler* phandler,
                        uint32_t id,
                        MessageData* pdata,
                        bool time_sensitive) {
  if (IsQuitting()) {
    delete pdata;
    return;
  }

  // Keep thread safe
  // Add the message to the end of the queue
  // Signal for the multiplexer to return

  {
    CritScope cs(&crit_);
    Message msg;
    msg.posted_from = posted_from;
    msg.phandler = phandler;
    msg.message_id = id;
    msg.pdata = pdata;
    if (time_sensitive) {
      msg.ts_sensitive = TimeMillis() + kMaxMsgLatency;
    }
    msgq_.push_back(msg);
  }
  WakeUpSocketServer(); //wgj
}

class MessageHandler {
 public:
  virtual ~MessageHandler();
  virtual void OnMessage(Message* msg) = 0;

 protected:
  MessageHandler() {}

 private:
  RTC_DISALLOW_COPY_AND_ASSIGN(MessageHandler);
};

一个demo:

复制代码
#include <iostream>
#include "rtc_base/thread.h"
#include "rtc_base/async_invoker.h"
#include "rtc_base/event.h"
#include "rtc_base/null_socket_server.h"
#include "rtc_base/physical_socket_server.h"
#include "rtc_base/socket_address.h"
#include "rtc_base/third_party/sigslot/sigslot.h"
#include "rtc_base/async_udp_socket.h"

using namespace std;
using namespace rtc;

struct MyMessage : public MessageData {
  explicit MyMessage(int v) : value(v) {}
  int value;
};

class Client : public MessageHandler,public sigslot::has_slots<> {
 public:
  Client(AsyncUDPSocket* socket,Thread * thread) : socket_(socket),thread_(thread) {
    // 用到了webrtc的sigslot,需要专门写篇文章。
    // 简单理解:OnPacket注册为socket的数据读取回调。
    socket_->SignalReadPacket.connect(this, &Client::OnPacket);
  }
  
  ~Client() { 
    delete socket_; 
  }

  // 消息队列中,消息触发后的回调。
  void OnMessage(Message* pmsg) override {
    MyMessage* msg = static_cast<MyMessage*>(pmsg->pdata);
    PacketOptions opt;
    socket_->Send(&msg->value, sizeof(msg->value),opt);
    delete msg;
  }
  
  void OnPacket(AsyncPacketSocket* socket,
                const char* buf,
                size_t size,
                const SocketAddress& remote_addr,
                const int64_t& packet_time_us) {
    uint32_t data = reinterpret_cast<const uint32_t*>(buf)[0];
    cout << "---Recv server data:"<<data<<endl;
    data++;
    // 收到服务端的消息,累加后,继续发送给服务端
    thread_->PostDelayed(RTC_FROM_HERE, 2000, this, 0,new MyMessage(data));
  }

 private:
  AsyncUDPSocket* socket_;
  Thread * thread_;
};

class Server : public MessageHandler,public sigslot::has_slots<> {
 public:
  Server(AsyncUDPSocket* socket,Thread * thread) : socket_(socket),thread_(thread) {
    socket_->SignalReadPacket.connect(this, &Server::OnPacket);
  }
  
  ~Server() { 
    delete socket_; 
  }

  void OnMessage(Message* pmsg) override {
    MyMessage* msg = static_cast<MyMessage*>(pmsg->pdata);
    PacketOptions opt;
    socket_->SendTo(&msg->value, sizeof(msg->value),remote_addr_,opt);
    delete msg;
  }

  void OnPacket(AsyncPacketSocket* socket,
                const char* buf,
                size_t size,
                const SocketAddress& remote_addr,
                const int64_t& packet_time_us) {
    remote_addr_=remote_addr;
    uint32_t data = reinterpret_cast<const uint32_t*>(buf)[0];
    cout << "---Recv client data:"<<data<<"|"<<remote_addr_.ToString()<<endl;
    data++;
    // 收到客户端的消息,累加后,继续发送给客户端
    thread_->PostDelayed(RTC_FROM_HERE, 2000, this, 0,new MyMessage(data));
  }

 private:
  AsyncUDPSocket* socket_;
  Thread * thread_;
  SocketAddress remote_addr_;
};

int main(){
  // 客户端
  SocketAddress addr1("0.0.0.0", 7000);
  std::unique_ptr<Thread> th1=Thread::CreateWithSocketServer();
  AsyncSocket* sock1 = th1->socketserver()->CreateAsyncSocket(addr1.family(), SOCK_DGRAM);
  AsyncUDPSocket * clientSock=AsyncUDPSocket::Create(sock1, addr1);
  Client client(clientSock,th1.get());

  // 服务端
  SocketAddress addr2("0.0.0.0", 7001);
  std::unique_ptr<Thread> th2=Thread::CreateWithSocketServer();
  AsyncSocket* sock2 = th2->socketserver()->CreateAsyncSocket(addr2.family(), SOCK_DGRAM);
  AsyncUDPSocket * serverSock=AsyncUDPSocket::Create(sock2, addr2);
  Server server(serverSock,th2.get());

  sock1->Connect(serverSock->GetLocalAddress());
  
  th1->Start();
  th2->Start();

  // 触发终端发数据,向线程的消息队列添加Message
  th1->PostDelayed(RTC_FROM_HERE, 1000, &client, 0, new MyMessage(1));

  // 主线程,无限循环,避免程序退出
  Thread::Current()->ProcessMessages(-1);
  return 0;
}
相关推荐
任小栗2 天前
【实战干货】Vue3 + WebRTC + SIP + AI 实现全自动语音接警系统(远程流获取+实时ASR+TTS回播)
人工智能·webrtc
runner365.git2 天前
如何使用RTCPilot--跨平台WebRTC开源服务
webrtc·音视频开发
runner365.git2 天前
RTC实现VoiceAgent(二)
大模型·webrtc·实时音视频·voiceagent
runner365.git3 天前
WebRTC实现VoiceAgent智能体
webrtc
runner365.git3 天前
RTCPilot的信令流程
webrtc·音视频开发
runner365.git3 天前
如何使用RTCPilot配置一个集群RTC服务
webrtc·实时音视频·音视频开发
深念Y4 天前
从WebSocket到WebRTC,豆包级实时语音交互背后的技术演进
websocket·网络协议·实时互动·webrtc·语音识别·实时音视频
AI视觉网奇6 天前
webrtc 硬编码
ffmpeg·webrtc
REDcker6 天前
WebRTC 接收端音频流畅低延迟播放:原理与源码对照(NetEQ / Opus)
音视频·webrtc
SUNNY_SHUN6 天前
LiveKit Agents:基于WebRTC的实时语音视频AI Agent框架(9.9k Star)
人工智能·github·webrtc