Changeset 212
- Timestamp:
- Feb 21, 2006 11:47:00 PM (19 years ago)
- Location:
- pjproject/trunk/pjsip
- Files:
-
- 2 added
- 20 edited
Legend:
- Unmodified
- Added
- Removed
-
pjproject/trunk/pjsip/build/pjsip_ua.dsp
r197 r212 94 94 SOURCE="..\src\pjsip-ua\sip_reg.c" 95 95 # End Source File 96 # Begin Source File 97 98 SOURCE="..\src\pjsip-ua\sip_xfer.c" 99 # End Source File 96 100 # End Group 97 101 # Begin Group "Header Files" … … 110 114 SOURCE="..\include\pjsip-ua\sip_regc.h" 111 115 # End Source File 116 # Begin Source File 117 118 SOURCE="..\include\pjsip-ua\sip_xfer.h" 119 # End Source File 112 120 # End Group 113 121 # End Target -
pjproject/trunk/pjsip/include/pjsip-simple/errno.h
r197 r212 24 24 25 25 /** 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 /** 26 32 * @hideinitializer 27 33 * No event package with the specified name. 28 34 */ 29 #define PJSIP_SIMPLE_ENOPKG -135 #define PJSIP_SIMPLE_ENOPKG (PJSIP_SIMPLE_ERRNO_START+1) /*270001*/ 30 36 /** 31 37 * @hideinitializer 32 38 * Event package already exists. 33 39 */ 34 #define PJSIP_SIMPLE_EPKGEXISTS -140 #define PJSIP_SIMPLE_EPKGEXISTS (PJSIP_SIMPLE_ERRNO_START+2) /*270002*/ 35 41 36 42 … … 39 45 * Expecting SUBSCRIBE request 40 46 */ 41 #define PJSIP_SIMPLE_ENOTSUBSCRIBE -147 #define PJSIP_SIMPLE_ENOTSUBSCRIBE (PJSIP_SIMPLE_ERRNO_START+20) /*270020*/ 42 48 /** 43 49 * @hideinitializer 44 50 * No presence associated with subscription 45 51 */ 46 #define PJSIP_SIMPLE_ENOPRESENCE -152 #define PJSIP_SIMPLE_ENOPRESENCE (PJSIP_SIMPLE_ERRNO_START+21) /*270021*/ 47 53 /** 48 54 * @hideinitializer 49 55 * No presence info in server subscription 50 56 */ 51 #define PJSIP_SIMPLE_ENOPRESENCEINFO -157 #define PJSIP_SIMPLE_ENOPRESENCEINFO (PJSIP_SIMPLE_ERRNO_START+22) /*270022*/ 52 58 /** 53 59 * @hideinitializer 54 60 * Bad Content-Type 55 61 */ 56 #define PJSIP_SIMPLE_EBADCONTENT -162 #define PJSIP_SIMPLE_EBADCONTENT (PJSIP_SIMPLE_ERRNO_START+23) /*270023*/ 57 63 /** 58 64 * @hideinitializer 59 65 * Bad PIDF Message 60 66 */ 61 #define PJSIP_SIMPLE_EBADPIDF -167 #define PJSIP_SIMPLE_EBADPIDF (PJSIP_SIMPLE_ERRNO_START+24) /*270024*/ 62 68 /** 63 69 * @hideinitializer 64 70 * Bad XPIDF Message 65 71 */ 66 #define PJSIP_SIMPLE_EBADXPIDF -172 #define PJSIP_SIMPLE_EBADXPIDF (PJSIP_SIMPLE_ERRNO_START+25) /*270025*/ 67 73 68 74 -
pjproject/trunk/pjsip/include/pjsip-simple/evsub.h
r197 r212 77 77 78 78 79 /** 80 * Some options for the event subscription. 81 */ 82 enum 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 79 92 80 93 /** … … 245 258 * @param user_cb Callback to receive event subscription notifications. 246 259 * @param event Event name. 260 * @param option Bitmask of options. 247 261 * @param p_evsub Pointer to receive event subscription instance. 248 262 * … … 252 266 const pjsip_evsub_user *user_cb, 253 267 const pj_str_t *event, 268 unsigned option, 254 269 pjsip_evsub **p_evsub); 255 270 … … 261 276 * @param rdata The incoming request that creates the event 262 277 * subscription, such as SUBSCRIBE or REFER. 278 * @param option Bitmask of options. 263 279 * @param p_evsub Pointer to receive event subscription instance. 264 280 * … … 268 284 const pjsip_evsub_user *user_cb, 269 285 pjsip_rx_data *rdata, 286 unsigned option, 270 287 pjsip_evsub **p_evsub); 271 288 … … 367 384 368 385 /** 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. 370 390 * 371 391 * @param sub The event subscription object. -
pjproject/trunk/pjsip/include/pjsip-simple/presence.h
r197 r212 203 203 204 204 /** 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. 206 209 * 207 210 * @param sub The subscription object. -
pjproject/trunk/pjsip/include/pjsip-ua/sip_inv.h
r184 r212 98 98 * This callback is called when the invite session has received 99 99 * 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". 106 101 * 107 102 * @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); 110 107 111 108 /** … … 122 119 void (*on_media_update)(pjsip_inv_session *inv_ses, 123 120 pj_status_t status); 124 125 121 }; 126 122 … … 388 384 389 385 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). 399 389 * 400 390 * @param inv The invite session. 401 391 * @param sdp The SDP description which will be set as answer 402 392 * 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 */ 397 PJ_DECL(pj_status_t) pjsip_inv_set_sdp_answer(pjsip_inv_session *inv, 398 const pjmedia_sdp_session *sdp ); 399 407 400 408 401 /** -
pjproject/trunk/pjsip/include/pjsip/sip_dialog.h
r196 r212 42 42 { 43 43 pjsip_fromto_hdr *info; /**< From/To header, inc tag. */ 44 pj_str_t info_str; /**< String rep of info header. */ 44 45 pj_uint32_t tag_hval; /**< Hashed value of the tag. */ 45 46 pjsip_contact_hdr *contact; /**< Contact header. */ … … 77 78 78 79 /* Dialog's session properties. */ 79 enumpjsip_dialog_state state; /**< Dialog state. */80 pjsip_dialog_state state; /**< Dialog state. */ 80 81 pjsip_uri *target; /**< Current target. */ 82 pjsip_hdr inv_hdr; /**< Headers from hparam in dest URL */ 81 83 pjsip_dlg_party local; /**< Local party info. */ 82 84 pjsip_dlg_party remote; /**< Remote party info. */ -
pjproject/trunk/pjsip/include/pjsip/sip_errno.h
r197 r212 172 172 */ 173 173 #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 */ 174 179 175 180 … … 348 353 */ 349 354 #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 350 366 351 367 -
pjproject/trunk/pjsip/include/pjsip/sip_msg.h
r197 r212 585 585 586 586 /** 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 */ 598 PJ_DECL(void*) pjsip_clone_text_data( pj_pool_t *pool, const void *data, 599 unsigned len); 600 601 602 /** 587 603 * Clone the message body in src_body to the dst_body. This will duplicate 588 604 * the contents of the message body using the \a clone_data member of the -
pjproject/trunk/pjsip/include/pjsip_ua.h
r141 r212 22 22 #include <pjsip-ua/sip_inv.h> 23 23 #include <pjsip-ua/sip_regc.h> 24 #include <pjsip-ua/sip_xfer.h> 24 25 25 26 -
pjproject/trunk/pjsip/src/pjsip-simple/errno.c
r198 r212 18 18 */ 19 19 #include <pjsip-simple/errno.h> 20 #include <pj/string.h> 20 21 22 /* PJSIP-SIMPLE's own error codes/messages 23 * MUST KEEP THIS ARRAY SORTED!! 24 * Message must be limited to 64 chars! 25 */ 26 static 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 */ 48 PJ_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 198 198 pjsip_dialog *dlg; /**< Underlying dialog. */ 199 199 struct evpkg *pkg; /**< The event package. */ 200 unsigned option; /**< Options. */ 200 201 pjsip_evsub_user user; /**< Callback. */ 201 202 pjsip_role_e role; /**< UAC=subscriber, UAS=notifier */ … … 236 237 static const pj_str_t STR_TIMEOUT = { "timeout", 7}; 237 238 239 238 240 /* 239 241 * On unload module. … … 246 248 return PJ_SUCCESS; 247 249 } 250 251 /* Proto for pjsipsimple_strerror(). 252 * Defined in errno.c 253 */ 254 PJ_DECL(pj_str_t) pjsipsimple_strerror( pj_status_t statcode, 255 char *buf, pj_size_t bufsize ); 248 256 249 257 /* … … 257 265 { "NOTIFY", 6} 258 266 }; 267 268 pj_register_strerror(PJSIP_SIMPLE_ERRNO_START, PJ_ERRNO_SPACE_SIZE, 269 &pjsipsimple_strerror); 259 270 260 271 PJ_ASSERT_RETURN(endpt != NULL, PJ_EINVAL); … … 619 630 const pjsip_evsub_user *user_cb, 620 631 const pj_str_t *event, 632 unsigned option, 621 633 pjsip_evsub **p_evsub ) 622 634 { … … 641 653 sub->pkg = pkg; 642 654 sub->role = role; 655 sub->option = option; 643 656 sub->state = PJSIP_EVSUB_STATE_NULL; 644 657 sub->state_str = evsub_state_names[sub->state]; … … 698 711 const pjsip_evsub_user *user_cb, 699 712 const pj_str_t *event, 713 unsigned option, 700 714 pjsip_evsub **p_evsub) 701 715 { … … 706 720 707 721 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); 709 723 if (status != PJ_SUCCESS) 710 724 goto on_return; 711 725 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 } 714 732 715 733 /* Increment dlg session. */ … … 731 749 const pjsip_evsub_user *user_cb, 732 750 pjsip_rx_data *rdata, 751 unsigned option, 733 752 pjsip_evsub **p_evsub) 734 753 { … … 758 777 PJ_ASSERT_RETURN(user_cb->on_rx_refresh, PJ_EINVALIDOP); 759 778 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 */ 762 782 event_hdr = (pjsip_event_hdr*) 763 783 pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &STR_EVENT, NULL); … … 773 793 774 794 status = evsub_create(dlg, PJSIP_UAS_ROLE, user_cb, 775 &event_hdr->event_type, &sub);795 &event_hdr->event_type, option, &sub); 776 796 if (status != PJ_SUCCESS) 777 797 goto on_return; … … 1148 1168 } 1149 1169 1170 1150 1171 switch (event->body.tsx_state.type) { 1151 1172 case PJSIP_EVENT_RX_MSG: … … 1164 1185 1165 1186 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!"); 1167 1192 return NULL; 1168 1193 } … … 1188 1213 while (dlgsub != dlgsub_head) { 1189 1214 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) 1193 1217 { 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 1196 1252 dlgsub = dlgsub->next; 1197 1253 } … … 1201 1257 PJ_LOG(4,(THIS_FILE, 1202 1258 "Subscription not found for %.*s, event=%.*s;id=%.*s", 1259 (int)tsx->method.name.slen, 1260 tsx->method.name.ptr, 1203 1261 (int)event_hdr->event_type.slen, 1204 1262 event_hdr->event_type.ptr, … … 1738 1796 set_state(sub, PJSIP_EVSUB_STATE_TERMINATED, NULL, NULL); 1739 1797 } 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 } 1741 1810 1742 1811 } else { -
pjproject/trunk/pjsip/src/pjsip-simple/presence.c
r198 r212 192 192 193 193 /* 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); 195 195 if (status != PJ_SUCCESS) 196 196 goto on_return; … … 199 199 pres = pj_pool_zalloc(dlg->pool, sizeof(pjsip_pres)); 200 200 pres->dlg = dlg; 201 pres->sub = sub; 201 202 if (user_cb) 202 203 pj_memcpy(&pres->user_cb, user_cb, sizeof(pjsip_evsub_user)); … … 298 299 299 300 /* 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); 301 302 if (status != PJ_SUCCESS) 302 303 goto on_return; -
pjproject/trunk/pjsip/src/pjsip-ua/sip_inv.c
r184 r212 201 201 * move state to CONFIRMED. 202 202 */ 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) { 207 204 208 205 /* Terminate INVITE transaction, if it's still present. */ … … 215 212 } 216 213 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 } 219 220 } 220 221 … … 251 252 */ 252 253 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 { 254 257 255 258 inv_send_ack(inv, rdata); … … 866 869 pjsip_tx_data *tdata; 867 870 const pjsip_hdr *hdr; 871 pj_bool_t has_sdp; 868 872 pj_status_t status; 869 873 … … 871 875 PJ_ASSERT_RETURN(inv && p_tdata, PJ_EINVAL); 872 876 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); 875 881 876 882 /* Create the INVITE request. */ … … 880 886 return status; 881 887 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 882 917 /* 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) { 886 919 const pjmedia_sdp_session *offer; 887 920 … … 941 974 * Check in incoming message for SDP offer/answer. 942 975 */ 943 static voidinv_check_sdp_in_incoming_msg( pjsip_inv_session *inv,944 945 976 static pj_status_t inv_check_sdp_in_incoming_msg( pjsip_inv_session *inv, 977 pjsip_transaction *tsx, 978 pjsip_rx_data *rdata) 946 979 { 947 980 struct tsx_inv_data *tsx_inv_data; … … 964 997 965 998 if (tsx_inv_data->sdp_done) 966 return ;999 return PJ_SUCCESS; 967 1000 968 1001 /* Check if SDP is present in the message. */ … … 971 1004 if (msg->body == NULL) { 972 1005 /* Message doesn't have body. */ 973 return ;1006 return PJ_SUCCESS; 974 1007 } 975 1008 … … 978 1011 { 979 1012 /* Message body is not "application/sdp" */ 980 return ;1013 return PJMEDIA_SDP_EINSDP; 981 1014 } 982 1015 … … 990 1023 PJ_LOG(4,(THIS_FILE, "Error parsing SDP in %s: %s", 991 1024 pjsip_rx_data_get_info(rdata), errmsg)); 992 return ;1025 return PJMEDIA_SDP_EINSDP; 993 1026 } 994 1027 … … 1016 1049 PJ_LOG(4,(THIS_FILE, "Error processing SDP offer in %s: %s", 1017 1050 pjsip_rx_data_get_info(rdata), errmsg)); 1018 return ;1051 return PJMEDIA_SDP_EINSDP; 1019 1052 } 1020 1053 1021 1054 /* Inform application about remote offer. */ 1022 1055 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 } 1025 1061 1026 1062 } else if (pjmedia_sdp_neg_get_state(inv->neg) == … … 1042 1078 PJ_LOG(4,(THIS_FILE, "Error processing SDP answer in %s: %s", 1043 1079 pjsip_rx_data_get_info(rdata), errmsg)); 1044 return ;1080 return PJMEDIA_SDP_EINSDP; 1045 1081 } 1046 1082 … … 1060 1096 } 1061 1097 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 */ 1105 static 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. 1068 1160 */ 1069 1161 PJ_DEF(pj_status_t) pjsip_inv_answer( pjsip_inv_session *inv, … … 1088 1180 * offer before. 1089 1181 */ 1090 if (local_sdp ) {1182 if (local_sdp && (st_code/100==1 || st_code/100==2)) { 1091 1183 1092 1184 if (inv->neg == NULL) { … … 1109 1201 } 1110 1202 1203 1204 1205 1206 /* Modify last response. */ 1111 1207 last_res = inv->invite_tsx->last_tx; 1112 1113 /* Modify last response. */1114 1208 status = pjsip_dlg_modify_response(inv->dlg, last_res, st_code, st_text); 1115 1209 if (status != PJ_SUCCESS) 1116 1210 return status; 1117 1211 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; 1147 1217 1148 1218 … … 1150 1220 1151 1221 return PJ_SUCCESS; 1222 } 1223 1224 1225 /* 1226 * Set SDP answer. 1227 */ 1228 PJ_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; 1152 1240 } 1153 1241 … … 1206 1294 PJ_ASSERT_RETURN(tdata != NULL, PJ_EINVALIDOP); 1207 1295 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); 1210 1299 } 1211 1300 break; … … 1248 1337 pjsip_tx_data **p_tdata ) 1249 1338 { 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 1412 on_return: 1413 pjsip_dlg_dec_lock(inv->dlg); 1414 return status; 1257 1415 } 1258 1416 … … 1909 2067 1910 2068 } 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 } 1911 2187 } 1912 2188 -
pjproject/trunk/pjsip/src/pjsip/sip_dialog.c
r196 r212 79 79 dlg->state = PJSIP_DIALOG_STATE_NULL; 80 80 81 pj_list_init(&dlg->inv_hdr); 82 81 83 status = pj_mutex_create_recursive(pool, "dlg%p", &dlg->mutex); 82 84 if (status != PJ_SUCCESS) … … 132 134 } 133 135 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, ¶m->name, 148 ¶m->value); 149 pj_list_push_back(&dlg->inv_hdr, req_hdr); 150 151 param = param->next; 152 } 153 } 154 134 155 /* Init local info. */ 135 156 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); 138 161 if (!dlg->local.info->uri) { 139 162 status = PJSIP_EINVALIDURI; … … 165 188 /* Init remote info. */ 166 189 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); 169 194 if (!dlg->remote.info->uri) { 170 195 status = PJSIP_EINVALIDURI; … … 226 251 pjsip_rr_hdr *rr; 227 252 pjsip_transaction *tsx = NULL; 253 pj_str_t tmp; 254 enum { TMP_LEN=128}; 255 pj_ssize_t len; 228 256 pjsip_dialog *dlg; 229 257 … … 250 278 return status; 251 279 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 252 285 /* Init local info from the To header. */ 253 286 dlg->local.info = pjsip_hdr_clone(dlg->pool, rdata->msg_info.to); … … 257 290 pj_create_unique_string(dlg->pool, &dlg->local.info->tag); 258 291 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 259 305 /* Calculate hash value of local tag. */ 260 306 dlg->local.tag_hval = pj_hash_calc(0, dlg->local.info->tag.ptr, 261 307 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 262 321 263 322 /* Randomize local cseq */ … … 1086 1145 pjsip_tx_data *tdata) 1087 1146 { 1147 pj_status_t status; 1148 1088 1149 /* Sanity check. */ 1089 1150 PJ_ASSERT_RETURN(dlg && tsx && tdata && tdata->msg, PJ_EINVAL); … … 1108 1169 #endif 1109 1170 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; 1111 1179 } 1112 1180 -
pjproject/trunk/pjsip/src/pjsip/sip_endpoint.c
r197 r212 325 325 htype==PJSIP_H_SUPPORTED, 326 326 PJ_EINVAL); 327 328 PJ_UNUSED_ARG(mod); 327 329 328 330 /* Find the header. */ -
pjproject/trunk/pjsip/src/pjsip/sip_msg.c
r197 r212 1747 1747 } 1748 1748 1749 PJ_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 1749 1761 PJ_DEF(pj_status_t) pjsip_msg_body_clone( pj_pool_t *pool, 1750 1762 pjsip_msg_body *dst_body, -
pjproject/trunk/pjsip/src/pjsua/main.c
r205 r212 114 114 "%s (%.*s;expires=%d)", 115 115 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, 118 118 info.next_reg); 119 119 … … 132 132 puts("| | | |"); 133 133 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 | rUnregister |");136 puts("| ] Select next dialog | t To ggle 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 |"); 137 137 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("+------------------------------+--------------------------+-------------------+"); 144 144 puts("| q QUIT |"); 145 145 puts("+=============================================================================+"); … … 284 284 char menuin[10]; 285 285 char buf[128]; 286 pjsip_inv_session *inv;287 286 struct input_result result; 288 287 … … 306 305 puts("You can't do that with make call!"); 307 306 else 308 pjsua_invite(pjsua.buddies[result.nb_result].uri.ptr, &inv);307 pjsua_invite(pjsua.buddies[result.nb_result].uri.ptr, NULL); 309 308 } else if (result.uri_result) 310 pjsua_invite(result.uri_result, &inv);309 pjsua_invite(result.uri_result, NULL); 311 310 312 311 break; … … 354 353 355 354 } 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'; 366 385 } 367 386 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); 374 439 } 375 440 } 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;388 441 break; 389 442 390 443 case 's': 391 444 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); 393 449 if (result.nb_result != NO_NB) { 394 450 if (result.nb_result == -1) { … … 403 459 404 460 } 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 } 412 482 break; 413 483 414 case 'r':415 pjsua_regc_update(PJ_FALSE);416 break;417 418 484 case 't': 419 485 pjsua.online_status = !pjsua.online_status; … … 431 497 char src_port[10], dst_port[10]; 432 498 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))) 435 511 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))) 437 514 break; 438 515 439 516 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)); 441 520 } 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)); 443 524 } 444 525 if (status == PJ_SUCCESS) { -
pjproject/trunk/pjsip/src/pjsua/pjsua.h
r205 r212 69 69 unsigned conf_slot; /**< Slot # in conference bridge. */ 70 70 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. */ 71 73 }; 72 74 … … 255 257 */ 256 258 pj_status_t pjsua_invite(const char *cstr_dest_uri, 257 pjsip_inv_session **p_inv);259 struct pjsua_inv_data **p_inv_data); 258 260 259 261 … … 262 264 */ 263 265 pj_bool_t pjsua_inv_on_incoming(pjsip_rx_data *rdata); 266 267 268 /** 269 * Hangup call. 270 */ 271 void pjsua_inv_hangup(struct pjsua_inv_data *inv_session, int code); 272 273 274 /** 275 * Put call on-hold. 276 */ 277 void pjsua_inv_set_hold(struct pjsua_inv_data *inv_session); 278 279 280 /** 281 * Send re-INVITE (to release hold). 282 */ 283 void pjsua_inv_reinvite(struct pjsua_inv_data *inv_session); 284 285 286 /** 287 * Transfer call. 288 */ 289 void pjsua_inv_xfer_call(struct pjsua_inv_data *inv_session, 290 const char *dest); 264 291 265 292 … … 284 311 void pjsua_inv_on_media_update(pjsip_inv_session *inv, pj_status_t status); 285 312 313 /** 314 * Callback called when invite session received new offer. 315 */ 316 void 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 */ 323 void pjsua_inv_on_tsx_state_changed(pjsip_inv_session *inv, 324 pjsip_transaction *tsx, 325 pjsip_event *e); 286 326 287 327 /** -
pjproject/trunk/pjsip/src/pjsua/pjsua_core.c
r205 r212 142 142 RTP_START_PORT = 4000, 143 143 RTP_RANDOM_START = 2, 144 RTP_RETRY = 10144 RTP_RETRY = 20 145 145 }; 146 146 enum { … … 393 393 inv_cb.on_new_session = &pjsua_inv_on_new_session; 394 394 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 395 398 396 399 /* Initialize invite session module: */ … … 480 483 pjsip_pres_init_module( pjsua.endpt, pjsip_evsub_instance()); 481 484 485 /* Init xfer/REFER module */ 486 487 pjsip_xfer_init_module( pjsua.endpt ); 482 488 483 489 /* Init pjsua presence handler: */ … … 752 758 busy_sleep(1000); 753 759 760 /* Destroy conference bridge. */ 761 if (pjsua.mconf) 762 pjmedia_conf_destroy(pjsua.mconf); 763 754 764 /* Shutdown pjmedia-codec: */ 755 765 pjmedia_codec_deinit(); -
pjproject/trunk/pjsip/src/pjsua/pjsua_inv.c
r205 r212 34 34 */ 35 35 pj_status_t pjsua_invite(const char *cstr_dest_uri, 36 pjsip_inv_session **p_inv)36 struct pjsua_inv_data **p_inv_data) 37 37 { 38 38 pj_str_t dest_uri; … … 137 137 138 138 /* Done. */ 139 140 *p_inv = inv;139 if (p_inv_data) 140 *p_inv_data = inv_data; 141 141 142 142 return PJ_SUCCESS; … … 159 159 pjsip_transaction *tsx = pjsip_rdata_get_tsx(rdata); 160 160 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 161 206 162 207 /* 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); 278 221 return PJ_TRUE; 279 222 } 280 223 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; 282 300 } 283 301 … … 289 307 void pjsua_inv_on_state_changed(pjsip_inv_session *inv, pjsip_event *e) 290 308 { 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 291 366 292 367 /* Destroy media session when invite session is disconnected. */ 293 368 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];297 369 298 370 pj_assert(inv_data != NULL); … … 319 391 320 392 /* 393 * Callback called by event framework when the xfer subscription state 394 * has changed. 395 */ 396 static 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 */ 423 static 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 */ 528 void 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 /* 321 545 * This callback is called by invite session framework when UAC session 322 546 * has forked. … … 328 552 329 553 PJ_TODO(HANDLE_FORKED_DIALOG); 554 } 555 556 557 /* 558 * Create inactive SDP for call hold. 559 */ 560 static 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 */ 603 void 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 330 657 } 331 658 … … 341 668 const pjmedia_sdp_session *local_sdp; 342 669 const pjmedia_sdp_session *remote_sdp; 670 pjmedia_port *media_port; 671 pj_str_t port_name; 672 char tmp[PJSIP_MAX_URL_SIZE]; 343 673 344 674 if (status != PJ_SUCCESS) { … … 381 711 * The media session is active immediately. 382 712 */ 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; 397 798 } 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 */ 807 void 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 */ 834 void 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 */ 868 void 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 */ 908 void 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 */ 425 947 } 426 948 … … 446 968 } 447 969 970
Note: See TracChangeset
for help on using the changeset viewer.