simpleua.c在进行媒体相关初始化时,首先创建媒体端点,看看媒体端点的数据结构和创建流程。
#if PJ_HAS_THREADS
status = pjmedia_endpt_create(&cp.factory, NULL, 1, &g_med_endpt);
#else
status = pjmedia_endpt_create(&cp.factory,
pjsip_endpt_get_ioqueue(g_endpt),
0, &g_med_endpt);
#endif
pjmedia_endpt结构体
/** Concrete declaration of media endpoint. */
struct pjmedia_endpt
{
/** Pool. */
pj_pool_t *pool;
/** Pool factory. */
pj_pool_factory *pf;
/** Codec manager. */
pjmedia_codec_mgr codec_mgr;
/** IOqueue instance. */
pj_ioqueue_t *ioqueue;
/** Do we own the ioqueue? */
pj_bool_t own_ioqueue;
/** Number of threads. */
unsigned thread_cnt;
/** IOqueue polling thread, if any. */
pj_thread_t *thread[MAX_THREADS];
/** To signal polling thread to quit. */
pj_bool_t quit_flag;
/** Is telephone-event enable */
pj_bool_t has_telephone_event;
/** List of exit callback. */
exit_cb exit_cb_list;
};
ioqueue:用于绑定socket,然后异步接收数据;
thread[]:线程数组,存储工作线程。
codec_mgr:codec的管理者
exit_cb_list:退出时的回调链表
quit_flag:置位则工作线程都退出
创建端点
/**
* Initialize and get the instance of media endpoint.
*/
PJ_DEF(pj_status_t) pjmedia_endpt_create2(pj_pool_factory *pf,
pj_ioqueue_t *ioqueue,
unsigned worker_cnt,
pjmedia_endpt **p_endpt)
{
pj_pool_t *pool;
pjmedia_endpt *endpt;
unsigned i;
pj_status_t status;
pool = pj_pool_create(pf, "med-ept", 512, 512, NULL);
if (!pool)
return PJ_ENOMEM;
endpt = PJ_POOL_ZALLOC_T(pool, struct pjmedia_endpt);
endpt->pool = pool;
endpt->pf = pf;
endpt->ioqueue = ioqueue;
endpt->thread_cnt = worker_cnt;
endpt->has_telephone_event = PJ_TRUE;
/* Init codec manager. */
status = pjmedia_codec_mgr_init(&endpt->codec_mgr, endpt->pf);
if (status != PJ_SUCCESS)
goto on_error;
/* Initialize exit callback list. */
pj_list_init(&endpt->exit_cb_list);
/* Create ioqueue if none is specified. */
if (endpt->ioqueue == NULL) {
endpt->own_ioqueue = PJ_TRUE;
status = pj_ioqueue_create( endpt->pool, PJ_IOQUEUE_MAX_HANDLES,
&endpt->ioqueue);
if (status != PJ_SUCCESS)
goto on_error;
}
/* Create worker threads if asked. */
for (i=0; ipool, "media", &worker_proc,
endpt, 0, 0, &endpt->thread[i]);
if (status != PJ_SUCCESS)
goto on_error;
}
*p_endpt = endpt;
return PJ_SUCCESS;
on_error:
/* Destroy threads */
for (i=0; ithread_cnt; ++i) {
if (endpt->thread[i]) {
pj_thread_destroy(endpt->thread[i]);
}
}
/* Destroy internal ioqueue */
if (endpt->ioqueue && endpt->own_ioqueue)
pj_ioqueue_destroy(endpt->ioqueue);
pjmedia_codec_mgr_destroy(&endpt->codec_mgr);
//pjmedia_aud_subsys_shutdown();
pj_pool_release(pool);
return status;
}
1、创建内存池med-ept
2、申请媒体端点结构体内存,并把外部的ioqueue地址存到结构体 endpt->ioqueue = ioqueue;
3、初始化编码器管理者pjmedia_codec_mgr_init(&endpt->codec_mgr, endpt->pf)
4、如果初入的ioqueue为空,则创建一个新的ioqueue
5、创建工作线程组,线程函数是worker_proc
工作线程
/**
* Worker thread proc.
*/
static int PJ_THREAD_FUNC worker_proc(void *arg)
{
pjmedia_endpt *endpt = (pjmedia_endpt*) arg;
while (!endpt->quit_flag) {
pj_time_val timeout = { 0, 500 };
pj_ioqueue_poll(endpt->ioqueue, &timeout);
}
return 0;
}
工作线程就是每500ms调用一次pj_ioqueue_pool。刚创建媒体端点时,ioqueue还没有注册socket,所以不会监控到数据。