#include "StdAfx.h" #include "SessionShell.h" #include "CallSession.h" #include "MC.h" #include "ProxyShell.h" SINGLETON_IMPLEMENT(CSessionShell) CSessionShell::CSessionShell(void) : m_pThreadObj(NULL), m_Stop(true), m_nBaseCallId(0) { m_mapCall.InitHashTable(4999); } CSessionShell::~CSessionShell(void) { __freeAllLineState(); __freeAllCall(); } /***************************************************************** **【函数名称】 __procLineStatus **【函数功能】 将事件队列中的事件进行分发处理 **【参数】 **【返回值】 当前队列中结余的事件数 ****************************************************************/ UINT CSessionShell::__procLineStatus( void ) { int LeftCount = 0; LineState* pInfo = __popLineState(LeftCount); if(pInfo == NULL) return LeftCount; // 开始处理事件 if(pInfo->nSession == SESSION_INVALID_CALL) // 状态变化的线路未在会话中 { if((pInfo->nState == VIRTUAL_LINE_STATE_FREE || pInfo->nState == VIRTUAL_LINE_STATE_DISABLED || pInfo->nState == VIRTUAL_LINE_STATE_REMOVE)) { // 不需启动会话,直接通知上层逻辑 CProxyShell::GetInstance().onLineStateUpdated(pInfo->nLineDevId, SESSION_INVALID_CALL, SESSION_INVALID_SUB_CALL, pInfo->nState, pInfo->szCallerNum, pInfo->szCalleeNum); } else { CCallSession* pNewCall = __createCall(pInfo->nLineDevId); // 创建新会话 pNewCall->onLineStateChanged(pInfo->nLineDevId, pInfo->nState, pInfo->szCallerNum, pInfo->szCalleeNum); } // end if(nDevState) } else // 线路在会话中 { CCallSession* pCall = __getCall(pInfo->nSession); if(pCall != NULL) { pCall->onLineStateChanged(pInfo->nLineDevId, pInfo->nState, pInfo->szCallerNum, pInfo->szCalleeNum); // 是否清除会话 if(pInfo->nState == VIRTUAL_LINE_STATE_FREE && pCall->lineCount() == 0) { __delCall(pInfo->nSession); pCall = NULL; } // end if } else { CProxyShell::GetInstance().onLineStateUpdated(pInfo->nLineDevId, SESSION_INVALID_CALL, SESSION_INVALID_SUB_CALL, pInfo->nState, pInfo->szCallerNum, pInfo->szCalleeNum); } } // end if // 处理完成 delete pInfo; return LeftCount; } /***************************************************************** **【函数名称】 __wait **【函数功能】 置线程于等待信号状态 **【参数】 **【返回值】 ****************************************************************/ void CSessionShell::__wait( void ) { m_ThreadWaitFlag.Lock(); } /***************************************************************** **【函数名称】 __pushLineState **【函数功能】 存入一个线路状态事件 **【参数】 **【返回值】 *****************************************************************/ void CSessionShell::__pushLineState( LineState* pState ) { m_Cs4LineStateEvent.Lock(); m_listLineStatus.AddTail(pState); m_Cs4LineStateEvent.Unlock(); } /***************************************************************** **【函数名称】 __popLineState **【函数功能】 弹出一个线路状态事件 **【参数】 **【返回值】 *****************************************************************/ LineState* CSessionShell::__popLineState( int& LeftCount ) { LineState* pState = NULL; m_Cs4LineStateEvent.Lock(); if((LeftCount = m_listLineStatus.GetCount()) > 0) { --LeftCount; pState = m_listLineStatus.RemoveHead(); } m_Cs4LineStateEvent.Unlock(); return pState; } /***************************************************************** **【函数名称】 __freeAllLineState **【函数功能】 释放所有线路状态事件 **【参数】 **【返回值】 *****************************************************************/ void CSessionShell::__freeAllLineState( void ) { m_Cs4LineStateEvent.Lock(); while(m_listLineStatus.GetCount() > 0) { delete m_listLineStatus.RemoveHead(); } m_Cs4LineStateEvent.Unlock(); } /***************************************************************** **【函数名称】 __createCall **【函数功能】 生成新会话 **【参数】 HostLineId 会话的主控线路ID **【返回值】 新创建的会话实体指针 *****************************************************************/ CCallSession* CSessionShell::__createCall(CRDRID HostLineId) { CCallSession* pNewCall = NULL; m_Cs4Session.Lock(); pNewCall = new CCallSession(++m_nBaseCallId); m_mapCall.SetAt(m_nBaseCallId, pNewCall); m_Cs4Session.Unlock(); pNewCall->insertLine(HostLineId, CALL_PARTY_HOST, true); // 添加主控线路到会话 return pNewCall; } /***************************************************************** **【函数名称】 __delCall **【函数功能】 删除会话 **【参数】 会话ID **【返回值】 *****************************************************************/ void CSessionShell::__delCall( long CallId ) { CCallSession* pCall = NULL; m_Cs4Session.Lock(); if(m_mapCall.Lookup(CallId, pCall)) { m_mapCall.RemoveKey(CallId); delete pCall; } m_Cs4Session.Unlock(); } /***************************************************************** **【函数名称】 __GetCall **【函数功能】 查找指定的会话 **【参数】 会话ID **【返回值】 指定ID的会话实体 *****************************************************************/ CCallSession* CSessionShell::__getCall(long CallId) { CCallSession* pCall = NULL; m_Cs4Session.Lock(); m_mapCall.Lookup(CallId, pCall); m_Cs4Session.Unlock(); return pCall; } /***************************************************************** **【函数名称】 __freeAllCall **【函数功能】 销毁所有会话 **【参数】 **【返回值】 *****************************************************************/ void CSessionShell::__freeAllCall( void ) { m_Cs4Session.Lock(); long CallId; CCallSession* pCall = NULL; POSITION Pos = m_mapCall.GetStartPosition(); while(Pos != NULL) { m_mapCall.GetNextAssoc(Pos, CallId, pCall); ASSERT(pCall != NULL); delete pCall; } m_mapCall.RemoveAll(); m_Cs4Session.Unlock(); } /***************************************************************** **【函数名称】 __DispatchLineStatus **【函数功能】 分发线路状态事件的线程函数 **【参数】 **【返回值】 ****************************************************************/ UINT CSessionShell::__dispatchLineState(LPVOID pParam) { CSessionShell* pSelf = (CSessionShell*)pParam; ASSERT(pSelf != NULL); // 工作线程开始处理 while(!pSelf->m_Stop) { pSelf->__wait(); while(pSelf->__procLineStatus() > 0); } // end while return 0; } /***************************************************************** **【函数名称】 procReqDialSetup **【函数功能】 线路操作控制[临时呼叫启动] **【参数】 SubCall 当前操作关联的子会话ID(回传参数) pInfo 呼叫内容 **【返回值】 操作启动是否成功 *****************************************************************/ bool CSessionShell::procReqDialSetup( long &SubCall, PendingCallInfo* pInfo ) { CCallSession* pCall = NULL; if(pInfo->nCall == 0) pCall = __createCall(pInfo->nHostLine); // 创建新会话 else pCall = __getCall(pInfo->nCall); ASSERT(pCall != NULL); if(pCall == NULL) return false; return pCall->setupPendingCall(SubCall, pInfo); } /***************************************************************** **【函数名称】 procReqLeave **【函数功能】 线路操作控制[指定线路退出会话且挂机] **【参数】 Call 线路要退出的会话 LineId 线路ID **【返回值】 操作启动是否成功 *****************************************************************/ bool CSessionShell::procReqLeave( long Call, CRDRID LineId ) { CCallSession* pCall = __getCall(Call); if(pCall == NULL) return false; return pCall->lineLeave(LineId); } /***************************************************************** **【函数名称】 procReqInstead **【函数功能】 线路操作控制[代接指定线路] **【参数】 Call 目标线路所在的会话 HostLine 申请代接的线路 PeerLine 被代接的线路 ExtNum 申请代接线路的分机号 **【返回值】 操作启动是否成功 *****************************************************************/ bool CSessionShell::procReqInstead( long Call, CRDRID HostLine, CRDRID PeerLine, UINT ExtNum ) { CCallSession* pCall = __getCall(Call); if(pCall == NULL) return false; return pCall->lineInstead(HostLine, PeerLine, ExtNum); } /***************************************************************** **【函数名称】 procReqIntercept **【函数功能】 线路操作控制[替换通话中的线路] **【参数】 Call 目标线路所在的会话 HostLine 主控线路 PeerLine 被替换的线路 **【返回值】 操作启动是否成功 *****************************************************************/ bool CSessionShell::procReqIntercept( long Call, CRDRID HostLine, CRDRID PeerLine ) { CCallSession* pCall = __getCall(Call); if(pCall == NULL) return false; return pCall->lineIntercept(HostLine, PeerLine); } /***************************************************************** **【函数名称】 procReqInsert **【函数功能】 线路操作控制[插入通话中的线路] **【参数】 Call 线路要进入的会话 HostLine 要进入会话的线路ID PeerLine 被插入线路的线路ID **【返回值】 操作启动是否成功 *****************************************************************/ bool CSessionShell::procReqInsert( long Call, CRDRID HostLine, CRDRID PeerLine ) { CCallSession* pCall = __getCall(Call); if(pCall == NULL) return false; return pCall->lineInsert(HostLine, PeerLine); } /***************************************************************** **【函数名称】 procReqListen **【函数功能】 线路操作控制[监听通话中的线路] **【参数】 Call 目标线路所在的会话 HostLine 主控线路 PeerLine 被监听的线路 **【返回值】 操作启动是否成功 *****************************************************************/ bool CSessionShell::procReqListen( long Call, CRDRID HostLine, CRDRID PeerLine ) { CCallSession* pCall = __getCall(Call); if(pCall == NULL) return false; return pCall->lineListen(HostLine, PeerLine); } /***************************************************************** **【函数名称】 procReqRecord **【函数功能】 线路操作控制[录音启动] **【参数】 Call 目标线路所在的会话 HostLine 主控线路 lpFileName 录音文件名 **【返回值】 操作启动是否成功 *****************************************************************/ bool CSessionShell::procReqRecord( long Call, CRDRID HostLine, LPCTSTR lpFileName ) { CCallSession* pCall = __getCall(Call); if(pCall == NULL) return false; return pCall->lineRecord(HostLine, lpFileName); } /***************************************************************** **【函数名称】 procReqLeaveWord **【函数功能】 线路操作控制[留言启动] **【参数】 Call 目标线路所在的会话 HostLine 主控线路 pContent 留言参数 **【返回值】 操作启动是否成功 *****************************************************************/ bool CSessionShell::procReqLeaveWord( long Call, CRDRID HostLine, RecordContent* pContent ) { CCallSession* pCall = __getCall(Call); if(pCall == NULL) return false; return pCall->lineLeaveWord(HostLine, pContent); } /***************************************************************** **【函数名称】 procReqMute **【函数功能】 线路操作控制[静音控制] **【参数】 Call 目标线路所在的会话 HostLine 主控线路 **【返回值】 操作启动是否成功 *****************************************************************/ bool CSessionShell::procReqMute( long Call, CRDRID HostLine, bool IsOn ) { CCallSession* pCall = __getCall(Call); if(pCall == NULL) return false; return pCall->lineMute(HostLine, IsOn); } /***************************************************************** **【函数名称】 procReqConsultConfirm **【函数功能】 线路操作控制[协商呼叫] **【参数】 Call 目标线路所在的会话 HostLine 主控线路 PeerLine 被叫线路 Type 会话类型 0 -> 转移,1 -> 会议 **【返回值】 操作是否成功 *****************************************************************/ bool CSessionShell::procReqConsultConfirm( long Call, CRDRID HostLine, CRDRID PeerLine, int Type ) { CCallSession* pCall = __getCall(Call); if(pCall == NULL) return false; return pCall->lineConsultConfirm(PeerLine, Type); } /***************************************************************** **【函数名称】 onDevResourceNew **【函数功能】 线路初始化 **【参数】 **【返回值】 *****************************************************************/ void CSessionShell::onDevResourceNew( CRDRID Id ) { // 转发初始化线路信息至ClientProxy CProxyShell::GetInstance().onLineNew(Id); } /***************************************************************** **【函数名称】 onDevResourceDel **【函数功能】 线路逆初始化 **【参数】 **【返回值】 *****************************************************************/ void CSessionShell::onDevResourceDel( CRDRID Id ) { // 转发删除线路信息至ClientProxy CProxyShell::GetInstance().onLineDelete(Id); } /***************************************************************** **【函数名称】 OnLineStateChanged **【函数功能】 线路状态变化 **【参数】 Id 线路设备ID Session 物理线路关联的主呼叫ID State 线路当前状态(ACS_LINE_STATUS) Caller 主叫号码 Callee 被叫号码 **【返回值】 *****************************************************************/ void CSessionShell::onLineStateChanged( CRDRID Id, long Session, VIRTUAL_LINE_STATE State, LPCTSTR Caller, LPCTSTR Callee ) { // 填充事件内容 LineState* pInfo = new LineState; memset(pInfo, 0, sizeof(LineState)); pInfo->nLineDevId = Id; pInfo->nSession = Session; pInfo->nState = State; if(Caller != NULL) lstrcpy(pInfo->szCallerNum, Caller); if(Callee != NULL) lstrcpy(pInfo->szCalleeNum, Callee); __pushLineState(pInfo); // 需要唤醒分发线程 m_ThreadWaitFlag.SetEvent(); } /***************************************************************** **【函数名称】 onLineChannelEvent **【函数功能】 线路向上层发送的设备主动事件 **【参数】 Id 触发事件的线路ID Session 线路所在的会话 EvtType 事件类型 lpContent 事件内容 **【返回值】 *****************************************************************/ bool CSessionShell::onLineChannelEvent( CRDRID Id, long Session, DEV_CH_EVT_TYPE EvtType, LPCTSTR lpContent, UINT ExtenId /*= 0*/ ) { switch(EvtType) { case DEV_CH_EVT_FUN_CODE: // 收取功能键 case DEV_CH_EVT_PLAY_END: // 放音结束 case DEV_CH_EVT_OFF_HOOK: // 内线摘机 case DEV_CH_EVT_FAX_OK: // 传真成功 case DEV_CH_EVT_FAX_FAILED: // 传真失败 case DEV_CH_EVT_HOLD_ON: // 保持 case DEV_CH_EVT_TAKE_BACK: // 接回 case DEV_CH_EVT_CALL_FAILD_CAUSE: // 呼叫失败原因 { return CProxyShell::GetInstance().onDevChannelEvent(Id, EvtType, lpContent, ExtenId); } break; case DEV_CH_EVT_REC_END: // 录音完成 { CCallSession* pSession = __getCall(Session); ASSERT(pSession != NULL); if(pSession != NULL) pSession->onRecordStop(Id, atoi(lpContent)); } break; } // end switch return true; } /***************************************************************** **【函数名称】 start **【函数功能】 启动 **【参数】 **【返回值】 ****************************************************************/ void CSessionShell::start( void ) { m_Stop = false; m_pThreadObj = AfxBeginThread(__dispatchLineState, this); // 启动事件处理线程 LOGGER(LOG_CLASS_BUSI, LOG_LEVEL_NORMAL, _T("{SessionShell}: 会话管理器启动")); } /***************************************************************** **【函数名称】 stop **【函数功能】 停止 **【参数】 **【返回值】 ****************************************************************/ void CSessionShell::stop( void ) { m_Stop = true; if(m_pThreadObj != NULL) { DWORD ExitCode; GetExitCodeThread(m_pThreadObj->m_hThread, &ExitCode); if(ExitCode == STILL_ACTIVE) { m_ThreadWaitFlag.SetEvent(); WaitForSingleObject(m_pThreadObj->m_hThread, INFINITE); } m_pThreadObj = NULL; } __freeAllLineState(); __freeAllCall(); }