mediasoup源码分析--channel创建及信令交互

2024-06-18 09:44

本文主要是介绍mediasoup源码分析--channel创建及信令交互,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

mediasoup源码分析--channel创建及信令交互

    • 概述
    • 跨职能图
    • 业务流程图
    • 代码剖析

概述

在golang实现mediasoup的tcp服务及channel通道一文中,已经介绍过信令服务中tcp和channel的创建,本文主要讲解c++中mediasoup的channel创建,以及信令服务和mediasoup服务如何交互

跨职能图

c92bb199ca71184775fa8bea149e201.png

业务流程图

image.png

数据发送有两种方式:
应用层发送的request最后被封装在Requst对象中,其中包含着"id",因为Request对象中包含着Channel::UnixStreamSocket对象,所以可以直接调用Request::Accept()将处理后的结果告诉应用层进程。
Worker进程也可以主动给应用层进程发送消息,通过Notifier::Emit()即可以给应用进程发送消息,Notifier类中有Channel::UnixStreamSocket,所以直接调用Channel::UnixStreamSocket::Send()就可以发送消息。Notifier类内部的数据成员和函数成员都是静态的,所以在任意位置可以直接通过Channel::Notifier::Emit()函数发送消息。

代码剖析

1.channel创建

int main(int argc, char* argv[])
{// Ensure we are called by our Node library.if (argc == 1){std::cerr << "ERROR: you don't seem to be my real father" << std::endl;std::_Exit(EXIT_FAILURE);}std::string id = std::string(argv[1]);std::string ip = std::string(argv[2]);int port = atoi(argv[3]);int iperfPort = atoi(argv[4]);// Initialize libuv stuff (we need it for the Channel).DepLibUV::ClassInit();//..........省略部分代码..............// Set the Channel socket (this will be handled and deleted by the Worker).printf("new Channel to %s:%d\n",ip.c_str(),port);auto* channel = new Channel::UnixStreamSocket(ip,port);//..........省略部分代码..............try{// Run the Worker.Worker worker(id,channel);// Worker ended.destroy();exitSuccess();}catch (const MediaSoupError& error){MS_ERROR_STD("failure exit: %s", error.what());destroy();exitWithError();}
}

UnixStreamSocket构造函数

UnixStreamSocket::UnixStreamSocket(const std::string& ip,int port) : ::UnixStreamSocket::UnixStreamSocket(ip,port, MaxSize)
{MS_TRACE_STD();// Create the JSON reader.{Json::CharReaderBuilder builder;Json::Value settings = Json::nullValue;Json::Value invalidSettings;builder.strictMode(&settings);MS_ASSERT(builder.validate(&invalidSettings), "invalid Json::CharReaderBuilder");this->jsonReader = builder.newCharReader();}// Create the JSON writer.{Json::StreamWriterBuilder builder;Json::Value invalidSettings;builder["commentStyle"]            = "None";builder["indentation"]             = "";builder["enableYAMLCompatibility"] = false;builder["dropNullPlaceholders"]    = false;MS_ASSERT(builder.validate(&invalidSettings), "invalid Json::StreamWriterBuilder");this->jsonWriter = builder.newStreamWriter();}
}

跳转到handles\UnixStreamSocket.cpp下

UnixStreamSocket::UnixStreamSocket( const std::string& ip,int port,size_t bufferSize) : bufferSize(bufferSize)
{printf("::UnixStreamSocket::UnixStreamSocket\n");MS_TRACE_STD();int err;this->uvHandle       = new uv_tcp_t;this->uvHandle->data = (void*)this;err = uv_tcp_init(DepLibUV::GetLoop(), this->uvHandle);if (err != 0){delete this->uvHandle;this->uvHandle = nullptr;printf("uv_tcp_init() failed: %s\n", uv_strerror(err));MS_THROW_ERROR_STD("uv_tcp_init() failed: %s", uv_strerror(err));}struct sockaddr_in dest;uv_ip4_addr(ip.c_str(), port, &dest);this->connect = new uv_connect_t;printf("will connect to %s:%d\n",ip.c_str(),port);err = uv_tcp_connect(this->connect, this->uvHandle, (const struct sockaddr*)&dest, onConnect);if (err != 0){delete this->uvHandle;this->uvHandle = nullptr;printf("uv_tcp_connect() failed: %s\n", uv_strerror(err));MS_THROW_ERROR_STD("uv_tcp_connect() failed: %s", uv_strerror(err));}// Start reading.err = uv_read_start(reinterpret_cast<uv_stream_t*>(this->uvHandle),static_cast<uv_alloc_cb>(onAlloc),static_cast<uv_read_cb>(onRead));if (err != 0){uv_close(reinterpret_cast<uv_handle_t*>(this->uvHandle), static_cast<uv_close_cb>(onClose));MS_THROW_ERROR_STD("uv_read_start() failed: %s", uv_strerror(err));}// NOTE: Don't allocate the buffer here. Instead wait for the first uv_alloc_cb().
}

代码中的uv_read_start接口中onRead回调

    err = uv_read_start(reinterpret_cast<uv_stream_t*>(this->uvHandle),static_cast<uv_alloc_cb>(onAlloc),static_cast<uv_read_cb>(onRead));

跳转到onRead中

inline static void onRead(uv_stream_t* handle, ssize_t nread, const uv_buf_t* buf)
{auto* socket = static_cast<UnixStreamSocket*>(handle->data);if (socket == nullptr)return;socket->OnUvRead(nread, buf);
}

OnUvRead中调用UserOnUnixStreamRead

	void UnixStreamSocket::UserOnUnixStreamRead(){MS_TRACE_STD();// Be ready to parse more than a single message in a single TCP chunk.while (true){if (IsClosed())return;size_t readLen  = this->bufferDataLen - this->msgStart;char* jsonStart = nullptr;size_t jsonLen;int nsRet = netstring_read(reinterpret_cast<char*>(this->buffer + this->msgStart), readLen, &jsonStart, &jsonLen);//.............省略部分代码..............// If here it means that jsonStart points to the beginning of a JSON string// with jsonLen bytes length, so recalculate readLen.readLen =reinterpret_cast<const uint8_t*>(jsonStart) - (this->buffer + this->msgStart) + jsonLen + 1;Json::Value json;std::string jsonParseError;if (this->jsonReader->parse((const char*)jsonStart, (const char*)jsonStart + jsonLen, &json, &jsonParseError)){Channel::Request* request = nullptr;try{request = new Channel::Request(this, json);}catch (const MediaSoupError& error){MS_ERROR_STD("discarding wrong Channel request");}if (request != nullptr){// Notify the listener.this->listener->OnChannelRequest(this, request);// Delete the Request.delete request;}//.............省略部分代码.................}}

channel创建完成,至此,跳转到worker.cpp中的OnChannelRequest接口。mediasoup监听channel信令并根据request->methodId分类处理
根据request->methodId,分别执行不同的业务
request->methodId有如下分类

	std::unordered_map<std::string, Request::MethodId> Request::string2MethodId ={{ "worker.dump",                       Request::MethodId::WORKER_DUMP                          },{ "worker.updateSettings",             Request::MethodId::WORKER_UPDATE_SETTINGS               },{ "worker.createRouter",               Request::MethodId::WORKER_CREATE_ROUTER                 },{ "router.close",                      Request::MethodId::ROUTER_CLOSE                         },{ "router.dump",                       Request::MethodId::ROUTER_DUMP                          },{ "router.createWebRtcTransport",      Request::MethodId::ROUTER_CREATE_WEBRTC_TRANSPORT       },{ "router.createPlainRtpTransport",    Request::MethodId::ROUTER_CREATE_PLAIN_RTP_TRANSPORT    },{ "router.createProducer",             Request::MethodId::ROUTER_CREATE_PRODUCER               },{ "router.createConsumer",             Request::MethodId::ROUTER_CREATE_CONSUMER               },{ "router.setAudioLevelsEvent",        Request::MethodId::ROUTER_SET_AUDIO_LEVELS_EVENT        },{ "transport.close",                   Request::MethodId::TRANSPORT_CLOSE                      },{ "transport.dump",                    Request::MethodId::TRANSPORT_DUMP                       },{ "transport.getStats",                Request::MethodId::TRANSPORT_GET_STATS                  },{ "transport.setRemoteDtlsParameters", Request::MethodId::TRANSPORT_SET_REMOTE_DTLS_PARAMETERS },{ "transport.setRemoteParameters",     Request::MethodId::TRANSPORT_SET_REMOTE_PARAMETERS      },{ "transport.setMaxBitrate",           Request::MethodId::TRANSPORT_SET_MAX_BITRATE            },{ "transport.changeUfragPwd",          Request::MethodId::TRANSPORT_CHANGE_UFRAG_PWD           },{ "transport.startMirroring",          Request::MethodId::TRANSPORT_START_MIRRORING            },{ "transport.stopMirroring",           Request::MethodId::TRANSPORT_STOP_MIRRORING             },{ "producer.close",                    Request::MethodId::PRODUCER_CLOSE                       },{ "producer.dump",                     Request::MethodId::PRODUCER_DUMP                        },{ "producer.getStats",                 Request::MethodId::PRODUCER_GET_STATS                   },{ "producer.pause",                    Request::MethodId::PRODUCER_PAUSE                       },{ "producer.resume" ,                  Request::MethodId::PRODUCER_RESUME                      },{ "producer.setPreferredProfile",      Request::MethodId::PRODUCER_SET_PREFERRED_PROFILE       },{ "consumer.close",                    Request::MethodId::CONSUMER_CLOSE                       },{ "consumer.dump",                     Request::MethodId::CONSUMER_DUMP                        },{ "consumer.getStats",                 Request::MethodId::CONSUMER_GET_STATS                   },{ "consumer.enable",                   Request::MethodId::CONSUMER_ENABLE                      },{ "consumer.pause",                    Request::MethodId::CONSUMER_PAUSE                       },{ "consumer.resume",                   Request::MethodId::CONSUMER_RESUME                      },{ "consumer.setPreferredProfile",      Request::MethodId::CONSUMER_SET_PREFERRED_PROFILE       },{ "consumer.setEncodingPreferences",   Request::MethodId::CONSUMER_SET_ENCODING_PREFERENCES    },{ "consumer.requestKeyFrame",          Request::MethodId::CONSUMER_REQUEST_KEY_FRAME           }};

下一章节介绍mediasoup如何将信令返回值及其他通知信息推送到信令服务,敬请期待!

这篇关于mediasoup源码分析--channel创建及信令交互的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1071855

相关文章

性能分析之MySQL索引实战案例

文章目录 一、前言二、准备三、MySQL索引优化四、MySQL 索引知识回顾五、总结 一、前言 在上一讲性能工具之 JProfiler 简单登录案例分析实战中已经发现SQL没有建立索引问题,本文将一起从代码层去分析为什么没有建立索引? 开源ERP项目地址:https://gitee.com/jishenghua/JSH_ERP 二、准备 打开IDEA找到登录请求资源路径位置

JAVA智听未来一站式有声阅读平台听书系统小程序源码

智听未来,一站式有声阅读平台听书系统 🌟&nbsp;开篇:遇见未来,从“智听”开始 在这个快节奏的时代,你是否渴望在忙碌的间隙,找到一片属于自己的宁静角落?是否梦想着能随时随地,沉浸在知识的海洋,或是故事的奇幻世界里?今天,就让我带你一起探索“智听未来”——这一站式有声阅读平台听书系统,它正悄悄改变着我们的阅读方式,让未来触手可及! 📚&nbsp;第一站:海量资源,应有尽有 走进“智听

【Python编程】Linux创建虚拟环境并配置与notebook相连接

1.创建 使用 venv 创建虚拟环境。例如,在当前目录下创建一个名为 myenv 的虚拟环境: python3 -m venv myenv 2.激活 激活虚拟环境使其成为当前终端会话的活动环境。运行: source myenv/bin/activate 3.与notebook连接 在虚拟环境中,使用 pip 安装 Jupyter 和 ipykernel: pip instal

在cscode中通过maven创建java项目

在cscode中创建java项目 可以通过博客完成maven的导入 建立maven项目 使用快捷键 Ctrl + Shift + P 建立一个 Maven 项目 1 Ctrl + Shift + P 打开输入框2 输入 "> java create"3 选择 maven4 选择 No Archetype5 输入 域名6 输入项目名称7 建立一个文件目录存放项目,文件名一般为项目名8 确定

Java 创建图形用户界面(GUI)入门指南(Swing库 JFrame 类)概述

概述 基本概念 Java Swing 的架构 Java Swing 是一个为 Java 设计的 GUI 工具包,是 JAVA 基础类的一部分,基于 Java AWT 构建,提供了一系列轻量级、可定制的图形用户界面(GUI)组件。 与 AWT 相比,Swing 提供了许多比 AWT 更好的屏幕显示元素,更加灵活和可定制,具有更好的跨平台性能。 组件和容器 Java Swing 提供了许多

Java ArrayList扩容机制 (源码解读)

结论:初始长度为10,若所需长度小于1.5倍原长度,则按照1.5倍扩容。若不够用则按照所需长度扩容。 一. 明确类内部重要变量含义         1:数组默认长度         2:这是一个共享的空数组实例,用于明确创建长度为0时的ArrayList ,比如通过 new ArrayList<>(0),ArrayList 内部的数组 elementData 会指向这个 EMPTY_EL

如何在Visual Studio中调试.NET源码

今天偶然在看别人代码时,发现在他的代码里使用了Any判断List<T>是否为空。 我一般的做法是先判断是否为null,再判断Count。 看了一下Count的源码如下: 1 [__DynamicallyInvokable]2 public int Count3 {4 [__DynamicallyInvokable]5 get

SWAP作物生长模型安装教程、数据制备、敏感性分析、气候变化影响、R模型敏感性分析与贝叶斯优化、Fortran源代码分析、气候数据降尺度与变化影响分析

查看原文>>>全流程SWAP农业模型数据制备、敏感性分析及气候变化影响实践技术应用 SWAP模型是由荷兰瓦赫宁根大学开发的先进农作物模型,它综合考虑了土壤-水分-大气以及植被间的相互作用;是一种描述作物生长过程的一种机理性作物生长模型。它不但运用Richard方程,使其能够精确的模拟土壤中水分的运动,而且耦合了WOFOST作物模型使作物的生长描述更为科学。 本文让更多的科研人员和农业工作者

MOLE 2.5 分析分子通道和孔隙

软件介绍 生物大分子通道和孔隙在生物学中发挥着重要作用,例如在分子识别和酶底物特异性方面。 我们介绍了一种名为 MOLE 2.5 的高级软件工具,该工具旨在分析分子通道和孔隙。 与其他可用软件工具的基准测试表明,MOLE 2.5 相比更快、更强大、功能更丰富。作为一项新功能,MOLE 2.5 可以估算已识别通道的物理化学性质。 软件下载 https://pan.quark.cn/s/57

工厂ERP管理系统实现源码(JAVA)

工厂进销存管理系统是一个集采购管理、仓库管理、生产管理和销售管理于一体的综合解决方案。该系统旨在帮助企业优化流程、提高效率、降低成本,并实时掌握各环节的运营状况。 在采购管理方面,系统能够处理采购订单、供应商管理和采购入库等流程,确保采购过程的透明和高效。仓库管理方面,实现库存的精准管理,包括入库、出库、盘点等操作,确保库存数据的准确性和实时性。 生产管理模块则涵盖了生产计划制定、物料需求计划、