Changeset 4461 for pjproject/trunk/pjsip-apps/src/pjsua/pjsua_app.c
- Timestamp:
- Apr 5, 2013 3:02:19 AM (12 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
pjproject/trunk/pjsip-apps/src/pjsua/pjsua_app.c
r4440 r4461 18 18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 19 */ 20 #include "pjsua_c md.h"20 #include "pjsua_common.h" 21 21 #include "gui.h" 22 22 … … 44 44 #define current_acc pjsua_acc_get_default() 45 45 46 static pj_str_t uri_arg;47 48 46 #ifdef STEREO_DEMO 49 47 static void stereo_demo(); … … 51 49 52 50 pj_status_t app_destroy(void); 51 53 52 static void ringback_start(pjsua_call_id call_id); 54 53 static void ring_start(pjsua_call_id call_id); 55 54 static void ring_stop(pjsua_call_id call_id); 56 55 57 pj_bool_t app_restart; 58 pj_log_func *log_cb = NULL; 59 static const char *stdout_refresh_text = "STDOUT_REFRESH"; 56 static pj_status_t receive_end_sig; 57 static pj_thread_t *sig_thread; 58 pj_str_t uri_arg; 59 pj_bool_t app_restart; 60 pj_bool_t app_running = PJ_FALSE; 61 pj_log_func *log_cb = NULL; 60 62 61 63 /** Forward declaration **/ 62 void console_app_main(const pj_str_t *uri_to_call, pj_bool_t *app_restart); 63 64 void cli_console_app_main(const pj_str_t *uri_to_call, pj_bool_t *app_restart); 64 /** Defined in pjsua_common.c **/ 65 65 void app_config_init_video(pjsua_acc_config *acc_cfg); 66 pj_status_t setup_cli(); 67 void destroy_cli(); 66 /** Defined in pjsua_legacy.c **/ 67 void start_ui_main(pj_str_t *uri_to_call, pj_bool_t *app_restart); 68 /** Defined in pjsua_cli.c **/ 69 void start_cli_main(pj_str_t *uri_to_call, pj_bool_t *app_restart); 70 pj_status_t setup_cli(pj_bool_t with_console, pj_bool_t with_telnet, 71 pj_uint16_t telnet_port, 72 pj_cli_telnet_on_started on_started_cb, 73 pj_cli_on_quit on_quit_cb, 74 pj_cli_on_destroy on_destroy_cb, 75 pj_cli_on_restart_pjsua on_restart_pjsua_cb); 76 void destroy_cli(pj_bool_t app_restart); 68 77 69 78 /***************************************************************************** … … 92 101 #endif 93 102 94 /* Show usage */95 static void usage(void)96 {97 puts ("Usage:");98 puts (" pjsua [options] [SIP URL to call]");99 puts ("");100 puts ("General options:");101 puts (" --config-file=file Read the config/arguments from file.");102 puts (" --help Display this help screen");103 puts (" --version Display version info");104 puts ("");105 puts ("Logging options:");106 puts (" --log-file=fname Log to filename (default stderr)");107 puts (" --log-level=N Set log max level to N (0(none) to 6(trace)) (default=5)");108 puts (" --app-log-level=N Set log max level for stdout display (default=4)");109 puts (" --log-append Append instead of overwrite existing log file.\n");110 puts (" --color Use colorful logging (default yes on Win32)");111 puts (" --no-color Disable colorful logging");112 puts (" --light-bg Use dark colors for light background (default is dark bg)");113 puts (" --no-stderr Disable stderr");114 115 puts ("");116 puts ("SIP Account options:");117 puts (" --registrar=url Set the URL of registrar server");118 puts (" --id=url Set the URL of local ID (used in From header)");119 puts (" --realm=string Set realm");120 puts (" --username=string Set authentication username");121 puts (" --password=string Set authentication password");122 puts (" --contact=url Optionally override the Contact information");123 puts (" --contact-params=S Append the specified parameters S in Contact header");124 puts (" --contact-uri-params=S Append the specified parameters S in Contact URI");125 puts (" --proxy=url Optional URL of proxy server to visit");126 puts (" May be specified multiple times");127 printf(" --reg-timeout=SEC Optional registration interval (default %d)\n",128 PJSUA_REG_INTERVAL);129 printf(" --rereg-delay=SEC Optional auto retry registration interval (default %d)\n",130 PJSUA_REG_RETRY_INTERVAL);131 puts (" --reg-use-proxy=N Control the use of proxy settings in REGISTER.");132 puts (" 0=no proxy, 1=outbound only, 2=acc only, 3=all (default)");133 puts (" --publish Send presence PUBLISH for this account");134 puts (" --mwi Subscribe to message summary/waiting indication");135 puts (" --use-ims Enable 3GPP/IMS related settings on this account");136 #if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)137 puts (" --use-srtp=N Use SRTP? 0:disabled, 1:optional, 2:mandatory,");138 puts (" 3:optional by duplicating media offer (def:0)");139 puts (" --srtp-secure=N SRTP require secure SIP? 0:no, 1:tls, 2:sips (def:1)");140 #endif141 puts (" --use-100rel Require reliable provisional response (100rel)");142 puts (" --use-timer=N Use SIP session timers? (default=1)");143 puts (" 0:inactive, 1:optional, 2:mandatory, 3:always");144 printf(" --timer-se=N Session timers expiration period, in secs (def:%d)\n",145 PJSIP_SESS_TIMER_DEF_SE);146 puts (" --timer-min-se=N Session timers minimum expiration period, in secs (def:90)");147 puts (" --outb-rid=string Set SIP outbound reg-id (default:1)");148 puts (" --auto-update-nat=N Where N is 0 or 1 to enable/disable SIP traversal behind");149 puts (" symmetric NAT (default 1)");150 puts (" --disable-stun Disable STUN for this account");151 puts (" --next-cred Add another credentials");152 puts ("");153 puts ("SIP Account Control:");154 puts (" --next-account Add more account");155 puts ("");156 puts ("Transport Options:");157 #if defined(PJ_HAS_IPV6) && PJ_HAS_IPV6158 puts (" --ipv6 Use IPv6 instead for SIP and media.");159 #endif160 puts (" --set-qos Enable QoS tagging for SIP and media.");161 puts (" --local-port=port Set TCP/UDP port. This implicitly enables both ");162 puts (" TCP and UDP transports on the specified port, unless");163 puts (" if TCP or UDP is disabled.");164 puts (" --ip-addr=IP Use the specifed address as SIP and RTP addresses.");165 puts (" (Hint: the IP may be the public IP of the NAT/router)");166 puts (" --bound-addr=IP Bind transports to this IP interface");167 puts (" --no-tcp Disable TCP transport.");168 puts (" --no-udp Disable UDP transport.");169 puts (" --nameserver=NS Add the specified nameserver to enable SRV resolution");170 puts (" This option can be specified multiple times.");171 puts (" --outbound=url Set the URL of global outbound proxy server");172 puts (" May be specified multiple times");173 puts (" --stun-srv=FORMAT Set STUN server host or domain. This option may be");174 puts (" specified more than once. FORMAT is hostdom[:PORT]");175 176 #if defined(PJSIP_HAS_TLS_TRANSPORT) && (PJSIP_HAS_TLS_TRANSPORT != 0)177 puts ("");178 puts ("TLS Options:");179 puts (" --use-tls Enable TLS transport (default=no)");180 puts (" --tls-ca-file Specify TLS CA file (default=none)");181 puts (" --tls-cert-file Specify TLS certificate file (default=none)");182 puts (" --tls-privkey-file Specify TLS private key file (default=none)");183 puts (" --tls-password Specify TLS password to private key file (default=none)");184 puts (" --tls-verify-server Verify server's certificate (default=no)");185 puts (" --tls-verify-client Verify client's certificate (default=no)");186 puts (" --tls-neg-timeout Specify TLS negotiation timeout (default=no)");187 puts (" --tls-srv-name Specify TLS server name for multihosting server");188 puts (" --tls-cipher Specify prefered TLS cipher (optional).");189 puts (" May be specified multiple times");190 #endif191 192 puts ("");193 puts ("Audio Options:");194 puts (" --add-codec=name Manually add codec (default is to enable all)");195 puts (" --dis-codec=name Disable codec (can be specified multiple times)");196 puts (" --clock-rate=N Override conference bridge clock rate");197 puts (" --snd-clock-rate=N Override sound device clock rate");198 puts (" --stereo Audio device and conference bridge opened in stereo mode");199 puts (" --null-audio Use NULL audio device");200 puts (" --play-file=file Register WAV file in conference bridge.");201 puts (" This can be specified multiple times.");202 puts (" --play-tone=FORMAT Register tone to the conference bridge.");203 puts (" FORMAT is 'F1,F2,ON,OFF', where F1,F2 are");204 puts (" frequencies, and ON,OFF=on/off duration in msec.");205 puts (" This can be specified multiple times.");206 puts (" --auto-play Automatically play the file (to incoming calls only)");207 puts (" --auto-loop Automatically loop incoming RTP to outgoing RTP");208 puts (" --auto-conf Automatically put calls in conference with others");209 puts (" --rec-file=file Open file recorder (extension can be .wav or .mp3");210 puts (" --auto-rec Automatically record conversation");211 puts (" --quality=N Specify media quality (0-10, default=6)");212 puts (" --ptime=MSEC Override codec ptime to MSEC (default=specific)");213 puts (" --no-vad Disable VAD/silence detector (default=vad enabled)");214 puts (" --ec-tail=MSEC Set echo canceller tail length (default=256)");215 puts (" --ec-opt=OPT Select echo canceller algorithm (0=default, ");216 puts (" 1=speex, 2=suppressor)");217 puts (" --ilbc-mode=MODE Set iLBC codec mode (20 or 30, default is 30)");218 puts (" --capture-dev=id Audio capture device ID (default=-1)");219 puts (" --playback-dev=id Audio playback device ID (default=-1)");220 puts (" --capture-lat=N Audio capture latency, in ms (default=100)");221 puts (" --playback-lat=N Audio playback latency, in ms (default=100)");222 puts (" --snd-auto-close=N Auto close audio device when idle for N secs (default=1)");223 puts (" Specify N=-1 to disable this feature.");224 puts (" Specify N=0 for instant close when unused.");225 puts (" --no-tones Disable audible tones");226 puts (" --jb-max-size Specify jitter buffer maximum size, in frames (default=-1)");227 puts (" --extra-audio Add one more audio stream");228 229 #if PJSUA_HAS_VIDEO230 puts ("");231 puts ("Video Options:");232 puts (" --video Enable video");233 puts (" --vcapture-dev=id Video capture device ID (default=-1)");234 puts (" --vrender-dev=id Video render device ID (default=-2)");235 puts (" --play-avi=FILE Load this AVI as virtual capture device");236 puts (" --auto-play-avi Automatically play the AVI media to call");237 #endif238 239 puts ("");240 puts ("Media Transport Options:");241 puts (" --use-ice Enable ICE (default:no)");242 puts (" --ice-regular Use ICE regular nomination (default: aggressive)");243 puts (" --ice-max-hosts=N Set maximum number of ICE host candidates");244 puts (" --ice-no-rtcp Disable RTCP component in ICE (default: no)");245 puts (" --rtp-port=N Base port to try for RTP (default=4000)");246 puts (" --rx-drop-pct=PCT Drop PCT percent of RX RTP (for pkt lost sim, default: 0)");247 puts (" --tx-drop-pct=PCT Drop PCT percent of TX RTP (for pkt lost sim, default: 0)");248 puts (" --use-turn Enable TURN relay with ICE (default:no)");249 puts (" --turn-srv Domain or host name of TURN server (\"NAME:PORT\" format)");250 puts (" --turn-tcp Use TCP connection to TURN server (default no)");251 puts (" --turn-user TURN username");252 puts (" --turn-passwd TURN password");253 254 puts ("");255 puts ("Buddy List (can be more than one):");256 puts (" --add-buddy url Add the specified URL to the buddy list.");257 puts ("");258 puts ("User Agent options:");259 puts (" --auto-answer=code Automatically answer incoming calls with code (e.g. 200)");260 puts (" --max-calls=N Maximum number of concurrent calls (default:4, max:255)");261 puts (" --thread-cnt=N Number of worker threads (default:1)");262 puts (" --duration=SEC Set maximum call duration (default:no limit)");263 puts (" --norefersub Suppress event subscription when transfering calls");264 puts (" --use-compact-form Minimize SIP message size");265 puts (" --no-force-lr Allow strict-route to be used (i.e. do not force lr)");266 puts (" --accept-redirect=N Specify how to handle call redirect (3xx) response.");267 puts (" 0: reject, 1: follow automatically,");268 puts (" 2: follow + replace To header (default), 3: ask");269 270 puts ("");271 puts ("CLI options:");272 puts (" --use-cli Use CLI as user interface");273 puts (" --cli-telnet-port=N CLI telnet port");274 puts ("");275 276 puts ("");277 puts ("When URL is specified, pjsua will immediately initiate call to that URL");278 puts ("");279 280 fflush(stdout);281 }282 283 static int stdout_refresh_proc(void *arg)284 {285 PJ_UNUSED_ARG(arg);286 287 /* Set thread to lowest priority so that it doesn't clobber288 * stdout output289 */290 pj_thread_set_prio(pj_thread_this(),291 pj_thread_get_prio_min(pj_thread_this()));292 293 while (!stdout_refresh_quit) {294 pj_thread_sleep(stdout_refresh * 1000);295 puts(stdout_refresh_text);296 fflush(stdout);297 }298 299 return 0;300 }301 302 /* Set default config. */303 static void default_config(pjsua_app_config *cfg)304 {305 char tmp[80];306 unsigned i;307 308 pjsua_config_default(&cfg->cfg);309 pj_ansi_sprintf(tmp, "PJSUA v%s %s", pj_get_version(),310 pj_get_sys_info()->info.ptr);311 pj_strdup2_with_null(app_config.pool, &cfg->cfg.user_agent, tmp);312 313 pjsua_logging_config_default(&cfg->log_cfg);314 pjsua_media_config_default(&cfg->media_cfg);315 pjsua_transport_config_default(&cfg->udp_cfg);316 cfg->udp_cfg.port = 5060;317 pjsua_transport_config_default(&cfg->rtp_cfg);318 cfg->rtp_cfg.port = 4000;319 cfg->redir_op = PJSIP_REDIRECT_ACCEPT_REPLACE;320 cfg->duration = NO_LIMIT_DURATION;321 cfg->wav_id = PJSUA_INVALID_ID;322 cfg->rec_id = PJSUA_INVALID_ID;323 cfg->wav_port = PJSUA_INVALID_ID;324 cfg->rec_port = PJSUA_INVALID_ID;325 cfg->mic_level = cfg->speaker_level = 1.0;326 cfg->capture_dev = PJSUA_INVALID_ID;327 cfg->playback_dev = PJSUA_INVALID_ID;328 cfg->capture_lat = PJMEDIA_SND_DEFAULT_REC_LATENCY;329 cfg->playback_lat = PJMEDIA_SND_DEFAULT_PLAY_LATENCY;330 cfg->ringback_slot = PJSUA_INVALID_ID;331 cfg->ring_slot = PJSUA_INVALID_ID;332 333 for (i=0; i<PJ_ARRAY_SIZE(cfg->acc_cfg); ++i)334 pjsua_acc_config_default(&cfg->acc_cfg[i]);335 336 for (i=0; i<PJ_ARRAY_SIZE(cfg->buddy_cfg); ++i)337 pjsua_buddy_config_default(&cfg->buddy_cfg[i]);338 339 cfg->vid.vcapture_dev = PJMEDIA_VID_DEFAULT_CAPTURE_DEV;340 cfg->vid.vrender_dev = PJMEDIA_VID_DEFAULT_RENDER_DEV;341 cfg->aud_cnt = 1;342 343 cfg->avi_def_idx = PJSUA_INVALID_ID;344 345 cfg->use_cli = PJ_FALSE;346 cfg->cli_telnet_port = 0;347 }348 349 /*350 * Read command arguments from config file.351 */352 static int read_config_file(pj_pool_t *pool, const char *filename,353 int *app_argc, char ***app_argv)354 {355 int i;356 FILE *fhnd;357 char line[200];358 int argc = 0;359 char **argv;360 enum { MAX_ARGS = 128 };361 362 /* Allocate MAX_ARGS+1 (argv needs to be terminated with NULL argument) */363 argv = pj_pool_calloc(pool, MAX_ARGS+1, sizeof(char*));364 argv[argc++] = *app_argv[0];365 366 /* Open config file. */367 fhnd = fopen(filename, "rt");368 if (!fhnd) {369 PJ_LOG(1,(THIS_FILE, "Unable to open config file %s", filename));370 fflush(stdout);371 return -1;372 }373 374 /* Scan tokens in the file. */375 while (argc < MAX_ARGS && !feof(fhnd)) {376 char *token;377 char *p;378 const char *whitespace = " \t\r\n";379 char cDelimiter;380 int len, token_len;381 382 pj_bzero(line, sizeof(line));383 if (fgets(line, sizeof(line), fhnd) == NULL) break;384 385 // Trim ending newlines386 len = strlen(line);387 if (line[len-1]=='\n')388 line[--len] = '\0';389 if (line[len-1]=='\r')390 line[--len] = '\0';391 392 if (len==0) continue;393 394 for (p = line; *p != '\0' && argc < MAX_ARGS; p++) {395 // first, scan whitespaces396 while (*p != '\0' && strchr(whitespace, *p) != NULL) p++;397 398 if (*p == '\0') // are we done yet?399 break;400 401 if (*p == '"' || *p == '\'') { // is token a quoted string402 cDelimiter = *p++; // save quote delimiter403 token = p;404 405 while (*p != '\0' && *p != cDelimiter) p++;406 407 if (*p == '\0') // found end of the line, but,408 cDelimiter = '\0'; // didn't find a matching quote409 410 } else { // token's not a quoted string411 token = p;412 413 while (*p != '\0' && strchr(whitespace, *p) == NULL) p++;414 415 cDelimiter = *p;416 }417 418 *p = '\0';419 token_len = p-token;420 421 if (token_len > 0) {422 if (*token == '#')423 break; // ignore remainder of line424 425 argv[argc] = pj_pool_alloc(pool, token_len + 1);426 pj_memcpy(argv[argc], token, token_len + 1);427 ++argc;428 }429 430 *p = cDelimiter;431 }432 }433 434 /* Copy arguments from command line */435 for (i=1; i<*app_argc && argc < MAX_ARGS; ++i)436 argv[argc++] = (*app_argv)[i];437 438 if (argc == MAX_ARGS && (i!=*app_argc || !feof(fhnd))) {439 PJ_LOG(1,(THIS_FILE,440 "Too many arguments specified in cmd line/config file"));441 fflush(stdout);442 fclose(fhnd);443 return -1;444 }445 446 fclose(fhnd);447 448 /* Assign the new command line back to the original command line. */449 *app_argc = argc;450 *app_argv = argv;451 return 0;452 }453 454 /* Parse arguments. */455 static pj_status_t parse_args(int argc, char *argv[],456 pjsua_app_config *cfg,457 pj_str_t *uri_to_call)458 {459 int c;460 int option_index;461 enum { OPT_CONFIG_FILE=127, OPT_LOG_FILE, OPT_LOG_LEVEL, OPT_APP_LOG_LEVEL,462 OPT_LOG_APPEND, OPT_COLOR, OPT_NO_COLOR, OPT_LIGHT_BG, OPT_NO_STDERR,463 OPT_HELP, OPT_VERSION, OPT_NULL_AUDIO, OPT_SND_AUTO_CLOSE,464 OPT_LOCAL_PORT, OPT_IP_ADDR, OPT_PROXY, OPT_OUTBOUND_PROXY,465 OPT_REGISTRAR, OPT_REG_TIMEOUT, OPT_PUBLISH, OPT_ID, OPT_CONTACT,466 OPT_BOUND_ADDR, OPT_CONTACT_PARAMS, OPT_CONTACT_URI_PARAMS,467 OPT_100REL, OPT_USE_IMS, OPT_REALM, OPT_USERNAME, OPT_PASSWORD,468 OPT_REG_RETRY_INTERVAL, OPT_REG_USE_PROXY,469 OPT_MWI, OPT_NAMESERVER, OPT_STUN_SRV, OPT_OUTB_RID,470 OPT_ADD_BUDDY, OPT_OFFER_X_MS_MSG, OPT_NO_PRESENCE,471 OPT_AUTO_ANSWER, OPT_AUTO_PLAY, OPT_AUTO_PLAY_HANGUP, OPT_AUTO_LOOP,472 OPT_AUTO_CONF, OPT_CLOCK_RATE, OPT_SND_CLOCK_RATE, OPT_STEREO,473 OPT_USE_ICE, OPT_ICE_REGULAR, OPT_USE_SRTP, OPT_SRTP_SECURE,474 OPT_USE_TURN, OPT_ICE_MAX_HOSTS, OPT_ICE_NO_RTCP, OPT_TURN_SRV,475 OPT_TURN_TCP, OPT_TURN_USER, OPT_TURN_PASSWD,476 OPT_PLAY_FILE, OPT_PLAY_TONE, OPT_RTP_PORT, OPT_ADD_CODEC,477 OPT_ILBC_MODE, OPT_REC_FILE, OPT_AUTO_REC,478 OPT_COMPLEXITY, OPT_QUALITY, OPT_PTIME, OPT_NO_VAD,479 OPT_RX_DROP_PCT, OPT_TX_DROP_PCT, OPT_EC_TAIL, OPT_EC_OPT,480 OPT_NEXT_ACCOUNT, OPT_NEXT_CRED, OPT_MAX_CALLS,481 OPT_DURATION, OPT_NO_TCP, OPT_NO_UDP, OPT_THREAD_CNT,482 OPT_NOREFERSUB, OPT_ACCEPT_REDIRECT,483 OPT_USE_TLS, OPT_TLS_CA_FILE, OPT_TLS_CERT_FILE, OPT_TLS_PRIV_FILE,484 OPT_TLS_PASSWORD, OPT_TLS_VERIFY_SERVER, OPT_TLS_VERIFY_CLIENT,485 OPT_TLS_NEG_TIMEOUT, OPT_TLS_CIPHER,486 OPT_CAPTURE_DEV, OPT_PLAYBACK_DEV,487 OPT_CAPTURE_LAT, OPT_PLAYBACK_LAT, OPT_NO_TONES, OPT_JB_MAX_SIZE,488 OPT_STDOUT_REFRESH, OPT_STDOUT_REFRESH_TEXT, OPT_IPV6, OPT_QOS,489 #ifdef _IONBF490 OPT_STDOUT_NO_BUF,491 #endif492 OPT_AUTO_UPDATE_NAT,OPT_USE_COMPACT_FORM,OPT_DIS_CODEC,493 OPT_DISABLE_STUN, OPT_NO_FORCE_LR,494 OPT_TIMER, OPT_TIMER_SE, OPT_TIMER_MIN_SE,495 OPT_VIDEO, OPT_EXTRA_AUDIO,496 OPT_VCAPTURE_DEV, OPT_VRENDER_DEV, OPT_PLAY_AVI, OPT_AUTO_PLAY_AVI,497 OPT_USE_CLI, OPT_CLI_TELNET_PORT498 };499 struct pj_getopt_option long_options[] = {500 { "config-file",1, 0, OPT_CONFIG_FILE},501 { "log-file", 1, 0, OPT_LOG_FILE},502 { "log-level", 1, 0, OPT_LOG_LEVEL},503 { "app-log-level",1,0,OPT_APP_LOG_LEVEL},504 { "log-append", 0, 0, OPT_LOG_APPEND},505 { "color", 0, 0, OPT_COLOR},506 { "no-color", 0, 0, OPT_NO_COLOR},507 { "light-bg", 0, 0, OPT_LIGHT_BG},508 { "no-stderr", 0, 0, OPT_NO_STDERR},509 { "help", 0, 0, OPT_HELP},510 { "version", 0, 0, OPT_VERSION},511 { "clock-rate", 1, 0, OPT_CLOCK_RATE},512 { "snd-clock-rate", 1, 0, OPT_SND_CLOCK_RATE},513 { "stereo", 0, 0, OPT_STEREO},514 { "null-audio", 0, 0, OPT_NULL_AUDIO},515 { "local-port", 1, 0, OPT_LOCAL_PORT},516 { "ip-addr", 1, 0, OPT_IP_ADDR},517 { "bound-addr", 1, 0, OPT_BOUND_ADDR},518 { "no-tcp", 0, 0, OPT_NO_TCP},519 { "no-udp", 0, 0, OPT_NO_UDP},520 { "norefersub", 0, 0, OPT_NOREFERSUB},521 { "proxy", 1, 0, OPT_PROXY},522 { "outbound", 1, 0, OPT_OUTBOUND_PROXY},523 { "registrar", 1, 0, OPT_REGISTRAR},524 { "reg-timeout",1, 0, OPT_REG_TIMEOUT},525 { "publish", 0, 0, OPT_PUBLISH},526 { "mwi", 0, 0, OPT_MWI},527 { "use-100rel", 0, 0, OPT_100REL},528 { "use-ims", 0, 0, OPT_USE_IMS},529 { "id", 1, 0, OPT_ID},530 { "contact", 1, 0, OPT_CONTACT},531 { "contact-params",1,0, OPT_CONTACT_PARAMS},532 { "contact-uri-params",1,0, OPT_CONTACT_URI_PARAMS},533 { "auto-update-nat", 1, 0, OPT_AUTO_UPDATE_NAT},534 { "disable-stun",0,0, OPT_DISABLE_STUN},535 { "use-compact-form", 0, 0, OPT_USE_COMPACT_FORM},536 { "accept-redirect", 1, 0, OPT_ACCEPT_REDIRECT},537 { "no-force-lr",0, 0, OPT_NO_FORCE_LR},538 { "realm", 1, 0, OPT_REALM},539 { "username", 1, 0, OPT_USERNAME},540 { "password", 1, 0, OPT_PASSWORD},541 { "rereg-delay",1, 0, OPT_REG_RETRY_INTERVAL},542 { "reg-use-proxy", 1, 0, OPT_REG_USE_PROXY},543 { "nameserver", 1, 0, OPT_NAMESERVER},544 { "stun-srv", 1, 0, OPT_STUN_SRV},545 { "add-buddy", 1, 0, OPT_ADD_BUDDY},546 { "offer-x-ms-msg",0,0,OPT_OFFER_X_MS_MSG},547 { "no-presence", 0, 0, OPT_NO_PRESENCE},548 { "auto-answer",1, 0, OPT_AUTO_ANSWER},549 { "auto-play", 0, 0, OPT_AUTO_PLAY},550 { "auto-play-hangup",0, 0, OPT_AUTO_PLAY_HANGUP},551 { "auto-rec", 0, 0, OPT_AUTO_REC},552 { "auto-loop", 0, 0, OPT_AUTO_LOOP},553 { "auto-conf", 0, 0, OPT_AUTO_CONF},554 { "play-file", 1, 0, OPT_PLAY_FILE},555 { "play-tone", 1, 0, OPT_PLAY_TONE},556 { "rec-file", 1, 0, OPT_REC_FILE},557 { "rtp-port", 1, 0, OPT_RTP_PORT},558 559 { "use-ice", 0, 0, OPT_USE_ICE},560 { "ice-regular",0, 0, OPT_ICE_REGULAR},561 { "use-turn", 0, 0, OPT_USE_TURN},562 { "ice-max-hosts",1, 0, OPT_ICE_MAX_HOSTS},563 { "ice-no-rtcp",0, 0, OPT_ICE_NO_RTCP},564 { "turn-srv", 1, 0, OPT_TURN_SRV},565 { "turn-tcp", 0, 0, OPT_TURN_TCP},566 { "turn-user", 1, 0, OPT_TURN_USER},567 { "turn-passwd",1, 0, OPT_TURN_PASSWD},568 569 #if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)570 { "use-srtp", 1, 0, OPT_USE_SRTP},571 { "srtp-secure",1, 0, OPT_SRTP_SECURE},572 #endif573 { "add-codec", 1, 0, OPT_ADD_CODEC},574 { "dis-codec", 1, 0, OPT_DIS_CODEC},575 { "complexity", 1, 0, OPT_COMPLEXITY},576 { "quality", 1, 0, OPT_QUALITY},577 { "ptime", 1, 0, OPT_PTIME},578 { "no-vad", 0, 0, OPT_NO_VAD},579 { "ec-tail", 1, 0, OPT_EC_TAIL},580 { "ec-opt", 1, 0, OPT_EC_OPT},581 { "ilbc-mode", 1, 0, OPT_ILBC_MODE},582 { "rx-drop-pct",1, 0, OPT_RX_DROP_PCT},583 { "tx-drop-pct",1, 0, OPT_TX_DROP_PCT},584 { "next-account",0,0, OPT_NEXT_ACCOUNT},585 { "next-cred", 0, 0, OPT_NEXT_CRED},586 { "max-calls", 1, 0, OPT_MAX_CALLS},587 { "duration", 1, 0, OPT_DURATION},588 { "thread-cnt", 1, 0, OPT_THREAD_CNT},589 #if defined(PJSIP_HAS_TLS_TRANSPORT) && (PJSIP_HAS_TLS_TRANSPORT != 0)590 { "use-tls", 0, 0, OPT_USE_TLS},591 { "tls-ca-file",1, 0, OPT_TLS_CA_FILE},592 { "tls-cert-file",1,0, OPT_TLS_CERT_FILE},593 { "tls-privkey-file",1,0, OPT_TLS_PRIV_FILE},594 { "tls-password",1,0, OPT_TLS_PASSWORD},595 { "tls-verify-server", 0, 0, OPT_TLS_VERIFY_SERVER},596 { "tls-verify-client", 0, 0, OPT_TLS_VERIFY_CLIENT},597 { "tls-neg-timeout", 1, 0, OPT_TLS_NEG_TIMEOUT},598 { "tls-cipher", 1, 0, OPT_TLS_CIPHER},599 #endif600 { "capture-dev", 1, 0, OPT_CAPTURE_DEV},601 { "playback-dev", 1, 0, OPT_PLAYBACK_DEV},602 { "capture-lat", 1, 0, OPT_CAPTURE_LAT},603 { "playback-lat", 1, 0, OPT_PLAYBACK_LAT},604 { "stdout-refresh", 1, 0, OPT_STDOUT_REFRESH},605 { "stdout-refresh-text", 1, 0, OPT_STDOUT_REFRESH_TEXT},606 #ifdef _IONBF607 { "stdout-no-buf", 0, 0, OPT_STDOUT_NO_BUF },608 #endif609 { "snd-auto-close", 1, 0, OPT_SND_AUTO_CLOSE},610 { "no-tones", 0, 0, OPT_NO_TONES},611 { "jb-max-size", 1, 0, OPT_JB_MAX_SIZE},612 #if defined(PJ_HAS_IPV6) && PJ_HAS_IPV6613 { "ipv6", 0, 0, OPT_IPV6},614 #endif615 { "set-qos", 0, 0, OPT_QOS},616 { "use-timer", 1, 0, OPT_TIMER},617 { "timer-se", 1, 0, OPT_TIMER_SE},618 { "timer-min-se", 1, 0, OPT_TIMER_MIN_SE},619 { "outb-rid", 1, 0, OPT_OUTB_RID},620 { "video", 0, 0, OPT_VIDEO},621 { "extra-audio",0, 0, OPT_EXTRA_AUDIO},622 { "vcapture-dev", 1, 0, OPT_VCAPTURE_DEV},623 { "vrender-dev", 1, 0, OPT_VRENDER_DEV},624 { "play-avi", 1, 0, OPT_PLAY_AVI},625 { "auto-play-avi", 0, 0, OPT_AUTO_PLAY_AVI},626 { "use-cli", 0, 0, OPT_USE_CLI},627 { "cli-telnet-port", 1, 0, OPT_CLI_TELNET_PORT},628 { NULL, 0, 0, 0}629 };630 pj_status_t status;631 pjsua_acc_config *cur_acc;632 char *config_file = NULL;633 unsigned i;634 635 /* Run pj_getopt once to see if user specifies config file to read. */636 pj_optind = 0;637 while ((c=pj_getopt_long(argc, argv, "", long_options,638 &option_index)) != -1)639 {640 switch (c) {641 case OPT_CONFIG_FILE:642 config_file = pj_optarg;643 break;644 }645 if (config_file)646 break;647 }648 649 if (config_file) {650 status = read_config_file(cfg->pool, config_file, &argc, &argv);651 if (status != 0)652 return status;653 }654 655 cfg->acc_cnt = 0;656 cur_acc = &cfg->acc_cfg[0];657 658 659 /* Reinitialize and re-run pj_getopt again, possibly with new arguments660 * read from config file.661 */662 pj_optind = 0;663 while((c=pj_getopt_long(argc,argv, "", long_options,&option_index))!=-1) {664 pj_str_t tmp;665 long lval;666 667 switch (c) {668 669 case OPT_CONFIG_FILE:670 /* Ignore as this has been processed before */671 break;672 673 case OPT_LOG_FILE:674 cfg->log_cfg.log_filename = pj_str(pj_optarg);675 break;676 677 case OPT_LOG_LEVEL:678 c = pj_strtoul(pj_cstr(&tmp, pj_optarg));679 if (c < 0 || c > 6) {680 PJ_LOG(1,(THIS_FILE,681 "Error: expecting integer value 0-6 "682 "for --log-level"));683 return PJ_EINVAL;684 }685 cfg->log_cfg.level = c;686 pj_log_set_level( c );687 break;688 689 case OPT_APP_LOG_LEVEL:690 cfg->log_cfg.console_level = pj_strtoul(pj_cstr(&tmp, pj_optarg));691 if (cfg->log_cfg.console_level < 0 || cfg->log_cfg.console_level > 6) {692 PJ_LOG(1,(THIS_FILE,693 "Error: expecting integer value 0-6 "694 "for --app-log-level"));695 return PJ_EINVAL;696 }697 break;698 699 case OPT_LOG_APPEND:700 cfg->log_cfg.log_file_flags |= PJ_O_APPEND;701 break;702 703 case OPT_COLOR:704 cfg->log_cfg.decor |= PJ_LOG_HAS_COLOR;705 break;706 707 case OPT_NO_COLOR:708 cfg->log_cfg.decor &= ~PJ_LOG_HAS_COLOR;709 break;710 711 case OPT_LIGHT_BG:712 pj_log_set_color(1, PJ_TERM_COLOR_R);713 pj_log_set_color(2, PJ_TERM_COLOR_R | PJ_TERM_COLOR_G);714 pj_log_set_color(3, PJ_TERM_COLOR_B | PJ_TERM_COLOR_G);715 pj_log_set_color(4, 0);716 pj_log_set_color(5, 0);717 pj_log_set_color(77, 0);718 break;719 720 case OPT_NO_STDERR:721 freopen("/dev/null", "w", stderr);722 break;723 724 case OPT_HELP:725 usage();726 return PJ_EINVAL;727 728 case OPT_VERSION: /* version */729 pj_dump_config();730 return PJ_EINVAL;731 732 case OPT_NULL_AUDIO:733 cfg->null_audio = PJ_TRUE;734 break;735 736 case OPT_CLOCK_RATE:737 lval = pj_strtoul(pj_cstr(&tmp, pj_optarg));738 if (lval < 8000 || lval > 192000) {739 PJ_LOG(1,(THIS_FILE, "Error: expecting value between "740 "8000-192000 for conference clock rate"));741 return PJ_EINVAL;742 }743 cfg->media_cfg.clock_rate = lval;744 break;745 746 case OPT_SND_CLOCK_RATE:747 lval = pj_strtoul(pj_cstr(&tmp, pj_optarg));748 if (lval < 8000 || lval > 192000) {749 PJ_LOG(1,(THIS_FILE, "Error: expecting value between "750 "8000-192000 for sound device clock rate"));751 return PJ_EINVAL;752 }753 cfg->media_cfg.snd_clock_rate = lval;754 break;755 756 case OPT_STEREO:757 cfg->media_cfg.channel_count = 2;758 break;759 760 case OPT_LOCAL_PORT: /* local-port */761 lval = pj_strtoul(pj_cstr(&tmp, pj_optarg));762 if (lval < 0 || lval > 65535) {763 PJ_LOG(1,(THIS_FILE,764 "Error: expecting integer value for "765 "--local-port"));766 return PJ_EINVAL;767 }768 cfg->udp_cfg.port = (pj_uint16_t)lval;769 break;770 771 case OPT_IP_ADDR: /* ip-addr */772 cfg->udp_cfg.public_addr = pj_str(pj_optarg);773 cfg->rtp_cfg.public_addr = pj_str(pj_optarg);774 break;775 776 case OPT_BOUND_ADDR: /* bound-addr */777 cfg->udp_cfg.bound_addr = pj_str(pj_optarg);778 cfg->rtp_cfg.bound_addr = pj_str(pj_optarg);779 break;780 781 case OPT_NO_UDP: /* no-udp */782 if (cfg->no_tcp && !cfg->use_tls) {783 PJ_LOG(1,(THIS_FILE,"Error: cannot disable both TCP and UDP"));784 return PJ_EINVAL;785 }786 787 cfg->no_udp = PJ_TRUE;788 break;789 790 case OPT_NOREFERSUB: /* norefersub */791 cfg->no_refersub = PJ_TRUE;792 break;793 794 case OPT_NO_TCP: /* no-tcp */795 if (cfg->no_udp && !cfg->use_tls) {796 PJ_LOG(1,(THIS_FILE,"Error: cannot disable both TCP and UDP"));797 return PJ_EINVAL;798 }799 800 cfg->no_tcp = PJ_TRUE;801 break;802 803 case OPT_PROXY: /* proxy */804 if (pjsua_verify_sip_url(pj_optarg) != 0) {805 PJ_LOG(1,(THIS_FILE,806 "Error: invalid SIP URL '%s' "807 "in proxy argument", pj_optarg));808 return PJ_EINVAL;809 }810 cur_acc->proxy[cur_acc->proxy_cnt++] = pj_str(pj_optarg);811 break;812 813 case OPT_OUTBOUND_PROXY: /* outbound proxy */814 if (pjsua_verify_sip_url(pj_optarg) != 0) {815 PJ_LOG(1,(THIS_FILE,816 "Error: invalid SIP URL '%s' "817 "in outbound proxy argument", pj_optarg));818 return PJ_EINVAL;819 }820 cfg->cfg.outbound_proxy[cfg->cfg.outbound_proxy_cnt++] = pj_str(pj_optarg);821 break;822 823 case OPT_REGISTRAR: /* registrar */824 if (pjsua_verify_sip_url(pj_optarg) != 0) {825 PJ_LOG(1,(THIS_FILE,826 "Error: invalid SIP URL '%s' in "827 "registrar argument", pj_optarg));828 return PJ_EINVAL;829 }830 cur_acc->reg_uri = pj_str(pj_optarg);831 break;832 833 case OPT_REG_TIMEOUT: /* reg-timeout */834 cur_acc->reg_timeout = pj_strtoul(pj_cstr(&tmp,pj_optarg));835 if (cur_acc->reg_timeout < 1 || cur_acc->reg_timeout > 3600) {836 PJ_LOG(1,(THIS_FILE,837 "Error: invalid value for --reg-timeout "838 "(expecting 1-3600)"));839 return PJ_EINVAL;840 }841 break;842 843 case OPT_PUBLISH: /* publish */844 cur_acc->publish_enabled = PJ_TRUE;845 break;846 847 case OPT_MWI: /* mwi */848 cur_acc->mwi_enabled = PJ_TRUE;849 break;850 851 case OPT_100REL: /** 100rel */852 cur_acc->require_100rel = PJSUA_100REL_MANDATORY;853 cfg->cfg.require_100rel = PJSUA_100REL_MANDATORY;854 break;855 856 case OPT_TIMER: /** session timer */857 lval = pj_strtoul(pj_cstr(&tmp, pj_optarg));858 if (lval < 0 || lval > 3) {859 PJ_LOG(1,(THIS_FILE,860 "Error: expecting integer value 0-3 for --use-timer"));861 return PJ_EINVAL;862 }863 cur_acc->use_timer = lval;864 cfg->cfg.use_timer = lval;865 break;866 867 case OPT_TIMER_SE: /** session timer session expiration */868 cur_acc->timer_setting.sess_expires = pj_strtoul(pj_cstr(&tmp, pj_optarg));869 if (cur_acc->timer_setting.sess_expires < 90) {870 PJ_LOG(1,(THIS_FILE,871 "Error: invalid value for --timer-se "872 "(expecting higher than 90)"));873 return PJ_EINVAL;874 }875 cfg->cfg.timer_setting.sess_expires = cur_acc->timer_setting.sess_expires;876 break;877 878 case OPT_TIMER_MIN_SE: /** session timer minimum session expiration */879 cur_acc->timer_setting.min_se = pj_strtoul(pj_cstr(&tmp, pj_optarg));880 if (cur_acc->timer_setting.min_se < 90) {881 PJ_LOG(1,(THIS_FILE,882 "Error: invalid value for --timer-min-se "883 "(expecting higher than 90)"));884 return PJ_EINVAL;885 }886 cfg->cfg.timer_setting.min_se = cur_acc->timer_setting.min_se;887 break;888 889 case OPT_OUTB_RID: /* Outbound reg-id */890 cur_acc->rfc5626_reg_id = pj_str(pj_optarg);891 break;892 893 case OPT_USE_IMS: /* Activate IMS settings */894 cur_acc->auth_pref.initial_auth = PJ_TRUE;895 break;896 897 case OPT_ID: /* id */898 if (pjsua_verify_url(pj_optarg) != 0) {899 PJ_LOG(1,(THIS_FILE,900 "Error: invalid SIP URL '%s' "901 "in local id argument", pj_optarg));902 return PJ_EINVAL;903 }904 cur_acc->id = pj_str(pj_optarg);905 break;906 907 case OPT_CONTACT: /* contact */908 if (pjsua_verify_sip_url(pj_optarg) != 0) {909 PJ_LOG(1,(THIS_FILE,910 "Error: invalid SIP URL '%s' "911 "in contact argument", pj_optarg));912 return PJ_EINVAL;913 }914 cur_acc->force_contact = pj_str(pj_optarg);915 break;916 917 case OPT_CONTACT_PARAMS:918 cur_acc->contact_params = pj_str(pj_optarg);919 break;920 921 case OPT_CONTACT_URI_PARAMS:922 cur_acc->contact_uri_params = pj_str(pj_optarg);923 break;924 925 case OPT_AUTO_UPDATE_NAT: /* OPT_AUTO_UPDATE_NAT */926 cur_acc->allow_contact_rewrite = pj_strtoul(pj_cstr(&tmp, pj_optarg));927 break;928 929 case OPT_DISABLE_STUN:930 cur_acc->sip_stun_use = PJSUA_STUN_USE_DISABLED;931 cur_acc->media_stun_use = PJSUA_STUN_USE_DISABLED;932 break;933 934 case OPT_USE_COMPACT_FORM:935 /* enable compact form - from Ticket #342 */936 {937 extern pj_bool_t pjsip_use_compact_form;938 extern pj_bool_t pjsip_include_allow_hdr_in_dlg;939 extern pj_bool_t pjmedia_add_rtpmap_for_static_pt;940 941 pjsip_use_compact_form = PJ_TRUE;942 /* do not transmit Allow header */943 pjsip_include_allow_hdr_in_dlg = PJ_FALSE;944 /* Do not include rtpmap for static payload types (<96) */945 pjmedia_add_rtpmap_for_static_pt = PJ_FALSE;946 }947 break;948 949 case OPT_ACCEPT_REDIRECT:950 cfg->redir_op = my_atoi(pj_optarg);951 if (cfg->redir_op<0 || cfg->redir_op>PJSIP_REDIRECT_STOP) {952 PJ_LOG(1,(THIS_FILE,953 "Error: accept-redirect value '%s' ", pj_optarg));954 return PJ_EINVAL;955 }956 break;957 958 case OPT_NO_FORCE_LR:959 cfg->cfg.force_lr = PJ_FALSE;960 break;961 962 case OPT_NEXT_ACCOUNT: /* Add more account. */963 cfg->acc_cnt++;964 cur_acc = &cfg->acc_cfg[cfg->acc_cnt];965 break;966 967 case OPT_USERNAME: /* Default authentication user */968 cur_acc->cred_info[cur_acc->cred_count].username = pj_str(pj_optarg);969 cur_acc->cred_info[cur_acc->cred_count].scheme = pj_str("Digest");970 break;971 972 case OPT_REALM: /* Default authentication realm. */973 cur_acc->cred_info[cur_acc->cred_count].realm = pj_str(pj_optarg);974 break;975 976 case OPT_PASSWORD: /* authentication password */977 cur_acc->cred_info[cur_acc->cred_count].data_type = PJSIP_CRED_DATA_PLAIN_PASSWD;978 cur_acc->cred_info[cur_acc->cred_count].data = pj_str(pj_optarg);979 #if PJSIP_HAS_DIGEST_AKA_AUTH980 cur_acc->cred_info[cur_acc->cred_count].data_type |= PJSIP_CRED_DATA_EXT_AKA;981 cur_acc->cred_info[cur_acc->cred_count].ext.aka.k = pj_str(pj_optarg);982 cur_acc->cred_info[cur_acc->cred_count].ext.aka.cb = &pjsip_auth_create_aka_response;983 #endif984 break;985 986 case OPT_REG_RETRY_INTERVAL:987 cur_acc->reg_retry_interval = pj_strtoul(pj_cstr(&tmp, pj_optarg));988 break;989 990 case OPT_REG_USE_PROXY:991 cur_acc->reg_use_proxy = (unsigned)pj_strtoul(pj_cstr(&tmp, pj_optarg));992 if (cur_acc->reg_use_proxy > 3) {993 PJ_LOG(1,(THIS_FILE, "Error: invalid --reg-use-proxy value '%s'",994 pj_optarg));995 return PJ_EINVAL;996 }997 break;998 999 case OPT_NEXT_CRED: /* next credential */1000 cur_acc->cred_count++;1001 break;1002 1003 case OPT_NAMESERVER: /* nameserver */1004 cfg->cfg.nameserver[cfg->cfg.nameserver_count++] = pj_str(pj_optarg);1005 if (cfg->cfg.nameserver_count > PJ_ARRAY_SIZE(cfg->cfg.nameserver)) {1006 PJ_LOG(1,(THIS_FILE, "Error: too many nameservers"));1007 return PJ_ETOOMANY;1008 }1009 break;1010 1011 case OPT_STUN_SRV: /* STUN server */1012 cfg->cfg.stun_host = pj_str(pj_optarg);1013 if (cfg->cfg.stun_srv_cnt==PJ_ARRAY_SIZE(cfg->cfg.stun_srv)) {1014 PJ_LOG(1,(THIS_FILE, "Error: too many STUN servers"));1015 return PJ_ETOOMANY;1016 }1017 cfg->cfg.stun_srv[cfg->cfg.stun_srv_cnt++] = pj_str(pj_optarg);1018 break;1019 1020 case OPT_ADD_BUDDY: /* Add to buddy list. */1021 if (pjsua_verify_url(pj_optarg) != 0) {1022 PJ_LOG(1,(THIS_FILE,1023 "Error: invalid URL '%s' in "1024 "--add-buddy option", pj_optarg));1025 return -1;1026 }1027 if (cfg->buddy_cnt == PJ_ARRAY_SIZE(cfg->buddy_cfg)) {1028 PJ_LOG(1,(THIS_FILE,1029 "Error: too many buddies in buddy list."));1030 return -1;1031 }1032 cfg->buddy_cfg[cfg->buddy_cnt].uri = pj_str(pj_optarg);1033 cfg->buddy_cnt++;1034 break;1035 1036 case OPT_AUTO_PLAY:1037 cfg->auto_play = 1;1038 break;1039 1040 case OPT_AUTO_PLAY_HANGUP:1041 cfg->auto_play_hangup = 1;1042 break;1043 1044 case OPT_AUTO_REC:1045 cfg->auto_rec = 1;1046 break;1047 1048 case OPT_AUTO_LOOP:1049 cfg->auto_loop = 1;1050 break;1051 1052 case OPT_AUTO_CONF:1053 cfg->auto_conf = 1;1054 break;1055 1056 case OPT_PLAY_FILE:1057 cfg->wav_files[cfg->wav_count++] = pj_str(pj_optarg);1058 break;1059 1060 case OPT_PLAY_TONE:1061 {1062 int f1, f2, on, off;1063 int n;1064 1065 n = sscanf(pj_optarg, "%d,%d,%d,%d", &f1, &f2, &on, &off);1066 if (n != 4) {1067 puts("Expecting f1,f2,on,off in --play-tone");1068 return -1;1069 }1070 1071 cfg->tones[cfg->tone_count].freq1 = (short)f1;1072 cfg->tones[cfg->tone_count].freq2 = (short)f2;1073 cfg->tones[cfg->tone_count].on_msec = (short)on;1074 cfg->tones[cfg->tone_count].off_msec = (short)off;1075 ++cfg->tone_count;1076 }1077 break;1078 1079 case OPT_REC_FILE:1080 cfg->rec_file = pj_str(pj_optarg);1081 break;1082 1083 case OPT_USE_ICE:1084 cfg->media_cfg.enable_ice =1085 cur_acc->ice_cfg.enable_ice = PJ_TRUE;1086 break;1087 1088 case OPT_ICE_REGULAR:1089 cfg->media_cfg.ice_opt.aggressive =1090 cur_acc->ice_cfg.ice_opt.aggressive = PJ_FALSE;1091 break;1092 1093 case OPT_USE_TURN:1094 cfg->media_cfg.enable_turn =1095 cur_acc->turn_cfg.enable_turn = PJ_TRUE;1096 break;1097 1098 case OPT_ICE_MAX_HOSTS:1099 cfg->media_cfg.ice_max_host_cands =1100 cur_acc->ice_cfg.ice_max_host_cands = my_atoi(pj_optarg);1101 break;1102 1103 case OPT_ICE_NO_RTCP:1104 cfg->media_cfg.ice_no_rtcp =1105 cur_acc->ice_cfg.ice_no_rtcp = PJ_TRUE;1106 break;1107 1108 case OPT_TURN_SRV:1109 cfg->media_cfg.turn_server =1110 cur_acc->turn_cfg.turn_server = pj_str(pj_optarg);1111 break;1112 1113 case OPT_TURN_TCP:1114 cfg->media_cfg.turn_conn_type =1115 cur_acc->turn_cfg.turn_conn_type = PJ_TURN_TP_TCP;1116 break;1117 1118 case OPT_TURN_USER:1119 cfg->media_cfg.turn_auth_cred.type =1120 cur_acc->turn_cfg.turn_auth_cred.type = PJ_STUN_AUTH_CRED_STATIC;1121 cfg->media_cfg.turn_auth_cred.data.static_cred.realm =1122 cur_acc->turn_cfg.turn_auth_cred.data.static_cred.realm = pj_str("*");1123 cfg->media_cfg.turn_auth_cred.data.static_cred.username =1124 cur_acc->turn_cfg.turn_auth_cred.data.static_cred.username = pj_str(pj_optarg);1125 break;1126 1127 case OPT_TURN_PASSWD:1128 cfg->media_cfg.turn_auth_cred.data.static_cred.data_type =1129 cur_acc->turn_cfg.turn_auth_cred.data.static_cred.data_type = PJ_STUN_PASSWD_PLAIN;1130 cfg->media_cfg.turn_auth_cred.data.static_cred.data =1131 cur_acc->turn_cfg.turn_auth_cred.data.static_cred.data = pj_str(pj_optarg);1132 break;1133 1134 #if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)1135 case OPT_USE_SRTP:1136 app_config.cfg.use_srtp = my_atoi(pj_optarg);1137 if (!pj_isdigit(*pj_optarg) || app_config.cfg.use_srtp > 3) {1138 PJ_LOG(1,(THIS_FILE, "Invalid value for --use-srtp option"));1139 return -1;1140 }1141 if ((int)app_config.cfg.use_srtp == 3) {1142 /* SRTP optional mode with duplicated media offer */1143 app_config.cfg.use_srtp = PJMEDIA_SRTP_OPTIONAL;1144 app_config.cfg.srtp_optional_dup_offer = PJ_TRUE;1145 cur_acc->srtp_optional_dup_offer = PJ_TRUE;1146 }1147 cur_acc->use_srtp = app_config.cfg.use_srtp;1148 break;1149 case OPT_SRTP_SECURE:1150 app_config.cfg.srtp_secure_signaling = my_atoi(pj_optarg);1151 if (!pj_isdigit(*pj_optarg) ||1152 app_config.cfg.srtp_secure_signaling > 2)1153 {1154 PJ_LOG(1,(THIS_FILE, "Invalid value for --srtp-secure option"));1155 return -1;1156 }1157 cur_acc->srtp_secure_signaling = app_config.cfg.srtp_secure_signaling;1158 break;1159 #endif1160 1161 case OPT_RTP_PORT:1162 cfg->rtp_cfg.port = my_atoi(pj_optarg);1163 if (cfg->rtp_cfg.port == 0) {1164 enum { START_PORT=4000 };1165 unsigned range;1166 1167 range = (65535-START_PORT-PJSUA_MAX_CALLS*2);1168 cfg->rtp_cfg.port = START_PORT +1169 ((pj_rand() % range) & 0xFFFE);1170 }1171 1172 if (cfg->rtp_cfg.port < 1 || cfg->rtp_cfg.port > 65535) {1173 PJ_LOG(1,(THIS_FILE,1174 "Error: rtp-port argument value "1175 "(expecting 1-65535"));1176 return -1;1177 }1178 break;1179 1180 case OPT_DIS_CODEC:1181 cfg->codec_dis[cfg->codec_dis_cnt++] = pj_str(pj_optarg);1182 break;1183 1184 case OPT_ADD_CODEC:1185 cfg->codec_arg[cfg->codec_cnt++] = pj_str(pj_optarg);1186 break;1187 1188 /* These options were no longer valid after new pjsua */1189 /*1190 case OPT_COMPLEXITY:1191 cfg->complexity = my_atoi(pj_optarg);1192 if (cfg->complexity < 0 || cfg->complexity > 10) {1193 PJ_LOG(1,(THIS_FILE,1194 "Error: invalid --complexity (expecting 0-10"));1195 return -1;1196 }1197 break;1198 */1199 1200 case OPT_DURATION:1201 cfg->duration = my_atoi(pj_optarg);1202 break;1203 1204 case OPT_THREAD_CNT:1205 cfg->cfg.thread_cnt = my_atoi(pj_optarg);1206 if (cfg->cfg.thread_cnt > 128) {1207 PJ_LOG(1,(THIS_FILE,1208 "Error: invalid --thread-cnt option"));1209 return -1;1210 }1211 break;1212 1213 case OPT_PTIME:1214 cfg->media_cfg.ptime = my_atoi(pj_optarg);1215 if (cfg->media_cfg.ptime < 10 || cfg->media_cfg.ptime > 1000) {1216 PJ_LOG(1,(THIS_FILE,1217 "Error: invalid --ptime option"));1218 return -1;1219 }1220 break;1221 1222 case OPT_NO_VAD:1223 cfg->media_cfg.no_vad = PJ_TRUE;1224 break;1225 1226 case OPT_EC_TAIL:1227 cfg->media_cfg.ec_tail_len = my_atoi(pj_optarg);1228 if (cfg->media_cfg.ec_tail_len > 1000) {1229 PJ_LOG(1,(THIS_FILE, "I think the ec-tail length setting "1230 "is too big"));1231 return -1;1232 }1233 break;1234 1235 case OPT_EC_OPT:1236 cfg->media_cfg.ec_options = my_atoi(pj_optarg);1237 break;1238 1239 case OPT_QUALITY:1240 cfg->media_cfg.quality = my_atoi(pj_optarg);1241 if (cfg->media_cfg.quality < 0 || cfg->media_cfg.quality > 10) {1242 PJ_LOG(1,(THIS_FILE,1243 "Error: invalid --quality (expecting 0-10"));1244 return -1;1245 }1246 break;1247 1248 case OPT_ILBC_MODE:1249 cfg->media_cfg.ilbc_mode = my_atoi(pj_optarg);1250 if (cfg->media_cfg.ilbc_mode!=20 && cfg->media_cfg.ilbc_mode!=30) {1251 PJ_LOG(1,(THIS_FILE,1252 "Error: invalid --ilbc-mode (expecting 20 or 30"));1253 return -1;1254 }1255 break;1256 1257 case OPT_RX_DROP_PCT:1258 cfg->media_cfg.rx_drop_pct = my_atoi(pj_optarg);1259 if (cfg->media_cfg.rx_drop_pct > 100) {1260 PJ_LOG(1,(THIS_FILE,1261 "Error: invalid --rx-drop-pct (expecting <= 100"));1262 return -1;1263 }1264 break;1265 1266 case OPT_TX_DROP_PCT:1267 cfg->media_cfg.tx_drop_pct = my_atoi(pj_optarg);1268 if (cfg->media_cfg.tx_drop_pct > 100) {1269 PJ_LOG(1,(THIS_FILE,1270 "Error: invalid --tx-drop-pct (expecting <= 100"));1271 return -1;1272 }1273 break;1274 1275 case OPT_AUTO_ANSWER:1276 cfg->auto_answer = my_atoi(pj_optarg);1277 if (cfg->auto_answer < 100 || cfg->auto_answer > 699) {1278 PJ_LOG(1,(THIS_FILE,1279 "Error: invalid code in --auto-answer "1280 "(expecting 100-699"));1281 return -1;1282 }1283 break;1284 1285 case OPT_MAX_CALLS:1286 cfg->cfg.max_calls = my_atoi(pj_optarg);1287 if (cfg->cfg.max_calls < 1 || cfg->cfg.max_calls > PJSUA_MAX_CALLS) {1288 PJ_LOG(1,(THIS_FILE,"Error: maximum call setting exceeds "1289 "compile time limit (PJSUA_MAX_CALLS=%d)",1290 PJSUA_MAX_CALLS));1291 return -1;1292 }1293 break;1294 1295 #if defined(PJSIP_HAS_TLS_TRANSPORT) && (PJSIP_HAS_TLS_TRANSPORT != 0)1296 case OPT_USE_TLS:1297 cfg->use_tls = PJ_TRUE;1298 break;1299 1300 case OPT_TLS_CA_FILE:1301 cfg->udp_cfg.tls_setting.ca_list_file = pj_str(pj_optarg);1302 break;1303 1304 case OPT_TLS_CERT_FILE:1305 cfg->udp_cfg.tls_setting.cert_file = pj_str(pj_optarg);1306 break;1307 1308 case OPT_TLS_PRIV_FILE:1309 cfg->udp_cfg.tls_setting.privkey_file = pj_str(pj_optarg);1310 break;1311 1312 case OPT_TLS_PASSWORD:1313 cfg->udp_cfg.tls_setting.password = pj_str(pj_optarg);1314 break;1315 1316 case OPT_TLS_VERIFY_SERVER:1317 cfg->udp_cfg.tls_setting.verify_server = PJ_TRUE;1318 break;1319 1320 case OPT_TLS_VERIFY_CLIENT:1321 cfg->udp_cfg.tls_setting.verify_client = PJ_TRUE;1322 cfg->udp_cfg.tls_setting.require_client_cert = PJ_TRUE;1323 break;1324 1325 case OPT_TLS_NEG_TIMEOUT:1326 cfg->udp_cfg.tls_setting.timeout.sec = atoi(pj_optarg);1327 break;1328 1329 case OPT_TLS_CIPHER:1330 {1331 pj_ssl_cipher cipher;1332 1333 if (pj_ansi_strnicmp(pj_optarg, "0x", 2) == 0) {1334 pj_str_t cipher_st = pj_str(pj_optarg + 2);1335 cipher = pj_strtoul2(&cipher_st, NULL, 16);1336 } else {1337 cipher = atoi(pj_optarg);1338 }1339 1340 if (pj_ssl_cipher_is_supported(cipher)) {1341 static pj_ssl_cipher tls_ciphers[128];1342 1343 tls_ciphers[cfg->udp_cfg.tls_setting.ciphers_num++] = cipher;1344 cfg->udp_cfg.tls_setting.ciphers = tls_ciphers;1345 } else {1346 pj_ssl_cipher ciphers[128];1347 unsigned j, ciphers_cnt;1348 1349 ciphers_cnt = PJ_ARRAY_SIZE(ciphers);1350 pj_ssl_cipher_get_availables(ciphers, &ciphers_cnt);1351 1352 PJ_LOG(1,(THIS_FILE, "Cipher \"%s\" is not supported by "1353 "TLS/SSL backend.", pj_optarg));1354 printf("Available TLS/SSL ciphers (%d):\n", ciphers_cnt);1355 for (j=0; j<ciphers_cnt; ++j)1356 printf("- 0x%06X: %s\n", ciphers[j], pj_ssl_cipher_name(ciphers[j]));1357 return -1;1358 }1359 }1360 break;1361 #endif /* PJSIP_HAS_TLS_TRANSPORT */1362 1363 case OPT_CAPTURE_DEV:1364 cfg->capture_dev = atoi(pj_optarg);1365 break;1366 1367 case OPT_PLAYBACK_DEV:1368 cfg->playback_dev = atoi(pj_optarg);1369 break;1370 1371 case OPT_STDOUT_REFRESH:1372 stdout_refresh = atoi(pj_optarg);1373 break;1374 1375 case OPT_STDOUT_REFRESH_TEXT:1376 stdout_refresh_text = pj_optarg;1377 break;1378 1379 #ifdef _IONBF1380 case OPT_STDOUT_NO_BUF:1381 setvbuf(stdout, NULL, _IONBF, 0);1382 break;1383 #endif1384 1385 case OPT_CAPTURE_LAT:1386 cfg->capture_lat = atoi(pj_optarg);1387 break;1388 1389 case OPT_PLAYBACK_LAT:1390 cfg->playback_lat = atoi(pj_optarg);1391 break;1392 1393 case OPT_SND_AUTO_CLOSE:1394 cfg->media_cfg.snd_auto_close_time = atoi(pj_optarg);1395 break;1396 1397 case OPT_NO_TONES:1398 cfg->no_tones = PJ_TRUE;1399 break;1400 1401 case OPT_JB_MAX_SIZE:1402 cfg->media_cfg.jb_max = atoi(pj_optarg);1403 break;1404 1405 #if defined(PJ_HAS_IPV6) && PJ_HAS_IPV61406 case OPT_IPV6:1407 cfg->ipv6 = PJ_TRUE;1408 break;1409 #endif1410 case OPT_QOS:1411 cfg->enable_qos = PJ_TRUE;1412 /* Set RTP traffic type to Voice */1413 cfg->rtp_cfg.qos_type = PJ_QOS_TYPE_VOICE;1414 /* Directly apply DSCP value to SIP traffic. Say lets1415 * set it to CS3 (DSCP 011000). Note that this will not1416 * work on all platforms.1417 */1418 cfg->udp_cfg.qos_params.flags = PJ_QOS_PARAM_HAS_DSCP;1419 cfg->udp_cfg.qos_params.dscp_val = 0x18;1420 break;1421 case OPT_VIDEO:1422 cfg->vid.vid_cnt = 1;1423 cfg->vid.in_auto_show = PJ_TRUE;1424 cfg->vid.out_auto_transmit = PJ_TRUE;1425 break;1426 case OPT_EXTRA_AUDIO:1427 cfg->aud_cnt++;1428 break;1429 1430 case OPT_VCAPTURE_DEV:1431 cfg->vid.vcapture_dev = atoi(pj_optarg);1432 cur_acc->vid_cap_dev = cfg->vid.vcapture_dev;1433 break;1434 1435 case OPT_VRENDER_DEV:1436 cfg->vid.vrender_dev = atoi(pj_optarg);1437 cur_acc->vid_rend_dev = cfg->vid.vrender_dev;1438 break;1439 1440 case OPT_PLAY_AVI:1441 if (app_config.avi_cnt >= MAX_AVI) {1442 PJ_LOG(1,(THIS_FILE, "Too many AVIs"));1443 return -1;1444 }1445 app_config.avi[app_config.avi_cnt++].path = pj_str(pj_optarg);1446 break;1447 1448 case OPT_AUTO_PLAY_AVI:1449 app_config.avi_auto_play = PJ_TRUE;1450 break;1451 1452 case OPT_USE_CLI:1453 cfg->use_cli = PJ_TRUE;1454 break;1455 1456 case OPT_CLI_TELNET_PORT:1457 cfg->cli_telnet_port = atoi(pj_optarg);1458 break;1459 1460 default:1461 PJ_LOG(1,(THIS_FILE,1462 "Argument \"%s\" is not valid. Use --help to see help",1463 argv[pj_optind-1]));1464 return -1;1465 }1466 }1467 1468 if (pj_optind != argc) {1469 pj_str_t uri_arg;1470 1471 if (pjsua_verify_url(argv[pj_optind]) != PJ_SUCCESS) {1472 PJ_LOG(1,(THIS_FILE, "Invalid SIP URI %s", argv[pj_optind]));1473 return -1;1474 }1475 uri_arg = pj_str(argv[pj_optind]);1476 if (uri_to_call)1477 *uri_to_call = uri_arg;1478 pj_optind++;1479 1480 /* Add URI to call to buddy list if it's not already there */1481 for (i=0; i<cfg->buddy_cnt; ++i) {1482 if (pj_stricmp(&cfg->buddy_cfg[i].uri, &uri_arg)==0)1483 break;1484 }1485 if (i == cfg->buddy_cnt && cfg->buddy_cnt < PJSUA_MAX_BUDDIES) {1486 cfg->buddy_cfg[cfg->buddy_cnt++].uri = uri_arg;1487 }1488 1489 } else {1490 if (uri_to_call)1491 uri_to_call->slen = 0;1492 }1493 1494 if (pj_optind != argc) {1495 PJ_LOG(1,(THIS_FILE, "Error: unknown options %s", argv[pj_optind]));1496 return PJ_EINVAL;1497 }1498 1499 if (cfg->acc_cfg[cfg->acc_cnt].id.slen)1500 cfg->acc_cnt++;1501 1502 for (i=0; i<cfg->acc_cnt; ++i) {1503 pjsua_acc_config *acfg = &cfg->acc_cfg[i];1504 1505 if (acfg->cred_info[acfg->cred_count].username.slen)1506 {1507 acfg->cred_count++;1508 }1509 1510 if (acfg->ice_cfg.enable_ice) {1511 acfg->ice_cfg_use = PJSUA_ICE_CONFIG_USE_CUSTOM;1512 }1513 if (acfg->turn_cfg.enable_turn) {1514 acfg->turn_cfg_use = PJSUA_TURN_CONFIG_USE_CUSTOM;1515 }1516 1517 /* When IMS mode is enabled for the account, verify that settings1518 * are okay.1519 */1520 /* For now we check if IMS mode is activated by looking if1521 * initial_auth is set.1522 */1523 if (acfg->auth_pref.initial_auth && acfg->cred_count) {1524 /* Realm must point to the real domain */1525 if (*acfg->cred_info[0].realm.ptr=='*') {1526 PJ_LOG(1,(THIS_FILE,1527 "Error: cannot use '*' as realm with IMS"));1528 return PJ_EINVAL;1529 }1530 1531 /* Username for authentication must be in a@b format */1532 if (strchr(acfg->cred_info[0].username.ptr, '@')==0) {1533 PJ_LOG(1,(THIS_FILE,1534 "Error: Username for authentication must "1535 "be in user@domain format with IMS"));1536 return PJ_EINVAL;1537 }1538 }1539 }1540 return PJ_SUCCESS;1541 }1542 1543 103 /***************************************************************************** 1544 * C onsole application104 * Callback 1545 105 */ 1546 106 static void ringback_start(pjsua_call_id call_id) … … 1659 219 /* Cancel duration timer, if any */ 1660 220 if (app_config.call_data[call_id].timer.id != PJSUA_INVALID_ID) { 1661 structcall_data *cd = &app_config.call_data[call_id];221 app_call_data *cd = &app_config.call_data[call_id]; 1662 222 pjsip_endpoint *endpt = pjsua_get_pjsip_endpt(); 1663 223 … … 1696 256 { 1697 257 /* Schedule timer to hangup call after the specified duration */ 1698 structcall_data *cd = &app_config.call_data[call_id];258 app_call_data *cd = &app_config.call_data[call_id]; 1699 259 pjsip_endpoint *endpt = pjsua_get_pjsip_endpt(); 1700 260 pj_time_val delay; … … 1810 370 } 1811 371 } 1812 1813 372 1814 373 /* … … 2690 1249 }; 2691 1250 1251 #if defined(PJ_WIN32) && PJ_WIN32!=0 1252 #include <windows.h> 1253 1254 static pj_thread_desc handler_desc; 1255 1256 static BOOL WINAPI CtrlHandler(DWORD fdwCtrlType) 1257 { 1258 switch (fdwCtrlType) 1259 { 1260 // Handle the CTRL+C signal. 1261 1262 case CTRL_C_EVENT: 1263 case CTRL_CLOSE_EVENT: 1264 case CTRL_BREAK_EVENT: 1265 case CTRL_LOGOFF_EVENT: 1266 case CTRL_SHUTDOWN_EVENT: 1267 pj_thread_register("ctrlhandler", handler_desc, &sig_thread); 1268 PJ_LOG(3,(THIS_FILE, "Ctrl-C detected, quitting..")); 1269 receive_end_sig = PJ_TRUE; 1270 app_destroy(); 1271 ExitProcess(1); 1272 PJ_UNREACHED(return TRUE;) 1273 1274 default: 1275 1276 return FALSE; 1277 } 1278 } 1279 1280 static void setup_socket_signal() 1281 { 1282 } 1283 1284 #else 1285 #include <signal.h> 1286 1287 static void setup_socket_signal() 1288 { 1289 signal(SIGPIPE, SIG_IGN); 1290 } 1291 1292 #endif 1293 1294 static pj_status_t setup_pjsua() 1295 { 1296 pj_status_t status = pjsua_destroy(); 1297 if (status != PJ_SUCCESS) 1298 return status; 1299 1300 /* Create pjsua */ 1301 status = pjsua_create(); 1302 if (status != PJ_SUCCESS) 1303 return status; 1304 1305 /* Create pool for application */ 1306 app_config.pool = pjsua_pool_create("pjsua-app", 1000, 1000); 1307 1308 return status; 1309 } 1310 2692 1311 /***************************************************************************** 2693 1312 * Public API 2694 1313 */ 2695 1314 2696 pj_status_t app_init(int argc, char *argv[]) 1315 #if defined(PJ_WIN32) && PJ_WIN32!=0 1316 PJ_DEF(void) setup_signal_handler(void) 1317 { 1318 SetConsoleCtrlHandler(&CtrlHandler, TRUE); 1319 } 1320 #else 1321 PJ_DEF(void) setup_signal_handler(void) 1322 { 1323 } 1324 #endif 1325 1326 int stdout_refresh_proc(void *arg) 1327 { 1328 extern char *stdout_refresh_text; 1329 1330 PJ_UNUSED_ARG(arg); 1331 1332 /* Set thread to lowest priority so that it doesn't clobber 1333 * stdout output 1334 */ 1335 pj_thread_set_prio(pj_thread_this(), 1336 pj_thread_get_prio_min(pj_thread_this())); 1337 1338 while (!stdout_refresh_quit) { 1339 pj_thread_sleep(stdout_refresh * 1000); 1340 puts(stdout_refresh_text); 1341 fflush(stdout); 1342 } 1343 1344 return 0; 1345 } 1346 1347 PJ_DEF(pj_status_t) app_init(pj_cli_telnet_on_started on_started_cb, 1348 pj_cli_on_quit on_quit_cb, 1349 pj_cli_on_destroy on_destroy_cb, 1350 pj_cli_on_restart_pjsua on_restart_pjsua_cb) 2697 1351 { 2698 1352 pjsua_transport_id transport_id = -1; … … 2701 1355 pj_status_t status; 2702 1356 2703 app_restart = PJ_FALSE; 2704 2705 /* Create pjsua */ 2706 status = pjsua_create(); 1357 /** Setup pjsua **/ 1358 status = setup_pjsua(); 2707 1359 if (status != PJ_SUCCESS) 2708 1360 return status; 2709 1361 2710 /* Create pool for application */ 2711 app_config.pool = pjsua_pool_create("pjsua-app", 1000, 1000); 2712 2713 /* Initialize default config */ 2714 default_config(&app_config); 2715 2716 /* Parse the arguments */ 2717 status = parse_args(argc, argv, &app_config, &uri_arg); 1362 /** Load config **/ 1363 status = load_config(&app_config, &uri_arg, app_running); 2718 1364 if (status != PJ_SUCCESS) 2719 return status; 1365 return status; 1366 1367 #if defined(PJ_SYMBIAN) && PJ_SYMBIAN!=0 1368 /* Disable threading on Symbian */ 1369 app_config.cfg.thread_cnt = 0; 1370 app_config.media_cfg.thread_cnt = 0; 1371 app_config.media_cfg.has_ioqueue = PJ_FALSE; 1372 #endif 2720 1373 2721 1374 /* Initialize application callbacks */ … … 3237 1890 } 3238 1891 1892 /* Init call setting */ 1893 pjsua_call_setting_default(&call_opt); 1894 call_opt.aud_cnt = app_config.aud_cnt; 1895 call_opt.vid_cnt = app_config.vid.vid_cnt; 1896 1897 /* Init CLI if configured */ 3239 1898 if (app_config.use_cli) { 3240 /*3241 * Init CLI3242 */3243 status = setup_cli();3244 if (status != PJ_SUCCESS)3245 goto on_error;3246 3247 PJ_LOG(3,(THIS_FILE, "CLI telnet daemon listening at port %d",3248 app_config.cli_telnet_port));1899 if (app_restart) { 1900 pj_uint16_t port = (pj_uint16_t)app_config.cli_telnet_port; 1901 status = setup_cli(!app_config.disable_cli_console, 1902 app_config.cli_telnet_port >= 0, port, 1903 on_started_cb, on_quit_cb, on_destroy_cb, 1904 on_restart_pjsua_cb); 1905 if (status != PJ_SUCCESS) 1906 goto on_error; 1907 } 3249 1908 } 3250 1909 … … 3252 1911 3253 1912 on_error: 1913 app_restart = PJ_FALSE; 3254 1914 app_destroy(); 3255 1915 return status; … … 3259 1919 { 3260 1920 pj_thread_t *stdout_refresh_thread = NULL; 3261 pj_status_t status;3262 3263 /* Start pjsua */3264 status = pjsua_start();3265 if (status != PJ_SUCCESS) {3266 app_destroy();3267 return status;3268 }3269 1921 3270 1922 /* Start console refresh thread */ … … 3275 1927 3276 1928 if (app_config.use_cli) 3277 cli_console_app_main(&uri_arg, &app_restart);3278 else 3279 console_app_main(&uri_arg, &app_restart);1929 start_cli_main(&uri_arg, &app_restart); 1930 else 1931 start_ui_main(&uri_arg, &app_restart); 3280 1932 3281 1933 if (stdout_refresh_thread) { … … 3288 1940 } 3289 1941 3290 pj_status_t app_destroy( void)1942 pj_status_t app_destroy() 3291 1943 { 3292 1944 pj_status_t status; … … 3344 1996 3345 1997 if (app_config.use_cli) { 3346 destroy_cli( );1998 destroy_cli(app_restart); 3347 1999 } 3348 2000 … … 3351 2003 app_config.pool = NULL; 3352 2004 } 3353 2005 3354 2006 status = pjsua_destroy(); 3355 3356 pj_bzero(&app_config, sizeof(app_config)); 3357 2007 2008 if (!app_restart) 2009 pj_bzero(&app_config, sizeof(app_config)); 2010 3358 2011 return status; 3359 2012 } 3360 2013 2014 /** === CLI Callback == **/ 2015 2016 static void cli_telnet_started(pj_cli_telnet_info *telnet_info) 2017 { 2018 PJ_LOG(3,(THIS_FILE, "Telnet daemon listening at %.*s:%d", 2019 telnet_info->ip_address.slen, telnet_info->ip_address.ptr, 2020 telnet_info->port)); 2021 } 2022 2023 static void cli_on_quit (pj_bool_t is_restarted) 2024 { 2025 PJ_LOG(3,(THIS_FILE, "CLI quit, restart(%d)", is_restarted)); 2026 } 2027 2028 static void cli_on_destroy(void) 2029 { 2030 PJ_LOG(3,(THIS_FILE, "CLI destroyed")); 2031 } 2032 2033 static void cli_on_restart_pjsua(void) 2034 { 2035 PJ_LOG(3,(THIS_FILE, "Restart pjsua")); 2036 } 2037 2038 /** ======================= **/ 2039 2040 int main_func(int argc, char *argv[]) 2041 { 2042 pj_status_t status; 2043 2044 setup_socket_signal(); 2045 2046 receive_end_sig = PJ_FALSE; 2047 app_restart = PJ_TRUE; 2048 2049 add_startup_config(argc, argv); 2050 2051 do { 2052 if (app_restart) { 2053 status = app_init(cli_telnet_started, cli_on_quit, 2054 cli_on_destroy, cli_on_restart_pjsua); 2055 if (status != PJ_SUCCESS) 2056 return 1; 2057 } 2058 2059 app_running = PJ_TRUE; 2060 2061 app_main(); 2062 if (!receive_end_sig) { 2063 app_destroy(); 2064 2065 /* This is on purpose */ 2066 app_destroy(); 2067 } else { 2068 pj_thread_join(sig_thread); 2069 } 2070 } while (app_restart); 2071 return 0; 2072 } 3361 2073 3362 2074 #ifdef STEREO_DEMO … … 3431 2143 } 3432 2144 #endif 3433
Note: See TracChangeset
for help on using the changeset viewer.