#include "StdAfx.h" #include "TapiLine.h" #include "TapiOpBase.h" CTapiLine::CTapiLine(DWORD DevID, HLINE Handle, DWORD ApiVersion, CString ExtID, HLINEAPP LineApp): m_DevID(DevID), m_Handle(Handle), m_ApiVersion(ApiVersion), m_ExtenID(ExtID), m_LineApp(LineApp), m_ActiveCall(NULL), m_PendingCall(NULL), m_HeldCall(NULL), m_DevLinkCallId(CONST_DEV_LINK_CALL_NULL), m_DevLinkHeldId(CONST_DEV_LINK_CALL_NULL), m_IsListener(false), m_LineStatus(INNER_STATE_FREE), m_pCurrTapiOp(NULL), m_InitTime(time(0)) { // 事件过滤 HRESULT hRet = ::lineSetStatusMessages(m_Handle, LINE_DEV_STATE_ALL, LINE_ADDRESS_STATE_ALL); ASSERT(hRet == 0); } CTapiLine::~CTapiLine(void) { } /***************************************************************** **【函数名称】 __onReply **【函数功能】 线路操作异步返回事件响应 **【参数】 **【返回值】 ****************************************************************/ void CTapiLine::__onReply( LONG RequestID, HRESULT Result ) { CSingleLock locker(&m_LockSection, TRUE); if(m_pCurrTapiOp != NULL) m_pCurrTapiOp->onReply(this, RequestID, Result); } /***************************************************************** **【函数名称】 __onNewCall **【函数功能】 新呼叫生成事件响应 **【参数】 **【返回值】 ****************************************************************/ void CTapiLine::__onNewCall( DWORD AddressID, HCALL CallId, DWORD CallPrivilege ) { } /***************************************************************** **【函数名称】 __onCallState **【函数功能】 呼叫状态变化事件响应 **【参数】 **【返回值】 ****************************************************************/ void CTapiLine::__onCallState( HCALL CallId, DWORD CallState, DWORD CallStateDetail, DWORD CallPrivilege ) { // 更新相关呼叫句柄 __updateHCall(CallId, CallState, CallStateDetail); // 线路初始化时提取设备的初始状态 if((time(0) - m_InitTime) < CONST_LINE_INIT_TIME_LIMIT) // 3秒内认为初始化未结束 { _procLineInitStatus(CallId, CallState, CallStateDetail, CallPrivilege); } // end if // 通知关联操作 CSingleLock locker(&m_LockSection, TRUE); if(m_pCurrTapiOp != NULL) m_pCurrTapiOp->onCallState(this, CallId, CallState, CallStateDetail); } /***************************************************************** **【函数名称】 __onCallInfo **【函数功能】 呼叫信息变化事件响应 **【参数】 **【返回值】 ****************************************************************/ void CTapiLine::__onCallInfo( HCALL CallId, DWORD CallInfoState ) { } /***************************************************************** **【函数名称】 loopLineGetCallInfo **【函数功能】 获取呼叫信息 **【参数】 CallId 呼叫句柄 **【返回值】 操作结果 pCallInfo 呼叫信息 ****************************************************************/ HRESULT CTapiLine::__loopLineGetCallInfo( HCALL CallId, LINECALLINFO* &pCallInfo ) { HRESULT hRet = S_OK; size_t nCurrentSize = 512; // Starting value - usually big enough for (;;) { // Allocate some memory for the call pCallInfo = (LINECALLINFO *) new BYTE[nCurrentSize]; ZeroMemory(&pCallInfo[0], nCurrentSize); pCallInfo->dwTotalSize = nCurrentSize; // Ask TAPI for some information hRet = ::lineGetCallInfo(CallId, pCallInfo); // Cope with variable length structures if (hRet == LINEERR_STRUCTURETOOSMALL) { if (pCallInfo->dwNeededSize <= 0) break; nCurrentSize = pCallInfo->dwNeededSize; delete [] pCallInfo; pCallInfo = NULL; } else { break; // 获取成功,退出循环 } } // end for return hRet; } /***************************************************************** **【函数名称】 __loopLineGetCallStatus **【函数功能】 获取呼叫状态 **【参数】 CallId 呼叫句柄 **【返回值】 操作结果 pCallStatus 呼叫状态 ****************************************************************/ HRESULT CTapiLine::__loopLineGetCallStatus( HCALL CallId, DWORD& CallStatus ) { HRESULT hRet = S_OK; size_t nCurrentSize = 512; // Starting value - usually big enough for (;;) { // Allocate some memory for the call LINECALLSTATUS * pCallStatus = (LINECALLSTATUS *) new BYTE[nCurrentSize]; ZeroMemory(&pCallStatus[0], nCurrentSize); pCallStatus->dwTotalSize = nCurrentSize; // Ask TAPI for some information hRet = ::lineGetCallStatus(CallId, pCallStatus); // Cope with variable length structures if (hRet == LINEERR_STRUCTURETOOSMALL) { if (pCallStatus->dwNeededSize <= 0) break; nCurrentSize = pCallStatus->dwNeededSize; delete [] pCallStatus; pCallStatus = NULL; } else { CallStatus = pCallStatus->dwCallState; delete [] pCallStatus; pCallStatus = NULL; break; // 获取成功,退出循环 } } // end for return hRet; } /***************************************************************** **【函数名称】 __updateHCall **【函数功能】 更新相关呼叫句柄(__onCallState子函数) **【参数】 **【返回值】 ****************************************************************/ void CTapiLine::__updateHCall( HCALL CallId, DWORD CallState, DWORD CallStateDetail ) { // 根据呼叫状态转换相关呼叫句柄 if(CallState & LINECALLSTATE_IDLE) // 呼叫释放 { HRESULT nRet = ::lineDeallocateCall(CallId); if(nRet == S_OK) { if(CallId == m_PendingCall) m_PendingCall = NULL; if(CallId == m_ActiveCall) m_ActiveCall = NULL; } // end if(nRet) } else if(CallState & LINECALLSTATE_DISCONNECTED) // 呼叫断开 { ::lineDrop(CallId, NULL, 0); } else if(CallState & LINECALLSTATE_CONNECTED) // 呼叫建立 { m_ActiveCall = CallId; if(CallId == m_PendingCall) m_PendingCall = NULL; } else if(CallState & (LINECALLSTATE_ONHOLDPENDTRANSFER | // 转移或会议或保持的中间过程 LINECALLSTATE_ONHOLD | LINECALLSTATE_ONHOLDPENDCONF)) { if(CallId == m_ActiveCall) m_ActiveCall = m_PendingCall; m_PendingCall = CallId; } else if(CallState & (LINECALLSTATE_OFFERING | // 其它状态 LINECALLSTATE_DIALING | LINECALLSTATE_PROCEEDING | LINECALLSTATE_DIALTONE | LINECALLSTATE_RINGBACK | LINECALLSTATE_CONFERENCED)) { m_ActiveCall = CallId; if(CallId == m_PendingCall) m_PendingCall = NULL; } // end if(CallState) } /***************************************************************** **【函数名称】 _mapTapiCallState **【函数功能】 将呼叫的设备状态定义转为CTI系统定义 **【参数】 CallState 呼叫的设备状态 **【返回值】 ****************************************************************/ INNER_STATE CTapiLine::_mapTapiCallState( DWORD CallState ) { INNER_STATE nTmpState = INNER_STATE_FREE; if(CallState & LINECALLSTATE_IDLE || CallState & LINECALLSTATE_DISCONNECTED) // 线路空闲 { nTmpState = INNER_STATE_FREE; } else if(CallState & LINECALLSTATE_DIALTONE) // 摘机等待拨号 { nTmpState = INNER_STATE_INIT; } else if(CallState & LINECALLSTATE_DIALING) // 正在拨号 { nTmpState = INNER_STATE_DIALING; } else if(CallState & LINECALLSTATE_RINGBACK) // 对端振铃,等待接听 { nTmpState = INNER_STATE_RING_BACK; } else if(CallState & LINECALLSTATE_OFFERING) // 来电振铃 { nTmpState = INNER_STATE_ALERTING; } else if(CallState & LINECALLSTATE_CONNECTED || CallState & LINECALLSTATE_CONFERENCED) // 通话中 { nTmpState = INNER_STATE_TALKING; } return nTmpState; } /***************************************************************** **【函数名称】 getCallStatus **【函数功能】 **【参数】 CallId 要读取信息的呼叫句柄 **【返回值】 呼叫的物理状态 ****************************************************************/ DWORD CTapiLine::getCallStatus( const HCALL CallId ) { DWORD CallStatus = 0; __loopLineGetCallStatus(CallId, CallStatus); return CallStatus; } /***************************************************************** **【函数名称】 isAssoDevLinkCallId **【函数功能】 DevLinkCallId是否与当前线路有关联 **【参数】 **【返回值】 ****************************************************************/ bool CTapiLine::isAssoDevLinkCallId( int DevLinkCallId ) { if(DevLinkCallId == m_DevLinkCallId || DevLinkCallId == m_DevLinkHeldId) return true; else return false; } /***************************************************************** **【函数名称】 onTapiEvent **【函数功能】 Tapi事件入口主函数 **【参数】 **【返回值】 ****************************************************************/ void CTapiLine::onTapiEvent( DWORD nDevice, DWORD nMsg, DWORD Param1, DWORD Param2, DWORD Param3 ) { switch(nMsg) { case LINE_REPLY: // Reply to an asynchronous TAPI function __onReply(Param1, Param2); break; case LINE_CLOSE: // A line has closed break; case LINE_ADDRESSSTATE: // The address state has changed break; case LINE_CALLINFO: // The call info has changed __onCallInfo((HCALL)nDevice, Param1); break; case LINE_CALLSTATE: // The call state has changed __onCallState((HCALL)nDevice, Param1, Param2, Param3); break; case LINE_LINEDEVSTATE: // The device state has changed break; case LINE_APPNEWCALL: // There is a new incoming call __onNewCall(Param1, (HCALL)Param2, Param3); break; case LINE_DEVSPECIFIC: // The device specific data has changed break; case LINE_DEVSPECIFICFEATURE: // The device specific features have changed break; case LINE_GATHERDIGITS: // A digit has been received break; case LINE_GENERATE: // A tone has been generated break; case LINE_MONITORDIGITS: // A digit has been received break; case LINE_MONITORMEDIA: break; case LINE_MONITORTONE: // A tone has been detected break; case LINE_REQUEST: break; } // end switch } /***************************************************************** **【函数名称】 onDevLinkEventS **【函数功能】 DEV Link S 事件响应 **【参数】 **【返回值】 ****************************************************************/ void CTapiLine::onDevLinkEventS( DevLinkInfoS* pInfoS ) { CSingleLock locker(&m_LockSection, TRUE); _procDevLinkEventS(pInfoS); } /***************************************************************** **【函数名称】 onDevLinkEventA **【函数功能】 DEV Link A 事件响应 **【参数】 **【返回值】 ****************************************************************/ void CTapiLine::onDevLinkEventA( int DevLinkCallId ) { CSingleLock locker(&m_LockSection, TRUE); if(m_pCurrTapiOp != NULL) m_pCurrTapiOp->onDevLinkEventA(this, DevLinkCallId); } /***************************************************************** **【函数名称】 onDevLinkEventD **【函数功能】 DEV Link D 事件响应 **【参数】 **【返回值】 ****************************************************************/ void CTapiLine::onDevLinkEventD( int DevLinkCallId ) { CSingleLock locker(&m_LockSection, TRUE); _procDevLinkEventD(DevLinkCallId); } /***************************************************************** **【函数名称】 LineReopen **【函数功能】 线路重新打开 **【参数】 **【返回值】 操作是否成功 ****************************************************************/ bool CTapiLine::lineReopen( void ) { ::lineClose(m_Handle); ::lineOpen(m_LineApp, m_DevID, &m_Handle, m_ApiVersion, 0, m_DevID, LINECALLPRIVILEGE_OWNER, LINEMEDIAMODE_INTERACTIVEVOICE, 0); LINEDEVCAPS* pDevCaps = (LINEDEVCAPS *) new BYTE[512]; ZeroMemory(&pDevCaps[0], 512); pDevCaps->dwTotalSize = 512; ::lineGetDevCaps(m_LineApp, m_DevID, m_ApiVersion, 0, pDevCaps); ::lineSetStatusMessages(m_Handle, LINE_DEV_STATE_ALL, LINE_ADDRESS_STATE_ALL); delete[] pDevCaps; // 释放内存 return true; } /***************************************************************** **【函数名称】 LineMakeCall **【函数功能】 呼出 **【参数】 pszDest 被叫号码 **【返回值】 bool 操作是否成功 hWaitingCall 等待后续处理的呼叫句柄 ****************************************************************/ bool CTapiLine::lineMakeCall( LPCTSTR pszDest, HCALL& WaitingCall ) { size_t cbDestAddress = strlen(pszDest) + 1; size_t cbCallParams = sizeof(LINECALLPARAMS) + cbDestAddress; LINECALLPARAMS* pCallParams = (LINECALLPARAMS*)(new BYTE[cbCallParams]); // Setup the parameters if (pCallParams) { ZeroMemory(pCallParams, cbCallParams); pCallParams->dwTotalSize = cbCallParams; pCallParams->dwBearerMode = LINEBEARERMODE_VOICE; pCallParams->dwMinRate = 0; // Use device default pCallParams->dwMaxRate = 0; // Use device default pCallParams->dwMediaMode = LINEMEDIAMODE_INTERACTIVEVOICE; pCallParams->dwCallParamFlags = 0; // No flags pCallParams->dwAddressMode = LINEADDRESSMODE_ADDRESSID; pCallParams->dwAddressID = 0; // Use the main (and only) line address // Variable length strings pCallParams->dwDisplayableAddressSize = cbDestAddress; pCallParams->dwDisplayableAddressOffset = sizeof(LINECALLPARAMS); char* pszDisplayableAddress = (char*)((BYTE*)pCallParams + sizeof(LINECALLPARAMS)); lstrcpy(pszDisplayableAddress, pszDest); } // Ask TAPI to make the call HRESULT hRet = ::lineMakeCall(m_Handle, &WaitingCall, pszDest, 0, pCallParams); delete[] pCallParams; return hRet > 0 ? true : false; } /***************************************************************** **【函数名称】 lineAnswerCall **【函数功能】 应答呼叫 **【参数】 要应答的呼叫句柄 **【返回值】 ****************************************************************/ bool CTapiLine::lineAnswerCall( HCALL CallId ) { HRESULT hRet = ::lineAnswer(CallId, NULL, 0); return hRet > 0; } /***************************************************************** **【函数名称】 lineDropCall **【函数功能】 终止呼叫 **【参数】 要挂断的呼叫句柄 **【返回值】 ****************************************************************/ bool CTapiLine::lineDropCall( HCALL CallId ) { HRESULT hRet = ::lineDrop(CallId, NULL, 0); return hRet > 0; } /***************************************************************** **【函数名称】 lineHold **【函数功能】 呼叫保持 **【参数】 要保持的呼叫句柄 **【返回值】 ****************************************************************/ bool CTapiLine::lineHold( HCALL CallId ) { HRESULT hRet = ::lineHold(CallId); return hRet > 0; } /***************************************************************** **【函数名称】 lineTakeBack **【函数功能】 呼叫接回 **【参数】 要接回的呼叫句柄 **【返回值】 ****************************************************************/ bool CTapiLine::lineTakeBack( HCALL CallId ) { HRESULT hRet = ::lineUnhold(CallId); return hRet > 0; } /***************************************************************** **【函数名称】 lineListen **【函数功能】 监听 **【参数】 监听的目的地址 **【返回值】 ****************************************************************/ bool CTapiLine::lineListen( LPCTSTR pszDest ) { TCHAR buffer[50]; DWORD len = 0; buffer[0] = 9; buffer[1] = 100; // Listen lstrcpy(&(buffer[2]),pszDest); buffer[2 + _tcslen(pszDest)] = 0; // NULL terminate len = 3 + _tcslen(pszDest); HRESULT hRet = ::lineDevSpecific(m_Handle, 0, NULL, buffer, len); return hRet > 0; } /***************************************************************** **【函数名称】 lineDial **【函数功能】 在指定呼叫上开始呼叫操作 **【参数】 CallId 执行Dial操作的呼叫句柄 pszDest 被叫号码 **【返回值】 ****************************************************************/ bool CTapiLine::lineDial( HCALL CallId, LPCTSTR pszDest ) { HRESULT hRet = ::lineDial(CallId, pszDest, 0); return hRet > 0; } /***************************************************************** **【函数名称】 lineRedirectCall **【函数功能】 重定向呼叫 **【参数】 pszDest 重定向的号码 **【返回值】 ****************************************************************/ bool CTapiLine::lineRedirectCall( HCALL CallId, LPCTSTR pszDest ) { HRESULT hRet = ::lineRedirect(CallId, pszDest, 0); return hRet > 0; } /***************************************************************** **【函数名称】 lineInsert **【函数功能】 强插 **【参数】 强插的目的地址 **【返回值】 ****************************************************************/ bool CTapiLine::lineInsert( LPCTSTR pszDest ) { TCHAR buffer[50]; DWORD len = 0; buffer[0] = 9; buffer[1] = 83; // Intrude lstrcpy(&(buffer[2]),pszDest); buffer[2 + _tcslen(pszDest)] = 0; // NULL terminate len = 3 + _tcslen(pszDest); HRESULT hRet = ::lineDevSpecific(m_Handle, 0, NULL, buffer, len); return hRet > 0; } /***************************************************************** **【函数名称】 linePickupCall **【函数功能】 代答 **【参数】 pszDest 申请代接的号码 **【返回值】 ****************************************************************/ bool CTapiLine::linePickupCall( LPHCALL lphWaitingCall, LPCTSTR pszDest ) { HRESULT hRet = ::linePickup(m_Handle, 0, lphWaitingCall, pszDest, NULL); return hRet > 0; } /***************************************************************** **【函数名称】 lineSetupTransfer **【函数功能】 启动转移 **【参数】 **【返回值】 ****************************************************************/ bool CTapiLine::lineSetupTransfer( LPHCALL lphTransferCall ) { HRESULT hRet = ::lineSetupTransfer(m_ActiveCall, lphTransferCall, 0); return hRet > 0; } /***************************************************************** **【函数名称】 lineCompleteTransfer **【函数功能】 完成转移 **【参数】 HeldCall 被保持的呼叫 TransferCall 新建立的呼叫 **【返回值】 ****************************************************************/ bool CTapiLine::lineCompleteTransfer( HCALL HeldCall, HCALL TransferCall ) { HRESULT hRet = ::lineCompleteTransfer(HeldCall, TransferCall, NULL, LINETRANSFERMODE_TRANSFER); return hRet > 0; } /***************************************************************** **【函数名称】 lineCompleteConference **【函数功能】 完成三方会议 **【参数】 hHeldCall 被保持的呼叫 hTransferCall 新建立的呼叫 **【返回值】 ****************************************************************/ bool CTapiLine::lineCompleteConference( HCALL HeldCall, HCALL ConferenceCall ) { HCALL hNewConfCall; HRESULT hRet = ::lineCompleteTransfer(HeldCall, ConferenceCall, &hNewConfCall, LINETRANSFERMODE_CONFERENCE); return hRet > 0; } /***************************************************************** **【函数名称】 lineGenerateDigit **【函数功能】 生成按键 **【参数】 CallId 生成按键的呼叫句柄 pszDigits 生成的按键 **【返回值】 ****************************************************************/ bool CTapiLine::lineGenerateDigit( HCALL CallId, LPCTSTR pszDigits ) { HRESULT hRet = ::lineGenerateDigits(CallId, LINEDIGITMODE_DTMF, pszDigits, 0); return hRet > 0; } /***************************************************************** **【函数名称】 lineReset **【函数功能】 线路重置 **【参数】 **【返回值】 ****************************************************************/ bool CTapiLine::lineReset( void ) { m_DevLinkHeldId = CONST_DEV_LINK_CALL_NULL; // 关闭保持状态 if(m_ActiveCall != NULL) lineDropCall(m_ActiveCall); if(m_HeldCall != NULL) lineDropCall(m_HeldCall); if(m_PendingCall != NULL) lineDropCall(m_PendingCall); return true; } /***************************************************************** **【函数名称】 linePark **【函数功能】 呼叫停靠 **【参数】 CallId 正在通话的呼叫句柄 pszAddress 停靠地址 **【返回值】 ****************************************************************/ bool CTapiLine::linePark( HCALL CallId, LPCTSTR pszAddress ) { HRESULT hRet = 0; if(pszAddress != NULL) { hRet = ::linePark(CallId, LINEPARKMODE_DIRECTED, pszAddress, NULL); } else { DWORD size = 512; VARSTRING* pAddress = (VARSTRING*) new char[size]; // This should be big enough ZeroMemory(&pAddress[0], size); pAddress->dwTotalSize = size; pAddress->dwStringFormat = STRINGFORMAT_ASCII; hRet = ::linePark(CallId, LINEPARKMODE_NONDIRECTED, NULL, pAddress); delete []pAddress; } // end if return hRet > 0; } /***************************************************************** **【函数名称】 lineUnPark **【函数功能】 停靠接回 **【参数】 pszAddress 停靠地址 **【返回值】 ****************************************************************/ bool CTapiLine::lineUnPark( HCALL& CallId, LPCTSTR pszAddress ) { HRESULT hRet = ::lineUnpark(m_Handle, 0, &CallId, pszAddress); return hRet > 0; }