#include "StdAfx.h" #include "IpmChannel.h" #include "Config.h" #include "MC.h" #include "VoipChannel.h" CIpmChannel::CIpmChannel(DEV_RES_CH_TYPE ChannelNo, DEV_RES_NO_TYPE NodeNo, DEV_RES_NO_TYPE BoardNo) : CChannelResource(DEV_RES_TYPE_IPM, NodeNo, BoardNo, DEVICE_RES_NO_ANY, ChannelNo), m_pVoipChanBind(NULL), m_StartFlag(false), m_FaxFlag(false) { } CIpmChannel::~CIpmChannel(void) { } /***************************************************************** **【函数名称】 __onAnswer **【函数功能】 应答检测处理 **【参数】 **【返回值】 ****************************************************************/ void CIpmChannel::__onAnswer( METAEVENT* pMetaEvent ) { if(ISX_sr_getevtlen() > 1) { /*获取RTP流中携带的远端IP和端口*/ IPMEV_ANSWER_INFO *pAnswerInfo = (IPMEV_ANSWER_INFO *)ISX_sr_getevtdatap(); ASSERT(pAnswerInfo != NULL); if(pAnswerInfo != NULL) { /*确认远端IP和端口有变化,需要重新启动媒体协商*/ if(strcmp(m_XoipCfg.DstIpAddr.IpAddr, pAnswerInfo->RemoteIpAddr) != 0 || m_XoipCfg.DstRtpPort.UdpPort != pAnswerInfo->RemoteUdpPort) { lstrcpy(m_XoipCfg.DstIpAddr.IpAddr, pAnswerInfo->RemoteIpAddr); m_XoipCfg.DstRtpPort.UdpPort = pAnswerInfo->RemoteUdpPort; ISX_ipm_SetParm(m_Handle, &m_XoipCfg, EV_ASYNC); } if(pAnswerInfo->ucEvtType == 0) LOGGER(LOG_CLASS_DEV, LOG_LEVEL_NORMAL, _T("{IPMCh}: 通道[%d-%d-%d]语音停止, Remote[addr = %s, port = %u]"), m_Id.NodeNo, m_Id.BoardNo, m_Id.ChanNo, m_XoipCfg.DstIpAddr.IpAddr, m_XoipCfg.DstRtpPort.UdpPort); else LOGGER(LOG_CLASS_DEV, LOG_LEVEL_NORMAL, _T("{IPMCh}: 通道[%d-%d-%d]语音开始, Remote[addr = %s, port = %u]"), m_Id.NodeNo, m_Id.BoardNo, m_Id.ChanNo, m_XoipCfg.DstIpAddr.IpAddr, m_XoipCfg.DstRtpPort.UdpPort); } } else { UCHAR AnswerFlag = *(UCHAR*)ISX_sr_getevtdatap(); if(AnswerFlag == 0) LOGGER(LOG_CLASS_DEV, LOG_LEVEL_NORMAL, _T("{IPMCh}: 通道[%d-%d-%d]语音停止, Remote[addr = %s, port = %u]"), m_Id.NodeNo, m_Id.BoardNo, m_Id.ChanNo, m_XoipCfg.DstIpAddr.IpAddr, m_XoipCfg.DstRtpPort.UdpPort); else LOGGER(LOG_CLASS_DEV, LOG_LEVEL_NORMAL, _T("{IPMCh}: 通道[%d-%d-%d]语音开始, Remote[addr = %s, port = %u]"), m_Id.NodeNo, m_Id.BoardNo, m_Id.ChanNo, m_XoipCfg.DstIpAddr.IpAddr, m_XoipCfg.DstRtpPort.UdpPort); } } /***************************************************************** **【函数名称】 __onSetParam **【函数功能】 传输参数设置的响应 **【参数】 **【返回值】 ****************************************************************/ void CIpmChannel::__onSetParam( METAEVENT* pMetaEvent ) { ISX_ipm_SwitchVF(m_Handle, IPM_SWITCH_FAX2VOICE, EV_ASYNC); LOGGER(LOG_CLASS_DEV, LOG_LEVEL_NORMAL, _T("{IPMCh}: 通道[%d-%d-%d]远端地址更改响应, Remote[addr = %s, port = %u]"), m_Id.NodeNo, m_Id.BoardNo, m_Id.ChanNo, m_XoipCfg.DstIpAddr.IpAddr, m_XoipCfg.DstRtpPort.UdpPort); } /***************************************************************** **【函数名称】 __onFax **【函数功能】 传真启动处理 **【参数】 **【返回值】 ****************************************************************/ void CIpmChannel::__onFax( METAEVENT* pMetaEvent ) { UCHAR FaxMark = *( UCHAR *)ISX_sr_getevtdatap(); // FaxMark = 0表示传真启动 if(FaxMark == 0 && !m_FaxFlag) { if(m_pVoipChanBind != NULL) m_pVoipChanBind->reinvite4T38(); } } /***************************************************************** **【函数名称】 open **【函数功能】 打开系统资源 **【参数】 **【返回值】 成功true,失败false ****************************************************************/ bool CIpmChannel::open( void ) { ASSERT(m_Handle == DEV_HANDLE_INVALID); m_Handle = ISX_ipm_Open(m_Id.NodeNo, m_Id.BoardNo, m_Id.ChanNo, this); if (m_Handle <= -1) { m_Handle = DEV_HANDLE_INVALID; LOGGER(LOG_CLASS_DEV, LOG_LEVEL_ERROR, _T("{IPMCh}: 通道[%d-%d-%d]打开失败"), m_Id.NodeNo, m_Id.BoardNo, m_Id.ChanNo); return false; } eIPM_EVENT EnableEvt[] = {EVT_RFC2833, EVT_ENERGY_DETECTOR, EVT_ANSWER_DETECTOR, EVT_FAX, EVT_RTP_TIMEOUT}; ISX_ipm_EnableEvents(m_Handle, EnableEvt, 5, EV_SYNC, 0); ISX_ipm_ReceiveDigits(m_Handle, NULL, EV_SYNC); //LOGGER(LOG_CLASS_DEV, LOG_LEVEL_NORMAL, _T("{IPMCh}: 通道[%d-%d-%d]打开成功"), m_Id.NodeNo, m_Id.BoardNo, m_Id.ChanNo); return true; } /***************************************************************** **【函数名称】 close **【函数功能】 关闭系统资源 **【参数】 **【返回值】 ****************************************************************/ void CIpmChannel::close( void ) { if(m_Handle != DEV_HANDLE_INVALID) { ISX_ipm_Close(m_Handle); m_Handle = DEV_HANDLE_INVALID; //LOGGER(LOG_CLASS_DEV, LOG_LEVEL_NORMAL, _T("{IPMCh}: 通道[%d-%d-%d]关闭"), m_Id.NodeNo, m_Id.BoardNo, m_Id.ChanNo); } } /***************************************************************** **【函数名称】 startMedia **【函数功能】 启动通道媒体流 **【参数】 **【返回值】 ****************************************************************/ bool CIpmChannel::startMedia( void ) { if(m_StartFlag) return false; ASSERT(m_pVoipChanBind != NULL); ISX_ipm_Set2Default(&m_XoipCfg); m_SrcAddr.IpAddr.Valid = 1; mediaAddrBoard(m_SrcAddr.IpAddr.IpAddr); m_SrcAddr.RtpPort.Valid = 1; m_SrcAddr.RtpPort.UdpPort = mediaPort(); m_XoipCfg.VoiceCfg.SrcRTCPPort.Valid = 0 ; m_XoipCfg.VoiceCfg.SrcRTCPPort.UdpPort = 0; m_XoipCfg.DstIpAddr.Valid = 1; lstrcpy(m_XoipCfg.DstIpAddr.IpAddr, m_pVoipChanBind->getPeerConnectAddr()); m_XoipCfg.DstRtpPort.Valid = 1; m_XoipCfg.DstRtpPort.UdpPort = m_pVoipChanBind->getPeerMediaPort(); m_XoipCfg.VoiceCfg.DstRTCPPort.Valid = 0 ; m_XoipCfg.VoiceCfg.DstRTCPPort.UdpPort = 0; m_XoipCfg.FaxCfg.SrcT38Port.Valid = 0; m_XoipCfg.FaxCfg.SrcT38Port.UdpPort = 0; m_XoipCfg.FaxCfg.DstT38Port.Valid = 0; m_XoipCfg.FaxCfg.DstT38Port.UdpPort = 0; m_XoipCfg.VoiceCfg.PayloadType.Valid = 1; m_XoipCfg.VoiceCfg.PayloadType.PaylaodType = m_pVoipChanBind->getPeerCodecId(); m_XoipCfg.DtmfCfg.DigitRelay.Valid = 1; m_XoipCfg.DtmfCfg.DigitRelay.DigitRelayMode = DRM_ERASE_AND_RELAY_RFC2833; m_XoipCfg.DtmfCfg.DynamicPayload.Valid = 0; m_XoipCfg.VoiceCfg.EchoCancel.Valid = 1; m_XoipCfg.VoiceCfg.EchoCancel.EchoCancel = 1; m_XoipCfg.VoiceCfg.EchoCancel.EchoCancellerLength = ECLength128MSec; if(ISX_ipm_StartMedia(m_Handle, &m_SrcAddr, &m_XoipCfg, EV_ASYNC, 0) == 0) m_StartFlag = true; else m_StartFlag = false; return m_StartFlag; } /***************************************************************** **【函数名称】 stopMedia **【函数功能】 停止通道媒体流 **【参数】 **【返回值】 ****************************************************************/ void CIpmChannel::stopMedia( void ) { ISX_ipm_Stop(m_Handle, STOP_ALL, EV_ASYNC); m_StartFlag = false; } /***************************************************************** **【函数名称】 switchVF **【函数功能】 语音与传真之间转换 **【参数】 **【返回值】 ****************************************************************/ bool CIpmChannel::switchVF( ISXSIP_IE_BODY_EX* pSdp ) { ASSERT(!m_FaxFlag); if(m_FaxFlag) return false; ASSERT(pSdp != NULL); USHORT Port = 0; int LoopNum = pSdp->u.BodySdp.SdpNum; ISXSIP_IE_BODY_SDP_EX* pSdpex = &pSdp->u.BodySdp; for(int i = 0; i < LoopNum; i++) { if(pSdpex->Sdp[i].Tag != ISXSIP_IE_SDP_TAG_MEDIA_DESC) continue; if(pSdpex->Sdp[i].u.MediaDesc.MediaPort > 0) { Port = pSdpex->Sdp[i].u.MediaDesc.MediaPort; break; } } if(Port > 0) { m_XoipCfg.FaxCfg.FaxType.Valid = 1; m_XoipCfg.FaxCfg.FaxType.FaxType = 1; // Fax配置类型,可以为:0为禁止传真,1为Relay,允许T.38传真中继,2 为Bypass,传真旁路 m_XoipCfg.VoiceCfg.EchoCancel.Valid = 1; m_XoipCfg.VoiceCfg.EchoCancel.EchoCancel = 0; m_XoipCfg.FaxCfg.SrcT38Port.Valid = 0; m_XoipCfg.FaxCfg.SrcT38Port.UdpPort = 0; m_XoipCfg.FaxCfg.DstT38Port.Valid = 1; m_XoipCfg.FaxCfg.DstT38Port.UdpPort = Port; ISX_ipm_SetParm(m_Handle, &m_XoipCfg, EV_ASYNC); if(ISX_ipm_SwitchVF(m_Handle, IPM_SWITCH_VOICE2FAX, EV_ASYNC) == 0) { m_FaxFlag = true; return true; } } LOGGER(LOG_CLASS_DEV, LOG_LEVEL_WARNING, _T("{IPMCh}: 通道[%d-%d-%d]在语音和传真模式间切换失败"), m_Id.NodeNo, m_Id.BoardNo, m_Id.ChanNo); return false; } /***************************************************************** **【函数名称】 onDevEvent **【函数功能】 系统事件处理 **【参数】 **【返回值】 ****************************************************************/ void CIpmChannel::onDevEvent( METAEVENT* pMetaEvent ) { ASSERT(pMetaEvent != NULL); switch(pMetaEvent->evttype) { case IPMEV_ANSWER: __onAnswer(pMetaEvent); break; case IPMEV_SET_PARM: __onSetParam(pMetaEvent); break; case IPMEV_FAX: __onFax(pMetaEvent); break; } } /***************************************************************** **【函数名称】 reset **【函数功能】 重置成员变量 **【参数】 **【返回值】 ****************************************************************/ void CIpmChannel::reset( void ) { m_StartFlag = false; m_FaxFlag = false; m_pVoipChanBind = NULL; CMC::GetInstance().onDevResState(m_Id); } /***************************************************************** **【函数名称】 state **【函数功能】 返回状态字符串 **【参数】 **【返回值】 ****************************************************************/ LPCTSTR CIpmChannel::getStateStr( void ) const { if(m_pVoipChanBind != NULL) return _T("busy"); else return (m_FaxFlag ? _T("fax") : _T("free")); } /***************************************************************** **【函数名称】 bind **【函数功能】 绑定VOIP通道 **【参数】 **【返回值】 ****************************************************************/ void CIpmChannel::bind( CVoipChannel* pVoipChannel ) { m_pVoipChanBind = pVoipChannel; CMC::GetInstance().onDevResState(m_Id); } /***************************************************************** **【函数名称】 startFax **【函数功能】 开始传真 **【参数】 **【返回值】 ****************************************************************/ void CIpmChannel::startFax( void ) { m_FaxFlag = true; CMC::GetInstance().onDevResState(m_Id); } /***************************************************************** **【函数名称】 stopFax **【函数功能】 结束传真 **【参数】 **【返回值】 ****************************************************************/ void CIpmChannel::stopFax( void ) { m_FaxFlag = false; CMC::GetInstance().onDevResState(m_Id); } /***************************************************************** **【函数名称】 mediaAddrBoard **【函数功能】 获取IPM板第二网口地址 **【参数】 **【返回值】 ****************************************************************/ bool CIpmChannel::mediaAddrBoard( LPTSTR Buffer ) { return ISX_sr_getnet2cfg(m_Id.NodeNo, m_Id.BoardNo, BT_XOIP, Buffer, NULL) == 0; } /***************************************************************** **【函数名称】 mediaAddrTrunk **【函数功能】 获取IPM板中继媒体地址 **【参数】 **【返回值】 ****************************************************************/ void CIpmChannel::mediaAddrTrunk( LPTSTR Buffer ) { lstrcpy(Buffer, CConfig::voipMediaAddr()); }