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;
}
相关推荐
linux_cfan5 天前
WordPress 视频播放痛点解决方案:支持 RTSP/WebRTC 与字幕检索的 ZWPlayer 插件实测
php·音视频·webrtc
txp玩Linux6 天前
rk3568移植WebRTC AudioProcessing
webrtc
一叶飘零_sweeeet7 天前
WebRTC 核心原理拆解与企业级 RTC SDK 落地实践
webrtc
nov4th10 天前
WebRTC实现无插件多端视频通话
java·spring boot·音视频·webrtc·实时音视频·html5·视频
好家伙VCC14 天前
### WebRTC技术:实时通信的革新与实现####webRTC(Web Real-TimeComm
java·前端·python·webrtc
XHW___00114 天前
webrtc 关键模块创建的时机
网络·音视频·webrtc
我真会写代码14 天前
WebSocket:告别轮询,实现Web实时通信 WebRTC:无需插件,实现浏览器端实时音视频通信
网络·websocket·网络协议·webrtc·实时音视频
又是忙碌的一天14 天前
SpringBoot+Vue+Netty+WebSocket+WebRTC 视频聊天实现
websocket·音视频·webrtc
柒.梧.15 天前
理解WebRTC:浏览器原生实时音视频通信
webrtc·实时音视频