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

📄 pjsua_call.c

📁 基于sip协议的网络电话源码
💻 C
📖 第 1 页 / 共 5 页
字号:
	     */	    st_code = e->body.tsx_state.tsx->status_code;	    ev_state = PJSIP_EVSUB_STATE_TERMINATED;	    break;	case PJSIP_INV_STATE_DISCONNECTED:	    st_code = e->body.tsx_state.tsx->status_code;	    ev_state = PJSIP_EVSUB_STATE_TERMINATED;	    break;	case PJSIP_INV_STATE_INCOMING:	    /* Nothing to do. Just to keep gcc from complaining about	     * unused enums.	     */	    break;	}	if (st_code != -1) {	    pjsip_tx_data *tdata;	    pj_status_t status;	    status = pjsip_xfer_notify( call->xfer_sub,					ev_state, st_code,					NULL, &tdata);	    if (status != PJ_SUCCESS) {		pjsua_perror(THIS_FILE, "Unable to create NOTIFY", status);	    } else {		status = pjsip_xfer_send_request(call->xfer_sub, tdata);		if (status != PJ_SUCCESS) {		    pjsua_perror(THIS_FILE, "Unable to send NOTIFY", status);		}	    }	}    }    if (pjsua_var.ua_cfg.cb.on_call_state)	(*pjsua_var.ua_cfg.cb.on_call_state)(call->index, e);    /* call->inv may be NULL now */    /* Destroy media session when invite session is disconnected. */    if (inv->state == PJSIP_INV_STATE_DISCONNECTED) {	pj_assert(call != NULL);	if (call)	    call_destroy_media(call->index);	/* Free call */	call->inv = NULL;	--pjsua_var.call_cnt;	/* Reset call */	reset_call(call->index);    }    PJSUA_UNLOCK();}/* * This callback is called by invite session framework when UAC session * has forked. */static void pjsua_call_on_forked( pjsip_inv_session *inv, 				  pjsip_event *e){    PJ_UNUSED_ARG(inv);    PJ_UNUSED_ARG(e);    PJ_TODO(HANDLE_FORKED_DIALOG);}/* * Disconnect call upon error. */static void call_disconnect( pjsip_inv_session *inv, 			     int code ){    pjsip_tx_data *tdata;    pj_status_t status;    status = pjsip_inv_end_session(inv, code, NULL, &tdata);    if (status == PJ_SUCCESS)	pjsip_inv_send_msg(inv, tdata);}/* * DTMF callback from the stream. */static void dtmf_callback(pjmedia_stream *strm, void *user_data,			  int digit){    PJ_UNUSED_ARG(strm);    if (pjsua_var.ua_cfg.cb.on_dtmf_digit) {	pjsua_call_id call_id;	call_id = (pjsua_call_id)user_data;	pjsua_var.ua_cfg.cb.on_dtmf_digit(call_id, digit);    }}/* * Callback to be called when SDP offer/answer negotiation has just completed * in the session. This function will start/update media if negotiation * has succeeded. */static void pjsua_call_on_media_update(pjsip_inv_session *inv,				       pj_status_t status){    int prev_media_st = 0;    pjsua_call *call;    pjmedia_session_info sess_info;    const pjmedia_sdp_session *local_sdp;    const pjmedia_sdp_session *remote_sdp;    pjmedia_port *media_port;    pj_str_t port_name;    char tmp[PJSIP_MAX_URL_SIZE];    PJSUA_LOCK();    call = inv->dlg->mod_data[pjsua_var.mod.id];    if (status != PJ_SUCCESS) {	pjsua_perror(THIS_FILE, "SDP negotiation has failed", status);	/* Stop/destroy media, if any */	call_destroy_media(call->index);	/* Disconnect call if we're not in the middle of initializing an	 * UAS dialog and if this is not a re-INVITE 	 */	if (inv->state != PJSIP_INV_STATE_NULL &&	    inv->state != PJSIP_INV_STATE_CONFIRMED) 	{	    //call_disconnect(inv, PJSIP_SC_UNSUPPORTED_MEDIA_TYPE);	}	PJSUA_UNLOCK();	return;    }    /* Destroy existing media session, if any. */    if (call) {	prev_media_st = call->media_st;	call_destroy_media(call->index);    }    /* Get local and remote SDP */    status = pjmedia_sdp_neg_get_active_local(call->inv->neg, &local_sdp);    if (status != PJ_SUCCESS) {	pjsua_perror(THIS_FILE, 		     "Unable to retrieve currently active local SDP", 		     status);	//call_disconnect(inv, PJSIP_SC_UNSUPPORTED_MEDIA_TYPE);	PJSUA_UNLOCK();	return;    }    status = pjmedia_sdp_neg_get_active_remote(call->inv->neg, &remote_sdp);    if (status != PJ_SUCCESS) {	pjsua_perror(THIS_FILE, 		     "Unable to retrieve currently active remote SDP", 		     status);	//call_disconnect(inv, PJSIP_SC_UNSUPPORTED_MEDIA_TYPE);	PJSUA_UNLOCK();	return;    }    /* Create media session info based on SDP parameters.      * We only support one stream per session at the moment     */        status = pjmedia_session_info_from_sdp( call->inv->dlg->pool, 					    pjsua_var.med_endpt, 					    1,&sess_info, 					    local_sdp, remote_sdp);    if (status != PJ_SUCCESS) {	pjsua_perror(THIS_FILE, "Unable to create media session", 		     status);	call_disconnect(inv, PJSIP_SC_UNSUPPORTED_MEDIA_TYPE);	PJSUA_UNLOCK();	return;    }    /* Check if media is put on-hold */    if (sess_info.stream_cnt == 0 || 	sess_info.stream_info[0].dir == PJMEDIA_DIR_NONE)    {	/* Determine who puts the call on-hold */	if (prev_media_st == PJSUA_CALL_MEDIA_ACTIVE) {	    if (pjmedia_sdp_neg_was_answer_remote(call->inv->neg)) {		/* It was local who offer hold */		call->media_st = PJSUA_CALL_MEDIA_LOCAL_HOLD;	    } else {		call->media_st = PJSUA_CALL_MEDIA_REMOTE_HOLD;	    }	}	call->media_dir = PJMEDIA_DIR_NONE;    } else {	/* Override ptime, if this option is specified. */	if (pjsua_var.media_cfg.ptime != 0) {	    sess_info.stream_info[0].param->setting.frm_per_pkt = (pj_uint8_t)		(pjsua_var.media_cfg.ptime / sess_info.stream_info[0].param->info.frm_ptime);	    if (sess_info.stream_info[0].param->setting.frm_per_pkt == 0)		sess_info.stream_info[0].param->setting.frm_per_pkt = 1;	}	/* Disable VAD, if this option is specified. */	if (pjsua_var.media_cfg.no_vad) {	    sess_info.stream_info[0].param->setting.vad = 0;	}	/* Optionally, application may modify other stream settings here	 * (such as jitter buffer parameters, codec ptime, etc.)	 */	sess_info.stream_info[0].jb_init = pjsua_var.media_cfg.jb_init;	sess_info.stream_info[0].jb_min_pre = pjsua_var.media_cfg.jb_min_pre;	sess_info.stream_info[0].jb_max_pre = pjsua_var.media_cfg.jb_max_pre;	sess_info.stream_info[0].jb_max = pjsua_var.media_cfg.jb_max;	/* Create session based on session info. */	status = pjmedia_session_create( pjsua_var.med_endpt, &sess_info,					 &call->med_tp,					 call, &call->session );	if (status != PJ_SUCCESS) {	    pjsua_perror(THIS_FILE, "Unable to create media session", 			 status);	    //call_disconnect(inv, PJSIP_SC_UNSUPPORTED_MEDIA_TYPE);	    PJSUA_UNLOCK();	    return;	}	/* If DTMF callback is installed by application, install our	 * callback to the session.	 */	if (pjsua_var.ua_cfg.cb.on_dtmf_digit) {	    pjmedia_session_set_dtmf_callback(call->session, 0, 					      &dtmf_callback, 					      (void*)(call->index));	}	/* Get the port interface of the first stream in the session.	 * We need the port interface to add to the conference bridge.	 */	pjmedia_session_get_port(call->session, 0, &media_port);	/*	 * Add the call to conference bridge.	 */	port_name.ptr = tmp;	port_name.slen = pjsip_uri_print(PJSIP_URI_IN_REQ_URI,					 call->inv->dlg->remote.info->uri,					 tmp, sizeof(tmp));	if (port_name.slen < 1) {	    port_name = pj_str("call");	}	status = pjmedia_conf_add_port( pjsua_var.mconf, call->inv->pool,					media_port, 					&port_name,					(unsigned*)&call->conf_slot);	if (status != PJ_SUCCESS) {	    pjsua_perror(THIS_FILE, "Unable to create conference slot", 			 status);	    call_destroy_media(call->index);	    //call_disconnect(inv, PJSIP_SC_INTERNAL_SERVER_ERROR);	    PJSUA_UNLOCK();	    return;	}	/* Call's media state is active */	call->media_st = PJSUA_CALL_MEDIA_ACTIVE;	call->media_dir = sess_info.stream_info[0].dir;    }    /* Print info. */    {	char info[80];	int info_len = 0;	unsigned i;	for (i=0; i<sess_info.stream_cnt; ++i) {	    int len;	    const char *dir;	    pjmedia_stream_info *strm_info = &sess_info.stream_info[i];	    switch (strm_info->dir) {	    case PJMEDIA_DIR_NONE:		dir = "inactive";		break;	    case PJMEDIA_DIR_ENCODING:		dir = "sendonly";		break;	    case PJMEDIA_DIR_DECODING:		dir = "recvonly";		break;	    case PJMEDIA_DIR_ENCODING_DECODING:		dir = "sendrecv";		break;	    default:		dir = "unknown";		break;	    }	    len = pj_ansi_sprintf( info+info_len,				   ", stream #%d: %.*s (%s)", i,				   (int)strm_info->fmt.encoding_name.slen,				   strm_info->fmt.encoding_name.ptr,				   dir);	    if (len > 0)		info_len += len;	}	PJ_LOG(4,(THIS_FILE,"Media updates%s", info));    }    /* Call application callback, if any */    if (pjsua_var.ua_cfg.cb.on_call_media_state)	pjsua_var.ua_cfg.cb.on_call_media_state(call->index);    PJSUA_UNLOCK();}/* * Create inactive SDP for call hold. */static pj_status_t create_inactive_sdp(pjsua_call *call,				       pjmedia_sdp_session **p_answer){    pj_status_t status;    pjmedia_sdp_conn *conn;    pjmedia_sdp_attr *attr;    pjmedia_sdp_session *sdp;    /* Create new offer */    status = pjmedia_endpt_create_sdp(pjsua_var.med_endpt, pjsua_var.pool, 1,				      &call->skinfo, &sdp);    if (status != PJ_SUCCESS) {	pjsua_perror(THIS_FILE, "Unable to create local SDP", status);	return status;    }    /* Get SDP media connection line */    conn = sdp->media[0]->conn;    if (!conn)	conn = sdp->conn;    /* Modify address */    conn->addr = pj_str("0.0.0.0");    /* Remove existing directions attributes */    pjmedia_sdp_media_remove_all_attr(sdp->media[0], "sendrecv");    pjmedia_sdp_media_remove_all_attr(sdp->media[0], "sendonly");    pjmedia_sdp_media_remove_all_attr(sdp->media[0], "recvonly");    pjmedia_sdp_media_remove_all_attr(sdp->media[0], "inactive");    /* Add inactive attribute */    attr = pjmedia_sdp_attr_create(pjsua_var.pool, "inactive", NULL);    pjmedia_sdp_media_add_attr(sdp->media[0], attr);    *p_answer = sdp;    return status;}/* * Called when session received new offer. */static void pjsua_call_on_rx_offer(pjsip_inv_session *inv,				   const pjmedia_sdp_session *offer){    const char *remote_state;    pjsua_call *call;    pjmedia_sdp_conn *conn;    pjmedia_sdp_session *answer;    pj_bool_t is_remote_active;    pj_status_t status;    PJSUA_LOCK();    call = inv->dlg->mod_data[pjsua_var.mod.id];    /*     * See if remote is offering active media (i.e. not on-hold)     */    is_remote_active = PJ_TRUE;    conn = offer->media[0]->conn;    if (!conn)	conn = offer->conn;    if (pj_strcmp2(&conn->addr, "0.0.0.0")==0 ||	pj_strcmp2(&conn->addr, "0")==0)    {	is_remote_active = PJ_FALSE;    }     else if (pjmedia_sdp_media_find_attr2(offer->media[0], "inactive", NULL))    {	is_remote_active = PJ_FALSE;    }    remote_state = (is_remote_active ? "active" : "inactive");    /* Supply candidate answer */    if (call->media_st == PJSUA_CALL_MEDIA_LOCAL_HOLD || !is_remote_active) {	PJ_LOG(4,(THIS_FILE, 		  "Call %d: RX new media offer, creating inactive SDP "		  "(media in offer is %s)", call->index, remote_state));	status = create_inactive_sdp( call, &answer );    } else {	PJ_LOG(4,(THIS_FILE, "Call %d: received updated media offer",		  call->index));	status = pjmedia_endpt_create_sdp( pjsua_var.med_endpt, 					   call->inv->pool, 1,					   &call->skinfo, &answer);	    }    if (status != PJ_SUCCESS) {	pjsua_perror(THIS_FILE, "Unable to create local SDP", status);	PJSUA_UNLOCK();	return;    }    status = pjsip_inv_set_sdp_answer(call->inv, answer);    if (status != PJ_SUCCESS) {	pjsua_perror(THIS_FILE, "Unable to set answer", status);	PJSUA_UNLOCK();	return;    }    PJSUA_UNLOCK();}/* * Callback called by event framework when the xfer subscription state * has changed. */static void xfer_client_on_evsub_state( pjsip_evsub *sub, pjsip_event *event){        PJ_UNUSED_ARG(event);    /*     * When subscription is accepted (got 200/OK to REFER), check if      * subscription suppressed.     */    if (pjsip_evsub_get_state(sub) == PJSIP_EVSUB_STATE_ACCEPTED) {	pjsip_rx_data *rdata;	pjsip_generic_string_hdr *refer_sub;	const pj_str_t REFER_SUB = { "Refer-Sub", 9 };	pjsua_call *call;	call = pjsip_evsub_get_mod_data(sub, pjsua_var.mod.id);	/* Must be receipt of response message */	pj_assert(event->type == PJSIP_EVENT_TSX_STATE && 		  event->body.tsx_state.type == PJSIP_EVENT_RX_MSG);	rdata = event->body.tsx_state.src.rdata;	/* Find Refer-Sub header */	refer_sub = (pjsip_generic_string_hdr*)		    pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, 					       &REFER_SUB, NULL);	/* Check if subscription is suppressed */	if (refer_sub && pj_stricmp2(&refer_sub->hvalue, "false")==0) {	    /* Since no subscription is desired, assume that call has been	     * transfered successfully.	     */	    if (call && pjsua_var.ua_cfg.cb.on_call_transfer_status) {		const pj_str_t ACCEPTED = { "Accepted", 8 };		pj_bool_t cont = PJ_FALSE;		(*pjsua_var.ua_cfg.cb.on_call_transfer_status)(call->index, 							       200,							       &ACCEPTED,							       PJ_TRUE,							       &cont);	    }

⌨️ 快捷键说明

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