mediasoup源码分析(三)channel创建及信令交互

news2024/10/7 2:27:56

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

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【吉林大学Java程序设计】第11章:网络编程技术

第11章&#xff1a;网络编程技术 1.网络协议概述2.网络类及应用&#xff08;1&#xff09;InetAddress类&#xff08;2&#xff09;ServerSocket类&#xff08;3&#xff09;Socket类基于TCP的点对点通信基于TCP的点对面通信&#xff08;一个服务器&#xff0c;多个客户端&…

css之sprite

css之sprite 图片整合 sprite 优势 整合的方法 ps 新建图层&#xff08;名字为英文、给定宽高、选择像素、背景内容设置透明、创建&#xff09;ctrlc复制小图 ctrlv 粘贴 选择工具移动位置裁剪工具&#xff0c;剪掉下方多余的位置 enter导出&#xff08;PNG&#xff09; 精灵…

2024年最好用的精简系统推荐!旧电脑福音!

精简版电脑系统经过精心优化&#xff0c;去除了冗余功能&#xff0c;保留了核心功能&#xff0c;让用户的操作更加便捷高效&#xff0c;同时也具备强大的兼容性和稳定性&#xff0c;整体操作体验感很好。但是&#xff0c;许多新手用户不知道在哪里才可以找到好用的精简版系统&a…

四步搞定!图文详解qq音乐转mp3

随着数字音乐的普及&#xff0c;许多人选择使用QQ音乐来欣赏自己喜爱的歌曲和专辑。然而&#xff0c;有时我们可能希望将QQ音乐中的音频转换为MP3格式&#xff0c;以便更灵活地在各种设备上播放或分享。虽然QQ音乐并没有直接提供MP3下载选项&#xff0c;但通过一些巧妙的方法&a…

对 PLC AC 模块的 TRIAC 输出进行故障排除

在大多数离散 PLC 系统中&#xff0c;排除输出设备故障的过程相当简单。如果输出端正常工作&#xff0c;则在“关闭”时应测量 0 V&#xff0c;在“开启”时应测量满源电压。对于数字和继电器输出&#xff0c;情况确实如此。对于由 TRIAC 驱动的 AC 输出也应如此&#xff0c;但…

streamlit markdown里支持latex公式显示

参考&#xff1a; https://docs.streamlit.io/develop/api-reference/write-magic/st.write https://discuss.streamlit.io/t/streamlit-markdown-a-streaming-markdown-component-with-latex-mermaid-table-code-support/72187 也有独立支持的st.latex 接口单独显示公司&…

Fedora40的#!bash #!/bin/bash #!/bin/env bash #!/usr/bin/bash #!/usr/bin/env bash

bash脚本开头可写成 #!/bin/bash , #!/bin/env bash , #!/usr/bin/bash , #!/usr/bin/env bash #!/bin/bash , #!/usr/bin/bash#!/bin/env bash , #!/usr/bin/env bash Fedora40Workstation版的 /bin 是 /usr/bin 的软链接, /sbin 是 /usr/sbin 的软链接, rootfedora:~# ll …

Android SurfaceFlinger——概述(一)

一、基础介绍 SurfaceFlinger 是 Android 系统中的一个关键组件&#xff0c;负责管理屏幕显示的合成和渲染。 服务角色&#xff1a;SurfaceFlinger 作为一个系统服务独立运行&#xff0c;它不依赖于任何应用程序进程&#xff0c;而是由系统启动并持续运行。窗口管理&#xff1a…

温度传感器NST175手册阅读

温度传感器NST175手册阅读 首先看芯片的输入和输出&#xff1a;主要关注IIC接口&#xff0c;毕竟是要驱动这个芯片读取温度。在编写此博客时还未对改温度传感器进行调试&#xff0c;只是阅读手册&#xff0c;把需要重点关注的地方标记出来。 一、芯片管脚 二、温度输出格式 …

【分享】WinRAR如何加密压缩文件?

WinRAR除了用来解压缩文件&#xff0c;还可以作为一款加密软件&#xff0c;给压缩文件设置密码保护&#xff0c;今天一起来看看&#xff0c;WinRAR的3种加密方法。 方法1&#xff1a;设置单次加密 如果偶尔需要给压缩文件设置密码&#xff0c;可以使用单次加密方法。 首先&am…

YOLOv10涨点改进:改进检测头(Partial_C_v10Detect)检测头结构创新,实现涨点

目录 1,YOLOv10介绍 1.1 C2fUIB介绍 1.2 PSA介绍 1.3 SCDown 1.Partial C v10Detect原理介绍 1.1 Partial Convolution 3.v10Detect二次创新引入到yolov10 3.1 修改ultralytics/nn/modules/head.py 第一处修改:PConv加入以下代码 1,YOLOv10介绍 论文:https://arxiv.or…

Python数据分析-对驾驶安全数据进行了预测

一、研究背景和意义 随着汽车保有量的不断增加&#xff0c;交通事故已成为全球范围内的重大公共安全问题。每年因交通事故造成的人员伤亡和财产损失给社会带来了巨大的负担。为了提高驾驶安全&#xff0c;减少交通事故的发生&#xff0c;许多研究致力于探索影响驾驶安全的因素…

IRIS论文阅读笔记

这是ICLR2023一篇world model的论文&#xff0c;提出了一个称为IRIS的world model方法模型仍然是分为两部分&#xff0c;一部分是模拟世界的world model&#xff0c;包括预测下一帧的观测&#xff0c;预测当前reward&#xff0c;预测是否terminate的三个输出&#xff1b;第二部…

echarts legend 背景色渐变

问题与本文无关&#xff1a;如果检测软件显示loadsh.js 的版本是4.17.10 装element-ui 2.15.8版本以下&#xff0c;2.15.6经过测试可以 代码&#xff1a; <template><div class"levelMain"><div class"survey-head"><div class"…

信号与系统实验MATLAB-实验1-信号的MATLAB表示及信号运算

实验1-信号的MATLAB表示及信号运算 一、实验目的 1、掌握MATLAB的使用&#xff1b; 2、掌握MATLAB生成信号波形&#xff1b; 3、掌握MATLAB分析常用连续信号&#xff1b; 4、掌握信号运算的MATLAB实现。 二、实验内容 编写程序实现下列常用函数&#xff0c;并显示波形。…

OpenMMlab AI实战营第七期培训

OpenMMlab AI实战营第七期培训 OpenMMlab实战营第七次课2023.2.10学习参考一、全流程的语义分割实战1.回顾**语义分割**、**实例分割**、**全景分割**2.代码模板的全流程3.数据集推荐&#xff1a;4.代码全流程 OpenMMlab实战营 第七次课2023.2.10 此次实战营的积分规则介绍&a…

LabView_波形控件

波形图表 将一定数量的数据点存储在缓冲区&#xff0c;并通过这种方式存储并显示这些数据点。当缓冲区被填满后&#xff0c;波形图表将会用新的数据点覆盖缓冲区中存在时间最久的数据点。 当数据点可用时&#xff0c;波形图表将显示已有的数据点外加最新接收到的数据点 。 您可…

Vatee万腾平台:创新科技,助力企业腾飞

在全球化竞争日益激烈的今天&#xff0c;企业如何借助科技力量实现转型升级&#xff0c;已成为摆在众多企业家面前的重大课题。Vatee万腾平台凭借其卓越的创新科技和专业的服务能力&#xff0c;成为众多企业实现腾飞的得力助手。 一、创新科技&#xff0c;引领企业前行 Vatee万…

解读自然语言处理:技术、应用与未来展望

引言 自然语言处理&#xff08;Natural Language Processing&#xff0c;简称NLP&#xff09;是计算机科学、人工智能和语言学的一个跨学科领域&#xff0c;致力于实现人与计算机之间通过自然语言进行有效沟通的能力。NLP 的核心任务是理解、解释和生成人类语言&#xff0c;使计…

【GlobalMapper精品教程】086:批量修改符号的样式

跟ArcGIS一样,Globalmapper也可以批量修改符号的样式,如样式、填充颜色、轮廓等等。 文章目录 一、加载实验数据二、土地利用符号化三、批量修改符号样式四、注意事项一、加载实验数据 订阅专栏后,从私信查收专栏配套的完整实验数据包,打开data086.rar中的土地利用数据,如…