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. 参赛选手可以自行编写相关代码或以该代码为基础,根据所选单片机类型、运行速度和试题中对单片机时钟频率的要求,进行代码调试和修改。 */ #include <STC1…...
IDC报告背后:大模型时代,重新理解AI公有云
大模型之于AI公有云的意义,在于大模型可以改变过去“手工作坊定制算法”的高成本模式,转向“工厂模式”,只需要微调和精调,就可以形成针对性的场景算法。 作者|葛覃 出品|产业家 一年前,依然有不少云计算从业者思…...
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项目的时候一般要写登录操作,而为了安全起见,现在的登录功能都会加上输入图片验证码这一功能ÿ…...
一些有趣的 js 功能函数
一些有趣的 js 功能函数 数组生成数组打乱数组数组简单数据去重数组唯一值数据去重多数组取交集查找最大值索引查找最小值索引找到最接近的数值压缩多个数组(拉链函数)矩阵交换行和列 数字转换进制转换 正则手机号格式化去除多余空格 web重新加载当前页面…...
摄像头m2dock(MAIX-II DOCK)
官方文档地址 https://wiki.sipeed.com/soft/maixpy3/zh/index.html 一、软件准备 1 烧录镜像软件 2 镜像 当前最近版本镜像文件 3 SDFormatter 4 Maixpy IDE 二、SD卡准备 1 格式化SD卡(用SDFormatter) 2 烧录 3 弹出,插入开发板中 出现…...
SpringBoot 如何优雅的进行全局异常处理
在SpringBoot的开发中,为了提高程序运行的鲁棒性,我们经常需要对各种程序异常进行处理,但是如果在每个出异常的地方进行单独处理的话,这会引入大量业务不相关的异常处理代码,增加了程序的耦合,同时未来想改…...
OSPF路由协议(红茶三杯CCNA)
链路状态路由协议 OSPF(开放式最短路径优先)Open Shortest Path First 是一种链路状态路由协议,无路由循环(全局拓扑),RFC2328 “开放”意味着非私有的 管理型距离:110 OSPF采用SPF算法计算到达…...
redis中使用bloomfilter判断元素是否存在
一 bloomfiler的作用 1.1 bloomfilter的作用 由一个初始值为0的bit数组组成,和多个hash函数构成,用来判断集合中是否存在某个元素。 一个很长的二进制数组(00000000)一系列随机hash算法映射函数。主要用于判断一个元素是否存在…...
互联网医院系统源码实现:打造现代化医疗服务平台
摘要 本文将介绍一个基于Python的简化版互联网医院系统的源码实现,主要包含用户注册与登录、医生信息管理、在线预约挂号、在线问诊与咨询、电子病历管理、在线支付与结算等功能。该源码实现仅为示例,实际开发中需要考虑更多的业务逻辑和安全性。 1. …...
每天100w次登陆请求, 8G 内存该如何设置JVM参数?
一、新系统上线如何规划容量? 1.套路总结 任何新的业务系统在上线以前都需要去估算服务器配置和JVM的内存参数,这个容量与资源规划并不仅仅是系统架构师的随意估算的,需要根据系统所在业务场景去估算,推断出来一个系统运行模型&…...
Fiddler Everywhere(TTP调试抓包工具) for Mac苹果电脑版
Fiddler Everywhere for Mac版是Mac电脑上的一款跨平台的HTTP调试抓包工具,Fiddler Everywhere for Mac能够记录客户端与服务器之间的所有HTTP(S)通信,支持对包进行监视、分析、设置断点、甚至修改请求/响应数据等操作。 适用于任…...
Paragon NTFS2023最新版Mac读写NTFS磁盘工具
Paragon NTFS for Mac是Mac平台上一款非常优秀的读写工具,可以在Mac OS X中完全读写、修改、访问NTFS硬盘、U盘等外接设备的文件。这款软件最大的亮点简书可以让我们读写 NTFS 分区,因为在Mac OS X 系统上,默认状态下我们只能读取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…...
线程与协程
1. 线程与协程 1.1. “函数调用级别”的切换、上下文切换 1. 函数调用级别的切换 “函数调用级别的切换”是指:像函数调用/返回一样轻量地完成任务切换。 举例说明: 当你在程序中写一个函数调用: funcA() 然后 funcA 执行完后返回&…...
STM32F4基本定时器使用和原理详解
STM32F4基本定时器使用和原理详解 前言如何确定定时器挂载在哪条时钟线上配置及使用方法参数配置PrescalerCounter ModeCounter Periodauto-reload preloadTrigger Event Selection 中断配置生成的代码及使用方法初始化代码基本定时器触发DCA或者ADC的代码讲解中断代码定时启动…...
SAP学习笔记 - 开发26 - 前端Fiori开发 OData V2 和 V4 的差异 (Deepseek整理)
上一章用到了V2 的概念,其实 Fiori当中还有 V4,咱们这一章来总结一下 V2 和 V4。 SAP学习笔记 - 开发25 - 前端Fiori开发 Remote OData Service(使用远端Odata服务),代理中间件(ui5-middleware-simpleproxy)-CSDN博客…...
在Ubuntu24上采用Wine打开SourceInsight
1. 安装wine sudo apt install wine 2. 安装32位库支持,SourceInsight是32位程序 sudo dpkg --add-architecture i386 sudo apt update sudo apt install wine32:i386 3. 验证安装 wine --version 4. 安装必要的字体和库(解决显示问题) sudo apt install fonts-wqy…...
基于Java+MySQL实现(GUI)客户管理系统
客户资料管理系统的设计与实现 第一章 需求分析 1.1 需求总体介绍 本项目为了方便维护客户信息为了方便维护客户信息,对客户进行统一管理,可以把所有客户信息录入系统,进行维护和统计功能。可通过文件的方式保存相关录入数据,对…...
C语言中提供的第三方库之哈希表实现
一. 简介 前面一篇文章简单学习了C语言中第三方库(uthash库)提供对哈希表的操作,文章如下: C语言中提供的第三方库uthash常用接口-CSDN博客 本文简单学习一下第三方库 uthash库对哈希表的操作。 二. uthash库哈希表操作示例 u…...
Python 训练营打卡 Day 47
注意力热力图可视化 在day 46代码的基础上,对比不同卷积层热力图可视化的结果 import torch import torch.nn as nn import torch.optim as optim from torchvision import datasets, transforms from torch.utils.data import DataLoader import matplotlib.pypl…...
[论文阅读]TrustRAG: Enhancing Robustness and Trustworthiness in RAG
TrustRAG: Enhancing Robustness and Trustworthiness in RAG [2501.00879] TrustRAG: Enhancing Robustness and Trustworthiness in Retrieval-Augmented Generation 代码:HuichiZhou/TrustRAG: Code for "TrustRAG: Enhancing Robustness and Trustworthin…...
用 Rust 重写 Linux 内核模块实战:迈向安全内核的新篇章
用 Rust 重写 Linux 内核模块实战:迈向安全内核的新篇章 摘要: 操作系统内核的安全性、稳定性至关重要。传统 Linux 内核模块开发长期依赖于 C 语言,受限于 C 语言本身的内存安全和并发安全问题,开发复杂模块极易引入难以…...
从实验室到产业:IndexTTS 在六大核心场景的落地实践
一、内容创作:重构数字内容生产范式 在短视频创作领域,IndexTTS 的语音克隆技术彻底改变了配音流程。B 站 UP 主通过 5 秒参考音频即可克隆出郭老师音色,生成的 “各位吴彦祖们大家好” 语音相似度达 97%,单条视频播放量突破百万…...
