Changeset 503


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

-- REWRITE OF PJSUA API --

Location:
pjproject/trunk
Files:
4 added
5 deleted
12 edited

Legend:

Unmodified
Added
Removed
  • pjproject/trunk/pjlib/src/pj/config.c

    r468 r503  
    2222 
    2323static const char *id = "config.c"; 
    24 const char *PJ_VERSION = "0.5.5.6"; 
     24const char *PJ_VERSION = "0.5.6.0"; 
    2525 
    2626PJ_DEF(void) pj_dump_config(void) 
  • pjproject/trunk/pjsip-apps/build

    • Property svn:ignore
      •  

        old new  
        88*.suo 
        99*.pdb 
         10activex-pjsua_p.c 
         11dlldata.c 
  • pjproject/trunk/pjsip-apps/build/activex-pjsua.dsp

    r487 r503  
    324324# Begin Source File 
    325325 
    326 SOURCE="..\src\activex-pjsua\pjsua.h" 
     326SOURCE="..\src\activex-pjsua\pjsua-structs.h" 
    327327# End Source File 
    328328# Begin Source File 
  • pjproject/trunk/pjsip-apps/build/pjsua.dsp

    r458 r503  
    9393SOURCE=..\src\pjsua\main.c 
    9494# End Source File 
     95# Begin Source File 
     96 
     97SOURCE=..\src\pjsua\pjsua.c 
     98# End Source File 
    9599# End Group 
    96100# Begin Group "Header Files" 
  • pjproject/trunk/pjsip-apps/src/activex-pjsua

    • Property svn:ignore set to
      old*
      backup*
      *.tlb
      *.aps
      activex-pjsua.h
      activex-pjsua_i.c
      pjsua-structs.h
      resource.h
  • pjproject/trunk/pjsip-apps/src/pjsua/main.c

    r492 r503  
    1818 */ 
    1919#include <pjsua-lib/pjsua.h> 
    20 #include <pjsua-lib/pjsua_console_app.h> 
    21  
    2220 
    2321#define THIS_FILE       "main.c" 
    2422 
    25 /***************************************************************************** 
    26  * main(): 
     23 
     24/* 
     25 * These are defined in pjsua.c. 
    2726 */ 
     27pj_status_t app_init(int argc, char *argv[]); 
     28pj_status_t app_main(void); 
     29pj_status_t app_destroy(void); 
     30 
    2831int main(int argc, char *argv[]) 
    2932{ 
    30     pjsua_config cfg; 
    31     pj_str_t uri_to_call = { NULL, 0 }; 
    32  
    33     /* Init default settings. */ 
    34     pjsua_default_config(&cfg); 
    35  
    36  
    37     /* Create PJLIB and memory pool */ 
    38     pjsua_create(); 
    39  
    40  
    41     /* Parse command line arguments: */ 
    42     if (pjsua_parse_args(argc, argv, &cfg, &uri_to_call) != PJ_SUCCESS) 
     33    if (app_init(argc, argv) != PJ_SUCCESS) 
    4334        return 1; 
    4435 
    45  
    46     /* Init pjsua */ 
    47     if (pjsua_init(&cfg, &console_callback) != PJ_SUCCESS) 
    48         return 1; 
    49  
    50  
    51     /* Start pjsua! */ 
    52     if (pjsua_start() != PJ_SUCCESS) { 
    53         pjsua_destroy(); 
    54         return 1; 
    55     } 
    56  
    57  
    58     /* Sleep for a while, let any messages get printed to console: */ 
    59     pj_thread_sleep(500); 
    60  
    61  
    62     /* Start UI console main loop: */ 
    63     pjsua_console_app_main(&uri_to_call); 
    64  
    65  
    66     /* Destroy pjsua: */ 
    67     pjsua_destroy(); 
    68  
    69     /* This is for internal testing, to make sure that pjsua_destroy() 
    70      * can be called multiple times.  
    71      */ 
    72     pjsua_destroy(); 
    73  
    74  
    75     /* Exit... */ 
     36    app_main(); 
     37    app_destroy(); 
    7638 
    7739    return 0; 
  • pjproject/trunk/pjsip/build/pjsua_lib.dsp

    r476 r503  
    8888# Begin Source File 
    8989 
    90 SOURCE="..\src\pjsua-lib\pjsua_call.c" 
     90SOURCE="..\src\pjsua-lib\pjsua_acc.c" 
    9191# End Source File 
    9292# Begin Source File 
    9393 
    94 SOURCE="..\src\pjsua-lib\pjsua_console_app.c" 
     94SOURCE="..\src\pjsua-lib\pjsua_call.c" 
    9595# End Source File 
    9696# Begin Source File 
     
    104104# Begin Source File 
    105105 
    106 SOURCE="..\src\pjsua-lib\pjsua_imp.h" 
     106SOURCE="..\src\pjsua-lib\pjsua_media.c" 
    107107# End Source File 
    108108# Begin Source File 
    109109 
    110110SOURCE="..\src\pjsua-lib\pjsua_pres.c" 
    111 # End Source File 
    112 # Begin Source File 
    113  
    114 SOURCE="..\src\pjsua-lib\pjsua_reg.c" 
    115 # End Source File 
    116 # Begin Source File 
    117  
    118 SOURCE="..\src\pjsua-lib\pjsua_settings.c" 
    119111# End Source File 
    120112# End Group 
     
    128120# Begin Source File 
    129121 
    130 SOURCE="..\include\pjsua-lib\pjsua_console_app.h" 
     122SOURCE="..\include\pjsua-lib\pjsua_internal.h" 
    131123# End Source File 
    132124# End Group 
  • pjproject/trunk/pjsip/include/pjsua-lib/pjsua.h

    r492 r503  
    5757 */ 
    5858#ifndef PJSUA_MAX_CALLS 
    59 #   define PJSUA_MAX_CALLS          256 
     59#   define PJSUA_MAX_CALLS          32 
    6060#endif 
    6161 
    6262 
    6363/** 
     64 * Max ports in the conference bridge. 
     65 */ 
     66#ifndef PJSUA_MAX_CONF_PORTS 
     67#   define PJSUA_MAX_CONF_PORTS     254 
     68#endif 
     69 
     70 
     71/** 
    6472 * Maximum accounts. 
    6573 */ 
    6674#ifndef PJSUA_MAX_ACC 
    67 #   define PJSUA_MAX_ACC            32 
     75#   define PJSUA_MAX_ACC            8 
    6876#endif 
    6977 
    7078 
     79/** 
     80 * Maximum proxies in account. 
     81 */ 
     82#ifndef PJSUA_ACC_MAX_PROXIES 
     83#   define PJSUA_ACC_MAX_PROXIES    8 
     84#endif 
     85 
     86/** 
     87 * Default registration interval. 
     88 */ 
     89#ifndef PJSUA_REG_INTERVAL 
     90#   define PJSUA_REG_INTERVAL       55 
     91#endif 
     92 
     93 
     94/** Account identification */ 
    7195typedef int pjsua_acc_id; 
     96 
     97/** Call identification */ 
     98typedef int pjsua_call_id; 
     99 
     100/** SIP transport identification */ 
     101typedef int pjsua_transport_id; 
     102 
     103/** Buddy identification */ 
    72104typedef int pjsua_buddy_id; 
     105 
     106/** File player identification */ 
    73107typedef int pjsua_player_id; 
     108 
     109/** File recorder identification */ 
    74110typedef int pjsua_recorder_id; 
     111 
     112/** Conference port identification */ 
    75113typedef int pjsua_conf_port_id; 
    76114 
    77115 
     116/** Constant to identify invalid ID for all sorts of IDs. */ 
     117#define PJSUA_INVALID_ID            (-1) 
     118 
     119 
     120 
    78121/** 
    79122 * Account configuration. 
    80123 */ 
    81 struct pjsua_acc_config 
    82 { 
    83     /** SIP URL for account ID (mandatory) */ 
     124typedef struct pjsua_acc_config 
     125{ 
     126    /**  
     127     * The full SIP URL for the account. The value can take name address or  
     128     * URL format, and will look something like "sip:account@serviceprovider". 
     129     * 
     130     * This field is mandatory. 
     131     */ 
    84132    pj_str_t        id; 
    85133 
    86     /** Registrar URI (mandatory) */ 
     134    /**  
     135     * This is the URL to be put in the request URI for the registration, 
     136     * and will look something like "sip:serviceprovider". 
     137     * 
     138     * This field should be specified if registration is desired. If the 
     139     * value is empty, no account registration will be performed. 
     140     */ 
    87141    pj_str_t        reg_uri; 
    88142 
    89     /** Optional contact URI */ 
     143    /**  
     144     * Optional URI to be put as Contact for this account. It is recommended 
     145     * that this field is left empty, so that the value will be calculated 
     146     * automatically based on the transport address. 
     147     */ 
    90148    pj_str_t        contact; 
    91149 
    92     /** Service proxy (default: none) */ 
    93     pj_str_t        proxy; 
    94  
    95     /** Default timeout (mandatory) */ 
    96     pj_int32_t      reg_timeout; 
    97  
    98     /** Number of credentials. */ 
     150    /** 
     151     * Number of proxies in the proxy array below. 
     152     */ 
     153    unsigned        proxy_cnt; 
     154 
     155    /**  
     156     * Optional URI of the proxies to be visited for all outgoing requests  
     157     * that are using this account (REGISTER, INVITE, etc). Application need  
     158     * to specify these proxies if the service provider requires that requests 
     159     * destined towards its network should go through certain proxies first 
     160     * (for example, border controllers). 
     161     * 
     162     * These proxies will be put in the route set for this account, with  
     163     * maintaining the orders (the first proxy in the array will be visited 
     164     * first). 
     165     */ 
     166    pj_str_t        proxy[PJSUA_ACC_MAX_PROXIES]; 
     167 
     168    /**  
     169     * Optional interval for registration, in seconds. If the value is zero,  
     170     * default interval will be used (PJSUA_REG_INTERVAL, 55 seconds). 
     171     */ 
     172    unsigned        reg_timeout; 
     173 
     174    /**  
     175     * Number of credentials in the credential array. 
     176     */ 
    99177    unsigned        cred_count; 
    100178 
    101     /** Array of credentials. */ 
    102     pjsip_cred_info cred_info[4]; 
    103  
    104 }; 
    105  
    106  
    107 /** 
    108  * @see pjsua_acc_config 
    109  */ 
    110 typedef struct pjsua_acc_config pjsua_acc_config; 
    111  
    112  
    113 /** 
    114  * PJSUA settings. 
    115  */ 
    116 struct pjsua_config 
    117 { 
    118     /** SIP UDP signaling port. Set to zero to disable UDP signaling, 
    119      * which in this case application must manually add a transport 
    120      * to SIP endpoint. 
    121      * (default: 5060)  
    122      */ 
    123     unsigned    udp_port; 
    124  
    125     /** Optional hostname or IP address to publish as the host part of 
    126      *  Contact header. This must be specified if UDP transport is 
    127      *  disabled. 
    128      *  (default: NULL) 
    129      */ 
    130     pj_str_t    sip_host; 
    131  
    132     /** Optional port number to publish in the port part of Contact header. 
    133      *  This must be specified if UDP transport is disabled. 
    134      *  (default: 0) 
    135      */ 
    136     unsigned    sip_port; 
    137  
    138     /** Start of RTP port. Set to zero to prevent pjsua from creating 
    139      *  media transports, which in this case application must manually 
    140      *  create media transport for each calls. 
    141      *  (default: 4000)  
    142      */ 
    143     unsigned    start_rtp_port; 
    144  
    145     /** 
    146      * Enable incoming and outgoing message logging (default: 1). 
     179    /**  
     180     * Array of credentials. If registration is desired, normally there should 
     181     * be at least one credential specified, to successfully authenticate 
     182     * against the service provider. More credentials can be specified, for 
     183     * example when the requests are expected to be challenged by the 
     184     * proxies in the route set. 
     185     */ 
     186    pjsip_cred_info cred_info[PJSUA_ACC_MAX_PROXIES]; 
     187 
     188} pjsua_acc_config; 
     189 
     190 
     191/** 
     192 * Call this function to initialize account config with default values. 
     193 * 
     194 * @param cfg       The account config to be initialized. 
     195 */ 
     196PJ_INLINE(void) pjsua_acc_config_default(pjsua_acc_config *cfg) 
     197{ 
     198    pj_memset(cfg, 0, sizeof(*cfg)); 
     199 
     200    cfg->reg_timeout = PJSUA_REG_INTERVAL; 
     201} 
     202 
     203 
     204 
     205/** 
     206 * Account info. Application can query account info by calling  
     207 * #pjsua_acc_get_info(). 
     208 */ 
     209typedef struct pjsua_acc_info 
     210{ 
     211    /**  
     212     * The account ID.  
     213     */ 
     214    pjsua_acc_id        id; 
     215 
     216    /** 
     217     * Flag to indicate whether this is the default account. 
     218     */ 
     219    pj_bool_t           is_default; 
     220 
     221    /**  
     222     * Account URI  
     223     */ 
     224    pj_str_t            acc_uri; 
     225 
     226    /**  
     227     * Flag to tell whether this account has registration setting 
     228     * (reg_uri is not empty). 
     229     */ 
     230    pj_bool_t           has_registration; 
     231 
     232    /** 
     233     * An up to date expiration interval for account registration session. 
     234     */ 
     235    int                 expires; 
     236 
     237    /** 
     238     * Last registration status code. If status code is zero, the account 
     239     * is currently not registered. Any other value indicates the SIP 
     240     * status code of the registration. 
     241     */ 
     242    pjsip_status_code   status; 
     243 
     244    /** 
     245     * String describing the registration status. 
     246     */ 
     247    pj_str_t            status_text; 
     248 
     249    /** 
     250     * Presence online status for this account. 
     251     */ 
     252    pj_bool_t           online_status; 
     253 
     254    /** 
     255     * Buffer that is used internally to store the status text. 
     256     */ 
     257    char                buf_[PJ_ERR_MSG_SIZE]; 
     258 
     259} pjsua_acc_info; 
     260 
     261 
     262 
     263/** 
     264 * STUN configuration. 
     265 */ 
     266typedef struct pjsua_stun_config 
     267{ 
     268    /** 
     269     * The first STUN server IP address or hostname. 
     270     */ 
     271    pj_str_t    stun_srv1; 
     272 
     273    /** 
     274     * Port number of the first STUN server. 
     275     * If zero, default STUN port will be used. 
     276     */ 
     277    unsigned    stun_port1; 
     278     
     279    /** 
     280     * Optional second STUN server IP address or hostname, for which the 
     281     * result of the mapping request will be compared to. If the value 
     282     * is empty, only one STUN server will be used. 
     283     */ 
     284    pj_str_t    stun_srv2; 
     285 
     286    /** 
     287     * Port number of the second STUN server. 
     288     * If zero, default STUN port will be used. 
     289     */ 
     290    unsigned    stun_port2; 
     291 
     292} pjsua_stun_config; 
     293 
     294 
     295 
     296/** 
     297 * Call this function to initialize STUN config with default values. 
     298 * 
     299 * @param cfg       The STUN config to be initialized. 
     300 */ 
     301PJ_INLINE(void) pjsua_stun_config_default(pjsua_stun_config *cfg) 
     302{ 
     303    pj_memset(cfg, 0, sizeof(*cfg)); 
     304} 
     305 
     306 
     307/** 
     308 * Transport configuration for creating UDP transports for both SIP 
     309 * and media. 
     310 */ 
     311typedef struct pjsua_transport_config 
     312{ 
     313    /** 
     314     * UDP port number to bind locally. This setting MUST be specified 
     315     * even when default port is desired. If the value is zero, the 
     316     * transport will be bound to any available port, and application 
     317     * can query the port by querying the transport info. 
     318     */ 
     319    unsigned            port; 
     320 
     321    /** 
     322     * Optional address where the socket should be bound. 
     323     */ 
     324    pj_in_addr          ip_addr; 
     325 
     326    /** 
     327     * Flag to indicate whether STUN should be used. 
     328     */ 
     329    pj_bool_t           use_stun; 
     330 
     331    /** 
     332     * STUN configuration, must be specified when STUN is used. 
     333     */ 
     334    pjsua_stun_config   stun_config; 
     335 
     336} pjsua_transport_config; 
     337 
     338 
     339/** 
     340 * Call this function to initialize UDP config with default values. 
     341 * 
     342 * @param cfg       The UDP config to be initialized. 
     343 */ 
     344PJ_INLINE(void) pjsua_transport_config_default(pjsua_transport_config *cfg) 
     345{ 
     346    pj_memset(cfg, 0, sizeof(*cfg)); 
     347} 
     348 
     349 
     350/** 
     351 * Normalize STUN config. 
     352 */ 
     353PJ_INLINE(void) pjsua_normalize_stun_config( pjsua_stun_config *cfg ) 
     354{ 
     355    if (cfg->stun_srv1.slen) { 
     356 
     357        if (cfg->stun_port1 == 0) 
     358            cfg->stun_port1 = 3478; 
     359 
     360        if (cfg->stun_srv2.slen == 0) { 
     361            cfg->stun_srv2 = cfg->stun_srv1; 
     362            cfg->stun_port2 = cfg->stun_port1; 
     363        } else { 
     364            if (cfg->stun_port2 == 0) 
     365                cfg->stun_port2 = 3478; 
     366        } 
     367 
     368    } else { 
     369        cfg->stun_port1 = 0; 
     370        cfg->stun_srv2.slen = 0; 
     371        cfg->stun_port2 = 0; 
     372    } 
     373} 
     374 
     375 
     376/** 
     377 * Duplicate transport config. 
     378 */ 
     379PJ_INLINE(void) pjsua_transport_config_dup(pj_pool_t *pool, 
     380                                           pjsua_transport_config *dst, 
     381                                           const pjsua_transport_config *src) 
     382{ 
     383    pj_memcpy(dst, src, sizeof(*src)); 
     384 
     385    if (src->stun_config.stun_srv1.slen) { 
     386        pj_strdup_with_null(pool, &dst->stun_config.stun_srv1, 
     387                            &src->stun_config.stun_srv1); 
     388    } 
     389 
     390    if (src->stun_config.stun_srv2.slen) { 
     391        pj_strdup_with_null(pool, &dst->stun_config.stun_srv2, 
     392                            &src->stun_config.stun_srv2); 
     393    } 
     394 
     395    pjsua_normalize_stun_config(&dst->stun_config); 
     396} 
     397 
     398 
     399 
     400/** 
     401 * Transport info. 
     402 */ 
     403typedef struct pjsua_transport_info 
     404{ 
     405    /** 
     406     * PJSUA transport identification. 
     407     */ 
     408    pjsua_transport_id      id; 
     409 
     410    /** 
     411     * Transport type. 
     412     */ 
     413    pjsip_transport_type_e  type; 
     414 
     415    /** 
     416     * Transport type name. 
     417     */ 
     418    pj_str_t                type_name; 
     419 
     420    /** 
     421     * Transport string info/description. 
     422     */ 
     423    pj_str_t                info; 
     424 
     425    /** 
     426     * Transport flag (see ##pjsip_transport_flags_e). 
     427     */ 
     428    unsigned                flag; 
     429 
     430    /** 
     431     * Local address length. 
     432     */ 
     433    unsigned                addr_len; 
     434 
     435    /** 
     436     * Local/bound address. 
     437     */ 
     438    pj_sockaddr             local_addr; 
     439 
     440    /** 
     441     * Published address (or transport address name). 
     442     */ 
     443    pjsip_host_port         local_name; 
     444 
     445    /** 
     446     * Current number of objects currently referencing this transport. 
     447     */ 
     448    unsigned                usage_count; 
     449 
     450 
     451} pjsua_transport_info; 
     452 
     453 
     454/** 
     455 * Media configuration. 
     456 */ 
     457typedef struct pjsua_media_config 
     458{ 
     459    /** 
     460     * Clock rate to be applied to the conference bridge. 
     461     * If value is zero, default clock rate will be used (16KHz). 
     462     */ 
     463    unsigned            clock_rate; 
     464 
     465    /** 
     466     * Specify maximum number of media ports to be created in the 
     467     * conference bridge. Since all media terminate in the bridge 
     468     * (calls, file player, file recorder, etc), the value must be 
     469     * large enough to support all of them. However, the larger 
     470     * the value, the more computations are performed. 
     471     */ 
     472    unsigned            max_media_ports; 
     473 
     474    /** 
     475     * Specify whether the media manager should manage its own 
     476     * ioqueue for the RTP/RTCP sockets. If yes, ioqueue will be created 
     477     * and at least one worker thread will be created too. If no, 
     478     * the RTP/RTCP sockets will share the same ioqueue as SIP sockets, 
     479     * and no worker thread is needed. 
     480     * 
     481     * Normally application would say yes here, unless it wants to 
     482     * run everything from a single thread. 
     483     */ 
     484    pj_bool_t           has_ioqueue; 
     485 
     486    /** 
     487     * Specify the number of worker threads to handle incoming RTP 
     488     * packets. A value of one is recommended for most applications. 
     489     */ 
     490    unsigned            thread_cnt; 
     491 
     492 
     493} pjsua_media_config; 
     494 
     495 
     496/** 
     497 * Use this function to initialize media config. 
     498 * 
     499 * @param cfg   The media config to be initialized. 
     500 */ 
     501PJ_INLINE(void) pjsua_media_config_default(pjsua_media_config *cfg) 
     502{ 
     503    pj_memset(cfg, 0, sizeof(*cfg)); 
     504 
     505    cfg->clock_rate = 16000; 
     506    cfg->max_media_ports = 32; 
     507    cfg->has_ioqueue = PJ_TRUE; 
     508    cfg->thread_cnt = 1; 
     509} 
     510 
     511 
     512 
     513/** 
     514 * Logging configuration. 
     515 */ 
     516typedef struct pjsua_logging_config 
     517{ 
     518    /** 
     519     * Log incoming and outgoing SIP message? Yes! 
    147520     */ 
    148521    pj_bool_t   msg_logging; 
    149522 
    150     /** Maximum calls to support (default: 4) */ 
    151     unsigned    max_calls; 
    152  
    153     /** Maximum slots in the conference bridge (default: 0/calculated 
    154      *  as max_calls*2 
    155      */ 
    156     unsigned    conf_ports; 
    157  
    158     /** Number of worker threads (value >=0, default: 1) */ 
    159     unsigned    thread_cnt; 
    160  
    161     /** Separate ioqueue for media? (default: yes) */ 
    162     pj_bool_t   media_has_ioqueue; 
    163  
    164     /** Number of worker thread for media (value >=0, default: 1) */ 
    165     unsigned    media_thread_cnt; 
    166  
    167     /** First STUN server IP address. When STUN is configured, then the 
    168      *  two STUN server settings must be fully set. 
    169      *  (default: none)  
    170      */ 
    171     pj_str_t    stun_srv1; 
    172  
    173     /** First STUN port number */ 
    174     unsigned    stun_port1; 
    175  
    176     /** Second STUN server IP address */ 
    177     pj_str_t    stun_srv2; 
    178  
    179     /** Second STUN server port number */ 
    180     unsigned    stun_port2; 
    181  
    182     /** Sound player device ID (default: 0) */ 
    183     unsigned    snd_player_id; 
    184  
    185     /** Sound capture device ID (default: 0) */ 
    186     unsigned    snd_capture_id; 
    187  
    188     /** Internal clock rate (to be applied to sound devices and conference 
    189      *  bridge, default is 0/follows the codec, or 44100 for MacOS). 
    190      */ 
    191     unsigned    clock_rate; 
    192  
    193     /** Do not use sound device (default: 0). */ 
    194     pj_bool_t   null_audio; 
    195  
    196     /** WAV file to load for auto_play (default: NULL) */ 
    197     pj_str_t    wav_file; 
    198  
    199     /** Auto play WAV file for calls? (default: no) */ 
    200     pj_bool_t   auto_play; 
    201  
    202     /** Auto loopback calls? (default: no) */ 
    203     pj_bool_t   auto_loop; 
    204  
    205     /** Automatically put calls to conference? (default: no) */ 
    206     pj_bool_t   auto_conf; 
    207  
    208     /** Speex codec complexity? (default: 10) */ 
    209     unsigned    complexity; 
    210  
    211     /** Speex codec quality? (default: 10) */ 
    212     unsigned    quality; 
    213  
    214     /** Codec ptime? (default: 0 (follows the codec)) */ 
    215     unsigned    ptime; 
    216  
    217     /** Number of additional codecs/"--add-codec" with pjsua (default: 0) */ 
    218     unsigned    codec_cnt; 
    219  
    220     /** Additional codecs/"--add-codec" options */ 
    221     pj_str_t    codec_arg[32]; 
    222  
    223     /** SIP status code to be automatically sent to incoming calls 
    224      *  (default: 100). 
    225      */ 
    226     unsigned    auto_answer; 
    227  
    228     /** Periodic time to refresh call with re-INVITE (default: 0) 
    229      */ 
    230     unsigned    uas_refresh; 
    231  
    232     /** Maximum incoming call duration (default: 3600) */ 
    233     unsigned    uas_duration; 
    234  
    235     /** Outbound proxy (default: none) */ 
    236     pj_str_t    outbound_proxy; 
    237  
    238     /** Number of SIP accounts */ 
    239     unsigned    acc_cnt; 
    240  
    241     /** SIP accounts configuration */ 
    242     pjsua_acc_config    acc_config[32]; 
    243  
    244     /** Logging verbosity (default: 5). */ 
    245     unsigned    log_level; 
    246  
    247     /** Logging to be displayed to stdout (default: 4) */ 
    248     unsigned    app_log_level; 
    249  
    250     /** Log decoration */ 
    251     unsigned    log_decor; 
    252  
    253     /** Optional log filename (default: NULL) */ 
     523    /** 
     524     * Input verbosity level. Value 5 is reasonable. 
     525     */ 
     526    unsigned    level; 
     527 
     528    /** 
     529     * Verbosity level for console. Value 4 is reasonable. 
     530     */ 
     531    unsigned    console_level; 
     532 
     533    /** 
     534     * Log decoration. 
     535     */ 
     536    unsigned    decor; 
     537 
     538    /** 
     539     * Optional log filename. 
     540     */ 
    254541    pj_str_t    log_filename; 
    255542 
    256     /** Number of buddies in address book (default: 0) */ 
    257     unsigned    buddy_cnt; 
    258  
    259     /** Buddies URI */ 
    260     pj_str_t    buddy_uri[256]; 
    261 }; 
    262  
    263  
    264 /** 
    265  * @see pjsua_config 
    266  */ 
    267 typedef struct pjsua_config pjsua_config; 
    268  
     543    /** 
     544     * Optional callback function to be called to write log to  
     545     * application specific device. This function will be called for 
     546     * log messages on input verbosity level. 
     547     */ 
     548    void       (*cb)(int level, const char *data, pj_size_t len); 
     549 
     550 
     551} pjsua_logging_config; 
     552 
     553 
     554/** 
     555 * Use this function to initialize logging config. 
     556 * 
     557 * @param cfg   The logging config to be initialized. 
     558 */ 
     559PJ_INLINE(void) pjsua_logging_config_default(pjsua_logging_config *cfg) 
     560{ 
     561    pj_memset(cfg, 0, sizeof(*cfg)); 
     562 
     563    cfg->msg_logging = PJ_TRUE; 
     564    cfg->level = 5; 
     565    cfg->console_level = 4; 
     566    cfg->decor = PJ_LOG_HAS_SENDER | PJ_LOG_HAS_TIME |  
     567                 PJ_LOG_HAS_MICRO_SEC | PJ_LOG_HAS_NEWLINE; 
     568} 
     569 
     570/** 
     571 * Use this function to duplicate logging config. 
     572 * 
     573 * @param pool      Pool to use. 
     574 * @param dst       Destination config. 
     575 * @param src       Source config. 
     576 */ 
     577PJ_INLINE(void) pjsua_logging_config_dup(pj_pool_t *pool, 
     578                                         pjsua_logging_config *dst, 
     579                                         const pjsua_logging_config *src) 
     580{ 
     581    pj_memcpy(dst, src, sizeof(*src)); 
     582    pj_strdup_with_null(pool, &dst->log_filename, &src->log_filename); 
     583} 
     584 
     585 
     586/** 
     587 * Buddy configuration. 
     588 */ 
     589typedef struct pjsua_buddy_config 
     590{ 
     591    /** 
     592     * Buddy URL or name address. 
     593     */ 
     594    pj_str_t    uri; 
     595 
     596    /** 
     597     * Specify whether presence subscription should start immediately. 
     598     */ 
     599    pj_bool_t   subscribe; 
     600 
     601} pjsua_buddy_config; 
     602 
     603 
     604/** 
     605 * Buddy's online status. 
     606 */ 
     607typedef enum pjsua_buddy_status 
     608{ 
     609    /** 
     610     * Online status is unknown (possibly because no presence subscription 
     611     * has been established). 
     612     */ 
     613    PJSUA_BUDDY_STATUS_UNKNOWN, 
     614 
     615    /** 
     616     * Buddy is known to be offline. 
     617     */ 
     618    PJSUA_BUDDY_STATUS_ONLINE, 
     619 
     620    /** 
     621     * Buddy is offline. 
     622     */ 
     623    PJSUA_BUDDY_STATUS_OFFLINE, 
     624 
     625} pjsua_buddy_status; 
     626 
     627 
     628 
     629/** 
     630 * Buddy info. 
     631 */ 
     632typedef struct pjsua_buddy_info 
     633{ 
     634    /** 
     635     * The buddy ID. 
     636     */ 
     637    pjsua_buddy_id      id; 
     638 
     639    /** 
     640     * The full URI of the buddy, as specified in the configuration. 
     641     */ 
     642    pj_str_t            uri; 
     643 
     644    /** 
     645     * Buddy's Contact, only available when presence subscription has 
     646     * been established to the buddy. 
     647     */ 
     648    pj_str_t            contact; 
     649 
     650    /** 
     651     * Buddy's online status. 
     652     */ 
     653    pjsua_buddy_status  status; 
     654 
     655    /** 
     656     * Text to describe buddy's online status. 
     657     */ 
     658    pj_str_t            status_text; 
     659 
     660    /** 
     661     * Flag to indicate that we should monitor the presence information for 
     662     * this buddy (normally yes, unless explicitly disabled). 
     663     */ 
     664    pj_bool_t           monitor_pres; 
     665 
     666    /** 
     667     * Internal buffer. 
     668     */ 
     669    char                buf_[256]; 
     670 
     671} pjsua_buddy_info; 
     672 
     673 
     674/** 
     675 * Codec config. 
     676 */ 
     677typedef struct pjsua_codec_info 
     678{ 
     679    /** 
     680     * Codec unique identification. 
     681     */ 
     682    pj_str_t            codec_id; 
     683 
     684    /** 
     685     * Codec priority (integer 0-255). 
     686     */ 
     687    pj_uint8_t          priority; 
     688 
     689    /** 
     690     * Internal buffer. 
     691     */ 
     692    char                buf_[32]; 
     693 
     694} pjsua_codec_info; 
    269695 
    270696 
     
    272698 * Application callbacks. 
    273699 */ 
    274 struct pjsua_callback 
     700typedef struct pjsua_callback 
    275701{ 
    276702    /** 
     
    279705     * detail call states. 
    280706     */ 
    281     void (*on_call_state)(int call_index, pjsip_event *e); 
     707    void (*on_call_state)(pjsua_call_id call_id, pjsip_event *e); 
    282708 
    283709    /** 
    284710     * Notify application on incoming call. 
    285711     */ 
    286     void (*on_incoming_call)(pjsua_acc_id acc_id, int call_index, 
     712    void (*on_incoming_call)(pjsua_acc_id acc_id, pjsua_call_id call_id, 
    287713                             pjsip_rx_data *rdata); 
     714 
     715    /** 
     716     * Notify application when media state in the call has changed. 
     717     * Normal application would need to implement this callback, e.g. 
     718     * to connect the call's media to sound device. 
     719     */ 
     720    void (*on_call_media_state)(pjsua_call_id call_id); 
    288721 
    289722    /** 
     
    294727     * transfer. 
    295728     */ 
    296     void (*on_call_transfered)(int call_index, 
     729    void (*on_call_transfered)(pjsua_call_id call_id, 
    297730                               const pj_str_t *dst, 
    298731                               pjsip_status_code *code); 
     
    313746    /** 
    314747     * Notify application on incoming pager (i.e. MESSAGE request). 
    315      * Argument call_index will be -1 if MESSAGE request is not related to an  
     748     * Argument call_id will be -1 if MESSAGE request is not related to an 
    316749     * existing call. 
    317750     */ 
    318     void (*on_pager)(int call_index, const pj_str_t *from, 
    319                      const pj_str_t *to, const pj_str_t *txt); 
     751    void (*on_pager)(pjsua_call_id call_id, const pj_str_t *from, 
     752                     const pj_str_t *to, const pj_str_t *contact, 
     753                     const pj_str_t *mime_type, const pj_str_t *body); 
     754 
     755    /** 
     756     * Notify application about the delivery status of outgoing pager 
     757     * request. 
     758     * 
     759     * @param call_id       Containts the ID of the call where the IM was 
     760     *                      sent, or PJSUA_INVALID_ID if the IM was sent 
     761     *                      outside call context. 
     762     * @param to            Destination URI. 
     763     * @param body          Message body. 
     764     * @param user_data     Arbitrary data that was specified when sending 
     765     *                      IM message. 
     766     * @param status        Delivery status. 
     767     * @param reason        Delivery status reason. 
     768     */ 
     769    void (*on_pager_status)(pjsua_call_id call_id, 
     770                            const pj_str_t *to, 
     771                            const pj_str_t *body, 
     772                            void *user_data, 
     773                            pjsip_status_code status, 
     774                            const pj_str_t *reason); 
    320775 
    321776    /** 
    322777     * Notify application about typing indication. 
    323778     */ 
    324     void (*on_typing)(int call_index, const pj_str_t *from, 
    325                       const pj_str_t *to, pj_bool_t is_typing); 
    326  
    327 }; 
    328  
    329 /** 
    330  * @see pjsua_callback 
    331  */ 
    332 typedef struct pjsua_callback pjsua_callback; 
     779    void (*on_typing)(pjsua_call_id call_id, const pj_str_t *from, 
     780                      const pj_str_t *to, const pj_str_t *contact, 
     781                      pj_bool_t is_typing); 
     782 
     783} pjsua_callback; 
     784 
     785 
     786 
     787 
     788/** 
     789 * PJSUA settings. 
     790 */ 
     791typedef struct pjsua_config 
     792{ 
     793 
     794    /**  
     795     * Maximum calls to support (default: 4)  
     796     */ 
     797    unsigned        max_calls; 
     798 
     799    /**  
     800     * Number of worker threads. Normally application will want to have at 
     801     * least one worker thread, unless when it wants to poll the library 
     802     * periodically, which in this case the worker thread can be set to 
     803     * zero. 
     804     */ 
     805    unsigned        thread_cnt; 
     806 
     807    /** 
     808     * Number of outbound proxies in the array. 
     809     */ 
     810    unsigned        outbound_proxy_cnt; 
     811 
     812    /**  
     813     * Specify the URL of outbound proxies to visit for all outgoing requests. 
     814     * The outbound proxies will be used for all accounts, and it will 
     815     * be used to build the route set for outgoing requests. The final 
     816     * route set for outgoing requests will consists of the outbound proxies 
     817     * and the proxy configured in the account. 
     818     */ 
     819    pj_str_t        outbound_proxy[4]; 
     820 
     821    /**  
     822     * Number of credentials in the credential array. 
     823     */ 
     824    unsigned        cred_count; 
     825 
     826    /**  
     827     * Array of credentials. These credentials will be used by all accounts, 
     828     * and can be used to authenticate against outbound proxies. 
     829     */ 
     830    pjsip_cred_info cred_info[PJSUA_ACC_MAX_PROXIES]; 
     831 
     832    /** 
     833     * Application callback. 
     834     */ 
     835    pjsua_callback  cb; 
     836 
     837} pjsua_config; 
     838 
     839 
     840/** 
     841 * Use this function to initialize pjsua config. 
     842 * 
     843 * @param cfg   pjsua config to be initialized. 
     844 */ 
     845PJ_INLINE(void) pjsua_config_default(pjsua_config *cfg) 
     846{ 
     847    pj_memset(cfg, 0, sizeof(*cfg)); 
     848 
     849    cfg->max_calls = 4; 
     850    cfg->thread_cnt = 1; 
     851} 
     852 
     853 
     854/** 
     855 * Duplicate credential. 
     856 */ 
     857PJ_INLINE(void) pjsip_cred_dup( pj_pool_t *pool, 
     858                                pjsip_cred_info *dst, 
     859                                const pjsip_cred_info *src) 
     860{ 
     861    pj_strdup_with_null(pool, &dst->realm, &src->realm); 
     862    pj_strdup_with_null(pool, &dst->scheme, &src->scheme); 
     863    pj_strdup_with_null(pool, &dst->username, &src->username); 
     864    pj_strdup_with_null(pool, &dst->data, &src->data); 
     865 
     866} 
     867 
     868 
     869/** 
     870 * Duplicate pjsua_config. 
     871 */ 
     872PJ_INLINE(void) pjsua_config_dup(pj_pool_t *pool, 
     873                                 pjsua_config *dst, 
     874                                 const pjsua_config *src) 
     875{ 
     876    unsigned i; 
     877 
     878    pj_memcpy(dst, src, sizeof(*src)); 
     879 
     880    for (i=0; i<src->outbound_proxy_cnt; ++i) { 
     881        pj_strdup_with_null(pool, &dst->outbound_proxy[i], 
     882                            &src->outbound_proxy[i]); 
     883    } 
     884 
     885    for (i=0; i<src->cred_count; ++i) { 
     886        pjsip_cred_dup(pool, &dst->cred_info[i], &src->cred_info[i]); 
     887    } 
     888} 
     889 
     890 
     891/** 
     892 * Call media status. 
     893 */ 
     894typedef enum pjsua_call_media_status 
     895{ 
     896    PJSUA_CALL_MEDIA_NONE, 
     897    PJSUA_CALL_MEDIA_ACTIVE, 
     898    PJSUA_CALL_MEDIA_LOCAL_HOLD, 
     899    PJSUA_CALL_MEDIA_REMOTE_HOLD, 
     900} pjsua_call_media_status; 
    333901 
    334902 
     
    336904 * Call info. 
    337905 */ 
    338 struct pjsua_call_info 
    339 { 
    340     unsigned            index; 
    341     pj_bool_t           active; 
     906typedef struct pjsua_call_info 
     907{ 
     908    /** Call identification. */ 
     909    pjsua_call_id       id; 
     910 
     911    /** Initial call role (UAC == caller) */ 
    342912    pjsip_role_e        role; 
     913 
     914    /** Local URI */ 
    343915    pj_str_t            local_info; 
     916 
     917    /** Local Contact */ 
     918    pj_str_t            local_contact; 
     919 
     920    /** Remote URI */ 
    344921    pj_str_t            remote_info; 
     922 
     923    /** Remote contact */ 
     924    pj_str_t            remote_contact; 
     925 
     926    /** Dialog Call-ID string. */ 
     927    pj_str_t            call_id; 
     928 
     929    /** Call state */ 
    345930    pjsip_inv_state     state; 
     931 
     932    /** Text describing the state */ 
    346933    pj_str_t            state_text; 
     934 
     935    /** Last status code heard, which can be used as cause code */ 
    347936    pjsip_status_code   last_status; 
     937 
     938    /** The reason phrase describing the status. */ 
    348939    pj_str_t            last_status_text; 
     940 
     941    /** Call media status. */ 
     942    pjsua_call_media_status media_status; 
     943 
     944    /** Media direction */ 
     945    pjmedia_dir         media_dir; 
     946 
     947    /** The conference port number for the call */ 
     948    pjsua_conf_port_id  conf_slot; 
     949 
     950    /** Up-to-date call connected duration (zero when call is not  
     951     *  established) 
     952     */ 
    349953    pj_time_val         connect_duration; 
     954 
     955    /** Total call duration, including set-up time */ 
    350956    pj_time_val         total_duration; 
    351     pj_bool_t           has_media; 
    352     pjsua_conf_port_id  conf_slot; 
    353 }; 
    354  
    355 typedef struct pjsua_call_info pjsua_call_info; 
    356  
    357  
    358 enum pjsua_buddy_status 
    359 { 
    360     PJSUA_BUDDY_STATUS_UNKNOWN, 
    361     PJSUA_BUDDY_STATUS_ONLINE, 
    362     PJSUA_BUDDY_STATUS_OFFLINE, 
    363 }; 
    364  
    365 typedef enum pjsua_buddy_status pjsua_buddy_status; 
    366  
    367  
    368 /** 
    369  * Buddy info. 
    370  */ 
    371 struct pjsua_buddy_info 
    372 { 
    373     pjsua_buddy_id      index; 
    374     pj_bool_t           is_valid; 
     957 
     958    /** Internal */ 
     959    struct { 
     960        char    local_info[128]; 
     961        char    local_contact[128]; 
     962        char    remote_info[128]; 
     963        char    remote_contact[128]; 
     964        char    call_id[128]; 
     965        char    last_status_text[128]; 
     966    } buf_; 
     967 
     968} pjsua_call_info; 
     969 
     970 
     971 
     972 
     973/** 
     974 * Conference port info. 
     975 */ 
     976typedef struct pjsua_conf_port_info 
     977{ 
     978    /** Conference port number. */ 
     979    pjsua_conf_port_id  slot_id; 
     980 
     981    /** Port name. */ 
    375982    pj_str_t            name; 
    376     pj_str_t            display_name; 
    377     pj_str_t            host; 
    378     unsigned            port; 
    379     pj_str_t            uri; 
    380     pjsua_buddy_status  status; 
    381     pj_str_t            status_text; 
    382     pj_bool_t           monitor; 
    383 }; 
    384  
    385 typedef struct pjsua_buddy_info pjsua_buddy_info; 
    386  
    387  
    388 /** 
    389  * Account info. 
    390  */ 
    391 struct pjsua_acc_info 
    392 { 
    393     pjsua_acc_id        index; 
    394     pj_str_t            acc_id; 
    395     pj_bool_t           has_registration; 
    396     int                 expires; 
    397     pjsip_status_code   status; 
    398     pj_str_t            status_text; 
    399     pj_bool_t           online_status; 
    400     char                buf[PJ_ERR_MSG_SIZE]; 
    401 }; 
    402  
    403 typedef struct pjsua_acc_info pjsua_acc_info; 
    404  
    405  
    406 /** 
    407  * Conference port info. 
    408  */ 
    409 struct pjsua_conf_port_info 
    410 { 
    411     pjsua_conf_port_id  slot_id; 
    412     pj_str_t            name; 
     983 
     984    /** Clock rate. */ 
    413985    unsigned            clock_rate; 
     986 
     987    /** Number of channels. */ 
    414988    unsigned            channel_count; 
     989 
     990    /** Samples per frame */ 
    415991    unsigned            samples_per_frame; 
     992 
     993    /** Bits per sample */ 
    416994    unsigned            bits_per_sample; 
     995 
     996    /** Number of listeners in the array. */ 
    417997    unsigned            listener_cnt; 
    418     pjsua_conf_port_id  listeners[256]; 
    419 }; 
    420  
    421  
    422 typedef struct pjsua_conf_port_info pjsua_conf_port_info; 
     998 
     999    /** Array of listeners (in other words, ports where this port is  
     1000     *  transmitting to. 
     1001     */ 
     1002    pjsua_conf_port_id  listeners[PJSUA_MAX_CONF_PORTS]; 
     1003 
     1004} pjsua_conf_port_info; 
     1005 
     1006 
     1007/** 
     1008 * This structure holds information about custom media transport to 
     1009 * be registered to pjsua. 
     1010 */ 
     1011typedef struct pjsua_media_transport 
     1012{ 
     1013    /** 
     1014     * Media socket information containing the address information 
     1015     * of the RTP and RTCP socket. 
     1016     */ 
     1017    pjmedia_sock_info    skinfo; 
     1018 
     1019    /** 
     1020     * The media transport instance. 
     1021     */ 
     1022    pjmedia_transport   *transport; 
     1023 
     1024} pjsua_media_transport; 
     1025 
     1026 
     1027/** 
     1028 * This structure describes additional information to be sent with 
     1029 * outgoing SIP message. 
     1030 */ 
     1031typedef struct pjsua_msg_data 
     1032{ 
     1033    /** 
     1034     * Additional message headers as linked list. 
     1035     */ 
     1036    pjsip_hdr   hdr_list; 
     1037 
     1038    /** 
     1039     * MIME type of optional message body.  
     1040     */ 
     1041    pj_str_t    content_type; 
     1042 
     1043    /** 
     1044     * Optional message body. 
     1045     */ 
     1046    pj_str_t    msg_body; 
     1047 
     1048} pjsua_msg_data; 
     1049 
     1050 
     1051/** 
     1052 * Initialize message data. 
     1053 * 
     1054 * @param msg_data  Message data to be initialized. 
     1055 */ 
     1056PJ_INLINE(void) pjsua_msg_data_init(pjsua_msg_data *msg_data) 
     1057{ 
     1058    pj_memset(msg_data, 0, sizeof(*msg_data)); 
     1059    pj_list_init(&msg_data->hdr_list); 
     1060} 
    4231061 
    4241062 
    4251063/***************************************************************************** 
    426  * PJSUA API (defined in pjsua_core.c). 
    427  */ 
    428  
    429 /** 
    430  * Initialize pjsua settings with default parameters. 
    431  */ 
    432 PJ_DECL(void) pjsua_default_config(pjsua_config *cfg); 
    433  
    434  
    435 /** 
    436  * Validate configuration. 
    437  */ 
    438 PJ_DECL(pj_status_t) pjsua_test_config(const pjsua_config *cfg, 
    439                                        char *errmsg, 
    440                                        int len); 
    441  
    442  
    443 /** 
    444  * Instantiate pjsua application. This initializes pjlib/pjlib-util, and  
    445  * creates memory pool factory to be used by application. 
     1064 * PJSUA Core API 
     1065 */ 
     1066 
     1067 
     1068/** 
     1069 * Instantiate pjsua application. Application must call this function before 
     1070 * calling any other functions, to make sure that the underlying libraries 
     1071 * are properly initialized. Once this function has returned success, 
     1072 * application must call pjsua_destroy() before quitting. 
     1073 * 
     1074 * @return              PJ_SUCCESS on success, or the appropriate error code. 
    4461075 */ 
    4471076PJ_DECL(pj_status_t) pjsua_create(void); 
     
    4491078 
    4501079/** 
    451  * Initialize pjsua application with the specified settings. 
    452  * 
    453  * This will initialize all libraries, create endpoint instance, and register 
    454  * pjsip modules.  
    455  * 
    456  * Application may register module after calling this function. 
    457  */ 
    458 PJ_DECL(pj_status_t) pjsua_init(const pjsua_config *cfg, 
    459                                 const pjsua_callback *cb); 
    460  
    461  
    462 /** 
    463  * Start pjsua stack. Application calls this after pjsua settings has been 
    464  * configured. 
    465  * 
    466  * This will start the transport, worker threads (if any), and registration  
    467  * process, if registration is configured. 
     1080 * Initialize pjsua with the specified settings. All the settings are  
     1081 * optional, and the default values will be used when the config is not 
     1082 * specified. 
     1083 * 
     1084 * @param ua_cfg        User agent configuration. 
     1085 * @param log_cfg       Optional logging configuration. 
     1086 * @param media_cfg     Optional media configuration. 
     1087 * 
     1088 * @return              PJ_SUCCESS on success, or the appropriate error code. 
     1089 */ 
     1090PJ_DECL(pj_status_t) pjsua_init(const pjsua_config *ua_cfg, 
     1091                                const pjsua_logging_config *log_cfg, 
     1092                                const pjsua_media_config *media_cfg); 
     1093 
     1094 
     1095/** 
     1096 * Application is recommended to call this function after all initialization 
     1097 * is done, so that the library can do additional checking set up 
     1098 * additional  
     1099 * 
     1100 * @return              PJ_SUCCESS on success, or the appropriate error code. 
    4681101 */ 
    4691102PJ_DECL(pj_status_t) pjsua_start(void); 
    4701103 
    471 /** 
    472  * Destroy pjsua. 
     1104 
     1105/** 
     1106 * Destroy pjsua. This function must be called once PJSUA is created. To 
     1107 * make it easier for application, application may call this function 
     1108 * several times with no danger. 
     1109 * 
     1110 * @return              PJ_SUCCESS on success, or the appropriate error code. 
    4731111 */ 
    4741112PJ_DECL(pj_status_t) pjsua_destroy(void); 
    4751113 
    476 /** 
    477  * Poll pjsua. 
     1114 
     1115/** 
     1116 * Poll pjsua for events, and if necessary block the caller thread for 
     1117 * the specified maximum interval (in miliseconds). 
     1118 * 
     1119 * @param msec_timeout  Maximum time to wait, in miliseconds. 
     1120 * 
     1121 * @return  The number of events that have been handled during the 
     1122 *          poll. Negative value indicates error, and application 
     1123 *          can retrieve the error as (err = -return_value). 
    4781124 */ 
    4791125PJ_DECL(int) pjsua_handle_events(unsigned msec_timeout); 
     
    4811127 
    4821128/** 
    483  * Get SIP endpoint instance. 
    484  * Only valid after pjsua_init(). 
     1129 * Create memory pool. 
     1130 * 
     1131 * @param name          Optional pool name. 
     1132 * @param size          Initial size of the pool. 
     1133 * @param increment     Increment size. 
     1134 * 
     1135 * @return              The pool, or NULL when there's no memory. 
     1136 */ 
     1137PJ_DECL(pj_pool_t*) pjsua_pool_create(const char *name, pj_size_t init_size, 
     1138                                      pj_size_t increment); 
     1139 
     1140 
     1141/** 
     1142 * Application can call this function at any time (after pjsua_create(), of 
     1143 * course) to change logging settings. 
     1144 * 
     1145 * @param c             Logging configuration. 
     1146 * 
     1147 * @return              PJ_SUCCESS on success, or the appropriate error code. 
     1148 */ 
     1149PJ_DECL(pj_status_t) pjsua_reconfigure_logging(const pjsua_logging_config *c); 
     1150 
     1151 
     1152/** 
     1153 * Internal function to get SIP endpoint instance of pjsua, which is 
     1154 * needed for example to register module, create transports, etc. 
     1155 * Probably is only valid after #pjsua_init() is called. 
     1156 *  
     1157 * @return              SIP endpoint instance. 
    4851158 */ 
    4861159PJ_DECL(pjsip_endpoint*) pjsua_get_pjsip_endpt(void); 
    4871160 
    4881161/** 
    489  * Get media endpoint instance. 
    490  * Only valid after pjsua_init(). 
     1162 * Internal function to get media endpoint instance. 
     1163 * Only valid after #pjsua_init() is called. 
     1164 * 
     1165 * @return              Media endpoint instance. 
    4911166 */ 
    4921167PJ_DECL(pjmedia_endpt*) pjsua_get_pjmedia_endpt(void); 
    4931168 
    494 /** 
    495  * Replace media transport. 
    496  */ 
    497 PJ_DECL(pj_status_t) pjsua_set_call_media_transport(unsigned call_index, 
    498                                                     const pjmedia_sock_info *i, 
    499                                                     pjmedia_transport *tp); 
    500  
    5011169 
    5021170/***************************************************************************** 
    503  * PJSUA Call API (defined in pjsua_call.c). 
     1171 * PJSUA SIP Transport API. 
     1172 */ 
     1173 
     1174/** 
     1175 * Create SIP transport. 
     1176 * 
     1177 * @param type          Transport type. 
     1178 * @param cfg           Transport configuration. 
     1179 * @param p_id          Optional pointer to receive transport ID. 
     1180 * 
     1181 * @return              PJ_SUCCESS on success, or the appropriate error code. 
     1182 */ 
     1183PJ_DECL(pj_status_t) pjsua_transport_create(pjsip_transport_type_e type, 
     1184                                            const pjsua_transport_config *cfg, 
     1185                                            pjsua_transport_id *p_id); 
     1186 
     1187/** 
     1188 * Register transport that has been created by application. 
     1189 * 
     1190 * @param tp            Transport instance. 
     1191 * @param p_id          Optional pointer to receive transport ID. 
     1192 * 
     1193 * @return              PJ_SUCCESS on success, or the appropriate error code. 
     1194 */ 
     1195PJ_DECL(pj_status_t) pjsua_transport_register(pjsip_transport *tp, 
     1196                                              pjsua_transport_id *p_id); 
     1197 
     1198 
     1199/** 
     1200 * Enumerate all transports currently created in the system. 
     1201 * 
     1202 * @param id            Array to receive transport ids. 
     1203 * @param count         In input, specifies the maximum number of elements. 
     1204 *                      On return, it contains the actual number of elements. 
     1205 * 
     1206 * @return              PJ_SUCCESS on success, or the appropriate error code. 
     1207 */ 
     1208PJ_DECL(pj_status_t) pjsua_enum_transports( pjsua_transport_id id[], 
     1209                                            unsigned *count ); 
     1210 
     1211 
     1212/** 
     1213 * Get information about transports. 
     1214 * 
     1215 * @param id            Transport ID. 
     1216 * @param info          Pointer to receive transport info. 
     1217 * 
     1218 * @return              PJ_SUCCESS on success, or the appropriate error code. 
     1219 */ 
     1220PJ_DECL(pj_status_t) pjsua_transport_get_info(pjsua_transport_id id, 
     1221                                              pjsua_transport_info *info); 
     1222 
     1223 
     1224/** 
     1225 * Disable a transport or re-enable it. By default transport is always  
     1226 * enabled after it is created. Disabling a transport does not necessarily 
     1227 * close the socket, it will only discard incoming messages and prevent 
     1228 * the transport from being used to send outgoing messages. 
     1229 * 
     1230 * @param id            Transport ID. 
     1231 * @param enabled       Non-zero to enable, zero to disable. 
     1232 * 
     1233 * @return              PJ_SUCCESS on success, or the appropriate error code. 
     1234 */ 
     1235PJ_DECL(pj_status_t) pjsua_transport_set_enable(pjsua_transport_id id, 
     1236                                                pj_bool_t enabled); 
     1237 
     1238 
     1239/** 
     1240 * Close the transport. If transport is forcefully closed, it will be 
     1241 * immediately closed, and any pending transactions that are using the 
     1242 * transport may not terminate properly. Otherwise, the system will wait 
     1243 * until all transactions are closed while preventing new users from 
     1244 * using the transport, and will close the transport when it is safe to 
     1245 * do so. 
     1246 * 
     1247 * @param id            Transport ID. 
     1248 * @param force         Non-zero to immediately close the transport. This 
     1249 *                      is not recommended! 
     1250 * 
     1251 * @return              PJ_SUCCESS on success, or the appropriate error code. 
     1252 */ 
     1253PJ_DECL(pj_status_t) pjsua_transport_close( pjsua_transport_id id, 
     1254                                            pj_bool_t force ); 
     1255 
     1256 
     1257/***************************************************************************** 
     1258 * PJSUA Media Transport. 
     1259 */ 
     1260 
     1261/** 
     1262 * Create UDP media transports for all the calls. This function creates 
     1263 * one UDP media transport for each call. 
     1264 * 
     1265 * @param cfg           Media transport configuration. The "port" field in the 
     1266 *                      configuration is used as the start port to bind the 
     1267 *                      sockets. 
     1268 * 
     1269 * @return              PJ_SUCCESS on success, or the appropriate error code. 
     1270 */ 
     1271PJ_DECL(pj_status_t)  
     1272pjsua_media_transports_create(const pjsua_transport_config *cfg); 
     1273 
     1274 
     1275/** 
     1276 * Register custom media transports to be used by calls. There must 
     1277 * enough media transports for all calls. 
     1278 * 
     1279 * @param tp            The media transport array. 
     1280 * @param count         Number of elements in the array. This number MUST 
     1281 *                      match the number of maximum calls configured when 
     1282 *                      pjsua is created. 
     1283 * @param auto_delete   Flag to indicate whether the transports should be 
     1284 *                      destroyed when pjsua is shutdown. 
     1285 * 
     1286 * @return              PJ_SUCCESS on success, or the appropriate error code. 
     1287 */ 
     1288PJ_DECL(pj_status_t)  
     1289pjsua_media_transports_attach( pjsua_media_transport tp[], 
     1290                               unsigned count, 
     1291                               pj_bool_t auto_delete); 
     1292 
     1293 
     1294 
     1295/***************************************************************************** 
     1296 * PJSUA Call API. 
    5041297 */ 
    5051298 
    5061299/** 
    5071300 * Get maximum number of calls configured in pjsua. 
     1301 * 
     1302 * @return              Maximum number of calls configured. 
    5081303 */ 
    5091304PJ_DECL(unsigned) pjsua_call_get_max_count(void); 
    5101305 
    5111306/** 
    512  * Get current number of active calls. 
     1307 * Get number of currently active calls. 
     1308 * 
     1309 * @return              Number of currently active calls. 
    5131310 */ 
    5141311PJ_DECL(unsigned) pjsua_call_get_count(void); 
     1312 
     1313/** 
     1314 * Enumerate all active calls. 
     1315 * 
     1316 * @param ids           Array of account IDs to be initialized. 
     1317 * @param count         In input, specifies the maximum number of elements. 
     1318 *                      On return, it contains the actual number of elements. 
     1319 * 
     1320 * @return              PJ_SUCCESS on success, or the appropriate error code. 
     1321 */ 
     1322PJ_DECL(pj_status_t) pjsua_enum_calls(pjsua_call_id ids[], 
     1323                                      unsigned *count); 
     1324 
     1325 
     1326/** 
     1327 * Make outgoing call to the specified URI using the specified account. 
     1328 * 
     1329 * @param acc_id        The account to be used. 
     1330 * @param target        URI to be put in the request URI. 
     1331 * @param dst_uri       URI to be put in the To header (normally is the same 
     1332 *                      as the target URI). 
     1333 * @param options       Options (must be zero at the moment). 
     1334 * @param user_data     Arbitrary user data to be attached to the call, and 
     1335 *                      can be retrieved later. 
     1336 * @param msg_data      Optional headers etc to be added to outgoing INVITE 
     1337 *                      request, or NULL if no custom header is desired. 
     1338 * @param p_call_id     Pointer to receive call identification. 
     1339 * 
     1340 * @return              PJ_SUCCESS on success, or the appropriate error code. 
     1341 */ 
     1342PJ_DECL(pj_status_t) pjsua_call_make_call(pjsua_acc_id acc_id, 
     1343                                          const pj_str_t *dst_uri, 
     1344                                          unsigned options, 
     1345                                          void *user_data, 
     1346                                          const pjsua_msg_data *msg_data, 
     1347                                          pjsua_call_id *p_call_id); 
     1348 
    5151349 
    5161350/** 
    5171351 * Check if the specified call has active INVITE session and the INVITE 
    5181352 * session has not been disconnected. 
    519  */ 
    520 PJ_DECL(pj_bool_t) pjsua_call_is_active(unsigned call_index); 
    521  
    522  
    523 /** 
    524  * Check if call has a media session. 
    525  */ 
    526 PJ_DECL(pj_bool_t) pjsua_call_has_media(unsigned call_index); 
    527  
    528  
    529 /** 
    530  * Get call info. 
    531  */ 
    532 PJ_DECL(pj_status_t) pjsua_call_get_info(unsigned call_index, 
     1353 * 
     1354 * @param call_id       Call identification. 
     1355 * 
     1356 * @return              Non-zero if call is active. 
     1357 */ 
     1358PJ_DECL(pj_bool_t) pjsua_call_is_active(pjsua_call_id call_id); 
     1359 
     1360 
     1361/** 
     1362 * Check if call has an active media session. 
     1363 * 
     1364 * @param call_id       Call identification. 
     1365 * 
     1366 * @return              Non-zero if yes. 
     1367 */ 
     1368PJ_DECL(pj_bool_t) pjsua_call_has_media(pjsua_call_id call_id); 
     1369 
     1370 
     1371/** 
     1372 * Get the conference port identification associated with the call. 
     1373 * 
     1374 * @param call_id       Call identification. 
     1375 * 
     1376 * @return              Conference port ID, or PJSUA_INVALID_ID when the  
     1377 *                      media has not been established or is not active. 
     1378 */ 
     1379PJ_DECL(pjsua_conf_port_id) pjsua_call_get_conf_port(pjsua_call_id call_id); 
     1380 
     1381/** 
     1382 * Obtain detail information about the specified call. 
     1383 * 
     1384 * @param call_id       Call identification. 
     1385 * @param info          Call info to be initialized. 
     1386 * 
     1387 * @return              PJ_SUCCESS on success, or the appropriate error code. 
     1388 */ 
     1389PJ_DECL(pj_status_t) pjsua_call_get_info(pjsua_call_id call_id, 
    5331390                                         pjsua_call_info *info); 
    5341391 
    5351392 
    5361393/** 
    537  * Duplicate call info. 
    538  */ 
    539 PJ_DECL(void) pjsua_call_info_dup(pj_pool_t *pool, 
    540                                   pjsua_call_info *dst_info, 
    541                                   const pjsua_call_info *src_info); 
    542  
    543  
    544 /** 
    545  * Make outgoing call. 
    546  */ 
    547 PJ_DECL(pj_status_t) pjsua_call_make_call(unsigned acc_id, 
    548                                           const pj_str_t *dst_uri, 
    549                                           int *p_call_index); 
    550  
    551  
    552 /** 
    553  * Answer call. 
    554  */ 
    555 PJ_DECL(pj_status_t) pjsua_call_answer(int call_index, int code); 
    556  
    557 /** 
    558  * Hangup call. 
    559  */ 
    560 PJ_DECL(void) pjsua_call_hangup(int call_index); 
    561  
    562  
    563 /** 
    564  * Put call on-hold. 
    565  */ 
    566 PJ_DECL(pj_status_t) pjsua_call_set_hold(int call_index); 
     1394 * Attach application specific data to the call. 
     1395 * 
     1396 * @param call_id       Call identification. 
     1397 * @param user_data     Arbitrary data to be attached to the call. 
     1398 * 
     1399 * @return              The user data. 
     1400 */ 
     1401PJ_DECL(pj_status_t) pjsua_call_set_user_data(pjsua_call_id call_id, 
     1402                                              void *user_data); 
     1403 
     1404 
     1405/** 
     1406 * Get user data attached to the call. 
     1407 * 
     1408 * @param call_id       Call identification. 
     1409 * 
     1410 * @return              The user data. 
     1411 */ 
     1412PJ_DECL(void*) pjsua_call_get_user_data(pjsua_call_id call_id); 
     1413 
     1414 
     1415/** 
     1416 * Send response to incoming INVITE request. 
     1417 * 
     1418 * @param call_id       Incoming call identification. 
     1419 * @param code          Status code, (100-699). 
     1420 * @param reason        Optional reason phrase. If NULL, default text 
     1421 *                      will be used. 
     1422 * @param msg_data      Optional list of headers etc to be added to outgoing 
     1423 *                      response message. 
     1424 * 
     1425 * @return              PJ_SUCCESS on success, or the appropriate error code. 
     1426 */ 
     1427PJ_DECL(pj_status_t) pjsua_call_answer(pjsua_call_id call_id,  
     1428                                       unsigned code, 
     1429                                       const pj_str_t *reason, 
     1430                                       const pjsua_msg_data *msg_data); 
     1431 
     1432/** 
     1433 * Hangup call by using method that is appropriate according to the 
     1434 * call state. 
     1435 * 
     1436 * @param call_id       Call identification. 
     1437 * @param code          Optional status code to be sent when we're rejecting 
     1438 *                      incoming call. If the value is zero, "603/Decline" 
     1439 *                      will be sent. 
     1440 * @param reason        Optional reason phrase to be sent when we're rejecting 
     1441 *                      incoming call.  If NULL, default text will be used. 
     1442 * @param msg_data      Optional list of headers etc to be added to outgoing 
     1443 *                      request/response message. 
     1444 * 
     1445 * @return              PJ_SUCCESS on success, or the appropriate error code. 
     1446 */ 
     1447PJ_DECL(pj_status_t) pjsua_call_hangup(pjsua_call_id call_id, 
     1448                                       unsigned code, 
     1449                                       const pj_str_t *reason, 
     1450                                       const pjsua_msg_data *msg_data); 
     1451 
     1452 
     1453/** 
     1454 * Put the specified call on hold. 
     1455 * 
     1456 * @param call_id       Call identification. 
     1457 * @param msg_data      Optional message components to be sent with 
     1458 *                      the request. 
     1459 * 
     1460 * @return              PJ_SUCCESS on success, or the appropriate error code. 
     1461 */ 
     1462PJ_DECL(pj_status_t) pjsua_call_set_hold(pjsua_call_id call_id, 
     1463                                         const pjsua_msg_data *msg_data); 
    5671464 
    5681465 
    5691466/** 
    5701467 * Send re-INVITE (to release hold). 
    571  */ 
    572 PJ_DECL(pj_status_t) pjsua_call_reinvite(int call_index); 
    573  
    574  
    575 /** 
    576  * Transfer call. 
    577  */ 
    578 PJ_DECL(pj_status_t) pjsua_call_xfer(unsigned call_index, const pj_str_t *dest); 
    579  
    580 /** 
    581  * Dial DTMF. 
    582  */ 
    583 PJ_DECL(pj_status_t) pjsua_call_dial_dtmf(unsigned call_index,  
     1468 * 
     1469 * @param call_id       Call identification. 
     1470 * @param unhold        If this argument is non-zero and the call is locally 
     1471 *                      held, this will release the local hold. 
     1472 * @param msg_data      Optional message components to be sent with 
     1473 *                      the request. 
     1474 * 
     1475 * @return              PJ_SUCCESS on success, or the appropriate error code. 
     1476 */ 
     1477PJ_DECL(pj_status_t) pjsua_call_reinvite(pjsua_call_id call_id, 
     1478                                         pj_bool_t unhold, 
     1479                                         const pjsua_msg_data *msg_data); 
     1480 
     1481 
     1482/** 
     1483 * Initiate call transfer to the specified address. 
     1484 * 
     1485 * @param call_id       Call identification. 
     1486 * @param dest          Address of new target to be contacted. 
     1487 * @param msg_data      Optional message components to be sent with 
     1488 *                      the request. 
     1489 * 
     1490 * @return              PJ_SUCCESS on success, or the appropriate error code. 
     1491 */ 
     1492PJ_DECL(pj_status_t) pjsua_call_xfer(pjsua_call_id call_id,  
     1493                                     const pj_str_t *dest, 
     1494                                     const pjsua_msg_data *msg_data); 
     1495 
     1496/** 
     1497 * Send DTMF digits to remote using RFC 2833 payload formats. 
     1498 * 
     1499 * @param call_id       Call identification. 
     1500 * @param digits        DTMF digits to be sent. 
     1501 * 
     1502 * @return              PJ_SUCCESS on success, or the appropriate error code. 
     1503 */ 
     1504PJ_DECL(pj_status_t) pjsua_call_dial_dtmf(pjsua_call_id call_id,  
    5841505                                          const pj_str_t *digits); 
    5851506 
    586  
    5871507/** 
    5881508 * Send instant messaging inside INVITE session. 
    589  */ 
    590 PJ_DECL(pj_status_t) pjsua_call_send_im(int call_index, const pj_str_t *text); 
     1509 * 
     1510 * @param call_id       Call identification. 
     1511 * @param mime_type     Optional MIME type. If NULL, then "text/plain" is  
     1512 *                      assumed. 
     1513 * @param content       The message content. 
     1514 * @param msg_data      Optional list of headers etc to be included in outgoing 
     1515 *                      request. The body descriptor in the msg_data is  
     1516 *                      ignored. 
     1517 * @param user_data     Optional user data, which will be given back when 
     1518 *                      the IM callback is called. 
     1519 * 
     1520 * @return              PJ_SUCCESS on success, or the appropriate error code. 
     1521 */ 
     1522PJ_DECL(pj_status_t) pjsua_call_send_im( pjsua_call_id call_id,  
     1523                                         const pj_str_t *mime_type, 
     1524                                         const pj_str_t *content, 
     1525                                         const pjsua_msg_data *msg_data, 
     1526                                         void *user_data); 
    5911527 
    5921528 
    5931529/** 
    5941530 * Send IM typing indication inside INVITE session. 
    595  */ 
    596 PJ_DECL(pj_status_t) pjsua_call_send_typing_ind(int call_index,  
    597                                                 pj_bool_t is_typing); 
     1531 * 
     1532 * @param call_id       Call identification. 
     1533 * @param is_typing     Non-zero to indicate to remote that local person is 
     1534 *                      currently typing an IM. 
     1535 * @param msg_data      Optional list of headers etc to be included in outgoing 
     1536 *                      request. 
     1537 * 
     1538 * @return              PJ_SUCCESS on success, or the appropriate error code. 
     1539 */ 
     1540PJ_DECL(pj_status_t) pjsua_call_send_typing_ind(pjsua_call_id call_id,  
     1541                                                pj_bool_t is_typing, 
     1542                                                const pjsua_msg_data*msg_data); 
    5981543 
    5991544/** 
     
    6051550/** 
    6061551 * Dump call and media statistics to string. 
    607  */ 
    608 PJ_DECL(void) pjsua_call_dump(int call_index, int with_media,  
    609                               char *buffer, unsigned maxlen, 
    610                               const char *indent); 
     1552 * 
     1553 * @param call_id       Call identification. 
     1554 * @param with_media    Non-zero to include media information too. 
     1555 * @param buffer        Buffer where the statistics are to be written to. 
     1556 * @param maxlen        Maximum length of buffer. 
     1557 * @param indent        Spaces for left indentation. 
     1558 * 
     1559 * @return              PJ_SUCCESS on success. 
     1560 */ 
     1561PJ_DECL(pj_status_t) pjsua_call_dump(pjsua_call_id call_id,  
     1562                                     pj_bool_t with_media,  
     1563                                     char *buffer,  
     1564                                     unsigned maxlen, 
     1565                                     const char *indent); 
    6111566 
    6121567 
    6131568/***************************************************************************** 
    614  * PJSUA Account and Client Registration API (defined in pjsua_reg.c). 
    615  */ 
    616  
    617  
    618 /** 
    619  * Get number of accounts. 
    620  */ 
    621 PJ_DECL(unsigned) pjsua_get_acc_count(void); 
    622  
    623 /** 
    624  * Get account info. 
     1569 * PJSUA Account and Client Registration API. 
     1570 */ 
     1571 
     1572 
     1573/** 
     1574 * Get number of current accounts. 
     1575 * 
     1576 * @return              Current number of accounts. 
     1577 */ 
     1578PJ_DECL(unsigned) pjsua_acc_get_count(void); 
     1579 
     1580 
     1581/** 
     1582 * Check if the specified account ID is valid. 
     1583 * 
     1584 * @param acc_id        Account ID to check. 
     1585 * 
     1586 * @return              Non-zero if account ID is valid. 
     1587 */ 
     1588PJ_DECL(pj_bool_t) pjsua_acc_is_valid(pjsua_acc_id acc_id); 
     1589 
     1590 
     1591/** 
     1592 * Add a new account to pjsua. PJSUA must have been initialized (with 
     1593 * #pjsua_init()) before calling this function. 
     1594 * 
     1595 * @param cfg           Account configuration. 
     1596 * @param is_default    If non-zero, this account will be set as the default 
     1597 *                      account. The default account will be used when sending 
     1598 *                      outgoing requests (e.g. making call) when no account is 
     1599 *                      specified, and when receiving incoming requests when the 
     1600 *                      request does not match any accounts. It is recommended 
     1601 *                      that default account is set to local/LAN account. 
     1602 * @param p_acc_id      Pointer to receive account ID of the new account. 
     1603 * 
     1604 * @return              PJ_SUCCESS on success, or the appropriate error code. 
     1605 */ 
     1606PJ_DECL(pj_status_t) pjsua_acc_add(const pjsua_acc_config *cfg, 
     1607                                   pj_bool_t is_default, 
     1608                                   pjsua_acc_id *p_acc_id); 
     1609 
     1610 
     1611/** 
     1612 * Add a local account. A local account is used to identify local endpoint 
     1613 * instead of a specific user, and for this reason, a transport ID is needed 
     1614 * to obtain the local address information. 
     1615 * 
     1616 * @param tid           Transport ID to generate account address. 
     1617 * @param is_default    If non-zero, this account will be set as the default 
     1618 *                      account. The default account will be used when sending 
     1619 *                      outgoing requests (e.g. making call) when no account is 
     1620 *                      specified, and when receiving incoming requests when the 
     1621 *                      request does not match any accounts. It is recommended 
     1622 *                      that default account is set to local/LAN account. 
     1623 * @param p_acc_id      Pointer to receive account ID of the new account. 
     1624 * 
     1625 * @return              PJ_SUCCESS on success, or the appropriate error code. 
     1626 */ 
     1627PJ_DECL(pj_status_t) pjsua_acc_add_local(pjsua_transport_id tid, 
     1628                                         pj_bool_t is_default, 
     1629                                         pjsua_acc_id *p_acc_id); 
     1630 
     1631/** 
     1632 * Delete account. 
     1633 * 
     1634 * @param acc_id        Id of the account to be deleted. 
     1635 * 
     1636 * @return              PJ_SUCCESS on success, or the appropriate error code. 
     1637 */ 
     1638PJ_DECL(pj_status_t) pjsua_acc_del(pjsua_acc_id acc_id); 
     1639 
     1640 
     1641/** 
     1642 * Modify account information. 
     1643 * 
     1644 * @param acc_id        Id of the account to be modified. 
     1645 * @param cfg           New account configuration. 
     1646 * 
     1647 * @return              PJ_SUCCESS on success, or the appropriate error code. 
     1648 */ 
     1649PJ_DECL(pj_status_t) pjsua_acc_modify(pjsua_acc_id acc_id, 
     1650                                      const pjsua_acc_config *cfg); 
     1651 
     1652 
     1653/** 
     1654 * Modify account's presence status to be advertised to remote/presence 
     1655 * subscribers. 
     1656 * 
     1657 * @param acc_id        The account ID. 
     1658 * @param is_online     True of false. 
     1659 * 
     1660 * @return              PJ_SUCCESS on success, or the appropriate error code. 
     1661 */ 
     1662PJ_DECL(pj_status_t) pjsua_acc_set_online_status(pjsua_acc_id acc_id, 
     1663                                                 pj_bool_t is_online); 
     1664 
     1665 
     1666/** 
     1667 * Update registration or perform unregistration.  
     1668 * 
     1669 * @param acc_id        The account ID. 
     1670 * @param renew         If renew argument is zero, this will start  
     1671 *                      unregistration process. 
     1672 * 
     1673 * @return              PJ_SUCCESS on success, or the appropriate error code. 
     1674 */ 
     1675PJ_DECL(pj_status_t) pjsua_acc_set_registration(pjsua_acc_id acc_id,  
     1676                                                pj_bool_t renew); 
     1677 
     1678 
     1679/** 
     1680 * Get account information. 
     1681 * 
     1682 * @param acc_id        Account identification. 
     1683 * @param info          Pointer to receive account information. 
     1684 * 
     1685 * @return              PJ_SUCCESS on success, or the appropriate error code. 
    6251686 */ 
    6261687PJ_DECL(pj_status_t) pjsua_acc_get_info(pjsua_acc_id acc_id, 
     
    6291690 
    6301691/** 
    631  * Enum accounts id. 
    632  */ 
    633 PJ_DECL(pj_status_t) pjsua_acc_enum_id( pjsua_acc_id ids[], 
    634                                         unsigned *count ); 
     1692 * Enum accounts all account ids. 
     1693 * 
     1694 * @param ids           Array of account IDs to be initialized. 
     1695 * @param count         In input, specifies the maximum number of elements. 
     1696 *                      On return, it contains the actual number of elements. 
     1697 * 
     1698 * @return              PJ_SUCCESS on success, or the appropriate error code. 
     1699 */ 
     1700PJ_DECL(pj_status_t) pjsua_enum_accs(pjsua_acc_id ids[], 
     1701                                     unsigned *count ); 
    6351702 
    6361703 
    6371704/** 
    6381705 * Enum accounts info. 
     1706 * 
     1707 * @param info          Array of account infos to be initialized. 
     1708 * @param count         In input, specifies the maximum number of elements. 
     1709 *                      On return, it contains the actual number of elements. 
     1710 * 
     1711 * @return              PJ_SUCCESS on success, or the appropriate error code. 
    6391712 */ 
    6401713PJ_DECL(pj_status_t) pjsua_acc_enum_info( pjsua_acc_info info[], 
     
    6431716 
    6441717/** 
    645  * Find account for outgoing request. 
     1718 * This is an internal function to find the most appropriate account to 
     1719 * used to reach to the specified URL. 
     1720 * 
     1721 * @param url           The remote URL to reach. 
     1722 * 
     1723 * @return              Account id. 
    6461724 */ 
    6471725PJ_DECL(pjsua_acc_id) pjsua_acc_find_for_outgoing(const pj_str_t *url); 
    6481726 
    649 /** 
    650  * Find account for incoming request. 
     1727 
     1728/** 
     1729 * This is an internal function to find the most appropriate account to be 
     1730 * used to handle incoming calls. 
     1731 * 
     1732 * @param rdata         The incoming request message. 
     1733 * 
     1734 * @return              Account id. 
    6511735 */ 
    6521736PJ_DECL(pjsua_acc_id) pjsua_acc_find_for_incoming(pjsip_rx_data *rdata); 
    653  
    654 /** 
    655  * Add a new account. 
    656  * This function should be called after pjsua_init(). 
    657  * Application should call pjsua_acc_set_registration() to start  
    658  * registration for this account. 
    659  */ 
    660 PJ_DECL(pj_status_t) pjsua_acc_add(const pjsua_acc_config *cfg, 
    661                                    pjsua_acc_id *acc_id); 
    662  
    663 /** 
    664  * Delete account. 
    665  */ 
    666 PJ_DECL(pj_status_t) pjsua_acc_del(pjsua_acc_id acc_id); 
    667  
    668  
    669 /** 
    670  * Set account's presence status. 
    671  */ 
    672 PJ_DECL(pj_status_t) pjsua_acc_set_online_status(pjsua_acc_id acc_id, 
    673                                                  pj_bool_t is_online); 
    674  
    675  
    676 /** 
    677  * Update registration or perform unregistration. If renew argument is zero, 
    678  * this will start unregistration process. 
    679  */ 
    680 PJ_DECL(pj_status_t) pjsua_acc_set_registration(pjsua_acc_id acc_id,  
    681                                                 pj_bool_t renew); 
    682  
    6831737 
    6841738 
     
    6891743 
    6901744/** 
    691  * Get buddy count. 
     1745 * Get total number of buddies. 
     1746 * 
     1747 * @return              Number of buddies. 
    6921748 */ 
    6931749PJ_DECL(unsigned) pjsua_get_buddy_count(void); 
     
    6951751 
    6961752/** 
    697  * Get buddy info. 
    698  */ 
    699 PJ_DECL(pj_status_t) pjsua_buddy_get_info(pjsua_buddy_id buddy_index, 
     1753 * Check if buddy ID is valid. 
     1754 * 
     1755 * @param buddy_id      Buddy ID to check. 
     1756 * 
     1757 * @return              Non-zero if buddy ID is valid. 
     1758 */ 
     1759PJ_DECL(pj_bool_t) pjsua_buddy_is_valid(pjsua_buddy_id buddy_id); 
     1760 
     1761 
     1762/** 
     1763 * Enum buddy IDs. 
     1764 * 
     1765 * @param ids           Array of ids to be initialized. 
     1766 * @param count         On input, specifies max elements in the array. 
     1767 *                      On return, it contains actual number of elements 
     1768 *                      that have been initialized. 
     1769 * 
     1770 * @return              PJ_SUCCESS on success, or the appropriate error code. 
     1771 */ 
     1772PJ_DECL(pj_status_t) pjsua_enum_buddies(pjsua_buddy_id ids[], 
     1773                                        unsigned *count); 
     1774 
     1775/** 
     1776 * Get detailed buddy info. 
     1777 * 
     1778 * @param buddy_id      The buddy identification. 
     1779 * @param info          Pointer to receive information about buddy. 
     1780 * 
     1781 * @return              PJ_SUCCESS on success, or the appropriate error code. 
     1782 */ 
     1783PJ_DECL(pj_status_t) pjsua_buddy_get_info(pjsua_buddy_id buddy_id, 
    7001784                                          pjsua_buddy_info *info); 
    7011785 
    7021786/** 
    7031787 * Add new buddy. 
    704  */ 
    705 PJ_DECL(pj_status_t) pjsua_buddy_add(const pj_str_t *uri, 
    706                                      pjsua_buddy_id *buddy_index); 
     1788 * 
     1789 * @param cfg           Buddy configuration. 
     1790 * @param p_buddy_id    Pointer to receive buddy ID. 
     1791 * 
     1792 * @return              PJ_SUCCESS on success, or the appropriate error code. 
     1793 */ 
     1794PJ_DECL(pj_status_t) pjsua_buddy_add(const pjsua_buddy_config *cfg, 
     1795                                     pjsua_buddy_id *p_buddy_id); 
    7071796 
    7081797 
    7091798/** 
    7101799 * Delete buddy. 
    711  */ 
    712 PJ_DECL(pj_status_t) pjsua_buddy_del(pjsua_buddy_id buddy_index); 
     1800 * 
     1801 * @param buddy_id      Buddy identification. 
     1802 * 
     1803 * @return              PJ_SUCCESS on success, or the appropriate error code. 
     1804 */ 
     1805PJ_DECL(pj_status_t) pjsua_buddy_del(pjsua_buddy_id buddy_id); 
    7131806 
    7141807 
    7151808/** 
    7161809 * Enable/disable buddy's presence monitoring. 
    717  */ 
    718 PJ_DECL(pj_status_t) pjsua_buddy_subscribe_pres(pjsua_buddy_id buddy_index, 
    719                                                 pj_bool_t monitor); 
    720  
    721  
    722 /** 
    723  * Dump presence subscriptions. 
    724  */ 
    725 PJ_DECL(void) pjsua_pres_dump(pj_bool_t detail); 
     1810 * 
     1811 * @param buddy_id      Buddy identification. 
     1812 * @param subscribe     Specify non-zero to activate presence subscription to 
     1813 *                      the specified buddy. 
     1814 * 
     1815 * @return              PJ_SUCCESS on success, or the appropriate error code. 
     1816 */ 
     1817PJ_DECL(pj_status_t) pjsua_buddy_subscribe_pres(pjsua_buddy_id buddy_id, 
     1818                                                pj_bool_t subscribe); 
     1819 
     1820 
     1821/** 
     1822 * Dump presence subscriptions to log file. 
     1823 * 
     1824 * @param verbose       Yes or no. 
     1825 */ 
     1826PJ_DECL(void) pjsua_pres_dump(pj_bool_t verbose); 
    7261827 
    7271828 
     
    7381839 
    7391840/** 
    740  * Send IM outside dialog. 
    741  */ 
    742 PJ_DECL(pj_status_t) pjsua_im_send(int acc_id, const pj_str_t *dst_uri,  
    743                                    const pj_str_t *text); 
     1841 * Send instant messaging outside dialog, using the specified account for 
     1842 * route set and authentication. 
     1843 * 
     1844 * @param acc_id        Account ID to be used to send the request. 
     1845 * @param to            Remote URI. 
     1846 * @param mime_type     Optional MIME type. If NULL, then "text/plain" is  
     1847 *                      assumed. 
     1848 * @param content       The message content. 
     1849 * @param msg_data      Optional list of headers etc to be included in outgoing 
     1850 *                      request. The body descriptor in the msg_data is  
     1851 *                      ignored. 
     1852 * @param user_data     Optional user data, which will be given back when 
     1853 *                      the IM callback is called. 
     1854 * 
     1855 * @return              PJ_SUCCESS on success, or the appropriate error code. 
     1856 */ 
     1857PJ_DECL(pj_status_t) pjsua_im_send(pjsua_acc_id acc_id,  
     1858                                   const pj_str_t *to, 
     1859                                   const pj_str_t *mime_type, 
     1860                                   const pj_str_t *content, 
     1861                                   const pjsua_msg_data *msg_data, 
     1862                                   void *user_data); 
    7441863 
    7451864 
    7461865/** 
    7471866 * Send typing indication outside dialog. 
    748  */ 
    749 PJ_DECL(pj_status_t) pjsua_im_typing(int acc_id, const pj_str_t *dst_uri,  
    750                                      pj_bool_t is_typing); 
     1867 * 
     1868 * @param acc_id        Account ID to be used to send the request. 
     1869 * @param to            Remote URI. 
     1870 * @param is_typing     If non-zero, it tells remote person that local person 
     1871 *                      is currently composing an IM. 
     1872 * @param msg_data      Optional list of headers etc to be added to outgoing 
     1873 *                      request. 
     1874 * 
     1875 * @return              PJ_SUCCESS on success, or the appropriate error code. 
     1876 */ 
     1877PJ_DECL(pj_status_t) pjsua_im_typing(pjsua_acc_id acc_id,  
     1878                                     const pj_str_t *to,  
     1879                                     pj_bool_t is_typing, 
     1880                                     const pjsua_msg_data *msg_data); 
    7511881 
    7521882 
    7531883 
    7541884/***************************************************************************** 
    755  * Media. 
     1885 * Conference bridge manipulation. 
    7561886 */ 
    7571887 
    7581888/** 
    7591889 * Get maxinum number of conference ports. 
    760  */ 
    761 PJ_DECL(unsigned) pjsua_conf_max_ports(void); 
    762  
    763  
    764 /** 
    765  * Enum all conference ports. 
    766  */ 
    767 PJ_DECL(pj_status_t) pjsua_conf_enum_port_ids(pjsua_conf_port_id id[], 
    768                                               unsigned *count); 
     1890 * 
     1891 * @return              Maximum number of ports in the conference bridge. 
     1892 */ 
     1893PJ_DECL(unsigned) pjsua_conf_get_max_ports(void); 
     1894 
     1895 
     1896/** 
     1897 * Get current number of active ports in the bridge. 
     1898 * 
     1899 * @return              The number. 
     1900 */ 
     1901PJ_DECL(unsigned) pjsua_conf_get_active_ports(void); 
     1902 
     1903 
     1904/** 
     1905 * Enumerate all conference ports. 
     1906 * 
     1907 * @param id            Array of conference port ID to be initialized. 
     1908 * @param count         On input, specifies max elements in the array. 
     1909 *                      On return, it contains actual number of elements 
     1910 *                      that have been initialized. 
     1911 * 
     1912 * @return              PJ_SUCCESS on success, or the appropriate error code. 
     1913 */ 
     1914PJ_DECL(pj_status_t) pjsua_enum_conf_ports(pjsua_conf_port_id id[], 
     1915                                           unsigned *count); 
    7691916 
    7701917 
    7711918/** 
    7721919 * Get information about the specified conference port 
     1920 * 
     1921 * @param id            Port identification. 
     1922 * @param info          Pointer to store the port info. 
     1923 * 
     1924 * @return              PJ_SUCCESS on success, or the appropriate error code. 
    7731925 */ 
    7741926PJ_DECL(pj_status_t) pjsua_conf_get_port_info( pjsua_conf_port_id id, 
     
    7771929 
    7781930/** 
    779  * Connect conference port. 
    780  */ 
    781 PJ_DECL(pj_status_t) pjsua_conf_connect(pjsua_conf_port_id src_port, 
    782                                         pjsua_conf_port_id dst_port); 
    783  
    784  
    785 /** 
    786  * Connect conference port connection. 
    787  */ 
    788 PJ_DECL(pj_status_t) pjsua_conf_disconnect(pjsua_conf_port_id src_port, 
    789                                            pjsua_conf_port_id dst_port); 
    790  
    791  
    792 /** 
    793  * Create a file player. 
     1931 * Establish unidirectional media flow from souce to sink. One source 
     1932 * may transmit to multiple destinations/sink. And if multiple 
     1933 * sources are transmitting to the same sink, the media will be mixed 
     1934 * together. Source and sink may refer to the same ID, effectively 
     1935 * looping the media. 
     1936 * 
     1937 * If bidirectional media flow is desired, application needs to call 
     1938 * this function twice, with the second one having the arguments 
     1939 * reversed. 
     1940 * 
     1941 * @param source        Port ID of the source media/transmitter. 
     1942 * @param sink          Port ID of the destination media/received. 
     1943 * 
     1944 * @return              PJ_SUCCESS on success, or the appropriate error code. 
     1945 */ 
     1946PJ_DECL(pj_status_t) pjsua_conf_connect(pjsua_conf_port_id source, 
     1947                                        pjsua_conf_port_id sink); 
     1948 
     1949 
     1950/** 
     1951 * Disconnect media flow from the source to destination port. 
     1952 * 
     1953 * @param source        Port ID of the source media/transmitter. 
     1954 * @param sink          Port ID of the destination media/received. 
     1955 * 
     1956 * @return              PJ_SUCCESS on success, or the appropriate error code. 
     1957 */ 
     1958PJ_DECL(pj_status_t) pjsua_conf_disconnect(pjsua_conf_port_id source, 
     1959                                           pjsua_conf_port_id sink); 
     1960 
     1961 
     1962/***************************************************************************** 
     1963 * File player. 
     1964 */ 
     1965 
     1966/** 
     1967 * Create a file player, and automatically connect this player to 
     1968 * the conference bridge. 
     1969 * 
     1970 * @param filename      The filename to be played. Currently only 
     1971 *                      WAV files are supported. 
     1972 * @param options       Options (currently zero). 
     1973 * @param user_data     Arbitrary user data to be associated with the player. 
     1974 * @param p_id          Pointer to receive player ID. 
     1975 * 
     1976 * @return              PJ_SUCCESS on success, or the appropriate error code. 
    7941977 */ 
    7951978PJ_DECL(pj_status_t) pjsua_player_create(const pj_str_t *filename, 
    796                                          pjsua_player_id *id); 
    797  
    798  
    799 /** 
    800  * Get conference port associated with player. 
     1979                                         unsigned options, 
     1980                                         void *user_data, 
     1981                                         pjsua_player_id *p_id); 
     1982 
     1983 
     1984/** 
     1985 * Get conference port ID associated with player. 
     1986 * 
     1987 * @param id            The file player ID. 
     1988 * 
     1989 * @return              Conference port ID associated with this player. 
    8011990 */ 
    8021991PJ_DECL(pjsua_conf_port_id) pjsua_player_get_conf_port(pjsua_player_id id); 
     
    8051994/** 
    8061995 * Set playback position. 
     1996 * 
     1997 * @param id            The file player ID. 
     1998 * @param samples       The playback position, in samples. Application can 
     1999 *                      specify zero to re-start the playback. 
     2000 * 
     2001 * @return              PJ_SUCCESS on success, or the appropriate error code. 
    8072002 */ 
    8082003PJ_DECL(pj_status_t) pjsua_player_set_pos(pjsua_player_id id, 
     
    8112006 
    8122007/** 
    813  * Destroy player. 
     2008 * Close the file, remove the player from the bridge, and free 
     2009 * resources associated with the file player. 
     2010 * 
     2011 * @param id            The file player ID. 
     2012 * 
     2013 * @return              PJ_SUCCESS on success, or the appropriate error code. 
    8142014 */ 
    8152015PJ_DECL(pj_status_t) pjsua_player_destroy(pjsua_player_id id); 
    8162016 
    8172017 
    818  
    819 /** 
    820  * Create a file recorder. 
     2018/***************************************************************************** 
     2019 * File recorder. 
     2020 */ 
     2021 
     2022/** 
     2023 * Create a file recorder, and automatically connect this recorder to 
     2024 * the conference bridge. 
     2025 * 
     2026 * @param filename      Output file name. 
     2027 * @param file_format   Specify the file format (currently only WAV is 
     2028 *                      supported, so the value MUST be zero). 
     2029 * @param encoding      Specify the encoding to be applied to the file. 
     2030 *                      Currently only 16bit raw PCM is supported, so 
     2031 *                      the value must be NULL. 
     2032 * @param max_size      Maximum file size. Specify -1 to remove size 
     2033 *                      limitation. 
     2034 * @param options       Optional options. 
     2035 * @param user_data     Arbitrary user data which will be given in the  
     2036 *                      callback once the recording complete. 
     2037 * @param p_id          Pointer to receive the recorder instance. 
     2038 * 
     2039 * @return              PJ_SUCCESS on success, or the appropriate error code. 
    8212040 */ 
    8222041PJ_DECL(pj_status_t) pjsua_recorder_create(const pj_str_t *filename, 
    823                                            pjsua_recorder_id *id); 
     2042                                           unsigned file_format, 
     2043                                           const pj_str_t *encoding, 
     2044                                           pj_ssize_t max_size, 
     2045                                           unsigned options, 
     2046                                           void *user_data, 
     2047                                           pjsua_recorder_id *p_id); 
    8242048 
    8252049 
    8262050/** 
    8272051 * Get conference port associated with recorder. 
     2052 * 
     2053 * @param id            The recorder ID. 
     2054 * 
     2055 * @return              Conference port ID associated with this recorder. 
    8282056 */ 
    8292057PJ_DECL(pjsua_conf_port_id) pjsua_recorder_get_conf_port(pjsua_recorder_id id); 
     
    8312059 
    8322060/** 
    833  * Destroy recorder (will complete recording). 
     2061 * Destroy recorder (this will complete recording). 
     2062 * 
     2063 * @param id            The recorder ID. 
     2064 * 
     2065 * @return              PJ_SUCCESS on success, or the appropriate error code. 
    8342066 */ 
    8352067PJ_DECL(pj_status_t) pjsua_recorder_destroy(pjsua_recorder_id id); 
    8362068 
    8372069 
     2070/***************************************************************************** 
     2071 * Sound devices. 
     2072 */ 
     2073 
    8382074/** 
    8392075 * Enum sound devices. 
    840  */ 
    841 PJ_DECL(pj_status_t) pjsua_enum_snd_devices(unsigned *count, 
    842                                             pjmedia_snd_dev_info info[]); 
    843  
    844  
    845 /** 
    846  * Select or change sound device. 
    847  * This will only change the device ID in configuration (not changing 
    848  * the current device). 
    849  */ 
    850 PJ_DECL(pj_status_t) pjsua_set_snd_dev(int snd_capture_id, 
    851                                        int snd_player_id); 
     2076 * 
     2077 * @param info          Array of info to be initialized. 
     2078 * @param count         On input, specifies max elements in the array. 
     2079 *                      On return, it contains actual number of elements 
     2080 *                      that have been initialized. 
     2081 * 
     2082 * @return              PJ_SUCCESS on success, or the appropriate error code. 
     2083 */ 
     2084PJ_DECL(pj_status_t) pjsua_enum_snd_devs(pjmedia_snd_dev_info info[], 
     2085                                         unsigned *count); 
     2086 
     2087 
     2088/** 
     2089 * Select or change sound device. Application may call this function at 
     2090 * any time to replace current sound device. 
     2091 * 
     2092 * @param capture_dev   Device ID of the capture device. 
     2093 * @param playback_dev  Device ID of the playback device. 
     2094 * 
     2095 * @return              PJ_SUCCESS on success, or the appropriate error code. 
     2096 */ 
     2097PJ_DECL(pj_status_t) pjsua_set_snd_dev(int capture_dev, 
     2098                                       int playback_dev); 
     2099 
     2100 
     2101/** 
     2102 * Set pjsua to use null sound device. The null sound device only provides 
     2103 * the timing needed by the conference bridge, and will not interract with 
     2104 * any hardware. 
     2105 * 
     2106 * @return              PJ_SUCCESS on success, or the appropriate error code. 
     2107 */ 
     2108PJ_DECL(pj_status_t) pjsua_set_null_snd_dev(void); 
     2109 
     2110 
     2111/***************************************************************************** 
     2112 * Codecs. 
     2113 */ 
     2114 
     2115/** 
     2116 * Enum all supported codecs in the system. 
     2117 * 
     2118 * @param id            Array of ID to be initialized. 
     2119 * @param count         On input, specifies max elements in the array. 
     2120 *                      On return, it contains actual number of elements 
     2121 *                      that have been initialized. 
     2122 * 
     2123 * @return              PJ_SUCCESS on success, or the appropriate error code. 
     2124 */ 
     2125PJ_DECL(pj_status_t) pjsua_enum_codecs( pjsua_codec_info id[], 
     2126                                        unsigned *count ); 
     2127 
     2128 
     2129/** 
     2130 * Change codec priority. 
     2131 * 
     2132 * @param id            Codec ID. 
     2133 * @param priority      Codec priority, 0-255, where zero means to disable 
     2134 *                      the codec. 
     2135 * 
     2136 * @return              PJ_SUCCESS on success, or the appropriate error code. 
     2137 */ 
     2138PJ_DECL(pj_status_t) pjsua_codec_set_priority( const pj_str_t *id, 
     2139                                               pj_uint8_t priority ); 
     2140 
     2141 
     2142/** 
     2143 * Get codec parameters. 
     2144 * 
     2145 * @param id            Codec ID. 
     2146 * @param param         Structure to receive codec parameters. 
     2147 * 
     2148 * @return              PJ_SUCCESS on success, or the appropriate error code. 
     2149 */ 
     2150PJ_DECL(pj_status_t) pjsua_codec_get_param( const pj_str_t *id, 
     2151                                            pjmedia_codec_param *param ); 
     2152 
     2153 
     2154/** 
     2155 * Set codec parameters. 
     2156 * 
     2157 * @param id            Codec ID. 
     2158 * @param param         Codec parameter to set. 
     2159 * 
     2160 * @return              PJ_SUCCESS on success, or the appropriate error code. 
     2161 */ 
     2162PJ_DECL(pj_status_t) pjsua_codec_set_param( const pj_str_t *id, 
     2163                                            const pjmedia_codec_param *param); 
     2164 
     2165 
     2166 
    8522167 
    8532168 
     
    8572172 */ 
    8582173 
    859 /** String to describe invite session states */ 
    860 extern const char *pjsua_inv_state_names[]; 
    861  
    862 /** 
    863  * Parse arguments (pjsua_opt.c). 
    864  */ 
    865 PJ_DECL(pj_status_t) pjsua_parse_args(int argc, char *argv[], 
    866                                       pjsua_config *cfg, 
    867                                       pj_str_t *uri_to_call); 
    868  
    869 /** 
    870  * Load settings from a file. 
    871  */ 
    872 PJ_DECL(pj_status_t) pjsua_load_settings(const char *filename, 
    873                                          pjsua_config *cfg, 
    874                                          pj_str_t *uri_to_call); 
    875  
    876 /** 
    877  * Get pjsua running config. 
    878  */ 
    879 PJ_DECL(void) pjsua_get_config(pj_pool_t *pool, 
    880                                pjsua_config *config); 
    881  
    882  
    883 /** 
    884  * Dump settings. 
    885  * If cfg is NULL, it will dump current settings. 
    886  */ 
    887 PJ_DECL(int) pjsua_dump_settings(const pjsua_config *cfg, 
    888                                  char *buf, pj_size_t max); 
    889  
    890 /** 
    891  * Save settings to a file. 
    892  */ 
    893 PJ_DECL(pj_status_t) pjsua_save_settings(const char *filename, 
    894                                          const pjsua_config *cfg); 
    895  
    896  
    8972174/* 
    8982175 * Verify that valid SIP url is given. 
    899  * @return  PJ_SUCCESS if valid. 
     2176 * 
     2177 * @param c_url         The URL, as NULL terminated string. 
     2178 * 
     2179 * @return              PJ_SUCCESS on success, or the appropriate error code. 
    9002180 */ 
    9012181PJ_DECL(pj_status_t) pjsua_verify_sip_url(const char *c_url); 
    9022182 
    903 /* 
    904  * Dump application states. 
    905  */ 
    906 PJ_DECL(void) pjsua_dump(pj_bool_t detail); 
    9072183 
    9082184/** 
    9092185 * Display error message for the specified error code. 
     2186 * 
     2187 * @param sender        The log sender field. 
     2188 * @param title         Message title for the error. 
     2189 * @param status        Status code. 
    9102190 */ 
    9112191PJ_DECL(void) pjsua_perror(const char *sender, const char *title,  
  • pjproject/trunk/pjsip/src/pjsua-lib/pjsua_call.c

    r492 r503  
    1818 */ 
    1919#include <pjsua-lib/pjsua.h> 
    20 #include <pj/log.h> 
    21 #include "pjsua_imp.h" 
    22  
    23 /* 
    24  * pjsua_call.c 
    25  * 
    26  * Call (INVITE) related stuffs. 
    27  */ 
    28  
    29 #define THIS_FILE   "pjsua_call.c" 
    30  
    31  
    32 #define REFRESH_CALL_TIMER      0x63 
    33 #define HANGUP_CALL_TIMER       0x64 
    34  
    35 /* Proto */ 
    36 static void schedule_call_timer( pjsua_call *call, pj_timer_entry *e, 
    37                                  int timer_type, int duration ); 
    38  
    39 /* 
    40  * Timer callback when UAS needs to send re-INVITE to see if remote 
    41  * is still there. 
    42  */ 
    43 static void call_on_timer(pj_timer_heap_t *ht, pj_timer_entry *e) 
    44 { 
    45     pjsua_call *call = e->user_data; 
    46  
    47     PJ_UNUSED_ARG(ht); 
    48  
    49     if (e->id == REFRESH_CALL_TIMER) { 
    50  
    51         /* If call is still not connected, hangup. */ 
    52         if (call->inv->state != PJSIP_INV_STATE_CONFIRMED) { 
    53             PJ_LOG(3,(THIS_FILE, "Refresh call timer is called when " 
    54                       "invite is still not confirmed. Call %d will " 
    55                       "disconnect.", call->index)); 
    56             pjsua_call_hangup(call->index); 
    57         } else { 
    58             PJ_LOG(3,(THIS_FILE, "Refreshing call %d", call->index)); 
    59             schedule_call_timer(call,e,REFRESH_CALL_TIMER, 
    60                                 pjsua.config.uas_refresh); 
    61             pjsua_call_reinvite(call->index); 
    62         } 
    63  
    64     } else if (e->id == HANGUP_CALL_TIMER) { 
    65         PJ_LOG(3,(THIS_FILE, "Call %d duration exceeded, disconnecting call", 
    66                              call->index)); 
    67         pjsua_call_hangup(call->index); 
    68  
    69     } 
    70 } 
    71  
    72 /* 
    73  * Schedule call timer. 
    74  */ 
    75 static void schedule_call_timer( pjsua_call *call, pj_timer_entry *e, 
    76                                  int timer_type, int duration ) 
    77 { 
    78     pj_time_val timeout; 
    79  
    80     if (duration == 0) { 
    81         /* Cancel timer. */ 
    82         if (e->id != 0) { 
    83             pjsip_endpt_cancel_timer(pjsua.endpt, e); 
    84             e->id = 0; 
    85         } 
    86  
    87     } else { 
    88         /* Schedule timer. */ 
    89         timeout.sec = duration; 
    90         timeout.msec = 0; 
    91  
    92         e->cb = &call_on_timer; 
    93         e->id = timer_type; 
    94         e->user_data = call; 
    95  
    96         pjsip_endpt_schedule_timer( pjsua.endpt, e, &timeout); 
    97     } 
    98 } 
    99  
    100  
    101 /* 
    102  * Destroy the call's media 
    103  */ 
    104 static pj_status_t call_destroy_media(int call_index) 
    105 { 
    106     pjsua_call *call = &pjsua.calls[call_index]; 
    107  
    108     if (call->conf_slot > 0) { 
    109         pjmedia_conf_remove_port(pjsua.mconf, call->conf_slot); 
    110         call->conf_slot = 0; 
    111     } 
    112  
    113     if (call->session) { 
    114         /* Destroy session (this will also close RTP/RTCP sockets). */ 
    115         pjmedia_session_destroy(call->session); 
    116         call->session = NULL; 
    117  
    118         PJ_LOG(3,(THIS_FILE, "Media session for call %d is destroyed",  
    119                              call_index)); 
    120  
    121     } 
    122  
     20#include <pjsua-lib/pjsua_internal.h> 
     21 
     22 
     23#define THIS_FILE               "pjsua_call.c" 
     24 
     25 
     26/* This callback receives notification from invite session when the 
     27 * session state has changed. 
     28 */ 
     29static void pjsua_call_on_state_changed(pjsip_inv_session *inv,  
     30                                        pjsip_event *e); 
     31 
     32/* This callback is called by invite session framework when UAC session 
     33 * has forked. 
     34 */ 
     35static void pjsua_call_on_forked( pjsip_inv_session *inv,  
     36                                  pjsip_event *e); 
     37 
     38/* 
     39 * Callback to be called when SDP offer/answer negotiation has just completed 
     40 * in the session. This function will start/update media if negotiation 
     41 * has succeeded. 
     42 */ 
     43static void pjsua_call_on_media_update(pjsip_inv_session *inv, 
     44                                       pj_status_t status); 
     45 
     46/* 
     47 * Called when session received new offer. 
     48 */ 
     49static void pjsua_call_on_rx_offer(pjsip_inv_session *inv, 
     50                                   const pjmedia_sdp_session *offer); 
     51 
     52/* 
     53 * This callback is called when transaction state has changed in INVITE 
     54 * session. We use this to trap: 
     55 *  - incoming REFER request. 
     56 *  - incoming MESSAGE request. 
     57 */ 
     58static void pjsua_call_on_tsx_state_changed(pjsip_inv_session *inv, 
     59                                            pjsip_transaction *tsx, 
     60                                            pjsip_event *e); 
     61 
     62 
     63/* Destroy the call's media */ 
     64static pj_status_t call_destroy_media(int call_id); 
     65 
     66/* Create inactive SDP for call hold. */ 
     67static pj_status_t create_inactive_sdp(pjsua_call *call, 
     68                                       pjmedia_sdp_session **p_answer); 
     69 
     70 
     71/* 
     72 * Reset call descriptor. 
     73 */ 
     74static void reset_call(pjsua_call_id id) 
     75{ 
     76    pjsua_call *call = &pjsua_var.calls[id]; 
     77 
     78    call->index = id; 
     79    call->inv = NULL; 
     80    call->user_data = NULL; 
     81    call->session = NULL; 
     82    call->xfer_sub = NULL; 
     83    call->last_code = 0; 
     84    call->conf_slot = PJSUA_INVALID_ID; 
     85    call->last_text.ptr = call->last_text_buf_; 
     86    call->last_text.slen = 0; 
     87} 
     88 
     89 
     90/* 
     91 * Init call subsystem. 
     92 */ 
     93pj_status_t pjsua_call_subsys_init(const pjsua_config *cfg) 
     94{ 
     95    pjsip_inv_callback inv_cb; 
     96    unsigned i; 
     97    pj_status_t status; 
     98 
     99    /* Init calls array. */ 
     100    for (i=0; i<PJ_ARRAY_SIZE(pjsua_var.calls); ++i) 
     101        reset_call(i); 
     102 
     103    /* Copy config */ 
     104    pjsua_config_dup(pjsua_var.pool, &pjsua_var.ua_cfg, cfg); 
     105 
     106    /* Initialize invite session callback. */ 
     107    pj_memset(&inv_cb, 0, sizeof(inv_cb)); 
     108    inv_cb.on_state_changed = &pjsua_call_on_state_changed; 
     109    inv_cb.on_new_session = &pjsua_call_on_forked; 
     110    inv_cb.on_media_update = &pjsua_call_on_media_update; 
     111    inv_cb.on_rx_offer = &pjsua_call_on_rx_offer; 
     112    inv_cb.on_tsx_state_changed = &pjsua_call_on_tsx_state_changed; 
     113 
     114 
     115    /* Initialize invite session module: */ 
     116    status = pjsip_inv_usage_init(pjsua_var.endpt, &inv_cb); 
     117    PJ_ASSERT_RETURN(status == PJ_SUCCESS, status); 
     118 
     119    return status; 
     120} 
     121 
     122 
     123/* 
     124 * Start call subsystem. 
     125 */ 
     126pj_status_t pjsua_call_subsys_start(void) 
     127{ 
     128    /* Nothing to do */ 
    123129    return PJ_SUCCESS; 
    124130} 
    125131 
    126132 
    127 /** 
     133/* 
    128134 * Get maximum number of calls configured in pjsua. 
    129135 */ 
    130136PJ_DEF(unsigned) pjsua_call_get_max_count(void) 
    131137{ 
    132     return pjsua.config.max_calls; 
    133 } 
    134  
    135  
    136 /** 
    137  * Get current number of active calls. 
     138    return pjsua_var.ua_cfg.max_calls; 
     139} 
     140 
     141 
     142/* 
     143 * Get number of currently active calls. 
    138144 */ 
    139145PJ_DEF(unsigned) pjsua_call_get_count(void) 
    140146{ 
    141     return pjsua.call_cnt; 
    142 } 
    143  
    144  
    145 /** 
    146  * Check if the specified call is active. 
    147  */ 
    148 PJ_DEF(pj_bool_t) pjsua_call_is_active(unsigned call_index) 
    149 { 
    150     PJ_ASSERT_RETURN(call_index < pjsua.config.max_calls, 
    151                      PJ_EINVAL); 
    152     return pjsua.calls[call_index].inv != NULL && 
    153            pjsua.calls[call_index].inv->state != PJSIP_INV_STATE_DISCONNECTED; 
    154 } 
    155  
    156 /** 
    157  * Check if call has a media session. 
    158  */ 
    159 PJ_DEF(pj_bool_t) pjsua_call_has_media(unsigned call_index) 
    160 { 
    161     PJ_ASSERT_RETURN(call_index < pjsua.config.max_calls, PJ_EINVAL); 
    162     return pjsua.calls[call_index].session != NULL; 
    163 } 
    164  
    165  
    166 /** 
    167  * Get call info. 
    168  */ 
    169 PJ_DEF(pj_status_t) pjsua_call_get_info( unsigned call_index, 
    170                                          pjsua_call_info *info) 
    171 { 
    172     pjsua_call *call; 
    173  
    174     PJ_ASSERT_RETURN(call_index < pjsua.config.max_calls, 
    175                      PJ_EINVAL); 
    176  
    177     pj_memset(info, 0, sizeof(pjsua_call_info)); 
    178  
    179     call = &pjsua.calls[call_index]; 
    180     info->active = pjsua_call_is_active(call_index); 
    181  
    182     if (call->inv == NULL) 
    183         return PJ_SUCCESS; 
    184  
    185     info->index = call_index; 
    186     info->role = call->inv->role; 
    187     info->local_info = call->inv->dlg->local.info_str; 
    188     info->remote_info = call->inv->dlg->remote.info_str; 
    189     info->state = call->inv->state; 
    190     info->state_text = pj_str((char*)pjsip_inv_state_name(info->state)); 
    191      
    192     if (info->state >= PJSIP_INV_STATE_DISCONNECTED) { 
    193  
    194         info->total_duration = call->dis_time; 
    195         PJ_TIME_VAL_SUB(info->total_duration, call->start_time); 
    196  
    197         if (call->conn_time.sec) { 
    198             info->connect_duration = call->dis_time; 
    199             PJ_TIME_VAL_SUB(info->total_duration, call->conn_time); 
    200         } 
    201  
    202     } else if (info->state == PJSIP_INV_STATE_CONFIRMED) { 
    203  
    204         pj_gettimeofday(&info->total_duration); 
    205         PJ_TIME_VAL_SUB(info->total_duration, call->start_time); 
    206  
    207         pj_gettimeofday(&info->connect_duration); 
    208         PJ_TIME_VAL_SUB(info->connect_duration, call->conn_time); 
    209  
    210     } else { 
    211         pj_gettimeofday(&info->total_duration); 
    212         PJ_TIME_VAL_SUB(info->total_duration, call->start_time); 
    213     } 
    214  
    215     info->last_status = call->last_code; 
    216     info->last_status_text = *pjsip_get_status_text(info->last_status); 
    217  
    218     info->has_media = (call->session != NULL); 
    219     info->conf_slot = call->conf_slot; 
     147    return pjsua_var.call_cnt; 
     148} 
     149 
     150 
     151/* 
     152 * Enum calls. 
     153 */ 
     154PJ_DEF(pj_status_t) pjsua_enum_calls( pjsua_call_id ids[], 
     155                                      unsigned *count) 
     156{ 
     157    unsigned i, c; 
     158 
     159    PJ_ASSERT_RETURN(ids && *count, PJ_EINVAL); 
     160 
     161    PJSUA_LOCK(); 
     162 
     163    for (i=0, c=0; c<*count && i<pjsua_var.ua_cfg.max_calls; ++i) { 
     164        if (!pjsua_var.calls[i].inv) 
     165            continue; 
     166        ids[c] = i; 
     167        ++c; 
     168    } 
     169 
     170    *count = c; 
     171 
     172    PJSUA_UNLOCK(); 
    220173 
    221174    return PJ_SUCCESS; 
     
    223176 
    224177 
    225 /** 
    226  * Duplicate call info. 
    227  */ 
    228 PJ_DEF(void) pjsua_call_info_dup( pj_pool_t *pool, 
    229                                   pjsua_call_info *dst_info, 
    230                                   const pjsua_call_info *src_info) 
    231 { 
    232     PJ_ASSERT_ON_FAIL(pool && dst_info && src_info, return); 
    233  
    234     pj_memcpy(dst_info, src_info, sizeof(pjsua_call_info)); 
    235  
    236     pj_strdup(pool, &dst_info->local_info, &src_info->local_info); 
    237     pj_strdup(pool, &dst_info->remote_info, &src_info->remote_info); 
    238      
    239     /* state_text and cause_text belong to pjsip, so don't need to be 
    240      * duplicated because they'll always be available. 
    241      */ 
    242 } 
    243  
    244  
    245 /** 
    246  * Make outgoing call. 
    247  */ 
    248 PJ_DEF(pj_status_t) pjsua_call_make_call(unsigned acc_index, 
    249                                          const pj_str_t *dest_uri, 
    250                                          int *p_call_index) 
     178/* 
     179 * Make outgoing call to the specified URI using the specified account. 
     180 */ 
     181PJ_DEF(pj_status_t) pjsua_call_make_call( pjsua_acc_id acc_id, 
     182                                          const pj_str_t *dest_uri, 
     183                                          unsigned options, 
     184                                          void *user_data, 
     185                                          const pjsua_msg_data *msg_data, 
     186                                          pjsua_call_id *p_call_id) 
    251187{ 
    252188    pjsip_dialog *dlg = NULL; 
    253189    pjmedia_sdp_session *offer; 
    254190    pjsip_inv_session *inv = NULL; 
    255     unsigned call_index; 
     191    pjsua_acc *acc; 
     192    pjsua_call *call; 
     193    unsigned call_id; 
    256194    pjsip_tx_data *tdata; 
    257195    pj_status_t status; 
    258196 
    259197 
    260     PJ_ASSERT_RETURN(acc_index==0 || acc_index < pjsua.config.acc_cnt,  
     198    /* Check that account is valid */ 
     199    PJ_ASSERT_RETURN(acc_id>=0 || acc_id<PJ_ARRAY_SIZE(pjsua_var.acc),  
    261200                     PJ_EINVAL); 
    262201 
     202    /* Options must be zero for now */ 
     203    PJ_ASSERT_RETURN(options == 0, PJ_EINVAL); 
     204 
     205    PJSUA_LOCK(); 
     206 
     207    acc = &pjsua_var.acc[acc_id]; 
     208    if (!acc->valid) { 
     209        pjsua_perror(THIS_FILE, "Unable to make call because account " 
     210                     "is not valid", PJ_EINVALIDOP); 
     211        PJSUA_UNLOCK(); 
     212        return PJ_EINVALIDOP; 
     213    } 
    263214 
    264215    /* Find free call slot. */ 
    265     for (call_index=0; call_index<pjsua.config.max_calls; ++call_index) { 
    266         if (pjsua.calls[call_index].inv == NULL) 
     216    for (call_id=0; call_id<pjsua_var.ua_cfg.max_calls; ++call_id) { 
     217        if (pjsua_var.calls[call_id].inv == NULL) 
    267218            break; 
    268219    } 
    269220 
    270     if (call_index == pjsua.config.max_calls) { 
    271         PJ_LOG(3,(THIS_FILE, "Error: too many calls!")); 
     221    if (call_id == pjsua_var.ua_cfg.max_calls) { 
     222        pjsua_perror(THIS_FILE, "Error making file", PJ_ETOOMANY); 
     223        PJSUA_UNLOCK(); 
    272224        return PJ_ETOOMANY; 
    273225    } 
    274226 
     227    call = &pjsua_var.calls[call_id]; 
     228 
    275229    /* Mark call start time. */ 
    276     pj_gettimeofday(&pjsua.calls[call_index].start_time); 
     230    pj_gettimeofday(&call->start_time); 
    277231 
    278232    /* Reset first response time */ 
    279     pjsua.calls[call_index].res_time.sec = 0; 
     233    call->res_time.sec = 0; 
    280234 
    281235    /* Create outgoing dialog: */ 
    282236    status = pjsip_dlg_create_uac( pjsip_ua_instance(),  
    283                                    &pjsua.config.acc_config[acc_index].id, 
    284                                    &pjsua.config.acc_config[acc_index].contact, 
    285                                    dest_uri, dest_uri, 
    286                                    &dlg); 
     237                                   &acc->cfg.id, &acc->cfg.contact, 
     238                                   dest_uri, dest_uri, &dlg); 
    287239    if (status != PJ_SUCCESS) { 
    288240        pjsua_perror(THIS_FILE, "Dialog creation failed", status); 
     241        PJSUA_UNLOCK(); 
    289242        return status; 
    290243    } 
     
    292245    /* Get media capability from media endpoint: */ 
    293246 
    294     status = pjmedia_endpt_create_sdp( pjsua.med_endpt, dlg->pool, 1,  
    295                                        &pjsua.calls[call_index].skinfo,  
    296                                        &offer); 
     247    status = pjmedia_endpt_create_sdp( pjsua_var.med_endpt, dlg->pool, 1,  
     248                                       &call->skinfo, &offer); 
    297249    if (status != PJ_SUCCESS) { 
    298250        pjsua_perror(THIS_FILE, "pjmedia unable to create SDP", status); 
     
    311263    /* Create and associate our data in the session. */ 
    312264 
    313     pjsua.calls[call_index].inv = inv; 
    314  
    315     dlg->mod_data[pjsua.mod.id] = &pjsua.calls[call_index]; 
    316     inv->mod_data[pjsua.mod.id] = &pjsua.calls[call_index]; 
    317  
     265    call->inv = inv; 
     266 
     267    dlg->mod_data[pjsua_var.mod.id] = call; 
     268    inv->mod_data[pjsua_var.mod.id] = call; 
     269 
     270    /* Attach user data */ 
     271    call->user_data = user_data; 
    318272 
    319273    /* Set dialog Route-Set: */ 
    320  
    321     if (!pj_list_empty(&pjsua.acc[acc_index].route_set)) 
    322         pjsip_dlg_set_route_set(dlg, &pjsua.acc[acc_index].route_set); 
     274    if (!pj_list_empty(&acc->route_set)) 
     275        pjsip_dlg_set_route_set(dlg, &acc->route_set); 
    323276 
    324277 
    325278    /* Set credentials: */ 
    326     if (pjsua.config.acc_config[acc_index].cred_count) { 
    327         pjsua_acc_config *acc_cfg = &pjsua.config.acc_config[acc_index]; 
     279    if (acc->cred_cnt) { 
    328280        pjsip_auth_clt_set_credentials( &dlg->auth_sess,  
    329                                         acc_cfg->cred_count, 
    330                                         acc_cfg->cred_info); 
     281                                        acc->cred_cnt, acc->cred); 
    331282    } 
    332283 
     
    341292    } 
    342293 
     294 
     295    /* Add additional headers etc */ 
     296 
     297    pjsua_process_msg_data( tdata, msg_data); 
    343298 
    344299    /* Send initial INVITE: */ 
     
    357312    } 
    358313 
    359  
    360314    /* Done. */ 
    361315 
    362     ++pjsua.call_cnt; 
    363  
    364     if (p_call_index) 
    365         *p_call_index = call_index; 
     316    ++pjsua_var.call_cnt; 
     317 
     318    if (p_call_id) 
     319        *p_call_id = call_id; 
     320 
     321    PJSUA_UNLOCK(); 
    366322 
    367323    return PJ_SUCCESS; 
     
    375331    } 
    376332 
    377     if (call_index != -1) { 
    378         pjsua.calls[call_index].inv = NULL; 
    379     } 
    380     return status; 
    381 } 
    382  
    383  
    384 /** 
    385  * Answer call. 
    386  */ 
    387 PJ_DEF(pj_status_t) pjsua_call_answer(int call_index, int code) 
    388 { 
    389     pjsip_tx_data *tdata; 
    390     pj_status_t status; 
    391  
    392     PJ_ASSERT_RETURN( call_index >= 0 &&  
    393                       call_index < (int)pjsua.config.max_calls, 
    394                       PJ_EINVAL); 
    395  
    396     if (pjsua.calls[call_index].inv == NULL) { 
    397         PJ_LOG(3,(THIS_FILE, "Call %d already disconnected")); 
    398         return PJSIP_ESESSIONTERMINATED; 
    399     } 
    400  
    401     status = pjsip_inv_answer(pjsua.calls[call_index].inv, 
    402                               code, NULL, NULL, &tdata); 
    403     if (status == PJ_SUCCESS) 
    404         status = pjsip_inv_send_msg(pjsua.calls[call_index].inv, 
    405                                     tdata); 
    406  
    407     if (status != PJ_SUCCESS) 
    408         pjsua_perror(THIS_FILE, "Unable to create/send response",  
    409                      status); 
    410  
     333    if (call_id != -1) { 
     334        reset_call(call_id); 
     335    } 
     336 
     337    PJSUA_UNLOCK(); 
    411338    return status; 
    412339} 
     
    415342/** 
    416343 * Handle incoming INVITE request. 
     344 * Called by pjsua_core.c 
    417345 */ 
    418346pj_bool_t pjsua_call_on_incoming(pjsip_rx_data *rdata) 
     
    424352    unsigned options = 0; 
    425353    pjsip_inv_session *inv = NULL; 
    426     int acc_index; 
    427     unsigned call_index; 
     354    int acc_id; 
     355    pjsua_call *call; 
     356    int call_id = -1; 
    428357    pjmedia_sdp_session *answer; 
    429358    pj_status_t status; 
     
    442371    /* Verify that we can handle the request. */ 
    443372    status = pjsip_inv_verify_request(rdata, &options, NULL, NULL, 
    444                                       pjsua.endpt, &response); 
     373                                      pjsua_var.endpt, &response); 
    445374    if (status != PJ_SUCCESS) { 
    446375 
     
    453382 
    454383            pjsip_get_response_addr(response->pool, rdata, &res_addr); 
    455             pjsip_endpt_send_response(pjsua.endpt, &res_addr, response,  
     384            pjsip_endpt_send_response(pjsua_var.endpt, &res_addr, response,  
    456385                                      NULL, NULL); 
    457386 
     
    459388 
    460389            /* Respond with 500 (Internal Server Error) */ 
    461             pjsip_endpt_respond_stateless(pjsua.endpt, rdata, 500, NULL, 
     390            pjsip_endpt_respond_stateless(pjsua_var.endpt, rdata, 500, NULL, 
    462391                                          NULL, NULL); 
    463392        } 
     
    472401 
    473402    /* Find free call slot. */ 
    474     for (call_index=0; call_index < pjsua.config.max_calls; ++call_index) { 
    475         if (pjsua.calls[call_index].inv == NULL) 
     403    for (call_id=0; call_id<(int)pjsua_var.ua_cfg.max_calls; ++call_id) { 
     404        if (pjsua_var.calls[call_id].inv == NULL) 
    476405            break; 
    477406    } 
    478407 
    479     if (call_index == PJSUA_MAX_CALLS) { 
    480         pjsip_endpt_respond_stateless(pjsua.endpt, rdata,  
     408    if (call_id == (int)pjsua_var.ua_cfg.max_calls) { 
     409        pjsip_endpt_respond_stateless(pjsua_var.endpt, rdata,  
    481410                                      PJSIP_SC_BUSY_HERE, NULL, 
    482411                                      NULL, NULL); 
     
    484413    } 
    485414 
     415    /* Clear call descriptor */ 
     416    reset_call(call_id); 
     417 
     418    call = &pjsua_var.calls[call_id]; 
     419 
    486420    /* Mark call start time. */ 
    487     pj_gettimeofday(&pjsua.calls[call_index].start_time); 
    488  
    489     /* Reset first response time */ 
    490     pjsua.calls[call_index].res_time.sec = 0; 
     421    pj_gettimeofday(&call->start_time); 
    491422 
    492423    /* Get media capability from media endpoint: */ 
    493  
    494     status = pjmedia_endpt_create_sdp( pjsua.med_endpt, rdata->tp_info.pool, 1, 
    495                                        &pjsua.calls[call_index].skinfo,  
    496                                        &answer ); 
    497     if (status != PJ_SUCCESS) { 
    498         pjsip_endpt_respond_stateless(pjsua.endpt, rdata, 500, NULL, 
     424    status = pjmedia_endpt_create_sdp( pjsua_var.med_endpt,  
     425                                       rdata->tp_info.pool, 1, 
     426                                       &call->skinfo, &answer ); 
     427    if (status != PJ_SUCCESS) { 
     428        pjsip_endpt_respond_stateless(pjsua_var.endpt, rdata, 500, NULL, 
    499429                                      NULL, NULL); 
    500  
    501430        return PJ_TRUE; 
    502431    } 
    503432 
    504     /* TODO:  
    505      * 
     433    /*  
    506434     * Get which account is most likely to be associated with this incoming 
    507435     * call. We need the account to find which contact URI to put for 
    508436     * the call. 
    509437     */ 
    510     acc_index = 0; 
     438    acc_id = pjsua_acc_find_for_incoming(rdata); 
    511439 
    512440    /* Create dialog: */ 
    513  
    514441    status = pjsip_dlg_create_uas( pjsip_ua_instance(), rdata, 
    515                                    &pjsua.config.acc_config[acc_index].contact, 
     442                                   &pjsua_var.acc[acc_id].cfg.contact,  
    516443                                   &dlg); 
    517444    if (status != PJ_SUCCESS) { 
    518         pjsip_endpt_respond_stateless(pjsua.endpt, rdata, 500, NULL, 
     445        pjsip_endpt_respond_stateless(pjsua_var.endpt, rdata, 500, NULL, 
    519446                                      NULL, NULL); 
    520447 
     
    522449    } 
    523450 
     451    /* Set credentials */ 
     452    if (pjsua_var.acc[acc_id].cred_cnt) { 
     453        pjsip_auth_clt_set_credentials(&dlg->auth_sess,  
     454                                       pjsua_var.acc[acc_id].cred_cnt, 
     455                                       pjsua_var.acc[acc_id].cred); 
     456    } 
    524457 
    525458    /* Create invite session: */ 
    526  
    527459    status = pjsip_inv_create_uas( dlg, rdata, answer, 0, &inv); 
    528460    if (status != PJ_SUCCESS) { 
    529  
    530461        pjsip_dlg_respond(dlg, rdata, 500, NULL, NULL, NULL); 
    531462        pjsip_dlg_terminate(dlg); 
     
    534465 
    535466 
    536     /* Create and attach pjsua data to the dialog: */ 
    537  
    538     pjsua.calls[call_index].inv = inv; 
    539  
    540     dlg->mod_data[pjsua.mod.id] = &pjsua.calls[call_index]; 
    541     inv->mod_data[pjsua.mod.id] = &pjsua.calls[call_index]; 
     467    /* Create and attach pjsua_var data to the dialog: */ 
     468    call->inv = inv; 
     469 
     470    dlg->mod_data[pjsua_var.mod.id] = call; 
     471    inv->mod_data[pjsua_var.mod.id] = call; 
    542472 
    543473 
     
    545475     * If auto-answer flag is set, send 200 straight away, otherwise send 100. 
    546476     */ 
    547      
    548477    status = pjsip_inv_initial_answer(inv, rdata,  
    549                                       (pjsua.config.auto_answer ?  
    550                                       pjsua.config.auto_answer : 100),  
    551                                       NULL, NULL, &response); 
    552     if (status != PJ_SUCCESS) { 
    553          
    554         int st_code; 
    555  
     478                                      100, NULL, NULL, &response); 
     479    if (status != PJ_SUCCESS) { 
    556480        pjsua_perror(THIS_FILE, "Unable to send answer to incoming INVITE",  
    557481                     status); 
    558482 
    559         /* If failed to send 2xx response, there's a good chance that it is 
    560          * because SDP negotiation has failed. 
    561          */ 
    562         if (pjsua.config.auto_answer/100 == 2) 
    563             st_code = PJSIP_SC_UNSUPPORTED_MEDIA_TYPE; 
    564         else 
    565             st_code = 500; 
    566  
    567         pjsip_dlg_respond(dlg, rdata, st_code, NULL, NULL, NULL); 
    568         pjsip_inv_terminate(inv, st_code, PJ_FALSE); 
     483        pjsip_dlg_respond(dlg, rdata, 500, NULL, NULL, NULL); 
     484        pjsip_inv_terminate(inv, 500, PJ_FALSE); 
    569485        return PJ_TRUE; 
    570486 
     
    575491    } 
    576492 
    577     if (pjsua.config.auto_answer < 200) { 
    578         PJ_LOG(3,(THIS_FILE, 
    579                   "\nIncoming call!!\n" 
    580                   "From: %.*s\n" 
    581                   "To:   %.*s\n" 
    582                   "(press 'a' to answer, 'h' to decline)", 
    583                   (int)dlg->remote.info_str.slen, 
    584                   dlg->remote.info_str.ptr, 
    585                   (int)dlg->local.info_str.slen, 
    586                   dlg->local.info_str.ptr)); 
    587     } else { 
    588         PJ_LOG(3,(THIS_FILE, 
    589                   "Call From:%.*s To:%.*s was answered with %d (%s)", 
    590                   (int)dlg->remote.info_str.slen, 
    591                   dlg->remote.info_str.ptr, 
    592                   (int)dlg->local.info_str.slen, 
    593                   dlg->local.info_str.ptr, 
    594                   pjsua.config.auto_answer, 
    595                   pjsip_get_status_text(pjsua.config.auto_answer)->ptr )); 
    596     } 
    597  
    598     ++pjsua.call_cnt; 
    599  
    600     /* Schedule timer to refresh. */ 
    601     if (pjsua.config.uas_refresh > 0) { 
    602         schedule_call_timer( &pjsua.calls[call_index],  
    603                              &pjsua.calls[call_index].refresh_tm, 
    604                              REFRESH_CALL_TIMER, 
    605                              pjsua.config.uas_refresh); 
    606     } 
    607  
    608     /* Schedule timer to hangup call. */ 
    609     if (pjsua.config.uas_duration > 0) { 
    610         schedule_call_timer( &pjsua.calls[call_index],  
    611                              &pjsua.calls[call_index].hangup_tm, 
    612                              HANGUP_CALL_TIMER, 
    613                              pjsua.config.uas_duration); 
    614     } 
     493    ++pjsua_var.call_cnt; 
     494 
    615495 
    616496    /* Notify application */ 
    617     if (pjsua.cb.on_incoming_call) 
    618         pjsua.cb.on_incoming_call(acc_index, call_index, rdata); 
    619  
     497    if (pjsua_var.ua_cfg.cb.on_incoming_call) 
     498        pjsua_var.ua_cfg.cb.on_incoming_call(acc_id, call_id, rdata); 
    620499 
    621500    /* This INVITE request has been handled. */ 
     
    624503 
    625504 
     505 
     506/* 
     507 * Check if the specified call has active INVITE session and the INVITE 
     508 * session has not been disconnected. 
     509 */ 
     510PJ_DEF(pj_bool_t) pjsua_call_is_active(pjsua_call_id call_id) 
     511{ 
     512    PJ_ASSERT_RETURN(call_id>=0 && call_id<(int)pjsua_var.ua_cfg.max_calls, 
     513                     PJ_EINVAL); 
     514    return pjsua_var.calls[call_id].inv != NULL && 
     515           pjsua_var.calls[call_id].inv->state != PJSIP_INV_STATE_DISCONNECTED; 
     516} 
     517 
     518 
     519/* 
     520 * Check if call has an active media session. 
     521 */ 
     522PJ_DEF(pj_bool_t) pjsua_call_has_media(pjsua_call_id call_id) 
     523{ 
     524    PJ_ASSERT_RETURN(call_id>=0 && call_id<(int)pjsua_var.ua_cfg.max_calls,  
     525                     PJ_EINVAL); 
     526    return pjsua_var.calls[call_id].session != NULL; 
     527} 
     528 
     529 
     530/* 
     531 * Get the conference port identification associated with the call. 
     532 */ 
     533PJ_DEF(pjsua_conf_port_id) pjsua_call_get_conf_port(pjsua_call_id call_id) 
     534{ 
     535    PJ_ASSERT_RETURN(call_id>=0 && call_id<(int)pjsua_var.ua_cfg.max_calls,  
     536                     PJ_EINVAL); 
     537    return pjsua_var.calls[call_id].conf_slot; 
     538} 
     539 
     540 
     541/* 
     542 * Obtain detail information about the specified call. 
     543 */ 
     544PJ_DEF(pj_status_t) pjsua_call_get_info( pjsua_call_id call_id, 
     545                                         pjsua_call_info *info) 
     546{ 
     547    pjsua_call *call; 
     548 
     549    PJ_ASSERT_RETURN(call_id>=0 && call_id<(int)pjsua_var.ua_cfg.max_calls, 
     550                     PJ_EINVAL); 
     551 
     552    pj_memset(info, 0, sizeof(*info)); 
     553 
     554    PJSUA_LOCK(); 
     555 
     556    call = &pjsua_var.calls[call_id]; 
     557 
     558    if (call->inv == NULL) { 
     559        PJSUA_UNLOCK(); 
     560        return PJ_SUCCESS; 
     561    } 
     562 
     563    pjsip_dlg_inc_lock(call->inv->dlg); 
     564 
     565 
     566    /* id and role */ 
     567    info->id = call_id; 
     568    info->role = call->inv->role; 
     569 
     570    /* local info */ 
     571    info->local_info.ptr = info->buf_.local_info; 
     572    pj_strncpy(&info->local_info, &call->inv->dlg->local.info_str, 
     573               sizeof(info->buf_.local_info)); 
     574 
     575    /* local contact */ 
     576    info->local_contact.ptr = info->buf_.local_contact; 
     577    info->local_contact.slen = pjsip_uri_print(PJSIP_URI_IN_CONTACT_HDR, 
     578                                               call->inv->dlg->local.contact->uri, 
     579                                               info->local_contact.ptr, 
     580                                               sizeof(info->buf_.local_contact)); 
     581 
     582    /* remote info */ 
     583    info->remote_info.ptr = info->buf_.remote_info; 
     584    pj_strncpy(&info->remote_info, &call->inv->dlg->remote.info_str, 
     585               sizeof(info->buf_.remote_info)); 
     586 
     587    /* remote contact */ 
     588    if (call->inv->dlg->remote.contact) { 
     589        int len; 
     590        info->remote_contact.ptr = info->buf_.remote_contact; 
     591        len = pjsip_uri_print(PJSIP_URI_IN_CONTACT_HDR, 
     592                              call->inv->dlg->remote.contact->uri, 
     593                              info->remote_contact.ptr, 
     594                              sizeof(info->buf_.remote_contact)); 
     595        if (len < 0) len = 0; 
     596        info->remote_contact.slen = len; 
     597    } else { 
     598        info->remote_contact.slen = 0; 
     599    } 
     600 
     601    /* call id */ 
     602    info->call_id.ptr = info->buf_.call_id; 
     603    pj_strncpy(&info->call_id, &call->inv->dlg->call_id->id, 
     604               sizeof(info->buf_.call_id)); 
     605 
     606    /* state, state_text */ 
     607    info->state = call->inv->state; 
     608    info->state_text = pj_str((char*)pjsip_inv_state_name(info->state)); 
     609 
     610    /* If call is disconnected, set the last_status from the cause code */ 
     611    if (call->inv->state >= PJSIP_INV_STATE_DISCONNECTED) { 
     612        /* last_status, last_status_text */ 
     613        info->last_status = call->inv->cause; 
     614 
     615        info->last_status_text.ptr = info->buf_.last_status_text; 
     616        pj_strncpy(&info->last_status_text, &call->inv->cause_text, 
     617                   sizeof(info->buf_.last_status_text)); 
     618    } else { 
     619        /* last_status, last_status_text */ 
     620        info->last_status = call->last_code; 
     621 
     622        info->last_status_text.ptr = info->buf_.last_status_text; 
     623        pj_strncpy(&info->last_status_text, &call->last_text, 
     624                   sizeof(info->buf_.last_status_text)); 
     625    } 
     626     
     627    /* media status and dir */ 
     628    info->media_status = call->media_st; 
     629    info->media_dir = call->media_dir; 
     630 
     631 
     632    /* conference slot number */ 
     633    info->conf_slot = call->conf_slot; 
     634 
     635    /* calculate duration */ 
     636    if (info->state >= PJSIP_INV_STATE_DISCONNECTED) { 
     637 
     638        info->total_duration = call->dis_time; 
     639        PJ_TIME_VAL_SUB(info->total_duration, call->start_time); 
     640 
     641        if (call->conn_time.sec) { 
     642            info->connect_duration = call->dis_time; 
     643            PJ_TIME_VAL_SUB(info->connect_duration, call->conn_time); 
     644        } 
     645 
     646    } else if (info->state == PJSIP_INV_STATE_CONFIRMED) { 
     647 
     648        pj_gettimeofday(&info->total_duration); 
     649        PJ_TIME_VAL_SUB(info->total_duration, call->start_time); 
     650 
     651        pj_gettimeofday(&info->connect_duration); 
     652        PJ_TIME_VAL_SUB(info->connect_duration, call->conn_time); 
     653 
     654    } else { 
     655        pj_gettimeofday(&info->total_duration); 
     656        PJ_TIME_VAL_SUB(info->total_duration, call->start_time); 
     657    } 
     658 
     659    pjsip_dlg_dec_lock(call->inv->dlg); 
     660    PJSUA_UNLOCK(); 
     661 
     662    return PJ_SUCCESS; 
     663} 
     664 
     665 
     666/* 
     667 * Attach application specific data to the call. 
     668 */ 
     669PJ_DEF(pj_status_t) pjsua_call_set_user_data( pjsua_call_id call_id, 
     670                                              void *user_data) 
     671{ 
     672    PJ_ASSERT_RETURN(call_id>=0 && call_id<(int)pjsua_var.ua_cfg.max_calls, 
     673                     PJ_EINVAL); 
     674    pjsua_var.calls[call_id].user_data = user_data; 
     675 
     676    return PJ_SUCCESS; 
     677} 
     678 
     679 
     680/* 
     681 * Get user data attached to the call. 
     682 */ 
     683PJ_DEF(void*) pjsua_call_get_user_data(pjsua_call_id call_id) 
     684{ 
     685    PJ_ASSERT_RETURN(call_id>=0 && call_id<(int)pjsua_var.ua_cfg.max_calls, 
     686                     NULL); 
     687    return pjsua_var.calls[call_id].user_data; 
     688} 
     689 
     690 
     691/* 
     692 * Send response to incoming INVITE request. 
     693 */ 
     694PJ_DEF(pj_status_t) pjsua_call_answer( pjsua_call_id call_id,  
     695                                       unsigned code, 
     696                                       const pj_str_t *reason, 
     697                                       const pjsua_msg_data *msg_data) 
     698{ 
     699    pjsua_call *call; 
     700    pjsip_tx_data *tdata; 
     701    pj_status_t status; 
     702 
     703    PJ_ASSERT_RETURN(call_id>=0 && call_id<(int)pjsua_var.ua_cfg.max_calls, 
     704                     PJ_EINVAL); 
     705 
     706    PJSUA_LOCK(); 
     707 
     708    call = &pjsua_var.calls[call_id]; 
     709 
     710    if (call->inv == NULL) { 
     711        PJ_LOG(3,(THIS_FILE, "Call %d already disconnected", call_id)); 
     712        PJSUA_UNLOCK(); 
     713        return PJSIP_ESESSIONTERMINATED; 
     714    } 
     715 
     716    /* Create response message */ 
     717    status = pjsip_inv_answer(call->inv, code, reason, NULL, &tdata); 
     718    if (status != PJ_SUCCESS) { 
     719        pjsua_perror(THIS_FILE, "Error creating response",  
     720                     status); 
     721        PJSUA_UNLOCK(); 
     722        return status; 
     723    } 
     724 
     725    /* Add additional headers etc */ 
     726    pjsua_process_msg_data( tdata, msg_data); 
     727 
     728    /* Send the message */ 
     729    status = pjsip_inv_send_msg(call->inv, tdata); 
     730    if (status != PJ_SUCCESS) 
     731        pjsua_perror(THIS_FILE, "Error sending response",  
     732                     status); 
     733 
     734    PJSUA_UNLOCK(); 
     735 
     736    return status; 
     737} 
     738 
     739 
     740/* 
     741 * Hangup call by using method that is appropriate according to the 
     742 * call state. 
     743 */ 
     744PJ_DEF(pj_status_t) pjsua_call_hangup(pjsua_call_id call_id, 
     745                                      unsigned code, 
     746                                      const pj_str_t *reason, 
     747                                      const pjsua_msg_data *msg_data) 
     748{ 
     749    pjsua_call *call; 
     750    pj_status_t status; 
     751    pjsip_tx_data *tdata; 
     752 
     753 
     754    PJ_ASSERT_RETURN(call_id>=0 && call_id<(int)pjsua_var.ua_cfg.max_calls, 
     755                     PJ_EINVAL); 
     756 
     757    PJSUA_LOCK(); 
     758 
     759    call = &pjsua_var.calls[call_id]; 
     760 
     761    if (!call->inv) { 
     762        PJ_LOG(3,(THIS_FILE,"Call has been disconnected")); 
     763        PJSUA_UNLOCK(); 
     764        return PJ_EINVAL; 
     765    } 
     766 
     767    if (code==0) { 
     768        if (call->inv->state == PJSIP_INV_STATE_CONFIRMED) 
     769            code = PJSIP_SC_OK; 
     770        else if (call->inv->role == PJSIP_ROLE_UAS) 
     771            code = PJSIP_SC_DECLINE; 
     772        else 
     773            code = PJSIP_SC_REQUEST_TERMINATED; 
     774    } 
     775 
     776    status = pjsip_inv_end_session(call->inv, code, reason, &tdata); 
     777    if (status != PJ_SUCCESS) { 
     778        pjsua_perror(THIS_FILE,  
     779                     "Failed to create end session message",  
     780                     status); 
     781        PJSUA_UNLOCK(); 
     782        return status; 
     783    } 
     784 
     785    /* pjsip_inv_end_session may return PJ_SUCCESS with NULL  
     786     * as p_tdata when INVITE transaction has not been answered 
     787     * with any provisional responses. 
     788     */ 
     789    if (tdata == NULL) { 
     790        PJSUA_UNLOCK(); 
     791        return PJ_SUCCESS; 
     792    } 
     793 
     794    /* Add additional headers etc */ 
     795    pjsua_process_msg_data( tdata, msg_data); 
     796 
     797    /* Send the message */ 
     798    status = pjsip_inv_send_msg(call->inv, tdata); 
     799    if (status != PJ_SUCCESS) { 
     800        pjsua_perror(THIS_FILE,  
     801                     "Failed to send end session message",  
     802                     status); 
     803        PJSUA_UNLOCK(); 
     804        return status; 
     805    } 
     806 
     807    PJSUA_UNLOCK(); 
     808 
     809    return PJ_SUCCESS; 
     810} 
     811 
     812 
     813/* 
     814 * Put the specified call on hold. 
     815 */ 
     816PJ_DEF(pj_status_t) pjsua_call_set_hold(pjsua_call_id call_id, 
     817                                        const pjsua_msg_data *msg_data) 
     818{ 
     819    pjmedia_sdp_session *sdp; 
     820    pjsua_call *call; 
     821    pjsip_tx_data *tdata; 
     822    pj_status_t status; 
     823 
     824    PJ_ASSERT_RETURN(call_id>=0 && call_id<(int)pjsua_var.ua_cfg.max_calls, 
     825                     PJ_EINVAL); 
     826 
     827    PJSUA_LOCK(); 
     828 
     829    call = &pjsua_var.calls[call_id]; 
     830     
     831    if (!call->inv) { 
     832        PJ_LOG(3,(THIS_FILE,"Call has been disconnected")); 
     833        PJSUA_UNLOCK(); 
     834        return PJSIP_ESESSIONTERMINATED; 
     835    } 
     836 
     837    if (call->inv->state != PJSIP_INV_STATE_CONFIRMED) { 
     838        PJ_LOG(3,(THIS_FILE, "Can not hold call that is not confirmed")); 
     839        PJSUA_UNLOCK(); 
     840        return PJSIP_ESESSIONSTATE; 
     841    } 
     842 
     843    status = create_inactive_sdp(call, &sdp); 
     844    if (status != PJ_SUCCESS) { 
     845        PJSUA_UNLOCK(); 
     846        return status; 
     847    } 
     848 
     849    /* Create re-INVITE with new offer */ 
     850    status = pjsip_inv_reinvite( call->inv, NULL, sdp, &tdata); 
     851    if (status != PJ_SUCCESS) { 
     852        pjsua_perror(THIS_FILE, "Unable to create re-INVITE", status); 
     853        PJSUA_UNLOCK(); 
     854        return status; 
     855    } 
     856 
     857    /* Add additional headers etc */ 
     858    pjsua_process_msg_data( tdata, msg_data); 
     859 
     860    /* Send the request */ 
     861    status = pjsip_inv_send_msg( call->inv, tdata); 
     862    if (status != PJ_SUCCESS) { 
     863        pjsua_perror(THIS_FILE, "Unable to send re-INVITE", status); 
     864        PJSUA_UNLOCK(); 
     865        return status; 
     866    } 
     867 
     868    PJSUA_UNLOCK(); 
     869 
     870    return PJ_SUCCESS; 
     871} 
     872 
     873 
     874/* 
     875 * Send re-INVITE (to release hold). 
     876 */ 
     877PJ_DEF(pj_status_t) pjsua_call_reinvite( pjsua_call_id call_id, 
     878                                         pj_bool_t unhold, 
     879                                         const pjsua_msg_data *msg_data) 
     880{ 
     881    pjmedia_sdp_session *sdp; 
     882    pjsip_tx_data *tdata; 
     883    pjsua_call *call; 
     884    pj_status_t status; 
     885 
     886 
     887    PJ_ASSERT_RETURN(call_id>=0 && call_id<(int)pjsua_var.ua_cfg.max_calls, 
     888                     PJ_EINVAL); 
     889 
     890    PJSUA_LOCK(); 
     891 
     892    call = &pjsua_var.calls[call_id]; 
     893 
     894    if (!call->inv) { 
     895        PJ_LOG(3,(THIS_FILE,"Call has been disconnected")); 
     896        PJSUA_UNLOCK(); 
     897        return PJSIP_ESESSIONTERMINATED; 
     898    } 
     899 
     900 
     901    if (call->inv->state != PJSIP_INV_STATE_CONFIRMED) { 
     902        PJ_LOG(3,(THIS_FILE, "Can not re-INVITE call that is not confirmed")); 
     903        PJSUA_UNLOCK(); 
     904        return PJSIP_ESESSIONSTATE; 
     905    } 
     906 
     907    /* Create SDP */ 
     908    status = pjmedia_endpt_create_sdp( pjsua_var.med_endpt, call->inv->pool,  
     909                                       1, &call->skinfo, &sdp); 
     910    if (status != PJ_SUCCESS) { 
     911        pjsua_perror(THIS_FILE, "Unable to get SDP from media endpoint",  
     912                     status); 
     913        PJSUA_UNLOCK(); 
     914        return status; 
     915    } 
     916 
     917    /* Create re-INVITE with new offer */ 
     918    status = pjsip_inv_reinvite( call->inv, NULL, sdp, &tdata); 
     919    if (status != PJ_SUCCESS) { 
     920        pjsua_perror(THIS_FILE, "Unable to create re-INVITE", status); 
     921        PJSUA_UNLOCK(); 
     922        return status; 
     923    } 
     924 
     925    /* Add additional headers etc */ 
     926    pjsua_process_msg_data( tdata, msg_data); 
     927 
     928    /* Send the request */ 
     929    status = pjsip_inv_send_msg( call->inv, tdata); 
     930    if (status != PJ_SUCCESS) { 
     931        pjsua_perror(THIS_FILE, "Unable to send re-INVITE", status); 
     932        PJSUA_UNLOCK(); 
     933        return status; 
     934    } 
     935 
     936    PJSUA_UNLOCK(); 
     937 
     938    return PJ_SUCCESS; 
     939} 
     940 
     941 
     942/* 
     943 * Initiate call transfer to the specified address. 
     944 */ 
     945PJ_DEF(pj_status_t) pjsua_call_xfer( pjsua_call_id call_id,  
     946                                     const pj_str_t *dest, 
     947                                     const pjsua_msg_data *msg_data) 
     948{ 
     949    pjsip_evsub *sub; 
     950    pjsip_tx_data *tdata; 
     951    pjsua_call *call; 
     952    pj_status_t status; 
     953 
     954 
     955    PJ_ASSERT_RETURN(call_id>=0 && call_id<(int)pjsua_var.ua_cfg.max_calls, 
     956                     PJ_EINVAL); 
     957     
     958    PJSUA_LOCK(); 
     959 
     960    call = &pjsua_var.calls[call_id]; 
     961 
     962    if (!call->inv) { 
     963        PJ_LOG(3,(THIS_FILE,"Call has been disconnected")); 
     964        PJSUA_UNLOCK(); 
     965        return PJSIP_ESESSIONTERMINATED; 
     966    } 
     967    
     968    /* Create xfer client subscription. 
     969     * We're not interested in knowing the transfer result, so we 
     970     * put NULL as the callback. 
     971     */ 
     972    status = pjsip_xfer_create_uac(call->inv->dlg, NULL, &sub); 
     973    if (status != PJ_SUCCESS) { 
     974        pjsua_perror(THIS_FILE, "Unable to create xfer", status); 
     975        PJSUA_UNLOCK(); 
     976        return status; 
     977    } 
     978 
     979    /* 
     980     * Create REFER request. 
     981     */ 
     982    status = pjsip_xfer_initiate(sub, dest, &tdata); 
     983    if (status != PJ_SUCCESS) { 
     984        pjsua_perror(THIS_FILE, "Unable to create REFER request", status); 
     985        PJSUA_UNLOCK(); 
     986        return status; 
     987    } 
     988 
     989    /* Add additional headers etc */ 
     990    pjsua_process_msg_data( tdata, msg_data); 
     991 
     992    /* Send. */ 
     993    status = pjsip_xfer_send_request(sub, tdata); 
     994    if (status != PJ_SUCCESS) { 
     995        pjsua_perror(THIS_FILE, "Unable to send REFER request", status); 
     996        PJSUA_UNLOCK(); 
     997        return status; 
     998    } 
     999 
     1000    /* For simplicity (that's what this program is intended to be!),  
     1001     * leave the original invite session as it is. More advanced application 
     1002     * may want to hold the INVITE, or terminate the invite, or whatever. 
     1003     */ 
     1004 
     1005    PJSUA_UNLOCK(); 
     1006 
     1007    return PJ_SUCCESS; 
     1008 
     1009} 
     1010 
     1011 
     1012/* 
     1013 * Send DTMF digits to remote using RFC 2833 payload formats. 
     1014 */ 
     1015PJ_DEF(pj_status_t) pjsua_call_dial_dtmf( pjsua_call_id call_id,  
     1016                                          const pj_str_t *digits) 
     1017{ 
     1018    pjsua_call *call; 
     1019    pj_status_t status; 
     1020 
     1021    PJ_ASSERT_RETURN(call_id>=0 && call_id<(int)pjsua_var.ua_cfg.max_calls, 
     1022                     PJ_EINVAL); 
     1023     
     1024    PJSUA_LOCK(); 
     1025 
     1026    call = &pjsua_var.calls[call_id]; 
     1027 
     1028    if (!call->session) { 
     1029        PJ_LOG(3,(THIS_FILE, "Media is not established yet!")); 
     1030        PJSUA_UNLOCK(); 
     1031        return PJ_EINVALIDOP; 
     1032    } 
     1033 
     1034    status = pjmedia_session_dial_dtmf( call->session, 0, digits); 
     1035 
     1036    PJSUA_UNLOCK(); 
     1037 
     1038    return status; 
     1039} 
     1040 
     1041 
     1042/** 
     1043 * Send instant messaging inside INVITE session. 
     1044 */ 
     1045PJ_DEF(pj_status_t) pjsua_call_send_im( pjsua_call_id call_id,  
     1046                                        const pj_str_t *mime_type, 
     1047                                        const pj_str_t *content, 
     1048                                        const pjsua_msg_data *msg_data, 
     1049                                        void *user_data) 
     1050{ 
     1051    pjsua_call *call; 
     1052    const pj_str_t mime_text_plain = pj_str("text/plain"); 
     1053    pjsip_media_type ctype; 
     1054    pjsua_im_data *im_data; 
     1055    pjsip_tx_data *tdata; 
     1056    pj_status_t status; 
     1057 
     1058 
     1059    PJ_ASSERT_RETURN(call_id>=0 && call_id<(int)pjsua_var.ua_cfg.max_calls, 
     1060                     PJ_EINVAL); 
     1061 
     1062    PJSUA_LOCK(); 
     1063 
     1064    call = &pjsua_var.calls[call_id]; 
     1065 
     1066    if (!call->inv) { 
     1067        PJ_LOG(3,(THIS_FILE,"Call has been disconnected")); 
     1068        PJSUA_UNLOCK(); 
     1069        return PJSIP_ESESSIONTERMINATED; 
     1070    } 
     1071 
     1072    /* Lock dialog. */ 
     1073    pjsip_dlg_inc_lock(call->inv->dlg); 
     1074 
     1075    /* Set default media type if none is specified */ 
     1076    if (mime_type == NULL) { 
     1077        mime_type = &mime_text_plain; 
     1078    } 
     1079 
     1080    /* Create request message. */ 
     1081    status = pjsip_dlg_create_request( call->inv->dlg, &pjsip_message_method, 
     1082                                       -1, &tdata); 
     1083    if (status != PJ_SUCCESS) { 
     1084        pjsua_perror(THIS_FILE, "Unable to create MESSAGE request", status); 
     1085        goto on_return; 
     1086    } 
     1087 
     1088    /* Add accept header. */ 
     1089    pjsip_msg_add_hdr( tdata->msg,  
     1090                       (pjsip_hdr*)pjsua_im_create_accept(tdata->pool)); 
     1091 
     1092    /* Parse MIME type */ 
     1093    pjsua_parse_media_type(tdata->pool, mime_type, &ctype); 
     1094 
     1095    /* Create "text/plain" message body. */ 
     1096    tdata->msg->body = pjsip_msg_body_create( tdata->pool, &ctype.type, 
     1097                                              &ctype.subtype, content); 
     1098    if (tdata->msg->body == NULL) { 
     1099        pjsua_perror(THIS_FILE, "Unable to create msg body", PJ_ENOMEM); 
     1100        pjsip_tx_data_dec_ref(tdata); 
     1101        goto on_return; 
     1102    } 
     1103 
     1104    /* Add additional headers etc */ 
     1105    pjsua_process_msg_data( tdata, msg_data); 
     1106 
     1107    /* Create IM data and attach to the request. */ 
     1108    im_data = pj_pool_zalloc(tdata->pool, sizeof(*im_data)); 
     1109    im_data->acc_id = call->acc_id; 
     1110    im_data->call_id = call_id; 
     1111    im_data->to = call->inv->dlg->remote.info_str; 
     1112    pj_strdup_with_null(tdata->pool, &im_data->body, content); 
     1113    im_data->user_data = user_data; 
     1114 
     1115 
     1116    /* Send the request. */ 
     1117    status = pjsip_dlg_send_request( call->inv->dlg, tdata,  
     1118                                     pjsua_var.mod.id, im_data); 
     1119    if (status != PJ_SUCCESS) { 
     1120        pjsua_perror(THIS_FILE, "Unable to send MESSAGE request", status); 
     1121        goto on_return; 
     1122    } 
     1123 
     1124on_return: 
     1125    pjsip_dlg_dec_lock(call->inv->dlg); 
     1126    PJSUA_UNLOCK(); 
     1127    return status; 
     1128} 
     1129 
     1130 
     1131/* 
     1132 * Send IM typing indication inside INVITE session. 
     1133 */ 
     1134PJ_DEF(pj_status_t) pjsua_call_send_typing_ind( pjsua_call_id call_id,  
     1135                                                pj_bool_t is_typing, 
     1136                                                const pjsua_msg_data*msg_data) 
     1137{ 
     1138    pjsua_call *call; 
     1139    pjsip_tx_data *tdata; 
     1140    pj_status_t status; 
     1141 
     1142 
     1143    PJ_ASSERT_RETURN(call_id>=0 && call_id<(int)pjsua_var.ua_cfg.max_calls, 
     1144                     PJ_EINVAL); 
     1145 
     1146    PJSUA_LOCK(); 
     1147 
     1148    call = &pjsua_var.calls[call_id]; 
     1149 
     1150    if (!call->inv) { 
     1151        PJ_LOG(3,(THIS_FILE,"Call has been disconnected")); 
     1152        PJSUA_UNLOCK(); 
     1153        return PJSIP_ESESSIONTERMINATED; 
     1154    } 
     1155 
     1156    /* Lock dialog. */ 
     1157    pjsip_dlg_inc_lock(call->inv->dlg); 
     1158     
     1159    /* Create request message. */ 
     1160    status = pjsip_dlg_create_request( call->inv->dlg, &pjsip_message_method, 
     1161                                       -1, &tdata); 
     1162    if (status != PJ_SUCCESS) { 
     1163        pjsua_perror(THIS_FILE, "Unable to create MESSAGE request", status); 
     1164        goto on_return; 
     1165    } 
     1166 
     1167    /* Create "application/im-iscomposing+xml" msg body. */ 
     1168    tdata->msg->body = pjsip_iscomposing_create_body(tdata->pool, is_typing, 
     1169                                                     NULL, NULL, -1); 
     1170 
     1171    /* Add additional headers etc */ 
     1172    pjsua_process_msg_data( tdata, msg_data); 
     1173 
     1174    /* Send the request. */ 
     1175    status = pjsip_dlg_send_request( call->inv->dlg, tdata, -1, NULL); 
     1176    if (status != PJ_SUCCESS) { 
     1177        pjsua_perror(THIS_FILE, "Unable to send MESSAGE request", status); 
     1178        goto on_return; 
     1179    } 
     1180 
     1181on_return: 
     1182    pjsip_dlg_dec_lock(call->inv->dlg); 
     1183    PJSUA_UNLOCK(); 
     1184    return status; 
     1185} 
     1186 
     1187 
     1188/* 
     1189 * Terminate all calls. 
     1190 */ 
     1191PJ_DEF(void) pjsua_call_hangup_all(void) 
     1192{ 
     1193    unsigned i; 
     1194 
     1195    PJSUA_LOCK(); 
     1196 
     1197    for (i=0; i<pjsua_var.ua_cfg.max_calls; ++i) { 
     1198        if (pjsua_var.calls[i].inv) 
     1199            pjsua_call_hangup(i, 0, NULL, NULL); 
     1200    } 
     1201 
     1202    PJSUA_UNLOCK(); 
     1203} 
     1204 
     1205 
     1206static const char *good_number(char *buf, pj_int32_t val) 
     1207{ 
     1208    if (val < 1000) { 
     1209        pj_ansi_sprintf(buf, "%d", val); 
     1210    } else if (val < 1000000) { 
     1211        pj_ansi_sprintf(buf, "%d.%dK",  
     1212                        val / 1000, 
     1213                        (val % 1000) / 100); 
     1214    } else { 
     1215        pj_ansi_sprintf(buf, "%d.%02dM",  
     1216                        val / 1000000, 
     1217                        (val % 1000000) / 10000); 
     1218    } 
     1219 
     1220    return buf; 
     1221} 
     1222 
     1223 
     1224/* Dump media session */ 
     1225static void dump_media_session(const char *indent,  
     1226                               char *buf, unsigned maxlen, 
     1227                               pjmedia_session *session) 
     1228{ 
     1229    unsigned i; 
     1230    char *p = buf, *end = buf+maxlen; 
     1231    int len; 
     1232    pjmedia_session_info info; 
     1233 
     1234    pjmedia_session_get_info(session, &info); 
     1235 
     1236    for (i=0; i<info.stream_cnt; ++i) { 
     1237        pjmedia_rtcp_stat stat; 
     1238        const char *rem_addr; 
     1239        int rem_port; 
     1240        const char *dir; 
     1241        char last_update[40]; 
     1242        char packets[16], bytes[16], ipbytes[16]; 
     1243        pj_time_val now; 
     1244 
     1245        pjmedia_session_get_stream_stat(session, i, &stat); 
     1246        rem_addr = pj_inet_ntoa(info.stream_info[i].rem_addr.sin_addr); 
     1247        rem_port = pj_ntohs(info.stream_info[i].rem_addr.sin_port); 
     1248 
     1249        if (info.stream_info[i].dir == PJMEDIA_DIR_ENCODING) 
     1250            dir = "sendonly"; 
     1251        else if (info.stream_info[i].dir == PJMEDIA_DIR_DECODING) 
     1252            dir = "recvonly"; 
     1253        else if (info.stream_info[i].dir == PJMEDIA_DIR_ENCODING_DECODING) 
     1254            dir = "sendrecv"; 
     1255        else 
     1256            dir = "inactive"; 
     1257 
     1258         
     1259        len = pj_ansi_snprintf(buf, end-p,  
     1260                  "%s  #%d %.*s @%dKHz, %s, peer=%s:%d", 
     1261                  indent, i, 
     1262                  info.stream_info[i].fmt.encoding_name.slen, 
     1263                  info.stream_info[i].fmt.encoding_name.ptr, 
     1264                  info.stream_info[i].fmt.clock_rate / 1000, 
     1265                  dir, 
     1266                  rem_addr, rem_port); 
     1267        if (len < 1 || len > end-p) { 
     1268            *p = '\0'; 
     1269            return; 
     1270        } 
     1271 
     1272        p += len; 
     1273        *p++ = '\n'; 
     1274        *p = '\0'; 
     1275 
     1276        if (stat.rx.update_cnt == 0) 
     1277            strcpy(last_update, "never"); 
     1278        else { 
     1279            pj_gettimeofday(&now); 
     1280            PJ_TIME_VAL_SUB(now, stat.rx.update); 
     1281            sprintf(last_update, "%02ldh:%02ldm:%02ld.%03lds ago", 
     1282                    now.sec / 3600, 
     1283                    (now.sec % 3600) / 60, 
     1284                    now.sec % 60, 
     1285                    now.msec); 
     1286        } 
     1287 
     1288        len = pj_ansi_snprintf(p, end-p, 
     1289               "%s     RX pt=%d, stat last update: %s\n" 
     1290               "%s        total %spkt %sB (%sB +IP hdr)\n" 
     1291               "%s        pkt loss=%d (%3.1f%%), dup=%d (%3.1f%%), reorder=%d (%3.1f%%)\n" 
     1292               "%s              (msec)    min     avg     max     last\n" 
     1293               "%s        loss period: %7.3f %7.3f %7.3f %7.3f\n" 
     1294               "%s        jitter     : %7.3f %7.3f %7.3f %7.3f%s", 
     1295               indent, info.stream_info[i].fmt.pt, 
     1296               last_update, 
     1297               indent, 
     1298               good_number(packets, stat.rx.pkt), 
     1299               good_number(bytes, stat.rx.bytes), 
     1300               good_number(ipbytes, stat.rx.bytes + stat.rx.pkt * 32), 
     1301               indent, 
     1302               stat.rx.loss, 
     1303               stat.rx.loss * 100.0 / stat.rx.pkt, 
     1304               stat.rx.dup,  
     1305               stat.rx.dup * 100.0 / stat.rx.pkt, 
     1306               stat.rx.reorder,  
     1307               stat.rx.reorder * 100.0 / stat.rx.pkt, 
     1308               indent, indent, 
     1309               stat.rx.loss_period.min / 1000.0,  
     1310               stat.rx.loss_period.avg / 1000.0,  
     1311               stat.rx.loss_period.max / 1000.0, 
     1312               stat.rx.loss_period.last / 1000.0, 
     1313               indent, 
     1314               stat.rx.jitter.min / 1000.0, 
     1315               stat.rx.jitter.avg / 1000.0, 
     1316               stat.rx.jitter.max / 1000.0, 
     1317               stat.rx.jitter.last / 1000.0, 
     1318               "" 
     1319               ); 
     1320 
     1321        if (len < 1 || len > end-p) { 
     1322            *p = '\0'; 
     1323            return; 
     1324        } 
     1325 
     1326        p += len; 
     1327        *p++ = '\n'; 
     1328        *p = '\0'; 
     1329         
     1330        if (stat.tx.update_cnt == 0) 
     1331            strcpy(last_update, "never"); 
     1332        else { 
     1333            pj_gettimeofday(&now); 
     1334            PJ_TIME_VAL_SUB(now, stat.tx.update); 
     1335            sprintf(last_update, "%02ldh:%02ldm:%02ld.%03lds ago", 
     1336                    now.sec / 3600, 
     1337                    (now.sec % 3600) / 60, 
     1338                    now.sec % 60, 
     1339                    now.msec); 
     1340        } 
     1341 
     1342        len = pj_ansi_snprintf(p, end-p, 
     1343               "%s     TX pt=%d, ptime=%dms, stat last update: %s\n" 
     1344               "%s        total %spkt %sB (%sB +IP hdr)\n" 
     1345               "%s        pkt loss=%d (%3.1f%%), dup=%d (%3.1f%%), reorder=%d (%3.1f%%)\n" 
     1346               "%s              (msec)    min     avg     max     last\n" 
     1347               "%s        loss period: %7.3f %7.3f %7.3f %7.3f\n" 
     1348               "%s        jitter     : %7.3f %7.3f %7.3f %7.3f%s", 
     1349               indent, 
     1350               info.stream_info[i].tx_pt, 
     1351               info.stream_info[i].param->info.frm_ptime * 
     1352                info.stream_info[i].param->setting.frm_per_pkt, 
     1353               last_update, 
     1354 
     1355               indent, 
     1356               good_number(packets, stat.tx.pkt), 
     1357               good_number(bytes, stat.tx.bytes), 
     1358               good_number(ipbytes, stat.tx.bytes + stat.tx.pkt * 32), 
     1359 
     1360               indent, 
     1361               stat.tx.loss, 
     1362               stat.tx.loss * 100.0 / stat.tx.pkt, 
     1363               stat.tx.dup,  
     1364               stat.tx.dup * 100.0 / stat.tx.pkt, 
     1365               stat.tx.reorder,  
     1366               stat.tx.reorder * 100.0 / stat.tx.pkt, 
     1367 
     1368               indent, indent, 
     1369               stat.tx.loss_period.min / 1000.0,  
     1370               stat.tx.loss_period.avg / 1000.0,  
     1371               stat.tx.loss_period.max / 1000.0, 
     1372               stat.tx.loss_period.last / 1000.0, 
     1373               indent, 
     1374               stat.tx.jitter.min / 1000.0, 
     1375               stat.tx.jitter.avg / 1000.0, 
     1376               stat.tx.jitter.max / 1000.0, 
     1377               stat.tx.jitter.last / 1000.0, 
     1378               "" 
     1379               ); 
     1380 
     1381        if (len < 1 || len > end-p) { 
     1382            *p = '\0'; 
     1383            return; 
     1384        } 
     1385 
     1386        p += len; 
     1387        *p++ = '\n'; 
     1388        *p = '\0'; 
     1389 
     1390        len = pj_ansi_snprintf(p, end-p, 
     1391               "%s    RTT msec       : %7.3f %7.3f %7.3f %7.3f",  
     1392               indent, 
     1393               stat.rtt.min / 1000.0, 
     1394               stat.rtt.avg / 1000.0, 
     1395               stat.rtt.max / 1000.0, 
     1396               stat.rtt.last / 1000.0 
     1397               ); 
     1398        if (len < 1 || len > end-p) { 
     1399            *p = '\0'; 
     1400            return; 
     1401        } 
     1402 
     1403        p += len; 
     1404        *p++ = '\n'; 
     1405        *p = '\0'; 
     1406    } 
     1407} 
     1408 
     1409 
     1410/* Print call info */ 
     1411static void print_call(const char *title, 
     1412                       int call_id,  
     1413                       char *buf, pj_size_t size) 
     1414{ 
     1415    int len; 
     1416    pjsip_inv_session *inv = pjsua_var.calls[call_id].inv; 
     1417    pjsip_dialog *dlg = inv->dlg; 
     1418    char userinfo[128]; 
     1419 
     1420    /* Dump invite sesion info. */ 
     1421 
     1422    len = pjsip_hdr_print_on(dlg->remote.info, userinfo, sizeof(userinfo)); 
     1423    if (len < 1) 
     1424        pj_ansi_strcpy(userinfo, "<--uri too long-->"); 
     1425    else 
     1426        userinfo[len] = '\0'; 
     1427     
     1428    len = pj_ansi_snprintf(buf, size, "%s[%s] %s", 
     1429                           title, 
     1430                           pjsip_inv_state_name(inv->state), 
     1431                           userinfo); 
     1432    if (len < 1 || len >= (int)size) { 
     1433        pj_ansi_strcpy(buf, "<--uri too long-->"); 
     1434        len = 18; 
     1435    } else 
     1436        buf[len] = '\0'; 
     1437} 
     1438 
     1439 
     1440/* 
     1441 * Dump call and media statistics to string. 
     1442 */ 
     1443PJ_DEF(pj_status_t) pjsua_call_dump( pjsua_call_id call_id,  
     1444                                     pj_bool_t with_media,  
     1445                                     char *buffer,  
     1446                                     unsigned maxlen, 
     1447                                     const char *indent) 
     1448{ 
     1449    pjsua_call *call; 
     1450    pj_time_val duration, res_delay, con_delay; 
     1451    char tmp[128]; 
     1452    char *p, *end; 
     1453    int len; 
     1454 
     1455    PJ_ASSERT_RETURN(call_id>=0 && call_id<(int)pjsua_var.ua_cfg.max_calls, 
     1456                     PJ_EINVAL); 
     1457 
     1458    PJSUA_LOCK(); 
     1459 
     1460    call = &pjsua_var.calls[call_id]; 
     1461 
     1462    *buffer = '\0'; 
     1463    p = buffer; 
     1464    end = buffer + maxlen; 
     1465    len = 0; 
     1466 
     1467    if (call->inv == NULL) { 
     1468        PJSUA_UNLOCK(); 
     1469        return PJ_EINVALIDOP; 
     1470    } 
     1471 
     1472    print_call(indent, call_id, tmp, sizeof(tmp)); 
     1473     
     1474    len = pj_ansi_strlen(tmp); 
     1475    pj_ansi_strcpy(buffer, tmp); 
     1476 
     1477    p += len; 
     1478    *p++ = '\r'; 
     1479    *p++ = '\n'; 
     1480 
     1481    /* Calculate call duration */ 
     1482    if (call->inv->state >= PJSIP_INV_STATE_CONFIRMED) { 
     1483        pj_gettimeofday(&duration); 
     1484        PJ_TIME_VAL_SUB(duration, call->conn_time); 
     1485        con_delay = call->conn_time; 
     1486        PJ_TIME_VAL_SUB(con_delay, call->start_time); 
     1487    } else { 
     1488        duration.sec = duration.msec = 0; 
     1489        con_delay.sec = con_delay.msec = 0; 
     1490    } 
     1491 
     1492    /* Calculate first response delay */ 
     1493    if (call->inv->state >= PJSIP_INV_STATE_EARLY) { 
     1494        res_delay = call->res_time; 
     1495        PJ_TIME_VAL_SUB(res_delay, call->start_time); 
     1496    } else { 
     1497        res_delay.sec = res_delay.msec = 0; 
     1498    } 
     1499 
     1500    /* Print duration */ 
     1501    len = pj_ansi_snprintf(p, end-p,  
     1502                           "%s  Call time: %02dh:%02dm:%02ds, " 
     1503                           "1st res in %d ms, conn in %dms", 
     1504                           indent, 
     1505                           (duration.sec / 3600), 
     1506                           ((duration.sec % 3600)/60), 
     1507                           (duration.sec % 60), 
     1508                           PJ_TIME_VAL_MSEC(res_delay),  
     1509                           PJ_TIME_VAL_MSEC(con_delay)); 
     1510     
     1511    if (len > 0 && len < end-p) { 
     1512        p += len; 
     1513        *p++ = '\n'; 
     1514        *p = '\0'; 
     1515    } 
     1516 
     1517    /* Dump session statistics */ 
     1518    if (with_media && call->session) 
     1519        dump_media_session(indent, p, end-p, call->session); 
     1520 
     1521    PJSUA_UNLOCK(); 
     1522 
     1523    return PJ_SUCCESS; 
     1524} 
     1525 
     1526 
     1527/* 
     1528 * Destroy the call's media 
     1529 */ 
     1530static pj_status_t call_destroy_media(int call_id) 
     1531{ 
     1532    pjsua_call *call = &pjsua_var.calls[call_id]; 
     1533 
     1534    if (call->conf_slot != PJSUA_INVALID_ID) { 
     1535        pjmedia_conf_remove_port(pjsua_var.mconf, call->conf_slot); 
     1536        call->conf_slot = PJSUA_INVALID_ID; 
     1537    } 
     1538 
     1539    if (call->session) { 
     1540        /* Destroy session (this will also close RTP/RTCP sockets). */ 
     1541        pjmedia_session_destroy(call->session); 
     1542        call->session = NULL; 
     1543 
     1544        PJ_LOG(4,(THIS_FILE, "Media session for call %d is destroyed",  
     1545                             call_id)); 
     1546 
     1547    } 
     1548 
     1549    call->media_st = PJSUA_CALL_MEDIA_NONE; 
     1550 
     1551    return PJ_SUCCESS; 
     1552} 
     1553 
     1554 
    6261555/* 
    6271556 * This callback receives notification from invite session when the 
     
    6311560                                        pjsip_event *e) 
    6321561{ 
    633     pjsua_call *call = inv->dlg->mod_data[pjsua.mod.id]; 
    634  
    635     if (!call) 
     1562    pjsua_call *call; 
     1563 
     1564    PJSUA_LOCK(); 
     1565 
     1566    call = inv->dlg->mod_data[pjsua_var.mod.id]; 
     1567 
     1568    if (!call) { 
     1569        PJSUA_UNLOCK(); 
    6361570        return; 
     1571    } 
     1572 
    6371573 
    6381574    /* Get call times */ 
     
    6431579                pj_gettimeofday(&call->res_time); 
    6441580            call->last_code = e->body.tsx_state.tsx->status_code; 
     1581            pj_strncpy(&call->last_text,  
     1582                       &e->body.tsx_state.tsx->status_text, 
     1583                       sizeof(call->last_text_buf_)); 
    6451584            break; 
    6461585        case PJSIP_INV_STATE_CONFIRMED: 
     
    6511590            if (e->body.tsx_state.tsx->status_code > call->last_code) { 
    6521591                call->last_code = e->body.tsx_state.tsx->status_code; 
     1592                pj_strncpy(&call->last_text,  
     1593                           &e->body.tsx_state.tsx->status_text, 
     1594                           sizeof(call->last_text_buf_)); 
    6531595            } 
    6541596            break; 
    6551597        default: 
    6561598            call->last_code = e->body.tsx_state.tsx->status_code; 
     1599            pj_strncpy(&call->last_text,  
     1600                       &e->body.tsx_state.tsx->status_text, 
     1601                       sizeof(call->last_text_buf_)); 
    6571602            break; 
    6581603    } 
     
    7171662 
    7181663 
    719     if (pjsua.cb.on_call_state) 
    720         (*pjsua.cb.on_call_state)(call->index, e); 
     1664    if (pjsua_var.ua_cfg.cb.on_call_state) 
     1665        (*pjsua_var.ua_cfg.cb.on_call_state)(call->index, e); 
    7211666 
    7221667    /* call->inv may be NULL now */ 
     
    7301675            call_destroy_media(call->index); 
    7311676 
    732         /* Remove timers. */ 
    733         schedule_call_timer(call, &call->refresh_tm, REFRESH_CALL_TIMER, 0); 
    734         schedule_call_timer(call, &call->hangup_tm, HANGUP_CALL_TIMER, 0); 
    735  
    7361677        /* Free call */ 
    7371678        call->inv = NULL; 
    738         --pjsua.call_cnt; 
    739     } 
    740 } 
    741  
    742  
    743 /* 
    744  * Callback called by event framework when the xfer subscription state 
    745  * has changed. 
    746  */ 
    747 static void xfer_on_evsub_state( pjsip_evsub *sub, pjsip_event *event) 
    748 { 
    749      
    750     PJ_UNUSED_ARG(event); 
    751  
    752     /* 
    753      * We're only interested when subscription is terminated, to  
    754      * clear the xfer_sub member of the inv_data. 
    755      */ 
    756     if (pjsip_evsub_get_state(sub) == PJSIP_EVSUB_STATE_TERMINATED) { 
    757         pjsua_call *call; 
    758  
    759         call = pjsip_evsub_get_mod_data(sub, pjsua.mod.id); 
    760         if (!call) 
    761             return; 
    762  
    763         pjsip_evsub_set_mod_data(sub, pjsua.mod.id, NULL); 
    764         call->xfer_sub = NULL; 
    765  
    766         PJ_LOG(3,(THIS_FILE, "Xfer subscription terminated")); 
    767     } 
    768 } 
    769  
    770  
    771 /* 
    772  * Follow transfer (REFER) request. 
    773  */ 
    774 static void on_call_transfered( pjsip_inv_session *inv, 
    775                                 pjsip_rx_data *rdata ) 
    776 { 
    777     pj_status_t status; 
    778     pjsip_tx_data *tdata; 
    779     pjsua_call *existing_call; 
    780     int new_call; 
    781     const pj_str_t str_refer_to = { "Refer-To", 8}; 
    782     pjsip_generic_string_hdr *refer_to; 
    783     char *uri; 
    784     pj_str_t tmp; 
    785     struct pjsip_evsub_user xfer_cb; 
    786     pjsip_status_code code; 
    787     pjsip_evsub *sub; 
    788  
    789     existing_call = inv->dlg->mod_data[pjsua.mod.id]; 
    790  
    791     /* Find the Refer-To header */ 
    792     refer_to = (pjsip_generic_string_hdr*) 
    793         pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &str_refer_to, NULL); 
    794  
    795     if (refer_to == NULL) { 
    796         /* Invalid Request. 
    797          * No Refer-To header! 
    798          */ 
    799         PJ_LOG(4,(THIS_FILE, "Received REFER without Refer-To header!")); 
    800         pjsip_dlg_respond( inv->dlg, rdata, 400, NULL, NULL, NULL); 
    801         return; 
    802     } 
    803  
    804     /* Notify callback */ 
    805     code = PJSIP_SC_OK; 
    806     if (pjsua.cb.on_call_transfered) 
    807         (*pjsua.cb.on_call_transfered)(existing_call->index, 
    808                                        &refer_to->hvalue, &code); 
    809  
    810     if (code < 200) 
    811         code = 200; 
    812     if (code >= 300) { 
    813         /* Application rejects call transfer request */ 
    814         pjsip_dlg_respond( inv->dlg, rdata, code, NULL, NULL, NULL); 
    815         return; 
    816     } 
    817  
    818     PJ_LOG(3,(THIS_FILE, "Call to %.*s is being transfered to %.*s", 
    819               (int)inv->dlg->remote.info_str.slen, 
    820               inv->dlg->remote.info_str.ptr, 
    821               (int)refer_to->hvalue.slen,  
    822               refer_to->hvalue.ptr)); 
    823  
    824     /* Init callback */ 
    825     pj_memset(&xfer_cb, 0, sizeof(xfer_cb)); 
    826     xfer_cb.on_evsub_state = &xfer_on_evsub_state; 
    827  
    828     /* Create transferee event subscription */ 
    829     status = pjsip_xfer_create_uas( inv->dlg, &xfer_cb, rdata, &sub); 
    830     if (status != PJ_SUCCESS) { 
    831         pjsua_perror(THIS_FILE, "Unable to create xfer uas", status); 
    832         pjsip_dlg_respond( inv->dlg, rdata, 500, NULL, NULL, NULL); 
    833         return; 
    834     } 
    835  
    836     /* Accept the REFER request, send 200 (OK). */ 
    837     pjsip_xfer_accept(sub, rdata, code, NULL); 
    838  
    839     /* Create initial NOTIFY request */ 
    840     status = pjsip_xfer_notify( sub, PJSIP_EVSUB_STATE_ACTIVE, 
    841                                 100, NULL, &tdata); 
    842     if (status != PJ_SUCCESS) { 
    843         pjsua_perror(THIS_FILE, "Unable to create NOTIFY to REFER", status); 
    844         return; 
    845     } 
    846  
    847     /* Send initial NOTIFY request */ 
    848     status = pjsip_xfer_send_request( sub, tdata); 
    849     if (status != PJ_SUCCESS) { 
    850         pjsua_perror(THIS_FILE, "Unable to send NOTIFY to REFER", status); 
    851         return; 
    852     } 
    853  
    854     /* We're cheating here. 
    855      * We need to get a null terminated string from a pj_str_t. 
    856      * So grab the pointer from the hvalue and NULL terminate it, knowing 
    857      * that the NULL position will be occupied by a newline.  
    858      */ 
    859     uri = refer_to->hvalue.ptr; 
    860     uri[refer_to->hvalue.slen] = '\0'; 
    861  
    862     /* Now make the outgoing call. */ 
    863     tmp = pj_str(uri); 
    864     status = pjsua_call_make_call(existing_call->acc_index, &tmp, &new_call); 
    865     if (status != PJ_SUCCESS) { 
    866  
    867         /* Notify xferer about the error */ 
    868         status = pjsip_xfer_notify(sub, PJSIP_EVSUB_STATE_TERMINATED, 
    869                                    500, NULL, &tdata); 
    870         if (status != PJ_SUCCESS) { 
    871             pjsua_perror(THIS_FILE, "Unable to create NOTIFY to REFER",  
    872                           status); 
    873             return; 
    874         } 
    875         status = pjsip_xfer_send_request(sub, tdata); 
    876         if (status != PJ_SUCCESS) { 
    877             pjsua_perror(THIS_FILE, "Unable to send NOTIFY to REFER",  
    878                           status); 
    879             return; 
    880         } 
    881         return; 
    882     } 
    883  
    884     /* Put the server subscription in inv_data. 
    885      * Subsequent state changed in pjsua_inv_on_state_changed() will be 
    886      * reported back to the server subscription. 
    887      */ 
    888     pjsua.calls[new_call].xfer_sub = sub; 
    889  
    890     /* Put the invite_data in the subscription. */ 
    891     pjsip_evsub_set_mod_data(sub, pjsua.mod.id, &pjsua.calls[new_call]); 
    892 } 
    893  
    894  
    895 /* 
    896  * This callback is called when transaction state has changed in INVITE 
    897  * session. We use this to trap: 
    898  *  - incoming REFER request. 
    899  *  - incoming MESSAGE request. 
    900  */ 
    901 static void pjsua_call_on_tsx_state_changed(pjsip_inv_session *inv, 
    902                                             pjsip_transaction *tsx, 
    903                                             pjsip_event *e) 
    904 { 
    905     pjsua_call *call = inv->dlg->mod_data[pjsua.mod.id]; 
    906  
    907     if (tsx->role==PJSIP_ROLE_UAS && 
    908         tsx->state==PJSIP_TSX_STATE_TRYING && 
    909         pjsip_method_cmp(&tsx->method, &pjsip_refer_method)==0) 
    910     { 
    911         /* 
    912          * Incoming REFER request. 
    913          */ 
    914         on_call_transfered(call->inv, e->body.tsx_state.src.rdata); 
    915  
    916     } 
    917     else if (tsx->role==PJSIP_ROLE_UAS && 
    918              tsx->state==PJSIP_TSX_STATE_TRYING && 
    919              pjsip_method_cmp(&tsx->method, &pjsip_message_method)==0) 
    920     { 
    921         /* 
    922          * Incoming MESSAGE request! 
    923          */ 
    924         pjsip_rx_data *rdata; 
    925         pjsip_msg *msg; 
    926         pjsip_accept_hdr *accept_hdr; 
    927         pj_status_t status; 
    928  
    929         rdata = e->body.tsx_state.src.rdata; 
    930         msg = rdata->msg_info.msg; 
    931  
    932         /* Request MUST have message body, with Content-Type equal to 
    933          * "text/plain". 
    934          */ 
    935         if (pjsua_im_accept_pager(rdata, &accept_hdr) == PJ_FALSE) { 
    936  
    937             pjsip_hdr hdr_list; 
    938  
    939             pj_list_init(&hdr_list); 
    940             pj_list_push_back(&hdr_list, accept_hdr); 
    941  
    942             pjsip_dlg_respond( inv->dlg, rdata, PJSIP_SC_NOT_ACCEPTABLE_HERE,  
    943                                NULL, &hdr_list, NULL ); 
    944             return; 
    945         } 
    946  
    947         /* Respond with 200 first, so that remote doesn't retransmit in case 
    948          * the UI takes too long to process the message.  
    949          */ 
    950         status = pjsip_dlg_respond( inv->dlg, rdata, 200, NULL, NULL, NULL); 
    951  
    952         /* Process MESSAGE request */ 
    953         pjsua_im_process_pager(call->index, &inv->dlg->remote.info_str, 
    954                                &inv->dlg->local.info_str, rdata); 
    955     } 
    956  
    957 } 
    958  
     1679        --pjsua_var.call_cnt; 
     1680    } 
     1681 
     1682    PJSUA_UNLOCK(); 
     1683} 
    9591684 
    9601685/* 
     
    9711696} 
    9721697 
    973  
    974 /* 
    975  * Create inactive SDP for call hold. 
    976  */ 
    977 static pj_status_t create_inactive_sdp(pjsua_call *call, 
    978                                        pjmedia_sdp_session **p_answer) 
    979 { 
    980     pj_status_t status; 
    981     pjmedia_sdp_conn *conn; 
    982     pjmedia_sdp_attr *attr; 
    983     pjmedia_sdp_session *sdp; 
    984  
    985     /* Create new offer */ 
    986     status = pjmedia_endpt_create_sdp(pjsua.med_endpt, pjsua.pool, 1, 
    987                                       &call->skinfo, &sdp); 
    988     if (status != PJ_SUCCESS) { 
    989         pjsua_perror(THIS_FILE, "Unable to create local SDP", status); 
    990         return status; 
    991     } 
    992  
    993     /* Get SDP media connection line */ 
    994     conn = sdp->media[0]->conn; 
    995     if (!conn) 
    996         conn = sdp->conn; 
    997  
    998     /* Modify address */ 
    999     conn->addr = pj_str("0.0.0.0"); 
    1000  
    1001     /* Remove existing directions attributes */ 
    1002     pjmedia_sdp_media_remove_all_attr(sdp->media[0], "sendrecv"); 
    1003     pjmedia_sdp_media_remove_all_attr(sdp->media[0], "sendonly"); 
    1004     pjmedia_sdp_media_remove_all_attr(sdp->media[0], "recvonly"); 
    1005     pjmedia_sdp_media_remove_all_attr(sdp->media[0], "inactive"); 
    1006  
    1007     /* Add inactive attribute */ 
    1008     attr = pjmedia_sdp_attr_create(pjsua.pool, "inactive", NULL); 
    1009     pjmedia_sdp_media_add_attr(sdp->media[0], attr); 
    1010  
    1011     *p_answer = sdp; 
    1012  
    1013     return status; 
    1014 } 
    1015  
    1016 /* 
    1017  * Called when session received new offer. 
    1018  */ 
    1019 static void pjsua_call_on_rx_offer(pjsip_inv_session *inv, 
    1020                                    const pjmedia_sdp_session *offer) 
    1021 { 
    1022     pjsua_call *call; 
    1023     pjmedia_sdp_conn *conn; 
    1024     pjmedia_sdp_session *answer; 
    1025     pj_bool_t is_remote_active; 
    1026     pj_status_t status; 
    1027  
    1028     call = inv->dlg->mod_data[pjsua.mod.id]; 
    1029  
    1030     /* 
    1031      * See if remote is offering active media (i.e. not on-hold) 
    1032      */ 
    1033     is_remote_active = PJ_TRUE; 
    1034  
    1035     conn = offer->media[0]->conn; 
    1036     if (!conn) 
    1037         conn = offer->conn; 
    1038  
    1039     if (pj_strcmp2(&conn->addr, "0.0.0.0")==0 || 
    1040         pj_strcmp2(&conn->addr, "0")==0) 
    1041     { 
    1042         is_remote_active = PJ_FALSE; 
    1043  
    1044     }  
    1045     else if (pjmedia_sdp_media_find_attr2(offer->media[0], "inactive", NULL)) 
    1046     { 
    1047         is_remote_active = PJ_FALSE; 
    1048     } 
    1049  
    1050     PJ_LOG(4,(THIS_FILE, "Received SDP offer, remote media is %s", 
    1051               (is_remote_active ? "active" : "inactive"))); 
    1052  
    1053     /* Supply candidate answer */ 
    1054     if (is_remote_active) { 
    1055         status = pjmedia_endpt_create_sdp( pjsua.med_endpt, call->inv->pool, 1, 
    1056                                            &call->skinfo, &answer); 
    1057     } else { 
    1058         status = create_inactive_sdp( call, &answer ); 
    1059     } 
    1060  
    1061     if (status != PJ_SUCCESS) { 
    1062         pjsua_perror(THIS_FILE, "Unable to create local SDP", status); 
    1063         return; 
    1064     } 
    1065  
    1066     status = pjsip_inv_set_sdp_answer(call->inv, answer); 
    1067     if (status != PJ_SUCCESS) { 
    1068         pjsua_perror(THIS_FILE, "Unable to set answer", status); 
    1069         return; 
    1070     } 
    1071  
    1072 } 
    1073  
    1074 #if 0 
    1075 /* Disconnect call */ 
    1076 static void call_disconnect(pjsip_inv_session *inv, 
    1077                             int st_code) 
    1078 { 
    1079     pjsip_tx_data *tdata; 
    1080     pj_status_t status; 
    1081  
    1082     status = pjsip_inv_end_session(inv, st_code, NULL, &tdata); 
    1083     if (status == PJ_SUCCESS) 
    1084         status = pjsip_inv_send_msg(inv, tdata); 
    1085  
    1086     if (status != PJ_SUCCESS) { 
    1087         pjsua_perror(THIS_FILE, "Unable to disconnect call", status); 
    1088     } 
    1089 } 
    1090 #endif 
    10911698 
    10921699/* 
     
    10981705                                       pj_status_t status) 
    10991706{ 
     1707    int prev_media_st = 0; 
    11001708    pjsua_call *call; 
    11011709    pjmedia_session_info sess_info; 
     
    11061714    char tmp[PJSIP_MAX_URL_SIZE]; 
    11071715 
    1108     call = inv->dlg->mod_data[pjsua.mod.id]; 
     1716    PJSUA_LOCK(); 
     1717 
     1718    call = inv->dlg->mod_data[pjsua_var.mod.id]; 
    11091719 
    11101720    if (status != PJ_SUCCESS) { 
     
    11201730            //call_disconnect(inv, PJSIP_SC_UNSUPPORTED_MEDIA_TYPE); 
    11211731        } 
     1732 
     1733        PJSUA_UNLOCK(); 
    11221734        return; 
    1123  
    11241735    } 
    11251736 
    11261737    /* Destroy existing media session, if any. */ 
    11271738 
    1128     if (call) 
     1739    if (call) { 
     1740        prev_media_st = call->media_st; 
    11291741        call_destroy_media(call->index); 
     1742    } 
    11301743 
    11311744    /* Get local and remote SDP */ 
     
    11371750                     status); 
    11381751        //call_disconnect(inv, PJSIP_SC_UNSUPPORTED_MEDIA_TYPE); 
     1752        PJSUA_UNLOCK(); 
    11391753        return; 
    11401754    } 
     
    11471761                     status); 
    11481762        //call_disconnect(inv, PJSIP_SC_UNSUPPORTED_MEDIA_TYPE); 
     1763        PJSUA_UNLOCK(); 
    11491764        return; 
    11501765    } 
    1151  
    1152     if (pjsua.config.null_audio) 
    1153         return; 
    11541766 
    11551767    /* Create media session info based on SDP parameters.  
     
    11571769     */     
    11581770    status = pjmedia_session_info_from_sdp( call->inv->dlg->pool,  
    1159                                             pjsua.med_endpt,  
     1771                                            pjsua_var.med_endpt,  
    11601772                                            1,&sess_info,  
    11611773                                            local_sdp, remote_sdp); 
     
    11641776                     status); 
    11651777        //call_disconnect(inv, PJSIP_SC_UNSUPPORTED_MEDIA_TYPE); 
     1778        PJSUA_UNLOCK(); 
    11661779        return; 
    11671780    } 
    11681781 
    1169     /* Override ptime, if this option is specified. */ 
    1170     if (pjsua.config.ptime) { 
    1171         sess_info.stream_info[0].param->setting.frm_per_pkt = (pj_uint8_t) 
    1172             (pjsua.config.ptime /  
    1173               sess_info.stream_info[0].param->info.frm_ptime); 
    1174         if (sess_info.stream_info[0].param->setting.frm_per_pkt==0) 
    1175             sess_info.stream_info[0].param->setting.frm_per_pkt = 1; 
    1176     } 
    1177  
    1178     /* Optionally, application may modify other stream settings here 
    1179      * (such as jitter buffer parameters, codec ptime, etc.) 
    1180      */ 
    1181  
    1182     /* Create session based on session info. */ 
    1183     status = pjmedia_session_create( pjsua.med_endpt, &sess_info, 
    1184                                      &call->med_tp, 
    1185                                      call, &call->session ); 
    1186     if (status != PJ_SUCCESS) { 
    1187         pjsua_perror(THIS_FILE, "Unable to create media session",  
    1188                      status); 
    1189         //call_disconnect(inv, PJSIP_SC_UNSUPPORTED_MEDIA_TYPE); 
    1190         return; 
    1191     } 
    1192  
    1193  
    1194     /* Get the port interface of the first stream in the session. 
    1195      * We need the port interface to add to the conference bridge. 
    1196      */ 
    1197     pjmedia_session_get_port(call->session, 0, &media_port); 
    1198  
    1199  
    1200     /* 
    1201      * Add the call to conference bridge. 
    1202      */ 
    1203     port_name.ptr = tmp; 
    1204     port_name.slen = pjsip_uri_print(PJSIP_URI_IN_REQ_URI, 
    1205                                      call->inv->dlg->remote.info->uri, 
    1206                                      tmp, sizeof(tmp)); 
    1207     if (port_name.slen < 1) { 
    1208         port_name = pj_str("call"); 
    1209     } 
    1210     status = pjmedia_conf_add_port( pjsua.mconf, call->inv->pool, 
    1211                                     media_port,  
    1212                                     &port_name, 
    1213                                     &call->conf_slot); 
    1214     if (status != PJ_SUCCESS) { 
    1215         pjsua_perror(THIS_FILE, "Unable to create conference slot",  
    1216                      status); 
    1217         call_destroy_media(call->index); 
    1218         //call_disconnect(inv, PJSIP_SC_INTERNAL_SERVER_ERROR); 
    1219         return; 
    1220     } 
    1221  
    1222     /* If auto-play is configured, connect the call to the file player  
    1223      * port  
    1224      */ 
    1225     if (pjsua.config.auto_play && pjsua.config.wav_file.slen &&  
    1226         call->inv->role == PJSIP_ROLE_UAS)  
     1782    /* Check if media is put on-hold */ 
     1783    if (sess_info.stream_cnt == 0 ||  
     1784        sess_info.stream_info[0].dir == PJMEDIA_DIR_NONE) 
    12271785    { 
    12281786 
    1229         pjmedia_conf_connect_port( pjsua.mconf, pjsua.player[0].slot,  
    1230                                    call->conf_slot, 0); 
    1231  
    1232     } 
    1233     if (pjsua.config.auto_loop && call->inv->role == PJSIP_ROLE_UAS) { 
    1234  
    1235         pjmedia_conf_connect_port( pjsua.mconf, call->conf_slot,  
    1236                                    call->conf_slot, 0); 
    1237  
    1238     } 
    1239     if (pjsua.config.auto_conf) { 
    1240         unsigned i; 
    1241  
    1242         pjmedia_conf_connect_port( pjsua.mconf, 0, call->conf_slot, 0); 
    1243         pjmedia_conf_connect_port( pjsua.mconf, call->conf_slot, 0, 0); 
    1244  
    1245         for (i=0; i < pjsua.config.max_calls; ++i) { 
    1246  
    1247             if (!pjsua.calls[i].session) 
    1248                 continue; 
    1249  
    1250             pjmedia_conf_connect_port( pjsua.mconf, call->conf_slot,  
    1251                                        pjsua.calls[i].conf_slot, 0); 
    1252             pjmedia_conf_connect_port( pjsua.mconf, pjsua.calls[i].conf_slot, 
    1253                                        call->conf_slot, 0); 
     1787        /* Determine who puts the call on-hold */ 
     1788        if (prev_media_st == PJSUA_CALL_MEDIA_ACTIVE) { 
     1789            if (pjmedia_sdp_neg_was_answer_remote(call->inv->neg)) { 
     1790                /* It was local who offer hold */ 
     1791                call->media_st = PJSUA_CALL_MEDIA_LOCAL_HOLD; 
     1792            } else { 
     1793                call->media_st = PJSUA_CALL_MEDIA_REMOTE_HOLD; 
     1794            } 
    12541795        } 
    12551796 
    1256     }  
    1257      
    1258     /* Normal operation: if no auto_xx is given, connect new call to  
    1259      * the sound device port (port zero) in the main conference bridge. 
    1260      */ 
    1261     if (pjsua.config.auto_play == 0 && pjsua.config.auto_loop == 0 && 
    1262         pjsua.config.auto_conf == 0) 
     1797        call->media_dir = PJMEDIA_DIR_NONE; 
     1798 
     1799    } else { 
     1800 
     1801        /* Override ptime, if this option is specified. */ 
     1802        PJ_TODO(set_codec_ptime_in_call); 
     1803 
     1804 
     1805        /* Optionally, application may modify other stream settings here 
     1806         * (such as jitter buffer parameters, codec ptime, etc.) 
     1807         */ 
     1808 
     1809        /* Create session based on session info. */ 
     1810        status = pjmedia_session_create( pjsua_var.med_endpt, &sess_info, 
     1811                                         &call->med_tp, 
     1812                                         call, &call->session ); 
     1813        if (status != PJ_SUCCESS) { 
     1814            pjsua_perror(THIS_FILE, "Unable to create media session",  
     1815                         status); 
     1816            //call_disconnect(inv, PJSIP_SC_UNSUPPORTED_MEDIA_TYPE); 
     1817            PJSUA_UNLOCK(); 
     1818            return; 
     1819        } 
     1820 
     1821 
     1822        /* Get the port interface of the first stream in the session. 
     1823         * We need the port interface to add to the conference bridge. 
     1824         */ 
     1825        pjmedia_session_get_port(call->session, 0, &media_port); 
     1826 
     1827 
     1828        /* 
     1829         * Add the call to conference bridge. 
     1830         */ 
     1831        port_name.ptr = tmp; 
     1832        port_name.slen = pjsip_uri_print(PJSIP_URI_IN_REQ_URI, 
     1833                                         call->inv->dlg->remote.info->uri, 
     1834                                         tmp, sizeof(tmp)); 
     1835        if (port_name.slen < 1) { 
     1836            port_name = pj_str("call"); 
     1837        } 
     1838        status = pjmedia_conf_add_port( pjsua_var.mconf, call->inv->pool, 
     1839                                        media_port,  
     1840                                        &port_name, 
     1841                                        (unsigned*)&call->conf_slot); 
     1842        if (status != PJ_SUCCESS) { 
     1843            pjsua_perror(THIS_FILE, "Unable to create conference slot",  
     1844                         status); 
     1845            call_destroy_media(call->index); 
     1846            //call_disconnect(inv, PJSIP_SC_INTERNAL_SERVER_ERROR); 
     1847            PJSUA_UNLOCK(); 
     1848            return; 
     1849        } 
     1850 
     1851        /* Call's media state is active */ 
     1852        call->media_st = PJSUA_CALL_MEDIA_ACTIVE; 
     1853        call->media_dir = sess_info.stream_info[0].dir; 
     1854    } 
     1855 
     1856    /* Print info. */ 
    12631857    { 
    1264         pjmedia_conf_connect_port( pjsua.mconf, 0, call->conf_slot, 0); 
    1265         pjmedia_conf_connect_port( pjsua.mconf, call->conf_slot, 0, 0); 
    1266     } 
    1267  
    1268  
    1269     /* Done. */ 
    1270     { 
    1271         struct pjmedia_session_info sess_info; 
    12721858        char info[80]; 
    12731859        int info_len = 0; 
    12741860        unsigned i; 
    12751861 
    1276         pjmedia_session_get_info(call->session, &sess_info); 
    12771862        for (i=0; i<sess_info.stream_cnt; ++i) { 
    12781863            int len; 
     
    13051890                info_len += len; 
    13061891        } 
    1307         PJ_LOG(3,(THIS_FILE,"Media started%s", info)); 
    1308     } 
    1309 } 
    1310  
    1311  
    1312 /* 
    1313  * Hangup call. 
    1314  */ 
    1315 PJ_DEF(void) pjsua_call_hangup(int call_index) 
    1316 { 
     1892        PJ_LOG(4,(THIS_FILE,"Media updates%s", info)); 
     1893    } 
     1894 
     1895    /* Call application callback, if any */ 
     1896    if (pjsua_var.ua_cfg.cb.on_call_media_state) 
     1897        pjsua_var.ua_cfg.cb.on_call_media_state(call->index); 
     1898 
     1899 
     1900    PJSUA_UNLOCK(); 
     1901} 
     1902 
     1903 
     1904/* 
     1905 * Create inactive SDP for call hold. 
     1906 */ 
     1907static pj_status_t create_inactive_sdp(pjsua_call *call, 
     1908                                       pjmedia_sdp_session **p_answer) 
     1909{ 
     1910    pj_status_t status; 
     1911    pjmedia_sdp_conn *conn; 
     1912    pjmedia_sdp_attr *attr; 
     1913    pjmedia_sdp_session *sdp; 
     1914 
     1915    /* Create new offer */ 
     1916    status = pjmedia_endpt_create_sdp(pjsua_var.med_endpt, pjsua_var.pool, 1, 
     1917                                      &call->skinfo, &sdp); 
     1918    if (status != PJ_SUCCESS) { 
     1919        pjsua_perror(THIS_FILE, "Unable to create local SDP", status); 
     1920        return status; 
     1921    } 
     1922 
     1923    /* Get SDP media connection line */ 
     1924    conn = sdp->media[0]->conn; 
     1925    if (!conn) 
     1926        conn = sdp->conn; 
     1927 
     1928    /* Modify address */ 
     1929    conn->addr = pj_str("0.0.0.0"); 
     1930 
     1931    /* Remove existing directions attributes */ 
     1932    pjmedia_sdp_media_remove_all_attr(sdp->media[0], "sendrecv"); 
     1933    pjmedia_sdp_media_remove_all_attr(sdp->media[0], "sendonly"); 
     1934    pjmedia_sdp_media_remove_all_attr(sdp->media[0], "recvonly"); 
     1935    pjmedia_sdp_media_remove_all_attr(sdp->media[0], "inactive"); 
     1936 
     1937    /* Add inactive attribute */ 
     1938    attr = pjmedia_sdp_attr_create(pjsua_var.pool, "inactive", NULL); 
     1939    pjmedia_sdp_media_add_attr(sdp->media[0], attr); 
     1940 
     1941    *p_answer = sdp; 
     1942 
     1943    return status; 
     1944} 
     1945 
     1946 
     1947/* 
     1948 * Called when session received new offer. 
     1949 */ 
     1950static void pjsua_call_on_rx_offer(pjsip_inv_session *inv, 
     1951                                   const pjmedia_sdp_session *offer) 
     1952{ 
     1953    const char *remote_state; 
    13171954    pjsua_call *call; 
    1318     int code; 
     1955    pjmedia_sdp_conn *conn; 
     1956    pjmedia_sdp_session *answer; 
     1957    pj_bool_t is_remote_active; 
     1958    pj_status_t status; 
     1959 
     1960    PJSUA_LOCK(); 
     1961 
     1962    call = inv->dlg->mod_data[pjsua_var.mod.id]; 
     1963 
     1964    /* 
     1965     * See if remote is offering active media (i.e. not on-hold) 
     1966     */ 
     1967    is_remote_active = PJ_TRUE; 
     1968 
     1969    conn = offer->media[0]->conn; 
     1970    if (!conn) 
     1971        conn = offer->conn; 
     1972 
     1973    if (pj_strcmp2(&conn->addr, "0.0.0.0")==0 || 
     1974        pj_strcmp2(&conn->addr, "0")==0) 
     1975    { 
     1976        is_remote_active = PJ_FALSE; 
     1977 
     1978    }  
     1979    else if (pjmedia_sdp_media_find_attr2(offer->media[0], "inactive", NULL)) 
     1980    { 
     1981        is_remote_active = PJ_FALSE; 
     1982    } 
     1983 
     1984    remote_state = (is_remote_active ? "active" : "inactive"); 
     1985 
     1986    /* Supply candidate answer */ 
     1987    if (call->media_st == PJSUA_CALL_MEDIA_LOCAL_HOLD || !is_remote_active) { 
     1988        PJ_LOG(4,(THIS_FILE,  
     1989                  "Call %d: RX new media offer, creating inactive SDP " 
     1990                  "(media in offer is %s)", call->index, remote_state)); 
     1991        status = create_inactive_sdp( call, &answer ); 
     1992    } else { 
     1993        PJ_LOG(4,(THIS_FILE, "Call %d: received updated media offer", 
     1994                  call->index)); 
     1995        status = pjmedia_endpt_create_sdp( pjsua_var.med_endpt,  
     1996                                           call->inv->pool, 1, 
     1997                                           &call->skinfo, &answer);      
     1998    } 
     1999 
     2000    if (status != PJ_SUCCESS) { 
     2001        pjsua_perror(THIS_FILE, "Unable to create local SDP", status); 
     2002        PJSUA_UNLOCK(); 
     2003        return; 
     2004    } 
     2005 
     2006    status = pjsip_inv_set_sdp_answer(call->inv, answer); 
     2007    if (status != PJ_SUCCESS) { 
     2008        pjsua_perror(THIS_FILE, "Unable to set answer", status); 
     2009        PJSUA_UNLOCK(); 
     2010        return; 
     2011    } 
     2012 
     2013    PJSUA_UNLOCK(); 
     2014} 
     2015 
     2016 
     2017/* 
     2018 * Callback called by event framework when the xfer subscription state 
     2019 * has changed. 
     2020 */ 
     2021static void xfer_on_evsub_state( pjsip_evsub *sub, pjsip_event *event) 
     2022{ 
     2023     
     2024    PJ_UNUSED_ARG(event); 
     2025 
     2026    /* 
     2027     * We're only interested when subscription is terminated, to  
     2028     * clear the xfer_sub member of the inv_data. 
     2029     */ 
     2030    if (pjsip_evsub_get_state(sub) == PJSIP_EVSUB_STATE_TERMINATED) { 
     2031        pjsua_call *call; 
     2032 
     2033        call = pjsip_evsub_get_mod_data(sub, pjsua_var.mod.id); 
     2034        if (!call) 
     2035            return; 
     2036 
     2037        pjsip_evsub_set_mod_data(sub, pjsua_var.mod.id, NULL); 
     2038        call->xfer_sub = NULL; 
     2039 
     2040        PJ_LOG(3,(THIS_FILE, "Xfer subscription terminated")); 
     2041    } 
     2042} 
     2043 
     2044 
     2045/* 
     2046 * Follow transfer (REFER) request. 
     2047 */ 
     2048static void on_call_transfered( pjsip_inv_session *inv, 
     2049                                pjsip_rx_data *rdata ) 
     2050{ 
    13192051    pj_status_t status; 
    13202052    pjsip_tx_data *tdata; 
    1321  
    1322  
    1323     call = &pjsua.calls[call_index]; 
    1324  
    1325     if (!call->inv) { 
    1326         PJ_LOG(3,(THIS_FILE,"Call has been disconnected")); 
     2053    pjsua_call *existing_call; 
     2054    int new_call; 
     2055    const pj_str_t str_refer_to = { "Refer-To", 8}; 
     2056    pjsip_generic_string_hdr *refer_to; 
     2057    char *uri; 
     2058    pj_str_t tmp; 
     2059    struct pjsip_evsub_user xfer_cb; 
     2060    pjsip_status_code code; 
     2061    pjsip_evsub *sub; 
     2062 
     2063    existing_call = inv->dlg->mod_data[pjsua_var.mod.id]; 
     2064 
     2065    /* Find the Refer-To header */ 
     2066    refer_to = (pjsip_generic_string_hdr*) 
     2067        pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &str_refer_to, NULL); 
     2068 
     2069    if (refer_to == NULL) { 
     2070        /* Invalid Request. 
     2071         * No Refer-To header! 
     2072         */ 
     2073        PJ_LOG(4,(THIS_FILE, "Received REFER without Refer-To header!")); 
     2074        pjsip_dlg_respond( inv->dlg, rdata, 400, NULL, NULL, NULL); 
    13272075        return; 
    13282076    } 
    13292077 
    1330     if (call->inv->state == PJSIP_INV_STATE_CONFIRMED) 
    1331         code = PJSIP_SC_OK; 
    1332     else if (call->inv->role == PJSIP_ROLE_UAS) 
    1333         code = PJSIP_SC_DECLINE; 
    1334     else 
    1335         code = PJSIP_SC_REQUEST_TERMINATED; 
    1336  
    1337     status = pjsip_inv_end_session(call->inv, code, NULL, &tdata); 
    1338     if (status != PJ_SUCCESS) { 
    1339         pjsua_perror(THIS_FILE,  
    1340                      "Failed to create end session message",  
    1341                      status); 
     2078    /* Notify callback */ 
     2079    code = PJSIP_SC_OK; 
     2080    if (pjsua_var.ua_cfg.cb.on_call_transfered) 
     2081        (*pjsua_var.ua_cfg.cb.on_call_transfered)(existing_call->index, 
     2082                                                  &refer_to->hvalue, &code); 
     2083 
     2084    if (code < 200) 
     2085        code = 200; 
     2086    if (code >= 300) { 
     2087        /* Application rejects call transfer request */ 
     2088        pjsip_dlg_respond( inv->dlg, rdata, code, NULL, NULL, NULL); 
    13422089        return; 
    13432090    } 
    13442091 
    1345     /* pjsip_inv_end_session may return PJ_SUCCESS with NULL  
    1346      * as p_tdata when INVITE transaction has not been answered 
    1347      * with any provisional responses. 
     2092    PJ_LOG(3,(THIS_FILE, "Call to %.*s is being transfered to %.*s", 
     2093              (int)inv->dlg->remote.info_str.slen, 
     2094              inv->dlg->remote.info_str.ptr, 
     2095              (int)refer_to->hvalue.slen,  
     2096              refer_to->hvalue.ptr)); 
     2097 
     2098    /* Init callback */ 
     2099    pj_memset(&xfer_cb, 0, sizeof(xfer_cb)); 
     2100    xfer_cb.on_evsub_state = &xfer_on_evsub_state; 
     2101 
     2102    /* Create transferee event subscription */ 
     2103    status = pjsip_xfer_create_uas( inv->dlg, &xfer_cb, rdata, &sub); 
     2104    if (status != PJ_SUCCESS) { 
     2105        pjsua_perror(THIS_FILE, "Unable to create xfer uas", status); 
     2106        pjsip_dlg_respond( inv->dlg, rdata, 500, NULL, NULL, NULL); 
     2107        return; 
     2108    } 
     2109 
     2110    /* Accept the REFER request, send 200 (OK). */ 
     2111    pjsip_xfer_accept(sub, rdata, code, NULL); 
     2112 
     2113    /* Create initial NOTIFY request */ 
     2114    status = pjsip_xfer_notify( sub, PJSIP_EVSUB_STATE_ACTIVE, 
     2115                                100, NULL, &tdata); 
     2116    if (status != PJ_SUCCESS) { 
     2117        pjsua_perror(THIS_FILE, "Unable to create NOTIFY to REFER", status); 
     2118        return; 
     2119    } 
     2120 
     2121    /* Send initial NOTIFY request */ 
     2122    status = pjsip_xfer_send_request( sub, tdata); 
     2123    if (status != PJ_SUCCESS) { 
     2124        pjsua_perror(THIS_FILE, "Unable to send NOTIFY to REFER", status); 
     2125        return; 
     2126    } 
     2127 
     2128    /* We're cheating here. 
     2129     * We need to get a null terminated string from a pj_str_t. 
     2130     * So grab the pointer from the hvalue and NULL terminate it, knowing 
     2131     * that the NULL position will be occupied by a newline.  
    13482132     */ 
    1349     if (tdata == NULL) 
     2133    uri = refer_to->hvalue.ptr; 
     2134    uri[refer_to->hvalue.slen] = '\0'; 
     2135 
     2136    /* Now make the outgoing call. */ 
     2137    tmp = pj_str(uri); 
     2138    status = pjsua_call_make_call(existing_call->acc_id, &tmp, 0, 
     2139                                  existing_call->user_data, NULL,  
     2140                                  &new_call); 
     2141    if (status != PJ_SUCCESS) { 
     2142 
     2143        /* Notify xferer about the error */ 
     2144        status = pjsip_xfer_notify(sub, PJSIP_EVSUB_STATE_TERMINATED, 
     2145                                   500, NULL, &tdata); 
     2146        if (status != PJ_SUCCESS) { 
     2147            pjsua_perror(THIS_FILE, "Unable to create NOTIFY to REFER",  
     2148                          status); 
     2149            return; 
     2150        } 
     2151        status = pjsip_xfer_send_request(sub, tdata); 
     2152        if (status != PJ_SUCCESS) { 
     2153            pjsua_perror(THIS_FILE, "Unable to send NOTIFY to REFER",  
     2154                          status); 
     2155            return; 
     2156        } 
    13502157        return; 
    1351  
    1352     status = pjsip_inv_send_msg(call->inv, tdata); 
    1353     if (status != PJ_SUCCESS) { 
    1354         pjsua_perror(THIS_FILE,  
    1355                      "Failed to send end session message",  
    1356                      status); 
    1357         return; 
    1358     } 
    1359 } 
    1360  
    1361  
    1362 /* 
    1363  * Put call on-Hold. 
    1364  */ 
    1365 PJ_DEF(pj_status_t) pjsua_call_set_hold(int call_index) 
    1366 { 
    1367     pjmedia_sdp_session *sdp; 
    1368     pjsua_call *call; 
    1369     pjsip_tx_data *tdata; 
    1370     pj_status_t status; 
    1371  
    1372     call = &pjsua.calls[call_index]; 
    1373      
    1374     if (!call->inv) { 
    1375         PJ_LOG(3,(THIS_FILE,"Call has been disconnected")); 
    1376         return PJSIP_ESESSIONTERMINATED; 
    1377     } 
    1378  
    1379     if (call->inv->state != PJSIP_INV_STATE_CONFIRMED) { 
    1380         PJ_LOG(3,(THIS_FILE, "Can not hold call that is not confirmed")); 
    1381         return PJSIP_ESESSIONSTATE; 
    1382     } 
    1383  
    1384     status = create_inactive_sdp(call, &sdp); 
    1385     if (status != PJ_SUCCESS) 
    1386         return status; 
    1387  
    1388     /* Send re-INVITE with new offer */ 
    1389     status = pjsip_inv_reinvite( call->inv, NULL, sdp, &tdata); 
    1390     if (status != PJ_SUCCESS) { 
    1391         pjsua_perror(THIS_FILE, "Unable to create re-INVITE", status); 
    1392         return status; 
    1393     } 
    1394  
    1395     status = pjsip_inv_send_msg( call->inv, tdata); 
    1396     if (status != PJ_SUCCESS) { 
    1397         pjsua_perror(THIS_FILE, "Unable to send re-INVITE", status); 
    1398         return status; 
    1399     } 
    1400  
    1401     return PJ_SUCCESS; 
    1402 } 
    1403  
    1404  
    1405 /* 
    1406  * re-INVITE. 
    1407  */ 
    1408 PJ_DEF(pj_status_t) pjsua_call_reinvite(int call_index) 
    1409 { 
    1410     pjmedia_sdp_session *sdp; 
    1411     pjsip_tx_data *tdata; 
    1412     pjsua_call *call; 
    1413     pj_status_t status; 
    1414  
    1415     call = &pjsua.calls[call_index]; 
    1416  
    1417     if (!call->inv) { 
    1418         PJ_LOG(3,(THIS_FILE,"Call has been disconnected")); 
    1419         return PJSIP_ESESSIONTERMINATED; 
    1420     } 
    1421  
    1422  
    1423     if (call->inv->state != PJSIP_INV_STATE_CONFIRMED) { 
    1424         PJ_LOG(3,(THIS_FILE, "Can not re-INVITE call that is not confirmed")); 
    1425         return PJSIP_ESESSIONSTATE; 
    1426     } 
    1427  
    1428     /* Create SDP */ 
    1429     status = pjmedia_endpt_create_sdp( pjsua.med_endpt, call->inv->pool, 1, 
    1430                                        &call->skinfo, &sdp); 
    1431     if (status != PJ_SUCCESS) { 
    1432         pjsua_perror(THIS_FILE, "Unable to get SDP from media endpoint",  
    1433                      status); 
    1434         return status; 
    1435     } 
    1436  
    1437     /* Send re-INVITE with new offer */ 
    1438     status = pjsip_inv_reinvite( call->inv, NULL, sdp, &tdata); 
    1439     if (status != PJ_SUCCESS) { 
    1440         pjsua_perror(THIS_FILE, "Unable to create re-INVITE", status); 
    1441         return status; 
    1442     } 
    1443  
    1444     status = pjsip_inv_send_msg( call->inv, tdata); 
    1445     if (status != PJ_SUCCESS) { 
    1446         pjsua_perror(THIS_FILE, "Unable to send re-INVITE", status); 
    1447         return status; 
    1448     } 
    1449  
    1450     return PJ_SUCCESS; 
    1451 } 
    1452  
    1453  
    1454 /* 
    1455  * Transfer call. 
    1456  */ 
    1457 PJ_DEF(pj_status_t) pjsua_call_xfer(unsigned call_index, const pj_str_t *dest) 
    1458 { 
    1459     pjsip_evsub *sub; 
    1460     pjsip_tx_data *tdata; 
    1461     pjsua_call *call; 
    1462     pj_status_t status; 
    1463  
    1464      
    1465     call = &pjsua.calls[call_index]; 
    1466  
    1467     if (!call->inv) { 
    1468         PJ_LOG(3,(THIS_FILE,"Call has been disconnected")); 
    1469         return PJSIP_ESESSIONTERMINATED; 
    1470     } 
    1471     
    1472     /* Create xfer client subscription. 
    1473      * We're not interested in knowing the transfer result, so we 
    1474      * put NULL as the callback. 
     2158    } 
     2159 
     2160    /* Put the server subscription in inv_data. 
     2161     * Subsequent state changed in pjsua_inv_on_state_changed() will be 
     2162     * reported back to the server subscription. 
    14752163     */ 
    1476     status = pjsip_xfer_create_uac(call->inv->dlg, NULL, &sub); 
    1477     if (status != PJ_SUCCESS) { 
    1478         pjsua_perror(THIS_FILE, "Unable to create xfer", status); 
    1479         return status; 
    1480     } 
    1481  
    1482     /* 
    1483      * Create REFER request. 
    1484      */ 
    1485     status = pjsip_xfer_initiate(sub, dest, &tdata); 
    1486     if (status != PJ_SUCCESS) { 
    1487         pjsua_perror(THIS_FILE, "Unable to create REFER request", status); 
    1488         return status; 
    1489     } 
    1490  
    1491     /* Send. */ 
    1492     status = pjsip_xfer_send_request(sub, tdata); 
    1493     if (status != PJ_SUCCESS) { 
    1494         pjsua_perror(THIS_FILE, "Unable to send REFER request", status); 
    1495         return status; 
    1496     } 
    1497  
    1498     /* For simplicity (that's what this program is intended to be!),  
    1499      * leave the original invite session as it is. More advanced application 
    1500      * may want to hold the INVITE, or terminate the invite, or whatever. 
    1501      */ 
    1502  
    1503     return PJ_SUCCESS; 
    1504 } 
    1505  
    1506  
    1507 /** 
    1508  * Dial DTMF. 
    1509  */ 
    1510 PJ_DEF(pj_status_t) pjsua_call_dial_dtmf( unsigned call_index,  
    1511                                           const pj_str_t *digits) 
    1512 { 
    1513     pjsua_call *call = &pjsua.calls[call_index]; 
    1514  
    1515     PJ_ASSERT_RETURN(call_index < pjsua.config.max_calls, PJ_EINVAL); 
    1516  
    1517     if (!call->session) { 
    1518         PJ_LOG(3,(THIS_FILE, "Media is not established yet!")); 
    1519         return -1; 
    1520     } 
    1521  
    1522     return pjmedia_session_dial_dtmf( call->session, 0, digits); 
    1523 } 
    1524  
    1525  
    1526 /** 
    1527  * Send instant messaging inside INVITE session. 
    1528  */ 
    1529 PJ_DEF(pj_status_t) pjsua_call_send_im(int call_index, const pj_str_t *str) 
    1530 { 
    1531     pjsua_call *call; 
    1532     const pj_str_t mime_text = pj_str("text"); 
    1533     const pj_str_t mime_plain = pj_str("plain"); 
    1534     pjsip_tx_data *tdata; 
    1535     pj_status_t status; 
    1536  
    1537     call = &pjsua.calls[call_index]; 
    1538  
    1539     if (!call->inv) { 
    1540         PJ_LOG(3,(THIS_FILE,"Call has been disconnected")); 
    1541         return PJSIP_ESESSIONTERMINATED; 
    1542     } 
    1543  
    1544     /* Lock dialog. */ 
    1545     pjsip_dlg_inc_lock(call->inv->dlg); 
    1546      
    1547     /* Create request message. */ 
    1548     status = pjsip_dlg_create_request( call->inv->dlg, &pjsip_message_method, 
    1549                                        -1, &tdata); 
    1550     if (status != PJ_SUCCESS) { 
    1551         pjsua_perror(THIS_FILE, "Unable to create MESSAGE request", status); 
    1552         goto on_return; 
    1553     } 
    1554  
    1555     /* Add accept header. */ 
    1556     pjsip_msg_add_hdr( tdata->msg,  
    1557                        (pjsip_hdr*)pjsua_im_create_accept(tdata->pool)); 
    1558  
    1559     /* Create "text/plain" message body. */ 
    1560     tdata->msg->body = pjsip_msg_body_create( tdata->pool, &mime_text, 
    1561                                               &mime_plain, str); 
    1562     if (tdata->msg->body == NULL) { 
    1563         pjsua_perror(THIS_FILE, "Unable to create msg body", PJ_ENOMEM); 
    1564         pjsip_tx_data_dec_ref(tdata); 
    1565         goto on_return; 
    1566     } 
    1567  
    1568     /* Send the request. */ 
    1569     status = pjsip_dlg_send_request( call->inv->dlg, tdata, -1, NULL); 
    1570     if (status != PJ_SUCCESS) { 
    1571         pjsua_perror(THIS_FILE, "Unable to send MESSAGE request", status); 
    1572         goto on_return; 
    1573     } 
    1574  
    1575 on_return: 
    1576     pjsip_dlg_dec_lock(call->inv->dlg); 
    1577     return status; 
    1578 } 
    1579  
    1580  
    1581 /** 
    1582  * Send IM typing indication inside INVITE session. 
    1583  */ 
    1584 PJ_DEF(pj_status_t) pjsua_call_send_typing_ind(int call_index,  
    1585                                                pj_bool_t is_typing) 
    1586 { 
    1587     pjsua_call *call; 
    1588     pjsip_tx_data *tdata; 
    1589     pj_status_t status; 
    1590  
    1591     call = &pjsua.calls[call_index]; 
    1592  
    1593     if (!call->inv) { 
    1594         PJ_LOG(3,(THIS_FILE,"Call has been disconnected")); 
    1595         return PJSIP_ESESSIONTERMINATED; 
    1596     } 
    1597  
    1598     /* Lock dialog. */ 
    1599     pjsip_dlg_inc_lock(call->inv->dlg); 
    1600      
    1601     /* Create request message. */ 
    1602     status = pjsip_dlg_create_request( call->inv->dlg, &pjsip_message_method, 
    1603                                        -1, &tdata); 
    1604     if (status != PJ_SUCCESS) { 
    1605         pjsua_perror(THIS_FILE, "Unable to create MESSAGE request", status); 
    1606         goto on_return; 
    1607     } 
    1608  
    1609     /* Create "application/im-iscomposing+xml" msg body. */ 
    1610     tdata->msg->body = pjsip_iscomposing_create_body(tdata->pool, is_typing, 
    1611                                                      NULL, NULL, -1); 
    1612  
    1613     /* Send the request. */ 
    1614     status = pjsip_dlg_send_request( call->inv->dlg, tdata, -1, NULL); 
    1615     if (status != PJ_SUCCESS) { 
    1616         pjsua_perror(THIS_FILE, "Unable to send MESSAGE request", status); 
    1617         goto on_return; 
    1618     } 
    1619  
    1620 on_return: 
    1621     pjsip_dlg_dec_lock(call->inv->dlg); 
    1622     return status; 
    1623 } 
    1624  
    1625  
    1626 /* 
    1627  * Terminate all calls. 
    1628  */ 
    1629 PJ_DEF(void) pjsua_call_hangup_all(void) 
    1630 { 
    1631     unsigned i; 
    1632  
    1633     for (i=0; i<pjsua.config.max_calls; ++i) { 
    1634         pjsip_tx_data *tdata; 
    1635         int st_code; 
    1636         pjsua_call *call; 
    1637  
    1638         if (pjsua.calls[i].inv == NULL) 
    1639             continue; 
    1640  
    1641         call = &pjsua.calls[i]; 
    1642  
    1643         if (call->inv->state == PJSIP_INV_STATE_CONFIRMED) { 
    1644             st_code = 200; 
    1645         } else { 
    1646             st_code = PJSIP_SC_GONE; 
     2164    pjsua_var.calls[new_call].xfer_sub = sub; 
     2165 
     2166    /* Put the invite_data in the subscription. */ 
     2167    pjsip_evsub_set_mod_data(sub, pjsua_var.mod.id,  
     2168                             &pjsua_var.calls[new_call]); 
     2169} 
     2170 
     2171 
     2172 
     2173/* 
     2174 * This callback is called when transaction state has changed in INVITE 
     2175 * session. We use this to trap: 
     2176 *  - incoming REFER request. 
     2177 *  - incoming MESSAGE request. 
     2178 */ 
     2179static void pjsua_call_on_tsx_state_changed(pjsip_inv_session *inv, 
     2180                                            pjsip_transaction *tsx, 
     2181                                            pjsip_event *e) 
     2182{ 
     2183    pjsua_call *call = inv->dlg->mod_data[pjsua_var.mod.id]; 
     2184 
     2185    PJSUA_LOCK(); 
     2186 
     2187    if (tsx->role==PJSIP_ROLE_UAS && 
     2188        tsx->state==PJSIP_TSX_STATE_TRYING && 
     2189        pjsip_method_cmp(&tsx->method, &pjsip_refer_method)==0) 
     2190    { 
     2191        /* 
     2192         * Incoming REFER request. 
     2193         */ 
     2194        on_call_transfered(call->inv, e->body.tsx_state.src.rdata); 
     2195 
     2196    } 
     2197    else if (tsx->role==PJSIP_ROLE_UAS && 
     2198             tsx->state==PJSIP_TSX_STATE_TRYING && 
     2199             pjsip_method_cmp(&tsx->method, &pjsip_message_method)==0) 
     2200    { 
     2201        /* 
     2202         * Incoming MESSAGE request! 
     2203         */ 
     2204        pjsip_rx_data *rdata; 
     2205        pjsip_msg *msg; 
     2206        pjsip_accept_hdr *accept_hdr; 
     2207        pj_status_t status; 
     2208 
     2209        rdata = e->body.tsx_state.src.rdata; 
     2210        msg = rdata->msg_info.msg; 
     2211 
     2212        /* Request MUST have message body, with Content-Type equal to 
     2213         * "text/plain". 
     2214         */ 
     2215        if (pjsua_im_accept_pager(rdata, &accept_hdr) == PJ_FALSE) { 
     2216 
     2217            pjsip_hdr hdr_list; 
     2218 
     2219            pj_list_init(&hdr_list); 
     2220            pj_list_push_back(&hdr_list, accept_hdr); 
     2221 
     2222            pjsip_dlg_respond( inv->dlg, rdata, PJSIP_SC_NOT_ACCEPTABLE_HERE,  
     2223                               NULL, &hdr_list, NULL ); 
     2224            PJSUA_UNLOCK(); 
     2225            return; 
    16472226        } 
    16482227 
    1649         if (pjsip_inv_end_session(call->inv, st_code, NULL, &tdata)==0) { 
    1650             if (tdata) 
    1651                 pjsip_inv_send_msg(call->inv, tdata); 
     2228        /* Respond with 200 first, so that remote doesn't retransmit in case 
     2229         * the UI takes too long to process the message.  
     2230         */ 
     2231        status = pjsip_dlg_respond( inv->dlg, rdata, 200, NULL, NULL, NULL); 
     2232 
     2233        /* Process MESSAGE request */ 
     2234        pjsua_im_process_pager(call->index, &inv->dlg->remote.info_str, 
     2235                               &inv->dlg->local.info_str, rdata); 
     2236 
     2237    } 
     2238    else if (tsx->role == PJSIP_ROLE_UAC && 
     2239             pjsip_method_cmp(&tsx->method, &pjsip_message_method)==0) 
     2240    { 
     2241        /* Handle outgoing pager status */ 
     2242        if (tsx->status_code >= 200) { 
     2243            pjsua_im_data *im_data; 
     2244 
     2245            im_data = tsx->mod_data[pjsua_var.mod.id]; 
     2246            /* im_data can be NULL if this is typing indication */ 
     2247 
     2248            if (im_data && pjsua_var.ua_cfg.cb.on_pager_status) { 
     2249                pjsua_var.ua_cfg.cb.on_pager_status(im_data->call_id, 
     2250                                                    &im_data->to, 
     2251                                                    &im_data->body, 
     2252                                                    im_data->user_data, 
     2253                                                    tsx->status_code, 
     2254                                                    &tsx->status_text); 
     2255            } 
    16522256        } 
    16532257    } 
    1654 } 
    1655  
    1656  
    1657 pj_status_t pjsua_call_init(void) 
    1658 { 
    1659     /* Initialize invite session callback. */ 
    1660     pjsip_inv_callback inv_cb; 
    1661     pj_status_t status; 
    1662  
    1663     pj_memset(&inv_cb, 0, sizeof(inv_cb)); 
    1664     inv_cb.on_state_changed = &pjsua_call_on_state_changed; 
    1665     inv_cb.on_new_session = &pjsua_call_on_forked; 
    1666     inv_cb.on_media_update = &pjsua_call_on_media_update; 
    1667     inv_cb.on_rx_offer = &pjsua_call_on_rx_offer; 
    1668     inv_cb.on_tsx_state_changed = &pjsua_call_on_tsx_state_changed; 
    1669  
    1670  
    1671     /* Initialize invite session module: */ 
    1672     status = pjsip_inv_usage_init(pjsua.endpt, &inv_cb); 
    1673      
    1674     return status; 
    1675 } 
    1676  
    1677 /** 
    1678  * Replace media transport. 
    1679  */ 
    1680 PJ_DEF(pj_status_t) pjsua_set_call_media_transport( unsigned call_index, 
    1681                                                     const pjmedia_sock_info *i, 
    1682                                                     pjmedia_transport *tp) 
    1683 { 
    1684     pjsua_call *call = &pjsua.calls[call_index]; 
    1685  
    1686     if (i) 
    1687         pj_memcpy(&call->skinfo, i, sizeof(pjmedia_sock_info)); 
    1688      
    1689     if (call->med_tp) 
    1690         (*call->med_tp->op->destroy)(call->med_tp); 
    1691  
    1692     call->med_tp = tp; 
    1693     return PJ_SUCCESS; 
    1694 } 
     2258 
     2259 
     2260    PJSUA_UNLOCK(); 
     2261} 
  • 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} 
  • pjproject/trunk/pjsip/src/pjsua-lib/pjsua_im.c

    r492 r503  
    1818 */ 
    1919#include <pjsua-lib/pjsua.h> 
    20 #include <pj/log.h> 
    21 #include "pjsua_imp.h" 
    22  
    23 /* 
    24  * pjsua_im.c 
    25  * 
    26  * To handle incoming MESSAGE outside dialog. 
    27  * Incoming MESSAGE inside dialog is hanlded in pjsua_call.c. 
    28  */ 
    29  
    30 #define THIS_FILE   "pjsua_im.c" 
     20#include <pjsua-lib/pjsua_internal.h> 
     21 
     22 
     23#define THIS_FILE   "pjsua_im.h" 
    3124 
    3225 
     
    5043/* Proto */ 
    5144static pj_bool_t im_on_rx_request(pjsip_rx_data *rdata); 
     45 
    5246 
    5347/* The module instance. */ 
     
    137131 *          This may trigger pjsua_ui_on_pager() or pjsua_ui_on_typing(). 
    138132 */ 
    139 void pjsua_im_process_pager(int call_index, const pj_str_t *from, 
     133void pjsua_im_process_pager(int call_id, const pj_str_t *from, 
    140134                            const pj_str_t *to, pjsip_rx_data *rdata) 
    141135{ 
     136    pjsip_contact_hdr *contact_hdr; 
     137    pj_str_t contact; 
    142138    pjsip_msg_body *body = rdata->msg_info.msg->body; 
    143139 
    144140    /* Body MUST have been checked before */ 
    145141    pj_assert(body != NULL); 
     142 
     143 
     144    /* Build remote contact */ 
     145    contact_hdr = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_CONTACT, 
     146                                     NULL); 
     147    if (contact_hdr) { 
     148        contact.ptr = pj_pool_alloc(rdata->tp_info.pool,  
     149                                    PJSIP_MAX_URL_SIZE); 
     150        contact.slen = pjsip_uri_print(PJSIP_URI_IN_CONTACT_HDR, 
     151                                       contact_hdr->uri, contact.ptr, 
     152                                       PJSIP_MAX_URL_SIZE); 
     153    } else { 
     154        contact.slen = 0; 
     155    } 
     156 
    146157 
    147158    if (pj_stricmp(&body->content_type.type, &STR_MIME_TEXT)==0 && 
    148159        pj_stricmp(&body->content_type.subtype, &STR_MIME_PLAIN)==0) 
    149160    { 
    150         pj_str_t text; 
    151  
    152         /* Build the text. */ 
    153         text.ptr = rdata->msg_info.msg->body->data; 
    154         text.slen = rdata->msg_info.msg->body->len; 
    155  
    156         if (pjsua.cb.on_pager) 
    157             (*pjsua.cb.on_pager)(call_index, from, to, &text); 
     161        const pj_str_t mime_text_plain = pj_str("text/plain"); 
     162        pj_str_t text_body; 
     163         
     164        /* Save text body */ 
     165        text_body.ptr = rdata->msg_info.msg->body->data; 
     166        text_body.slen = rdata->msg_info.msg->body->len; 
     167 
     168        if (pjsua_var.ua_cfg.cb.on_pager) { 
     169            (*pjsua_var.ua_cfg.cb.on_pager)(call_id, from, to, &contact,  
     170                                            &mime_text_plain, &text_body); 
     171        } 
    158172 
    159173    } else { 
    160  
    161174        /* Expecting typing indication */ 
    162  
    163175        pj_status_t status; 
    164176        pj_bool_t is_typing; 
     
    172184        } 
    173185 
    174         if (pjsua.cb.on_typing) 
    175             (*pjsua.cb.on_typing)(call_index, from, to, is_typing); 
     186        if (pjsua_var.ua_cfg.cb.on_typing) { 
     187            (*pjsua_var.ua_cfg.cb.on_typing)(call_id, from, to, &contact, 
     188                                             is_typing); 
     189        } 
    176190    } 
    177191 
     
    211225        pj_list_push_back(&hdr_list, accept_hdr); 
    212226 
    213         pjsip_endpt_respond_stateless(pjsua.endpt, rdata,  
     227        pjsip_endpt_respond_stateless(pjsua_var.endpt, rdata,  
    214228                                      PJSIP_SC_NOT_ACCEPTABLE_HERE, NULL,  
    215229                                      &hdr_list, NULL); 
     
    220234     * the UI takes too long to process the message.  
    221235     */ 
    222     status = pjsip_endpt_respond( pjsua.endpt, NULL, rdata, 200, NULL, 
     236    status = pjsip_endpt_respond( pjsua_var.endpt, NULL, rdata, 200, NULL, 
    223237                                  NULL, NULL, NULL); 
    224238 
     
    262276static void im_callback(void *token, pjsip_event *e) 
    263277{ 
    264     pj_str_t *text = token; 
     278    pjsua_im_data *im_data = token; 
    265279 
    266280    if (e->type == PJSIP_EVENT_TSX_STATE) { 
    267281 
    268282        pjsip_transaction *tsx = e->body.tsx_state.tsx; 
     283 
     284        /* Ignore provisional response, if any */ 
     285        if (tsx->status_code < 200) 
     286            return; 
     287 
     288 
     289        /* Handle authentication challenges */ 
     290        if (e->body.tsx_state.type == PJSIP_EVENT_RX_MSG && 
     291            (tsx->status_code == 401 || tsx->status_code == 407))  
     292        { 
     293            pjsip_rx_data *rdata = e->body.tsx_state.src.rdata; 
     294            pjsip_tx_data *tdata; 
     295            pjsip_auth_clt_sess auth; 
     296            pj_status_t status; 
     297 
     298            PJ_LOG(4,(THIS_FILE, "Resending IM with authentication")); 
     299 
     300            /* Create temporary authentication session */ 
     301            pjsip_auth_clt_init(&auth,pjsua_var.endpt,rdata->tp_info.pool, 0); 
     302     
     303            pjsip_auth_clt_set_credentials(&auth,  
     304                pjsua_var.acc[im_data->acc_id].cred_cnt, 
     305                pjsua_var.acc[im_data->acc_id].cred); 
     306 
     307            status = pjsip_auth_clt_reinit_req(&auth, rdata, tsx->last_tx, 
     308                                               &tdata); 
     309            if (status == PJ_SUCCESS) { 
     310                pjsua_im_data *im_data2; 
     311 
     312                /* Must duplicate im_data */ 
     313                im_data2 = pjsua_im_data_dup(tdata->pool, im_data); 
     314 
     315                /* Re-send request */ 
     316                status = pjsip_endpt_send_request( pjsua_var.endpt, tdata, -1, 
     317                                                   im_data2, &im_callback); 
     318                if (status == PJ_SUCCESS) { 
     319                    /* Done */ 
     320                    return; 
     321                } 
     322            } 
     323        } 
    269324 
    270325        if (tsx->status_code/100 == 2) { 
    271326            PJ_LOG(4,(THIS_FILE,  
    272327                      "Message \'%s\' delivered successfully", 
    273                       text->ptr)); 
     328                      im_data->body.ptr)); 
    274329        } else { 
    275330            PJ_LOG(3,(THIS_FILE,  
    276                       "Failed to deliver message \'%s\': %s [st_code=%d]", 
    277                       text->ptr, 
    278                       pjsip_get_status_text(tsx->status_code)->ptr, 
    279                       tsx->status_code)); 
     331                      "Failed to deliver message \'%s\': %d/%.*s", 
     332                      im_data->body.ptr, 
     333                      tsx->status_code, 
     334                      (int)tsx->status_text.slen, 
     335                      tsx->status_text.ptr)); 
    280336        } 
    281     } 
    282 } 
    283  
    284  
    285 /** 
    286  * Send IM outside dialog. 
    287  */ 
    288 PJ_DEF(pj_status_t) pjsua_im_send(int acc_index, const pj_str_t *dst_uri,  
    289                                   const pj_str_t *str) 
     337 
     338        if (pjsua_var.ua_cfg.cb.on_pager_status) 
     339            pjsua_var.ua_cfg.cb.on_pager_status(im_data->call_id,  
     340                                                &im_data->to, 
     341                                                &im_data->body, 
     342                                                im_data->user_data, 
     343                                                tsx->status_code, 
     344                                                &tsx->status_text); 
     345    } 
     346} 
     347 
     348 
     349/* Outgoing typing indication callback.  
     350 * (used to reauthenticate request) 
     351 */ 
     352static void typing_callback(void *token, pjsip_event *e) 
     353{ 
     354    pjsua_im_data *im_data = token; 
     355 
     356    if (e->type == PJSIP_EVENT_TSX_STATE) { 
     357 
     358        pjsip_transaction *tsx = e->body.tsx_state.tsx; 
     359 
     360        /* Ignore provisional response, if any */ 
     361        if (tsx->status_code < 200) 
     362            return; 
     363 
     364        /* Handle authentication challenges */ 
     365        if (e->body.tsx_state.type == PJSIP_EVENT_RX_MSG && 
     366            (tsx->status_code == 401 || tsx->status_code == 407))  
     367        { 
     368            pjsip_rx_data *rdata = e->body.tsx_state.src.rdata; 
     369            pjsip_tx_data *tdata; 
     370            pjsip_auth_clt_sess auth; 
     371            pj_status_t status; 
     372 
     373            PJ_LOG(4,(THIS_FILE, "Resending IM with authentication")); 
     374 
     375            /* Create temporary authentication session */ 
     376            pjsip_auth_clt_init(&auth,pjsua_var.endpt,rdata->tp_info.pool, 0); 
     377     
     378            pjsip_auth_clt_set_credentials(&auth,  
     379                pjsua_var.acc[im_data->acc_id].cred_cnt, 
     380                pjsua_var.acc[im_data->acc_id].cred); 
     381 
     382            status = pjsip_auth_clt_reinit_req(&auth, rdata, tsx->last_tx, 
     383                                               &tdata); 
     384            if (status == PJ_SUCCESS) { 
     385                pjsua_im_data *im_data2; 
     386 
     387                /* Must duplicate im_data */ 
     388                im_data2 = pjsua_im_data_dup(tdata->pool, im_data); 
     389 
     390                /* Re-send request */ 
     391                status = pjsip_endpt_send_request( pjsua_var.endpt, tdata, -1, 
     392                                                   im_data2, &typing_callback); 
     393                if (status == PJ_SUCCESS) { 
     394                    /* Done */ 
     395                    return; 
     396                } 
     397            } 
     398        } 
     399 
     400    } 
     401} 
     402 
     403 
     404/* 
     405 * Send instant messaging outside dialog, using the specified account for 
     406 * route set and authentication. 
     407 */ 
     408PJ_DEF(pj_status_t) pjsua_im_send( pjsua_acc_id acc_id,  
     409                                   const pj_str_t *to, 
     410                                   const pj_str_t *mime_type, 
     411                                   const pj_str_t *content, 
     412                                   const pjsua_msg_data *msg_data, 
     413                                   void *user_data) 
    290414{ 
    291415    pjsip_tx_data *tdata; 
     416    const pj_str_t mime_text_plain = pj_str("text/plain"); 
    292417    const pj_str_t STR_CONTACT = { "Contact", 7 }; 
    293     const pj_str_t mime_text = pj_str("text"); 
    294     const pj_str_t mime_plain = pj_str("plain"); 
    295     pj_str_t *text; 
     418    pjsip_media_type media_type; 
     419    pjsua_im_data *im_data; 
    296420    pj_status_t status; 
    297421 
     422    /* To and message body must be specified. */ 
     423    PJ_ASSERT_RETURN(to && content, PJ_EINVAL); 
     424 
    298425    /* Create request. */ 
    299     status = pjsip_endpt_create_request(pjsua.endpt, &pjsip_message_method, 
    300                                         dst_uri,  
    301                                         &pjsua.config.acc_config[acc_index].id, 
    302                                         dst_uri, NULL, NULL, -1, NULL, &tdata); 
     426    status = pjsip_endpt_create_request(pjsua_var.endpt,  
     427                                        &pjsip_message_method, to,  
     428                                        &pjsua_var.acc[acc_id].cfg.id, 
     429                                        to, NULL, NULL, -1, NULL, &tdata); 
    303430    if (status != PJ_SUCCESS) { 
    304431        pjsua_perror(THIS_FILE, "Unable to create request", status); 
     
    314441        pjsip_generic_string_hdr_create(tdata->pool,  
    315442                                        &STR_CONTACT, 
    316                                         &pjsua.config.acc_config[acc_index].contact)); 
    317  
    318     /* Duplicate text. 
    319      * We need to keep the text because we will display it when we fail to 
    320      * send the message. 
     443                                        &pjsua_var.acc[acc_id].cfg.contact)); 
     444 
     445    /* Create IM data to keep message details and give it back to 
     446     * application on the callback 
    321447     */ 
    322     text = pj_pool_alloc(tdata->pool, sizeof(pj_str_t)); 
    323     pj_strdup_with_null(tdata->pool, text, str); 
     448    im_data = pj_pool_zalloc(tdata->pool, sizeof(*im_data)); 
     449    im_data->acc_id = acc_id; 
     450    im_data->call_id = PJSUA_INVALID_ID; 
     451    pj_strdup_with_null(tdata->pool, &im_data->to, to); 
     452    pj_strdup_with_null(tdata->pool, &im_data->body, content); 
     453    im_data->user_data = user_data; 
     454 
     455 
     456    /* Set default media type if none is specified */ 
     457    if (mime_type == NULL) { 
     458        mime_type = &mime_text_plain; 
     459    } 
     460 
     461    /* Parse MIME type */ 
     462    pjsua_parse_media_type(tdata->pool, mime_type, &media_type); 
    324463 
    325464    /* Add message body */ 
    326     tdata->msg->body = pjsip_msg_body_create( tdata->pool, &mime_text, 
    327                                               &mime_plain, text); 
     465    tdata->msg->body = pjsip_msg_body_create( tdata->pool, &media_type.type, 
     466                                              &media_type.subtype,  
     467                                              &im_data->body); 
    328468    if (tdata->msg->body == NULL) { 
    329469        pjsua_perror(THIS_FILE, "Unable to create msg body", PJ_ENOMEM); 
     
    332472    } 
    333473 
     474    /* Add additional headers etc. */ 
     475    pjsua_process_msg_data(tdata, msg_data); 
     476 
     477    /* Add route set */ 
     478    pjsua_set_msg_route_set(tdata, &pjsua_var.acc[acc_id].route_set); 
     479 
    334480    /* Send request (statefully) */ 
    335     status = pjsip_endpt_send_request( pjsua.endpt, tdata, -1,  
    336                                        text, &im_callback); 
     481    status = pjsip_endpt_send_request( pjsua_var.endpt, tdata, -1,  
     482                                       im_data, &im_callback); 
    337483    if (status != PJ_SUCCESS) { 
    338484        pjsua_perror(THIS_FILE, "Unable to send request", status); 
     
    344490 
    345491 
    346 /** 
     492/* 
    347493 * Send typing indication outside dialog. 
    348494 */ 
    349 PJ_DEF(pj_status_t) pjsua_im_typing(int acc_index, const pj_str_t *dst_uri,  
    350                                     pj_bool_t is_typing) 
     495PJ_DEF(pj_status_t) pjsua_im_typing( pjsua_acc_id acc_id,  
     496                                     const pj_str_t *to,  
     497                                     pj_bool_t is_typing, 
     498                                     const pjsua_msg_data *msg_data) 
    351499{ 
    352500    const pj_str_t STR_CONTACT = { "Contact", 7 }; 
     501    pjsua_im_data *im_data; 
    353502    pjsip_tx_data *tdata; 
    354503    pj_status_t status; 
    355504 
    356505    /* Create request. */ 
    357     status = pjsip_endpt_create_request( pjsua.endpt, &pjsip_message_method, 
    358                                          dst_uri,  
    359                                          &pjsua.config.acc_config[acc_index].id, 
    360                                          dst_uri, NULL, NULL, -1, NULL, &tdata); 
     506    status = pjsip_endpt_create_request( pjsua_var.endpt, &pjsip_message_method, 
     507                                         to, &pjsua_var.acc[acc_id].cfg.id, 
     508                                         to, NULL, NULL, -1, NULL, &tdata); 
    361509    if (status != PJ_SUCCESS) { 
    362510        pjsua_perror(THIS_FILE, "Unable to create request", status); 
     
    374522        pjsip_generic_string_hdr_create(tdata->pool,  
    375523                                        &STR_CONTACT, 
    376                                         &pjsua.config.acc_config[acc_index].contact)); 
     524                                        &pjsua_var.acc[acc_id].cfg.contact)); 
    377525 
    378526 
     
    381529                                                      NULL, NULL, -1); 
    382530 
     531    /* Add additional headers etc. */ 
     532    pjsua_process_msg_data(tdata, msg_data); 
     533 
     534    /* Create data to reauthenticate */ 
     535    im_data = pj_pool_zalloc(tdata->pool, sizeof(*im_data)); 
     536    im_data->acc_id = acc_id; 
     537 
    383538    /* Send request (statefully) */ 
    384     status = pjsip_endpt_send_request( pjsua.endpt, tdata, -1,  
    385                                        NULL, NULL); 
     539    status = pjsip_endpt_send_request( pjsua_var.endpt, tdata, -1,  
     540                                       im_data, &typing_callback); 
    386541    if (status != PJ_SUCCESS) { 
    387542        pjsua_perror(THIS_FILE, "Unable to send request", status); 
     
    402557 
    403558    /* Register module */ 
    404     status = pjsip_endpt_register_module(pjsua.endpt, &mod_pjsua_im); 
     559    status = pjsip_endpt_register_module(pjsua_var.endpt, &mod_pjsua_im); 
    405560    if (status != PJ_SUCCESS) 
    406561        return status; 
    407562 
    408563    /* Register support for MESSAGE method. */ 
    409     pjsip_endpt_add_capability( pjsua.endpt, &mod_pjsua_im, PJSIP_H_ALLOW, 
     564    pjsip_endpt_add_capability( pjsua_var.endpt, &mod_pjsua_im, PJSIP_H_ALLOW, 
    410565                                NULL, 1, &msg_tag); 
    411566 
  • pjproject/trunk/pjsip/src/pjsua-lib/pjsua_pres.c

    r492 r503  
    1818 */ 
    1919#include <pjsua-lib/pjsua.h> 
    20 #include "pjsua_imp.h" 
    21  
    22 /* 
    23  * pjsua_pres.c 
    24  * 
    25  * Presence related stuffs. 
    26  */ 
     20#include <pjsua-lib/pjsua_internal.h> 
     21 
    2722 
    2823#define THIS_FILE   "pjsua_pres.c" 
    2924 
    3025 
    31  
    32 /* ************************************************************************** 
    33  * THE FOLLOWING PART HANDLES SERVER SUBSCRIPTION 
    34  * ************************************************************************** 
     26/* 
     27 * Get total number of buddies. 
     28 */ 
     29PJ_DEF(unsigned) pjsua_get_buddy_count(void) 
     30{ 
     31    return pjsua_var.buddy_cnt; 
     32} 
     33 
     34 
     35/* 
     36 * Check if buddy ID is valid. 
     37 */ 
     38PJ_DEF(pj_bool_t) pjsua_buddy_is_valid(pjsua_buddy_id buddy_id) 
     39{ 
     40    return buddy_id>=0 && buddy_id<PJ_ARRAY_SIZE(pjsua_var.buddy) && 
     41           pjsua_var.buddy[buddy_id].uri.slen != 0; 
     42} 
     43 
     44 
     45/* 
     46 * Enum buddy IDs. 
     47 */ 
     48PJ_DEF(pj_status_t) pjsua_enum_buddies( pjsua_buddy_id ids[], 
     49                                        unsigned *count) 
     50{ 
     51    unsigned i, c; 
     52 
     53    PJ_ASSERT_RETURN(ids && count, PJ_EINVAL); 
     54 
     55    PJSUA_LOCK(); 
     56 
     57    for (i=0, c=0; c<*count && i<PJ_ARRAY_SIZE(pjsua_var.buddy); ++i) { 
     58        if (!pjsua_var.buddy[i].uri.slen) 
     59            continue; 
     60        ids[c] = i; 
     61        ++c; 
     62    } 
     63 
     64    *count = c; 
     65 
     66    PJSUA_UNLOCK(); 
     67 
     68    return PJ_SUCCESS; 
     69 
     70} 
     71 
     72 
     73/* 
     74 * Get detailed buddy info. 
     75 */ 
     76PJ_DEF(pj_status_t) pjsua_buddy_get_info( pjsua_buddy_id buddy_id, 
     77                                          pjsua_buddy_info *info) 
     78{ 
     79    int total=0; 
     80    pjsua_buddy *buddy; 
     81 
     82    PJ_ASSERT_RETURN(buddy_id>=0 &&  
     83                       buddy_id<(int)PJ_ARRAY_SIZE(pjsua_var.buddy),  
     84                     PJ_EINVAL); 
     85 
     86    PJSUA_LOCK(); 
     87 
     88    pj_memset(info, 0, sizeof(pjsua_buddy_info)); 
     89 
     90    buddy = &pjsua_var.buddy[buddy_id]; 
     91    info->id = buddy->index; 
     92    if (pjsua_var.buddy[buddy_id].uri.slen == 0) { 
     93        PJSUA_UNLOCK(); 
     94        return PJ_SUCCESS; 
     95    } 
     96 
     97    /* uri */ 
     98    info->uri.ptr = info->buf_ + total; 
     99    pj_strncpy(&info->uri, &buddy->uri, sizeof(info->buf_)-total); 
     100    total += info->uri.slen; 
     101 
     102    /* contact */ 
     103    info->contact.ptr = info->buf_ + total; 
     104    pj_strncpy(&info->contact, &buddy->contact, sizeof(info->buf_)-total); 
     105    total += info->contact.slen; 
     106         
     107    /* status and status text */     
     108    if (buddy->sub == NULL || buddy->status.info_cnt==0) { 
     109        info->status = PJSUA_BUDDY_STATUS_UNKNOWN; 
     110        info->status_text = pj_str("?"); 
     111    } else if (pjsua_var.buddy[buddy_id].status.info[0].basic_open) { 
     112        info->status = PJSUA_BUDDY_STATUS_ONLINE; 
     113        info->status_text = pj_str("Online"); 
     114    } else { 
     115        info->status = PJSUA_BUDDY_STATUS_OFFLINE; 
     116        info->status_text = pj_str("Offline"); 
     117    } 
     118 
     119    /* monitor pres */ 
     120    info->monitor_pres = buddy->monitor; 
     121 
     122    PJSUA_UNLOCK(); 
     123    return PJ_SUCCESS; 
     124} 
     125 
     126 
     127/* 
     128 * Reset buddy descriptor. 
     129 */ 
     130static void reset_buddy(pjsua_buddy_id id) 
     131{ 
     132    pj_memset(&pjsua_var.buddy[id], 0, sizeof(pjsua_var.buddy[id])); 
     133    pjsua_var.buddy[id].index = id; 
     134} 
     135 
     136 
     137/* 
     138 * Add new buddy. 
     139 */ 
     140PJ_DEF(pj_status_t) pjsua_buddy_add( const pjsua_buddy_config *cfg, 
     141                                     pjsua_buddy_id *p_buddy_id) 
     142{ 
     143    pjsip_name_addr *url; 
     144    pjsip_sip_uri *sip_uri; 
     145    int index; 
     146    pj_str_t tmp; 
     147 
     148    PJ_ASSERT_RETURN(pjsua_var.buddy_cnt <=  
     149                        PJ_ARRAY_SIZE(pjsua_var.buddy), 
     150                     PJ_ETOOMANY); 
     151 
     152    PJSUA_LOCK(); 
     153 
     154    /* Find empty slot */ 
     155    for (index=0; index<PJ_ARRAY_SIZE(pjsua_var.buddy); ++index) { 
     156        if (pjsua_var.buddy[index].uri.slen == 0) 
     157            break; 
     158    } 
     159 
     160    /* Expect to find an empty slot */ 
     161    if (index == PJ_ARRAY_SIZE(pjsua_var.buddy)) { 
     162        PJSUA_UNLOCK(); 
     163        /* This shouldn't happen */ 
     164        pj_assert(!"index < PJ_ARRAY_SIZE(pjsua_var.buddy)"); 
     165        return PJ_ETOOMANY; 
     166    } 
     167 
     168 
     169    /* Get name and display name for buddy */ 
     170    pj_strdup_with_null(pjsua_var.pool, &tmp, &cfg->uri); 
     171    url = (pjsip_name_addr*)pjsip_parse_uri(pjsua_var.pool, tmp.ptr, tmp.slen, 
     172                                            PJSIP_PARSE_URI_AS_NAMEADDR); 
     173 
     174    if (url == NULL) { 
     175        pjsua_perror(THIS_FILE, "Unable to add buddy", PJSIP_EINVALIDURI); 
     176        PJSUA_UNLOCK(); 
     177        return PJSIP_EINVALIDURI; 
     178    } 
     179 
     180    /* Reset buddy, to make sure everything is cleared with default 
     181     * values 
     182     */ 
     183    reset_buddy(index); 
     184 
     185    /* Save URI */ 
     186    pjsua_var.buddy[index].uri = tmp; 
     187 
     188    sip_uri = (pjsip_sip_uri*) url->uri; 
     189    pjsua_var.buddy[index].name = sip_uri->user; 
     190    pjsua_var.buddy[index].display = url->display; 
     191    pjsua_var.buddy[index].host = sip_uri->host; 
     192    pjsua_var.buddy[index].port = sip_uri->port; 
     193    pjsua_var.buddy[index].monitor = cfg->subscribe; 
     194    if (pjsua_var.buddy[index].port == 0) 
     195        pjsua_var.buddy[index].port = 5060; 
     196 
     197    if (p_buddy_id) 
     198        *p_buddy_id = index; 
     199 
     200    pjsua_var.buddy_cnt++; 
     201 
     202    pjsua_buddy_subscribe_pres(index, cfg->subscribe); 
     203 
     204    PJSUA_UNLOCK(); 
     205 
     206    return PJ_SUCCESS; 
     207} 
     208 
     209 
     210/* 
     211 * Delete buddy. 
     212 */ 
     213PJ_DEF(pj_status_t) pjsua_buddy_del(pjsua_buddy_id buddy_id) 
     214{ 
     215    PJ_ASSERT_RETURN(buddy_id>=0 &&  
     216                        buddy_id<(int)PJ_ARRAY_SIZE(pjsua_var.buddy), 
     217                     PJ_EINVAL); 
     218 
     219    PJSUA_LOCK(); 
     220 
     221    if (pjsua_var.buddy[buddy_id].uri.slen == 0) { 
     222        PJSUA_UNLOCK(); 
     223        return PJ_SUCCESS; 
     224    } 
     225 
     226    /* Unsubscribe presence */ 
     227    pjsua_buddy_subscribe_pres(buddy_id, PJ_FALSE); 
     228 
     229    /* Remove buddy */ 
     230    pjsua_var.buddy[buddy_id].uri.slen = 0; 
     231    pjsua_var.buddy_cnt--; 
     232 
     233    /* Reset buddy struct */ 
     234    reset_buddy(buddy_id); 
     235 
     236    PJSUA_UNLOCK(); 
     237    return PJ_SUCCESS; 
     238} 
     239 
     240 
     241/* 
     242 * Enable/disable buddy's presence monitoring. 
     243 */ 
     244PJ_DEF(pj_status_t) pjsua_buddy_subscribe_pres( pjsua_buddy_id buddy_id, 
     245                                                pj_bool_t subscribe) 
     246{ 
     247    pjsua_buddy *buddy; 
     248 
     249    PJ_ASSERT_RETURN(buddy_id>=0 &&  
     250                        buddy_id<(int)PJ_ARRAY_SIZE(pjsua_var.buddy), 
     251                     PJ_EINVAL); 
     252 
     253    PJSUA_LOCK(); 
     254 
     255    buddy = &pjsua_var.buddy[buddy_id]; 
     256    buddy->monitor = subscribe; 
     257    pjsua_pres_refresh(); 
     258 
     259    PJSUA_UNLOCK(); 
     260 
     261    return PJ_SUCCESS; 
     262} 
     263 
     264 
     265/* 
     266 * Dump presence subscriptions to log file. 
     267 */ 
     268PJ_DEF(void) pjsua_pres_dump(pj_bool_t verbose) 
     269{ 
     270    unsigned acc_id; 
     271    unsigned i; 
     272 
     273     
     274    PJSUA_LOCK(); 
     275 
     276    /* 
     277     * When no detail is required, just dump number of server and client 
     278     * subscriptions. 
     279     */ 
     280    if (verbose == PJ_FALSE) { 
     281         
     282        int count = 0; 
     283 
     284        for (acc_id=0; acc_id<PJ_ARRAY_SIZE(pjsua_var.acc); ++acc_id) { 
     285 
     286            if (!pjsua_var.acc[acc_id].valid) 
     287                continue; 
     288 
     289            if (!pj_list_empty(&pjsua_var.acc[acc_id].pres_srv_list)) { 
     290                struct pjsua_srv_pres *uapres; 
     291 
     292                uapres = pjsua_var.acc[acc_id].pres_srv_list.next; 
     293                while (uapres != &pjsua_var.acc[acc_id].pres_srv_list) { 
     294                    ++count; 
     295                    uapres = uapres->next; 
     296                } 
     297            } 
     298        } 
     299 
     300        PJ_LOG(3,(THIS_FILE, "Number of server/UAS subscriptions: %d",  
     301                  count)); 
     302 
     303        count = 0; 
     304 
     305        for (i=0; i<PJ_ARRAY_SIZE(pjsua_var.buddy); ++i) { 
     306            if (pjsua_var.buddy[i].uri.slen == 0) 
     307                continue; 
     308            if (pjsua_var.buddy[i].sub) { 
     309                ++count; 
     310            } 
     311        } 
     312 
     313        PJ_LOG(3,(THIS_FILE, "Number of client/UAC subscriptions: %d",  
     314                  count)); 
     315        PJSUA_UNLOCK(); 
     316        return; 
     317    } 
     318     
     319 
     320    /* 
     321     * Dumping all server (UAS) subscriptions 
     322     */ 
     323    PJ_LOG(3,(THIS_FILE, "Dumping pjsua server subscriptions:")); 
     324 
     325    for (acc_id=0; acc_id<(int)PJ_ARRAY_SIZE(pjsua_var.acc); ++acc_id) { 
     326 
     327        if (!pjsua_var.acc[acc_id].valid) 
     328            continue; 
     329 
     330        PJ_LOG(3,(THIS_FILE, "  %.*s", 
     331                  (int)pjsua_var.acc[acc_id].cfg.id.slen, 
     332                  pjsua_var.acc[acc_id].cfg.id.ptr)); 
     333 
     334        if (pj_list_empty(&pjsua_var.acc[acc_id].pres_srv_list)) { 
     335 
     336            PJ_LOG(3,(THIS_FILE, "  - none - ")); 
     337 
     338        } else { 
     339            struct pjsua_srv_pres *uapres; 
     340 
     341            uapres = pjsua_var.acc[acc_id].pres_srv_list.next; 
     342            while (uapres != &pjsua_var.acc[acc_id].pres_srv_list) { 
     343             
     344                PJ_LOG(3,(THIS_FILE, "    %10s %s", 
     345                          pjsip_evsub_get_state_name(uapres->sub), 
     346                          uapres->remote)); 
     347 
     348                uapres = uapres->next; 
     349            } 
     350        } 
     351    } 
     352 
     353    /* 
     354     * Dumping all client (UAC) subscriptions 
     355     */ 
     356    PJ_LOG(3,(THIS_FILE, "Dumping pjsua client subscriptions:")); 
     357 
     358    if (pjsua_var.buddy_cnt == 0) { 
     359 
     360        PJ_LOG(3,(THIS_FILE, "  - no buddy list - ")); 
     361 
     362    } else { 
     363        for (i=0; i<PJ_ARRAY_SIZE(pjsua_var.buddy); ++i) { 
     364 
     365            if (pjsua_var.buddy[i].uri.slen == 0) 
     366                continue; 
     367 
     368            if (pjsua_var.buddy[i].sub) { 
     369                PJ_LOG(3,(THIS_FILE, "  %10s %.*s", 
     370                          pjsip_evsub_get_state_name(pjsua_var.buddy[i].sub), 
     371                          (int)pjsua_var.buddy[i].uri.slen, 
     372                          pjsua_var.buddy[i].uri.ptr)); 
     373            } else { 
     374                PJ_LOG(3,(THIS_FILE, "  %10s %.*s", 
     375                          "(null)", 
     376                          (int)pjsua_var.buddy[i].uri.slen, 
     377                          pjsua_var.buddy[i].uri.ptr)); 
     378            } 
     379        } 
     380    } 
     381 
     382    PJSUA_UNLOCK(); 
     383} 
     384 
     385 
     386/*************************************************************************** 
     387 * Server subscription. 
    35388 */ 
    36389 
     
    61414static void pres_evsub_on_srv_state( pjsip_evsub *sub, pjsip_event *event) 
    62415{ 
    63     pjsua_srv_pres *uapres = pjsip_evsub_get_mod_data(sub, pjsua.mod.id); 
     416    pjsua_srv_pres *uapres; 
    64417 
    65418    PJ_UNUSED_ARG(event); 
    66419 
     420    PJSUA_LOCK(); 
     421 
     422    uapres = pjsip_evsub_get_mod_data(sub, pjsua_var.mod.id); 
    67423    if (uapres) { 
    68424        PJ_LOG(3,(THIS_FILE, "Server subscription to %s is %s", 
     
    70426 
    71427        if (pjsip_evsub_get_state(sub) == PJSIP_EVSUB_STATE_TERMINATED) { 
    72             pjsip_evsub_set_mod_data(sub, pjsua.mod.id, NULL); 
     428            pjsip_evsub_set_mod_data(sub, pjsua_var.mod.id, NULL); 
    73429            pj_list_erase(uapres); 
    74430        } 
    75431    } 
     432 
     433    PJSUA_UNLOCK(); 
    76434} 
    77435 
     
    81439static pj_bool_t pres_on_rx_request(pjsip_rx_data *rdata) 
    82440{ 
    83     int acc_index; 
     441    int acc_id; 
    84442    pjsua_acc_config *acc_config; 
    85443    pjsip_method *req_method = &rdata->msg_info.msg->line.req.method; 
     
    97455    /* Incoming SUBSCRIBE: */ 
    98456 
     457    PJSUA_LOCK(); 
     458 
    99459    /* Find which account for the incoming request. */ 
    100     acc_index = pjsua_acc_find_for_incoming(rdata); 
    101     acc_config = &pjsua.config.acc_config[acc_index]; 
     460    acc_id = pjsua_acc_find_for_incoming(rdata); 
     461    acc_config = &pjsua_var.acc[acc_id].cfg; 
    102462 
    103463    /* Create UAS dialog: */ 
     
    109469                     "Unable to create UAS dialog for subscription",  
    110470                     status); 
    111         return PJ_FALSE; 
     471        PJSUA_UNLOCK(); 
     472        return PJ_TRUE; 
    112473    } 
    113474 
     
    122483        pjsua_perror(THIS_FILE, "Unable to create server subscription",  
    123484                     status); 
    124         return PJ_FALSE; 
     485        PJSUA_UNLOCK(); 
     486        return PJ_TRUE; 
    125487    } 
    126488 
     
    136498        uapres->remote[status] = '\0'; 
    137499 
    138     pjsip_evsub_set_mod_data(sub, pjsua.mod.id, uapres); 
     500    pjsip_evsub_set_mod_data(sub, pjsua_var.mod.id, uapres); 
    139501 
    140502    /* Add server subscription to the list: */ 
    141     pj_list_push_back(&pjsua.acc[acc_index].pres_srv_list, uapres); 
     503    pj_list_push_back(&pjsua_var.acc[acc_id].pres_srv_list, uapres); 
    142504 
    143505 
     
    149511        pj_list_erase(uapres); 
    150512        pjsip_pres_terminate(sub, PJ_FALSE); 
     513        PJSUA_UNLOCK(); 
    151514        return PJ_FALSE; 
    152515    } 
     
    156519    pj_memset(&pres_status, 0, sizeof(pres_status)); 
    157520    pres_status.info_cnt = 1; 
    158     pres_status.info[0].basic_open = pjsua.acc[acc_index].online_status; 
    159     //Both pjsua.local_uri and pjsua.contact_uri are enclosed in "<" and ">" 
     521    pres_status.info[0].basic_open = pjsua_var.acc[acc_id].online_status; 
     522    //Both pjsua_var.local_uri and pjsua_var.contact_uri are enclosed in "<" and ">" 
    160523    //causing XML parsing to fail. 
    161     //pres_status.info[0].contact = pjsua.local_uri; 
     524    //pres_status.info[0].contact = pjsua_var.local_uri; 
    162525 
    163526    pjsip_pres_set_status(sub, &pres_status); 
     
    174537        pj_list_erase(uapres); 
    175538        pjsip_pres_terminate(sub, PJ_FALSE); 
     539        PJSUA_UNLOCK(); 
    176540        return PJ_FALSE; 
    177541    } 
     
    180544    /* Done: */ 
    181545 
     546    PJSUA_UNLOCK(); 
     547 
    182548    return PJ_TRUE; 
    183549} 
    184550 
    185551 
     552/* Terminate server subscription for the account */ 
     553void pjsua_pres_delete_acc(int acc_id) 
     554{ 
     555    pjsua_srv_pres *uapres; 
     556 
     557    uapres = pjsua_var.acc[acc_id].pres_srv_list.next; 
     558 
     559    while (uapres != &pjsua_var.acc[acc_id].pres_srv_list) { 
     560         
     561        pjsip_pres_status pres_status; 
     562        pj_str_t reason = { "noresource", 10 }; 
     563        pjsip_tx_data *tdata; 
     564 
     565        pjsip_pres_get_status(uapres->sub, &pres_status); 
     566         
     567        pres_status.info[0].basic_open = pjsua_var.acc[acc_id].online_status; 
     568        pjsip_pres_set_status(uapres->sub, &pres_status); 
     569 
     570        if (pjsip_pres_notify(uapres->sub,  
     571                              PJSIP_EVSUB_STATE_TERMINATED, NULL, 
     572                              &reason, &tdata)==PJ_SUCCESS) 
     573        { 
     574            pjsip_pres_send_request(uapres->sub, tdata); 
     575        } 
     576 
     577        uapres = uapres->next; 
     578    } 
     579} 
     580 
     581 
    186582/* Refresh subscription (e.g. when our online status has changed) */ 
    187 static void refresh_server_subscription(int acc_index) 
     583static void refresh_server_subscription(int acc_id) 
    188584{ 
    189585    pjsua_srv_pres *uapres; 
    190586 
    191     uapres = pjsua.acc[acc_index].pres_srv_list.next; 
    192  
    193     while (uapres != &pjsua.acc[acc_index].pres_srv_list) { 
     587    uapres = pjsua_var.acc[acc_id].pres_srv_list.next; 
     588 
     589    while (uapres != &pjsua_var.acc[acc_id].pres_srv_list) { 
    194590         
    195591        pjsip_pres_status pres_status; 
     
    197593 
    198594        pjsip_pres_get_status(uapres->sub, &pres_status); 
    199         if (pres_status.info[0].basic_open != pjsua.acc[acc_index].online_status) { 
    200             pres_status.info[0].basic_open = pjsua.acc[acc_index].online_status; 
     595        if (pres_status.info[0].basic_open != pjsua_var.acc[acc_id].online_status) { 
     596            pres_status.info[0].basic_open = pjsua_var.acc[acc_id].online_status; 
    201597            pjsip_pres_set_status(uapres->sub, &pres_status); 
    202598 
    203             if (pjsua.quit_flag) { 
    204                 pj_str_t reason = { "noresource", 10 }; 
    205                 if (pjsip_pres_notify(uapres->sub,  
    206                                       PJSIP_EVSUB_STATE_TERMINATED, NULL, 
    207                                       &reason, &tdata)==PJ_SUCCESS) 
    208                 { 
    209                     pjsip_pres_send_request(uapres->sub, tdata); 
    210                 } 
    211             } else { 
    212                 if (pjsip_pres_current_notify(uapres->sub, &tdata)==PJ_SUCCESS) 
    213                     pjsip_pres_send_request(uapres->sub, tdata); 
    214             } 
     599            if (pjsip_pres_current_notify(uapres->sub, &tdata)==PJ_SUCCESS) 
     600                pjsip_pres_send_request(uapres->sub, tdata); 
    215601        } 
    216602 
     
    221607 
    222608 
    223 /* ************************************************************************** 
    224  * THE FOLLOWING PART HANDLES CLIENT SUBSCRIPTION 
    225  * ************************************************************************** 
     609/*************************************************************************** 
     610 * Client subscription. 
    226611 */ 
    227612 
     
    233618    PJ_UNUSED_ARG(event); 
    234619 
    235     buddy = pjsip_evsub_get_mod_data(sub, pjsua.mod.id); 
     620    PJSUA_LOCK(); 
     621 
     622    buddy = pjsip_evsub_get_mod_data(sub, pjsua_var.mod.id); 
    236623    if (buddy) { 
    237624        PJ_LOG(3,(THIS_FILE,  
    238625                  "Presence subscription to %.*s is %s", 
    239                   (int)pjsua.config.buddy_uri[buddy->index].slen, 
    240                   pjsua.config.buddy_uri[buddy->index].ptr,  
     626                  (int)pjsua_var.buddy[buddy->index].uri.slen, 
     627                  pjsua_var.buddy[buddy->index].uri.ptr,  
    241628                  pjsip_evsub_get_state_name(sub))); 
    242629 
     
    244631            buddy->sub = NULL; 
    245632            buddy->status.info_cnt = 0; 
    246             pjsip_evsub_set_mod_data(sub, pjsua.mod.id, NULL); 
     633            pjsip_evsub_set_mod_data(sub, pjsua_var.mod.id, NULL); 
    247634        } 
    248635 
    249636        /* Call callback */ 
    250         if (pjsua.cb.on_buddy_state) 
    251             (*pjsua.cb.on_buddy_state)(buddy->index); 
    252     } 
    253 } 
     637        if (pjsua_var.ua_cfg.cb.on_buddy_state) 
     638            (*pjsua_var.ua_cfg.cb.on_buddy_state)(buddy->index); 
     639    } 
     640 
     641    PJSUA_UNLOCK(); 
     642} 
     643 
     644 
     645/* Callback when transaction state has changed. */ 
     646static void pjsua_evsub_on_tsx_state(pjsip_evsub *sub,  
     647                                     pjsip_transaction *tsx, 
     648                                     pjsip_event *event) 
     649{ 
     650    pjsua_buddy *buddy; 
     651    pjsip_contact_hdr *contact_hdr; 
     652 
     653    PJSUA_LOCK(); 
     654 
     655    buddy = pjsip_evsub_get_mod_data(sub, pjsua_var.mod.id); 
     656    if (!buddy) { 
     657        PJSUA_UNLOCK(); 
     658        return; 
     659    } 
     660 
     661    /* We only use this to update buddy's Contact, when it's not 
     662     * set. 
     663     */ 
     664    if (buddy->contact.slen != 0) { 
     665        /* Contact already set */ 
     666        PJSUA_UNLOCK(); 
     667        return; 
     668    } 
     669     
     670    /* Only care about 2xx response to outgoing SUBSCRIBE */ 
     671    if (tsx->status_code/100 != 2 || 
     672        tsx->role != PJSIP_UAC_ROLE || 
     673        event->type != PJSIP_EVENT_RX_MSG ||  
     674        pjsip_method_cmp(&tsx->method, &pjsip_subscribe_method)!=0) 
     675    { 
     676        PJSUA_UNLOCK(); 
     677        return; 
     678    } 
     679 
     680    /* Find contact header. */ 
     681    contact_hdr = pjsip_msg_find_hdr(event->body.rx_msg.rdata->msg_info.msg, 
     682                                     PJSIP_H_CONTACT, NULL); 
     683    if (!contact_hdr) { 
     684        PJSUA_UNLOCK(); 
     685        return; 
     686    } 
     687 
     688    buddy->contact.ptr = pj_pool_alloc(pjsua_var.pool, PJSIP_MAX_URL_SIZE); 
     689    buddy->contact.slen = pjsip_uri_print( PJSIP_URI_IN_CONTACT_HDR, 
     690                                           contact_hdr->uri, 
     691                                           buddy->contact.ptr,  
     692                                           PJSIP_MAX_URL_SIZE); 
     693    if (buddy->contact.slen < 0) 
     694        buddy->contact.slen = 0; 
     695 
     696    PJSUA_UNLOCK(); 
     697} 
     698 
    254699 
    255700/* Callback called when we receive NOTIFY */ 
     
    263708    pjsua_buddy *buddy; 
    264709 
    265     buddy = pjsip_evsub_get_mod_data(sub, pjsua.mod.id); 
     710    PJSUA_LOCK(); 
     711 
     712    buddy = pjsip_evsub_get_mod_data(sub, pjsua_var.mod.id); 
    266713    if (buddy) { 
    267714        /* Update our info. */ 
     
    277724    PJ_UNUSED_ARG(res_hdr); 
    278725    PJ_UNUSED_ARG(p_body); 
     726 
     727    PJSUA_UNLOCK(); 
    279728} 
    280729 
     
    284733{ 
    285734    &pjsua_evsub_on_state,   
    286  
    287     NULL,   /* on_tsx_state: don't care about transaction state. */ 
     735    &pjsua_evsub_on_tsx_state, 
    288736 
    289737    NULL,   /* on_rx_refresh: don't care about SUBSCRIBE refresh, unless  
     
    305753static void subscribe_buddy_presence(unsigned index) 
    306754{ 
    307     int acc_index; 
    308     pjsua_acc_config *acc_config; 
     755    pjsua_buddy *buddy; 
     756    int acc_id; 
     757    pjsua_acc *acc; 
    309758    pjsip_dialog *dlg; 
    310759    pjsip_tx_data *tdata; 
    311760    pj_status_t status; 
    312761 
    313     acc_index = pjsua_acc_find_for_outgoing(&pjsua.config.buddy_uri[index]); 
    314  
    315     acc_config = &pjsua.config.acc_config[acc_index]; 
    316  
     762    buddy = &pjsua_var.buddy[index]; 
     763    acc_id = pjsua_acc_find_for_outgoing(&buddy->uri); 
     764 
     765    acc = &pjsua_var.acc[acc_id]; 
     766 
     767    /* Create UAC dialog */ 
    317768    status = pjsip_dlg_create_uac( pjsip_ua_instance(),  
    318                                    &acc_config->id, 
    319                                    &acc_config->contact, 
    320                                    &pjsua.config.buddy_uri[index], 
     769                                   &acc->cfg.id, 
     770                                   &acc->cfg.contact, 
     771                                   &buddy->uri, 
    321772                                   NULL, &dlg); 
    322773    if (status != PJ_SUCCESS) { 
     
    326777    } 
    327778 
    328     if (acc_config->cred_count) { 
     779    /* Set route-set */ 
     780    if (!pj_list_empty(&acc->route_set)) { 
     781        pjsip_dlg_set_route_set(dlg, &acc->route_set); 
     782    } 
     783 
     784    /* Set credentials */ 
     785    if (acc->cred_cnt) { 
    329786        pjsip_auth_clt_set_credentials( &dlg->auth_sess,  
    330                                         acc_config->cred_count, 
    331                                         acc_config->cred_info); 
     787                                        acc->cred_cnt, acc->cred); 
    332788    } 
    333789 
    334790    status = pjsip_pres_create_uac( dlg, &pres_callback,  
    335                                     &pjsua.buddies[index].sub); 
     791                                    &buddy->sub); 
    336792    if (status != PJ_SUCCESS) { 
    337         pjsua.buddies[index].sub = NULL; 
     793        pjsua_var.buddy[index].sub = NULL; 
    338794        pjsua_perror(THIS_FILE, "Unable to create presence client",  
    339795                     status); 
     
    342798    } 
    343799 
    344     pjsip_evsub_set_mod_data(pjsua.buddies[index].sub, pjsua.mod.id, 
    345                              &pjsua.buddies[index]); 
    346  
    347     status = pjsip_pres_initiate(pjsua.buddies[index].sub, -1, &tdata); 
     800    pjsip_evsub_set_mod_data(buddy->sub, pjsua_var.mod.id, buddy); 
     801 
     802    status = pjsip_pres_initiate(buddy->sub, -1, &tdata); 
    348803    if (status != PJ_SUCCESS) { 
    349         pjsip_pres_terminate(pjsua.buddies[index].sub, PJ_FALSE); 
    350         pjsua.buddies[index].sub = NULL; 
     804        pjsip_pres_terminate(buddy->sub, PJ_FALSE); 
     805        buddy->sub = NULL; 
    351806        pjsua_perror(THIS_FILE, "Unable to create initial SUBSCRIBE",  
    352807                     status); 
     
    354809    } 
    355810 
    356     status = pjsip_pres_send_request(pjsua.buddies[index].sub, tdata); 
     811    status = pjsip_pres_send_request(buddy->sub, tdata); 
    357812    if (status != PJ_SUCCESS) { 
    358         pjsip_pres_terminate(pjsua.buddies[index].sub, PJ_FALSE); 
    359         pjsua.buddies[index].sub = NULL; 
     813        pjsip_pres_terminate(buddy->sub, PJ_FALSE); 
     814        buddy->sub = NULL; 
    360815        pjsua_perror(THIS_FILE, "Unable to send initial SUBSCRIBE",  
    361816                     status); 
     
    368823static void unsubscribe_buddy_presence(unsigned index) 
    369824{ 
     825    pjsua_buddy *buddy; 
    370826    pjsip_tx_data *tdata; 
    371827    pj_status_t status; 
    372828 
    373     if (pjsua.buddies[index].sub == NULL) 
    374         return; 
    375  
    376     if (pjsip_evsub_get_state(pjsua.buddies[index].sub) ==  
    377         PJSIP_EVSUB_STATE_TERMINATED) 
    378     { 
    379         pjsua.buddies[index].sub = NULL; 
    380         return; 
    381     } 
    382  
    383     status = pjsip_pres_initiate( pjsua.buddies[index].sub, 0, &tdata); 
     829    buddy = &pjsua_var.buddy[index]; 
     830 
     831    if (buddy->sub == NULL) 
     832        return; 
     833 
     834    if (pjsip_evsub_get_state(buddy->sub) == PJSIP_EVSUB_STATE_TERMINATED) { 
     835        pjsua_var.buddy[index].sub = NULL; 
     836        return; 
     837    } 
     838 
     839    status = pjsip_pres_initiate( buddy->sub, 0, &tdata); 
    384840    if (status == PJ_SUCCESS) 
    385         status = pjsip_pres_send_request( pjsua.buddies[index].sub, tdata ); 
     841        status = pjsip_pres_send_request( buddy->sub, tdata ); 
    386842 
    387843    if (status != PJ_SUCCESS) { 
    388  
    389         pjsip_pres_terminate(pjsua.buddies[index].sub, PJ_FALSE); 
    390         pjsua.buddies[index].sub = NULL; 
     844        pjsip_pres_terminate(buddy->sub, PJ_FALSE); 
     845        buddy->sub = NULL; 
    391846        pjsua_perror(THIS_FILE, "Unable to unsubscribe presence",  
    392847                     status); 
     
    396851 
    397852/* It does what it says.. */ 
    398 static void refresh_client_subscription(void) 
     853static void refresh_client_subscriptions(void) 
    399854{ 
    400855    unsigned i; 
    401856 
    402     for (i=0; i<pjsua.config.buddy_cnt; ++i) { 
    403  
    404         if (pjsua.buddies[i].monitor && !pjsua.buddies[i].sub) { 
     857    for (i=0; i<PJ_ARRAY_SIZE(pjsua_var.buddy); ++i) { 
     858 
     859        if (!pjsua_var.buddy[i].uri.slen) 
     860            continue; 
     861 
     862        if (pjsua_var.buddy[i].monitor && !pjsua_var.buddy[i].sub) { 
    405863            subscribe_buddy_presence(i); 
    406864 
    407         } else if (!pjsua.buddies[i].monitor && pjsua.buddies[i].sub) { 
     865        } else if (!pjsua_var.buddy[i].monitor && pjsua_var.buddy[i].sub) { 
    408866            unsubscribe_buddy_presence(i); 
    409867 
     
    418876pj_status_t pjsua_pres_init() 
    419877{ 
     878    unsigned i; 
    420879    pj_status_t status; 
    421880 
    422     status = pjsip_endpt_register_module( pjsua.endpt, &mod_pjsua_pres); 
     881    status = pjsip_endpt_register_module( pjsua_var.endpt, &mod_pjsua_pres); 
    423882    if (status != PJ_SUCCESS) { 
    424883        pjsua_perror(THIS_FILE, "Unable to register pjsua presence module",  
     
    426885    } 
    427886 
     887    for (i=0; i<PJ_ARRAY_SIZE(pjsua_var.buddy); ++i) { 
     888        reset_buddy(i); 
     889    } 
     890 
    428891    return status; 
    429892} 
    430893 
    431 /* 
    432  * Get buddy count. 
    433  */ 
    434 PJ_DEF(unsigned) pjsua_get_buddy_count(void) 
    435 { 
    436     return pjsua.config.buddy_cnt; 
    437 } 
    438  
    439  
    440 /** 
    441  * Get buddy info. 
    442  */ 
    443 PJ_DEF(pj_status_t) pjsua_buddy_get_info(pjsua_buddy_id index, 
    444                                          pjsua_buddy_info *info) 
    445 { 
    446     pjsua_buddy *buddy; 
    447  
    448     PJ_ASSERT_RETURN(index < (int)PJ_ARRAY_SIZE(pjsua.config.buddy_uri),  
    449                      PJ_EINVAL); 
    450  
    451     pj_memset(info, 0, sizeof(pjsua_buddy_info)); 
    452  
    453     buddy = &pjsua.buddies[index]; 
    454     info->index = buddy->index; 
    455     info->is_valid = pjsua.config.buddy_uri[index].slen; 
    456     if (!info->is_valid) 
    457         return PJ_SUCCESS; 
    458  
    459     info->name = buddy->name; 
    460     info->display_name = buddy->display; 
    461     info->host = buddy->host; 
    462     info->port = buddy->port; 
    463     info->uri = pjsua.config.buddy_uri[index]; 
    464      
    465     if (buddy->sub == NULL || buddy->status.info_cnt==0) { 
    466         info->status = PJSUA_BUDDY_STATUS_UNKNOWN; 
    467         info->status_text = pj_str("?"); 
    468     } else if (pjsua.buddies[index].status.info[0].basic_open) { 
    469         info->status = PJSUA_BUDDY_STATUS_ONLINE; 
    470         info->status_text = pj_str("Online"); 
    471     } else { 
    472         info->status = PJSUA_BUDDY_STATUS_OFFLINE; 
    473         info->status_text = pj_str("Offline"); 
    474     } 
    475  
     894 
     895/* 
     896 * Start presence subsystem. 
     897 */ 
     898pj_status_t pjsua_pres_start(void) 
     899{ 
     900    /* Nothing to do (is it?) */ 
    476901    return PJ_SUCCESS; 
    477902} 
    478903 
    479904 
    480 /** 
    481  * Add new buddy. 
    482  */ 
    483 PJ_DEF(pj_status_t) pjsua_buddy_add( const pj_str_t *uri, 
    484                                      pjsua_buddy_id *buddy_index) 
    485 { 
    486     pjsip_name_addr *url; 
    487     pjsip_sip_uri *sip_uri; 
    488     int index; 
    489     pj_str_t tmp; 
    490  
    491     PJ_ASSERT_RETURN(pjsua.config.buddy_cnt <=  
    492                         PJ_ARRAY_SIZE(pjsua.config.buddy_uri), 
    493                      PJ_ETOOMANY); 
    494  
    495     /* Find empty slot */ 
    496     for (index=0; index<PJ_ARRAY_SIZE(pjsua.config.buddy_uri); ++index) { 
    497         if (pjsua.config.buddy_uri[index].slen == 0) 
    498             break; 
    499     } 
    500  
    501     /* Expect to find an empty slot */ 
    502     PJ_ASSERT_RETURN(index < PJ_ARRAY_SIZE(pjsua.config.buddy_uri), 
    503                      PJ_ETOOMANY); 
    504  
    505  
    506     /* Get name and display name for buddy */ 
    507     pj_strdup_with_null(pjsua.pool, &tmp, uri); 
    508     url = (pjsip_name_addr*)pjsip_parse_uri(pjsua.pool, tmp.ptr, tmp.slen, 
    509                                             PJSIP_PARSE_URI_AS_NAMEADDR); 
    510  
    511     if (url == NULL) 
    512         return PJSIP_EINVALIDURI; 
    513  
    514     /* Save URI */ 
    515     pjsua.config.buddy_uri[index] = tmp; 
    516  
    517     sip_uri = (pjsip_sip_uri*) url->uri; 
    518     pjsua.buddies[index].name = sip_uri->user; 
    519     pjsua.buddies[index].display = url->display; 
    520     pjsua.buddies[index].host = sip_uri->host; 
    521     pjsua.buddies[index].port = sip_uri->port; 
    522     if (pjsua.buddies[index].port == 0) 
    523         pjsua.buddies[index].port = 5060; 
    524  
    525     if (buddy_index) 
    526         *buddy_index = index; 
    527  
    528     pjsua.config.buddy_cnt++; 
    529  
    530     return PJ_SUCCESS; 
    531 } 
    532  
    533  
    534  
    535 /** 
    536  * Delete buddy. 
    537  */ 
    538 PJ_DEF(pj_status_t) pjsua_buddy_del(pjsua_buddy_id index) 
    539 { 
    540     PJ_ASSERT_RETURN(index < (int)PJ_ARRAY_SIZE(pjsua.config.buddy_uri),  
    541                      PJ_EINVAL); 
    542  
    543     if (pjsua.config.buddy_uri[index].slen == 0) 
    544         return PJ_SUCCESS; 
    545  
    546     /* Unsubscribe presence */ 
    547     pjsua_buddy_subscribe_pres(index, PJ_FALSE); 
    548  
    549     /* Remove buddy */ 
    550     pjsua.config.buddy_uri[index].slen = 0; 
    551     pjsua.config.buddy_cnt--; 
    552  
    553     return PJ_SUCCESS; 
    554 } 
    555  
    556  
    557 PJ_DEF(pj_status_t) pjsua_buddy_subscribe_pres( pjsua_buddy_id index, 
    558                                                 pj_bool_t monitor) 
    559 { 
    560     pjsua_buddy *buddy; 
    561  
    562     PJ_ASSERT_RETURN(index < (int)PJ_ARRAY_SIZE(pjsua.config.buddy_uri), 
    563                      PJ_EINVAL); 
    564  
    565     buddy = &pjsua.buddies[index]; 
    566     buddy->monitor = monitor; 
     905/* 
     906 * Refresh presence subscriptions 
     907 */ 
     908void pjsua_pres_refresh() 
     909{ 
     910    unsigned i; 
     911 
     912    refresh_client_subscriptions(); 
     913 
     914    for (i=0; i<PJ_ARRAY_SIZE(pjsua_var.acc); ++i) { 
     915        if (pjsua_var.acc[i].valid) 
     916            refresh_server_subscription(i); 
     917    } 
     918} 
     919 
     920 
     921/* 
     922 * Shutdown presence. 
     923 */ 
     924void pjsua_pres_shutdown(void) 
     925{ 
     926    unsigned i; 
     927 
     928    for (i=0; i<PJ_ARRAY_SIZE(pjsua_var.acc); ++i) { 
     929        if (!pjsua_var.acc[i].valid) 
     930            continue; 
     931        pjsua_pres_delete_acc(i); 
     932    } 
     933 
     934    for (i=0; i<PJ_ARRAY_SIZE(pjsua_var.buddy); ++i) { 
     935        pjsua_var.buddy[i].monitor = 0; 
     936    } 
     937 
    567938    pjsua_pres_refresh(); 
    568     return PJ_SUCCESS; 
    569 } 
    570  
    571  
    572 PJ_DEF(pj_status_t) pjsua_acc_set_online_status( pjsua_acc_id acc_index, 
    573                                                  pj_bool_t is_online) 
    574 { 
    575     PJ_ASSERT_RETURN(acc_index < (int)PJ_ARRAY_SIZE(pjsua.acc),  
    576                      PJ_EINVAL); 
    577     PJ_ASSERT_RETURN(pjsua.acc[acc_index].valid, PJ_EINVALIDOP); 
    578  
    579     pjsua.acc[acc_index].online_status = is_online; 
    580     pjsua_pres_refresh(); 
    581     return PJ_SUCCESS; 
    582 } 
    583  
    584  
    585 /* 
    586  * Refresh presence 
    587  */ 
    588 PJ_DEF(void) pjsua_pres_refresh() 
    589 { 
    590     unsigned i; 
    591  
    592     refresh_client_subscription(); 
    593  
    594     for (i=0; i<PJ_ARRAY_SIZE(pjsua.acc); ++i) 
    595         refresh_server_subscription(i); 
    596 } 
    597  
    598  
    599 /* 
    600  * Shutdown presence. 
    601  */ 
    602 void pjsua_pres_shutdown(void) 
    603 { 
    604     unsigned acc_index; 
    605     unsigned i; 
    606  
    607     for (acc_index=0; acc_index<(int)pjsua.config.acc_cnt; ++acc_index) { 
    608         pjsua.acc[acc_index].online_status = 0; 
    609     } 
    610  
    611     for (i=0; i<pjsua.config.buddy_cnt; ++i) { 
    612         pjsua.buddies[i].monitor = 0; 
    613     } 
    614  
    615     pjsua_pres_refresh(); 
    616 } 
    617  
    618 /* 
    619  * Dump presence status. 
    620  */ 
    621 void pjsua_pres_dump(pj_bool_t detail) 
    622 { 
    623     unsigned acc_index; 
    624     unsigned i; 
    625  
    626  
    627     /* 
    628      * When no detail is required, just dump number of server and client 
    629      * subscriptions. 
    630      */ 
    631     if (detail == PJ_FALSE) { 
    632          
    633         int count = 0; 
    634  
    635         for (acc_index=0; acc_index < (int)pjsua.config.acc_cnt; ++acc_index) { 
    636  
    637             if (!pj_list_empty(&pjsua.acc[acc_index].pres_srv_list)) { 
    638                 struct pjsua_srv_pres *uapres; 
    639  
    640                 uapres = pjsua.acc[acc_index].pres_srv_list.next; 
    641                 while (uapres != &pjsua.acc[acc_index].pres_srv_list) { 
    642                     ++count; 
    643                     uapres = uapres->next; 
    644                 } 
    645             } 
    646         } 
    647  
    648         PJ_LOG(3,(THIS_FILE, "Number of server/UAS subscriptions: %d",  
    649                   count)); 
    650  
    651         count = 0; 
    652  
    653         for (i=0; i<pjsua.config.buddy_cnt; ++i) { 
    654             if (pjsua.buddies[i].sub) { 
    655                 ++count; 
    656             } 
    657         } 
    658  
    659         PJ_LOG(3,(THIS_FILE, "Number of client/UAC subscriptions: %d",  
    660                   count)); 
    661         return; 
    662     } 
    663      
    664  
    665     /* 
    666      * Dumping all server (UAS) subscriptions 
    667      */ 
    668     PJ_LOG(3,(THIS_FILE, "Dumping pjsua server subscriptions:")); 
    669  
    670     for (acc_index=0; acc_index < (int)pjsua.config.acc_cnt; ++acc_index) { 
    671  
    672         PJ_LOG(3,(THIS_FILE, "  %.*s", 
    673                   (int)pjsua.config.acc_config[acc_index].id.slen, 
    674                   pjsua.config.acc_config[acc_index].id.ptr)); 
    675  
    676         if (pj_list_empty(&pjsua.acc[acc_index].pres_srv_list)) { 
    677  
    678             PJ_LOG(3,(THIS_FILE, "  - none - ")); 
    679  
    680         } else { 
    681             struct pjsua_srv_pres *uapres; 
    682  
    683             uapres = pjsua.acc[acc_index].pres_srv_list.next; 
    684             while (uapres != &pjsua.acc[acc_index].pres_srv_list) { 
    685              
    686                 PJ_LOG(3,(THIS_FILE, "    %10s %s", 
    687                           pjsip_evsub_get_state_name(uapres->sub), 
    688                           uapres->remote)); 
    689  
    690                 uapres = uapres->next; 
    691             } 
    692         } 
    693     } 
    694  
    695     /* 
    696      * Dumping all client (UAC) subscriptions 
    697      */ 
    698     PJ_LOG(3,(THIS_FILE, "Dumping pjsua client subscriptions:")); 
    699  
    700     if (pjsua.config.buddy_cnt == 0) { 
    701  
    702         PJ_LOG(3,(THIS_FILE, "  - no buddy list - ")); 
    703  
    704     } else { 
    705         for (i=0; i<pjsua.config.buddy_cnt; ++i) { 
    706  
    707             if (pjsua.buddies[i].sub) { 
    708                 PJ_LOG(3,(THIS_FILE, "  %10s %.*s", 
    709                           pjsip_evsub_get_state_name(pjsua.buddies[i].sub), 
    710                           (int)pjsua.config.buddy_uri[i].slen, 
    711                           pjsua.config.buddy_uri[i].ptr)); 
    712             } else { 
    713                 PJ_LOG(3,(THIS_FILE, "  %10s %.*s", 
    714                           "(null)", 
    715                           (int)pjsua.config.buddy_uri[i].slen, 
    716                           pjsua.config.buddy_uri[i].ptr)); 
    717             } 
    718         } 
    719     } 
    720 } 
    721  
     939} 
Note: See TracChangeset for help on using the changeset viewer.