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

📄 pjsua_call.c

📁 基于sip协议的网络电话源码
💻 C
📖 第 1 页 / 共 5 页
字号:
on_return:    pjsip_dlg_dec_lock(dlg);    return status;}/* * Send IM typing indication inside INVITE session. */PJ_DEF(pj_status_t) pjsua_call_send_typing_ind( pjsua_call_id call_id, 						pj_bool_t is_typing,						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,		     PJ_EINVAL);    status = acquire_call("pjsua_call_send_typing_ind", call_id, &call, &dlg);    if (status != PJ_SUCCESS)	return status;    /* Create request message. */    status = pjsip_dlg_create_request( call->inv->dlg, &pjsip_message_method,				       -1, &tdata);    if (status != PJ_SUCCESS) {	pjsua_perror(THIS_FILE, "Unable to create MESSAGE request", status);	goto on_return;    }    /* Create "application/im-iscomposing+xml" msg body. */    tdata->msg->body = pjsip_iscomposing_create_body(tdata->pool, is_typing,						     NULL, NULL, -1);    /* Add additional headers etc */    pjsua_process_msg_data( tdata, msg_data);    /* Send the request. */    status = pjsip_dlg_send_request( call->inv->dlg, tdata, -1, NULL);    if (status != PJ_SUCCESS) {	pjsua_perror(THIS_FILE, "Unable to send MESSAGE request", status);	goto on_return;    }on_return:    pjsip_dlg_dec_lock(dlg);    return status;}/* * Terminate all calls. */PJ_DEF(void) pjsua_call_hangup_all(void){    unsigned i;    PJSUA_LOCK();    for (i=0; i<pjsua_var.ua_cfg.max_calls; ++i) {	if (pjsua_var.calls[i].inv)	    pjsua_call_hangup(i, 0, NULL, NULL);    }    PJSUA_UNLOCK();}static const char *good_number(char *buf, pj_int32_t val){    if (val < 1000) {	pj_ansi_sprintf(buf, "%d", val);    } else if (val < 1000000) {	pj_ansi_sprintf(buf, "%d.%dK", 			val / 1000,			(val % 1000) / 100);    } else {	pj_ansi_sprintf(buf, "%d.%02dM", 			val / 1000000,			(val % 1000000) / 10000);    }    return buf;}/* Dump media session */static void dump_media_session(const char *indent, 			       char *buf, unsigned maxlen,			       pjmedia_session *session){    unsigned i;    char *p = buf, *end = buf+maxlen;    int len;    pjmedia_session_info info;    pjmedia_session_get_info(session, &info);    for (i=0; i<info.stream_cnt; ++i) {	pjmedia_rtcp_stat stat;	const char *rem_addr;	int rem_port;	const char *dir;	char last_update[64];	char packets[32], bytes[32], ipbytes[32], avg_bps[32];	pj_time_val media_duration, now;	pjmedia_session_get_stream_stat(session, i, &stat);	rem_addr = pj_inet_ntoa(info.stream_info[i].rem_addr.sin_addr);	rem_port = pj_ntohs(info.stream_info[i].rem_addr.sin_port);	if (info.stream_info[i].dir == PJMEDIA_DIR_ENCODING)	    dir = "sendonly";	else if (info.stream_info[i].dir == PJMEDIA_DIR_DECODING)	    dir = "recvonly";	else if (info.stream_info[i].dir == PJMEDIA_DIR_ENCODING_DECODING)	    dir = "sendrecv";	else	    dir = "inactive";		len = pj_ansi_snprintf(buf, end-p, 		  "%s  #%d %.*s @%dKHz, %s, peer=%s:%d",		  indent, i,		  (int)info.stream_info[i].fmt.encoding_name.slen,		  info.stream_info[i].fmt.encoding_name.ptr,		  info.stream_info[i].fmt.clock_rate / 1000,		  dir,		  rem_addr, rem_port);	if (len < 1 || len > end-p) {	    *p = '\0';	    return;	}	p += len;	*p++ = '\n';	*p = '\0';	if (stat.rx.update_cnt == 0)	    strcpy(last_update, "never");	else {	    pj_gettimeofday(&now);	    PJ_TIME_VAL_SUB(now, stat.rx.update);	    sprintf(last_update, "%02ldh:%02ldm:%02ld.%03lds ago",		    now.sec / 3600,		    (now.sec % 3600) / 60,		    now.sec % 60,		    now.msec);	}	pj_gettimeofday(&media_duration);	PJ_TIME_VAL_SUB(media_duration, stat.start);	if (PJ_TIME_VAL_MSEC(media_duration) == 0)	    media_duration.msec = 1;	len = pj_ansi_snprintf(p, end-p,	       "%s     RX pt=%d, stat last update: %s\n"	       "%s        total %spkt %sB (%sB +IP hdr) @avg=%sbps\n"	       "%s        pkt loss=%d (%3.1f%%), dup=%d (%3.1f%%), reorder=%d (%3.1f%%)\n"	       "%s              (msec)    min     avg     max     last\n"	       "%s        loss period: %7.3f %7.3f %7.3f %7.3f\n"	       "%s        jitter     : %7.3f %7.3f %7.3f %7.3f%s",	       indent, info.stream_info[i].fmt.pt,	       last_update,	       indent,	       good_number(packets, stat.rx.pkt),	       good_number(bytes, stat.rx.bytes),	       good_number(ipbytes, stat.rx.bytes + stat.rx.pkt * 32),	       good_number(avg_bps, stat.rx.bytes * 8 * 1000 / PJ_TIME_VAL_MSEC(media_duration)),	       indent,	       stat.rx.loss,	       stat.rx.loss * 100.0 / (stat.rx.pkt + stat.rx.loss),	       stat.rx.dup, 	       stat.rx.dup * 100.0 / (stat.rx.pkt + stat.rx.loss),	       stat.rx.reorder, 	       stat.rx.reorder * 100.0 / (stat.rx.pkt + stat.rx.loss),	       indent, indent,	       stat.rx.loss_period.min / 1000.0, 	       stat.rx.loss_period.avg / 1000.0, 	       stat.rx.loss_period.max / 1000.0,	       stat.rx.loss_period.last / 1000.0,	       indent,	       stat.rx.jitter.min / 1000.0,	       stat.rx.jitter.avg / 1000.0,	       stat.rx.jitter.max / 1000.0,	       stat.rx.jitter.last / 1000.0,	       ""	       );	if (len < 1 || len > end-p) {	    *p = '\0';	    return;	}	p += len;	*p++ = '\n';	*p = '\0';		if (stat.tx.update_cnt == 0)	    strcpy(last_update, "never");	else {	    pj_gettimeofday(&now);	    PJ_TIME_VAL_SUB(now, stat.tx.update);	    sprintf(last_update, "%02ldh:%02ldm:%02ld.%03lds ago",		    now.sec / 3600,		    (now.sec % 3600) / 60,		    now.sec % 60,		    now.msec);	}	len = pj_ansi_snprintf(p, end-p,	       "%s     TX pt=%d, ptime=%dms, stat last update: %s\n"	       "%s        total %spkt %sB (%sB +IP hdr) @avg %sbps\n"	       "%s        pkt loss=%d (%3.1f%%), dup=%d (%3.1f%%), reorder=%d (%3.1f%%)\n"	       "%s              (msec)    min     avg     max     last\n"	       "%s        loss period: %7.3f %7.3f %7.3f %7.3f\n"	       "%s        jitter     : %7.3f %7.3f %7.3f %7.3f%s",	       indent,	       info.stream_info[i].tx_pt,	       info.stream_info[i].param->info.frm_ptime *		info.stream_info[i].param->setting.frm_per_pkt,	       last_update,	       indent,	       good_number(packets, stat.tx.pkt),	       good_number(bytes, stat.tx.bytes),	       good_number(ipbytes, stat.tx.bytes + stat.tx.pkt * 32),	       good_number(avg_bps, stat.tx.bytes * 8 * 1000 / PJ_TIME_VAL_MSEC(media_duration)),	       indent,	       stat.tx.loss,	       stat.tx.loss * 100.0 / (stat.tx.pkt + stat.tx.loss),	       stat.tx.dup, 	       stat.tx.dup * 100.0 / (stat.tx.pkt + stat.tx.loss),	       stat.tx.reorder, 	       stat.tx.reorder * 100.0 / (stat.tx.pkt + stat.tx.loss),	       indent, indent,	       stat.tx.loss_period.min / 1000.0, 	       stat.tx.loss_period.avg / 1000.0, 	       stat.tx.loss_period.max / 1000.0,	       stat.tx.loss_period.last / 1000.0,	       indent,	       stat.tx.jitter.min / 1000.0,	       stat.tx.jitter.avg / 1000.0,	       stat.tx.jitter.max / 1000.0,	       stat.tx.jitter.last / 1000.0,	       ""	       );	if (len < 1 || len > end-p) {	    *p = '\0';	    return;	}	p += len;	*p++ = '\n';	*p = '\0';	len = pj_ansi_snprintf(p, end-p,	       "%s    RTT msec       : %7.3f %7.3f %7.3f %7.3f", 	       indent,	       stat.rtt.min / 1000.0,	       stat.rtt.avg / 1000.0,	       stat.rtt.max / 1000.0,	       stat.rtt.last / 1000.0	       );	if (len < 1 || len > end-p) {	    *p = '\0';	    return;	}	p += len;	*p++ = '\n';	*p = '\0';    }}/* Print call info */static void print_call(const char *title,		       int call_id, 		       char *buf, pj_size_t size){    int len;    pjsip_inv_session *inv = pjsua_var.calls[call_id].inv;    pjsip_dialog *dlg = inv->dlg;    char userinfo[128];    /* Dump invite sesion info. */    len = pjsip_hdr_print_on(dlg->remote.info, userinfo, sizeof(userinfo));    if (len < 1)	pj_ansi_strcpy(userinfo, "<--uri too long-->");    else	userinfo[len] = '\0';        len = pj_ansi_snprintf(buf, size, "%s[%s] %s",			   title,			   pjsip_inv_state_name(inv->state),			   userinfo);    if (len < 1 || len >= (int)size) {	pj_ansi_strcpy(buf, "<--uri too long-->");	len = 18;    } else	buf[len] = '\0';}/* * Dump call and media statistics to string. */PJ_DEF(pj_status_t) pjsua_call_dump( pjsua_call_id call_id, 				     pj_bool_t with_media, 				     char *buffer, 				     unsigned maxlen,				     const char *indent){    pjsua_call *call;    pjsip_dialog *dlg;    pj_time_val duration, res_delay, con_delay;    char tmp[128];    char *p, *end;    pj_status_t status;    int len;    PJ_ASSERT_RETURN(call_id>=0 && call_id<(int)pjsua_var.ua_cfg.max_calls,		     PJ_EINVAL);    status = acquire_call("pjsua_call_dump()", call_id, &call, &dlg);    if (status != PJ_SUCCESS)	return status;    *buffer = '\0';    p = buffer;    end = buffer + maxlen;    len = 0;    print_call(indent, call_id, tmp, sizeof(tmp));        len = pj_ansi_strlen(tmp);    pj_ansi_strcpy(buffer, tmp);    p += len;    *p++ = '\r';    *p++ = '\n';    /* Calculate call duration */    if (call->conn_time.sec != 0) {	pj_gettimeofday(&duration);	PJ_TIME_VAL_SUB(duration, call->conn_time);	con_delay = call->conn_time;	PJ_TIME_VAL_SUB(con_delay, call->start_time);    } else {	duration.sec = duration.msec = 0;	con_delay.sec = con_delay.msec = 0;    }    /* Calculate first response delay */    if (call->res_time.sec != 0) {	res_delay = call->res_time;	PJ_TIME_VAL_SUB(res_delay, call->start_time);    } else {	res_delay.sec = res_delay.msec = 0;    }    /* Print duration */    len = pj_ansi_snprintf(p, end-p, 		           "%s  Call time: %02dh:%02dm:%02ds, "		           "1st res in %d ms, conn in %dms",			   indent,		           (int)(duration.sec / 3600),		           (int)((duration.sec % 3600)/60),		           (int)(duration.sec % 60),		           (int)PJ_TIME_VAL_MSEC(res_delay), 		           (int)PJ_TIME_VAL_MSEC(con_delay));        if (len > 0 && len < end-p) {	p += len;	*p++ = '\n';	*p = '\0';    }    /* Dump session statistics */    if (with_media && call->session)	dump_media_session(indent, p, end-p, call->session);    pjsip_dlg_dec_lock(dlg);    return PJ_SUCCESS;}/* * Destroy the call's media */static pj_status_t call_destroy_media(int call_id){    pjsua_call *call = &pjsua_var.calls[call_id];    if (call->conf_slot != PJSUA_INVALID_ID) {	pjmedia_conf_remove_port(pjsua_var.mconf, call->conf_slot);	call->conf_slot = PJSUA_INVALID_ID;    }    if (call->session) {	/* Destroy session (this will also close RTP/RTCP sockets). */	pjmedia_session_destroy(call->session);	call->session = NULL;	PJ_LOG(4,(THIS_FILE, "Media session for call %d is destroyed", 			     call_id));    }    call->media_st = PJSUA_CALL_MEDIA_NONE;    return PJ_SUCCESS;}/* * This callback receives notification from invite session when the * session state has changed. */static void pjsua_call_on_state_changed(pjsip_inv_session *inv, 					pjsip_event *e){    pjsua_call *call;    PJSUA_LOCK();    call = inv->dlg->mod_data[pjsua_var.mod.id];    if (!call) {	PJSUA_UNLOCK();	return;    }    /* Get call times */    switch (inv->state) {	case PJSIP_INV_STATE_EARLY:	case PJSIP_INV_STATE_CONNECTING:	    if (call->res_time.sec == 0)		pj_gettimeofday(&call->res_time);	    call->last_code = e->body.tsx_state.tsx->status_code;	    pj_strncpy(&call->last_text, 		       &e->body.tsx_state.tsx->status_text,		       sizeof(call->last_text_buf_));	    break;	case PJSIP_INV_STATE_CONFIRMED:	    pj_gettimeofday(&call->conn_time);	    break;	case PJSIP_INV_STATE_DISCONNECTED:	    pj_gettimeofday(&call->dis_time);	    if (call->res_time.sec == 0)		pj_gettimeofday(&call->res_time);	    if (e->body.tsx_state.tsx->status_code > call->last_code) {		call->last_code = e->body.tsx_state.tsx->status_code;		pj_strncpy(&call->last_text, 			   &e->body.tsx_state.tsx->status_text,			   sizeof(call->last_text_buf_));	    }	    break;	default:	    call->last_code = e->body.tsx_state.tsx->status_code;	    pj_strncpy(&call->last_text, 		       &e->body.tsx_state.tsx->status_text,		       sizeof(call->last_text_buf_));	    break;    }    /* If this is an outgoing INVITE that was created because of     * REFER/transfer, send NOTIFY to transferer.     */    if (call->xfer_sub && e->type==PJSIP_EVENT_TSX_STATE)  {	int st_code = -1;	pjsip_evsub_state ev_state = PJSIP_EVSUB_STATE_ACTIVE;		switch (call->inv->state) {	case PJSIP_INV_STATE_NULL:	case PJSIP_INV_STATE_CALLING:	    /* Do nothing */	    break;	case PJSIP_INV_STATE_EARLY:	case PJSIP_INV_STATE_CONNECTING:	    st_code = e->body.tsx_state.tsx->status_code;	    ev_state = PJSIP_EVSUB_STATE_ACTIVE;	    break;	case PJSIP_INV_STATE_CONFIRMED:	    /* When state is confirmed, send the final 200/OK and terminate	     * subscription.

⌨️ 快捷键说明

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