Ignore:
Timestamp:
Jun 13, 2006 10:57:13 PM (18 years ago)
Author:
bennylp
Message:

-- REWRITE OF PJSUA API --

File:
1 edited

Legend:

Unmodified
Added
Removed
  • pjproject/trunk/pjsip/src/pjsua-lib/pjsua_core.c

    r492 r503  
    1818 */ 
    1919#include <pjsua-lib/pjsua.h> 
    20 #include "pjsua_imp.h" 
    21  
    22 /* 
    23  * pjsua_core.c 
     20#include <pjsua-lib/pjsua_internal.h> 
     21 
     22 
     23#define THIS_FILE   "pjsua_core.c" 
     24 
     25 
     26/* PJSUA application instance. */ 
     27struct pjsua_data pjsua_var; 
     28 
     29 
     30/* Display error */ 
     31PJ_DEF(void) pjsua_perror( const char *sender, const char *title,  
     32                           pj_status_t status) 
     33{ 
     34    char errmsg[PJ_ERR_MSG_SIZE]; 
     35 
     36    pj_strerror(status, errmsg, sizeof(errmsg)); 
     37    PJ_LOG(3,(sender, "%s: %s [status=%d]", title, errmsg, status)); 
     38} 
     39 
     40 
     41static void init_data() 
     42{ 
     43    unsigned i; 
     44 
     45    for (i=0; i<PJ_ARRAY_SIZE(pjsua_var.acc); ++i) 
     46        pjsua_var.acc[i].index = i; 
     47     
     48    for (i=0; i<PJ_ARRAY_SIZE(pjsua_var.tpdata); ++i) 
     49        pjsua_var.tpdata[i].index = i; 
     50} 
     51 
     52 
     53 
     54/***************************************************************************** 
     55 * This is a very simple PJSIP module, whose sole purpose is to display 
     56 * incoming and outgoing messages to log. This module will have priority 
     57 * higher than transport layer, which means: 
    2458 * 
    25  * Core application functionalities. 
    26  */ 
    27  
    28 #define THIS_FILE   "pjsua_core.c" 
    29  
    30  
    31 /*  
    32  * Global variable. 
    33  */ 
    34 struct pjsua pjsua; 
    35  
    36  
    37 /*  
    38  * Default local URI, if none is specified in cmd-line  
    39  */ 
    40 #define PJSUA_LOCAL_URI     "<sip:user@127.0.0.1>" 
    41  
    42  
    43  
    44 /* 
    45  * Init default application parameters. 
    46  */ 
    47 PJ_DEF(void) pjsua_default_config(pjsua_config *cfg) 
    48 { 
    49     unsigned i; 
    50  
    51     pj_memset(cfg, 0, sizeof(pjsua_config)); 
    52  
    53     cfg->thread_cnt = 1; 
    54     cfg->media_has_ioqueue = 1; 
    55     cfg->media_thread_cnt = 1; 
    56     cfg->udp_port = 5060; 
    57     cfg->start_rtp_port = 4000; 
    58     cfg->msg_logging = PJ_TRUE; 
    59     cfg->max_calls = 4; 
    60     cfg->conf_ports = 0; 
    61  
    62 #if defined(PJ_DARWINOS) && PJ_DARWINOS!=0 
    63     pjsua.clock_rate = 44100; 
    64 #endif 
    65  
    66     cfg->complexity = 10; 
    67     cfg->quality = 10; 
     59 *  - incoming messages will come to this module first before reaching 
     60 *    transaction layer. 
     61 * 
     62 *  - outgoing messages will come to this module last, after the message 
     63 *    has been 'printed' to contiguous buffer by transport layer and 
     64 *    appropriate transport instance has been decided for this message. 
     65 * 
     66 */ 
     67 
     68/* Notification on incoming messages */ 
     69static pj_bool_t logging_on_rx_msg(pjsip_rx_data *rdata) 
     70{ 
     71    PJ_LOG(4,(THIS_FILE, "RX %d bytes %s from %s:%d:\n" 
     72                         "%s\n" 
     73                         "--end msg--", 
     74                         rdata->msg_info.len, 
     75                         pjsip_rx_data_get_info(rdata), 
     76                         rdata->pkt_info.src_name, 
     77                         rdata->pkt_info.src_port, 
     78                         rdata->msg_info.msg_buf)); 
    6879     
    69     cfg->auto_answer = 100; 
    70     cfg->uas_duration = 3600; 
    71  
    72     /* Default logging settings: */ 
    73     cfg->log_level = 5; 
    74     cfg->app_log_level = 4; 
    75     cfg->log_decor =  PJ_LOG_HAS_SENDER | PJ_LOG_HAS_TIME |  
    76                       PJ_LOG_HAS_MICRO_SEC | PJ_LOG_HAS_NEWLINE; 
    77  
    78  
    79     /* Also init logging settings in pjsua.config, because log 
    80      * may be written before pjsua_init() is called. 
     80    /* Always return false, otherwise messages will not get processed! */ 
     81    return PJ_FALSE; 
     82} 
     83 
     84/* Notification on outgoing messages */ 
     85static pj_status_t logging_on_tx_msg(pjsip_tx_data *tdata) 
     86{ 
     87     
     88    /* Important note: 
     89     *  tp_info field is only valid after outgoing messages has passed 
     90     *  transport layer. So don't try to access tp_info when the module 
     91     *  has lower priority than transport layer. 
    8192     */ 
    82     pjsua.config.log_level = 5; 
    83     pjsua.config.app_log_level = 4; 
    84  
    85  
    86     /* Init accounts: */ 
    87     for (i=0; i<PJ_ARRAY_SIZE(pjsua.acc); ++i) { 
    88         cfg->acc_config[i].reg_timeout = 55; 
    89     } 
    90  
    91 } 
    92  
    93  
    94 #define strncpy_with_null(dst,src,len)  \ 
    95 do { \ 
    96     strncpy(dst, src, len); \ 
    97     dst[len-1] = '\0'; \ 
    98 } while (0) 
    99  
    100  
    101  
    102 PJ_DEF(pj_status_t) pjsua_test_config( const pjsua_config *cfg, 
    103                                        char *errmsg, 
    104                                        int len) 
    105 { 
    106     unsigned i; 
    107  
    108     /* If UDP port is zero, then sip_host and sip_port must be specified */ 
    109     if (cfg->udp_port == 0) { 
    110         if (cfg->sip_host.slen==0 || cfg->sip_port==0) { 
    111             strncpy_with_null(errmsg,  
    112                               "sip_host and sip_port must be specified", 
    113                               len); 
    114             return -1; 
    115         } 
    116     } 
    117  
    118     if (cfg->max_calls < 1) { 
    119         strncpy_with_null(errmsg,  
    120                           "max_calls needs to be at least 1", 
    121                           len); 
    122         return -1; 
    123     } 
    124  
    125     /* STUN */ 
    126     if (cfg->stun_srv1.slen || cfg->stun_port1 || cfg->stun_port2 ||  
    127         cfg->stun_srv2.slen)  
    128     { 
    129         if (cfg->stun_port1 == 0) { 
    130             strncpy_with_null(errmsg, "stun_port1 required", len); 
    131             return -1; 
    132         } 
    133         if (cfg->stun_srv1.slen == 0) { 
    134             strncpy_with_null(errmsg, "stun_srv1 required", len); 
    135             return -1; 
    136         } 
    137         if (cfg->stun_port2 == 0) { 
    138             strncpy_with_null(errmsg, "stun_port2 required", len); 
    139             return -1; 
    140         } 
    141         if (cfg->stun_srv2.slen == 0) { 
    142             strncpy_with_null(errmsg, "stun_srv2 required", len); 
    143             return -1; 
    144         } 
    145     } 
    146  
    147     /* Verify accounts */ 
    148     for (i=0; i<cfg->acc_cnt; ++i) { 
    149         const pjsua_acc_config *acc_cfg = &cfg->acc_config[i]; 
    150         unsigned j; 
    151  
    152         if (acc_cfg->id.slen == 0) { 
    153             strncpy_with_null(errmsg, "missing account ID", len); 
    154             return -1; 
    155         } 
    156  
    157         if (acc_cfg->id.slen == 0) { 
    158             strncpy_with_null(errmsg, "missing registrar URI", len); 
    159             return -1; 
    160         } 
    161  
    162         if (acc_cfg->reg_timeout == 0) { 
    163             strncpy_with_null(errmsg, "missing registration timeout", len); 
    164             return -1; 
    165         } 
    166  
    167  
    168         for (j=0; j<acc_cfg->cred_count; ++j) { 
    169  
    170             if (acc_cfg->cred_info[j].scheme.slen == 0) { 
    171                 strncpy_with_null(errmsg, "missing auth scheme in account",  
    172                                   len); 
    173                 return -1; 
    174             } 
    175  
    176             if (acc_cfg->cred_info[j].realm.slen == 0) { 
    177                 strncpy_with_null(errmsg, "missing realm in account", len); 
    178                 return -1; 
    179             } 
    180  
    181             if (acc_cfg->cred_info[j].username.slen == 0) { 
    182                 strncpy_with_null(errmsg, "missing username in account", len); 
    183                 return -1; 
    184             } 
    185  
    186         } 
    187     } 
    188  
     93 
     94    PJ_LOG(4,(THIS_FILE, "TX %d bytes %s to %s:%d:\n" 
     95                         "%s\n" 
     96                         "--end msg--", 
     97                         (tdata->buf.cur - tdata->buf.start), 
     98                         pjsip_tx_data_get_info(tdata), 
     99                         tdata->tp_info.dst_name, 
     100                         tdata->tp_info.dst_port, 
     101                         tdata->buf.start)); 
     102 
     103    /* Always return success, otherwise message will not get sent! */ 
    189104    return PJ_SUCCESS; 
    190105} 
    191106 
     107/* The module instance. */ 
     108static pjsip_module pjsua_msg_logger =  
     109{ 
     110    NULL, NULL,                         /* prev, next.          */ 
     111    { "mod-pjsua-log", 13 },            /* Name.                */ 
     112    -1,                                 /* Id                   */ 
     113    PJSIP_MOD_PRIORITY_TRANSPORT_LAYER-1,/* Priority            */ 
     114    NULL,                               /* load()               */ 
     115    NULL,                               /* start()              */ 
     116    NULL,                               /* stop()               */ 
     117    NULL,                               /* unload()             */ 
     118    &logging_on_rx_msg,                 /* on_rx_request()      */ 
     119    &logging_on_rx_msg,                 /* on_rx_response()     */ 
     120    &logging_on_tx_msg,                 /* on_tx_request.       */ 
     121    &logging_on_tx_msg,                 /* on_tx_response()     */ 
     122    NULL,                               /* on_tsx_state()       */ 
     123 
     124}; 
     125 
     126 
     127/***************************************************************************** 
     128 * These two functions are the main callbacks registered to PJSIP stack 
     129 * to receive SIP request and response messages that are outside any 
     130 * dialogs and any transactions. 
     131 */ 
    192132 
    193133/* 
     
    202142static pj_bool_t mod_pjsua_on_rx_request(pjsip_rx_data *rdata) 
    203143{ 
     144    pj_bool_t processed = PJ_FALSE; 
     145 
     146    PJSUA_LOCK(); 
    204147 
    205148    if (rdata->msg_info.msg->line.req.method.id == PJSIP_INVITE_METHOD) { 
    206149 
    207         return pjsua_call_on_incoming(rdata); 
    208     } 
    209  
    210     return PJ_FALSE; 
     150        processed = pjsua_call_on_incoming(rdata); 
     151    } 
     152 
     153    PJSUA_UNLOCK(); 
     154 
     155    return processed; 
    211156} 
    212157 
     
    230175 
    231176 
    232 static int PJ_THREAD_FUNC pjsua_poll(void *arg) 
    233 { 
    234     pj_status_t last_err = 0; 
    235  
    236     PJ_UNUSED_ARG(arg); 
    237  
    238     do { 
    239         pj_time_val timeout = { 0, 10 }; 
    240         pj_status_t status; 
    241          
    242         status = pjsip_endpt_handle_events (pjsua.endpt, &timeout); 
    243         if (status != PJ_SUCCESS && status != last_err) { 
    244             last_err = status; 
    245             pjsua_perror(THIS_FILE, "handle_events() returned error", status); 
    246         } 
    247     } while (!pjsua.quit_flag); 
    248  
    249     return 0; 
    250 } 
    251  
    252 /** 
    253  * Poll pjsua. 
    254  */ 
    255 PJ_DECL(int) pjsua_handle_events(unsigned msec_timeout) 
    256 { 
    257     unsigned count = 0; 
    258     pj_time_val tv; 
     177/***************************************************************************** 
     178 * Logging. 
     179 */ 
     180 
     181/* Log callback */ 
     182static void log_writer(int level, const char *buffer, int len) 
     183{ 
     184    /* Write to stdout, file, and application callback. */ 
     185 
     186    if (level <= (int)pjsua_var.log_cfg.console_level) 
     187        pj_log_write(level, buffer, len); 
     188 
     189    if (pjsua_var.log_file) { 
     190        pj_ssize_t size = len; 
     191        pj_file_write(pjsua_var.log_file, buffer, &size); 
     192    } 
     193 
     194    if (pjsua_var.log_cfg.cb) 
     195        (*pjsua_var.log_cfg.cb)(level, buffer, len); 
     196} 
     197 
     198 
     199/* 
     200 * Application can call this function at any time (after pjsua_create(), of 
     201 * course) to change logging settings. 
     202 */ 
     203PJ_DEF(pj_status_t) pjsua_reconfigure_logging(const pjsua_logging_config *cfg) 
     204{ 
    259205    pj_status_t status; 
    260206 
    261     tv.sec = 0; 
    262     tv.msec = msec_timeout; 
    263     pj_time_val_normalize(&tv); 
    264  
    265     status = pjsip_endpt_handle_events2(pjsua.endpt, &tv, &count); 
    266     if (status != PJ_SUCCESS) 
    267         return -status; 
    268  
    269     return count; 
    270 } 
    271  
    272  
    273 #define pjsua_has_stun()    (pjsua.config.stun_port1 && \ 
    274                              pjsua.config.stun_port2) 
    275  
    276  
    277 /* 
    278  * Create and initialize SIP socket (and possibly resolve public 
    279  * address via STUN, depending on config). 
    280  */ 
    281 static pj_status_t create_sip_udp_sock(int port, 
    282                                        pj_sock_t *p_sock, 
    283                                        pj_sockaddr_in *p_pub_addr) 
    284 { 
    285     pj_sock_t sock; 
    286     pj_status_t status; 
    287  
    288     status = pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, &sock); 
    289     if (status != PJ_SUCCESS) { 
    290         pjsua_perror(THIS_FILE, "socket() error", status); 
    291         return status; 
    292     } 
    293  
    294     status = pj_sock_bind_in(sock, 0, (pj_uint16_t)port); 
    295     if (status != PJ_SUCCESS) { 
    296         pjsua_perror(THIS_FILE, "bind() error", status); 
    297         pj_sock_close(sock); 
    298         return status; 
    299     } 
    300  
    301     if (pjsua_has_stun()) { 
    302         status = pj_stun_get_mapped_addr(&pjsua.cp.factory, 1, &sock, 
    303                                          &pjsua.config.stun_srv1,  
    304                                          pjsua.config.stun_port1, 
    305                                          &pjsua.config.stun_srv2,  
    306                                          pjsua.config.stun_port2, 
    307                                          p_pub_addr); 
     207    /* Save config. */ 
     208    pjsua_logging_config_dup(pjsua_var.pool, &pjsua_var.log_cfg, cfg); 
     209 
     210    /* Redirect log function to ours */ 
     211    pj_log_set_log_func( &log_writer ); 
     212 
     213    /* Close existing file, if any */ 
     214    if (pjsua_var.log_file) { 
     215        pj_file_close(pjsua_var.log_file); 
     216        pjsua_var.log_file = NULL; 
     217    } 
     218 
     219    /* If output log file is desired, create the file: */ 
     220    if (pjsua_var.log_cfg.log_filename.slen) { 
     221 
     222        status = pj_file_open(pjsua_var.pool,  
     223                              pjsua_var.log_cfg.log_filename.ptr, 
     224                              PJ_O_WRONLY,  
     225                              &pjsua_var.log_file); 
     226 
    308227        if (status != PJ_SUCCESS) { 
    309             pjsua_perror(THIS_FILE, "STUN resolve error", status); 
    310             pj_sock_close(sock); 
     228            pjsua_perror(THIS_FILE, "Error creating log file", status); 
    311229            return status; 
    312230        } 
    313  
    314     } else { 
    315  
    316         const pj_str_t *hostname = pj_gethostname(); 
    317         struct pj_hostent he; 
    318  
    319         status = pj_gethostbyname(hostname, &he); 
    320         if (status != PJ_SUCCESS) { 
    321             pjsua_perror(THIS_FILE, "Unable to resolve local host", status); 
    322             pj_sock_close(sock); 
    323             return status; 
    324         } 
    325  
    326         pj_memset(p_pub_addr, 0, sizeof(pj_sockaddr_in)); 
    327         p_pub_addr->sin_family = PJ_AF_INET; 
    328         p_pub_addr->sin_port = pj_htons((pj_uint16_t)port); 
    329         p_pub_addr->sin_addr = *(pj_in_addr*)he.h_addr; 
    330     } 
    331  
    332     *p_sock = sock; 
     231    } 
     232 
     233    /* Unregister msg logging if it's previously registered */ 
     234    if (pjsua_msg_logger.id >= 0) { 
     235        pjsip_endpt_unregister_module(pjsua_var.endpt, &pjsua_msg_logger); 
     236        pjsua_msg_logger.id = -1; 
     237    } 
     238 
     239    /* Enable SIP message logging */ 
     240    if (pjsua_var.log_cfg.msg_logging) 
     241        pjsip_endpt_register_module(pjsua_var.endpt, &pjsua_msg_logger); 
     242 
     243 
    333244    return PJ_SUCCESS; 
    334245} 
    335246 
    336247 
    337 /*  
    338  * Create RTP and RTCP socket pair, and possibly resolve their public 
    339  * address via STUN. 
    340  */ 
    341 static pj_status_t create_rtp_rtcp_sock(pjmedia_sock_info *skinfo) 
    342 { 
    343     enum {  
    344         RTP_RETRY = 100 
    345     }; 
    346     int i; 
    347     static pj_uint16_t rtp_port; 
    348     pj_sockaddr_in mapped_addr[2]; 
    349     pj_status_t status = PJ_SUCCESS; 
    350     pj_sock_t sock[2]; 
    351  
    352     if (rtp_port == 0) 
    353         rtp_port = (pj_uint16_t)pjsua.config.start_rtp_port; 
    354  
    355     for (i=0; i<2; ++i) 
    356         sock[i] = PJ_INVALID_SOCKET; 
    357  
    358  
    359     /* Loop retry to bind RTP and RTCP sockets. */ 
    360     for (i=0; i<RTP_RETRY; ++i, rtp_port += 2) { 
    361  
    362         /* Create and bind RTP socket. */ 
    363         status = pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, &sock[0]); 
    364         if (status != PJ_SUCCESS) { 
    365             pjsua_perror(THIS_FILE, "socket() error", status); 
    366             return status; 
    367         } 
    368  
    369         status = pj_sock_bind_in(sock[0], 0, rtp_port); 
    370         if (status != PJ_SUCCESS) { 
    371             pj_sock_close(sock[0]);  
    372             sock[0] = PJ_INVALID_SOCKET; 
    373             continue; 
    374         } 
    375  
    376         /* Create and bind RTCP socket. */ 
    377         status = pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, &sock[1]); 
    378         if (status != PJ_SUCCESS) { 
    379             pjsua_perror(THIS_FILE, "socket() error", status); 
    380             pj_sock_close(sock[0]); 
    381             return status; 
    382         } 
    383  
    384         status = pj_sock_bind_in(sock[1], 0, (pj_uint16_t)(rtp_port+1)); 
    385         if (status != PJ_SUCCESS) { 
    386             pj_sock_close(sock[0]);  
    387             sock[0] = PJ_INVALID_SOCKET; 
    388  
    389             pj_sock_close(sock[1]);  
    390             sock[1] = PJ_INVALID_SOCKET; 
    391             continue; 
    392         } 
    393  
    394         /* 
    395          * If we're configured to use STUN, then find out the mapped address, 
    396          * and make sure that the mapped RTCP port is adjacent with the RTP. 
    397          */ 
    398         if (pjsua_has_stun()) { 
    399             status=pj_stun_get_mapped_addr(&pjsua.cp.factory, 2, sock, 
    400                                            &pjsua.config.stun_srv1,  
    401                                            pjsua.config.stun_port1, 
    402                                            &pjsua.config.stun_srv2,  
    403                                            pjsua.config.stun_port2, 
    404                                            mapped_addr); 
    405             if (status != PJ_SUCCESS) { 
    406                 pjsua_perror(THIS_FILE, "STUN resolve error", status); 
    407                 goto on_error; 
    408             } 
    409  
    410             if (pj_ntohs(mapped_addr[1].sin_port) ==  
    411                 pj_ntohs(mapped_addr[0].sin_port)+1) 
    412             { 
    413                 /* Success! */ 
    414                 break; 
    415             } 
    416  
    417             pj_sock_close(sock[0]);  
    418             sock[0] = PJ_INVALID_SOCKET; 
    419  
    420             pj_sock_close(sock[1]);  
    421             sock[1] = PJ_INVALID_SOCKET; 
    422  
    423         } else { 
    424             const pj_str_t *hostname; 
    425             pj_sockaddr_in addr; 
    426  
    427             /* Get local IP address. */ 
    428             hostname = pj_gethostname(); 
    429  
    430             pj_memset( &addr, 0, sizeof(addr)); 
    431             addr.sin_family = PJ_AF_INET; 
    432             status = pj_sockaddr_in_set_str_addr( &addr, hostname); 
    433             if (status != PJ_SUCCESS) { 
    434                 pjsua_perror(THIS_FILE, "Unresolvable local hostname",  
    435                              status); 
    436                 goto on_error; 
    437             } 
    438  
    439             for (i=0; i<2; ++i) 
    440                 pj_memcpy(&mapped_addr[i], &addr, sizeof(addr)); 
    441  
    442             mapped_addr[0].sin_port=pj_htons((pj_uint16_t)rtp_port); 
    443             mapped_addr[1].sin_port=pj_htons((pj_uint16_t)(rtp_port+1)); 
    444             break; 
    445         } 
    446     } 
    447  
    448     if (sock[0] == PJ_INVALID_SOCKET) { 
    449         PJ_LOG(1,(THIS_FILE,  
    450                   "Unable to find appropriate RTP/RTCP ports combination")); 
    451         goto on_error; 
    452     } 
    453  
    454  
    455     skinfo->rtp_sock = sock[0]; 
    456     pj_memcpy(&skinfo->rtp_addr_name,  
    457               &mapped_addr[0], sizeof(pj_sockaddr_in)); 
    458  
    459     skinfo->rtcp_sock = sock[1]; 
    460     pj_memcpy(&skinfo->rtcp_addr_name,  
    461               &mapped_addr[1], sizeof(pj_sockaddr_in)); 
    462  
    463     PJ_LOG(4,(THIS_FILE, "RTP socket reachable at %s:%d", 
    464               pj_inet_ntoa(skinfo->rtp_addr_name.sin_addr),  
    465               pj_ntohs(skinfo->rtp_addr_name.sin_port))); 
    466     PJ_LOG(4,(THIS_FILE, "RTCP socket reachable at %s:%d", 
    467               pj_inet_ntoa(skinfo->rtcp_addr_name.sin_addr),  
    468               pj_ntohs(skinfo->rtcp_addr_name.sin_port))); 
    469  
    470     rtp_port += 2; 
     248/***************************************************************************** 
     249 * PJSUA Base API. 
     250 */ 
     251 
     252/* Worker thread function. */ 
     253static int worker_thread(void *arg) 
     254{ 
     255    enum { TIMEOUT = 10 }; 
     256 
     257    PJ_UNUSED_ARG(arg); 
     258 
     259    while (!pjsua_var.thread_quit_flag) { 
     260        int count; 
     261 
     262        count = pjsua_handle_events(TIMEOUT); 
     263        if (count < 0) 
     264            pj_thread_sleep(TIMEOUT); 
     265    } 
     266 
     267    return 0; 
     268} 
     269 
     270 
     271/* 
     272 * Instantiate pjsua application. 
     273 */ 
     274PJ_DEF(pj_status_t) pjsua_create(void) 
     275{ 
     276    pj_status_t status; 
     277 
     278    /* Init pjsua data */ 
     279    init_data(); 
     280 
     281    /* Set default logging settings */ 
     282    pjsua_logging_config_default(&pjsua_var.log_cfg); 
     283 
     284    /* Init PJLIB: */ 
     285    status = pj_init(); 
     286    PJ_ASSERT_RETURN(status == PJ_SUCCESS, status); 
     287 
     288 
     289    /* Init PJLIB-UTIL: */ 
     290    status = pjlib_util_init(); 
     291    PJ_ASSERT_RETURN(status == PJ_SUCCESS, status); 
     292 
     293 
     294    /* Init caching pool. */ 
     295    pj_caching_pool_init(&pjsua_var.cp, &pj_pool_factory_default_policy, 0); 
     296 
     297    /* Create memory pool for application. */ 
     298    pjsua_var.pool = pjsua_pool_create("pjsua", 4000, 4000); 
     299     
     300    PJ_ASSERT_RETURN(pjsua_var.pool, PJ_ENOMEM); 
     301 
     302    /* Create mutex */ 
     303    status = pj_mutex_create_recursive(pjsua_var.pool, "pjsua",  
     304                                       &pjsua_var.mutex); 
     305    if (status != PJ_SUCCESS) { 
     306        pjsua_perror(THIS_FILE, "Unable to create mutex", status); 
     307        return status; 
     308    } 
     309 
     310    /* Must create SIP endpoint to initialize SIP parser. The parser 
     311     * is needed for example when application needs to call pjsua_verify_url(). 
     312     */ 
     313    status = pjsip_endpt_create(&pjsua_var.cp.factory,  
     314                                pj_gethostname()->ptr,  
     315                                &pjsua_var.endpt); 
     316    PJ_ASSERT_RETURN(status == PJ_SUCCESS, status); 
     317 
     318 
    471319    return PJ_SUCCESS; 
    472  
    473 on_error: 
    474     for (i=0; i<2; ++i) { 
    475         if (sock[i] != PJ_INVALID_SOCKET) 
    476             pj_sock_close(sock[i]); 
    477     } 
    478     return status; 
    479 } 
    480  
    481  
    482  
    483 /** 
    484  * Create pjsua application. 
    485  * This initializes pjlib/pjlib-util, and creates memory pool factory to 
    486  * be used by application. 
    487  */ 
    488 PJ_DEF(pj_status_t) pjsua_create(void) 
    489 { 
     320} 
     321 
     322 
     323/* 
     324 * Initialize pjsua with the specified settings. All the settings are  
     325 * optional, and the default values will be used when the config is not 
     326 * specified. 
     327 */ 
     328PJ_DEF(pj_status_t) pjsua_init( const pjsua_config *ua_cfg, 
     329                                const pjsua_logging_config *log_cfg, 
     330                                const pjsua_media_config *media_cfg) 
     331{ 
     332    pjsua_config         default_cfg; 
     333    pjsua_media_config   default_media_cfg; 
    490334    pj_status_t status; 
    491335 
    492     /* Init PJLIB: */ 
    493  
    494     status = pj_init(); 
    495     if (status != PJ_SUCCESS) { 
    496         pjsua_perror(THIS_FILE, "pj_init() error", status); 
    497         return status; 
    498     } 
    499  
    500     /* Init PJLIB-UTIL: */ 
    501  
    502     status = pjlib_util_init(); 
    503     if (status != PJ_SUCCESS) { 
    504         pjsua_perror(THIS_FILE, "pjlib_util_init() error", status); 
    505         return status; 
    506     } 
    507  
    508     /* Init memory pool: */ 
    509  
    510     /* Init caching pool. */ 
    511     pj_caching_pool_init(&pjsua.cp, &pj_pool_factory_default_policy, 0); 
    512  
    513     /* Create memory pool for application. */ 
    514     pjsua.pool = pj_pool_create(&pjsua.cp.factory, "pjsua", 4000, 4000, NULL); 
    515  
    516     /* Must create endpoint to initialize SIP parser. */ 
    517     /* Create global endpoint: */ 
    518  
    519     status = pjsip_endpt_create(&pjsua.cp.factory,  
    520                                 pj_gethostname()->ptr,  
    521                                 &pjsua.endpt); 
    522     if (status != PJ_SUCCESS) { 
    523         pjsua_perror(THIS_FILE, "Unable to create SIP endpoint", status); 
    524         return status; 
    525     } 
    526  
    527     /* Must create media endpoint too */ 
    528     status = pjmedia_endpt_create(&pjsua.cp.factory,  
    529                                   pjsua.config.media_has_ioqueue? NULL : 
    530                                        pjsip_endpt_get_ioqueue(pjsua.endpt),  
    531                                   pjsua.config.media_thread_cnt, 
    532                                   &pjsua.med_endpt); 
    533     if (status != PJ_SUCCESS) { 
    534         pjsua_perror(THIS_FILE,  
    535                      "Media stack initialization has returned error",  
    536                      status); 
    537         return status; 
    538     } 
    539  
    540  
    541     return PJ_SUCCESS; 
    542 } 
    543  
    544  
    545  
    546 /* 
    547  * Init media. 
    548  */ 
    549 static pj_status_t init_media(void) 
    550 { 
    551     int i; 
    552     unsigned options; 
    553     pj_str_t codec_id; 
    554     pj_status_t status; 
    555  
    556     /* Register all codecs */ 
    557 #if PJMEDIA_HAS_SPEEX_CODEC 
    558     /* Register speex. */ 
    559     status = pjmedia_codec_speex_init(pjsua.med_endpt,  
    560                                       PJMEDIA_SPEEX_NO_UWB, 
    561                                       pjsua.config.quality,  
    562                                       pjsua.config.complexity ); 
    563     if (status != PJ_SUCCESS) { 
    564         pjsua_perror(THIS_FILE, "Error initializing Speex codec", 
    565                      status); 
    566         return status; 
    567     } 
    568  
    569     /* Set "speex/16000/1" to have highest priority */ 
    570     codec_id = pj_str("speex/16000/1"); 
    571     pjmedia_codec_mgr_set_codec_priority(  
    572         pjmedia_endpt_get_codec_mgr(pjsua.med_endpt), 
    573         &codec_id,  
    574         PJMEDIA_CODEC_PRIO_HIGHEST); 
    575  
    576 #endif /* PJMEDIA_HAS_SPEEX_CODEC */ 
    577  
    578 #if PJMEDIA_HAS_GSM_CODEC 
    579     /* Register GSM */ 
    580     status = pjmedia_codec_gsm_init(pjsua.med_endpt); 
    581     if (status != PJ_SUCCESS) { 
    582         pjsua_perror(THIS_FILE, "Error initializing GSM codec", 
    583                      status); 
    584         return status; 
    585     } 
    586 #endif /* PJMEDIA_HAS_GSM_CODEC */ 
    587  
    588 #if PJMEDIA_HAS_G711_CODEC 
    589     /* Register PCMA and PCMU */ 
    590     status = pjmedia_codec_g711_init(pjsua.med_endpt); 
    591     if (status != PJ_SUCCESS) { 
    592         pjsua_perror(THIS_FILE, "Error initializing G711 codec", 
    593                      status); 
    594         return status; 
    595     } 
    596 #endif  /* PJMEDIA_HAS_G711_CODEC */ 
    597  
    598 #if PJMEDIA_HAS_L16_CODEC 
    599     /* Register L16 family codecs, but disable all */ 
    600     status = pjmedia_codec_l16_init(pjsua.med_endpt, 0); 
    601     if (status != PJ_SUCCESS) { 
    602         pjsua_perror(THIS_FILE, "Error initializing L16 codecs", 
    603                      status); 
    604         return status; 
    605     } 
    606  
    607     /* Disable ALL L16 codecs */ 
    608     codec_id = pj_str("L16"); 
    609     pjmedia_codec_mgr_set_codec_priority(  
    610         pjmedia_endpt_get_codec_mgr(pjsua.med_endpt), 
    611         &codec_id,  
    612         PJMEDIA_CODEC_PRIO_DISABLED); 
    613  
    614 #endif  /* PJMEDIA_HAS_L16_CODEC */ 
    615  
    616  
    617     /* Enable those codecs that user put with "--add-codec", and move 
    618      * the priority to top 
    619      */ 
    620     for (i=0; i<(int)pjsua.config.codec_cnt; ++i) { 
    621         pjmedia_codec_mgr_set_codec_priority(  
    622             pjmedia_endpt_get_codec_mgr(pjsua.med_endpt), 
    623             &pjsua.config.codec_arg[i],  
    624             PJMEDIA_CODEC_PRIO_HIGHEST); 
    625     } 
    626  
    627  
    628     /* Init options for conference bridge. */ 
    629     options = PJMEDIA_CONF_NO_DEVICE; 
    630  
    631     /* Calculate maximum number of ports, if it's not specified */ 
    632     if (pjsua.config.conf_ports == 0) { 
    633         pjsua.config.conf_ports = 3 * pjsua.config.max_calls; 
    634     } 
    635  
    636     /* Init conference bridge. */ 
    637     pjsua.clock_rate = pjsua.config.clock_rate ? pjsua.config.clock_rate : 16000; 
    638     pjsua.samples_per_frame = pjsua.clock_rate * 10 / 1000; 
    639     status = pjmedia_conf_create(pjsua.pool,  
    640                                  pjsua.config.conf_ports,  
    641                                  pjsua.clock_rate,  
    642                                  1, /* mono */ 
    643                                  pjsua.samples_per_frame,  
    644                                  16,  
    645                                  options, 
    646                                  &pjsua.mconf); 
    647     if (status != PJ_SUCCESS) { 
    648         pjsua_perror(THIS_FILE,  
    649                      "Media stack initialization has returned error",  
    650                      status); 
    651         return status; 
    652     } 
    653  
    654     if (pjsua.config.null_audio == PJ_FALSE) { 
    655         pjmedia_port *conf_port; 
    656  
    657         /* Create sound device port */ 
    658         status = pjmedia_snd_port_create(pjsua.pool,  
    659                                          pjsua.config.snd_capture_id, 
    660                                          pjsua.config.snd_player_id,  
    661                                          pjsua.clock_rate, 1 /* mono */, 
    662                                          pjsua.samples_per_frame, 16, 
    663                                          0, &pjsua.snd_port); 
    664         if (status != PJ_SUCCESS) { 
    665             pjsua_perror(THIS_FILE, "Unable to create sound device", status); 
    666             return status; 
    667         } 
    668  
    669         /* Get the port interface of the conference bridge */ 
    670         conf_port = pjmedia_conf_get_master_port(pjsua.mconf); 
    671  
    672         /* Connect conference port interface to sound port */ 
    673         pjmedia_snd_port_connect( pjsua.snd_port, conf_port); 
    674  
    675     } else { 
    676         pjmedia_port *null_port, *conf_port; 
    677  
    678         /* Create NULL port */ 
    679         status = pjmedia_null_port_create(pjsua.pool, pjsua.clock_rate, 
    680                                           1, pjsua.samples_per_frame, 16, 
    681                                           &null_port); 
    682         if (status != PJ_SUCCESS) { 
    683             pjsua_perror(THIS_FILE, "Unable to create NULL port", status); 
    684             return status; 
    685         } 
    686  
    687         /* Get the port interface of the conference bridge */ 
    688         conf_port = pjmedia_conf_get_master_port(pjsua.mconf); 
    689  
    690         /* Create master port to control conference bridge's clock */ 
    691         status = pjmedia_master_port_create(pjsua.pool, null_port, conf_port, 
    692                                             0, &pjsua.master_port); 
    693         if (status != PJ_SUCCESS) { 
    694             pjsua_perror(THIS_FILE, "Unable to create master port", status); 
    695             return status; 
    696         } 
    697     } 
    698  
    699     /* Create WAV file player if required: */ 
    700  
    701     if (pjsua.config.wav_file.slen) { 
    702  
    703         status = pjsua_player_create(&pjsua.config.wav_file, NULL); 
    704         if (status != PJ_SUCCESS) { 
    705             pjsua_perror(THIS_FILE, "Unable to create file player",  
    706                          status); 
    707             return status; 
    708         } 
    709     } 
    710  
    711  
    712     return PJ_SUCCESS; 
    713 } 
    714  
    715  
    716 /* 
    717  * Copy account configuration. 
    718  */ 
    719 static void copy_acc_config(pj_pool_t *pool, 
    720                             pjsua_acc_config *dst_acc, 
    721                             const pjsua_acc_config *src_acc) 
    722 { 
    723     unsigned j; 
    724  
    725     pj_memcpy(dst_acc, src_acc, sizeof(pjsua_acc_config)); 
    726  
    727     pj_strdup_with_null(pool, &dst_acc->id, &src_acc->id); 
    728     pj_strdup_with_null(pool, &dst_acc->reg_uri, &src_acc->reg_uri); 
    729     pj_strdup_with_null(pool, &dst_acc->contact, &src_acc->contact); 
    730     pj_strdup_with_null(pool, &dst_acc->proxy, &src_acc->proxy); 
    731  
    732     for (j=0; j<src_acc->cred_count; ++j) { 
    733         pj_strdup_with_null(pool, &dst_acc->cred_info[j].realm,  
    734                             &src_acc->cred_info[j].realm); 
    735         pj_strdup_with_null(pool, &dst_acc->cred_info[j].scheme,  
    736                             &src_acc->cred_info[j].scheme); 
    737         pj_strdup_with_null(pool, &dst_acc->cred_info[j].username,  
    738                             &src_acc->cred_info[j].username); 
    739         pj_strdup_with_null(pool, &dst_acc->cred_info[j].data,  
    740                             &src_acc->cred_info[j].data); 
    741     } 
    742 } 
    743  
    744  
    745 /* 
    746  * Copy configuration. 
    747  */ 
    748 void pjsua_copy_config( pj_pool_t *pool, pjsua_config *dst,  
    749                         const pjsua_config *src) 
    750 { 
    751     unsigned i; 
    752  
    753     /* Plain memcpy */ 
    754     pj_memcpy(dst, src, sizeof(pjsua_config)); 
    755  
    756     /* Duplicate strings */ 
    757     pj_strdup_with_null(pool, &dst->sip_host, &src->sip_host); 
    758     pj_strdup_with_null(pool, &dst->stun_srv1, &src->stun_srv1); 
    759     pj_strdup_with_null(pool, &dst->stun_srv2, &src->stun_srv2); 
    760     pj_strdup_with_null(pool, &dst->wav_file, &src->wav_file); 
    761      
    762     for (i=0; i<src->codec_cnt; ++i) { 
    763         pj_strdup_with_null(pool, &dst->codec_arg[i], &src->codec_arg[i]); 
    764     } 
    765  
    766     pj_strdup_with_null(pool, &dst->outbound_proxy, &src->outbound_proxy); 
    767     //pj_strdup_with_null(pool, &dst->uri_to_call, &src->uri_to_call); 
    768  
    769     for (i=0; i<src->acc_cnt; ++i) { 
    770         pjsua_acc_config *dst_acc = &dst->acc_config[i]; 
    771         const pjsua_acc_config *src_acc = &src->acc_config[i]; 
    772         copy_acc_config(pool, dst_acc, src_acc); 
    773     } 
    774  
    775     pj_strdup_with_null(pool, &dst->log_filename, &src->log_filename); 
    776  
    777     for (i=0; i<src->buddy_cnt; ++i) { 
    778         pj_strdup_with_null(pool, &dst->buddy_uri[i], &src->buddy_uri[i]); 
    779     } 
    780 } 
    781  
    782  
    783 /***************************************************************************** 
    784  * Console application custom logging: 
    785  */ 
    786  
    787  
    788 static void log_writer(int level, const char *buffer, int len) 
    789 { 
    790     /* Write to both stdout and file. */ 
    791  
    792     if (level <= (int)pjsua.config.app_log_level) 
    793         pj_log_write(level, buffer, len); 
    794  
    795     if (pjsua.log_file) { 
    796         fwrite(buffer, len, 1, pjsua.log_file); 
    797         fflush(pjsua.log_file); 
    798     } 
    799 } 
    800  
    801  
    802 static pj_status_t logging_init() 
    803 { 
    804     /* Redirect log function to ours */ 
    805  
    806     pj_log_set_log_func( &log_writer ); 
    807  
    808     /* If output log file is desired, create the file: */ 
    809  
    810     if (pjsua.config.log_filename.slen) { 
    811         pjsua.log_file = fopen(pjsua.config.log_filename.ptr, "wt"); 
    812         if (pjsua.log_file == NULL) { 
    813             PJ_LOG(1,(THIS_FILE, "Unable to open log file %s",  
    814                       pjsua.config.log_filename.ptr));    
    815             return -1; 
    816         } 
    817     } 
    818  
    819     /* Enable SIP message logging */ 
    820     if (pjsua.config.msg_logging) 
    821         pjsip_endpt_register_module(pjsua.endpt, &pjsua_msg_logger); 
    822  
    823     return PJ_SUCCESS; 
    824 } 
    825  
    826  
    827 static void logging_shutdown(void) 
    828 { 
    829     /* Close logging file, if any: */ 
    830  
    831     if (pjsua.log_file) { 
    832         fclose(pjsua.log_file); 
    833         pjsua.log_file = NULL; 
    834     } 
    835 } 
    836  
    837  
    838 /* 
    839  * Initialize pjsua application. 
    840  * This will initialize all libraries, create endpoint instance, and register 
    841  * pjsip modules. 
    842  */ 
    843 PJ_DECL(pj_status_t) pjsua_init(const pjsua_config *cfg, 
    844                                 const pjsua_callback *cb) 
    845 { 
    846     char errmsg[80]; 
    847     unsigned i; 
    848     pj_status_t status; 
    849  
    850  
    851     /* Init accounts: */ 
    852     for (i=0; i<PJ_ARRAY_SIZE(pjsua.acc); ++i) { 
    853         pjsua.acc[i].index = i; 
    854         pjsua.acc[i].online_status = PJ_TRUE; 
    855         pj_list_init(&pjsua.acc[i].route_set); 
    856         pj_list_init(&pjsua.acc[i].pres_srv_list); 
    857     } 
    858  
    859     /* Init call array: */ 
    860     for (i=0; i<PJ_ARRAY_SIZE(pjsua.calls); ++i) { 
    861         pjsua.calls[i].index = i; 
    862         pjsua.calls[i].refresh_tm._timer_id = -1; 
    863         pjsua.calls[i].hangup_tm._timer_id = -1; 
    864         pjsua.calls[i].conf_slot = 0; 
    865     } 
    866  
    867     /* Init buddies array */ 
    868     for (i=0; i<PJ_ARRAY_SIZE(pjsua.buddies); ++i) { 
    869         pjsua.buddies[i].index = i; 
    870     } 
    871  
    872     /* Copy configuration */ 
    873     pjsua_copy_config(pjsua.pool, &pjsua.config, cfg); 
    874  
    875     /* Copy callback */ 
    876     pj_memcpy(&pjsua.cb, cb, sizeof(pjsua_callback)); 
    877  
    878     /* Test configuration */ 
    879     if (pjsua_test_config(&pjsua.config, errmsg, sizeof(errmsg))) { 
    880         PJ_LOG(1,(THIS_FILE, "Error in configuration: %s", errmsg)); 
    881         status = -1; 
    882         goto on_error; 
    883     } 
    884  
    885  
    886     /* Init PJLIB logging: */ 
    887  
    888     pj_log_set_level(pjsua.config.log_level); 
    889     pj_log_set_decor(pjsua.config.log_decor); 
    890  
    891     status = logging_init(); 
    892     if (status != PJ_SUCCESS) 
    893         goto on_error; 
    894  
    895  
    896     /* Create SIP UDP socket */ 
    897     if (pjsua.config.udp_port) { 
    898  
    899         status = create_sip_udp_sock( pjsua.config.udp_port, 
    900                                       &pjsua.sip_sock, 
    901                                       &pjsua.sip_sock_name); 
    902         if (status != PJ_SUCCESS) 
    903             goto on_error; 
    904      
    905         pj_strdup2_with_null(pjsua.pool, &pjsua.config.sip_host, 
    906                              pj_inet_ntoa(pjsua.sip_sock_name.sin_addr)); 
    907         pjsua.config.sip_port = pj_ntohs(pjsua.sip_sock_name.sin_port); 
    908  
    909     } else { 
    910  
    911         /* Check that SIP host and port is configured */ 
    912         if (cfg->sip_host.slen == 0 || cfg->sip_port == 0) { 
    913             PJ_LOG(1,(THIS_FILE,  
    914                       "Error: sip_host and sip_port must be specified")); 
    915             status = PJ_EINVAL; 
    916             goto on_error; 
    917         } 
    918  
    919         pjsua.sip_sock = PJ_INVALID_SOCKET; 
    920     } 
    921  
    922  
    923     /* Init media endpoint */ 
    924     status = init_media(); 
    925     if (status != PJ_SUCCESS) 
    926         goto on_error; 
    927  
    928  
    929     /* Init RTP sockets, only when UDP transport is enabled */ 
    930     for (i=0; pjsua.config.start_rtp_port && i<pjsua.config.max_calls; ++i) { 
    931         status = create_rtp_rtcp_sock(&pjsua.calls[i].skinfo); 
    932         if (status != PJ_SUCCESS) { 
    933             unsigned j; 
    934             for (j=0; j<i; ++j) { 
    935                 if (pjsua.calls[i].med_tp) 
    936                     pjsua.calls[i].med_tp->op->destroy(pjsua.calls[i].med_tp); 
    937             } 
    938             goto on_error; 
    939         } 
    940         status = pjmedia_transport_udp_attach(pjsua.med_endpt, NULL, 
    941                                               &pjsua.calls[i].skinfo, 0, 
    942                                               &pjsua.calls[i].med_tp); 
    943     } 
    944  
    945     /* Init PJSIP : */ 
     336 
     337    /* Create default configurations when the config is not supplied */ 
     338 
     339    if (ua_cfg == NULL) { 
     340        pjsua_config_default(&default_cfg); 
     341        ua_cfg = &default_cfg; 
     342    } 
     343 
     344    if (media_cfg == NULL) { 
     345        pjsua_media_config_default(&default_media_cfg); 
     346        media_cfg = &default_media_cfg; 
     347    } 
     348 
     349    /* Initialize logging first so that info/errors can be captured */ 
     350    if (log_cfg) { 
     351        status = pjsua_reconfigure_logging(log_cfg); 
     352        PJ_ASSERT_RETURN(status == PJ_SUCCESS, status); 
     353    } 
     354 
     355    /* Init SIP UA: */ 
    946356 
    947357    /* Initialize transaction layer: */ 
    948  
    949     status = pjsip_tsx_layer_init_module(pjsua.endpt); 
    950     if (status != PJ_SUCCESS) { 
    951         pjsua_perror(THIS_FILE, "Transaction layer initialization error",  
    952                      status); 
    953         goto on_error; 
    954     } 
     358    status = pjsip_tsx_layer_init_module(pjsua_var.endpt); 
     359    PJ_ASSERT_RETURN(status == PJ_SUCCESS, status); 
     360 
    955361 
    956362    /* Initialize UA layer module: */ 
    957  
    958     status = pjsip_ua_init_module( pjsua.endpt, NULL ); 
    959     if (status != PJ_SUCCESS) { 
    960         pjsua_perror(THIS_FILE, "UA layer initialization error", status); 
    961         goto on_error; 
    962     } 
    963  
    964     /* Initialize and register pjsua's application module: */ 
    965  
     363    status = pjsip_ua_init_module( pjsua_var.endpt, NULL ); 
     364    PJ_ASSERT_RETURN(status == PJ_SUCCESS, status); 
     365 
     366 
     367    /* Initialize and register PJSUA application module. */ 
    966368    { 
    967         pjsip_module my_mod =  
     369        const pjsip_module mod_initializer =  
    968370        { 
    969371        NULL, NULL,                 /* prev, next.                      */ 
     
    982384        }; 
    983385 
    984         pjsua.mod = my_mod; 
    985  
    986         status = pjsip_endpt_register_module(pjsua.endpt, &pjsua.mod); 
    987         if (status != PJ_SUCCESS) { 
    988             pjsua_perror(THIS_FILE, "Unable to register pjsua module",  
    989                          status); 
    990             goto on_error; 
     386        pjsua_var.mod = mod_initializer; 
     387 
     388        status = pjsip_endpt_register_module(pjsua_var.endpt, &pjsua_var.mod); 
     389        PJ_ASSERT_RETURN(status == PJ_SUCCESS, status); 
     390    } 
     391 
     392     
     393 
     394    /* Initialize PJSUA call subsystem: */ 
     395    status = pjsua_call_subsys_init(ua_cfg); 
     396    if (status != PJ_SUCCESS) 
     397        goto on_error; 
     398 
     399 
     400    /* Initialize PJSUA media subsystem */ 
     401    status = pjsua_media_subsys_init(media_cfg); 
     402    if (status != PJ_SUCCESS) 
     403        goto on_error; 
     404 
     405 
     406    /* Init core SIMPLE module : */ 
     407    status = pjsip_evsub_init_module(pjsua_var.endpt); 
     408    PJ_ASSERT_RETURN(status == PJ_SUCCESS, status); 
     409 
     410 
     411    /* Init presence module: */ 
     412    status = pjsip_pres_init_module( pjsua_var.endpt, pjsip_evsub_instance()); 
     413    PJ_ASSERT_RETURN(status == PJ_SUCCESS, status); 
     414 
     415 
     416    /* Init xfer/REFER module */ 
     417    status = pjsip_xfer_init_module( pjsua_var.endpt ); 
     418    PJ_ASSERT_RETURN(status == PJ_SUCCESS, status); 
     419 
     420    /* Init pjsua presence handler: */ 
     421    status = pjsua_pres_init(); 
     422    if (status != PJ_SUCCESS) 
     423        goto on_error; 
     424 
     425    /* Init out-of-dialog MESSAGE request handler. */ 
     426    status = pjsua_im_init(); 
     427    if (status != PJ_SUCCESS) 
     428        goto on_error; 
     429 
     430    /* Start worker thread if needed. */ 
     431    if (pjsua_var.ua_cfg.thread_cnt) { 
     432        unsigned i; 
     433 
     434        if (pjsua_var.ua_cfg.thread_cnt > PJ_ARRAY_SIZE(pjsua_var.thread)) 
     435            pjsua_var.ua_cfg.thread_cnt = PJ_ARRAY_SIZE(pjsua_var.thread); 
     436 
     437        for (i=0; i<pjsua_var.ua_cfg.thread_cnt; ++i) { 
     438            status = pj_thread_create(pjsua_var.pool, "pjsua", &worker_thread, 
     439                                      NULL, 0, 0, &pjsua_var.thread[i]); 
     440            if (status != PJ_SUCCESS) 
     441                goto on_error; 
    991442        } 
    992443    } 
    993444 
    994     /* Initialize invite session module: */ 
    995  
    996     status = pjsua_call_init(); 
    997     if (status != PJ_SUCCESS) { 
    998         pjsua_perror(THIS_FILE, "Invite usage initialization error",  
    999                      status); 
    1000         goto on_error; 
    1001     } 
    1002  
    1003     /* Init core SIMPLE module : */ 
    1004  
    1005     pjsip_evsub_init_module(pjsua.endpt); 
    1006  
    1007     /* Init presence module: */ 
    1008  
    1009     pjsip_pres_init_module( pjsua.endpt, pjsip_evsub_instance()); 
    1010  
    1011     /* Init xfer/REFER module */ 
    1012  
    1013     pjsip_xfer_init_module( pjsua.endpt ); 
    1014  
    1015     /* Init pjsua presence handler: */ 
    1016  
    1017     pjsua_pres_init(); 
    1018  
    1019     /* Init out-of-dialog MESSAGE request handler. */ 
    1020  
    1021     pjsua_im_init(); 
    1022  
    1023  
    1024     /* Done. */ 
     445    /* Done! */ 
     446 
     447    PJ_LOG(3,(THIS_FILE, "pjsua version %s for %s initialized",  
     448                         PJ_VERSION, PJ_OS_NAME)); 
     449 
    1025450    return PJ_SUCCESS; 
    1026451 
     
    1031456 
    1032457 
    1033 /* 
    1034  * Find account for incoming request. 
    1035  */ 
    1036 PJ_DEF(pjsua_acc_id) pjsua_acc_find_for_incoming(pjsip_rx_data *rdata) 
    1037 { 
    1038     pjsip_uri *uri; 
    1039     pjsip_sip_uri *sip_uri; 
    1040     unsigned acc_index; 
    1041  
    1042     uri = rdata->msg_info.to->uri; 
    1043  
    1044     /* Just return default account if To URI is not SIP: */ 
    1045     if (!PJSIP_URI_SCHEME_IS_SIP(uri) &&  
    1046         !PJSIP_URI_SCHEME_IS_SIPS(uri))  
    1047     { 
    1048         return pjsua.default_acc; 
    1049     } 
    1050  
    1051  
    1052     sip_uri = (pjsip_sip_uri*)pjsip_uri_get_uri(uri); 
    1053  
    1054     /* Find account which has matching username and domain. */ 
    1055     for (acc_index=0; acc_index < pjsua.config.acc_cnt; ++acc_index) { 
    1056  
    1057         pjsua_acc *acc = &pjsua.acc[acc_index]; 
    1058  
    1059         if (pj_stricmp(&acc->user_part, &sip_uri->user)==0 && 
    1060             pj_stricmp(&acc->host_part, &sip_uri->host)==0)  
    1061         { 
    1062             /* Match ! */ 
    1063             return acc_index; 
    1064         } 
    1065     } 
    1066  
    1067     /* No matching, try match domain part only. */ 
    1068     for (acc_index=0; acc_index < pjsua.config.acc_cnt; ++acc_index) { 
    1069  
    1070         pjsua_acc *acc = &pjsua.acc[acc_index]; 
    1071  
    1072         if (pj_stricmp(&acc->host_part, &sip_uri->host)==0) { 
    1073             /* Match ! */ 
    1074             return acc_index; 
    1075         } 
    1076     } 
    1077  
    1078     /* Still no match, use default account */ 
    1079     return pjsua.default_acc; 
    1080 } 
    1081  
    1082  
    1083 /* 
    1084  * Find account for outgoing request. 
    1085  */ 
    1086 PJ_DEF(pjsua_acc_id) pjsua_acc_find_for_outgoing(const pj_str_t *str_url) 
    1087 { 
    1088     pj_str_t tmp; 
    1089     pjsip_uri *uri; 
    1090     pjsip_sip_uri *sip_uri; 
    1091     unsigned i; 
    1092  
    1093     pj_strdup_with_null(pjsua.pool, &tmp, str_url); 
    1094  
    1095     uri = pjsip_parse_uri(pjsua.pool, tmp.ptr, tmp.slen, 0); 
    1096     if (!uri) 
    1097         return pjsua.config.acc_cnt-1; 
    1098  
    1099     if (!PJSIP_URI_SCHEME_IS_SIP(uri) &&  
    1100         !PJSIP_URI_SCHEME_IS_SIPS(uri))  
    1101     { 
    1102         /* Return the first account with proxy */ 
    1103         for (i=0; i<PJ_ARRAY_SIZE(pjsua.acc); ++i) { 
    1104             if (!pjsua.acc[i].valid) 
    1105                 continue; 
    1106             if (pjsua.config.acc_config[i].proxy.slen) 
    1107                 break; 
    1108         } 
    1109  
    1110         if (i != PJ_ARRAY_SIZE(pjsua.acc)) 
    1111             return i; 
    1112  
    1113         /* Not found, use default account */ 
    1114         return pjsua.default_acc; 
    1115     } 
    1116  
    1117     sip_uri = pjsip_uri_get_uri(uri); 
    1118  
    1119     /* Find matching domain */ 
    1120     for (i=0; i<PJ_ARRAY_SIZE(pjsua.acc); ++i) { 
    1121         if (!pjsua.acc[i].valid) 
    1122             continue; 
    1123         if (pj_stricmp(&pjsua.acc[i].host_part, &sip_uri->host)==0) 
    1124             break; 
    1125     } 
    1126  
    1127     if (i != PJ_ARRAY_SIZE(pjsua.acc)) 
    1128         return i; 
    1129  
    1130     /* Just use default account */ 
    1131     return pjsua.default_acc; 
    1132 } 
    1133  
    1134  
    1135 /* 
    1136  * Init account 
    1137  */ 
    1138 static pj_status_t init_acc(unsigned acc_index) 
    1139 { 
    1140     pjsua_acc_config *acc_cfg = &pjsua.config.acc_config[acc_index]; 
    1141     pjsua_acc *acc = &pjsua.acc[acc_index]; 
    1142     pjsip_uri *uri; 
    1143     pjsip_sip_uri *sip_uri; 
    1144  
    1145     /* Need to parse local_uri to get the elements: */ 
    1146  
    1147     uri = pjsip_parse_uri(pjsua.pool, acc_cfg->id.ptr, 
    1148                           acc_cfg->id.slen, 0); 
    1149     if (uri == NULL) { 
    1150         pjsua_perror(THIS_FILE, "Invalid local URI",  
    1151                      PJSIP_EINVALIDURI); 
    1152         return PJSIP_EINVALIDURI; 
    1153     } 
    1154  
    1155     /* Local URI MUST be a SIP or SIPS: */ 
    1156  
    1157     if (!PJSIP_URI_SCHEME_IS_SIP(uri) &&  
    1158         !PJSIP_URI_SCHEME_IS_SIPS(uri))  
    1159     { 
    1160         pjsua_perror(THIS_FILE, "Invalid local URI",  
    1161                      PJSIP_EINVALIDSCHEME); 
    1162         return PJSIP_EINVALIDSCHEME; 
    1163     } 
    1164  
    1165  
    1166     /* Get the SIP URI object: */ 
    1167  
    1168     sip_uri = (pjsip_sip_uri*) pjsip_uri_get_uri(uri); 
    1169  
    1170     acc->user_part = sip_uri->user; 
    1171     acc->host_part = sip_uri->host; 
    1172  
    1173     /* Build Contact header */ 
    1174  
    1175     if (acc_cfg->contact.slen == 0)  { 
    1176         char contact[128]; 
    1177         const char *addr; 
    1178         int port; 
    1179         int len; 
    1180  
    1181         addr = pjsua.config.sip_host.ptr; 
    1182         port = pjsua.config.sip_port; 
    1183  
    1184         /* The local Contact is the username@ip-addr, where 
    1185          *  - username is taken from the local URI, 
    1186          *  - ip-addr in UDP transport's address name (which may have been 
    1187          *    resolved from STUN. 
    1188          */ 
    1189          
    1190         /* Build temporary contact string. */ 
    1191  
    1192         if (sip_uri->user.slen) { 
    1193  
    1194             /* With the user part. */ 
    1195             len = pj_ansi_snprintf(contact, sizeof(contact), 
    1196                               "<sip:%.*s@%s:%d>", 
    1197                               (int)sip_uri->user.slen, 
    1198                               sip_uri->user.ptr, 
    1199                               addr, port); 
    1200         } else { 
    1201  
    1202             /* Without user part */ 
    1203  
    1204             len = pj_ansi_snprintf(contact, sizeof(contact), 
    1205                               "<sip:%s:%d>", 
    1206                               addr, port); 
    1207         } 
    1208  
    1209         if (len < 1 || len >= sizeof(contact)) { 
    1210             pjsua_perror(THIS_FILE, "Invalid Contact", PJSIP_EURITOOLONG); 
    1211             return PJSIP_EURITOOLONG; 
    1212         } 
    1213  
    1214         /* Duplicate Contact uri. */ 
    1215  
    1216         pj_strdup2(pjsua.pool, &acc_cfg->contact, contact); 
    1217  
    1218     } 
    1219  
    1220  
    1221     /* Build route-set for this account */ 
    1222     if (pjsua.config.outbound_proxy.slen) { 
    1223         pj_str_t hname = { "Route", 5}; 
    1224         pjsip_route_hdr *r; 
    1225         pj_str_t tmp; 
    1226  
    1227         pj_strdup_with_null(pjsua.pool, &tmp, &pjsua.config.outbound_proxy); 
    1228         r = pjsip_parse_hdr(pjsua.pool, &hname, tmp.ptr, tmp.slen, NULL); 
    1229         pj_list_push_back(&acc->route_set, r); 
    1230     } 
    1231  
    1232     if (acc_cfg->proxy.slen) { 
    1233         pj_str_t hname = { "Route", 5}; 
    1234         pjsip_route_hdr *r; 
    1235         pj_str_t tmp; 
    1236  
    1237         pj_strdup_with_null(pjsua.pool, &tmp, &acc_cfg->proxy); 
    1238         r = pjsip_parse_hdr(pjsua.pool, &hname, tmp.ptr, tmp.slen, NULL); 
    1239         pj_list_push_back(&acc->route_set, r); 
    1240     } 
    1241  
    1242     /* Mark account as valid */ 
    1243     pjsua.acc[acc_index].valid = PJ_TRUE; 
    1244  
    1245  
    1246     return PJ_SUCCESS; 
    1247 } 
    1248  
    1249 /* 
    1250  * Add a new account. 
    1251  */ 
    1252 PJ_DEF(pj_status_t) pjsua_acc_add( const pjsua_acc_config *cfg, 
    1253                                    pjsua_acc_id *acc_index) 
    1254 { 
    1255     unsigned index; 
    1256     pj_status_t status; 
    1257  
    1258     PJ_ASSERT_RETURN(pjsua.config.acc_cnt <  
    1259                         PJ_ARRAY_SIZE(pjsua.config.acc_config), 
    1260                      PJ_ETOOMANY); 
    1261  
    1262     /* Find empty account index. */ 
    1263     for (index=0; index < PJ_ARRAY_SIZE(pjsua.acc); ++index) { 
    1264         if (pjsua.acc[index].valid == PJ_FALSE) 
    1265             break; 
    1266     } 
    1267  
    1268     /* Expect to find a slot */ 
    1269     PJ_ASSERT_RETURN(index < PJ_ARRAY_SIZE(pjsua.acc), PJ_EBUG); 
    1270  
    1271     copy_acc_config(pjsua.pool, &pjsua.config.acc_config[index], cfg); 
    1272      
    1273     status = init_acc(index); 
    1274     if (status != PJ_SUCCESS) { 
    1275         pjsua_perror(THIS_FILE, "Error adding account", status); 
    1276         return status; 
    1277     } 
    1278  
    1279     if (acc_index) 
    1280         *acc_index = index; 
    1281  
    1282     pjsua.config.acc_cnt++; 
    1283  
    1284     return PJ_SUCCESS; 
    1285 } 
    1286  
    1287  
    1288 /* 
    1289  * Delete account. 
    1290  */ 
    1291 PJ_DEF(pj_status_t) pjsua_acc_del(pjsua_acc_id acc_index) 
    1292 { 
    1293     PJ_ASSERT_RETURN(acc_index < (int)pjsua.config.acc_cnt,  
    1294                      PJ_EINVAL); 
    1295     PJ_ASSERT_RETURN(pjsua.acc[acc_index].valid, PJ_EINVALIDOP); 
    1296  
    1297     /* Delete registration */ 
    1298     if (pjsua.acc[acc_index].regc != NULL)  
    1299         pjsua_acc_set_registration(acc_index, PJ_FALSE); 
    1300  
    1301     /* Invalidate */ 
    1302     pjsua.acc[acc_index].valid = PJ_FALSE; 
    1303  
    1304     return PJ_SUCCESS; 
    1305 } 
    1306  
    1307  
    1308 /* 
    1309  * Start pjsua stack. 
    1310  * This will start the registration process, if registration is configured. 
    1311  */ 
    1312 PJ_DEF(pj_status_t) pjsua_start(void) 
    1313 { 
    1314     int i;  /* Must be signed */ 
    1315     unsigned count; 
    1316     pj_status_t status = PJ_SUCCESS; 
    1317  
    1318  
    1319     /* Add UDP transport: */ 
    1320     if (pjsua.sip_sock > 0) { 
    1321  
    1322         /* Init the published name for the transport. 
    1323          * Depending whether STUN is used, this may be the STUN mapped 
    1324          * address, or socket's bound address. 
    1325          */ 
    1326         pjsip_host_port addr_name; 
    1327  
    1328         addr_name.host = pjsua.config.sip_host; 
    1329         addr_name.port = pjsua.config.sip_port; 
    1330  
    1331         /* Create UDP transport from previously created UDP socket: */ 
    1332  
    1333         status = pjsip_udp_transport_attach( pjsua.endpt, pjsua.sip_sock, 
    1334                                              &addr_name, 1,  
    1335                                              NULL); 
    1336         if (status != PJ_SUCCESS) { 
    1337             pjsua_perror(THIS_FILE, "Unable to start UDP transport",  
    1338                          status); 
    1339             goto on_error; 
    1340         } 
    1341     } 
    1342  
    1343     /* Initialize all unused accounts with default id and contact. 
    1344      */ 
    1345     { 
    1346         char buf[80]; 
    1347         pj_str_t tmp, id; 
    1348  
    1349         tmp.ptr = buf; 
    1350         tmp.slen = pj_ansi_sprintf(tmp.ptr, "Local <sip:%s:%d>",  
    1351                                    pjsua.config.sip_host.ptr, 
    1352                                    pjsua.config.sip_port); 
    1353         pj_strdup_with_null( pjsua.pool, &id, &tmp); 
    1354  
    1355         for (i=pjsua.config.acc_cnt; i<PJ_ARRAY_SIZE(pjsua.config.acc_config); 
    1356              ++i) 
    1357         { 
    1358             pjsua_acc_config *acc_cfg =  
    1359                 &pjsua.config.acc_config[pjsua.config.acc_cnt]; 
    1360  
    1361             acc_cfg->id = id; 
    1362             acc_cfg->contact = id; 
    1363         } 
    1364     } 
    1365      
    1366  
    1367     /* Add another account as the last one.  
    1368      * This account corresponds to local endpoint, and is user-less. 
    1369      * This is also the default account. 
    1370      */ 
    1371     if (pjsua.config.acc_cnt < PJ_ARRAY_SIZE(pjsua.config.acc_config)) { 
    1372         pjsua.default_acc = pjsua.config.acc_cnt; 
    1373         pjsua.acc[pjsua.default_acc].auto_gen = 1; 
    1374         pjsua.config.acc_cnt++; 
    1375     } 
    1376  
    1377  
    1378     /* Initialize accounts: */ 
    1379     for (i=0; i<(int)pjsua.config.acc_cnt; ++i) { 
    1380         status = init_acc(i); 
    1381         if (status != PJ_SUCCESS) { 
    1382             pjsua_perror(THIS_FILE, "Error initializing account", status); 
    1383             goto on_error; 
    1384         } 
    1385     } 
    1386  
    1387  
    1388     /* Create worker thread(s), if required: */ 
    1389  
    1390     for (i=0; i<(int)pjsua.config.thread_cnt; ++i) { 
    1391         status = pj_thread_create( pjsua.pool, "pjsua", &pjsua_poll, 
    1392                                    NULL, 0, 0, &pjsua.threads[i]); 
    1393         if (status != PJ_SUCCESS) { 
    1394             pjsua.quit_flag = 1; 
    1395             for (--i; i>=0; --i) { 
    1396                 pj_thread_join(pjsua.threads[i]); 
    1397                 pj_thread_destroy(pjsua.threads[i]); 
    1398             } 
    1399             goto on_error; 
    1400         } 
    1401     } 
    1402  
    1403     /* Start registration: */ 
    1404  
    1405     /* Create client registration session: */ 
    1406     for (i=0; i<(int)pjsua.config.acc_cnt; ++i) { 
    1407         status = pjsua_regc_init(i); 
    1408         if (status != PJ_SUCCESS) 
    1409             goto on_error; 
    1410  
    1411         /* Perform registration, if required. */ 
    1412         if (pjsua.acc[i].regc) { 
    1413             pjsua_acc_set_registration(i, PJ_TRUE); 
    1414         } 
    1415     } 
    1416  
    1417  
    1418     /* Re-init buddies */ 
    1419     count = pjsua.config.buddy_cnt; 
    1420     pjsua.config.buddy_cnt = 0; 
    1421     for (i=0; i<(int)count; ++i) { 
    1422         pj_str_t uri = pjsua.config.buddy_uri[i]; 
    1423         pjsua_buddy_add(&uri, NULL); 
    1424     } 
    1425  
    1426  
    1427     /* Refresh presence */ 
    1428     pjsua_pres_refresh(); 
    1429  
    1430  
    1431     PJ_LOG(3,(THIS_FILE, "PJSUA version %s started", PJ_VERSION)); 
    1432     return PJ_SUCCESS; 
    1433  
    1434 on_error: 
    1435     pjsua_destroy(); 
    1436     return status; 
    1437 } 
    1438  
    1439  
    1440458/* Sleep with polling */ 
    1441459static void busy_sleep(unsigned msec) 
     
    1448466 
    1449467    do { 
    1450         pjsua_poll(NULL); 
     468        while (pjsua_handle_events(10) > 0) 
     469            ; 
    1451470        pj_gettimeofday(&now); 
    1452471    } while (PJ_TIME_VAL_LT(now, timeout)); 
    1453472} 
    1454473 
    1455 /** 
    1456  * Get maxinum number of conference ports. 
    1457  */ 
    1458 PJ_DEF(unsigned) pjsua_conf_max_ports(void) 
    1459 { 
    1460     return pjsua.config.conf_ports; 
    1461 } 
    1462  
    1463  
    1464 /** 
    1465  * Enum all conference port ID. 
    1466  */ 
    1467 PJ_DEF(pj_status_t) pjsua_conf_enum_port_ids( pjsua_conf_port_id id[], 
    1468                                               unsigned *count) 
    1469 { 
    1470     return pjmedia_conf_enum_ports( pjsua.mconf, (unsigned*)id, count); 
    1471 } 
    1472  
    1473  
    1474  
    1475 /** 
    1476  * Get information about the specified conference port 
    1477  */ 
    1478 PJ_DEF(pj_status_t) pjsua_conf_get_port_info( pjsua_conf_port_id id, 
    1479                                               pjsua_conf_port_info *info) 
    1480 { 
    1481     pjmedia_conf_port_info cinfo; 
    1482     unsigned i, count; 
    1483     pj_status_t status; 
    1484  
    1485     status = pjmedia_conf_get_port_info( pjsua.mconf, id, &cinfo); 
    1486     if (status != PJ_SUCCESS) 
    1487         return status; 
    1488  
    1489     pj_memset(info, 0, sizeof(*info)); 
    1490     info->slot_id = id; 
    1491     info->name = cinfo.name; 
    1492     info->clock_rate = cinfo.clock_rate; 
    1493     info->channel_count = cinfo.channel_count; 
    1494     info->samples_per_frame = cinfo.samples_per_frame; 
    1495     info->bits_per_sample = cinfo.bits_per_sample; 
    1496  
    1497     /* Build array of listeners */ 
    1498     count = pjsua.config.conf_ports; 
    1499     for (i=0; i<count; ++i) { 
    1500         if (cinfo.listener[i]) { 
    1501             info->listeners[info->listener_cnt++] = i; 
     474/* 
     475 * Destroy pjsua. 
     476 */ 
     477PJ_DEF(pj_status_t) pjsua_destroy(void) 
     478{ 
     479    int i;  /* Must be signed */ 
     480 
     481    /* Signal threads to quit: */ 
     482    pjsua_var.thread_quit_flag = 1; 
     483 
     484    /* Wait worker threads to quit: */ 
     485    for (i=0; i<(int)pjsua_var.ua_cfg.thread_cnt; ++i) { 
     486        if (pjsua_var.thread[i]) { 
     487            pj_thread_join(pjsua_var.thread[i]); 
     488            pj_thread_destroy(pjsua_var.thread[i]); 
     489            pjsua_var.thread[i] = NULL; 
    1502490        } 
    1503491    } 
    1504  
    1505     return PJ_SUCCESS; 
    1506 } 
    1507  
    1508  
    1509 /** 
    1510  * Connect conference port. 
    1511  */ 
    1512 PJ_DEF(pj_status_t) pjsua_conf_connect( pjsua_conf_port_id src_port, 
    1513                                         pjsua_conf_port_id dst_port) 
    1514 { 
    1515     return pjmedia_conf_connect_port(pjsua.mconf, src_port, dst_port, 0); 
    1516 } 
    1517  
    1518  
    1519 /** 
    1520  * Connect conference port connection. 
    1521  */ 
    1522 PJ_DEF(pj_status_t) pjsua_conf_disconnect( pjsua_conf_port_id src_port, 
    1523                                            pjsua_conf_port_id dst_port) 
    1524 { 
    1525     return pjmedia_conf_disconnect_port(pjsua.mconf, src_port, dst_port); 
    1526 } 
    1527  
    1528  
    1529  
    1530 /** 
    1531  * Create a file player. 
    1532  */ 
    1533 PJ_DEF(pj_status_t) pjsua_player_create( const pj_str_t *filename, 
    1534                                          pjsua_player_id *id) 
    1535 { 
    1536     unsigned slot; 
    1537     char path[128]; 
    1538     pjmedia_port *port; 
    1539     pj_status_t status; 
    1540  
    1541     if (pjsua.player_cnt >= PJ_ARRAY_SIZE(pjsua.player)) 
    1542         return PJ_ETOOMANY; 
    1543  
    1544     pj_memcpy(path, filename->ptr, filename->slen); 
    1545     path[filename->slen] = '\0'; 
    1546     status = pjmedia_wav_player_port_create(pjsua.pool, path, 
    1547                                             pjsua.samples_per_frame * 
    1548                                                1000 / pjsua.clock_rate, 
    1549                                             0, 0, NULL, 
    1550                                             &port); 
    1551     if (status != PJ_SUCCESS) 
    1552         return status; 
    1553  
    1554     status = pjmedia_conf_add_port(pjsua.mconf, pjsua.pool,  
    1555                                    port, filename, &slot); 
    1556     if (status != PJ_SUCCESS) { 
    1557         pjmedia_port_destroy(port); 
    1558         return status; 
    1559     } 
    1560  
    1561     pjsua.player[pjsua.player_cnt].port = port; 
    1562     pjsua.player[pjsua.player_cnt].slot = slot; 
    1563  
    1564     if (id) 
    1565         *id = pjsua.player_cnt; 
    1566  
    1567     ++pjsua.player_cnt; 
    1568  
    1569     return PJ_SUCCESS; 
    1570 } 
    1571  
    1572  
    1573 /** 
    1574  * Get conference port associated with player. 
    1575  */ 
    1576 PJ_DEF(pjsua_conf_port_id) pjsua_player_get_conf_port(pjsua_player_id id) 
    1577 { 
    1578     PJ_ASSERT_RETURN(id>=0 && id < PJ_ARRAY_SIZE(pjsua.player), PJ_EINVAL); 
    1579     return pjsua.player[id].slot; 
    1580 } 
    1581  
    1582  
    1583 /** 
    1584  * Re-wind playback. 
    1585  */ 
    1586 PJ_DEF(pj_status_t) pjsua_player_set_pos(pjsua_player_id id, 
    1587                                          pj_uint32_t samples) 
    1588 { 
    1589     PJ_ASSERT_RETURN(id>=0 && id < PJ_ARRAY_SIZE(pjsua.player), PJ_EINVAL); 
    1590     PJ_ASSERT_RETURN(pjsua.player[id].port != NULL, PJ_EINVALIDOP); 
    1591  
    1592     return pjmedia_wav_player_port_set_pos(pjsua.player[id].port, samples); 
    1593 } 
    1594  
    1595  
    1596 /** 
    1597  * Get conference port associated with player. 
    1598  */ 
    1599 PJ_DEF(pj_status_t) pjsua_player_destroy(pjsua_player_id id) 
    1600 { 
    1601     PJ_ASSERT_RETURN(id>=0 && id < PJ_ARRAY_SIZE(pjsua.player), PJ_EINVAL); 
    1602  
    1603     if (pjsua.player[id].port) { 
    1604         pjmedia_port_destroy(pjsua.player[id].port); 
    1605         pjsua.player[id].port = NULL; 
    1606         pjsua.player[id].slot = 0xFFFF; 
    1607         pjsua.player_cnt--; 
    1608     } 
    1609  
    1610     return PJ_SUCCESS; 
    1611 } 
    1612  
    1613  
    1614 /** 
    1615  * Create a file recorder. 
    1616  */ 
    1617 PJ_DEF(pj_status_t) pjsua_recorder_create( const pj_str_t *filename, 
    1618                                            pjsua_recorder_id *id) 
    1619 { 
    1620     unsigned slot; 
    1621     char path[128]; 
    1622     pjmedia_port *port; 
    1623     pj_status_t status; 
    1624  
    1625     if (pjsua.recorder_cnt >= PJ_ARRAY_SIZE(pjsua.recorder)) 
    1626         return PJ_ETOOMANY; 
    1627  
    1628     pj_memcpy(path, filename->ptr, filename->slen); 
    1629     path[filename->slen] = '\0'; 
    1630     status = pjmedia_wav_writer_port_create(pjsua.pool, path, 
    1631                                             pjsua.clock_rate, 1, 
    1632                                             pjsua.samples_per_frame, 
    1633                                             16, 0, 0, NULL, 
    1634                                             &port); 
    1635     if (status != PJ_SUCCESS) 
    1636         return status; 
    1637  
    1638     status = pjmedia_conf_add_port(pjsua.mconf, pjsua.pool,  
    1639                                    port, filename, &slot); 
    1640     if (status != PJ_SUCCESS) { 
    1641         pjmedia_port_destroy(port); 
    1642         return status; 
    1643     } 
    1644  
    1645     pjsua.recorder[pjsua.recorder_cnt].port = port; 
    1646     pjsua.recorder[pjsua.recorder_cnt].slot = slot; 
    1647  
    1648     if (*id) 
    1649         *id = pjsua.recorder_cnt; 
    1650  
    1651     ++pjsua.recorder_cnt; 
    1652  
    1653     return PJ_SUCCESS; 
    1654 } 
    1655  
    1656  
    1657 /** 
    1658  * Get conference port associated with recorder. 
    1659  */ 
    1660 PJ_DEF(pjsua_conf_port_id) pjsua_recorder_get_conf_port(pjsua_recorder_id id) 
    1661 { 
    1662     PJ_ASSERT_RETURN(id>=0 && id < PJ_ARRAY_SIZE(pjsua.recorder), PJ_EINVAL); 
    1663     return pjsua.recorder[id].slot; 
    1664 } 
    1665  
    1666  
    1667 /** 
    1668  * Destroy recorder (will complete recording). 
    1669  */ 
    1670 PJ_DEF(pj_status_t) pjsua_recorder_destroy(pjsua_recorder_id id) 
    1671 { 
    1672     PJ_ASSERT_RETURN(id>=0 && id < PJ_ARRAY_SIZE(pjsua.recorder), PJ_EINVAL); 
    1673  
    1674     if (pjsua.recorder[id].port) { 
    1675         pjmedia_port_destroy(pjsua.recorder[id].port); 
    1676         pjsua.recorder[id].port = NULL; 
    1677         pjsua.recorder[id].slot = 0xFFFF; 
    1678         pjsua.recorder_cnt--; 
    1679     } 
    1680  
    1681     return PJ_SUCCESS; 
    1682 } 
    1683  
    1684 /** 
    1685  * Enum sound devices. 
    1686  */ 
    1687 PJ_DEF(pj_status_t) pjsua_enum_snd_devices( unsigned *count, 
    1688                                             pjmedia_snd_dev_info info[]) 
    1689 { 
    1690     int i, dev_count; 
    1691  
    1692     dev_count = pjmedia_snd_get_dev_count(); 
    1693     if (dev_count > (int)*count) 
    1694         dev_count = *count; 
    1695  
    1696     for (i=0; i<dev_count; ++i) { 
    1697         const pjmedia_snd_dev_info *dev_info; 
    1698         dev_info = pjmedia_snd_get_dev_info(i); 
    1699         pj_memcpy(&info[i], dev_info, sizeof(pjmedia_snd_dev_info)); 
    1700     } 
    1701  
    1702     *count = dev_count; 
    1703     return PJ_SUCCESS; 
    1704 } 
    1705  
    1706  
    1707 /** 
    1708  * Select or change sound device. 
    1709  */ 
    1710 PJ_DEF(pj_status_t) pjsua_set_snd_dev( int snd_capture_id, 
    1711                                        int snd_player_id) 
    1712 { 
    1713     pjsua.config.snd_capture_id = snd_capture_id; 
    1714     pjsua.config.snd_player_id = snd_player_id; 
    1715     return PJ_SUCCESS; 
    1716 } 
    1717  
    1718  
    1719 /* 
    1720  * Destroy pjsua. 
    1721  */ 
    1722 PJ_DEF(pj_status_t) pjsua_destroy(void) 
    1723 { 
    1724     int i;  /* Must be signed */ 
    1725  
    1726     /* Signal threads to quit: */ 
    1727     pjsua.quit_flag = 1; 
    1728  
    1729     /* Wait worker threads to quit: */ 
    1730     for (i=0; i<(int)pjsua.config.thread_cnt; ++i) { 
    1731          
    1732         if (pjsua.threads[i]) { 
    1733             pj_thread_join(pjsua.threads[i]); 
    1734             pj_thread_destroy(pjsua.threads[i]); 
    1735             pjsua.threads[i] = NULL; 
    1736         } 
    1737     } 
    1738  
    1739492     
    1740     if (pjsua.endpt) { 
     493    if (pjsua_var.endpt) { 
    1741494        /* Terminate all calls. */ 
    1742495        pjsua_call_hangup_all(); 
     
    1746499 
    1747500        /* Unregister, if required: */ 
    1748         for (i=0; i<(int)pjsua.config.acc_cnt; ++i) { 
    1749             if (pjsua.acc[i].regc) { 
     501        for (i=0; i<(int)PJ_ARRAY_SIZE(pjsua_var.acc); ++i) { 
     502            if (!pjsua_var.acc[i].valid) 
     503                continue; 
     504 
     505            if (pjsua_var.acc[i].regc) { 
    1750506                pjsua_acc_set_registration(i, PJ_FALSE); 
    1751507            } 
     
    1757513    } 
    1758514 
    1759     /* If we have master port, destroying master port will recursively 
    1760      * destroy conference bridge, otherwise must destroy it manually.  
     515    /* Destroy media */ 
     516    pjsua_media_subsys_destroy(); 
     517 
     518    /* Destroy endpoint. */ 
     519    if (pjsua_var.endpt) { 
     520        pjsip_endpt_destroy(pjsua_var.endpt); 
     521        pjsua_var.endpt = NULL; 
     522    } 
     523 
     524    /* Destroy mutex */ 
     525    if (pjsua_var.mutex) { 
     526        pj_mutex_destroy(pjsua_var.mutex); 
     527        pjsua_var.mutex = NULL; 
     528    } 
     529 
     530    /* Destroy pool and pool factory. */ 
     531    if (pjsua_var.pool) { 
     532        pj_pool_release(pjsua_var.pool); 
     533        pjsua_var.pool = NULL; 
     534        pj_caching_pool_destroy(&pjsua_var.cp); 
     535    } 
     536 
     537 
     538    PJ_LOG(4,(THIS_FILE, "PJSUA destroyed...")); 
     539 
     540    /* End logging */ 
     541    if (pjsua_var.log_file) { 
     542        pj_file_close(pjsua_var.log_file); 
     543        pjsua_var.log_file = NULL; 
     544    } 
     545 
     546    /* Done. */ 
     547    return PJ_SUCCESS; 
     548} 
     549 
     550 
     551/** 
     552 * Application is recommended to call this function after all initialization 
     553 * is done, so that the library can do additional checking set up 
     554 * additional  
     555 * 
     556 * @return              PJ_SUCCESS on success, or the appropriate error code. 
     557 */ 
     558PJ_DEF(pj_status_t) pjsua_start(void) 
     559{ 
     560    pj_status_t status; 
     561 
     562    status = pjsua_call_subsys_start(); 
     563    if (status != PJ_SUCCESS) 
     564        return status; 
     565 
     566    status = pjsua_media_subsys_start(); 
     567    if (status != PJ_SUCCESS) 
     568        return status; 
     569 
     570    status = pjsua_pres_start(); 
     571    if (status != PJ_SUCCESS) 
     572        return status; 
     573 
     574    return PJ_SUCCESS; 
     575} 
     576 
     577 
     578/** 
     579 * Poll pjsua for events, and if necessary block the caller thread for 
     580 * the specified maximum interval (in miliseconds). 
     581 */ 
     582PJ_DEF(int) pjsua_handle_events(unsigned msec_timeout) 
     583{ 
     584    unsigned count = 0; 
     585    pj_time_val tv; 
     586    pj_status_t status; 
     587 
     588    tv.sec = 0; 
     589    tv.msec = msec_timeout; 
     590    pj_time_val_normalize(&tv); 
     591 
     592    status = pjsip_endpt_handle_events2(pjsua_var.endpt, &tv, &count); 
     593 
     594    if (status != PJ_SUCCESS) 
     595        return -status; 
     596 
     597    return count; 
     598} 
     599 
     600 
     601/* 
     602 * Create memory pool. 
     603 */ 
     604PJ_DEF(pj_pool_t*) pjsua_pool_create( const char *name, pj_size_t init_size, 
     605                                      pj_size_t increment) 
     606{ 
     607    /* Pool factory is thread safe, no need to lock */ 
     608    return pj_pool_create(&pjsua_var.cp.factory, name, init_size, increment,  
     609                          NULL); 
     610} 
     611 
     612 
     613/* 
     614 * Internal function to get SIP endpoint instance of pjsua, which is 
     615 * needed for example to register module, create transports, etc. 
     616 * Probably is only valid after #pjsua_init() is called. 
     617 */ 
     618PJ_DEF(pjsip_endpoint*) pjsua_get_pjsip_endpt(void) 
     619{ 
     620    return pjsua_var.endpt; 
     621} 
     622 
     623/* 
     624 * Internal function to get media endpoint instance. 
     625 * Only valid after #pjsua_init() is called. 
     626 */ 
     627PJ_DEF(pjmedia_endpt*) pjsua_get_pjmedia_endpt(void) 
     628{ 
     629    return pjsua_var.med_endpt; 
     630} 
     631 
     632 
     633/***************************************************************************** 
     634 * PJSUA SIP Transport API. 
     635 */ 
     636 
     637/* 
     638 * Create and initialize SIP socket (and possibly resolve public 
     639 * address via STUN, depending on config). 
     640 */ 
     641static pj_status_t create_sip_udp_sock(pj_in_addr bound_addr, 
     642                                       int port, 
     643                                       pj_bool_t use_stun, 
     644                                       const pjsua_stun_config *stun_param, 
     645                                       pj_sock_t *p_sock, 
     646                                       pj_sockaddr_in *p_pub_addr) 
     647{ 
     648    pjsua_stun_config stun; 
     649    pj_sock_t sock; 
     650    pj_status_t status; 
     651 
     652    PJSUA_LOCK(); 
     653 
     654    status = pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, &sock); 
     655    if (status != PJ_SUCCESS) { 
     656        pjsua_perror(THIS_FILE, "socket() error", status); 
     657        goto on_return; 
     658    } 
     659 
     660    status = pj_sock_bind_in(sock, bound_addr.s_addr, (pj_uint16_t)port); 
     661    if (status != PJ_SUCCESS) { 
     662        pjsua_perror(THIS_FILE, "bind() error", status); 
     663        pj_sock_close(sock); 
     664        goto on_return; 
     665    } 
     666 
     667    /* Copy and normalize STUN param */ 
     668    if (use_stun) { 
     669        pj_memcpy(&stun, stun_param, sizeof(*stun_param)); 
     670        pjsua_normalize_stun_config(&stun); 
     671    } else { 
     672        pj_memset(&stun, 0, sizeof(pjsua_stun_config)); 
     673    } 
     674 
     675    /* Get the published address, either by STUN or by resolving 
     676     * the name of local host. 
    1761677     */ 
    1762     if (pjsua.master_port) { 
    1763         pjmedia_master_port_destroy(pjsua.master_port); 
    1764         pjsua.master_port = NULL; 
     678    if (stun.stun_srv1.slen) { 
     679        status = pj_stun_get_mapped_addr(&pjsua_var.cp.factory, 1, &sock, 
     680                                         &stun.stun_srv1,  
     681                                          stun.stun_port1, 
     682                                         &stun.stun_srv2,  
     683                                          stun.stun_port2, 
     684                                          p_pub_addr); 
     685        if (status != PJ_SUCCESS) { 
     686            pjsua_perror(THIS_FILE, "Error resolving with STUN", status); 
     687            pj_sock_close(sock); 
     688            goto on_return; 
     689        } 
     690 
    1765691    } else { 
    1766         if (pjsua.snd_port) { 
    1767             pjmedia_snd_port_destroy(pjsua.snd_port); 
    1768             pjsua.snd_port = NULL; 
     692 
     693        const pj_str_t *hostname = pj_gethostname(); 
     694        struct pj_hostent he; 
     695 
     696        status = pj_gethostbyname(hostname, &he); 
     697        if (status != PJ_SUCCESS) { 
     698            pjsua_perror(THIS_FILE, "Unable to resolve local host", status); 
     699            pj_sock_close(sock); 
     700            goto on_return; 
    1769701        } 
    1770         if (pjsua.mconf) { 
    1771             pjmedia_conf_destroy(pjsua.mconf); 
    1772             pjsua.mconf = NULL; 
     702 
     703        pj_memset(p_pub_addr, 0, sizeof(pj_sockaddr_in)); 
     704        p_pub_addr->sin_family = PJ_AF_INET; 
     705        p_pub_addr->sin_port = pj_htons((pj_uint16_t)port); 
     706        p_pub_addr->sin_addr = *(pj_in_addr*)he.h_addr; 
     707    } 
     708 
     709    *p_sock = sock; 
     710 
     711on_return: 
     712 
     713    PJSUA_UNLOCK(); 
     714 
     715    PJ_LOG(4,(THIS_FILE, "SIP UDP socket reachable at %s:%d", 
     716              pj_inet_ntoa(p_pub_addr->sin_addr), 
     717              (int)pj_ntohs(p_pub_addr->sin_port))); 
     718 
     719    return status; 
     720} 
     721 
     722 
     723/* 
     724 * Create SIP transport. 
     725 */ 
     726PJ_DEF(pj_status_t) pjsua_transport_create( pjsip_transport_type_e type, 
     727                                            const pjsua_transport_config *cfg, 
     728                                            pjsua_transport_id *p_id) 
     729{ 
     730    pjsip_transport *tp; 
     731    unsigned id; 
     732    pj_status_t status; 
     733 
     734    PJSUA_LOCK(); 
     735 
     736    /* Find empty transport slot */ 
     737    for (id=0; id < PJ_ARRAY_SIZE(pjsua_var.tpdata); ++id) { 
     738        if (pjsua_var.tpdata[id].tp == NULL) 
     739            break; 
     740    } 
     741 
     742    if (id == PJ_ARRAY_SIZE(pjsua_var.tpdata)) { 
     743        status = PJ_ETOOMANY; 
     744        pjsua_perror(THIS_FILE, "Error creating transport", status); 
     745        goto on_return; 
     746    } 
     747 
     748    /* Create the transport */ 
     749    if (type == PJSIP_TRANSPORT_UDP) { 
     750 
     751        pjsua_transport_config config; 
     752        pj_sock_t sock; 
     753        pj_sockaddr_in pub_addr; 
     754        pjsip_host_port addr_name; 
     755 
     756        /* Supply default config if it's not specified */ 
     757        if (cfg == NULL) { 
     758            pjsua_transport_config_default(&config); 
     759            cfg = &config; 
    1773760        } 
    1774     } 
    1775  
    1776     /* Destroy file players */ 
    1777     for (i=0; i<PJ_ARRAY_SIZE(pjsua.player); ++i) { 
    1778         if (pjsua.player[i].port) { 
    1779             pjmedia_port_destroy(pjsua.player[i].port); 
    1780             pjsua.player[i].port = NULL; 
     761 
     762        /* Create the socket and possibly resolve the address with STUN */ 
     763        status = create_sip_udp_sock(cfg->ip_addr, cfg->port, cfg->use_stun, 
     764                                     &cfg->stun_config, &sock, &pub_addr); 
     765        if (status != PJ_SUCCESS) 
     766            goto on_return; 
     767 
     768        addr_name.host = pj_str(pj_inet_ntoa(pub_addr.sin_addr)); 
     769        addr_name.port = pj_ntohs(pub_addr.sin_port); 
     770 
     771        /* Create UDP transport */ 
     772        status = pjsip_udp_transport_attach( pjsua_var.endpt, sock, 
     773                                             &addr_name, 1,  
     774                                             &tp); 
     775        if (status != PJ_SUCCESS) { 
     776            pjsua_perror(THIS_FILE, "Error creating SIP UDP transport",  
     777                         status); 
     778            pj_sock_close(sock); 
     779            goto on_return; 
    1781780        } 
    1782     } 
    1783  
    1784  
    1785     /* Destroy file recorders */ 
    1786     for (i=0; i<PJ_ARRAY_SIZE(pjsua.recorder); ++i) { 
    1787         if (pjsua.recorder[i].port) { 
    1788             pjmedia_port_destroy(pjsua.recorder[i].port); 
    1789             pjsua.recorder[i].port = NULL; 
    1790         } 
    1791     } 
    1792  
    1793  
    1794     /* Close transports */ 
    1795     for (i=0; i<(int)pjsua.config.max_calls; ++i) { 
    1796         if (pjsua.calls[i].med_tp) { 
    1797             (*pjsua.calls[i].med_tp->op->destroy)(pjsua.calls[i].med_tp); 
    1798             pjsua.calls[i].med_tp = NULL; 
    1799         } 
    1800     } 
    1801  
    1802     /* Destroy media endpoint. */ 
    1803     if (pjsua.med_endpt) { 
    1804  
    1805         /* Shutdown all codecs: */ 
    1806 #       if PJMEDIA_HAS_SPEEX_CODEC 
    1807             pjmedia_codec_speex_deinit(); 
    1808 #       endif /* PJMEDIA_HAS_SPEEX_CODEC */ 
    1809  
    1810 #       if PJMEDIA_HAS_GSM_CODEC 
    1811             pjmedia_codec_gsm_deinit(); 
    1812 #       endif /* PJMEDIA_HAS_GSM_CODEC */ 
    1813  
    1814 #       if PJMEDIA_HAS_G711_CODEC 
    1815             pjmedia_codec_g711_deinit(); 
    1816 #       endif   /* PJMEDIA_HAS_G711_CODEC */ 
    1817  
    1818 #       if PJMEDIA_HAS_L16_CODEC 
    1819             pjmedia_codec_l16_deinit(); 
    1820 #       endif   /* PJMEDIA_HAS_L16_CODEC */ 
    1821  
    1822  
    1823         pjmedia_endpt_destroy(pjsua.med_endpt); 
    1824         pjsua.med_endpt = NULL; 
    1825     } 
    1826  
    1827     /* Destroy endpoint. */ 
    1828     if (pjsua.endpt) { 
    1829         pjsip_endpt_destroy(pjsua.endpt); 
    1830         pjsua.endpt = NULL; 
    1831     } 
    1832  
    1833     /* Destroy caching pool. */ 
    1834     pj_caching_pool_destroy(&pjsua.cp); 
    1835  
    1836  
    1837     PJ_LOG(4,(THIS_FILE, "PJSUA destroyed...")); 
    1838  
    1839     /* End logging */ 
    1840     logging_shutdown(); 
    1841  
    1842     /* Done. */ 
     781 
     782    } else { 
     783        status = PJSIP_EUNSUPTRANSPORT; 
     784        pjsua_perror(THIS_FILE, "Error creating transport", status); 
     785        goto on_return; 
     786    } 
     787 
     788    /* Save the transport */ 
     789    pjsua_var.tpdata[id].tp = tp; 
     790 
     791    /* Return the ID */ 
     792    if (p_id) *p_id = id; 
     793 
     794    status = PJ_SUCCESS; 
     795 
     796on_return: 
     797 
     798    PJSUA_UNLOCK(); 
    1843799 
    1844800    return PJ_SUCCESS; 
     
    1846802 
    1847803 
    1848 /** 
    1849  * Get SIP endpoint instance. 
    1850  * Only valid after pjsua_init(). 
    1851  */ 
    1852 PJ_DEF(pjsip_endpoint*) pjsua_get_pjsip_endpt(void) 
    1853 { 
    1854     return pjsua.endpt; 
    1855 } 
    1856  
    1857 /** 
    1858  * Get media endpoint instance. 
    1859  * Only valid after pjsua_init(). 
    1860  */ 
    1861 PJ_DEF(pjmedia_endpt*) pjsua_get_pjmedia_endpt(void) 
    1862 { 
    1863     return pjsua.med_endpt; 
    1864 } 
    1865  
     804/* 
     805 * Register transport that has been created by application. 
     806 */ 
     807PJ_DEF(pj_status_t) pjsua_transport_register( pjsip_transport *tp, 
     808                                              pjsua_transport_id *p_id) 
     809{ 
     810    unsigned id; 
     811 
     812    PJSUA_LOCK(); 
     813 
     814    /* Find empty transport slot */ 
     815    for (id=0; id < PJ_ARRAY_SIZE(pjsua_var.tpdata); ++id) { 
     816        if (pjsua_var.tpdata[id].tp == NULL) 
     817            break; 
     818    } 
     819 
     820    if (id == PJ_ARRAY_SIZE(pjsua_var.tpdata)) { 
     821        pjsua_perror(THIS_FILE, "Error creating transport", PJ_ETOOMANY); 
     822        PJSUA_UNLOCK(); 
     823        return PJ_ETOOMANY; 
     824    } 
     825 
     826    /* Save the transport */ 
     827    pjsua_var.tpdata[id].tp = tp; 
     828 
     829    /* Return the ID */ 
     830    if (p_id) *p_id = id; 
     831 
     832    PJSUA_UNLOCK(); 
     833 
     834    return PJ_SUCCESS; 
     835} 
     836 
     837 
     838/* 
     839 * Enumerate all transports currently created in the system. 
     840 */ 
     841PJ_DEF(pj_status_t) pjsua_enum_transports( pjsua_transport_id id[], 
     842                                           unsigned *p_count ) 
     843{ 
     844    unsigned i, count; 
     845 
     846    PJSUA_LOCK(); 
     847 
     848    for (i=0, count=0; i<PJ_ARRAY_SIZE(pjsua_var.tpdata) && count<*p_count;  
     849         ++i)  
     850    { 
     851        if (!pjsua_var.tpdata[i].tp) 
     852            continue; 
     853 
     854        id[count++] = i; 
     855    } 
     856 
     857    *p_count = count; 
     858 
     859    PJSUA_UNLOCK(); 
     860 
     861    return PJ_SUCCESS; 
     862} 
     863 
     864 
     865/* 
     866 * Get information about transports. 
     867 */ 
     868PJ_DEF(pj_status_t) pjsua_transport_get_info( pjsua_transport_id id, 
     869                                              pjsua_transport_info *info) 
     870{ 
     871    pjsip_transport *tp; 
     872 
     873    pj_memset(info, 0, sizeof(*info)); 
     874 
     875    /* Make sure id is in range. */ 
     876    PJ_ASSERT_RETURN(id>=0 && id<PJ_ARRAY_SIZE(pjsua_var.tpdata), PJ_EINVAL); 
     877 
     878    /* Make sure that transport exists */ 
     879    PJ_ASSERT_RETURN(pjsua_var.tpdata[id].tp != NULL, PJ_EINVAL); 
     880 
     881    PJSUA_LOCK(); 
     882 
     883    tp = pjsua_var.tpdata[id].tp; 
     884    if (tp == NULL) { 
     885        PJSUA_UNLOCK(); 
     886        return PJ_EINVALIDOP; 
     887    } 
     888     
     889    info->id = id; 
     890    info->type = tp->key.type; 
     891    info->type_name = pj_str(tp->type_name); 
     892    info->info = pj_str(tp->info); 
     893    info->flag = tp->flag; 
     894    info->addr_len = tp->addr_len; 
     895    info->local_addr = tp->local_addr; 
     896    info->local_name = tp->local_name; 
     897    info->usage_count = pj_atomic_get(tp->ref_cnt); 
     898 
     899    PJSUA_UNLOCK(); 
     900 
     901    return PJ_EINVALIDOP; 
     902} 
     903 
     904 
     905/* 
     906 * Disable a transport or re-enable it. 
     907 */ 
     908PJ_DEF(pj_status_t) pjsua_transport_set_enable( pjsua_transport_id id, 
     909                                                pj_bool_t enabled) 
     910{ 
     911    /* Make sure id is in range. */ 
     912    PJ_ASSERT_RETURN(id>=0 && id<PJ_ARRAY_SIZE(pjsua_var.tpdata), PJ_EINVAL); 
     913 
     914    /* Make sure that transport exists */ 
     915    PJ_ASSERT_RETURN(pjsua_var.tpdata[id].tp != NULL, PJ_EINVAL); 
     916 
     917 
     918    /* To be done!! */ 
     919    PJ_TODO(pjsua_transport_set_enable); 
     920 
     921    return PJ_EINVALIDOP; 
     922} 
     923 
     924 
     925/* 
     926 * Close the transport. 
     927 */ 
     928PJ_DEF(pj_status_t) pjsua_transport_close( pjsua_transport_id id, 
     929                                           pj_bool_t force ) 
     930{ 
     931    /* Make sure id is in range. */ 
     932    PJ_ASSERT_RETURN(id>=0 && id<PJ_ARRAY_SIZE(pjsua_var.tpdata), PJ_EINVAL); 
     933 
     934    /* Make sure that transport exists */ 
     935    PJ_ASSERT_RETURN(pjsua_var.tpdata[id].tp != NULL, PJ_EINVAL); 
     936 
     937 
     938    /* To be done!! */ 
     939 
     940 
     941    PJ_TODO(pjsua_transport_close); 
     942 
     943    return PJ_EINVALIDOP; 
     944} 
     945 
     946 
     947/* 
     948 * Add additional headers etc in msg_data specified by application 
     949 * when sending requests. 
     950 */ 
     951void pjsua_process_msg_data(pjsip_tx_data *tdata, 
     952                            const pjsua_msg_data *msg_data) 
     953{ 
     954    pj_bool_t allow_body; 
     955    const pjsip_hdr *hdr; 
     956 
     957    if (!msg_data) 
     958        return; 
     959 
     960    hdr = msg_data->hdr_list.next; 
     961    while (hdr && hdr != &msg_data->hdr_list) { 
     962        pjsip_hdr *new_hdr; 
     963 
     964        new_hdr = pjsip_hdr_clone(tdata->pool, hdr); 
     965        pjsip_msg_add_hdr(tdata->msg, new_hdr); 
     966 
     967        hdr = hdr->next; 
     968    } 
     969 
     970    allow_body = (tdata->msg->body == NULL); 
     971 
     972    if (allow_body && msg_data->content_type.slen && msg_data->msg_body.slen) { 
     973        pjsip_media_type ctype; 
     974        pjsip_msg_body *body;    
     975 
     976        pjsua_parse_media_type(tdata->pool, &msg_data->content_type, &ctype); 
     977        body = pjsip_msg_body_create(tdata->pool, &ctype.type, &ctype.subtype, 
     978                                     &msg_data->msg_body); 
     979        tdata->msg->body = body; 
     980    } 
     981} 
     982 
     983 
     984/* 
     985 * Add route_set to outgoing requests 
     986 */ 
     987void pjsua_set_msg_route_set( pjsip_tx_data *tdata, 
     988                              const pjsip_route_hdr *route_set ) 
     989{ 
     990    const pjsip_route_hdr *r; 
     991 
     992    r = route_set->next; 
     993    while (r != route_set) { 
     994        pjsip_route_hdr *new_r; 
     995 
     996        new_r = pjsip_hdr_clone(tdata->pool, r); 
     997        pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)new_r); 
     998 
     999        r = r->next; 
     1000    } 
     1001} 
     1002 
     1003 
     1004/* 
     1005 * Simple version of MIME type parsing (it doesn't support parameters) 
     1006 */ 
     1007void pjsua_parse_media_type( pj_pool_t *pool, 
     1008                             const pj_str_t *mime, 
     1009                             pjsip_media_type *media_type) 
     1010{ 
     1011    pj_str_t tmp; 
     1012    char *pos; 
     1013 
     1014    pj_memset(media_type, 0, sizeof(*media_type)); 
     1015 
     1016    pj_strdup_with_null(pool, &tmp, mime); 
     1017 
     1018    pos = pj_strchr(&tmp, '/'); 
     1019    if (pos) { 
     1020        media_type->type.ptr = tmp.ptr;  
     1021        media_type->type.slen = (pos-tmp.ptr); 
     1022        media_type->subtype.ptr = pos+1;  
     1023        media_type->subtype.slen = tmp.ptr+tmp.slen-pos-1; 
     1024    } else { 
     1025        media_type->type = tmp; 
     1026    } 
     1027} 
     1028 
     1029 
     1030/* 
     1031 * Verify that valid SIP url is given. 
     1032 */ 
     1033PJ_DEF(pj_status_t) pjsua_verify_sip_url(const char *c_url) 
     1034{ 
     1035    pjsip_uri *p; 
     1036    pj_pool_t *pool; 
     1037    char *url; 
     1038    int len = (c_url ? pj_ansi_strlen(c_url) : 0); 
     1039 
     1040    if (!len) return -1; 
     1041 
     1042    pool = pj_pool_create(&pjsua_var.cp.factory, "check%p", 1024, 0, NULL); 
     1043    if (!pool) return -1; 
     1044 
     1045    url = pj_pool_alloc(pool, len+1); 
     1046    pj_ansi_strcpy(url, c_url); 
     1047 
     1048    p = pjsip_parse_uri(pool, url, len, 0); 
     1049    if (!p || pj_stricmp2(pjsip_uri_get_scheme(p), "sip") != 0) 
     1050        p = NULL; 
     1051 
     1052    pj_pool_release(pool); 
     1053    return p ? 0 : -1; 
     1054} 
Note: See TracChangeset for help on using the changeset viewer.