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

📄 pjsua_app.c

📁 基于sip协议的网络电话源码
💻 C
📖 第 1 页 / 共 5 页
字号:
/* $Id: pjsua_app.c 1271 2007-05-14 16:37:47Z 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  */#include <pjsua-lib/pjsua.h>#define THIS_FILE	"pjsua.c"#define NO_LIMIT	(int)0x7FFFFFFF//#define STEREO_DEMO/* Call specific data */struct call_data{    pj_timer_entry	    timer;};/* Pjsua application data */static struct app_config{    pjsua_config	    cfg;    pjsua_logging_config    log_cfg;    pjsua_media_config	    media_cfg;    pj_bool_t		    no_refersub;    pj_bool_t		    no_tcp;    pj_bool_t		    no_udp;    pj_bool_t		    use_tls;    pjsua_transport_config  udp_cfg;    pjsua_transport_config  rtp_cfg;    unsigned		    acc_cnt;    pjsua_acc_config	    acc_cfg[PJSUA_MAX_ACC];    unsigned		    buddy_cnt;    pjsua_buddy_config	    buddy_cfg[PJSUA_MAX_BUDDIES];    struct call_data	    call_data[PJSUA_MAX_CALLS];    pj_pool_t		   *pool;    /* Compatibility with older pjsua */    unsigned		    codec_cnt;    pj_str_t		    codec_arg[32];    pj_bool_t		    null_audio;    unsigned		    wav_count;    pj_str_t		    wav_files[32];    unsigned		    tone_count;    pjmedia_tone_desc	    tones[32];    pjsua_conf_port_id	    tone_slots[32];    pjsua_player_id	    wav_id;    pjsua_conf_port_id	    wav_port;    pj_bool_t		    auto_play;    pj_bool_t		    auto_loop;    pj_bool_t		    auto_conf;    pj_str_t		    rec_file;    pj_bool_t		    auto_rec;    pjsua_recorder_id	    rec_id;    pjsua_conf_port_id	    rec_port;    unsigned		    ptime;    unsigned		    auto_answer;    unsigned		    duration;#ifdef STEREO_DEMO    pjmedia_snd_port	   *snd;#endif    float		    mic_level,			    speaker_level;    int			    capture_dev, playback_dev;} app_config;//static pjsua_acc_id	current_acc;#define current_acc	pjsua_acc_get_default()static pjsua_call_id	current_call = PJSUA_INVALID_ID;static pj_str_t		uri_arg;#ifdef STEREO_DEMOstatic void stereo_demo();#endifpj_status_t app_destroy(void);/***************************************************************************** * Configuration manipulation *//* Show usage */static void usage(void){    puts  ("Usage:");    puts  ("  pjsua [options] [SIP URL to call]");    puts  ("");    puts  ("General options:");    puts  ("  --config-file=file  Read the config/arguments from file.");    puts  ("  --help              Display this help screen");    puts  ("  --version           Display version info");    puts  ("");    puts  ("Logging options:");    puts  ("  --log-file=fname    Log to filename (default stderr)");    puts  ("  --log-level=N       Set log max level to N (0(none) to 6(trace)) (default=5)");    puts  ("  --app-log-level=N   Set log max level for stdout display (default=4)");    puts  ("");    puts  ("SIP Account options:");    puts  ("  --registrar=url     Set the URL of registrar server");    puts  ("  --id=url            Set the URL of local ID (used in From header)");    puts  ("  --contact=url       Optionally override the Contact information");    puts  ("  --proxy=url         Optional URL of proxy server to visit");    puts  ("                      May be specified multiple times");    puts  ("  --reg-timeout=SEC   Optional registration interval (default 55)");    puts  ("  --realm=string      Set realm");    puts  ("  --username=string   Set authentication username");    puts  ("  --password=string   Set authentication password");    puts  ("  --publish           Send presence PUBLISH for this account");    puts  ("  --next-cred         Add another credentials");    puts  ("");    puts  ("SIP Account Control:");    puts  ("  --next-account      Add more account");    puts  ("");    puts  ("Transport Options:");    puts  ("  --local-port=port   Set TCP/UDP port. This implicitly enables both ");    puts  ("                      TCP and UDP transports on the specified port, unless");    puts  ("                      if TCP or UDP is disabled.");    puts  ("  --ip-addr=IP        Use the specifed address as SIP and RTP addresses.");    puts  ("                      (Hint: the IP may be the public IP of the NAT/router)");    puts  ("  --no-tcp            Disable TCP transport.");    puts  ("  --no-udp            Disable UDP transport.");    puts  ("  --nameserver=NS     Add the specified nameserver to enable SRV resolution");    puts  ("                      This option can be specified multiple times.");    puts  ("  --outbound=url      Set the URL of global outbound proxy server");    puts  ("                      May be specified multiple times");    puts  ("  --use-stun1=FORMAT  where FORMAT=host[:port]");    puts  ("  --use-stun2=FORMAT  Resolve local IP with the specified STUN servers");    puts  ("");    puts  ("TLS Options:");    puts  ("  --use-tls           Enable TLS transport (default=no)");    puts  ("  --tls-ca-file       Specify TLS CA file (default=none)");    puts  ("  --tls-cert-file     Specify TLS certificate file (default=none)");    puts  ("  --tls-privkey-file  Specify TLS private key file (default=none)");    puts  ("  --tls-password      Specify TLS password to private key file (default=none)");    puts  ("  --tls-verify-server Verify server's certificate (default=no)");    puts  ("  --tls-verify-client Verify client's certificate (default=no)");    puts  ("  --tls-neg-timeout   Specify TLS negotiation timeout (default=no)");    puts  ("");    puts  ("Media Options:");    puts  ("  --add-codec=name    Manually add codec (default is to enable all)");    puts  ("  --clock-rate=N      Override sound device clock rate");    puts  ("  --null-audio        Use NULL audio device");    puts  ("  --play-file=file    Register WAV file in conference bridge.");    puts  ("                      This can be specified multiple times.");    puts  ("  --play-tone=FORMAT  Register tone to the conference bridge.");    puts  ("                      FORMAT is 'F1,F2,ON,OFF', where F1,F2 are");    puts  ("                      frequencies, and ON,OFF=on/off duration in msec.");    puts  ("                      This can be specified multiple times.");    puts  ("  --auto-play         Automatically play the file (to incoming calls only)");    puts  ("  --auto-loop         Automatically loop incoming RTP to outgoing RTP");    puts  ("  --auto-conf         Automatically put calls in conference with others");    puts  ("  --rec-file=file     Open file recorder (extension can be .wav or .mp3");    puts  ("  --auto-rec          Automatically record conversation");    puts  ("  --rtp-port=N        Base port to try for RTP (default=4000)");    puts  ("  --quality=N         Specify media quality (0-10, default=6)");    puts  ("  --ptime=MSEC        Override codec ptime to MSEC (default=specific)");    puts  ("  --no-vad            Disable VAD/silence detector (default=vad enabled)");    puts  ("  --ec-tail=MSEC      Set echo canceller tail length (default=256)");    puts  ("  --ilbc-mode=MODE    Set iLBC codec mode (20 or 30, default is 20)");    puts  ("  --rx-drop-pct=PCT   Drop PCT percent of RX RTP (for pkt lost sim, default: 0)");    puts  ("  --tx-drop-pct=PCT   Drop PCT percent of TX RTP (for pkt lost sim, default: 0)");    puts  ("  --capture-dev=id    Audio capture device ID (default=-1)");    puts  ("  --playback-dev=id   Audio playback device ID (default=-1)");    puts  ("");    puts  ("Buddy List (can be more than one):");    puts  ("  --add-buddy url     Add the specified URL to the buddy list.");    puts  ("");    puts  ("User Agent options:");    puts  ("  --auto-answer=code  Automatically answer incoming calls with code (e.g. 200)");    puts  ("  --max-calls=N       Maximum number of concurrent calls (default:4, max:255)");    puts  ("  --thread-cnt=N      Number of worker threads (default:1)");    puts  ("  --duration=SEC      Set maximum call duration (default:no limit)");    puts  ("  --norefersub        Suppress event subscription when transfering calls");    puts  ("");    puts  ("When URL is specified, pjsua will immediately initiate call to that URL");    puts  ("");    fflush(stdout);}/* Set default config. */static void default_config(struct app_config *cfg){    char tmp[80];    unsigned i;    pjsua_config_default(&cfg->cfg);    pj_ansi_sprintf(tmp, "PJSUA v%s/%s", PJ_VERSION, PJ_OS_NAME);    pj_strdup2_with_null(app_config.pool, &cfg->cfg.user_agent, tmp);    pjsua_logging_config_default(&cfg->log_cfg);    pjsua_media_config_default(&cfg->media_cfg);    pjsua_transport_config_default(&cfg->udp_cfg);    cfg->udp_cfg.port = 5060;    pjsua_transport_config_default(&cfg->rtp_cfg);    cfg->rtp_cfg.port = 4000;    cfg->duration = NO_LIMIT;    cfg->wav_id = PJSUA_INVALID_ID;    cfg->rec_id = PJSUA_INVALID_ID;    cfg->wav_port = PJSUA_INVALID_ID;    cfg->rec_port = PJSUA_INVALID_ID;    cfg->mic_level = cfg->speaker_level = 1.0;    cfg->capture_dev = PJSUA_INVALID_ID;    cfg->playback_dev = PJSUA_INVALID_ID;    for (i=0; i<PJ_ARRAY_SIZE(cfg->acc_cfg); ++i)	pjsua_acc_config_default(&cfg->acc_cfg[i]);    for (i=0; i<PJ_ARRAY_SIZE(cfg->buddy_cfg); ++i)	pjsua_buddy_config_default(&cfg->buddy_cfg[i]);}/* * Read command arguments from config file. */static int read_config_file(pj_pool_t *pool, const char *filename, 			    int *app_argc, char ***app_argv){    int i;    FILE *fhnd;    char line[200];    int argc = 0;    char **argv;    enum { MAX_ARGS = 64 };    /* Allocate MAX_ARGS+1 (argv needs to be terminated with NULL argument) */    argv = pj_pool_calloc(pool, MAX_ARGS+1, sizeof(char*));    argv[argc++] = *app_argv[0];    /* Open config file. */    fhnd = fopen(filename, "rt");    if (!fhnd) {	PJ_LOG(1,(THIS_FILE, "Unable to open config file %s", filename));	fflush(stdout);	return -1;    }    /* Scan tokens in the file. */    while (argc < MAX_ARGS && !feof(fhnd)) {	char *token, *p = line;	if (fgets(line, sizeof(line), fhnd) == NULL) break;	for (token = strtok(p, " \t\r\n"); argc < MAX_ARGS; 	     token = strtok(NULL, " \t\r\n"))	{	    int token_len;	    	    if (!token) break;	    if (*token == '#') break;	    token_len = strlen(token);	    if (!token_len)		continue;	    argv[argc] = pj_pool_alloc(pool, token_len+1);	    pj_memcpy(argv[argc], token, token_len+1);	    ++argc;	}    }    /* Copy arguments from command line */    for (i=1; i<*app_argc && argc < MAX_ARGS; ++i)	argv[argc++] = (*app_argv)[i];    if (argc == MAX_ARGS && (i!=*app_argc || !feof(fhnd))) {	PJ_LOG(1,(THIS_FILE, 		  "Too many arguments specified in cmd line/config file"));	fflush(stdout);	fclose(fhnd);	return -1;    }    fclose(fhnd);    /* Assign the new command line back to the original command line. */    *app_argc = argc;    *app_argv = argv;    return 0;}static int my_atoi(const char *cs){    pj_str_t s;    return pj_strtoul(pj_cstr(&s, cs));}/* Parse arguments. */static pj_status_t parse_args(int argc, char *argv[],			      struct app_config *cfg,			      pj_str_t *uri_to_call){    int c;    int option_index;    enum { OPT_CONFIG_FILE=127, OPT_LOG_FILE, OPT_LOG_LEVEL, OPT_APP_LOG_LEVEL, 	   OPT_HELP, OPT_VERSION, OPT_NULL_AUDIO, 	   OPT_LOCAL_PORT, OPT_IP_ADDR, OPT_PROXY, OPT_OUTBOUND_PROXY, 	   OPT_REGISTRAR, OPT_REG_TIMEOUT, OPT_PUBLISH, OPT_ID, OPT_CONTACT,	   OPT_REALM, OPT_USERNAME, OPT_PASSWORD,	   OPT_NAMESERVER, OPT_USE_STUN1, OPT_USE_STUN2, 	   OPT_ADD_BUDDY, OPT_OFFER_X_MS_MSG, OPT_NO_PRESENCE,	   OPT_AUTO_ANSWER, OPT_AUTO_HANGUP, OPT_AUTO_PLAY, OPT_AUTO_LOOP,	   OPT_AUTO_CONF, OPT_CLOCK_RATE,	   OPT_PLAY_FILE, OPT_PLAY_TONE, OPT_RTP_PORT, OPT_ADD_CODEC, 	   OPT_ILBC_MODE, OPT_REC_FILE, OPT_AUTO_REC,	   OPT_COMPLEXITY, OPT_QUALITY, OPT_PTIME, OPT_NO_VAD,	   OPT_RX_DROP_PCT, OPT_TX_DROP_PCT, OPT_EC_TAIL,	   OPT_NEXT_ACCOUNT, OPT_NEXT_CRED, OPT_MAX_CALLS, 	   OPT_DURATION, OPT_NO_TCP, OPT_NO_UDP, OPT_THREAD_CNT,	   OPT_NOREFERSUB,	   OPT_USE_TLS, OPT_TLS_CA_FILE, OPT_TLS_CERT_FILE, OPT_TLS_PRIV_FILE,	   OPT_TLS_PASSWORD, OPT_TLS_VERIFY_SERVER, OPT_TLS_VERIFY_CLIENT,	   OPT_TLS_NEG_TIMEOUT,	   OPT_CAPTURE_DEV, OPT_PLAYBACK_DEV,    };    struct pj_getopt_option long_options[] = {	{ "config-file",1, 0, OPT_CONFIG_FILE},	{ "log-file",	1, 0, OPT_LOG_FILE},	{ "log-level",	1, 0, OPT_LOG_LEVEL},	{ "app-log-level",1,0,OPT_APP_LOG_LEVEL},	{ "help",	0, 0, OPT_HELP},	{ "version",	0, 0, OPT_VERSION},	{ "clock-rate",	1, 0, OPT_CLOCK_RATE},	{ "null-audio", 0, 0, OPT_NULL_AUDIO},	{ "local-port", 1, 0, OPT_LOCAL_PORT},	{ "ip-addr",	1, 0, OPT_IP_ADDR},	{ "no-tcp",     0, 0, OPT_NO_TCP},	{ "no-udp",     0, 0, OPT_NO_UDP},	{ "norefersub", 0, 0, OPT_NOREFERSUB},	{ "proxy",	1, 0, OPT_PROXY},	{ "outbound",	1, 0, OPT_OUTBOUND_PROXY},	{ "registrar",	1, 0, OPT_REGISTRAR},	{ "reg-timeout",1, 0, OPT_REG_TIMEOUT},	{ "publish",    0, 0, OPT_PUBLISH},	{ "id",		1, 0, OPT_ID},	{ "contact",	1, 0, OPT_CONTACT},	{ "realm",	1, 0, OPT_REALM},	{ "username",	1, 0, OPT_USERNAME},	{ "password",	1, 0, OPT_PASSWORD},	{ "nameserver", 1, 0, OPT_NAMESERVER},	{ "use-stun1",  1, 0, OPT_USE_STUN1},	{ "use-stun2",  1, 0, OPT_USE_STUN2},	{ "add-buddy",  1, 0, OPT_ADD_BUDDY},	{ "offer-x-ms-msg",0,0,OPT_OFFER_X_MS_MSG},	{ "no-presence", 0, 0, OPT_NO_PRESENCE},	{ "auto-answer",1, 0, OPT_AUTO_ANSWER},	{ "auto-hangup",1, 0, OPT_AUTO_HANGUP},	{ "auto-play",  0, 0, OPT_AUTO_PLAY},	{ "auto-rec",   0, 0, OPT_AUTO_REC},	{ "auto-loop",  0, 0, OPT_AUTO_LOOP},	{ "auto-conf",  0, 0, OPT_AUTO_CONF},	{ "play-file",  1, 0, OPT_PLAY_FILE},	{ "play-tone",  1, 0, OPT_PLAY_TONE},	{ "rec-file",   1, 0, OPT_REC_FILE},	{ "rtp-port",	1, 0, OPT_RTP_PORT},	{ "add-codec",  1, 0, OPT_ADD_CODEC},	{ "complexity",	1, 0, OPT_COMPLEXITY},	{ "quality",	1, 0, OPT_QUALITY},	{ "ptime",      1, 0, OPT_PTIME},	{ "no-vad",     0, 0, OPT_NO_VAD},	{ "ec-tail",    1, 0, OPT_EC_TAIL},	{ "ilbc-mode",	1, 0, OPT_ILBC_MODE},	{ "rx-drop-pct",1, 0, OPT_RX_DROP_PCT},	{ "tx-drop-pct",1, 0, OPT_TX_DROP_PCT},	{ "next-account",0,0, OPT_NEXT_ACCOUNT},	{ "next-cred",	0, 0, OPT_NEXT_CRED},	{ "max-calls",	1, 0, OPT_MAX_CALLS},	{ "duration",	1, 0, OPT_DURATION},	{ "thread-cnt",	1, 0, OPT_THREAD_CNT},	{ "use-tls",	0, 0, OPT_USE_TLS}, 	{ "tls-ca-file",1, 0, OPT_TLS_CA_FILE},	{ "tls-cert-file",1,0, OPT_TLS_CERT_FILE}, 	{ "tls-privkey-file",1,0, OPT_TLS_PRIV_FILE},	{ "tls-password",1,0, OPT_TLS_PASSWORD},	{ "tls-verify-server", 0, 0, OPT_TLS_VERIFY_SERVER},	{ "tls-verify-client", 0, 0, OPT_TLS_VERIFY_CLIENT},	{ "tls-neg-timeout", 1, 0, OPT_TLS_NEG_TIMEOUT},	{ "capture-dev",    1, 0, OPT_CAPTURE_DEV},	{ "playback-dev",   1, 0, OPT_PLAYBACK_DEV},	{ NULL, 0, 0, 0}    };    pj_status_t status;    pjsua_acc_config *cur_acc;    char *config_file = NULL;    unsigned i;    /* Run pj_getopt once to see if user specifies config file to read. */     pj_optind = 0;    while ((c=pj_getopt_long(argc, argv, "", long_options, 			     &option_index)) != -1)     {	switch (c) {	case OPT_CONFIG_FILE:	    config_file = pj_optarg;	    break;	}	if (config_file)	    break;    }    if (config_file) {	status = read_config_file(app_config.pool, config_file, &argc, &argv);	if (status != 0)	    return status;    }    cfg->acc_cnt = 0;    cur_acc = &cfg->acc_cfg[0];    /* Reinitialize and re-run pj_getopt again, possibly with new arguments     * read from config file.     */    pj_optind = 0;    while((c=pj_getopt_long(argc,argv, "", long_options,&option_index))!=-1) {	char *p;	pj_str_t tmp;	long lval;	switch (c) {	case OPT_CONFIG_FILE:	    /* Ignore as this has been processed before */	    break;		case OPT_LOG_FILE:	    cfg->log_cfg.log_filename = pj_str(pj_optarg);	    break;	case OPT_LOG_LEVEL:	    c = pj_strtoul(pj_cstr(&tmp, pj_optarg));	    if (c < 0 || c > 6) {		PJ_LOG(1,(THIS_FILE, 			  "Error: expecting integer value 0-6 "			  "for --log-level"));		return PJ_EINVAL;	    }	    cfg->log_cfg.level = c;	    pj_log_set_level( c );	    break;	case OPT_APP_LOG_LEVEL:	    cfg->log_cfg.console_level = pj_strtoul(pj_cstr(&tmp, pj_optarg));	    if (cfg->log_cfg.console_level < 0 || cfg->log_cfg.console_level > 6) {		PJ_LOG(1,(THIS_FILE, 			  "Error: expecting integer value 0-6 "			  "for --app-log-level"));		return PJ_EINVAL;	    }	    break;	case OPT_HELP:

⌨️ 快捷键说明

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