Changeset 212


Ignore:
Timestamp:
Feb 21, 2006 11:47:00 PM (18 years ago)
Author:
bennylp
Message:

Implemented major feature: call hold and transfer

Location:
pjproject/trunk/pjsip
Files:
2 added
20 edited

Legend:

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

    r197 r212  
    9494SOURCE="..\src\pjsip-ua\sip_reg.c" 
    9595# End Source File 
     96# Begin Source File 
     97 
     98SOURCE="..\src\pjsip-ua\sip_xfer.c" 
     99# End Source File 
    96100# End Group 
    97101# Begin Group "Header Files" 
     
    110114SOURCE="..\include\pjsip-ua\sip_regc.h" 
    111115# End Source File 
     116# Begin Source File 
     117 
     118SOURCE="..\include\pjsip-ua\sip_xfer.h" 
     119# End Source File 
    112120# End Group 
    113121# End Target 
  • pjproject/trunk/pjsip/include/pjsip-simple/errno.h

    r197 r212  
    2424 
    2525/** 
     26 * Start of error code relative to PJ_ERRNO_START_USER. 
     27 */ 
     28#define PJSIP_SIMPLE_ERRNO_START  (PJ_ERRNO_START_USER + PJ_ERRNO_SPACE_SIZE*2) 
     29 
     30 
     31/** 
    2632 * @hideinitializer 
    2733 * No event package with the specified name. 
    2834 */ 
    29 #define PJSIP_SIMPLE_ENOPKG         -1 
     35#define PJSIP_SIMPLE_ENOPKG         (PJSIP_SIMPLE_ERRNO_START+1)    /*270001*/ 
    3036/** 
    3137 * @hideinitializer 
    3238 * Event package already exists. 
    3339 */ 
    34 #define PJSIP_SIMPLE_EPKGEXISTS     -1 
     40#define PJSIP_SIMPLE_EPKGEXISTS     (PJSIP_SIMPLE_ERRNO_START+2)    /*270002*/ 
    3541 
    3642 
     
    3945 * Expecting SUBSCRIBE request 
    4046 */ 
    41 #define PJSIP_SIMPLE_ENOTSUBSCRIBE  -1 
     47#define PJSIP_SIMPLE_ENOTSUBSCRIBE  (PJSIP_SIMPLE_ERRNO_START+20)   /*270020*/ 
    4248/** 
    4349 * @hideinitializer 
    4450 * No presence associated with subscription 
    4551 */ 
    46 #define PJSIP_SIMPLE_ENOPRESENCE    -1 
     52#define PJSIP_SIMPLE_ENOPRESENCE    (PJSIP_SIMPLE_ERRNO_START+21)   /*270021*/ 
    4753/** 
    4854 * @hideinitializer 
    4955 * No presence info in server subscription 
    5056 */ 
    51 #define PJSIP_SIMPLE_ENOPRESENCEINFO -1 
     57#define PJSIP_SIMPLE_ENOPRESENCEINFO (PJSIP_SIMPLE_ERRNO_START+22)  /*270022*/ 
    5258/** 
    5359 * @hideinitializer 
    5460 * Bad Content-Type 
    5561 */ 
    56 #define PJSIP_SIMPLE_EBADCONTENT    -1 
     62#define PJSIP_SIMPLE_EBADCONTENT    (PJSIP_SIMPLE_ERRNO_START+23)   /*270023*/ 
    5763/** 
    5864 * @hideinitializer 
    5965 * Bad PIDF Message 
    6066 */ 
    61 #define PJSIP_SIMPLE_EBADPIDF       -1 
     67#define PJSIP_SIMPLE_EBADPIDF       (PJSIP_SIMPLE_ERRNO_START+24)   /*270024*/ 
    6268/** 
    6369 * @hideinitializer 
    6470 * Bad XPIDF Message 
    6571 */ 
    66 #define PJSIP_SIMPLE_EBADXPIDF      -1 
     72#define PJSIP_SIMPLE_EBADXPIDF      (PJSIP_SIMPLE_ERRNO_START+25)   /*270025*/ 
    6773 
    6874 
  • pjproject/trunk/pjsip/include/pjsip-simple/evsub.h

    r197 r212  
    7777 
    7878 
     79/** 
     80 * Some options for the event subscription. 
     81 */ 
     82enum 
     83{ 
     84    /**  
     85     * If this flag is set, then outgoing request to create subscription 
     86     * will not have id in the Event header (e.g. in REFER request). But if  
     87     * there is an id in the incoming NOTIFY, that id will be used. 
     88     */ 
     89    PJSIP_EVSUB_NO_EVENT_ID  = 1, 
     90}; 
     91 
    7992 
    8093/** 
     
    245258 * @param user_cb       Callback to receive event subscription notifications. 
    246259 * @param event         Event name. 
     260 * @param option        Bitmask of options. 
    247261 * @param p_evsub       Pointer to receive event subscription instance. 
    248262 * 
     
    252266                                             const pjsip_evsub_user *user_cb, 
    253267                                             const pj_str_t *event, 
     268                                             unsigned option, 
    254269                                             pjsip_evsub **p_evsub); 
    255270 
     
    261276 * @param rdata         The incoming request that creates the event  
    262277 *                      subscription, such as SUBSCRIBE or REFER. 
     278 * @param option        Bitmask of options. 
    263279 * @param p_evsub       Pointer to receive event subscription instance. 
    264280 * 
     
    268284                                             const pjsip_evsub_user *user_cb, 
    269285                                             pjsip_rx_data *rdata, 
     286                                             unsigned option, 
    270287                                             pjsip_evsub **p_evsub); 
    271288 
     
    367384 
    368385/** 
    369  * Send request message. 
     386 * Send request message that was previously created with initiate(), notify(), 
     387 * or current_notify(). Application may also send request created with other 
     388 * functions, e.g. authentication. But the request MUST be either request 
     389 * that creates/refresh subscription or NOTIFY request. 
    370390 * 
    371391 * @param sub           The event subscription object. 
  • pjproject/trunk/pjsip/include/pjsip-simple/presence.h

    r197 r212  
    203203 
    204204/** 
    205  * Send request. 
     205 * Send request message that was previously created with initiate(), notify(), 
     206 * or current_notify(). Application may also send request created with other 
     207 * functions, e.g. authentication. But the request MUST be either request 
     208 * that creates/refresh subscription or NOTIFY request. 
    206209 * 
    207210 * @param sub           The subscription object. 
  • pjproject/trunk/pjsip/include/pjsip-ua/sip_inv.h

    r184 r212  
    9898     * This callback is called when the invite session has received  
    9999     * new offer from peer. Application can inspect the remote offer  
    100      * by calling negotiator's pjmedia_sdp_neg_get_neg_remote(), and  
    101      * optionally specify a modified answer.  
    102      * 
    103      * This callback is optional. When it's not specified, the default  
    104      * behavior is nothing. After calling this callback, the negotiator  
    105      * will negotiate remote offer with session's initial capability. 
     100     * in "offer".  
    106101     * 
    107102     * @param inv       The invite session. 
    108      */ 
    109     void (*on_rx_offer)(pjsip_inv_session *inv); 
     103     * @param offer     Remote offer. 
     104     */ 
     105    void (*on_rx_offer)(pjsip_inv_session *inv, 
     106                        const pjmedia_sdp_session *offer); 
    110107 
    111108    /** 
     
    122119    void (*on_media_update)(pjsip_inv_session *inv_ses,  
    123120                            pj_status_t status); 
    124  
    125121}; 
    126122 
     
    388384 
    389385 
    390 #if 0 
    391  If we implement this, we need to send SDP answer automatically on  
    392  subsequent request/response. Something like "has_answer" flag. 
    393  
    394 /** 
    395  * Set local answer to respond to remote SDP offer. By calling this function, 
    396  * application can start SDP negotiation immediately without having to 
    397  * send any request or response message. This function is normally called 
    398  * when on_rx_offer() callback is called. 
     386/** 
     387 * Set local answer to respond to remote SDP offer, to be carried by  
     388 * subsequent response (or request). 
    399389 * 
    400390 * @param inv           The invite session. 
    401391 * @param sdp           The SDP description which will be set as answer 
    402392 *                      to remote. 
    403  */ 
    404 PJ_DECL(pj_status_t) pjsip_inv_set_sdp_answer( pjsip_inv_session *inv, 
    405                                                const pjmedia_sdp_session *sdp ); 
    406 #endif 
     393 * 
     394 * @return              PJ_SUCCESS if local answer can be accepted by 
     395 *                      SDP negotiator. 
     396 */ 
     397PJ_DECL(pj_status_t) pjsip_inv_set_sdp_answer(pjsip_inv_session *inv, 
     398                                              const pjmedia_sdp_session *sdp ); 
     399 
    407400 
    408401/** 
  • pjproject/trunk/pjsip/include/pjsip/sip_dialog.h

    r196 r212  
    4242{ 
    4343    pjsip_fromto_hdr    *info;      /**< From/To header, inc tag.       */ 
     44    pj_str_t             info_str;  /**< String rep of info header.     */ 
    4445    pj_uint32_t          tag_hval;  /**< Hashed value of the tag.       */ 
    4546    pjsip_contact_hdr   *contact;   /**< Contact header.                */ 
     
    7778 
    7879    /* Dialog's session properties. */ 
    79     enum pjsip_dialog_state     state;      /**< Dialog state.                      */ 
     80    pjsip_dialog_state  state;      /**< Dialog state.                      */ 
    8081    pjsip_uri          *target;     /**< Current target.                    */ 
     82    pjsip_hdr           inv_hdr;    /**< Headers from hparam in dest URL    */ 
    8183    pjsip_dlg_party     local;      /**< Local party info.                  */ 
    8284    pjsip_dlg_party     remote;     /**< Remote party info.                 */ 
  • pjproject/trunk/pjsip/include/pjsip/sip_errno.h

    r197 r212  
    172172 */ 
    173173#define PJSIP_EMISSINGBODY      (PJSIP_ERRNO_START_PJSIP + 54)  /* 171054 */ 
     174/** 
     175 * @hideinitializer 
     176 * Invalid/unexpected method. 
     177 */ 
     178#define PJSIP_EINVALIDMETHOD    (PJSIP_ERRNO_START_PJSIP + 55)  /* 171055 */ 
    174179 
    175180 
     
    348353 */ 
    349354#define PJSIP_EMISSINGTAG        (PJSIP_ERRNO_START_PJSIP+120)  /* 171120 */ 
     355/** 
     356 * @hideinitializer 
     357 * Expecting REFER method 
     358 */ 
     359#define PJSIP_ENOTREFER          (PJSIP_ERRNO_START_PJSIP+121)  /* 171121 */ 
     360/** 
     361 * @hideinitializer 
     362 * Not associated with REFER subscription 
     363 */ 
     364#define PJSIP_ENOREFERSESSION    (PJSIP_ERRNO_START_PJSIP+122)  /* 171122 */ 
     365 
    350366 
    351367 
  • pjproject/trunk/pjsip/include/pjsip/sip_msg.h

    r197 r212  
    585585 
    586586/** 
     587 * General purpose function to clone textual data in a SIP body. Attach this 
     588 * function as "clone_data" member of the SIP body only if the data type 
     589 * is a text (i.e. C string, not pj_str_t), and the length indicates the 
     590 * length of the text. 
     591 * 
     592 *  @param pool         Pool used to clone the data. 
     593 *  @param data         Textual data. 
     594 *  @param len          The length of the string. 
     595 * 
     596 *  @return             New text duplicated from the original text. 
     597 */ 
     598PJ_DECL(void*) pjsip_clone_text_data( pj_pool_t *pool, const void *data, 
     599                                      unsigned len); 
     600 
     601 
     602/** 
    587603 * Clone the message body in src_body to the dst_body. This will duplicate 
    588604 * the contents of the message body using the \a clone_data member of the 
  • pjproject/trunk/pjsip/include/pjsip_ua.h

    r141 r212  
    2222#include <pjsip-ua/sip_inv.h> 
    2323#include <pjsip-ua/sip_regc.h> 
     24#include <pjsip-ua/sip_xfer.h> 
    2425 
    2526 
  • pjproject/trunk/pjsip/src/pjsip-simple/errno.c

    r198 r212  
    1818 */ 
    1919#include <pjsip-simple/errno.h> 
     20#include <pj/string.h> 
    2021 
     22/* PJSIP-SIMPLE's own error codes/messages  
     23 * MUST KEEP THIS ARRAY SORTED!! 
     24 * Message must be limited to 64 chars! 
     25 */ 
     26static const struct  
     27{ 
     28    int code; 
     29    const char *msg; 
     30} err_str[] =  
     31{ 
     32    { PJSIP_SIMPLE_ENOPKG,          "No SIP event package with the specified name" }, 
     33    { PJSIP_SIMPLE_EPKGEXISTS,      "SIP event package already exist" }, 
     34 
     35    { PJSIP_SIMPLE_ENOTSUBSCRIBE,   "Expecting SUBSCRIBE request" }, 
     36    { PJSIP_SIMPLE_ENOPRESENCE,     "No presence associated with the subscription" }, 
     37    { PJSIP_SIMPLE_ENOPRESENCEINFO, "No presence info in the server subscription" }, 
     38    { PJSIP_SIMPLE_EBADCONTENT,     "Bad Content-Type for presence" }, 
     39    { PJSIP_SIMPLE_EBADPIDF,        "Bad PIDF content for presence" }, 
     40    { PJSIP_SIMPLE_EBADXPIDF,       "Bad XPIDF content for presence" }, 
     41}; 
     42 
     43 
     44 
     45/* 
     46 * pjsipsimple_strerror() 
     47 */ 
     48PJ_DEF(pj_str_t) pjsipsimple_strerror( pj_status_t statcode,  
     49                                       char *buf, pj_size_t bufsize ) 
     50{ 
     51    pj_str_t errstr; 
     52 
     53    if (statcode >= PJSIP_SIMPLE_ERRNO_START &&  
     54        statcode < PJSIP_SIMPLE_ERRNO_START + PJ_ERRNO_SPACE_SIZE) 
     55    { 
     56        /* Find the error in the table. 
     57         * Use binary search! 
     58         */ 
     59        int first = 0; 
     60        int n = PJ_ARRAY_SIZE(err_str); 
     61 
     62        while (n > 0) { 
     63            int half = n/2; 
     64            int mid = first + half; 
     65 
     66            if (err_str[mid].code < statcode) { 
     67                first = mid+1; 
     68                n -= (half+1); 
     69            } else if (err_str[mid].code > statcode) { 
     70                n = half; 
     71            } else { 
     72                first = mid; 
     73                break; 
     74            } 
     75        } 
     76 
     77 
     78        if (PJ_ARRAY_SIZE(err_str) && err_str[first].code == statcode) { 
     79            pj_str_t msg; 
     80             
     81            msg.ptr = (char*)err_str[first].msg; 
     82            msg.slen = pj_ansi_strlen(err_str[first].msg); 
     83 
     84            errstr.ptr = buf; 
     85            pj_strncpy_with_null(&errstr, &msg, bufsize); 
     86            return errstr; 
     87 
     88        }  
     89    } 
     90 
     91    /* Error not found. */ 
     92    errstr.ptr = buf; 
     93    errstr.slen = pj_snprintf(buf, bufsize,  
     94                              "Unknown error %d", 
     95                              statcode); 
     96 
     97    return errstr; 
     98} 
     99 
  • pjproject/trunk/pjsip/src/pjsip-simple/evsub.c

    r201 r212  
    198198    pjsip_dialog         *dlg;          /**< Underlying dialog.             */ 
    199199    struct evpkg         *pkg;          /**< The event package.             */ 
     200    unsigned              option;       /**< Options.                       */ 
    200201    pjsip_evsub_user      user;         /**< Callback.                      */ 
    201202    pjsip_role_e          role;         /**< UAC=subscriber, UAS=notifier   */ 
     
    236237static const pj_str_t STR_TIMEOUT    = { "timeout", 7}; 
    237238 
     239 
    238240/* 
    239241 * On unload module. 
     
    246248    return PJ_SUCCESS; 
    247249} 
     250 
     251/* Proto for pjsipsimple_strerror(). 
     252 * Defined in errno.c 
     253 */ 
     254PJ_DECL(pj_str_t) pjsipsimple_strerror( pj_status_t statcode,  
     255                                        char *buf, pj_size_t bufsize ); 
    248256 
    249257/* 
     
    257265        { "NOTIFY", 6} 
    258266    }; 
     267 
     268    pj_register_strerror(PJSIP_SIMPLE_ERRNO_START, PJ_ERRNO_SPACE_SIZE, 
     269                         &pjsipsimple_strerror); 
    259270 
    260271    PJ_ASSERT_RETURN(endpt != NULL, PJ_EINVAL); 
     
    619630                                 const pjsip_evsub_user *user_cb, 
    620631                                 const pj_str_t *event, 
     632                                 unsigned option, 
    621633                                 pjsip_evsub **p_evsub ) 
    622634{ 
     
    641653    sub->pkg = pkg; 
    642654    sub->role = role; 
     655    sub->option = option; 
    643656    sub->state = PJSIP_EVSUB_STATE_NULL; 
    644657    sub->state_str = evsub_state_names[sub->state]; 
     
    698711                                            const pjsip_evsub_user *user_cb, 
    699712                                            const pj_str_t *event, 
     713                                            unsigned option, 
    700714                                            pjsip_evsub **p_evsub) 
    701715{ 
     
    706720 
    707721    pjsip_dlg_inc_lock(dlg); 
    708     status = evsub_create(dlg, PJSIP_UAC_ROLE, user_cb, event, &sub); 
     722    status = evsub_create(dlg, PJSIP_UAC_ROLE, user_cb, event, option, &sub); 
    709723    if (status != PJ_SUCCESS) 
    710724        goto on_return; 
    711725 
    712     /* Add unique Id to Event header */ 
    713     pj_create_unique_string(sub->pool, &sub->event->id_param); 
     726    /* Add unique Id to Event header, only when PJSIP_EVSUB_NO_EVENT_ID 
     727     * is not specified. 
     728     */ 
     729    if ((option & PJSIP_EVSUB_NO_EVENT_ID) == 0) { 
     730        pj_create_unique_string(sub->pool, &sub->event->id_param); 
     731    } 
    714732 
    715733    /* Increment dlg session. */ 
     
    731749                                            const pjsip_evsub_user *user_cb, 
    732750                                            pjsip_rx_data *rdata, 
     751                                            unsigned option, 
    733752                                            pjsip_evsub **p_evsub) 
    734753{ 
     
    758777    PJ_ASSERT_RETURN(user_cb->on_rx_refresh, PJ_EINVALIDOP); 
    759778 
    760     /* Request MUST have "Event" header: */ 
    761  
     779    /* Request MUST have "Event" header. We need the Event header to get  
     780     * the package name (don't want to add more arguments in the function). 
     781     */ 
    762782    event_hdr = (pjsip_event_hdr*)  
    763783        pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &STR_EVENT, NULL); 
     
    773793 
    774794    status = evsub_create(dlg, PJSIP_UAS_ROLE, user_cb,  
    775                           &event_hdr->event_type, &sub); 
     795                          &event_hdr->event_type, option, &sub); 
    776796    if (status != PJ_SUCCESS) 
    777797        goto on_return; 
     
    11481168    } 
    11491169 
     1170 
    11501171    switch (event->body.tsx_state.type) { 
    11511172    case PJSIP_EVENT_RX_MSG: 
     
    11641185     
    11651186    if (!msg) { 
    1166         pj_assert(!"First transaction event is not TX or RX!"); 
     1187        //Note: 
     1188        // this transaction can be other transaction in the dialog. 
     1189        // The assertion below probably only valid for dialog that 
     1190        // only has one event subscription usage. 
     1191        //pj_assert(!"First transaction event is not TX or RX!"); 
    11671192        return NULL; 
    11681193    } 
     
    11881213    while (dlgsub != dlgsub_head) { 
    11891214 
    1190         /* Match event type and Id */ 
    1191         if (pj_strcmp(&dlgsub->sub->event->id_param, &event_hdr->id_param)==0 && 
    1192             pj_stricmp(&dlgsub->sub->event->event_type, &event_hdr->event_type)==0) 
     1215        if (pj_stricmp(&dlgsub->sub->event->event_type,  
     1216                       &event_hdr->event_type)==0) 
    11931217        { 
    1194             break; 
    1195         } 
     1218            /* Event type matched.  
     1219             * Check if event ID matched too. 
     1220             */ 
     1221            if (pj_strcmp(&dlgsub->sub->event->id_param,  
     1222                          &event_hdr->id_param)==0) 
     1223            { 
     1224                 
     1225                break; 
     1226 
     1227            } 
     1228            /* 
     1229             * Otherwise if it is an UAC subscription, AND 
     1230             * PJSIP_EVSUB_NO_EVENT_ID flag is set, AND 
     1231             * the session's event id is NULL, AND 
     1232             * the incoming request is NOTIFY with event ID, then 
     1233             * we consider it as a match, and update the 
     1234             * session's event id. 
     1235             */ 
     1236            else if (dlgsub->sub->role == PJSIP_ROLE_UAC && 
     1237                     (dlgsub->sub->option & PJSIP_EVSUB_NO_EVENT_ID)!=0 && 
     1238                     dlgsub->sub->event->id_param.slen==0 && 
     1239                     !pjsip_method_cmp(&tsx->method, &pjsip_notify_method)) 
     1240            { 
     1241                /* Update session's event id. */ 
     1242                pj_strdup(dlgsub->sub->pool,  
     1243                          &dlgsub->sub->event->id_param, 
     1244                          &event_hdr->id_param); 
     1245 
     1246                break; 
     1247            } 
     1248        } 
     1249         
     1250 
     1251 
    11961252        dlgsub = dlgsub->next; 
    11971253    } 
     
    12011257        PJ_LOG(4,(THIS_FILE,  
    12021258                  "Subscription not found for %.*s, event=%.*s;id=%.*s", 
     1259                  (int)tsx->method.name.slen, 
     1260                  tsx->method.name.ptr, 
    12031261                  (int)event_hdr->event_type.slen, 
    12041262                  event_hdr->event_type.ptr, 
     
    17381796                set_state(sub, PJSIP_EVSUB_STATE_TERMINATED, NULL, NULL); 
    17391797            } 
    1740         }  
     1798 
     1799        } 
     1800        /* 
     1801         * Terminate event usage if we receive 481, 408, and 7 class 
     1802         * responses. 
     1803         */ 
     1804        if (sub->state != PJSIP_EVSUB_STATE_TERMINATED && 
     1805            (tsx->status_code==481 || tsx->status_code==408 || 
     1806             tsx->status_code/100 == 7)) 
     1807        { 
     1808            set_state(sub, PJSIP_EVSUB_STATE_TERMINATED, NULL, event); 
     1809        } 
    17411810 
    17421811    } else { 
  • pjproject/trunk/pjsip/src/pjsip-simple/presence.c

    r198 r212  
    192192 
    193193    /* Create event subscription */ 
    194     status = pjsip_evsub_create_uac( dlg,  &pres_user, &STR_PRESENCE, &sub); 
     194    status = pjsip_evsub_create_uac( dlg,  &pres_user, &STR_PRESENCE, 0, &sub); 
    195195    if (status != PJ_SUCCESS) 
    196196        goto on_return; 
     
    199199    pres = pj_pool_zalloc(dlg->pool, sizeof(pjsip_pres)); 
    200200    pres->dlg = dlg; 
     201    pres->sub = sub; 
    201202    if (user_cb) 
    202203        pj_memcpy(&pres->user_cb, user_cb, sizeof(pjsip_evsub_user)); 
     
    298299 
    299300    /* Create server subscription */ 
    300     status = pjsip_evsub_create_uas( dlg, &pres_user, rdata, &sub); 
     301    status = pjsip_evsub_create_uas( dlg, &pres_user, rdata, 0, &sub); 
    301302    if (status != PJ_SUCCESS) 
    302303        goto on_return; 
  • pjproject/trunk/pjsip/src/pjsip-ua/sip_inv.c

    r184 r212  
    201201     * move state to CONFIRMED. 
    202202     */ 
    203     if (method->id == PJSIP_ACK_METHOD && inv && 
    204         inv->state != PJSIP_INV_STATE_CONFIRMED) 
    205     { 
    206         pjsip_event event; 
     203    if (method->id == PJSIP_ACK_METHOD && inv) { 
    207204 
    208205        /* Terminate INVITE transaction, if it's still present. */ 
     
    215212        } 
    216213 
    217         PJSIP_EVENT_INIT_RX_MSG(event, rdata); 
    218         inv_set_state(inv, PJSIP_INV_STATE_CONFIRMED, &event); 
     214        if (inv->state != PJSIP_INV_STATE_CONFIRMED) { 
     215            pjsip_event event; 
     216 
     217            PJSIP_EVENT_INIT_RX_MSG(event, rdata); 
     218            inv_set_state(inv, PJSIP_INV_STATE_CONFIRMED, &event); 
     219        } 
    219220    } 
    220221 
     
    251252     */ 
    252253    if (msg->type == PJSIP_RESPONSE_MSG && msg->line.status.code/100==2 && 
    253         rdata->msg_info.cseq->method.id == PJSIP_INVITE_METHOD) { 
     254        rdata->msg_info.cseq->method.id == PJSIP_INVITE_METHOD && 
     255        inv->invite_tsx == NULL)  
     256    { 
    254257 
    255258        inv_send_ack(inv, rdata); 
     
    866869    pjsip_tx_data *tdata; 
    867870    const pjsip_hdr *hdr; 
     871    pj_bool_t has_sdp; 
    868872    pj_status_t status; 
    869873 
     
    871875    PJ_ASSERT_RETURN(inv && p_tdata, PJ_EINVAL); 
    872876 
    873     /* State MUST be NULL. */ 
    874     PJ_ASSERT_RETURN(inv->state == PJSIP_INV_STATE_NULL, PJ_EINVAL); 
     877    /* State MUST be NULL or CONFIRMED. */ 
     878    PJ_ASSERT_RETURN(inv->state == PJSIP_INV_STATE_NULL || 
     879                     inv->state == PJSIP_INV_STATE_CONFIRMED,  
     880                     PJ_EINVALIDOP); 
    875881 
    876882    /* Create the INVITE request. */ 
     
    880886        return status; 
    881887 
     888    /* If this is the first INVITE, then copy the headers from inv_hdr. 
     889     * These are the headers parsed from the request URI when the 
     890     * dialog was created. 
     891     */ 
     892    if (inv->state == PJSIP_INV_STATE_NULL) { 
     893        hdr = inv->dlg->inv_hdr.next; 
     894 
     895        while (hdr != &inv->dlg->inv_hdr) { 
     896            pjsip_msg_add_hdr(tdata->msg, 
     897                              pjsip_hdr_shallow_clone(tdata->pool, hdr)); 
     898            hdr = hdr->next; 
     899        } 
     900    } 
     901 
     902    /* See if we have SDP to send. */ 
     903    if (inv->neg) { 
     904        pjmedia_sdp_neg_state neg_state; 
     905 
     906        neg_state = pjmedia_sdp_neg_get_state(inv->neg); 
     907 
     908        has_sdp = (neg_state == PJMEDIA_SDP_NEG_STATE_LOCAL_OFFER || 
     909                   (neg_state == PJMEDIA_SDP_NEG_STATE_WAIT_NEGO && 
     910                    pjmedia_sdp_neg_has_local_answer(inv->neg))); 
     911 
     912 
     913    } else { 
     914        has_sdp = PJ_FALSE; 
     915    } 
     916 
    882917    /* Add SDP, if any. */ 
    883     if (inv->neg &&  
    884         pjmedia_sdp_neg_get_state(inv->neg)==PJMEDIA_SDP_NEG_STATE_LOCAL_OFFER) 
    885     { 
     918    if (has_sdp) { 
    886919        const pjmedia_sdp_session *offer; 
    887920 
     
    941974 * Check in incoming message for SDP offer/answer. 
    942975 */ 
    943 static void inv_check_sdp_in_incoming_msg( pjsip_inv_session *inv, 
    944                                            pjsip_transaction *tsx, 
    945                                            pjsip_rx_data *rdata) 
     976static pj_status_t inv_check_sdp_in_incoming_msg( pjsip_inv_session *inv, 
     977                                                  pjsip_transaction *tsx, 
     978                                                  pjsip_rx_data *rdata) 
    946979{ 
    947980    struct tsx_inv_data *tsx_inv_data; 
     
    964997 
    965998    if (tsx_inv_data->sdp_done) 
    966         return; 
     999        return PJ_SUCCESS; 
    9671000 
    9681001    /* Check if SDP is present in the message. */ 
     
    9711004    if (msg->body == NULL) { 
    9721005        /* Message doesn't have body. */ 
    973         return; 
     1006        return PJ_SUCCESS; 
    9741007    } 
    9751008 
     
    9781011    { 
    9791012        /* Message body is not "application/sdp" */ 
    980         return; 
     1013        return PJMEDIA_SDP_EINSDP; 
    9811014    } 
    9821015 
     
    9901023        PJ_LOG(4,(THIS_FILE, "Error parsing SDP in %s: %s", 
    9911024                  pjsip_rx_data_get_info(rdata), errmsg)); 
    992         return; 
     1025        return PJMEDIA_SDP_EINSDP; 
    9931026    } 
    9941027 
     
    10161049            PJ_LOG(4,(THIS_FILE, "Error processing SDP offer in %s: %s", 
    10171050                      pjsip_rx_data_get_info(rdata), errmsg)); 
    1018             return; 
     1051            return PJMEDIA_SDP_EINSDP; 
    10191052        } 
    10201053 
    10211054        /* Inform application about remote offer. */ 
    10221055 
    1023         if (mod_inv.cb.on_rx_offer) 
    1024             (*mod_inv.cb.on_rx_offer)(inv); 
     1056        if (mod_inv.cb.on_rx_offer) { 
     1057 
     1058            (*mod_inv.cb.on_rx_offer)(inv, sdp); 
     1059 
     1060        } 
    10251061 
    10261062    } else if (pjmedia_sdp_neg_get_state(inv->neg) ==  
     
    10421078            PJ_LOG(4,(THIS_FILE, "Error processing SDP answer in %s: %s", 
    10431079                      pjsip_rx_data_get_info(rdata), errmsg)); 
    1044             return; 
     1080            return PJMEDIA_SDP_EINSDP; 
    10451081        } 
    10461082 
     
    10601096    } 
    10611097 
    1062 } 
    1063  
    1064  
    1065  
    1066 /* 
    1067  * Answer initial INVITE. 
     1098    return PJ_SUCCESS; 
     1099} 
     1100 
     1101 
     1102/* 
     1103 * Process INVITE answer, for both initial and subsequent re-INVITE 
     1104 */ 
     1105static pj_status_t process_answer( pjsip_inv_session *inv, 
     1106                                   int st_code, 
     1107                                   pjsip_tx_data *tdata ) 
     1108{ 
     1109    pj_status_t status; 
     1110    pjmedia_sdp_session *sdp = NULL; 
     1111 
     1112    /* Include SDP for 18x and 2xx response.  
     1113     * Also if SDP negotiator is ready, start negotiation. 
     1114     */ 
     1115    if (st_code/10 == 18 || st_code/10 == 20) { 
     1116 
     1117        pjmedia_sdp_neg_state neg_state; 
     1118 
     1119        neg_state = inv->neg ? pjmedia_sdp_neg_get_state(inv->neg) : 
     1120                    PJMEDIA_SDP_NEG_STATE_NULL; 
     1121 
     1122        if (neg_state == PJMEDIA_SDP_NEG_STATE_LOCAL_OFFER) { 
     1123 
     1124            status = pjmedia_sdp_neg_get_neg_local(inv->neg, &sdp); 
     1125 
     1126        } else if (neg_state == PJMEDIA_SDP_NEG_STATE_WAIT_NEGO && 
     1127                   pjmedia_sdp_neg_has_local_answer(inv->neg) ) 
     1128        { 
     1129 
     1130            status = inv_negotiate_sdp(inv); 
     1131            if (status != PJ_SUCCESS) 
     1132                return status; 
     1133             
     1134            status = pjmedia_sdp_neg_get_active_local(inv->neg, &sdp); 
     1135        } 
     1136 
     1137    } 
     1138 
     1139 
     1140 
     1141    /* Include SDP when it's available. 
     1142     * Subsequent response will include this SDP. 
     1143     */ 
     1144    if (sdp) { 
     1145        tdata->msg->body = create_sdp_body(tdata->pool, sdp); 
     1146    } 
     1147 
     1148    /* Remove message body if this is a non-2xx final response */ 
     1149    if (st_code >= 300) 
     1150        tdata->msg->body = NULL; 
     1151 
     1152 
     1153    return PJ_SUCCESS; 
     1154} 
     1155 
     1156 
     1157/* 
     1158 * Answer initial INVITE 
     1159 * Re-INVITE will be answered automatically, and will not use this function. 
    10681160 */  
    10691161PJ_DEF(pj_status_t) pjsip_inv_answer(   pjsip_inv_session *inv, 
     
    10881180     * offer before.  
    10891181     */ 
    1090     if (local_sdp) { 
     1182    if (local_sdp && (st_code/100==1 || st_code/100==2)) { 
    10911183 
    10921184        if (inv->neg == NULL) { 
     
    11091201    } 
    11101202 
     1203 
     1204 
     1205 
     1206    /* Modify last response. */ 
    11111207    last_res = inv->invite_tsx->last_tx; 
    1112  
    1113     /* Modify last response. */ 
    11141208    status = pjsip_dlg_modify_response(inv->dlg, last_res, st_code, st_text); 
    11151209    if (status != PJ_SUCCESS) 
    11161210        return status; 
    11171211 
    1118     /* Include SDP for 18x and 2xx response.  
    1119      * Also if SDP negotiator is ready, start negotiation. 
    1120      */ 
    1121     if (st_code/10 == 18 || st_code/10 == 20) { 
    1122  
    1123         pjmedia_sdp_neg_state neg_state; 
    1124  
    1125         neg_state = inv->neg ? pjmedia_sdp_neg_get_state(inv->neg) : 
    1126                     PJMEDIA_SDP_NEG_STATE_NULL; 
    1127  
    1128         if (neg_state == PJMEDIA_SDP_NEG_STATE_LOCAL_OFFER || 
    1129             neg_state == PJMEDIA_SDP_NEG_STATE_WAIT_NEGO) 
    1130         { 
    1131             const pjmedia_sdp_session *local; 
    1132  
    1133             status = pjmedia_sdp_neg_get_neg_local(inv->neg, &local); 
    1134             if (status == PJ_SUCCESS) 
    1135                 last_res->msg->body = create_sdp_body(last_res->pool, local); 
    1136         } 
    1137  
    1138         /* Start negotiation, if ready. */ 
    1139         if (neg_state == PJMEDIA_SDP_NEG_STATE_WAIT_NEGO) { 
    1140             status = inv_negotiate_sdp(inv); 
    1141             if (status != PJ_SUCCESS) { 
    1142                 pjsip_tx_data_dec_ref(last_res); 
    1143                 return status; 
    1144             } 
    1145         } 
    1146     } 
     1212 
     1213    /* Process SDP in answer */ 
     1214    status = process_answer(inv, st_code, last_res); 
     1215    if (status != PJ_SUCCESS) 
     1216        return status; 
    11471217 
    11481218 
     
    11501220 
    11511221    return PJ_SUCCESS; 
     1222} 
     1223 
     1224 
     1225/* 
     1226 * Set SDP answer. 
     1227 */ 
     1228PJ_DEF(pj_status_t) pjsip_inv_set_sdp_answer( pjsip_inv_session *inv, 
     1229                                              const pjmedia_sdp_session *sdp ) 
     1230{ 
     1231    pj_status_t status; 
     1232 
     1233    PJ_ASSERT_RETURN(inv && sdp, PJ_EINVAL); 
     1234 
     1235    pjsip_dlg_inc_lock(inv->dlg); 
     1236    status = pjmedia_sdp_neg_set_local_answer( inv->pool, inv->neg, sdp); 
     1237    pjsip_dlg_dec_lock(inv->dlg); 
     1238 
     1239    return status; 
    11521240} 
    11531241 
     
    12061294            PJ_ASSERT_RETURN(tdata != NULL, PJ_EINVALIDOP); 
    12071295 
    1208             status = pjsip_dlg_modify_response(inv->dlg, tdata, st_code, 
    1209                                                st_text); 
     1296            //status = pjsip_dlg_modify_response(inv->dlg, tdata, st_code, 
     1297            //                                 st_text); 
     1298            status = pjsip_inv_answer(inv, st_code, st_text, NULL, &tdata); 
    12101299        } 
    12111300        break; 
     
    12481337                                        pjsip_tx_data **p_tdata ) 
    12491338{ 
    1250     PJ_UNUSED_ARG(inv); 
    1251     PJ_UNUSED_ARG(new_contact); 
    1252     PJ_UNUSED_ARG(new_offer); 
    1253     PJ_UNUSED_ARG(p_tdata); 
    1254  
    1255     PJ_TODO(CREATE_REINVITE_REQUEST); 
    1256     return PJ_ENOTSUP; 
     1339    pj_status_t status; 
     1340    pjsip_contact_hdr *contact_hdr = NULL; 
     1341 
     1342    /* Check arguments. */ 
     1343    PJ_ASSERT_RETURN(inv && p_tdata, PJ_EINVAL); 
     1344 
     1345    /* Must NOT have a pending INVITE transaction */ 
     1346    PJ_ASSERT_RETURN(inv->invite_tsx==NULL, PJ_EINVALIDOP); 
     1347 
     1348 
     1349    pjsip_dlg_inc_lock(inv->dlg); 
     1350 
     1351    if (new_contact) { 
     1352        pj_str_t tmp; 
     1353        const pj_str_t STR_CONTACT = { "Contact", 7 }; 
     1354 
     1355        pj_strdup_with_null(inv->dlg->pool, &tmp, new_contact); 
     1356        contact_hdr = pjsip_parse_hdr(inv->dlg->pool, &STR_CONTACT,  
     1357                                      tmp.ptr, tmp.slen, NULL); 
     1358        if (!contact_hdr) { 
     1359            status = PJSIP_EINVALIDURI; 
     1360            goto on_return; 
     1361        } 
     1362    } 
     1363 
     1364 
     1365    if (new_offer) { 
     1366        if (!inv->neg) { 
     1367            status = pjmedia_sdp_neg_create_w_local_offer(inv->pool, new_offer, 
     1368                                                          &inv->neg); 
     1369            if (status != PJ_SUCCESS) 
     1370                goto on_return; 
     1371 
     1372        } else switch (pjmedia_sdp_neg_get_state(inv->neg)) { 
     1373 
     1374            case PJMEDIA_SDP_NEG_STATE_NULL: 
     1375                pj_assert(!"Unexpected SDP neg state NULL"); 
     1376                status = PJ_EBUG; 
     1377                goto on_return; 
     1378 
     1379            case PJMEDIA_SDP_NEG_STATE_LOCAL_OFFER: 
     1380                PJ_LOG(4,(inv->obj_name,  
     1381                          "pjsip_inv_reinvite: already have an offer, new " 
     1382                          "offer is ignored")); 
     1383                break; 
     1384 
     1385            case PJMEDIA_SDP_NEG_STATE_REMOTE_OFFER: 
     1386                status = pjmedia_sdp_neg_set_local_answer(inv->pool, inv->neg, 
     1387                                                          new_offer); 
     1388                if (status != PJ_SUCCESS) 
     1389                    goto on_return; 
     1390                break; 
     1391 
     1392            case PJMEDIA_SDP_NEG_STATE_WAIT_NEGO: 
     1393                PJ_LOG(4,(inv->obj_name,  
     1394                          "pjsip_inv_reinvite: SDP in WAIT_NEGO state, new " 
     1395                          "offer is ignored")); 
     1396                break; 
     1397 
     1398            case PJMEDIA_SDP_NEG_STATE_DONE: 
     1399                status = pjmedia_sdp_neg_modify_local_offer(inv->pool,inv->neg, 
     1400                                                            new_offer); 
     1401                if (status != PJ_SUCCESS) 
     1402                    goto on_return; 
     1403                break; 
     1404        } 
     1405    } 
     1406 
     1407    if (contact_hdr) 
     1408        inv->dlg->local.contact = contact_hdr; 
     1409 
     1410    status = pjsip_inv_invite(inv, p_tdata); 
     1411 
     1412on_return: 
     1413    pjsip_dlg_dec_lock(inv->dlg); 
     1414    return status; 
    12571415} 
    12581416 
     
    19092067 
    19102068    } 
     2069    else if (tsx->method.id == PJSIP_INVITE_METHOD && 
     2070             tsx->role == PJSIP_ROLE_UAS) 
     2071    { 
     2072 
     2073        /* 
     2074         * Handle incoming re-INVITE 
     2075         */ 
     2076        if (tsx->state == PJSIP_TSX_STATE_TRYING) { 
     2077             
     2078            pjsip_rx_data *rdata = e->body.tsx_state.src.rdata; 
     2079            pjsip_tx_data *tdata; 
     2080            pj_status_t status; 
     2081 
     2082            /* Check if we have INVITE pending. */ 
     2083            if (inv->invite_tsx && inv->invite_tsx!=tsx) { 
     2084 
     2085                /* Can not receive re-INVITE while another one is pending. */ 
     2086                status = pjsip_dlg_create_response( inv->dlg, rdata, 500, NULL, 
     2087                                                    &tdata); 
     2088                if (status != PJ_SUCCESS) 
     2089                    return; 
     2090 
     2091                status = pjsip_dlg_send_response( inv->dlg, tsx, tdata); 
     2092                 
     2093 
     2094                return; 
     2095            } 
     2096 
     2097            /* Save the invite transaction. */ 
     2098            inv->invite_tsx = tsx; 
     2099 
     2100            /* Process SDP in incoming message. */ 
     2101            status = inv_check_sdp_in_incoming_msg(inv, tsx, rdata); 
     2102 
     2103            if (status != PJ_SUCCESS) { 
     2104 
     2105                /* Not Acceptable */ 
     2106                const pjsip_hdr *accept; 
     2107 
     2108                status = pjsip_dlg_create_response(inv->dlg, rdata,  
     2109                                                   488, NULL, &tdata); 
     2110                if (status != PJ_SUCCESS) 
     2111                    return; 
     2112 
     2113 
     2114                accept = pjsip_endpt_get_capability(dlg->endpt, PJSIP_H_ACCEPT, 
     2115                                                    NULL); 
     2116                if (accept) { 
     2117                    pjsip_msg_add_hdr(tdata->msg, 
     2118                                      pjsip_hdr_clone(tdata->pool, accept)); 
     2119                } 
     2120 
     2121                status = pjsip_dlg_send_response(dlg, tsx, tdata); 
     2122 
     2123                return; 
     2124            } 
     2125 
     2126            /* Create 2xx ANSWER */ 
     2127            status = pjsip_dlg_create_response(dlg, rdata, 200, NULL, &tdata); 
     2128            if (status != PJ_SUCCESS) 
     2129                return; 
     2130 
     2131            /* Process SDP in the answer */ 
     2132            status = process_answer(inv, 200, tdata); 
     2133            if (status != PJ_SUCCESS) 
     2134                return; 
     2135 
     2136            status = pjsip_inv_send_msg(inv, tdata, NULL); 
     2137 
     2138        } 
     2139 
     2140    } 
     2141    else if (tsx->method.id == PJSIP_INVITE_METHOD && 
     2142             tsx->role == PJSIP_ROLE_UAC) 
     2143    { 
     2144        /* 
     2145         * Handle outgoing re-INVITE 
     2146         */ 
     2147        if (tsx->state == PJSIP_TSX_STATE_TERMINATED && 
     2148            tsx->status_code/100 == 2)  
     2149        { 
     2150 
     2151            /* Re-INVITE was accepted. */ 
     2152 
     2153            /* Process SDP */ 
     2154            inv_check_sdp_in_incoming_msg(inv, tsx,  
     2155                                          e->body.tsx_state.src.rdata); 
     2156 
     2157            /* Send ACK */ 
     2158            inv_send_ack(inv, e->body.tsx_state.src.rdata); 
     2159 
     2160        } else if (tsx->state == PJSIP_TSX_STATE_COMPLETED && 
     2161                   (tsx->status_code==401 || tsx->status_code==407)) 
     2162        { 
     2163            pjsip_tx_data *tdata; 
     2164            pj_status_t status; 
     2165 
     2166            /* Handle authentication challenge. */ 
     2167            status = pjsip_auth_clt_reinit_req( &dlg->auth_sess, 
     2168                                                e->body.tsx_state.src.rdata, 
     2169                                                tsx->last_tx, 
     2170                                                &tdata); 
     2171            if (status != PJ_SUCCESS) 
     2172                return; 
     2173 
     2174            /* Send re-INVITE */ 
     2175            status = pjsip_inv_send_msg( inv, tdata, NULL); 
     2176 
     2177        } else if (tsx->status_code==PJSIP_SC_CALL_TSX_DOES_NOT_EXIST || 
     2178                   tsx->status_code==PJSIP_SC_REQUEST_TIMEOUT || 
     2179                   tsx->status_code >= 700) 
     2180        { 
     2181            /* 
     2182             * Handle responses that terminates dialog. 
     2183             */ 
     2184            inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e); 
     2185        } 
     2186    } 
    19112187} 
    19122188 
  • pjproject/trunk/pjsip/src/pjsip/sip_dialog.c

    r196 r212  
    7979    dlg->state = PJSIP_DIALOG_STATE_NULL; 
    8080 
     81    pj_list_init(&dlg->inv_hdr); 
     82 
    8183    status = pj_mutex_create_recursive(pool, "dlg%p", &dlg->mutex); 
    8284    if (status != PJ_SUCCESS) 
     
    132134    } 
    133135 
     136    /* Put any header param in the target URI into INVITE header list. */ 
     137    if (PJSIP_URI_SCHEME_IS_SIP(dlg->target) || 
     138        PJSIP_URI_SCHEME_IS_SIPS(dlg->target)) 
     139    { 
     140        pjsip_param *param; 
     141        pjsip_sip_uri *uri = (pjsip_sip_uri*)pjsip_uri_get_uri(dlg->target); 
     142 
     143        param = uri->header_param.next; 
     144        while (param != &uri->header_param) { 
     145            pjsip_generic_string_hdr *req_hdr; 
     146 
     147            req_hdr = pjsip_generic_string_hdr_create(dlg->pool, &param->name, 
     148                                                      &param->value); 
     149            pj_list_push_back(&dlg->inv_hdr, req_hdr); 
     150 
     151            param = param->next; 
     152        } 
     153    } 
     154 
    134155    /* Init local info. */ 
    135156    dlg->local.info = pjsip_from_hdr_create(dlg->pool); 
    136     pj_strdup_with_null(dlg->pool, &tmp, local_uri); 
    137     dlg->local.info->uri = pjsip_parse_uri(dlg->pool, tmp.ptr, tmp.slen, 0); 
     157    pj_strdup_with_null(dlg->pool, &dlg->local.info_str, local_uri); 
     158    dlg->local.info->uri = pjsip_parse_uri(dlg->pool,  
     159                                           dlg->local.info_str.ptr,  
     160                                           dlg->local.info_str.slen, 0); 
    138161    if (!dlg->local.info->uri) { 
    139162        status = PJSIP_EINVALIDURI; 
     
    165188    /* Init remote info. */ 
    166189    dlg->remote.info = pjsip_to_hdr_create(dlg->pool); 
    167     pj_strdup_with_null(dlg->pool, &tmp, remote_uri); 
    168     dlg->remote.info->uri = pjsip_parse_uri(dlg->pool, tmp.ptr, tmp.slen, 0); 
     190    pj_strdup_with_null(dlg->pool, &dlg->remote.info_str, remote_uri); 
     191    dlg->remote.info->uri = pjsip_parse_uri(dlg->pool,  
     192                                            dlg->remote.info_str.ptr,  
     193                                            dlg->remote.info_str.slen, 0); 
    169194    if (!dlg->remote.info->uri) { 
    170195        status = PJSIP_EINVALIDURI; 
     
    226251    pjsip_rr_hdr *rr; 
    227252    pjsip_transaction *tsx = NULL; 
     253    pj_str_t tmp; 
     254    enum { TMP_LEN=128}; 
     255    pj_ssize_t len; 
    228256    pjsip_dialog *dlg; 
    229257 
     
    250278        return status; 
    251279 
     280    /* Temprary string for getting the string representation of 
     281     * both local and remote URI. 
     282     */ 
     283    tmp.ptr = pj_pool_alloc(rdata->tp_info.pool, TMP_LEN); 
     284 
    252285    /* Init local info from the To header. */ 
    253286    dlg->local.info = pjsip_hdr_clone(dlg->pool, rdata->msg_info.to); 
     
    257290    pj_create_unique_string(dlg->pool, &dlg->local.info->tag); 
    258291 
     292 
     293    /* Print the local info. */ 
     294    len = pjsip_uri_print(PJSIP_URI_IN_FROMTO_HDR, 
     295                          dlg->local.info->uri, tmp.ptr, TMP_LEN); 
     296    if (len < 1) { 
     297        pj_ansi_strcpy(tmp.ptr, "<-error: uri too long->"); 
     298        tmp.slen = pj_ansi_strlen(tmp.ptr); 
     299    } else 
     300        tmp.slen = len; 
     301 
     302    /* Save the local info. */ 
     303    pj_strdup(dlg->pool, &dlg->local.info_str, &tmp); 
     304 
    259305    /* Calculate hash value of local tag. */ 
    260306    dlg->local.tag_hval = pj_hash_calc(0, dlg->local.info->tag.ptr, 
    261307                                       dlg->local.info->tag.slen); 
     308 
     309    /* Print the local info. */ 
     310    len = pjsip_uri_print(PJSIP_URI_IN_FROMTO_HDR, 
     311                          dlg->local.info->uri, tmp.ptr, TMP_LEN); 
     312    if (len < 1) { 
     313        pj_ansi_strcpy(tmp.ptr, "<-error: uri too long->"); 
     314        tmp.slen = pj_ansi_strlen(tmp.ptr); 
     315    } else 
     316        tmp.slen = len; 
     317 
     318    /* Save the local info. */ 
     319    pj_strdup(dlg->pool, &dlg->remote.info_str, &tmp); 
     320 
    262321 
    263322    /* Randomize local cseq */ 
     
    10861145                                             pjsip_tx_data *tdata) 
    10871146{ 
     1147    pj_status_t status; 
     1148 
    10881149    /* Sanity check. */ 
    10891150    PJ_ASSERT_RETURN(dlg && tsx && tdata && tdata->msg, PJ_EINVAL); 
     
    11081169#endif 
    11091170 
    1110     return pjsip_tsx_send_msg(tsx, tdata); 
     1171    /* Must acquire dialog first, to prevent deadlock */ 
     1172    pjsip_dlg_inc_lock(dlg); 
     1173 
     1174    status = pjsip_tsx_send_msg(tsx, tdata); 
     1175 
     1176    pjsip_dlg_dec_lock(dlg); 
     1177 
     1178    return status; 
    11111179} 
    11121180 
  • pjproject/trunk/pjsip/src/pjsip/sip_endpoint.c

    r197 r212  
    325325                     htype==PJSIP_H_SUPPORTED, 
    326326                     PJ_EINVAL); 
     327 
     328    PJ_UNUSED_ARG(mod); 
    327329 
    328330    /* Find the header. */ 
  • pjproject/trunk/pjsip/src/pjsip/sip_msg.c

    r197 r212  
    17471747} 
    17481748 
     1749PJ_DEF(void*) pjsip_clone_text_data( pj_pool_t *pool, const void *data, 
     1750                                     unsigned len) 
     1751{ 
     1752    char *newdata = ""; 
     1753 
     1754    if (len) { 
     1755        newdata = pj_pool_alloc(pool, len); 
     1756        pj_memcpy(newdata, data, len); 
     1757    } 
     1758    return newdata; 
     1759} 
     1760 
    17491761PJ_DEF(pj_status_t) pjsip_msg_body_clone( pj_pool_t *pool, 
    17501762                                          pjsip_msg_body *dst_body, 
  • pjproject/trunk/pjsip/src/pjsua/main.c

    r205 r212  
    114114                    "%s (%.*s;expires=%d)", 
    115115                    pjsip_get_status_text(pjsua.regc_last_code)->ptr, 
    116                     (int)info.server_uri.slen, 
    117                     info.server_uri.ptr, 
     116                    (int)info.client_uri.slen, 
     117                    info.client_uri.ptr, 
    118118                    info.next_reg); 
    119119 
     
    132132    puts("|                              |                          |                   |"); 
    133133    puts("|  m  Make new call            |  i  Send IM              |  o  Send OPTIONS  |"); 
    134     puts("|  a  Answer call              |  s  Subscribe presence   |  R  (Re-)register |"); 
    135     puts("|  h  Hangup call              |  u  Unsubscribe presence |  r  Unregister    |"); 
    136     puts("|  ]  Select next dialog       |  t  Toggle Online status |  d  Dump status   |"); 
     134    puts("|  a  Answer call              |  s  Subscribe presence   | rr  (Re-)register |"); 
     135    puts("|  h  Hangup call              |  u  Unsubscribe presence | ru  Unregister    |"); 
     136    puts("|  ]  Select next dialog       |  t  ToGgle Online status |  d  Dump status   |"); 
    137137    puts("|  [  Select previous dialog   |                          |                   |"); 
    138     puts("+-----------------------------------------------------------------------------+"); 
    139     puts("|      Conference Command                                                     |"); 
    140     puts("| cl  List ports                                                              |"); 
    141     puts("| cc  Connect port                                                            |"); 
    142     puts("| cd  Disconnect port                                                         |"); 
    143     puts("+-----------------------------------------------------------------------------+"); 
     138    puts("|                              +--------------------------+-------------------+"); 
     139    puts("|  H  Hold call                |     Conference Command   |                   |"); 
     140    puts("|  v  re-inVite (release hold) | cl  List ports           |                   |"); 
     141    puts("|  x  Xfer call                | cc  Connect port         |                   |"); 
     142    puts("|                              | cd  Disconnect port      |                   |"); 
     143    puts("+------------------------------+--------------------------+-------------------+"); 
    144144    puts("|  q  QUIT                                                                    |"); 
    145145    puts("+=============================================================================+"); 
     
    284284    char menuin[10]; 
    285285    char buf[128]; 
    286     pjsip_inv_session *inv; 
    287286    struct input_result result; 
    288287 
     
    306305                    puts("You can't do that with make call!"); 
    307306                else 
    308                     pjsua_invite(pjsua.buddies[result.nb_result].uri.ptr, &inv); 
     307                    pjsua_invite(pjsua.buddies[result.nb_result].uri.ptr, NULL); 
    309308            } else if (result.uri_result) 
    310                 pjsua_invite(result.uri_result, &inv); 
     309                pjsua_invite(result.uri_result, NULL); 
    311310             
    312311            break; 
     
    354353 
    355354            } else { 
    356                 pj_status_t status; 
    357                 pjsip_tx_data *tdata; 
    358  
    359                 status = pjsip_inv_end_session(inv_session->inv,  
    360                                                PJSIP_SC_DECLINE, NULL, &tdata); 
    361                 if (status != PJ_SUCCESS) { 
    362                     pjsua_perror(THIS_FILE,  
    363                                  "Failed to create end session message",  
    364                                  status); 
    365                     continue; 
     355                pjsua_inv_hangup(inv_session, PJSIP_SC_DECLINE); 
     356            } 
     357            break; 
     358 
     359        case ']': 
     360        case '[': 
     361            /* 
     362             * Cycle next/prev dialog. 
     363             */ 
     364            if (menuin[0] == ']') { 
     365                inv_session = inv_session->next; 
     366                if (inv_session == &pjsua.inv_list) 
     367                    inv_session = pjsua.inv_list.next; 
     368 
     369            } else { 
     370                inv_session = inv_session->prev; 
     371                if (inv_session == &pjsua.inv_list) 
     372                    inv_session = pjsua.inv_list.prev; 
     373            } 
     374 
     375            if (inv_session != &pjsua.inv_list) { 
     376                char url[PJSIP_MAX_URL_SIZE]; 
     377                int len; 
     378 
     379                len = pjsip_uri_print(0, inv_session->inv->dlg->remote.info->uri, 
     380                                      url, sizeof(url)-1); 
     381                if (len < 1) { 
     382                    pj_ansi_strcpy(url, "<uri is too long>"); 
     383                } else { 
     384                    url[len] = '\0'; 
    366385                } 
    367386 
    368                 status = pjsip_inv_send_msg(inv_session->inv, tdata, NULL); 
    369                 if (status != PJ_SUCCESS) { 
    370                     pjsua_perror(THIS_FILE,  
    371                                  "Failed to send end session message",  
    372                                  status); 
    373                     continue; 
     387                PJ_LOG(3,(THIS_FILE,"Current dialog: %s", url)); 
     388 
     389            } else { 
     390                PJ_LOG(3,(THIS_FILE,"No current dialog")); 
     391            } 
     392            break; 
     393 
     394        case 'H': 
     395            /* 
     396             * Hold call. 
     397             */ 
     398            if (inv_session != &pjsua.inv_list) { 
     399                 
     400                pjsua_inv_set_hold(inv_session); 
     401 
     402            } else { 
     403                PJ_LOG(3,(THIS_FILE, "No current call")); 
     404            } 
     405            break; 
     406 
     407        case 'v': 
     408            /* 
     409             * Send re-INVITE (to release hold, etc). 
     410             */ 
     411            if (inv_session != &pjsua.inv_list) { 
     412                 
     413                pjsua_inv_reinvite(inv_session); 
     414 
     415            } else { 
     416                PJ_LOG(3,(THIS_FILE, "No current call")); 
     417            } 
     418            break; 
     419 
     420        case 'x': 
     421            /* 
     422             * Transfer call. 
     423             */ 
     424            if (inv_session == &pjsua.inv_list) { 
     425                 
     426                PJ_LOG(3,(THIS_FILE, "No current call")); 
     427 
     428            } else { 
     429                ui_input_url("Transfer to URL", buf, sizeof(buf), &result); 
     430                if (result.nb_result != NO_NB) { 
     431                    if (result.nb_result == -1)  
     432                        puts("You can't do that with transfer call!"); 
     433                    else 
     434                        pjsua_inv_xfer_call( inv_session, 
     435                                             pjsua.buddies[result.nb_result].uri.ptr); 
     436 
     437                } else if (result.uri_result) { 
     438                    pjsua_inv_xfer_call( inv_session, result.uri_result); 
    374439                } 
    375440            } 
    376             break; 
    377  
    378         case ']': 
    379             inv_session = inv_session->next; 
    380             if (inv_session == &pjsua.inv_list) 
    381                 inv_session = pjsua.inv_list.next; 
    382             break; 
    383  
    384         case '[': 
    385             inv_session = inv_session->prev; 
    386             if (inv_session == &pjsua.inv_list) 
    387                 inv_session = pjsua.inv_list.prev; 
    388441            break; 
    389442 
    390443        case 's': 
    391444        case 'u': 
    392             ui_input_url("Subscribe presence of", buf, sizeof(buf), &result); 
     445            /* 
     446             * Subscribe/unsubscribe presence. 
     447             */ 
     448            ui_input_url("(un)Subscribe presence of", buf, sizeof(buf), &result); 
    393449            if (result.nb_result != NO_NB) { 
    394450                if (result.nb_result == -1) { 
     
    403459 
    404460            } else if (result.uri_result) { 
    405                 puts("Sorry, can only subscribe to buddy's presence, not arbitrary URL (for now)"); 
    406             } 
    407  
    408             break; 
    409  
    410         case 'R': 
    411             pjsua_regc_update(PJ_TRUE); 
     461                puts("Sorry, can only subscribe to buddy's presence, " 
     462                     "not arbitrary URL (for now)"); 
     463            } 
     464 
     465            break; 
     466 
     467        case 'r': 
     468            switch (menuin[1]) { 
     469            case 'r': 
     470                /* 
     471                 * Re-Register. 
     472                 */ 
     473                pjsua_regc_update(PJ_TRUE); 
     474                break; 
     475            case 'u': 
     476                /* 
     477                 * Unregister 
     478                 */ 
     479                pjsua_regc_update(PJ_FALSE); 
     480                break; 
     481            } 
    412482            break; 
    413483             
    414         case 'r': 
    415             pjsua_regc_update(PJ_FALSE); 
    416             break; 
    417  
    418484        case 't': 
    419485            pjsua.online_status = !pjsua.online_status; 
     
    431497                    char src_port[10], dst_port[10]; 
    432498                    pj_status_t status; 
    433  
    434                     if (!simple_input("Connect src port #:", src_port, sizeof(src_port))) 
     499                    const char *src_title, *dst_title; 
     500 
     501                    conf_list(); 
     502 
     503                    src_title = (menuin[1]=='c'? 
     504                                 "Connect src port #": 
     505                                 "Disconnect src port #"); 
     506                    dst_title = (menuin[1]=='c'? 
     507                                 "To dst port #": 
     508                                 "From dst port #"); 
     509 
     510                    if (!simple_input(src_title, src_port, sizeof(src_port))) 
    435511                        break; 
    436                     if (!simple_input("To dst port #:", dst_port, sizeof(dst_port))) 
     512 
     513                    if (!simple_input(dst_title, dst_port, sizeof(dst_port))) 
    437514                        break; 
    438515 
    439516                    if (menuin[1]=='c') { 
    440                         status = pjmedia_conf_connect_port(pjsua.mconf, atoi(src_port), atoi(dst_port)); 
     517                        status = pjmedia_conf_connect_port(pjsua.mconf,  
     518                                                           atoi(src_port),  
     519                                                           atoi(dst_port)); 
    441520                    } else { 
    442                         status = pjmedia_conf_disconnect_port(pjsua.mconf, atoi(src_port), atoi(dst_port)); 
     521                        status = pjmedia_conf_disconnect_port(pjsua.mconf,  
     522                                                              atoi(src_port),  
     523                                                              atoi(dst_port)); 
    443524                    } 
    444525                    if (status == PJ_SUCCESS) { 
  • pjproject/trunk/pjsip/src/pjsua/pjsua.h

    r205 r212  
    6969    unsigned             conf_slot; /**< Slot # in conference bridge.       */ 
    7070    unsigned             call_slot; /**< RTP media index in med_sock_use[]  */ 
     71    pjsip_evsub         *xfer_sub;  /**< Xfer server subscription, if this 
     72                                         call was triggered by xfer.        */ 
    7173}; 
    7274 
     
    255257 */ 
    256258pj_status_t pjsua_invite(const char *cstr_dest_uri, 
    257                          pjsip_inv_session **p_inv); 
     259                         struct pjsua_inv_data **p_inv_data); 
    258260 
    259261 
     
    262264 */ 
    263265pj_bool_t pjsua_inv_on_incoming(pjsip_rx_data *rdata); 
     266 
     267 
     268/** 
     269 * Hangup call. 
     270 */ 
     271void pjsua_inv_hangup(struct pjsua_inv_data *inv_session, int code); 
     272 
     273 
     274/** 
     275 * Put call on-hold. 
     276 */ 
     277void pjsua_inv_set_hold(struct pjsua_inv_data *inv_session); 
     278 
     279 
     280/** 
     281 * Send re-INVITE (to release hold). 
     282 */ 
     283void pjsua_inv_reinvite(struct pjsua_inv_data *inv_session); 
     284 
     285 
     286/** 
     287 * Transfer call. 
     288 */ 
     289void pjsua_inv_xfer_call(struct pjsua_inv_data *inv_session, 
     290                         const char *dest); 
    264291 
    265292 
     
    284311void pjsua_inv_on_media_update(pjsip_inv_session *inv, pj_status_t status); 
    285312 
     313/** 
     314 * Callback called when invite session received new offer. 
     315 */ 
     316void pjsua_inv_on_rx_offer( pjsip_inv_session *inv, 
     317                            const pjmedia_sdp_session *offer); 
     318 
     319/** 
     320 * Callback to receive transaction state inside invite session or dialog 
     321 * (e.g. REFER, MESSAGE). 
     322 */ 
     323void pjsua_inv_on_tsx_state_changed(pjsip_inv_session *inv, 
     324                                    pjsip_transaction *tsx, 
     325                                    pjsip_event *e); 
    286326 
    287327/** 
  • pjproject/trunk/pjsip/src/pjsua/pjsua_core.c

    r205 r212  
    142142        RTP_START_PORT = 4000, 
    143143        RTP_RANDOM_START = 2, 
    144         RTP_RETRY = 10  
     144        RTP_RETRY = 20  
    145145    }; 
    146146    enum { 
     
    393393        inv_cb.on_new_session = &pjsua_inv_on_new_session; 
    394394        inv_cb.on_media_update = &pjsua_inv_on_media_update; 
     395        inv_cb.on_rx_offer = &pjsua_inv_on_rx_offer; 
     396        inv_cb.on_tsx_state_changed = &pjsua_inv_on_tsx_state_changed; 
     397 
    395398 
    396399        /* Initialize invite session module: */ 
     
    480483    pjsip_pres_init_module( pjsua.endpt, pjsip_evsub_instance()); 
    481484 
     485    /* Init xfer/REFER module */ 
     486 
     487    pjsip_xfer_init_module( pjsua.endpt ); 
    482488 
    483489    /* Init pjsua presence handler: */ 
     
    752758    busy_sleep(1000); 
    753759 
     760    /* Destroy conference bridge. */ 
     761    if (pjsua.mconf) 
     762        pjmedia_conf_destroy(pjsua.mconf); 
     763 
    754764    /* Shutdown pjmedia-codec: */ 
    755765    pjmedia_codec_deinit(); 
  • pjproject/trunk/pjsip/src/pjsua/pjsua_inv.c

    r205 r212  
    3434 */ 
    3535pj_status_t pjsua_invite(const char *cstr_dest_uri, 
    36                          pjsip_inv_session **p_inv) 
     36                         struct pjsua_inv_data **p_inv_data) 
    3737{ 
    3838    pj_str_t dest_uri; 
     
    137137 
    138138    /* Done. */ 
    139  
    140     *p_inv = inv; 
     139    if (p_inv_data) 
     140        *p_inv_data = inv_data; 
    141141 
    142142    return PJ_SUCCESS; 
     
    159159    pjsip_transaction *tsx = pjsip_rdata_get_tsx(rdata); 
    160160    pjsip_msg *msg = rdata->msg_info.msg; 
     161    pjsip_tx_data *response = NULL; 
     162    unsigned options = 0; 
     163    pjsip_inv_session *inv; 
     164    struct pjsua_inv_data *inv_data; 
     165    pjmedia_sdp_session *answer; 
     166    int med_sk_index; 
     167    pj_status_t status; 
     168 
     169    /* Don't want to handle anything but INVITE */ 
     170    if (msg->line.req.method.id != PJSIP_INVITE_METHOD) 
     171        return PJ_FALSE; 
     172 
     173    /* Don't want to handle anything that's already associated with 
     174     * existing dialog or transaction. 
     175     */ 
     176    if (dlg || tsx) 
     177        return PJ_FALSE; 
     178 
     179 
     180    /* Verify that we can handle the request. */ 
     181    status = pjsip_inv_verify_request(rdata, &options, NULL, NULL, 
     182                                      pjsua.endpt, &response); 
     183    if (status != PJ_SUCCESS) { 
     184 
     185        /* 
     186         * No we can't handle the incoming INVITE request. 
     187         */ 
     188 
     189        if (response) { 
     190            pjsip_response_addr res_addr; 
     191 
     192            pjsip_get_response_addr(response->pool, rdata, &res_addr); 
     193            pjsip_endpt_send_response(pjsua.endpt, &res_addr, response,  
     194                                      NULL, NULL); 
     195 
     196        } else { 
     197 
     198            /* Respond with 500 (Internal Server Error) */ 
     199            pjsip_endpt_respond_stateless(pjsua.endpt, rdata, 500, NULL, 
     200                                          NULL, NULL); 
     201        } 
     202 
     203        return PJ_TRUE; 
     204    }  
     205 
    161206 
    162207    /* 
    163      * Handle incoming INVITE outside dialog. 
    164      */ 
    165     if (dlg == NULL && tsx == NULL && 
    166         msg->line.req.method.id == PJSIP_INVITE_METHOD) 
    167     { 
    168         pj_status_t status; 
    169         pjsip_tx_data *response = NULL; 
    170         unsigned options = 0; 
    171  
    172         /* Verify that we can handle the request. */ 
    173         status = pjsip_inv_verify_request(rdata, &options, NULL, NULL, 
    174                                           pjsua.endpt, &response); 
    175         if (status != PJ_SUCCESS) { 
    176  
    177             /* 
    178              * No we can't handle the incoming INVITE request. 
    179              */ 
    180  
    181             if (response) { 
    182                 pjsip_response_addr res_addr; 
    183  
    184                 pjsip_get_response_addr(response->pool, rdata, &res_addr); 
    185                 pjsip_endpt_send_response(pjsua.endpt, &res_addr, response,  
    186                                           NULL, NULL); 
    187  
    188             } else { 
    189  
    190                 /* Respond with 500 (Internal Server Error) */ 
    191                 pjsip_endpt_respond_stateless(pjsua.endpt, rdata, 500, NULL, 
    192                                               NULL, NULL); 
    193             } 
    194  
    195         } else { 
    196             /* 
    197              * Yes we can handle the incoming INVITE request. 
    198              */ 
    199             pjsip_inv_session *inv; 
    200             struct pjsua_inv_data *inv_data; 
    201             pjmedia_sdp_session *answer; 
    202             int med_sk_index; 
    203  
    204  
    205             /* Find free socket. */ 
    206             for (med_sk_index=0; med_sk_index<PJSUA_MAX_CALLS; ++med_sk_index) { 
    207                 if (!pjsua.med_sock_use[med_sk_index]) 
    208                     break; 
    209             } 
    210  
    211             if (med_sk_index == PJSUA_MAX_CALLS) { 
    212                 PJ_LOG(3,(THIS_FILE, "Error: too many calls!")); 
    213                 return PJ_TRUE; 
    214             } 
    215  
    216  
    217             pjsua.med_sock_use[med_sk_index] = 1; 
    218  
    219             /* Get media capability from media endpoint: */ 
    220  
    221             status = pjmedia_endpt_create_sdp( pjsua.med_endpt, rdata->tp_info.pool, 
    222                                                1, &pjsua.med_sock_info[med_sk_index],  
    223                                                &answer ); 
    224             if (status != PJ_SUCCESS) { 
    225  
    226                 pjsip_endpt_respond_stateless(pjsua.endpt, rdata, 500, NULL, 
    227                                               NULL, NULL); 
    228                 pjsua.med_sock_use[med_sk_index] = 0; 
    229                 return PJ_TRUE; 
    230             } 
    231  
    232             /* Create dialog: */ 
    233  
    234             status = pjsip_dlg_create_uas( pjsip_ua_instance(), rdata, 
    235                                            &pjsua.contact_uri, &dlg); 
    236             if (status != PJ_SUCCESS) { 
    237                 pjsua.med_sock_use[med_sk_index] = 0; 
    238                 return PJ_TRUE; 
    239             } 
    240  
    241  
    242             /* Create invite session: */ 
    243  
    244             status = pjsip_inv_create_uas( dlg, rdata, answer, 0, &inv); 
    245             if (status != PJ_SUCCESS) { 
    246  
    247                 status = pjsip_dlg_create_response( dlg, rdata, 500, NULL, 
    248                                                     &response); 
    249                 if (status == PJ_SUCCESS) 
    250                     status = pjsip_dlg_send_response(dlg,  
    251                                                      pjsip_rdata_get_tsx(rdata), 
    252                                                      response); 
    253                 pjsua.med_sock_use[med_sk_index] = 0; 
    254                 return PJ_TRUE; 
    255  
    256             } 
    257  
    258  
    259             /* Create and attach pjsua data to the dialog: */ 
    260  
    261             inv_data = pj_pool_zalloc(dlg->pool, sizeof(struct pjsua_inv_data)); 
    262             inv_data->inv = inv; 
    263             inv_data->call_slot = inv_data->call_slot = med_sk_index; 
    264             dlg->mod_data[pjsua.mod.id] = inv_data; 
    265             inv->mod_data[pjsua.mod.id] = inv_data; 
    266  
    267             pj_list_push_back(&pjsua.inv_list, inv_data); 
    268  
    269  
    270             /* Answer with 100 (using the dialog, not invite): */ 
    271  
    272             status = pjsip_dlg_create_response(dlg, rdata, 100, NULL, &response); 
    273             if (status == PJ_SUCCESS) 
    274                 status = pjsip_dlg_send_response(dlg, pjsip_rdata_get_tsx(rdata), response); 
    275         } 
    276  
    277         /* This INVITE request has been handled. */ 
     208     * Yes we can handle the incoming INVITE request. 
     209     */ 
     210 
     211    /* Find free call slot. */ 
     212    for (med_sk_index=0; med_sk_index<PJSUA_MAX_CALLS; ++med_sk_index) { 
     213        if (!pjsua.med_sock_use[med_sk_index]) 
     214            break; 
     215    } 
     216 
     217    if (med_sk_index == PJSUA_MAX_CALLS) { 
     218        pjsip_endpt_respond_stateless(pjsua.endpt, rdata,  
     219                                      PJSIP_SC_BUSY_HERE, NULL, 
     220                                      NULL, NULL); 
    278221        return PJ_TRUE; 
    279222    } 
    280223 
    281     return PJ_FALSE; 
     224 
     225    pjsua.med_sock_use[med_sk_index] = 1; 
     226 
     227    /* Get media capability from media endpoint: */ 
     228 
     229    status = pjmedia_endpt_create_sdp( pjsua.med_endpt, rdata->tp_info.pool, 
     230                                       1, &pjsua.med_sock_info[med_sk_index],  
     231                                       &answer ); 
     232    if (status != PJ_SUCCESS) { 
     233        pjsip_endpt_respond_stateless(pjsua.endpt, rdata, 500, NULL, 
     234                                      NULL, NULL); 
     235 
     236        /* Free call socket. */ 
     237        pjsua.med_sock_use[med_sk_index] = 0; 
     238        return PJ_TRUE; 
     239    } 
     240 
     241    /* Create dialog: */ 
     242 
     243    status = pjsip_dlg_create_uas( pjsip_ua_instance(), rdata, 
     244                                   &pjsua.contact_uri, &dlg); 
     245    if (status != PJ_SUCCESS) { 
     246        pjsip_endpt_respond_stateless(pjsua.endpt, rdata, 500, NULL, 
     247                                      NULL, NULL); 
     248 
     249        /* Free call socket. */ 
     250        pjsua.med_sock_use[med_sk_index] = 0; 
     251        return PJ_TRUE; 
     252    } 
     253 
     254 
     255    /* Create invite session: */ 
     256 
     257    status = pjsip_inv_create_uas( dlg, rdata, answer, 0, &inv); 
     258    if (status != PJ_SUCCESS) { 
     259 
     260        pjsip_dlg_respond(dlg, rdata, 500, NULL); 
     261 
     262        /* Free call socket. */ 
     263        pjsua.med_sock_use[med_sk_index] = 0; 
     264 
     265        // TODO: Need to delete dialog 
     266        return PJ_TRUE; 
     267    } 
     268 
     269 
     270    /* Create and attach pjsua data to the dialog: */ 
     271 
     272    inv_data = pj_pool_zalloc(dlg->pool, sizeof(struct pjsua_inv_data)); 
     273    inv_data->inv = inv; 
     274    inv_data->call_slot = inv_data->call_slot = med_sk_index; 
     275    dlg->mod_data[pjsua.mod.id] = inv_data; 
     276    inv->mod_data[pjsua.mod.id] = inv_data; 
     277 
     278    pj_list_push_back(&pjsua.inv_list, inv_data); 
     279 
     280 
     281    /* Answer with 100 (using the dialog, not invite): */ 
     282 
     283    status = pjsip_dlg_create_response(dlg, rdata, 100, NULL, &response); 
     284    if (status != PJ_SUCCESS) { 
     285         
     286        pjsip_dlg_respond(dlg, rdata, 500, NULL); 
     287 
     288        /* Free call socket. */ 
     289        pjsua.med_sock_use[med_sk_index] = 0; 
     290 
     291        // TODO: Need to delete dialog 
     292 
     293    } else { 
     294        status = pjsip_dlg_send_response(dlg, pjsip_rdata_get_tsx(rdata),  
     295                                         response); 
     296    } 
     297 
     298    /* This INVITE request has been handled. */ 
     299    return PJ_TRUE; 
    282300} 
    283301 
     
    289307void pjsua_inv_on_state_changed(pjsip_inv_session *inv, pjsip_event *e) 
    290308{ 
     309    struct pjsua_inv_data *inv_data; 
     310 
     311    inv_data = inv->dlg->mod_data[pjsua.mod.id]; 
     312 
     313    /* If this is an outgoing INVITE that was created because of 
     314     * REFER/transfer, send NOTIFY to transferer. 
     315     */ 
     316    if (inv_data && inv_data->xfer_sub && e->type==PJSIP_EVENT_TSX_STATE)  
     317    { 
     318        int st_code = -1; 
     319        pjsip_evsub_state ev_state = PJSIP_EVSUB_STATE_ACTIVE; 
     320         
     321 
     322        switch (inv->state) { 
     323        case PJSIP_INV_STATE_NULL: 
     324        case PJSIP_INV_STATE_CALLING: 
     325            /* Do nothing */ 
     326            break; 
     327 
     328        case PJSIP_INV_STATE_EARLY: 
     329        case PJSIP_INV_STATE_CONNECTING: 
     330            st_code = e->body.tsx_state.tsx->status_code; 
     331            ev_state = PJSIP_EVSUB_STATE_ACTIVE; 
     332            break; 
     333 
     334        case PJSIP_INV_STATE_CONFIRMED: 
     335            /* When state is confirmed, send the final 200/OK and terminate 
     336             * subscription. 
     337             */ 
     338            st_code = e->body.tsx_state.tsx->status_code; 
     339            ev_state = PJSIP_EVSUB_STATE_TERMINATED; 
     340            break; 
     341 
     342        case PJSIP_INV_STATE_DISCONNECTED: 
     343            st_code = e->body.tsx_state.tsx->status_code; 
     344            ev_state = PJSIP_EVSUB_STATE_TERMINATED; 
     345            break; 
     346        } 
     347 
     348        if (st_code != -1) { 
     349            pjsip_tx_data *tdata; 
     350            pj_status_t status; 
     351 
     352            status = pjsip_xfer_notify( inv_data->xfer_sub, 
     353                                        ev_state, st_code, 
     354                                        NULL, &tdata); 
     355            if (status != PJ_SUCCESS) { 
     356                pjsua_perror(THIS_FILE, "Unable to create NOTIFY", status); 
     357            } else { 
     358                status = pjsip_xfer_send_request(inv_data->xfer_sub, tdata); 
     359                if (status != PJ_SUCCESS) { 
     360                    pjsua_perror(THIS_FILE, "Unable to send NOTIFY", status); 
     361                } 
     362            } 
     363        } 
     364    } 
     365 
    291366 
    292367    /* Destroy media session when invite session is disconnected. */ 
    293368    if (inv->state == PJSIP_INV_STATE_DISCONNECTED) { 
    294         struct pjsua_inv_data *inv_data; 
    295  
    296         inv_data = inv->dlg->mod_data[pjsua.mod.id]; 
    297369 
    298370        pj_assert(inv_data != NULL); 
     
    319391 
    320392/* 
     393 * Callback called by event framework when the xfer subscription state 
     394 * has changed. 
     395 */ 
     396static void xfer_on_evsub_state( pjsip_evsub *sub, pjsip_event *event) 
     397{ 
     398     
     399    PJ_UNUSED_ARG(event); 
     400 
     401    /* 
     402     * We're only interested when subscription is terminated, to  
     403     * clear the xfer_sub member of the inv_data. 
     404     */ 
     405    if (pjsip_evsub_get_state(sub) == PJSIP_EVSUB_STATE_TERMINATED) { 
     406        struct pjsua_inv_data *inv_data; 
     407 
     408        inv_data = pjsip_evsub_get_mod_data(sub, pjsua.mod.id); 
     409        if (!inv_data) 
     410            return; 
     411 
     412        pjsip_evsub_set_mod_data(sub, pjsua.mod.id, NULL); 
     413        inv_data->xfer_sub = NULL; 
     414 
     415        PJ_LOG(3,(THIS_FILE, "Xfer subscription terminated")); 
     416    } 
     417} 
     418 
     419 
     420/* 
     421 * Follow transfer (REFER) request. 
     422 */ 
     423static void on_call_transfered( pjsip_inv_session *inv, 
     424                                pjsip_rx_data *rdata ) 
     425{ 
     426    pj_status_t status; 
     427    pjsip_tx_data *tdata; 
     428    struct pjsua_inv_data *inv_data; 
     429    const pj_str_t str_refer_to = { "Refer-To", 8}; 
     430    pjsip_generic_string_hdr *refer_to; 
     431    char *uri; 
     432    struct pjsip_evsub_user xfer_cb; 
     433    pjsip_evsub *sub; 
     434 
     435    /* Find the Refer-To header */ 
     436    refer_to = (pjsip_generic_string_hdr*) 
     437        pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &str_refer_to, NULL); 
     438 
     439    if (refer_to == NULL) { 
     440        /* Invalid Request. 
     441         * No Refer-To header! 
     442         */ 
     443        PJ_LOG(4,(THIS_FILE, "Received REFER without Refer-To header!")); 
     444        pjsip_dlg_respond( inv->dlg, rdata, 400, NULL); 
     445        return; 
     446    } 
     447 
     448    PJ_LOG(3,(THIS_FILE, "Call to %.*s is being transfered to %.*s", 
     449              (int)inv->dlg->remote.info_str.slen, 
     450              inv->dlg->remote.info_str.ptr, 
     451              (int)refer_to->hvalue.slen,  
     452              refer_to->hvalue.ptr)); 
     453 
     454    /* Init callback */ 
     455    pj_memset(&xfer_cb, 0, sizeof(xfer_cb)); 
     456    xfer_cb.on_evsub_state = &xfer_on_evsub_state; 
     457 
     458    /* Create transferee event subscription */ 
     459    status = pjsip_xfer_create_uas( inv->dlg, &xfer_cb, rdata, &sub); 
     460    if (status != PJ_SUCCESS) { 
     461        pjsua_perror(THIS_FILE, "Unable to create xfer uas", status); 
     462        pjsip_dlg_respond( inv->dlg, rdata, 500, NULL); 
     463        return; 
     464    } 
     465 
     466    /* Accept the REFER request, send 200 (OK). */ 
     467    pjsip_xfer_accept(sub, rdata, 200, NULL); 
     468 
     469    /* Create initial NOTIFY request */ 
     470    status = pjsip_xfer_notify( sub, PJSIP_EVSUB_STATE_ACTIVE, 
     471                                100, NULL, &tdata); 
     472    if (status != PJ_SUCCESS) { 
     473        pjsua_perror(THIS_FILE, "Unable to create NOTIFY to REFER", status); 
     474        return; 
     475    } 
     476 
     477    /* Send initial NOTIFY request */ 
     478    status = pjsip_xfer_send_request( sub, tdata); 
     479    if (status != PJ_SUCCESS) { 
     480        pjsua_perror(THIS_FILE, "Unable to send NOTIFY to REFER", status); 
     481        return; 
     482    } 
     483 
     484    /* We're cheating here. 
     485     * We need to get a null terminated string from a pj_str_t. 
     486     * So grab the pointer from the hvalue and NULL terminate it, knowing 
     487     * that the NULL position will be occupied by a newline.  
     488     */ 
     489    uri = refer_to->hvalue.ptr; 
     490    uri[refer_to->hvalue.slen] = '\0'; 
     491 
     492    /* Now make the outgoing call. */ 
     493    status = pjsua_invite(uri, &inv_data); 
     494    if (status != PJ_SUCCESS) { 
     495 
     496        /* Notify xferer about the error */ 
     497        status = pjsip_xfer_notify(sub, PJSIP_EVSUB_STATE_TERMINATED, 
     498                                   500, NULL, &tdata); 
     499        if (status != PJ_SUCCESS) { 
     500            pjsua_perror(THIS_FILE, "Unable to create NOTIFY to REFER",  
     501                          status); 
     502            return; 
     503        } 
     504        status = pjsip_xfer_send_request(sub, tdata); 
     505        if (status != PJ_SUCCESS) { 
     506            pjsua_perror(THIS_FILE, "Unable to send NOTIFY to REFER",  
     507                          status); 
     508            return; 
     509        } 
     510        return; 
     511    } 
     512 
     513    /* Put the server subscription in inv_data. 
     514     * Subsequent state changed in pjsua_inv_on_state_changed() will be 
     515     * reported back to the server subscription. 
     516     */ 
     517    inv_data->xfer_sub = sub; 
     518 
     519    /* Put the invite_data in the subscription. */ 
     520    pjsip_evsub_set_mod_data(sub, pjsua.mod.id, inv_data); 
     521} 
     522 
     523 
     524/* 
     525 * This callback is called when transaction state has changed in INVITE 
     526 * session. We use this to trap incoming REFER request. 
     527 */ 
     528void pjsua_inv_on_tsx_state_changed(pjsip_inv_session *inv, 
     529                                    pjsip_transaction *tsx, 
     530                                    pjsip_event *e) 
     531{ 
     532    if (tsx->role==PJSIP_ROLE_UAS && 
     533        tsx->state==PJSIP_TSX_STATE_TRYING && 
     534        pjsip_method_cmp(&tsx->method, &pjsip_refer_method)==0) 
     535    { 
     536        /* 
     537         * Incoming REFER request. 
     538         */ 
     539        on_call_transfered(inv, e->body.tsx_state.src.rdata); 
     540    } 
     541} 
     542 
     543 
     544/* 
    321545 * This callback is called by invite session framework when UAC session 
    322546 * has forked. 
     
    328552 
    329553    PJ_TODO(HANDLE_FORKED_DIALOG); 
     554} 
     555 
     556 
     557/* 
     558 * Create inactive SDP for call hold. 
     559 */ 
     560static pj_status_t create_inactive_sdp(struct pjsua_inv_data *inv_session, 
     561                                       pjmedia_sdp_session **p_answer) 
     562{ 
     563    pj_status_t status; 
     564    pjmedia_sdp_conn *conn; 
     565    pjmedia_sdp_attr *attr; 
     566    pjmedia_sdp_session *sdp; 
     567 
     568    /* Create new offer */ 
     569    status = pjmedia_endpt_create_sdp(pjsua.med_endpt, pjsua.pool, 1, 
     570                                      &pjsua.med_sock_info[inv_session->call_slot], 
     571                                      &sdp); 
     572    if (status != PJ_SUCCESS) { 
     573        pjsua_perror(THIS_FILE, "Unable to create local SDP", status); 
     574        return status; 
     575    } 
     576 
     577    /* Get SDP media connection line */ 
     578    conn = sdp->media[0]->conn; 
     579    if (!conn) 
     580        conn = sdp->conn; 
     581 
     582    /* Modify address */ 
     583    conn->addr = pj_str("0.0.0.0"); 
     584 
     585    /* Remove existing directions attributes */ 
     586    pjmedia_sdp_media_remove_all_attr(sdp->media[0], "sendrecv"); 
     587    pjmedia_sdp_media_remove_all_attr(sdp->media[0], "sendonly"); 
     588    pjmedia_sdp_media_remove_all_attr(sdp->media[0], "recvonly"); 
     589    pjmedia_sdp_media_remove_all_attr(sdp->media[0], "inactive"); 
     590 
     591    /* Add inactive attribute */ 
     592    attr = pjmedia_sdp_attr_create(pjsua.pool, "inactive", NULL); 
     593    pjmedia_sdp_media_add_attr(sdp->media[0], attr); 
     594 
     595    *p_answer = sdp; 
     596 
     597    return status; 
     598} 
     599 
     600/* 
     601 * Called when session received new offer. 
     602 */ 
     603void pjsua_inv_on_rx_offer( pjsip_inv_session *inv, 
     604                            const pjmedia_sdp_session *offer) 
     605{ 
     606    struct pjsua_inv_data *inv_data; 
     607    pjmedia_sdp_conn *conn; 
     608    pjmedia_sdp_session *answer; 
     609    pj_bool_t is_remote_active; 
     610    pj_status_t status; 
     611 
     612    inv_data = inv->dlg->mod_data[pjsua.mod.id]; 
     613 
     614    /* 
     615     * See if remote is offering active media (i.e. not on-hold) 
     616     */ 
     617    is_remote_active = PJ_TRUE; 
     618 
     619    conn = offer->media[0]->conn; 
     620    if (!conn) 
     621        conn = offer->conn; 
     622 
     623    if (pj_strcmp2(&conn->addr, "0.0.0.0")==0 || 
     624        pj_strcmp2(&conn->addr, "0")==0) 
     625    { 
     626        is_remote_active = PJ_FALSE; 
     627 
     628    }  
     629    else if (pjmedia_sdp_media_find_attr2(offer->media[0], "inactive", NULL)) 
     630    { 
     631        is_remote_active = PJ_FALSE; 
     632    } 
     633 
     634    PJ_LOG(4,(THIS_FILE, "Received SDP offer, remote media is %s", 
     635              (is_remote_active ? "active" : "inactive"))); 
     636 
     637    /* Supply candidate answer */ 
     638    if (is_remote_active) { 
     639        status = pjmedia_endpt_create_sdp( pjsua.med_endpt, inv->pool, 1, 
     640                                           &pjsua.med_sock_info[inv_data->call_slot], 
     641                                           &answer); 
     642    } else { 
     643        status = create_inactive_sdp( inv_data, &answer ); 
     644    } 
     645 
     646    if (status != PJ_SUCCESS) { 
     647        pjsua_perror(THIS_FILE, "Unable to create local SDP", status); 
     648        return; 
     649    } 
     650 
     651    status = pjsip_inv_set_sdp_answer(inv, answer); 
     652    if (status != PJ_SUCCESS) { 
     653        pjsua_perror(THIS_FILE, "Unable to set answer", status); 
     654        return; 
     655    } 
     656 
    330657} 
    331658 
     
    341668    const pjmedia_sdp_session *local_sdp; 
    342669    const pjmedia_sdp_session *remote_sdp; 
     670    pjmedia_port *media_port; 
     671    pj_str_t port_name; 
     672    char tmp[PJSIP_MAX_URL_SIZE]; 
    343673 
    344674    if (status != PJ_SUCCESS) { 
     
    381711     * The media session is active immediately. 
    382712     */ 
    383  
    384     if (!pjsua.null_audio) { 
    385         pjmedia_port *media_port; 
    386         pj_str_t port_name; 
    387         char tmp[PJSIP_MAX_URL_SIZE]; 
    388  
    389         status = pjmedia_session_create( pjsua.med_endpt, 1,  
    390                                          &pjsua.med_sock_info[inv_data->call_slot], 
    391                                          local_sdp, remote_sdp,  
    392                                          &inv_data->session ); 
    393         if (status != PJ_SUCCESS) { 
    394             pjsua_perror(THIS_FILE, "Unable to create media session",  
    395                          status); 
    396             return; 
     713    if (pjsua.null_audio) 
     714        return; 
     715     
     716    status = pjmedia_session_create( pjsua.med_endpt, 1,  
     717                                     &pjsua.med_sock_info[inv_data->call_slot], 
     718                                     local_sdp, remote_sdp,  
     719                                     &inv_data->session ); 
     720    if (status != PJ_SUCCESS) { 
     721        pjsua_perror(THIS_FILE, "Unable to create media session",  
     722                     status); 
     723        return; 
     724    } 
     725 
     726 
     727    /* Get the port interface of the first stream in the session. 
     728     * We need the port interface to add to the conference bridge. 
     729     */ 
     730    pjmedia_session_get_port(inv_data->session, 0, &media_port); 
     731 
     732 
     733    /* 
     734     * Add the call to conference bridge. 
     735     */ 
     736    port_name.ptr = tmp; 
     737    port_name.slen = pjsip_uri_print(PJSIP_URI_IN_REQ_URI, 
     738                                     inv_data->inv->dlg->remote.info->uri, 
     739                                     tmp, sizeof(tmp)); 
     740    if (port_name.slen < 1) { 
     741        port_name = pj_str("call"); 
     742    } 
     743    status = pjmedia_conf_add_port( pjsua.mconf, inv->pool, 
     744                                    media_port,  
     745                                    &port_name, 
     746                                    &inv_data->conf_slot); 
     747    if (status != PJ_SUCCESS) { 
     748        pjsua_perror(THIS_FILE, "Unable to create conference slot",  
     749                     status); 
     750        pjmedia_session_destroy(inv_data->session); 
     751        inv_data->session = NULL; 
     752        return; 
     753    } 
     754 
     755    /* Connect new call to the sound device port (port zero) in the 
     756     * main conference bridge. 
     757     */ 
     758    pjmedia_conf_connect_port( pjsua.mconf, 0, inv_data->conf_slot); 
     759    pjmedia_conf_connect_port( pjsua.mconf, inv_data->conf_slot, 0); 
     760 
     761    /* Done. */ 
     762    { 
     763        struct pjmedia_session_info sess_info; 
     764        char info[80]; 
     765        int info_len = 0; 
     766        unsigned i; 
     767 
     768        pjmedia_session_get_info(inv_data->session, &sess_info); 
     769        for (i=0; i<sess_info.stream_cnt; ++i) { 
     770            int len; 
     771            const char *dir; 
     772            pjmedia_stream_info *strm_info = &sess_info.stream_info[i]; 
     773 
     774            switch (strm_info->dir) { 
     775            case PJMEDIA_DIR_NONE: 
     776                dir = "inactive"; 
     777                break; 
     778            case PJMEDIA_DIR_ENCODING: 
     779                dir = "sendonly"; 
     780                break; 
     781            case PJMEDIA_DIR_DECODING: 
     782                dir = "recvonly"; 
     783                break; 
     784            case PJMEDIA_DIR_ENCODING_DECODING: 
     785                dir = "sendrecv"; 
     786                break; 
     787            default: 
     788                dir = "unknown"; 
     789                break; 
     790            } 
     791            len = pj_ansi_sprintf( info+info_len, 
     792                                   ", stream #%d: %.*s (%s)", i, 
     793                                   (int)strm_info->fmt.encoding_name.slen, 
     794                                   (int)strm_info->fmt.encoding_name.ptr, 
     795                                   dir); 
     796            if (len > 0) 
     797                info_len += len; 
    397798        } 
    398  
    399         pjmedia_session_get_port(inv_data->session, 0, &media_port); 
    400  
    401         port_name.ptr = tmp; 
    402         port_name.slen = pjsip_uri_print(PJSIP_URI_IN_REQ_URI, 
    403                                          inv_data->inv->dlg->remote.info->uri, 
    404                                          tmp, sizeof(tmp)); 
    405         if (port_name.slen < 1) { 
    406             port_name = pj_str("call"); 
    407         } 
    408         status = pjmedia_conf_add_port( pjsua.mconf, inv->pool, 
    409                                         media_port,  
    410                                         &port_name, 
    411                                         &inv_data->conf_slot); 
    412         if (status != PJ_SUCCESS) { 
    413             pjsua_perror(THIS_FILE, "Unable to create conference slot",  
    414                          status); 
    415             pjmedia_session_destroy(inv_data->session); 
    416             inv_data->session = NULL; 
    417             return; 
    418         } 
    419  
    420         pjmedia_conf_connect_port( pjsua.mconf, 0, inv_data->conf_slot); 
    421         pjmedia_conf_connect_port( pjsua.mconf, inv_data->conf_slot, 0); 
    422  
    423         PJ_LOG(3,(THIS_FILE,"Media has been started successfully")); 
    424     } 
     799        PJ_LOG(3,(THIS_FILE,"Media started%s", info)); 
     800    } 
     801} 
     802 
     803 
     804/* 
     805 * Hangup call. 
     806 */ 
     807void pjsua_inv_hangup(struct pjsua_inv_data *inv_session, int code) 
     808{ 
     809    pj_status_t status; 
     810    pjsip_tx_data *tdata; 
     811 
     812    status = pjsip_inv_end_session(inv_session->inv,  
     813                                   code, NULL, &tdata); 
     814    if (status != PJ_SUCCESS) { 
     815        pjsua_perror(THIS_FILE,  
     816                     "Failed to create end session message",  
     817                     status); 
     818        return; 
     819    } 
     820 
     821    status = pjsip_inv_send_msg(inv_session->inv, tdata, NULL); 
     822    if (status != PJ_SUCCESS) { 
     823        pjsua_perror(THIS_FILE,  
     824                     "Failed to send end session message",  
     825                     status); 
     826        return; 
     827    } 
     828} 
     829 
     830 
     831/* 
     832 * Put call on-Hold. 
     833 */ 
     834void pjsua_inv_set_hold(struct pjsua_inv_data *inv_session) 
     835{ 
     836    pjmedia_sdp_session *sdp; 
     837    pjsip_inv_session *inv = inv_session->inv; 
     838    pjsip_tx_data *tdata; 
     839    pj_status_t status; 
     840 
     841    if (inv->state != PJSIP_INV_STATE_CONFIRMED) { 
     842        PJ_LOG(3,(THIS_FILE, "Can not hold call that is not confirmed")); 
     843        return; 
     844    } 
     845 
     846    status = create_inactive_sdp(inv_session, &sdp); 
     847    if (status != PJ_SUCCESS) 
     848        return; 
     849 
     850    /* Send re-INVITE with new offer */ 
     851    status = pjsip_inv_reinvite( inv_session->inv, NULL, sdp, &tdata); 
     852    if (status != PJ_SUCCESS) { 
     853        pjsua_perror(THIS_FILE, "Unable to create re-INVITE", status); 
     854        return; 
     855    } 
     856 
     857    status = pjsip_inv_send_msg( inv_session->inv, tdata, NULL); 
     858    if (status != PJ_SUCCESS) { 
     859        pjsua_perror(THIS_FILE, "Unable to send re-INVITE", status); 
     860        return; 
     861    } 
     862} 
     863 
     864 
     865/* 
     866 * re-INVITE. 
     867 */ 
     868void pjsua_inv_reinvite(struct pjsua_inv_data *inv_session) 
     869{ 
     870    pjmedia_sdp_session *sdp; 
     871    pjsip_tx_data *tdata; 
     872    pjsip_inv_session *inv = inv_session->inv; 
     873    pj_status_t status; 
     874 
     875 
     876    if (inv->state != PJSIP_INV_STATE_CONFIRMED) { 
     877        PJ_LOG(3,(THIS_FILE, "Can not re-INVITE call that is not confirmed")); 
     878        return; 
     879    } 
     880 
     881    /* Create SDP */ 
     882    status = pjmedia_endpt_create_sdp( pjsua.med_endpt, inv->pool, 1, 
     883                                       &pjsua.med_sock_info[inv_session->call_slot], 
     884                                       &sdp); 
     885    if (status != PJ_SUCCESS) { 
     886        pjsua_perror(THIS_FILE, "Unable to get SDP from media endpoint", status); 
     887        return; 
     888    } 
     889 
     890    /* Send re-INVITE with new offer */ 
     891    status = pjsip_inv_reinvite( inv_session->inv, NULL, sdp, &tdata); 
     892    if (status != PJ_SUCCESS) { 
     893        pjsua_perror(THIS_FILE, "Unable to create re-INVITE", status); 
     894        return; 
     895    } 
     896 
     897    status = pjsip_inv_send_msg( inv_session->inv, tdata, NULL); 
     898    if (status != PJ_SUCCESS) { 
     899        pjsua_perror(THIS_FILE, "Unable to send re-INVITE", status); 
     900        return; 
     901    } 
     902} 
     903 
     904 
     905/* 
     906 * Transfer call. 
     907 */ 
     908void pjsua_inv_xfer_call(struct pjsua_inv_data *inv_session, 
     909                         const char *dest) 
     910{ 
     911    pjsip_evsub *sub; 
     912    pjsip_tx_data *tdata; 
     913    pj_str_t tmp; 
     914    pj_status_t status; 
     915  
     916     
     917    /* Create xfer client subscription. 
     918     * We're not interested in knowing the transfer result, so we 
     919     * put NULL as the callback. 
     920     */ 
     921    status = pjsip_xfer_create_uac(inv_session->inv->dlg, NULL, &sub); 
     922    if (status != PJ_SUCCESS) { 
     923        pjsua_perror(THIS_FILE, "Unable to create xfer", status); 
     924        return; 
     925    } 
     926 
     927    /* 
     928     * Create REFER request. 
     929     */ 
     930    status = pjsip_xfer_initiate(sub, pj_cstr(&tmp, dest), &tdata); 
     931    if (status != PJ_SUCCESS) { 
     932        pjsua_perror(THIS_FILE, "Unable to create REFER request", status); 
     933        return; 
     934    } 
     935 
     936    /* Send. */ 
     937    status = pjsip_xfer_send_request(sub, tdata); 
     938    if (status != PJ_SUCCESS) { 
     939        pjsua_perror(THIS_FILE, "Unable to send REFER request", status); 
     940        return; 
     941    } 
     942 
     943    /* For simplicity (that's what this program is intended to be!),  
     944     * leave the original invite session as it is. More advanced application 
     945     * may want to hold the INVITE, or terminate the invite, or whatever. 
     946     */ 
    425947} 
    426948 
     
    446968} 
    447969 
     970 
Note: See TracChangeset for help on using the changeset viewer.