⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pjsua_call.c

📁 基于sip协议的网络电话源码
💻 C
📖 第 1 页 / 共 5 页
字号:
	pjsua_call *replaced_call;	int st_code = 200;	pj_str_t st_text = { "OK", 2 };	/* Get the replaced call instance */	replaced_call = replaced_dlg->mod_data[pjsua_var.mod.id];	/* Notify application */	pjsua_var.ua_cfg.cb.on_call_replace_request(replaced_call->index,						    rdata, &st_code, &st_text);	/* Must specify final response */	PJ_ASSERT_ON_FAIL(st_code >= 200, st_code = 200);	/* Check if application rejects this request. */	if (st_code >= 300) {	    if (st_text.slen == 2)		st_text = *pjsip_get_status_text(st_code);	    pjsip_endpt_respond(pjsua_var.endpt, NULL, rdata, 				st_code, &st_text, NULL, NULL, NULL);	    PJSUA_UNLOCK();	    return PJ_TRUE;	}    }    /* Get media capability from media endpoint: */    status = pjmedia_endpt_create_sdp( pjsua_var.med_endpt, 				       rdata->tp_info.pool, 1,				       &call->skinfo, &answer );    if (status != PJ_SUCCESS) {	pjsip_endpt_respond_stateless(pjsua_var.endpt, rdata, 500, NULL,				      NULL, NULL);	PJSUA_UNLOCK();	return PJ_TRUE;    }    /* Verify that we can handle the request. */    status = pjsip_inv_verify_request(rdata, &options, answer, NULL,				      pjsua_var.endpt, &response);    if (status != PJ_SUCCESS) {	/*	 * No we can't handle the incoming INVITE request.	 */	if (response) {	    pjsip_response_addr res_addr;	    pjsip_get_response_addr(response->pool, rdata, &res_addr);	    pjsip_endpt_send_response(pjsua_var.endpt, &res_addr, response, 				      NULL, NULL);	} else {	    /* Respond with 500 (Internal Server Error) */	    pjsip_endpt_respond_stateless(pjsua_var.endpt, rdata, 500, NULL,					  NULL, NULL);	}	PJSUA_UNLOCK();	return PJ_TRUE;    }     /*      * Get which account is most likely to be associated with this incoming     * call. We need the account to find which contact URI to put for     * the call.     */    acc_id = call->acc_id = pjsua_acc_find_for_incoming(rdata);    /* Get suitable Contact header */    status = pjsua_acc_create_uas_contact(rdata->tp_info.pool, &contact,					  acc_id, rdata);    if (status != PJ_SUCCESS) {	pjsua_perror(THIS_FILE, "Unable to generate Contact header", status);	pjsip_endpt_respond_stateless(pjsua_var.endpt, rdata, 500, NULL,				      NULL, NULL);	PJSUA_UNLOCK();	return PJ_TRUE;    }    /* Create dialog: */    status = pjsip_dlg_create_uas( pjsip_ua_instance(), rdata,				   &contact, &dlg);    if (status != PJ_SUCCESS) {	pjsip_endpt_respond_stateless(pjsua_var.endpt, rdata, 500, NULL,				      NULL, NULL);	PJSUA_UNLOCK();	return PJ_TRUE;    }    /* Set credentials */    if (pjsua_var.acc[acc_id].cred_cnt) {	pjsip_auth_clt_set_credentials(&dlg->auth_sess, 				       pjsua_var.acc[acc_id].cred_cnt,				       pjsua_var.acc[acc_id].cred);    }    /* Create invite session: */    status = pjsip_inv_create_uas( dlg, rdata, answer, 0, &inv);    if (status != PJ_SUCCESS) {	pjsip_hdr hdr_list;	pjsip_warning_hdr *w;	w = pjsip_warning_hdr_create_from_status(dlg->pool, 						 pjsip_endpt_name(pjsua_var.endpt),						 status);	pj_list_init(&hdr_list);	pj_list_push_back(&hdr_list, w);	pjsip_dlg_respond(dlg, rdata, 500, NULL, &hdr_list, NULL);	/* Can't terminate dialog because transaction is in progress.	pjsip_dlg_terminate(dlg);	 */	PJSUA_UNLOCK();	return PJ_TRUE;    }    /* Create and attach pjsua_var data to the dialog: */    call->inv = inv;    dlg->mod_data[pjsua_var.mod.id] = call;    inv->mod_data[pjsua_var.mod.id] = call;    /* If account is locked to specific transport, then lock dialog     * to this transport too.     */    if (pjsua_var.acc[acc_id].cfg.transport_id != PJSUA_INVALID_ID) {	pjsip_tpselector tp_sel;	pjsua_init_tpselector(pjsua_var.acc[acc_id].cfg.transport_id, &tp_sel);	pjsip_dlg_set_transport(dlg, &tp_sel);    }    /* Must answer with some response to initial INVITE.     */    status = pjsip_inv_initial_answer(inv, rdata, 				      100, NULL, NULL, &response);    if (status != PJ_SUCCESS) {	pjsua_perror(THIS_FILE, "Unable to send answer to incoming INVITE", 		     status);	pjsip_dlg_respond(dlg, rdata, 500, NULL, NULL, NULL);	pjsip_inv_terminate(inv, 500, PJ_FALSE);	PJSUA_UNLOCK();	return PJ_TRUE;    } else {	status = pjsip_inv_send_msg(inv, response);	if (status != PJ_SUCCESS)	    pjsua_perror(THIS_FILE, "Unable to send 100 response", status);    }    ++pjsua_var.call_cnt;    /* Check if this request should replace existing call */    if (replaced_dlg) {	pjsip_inv_session *replaced_inv;	struct pjsua_call *replaced_call;	pjsip_tx_data *tdata;	/* Get the invite session in the dialog */	replaced_inv = pjsip_dlg_get_inv_session(replaced_dlg);	/* Get the replaced call instance */	replaced_call = replaced_dlg->mod_data[pjsua_var.mod.id];	/* Notify application */	if (pjsua_var.ua_cfg.cb.on_call_replaced)	    pjsua_var.ua_cfg.cb.on_call_replaced(replaced_call->index,					         call_id);	PJ_LOG(4,(THIS_FILE, "Answering replacement call %d with 200/OK",			     call_id));	/* Answer the new call with 200 response */	status = pjsip_inv_answer(inv, 200, NULL, NULL, &tdata);	if (status == PJ_SUCCESS)	    status = pjsip_inv_send_msg(inv, tdata);	if (status != PJ_SUCCESS)	    pjsua_perror(THIS_FILE, "Error answering session", status);	/* Note that inv may be invalid if 200/OK has caused error in	 * starting the media.	 */	PJ_LOG(4,(THIS_FILE, "Disconnecting replaced call %d",			     replaced_call->index));	/* Disconnect replaced invite session */	status = pjsip_inv_end_session(replaced_inv, PJSIP_SC_GONE, NULL,				       &tdata);	if (status == PJ_SUCCESS && tdata)	    status = pjsip_inv_send_msg(replaced_inv, tdata);	if (status != PJ_SUCCESS)	    pjsua_perror(THIS_FILE, "Error terminating session", status);    } else {	/* Notify application if on_incoming_call() is overriden, 	 * otherwise hangup the call with 480	 */	if (pjsua_var.ua_cfg.cb.on_incoming_call) {	    pjsua_var.ua_cfg.cb.on_incoming_call(acc_id, call_id, rdata);	} else {	    pjsua_call_hangup(call_id, PJSIP_SC_TEMPORARILY_UNAVAILABLE, 			      NULL, NULL);	}    }    /* This INVITE request has been handled. */    PJSUA_UNLOCK();    return PJ_TRUE;}/* * Check if the specified call has active INVITE session and the INVITE * session has not been disconnected. */PJ_DEF(pj_bool_t) pjsua_call_is_active(pjsua_call_id call_id){    PJ_ASSERT_RETURN(call_id>=0 && call_id<(int)pjsua_var.ua_cfg.max_calls,		     PJ_EINVAL);    return pjsua_var.calls[call_id].inv != NULL &&	   pjsua_var.calls[call_id].inv->state != PJSIP_INV_STATE_DISCONNECTED;}/* * Check if call has an active media session. */PJ_DEF(pj_bool_t) pjsua_call_has_media(pjsua_call_id call_id){    PJ_ASSERT_RETURN(call_id>=0 && call_id<(int)pjsua_var.ua_cfg.max_calls, 		     PJ_EINVAL);    return pjsua_var.calls[call_id].session != NULL;}/* Acquire lock to the specified call_id */static pj_status_t acquire_call(const char *title,				pjsua_call_id call_id,				pjsua_call **p_call,				pjsip_dialog **p_dlg){    enum { MAX_RETRY=50 };    unsigned retry;    pjsua_call *call = NULL;    pj_bool_t has_pjsua_lock = PJ_FALSE;    pj_status_t status = PJ_SUCCESS;    for (retry=0; retry<MAX_RETRY; ++retry) {		has_pjsua_lock = PJ_FALSE;	status = PJSUA_TRY_LOCK();	if (status != PJ_SUCCESS) {	    pj_thread_sleep(retry/10);	    continue;	}	has_pjsua_lock = PJ_TRUE;	call = &pjsua_var.calls[call_id];	if (call->inv == NULL) {	    PJSUA_UNLOCK();	    PJ_LOG(3,(THIS_FILE, "Invalid call_id %d in %s", call_id, title));	    return PJSIP_ESESSIONTERMINATED;	}	status = pjsip_dlg_try_inc_lock(call->inv->dlg);	if (status != PJ_SUCCESS) {	    PJSUA_UNLOCK();	    pj_thread_sleep(retry/10);	    continue;	}	PJSUA_UNLOCK();	break;    }    if (status != PJ_SUCCESS) {	if (has_pjsua_lock == PJ_FALSE)	    PJ_LOG(1,(THIS_FILE, "Timed-out trying to acquire PJSUA mutex "				 "(possibly system has deadlocked) in %s",				 title));	else	    PJ_LOG(1,(THIS_FILE, "Timed-out trying to acquire dialog mutex "				 "(possibly system has deadlocked) in %s",				 title));	return PJ_ETIMEDOUT;    }        *p_call = call;    *p_dlg = call->inv->dlg;    return PJ_SUCCESS;}/* * Get the conference port identification associated with the call. */PJ_DEF(pjsua_conf_port_id) pjsua_call_get_conf_port(pjsua_call_id call_id){    pjsua_call *call;    pjsua_conf_port_id port_id;    pjsip_dialog *dlg;    pj_status_t status;    PJ_ASSERT_RETURN(call_id>=0 && call_id<(int)pjsua_var.ua_cfg.max_calls, 		     PJ_EINVAL);    status = acquire_call("pjsua_call_get_conf_port()", call_id, &call, &dlg);    if (status != PJ_SUCCESS)	return PJSUA_INVALID_ID;    port_id = call->conf_slot;    pjsip_dlg_dec_lock(dlg);    return port_id;}/* * Obtain detail information about the specified call. */PJ_DEF(pj_status_t) pjsua_call_get_info( pjsua_call_id call_id,					 pjsua_call_info *info){    pjsua_call *call;    pjsip_dialog *dlg;    pj_status_t status;    PJ_ASSERT_RETURN(call_id>=0 && call_id<(int)pjsua_var.ua_cfg.max_calls,		     PJ_EINVAL);    pj_bzero(info, sizeof(*info));    status = acquire_call("pjsua_call_get_info()", call_id, &call, &dlg);    if (status != PJ_SUCCESS) {	return status;    }    /* id and role */    info->id = call_id;    info->role = call->inv->role;    info->acc_id = call->acc_id;    /* local info */    info->local_info.ptr = info->buf_.local_info;    pj_strncpy(&info->local_info, &call->inv->dlg->local.info_str,	       sizeof(info->buf_.local_info));    /* local contact */    info->local_contact.ptr = info->buf_.local_contact;    info->local_contact.slen = pjsip_uri_print(PJSIP_URI_IN_CONTACT_HDR,					       call->inv->dlg->local.contact->uri,					       info->local_contact.ptr,					       sizeof(info->buf_.local_contact));    /* remote info */    info->remote_info.ptr = info->buf_.remote_info;    pj_strncpy(&info->remote_info, &call->inv->dlg->remote.info_str,	       sizeof(info->buf_.remote_info));    /* remote contact */    if (call->inv->dlg->remote.contact) {	int len;	info->remote_contact.ptr = info->buf_.remote_contact;	len = pjsip_uri_print(PJSIP_URI_IN_CONTACT_HDR,			      call->inv->dlg->remote.contact->uri,			      info->remote_contact.ptr,			      sizeof(info->buf_.remote_contact));	if (len < 0) len = 0;	info->remote_contact.slen = len;    } else {	info->remote_contact.slen = 0;    }    /* call id */    info->call_id.ptr = info->buf_.call_id;    pj_strncpy(&info->call_id, &call->inv->dlg->call_id->id,	       sizeof(info->buf_.call_id));    /* state, state_text */    info->state = call->inv->state;    info->state_text = pj_str((char*)pjsip_inv_state_name(info->state));    /* If call is disconnected, set the last_status from the cause code */    if (call->inv->state >= PJSIP_INV_STATE_DISCONNECTED) {	/* last_status, last_status_text */	info->last_status = call->inv->cause;	info->last_status_text.ptr = info->buf_.last_status_text;	pj_strncpy(&info->last_status_text, &call->inv->cause_text,		   sizeof(info->buf_.last_status_text));    } else {	/* last_status, last_status_text */	info->last_status = call->last_code;	info->last_status_text.ptr = info->buf_.last_status_text;	pj_strncpy(&info->last_status_text, &call->last_text,		   sizeof(info->buf_.last_status_text));    }        /* media status and dir */    info->media_status = call->media_st;    info->media_dir = call->media_dir;    /* conference slot number */    info->conf_slot = call->conf_slot;    /* calculate duration */    if (info->state >= PJSIP_INV_STATE_DISCONNECTED) {	info->total_duration = call->dis_time;	PJ_TIME_VAL_SUB(info->total_duration, call->start_time);	if (call->conn_time.sec) {	    info->connect_duration = call->dis_time;	    PJ_TIME_VAL_SUB(info->connect_duration, call->conn_time);	}    } else if (info->state == PJSIP_INV_STATE_CONFIRMED) {	pj_gettimeofday(&info->total_duration);	PJ_TIME_VAL_SUB(info->total_duration, call->start_time);	pj_gettimeofday(&info->connect_duration);	PJ_TIME_VAL_SUB(info->connect_duration, call->conn_time);    } else {	pj_gettimeofday(&info->total_duration);	PJ_TIME_VAL_SUB(info->total_duration, call->start_time);    }    pjsip_dlg_dec_lock(dlg);    return PJ_SUCCESS;}/* * Attach application specific data to the call. */PJ_DEF(pj_status_t) pjsua_call_set_user_data( pjsua_call_id call_id,					      void *user_data){    PJ_ASSERT_RETURN(call_id>=0 && call_id<(int)pjsua_var.ua_cfg.max_calls,		     PJ_EINVAL);    pjsua_var.calls[call_id].user_data = user_data;    return PJ_SUCCESS;}/* * Get user data attached to the call. */PJ_DEF(void*) pjsua_call_get_user_data(pjsua_call_id call_id){    PJ_ASSERT_RETURN(call_id>=0 && call_id<(int)pjsua_var.ua_cfg.max_calls,		     NULL);    return pjsua_var.calls[call_id].user_data;}/* * Send response to incoming INVITE request. */PJ_DEF(pj_status_t) pjsua_call_answer( pjsua_call_id call_id, 				       unsigned code,				       const pj_str_t *reason,				       const pjsua_msg_data *msg_data){    pjsua_call *call;    pjsip_dialog *dlg;    pjsip_tx_data *tdata;    pj_status_t status;    PJ_ASSERT_RETURN(call_id>=0 && call_id<(int)pjsua_var.ua_cfg.max_calls,

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -