ENDPT_410_ProcessVrgEndptCreateConnection

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 );


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值