Ignore:
Timestamp:
Apr 5, 2013 3:02:19 AM (11 years ago)
Author:
riza
Message:

Re #1643: Code restructure+add callback to support symbian gui app

File:
1 edited

Legend:

Unmodified
Added
Removed
  • pjproject/trunk/pjsip-apps/src/pjsua/pjsua_app.c

    r4440 r4461  
    1818 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA  
    1919 */ 
    20 #include "pjsua_cmd.h" 
     20#include "pjsua_common.h" 
    2121#include "gui.h" 
    2222 
     
    4444#define current_acc     pjsua_acc_get_default() 
    4545 
    46 static pj_str_t         uri_arg; 
    47  
    4846#ifdef STEREO_DEMO 
    4947static void stereo_demo(); 
     
    5149 
    5250pj_status_t app_destroy(void); 
     51 
    5352static void ringback_start(pjsua_call_id call_id); 
    5453static void ring_start(pjsua_call_id call_id); 
    5554static void ring_stop(pjsua_call_id call_id); 
    5655 
    57 pj_bool_t       app_restart; 
    58 pj_log_func     *log_cb = NULL; 
    59 static const char      *stdout_refresh_text = "STDOUT_REFRESH"; 
     56static pj_status_t          receive_end_sig; 
     57static pj_thread_t          *sig_thread; 
     58pj_str_t                    uri_arg; 
     59pj_bool_t                   app_restart; 
     60pj_bool_t                   app_running = PJ_FALSE; 
     61pj_log_func                 *log_cb = NULL; 
    6062 
    6163/** 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 **/ 
    6565void 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 **/ 
     67void start_ui_main(pj_str_t *uri_to_call, pj_bool_t *app_restart); 
     68/** Defined in pjsua_cli.c **/ 
     69void start_cli_main(pj_str_t *uri_to_call, pj_bool_t *app_restart); 
     70pj_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); 
     76void destroy_cli(pj_bool_t app_restart); 
    6877 
    6978/***************************************************************************** 
     
    92101#endif 
    93102 
    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 #endif 
    141     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_IPV6 
    158     puts  ("  --ipv6              Use IPv6 instead for SIP and media."); 
    159 #endif 
    160     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 #endif 
    191  
    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_VIDEO 
    230     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 #endif 
    238  
    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 clobber 
    288      * stdout output 
    289      */ 
    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 newlines 
    386         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 whitespaces 
    396             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 string 
    402                 cDelimiter = *p++;          // save quote delimiter 
    403                 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 quote 
    409  
    410             } else {                    // token's not a quoted string 
    411                 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 line 
    424                  
    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 _IONBF 
    490            OPT_STDOUT_NO_BUF, 
    491 #endif 
    492            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_PORT 
    498     }; 
    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 #endif 
    573         { "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 #endif 
    600         { "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 _IONBF 
    607         { "stdout-no-buf",  0, 0, OPT_STDOUT_NO_BUF }, 
    608 #endif 
    609         { "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_IPV6 
    613         { "ipv6",        0, 0, OPT_IPV6}, 
    614 #endif 
    615         { "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 arguments 
    660      * 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_AUTH 
    980             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 #endif 
    984             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 #endif 
    1160  
    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 _IONBF 
    1380         case OPT_STDOUT_NO_BUF: 
    1381             setvbuf(stdout, NULL, _IONBF, 0); 
    1382             break; 
    1383 #endif 
    1384  
    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_IPV6 
    1406         case OPT_IPV6: 
    1407             cfg->ipv6 = PJ_TRUE; 
    1408             break; 
    1409 #endif 
    1410         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 lets 
    1415              * set it to CS3 (DSCP 011000). Note that this will not  
    1416              * 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 settings 
    1518          * are okay. 
    1519          */ 
    1520         /* For now we check if IMS mode is activated by looking if 
    1521          * 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  
    1543103/***************************************************************************** 
    1544  * Console application 
     104 * Callback  
    1545105 */ 
    1546106static void ringback_start(pjsua_call_id call_id) 
     
    1659219        /* Cancel duration timer, if any */ 
    1660220        if (app_config.call_data[call_id].timer.id != PJSUA_INVALID_ID) { 
    1661             struct call_data *cd = &app_config.call_data[call_id]; 
     221            app_call_data *cd = &app_config.call_data[call_id]; 
    1662222            pjsip_endpoint *endpt = pjsua_get_pjsip_endpt(); 
    1663223 
     
    1696256        { 
    1697257            /* Schedule timer to hangup call after the specified duration */ 
    1698             struct call_data *cd = &app_config.call_data[call_id]; 
     258            app_call_data *cd = &app_config.call_data[call_id]; 
    1699259            pjsip_endpoint *endpt = pjsua_get_pjsip_endpt(); 
    1700260            pj_time_val delay; 
     
    1810370    } 
    1811371} 
    1812  
    1813372 
    1814373/* 
     
    26901249}; 
    26911250 
     1251#if defined(PJ_WIN32) && PJ_WIN32!=0 
     1252#include <windows.h> 
     1253 
     1254static pj_thread_desc handler_desc; 
     1255 
     1256static 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 
     1280static void setup_socket_signal() 
     1281{ 
     1282} 
     1283 
     1284#else 
     1285#include <signal.h> 
     1286 
     1287static void setup_socket_signal() 
     1288{ 
     1289    signal(SIGPIPE, SIG_IGN); 
     1290} 
     1291 
     1292#endif 
     1293 
     1294static 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 
    26921311/***************************************************************************** 
    26931312 * Public API 
    26941313 */ 
    26951314 
    2696 pj_status_t app_init(int argc, char *argv[]) 
     1315#if defined(PJ_WIN32) && PJ_WIN32!=0 
     1316PJ_DEF(void) setup_signal_handler(void) 
     1317{ 
     1318    SetConsoleCtrlHandler(&CtrlHandler, TRUE); 
     1319} 
     1320#else 
     1321PJ_DEF(void) setup_signal_handler(void) 
     1322{ 
     1323} 
     1324#endif 
     1325 
     1326int 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 
     1347PJ_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) 
    26971351{ 
    26981352    pjsua_transport_id transport_id = -1; 
     
    27011355    pj_status_t status; 
    27021356 
    2703     app_restart = PJ_FALSE; 
    2704  
    2705     /* Create pjsua */ 
    2706     status = pjsua_create(); 
     1357    /** Setup pjsua **/ 
     1358    status = setup_pjsua(); 
    27071359    if (status != PJ_SUCCESS) 
    27081360        return status; 
    27091361 
    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); 
    27181364    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 
    27201373 
    27211374    /* Initialize application callbacks */ 
     
    32371890    } 
    32381891 
     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 */     
    32391898    if (app_config.use_cli) { 
    3240         /* 
    3241          * Init CLI 
    3242          */     
    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        } 
    32491908    } 
    32501909 
     
    32521911 
    32531912on_error: 
     1913    app_restart = PJ_FALSE; 
    32541914    app_destroy(); 
    32551915    return status; 
     
    32591919{ 
    32601920    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     } 
    32691921 
    32701922    /* Start console refresh thread */ 
     
    32751927 
    32761928    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); 
    32801932 
    32811933    if (stdout_refresh_thread) { 
     
    32881940} 
    32891941 
    3290 pj_status_t app_destroy(void) 
     1942pj_status_t app_destroy() 
    32911943{ 
    32921944    pj_status_t status; 
     
    33441996 
    33451997    if (app_config.use_cli) {    
    3346         destroy_cli(); 
     1998        destroy_cli(app_restart); 
    33471999    } 
    33482000 
     
    33512003        app_config.pool = NULL; 
    33522004    } 
    3353  
     2005     
    33542006    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     
    33582011    return status; 
    33592012} 
    33602013 
     2014/** === CLI Callback == **/ 
     2015 
     2016static 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 
     2023static void cli_on_quit (pj_bool_t is_restarted) 
     2024{ 
     2025    PJ_LOG(3,(THIS_FILE, "CLI quit, restart(%d)", is_restarted)); 
     2026} 
     2027 
     2028static void cli_on_destroy(void) 
     2029{ 
     2030    PJ_LOG(3,(THIS_FILE, "CLI destroyed")); 
     2031} 
     2032 
     2033static void cli_on_restart_pjsua(void) 
     2034{ 
     2035    PJ_LOG(3,(THIS_FILE, "Restart pjsua")); 
     2036} 
     2037 
     2038/** ======================= **/ 
     2039 
     2040int 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} 
    33612073 
    33622074#ifdef STEREO_DEMO 
     
    34312143} 
    34322144#endif 
    3433  
Note: See TracChangeset for help on using the changeset viewer.