商丘数字城管中间件 - 测试用

FsProxy.cpp 32KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068
  1. #include "StdAfx.h"
  2. #include "FsProxy.h"
  3. #include "ChanExten.h"
  4. #include "ChanTrunk.h"
  5. #include "Session.h"
  6. #include "OperationReactor.h"
  7. #include "../IVR/IvrSysInc.h"
  8. SINGLETON_IMPLEMENT(CFsProxy)
  9. CFsProxy::CFsProxy(void) : m_Gateway(this), m_pEventHandler(NULL)
  10. {
  11. }
  12. CFsProxy::~CFsProxy(void)
  13. {
  14. }
  15. /*****************************************************************
  16. **【函数名称】 __transLogicState2CtiState
  17. **【函数功能】 将逻辑状态转换为CTI识别的状态
  18. **【参数】
  19. **【返回值】
  20. ****************************************************************/
  21. UINT CFsProxy::__transLogicState2CtiState( DEV_RES_TYPE ChanType, CHAN_LOGIC_STATE State )
  22. {
  23. if(ChanType == DEV_RES_TYPE_EXT)
  24. {
  25. UINT HoldMask = State & HELD_STATE_IND_MASK;
  26. switch(State & HELD_STATE_FILTER_MASK)
  27. {
  28. case CHAN_LOGIC_STATE_DISABLED: return INNER_STATE_DISABLED; // 不可用
  29. case CHAN_LOGIC_STATE_FREE: return INNER_STATE_FREE | HoldMask; // 空闲
  30. case CHAN_LOGIC_STATE_INIT: return INNER_STATE_INIT | HoldMask; // 摘机等待拨号
  31. case CHAN_LOGIC_STATE_DIALING: return INNER_STATE_DIALING | HoldMask; // 拨号
  32. case CHAN_LOGIC_STATE_RING_BACK: return INNER_STATE_RING_BACK | HoldMask; // 呼出振铃
  33. case CHAN_LOGIC_STATE_ALERTING: return INNER_STATE_ALERTING | HoldMask; // 来电振铃
  34. case CHAN_LOGIC_STATE_TALKING: return INNER_STATE_TALKING | HoldMask; // 通话中
  35. default:
  36. ASSERT(FALSE);
  37. return INNER_STATE_DISABLED;
  38. }
  39. }
  40. else
  41. {
  42. switch(State)
  43. {
  44. case CHAN_LOGIC_STATE_DISABLED: return TRUNK_STATE_DISABLED; // 不可用
  45. case CHAN_LOGIC_STATE_FREE: return TRUNK_STATE_FREE; // 空闲
  46. case CHAN_LOGIC_STATE_DIALING: return TRUNK_STATE_DIALING; // 拨号
  47. case CHAN_LOGIC_STATE_RING_BACK: return TRUNK_STATE_RING_BACK; // 呼出振铃
  48. case CHAN_LOGIC_STATE_ALERTING: return TRUNK_STATE_ALERTING; // 来电振铃
  49. case CHAN_LOGIC_STATE_STANDBY:
  50. case CHAN_LOGIC_STATE_TALKING: return TRUNK_STATE_TALKING; // 通话中
  51. default:
  52. ASSERT(FALSE);
  53. return TRUNK_STATE_UNKNOWN;
  54. }
  55. }
  56. }
  57. /*****************************************************************
  58. **【函数名称】 __addExten
  59. **【函数功能】 添加分机
  60. **【参数】
  61. **【返回值】
  62. ****************************************************************/
  63. void CFsProxy::__addExten( UINT ExtenNo )
  64. {
  65. CChanExten* pExten = new CChanExten(this, ExtenNo);
  66. m_MapChanExt.SetAt(ExtenNo, pExten);
  67. pExten->regist();
  68. }
  69. /*****************************************************************
  70. **【函数名称】 delExten
  71. **【函数功能】 删除分机
  72. **【参数】
  73. **【返回值】
  74. ****************************************************************/
  75. void CFsProxy::__delExten( UINT ExtenNo )
  76. {
  77. CChanExten* pExten = NULL;
  78. if(m_MapChanExt.Lookup(ExtenNo, pExten))
  79. {
  80. if(pExten->isFree())
  81. {
  82. m_MapChanExt.RemoveKey(ExtenNo);
  83. FS_LINK_DELETE(pExten);
  84. }
  85. else pExten->discard(true);
  86. }
  87. }
  88. /*****************************************************************
  89. **【函数名称】 __freeExten
  90. **【函数功能】 清空分机
  91. **【参数】
  92. **【返回值】
  93. ****************************************************************/
  94. void CFsProxy::__freeExten( void )
  95. {
  96. UINT ExtenNo = 0;
  97. CChanExten* pExten = NULL;
  98. POSITION Pos = m_MapChanExt.GetStartPosition();
  99. while(Pos != NULL)
  100. {
  101. m_MapChanExt.GetNextAssoc(Pos, ExtenNo, pExten);
  102. FS_LINK_DELETE(pExten);
  103. }
  104. m_MapChanExt.RemoveAll();
  105. }
  106. /*****************************************************************
  107. **【函数名称】 __initTrunkChan
  108. **【函数功能】 初始化中继通道
  109. **【参数】
  110. **【返回值】
  111. ****************************************************************/
  112. void CFsProxy::__initTrunkChan( void )
  113. {
  114. for(int i = 1; i <= CConfig::trunkCount(); ++i)
  115. {
  116. CChanTrunk* pTrunk = new CChanTrunk(this, i);
  117. m_ArrayTrunk.Add(pTrunk);
  118. pTrunk->regist();
  119. }
  120. }
  121. /*****************************************************************
  122. **【函数名称】 __freeTrunkChan
  123. **【函数功能】 清空中继通道
  124. **【参数】
  125. **【返回值】
  126. ****************************************************************/
  127. void CFsProxy::__freeTrunkChan( void )
  128. {
  129. CChanTrunk* pTrunk = NULL;
  130. for(int i = 0; i < m_ArrayTrunk.GetCount(); ++i)
  131. {
  132. pTrunk = m_ArrayTrunk[i];
  133. FS_LINK_DELETE(pTrunk);
  134. }
  135. m_ArrayTrunk.RemoveAll();
  136. }
  137. /*****************************************************************
  138. **【函数名称】 __getSession
  139. **【函数功能】 查找会话
  140. **【参数】
  141. **【返回值】
  142. ****************************************************************/
  143. CSession* CFsProxy::__getSession( PCHAN_EVENT_NOTIFY pNotify, bool NewWhenNull /*= false*/ )
  144. {
  145. CSession* pSession = __getSession(pNotify->CallId);
  146. if(pSession == NULL && NewWhenNull)
  147. {
  148. pSession = new CSession(this, pNotify->CallId);
  149. pSession->prepare(pNotify);
  150. m_MapSession.SetAt(pNotify->CallId, pSession);
  151. LOGGER(LOG_LEVEL_NORMAL,_T("{CFsProxy}:Add Session[%s],ChanId[%s],EventId[%d]"), pSession->id(), pNotify->ChanId, pNotify->EventId);
  152. }
  153. return pSession;
  154. }
  155. /*****************************************************************
  156. **【函数名称】 __getSession
  157. **【函数功能】 查找会话
  158. **【参数】
  159. **【返回值】
  160. ****************************************************************/
  161. CSession* CFsProxy::__getSession( LPCTSTR SessionId )
  162. {
  163. CSession* pSession = NULL;
  164. m_MapSession.Lookup(SessionId, pSession);
  165. return pSession;
  166. }
  167. /*****************************************************************
  168. **【函数名称】 __delSession
  169. **【函数功能】 删除会话
  170. **【参数】
  171. **【返回值】
  172. ****************************************************************/
  173. void CFsProxy::__delSession( LPCTSTR SessionId )
  174. {
  175. if (SessionId == NULL)
  176. return;
  177. CSession* pSession = NULL;
  178. if(m_MapSession.Lookup(SessionId, pSession))
  179. {
  180. m_MapSession.RemoveKey(SessionId);
  181. LOGGER(LOG_LEVEL_NORMAL, _T("{FsProxy}: Delete Session[%s]"), pSession->id());
  182. FS_LINK_DELETE(pSession);
  183. }
  184. }
  185. /*****************************************************************
  186. **【函数名称】 __freeSession
  187. **【函数功能】 清空会话
  188. **【参数】
  189. **【返回值】
  190. ****************************************************************/
  191. void CFsProxy::__freeSession( void )
  192. {
  193. CString SessionId = 0;
  194. CSession* pSession = NULL;
  195. POSITION Pos = m_MapSession.GetStartPosition();
  196. while(Pos != NULL)
  197. {
  198. m_MapSession.GetNextAssoc(Pos, SessionId, pSession);
  199. FS_LINK_DELETE(pSession);
  200. }
  201. m_MapSession.RemoveAll();
  202. }
  203. /*****************************************************************
  204. **【函数名称】 __kill
  205. **【函数功能】 挂断通道
  206. **【参数】
  207. **【返回值】
  208. ****************************************************************/
  209. bool CFsProxy::__kill( LONG JobId, LPCTSTR ChanId )
  210. {
  211. CString EslCmd;
  212. if(JobId == FS_LINK_JOBID_INVALID)
  213. EslCmd.Format(_T("bgapi uuid_kill %s"), ChanId);
  214. else
  215. EslCmd.Format(_T("bgapi uuid_kill %s\r\n%s: %ld"), ChanId, ESL_HEADER_JOB_UUID, JobId);
  216. return m_Gateway.sendCmd(EslCmd);
  217. }
  218. /*****************************************************************
  219. **【函数名称】 init
  220. **【函数功能】 初始化
  221. **【参数】
  222. **【返回值】
  223. ****************************************************************/
  224. bool CFsProxy::init( IEslEventHandler* pEventHandler )
  225. {
  226. ASSERT(pEventHandler != NULL);
  227. m_pEventHandler = pEventHandler;
  228. __initTrunkChan();
  229. if(m_Gateway.start())
  230. {
  231. m_Gateway.hangupAll();
  232. if(m_Gateway.scanExten())
  233. {
  234. LOGGER(LOG_LEVEL_NORMAL, _T("{FsProxy}: FreeSWITCH代理初始化成功"));
  235. return true;
  236. }
  237. else
  238. {
  239. LOGGER(LOG_LEVEL_ERROR, _T("{FsProxy}: FreeSWITCH代理初始化失败, 扫描分机资源失败"));
  240. return false;
  241. }
  242. }
  243. else
  244. {
  245. LOGGER(LOG_LEVEL_ERROR, _T("{FsProxy}: FreeSWITCH代理初始化失败, ESL网关启动失败"));
  246. m_pEventHandler = NULL;
  247. return false;
  248. }
  249. }
  250. /*****************************************************************
  251. **【函数名称】 release
  252. **【函数功能】 释放资源
  253. **【参数】
  254. **【返回值】
  255. ****************************************************************/
  256. void CFsProxy::release( void )
  257. {
  258. esl_disconnect(&m_EslHandle);
  259. m_Gateway.stop();
  260. __freeSession();
  261. __freeExten();
  262. __freeTrunkChan();
  263. }
  264. /*****************************************************************
  265. **【函数名称】 onChanRegist
  266. **【函数功能】 通道注册的处理函数
  267. **【参数】
  268. **【返回值】
  269. ****************************************************************/
  270. void CFsProxy::onChanRegist( DEV_RES_TYPE ChanType, UINT ChanNo, CHAN_LOGIC_STATE ChanState )
  271. {
  272. CDevControl::GetInstance().onEventResDetail(ChanType, ChanNo);
  273. CDevControl::GetInstance().onEventResState(ChanType, ChanNo, __transLogicState2CtiState(ChanType, ChanState));
  274. }
  275. /*****************************************************************
  276. **【函数名称】 onExtenDestroy
  277. **【函数功能】 分机销毁的处理函数
  278. **【参数】
  279. **【返回值】
  280. ****************************************************************/
  281. void CFsProxy::onExtenDestroy( UINT ExtenNo )
  282. {
  283. CDevControl::GetInstance().onEventResState(DEV_RES_TYPE_EXT, ExtenNo, INNER_STATE_REMOVE);
  284. }
  285. /*****************************************************************
  286. **【函数名称】 onExtenDirectOp
  287. **【函数功能】 分机直接操作启动
  288. **【参数】 OpType 启动的操作类型
  289. pHostChan 触发事件的通道
  290. pNotify 触发操作事件内容
  291. **【返回值】
  292. ****************************************************************/
  293. void CFsProxy::onExtenDirectOp( DEV_OP OpType, CVirtualChan* pHostChan, PCHAN_EVENT_NOTIFY pNotify )
  294. {
  295. switch(OpType)
  296. {
  297. case DEV_OP_CALL_OUT:
  298. {
  299. if(!COperationReactor::GetInstance().onExtenCallFromDev(pHostChan, pNotify))
  300. __kill(FS_LINK_JOBID_INVALID, pHostChan->chanId());
  301. }
  302. break;
  303. } // end switch
  304. }
  305. /*****************************************************************
  306. **【函数名称】 onChanStateUpdate
  307. **【函数功能】 通道状态更新处理
  308. **【参数】
  309. **【返回值】
  310. *****************************************************************/
  311. void CFsProxy::onChanStateUpdate( LONG OpInstance, CVirtualChan* pChan )
  312. {
  313. if(OpInstance != FS_LINK_INSTANCE_INVALID)
  314. m_pEventHandler->onEslEvtChanState(OpInstance, pChan);
  315. CDevControl::GetInstance().onEventResState(pChan->type(), pChan->no(), __transLogicState2CtiState(pChan->type(), pChan->state()), pChan->callerNum(), pChan->calleeNum());
  316. }
  317. /*****************************************************************
  318. **【函数名称】 onChanPoor
  319. **【函数功能】 空闲通道枯竭处理
  320. **【参数】
  321. **【返回值】
  322. *****************************************************************/
  323. void CFsProxy::onChanPoor( CSession* pSession, PCHAN_EVENT_NOTIFY pNotify )
  324. {
  325. __kill(FS_LINK_JOBID_INVALID, pNotify->ChanId);
  326. }
  327. /*****************************************************************
  328. **【函数名称】 onTrunkCallIn
  329. **【函数功能】 中继呼入
  330. **【参数】
  331. **【返回值】
  332. *****************************************************************/
  333. void CFsProxy::onTrunkCallIn( CChanTrunk* pTrunk )
  334. {
  335. CDevControl::GetInstance().onEventDevOperation(pTrunk->no(), DEV_OP_CALL_IN, pTrunk->callerNum(), pTrunk->calleeNum());
  336. }
  337. /*****************************************************************
  338. **【函数名称】 onEslDisconnect
  339. **【函数功能】 ESL连接中断处理
  340. **【参数】
  341. **【返回值】
  342. *****************************************************************/
  343. void CFsProxy::onEslDisconnect( void )
  344. {
  345. CDevControl::GetInstance().onEventDevDown();
  346. }
  347. /*****************************************************************
  348. **【函数名称】 onEslSipReg
  349. **【函数功能】 分机注册的处理函数
  350. **【参数】
  351. **【返回值】
  352. ****************************************************************/
  353. void CFsProxy::onEslExtenReg( UINT ExtenNo )
  354. {
  355. CChanExten* pExten = getExten(ExtenNo);
  356. if(pExten == NULL)
  357. {
  358. __addExten(ExtenNo);
  359. }
  360. else
  361. {
  362. if(pExten->isVoid()) // 若被丢弃,则改变丢弃状态
  363. pExten->discard(false);
  364. }
  365. #ifdef _DEBUG
  366. LOGGER(LOG_LEVEL_NORMAL, _T("{FsProxy}: 分机[%u]注册"), ExtenNo);
  367. #endif
  368. }
  369. /*****************************************************************
  370. **【函数名称】 onEslExtenUnreg
  371. **【函数功能】 分机注销的处理函数
  372. **【参数】
  373. **【返回值】
  374. ****************************************************************/
  375. void CFsProxy::onEslExtenUnreg( UINT ExtenNo )
  376. {
  377. __delExten(ExtenNo);
  378. #ifdef _DEBUG
  379. LOGGER(LOG_LEVEL_NORMAL, _T("{FsProxy}: 分机[%u]注销"), ExtenNo);
  380. #endif
  381. }
  382. /*****************************************************************
  383. **【函数名称】 onEslGwExten
  384. **【函数功能】 网关分机的处理函数
  385. **【参数】
  386. **【返回值】
  387. ****************************************************************/
  388. void CFsProxy::onEslGwExtenReg(LPCTSTR ExtenNo, LPCTSTR Ip)
  389. {
  390. m_MapAddrGwExt.SetAt(ExtenNo, Ip);
  391. return;
  392. }
  393. void CFsProxy::onEslGwExtenUnreg(LPCTSTR ExtenNo)
  394. {
  395. CString t_ip;
  396. if (m_MapAddrGwExt.Lookup(ExtenNo, t_ip))
  397. {
  398. t_ip.Empty();
  399. m_MapAddrGwExt.RemoveKey(ExtenNo);
  400. }
  401. }
  402. /*****************************************************************
  403. **【函数名称】 onEslEvtBgJobDone
  404. **【函数功能】 后台任务执行结束事件处理
  405. **【参数】
  406. **【返回值】
  407. *****************************************************************/
  408. void CFsProxy::onEslEvtBgJobDone( PBG_JOB_NOTIFY pNotify )
  409. {
  410. ASSERT(m_pEventHandler != NULL);
  411. m_pEventHandler->onEslEvtBgJobDone(pNotify);
  412. }
  413. /*****************************************************************
  414. **【函数名称】 onEslEvtChannel
  415. **【函数功能】 通道事件处理
  416. **【参数】
  417. **【返回值】
  418. *****************************************************************/
  419. void CFsProxy::onEslEvtChannel( PCHAN_EVENT_NOTIFY pNotify )
  420. {
  421. ASSERT(pNotify != NULL);
  422. if (pNotify == NULL)
  423. return;
  424. CSession* pSession = __getSession(pNotify, true);
  425. ASSERT(pSession != NULL);
  426. if (pSession == NULL)
  427. {
  428. LOGGER(LOG_LEVEL_WARNING, _T("{FsProxy}: 通道事件,没有找到会话,EslEventId=%d,ChanId[%s],CallId[%s],Caller[%s],Callee[%s]"), pNotify->EventId, pNotify->ChanId, pNotify->CallId, pNotify->Caller, pNotify->Callee);
  429. return;
  430. }
  431. __try {
  432. pSession->onChanEvent(pNotify);
  433. if (pSession->isVoid())
  434. __delSession(pSession->id());
  435. }
  436. __except (EXCEPTION_EXECUTE_HANDLER)
  437. {
  438. LOGGER(LOG_LEVEL_WARNING, _T("{FsProxy}: 处理通道事件时异常[%u],EslEventId=%d,ChanId[%s],CallId[%s],Caller[%s],Callee[%s]"), GetExceptionCode(), pNotify->EventId, pNotify->ChanId, pNotify->CallId, pNotify->Caller, pNotify->Callee);
  439. __delSession(pSession->id());
  440. }
  441. }
  442. /*****************************************************************
  443. **【函数名称】 onEslEvtDtmf
  444. **【函数功能】 DTMF事件处理
  445. **【参数】
  446. **【返回值】
  447. *****************************************************************/
  448. void CFsProxy::onEslEvtDtmf( PDTMF_NOTIFY pNotify )
  449. {
  450. ASSERT(pNotify != NULL);
  451. CSession* pSession = __getSession(pNotify->CallId);
  452. ASSERT(pSession != NULL);
  453. if(pSession != NULL)
  454. pSession->onChanDtmf(pNotify);
  455. }
  456. /*****************************************************************
  457. **【函数名称】 onEslEvtHold
  458. **【函数功能】 保持事件处理
  459. **【参数】
  460. **【返回值】
  461. *****************************************************************/
  462. void CFsProxy::onEslEvtHold( PHOLD_NOTIFY pNotify )
  463. {
  464. ASSERT(pNotify != NULL);
  465. CSession* pSession = __getSession(pNotify->CallId);
  466. ASSERT(pSession != NULL);
  467. if(pSession != NULL)
  468. pSession->onChanHold(pNotify);
  469. }
  470. /*****************************************************************
  471. **【函数名称】 getExten
  472. **【函数功能】 查找分机
  473. **【参数】
  474. **【返回值】
  475. ****************************************************************/
  476. CChanExten* CFsProxy::getExten( UINT ExtenNo )
  477. {
  478. CChanExten* pExten = NULL;
  479. m_MapChanExt.Lookup(ExtenNo, pExten);
  480. return pExten;
  481. }
  482. /*****************************************************************
  483. **【函数名称】 getTrunk
  484. **【函数功能】 查找中继
  485. **【参数】
  486. **【返回值】
  487. ****************************************************************/
  488. CChanTrunk* CFsProxy::getTrunk( UINT TrunkNo )
  489. {
  490. if (TrunkNo <= 0 || TrunkNo > (UINT)m_ArrayTrunk.GetCount())
  491. return NULL;
  492. --TrunkNo;
  493. return m_ArrayTrunk[TrunkNo];
  494. }
  495. /*****************************************************************
  496. **【函数名称】 delChan
  497. **【函数功能】 删除通道
  498. **【参数】
  499. **【返回值】
  500. ****************************************************************/
  501. void CFsProxy::delChan( CVirtualChan* pChan )
  502. {
  503. if(pChan->type() == DEV_RES_TYPE_EXT)
  504. __delExten(pChan->no());
  505. }
  506. /*****************************************************************
  507. **【函数名称】 getFreeTrunk
  508. **【函数功能】 查找空闲中继
  509. **【参数】
  510. **【返回值】
  511. ****************************************************************/
  512. CChanTrunk* CFsProxy::getFreeTrunk( void )
  513. {
  514. // 当前轮循到的索引
  515. static int PosStatic = 0;
  516. int CurPos = PosStatic;
  517. int BusyTruckCount = 0;
  518. // 保证遍历一轮
  519. for(int i = 0; i < m_ArrayTrunk.GetCount(); ++i)
  520. {
  521. // 保证POS是有效的
  522. if(PosStatic >= m_ArrayTrunk.GetCount())
  523. PosStatic = 0;
  524. CChanTrunk* pTrunk = m_ArrayTrunk[PosStatic++];
  525. ASSERT(pTrunk != NULL);
  526. // 当前外线是否空闲
  527. if (pTrunk->isFree())
  528. {
  529. return pTrunk;
  530. }
  531. else
  532. {
  533. BusyTruckCount++;
  534. }
  535. }
  536. LOGGER(LOG_LEVEL_WARNING, _T("{FsProxy}: 没有空闲中继通道,起始索引=%d,当前索引=%d,中继总数量=%d,忙通道数量=%d"), CurPos, PosStatic, m_ArrayTrunk.GetCount(), BusyTruckCount);
  537. //2019.3.7
  538. PosStatic = CurPos;
  539. for (int i = 0; i < m_ArrayTrunk.GetCount(); ++i)
  540. {
  541. // 保证POS是有效的
  542. if (PosStatic >= m_ArrayTrunk.GetCount())
  543. PosStatic = 0;
  544. CChanTrunk* pTrunk = m_ArrayTrunk[PosStatic++];
  545. ASSERT(pTrunk != NULL);
  546. // 当前外线是否空闲
  547. if (pTrunk->state() == CHAN_LOGIC_STATE_FREE)
  548. {
  549. if (pTrunk->currOp() != NULL) {
  550. COperationReactor::GetInstance().releaseOpResult(pTrunk->currOp());
  551. pTrunk->releaseOp(pTrunk->currOp());
  552. LOGGER(LOG_LEVEL_WARNING, _T("{FsProxy}:没有空闲中继通道,通道[%u],释放操作."), pTrunk->no());
  553. }
  554. return pTrunk;
  555. }
  556. }
  557. LOGGER(LOG_LEVEL_WARNING, _T("{FsProxy}: 没有空闲中继通道,起始索引=%d,当前索引=%d"), CurPos, PosStatic);
  558. return NULL;
  559. }
  560. /*****************************************************************
  561. **【函数名称】 getAssoChanInSession
  562. **【函数功能】 获取会话中关联通道
  563. **【参数】
  564. **【返回值】
  565. ****************************************************************/
  566. CVirtualChan* CFsProxy::getAssoChanInSession( CVirtualChan* pChan )
  567. {
  568. CSession* pSession = __getSession(pChan->sessionId());
  569. if(pSession != NULL)
  570. return pSession->getAssoChan(pChan);
  571. else
  572. return NULL;
  573. }
  574. /*****************************************************************
  575. **【函数名称】 getBusyChan
  576. **【函数功能】 获取忙通道
  577. **【参数】
  578. **【返回值】
  579. *****************************************************************/
  580. CVirtualChan* CFsProxy::getBusyChan( LPCTSTR ChanId )
  581. {
  582. CVirtualChan* pBusyChan = NULL;
  583. m_MapBusyChan.Lookup(ChanId, pBusyChan);
  584. return pBusyChan;
  585. }
  586. /*****************************************************************
  587. **【函数名称】 regBusyChan
  588. **【函数功能】 登记忙通道
  589. **【参数】
  590. **【返回值】
  591. *****************************************************************/
  592. void CFsProxy::regBusyChan( CVirtualChan* pChan )
  593. {
  594. m_MapBusyChan.SetAt(pChan->chanId(), pChan);
  595. }
  596. /*****************************************************************
  597. **【函数名称】 unregBusyChan
  598. **【函数功能】 取消登记忙通道
  599. **【参数】
  600. **【返回值】
  601. *****************************************************************/
  602. void CFsProxy::unregBusyChan( CVirtualChan* pChan )
  603. {
  604. m_MapBusyChan.RemoveKey(pChan->chanId());
  605. }
  606. /*****************************************************************
  607. **【函数名称】 ExtenCall
  608. **【函数功能】 分机呼叫
  609. **【参数】
  610. **【返回值】
  611. ****************************************************************/
  612. bool CFsProxy::ExtenCall( LONG JobId, CVirtualChan* pChan, LPCTSTR CallerNum, LPCTSTR CalleeNum )
  613. {
  614. CString EslCmd;
  615. EslCmd.Format(_T("bgapi originate {origination_caller_id_number=%lu}user/%lu %s XML %s\r\n%s: %ld"),
  616. pChan->no(), pChan->no(), CalleeNum, CConfig::extContext(), ESL_HEADER_JOB_UUID, JobId);
  617. return m_Gateway.sendCmd(EslCmd);
  618. }
  619. /*****************************************************************
  620. **【函数名称】 PredictionCall
  621. **【函数功能】 预测外呼
  622. **【参数】
  623. **【返回值】
  624. ****************************************************************/
  625. bool CFsProxy::PredictionCall( LONG JobId, CString CallerNum, CString CalleeNum )
  626. {
  627. CString CallString;
  628. if(!m_CallStringMaker.makeCallStringWithDefault(CallerNum, CalleeNum, CallString))
  629. return false;
  630. CString EslCmd;
  631. EslCmd.Format(_T("bgapi originate {origination_caller_id_number=%s,%s=%ld}%s %s XML %s\r\n%s: %ld"),
  632. CallerNum, ESL_VAR_OP_INSTANCE, JobId, CallString, CalleeNum, CConfig::pCallContext(), ESL_HEADER_JOB_UUID, JobId);
  633. return m_Gateway.sendCmd(EslCmd);
  634. }
  635. /*****************************************************************
  636. **【函数名称】 answer
  637. **【函数功能】 应答通道
  638. **【参数】
  639. **【返回值】
  640. ****************************************************************/
  641. bool CFsProxy::answer( LONG JobId, CVirtualChan* pChan )
  642. {
  643. return false;
  644. }
  645. /*****************************************************************
  646. **【函数名称】 kill
  647. **【函数功能】 挂断通道
  648. **【参数】
  649. **【返回值】
  650. ****************************************************************/
  651. bool CFsProxy::kill( LONG JobId, CVirtualChan* pChan )
  652. {
  653. return __kill(JobId, pChan->chanId());
  654. }
  655. /*****************************************************************
  656. **【函数名称】 consult
  657. **【函数功能】 协商呼叫
  658. **【参数】
  659. **【返回值】
  660. ****************************************************************/
  661. bool CFsProxy::consult( LONG JobId, CVirtualChan* pChan, CString DestNum )
  662. {
  663. CString CallerNum;
  664. CString CallString;
  665. if(!m_CallStringMaker.makeCallString(CallerNum, DestNum, CallString))
  666. return false;
  667. CString EslCmd;
  668. EslCmd.Format(_T("bgapi uuid_broadcast %s att_xfer::%s\r\n%s: %ld"), pChan->chanId(), CallString, ESL_HEADER_JOB_UUID, JobId);
  669. return m_Gateway.sendCmd(EslCmd);
  670. }
  671. /*****************************************************************
  672. **【函数名称】 insert
  673. **【函数功能】 强插
  674. **【参数】
  675. **【返回值】
  676. ****************************************************************/
  677. bool CFsProxy::insert( LONG JobId, CVirtualChan* pChan, LPCTSTR DestSessionId )
  678. {
  679. CString EslCmd;
  680. EslCmd.Format(_T("bgapi originate {origination_caller_id_number=%lu}user/%lu &three_way(%s)\r\n%s: %ld"),
  681. pChan->no(), pChan->no(), DestSessionId, ESL_HEADER_JOB_UUID, JobId);
  682. return m_Gateway.sendCmd(EslCmd);
  683. }
  684. /*****************************************************************
  685. **【函数名称】 intercept
  686. **【函数功能】 强截
  687. **【参数】
  688. **【返回值】
  689. ****************************************************************/
  690. bool CFsProxy::intercept( LONG JobId, CVirtualChan* pChan, LPCTSTR DestChanId )
  691. {
  692. CString EslCmd;
  693. EslCmd.Format(_T("bgapi originate {origination_caller_id_number=%lu}user/%lu &intercept(%s)\r\n%s: %ld"),
  694. pChan->no(), pChan->no(), DestChanId, ESL_HEADER_JOB_UUID, JobId);
  695. return m_Gateway.sendCmd(EslCmd);
  696. }
  697. /*****************************************************************
  698. **【函数名称】 listen
  699. **【函数功能】 监听
  700. **【参数】
  701. **【返回值】
  702. ****************************************************************/
  703. bool CFsProxy::listen( LONG JobId, CVirtualChan* pChan, LPCTSTR DestChanId )
  704. {
  705. CString EslCmd;
  706. EslCmd.Format(_T("bgapi originate {origination_caller_id_number=%lu}user/%lu &eavesdrop(%s)\r\n%s: %ld"),
  707. pChan->no(), pChan->no(), DestChanId, ESL_HEADER_JOB_UUID, JobId);
  708. return m_Gateway.sendCmd(EslCmd);
  709. }
  710. // ych
  711. std::string CFsProxy::EslCommand(std::string strFsIp, int FsPort, std::string strName, std::string strPsWd, std::string strCommand)
  712. {
  713. if (!m_EslHandle.connected)
  714. {
  715. esl_connect(&m_EslHandle, strFsIp.c_str(), FsPort, strName.c_str(), strPsWd.c_str());
  716. }
  717. if (m_EslHandle.connected)
  718. {
  719. esl_send_recv_timed(&m_EslHandle, strCommand.c_str(), 2000);
  720. if (m_EslHandle.last_sr_event && m_EslHandle.last_sr_event->body)
  721. {
  722. std::string strRet = m_EslHandle.last_sr_event->body;
  723. return strRet;
  724. }
  725. }
  726. return "";
  727. }
  728. /*****************************************************************
  729. **【函数名称】 meeting
  730. **【函数功能】 会议
  731. **【参数】
  732. **【返回值】
  733. ****************************************************************/
  734. bool CFsProxy::meeting( LONG JobId, CString CallerNum, CString DestNum, LPCTSTR MeetingId )
  735. {
  736. bool bMatchPrefix = m_CallStringMaker.isMatchPrefix(DestNum);
  737. TRUNK_MATCH* pMatch = NULL;
  738. CString CallString;
  739. if (!m_CallStringMaker.makeCallString(CallerNum, DestNum, CallString, pMatch))
  740. return false;
  741. if (pMatch != NULL)
  742. {
  743. SIP_ACCOUNT* pAccount = CConfig::sipAccount().getAccount(pMatch->TrunkItemId);
  744. if (bMatchPrefix && pAccount != NULL && pAccount->IsDynamicGw) // 外线且动态网关
  745. {
  746. std::string strSipAccount = pAccount->Account;
  747. std::string strGwIp = EslCommand(CConfig::fsAddr(), CConfig::fsPort(), "", CConfig::fsPwd(), "api sofia_contact " + strSipAccount);
  748. if (!strGwIp.empty())
  749. {
  750. size_t Index = strGwIp.find_first_of('@');
  751. if (Index != std::string::npos)
  752. {
  753. strGwIp = strGwIp.substr(Index);
  754. CallString = "sofia/internal/";
  755. CallString += DestNum;
  756. CallString += strGwIp.c_str();
  757. }
  758. }
  759. }
  760. }
  761. LOGGER(LOG_LEVEL_NORMAL, _T("{FsProxy}: 三方会议呼叫字符串: %s"), CallString);
  762. CString EslCmd;
  763. EslCmd.Format(_T("bgapi originate {origination_caller_id_number=%s,%s=%ld}%s %s XML %s\r\n%s: %ld"),
  764. CallerNum, ESL_VAR_OP_INSTANCE, JobId, CallString, MeetingId, CConfig::meetingContext(), ESL_HEADER_JOB_UUID, JobId);
  765. return m_Gateway.sendCmd(EslCmd);
  766. }
  767. /*****************************************************************
  768. **【函数名称】 muteOn
  769. **【函数功能】 静音
  770. **【参数】
  771. **【返回值】
  772. ****************************************************************/
  773. bool CFsProxy::muteOn( LONG JobId, CVirtualChan* pChan )
  774. {
  775. CString EslCmd;
  776. EslCmd.Format(_T("bgapi uuid_audio %s start write mute -4\r\n%s: %ld"), pChan->chanId(), ESL_HEADER_JOB_UUID, JobId);
  777. return m_Gateway.sendCmd(EslCmd);
  778. }
  779. /*****************************************************************
  780. **【函数名称】 muteOff
  781. **【函数功能】 取消静音
  782. **【参数】
  783. **【返回值】
  784. ****************************************************************/
  785. bool CFsProxy::muteOff( LONG JobId, CVirtualChan* pChan )
  786. {
  787. CString EslCmd;
  788. EslCmd.Format(_T("bgapi uuid_audio %s stop write mute -4\r\n%s: %ld"), pChan->chanId(), ESL_HEADER_JOB_UUID, JobId);
  789. return m_Gateway.sendCmd(EslCmd);
  790. }
  791. /*****************************************************************
  792. **【函数名称】 holdon
  793. **【函数功能】 保持
  794. **【参数】
  795. **【返回值】
  796. ****************************************************************/
  797. bool CFsProxy::holdon( LONG JobId, CVirtualChan* pChan )
  798. {
  799. CString EslCmd;
  800. EslCmd.Format(_T("bgapi uuid_hold %s\r\n%s: %ld"), pChan->chanId(), ESL_HEADER_JOB_UUID, JobId);
  801. return m_Gateway.sendCmd(EslCmd);
  802. }
  803. /*****************************************************************
  804. **【函数名称】 takeBack
  805. **【函数功能】 接回
  806. **【参数】
  807. **【返回值】
  808. ****************************************************************/
  809. bool CFsProxy::takeBack( LONG JobId, CVirtualChan* pChan )
  810. {
  811. CString EslCmd;
  812. EslCmd.Format(_T("bgapi uuid_hold off %s\r\n%s: %ld"), pChan->chanId(), ESL_HEADER_JOB_UUID, JobId);
  813. return m_Gateway.sendCmd(EslCmd);
  814. }
  815. /*****************************************************************
  816. **【函数名称】 record
  817. **【函数功能】 录音
  818. **【参数】
  819. **【返回值】
  820. ****************************************************************/
  821. bool CFsProxy::record( LONG JobId, CVirtualChan* pChan, LPCTSTR RcdFile )
  822. {
  823. CString EslCmd;
  824. EslCmd.Format(_T("bgapi uuid_record %s start %s\r\n%s: %ld"), pChan->chanId(), RcdFile, ESL_HEADER_JOB_UUID, JobId);
  825. return m_Gateway.sendCmd(EslCmd);
  826. }
  827. /*****************************************************************
  828. **【函数名称】 transfer
  829. **【函数功能】 呼叫转移
  830. **【参数】
  831. **【返回值】
  832. ****************************************************************/
  833. bool CFsProxy::transfer( LONG JobId, CVirtualChan* pChan, LPCTSTR DestNum )
  834. {
  835. CString EslCmd;
  836. EslCmd.Format(_T("bgapi uuid_transfer %s %s xml %s\r\n%s: %ld"), pChan->chanId(), DestNum, CConfig::extContext(), ESL_HEADER_JOB_UUID, JobId);
  837. return m_Gateway.sendCmd(EslCmd);
  838. }
  839. /*****************************************************************
  840. **【函数名称】 transfer2Context
  841. **【函数功能】 转移通道至其它Context
  842. **【参数】
  843. **【返回值】
  844. ****************************************************************/
  845. bool CFsProxy::transfer2Context( LONG JobId, LPCTSTR DestChanId, LPCTSTR Exten, LPCTSTR Context, bool BothSide /*= false*/ )
  846. {
  847. CString EslCmd;
  848. if(BothSide)
  849. EslCmd.Format(_T("bgapi uuid_transfer %s -both %s xml %s\r\n%s: %ld"), DestChanId, Exten, Context, ESL_HEADER_JOB_UUID, JobId);
  850. else
  851. EslCmd.Format(_T("bgapi uuid_transfer %s %s xml %s\r\n%s: %ld"), DestChanId, Exten, Context, ESL_HEADER_JOB_UUID, JobId);
  852. return m_Gateway.sendCmd(EslCmd);
  853. }
  854. /*****************************************************************
  855. **【函数名称】 cancel
  856. **【函数功能】 取消当前执行的应用
  857. **【参数】
  858. **【返回值】
  859. ****************************************************************/
  860. bool CFsProxy::cancel( CChanTrunk* pChan )
  861. {
  862. ASSERT(pChan != NULL);
  863. return m_Gateway.Execte2(ESL_APP_BREAK,NULL,pChan->chanId());
  864. }
  865. /*****************************************************************
  866. **【函数名称】 hangup
  867. **【函数功能】 挂机
  868. **【参数】
  869. **【返回值】
  870. ****************************************************************/
  871. bool CFsProxy::hangup( CChanTrunk* pChan )
  872. {
  873. ASSERT(pChan != NULL);
  874. return m_Gateway.execute(pChan->m_pEslHandle,ESL_APP_HANGUP,NULL);
  875. }
  876. /*****************************************************************
  877. **【函数名称】 leaveWord
  878. **【函数功能】 留言
  879. **【参数】
  880. **【返回值】
  881. ****************************************************************/
  882. bool CFsProxy::leaveWord( CChanTrunk* pChan, LPCTSTR FileName, UINT LimitTime, TCHAR FinishKey )
  883. {
  884. ASSERT(pChan != NULL);
  885. CString Param;
  886. Param.Format(_T("playback_terminators=%c"), FinishKey);
  887. m_Gateway.Execte2(ESL_APP_SET,Param,pChan->chanId());
  888. Param.Format(_T("%s %lu"), FileName, LimitTime);
  889. return m_Gateway.Execte2(ESL_APP_LEAVEWORD,Param,pChan->chanId());
  890. }
  891. /*****************************************************************
  892. **【函数名称】 playAndDtmf
  893. **【函数功能】 放音收按键
  894. **【参数】
  895. **【返回值】
  896. ****************************************************************/
  897. bool CFsProxy::playAndDtmf( CChanTrunk* pChan, PlayVoiceContent* pPlayContent )
  898. {
  899. ASSERT(pChan != NULL);
  900. ASSERT(pPlayContent != NULL);
  901. if(pChan==NULL||pPlayContent==NULL) return false;
  902. TCHAR AudioFile[MAX_PATH] = { 0 };
  903. // 如果使用了TTS,进行TTS转换
  904. switch(pPlayContent->nTts)
  905. {
  906. default:
  907. case PLAY_CONTENT_AUDIO: // 不使用TTS
  908. lstrcpy(AudioFile, pPlayContent->szFileName);
  909. break;
  910. case PLAY_CONTENT_TTS_STR: // TTS文本
  911. {
  912. ITtsInterface::getInstance().setTTSParam(pPlayContent->nTtsDigitMode, pPlayContent->nTtsSpeed, pPlayContent->nTtsVolume);
  913. if(!ITtsInterface::getInstance().string2Audio(pPlayContent->szFileName, AudioFile, MAX_PATH))
  914. {
  915. LOGGER(LOG_LEVEL_WARNING, _T("{FsProxy}: 中继通道[%lu]放音时TTS文本转换失败"), pChan->no());
  916. return false;
  917. }
  918. }
  919. break;
  920. case PLAY_CONTENT_TTS_FILE: // TTS文件
  921. {
  922. ITtsInterface::getInstance().setTTSParam(pPlayContent->nTtsDigitMode, pPlayContent->nTtsSpeed, pPlayContent->nTtsVolume);
  923. if(!ITtsInterface::getInstance().file2Audio(pPlayContent->szFileName, AudioFile, MAX_PATH))
  924. {
  925. LOGGER(LOG_LEVEL_WARNING, _T("{FsProxy}: 中继通道[%lu]放音时TTS文件转换失败, File = %s"), pChan->no(), pPlayContent->szFileName);
  926. return false;
  927. }
  928. }
  929. break;
  930. }
  931. CString Param;
  932. if(pPlayContent->nModel == PVM_PLAY_ONLY && pPlayContent->cDtmfEnd == 0)
  933. {
  934. Param.Format(_T("playback_terminators=none"));
  935. m_Gateway.Execte2(ESL_APP_SET,Param,pChan->chanId());
  936. //m_Gateway.execute(pChan->m_pEslHandle,ESL_APP_SET,Param);
  937. Param.Format(_T("%s"), AudioFile);
  938. return m_Gateway.Execte2(ESL_APP_PLAY,Param,pChan->chanId());
  939. //return m_Gateway.execute(pChan->m_pEslHandle,ESL_APP_PLAY,Param);
  940. }
  941. else
  942. {
  943. Param.Format(_T("%lu %lu 1 %lu %c %s silence_stream://250 %s"), pPlayContent->nDtmfCount, pPlayContent->nDtmfCount,
  944. pPlayContent->nDtmfCount * pPlayContent->nDtmfPeriod * 1000, pPlayContent->cDtmfEnd, AudioFile, ESL_VAR_DTMF_KEY);
  945. return m_Gateway.Execte2(ESL_APP_PLAY_DTMF,Param,pChan->chanId());
  946. //return m_Gateway.execute(pChan->m_pEslHandle,ESL_APP_PLAY_DTMF,Param);
  947. }
  948. }
  949. /*****************************************************************
  950. **【函数名称】 bridge
  951. **【函数功能】 桥接通道
  952. **【参数】
  953. **【返回值】
  954. ****************************************************************/
  955. bool CFsProxy::bridge( CChanTrunk* pChan, CString CallerNum, CString CalleeNum )
  956. {
  957. CString CallString;
  958. if(!m_CallStringMaker.makeCallString(CallerNum, CalleeNum, CallString))
  959. return false;
  960. CString Param;
  961. Param.Format(_T("ringback=${us-ring}"));
  962. m_Gateway.Execte2(ESL_APP_SET,Param,pChan->chanId());
  963. return m_Gateway.Execte2(ESL_APP_BRIDGE,CallString,pChan->chanId());
  964. }