VOIP Media/CODEC 协议组

本文介绍了音视频领域的关键技术标准,包括G.7xx系列音频压缩协议、H.261/H.263/H.264等视频编码标准及RTP/RTCP传输协议,为读者提供了对音视频编解码技术的基础理解。
pj_status_t pjsua_media_channel_create_sdp(pjsua_call_id call_id, pj_pool_t *pool, const pjmedia_sdp_session *rem_sdp, pjmedia_sdp_session **p_sdp, int *sip_status_code, pj_bool_t createFwRule) { enum { MAX_MEDIA = 1 }; pjmedia_sdp_session *sdp; pjmedia_transport_info tpinfo; pjsua_call *call = &pjsua_var.calls[call_id]; pjmedia_sdp_neg_state sdp_neg_state = PJMEDIA_SDP_NEG_STATE_NULL; pj_status_t status; /*ycw-pjsip-codec*/ #if 1 pjsua_acc* acc = NULL; unsigned i; pj_str_t* codec = NULL; pjsua_codec_info c[32]; unsigned count = PJ_ARRAY_SIZE(c);/*ycw-pjsip. Must init, or there would be a error.*/ #endif pj_bool_t offer_has_telephone_evt = PJ_FALSE; # ifdef SUPPORT_METABOLIC_MEDIA_PORT pj_uint16_t medport; pj_bool_t portAvaible = PJ_TRUE; # endif #if defined(PJSIP_HAS_FIREWALL_FILTER) && PJSIP_HAS_FIREWALL_FILTER!=0 char localIp[CMSIP_STR_40]; pj_uint16_t localPort; pj_uint16_t localRtcpPort; pj_str_t ip; PJ_FIREWALL_RULE* pFwRule = NULL; #endif pj_str_t *pBoundIp = &pjsua_var.BoundIp; int family = AF_INET; # if defined(SUPPORT_IPCALL_NO_ACCOUNT) && SUPPORT_IPCALL_NO_ACCOUNT!=0 if (call->acc_id>=0) { # endif acc = &pjsua_var.acc[call->acc_id]; # if defined(SUPPORT_IPCALL_NO_ACCOUNT) && SUPPORT_IPCALL_NO_ACCOUNT!=0 } # endif CMSIP_PRINT("--call[%d],account[%d], rem_sdp[%p]", call_id, call->acc_id, rem_sdp); /* Return error if media transport has not been created yet * (e.g. application is starting) */ if (call->med_tp == NULL) { return PJ_EBUSY; } /*ycw-pjsip-codec*/ if ( # if defined(INCLUDE_PSTN_GATEWAY) (PJ_TRUE == call->isPstn) # else 0 # endif || # if (defined(SUPPORT_FAX_T38) && SUPPORT_FAX_T38!=0) (PJ_TRUE == call->isFaxPassthrough) # else 0 # endif || # if (defined(PJ_MEDIA_TRANSIT_BY_PJSIP) && 0==PJ_MEDIA_TRANSIT_BY_PJSIP) && \ defined(INCLUDE_USB_VOICEMAIL) PJ_TRUE == call->isUsbVm # else 0 # endif || # if (defined(NUM_VOICEAPP_CHANNELS) && 0!=NUM_VOICEAPP_CHANNELS) PJ_TRUE == call->isVoiceapp # else 0 # endif ) { # if defined(INCLUDE_PSTN_GATEWAY) || \ ((defined(PJ_MEDIA_TRANSIT_BY_PJSIP) && 0==PJ_MEDIA_TRANSIT_BY_PJSIP)&& defined(INCLUDE_USB_VOICEMAIL))\ || (defined(SUPPORT_FAX_T38) && SUPPORT_FAX_T38!=0) || (defined(NUM_VOICEAPP_CHANNELS) && 0!=NUM_VOICEAPP_CHANNELS) pjsua_codec_mgr_switch_to_lite(); # endif } else { pjsua_codec_mgr_switch_to_full(); } pjsua_enum_codecs(c, &count); for(i = 0; i < count; ++i) { codec = &c[i].codec_id; status = pjsua_codec_set_priority(codec, PJMEDIA_CODEC_PRIO_NORMAL); if (status != PJ_SUCCESS) { pjsua_perror(THIS_FILE, "Error reset codecs' priority!", status); return status; } } # if defined(SUPPORT_IPCALL_NO_ACCOUNT) && SUPPORT_IPCALL_NO_ACCOUNT!=0 if (acc) { # endif CMSIP_PRINT("------------haha,I can use account(%d)---", acc->index); for (i = 0, count = 0; i < acc->cfg.codec_cnt; ++i) { codec = &acc->cfg.codecs[i]; if (PJ_TRUE == pjsua_codec_mgr_codec_is_exist(codec)) { status = pjsua_codec_set_priority(codec, PJMEDIA_CODEC_PRIO_HIGHEST - i); if (status != PJ_SUCCESS) { pjsua_perror(THIS_FILE, "Error reset codecs' priority!", status); return status; } ++count; } } # if defined(SUPPORT_IPCALL_NO_ACCOUNT) && SUPPORT_IPCALL_NO_ACCOUNT!=0 } # endif if (rem_sdp && rem_sdp->media_count != 0) { pj_bool_t srtp_active; #if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0) # if defined(SUPPORT_IPCALL_NO_ACCOUNT) && SUPPORT_IPCALL_NO_ACCOUNT!=0 if (acc) { # endif srtp_active = pjsua_var.acc[call->acc_id].cfg.use_srtp; # if defined(SUPPORT_IPCALL_NO_ACCOUNT) && SUPPORT_IPCALL_NO_ACCOUNT!=0 } else { srtp_active = PJ_FALSE; } # endif #else srtp_active = PJ_FALSE; #endif call->audio_idx = find_audio_index(rem_sdp, srtp_active); if (call->audio_idx == -1) { /* No audio in the offer. We can't accept this */ PJ_LOG(4,(THIS_FILE, "Unable to accept SDP offer without audio for call %d", call_id)); return PJMEDIA_SDP_EINMEDIA; } CMSIP_PRINT("---select Media Index[%d] for call[%d]", call->audio_idx, call->index); } /* Media index must have been determined before */ pj_assert(call->audio_idx != -1); /* Create media if it's not created. This could happen when call is * currently on-hold */ if (call->med_tp_st == PJSUA_MED_TP_IDLE) { /*ycw-pjsip:�����Ҫ��̬�������䣬���������ʵ��*/ pjsip_role_e role; role = (rem_sdp ? PJSIP_ROLE_UAS : PJSIP_ROLE_UAC); status = pjsua_media_channel_init(call_id, role, call->secure_level, pool, rem_sdp, sip_status_code); if (status != PJ_SUCCESS) { return status; } } /* Get SDP negotiator state */ if (call->inv && call->inv->neg) { sdp_neg_state = pjmedia_sdp_neg_get_state(call->inv->neg); } /* Get media socket info */ pjmedia_transport_info_init(&tpinfo); # ifdef SUPPORT_METABOLIC_MEDIA_PORT #ifdef INCLUDE_VOIP_SUPPORT_IPV6 if (pjsua_var.BoundIp6.slen <= 0 || !strncmp(pjsua_var.BoundIp6.ptr, "::", 2)) { CMSIP_PRINT("-------use IPv4--------"); family = pj_AF_INET(); pBoundIp = &pjsua_var.BoundIp; } else { CMSIP_PRINT("-------use IPv6--------"); family = pj_AF_INET6(); pBoundIp = &pjsua_var.BoundIp6; } #endif for (i = 0; i < PJMEDIA_PORT_TEST_COUNT; ++i) { medport = pjmedia_endpt_get_mediaPort(pjsua_var.med_endpt); CMSIP_PRINT("-------Media port is (%d)----", medport); pjmedia_endpt_set_mediaPort(pjsua_var.med_endpt); /*test RTP media port*/ status = pjmedia_endpt_test_media_port(*pBoundIp, medport, &portAvaible, family); if (PJ_FALSE==portAvaible && EADDRINUSE == errno) { CMSIP_PRINT("----address is already used---------"); errno = 0; continue; } else if (PJ_SUCCESS != status) { CMSIP_PRINT("--------test media port error----------"); return status; } /*test RTCP media port*/ status = pjmedia_endpt_test_media_port(*pBoundIp, (medport+1), &portAvaible, family); if (PJ_FALSE==portAvaible && EADDRINUSE == errno) { CMSIP_PRINT("-------address is already used-------"); errno = 0; continue; } else if (PJ_SUCCESS != status) { CMSIP_PRINT("----------test media port error-----------"); return status; } else { break; } } if (i >= PJMEDIA_PORT_TEST_COUNT) { CMSIP_PRINT("--------test media port error----------"); return status; } pjmedia_transport_udp_set_mediaPort(call->med_tp, medport); # endif pjmedia_transport_get_info(call->med_tp, &tpinfo); #if defined(PJSIP_HAS_FIREWALL_FILTER) && PJSIP_HAS_FIREWALL_FILTER!=0 if (createFwRule) { for (i = 0; i < PJ_ARRAY_SIZE(call->fwRule); ++i) { CMSIP_PRINT("--------ready to delete iptables rule--------"); pFwRule = &call->fwRule[i]; if (pFwRule->destination.slen > 0 && pFwRule->dport > 0) { pj_firewall_set_rule_accept(PJ_FIREWALLCFG_DEL, PJ_TRANSPORT_UDP, &pFwRule->destination, NULL, pFwRule->dport, NULL, NULL, -1, pj_firewall_get_fwtype(pFwRule->family) #ifdef INCLUDE_VOIP_SUPPORT_IPV6 , pFwRule->family #endif /* INCLUDE_VOIP_SUPPORT_IPV6 */ , pjsua_var.tcMark ); } } pjmedia_transport_udp_local_info(call->med_orig, localIp, &localPort, &localRtcpPort, &family); ip = pj_str(localIp); CMSIP_PRINT("-----add iptables rule(dstIp(%s), localPort(%d), localRtcpPort(%d))", localIp, localPort, localRtcpPort); #ifdef INCLUDE_VOIP_SUPPORT_IPV6 if (AF_INET == family) { #endif /* INCLUDE_VOIP_SUPPORT_IPV6 */ /*����DMZ������ʱ������Է���rtp�ȵ����ʹ�ñ�������DUT VOIP��rtp���ݰ�֮��ֱ�� ��DMZ��iptables����ת��������DUT VOIP�޷����յ����ݰ�������������Ҫ�ڷ���INVITE֮ ǰ�Ϳ�����Ӧ�˿ڡ�by yuchuwei*/ /*now, only support UDP*/ status = pj_firewall_set_rule_accept(PJ_FIREWALLCFG_ADD, PJ_TRANSPORT_UDP, &ip, NULL, localPort, NULL, NULL, -1, pjsua_var.fwType #ifdef INCLUDE_VOIP_SUPPORT_IPV6 , AF_INET #endif /* INCLUDE_VOIP_SUPPORT_IPV6 */ , pjsua_var.tcMark); if (status != PJ_SUCCESS) { pjsua_perror(THIS_FILE, "Error create Netfilter rule", status); return status; } #ifdef INCLUDE_VOIP_SUPPORT_IPV6 } #endif /* INCLUDE_VOIP_SUPPORT_IPV6 */ CMSIP_PRINT("=============add iptables rule end===================================="); pFwRule = &call->fwRule[0]; memset(pFwRule, 0, sizeof(PJ_FIREWALL_RULE)); pFwRule->protocol = PJ_TRANSPORT_UDP; strcpy(pFwRule->dstBuf, localIp); pFwRule->destination = pj_str(pFwRule->dstBuf); pFwRule->dport = localPort; pFwRule->sport = -1; pFwRule->family = family; status = pj_firewall_set_rule_accept(PJ_FIREWALLCFG_ADD, PJ_TRANSPORT_UDP, &ip, NULL, localRtcpPort, NULL, NULL, -1, pj_firewall_get_fwtype(family) #ifdef INCLUDE_VOIP_SUPPORT_IPV6 , family #endif /* INCLUDE_VOIP_SUPPORT_IPV6 */ , pjsua_var.tcMark); if (status != PJ_SUCCESS) { #ifdef INCLUDE_VOIP_SUPPORT_IPV6 if (AF_INET == family) { #endif /* INCLUDE_VOIP_SUPPORT_IPV6 */ pj_firewall_set_rule_accept(PJ_FIREWALLCFG_DEL, PJ_TRANSPORT_UDP, &ip, NULL, localPort, NULL, NULL, -1, pjsua_var.fwType #ifdef INCLUDE_VOIP_SUPPORT_IPV6 , pj_AF_INET() #endif /* INCLUDE_VOIP_SUPPORT_IPV6 */ , pjsua_var.tcMark); #ifdef INCLUDE_VOIP_SUPPORT_IPV6 } #endif /* INCLUDE_VOIP_SUPPORT_IPV6 */ pjsua_perror(THIS_FILE, "Error create Netfilter rule", status); return status; } CMSIP_PRINT("=============add iptables rule end===================================="); pFwRule = &call->fwRule[1]; memset(pFwRule, 0, sizeof(PJ_FIREWALL_RULE)); pFwRule->protocol = PJ_TRANSPORT_UDP; strcpy(pFwRule->dstBuf, localIp); pFwRule->destination = pj_str(pFwRule->dstBuf); pFwRule->dport = localRtcpPort; pFwRule->sport = -1; pFwRule->family = family; } #endif /* Create SDP */ /*ycw-pjsip.Current only one media*/ if (rem_sdp && rem_sdp->media_count > 0) { int k; pjmedia_sdp_media* m = rem_sdp->media[0]; pjmedia_sdp_attr* attr = NULL; pjmedia_sdp_rtpmap rtpmap; for (k = 0; k < m->desc.fmt_count; ++k) { attr = pjmedia_sdp_media_find_attr2(m, "rtpmap", &m->desc.fmt[k]); if (!attr) continue; pjmedia_sdp_attr_get_rtpmap(attr, &rtpmap); if (!pj_stricmp2(&rtpmap.enc_name, "telephone-event")) { offer_has_telephone_evt = PJ_TRUE; } } } /*ycw-pjsip-ptime*/ #if 0 status = pjmedia_endpt_create_sdp(pjsua_var.med_endpt, pool, MAX_MEDIA, &tpinfo.sock_info, &sdp); #else status = pjmedia_endpt_create_sdp(pjsua_var.med_endpt, pool, MAX_MEDIA, &tpinfo.sock_info, # if defined(SUPPORT_IPCALL_NO_ACCOUNT) && SUPPORT_IPCALL_NO_ACCOUNT!=0 acc ? acc->cfg.ptime : PJSUA_DEFAULT_LOCAL_PTIME, # else acc->cfg.ptime, # endif offer_has_telephone_evt, &sdp); #endif if (status != PJ_SUCCESS) { if (sip_status_code) { *sip_status_code = 500; } return status; } /* If we're answering or updating the session with a new offer, * and the selected media is not the first media * in SDP, then fill in the unselected media with with zero port. * Otherwise we'll crash in transport_encode_sdp() because the media * lines are not aligned between offer and answer. */ if (call->audio_idx != 0 && (rem_sdp || sdp_neg_state==PJMEDIA_SDP_NEG_STATE_DONE)) { unsigned i; const pjmedia_sdp_session *ref_sdp = rem_sdp; if (!ref_sdp) { /* We are updating session with a new offer */ status = pjmedia_sdp_neg_get_active_local(call->inv->neg, &ref_sdp); pj_assert(status == PJ_SUCCESS); } CMSIP_PRINT("--ref sdp's media count[%d]", ref_sdp->media_count); for (i=0; i<ref_sdp->media_count; ++i) { const pjmedia_sdp_media *ref_m = ref_sdp->media[i]; pjmedia_sdp_media *m; if ((int)i == call->audio_idx) { continue; } m = pjmedia_sdp_media_clone_deactivate(pool, ref_m); if (i==sdp->media_count) { sdp->media[sdp->media_count++] = m; } else { pj_array_insert(sdp->media, sizeof(sdp->media[0]), sdp->media_count, i, &m); ++sdp->media_count; } } } #if SUPPORT_STUN /* Add NAT info in the SDP */ if (pjsua_var.ua_cfg.nat_type_in_sdp) { pjmedia_sdp_attr *a; pj_str_t value; char nat_info[80]; value.ptr = nat_info; if (pjsua_var.ua_cfg.nat_type_in_sdp == 1) { value.slen = pj_ansi_snprintf(nat_info, sizeof(nat_info), "%d", pjsua_var.nat_type); } else { const char *type_name = pj_stun_get_nat_name(pjsua_var.nat_type); value.slen = pj_ansi_snprintf(nat_info, sizeof(nat_info), "%d %s", pjsua_var.nat_type, type_name); } a = pjmedia_sdp_attr_create(pool, "X-nat", &value); pjmedia_sdp_attr_add(&sdp->attr_count, sdp->attr, a); } #endif /* SUPPORT_STUN */ /* Give the SDP to media transport */ status = pjmedia_transport_encode_sdp(call->med_tp, pool, sdp, rem_sdp, call->audio_idx); if (status != PJ_SUCCESS) { if (sip_status_code) { *sip_status_code = PJSIP_SC_NOT_ACCEPTABLE; } return status; } char buf[16]; int len = snprintf(buf,"%d", medport); int fd = open("/proc/voip_port", O_WRONLY); if (fd > 0 ) { write(fd, buf, len); close(fd); } else { close(fd); CMSIP_PRINT("--------open /proc/voip_port error----------"); } #if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0) /* Check if SRTP is in optional mode and configured to use duplicated * media, i.e: secured and unsecured version, in the SDP offer. */ if (!rem_sdp && acc && pjsua_var.acc[call->acc_id].cfg.use_srtp == PJMEDIA_SRTP_OPTIONAL && pjsua_var.acc[call->acc_id].cfg.srtp_optional_dup_offer) { unsigned i; for (i = 0; i < sdp->media_count; ++i) { pjmedia_sdp_media *m = sdp->media[i]; /* Check if this media is unsecured but has SDP "crypto" * attribute. */ if (pj_stricmp2(&m->desc.transport, "RTP/AVP") == 0 && pjmedia_sdp_media_find_attr2(m, "crypto", NULL) != NULL) { if (i == (unsigned)call->audio_idx && sdp_neg_state == PJMEDIA_SDP_NEG_STATE_DONE) { /* This is a session update, and peer has chosen the * unsecured version, so let's make this unsecured too. */ pjmedia_sdp_media_remove_all_attr(m, "crypto"); } else { /* This is new offer, duplicate media so we'll have * secured (with "RTP/SAVP" transport) and and unsecured * versions. */ pjmedia_sdp_media *new_m; /* Duplicate this media and apply secured transport */ new_m = pjmedia_sdp_media_clone(pool, m); pj_strdup2(pool, &new_m->desc.transport, "RTP/SAVP"); /* Remove the "crypto" attribute in the unsecured media */ pjmedia_sdp_media_remove_all_attr(m, "crypto"); /* Insert the new media before the unsecured media */ if (sdp->media_count < PJMEDIA_MAX_SDP_MEDIA) { pj_array_insert(sdp->media, sizeof(new_m), sdp->media_count, i, &new_m); ++sdp->media_count; ++i; } } } } } #endif /* Update currently advertised RTP source address */ pj_memcpy(&call->med_rtp_addr, &tpinfo.sock_info.rtp_addr_name, sizeof(pj_sockaddr)); *p_sdp = sdp; return PJ_SUCCESS; }/src/pjsua-lib/pjsua_media.c:2169:34: error: 'medport' undeclared (first use in this function) int len = snprintf(buf,"%d", medport); ^ ../src/pjsua-lib/pjsua_media.c:2169:34: note: each undeclared identifier is reported only once for each function it appears in ../src/pjsua-lib/pjsua_media.c:2169:28: warning: passing argument 2 of 'snprintf' makes integer from pointer without a cast int len = snprintf(buf,"%d", medport); ^ In file included from ../../pjlib/include/pj/compat/string.h:39:0, from ../../pjlib/include/pj/string.h:29, from ../include/pjsip/sip_transport_tls.h:30, from ../include/pjsip.h:45,
最新发布
10-21
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值