#include "StdAfx.h" #include "CallSession.h" #include "MC.h" #include "ProxyShell.h" #include "ConsultSession.h" #include "MeetingSession.h" #include "DirectSession.h" #include "TransferSession.h" #include "TrunkSession.h" #include "Config.h" #include "VirtualProxy.h" CCallSession::CCallSession(long SessionId) : m_Id(SessionId), m_SubCallIndex(0) { ZeroMemory(&m_MeetingId, sizeof(MeetingInfo)); m_MeetingId.MeetingId = MEETING_ID_INVALID; } CCallSession::~CCallSession(void) { __clearSubSession(); } /***************************************************************** **【函数名称】 __isLineMine **【函数功能】 指定线路是否属于当前会话 **【参数】 LineId 要查找的线路ID **【返回值】 *****************************************************************/ CALL_PARTY_TYPE CCallSession::__isLineMine( CRDRID LineId ) { int Type; if(m_LineMap.Lookup(LineId, Type)) return (CALL_PARTY_TYPE)Type; else return CALL_PARTY_UNKNOWN; } /***************************************************************** **【函数名称】 __GetSubCall **【函数功能】 通过待处理线路ID查找子呼叫 **【参数】 PendingLine 通话待处理线路ID **【返回值】 *****************************************************************/ CSubSession* CCallSession::__getSubSession(CRDRID PendingLine) { UINT SubCall = 0; CSubSession* pSubCall = NULL; // 找到子呼叫的ID if(!m_PendingLineMap.Lookup(PendingLine, SubCall)) return NULL; // 查找子呼叫指针 m_SubCallMap.Lookup(SubCall, pSubCall); return pSubCall; } /***************************************************************** **【函数名称】 __clearSubSession **【函数功能】 释放所有子会话 **【参数】 **【返回值】 *****************************************************************/ void CCallSession::__clearSubSession( void ) { UINT Key = 0; CSubSession* pSub = NULL; POSITION pos = m_SubCallMap.GetStartPosition(); while(pos != NULL) { m_SubCallMap.GetNextAssoc(pos, Key, pSub); ASSERT(pSub != NULL); delete pSub; } // end while m_SubCallMap.RemoveAll(); } /***************************************************************** **【函数名称】 __notifySubSessionLineFree **【函数功能】 通知子会话相关线路空闲 **【参数】 **【返回值】 *****************************************************************/ void CCallSession::__notifySubSessionLineFree( CRDRID LineId ) { UINT Key = 0; CSubSession* pSub = NULL; POSITION pos = m_SubCallMap.GetStartPosition(); while(pos != NULL) { m_SubCallMap.GetNextAssoc(pos, Key, pSub); ASSERT(pSub != NULL); if(pSub->getSubHostLine() == LineId) pSub->onHostLineStateFree(); else if(pSub->getSubPeerLine() == LineId) pSub->onPeerLineStateFree(); } // end while } /***************************************************************** **【函数名称】 __lineDoRecord **【函数功能】 执行录音操作 **【参数】 HostLine 录音线路 lpFileName 录音文件名 **【返回值】 *****************************************************************/ bool CCallSession::__lineRecord(CRDRID HostLine, LPCTSTR lpFileName) { // 填充录音参数 RecordContent content; memset(&content, 0, sizeof(RecordContent)); lstrcpy(content.szFileName, lpFileName); content.nTaskId = RECORD_TASK_ID_NORMAL; CALL_PARTY_TYPE Party = __isLineMine(HostLine); switch(Party) { case CALL_PARTY_HOST: // 主控线路 { content.nModel = RECORD_MODE_NORMAL; content.nPeerLine = m_LinePeer; } break; case CALL_PARTY_PEER: // 对端线路 { content.nModel = RECORD_MODE_NORMAL; content.nPeerLine = m_LineHost; } break; case CALL_PARTY_MEETING: // 会议线路 { content.nModel = RECORD_MODE_MEETING; } break; case CALL_PARTY_PENDING: { content.nModel = RECORD_MODE_NORMAL; CSubSession * pSubCall = __getSubSession(HostLine); content.nPeerLine = pSubCall->getSubHostLine(); } break; } // end switch // 启动录音 return CMC::GetInstance().startRecord(HostLine, &content); } /***************************************************************** **【函数名称】 __LineDoMute **【函数功能】 线路静音操作 **【参数】 HostLine 静音线路 IsBegin 静音启动/结束 **【返回值】 *****************************************************************/ bool CCallSession::__lineMute(CRDRID HostLine, bool IsOn) { // 查询对端线路 DEV_RES_ID AssoLine = getPeerLine(HostLine); if(AssoLine.isEmpty()) return false; // 静音控制 if(IsOn) { // 断开通话 CMC::GetInstance().bridgeDevice(HostLine, AssoLine, false); // 对端线路播放保持音 CMC::GetInstance().playTone(AssoLine, CHANNEL_TONE_HOLD); } else { // 停止放音 CMC::GetInstance().playStop(AssoLine); // 重连通话 CMC::GetInstance().bridgeDevice(HostLine, AssoLine, true); } // end if return true; } /***************************************************************** **【函数名称】 __meetingMute **【函数功能】 会议静音操作 **【参数】 HostLine 静音线路 IsBegin 静音启动/结束 **【返回值】 *****************************************************************/ bool CCallSession::__meetingMute(CRDRID HostLine, bool IsOn) { return CMC::GetInstance().meetingMute(HostLine, m_MeetingId, !IsOn); } /***************************************************************** **【函数名称】 __line2Link **【函数功能】 线路进入双向通话 **【参数】 LineId 要进入通话的线路ID LinePeeer 要进行通话的对端线路 **【返回值】 *****************************************************************/ bool CCallSession::__line2Link(CRDRID LineId, CRDRID LinePeer) { CString strRecFile; // 当前录音采用混音模式,原线路在录音时不影响线路之间通话的建立,故不需停止当前录音, // 因此注释一下三行。 //// 停止当前录音 //if(m_RecordMap.Lookup(LinePeer, strRecFile)) // CMC::GetInstance().stopRecord(LinePeer); // 线路双向连通 return CMC::GetInstance().bridgeDevice(LineId, LinePeer, true); } /***************************************************************** **【函数名称】 __detachListen **【函数功能】 解除指定线路的监听 **【参数】 HostLine 当前挂机的线路 **【返回值】 *****************************************************************/ void CCallSession::__detachListen(CRDRID HostLine) { POSITION pos = m_ListenLineMap.GetStartPosition(); while(pos != NULL) { DEV_RES_ID DevId; DEV_RES_ID LineListen; m_ListenLineMap.GetNextAssoc(pos, LineListen, DevId); if(DevId == HostLine) CMC::GetInstance().dropCall(LineListen, false); // 监听线路挂机 } } /***************************************************************** **【函数名称】 getPeerLine **【函数功能】 获取当前线路关联的对端线路 **【参数】 LineId 要查询的线路 **【返回值】 0 -> 无对端线路 *****************************************************************/ DEV_RES_ID CCallSession::getPeerLine(CRDRID LineId) { // 当前线路在会话中的职责 DEV_RES_ID AssoLine; CALL_PARTY_TYPE Party = __isLineMine(LineId); switch(Party) { case CALL_PARTY_HOST: // 主控线路 AssoLine = m_LinePeer; break; case CALL_PARTY_PEER: // 对端线路 AssoLine = m_LineHost; break; default: // 其它线路 break; } // end switch return AssoLine; } /***************************************************************** **【函数名称】 IsExist **【函数功能】 指定职责的线路是否在会话中 **【参数】 LineId 要查询的线路ID PartyType 线路在会话中的职责 **【返回值】 *****************************************************************/ bool CCallSession::isExist(CRDRID LineId, CALL_PARTY_TYPE PartyType) { int Type; if(m_LineMap.Lookup(LineId, Type)) { return PartyType == (CALL_PARTY_TYPE)Type; } else { return false; } } /***************************************************************** **【函数名称】 onLineStateChanged **【函数功能】 线路状态变化事件处理 **【参数】 LineId 状态变化的线路ID LineState 线路当前状态 lpCallerNum 主叫号码 lpCallerNum 被叫号码 **【返回值】 *****************************************************************/ void CCallSession::onLineStateChanged(CRDRID LineId, VIRTUAL_LINE_STATE LineState, LPCTSTR lpCallerNum, LPCTSTR lpCalleeNum) { // 根据线路物理状态进行分类处理 switch(LineState) { case VIRTUAL_LINE_STATE_FREE: __onLineStateFree(LineId, lpCallerNum, lpCalleeNum); break; case VIRTUAL_LINE_STATE_INIT: case VIRTUAL_LINE_STATE_DIALING: case VIRTUAL_LINE_STATE_DISABLED: CProxyShell::GetInstance().onLineStateUpdated(LineId, m_Id, SESSION_INVALID_SUB_CALL, LineState, lpCallerNum, lpCalleeNum); break; case VIRTUAL_LINE_STATE_RING_BACK: __onLineStateRingBack(LineId, lpCallerNum, lpCalleeNum); break; case VIRTUAL_LINE_STATE_ALERTING: __onLineStateAlerting(LineId, lpCallerNum, lpCalleeNum); break; case VIRTUAL_LINE_STATE_PROGRESSING: __onLineStateProgressing(LineId, lpCallerNum, lpCalleeNum); break; case VIRTUAL_LINE_STATE_TALKING: //__setTimer(0,1000*60*10); //鹤壁12345 通话不能超过10分钟 __onLineStateTalking(LineId, lpCallerNum, lpCalleeNum); break; } // end switch } /***************************************************************** **【函数名称】 onRecordStop **【函数功能】 录音停止事件 **【参数】 LineId 录音停止的线路ID TaskId 录音启动时的任务ID **【返回值】 *****************************************************************/ void CCallSession::onRecordStop(CRDRID LineId, UINT TaskId) { if(TaskId == RECORD_TASK_ID_LEAVEWORD) CProxyShell::GetInstance().onDevChannelEvent(LineId, DEV_CH_EVT_REC_END, NULL, 0); } /***************************************************************** **【函数名称】 __onLineStateFree **【函数功能】 线路状态处理【空闲】 **【参数】 nLineId 状态变化的线路ID lpCallerNum 主叫号码 lpCallerNum 被叫号码 **【返回值】 *****************************************************************/ void CCallSession::__onLineStateFree(CRDRID LineId, LPCTSTR lpCallerNum, LPCTSTR lpCalleeNum) { // 获取线路在会话中的职责 CALL_PARTY_TYPE Type = __isLineMine(LineId); // 清除线路录音 m_RecordMap.RemoveKey(LineId); // 根据线路在会话中的职责进行分类处理 switch(Type) { case CALL_PARTY_HOST: // 主控线路 case CALL_PARTY_PEER: // 对端线路 { removeLine(LineId, Type); // 从会话中删除线路 CProxyShell::GetInstance().onLineStateUpdated(LineId, m_Id, SESSION_INVALID_SUB_CALL, VIRTUAL_LINE_STATE_FREE); // 对端线路挂机 DEV_RES_ID AssoLine = (Type == CALL_PARTY_HOST) ? m_LinePeer : m_LineHost; if(!AssoLine.isEmpty()) CMC::GetInstance().dropCall(AssoLine, true); } break; case CALL_PARTY_PENDING: // 操作待处理线路 { CSubSession* pSubCall = __getSubSession(LineId); ASSERT(pSubCall != NULL); removeLine(LineId, Type); // 从会话中删除线路 if(pSubCall != NULL) pSubCall->onPendingLineState(VIRTUAL_LINE_STATE_FREE); } break; case CALL_PARTY_LISTEN: // 通话的监听线路 { removeLine(LineId, Type); // 从会话中删除线路 CProxyShell::GetInstance().onLineStateUpdated(LineId, m_Id, SESSION_INVALID_SUB_CALL, VIRTUAL_LINE_STATE_FREE); } break; case CALL_PARTY_MEETING: // 会议中的线路 { removeLine(LineId, Type); // 从会话中删除线路 CProxyShell::GetInstance().onLineStateUpdated(LineId, m_Id, SESSION_INVALID_SUB_CALL, VIRTUAL_LINE_STATE_FREE); // 如果会议中只剩下一条线路,线路中可能存在监听线路 if(lineCount() == 1 && m_ListenLineMap.GetSize() > 0) { const CMap::CPair* pLastListenLine = m_ListenLineMap.PGetFirstAssoc(); ASSERT(pLastListenLine != NULL); // 挂断此线路 CMC::GetInstance().dropCall(pLastListenLine->key, true); } // end if } break; default: CProxyShell::GetInstance().onLineStateUpdated(LineId, m_Id, SESSION_INVALID_SUB_CALL, VIRTUAL_LINE_STATE_FREE, lpCallerNum, lpCalleeNum); break; } // end switch __notifySubSessionLineFree(LineId); CMC::GetInstance().freeChanResource(LineId); } /***************************************************************** **【函数名称】 __onLineStateAlerting **【函数功能】 线路状态处理【来电振铃】 **【参数】 LineId 状态变化的线路ID lpCallerNum 主叫号码 lpCallerNum 被叫号码 **【返回值】 *****************************************************************/ void CCallSession::__onLineStateAlerting(CRDRID LineId, LPCTSTR lpCallerNum, LPCTSTR lpCalleeNum) { // 获取线路在会话中的职责 CALL_PARTY_TYPE Type = __isLineMine(LineId); switch(Type) { case CALL_PARTY_HOST: // 主控线路 { CProxyShell::GetInstance().onLineStateUpdated(LineId, m_Id, SESSION_INVALID_SUB_CALL, VIRTUAL_LINE_STATE_ALERTING, lpCallerNum, lpCalleeNum); } break; case CALL_PARTY_PEER: // 通话对端线路 break; case CALL_PARTY_LISTEN: // 通话的监听线路 break; case CALL_PARTY_PENDING: // 操作待处理线路 { CSubSession* pSubCall = __getSubSession(LineId); ASSERT(pSubCall != NULL); pSubCall->onPendingLineState(VIRTUAL_LINE_STATE_ALERTING); } break; case CALL_PARTY_MEETING: // 会议中的线路 break; default: ASSERT(FALSE); break; } // end switch } /***************************************************************** **【函数名称】 __onLineStateProgressing **【函数功能】 线路状态处理【通话进展】 **【参数】 LineId 状态变化的线路ID lpCallerNum 主叫号码 lpCallerNum 被叫号码 **【返回值】 *****************************************************************/ void CCallSession::__onLineStateProgressing( CRDRID LineId, LPCTSTR lpCallerNum, LPCTSTR lpCalleeNum ) { // 获取线路在会话中的职责 CALL_PARTY_TYPE Type = __isLineMine(LineId); if(Type == CALL_PARTY_PENDING) { CSubSession* pSubCall = __getSubSession(LineId); ASSERT(pSubCall != NULL); pSubCall->onPendingLineState(VIRTUAL_LINE_STATE_PROGRESSING); } } /***************************************************************** **【函数名称】 __onLineStateRingBack **【函数功能】 线路状态处理【呼出振铃】 **【参数】 LineId 状态变化的线路ID lpCallerNum 主叫号码 lpCallerNum 被叫号码 **【返回值】 *****************************************************************/ void CCallSession::__onLineStateRingBack(CRDRID LineId, LPCTSTR lpCallerNum, LPCTSTR lpCalleeNum) { // 获取线路在会话中的职责 CALL_PARTY_TYPE Type = __isLineMine(LineId); // 根据线路在会话中的职责进行分类处理 switch(Type) { case CALL_PARTY_HOST: // 主控线路 { CProxyShell::GetInstance().onLineStateUpdated(LineId, m_Id, SESSION_INVALID_SUB_CALL, VIRTUAL_LINE_STATE_RING_BACK, lpCallerNum, lpCalleeNum); } break; case CALL_PARTY_PEER: // 对端线路 break; case CALL_PARTY_LISTEN: // 通话的监听线路 break; case CALL_PARTY_PENDING: // 操作待处理线路 { CSubSession* pSubCall = __getSubSession(LineId); ASSERT(pSubCall != NULL); pSubCall->onPendingLineState(VIRTUAL_LINE_STATE_RING_BACK); } break; case CALL_PARTY_MEETING: // 会议中的线路 break; default: ASSERT(FALSE); } // end switch } /***************************************************************** **【函数名称】 __onLineStateTalking **【函数功能】 线路状态处理【通话】 **【参数】 LineId 状态变化的线路ID lpCallerNum 主叫号码 lpCallerNum 被叫号码 **【返回值】 *****************************************************************/ void CCallSession::__onLineStateTalking(CRDRID LineId, LPCTSTR lpCallerNum, LPCTSTR lpCalleeNum) { // 获取线路在会话中的职责 CALL_PARTY_TYPE Type = __isLineMine(LineId); switch(Type) { case CALL_PARTY_HOST: // 主控线路 { CProxyShell::GetInstance().onLineStateUpdated(LineId, m_Id, SESSION_INVALID_SUB_CALL, VIRTUAL_LINE_STATE_TALKING, lpCallerNum, lpCalleeNum); } break; case CALL_PARTY_PEER: // 通话对端线路 break; case CALL_PARTY_LISTEN: // 通话的监听线路 break; case CALL_PARTY_PENDING: // 操作待处理线路 { CSubSession* pSubCall = __getSubSession(LineId); ASSERT(pSubCall != NULL); pSubCall->onPendingLineState(VIRTUAL_LINE_STATE_TALKING); } break; case CALL_PARTY_MEETING: // 会议中的线路 break; default: ASSERT(FALSE); break; } // end switch } /***************************************************************** **【函数名称】 insertLine **【函数功能】 添加待定线路到会话 **【参数】 LineId 要添加的线路ID PartyType 新增线路在会话中的职责 Info 附加信息 IsLink 是否作通道连接 **【返回值】 *****************************************************************/ bool CCallSession::insertLine(CRDRID LineId, UINT SessionId, bool IsLink) { // 通知当前线路关联呼叫 CMC::GetInstance().setSessionInfo2Line(LineId, m_Id); CProxyShell::GetInstance().onNewCall(LineId, m_Id, SESSION_INVALID_SUB_CALL); m_LineMap[LineId] = CALL_PARTY_PENDING; m_PendingLineMap[LineId] = SessionId; return true; } /***************************************************************** **【函数名称】 insertLine **【函数功能】 添加指定线路到会话 **【参数】 LineId 要添加的线路ID PartyType 新增线路在会话中的职责 IsLink 是否作通道连接 **【返回值】 *****************************************************************/ bool CCallSession::insertLine( CRDRID LineId, CALL_PARTY_TYPE PartyType, bool IsLink ) { // 通知当前线路关联呼叫 CMC::GetInstance().setSessionInfo2Line(LineId, m_Id); CProxyShell::GetInstance().onNewCall(LineId, m_Id, SESSION_INVALID_SUB_CALL); // 根据职责保存线路到指定位置 switch(PartyType) { case CALL_PARTY_HOST: // 主控线路 { m_LineHost = LineId; m_LineMap[LineId] = CALL_PARTY_HOST; if(!m_LinePeer.isEmpty() && IsLink) { if(!__line2Link(LineId, m_LinePeer)) return false; } } break; case CALL_PARTY_PEER: // 通话对端线路 { m_LinePeer = LineId; m_LineMap[LineId] = CALL_PARTY_PEER; if(!m_LineHost.isEmpty() && IsLink) { if(!__line2Link(LineId, m_LineHost)) return false; } } break; case CALL_PARTY_MEETING: // 会议中的线路 { m_LineMap[LineId] = CALL_PARTY_MEETING; if(!CMC::GetInstance().move2Meeting(LineId, m_MeetingId, false)) return false; } break; } // end switch return true; } /***************************************************************** **【函数名称】 insertLine **【函数功能】 添加监听线路到会话 **【参数】 LineId 要添加的线路ID PartyType 新增线路在会话中的职责 IsLink 是否作通道连接 **【返回值】 *****************************************************************/ bool CCallSession::insertLine( CRDRID HostLineId, CRDRID SrcLineId, bool IsLink ) { // 通知当前线路关联呼叫 CMC::GetInstance().setSessionInfo2Line(HostLineId, m_Id); CProxyShell::GetInstance().onNewCall(HostLineId, m_Id, SESSION_INVALID_SUB_CALL); m_LineMap[HostLineId] = CALL_PARTY_LISTEN; m_ListenLineMap[HostLineId] = SrcLineId; CALL_PARTY_TYPE Type = __isLineMine(SrcLineId); if (Type == CALL_PARTY_MEETING) { if(!CMC::GetInstance().meetingListen(HostLineId, m_MeetingId, true)) return false; } else { DEV_RES_ID PeerId = getPeerLine(SrcLineId); if(!CMC::GetInstance().channelListen(SrcLineId, PeerId, HostLineId, true)) return false; } return true; } /***************************************************************** **【函数名称】 removeLine **【函数功能】 从会话中删除指定线路 **【参数】 LineId 要删除的线路ID PartyType 要删除的线路在会话中的职责 **【返回值】 *****************************************************************/ void CCallSession::removeLine(CRDRID LineId, CALL_PARTY_TYPE PartyType, PENDING_CALL_TYPE CallType /*= PENDING_CALL_DIRECT*/) { // 根据职责保存线路到指定位置 switch(PartyType) { case CALL_PARTY_HOST: // 主控线路 { if(!m_LinePeer.isEmpty()) CMC::GetInstance().bridgeDevice(m_LineHost, m_LinePeer, false); m_LineHost.reset(); if(CallType != PENDING_CALL_MEETING) __detachListen(LineId); // 监听线路挂机 } break; case CALL_PARTY_PEER: // 通话对端线路 { if(!m_LineHost.isEmpty()) CMC::GetInstance().bridgeDevice(m_LineHost, m_LinePeer, false); m_LinePeer.reset(); if(CallType != PENDING_CALL_MEETING) __detachListen(LineId); // 监听线路挂机 } break; case CALL_PARTY_LISTEN: // 通话的监听线路 { // 关闭监听 DEV_RES_ID DestLine; if(m_ListenLineMap.Lookup(LineId, DestLine)) { CALL_PARTY_TYPE Type = __isLineMine(DestLine); if (Type == CALL_PARTY_MEETING) { CMC::GetInstance().meetingListen(LineId, m_MeetingId, false); } else { DEV_RES_ID PeerId = getPeerLine(DestLine); CMC::GetInstance().channelListen(DestLine, PeerId, LineId, false); } // 清除线路 m_ListenLineMap.RemoveKey(LineId); } } break; case CALL_PARTY_PENDING: // 操作待处理线路 { m_PendingLineMap.RemoveKey(LineId); } break; case CALL_PARTY_MEETING: // 会议中的线路 { int Type; if(m_LineMap.Lookup(LineId, Type)) { ASSERT(Type == CALL_PARTY_MEETING); CMC::GetInstance().removeFromMeeting(LineId, m_MeetingId); if(CallType != PENDING_CALL_MEETING) __detachListen(LineId); // 监听线路挂机 } } break; } // end switch m_LineMap.RemoveKey(LineId); } /***************************************************************** **【函数名称】 setupPendingCall **【函数功能】 启动待处理呼叫 **【参数】 SubCall 新生成的子会话ID(回传参数) pInfo 呼叫内容 **【返回值】 启动呼叫时否成功 *****************************************************************/ bool CCallSession::setupPendingCall(long& SubCall, PendingCallInfo* pInfo) { // 是否为会话中的通话线路 CALL_PARTY_TYPE HostLineParty = __isLineMine(pInfo->nHostLine); if(HostLineParty != CALL_PARTY_HOST && HostLineParty != CALL_PARTY_PEER && HostLineParty != CALL_PARTY_MEETING) { return false; } // 添加待处理线路到会话 if(!insertLine(pInfo->nAssoLine, m_SubCallIndex + 1, true)) return false; // 生成子呼叫 CSubSession* pSubCall = NULL; switch(pInfo->nCallType) { case PENDING_CALL_DIRECT: pSubCall = new CDirectSession(this, ++m_SubCallIndex, pInfo); break; case PENDING_CALL_TRANSFER: pSubCall = new CTransferSession(this, ++m_SubCallIndex, pInfo); break; case PENDING_CALL_MEETING: pSubCall = new CMeetingSession(this, ++m_SubCallIndex, pInfo); break; case PENDING_CALL_TRUNK: pSubCall = new CTrunkSession(this, ++m_SubCallIndex, pInfo); break; case PENDING_CALL_CONSULT: pSubCall = new CConsultSession(this, ++m_SubCallIndex, pInfo); break; } // end if SubCall = m_SubCallIndex; // 回传参数 m_SubCallMap.SetAt(m_SubCallIndex, pSubCall); // 启动操作 return pSubCall->begin(HostLineParty); } /***************************************************************** **【函数名称】 lineLeave **【函数功能】 指定线路退出会话且挂机 **【参数】 LineId 要退出会话的线路ID **【返回值】 *****************************************************************/ bool CCallSession::lineLeave(CRDRID LineId) { CALL_PARTY_TYPE nParty = __isLineMine(LineId); // 此操作序列不会关联对端线路挂机 removeLine(LineId, nParty); m_RecordMap.RemoveKey(LineId); // 释放录音关联 return CMC::GetInstance().dropCall(LineId, false); } /***************************************************************** **【函数名称】 LineInstead **【函数功能】 代接指定线路 **【参数】 HostLine 申请代接的线路 PeerLine 被代接的线路 ExtNum 申请代接线路的分机号 **【返回值】 *****************************************************************/ bool CCallSession::lineInstead(CRDRID HostLine, CRDRID PeerLine, UINT ExtNum) { // 被代接线路是否还在子会话中 CSubSession* pSubCall = __getSubSession(PeerLine); if(pSubCall == NULL) return false; // 执行替换操作 return pSubCall->replace(HostLine, PeerLine, ExtNum); } /***************************************************************** **【函数名称】 lineIntercept **【函数功能】 替换指定线路 **【参数】 HostLine 要进入会话的线路 PeerLine 要退出会话的线路 **【返回值】 *****************************************************************/ bool CCallSession::lineIntercept(CRDRID HostLine, CRDRID PeerLine) { // 读取被替换线路在会话中的职责 CALL_PARTY_TYPE Party = __isLineMine(PeerLine); if(Party != CALL_PARTY_HOST && Party != CALL_PARTY_PEER && Party != CALL_PARTY_MEETING) { return false; } // end if // 目标线路退出会话 removeLine(PeerLine, Party); if(!CMC::GetInstance().dropCall(PeerLine, true)) return false; // 主控线路加入会话 if(!insertLine(HostLine, Party, true)) return false; CString strCallerNum, strCalleeNum; // 获取代接线路绑定的分机号 CVirtualProxy* pHostProxy = CProxyShell::GetInstance().getProxy(HostLine.toIntId()); ASSERT(pHostProxy != NULL); if(pHostProxy != NULL) pHostProxy->getAssoExtenNo(strCalleeNum); // 获取被代接线路当前的主叫号码 CVirtualProxy* pPeerProxy = CProxyShell::GetInstance().getProxy(PeerLine.toIntId()); ASSERT(pPeerProxy != NULL); if(pPeerProxy != NULL) strCallerNum = pPeerProxy->callerNum(); CProxyShell::GetInstance().onLineStateUpdated(HostLine, m_Id, SESSION_INVALID_SUB_CALL, VIRTUAL_LINE_STATE_TALKING, strCallerNum, strCalleeNum); return true; } /***************************************************************** **【函数名称】 lineInsert **【函数功能】 插入线路到会话 **【参数】 HostLine 要进入会话的线路 **【返回值】 *****************************************************************/ bool CCallSession::lineInsert(CRDRID HostLine, CRDRID PeerLine) { // 如果当前会话不是会议 if(m_MeetingId.MeetingId == MEETING_ID_INVALID) { if(m_LineHost.isEmpty() || m_LinePeer.isEmpty()) return false; // 将原通话转为会议 if(!trans2Meeting(m_LineHost)) return false; } // end if // 将主控线路添加到会议 if(!insertLine(HostLine, CALL_PARTY_MEETING, true)) return false; CString strCallerNum, strCalleeNum; // 获取插入线路绑定的分机号 CVirtualProxy* pHostProxy = CProxyShell::GetInstance().getProxy(HostLine.toIntId()); ASSERT(pHostProxy != NULL); if(pHostProxy != NULL) pHostProxy->getAssoExtenNo(strCallerNum); // 获取被插入线路绑定的分机号 CVirtualProxy* pPeerProxy = CProxyShell::GetInstance().getProxy(PeerLine.toIntId()); ASSERT(pPeerProxy != NULL); if(pPeerProxy != NULL) pPeerProxy->getAssoExtenNo(strCalleeNum); CProxyShell::GetInstance().onLineStateUpdated(HostLine, m_Id, SESSION_INVALID_SUB_CALL, VIRTUAL_LINE_STATE_TALKING, strCallerNum, strCalleeNum); return true; } /***************************************************************** **【函数名称】 lineListen **【函数功能】 监听指定线路 **【参数】 HostLine 主控线路 PeerLine 被监听线路 **【返回值】 *****************************************************************/ bool CCallSession::lineListen(CRDRID HostLine, CRDRID PeerLine) { // 被监听线路是否还在会话中 CALL_PARTY_TYPE Party = __isLineMine(PeerLine); if(Party == CALL_PARTY_HOST || Party == CALL_PARTY_PEER || Party == CALL_PARTY_MEETING) { if(!insertLine(HostLine, PeerLine, true)) // 添加线路到会话 return false; CString strCallerNum, strCalleeNum; // 获取监听线路绑定的分机号 CVirtualProxy* pHostProxy = CProxyShell::GetInstance().getProxy(HostLine.toIntId()); ASSERT(pHostProxy != NULL); if(pHostProxy != NULL) pHostProxy->getAssoExtenNo(strCallerNum); // 获取被监听线路绑定的分机号 CVirtualProxy* pPeerProxy = CProxyShell::GetInstance().getProxy(PeerLine.toIntId()); ASSERT(pPeerProxy != NULL); if(pPeerProxy != NULL) pPeerProxy->getAssoExtenNo(strCalleeNum); CProxyShell::GetInstance().onLineStateUpdated(HostLine, m_Id, SESSION_INVALID_SUB_CALL, VIRTUAL_LINE_STATE_TALKING, strCallerNum, strCalleeNum); return true; } // end if return false; } /***************************************************************** **【函数名称】 lineRecord **【函数功能】 线路录音启动 **【参数】 HostLine 主控线路 lpFileName 录音文件名 **【返回值】 *****************************************************************/ bool CCallSession::lineRecord(CRDRID HostLine, LPCTSTR lpFileName) { // 如果当前线路已在录音 CString strRecFile; if(m_RecordMap.Lookup(HostLine, strRecFile)) return false; // 启动录音 if(__lineRecord(HostLine, lpFileName)) { m_RecordMap.SetAt(HostLine, lpFileName); return true; } // end if return false; } /***************************************************************** **【函数名称】 lineLeaveWord **【函数功能】 线路留言启动 **【参数】 HostLine 主控线路 pContent 留言参数 **【返回值】 *****************************************************************/ bool CCallSession::lineLeaveWord(CRDRID HostLine, RecordContent* pContent) { if(__isLineMine(HostLine) == CALL_PARTY_UNKNOWN) return false; // 启动留言 pContent->nModel = RECORD_MODE_LEAVEWORD; return CMC::GetInstance().startRecord(HostLine, pContent); } /***************************************************************** **【函数名称】 lineMute **【函数功能】 线路静音控制 **【参数】 HostLine 主控线路 IsBegin 是启动还是结束 **【返回值】 *****************************************************************/ bool CCallSession::lineMute(CRDRID HostLine, bool IsOn) { // 是否对会议中的线路静音 CALL_PARTY_TYPE Type = __isLineMine(HostLine); bool IsMeetingMute = Type == CALL_PARTY_MEETING ? true : false; if (IsMeetingMute) { return __meetingMute(HostLine, IsOn); } else { return __lineMute(HostLine, IsOn); } } /***************************************************************** **【函数名称】 lineConsultConfirm **【函数功能】 协商呼叫确认 **【参数】 PeerLine 协商呼叫的被叫线路 Type 呼叫类型 **【返回值】 *****************************************************************/ bool CCallSession::lineConsultConfirm(CRDRID PeerLine, UINT Type) { // 被代接线路是否还在子会话中 CSubSession* pSubCall = __getSubSession(PeerLine); if(pSubCall == NULL) return false; // 执行替换操作 return pSubCall->resume(Type); } /***************************************************************** **【函数名称】 line2Meeting **【函数功能】 通话线路转入会议 **【参数】 LineId 要转入会议的线路ID Party 要进入会议的线路在原会话中的职责 **【返回值】 *****************************************************************/ bool CCallSession::line2Meeting(DEV_RES_ID LineId, CALL_PARTY_TYPE Party) { removeLine(LineId, Party, PENDING_CALL_MEETING); // 线路转入会议 return insertLine(LineId, CALL_PARTY_MEETING, true); } /***************************************************************** **【函数名称】 trans2Meeting **【函数功能】 将当前会话转换为会议 **【参数】 HostLineId 发起会议的主控线路 **【返回值】 *****************************************************************/ bool CCallSession::trans2Meeting(CRDRID HostLineId) { if(m_MeetingId.MeetingId != MEETING_ID_INVALID) return true; if(!CMC::GetInstance().createMeeting(HostLineId, m_MeetingId)) { LOGGER(LOG_CLASS_BUSI, LOG_LEVEL_WARNING, _T("{Session}: 会话环境转换为会议失败, HostLine = %u, PeerLine = %u"), m_LineHost.toIntId(), m_LinePeer.toIntId()); return false; } bool HostTrans2MeetingResult = false; // 原通话线路职责转换 if(!m_LineHost.isEmpty()) { HostTrans2MeetingResult = line2Meeting(m_LineHost, CALL_PARTY_HOST); if(!HostTrans2MeetingResult) // 若主线路转为会议不成功,就说明DSP资源枯竭,此次会议就宣告失败 { CMC::GetInstance().deleteMeeting(m_MeetingId); LOGGER(LOG_CLASS_BUSI, LOG_LEVEL_WARNING, _T("{Session}: 主线路转换为会议失败, HostLine = %u, PeerLine = %u"), m_LineHost.toIntId(), m_LinePeer.toIntId()); return false; } } if(!m_LinePeer.isEmpty()) { if(!line2Meeting(m_LinePeer, CALL_PARTY_PEER)) { if(!HostTrans2MeetingResult) { // 运行到此,说明主线路为空(即:m_LineHost == 0),因此要删除以创建的会议, // 但若主线路成功转为会议则不删除,因为主线路挂机后会自动删除。 CMC::GetInstance().deleteMeeting(m_MeetingId); } LOGGER(LOG_CLASS_BUSI, LOG_LEVEL_WARNING, _T("{Session}: 对端线路转换为会议失败, HostLine = %u, PeerLine = %u"), m_LineHost.toIntId(), m_LinePeer.toIntId()); return false; } } return true; } void CCallSession::__setTimer(UINT TimmerId, UINT Elapse) { m_SessionTimer.StopSafely(); m_SessionTimer.SetTimedEvent(this, &CCallSession::__onTimerPostProcessing); m_SessionTimer.Start(Elapse, false, true, WT_EXECUTEDEFAULT); } void CCallSession::__onTimerPostProcessing(void) { CMC::GetInstance().dropCall(m_LineHost, true); }