修改三方通话功能,在发起三方通话时,先保持住主叫,然后再拉回主叫到会议

IpmChannel.cpp 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369
  1. #include "StdAfx.h"
  2. #include "IpmChannel.h"
  3. #include "Config.h"
  4. #include "MC.h"
  5. #include "VoipChannel.h"
  6. CIpmChannel::CIpmChannel(DEV_RES_CH_TYPE ChannelNo, DEV_RES_NO_TYPE NodeNo, DEV_RES_NO_TYPE BoardNo)
  7. : CChannelResource(DEV_RES_TYPE_IPM, NodeNo, BoardNo, DEVICE_RES_NO_ANY, ChannelNo),
  8. m_pVoipChanBind(NULL), m_StartFlag(false), m_FaxFlag(false)
  9. {
  10. }
  11. CIpmChannel::~CIpmChannel(void)
  12. {
  13. }
  14. /*****************************************************************
  15. **【函数名称】 __onAnswer
  16. **【函数功能】 应答检测处理
  17. **【参数】
  18. **【返回值】
  19. ****************************************************************/
  20. void CIpmChannel::__onAnswer( METAEVENT* pMetaEvent )
  21. {
  22. if(ISX_sr_getevtlen() > 1)
  23. {
  24. /*获取RTP流中携带的远端IP和端口*/
  25. IPMEV_ANSWER_INFO *pAnswerInfo = (IPMEV_ANSWER_INFO *)ISX_sr_getevtdatap();
  26. ASSERT(pAnswerInfo != NULL);
  27. if(pAnswerInfo != NULL)
  28. {
  29. /*确认远端IP和端口有变化,需要重新启动媒体协商*/
  30. if(strcmp(m_XoipCfg.DstIpAddr.IpAddr, pAnswerInfo->RemoteIpAddr) != 0 || m_XoipCfg.DstRtpPort.UdpPort != pAnswerInfo->RemoteUdpPort)
  31. {
  32. lstrcpy(m_XoipCfg.DstIpAddr.IpAddr, pAnswerInfo->RemoteIpAddr);
  33. m_XoipCfg.DstRtpPort.UdpPort = pAnswerInfo->RemoteUdpPort;
  34. ISX_ipm_SetParm(m_Handle, &m_XoipCfg, EV_ASYNC);
  35. }
  36. if(pAnswerInfo->ucEvtType == 0)
  37. LOGGER(LOG_CLASS_DEV, LOG_LEVEL_NORMAL, _T("{IPMCh}: 通道[%d-%d-%d]语音停止, Remote[addr = %s, port = %u]"),
  38. m_Id.NodeNo, m_Id.BoardNo, m_Id.ChanNo, m_XoipCfg.DstIpAddr.IpAddr, m_XoipCfg.DstRtpPort.UdpPort);
  39. else
  40. LOGGER(LOG_CLASS_DEV, LOG_LEVEL_NORMAL, _T("{IPMCh}: 通道[%d-%d-%d]语音开始, Remote[addr = %s, port = %u]"),
  41. m_Id.NodeNo, m_Id.BoardNo, m_Id.ChanNo, m_XoipCfg.DstIpAddr.IpAddr, m_XoipCfg.DstRtpPort.UdpPort);
  42. }
  43. }
  44. else
  45. {
  46. UCHAR AnswerFlag = *(UCHAR*)ISX_sr_getevtdatap();
  47. if(AnswerFlag == 0)
  48. LOGGER(LOG_CLASS_DEV, LOG_LEVEL_NORMAL, _T("{IPMCh}: 通道[%d-%d-%d]语音停止, Remote[addr = %s, port = %u]"),
  49. m_Id.NodeNo, m_Id.BoardNo, m_Id.ChanNo, m_XoipCfg.DstIpAddr.IpAddr, m_XoipCfg.DstRtpPort.UdpPort);
  50. else
  51. LOGGER(LOG_CLASS_DEV, LOG_LEVEL_NORMAL, _T("{IPMCh}: 通道[%d-%d-%d]语音开始, Remote[addr = %s, port = %u]"),
  52. m_Id.NodeNo, m_Id.BoardNo, m_Id.ChanNo, m_XoipCfg.DstIpAddr.IpAddr, m_XoipCfg.DstRtpPort.UdpPort);
  53. }
  54. }
  55. /*****************************************************************
  56. **【函数名称】 __onSetParam
  57. **【函数功能】 传输参数设置的响应
  58. **【参数】
  59. **【返回值】
  60. ****************************************************************/
  61. void CIpmChannel::__onSetParam( METAEVENT* pMetaEvent )
  62. {
  63. ISX_ipm_SwitchVF(m_Handle, IPM_SWITCH_FAX2VOICE, EV_ASYNC);
  64. LOGGER(LOG_CLASS_DEV, LOG_LEVEL_NORMAL, _T("{IPMCh}: 通道[%d-%d-%d]远端地址更改响应, Remote[addr = %s, port = %u]"),
  65. m_Id.NodeNo, m_Id.BoardNo, m_Id.ChanNo, m_XoipCfg.DstIpAddr.IpAddr, m_XoipCfg.DstRtpPort.UdpPort);
  66. }
  67. /*****************************************************************
  68. **【函数名称】 __onFax
  69. **【函数功能】 传真启动处理
  70. **【参数】
  71. **【返回值】
  72. ****************************************************************/
  73. void CIpmChannel::__onFax( METAEVENT* pMetaEvent )
  74. {
  75. UCHAR FaxMark = *( UCHAR *)ISX_sr_getevtdatap();
  76. // FaxMark = 0表示传真启动
  77. if(FaxMark == 0 && !m_FaxFlag)
  78. {
  79. if(m_pVoipChanBind != NULL)
  80. m_pVoipChanBind->reinvite4T38();
  81. }
  82. }
  83. /*****************************************************************
  84. **【函数名称】 open
  85. **【函数功能】 打开系统资源
  86. **【参数】
  87. **【返回值】 成功true,失败false
  88. ****************************************************************/
  89. bool CIpmChannel::open( void )
  90. {
  91. ASSERT(m_Handle == DEV_HANDLE_INVALID);
  92. m_Handle = ISX_ipm_Open(m_Id.NodeNo, m_Id.BoardNo, m_Id.ChanNo, this);
  93. if (m_Handle <= -1)
  94. {
  95. m_Handle = DEV_HANDLE_INVALID;
  96. LOGGER(LOG_CLASS_DEV, LOG_LEVEL_ERROR, _T("{IPMCh}: 通道[%d-%d-%d]打开失败"), m_Id.NodeNo, m_Id.BoardNo, m_Id.ChanNo);
  97. return false;
  98. }
  99. eIPM_EVENT EnableEvt[] = {EVT_RFC2833, EVT_ENERGY_DETECTOR, EVT_ANSWER_DETECTOR, EVT_FAX, EVT_RTP_TIMEOUT};
  100. ISX_ipm_EnableEvents(m_Handle, EnableEvt, 5, EV_SYNC, 0);
  101. ISX_ipm_ReceiveDigits(m_Handle, NULL, EV_SYNC);
  102. //LOGGER(LOG_CLASS_DEV, LOG_LEVEL_NORMAL, _T("{IPMCh}: 通道[%d-%d-%d]打开成功"), m_Id.NodeNo, m_Id.BoardNo, m_Id.ChanNo);
  103. return true;
  104. }
  105. /*****************************************************************
  106. **【函数名称】 close
  107. **【函数功能】 关闭系统资源
  108. **【参数】
  109. **【返回值】
  110. ****************************************************************/
  111. void CIpmChannel::close( void )
  112. {
  113. if(m_Handle != DEV_HANDLE_INVALID)
  114. {
  115. ISX_ipm_Close(m_Handle);
  116. m_Handle = DEV_HANDLE_INVALID;
  117. //LOGGER(LOG_CLASS_DEV, LOG_LEVEL_NORMAL, _T("{IPMCh}: 通道[%d-%d-%d]关闭"), m_Id.NodeNo, m_Id.BoardNo, m_Id.ChanNo);
  118. }
  119. }
  120. /*****************************************************************
  121. **【函数名称】 startMedia
  122. **【函数功能】 启动通道媒体流
  123. **【参数】
  124. **【返回值】
  125. ****************************************************************/
  126. bool CIpmChannel::startMedia( void )
  127. {
  128. if(m_StartFlag)
  129. return false;
  130. ASSERT(m_pVoipChanBind != NULL);
  131. ISX_ipm_Set2Default(&m_XoipCfg);
  132. m_SrcAddr.IpAddr.Valid = 1;
  133. mediaAddrBoard(m_SrcAddr.IpAddr.IpAddr);
  134. m_SrcAddr.RtpPort.Valid = 1;
  135. m_SrcAddr.RtpPort.UdpPort = mediaPort();
  136. m_XoipCfg.VoiceCfg.SrcRTCPPort.Valid = 0 ;
  137. m_XoipCfg.VoiceCfg.SrcRTCPPort.UdpPort = 0;
  138. m_XoipCfg.DstIpAddr.Valid = 1;
  139. lstrcpy(m_XoipCfg.DstIpAddr.IpAddr, m_pVoipChanBind->getPeerConnectAddr());
  140. m_XoipCfg.DstRtpPort.Valid = 1;
  141. m_XoipCfg.DstRtpPort.UdpPort = m_pVoipChanBind->getPeerMediaPort();
  142. m_XoipCfg.VoiceCfg.DstRTCPPort.Valid = 0 ;
  143. m_XoipCfg.VoiceCfg.DstRTCPPort.UdpPort = 0;
  144. m_XoipCfg.FaxCfg.SrcT38Port.Valid = 0;
  145. m_XoipCfg.FaxCfg.SrcT38Port.UdpPort = 0;
  146. m_XoipCfg.FaxCfg.DstT38Port.Valid = 0;
  147. m_XoipCfg.FaxCfg.DstT38Port.UdpPort = 0;
  148. m_XoipCfg.VoiceCfg.PayloadType.Valid = 1;
  149. m_XoipCfg.VoiceCfg.PayloadType.PaylaodType = m_pVoipChanBind->getPeerCodecId();
  150. m_XoipCfg.DtmfCfg.DigitRelay.Valid = 1;
  151. m_XoipCfg.DtmfCfg.DigitRelay.DigitRelayMode = DRM_ERASE_AND_RELAY_RFC2833;
  152. m_XoipCfg.DtmfCfg.DynamicPayload.Valid = 0;
  153. m_XoipCfg.VoiceCfg.EchoCancel.Valid = 1;
  154. m_XoipCfg.VoiceCfg.EchoCancel.EchoCancel = 1;
  155. m_XoipCfg.VoiceCfg.EchoCancel.EchoCancellerLength = ECLength128MSec;
  156. if(ISX_ipm_StartMedia(m_Handle, &m_SrcAddr, &m_XoipCfg, EV_ASYNC, 0) == 0)
  157. m_StartFlag = true;
  158. else
  159. m_StartFlag = false;
  160. return m_StartFlag;
  161. }
  162. /*****************************************************************
  163. **【函数名称】 stopMedia
  164. **【函数功能】 停止通道媒体流
  165. **【参数】
  166. **【返回值】
  167. ****************************************************************/
  168. void CIpmChannel::stopMedia( void )
  169. {
  170. ISX_ipm_Stop(m_Handle, STOP_ALL, EV_ASYNC);
  171. m_StartFlag = false;
  172. }
  173. /*****************************************************************
  174. **【函数名称】 switchVF
  175. **【函数功能】 语音与传真之间转换
  176. **【参数】
  177. **【返回值】
  178. ****************************************************************/
  179. bool CIpmChannel::switchVF( ISXSIP_IE_BODY_EX* pSdp )
  180. {
  181. ASSERT(!m_FaxFlag);
  182. if(m_FaxFlag)
  183. return false;
  184. ASSERT(pSdp != NULL);
  185. USHORT Port = 0;
  186. int LoopNum = pSdp->u.BodySdp.SdpNum;
  187. ISXSIP_IE_BODY_SDP_EX* pSdpex = &pSdp->u.BodySdp;
  188. for(int i = 0; i < LoopNum; i++)
  189. {
  190. if(pSdpex->Sdp[i].Tag != ISXSIP_IE_SDP_TAG_MEDIA_DESC)
  191. continue;
  192. if(pSdpex->Sdp[i].u.MediaDesc.MediaPort > 0)
  193. {
  194. Port = pSdpex->Sdp[i].u.MediaDesc.MediaPort;
  195. break;
  196. }
  197. }
  198. if(Port > 0)
  199. {
  200. m_XoipCfg.FaxCfg.FaxType.Valid = 1;
  201. m_XoipCfg.FaxCfg.FaxType.FaxType = 1; // Fax配置类型,可以为:0为禁止传真,1为Relay,允许T.38传真中继,2 为Bypass,传真旁路
  202. m_XoipCfg.VoiceCfg.EchoCancel.Valid = 1;
  203. m_XoipCfg.VoiceCfg.EchoCancel.EchoCancel = 0;
  204. m_XoipCfg.FaxCfg.SrcT38Port.Valid = 0;
  205. m_XoipCfg.FaxCfg.SrcT38Port.UdpPort = 0;
  206. m_XoipCfg.FaxCfg.DstT38Port.Valid = 1;
  207. m_XoipCfg.FaxCfg.DstT38Port.UdpPort = Port;
  208. ISX_ipm_SetParm(m_Handle, &m_XoipCfg, EV_ASYNC);
  209. if(ISX_ipm_SwitchVF(m_Handle, IPM_SWITCH_VOICE2FAX, EV_ASYNC) == 0)
  210. {
  211. m_FaxFlag = true;
  212. return true;
  213. }
  214. }
  215. LOGGER(LOG_CLASS_DEV, LOG_LEVEL_WARNING, _T("{IPMCh}: 通道[%d-%d-%d]在语音和传真模式间切换失败"), m_Id.NodeNo, m_Id.BoardNo, m_Id.ChanNo);
  216. return false;
  217. }
  218. /*****************************************************************
  219. **【函数名称】 onDevEvent
  220. **【函数功能】 系统事件处理
  221. **【参数】
  222. **【返回值】
  223. ****************************************************************/
  224. void CIpmChannel::onDevEvent( METAEVENT* pMetaEvent )
  225. {
  226. ASSERT(pMetaEvent != NULL);
  227. switch(pMetaEvent->evttype)
  228. {
  229. case IPMEV_ANSWER:
  230. __onAnswer(pMetaEvent);
  231. break;
  232. case IPMEV_SET_PARM:
  233. __onSetParam(pMetaEvent);
  234. break;
  235. case IPMEV_FAX:
  236. __onFax(pMetaEvent);
  237. break;
  238. }
  239. }
  240. /*****************************************************************
  241. **【函数名称】 reset
  242. **【函数功能】 重置成员变量
  243. **【参数】
  244. **【返回值】
  245. ****************************************************************/
  246. void CIpmChannel::reset( void )
  247. {
  248. m_StartFlag = false;
  249. m_FaxFlag = false;
  250. m_pVoipChanBind = NULL;
  251. CMC::GetInstance().onDevResState(m_Id);
  252. }
  253. /*****************************************************************
  254. **【函数名称】 state
  255. **【函数功能】 返回状态字符串
  256. **【参数】
  257. **【返回值】
  258. ****************************************************************/
  259. LPCTSTR CIpmChannel::getStateStr( void ) const
  260. {
  261. if(m_pVoipChanBind != NULL)
  262. return _T("busy");
  263. else
  264. return (m_FaxFlag ? _T("fax") : _T("free"));
  265. }
  266. /*****************************************************************
  267. **【函数名称】 bind
  268. **【函数功能】 绑定VOIP通道
  269. **【参数】
  270. **【返回值】
  271. ****************************************************************/
  272. void CIpmChannel::bind( CVoipChannel* pVoipChannel )
  273. {
  274. m_pVoipChanBind = pVoipChannel;
  275. CMC::GetInstance().onDevResState(m_Id);
  276. }
  277. /*****************************************************************
  278. **【函数名称】 startFax
  279. **【函数功能】 开始传真
  280. **【参数】
  281. **【返回值】
  282. ****************************************************************/
  283. void CIpmChannel::startFax( void )
  284. {
  285. m_FaxFlag = true;
  286. CMC::GetInstance().onDevResState(m_Id);
  287. }
  288. /*****************************************************************
  289. **【函数名称】 stopFax
  290. **【函数功能】 结束传真
  291. **【参数】
  292. **【返回值】
  293. ****************************************************************/
  294. void CIpmChannel::stopFax( void )
  295. {
  296. m_FaxFlag = false;
  297. CMC::GetInstance().onDevResState(m_Id);
  298. }
  299. /*****************************************************************
  300. **【函数名称】 mediaAddrBoard
  301. **【函数功能】 获取IPM板第二网口地址
  302. **【参数】
  303. **【返回值】
  304. ****************************************************************/
  305. bool CIpmChannel::mediaAddrBoard( LPTSTR Buffer )
  306. {
  307. return ISX_sr_getnet2cfg(m_Id.NodeNo, m_Id.BoardNo, BT_XOIP, Buffer, NULL) == 0;
  308. }
  309. /*****************************************************************
  310. **【函数名称】 mediaAddrTrunk
  311. **【函数功能】 获取IPM板中继媒体地址
  312. **【参数】
  313. **【返回值】
  314. ****************************************************************/
  315. void CIpmChannel::mediaAddrTrunk( LPTSTR Buffer )
  316. {
  317. lstrcpy(Buffer, CConfig::voipMediaAddr());
  318. }