state = GetEndptState( lineId ); //获取ENDPT对象
//收发模式校验
if (!IsCnxModeSupported(cnxParam->mode, dspNum))
return ( EPSTATUS_UNSUPPORTED_MODE );
if ( state->endptType == EPTYPE_PSTN ) //FXO口类型
if( state->cnx[PRIMARY_CNX_INDEX] ) //有资源对象
//查找一个非轻量级的资源对象
cnx = state->cnx[PRIMARY_CNX_INDEX];
while ( cnx->bLiteWeight )
cnx = GetNewSecondaryCnxState( dspNum );
state->cnx[PRIMARY_CNX_INDEX] = cnx;
cnxIndex = PRIMARY_CNX_INDEX;
//获取一个空闲资源对象
for( cnxIndex = PRIMARY_CNX_INDEX; cnxIndex < VRG_ENDPT_CFG_MAX_CNX_PER_ENDPT; cnxIndex++ )
if (state->cnx[cnxIndex] &&(state->cnx[cnxIndex]->cnxId == CNX_IDLE))
cnx = state->cnx[cnxIndex];
break;
//如果没有获取到资源对象,则重新分配一个,并进行线路对象绑定
if (cnxIndex == VRG_ENDPT_CFG_MAX_CNX_PER_ENDPT)
cnx = GetNewSecondaryCnxState( dspNum );
for( cnxIndex = PRIMARY_CNX_INDEX; cnxIndex < VRG_ENDPT_CFG_MAX_CNX_PER_ENDPT;
cnxIndex++ )
if (state->cnx[cnxIndex] == 0)
state->cnx[cnxIndex] = cnx;
break;
//复位CNX状态
cnx->cnxId = cnxId; //资源ID
cnx->lineId = lineId; //线路ID
cnx->firstValidRTPPkt = 1; //标记需要检测第一个RTP
cnx->bSBDisconnect = VRG_FALSE; //标记线路VHD与资源VHD没有断开
cnx->bCngDetEnabled = VRG_TRUE; //标记检测CNG
cnx->bNotifyFaxCall = VRG_FALSE; //标记还没有通知过T38事件
cnx->localSsrc = cnxParam->localSsrc; //从用户侧获取SSRC起始序号
//通知监控任务,有CNX状态对象激活
hbUpdatePatientEndptId( cnx->cnxStateHBId, lineId );
hbUpdatePatientState( cnx->cnxStateHBId, HBSTATE_ACTIVE );
//将当前资源VHD对象与线路VHD对象及其它相关资源VHD对象进行关联
if ( state->endptType == EPTYPE_FXS )
//将VHD对象进行关联,这里只介绍一下会议模式,其它模式类似
UpdateSBMasks( state->cnx[cnxIndex], cnxParam->mode);
endptState = GetEndptState( cnx->lineId ); //获取对应线路对象
//如果模式为环回测试,则将模式更正为发送接收模式
if (endptState->testMode == TESTMODE_PACKETLOOPBACK)
mode = EPCNXMODE_SNDRX;
//记载线路号及老的接收发送掩码
endptNum = endptState->endptNum;
oldinMask = cnx->inMask;
oldoutMask = cnx->outMask;
//只介绍一下会议模式
switch( mode )
case EPCNXMODE_CONF:
//标记当前资源VHD对象与线路VHD对象收发双向需要进行关联
cnx->inMask = ( 1 << endptNum );
cnx->outMask = ( 1 << endptNum );
//查找该线路对象上有设置为会议模式的其它资源VHD(非当前资源VHD),
//并标记两个资源VHD对象需要收发双向关联。
for ( i = 0; i < VRG_ENDPT_CFG_MAX_CNX_PER_ENDPT; i++ )
if (( endptState->cnx[i] ) && ( endptState->cnx[i] != cnx ) &&
( endptState->cnx[i]->mode == EPCNXMODE_CONF ))
for ( j = 0; j < VRG_ENDPT_CFG_NUM_CNX; j++ )
if ( vrgCnxState[j].vhdhdl == endptState->cnx[i]->vhdhdl )
cnx->inMask |= ( 1 << j << vrgEndptGetNumEndpoints() );
cnx->outMask |= ( 1 << j << vrgEndptGetNumEndpoints() );
break;
//如果当前模式非测试、编码转换模式时,则允许线路VHD对象与当前资源
//VHD对象进行发送关联。
//注释上说是为了在当前连接上检测传真、MODEM音
if ( (mode != EPCNXMODE_TEST) && (mode != EPCNXMODE_TRANSCODE) )
cnx->inMask |= ( 1 << endptNum );
//记载当前值与老值是否相同
inMaskDiff = oldinMask ^ cnx->inMask;
outMaskDiff = oldoutMask ^ cnx->outMask;
//设置关联
SetupSB(cnx->vhdhdl, cnx->inMask, inMaskDiff, cnx->outMask, outMaskDiff);
//遍列整个线路及资源掩码位,这里所有线路对象位在前,所以资源对象位
//在后。位值如下:
// 0 1 2 3 4 5 6 7
// line0 line1 cnx0 cnx1 cnx2 cnx3 cnx4 cnx5……
n = VRG_ENDPT_CFG_NUM_CNX + vrgEndptGetNumEndpoints();
for (i = 0; i < n; i++)
bitmask = 1 << i;
if (bitmask & outMaskDiff) //判断当前发送位是否变动
//标记当前发送侧是断开还是连接
bConnect = ( bitmask & outMask ) ? VRG_TRUE : VRG_FALSE;
//设置VHD对象与当前资源VHD对象接收方向单向关联。
//如果当前处理的是线路对象,将标记当前资源对象关联的对象为线
//路对象,让线路对象的顶部与当前资源对象进行连接。如果当前处
//理的是资源对象,将标记当前资源对象关联的对象为资源对象,让
//资源对象的底部与当前资源对象进行连接。这里列举一下会议模式
//下的情况,会议会有一个线路VHD对象及一个资源VHD对象与当
//前资源VHD对象进行关联,关联的图示如:
// CnxVhd CnxVhd
// |---| |---|
// |---|--------------|---|--
// |
// |---| LineVhd
// |---|
if ( i < vrgEndptGetNumEndpoints() )
dstHandle = vrgEndpt[i].lineVhdHdl;
dstInterface = HAPI_SWB_TOS;
else
dstHandle = vrgCnxState[ i - vrgEndptGetNumEndpoints() ].vhdhdl;
dstInterface = HAPI_SWB_BOS;
//设置上面的VHD对象与当前资源VHD对象的底部单向关联
hdspRmSwitchBoardConnect( vhdhdl, HAPI_SWB_BOS, dstHandle,
dstInterface, HAPI_SWB_SIMPLEX, bConnect ) )
//设置VHD对象与当前资源VHD对象发送方向单向关联。和上面接
//收代码一样,这里不写了。
//根据上层设置控制回声开关
if (cnxParam->echocancel)
ecanProcessStm(state, ECANEVT_CRCX_ON);
else
ecanProcessStm(state, ECANEVT_CRCX_OFF);
if(cnxParam->JBFreeze) //上层设置静态JB
newVoiceJBFixed = cnxParam->JBFreeze;
if(cnxParam->JBMax < 0) cnxParam->JBMax = 0;
if(cnxParam->JBMax > 180) cnxParam->JBMax = 180;
if(cnxParam->JBTarget < 0) cnxParam->JBTarget = 0;
if(cnxParam->JBTarget > 180) cnxParam->JBTarget = 180;
newVoiceJBMin = 0;
newVoiceJBMax = cnxParam->JBMax;
newVoiceJBTarget = cnxParam->JBTarget;
newDataJBTarget = cnxParam->JBTarget;
else //否则为动态JB
newDataJBTarget = cnxParam->JBTarget;
//如果当前有JB值变动,则更新DSP,并保存最新值
if(( !is_JBauto && !newVoiceJBFixed )|| ( newVoiceJBFixed != cnx->vrgVoiceJBFixed ) ||
( newVoiceJBMin != cnx->vrgVoiceJBMin ) || ( newVoiceJBMax != cnx->vrgVoiceJBMax ) ||
( newVoiceJBTarget != cnx->vrgVoiceJBTarget ) || ( newDataJBTarget != cnx->vrgDataJBTarget )
result = hdspVhdSetJitterBuffer( cnx->vhdhdl, newVoiceJBFixed, newVoiceJBMin,
newVoiceJBMax, newVoiceJBTarget, newDataJBTarget, cnx->ajcCustomReg );
cnx->vrgVoiceJBFixed = newVoiceJBFixed;
cnx->vrgVoiceJBMin = newVoiceJBMin;
cnx->vrgVoiceJBMax = newVoiceJBMax;
cnx->vrgVoiceJBTarget = newVoiceJBTarget;
cnx->vrgDataJBTarget = newDataJBTarget;
//从配置中读取是否检测CNG信号,并根据结果设置网络模块寄存器变量
netregs = cnx->netRegs;
Provision( state->endptArchive, EPPROV_FaxDetection, &provCngDetEnabled );
if ( provCngDetEnabled == MIB_CNG_DET_ENABLED )
netregs.hsxNetOptions &= ~HSNET_NET_OPTION_IGNORE_CNG_ING_EVT;
cnx->bCngDetEnabled = VRG_TRUE;
else
netregs.hsxNetOptions |= HSNET_NET_OPTION_IGNORE_CNG_ING_EVT;
cnx->bCngDetEnabled = VRG_FALSE;
//初始化bell103功能关闭,检测CIS/DIS信号
cnx->bBell103Enabled = VRG_FALSE;
netregs.hsxNetOptions |= HSNET_NET_OPTION_CDIS;
//去除V18检测、BELL103检测、自定义声音检测
netregs.hsxCallDOptions &= ~( HSNET_CDIS_OPTION_V18ACTIVE | HSNET_CDIS_OPTION_BELL103ACTIVE | HSNET_CDIS_OPTION_CUSTOMTONEACTIVE );
//当前配置里没有EPPROV_ToneDetectionCtrl项,status返回不成功
status = Provision( state->endptArchive, EPPROV_ToneDetectionCtrl, &provToneDetCtrl );
//status返回不成功,这里确认哪些事件检测代码忽略
if ( status == EPSTATUS_SUCCESS )
{
……
}
//设置编码自切换
if (cnxParam->autoEncoder == EPAUTOENC_ON)
netregs.hsxNetOptions |= HSNET_NET_OPTION_AUTO_ENC_SWITCH;
else
netregs.hsxNetOptions &= ~HSNET_NET_OPTION_AUTO_ENC_SWITCH;
//如果上面设置的事件检测相关参数有变更,则设置DSP相关项
if ( (netregs.hsxCallDOptions != cnx->netRegs.hsxCallDOptions) || (netregs.hsxNetOptions != cnx->netRegs.hsxNetOptions) )
hdspSendCmdDataAsync( cnx->vhdhdl, HAPINET_CONFIG_SETREGS,
HSCMDEXTDATA_ASYNC, sizeof( netregs ), &netregs );
cnx->netRegs.hsxCallDOptions = netregs.hsxCallDOptions;
cnx->netRegs.hsxNetOptions = netregs.hsxNetOptions;
//设置2833配置
cnx->digitRelayType = cnxParam->digitRelayType;
//初始化RTP模块寄存器变量
InitRtpServiceRegisters( state->cnx[cnxIndex] );
//从DSP获取RTP模块寄存器值
status = hdspSendCmdData( cnx->vhdhdl, HAPINET_RTP_GETREGS, HSCMDRESP,
sizeof(rtpRegs), &rtpRegs );
status = hdspSendCmdData( cnx->vhdhdl, HAPI_RTP_GETREGS2_CMD, HSCMDRESP,
sizeof(rtpRegs2), &rtpRegs2 );
//在接收数据包时检测到错误,都上报给主机
rtpRegs.configFlags |= HAPI_RTP_EGRESS_REPORT_ERROR_TO_HOST_ENABLE_MASK;
//生成RTCP包并发送到网络
rtpRegs.configFlags |= HAPI_RTP_INGRESS_SEND_RTCP_PACKETS_ENABLE_MASK;
//发送RTCP包事件不上报给主机
rtpRegs.configFlags &= ~HAPI_RTP_INGRESS_SEND_RTCP_PACKETS_TO_HOST_ENABLE_MASK;
//接收RTCP包事件不上报给主机
rtpRegs.configFlags &= ~HAPI_RTP_EGRESS_SEND_RTCP_PACKETS_TO_HOST_ENABLE_MASK;
//不检测RTP包中SSRC字段冲突
rtpRegs.configFlags &= ~HAPI_RTP_EGRESS_CHECK_FOR_SSRC_COLLISION_MASK;
//忽略接收的2198包中冗错部分处理
rtpRegs.configFlags |= HAPI_RTP_EGRESS_DROP_REDUNDANT_PAYLOAD_MASK;
//所有发送的非2198包,不按照2198包进行处理
rtpRegs.configFlags &= ~HAPI_RTP_INGRESS_RFC2198_ENABLE_MASK;
//生成RTCP BYE包并发送到网络
rtpRegs.configFlags |= HAPI_RTP_INGRESS_GENERATE_RTCP_BYE_PACKET_ENABLE_MASK;
//收到的RTCP BYE包不上报到主机
rtpRegs.configFlags &= ~HAPI_RTP_EGRESS_ACCEPT_RTCP_BYE_PACKET_ENABLE_MASK;
//关闭QOS相关事件
rtpRegs.configFlags &= ~HAPI_RTP_QOS_EVENT_ENABLE_MASK;
//在没有激活语音之前,先停止RTP发送、RTP接收、RTCP发送
rtpRegs2.configFlags2 |= HAPI_RTP_INGRESS_SEND_RTP_PACKETS_DISABLE_MASK;
rtpRegs2.configFlags2 |= HAPI_RTP_EGRESS_PROCESS_RTP_PACKETS_DISABLE_MASK;
rtpRegs.configFlags &= ~HAPI_RTP_INGRESS_SEND_RTCP_XR_PACKETS_ENABLE_MASK;
//关闭V152及2198冗余
rtpRegs.configFlags &= ~HAPI_RTP_VBD_V152_ENABLE_MASK;
rtpRegs.configFlags &= ~HAPI_RTP_VBD_V152_INGRESS_RFC2198_ENABLE_MASK;
//如果上层设置ssrc值,则设置SSRC使用用户自定义
if ( cnx->localSsrc != 0 )
rtpRegs.configFlags |= HAPI_RTP_USE_USER_DEFINED_SSRC_MASK;
//设置2833声音能量大小
state = GetEndptState( cnx->lineId );
Provision( state->endptArchive, EPPROV_Rfc2833ToneLevel, &nteToneLevel );
rtpRegs.nteToneLevel = nteToneLevel;
//开启三位声音冗余?不明白什么意思
rtpRegs2.configFlags2 |= HAPI_RTP_TONE_TRIPLICATE_REDUNDANCY_MASK;
//当前配置不支持GR303,关闭GR303及保活机制
if ( state->bGR303Support )
rtpRegs2.configFlags2 |= HAPI_RTP_GR303_NUERA_ENABLE_MASK;
rtpRegs2.configFlags2 |= HAPI_RTP_RFC2833_KEEP_ALIVE_ENABLE_MASK;
else
rtpRegs2.configFlags2 &= ~HAPI_RTP_GR303_NUERA_ENABLE_MASK;
rtpRegs2.configFlags2 &= ~HAPI_RTP_RFC2833_KEEP_ALIVE_ENABLE_MASK;
//如果上层设置2833类型为EPDTMFRFC2833_SUBTRACT,则在语音包中去除DTMF
//按键音
if ( cnx->digitRelayType == EPDTMFRFC2833_SUBTRACT )
rtpRegs2.configFlags2 |= HAPI_RTP_SUBTRACT_DTMF_ENABLE_MASK;
else
rtpRegs2.configFlags2 &= ~HAPI_RTP_SUBTRACT_DTMF_ENABLE_MASK;
//将上面所有设置的值重新设置到DSP
hdspSendCmdDataAsync( cnx->vhdhdl, HAPINET_RTP_SETREGS, HSCMDEXTDATA_ASYNC,
sizeof( rtpRegs ), &rtpRegs);
hdspSendCmdAsync( cnx->vhdhdl, HAPI_RTP_SETREG21_CMD, HSCMDDATA,
OFFSETOF(HAPI_RTP_REGS2, configFlags2), rtpRegs2.configFlags2);
//生成一个RTCP SDES CNAME值,用于整个RTP会话
sprintf( rtpRegsCname, "%d", (int)net_random() );
rtpRegs.cnameLength = strlen(rtpRegsCname);
//保存
cnx->rtpRegs = rtpRegs;
cnx->rtpRegs2 = rtpRegs2;
//设置RTCP RR/SR、设置VBD,第四个参数加密头函数里没用到
SetRtpServiceRegisters( state->cnx[cnxIndex], cnxParam->rtcpXRMode, &cnxParam->vbdparam, cnxParam->secHdrSize );
//如果是T38模式则直接返回
if ( cnx->vhdMode == NETMODE_FAXRELAY )
return;
//根据RTCP XR模式,设置是否发送RTCP SR/RR包,及报告
switch (XRmode)
case EPRTCPXRMODE_ON:
rtpRegs.configFlags |= HAPI_RTP_INGRESS_SEND_RTCP_XR_PACKETS_ENABLE_MASK;
rtpRegs.rtcpXrConfigFlags |= HAPI_RTP_RTCP_XR_GENERATE_VOIP_REPORT;
case EPRTCPXRMODE_NEGOTIATE:
rtpRegs.configFlags |= HAPI_RTP_INGRESS_SEND_RTCP_XR_PACKETS_ENABLE_MASK;
rtpRegs.rtcpXrConfigFlags &= ~HAPI_RTP_RTCP_XR_GENERATE_VOIP_REPORT;
case EPRTCPXRMODE_OFF:
rtpRegs.configFlags&= ~HAPI_RTP_INGRESS_SEND_RTCP_XR_PACKETS_ENABLE_MASK;
rtpRegs.rtcpXrConfigFlags &= ~HAPI_RTP_RTCP_XR_GENERATE_VOIP_REPORT;
//关闭一些RTCP报告项
rtpRegs.rtcpXrConfigFlags &= ~HAPI_RTP_RTCP_XR_GENERATE_LOSS_RLE_REPORT;
rtpRegs.rtcpXrConfigFlags &= ~HAPI_RTP_RTCP_XR_GENERATE_DUPLICATE_RLE_REPORT;
rtpRegs.rtcpXrConfigFlags &=
~HAPI_RTP_RTCP_XR_GENERATE_PACKET_RECEIPT_TIMES_REPORT;
rtpRegs.rtcpXrConfigFlags &=
~HAPI_RTP_RTCP_XR_GENERATE_RECEIVER_REFERENCE_TIME_REPORT;
rtpRegs.rtcpXrConfigFlags &= ~HAPI_RTP_RTCP_XR_GENERATE_DLRR_REPORT;
rtpRegs.rtcpXrConfigFlags &= ~HAPI_RTP_RTCP_XR_GENERATE_STATISTICS_REPORT;
//如果配置了VBD模式
if( (vbdParam->vbdMode & EPVBDMODE_V152) == EPVBDMODE_V152 )
//开启VBD,并设置2198冗余
rtpRegs.configFlags |= HAPI_RTP_VBD_V152_ENABLE_MASK;
switch( vbdParam->vbdRedMode )
case EPVBDRED_ON:
rtpRegs.configFlags |= HAPI_RTP_VBD_V152_INGRESS_RFC2198_ENABLE_MASK;
case EPVBDRED_OFF:
rtpRegs.configFlags &=
~HAPI_RTP_VBD_V152_INGRESS_RFC2198_ENABLE_MASK;
else
//否则关闭VBD及2198冗余
rtpRegs.configFlags &= ~HAPI_RTP_VBD_V152_ENABLE_MASK;
rtpRegs.configFlags &= ~HAPI_RTP_VBD_V152_INGRESS_RFC2198_ENABLE_MASK;
//将上面配置设置到DSP
hdspSendCmdAsync( vhdHdl, HAPI_RTP_SETREG21_CMD, HSCMDDATA,
OFFSETOF(HAPI_RTP_REGS2, configFlags2), rtpRegs2.configFlags2);
hdspSendCmdData( cnx->vhdhdl, HAPINET_RTP_SETREGS, HSCMDEXTDATA_SYNC,
sizeof( rtpRegs ), &rtpRegs);
//保存
cnx->rtpRegs = rtpRegs;
cnx->rtpRegs2 = rtpRegs2;
//初始化RTP状态块
RtpInit( &cnx->rtpstate );
memset( state, 0, sizeof( RTPSTATE ) );
//设置2833编码为无效值
state->sendNtePayloadType = RTP_PAYLOAD_INVALID;
state->recvNtePayloadType = RTP_PAYLOAD_INVALID;
//设置2198编码为无效值
state->sendRedPayloadType = RTP_PAYLOAD_INVALID;
state->recvRedPayloadType = RTP_PAYLOAD_INVALID;
//设置连接选项
SetConnectionOptions( cnx1, cnxParam, VRG_TRUE );
state = GetEndptState( cnx->lineId ); //获取线路对象
//如果本地配置2833,则标记使用2833
if ( (cnxParam->digitRelayType == EPDTMFRFC2833_ENABLED)
|| (cnxParam->digitRelayType == EPDTMFRFC2833_SUBTRACT) )
bEnableDigitRelay = VRG_TRUE;
//如果资源列表中有2833编码,则标记使用2833
for ( i = 0; i < cnxParam->cnxParmList.send.numCodecs; i++ )
if ( cnxParam->cnxParmList.send.codecs[i].type == CODEC_NTE )
if ( cnxParam->namedPhoneEvts & CODEC_NTE_DTMF )
bEnableDigitRelay = VRG_TRUE;
//设置RTP的SSRC字段
if ( cnxParam->localSsrc != 0 )
hdspVhdSetSSRC( cnx->vhdhdl, cnxParam->localSsrc );
//获取第一个发送编码类型
selectedCodec = cnxParam->cnxParmList.send.codecs[0].type;
switch ( selectedCodec )
case ( CODEC_T38_MUTE ): //T38静音模式
SetT38PktSize( cnx, cnxParam->cnxParmList.send.period[0] ); //设置T38发包周期
SetT38EcMode( cnx, &(cnxParam->t38param) ); //设置T38冗余等级
bMuteT38 = VRG_TRUE; //标记当前编码为T38静音
SetVoiceMode( cnx, VM_FAX_RELAY ); //设置当成模式为T38传真
//如果当前模式为非传真模式,并且模式未改变时,不做处理
if ((cnx->voiceMode == mode) && (mode != VM_FAX_RELAY) &&
(!cnx->vbData.bEnabled))
return;
//如果设置模式为空闲,或者当成模式为空闲,则设置当成VBD开启为否
if (( mode == VM_IDLE ) || ( cnx->voiceMode == VM_IDLE ))
ResetVBDataState( &cnx->vbData );
pVbData->bEnabled = VRG_FALSE;
switch ( mode ) //这里我们只关心VM_FAX_RELAY条件
case ( VM_FAX_RELAY ):
//根据在HapiCnxEventProcess回调保存的最后传真事件确定初始传真
//模式,如果没有对应的映射则初始传真模式取HSFAXRNORMAL
const EPFAX_EVT_MAP *pFaxMap = epFaxEvtMap;
while ( ( pFaxMap->faxLastEvt != EPFAX_EVT_NONE ) &&
( pFaxMap->faxLastEvt != cnx->lastFaxEvent ) )
pFaxMap++;
if ( pFaxMap->faxLastEvt != EPFAX_EVT_NONE )
initMode = pFaxMap->faxInitMode;
else
initMode = HSFAXRNORMAL;
vhdMode = NETMODE_FAXRELAY; //设置VHD模式为T38传真
//根据上面参数设置VHD模式
hdspVhdSetMode( cnx->vhdhdl, vhdMode, initMode );
//如果开启GR303支持,则使用2833上报摘挂机事件
if ( state->bGR303Support )
GenerateNteEvent( cnx, (endptState->earlyOffHook? RTP_NTE_OFFHOOK :
RTP_NTE_ONHOOK) );
case ( CODEC_T38 ): //T38模式
//和T38静音模式基本相同,只是bMuteT38临时变量没有标记为TRUE,这里代
//码就不注释了
case ( CODEC_RED ): //VBD冗余模式
//获取VBD使用的编码类型
selectedCodec = cnxParam->cnxParmList.send.codecs[0].options.rfc2198Type;
//校正编码速率,如果超出有效值10~30ms的范围,则校正为默认值(G723编码默认
//值为30,其它编码默认值为20)
superPktInterval = checkPacketTime( cnxParam ) * 8;
//设置是否开启2833及是否切换到T38
EnableRelay( cnx, bEnableDigitRelay, superPktInterval, cnxParam->dataMode )
//如果开启2833,并且编码速率与保存的值不相等,则重新设置速率
if ( digitRelay )
if (cnx->period != (rate>>3)) //这里右移3位是因为rate值在上面乘以8
hdspSendCmdAsync( cnx->vhdhdl, HAPINET_PTE_SETREG1, HSCMDDATA,
VRG_OFFSETOF(HAPI_PTE_REGS, refreshInterval), rate );
//如果2833设置值在相同模式下没有变化,则直接返回
if ( (cnx->digitRelay == digitRelay) && (cnx->dataMode == dataMode) )
return ( EPSTATUS_SUCCESS );
netregs = cnx->netRegs;
//设置是否开启2833
if ( digitRelay )
netregs.hsxPtePacketVoiceOptions |= HSNET_PTE_OPTION_DIG_RELAY;
elese
netregs.hsxPtePacketVoiceOptions &= (~HSNET_PTE_OPTION_DIG_RELAY);
//设置是否切换到t38
switch ( dataMode )
case EPDATAMODE_T38_MUTE:
case EPDATAMODE_T38:
netregs.hsxNetOptions |= HSNET_NET_OPTION_FAXRELAY;
case EPDATAMODE_VBD:
default:
netregs.hsxNetOptions &= ~HSNET_NET_OPTION_FAXRELAY;
//将上面的值设置到DSP
hdspSendCmdDataAsync( cnx->vhdhdl, HAPINET_CONFIG_SETREGS,
HSCMDEXTDATA_ASYNC, sizeof( netregs ), &netregs );
//保存
cnx->digitRelay = digitRelay;
cnx->dataMode = dataMode;
cnx->netRegs.hsxNetOptions = netregs.hsxNetOptions;
cnx->netRegs.hsxPtePacketVoiceOptions = netregs.hsxPtePacketVoiceOptions;
//如果切换到T38模式,则不需要在设置下面选项
if ( selectedCodec == CODEC_T38 || selectedCodec == CODEC_T38_MUTE )
cnx->bMuteT38 = bMuteT38;
return ( EPSTATUS_SUCCESS );
//校正G729编码为DSP实际编解码值。注释里说G729和G729A是可以共操作的,但
//一般RTP协商只设置为G729,这里校正是为了设置DSP实际编码值。
if (( selectedCodec == CODEC_G729 ) && ( vrgEndptCap[dspNum].codecCap[CODEC_G729A]
== CODEC_SUPPORTED ) && ( vrgEndptCap[dspNum].codecCap[CODEC_G729B] ==
CODEC_SUPPORTED ))
selectedCodec = CODEC_G729B;
else if (( selectedCodec == CODEC_G729 ) &&
( vrgEndptCap[dspNum].codecCap[CODEC_G729A] == CODEC_SUPPORTED ))
selectedCodec = CODEC_G729A;
//编码能力校验
rateMap = epRateMap;
while (( rateMap->codec != CODEC_NULL ) && ( rateMap->codec != selectedCodec ))
rateMap++;
if ( rateMap->codec == CODEC_NULL )
return ( EPSTATUS_UNSUPPORTED_MODE );
//获取当前编码最小速率采样大小
baseFrameRate = codecGetBaseFrameRate( selectedCodec )
//如果当前资源为会议模式,则只支持基本编码
if ( cnx->bLiteWeight )
if (( selectedCodec != CODEC_PCMU ) && ( selectedCodec != CODEC_PCMA ) &&
( selectedCodec != CODEC_NTE ))
return ( EPSTATUS_UNSUPPORTED_MODE );
//如果当前是VBD模式,则关闭静音检测
if ( cnx->vbData.bEnabled )
vadMode = HAPI_GVAD_MODE_OFF;
vadType = HAPI_VAD_TYPE_NONE;
else //否则当前非VBD模式
if ( cnxParam->silence ) //如果需要开启静音检测
vadMode = HAPI_GVAD_MODE_TRANSPARENT; //设置开启静音检测
//设置静音检测类型。如果是G723或G729编码则是内置的静音包,
//否则其它编码则为单独构造的静音编码包
if ( (rateMap->codec == CODEC_G729B) || ( rateMap->codec ==
CODEC_G7231A_53 ) || ( rateMap->codec == CODEC_G7231A_63 ) )
vadType = HAPI_VAD_TYPE_BUILTIN;
else
vadType = HAPI_VAD_TYPE_GENERIC;
else //如果不需要开启静音检测则关闭
vadMode = HAPI_GVAD_MODE_OFF;
vadType = HAPI_VAD_TYPE_NONE;
//根据编码选择PLC类型。还不清楚PLC是指什么。
plcType = vrgEndptRetrievePlcSettings( selectedCodec );
cng = cnxParam->comfortNoise; //获取上层用户设置的CNG使能
//如果VAD、CNG、PLC值有变动,则重新设置到DSP,并保存值
if ((cnx->VadMode != vadMode) || (cnx->CngMode != cng) || (cnx->PlcMode != plcType))
hdspVhdSetVadCngPlc( cnx->vhdhdl, vadMode, cng, plcType );
cnx->VadMode = vadMode;
cnx->CngMode = cng;
cnx->PlcMode = plcType;
//转换为DSP使用的编码类型
switch ( cnxParam->cnxParmList.send.codecs[0].type )
case ( CODEC_G7231_53_VAR ):
xChgCodec = HAPI_PKT_VC_G7231_53;
case ( CODEC_G7231_63_VAR ):
xChgCodec = HAPI_PKT_VC_G7231_63;
case ( CODEC_G7231_VAR ):
xChgCodec = HAPI_PKT_VC_G7231_63;
default:
xChgCodec = rateMap->rate;
//校正不同G723可变编码为DSP支持的G723编码类型
checkG7231var( &cnxParam->cnxParmList.recv );
checkG7231var( &cnxParam->cnxParmList.send );
//如果静音检测、编码速率、编码类型有变化
if (( cnx->silence != cnxParam->silence ) ||
( cnx->period != cnxParam->cnxParmList.send.period[0] ) ||
( cnx->codecType != cnxParam->cnxParmList.send.codecs[0].type ))
//设置编码类型、VAD类型、编码速率
cnx->netRegs.hsxPacketVoiceEncoder = (VRG_UINT16)( ( vadType << 8 ) + xChgCodec );
cnx->netRegs.hsxVoiceSuperPktInterval = superPktInterval;
cnx->netRegs.hsxVBDSuperPktInterval = superPktInterval;
//设置上面值设置到DSP
if (bInitialChange)
hdspSendCmdDataAsync( cnx->vhdhdl, HAPINET_CONFIG_SETREGS,
HSCMDEXTDATA_ASYNC, sizeof(HSZNETREGS), & cnx->netRegs )
else
hdspVhdSetVoiceCodec( cnx->vhdhdl, xChgCodec, vadType,
superPktInterval, bInitialChange );
//设置VBD编码。这里provision里没有设置首选VBD编码类型,所以这里采的是默认
//值G711U
cnx->netRegs.hsxVoiceBandDefault = (VRG_UINT16)( ( vadType << 8 ) + vbdCodec );
hdspVhdSetVBDCodec( cnx->vhdhdl, vbdCodec, vadType );
//保存当前是否设置T38静音模式
cnx->bMuteT38 = bMuteT38;
switch( cnxParam->mode )
case EPCNXMODE_SNDO: //仅发送
case EPCNXMODE_RCVO: //仅接收
case EPCNXMODE_SNDRX: //发送/接收
case EPCNXMODE_LOOP: //环回测试
case EPCNXMODE_TEST: //连续性测试,不明白
case EPCNXMODE_REPLCATE: //重复性测试,不明白
case EPCNXMODE_CONF: //会议模式
case EPCNXMODE_TRANSCODE: //编码转换模式
//设置DSP当前为语音模式或VBD模式,这个函数在上面调用过,有注释说明,这里
//就不写了
SetVoiceMode( state->cnx[cnxIndex], VM_ACTIVE );
case EPCNXMODE_INACT: //去激活模式
SaveConnectionOptions( cnx, cnxParam ); //保存部分连接配置项
//设置DSP当前为语音模式或VBD模式,这个函数在上面调用过,有注释说明,这里
//就不写了
SetVoiceMode( state->cnx[cnxIndex], VM_ACTIVE );
return ( EPSTATUS_SUCCESS );
default:
//通过心跳模式,当前连接为未激活状态
hbUpdatePatientEndptId( cnx->cnxStateHBId, HBPATIENT_UNKNOWN_ENDPT );
hbUpdatePatientState( cnx->cnxStateHBId, HBSTATE_INACTIVE );
return ( EPSTATUS_UNSUPPORTED_MODE );
//如果当前测试模式为TR57,并且资源模式为收送、接收,则设置当前VHD模式为VBD模
//式,SetVoiceMode函数在上面调用过,有注释说明,这里就不写了
if (state->testMode == TESTMODE_TR57)
if ( cnxParam->mode == EPCNXMODE_SNDRX)
cnx->vbData.bEnabled = VRG_TRUE;
SetVoiceMode( cnx, VM_ACTIVE );
//设置RTP payload对应的编码类型,静态的不需要变更,动态的需要变更
SetRtpPayloadTypes( cnx, &cnxParam->cnxParmList );
//默认未开启VBD冗余
VRG_BOOL sendRedEnabled = VRG_FALSE;
VRG_BOOL recvRedEnabled = VRG_FALSE;
//预制所有静态payload编码映射
HAPI_UINT16 mediaPayloadTypeMap[HAPI_RTP_MAX_N_CODECS] = {
HAPI_RTP_MAKE_MEDIA_PAYLOAD_TYPE_MAP_ENTRY(HAPI_RTP_IETF_PT_CODEC_G711U, HAPI_PKT_VC_G711_ULAW), \
HAPI_RTP_MAKE_MEDIA_PAYLOAD_TYPE_MAP_ENTRY(HAPI_RTP_IETF_PT_CODEC_G711A, HAPI_PKT_VC_G711_ALAW), \
HAPI_RTP_MAKE_MEDIA_PAYLOAD_TYPE_MAP_ENTRY(HAPI_RTP_IETF_PT_CODEC_G728, HAPI_PKT_VC_G728_16), \
HAPI_RTP_MAKE_MEDIA_PAYLOAD_TYPE_MAP_ENTRY(HAPI_RTP_IETF_PT_CODEC_G729, HAPI_PKT_VC_G729_8), \
HAPI_RTP_MAKE_MEDIA_PAYLOAD_TYPE_MAP_ENTRY(HAPI_RTP_IETF_PT_CODEC_G723, HAPI_PKT_VC_G7231_VARIABLE), \
HAPI_RTP_MAKE_MEDIA_PAYLOAD_TYPE_MAP_ENTRY(HAPI_RTP_IETF_PT_CODEC_GSM, HAPI_PKT_VC_GSM_AMR_VARIABLE), \
HAPI_RTP_MAKE_MEDIA_PAYLOAD_TYPE_MAP_ENTRY((HAPI_RTP_IETF_PT_CODEC_G722), HAPI_PKT_VC_G722_64_MODE_1)
};
HAPI_UINT16 mediaEgressPayloadTypeMap[HAPI_RTP_MAX_N_CODECS] = {
HAPI_RTP_MAKE_MEDIA_PAYLOAD_TYPE_MAP_ENTRY(HAPI_RTP_IETF_PT_CODEC_G711U, HAPI_PKT_VC_G711_ULAW), \
HAPI_RTP_MAKE_MEDIA_PAYLOAD_TYPE_MAP_ENTRY(HAPI_RTP_IETF_PT_CODEC_G711A, HAPI_PKT_VC_G711_ALAW), \
HAPI_RTP_MAKE_MEDIA_PAYLOAD_TYPE_MAP_ENTRY(HAPI_RTP_IETF_PT_CODEC_G728, HAPI_PKT_VC_G728_16), \
HAPI_RTP_MAKE_MEDIA_PAYLOAD_TYPE_MAP_ENTRY(HAPI_RTP_IETF_PT_CODEC_G729, HAPI_PKT_VC_G729_8), \
HAPI_RTP_MAKE_MEDIA_PAYLOAD_TYPE_MAP_ENTRY(HAPI_RTP_IETF_PT_CODEC_G723, HAPI_PKT_VC_G7231_VARIABLE), \
HAPI_RTP_MAKE_MEDIA_PAYLOAD_TYPE_MAP_ENTRY(HAPI_RTP_IETF_PT_CODEC_GSM, HAPI_PKT_VC_GSM_AMR_VARIABLE), \
HAPI_RTP_MAKE_MEDIA_PAYLOAD_TYPE_MAP_ENTRY((HAPI_RTP_IETF_PT_CODEC_G722), HAPI_PKT_VC_G722_64_MODE_1)
};
//如果没有设置语音模式或者当前为T38模式,则不需要设置RTP payload映射
if ( cnx->voiceMode != VM_ACTIVE || cnx->vhdMode == NETMODE_FAXRELAY )
return;
codecMapSize = 1;
codecPcmuSet = 0;
for ( i = 0; i < codecList->send.numCodecs; i++ ) //遍历当前发送侧所有编码列表
//查找对应的DSP编码类型
rateMap = epRateMap;
while (( rateMap->codec != CODEC_NULL ) &&
(( rateMap->codec != codecList->send.codecs[i].type )))
rateMap++;
if( rateMap->codec == CODEC_NTE ) //如果编码类型为2833
//设置RTP寄存器对应2833 payload值项
rtpRegs.ntePayloadType = codecList->send.codecs[i].rtpPayloadType;
cnx->rtpstate.sendNtePayloadType = codecList->send.codecs[i].rtpPayloadType;
else if( rateMap->codec == CODEC_RED ) //如果编码类型为VBD冗余
sendRedEnabled = VRG_TRUE; //记载需要发送VBD冗余
//设置2198 payload值
rtpRegs.rfc2198PayloadType = codecList->send.codecs[i].rtpPayloadType;
cnx->rtpstate.sendRedPayloadType = codecList->send.codecs[i].rtpPayloadType;
//设置2198冗余等级
cnx->rtpstate.redLevel = codecList->send.codecs[i].options.opt1;
//设置2198媒体包的负载编码类型
rateRedMap = epRateMap;
while (( rateRedMap->codec != CODEC_NULL ) &&
(( rateRedMap->codec != codecList->send.codecs[i].options.rfc2198Type )))
rateRedMap++;
hdspSendCmdAsync( cnx->vhdhdl, HAPI_RTP_VBD_PAYLOADMAP_SET_CMD,
HSCMDDATA, codecList->send.codecs[i].options.opt2, rateRedMap->rate );
else //否则为其它编码类型时
//合法性校验,如果编码为2198冗余时,会用设置opt1值为非零来做为
//冗余等级
if( !codecList->send.codecs[i].options.opt1 )
//暂时没用,因为VRG_ENDPT_CFG_PRELOAD_RTP_PAYLOAD_MAP为1
if( rateMap->codec == CODEC_PCMU )
codecPcmuSet = 1;
//传入当前编码类型、编码payload值,及payload类型映射表,如果
//当前payload为动态值,则需要更新payload类型映射表
MapRtpPayloadType( rateMap->rate,
codecList->send.codecs[i].rtpPayloadType, mediaPayloadTypeMap );
//校正g729编码的payload值
if (( codec == HAPI_PKT_VC_G729A_8 ))
payloadType = HAPI_RTP_IETF_PT_CODEC_G729;
//校正g729编码类型
if (( codec == HAPI_PKT_VC_G729_8 ) &&
( vrgEndptCap[0].codecCap[CODEC_G729A] == CODEC_SUPPORTED ))
codec = HAPI_PKT_VC_G729A_8;
//将当前编码类型和编码payload值进行宏合并,与方便和静态的payload
//映射表中条目进行比较
mediaPayloadType =
HAPI_RTP_MAKE_MEDIA_PAYLOAD_TYPE_MAP_ENTRY(payloadType, codec );
for( i = 1 ; i < HAPI_RTP_MAX_N_CODECS ; i++ ) //遍历静态payload映射表
//如果当前payload映射与静态表相同,则不需要变更
if( mediaPayloadType == mediaPayloadTypeMap[i] )
return 0;
//如果当前payload不与静态表映射相同,但当前payload值与静态
//表当前条目的payload值相同,并且非g723编码类型,则使用当前
//payload值的编码映射更新默认的映射表
if ( payloadType ==
HAPI_RTP_GET_PAYLOAD_TYPE_FROM_MEDIA_PAYLOAD_TYPE_MAP_ENTRY
(mediaPayloadTypeMap[i]) &&
(!(HAPI_PKT_IS_7231( HAPI_RTP_GET_CODEC_FROM_MEDIA_PAYLOAD_TYPE_MAP_ENTRY(mediaPayloadTypeMap[i]))) ||!(HAPI_PKT_IS_7231( codec )) ) )
mediaPayloadTypeMap[i] = 0;
if ( mediaPayloadTypeMap[i] == 0 )
mediaPayloadTypeMap[i] = mediaPayloadType;
return 1;
//临时设置接收侧2833及2198冗余的payload类型值为默认值
rtpRegs.nteEgressPayloadType = cnx->rtpstate.recvNtePayloadType =
NTE_DEFAULT_PAYLOAD;
rtpRegs.rfc2198EgressPayloadType = cnx->rtpstate.recvRedPayloadType =
RED_DEFAULT_PAYLOAD;
//处理接收侧payload映射表,同上面处理发送侧payload映射表的代码相同,这里就
//不注释说明了
//如果接收、发送侧都有2198冗余编码,则开启VBD冗余,否则关闭VBD冗余
if ( sendRedEnabled == VRG_TRUE && recvRedEnabled == VRG_TRUE )
rtpRegs.configFlags &= ~HAPI_RTP_EGRESS_DROP_REDUNDANT_PAYLOAD_MASK;
rtpRegs.configFlags |= HAPI_RTP_INGRESS_RFC2198_ENABLE_MASK;
else
rtpRegs.configFlags |= HAPI_RTP_EGRESS_DROP_REDUNDANT_PAYLOAD_MASK;
rtpRegs.configFlags &= ~HAPI_RTP_INGRESS_RFC2198_ENABLE_MASK;
//将上面设置好的接收、发送侧的payload映射表复制到rtp模块寄存器变量中
memcpy(rtpRegs.mediaPayloadTypeMap, mediaPayloadTypeMap,
sizeof(mediaPayloadTypeMap) );
memcpy( rtpRegs.mediaEgressPayloadTypeMap, mediaEgressPayloadTypeMap,
sizeof(mediaEgressPayloadTypeMap));
//更新DSP
hdspSendCmdDataAsync( cnx->vhdhdl, HAPINET_RTP_SETREGS, HSCMDEXTDATA_ASYNC,
sizeof( rtpRegs ), &rtpRegs);
cnx->rtpRegs = rtpRegs; //保存
//设置RTP模式
SetRtpMode( state->cnx[cnxIndex], cnxParam->mode );
//如果没有设置语音模式或者当前为T38模式,则不需要设置RTP模式
if ( cnx->voiceMode != VM_ACTIVE || cnx->vhdMode == NETMODE_FAXRELAY )
return;
//如果当前需要发送RTP包,或者需要向对摘发送回铃音并且非环回测试,则设置发
//送RTP包,否则不向网络侧发送RTP包
if ( ModeCheck( mode, SENDMODE) || ( cnx->activeSignal &&
(mode != EPCNXMODE_LOOP) ) )
rtpRegs2.configFlags2 &= ~HAPI_RTP_INGRESS_SEND_RTP_PACKETS_DISABLE_MASK;
else
rtpRegs2.configFlags2 |= HAPI_RTP_INGRESS_SEND_RTP_PACKETS_DISABLE_MASK;
//设置是否需要接收RTP包
if ( ModeCheck( mode, RECVMODE) )
rtpRegs2.configFlags2 &=
~HAPI_RTP_EGRESS_PROCESS_RTP_PACKETS_DISABLE_MASK;
else
rtpRegs2.configFlags2 |= HAPI_RTP_EGRESS_PROCESS_RTP_PACKETS_DISABLE_MASK;
//如果DSP中值与要设置值不同,则重新设置DSP
if ( rtpRegs2.configFlags2 != cnx->rtpRegs2.configFlags2 )
hdspSendCmdAsync( vhdHdl, HAPI_RTP_SETREG21_CMD, HSCMDDATA,
OFFSETOF(HAPI_RTP_REGS2, configFlags2), rtpRegs2.configFlags2);
//保存值
cnx->rtpRegs2 = rtpRegs2;
//保存部分连接配置项
SaveConnectionOptions( cnx, cnxParam );
ENDPT_410_ProcessVrgEndptCreateConnection
最新推荐文章于 2016-05-26 15:42:27 发布