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

📄 siprtp.c

📁 基于sip协议的网络电话源码
💻 C
📖 第 1 页 / 共 4 页
字号:
/* $Id: siprtp.c 974 2007-02-19 01:13:53Z bennylp $ *//*  * Copyright (C) 2003-2007 Benny Prijono <benny@prijono.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA  *//* Usage */static const char *USAGE = " PURPOSE:								    \n""   This program establishes SIP INVITE session and media, and calculate    \n""   the media quality (packet lost, jitter, rtt, etc.). Unlike normal	    \n""   pjmedia applications, this program bypasses all pjmedia stream	    \n""   framework and transmit encoded RTP packets manually using own thread.   \n""\n"" USAGE:\n""   siprtp [options]        => to start in server mode\n""   siprtp [options] URL    => to start in client mode\n""\n"" Program options:\n""   --count=N,        -c    Set number of calls to create (default:1) \n""   --duration=SEC,   -d    Set maximum call duration (default:unlimited) \n""   --auto-quit,      -q    Quit when calls have been completed (default:no)\n""\n"" Address and ports options:\n""   --local-port=PORT,-p    Set local SIP port (default: 5060)\n""   --rtp-port=PORT,  -r    Set start of RTP port (default: 4000)\n""   --ip-addr=IP,     -i    Set local IP address to use (otherwise it will\n""                           try to determine local IP address from hostname)\n""\n"" Logging Options:\n""   --log-level=N,    -l    Set log verbosity level (default=5)\n""   --app-log-level=N       Set app screen log verbosity (default=3)\n""   --log-file=FILE         Write log to file FILE\n""   --report-file=FILE      Write report to file FILE\n""\n"/* Don't support this anymore, because codec is properly examined in   pjmedia_session_info_from_sdp() function." Codec Options:\n""   --a-pt=PT               Set audio payload type to PT (default=0)\n""   --a-name=NAME           Set audio codec name to NAME (default=pcmu)\n""   --a-clock=RATE          Set audio codec rate to RATE Hz (default=8000Hz)\n""   --a-bitrate=BPS         Set audio codec bitrate to BPS (default=64000bps)\n""   --a-ptime=MS            Set audio frame time to MS msec (default=20ms)\n"*/;/* Include all headers. */#include <pjsip.h>#include <pjmedia.h>#include <pjmedia-codec.h>#include <pjsip_ua.h>#include <pjsip_simple.h>#include <pjlib-util.h>#include <pjlib.h>#include <stdlib.h>#if PJ_HAS_HIGH_RES_TIMER==0#   error "High resolution timer is needed for this sample"#endif#define THIS_FILE	"siprtp.c"#define MAX_CALLS	1024#define RTP_START_PORT	4000/* Codec descriptor: */struct codec{    unsigned	pt;    char*	name;    unsigned	clock_rate;    unsigned	bit_rate;    unsigned	ptime;    char*	description;};/* A bidirectional media stream created when the call is active. */struct media_stream{    /* Static: */    unsigned		 call_index;	    /* Call owner.		*/    unsigned		 media_index;	    /* Media index in call.	*/    pjmedia_transport   *transport;	    /* To send/recv RTP/RTCP	*/    /* Active? */    pj_bool_t		 active;	    /* Non-zero if is in call.	*/    /* Current stream info: */    pjmedia_stream_info	 si;		    /* Current stream info.	*/    /* More info: */    unsigned		 clock_rate;	    /* clock rate		*/    unsigned		 samples_per_frame; /* samples per frame	*/    unsigned		 bytes_per_frame;   /* frame size.		*/    /* RTP session: */    pjmedia_rtp_session	 out_sess;	    /* outgoing RTP session	*/    pjmedia_rtp_session	 in_sess;	    /* incoming RTP session	*/    /* RTCP stats: */    pjmedia_rtcp_session rtcp;		    /* incoming RTCP session.	*/    /* Thread: */    pj_bool_t		 thread_quit_flag;  /* Stop media thread.	*/    pj_thread_t		*thread;	    /* Media thread.		*/};/* This is a call structure that is created when the application starts * and only destroyed when the application quits. */struct call{    unsigned		 index;    pjsip_inv_session	*inv;    unsigned		 media_count;    struct media_stream	 media[1];    pj_time_val		 start_time;    pj_time_val		 response_time;    pj_time_val		 connect_time;    pj_timer_entry	 d_timer;	    /**< Disconnect timer.	*/};/* Application's global variables */static struct app{    unsigned		 max_calls;    unsigned		 uac_calls;    unsigned		 duration;    pj_bool_t		 auto_quit;    unsigned		 thread_count;    int			 sip_port;    int			 rtp_start_port;    pj_str_t		 local_addr;    pj_str_t		 local_uri;    pj_str_t		 local_contact;        int			 app_log_level;    int			 log_level;    char		*log_filename;    char		*report_filename;    struct codec	 audio_codec;    pj_str_t		 uri_to_call;    pj_caching_pool	 cp;    pj_pool_t		*pool;    pjsip_endpoint	*sip_endpt;    pj_bool_t		 thread_quit;    pj_thread_t		*sip_thread[1];    pjmedia_endpt	*med_endpt;    struct call		 call[MAX_CALLS];} app;/* * Prototypes: *//* Callback to be called when SDP negotiation is done in the call: */static void call_on_media_update( pjsip_inv_session *inv,				  pj_status_t status);/* Callback to be called when invite session's state has changed: */static void call_on_state_changed( pjsip_inv_session *inv, 				   pjsip_event *e);/* Callback to be called when dialog has forked: */static void call_on_forked(pjsip_inv_session *inv, pjsip_event *e);/* Callback to be called to handle incoming requests outside dialogs: */static pj_bool_t on_rx_request( pjsip_rx_data *rdata );/* Worker thread prototype */static int sip_worker_thread(void *arg);/* Create SDP for call */static pj_status_t create_sdp( pj_pool_t *pool,			       struct call *call,			       pjmedia_sdp_session **p_sdp);/* Hangup call */static void hangup_call(unsigned index);/* Destroy the call's media */static void destroy_call_media(unsigned call_index);/* Destroy media. */static void destroy_media();/* This callback is called by media transport on receipt of RTP packet. */static void on_rx_rtp(void *user_data, const void *pkt, pj_ssize_t size);/* This callback is called by media transport on receipt of RTCP packet. */static void on_rx_rtcp(void *user_data, const void *pkt, pj_ssize_t size);/* Display error */static void app_perror(const char *sender, const char *title, 		       pj_status_t status);/* Print call */static void print_call(int call_index);/* This is a PJSIP module to be registered by application to handle * incoming requests outside any dialogs/transactions. The main purpose * here is to handle incoming INVITE request message, where we will * create a dialog and INVITE session for it. */static pjsip_module mod_siprtp ={    NULL, NULL,			    /* prev, next.		*/    { "mod-siprtpapp", 13 },	    /* Name.			*/    -1,				    /* Id			*/    PJSIP_MOD_PRIORITY_APPLICATION, /* Priority			*/    NULL,			    /* load()			*/    NULL,			    /* start()			*/    NULL,			    /* stop()			*/    NULL,			    /* unload()			*/    &on_rx_request,		    /* on_rx_request()		*/    NULL,			    /* on_rx_response()		*/    NULL,			    /* on_tx_request.		*/    NULL,			    /* on_tx_response()		*/    NULL,			    /* on_tsx_state()		*/};/* Codec constants */struct codec audio_codecs[] = {    { 0,  "PCMU", 8000, 64000, 20, "G.711 ULaw" },    { 3,  "GSM",  8000, 13200, 20, "GSM" },    { 4,  "G723", 8000, 6400,  30, "G.723.1" },    { 8,  "PCMA", 8000, 64000, 20, "G.711 ALaw" },    { 18, "G729", 8000, 8000,  20, "G.729" },};/* * Init SIP stack */static pj_status_t init_sip(){    unsigned i;    pj_status_t status;    /* init PJLIB-UTIL: */    status = pjlib_util_init();    PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);    /* Must create a pool factory before we can allocate any memory. */    pj_caching_pool_init(&app.cp, &pj_pool_factory_default_policy, 0);    /* Create application pool for misc. */    app.pool = pj_pool_create(&app.cp.factory, "app", 1000, 1000, NULL);    /* Create the endpoint: */    status = pjsip_endpt_create(&app.cp.factory, pj_gethostname()->ptr, 				&app.sip_endpt);    PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);    /* Add UDP transport. */    {	pj_sockaddr_in addr;	pjsip_host_port addrname;	pjsip_transport *tp;	pj_bzero(&addr, sizeof(addr));	addr.sin_family = PJ_AF_INET;	addr.sin_addr.s_addr = 0;	addr.sin_port = pj_htons((pj_uint16_t)app.sip_port);	if (app.local_addr.slen) {	    addrname.host = app.local_addr;	    addrname.port = app.sip_port;	    status = pj_sockaddr_in_init(&addr, &app.local_addr, 					 (pj_uint16_t)app.sip_port);	    if (status != PJ_SUCCESS) {		app_perror(THIS_FILE, "Unable to resolve IP interface", status);		return status;	    }	}	status = pjsip_udp_transport_start( app.sip_endpt, &addr, 					    (app.local_addr.slen ? &addrname:NULL),					    1, &tp);	if (status != PJ_SUCCESS) {	    app_perror(THIS_FILE, "Unable to start UDP transport", status);	    return status;	}	PJ_LOG(3,(THIS_FILE, "SIP UDP listening on %.*s:%d",		  (int)tp->local_name.host.slen, tp->local_name.host.ptr,		  tp->local_name.port));    }    /*      * Init transaction layer.     * This will create/initialize transaction hash tables etc.     */    status = pjsip_tsx_layer_init_module(app.sip_endpt);    PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);    /*  Initialize UA layer. */    status = pjsip_ua_init_module( app.sip_endpt, NULL );    PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);    /*  Init invite session module. */    {	pjsip_inv_callback inv_cb;	/* Init the callback for INVITE session: */	pj_bzero(&inv_cb, sizeof(inv_cb));	inv_cb.on_state_changed = &call_on_state_changed;	inv_cb.on_new_session = &call_on_forked;	inv_cb.on_media_update = &call_on_media_update;	/* Initialize invite session module:  */	status = pjsip_inv_usage_init(app.sip_endpt, &inv_cb);	PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);    }    /* Register our module to receive incoming requests. */    status = pjsip_endpt_register_module( app.sip_endpt, &mod_siprtp);    PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);    /* Init calls */    for (i=0; i<app.max_calls; ++i)	app.call[i].index = i;    /* Done */    return PJ_SUCCESS;}/* * Destroy SIP */static void destroy_sip(){    unsigned i;    app.thread_quit = 1;    for (i=0; i<app.thread_count; ++i) {	if (app.sip_thread[i]) {	    pj_thread_join(app.sip_thread[i]);	    pj_thread_destroy(app.sip_thread[i]);	    app.sip_thread[i] = NULL;	}    }    if (app.sip_endpt) {	pjsip_endpt_destroy(app.sip_endpt);	app.sip_endpt = NULL;    }}/* * Init media stack. */static pj_status_t init_media(){    unsigned	i, count;    pj_uint16_t	rtp_port;    pj_status_t	status;    /* Initialize media endpoint so that at least error subsystem is properly     * initialized.     */    status = pjmedia_endpt_create(&app.cp.factory, NULL, 1, &app.med_endpt);    PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);    /* Must register codecs to be supported */#if defined(PJMEDIA_HAS_G711_CODEC) && PJMEDIA_HAS_G711_CODEC!=0    pjmedia_codec_g711_init(app.med_endpt);#endif    /* RTP port counter */    rtp_port = (pj_uint16_t)(app.rtp_start_port & 0xFFFE);    /* Init media transport for all calls. */    for (i=0, count=0; i<app.max_calls; ++i, ++count) {	unsigned j;	/* Create transport for each media in the call */	for (j=0; j<PJ_ARRAY_SIZE(app.call[0].media); ++j) {	    /* Repeat binding media socket to next port when fails to bind	     * to current port number.	     */	    int retry;	    app.call[i].media[j].call_index = i;	    app.call[i].media[j].media_index = j;	    status = -1;	    for (retry=0; retry<100; ++retry,rtp_port+=2)  {		struct media_stream *m = &app.call[i].media[j];				status = pjmedia_transport_udp_create2(app.med_endpt, 						       "siprtp",						       &app.local_addr,						       rtp_port, 0, 						       &m->transport);		if (status == PJ_SUCCESS) {		    rtp_port += 2;		    break;		}	    }	}	if (status != PJ_SUCCESS)	    goto on_error;    }    /* Done */    return PJ_SUCCESS;on_error:    destroy_media();    return status;}/* * Destroy media. */static void destroy_media(){    unsigned i;    for (i=0; i<app.max_calls; ++i) {	unsigned j;	for (j=0; j<PJ_ARRAY_SIZE(app.call[0].media); ++j) {	    struct media_stream *m = &app.call[i].media[j];	    if (m->transport) {		pjmedia_transport_close(m->transport);		m->transport = NULL;	    }	}    }    if (app.med_endpt) {	pjmedia_endpt_destroy(app.med_endpt);	app.med_endpt = NULL;    }}/* * Make outgoing call. */static pj_status_t make_call(const pj_str_t *dst_uri){    unsigned i;    struct call *call;    pjsip_dialog *dlg;    pjmedia_sdp_session *sdp;    pjsip_tx_data *tdata;    pj_status_t status;    /* Find unused call slot */    for (i=0; i<app.max_calls; ++i) {	if (app.call[i].inv == NULL)	    break;    }    if (i == app.max_calls)	return PJ_ETOOMANY;    call = &app.call[i];    /* Create UAC dialog */    status = pjsip_dlg_create_uac( pjsip_ua_instance(), 				   &app.local_uri,	/* local URI	    */				   &app.local_contact,	/* local Contact    */				   dst_uri,		/* remote URI	    */				   dst_uri,		/* remote target    */				   &dlg);		/* dialog	    */    if (status != PJ_SUCCESS) {	++app.uac_calls;	return status;    }    /* Create SDP */    create_sdp( dlg->pool, call, &sdp);    /* Create the INVITE session. */    status = pjsip_inv_create_uac( dlg, sdp, 0, &call->inv);    if (status != PJ_SUCCESS) {	pjsip_dlg_terminate(dlg);	++app.uac_calls;	return status;    }

⌨️ 快捷键说明

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