• 【MediaSoup---源码篇】(二)Router


    概述

    Router:路由对象,类似于房间的功能,保存了流之间的订阅关系,它接收 Producer 的数据并转发给订阅该 Producer 的 Consumer

    Router继承了以下类:

    RTC::Transport::Listener,RTC::RtpObserver::Listener,Channel::ChannelSocket::RequestHandler

    RTC::Transport,它用于在mediasoup与客户端之间传输实时音视频数据

    RTC::RtpObserver,是一个用于观察和处理实时传输协议(RTP)数据的接口

    Channel::ChannelSocket,是用于响应与上层之间的传输

    1. { //router和房间是一对一的关系,一个router就表示一个房间。当router接收到房间内成员的RTP数据后,会转发给所有房间内的其它成员,或者其它worker。
    2. class Router : public RTC::Transport::Listener,
    3. public RTC::RtpObserver::Listener,
    4. public Channel::ChannelSocket::RequestHandler
    创建Router房间的流程

     在Worker层,首先上层会传入一个创建Router的信令,先到达Worker

    inline void Worker::HandleRequest(Channel::ChannelRequest* request)

     通过类型判断进入到创建房间中,其中在Worker中保存了roomid与Router实例的映射关系

    1. //创建房间
    2. case Channel::ChannelRequest::MethodId::WORKER_CREATE_ROUTER:
    3. {
    4. std::string routerId;//保存上层传递的roomid
    5. try
    6. {
    7. //根据上层信令传入的roomid来创建底层的房间概念
    8. SetNewRouterIdFromData(request->data, routerId);
    9. }
    10. catch (const MediaSoupError& error)
    11. {
    12. MS_THROW_ERROR("%s [method:%s]", error.what(), request->method.c_str());
    13. }
    14. //创建好了Router与Router内处理各种消息的事宜
    15. auto* router = new RTC::Router(this->shared, routerId, this);
    16. //把routerId和router实例进行绑定
    17. this->mapRouters[routerId] = router;
    18. MS_DEBUG_DEV("Router created [routerId:%s]", routerId.c_str());
    19. request->Accept();
    20. break;
    21. }
    Router构造函数
    1. /* Instance methods. */
    2. // 实例化`Router` 类并注册其消息处理程序的构造函数。
    3. Router::Router(RTC::Shared* shared, const std::string& id, Listener* listener)
    4. : id(id), shared(shared), listener(listener)
    5. {
    6. MS_TRACE();
    7. /*
    8. 这段代码是C++中的函数调用,用于将一个请求处理程序注册到一个通道消息注册器中。具体来说,这个函数调用的参数包括:
    9. -`this->id`:表示当前对象的id或标识符。
    10. -`channelRequestHandler`:指向请求处理函数的指针。
    11. -`payloadChannelRequestHandler`:指向负载请求处理函数的指针,此处为nullptr,表示没有负载请求处理函数。
    12. -`payloadChannelNotificationHandler`:指向负载通知处理函数的指针,此处为nullptr,表示没有负载通知处理函数。
    13. 通过注册请求处理程序,可以在接收到相应的通道消息时,调用相应的处理函数对消息进行处理。这个函数调用是一种常见的使用C++进行事件驱动编程的方式。
    14. */
    15. // NOTE: This may throw.
    16. this->shared->channelMessageRegistrator->RegisterHandler(
    17. this->id,
    18. /*channelRequestHandler*/ this,
    19. /*payloadChannelRequestHandler*/ nullptr,
    20. /*payloadChannelNotificationHandler*/ nullptr);
    21. }

    对以上代码深度解析,首先在Router中持有了RTC::Shared 和  Listener。

    RTC::Shared实际为Worker中的shared,Listener为Worker.

    在构造函数中有一个重要的地方,我们来分析一下this->shared->channelMessageRegistrator->RegisterHandler,这句调用的意义在于,将当前的Router注册为响应通道消息的处理函数,如果通道发生了响应消息,就会自动转到该Router中进行相应处理。其中保存的方法为roomid与房间实例进行映射。

    1. /将当前路由器实例注册为消息处理程序。
    2. //`RegisterHandler()` 方法为 mediasoup 应用程序提供通用消息通信区域,并可将不同的消息分发给不同的路由器实例进行处理。
    3. void ChannelMessageRegistrator::RegisterHandler(
    4. const std::string& id,//当前路由器实例的 ID,用于标识路由器实例
    5. Channel::ChannelSocket::RequestHandler* channelRequestHandler,//指向处理特定类型的通用请求的函数的指针
    6. PayloadChannel::PayloadChannelSocket::RequestHandler* payloadChannelRequestHandler,//通用请求和通知处理程序,这些处理程序用于处理特定类型的请求和通知消息
    7. PayloadChannel::PayloadChannelSocket::NotificationHandler* payloadChannelNotificationHandler)
    8. {
    9. MS_TRACE();
    10. //channelRequestHandler理论上为创建Router时候的实例
    11. if (channelRequestHandler != nullptr)
    12. {
    13. if (this->mapChannelRequestHandlers.find(id) != this->mapChannelRequestHandlers.end())
    14. {
    15. MS_THROW_ERROR("Channel request handler with ID %s already exists", id.c_str());
    16. }
    17. //把id作为key,处理特定类型的通用请求的函数的指针作为value保存
    18. this->mapChannelRequestHandlers[id] = channelRequestHandler;
    19. }
    20. //理论说用transport的时候会进行绑定
    21. if (payloadChannelRequestHandler != nullptr)
    22. { //如果存在旧的,就先删除
    23. if (this->mapPayloadChannelRequestHandlers.find(id) != this->mapPayloadChannelRequestHandlers.end())
    24. {
    25. if (channelRequestHandler != nullptr)
    26. {
    27. this->mapChannelRequestHandlers.erase(id);
    28. }
    29. MS_THROW_ERROR("PayloadChannel request handler with ID %s already exists", id.c_str());
    30. }
    31. //重新为本次分配
    32. this->mapPayloadChannelRequestHandlers[id] = payloadChannelRequestHandler;
    33. }
    34. if (payloadChannelNotificationHandler != nullptr)
    35. {
    36. if (
    37. this->mapPayloadChannelNotificationHandlers.find(id) !=
    38. this->mapPayloadChannelNotificationHandlers.end())
    39. {
    40. if (channelRequestHandler != nullptr)
    41. {
    42. this->mapChannelRequestHandlers.erase(id);
    43. }
    44. if (payloadChannelRequestHandler != nullptr)
    45. {
    46. this->mapPayloadChannelRequestHandlers.erase(id);
    47. }
    48. MS_THROW_ERROR("PayloadChannel notification handler with ID %s already exists", id.c_str());
    49. }
    50. this->mapPayloadChannelNotificationHandlers[id] = payloadChannelNotificationHandler;
    51. }
    52. }

    当发生通道消息时候会先通过ID查找对应Router实例

    1. //通过路由器ID查找相应的处理函数
    2. Channel::ChannelSocket::RequestHandler* ChannelMessageRegistrator::GetChannelRequestHandler(
    3. const std::string& id)
    4. {
    5. MS_TRACE();
    6. auto it = this->mapChannelRequestHandlers.find(id);
    7. if (it != this->mapChannelRequestHandlers.end())
    8. {
    9. return it->second;
    10. }
    11. else
    12. {
    13. return nullptr;
    14. }
    15. }

    在Worker中触发上面所说的

    1. default:
    2. {
    3. try
    4. { //事件驱动机制通过id来查找相对应的处理模块
    5. auto* handler =
    6. this->shared->channelMessageRegistrator->GetChannelRequestHandler(request->handlerId);
    7. if (handler == nullptr)
    8. {
    9. MS_THROW_ERROR("Channel request handler with ID %s not found", request->handlerId.c_str());
    10. }
    11. //一般是Router::HandleRequest
    12. handler->HandleRequest(request);
    13. }
    14. catch (const MediaSoupTypeError& error)
    15. {
    16. MS_THROW_TYPE_ERROR("%s [method:%s]", error.what(), request->method.c_str());
    17. }
    18. catch (const MediaSoupError& error)
    19. {
    20. MS_THROW_ERROR("%s [method:%s]", error.what(), request->method.c_str());
    21. }
    22. break;
    23. }

    经过上面的周转,又回来的Router中的处理

    1. //房间内部处理指令
    2. void Router::HandleRequest(Channel::ChannelRequest* request)

  • 相关阅读:
    前端智能化实践——可微编程
    数据库的三大范式(重要)
    科技资讯|苹果Vision Pro头显申请游戏手柄专利和商标
    阿里P8现身说法,解密“架构”原理与实战笔记:从分布式到微服务
    springboot集成 生成二维码微信支付
    Java高级应用——多线程
    艾美捷支原体检测试剂盒基本参数和样本数据分析
    SpringMVC实现文件的上传(CommonsMultipartResolver和StanderServletMultipartResolver)
    RubyMine 2023:让Ruby编程变得更简单 mac/win版
    Android U 匹配不到APN,无法发起数据建立的问题分析
  • 原文地址:https://blog.csdn.net/qq_40179458/article/details/133162522