#include "StdAfx.h" #include "CallSession.h" #include "LogicLine.h" #include "Record.h" #include "TaskMgr.h" #include "IvrFlow.h" #include "IvrFlowHolder.h" #include "StatisticsMgr.h" #include "LineHolder.h" #include "CtiCore.h" #include "NetworkCti.h" #include "LogicLineExt.h" CCallSession::CCallSession(ULONG CallId) : m_CallId(CallId), m_RecFile(_T("")), m_Data(_T("")) { } CCallSession::~CCallSession(void) { } /***************************************************************** **【函数名称】 __procLineRecord **【函数功能】 处理线路录音 **【参数】 pRecLine: 录音线路 RecFile:录音文件 **【返回值】 ****************************************************************/ void CCallSession::__procLineRecord( CLogicLine* pRecLine, CString& RecFile ) { // 设置会话中录音文件名 m_RecFile = RecFile; // 设置录音线路的录音文件名 pRecLine->setRecordFile(RecFile); // 设置关联线路的录音文件名 CLogicLine* pLine = NULL; CLineHolder& LineHolder = CLineHolder::GetInstance(); POSITION pos = m_LineList.GetHeadPosition(); while(pos != NULL) { pLine = LineHolder.getLogicLine(m_LineList.GetNext(pos)); ASSERT(pLine != NULL); if(pLine != NULL && pRecLine->type() != pLine->type() && pLine->recordFile() == _T("")) pLine->setRecordFile(RecFile); } } /***************************************************************** **【函数名称】 __onLineTalking **【函数功能】 开始通话后的处理函数 **【参数】 pLine:通话线路 **【返回值】 ****************************************************************/ void CCallSession::__onLineTalking( CLogicLine* pLine ) { ASSERT(pLine != NULL); //如果是监听 不再产生录音文件文件路径 if (pLine->opType() == PDU_CMD_AGENT_MONI_LISTEN) return; // 对该线路进行录音处理 CString RecFile = ""; if(CRecord::GetInstance().record(pLine, RecFile)) __procLineRecord(pLine, RecFile); else pLine->setRecordFile(m_RecFile); } /***************************************************************** **【函数名称】 __onLineHangUp **【函数功能】 处理线路挂机(离开会话) **【参数】 pLine:通话线路 **【返回值】 ****************************************************************/ void CCallSession::__onLineHangUp( CLogicLine* pLine ) { // 通知IVR线路挂机 if (pLine->type() == DEV_RES_TYPE_TRUNK || pLine->type() == DEV_RES_TYPE_VOIP) { // 显示日志 ILogger::getInstance().log(LOG_CLASS_BUSI, LOG_LEVEL_NORMAL, _T("{CallSession}: [外线挂机], Trunk = %d,CallId = %d,caller=%s,callee=%s"), pLine->lineId(), m_CallId, pLine->callerNum(), pLine->calleeNum()); // 通知IVR外线挂机 CIvrFlow* pIvrFlow = CIvrFlowHolder::GetInstance().getFlowByLineId(pLine->lineId()); if (pIvrFlow != NULL) { ILogger::getInstance().log(LOG_CLASS_BUSI, LOG_LEVEL_NORMAL, _T("{CallSession}: [外线挂机], Trunk = %d,IvrFlow_assoLineId=%d"), pLine->lineId(), pIvrFlow->assoLineId()); pIvrFlow->procLineHangUp(); } if (pLine->opType() != PDU_CMD_AGENT_FAX && pLine->opType() != PDU_CMD_IVR_FAX) { // 通知外线关联Task销毁,不在向IVR发返回消息 CTaskMgr::GetInstance().removeTask(pLine->taskIdBinded()); } } // 2021-12-21 返回市民挂机状态 if (pLine->type() == DEV_RES_TYPE_TRUNK && pLine->isFirstTrunk()) { auto pAssoLine = getAssoLine(pLine); if (pAssoLine != NULL && pAssoLine->type() == DEV_RES_TYPE_EXT && pAssoLine->isMeeting()) { CPduEntity cmd(PDU_CMD_AGENT_HANGUP); cmd.SetToExecReturn(); cmd.SetDataUInt(1, pAssoLine->lineId()); cmd.SetDataUInt(2, pAssoLine->getAgentNum()); CString lineId; lineId.Format("%u", pAssoLine->lineId()); if (pAssoLine->callerNum() == lineId) cmd.SetDataString(3, pLine->calleeNum()); else cmd.SetDataString(3, pLine->callerNum()); CNetworkCti::GetInstance().send2ACD(cmd); } } // 统计挂机 T_EvtHangUp repInfo; memset(&repInfo, 0, sizeof(repInfo)); repInfo.nHangUpFlag = (m_LineList.GetCount() > 1 ? 0:1); // 0本端先挂机 1对端先挂机 CStatisticsMgr::GetInstance().onCallDetail(m_CallId, REP_EVENT_HANG_UP, pLine->lineId(), &repInfo); // 移除线路 POSITION pos = m_LineList.Find(pLine->lineId()); if(pos != NULL) m_LineList.RemoveAt(pos); // 任务(协商转移)失败时,不重置发起方的逻辑线路信息 if (pLine->opResult() == FALSE && pLine->opType() == PDU_CMD_AGENT_CONSULTATION_CALL) pLine->opType() = PDU_CMD_UNKNOWN; else { pLine->resetLine(); // 重置线路信息 } } void CCallSession::__onSetChannelVar(CLogicLine * pLine, CLogicLine * pTempLine) { if (pLine == NULL || pTempLine == NULL) return; if (pLine->type() == DEV_RES_TYPE_EXT && pLine->isMeeting()) return; if (pTempLine->type() == DEV_RES_TYPE_EXT && pTempLine->isMeeting()) return; // 会议中不识别 LineOpParam pLineOpParam; memset(&pLineOpParam, 0, sizeof(pLineOpParam)); sprintf_s(pLineOpParam.szParam3, "%ld", pLine->callId()); // 保存callid AsrInfo asrInfo; asrInfo.callId = std::to_string(m_CallId); // callid asrInfo.callStartTime = GetUnixTime(); // 接通时间 CString str = m_RecFile; str.Replace('\\',','); // 替换路径中的 \为,,解析时再由逗号转为反斜杠 asrInfo.reference = str.GetBuffer(0); // 录音路径 if (pLine->type() == DEV_RES_TYPE_EXT) // { CString lineId; lineId.Format("%d", pLine->lineId()); if (lineId == pLine->calleeNum()) // 该线路被叫,坐席呼入 { asrInfo.direction = "CallIn"; // 呼叫方向 } else { asrInfo.direction = "CallOut"; } asrInfo.agentId = std::to_string(pLine->getAgentNum()); // 坐席id CString str; str = pLine->calleeNum(); asrInfo.calledId = str.GetBuffer(0); // 被叫号码 str.ReleaseBuffer(); str = pLine->callerNum(); asrInfo.callerId = str.GetBuffer(0); // 主叫号码 str.ReleaseBuffer(); asrInfo.vocDirect = "Agent"; //角色标识,坐席 std::string asrStr; asrInfo >> asrStr; memset(pLineOpParam.szParam4, 0, sizeof(pLineOpParam.szParam4)); strcpy_s(pLineOpParam.szParam4, asrStr.c_str()); CCtiCore::GetInstance().getDevLink().exec(-1, LINE_OP_SET_CHANNEL_VARIABLE, pLine->lineId(), &pLineOpParam); if (pTempLine->type() == DEV_RES_TYPE_TRUNK) // 另一条是外线 asrInfo.vocDirect = "User"; //角色标识,坐席 asrStr.clear(); asrInfo >> asrStr; memset(pLineOpParam.szParam4, 0, sizeof(pLineOpParam.szParam4)); strcpy_s(pLineOpParam.szParam4, asrStr.c_str()); CCtiCore::GetInstance().getDevLink().exec(-1, LINE_OP_SET_CHANNEL_VARIABLE, pTempLine->lineId(), &pLineOpParam); } else // 当前线路是外线 { if (pTempLine->type() == DEV_RES_TYPE_TRUNK) return; // 如果两条线路都是外线,不处理 CString lineId; lineId.Format("%d", pTempLine->lineId()); if (lineId == pTempLine->calleeNum()) // 该线路被叫,坐席呼入 { asrInfo.direction = "CallIn"; // 呼叫方向 } else { asrInfo.direction = "CallOut"; } asrInfo.agentId = std::to_string(pTempLine->getAgentNum()); // 坐席id CString str; str = pTempLine->calleeNum(); asrInfo.calledId = str.GetBuffer(0); // 被叫号码 str.ReleaseBuffer(); str = pTempLine->callerNum(); asrInfo.callerId = str.GetBuffer(0); // 主叫号码 str.ReleaseBuffer(); asrInfo.vocDirect = "Agent"; //角色标识,坐席 std::string asrStr; asrInfo >> asrStr; memset(pLineOpParam.szParam4, 0, sizeof(pLineOpParam.szParam4)); strcpy_s(pLineOpParam.szParam4, asrStr.c_str()); CCtiCore::GetInstance().getDevLink().exec(-1, LINE_OP_SET_CHANNEL_VARIABLE, pTempLine->lineId(), &pLineOpParam); asrInfo.vocDirect = "User"; //角色标识,坐席 asrStr.clear(); asrInfo >> asrStr; memset(pLineOpParam.szParam4, 0, sizeof(pLineOpParam.szParam4)); strcpy_s(pLineOpParam.szParam4, asrStr.c_str()); CCtiCore::GetInstance().getDevLink().exec(-1, LINE_OP_SET_CHANNEL_VARIABLE, pLine->lineId(), &pLineOpParam); } } /***************************************************************** **【函数名称】 getAssoLineExt **【函数功能】 获取指定线路的关联线路 **【参数】 pHostLine:指定线路 **【返回值】 关联线路对象 ****************************************************************/ CLogicLine* CCallSession::getAssoLine( CLogicLine* pHostLine ) { if(m_LineList.GetCount() < 2) return NULL; CLineHolder& LineHolder = CLineHolder::GetInstance(); POSITION pos = m_LineList.GetHeadPosition(); while(pos != NULL) { CLogicLine* pLine = LineHolder.getLogicLine(m_LineList.GetNext(pos)); ASSERT(pLine != NULL); if(pLine != NULL && pLine != pHostLine) return pLine; } return NULL; } /***************************************************************** **【函数名称】 addLine **【函数功能】 会话中添加线路 **【参数】 pLine: 待添加线路 **【返回值】 ****************************************************************/ void CCallSession::addLine( CLogicLine *pLine ) { ASSERT(pLine != NULL); if(pLine == NULL) return; if(m_LineList.Find(pLine->lineId()) != NULL) return; m_LineList.AddTail(pLine->lineId()); pLine->callId() = m_CallId; } /***************************************************************** **【函数名称】 onLineStatusUpdated **【函数功能】 处理线路状态改变 **【参数】 pLine: 状态变化的线路 **【返回值】 ****************************************************************/ void CCallSession::onLineStatusUpdated( CLogicLine* pLine ) { // 保持状态过滤 UINT Status = (HELD_STATE_FILTER_MASK & pLine->status()); ILogger::getInstance().log(LOG_CLASS_BUSI, LOG_LEVEL_NORMAL, _T("{CallSession}:onLineStatusUpdated, Trunk = %d,CallId = %d,Status=%d"), pLine->lineId(), m_CallId, Status); // 通话 if(Status == TRUNK_STATE_TALKING || Status == INNER_STATE_TALKING) { // 有至少两个线路通话时才录音 CLogicLine* pTempLine = NULL; CLineHolder& LineHolder = CLineHolder::GetInstance(); POSITION pos = m_LineList.GetHeadPosition(); while(pos) { pTempLine = LineHolder.getLogicLine(m_LineList.GetNext(pos)); ASSERT(pTempLine != NULL); if(pTempLine == NULL || pTempLine == pLine) continue; UINT nTempStatus = (HELD_STATE_FILTER_MASK & pTempLine->status()); if(nTempStatus == INNER_STATE_TALKING || nTempStatus == TRUNK_STATE_TALKING) { __onLineTalking(pLine); __onLineTalking(pTempLine); // 2021-12-3 设置asr通道变量 __onSetChannelVar(pLine, pTempLine); break; } } } // 空闲状态当挂机处理 if(Status == TRUNK_STATE_FREE || Status == INNER_STATE_FREE) __onLineHangUp(pLine); } void CCallSession::onRecord(CLogicLine* pLine) { //ILogger::getInstance().log(LOG_CLASS_SOCKET, LOG_LEVEL_NORMAL, _T("{CallSession},onRecord")); CLogicLine* pTempLine = NULL; CLineHolder& LineHolder = CLineHolder::GetInstance(); POSITION pos = m_LineList.GetHeadPosition(); while (pos) { pTempLine = LineHolder.getLogicLine(m_LineList.GetNext(pos)); ASSERT(pTempLine != NULL); if (pTempLine == NULL || pTempLine == pLine) continue; UINT nTempStatus = (HELD_STATE_FILTER_MASK & pTempLine->status()); if (nTempStatus == INNER_STATE_TALKING || nTempStatus == TRUNK_STATE_TALKING) { ILogger::getInstance().log(LOG_CLASS_SOCKET, LOG_LEVEL_NORMAL, _T("{CallSession},onRecord,%d"), nTempStatus); __onLineTalking(pLine); __onLineTalking(pTempLine); break; } else { ILogger::getInstance().log(LOG_CLASS_SOCKET, LOG_LEVEL_NORMAL, _T("{CallSession},onRecord,nTempStatus=%d"), nTempStatus); } } }