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