Changeset 1098 for pjproject/trunk/pjsip/src/pjsua-lib/pjsua_media.c
- Timestamp:
- Mar 23, 2007 4:34:20 PM (17 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
pjproject/trunk/pjsip/src/pjsua-lib/pjsua_media.c
r1066 r1098 216 216 pj_sock_t sock[2]; 217 217 218 /* Make sure STUN server resolution has completed */ 219 status = pjsua_resolve_stun_server(PJ_TRUE); 220 if (status != PJ_SUCCESS) { 221 pjsua_perror(THIS_FILE, "Error resolving STUN server", status); 222 return status; 223 } 224 225 218 226 if (next_rtp_port == 0) 219 227 next_rtp_port = (pj_uint16_t)cfg->port; … … 273 281 * and make sure that the mapped RTCP port is adjacent with the RTP. 274 282 */ 275 if (cfg->stun_config.stun_srv1.slen) { 283 if (pjsua_var.stun_srv.addr.sa_family != 0) { 284 char ip_addr[32]; 285 pj_str_t stun_srv; 286 287 pj_ansi_strcpy(ip_addr, 288 pj_inet_ntoa(pjsua_var.stun_srv.ipv4.sin_addr)); 289 stun_srv = pj_str(ip_addr); 290 276 291 status=pjstun_get_mapped_addr(&pjsua_var.cp.factory, 2, sock, 277 &cfg->stun_config.stun_srv1, 278 cfg->stun_config.stun_port1, 279 &cfg->stun_config.stun_srv2, 280 cfg->stun_config.stun_port2, 292 &stun_srv, 3478, 293 &stun_srv, 3478, 281 294 mapped_addr); 282 295 if (status != PJ_SUCCESS) { … … 489 502 490 503 491 /* 492 * Create UDP media transports for all the calls. This function creates 493 * one UDP media transport for each call. 494 */ 495 PJ_DEF(pj_status_t) 496 pjsua_media_transports_create(const pjsua_transport_config *app_cfg) 497 { 498 pjsua_transport_config cfg; 504 /* Create normal UDP media transports */ 505 static pj_status_t create_udp_media_transports(pjsua_transport_config *cfg) 506 { 499 507 unsigned i; 500 508 pj_status_t status; 501 509 502 503 /* Make sure pjsua_init() has been called */504 PJ_ASSERT_RETURN(pjsua_var.ua_cfg.max_calls>0, PJ_EINVALIDOP);505 506 PJSUA_LOCK();507 508 /* Delete existing media transports */509 for (i=0; i<pjsua_var.ua_cfg.max_calls; ++i) {510 if (pjsua_var.calls[i].med_tp != NULL) {511 pjsua_var.calls[i].med_tp->op->destroy(pjsua_var.calls[i].med_tp);512 pjsua_var.calls[i].med_tp = NULL;513 }514 }515 516 /* Copy config */517 pj_memcpy(&cfg, app_cfg, sizeof(*app_cfg));518 pjsua_normalize_stun_config(&cfg.stun_config);519 520 510 /* Create each media transport */ 521 511 for (i=0; i<pjsua_var.ua_cfg.max_calls; ++i) { 522 512 523 status = create_rtp_rtcp_sock( &cfg, &pjsua_var.calls[i].skinfo);513 status = create_rtp_rtcp_sock(cfg, &pjsua_var.calls[i].skinfo); 524 514 if (status != PJ_SUCCESS) { 525 515 pjsua_perror(THIS_FILE, "Unable to create RTP/RTCP socket", … … 546 536 } 547 537 548 PJSUA_UNLOCK();549 550 538 return PJ_SUCCESS; 551 539 … … 553 541 for (i=0; i<pjsua_var.ua_cfg.max_calls; ++i) { 554 542 if (pjsua_var.calls[i].med_tp != NULL) { 555 pj sua_var.calls[i].med_tp->op->destroy(pjsua_var.calls[i].med_tp);543 pjmedia_transport_close(pjsua_var.calls[i].med_tp); 556 544 pjsua_var.calls[i].med_tp = NULL; 557 545 } 558 546 } 559 547 548 return status; 549 } 550 551 552 /* Create ICE media transports (when ice is enabled) */ 553 static pj_status_t create_ice_media_transports(pjsua_transport_config *cfg) 554 { 555 unsigned i; 556 pj_status_t status; 557 558 /* Create each media transport */ 559 for (i=0; i<pjsua_var.ua_cfg.max_calls; ++i) { 560 pj_ice_st *ice_st; 561 562 status = pjmedia_ice_create(pjsua_var.med_endpt, NULL, 1, 563 &pjsua_var.stun_cfg, 564 &pjsua_var.calls[i].med_tp); 565 if (status != PJ_SUCCESS) { 566 pjsua_perror(THIS_FILE, "Unable to create ICE media transport", 567 status); 568 goto on_error; 569 } 570 571 ice_st = pjmedia_ice_get_ice_st(pjsua_var.calls[i].med_tp); 572 573 /* Add host candidates for RTP */ 574 status = pj_ice_st_add_all_host_interfaces(ice_st, 1, 0, 575 PJ_FALSE, NULL); 576 if (status != PJ_SUCCESS) { 577 pjsua_perror(THIS_FILE, "Error adding ICE host candidates", 578 status); 579 goto on_error; 580 } 581 582 /* Configure STUN server */ 583 if (pjsua_var.stun_srv.addr.sa_family != 0) { 584 585 status = pj_ice_st_set_stun_addr(ice_st, 586 pjsua_var.media_cfg.enable_relay, 587 &pjsua_var.stun_srv.ipv4); 588 if (status != PJ_SUCCESS) { 589 pjsua_perror(THIS_FILE, "Error setting ICE's STUN server", 590 status); 591 goto on_error; 592 } 593 594 /* Add STUN server reflexive candidate for RTP */ 595 status = pj_ice_st_add_stun_interface(ice_st, 1, 0, 596 PJ_FALSE, NULL); 597 if (status != PJ_SUCCESS) { 598 pjsua_perror(THIS_FILE, "Error adding ICE address", 599 status); 600 goto on_error; 601 } 602 } 603 } 604 605 /* Wait until all ICE transports are ready */ 606 for (i=0; i<pjsua_var.ua_cfg.max_calls; ++i) { 607 pj_ice_st *ice_st; 608 609 ice_st = pjmedia_ice_get_ice_st(pjsua_var.calls[i].med_tp); 610 611 /* Wait until interface status is PJ_SUCCESS */ 612 for (;;) { 613 status = pj_ice_st_get_interfaces_status(ice_st); 614 if (status == PJ_EPENDING) 615 pjsua_handle_events(100); 616 else 617 break; 618 } 619 620 if (status != PJ_SUCCESS) { 621 pjsua_perror(THIS_FILE, 622 "Error adding STUN address to ICE media transport", 623 status); 624 goto on_error; 625 } 626 627 /* Get transport info */ 628 pjmedia_transport_get_info(pjsua_var.calls[i].med_tp, 629 &pjsua_var.calls[i].skinfo); 630 631 } 632 633 return PJ_SUCCESS; 634 635 on_error: 636 for (i=0; i<pjsua_var.ua_cfg.max_calls; ++i) { 637 if (pjsua_var.calls[i].med_tp != NULL) { 638 pjmedia_transport_close(pjsua_var.calls[i].med_tp); 639 pjsua_var.calls[i].med_tp = NULL; 640 } 641 } 642 643 return status; 644 } 645 646 647 /* 648 * Create UDP media transports for all the calls. This function creates 649 * one UDP media transport for each call. 650 */ 651 PJ_DEF(pj_status_t) 652 pjsua_media_transports_create(const pjsua_transport_config *app_cfg) 653 { 654 pjsua_transport_config cfg; 655 unsigned i; 656 pj_status_t status; 657 658 659 /* Make sure pjsua_init() has been called */ 660 PJ_ASSERT_RETURN(pjsua_var.ua_cfg.max_calls>0, PJ_EINVALIDOP); 661 662 PJSUA_LOCK(); 663 664 /* Delete existing media transports */ 665 for (i=0; i<pjsua_var.ua_cfg.max_calls; ++i) { 666 if (pjsua_var.calls[i].med_tp != NULL) { 667 pjmedia_transport_close(pjsua_var.calls[i].med_tp); 668 pjsua_var.calls[i].med_tp = NULL; 669 } 670 } 671 672 /* Copy config */ 673 pjsua_transport_config_dup(pjsua_var.pool, &cfg, app_cfg); 674 675 if (pjsua_var.media_cfg.enable_ice) { 676 status = create_ice_media_transports(&cfg); 677 } else { 678 status = create_udp_media_transports(&cfg); 679 } 680 681 560 682 PJSUA_UNLOCK(); 561 683 562 684 return status; 685 } 686 687 688 pj_status_t pjsua_media_channel_init(pjsua_call_id call_id, 689 pjsip_role_e role) 690 { 691 pjsua_call *call = &pjsua_var.calls[call_id]; 692 693 if (pjsua_var.media_cfg.enable_ice) { 694 pj_ice_role ice_role; 695 pj_status_t status; 696 697 ice_role = (role==PJSIP_ROLE_UAC ? PJ_ICE_ROLE_CONTROLLING : 698 PJ_ICE_ROLE_CONTROLLED); 699 700 /* Restart ICE */ 701 pjmedia_ice_stop_ice(call->med_tp); 702 703 status = pjmedia_ice_init_ice(call->med_tp, ice_role, NULL, NULL); 704 if (status != PJ_SUCCESS) 705 return status; 706 } 707 708 return PJ_SUCCESS; 709 } 710 711 pj_status_t pjsua_media_channel_create_sdp(pjsua_call_id call_id, 712 pj_pool_t *pool, 713 pjmedia_sdp_session **p_sdp) 714 { 715 pjmedia_sdp_session *sdp; 716 pjsua_call *call = &pjsua_var.calls[call_id]; 717 pj_status_t status; 718 719 status = pjmedia_endpt_create_sdp(pjsua_var.med_endpt, pool, 1, 720 &call->skinfo, &sdp); 721 if (status != PJ_SUCCESS) 722 goto on_error; 723 724 if (pjsua_var.media_cfg.enable_ice) { 725 status = pjmedia_ice_modify_sdp(call->med_tp, pool, sdp); 726 if (status != PJ_SUCCESS) 727 goto on_error; 728 } 729 730 *p_sdp = sdp; 731 return PJ_SUCCESS; 732 733 on_error: 734 pjsua_media_channel_deinit(call_id); 735 return status; 736 737 } 738 739 740 static void stop_media_session(pjsua_call_id call_id) 741 { 742 pjsua_call *call = &pjsua_var.calls[call_id]; 743 744 if (call->conf_slot != PJSUA_INVALID_ID) { 745 pjmedia_conf_remove_port(pjsua_var.mconf, call->conf_slot); 746 call->conf_slot = PJSUA_INVALID_ID; 747 } 748 749 if (call->session) { 750 pjmedia_session_destroy(call->session); 751 call->session = NULL; 752 753 PJ_LOG(4,(THIS_FILE, "Media session for call %d is destroyed", 754 call_id)); 755 756 } 757 758 call->media_st = PJSUA_CALL_MEDIA_NONE; 759 } 760 761 pj_status_t pjsua_media_channel_deinit(pjsua_call_id call_id) 762 { 763 pjsua_call *call = &pjsua_var.calls[call_id]; 764 765 stop_media_session(call_id); 766 767 if (pjsua_var.media_cfg.enable_ice) { 768 pjmedia_ice_stop_ice(call->med_tp); 769 } 770 771 return PJ_SUCCESS; 772 } 773 774 775 /* 776 * DTMF callback from the stream. 777 */ 778 static void dtmf_callback(pjmedia_stream *strm, void *user_data, 779 int digit) 780 { 781 PJ_UNUSED_ARG(strm); 782 783 if (pjsua_var.ua_cfg.cb.on_dtmf_digit) { 784 pjsua_call_id call_id; 785 786 call_id = (pjsua_call_id)user_data; 787 pjsua_var.ua_cfg.cb.on_dtmf_digit(call_id, digit); 788 } 789 } 790 791 792 pj_status_t pjsua_media_channel_update(pjsua_call_id call_id, 793 pjmedia_sdp_session *local_sdp, 794 pjmedia_sdp_session *remote_sdp) 795 { 796 int prev_media_st = 0; 797 pjsua_call *call = &pjsua_var.calls[call_id]; 798 pjmedia_session_info sess_info; 799 pjmedia_port *media_port; 800 pj_str_t port_name; 801 char tmp[PJSIP_MAX_URL_SIZE]; 802 pj_status_t status; 803 804 /* Destroy existing media session, if any. */ 805 prev_media_st = call->media_st; 806 stop_media_session(call->index); 807 808 /* Create media session info based on SDP parameters. 809 * We only support one stream per session at the moment 810 */ 811 status = pjmedia_session_info_from_sdp( call->inv->dlg->pool, 812 pjsua_var.med_endpt, 813 1,&sess_info, 814 local_sdp, remote_sdp); 815 if (status != PJ_SUCCESS) 816 return status; 817 818 819 /* Check if media is put on-hold */ 820 if (sess_info.stream_cnt == 0 || 821 sess_info.stream_info[0].dir == PJMEDIA_DIR_NONE) 822 { 823 824 /* Determine who puts the call on-hold */ 825 if (prev_media_st == PJSUA_CALL_MEDIA_ACTIVE) { 826 if (pjmedia_sdp_neg_was_answer_remote(call->inv->neg)) { 827 /* It was local who offer hold */ 828 call->media_st = PJSUA_CALL_MEDIA_LOCAL_HOLD; 829 } else { 830 call->media_st = PJSUA_CALL_MEDIA_REMOTE_HOLD; 831 } 832 } 833 834 call->media_dir = PJMEDIA_DIR_NONE; 835 836 /* Shutdown transport */ 837 /* No need because we need keepalive? */ 838 839 } else { 840 841 /* Start ICE */ 842 if (pjsua_var.media_cfg.enable_ice) { 843 status = pjmedia_ice_start_ice(call->med_tp, call->inv->pool, 844 remote_sdp); 845 if (status != PJ_SUCCESS) 846 return status; 847 } 848 849 /* Override ptime, if this option is specified. */ 850 if (pjsua_var.media_cfg.ptime != 0) { 851 sess_info.stream_info[0].param->setting.frm_per_pkt = (pj_uint8_t) 852 (pjsua_var.media_cfg.ptime / sess_info.stream_info[0].param->info.frm_ptime); 853 if (sess_info.stream_info[0].param->setting.frm_per_pkt == 0) 854 sess_info.stream_info[0].param->setting.frm_per_pkt = 1; 855 } 856 857 /* Disable VAD, if this option is specified. */ 858 if (pjsua_var.media_cfg.no_vad) { 859 sess_info.stream_info[0].param->setting.vad = 0; 860 } 861 862 863 /* Optionally, application may modify other stream settings here 864 * (such as jitter buffer parameters, codec ptime, etc.) 865 */ 866 sess_info.stream_info[0].jb_init = pjsua_var.media_cfg.jb_init; 867 sess_info.stream_info[0].jb_min_pre = pjsua_var.media_cfg.jb_min_pre; 868 sess_info.stream_info[0].jb_max_pre = pjsua_var.media_cfg.jb_max_pre; 869 sess_info.stream_info[0].jb_max = pjsua_var.media_cfg.jb_max; 870 871 /* Create session based on session info. */ 872 status = pjmedia_session_create( pjsua_var.med_endpt, &sess_info, 873 &call->med_tp, 874 call, &call->session ); 875 if (status != PJ_SUCCESS) { 876 return status; 877 } 878 879 /* If DTMF callback is installed by application, install our 880 * callback to the session. 881 */ 882 if (pjsua_var.ua_cfg.cb.on_dtmf_digit) { 883 pjmedia_session_set_dtmf_callback(call->session, 0, 884 &dtmf_callback, 885 (void*)(call->index)); 886 } 887 888 /* Get the port interface of the first stream in the session. 889 * We need the port interface to add to the conference bridge. 890 */ 891 pjmedia_session_get_port(call->session, 0, &media_port); 892 893 894 /* 895 * Add the call to conference bridge. 896 */ 897 port_name.ptr = tmp; 898 port_name.slen = pjsip_uri_print(PJSIP_URI_IN_REQ_URI, 899 call->inv->dlg->remote.info->uri, 900 tmp, sizeof(tmp)); 901 if (port_name.slen < 1) { 902 port_name = pj_str("call"); 903 } 904 status = pjmedia_conf_add_port( pjsua_var.mconf, call->inv->pool, 905 media_port, 906 &port_name, 907 (unsigned*)&call->conf_slot); 908 if (status != PJ_SUCCESS) { 909 return status; 910 } 911 912 /* Call's media state is active */ 913 call->media_st = PJSUA_CALL_MEDIA_ACTIVE; 914 call->media_dir = sess_info.stream_info[0].dir; 915 } 916 917 /* Print info. */ 918 { 919 char info[80]; 920 int info_len = 0; 921 unsigned i; 922 923 for (i=0; i<sess_info.stream_cnt; ++i) { 924 int len; 925 const char *dir; 926 pjmedia_stream_info *strm_info = &sess_info.stream_info[i]; 927 928 switch (strm_info->dir) { 929 case PJMEDIA_DIR_NONE: 930 dir = "inactive"; 931 break; 932 case PJMEDIA_DIR_ENCODING: 933 dir = "sendonly"; 934 break; 935 case PJMEDIA_DIR_DECODING: 936 dir = "recvonly"; 937 break; 938 case PJMEDIA_DIR_ENCODING_DECODING: 939 dir = "sendrecv"; 940 break; 941 default: 942 dir = "unknown"; 943 break; 944 } 945 len = pj_ansi_sprintf( info+info_len, 946 ", stream #%d: %.*s (%s)", i, 947 (int)strm_info->fmt.encoding_name.slen, 948 strm_info->fmt.encoding_name.ptr, 949 dir); 950 if (len > 0) 951 info_len += len; 952 } 953 PJ_LOG(4,(THIS_FILE,"Media updates%s", info)); 954 } 955 956 return PJ_SUCCESS; 563 957 } 564 958
Note: See TracChangeset
for help on using the changeset viewer.