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

📄 siprtp.c

📁 基于sip协议的网络电话源码
💻 C
📖 第 1 页 / 共 4 页
字号:
    /* Attach call data to invite session */    call->inv->mod_data[mod_siprtp.id] = call;    /* Mark start of call */    pj_gettimeofday(&call->start_time);    /* Create initial INVITE request.     * This INVITE request will contain a perfectly good request and      * an SDP body as well.     */    status = pjsip_inv_invite(call->inv, &tdata);    PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);    /* Send initial INVITE request.      * From now on, the invite session's state will be reported to us     * via the invite session callbacks.     */    status = pjsip_inv_send_msg(call->inv, tdata);    PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);    return PJ_SUCCESS;}/* * Receive incoming call */static void process_incoming_call(pjsip_rx_data *rdata){    unsigned i, options;    struct call *call;    pjsip_dialog *dlg;    pjmedia_sdp_session *sdp;    pjsip_tx_data *tdata;    pj_status_t status;    /* Find free call slot */    for (i=0; i<app.max_calls; ++i) {	if (app.call[i].inv == NULL)	    break;    }    if (i == app.max_calls) {	const pj_str_t reason = pj_str("Too many calls");	pjsip_endpt_respond_stateless( app.sip_endpt, rdata, 				       500, &reason,				       NULL, NULL);	return;    }    call = &app.call[i];    /* Verify that we can handle the request. */    options = 0;    status = pjsip_inv_verify_request(rdata, &options, NULL, NULL,  				   app.sip_endpt, &tdata);    if (status != PJ_SUCCESS) {	/*	 * No we can't handle the incoming INVITE request.	 */	if (tdata) {	    pjsip_response_addr res_addr;	    	    pjsip_get_response_addr(tdata->pool, rdata, &res_addr);	    pjsip_endpt_send_response(app.sip_endpt, &res_addr, tdata,		NULL, NULL);	    	} else {	    	    /* Respond with 500 (Internal Server Error) */	    pjsip_endpt_respond_stateless(app.sip_endpt, rdata, 500, NULL,		NULL, NULL);	}		return;    }    /* Create UAS dialog */    status = pjsip_dlg_create_uas( pjsip_ua_instance(), rdata,				   &app.local_contact, &dlg);    if (status != PJ_SUCCESS) {	const pj_str_t reason = pj_str("Unable to create dialog");	pjsip_endpt_respond_stateless( app.sip_endpt, rdata, 				       500, &reason,				       NULL, NULL);	return;    }    /* Create SDP */    create_sdp( dlg->pool, call, &sdp);    /* Create UAS invite session */    status = pjsip_inv_create_uas( dlg, rdata, sdp, 0, &call->inv);    if (status != PJ_SUCCESS) {	pjsip_dlg_create_response(dlg, rdata, 500, NULL, &tdata);	pjsip_dlg_send_response(dlg, pjsip_rdata_get_tsx(rdata), tdata);	return;    }        /* Attach call data to invite session */    call->inv->mod_data[mod_siprtp.id] = call;    /* Mark start of call */    pj_gettimeofday(&call->start_time);    /* Create 200 response .*/    status = pjsip_inv_initial_answer(call->inv, rdata, 200, 				      NULL, NULL, &tdata);    if (status != PJ_SUCCESS) {	status = pjsip_inv_initial_answer(call->inv, rdata, 					  PJSIP_SC_NOT_ACCEPTABLE,					  NULL, NULL, &tdata);	if (status == PJ_SUCCESS)	    pjsip_inv_send_msg(call->inv, tdata); 	else	    pjsip_inv_terminate(call->inv, 500, PJ_FALSE);	return;    }    /* Send the 200 response. */      status = pjsip_inv_send_msg(call->inv, tdata);     PJ_ASSERT_ON_FAIL(status == PJ_SUCCESS, return);    /* Done */}/* Callback to be called when dialog has forked: */static void call_on_forked(pjsip_inv_session *inv, pjsip_event *e){    PJ_UNUSED_ARG(inv);    PJ_UNUSED_ARG(e);    PJ_TODO( HANDLE_FORKING );}/* Callback to be called to handle incoming requests outside dialogs: */static pj_bool_t on_rx_request( pjsip_rx_data *rdata ){    /* Ignore strandled ACKs (must not send respone */    if (rdata->msg_info.msg->line.req.method.id == PJSIP_ACK_METHOD)	return PJ_FALSE;    /* Respond (statelessly) any non-INVITE requests with 500  */    if (rdata->msg_info.msg->line.req.method.id != PJSIP_INVITE_METHOD) {	pj_str_t reason = pj_str("Unsupported Operation");	pjsip_endpt_respond_stateless( app.sip_endpt, rdata, 				       500, &reason,				       NULL, NULL);	return PJ_TRUE;    }    /* Handle incoming INVITE */    process_incoming_call(rdata);    /* Done */    return PJ_TRUE;}/* Callback timer to disconnect call (limiting call duration) */static void timer_disconnect_call( pj_timer_heap_t *timer_heap,				   struct pj_timer_entry *entry){    struct call *call = entry->user_data;    PJ_UNUSED_ARG(timer_heap);    entry->id = 0;    hangup_call(call->index);}/* Callback to be called when invite session's state has changed: */static void call_on_state_changed( pjsip_inv_session *inv, 				   pjsip_event *e){    struct call *call = inv->mod_data[mod_siprtp.id];    PJ_UNUSED_ARG(e);    if (!call)	return;    if (inv->state == PJSIP_INV_STATE_DISCONNECTED) {		pj_time_val null_time = {0, 0};	if (call->d_timer.id != 0) {	    pjsip_endpt_cancel_timer(app.sip_endpt, &call->d_timer);	    call->d_timer.id = 0;	}	PJ_LOG(3,(THIS_FILE, "Call #%d disconnected. Reason=%d (%.*s)",		  call->index,		  inv->cause,		  (int)inv->cause_text.slen,		  inv->cause_text.ptr));	PJ_LOG(3,(THIS_FILE, "Call #%d statistics:", call->index));	print_call(call->index);	call->inv = NULL;	inv->mod_data[mod_siprtp.id] = NULL;	destroy_call_media(call->index);	call->start_time = null_time;	call->response_time = null_time;	call->connect_time = null_time;	++app.uac_calls;    } else if (inv->state == PJSIP_INV_STATE_CONFIRMED) {	pj_time_val t;	pj_gettimeofday(&call->connect_time);	if (call->response_time.sec == 0)	    call->response_time = call->connect_time;	t = call->connect_time;	PJ_TIME_VAL_SUB(t, call->start_time);	PJ_LOG(3,(THIS_FILE, "Call #%d connected in %d ms", call->index,		  PJ_TIME_VAL_MSEC(t)));	if (app.duration != 0) {	    call->d_timer.id = 1;	    call->d_timer.user_data = call;	    call->d_timer.cb = &timer_disconnect_call;	    t.sec = app.duration;	    t.msec = 0;	    pjsip_endpt_schedule_timer(app.sip_endpt, &call->d_timer, &t);	}    } else if (	inv->state == PJSIP_INV_STATE_EARLY ||		inv->state == PJSIP_INV_STATE_CONNECTING) {	if (call->response_time.sec == 0)	    pj_gettimeofday(&call->response_time);    }}/* Utility */static void app_perror(const char *sender, const char *title, 		       pj_status_t status){    char errmsg[PJ_ERR_MSG_SIZE];    pj_strerror(status, errmsg, sizeof(errmsg));    PJ_LOG(3,(sender, "%s: %s [status=%d]", title, errmsg, status));}/* Worker thread for SIP */static int sip_worker_thread(void *arg){    PJ_UNUSED_ARG(arg);    while (!app.thread_quit) {	pj_time_val timeout = {0, 10};	pjsip_endpt_handle_events(app.sip_endpt, &timeout);    }    return 0;}/* Init application options */static pj_status_t init_options(int argc, char *argv[]){    static char ip_addr[32];    static char local_uri[64];    enum { OPT_START,	   OPT_APP_LOG_LEVEL, OPT_LOG_FILE, 	   OPT_A_PT, OPT_A_NAME, OPT_A_CLOCK, OPT_A_BITRATE, OPT_A_PTIME,	   OPT_REPORT_FILE };    struct pj_getopt_option long_options[] = {	{ "count",	    1, 0, 'c' },	{ "duration",	    1, 0, 'd' },	{ "auto-quit",	    0, 0, 'q' },	{ "local-port",	    1, 0, 'p' },	{ "rtp-port",	    1, 0, 'r' },	{ "ip-addr",	    1, 0, 'i' },	{ "log-level",	    1, 0, 'l' },	{ "app-log-level",  1, 0, OPT_APP_LOG_LEVEL },	{ "log-file",	    1, 0, OPT_LOG_FILE },	{ "report-file",    1, 0, OPT_REPORT_FILE },	/* Don't support this anymore, see comments in USAGE above.	{ "a-pt",	    1, 0, OPT_A_PT },	{ "a-name",	    1, 0, OPT_A_NAME },	{ "a-clock",	    1, 0, OPT_A_CLOCK },	{ "a-bitrate",	    1, 0, OPT_A_BITRATE },	{ "a-ptime",	    1, 0, OPT_A_PTIME },	*/	{ NULL, 0, 0, 0 },    };    int c;    int option_index;    /* Get local IP address for the default IP address */    {	const pj_str_t *hostname;	pj_sockaddr_in tmp_addr;	char *addr;	hostname = pj_gethostname();	pj_sockaddr_in_init(&tmp_addr, hostname, 0);	addr = pj_inet_ntoa(tmp_addr.sin_addr);	pj_ansi_strcpy(ip_addr, addr);    }    /* Init defaults */    app.max_calls = 1;    app.thread_count = 1;    app.sip_port = 5060;    app.rtp_start_port = RTP_START_PORT;    app.local_addr = pj_str(ip_addr);    app.log_level = 5;    app.app_log_level = 3;    app.log_filename = NULL;    /* Default codecs: */    app.audio_codec = audio_codecs[0];    /* Parse options */    pj_optind = 0;    while((c=pj_getopt_long(argc,argv, "c:d:p:r:i:l:q", 			    long_options, &option_index))!=-1)     {	switch (c) {	case 'c':	    app.max_calls = atoi(pj_optarg);	    if (app.max_calls < 0 || app.max_calls > MAX_CALLS) {		PJ_LOG(3,(THIS_FILE, "Invalid max calls value %s", pj_optarg));		return 1;	    }	    break;	case 'd':	    app.duration = atoi(pj_optarg);	    break;	case 'q':	    app.auto_quit = 1;	    break;	case 'p':	    app.sip_port = atoi(pj_optarg);	    break;	case 'r':	    app.rtp_start_port = atoi(pj_optarg);	    break;	case 'i':	    app.local_addr = pj_str(pj_optarg);	    break;	case 'l':	    app.log_level = atoi(pj_optarg);	    break;	case OPT_APP_LOG_LEVEL:	    app.app_log_level = atoi(pj_optarg);	    break;	case OPT_LOG_FILE:	    app.log_filename = pj_optarg;	    break;	case OPT_A_PT:	    app.audio_codec.pt = atoi(pj_optarg);	    break;	case OPT_A_NAME:	    app.audio_codec.name = pj_optarg;	    break;	case OPT_A_CLOCK:	    app.audio_codec.clock_rate = atoi(pj_optarg);	    break;	case OPT_A_BITRATE:	    app.audio_codec.bit_rate = atoi(pj_optarg);	    break;	case OPT_A_PTIME:	    app.audio_codec.ptime = atoi(pj_optarg);	    break;	case OPT_REPORT_FILE:	    app.report_filename = pj_optarg;	    break;	default:	    puts(USAGE);	    return 1;	}    }    /* Check if URL is specified */    if (pj_optind < argc)	app.uri_to_call = pj_str(argv[pj_optind]);    /* Build local URI and contact */    pj_ansi_sprintf( local_uri, "sip:%s:%d", app.local_addr.ptr, app.sip_port);    app.local_uri = pj_str(local_uri);    app.local_contact = app.local_uri;    return PJ_SUCCESS;}/***************************************************************************** * MEDIA STUFFS *//* * Create SDP session for a call. */static pj_status_t create_sdp( pj_pool_t *pool,			       struct call *call,			       pjmedia_sdp_session **p_sdp){    pj_time_val tv;    pjmedia_sdp_session *sdp;    pjmedia_sdp_media *m;    pjmedia_sdp_attr *attr;    pjmedia_transport_udp_info tpinfo;    struct media_stream *audio = &call->media[0];    PJ_ASSERT_RETURN(pool && p_sdp, PJ_EINVAL);    /* Get transport info */    pjmedia_transport_udp_get_info(audio->transport, &tpinfo);    /* Create and initialize basic SDP session */    sdp = pj_pool_zalloc (pool, sizeof(pjmedia_sdp_session));    pj_gettimeofday(&tv);    sdp->origin.user = pj_str("pjsip-siprtp");    sdp->origin.version = sdp->origin.id = tv.sec + 2208988800UL;    sdp->origin.net_type = pj_str("IN");    sdp->origin.addr_type = pj_str("IP4");    sdp->origin.addr = *pj_gethostname();    sdp->name = pj_str("pjsip");    /* Since we only support one media stream at present, put the     * SDP connection line in the session level.     */    sdp->conn = pj_pool_zalloc (pool, sizeof(pjmedia_sdp_conn));    sdp->conn->net_type = pj_str("IN");    sdp->conn->addr_type = pj_str("IP4");    sdp->conn->addr = app.local_addr;    /* SDP time and attributes. */    sdp->time.start = sdp->time.stop = 0;    sdp->attr_count = 0;    /* Create media stream 0: */    sdp->media_count = 1;    m = pj_pool_zalloc (pool, sizeof(pjmedia_sdp_media));    sdp->media[0] = m;    /* Standard media info: */    m->desc.media = pj_str("audio");    m->desc.port = pj_ntohs(tpinfo.skinfo.rtp_addr_name.sin_port);    m->desc.port_count = 1;    m->desc.transport = pj_str("RTP/AVP");    /* Add format and rtpmap for each codec. */    m->desc.fmt_count = 1;    m->attr_count = 0;    {	pjmedia_sdp_rtpmap rtpmap;	pjmedia_sdp_attr *attr;	char ptstr[10];	sprintf(ptstr, "%d", app.audio_codec.pt);	pj_strdup2(pool, &m->desc.fmt[0], ptstr);	rtpmap.pt = m->desc.fmt[0];	rtpmap.clock_rate = app.audio_codec.clock_rate;	rtpmap.enc_name = pj_str(app.audio_codec.name);	rtpmap.param.slen = 0;	pjmedia_sdp_rtpmap_to_attr(pool, &rtpmap, &attr);	m->attr[m->attr_count++] = attr;    }    /* Add sendrecv attribute. */    attr = pj_pool_zalloc(pool, sizeof(pjmedia_sdp_attr));    attr->name = pj_str("sendrecv");    m->attr[m->attr_count++] = attr;#if 1    /*     * Add support telephony event     */    m->desc.fmt[m->desc.fmt_count++] = pj_str("121");    /* Add rtpmap. */    attr = pj_pool_zalloc(pool, sizeof(pjmedia_sdp_attr));    attr->name = pj_str("rtpmap");    attr->value = pj_str("121 telephone-event/8000");    m->attr[m->attr_count++] = attr;    /* Add fmtp */    attr = pj_pool_zalloc(pool, sizeof(pjmedia_sdp_attr));    attr->name = pj_str("fmtp");    attr->value = pj_str("121 0-15");    m->attr[m->attr_count++] = attr;#endif    /* Done */    *p_sdp = sdp;    return PJ_SUCCESS;}

⌨️ 快捷键说明

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