void	OpenDeviceOK ( DeviceID_t *pDevice )
{
	VOIP_STRUCT	*pOneVOIP;

	if (pDevice == NULL)
		return;

	if ( pDevice->m_s16DeviceMain == XMS_DEVMAIN_BOARD )
	{
		AllDeviceRes[pDevice->m_s8ModuleID].deviceID.m_CallID = pDevice->m_CallID;		// this line is very important, must before all operation
	}

	if ( pDevice->m_s16DeviceMain == XMS_DEVMAIN_VOIP )
	{
		pOneVOIP = &M_OneVOIP(*pDevice);

		pOneVOIP->deviceID.m_CallID = pDevice->m_CallID;		// this line is very important, must before all operation
	
		// init this Device: VOIP
		InitVOIPChannel ( pOneVOIP );

		XMS_ctsResetDevice ( g_acsHandle, pDevice, NULL );
		XMS_ctsGetDevState ( g_acsHandle, pDevice, NULL );	

		// modify the count
		g_iTotalVOIPOpened ++;
		AllDeviceRes[pDevice->m_s8ModuleID].lVOIPOpened ++;

		DrawCount_VOIP ( pDevice->m_s8ModuleID  );
	}

	if ( pDevice->m_s16DeviceMain == XMS_DEVMAIN_VOICE )
	{
		M_OneVoice(*pDevice).deviceID.m_CallID = pDevice->m_CallID;		// this is very important

		// init this Device: Voice
		M_OneVoice(*pDevice).State = VOC_FREE;

		XMS_ctsResetDevice ( g_acsHandle, pDevice, NULL );
		XMS_ctsGetDevState ( g_acsHandle, pDevice, NULL );

		// modify the count
		g_iTotalVoiceOpened ++;
		g_iTotalVoiceFree ++;
		AllDeviceRes[pDevice->m_s8ModuleID].lVocOpened ++;
		AllDeviceRes[pDevice->m_s8ModuleID].lVocFreeNum ++;

		DrawCount_Voc ( pDevice->m_s8ModuleID );
	}
}
int		FreeOneFreeVoice (  DeviceID_t *pFreeVocDeviceID )
{
	DJ_S8	s8ModID;

	s8ModID = pFreeVocDeviceID->m_s8ModuleID;
	if ( AllDeviceRes[s8ModID].lFlag == 1 )
	{
		M_OneVoice(*pFreeVocDeviceID).State = VOC_FREE;

		AllDeviceRes[s8ModID].lVocFreeNum++;
		g_iTotalVoiceFree ++;
		DrawCount_Voc ( s8ModID );
		return	0;		// OK
	}

	return -1;			// invalid VocDeviceID
}
void ResetVOIP ( VOIP_STRUCT *pOneVOIP, Acs_Evt_t *pAcsEvt )
{
	if (pOneVOIP == NULL || pAcsEvt == NULL)
		return ;

	// free the used Voice Resource
	if ( pOneVOIP->VocDevID.m_s16DeviceMain > 0 )
	{
		StopPlayFile ( &pOneVOIP->VocDevID );
		StopRecordFile(&pOneVOIP->VocDevID);	

		FreeOneFreeVoice (  &pOneVOIP->VocDevID );

		memset ( &M_OneVoice(pOneVOIP->VocDevID).UsedDevID,	0, sizeof(DeviceID_t) );		// 0表示还没有分配 Device 
		memset ( &pOneVOIP->VocDevID, 0, sizeof(DeviceID_t) );		// 0表示还没有分配 Device
		DrawMain_VocInfo ( pOneVOIP );
	}

	InitVOIPChannel ( pOneVOIP );
}
void VOIPWork ( VOIP_STRUCT *pOneVOIP, Acs_Evt_t *pAcsEvt )
{
	Acs_CallControl_Data   *pCallControl = NULL;
	VoIPCallPrivate_t      *voipCallPrivate = NULL;
	DeviceID_t				FreeVocDeviceID;
	char					FileName[256];
	char                    chTmpFilePath[256] = "";

	if (pOneVOIP == NULL || pAcsEvt == NULL)
		return;

	if ( pAcsEvt->m_s32EventType == XMS_EVT_CLEARCALL )	/*拆线事件*/
	{
		if (cfg_iVoiceCheck == 1)
		{
			StopPlayFile(&pOneVOIP->VocDevID);
			
			//删除录音文件
			GetFilePathName(pOneVOIP, chTmpFilePath);
			sprintf(FileName, "%s\\DemoRec.%0003d", chTmpFilePath, pOneVOIP->iSeqID);
			DeleteFile(FileName);
		}

		ResetVOIP ( pOneVOIP, pAcsEvt );
		Change_State(pOneVOIP, VOIP_FREE);

		return ; 
	}

	switch(pOneVOIP->State)
	{
	case VOIP_FREE:
		if ( pAcsEvt->m_s32EventType == XMS_EVT_CALLIN )	/*呼入事件*/
		{
			pCallControl = (Acs_CallControl_Data *)FetchEventData(pAcsEvt);

			ASSERT(pCallControl->m_PrivData.m_u32DataSize == sizeof(VoIPCallPrivate_t));
			voipCallPrivate = (VoIPCallPrivate_t *)&(pCallControl->m_PrivData);			

			XMS_ctsAlertCall ( g_acsHandle, &pOneVOIP->deviceID, NULL );

			XMS_ctsAnswerCallIn ( g_acsHandle, &pOneVOIP->deviceID, NULL );			
			
			pOneVOIP->iProtocol = voipCallPrivate->m_s32Protocol;

			//Caller Info
			strncpy(pOneVOIP->CallerAddr, voipCallPrivate->m_s8CallerAddress, sizeof(pOneVOIP->CallerAddr));			
			strncpy(pOneVOIP->CallerUserID, voipCallPrivate->m_s8CallerUserID, sizeof(pOneVOIP->CallerUserID));
			strncpy ( pOneVOIP->CallerNum, pCallControl->m_s8CallingNum, sizeof(pOneVOIP->CallerNum));
			pOneVOIP->iCallerPort = (unsigned short)voipCallPrivate->m_s32CallerPort;
			//

			//Callee Info
			strncpy(pOneVOIP->CalleeAddr, voipCallPrivate->m_s8CalleeAddress, sizeof(pOneVOIP->CalleeAddr));			
			strncpy(pOneVOIP->CalleeUserID, voipCallPrivate->m_s8CalleeUserID, sizeof(pOneVOIP->CalleeUserID));
			strncpy ( pOneVOIP->CalleeNum, pCallControl->m_s8CalledNum, sizeof(pOneVOIP->CalleeNum));			
			pOneVOIP->iCalleePort = (unsigned short)voipCallPrivate->m_s32CalleePort;
			//

			DrawMain_CallInfo( pOneVOIP );
			
			Change_State ( pOneVOIP, VOIP_WAIT_ANSWERCALL );
		}
		break;

	case VOIP_WAIT_ANSWERCALL:		
		if ( pAcsEvt->m_s32EventType == XMS_EVT_ANSWERCALL )	/*应答呼入完成事件*/
		{
			pCallControl = (Acs_CallControl_Data *)FetchEventData(pAcsEvt);

			if (cfg_iVoiceCheck == 1)
			{
				if ( SearchOneFreeVoice ( pOneVOIP,  &FreeVocDeviceID ) >= 0 )
				{
					pOneVOIP->u8PlayTag = 16;
					
					pOneVOIP->VocDevID = FreeVocDeviceID;
					
					M_OneVoice(FreeVocDeviceID).UsedDevID = pOneVOIP->deviceID; 
					
					DrawMain_VocInfo ( pOneVOIP );
					
					GetFilePathName(pOneVOIP, chTmpFilePath);
					sprintf(FileName, "%s\\DemoRec.%0003d", chTmpFilePath, pOneVOIP->iSeqID);		
					RecordFile ( pOneVOIP, FileName, 8000L*10, false);

					Change_State ( pOneVOIP, VOIP_RECORDFILE );					
				
				}
			}
			else
			{
				Change_State ( pOneVOIP, VOIP_WAITHANGUP );
			}
		}
		break;

	case VOIP_RECORDFILE:
		if ( CheckRecordEnd ( pOneVOIP, pAcsEvt) )	/*record完成事件*/
		{
			BindOneFreeVoice(pOneVOIP, pOneVOIP->VocDevID);
			Change_State ( pOneVOIP, VOIP_WAITBINDOK);
		}
		break;

	case VOIP_WAITBINDOK:
		if (pAcsEvt->m_s32EventType == XMS_EVT_SETPARAM)
		{
			GetFilePathName(pOneVOIP, chTmpFilePath);
			sprintf(FileName, "%s\\DemoRec.%0003d", chTmpFilePath, pOneVOIP->iSeqID);	
			pOneVOIP->u8PlayTag ++;
			PlayFile ( &pOneVOIP->VocDevID, FileName, pOneVOIP->u8PlayTag, true );

			Change_State (pOneVOIP, VOIP_PLAYRECORD);
		}	
		break;

	case VOIP_PLAYRECORD:
		if ( CheckPlayEnd ( pOneVOIP, pAcsEvt) )	/*play完成事件*/
		{
			// 主动挂机
			UnBindOneVoice(pOneVOIP);

			XMS_ctsClearCall ( g_acsHandle, &pOneVOIP->deviceID, 0, NULL );			

			Change_State ( pOneVOIP, VOIP_WAITHANGUP );
		}
		break;
	}
}
DJ_Void EvtHandler(DJ_U32 esrParam)
{
	Acs_Evt_t *			    pAcsEvt = NULL;
	Acs_Dev_List_Head_t * pAcsDevList = NULL;


	pAcsEvt = (Acs_Evt_t *) esrParam;
	DispEventInfo ( pAcsEvt );

	switch ( pAcsEvt->m_s32EventType )
	{
		case XMS_EVT_QUERY_DEVICE:
			if ( IsSysMod(pAcsEvt->m_DeviceID.m_s8ModuleID) )
			{
				pAcsDevList = ( Acs_Dev_List_Head_t *) FetchEventData(pAcsEvt);

				//收到设备变化的事件,增加/调整 该设备资源
				AddDeviceRes ( pAcsDevList );
			}
			break; 
		case XMS_EVT_QUERY_ONE_DSP_END:
			if ( IsSysMod(pAcsEvt->m_DeviceID.m_s8ModuleID) )
			{
				AllDeviceRes[pAcsEvt->m_DeviceID.m_s8ModuleID].lFlag = 1;		// 该DSP可以用了

				OpenAllDevice_Dsp ( pAcsEvt->m_DeviceID.m_s8ModuleID );

				RefreshMapTable ( );

				ReDrawAll ();
			}
			break;

		case XMS_EVT_QUERY_DEVICE_END:	// 获取设备列表结束
			break;

		case XMS_EVT_OPEN_DEVICE:
			OpenDeviceOK ( &pAcsEvt->m_DeviceID );
			break;

		case XMS_EVT_DEVICESTATE:
			HandleDevState ( pAcsEvt );
			break;

		case XMS_EVT_UNIFAILURE:
			// must handle this event in your real System
			break;

		default:
			if ( pAcsEvt->m_DeviceID.m_s16DeviceMain == XMS_DEVMAIN_INTERFACE_CH  )
			{
				TrunkWork ( &M_OneTrunk(pAcsEvt->m_DeviceID), pAcsEvt );			
			}
			else if ( pAcsEvt->m_DeviceID.m_s16DeviceMain == XMS_DEVMAIN_VOICE )
			{
				DeviceID_t	*pDevID;

				pDevID = &M_OneVoice(pAcsEvt->m_DeviceID).UsedDevID;

				if ( pDevID->m_s16DeviceMain == XMS_DEVMAIN_INTERFACE_CH )
				{
					TrunkWork ( &M_OneTrunk(*pDevID), pAcsEvt );
				}
			}
			break;
	}
}
void	DispEventInfo ( Acs_Evt_t *pAcsEvt )
{
	char	TmpStr[256]={0};
	char	TmpS[256]={0};
	DeviceID_t	*pLinkTrkDevID;
	Acs_Dev_List_Head_t * pAcsDevList = NULL;
	Acs_UniFailure_Data * pAcsUniFailure = NULL;
	Acs_GeneralProc_Data * pAcsProcData=NULL;

	sprintf ( TmpStr, "EVT(%4d) : ", pAcsEvt->m_s32EvtSize );
	strcat ( TmpStr, GetString_EventType ( pAcsEvt->m_s32EventType ) );

	switch ( pAcsEvt->m_s32EventType )
	{
	case XMS_EVT_OPEN_STREAM:
		break;
	case XMS_EVT_CALLOUT:
	case XMS_EVT_CALLIN:
	case XMS_EVT_ANALOG_INTERFACE:
	case XMS_EVT_LINKDEVICE:
	case XMS_EVT_UNLINKDEVICE:
	case XMS_EVT_SETPARAM:
	case XMS_EVT_PLAY:
	case XMS_EVT_RECORD:		
	case XMS_EVT_OPEN_DEVICE:
	case XMS_EVT_CONTROLPLAY:
	case XMS_EVT_CONTROLRECORD:
	case XMS_EVT_CLEARCALL:
	case XMS_EVT_ANSWERCALL:
	case XMS_EVT_CAS_MFC_START:
	case XMS_EVT_CAS_MFC_END:
	case XMS_EVT_SENDIODATA:
	case XMS_EVT_DEV_TIMER:
		sprintf ( TmpS, "(%s, %s, %d, %d)", 
			GetString_DeviceMain(pAcsEvt->m_DeviceID.m_s16DeviceMain),
			GetString_DeviceSub(pAcsEvt->m_DeviceID.m_s16DeviceSub),
			pAcsEvt->m_DeviceID.m_s8ModuleID,
			pAcsEvt->m_DeviceID.m_s16ChannelID);
		strcat ( TmpStr, TmpS );
		break;
	case XMS_EVT_DEVICESTATE:
		{	
			char StateStr[100]={0};
			pAcsProcData = (Acs_GeneralProc_Data *)FetchEventData(pAcsEvt);
			GetString_LineState ( StateStr, pAcsProcData->m_s32DeviceState );
			sprintf ( TmpS, "(%s, %s, %d, %d), %s", 
				GetString_DeviceMain(pAcsEvt->m_DeviceID.m_s16DeviceMain),
				GetString_DeviceSub(pAcsEvt->m_DeviceID.m_s16DeviceSub),
				pAcsEvt->m_DeviceID.m_s8ModuleID,
				pAcsEvt->m_DeviceID.m_s16ChannelID,
				StateStr);
			strcat ( TmpStr, TmpS );
		}

		break;
	case XMS_EVT_RECVIODATA:
		{
			char		*p;
			Acs_IO_Data				*pIOData = NULL;
			pIOData = (Acs_IO_Data *)FetchEventData(pAcsEvt);	
			pLinkTrkDevID = &M_OneVoice(pAcsEvt->m_DeviceID).UsedDevID;

			if ( ( pIOData->m_u16IoType == XMS_IO_TYPE_DTMF ) && ( pIOData->m_u16IoDataLen > 0 ) )
			{
				p = (char *)FetchIOData(pAcsEvt);
				sprintf(TmpS,"[%c], (%s, %s, %d, %d), LinkTrk(%s, %s, %d, %d)",*p, 
					GetString_DeviceMain(pAcsEvt->m_DeviceID.m_s16DeviceMain),
					GetString_DeviceSub(pAcsEvt->m_DeviceID.m_s16DeviceSub),
					pAcsEvt->m_DeviceID.m_s8ModuleID,
					pAcsEvt->m_DeviceID.m_s16ChannelID,
					GetString_DeviceMain(pLinkTrkDevID->m_s16DeviceMain),
					GetString_DeviceSub(pLinkTrkDevID->m_s16DeviceSub),
					pLinkTrkDevID->m_s8ModuleID,
					pLinkTrkDevID->m_s16ChannelID);				
				strcat ( TmpStr, TmpS );
			}else if ( (pIOData->m_u16IoType == XMS_IO_TYPE_FSK) && (pIOData->m_u16IoDataLen > 0 ))
			{
				p = (char *)FetchIOData(pAcsEvt);
				sprintf(TmpS,"[%s], (%s, %s, %d, %d), LinkTrk(%s, %s, %d, %d)",p, 
					GetString_DeviceMain(pAcsEvt->m_DeviceID.m_s16DeviceMain),
					GetString_DeviceSub(pAcsEvt->m_DeviceID.m_s16DeviceSub),
					pAcsEvt->m_DeviceID.m_s8ModuleID,
					pAcsEvt->m_DeviceID.m_s16ChannelID,
					GetString_DeviceMain(pLinkTrkDevID->m_s16DeviceMain),
					GetString_DeviceSub(pLinkTrkDevID->m_s16DeviceSub),
					pLinkTrkDevID->m_s8ModuleID,
					pLinkTrkDevID->m_s16ChannelID);				
				strcat ( TmpStr, TmpS );
				
			}else
			{
				sprintf(TmpS,", m_u16IoType:%d, (%s, %s, %d, %d)",
					pIOData->m_u16IoType,
					GetString_DeviceMain(pAcsEvt->m_DeviceID.m_s16DeviceMain),
					GetString_DeviceSub(pAcsEvt->m_DeviceID.m_s16DeviceSub),
					pAcsEvt->m_DeviceID.m_s8ModuleID,
					pAcsEvt->m_DeviceID.m_s16ChannelID);				
				strcat ( TmpStr, TmpS );
			}
		}
		break;

	case XMS_EVT_QUERY_DEVICE:
		pAcsDevList = (Acs_Dev_List_Head_t *) FetchEventData(pAcsEvt);
		sprintf ( TmpS, " (%s,%2d,%3d)", GetString_DeviceMain(pAcsDevList->m_s32DeviceMain),
			pAcsDevList->m_s32ModuleID,	pAcsDevList->m_s32DeviceNum );
		strcat ( TmpStr, TmpS );
		break;

	case XMS_EVT_UNIFAILURE:
		pAcsUniFailure = (Acs_UniFailure_Data *) FetchEventData(pAcsEvt);
		sprintf ( TmpS, ": %s(0x%X) dev=(%s, %d, %d),  %d ?=? %d+%d", 
			GetString_ErrorCode(pAcsUniFailure->m_s32AcsEvtErrCode), pAcsUniFailure->m_s32AcsEvtErrCode,
			GetString_DeviceMain(pAcsEvt->m_DeviceID.m_s16DeviceMain),  pAcsEvt->m_DeviceID.m_s8ModuleID, pAcsEvt->m_DeviceID.m_s16ChannelID,
			pAcsEvt->m_s32EvtSize, sizeof(Acs_Evt_t), sizeof(Acs_UniFailure_Data) );
		strcat ( TmpStr, TmpS );
		break;

	default:
		break;

	}
	WriteLog(LEVEL_DEBUG, TmpStr);
}