当前位置: 首页 > 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…...

Admin.Net中的消息通信SignalR解释

定义集线器接口 IOnlineUserHub public interface IOnlineUserHub {/// 在线用户列表Task OnlineUserList(OnlineUserList context);/// 强制下线Task ForceOffline(object context);/// 发布站内消息Task PublicNotice(SysNotice context);/// 接收消息Task ReceiveMessage(…...

通过Wrangler CLI在worker中创建数据库和表

官方使用文档&#xff1a;Getting started Cloudflare D1 docs 创建数据库 在命令行中执行完成之后&#xff0c;会在本地和远程创建数据库&#xff1a; npx wranglerlatest d1 create prod-d1-tutorial 在cf中就可以看到数据库&#xff1a; 现在&#xff0c;您的Cloudfla…...

linux 错误码总结

1,错误码的概念与作用 在Linux系统中,错误码是系统调用或库函数在执行失败时返回的特定数值,用于指示具体的错误类型。这些错误码通过全局变量errno来存储和传递,errno由操作系统维护,保存最近一次发生的错误信息。值得注意的是,errno的值在每次系统调用或函数调用失败时…...

TRS收益互换:跨境资本流动的金融创新工具与系统化解决方案

一、TRS收益互换的本质与业务逻辑 &#xff08;一&#xff09;概念解析 TRS&#xff08;Total Return Swap&#xff09;收益互换是一种金融衍生工具&#xff0c;指交易双方约定在未来一定期限内&#xff0c;基于特定资产或指数的表现进行现金流交换的协议。其核心特征包括&am…...

JUC笔记(上)-复习 涉及死锁 volatile synchronized CAS 原子操作

一、上下文切换 即使单核CPU也可以进行多线程执行代码&#xff0c;CPU会给每个线程分配CPU时间片来实现这个机制。时间片非常短&#xff0c;所以CPU会不断地切换线程执行&#xff0c;从而让我们感觉多个线程是同时执行的。时间片一般是十几毫秒(ms)。通过时间片分配算法执行。…...

tree 树组件大数据卡顿问题优化

问题背景 项目中有用到树组件用来做文件目录&#xff0c;但是由于这个树组件的节点越来越多&#xff0c;导致页面在滚动这个树组件的时候浏览器就很容易卡死。这种问题基本上都是因为dom节点太多&#xff0c;导致的浏览器卡顿&#xff0c;这里很明显就需要用到虚拟列表的技术&…...

iOS性能调优实战:借助克魔(KeyMob)与常用工具深度洞察App瓶颈

在日常iOS开发过程中&#xff0c;性能问题往往是最令人头疼的一类Bug。尤其是在App上线前的压测阶段或是处理用户反馈的高发期&#xff0c;开发者往往需要面对卡顿、崩溃、能耗异常、日志混乱等一系列问题。这些问题表面上看似偶发&#xff0c;但背后往往隐藏着系统资源调度不当…...

【MATLAB代码】基于最大相关熵准则(MCC)的三维鲁棒卡尔曼滤波算法(MCC-KF),附源代码|订阅专栏后可直接查看

文章所述的代码实现了基于最大相关熵准则(MCC)的三维鲁棒卡尔曼滤波算法(MCC-KF),针对传感器观测数据中存在的脉冲型异常噪声问题,通过非线性加权机制提升滤波器的抗干扰能力。代码通过对比传统KF与MCC-KF在含异常值场景下的表现,验证了后者在状态估计鲁棒性方面的显著优…...

C语言中提供的第三方库之哈希表实现

一. 简介 前面一篇文章简单学习了C语言中第三方库&#xff08;uthash库&#xff09;提供对哈希表的操作&#xff0c;文章如下&#xff1a; C语言中提供的第三方库uthash常用接口-CSDN博客 本文简单学习一下第三方库 uthash库对哈希表的操作。 二. uthash库哈希表操作示例 u…...

WebRTC从入门到实践 - 零基础教程

WebRTC从入门到实践 - 零基础教程 目录 WebRTC简介 基础概念 工作原理 开发环境搭建 基础实践 三个实战案例 常见问题解答 1. WebRTC简介 1.1 什么是WebRTC&#xff1f; WebRTC&#xff08;Web Real-Time Communication&#xff09;是一个支持网页浏览器进行实时语音…...