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

CallSession.cpp 31KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132
  1. #include "StdAfx.h"
  2. #include "CallSession.h"
  3. #include "MC.h"
  4. #include "ProxyShell.h"
  5. #include "ConsultSession.h"
  6. #include "MeetingSession.h"
  7. #include "DirectSession.h"
  8. #include "TransferSession.h"
  9. #include "TrunkSession.h"
  10. #include "Config.h"
  11. #include "VirtualProxy.h"
  12. CCallSession::CCallSession(long SessionId) : m_Id(SessionId), m_SubCallIndex(0)
  13. {
  14. ZeroMemory(&m_MeetingId, sizeof(MeetingInfo));
  15. m_MeetingId.MeetingId = MEETING_ID_INVALID;
  16. }
  17. CCallSession::~CCallSession(void)
  18. {
  19. __clearSubSession();
  20. }
  21. /*****************************************************************
  22. **【函数名称】 __isLineMine
  23. **【函数功能】 指定线路是否属于当前会话
  24. **【参数】 LineId 要查找的线路ID
  25. **【返回值】
  26. *****************************************************************/
  27. CALL_PARTY_TYPE CCallSession::__isLineMine( CRDRID LineId )
  28. {
  29. int Type;
  30. if(m_LineMap.Lookup(LineId, Type))
  31. return (CALL_PARTY_TYPE)Type;
  32. else
  33. return CALL_PARTY_UNKNOWN;
  34. }
  35. /*****************************************************************
  36. **【函数名称】 __GetSubCall
  37. **【函数功能】 通过待处理线路ID查找子呼叫
  38. **【参数】 PendingLine 通话待处理线路ID
  39. **【返回值】
  40. *****************************************************************/
  41. CSubSession* CCallSession::__getSubSession(CRDRID PendingLine)
  42. {
  43. UINT SubCall = 0;
  44. CSubSession* pSubCall = NULL;
  45. // 找到子呼叫的ID
  46. if(!m_PendingLineMap.Lookup(PendingLine, SubCall))
  47. return NULL;
  48. // 查找子呼叫指针
  49. m_SubCallMap.Lookup(SubCall, pSubCall);
  50. return pSubCall;
  51. }
  52. /*****************************************************************
  53. **【函数名称】 __clearSubSession
  54. **【函数功能】 释放所有子会话
  55. **【参数】
  56. **【返回值】
  57. *****************************************************************/
  58. void CCallSession::__clearSubSession( void )
  59. {
  60. UINT Key = 0;
  61. CSubSession* pSub = NULL;
  62. POSITION pos = m_SubCallMap.GetStartPosition();
  63. while(pos != NULL)
  64. {
  65. m_SubCallMap.GetNextAssoc(pos, Key, pSub);
  66. ASSERT(pSub != NULL);
  67. delete pSub;
  68. } // end while
  69. m_SubCallMap.RemoveAll();
  70. }
  71. /*****************************************************************
  72. **【函数名称】 __notifySubSessionLineFree
  73. **【函数功能】 通知子会话相关线路空闲
  74. **【参数】
  75. **【返回值】
  76. *****************************************************************/
  77. void CCallSession::__notifySubSessionLineFree( CRDRID LineId )
  78. {
  79. UINT Key = 0;
  80. CSubSession* pSub = NULL;
  81. POSITION pos = m_SubCallMap.GetStartPosition();
  82. while(pos != NULL)
  83. {
  84. m_SubCallMap.GetNextAssoc(pos, Key, pSub);
  85. ASSERT(pSub != NULL);
  86. if(pSub->getSubHostLine() == LineId)
  87. pSub->onHostLineStateFree();
  88. else if(pSub->getSubPeerLine() == LineId)
  89. pSub->onPeerLineStateFree();
  90. } // end while
  91. }
  92. /*****************************************************************
  93. **【函数名称】 __lineDoRecord
  94. **【函数功能】 执行录音操作
  95. **【参数】 HostLine 录音线路
  96. lpFileName 录音文件名
  97. **【返回值】
  98. *****************************************************************/
  99. bool CCallSession::__lineRecord(CRDRID HostLine, LPCTSTR lpFileName)
  100. {
  101. // 填充录音参数
  102. RecordContent content;
  103. memset(&content, 0, sizeof(RecordContent));
  104. lstrcpy(content.szFileName, lpFileName);
  105. content.nTaskId = RECORD_TASK_ID_NORMAL;
  106. CALL_PARTY_TYPE Party = __isLineMine(HostLine);
  107. switch(Party)
  108. {
  109. case CALL_PARTY_HOST: // 主控线路
  110. {
  111. content.nModel = RECORD_MODE_NORMAL;
  112. content.nPeerLine = m_LinePeer;
  113. }
  114. break;
  115. case CALL_PARTY_PEER: // 对端线路
  116. {
  117. content.nModel = RECORD_MODE_NORMAL;
  118. content.nPeerLine = m_LineHost;
  119. }
  120. break;
  121. case CALL_PARTY_MEETING: // 会议线路
  122. {
  123. content.nModel = RECORD_MODE_MEETING;
  124. }
  125. break;
  126. case CALL_PARTY_PENDING:
  127. {
  128. content.nModel = RECORD_MODE_NORMAL;
  129. CSubSession * pSubCall = __getSubSession(HostLine);
  130. content.nPeerLine = pSubCall->getSubHostLine();
  131. }
  132. break;
  133. } // end switch
  134. // 启动录音
  135. return CMC::GetInstance().startRecord(HostLine, &content);
  136. }
  137. /*****************************************************************
  138. **【函数名称】 __LineDoMute
  139. **【函数功能】 线路静音操作
  140. **【参数】 HostLine 静音线路
  141. IsBegin 静音启动/结束
  142. **【返回值】
  143. *****************************************************************/
  144. bool CCallSession::__lineMute(CRDRID HostLine, bool IsOn)
  145. {
  146. // 查询对端线路
  147. DEV_RES_ID AssoLine = getPeerLine(HostLine);
  148. if(AssoLine.isEmpty())
  149. return false;
  150. // 静音控制
  151. if(IsOn)
  152. {
  153. // 断开通话
  154. CMC::GetInstance().bridgeDevice(HostLine, AssoLine, false);
  155. // 对端线路播放保持音
  156. CMC::GetInstance().playTone(AssoLine, CHANNEL_TONE_HOLD);
  157. }
  158. else
  159. {
  160. // 停止放音
  161. CMC::GetInstance().playStop(AssoLine);
  162. // 重连通话
  163. CMC::GetInstance().bridgeDevice(HostLine, AssoLine, true);
  164. } // end if
  165. return true;
  166. }
  167. /*****************************************************************
  168. **【函数名称】 __meetingMute
  169. **【函数功能】 会议静音操作
  170. **【参数】 HostLine 静音线路
  171. IsBegin 静音启动/结束
  172. **【返回值】
  173. *****************************************************************/
  174. bool CCallSession::__meetingMute(CRDRID HostLine, bool IsOn)
  175. {
  176. return CMC::GetInstance().meetingMute(HostLine, m_MeetingId, !IsOn);
  177. }
  178. /*****************************************************************
  179. **【函数名称】 __line2Link
  180. **【函数功能】 线路进入双向通话
  181. **【参数】 LineId 要进入通话的线路ID
  182. LinePeeer 要进行通话的对端线路
  183. **【返回值】
  184. *****************************************************************/
  185. bool CCallSession::__line2Link(CRDRID LineId, CRDRID LinePeer)
  186. {
  187. CString strRecFile;
  188. // 当前录音采用混音模式,原线路在录音时不影响线路之间通话的建立,故不需停止当前录音,
  189. // 因此注释一下三行。
  190. //// 停止当前录音
  191. //if(m_RecordMap.Lookup(LinePeer, strRecFile))
  192. // CMC::GetInstance().stopRecord(LinePeer);
  193. // 线路双向连通
  194. return CMC::GetInstance().bridgeDevice(LineId, LinePeer, true);
  195. }
  196. /*****************************************************************
  197. **【函数名称】 __detachListen
  198. **【函数功能】 解除指定线路的监听
  199. **【参数】 HostLine 当前挂机的线路
  200. **【返回值】
  201. *****************************************************************/
  202. void CCallSession::__detachListen(CRDRID HostLine)
  203. {
  204. POSITION pos = m_ListenLineMap.GetStartPosition();
  205. while(pos != NULL)
  206. {
  207. DEV_RES_ID DevId;
  208. DEV_RES_ID LineListen;
  209. m_ListenLineMap.GetNextAssoc(pos, LineListen, DevId);
  210. if(DevId == HostLine)
  211. CMC::GetInstance().dropCall(LineListen, false); // 监听线路挂机
  212. }
  213. }
  214. /*****************************************************************
  215. **【函数名称】 getPeerLine
  216. **【函数功能】 获取当前线路关联的对端线路
  217. **【参数】 LineId 要查询的线路
  218. **【返回值】 0 -> 无对端线路
  219. *****************************************************************/
  220. DEV_RES_ID CCallSession::getPeerLine(CRDRID LineId)
  221. {
  222. // 当前线路在会话中的职责
  223. DEV_RES_ID AssoLine;
  224. CALL_PARTY_TYPE Party = __isLineMine(LineId);
  225. switch(Party)
  226. {
  227. case CALL_PARTY_HOST: // 主控线路
  228. AssoLine = m_LinePeer;
  229. break;
  230. case CALL_PARTY_PEER: // 对端线路
  231. AssoLine = m_LineHost;
  232. break;
  233. default: // 其它线路
  234. break;
  235. } // end switch
  236. return AssoLine;
  237. }
  238. /*****************************************************************
  239. **【函数名称】 IsExist
  240. **【函数功能】 指定职责的线路是否在会话中
  241. **【参数】 LineId 要查询的线路ID
  242. PartyType 线路在会话中的职责
  243. **【返回值】
  244. *****************************************************************/
  245. bool CCallSession::isExist(CRDRID LineId, CALL_PARTY_TYPE PartyType)
  246. {
  247. int Type;
  248. if(m_LineMap.Lookup(LineId, Type))
  249. {
  250. return PartyType == (CALL_PARTY_TYPE)Type;
  251. }
  252. else
  253. {
  254. return false;
  255. }
  256. }
  257. /*****************************************************************
  258. **【函数名称】 onLineStateChanged
  259. **【函数功能】 线路状态变化事件处理
  260. **【参数】 LineId 状态变化的线路ID
  261. LineState 线路当前状态
  262. lpCallerNum 主叫号码
  263. lpCallerNum 被叫号码
  264. **【返回值】
  265. *****************************************************************/
  266. void CCallSession::onLineStateChanged(CRDRID LineId, VIRTUAL_LINE_STATE LineState, LPCTSTR lpCallerNum, LPCTSTR lpCalleeNum)
  267. {
  268. // 根据线路物理状态进行分类处理
  269. switch(LineState)
  270. {
  271. case VIRTUAL_LINE_STATE_FREE:
  272. __onLineStateFree(LineId, lpCallerNum, lpCalleeNum);
  273. break;
  274. case VIRTUAL_LINE_STATE_INIT:
  275. case VIRTUAL_LINE_STATE_DIALING:
  276. case VIRTUAL_LINE_STATE_DISABLED:
  277. CProxyShell::GetInstance().onLineStateUpdated(LineId, m_Id, SESSION_INVALID_SUB_CALL, LineState, lpCallerNum, lpCalleeNum);
  278. break;
  279. case VIRTUAL_LINE_STATE_RING_BACK:
  280. __onLineStateRingBack(LineId, lpCallerNum, lpCalleeNum);
  281. break;
  282. case VIRTUAL_LINE_STATE_ALERTING:
  283. __onLineStateAlerting(LineId, lpCallerNum, lpCalleeNum);
  284. break;
  285. case VIRTUAL_LINE_STATE_PROGRESSING:
  286. __onLineStateProgressing(LineId, lpCallerNum, lpCalleeNum);
  287. break;
  288. case VIRTUAL_LINE_STATE_TALKING:
  289. //__setTimer(0,1000*60*10); //鹤壁12345 通话不能超过10分钟
  290. __onLineStateTalking(LineId, lpCallerNum, lpCalleeNum);
  291. break;
  292. } // end switch
  293. }
  294. /*****************************************************************
  295. **【函数名称】 onRecordStop
  296. **【函数功能】 录音停止事件
  297. **【参数】 LineId 录音停止的线路ID
  298. TaskId 录音启动时的任务ID
  299. **【返回值】
  300. *****************************************************************/
  301. void CCallSession::onRecordStop(CRDRID LineId, UINT TaskId)
  302. {
  303. if(TaskId == RECORD_TASK_ID_LEAVEWORD)
  304. CProxyShell::GetInstance().onDevChannelEvent(LineId, DEV_CH_EVT_REC_END, NULL, 0);
  305. }
  306. /*****************************************************************
  307. **【函数名称】 __onLineStateFree
  308. **【函数功能】 线路状态处理【空闲】
  309. **【参数】 nLineId 状态变化的线路ID
  310. lpCallerNum 主叫号码
  311. lpCallerNum 被叫号码
  312. **【返回值】
  313. *****************************************************************/
  314. void CCallSession::__onLineStateFree(CRDRID LineId, LPCTSTR lpCallerNum, LPCTSTR lpCalleeNum)
  315. {
  316. // 获取线路在会话中的职责
  317. CALL_PARTY_TYPE Type = __isLineMine(LineId);
  318. // 清除线路录音
  319. m_RecordMap.RemoveKey(LineId);
  320. // 根据线路在会话中的职责进行分类处理
  321. switch(Type)
  322. {
  323. case CALL_PARTY_HOST: // 主控线路
  324. case CALL_PARTY_PEER: // 对端线路
  325. {
  326. removeLine(LineId, Type); // 从会话中删除线路
  327. CProxyShell::GetInstance().onLineStateUpdated(LineId, m_Id, SESSION_INVALID_SUB_CALL, VIRTUAL_LINE_STATE_FREE);
  328. // 对端线路挂机
  329. DEV_RES_ID AssoLine = (Type == CALL_PARTY_HOST) ? m_LinePeer : m_LineHost;
  330. if(!AssoLine.isEmpty())
  331. CMC::GetInstance().dropCall(AssoLine, true);
  332. }
  333. break;
  334. case CALL_PARTY_PENDING: // 操作待处理线路
  335. {
  336. CSubSession* pSubCall = __getSubSession(LineId);
  337. ASSERT(pSubCall != NULL);
  338. removeLine(LineId, Type); // 从会话中删除线路
  339. if(pSubCall != NULL)
  340. pSubCall->onPendingLineState(VIRTUAL_LINE_STATE_FREE);
  341. }
  342. break;
  343. case CALL_PARTY_LISTEN: // 通话的监听线路
  344. {
  345. removeLine(LineId, Type); // 从会话中删除线路
  346. CProxyShell::GetInstance().onLineStateUpdated(LineId, m_Id, SESSION_INVALID_SUB_CALL, VIRTUAL_LINE_STATE_FREE);
  347. }
  348. break;
  349. case CALL_PARTY_MEETING: // 会议中的线路
  350. {
  351. removeLine(LineId, Type); // 从会话中删除线路
  352. CProxyShell::GetInstance().onLineStateUpdated(LineId, m_Id, SESSION_INVALID_SUB_CALL, VIRTUAL_LINE_STATE_FREE);
  353. // 如果会议中只剩下一条线路,线路中可能存在监听线路
  354. if(lineCount() == 1 && m_ListenLineMap.GetSize() > 0)
  355. {
  356. const CMap<DEV_RES_ID, CRDRID, DEV_RES_ID, CRDRID>::CPair* pLastListenLine = m_ListenLineMap.PGetFirstAssoc();
  357. ASSERT(pLastListenLine != NULL);
  358. // 挂断此线路
  359. CMC::GetInstance().dropCall(pLastListenLine->key, true);
  360. } // end if
  361. }
  362. break;
  363. default:
  364. CProxyShell::GetInstance().onLineStateUpdated(LineId, m_Id, SESSION_INVALID_SUB_CALL, VIRTUAL_LINE_STATE_FREE, lpCallerNum, lpCalleeNum);
  365. break;
  366. } // end switch
  367. __notifySubSessionLineFree(LineId);
  368. CMC::GetInstance().freeChanResource(LineId);
  369. }
  370. /*****************************************************************
  371. **【函数名称】 __onLineStateAlerting
  372. **【函数功能】 线路状态处理【来电振铃】
  373. **【参数】 LineId 状态变化的线路ID
  374. lpCallerNum 主叫号码
  375. lpCallerNum 被叫号码
  376. **【返回值】
  377. *****************************************************************/
  378. void CCallSession::__onLineStateAlerting(CRDRID LineId, LPCTSTR lpCallerNum, LPCTSTR lpCalleeNum)
  379. {
  380. // 获取线路在会话中的职责
  381. CALL_PARTY_TYPE Type = __isLineMine(LineId);
  382. switch(Type)
  383. {
  384. case CALL_PARTY_HOST: // 主控线路
  385. {
  386. CProxyShell::GetInstance().onLineStateUpdated(LineId, m_Id, SESSION_INVALID_SUB_CALL, VIRTUAL_LINE_STATE_ALERTING, lpCallerNum, lpCalleeNum);
  387. }
  388. break;
  389. case CALL_PARTY_PEER: // 通话对端线路
  390. break;
  391. case CALL_PARTY_LISTEN: // 通话的监听线路
  392. break;
  393. case CALL_PARTY_PENDING: // 操作待处理线路
  394. {
  395. CSubSession* pSubCall = __getSubSession(LineId);
  396. ASSERT(pSubCall != NULL);
  397. pSubCall->onPendingLineState(VIRTUAL_LINE_STATE_ALERTING);
  398. }
  399. break;
  400. case CALL_PARTY_MEETING: // 会议中的线路
  401. break;
  402. default:
  403. ASSERT(FALSE);
  404. break;
  405. } // end switch
  406. }
  407. /*****************************************************************
  408. **【函数名称】 __onLineStateProgressing
  409. **【函数功能】 线路状态处理【通话进展】
  410. **【参数】 LineId 状态变化的线路ID
  411. lpCallerNum 主叫号码
  412. lpCallerNum 被叫号码
  413. **【返回值】
  414. *****************************************************************/
  415. void CCallSession::__onLineStateProgressing( CRDRID LineId, LPCTSTR lpCallerNum, LPCTSTR lpCalleeNum )
  416. {
  417. // 获取线路在会话中的职责
  418. CALL_PARTY_TYPE Type = __isLineMine(LineId);
  419. if(Type == CALL_PARTY_PENDING)
  420. {
  421. CSubSession* pSubCall = __getSubSession(LineId);
  422. ASSERT(pSubCall != NULL);
  423. pSubCall->onPendingLineState(VIRTUAL_LINE_STATE_PROGRESSING);
  424. }
  425. }
  426. /*****************************************************************
  427. **【函数名称】 __onLineStateRingBack
  428. **【函数功能】 线路状态处理【呼出振铃】
  429. **【参数】 LineId 状态变化的线路ID
  430. lpCallerNum 主叫号码
  431. lpCallerNum 被叫号码
  432. **【返回值】
  433. *****************************************************************/
  434. void CCallSession::__onLineStateRingBack(CRDRID LineId, LPCTSTR lpCallerNum, LPCTSTR lpCalleeNum)
  435. {
  436. // 获取线路在会话中的职责
  437. CALL_PARTY_TYPE Type = __isLineMine(LineId);
  438. // 根据线路在会话中的职责进行分类处理
  439. switch(Type)
  440. {
  441. case CALL_PARTY_HOST: // 主控线路
  442. {
  443. CProxyShell::GetInstance().onLineStateUpdated(LineId, m_Id, SESSION_INVALID_SUB_CALL, VIRTUAL_LINE_STATE_RING_BACK, lpCallerNum, lpCalleeNum);
  444. }
  445. break;
  446. case CALL_PARTY_PEER: // 对端线路
  447. break;
  448. case CALL_PARTY_LISTEN: // 通话的监听线路
  449. break;
  450. case CALL_PARTY_PENDING: // 操作待处理线路
  451. {
  452. CSubSession* pSubCall = __getSubSession(LineId);
  453. ASSERT(pSubCall != NULL);
  454. pSubCall->onPendingLineState(VIRTUAL_LINE_STATE_RING_BACK);
  455. }
  456. break;
  457. case CALL_PARTY_MEETING: // 会议中的线路
  458. break;
  459. default:
  460. ASSERT(FALSE);
  461. } // end switch
  462. }
  463. /*****************************************************************
  464. **【函数名称】 __onLineStateTalking
  465. **【函数功能】 线路状态处理【通话】
  466. **【参数】 LineId 状态变化的线路ID
  467. lpCallerNum 主叫号码
  468. lpCallerNum 被叫号码
  469. **【返回值】
  470. *****************************************************************/
  471. void CCallSession::__onLineStateTalking(CRDRID LineId, LPCTSTR lpCallerNum, LPCTSTR lpCalleeNum)
  472. {
  473. // 获取线路在会话中的职责
  474. CALL_PARTY_TYPE Type = __isLineMine(LineId);
  475. switch(Type)
  476. {
  477. case CALL_PARTY_HOST: // 主控线路
  478. {
  479. CProxyShell::GetInstance().onLineStateUpdated(LineId, m_Id, SESSION_INVALID_SUB_CALL, VIRTUAL_LINE_STATE_TALKING, lpCallerNum, lpCalleeNum);
  480. }
  481. break;
  482. case CALL_PARTY_PEER: // 通话对端线路
  483. break;
  484. case CALL_PARTY_LISTEN: // 通话的监听线路
  485. break;
  486. case CALL_PARTY_PENDING: // 操作待处理线路
  487. {
  488. CSubSession* pSubCall = __getSubSession(LineId);
  489. ASSERT(pSubCall != NULL);
  490. pSubCall->onPendingLineState(VIRTUAL_LINE_STATE_TALKING);
  491. }
  492. break;
  493. case CALL_PARTY_MEETING: // 会议中的线路
  494. break;
  495. default:
  496. ASSERT(FALSE);
  497. break;
  498. } // end switch
  499. }
  500. /*****************************************************************
  501. **【函数名称】 insertLine
  502. **【函数功能】 添加待定线路到会话
  503. **【参数】 LineId 要添加的线路ID
  504. PartyType 新增线路在会话中的职责
  505. Info 附加信息
  506. IsLink 是否作通道连接
  507. **【返回值】
  508. *****************************************************************/
  509. bool CCallSession::insertLine(CRDRID LineId, UINT SessionId, bool IsLink)
  510. {
  511. // 通知当前线路关联呼叫
  512. CMC::GetInstance().setSessionInfo2Line(LineId, m_Id);
  513. CProxyShell::GetInstance().onNewCall(LineId, m_Id, SESSION_INVALID_SUB_CALL);
  514. m_LineMap[LineId] = CALL_PARTY_PENDING;
  515. m_PendingLineMap[LineId] = SessionId;
  516. return true;
  517. }
  518. /*****************************************************************
  519. **【函数名称】 insertLine
  520. **【函数功能】 添加指定线路到会话
  521. **【参数】 LineId 要添加的线路ID
  522. PartyType 新增线路在会话中的职责
  523. IsLink 是否作通道连接
  524. **【返回值】
  525. *****************************************************************/
  526. bool CCallSession::insertLine( CRDRID LineId, CALL_PARTY_TYPE PartyType, bool IsLink )
  527. {
  528. // 通知当前线路关联呼叫
  529. CMC::GetInstance().setSessionInfo2Line(LineId, m_Id);
  530. CProxyShell::GetInstance().onNewCall(LineId, m_Id, SESSION_INVALID_SUB_CALL);
  531. // 根据职责保存线路到指定位置
  532. switch(PartyType)
  533. {
  534. case CALL_PARTY_HOST: // 主控线路
  535. {
  536. m_LineHost = LineId;
  537. m_LineMap[LineId] = CALL_PARTY_HOST;
  538. if(!m_LinePeer.isEmpty() && IsLink)
  539. {
  540. if(!__line2Link(LineId, m_LinePeer))
  541. return false;
  542. }
  543. }
  544. break;
  545. case CALL_PARTY_PEER: // 通话对端线路
  546. {
  547. m_LinePeer = LineId;
  548. m_LineMap[LineId] = CALL_PARTY_PEER;
  549. if(!m_LineHost.isEmpty() && IsLink)
  550. {
  551. if(!__line2Link(LineId, m_LineHost))
  552. return false;
  553. }
  554. }
  555. break;
  556. case CALL_PARTY_MEETING: // 会议中的线路
  557. {
  558. m_LineMap[LineId] = CALL_PARTY_MEETING;
  559. if(!CMC::GetInstance().move2Meeting(LineId, m_MeetingId, false))
  560. return false;
  561. }
  562. break;
  563. } // end switch
  564. return true;
  565. }
  566. /*****************************************************************
  567. **【函数名称】 insertLine
  568. **【函数功能】 添加监听线路到会话
  569. **【参数】 LineId 要添加的线路ID
  570. PartyType 新增线路在会话中的职责
  571. IsLink 是否作通道连接
  572. **【返回值】
  573. *****************************************************************/
  574. bool CCallSession::insertLine( CRDRID HostLineId, CRDRID SrcLineId, bool IsLink )
  575. {
  576. // 通知当前线路关联呼叫
  577. CMC::GetInstance().setSessionInfo2Line(HostLineId, m_Id);
  578. CProxyShell::GetInstance().onNewCall(HostLineId, m_Id, SESSION_INVALID_SUB_CALL);
  579. m_LineMap[HostLineId] = CALL_PARTY_LISTEN;
  580. m_ListenLineMap[HostLineId] = SrcLineId;
  581. CALL_PARTY_TYPE Type = __isLineMine(SrcLineId);
  582. if (Type == CALL_PARTY_MEETING)
  583. {
  584. if(!CMC::GetInstance().meetingListen(HostLineId, m_MeetingId, true))
  585. return false;
  586. }
  587. else
  588. {
  589. DEV_RES_ID PeerId = getPeerLine(SrcLineId);
  590. if(!CMC::GetInstance().channelListen(SrcLineId, PeerId, HostLineId, true))
  591. return false;
  592. }
  593. return true;
  594. }
  595. /*****************************************************************
  596. **【函数名称】 removeLine
  597. **【函数功能】 从会话中删除指定线路
  598. **【参数】 LineId 要删除的线路ID
  599. PartyType 要删除的线路在会话中的职责
  600. **【返回值】
  601. *****************************************************************/
  602. void CCallSession::removeLine(CRDRID LineId, CALL_PARTY_TYPE PartyType, PENDING_CALL_TYPE CallType /*= PENDING_CALL_DIRECT*/)
  603. {
  604. // 根据职责保存线路到指定位置
  605. switch(PartyType)
  606. {
  607. case CALL_PARTY_HOST: // 主控线路
  608. {
  609. if(!m_LinePeer.isEmpty())
  610. CMC::GetInstance().bridgeDevice(m_LineHost, m_LinePeer, false);
  611. m_LineHost.reset();
  612. if(CallType != PENDING_CALL_MEETING)
  613. __detachListen(LineId); // 监听线路挂机
  614. }
  615. break;
  616. case CALL_PARTY_PEER: // 通话对端线路
  617. {
  618. if(!m_LineHost.isEmpty())
  619. CMC::GetInstance().bridgeDevice(m_LineHost, m_LinePeer, false);
  620. m_LinePeer.reset();
  621. if(CallType != PENDING_CALL_MEETING)
  622. __detachListen(LineId); // 监听线路挂机
  623. }
  624. break;
  625. case CALL_PARTY_LISTEN: // 通话的监听线路
  626. {
  627. // 关闭监听
  628. DEV_RES_ID DestLine;
  629. if(m_ListenLineMap.Lookup(LineId, DestLine))
  630. {
  631. CALL_PARTY_TYPE Type = __isLineMine(DestLine);
  632. if (Type == CALL_PARTY_MEETING)
  633. {
  634. CMC::GetInstance().meetingListen(LineId, m_MeetingId, false);
  635. }
  636. else
  637. {
  638. DEV_RES_ID PeerId = getPeerLine(DestLine);
  639. CMC::GetInstance().channelListen(DestLine, PeerId, LineId, false);
  640. }
  641. // 清除线路
  642. m_ListenLineMap.RemoveKey(LineId);
  643. }
  644. }
  645. break;
  646. case CALL_PARTY_PENDING: // 操作待处理线路
  647. {
  648. m_PendingLineMap.RemoveKey(LineId);
  649. }
  650. break;
  651. case CALL_PARTY_MEETING: // 会议中的线路
  652. {
  653. int Type;
  654. if(m_LineMap.Lookup(LineId, Type))
  655. {
  656. ASSERT(Type == CALL_PARTY_MEETING);
  657. CMC::GetInstance().removeFromMeeting(LineId, m_MeetingId);
  658. if(CallType != PENDING_CALL_MEETING)
  659. __detachListen(LineId); // 监听线路挂机
  660. }
  661. }
  662. break;
  663. } // end switch
  664. m_LineMap.RemoveKey(LineId);
  665. }
  666. /*****************************************************************
  667. **【函数名称】 setupPendingCall
  668. **【函数功能】 启动待处理呼叫
  669. **【参数】 SubCall 新生成的子会话ID(回传参数)
  670. pInfo 呼叫内容
  671. **【返回值】 启动呼叫时否成功
  672. *****************************************************************/
  673. bool CCallSession::setupPendingCall(long& SubCall, PendingCallInfo* pInfo)
  674. {
  675. // 是否为会话中的通话线路
  676. CALL_PARTY_TYPE HostLineParty = __isLineMine(pInfo->nHostLine);
  677. if(HostLineParty != CALL_PARTY_HOST &&
  678. HostLineParty != CALL_PARTY_PEER &&
  679. HostLineParty != CALL_PARTY_MEETING)
  680. {
  681. return false;
  682. }
  683. // 添加待处理线路到会话
  684. if(!insertLine(pInfo->nAssoLine, m_SubCallIndex + 1, true))
  685. return false;
  686. // 生成子呼叫
  687. CSubSession* pSubCall = NULL;
  688. switch(pInfo->nCallType)
  689. {
  690. case PENDING_CALL_DIRECT:
  691. pSubCall = new CDirectSession(this, ++m_SubCallIndex, pInfo);
  692. break;
  693. case PENDING_CALL_TRANSFER:
  694. pSubCall = new CTransferSession(this, ++m_SubCallIndex, pInfo);
  695. break;
  696. case PENDING_CALL_MEETING:
  697. pSubCall = new CMeetingSession(this, ++m_SubCallIndex, pInfo);
  698. break;
  699. case PENDING_CALL_TRUNK:
  700. pSubCall = new CTrunkSession(this, ++m_SubCallIndex, pInfo);
  701. break;
  702. case PENDING_CALL_CONSULT:
  703. pSubCall = new CConsultSession(this, ++m_SubCallIndex, pInfo);
  704. break;
  705. } // end if
  706. SubCall = m_SubCallIndex; // 回传参数
  707. m_SubCallMap.SetAt(m_SubCallIndex, pSubCall);
  708. // 启动操作
  709. return pSubCall->begin(HostLineParty);
  710. }
  711. /*****************************************************************
  712. **【函数名称】 lineLeave
  713. **【函数功能】 指定线路退出会话且挂机
  714. **【参数】 LineId 要退出会话的线路ID
  715. **【返回值】
  716. *****************************************************************/
  717. bool CCallSession::lineLeave(CRDRID LineId)
  718. {
  719. CALL_PARTY_TYPE nParty = __isLineMine(LineId);
  720. // 此操作序列不会关联对端线路挂机
  721. removeLine(LineId, nParty);
  722. m_RecordMap.RemoveKey(LineId); // 释放录音关联
  723. return CMC::GetInstance().dropCall(LineId, false);
  724. }
  725. /*****************************************************************
  726. **【函数名称】 LineInstead
  727. **【函数功能】 代接指定线路
  728. **【参数】 HostLine 申请代接的线路
  729. PeerLine 被代接的线路
  730. ExtNum 申请代接线路的分机号
  731. **【返回值】
  732. *****************************************************************/
  733. bool CCallSession::lineInstead(CRDRID HostLine, CRDRID PeerLine, UINT ExtNum)
  734. {
  735. // 被代接线路是否还在子会话中
  736. CSubSession* pSubCall = __getSubSession(PeerLine);
  737. if(pSubCall == NULL)
  738. return false;
  739. // 执行替换操作
  740. return pSubCall->replace(HostLine, PeerLine, ExtNum);
  741. }
  742. /*****************************************************************
  743. **【函数名称】 lineIntercept
  744. **【函数功能】 替换指定线路
  745. **【参数】 HostLine 要进入会话的线路
  746. PeerLine 要退出会话的线路
  747. **【返回值】
  748. *****************************************************************/
  749. bool CCallSession::lineIntercept(CRDRID HostLine, CRDRID PeerLine)
  750. {
  751. // 读取被替换线路在会话中的职责
  752. CALL_PARTY_TYPE Party = __isLineMine(PeerLine);
  753. if(Party != CALL_PARTY_HOST &&
  754. Party != CALL_PARTY_PEER &&
  755. Party != CALL_PARTY_MEETING)
  756. {
  757. return false;
  758. } // end if
  759. // 目标线路退出会话
  760. removeLine(PeerLine, Party);
  761. if(!CMC::GetInstance().dropCall(PeerLine, true))
  762. return false;
  763. // 主控线路加入会话
  764. if(!insertLine(HostLine, Party, true))
  765. return false;
  766. CString strCallerNum, strCalleeNum;
  767. // 获取代接线路绑定的分机号
  768. CVirtualProxy* pHostProxy = CProxyShell::GetInstance().getProxy(HostLine.toIntId());
  769. ASSERT(pHostProxy != NULL);
  770. if(pHostProxy != NULL)
  771. pHostProxy->getAssoExtenNo(strCalleeNum);
  772. // 获取被代接线路当前的主叫号码
  773. CVirtualProxy* pPeerProxy = CProxyShell::GetInstance().getProxy(PeerLine.toIntId());
  774. ASSERT(pPeerProxy != NULL);
  775. if(pPeerProxy != NULL)
  776. strCallerNum = pPeerProxy->callerNum();
  777. CProxyShell::GetInstance().onLineStateUpdated(HostLine, m_Id, SESSION_INVALID_SUB_CALL, VIRTUAL_LINE_STATE_TALKING, strCallerNum, strCalleeNum);
  778. return true;
  779. }
  780. /*****************************************************************
  781. **【函数名称】 lineInsert
  782. **【函数功能】 插入线路到会话
  783. **【参数】 HostLine 要进入会话的线路
  784. **【返回值】
  785. *****************************************************************/
  786. bool CCallSession::lineInsert(CRDRID HostLine, CRDRID PeerLine)
  787. {
  788. // 如果当前会话不是会议
  789. if(m_MeetingId.MeetingId == MEETING_ID_INVALID)
  790. {
  791. if(m_LineHost.isEmpty() || m_LinePeer.isEmpty())
  792. return false;
  793. // 将原通话转为会议
  794. if(!trans2Meeting(m_LineHost))
  795. return false;
  796. } // end if
  797. // 将主控线路添加到会议
  798. if(!insertLine(HostLine, CALL_PARTY_MEETING, true))
  799. return false;
  800. CString strCallerNum, strCalleeNum;
  801. // 获取插入线路绑定的分机号
  802. CVirtualProxy* pHostProxy = CProxyShell::GetInstance().getProxy(HostLine.toIntId());
  803. ASSERT(pHostProxy != NULL);
  804. if(pHostProxy != NULL)
  805. pHostProxy->getAssoExtenNo(strCallerNum);
  806. // 获取被插入线路绑定的分机号
  807. CVirtualProxy* pPeerProxy = CProxyShell::GetInstance().getProxy(PeerLine.toIntId());
  808. ASSERT(pPeerProxy != NULL);
  809. if(pPeerProxy != NULL)
  810. pPeerProxy->getAssoExtenNo(strCalleeNum);
  811. CProxyShell::GetInstance().onLineStateUpdated(HostLine, m_Id, SESSION_INVALID_SUB_CALL, VIRTUAL_LINE_STATE_TALKING, strCallerNum, strCalleeNum);
  812. return true;
  813. }
  814. /*****************************************************************
  815. **【函数名称】 lineListen
  816. **【函数功能】 监听指定线路
  817. **【参数】 HostLine 主控线路
  818. PeerLine 被监听线路
  819. **【返回值】
  820. *****************************************************************/
  821. bool CCallSession::lineListen(CRDRID HostLine, CRDRID PeerLine)
  822. {
  823. // 被监听线路是否还在会话中
  824. CALL_PARTY_TYPE Party = __isLineMine(PeerLine);
  825. if(Party == CALL_PARTY_HOST ||
  826. Party == CALL_PARTY_PEER ||
  827. Party == CALL_PARTY_MEETING)
  828. {
  829. if(!insertLine(HostLine, PeerLine, true)) // 添加线路到会话
  830. return false;
  831. CString strCallerNum, strCalleeNum;
  832. // 获取监听线路绑定的分机号
  833. CVirtualProxy* pHostProxy = CProxyShell::GetInstance().getProxy(HostLine.toIntId());
  834. ASSERT(pHostProxy != NULL);
  835. if(pHostProxy != NULL)
  836. pHostProxy->getAssoExtenNo(strCallerNum);
  837. // 获取被监听线路绑定的分机号
  838. CVirtualProxy* pPeerProxy = CProxyShell::GetInstance().getProxy(PeerLine.toIntId());
  839. ASSERT(pPeerProxy != NULL);
  840. if(pPeerProxy != NULL)
  841. pPeerProxy->getAssoExtenNo(strCalleeNum);
  842. CProxyShell::GetInstance().onLineStateUpdated(HostLine, m_Id, SESSION_INVALID_SUB_CALL, VIRTUAL_LINE_STATE_TALKING, strCallerNum, strCalleeNum);
  843. return true;
  844. } // end if
  845. return false;
  846. }
  847. /*****************************************************************
  848. **【函数名称】 lineRecord
  849. **【函数功能】 线路录音启动
  850. **【参数】 HostLine 主控线路
  851. lpFileName 录音文件名
  852. **【返回值】
  853. *****************************************************************/
  854. bool CCallSession::lineRecord(CRDRID HostLine, LPCTSTR lpFileName)
  855. {
  856. // 如果当前线路已在录音
  857. CString strRecFile;
  858. if(m_RecordMap.Lookup(HostLine, strRecFile))
  859. return false;
  860. // 启动录音
  861. if(__lineRecord(HostLine, lpFileName))
  862. {
  863. m_RecordMap.SetAt(HostLine, lpFileName);
  864. return true;
  865. } // end if
  866. return false;
  867. }
  868. /*****************************************************************
  869. **【函数名称】 lineLeaveWord
  870. **【函数功能】 线路留言启动
  871. **【参数】 HostLine 主控线路
  872. pContent 留言参数
  873. **【返回值】
  874. *****************************************************************/
  875. bool CCallSession::lineLeaveWord(CRDRID HostLine, RecordContent* pContent)
  876. {
  877. if(__isLineMine(HostLine) == CALL_PARTY_UNKNOWN)
  878. return false;
  879. // 启动留言
  880. pContent->nModel = RECORD_MODE_LEAVEWORD;
  881. return CMC::GetInstance().startRecord(HostLine, pContent);
  882. }
  883. /*****************************************************************
  884. **【函数名称】 lineMute
  885. **【函数功能】 线路静音控制
  886. **【参数】 HostLine 主控线路
  887. IsBegin 是启动还是结束
  888. **【返回值】
  889. *****************************************************************/
  890. bool CCallSession::lineMute(CRDRID HostLine, bool IsOn)
  891. {
  892. // 是否对会议中的线路静音
  893. CALL_PARTY_TYPE Type = __isLineMine(HostLine);
  894. bool IsMeetingMute = Type == CALL_PARTY_MEETING ? true : false;
  895. if (IsMeetingMute)
  896. {
  897. return __meetingMute(HostLine, IsOn);
  898. }
  899. else
  900. {
  901. return __lineMute(HostLine, IsOn);
  902. }
  903. }
  904. /*****************************************************************
  905. **【函数名称】 lineConsultConfirm
  906. **【函数功能】 协商呼叫确认
  907. **【参数】 PeerLine 协商呼叫的被叫线路
  908. Type 呼叫类型
  909. **【返回值】
  910. *****************************************************************/
  911. bool CCallSession::lineConsultConfirm(CRDRID PeerLine, UINT Type)
  912. {
  913. // 被代接线路是否还在子会话中
  914. CSubSession* pSubCall = __getSubSession(PeerLine);
  915. if(pSubCall == NULL)
  916. return false;
  917. // 执行替换操作
  918. return pSubCall->resume(Type);
  919. }
  920. /*****************************************************************
  921. **【函数名称】 line2Meeting
  922. **【函数功能】 通话线路转入会议
  923. **【参数】 LineId 要转入会议的线路ID
  924. Party 要进入会议的线路在原会话中的职责
  925. **【返回值】
  926. *****************************************************************/
  927. bool CCallSession::line2Meeting(DEV_RES_ID LineId, CALL_PARTY_TYPE Party)
  928. {
  929. removeLine(LineId, Party, PENDING_CALL_MEETING);
  930. // 线路转入会议
  931. return insertLine(LineId, CALL_PARTY_MEETING, true);
  932. }
  933. /*****************************************************************
  934. **【函数名称】 trans2Meeting
  935. **【函数功能】 将当前会话转换为会议
  936. **【参数】 HostLineId 发起会议的主控线路
  937. **【返回值】
  938. *****************************************************************/
  939. bool CCallSession::trans2Meeting(CRDRID HostLineId)
  940. {
  941. if(m_MeetingId.MeetingId != MEETING_ID_INVALID)
  942. return true;
  943. if(!CMC::GetInstance().createMeeting(HostLineId, m_MeetingId))
  944. {
  945. LOGGER(LOG_CLASS_BUSI, LOG_LEVEL_WARNING, _T("{Session}: 会话环境转换为会议失败, HostLine = %u, PeerLine = %u"),
  946. m_LineHost.toIntId(), m_LinePeer.toIntId());
  947. return false;
  948. }
  949. bool HostTrans2MeetingResult = false;
  950. // 原通话线路职责转换
  951. if(!m_LineHost.isEmpty())
  952. {
  953. HostTrans2MeetingResult = line2Meeting(m_LineHost, CALL_PARTY_HOST);
  954. if(!HostTrans2MeetingResult) // 若主线路转为会议不成功,就说明DSP资源枯竭,此次会议就宣告失败
  955. {
  956. CMC::GetInstance().deleteMeeting(m_MeetingId);
  957. LOGGER(LOG_CLASS_BUSI, LOG_LEVEL_WARNING, _T("{Session}: 主线路转换为会议失败, HostLine = %u, PeerLine = %u"),
  958. m_LineHost.toIntId(), m_LinePeer.toIntId());
  959. return false;
  960. }
  961. }
  962. if(!m_LinePeer.isEmpty())
  963. {
  964. if(!line2Meeting(m_LinePeer, CALL_PARTY_PEER))
  965. {
  966. if(!HostTrans2MeetingResult)
  967. {
  968. // 运行到此,说明主线路为空(即:m_LineHost == 0),因此要删除以创建的会议,
  969. // 但若主线路成功转为会议则不删除,因为主线路挂机后会自动删除。
  970. CMC::GetInstance().deleteMeeting(m_MeetingId);
  971. }
  972. LOGGER(LOG_CLASS_BUSI, LOG_LEVEL_WARNING, _T("{Session}: 对端线路转换为会议失败, HostLine = %u, PeerLine = %u"),
  973. m_LineHost.toIntId(), m_LinePeer.toIntId());
  974. return false;
  975. }
  976. }
  977. return true;
  978. }
  979. void CCallSession::__setTimer(UINT TimmerId, UINT Elapse)
  980. {
  981. m_SessionTimer.StopSafely();
  982. m_SessionTimer.SetTimedEvent(this, &CCallSession::__onTimerPostProcessing);
  983. m_SessionTimer.Start(Elapse, false, true, WT_EXECUTEDEFAULT);
  984. }
  985. void CCallSession::__onTimerPostProcessing(void)
  986. {
  987. CMC::GetInstance().dropCall(m_LineHost, true);
  988. }