Changeset 476


Ignore:
Timestamp:
May 26, 2006 12:17:46 PM (18 years ago)
Author:
bennylp
Message:

First stage in pjsua library re-arrangements towards creating an easy to use high level API

Location:
pjproject/trunk
Files:
3 added
10 edited

Legend:

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

    r422 r476  
    1818 */ 
    1919#include <pjsua-lib/pjsua.h> 
    20 #include <stdlib.h>             /* atoi */ 
    21 #include <stdio.h> 
     20#include <pjsua-lib/pjsua_console_app.h> 
     21 
    2222 
    2323#define THIS_FILE       "main.c" 
    24  
    25 /* Current dialog */ 
    26 static int current_acc; 
    27 static int current_call = -1; 
    28  
    29  
    30 /* 
    31  * Find next call. 
    32  */ 
    33 static pj_bool_t find_next_call(void) 
    34 { 
    35     int i; 
    36  
    37     for (i=current_call+1; i<(int)pjsua.max_calls; ++i) { 
    38         if (pjsua.calls[i].inv != NULL) { 
    39             current_call = i; 
    40             return PJ_TRUE; 
    41         } 
    42     } 
    43  
    44     for (i=0; i<current_call; ++i) { 
    45         if (pjsua.calls[i].inv != NULL) { 
    46             current_call = i; 
    47             return PJ_TRUE; 
    48         } 
    49     } 
    50  
    51     current_call = -1; 
    52     return PJ_FALSE; 
    53 } 
    54  
    55  
    56 /* 
    57  * Find previous call. 
    58  */ 
    59 static pj_bool_t find_prev_call(void) 
    60 { 
    61     int i; 
    62  
    63     for (i=current_call-1; i>=0; --i) { 
    64         if (pjsua.calls[i].inv != NULL) { 
    65             current_call = i; 
    66             return PJ_TRUE; 
    67         } 
    68     } 
    69  
    70     for (i=pjsua.max_calls-1; i>current_call; --i) { 
    71         if (pjsua.calls[i].inv != NULL) { 
    72             current_call = i; 
    73             return PJ_TRUE; 
    74         } 
    75     } 
    76  
    77     current_call = -1; 
    78     return PJ_FALSE; 
    79 } 
    80  
    81  
    82  
    83 /* 
    84  * Notify UI when invite state has changed. 
    85  */ 
    86 void pjsua_ui_on_call_state(int call_index, pjsip_event *e) 
    87 { 
    88     pjsua_call *call = &pjsua.calls[call_index]; 
    89  
    90     PJ_UNUSED_ARG(e); 
    91  
    92     if (call->inv->state == PJSIP_INV_STATE_DISCONNECTED) { 
    93  
    94         PJ_LOG(3,(THIS_FILE, "Call %d is DISCONNECTED [reason=%d (%s)]",  
    95                   call_index, 
    96                   call->inv->cause, 
    97                   pjsip_get_status_text(call->inv->cause)->ptr)); 
    98  
    99         call->inv = NULL; 
    100         if ((int)call->index == current_call) { 
    101             find_next_call(); 
    102         } 
    103  
    104     } else { 
    105  
    106         PJ_LOG(3,(THIS_FILE, "Call %d state changed to %s",  
    107                   call_index, 
    108                   pjsua_inv_state_names[call->inv->state])); 
    109  
    110         if (call && current_call==-1) 
    111             current_call = call->index; 
    112  
    113     } 
    114 } 
    115  
    116 /** 
    117  * Notify UI when registration status has changed. 
    118  */ 
    119 void pjsua_ui_on_reg_state(int acc_index) 
    120 { 
    121     PJ_UNUSED_ARG(acc_index); 
    122  
    123     // Log already written. 
    124 } 
    125  
    126  
    127 /** 
    128  * Incoming IM message (i.e. MESSAGE request)! 
    129  */ 
    130 void pjsua_ui_on_pager(int call_index, const pj_str_t *from,  
    131                        const pj_str_t *to, const pj_str_t *text) 
    132 { 
    133     /* Note: call index may be -1 */ 
    134     PJ_UNUSED_ARG(call_index); 
    135     PJ_UNUSED_ARG(to); 
    136  
    137     PJ_LOG(3,(THIS_FILE,"MESSAGE from %.*s: %.*s", 
    138               (int)from->slen, from->ptr, 
    139               (int)text->slen, text->ptr)); 
    140 } 
    141  
    142  
    143 /** 
    144  * Typing indication 
    145  */ 
    146 void pjsua_ui_on_typing(int call_index, const pj_str_t *from, 
    147                         const pj_str_t *to, pj_bool_t is_typing) 
    148 { 
    149     PJ_UNUSED_ARG(call_index); 
    150     PJ_UNUSED_ARG(to); 
    151  
    152     PJ_LOG(3,(THIS_FILE, "IM indication: %.*s %s", 
    153               (int)from->slen, from->ptr, 
    154               (is_typing?"is typing..":"has stopped typing"))); 
    155 } 
    156  
    157  
    158 /* 
    159  * Print buddy list. 
    160  */ 
    161 static void print_buddy_list(void) 
    162 { 
    163     int i; 
    164  
    165     puts("Buddy list:"); 
    166  
    167     if (pjsua.buddy_cnt == 0) 
    168         puts(" -none-"); 
    169     else { 
    170         for (i=0; i<pjsua.buddy_cnt; ++i) { 
    171             const char *status; 
    172  
    173             if (pjsua.buddies[i].sub == NULL ||  
    174                 pjsua.buddies[i].status.info_cnt==0) 
    175             { 
    176                 status = "   ?   "; 
    177             }  
    178             else if (pjsua.buddies[i].status.info[0].basic_open) 
    179                 status = " Online"; 
    180             else 
    181                 status = "Offline"; 
    182  
    183             printf(" [%2d] <%s>  %s\n",  
    184                     i+1, status, pjsua.buddies[i].uri.ptr); 
    185         } 
    186     } 
    187     puts(""); 
    188 } 
    189  
    190  
    191 /* 
    192  * Print account status. 
    193  */ 
    194 static void print_acc_status(int acc_index) 
    195 { 
    196     char reg_status[128]; 
    197  
    198     if (pjsua.acc[acc_index].regc == NULL) { 
    199         pj_ansi_strcpy(reg_status, " -not registered to server-"); 
    200  
    201     } else if (pjsua.acc[acc_index].reg_last_err != PJ_SUCCESS) { 
    202         pj_strerror(pjsua.acc[acc_index].reg_last_err, reg_status, sizeof(reg_status)); 
    203  
    204     } else if (pjsua.acc[acc_index].reg_last_code>=200 &&  
    205                pjsua.acc[acc_index].reg_last_code<=699) { 
    206  
    207         pjsip_regc_info info; 
    208         const pj_str_t *status_str; 
    209  
    210         pjsip_regc_get_info(pjsua.acc[acc_index].regc, &info); 
    211  
    212         status_str = pjsip_get_status_text(pjsua.acc[acc_index].reg_last_code); 
    213         pj_ansi_snprintf(reg_status, sizeof(reg_status), 
    214                          "%s (%.*s;expires=%d)", 
    215                          status_str->ptr, 
    216                          (int)info.client_uri.slen, 
    217                          info.client_uri.ptr, 
    218                          info.next_reg); 
    219  
    220     } else { 
    221         pj_ansi_sprintf(reg_status, "in progress (%d)",  
    222                         pjsua.acc[acc_index].reg_last_code); 
    223     } 
    224  
    225     printf("[%2d] Registration status: %s\n", acc_index, reg_status); 
    226     printf("     Online status: %s\n",  
    227            (pjsua.acc[acc_index].online_status ? "Online" : "Invisible")); 
    228 } 
    229  
    230 /* 
    231  * Show a bit of help. 
    232  */ 
    233 static void keystroke_help(void) 
    234 { 
    235     int i; 
    236  
    237     printf(">>>>\n"); 
    238  
    239     for (i=0; i<pjsua.acc_cnt; ++i) 
    240         print_acc_status(i); 
    241  
    242     print_buddy_list(); 
    243      
    244     //puts("Commands:"); 
    245     puts("+=============================================================================+"); 
    246     puts("|       Call Commands:         |      IM & Presence:      |   Misc:           |"); 
    247     puts("|                              |                          |                   |"); 
    248     puts("|  m  Make new call            |  i  Send IM              |  o  Send OPTIONS  |"); 
    249     puts("|  M  Make multiple calls      |  s  Subscribe presence   | rr  (Re-)register |"); 
    250     puts("|  a  Answer call              |  u  Unsubscribe presence | ru  Unregister    |"); 
    251     puts("|  h  Hangup call  (ha=all)    |  t  ToGgle Online status |                   |"); 
    252     puts("|  H  Hold call                |                          |                   |"); 
    253     puts("|  v  re-inVite (release hold) +--------------------------+-------------------+"); 
    254     puts("|  ]  Select next dialog       |     Conference Command   |                   |"); 
    255     puts("|  [  Select previous dialog   | cl  List ports           |  d  Dump status   |"); 
    256     puts("|  x  Xfer call                | cc  Connect port         | dd  Dump detailed |"); 
    257     puts("|  #  Send DTMF string         | cd  Disconnect port      | dc  Dump config   |"); 
    258     puts("+------------------------------+--------------------------+-------------------+"); 
    259     puts("|  q  QUIT                                                                    |"); 
    260     puts("+=============================================================================+"); 
    261 } 
    262  
    263  
    264 /* 
    265  * Input simple string 
    266  */ 
    267 static pj_bool_t simple_input(const char *title, char *buf, pj_size_t len) 
    268 { 
    269     char *p; 
    270  
    271     printf("%s (empty to cancel): ", title); fflush(stdout); 
    272     fgets(buf, len, stdin); 
    273  
    274     /* Remove trailing newlines. */ 
    275     for (p=buf; ; ++p) { 
    276         if (*p=='\r' || *p=='\n') *p='\0'; 
    277         else if (!*p) break; 
    278     } 
    279  
    280     if (!*buf) 
    281         return PJ_FALSE; 
    282      
    283     return PJ_TRUE; 
    284 } 
    285  
    286  
    287 #define NO_NB   -2 
    288 struct input_result 
    289 { 
    290     int   nb_result; 
    291     char *uri_result; 
    292 }; 
    293  
    294  
    295 /* 
    296  * Input URL. 
    297  */ 
    298 static void ui_input_url(const char *title, char *buf, int len,  
    299                          struct input_result *result) 
    300 { 
    301     result->nb_result = NO_NB; 
    302     result->uri_result = NULL; 
    303  
    304     print_buddy_list(); 
    305  
    306     printf("Choices:\n" 
    307            "   0         For current dialog.\n" 
    308            "  -1         All %d buddies in buddy list\n" 
    309            "  [1 -%2d]    Select from buddy list\n" 
    310            "  URL        An URL\n" 
    311            "  <Enter>    Empty input (or 'q') to cancel\n" 
    312            , pjsua.buddy_cnt, pjsua.buddy_cnt); 
    313     printf("%s: ", title); 
    314  
    315     fflush(stdout); 
    316     fgets(buf, len, stdin); 
    317     len = strlen(buf); 
    318  
    319     /* Left trim */ 
    320     while (pj_isspace(*buf)) { 
    321         ++buf; 
    322         --len; 
    323     } 
    324  
    325     /* Remove trailing newlines */ 
    326     while (len && (buf[len-1] == '\r' || buf[len-1] == '\n')) 
    327         buf[--len] = '\0'; 
    328  
    329     if (len == 0 || buf[0]=='q') 
    330         return; 
    331  
    332     if (pj_isdigit(*buf) || *buf=='-') { 
    333          
    334         int i; 
    335          
    336         if (*buf=='-') 
    337             i = 1; 
    338         else 
    339             i = 0; 
    340  
    341         for (; i<len; ++i) { 
    342             if (!pj_isdigit(buf[i])) { 
    343                 puts("Invalid input"); 
    344                 return; 
    345             } 
    346         } 
    347  
    348         result->nb_result = atoi(buf); 
    349  
    350         if (result->nb_result >= 0 && result->nb_result <= (int)pjsua.buddy_cnt) { 
    351             return; 
    352         } 
    353         if (result->nb_result == -1) 
    354             return; 
    355  
    356         puts("Invalid input"); 
    357         result->nb_result = NO_NB; 
    358         return; 
    359  
    360     } else { 
    361         pj_status_t status; 
    362  
    363         if ((status=pjsua_verify_sip_url(buf)) != PJ_SUCCESS) { 
    364             pjsua_perror(THIS_FILE, "Invalid URL", status); 
    365             return; 
    366         } 
    367  
    368         result->uri_result = buf; 
    369     } 
    370 } 
    371  
    372 static void conf_list(void) 
    373 { 
    374     unsigned i, count; 
    375     pjmedia_conf_port_info info[PJSUA_MAX_CALLS]; 
    376  
    377     printf("Conference ports:\n"); 
    378  
    379     count = PJ_ARRAY_SIZE(info); 
    380     pjmedia_conf_get_ports_info(pjsua.mconf, &count, info); 
    381     for (i=0; i<count; ++i) { 
    382         char txlist[PJSUA_MAX_CALLS*4+10]; 
    383         int j; 
    384         pjmedia_conf_port_info *port_info = &info[i];    
    385          
    386         txlist[0] = '\0'; 
    387         for (j=0; j<pjsua.max_calls+PJSUA_CONF_MORE_PORTS; ++j) { 
    388             char s[10]; 
    389             if (port_info->listener[j]) { 
    390                 pj_ansi_sprintf(s, "#%d ", j); 
    391                 pj_ansi_strcat(txlist, s); 
    392             } 
    393         } 
    394         printf("Port #%02d[%2dKHz/%dms] %20.*s  transmitting to: %s\n",  
    395                port_info->slot,  
    396                port_info->clock_rate/1000, 
    397                port_info->samples_per_frame * 1000 / port_info->clock_rate, 
    398                (int)port_info->name.slen,  
    399                port_info->name.ptr, 
    400                txlist); 
    401  
    402     } 
    403     puts(""); 
    404 } 
    405  
    406  
    407 static void ui_console_main(void) 
    408 { 
    409     char menuin[10]; 
    410     char buf[128]; 
    411     char text[128]; 
    412     int i, count; 
    413     char *uri; 
    414     struct input_result result; 
    415  
    416  
    417     /* If user specifies URI to call, then call the URI */ 
    418     if (pjsua.uri_to_call.slen) { 
    419         pjsua_make_call( current_acc, pjsua.uri_to_call.ptr, NULL); 
    420     } 
    421  
    422     keystroke_help(); 
    423  
    424     for (;;) { 
    425  
    426         printf(">>> "); 
    427         fflush(stdout); 
    428  
    429         fgets(menuin, sizeof(menuin), stdin); 
    430  
    431         switch (menuin[0]) { 
    432  
    433         case 'm': 
    434             /* Make call! : */ 
    435             printf("(You currently have %d calls)\n", pjsua.call_cnt); 
    436              
    437             uri = NULL; 
    438             ui_input_url("Make call", buf, sizeof(buf), &result); 
    439             if (result.nb_result != NO_NB) { 
    440  
    441                 if (result.nb_result == -1 || result.nb_result == 0) { 
    442                     puts("You can't do that with make call!"); 
    443                     continue; 
    444                 } else { 
    445                     uri = pjsua.buddies[result.nb_result-1].uri.ptr; 
    446                 } 
    447  
    448             } else if (result.uri_result) { 
    449                 uri = result.uri_result; 
    450             } 
    451              
    452             pjsua_make_call( current_acc, uri, NULL); 
    453             break; 
    454  
    455         case 'M': 
    456             /* Make multiple calls! : */ 
    457             printf("(You currently have %d calls)\n", pjsua.call_cnt); 
    458              
    459             if (!simple_input("Number of calls", menuin, sizeof(menuin))) 
    460                 continue; 
    461  
    462             count = atoi(menuin); 
    463             if (count < 1) 
    464                 continue; 
    465  
    466             ui_input_url("Make call", buf, sizeof(buf), &result); 
    467             if (result.nb_result != NO_NB) { 
    468                 if (result.nb_result == -1 || result.nb_result == 0) { 
    469                     puts("You can't do that with make call!"); 
    470                     continue; 
    471                 } 
    472                 uri = pjsua.buddies[result.nb_result-1].uri.ptr; 
    473             } else { 
    474                 uri =  result.uri_result; 
    475             } 
    476  
    477             for (i=0; i<atoi(menuin); ++i) { 
    478                 pj_status_t status; 
    479  
    480                 status = pjsua_make_call(current_acc, uri, NULL); 
    481                 if (status != PJ_SUCCESS) 
    482                     break; 
    483             } 
    484             break; 
    485  
    486         case 'i': 
    487             /* Send instant messaeg */ 
    488  
    489             /* i is for call index to send message, if any */ 
    490             i = -1; 
    491      
    492             /* Make compiler happy. */ 
    493             uri = NULL; 
    494  
    495             /* Input destination. */ 
    496             ui_input_url("Send IM to", buf, sizeof(buf), &result); 
    497             if (result.nb_result != NO_NB) { 
    498  
    499                 if (result.nb_result == -1) { 
    500                     puts("You can't send broadcast IM like that!"); 
    501                     continue; 
    502  
    503                 } else if (result.nb_result == 0) { 
    504      
    505                     i = current_call; 
    506  
    507                 } else { 
    508                     uri = pjsua.buddies[result.nb_result-1].uri.ptr; 
    509                 } 
    510  
    511             } else if (result.uri_result) { 
    512                 uri = result.uri_result; 
    513             } 
    514              
    515  
    516             /* Send typing indication. */ 
    517             if (i != -1) 
    518                 pjsua_call_typing(i, PJ_TRUE); 
    519             else 
    520                 pjsua_im_typing(current_acc, uri, PJ_TRUE); 
    521  
    522             /* Input the IM . */ 
    523             if (!simple_input("Message", text, sizeof(text))) { 
    524                 /* 
    525                  * Cancelled. 
    526                  * Send typing notification too, saying we're not typing. 
    527                  */ 
    528                 if (i != -1) 
    529                     pjsua_call_typing(i, PJ_FALSE); 
    530                 else 
    531                     pjsua_im_typing(current_acc, uri, PJ_FALSE); 
    532                 continue; 
    533             } 
    534  
    535             /* Send the IM */ 
    536             if (i != -1) 
    537                 pjsua_call_send_im(i, text); 
    538             else 
    539                 pjsua_im_send(current_acc, uri, text); 
    540  
    541             break; 
    542  
    543         case 'a': 
    544  
    545             if (current_call == -1 ||  
    546                 pjsua.calls[current_call].inv->role != PJSIP_ROLE_UAS || 
    547                 pjsua.calls[current_call].inv->state >= PJSIP_INV_STATE_CONNECTING) 
    548             { 
    549                 puts("No pending incoming call"); 
    550                 fflush(stdout); 
    551                 continue; 
    552  
    553             } else { 
    554                 pj_status_t status; 
    555                 pjsip_tx_data *tdata; 
    556  
    557                 if (!simple_input("Answer with code (100-699)", buf, sizeof(buf))) 
    558                     continue; 
    559                  
    560                 if (atoi(buf) < 100) 
    561                     continue; 
    562  
    563                 /* 
    564                  * Must check again! 
    565                  * Call may have been disconnected while we're waiting for  
    566                  * keyboard input. 
    567                  */ 
    568                 if (current_call == -1) { 
    569                     puts("Call has been disconnected"); 
    570                     fflush(stdout); 
    571                     continue; 
    572                 } 
    573  
    574                 status = pjsip_inv_answer(pjsua.calls[current_call].inv,  
    575                                           atoi(buf),  
    576                                           NULL, NULL, &tdata); 
    577                 if (status == PJ_SUCCESS) 
    578                     status = pjsip_inv_send_msg(pjsua.calls[current_call].inv, 
    579                                                 tdata); 
    580  
    581                 if (status != PJ_SUCCESS) 
    582                     pjsua_perror(THIS_FILE, "Unable to create/send response",  
    583                                  status); 
    584             } 
    585  
    586             break; 
    587  
    588  
    589         case 'h': 
    590  
    591             if (current_call == -1) { 
    592                 puts("No current call"); 
    593                 fflush(stdout); 
    594                 continue; 
    595  
    596             } else if (menuin[1] == 'a') { 
    597                  
    598                 /* Hangup all calls */ 
    599                 pjsua_call_hangup_all(); 
    600  
    601             } else { 
    602  
    603                 /* Hangup current calls */ 
    604                 pjsua_call_hangup(current_call); 
    605             } 
    606             break; 
    607  
    608         case ']': 
    609         case '[': 
    610             /* 
    611              * Cycle next/prev dialog. 
    612              */ 
    613             if (menuin[0] == ']') { 
    614                 find_next_call(); 
    615  
    616             } else { 
    617                 find_prev_call(); 
    618             } 
    619  
    620             if (current_call != -1) { 
    621                 char url[PJSIP_MAX_URL_SIZE]; 
    622                 int len; 
    623                 const pjsip_uri *u; 
    624  
    625                 u = pjsua.calls[current_call].inv->dlg->remote.info->uri; 
    626                 len = pjsip_uri_print(0, u, url, sizeof(url)-1); 
    627                 if (len < 1) { 
    628                     pj_ansi_strcpy(url, "<uri is too long>"); 
    629                 } else { 
    630                     url[len] = '\0'; 
    631                 } 
    632  
    633                 PJ_LOG(3,(THIS_FILE,"Current dialog: %s", url)); 
    634  
    635             } else { 
    636                 PJ_LOG(3,(THIS_FILE,"No current dialog")); 
    637             } 
    638             break; 
    639  
    640         case 'H': 
    641             /* 
    642              * Hold call. 
    643              */ 
    644             if (current_call != -1) { 
    645                  
    646                 pjsua_call_set_hold(current_call); 
    647  
    648             } else { 
    649                 PJ_LOG(3,(THIS_FILE, "No current call")); 
    650             } 
    651             break; 
    652  
    653         case 'v': 
    654             /* 
    655              * Send re-INVITE (to release hold, etc). 
    656              */ 
    657             if (current_call != -1) { 
    658                  
    659                 pjsua_call_reinvite(current_call); 
    660  
    661             } else { 
    662                 PJ_LOG(3,(THIS_FILE, "No current call")); 
    663             } 
    664             break; 
    665  
    666         case 'x': 
    667             /* 
    668              * Transfer call. 
    669              */ 
    670             if (current_call == -1) { 
    671                  
    672                 PJ_LOG(3,(THIS_FILE, "No current call")); 
    673  
    674             } else { 
    675                 int call = current_call; 
    676  
    677                 ui_input_url("Transfer to URL", buf, sizeof(buf), &result); 
    678  
    679                 /* Check if call is still there. */ 
    680  
    681                 if (call != current_call) { 
    682                     puts("Call has been disconnected"); 
    683                     continue; 
    684                 } 
    685  
    686                 if (result.nb_result != NO_NB) { 
    687                     if (result.nb_result == -1 || result.nb_result == 0) 
    688                         puts("You can't do that with transfer call!"); 
    689                     else 
    690                         pjsua_call_xfer( current_call, 
    691                                          pjsua.buddies[result.nb_result-1].uri.ptr); 
    692  
    693                 } else if (result.uri_result) { 
    694                     pjsua_call_xfer( current_call, result.uri_result); 
    695                 } 
    696             } 
    697             break; 
    698  
    699         case '#': 
    700             /* 
    701              * Send DTMF strings. 
    702              */ 
    703             if (current_call == -1) { 
    704                  
    705                 PJ_LOG(3,(THIS_FILE, "No current call")); 
    706  
    707             } else if (pjsua.calls[current_call].session == NULL) { 
    708  
    709                 PJ_LOG(3,(THIS_FILE, "Media is not established yet!")); 
    710  
    711             } else { 
    712                 pj_str_t digits; 
    713                 int call = current_call; 
    714                 pj_status_t status; 
    715  
    716                 if (!simple_input("DTMF strings to send (0-9*#A-B)", buf,  
    717                                   sizeof(buf))) 
    718                 { 
    719                         break; 
    720                 } 
    721  
    722                 if (call != current_call) { 
    723                     puts("Call has been disconnected"); 
    724                     continue; 
    725                 } 
    726  
    727                 digits = pj_str(buf); 
    728                 status = pjmedia_session_dial_dtmf(pjsua.calls[current_call].session, 0,  
    729                                                    &digits); 
    730                 if (status != PJ_SUCCESS) { 
    731                     pjsua_perror(THIS_FILE, "Unable to send DTMF", status); 
    732                 } else { 
    733                     puts("DTMF digits enqueued for transmission"); 
    734                 } 
    735             } 
    736             break; 
    737  
    738         case 's': 
    739         case 'u': 
    740             /* 
    741              * Subscribe/unsubscribe presence. 
    742              */ 
    743             ui_input_url("(un)Subscribe presence of", buf, sizeof(buf), &result); 
    744             if (result.nb_result != NO_NB) { 
    745                 if (result.nb_result == -1) { 
    746                     int i; 
    747                     for (i=0; i<pjsua.buddy_cnt; ++i) 
    748                         pjsua.buddies[i].monitor = (menuin[0]=='s'); 
    749                 } else if (result.nb_result == 0) { 
    750                     puts("Sorry, can only subscribe to buddy's presence, " 
    751                          "not from existing call"); 
    752                 } else { 
    753                     pjsua.buddies[result.nb_result-1].monitor = (menuin[0]=='s'); 
    754                 } 
    755  
    756                 pjsua_pres_refresh(current_acc); 
    757  
    758             } else if (result.uri_result) { 
    759                 puts("Sorry, can only subscribe to buddy's presence, " 
    760                      "not arbitrary URL (for now)"); 
    761             } 
    762  
    763             break; 
    764  
    765         case 'r': 
    766             switch (menuin[1]) { 
    767             case 'r': 
    768                 /* 
    769                  * Re-Register. 
    770                  */ 
    771                 pjsua_regc_update(current_acc, PJ_TRUE); 
    772                 break; 
    773             case 'u': 
    774                 /* 
    775                  * Unregister 
    776                  */ 
    777                 pjsua_regc_update(current_acc, PJ_FALSE); 
    778                 break; 
    779             } 
    780             break; 
    781              
    782         case 't': 
    783             pjsua.acc[current_acc].online_status =  
    784                 !pjsua.acc[current_acc].online_status; 
    785             printf("Setting %s online status to %s\n", 
    786                    pjsua.acc[current_acc].local_uri.ptr, 
    787                    (pjsua.acc[current_acc].online_status?"online":"offline")); 
    788             pjsua_pres_refresh(current_acc); 
    789             break; 
    790  
    791         case 'c': 
    792             switch (menuin[1]) { 
    793             case 'l': 
    794                 conf_list(); 
    795                 break; 
    796             case 'c': 
    797             case 'd': 
    798                 { 
    799                     char src_port[10], dst_port[10]; 
    800                     pj_status_t status; 
    801                     const char *src_title, *dst_title; 
    802  
    803                     conf_list(); 
    804  
    805                     src_title = (menuin[1]=='c'? 
    806                                  "Connect src port #": 
    807                                  "Disconnect src port #"); 
    808                     dst_title = (menuin[1]=='c'? 
    809                                  "To dst port #": 
    810                                  "From dst port #"); 
    811  
    812                     if (!simple_input(src_title, src_port, sizeof(src_port))) 
    813                         break; 
    814  
    815                     if (!simple_input(dst_title, dst_port, sizeof(dst_port))) 
    816                         break; 
    817  
    818                     if (menuin[1]=='c') { 
    819                         status = pjmedia_conf_connect_port(pjsua.mconf,  
    820                                                            atoi(src_port),  
    821                                                            atoi(dst_port), 
    822                                                            0); 
    823                     } else { 
    824                         status = pjmedia_conf_disconnect_port(pjsua.mconf,  
    825                                                               atoi(src_port),  
    826                                                               atoi(dst_port)); 
    827                     } 
    828                     if (status == PJ_SUCCESS) { 
    829                         puts("Success"); 
    830                     } else { 
    831                         puts("ERROR!!"); 
    832                     } 
    833                 } 
    834                 break; 
    835             } 
    836             break; 
    837  
    838         case 'd': 
    839             if (menuin[1] == 'c') { 
    840                 char settings[2000]; 
    841                 int len; 
    842  
    843                 len = pjsua_dump_settings(settings, sizeof(settings)); 
    844                 if (len < 1) 
    845                     PJ_LOG(3,(THIS_FILE, "Error: not enough buffer")); 
    846                 else 
    847                     PJ_LOG(3,(THIS_FILE,  
    848                               "Dumping configuration (%d bytes):\n%s\n", 
    849                               len, settings)); 
    850             } else { 
    851                 pjsua_dump(menuin[1]=='d'); 
    852             } 
    853             break; 
    854  
    855         case 'q': 
    856             goto on_exit; 
    857  
    858         default: 
    859             if (menuin[0] != '\n' && menuin[0] != '\r') { 
    860                 printf("Invalid input %s", menuin); 
    861             } 
    862             keystroke_help(); 
    863             break; 
    864         } 
    865     } 
    866  
    867 on_exit: 
    868     ; 
    869 } 
    870  
    871  
    872 /***************************************************************************** 
    873  * This is a very simple PJSIP module, whose sole purpose is to display 
    874  * incoming and outgoing messages to log. This module will have priority 
    875  * higher than transport layer, which means: 
    876  * 
    877  *  - incoming messages will come to this module first before reaching 
    878  *    transaction layer. 
    879  * 
    880  *  - outgoing messages will come to this module last, after the message 
    881  *    has been 'printed' to contiguous buffer by transport layer and 
    882  *    appropriate transport instance has been decided for this message. 
    883  * 
    884  */ 
    885  
    886 /* Notification on incoming messages */ 
    887 static pj_bool_t console_on_rx_msg(pjsip_rx_data *rdata) 
    888 { 
    889     PJ_LOG(4,(THIS_FILE, "RX %d bytes %s from %s:%d:\n" 
    890                          "%s\n" 
    891                          "--end msg--", 
    892                          rdata->msg_info.len, 
    893                          pjsip_rx_data_get_info(rdata), 
    894                          rdata->pkt_info.src_name, 
    895                          rdata->pkt_info.src_port, 
    896                          rdata->msg_info.msg_buf)); 
    897      
    898     /* Always return false, otherwise messages will not get processed! */ 
    899     return PJ_FALSE; 
    900 } 
    901  
    902 /* Notification on outgoing messages */ 
    903 static pj_status_t console_on_tx_msg(pjsip_tx_data *tdata) 
    904 { 
    905      
    906     /* Important note: 
    907      *  tp_info field is only valid after outgoing messages has passed 
    908      *  transport layer. So don't try to access tp_info when the module 
    909      *  has lower priority than transport layer. 
    910      */ 
    911  
    912     PJ_LOG(4,(THIS_FILE, "TX %d bytes %s to %s:%d:\n" 
    913                          "%s\n" 
    914                          "--end msg--", 
    915                          (tdata->buf.cur - tdata->buf.start), 
    916                          pjsip_tx_data_get_info(tdata), 
    917                          tdata->tp_info.dst_name, 
    918                          tdata->tp_info.dst_port, 
    919                          tdata->buf.start)); 
    920  
    921     /* Always return success, otherwise message will not get sent! */ 
    922     return PJ_SUCCESS; 
    923 } 
    924  
    925 /* The module instance. */ 
    926 static pjsip_module console_msg_logger =  
    927 { 
    928     NULL, NULL,                         /* prev, next.          */ 
    929     { "mod-pjsua-log", 13 },            /* Name.                */ 
    930     -1,                                 /* Id                   */ 
    931     PJSIP_MOD_PRIORITY_TRANSPORT_LAYER-1,/* Priority            */ 
    932     NULL,                               /* load()               */ 
    933     NULL,                               /* start()              */ 
    934     NULL,                               /* stop()               */ 
    935     NULL,                               /* unload()             */ 
    936     &console_on_rx_msg,                 /* on_rx_request()      */ 
    937     &console_on_rx_msg,                 /* on_rx_response()     */ 
    938     &console_on_tx_msg,                 /* on_tx_request.       */ 
    939     &console_on_tx_msg,                 /* on_tx_response()     */ 
    940     NULL,                               /* on_tsx_state()       */ 
    941  
    942 }; 
    943  
    944  
    945  
    946 /***************************************************************************** 
    947  * Console application custom logging: 
    948  */ 
    949  
    950  
    951 static FILE *log_file; 
    952  
    953  
    954 static void app_log_writer(int level, const char *buffer, int len) 
    955 { 
    956     /* Write to both stdout and file. */ 
    957  
    958     if (level <= pjsua.app_log_level) 
    959         pj_log_write(level, buffer, len); 
    960  
    961     if (log_file) { 
    962         fwrite(buffer, len, 1, log_file); 
    963         fflush(log_file); 
    964     } 
    965 } 
    966  
    967  
    968 pj_status_t app_logging_init(void) 
    969 { 
    970     /* Redirect log function to ours */ 
    971  
    972     pj_log_set_log_func( &app_log_writer ); 
    973  
    974     /* If output log file is desired, create the file: */ 
    975  
    976     if (pjsua.log_filename) { 
    977         log_file = fopen(pjsua.log_filename, "wt"); 
    978         if (log_file == NULL) { 
    979             PJ_LOG(1,(THIS_FILE, "Unable to open log file %s",  
    980                       pjsua.log_filename));    
    981             return -1; 
    982         } 
    983     } 
    984  
    985     return PJ_SUCCESS; 
    986 } 
    987  
    988  
    989 void app_logging_shutdown(void) 
    990 { 
    991     /* Close logging file, if any: */ 
    992  
    993     if (log_file) { 
    994         fclose(log_file); 
    995         log_file = NULL; 
    996     } 
    997 } 
    998  
    999 /***************************************************************************** 
    1000  * Error display: 
    1001  */ 
    1002  
    1003 /* 
    1004  * Display error message for the specified error code. 
    1005  */ 
    1006 void pjsua_perror(const char *sender, const char *title,  
    1007                   pj_status_t status) 
    1008 { 
    1009     char errmsg[PJ_ERR_MSG_SIZE]; 
    1010  
    1011     pj_strerror(status, errmsg, sizeof(errmsg)); 
    1012  
    1013     PJ_LOG(1,(sender, "%s: %s [code=%d]", title, errmsg, status)); 
    1014 } 
    1015  
    1016  
    1017  
    101824 
    101925/***************************************************************************** 
     
    102329{ 
    102430 
     31    pjsua_config cfg; 
     32 
    102533    /* Init default settings. */ 
    1026     pjsua_default(); 
     34    pjsua_default_config(&cfg); 
    102735 
    102836 
    1029     /* Initialize pjsua (to create pool etc). 
    1030      */ 
    1031     if (pjsua_init() != PJ_SUCCESS) 
    1032         return 1; 
     37    /* Create PJLIB and memory pool */ 
     38    pjsua_create(); 
    103339 
    103440 
    103541    /* Parse command line arguments: */ 
    1036     if (pjsua_parse_args(argc, argv) != PJ_SUCCESS) 
     42    if (pjsua_parse_args(argc, argv, &cfg) != PJ_SUCCESS) 
    103743        return 1; 
    103844 
    103945 
    104046    /* Init logging: */ 
    1041     if (app_logging_init() != PJ_SUCCESS) 
     47    if (pjsua_console_app_logging_init(&cfg) != PJ_SUCCESS) 
    104248        return 1; 
    104349 
     50 
     51    /* Init pjsua */ 
     52    if (pjsua_init(&cfg, &console_callback) != PJ_SUCCESS) 
     53        return 1; 
    104454 
    104555    /* Register message logger to print incoming and outgoing 
    104656     * messages. 
    104757     */ 
    1048     pjsip_endpt_register_module(pjsua.endpt, &console_msg_logger); 
     58    pjsip_endpt_register_module(pjsua.endpt,  
     59                                &pjsua_console_app_msg_logger); 
    104960 
    105061 
     
    106273 
    106374    /* Start UI console main loop: */ 
    1064     ui_console_main(); 
     75    pjsua_console_app_main(); 
    106576 
    106677 
     
    107081 
    107182    /* Close logging: */ 
    1072     app_logging_shutdown(); 
     83    pjsua_console_app_logging_shutdown(); 
    107384 
    107485 
  • pjproject/trunk/pjsip/build/pjsua_lib.dsp

    r360 r476  
    9292# Begin Source File 
    9393 
     94SOURCE="..\src\pjsua-lib\pjsua_console_app.c" 
     95# End Source File 
     96# Begin Source File 
     97 
    9498SOURCE="..\src\pjsua-lib\pjsua_core.c" 
    9599# End Source File 
     
    97101 
    98102SOURCE="..\src\pjsua-lib\pjsua_im.c" 
     103# End Source File 
     104# Begin Source File 
     105 
     106SOURCE="..\src\pjsua-lib\pjsua_imp.h" 
    99107# End Source File 
    100108# Begin Source File 
     
    118126SOURCE="..\include\pjsua-lib\pjsua.h" 
    119127# End Source File 
     128# Begin Source File 
     129 
     130SOURCE="..\include\pjsua-lib\pjsua_console_app.h" 
     131# End Source File 
    120132# End Group 
    121133# End Target 
  • pjproject/trunk/pjsip/include/pjsua-lib/pjsua.h

    r452 r476  
    4949 */ 
    5050#ifndef PJSUA_MAX_BUDDIES 
    51 #   define PJSUA_MAX_BUDDIES        32 
     51#   define PJSUA_MAX_BUDDIES        256 
    5252#endif 
    5353 
     
    6262 
    6363/** 
    64  * Aditional ports to be allocated in the conference ports for non-call 
    65  * streams. 
    66  */ 
    67 #define PJSUA_CONF_MORE_PORTS       3 
    68  
    69  
    70 /** 
    7164 * Maximum accounts. 
    7265 */ 
    7366#ifndef PJSUA_MAX_ACC 
    74 #   define PJSUA_MAX_ACC            8 
     67#   define PJSUA_MAX_ACC            32 
    7568#endif 
    7669 
    77  
    78 /** 
    79  * Maximum credentials. 
    80  */ 
    81 #ifndef PJSUA_MAX_CRED 
    82 #   define PJSUA_MAX_CRED           PJSUA_MAX_ACC 
    83 #endif 
    8470 
    8571 
     
    141127 
    142128/** 
     129 * Account configuration. 
     130 */ 
     131struct pjsua_acc_config 
     132{ 
     133    /** SIP URL for account ID (mandatory) */ 
     134    pj_str_t        id; 
     135 
     136    /** Registrar URI (mandatory) */ 
     137    pj_str_t        reg_uri; 
     138 
     139    /** Optional contact URI */ 
     140    pj_str_t        contact; 
     141 
     142    /** Service proxy (default: none) */ 
     143    pj_str_t        proxy; 
     144 
     145    /** Default timeout (mandatory) */ 
     146    pj_int32_t      reg_timeout; 
     147 
     148    /** Number of credentials. */ 
     149    unsigned        cred_count; 
     150 
     151    /** Array of credentials. */ 
     152    pjsip_cred_info cred_info[4]; 
     153 
     154}; 
     155 
     156 
     157/** 
     158 * @see pjsua_acc_config 
     159 */ 
     160typedef struct pjsua_acc_config pjsua_acc_config; 
     161 
     162 
     163/** 
    143164 * Account 
    144165 */ 
     
    146167{ 
    147168    int              index;         /**< Index in accounts array.       */ 
    148     pj_str_t         local_uri;     /**< Uri in From: header.           */ 
    149169    pj_str_t         user_part;     /**< User part of local URI.        */ 
    150170    pj_str_t         host_part;     /**< Host part of local URI.        */ 
    151     pj_str_t         contact_uri;   /**< Uri in Contact: header.        */ 
    152  
    153     pj_str_t         reg_uri;       /**< Registrar URI.                 */ 
     171 
    154172    pjsip_regc      *regc;          /**< Client registration session.   */ 
    155     pj_int32_t       reg_timeout;   /**< Default timeout.               */ 
    156173    pj_timer_entry   reg_timer;     /**< Registration timer.            */ 
    157174    pj_status_t      reg_last_err;  /**< Last registration error.       */ 
    158175    int              reg_last_code; /**< Last status last register.     */ 
    159176 
    160     pj_str_t         proxy;         /**< Proxy URL.                     */ 
    161177    pjsip_route_hdr  route_set;     /**< Route set.                     */ 
    162178 
     
    168184 
    169185 
     186/** 
     187 * @see pjsua_acc 
     188 */ 
    170189typedef struct pjsua_acc pjsua_acc; 
     190 
     191 
     192/** 
     193 * PJSUA settings. 
     194 */ 
     195struct pjsua_config 
     196{ 
     197    /** SIP UDP signaling port. Set to zero to disable UDP signaling, 
     198     * which in this case application must manually add a transport 
     199     * to SIP endpoint. 
     200     * (default: 5060)  
     201     */ 
     202    unsigned    udp_port; 
     203 
     204    /** Optional hostname or IP address to publish as the host part of 
     205     *  Contact header. This must be specified if UDP transport is 
     206     *  disabled. 
     207     *  (default: NULL) 
     208     */ 
     209    pj_str_t    sip_host; 
     210 
     211    /** Optional port number to publish in the port part of Contact header. 
     212     *  This must be specified if UDP transport is disabled. 
     213     *  (default: 0) 
     214     */ 
     215    unsigned    sip_port; 
     216 
     217    /** Start of RTP port. Set to zero to prevent pjsua from creating 
     218     *  media transports, which in this case application must manually 
     219     *  create media transport for each calls. 
     220     *  (default: 4000)  
     221     */ 
     222    unsigned    start_rtp_port; 
     223 
     224    /** Maximum calls to support (default: 4) */ 
     225    unsigned    max_calls; 
     226 
     227    /** Maximum slots in the conference bridge (default: 0/calculated 
     228     *  as max_calls*2 
     229     */ 
     230    unsigned    conf_ports; 
     231 
     232    /** Number of worker threads (default: 1) */ 
     233    unsigned    thread_cnt; 
     234 
     235    /** First STUN server IP address. When STUN is configured, then the 
     236     *  two STUN server settings must be fully set. 
     237     *  (default: none)  
     238     */ 
     239    pj_str_t    stun_srv1; 
     240 
     241    /** First STUN port number */ 
     242    unsigned    stun_port1; 
     243 
     244    /** Second STUN server IP address */ 
     245    pj_str_t    stun_srv2; 
     246 
     247    /** Second STUN server port number */ 
     248    unsigned    stun_port2; 
     249 
     250    /** Internal clock rate (to be applied to sound devices and conference 
     251     *  bridge, default is 0/follows the codec, or 44100 for MacOS). 
     252     */ 
     253    unsigned    clock_rate; 
     254 
     255    /** Do not use sound device (default: 0). */ 
     256    pj_bool_t   null_audio; 
     257 
     258    /** WAV file to load for auto_play (default: NULL) */ 
     259    pj_str_t    wav_file; 
     260 
     261    /** Auto play WAV file for calls? (default: no) */ 
     262    pj_bool_t   auto_play; 
     263 
     264    /** Auto loopback calls? (default: no) */ 
     265    pj_bool_t   auto_loop; 
     266 
     267    /** Automatically put calls to conference? (default: no) */ 
     268    pj_bool_t   auto_conf; 
     269 
     270    /** Speex codec complexity? (default: 10) */ 
     271    unsigned    complexity; 
     272 
     273    /** Speex codec quality? (default: 10) */ 
     274    unsigned    quality; 
     275 
     276    /** Codec ptime? (default: 0 (follows the codec)) */ 
     277    unsigned    ptime; 
     278 
     279    /** Number of additional codecs/"--add-codec" with pjsua (default: 0) */ 
     280    unsigned    codec_cnt; 
     281 
     282    /** Additional codecs/"--add-codec" options */ 
     283    pj_str_t    codec_arg[32]; 
     284 
     285    /** SIP status code to be automatically sent to incoming calls 
     286     *  (default: 100). 
     287     */ 
     288    unsigned    auto_answer; 
     289 
     290    /** Periodic time to refresh call with re-INVITE (default: 0) 
     291     */ 
     292    unsigned    uas_refresh; 
     293 
     294    /** Maximum incoming call duration (default: 3600) */ 
     295    unsigned    uas_duration; 
     296 
     297    /** Outbound proxy (default: none) */ 
     298    pj_str_t    outbound_proxy; 
     299 
     300    /** URI to call.                    */ 
     301    pj_str_t    uri_to_call; 
     302 
     303    /** Number of SIP accounts */ 
     304    unsigned    acc_cnt; 
     305 
     306    /** SIP accounts configuration */ 
     307    pjsua_acc_config    acc_config[32]; 
     308 
     309    /** Logging verbosity (default: 5). */ 
     310    unsigned    log_level; 
     311 
     312    /** Logging to be displayed to stdout (default: 4) */ 
     313    unsigned    app_log_level; 
     314 
     315    /** Log decoration */ 
     316    unsigned    log_decor; 
     317 
     318    /** Optional log filename (default: NULL) */ 
     319    pj_str_t    log_filename; 
     320 
     321    /** Number of buddies in address book (default: 0) */ 
     322    unsigned    buddy_cnt; 
     323 
     324    /** Buddies URI */ 
     325    pj_str_t    buddy_uri[256]; 
     326}; 
     327 
     328 
     329/** 
     330 * @see pjsua_config 
     331 */ 
     332typedef struct pjsua_config pjsua_config; 
     333 
     334 
     335 
     336/** 
     337 * Application callbacks. 
     338 */ 
     339struct pjsua_callback 
     340{ 
     341    /** 
     342     * Notify UI when invite state has changed. 
     343     */ 
     344    void (*on_call_state)(int call_index, pjsip_event *e); 
     345 
     346    /** 
     347     * Notify UI when registration status has changed. 
     348     */ 
     349    void (*on_reg_state)(int acc_index); 
     350 
     351    /** 
     352     * Notify UI on incoming pager (i.e. MESSAGE request). 
     353     * Argument call_index will be -1 if MESSAGE request is not related to an  
     354     * existing call. 
     355     */ 
     356    void (*on_pager)(int call_index, const pj_str_t *from, 
     357                     const pj_str_t *to, const pj_str_t *txt); 
     358 
     359    /** 
     360     * Notify UI about typing indication. 
     361     */ 
     362    void (*on_typing)(int call_index, const pj_str_t *from, 
     363                      const pj_str_t *to, pj_bool_t is_typing); 
     364 
     365}; 
     366 
     367/** 
     368 * @see pjsua_callback 
     369 */ 
     370typedef struct pjsua_callback pjsua_callback; 
    171371 
    172372 
     
    179379    pj_pool_t       *pool;          /**< pjsua's private pool.          */ 
    180380    pjsip_module     mod;           /**< pjsua's PJSIP module.          */ 
     381 
    181382     
     383    /* Config: */ 
     384    pjsua_config    config;         /**< PJSUA configs                  */ 
     385 
     386    /* Application callback: */ 
     387    pjsua_callback  cb;             /**< Application callback.          */ 
    182388 
    183389    /* Media:  */ 
    184     int              start_rtp_port;/**< Start of RTP port to try.      */ 
    185390    pjmedia_endpt   *med_endpt;     /**< Media endpoint.                */ 
    186     unsigned         clock_rate;    /**< Internal clock rate.           */ 
    187391    pjmedia_conf    *mconf;         /**< Media conference.              */ 
    188     pj_bool_t        null_audio;    /**< Null audio flag.               */ 
    189     pj_bool_t        no_mic;        /**< Disable microphone.            */ 
    190     char            *wav_file;      /**< WAV file name to play.         */ 
    191392    unsigned         wav_slot;      /**< WAV player slot in bridge      */ 
    192393    pjmedia_port    *file_port;     /**< WAV player port.               */ 
    193     pjmedia_port    *null_port;     /**< NULL port.                     */ 
    194     pj_bool_t        auto_play;     /**< Auto play file for calls?      */ 
    195     pj_bool_t        auto_loop;     /**< Auto loop RTP stream?          */ 
    196     pj_bool_t        auto_conf;     /**< Auto put to conference?        */ 
    197     int              complexity;    /**< Codec complexity.              */ 
    198     int              quality;       /**< Codec quality.                 */ 
    199     int              ptime;         /**< Codec ptime in msec.           */ 
    200  
    201  
    202     /* Codec arguments: */ 
    203     int              codec_cnt;     /**< Number of --add-codec args.    */ 
    204     pj_str_t         codec_arg[32]; /**< Array of --add-codec args.     */ 
    205     pj_status_t     (*codec_deinit[32])(void);  /**< Array of funcs.    */ 
    206  
    207     /* User Agent behaviour: */ 
    208     int              auto_answer;   /**< Automatically answer in calls. */ 
    209     int              uas_refresh;   /**< Time to re-INVITE.             */ 
    210     int              uas_duration;  /**< Max call duration.             */ 
     394 
    211395 
    212396    /* Account: */ 
    213     pj_bool_t        has_acc;       /**< Any --id cmdline?              */ 
    214     int              acc_cnt;       /**< Number of client registrations */ 
    215397    pjsua_acc        acc[PJSUA_MAX_ACC];    /** Client regs array.      */ 
    216398 
    217399 
    218     /* Authentication credentials: */ 
    219  
    220     int              cred_count;    /**< Number of credentials.         */ 
    221     pjsip_cred_info  cred_info[10]; /**< Array of credentials.          */ 
    222  
    223  
    224400    /* Threading (optional): */ 
    225     int              thread_cnt;    /**< Thread count.                  */ 
    226401    pj_thread_t     *threads[8];    /**< Thread instances.              */ 
    227402    pj_bool_t        quit_flag;     /**< To signal thread to quit.      */ 
    228403 
    229404    /* Transport (UDP): */ 
    230     pj_uint16_t      sip_port;      /**< SIP signaling port.            */ 
    231405    pj_sock_t        sip_sock;      /**< SIP UDP socket.                */ 
    232406    pj_sockaddr_in   sip_sock_name; /**< Public/STUN UDP socket addr.   */ 
    233407 
    234     pj_str_t         outbound_proxy;/**< Outbound proxy.                */ 
    235  
    236  
    237     /* STUN: */ 
    238     pj_str_t         stun_srv1; 
    239     int              stun_port1; 
    240     pj_str_t         stun_srv2; 
    241     int              stun_port2; 
    242  
    243  
    244     /* Logging: */     
    245     int              log_level;     /**< Logging verbosity.             */ 
    246     int              app_log_level; /**< stdout log verbosity.          */ 
    247     unsigned         log_decor;     /**< Log decoration.                */ 
    248     char            *log_filename;  /**< Log filename.                  */ 
    249  
    250408 
    251409    /* PJSUA Calls: */ 
    252     pj_str_t         uri_to_call;   /**< URI to call.                   */ 
    253     int              max_calls;     /**< Max nb of calls.               */ 
    254410    int              call_cnt;      /**< Number of calls.               */ 
    255411    pjsua_call       calls[PJSUA_MAX_CALLS];    /** Calls array.        */ 
     
    274430 * Initialize pjsua settings with default parameters. 
    275431 */ 
    276 void pjsua_default(void); 
    277  
    278  
    279 /** 
    280  * Display error message for the specified error code. 
    281  */ 
    282 void pjsua_perror(const char *sender, const char *title,  
    283                   pj_status_t status); 
    284  
    285  
    286 /** 
    287  * Initialize pjsua application. Application can call this before parsing 
    288  * application settings. 
     432PJ_DECL(void) pjsua_default_config(pjsua_config *cfg); 
     433 
     434 
     435/** 
     436 * Test configuration. 
     437 */ 
     438PJ_DECL(pj_status_t) pjsua_test_config(const pjsua_config *cfg, 
     439                                       char *errmsg, 
     440                                       int len); 
     441 
     442 
     443/** 
     444 * Create pjsua application. 
     445 * This initializes pjlib/pjlib-util, and creates memory pool factory to 
     446 * be used by application. 
     447 */ 
     448PJ_DECL(pj_status_t) pjsua_create(void); 
     449 
     450 
     451/** 
     452 * Initialize pjsua application with the specified settings. 
    289453 * 
    290454 * This will initialize all libraries, create endpoint instance, and register 
    291  * pjsip modules. Transport will NOT be created however. 
     455 * pjsip modules.  
    292456 * 
    293457 * Application may register module after calling this function. 
    294458 */ 
    295 pj_status_t pjsua_init(void); 
     459PJ_DECL(pj_status_t) pjsua_init(const pjsua_config *cfg, 
     460                                const pjsua_callback *cb); 
    296461 
    297462 
     
    303468 * process, if registration is configured. 
    304469 */ 
    305 pj_status_t pjsua_start(void); 
     470PJ_DECL(pj_status_t) pjsua_start(void); 
    306471 
    307472 
     
    309474 * Destroy pjsua. 
    310475 */ 
    311 pj_status_t pjsua_destroy(void); 
    312  
    313  
    314 /** 
    315  * Find account for incoming request. 
    316  */ 
    317 int pjsua_find_account_for_incoming(pjsip_rx_data *rdata); 
    318  
    319  
    320 /** 
    321  * Find account for outgoing request. 
    322  */ 
    323 int pjsua_find_account_for_outgoing(const pj_str_t *url); 
     476PJ_DECL(pj_status_t) pjsua_destroy(void); 
    324477 
    325478 
     
    329482 
    330483/** 
    331  * Init pjsua call module. 
    332  */ 
    333 pj_status_t pjsua_call_init(void); 
    334  
    335 /** 
    336484 * Make outgoing call. 
    337485 */ 
    338 pj_status_t pjsua_make_call(int acc_index, 
    339                             const char *cstr_dest_uri, 
    340                             int *p_call_index); 
    341  
    342  
    343 /** 
    344  * Handle incoming invite request. 
    345  */ 
    346 pj_bool_t pjsua_call_on_incoming(pjsip_rx_data *rdata); 
     486PJ_DECL(pj_status_t) pjsua_make_call(int acc_index, 
     487                                     const char *cstr_dest_uri, 
     488                                     int *p_call_index); 
    347489 
    348490 
     
    350492 * Answer call. 
    351493 */ 
    352 void pjsua_call_answer(int call_index, int code); 
     494PJ_DECL(void) pjsua_call_answer(int call_index, int code); 
    353495 
    354496/** 
    355497 * Hangup call. 
    356498 */ 
    357 void pjsua_call_hangup(int call_index); 
     499PJ_DECL(void) pjsua_call_hangup(int call_index); 
    358500 
    359501 
     
    361503 * Put call on-hold. 
    362504 */ 
    363 void pjsua_call_set_hold(int call_index); 
     505PJ_DECL(void) pjsua_call_set_hold(int call_index); 
    364506 
    365507 
     
    367509 * Send re-INVITE (to release hold). 
    368510 */ 
    369 void pjsua_call_reinvite(int call_index); 
     511PJ_DECL(void) pjsua_call_reinvite(int call_index); 
    370512 
    371513 
     
    373515 * Transfer call. 
    374516 */ 
    375 void pjsua_call_xfer(int call_index, const char *dest); 
     517PJ_DECL(void) pjsua_call_xfer(int call_index, const char *dest); 
    376518 
    377519 
     
    379521 * Send instant messaging inside INVITE session. 
    380522 */ 
    381 void pjsua_call_send_im(int call_index, const char *text); 
     523PJ_DECL(void) pjsua_call_send_im(int call_index, const char *text); 
    382524 
    383525 
     
    385527 * Send IM typing indication inside INVITE session. 
    386528 */ 
    387 void pjsua_call_typing(int call_index, pj_bool_t is_typing); 
     529PJ_DECL(void) pjsua_call_typing(int call_index, pj_bool_t is_typing); 
    388530 
    389531/** 
    390532 * Terminate all calls. 
    391533 */ 
    392 void pjsua_call_hangup_all(void); 
     534PJ_DECL(void) pjsua_call_hangup_all(void); 
    393535 
    394536 
     
    398540 
    399541/** 
    400  * Initialize client registration session. 
    401  * 
    402  * @param app_callback  Optional callback 
    403  */ 
    404 pj_status_t pjsua_regc_init(int acc_index); 
    405  
    406 /** 
    407542 * Update registration or perform unregistration. If renew argument is zero, 
    408543 * this will start unregistration process. 
    409544 */ 
    410 void pjsua_regc_update(int acc_index, pj_bool_t renew); 
     545PJ_DECL(void) pjsua_regc_update(int acc_index, pj_bool_t renew); 
    411546 
    412547 
     
    418553 
    419554/** 
    420  * Init presence. 
    421  */ 
    422 pj_status_t pjsua_pres_init(); 
    423  
    424 /** 
    425555 * Refresh both presence client and server subscriptions. 
    426556 */ 
    427 void pjsua_pres_refresh(int acc_index); 
    428  
    429 /** 
    430  * Terminate all subscriptions 
    431  */ 
    432 void pjsua_pres_shutdown(void); 
     557PJ_DECL(void) pjsua_pres_refresh(int acc_index); 
    433558 
    434559/** 
    435560 * Dump presence subscriptions. 
    436561 */ 
    437 void pjsua_pres_dump(pj_bool_t detail); 
     562PJ_DECL(void) pjsua_pres_dump(pj_bool_t detail); 
    438563 
    439564 
     
    448573 
    449574 
    450 /** 
    451  * Init IM module handler to handle incoming MESSAGE outside dialog. 
    452  */ 
    453 pj_status_t pjsua_im_init(); 
    454  
    455  
    456 /** 
    457  * Create Accept header for MESSAGE. 
    458  */ 
    459 pjsip_accept_hdr* pjsua_im_create_accept(pj_pool_t *pool); 
    460575 
    461576/** 
    462577 * Send IM outside dialog. 
    463578 */ 
    464 pj_status_t pjsua_im_send(int acc_index, const char *dst_uri,  
    465                           const char *text); 
     579PJ_DECL(pj_status_t) pjsua_im_send(int acc_index, const char *dst_uri,  
     580                                   const char *text); 
    466581 
    467582 
     
    469584 * Send typing indication outside dialog. 
    470585 */ 
    471 pj_status_t pjsua_im_typing(int acc_index, const char *dst_uri,  
    472                             pj_bool_t is_typing); 
    473  
    474  
    475 /** 
    476  * Private: check if we can accept the message. 
    477  *          If not, then p_accept header will be filled with a valid 
    478  *          Accept header. 
    479  */ 
    480 pj_bool_t pjsua_im_accept_pager(pjsip_rx_data *rdata, 
    481                                 pjsip_accept_hdr **p_accept_hdr); 
    482  
    483 /** 
    484  * Private: process pager message. 
    485  *          This may trigger pjsua_ui_on_pager() or pjsua_ui_on_typing(). 
    486  */ 
    487 void pjsua_im_process_pager(int call_id, const pj_str_t *from, 
    488                             const pj_str_t *to, pjsip_rx_data *rdata); 
    489  
    490  
    491 /***************************************************************************** 
    492  * User Interface API. 
    493  * 
    494  * The UI API specifies functions that will be called by pjsua upon 
    495  * occurence of various events. 
    496  */ 
    497  
    498 /** 
    499  * Notify UI when invite state has changed. 
    500  */ 
    501 void pjsua_ui_on_call_state(int call_index, pjsip_event *e); 
    502  
    503 /** 
    504  * Notify UI when registration status has changed. 
    505  */ 
    506 void pjsua_ui_on_reg_state(int acc_index); 
    507  
    508 /** 
    509  * Notify UI on incoming pager (i.e. MESSAGE request). 
    510  * Argument call_index will be -1 if MESSAGE request is not related to an  
    511  * existing call. 
    512  */ 
    513 void pjsua_ui_on_pager(int call_index, const pj_str_t *from, 
    514                        const pj_str_t *to, const pj_str_t *txt); 
    515  
    516  
    517 /** 
    518  * Notify UI about typing indication. 
    519  */ 
    520 void pjsua_ui_on_typing(int call_index, const pj_str_t *from, 
    521                         const pj_str_t *to, pj_bool_t is_typing); 
     586PJ_DECL(pj_status_t) pjsua_im_typing(int acc_index, const char *dst_uri,  
     587                                     pj_bool_t is_typing); 
     588 
    522589 
    523590 
     
    533600 * Parse arguments (pjsua_opt.c). 
    534601 */ 
    535 pj_status_t pjsua_parse_args(int argc, char *argv[]); 
     602PJ_DECL(pj_status_t) pjsua_parse_args(int argc, char *argv[], 
     603                                      pjsua_config *cfg); 
    536604 
    537605/** 
    538606 * Load settings from a file. 
    539607 */ 
    540 pj_status_t pjsua_load_settings(const char *filename); 
     608PJ_DECL(pj_status_t) pjsua_load_settings(const char *filename, 
     609                                         pjsua_config *cfg); 
    541610 
    542611/** 
    543612 * Dump settings. 
    544613 */ 
    545 int pjsua_dump_settings(char *buf, pj_size_t max); 
     614PJ_DECL(int) pjsua_dump_settings(const pjsua_config *cfg, 
     615                                 char *buf, pj_size_t max); 
    546616 
    547617/** 
    548618 * Save settings to a file. 
    549619 */ 
    550 pj_status_t pjsua_save_settings(const char *filename); 
     620PJ_DECL(pj_status_t) pjsua_save_settings(const char *filename, 
     621                                         const pjsua_config *cfg); 
    551622 
    552623 
     
    555626 * @return  PJ_SUCCESS if valid. 
    556627 */ 
    557 pj_status_t pjsua_verify_sip_url(const char *c_url); 
     628PJ_DECL(pj_status_t) pjsua_verify_sip_url(const char *c_url); 
    558629 
    559630/* 
    560631 * Dump application states. 
    561632 */ 
    562 void pjsua_dump(pj_bool_t detail); 
     633PJ_DECL(void) pjsua_dump(pj_bool_t detail); 
     634 
     635/** 
     636 * Display error message for the specified error code. 
     637 */ 
     638PJ_DECL(void) pjsua_perror(const char *sender, const char *title,  
     639                           pj_status_t status); 
     640 
     641 
    563642 
    564643 
  • pjproject/trunk/pjsip/src/pjsip-ua/sip_reg.c

    r219 r476  
    485485     
    486486    /* Decrement pending transaction counter. */ 
     487    pj_assert(regc->pending_tsx > 0); 
    487488    --regc->pending_tsx; 
    488489 
     
    610611    cseq_hdr->cseq = cseq; 
    611612 
    612     /* Send. */ 
     613    /* Increment pending transaction first, since transaction callback 
     614     * may be called even before send_request() returns! 
     615     */ 
     616    ++regc->pending_tsx; 
    613617    status = pjsip_endpt_send_request(regc->endpt, tdata, -1, regc, &tsx_callback); 
    614     if (status==PJ_SUCCESS) 
    615         ++regc->pending_tsx; 
     618    if (status!=PJ_SUCCESS) 
     619        --regc->pending_tsx; 
    616620 
    617621    return status; 
  • pjproject/trunk/pjsip/src/pjsua-lib/pjsua_call.c

    r452 r476  
    1919#include <pjsua-lib/pjsua.h> 
    2020#include <pj/log.h> 
    21  
     21#include "pjsua_imp.h" 
    2222 
    2323/* 
     
    5757        } else { 
    5858            PJ_LOG(3,(THIS_FILE, "Refreshing call %d", call->index)); 
    59             schedule_call_timer(call,e,REFRESH_CALL_TIMER,pjsua.uas_refresh); 
     59            schedule_call_timer(call,e,REFRESH_CALL_TIMER, 
     60                                pjsua.config.uas_refresh); 
    6061            pjsua_call_reinvite(call->index); 
    6162        } 
     
    127128 * Make outgoing call. 
    128129 */ 
    129 pj_status_t pjsua_make_call(int acc_index, 
    130                             const char *cstr_dest_uri, 
    131                             int *p_call_index) 
     130PJ_DEF(pj_status_t) pjsua_make_call(int acc_index, 
     131                                    const char *cstr_dest_uri, 
     132                                    int *p_call_index) 
    132133{ 
    133134    pj_str_t dest_uri; 
     
    135136    pjmedia_sdp_session *offer; 
    136137    pjsip_inv_session *inv = NULL; 
    137     int call_index = -1; 
     138    unsigned call_index; 
    138139    pjsip_tx_data *tdata; 
    139140    pj_status_t status; 
     
    144145 
    145146    /* Find free call slot. */ 
    146     for (call_index=0; call_index<pjsua.max_calls; ++call_index) { 
     147    for (call_index=0; call_index<pjsua.config.max_calls; ++call_index) { 
    147148        if (pjsua.calls[call_index].inv == NULL) 
    148149            break; 
    149150    } 
    150151 
    151     if (call_index == pjsua.max_calls) { 
     152    if (call_index == pjsua.config.max_calls) { 
    152153        PJ_LOG(3,(THIS_FILE, "Error: too many calls!")); 
    153154        return PJ_ETOOMANY; 
     
    162163    /* Create outgoing dialog: */ 
    163164    status = pjsip_dlg_create_uac( pjsip_ua_instance(),  
    164                                    &pjsua.acc[acc_index].local_uri, 
    165                                    &pjsua.acc[acc_index].contact_uri,  
     165                                   &pjsua.config.acc_config[acc_index].id, 
     166                                   &pjsua.config.acc_config[acc_index].contact, 
    166167                                   &dest_uri, &dest_uri, 
    167168                                   &dlg); 
     
    205206 
    206207    /* Set credentials: */ 
    207  
    208     pjsip_auth_clt_set_credentials( &dlg->auth_sess, pjsua.cred_count,  
    209                                     pjsua.cred_info); 
     208    if (pjsua.config.acc_config[acc_index].cred_count) { 
     209        pjsua_acc_config *acc_cfg = &pjsua.config.acc_config[acc_index]; 
     210        pjsip_auth_clt_set_credentials( &dlg->auth_sess,  
     211                                        acc_cfg->cred_count, 
     212                                        acc_cfg->cred_info); 
     213    } 
    210214 
    211215 
     
    226230        pjsua_perror(THIS_FILE, "Unable to send initial INVITE request",  
    227231                     status); 
     232 
     233        /* Upon failure to send first request, both dialog and invite  
     234         * session would have been cleared. 
     235         */ 
     236        inv = NULL; 
     237        dlg = NULL; 
    228238        goto on_error; 
    229239    } 
     
    243253    if (inv != NULL) { 
    244254        pjsip_inv_terminate(inv, PJSIP_SC_OK, PJ_FALSE); 
    245     } else { 
     255    } else if (dlg) { 
    246256        pjsip_dlg_terminate(dlg); 
    247257    } 
     
    251261    } 
    252262    return status; 
     263} 
     264 
     265 
     266/** 
     267 * Answer call. 
     268 */ 
     269PJ_DEF(void) pjsua_call_answer(int call_index, int code) 
     270{ 
     271    pjsip_tx_data *tdata; 
     272    pj_status_t status; 
     273 
     274    PJ_ASSERT_ON_FAIL(call_index >= 0 &&  
     275                      call_index < (int)pjsua.config.max_calls, 
     276                      return); 
     277 
     278    if (pjsua.calls[call_index].inv == NULL) { 
     279        PJ_LOG(3,(THIS_FILE, "Call %d already disconnected")); 
     280        return; 
     281    } 
     282 
     283    status = pjsip_inv_answer(pjsua.calls[call_index].inv, 
     284                              code, NULL, NULL, &tdata); 
     285    if (status == PJ_SUCCESS) 
     286        status = pjsip_inv_send_msg(pjsua.calls[call_index].inv, 
     287                                    tdata); 
     288 
     289    if (status != PJ_SUCCESS) 
     290        pjsua_perror(THIS_FILE, "Unable to create/send response",  
     291                     status); 
     292 
    253293} 
    254294 
     
    266306    pjsip_inv_session *inv = NULL; 
    267307    int acc_index; 
    268     int call_index = -1; 
     308    unsigned call_index; 
    269309    pjmedia_sdp_session *answer; 
    270310    pj_status_t status; 
     
    313353 
    314354    /* Find free call slot. */ 
    315     for (call_index=0; call_index < pjsua.max_calls; ++call_index) { 
     355    for (call_index=0; call_index < pjsua.config.max_calls; ++call_index) { 
    316356        if (pjsua.calls[call_index].inv == NULL) 
    317357            break; 
     
    354394 
    355395    status = pjsip_dlg_create_uas( pjsip_ua_instance(), rdata, 
    356                                    &pjsua.acc[acc_index].contact_uri,  
     396                                   &pjsua.config.acc_config[acc_index].contact, 
    357397                                   &dlg); 
    358398    if (status != PJ_SUCCESS) { 
     
    388428     
    389429    status = pjsip_inv_initial_answer(inv, rdata,  
    390                                       (pjsua.auto_answer ? pjsua.auto_answer  
    391                                         : 100),  
     430                                      (pjsua.config.auto_answer ?  
     431                                      pjsua.config.auto_answer : 100),  
    392432                                      NULL, NULL, &response); 
    393433    if (status != PJ_SUCCESS) { 
     
    401441         * because SDP negotiation has failed. 
    402442         */ 
    403         if (pjsua.auto_answer/100 == 2) 
     443        if (pjsua.config.auto_answer/100 == 2) 
    404444            st_code = PJSIP_SC_UNSUPPORTED_MEDIA_TYPE; 
    405445        else 
     
    416456    } 
    417457 
    418     if (pjsua.auto_answer < 200) { 
     458    if (pjsua.config.auto_answer < 200) { 
    419459        PJ_LOG(3,(THIS_FILE, 
    420460                  "\nIncoming call!!\n" 
     
    433473                  (int)dlg->local.info_str.slen, 
    434474                  dlg->local.info_str.ptr, 
    435                   pjsua.auto_answer, 
    436                   pjsip_get_status_text(pjsua.auto_answer)->ptr )); 
     475                  pjsua.config.auto_answer, 
     476                  pjsip_get_status_text(pjsua.config.auto_answer)->ptr )); 
    437477    } 
    438478 
     
    440480 
    441481    /* Schedule timer to refresh. */ 
    442     if (pjsua.uas_refresh > 0) { 
     482    if (pjsua.config.uas_refresh > 0) { 
    443483        schedule_call_timer( &pjsua.calls[call_index],  
    444484                             &pjsua.calls[call_index].refresh_tm, 
    445485                             REFRESH_CALL_TIMER, 
    446                              pjsua.uas_refresh); 
     486                             pjsua.config.uas_refresh); 
    447487    } 
    448488 
    449489    /* Schedule timer to hangup call. */ 
    450     if (pjsua.uas_duration > 0) { 
     490    if (pjsua.config.uas_duration > 0) { 
    451491        schedule_call_timer( &pjsua.calls[call_index],  
    452492                             &pjsua.calls[call_index].hangup_tm, 
    453493                             HANGUP_CALL_TIMER, 
    454                              pjsua.uas_duration); 
     494                             pjsua.config.uas_duration); 
    455495    } 
    456496 
     
    551591 
    552592 
    553     pjsua_ui_on_call_state(call->index, e); 
     593    if (pjsua.cb.on_call_state) 
     594        (*pjsua.cb.on_call_state)(call->index, e); 
    554595 
    555596    /* call->inv may be NULL now */ 
     
    9661007    } 
    9671008 
    968     if (pjsua.null_audio) 
     1009    if (pjsua.config.null_audio) 
    9691010        return; 
    9701011 
     
    9841025 
    9851026    /* Override ptime, if this option is specified. */ 
    986     if (pjsua.ptime) { 
     1027    if (pjsua.config.ptime) { 
    9871028        sess_info.stream_info[0].param->setting.frm_per_pkt = (pj_uint8_t) 
    988             (pjsua.ptime / sess_info.stream_info[0].param->info.frm_ptime); 
     1029            (pjsua.config.ptime /  
     1030              sess_info.stream_info[0].param->info.frm_ptime); 
    9891031        if (sess_info.stream_info[0].param->setting.frm_per_pkt==0) 
    9901032            sess_info.stream_info[0].param->setting.frm_per_pkt = 1; 
     
    10381080     * port  
    10391081     */ 
    1040     if (pjsua.auto_play && pjsua.wav_file &&  
     1082    if (pjsua.config.auto_play && pjsua.config.wav_file.slen &&  
    10411083        call->inv->role == PJSIP_ROLE_UAS)  
    10421084    { 
     
    10461088 
    10471089    } 
    1048     if (pjsua.auto_loop && call->inv->role == PJSIP_ROLE_UAS) { 
     1090    if (pjsua.config.auto_loop && call->inv->role == PJSIP_ROLE_UAS) { 
    10491091 
    10501092        pjmedia_conf_connect_port( pjsua.mconf, call->conf_slot,  
     
    10521094 
    10531095    } 
    1054     if (pjsua.auto_conf) { 
    1055         int i; 
     1096    if (pjsua.config.auto_conf) { 
     1097        unsigned i; 
    10561098 
    10571099        pjmedia_conf_connect_port( pjsua.mconf, 0, call->conf_slot, 0); 
    10581100        pjmedia_conf_connect_port( pjsua.mconf, call->conf_slot, 0, 0); 
    10591101 
    1060         for (i=0; i < pjsua.max_calls; ++i) { 
     1102        for (i=0; i < pjsua.config.max_calls; ++i) { 
    10611103 
    10621104            if (!pjsua.calls[i].session) 
     
    10741116     * the sound device port (port zero) in the main conference bridge. 
    10751117     */ 
    1076     if (pjsua.auto_play == 0 && pjsua.auto_loop == 0 && 
    1077         pjsua.auto_conf == 0) 
     1118    if (pjsua.config.auto_play == 0 && pjsua.config.auto_loop == 0 && 
     1119        pjsua.config.auto_conf == 0) 
    10781120    { 
    10791121        pjmedia_conf_connect_port( pjsua.mconf, 0, call->conf_slot, 0); 
     
    11281170 * Hangup call. 
    11291171 */ 
    1130 void pjsua_call_hangup(int call_index) 
     1172PJ_DEF(void) pjsua_call_hangup(int call_index) 
    11311173{ 
    11321174    pjsua_call *call; 
     
    11781220 * Put call on-Hold. 
    11791221 */ 
    1180 void pjsua_call_set_hold(int call_index) 
     1222PJ_DEF(void) pjsua_call_set_hold(int call_index) 
    11811223{ 
    11821224    pjmedia_sdp_session *sdp; 
     
    12191261 * re-INVITE. 
    12201262 */ 
    1221 void pjsua_call_reinvite(int call_index) 
     1263PJ_DEF(void) pjsua_call_reinvite(int call_index) 
    12221264{ 
    12231265    pjmedia_sdp_session *sdp; 
     
    12661308 * Transfer call. 
    12671309 */ 
    1268 void pjsua_call_xfer(int call_index, const char *dest) 
     1310PJ_DEF(void) pjsua_call_xfer(int call_index, const char *dest) 
    12691311{ 
    12701312    pjsip_evsub *sub; 
     
    13181360 * Send instant messaging inside INVITE session. 
    13191361 */ 
    1320 void pjsua_call_send_im(int call_index, const char *str) 
     1362PJ_DECL(void) pjsua_call_send_im(int call_index, const char *str) 
    13211363{ 
    13221364    pjsua_call *call; 
     
    13741416 * Send IM typing indication inside INVITE session. 
    13751417 */ 
    1376 void pjsua_call_typing(int call_index, pj_bool_t is_typing) 
     1418PJ_DECL(void) pjsua_call_typing(int call_index, pj_bool_t is_typing) 
    13771419{ 
    13781420    pjsua_call *call; 
     
    14161458 * Terminate all calls. 
    14171459 */ 
    1418 void pjsua_call_hangup_all(void) 
    1419 { 
    1420     int i; 
    1421  
    1422     for (i=0; i<pjsua.max_calls; ++i) { 
     1460PJ_DEF(void) pjsua_call_hangup_all(void) 
     1461{ 
     1462    unsigned i; 
     1463 
     1464    for (i=0; i<pjsua.config.max_calls; ++i) { 
    14231465        pjsip_tx_data *tdata; 
    14241466        int st_code; 
  • pjproject/trunk/pjsip/src/pjsua-lib/pjsua_core.c

    r452 r476  
    1818 */ 
    1919#include <pjsua-lib/pjsua.h> 
     20#include "pjsua_imp.h" 
    2021 
    2122/* 
     
    4445 * Init default application parameters. 
    4546 */ 
    46 void pjsua_default(void) 
     47PJ_DEF(void) pjsua_default_config(pjsua_config *cfg) 
    4748{ 
    4849    unsigned i; 
    4950 
    50  
    51     /* Normally need another thread for console application, because main  
    52      * thread will be blocked in fgets(). 
    53      */ 
    54     pjsua.thread_cnt = 1; 
    55  
    56  
    57     /* Default transport settings: */ 
    58     pjsua.sip_port = 5060; 
    59  
    60  
    61     /* Default we start RTP at port 4000 */ 
    62     pjsua.start_rtp_port = 4000; 
    63  
    64  
    65     /* Default logging settings: */ 
    66     pjsua.log_level = 5; 
    67     pjsua.app_log_level = 4; 
    68     pjsua.log_decor = PJ_LOG_HAS_SENDER | PJ_LOG_HAS_TIME |  
    69                       PJ_LOG_HAS_MICRO_SEC | PJ_LOG_HAS_NEWLINE; 
    70  
    71  
    72     /* Default call settings. */ 
    73     pjsua.uas_refresh = -1; 
    74     pjsua.uas_duration = -1; 
    75  
    76     /* Default: do not use STUN: */ 
    77     pjsua.stun_port1 = pjsua.stun_port2 = 0; 
    78  
    79     /* Default for media: */ 
     51    pj_memset(cfg, 0, sizeof(pjsua_config)); 
     52 
     53    cfg->thread_cnt = 1; 
     54    cfg->udp_port = 5060; 
     55    cfg->start_rtp_port = 4000; 
     56    cfg->max_calls = 4; 
     57    cfg->conf_ports = 0; 
     58 
    8059#if defined(PJ_DARWINOS) && PJ_DARWINOS!=0 
    8160    pjsua.clock_rate = 44100; 
    8261#endif 
    83     pjsua.complexity = -1; 
    84     pjsua.quality = 4; 
     62 
     63    cfg->complexity = 10; 
     64    cfg->quality = 10; 
     65     
     66    cfg->auto_answer = 100; 
     67    cfg->uas_duration = 3600; 
     68 
     69    /* Default logging settings: */ 
     70    cfg->log_level = 5; 
     71    cfg->app_log_level = 4; 
     72    cfg->log_decor =  PJ_LOG_HAS_SENDER | PJ_LOG_HAS_TIME |  
     73                      PJ_LOG_HAS_MICRO_SEC | PJ_LOG_HAS_NEWLINE; 
     74 
     75 
     76    /* Also init logging settings in pjsua.config, because log 
     77     * may be written before pjsua_init() is called. 
     78     */ 
     79    pjsua.config.log_level = 5; 
     80    pjsua.config.app_log_level = 4; 
    8581 
    8682 
    8783    /* Init accounts: */ 
    88     pjsua.acc_cnt = 1; 
    8984    for (i=0; i<PJ_ARRAY_SIZE(pjsua.acc); ++i) { 
    90         pjsua.acc[i].index = i; 
    91         pjsua.acc[i].local_uri = pj_str(PJSUA_LOCAL_URI); 
    92         pjsua.acc[i].reg_timeout = 55; 
    93         pjsua.acc[i].online_status = PJ_TRUE; 
    94         pj_list_init(&pjsua.acc[i].route_set); 
    95         pj_list_init(&pjsua.acc[i].pres_srv_list); 
    96     } 
    97  
    98     /* Init call array: */ 
    99     for (i=0; i<PJ_ARRAY_SIZE(pjsua.calls); ++i) { 
    100         pjsua.calls[i].index = i; 
    101         pjsua.calls[i].refresh_tm._timer_id = -1; 
    102         pjsua.calls[i].hangup_tm._timer_id = -1; 
    103         pjsua.calls[i].conf_slot = 0; 
    104     } 
    105  
    106     /* Default max nb of calls. */ 
    107     pjsua.max_calls = 4; 
    108  
    109     /* Init server presence subscription list: */ 
    110      
    111  
    112 } 
    113  
     85        cfg->acc_config[i].reg_timeout = 55; 
     86    } 
     87} 
     88 
     89 
     90#define strncpy_with_null(dst,src,len)  \ 
     91do { \ 
     92    strncpy(dst, src, len); \ 
     93    dst[len-1] = '\0'; \ 
     94} while (0) 
     95 
     96 
     97 
     98PJ_DEF(pj_status_t) pjsua_test_config( const pjsua_config *cfg, 
     99                                       char *errmsg, 
     100                                       int len) 
     101{ 
     102    unsigned i; 
     103 
     104    /* If UDP port is zero, then sip_host and sip_port must be specified */ 
     105    if (cfg->udp_port == 0) { 
     106        if (cfg->sip_host.slen==0 || cfg->sip_port==0) { 
     107            strncpy_with_null(errmsg,  
     108                              "sip_host and sip_port must be specified", 
     109                              len); 
     110            return -1; 
     111        } 
     112    } 
     113 
     114    if (cfg->max_calls < 1) { 
     115        strncpy_with_null(errmsg,  
     116                          "max_calls needs to be at least 1", 
     117                          len); 
     118        return -1; 
     119    } 
     120 
     121    /* STUN */ 
     122    if (cfg->stun_srv1.slen || cfg->stun_port1 || cfg->stun_port2 ||  
     123        cfg->stun_srv2.slen)  
     124    { 
     125        if (cfg->stun_port1 == 0) { 
     126            strncpy_with_null(errmsg, "stun_port1 required", len); 
     127            return -1; 
     128        } 
     129        if (cfg->stun_srv1.slen == 0) { 
     130            strncpy_with_null(errmsg, "stun_srv1 required", len); 
     131            return -1; 
     132        } 
     133        if (cfg->stun_port2 == 0) { 
     134            strncpy_with_null(errmsg, "stun_port2 required", len); 
     135            return -1; 
     136        } 
     137        if (cfg->stun_srv2.slen == 0) { 
     138            strncpy_with_null(errmsg, "stun_srv2 required", len); 
     139            return -1; 
     140        } 
     141    } 
     142 
     143    /* Verify accounts */ 
     144    for (i=0; i<cfg->acc_cnt; ++i) { 
     145        const pjsua_acc_config *acc_cfg = &cfg->acc_config[i]; 
     146        unsigned j; 
     147 
     148        if (acc_cfg->id.slen == 0) { 
     149            strncpy_with_null(errmsg, "missing account ID", len); 
     150            return -1; 
     151        } 
     152 
     153        if (acc_cfg->id.slen == 0) { 
     154            strncpy_with_null(errmsg, "missing registrar URI", len); 
     155            return -1; 
     156        } 
     157 
     158        if (acc_cfg->reg_timeout == 0) { 
     159            strncpy_with_null(errmsg, "missing registration timeout", len); 
     160            return -1; 
     161        } 
     162 
     163 
     164        for (j=0; j<acc_cfg->cred_count; ++j) { 
     165 
     166            if (acc_cfg->cred_info[j].scheme.slen == 0) { 
     167                strncpy_with_null(errmsg, "missing auth scheme in account",  
     168                                  len); 
     169                return -1; 
     170            } 
     171 
     172            if (acc_cfg->cred_info[j].realm.slen == 0) { 
     173                strncpy_with_null(errmsg, "missing realm in account", len); 
     174                return -1; 
     175            } 
     176 
     177            if (acc_cfg->cred_info[j].username.slen == 0) { 
     178                strncpy_with_null(errmsg, "missing username in account", len); 
     179                return -1; 
     180            } 
     181 
     182        } 
     183    } 
     184 
     185    return PJ_SUCCESS; 
     186} 
    114187 
    115188 
     
    153226 
    154227 
     228static int PJ_THREAD_FUNC pjsua_poll(void *arg) 
     229{ 
     230    pj_status_t last_err = 0; 
     231 
     232    PJ_UNUSED_ARG(arg); 
     233 
     234    do { 
     235        pj_time_val timeout = { 0, 10 }; 
     236        pj_status_t status; 
     237         
     238        status = pjsip_endpt_handle_events (pjsua.endpt, &timeout); 
     239        if (status != PJ_SUCCESS && status != last_err) { 
     240            last_err = status; 
     241            pjsua_perror(THIS_FILE, "handle_events() returned error", status); 
     242        } 
     243    } while (!pjsua.quit_flag); 
     244 
     245    return 0; 
     246} 
     247 
     248 
     249 
     250#define pjsua_has_stun()    (pjsua.config.stun_port1 && \ 
     251                             pjsua.config.stun_port2) 
     252 
     253 
     254/* 
     255 * Create and initialize SIP socket (and possibly resolve public 
     256 * address via STUN, depending on config). 
     257 */ 
     258static pj_status_t create_sip_udp_sock(int port, 
     259                                       pj_sock_t *p_sock, 
     260                                       pj_sockaddr_in *p_pub_addr) 
     261{ 
     262    pj_sock_t sock; 
     263    pj_status_t status; 
     264 
     265    status = pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, &sock); 
     266    if (status != PJ_SUCCESS) { 
     267        pjsua_perror(THIS_FILE, "socket() error", status); 
     268        return status; 
     269    } 
     270 
     271    status = pj_sock_bind_in(sock, 0, (pj_uint16_t)port); 
     272    if (status != PJ_SUCCESS) { 
     273        pjsua_perror(THIS_FILE, "bind() error", status); 
     274        pj_sock_close(sock); 
     275        return status; 
     276    } 
     277 
     278    if (pjsua_has_stun()) { 
     279        status = pj_stun_get_mapped_addr(&pjsua.cp.factory, 1, &sock, 
     280                                         &pjsua.config.stun_srv1,  
     281                                         pjsua.config.stun_port1, 
     282                                         &pjsua.config.stun_srv2,  
     283                                         pjsua.config.stun_port2, 
     284                                         p_pub_addr); 
     285        if (status != PJ_SUCCESS) { 
     286            pjsua_perror(THIS_FILE, "STUN resolve error", status); 
     287            pj_sock_close(sock); 
     288            return status; 
     289        } 
     290 
     291    } else { 
     292 
     293        const pj_str_t *hostname = pj_gethostname(); 
     294        struct pj_hostent he; 
     295 
     296        status = pj_gethostbyname(hostname, &he); 
     297        if (status != PJ_SUCCESS) { 
     298            pjsua_perror(THIS_FILE, "Unable to resolve local host", status); 
     299            pj_sock_close(sock); 
     300            return status; 
     301        } 
     302 
     303        pj_memset(p_pub_addr, 0, sizeof(pj_sockaddr_in)); 
     304        p_pub_addr->sin_family = PJ_AF_INET; 
     305        p_pub_addr->sin_port = pj_htons((pj_uint16_t)port); 
     306        p_pub_addr->sin_addr = *(pj_in_addr*)he.h_addr; 
     307    } 
     308 
     309    *p_sock = sock; 
     310    return PJ_SUCCESS; 
     311} 
     312 
     313 
    155314/*  
    156  * Initialize sockets and optionally get the public address via STUN.  
    157  */ 
    158 static pj_status_t init_sockets(pj_bool_t sip, 
    159                                 pjmedia_sock_info *skinfo) 
     315 * Create RTP and RTCP socket pair, and possibly resolve their public 
     316 * address via STUN. 
     317 */ 
     318static pj_status_t create_rtp_rtcp_sock(pjmedia_sock_info *skinfo) 
    160319{ 
    161320    enum {  
    162321        RTP_RETRY = 100 
    163322    }; 
    164     enum { 
    165         SIP_SOCK, 
    166         RTP_SOCK, 
    167         RTCP_SOCK, 
    168     }; 
    169323    int i; 
    170324    static pj_uint16_t rtp_port; 
    171     pj_sock_t sock[3]; 
    172     pj_sockaddr_in mapped_addr[3]; 
     325    pj_sockaddr_in mapped_addr[2]; 
    173326    pj_status_t status = PJ_SUCCESS; 
     327    pj_sock_t sock[2]; 
    174328 
    175329    if (rtp_port == 0) 
    176         rtp_port = (pj_uint16_t)pjsua.start_rtp_port; 
    177  
    178     for (i=0; i<3; ++i) 
     330        rtp_port = (pj_uint16_t)pjsua.config.start_rtp_port; 
     331 
     332    for (i=0; i<2; ++i) 
    179333        sock[i] = PJ_INVALID_SOCKET; 
    180  
    181     /* Create and bind SIP UDP socket. */ 
    182     status = pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, &sock[SIP_SOCK]); 
    183     if (status != PJ_SUCCESS) { 
    184         pjsua_perror(THIS_FILE, "socket() error", status); 
    185         goto on_error; 
    186     } 
    187  
    188     if (sip) { 
    189         status = pj_sock_bind_in(sock[SIP_SOCK], 0, pjsua.sip_port); 
    190         if (status != PJ_SUCCESS) { 
    191             pjsua_perror(THIS_FILE, "bind() error", status); 
    192             goto on_error; 
    193         } 
    194     } else { 
    195         status = pj_sock_bind_in(sock[SIP_SOCK], 0, 0); 
    196         if (status != PJ_SUCCESS) { 
    197             pjsua_perror(THIS_FILE, "bind() error", status); 
    198             goto on_error; 
    199         } 
    200     } 
    201334 
    202335 
     
    205338 
    206339        /* Create and bind RTP socket. */ 
    207         status = pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, &sock[RTP_SOCK]); 
     340        status = pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, &sock[0]); 
    208341        if (status != PJ_SUCCESS) { 
    209342            pjsua_perror(THIS_FILE, "socket() error", status); 
    210             goto on_error; 
    211         } 
    212  
    213         status = pj_sock_bind_in(sock[RTP_SOCK], 0, rtp_port); 
     343            return status; 
     344        } 
     345 
     346        status = pj_sock_bind_in(sock[0], 0, rtp_port); 
    214347        if (status != PJ_SUCCESS) { 
    215             pj_sock_close(sock[RTP_SOCK]);  
    216             sock[RTP_SOCK] = PJ_INVALID_SOCKET; 
     348            pj_sock_close(sock[0]);  
     349            sock[0] = PJ_INVALID_SOCKET; 
    217350            continue; 
    218351        } 
    219352 
    220353        /* Create and bind RTCP socket. */ 
    221         status = pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, &sock[RTCP_SOCK]); 
     354        status = pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, &sock[1]); 
    222355        if (status != PJ_SUCCESS) { 
    223356            pjsua_perror(THIS_FILE, "socket() error", status); 
    224             goto on_error; 
    225         } 
    226  
    227         status = pj_sock_bind_in(sock[RTCP_SOCK], 0, (pj_uint16_t)(rtp_port+1)); 
     357            pj_sock_close(sock[0]); 
     358            return status; 
     359        } 
     360 
     361        status = pj_sock_bind_in(sock[1], 0, (pj_uint16_t)(rtp_port+1)); 
    228362        if (status != PJ_SUCCESS) { 
    229             pj_sock_close(sock[RTP_SOCK]);  
    230             sock[RTP_SOCK] = PJ_INVALID_SOCKET; 
    231  
    232             pj_sock_close(sock[RTCP_SOCK]);  
    233             sock[RTCP_SOCK] = PJ_INVALID_SOCKET; 
     363            pj_sock_close(sock[0]);  
     364            sock[0] = PJ_INVALID_SOCKET; 
     365 
     366            pj_sock_close(sock[1]);  
     367            sock[1] = PJ_INVALID_SOCKET; 
    234368            continue; 
    235369        } 
     
    239373         * and make sure that the mapped RTCP port is adjacent with the RTP. 
    240374         */ 
    241         if (pjsua.stun_port1 == 0) { 
     375        if (pjsua_has_stun()) { 
     376            status=pj_stun_get_mapped_addr(&pjsua.cp.factory, 2, sock, 
     377                                           &pjsua.config.stun_srv1,  
     378                                           pjsua.config.stun_port1, 
     379                                           &pjsua.config.stun_srv2,  
     380                                           pjsua.config.stun_port2, 
     381                                           mapped_addr); 
     382            if (status != PJ_SUCCESS) { 
     383                pjsua_perror(THIS_FILE, "STUN resolve error", status); 
     384                goto on_error; 
     385            } 
     386 
     387            if (pj_ntohs(mapped_addr[1].sin_port) ==  
     388                pj_ntohs(mapped_addr[0].sin_port)+1) 
     389            { 
     390                /* Success! */ 
     391                break; 
     392            } 
     393 
     394            pj_sock_close(sock[0]);  
     395            sock[0] = PJ_INVALID_SOCKET; 
     396 
     397            pj_sock_close(sock[1]);  
     398            sock[1] = PJ_INVALID_SOCKET; 
     399 
     400        } else { 
    242401            const pj_str_t *hostname; 
    243402            pj_sockaddr_in addr; 
     
    255414            } 
    256415 
    257             for (i=0; i<3; ++i) 
     416            for (i=0; i<2; ++i) 
    258417                pj_memcpy(&mapped_addr[i], &addr, sizeof(addr)); 
    259418 
    260             if (sip) { 
    261                 mapped_addr[SIP_SOCK].sin_port =  
    262                     pj_htons((pj_uint16_t)pjsua.sip_port); 
    263             } 
    264             mapped_addr[RTP_SOCK].sin_port=pj_htons((pj_uint16_t)rtp_port); 
    265             mapped_addr[RTCP_SOCK].sin_port=pj_htons((pj_uint16_t)(rtp_port+1)); 
     419            mapped_addr[0].sin_port=pj_htons((pj_uint16_t)rtp_port); 
     420            mapped_addr[1].sin_port=pj_htons((pj_uint16_t)(rtp_port+1)); 
    266421            break; 
    267  
    268         } else { 
    269             status=pj_stun_get_mapped_addr(&pjsua.cp.factory, 3, sock, 
    270                                            &pjsua.stun_srv1, pjsua.stun_port1, 
    271                                            &pjsua.stun_srv2, pjsua.stun_port2, 
    272                                            mapped_addr); 
    273             if (status != PJ_SUCCESS) { 
    274                 pjsua_perror(THIS_FILE, "STUN error", status); 
    275                 goto on_error; 
    276             } 
    277  
    278             if (pj_ntohs(mapped_addr[2].sin_port) ==  
    279                 pj_ntohs(mapped_addr[1].sin_port)+1) 
    280             { 
    281                 break; 
    282             } 
    283  
    284             pj_sock_close(sock[RTP_SOCK]);  
    285             sock[RTP_SOCK] = PJ_INVALID_SOCKET; 
    286  
    287             pj_sock_close(sock[RTCP_SOCK]);  
    288             sock[RTCP_SOCK] = PJ_INVALID_SOCKET; 
    289         } 
    290     } 
    291  
    292     if (sock[RTP_SOCK] == PJ_INVALID_SOCKET) { 
     422        } 
     423    } 
     424 
     425    if (sock[0] == PJ_INVALID_SOCKET) { 
    293426        PJ_LOG(1,(THIS_FILE,  
    294427                  "Unable to find appropriate RTP/RTCP ports combination")); 
     
    296429    } 
    297430 
    298     if (sip) { 
    299         pjsua.sip_sock = sock[SIP_SOCK]; 
    300         pj_memcpy(&pjsua.sip_sock_name,  
    301                   &mapped_addr[SIP_SOCK],  
    302                   sizeof(pj_sockaddr_in)); 
    303     } else { 
    304         pj_sock_close(sock[0]); 
    305     } 
    306  
    307     skinfo->rtp_sock = sock[RTP_SOCK]; 
     431 
     432    skinfo->rtp_sock = sock[0]; 
    308433    pj_memcpy(&skinfo->rtp_addr_name,  
    309               &mapped_addr[RTP_SOCK], sizeof(pj_sockaddr_in)); 
    310  
    311     skinfo->rtcp_sock = sock[RTCP_SOCK]; 
     434              &mapped_addr[0], sizeof(pj_sockaddr_in)); 
     435 
     436    skinfo->rtcp_sock = sock[1]; 
    312437    pj_memcpy(&skinfo->rtcp_addr_name,  
    313               &mapped_addr[RTCP_SOCK], sizeof(pj_sockaddr_in)); 
    314  
    315     if (sip) { 
    316         PJ_LOG(4,(THIS_FILE, "SIP UDP socket reachable at %s:%d", 
    317                   pj_inet_ntoa(pjsua.sip_sock_name.sin_addr),  
    318                   pj_ntohs(pjsua.sip_sock_name.sin_port))); 
    319     } 
     438              &mapped_addr[1], sizeof(pj_sockaddr_in)); 
     439 
    320440    PJ_LOG(4,(THIS_FILE, "RTP socket reachable at %s:%d", 
    321441              pj_inet_ntoa(skinfo->rtp_addr_name.sin_addr),  
     
    329449 
    330450on_error: 
    331     for (i=0; i<3; ++i) { 
    332         if (sip && i==0) 
    333             continue; 
     451    for (i=0; i<2; ++i) { 
    334452        if (sock[i] != PJ_INVALID_SOCKET) 
    335453            pj_sock_close(sock[i]); 
     
    340458 
    341459 
    342 /*  
    343  * Initialize stack.  
    344  */ 
    345 static pj_status_t init_stack(void) 
     460/** 
     461 * Create pjsua application. 
     462 * This initializes pjlib/pjlib-util, and creates memory pool factory to 
     463 * be used by application. 
     464 */ 
     465PJ_DEF(pj_status_t) pjsua_create(void) 
    346466{ 
    347467    pj_status_t status; 
    348468 
     469    /* Init PJLIB: */ 
     470 
     471    status = pj_init(); 
     472    if (status != PJ_SUCCESS) { 
     473        pjsua_perror(THIS_FILE, "pj_init() error", status); 
     474        return status; 
     475    } 
     476 
     477    /* Init PJLIB-UTIL: */ 
     478 
     479    status = pjlib_util_init(); 
     480    if (status != PJ_SUCCESS) { 
     481        pjsua_perror(THIS_FILE, "pjlib_util_init() error", status); 
     482        return status; 
     483    } 
     484 
     485    /* Init memory pool: */ 
     486 
     487    /* Init caching pool. */ 
     488    pj_caching_pool_init(&pjsua.cp, &pj_pool_factory_default_policy, 0); 
     489 
     490    /* Create memory pool for application. */ 
     491    pjsua.pool = pj_pool_create(&pjsua.cp.factory, "pjsua", 4000, 4000, NULL); 
     492 
     493    /* Must create endpoint to initialize SIP parser. */ 
    349494    /* Create global endpoint: */ 
    350495 
    351     { 
    352         const pj_str_t *hostname; 
    353         const char *endpt_name; 
    354  
    355         /* Endpoint MUST be assigned a globally unique name. 
    356          * The name will be used as the hostname in Warning header. 
    357          */ 
    358  
    359         /* For this implementation, we'll use hostname for simplicity */ 
    360         hostname = pj_gethostname(); 
    361         endpt_name = hostname->ptr; 
    362  
    363         /* Create the endpoint: */ 
    364  
    365         status = pjsip_endpt_create(&pjsua.cp.factory, endpt_name,  
    366                                     &pjsua.endpt); 
     496    status = pjsip_endpt_create(&pjsua.cp.factory,  
     497                                pj_gethostname()->ptr,  
     498                                &pjsua.endpt); 
     499    if (status != PJ_SUCCESS) { 
     500        pjsua_perror(THIS_FILE, "Unable to create SIP endpoint", status); 
     501        return status; 
     502    } 
     503 
     504    /* Must create media endpoint too */ 
     505    status = pjmedia_endpt_create(&pjsua.cp.factory,  
     506                                  pjsip_endpt_get_ioqueue(pjsua.endpt), 0, 
     507                                  &pjsua.med_endpt); 
     508    if (status != PJ_SUCCESS) { 
     509        pjsua_perror(THIS_FILE,  
     510                     "Media stack initialization has returned error",  
     511                     status); 
     512        return status; 
     513    } 
     514 
     515 
     516    return PJ_SUCCESS; 
     517} 
     518 
     519 
     520 
     521/* 
     522 * Init media. 
     523 */ 
     524static pj_status_t init_media(void) 
     525{ 
     526    int i; 
     527    unsigned options; 
     528    unsigned clock_rate; 
     529    unsigned samples_per_frame; 
     530    pj_str_t codec_id; 
     531    pj_status_t status; 
     532 
     533    /* Register all codecs */ 
     534#if PJMEDIA_HAS_SPEEX_CODEC 
     535    /* Register speex. */ 
     536    status = pjmedia_codec_speex_init(pjsua.med_endpt,  
     537                                      PJMEDIA_SPEEX_NO_UWB, 
     538                                      pjsua.config.quality,  
     539                                      pjsua.config.complexity ); 
     540    if (status != PJ_SUCCESS) { 
     541        pjsua_perror(THIS_FILE, "Error initializing Speex codec", 
     542                     status); 
     543        return status; 
     544    } 
     545 
     546    /* Set "speex/16000/1" to have highest priority */ 
     547    codec_id = pj_str("speex/16000/1"); 
     548    pjmedia_codec_mgr_set_codec_priority(  
     549        pjmedia_endpt_get_codec_mgr(pjsua.med_endpt), 
     550        &codec_id,  
     551        PJMEDIA_CODEC_PRIO_HIGHEST); 
     552 
     553#endif /* PJMEDIA_HAS_SPEEX_CODEC */ 
     554 
     555#if PJMEDIA_HAS_GSM_CODEC 
     556    /* Register GSM */ 
     557    status = pjmedia_codec_gsm_init(pjsua.med_endpt); 
     558    if (status != PJ_SUCCESS) { 
     559        pjsua_perror(THIS_FILE, "Error initializing GSM codec", 
     560                     status); 
     561        return status; 
     562    } 
     563#endif /* PJMEDIA_HAS_GSM_CODEC */ 
     564 
     565#if PJMEDIA_HAS_G711_CODEC 
     566    /* Register PCMA and PCMU */ 
     567    status = pjmedia_codec_g711_init(pjsua.med_endpt); 
     568    if (status != PJ_SUCCESS) { 
     569        pjsua_perror(THIS_FILE, "Error initializing G711 codec", 
     570                     status); 
     571        return status; 
     572    } 
     573#endif  /* PJMEDIA_HAS_G711_CODEC */ 
     574 
     575#if PJMEDIA_HAS_L16_CODEC 
     576    /* Register L16 family codecs, but disable all */ 
     577    status = pjmedia_codec_l16_init(pjsua.med_endpt, 0); 
     578    if (status != PJ_SUCCESS) { 
     579        pjsua_perror(THIS_FILE, "Error initializing L16 codecs", 
     580                     status); 
     581        return status; 
     582    } 
     583 
     584    /* Disable ALL L16 codecs */ 
     585    codec_id = pj_str("L16"); 
     586    pjmedia_codec_mgr_set_codec_priority(  
     587        pjmedia_endpt_get_codec_mgr(pjsua.med_endpt), 
     588        &codec_id,  
     589        PJMEDIA_CODEC_PRIO_DISABLED); 
     590 
     591#endif  /* PJMEDIA_HAS_L16_CODEC */ 
     592 
     593 
     594    /* Enable those codecs that user put with "--add-codec", and move 
     595     * the priority to top 
     596     */ 
     597    for (i=0; i<(int)pjsua.config.codec_cnt; ++i) { 
     598        pjmedia_codec_mgr_set_codec_priority(  
     599            pjmedia_endpt_get_codec_mgr(pjsua.med_endpt), 
     600            &pjsua.config.codec_arg[i],  
     601            PJMEDIA_CODEC_PRIO_HIGHEST); 
     602    } 
     603 
     604 
     605    /* Init options for conference bridge. */ 
     606    options = 0; 
     607 
     608    /* Calculate maximum number of ports, if it's not specified */ 
     609    if (pjsua.config.conf_ports == 0) { 
     610        pjsua.config.conf_ports = 3 * pjsua.config.max_calls; 
     611    } 
     612 
     613    /* Init conference bridge. */ 
     614    clock_rate = pjsua.config.clock_rate ? pjsua.config.clock_rate : 16000; 
     615    samples_per_frame = clock_rate * 10 / 1000; 
     616    status = pjmedia_conf_create(pjsua.pool,  
     617                                 pjsua.config.conf_ports,  
     618                                 clock_rate,  
     619                                 1, /* mono */ 
     620                                 samples_per_frame,  
     621                                 16,  
     622                                 options, 
     623                                 &pjsua.mconf); 
     624    if (status != PJ_SUCCESS) { 
     625        pjsua_perror(THIS_FILE,  
     626                     "Media stack initialization has returned error",  
     627                     status); 
     628        return status; 
     629    } 
     630 
     631    /* Create WAV file player if required: */ 
     632 
     633    if (pjsua.config.wav_file.slen) { 
     634        pj_str_t port_name; 
     635 
     636        /* Create the file player port. */ 
     637        status = pjmedia_wav_player_port_create(  pjsua.pool,  
     638                                                  pjsua.config.wav_file.ptr, 
     639                                                  0, 0, -1, NULL,  
     640                                                  &pjsua.file_port); 
    367641        if (status != PJ_SUCCESS) { 
    368             pjsua_perror(THIS_FILE, "Unable to create SIP endpoint", status); 
     642            pjsua_perror(THIS_FILE,  
     643                         "Error playing media file",  
     644                         status); 
    369645            return status; 
    370646        } 
    371     } 
    372  
     647 
     648        /* Add port to conference bridge: */ 
     649        port_name = pjsua.config.wav_file; 
     650        status = pjmedia_conf_add_port(pjsua.mconf, pjsua.pool,  
     651                                       pjsua.file_port,  
     652                                       &port_name, 
     653                                       &pjsua.wav_slot); 
     654        if (status != PJ_SUCCESS) { 
     655            pjsua_perror(THIS_FILE,  
     656                         "Unable to add file player to conference bridge",  
     657                         status); 
     658            return status; 
     659        } 
     660    } 
     661 
     662 
     663    return PJ_SUCCESS; 
     664} 
     665 
     666 
     667/* 
     668 * Copy configuration. 
     669 */ 
     670static void copy_config(pj_pool_t *pool, pjsua_config *dst,  
     671                        const pjsua_config *src) 
     672{ 
     673    unsigned i; 
     674 
     675    /* Plain memcpy */ 
     676    pj_memcpy(dst, src, sizeof(pjsua_config)); 
     677 
     678    /* Duplicate strings */ 
     679    pj_strdup_with_null(pool, &dst->sip_host, &src->sip_host); 
     680    pj_strdup_with_null(pool, &dst->stun_srv1, &src->stun_srv1); 
     681    pj_strdup_with_null(pool, &dst->stun_srv2, &src->stun_srv2); 
     682    pj_strdup_with_null(pool, &dst->wav_file, &src->wav_file); 
     683     
     684    for (i=0; i<src->codec_cnt; ++i) { 
     685        pj_strdup_with_null(pool, &dst->codec_arg[i], &src->codec_arg[i]); 
     686    } 
     687 
     688    pj_strdup_with_null(pool, &dst->outbound_proxy, &src->outbound_proxy); 
     689    pj_strdup_with_null(pool, &dst->uri_to_call, &src->uri_to_call); 
     690 
     691    for (i=0; i<src->acc_cnt; ++i) { 
     692        pjsua_acc_config *dst_acc = &dst->acc_config[i]; 
     693        const pjsua_acc_config *src_acc = &src->acc_config[i]; 
     694        unsigned j; 
     695 
     696        pj_strdup_with_null(pool, &dst_acc->id, &src_acc->id); 
     697        pj_strdup_with_null(pool, &dst_acc->reg_uri, &src_acc->reg_uri); 
     698        pj_strdup_with_null(pool, &dst_acc->contact, &src_acc->contact); 
     699        pj_strdup_with_null(pool, &dst_acc->proxy, &src_acc->proxy); 
     700 
     701        for (j=0; j<src_acc->cred_count; ++j) { 
     702            pj_strdup_with_null(pool, &dst_acc->cred_info[j].realm,  
     703                                &src_acc->cred_info[j].realm); 
     704            pj_strdup_with_null(pool, &dst_acc->cred_info[j].scheme,  
     705                                &src_acc->cred_info[j].scheme); 
     706            pj_strdup_with_null(pool, &dst_acc->cred_info[j].username,  
     707                                &src_acc->cred_info[j].username); 
     708            pj_strdup_with_null(pool, &dst_acc->cred_info[j].data,  
     709                                &src_acc->cred_info[j].data); 
     710        } 
     711    } 
     712 
     713    pj_strdup_with_null(pool, &dst->log_filename, &src->log_filename); 
     714 
     715    for (i=0; i<src->buddy_cnt; ++i) { 
     716        pj_strdup_with_null(pool, &dst->buddy_uri[i], &src->buddy_uri[i]); 
     717    } 
     718} 
     719 
     720 
     721/* 
     722 * Initialize pjsua application. 
     723 * This will initialize all libraries, create endpoint instance, and register 
     724 * pjsip modules. 
     725 */ 
     726PJ_DECL(pj_status_t) pjsua_init(const pjsua_config *cfg, 
     727                                const pjsua_callback *cb) 
     728{ 
     729    char errmsg[80]; 
     730    unsigned i; 
     731    pj_status_t status; 
     732 
     733 
     734    /* Init accounts: */ 
     735    for (i=0; i<PJ_ARRAY_SIZE(pjsua.acc); ++i) { 
     736        pjsua.acc[i].index = i; 
     737        pjsua.acc[i].online_status = PJ_TRUE; 
     738        pj_list_init(&pjsua.acc[i].route_set); 
     739        pj_list_init(&pjsua.acc[i].pres_srv_list); 
     740    } 
     741 
     742    /* Init call array: */ 
     743    for (i=0; i<PJ_ARRAY_SIZE(pjsua.calls); ++i) { 
     744        pjsua.calls[i].index = i; 
     745        pjsua.calls[i].refresh_tm._timer_id = -1; 
     746        pjsua.calls[i].hangup_tm._timer_id = -1; 
     747        pjsua.calls[i].conf_slot = 0; 
     748    } 
     749 
     750    /* Copy configuration */ 
     751    copy_config(pjsua.pool, &pjsua.config, cfg); 
     752 
     753    /* Copy callback */ 
     754    pj_memcpy(&pjsua.cb, cb, sizeof(pjsua_callback)); 
     755 
     756    /* Test configuration */ 
     757    if (pjsua_test_config(&pjsua.config, errmsg, sizeof(errmsg))) { 
     758        PJ_LOG(1,(THIS_FILE, "Error in configuration: %s", errmsg)); 
     759        return -1; 
     760    } 
     761 
     762 
     763    /* Init PJLIB logging: */ 
     764 
     765    pj_log_set_level(pjsua.config.log_level); 
     766    pj_log_set_decor(pjsua.config.log_decor); 
     767 
     768 
     769    /* Create SIP UDP socket */ 
     770    if (pjsua.config.udp_port) { 
     771 
     772        status = create_sip_udp_sock( pjsua.config.udp_port, 
     773                                      &pjsua.sip_sock, 
     774                                      &pjsua.sip_sock_name); 
     775        if (status != PJ_SUCCESS) 
     776            return status; 
     777     
     778        pj_strdup2_with_null(pjsua.pool, &pjsua.config.sip_host, 
     779                             pj_inet_ntoa(pjsua.sip_sock_name.sin_addr)); 
     780        pjsua.config.sip_port = pj_ntohs(pjsua.sip_sock_name.sin_port); 
     781 
     782    } else { 
     783 
     784        /* Check that SIP host and port is configured */ 
     785        if (cfg->sip_host.slen == 0 || cfg->sip_port == 0) { 
     786            PJ_LOG(1,(THIS_FILE,  
     787                      "Error: sip_host and sip_port must be specified")); 
     788            return PJ_EINVAL; 
     789        } 
     790 
     791        pjsua.sip_sock = PJ_INVALID_SOCKET; 
     792    } 
     793 
     794 
     795    /* Init media endpoint */ 
     796    status = init_media(); 
     797    if (status != PJ_SUCCESS) 
     798        return status; 
     799 
     800 
     801    /* Init RTP sockets, only when UDP transport is enabled */ 
     802    for (i=0; pjsua.config.start_rtp_port && i<pjsua.config.max_calls; ++i) { 
     803        status = create_rtp_rtcp_sock(&pjsua.calls[i].skinfo); 
     804        if (status != PJ_SUCCESS) { 
     805            unsigned j; 
     806            for (j=0; j<i; ++j) { 
     807                pjmedia_transport_udp_close(pjsua.calls[j].med_tp); 
     808            } 
     809            return status; 
     810        } 
     811        status = pjmedia_transport_udp_attach(pjsua.med_endpt, NULL, 
     812                                              &pjsua.calls[i].skinfo, 
     813                                              &pjsua.calls[i].med_tp); 
     814    } 
     815 
     816    /* Init PJSIP : */ 
    373817 
    374818    /* Initialize transaction layer: */ 
     
    428872    } 
    429873 
    430     /* Done */ 
    431  
    432     return PJ_SUCCESS; 
    433  
    434  
    435 on_error: 
    436     pjsip_endpt_destroy(pjsua.endpt); 
    437     pjsua.endpt = NULL; 
    438     return status; 
    439 } 
    440  
    441  
    442 static int PJ_THREAD_FUNC pjsua_poll(void *arg) 
    443 { 
    444     pj_status_t last_err = 0; 
    445  
    446     PJ_UNUSED_ARG(arg); 
    447  
    448     do { 
    449         pj_time_val timeout = { 0, 10 }; 
    450         pj_status_t status; 
    451          
    452         status = pjsip_endpt_handle_events (pjsua.endpt, &timeout); 
    453         if (status != PJ_SUCCESS && status != last_err) { 
    454             last_err = status; 
    455             pjsua_perror(THIS_FILE, "handle_events() returned error", status); 
    456         } 
    457     } while (!pjsua.quit_flag); 
    458  
    459     return 0; 
    460 } 
    461  
    462 /* 
    463  * Initialize pjsua application. 
    464  * This will initialize all libraries, create endpoint instance, and register 
    465  * pjsip modules. 
    466  */ 
    467 pj_status_t pjsua_init(void) 
    468 { 
    469     pj_status_t status; 
    470  
    471     /* Init PJLIB logging: */ 
    472  
    473     pj_log_set_level(pjsua.log_level); 
    474     pj_log_set_decor(pjsua.log_decor); 
    475  
    476  
    477     /* Init PJLIB: */ 
    478  
    479     status = pj_init(); 
    480     if (status != PJ_SUCCESS) { 
    481         pjsua_perror(THIS_FILE, "pj_init() error", status); 
    482         return status; 
    483     } 
    484  
    485     /* Init PJLIB-UTIL: */ 
    486  
    487     status = pjlib_util_init(); 
    488     if (status != PJ_SUCCESS) { 
    489         pjsua_perror(THIS_FILE, "pjlib_util_init() error", status); 
    490         return status; 
    491     } 
    492  
    493     /* Init memory pool: */ 
    494  
    495     /* Init caching pool. */ 
    496     pj_caching_pool_init(&pjsua.cp, &pj_pool_factory_default_policy, 0); 
    497  
    498     /* Create memory pool for application. */ 
    499     pjsua.pool = pj_pool_create(&pjsua.cp.factory, "pjsua", 4000, 4000, NULL); 
    500  
    501  
    502     /* Init PJSIP : */ 
    503  
    504     status = init_stack(); 
    505     if (status != PJ_SUCCESS) { 
    506         pj_caching_pool_destroy(&pjsua.cp); 
    507         pjsua_perror(THIS_FILE, "Stack initialization has returned error",  
    508                      status); 
    509         return status; 
    510     } 
    511  
    512  
    513874    /* Init core SIMPLE module : */ 
    514875 
     
    531892    pjsua_im_init(); 
    532893 
    533  
    534     /* Init media endpoint: */ 
    535  
    536     status = pjmedia_endpt_create(&pjsua.cp.factory,  
    537                                   pjsip_endpt_get_ioqueue(pjsua.endpt), 0, 
    538                                   &pjsua.med_endpt); 
    539     if (status != PJ_SUCCESS) { 
    540         pj_caching_pool_destroy(&pjsua.cp); 
    541         pjsua_perror(THIS_FILE,  
    542                      "Media stack initialization has returned error",  
    543                      status); 
    544         return status; 
    545     } 
    546894 
    547895    /* Done. */ 
    548896    return PJ_SUCCESS; 
     897 
     898on_error: 
     899    pj_caching_pool_destroy(&pjsua.cp); 
     900    return status; 
    549901} 
    550902 
     
    557909    pjsip_uri *uri; 
    558910    pjsip_sip_uri *sip_uri; 
    559     int acc_index; 
     911    unsigned acc_index; 
    560912 
    561913    uri = rdata->msg_info.to->uri; 
    562914 
    563     /* Just return account #0 if To URI is not SIP: */ 
     915    /* Just return last account if To URI is not SIP: */ 
    564916    if (!PJSIP_URI_SCHEME_IS_SIP(uri) &&  
    565917        !PJSIP_URI_SCHEME_IS_SIPS(uri))  
    566918    { 
    567         return 0; 
     919        return pjsua.config.acc_cnt; 
    568920    } 
    569921 
     
    572924 
    573925    /* Find account which has matching username and domain. */ 
    574     for (acc_index=0; acc_index < pjsua.acc_cnt; ++acc_index) { 
     926    for (acc_index=0; acc_index < pjsua.config.acc_cnt; ++acc_index) { 
    575927 
    576928        pjsua_acc *acc = &pjsua.acc[acc_index]; 
     
    585937 
    586938    /* No matching, try match domain part only. */ 
    587     for (acc_index=0; acc_index < pjsua.acc_cnt; ++acc_index) { 
     939    for (acc_index=0; acc_index < pjsua.config.acc_cnt; ++acc_index) { 
    588940 
    589941        pjsua_acc *acc = &pjsua.acc[acc_index]; 
     
    595947    } 
    596948 
    597     /* Still no match, just return account #0 */ 
    598     return 0; 
     949    /* Still no match, just return last account */ 
     950    return pjsua.config.acc_cnt; 
    599951} 
    600952 
     
    611963} 
    612964 
    613  
    614 /* 
    615  * Init media. 
    616  */ 
    617 static pj_status_t init_media(void) 
    618 { 
    619     int i; 
    620     unsigned options; 
    621     unsigned clock_rate; 
    622     unsigned samples_per_frame; 
    623     pj_str_t codec_id; 
    624     pj_status_t status; 
    625  
    626     /* Register all codecs */ 
    627 #if PJMEDIA_HAS_SPEEX_CODEC 
    628     /* Register speex. */ 
    629     status = pjmedia_codec_speex_init(pjsua.med_endpt,  
    630                                       PJMEDIA_SPEEX_NO_UWB, 
    631                                       pjsua.quality, pjsua.complexity ); 
    632     if (status != PJ_SUCCESS) { 
    633         pjsua_perror(THIS_FILE, "Error initializing Speex codec", 
    634                      status); 
    635         return status; 
    636     } 
    637  
    638     /* Set "speex/16000/1" to have highest priority */ 
    639     codec_id = pj_str("speex/16000/1"); 
    640     pjmedia_codec_mgr_set_codec_priority(  
    641         pjmedia_endpt_get_codec_mgr(pjsua.med_endpt), 
    642         &codec_id,  
    643         PJMEDIA_CODEC_PRIO_HIGHEST); 
    644  
    645 #endif /* PJMEDIA_HAS_SPEEX_CODEC */ 
    646  
    647 #if PJMEDIA_HAS_GSM_CODEC 
    648     /* Register GSM */ 
    649     status = pjmedia_codec_gsm_init(pjsua.med_endpt); 
    650     if (status != PJ_SUCCESS) { 
    651         pjsua_perror(THIS_FILE, "Error initializing GSM codec", 
    652                      status); 
    653         return status; 
    654     } 
    655 #endif /* PJMEDIA_HAS_GSM_CODEC */ 
    656  
    657 #if PJMEDIA_HAS_G711_CODEC 
    658     /* Register PCMA and PCMU */ 
    659     status = pjmedia_codec_g711_init(pjsua.med_endpt); 
    660     if (status != PJ_SUCCESS) { 
    661         pjsua_perror(THIS_FILE, "Error initializing G711 codec", 
    662                      status); 
    663         return status; 
    664     } 
    665 #endif  /* PJMEDIA_HAS_G711_CODEC */ 
    666  
    667 #if PJMEDIA_HAS_L16_CODEC 
    668     /* Register L16 family codecs, but disable all */ 
    669     status = pjmedia_codec_l16_init(pjsua.med_endpt, 0); 
    670     if (status != PJ_SUCCESS) { 
    671         pjsua_perror(THIS_FILE, "Error initializing L16 codecs", 
    672                      status); 
    673         return status; 
    674     } 
    675  
    676     /* Disable ALL L16 codecs */ 
    677     codec_id = pj_str("L16"); 
    678     pjmedia_codec_mgr_set_codec_priority(  
    679         pjmedia_endpt_get_codec_mgr(pjsua.med_endpt), 
    680         &codec_id,  
    681         PJMEDIA_CODEC_PRIO_DISABLED); 
    682  
    683 #endif  /* PJMEDIA_HAS_L16_CODEC */ 
    684  
    685  
    686     /* Enable those codecs that user put with "--add-codec", and move 
    687      * the priority to top 
    688      */ 
    689     for (i=0; i<pjsua.codec_cnt; ++i) { 
    690         pjmedia_codec_mgr_set_codec_priority(  
    691             pjmedia_endpt_get_codec_mgr(pjsua.med_endpt), 
    692             &pjsua.codec_arg[i],  
    693             PJMEDIA_CODEC_PRIO_HIGHEST); 
    694     } 
    695  
    696  
    697     /* Init options for conference bridge. */ 
    698     options = 0; 
    699     if (pjsua.no_mic) 
    700         options |= PJMEDIA_CONF_NO_MIC; 
    701  
    702     /* Init conference bridge. */ 
    703     clock_rate = pjsua.clock_rate ? pjsua.clock_rate : 16000; 
    704     samples_per_frame = clock_rate * 10 / 1000; 
    705     status = pjmedia_conf_create(pjsua.pool,  
    706                                  pjsua.max_calls+PJSUA_CONF_MORE_PORTS,  
    707                                  clock_rate,  
    708                                  1, /* mono */ 
    709                                  samples_per_frame,  
    710                                  16,  
    711                                  options, 
    712                                  &pjsua.mconf); 
    713     if (status != PJ_SUCCESS) { 
    714         pjsua_perror(THIS_FILE,  
    715                      "Media stack initialization has returned error",  
    716                      status); 
    717         return status; 
    718     } 
    719  
    720     /* Add NULL port to the bridge. */ 
    721     status = pjmedia_null_port_create( pjsua.pool, clock_rate,  
    722                                        1, /* mono */ 
    723                                        samples_per_frame, 16, 
    724                                        &pjsua.null_port); 
    725     pjmedia_conf_add_port( pjsua.mconf, pjsua.pool, pjsua.null_port,  
    726                            &pjsua.null_port->info.name, NULL ); 
    727  
    728     /* Create WAV file player if required: */ 
    729  
    730     if (pjsua.wav_file) { 
    731         pj_str_t port_name; 
    732  
    733         /* Create the file player port. */ 
    734         status = pjmedia_wav_player_port_create(  pjsua.pool, pjsua.wav_file, 
    735                                                   0, 0, -1, NULL,  
    736                                                   &pjsua.file_port); 
    737         if (status != PJ_SUCCESS) { 
    738             pjsua_perror(THIS_FILE,  
    739                          "Error playing media file",  
    740                          status); 
    741             return status; 
    742         } 
    743  
    744         /* Add port to conference bridge: */ 
    745         status = pjmedia_conf_add_port(pjsua.mconf, pjsua.pool,  
    746                                        pjsua.file_port,  
    747                                        pj_cstr(&port_name, pjsua.wav_file), 
    748                                        &pjsua.wav_slot); 
    749         if (status != PJ_SUCCESS) { 
    750             pjsua_perror(THIS_FILE,  
    751                          "Unable to add file player to conference bridge",  
    752                          status); 
    753             return status; 
    754         } 
    755     } 
    756  
    757  
    758     return PJ_SUCCESS; 
    759 } 
    760965 
    761966 
     
    764969 * This will start the registration process, if registration is configured. 
    765970 */ 
    766 pj_status_t pjsua_start(void) 
     971PJ_DEF(pj_status_t) pjsua_start(void) 
    767972{ 
    768973    int i;  /* Must be signed */ 
    769     pjsip_transport *udp_transport; 
    770974    pj_status_t status = PJ_SUCCESS; 
    771975 
    772     /* 
    773      * Init media subsystem (codecs, conference bridge, et all). 
    774      */ 
    775     status = init_media(); 
    776     if (status != PJ_SUCCESS) 
    777         return status; 
    778  
    779     /* Init sockets (STUN etc): */ 
    780     for (i=0; i<(int)pjsua.max_calls; ++i) { 
    781         status = init_sockets(i==0, &pjsua.calls[i].skinfo); 
    782         if (status == PJ_SUCCESS) 
    783             status = pjmedia_transport_udp_attach(pjsua.med_endpt, NULL, 
    784                                                   &pjsua.calls[i].skinfo, 
    785                                                   &pjsua.calls[i].med_tp); 
    786         if (status != PJ_SUCCESS) { 
    787             pjsua_perror(THIS_FILE, "init_sockets() has returned error",  
    788                          status); 
    789             --i; 
    790             if (i >= 0) 
    791                 pj_sock_close(pjsua.sip_sock); 
    792             while (i >= 0) { 
    793                 pjmedia_transport_udp_close(pjsua.calls[i].med_tp); 
    794             } 
    795             return status; 
    796         } 
    797     } 
    798976 
    799977    /* Add UDP transport: */ 
    800  
    801     { 
     978    if (pjsua.sip_sock > 0) { 
     979 
    802980        /* Init the published name for the transport. 
    803981         * Depending whether STUN is used, this may be the STUN mapped 
     
    806984        pjsip_host_port addr_name; 
    807985 
    808         addr_name.host.ptr = pj_inet_ntoa(pjsua.sip_sock_name.sin_addr); 
    809         addr_name.host.slen = pj_ansi_strlen(addr_name.host.ptr); 
    810         addr_name.port = pj_ntohs(pjsua.sip_sock_name.sin_port); 
     986        addr_name.host = pjsua.config.sip_host; 
     987        addr_name.port = pjsua.config.sip_port; 
    811988 
    812989        /* Create UDP transport from previously created UDP socket: */ 
     
    814991        status = pjsip_udp_transport_attach( pjsua.endpt, pjsua.sip_sock, 
    815992                                             &addr_name, 1,  
    816                                              &udp_transport); 
     993                                             NULL); 
    817994        if (status != PJ_SUCCESS) { 
    818995            pjsua_perror(THIS_FILE, "Unable to start UDP transport",  
     
    822999    } 
    8231000 
    824     /* Initialize Contact URI, if one is not specified: */ 
    825     for (i=0; i<pjsua.acc_cnt; ++i) { 
    826  
     1001    /* The last account is default account to be used when nothing match  
     1002     * any configured accounts. 
     1003     */ 
     1004    { 
     1005        char buf[80]; 
     1006        pj_str_t tmp; 
     1007        pjsua_acc_config *acc_cfg =  
     1008            &pjsua.config.acc_config[pjsua.config.acc_cnt]; 
     1009 
     1010        tmp.ptr = buf; 
     1011        tmp.slen = pj_ansi_sprintf(tmp.ptr, "<sip:%s:%d>",  
     1012                                   pjsua.config.sip_host.ptr, 
     1013                                   pjsua.config.sip_port); 
     1014 
     1015        pj_strdup_with_null( pjsua.pool, &acc_cfg->id, &tmp); 
     1016        acc_cfg->contact = acc_cfg->id; 
     1017    } 
     1018     
     1019 
     1020    /* Initialize accounts: */ 
     1021    for (i=0; i<(int)pjsua.config.acc_cnt; ++i) { 
     1022 
     1023        pjsua_acc_config *acc_cfg = &pjsua.config.acc_config[i]; 
     1024        pjsua_acc *acc = &pjsua.acc[i]; 
    8271025        pjsip_uri *uri; 
    8281026        pjsip_sip_uri *sip_uri; 
     
    8301028        /* Need to parse local_uri to get the elements: */ 
    8311029 
    832         uri = pjsip_parse_uri(pjsua.pool, pjsua.acc[i].local_uri.ptr, 
    833                               pjsua.acc[i].local_uri.slen, 0); 
     1030        uri = pjsip_parse_uri(pjsua.pool, acc_cfg->id.ptr, 
     1031                              acc_cfg->id.slen, 0); 
    8341032        if (uri == NULL) { 
    8351033            pjsua_perror(THIS_FILE, "Invalid local URI",  
     
    8531051        sip_uri = (pjsip_sip_uri*) pjsip_uri_get_uri(uri); 
    8541052 
    855         pjsua.acc[i].user_part = sip_uri->user; 
    856         pjsua.acc[i].host_part = sip_uri->host; 
    857  
    858         if (pjsua.acc[i].contact_uri.slen == 0 &&  
    859             pjsua.acc[i].local_uri.slen)  
    860         { 
     1053        acc->user_part = sip_uri->user; 
     1054        acc->host_part = sip_uri->host; 
     1055 
     1056        /* Build Contact header */ 
     1057 
     1058        if (acc_cfg->contact.slen == 0)  { 
    8611059            char contact[128]; 
     1060            const char *addr; 
     1061            int port; 
    8621062            int len; 
     1063 
     1064            addr = pjsua.config.sip_host.ptr; 
     1065            port = pjsua.config.sip_port; 
    8631066 
    8641067            /* The local Contact is the username@ip-addr, where 
     
    8741077                /* With the user part. */ 
    8751078                len = pj_ansi_snprintf(contact, sizeof(contact), 
    876                                   "<sip:%.*s@%.*s:%d>", 
     1079                                  "<sip:%.*s@%s:%d>", 
    8771080                                  (int)sip_uri->user.slen, 
    8781081                                  sip_uri->user.ptr, 
    879                                   (int)udp_transport->local_name.host.slen, 
    880                                   udp_transport->local_name.host.ptr, 
    881                                   udp_transport->local_name.port); 
     1082                                  addr, port); 
    8821083            } else { 
    8831084 
     
    8851086 
    8861087                len = pj_ansi_snprintf(contact, sizeof(contact), 
    887                                   "<sip:%.*s:%d>", 
    888                                   (int)udp_transport->local_name.host.slen, 
    889                                   udp_transport->local_name.host.ptr, 
    890                                   udp_transport->local_name.port); 
     1088                                  "<sip:%s:%d>", 
     1089                                  addr, port); 
    8911090            } 
    8921091 
     
    8981097            /* Duplicate Contact uri. */ 
    8991098 
    900             pj_strdup2(pjsua.pool, &pjsua.acc[i].contact_uri, contact); 
    901  
    902         } 
    903     } 
    904  
    905     /* If outbound_proxy is specified, put it in the route_set: */ 
    906  
    907     if (pjsua.outbound_proxy.slen) { 
    908  
    909         pjsip_route_hdr *route; 
    910         const pj_str_t hname = { "Route", 5 }; 
    911         int parsed_len; 
    912  
    913         route = pjsip_parse_hdr( pjsua.pool, &hname,  
    914                                  pjsua.outbound_proxy.ptr,  
    915                                  pjsua.outbound_proxy.slen, 
    916                                    &parsed_len); 
    917         if (route == NULL) { 
    918             pjsua_perror(THIS_FILE, "Invalid outbound proxy URL",  
    919                          PJSIP_EINVALIDURI); 
    920             return PJSIP_EINVALIDURI; 
    921         } 
    922  
    923         for (i=0; i<pjsua.acc_cnt; ++i) { 
    924             pj_list_push_front(&pjsua.acc[i].route_set, route); 
    925         } 
    926     } 
     1099            pj_strdup2(pjsua.pool, &acc_cfg->contact, contact); 
     1100 
     1101        } 
     1102 
     1103 
     1104        /* Build route-set for this account */ 
     1105        if (pjsua.config.outbound_proxy.slen) { 
     1106            pj_str_t hname = { "Route", 5}; 
     1107            pjsip_route_hdr *r; 
     1108            pj_str_t tmp; 
     1109 
     1110            pj_strdup_with_null(pjsua.pool, &tmp, &pjsua.config.outbound_proxy); 
     1111            r = pjsip_parse_hdr(pjsua.pool, &hname, tmp.ptr, tmp.slen, NULL); 
     1112            pj_list_push_back(&acc->route_set, r); 
     1113        } 
     1114 
     1115        if (acc_cfg->proxy.slen) { 
     1116            pj_str_t hname = { "Route", 5}; 
     1117            pjsip_route_hdr *r; 
     1118            pj_str_t tmp; 
     1119 
     1120            pj_strdup_with_null(pjsua.pool, &tmp, &acc_cfg->proxy); 
     1121            r = pjsip_parse_hdr(pjsua.pool, &hname, tmp.ptr, tmp.slen, NULL); 
     1122            pj_list_push_back(&acc->route_set, r); 
     1123        } 
     1124    } 
     1125 
     1126 
    9271127 
    9281128 
    9291129    /* Create worker thread(s), if required: */ 
    9301130 
    931     for (i=0; i<pjsua.thread_cnt; ++i) { 
     1131    for (i=0; i<(int)pjsua.config.thread_cnt; ++i) { 
    9321132        status = pj_thread_create( pjsua.pool, "pjsua", &pjsua_poll, 
    9331133                                   NULL, 0, 0, &pjsua.threads[i]); 
     
    9451145 
    9461146    /* Create client registration session: */ 
    947     for (i=0; i<pjsua.acc_cnt; ++i) { 
     1147    for (i=0; i<(int)pjsua.config.acc_cnt; ++i) { 
    9481148        status = pjsua_regc_init(i); 
    9491149        if (status != PJ_SUCCESS) 
     
    9561156    } 
    9571157 
     1158 
     1159    /* Init buddies */ 
     1160    for (i=0; i<(int)pjsua.config.buddy_cnt; ++i) { 
     1161        pjsua.buddies[i].uri = pjsua.config.buddy_uri[i]; 
     1162    } 
     1163    pjsua.buddy_cnt = pjsua.config.buddy_cnt; 
    9581164 
    9591165    /* Find account for outgoing preence subscription */ 
     
    9871193 * Destroy pjsua. 
    9881194 */ 
    989 pj_status_t pjsua_destroy(void) 
     1195PJ_DEF(pj_status_t) pjsua_destroy(void) 
    9901196{ 
    9911197    int i;  /* Must be signed */ 
     
    10011207 
    10021208    /* Unregister, if required: */ 
    1003     for (i=0; i<pjsua.acc_cnt; ++i) { 
     1209    for (i=0; i<(int)pjsua.config.acc_cnt; ++i) { 
    10041210        if (pjsua.acc[i].regc) { 
    10051211            pjsua_regc_update(i, 0); 
     
    10081214 
    10091215    /* Wait worker threads to quit: */ 
    1010     for (i=0; i<pjsua.thread_cnt; ++i) { 
     1216    for (i=0; i<(int)pjsua.config.thread_cnt; ++i) { 
    10111217         
    10121218        if (pjsua.threads[i]) { 
     
    10301236        pjmedia_port_destroy(pjsua.file_port); 
    10311237 
    1032     /* Destroy null port. */ 
    1033     if (pjsua.null_port) 
    1034         pjmedia_port_destroy(pjsua.null_port); 
    1035  
    10361238 
    10371239    /* Shutdown all codecs: */ 
     
    10541256 
    10551257    /* Close transports */ 
    1056     for (i=0; i<pjsua.call_cnt; ++i) { 
     1258    for (i=0; pjsua.config.start_rtp_port && i<(int)pjsua.config.max_calls; ++i) { 
    10571259        pjmedia_transport_udp_close(pjsua.calls[i].med_tp); 
    10581260    } 
  • pjproject/trunk/pjsip/src/pjsua-lib/pjsua_im.c

    r300 r476  
    153153        text.slen = rdata->msg_info.msg->body->len; 
    154154 
    155         pjsua_ui_on_pager(call_index, from, to, &text); 
     155        if (pjsua.cb.on_pager) 
     156            (*pjsua.cb.on_pager)(call_index, from, to, &text); 
    156157 
    157158    } else { 
     
    170171        } 
    171172 
    172         pjsua_ui_on_typing(call_index, from, to, is_typing); 
     173        if (pjsua.cb.on_typing) 
     174            (*pjsua.cb.on_typing)(call_index, from, to, is_typing); 
    173175    } 
    174176 
     
    270272 * Send IM outside dialog. 
    271273 */ 
    272 pj_status_t pjsua_im_send(int acc_index, const char *dst_uri,  
    273                           const char *str) 
     274PJ_DEF(pj_status_t) pjsua_im_send(int acc_index, const char *dst_uri,  
     275                                  const char *str) 
    274276{ 
    275277    pjsip_tx_data *tdata; 
     
    282284 
    283285    /* Create request. */ 
    284     status = pjsip_endpt_create_request( pjsua.endpt, &pjsip_message_method, 
    285                                          &dst, &pjsua.acc[acc_index].local_uri, 
    286                                          &dst, NULL, NULL, -1, NULL, &tdata); 
     286    status = pjsip_endpt_create_request(pjsua.endpt, &pjsip_message_method, 
     287                                        &dst,  
     288                                        &pjsua.config.acc_config[acc_index].id, 
     289                                        &dst, NULL, NULL, -1, NULL, &tdata); 
    287290    if (status != PJ_SUCCESS) { 
    288291        pjsua_perror(THIS_FILE, "Unable to create request", status); 
     
    296299    /* Add contact. */ 
    297300    pjsip_msg_add_hdr( tdata->msg, (pjsip_hdr*) 
    298                        pjsip_generic_string_hdr_create(tdata->pool,  
    299                                                        &STR_CONTACT, 
    300                                                        &pjsua.acc[acc_index].contact_uri)); 
     301        pjsip_generic_string_hdr_create(tdata->pool,  
     302                                        &STR_CONTACT, 
     303                                        &pjsua.config.acc_config[acc_index].contact)); 
    301304 
    302305    /* Duplicate text. 
     
    331334 * Send typing indication outside dialog. 
    332335 */ 
    333 pj_status_t pjsua_im_typing(int acc_index, const char *dst_uri,  
    334                             pj_bool_t is_typing) 
     336PJ_DEF(pj_status_t) pjsua_im_typing(int acc_index, const char *dst_uri,  
     337                                    pj_bool_t is_typing) 
    335338{ 
    336339    const pj_str_t dst = pj_str((char*)dst_uri); 
     
    340343    /* Create request. */ 
    341344    status = pjsip_endpt_create_request( pjsua.endpt, &pjsip_message_method, 
    342                                          &dst, &pjsua.acc[acc_index].local_uri, 
     345                                         &dst,  
     346                                         &pjsua.config.acc_config[acc_index].id, 
    343347                                         &dst, NULL, NULL, -1, NULL, &tdata); 
    344348    if (status != PJ_SUCCESS) { 
  • pjproject/trunk/pjsip/src/pjsua-lib/pjsua_pres.c

    r424 r476  
    1818 */ 
    1919#include <pjsua-lib/pjsua.h> 
     20#include "pjsua_imp.h" 
    2021 
    2122/* 
     
    8182{ 
    8283    int acc_index; 
     84    pjsua_acc_config *acc_config; 
    8385    pjsip_method *req_method = &rdata->msg_info.msg->line.req.method; 
    8486    pjsua_srv_pres *uapres; 
     
    9799    /* Find which account for the incoming request. */ 
    98100    acc_index = pjsua_find_account_for_incoming(rdata); 
     101    acc_config = &pjsua.config.acc_config[acc_index]; 
    99102 
    100103    /* Create UAS dialog: */ 
    101     status = pjsip_dlg_create_uas( pjsip_ua_instance(), rdata,  
    102                                    &pjsua.acc[acc_index].contact_uri,  
    103                                    &dlg); 
     104    status = pjsip_dlg_create_uas(pjsip_ua_instance(), rdata,  
     105                                  &acc_config->contact, 
     106                                  &dlg); 
    104107    if (status != PJ_SUCCESS) { 
    105108        pjsua_perror(THIS_FILE,  
     
    307310{ 
    308311    int acc_index; 
     312    pjsua_acc_config *acc_config; 
    309313    pjsip_dialog *dlg; 
    310314    pjsip_tx_data *tdata; 
     
    312316 
    313317    acc_index = pjsua.buddies[index].acc_index; 
     318    acc_config = &pjsua.config.acc_config[acc_index]; 
    314319 
    315320    status = pjsip_dlg_create_uac( pjsip_ua_instance(),  
    316                                    &pjsua.acc[acc_index].local_uri, 
    317                                    &pjsua.acc[acc_index].contact_uri, 
     321                                   &acc_config->id, 
     322                                   &acc_config->contact, 
    318323                                   &pjsua.buddies[index].uri, 
    319324                                   NULL, &dlg); 
     
    324329    } 
    325330 
    326     pjsip_auth_clt_set_credentials( &dlg->auth_sess, pjsua.cred_count, 
    327                                     pjsua.cred_info); 
     331    if (acc_config->cred_count) { 
     332        pjsip_auth_clt_set_credentials( &dlg->auth_sess,  
     333                                        acc_config->cred_count, 
     334                                        acc_config->cred_info); 
     335    } 
    328336 
    329337    status = pjsip_pres_create_uac( dlg, &pres_callback,  
     
    427435 * Refresh presence 
    428436 */ 
    429 void pjsua_pres_refresh(int acc_index) 
     437PJ_DEF(void) pjsua_pres_refresh(int acc_index) 
    430438{ 
    431439    refresh_client_subscription(); 
     
    442450    int i; 
    443451 
    444     for (acc_index=0; acc_index<pjsua.acc_cnt; ++acc_index) { 
     452    for (acc_index=0; acc_index<(int)pjsua.config.acc_cnt; ++acc_index) { 
    445453        pjsua.acc[acc_index].online_status = 0; 
    446454    } 
     
    450458    } 
    451459 
    452     for (acc_index=0; acc_index<pjsua.acc_cnt; ++acc_index) { 
     460    for (acc_index=0; acc_index<(int)pjsua.config.acc_cnt; ++acc_index) { 
    453461        pjsua_pres_refresh(acc_index); 
    454462    } 
     
    472480        int count = 0; 
    473481 
    474         for (acc_index=0; acc_index < pjsua.acc_cnt; ++acc_index) { 
     482        for (acc_index=0; acc_index < (int)pjsua.config.acc_cnt; ++acc_index) { 
    475483 
    476484            if (!pj_list_empty(&pjsua.acc[acc_index].pres_srv_list)) { 
     
    507515    PJ_LOG(3,(THIS_FILE, "Dumping pjsua server subscriptions:")); 
    508516 
    509     for (acc_index=0; acc_index < pjsua.acc_cnt; ++acc_index) { 
     517    for (acc_index=0; acc_index < (int)pjsua.config.acc_cnt; ++acc_index) { 
    510518 
    511519        PJ_LOG(3,(THIS_FILE, "  %.*s", 
    512                   (int)pjsua.acc[acc_index].local_uri.slen, 
    513                   pjsua.acc[acc_index].local_uri.ptr)); 
     520                  (int)pjsua.config.acc_config[acc_index].id.slen, 
     521                  pjsua.config.acc_config[acc_index].id.ptr)); 
    514522 
    515523        if (pj_list_empty(&pjsua.acc[acc_index].pres_srv_list)) { 
  • pjproject/trunk/pjsip/src/pjsua-lib/pjsua_reg.c

    r268 r476  
    6060            acc->regc = NULL; 
    6161            PJ_LOG(3,(THIS_FILE, "%s: unregistration success", 
    62                       acc->local_uri.ptr)); 
     62                      pjsua.config.acc_config[acc->index].id.ptr)); 
    6363        } else { 
    6464            PJ_LOG(3, (THIS_FILE,  
    6565                       "%s: registration success, status=%d (%s), " 
    6666                       "will re-register in %d seconds",  
    67                        acc->local_uri.ptr, 
     67                       pjsua.config.acc_config[acc->index].id.ptr, 
    6868                       param->code, 
    6969                       pjsip_get_status_text(param->code)->ptr, 
     
    7878    acc->reg_last_code = param->code; 
    7979 
    80     pjsua_ui_on_reg_state(acc->index); 
     80    if (pjsua.cb.on_reg_state) 
     81        (*pjsua.cb.on_reg_state)(acc->index); 
    8182} 
    8283 
     
    8586 * Update registration. If renew is false, then unregistration will be performed. 
    8687 */ 
    87 void pjsua_regc_update(int acc_index, pj_bool_t renew) 
     88PJ_DECL(void) pjsua_regc_update(int acc_index, pj_bool_t renew) 
    8889{ 
    8990    pj_status_t status = 0; 
     
    130131pj_status_t pjsua_regc_init(int acc_index) 
    131132{ 
     133    pjsua_acc_config *acc_config; 
    132134    pj_status_t status; 
    133135 
    134     if (pjsua.acc[acc_index].reg_uri.slen == 0) { 
     136    acc_config = &pjsua.config.acc_config[acc_index]; 
     137 
     138    if (acc_config->reg_uri.slen == 0) { 
    135139        PJ_LOG(3,(THIS_FILE, "Registrar URI is not specified")); 
    136140        return PJ_SUCCESS; 
     
    152156 
    153157    status = pjsip_regc_init( pjsua.acc[acc_index].regc,  
    154                               &pjsua.acc[acc_index].reg_uri,  
    155                               &pjsua.acc[acc_index].local_uri,  
    156                               &pjsua.acc[acc_index].local_uri, 
    157                               1, &pjsua.acc[acc_index].contact_uri,  
    158                               pjsua.acc[acc_index].reg_timeout); 
     158                              &acc_config->reg_uri,  
     159                              &acc_config->id,  
     160                              &acc_config->id, 
     161                              1, &acc_config->contact,  
     162                              acc_config->reg_timeout); 
    159163    if (status != PJ_SUCCESS) { 
    160164        pjsua_perror(THIS_FILE,  
     
    164168    } 
    165169 
    166     pjsip_regc_set_credentials( pjsua.acc[acc_index].regc,  
    167                                 pjsua.cred_count,  
    168                                 pjsua.cred_info ); 
     170    if (acc_config->cred_count) { 
     171        pjsip_regc_set_credentials( pjsua.acc[acc_index].regc,  
     172                                    acc_config->cred_count,  
     173                                    acc_config->cred_info ); 
     174    } 
    169175 
    170176    pjsip_regc_set_route_set( pjsua.acc[acc_index].regc,  
  • pjproject/trunk/pjsip/src/pjsua-lib/pjsua_settings.c

    r438 r476  
    6060    puts  (""); 
    6161    puts  ("SIP Account options:"); 
     62    puts  ("  --registrar=url     Set the URL of registrar server"); 
    6263    puts  ("  --id=url            Set the URL of local ID (used in From header)"); 
    63     puts  ("  --contact=url       Override the Contact information"); 
    64     puts  ("  --proxy=url         Set the URL of proxy server"); 
    65     puts  (""); 
    66     puts  ("SIP Account Registration Options:"); 
    67     puts  ("  --registrar=url     Set the URL of registrar server"); 
    68     puts  ("  --reg-timeout=secs  Set registration interval to secs (default 3600)"); 
     64    puts  ("  --contact=url       Optionally override the Contact information"); 
     65    puts  ("  --proxy=url         Optional URL of proxy server to visit"); 
     66    puts  ("  --realm=string      Set realm"); 
     67    puts  ("  --username=string   Set authentication username"); 
     68    puts  ("  --password=string   Set authentication password"); 
     69    puts  ("  --reg-timeout=SEC   Optional registration interval (default 55)"); 
    6970    puts  (""); 
    7071    puts  ("SIP Account Control:"); 
    7172    puts  ("  --next-account      Add more account"); 
    72     puts  (""); 
    73     puts  ("Authentication options:"); 
    74     puts  ("  --realm=string      Set realm"); 
    75     puts  ("  --username=string   Set authentication username"); 
    76     puts  ("  --password=string   Set authentication password"); 
    77     puts  ("  --next-cred         Add more credential"); 
    7873    puts  (""); 
    7974    puts  ("Transport Options:"); 
     
    8782    puts  ("  --clock-rate=N      Override sound device clock rate"); 
    8883    puts  ("  --null-audio        Use NULL audio device"); 
    89     puts  ("  --no-mic            Disable microphone device"); 
    9084    puts  ("  --play-file=file    Play WAV file in conference bridge"); 
    9185    puts  ("  --auto-play         Automatically play the file (to incoming calls only)"); 
     
    114108 * Verify that valid SIP url is given. 
    115109 */ 
    116 pj_status_t pjsua_verify_sip_url(const char *c_url) 
     110PJ_DEF(pj_status_t) pjsua_verify_sip_url(const char *c_url) 
    117111{ 
    118112    pjsip_uri *p; 
     
    215209 
    216210/* Parse arguments. */ 
    217 pj_status_t pjsua_parse_args(int argc, char *argv[]) 
     211PJ_DEF(pj_status_t) pjsua_parse_args(int argc, char *argv[], 
     212                                     pjsua_config *cfg) 
    218213{ 
    219214    int c; 
    220215    int option_index; 
    221216    enum { OPT_CONFIG_FILE, OPT_LOG_FILE, OPT_LOG_LEVEL, OPT_APP_LOG_LEVEL,  
    222            OPT_HELP, OPT_VERSION, OPT_NULL_AUDIO, OPT_NO_MIC, 
     217           OPT_HELP, OPT_VERSION, OPT_NULL_AUDIO,  
    223218           OPT_LOCAL_PORT, OPT_PROXY, OPT_OUTBOUND_PROXY, OPT_REGISTRAR, 
    224219           OPT_REG_TIMEOUT, OPT_ID, OPT_CONTACT,  
     
    230225           OPT_PLAY_FILE, OPT_RTP_PORT, OPT_ADD_CODEC, 
    231226           OPT_COMPLEXITY, OPT_QUALITY, OPT_PTIME, 
    232            OPT_NEXT_ACCOUNT, OPT_NEXT_CRED, OPT_MAX_CALLS, OPT_UAS_REFRESH, 
     227           OPT_NEXT_ACCOUNT, OPT_MAX_CALLS, OPT_UAS_REFRESH, 
    233228           OPT_UAS_DURATION, 
    234229    }; 
     
    242237        { "clock-rate", 1, 0, OPT_CLOCK_RATE}, 
    243238        { "null-audio", 0, 0, OPT_NULL_AUDIO}, 
    244         { "no-mic",     0, 0, OPT_NO_MIC}, 
    245239        { "local-port", 1, 0, OPT_LOCAL_PORT}, 
    246240        { "proxy",      1, 0, OPT_PROXY}, 
     
    270264        { "ptime",      1, 0, OPT_PTIME}, 
    271265        { "next-account",0,0, OPT_NEXT_ACCOUNT}, 
    272         { "next-cred",  0, 0, OPT_NEXT_CRED}, 
    273266        { "max-calls",  1, 0, OPT_MAX_CALLS}, 
    274267        { "uas-refresh",1, 0, OPT_UAS_REFRESH}, 
     
    277270    }; 
    278271    pj_status_t status; 
    279     pjsua_acc *cur_acc; 
    280     pjsip_cred_info *cur_cred; 
     272    pjsua_acc_config *cur_acc; 
     273    char errmsg[80]; 
    281274    char *config_file = NULL; 
     275    unsigned i; 
    282276 
    283277    /* Run pj_getopt once to see if user specifies config file to read. */  
    284     while ((c=pj_getopt_long(argc, argv, "", long_options, &option_index)) != -1) { 
     278    while ((c=pj_getopt_long(argc, argv, "", long_options,  
     279                             &option_index)) != -1)  
     280    { 
    285281        switch (c) { 
    286282        case OPT_CONFIG_FILE: 
     
    298294    } 
    299295 
    300  
    301     cur_acc = &pjsua.acc[0]; 
    302     cur_cred = &pjsua.cred_info[0]; 
     296    cfg->acc_cnt = 0; 
     297    cur_acc = &cfg->acc_config[0]; 
    303298 
    304299 
     
    307302     */ 
    308303    pj_optind = 0; 
    309     while((c=pj_getopt_long(argc, argv, "", long_options, &option_index))!=-1) { 
     304    while((c=pj_getopt_long(argc,argv, "", long_options,&option_index))!=-1) { 
    310305        char *p; 
    311306        pj_str_t tmp; 
     
    315310 
    316311        case OPT_LOG_FILE: 
    317             pjsua.log_filename = pj_optarg; 
     312            cfg->log_filename = pj_str(pj_optarg); 
    318313            break; 
    319314 
     
    326321                return PJ_EINVAL; 
    327322            } 
     323            cfg->log_level = c; 
    328324            pj_log_set_level( c ); 
    329325            break; 
    330326 
    331327        case OPT_APP_LOG_LEVEL: 
    332             pjsua.app_log_level = pj_strtoul(pj_cstr(&tmp, pj_optarg)); 
    333             if (pjsua.app_log_level < 0 || pjsua.app_log_level > 6) { 
     328            cfg->app_log_level = pj_strtoul(pj_cstr(&tmp, pj_optarg)); 
     329            if (cfg->app_log_level < 0 || cfg->app_log_level > 6) { 
    334330                PJ_LOG(1,(THIS_FILE,  
    335331                          "Error: expecting integer value 0-6 " 
     
    348344 
    349345        case OPT_NULL_AUDIO: 
    350             pjsua.null_audio = 1; 
    351             break; 
    352  
    353         case OPT_NO_MIC: 
    354             pjsua.no_mic = 1; 
     346            cfg->null_audio = 1; 
    355347            break; 
    356348 
     
    362354                return PJ_EINVAL; 
    363355            } 
    364             pjsua.clock_rate = (int)lval;  
     356            cfg->clock_rate = lval;  
    365357            break; 
    366358 
     
    373365                return PJ_EINVAL; 
    374366            } 
    375             pjsua.sip_port = (pj_uint16_t)lval; 
     367            cfg->udp_port = (pj_uint16_t)lval; 
    376368            break; 
    377369 
     
    393385                return PJ_EINVAL; 
    394386            } 
    395             pjsua.outbound_proxy = pj_str(pj_optarg); 
     387            cfg->outbound_proxy = pj_str(pj_optarg); 
    396388            break; 
    397389 
     
    423415                return PJ_EINVAL; 
    424416            } 
    425             cur_acc->local_uri = pj_str(pj_optarg); 
    426             pjsua.has_acc = 1; 
     417            cur_acc->id = pj_str(pj_optarg); 
    427418            break; 
    428419 
     
    434425                return PJ_EINVAL; 
    435426            } 
    436             cur_acc->contact_uri = pj_str(pj_optarg); 
     427            cur_acc->contact = pj_str(pj_optarg); 
    437428            break; 
    438429 
    439430        case OPT_NEXT_ACCOUNT: /* Add more account. */ 
    440             pjsua.acc_cnt++; 
    441             cur_acc = &pjsua.acc[pjsua.acc_cnt - 1]; 
     431            cfg->acc_cnt++; 
     432            cur_acc = &cfg->acc_config[cfg->acc_cnt - 1]; 
    442433            break; 
    443434 
    444435        case OPT_USERNAME:   /* Default authentication user */ 
    445             if (pjsua.cred_count==0) pjsua.cred_count=1; 
    446             cur_cred->username = pj_str(pj_optarg); 
     436            cur_acc->cred_info[0].username = pj_str(pj_optarg); 
    447437            break; 
    448438 
    449439        case OPT_REALM:     /* Default authentication realm. */ 
    450             if (pjsua.cred_count==0) pjsua.cred_count=1; 
    451             cur_cred->realm = pj_str(pj_optarg); 
     440            cur_acc->cred_info[0].realm = pj_str(pj_optarg); 
    452441            break; 
    453442 
    454443        case OPT_PASSWORD:   /* authentication password */ 
    455             if (pjsua.cred_count==0) pjsua.cred_count=1; 
    456             cur_cred->data_type = 0; 
    457             cur_cred->data = pj_str(pj_optarg); 
    458             break; 
    459  
    460         case OPT_NEXT_CRED: /* Next credential */ 
    461             pjsua.cred_count++; 
    462             cur_cred = &pjsua.cred_info[pjsua.cred_count - 1]; 
     444            cur_acc->cred_info[0].data_type = PJSIP_CRED_DATA_PLAIN_PASSWD; 
     445            cur_acc->cred_info[0].data = pj_str(pj_optarg); 
    463446            break; 
    464447 
     
    467450            if (p) { 
    468451                *p = '\0'; 
    469                 pjsua.stun_srv1 = pj_str(pj_optarg); 
    470                 pjsua.stun_port1 = pj_strtoul(pj_cstr(&tmp, p+1)); 
    471                 if (pjsua.stun_port1 < 1 || pjsua.stun_port1 > 65535) { 
     452                cfg->stun_srv1 = pj_str(pj_optarg); 
     453                cfg->stun_port1 = pj_strtoul(pj_cstr(&tmp, p+1)); 
     454                if (cfg->stun_port1 < 1 || cfg->stun_port1 > 65535) { 
    472455                    PJ_LOG(1,(THIS_FILE,  
    473456                              "Error: expecting port number with " 
     
    476459                } 
    477460            } else { 
    478                 pjsua.stun_port1 = 3478; 
    479                 pjsua.stun_srv1 = pj_str(pj_optarg); 
     461                cfg->stun_port1 = 3478; 
     462                cfg->stun_srv1 = pj_str(pj_optarg); 
    480463            } 
    481464            break; 
     
    485468            if (p) { 
    486469                *p = '\0'; 
    487                 pjsua.stun_srv2 = pj_str(pj_optarg); 
    488                 pjsua.stun_port2 = pj_strtoul(pj_cstr(&tmp,p+1)); 
    489                 if (pjsua.stun_port2 < 1 || pjsua.stun_port2 > 65535) { 
     470                cfg->stun_srv2 = pj_str(pj_optarg); 
     471                cfg->stun_port2 = pj_strtoul(pj_cstr(&tmp,p+1)); 
     472                if (cfg->stun_port2 < 1 || cfg->stun_port2 > 65535) { 
    490473                    PJ_LOG(1,(THIS_FILE,  
    491474                              "Error: expecting port number with " 
     
    494477                } 
    495478            } else { 
    496                 pjsua.stun_port2 = 3478; 
    497                 pjsua.stun_srv2 = pj_str(pj_optarg); 
     479                cfg->stun_port2 = 3478; 
     480                cfg->stun_srv2 = pj_str(pj_optarg); 
    498481            } 
    499482            break; 
     
    506489                return -1; 
    507490            } 
    508             if (pjsua.buddy_cnt == PJSUA_MAX_BUDDIES) { 
     491            if (cfg->buddy_cnt == PJSUA_MAX_BUDDIES) { 
    509492                PJ_LOG(1,(THIS_FILE,  
    510493                          "Error: too many buddies in buddy list.")); 
    511494                return -1; 
    512495            } 
    513             pjsua.buddies[pjsua.buddy_cnt++].uri = pj_str(pj_optarg); 
     496            cfg->buddy_uri[cfg->buddy_cnt++] = pj_str(pj_optarg); 
    514497            break; 
    515498 
    516499        case OPT_AUTO_PLAY: 
    517             pjsua.auto_play = 1; 
     500            cfg->auto_play = 1; 
    518501            break; 
    519502 
    520503        case OPT_AUTO_LOOP: 
    521             pjsua.auto_loop = 1; 
     504            cfg->auto_loop = 1; 
    522505            break; 
    523506 
    524507        case OPT_AUTO_CONF: 
    525             pjsua.auto_conf = 1; 
     508            cfg->auto_conf = 1; 
    526509            break; 
    527510 
    528511        case OPT_PLAY_FILE: 
    529             pjsua.wav_file = pj_optarg; 
     512            cfg->wav_file = pj_str(pj_optarg); 
    530513            break; 
    531514 
    532515        case OPT_RTP_PORT: 
    533             pjsua.start_rtp_port = my_atoi(pj_optarg); 
    534             if (pjsua.start_rtp_port < 1 || pjsua.start_rtp_port > 65535) { 
     516            cfg->start_rtp_port = my_atoi(pj_optarg); 
     517            if (cfg->start_rtp_port < 1 || cfg->start_rtp_port > 65535) { 
    535518                PJ_LOG(1,(THIS_FILE, 
    536519                          "Error: rtp-port argument value " 
     
    541524 
    542525        case OPT_ADD_CODEC: 
    543             pjsua.codec_arg[pjsua.codec_cnt++] = pj_str(pj_optarg); 
     526            cfg->codec_arg[cfg->codec_cnt++] = pj_str(pj_optarg); 
    544527            break; 
    545528 
    546529        case OPT_COMPLEXITY: 
    547             pjsua.complexity = my_atoi(pj_optarg); 
    548             if (pjsua.complexity < 0 || pjsua.complexity > 10) { 
     530            cfg->complexity = my_atoi(pj_optarg); 
     531            if (cfg->complexity < 0 || cfg->complexity > 10) { 
    549532                PJ_LOG(1,(THIS_FILE, 
    550533                          "Error: invalid --complexity (expecting 0-10")); 
     
    554537 
    555538        case OPT_QUALITY: 
    556             pjsua.quality = my_atoi(pj_optarg); 
    557             if (pjsua.quality < 0 || pjsua.quality > 10) { 
     539            cfg->quality = my_atoi(pj_optarg); 
     540            if (cfg->quality < 0 || cfg->quality > 10) { 
    558541                PJ_LOG(1,(THIS_FILE, 
    559542                          "Error: invalid --quality (expecting 0-10")); 
     
    563546 
    564547        case OPT_PTIME: 
    565             pjsua.ptime = my_atoi(pj_optarg); 
    566             if (pjsua.ptime < 10 || pjsua.ptime > 1000) { 
     548            cfg->ptime = my_atoi(pj_optarg); 
     549            if (cfg->ptime < 10 || cfg->ptime > 1000) { 
    567550                PJ_LOG(1,(THIS_FILE, 
    568551                          "Error: invalid --ptime option")); 
     
    572555 
    573556        case OPT_AUTO_ANSWER: 
    574             pjsua.auto_answer = my_atoi(pj_optarg); 
    575             if (pjsua.auto_answer < 100 || pjsua.auto_answer > 699) { 
     557            cfg->auto_answer = my_atoi(pj_optarg); 
     558            if (cfg->auto_answer < 100 || cfg->auto_answer > 699) { 
    576559                PJ_LOG(1,(THIS_FILE, 
    577560                          "Error: invalid code in --auto-answer " 
     
    582565 
    583566        case OPT_MAX_CALLS: 
    584             pjsua.max_calls = my_atoi(pj_optarg); 
    585             if (pjsua.max_calls < 1 || pjsua.max_calls > 255) { 
     567            cfg->max_calls = my_atoi(pj_optarg); 
     568            if (cfg->max_calls < 1 || cfg->max_calls > 255) { 
    586569                PJ_LOG(1,(THIS_FILE,"Too many calls for max-calls (1-255)")); 
    587570                return -1; 
     
    590573 
    591574        case OPT_UAS_REFRESH: 
    592             pjsua.uas_refresh = my_atoi(pj_optarg); 
    593             if (pjsua.uas_refresh < 1) { 
     575            cfg->uas_refresh = my_atoi(pj_optarg); 
     576            if (cfg->uas_refresh < 1) { 
    594577                PJ_LOG(1,(THIS_FILE, 
    595578                          "Invalid value for --uas-refresh (must be >0)")); 
     
    599582 
    600583        case OPT_UAS_DURATION: 
    601             pjsua.uas_duration = my_atoi(pj_optarg); 
    602             if (pjsua.uas_duration < 1) { 
     584            cfg->uas_duration = my_atoi(pj_optarg); 
     585            if (cfg->uas_duration < 1) { 
    603586                PJ_LOG(1,(THIS_FILE, 
    604587                          "Invalid value for --uas-duration " 
     
    611594 
    612595    if (pj_optind != argc) { 
    613         int i; 
    614596 
    615597        if (pjsua_verify_sip_url(argv[pj_optind]) != PJ_SUCCESS) { 
     
    617599            return -1; 
    618600        } 
    619         pjsua.uri_to_call = pj_str(argv[pj_optind]); 
     601        cfg->uri_to_call = pj_str(argv[pj_optind]); 
    620602        pj_optind++; 
    621603 
    622604        /* Add URI to call to buddy list if it's not already there */ 
    623         for (i=0; i<pjsua.buddy_cnt; ++i) { 
    624             if (pj_stricmp(&pjsua.buddies[i].uri, &pjsua.uri_to_call)==0) 
     605        for (i=0; i<cfg->buddy_cnt; ++i) { 
     606            if (pj_stricmp(&cfg->buddy_uri[i], &cfg->uri_to_call)==0) 
    625607                break; 
    626608        } 
    627         if (i == pjsua.buddy_cnt && pjsua.buddy_cnt < PJSUA_MAX_BUDDIES) { 
    628             pjsua.buddies[pjsua.buddy_cnt++].uri = pjsua.uri_to_call; 
     609        if (i == cfg->buddy_cnt && cfg->buddy_cnt < PJSUA_MAX_BUDDIES) { 
     610            cfg->buddy_uri[cfg->buddy_cnt++] = cfg->uri_to_call; 
    629611        } 
    630612    } 
     
    633615        PJ_LOG(1,(THIS_FILE, "Error: unknown options %s", argv[pj_optind])); 
    634616        return PJ_EINVAL; 
     617    } 
     618 
     619    if (cfg->acc_config[0].id.slen && cfg->acc_cnt==0) 
     620        cfg->acc_cnt = 1; 
     621 
     622    for (i=0; i<cfg->acc_cnt; ++i) { 
     623        if (cfg->acc_config[i].cred_info[0].username.slen || 
     624            cfg->acc_config[i].cred_info[0].realm.slen) 
     625        { 
     626            cfg->acc_config[i].cred_count = 1; 
     627            cfg->acc_config[i].cred_info[0].scheme = pj_str("digest"); 
     628        } 
     629    } 
     630 
     631    if (pjsua_test_config(cfg, errmsg, sizeof(errmsg)) != PJ_SUCCESS) { 
     632        PJ_LOG(1,(THIS_FILE, "Error: %s", errmsg)); 
     633        return -1; 
    635634    } 
    636635 
     
    832831 * Dump application states. 
    833832 */ 
    834 void pjsua_dump(pj_bool_t detail) 
     833PJ_DEF(void) pjsua_dump(pj_bool_t detail) 
    835834{ 
    836835    char buf[128]; 
     
    859858 
    860859    } else { 
    861         int i; 
    862  
    863         for (i=0; i<pjsua.max_calls; ++i) { 
     860        unsigned i; 
     861 
     862        for (i=0; i<pjsua.config.max_calls; ++i) { 
    864863 
    865864            pjsua_call *call = &pjsua.calls[i]; 
     
    918917 * Load settings. 
    919918 */ 
    920 pj_status_t pjsua_load_settings(const char *filename) 
     919PJ_DECL(pj_status_t) pjsua_load_settings(const char *filename, 
     920                                         pjsua_config *cfg) 
    921921{ 
    922922    int argc = 3; 
     
    924924 
    925925    argv[3] = (char*)filename; 
    926     return pjsua_parse_args(argc, argv); 
     926    return pjsua_parse_args(argc, argv, cfg); 
    927927} 
    928928 
     
    934934{ 
    935935    char line[128]; 
    936     pjsua_acc *acc = &pjsua.acc[acc_index]; 
     936    pjsua_acc_config *acc_cfg = &pjsua.config.acc_config[acc_index]; 
    937937 
    938938     
     
    942942 
    943943    /* Identity */ 
    944     if (acc->local_uri.slen) { 
     944    if (acc_cfg->id.slen) { 
    945945        pj_ansi_sprintf(line, "--id %.*s\n",  
    946                         (int)acc->local_uri.slen,  
    947                         acc->local_uri.ptr); 
     946                        (int)acc_cfg->id.slen,  
     947                        acc_cfg->id.ptr); 
    948948        pj_strcat2(result, line); 
    949949    } 
    950950 
    951951    /* Registrar server */ 
    952     if (acc->reg_uri.slen) { 
     952    if (acc_cfg->reg_uri.slen) { 
    953953        pj_ansi_sprintf(line, "--registrar %.*s\n", 
    954                               (int)acc->reg_uri.slen, 
    955                               acc->reg_uri.ptr); 
     954                              (int)acc_cfg->reg_uri.slen, 
     955                              acc_cfg->reg_uri.ptr); 
    956956        pj_strcat2(result, line); 
    957957 
    958958        pj_ansi_sprintf(line, "--reg-timeout %u\n", 
    959                               acc->reg_timeout); 
     959                              acc_cfg->reg_timeout); 
    960960        pj_strcat2(result, line); 
    961961    } 
     
    963963 
    964964    /* Proxy */ 
    965     if (acc->proxy.slen) { 
     965    if (acc_cfg->proxy.slen) { 
    966966        pj_ansi_sprintf(line, "--proxy %.*s\n", 
    967                               (int)acc->proxy.slen, 
    968                               acc->proxy.ptr); 
     967                              (int)acc_cfg->proxy.slen, 
     968                              acc_cfg->proxy.ptr); 
    969969        pj_strcat2(result, line); 
    970970    } 
     971 
     972    if (acc_cfg->cred_info[0].realm.slen) { 
     973        pj_ansi_sprintf(line, "--realm %.*s\n", 
     974                              (int)acc_cfg->cred_info[0].realm.slen, 
     975                              acc_cfg->cred_info[0].realm.ptr); 
     976        pj_strcat2(result, line); 
     977    } 
     978 
     979    if (acc_cfg->cred_info[0].username.slen) { 
     980        pj_ansi_sprintf(line, "--username %.*s\n", 
     981                              (int)acc_cfg->cred_info[0].username.slen, 
     982                              acc_cfg->cred_info[0].username.ptr); 
     983        pj_strcat2(result, line); 
     984    } 
     985 
     986    if (acc_cfg->cred_info[0].data.slen) { 
     987        pj_ansi_sprintf(line, "--password %.*s\n", 
     988                              (int)acc_cfg->cred_info[0].data.slen, 
     989                              acc_cfg->cred_info[0].data.ptr); 
     990        pj_strcat2(result, line); 
     991    } 
     992 
    971993} 
    972994 
     
    976998 * Dump settings. 
    977999 */ 
    978 int pjsua_dump_settings(char *buf, pj_size_t max) 
    979 { 
    980     int acc_index; 
    981     int i; 
     1000PJ_DEF(int) pjsua_dump_settings(const pjsua_config *config, 
     1001                                char *buf, pj_size_t max) 
     1002{ 
     1003    unsigned acc_index; 
     1004    unsigned i; 
    9821005    pj_str_t cfg; 
    9831006    char line[128]; 
     
    9921015    pj_strcat2(&cfg, "#\n# Logging options:\n#\n"); 
    9931016    pj_ansi_sprintf(line, "--log-level %d\n", 
    994                     pjsua.log_level); 
     1017                    config->log_level); 
    9951018    pj_strcat2(&cfg, line); 
    9961019 
    9971020    pj_ansi_sprintf(line, "--app-log-level %d\n", 
    998                     pjsua.app_log_level); 
     1021                    config->app_log_level); 
    9991022    pj_strcat2(&cfg, line); 
    10001023 
    1001     if (pjsua.log_filename) { 
     1024    if (config->log_filename.slen) { 
    10021025        pj_ansi_sprintf(line, "--log-file %s\n", 
    1003                         pjsua.log_filename); 
     1026                        config->log_filename.ptr); 
    10041027        pj_strcat2(&cfg, line); 
    10051028    } 
     
    10071030 
    10081031    /* Save account settings. */ 
    1009     if (pjsua.has_acc) { 
    1010         for (acc_index=0; acc_index < pjsua.acc_cnt; ++acc_index) { 
    1011              
    1012             save_account_settings(acc_index, &cfg); 
    1013  
    1014             if (acc_index < pjsua.acc_cnt-1) 
    1015                 pj_strcat2(&cfg, "--next-account\n"); 
    1016         } 
    1017     } 
    1018  
    1019     /* Credentials. */ 
    1020     for (i=0; i<pjsua.cred_count; ++i) { 
    1021  
    1022         pj_ansi_sprintf(line, "#\n# Credential %d:\n#\n", i); 
     1032    for (acc_index=0; acc_index < config->acc_cnt; ++acc_index) { 
     1033         
     1034        save_account_settings(acc_index, &cfg); 
     1035 
     1036        if (acc_index < config->acc_cnt-1) 
     1037            pj_strcat2(&cfg, "--next-account\n"); 
     1038    } 
     1039 
     1040 
     1041    pj_strcat2(&cfg, "#\n# Network settings:\n#\n"); 
     1042 
     1043    /* Outbound proxy */ 
     1044    if (config->outbound_proxy.slen) { 
     1045        pj_ansi_sprintf(line, "--outbound %.*s\n", 
     1046                              (int)config->outbound_proxy.slen, 
     1047                              config->outbound_proxy.ptr); 
    10231048        pj_strcat2(&cfg, line); 
    1024  
    1025         if (pjsua.cred_info[i].realm.slen) { 
    1026             pj_ansi_sprintf(line, "--realm %.*s\n", 
    1027                                   (int)pjsua.cred_info[i].realm.slen, 
    1028                                   pjsua.cred_info[i].realm.ptr); 
    1029             pj_strcat2(&cfg, line); 
    1030         } 
    1031  
    1032         pj_ansi_sprintf(line, "--username %.*s\n", 
    1033                               (int)pjsua.cred_info[i].username.slen, 
    1034                               pjsua.cred_info[i].username.ptr); 
     1049    } 
     1050 
     1051 
     1052    /* Transport. */ 
     1053    pj_ansi_sprintf(line, "--local-port %d\n", config->udp_port); 
     1054    pj_strcat2(&cfg, line); 
     1055 
     1056 
     1057    /* STUN */ 
     1058    if (config->stun_port1) { 
     1059        pj_ansi_sprintf(line, "--use-stun1 %.*s:%d\n", 
     1060                        (int)config->stun_srv1.slen,  
     1061                        config->stun_srv1.ptr,  
     1062                        config->stun_port1); 
    10351063        pj_strcat2(&cfg, line); 
    1036  
    1037         pj_ansi_sprintf(line, "--password %.*s\n", 
    1038                               (int)pjsua.cred_info[i].data.slen, 
    1039                               pjsua.cred_info[i].data.ptr); 
     1064    } 
     1065 
     1066    if (config->stun_port2) { 
     1067        pj_ansi_sprintf(line, "--use-stun2 %.*s:%d\n", 
     1068                        (int)config->stun_srv2.slen,  
     1069                        config->stun_srv2.ptr,  
     1070                        config->stun_port2); 
    10401071        pj_strcat2(&cfg, line); 
    1041  
    1042         if (i < pjsua.cred_count-1) 
    1043             pj_strcat2(&cfg, "--next-cred\n"); 
    1044     } 
    1045  
    1046  
    1047     pj_strcat2(&cfg, "#\n# Network settings:\n#\n"); 
    1048  
    1049     /* Outbound proxy */ 
    1050     if (pjsua.outbound_proxy.slen) { 
    1051         pj_ansi_sprintf(line, "--outbound %.*s\n", 
    1052                               (int)pjsua.outbound_proxy.slen, 
    1053                               pjsua.outbound_proxy.ptr); 
     1072    } 
     1073 
     1074 
     1075    pj_strcat2(&cfg, "#\n# Media settings:\n#\n"); 
     1076 
     1077 
     1078    /* Media */ 
     1079    if (config->null_audio) 
     1080        pj_strcat2(&cfg, "--null-audio\n"); 
     1081    if (config->auto_play) 
     1082        pj_strcat2(&cfg, "--auto-play\n"); 
     1083    if (config->auto_loop) 
     1084        pj_strcat2(&cfg, "--auto-loop\n"); 
     1085    if (config->auto_conf) 
     1086        pj_strcat2(&cfg, "--auto-conf\n"); 
     1087    if (config->wav_file.slen) { 
     1088        pj_ansi_sprintf(line, "--play-file %s\n", 
     1089                        config->wav_file.ptr); 
    10541090        pj_strcat2(&cfg, line); 
    10551091    } 
    1056  
    1057  
    1058     /* Transport. */ 
    1059     pj_ansi_sprintf(line, "--local-port %d\n", pjsua.sip_port); 
    1060     pj_strcat2(&cfg, line); 
    1061  
    1062  
    1063     /* STUN */ 
    1064     if (pjsua.stun_port1) { 
    1065         pj_ansi_sprintf(line, "--use-stun1 %.*s:%d\n", 
    1066                         (int)pjsua.stun_srv1.slen,  
    1067                         pjsua.stun_srv1.ptr,  
    1068                         pjsua.stun_port1); 
    1069         pj_strcat2(&cfg, line); 
    1070     } 
    1071  
    1072     if (pjsua.stun_port2) { 
    1073         pj_ansi_sprintf(line, "--use-stun2 %.*s:%d\n", 
    1074                         (int)pjsua.stun_srv2.slen,  
    1075                         pjsua.stun_srv2.ptr,  
    1076                         pjsua.stun_port2); 
    1077         pj_strcat2(&cfg, line); 
    1078     } 
    1079  
    1080  
    1081     pj_strcat2(&cfg, "#\n# Media settings:\n#\n"); 
    1082  
    1083  
    1084     /* Media */ 
    1085     if (pjsua.null_audio) 
    1086         pj_strcat2(&cfg, "--null-audio\n"); 
    1087     if (pjsua.auto_play) 
    1088         pj_strcat2(&cfg, "--auto-play\n"); 
    1089     if (pjsua.auto_loop) 
    1090         pj_strcat2(&cfg, "--auto-loop\n"); 
    1091     if (pjsua.auto_conf) 
    1092         pj_strcat2(&cfg, "--auto-conf\n"); 
    1093     if (pjsua.wav_file) { 
    1094         pj_ansi_sprintf(line, "--play-file %s\n", 
    1095                         pjsua.wav_file); 
    1096         pj_strcat2(&cfg, line); 
    1097     } 
    10981092    /* Media clock rate. */ 
    1099     if (pjsua.clock_rate) { 
     1093    if (config->clock_rate) { 
    11001094        pj_ansi_sprintf(line, "--clock-rate %d\n", 
    1101                         pjsua.clock_rate); 
     1095                        config->clock_rate); 
    11021096        pj_strcat2(&cfg, line); 
    11031097    } 
     
    11061100    /* Encoding quality and complexity */ 
    11071101    pj_ansi_sprintf(line, "--quality %d\n", 
    1108                     pjsua.quality); 
     1102                    config->quality); 
    11091103    pj_strcat2(&cfg, line); 
    11101104    pj_ansi_sprintf(line, "--complexity %d\n", 
    1111                     pjsua.complexity); 
     1105                    config->complexity); 
    11121106    pj_strcat2(&cfg, line); 
    11131107 
    11141108    /* ptime */ 
    1115     if (pjsua.ptime) { 
     1109    if (config->ptime) { 
    11161110        pj_ansi_sprintf(line, "--ptime %d\n", 
    1117                         pjsua.ptime); 
     1111                        config->ptime); 
    11181112        pj_strcat2(&cfg, line); 
    11191113    } 
     
    11211115    /* Start RTP port. */ 
    11221116    pj_ansi_sprintf(line, "--rtp-port %d\n", 
    1123                     pjsua.start_rtp_port); 
     1117                    config->start_rtp_port); 
    11241118    pj_strcat2(&cfg, line); 
    11251119 
    11261120    /* Add codec. */ 
    1127     for (i=0; i<pjsua.codec_cnt; ++i) { 
     1121    for (i=0; i<config->codec_cnt; ++i) { 
    11281122        pj_ansi_sprintf(line, "--add-codec %s\n", 
    1129                     pjsua.codec_arg[i].ptr); 
     1123                    config->codec_arg[i].ptr); 
    11301124        pj_strcat2(&cfg, line); 
    11311125    } 
     
    11341128 
    11351129    /* Auto-answer. */ 
    1136     if (pjsua.auto_answer != 0) { 
     1130    if (config->auto_answer != 0) { 
    11371131        pj_ansi_sprintf(line, "--auto-answer %d\n", 
    1138                         pjsua.auto_answer); 
     1132                        config->auto_answer); 
    11391133        pj_strcat2(&cfg, line); 
    11401134    } 
     
    11421136    /* Max calls. */ 
    11431137    pj_ansi_sprintf(line, "--max-calls %d\n", 
    1144                     pjsua.max_calls); 
     1138                    config->max_calls); 
    11451139    pj_strcat2(&cfg, line); 
    11461140 
    11471141    /* Uas-refresh. */ 
    1148     if (pjsua.uas_refresh > 0) { 
     1142    if (config->uas_refresh > 0) { 
    11491143        pj_ansi_sprintf(line, "--uas-refresh %d\n", 
    1150                         pjsua.uas_refresh); 
     1144                        config->uas_refresh); 
    11511145        pj_strcat2(&cfg, line); 
    11521146    } 
    11531147 
    11541148    /* Uas-duration. */ 
    1155     if (pjsua.uas_duration > 0) { 
     1149    if (config->uas_duration > 0) { 
    11561150        pj_ansi_sprintf(line, "--uas-duration %d\n", 
    1157                         pjsua.uas_duration); 
     1151                        config->uas_duration); 
    11581152        pj_strcat2(&cfg, line); 
    11591153    } 
     
    11621156 
    11631157    /* Add buddies. */ 
    1164     for (i=0; i<pjsua.buddy_cnt; ++i) { 
     1158    for (i=0; i<config->buddy_cnt; ++i) { 
    11651159        pj_ansi_sprintf(line, "--add-buddy %.*s\n", 
    1166                               (int)pjsua.buddies[i].uri.slen, 
    1167                               pjsua.buddies[i].uri.ptr); 
     1160                              (int)config->buddy_uri[i].slen, 
     1161                              config->buddy_uri[i].ptr); 
    11681162        pj_strcat2(&cfg, line); 
    11691163    } 
     
    11771171 * Save settings. 
    11781172 */ 
    1179 pj_status_t pjsua_save_settings(const char *filename) 
     1173PJ_DEF(pj_status_t) pjsua_save_settings(const char *filename, 
     1174                                        const pjsua_config *config) 
    11801175{ 
    11811176    pj_str_t cfg; 
     
    11961191 
    11971192 
    1198     cfg.slen = pjsua_dump_settings(cfg.ptr, 3800); 
     1193    cfg.slen = pjsua_dump_settings(config, cfg.ptr, 3800); 
    11991194    if (cfg.slen < 1) { 
    12001195        pj_pool_release(pool); 
Note: See TracChangeset for help on using the changeset viewer.