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如何将信令返回值及其他通知信息推送到信令服务,敬请期待!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/722658.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

深圳比创达电子EMC|EMC与EMI滤波器:守护电子设备的电磁防火墙

随着科技的飞速发展&#xff0c;电子设备在我们日常生活中的普及率越来越高&#xff0c;从智能手机到大型工业设备&#xff0c;无一不体现出电子技术的重要地位。然而&#xff0c;随之而来的电磁兼容性问题&#xff08;EMC&#xff09;和电磁干扰问题&#xff08;EMI&#xff0…

基于稀疏学习现代信号处理方法的旋转机械故障诊断(MATLAB)

通过对滚动轴承故障诊断研究现状及稀疏表示方法在滚动轴承故障诊断领域中应用现状的调研&#xff0c;发现稀疏表示方法与故障特征提取和故障分类的关联&#xff0c;针对故障诊断问题&#xff0c;通过构造合理的故障稀疏表示模型&#xff0c;选取适合的模型优化算法&#xff0c;…

华为HCIP Datacom H12-821 卷6

1.单选题 下面是一台路由器的部分配置&#xff0c;关于该部分配置描述正确的是&#xff0c;[HUAWEllJip ip-prefix plpermit 10.0.192.0 8 greater-equal 17 less-equal 18 A、10.0.192.0/8 网段内&#xff0c;掩码长度为 20 的路由会匹配到该前缀列表&#xff0c;匹配规则为…

[保姆级教程]uniapp配置vueX

文章目录 注意新建文件简单的使用 注意 uniapp是支持vueX的只需配置一下就好 新建文件 在src文件中&#xff0c;新建一个store&#xff08;如果有的话跳过&#xff09; 在store中新建一个js文件&#xff0c;修改js文件名称和选择模板为default 在 uni-app 项目根目录下&…

牛客周赛 F-花花的地图

原题链接&#xff1a;F-花花的地图 题目大意&#xff1a;的网格里面&#xff0c;.为可以通行&#xff0c;#为不可以通行&#xff0c;如果想要通行可以花费代价将一列的障碍全部清除&#xff0c;求从到的最小花费。 思路&#xff1a;迪杰斯特拉的变种&#xff0c;优先队列里面…

用研究的眼光解读如何基于UVM搭建验证平台《UVM实战》(可下载)

UVM&#xff08;Universal Verification Methodology&#xff0c;通用验证方法学&#xff09;是一种用于硬件设计和验证的标准化方法学&#xff0c;它基于SystemVerilog语言扩展&#xff0c;由Accellera组织推出&#xff0c;并得到了主要的EDA&#xff08;Electronic Design Au…

重磅!首个跨平台的通用Linux端间互联组件Klink在openKylin开源

随着智能终端设备的普及&#xff0c;多个智能终端设备之间的互联互通应用场景日益丰富&#xff0c;多设备互联互通应用场景需要开发者单独实现通讯协议。因此&#xff0c;为解决跨平台互联互通问题&#xff0c;由openKylin社区理事单位麒麟软件旗下星光麒麟团队成立的Connectiv…

音频处理软件adobe audition使用教程

教程1笔记 基本操作 点击文件-》新建-》多轨会话&#xff1a; 编辑-》首选项&#xff0c;设置自动保存时间&#xff1a; 导入素材&#xff0c;文件-》导入素材&#xff0c;或者直接拖动进来文件&#xff01; 导出多轨混音&#xff1a; 更改为需要导出的格式wav,mp3等格式&am…

ROS程序设计系列 - 2.ROS Package

ROS程序设计系列 - 2.ROS Package 1. 源由2. 关键要点2.1 ROS包组成2.2 消息解耦2.3 包版本管理2.4 编译配置2.5 ROS C Client Library2.5.1 Initialization and spinning2.5.2 Node handle2.5.3 Logging2.5.4 Subscribe and Publisher2.5.5 Parameters 2.6 Object Oriented Pr…

【Android】使用Binder(AIDL)实现利用自定义Bean进行的进程间通信(二)

项目前置 这是我之前写的关于Binder的一些知识点和使用基本数据类型在通信的文章&#xff0c;感兴趣的可以看一下: Binder&#xff08;一&#xff09;Binder的介绍和AIDL使用Binder的实例 项目目标 在两个APP之间进行数据传递&#xff0c;使用Android推荐的Binder通讯&#…

产业生态远超预期,商用进程全面提速:5G RedCap,凭什么这么火?

2022年6月&#xff0c;3GPP R17版本正式宣布冻结。除了针对传统5G技术标准进行完善之外&#xff0c;R17还推出了一项新的中高速物联技术标准&#xff0c;也就是我们今天文章的主角——RedCap。 RedCap推出后&#xff0c;受到了业界上下的广泛关注。它在传统5G的基础上&#xff…

新手小白系列——关于 Docker 安装的方法

Docker 是一个应用打包、分发、部署的工具基础概念&#xff1a; 镜像&#xff1a;软件安装包&#xff0c;可以方便的进行传播和安装。 容器&#xff1a;软件安装之后的状态&#xff0c;每个软件运行环境都是独立的、隔离的&#xff0c;称之为容器 仓库&#xff1a;专门用来传播…

k8s集群新增计算节点使用华为iscsi存储创建的pvc存储挂载报错:FailedMount

背景&#xff1a; 因公司业务需求的增长&#xff0c;导致kubernetes集群测试环境的计算节点资源不够使用了&#xff0c;这时候就申请了几台服务器加入到kubernetes集群中&#xff0c;因为维护的kubernetes集群的对接华为了iscsi存储&#xff0c;通过storageclass组件来创建pvc存…

Vue3中的常见组件通信之插槽

Vue3中的常见组件通信之插槽 概述 ​ 在vue3中常见的组件通信有props、mitt、v-model、 r e f s 、 refs、 refs、parent、provide、inject、pinia、slot等。不同的组件关系用不同的传递方式。常见的撘配形式如下表所示。 组件关系传递方式父传子1. props2. v-model3. $refs…

GANs网络在图像和视频技术中的应用前景

Hi~&#xff01;这里是奋斗的小羊&#xff0c;很荣幸您能阅读我的文章&#xff0c;诚请评论指点&#xff0c;欢迎欢迎 ~~ &#x1f4a5;&#x1f4a5;个人主页&#xff1a;奋斗的小羊 &#x1f4a5;&#x1f4a5;所属专栏&#xff1a;C语言 &#x1f680;本系列文章为个人学习…

vue3中实现3D地图——three.js

需求点 地图区域大小随着父盒子大小变动&#xff0c;窗口缩放自动适配每个区域显示不同颜色和高度&#xff0c;描边每个区域显示名字label和icon点击区域改变其透明度&#xff0c;并且弹窗显示信息窗口点击点也可以可以自由放大缩小&#xff0c;360度旋转 包 npm install d3^…

lib9-02 配置扩展 ACL

实验&#xff1a;配置扩展 ACL 1、实验目的 通过本实验可以掌握编号扩展 ACL 定义和应用的方法命名扩展 ACL 定义和应用的方法 2、实验拓扑 实验拓扑如下图所示。使用扩展 ACL 实现如下访问控制 拒绝 PC1 所在网段访问 Server1 的 Web 服务拒绝 PC2 所在网段访问 Server1 …

Localization.strings文件显示乱码

项目场景&#xff1a; ios app 的多语言检测 问题描述 想检测app本地化文件&#xff0c;但打开Localization.strings文件发现都是乱码 原因分析&#xff1a; 1.编码问题 2.strings被识别编码成了binary的格式 解决方案&#xff1a; 使用苹果提供的plutil把binary转成json格…

天风宏观:再论经济“去金融化”

天风宏观认为&#xff0c;经济“去地产化”之后也正在“去金融化”&#xff0c;应逐渐淡化金融数据对于经济的指示意义&#xff0c;更关注经济数据本身和进行中的结构转型。 5月金融数据延续了此前逻辑&#xff0c; 受规范手工补息、存款分流等因素影响&#xff0c;M1同比-4.2%…

chrome 使用本地替换功能替换接口返回内容

前言 在web开发或测试过程中&#xff0c;我们经常会需要修改接口返回值来模拟数据进行开发或测试。 常用的方式一般通过抓包工具&#xff0c;如charles&#xff0c;或fildder 的功能。 例如我们可以使用charles打断点的方式&#xff0c;或者使用charles的map local 功能进行…