安徽省建设行业个人信息抚顺seo
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()