当前位置: 首页 > news >正文

unimrcp server的session资源分配与回收

        unimrcp使用APR的内存池管理内存,因此,处理函数中一般都会传递一个pool指针,需要内存时,就从pool里分配一块,一般也不需要关心内存的释放。因为,一路呼叫关联一个session,一个session对应一个pool。那么,这个poll是怎么生成的,又是怎样回收的呢?

首先,看一下mrcp_session_t结构的定义(libs\mrcp-signaling\include\mrcp_session.h):

struct mrcp_session_t {/** Memory pool to allocate memory from */apr_pool_t       *pool;/** Whether the memory pool is self-owned or not */apt_bool_t        self_owned;/** External object associated with session */void             *obj;/** External logger object associated with session */void             *log_obj;/** Informative name of the session used for debugging */const char       *name;/** Signaling (session managment) agent */mrcp_sig_agent_t          *signaling_agent;/** MRCPv2 connection agent, if any */void                      *connection_agent;/** Media processing engine */mpf_engine_t              *media_engine;/** RTP termination factory */mpf_termination_factory_t *rtp_factory;/** Session identifier */apt_str_t         id;/** Last request identifier sent for client, received for server */mrcp_request_id   last_request_id;/** Virtual request methods */const mrcp_session_request_vtable_t  *request_vtable;/** Virtual response methods */const mrcp_session_response_vtable_t *response_vtable;/** Virtual event methods */const mrcp_session_event_vtable_t    *event_vtable;/** Custom headers */apr_table_t                          *custom_headers;/** Trace ID*/apt_str_t   trace_id;
};

在unimrcpserver启动时,会加载一个sofiasip_task线程,它的任务是接收处理SIP消息,线程函数调用mrcp_sofia_task_run():

static apt_bool_t mrcp_sofia_task_run(apt_task_t *base)
{mrcp_sofia_task_t *task = apt_task_object_get(base);if(!task->root || !task->nua) {apt_log(SIP_LOG_MARK,APT_PRIO_WARNING,"Failed to Run Sofia-SIP Task");return FALSE;}/* Run event loop */su_root_run(task->root);apt_task_terminate_request_process(base);return TRUE;
}

很简单,就是su_base_port_run()函数(su_base_port.c)。

void su_base_port_run(su_port_t *self)
{su_duration_t tout = 0, tout2 = 0;assert(su_port_own_thread(self));for (self->sup_running = 1; self->sup_running;) {tout = self->sup_max_defer;if (self->sup_prepoll)self->sup_prepoll(self->sup_pp_magic, self->sup_pp_root);if (self->sup_head)self->sup_vtable->su_port_getmsgs(self);                                                                                                                                                                                                                             if (self->sup_timers || self->sup_deferrable) {su_time_t now = su_now();su_timer_expire(&self->sup_timers, &tout, now);su_timer_expire(&self->sup_deferrable, &tout2, now);}if (!self->sup_running)break;if (self->sup_head)      /* if there are messages do a quick wait */tout = 0;su_base_port_wait_events(self, tout);}
}

当SIP消息到来时,执行,self->sup_vtable->su_port_getmsgs(self); 其实调用的是su_base_port_execute_msgs()函数(su_base_port.c)

static int su_base_port_execute_msgs(su_msg_t *queue)
{su_msg_t *msg;int n = 0;for (msg = queue; msg; msg = queue) {su_msg_f f = msg->sum_func;queue = msg->sum_next, msg->sum_next = NULL;if (f) {su_root_t *root = msg->sum_to->sut_root;if (msg->sum_to->sut_port == NULL)msg->sum_to->sut_root = NULL;f(SU_ROOT_MAGIC(root), &msg, msg->sum_data);                                                                                                                                                                                                                         }   su_msg_delivery_report(&msg);n++;}return n;
}

f(SU_ROOT_MAGIC(root), &msg, msg->sum_data);这里f指向nua_application_event()函数,它的实现在nua_stack.c:

关键调用在下面这一行:

   nua->nua_callback((enum nua_event_e)e->e_event, e->e_status, e->e_phrase,nua, nua->nua_magic,nh, nh ? nh->nh_magic : NULL,e->e_msg ? sip_object(e->e_msg) : NULL,e->e_tags);

这个nua_callback批向mrcp_sofia_event_callback()函数,它在mrcp_sofiasip_server_agent.c里实现。它分发处理SIP消息。如果是INVITE消息,就是这个分支:

case nua_i_invite:mrcp_sofia_on_invite(sofia_agent,nh,sofia_session,sip,tags);break;

跳转进去,它调用mrcp_sofia_session_create()函数分配session对象:

sofia_session = mrcp_sofia_session_create(sofia_agent,nh);if(!sofia_session) {nua_respond(nh, SIP_488_NOT_ACCEPTABLE, TAG_END());return;}
static mrcp_sofia_session_t* mrcp_sofia_session_create(mrcp_sofia_agent_t *sofia_agent, nua_handle_t *nh)
{mrcp_sofia_session_t *sofia_session;mrcp_session_t* session = sofia_agent->sig_agent->create_server_session(sofia_agent->sig_agent);if(!session) {return NULL;}session->response_vtable = &session_response_vtable;session->event_vtable = &session_event_vtable;sofia_session = apr_palloc(session->pool,sizeof(mrcp_sofia_session_t));sofia_session->home = su_home_new(sizeof(*sofia_session->home));sofia_session->session = session;session->obj = sofia_session;nua_handle_bind(nh, sofia_session);sofia_session->nh = nh;mrcp_session_attribs_init(&sofia_session->attribs);sofia_session->trace_id = NULL;return sofia_session;
}

这一行mrcp_session_t* session = sofia_agent->sig_agent->create_server_session(sofia_agent->sig_agent);又跳转到 mrcp_server_sig_agent_session_create()函数,它在mrcp_server.c里实现。

static mrcp_session_t* mrcp_server_sig_agent_session_create(mrcp_sig_agent_t *signaling_agent)
{mrcp_server_t *server = signaling_agent->parent;mrcp_server_session_t *session = mrcp_server_session_create();session->server = server;session->profile = mrcp_server_profile_get_by_agent(server,session,signaling_agent);if(!session->profile) {apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Cannot Find Profile by Agent " APT_NAMESID_FMT,session->base.name,MRCP_SESSION_SID(&session->base));mrcp_session_destroy(&session->base);return NULL;}apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Create Session " APT_NAMESID_FMT" [%s]",session->base.name,MRCP_SESSION_SID(&session->base), session->profile->id);session->base.signaling_agent = signaling_agent;session->base.request_vtable = &session_request_vtable;return &session->base;
}

这里调用mrcp_server_session_create()分配对象,跳转到mrcp_server_session.c。

mrcp_server_session_t* mrcp_server_session_create()
{mrcp_server_session_t *session = (mrcp_server_session_t*) mrcp_session_create(sizeof(mrcp_server_session_t)-sizeof(mrcp_session_t));session->context = NULL;session->terminations = apr_array_make(session->base.pool,2,sizeof(mrcp_termination_slot_t));session->channels = apr_array_make(session->base.pool,2,sizeof(mrcp_channel_t*));session->active_request = NULL;session->request_queue = apt_list_create(session->base.pool);session->offer = NULL;session->answer = NULL;session->last_offer = NULL;session->last_answer = NULL;session->mpf_task_msg = NULL;session->subrequest_count = 0;session->state = SESSION_STATE_NONE;session->base.name = apr_psprintf(session->base.pool,"0x%pp",session);return session;
}

调用mrcp_session_create()函数,可以在mrcp_sig_agent.c里找到。

MRCP_DECLARE(mrcp_session_t*) mrcp_session_create(apr_size_t padding)
{apr_pool_t *pool = apt_pool_create();if(!pool) {return NULL;}return mrcp_session_create_ex(pool,TRUE,padding);
}

这里的apr_pool_create()就是根源了。

那么, 这个pool是在哪释放的呢?

实现plugin时,要实现mrcp_engine_channel_method_vtable_t这个接口,里面有一个close函数,但是,这个函数并不会直正释放资源,只是告知channel即将被关闭。如果处理结束,需要向server 对象发一条信号。

以demo_recog_engine为例:

/** Close engine channel (asynchronous response MUST be sent)*/
static apt_bool_t demo_recog_channel_close(mrcp_engine_channel_t *channel)                                                                                                                                                                                                 
{return demo_recog_msg_signal(DEMO_RECOG_MSG_CLOSE_CHANNEL,channel,NULL);
}

这个信号是可以异步给的。引擎核心只有收到这个信号才会回SIP BYE消息,并真正释放资源。

mrcp_server.c的mrcp_server_msg_process()函数是处理这个信号的地方。跟踪一下,一路的调用链条是:

mrcp_server_on_engine_channel_close()==>mrcp_server_session_subrequest_remove()==>mrcp_server_session_terminate_send()==>mrcp_session_terminate_response()==>mrcp_sofia_on_session_terminate()==>apr_pool_destroy()

相关文章:

unimrcp server的session资源分配与回收

unimrcp使用APR的内存池管理内存,因此,处理函数中一般都会传递一个pool指针,需要内存时,就从pool里分配一块,一般也不需要关心内存的释放。因为,一路呼叫关联一个session,一个session对应一个po…...

【图论】三种中心性 —— 特征向量、katz 和 PageRank

维基百科:在图论和网络分析中,中心性指标为图中相应网络位置的节点分配排名或数值。中心性这一概念最初起源于社交网络分析,因此很多衡量中心性的术语也反映了其社会学背景。 不同中心性指标对 “重要” 的衡量方式不同,因此适用于…...

[sqoop]将hive查询后的数据导入到MySQL

一、知识点 export:将Hive的表导入到mysql叫导出 搜了很多,发现sqoop在hive导出到mysql时 1)不支持where参数对数据进行过滤。 2)不支持指定hive表的方式导出,只能指定Hive目录进行导出。 二、操作 1、在MySQL中建表 creat…...

Linux df、du命令

df:查看文件系统硬盘使用情况 df 命令,用于显示 Linux 系统中各文件系统的硬盘使用情况,包括文件系统所在硬盘分区的总容量、已使用的容量、剩余容量等。 df 命令的基本格式为: [rootlocalhost ~]# df [选项] [目录或文件名] df…...

java版+免费商城搭建+小程序商城免费搭建+Spring Cloud + Spring Boot + MybatisPlus + 前后端分离 + 二次开发

J2EE企业分布式微服务云快速开发架构 Spring CloudSpring Boot2MybatisOauth2ElementUI 前后端分离 1. 鸿鹄Cloud架构清单 2. Commonservice(通用服务) 通用服务:对spring Cloud组件的使用&封装,是一套完整的针对于分布式微…...

软件设计师学习第一章

计算机组成与体系结构(6分) 内容概述 数据的表示 进制转换 R 进制转十进制使用按权展开法,其具体操作方式为:将 R 进制数的每一位数值用 Rk 形示,即幂的底数是 R ,指数为 k , k 与该位和小数点…...

蓝桥杯单片机第十一届国赛 真题+代码

iic.c /* # I2C代码片段说明1. 本文件夹中提供的驱动代码供参赛选手完成程序设计参考。2. 参赛选手可以自行编写相关代码或以该代码为基础&#xff0c;根据所选单片机类型、运行速度和试题中对单片机时钟频率的要求&#xff0c;进行代码调试和修改。 */ #include <STC1…...

IDC报告背后:大模型时代,重新理解AI公有云

大模型之于AI公有云的意义&#xff0c;在于大模型可以改变过去“手工作坊定制算法”的高成本模式&#xff0c;转向“工厂模式”&#xff0c;只需要微调和精调&#xff0c;就可以形成针对性的场景算法。 作者|葛覃 出品|产业家 一年前&#xff0c;依然有不少云计算从业者思…...

UNH-IOL Reservation 一致性测试用例【7】- 清除Reservation

Reservation 系列导航 UNH-IOL Reservation 一致性测试用例【1】- Reservation Report 命令验证 UNH-IOL Reservation 一致性测试用例【2】- Reservation注册 UNH-IOL Reservation 一致性测试用例【3】- 取消注册 UNH-IOL Reservation 一致性测试用例【4】- Reservation Acqui…...

Python 生成随机图片验证码

使用Python生成图片验证码 Python 生成随机图片验证码安装pillow包pillow包生成图片基本用法生成图片验证码 Python 生成随机图片验证码 在写一个Web项目的时候一般要写登录操作&#xff0c;而为了安全起见&#xff0c;现在的登录功能都会加上输入图片验证码这一功能&#xff…...

一些有趣的 js 功能函数

一些有趣的 js 功能函数 数组生成数组打乱数组数组简单数据去重数组唯一值数据去重多数组取交集查找最大值索引查找最小值索引找到最接近的数值压缩多个数组&#xff08;拉链函数&#xff09;矩阵交换行和列 数字转换进制转换 正则手机号格式化去除多余空格 web重新加载当前页面…...

摄像头m2dock(MAIX-II DOCK)

官方文档地址 https://wiki.sipeed.com/soft/maixpy3/zh/index.html 一、软件准备 1 烧录镜像软件 2 镜像 当前最近版本镜像文件 3 SDFormatter 4 Maixpy IDE 二、SD卡准备 1 格式化SD卡&#xff08;用SDFormatter&#xff09; 2 烧录 3 弹出&#xff0c;插入开发板中 出现…...

SpringBoot 如何优雅的进行全局异常处理

在SpringBoot的开发中&#xff0c;为了提高程序运行的鲁棒性&#xff0c;我们经常需要对各种程序异常进行处理&#xff0c;但是如果在每个出异常的地方进行单独处理的话&#xff0c;这会引入大量业务不相关的异常处理代码&#xff0c;增加了程序的耦合&#xff0c;同时未来想改…...

OSPF路由协议(红茶三杯CCNA)

链路状态路由协议 OSPF&#xff08;开放式最短路径优先&#xff09;Open Shortest Path First 是一种链路状态路由协议&#xff0c;无路由循环&#xff08;全局拓扑&#xff09;&#xff0c;RFC2328 “开放”意味着非私有的 管理型距离&#xff1a;110 OSPF采用SPF算法计算到达…...

redis中使用bloomfilter判断元素是否存在

一 bloomfiler的作用 1.1 bloomfilter的作用 由一个初始值为0的bit数组组成&#xff0c;和多个hash函数构成&#xff0c;用来判断集合中是否存在某个元素。 一个很长的二进制数组&#xff08;00000000&#xff09;一系列随机hash算法映射函数。主要用于判断一个元素是否存在…...

互联网医院系统源码实现:打造现代化医疗服务平台

摘要 本文将介绍一个基于Python的简化版互联网医院系统的源码实现&#xff0c;主要包含用户注册与登录、医生信息管理、在线预约挂号、在线问诊与咨询、电子病历管理、在线支付与结算等功能。该源码实现仅为示例&#xff0c;实际开发中需要考虑更多的业务逻辑和安全性。 1. …...

每天100w次登陆请求, 8G 内存该如何设置JVM参数?

一、新系统上线如何规划容量&#xff1f; 1.套路总结 任何新的业务系统在上线以前都需要去估算服务器配置和JVM的内存参数&#xff0c;这个容量与资源规划并不仅仅是系统架构师的随意估算的&#xff0c;需要根据系统所在业务场景去估算&#xff0c;推断出来一个系统运行模型&…...

Fiddler Everywhere(TTP调试抓包工具) for Mac苹果电脑版

Fiddler Everywhere for Mac版是Mac电脑上的一款跨平台的HTTP调试抓包工具&#xff0c;Fiddler Everywhere for Mac能够记录客户端与服务器之间的所有HTTP&#xff08;S&#xff09;通信&#xff0c;支持对包进行监视、分析、设置断点、甚至修改请求/响应数据等操作。 适用于任…...

Paragon NTFS2023最新版Mac读写NTFS磁盘工具

Paragon NTFS for Mac是Mac平台上一款非常优秀的读写工具&#xff0c;可以在Mac OS X中完全读写、修改、访问NTFS硬盘、U盘等外接设备的文件。这款软件最大的亮点简书可以让我们读写 NTFS 分区&#xff0c;因为在Mac OS X 系统上&#xff0c;默认状态下我们只能读取NTFS 分区&a…...

vs2013 32位 编译的 dll,重新用vs2022 64位编译,所遇问题记录

目录 一、vs2013 32 DLL 转 VS2022 64 DLL 所遇问题 1、 LNK2038: 检测到“_MSC_VER”的不匹配项: 值“1800”不匹配值“1900” 2、原先VS2013 现在 VS2022 导致的vsnprintf 重定义问题 3、 无法解析的外部符号 __vsnwprintf_s 4、无法解析的外部符号__imp__CertFreeC…...

Hive 存储格式深度解析:从 TextFile 到 ORC,如何选对数据存储方案?

在大数据处理领域&#xff0c;Hive 作为 Hadoop 生态中重要的数据仓库工具&#xff0c;其存储格式的选择直接影响数据存储成本、查询效率和计算资源消耗。面对 TextFile、SequenceFile、Parquet、RCFile、ORC 等多种存储格式&#xff0c;很多开发者常常陷入选择困境。本文将从底…...

面向无人机海岸带生态系统监测的语义分割基准数据集

描述&#xff1a;海岸带生态系统的监测是维护生态平衡和可持续发展的重要任务。语义分割技术在遥感影像中的应用为海岸带生态系统的精准监测提供了有效手段。然而&#xff0c;目前该领域仍面临一个挑战&#xff0c;即缺乏公开的专门面向海岸带生态系统的语义分割基准数据集。受…...

使用Spring AI和MCP协议构建图片搜索服务

目录 使用Spring AI和MCP协议构建图片搜索服务 引言 技术栈概览 项目架构设计 架构图 服务端开发 1. 创建Spring Boot项目 2. 实现图片搜索工具 3. 配置传输模式 Stdio模式&#xff08;本地调用&#xff09; SSE模式&#xff08;远程调用&#xff09; 4. 注册工具提…...

LCTF液晶可调谐滤波器在多光谱相机捕捉无人机目标检测中的作用

中达瑞和自2005年成立以来&#xff0c;一直在光谱成像领域深度钻研和发展&#xff0c;始终致力于研发高性能、高可靠性的光谱成像相机&#xff0c;为科研院校提供更优的产品和服务。在《低空背景下无人机目标的光谱特征研究及目标检测应用》这篇论文中提到中达瑞和 LCTF 作为多…...

HybridVLA——让单一LLM同时具备扩散和自回归动作预测能力:训练时既扩散也回归,但推理时则扩散

前言 如上一篇文章《dexcap升级版之DexWild》中的前言部分所说&#xff0c;在叠衣服的过程中&#xff0c;我会带着团队对比各种模型、方法、策略&#xff0c;毕竟针对各个场景始终寻找更优的解决方案&#xff0c;是我个人和我司「七月在线」的职责之一 且个人认为&#xff0c…...

WebRTC调研

WebRTC是什么&#xff0c;为什么&#xff0c;如何使用 WebRTC有什么优势 WebRTC Architecture Amazon KVS WebRTC 其它厂商WebRTC 海康门禁WebRTC 海康门禁其他界面整理 威视通WebRTC 局域网 Google浏览器 Microsoft Edge 公网 RTSP RTMP NVR ONVIF SIP SRT WebRTC协…...

【免费数据】2005-2019年我国272个地级市的旅游竞争力多指标数据(33个指标)

旅游业是一个城市的重要产业构成。旅游竞争力是一个城市竞争力的重要构成部分。一个城市的旅游竞争力反映了其在旅游市场竞争中的比较优势。 今日我们分享的是2005-2019年我国272个地级市的旅游竞争力多指标数据&#xff01;该数据集源自2025年4月发表于《地理学报》的论文成果…...

何谓AI编程【02】AI编程官网以优雅草星云智控为例建设实践-完善顶部-建立各项子页-调整排版-优雅草卓伊凡

何谓AI编程【02】AI编程官网以优雅草星云智控为例建设实践-完善顶部-建立各项子页-调整排版-优雅草卓伊凡 背景 我们以建设星云智控官网来做AI编程实践&#xff0c;很多人以为AI已经强大到不需要程序员了&#xff0c;其实不是&#xff0c;AI更加需要程序员&#xff0c;普通人…...

Linux-进程间的通信

1、IPC&#xff1a; Inter Process Communication&#xff08;进程间通信&#xff09;&#xff1a; 由于每个进程在操作系统中有独立的地址空间&#xff0c;它们不能像线程那样直接访问彼此的内存&#xff0c;所以必须通过某种方式进行通信。 常见的 IPC 方式包括&#…...

如何把工业通信协议转换成http websocket

1.现状 工业通信协议多数工作在边缘设备上&#xff0c;比如&#xff1a;PLC、IOT盒子等。上层业务系统需要根据不同的工业协议做对应开发&#xff0c;当设备上用的是modbus从站时&#xff0c;采集设备数据需要开发modbus主站&#xff1b;当设备上用的是西门子PN协议时&#xf…...