Changeset 3664 for pjproject/trunk/pjsip/src/pjsua-lib/pjsua_media.c
- Timestamp:
- Jul 19, 2011 3:42:28 AM (13 years ago)
- Location:
- pjproject/trunk
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
pjproject/trunk
- Property svn:mergeinfo changed
-
pjproject/trunk/pjsip/src/pjsua-lib/pjsua_media.c
r3553 r3664 59 59 } 60 60 61 61 62 /** 62 63 * Init media subsystems. … … 66 67 pj_str_t codec_id = {NULL, 0}; 67 68 unsigned opt; 69 pjmedia_audio_codec_config codec_cfg; 68 70 pj_status_t status; 69 71 … … 112 114 } 113 115 114 /* Register all codecs */ 115 116 #if PJMEDIA_HAS_SPEEX_CODEC 117 /* Register speex. */ 118 status = pjmedia_codec_speex_init(pjsua_var.med_endpt, 119 0, 120 pjsua_var.media_cfg.quality, 121 -1); 122 if (status != PJ_SUCCESS) { 123 pjsua_perror(THIS_FILE, "Error initializing Speex codec", 124 status); 125 return status; 126 } 127 128 /* Set speex/16000 to higher priority*/ 129 codec_id = pj_str("speex/16000"); 130 pjmedia_codec_mgr_set_codec_priority( 131 pjmedia_endpt_get_codec_mgr(pjsua_var.med_endpt), 132 &codec_id, PJMEDIA_CODEC_PRIO_NORMAL+2); 133 134 /* Set speex/8000 to next higher priority*/ 135 codec_id = pj_str("speex/8000"); 136 pjmedia_codec_mgr_set_codec_priority( 137 pjmedia_endpt_get_codec_mgr(pjsua_var.med_endpt), 138 &codec_id, PJMEDIA_CODEC_PRIO_NORMAL+1); 139 140 141 142 #endif /* PJMEDIA_HAS_SPEEX_CODEC */ 143 144 #if PJMEDIA_HAS_ILBC_CODEC 145 /* Register iLBC. */ 146 status = pjmedia_codec_ilbc_init( pjsua_var.med_endpt, 147 pjsua_var.media_cfg.ilbc_mode); 148 if (status != PJ_SUCCESS) { 149 pjsua_perror(THIS_FILE, "Error initializing iLBC codec", 150 status); 151 return status; 152 } 153 #endif /* PJMEDIA_HAS_ILBC_CODEC */ 154 155 #if PJMEDIA_HAS_GSM_CODEC 156 /* Register GSM */ 157 status = pjmedia_codec_gsm_init(pjsua_var.med_endpt); 158 if (status != PJ_SUCCESS) { 159 pjsua_perror(THIS_FILE, "Error initializing GSM codec", 160 status); 161 return status; 162 } 163 #endif /* PJMEDIA_HAS_GSM_CODEC */ 164 165 #if PJMEDIA_HAS_G711_CODEC 166 /* Register PCMA and PCMU */ 167 status = pjmedia_codec_g711_init(pjsua_var.med_endpt); 168 if (status != PJ_SUCCESS) { 169 pjsua_perror(THIS_FILE, "Error initializing G711 codec", 170 status); 171 return status; 172 } 173 #endif /* PJMEDIA_HAS_G711_CODEC */ 174 175 #if PJMEDIA_HAS_G722_CODEC 176 status = pjmedia_codec_g722_init( pjsua_var.med_endpt ); 177 if (status != PJ_SUCCESS) { 178 pjsua_perror(THIS_FILE, "Error initializing G722 codec", 179 status); 180 return status; 181 } 182 #endif /* PJMEDIA_HAS_G722_CODEC */ 183 184 #if PJMEDIA_HAS_INTEL_IPP 185 /* Register IPP codecs */ 186 status = pjmedia_codec_ipp_init(pjsua_var.med_endpt); 187 if (status != PJ_SUCCESS) { 188 pjsua_perror(THIS_FILE, "Error initializing IPP codecs", 189 status); 190 return status; 191 } 192 193 #endif /* PJMEDIA_HAS_INTEL_IPP */ 116 /* 117 * Register all codecs 118 */ 119 pjmedia_audio_codec_config_default(&codec_cfg); 120 codec_cfg.speex.quality = pjsua_var.media_cfg.quality; 121 codec_cfg.speex.complexity = -1; 122 codec_cfg.ilbc.mode = pjsua_var.media_cfg.ilbc_mode; 194 123 195 124 #if PJMEDIA_HAS_PASSTHROUGH_CODECS … … 199 128 unsigned ext_fmt_cnt = 0; 200 129 pjmedia_format ext_fmts[32]; 201 pjmedia_codec_passthrough_setting setting;202 130 203 131 /* List extended formats supported by audio devices */ … … 236 164 237 165 /* Init the passthrough codec with supported formats only */ 238 setting.fmt_cnt = ext_fmt_cnt; 239 setting.fmts = ext_fmts; 240 setting.ilbc_mode = cfg->ilbc_mode; 241 status = pjmedia_codec_passthrough_init2(pjsua_var.med_endpt, &setting); 242 if (status != PJ_SUCCESS) { 243 pjsua_perror(THIS_FILE, "Error initializing passthrough codecs", 244 status); 245 return status; 246 } 166 codec_cfg.passthrough.setting.fmt_cnt = ext_fmt_cnt; 167 codec_cfg.passthrough.setting.fmts = ext_fmts; 168 codec_cfg.passthrough.setting.ilbc_mode = cfg->ilbc_mode; 247 169 } 248 170 #endif /* PJMEDIA_HAS_PASSTHROUGH_CODECS */ 249 171 250 #if PJMEDIA_HAS_G7221_CODEC 251 /* Register G722.1 codecs */252 status = pjmedia_codec_g7221_init(pjsua_var.med_endpt);172 /* Register all codecs */ 173 status = pjmedia_codec_register_audio_codecs(pjsua_var.med_endpt, 174 &codec_cfg); 253 175 if (status != PJ_SUCCESS) { 254 pjsua_perror(THIS_FILE, "Error initializing G722.1 codec", 255 status); 176 PJ_PERROR(1,(THIS_FILE, status, "Error registering codecs")); 256 177 return status; 257 178 } 258 #endif /* PJMEDIA_HAS_G7221_CODEC */ 259 260 #if PJMEDIA_HAS_L16_CODEC 261 /* Register L16 family codecs, but disable all */ 262 status = pjmedia_codec_l16_init(pjsua_var.med_endpt, 0); 263 if (status != PJ_SUCCESS) { 264 pjsua_perror(THIS_FILE, "Error initializing L16 codecs", 265 status); 266 return status; 267 } 179 180 /* Set speex/16000 to higher priority*/ 181 codec_id = pj_str("speex/16000"); 182 pjmedia_codec_mgr_set_codec_priority( 183 pjmedia_endpt_get_codec_mgr(pjsua_var.med_endpt), 184 &codec_id, PJMEDIA_CODEC_PRIO_NORMAL+2); 185 186 /* Set speex/8000 to next higher priority*/ 187 codec_id = pj_str("speex/8000"); 188 pjmedia_codec_mgr_set_codec_priority( 189 pjmedia_endpt_get_codec_mgr(pjsua_var.med_endpt), 190 &codec_id, PJMEDIA_CODEC_PRIO_NORMAL+1); 268 191 269 192 /* Disable ALL L16 codecs */ … … 272 195 pjmedia_endpt_get_codec_mgr(pjsua_var.med_endpt), 273 196 &codec_id, PJMEDIA_CODEC_PRIO_DISABLED); 274 275 #endif /* PJMEDIA_HAS_L16_CODEC */276 197 277 198 … … 297 218 } 298 219 299 300 220 /* Init conference bridge. */ 301 221 status = pjmedia_conf_create(pjsua_var.pool, … … 335 255 #endif 336 256 257 /* Video */ 258 #if PJMEDIA_HAS_VIDEO 259 status = pjsua_vid_subsys_init(); 260 if (status != PJ_SUCCESS) 261 return status; 262 #endif 263 337 264 return PJ_SUCCESS; 338 265 } 339 266 340 341 /*342 * Create RTP and RTCP socket pair, and possibly resolve their public343 * address via STUN.344 */345 static pj_status_t create_rtp_rtcp_sock(const pjsua_transport_config *cfg,346 pjmedia_sock_info *skinfo)347 {348 enum {349 RTP_RETRY = 100350 };351 int i;352 pj_sockaddr_in bound_addr;353 pj_sockaddr_in mapped_addr[2];354 pj_status_t status = PJ_SUCCESS;355 char addr_buf[PJ_INET6_ADDRSTRLEN+2];356 pj_sock_t sock[2];357 358 /* Make sure STUN server resolution has completed */359 status = resolve_stun_server(PJ_TRUE);360 if (status != PJ_SUCCESS) {361 pjsua_perror(THIS_FILE, "Error resolving STUN server", status);362 return status;363 }364 365 if (next_rtp_port == 0)366 next_rtp_port = (pj_uint16_t)cfg->port;367 368 for (i=0; i<2; ++i)369 sock[i] = PJ_INVALID_SOCKET;370 371 bound_addr.sin_addr.s_addr = PJ_INADDR_ANY;372 if (cfg->bound_addr.slen) {373 status = pj_sockaddr_in_set_str_addr(&bound_addr, &cfg->bound_addr);374 if (status != PJ_SUCCESS) {375 pjsua_perror(THIS_FILE, "Unable to resolve transport bind address",376 status);377 return status;378 }379 }380 381 /* Loop retry to bind RTP and RTCP sockets. */382 for (i=0; i<RTP_RETRY; ++i, next_rtp_port += 2) {383 384 /* Create RTP socket. */385 status = pj_sock_socket(pj_AF_INET(), pj_SOCK_DGRAM(), 0, &sock[0]);386 if (status != PJ_SUCCESS) {387 pjsua_perror(THIS_FILE, "socket() error", status);388 return status;389 }390 391 /* Apply QoS to RTP socket, if specified */392 status = pj_sock_apply_qos2(sock[0], cfg->qos_type,393 &cfg->qos_params,394 2, THIS_FILE, "RTP socket");395 396 /* Bind RTP socket */397 status=pj_sock_bind_in(sock[0], pj_ntohl(bound_addr.sin_addr.s_addr),398 next_rtp_port);399 if (status != PJ_SUCCESS) {400 pj_sock_close(sock[0]);401 sock[0] = PJ_INVALID_SOCKET;402 continue;403 }404 405 /* Create RTCP socket. */406 status = pj_sock_socket(pj_AF_INET(), pj_SOCK_DGRAM(), 0, &sock[1]);407 if (status != PJ_SUCCESS) {408 pjsua_perror(THIS_FILE, "socket() error", status);409 pj_sock_close(sock[0]);410 return status;411 }412 413 /* Apply QoS to RTCP socket, if specified */414 status = pj_sock_apply_qos2(sock[1], cfg->qos_type,415 &cfg->qos_params,416 2, THIS_FILE, "RTCP socket");417 418 /* Bind RTCP socket */419 status=pj_sock_bind_in(sock[1], pj_ntohl(bound_addr.sin_addr.s_addr),420 (pj_uint16_t)(next_rtp_port+1));421 if (status != PJ_SUCCESS) {422 pj_sock_close(sock[0]);423 sock[0] = PJ_INVALID_SOCKET;424 425 pj_sock_close(sock[1]);426 sock[1] = PJ_INVALID_SOCKET;427 continue;428 }429 430 /*431 * If we're configured to use STUN, then find out the mapped address,432 * and make sure that the mapped RTCP port is adjacent with the RTP.433 */434 if (pjsua_var.stun_srv.addr.sa_family != 0) {435 char ip_addr[32];436 pj_str_t stun_srv;437 438 pj_ansi_strcpy(ip_addr,439 pj_inet_ntoa(pjsua_var.stun_srv.ipv4.sin_addr));440 stun_srv = pj_str(ip_addr);441 442 status=pjstun_get_mapped_addr(&pjsua_var.cp.factory, 2, sock,443 &stun_srv, pj_ntohs(pjsua_var.stun_srv.ipv4.sin_port),444 &stun_srv, pj_ntohs(pjsua_var.stun_srv.ipv4.sin_port),445 mapped_addr);446 if (status != PJ_SUCCESS) {447 pjsua_perror(THIS_FILE, "STUN resolve error", status);448 goto on_error;449 }450 451 #if PJSUA_REQUIRE_CONSECUTIVE_RTCP_PORT452 if (pj_ntohs(mapped_addr[1].sin_port) ==453 pj_ntohs(mapped_addr[0].sin_port)+1)454 {455 /* Success! */456 break;457 }458 459 pj_sock_close(sock[0]);460 sock[0] = PJ_INVALID_SOCKET;461 462 pj_sock_close(sock[1]);463 sock[1] = PJ_INVALID_SOCKET;464 #else465 if (pj_ntohs(mapped_addr[1].sin_port) !=466 pj_ntohs(mapped_addr[0].sin_port)+1)467 {468 PJ_LOG(4,(THIS_FILE,469 "Note: STUN mapped RTCP port %d is not adjacent"470 " to RTP port %d",471 pj_ntohs(mapped_addr[1].sin_port),472 pj_ntohs(mapped_addr[0].sin_port)));473 }474 /* Success! */475 break;476 #endif477 478 } else if (cfg->public_addr.slen) {479 480 status = pj_sockaddr_in_init(&mapped_addr[0], &cfg->public_addr,481 (pj_uint16_t)next_rtp_port);482 if (status != PJ_SUCCESS)483 goto on_error;484 485 status = pj_sockaddr_in_init(&mapped_addr[1], &cfg->public_addr,486 (pj_uint16_t)(next_rtp_port+1));487 if (status != PJ_SUCCESS)488 goto on_error;489 490 break;491 492 } else {493 494 if (bound_addr.sin_addr.s_addr == 0) {495 pj_sockaddr addr;496 497 /* Get local IP address. */498 status = pj_gethostip(pj_AF_INET(), &addr);499 if (status != PJ_SUCCESS)500 goto on_error;501 502 bound_addr.sin_addr.s_addr = addr.ipv4.sin_addr.s_addr;503 }504 505 for (i=0; i<2; ++i) {506 pj_sockaddr_in_init(&mapped_addr[i], NULL, 0);507 mapped_addr[i].sin_addr.s_addr = bound_addr.sin_addr.s_addr;508 }509 510 mapped_addr[0].sin_port=pj_htons((pj_uint16_t)next_rtp_port);511 mapped_addr[1].sin_port=pj_htons((pj_uint16_t)(next_rtp_port+1));512 break;513 }514 }515 516 if (sock[0] == PJ_INVALID_SOCKET) {517 PJ_LOG(1,(THIS_FILE,518 "Unable to find appropriate RTP/RTCP ports combination"));519 goto on_error;520 }521 522 523 skinfo->rtp_sock = sock[0];524 pj_memcpy(&skinfo->rtp_addr_name,525 &mapped_addr[0], sizeof(pj_sockaddr_in));526 527 skinfo->rtcp_sock = sock[1];528 pj_memcpy(&skinfo->rtcp_addr_name,529 &mapped_addr[1], sizeof(pj_sockaddr_in));530 531 PJ_LOG(4,(THIS_FILE, "RTP socket reachable at %s",532 pj_sockaddr_print(&skinfo->rtp_addr_name, addr_buf,533 sizeof(addr_buf), 3)));534 PJ_LOG(4,(THIS_FILE, "RTCP socket reachable at %s",535 pj_sockaddr_print(&skinfo->rtcp_addr_name, addr_buf,536 sizeof(addr_buf), 3)));537 538 next_rtp_port += 2;539 return PJ_SUCCESS;540 541 on_error:542 for (i=0; i<2; ++i) {543 if (sock[i] != PJ_INVALID_SOCKET)544 pj_sock_close(sock[i]);545 }546 return status;547 }548 267 549 268 /* Check if sound device is idle. */ … … 578 297 * It is idle when there is no port connection in the bridge and 579 298 * there is no active call. 299 * 300 * Note: this block is now valid if no snd dev is used because of #1299 580 301 */ 581 if ((pjsua_var.snd_port!=NULL || pjsua_var.null_snd!=NULL) && 302 if ((pjsua_var.snd_port!=NULL || pjsua_var.null_snd!=NULL || 303 pjsua_var.no_snd) && 582 304 pjsua_var.snd_idle_timer.id == PJ_FALSE && 583 305 pjmedia_conf_get_connect_count(pjsua_var.mconf) == 0 && … … 591 313 592 314 pjsua_var.snd_idle_timer.id = PJ_TRUE; 593 pjsip_endpt_schedule_timer(pjsua_var.endpt, &pjsua_var.snd_idle_timer, 315 pjsip_endpt_schedule_timer(pjsua_var.endpt, &pjsua_var.snd_idle_timer, 594 316 &delay); 595 317 } … … 605 327 PJSUA_LOCK(); 606 328 if (entry->id) { 607 PJ_LOG(4,(THIS_FILE,"Closing sound device after idle for %d seconds", 329 PJ_LOG(4,(THIS_FILE,"Closing sound device after idle for %d seconds", 608 330 pjsua_var.media_cfg.snd_auto_close_time)); 609 331 … … 623 345 pj_status_t status; 624 346 347 #if DISABLED_FOR_TICKET_1185 625 348 /* Create media for calls, if none is specified */ 626 if (pjsua_var.calls[0].med _tp == NULL) {349 if (pjsua_var.calls[0].media[0].tp == NULL) { 627 350 pjsua_transport_config transport_cfg; 628 351 … … 635 358 return status; 636 359 } 637 638 pj_timer_entry_init(&pjsua_var.snd_idle_timer, PJ_FALSE, NULL, 360 #endif 361 362 pj_timer_entry_init(&pjsua_var.snd_idle_timer, PJ_FALSE, NULL, 639 363 &close_snd_timer_cb); 640 364 365 /* Video */ 366 #if PJMEDIA_HAS_VIDEO 367 status = pjsua_vid_subsys_start(); 368 if (status != PJ_SUCCESS) 369 return status; 370 #endif 371 641 372 /* Perform NAT detection */ 642 pjsua_detect_nat_type(); 373 status = pjsua_detect_nat_type(); 374 if (status != PJ_SUCCESS) { 375 PJ_PERROR(1,(THIS_FILE, status, "NAT type detection failed")); 376 } 643 377 644 378 return PJ_SUCCESS; … … 685 419 /* Close media transports */ 686 420 for (i=0; i<pjsua_var.ua_cfg.max_calls; ++i) { 687 if (pjsua_var.calls[i].med_tp_st != PJSUA_MED_TP_IDLE) { 688 pjsua_media_channel_deinit(i); 689 } 690 if (pjsua_var.calls[i].med_tp && pjsua_var.calls[i].med_tp_auto_del) { 691 pjmedia_transport_close(pjsua_var.calls[i].med_tp); 692 } 693 pjsua_var.calls[i].med_tp = NULL; 421 unsigned strm_idx; 422 pjsua_call *call = &pjsua_var.calls[i]; 423 for (strm_idx=0; strm_idx<call->med_cnt; ++strm_idx) { 424 pjsua_call_media *call_med = &call->media[strm_idx]; 425 if (call_med->tp_st != PJSUA_MED_TP_IDLE) { 426 pjsua_media_channel_deinit(i); 427 } 428 if (call_med->tp && call_med->tp_auto_del) { 429 pjmedia_transport_close(call_med->tp); 430 } 431 call_med->tp = NULL; 432 } 694 433 } 695 434 … … 697 436 if (pjsua_var.med_endpt) { 698 437 699 /* Shutdown all codecs: */ 700 # if PJMEDIA_HAS_SPEEX_CODEC 701 pjmedia_codec_speex_deinit(); 702 # endif /* PJMEDIA_HAS_SPEEX_CODEC */ 703 704 # if PJMEDIA_HAS_GSM_CODEC 705 pjmedia_codec_gsm_deinit(); 706 # endif /* PJMEDIA_HAS_GSM_CODEC */ 707 708 # if PJMEDIA_HAS_G711_CODEC 709 pjmedia_codec_g711_deinit(); 710 # endif /* PJMEDIA_HAS_G711_CODEC */ 711 712 # if PJMEDIA_HAS_G722_CODEC 713 pjmedia_codec_g722_deinit(); 714 # endif /* PJMEDIA_HAS_G722_CODEC */ 715 716 # if PJMEDIA_HAS_INTEL_IPP 717 pjmedia_codec_ipp_deinit(); 718 # endif /* PJMEDIA_HAS_INTEL_IPP */ 719 720 # if PJMEDIA_HAS_PASSTHROUGH_CODECS 721 pjmedia_codec_passthrough_deinit(); 722 # endif /* PJMEDIA_HAS_PASSTHROUGH_CODECS */ 723 724 # if PJMEDIA_HAS_G7221_CODEC 725 pjmedia_codec_g7221_deinit(); 726 # endif /* PJMEDIA_HAS_G7221_CODEC */ 727 728 # if PJMEDIA_HAS_L16_CODEC 729 pjmedia_codec_l16_deinit(); 730 # endif /* PJMEDIA_HAS_L16_CODEC */ 438 # if PJMEDIA_HAS_VIDEO 439 pjsua_vid_subsys_destroy(); 440 # endif 731 441 732 442 pjmedia_endpt_destroy(pjsua_var.med_endpt); … … 745 455 } 746 456 747 457 /* 458 * Create RTP and RTCP socket pair, and possibly resolve their public 459 * address via STUN. 460 */ 461 static pj_status_t create_rtp_rtcp_sock(const pjsua_transport_config *cfg, 462 pjmedia_sock_info *skinfo) 463 { 464 enum { 465 RTP_RETRY = 100 466 }; 467 int i; 468 pj_sockaddr_in bound_addr; 469 pj_sockaddr_in mapped_addr[2]; 470 pj_status_t status = PJ_SUCCESS; 471 char addr_buf[PJ_INET6_ADDRSTRLEN+2]; 472 pj_sock_t sock[2]; 473 474 /* Make sure STUN server resolution has completed */ 475 status = resolve_stun_server(PJ_TRUE); 476 if (status != PJ_SUCCESS) { 477 pjsua_perror(THIS_FILE, "Error resolving STUN server", status); 478 return status; 479 } 480 481 if (next_rtp_port == 0) 482 next_rtp_port = (pj_uint16_t)cfg->port; 483 484 if (next_rtp_port == 0) 485 next_rtp_port = (pj_uint16_t)40000; 486 487 for (i=0; i<2; ++i) 488 sock[i] = PJ_INVALID_SOCKET; 489 490 bound_addr.sin_addr.s_addr = PJ_INADDR_ANY; 491 if (cfg->bound_addr.slen) { 492 status = pj_sockaddr_in_set_str_addr(&bound_addr, &cfg->bound_addr); 493 if (status != PJ_SUCCESS) { 494 pjsua_perror(THIS_FILE, "Unable to resolve transport bind address", 495 status); 496 return status; 497 } 498 } 499 500 /* Loop retry to bind RTP and RTCP sockets. */ 501 for (i=0; i<RTP_RETRY; ++i, next_rtp_port += 2) { 502 503 /* Create RTP socket. */ 504 status = pj_sock_socket(pj_AF_INET(), pj_SOCK_DGRAM(), 0, &sock[0]); 505 if (status != PJ_SUCCESS) { 506 pjsua_perror(THIS_FILE, "socket() error", status); 507 return status; 508 } 509 510 /* Apply QoS to RTP socket, if specified */ 511 status = pj_sock_apply_qos2(sock[0], cfg->qos_type, 512 &cfg->qos_params, 513 2, THIS_FILE, "RTP socket"); 514 515 /* Bind RTP socket */ 516 status=pj_sock_bind_in(sock[0], pj_ntohl(bound_addr.sin_addr.s_addr), 517 next_rtp_port); 518 if (status != PJ_SUCCESS) { 519 pj_sock_close(sock[0]); 520 sock[0] = PJ_INVALID_SOCKET; 521 continue; 522 } 523 524 /* Create RTCP socket. */ 525 status = pj_sock_socket(pj_AF_INET(), pj_SOCK_DGRAM(), 0, &sock[1]); 526 if (status != PJ_SUCCESS) { 527 pjsua_perror(THIS_FILE, "socket() error", status); 528 pj_sock_close(sock[0]); 529 return status; 530 } 531 532 /* Apply QoS to RTCP socket, if specified */ 533 status = pj_sock_apply_qos2(sock[1], cfg->qos_type, 534 &cfg->qos_params, 535 2, THIS_FILE, "RTCP socket"); 536 537 /* Bind RTCP socket */ 538 status=pj_sock_bind_in(sock[1], pj_ntohl(bound_addr.sin_addr.s_addr), 539 (pj_uint16_t)(next_rtp_port+1)); 540 if (status != PJ_SUCCESS) { 541 pj_sock_close(sock[0]); 542 sock[0] = PJ_INVALID_SOCKET; 543 544 pj_sock_close(sock[1]); 545 sock[1] = PJ_INVALID_SOCKET; 546 continue; 547 } 548 549 /* 550 * If we're configured to use STUN, then find out the mapped address, 551 * and make sure that the mapped RTCP port is adjacent with the RTP. 552 */ 553 if (pjsua_var.stun_srv.addr.sa_family != 0) { 554 char ip_addr[32]; 555 pj_str_t stun_srv; 556 557 pj_ansi_strcpy(ip_addr, 558 pj_inet_ntoa(pjsua_var.stun_srv.ipv4.sin_addr)); 559 stun_srv = pj_str(ip_addr); 560 561 status=pjstun_get_mapped_addr(&pjsua_var.cp.factory, 2, sock, 562 &stun_srv, pj_ntohs(pjsua_var.stun_srv.ipv4.sin_port), 563 &stun_srv, pj_ntohs(pjsua_var.stun_srv.ipv4.sin_port), 564 mapped_addr); 565 if (status != PJ_SUCCESS) { 566 pjsua_perror(THIS_FILE, "STUN resolve error", status); 567 goto on_error; 568 } 569 570 #if PJSUA_REQUIRE_CONSECUTIVE_RTCP_PORT 571 if (pj_ntohs(mapped_addr[1].sin_port) == 572 pj_ntohs(mapped_addr[0].sin_port)+1) 573 { 574 /* Success! */ 575 break; 576 } 577 578 pj_sock_close(sock[0]); 579 sock[0] = PJ_INVALID_SOCKET; 580 581 pj_sock_close(sock[1]); 582 sock[1] = PJ_INVALID_SOCKET; 583 #else 584 if (pj_ntohs(mapped_addr[1].sin_port) != 585 pj_ntohs(mapped_addr[0].sin_port)+1) 586 { 587 PJ_LOG(4,(THIS_FILE, 588 "Note: STUN mapped RTCP port %d is not adjacent" 589 " to RTP port %d", 590 pj_ntohs(mapped_addr[1].sin_port), 591 pj_ntohs(mapped_addr[0].sin_port))); 592 } 593 /* Success! */ 594 break; 595 #endif 596 597 } else if (cfg->public_addr.slen) { 598 599 status = pj_sockaddr_in_init(&mapped_addr[0], &cfg->public_addr, 600 (pj_uint16_t)next_rtp_port); 601 if (status != PJ_SUCCESS) 602 goto on_error; 603 604 status = pj_sockaddr_in_init(&mapped_addr[1], &cfg->public_addr, 605 (pj_uint16_t)(next_rtp_port+1)); 606 if (status != PJ_SUCCESS) 607 goto on_error; 608 609 break; 610 611 } else { 612 613 if (bound_addr.sin_addr.s_addr == 0) { 614 pj_sockaddr addr; 615 616 /* Get local IP address. */ 617 status = pj_gethostip(pj_AF_INET(), &addr); 618 if (status != PJ_SUCCESS) 619 goto on_error; 620 621 bound_addr.sin_addr.s_addr = addr.ipv4.sin_addr.s_addr; 622 } 623 624 for (i=0; i<2; ++i) { 625 pj_sockaddr_in_init(&mapped_addr[i], NULL, 0); 626 mapped_addr[i].sin_addr.s_addr = bound_addr.sin_addr.s_addr; 627 } 628 629 mapped_addr[0].sin_port=pj_htons((pj_uint16_t)next_rtp_port); 630 mapped_addr[1].sin_port=pj_htons((pj_uint16_t)(next_rtp_port+1)); 631 break; 632 } 633 } 634 635 if (sock[0] == PJ_INVALID_SOCKET) { 636 PJ_LOG(1,(THIS_FILE, 637 "Unable to find appropriate RTP/RTCP ports combination")); 638 goto on_error; 639 } 640 641 642 skinfo->rtp_sock = sock[0]; 643 pj_memcpy(&skinfo->rtp_addr_name, 644 &mapped_addr[0], sizeof(pj_sockaddr_in)); 645 646 skinfo->rtcp_sock = sock[1]; 647 pj_memcpy(&skinfo->rtcp_addr_name, 648 &mapped_addr[1], sizeof(pj_sockaddr_in)); 649 650 PJ_LOG(4,(THIS_FILE, "RTP socket reachable at %s", 651 pj_sockaddr_print(&skinfo->rtp_addr_name, addr_buf, 652 sizeof(addr_buf), 3))); 653 PJ_LOG(4,(THIS_FILE, "RTCP socket reachable at %s", 654 pj_sockaddr_print(&skinfo->rtcp_addr_name, addr_buf, 655 sizeof(addr_buf), 3))); 656 657 next_rtp_port += 2; 658 return PJ_SUCCESS; 659 660 on_error: 661 for (i=0; i<2; ++i) { 662 if (sock[i] != PJ_INVALID_SOCKET) 663 pj_sock_close(sock[i]); 664 } 665 return status; 666 } 667 668 /* Create normal UDP media transports */ 669 static pj_status_t create_udp_media_transport(const pjsua_transport_config *cfg, 670 pjsua_call_media *call_med) 671 { 672 pjmedia_sock_info skinfo; 673 pj_status_t status; 674 675 status = create_rtp_rtcp_sock(cfg, &skinfo); 676 if (status != PJ_SUCCESS) { 677 pjsua_perror(THIS_FILE, "Unable to create RTP/RTCP socket", 678 status); 679 goto on_error; 680 } 681 682 status = pjmedia_transport_udp_attach(pjsua_var.med_endpt, NULL, 683 &skinfo, 0, &call_med->tp); 684 if (status != PJ_SUCCESS) { 685 pjsua_perror(THIS_FILE, "Unable to create media transport", 686 status); 687 goto on_error; 688 } 689 690 pjmedia_transport_simulate_lost(call_med->tp, PJMEDIA_DIR_ENCODING, 691 pjsua_var.media_cfg.tx_drop_pct); 692 693 pjmedia_transport_simulate_lost(call_med->tp, PJMEDIA_DIR_DECODING, 694 pjsua_var.media_cfg.rx_drop_pct); 695 696 return PJ_SUCCESS; 697 698 on_error: 699 if (call_med->tp) 700 pjmedia_transport_close(call_med->tp); 701 702 return status; 703 } 704 705 #if DISABLED_FOR_TICKET_1185 748 706 /* Create normal UDP media transports */ 749 707 static pj_status_t create_udp_media_transports(pjsua_transport_config *cfg) 750 708 { 751 709 unsigned i; 752 pjmedia_sock_info skinfo;753 710 pj_status_t status; 754 711 755 /* Create each media transport */ 756 for (i=0; i<pjsua_var.ua_cfg.max_calls; ++i) { 757 758 status = create_rtp_rtcp_sock(cfg, &skinfo); 759 if (status != PJ_SUCCESS) { 760 pjsua_perror(THIS_FILE, "Unable to create RTP/RTCP socket", 761 status); 762 goto on_error; 763 } 764 765 status = pjmedia_transport_udp_attach(pjsua_var.med_endpt, NULL, 766 &skinfo, 0, 767 &pjsua_var.calls[i].med_tp); 768 if (status != PJ_SUCCESS) { 769 pjsua_perror(THIS_FILE, "Unable to create media transport", 770 status); 771 goto on_error; 772 } 773 774 pjmedia_transport_simulate_lost(pjsua_var.calls[i].med_tp, 775 PJMEDIA_DIR_ENCODING, 776 pjsua_var.media_cfg.tx_drop_pct); 777 778 pjmedia_transport_simulate_lost(pjsua_var.calls[i].med_tp, 779 PJMEDIA_DIR_DECODING, 780 pjsua_var.media_cfg.rx_drop_pct); 781 712 for (i=0; i < pjsua_var.ua_cfg.max_calls; ++i) { 713 pjsua_call *call = &pjsua_var.calls[i]; 714 unsigned strm_idx; 715 716 for (strm_idx=0; strm_idx < call->med_cnt; ++strm_idx) { 717 pjsua_call_media *call_med = &call->media[strm_idx]; 718 719 status = create_udp_media_transport(cfg, &call_med->tp); 720 if (status != PJ_SUCCESS) 721 goto on_error; 722 } 782 723 } 783 724 … … 785 726 786 727 on_error: 787 for (i=0; i<pjsua_var.ua_cfg.max_calls; ++i) { 788 if (pjsua_var.calls[i].med_tp != NULL) { 789 pjmedia_transport_close(pjsua_var.calls[i].med_tp); 790 pjsua_var.calls[i].med_tp = NULL; 791 } 792 } 793 728 for (i=0; i < pjsua_var.ua_cfg.max_calls; ++i) { 729 pjsua_call *call = &pjsua_var.calls[i]; 730 unsigned strm_idx; 731 732 for (strm_idx=0; strm_idx < call->med_cnt; ++strm_idx) { 733 pjsua_call_media *call_med = &call->media[strm_idx]; 734 735 if (call_med->tp) { 736 pjmedia_transport_close(call_med->tp); 737 call_med->tp = NULL; 738 } 739 } 740 } 794 741 return status; 795 742 } 796 743 #endif 797 744 798 745 /* This callback is called when ICE negotiation completes */ … … 801 748 pj_status_t result) 802 749 { 803 unsigned id; 804 pj_bool_t found = PJ_FALSE; 805 806 /* Find call which has this media transport */ 807 808 PJSUA_LOCK(); 809 810 for (id=0; id<pjsua_var.ua_cfg.max_calls; ++id) { 811 if (pjsua_var.calls[id].med_tp == tp || 812 pjsua_var.calls[id].med_orig == tp) 813 { 814 found = PJ_TRUE; 815 break; 816 } 817 } 818 819 PJSUA_UNLOCK(); 820 821 if (!found) 750 pjsua_call_media *call_med = (pjsua_call_media*)tp->user_data; 751 752 if (!call_med) 822 753 return; 823 754 824 755 switch (op) { 825 756 case PJ_ICE_STRANS_OP_INIT: 826 pjsua_var.calls[id].med_tp_ready = result;757 call_med->tp_ready = result; 827 758 break; 828 759 case PJ_ICE_STRANS_OP_NEGOTIATION: 829 760 if (result != PJ_SUCCESS) { 830 pjsua_var.calls[id].media_st= PJSUA_CALL_MEDIA_ERROR;831 pjsua_var.calls[id].media_dir = PJMEDIA_DIR_NONE;832 833 if ( pjsua_var.ua_cfg.cb.on_call_media_state) {834 pjsua_var.ua_cfg.cb.on_call_media_state( id);835 } 836 } else {761 call_med->state = PJSUA_CALL_MEDIA_ERROR; 762 call_med->dir = PJMEDIA_DIR_NONE; 763 764 if (call_med->call && pjsua_var.ua_cfg.cb.on_call_media_state) { 765 pjsua_var.ua_cfg.cb.on_call_media_state(call_med->call->index); 766 } 767 } else if (call_med->call) { 837 768 /* Send UPDATE if default transport address is different than 838 769 * what was advertised (ticket #881) … … 854 785 if (ii && ii->role==PJ_ICE_SESS_ROLE_CONTROLLING && 855 786 pj_sockaddr_cmp(&tpinfo.sock_info.rtp_addr_name, 856 & pjsua_var.calls[id].med_rtp_addr))787 &call_med->rtp_addr)) 857 788 { 858 789 pj_bool_t use_update; … … 861 792 pjsip_dialog *dlg; 862 793 863 dlg = pjsua_var.calls[id].inv->dlg;794 dlg = call_med->call->inv->dlg; 864 795 support_update = pjsip_dlg_remote_has_cap(dlg, PJSIP_H_ALLOW, 865 796 NULL, &STR_UPDATE); … … 868 799 PJ_LOG(4,(THIS_FILE, 869 800 "ICE default transport address has changed for " 870 "call %d, sending %s", id,801 "call %d, sending %s", call_med->call->index, 871 802 (use_update ? "UPDATE" : "re-INVITE"))); 872 803 873 804 if (use_update) 874 pjsua_call_update( id, 0, NULL);805 pjsua_call_update(call_med->call->index, 0, NULL); 875 806 else 876 pjsua_call_reinvite( id, 0, NULL);807 pjsua_call_reinvite(call_med->call->index, 0, NULL); 877 808 } 878 809 } … … 881 812 if (result != PJ_SUCCESS) { 882 813 PJ_PERROR(4,(THIS_FILE, result, 883 "ICE keep alive failure for transport %d", id)); 814 "ICE keep alive failure for transport %d:%d", 815 call_med->call->index, call_med->idx)); 884 816 } 885 817 if (pjsua_var.ua_cfg.cb.on_ice_transport_error) { 818 pjsua_call_id id = call_med->call->index; 886 819 (*pjsua_var.ua_cfg.cb.on_ice_transport_error)(id, op, result, 887 820 NULL); … … 919 852 920 853 /* Create ICE media transports (when ice is enabled) */ 921 static pj_status_t create_ice_media_transports(pjsua_transport_config *cfg) 854 static pj_status_t create_ice_media_transport( 855 const pjsua_transport_config *cfg, 856 pjsua_call_media *call_med) 922 857 { 923 858 char stunip[PJ_INET6_ADDRSTRLEN]; 924 859 pj_ice_strans_cfg ice_cfg; 925 unsigned i; 860 pjmedia_ice_cb ice_cb; 861 char name[32]; 862 unsigned comp_cnt; 926 863 pj_status_t status; 927 864 … … 980 917 } 981 918 982 /* Create each media transport */ 983 for (i=0; i<pjsua_var.ua_cfg.max_calls; ++i) { 984 pjmedia_ice_cb ice_cb; 985 char name[32]; 986 unsigned comp_cnt; 987 988 pj_bzero(&ice_cb, sizeof(pjmedia_ice_cb)); 989 ice_cb.on_ice_complete = &on_ice_complete; 990 pj_ansi_snprintf(name, sizeof(name), "icetp%02d", i); 991 pjsua_var.calls[i].med_tp_ready = PJ_EPENDING; 992 993 comp_cnt = 1; 994 if (PJMEDIA_ADVERTISE_RTCP && !pjsua_var.media_cfg.ice_no_rtcp) 995 ++comp_cnt; 996 997 status = pjmedia_ice_create(pjsua_var.med_endpt, name, comp_cnt, 998 &ice_cfg, &ice_cb, 999 &pjsua_var.calls[i].med_tp); 1000 if (status != PJ_SUCCESS) { 1001 pjsua_perror(THIS_FILE, "Unable to create ICE media transport", 1002 status); 1003 goto on_error; 1004 } 1005 1006 /* Wait until transport is initialized, or time out */ 1007 PJSUA_UNLOCK(); 1008 while (pjsua_var.calls[i].med_tp_ready == PJ_EPENDING) { 1009 pjsua_handle_events(100); 1010 } 1011 PJSUA_LOCK(); 1012 if (pjsua_var.calls[i].med_tp_ready != PJ_SUCCESS) { 1013 pjsua_perror(THIS_FILE, "Error initializing ICE media transport", 1014 pjsua_var.calls[i].med_tp_ready); 1015 status = pjsua_var.calls[i].med_tp_ready; 1016 goto on_error; 1017 } 1018 1019 pjmedia_transport_simulate_lost(pjsua_var.calls[i].med_tp, 1020 PJMEDIA_DIR_ENCODING, 1021 pjsua_var.media_cfg.tx_drop_pct); 1022 1023 pjmedia_transport_simulate_lost(pjsua_var.calls[i].med_tp, 1024 PJMEDIA_DIR_DECODING, 1025 pjsua_var.media_cfg.rx_drop_pct); 1026 } 919 pj_bzero(&ice_cb, sizeof(pjmedia_ice_cb)); 920 ice_cb.on_ice_complete = &on_ice_complete; 921 pj_ansi_snprintf(name, sizeof(name), "icetp%02d", call_med->idx); 922 call_med->tp_ready = PJ_EPENDING; 923 924 comp_cnt = 1; 925 if (PJMEDIA_ADVERTISE_RTCP && !pjsua_var.media_cfg.ice_no_rtcp) 926 ++comp_cnt; 927 928 status = pjmedia_ice_create3(pjsua_var.med_endpt, name, comp_cnt, 929 &ice_cfg, &ice_cb, 0, call_med, 930 &call_med->tp); 931 if (status != PJ_SUCCESS) { 932 pjsua_perror(THIS_FILE, "Unable to create ICE media transport", 933 status); 934 goto on_error; 935 } 936 937 /* Wait until transport is initialized, or time out */ 938 PJSUA_UNLOCK(); 939 while (call_med->tp_ready == PJ_EPENDING) { 940 pjsua_handle_events(100); 941 } 942 PJSUA_LOCK(); 943 if (call_med->tp_ready != PJ_SUCCESS) { 944 pjsua_perror(THIS_FILE, "Error initializing ICE media transport", 945 call_med->tp_ready); 946 status = call_med->tp_ready; 947 goto on_error; 948 } 949 950 pjmedia_transport_simulate_lost(call_med->tp, PJMEDIA_DIR_ENCODING, 951 pjsua_var.media_cfg.tx_drop_pct); 952 953 pjmedia_transport_simulate_lost(call_med->tp, PJMEDIA_DIR_DECODING, 954 pjsua_var.media_cfg.rx_drop_pct); 1027 955 1028 956 return PJ_SUCCESS; 1029 957 1030 958 on_error: 1031 for (i=0; i<pjsua_var.ua_cfg.max_calls; ++i) { 1032 if (pjsua_var.calls[i].med_tp != NULL) { 1033 pjmedia_transport_close(pjsua_var.calls[i].med_tp); 1034 pjsua_var.calls[i].med_tp = NULL; 1035 } 959 if (call_med->tp != NULL) { 960 pjmedia_transport_close(call_med->tp); 961 call_med->tp = NULL; 1036 962 } 1037 963 … … 1039 965 } 1040 966 1041 1042 /* 1043 * Create UDP media transports for all the calls. This function creates 967 #if DISABLED_FOR_TICKET_1185 968 /* Create ICE media transports (when ice is enabled) */ 969 static pj_status_t create_ice_media_transports(pjsua_transport_config *cfg) 970 { 971 unsigned i; 972 pj_status_t status; 973 974 for (i=0; i < pjsua_var.ua_cfg.max_calls; ++i) { 975 pjsua_call *call = &pjsua_var.calls[i]; 976 unsigned strm_idx; 977 978 for (strm_idx=0; strm_idx < call->med_cnt; ++strm_idx) { 979 pjsua_call_media *call_med = &call->media[strm_idx]; 980 981 status = create_ice_media_transport(cfg, call_med); 982 if (status != PJ_SUCCESS) 983 goto on_error; 984 } 985 } 986 987 return PJ_SUCCESS; 988 989 on_error: 990 for (i=0; i < pjsua_var.ua_cfg.max_calls; ++i) { 991 pjsua_call *call = &pjsua_var.calls[i]; 992 unsigned strm_idx; 993 994 for (strm_idx=0; strm_idx < call->med_cnt; ++strm_idx) { 995 pjsua_call_media *call_med = &call->media[strm_idx]; 996 997 if (call_med->tp) { 998 pjmedia_transport_close(call_med->tp); 999 call_med->tp = NULL; 1000 } 1001 } 1002 } 1003 return status; 1004 } 1005 #endif 1006 1007 #if DISABLED_FOR_TICKET_1185 1008 /* 1009 * Create media transports for all the calls. This function creates 1044 1010 * one UDP media transport for each call. 1045 1011 */ … … 1059 1025 /* Delete existing media transports */ 1060 1026 for (i=0; i<pjsua_var.ua_cfg.max_calls; ++i) { 1061 if (pjsua_var.calls[i].med_tp != NULL && 1062 pjsua_var.calls[i].med_tp_auto_del) 1063 { 1064 pjmedia_transport_close(pjsua_var.calls[i].med_tp); 1065 pjsua_var.calls[i].med_tp = NULL; 1066 pjsua_var.calls[i].med_orig = NULL; 1027 pjsua_call *call = &pjsua_var.calls[i]; 1028 unsigned strm_idx; 1029 1030 for (strm_idx=0; strm_idx < call->med_cnt; ++strm_idx) { 1031 pjsua_call_media *call_med = &call->media[strm_idx]; 1032 1033 if (call_med->tp && call_med->tp_auto_del) { 1034 pjmedia_transport_close(call_med->tp); 1035 call_med->tp = NULL; 1036 call_med->tp_orig = NULL; 1037 } 1067 1038 } 1068 1039 } … … 1080 1051 /* Set media transport auto_delete to True */ 1081 1052 for (i=0; i<pjsua_var.ua_cfg.max_calls; ++i) { 1082 pjsua_var.calls[i].med_tp_auto_del = PJ_TRUE; 1053 pjsua_call *call = &pjsua_var.calls[i]; 1054 unsigned strm_idx; 1055 1056 for (strm_idx=0; strm_idx < call->med_cnt; ++strm_idx) { 1057 pjsua_call_media *call_med = &call->media[strm_idx]; 1058 1059 call_med->tp_auto_del = PJ_TRUE; 1060 } 1083 1061 } 1084 1062 … … 1101 1079 /* Assign the media transports */ 1102 1080 for (i=0; i<pjsua_var.ua_cfg.max_calls; ++i) { 1103 if (pjsua_var.calls[i].med_tp != NULL && 1104 pjsua_var.calls[i].med_tp_auto_del) 1081 pjsua_call *call = &pjsua_var.calls[i]; 1082 unsigned strm_idx; 1083 1084 for (strm_idx=0; strm_idx < call->med_cnt; ++strm_idx) { 1085 pjsua_call_media *call_med = &call->media[strm_idx]; 1086 1087 if (call_med->tp && call_med->tp_auto_del) { 1088 pjmedia_transport_close(call_med->tp); 1089 call_med->tp = NULL; 1090 call_med->tp_orig = NULL; 1091 } 1092 } 1093 1094 PJ_TODO(remove_pjsua_media_transports_attach); 1095 1096 call->media[0].tp = tp[i].transport; 1097 call->media[0].tp_auto_del = auto_delete; 1098 } 1099 1100 return PJ_SUCCESS; 1101 } 1102 #endif 1103 1104 /* Go through the list of media in the SDP, find acceptable media, and 1105 * sort them based on the "quality" of the media, and store the indexes 1106 * in the specified array. Media with the best quality will be listed 1107 * first in the array. The quality factors considered currently is 1108 * encryption. 1109 */ 1110 static void sort_media(const pjmedia_sdp_session *sdp, 1111 const pj_str_t *type, 1112 pjmedia_srtp_use use_srtp, 1113 pj_uint8_t midx[], 1114 unsigned *p_count) 1115 { 1116 unsigned i; 1117 unsigned count = 0; 1118 int score[PJSUA_MAX_CALL_MEDIA]; 1119 1120 pj_assert(*p_count >= PJSUA_MAX_CALL_MEDIA); 1121 1122 *p_count = 0; 1123 for (i=0; i<PJSUA_MAX_CALL_MEDIA; ++i) 1124 score[i] = 1; 1125 1126 /* Score each media */ 1127 for (i=0; i<sdp->media_count && count<PJSUA_MAX_CALL_MEDIA; ++i) { 1128 const pjmedia_sdp_media *m = sdp->media[i]; 1129 const pjmedia_sdp_conn *c; 1130 1131 /* Skip different media */ 1132 if (pj_stricmp(&m->desc.media, type) != 0) { 1133 score[count++] = -22000; 1134 continue; 1135 } 1136 1137 c = m->conn? m->conn : sdp->conn; 1138 1139 /* Supported transports */ 1140 if (pj_stricmp2(&m->desc.transport, "RTP/SAVP")==0) { 1141 switch (use_srtp) { 1142 case PJMEDIA_SRTP_MANDATORY: 1143 case PJMEDIA_SRTP_OPTIONAL: 1144 ++score[i]; 1145 break; 1146 case PJMEDIA_SRTP_DISABLED: 1147 --score[i]; 1148 break; 1149 } 1150 } else if (pj_stricmp2(&m->desc.transport, "RTP/AVP")==0) { 1151 switch (use_srtp) { 1152 case PJMEDIA_SRTP_MANDATORY: 1153 --score[i]; 1154 break; 1155 case PJMEDIA_SRTP_OPTIONAL: 1156 /* No change in score */ 1157 break; 1158 case PJMEDIA_SRTP_DISABLED: 1159 ++score[i]; 1160 break; 1161 } 1162 } else { 1163 score[i] -= 10; 1164 } 1165 1166 /* Is media disabled? */ 1167 if (m->desc.port == 0) 1168 score[i] -= 10; 1169 1170 /* Is media inactive? */ 1171 if (pjmedia_sdp_media_find_attr2(m, "inactive", NULL) || 1172 pj_strcmp2(&c->addr, "0.0.0.0") == 0) 1105 1173 { 1106 pjmedia_transport_close(pjsua_var.calls[i].med_tp); 1107 } 1108 1109 pjsua_var.calls[i].med_tp = tp[i].transport; 1110 pjsua_var.calls[i].med_tp_auto_del = auto_delete; 1174 //score[i] -= 10; 1175 score[i] -= 1; 1176 } 1177 1178 ++count; 1179 } 1180 1181 /* Created sorted list based on quality */ 1182 for (i=0; i<count; ++i) { 1183 unsigned j; 1184 int best = 0; 1185 1186 for (j=1; j<count; ++j) { 1187 if (score[j] > score[best]) 1188 best = j; 1189 } 1190 /* Don't put media with negative score, that media is unacceptable 1191 * for us. 1192 */ 1193 if (score[best] >= 0) { 1194 midx[*p_count] = (pj_uint8_t)best; 1195 (*p_count)++; 1196 } 1197 1198 score[best] = -22000; 1199 1200 } 1201 } 1202 1203 /* Callback to receive media events */ 1204 static pj_status_t call_media_on_event(pjmedia_event_subscription *esub, 1205 pjmedia_event *event) 1206 { 1207 pjsua_call_media *call_med = (pjsua_call_media*)esub->user_data; 1208 pjsua_call *call = call_med->call; 1209 1210 if (pjsua_var.ua_cfg.cb.on_call_media_event && call) { 1211 ++event->proc_cnt; 1212 (*pjsua_var.ua_cfg.cb.on_call_media_event)(call->index, 1213 call_med->idx, event); 1111 1214 } 1112 1215 … … 1114 1217 } 1115 1218 1116 1117 static int find_audio_index(const pjmedia_sdp_session *sdp, 1118 pj_bool_t prefer_srtp) 1119 { 1120 unsigned i; 1121 int audio_idx = -1; 1122 1123 for (i=0; i<sdp->media_count; ++i) { 1124 const pjmedia_sdp_media *m = sdp->media[i]; 1125 1126 /* Skip if media is not audio */ 1127 if (pj_stricmp2(&m->desc.media, "audio") != 0) 1128 continue; 1129 1130 /* Skip if media is disabled */ 1131 if (m->desc.port == 0) 1132 continue; 1133 1134 /* Skip if transport is not supported */ 1135 if (pj_stricmp2(&m->desc.transport, "RTP/AVP") != 0 && 1136 pj_stricmp2(&m->desc.transport, "RTP/SAVP") != 0) 1137 { 1138 continue; 1139 } 1140 1141 if (audio_idx == -1) { 1142 audio_idx = i; 1219 /* Initialize the media line */ 1220 pj_status_t pjsua_call_media_init(pjsua_call_media *call_med, 1221 pjmedia_type type, 1222 const pjsua_transport_config *tcfg, 1223 int security_level, 1224 int *sip_err_code) 1225 { 1226 pjsua_acc *acc = &pjsua_var.acc[call_med->call->acc_id]; 1227 pj_status_t status; 1228 1229 /* 1230 * Note: this function may be called when the media already exists 1231 * (e.g. in reinvites, updates, etc.) 1232 */ 1233 call_med->type = type; 1234 1235 /* Create the media transport for initial call. This is blocking for now */ 1236 if (call_med->tp == NULL) { 1237 if (pjsua_var.media_cfg.enable_ice) { 1238 status = create_ice_media_transport(tcfg, call_med); 1143 1239 } else { 1144 /* We've found multiple candidates. This could happen 1145 * e.g. when remote is offering both RTP/SAVP and RTP/AVP, 1146 * or when remote for some reason offers two audio. 1147 */ 1148 1149 if (prefer_srtp && 1150 pj_stricmp2(&m->desc.transport, "RTP/SAVP")==0) 1151 { 1152 /* Prefer RTP/SAVP when our media transport is SRTP */ 1153 audio_idx = i; 1154 break; 1155 } else if (!prefer_srtp && 1156 pj_stricmp2(&m->desc.transport, "RTP/AVP")==0) 1157 { 1158 /* Prefer RTP/AVP when our media transport is NOT SRTP */ 1159 audio_idx = i; 1160 } 1161 } 1162 } 1163 1164 return audio_idx; 1165 } 1166 1240 status = create_udp_media_transport(tcfg, call_med); 1241 } 1242 1243 if (status != PJ_SUCCESS) { 1244 PJ_PERROR(1,(THIS_FILE, status, "Error creating media transport")); 1245 return status; 1246 } 1247 1248 call_med->tp_st = PJSUA_MED_TP_IDLE; 1249 1250 /* While in initial call, set default video devices */ 1251 if (type == PJMEDIA_TYPE_VIDEO) { 1252 call_med->strm.v.rdr_dev = acc->cfg.vid_rend_dev; 1253 call_med->strm.v.cap_dev = acc->cfg.vid_cap_dev; 1254 if (call_med->strm.v.rdr_dev == PJMEDIA_VID_DEFAULT_RENDER_DEV) { 1255 pjmedia_vid_dev_info info; 1256 pjmedia_vid_dev_get_info(call_med->strm.v.rdr_dev, &info); 1257 call_med->strm.v.rdr_dev = info.id; 1258 } 1259 if (call_med->strm.v.cap_dev == PJMEDIA_VID_DEFAULT_CAPTURE_DEV) { 1260 pjmedia_vid_dev_info info; 1261 pjmedia_vid_dev_get_info(call_med->strm.v.cap_dev, &info); 1262 call_med->strm.v.cap_dev = info.id; 1263 } 1264 } 1265 } else if (call_med->tp_st == PJSUA_MED_TP_DISABLED) { 1266 /* Media is being reenabled. */ 1267 call_med->tp_st = PJSUA_MED_TP_INIT; 1268 } 1269 1270 #if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0) 1271 /* This function may be called when SRTP transport already exists 1272 * (e.g: in re-invite, update), don't need to destroy/re-create. 1273 */ 1274 if (!call_med->tp_orig || call_med->tp == call_med->tp_orig) { 1275 pjmedia_srtp_setting srtp_opt; 1276 pjmedia_transport *srtp = NULL; 1277 1278 /* Check if SRTP requires secure signaling */ 1279 if (acc->cfg.use_srtp != PJMEDIA_SRTP_DISABLED) { 1280 if (security_level < acc->cfg.srtp_secure_signaling) { 1281 if (sip_err_code) 1282 *sip_err_code = PJSIP_SC_NOT_ACCEPTABLE; 1283 status = PJSIP_ESESSIONINSECURE; 1284 goto on_error; 1285 } 1286 } 1287 1288 /* Always create SRTP adapter */ 1289 pjmedia_srtp_setting_default(&srtp_opt); 1290 srtp_opt.close_member_tp = PJ_TRUE; 1291 /* If media session has been ever established, let's use remote's 1292 * preference in SRTP usage policy, especially when it is stricter. 1293 */ 1294 if (call_med->rem_srtp_use > acc->cfg.use_srtp) 1295 srtp_opt.use = call_med->rem_srtp_use; 1296 else 1297 srtp_opt.use = acc->cfg.use_srtp; 1298 1299 status = pjmedia_transport_srtp_create(pjsua_var.med_endpt, 1300 call_med->tp, 1301 &srtp_opt, &srtp); 1302 if (status != PJ_SUCCESS) { 1303 if (sip_err_code) 1304 *sip_err_code = PJSIP_SC_INTERNAL_SERVER_ERROR; 1305 goto on_error; 1306 } 1307 1308 /* Set SRTP as current media transport */ 1309 call_med->tp_orig = call_med->tp; 1310 call_med->tp = srtp; 1311 } 1312 #else 1313 call->tp_orig = call->tp; 1314 PJ_UNUSED_ARG(security_level); 1315 #endif 1316 1317 pjmedia_event_subscription_init(&call_med->esub_rend, &call_media_on_event, 1318 call_med); 1319 pjmedia_event_subscription_init(&call_med->esub_cap, &call_media_on_event, 1320 call_med); 1321 1322 return PJ_SUCCESS; 1323 1324 on_error: 1325 if (call_med->tp) { 1326 pjmedia_transport_close(call_med->tp); 1327 call_med->tp = NULL; 1328 } 1329 return status; 1330 } 1167 1331 1168 1332 pj_status_t pjsua_media_channel_init(pjsua_call_id call_id, … … 1173 1337 int *sip_err_code) 1174 1338 { 1339 const pj_str_t STR_AUDIO = { "audio", 5 }; 1340 const pj_str_t STR_VIDEO = { "video", 5 }; 1175 1341 pjsua_call *call = &pjsua_var.calls[call_id]; 1342 pjsua_acc *acc = &pjsua_var.acc[call->acc_id]; 1343 pj_uint8_t maudidx[PJSUA_MAX_CALL_MEDIA]; 1344 unsigned maudcnt = PJ_ARRAY_SIZE(maudidx); 1345 pj_uint8_t mvididx[PJSUA_MAX_CALL_MEDIA]; 1346 unsigned mvidcnt = PJ_ARRAY_SIZE(mvididx); 1347 pjmedia_type media_types[PJSUA_MAX_CALL_MEDIA]; 1348 unsigned mi; 1176 1349 pj_status_t status; 1177 1350 1178 #if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)1179 pjsua_acc *acc = &pjsua_var.acc[call->acc_id];1180 pjmedia_srtp_setting srtp_opt;1181 pjmedia_transport *srtp = NULL;1182 #endif1183 1184 1351 PJ_UNUSED_ARG(role); 1185 1352 1353 /* 1354 * Note: this function may be called when the media already exists 1355 * (e.g. in reinvites, updates, etc). 1356 */ 1357 1358 if (pjsua_get_state() != PJSUA_STATE_RUNNING) 1359 return PJ_EBUSY; 1360 1361 #if DISABLED_FOR_TICKET_1185 1186 1362 /* Return error if media transport has not been created yet 1187 1363 * (e.g. application is starting) 1188 1364 */ 1189 if (call->med_tp == NULL) { 1190 if (sip_err_code) 1191 *sip_err_code = PJSIP_SC_INTERNAL_SERVER_ERROR; 1192 return PJ_EBUSY; 1193 } 1194 1195 #if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0) 1196 /* This function may be called when SRTP transport already exists 1197 * (e.g: in re-invite, update), don't need to destroy/re-create. 1198 */ 1199 if (!call->med_orig || call->med_tp == call->med_orig) { 1200 1201 /* Check if SRTP requires secure signaling */ 1202 if (acc->cfg.use_srtp != PJMEDIA_SRTP_DISABLED) { 1203 if (security_level < acc->cfg.srtp_secure_signaling) { 1204 if (sip_err_code) 1205 *sip_err_code = PJSIP_SC_NOT_ACCEPTABLE; 1206 return PJSIP_ESESSIONINSECURE; 1207 } 1208 } 1209 1210 /* Always create SRTP adapter */ 1211 pjmedia_srtp_setting_default(&srtp_opt); 1212 srtp_opt.close_member_tp = PJ_FALSE; 1213 /* If media session has been ever established, let's use remote's 1214 * preference in SRTP usage policy, especially when it is stricter. 1365 for (i=0; i<call->med_cnt; ++i) { 1366 if (call->media[i].tp == NULL) { 1367 return PJ_EBUSY; 1368 } 1369 } 1370 #endif 1371 1372 if (rem_sdp) { 1373 sort_media(rem_sdp, &STR_AUDIO, acc->cfg.use_srtp, 1374 maudidx, &maudcnt); 1375 if (maudcnt > acc->cfg.max_audio_cnt) 1376 maudcnt = acc->cfg.max_audio_cnt; 1377 1378 if (maudcnt==0) { 1379 /* Expecting audio in the offer */ 1380 if (sip_err_code) *sip_err_code = PJSIP_SC_NOT_ACCEPTABLE_HERE; 1381 pjsua_media_channel_deinit(call_id); 1382 return PJSIP_ERRNO_FROM_SIP_STATUS(PJSIP_SC_NOT_ACCEPTABLE_HERE); 1383 } 1384 1385 sort_media(rem_sdp, &STR_VIDEO, acc->cfg.use_srtp, 1386 mvididx, &mvidcnt); 1387 if (mvidcnt > acc->cfg.max_video_cnt) 1388 mvidcnt = acc->cfg.max_video_cnt; 1389 1390 /* Update media count only when remote add any media, this media count 1391 * must never decrease. 1215 1392 */ 1216 if (call->rem_srtp_use > acc->cfg.use_srtp) 1217 srtp_opt.use = call->rem_srtp_use; 1218 else 1219 srtp_opt.use = acc->cfg.use_srtp; 1220 1221 status = pjmedia_transport_srtp_create(pjsua_var.med_endpt, 1222 call->med_tp, 1223 &srtp_opt, &srtp); 1224 if (status != PJ_SUCCESS) { 1225 if (sip_err_code) 1226 *sip_err_code = PJSIP_SC_INTERNAL_SERVER_ERROR; 1227 return status; 1228 } 1229 1230 /* Set SRTP as current media transport */ 1231 call->med_orig = call->med_tp; 1232 call->med_tp = srtp; 1233 } 1234 #else 1235 call->med_orig = call->med_tp; 1236 PJ_UNUSED_ARG(security_level); 1237 #endif 1238 1239 /* Find out which media line in SDP that we support. If we are offerer, 1240 * audio will be initialized at index 0 in SDP. 1241 */ 1242 if (rem_sdp == NULL) { 1243 call->audio_idx = 0; 1244 } 1245 /* Otherwise find out the candidate audio media line in SDP */ 1246 else { 1247 pj_bool_t srtp_active; 1248 1249 #if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0) 1250 srtp_active = acc->cfg.use_srtp; 1251 #else 1252 srtp_active = PJ_FALSE; 1253 #endif 1254 1255 /* Media count must have been checked */ 1256 pj_assert(rem_sdp->media_count != 0); 1257 1258 call->audio_idx = find_audio_index(rem_sdp, srtp_active); 1259 } 1260 1261 /* Reject offer if we couldn't find a good m=audio line in offer */ 1262 if (call->audio_idx < 0) { 1393 if (call->med_cnt < rem_sdp->media_count) 1394 call->med_cnt = PJ_MIN(rem_sdp->media_count, PJSUA_MAX_CALL_MEDIA); 1395 1396 } else { 1397 maudcnt = acc->cfg.max_audio_cnt; 1398 for (mi=0; mi<maudcnt; ++mi) { 1399 maudidx[mi] = (pj_uint8_t)mi; 1400 media_types[mi] = PJMEDIA_TYPE_AUDIO; 1401 } 1402 mvidcnt = acc->cfg.max_video_cnt; 1403 for (mi=0; mi<mvidcnt; ++mi) { 1404 media_types[maudcnt + mi] = PJMEDIA_TYPE_VIDEO; 1405 } 1406 1407 call->med_cnt = maudcnt + mvidcnt; 1408 } 1409 1410 if (call->med_cnt == 0) { 1411 /* Expecting at least one media */ 1263 1412 if (sip_err_code) *sip_err_code = PJSIP_SC_NOT_ACCEPTABLE_HERE; 1264 1413 pjsua_media_channel_deinit(call_id); … … 1266 1415 } 1267 1416 1268 PJ_LOG(4,(THIS_FILE, "Media index %d selected for call %d", 1417 /* Initialize each media line */ 1418 for (mi=0; mi < call->med_cnt; ++mi) { 1419 pjsua_call_media *call_med = &call->media[mi]; 1420 pj_bool_t enabled = PJ_FALSE; 1421 pjmedia_type media_type = PJMEDIA_TYPE_NONE; 1422 1423 if (rem_sdp) { 1424 if (mi >= rem_sdp->media_count) { 1425 /* Media has been removed in remote re-offer */ 1426 media_type = call_med->type; 1427 } else if (!pj_stricmp(&rem_sdp->media[mi]->desc.media, &STR_AUDIO)) { 1428 media_type = PJMEDIA_TYPE_AUDIO; 1429 if (pj_memchr(maudidx, mi, maudcnt * sizeof(maudidx[0]))) { 1430 enabled = PJ_TRUE; 1431 } 1432 } 1433 else if (!pj_stricmp(&rem_sdp->media[mi]->desc.media, &STR_VIDEO)) { 1434 media_type = PJMEDIA_TYPE_VIDEO; 1435 if (pj_memchr(mvididx, mi, mvidcnt * sizeof(mvididx[0]))) { 1436 enabled = PJ_TRUE; 1437 } 1438 } 1439 1440 } else { 1441 enabled = PJ_TRUE; 1442 media_type = media_types[mi]; 1443 } 1444 1445 if (enabled) { 1446 status = pjsua_call_media_init(call_med, media_type, 1447 &acc->cfg.rtp_cfg, 1448 security_level, sip_err_code); 1449 if (status != PJ_SUCCESS) { 1450 pjsua_media_channel_deinit(call_id); 1451 return status; 1452 } 1453 } else { 1454 /* By convention, the media is disabled if transport is NULL 1455 * or transport state is PJSUA_MED_TP_DISABLED. 1456 */ 1457 if (call_med->tp) { 1458 // Don't close transport here, as SDP negotiation has not been 1459 // done and stream may be still active. 1460 //pjmedia_transport_close(call_med->tp); 1461 //call_med->tp = NULL; 1462 pj_assert(call_med->tp_st == PJSUA_MED_TP_INIT || 1463 call_med->tp_st == PJSUA_MED_TP_RUNNING); 1464 call_med->tp_st = PJSUA_MED_TP_DISABLED; 1465 } 1466 1467 /* Put media type just for info */ 1468 call_med->type = media_type; 1469 } 1470 } 1471 1472 call->audio_idx = maudidx[0]; 1473 1474 PJ_LOG(4,(THIS_FILE, "Media index %d selected for audio call %d", 1269 1475 call->audio_idx, call->index)); 1270 1476 1271 /* Create the media transport */ 1272 status = pjmedia_transport_media_create(call->med_tp, tmp_pool, 0, 1273 rem_sdp, call->audio_idx); 1274 if (status != PJ_SUCCESS) { 1275 if (sip_err_code) *sip_err_code = PJSIP_SC_NOT_ACCEPTABLE; 1276 pjsua_media_channel_deinit(call_id); 1277 return status; 1278 } 1279 1280 call->med_tp_st = PJSUA_MED_TP_INIT; 1477 /* Tell the media transport of a new offer/answer session */ 1478 for (mi=0; mi < call->med_cnt; ++mi) { 1479 pjsua_call_media *call_med = &call->media[mi]; 1480 1481 /* Note: tp may be NULL if this media line is disabled */ 1482 if (call_med->tp && call_med->tp_st == PJSUA_MED_TP_IDLE) { 1483 status = pjmedia_transport_media_create(call_med->tp, 1484 tmp_pool, 0, 1485 rem_sdp, mi); 1486 if (status != PJ_SUCCESS) { 1487 if (sip_err_code) *sip_err_code = PJSIP_SC_NOT_ACCEPTABLE; 1488 pjsua_media_channel_deinit(call_id); 1489 return status; 1490 } 1491 1492 call_med->tp_st = PJSUA_MED_TP_INIT; 1493 } 1494 } 1495 1281 1496 return PJ_SUCCESS; 1282 1497 } … … 1286 1501 const pjmedia_sdp_session *rem_sdp, 1287 1502 pjmedia_sdp_session **p_sdp, 1288 int *sip_ status_code)1289 { 1290 enum { MAX_MEDIA = 1};1503 int *sip_err_code) 1504 { 1505 enum { MAX_MEDIA = PJSUA_MAX_CALL_MEDIA }; 1291 1506 pjmedia_sdp_session *sdp; 1292 pj media_transport_info tpinfo;1507 pj_sockaddr origin; 1293 1508 pjsua_call *call = &pjsua_var.calls[call_id]; 1294 1509 pjmedia_sdp_neg_state sdp_neg_state = PJMEDIA_SDP_NEG_STATE_NULL; 1510 unsigned mi; 1295 1511 pj_status_t status; 1296 1512 1297 /* Return error if media transport has not been created yet 1298 * (e.g. application is starting) 1513 if (pjsua_get_state() != PJSUA_STATE_RUNNING) 1514 return PJ_EBUSY; 1515 1516 if (rem_sdp) { 1517 /* If this is a re-offer, let's re-initialize media as remote may 1518 * add or remove media 1519 */ 1520 if (call->inv && call->inv->state == PJSIP_INV_STATE_CONFIRMED) { 1521 status = pjsua_media_channel_init(call_id, PJSIP_ROLE_UAS, 1522 call->secure_level, pool, 1523 rem_sdp, sip_err_code); 1524 if (status != PJ_SUCCESS) 1525 return status; 1526 } 1527 1528 #if 0 1529 pjsua_acc *acc = &pjsua_var.acc[call->acc_id]; 1530 pj_uint8_t maudidx[PJSUA_MAX_CALL_MEDIA]; 1531 unsigned maudcnt = PJ_ARRAY_SIZE(maudidx); 1532 1533 sort_media(rem_sdp, &STR_AUDIO, acc->cfg.use_srtp, 1534 maudidx, &maudcnt); 1535 1536 if (maudcnt==0) { 1537 /* Expecting audio in the offer */ 1538 if (sip_err_code) *sip_err_code = PJSIP_SC_NOT_ACCEPTABLE_HERE; 1539 pjsua_media_channel_deinit(call_id); 1540 return PJSIP_ERRNO_FROM_SIP_STATUS(PJSIP_SC_NOT_ACCEPTABLE_HERE); 1541 } 1542 1543 call->audio_idx = maudidx[0]; 1544 #endif 1545 } else { 1546 /* Audio is first in our offer, by convention */ 1547 // The audio_idx should not be changed here, as this function may be 1548 // called in generating re-offer and the current active audio index 1549 // can be anywhere. 1550 //call->audio_idx = 0; 1551 } 1552 1553 #if 0 1554 // Since r3512, old-style hold should have got transport, created by 1555 // pjsua_media_channel_init() in initial offer/answer or remote reoffer. 1556 /* Create media if it's not created. This could happen when call is 1557 * currently on-hold (with the old style hold) 1299 1558 */ 1300 if (call->med_tp == NULL) { 1301 return PJ_EBUSY; 1302 } 1303 1304 if (rem_sdp && rem_sdp->media_count != 0) { 1305 pj_bool_t srtp_active; 1306 1307 #if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0) 1308 srtp_active = pjsua_var.acc[call->acc_id].cfg.use_srtp; 1309 #else 1310 srtp_active = PJ_FALSE; 1311 #endif 1312 1313 call->audio_idx = find_audio_index(rem_sdp, srtp_active); 1314 if (call->audio_idx == -1) { 1315 /* No audio in the offer. We can't accept this */ 1316 PJ_LOG(4,(THIS_FILE, 1317 "Unable to accept SDP offer without audio for call %d", 1318 call_id)); 1319 return PJMEDIA_SDP_EINMEDIA; 1320 } 1321 } 1322 1323 /* Media index must have been determined before */ 1324 pj_assert(call->audio_idx != -1); 1325 1326 /* Create media if it's not created. This could happen when call is 1327 * currently on-hold 1328 */ 1329 if (call->med_tp_st == PJSUA_MED_TP_IDLE) { 1559 if (call->media[call->audio_idx].tp == NULL) { 1330 1560 pjsip_role_e role; 1331 1561 role = (rem_sdp ? PJSIP_ROLE_UAS : PJSIP_ROLE_UAC); 1332 1562 status = pjsua_media_channel_init(call_id, role, call->secure_level, 1333 pool, rem_sdp, sip_ status_code);1563 pool, rem_sdp, sip_err_code); 1334 1564 if (status != PJ_SUCCESS) 1335 1565 return status; 1336 1566 } 1567 #endif 1337 1568 1338 1569 /* Get SDP negotiator state */ … … 1340 1571 sdp_neg_state = pjmedia_sdp_neg_get_state(call->inv->neg); 1341 1572 1342 /* Get media socket info */ 1343 pjmedia_transport_info_init(&tpinfo); 1344 pjmedia_transport_get_info(call->med_tp, &tpinfo); 1345 1346 /* Create SDP */ 1347 status = pjmedia_endpt_create_sdp(pjsua_var.med_endpt, pool, MAX_MEDIA, 1348 &tpinfo.sock_info, &sdp); 1349 if (status != PJ_SUCCESS) { 1350 if (sip_status_code) *sip_status_code = 500; 1573 /* Get one address to use in the origin field */ 1574 pj_bzero(&origin, sizeof(origin)); 1575 for (mi=0; mi<call->med_cnt; ++mi) { 1576 pjmedia_transport_info tpinfo; 1577 1578 if (call->media[mi].tp == NULL) 1579 continue; 1580 1581 pjmedia_transport_info_init(&tpinfo); 1582 pjmedia_transport_get_info(call->media[mi].tp, &tpinfo); 1583 pj_sockaddr_cp(&origin, &tpinfo.sock_info.rtp_addr_name); 1584 break; 1585 } 1586 1587 /* Create the base (blank) SDP */ 1588 status = pjmedia_endpt_create_base_sdp(pjsua_var.med_endpt, pool, NULL, 1589 &origin, &sdp); 1590 if (status != PJ_SUCCESS) 1351 1591 return status; 1352 } 1353 1354 /* If we're answering or updating the session with a new offer, 1355 * and the selected media is not the first media 1356 * in SDP, then fill in the unselected media with with zero port. 1357 * Otherwise we'll crash in transport_encode_sdp() because the media 1358 * lines are not aligned between offer and answer. 1359 */ 1360 if (call->audio_idx != 0 && 1361 (rem_sdp || sdp_neg_state==PJMEDIA_SDP_NEG_STATE_DONE)) 1362 { 1363 unsigned i; 1364 const pjmedia_sdp_session *ref_sdp = rem_sdp; 1365 1366 if (!ref_sdp) { 1367 /* We are updating session with a new offer */ 1368 status = pjmedia_sdp_neg_get_active_local(call->inv->neg, 1369 &ref_sdp); 1370 pj_assert(status == PJ_SUCCESS); 1371 } 1372 1373 for (i=0; i<ref_sdp->media_count; ++i) { 1374 const pjmedia_sdp_media *ref_m = ref_sdp->media[i]; 1375 pjmedia_sdp_media *m; 1376 1377 if ((int)i == call->audio_idx) 1378 continue; 1379 1380 m = pjmedia_sdp_media_clone_deactivate(pool, ref_m); 1381 if (i==sdp->media_count) 1382 sdp->media[sdp->media_count++] = m; 1383 else { 1384 pj_array_insert(sdp->media, sizeof(sdp->media[0]), 1385 sdp->media_count, i, &m); 1386 ++sdp->media_count; 1387 } 1592 1593 /* Process each media line */ 1594 for (mi=0; mi<call->med_cnt; ++mi) { 1595 pjsua_call_media *call_med = &call->media[mi]; 1596 pjmedia_sdp_media *m = NULL; 1597 pjmedia_transport_info tpinfo; 1598 1599 if (rem_sdp && mi >= rem_sdp->media_count) { 1600 /* Remote might have removed some media lines. */ 1601 break; 1602 } 1603 1604 if (call_med->tp == NULL || call_med->tp_st == PJSUA_MED_TP_DISABLED) 1605 { 1606 /* 1607 * This media is disabled. Just create a valid SDP with zero 1608 * port. 1609 */ 1610 m = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_media); 1611 m->desc.transport = pj_str("RTP/AVP"); 1612 m->desc.fmt_count = 1; 1613 m->conn = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_conn); 1614 m->conn->net_type = pj_str("IN"); 1615 m->conn->addr_type = pj_str("IP4"); 1616 m->conn->addr = pj_str("127.0.0.1"); 1617 1618 switch (call_med->type) { 1619 case PJMEDIA_TYPE_AUDIO: 1620 m->desc.media = pj_str("audio"); 1621 m->desc.fmt[0] = pj_str("0"); 1622 break; 1623 case PJMEDIA_TYPE_VIDEO: 1624 m->desc.media = pj_str("video"); 1625 m->desc.fmt[0] = pj_str("31"); 1626 break; 1627 default: 1628 if (rem_sdp && mi < rem_sdp->media_count) { 1629 pj_strdup(pool, &m->desc.media, 1630 &rem_sdp->media[mi]->desc.media); 1631 pj_strdup(pool, &m->desc.fmt[0], 1632 &rem_sdp->media[mi]->desc.fmt[0]); 1633 } else { 1634 pj_assert(!"Invalid call_med media type"); 1635 return PJ_EBUG; 1636 } 1637 } 1638 1639 sdp->media[sdp->media_count++] = m; 1640 continue; 1641 } 1642 1643 /* Get transport address info */ 1644 pjmedia_transport_info_init(&tpinfo); 1645 pjmedia_transport_get_info(call_med->tp, &tpinfo); 1646 1647 /* Ask pjmedia endpoint to create SDP media line */ 1648 switch (call_med->type) { 1649 case PJMEDIA_TYPE_AUDIO: 1650 status = pjmedia_endpt_create_audio_sdp(pjsua_var.med_endpt, pool, 1651 &tpinfo.sock_info, 0, &m); 1652 break; 1653 case PJMEDIA_TYPE_VIDEO: 1654 status = pjmedia_endpt_create_video_sdp(pjsua_var.med_endpt, pool, 1655 &tpinfo.sock_info, 0, &m); 1656 break; 1657 default: 1658 pj_assert(!"Invalid call_med media type"); 1659 return PJ_EBUG; 1660 } 1661 1662 if (status != PJ_SUCCESS) 1663 return status; 1664 1665 sdp->media[sdp->media_count++] = m; 1666 1667 /* Give to transport */ 1668 status = pjmedia_transport_encode_sdp(call_med->tp, pool, 1669 sdp, rem_sdp, mi); 1670 if (status != PJ_SUCCESS) { 1671 if (sip_err_code) *sip_err_code = PJSIP_SC_NOT_ACCEPTABLE; 1672 return status; 1673 } 1674 1675 /* Copy c= line of the first media to session level, 1676 * if there's none. 1677 */ 1678 if (sdp->conn == NULL) { 1679 sdp->conn = pjmedia_sdp_conn_clone(pool, m->conn); 1388 1680 } 1389 1681 } … … 1413 1705 } 1414 1706 1415 /* Give the SDP to media transport */ 1416 status = pjmedia_transport_encode_sdp(call->med_tp, pool, sdp, rem_sdp, 1417 call->audio_idx); 1418 if (status != PJ_SUCCESS) { 1419 if (sip_status_code) *sip_status_code = PJSIP_SC_NOT_ACCEPTABLE; 1420 return status; 1421 } 1422 1423 #if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0) 1707 1708 #if DISABLED_FOR_TICKET_1185 && defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0) 1424 1709 /* Check if SRTP is in optional mode and configured to use duplicated 1425 1710 * media, i.e: secured and unsecured version, in the SDP offer. … … 1434 1719 pjmedia_sdp_media *m = sdp->media[i]; 1435 1720 1436 /* Check if this media is unsecured but has SDP "crypto" 1721 /* Check if this media is unsecured but has SDP "crypto" 1437 1722 * attribute. 1438 1723 */ … … 1440 1725 pjmedia_sdp_media_find_attr2(m, "crypto", NULL) != NULL) 1441 1726 { 1442 if (i == (unsigned)call->audio_idx && 1727 if (i == (unsigned)call->audio_idx && 1443 1728 sdp_neg_state == PJMEDIA_SDP_NEG_STATE_DONE) 1444 1729 { … … 1463 1748 /* Insert the new media before the unsecured media */ 1464 1749 if (sdp->media_count < PJMEDIA_MAX_SDP_MEDIA) { 1465 pj_array_insert(sdp->media, sizeof(new_m), 1750 pj_array_insert(sdp->media, sizeof(new_m), 1466 1751 sdp->media_count, i, &new_m); 1467 1752 ++sdp->media_count; … … 1474 1759 #endif 1475 1760 1476 /* Update currently advertised RTP source address */1477 pj_memcpy(&call->med_rtp_addr, &tpinfo.sock_info.rtp_addr_name,1478 sizeof(pj_sockaddr));1479 1480 1761 *p_sdp = sdp; 1481 1762 return PJ_SUCCESS; … … 1486 1767 { 1487 1768 pjsua_call *call = &pjsua_var.calls[call_id]; 1488 1489 if (call->conf_slot != PJSUA_INVALID_ID) { 1490 if (pjsua_var.mconf) { 1491 pjsua_conf_remove_port(call->conf_slot); 1492 } 1493 call->conf_slot = PJSUA_INVALID_ID; 1494 } 1495 1496 if (call->session) { 1497 pjmedia_rtcp_stat stat; 1498 1499 if ((call->media_dir & PJMEDIA_DIR_ENCODING) && 1500 (pjmedia_session_get_stream_stat(call->session, 0, &stat) 1501 == PJ_SUCCESS)) 1502 { 1503 /* Save RTP timestamp & sequence, so when media session is 1504 * restarted, those values will be restored as the initial 1505 * RTP timestamp & sequence of the new media session. So in 1506 * the same call session, RTP timestamp and sequence are 1507 * guaranteed to be contigue. 1508 */ 1509 call->rtp_tx_seq_ts_set = 1 | (1 << 1); 1510 call->rtp_tx_seq = stat.rtp_tx_last_seq; 1511 call->rtp_tx_ts = stat.rtp_tx_last_ts; 1512 } 1513 1514 if (pjsua_var.ua_cfg.cb.on_stream_destroyed) { 1515 pjsua_var.ua_cfg.cb.on_stream_destroyed(call_id, call->session, 0); 1516 } 1517 1518 pjmedia_session_destroy(call->session); 1519 call->session = NULL; 1520 1521 PJ_LOG(4,(THIS_FILE, "Media session for call %d is destroyed", 1522 call_id)); 1523 1524 } 1525 1526 call->media_st = PJSUA_CALL_MEDIA_NONE; 1769 unsigned mi; 1770 1771 for (mi=0; mi<call->med_cnt; ++mi) { 1772 pjsua_call_media *call_med = &call->media[mi]; 1773 1774 if (call_med->type == PJMEDIA_TYPE_AUDIO) { 1775 pjmedia_stream *strm = call_med->strm.a.stream; 1776 pjmedia_rtcp_stat stat; 1777 1778 if (strm) { 1779 if (call_med->strm.a.conf_slot != PJSUA_INVALID_ID) { 1780 if (pjsua_var.mconf) { 1781 pjsua_conf_remove_port(call_med->strm.a.conf_slot); 1782 } 1783 call_med->strm.a.conf_slot = PJSUA_INVALID_ID; 1784 } 1785 1786 if ((call_med->dir & PJMEDIA_DIR_ENCODING) && 1787 (pjmedia_stream_get_stat(strm, &stat) == PJ_SUCCESS)) 1788 { 1789 /* Save RTP timestamp & sequence, so when media session is 1790 * restarted, those values will be restored as the initial 1791 * RTP timestamp & sequence of the new media session. So in 1792 * the same call session, RTP timestamp and sequence are 1793 * guaranteed to be contigue. 1794 */ 1795 call_med->rtp_tx_seq_ts_set = 1 | (1 << 1); 1796 call_med->rtp_tx_seq = stat.rtp_tx_last_seq; 1797 call_med->rtp_tx_ts = stat.rtp_tx_last_ts; 1798 } 1799 1800 if (pjsua_var.ua_cfg.cb.on_stream_destroyed) { 1801 pjsua_var.ua_cfg.cb.on_stream_destroyed(call_id, strm, mi); 1802 } 1803 1804 pjmedia_stream_destroy(strm); 1805 call_med->strm.a.stream = NULL; 1806 } 1807 } 1808 1809 #if PJMEDIA_HAS_VIDEO 1810 else if (call_med->type == PJMEDIA_TYPE_VIDEO) { 1811 stop_video_stream(call_med); 1812 } 1813 #endif 1814 1815 PJ_LOG(4,(THIS_FILE, "Media session call%02d:%d is destroyed", 1816 call_id, mi)); 1817 call_med->state = PJSUA_CALL_MEDIA_NONE; 1818 } 1527 1819 } 1528 1820 … … 1530 1822 { 1531 1823 pjsua_call *call = &pjsua_var.calls[call_id]; 1824 unsigned mi; 1532 1825 1533 1826 stop_media_session(call_id); 1534 1827 1535 if (call->med_tp_st != PJSUA_MED_TP_IDLE) { 1536 pjmedia_transport_media_stop(call->med_tp); 1537 call->med_tp_st = PJSUA_MED_TP_IDLE; 1538 } 1539 1540 if (call->med_orig && call->med_tp && call->med_tp != call->med_orig) { 1541 pjmedia_transport_close(call->med_tp); 1542 call->med_tp = call->med_orig; 1828 for (mi=0; mi<call->med_cnt; ++mi) { 1829 pjsua_call_media *call_med = &call->media[mi]; 1830 1831 if (call_med->tp_st != PJSUA_MED_TP_IDLE) { 1832 pjmedia_transport_media_stop(call_med->tp); 1833 call_med->tp_st = PJSUA_MED_TP_IDLE; 1834 } 1835 1836 //if (call_med->tp_orig && call_med->tp && 1837 // call_med->tp != call_med->tp_orig) 1838 //{ 1839 // pjmedia_transport_close(call_med->tp); 1840 // call_med->tp = call_med->tp_orig; 1841 //} 1842 if (call_med->tp) { 1843 pjmedia_transport_close(call_med->tp); 1844 call_med->tp = call_med->tp_orig = NULL; 1845 } 1543 1846 } 1544 1847 … … 1570 1873 1571 1874 1572 pj_status_t pjsua_media_channel_update(pjsua_call_id call_id, 1573 const pjmedia_sdp_session *local_sdp, 1574 const pjmedia_sdp_session *remote_sdp) 1575 { 1576 int prev_media_st = 0; 1577 pjsua_call *call = &pjsua_var.calls[call_id]; 1578 pjmedia_session_info sess_info; 1579 pjmedia_stream_info *si = NULL; 1875 static pj_status_t audio_channel_update(pjsua_call_media *call_med, 1876 pj_pool_t *tmp_pool, 1877 const pjmedia_sdp_session *local_sdp, 1878 const pjmedia_sdp_session *remote_sdp) 1879 { 1880 pjsua_call *call = call_med->call; 1881 pjmedia_stream_info the_si, *si = &the_si; 1580 1882 pjmedia_port *media_port; 1883 unsigned strm_idx = call_med->idx; 1581 1884 pj_status_t status; 1582 1583 if (!pjsua_var.med_endpt) { 1584 /* We're being shutdown */ 1585 return PJ_EBUSY; 1586 } 1587 1588 /* Destroy existing media session, if any. */ 1589 prev_media_st = call->media_st; 1590 stop_media_session(call->index); 1591 1592 /* Create media session info based on SDP parameters. 1593 */ 1594 status = pjmedia_session_info_from_sdp( call->inv->pool_prov, 1595 pjsua_var.med_endpt, 1596 PJMEDIA_MAX_SDP_MEDIA, &sess_info, 1597 local_sdp, remote_sdp); 1885 1886 status = pjmedia_stream_info_from_sdp(si, tmp_pool, pjsua_var.med_endpt, 1887 local_sdp, remote_sdp, strm_idx); 1598 1888 if (status != PJ_SUCCESS) 1599 1889 return status; 1600 1890 1601 /* Update audio index from the negotiated SDP */1602 call->audio_idx = find_audio_index(local_sdp, PJ_TRUE);1603 1604 /* Find which session is audio */1605 PJ_ASSERT_RETURN(call->audio_idx != -1, PJ_EBUG);1606 PJ_ASSERT_RETURN(call->audio_idx < (int)sess_info.stream_cnt, PJ_EBUG);1607 si = &sess_info.stream_info[call->audio_idx];1608 1609 /* Reset session info with only one media stream */1610 sess_info.stream_cnt = 1;1611 if (si != &sess_info.stream_info[0]) {1612 pj_memcpy(&sess_info.stream_info[0], si, sizeof(pjmedia_stream_info));1613 si = &sess_info.stream_info[0];1614 }1615 1616 1891 /* Check if no media is active */ 1617 if (sess_info.stream_cnt == 0 || si->dir == PJMEDIA_DIR_NONE) 1618 { 1892 if (si->dir == PJMEDIA_DIR_NONE) { 1619 1893 /* Call media state */ 1620 call ->media_st= PJSUA_CALL_MEDIA_NONE;1894 call_med->state = PJSUA_CALL_MEDIA_NONE; 1621 1895 1622 1896 /* Call media direction */ 1623 call->media_dir = PJMEDIA_DIR_NONE; 1624 1625 /* Don't stop transport because we need to transmit keep-alives, and 1626 * also to prevent restarting ICE negotiation. See 1627 * http://trac.pjsip.org/repos/ticket/1094 1628 */ 1629 #if 0 1630 /* Shutdown transport's session */ 1631 pjmedia_transport_media_stop(call->med_tp); 1632 call->med_tp_st = PJSUA_MED_TP_IDLE; 1633 1634 /* No need because we need keepalive? */ 1635 1636 /* Close upper entry of transport stack */ 1637 if (call->med_orig && (call->med_tp != call->med_orig)) { 1638 pjmedia_transport_close(call->med_tp); 1639 call->med_tp = call->med_orig; 1640 } 1641 #endif 1897 call_med->dir = PJMEDIA_DIR_NONE; 1642 1898 1643 1899 } else { … … 1645 1901 1646 1902 /* Start/restart media transport */ 1647 status = pjmedia_transport_media_start(call->med_tp, 1648 call->inv->pool_prov, 1649 local_sdp, remote_sdp, 1650 call->audio_idx); 1903 status = pjmedia_transport_media_start(call_med->tp, 1904 tmp_pool, local_sdp, 1905 remote_sdp, strm_idx); 1651 1906 if (status != PJ_SUCCESS) 1652 1907 return status; 1653 1908 1654 call ->med_tp_st = PJSUA_MED_TP_RUNNING;1909 call_med->tp_st = PJSUA_MED_TP_RUNNING; 1655 1910 1656 1911 /* Get remote SRTP usage policy */ 1657 1912 pjmedia_transport_info_init(&tp_info); 1658 pjmedia_transport_get_info(call ->med_tp, &tp_info);1913 pjmedia_transport_get_info(call_med->tp, &tp_info); 1659 1914 if (tp_info.specific_info_cnt > 0) { 1660 1915 unsigned i; … … 1665 1920 (pjmedia_srtp_info*) tp_info.spc_info[i].buffer; 1666 1921 1667 call ->rem_srtp_use = srtp_info->peer_use;1922 call_med->rem_srtp_use = srtp_info->peer_use; 1668 1923 break; 1669 1924 } … … 1694 1949 1695 1950 /* Set SSRC */ 1696 si->ssrc = call ->ssrc;1951 si->ssrc = call_med->ssrc; 1697 1952 1698 1953 /* Set RTP timestamp & sequence, normally these value are intialized … … 1701 1956 * contigue. 1702 1957 */ 1703 si->rtp_ts = call ->rtp_tx_ts;1704 si->rtp_seq = call ->rtp_tx_seq;1705 si->rtp_seq_ts_set = call ->rtp_tx_seq_ts_set;1958 si->rtp_ts = call_med->rtp_tx_ts; 1959 si->rtp_seq = call_med->rtp_tx_seq; 1960 si->rtp_seq_ts_set = call_med->rtp_tx_seq_ts_set; 1706 1961 1707 1962 #if defined(PJMEDIA_STREAM_ENABLE_KA) && PJMEDIA_STREAM_ENABLE_KA!=0 … … 1711 1966 1712 1967 /* Create session based on session info. */ 1713 status = pjmedia_session_create( pjsua_var.med_endpt, &sess_info, 1714 &call->med_tp, 1715 call, &call->session ); 1968 status = pjmedia_stream_create(pjsua_var.med_endpt, NULL, si, 1969 call_med->tp, NULL, 1970 &call_med->strm.a.stream); 1971 if (status != PJ_SUCCESS) { 1972 return status; 1973 } 1974 1975 /* Start stream */ 1976 status = pjmedia_stream_start(call_med->strm.a.stream); 1716 1977 if (status != PJ_SUCCESS) { 1717 1978 return status; … … 1722 1983 */ 1723 1984 if (pjsua_var.ua_cfg.cb.on_dtmf_digit) { 1724 pjmedia_s ession_set_dtmf_callback(call->session, 0,1725 &dtmf_callback,1726 1985 pjmedia_stream_set_dtmf_callback(call_med->strm.a.stream, 1986 &dtmf_callback, 1987 (void*)(long)(call->index)); 1727 1988 } 1728 1989 … … 1730 1991 * We need the port interface to add to the conference bridge. 1731 1992 */ 1732 pjmedia_s ession_get_port(call->session, 0, &media_port);1993 pjmedia_stream_get_port(call_med->strm.a.stream, &media_port); 1733 1994 1734 1995 /* Notify application about stream creation. … … 1737 1998 */ 1738 1999 if (pjsua_var.ua_cfg.cb.on_stream_created) { 1739 pjsua_var.ua_cfg.cb.on_stream_created(call_id, call->session, 1740 0, &media_port); 2000 pjsua_var.ua_cfg.cb.on_stream_created(call->index, 2001 call_med->strm.a.stream, 2002 strm_idx, &media_port); 1741 2003 } 1742 2004 … … 1759 2021 media_port, 1760 2022 &port_name, 1761 (unsigned*)&call->conf_slot); 2023 (unsigned*) 2024 &call_med->strm.a.conf_slot); 1762 2025 if (status != PJ_SUCCESS) { 1763 2026 return status; … … 1766 2029 1767 2030 /* Call media direction */ 1768 call ->media_dir = si->dir;2031 call_med->dir = si->dir; 1769 2032 1770 2033 /* Call media state */ 1771 2034 if (call->local_hold) 1772 call ->media_st= PJSUA_CALL_MEDIA_LOCAL_HOLD;1773 else if (call ->media_dir == PJMEDIA_DIR_DECODING)1774 call ->media_st= PJSUA_CALL_MEDIA_REMOTE_HOLD;2035 call_med->state = PJSUA_CALL_MEDIA_LOCAL_HOLD; 2036 else if (call_med->dir == PJMEDIA_DIR_DECODING) 2037 call_med->state = PJSUA_CALL_MEDIA_REMOTE_HOLD; 1775 2038 else 1776 call ->media_st= PJSUA_CALL_MEDIA_ACTIVE;2039 call_med->state = PJSUA_CALL_MEDIA_ACTIVE; 1777 2040 } 1778 2041 … … 1781 2044 char info[80]; 1782 2045 int info_len = 0; 1783 unsigned i; 1784 1785 for (i=0; i<sess_info.stream_cnt; ++i) { 1786 int len; 1787 const char *dir; 1788 pjmedia_stream_info *strm_info = &sess_info.stream_info[i]; 1789 1790 switch (strm_info->dir) { 1791 case PJMEDIA_DIR_NONE: 1792 dir = "inactive"; 1793 break; 1794 case PJMEDIA_DIR_ENCODING: 1795 dir = "sendonly"; 1796 break; 1797 case PJMEDIA_DIR_DECODING: 1798 dir = "recvonly"; 1799 break; 1800 case PJMEDIA_DIR_ENCODING_DECODING: 1801 dir = "sendrecv"; 1802 break; 1803 default: 1804 dir = "unknown"; 1805 break; 1806 } 1807 len = pj_ansi_sprintf( info+info_len, 1808 ", stream #%d: %.*s (%s)", i, 1809 (int)strm_info->fmt.encoding_name.slen, 1810 strm_info->fmt.encoding_name.ptr, 1811 dir); 1812 if (len > 0) 1813 info_len += len; 1814 } 2046 int len; 2047 const char *dir; 2048 2049 switch (si->dir) { 2050 case PJMEDIA_DIR_NONE: 2051 dir = "inactive"; 2052 break; 2053 case PJMEDIA_DIR_ENCODING: 2054 dir = "sendonly"; 2055 break; 2056 case PJMEDIA_DIR_DECODING: 2057 dir = "recvonly"; 2058 break; 2059 case PJMEDIA_DIR_ENCODING_DECODING: 2060 dir = "sendrecv"; 2061 break; 2062 default: 2063 dir = "unknown"; 2064 break; 2065 } 2066 len = pj_ansi_sprintf( info+info_len, 2067 ", stream #%d: %.*s (%s)", strm_idx, 2068 (int)si->fmt.encoding_name.slen, 2069 si->fmt.encoding_name.ptr, 2070 dir); 2071 if (len > 0) 2072 info_len += len; 1815 2073 PJ_LOG(4,(THIS_FILE,"Media updates%s", info)); 1816 2074 } 1817 2075 1818 2076 return PJ_SUCCESS; 2077 } 2078 2079 pj_status_t pjsua_media_channel_update(pjsua_call_id call_id, 2080 const pjmedia_sdp_session *local_sdp, 2081 const pjmedia_sdp_session *remote_sdp) 2082 { 2083 pjsua_call *call = &pjsua_var.calls[call_id]; 2084 pj_pool_t *tmp_pool = call->inv->pool_prov; 2085 unsigned mi; 2086 pj_bool_t got_media = PJ_FALSE; 2087 pj_status_t status = PJ_SUCCESS; 2088 2089 if (pjsua_get_state() != PJSUA_STATE_RUNNING) 2090 return PJ_EBUSY; 2091 2092 /* Destroy existing media session, if any. */ 2093 stop_media_session(call->index); 2094 2095 /* Reset audio_idx first */ 2096 call->audio_idx = -1; 2097 2098 /* Process each media stream */ 2099 for (mi=0; mi < call->med_cnt; ++mi) { 2100 pjsua_call_media *call_med = &call->media[mi]; 2101 2102 if (mi >= local_sdp->media_count || 2103 mi >= remote_sdp->media_count) 2104 { 2105 /* This may happen when remote removed any SDP media lines in 2106 * its re-offer. 2107 */ 2108 continue; 2109 #if 0 2110 /* Something is wrong */ 2111 PJ_LOG(1,(THIS_FILE, "Error updating media for call %d: " 2112 "invalid media index %d in SDP", call_id, mi)); 2113 return PJMEDIA_SDP_EINSDP; 2114 #endif 2115 } 2116 2117 switch (call_med->type) { 2118 case PJMEDIA_TYPE_AUDIO: 2119 status = audio_channel_update(call_med, tmp_pool, 2120 local_sdp, remote_sdp); 2121 if (call->audio_idx==-1 && status==PJ_SUCCESS && 2122 call_med->strm.a.stream) 2123 { 2124 call->audio_idx = mi; 2125 } 2126 break; 2127 #if PJMEDIA_HAS_VIDEO 2128 case PJMEDIA_TYPE_VIDEO: 2129 status = video_channel_update(call_med, tmp_pool, 2130 local_sdp, remote_sdp); 2131 break; 2132 #endif 2133 default: 2134 status = PJMEDIA_EINVALIMEDIATYPE; 2135 break; 2136 } 2137 2138 if (status != PJ_SUCCESS) { 2139 PJ_PERROR(1,(THIS_FILE, status, "Error updating media call%02d:%d", 2140 call_id, mi)); 2141 } else { 2142 got_media = PJ_TRUE; 2143 } 2144 } 2145 2146 return (got_media? PJ_SUCCESS : PJMEDIA_SDPNEG_ENOMEDIA); 1819 2147 } 1820 2148 … … 1969 2297 { 1970 2298 need_reopen = (peer_info.format.id != port0_info.format.id || 1971 peer_info.format.bitrate != port0_info.format.bitrate || 2299 peer_info.format.det.aud.avg_bps != 2300 port0_info.format.det.aud.avg_bps || 1972 2301 peer_info.clock_rate != port0_info.clock_rate || 1973 peer_info.channel_count !=port0_info.channel_count);2302 peer_info.channel_count!=port0_info.channel_count); 1974 2303 } 1975 2304 … … 1986 2315 peer_info.bits_per_sample); 1987 2316 if (status != PJ_SUCCESS) { 1988 pjsua_perror(THIS_FILE, "Error opening sound device", status); 2317 pjsua_perror(THIS_FILE, "Error opening sound device", 2318 status); 1989 2319 return status; 1990 2320 } … … 1999 2329 status = open_snd_dev(¶m); 2000 2330 if (status != PJ_SUCCESS) { 2001 pjsua_perror(THIS_FILE, "Error opening sound device", status); 2331 pjsua_perror(THIS_FILE, "Error opening sound device", 2332 status); 2002 2333 return status; 2003 2334 } 2004 2335 } else { 2005 2336 /* Null-audio */ 2006 status = pjsua_set_snd_dev(pjsua_var.cap_dev, pjsua_var.play_dev); 2337 status = pjsua_set_snd_dev(pjsua_var.cap_dev, 2338 pjsua_var.play_dev); 2007 2339 if (status != PJ_SUCCESS) { 2008 pjsua_perror(THIS_FILE, "Error opening sound device", status); 2340 pjsua_perror(THIS_FILE, "Error opening sound device", 2341 status); 2009 2342 return status; 2010 2343 } 2344 } 2345 } else if (pjsua_var.no_snd) { 2346 if (!pjsua_var.snd_is_on) { 2347 pjsua_var.snd_is_on = PJ_TRUE; 2348 /* Notify app */ 2349 if (pjsua_var.ua_cfg.cb.on_snd_dev_operation) { 2350 (*pjsua_var.ua_cfg.cb.on_snd_dev_operation)(1); 2351 } 2011 2352 } 2012 2353 } … … 2026 2367 return status; 2027 2368 } 2028 } 2029 2369 } else if (pjsua_var.no_snd && !pjsua_var.snd_is_on) { 2370 pjsua_var.snd_is_on = PJ_TRUE; 2371 /* Notify app */ 2372 if (pjsua_var.ua_cfg.cb.on_snd_dev_operation) { 2373 (*pjsua_var.ua_cfg.cb.on_snd_dev_operation)(1); 2374 } 2375 } 2030 2376 } 2031 2377 … … 2143 2489 pool, path, 2144 2490 pjsua_var.mconf_cfg.samples_per_frame * 2145 1000 / pjsua_var.media_cfg.channel_count / 2491 1000 / pjsua_var.media_cfg.channel_count / 2146 2492 pjsua_var.media_cfg.clock_rate, 2147 2493 options, 0, &port); … … 2684 3030 close_snd_dev(); 2685 3031 3032 /* Notify app */ 3033 if (pjsua_var.ua_cfg.cb.on_snd_dev_operation) { 3034 (*pjsua_var.ua_cfg.cb.on_snd_dev_operation)(1); 3035 } 3036 2686 3037 /* Create memory pool for sound device. */ 2687 3038 pjsua_var.snd_pool = pjsua_pool_create("pjsua_snd", 4000, 4000); … … 2709 3060 if (!pjsua_var.is_mswitch && 2710 3061 param->base.ext_fmt.id == PJMEDIA_FORMAT_PCM && 2711 conf_port->info.clock_rate!= param->base.clock_rate)3062 PJMEDIA_PIA_SRATE(&conf_port->info) != param->base.clock_rate) 2712 3063 { 2713 3064 pjmedia_port *resample_port; … … 2745 3096 */ 2746 3097 if (pjsua_var.is_mswitch) { 2747 pj_memcpy(&conf_port->info.format, ¶m->base.ext_fmt, 2748 sizeof(conf_port->info.format)); 2749 conf_port->info.clock_rate = param->base.clock_rate; 2750 conf_port->info.samples_per_frame = param->base.samples_per_frame; 2751 conf_port->info.channel_count = param->base.channel_count; 2752 conf_port->info.bits_per_sample = 16; 2753 } 3098 pj_memcpy(&conf_port->info.fmt, ¶m->base.ext_fmt, 3099 sizeof(conf_port->info.fmt)); 3100 conf_port->info.fmt.det.aud.clock_rate = param->base.clock_rate; 3101 conf_port->info.fmt.det.aud.frame_time_usec = param->base.samples_per_frame* 3102 1000000 / 3103 param->base.clock_rate; 3104 conf_port->info.fmt.det.aud.channel_count = param->base.channel_count; 3105 conf_port->info.fmt.det.aud.bits_per_sample = 16; 3106 } 3107 2754 3108 2755 3109 /* Connect sound port to the bridge */ … … 2817 3171 static void close_snd_dev(void) 2818 3172 { 3173 /* Notify app */ 3174 if (pjsua_var.snd_is_on && pjsua_var.ua_cfg.cb.on_snd_dev_operation) { 3175 (*pjsua_var.ua_cfg.cb.on_snd_dev_operation)(0); 3176 } 3177 2819 3178 /* Close sound device */ 2820 3179 if (pjsua_var.snd_port) { … … 2850 3209 pj_pool_release(pjsua_var.snd_pool); 2851 3210 pjsua_var.snd_pool = NULL; 3211 pjsua_var.snd_is_on = PJ_FALSE; 2852 3212 } 2853 3213 … … 2913 3273 2914 3274 pjsua_var.no_snd = PJ_FALSE; 3275 pjsua_var.snd_is_on = PJ_TRUE; 2915 3276 2916 3277 return PJ_SUCCESS; … … 2947 3308 /* Close existing sound device */ 2948 3309 close_snd_dev(); 3310 3311 /* Notify app */ 3312 if (pjsua_var.ua_cfg.cb.on_snd_dev_operation) { 3313 (*pjsua_var.ua_cfg.cb.on_snd_dev_operation)(1); 3314 } 2949 3315 2950 3316 /* Create memory pool for sound device. */ … … 2977 3343 2978 3344 pjsua_var.no_snd = PJ_FALSE; 3345 pjsua_var.snd_is_on = PJ_TRUE; 2979 3346 2980 3347 return PJ_SUCCESS; … … 3122 3489 3123 3490 for (i=0; i<count; ++i) { 3491 pj_bzero(&id[i], sizeof(pjsua_codec_info)); 3492 3124 3493 pjmedia_codec_info_to_id(&info[i], id[i].buf_, sizeof(id[i].buf_)); 3125 3494 id[i].codec_id = pj_str(id[i].buf_); … … 3175 3544 3176 3545 if (count != 1) 3177 return PJ_ENOTFOUND;3546 return (count > 1? PJ_ETOOMANY : PJ_ENOTFOUND); 3178 3547 3179 3548 status = pjmedia_codec_mgr_get_default_param( codec_mgr, info, param); … … 3212 3581 return status; 3213 3582 } 3583 3584
Note: See TracChangeset
for help on using the changeset viewer.