PJSIP接口说明

PJsip接口说明

//媒体状态改变的回调函数
/* Callback called by the library when call's media state has changed */
static void on_call_media_state(pjsua_call_id call_id)
{
    pjsua_call_info ci;
    pjsua_call_get_info(call_id, &ci);
//    当媒体为激活时,连接呼叫和声音设备
    if (ci.media_status == PJSUA_CALL_MEDIA_ACTIVE) {
// When media is active, connect call to sound device.
pjsua_conf_connect(ci.conf_slot, 0);
pjsua_conf_connect(0, ci.conf_slot);
    }
}
static pj_status_t apply_call_setting(pjsua_call *call,
      const pjsua_call_setting *opt,
      const pjmedia_sdp_session *rem_sdp)
{
    pj_assert(call);
    if (!opt)
return PJ_SUCCESS;
#if !PJMEDIA_HAS_VIDEO
    pj_assert(opt->vid_cnt == 0);
#endif
    call->opt = *opt;
//    如果呼叫已建立,则设置本端的对话角色
//    如果有远端SDP,则本端为UAS(User Agent Server),否则为UAC
    /* If call is established, reinit media channel */
    if (call->inv && call->inv->state == PJSIP_INV_STATE_CONFIRMED) {
pjsip_role_e role = rem_sdp? PJSIP_ROLE_UAS : PJSIP_ROLE_UAC;
pj_status_t status;
//        初始化媒体通道
status = pjsua_media_channel_init(call->index, role,
  call->secure_level,
  call->inv->pool_prov,
  rem_sdp, NULL,
  PJ_FALSE, NULL);
if (status != PJ_SUCCESS) {
    pjsua_perror(THIS_FILE, "Error re-initializing media channel",
 status);
    return status;
}
    }
    return PJ_SUCCESS;
}
/* Allocate one call id */
static pjsua_call_id alloc_call_id(void)
{
    pjsua_call_id cid;
#if 1
    /* New algorithm: round-robin */
    if (pjsua_var.next_call_id >= (int)pjsua_var.ua_cfg.max_calls || 
pjsua_var.next_call_id < 0)
    {
pjsua_var.next_call_id = 0;
    }
//    从next_call_id到max_calls之间找一个空闲的calls数组元素
    for (cid=pjsua_var.next_call_id;
 cid<(int)pjsua_var.ua_cfg.max_calls; 
 ++cid) 
    {
if (pjsua_var.calls[cid].inv == NULL &&
            pjsua_var.calls[cid].async_call.dlg == NULL)
        {
    ++pjsua_var.next_call_id;
    return cid;
}
    }
//    从0到next_call_id之间找一个空闲的calls数组元素
    for (cid=0; cid < pjsua_var.next_call_id; ++cid) {
if (pjsua_var.calls[cid].inv == NULL &&
            pjsua_var.calls[cid].async_call.dlg == NULL)
        {
    ++pjsua_var.next_call_id;
    return cid;
}
    }
#else
    /* Old algorithm */
    for (cid=0; cid<(int)pjsua_var.ua_cfg.max_calls; ++cid) {
if (pjsua_var.calls[cid].inv == NULL)
    return cid;
    }
#endif
    return PJSUA_INVALID_ID;
}
/*
 * Make outgoing call to the specified URI using the specified account.
 */
PJ_DEF(pj_status_t) pjsua_call_make_call(pjsua_acc_id acc_id,
 const pj_str_t *dest_uri,
 const pjsua_call_setting *opt,
 void *user_data,
 const pjsua_msg_data *msg_data,
 pjsua_call_id *p_call_id)
{
    pj_pool_t *tmp_pool = NULL;
    pjsip_dialog *dlg = NULL;
    pjsua_acc *acc;
    pjsua_call *call;
    int call_id = -1;
    pj_str_t contact;
    pj_status_t status;
    /* Check that account is valid */
    PJ_ASSERT_RETURN(acc_id>=0 || acc_id<(int)PJ_ARRAY_SIZE(pjsua_var.acc), 
     PJ_EINVAL);
    /* Check arguments */
    PJ_ASSERT_RETURN(dest_uri, PJ_EINVAL);
    PJ_LOG(4,(THIS_FILE, "Making call with acc #%d to %.*s", acc_id,
      (int)dest_uri->slen, dest_uri->ptr));
    pj_log_push_indent();
    PJSUA_LOCK();
//    创建声音设备
    /* Create sound port if none is instantiated, to check if sound device
     * can be used. But only do this with the conference bridge, as with 
     * audio switchboard (i.e. APS-Direct), we can only open the sound 
     * device once the correct format has been known
     */
    if (!pjsua_var.is_mswitch && pjsua_var.snd_port==NULL && 
pjsua_var.null_snd==NULL && !pjsua_var.no_snd) 
    {
status = pjsua_set_snd_dev(pjsua_var.cap_dev, pjsua_var.play_dev);
if (status != PJ_SUCCESS)
    goto on_error;
    }
//    检查SIP帐号
    acc = &pjsua_var.acc[acc_id];
    if (!acc->valid) {
pjsua_perror(THIS_FILE, "Unable to make call because account "
     "is not valid", PJ_EINVALIDOP);
status = PJ_EINVALIDOP;
goto on_error;
    }
//    创建呼叫标识
    /* Find free call slot. */
    call_id = alloc_call_id();
    if (call_id == PJSUA_INVALID_ID) {
pjsua_perror(THIS_FILE, "Error making call", PJ_ETOOMANY);
status = PJ_ETOOMANY;
goto on_error;
    }
//    复位呼叫参数
    /* Clear call descriptor */
    reset_call(call_id);
    call = &pjsua_var.calls[call_id];
    /* Associate session with account */
    call->acc_id = acc_id;
    call->call_hold_type = acc->cfg.call_hold_type;
//    设置呼叫参数
    /* Apply call setting */
    status = apply_call_setting(call, opt, NULL);
    if (status != PJ_SUCCESS) {
pjsua_perror(THIS_FILE, "Failed to apply call setting", status);
goto on_error;
    }
    /* Create temporary pool */
    tmp_pool = pjsua_pool_create("tmpcall10", 512, 256);
    /* Verify that destination URI is valid before calling 
     * pjsua_acc_create_uac_contact, or otherwise there  
     * a misleading "Invalid Contact URI" error will be printed
     * when pjsua_acc_create_uac_contact() fails.
     */
    if (1) {
pjsip_uri *uri;
pj_str_t dup;
//        分析被叫SIP号码
pj_strdup_with_null(tmp_pool, &dup, dest_uri);
uri = pjsip_parse_uri(tmp_pool, dup.ptr, dup.slen, 0);
if (uri == NULL) {
    pjsua_perror(THIS_FILE, "Unable to make call", 
 PJSIP_EINVALIDREQURI);
    status = PJSIP_EINVALIDREQURI;
    goto on_error;
}
    }
    /* Mark call start time. */
    pj_gettimeofday(&call->start_time);
    /* Reset first response time */
    call->res_time.sec = 0;
//    创建Contact头域
    /* Create suitable Contact header unless a Contact header has been
     * set in the account.
     */
    if (acc->contact.slen) {
contact = acc->contact;
    } else {
status = pjsua_acc_create_uac_contact(tmp_pool, &contact,
      acc_id, dest_uri);
if (status != PJ_SUCCESS) {
    pjsua_perror(THIS_FILE, "Unable to generate Contact header", 
 status);
    goto on_error;
}
    }
//    创建SIP对话(Dialog)
    /* Create outgoing dialog: */
    status = pjsip_dlg_create_uac( pjsip_ua_instance(), 
   &acc->cfg.id, &contact,
   dest_uri, dest_uri, &dlg);
    if (status != PJ_SUCCESS) {
pjsua_perror(THIS_FILE, "Dialog creation failed", status);
goto on_error;
    }
    /* Increment the dialog's lock otherwise when invite session creation
     * fails the dialog will be destroyed prematurely.
     */
    pjsip_dlg_inc_lock(dlg);
//    设置Via头域
    if (acc->cfg.allow_via_rewrite && acc->via_addr.host.slen > 0)
        pjsip_dlg_set_via_sent_by(dlg, &acc->via_addr, acc->via_tp);
//    设置安全级别,安全级别有何作用?
    /* Calculate call's secure level */
    call->secure_level = get_secure_level(acc_id, dest_uri);
//    设置用户数据,用户数据是什么?
    /* Attach user data */
    call->user_data = user_data;
    
//    复制消息数据,消息数据有何作用?
    /* Store variables required for the callback after the async
     * media transport creation is completed.
     */
    if (msg_data) {
call->async_call.call_var.out_call.msg_data = pjsua_msg_data_clone(
                                                          dlg->pool, msg_data);
    }
//    保存对话信息
    call->async_call.dlg = dlg;
    /* Temporarily increment dialog session. Without this, dialog will be
     * prematurely destroyed if dec_lock() is called on the dialog before
     * the invite session is created.
     */
    pjsip_dlg_inc_session(dlg, &pjsua_var.mod);
//    初始化媒体通道
    /* Init media channel */
    status = pjsua_media_channel_init(call->index, PJSIP_ROLE_UAC, 
      call->secure_level, dlg->pool,
      NULL, NULL, PJ_TRUE,
                                      &on_make_call_med_tp_complete);
//    调用媒体传输回调函数
    if (status == PJ_SUCCESS) {
        status = on_make_call_med_tp_complete(call->index, NULL);
        if (status != PJ_SUCCESS)
    goto on_error;
    } else if (status != PJ_EPENDING) {
pjsua_perror(THIS_FILE, "Error initializing media channel", status);
        pjsip_dlg_dec_session(dlg, &pjsua_var.mod);
goto on_error;
    }
    /* Done. */
    if (p_call_id)
*p_call_id = call_id;
    pjsip_dlg_dec_lock(dlg);
    pj_pool_release(tmp_pool);
    PJSUA_UNLOCK();
    pj_log_pop_indent();
    return PJ_SUCCESS;
on_error:
    if (dlg) {
/* This may destroy the dialog */
pjsip_dlg_dec_lock(dlg);
    }
    if (call_id != -1) {
pjsua_media_channel_deinit(call_id);
reset_call(call_id);
    }
    pjsua_check_snd_dev_idle();
    if (tmp_pool)
pj_pool_release(tmp_pool);
    PJSUA_UNLOCK();
    pj_log_pop_indent();
    return status;
}


网友点评

*

*

*

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。