#include "StdAfx.h" #include "EslGateway.h" #include "FsProxy.h" #include "ChanTrunk.h" CEslGateway::CEslGateway(CFsProxy* pParent) : m_pParent(pParent), m_Stop(true), m_ListenThread(NULL), m_EventThread(NULL) { } CEslGateway::~CEslGateway(void) { } /***************************************************************** **【函数名称】 __eslListenThread **【函数功能】 ESL服务端线程函数 **【参数】 **【返回值】 *****************************************************************/ DWORD WINAPI CEslGateway::__eslListenThread( LPVOID lpParameter ) { CEslGateway* pGw = (CEslGateway*)lpParameter; ASSERT(pGw != NULL); if(esl_listen_threaded(_T("localhost"), CConfig::ivrPort(), __eslListenThreadCb, pGw, CConfig::trunkCount()) == ESL_SUCCESS) return 1; else { LOGGER(LOG_LEVEL_WARNING, _T("{EslGateway}: 监听IVR连接时连接出错")); pGw->m_pParent->onEslDisconnect(); return 0; } } /***************************************************************** **【函数名称】 __eslListenThreadCb **【函数功能】 ESL服务端线程回调函数 **【参数】 **【返回值】 *****************************************************************/ void CEslGateway::__eslListenThreadCb( esl_socket_t server_sock, esl_socket_t client_sock, struct sockaddr_in *addr, void *user_data ) { CEslGateway* pGw = (CEslGateway*)user_data; ASSERT(pGw != NULL); if(pGw->m_Stop) return; esl_handle_t Handle; memset(&Handle,0,sizeof(esl_handle_t)); esl_attach_handle(&Handle, client_sock, addr); if(Handle.info_event==NULL) return; //ti 判断是否为空 防止继续执行出错!!! // 获取通道ID LPCTSTR ChanId = esl_event_get_header(Handle.info_event, ESL_HEADER_CHANID); ASSERT(ChanId != NULL); if(ChanId == NULL) { LOGGER(LOG_LEVEL_WARNING, _T("{EslGateway}: 处理客户端连接时获取通道ID失败")); return; } // 查找关联通道 CChanTrunk* pTrunk = dynamic_cast(pGw->m_pParent->getBusyChan(ChanId)); ASSERT(pTrunk != NULL); if(pTrunk == NULL) { LOGGER(LOG_LEVEL_WARNING, _T("{EslGateway}: 处理客户端连接时获取通道失败, ChanId = %s"), ChanId); return; } LOGGER(LOG_LEVEL_NORMAL, _T("{EslGateway}: 客户端连接, TrunkNo = %lu"), pTrunk->no()); pGw->__processCallConnect(&Handle, pTrunk); esl_disconnect(&Handle); } /***************************************************************** **【函数名称】 __processCallConnect **【函数功能】 处理呼叫连接 **【参数】 **【返回值】 *****************************************************************/ void CEslGateway::__processCallConnect( esl_handle_t* pHandle, CChanTrunk* pTrunk ) { // 连接相关设置 esl_events(pHandle, ESL_EVENT_TYPE_PLAIN, _T("CHANNEL_EXECUTE_COMPLETE")); esl_filter(pHandle, ESL_HEADER_CHANID, pTrunk->chanId()); esl_send_recv(pHandle, _T("linger 5")); if(!pTrunk->processCallConnect(pHandle)) return; esl_status_t Status; while(!pTrunk->isStopConnect()) { Status = esl_recv_timed(pHandle, 500); if(Status == ESL_SUCCESS) { esl_event_t* pEvent = pHandle->last_ievent; if(pEvent != NULL && pEvent->event_id == ESL_EVENT_CHANNEL_EXECUTE_COMPLETE) { LPCTSTR Application = esl_event_get_header(pEvent, ESL_HEADER_APPLICATION); ASSERT(Application != NULL); if (Application == NULL) { LOGGER(LOG_LEVEL_WARNING, _T("{EslGateway}: NotFoundApplication, TrunkNo = %lu,EventName=%s,%s"), pTrunk->no(), pEvent->owner, pEvent->subclass_name); }else{ APP_EXEC_NOTIFY Notify; ZeroMemory(&Notify, sizeof(Notify)); lstrcpy(Notify.App, Application); pTrunk->onAppExecuted(&Notify); } } } else if(Status == ESL_BREAK) continue; else break; } pTrunk->processCallDisconnect(); } /***************************************************************** **【函数名称】 __eventThread **【函数功能】 ESL事件监听线程 **【参数】 **【返回值】 *****************************************************************/ DWORD WINAPI CEslGateway::__eventThread( LPVOID lpParameter ) { CEslGateway* pEslGw = (CEslGateway*)lpParameter; ASSERT(pEslGw != NULL); esl_event_t* pEvent = NULL; esl_handle_t* pListenHandle = &pEslGw->m_EslHdl4Listen; // 下面的设置保证执行同时多个APP时,后面的不会抢占前面的 pListenHandle->event_lock = 1; while (!pEslGw->m_Stop) { // esl_recv_event会阻塞线程,其第二个参数为1,表示优先检查内部缓存列表,防止遗漏事件。 if(esl_recv_event(pListenHandle, 1, NULL) == ESL_SUCCESS) { pEvent = pListenHandle->last_ievent; if(pEvent != NULL) pEslGw->__onEslEvent(pEvent); } else { // 连接中断 pEslGw->__onEslDisconnect(); return 0; } } return 1; } /***************************************************************** **【函数名称】 __onEslEvent **【函数功能】 ESL事件处理 **【参数】 **【返回值】 *****************************************************************/ void CEslGateway::__onEslEvent( esl_event_t* pEvent ) { switch(pEvent->event_id) { case ESL_EVENT_BACKGROUND_JOB: __onEslEvtBgJobDone(pEvent); break; case ESL_EVENT_CHANNEL_CREATE: case ESL_EVENT_CHANNEL_ANSWER: case ESL_EVENT_CHANNEL_BRIDGE: case ESL_EVENT_CHANNEL_PROGRESS: case ESL_EVENT_CHANNEL_PROGRESS_MEDIA: case ESL_EVENT_CHANNEL_HANGUP_COMPLETE: __onEslEvtChanEvent(pEvent); break; case ESL_EVENT_DTMF: __onEslEvtDtmf(pEvent); break; case ESL_EVENT_CHANNEL_HOLD: __onEslEvtHold(pEvent, EVENT_HOLD); break; case ESL_EVENT_CHANNEL_UNHOLD: __onEslEvtHold(pEvent, EVENT_UNHOLD); break; case ESL_EVENT_CUSTOM: __onEslEvtCustom(pEvent); break; } } /***************************************************************** **【函数名称】 __onEslDisconnect **【函数功能】 ESL连接中断处理 **【参数】 **【返回值】 *****************************************************************/ void CEslGateway::__onEslDisconnect( void ) { LOGGER(LOG_LEVEL_WARNING, _T("{EslGateway}: 监听通道事件时连接中断")); m_Stop = true; //esl_disconnect(&m_EslHdl4Listen); //esl_disconnect(&m_EslHdl4Send); CloseHandle(m_EventThread); m_EventThread = NULL; m_pParent->onEslDisconnect(); } /***************************************************************** **【函数名称】 __onEslEvtBgJobDone **【函数功能】 后台任务执行结束事件处理 **【参数】 **【返回值】 *****************************************************************/ void CEslGateway::__onEslEvtBgJobDone( esl_event_t* pEvent ) { BG_JOB_NOTIFY Notify; ZeroMemory(&Notify, sizeof(BG_JOB_NOTIFY)); LPCTSTR HeaderValue = esl_event_get_header(pEvent, ESL_HEADER_JOB_UUID); ASSERT(HeaderValue != NULL); Notify.JobInstance = atol(HeaderValue); HeaderValue = esl_event_get_header(pEvent, ESL_HEADER_JOB_CMD); ASSERT(HeaderValue != NULL); lstrcpy(Notify.JobCmd, HeaderValue); HeaderValue = esl_event_get_body(pEvent); ASSERT(HeaderValue != NULL); if(HeaderValue != NULL) lstrcpy(Notify.JobBody, HeaderValue); m_pParent->onEslEvtBgJobDone(&Notify); } /***************************************************************** **【函数名称】 __onEslEvtChanEvent **【函数功能】 通道事件处理 **【参数】 **【返回值】 *****************************************************************/ void CEslGateway::__onEslEvtChanEvent( esl_event_t* pEvent ) { CHAN_EVENT_NOTIFY Notify; ZeroMemory(&Notify, sizeof(Notify)); LPCTSTR HeaderValue = NULL; // 获取事件ID Notify.EventId = (CHAN_EVENT_ID)pEvent->event_id; // 获取通道方向 HeaderValue = esl_event_get_header(pEvent, ESL_HEADER_DIRECTION); ASSERT(HeaderValue != NULL); if(lstrcmp(HeaderValue, ESL_HDR_DIRECTION_INBOUND) == 0) Notify.Direction = CALL_DIRECTION_INBOUND; else Notify.Direction = CALL_DIRECTION_OUTBOUND; // 获取会话ID HeaderValue = esl_event_get_header(pEvent, ESL_HEADER_CALLID); ASSERT(HeaderValue != NULL); lstrcpy(Notify.CallId, HeaderValue); // 获取通道ID HeaderValue = esl_event_get_header(pEvent, ESL_HEADER_CHANID); ASSERT(HeaderValue != NULL); lstrcpy(Notify.ChanId, HeaderValue); // 获取主被叫 HeaderValue = esl_event_get_header(pEvent, ESL_HEADER_CALLER); lstrcpy(Notify.Caller, HeaderValue); HeaderValue = esl_event_get_header(pEvent, ESL_HEADER_CALLEE); if(HeaderValue != NULL) lstrcpy(Notify.Callee, HeaderValue); else { HeaderValue = esl_event_get_header(pEvent, ESL_HEADER_DEST_NUM); if(HeaderValue != NULL) lstrcpy(Notify.Callee, HeaderValue); } // 获取挂机原因 HeaderValue = esl_event_get_header(pEvent, ESL_HEADER_HANGUP_CAUSE); if(HeaderValue != NULL) lstrcpy(Notify.HangupCause, HeaderValue); else { HeaderValue = esl_event_get_header(pEvent, ESL_HEADER_CALL_FAILED_CAUSE); if(HeaderValue != NULL) lstrcpy(Notify.HangupCause, HeaderValue); } // 获取通道操作标识 HeaderValue = esl_event_get_header(pEvent, ESL_HEADER_CHAN_OP_INSTANCE); if(HeaderValue != NULL) Notify.ChanOpInstance = atol(HeaderValue); m_pParent->onEslEvtChannel(&Notify); } /***************************************************************** **【函数名称】 __onEslEvtCustom **【函数功能】 自定义事件处理 **【参数】 **【返回值】 *****************************************************************/ void CEslGateway::__onEslEvtCustom( esl_event_t* pEvent ) { LPCTSTR HeaderValue = NULL; HeaderValue = esl_event_get_header(pEvent, ESL_HEADER_SUBCLASS); ASSERT(HeaderValue != NULL); if(lstrcmp(HeaderValue, ESL_HDR_SUBCLASS_SIP_REG) == 0) // 分机注册事件 { HeaderValue = esl_event_get_header(pEvent, ESL_HEADER_EXTEN_NO); ASSERT(HeaderValue != NULL); UINT ExtenNo = 0; sscanf_s(HeaderValue, "%u", &ExtenNo); m_pParent->onEslExtenReg(ExtenNo); } else if(lstrcmp(HeaderValue, ESL_HDR_SUBCLASS_SIP_UNREG) == 0) // 分机注销事件 { HeaderValue = esl_event_get_header(pEvent, ESL_HEADER_EXTEN_NO); ASSERT(HeaderValue != NULL); UINT ExtenNo = 0; sscanf_s(HeaderValue, "%u", &ExtenNo); m_pParent->onEslExtenUnreg(ExtenNo); } } /***************************************************************** **【函数名称】 __onEslEvtDtmf **【函数功能】 DTMF事件处理 **【参数】 **【返回值】 *****************************************************************/ void CEslGateway::__onEslEvtDtmf( esl_event_t* pEvent ) { DTMF_NOTIFY Notify; ZeroMemory(&Notify, sizeof(Notify)); LPCTSTR HeaderValue = NULL; // 获取会话ID HeaderValue = esl_event_get_header(pEvent, ESL_HEADER_CALLID); ASSERT(HeaderValue != NULL); lstrcpy(Notify.CallId, HeaderValue); // 获取通道ID HeaderValue = esl_event_get_header(pEvent, ESL_HEADER_CHANID); ASSERT(HeaderValue != NULL); lstrcpy(Notify.ChanId, HeaderValue); // 获取DTMF HeaderValue = esl_event_get_header(pEvent, ESL_HEADER_DTMF); ASSERT(HeaderValue != NULL); lstrcpy(Notify.DTMF, HeaderValue); m_pParent->onEslEvtDtmf(&Notify); } /***************************************************************** **【函数名称】 __onEslEvtHold **【函数功能】 保持事件处理 **【参数】 **【返回值】 *****************************************************************/ void CEslGateway::__onEslEvtHold( esl_event_t* pEvent, EVENT_HOLD_TYPE EvtType ) { HOLD_NOTIFY Notify; ZeroMemory(&Notify, sizeof(Notify)); LPCTSTR HeaderValue = NULL; // 获取会话ID HeaderValue = esl_event_get_header(pEvent, ESL_HEADER_CALLID); ASSERT(HeaderValue != NULL); lstrcpy(Notify.CallId, HeaderValue); // 获取通道ID HeaderValue = esl_event_get_header(pEvent, ESL_HEADER_CHANID); ASSERT(HeaderValue != NULL); lstrcpy(Notify.ChanId, HeaderValue); // 获取保持事件类型 Notify.EvtType = EvtType; m_pParent->onEslEvtHold(&Notify); } /***************************************************************** **【函数名称】 start **【函数功能】 启动 **【参数】 **【返回值】 *****************************************************************/ bool CEslGateway::start( void ) { //m logger LOGGER(LOG_LEVEL_NORMAL, _T("{EslGateway}: 处理客户端连接, ip = %s,port=%d,pwd=%s"), CConfig::fsAddr(), CConfig::fsPort(), CConfig::fsPwd()); esl_connect(&m_EslHdl4Listen, CConfig::fsAddr(), CConfig::fsPort(), NULL, CConfig::fsPwd()); if(!m_EslHdl4Listen.connected) return false; LOGGER(LOG_LEVEL_NORMAL, _T("{EslGateway}: 处理客户端连接m_EslHdl4Listen OK")); esl_events(&m_EslHdl4Listen, ESL_EVENT_TYPE_PLAIN, _T("BACKGROUND_JOB CHANNEL_CREATE CHANNEL_PROGRESS CHANNEL_PROGRESS_MEDIA CHANNEL_ANSWER CHANNEL_HANGUP_COMPLETE CHANNEL_HOLD CHANNEL_UNHOLD DTMF CUSTOM sofia::register sofia::unregister")); esl_connect(&m_EslHdl4Send, CConfig::fsAddr(), CConfig::fsPort(), NULL, CConfig::fsPwd()); if(!m_EslHdl4Send.connected) { esl_disconnect(&m_EslHdl4Listen); return false; } m_Stop = false; m_EventThread = CreateThread(NULL, 0, __eventThread, this, 0, NULL); ASSERT(m_EventThread != NULL); if(m_EventThread == NULL) { m_Stop = true; esl_disconnect(&m_EslHdl4Listen); esl_disconnect(&m_EslHdl4Send); return false; } m_ListenThread = CreateThread(NULL, 0, __eslListenThread, this, 0, NULL); ASSERT(m_ListenThread != NULL); if(m_ListenThread == NULL) { m_Stop = true; CloseHandle(m_EventThread); m_EventThread = NULL; esl_disconnect(&m_EslHdl4Listen); esl_disconnect(&m_EslHdl4Send); return false; } return true; } /***************************************************************** **【函数名称】 stop **【函数功能】 停止 **【参数】 **【返回值】 *****************************************************************/ void CEslGateway::stop( void ) { if(m_ListenThread != NULL) { DWORD ExitCode; GetExitCodeThread(m_ListenThread, &ExitCode); if(ExitCode == STILL_ACTIVE) TerminateThread(m_ListenThread, 0); CloseHandle(m_ListenThread); m_ListenThread = NULL; } if(!m_Stop) { m_Stop = true; esl_disconnect(&m_EslHdl4Listen); esl_disconnect(&m_EslHdl4Send); if(m_EventThread != NULL) { DWORD ExitCode; GetExitCodeThread(m_EventThread, &ExitCode); if(ExitCode == STILL_ACTIVE) WaitForSingleObject(m_EventThread, INFINITE); CloseHandle(m_EventThread); m_EventThread = NULL; } } } /***************************************************************** **【函数名称】 hangupAll **【函数功能】 挂断所有通道 **【参数】 **【返回值】 *****************************************************************/ bool CEslGateway::hangupAll( void ) { return esl_send_recv(&m_EslHdl4Send, ESL_CMD_HANGUPALL) == ESL_SUCCESS; } /***************************************************************** **【函数名称】 scanExten **【函数功能】 扫描分机 **【参数】 **【返回值】 *****************************************************************/ bool CEslGateway::scanExten( void ) { if(esl_send_recv(&m_EslHdl4Send, ESL_CMD_SCAN_INTERNAL) != ESL_SUCCESS) return false; if (m_EslHdl4Send.last_sr_event == NULL || m_EslHdl4Send.last_sr_event->body == NULL) return false; UINT ExtenId = 0; char Buffer[FS_BUFFER_LEN_NORMAL] = { 0 }; char* lpNext = NULL; char* lpToken = strtok_s(m_EslHdl4Send.last_sr_event->body, ESL_EVT_SPLIT_FLAG, &lpNext); while(lpToken != NULL) { ZeroMemory(Buffer, FS_BUFFER_LEN_NORMAL); lstrcpyn(Buffer, lpToken, ESL_EVT_LEN_BODY_HDR_AUTH_USER); if(lstrcmp(Buffer, ESL_EVT_NAME_BODY_HDR_AUTH_USER) == 0) { sscanf_s(&lpToken[ESL_EVT_POS_BODY_HDR_AUTH_USER], "%u", &ExtenId); m_pParent->onEslExtenReg(ExtenId); } lpToken = strtok_s(NULL, ESL_EVT_SPLIT_FLAG, &lpNext); } return true; } /***************************************************************** **【函数名称】 sendCmd **【函数功能】 发送命令 **【参数】 **【返回值】 *****************************************************************/ bool CEslGateway::sendCmd( LPCTSTR pCmd ) { ASSERT(pCmd != NULL); esl_status_t Status = esl_send_recv(&m_EslHdl4Send, pCmd); return Status == ESL_SUCCESS; } /***************************************************************** **【函数名称】 execute **【函数功能】 执行应用 **【参数】 **【返回值】 *****************************************************************/ bool CEslGateway::execute( esl_handle_t* pHandle, LPCTSTR App, LPCTSTR Param ) { if(pHandle == NULL) return false; ASSERT(App != NULL); if(App==NULL) return false; esl_status_t Status = esl_execute(pHandle, App, Param, NULL); return Status == ESL_SUCCESS; } bool CEslGateway::Execte2(LPCTSTR App, LPCTSTR Param,LPCTSTR ChanId) { ASSERT(App != NULL); if(App==NULL) return false; esl_status_t Status = esl_execute(&m_EslHdl4Send, App, Param, ChanId); return Status == ESL_SUCCESS; }