- Timestamp:
- Sep 21, 2011 10:20:01 AM (13 years ago)
- Location:
- pjproject/trunk/pjsip
- Files:
-
- 6 edited
Legend:
- Unmodified
- Added
- Removed
-
pjproject/trunk/pjsip/include/pjsua-lib/pjsua.h
r3756 r3763 462 462 registration callback. */ 463 463 } pjsua_reg_info; 464 465 466 /** 467 * Enumeration of media transport state types. 468 */ 469 typedef enum pjsua_med_tp_st 470 { 471 /** Null, this is the state before media transport is created. */ 472 PJSUA_MED_TP_NULL, 473 474 /** 475 * Just before media transport is created, which can finish 476 * asynchronously later. 477 */ 478 PJSUA_MED_TP_CREATING, 479 480 /** Media transport creation is completed, but not initialized yet. */ 481 PJSUA_MED_TP_IDLE, 482 483 /** Initialized (media_create() has been called). */ 484 PJSUA_MED_TP_INIT, 485 486 /** Running (media_start() has been called). */ 487 PJSUA_MED_TP_RUNNING, 488 489 /** Disabled (transport is initialized, but media is being disabled). */ 490 PJSUA_MED_TP_DISABLED 491 492 } pjsua_med_tp_st; 493 494 495 /** 496 * Structure to be passed on media transport state callback. 497 */ 498 typedef struct pjsua_med_tp_state_info 499 { 500 /** 501 * The media index. 502 */ 503 unsigned med_idx; 504 505 /** 506 * The media transport state 507 */ 508 pjsua_med_tp_st state; 509 510 /** 511 * The last error code related to the media transport state. 512 */ 513 pj_status_t status; 514 515 /** 516 * Optional SIP error code. 517 */ 518 int sip_err_code; 519 520 /** 521 * Optional extended info, the content is specific for each transport type. 522 */ 523 void *ext_info; 524 525 } pjsua_med_tp_state_info; 526 527 528 /** 529 * Type of callback to be called when media transport state is changed. 530 * 531 * @param call_id The call ID. 532 * @param info The media transport state info. 533 */ 534 typedef void (*pjsua_med_tp_state_cb)(pjsua_call_id call_id, 535 const pjsua_med_tp_state_info *info); 464 536 465 537 … … 950 1022 951 1023 /** 1024 * This callback is called when media transport state is changed. See 1025 * also #pjsua_med_tp_state_cb. 1026 */ 1027 pjsua_med_tp_state_cb on_call_media_transport_state; 1028 1029 /** 952 1030 * This callback is called to report error in ICE media transport. 953 1031 * Currently it is used to report TURN Refresh error. … … 1363 1441 */ 1364 1442 PJ_DECL(void) pjsua_msg_data_init(pjsua_msg_data *msg_data); 1443 1444 1445 /** 1446 * Clone message data. 1447 * 1448 * @param pool Pool to allocate memory for the new message data. 1449 * @param rhs Message data to be cloned. 1450 * 1451 * @return The new message data. 1452 */ 1453 PJ_DECL(pjsua_msg_data*) pjsua_msg_data_clone(pj_pool_t *pool, 1454 const pjsua_msg_data *rhs); 1365 1455 1366 1456 -
pjproject/trunk/pjsip/include/pjsua-lib/pjsua_internal.h
r3758 r3763 28 28 PJ_BEGIN_DECL 29 29 30 /**31 * Media transport state.32 */33 typedef enum pjsua_med_tp_st34 {35 /** Not initialized */36 PJSUA_MED_TP_IDLE,37 38 /** Initialized (media_create() has been called) */39 PJSUA_MED_TP_INIT,40 41 /** Running (media_start() has been called) */42 PJSUA_MED_TP_RUNNING,43 44 /** Disabled (transport is initialized, but media is being disabled) */45 PJSUA_MED_TP_DISABLED46 47 } pjsua_med_tp_st;48 49 30 /** Forward decl of pjsua call */ 50 31 typedef struct pjsua_call pjsua_call; 32 33 /** Forward decl of pjsua call media */ 34 typedef struct pjsua_call_media pjsua_call_media; 51 35 52 36 … … 93 77 pj_status_t tp_ready; /**< Media transport status. */ 94 78 pjmedia_transport *tp_orig; /**< Original media transport */ 95 pj_bool_t tp_auto_del; /**< May delete media transport */79 pj_bool_t tp_auto_del; /**< May delete media transport */ 96 80 pjsua_med_tp_st tp_st; /**< Media transport state */ 97 81 pj_sockaddr rtp_addr; /**< Current RTP source address … … 100 84 pjmedia_srtp_use rem_srtp_use; /**< Remote's SRTP usage policy. */ 101 85 102 pjmedia_event_subscription esub_rend;/**< Subscribe renderer events. 86 pjmedia_event_subscription esub_rend;/**< Subscribe renderer events. */ 103 87 pjmedia_event_subscription esub_cap;/**< Subscribe capture events. */ 88 89 pjsua_med_tp_state_cb med_init_cb;/**< Media transport 90 initialization callback. */ 91 92 /** Media transport creation callback. */ 93 pj_status_t (*med_create_cb)(pjsua_call_media *call_med, 94 pj_status_t status, int security_level, 95 int *sip_err_code); 104 96 } pjsua_call_media; 105 97 … … 133 125 pjsua_call_media media[PJSUA_MAX_CALL_MEDIA]; /**< Array of media */ 134 126 int audio_idx; /**< First active audio media. */ 127 pj_mutex_t *med_ch_mutex;/**< Media channel callback's mutex. */ 128 pjsua_med_tp_state_cb med_ch_cb;/**< Media channel callback. */ 129 pjsua_med_tp_state_info med_ch_info;/**< Media channel info. */ 135 130 136 131 pjsip_evsub *xfer_sub; /**< Xfer server subscription, if this … … 148 143 contains multiple codecs. */ 149 144 145 struct { 146 pjsip_dialog *dlg; /**< Call dialog. */ 147 pjmedia_sdp_session *rem_sdp;/**< Remote SDP. */ 148 union { 149 struct { 150 unsigned options; /**< Outgoing call options. */ 151 pjsua_msg_data *msg_data;/**< Headers for outgoing INVITE. */ 152 } out_call; 153 } call_var; 154 } async_call; /**< Temporary storage for async 155 outgoing/incoming call. */ 150 156 }; 151 157 … … 509 515 pj_pool_t *tmp_pool, 510 516 const pjmedia_sdp_session *rem_sdp, 511 int *sip_err_code); 517 int *sip_err_code, 518 pj_bool_t async, 519 pjsua_med_tp_state_cb cb); 512 520 pj_status_t pjsua_media_channel_create_sdp(pjsua_call_id call_id, 513 521 pj_pool_t *pool, … … 524 532 const pjsua_transport_config *tcfg, 525 533 int security_level, 526 int *sip_err_code); 534 int *sip_err_code, 535 pj_bool_t async, 536 pjsua_med_tp_state_cb cb); 527 537 pj_status_t video_channel_update(pjsua_call_media *call_med, 528 538 pj_pool_t *tmp_pool, … … 530 540 const pjmedia_sdp_session *remote_sdp); 531 541 void stop_video_stream(pjsua_call_media *call_med); 542 void set_media_tp_state(pjsua_call_media *call_med, pjsua_med_tp_st tp_st); 532 543 533 544 -
pjproject/trunk/pjsip/src/pjsua-lib/pjsua_call.c
r3753 r3763 332 332 */ 333 333 334 static pj_status_t 335 on_make_call_med_tp_complete(pjsua_call_id call_id, 336 const pjsua_med_tp_state_info *info) 337 { 338 pjmedia_sdp_session *offer; 339 pjsip_inv_session *inv = NULL; 340 pjsua_call *call = &pjsua_var.calls[call_id]; 341 pjsua_acc *acc = &pjsua_var.acc[call->acc_id]; 342 pjsip_dialog *dlg = call->async_call.dlg; 343 unsigned options = call->async_call.call_var.out_call.options; 344 pjsip_tx_data *tdata; 345 pj_status_t status = (info? info->status: PJ_SUCCESS); 346 347 PJSUA_LOCK(); 348 349 /* Increment the dialog's lock otherwise when invite session creation 350 * fails the dialog will be destroyed prematurely. 351 */ 352 pjsip_dlg_inc_lock(dlg); 353 354 if (status != PJ_SUCCESS) { 355 pjsua_perror(THIS_FILE, "Error initializing media channel", status); 356 goto on_error; 357 } 358 359 /* Create offer */ 360 status = pjsua_media_channel_create_sdp(call->index, dlg->pool, NULL, 361 &offer, NULL); 362 if (status != PJ_SUCCESS) { 363 pjsua_perror(THIS_FILE, "Error initializing media channel", status); 364 goto on_error; 365 } 366 367 /* Create the INVITE session: */ 368 options |= PJSIP_INV_SUPPORT_100REL; 369 if (acc->cfg.require_100rel) 370 options |= PJSIP_INV_REQUIRE_100REL; 371 if (acc->cfg.use_timer != PJSUA_SIP_TIMER_INACTIVE) { 372 options |= PJSIP_INV_SUPPORT_TIMER; 373 if (acc->cfg.use_timer == PJSUA_SIP_TIMER_REQUIRED) 374 options |= PJSIP_INV_REQUIRE_TIMER; 375 else if (acc->cfg.use_timer == PJSUA_SIP_TIMER_ALWAYS) 376 options |= PJSIP_INV_ALWAYS_USE_TIMER; 377 } 378 379 status = pjsip_inv_create_uac( dlg, offer, options, &inv); 380 if (status != PJ_SUCCESS) { 381 pjsua_perror(THIS_FILE, "Invite session creation failed", status); 382 goto on_error; 383 } 384 385 /* Init Session Timers */ 386 status = pjsip_timer_init_session(inv, &acc->cfg.timer_setting); 387 if (status != PJ_SUCCESS) { 388 pjsua_perror(THIS_FILE, "Session Timer init failed", status); 389 goto on_error; 390 } 391 392 /* Create and associate our data in the session. */ 393 call->inv = inv; 394 395 dlg->mod_data[pjsua_var.mod.id] = call; 396 inv->mod_data[pjsua_var.mod.id] = call; 397 398 /* If account is locked to specific transport, then lock dialog 399 * to this transport too. 400 */ 401 if (acc->cfg.transport_id != PJSUA_INVALID_ID) { 402 pjsip_tpselector tp_sel; 403 404 pjsua_init_tpselector(acc->cfg.transport_id, &tp_sel); 405 pjsip_dlg_set_transport(dlg, &tp_sel); 406 } 407 408 /* Set dialog Route-Set: */ 409 if (!pj_list_empty(&acc->route_set)) 410 pjsip_dlg_set_route_set(dlg, &acc->route_set); 411 412 413 /* Set credentials: */ 414 if (acc->cred_cnt) { 415 pjsip_auth_clt_set_credentials( &dlg->auth_sess, 416 acc->cred_cnt, acc->cred); 417 } 418 419 /* Set authentication preference */ 420 pjsip_auth_clt_set_prefs(&dlg->auth_sess, &acc->cfg.auth_pref); 421 422 /* Create initial INVITE: */ 423 424 status = pjsip_inv_invite(inv, &tdata); 425 if (status != PJ_SUCCESS) { 426 pjsua_perror(THIS_FILE, "Unable to create initial INVITE request", 427 status); 428 goto on_error; 429 } 430 431 432 /* Add additional headers etc */ 433 434 pjsua_process_msg_data( tdata, 435 call->async_call.call_var.out_call.msg_data); 436 437 /* Must increment call counter now */ 438 ++pjsua_var.call_cnt; 439 440 /* Send initial INVITE: */ 441 442 status = pjsip_inv_send_msg(inv, tdata); 443 if (status != PJ_SUCCESS) { 444 pjsua_perror(THIS_FILE, "Unable to send initial INVITE request", 445 status); 446 447 /* Upon failure to send first request, the invite 448 * session would have been cleared. 449 */ 450 inv = NULL; 451 goto on_error; 452 } 453 454 /* Done. */ 455 456 pjsip_dlg_dec_lock(dlg); 457 PJSUA_UNLOCK(); 458 459 return PJ_SUCCESS; 460 461 on_error: 462 if (dlg) { 463 /* This may destroy the dialog */ 464 pjsip_dlg_dec_lock(dlg); 465 } 466 467 if (inv != NULL) { 468 pjsip_inv_terminate(inv, PJSIP_SC_OK, PJ_FALSE); 469 } 470 471 if (call_id != -1) { 472 reset_call(call_id); 473 pjsua_media_channel_deinit(call_id); 474 } 475 476 PJSUA_UNLOCK(); 477 return status; 478 } 479 334 480 335 481 /* … … 345 491 pj_pool_t *tmp_pool = NULL; 346 492 pjsip_dialog *dlg = NULL; 347 pjmedia_sdp_session *offer;348 pjsip_inv_session *inv = NULL;349 493 pjsua_acc *acc; 350 494 pjsua_call *call; 351 495 int call_id = -1; 352 496 pj_str_t contact; 353 pjsip_tx_data *tdata;354 497 pj_status_t status; 355 498 … … 377 520 pjsua_var.null_snd==NULL && !pjsua_var.no_snd) 378 521 { 379 pj_status_t status;380 381 522 status = pjsua_set_snd_dev(pjsua_var.cap_dev, pjsua_var.play_dev); 382 523 if (status != PJ_SUCCESS) … … 463 604 * fails the dialog will be destroyed prematurely. 464 605 */ 465 pjsip_dlg_inc_lock(dlg);606 // pjsip_dlg_inc_lock(dlg); 466 607 467 608 /* Calculate call's secure level */ 468 609 call->secure_level = get_secure_level(acc_id, dest_uri); 610 611 /* Attach user data */ 612 call->user_data = user_data; 613 614 call->async_call.call_var.out_call.options = options; 615 call->async_call.call_var.out_call.msg_data = pjsua_msg_data_clone( 616 dlg->pool, msg_data); 617 call->async_call.dlg = dlg; 469 618 470 619 /* Init media channel */ 471 620 status = pjsua_media_channel_init(call->index, PJSIP_ROLE_UAC, 472 621 call->secure_level, dlg->pool, 473 NULL, NULL); 474 if (status != PJ_SUCCESS) { 622 NULL, NULL, PJ_TRUE, 623 (pjsua_med_tp_state_cb) 624 &on_make_call_med_tp_complete); 625 if (status == PJ_SUCCESS) { 626 status = on_make_call_med_tp_complete(call->index, NULL); 627 if (status != PJ_SUCCESS) 628 goto on_error; 629 } else if (status != PJ_EPENDING) { 475 630 pjsua_perror(THIS_FILE, "Error initializing media channel", status); 476 631 goto on_error; 477 632 } 478 633 479 /* Create offer */480 status = pjsua_media_channel_create_sdp(call->index, dlg->pool, NULL,481 &offer, NULL);482 if (status != PJ_SUCCESS) {483 pjsua_perror(THIS_FILE, "Error initializing media channel", status);484 goto on_error;485 }486 487 /* Create the INVITE session: */488 options |= PJSIP_INV_SUPPORT_100REL;489 if (acc->cfg.require_100rel)490 options |= PJSIP_INV_REQUIRE_100REL;491 if (acc->cfg.use_timer != PJSUA_SIP_TIMER_INACTIVE) {492 options |= PJSIP_INV_SUPPORT_TIMER;493 if (acc->cfg.use_timer == PJSUA_SIP_TIMER_REQUIRED)494 options |= PJSIP_INV_REQUIRE_TIMER;495 else if (acc->cfg.use_timer == PJSUA_SIP_TIMER_ALWAYS)496 options |= PJSIP_INV_ALWAYS_USE_TIMER;497 }498 499 status = pjsip_inv_create_uac( dlg, offer, options, &inv);500 if (status != PJ_SUCCESS) {501 pjsua_perror(THIS_FILE, "Invite session creation failed", status);502 goto on_error;503 }504 505 /* Init Session Timers */506 status = pjsip_timer_init_session(inv, &acc->cfg.timer_setting);507 if (status != PJ_SUCCESS) {508 pjsua_perror(THIS_FILE, "Session Timer init failed", status);509 goto on_error;510 }511 512 /* Create and associate our data in the session. */513 call->inv = inv;514 515 dlg->mod_data[pjsua_var.mod.id] = call;516 inv->mod_data[pjsua_var.mod.id] = call;517 518 /* Attach user data */519 call->user_data = user_data;520 521 /* If account is locked to specific transport, then lock dialog522 * to this transport too.523 */524 if (acc->cfg.transport_id != PJSUA_INVALID_ID) {525 pjsip_tpselector tp_sel;526 527 pjsua_init_tpselector(acc->cfg.transport_id, &tp_sel);528 pjsip_dlg_set_transport(dlg, &tp_sel);529 }530 531 /* Set dialog Route-Set: */532 if (!pj_list_empty(&acc->route_set))533 pjsip_dlg_set_route_set(dlg, &acc->route_set);534 535 536 /* Set credentials: */537 if (acc->cred_cnt) {538 pjsip_auth_clt_set_credentials( &dlg->auth_sess,539 acc->cred_cnt, acc->cred);540 }541 542 /* Set authentication preference */543 pjsip_auth_clt_set_prefs(&dlg->auth_sess, &acc->cfg.auth_pref);544 545 /* Create initial INVITE: */546 547 status = pjsip_inv_invite(inv, &tdata);548 if (status != PJ_SUCCESS) {549 pjsua_perror(THIS_FILE, "Unable to create initial INVITE request",550 status);551 goto on_error;552 }553 554 555 /* Add additional headers etc */556 557 pjsua_process_msg_data( tdata, msg_data);558 559 /* Must increment call counter now */560 ++pjsua_var.call_cnt;561 562 /* Send initial INVITE: */563 564 status = pjsip_inv_send_msg(inv, tdata);565 if (status != PJ_SUCCESS) {566 pjsua_perror(THIS_FILE, "Unable to send initial INVITE request",567 status);568 569 /* Upon failure to send first request, the invite570 * session would have been cleared.571 */572 inv = NULL;573 goto on_error;574 }575 576 634 /* Done. */ 577 635 … … 579 637 *p_call_id = call_id; 580 638 581 pjsip_dlg_dec_lock(dlg);582 639 pj_pool_release(tmp_pool); 583 640 PJSUA_UNLOCK(); … … 590 647 on_error: 591 648 if (dlg) { 649 pjsip_dlg_inc_lock(dlg); 592 650 /* This may destroy the dialog */ 593 651 pjsip_dlg_dec_lock(dlg); 594 }595 596 if (inv != NULL) {597 pjsip_inv_terminate(inv, PJSIP_SC_OK, PJ_FALSE);598 652 } 599 653 … … 816 870 rdata->tp_info.pool, 817 871 offer, 818 &sip_err_code); 872 &sip_err_code, PJ_FALSE, 873 NULL); 819 874 if (status != PJ_SUCCESS) { 820 875 pjsua_perror(THIS_FILE, "Error initializing media channel", status); … … 833 888 goto on_return; 834 889 } 835 836 890 837 891 /* Verify that we can handle the request. */ … … 1015 1069 1016 1070 ++pjsua_var.call_cnt; 1017 1018 1071 1019 1072 /* Check if this request should replace existing call */ -
pjproject/trunk/pjsip/src/pjsua-lib/pjsua_core.c
r3756 r3763 149 149 pjsip_media_type_init(&msg_data->multipart_ctype, NULL, NULL); 150 150 pj_list_init(&msg_data->multipart_parts); 151 } 152 153 PJ_DEF(pjsua_msg_data*) pjsua_msg_data_clone(pj_pool_t *pool, 154 const pjsua_msg_data *rhs) 155 { 156 pjsua_msg_data *msg_data; 157 const pjsip_hdr *hdr; 158 const pjsip_multipart_part *mpart; 159 160 PJ_ASSERT_RETURN(pool && rhs, NULL); 161 162 msg_data = PJ_POOL_ZALLOC_T(pool, pjsua_msg_data); 163 PJ_ASSERT_RETURN(msg_data != NULL, NULL); 164 165 pj_list_init(&msg_data->hdr_list); 166 hdr = rhs->hdr_list.next; 167 while (hdr != &rhs->hdr_list) { 168 pj_list_push_back(&msg_data->hdr_list, pjsip_hdr_clone(pool, hdr)); 169 hdr = hdr->next; 170 } 171 172 pj_strdup(pool, &msg_data->content_type, &rhs->content_type); 173 pj_strdup(pool, &msg_data->msg_body, &rhs->msg_body); 174 175 pjsip_media_type_cp(pool, &msg_data->multipart_ctype, 176 &rhs->multipart_ctype); 177 178 pj_list_init(&msg_data->multipart_parts); 179 mpart = rhs->multipart_parts.next; 180 while (mpart != &rhs->multipart_parts) { 181 pj_list_push_back(&msg_data->multipart_parts, 182 pjsip_multipart_clone_part(pool, mpart)); 183 mpart = mpart->next; 184 } 185 186 return msg_data; 151 187 } 152 188 -
pjproject/trunk/pjsip/src/pjsua-lib/pjsua_media.c
r3753 r3763 711 711 pjsua_var.media_cfg.rx_drop_pct); 712 712 713 call_med->tp_ready = PJ_SUCCESS; 714 713 715 return PJ_SUCCESS; 714 716 … … 772 774 switch (op) { 773 775 case PJ_ICE_STRANS_OP_INIT: 774 call_med->tp_ready = result; 776 call_med->tp_ready = result; 777 if (call_med->med_create_cb) 778 (*call_med->med_create_cb)(call_med, result, 779 call_med->call->secure_level, NULL); 775 780 break; 776 781 case PJ_ICE_STRANS_OP_NEGOTIATION: … … 832 837 call_med->call->index, call_med->idx)); 833 838 } 839 if (pjsua_var.ua_cfg.cb.on_call_media_transport_state) { 840 pjsua_med_tp_state_info info; 841 842 pj_bzero(&info, sizeof(info)); 843 info.med_idx = call_med->idx; 844 info.state = call_med->tp_st; 845 info.status = result; 846 info.ext_info = &op; 847 (*pjsua_var.ua_cfg.cb.on_call_media_transport_state)( 848 call_med->call->index, &info); 849 } 834 850 if (pjsua_var.ua_cfg.cb.on_ice_transport_error) { 835 851 pjsua_call_id id = call_med->call->index; … … 871 887 static pj_status_t create_ice_media_transport( 872 888 const pjsua_transport_config *cfg, 873 pjsua_call_media *call_med) 889 pjsua_call_media *call_med, 890 pj_bool_t async) 874 891 { 875 892 char stunip[PJ_INET6_ADDRSTRLEN]; … … 953 970 954 971 /* Wait until transport is initialized, or time out */ 955 PJSUA_UNLOCK(); 956 while (call_med->tp_ready == PJ_EPENDING) { 957 pjsua_handle_events(100); 958 } 959 PJSUA_LOCK(); 960 if (call_med->tp_ready != PJ_SUCCESS) { 972 if (!async) { 973 PJSUA_UNLOCK(); 974 while (call_med->tp_ready == PJ_EPENDING) { 975 pjsua_handle_events(100); 976 } 977 PJSUA_LOCK(); 978 } 979 980 if (async && call_med->tp_ready == PJ_EPENDING) { 981 return PJ_EPENDING; 982 } else if (call_med->tp_ready != PJ_SUCCESS) { 961 983 pjsua_perror(THIS_FILE, "Error initializing ICE media transport", 962 984 call_med->tp_ready); … … 1236 1258 } 1237 1259 1260 /* Set media transport state and notify the application via the callback. */ 1261 void set_media_tp_state(pjsua_call_media *call_med, 1262 pjsua_med_tp_st tp_st) 1263 { 1264 if (pjsua_var.ua_cfg.cb.on_call_media_transport_state && 1265 call_med->tp_st != tp_st) 1266 { 1267 pjsua_med_tp_state_info info; 1268 1269 pj_bzero(&info, sizeof(info)); 1270 info.med_idx = call_med->idx; 1271 info.state = tp_st; 1272 info.status = call_med->tp_ready; 1273 (*pjsua_var.ua_cfg.cb.on_call_media_transport_state)( 1274 call_med->call->index, &info); 1275 } 1276 1277 call_med->tp_st = tp_st; 1278 } 1279 1280 /* Callback to resume pjsua_call_media_init() after media transport 1281 * creation is completed. 1282 */ 1283 static pj_status_t call_media_init_cb(pjsua_call_media *call_med, 1284 pj_status_t status, 1285 int security_level, 1286 int *sip_err_code) 1287 { 1288 pjsua_acc *acc = &pjsua_var.acc[call_med->call->acc_id]; 1289 int err_code = 0; 1290 1291 if (status != PJ_SUCCESS) 1292 goto on_error; 1293 1294 if (call_med->tp_st == PJSUA_MED_TP_CREATING) 1295 set_media_tp_state(call_med, PJSUA_MED_TP_IDLE); 1296 1297 #if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0) 1298 /* This function may be called when SRTP transport already exists 1299 * (e.g: in re-invite, update), don't need to destroy/re-create. 1300 */ 1301 if (!call_med->tp_orig || call_med->tp == call_med->tp_orig) { 1302 pjmedia_srtp_setting srtp_opt; 1303 pjmedia_transport *srtp = NULL; 1304 1305 /* Check if SRTP requires secure signaling */ 1306 if (acc->cfg.use_srtp != PJMEDIA_SRTP_DISABLED) { 1307 if (security_level < acc->cfg.srtp_secure_signaling) { 1308 err_code = PJSIP_SC_NOT_ACCEPTABLE; 1309 status = PJSIP_ESESSIONINSECURE; 1310 goto on_error; 1311 } 1312 } 1313 1314 /* Always create SRTP adapter */ 1315 pjmedia_srtp_setting_default(&srtp_opt); 1316 srtp_opt.close_member_tp = PJ_TRUE; 1317 /* If media session has been ever established, let's use remote's 1318 * preference in SRTP usage policy, especially when it is stricter. 1319 */ 1320 if (call_med->rem_srtp_use > acc->cfg.use_srtp) 1321 srtp_opt.use = call_med->rem_srtp_use; 1322 else 1323 srtp_opt.use = acc->cfg.use_srtp; 1324 1325 status = pjmedia_transport_srtp_create(pjsua_var.med_endpt, 1326 call_med->tp, 1327 &srtp_opt, &srtp); 1328 if (status != PJ_SUCCESS) { 1329 err_code = PJSIP_SC_INTERNAL_SERVER_ERROR; 1330 goto on_error; 1331 } 1332 1333 /* Set SRTP as current media transport */ 1334 call_med->tp_orig = call_med->tp; 1335 call_med->tp = srtp; 1336 } 1337 #else 1338 call_med->tp_orig = call_med->tp; 1339 PJ_UNUSED_ARG(security_level); 1340 #endif 1341 1342 pjmedia_event_subscription_init(&call_med->esub_rend, &call_media_on_event, 1343 call_med); 1344 pjmedia_event_subscription_init(&call_med->esub_cap, &call_media_on_event, 1345 call_med); 1346 1347 on_error: 1348 if (status != PJ_SUCCESS && call_med->tp) { 1349 pjmedia_transport_close(call_med->tp); 1350 call_med->tp = NULL; 1351 } 1352 1353 if (sip_err_code) 1354 *sip_err_code = err_code; 1355 1356 if (call_med->med_init_cb) { 1357 pjsua_med_tp_state_info info; 1358 1359 pj_bzero(&info, sizeof(info)); 1360 info.status = status; 1361 info.state = call_med->tp_st; 1362 info.med_idx = call_med->idx; 1363 info.sip_err_code = err_code; 1364 (*call_med->med_init_cb)(call_med->call->index, &info); 1365 } 1366 1367 return status; 1368 } 1369 1238 1370 /* Initialize the media line */ 1239 1371 pj_status_t pjsua_call_media_init(pjsua_call_media *call_med, … … 1241 1373 const pjsua_transport_config *tcfg, 1242 1374 int security_level, 1243 int *sip_err_code) 1375 int *sip_err_code, 1376 pj_bool_t async, 1377 pjsua_med_tp_state_cb cb) 1244 1378 { 1245 1379 pjsua_acc *acc = &pjsua_var.acc[call_med->call->acc_id]; 1246 pj_status_t status ;1380 pj_status_t status = PJ_SUCCESS; 1247 1381 1248 1382 /* … … 1252 1386 call_med->type = type; 1253 1387 1254 /* Create the media transport for initial call. This is blocking for now*/1388 /* Create the media transport for initial call. */ 1255 1389 if (call_med->tp == NULL) { 1256 if (pjsua_var.media_cfg.enable_ice) {1257 status = create_ice_media_transport(tcfg, call_med);1258 } else {1259 status = create_udp_media_transport(tcfg, call_med);1260 }1261 1262 if (status != PJ_SUCCESS) {1263 PJ_PERROR(1,(THIS_FILE, status, "Error creating media transport"));1264 return status;1265 }1266 1267 call_med->tp_st = PJSUA_MED_TP_IDLE;1268 1269 1390 #if defined(PJMEDIA_HAS_VIDEO) && (PJMEDIA_HAS_VIDEO != 0) 1270 1391 /* While in initial call, set default video devices */ … … 1285 1406 #endif 1286 1407 1408 set_media_tp_state(call_med, PJSUA_MED_TP_CREATING); 1409 1410 if (async) { 1411 call_med->med_create_cb = &call_media_init_cb; 1412 call_med->med_init_cb = cb; 1413 } 1414 1415 if (pjsua_var.media_cfg.enable_ice) { 1416 status = create_ice_media_transport(tcfg, call_med, async); 1417 } else { 1418 status = create_udp_media_transport(tcfg, call_med); 1419 } 1420 1421 if (status == PJ_EPENDING) { 1422 /* We will resume call media initialization in the 1423 * on_ice_complete() callback. 1424 */ 1425 return PJ_EPENDING; 1426 } else if (status != PJ_SUCCESS) { 1427 PJ_PERROR(1,(THIS_FILE, status, "Error creating media transport")); 1428 return status; 1429 } 1430 1431 /* Media transport creation completed immediately, so 1432 * we don't need to call the callback. 1433 */ 1434 call_med->med_init_cb = NULL; 1435 1287 1436 } else if (call_med->tp_st == PJSUA_MED_TP_DISABLED) { 1288 1437 /* Media is being reenabled. */ 1289 call_med->tp_st = PJSUA_MED_TP_INIT; 1290 } 1291 1292 #if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0) 1293 /* This function may be called when SRTP transport already exists 1294 * (e.g: in re-invite, update), don't need to destroy/re-create. 1295 */ 1296 if (!call_med->tp_orig || call_med->tp == call_med->tp_orig) { 1297 pjmedia_srtp_setting srtp_opt; 1298 pjmedia_transport *srtp = NULL; 1299 1300 /* Check if SRTP requires secure signaling */ 1301 if (acc->cfg.use_srtp != PJMEDIA_SRTP_DISABLED) { 1302 if (security_level < acc->cfg.srtp_secure_signaling) { 1303 if (sip_err_code) 1304 *sip_err_code = PJSIP_SC_NOT_ACCEPTABLE; 1305 status = PJSIP_ESESSIONINSECURE; 1438 set_media_tp_state(call_med, PJSUA_MED_TP_INIT); 1439 } 1440 1441 return call_media_init_cb(call_med, status, security_level, 1442 sip_err_code); 1443 } 1444 1445 /* Callback to resume pjsua_media_channel_init() after media transport 1446 * initialization is completed. 1447 */ 1448 static pj_status_t media_channel_init_cb(pjsua_call_id call_id, 1449 const pjsua_med_tp_state_info *info) 1450 { 1451 pjsua_call *call = &pjsua_var.calls[call_id]; 1452 pj_status_t status = (info? info->status : PJ_SUCCESS); 1453 unsigned mi; 1454 1455 if (info) { 1456 pj_mutex_lock(call->med_ch_mutex); 1457 1458 /* Set the callback to NULL to indicate that the async operation 1459 * has completed. 1460 */ 1461 call->media[info->med_idx].med_init_cb = NULL; 1462 1463 /* In case of failure, save the information to be returned 1464 * by the last media transport to finish. 1465 */ 1466 if (info->status != PJ_SUCCESS) 1467 pj_memcpy(&call->med_ch_info, info, sizeof(info)); 1468 1469 /* Check whether all the call's medias have finished calling their 1470 * callbacks. 1471 */ 1472 for (mi=0; mi < call->med_cnt; ++mi) { 1473 pjsua_call_media *call_med = &call->media[mi]; 1474 1475 if (call_med->med_init_cb) { 1476 pj_mutex_unlock(call->med_ch_mutex); 1477 return PJ_SUCCESS; 1478 } 1479 1480 if (call_med->tp_ready != PJ_SUCCESS) 1481 status = call_med->tp_ready; 1482 } 1483 1484 /* OK, we are called by the last media transport finished. */ 1485 pj_mutex_unlock(call->med_ch_mutex); 1486 } 1487 1488 if (call->med_ch_mutex) { 1489 pj_mutex_destroy(call->med_ch_mutex); 1490 call->med_ch_mutex = NULL; 1491 } 1492 1493 if (status != PJ_SUCCESS) { 1494 pjsua_media_channel_deinit(call_id); 1495 goto on_error; 1496 } 1497 1498 /* Tell the media transport of a new offer/answer session */ 1499 for (mi=0; mi < call->med_cnt; ++mi) { 1500 pjsua_call_media *call_med = &call->media[mi]; 1501 1502 /* Note: tp may be NULL if this media line is disabled */ 1503 if (call_med->tp && call_med->tp_st == PJSUA_MED_TP_IDLE) { 1504 pj_pool_t *tmp_pool = (call->inv? call->inv->pool_prov: 1505 call->async_call.dlg->pool); 1506 1507 status = pjmedia_transport_media_create( 1508 call_med->tp, tmp_pool, 1509 0, call->async_call.rem_sdp, mi); 1510 if (status != PJ_SUCCESS) { 1511 call->med_ch_info.status = status; 1512 call->med_ch_info.med_idx = mi; 1513 call->med_ch_info.state = call_med->tp_st; 1514 call->med_ch_info.sip_err_code = PJSIP_SC_NOT_ACCEPTABLE; 1515 pjsua_media_channel_deinit(call_id); 1306 1516 goto on_error; 1307 1517 } 1308 } 1309 1310 /* Always create SRTP adapter */ 1311 pjmedia_srtp_setting_default(&srtp_opt); 1312 srtp_opt.close_member_tp = PJ_TRUE; 1313 /* If media session has been ever established, let's use remote's 1314 * preference in SRTP usage policy, especially when it is stricter. 1315 */ 1316 if (call_med->rem_srtp_use > acc->cfg.use_srtp) 1317 srtp_opt.use = call_med->rem_srtp_use; 1318 else 1319 srtp_opt.use = acc->cfg.use_srtp; 1320 1321 status = pjmedia_transport_srtp_create(pjsua_var.med_endpt, 1322 call_med->tp, 1323 &srtp_opt, &srtp); 1324 if (status != PJ_SUCCESS) { 1325 if (sip_err_code) 1326 *sip_err_code = PJSIP_SC_INTERNAL_SERVER_ERROR; 1327 goto on_error; 1328 } 1329 1330 /* Set SRTP as current media transport */ 1331 call_med->tp_orig = call_med->tp; 1332 call_med->tp = srtp; 1333 } 1334 #else 1335 call_med->tp_orig = call_med->tp; 1336 PJ_UNUSED_ARG(security_level); 1337 #endif 1338 1339 pjmedia_event_subscription_init(&call_med->esub_rend, &call_media_on_event, 1340 call_med); 1341 pjmedia_event_subscription_init(&call_med->esub_cap, &call_media_on_event, 1342 call_med); 1343 1344 return PJ_SUCCESS; 1518 1519 set_media_tp_state(call_med, PJSUA_MED_TP_INIT); 1520 } 1521 } 1522 1523 call->med_ch_info.status = PJ_SUCCESS; 1345 1524 1346 1525 on_error: 1347 if (call_med->tp) { 1348 pjmedia_transport_close(call_med->tp); 1349 call_med->tp = NULL; 1350 } 1526 if (call->med_ch_cb) 1527 (*call->med_ch_cb)(call->index, &call->med_ch_info); 1528 1351 1529 return status; 1352 1530 } … … 1357 1535 pj_pool_t *tmp_pool, 1358 1536 const pjmedia_sdp_session *rem_sdp, 1359 int *sip_err_code) 1537 int *sip_err_code, 1538 pj_bool_t async, 1539 pjsua_med_tp_state_cb cb) 1360 1540 { 1361 1541 const pj_str_t STR_AUDIO = { "audio", 5 }; … … 1369 1549 pjmedia_type media_types[PJSUA_MAX_CALL_MEDIA]; 1370 1550 unsigned mi; 1551 pj_bool_t pending_med_tp = PJ_FALSE; 1371 1552 pj_status_t status; 1372 1553 1373 1554 PJ_UNUSED_ARG(role); 1555 PJ_UNUSED_ARG(tmp_pool); 1374 1556 1375 1557 /* … … 1380 1562 if (pjsua_get_state() != PJSUA_STATE_RUNNING) 1381 1563 return PJ_EBUSY; 1564 1565 if (async) { 1566 pj_pool_t *tmppool = (call->inv? call->inv->pool_prov: 1567 call->async_call.dlg->pool); 1568 1569 status = pj_mutex_create_simple(tmppool, NULL, &call->med_ch_mutex); 1570 if (status != PJ_SUCCESS) 1571 return status; 1572 } 1382 1573 1383 1574 PJ_LOG(4,(THIS_FILE, "Call %d: initializing media..", call_id)); … … 1450 1641 status = PJSIP_ERRNO_FROM_SIP_STATUS(PJSIP_SC_NOT_ACCEPTABLE_HERE); 1451 1642 goto on_error; 1643 } 1644 1645 if (async) { 1646 call->med_ch_cb = cb; 1647 if (rem_sdp) { 1648 /* TODO: change rem_sdp to non-const parameter. */ 1649 call->async_call.rem_sdp = 1650 pjmedia_sdp_session_clone(call->inv->pool_prov, rem_sdp); 1651 } 1452 1652 } 1453 1653 … … 1483 1683 status = pjsua_call_media_init(call_med, media_type, 1484 1684 &acc->cfg.rtp_cfg, 1485 security_level, sip_err_code); 1486 if (status != PJ_SUCCESS) { 1487 pjsua_media_channel_deinit(call_id); 1685 security_level, sip_err_code, 1686 async, 1687 (async? (pjsua_med_tp_state_cb) 1688 &media_channel_init_cb: NULL)); 1689 if (status == PJ_EPENDING) { 1690 pending_med_tp = PJ_TRUE; 1691 } else if (status != PJ_SUCCESS) { 1692 if (pending_med_tp) { 1693 /* Save failure information. */ 1694 call_med->tp_ready = status; 1695 pj_bzero(&call->med_ch_info, sizeof(call->med_ch_info)); 1696 call->med_ch_info.status = status; 1697 call->med_ch_info.state = call_med->tp_st; 1698 call->med_ch_info.med_idx = call_med->idx; 1699 if (sip_err_code) 1700 call->med_ch_info.sip_err_code = *sip_err_code; 1701 1702 /* We will return failure in the callback later. */ 1703 return PJ_EPENDING; 1704 } 1705 1706 pjsua_media_channel_deinit(call_id); 1488 1707 goto on_error; 1489 1708 } … … 1499 1718 pj_assert(call_med->tp_st == PJSUA_MED_TP_INIT || 1500 1719 call_med->tp_st == PJSUA_MED_TP_RUNNING); 1501 call_med->tp_st = PJSUA_MED_TP_DISABLED;1720 set_media_tp_state(call_med, PJSUA_MED_TP_DISABLED); 1502 1721 } 1503 1722 … … 1512 1731 call->audio_idx, call->index)); 1513 1732 1514 /* Tell the media transport of a new offer/answer session */ 1515 for (mi=0; mi < call->med_cnt; ++mi) { 1516 pjsua_call_media *call_med = &call->media[mi]; 1517 1518 /* Note: tp may be NULL if this media line is disabled */ 1519 if (call_med->tp && call_med->tp_st == PJSUA_MED_TP_IDLE) { 1520 status = pjmedia_transport_media_create(call_med->tp, 1521 tmp_pool, 0, 1522 rem_sdp, mi); 1523 if (status != PJ_SUCCESS) { 1524 if (sip_err_code) *sip_err_code = PJSIP_SC_NOT_ACCEPTABLE; 1525 pjsua_media_channel_deinit(call_id); 1526 goto on_error; 1527 } 1528 1529 call_med->tp_st = PJSUA_MED_TP_INIT; 1530 } 1531 } 1733 if (pending_med_tp) { 1734 /* We have a pending media transport initialization. */ 1735 pj_log_pop_indent(); 1736 return PJ_EPENDING; 1737 } 1738 1739 /* Media transport initialization completed immediately, so 1740 * we don't need to call the callback. 1741 */ 1742 call->med_ch_cb = NULL; 1743 1744 status = media_channel_init_cb(call_id, NULL); 1745 if (status != PJ_SUCCESS && sip_err_code) 1746 *sip_err_code = call->med_ch_info.sip_err_code; 1532 1747 1533 1748 pj_log_pop_indent(); 1534 return PJ_SUCCESS;1749 return status; 1535 1750 1536 1751 on_error: 1752 if (call->med_ch_mutex) { 1753 pj_mutex_destroy(call->med_ch_mutex); 1754 call->med_ch_mutex = NULL; 1755 } 1756 1537 1757 pj_log_pop_indent(); 1538 1758 return status; … … 1563 1783 status = pjsua_media_channel_init(call_id, PJSIP_ROLE_UAS, 1564 1784 call->secure_level, pool, 1565 rem_sdp, sip_err_code); 1785 rem_sdp, sip_err_code, 1786 PJ_FALSE, NULL); 1566 1787 if (status != PJ_SUCCESS) 1567 1788 return status; … … 1886 2107 pjsua_call_media *call_med = &call->media[mi]; 1887 2108 1888 if (call_med->tp_st !=PJSUA_MED_TP_IDLE) {2109 if (call_med->tp_st > PJSUA_MED_TP_IDLE) { 1889 2110 pjmedia_transport_media_stop(call_med->tp); 1890 call_med->tp_st = PJSUA_MED_TP_IDLE;2111 set_media_tp_state(call_med, PJSUA_MED_TP_IDLE); 1891 2112 } 1892 2113 … … 1972 2193 goto on_return; 1973 2194 1974 call_med->tp_st = PJSUA_MED_TP_RUNNING;2195 set_media_tp_state(call_med, PJSUA_MED_TP_RUNNING); 1975 2196 1976 2197 /* Get remote SRTP usage policy */ … … 2264 2485 pjmedia_transport_close(call_med->tp); 2265 2486 call_med->tp = call_med->tp_orig = NULL; 2266 call_med->tp_st = PJSUA_MED_TP_IDLE;2487 set_media_tp_state(call_med, PJSUA_MED_TP_IDLE); 2267 2488 } 2268 2489 -
pjproject/trunk/pjsip/src/pjsua-lib/pjsua_vid.c
r3758 r3763 676 676 goto on_error; 677 677 678 call_med->tp_st = PJSUA_MED_TP_RUNNING;678 set_media_tp_state(call_med, PJSUA_MED_TP_RUNNING); 679 679 680 680 /* Get remote SRTP usage policy */ … … 1473 1473 status = pjsua_call_media_init(call_med, PJMEDIA_TYPE_VIDEO, 1474 1474 &acc_cfg->rtp_cfg, call->secure_level, 1475 NULL );1475 NULL, PJ_FALSE, NULL); 1476 1476 if (status != PJ_SUCCESS) 1477 1477 goto on_error; … … 1486 1486 goto on_error; 1487 1487 1488 call_med->tp_st = PJSUA_MED_TP_INIT;1488 set_media_tp_state(call_med, PJSUA_MED_TP_INIT); 1489 1489 1490 1490 /* Get transport address info */ … … 1593 1593 status = pjsua_call_media_init(call_med, PJMEDIA_TYPE_VIDEO, 1594 1594 &acc_cfg->rtp_cfg, call->secure_level, 1595 NULL );1595 NULL, PJ_FALSE, NULL); 1596 1596 if (status != PJ_SUCCESS) 1597 1597 goto on_error; … … 1663 1663 // Don't close this here, as SDP negotiation has not been 1664 1664 // done and stream may be still active. 1665 call_med->tp_st = PJSUA_MED_TP_DISABLED;1665 set_media_tp_state(call_med, PJSUA_MED_TP_DISABLED); 1666 1666 1667 1667 /* Deactivate the stream */
Note: See TracChangeset
for help on using the changeset viewer.