Changeset 236 for pjproject/trunk


Ignore:
Timestamp:
Feb 26, 2006 9:23:45 PM (19 years ago)
Author:
bennylp
Message:

Major redesign in pjsua: call is indexed by number, multiple accounts, configurable max-calls, more auto-xxx features, fixed bugs in save_settings(), etc.

Location:
pjproject/trunk/pjsip
Files:
7 edited
1 moved

Legend:

Unmodified
Added
Removed
  • pjproject/trunk/pjsip/build/pjsua.dsp

    r197 r236  
    9999# Begin Source File 
    100100 
    101 SOURCE=..\src\pjsua\pjsua_core.c 
     101SOURCE=..\src\pjsua\pjsua_call.c 
    102102# End Source File 
    103103# Begin Source File 
    104104 
    105 SOURCE=..\src\pjsua\pjsua_inv.c 
     105SOURCE=..\src\pjsua\pjsua_core.c 
    106106# End Source File 
    107107# Begin Source File 
  • pjproject/trunk/pjsip/src/pjsua/main.c

    r230 r236  
    2424 
    2525/* Current dialog */ 
    26 static struct pjsua_inv_data *inv_session; 
     26static int current_acc; 
     27static int current_call = -1; 
     28 
     29 
     30/* 
     31 * Find next call. 
     32 */ 
     33static 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 */ 
     59static 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 
    2782 
    2883/* 
    2984 * Notify UI when invite state has changed. 
    3085 */ 
    31 void pjsua_ui_inv_on_state_changed(pjsip_inv_session *inv, pjsip_event *e) 
    32 { 
     86void pjsua_ui_inv_on_state_changed(int call_index, pjsip_event *e) 
     87{ 
     88    pjsua_call *call = &pjsua.calls[call_index]; 
     89 
    3390    PJ_UNUSED_ARG(e); 
    3491 
    35     PJ_LOG(3,(THIS_FILE, "INVITE session state changed to %s",  
    36               pjsua_inv_state_names[inv->state])); 
    37  
    38     if (inv->state == PJSIP_INV_STATE_DISCONNECTED) { 
    39         if (inv == inv_session->inv) { 
    40             inv_session = inv_session->next; 
    41             if (inv_session == &pjsua.inv_list) 
    42                 inv_session = pjsua.inv_list.next; 
     92    PJ_LOG(3,(THIS_FILE, "Call %d state changed to %s",  
     93              call_index, 
     94              pjsua_inv_state_names[call->inv->state])); 
     95 
     96    if (call->inv->state == PJSIP_INV_STATE_DISCONNECTED) { 
     97        call->inv = NULL; 
     98        if ((int)call->index == current_call) { 
     99            find_next_call(); 
    43100        } 
    44101 
    45102    } else { 
    46103 
    47         if (inv_session == &pjsua.inv_list || inv_session == NULL) 
    48             inv_session = inv->mod_data[pjsua.mod.id]; 
     104        if (call && current_call==-1) 
     105            current_call = call->index; 
    49106 
    50107    } 
     
    67124static void print_buddy_list(void) 
    68125{ 
    69     unsigned i; 
     126    int i; 
    70127 
    71128    puts("Buddy list:"); 
    72     //puts("-------------------------------------------------------------------------------"); 
     129 
    73130    if (pjsua.buddy_cnt == 0) 
    74131        puts(" -none-"); 
     
    94151} 
    95152 
     153 
    96154/* 
    97  * Show a bit of help. 
    98  */ 
    99 static void keystroke_help(void) 
     155 * Print account status. 
     156 */ 
     157static void print_acc_status(int acc_index) 
    100158{ 
    101159    char reg_status[128]; 
    102160 
    103     if (pjsua.regc == NULL) { 
     161    if (pjsua.acc[acc_index].regc == NULL) { 
    104162        pj_ansi_strcpy(reg_status, " -not registered to server-"); 
    105     } else if (pjsua.regc_last_err != PJ_SUCCESS) { 
    106         pj_strerror(pjsua.regc_last_err, reg_status, sizeof(reg_status)); 
    107     } else if (pjsua.regc_last_code>=200 && pjsua.regc_last_code<=699) { 
     163 
     164    } else if (pjsua.acc[acc_index].reg_last_err != PJ_SUCCESS) { 
     165        pj_strerror(pjsua.acc[acc_index].reg_last_err, reg_status, sizeof(reg_status)); 
     166 
     167    } else if (pjsua.acc[acc_index].reg_last_code>=200 &&  
     168               pjsua.acc[acc_index].reg_last_code<=699) { 
    108169 
    109170        pjsip_regc_info info; 
    110171 
    111         pjsip_regc_get_info(pjsua.regc, &info); 
     172        pjsip_regc_get_info(pjsua.acc[acc_index].regc, &info); 
    112173 
    113174        pj_snprintf(reg_status, sizeof(reg_status), 
    114175                    "%s (%.*s;expires=%d)", 
    115                     pjsip_get_status_text(pjsua.regc_last_code)->ptr, 
     176                    pjsip_get_status_text(pjsua.acc[acc_index].reg_last_code)->ptr, 
    116177                    (int)info.client_uri.slen, 
    117178                    info.client_uri.ptr, 
     
    119180 
    120181    } else { 
    121         pj_sprintf(reg_status, "in progress (%d)", pjsua.regc_last_code); 
    122     } 
    123  
    124     printf(">>>>\nRegistration status: %s\n", reg_status); 
    125     printf("Online status: %s\n",  
    126            (pjsua.online_status ? "Online" : "Invisible")); 
     182        pj_sprintf(reg_status, "in progress (%d)",  
     183                   pjsua.acc[acc_index].reg_last_code); 
     184    } 
     185 
     186    printf("[%2d] Registration status: %s\n", acc_index, reg_status); 
     187    printf("     Online status: %s\n",  
     188           (pjsua.acc[acc_index].online_status ? "Online" : "Invisible")); 
     189} 
     190 
     191/* 
     192 * Show a bit of help. 
     193 */ 
     194static void keystroke_help(void) 
     195{ 
     196    int i; 
     197 
     198    printf(">>>>\n"); 
     199 
     200    for (i=0; i<pjsua.acc_cnt; ++i) 
     201        print_acc_status(i); 
     202 
    127203    print_buddy_list(); 
    128204     
     
    135211    puts("|  h  Hangup call              |  u  Unsubscribe presence | ru  Unregister    |"); 
    136212    puts("|  ]  Select next dialog       |  t  ToGgle Online status |  d  Dump status   |"); 
    137     puts("|  [  Select previous dialog   |                          |                   |"); 
     213    puts("|  [  Select previous dialog   |                          | dc  Dump config   |"); 
    138214    puts("|                              +--------------------------+-------------------+"); 
    139215    puts("|  H  Hold call                |     Conference Command   |                   |"); 
     
    263339{ 
    264340    unsigned i, count; 
    265     pjmedia_conf_port_info info[16]; 
     341    pjmedia_conf_port_info info[PJSUA_MAX_CALLS]; 
    266342 
    267343    printf("Conference ports:\n"); 
     
    270346    pjmedia_conf_get_ports_info(pjsua.mconf, &count, info); 
    271347    for (i=0; i<count; ++i) { 
    272         char txlist[80]; 
    273         unsigned j; 
     348        char txlist[PJSUA_MAX_CALLS*4+10]; 
     349        int j; 
    274350        pjmedia_conf_port_info *port_info = &info[i];    
    275351         
    276352        txlist[0] = '\0'; 
    277         for (j=0; j<pjsua.max_ports; ++j) { 
     353        for (j=0; j<pjsua.max_calls+PJSUA_CONF_MORE_PORTS; ++j) { 
    278354            char s[10]; 
    279355            if (port_info->listener[j]) { 
     
    310386        case 'm': 
    311387            /* Make call! : */ 
    312             if (pj_list_size(&pjsua.inv_list)) 
    313                 printf("(You have %d calls)\n", pj_list_size(&pjsua.inv_list)); 
     388            printf("(You currently have %d calls)\n", pjsua.call_cnt); 
    314389             
    315390            ui_input_url("Make call", buf, sizeof(buf), &result); 
     
    318393                    puts("You can't do that with make call!"); 
    319394                else 
    320                     pjsua_invite(pjsua.buddies[result.nb_result].uri.ptr, NULL); 
     395                    pjsua_make_call( current_acc,  
     396                                     pjsua.buddies[result.nb_result].uri.ptr,  
     397                                     NULL); 
    321398            } else if (result.uri_result) 
    322                 pjsua_invite(result.uri_result, NULL); 
     399                pjsua_make_call( current_acc, result.uri_result, NULL); 
    323400             
    324401            break; 
     
    327404        case 'a': 
    328405 
    329             if (inv_session == &pjsua.inv_list ||  
    330                 inv_session->inv->role != PJSIP_ROLE_UAS || 
    331                 inv_session->inv->state >= PJSIP_INV_STATE_CONNECTING)  
     406            if (current_call == -1 ||  
     407                pjsua.calls[current_call].inv->role != PJSIP_ROLE_UAS || 
     408                pjsua.calls[current_call].inv->state >= PJSIP_INV_STATE_CONNECTING) 
    332409            { 
    333410                puts("No pending incoming call"); 
     
    350427                 * keyboard input. 
    351428                 */ 
    352                 if (inv_session == &pjsua.inv_list) { 
     429                if (current_call == -1) { 
    353430                    puts("Call has been disconnected"); 
    354431                    fflush(stdout); 
     
    356433                } 
    357434 
    358                 status = pjsip_inv_answer(inv_session->inv, atoi(buf),  
     435                status = pjsip_inv_answer(pjsua.calls[current_call].inv,  
     436                                          atoi(buf),  
    359437                                          NULL, NULL, &tdata); 
    360438                if (status == PJ_SUCCESS) 
    361                     status = pjsip_inv_send_msg(inv_session->inv, tdata, NULL); 
     439                    status = pjsip_inv_send_msg(pjsua.calls[current_call].inv, 
     440                                                tdata, NULL); 
    362441 
    363442                if (status != PJ_SUCCESS) 
     
    371450        case 'h': 
    372451 
    373             if (inv_session == &pjsua.inv_list) { 
     452            if (current_call == -1) { 
    374453                puts("No current call"); 
    375454                fflush(stdout); 
     
    377456 
    378457            } else { 
    379                 pjsua_inv_hangup(inv_session, PJSIP_SC_DECLINE); 
     458                pjsua_call_hangup(current_call, PJSIP_SC_DECLINE); 
    380459            } 
    381460            break; 
     
    387466             */ 
    388467            if (menuin[0] == ']') { 
    389                 inv_session = inv_session->next; 
    390                 if (inv_session == &pjsua.inv_list) 
    391                     inv_session = pjsua.inv_list.next; 
     468                find_next_call(); 
    392469 
    393470            } else { 
    394                 inv_session = inv_session->prev; 
    395                 if (inv_session == &pjsua.inv_list) 
    396                     inv_session = pjsua.inv_list.prev; 
    397             } 
    398  
    399             if (inv_session != &pjsua.inv_list) { 
     471                find_prev_call(); 
     472            } 
     473 
     474            if (current_call != -1) { 
    400475                char url[PJSIP_MAX_URL_SIZE]; 
    401476                int len; 
    402  
    403                 len = pjsip_uri_print(0, inv_session->inv->dlg->remote.info->uri, 
    404                                       url, sizeof(url)-1); 
     477                const pjsip_uri *u; 
     478 
     479                u = pjsua.calls[current_call].inv->dlg->remote.info->uri; 
     480                len = pjsip_uri_print(0, u, url, sizeof(url)-1); 
    405481                if (len < 1) { 
    406482                    pj_ansi_strcpy(url, "<uri is too long>"); 
     
    420496             * Hold call. 
    421497             */ 
    422             if (inv_session != &pjsua.inv_list) { 
     498            if (current_call != -1) { 
    423499                 
    424                 pjsua_inv_set_hold(inv_session); 
     500                pjsua_call_set_hold(current_call); 
    425501 
    426502            } else { 
     
    433509             * Send re-INVITE (to release hold, etc). 
    434510             */ 
    435             if (inv_session != &pjsua.inv_list) { 
     511            if (current_call != -1) { 
    436512                 
    437                 pjsua_inv_reinvite(inv_session); 
     513                pjsua_call_reinvite(current_call); 
    438514 
    439515            } else { 
     
    446522             * Transfer call. 
    447523             */ 
    448             if (inv_session == &pjsua.inv_list) { 
     524            if (current_call == -1) { 
    449525                 
    450526                PJ_LOG(3,(THIS_FILE, "No current call")); 
    451527 
    452528            } else { 
    453                 struct pjsua_inv_data *cur = inv_session; 
     529                int call = current_call; 
    454530 
    455531                ui_input_url("Transfer to URL", buf, sizeof(buf), &result); 
     
    457533                /* Check if call is still there. */ 
    458534 
    459                 if (cur != inv_session) { 
     535                if (call != current_call) { 
    460536                    puts("Call has been disconnected"); 
    461537                    continue; 
     
    466542                        puts("You can't do that with transfer call!"); 
    467543                    else 
    468                         pjsua_inv_xfer_call( inv_session, 
    469                                              pjsua.buddies[result.nb_result].uri.ptr); 
     544                        pjsua_call_xfer( current_call, 
     545                                         pjsua.buddies[result.nb_result].uri.ptr); 
    470546 
    471547                } else if (result.uri_result) { 
    472                     pjsua_inv_xfer_call( inv_session, result.uri_result); 
     548                    pjsua_call_xfer( current_call, result.uri_result); 
    473549                } 
    474550            } 
     
    479555             * Send DTMF strings. 
    480556             */ 
    481             if (inv_session == &pjsua.inv_list) { 
     557            if (current_call == -1) { 
    482558                 
    483559                PJ_LOG(3,(THIS_FILE, "No current call")); 
    484560 
    485             } else if (inv_session->session == NULL) { 
     561            } else if (pjsua.calls[current_call].session == NULL) { 
    486562 
    487563                PJ_LOG(3,(THIS_FILE, "Media is not established yet!")); 
     
    489565            } else { 
    490566                pj_str_t digits; 
    491                 struct pjsua_inv_data *cur = inv_session; 
     567                int call = current_call; 
    492568                pj_status_t status; 
    493569 
     
    498574                } 
    499575 
    500                 if (cur != inv_session) { 
     576                if (call != current_call) { 
    501577                    puts("Call has been disconnected"); 
    502578                    continue; 
     
    504580 
    505581                digits = pj_str(buf); 
    506                 status = pjmedia_session_dial_dtmf(inv_session->session, 0,  
     582                status = pjmedia_session_dial_dtmf(pjsua.calls[current_call].session, 0,  
    507583                                                   &digits); 
    508584                if (status != PJ_SUCCESS) { 
     
    522598            if (result.nb_result != NO_NB) { 
    523599                if (result.nb_result == -1) { 
    524                     unsigned i; 
     600                    int i; 
    525601                    for (i=0; i<pjsua.buddy_cnt; ++i) 
    526602                        pjsua.buddies[i].monitor = (menuin[0]=='s'); 
     
    529605                } 
    530606 
    531                 pjsua_pres_refresh(); 
     607                pjsua_pres_refresh(current_acc); 
    532608 
    533609            } else if (result.uri_result) { 
     
    544620                 * Re-Register. 
    545621                 */ 
    546                 pjsua_regc_update(PJ_TRUE); 
     622                pjsua_regc_update(current_acc, PJ_TRUE); 
    547623                break; 
    548624            case 'u': 
     
    550626                 * Unregister 
    551627                 */ 
    552                 pjsua_regc_update(PJ_FALSE); 
     628                pjsua_regc_update(current_acc, PJ_FALSE); 
    553629                break; 
    554630            } 
     
    556632             
    557633        case 't': 
    558             pjsua.online_status = !pjsua.online_status; 
    559             pjsua_pres_refresh(); 
     634            pjsua.acc[current_acc].online_status =  
     635                !pjsua.acc[current_acc].online_status; 
     636            pjsua_pres_refresh(current_acc); 
    560637            break; 
    561638 
     
    607684 
    608685        case 'd': 
    609             pjsua_dump(); 
     686            if (menuin[1] == 'c') { 
     687                char settings[2000]; 
     688                int len; 
     689 
     690                len = pjsua_dump_settings(settings, sizeof(settings)); 
     691                if (len < 1) 
     692                    PJ_LOG(3,(THIS_FILE, "Error: not enough buffer")); 
     693                else 
     694                    PJ_LOG(3,(THIS_FILE,  
     695                              "Dumping configuration (%d bytes):\n%s\n", 
     696                              len, settings)); 
     697            } else { 
     698                pjsua_dump(); 
     699            } 
    610700            break; 
    611701 
     
    766856 
    767857    /* Init default settings. */ 
    768  
    769858    pjsua_default(); 
    770859 
     
    772861    /* Initialize pjsua (to create pool etc). 
    773862     */ 
    774  
    775863    if (pjsua_init() != PJ_SUCCESS) 
    776864        return 1; 
     
    778866 
    779867    /* Parse command line arguments: */ 
    780  
    781868    if (pjsua_parse_args(argc, argv) != PJ_SUCCESS) 
    782869        return 1; 
     
    784871 
    785872    /* Init logging: */ 
    786  
    787873    app_logging_init(); 
    788874 
     
    791877     * messages. 
    792878     */ 
    793  
    794879    pjsip_endpt_register_module(pjsua.endpt, &console_msg_logger); 
    795880 
    796881 
    797882    /* Start pjsua! */ 
    798  
    799883    if (pjsua_start() != PJ_SUCCESS) { 
    800884 
     
    805889 
    806890    /* Sleep for a while, let any messages get printed to console: */ 
    807  
    808891    pj_thread_sleep(500); 
    809892 
    810893 
    811     /* No current call initially: */ 
    812  
    813     inv_session = &pjsua.inv_list; 
    814  
    815  
    816894    /* Start UI console main loop: */ 
    817  
    818895    ui_console_main(); 
    819896 
    820897 
    821898    /* Destroy pjsua: */ 
    822  
    823899    pjsua_destroy(); 
    824900 
    825901 
    826902    /* Close logging: */ 
    827  
    828903    app_logging_shutdown(); 
    829904 
  • pjproject/trunk/pjsip/src/pjsua/pjsua.h

    r223 r236  
    4848 * Max buddies in buddy list. 
    4949 */ 
    50 #define PJSUA_MAX_BUDDIES   32 
     50#ifndef PJSUA_MAX_BUDDIES 
     51#   define PJSUA_MAX_BUDDIES        32 
     52#endif 
     53 
    5154 
    5255/** 
    5356 * Max simultaneous calls. 
    5457 */ 
    55 #define PJSUA_MAX_CALLS     8 
     58#ifndef PJSUA_MAX_CALLS 
     59#   define PJSUA_MAX_CALLS          256 
     60#endif 
     61 
     62 
     63/** 
     64 * Aditional ports to be allocated in the conference ports for non-call 
     65 * streams. 
     66 */ 
     67#define PJSUA_CONF_MORE_PORTS       2 
     68 
     69 
     70/** 
     71 * Maximum accounts. 
     72 */ 
     73#ifndef PJSUA_MAX_ACC 
     74#   define PJSUA_MAX_ACC            8 
     75#endif 
     76 
     77 
     78/** 
     79 * Maximum credentials. 
     80 */ 
     81#ifndef PJSUA_MAX_CRED 
     82#   define PJSUA_MAX_CRED           PJSUA_MAX_ACC 
     83#endif 
    5684 
    5785 
    5886/**  
    59  * Structure to be attached to all dialog.  
     87 * Structure to be attached to invite dialog.  
    6088 * Given a dialog "dlg", application can retrieve this structure 
    6189 * by accessing dlg->mod_data[pjsua.mod.id]. 
    6290 */ 
    63 struct pjsua_inv_data 
     91struct pjsua_call 
    6492{ 
    65     PJ_DECL_LIST_MEMBER(struct pjsua_inv_data); 
    66  
     93    unsigned             index;     /**< Index in pjsua array.              */ 
    6794    pjsip_inv_session   *inv;       /**< The invite session.                */ 
     95    int                  acc_index; /**< Account index being used.          */ 
    6896    pjmedia_session     *session;   /**< The media session.                 */ 
    6997    unsigned             conf_slot; /**< Slot # in conference bridge.       */ 
    70     unsigned             call_slot; /**< RTP media index in med_sock_use[]  */ 
    7198    pjsip_evsub         *xfer_sub;  /**< Xfer server subscription, if this 
    7299                                         call was triggered by xfer.        */ 
     100    pjmedia_sock_info    skinfo;    /**< Preallocated media sockets.        */ 
     101 
     102    void                *app_data;  /**< Application data.                  */ 
    73103}; 
     104 
     105typedef struct pjsua_call pjsua_call; 
    74106 
    75107 
     
    80112{ 
    81113    pj_str_t             uri;       /**< Buddy URI                      */ 
     114    int                  acc_index; /**< Which account to use.          */ 
    82115    pj_bool_t            monitor;   /**< Should we monitor?             */ 
    83116    pjsip_evsub         *sub;       /**< Buddy presence subscription    */ 
     
    101134 
    102135 
     136/** 
     137 * Account 
     138 */ 
     139struct pjsua_acc 
     140{ 
     141    int              index;         /**< Index in accounts array.       */ 
     142    pj_str_t         local_uri;     /**< Uri in From: header.           */ 
     143    pj_str_t         user_part;     /**< User part of local URI.        */ 
     144    pj_str_t         host_part;     /**< Host part of local URI.        */ 
     145    pj_str_t         contact_uri;   /**< Uri in Contact: header.        */ 
     146 
     147    pj_str_t         reg_uri;       /**< Registrar URI.                 */ 
     148    pjsip_regc      *regc;          /**< Client registration session.   */ 
     149    pj_int32_t       reg_timeout;   /**< Default timeout.               */ 
     150    pj_timer_entry   reg_timer;     /**< Registration timer.            */ 
     151    pj_status_t      reg_last_err;  /**< Last registration error.       */ 
     152    int              reg_last_code; /**< Last status last register.     */ 
     153 
     154    pj_str_t         proxy;         /**< Proxy URL.                     */ 
     155    pjsip_route_hdr  route_set;     /**< Route set.                     */ 
     156 
     157    pj_bool_t        online_status; /**< Our online status.             */ 
     158    pjsua_srv_pres   pres_srv_list; /**< Server subscription list.      */ 
     159 
     160    void            *app_data;      /**< Application data.              */ 
     161}; 
     162 
     163 
     164typedef struct pjsua_acc pjsua_acc; 
     165 
    103166 
    104167/* PJSUA application variables. */ 
     
    106169{ 
    107170    /* Control: */ 
    108  
    109171    pj_caching_pool  cp;            /**< Global pool factory.           */ 
    110172    pjsip_endpoint  *endpt;         /**< Global endpoint.               */ 
     
    114176 
    115177    /* Media:  */ 
    116  
    117178    pjmedia_endpt   *med_endpt;     /**< Media endpoint.                */ 
    118     unsigned         max_ports;     /**< Max ports in conf.             */ 
    119179    pjmedia_conf    *mconf;         /**< Media conference.              */ 
    120180    pj_bool_t        null_audio;    /**< Null audio flag.               */ 
    121181    char            *wav_file;      /**< WAV file name to play.         */ 
    122182    unsigned         wav_slot;      /**< WAV player slot in bridge      */ 
     183    pj_bool_t        auto_play;     /**< Auto play file for calls?      */ 
     184    pj_bool_t        auto_loop;     /**< Auto loop RTP stream?          */ 
     185    pj_bool_t        auto_conf;     /**< Auto put to conference?        */ 
     186 
    123187 
    124188    /* User Agent behaviour: */ 
    125  
    126189    int              auto_answer;   /**< Automatically answer in calls. */ 
    127190 
    128  
    129     /* Since we support simultaneous calls, we need to have multiple 
    130      * RTP sockets. 
    131      */ 
    132     pjmedia_sock_info med_sock_info[PJSUA_MAX_CALLS]; 
    133     pj_bool_t         med_sock_use[PJSUA_MAX_CALLS]; 
    134  
    135     /* User info: */ 
    136  
    137     pj_str_t         local_uri;     /**< Uri in From: header.           */ 
    138     pj_str_t         contact_uri;   /**< Uri in Contact: header.        */ 
    139  
    140     /* Proxy URLs: */ 
    141  
    142     pj_str_t         proxy; 
    143     pj_str_t         outbound_proxy; 
    144     pjsip_route_hdr  route_set; 
    145  
    146  
    147     /* Registration: */ 
    148  
    149     pj_str_t         registrar_uri; 
    150     pjsip_regc      *regc; 
    151     pj_int32_t       reg_timeout; 
    152     pj_timer_entry   regc_timer; 
    153     pj_status_t      regc_last_err; /**< Last registration error.       */ 
    154     int              regc_last_code;/**< Last status last register.     */ 
     191    /* Account: */ 
     192    int              acc_cnt;       /**< Number of client registrations */ 
     193    pjsua_acc        acc[PJSUA_MAX_ACC];    /** Client regs array.      */ 
    155194 
    156195 
    157196    /* Authentication credentials: */ 
    158197 
    159     unsigned         cred_count; 
    160     pjsip_cred_info  cred_info[4]; 
     198    int              cred_count;    /**< Number of credentials.         */ 
     199    pjsip_cred_info  cred_info[10]; /**< Array of credentials.          */ 
    161200 
    162201 
    163202    /* Threading (optional): */ 
    164  
    165203    int              thread_cnt;    /**< Thread count.                  */ 
    166204    pj_thread_t     *threads[8];    /**< Thread instances.              */ 
     
    168206 
    169207    /* Transport (UDP): */ 
    170  
    171208    pj_uint16_t      sip_port;      /**< SIP signaling port.            */ 
    172209    pj_sock_t        sip_sock;      /**< SIP UDP socket.                */ 
    173210    pj_sockaddr_in   sip_sock_name; /**< Public/STUN UDP socket addr.   */ 
    174211 
     212    pj_str_t         outbound_proxy;/**< Outbound proxy.                */ 
    175213 
    176214 
    177215    /* STUN: */ 
    178  
    179216    pj_str_t         stun_srv1; 
    180217    int              stun_port1; 
     
    183220 
    184221 
    185     /* Logging: */ 
    186      
     222    /* Logging: */     
    187223    int              log_level;     /**< Logging verbosity.             */ 
    188224    int              app_log_level; /**< stdout log verbosity.          */ 
     
    191227 
    192228 
    193     /* List of invite sessions: */ 
    194  
    195     struct pjsua_inv_data inv_list; 
     229    /* PJSUA Calls: */ 
     230    int              max_calls;     /**< Max nb of calls.               */ 
     231    int              call_cnt;      /**< Number of calls.               */ 
     232    pjsua_call       calls[PJSUA_MAX_CALLS];    /** Calls array.        */ 
    196233 
    197234 
    198235    /* SIMPLE and buddy status: */ 
    199  
    200     pj_bool_t       online_status;  /**< Out online status.             */ 
    201     pjsua_srv_pres  pres_srv_list;  /**< Server subscription list.      */ 
    202  
    203     unsigned        buddy_cnt; 
    204     pjsua_buddy     buddies[PJSUA_MAX_BUDDIES]; 
     236    int              buddy_cnt; 
     237    pjsua_buddy      buddies[PJSUA_MAX_BUDDIES]; 
    205238}; 
    206239 
     
    256289 
    257290 
    258 /***************************************************************************** 
    259  * PJSUA Invite session API (defined in pjsua_inv.c). 
    260  */ 
     291/** 
     292 * Find account for incoming request. 
     293 */ 
     294int pjsua_find_account_for_incoming(pjsip_rx_data *rdata); 
     295 
     296 
     297/** 
     298 * Find account for outgoing request. 
     299 */ 
     300int pjsua_find_account_for_outgoing(const pj_str_t *url); 
     301 
     302 
     303/***************************************************************************** 
     304 * PJSUA Call API (defined in pjsua_call.c). 
     305 */ 
     306 
     307/** 
     308 * Init pjsua call module. 
     309 */ 
     310pj_status_t pjsua_call_init(void); 
    261311 
    262312/** 
    263313 * Make outgoing call. 
    264314 */ 
    265 pj_status_t pjsua_invite(const char *cstr_dest_uri, 
    266                          struct pjsua_inv_data **p_inv_data); 
     315pj_status_t pjsua_make_call(int acc_index, 
     316                            const char *cstr_dest_uri, 
     317                            int *p_call_index); 
    267318 
    268319 
     
    270321 * Handle incoming invite request. 
    271322 */ 
    272 pj_bool_t pjsua_inv_on_incoming(pjsip_rx_data *rdata); 
    273  
     323pj_bool_t pjsua_call_on_incoming(pjsip_rx_data *rdata); 
     324 
     325 
     326/** 
     327 * Answer call. 
     328 */ 
     329void pjsua_call_answer(int call_index, int code); 
    274330 
    275331/** 
    276332 * Hangup call. 
    277333 */ 
    278 void pjsua_inv_hangup(struct pjsua_inv_data *inv_session, int code); 
     334void pjsua_call_hangup(int call_index, int code); 
    279335 
    280336 
     
    282338 * Put call on-hold. 
    283339 */ 
    284 void pjsua_inv_set_hold(struct pjsua_inv_data *inv_session); 
     340void pjsua_call_set_hold(int call_index); 
    285341 
    286342 
     
    288344 * Send re-INVITE (to release hold). 
    289345 */ 
    290 void pjsua_inv_reinvite(struct pjsua_inv_data *inv_session); 
     346void pjsua_call_reinvite(int call_index); 
    291347 
    292348 
     
    294350 * Transfer call. 
    295351 */ 
    296 void pjsua_inv_xfer_call(struct pjsua_inv_data *inv_session, 
    297                          const char *dest); 
    298  
    299  
    300 /** 
    301  * Callback to be called by session when invite session's state has changed. 
    302  */ 
    303 void pjsua_inv_on_state_changed(pjsip_inv_session *inv, pjsip_event *e); 
    304  
    305  
    306 /** 
    307  * Callback to be called by session when outgoing dialog has forked. 
    308  * This function will create a forked dialog. 
    309  */ 
    310 void pjsua_inv_on_new_session(pjsip_inv_session *inv, pjsip_event *e); 
    311  
    312  
    313 /** 
    314  * Callback to be called when SDP offer/answer negotiation has just completed 
    315  * in the session. This function will start/update media if negotiation 
    316  * has succeeded. 
    317  */ 
    318 void pjsua_inv_on_media_update(pjsip_inv_session *inv, pj_status_t status); 
    319  
    320 /** 
    321  * Callback called when invite session received new offer. 
    322  */ 
    323 void pjsua_inv_on_rx_offer( pjsip_inv_session *inv, 
    324                             const pjmedia_sdp_session *offer); 
    325  
    326 /** 
    327  * Callback to receive transaction state inside invite session or dialog 
    328  * (e.g. REFER, MESSAGE). 
    329  */ 
    330 void pjsua_inv_on_tsx_state_changed(pjsip_inv_session *inv, 
    331                                     pjsip_transaction *tsx, 
    332                                     pjsip_event *e); 
     352void pjsua_call_xfer(int call_index, const char *dest); 
     353 
    333354 
    334355/** 
     
    347368 * @param app_callback  Optional callback 
    348369 */ 
    349 pj_status_t pjsua_regc_init(void); 
     370pj_status_t pjsua_regc_init(int acc_index); 
    350371 
    351372/** 
     
    353374 * this will start unregistration process. 
    354375 */ 
    355 void pjsua_regc_update(pj_bool_t renew); 
     376void pjsua_regc_update(int acc_index, pj_bool_t renew); 
    356377 
    357378 
     
    370391 * Refresh both presence client and server subscriptions. 
    371392 */ 
    372 void pjsua_pres_refresh(void); 
     393void pjsua_pres_refresh(int acc_index); 
    373394 
    374395/** 
     
    393414 * Notify UI when invite state has changed. 
    394415 */ 
    395 void pjsua_ui_inv_on_state_changed(pjsip_inv_session *inv, pjsip_event *e); 
     416void pjsua_ui_inv_on_state_changed(int call_index, pjsip_event *e); 
    396417 
    397418/** 
    398419 * Notify UI when registration status has changed. 
    399420 */ 
    400 void pjsua_ui_regc_on_state_changed(int code); 
     421void pjsua_ui_regc_on_state_changed(int acc_index); 
    401422 
    402423 
     
    418439 */ 
    419440pj_status_t pjsua_load_settings(const char *filename); 
     441 
     442/** 
     443 * Dump settings. 
     444 */ 
     445int pjsua_dump_settings(char *buf, pj_size_t max); 
    420446 
    421447/** 
  • pjproject/trunk/pjsip/src/pjsua/pjsua_call.c

    r226 r236  
    3333 * Make outgoing call. 
    3434 */ 
    35 pj_status_t pjsua_invite(const char *cstr_dest_uri, 
    36                          struct pjsua_inv_data **p_inv_data) 
     35pj_status_t pjsua_make_call(int acc_index, 
     36                            const char *cstr_dest_uri, 
     37                            int *p_call_index) 
    3738{ 
    3839    pj_str_t dest_uri; 
     
    4041    pjmedia_sdp_session *offer; 
    4142    pjsip_inv_session *inv; 
    42     struct pjsua_inv_data *inv_data; 
     43    int call_index = -1; 
    4344    pjsip_tx_data *tdata; 
    44     int med_sk_index = 0; 
    4545    pj_status_t status; 
    4646 
     
    4949    dest_uri = pj_str((char*)cstr_dest_uri); 
    5050 
    51     /* Find free socket. */ 
    52     for (med_sk_index=0; med_sk_index<PJSUA_MAX_CALLS; ++med_sk_index) { 
    53         if (!pjsua.med_sock_use[med_sk_index]) 
     51    /* Find free call slot. */ 
     52    for (call_index=0; call_index<pjsua.max_calls; ++call_index) { 
     53        if (pjsua.calls[call_index].inv == NULL) 
    5454            break; 
    5555    } 
    5656 
    57     if (med_sk_index == PJSUA_MAX_CALLS) { 
     57    if (call_index == pjsua.max_calls) { 
    5858        PJ_LOG(3,(THIS_FILE, "Error: too many calls!")); 
    5959        return PJ_ETOOMANY; 
    6060    } 
    6161 
    62     pjsua.med_sock_use[med_sk_index] = 1; 
    63  
    6462    /* Create outgoing dialog: */ 
    6563 
    66     status = pjsip_dlg_create_uac( pjsip_ua_instance(), &pjsua.local_uri, 
    67                                    &pjsua.contact_uri, &dest_uri, &dest_uri, 
     64    status = pjsip_dlg_create_uac( pjsip_ua_instance(),  
     65                                   &pjsua.acc[acc_index].local_uri, 
     66                                   &pjsua.acc[acc_index].contact_uri,  
     67                                   &dest_uri, &dest_uri, 
    6868                                   &dlg); 
    6969    if (status != PJ_SUCCESS) { 
     
    7474    /* Get media capability from media endpoint: */ 
    7575 
    76     status = pjmedia_endpt_create_sdp( pjsua.med_endpt, dlg->pool, 
    77                                        1, &pjsua.med_sock_info[med_sk_index],  
     76    status = pjmedia_endpt_create_sdp( pjsua.med_endpt, dlg->pool, 1,  
     77                                       &pjsua.calls[call_index].skinfo,  
    7878                                       &offer); 
    7979    if (status != PJ_SUCCESS) { 
     
    9393    /* Create and associate our data in the session. */ 
    9494 
    95     inv_data = pj_pool_zalloc( dlg->pool, sizeof(struct pjsua_inv_data)); 
    96     inv_data->inv = inv; 
    97     inv_data->call_slot = med_sk_index; 
    98     dlg->mod_data[pjsua.mod.id] = inv_data; 
    99     inv->mod_data[pjsua.mod.id] = inv_data; 
     95    pjsua.calls[call_index].inv = inv; 
     96 
     97    dlg->mod_data[pjsua.mod.id] = &pjsua.calls[call_index]; 
     98    inv->mod_data[pjsua.mod.id] = &pjsua.calls[call_index]; 
    10099 
    101100 
    102101    /* Set dialog Route-Set: */ 
    103102 
    104     if (!pj_list_empty(&pjsua.route_set)) 
    105         pjsip_dlg_set_route_set(dlg, &pjsua.route_set); 
     103    if (!pj_list_empty(&pjsua.acc[acc_index].route_set)) 
     104        pjsip_dlg_set_route_set(dlg, &pjsua.acc[acc_index].route_set); 
    106105 
    107106 
     
    122121 
    123122 
    124     /* Add invite session to the list. */ 
    125      
    126     pj_list_push_back(&pjsua.inv_list, inv_data); 
    127  
    128  
    129123    /* Send initial INVITE: */ 
    130124 
    131125    status = pjsip_inv_send_msg(inv, tdata, NULL); 
    132126    if (status != PJ_SUCCESS) { 
    133         /* 
    134          * Note: 
    135          *  inv_data will be removed from the list in the callback 
    136          */ 
    137127        pjsua_perror(THIS_FILE, "Unable to send initial INVITE request",  
    138128                     status); 
     
    142132 
    143133    /* Done. */ 
    144     if (p_inv_data) 
    145         *p_inv_data = inv_data; 
     134 
     135    ++pjsua.call_cnt; 
     136 
     137    if (p_call_index) 
     138        *p_call_index = call_index; 
    146139 
    147140    return PJ_SUCCESS; 
     
    149142 
    150143on_error: 
    151  
    152144    PJ_TODO(DESTROY_DIALOG_ON_FAIL); 
    153     pjsua.med_sock_use[med_sk_index] = 0; 
     145    if (call_index != -1) { 
     146        pjsua.calls[call_index].inv = NULL; 
     147    } 
    154148    return status; 
    155149} 
     
    159153 * Handle incoming INVITE request. 
    160154 */ 
    161 pj_bool_t pjsua_inv_on_incoming(pjsip_rx_data *rdata) 
     155pj_bool_t pjsua_call_on_incoming(pjsip_rx_data *rdata) 
    162156{ 
    163157    pjsip_dialog *dlg = pjsip_rdata_get_dlg(rdata); 
     
    167161    unsigned options = 0; 
    168162    pjsip_inv_session *inv; 
    169     struct pjsua_inv_data *inv_data; 
     163    int acc_index; 
     164    int call_index = -1; 
    170165    pjmedia_sdp_session *answer; 
    171     int med_sk_index; 
    172166    pj_status_t status; 
    173167 
     
    215209 
    216210    /* Find free call slot. */ 
    217     for (med_sk_index=0; med_sk_index<PJSUA_MAX_CALLS; ++med_sk_index) { 
    218         if (!pjsua.med_sock_use[med_sk_index]) 
     211    for (call_index=0; call_index < pjsua.max_calls; ++call_index) { 
     212        if (pjsua.calls[call_index].inv == NULL) 
    219213            break; 
    220214    } 
    221215 
    222     if (med_sk_index == PJSUA_MAX_CALLS) { 
     216    if (call_index == PJSUA_MAX_CALLS) { 
    223217        pjsip_endpt_respond_stateless(pjsua.endpt, rdata,  
    224218                                      PJSIP_SC_BUSY_HERE, NULL, 
     
    228222 
    229223 
    230     pjsua.med_sock_use[med_sk_index] = 1; 
    231  
    232224    /* Get media capability from media endpoint: */ 
    233225 
    234     status = pjmedia_endpt_create_sdp( pjsua.med_endpt, rdata->tp_info.pool, 
    235                                        1, &pjsua.med_sock_info[med_sk_index],  
     226    status = pjmedia_endpt_create_sdp( pjsua.med_endpt, rdata->tp_info.pool, 1, 
     227                                       &pjsua.calls[call_index].skinfo,  
    236228                                       &answer ); 
    237229    if (status != PJ_SUCCESS) { 
     
    239231                                      NULL, NULL); 
    240232 
    241         /* Free call socket. */ 
    242         pjsua.med_sock_use[med_sk_index] = 0; 
    243233        return PJ_TRUE; 
    244234    } 
    245235 
     236    /* TODO:  
     237     * 
     238     * Get which account is most likely to be associated with this incoming 
     239     * call. We need the account to find which contact URI to put for 
     240     * the call. 
     241     */ 
     242    acc_index = 0; 
     243 
    246244    /* Create dialog: */ 
    247245 
    248246    status = pjsip_dlg_create_uas( pjsip_ua_instance(), rdata, 
    249                                    &pjsua.contact_uri, &dlg); 
     247                                   &pjsua.acc[acc_index].contact_uri,  
     248                                   &dlg); 
    250249    if (status != PJ_SUCCESS) { 
    251250        pjsip_endpt_respond_stateless(pjsua.endpt, rdata, 500, NULL, 
    252251                                      NULL, NULL); 
    253252 
    254         /* Free call socket. */ 
    255         pjsua.med_sock_use[med_sk_index] = 0; 
    256253        return PJ_TRUE; 
    257254    } 
     
    264261 
    265262        pjsip_dlg_respond(dlg, rdata, 500, NULL); 
    266  
    267         /* Free call socket. */ 
    268         pjsua.med_sock_use[med_sk_index] = 0; 
    269263 
    270264        // TODO: Need to delete dialog 
     
    275269    /* Create and attach pjsua data to the dialog: */ 
    276270 
    277     inv_data = pj_pool_zalloc(dlg->pool, sizeof(struct pjsua_inv_data)); 
    278     inv_data->inv = inv; 
    279     inv_data->call_slot = inv_data->call_slot = med_sk_index; 
    280     dlg->mod_data[pjsua.mod.id] = inv_data; 
    281     inv->mod_data[pjsua.mod.id] = inv_data; 
    282  
    283     pj_list_push_back(&pjsua.inv_list, inv_data); 
     271    pjsua.calls[call_index].inv = inv; 
     272 
     273    dlg->mod_data[pjsua.mod.id] = &pjsua.calls[call_index]; 
     274    inv->mod_data[pjsua.mod.id] = &pjsua.calls[call_index]; 
    284275 
    285276 
     
    296287 
    297288        pjsip_dlg_respond(dlg, rdata, 500, NULL); 
    298  
    299         /* Free call socket. */ 
    300         pjsua.med_sock_use[med_sk_index] = 0; 
    301289 
    302290        // TODO: Need to delete dialog 
     
    329317    } 
    330318 
     319    ++pjsua.call_cnt; 
     320 
    331321    /* This INVITE request has been handled. */ 
    332322    return PJ_TRUE; 
     
    338328 * session state has changed. 
    339329 */ 
    340 void pjsua_inv_on_state_changed(pjsip_inv_session *inv, pjsip_event *e) 
    341 { 
    342     struct pjsua_inv_data *inv_data; 
    343  
    344     inv_data = inv->dlg->mod_data[pjsua.mod.id]; 
     330static void pjsua_call_on_state_changed(pjsip_inv_session *inv,  
     331                                        pjsip_event *e) 
     332{ 
     333    pjsua_call *call = inv->dlg->mod_data[pjsua.mod.id]; 
    345334 
    346335    /* If this is an outgoing INVITE that was created because of 
    347336     * REFER/transfer, send NOTIFY to transferer. 
    348337     */ 
    349     if (inv_data && inv_data->xfer_sub && e->type==PJSIP_EVENT_TSX_STATE)  
    350     { 
     338    if (call && call->xfer_sub && e->type==PJSIP_EVENT_TSX_STATE)  { 
    351339        int st_code = -1; 
    352340        pjsip_evsub_state ev_state = PJSIP_EVSUB_STATE_ACTIVE; 
    353341         
    354342 
    355         switch (inv->state) { 
     343        switch (call->inv->state) { 
    356344        case PJSIP_INV_STATE_NULL: 
    357345        case PJSIP_INV_STATE_CALLING: 
     
    383371            pj_status_t status; 
    384372 
    385             status = pjsip_xfer_notify( inv_data->xfer_sub, 
     373            status = pjsip_xfer_notify( call->xfer_sub, 
    386374                                        ev_state, st_code, 
    387375                                        NULL, &tdata); 
     
    389377                pjsua_perror(THIS_FILE, "Unable to create NOTIFY", status); 
    390378            } else { 
    391                 status = pjsip_xfer_send_request(inv_data->xfer_sub, tdata); 
     379                status = pjsip_xfer_send_request(call->xfer_sub, tdata); 
    392380                if (status != PJ_SUCCESS) { 
    393381                    pjsua_perror(THIS_FILE, "Unable to send NOTIFY", status); 
     
    398386 
    399387 
     388    pjsua_ui_inv_on_state_changed(call->index, e); 
     389 
     390    /* call->inv may be NULL now */ 
     391 
    400392    /* Destroy media session when invite session is disconnected. */ 
    401393    if (inv->state == PJSIP_INV_STATE_DISCONNECTED) { 
    402394 
    403         pj_assert(inv_data != NULL); 
    404  
    405         if (inv_data && inv_data->session) { 
    406             pjmedia_conf_remove_port(pjsua.mconf, inv_data->conf_slot); 
    407             pjmedia_session_destroy(inv_data->session); 
    408             pjsua.med_sock_use[inv_data->call_slot] = 0; 
    409             inv_data->session = NULL; 
     395        pj_assert(call != NULL); 
     396 
     397        if (call && call->session) { 
     398            pjmedia_conf_remove_port(pjsua.mconf, call->conf_slot); 
     399            pjmedia_session_destroy(call->session); 
     400            call->session = NULL; 
    410401 
    411402            PJ_LOG(3,(THIS_FILE,"Media session is destroyed")); 
    412403        } 
    413404 
    414         if (inv_data) { 
    415  
    416             pj_list_erase(inv_data); 
    417  
    418         } 
    419     } 
    420  
    421     pjsua_ui_inv_on_state_changed(inv, e); 
     405        call->inv = NULL; 
     406        --pjsua.call_cnt; 
     407    } 
    422408} 
    423409 
     
    437423     */ 
    438424    if (pjsip_evsub_get_state(sub) == PJSIP_EVSUB_STATE_TERMINATED) { 
    439         struct pjsua_inv_data *inv_data; 
    440  
    441         inv_data = pjsip_evsub_get_mod_data(sub, pjsua.mod.id); 
    442         if (!inv_data) 
     425        pjsua_call *call; 
     426 
     427        call = pjsip_evsub_get_mod_data(sub, pjsua.mod.id); 
     428        if (!call) 
    443429            return; 
    444430 
    445431        pjsip_evsub_set_mod_data(sub, pjsua.mod.id, NULL); 
    446         inv_data->xfer_sub = NULL; 
     432        call->xfer_sub = NULL; 
    447433 
    448434        PJ_LOG(3,(THIS_FILE, "Xfer subscription terminated")); 
     
    459445    pj_status_t status; 
    460446    pjsip_tx_data *tdata; 
    461     struct pjsua_inv_data *inv_data; 
     447    pjsua_call *existing_call; 
     448    int new_call; 
    462449    const pj_str_t str_refer_to = { "Refer-To", 8}; 
    463450    pjsip_generic_string_hdr *refer_to; 
     
    465452    struct pjsip_evsub_user xfer_cb; 
    466453    pjsip_evsub *sub; 
     454 
     455    existing_call = inv->dlg->mod_data[pjsua.mod.id]; 
    467456 
    468457    /* Find the Refer-To header */ 
     
    524513 
    525514    /* Now make the outgoing call. */ 
    526     status = pjsua_invite(uri, &inv_data); 
     515    status = pjsua_make_call(existing_call->acc_index, uri, &new_call); 
    527516    if (status != PJ_SUCCESS) { 
    528517 
     
    548537     * reported back to the server subscription. 
    549538     */ 
    550     inv_data->xfer_sub = sub; 
     539    pjsua.calls[new_call].xfer_sub = sub; 
    551540 
    552541    /* Put the invite_data in the subscription. */ 
    553     pjsip_evsub_set_mod_data(sub, pjsua.mod.id, inv_data); 
     542    pjsip_evsub_set_mod_data(sub, pjsua.mod.id, &pjsua.calls[new_call]); 
    554543} 
    555544 
     
    559548 * session. We use this to trap incoming REFER request. 
    560549 */ 
    561 void pjsua_inv_on_tsx_state_changed(pjsip_inv_session *inv, 
    562                                     pjsip_transaction *tsx, 
    563                                     pjsip_event *e) 
    564 { 
     550static void pjsua_call_on_tsx_state_changed(pjsip_inv_session *inv, 
     551                                            pjsip_transaction *tsx, 
     552                                            pjsip_event *e) 
     553{ 
     554    pjsua_call *call = inv->dlg->mod_data[pjsua.mod.id]; 
     555 
    565556    if (tsx->role==PJSIP_ROLE_UAS && 
    566557        tsx->state==PJSIP_TSX_STATE_TRYING && 
     
    570561         * Incoming REFER request. 
    571562         */ 
    572         on_call_transfered(inv, e->body.tsx_state.src.rdata); 
     563        on_call_transfered(call->inv, e->body.tsx_state.src.rdata); 
    573564    } 
    574565} 
     
    579570 * has forked. 
    580571 */ 
    581 void pjsua_inv_on_new_session(pjsip_inv_session *inv, pjsip_event *e) 
     572static void pjsua_call_on_forked( pjsip_inv_session *inv,  
     573                                  pjsip_event *e) 
    582574{ 
    583575    PJ_UNUSED_ARG(inv); 
     
    591583 * Create inactive SDP for call hold. 
    592584 */ 
    593 static pj_status_t create_inactive_sdp(struct pjsua_inv_data *inv_session, 
     585static pj_status_t create_inactive_sdp(pjsua_call *call, 
    594586                                       pjmedia_sdp_session **p_answer) 
    595587{ 
     
    601593    /* Create new offer */ 
    602594    status = pjmedia_endpt_create_sdp(pjsua.med_endpt, pjsua.pool, 1, 
    603                                       &pjsua.med_sock_info[inv_session->call_slot], 
    604                                       &sdp); 
     595                                      &call->skinfo, &sdp); 
    605596    if (status != PJ_SUCCESS) { 
    606597        pjsua_perror(THIS_FILE, "Unable to create local SDP", status); 
     
    634625 * Called when session received new offer. 
    635626 */ 
    636 void pjsua_inv_on_rx_offer( pjsip_inv_session *inv, 
    637                             const pjmedia_sdp_session *offer) 
    638 { 
    639     struct pjsua_inv_data *inv_data; 
     627static void pjsua_call_on_rx_offer(pjsip_inv_session *inv, 
     628                                   const pjmedia_sdp_session *offer) 
     629{ 
     630    pjsua_call *call; 
    640631    pjmedia_sdp_conn *conn; 
    641632    pjmedia_sdp_session *answer; 
     
    643634    pj_status_t status; 
    644635 
    645     inv_data = inv->dlg->mod_data[pjsua.mod.id]; 
     636    call = inv->dlg->mod_data[pjsua.mod.id]; 
    646637 
    647638    /* 
     
    670661    /* Supply candidate answer */ 
    671662    if (is_remote_active) { 
    672         status = pjmedia_endpt_create_sdp( pjsua.med_endpt, inv->pool, 1, 
    673                                            &pjsua.med_sock_info[inv_data->call_slot], 
    674                                            &answer); 
     663        status = pjmedia_endpt_create_sdp( pjsua.med_endpt, call->inv->pool, 1, 
     664                                           &call->skinfo, &answer); 
    675665    } else { 
    676         status = create_inactive_sdp( inv_data, &answer ); 
     666        status = create_inactive_sdp( call, &answer ); 
    677667    } 
    678668 
     
    682672    } 
    683673 
    684     status = pjsip_inv_set_sdp_answer(inv, answer); 
     674    status = pjsip_inv_set_sdp_answer(call->inv, answer); 
    685675    if (status != PJ_SUCCESS) { 
    686676        pjsua_perror(THIS_FILE, "Unable to set answer", status); 
     
    696686 * has succeeded. 
    697687 */ 
    698 void pjsua_inv_on_media_update(pjsip_inv_session *inv, pj_status_t status) 
    699 { 
    700     struct pjsua_inv_data *inv_data; 
     688static void pjsua_call_on_media_update(pjsip_inv_session *inv, 
     689                                       pj_status_t status) 
     690{ 
     691    pjsua_call *call; 
    701692    const pjmedia_sdp_session *local_sdp; 
    702693    const pjmedia_sdp_session *remote_sdp; 
     
    705696    char tmp[PJSIP_MAX_URL_SIZE]; 
    706697 
     698    call = inv->dlg->mod_data[pjsua.mod.id]; 
     699 
    707700    if (status != PJ_SUCCESS) { 
    708701 
     
    714707    /* Destroy existing media session, if any. */ 
    715708 
    716     inv_data = inv->dlg->mod_data[pjsua.mod.id]; 
    717     if (inv_data && inv_data->session) { 
    718         pjmedia_conf_remove_port(pjsua.mconf, inv_data->conf_slot); 
    719         pjmedia_session_destroy(inv_data->session); 
    720         pjsua.med_sock_use[inv_data->call_slot] = 0; 
    721         inv_data->session = NULL; 
     709    if (call && call->session) { 
     710        pjmedia_conf_remove_port(pjsua.mconf, call->conf_slot); 
     711        pjmedia_session_destroy(call->session); 
     712        call->session = NULL; 
    722713    } 
    723714 
    724715    /* Get local and remote SDP */ 
    725716 
    726     status = pjmedia_sdp_neg_get_active_local(inv->neg, &local_sdp); 
     717    status = pjmedia_sdp_neg_get_active_local(call->inv->neg, &local_sdp); 
    727718    if (status != PJ_SUCCESS) { 
    728719        pjsua_perror(THIS_FILE,  
     
    733724 
    734725 
    735     status = pjmedia_sdp_neg_get_active_remote(inv->neg, &remote_sdp); 
     726    status = pjmedia_sdp_neg_get_active_remote(call->inv->neg, &remote_sdp); 
    736727    if (status != PJ_SUCCESS) { 
    737728        pjsua_perror(THIS_FILE,  
     
    748739     
    749740    status = pjmedia_session_create( pjsua.med_endpt, 1,  
    750                                      &pjsua.med_sock_info[inv_data->call_slot], 
     741                                     &call->skinfo, 
    751742                                     local_sdp, remote_sdp,  
    752                                      inv_data, 
    753                                      &inv_data->session ); 
     743                                     call, 
     744                                     &call->session ); 
    754745    if (status != PJ_SUCCESS) { 
    755746        pjsua_perror(THIS_FILE, "Unable to create media session",  
     
    762753     * We need the port interface to add to the conference bridge. 
    763754     */ 
    764     pjmedia_session_get_port(inv_data->session, 0, &media_port); 
     755    pjmedia_session_get_port(call->session, 0, &media_port); 
    765756 
    766757 
     
    770761    port_name.ptr = tmp; 
    771762    port_name.slen = pjsip_uri_print(PJSIP_URI_IN_REQ_URI, 
    772                                      inv_data->inv->dlg->remote.info->uri, 
     763                                     call->inv->dlg->remote.info->uri, 
    773764                                     tmp, sizeof(tmp)); 
    774765    if (port_name.slen < 1) { 
    775766        port_name = pj_str("call"); 
    776767    } 
    777     status = pjmedia_conf_add_port( pjsua.mconf, inv->pool, 
     768    status = pjmedia_conf_add_port( pjsua.mconf, call->inv->pool, 
    778769                                    media_port,  
    779770                                    &port_name, 
    780                                     &inv_data->conf_slot); 
     771                                    &call->conf_slot); 
    781772    if (status != PJ_SUCCESS) { 
    782773        pjsua_perror(THIS_FILE, "Unable to create conference slot",  
    783774                     status); 
    784         pjmedia_session_destroy(inv_data->session); 
    785         inv_data->session = NULL; 
     775        pjmedia_session_destroy(call->session); 
     776        call->session = NULL; 
    786777        return; 
    787778    } 
     
    790781     * port  
    791782     */ 
    792     if (pjsua.wav_file && inv->role == PJSIP_ROLE_UAS) { 
     783    if (pjsua.auto_play && pjsua.wav_file &&  
     784        call->inv->role == PJSIP_ROLE_UAS)  
     785    { 
    793786 
    794787        pjmedia_conf_connect_port( pjsua.mconf, pjsua.wav_slot,  
    795                                    inv_data->conf_slot); 
     788                                   call->conf_slot); 
     789 
     790    } else if (pjsua.auto_loop && call->inv->role == PJSIP_ROLE_UAS) { 
     791 
     792        pjmedia_conf_connect_port( pjsua.mconf, call->conf_slot,  
     793                                   call->conf_slot); 
     794 
     795    } else if (pjsua.auto_conf) { 
     796 
     797        int i; 
     798 
     799        pjmedia_conf_connect_port( pjsua.mconf, 0, call->conf_slot); 
     800        pjmedia_conf_connect_port( pjsua.mconf, call->conf_slot, 0); 
     801 
     802        for (i=0; i < pjsua.max_calls; ++i) { 
     803 
     804            if (!pjsua.calls[i].session) 
     805                continue; 
     806 
     807            pjmedia_conf_connect_port( pjsua.mconf, call->conf_slot,  
     808                                       pjsua.calls[i].conf_slot); 
     809            pjmedia_conf_connect_port( pjsua.mconf, pjsua.calls[i].conf_slot, 
     810                                       call->conf_slot); 
     811        } 
    796812 
    797813    } else { 
     
    800816         * main conference bridge. 
    801817         */ 
    802         pjmedia_conf_connect_port( pjsua.mconf, 0, inv_data->conf_slot); 
    803         pjmedia_conf_connect_port( pjsua.mconf, inv_data->conf_slot, 0); 
     818        pjmedia_conf_connect_port( pjsua.mconf, 0, call->conf_slot); 
     819        pjmedia_conf_connect_port( pjsua.mconf, call->conf_slot, 0); 
    804820    } 
    805821 
     
    812828        unsigned i; 
    813829 
    814         pjmedia_session_get_info(inv_data->session, &sess_info); 
     830        pjmedia_session_get_info(call->session, &sess_info); 
    815831        for (i=0; i<sess_info.stream_cnt; ++i) { 
    816832            int len; 
     
    851867 * Hangup call. 
    852868 */ 
    853 void pjsua_inv_hangup(struct pjsua_inv_data *inv_session, int code) 
    854 { 
     869void pjsua_call_hangup(int call_index, int code) 
     870{ 
     871    pjsua_call *call; 
    855872    pj_status_t status; 
    856873    pjsip_tx_data *tdata; 
    857874 
    858     status = pjsip_inv_end_session(inv_session->inv,  
    859                                    code, NULL, &tdata); 
     875 
     876    call = &pjsua.calls[call_index]; 
     877 
     878    if (!call->inv) { 
     879        PJ_LOG(3,(THIS_FILE,"Call has been disconnected")); 
     880        return; 
     881    } 
     882 
     883    status = pjsip_inv_end_session(call->inv, code, NULL, &tdata); 
    860884    if (status != PJ_SUCCESS) { 
    861885        pjsua_perror(THIS_FILE,  
     
    872896        return; 
    873897 
    874     status = pjsip_inv_send_msg(inv_session->inv, tdata, NULL); 
     898    status = pjsip_inv_send_msg(call->inv, tdata, NULL); 
    875899    if (status != PJ_SUCCESS) { 
    876900        pjsua_perror(THIS_FILE,  
     
    885909 * Put call on-Hold. 
    886910 */ 
    887 void pjsua_inv_set_hold(struct pjsua_inv_data *inv_session) 
     911void pjsua_call_set_hold(int call_index) 
    888912{ 
    889913    pjmedia_sdp_session *sdp; 
    890     pjsip_inv_session *inv = inv_session->inv; 
     914    pjsua_call *call; 
    891915    pjsip_tx_data *tdata; 
    892916    pj_status_t status; 
    893917 
    894     if (inv->state != PJSIP_INV_STATE_CONFIRMED) { 
     918    call = &pjsua.calls[call_index]; 
     919     
     920    if (!call->inv) { 
     921        PJ_LOG(3,(THIS_FILE,"Call has been disconnected")); 
     922        return; 
     923    } 
     924 
     925    if (call->inv->state != PJSIP_INV_STATE_CONFIRMED) { 
    895926        PJ_LOG(3,(THIS_FILE, "Can not hold call that is not confirmed")); 
    896927        return; 
    897928    } 
    898929 
    899     status = create_inactive_sdp(inv_session, &sdp); 
     930    status = create_inactive_sdp(call, &sdp); 
    900931    if (status != PJ_SUCCESS) 
    901932        return; 
    902933 
    903934    /* Send re-INVITE with new offer */ 
    904     status = pjsip_inv_reinvite( inv_session->inv, NULL, sdp, &tdata); 
     935    status = pjsip_inv_reinvite( call->inv, NULL, sdp, &tdata); 
    905936    if (status != PJ_SUCCESS) { 
    906937        pjsua_perror(THIS_FILE, "Unable to create re-INVITE", status); 
     
    908939    } 
    909940 
    910     status = pjsip_inv_send_msg( inv_session->inv, tdata, NULL); 
     941    status = pjsip_inv_send_msg( call->inv, tdata, NULL); 
    911942    if (status != PJ_SUCCESS) { 
    912943        pjsua_perror(THIS_FILE, "Unable to send re-INVITE", status); 
     
    919950 * re-INVITE. 
    920951 */ 
    921 void pjsua_inv_reinvite(struct pjsua_inv_data *inv_session) 
     952void pjsua_call_reinvite(int call_index) 
    922953{ 
    923954    pjmedia_sdp_session *sdp; 
    924955    pjsip_tx_data *tdata; 
    925     pjsip_inv_session *inv = inv_session->inv; 
     956    pjsua_call *call; 
    926957    pj_status_t status; 
    927958 
    928  
    929     if (inv->state != PJSIP_INV_STATE_CONFIRMED) { 
     959    call = &pjsua.calls[call_index]; 
     960 
     961    if (!call->inv) { 
     962        PJ_LOG(3,(THIS_FILE,"Call has been disconnected")); 
     963        return; 
     964    } 
     965 
     966 
     967    if (call->inv->state != PJSIP_INV_STATE_CONFIRMED) { 
    930968        PJ_LOG(3,(THIS_FILE, "Can not re-INVITE call that is not confirmed")); 
    931969        return; 
     
    933971 
    934972    /* Create SDP */ 
    935     status = pjmedia_endpt_create_sdp( pjsua.med_endpt, inv->pool, 1, 
    936                                        &pjsua.med_sock_info[inv_session->call_slot], 
    937                                        &sdp); 
    938     if (status != PJ_SUCCESS) { 
    939         pjsua_perror(THIS_FILE, "Unable to get SDP from media endpoint", status); 
     973    status = pjmedia_endpt_create_sdp( pjsua.med_endpt, call->inv->pool, 1, 
     974                                       &call->skinfo, &sdp); 
     975    if (status != PJ_SUCCESS) { 
     976        pjsua_perror(THIS_FILE, "Unable to get SDP from media endpoint",  
     977                    status); 
    940978        return; 
    941979    } 
    942980 
    943981    /* Send re-INVITE with new offer */ 
    944     status = pjsip_inv_reinvite( inv_session->inv, NULL, sdp, &tdata); 
     982    status = pjsip_inv_reinvite( call->inv, NULL, sdp, &tdata); 
    945983    if (status != PJ_SUCCESS) { 
    946984        pjsua_perror(THIS_FILE, "Unable to create re-INVITE", status); 
     
    948986    } 
    949987 
    950     status = pjsip_inv_send_msg( inv_session->inv, tdata, NULL); 
     988    status = pjsip_inv_send_msg( call->inv, tdata, NULL); 
    951989    if (status != PJ_SUCCESS) { 
    952990        pjsua_perror(THIS_FILE, "Unable to send re-INVITE", status); 
     
    959997 * Transfer call. 
    960998 */ 
    961 void pjsua_inv_xfer_call(struct pjsua_inv_data *inv_session, 
    962                          const char *dest) 
     999void pjsua_call_xfer(int call_index, const char *dest) 
    9631000{ 
    9641001    pjsip_evsub *sub; 
    9651002    pjsip_tx_data *tdata; 
     1003    pjsua_call *call; 
    9661004    pj_str_t tmp; 
    9671005    pj_status_t status; 
    968   
     1006 
    9691007     
     1008    call = &pjsua.calls[call_index]; 
     1009 
     1010    if (!call->inv) { 
     1011        PJ_LOG(3,(THIS_FILE,"Call has been disconnected")); 
     1012        return; 
     1013    } 
     1014    
    9701015    /* Create xfer client subscription. 
    9711016     * We're not interested in knowing the transfer result, so we 
    9721017     * put NULL as the callback. 
    9731018     */ 
    974     status = pjsip_xfer_create_uac(inv_session->inv->dlg, NULL, &sub); 
     1019    status = pjsip_xfer_create_uac(call->inv->dlg, NULL, &sub); 
    9751020    if (status != PJ_SUCCESS) { 
    9761021        pjsua_perror(THIS_FILE, "Unable to create xfer", status); 
     
    10061051void pjsua_inv_shutdown() 
    10071052{ 
    1008     struct pjsua_inv_data *inv_data, *next; 
    1009  
    1010     inv_data = pjsua.inv_list.next; 
    1011     while (inv_data != &pjsua.inv_list) { 
     1053    int i; 
     1054 
     1055    for (i=0; i<pjsua.max_calls; ++i) { 
    10121056        pjsip_tx_data *tdata; 
    1013  
    1014         next = inv_data->next; 
    1015  
    1016         if (pjsip_inv_end_session(inv_data->inv, 410, NULL, &tdata)==0) { 
     1057        pjsua_call *call; 
     1058 
     1059        if (pjsua.calls[i].inv == NULL) 
     1060            continue; 
     1061 
     1062        call = &pjsua.calls[i]; 
     1063 
     1064        if (pjsip_inv_end_session(call->inv, 410, NULL, &tdata)==0) { 
    10171065            if (tdata) 
    1018                 pjsip_inv_send_msg(inv_data->inv, tdata, NULL); 
     1066                pjsip_inv_send_msg(call->inv, tdata, NULL); 
    10191067        } 
    1020  
    1021         inv_data = next; 
    1022     } 
    1023 } 
    1024  
    1025  
     1068    } 
     1069} 
     1070 
     1071 
     1072pj_status_t pjsua_call_init(void) 
     1073{ 
     1074    /* Initialize invite session callback. */ 
     1075    pjsip_inv_callback inv_cb; 
     1076    pj_status_t status; 
     1077 
     1078    pj_memset(&inv_cb, 0, sizeof(inv_cb)); 
     1079    inv_cb.on_state_changed = &pjsua_call_on_state_changed; 
     1080    inv_cb.on_new_session = &pjsua_call_on_forked; 
     1081    inv_cb.on_media_update = &pjsua_call_on_media_update; 
     1082    inv_cb.on_rx_offer = &pjsua_call_on_rx_offer; 
     1083    inv_cb.on_tsx_state_changed = &pjsua_call_on_tsx_state_changed; 
     1084 
     1085 
     1086    /* Initialize invite session module: */ 
     1087    status = pjsip_inv_usage_init(pjsua.endpt, &pjsua.mod, &inv_cb); 
     1088     
     1089    return status; 
     1090} 
  • pjproject/trunk/pjsip/src/pjsua/pjsua_core.c

    r230 r236  
    4646void pjsua_default(void) 
    4747{ 
     48    unsigned i; 
     49 
    4850 
    4951    /* Normally need another thread for console application, because main  
     
    5456 
    5557    /* Default transport settings: */ 
    56  
    5758    pjsua.sip_port = 5060; 
    5859 
    5960 
    6061    /* Default logging settings: */ 
    61  
    6262    pjsua.log_level = 5; 
    6363    pjsua.app_log_level = 4; 
     
    6565                      PJ_LOG_HAS_MICRO_SEC | PJ_LOG_HAS_NEWLINE; 
    6666 
     67 
    6768    /* Default: do not use STUN: */ 
    68  
    6969    pjsua.stun_port1 = pjsua.stun_port2 = 0; 
    7070 
    71     /* Default URIs: */ 
    72  
    73     pjsua.local_uri = pj_str(PJSUA_LOCAL_URI); 
    74  
    75     /* Default registration timeout: */ 
    76  
    77     pjsua.reg_timeout = 55; 
    78  
    79     /* Default maximum conference ports: */ 
    80  
    81     pjsua.max_ports = 8; 
    82  
    83     /* Init route set list: */ 
    84  
    85     pj_list_init(&pjsua.route_set); 
    86  
    87     /* Init invite session list: */ 
    88  
    89     pj_list_init(&pjsua.inv_list); 
     71    /* Init accounts: */ 
     72    pjsua.acc_cnt = 1; 
     73    for (i=0; i<PJ_ARRAY_SIZE(pjsua.acc); ++i) { 
     74        pjsua.acc[i].index = i; 
     75        pjsua.acc[i].local_uri = pj_str(PJSUA_LOCAL_URI); 
     76        pjsua.acc[i].reg_timeout = 55; 
     77        pj_list_init(&pjsua.acc[i].route_set); 
     78        pj_list_init(&pjsua.acc[i].pres_srv_list); 
     79    } 
     80 
     81    /* Init call array: */ 
     82    for (i=0; i<PJ_ARRAY_SIZE(pjsua.calls); ++i) 
     83        pjsua.calls[i].index = i; 
     84 
     85    /* Default max nb of calls. */ 
     86    pjsua.max_calls = 4; 
    9087 
    9188    /* Init server presence subscription list: */ 
    9289     
    93     pj_list_init(&pjsua.pres_srv_list); 
    9490 
    9591} 
     
    111107    if (rdata->msg_info.msg->line.req.method.id == PJSIP_INVITE_METHOD) { 
    112108 
    113         return pjsua_inv_on_incoming(rdata); 
    114  
     109        return pjsua_call_on_incoming(rdata); 
    115110    } 
    116111 
     
    146141        RTP_START_PORT = 4000, 
    147142        RTP_RANDOM_START = 2, 
    148         RTP_RETRY = 20  
     143        RTP_RETRY = 100 
    149144    }; 
    150145    enum { 
     
    241236                pj_memcpy(&mapped_addr[i], &addr, sizeof(addr)); 
    242237 
    243             if (sip) 
    244                 mapped_addr[SIP_SOCK].sin_port = pj_htons((pj_uint16_t)pjsua.sip_port); 
    245             mapped_addr[RTP_SOCK].sin_port = pj_htons((pj_uint16_t)rtp_port); 
    246             mapped_addr[RTCP_SOCK].sin_port = pj_htons((pj_uint16_t)(rtp_port+1)); 
     238            if (sip) { 
     239                mapped_addr[SIP_SOCK].sin_port =  
     240                    pj_htons((pj_uint16_t)pjsua.sip_port); 
     241            } 
     242            mapped_addr[RTP_SOCK].sin_port=pj_htons((pj_uint16_t)rtp_port); 
     243            mapped_addr[RTCP_SOCK].sin_port=pj_htons((pj_uint16_t)(rtp_port+1)); 
    247244            break; 
     245 
    248246        } else { 
    249             status = pj_stun_get_mapped_addr( &pjsua.cp.factory, 3, sock, 
    250                                               &pjsua.stun_srv1, pjsua.stun_port1, 
    251                                               &pjsua.stun_srv2, pjsua.stun_port2, 
    252                                               mapped_addr); 
     247            status=pj_stun_get_mapped_addr(&pjsua.cp.factory, 3, sock, 
     248                                           &pjsua.stun_srv1, pjsua.stun_port1, 
     249                                           &pjsua.stun_srv2, pjsua.stun_port2, 
     250                                           mapped_addr); 
    253251            if (status != PJ_SUCCESS) { 
    254252                pjsua_perror(THIS_FILE, "STUN error", status); 
     
    256254            } 
    257255 
    258             if (pj_ntohs(mapped_addr[2].sin_port) == pj_ntohs(mapped_addr[1].sin_port)+1) 
     256            if (pj_ntohs(mapped_addr[2].sin_port) ==  
     257                pj_ntohs(mapped_addr[1].sin_port)+1) 
     258            { 
    259259                break; 
    260  
    261             pj_sock_close(sock[RTP_SOCK]); sock[RTP_SOCK] = PJ_INVALID_SOCKET; 
    262             pj_sock_close(sock[RTCP_SOCK]); sock[RTCP_SOCK] = PJ_INVALID_SOCKET; 
     260            } 
     261 
     262            pj_sock_close(sock[RTP_SOCK]);  
     263            sock[RTP_SOCK] = PJ_INVALID_SOCKET; 
     264 
     265            pj_sock_close(sock[RTCP_SOCK]);  
     266            sock[RTCP_SOCK] = PJ_INVALID_SOCKET; 
    263267        } 
    264268    } 
    265269 
    266270    if (sock[RTP_SOCK] == PJ_INVALID_SOCKET) { 
    267         PJ_LOG(1,(THIS_FILE, "Unable to find appropriate RTP/RTCP ports combination")); 
     271        PJ_LOG(1,(THIS_FILE,  
     272                  "Unable to find appropriate RTP/RTCP ports combination")); 
    268273        goto on_error; 
    269274    } 
     
    271276    if (sip) { 
    272277        pjsua.sip_sock = sock[SIP_SOCK]; 
    273         pj_memcpy(&pjsua.sip_sock_name, &mapped_addr[SIP_SOCK], sizeof(pj_sockaddr_in)); 
     278        pj_memcpy(&pjsua.sip_sock_name,  
     279                  &mapped_addr[SIP_SOCK],  
     280                  sizeof(pj_sockaddr_in)); 
    274281    } else { 
    275282        pj_sock_close(sock[0]); 
     
    392399    /* Initialize invite session module: */ 
    393400 
    394     { 
    395          
    396         /* Initialize invite session callback. */ 
    397         pjsip_inv_callback inv_cb; 
    398  
    399         pj_memset(&inv_cb, 0, sizeof(inv_cb)); 
    400         inv_cb.on_state_changed = &pjsua_inv_on_state_changed; 
    401         inv_cb.on_new_session = &pjsua_inv_on_new_session; 
    402         inv_cb.on_media_update = &pjsua_inv_on_media_update; 
    403         inv_cb.on_rx_offer = &pjsua_inv_on_rx_offer; 
    404         inv_cb.on_tsx_state_changed = &pjsua_inv_on_tsx_state_changed; 
    405  
    406  
    407         /* Initialize invite session module: */ 
    408         status = pjsip_inv_usage_init(pjsua.endpt, &pjsua.mod, &inv_cb); 
    409         if (status != PJ_SUCCESS) { 
    410             pjsua_perror(THIS_FILE, "Invite usage initialization error",  
    411                          status); 
    412             goto on_error; 
    413         } 
    414  
    415     } 
    416  
     401    status = pjsua_call_init(); 
     402    if (status != PJ_SUCCESS) { 
     403        pjsua_perror(THIS_FILE, "Invite usage initialization error",  
     404                     status); 
     405        goto on_error; 
     406    } 
    417407 
    418408    /* Done */ 
     
    521511    /* Init conference bridge. */ 
    522512 
    523     status = pjmedia_conf_create(pjsua.pool, pjsua.max_ports,  
     513    status = pjmedia_conf_create(pjsua.pool,  
     514                                 pjsua.max_calls+PJSUA_CONF_MORE_PORTS,  
    524515                                 8000, 160, 16, &pjsua.mconf); 
    525516    if (status != PJ_SUCCESS) { 
     
    548539 
    549540 
     541/* 
     542 * Find account for incoming request. 
     543 */ 
     544int pjsua_find_account_for_incoming(pjsip_rx_data *rdata) 
     545{ 
     546    pjsip_uri *uri; 
     547    pjsip_sip_uri *sip_uri; 
     548    int acc_index; 
     549 
     550    uri = rdata->msg_info.to->uri; 
     551 
     552    /* Just return account #0 if To URI is not SIP: */ 
     553    if (!PJSIP_URI_SCHEME_IS_SIP(uri) &&  
     554        !PJSIP_URI_SCHEME_IS_SIPS(uri))  
     555    { 
     556        return 0; 
     557    } 
     558 
     559 
     560    sip_uri = (pjsip_sip_uri*)pjsip_uri_get_uri(uri); 
     561 
     562    /* Find account which has matching username and domain. */ 
     563    for (acc_index=0; acc_index < pjsua.acc_cnt; ++acc_index) { 
     564 
     565        pjsua_acc *acc = &pjsua.acc[acc_index]; 
     566 
     567        if (pj_stricmp(&acc->user_part, &sip_uri->user)==0 && 
     568            pj_stricmp(&acc->host_part, &sip_uri->host)==0)  
     569        { 
     570            /* Match ! */ 
     571            return acc_index; 
     572        } 
     573    } 
     574 
     575    /* No matching, try match domain part only. */ 
     576    for (acc_index=0; acc_index < pjsua.acc_cnt; ++acc_index) { 
     577 
     578        pjsua_acc *acc = &pjsua.acc[acc_index]; 
     579 
     580        if (pj_stricmp(&acc->host_part, &sip_uri->host)==0) { 
     581            /* Match ! */ 
     582            return acc_index; 
     583        } 
     584    } 
     585 
     586    /* Still no match, just return account #0 */ 
     587    return 0; 
     588} 
     589 
     590 
     591/* 
     592 * Find account for outgoing request. 
     593 */ 
     594int pjsua_find_account_for_outgoing(const pj_str_t *url) 
     595{ 
     596    PJ_UNUSED_ARG(url); 
     597 
     598    /* Just use account #0 */ 
     599    return 0; 
     600} 
     601 
    550602 
    551603/* 
     
    589641 
    590642    /* Init sockets (STUN etc): */ 
    591     for (i=0; i<PJ_ARRAY_SIZE(pjsua.med_sock_info); ++i) { 
    592         status = init_sockets(i==0, &pjsua.med_sock_info[i]); 
     643    for (i=0; i<(int)pjsua.max_calls; ++i) { 
     644        status = init_sockets(i==0, &pjsua.calls[i].skinfo); 
    593645        if (status != PJ_SUCCESS) { 
    594646            pjsua_perror(THIS_FILE, "init_sockets() has returned error",  
    595647                         status); 
     648            --i; 
     649            if (i >= 0) 
     650                pj_sock_close(pjsua.sip_sock); 
     651            while (i >= 0) { 
     652                pj_sock_close(pjsua.calls[i].skinfo.rtp_sock); 
     653                pj_sock_close(pjsua.calls[i].skinfo.rtcp_sock); 
     654            } 
    596655            return status; 
    597656        } 
     
    624683 
    625684    /* Initialize Contact URI, if one is not specified: */ 
    626  
    627     if (pjsua.contact_uri.slen == 0 && pjsua.local_uri.slen) { 
     685    for (i=0; i<pjsua.acc_cnt; ++i) { 
    628686 
    629687        pjsip_uri *uri; 
    630688        pjsip_sip_uri *sip_uri; 
    631         char contact[128]; 
    632         int len; 
    633  
    634         /* The local Contact is the username@ip-addr, where 
    635          *  - username is taken from the local URI, 
    636          *  - ip-addr in UDP transport's address name (which may have been 
    637          *    resolved from STUN. 
    638          */ 
    639          
     689 
    640690        /* Need to parse local_uri to get the elements: */ 
    641691 
    642         uri = pjsip_parse_uri(pjsua.pool, pjsua.local_uri.ptr,  
    643                               pjsua.local_uri.slen, 0); 
     692        uri = pjsip_parse_uri(pjsua.pool, pjsua.acc[i].local_uri.ptr, 
     693                              pjsua.acc[i].local_uri.slen, 0); 
    644694        if (uri == NULL) { 
    645695            pjsua_perror(THIS_FILE, "Invalid local URI",  
     
    648698        } 
    649699 
    650  
    651700        /* Local URI MUST be a SIP or SIPS: */ 
    652701 
    653         if (!PJSIP_URI_SCHEME_IS_SIP(uri) && !PJSIP_URI_SCHEME_IS_SIPS(uri)) { 
     702        if (!PJSIP_URI_SCHEME_IS_SIP(uri) &&  
     703            !PJSIP_URI_SCHEME_IS_SIPS(uri))  
     704        { 
    654705            pjsua_perror(THIS_FILE, "Invalid local URI",  
    655706                         PJSIP_EINVALIDSCHEME); 
     
    662713        sip_uri = (pjsip_sip_uri*) pjsip_uri_get_uri(uri); 
    663714 
    664          
    665         /* Build temporary contact string. */ 
    666  
    667         if (sip_uri->user.slen) { 
    668  
    669             /* With the user part. */ 
    670             len = pj_snprintf(contact, sizeof(contact), 
    671                               "<sip:%.*s@%.*s:%d>", 
    672                               (int)sip_uri->user.slen, 
    673                               sip_uri->user.ptr, 
    674                               (int)udp_transport->local_name.host.slen, 
    675                               udp_transport->local_name.host.ptr, 
    676                               udp_transport->local_name.port); 
    677         } else { 
    678  
    679             /* Without user part */ 
    680  
    681             len = pj_snprintf(contact, sizeof(contact), 
    682                               "<sip:%.*s:%d>", 
    683                               (int)udp_transport->local_name.host.slen, 
    684                               udp_transport->local_name.host.ptr, 
    685                               udp_transport->local_name.port); 
    686         } 
    687  
    688         if (len < 1 || len >= sizeof(contact)) { 
    689             pjsua_perror(THIS_FILE, "Invalid Contact", PJSIP_EURITOOLONG); 
    690             return PJSIP_EURITOOLONG; 
    691         } 
    692  
    693         /* Duplicate Contact uri. */ 
    694  
    695         pj_strdup2(pjsua.pool, &pjsua.contact_uri, contact); 
    696  
     715        pjsua.acc[i].user_part = sip_uri->user; 
     716        pjsua.acc[i].host_part = sip_uri->host; 
     717 
     718        if (pjsua.acc[i].contact_uri.slen == 0 &&  
     719            pjsua.acc[i].local_uri.slen)  
     720        { 
     721            char contact[128]; 
     722            int len; 
     723 
     724            /* The local Contact is the username@ip-addr, where 
     725             *  - username is taken from the local URI, 
     726             *  - ip-addr in UDP transport's address name (which may have been 
     727             *    resolved from STUN. 
     728             */ 
     729             
     730            /* Build temporary contact string. */ 
     731 
     732            if (sip_uri->user.slen) { 
     733 
     734                /* With the user part. */ 
     735                len = pj_snprintf(contact, sizeof(contact), 
     736                                  "<sip:%.*s@%.*s:%d>", 
     737                                  (int)sip_uri->user.slen, 
     738                                  sip_uri->user.ptr, 
     739                                  (int)udp_transport->local_name.host.slen, 
     740                                  udp_transport->local_name.host.ptr, 
     741                                  udp_transport->local_name.port); 
     742            } else { 
     743 
     744                /* Without user part */ 
     745 
     746                len = pj_snprintf(contact, sizeof(contact), 
     747                                  "<sip:%.*s:%d>", 
     748                                  (int)udp_transport->local_name.host.slen, 
     749                                  udp_transport->local_name.host.ptr, 
     750                                  udp_transport->local_name.port); 
     751            } 
     752 
     753            if (len < 1 || len >= sizeof(contact)) { 
     754                pjsua_perror(THIS_FILE, "Invalid Contact", PJSIP_EURITOOLONG); 
     755                return PJSIP_EURITOOLONG; 
     756            } 
     757 
     758            /* Duplicate Contact uri. */ 
     759 
     760            pj_strdup2(pjsua.pool, &pjsua.acc[i].contact_uri, contact); 
     761 
     762        } 
    697763    } 
    698764 
     
    715781        } 
    716782 
    717         pj_list_push_back(&pjsua.route_set, route); 
     783        for (i=0; i<pjsua.acc_cnt; ++i) { 
     784            pj_list_push_front(&pjsua.acc[i].route_set, route); 
     785        } 
    718786    } 
    719787 
     
    737805 
    738806    /* Create client registration session: */ 
    739  
    740     status = pjsua_regc_init(); 
    741     if (status != PJ_SUCCESS) 
    742         return status; 
    743  
    744     /* Perform registration, if required. */ 
    745     if (pjsua.regc) { 
    746         pjsua_regc_update(1); 
     807    for (i=0; i<pjsua.acc_cnt; ++i) { 
     808        status = pjsua_regc_init(i); 
     809        if (status != PJ_SUCCESS) 
     810            return status; 
     811 
     812        /* Perform registration, if required. */ 
     813        if (pjsua.acc[i].regc) { 
     814            pjsua_regc_update(i, 1); 
     815        } 
     816    } 
     817 
     818 
     819    /* Find account for outgoing preence subscription */ 
     820    for (i=0; i<pjsua.buddy_cnt; ++i) { 
     821        pjsua.buddies[i].acc_index =  
     822            pjsua_find_account_for_outgoing(&pjsua.buddies[i].uri); 
    747823    } 
    748824 
     
    777853    /* Signal threads to quit: */ 
    778854    pjsua.quit_flag = 1; 
     855 
     856    /* Terminate all calls. */ 
     857    pjsua_inv_shutdown(); 
     858 
     859    /* Terminate all presence subscriptions. */ 
     860    pjsua_pres_shutdown(); 
     861 
     862    /* Unregister, if required: */ 
     863    for (i=0; i<pjsua.acc_cnt; ++i) { 
     864        if (pjsua.acc[i].regc) { 
     865            pjsua_regc_update(i, 0); 
     866        } 
     867    } 
    779868 
    780869    /* Wait worker threads to quit: */ 
     
    789878 
    790879 
    791     /* Terminate all calls. */ 
    792     pjsua_inv_shutdown(); 
    793  
    794     /* Terminate all presence subscriptions. */ 
    795     pjsua_pres_shutdown(); 
    796  
    797     /* Unregister, if required: */ 
    798     if (pjsua.regc) { 
    799         pjsua_regc_update(0); 
    800     } 
    801  
    802880    /* Wait for some time to allow unregistration to complete: */ 
    803881    PJ_LOG(4,(THIS_FILE, "Shutting down...")); 
  • pjproject/trunk/pjsip/src/pjsua/pjsua_opt.c

    r223 r236  
    4444    puts("  pjsua [options]"); 
    4545    puts(""); 
    46     puts("  [sip-url]   Default URL to invite."); 
    47     puts(""); 
    4846    puts("General options:"); 
    4947    puts("  --help              Display this help screen"); 
     
    5654    puts("  --app-log-level=N   Set log max level for stdout display to N"); 
    5755    puts(""); 
     56    puts("SIP Account options:"); 
     57    puts("  --id=url            Set the URL of local ID (used in From header)"); 
     58    puts("  --contact=url       Override the Contact information"); 
     59    puts("  --proxy=url         Set the URL of proxy server"); 
     60    puts(""); 
     61    puts("SIP Account Registration Options:"); 
     62    puts("  --registrar=url     Set the URL of registrar server"); 
     63    puts("  --reg-timeout=secs  Set registration interval to secs (default 3600)"); 
     64    puts(""); 
     65    puts("SIP Account Control:"); 
     66    puts("  --next-account      Add more account"); 
     67    puts(""); 
    5868    puts("Authentication options:"); 
    5969    puts("  --realm=string      Set realm"); 
    6070    puts("  --username=string   Set authentication username"); 
    6171    puts("  --password=string   Set authentication password"); 
    62     puts(""); 
    63     puts("SIP options:"); 
    64     puts("  --id=url            Set the URL of local ID (used in From header)"); 
    65     puts("  --contact=url       Override the Contact information"); 
    66     puts("  --proxy=url         Set the URL of proxy server"); 
    67     //puts("  --outbound=url      Set the URL of outbound proxy server"); 
    68     puts(""); 
    69     puts("Registration Options:"); 
    70     puts("  --registrar=url     Set the URL of registrar server"); 
    71     puts("  --reg-timeout=secs  Set registration interval to secs (default 3600)"); 
     72    puts("  --next-cred         Add more credential"); 
    7273    puts(""); 
    7374    puts("Transport Options:"); 
    74     puts("  --local-port=port   Set TCP/UDP port"); 
     75    puts("  --local-port=port        Set TCP/UDP port"); 
     76    puts("  --outbound=url           Set the URL of outbound proxy server"); 
    7577    puts("  --use-stun1=host[:port]"); 
    76     puts("  --use-stun2=host[:port]  Use STUN and set host name and port of STUN servers"); 
     78    puts("  --use-stun2=host[:port]  Resolve local IP with the specified STUN servers"); 
    7779    puts(""); 
    7880    puts("Media Options:"); 
    7981    puts("  --null-audio        Use NULL audio device"); 
    80     //puts("  --wav-file=file     Play WAV file in conference bridge"); 
     82    puts("  --play-file=file    Play WAV file in conference bridge"); 
     83    puts("  --auto-play         Automatically play the file (to incoming calls only)"); 
     84    puts("  --auto-loop         Automatically loop incoming RTP to outgoing RTP"); 
     85    puts("  --auto-conf         Automatically put incoming calls to conference"); 
    8186    puts(""); 
    8287    puts("Buddy List (can be more than one):"); 
     
    8590    puts("User Agent options:"); 
    8691    puts("  --auto-answer=code  Automatically answer incoming calls with code (e.g. 200)"); 
    87     puts("  --auto-play=file    Automatically play WAVE file to incoming calls"); 
     92    puts("  --max-calls=N       Maximum number of concurrent calls (default:4, max:255)"); 
    8893    puts(""); 
    8994    fflush(stdout); 
     
    200205           OPT_USE_STUN1, OPT_USE_STUN2,  
    201206           OPT_ADD_BUDDY, OPT_OFFER_X_MS_MSG, OPT_NO_PRESENCE, 
    202            OPT_AUTO_ANSWER, OPT_AUTO_HANGUP, OPT_AUTO_PLAY}; 
     207           OPT_AUTO_ANSWER, OPT_AUTO_HANGUP, OPT_AUTO_PLAY, OPT_AUTO_LOOP, 
     208           OPT_AUTO_CONF, 
     209           OPT_PLAY_FILE, 
     210           OPT_NEXT_ACCOUNT, OPT_NEXT_CRED, OPT_MAX_CALLS, 
     211    }; 
    203212    struct option long_options[] = { 
    204213        { "config-file",1, 0, OPT_CONFIG_FILE}, 
     
    226235        { "auto-answer",1, 0, OPT_AUTO_ANSWER}, 
    227236        { "auto-hangup",1, 0, OPT_AUTO_HANGUP}, 
    228         { "auto-play",  1, 0, OPT_AUTO_PLAY}, 
     237        { "auto-play",  0, 0, OPT_AUTO_PLAY}, 
     238        { "auto-loop",  0, 0, OPT_AUTO_LOOP}, 
     239        { "auto-conf",  0, 0, OPT_AUTO_CONF}, 
     240        { "play-file",  1, 0, OPT_PLAY_FILE}, 
     241        { "next-account",0,0, OPT_NEXT_ACCOUNT}, 
     242        { "next-cred",  0, 0, OPT_NEXT_CRED}, 
     243        { "max-calls",  1, 0, OPT_MAX_CALLS}, 
    229244        { NULL, 0, 0, 0} 
    230245    }; 
    231246    pj_status_t status; 
     247    pjsua_acc *cur_acc; 
     248    pjsip_cred_info *cur_cred; 
    232249    char *config_file = NULL; 
    233250 
     
    248265            return status; 
    249266    } 
     267 
     268 
     269    cur_acc = &pjsua.acc[0]; 
     270    cur_cred = &pjsua.cred_info[0]; 
    250271 
    251272 
     
    308329                return PJ_EINVAL; 
    309330            } 
    310             pjsua.proxy = pj_str(optarg); 
     331            cur_acc->proxy = pj_str(optarg); 
    311332            break; 
    312333 
     
    324345                return PJ_EINVAL; 
    325346            } 
    326             pjsua.registrar_uri = pj_str(optarg); 
     347            cur_acc->reg_uri = pj_str(optarg); 
    327348            break; 
    328349 
    329350        case OPT_REG_TIMEOUT:   /* reg-timeout */ 
    330             pjsua.reg_timeout = pj_strtoul(pj_cstr(&tmp,optarg)); 
    331             if (pjsua.reg_timeout < 1 || pjsua.reg_timeout > 3600) { 
     351            cur_acc->reg_timeout = pj_strtoul(pj_cstr(&tmp,optarg)); 
     352            if (cur_acc->reg_timeout < 1 || cur_acc->reg_timeout > 3600) { 
    332353                printf("Error: invalid value for --reg-timeout (expecting 1-3600)\n"); 
    333354                return PJ_EINVAL; 
     
    340361                return PJ_EINVAL; 
    341362            } 
    342             pjsua.local_uri = pj_str(optarg); 
     363            cur_acc->local_uri = pj_str(optarg); 
    343364            break; 
    344365 
     
    348369                return PJ_EINVAL; 
    349370            } 
    350             pjsua.contact_uri = pj_str(optarg); 
     371            cur_acc->contact_uri = pj_str(optarg); 
     372            break; 
     373 
     374        case OPT_NEXT_ACCOUNT: /* Add more account. */ 
     375            pjsua.acc_cnt++; 
     376            cur_acc = &pjsua.acc[pjsua.acc_cnt - 1]; 
    351377            break; 
    352378 
    353379        case OPT_USERNAME:   /* Default authentication user */ 
    354             if (!pjsua.cred_count) pjsua.cred_count = 1; 
    355             pjsua.cred_info[0].username = pj_str(optarg); 
     380            if (pjsua.cred_count==0) pjsua.cred_count=1; 
     381            cur_cred->username = pj_str(optarg); 
    356382            break; 
    357383 
    358384        case OPT_REALM:     /* Default authentication realm. */ 
    359             if (!pjsua.cred_count) pjsua.cred_count = 1; 
    360             pjsua.cred_info[0].realm = pj_str(optarg); 
     385            if (pjsua.cred_count==0) pjsua.cred_count=1; 
     386            cur_cred->realm = pj_str(optarg); 
    361387            break; 
    362388 
    363389        case OPT_PASSWORD:   /* authentication password */ 
    364             if (!pjsua.cred_count) pjsua.cred_count = 1; 
    365             pjsua.cred_info[0].data_type = 0; 
    366             pjsua.cred_info[0].data = pj_str(optarg); 
     390            if (pjsua.cred_count==0) pjsua.cred_count=1; 
     391            cur_cred->data_type = 0; 
     392            cur_cred->data = pj_str(optarg); 
     393            break; 
     394 
     395        case OPT_NEXT_CRED: /* Next credential */ 
     396            pjsua.cred_count++; 
     397            cur_cred = &pjsua.cred_info[pjsua.cred_count - 1]; 
    367398            break; 
    368399 
     
    412443 
    413444        case OPT_AUTO_PLAY: 
     445            pjsua.auto_play = 1; 
     446            break; 
     447 
     448        case OPT_AUTO_LOOP: 
     449            pjsua.auto_loop = 1; 
     450            break; 
     451 
     452        case OPT_AUTO_CONF: 
     453            pjsua.auto_conf = 1; 
     454            break; 
     455 
     456        case OPT_PLAY_FILE: 
    414457            pjsua.wav_file = optarg; 
    415458            break; 
     
    422465            } 
    423466            break; 
     467 
     468        case OPT_MAX_CALLS: 
     469            pjsua.max_calls = atoi(optarg); 
     470            if (pjsua.max_calls < 1 || pjsua.max_calls > 255) { 
     471                puts("Too many calls for max-calls (1-255)"); 
     472                return -1; 
     473            } 
     474            break; 
    424475        } 
    425476    } 
     
    430481    } 
    431482 
    432     if (pjsua.reg_timeout == 0) 
    433         pjsua.reg_timeout = 3600; 
    434  
    435  
    436483    return PJ_SUCCESS; 
    437484} 
     
    439486 
    440487 
    441 static void print_invite_session(const char *title, 
    442                                  struct pjsua_inv_data *inv_data,  
    443                                 char *buf, pj_size_t size) 
     488static void print_call(const char *title, 
     489                       int call_index,  
     490                      char *buf, pj_size_t size) 
    444491{ 
    445492    int len; 
    446     pjsip_inv_session *inv = inv_data->inv; 
     493    pjsip_inv_session *inv = pjsua.calls[call_index].inv; 
    447494    pjsip_dialog *dlg = inv->dlg; 
    448495    char userinfo[128]; 
     
    516563void pjsua_dump(void) 
    517564{ 
    518     struct pjsua_inv_data *inv_data; 
    519565    char buf[128]; 
    520566    unsigned old_decor; 
     
    534580    PJ_LOG(3,(THIS_FILE, "Dumping invite sessions:")); 
    535581 
    536     if (pj_list_empty(&pjsua.inv_list)) { 
     582    if (pjsua.call_cnt == 0) { 
    537583 
    538584        PJ_LOG(3,(THIS_FILE, "  - no sessions -")); 
    539585 
    540586    } else { 
    541  
    542         inv_data = pjsua.inv_list.next; 
    543  
    544         while (inv_data != &pjsua.inv_list) { 
    545  
    546             print_invite_session("  ", inv_data, buf, sizeof(buf)); 
     587        int i; 
     588 
     589        for (i=0; i<pjsua.max_calls; ++i) { 
     590 
     591            if (pjsua.calls[i].inv == NULL) 
     592                continue; 
     593 
     594            print_call("  ", i, buf, sizeof(buf)); 
    547595            PJ_LOG(3,(THIS_FILE, "%s", buf)); 
    548596 
    549             if (inv_data->session) 
    550                 dump_media_session(inv_data->session); 
    551  
    552             inv_data = inv_data->next; 
     597            if (pjsua.calls[i].session) 
     598                dump_media_session(pjsua.calls[i].session); 
    553599        } 
    554600    } 
     
    576622 
    577623/* 
    578  * Save settings. 
     624 * Save account settings 
    579625 */ 
    580 pj_status_t pjsua_save_settings(const char *filename) 
    581 { 
    582     unsigned i; 
     626static void save_account_settings(int acc_index, pj_str_t *result) 
     627{ 
     628    char line[128]; 
     629    pjsua_acc *acc = &pjsua.acc[acc_index]; 
     630 
     631     
     632    pj_ansi_sprintf(line, "#\n# Account %d:\n#\n", acc_index); 
     633    pj_strcat2(result, line); 
     634 
     635 
     636    /* Identity */ 
     637    if (acc->local_uri.slen) { 
     638        pj_ansi_sprintf(line, "--id %.*s\n",  
     639                        (int)acc->local_uri.slen,  
     640                        acc->local_uri.ptr); 
     641        pj_strcat2(result, line); 
     642    } 
     643 
     644    /* Registrar server */ 
     645    if (acc->reg_uri.slen) { 
     646        pj_ansi_sprintf(line, "--registrar %.*s\n", 
     647                              (int)acc->reg_uri.slen, 
     648                              acc->reg_uri.ptr); 
     649        pj_strcat2(result, line); 
     650 
     651        pj_ansi_sprintf(line, "--reg-timeout %u\n", 
     652                              acc->reg_timeout); 
     653        pj_strcat2(result, line); 
     654    } 
     655 
     656 
     657    /* Proxy */ 
     658    if (acc->proxy.slen) { 
     659        pj_ansi_sprintf(line, "--proxy %.*s\n", 
     660                              (int)acc->proxy.slen, 
     661                              acc->proxy.ptr); 
     662        pj_strcat2(result, line); 
     663    } 
     664} 
     665 
     666 
     667 
     668/* 
     669 * Dump settings. 
     670 */ 
     671int pjsua_dump_settings(char *buf, pj_size_t max) 
     672{ 
     673    int acc_index; 
     674    int i; 
    583675    pj_str_t cfg; 
    584676    char line[128]; 
    585     pj_pool_t *pool; 
    586     FILE *fhnd; 
    587  
    588     /* Create pool for temporary buffer. */ 
    589     pool = pj_pool_create(&pjsua.cp.factory, "settings", 4000, 0, NULL); 
    590     if (!pool) 
    591         return PJ_ENOMEM; 
    592  
    593  
    594     cfg.ptr = pj_pool_alloc(pool, 3800); 
    595     if (!cfg.ptr) { 
    596         pj_pool_release(pool); 
    597         return PJ_EBUG; 
    598     } 
     677 
     678    cfg.ptr = buf; 
    599679    cfg.slen = 0; 
    600680 
    601681 
    602     /* Identity */ 
    603     if (pjsua.local_uri.slen) { 
    604         pj_ansi_sprintf(line, "--id %.*s\n",  
    605                         (int)pjsua.local_uri.slen,  
    606                         pjsua.local_uri.ptr); 
    607         pj_strcat2(&cfg, line); 
     682    /* Logging. */ 
     683    pj_strcat2(&cfg, "#\n# Logging options:\n#\n"); 
     684    pj_ansi_sprintf(line, "--log-level %d\n", 
     685                    pjsua.log_level); 
     686    pj_strcat2(&cfg, line); 
     687 
     688    pj_ansi_sprintf(line, "--app-log-level %d\n", 
     689                    pjsua.app_log_level); 
     690    pj_strcat2(&cfg, line); 
     691 
     692    if (pjsua.log_filename) { 
     693        pj_ansi_sprintf(line, "--log-file %s\n", 
     694                        pjsua.log_filename); 
     695        pj_strcat2(&cfg, line); 
     696    } 
     697 
     698 
     699    /* Save account settings. */ 
     700    for (acc_index=0; acc_index < pjsua.acc_cnt; ++acc_index) { 
     701         
     702        save_account_settings(acc_index, &cfg); 
     703 
     704        if (acc_index < pjsua.acc_cnt-1) 
     705            pj_strcat2(&cfg, "--next-account\n"); 
    608706    } 
    609707 
    610708    /* Credentials. */ 
    611709    for (i=0; i<pjsua.cred_count; ++i) { 
     710 
     711        pj_ansi_sprintf(line, "#\n# Credential %d:\n#\n", i); 
     712        pj_strcat2(&cfg, line); 
     713 
    612714        if (pjsua.cred_info[i].realm.slen) { 
    613715            pj_ansi_sprintf(line, "--realm %.*s\n", 
     
    626728                              pjsua.cred_info[i].data.ptr); 
    627729        pj_strcat2(&cfg, line); 
    628     } 
    629  
    630     /* Registrar server */ 
    631     if (pjsua.registrar_uri.slen) { 
    632         pj_ansi_sprintf(line, "--registrar %.*s\n", 
    633                               (int)pjsua.registrar_uri.slen, 
    634                               pjsua.registrar_uri.ptr); 
    635         pj_strcat2(&cfg, line); 
    636     } 
    637  
     730 
     731        if (i < pjsua.cred_count-1) 
     732            pj_strcat2(&cfg, "--next-cred\n"); 
     733    } 
     734 
     735 
     736    pj_strcat2(&cfg, "#\n# Network settings:\n#\n"); 
    638737 
    639738    /* Outbound proxy */ 
     
    644743        pj_strcat2(&cfg, line); 
    645744    } 
    646  
    647     /* Media */ 
    648     if (pjsua.null_audio) 
    649         pj_strcat2(&cfg, "--null-audio\n"); 
    650745 
    651746 
     
    673768 
    674769 
     770    pj_strcat2(&cfg, "#\n# Media settings:\n#\n"); 
     771 
     772 
     773    /* Media */ 
     774    if (pjsua.null_audio) 
     775        pj_strcat2(&cfg, "--null-audio\n"); 
     776    if (pjsua.auto_play) 
     777        pj_strcat2(&cfg, "--auto-play\n"); 
     778    if (pjsua.auto_loop) 
     779        pj_strcat2(&cfg, "--auto-loop\n"); 
     780    if (pjsua.auto_conf) 
     781        pj_strcat2(&cfg, "--auto-conf\n"); 
     782    if (pjsua.wav_file) { 
     783        pj_ansi_sprintf(line, "--play-file %s\n", 
     784                        pjsua.wav_file); 
     785        pj_strcat2(&cfg, line); 
     786    } 
     787 
     788 
     789    pj_strcat2(&cfg, "#\n# User agent:\n#\n"); 
     790 
     791    /* Auto-answer. */ 
     792    if (pjsua.auto_answer != 0) { 
     793        pj_ansi_sprintf(line, "--auto-answer %d\n", 
     794                        pjsua.auto_answer); 
     795        pj_strcat2(&cfg, line); 
     796    } 
     797 
     798    /* Max calls. */ 
     799    pj_ansi_sprintf(line, "--max-calls %d\n", 
     800                    pjsua.max_calls); 
     801    pj_strcat2(&cfg, line); 
     802 
     803 
     804    pj_strcat2(&cfg, "#\n# Buddies:\n#\n"); 
     805 
    675806    /* Add buddies. */ 
    676807    for (i=0; i<pjsua.buddy_cnt; ++i) { 
     
    682813 
    683814 
     815    *(cfg.ptr + cfg.slen) = '\0'; 
     816    return cfg.slen; 
     817} 
     818 
     819/* 
     820 * Save settings. 
     821 */ 
     822pj_status_t pjsua_save_settings(const char *filename) 
     823{ 
     824    pj_str_t cfg; 
     825    pj_pool_t *pool; 
     826    FILE *fhnd; 
     827 
     828    /* Create pool for temporary buffer. */ 
     829    pool = pj_pool_create(&pjsua.cp.factory, "settings", 4000, 0, NULL); 
     830    if (!pool) 
     831        return PJ_ENOMEM; 
     832 
     833 
     834    cfg.ptr = pj_pool_alloc(pool, 3800); 
     835    if (!cfg.ptr) { 
     836        pj_pool_release(pool); 
     837        return PJ_EBUG; 
     838    } 
     839 
     840 
     841    cfg.slen = pjsua_dump_settings(cfg.ptr, 3800); 
     842    if (cfg.slen < 1) { 
     843        pj_pool_release(pool); 
     844        return PJ_ENOMEM; 
     845    } 
     846 
     847 
    684848    /* Write to file. */ 
    685849    fhnd = fopen(filename, "wt"); 
  • pjproject/trunk/pjsip/src/pjsua/pjsua_pres.c

    r230 r236  
    8080static pj_bool_t pres_on_rx_request(pjsip_rx_data *rdata) 
    8181{ 
     82    int acc_index; 
    8283    pjsip_method *req_method = &rdata->msg_info.msg->line.req.method; 
    8384    pjsua_srv_pres *uapres; 
     
    9495    /* Incoming SUBSCRIBE: */ 
    9596 
     97    /* Find which account for the incoming request. */ 
     98    acc_index = pjsua_find_account_for_incoming(rdata); 
     99 
    96100    /* Create UAS dialog: */ 
    97101    status = pjsip_dlg_create_uas( pjsip_ua_instance(), rdata,  
    98                                    &pjsua.contact_uri, &dlg); 
     102                                   &pjsua.acc[acc_index].contact_uri,  
     103                                   &dlg); 
    99104    if (status != PJ_SUCCESS) { 
    100105        pjsua_perror(THIS_FILE,  
     
    131136 
    132137    /* Add server subscription to the list: */ 
    133     pj_list_push_back(&pjsua.pres_srv_list, uapres); 
     138    pj_list_push_back(&pjsua.acc[acc_index].pres_srv_list, uapres); 
    134139 
    135140 
     
    147152    pj_memset(&pres_status, 0, sizeof(pres_status)); 
    148153    pres_status.info_cnt = 1; 
    149     pres_status.info[0].basic_open = pjsua.online_status; 
     154    pres_status.info[0].basic_open = pjsua.acc[acc_index].online_status; 
    150155    //Both pjsua.local_uri and pjsua.contact_uri are enclosed in "<" and ">" 
    151156    //causing XML parsing to fail. 
     
    175180 
    176181/* Refresh subscription (e.g. when our online status has changed) */ 
    177 static void refresh_server_subscription() 
     182static void refresh_server_subscription(int acc_index) 
    178183{ 
    179184    pjsua_srv_pres *uapres; 
    180185 
    181     uapres = pjsua.pres_srv_list.next; 
    182  
    183     while (uapres != &pjsua.pres_srv_list) { 
     186    uapres = pjsua.acc[acc_index].pres_srv_list.next; 
     187 
     188    while (uapres != &pjsua.acc[acc_index].pres_srv_list) { 
    184189         
    185190        pjsip_pres_status pres_status; 
     
    187192 
    188193        pjsip_pres_get_status(uapres->sub, &pres_status); 
    189         if (pres_status.info[0].basic_open != pjsua.online_status) { 
    190             pres_status.info[0].basic_open = pjsua.online_status; 
     194        if (pres_status.info[0].basic_open != pjsua.acc[acc_index].online_status) { 
     195            pres_status.info[0].basic_open = pjsua.acc[acc_index].online_status; 
    191196            pjsip_pres_set_status(uapres->sub, &pres_status); 
    192197 
     
    299304static void subscribe_buddy_presence(unsigned index) 
    300305{ 
     306    int acc_index; 
    301307    pjsip_dialog *dlg; 
    302308    pjsip_tx_data *tdata; 
    303309    pj_status_t status; 
    304310 
     311    acc_index = pjsua.buddies[index].acc_index; 
     312 
    305313    status = pjsip_dlg_create_uac( pjsip_ua_instance(),  
    306                                    &pjsua.local_uri, 
    307                                    &pjsua.contact_uri, 
     314                                   &pjsua.acc[acc_index].local_uri, 
     315                                   &pjsua.acc[acc_index].contact_uri, 
    308316                                   &pjsua.buddies[index].uri, 
    309317                                   NULL, &dlg); 
     
    326334                             &pjsua.buddies[index]); 
    327335 
    328     status = pjsip_pres_initiate(pjsua.buddies[index].sub, 60, &tdata); 
     336    status = pjsip_pres_initiate(pjsua.buddies[index].sub, -1, &tdata); 
    329337    if (status != PJ_SUCCESS) { 
    330338        pjsua.buddies[index].sub = NULL; 
     
    382390static void refresh_client_subscription(void) 
    383391{ 
    384     unsigned i; 
     392    int i; 
    385393 
    386394    for (i=0; i<pjsua.buddy_cnt; ++i) { 
     
    416424 * Refresh presence 
    417425 */ 
    418 void pjsua_pres_refresh(void) 
     426void pjsua_pres_refresh(int acc_index) 
    419427{ 
    420428    refresh_client_subscription(); 
    421     refresh_server_subscription(); 
     429    refresh_server_subscription(acc_index); 
    422430} 
    423431 
     
    428436void pjsua_pres_shutdown(void) 
    429437{ 
    430     unsigned i; 
    431  
    432     pjsua.online_status = 0; 
     438    int acc_index; 
     439    int i; 
     440 
     441    for (acc_index=0; acc_index<pjsua.acc_cnt; ++acc_index) { 
     442        pjsua.acc[acc_index].online_status = 0; 
     443    } 
     444 
    433445    for (i=0; i<pjsua.buddy_cnt; ++i) { 
    434446        pjsua.buddies[i].monitor = 0; 
    435447    } 
    436     pjsua_pres_refresh(); 
     448 
     449    for (acc_index=0; acc_index<pjsua.acc_cnt; ++acc_index) { 
     450        pjsua_pres_refresh(acc_index); 
     451    } 
    437452} 
    438453 
     
    442457void pjsua_pres_dump(void) 
    443458{ 
    444     unsigned i; 
     459    int acc_index; 
     460    int i; 
    445461 
    446462    PJ_LOG(3,(THIS_FILE, "Dumping pjsua server subscriptions:")); 
    447     if (pj_list_empty(&pjsua.pres_srv_list)) { 
    448         PJ_LOG(3,(THIS_FILE, "  - none - ")); 
    449     } else { 
    450         struct pjsua_srv_pres *uapres; 
    451  
    452         uapres = pjsua.pres_srv_list.next; 
    453         while (uapres != &pjsua.pres_srv_list) { 
    454          
    455             PJ_LOG(3,(THIS_FILE, "  %10s %s", 
    456                       pjsip_evsub_get_state_name(uapres->sub), 
    457                       uapres->remote)); 
    458  
    459             uapres = uapres->next; 
     463    for (acc_index=0; acc_index < pjsua.acc_cnt; ++acc_index) { 
     464 
     465        PJ_LOG(3,(THIS_FILE, "  %.*s", 
     466                  (int)pjsua.acc[acc_index].local_uri.slen, 
     467                  pjsua.acc[acc_index].local_uri.ptr)); 
     468 
     469        if (pj_list_empty(&pjsua.acc[acc_index].pres_srv_list)) { 
     470            PJ_LOG(3,(THIS_FILE, "  - none - ")); 
     471        } else { 
     472            struct pjsua_srv_pres *uapres; 
     473 
     474            uapres = pjsua.acc[acc_index].pres_srv_list.next; 
     475            while (uapres != &pjsua.acc[acc_index].pres_srv_list) { 
     476             
     477                PJ_LOG(3,(THIS_FILE, "    %10s %s", 
     478                          pjsip_evsub_get_state_name(uapres->sub), 
     479                          uapres->remote)); 
     480 
     481                uapres = uapres->next; 
     482            } 
    460483        } 
    461484    } 
  • pjproject/trunk/pjsip/src/pjsua/pjsua_reg.c

    r201 r236  
    3535static void regc_cb(struct pjsip_regc_cbparam *param) 
    3636{ 
     37 
     38    pjsua_acc *acc = param->token; 
     39 
    3740    /* 
    3841     * Print registration status. 
     
    4144        pjsua_perror(THIS_FILE, "SIP registration error",  
    4245                     param->status); 
    43         pjsua.regc = NULL; 
     46        pjsip_regc_destroy(acc->regc); 
     47        acc->regc = NULL; 
    4448         
    4549    } else if (param->code < 0 || param->code >= 300) { 
     
    4751                   param->code,  
    4852                   pjsip_get_status_text(param->code)->ptr)); 
    49         pjsua.regc = NULL; 
     53        pjsip_regc_destroy(acc->regc); 
     54        acc->regc = NULL; 
    5055 
    5156    } else if (PJSIP_IS_STATUS_IN_CLASS(param->code, 200)) { 
    52         PJ_LOG(3, (THIS_FILE, "SIP registration success, status=%d (%s), " 
    53                               "will re-register in %d seconds",  
    54                               param->code, 
    55                               pjsip_get_status_text(param->code)->ptr, 
    56                               param->expiration)); 
     57 
     58        if (param->expiration < 1) { 
     59            pjsip_regc_destroy(acc->regc); 
     60            acc->regc = NULL; 
     61            PJ_LOG(3,(THIS_FILE, "%s: unregistration success", 
     62                      acc->local_uri.ptr)); 
     63        } else { 
     64            PJ_LOG(3, (THIS_FILE,  
     65                       "%s: registration success, status=%d (%s), " 
     66                       "will re-register in %d seconds",  
     67                       acc->local_uri.ptr, 
     68                       param->code, 
     69                       pjsip_get_status_text(param->code)->ptr, 
     70                       param->expiration)); 
     71        } 
    5772 
    5873    } else { 
     
    6075    } 
    6176 
    62     pjsua.regc_last_err = param->status; 
    63     pjsua.regc_last_code = param->code; 
     77    acc->reg_last_err = param->status; 
     78    acc->reg_last_code = param->code; 
    6479 
    65     pjsua_ui_regc_on_state_changed(pjsua.regc_last_code); 
     80    pjsua_ui_regc_on_state_changed(acc->index); 
    6681} 
    6782 
     
    7085 * Update registration. If renew is false, then unregistration will be performed. 
    7186 */ 
    72 void pjsua_regc_update(pj_bool_t renew) 
     87void pjsua_regc_update(int acc_index, pj_bool_t renew) 
    7388{ 
    7489    pj_status_t status; 
     
    7691 
    7792    if (renew) { 
    78         if (pjsua.regc == NULL) { 
    79             status = pjsua_regc_init(); 
     93        if (pjsua.acc[acc_index].regc == NULL) { 
     94            status = pjsua_regc_init(acc_index); 
    8095            if (status != PJ_SUCCESS) { 
    8196                pjsua_perror(THIS_FILE, "Unable to create registration",  
     
    8499            } 
    85100        } 
    86         status = pjsip_regc_register(pjsua.regc, 1, &tdata); 
     101        status = pjsip_regc_register(pjsua.acc[acc_index].regc, 1, &tdata); 
    87102    } else { 
    88         if (pjsua.regc == NULL) { 
     103        if (pjsua.acc[acc_index].regc == NULL) { 
    89104            PJ_LOG(3,(THIS_FILE, "Currently not registered")); 
    90105            return; 
    91106        } 
    92         status = pjsip_regc_unregister(pjsua.regc, &tdata); 
     107        status = pjsip_regc_unregister(pjsua.acc[acc_index].regc, &tdata); 
    93108    } 
    94109 
    95110    if (status == PJ_SUCCESS) 
    96         status = pjsip_regc_send( pjsua.regc, tdata ); 
     111        status = pjsip_regc_send( pjsua.acc[acc_index].regc, tdata ); 
    97112 
    98113    if (status != PJ_SUCCESS) { 
     
    108123 * Initialize client registration. 
    109124 */ 
    110 pj_status_t pjsua_regc_init(void) 
     125pj_status_t pjsua_regc_init(int acc_index) 
    111126{ 
    112127    pj_status_t status; 
    113128 
    114129    /* initialize SIP registration if registrar is configured */ 
    115     if (pjsua.registrar_uri.slen) { 
     130    if (pjsua.acc[acc_index].reg_uri.slen) { 
    116131 
    117         status = pjsip_regc_create( pjsua.endpt, NULL, &regc_cb, &pjsua.regc); 
     132        status = pjsip_regc_create( pjsua.endpt,  
     133                                    &pjsua.acc[acc_index],  
     134                                    &regc_cb,  
     135                                    &pjsua.acc[acc_index].regc); 
    118136 
    119137        if (status != PJ_SUCCESS) { 
     
    124142 
    125143 
    126         status = pjsip_regc_init( pjsua.regc, &pjsua.registrar_uri,  
    127                                   &pjsua.local_uri,  
    128                                   &pjsua.local_uri, 
    129                                   1, &pjsua.contact_uri,  
    130                                   pjsua.reg_timeout); 
     144        status = pjsip_regc_init( pjsua.acc[acc_index].regc,  
     145                                  &pjsua.acc[acc_index].reg_uri,  
     146                                  &pjsua.acc[acc_index].local_uri,  
     147                                  &pjsua.acc[acc_index].local_uri, 
     148                                  1, &pjsua.acc[acc_index].contact_uri,  
     149                                  pjsua.acc[acc_index].reg_timeout); 
    131150        if (status != PJ_SUCCESS) { 
    132151            pjsua_perror(THIS_FILE,  
     
    136155        } 
    137156 
    138         pjsip_regc_set_credentials( pjsua.regc, pjsua.cred_count,  
     157        pjsip_regc_set_credentials( pjsua.acc[acc_index].regc,  
     158                                    pjsua.cred_count,  
    139159                                    pjsua.cred_info ); 
    140160 
    141         pjsip_regc_set_route_set( pjsua.regc, &pjsua.route_set ); 
     161        pjsip_regc_set_route_set( pjsua.acc[acc_index].regc,  
     162                                  &pjsua.acc[acc_index].route_set ); 
    142163    } 
    143164 
Note: See TracChangeset for help on using the changeset viewer.