www.pudn.com > TAPISample.rar > TapiLine.cpp
// TapiLine.cpp: implementation of the CTapiLine class.
// Author: T.Yogaramanan
// Include this header if you use any part of the code from this file
/////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "TAPISample.h"
#include "TapiLine.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CTapiLine::CTapiLine()
{
m_hEventFromThread = NULL;
m_hLineMsgThread = NULL; // TAPI Event monitoring thread.
m_bStopLineEventThread = true;
m_lEventThreadResult = 0;
m_dwLineMsg= 0;
m_nDevID = 0;
m_hLineApp = NULL;
m_hLine = NULL;
m_hCall = NULL;
m_bConnected = false;
}
CTapiLine::~CTapiLine()
{
Close();
}
// if nMode = 0 then it is data/fax calls
// nMode = 1 then it is data/fax/voice calls
int CTapiLine::Open(int nMode)
{
LINEINITIALIZEEXPARAMS stInitParams;
LINEDEVCAPS *lpDevCaps =NULL;
LONG lRet;
DWORD dwMediaMode;
DWORD dwNumDevs =0;
DWORD dwTAPIVer =TAPI_CURRENT_VERSION;;
DWORD dwTmpVer =0;
LINEEXTENSIONID stExtID;
if(!nMode)
dwMediaMode = LINEMEDIAMODE_DATAMODEM; // data/fax this should be
else
dwMediaMode = LINEMEDIAMODE_AUTOMATEDVOICE;// for voice this should be
memset(&stInitParams, 0, sizeof(LINEINITIALIZEEXPARAMS));
// set the options...
stInitParams.dwTotalSize = sizeof(LINEINITIALIZEEXPARAMS);
stInitParams.dwOptions = LINEINITIALIZEEXOPTION_USEEVENT;
// Initialize TAPI.
lRet = lineInitializeEx(&m_hLineApp, NULL, NULL, "CallAnswer", &dwNumDevs, &dwTAPIVer, &stInitParams);
if(lRet) //error
return lRet;
// Got the event handle...
m_hLineEvent = stInitParams.Handles.hEvent;
m_nDevID = -1;
// go through the device list and select the appropriate device to transfer voice
for(int i=0; idwTotalSize = sizeof(LINEDEVCAPS)+1024;
lRet = lineGetDevCaps(m_hLineApp, i, dwTmpVer, 0, lpDevCaps);
if(lRet) //error
{
free(lpDevCaps);
lpDevCaps=NULL;
continue;
}
char *szText = ((char*)lpDevCaps) + lpDevCaps->dwLineNameOffset;// FOR DEBUGGING
// for more refer LINEMEDIAMODE_ Constants in MSDN
if(lpDevCaps->dwMediaModes & dwMediaMode)
{
free(lpDevCaps);
m_nDevID = i;
break;
}
free(lpDevCaps);
}
if(m_nDevID < 0)
return LINEERR_BADDEVICEID; // no device available
// Open the line...
lRet = lineOpen(m_hLineApp, m_nDevID, &m_hLine, dwTAPIVer, 0x00000000, 1,LINECALLPRIVILEGE_OWNER,dwMediaMode,NULL);
if(lRet)
{
lineShutdown(m_hLineApp);
return lRet;
}
// We want to be notified for everything
lRet = lineSetStatusMessages(m_hLine, 0x1ffffff, 0);
if(lRet)
{
lineShutdown(m_hLineApp);
return lRet;
}
m_bStopLineEventThread = false;
m_hLineMsgThread = CreateThread(NULL,NULL,LineEventThread,this,NULL,0);
/// 在这个事件上建立信号
m_hEventFromThread = CreateEvent(NULL,0,0,NULL);
return 0;
}
int CTapiLine::Close()
{
LINECALLSTATUS stLineStatus;
LONG lRet;
if(m_hCall) // Call might be in progress...
{
memset(&stLineStatus, 0, sizeof(LINECALLSTATUS));
lRet = lineGetCallStatus(m_hCall, &stLineStatus);
// Technically, lineGetCallStatus returns more info than
// there is in the structure. Since we don't care about it,
// We just go on our merry way...
if(!lRet) // If it didn't fail, there's at least a call that needs to be droped.
lineDrop(m_hCall, NULL, 0);
}
m_hCall = NULL;
if(m_hLine)
lineClose(m_hLine);
m_hLine = NULL;
if(m_hLineMsgThread)
{
m_bStopLineEventThread = true; // stop the event waiting thread
WaitForSingleObject(m_hLineMsgThread, INFINITE); // Wait for it to comit suicide..
CloseHandle(m_hLineMsgThread);
CloseHandle(m_hEventFromThread);
}
if(m_hLineApp)
lineShutdown(m_hLineApp);
m_hLineApp = NULL;
m_hLineMsgThread = NULL;
m_hEventFromThread = NULL;
m_hLineMsgThread = NULL;
m_lEventThreadResult = 0;
m_dwLineMsg= 0;
m_nDevID = -1;
m_bConnected= false;
return 0;
}
int CTapiLine::GetIncomingCall()
{
long lRet;
// set the ring b4 receiving the call
lRet = lineSetNumRings(m_hLine,0,5);
if(lRet)
return lRet;
// Now we wait for notification.
switch(WaitForSingleObject(m_hEventFromThread, INFINITE))
{
case WAIT_OBJECT_0:
if(m_dwLineMsg == LINECALLSTATE_OFFERING)
{
lRet = lineAnswer(m_hCall, NULL, 0);
lRet = (lRet>0)?0:lRet;
if(lRet)
Close();
return lRet;
}
break;
case WAIT_TIMEOUT:
return ERROR_TIMEOUT;
};
return 0xffffffff; // unknown error
}
int CTapiLine::PickupIncomingCall()
{
long lRet;
lRet = linePickup(m_hLine,0,&m_hCall,NULL,NULL);
return (lRet>=0)?0:lRet;
}
int CTapiLine::MakeOutgoingCall(const char *szAddress)
{
long lRet;
LPLINECALLPARAMS lpCallParams;
lpCallParams = (LPLINECALLPARAMS)malloc(sizeof(LINECALLPARAMS)+1024);
memset(lpCallParams,0,sizeof(LINECALLPARAMS)+1024);
lpCallParams->dwTotalSize = sizeof(LINECALLPARAMS)+1024;
// This is where we configure the line for DATAMODEM usage.
lpCallParams->dwBearerMode = LINEBEARERMODE_VOICE;
lpCallParams->dwMediaMode = LINEMEDIAMODE_DATAMODEM;
// This specifies that we want to use only IDLE calls and
// don't want to cut into a call that might not be IDLE (ie, in use).
lpCallParams->dwCallParamFlags = LINECALLPARAMFLAGS_IDLE;
// if there are multiple addresses on line, use first anyway.
// It will take a more complex application than a simple tty app
// to use multiple addresses on a line anyway.
lpCallParams->dwAddressMode = LINEADDRESSMODE_ADDRESSID;
lpCallParams->dwAddressID = 0;
// Address we are dialing.
lpCallParams->dwDisplayableAddressOffset = sizeof(LINECALLPARAMS);
lpCallParams->dwDisplayableAddressSize = strlen(szAddress);
strcpy((LPSTR)lpCallParams+sizeof(LINECALLPARAMS), szAddress);
lRet = lineMakeCall(m_hLine, &m_hCall, szAddress, 0, lpCallParams);
return (lRet>=0)?0:lRet;
}
//Author: Ramanan.T
HANDLE CTapiLine::GetHandle(const char *szClassType, long *lError)
{
if(!m_bConnected)
{
*lError = ERROR_DEVICE_NOT_CONNECTED;
return NULL;
}
VARSTRING *pvarStrDevID = (VARSTRING *)malloc(sizeof(VARSTRING)+255);
memset(pvarStrDevID,0,sizeof(VARSTRING)+255);
pvarStrDevID->dwTotalSize = sizeof(VARSTRING)+255;
long lRet = lineGetID(m_hLine,0,m_hCall,LINECALLSELECT_LINE,pvarStrDevID,szClassType);
if(lRet)
{
*lError = lRet;
return NULL;
}
*lError = 0;
return *((LPHANDLE)((char *)pvarStrDevID + pvarStrDevID->dwStringOffset));
}
//Author: Ramanan.T
/// 这里有事件处理函数
DWORD WINAPI CTapiLine::LineEventThread(LPVOID lpVoid)
{
CTapiLine *pcTapiLine = (CTapiLine *)lpVoid;
long lRet;
LINEMESSAGE stLineMsg;
LINECALLINFO *lpCallInfo;
while(!pcTapiLine->m_bStopLineEventThread)
{
// Get a TAPI event if available, wait for 10ms just enough to give up quontum
switch(WaitForSingleObject(pcTapiLine->m_hLineEvent, 10))
{
case WAIT_OBJECT_0:
//TAPI's got something
if ((lRet = lineGetMessage(pcTapiLine->m_hLineApp, &stLineMsg, 0)) != 0)
{
pcTapiLine->m_lEventThreadResult = lRet;
return lRet;
}
// Process the retruned msg
switch (stLineMsg.dwMessageID)
{
case LINE_REPLY: // Sent after lineMakeCall or lineDrop
pcTapiLine->m_lEventThreadResult = (LONG)stLineMsg.dwParam2;
break;
case LINE_CALLSTATE: // Sent after change of call state
switch (stLineMsg.dwParam1)
{
case LINECALLSTATE_OFFERING: //Incoming call is offering.
// Get the call handle
pcTapiLine->m_hCall = (HCALL)stLineMsg.hDevice;
/// 设置消息
pcTapiLine->m_dwLineMsg = LINECALLSTATE_OFFERING;
/// 设置事件
SetEvent(pcTapiLine->m_hEventFromThread);
break;
case LINECALLSTATE_IDLE:
lineDrop(pcTapiLine->m_hCall, NULL, 0);
pcTapiLine->m_hCall = NULL;
break;
case LINECALLSTATE_CONNECTED:
if(stLineMsg.dwCallbackInstance == 1)
{
pcTapiLine->m_dwLineMsg = LINECALLSTATE_CONNECTED;
SetEvent(pcTapiLine->m_hEventFromThread);
pcTapiLine->m_bConnected = true;
}
break;
case LINECALLSTATE_DISCONNECTED:
switch (stLineMsg.dwParam2)
{// currently these r not handled separately
case LINEDISCONNECTMODE_NORMAL:
case LINEDISCONNECTMODE_UNKNOWN:
case LINEDISCONNECTMODE_REJECT:
case LINEDISCONNECTMODE_PICKUP:
case LINEDISCONNECTMODE_FORWARDED:
case LINEDISCONNECTMODE_BUSY:
case LINEDISCONNECTMODE_NOANSWER:
case LINEDISCONNECTMODE_BADADDRESS:
case LINEDISCONNECTMODE_UNREACHABLE:
case LINEDISCONNECTMODE_CONGESTION:
case LINEDISCONNECTMODE_INCOMPATIBLE:
case LINEDISCONNECTMODE_UNAVAIL:
case LINEDISCONNECTMODE_NODIALTONE:
default:
// Got disconnected, so drop the call
lineDrop((HCALL)stLineMsg.hDevice, NULL, 0);
pcTapiLine->m_bConnected = false;
break;
}
break;
default:
break;
}
break;
case LINE_CALLINFO: // Call Info is available
if(stLineMsg.dwParam1 == LINECALLINFOSTATE_CALLID)
{ //Caller ID became available.
lpCallInfo = (LINECALLINFO *)malloc(sizeof(LINECALLINFO)+1000);
memset(lpCallInfo, 0, sizeof(LINECALLINFO)+1024);
lpCallInfo->dwTotalSize = sizeof(LINECALLINFO)+1024;
lineGetCallInfo(pcTapiLine->m_hCall, lpCallInfo);
if (lpCallInfo->dwTotalSize < lpCallInfo->dwNeededSize)
{
lpCallInfo = (LINECALLINFO *)realloc(lpCallInfo, lpCallInfo->dwNeededSize);
lineGetCallInfo(pcTapiLine->m_hCall, lpCallInfo);
}
}
break;
default:
break;
};
break;
case WAIT_TIMEOUT:
break;;
default:
continue;
};
}
return 0;
}
//Author: Ramanan.T
void CTapiLine::GetErrorString(int nError, char *&szErrText)
{
szErrText = (char*)malloc(255);
switch(nError)
{
case LINEERR_ALLOCATED:
strcpy(szErrText,"LINEERR_ALLOCATED");
break;
case LINEERR_BADDEVICEID:
strcpy(szErrText,"LINEERR_BADDEVICEID");
break;
case LINEERR_BEARERMODEUNAVAIL:
strcpy(szErrText,"LINEERR_BEARERMODEUNAVAIL");
break;
case LINEERR_CALLUNAVAIL:
strcpy(szErrText,"LINEERR_CALLUNAVAIL");
break;
case LINEERR_COMPLETIONOVERRUN:
strcpy(szErrText,"LINEERR_COMPLETIONOVERRUN");
break;
case LINEERR_CONFERENCEFULL:
strcpy(szErrText,"LINEERR_CONFERENCEFULL");
break;
case LINEERR_DIALBILLING:
strcpy(szErrText,"LINEERR_DIALBILLING");
break;
case LINEERR_DIALDIALTONE:
strcpy(szErrText,"LINEERR_DIALDIALTONE");
break;
case LINEERR_DIALPROMPT:
strcpy(szErrText,"LINEERR_DIALPROMPT");
break;
case LINEERR_DIALQUIET:
strcpy(szErrText,"LINEERR_DIALQUIET");
break;
case LINEERR_INCOMPATIBLEAPIVERSION:
strcpy(szErrText,"LINEERR_INCOMPATIBLEAPIVERSION");
break;
case LINEERR_INCOMPATIBLEEXTVERSION:
strcpy(szErrText,"LINEERR_INCOMPATIBLEEXTVERSION");
break;
case LINEERR_INIFILECORRUPT:
strcpy(szErrText,"LINEERR_INIFILECORRUPT");
break;
case LINEERR_INUSE:
strcpy(szErrText,"LINEERR_INUSE");
break;
case LINEERR_INVALADDRESS:
strcpy(szErrText,"LINEERR_INVALADDRESS");
break;
case LINEERR_INVALADDRESSID:
strcpy(szErrText,"LINEERR_INVALADDRESSID");
break;
case LINEERR_INVALADDRESSMODE:
strcpy(szErrText,"LINEERR_INVALADDRESSMODE");
break;
case LINEERR_INVALADDRESSSTATE:
strcpy(szErrText,"LINEERR_INVALADDRESSSTATE");
break;
case LINEERR_INVALAPPHANDLE:
strcpy(szErrText,"LINEERR_INVALAPPHANDLE");
break;
case LINEERR_INVALAPPNAME:
strcpy(szErrText,"LINEERR_INVALAPPNAME");
break;
case LINEERR_INVALBEARERMODE:
strcpy(szErrText,"LINEERR_INVALBEARERMODE");
break;
case LINEERR_INVALCALLCOMPLMODE:
strcpy(szErrText,"LINEERR_INVALCALLCOMPLMODE");
break;
case LINEERR_INVALCALLHANDLE:
strcpy(szErrText,"LINEERR_INVALCALLHANDLE");
break;
case LINEERR_INVALCALLPARAMS:
strcpy(szErrText,"LINEERR_INVALCALLPARAMS");
break;
case LINEERR_INVALCALLPRIVILEGE:
strcpy(szErrText,"LINEERR_INVALCALLPRIVILEGE");
break;
case LINEERR_INVALCALLSELECT:
strcpy(szErrText,"LINEERR_INVALCALLSELECT");
break;
case LINEERR_INVALCALLSTATE:
strcpy(szErrText,"LINEERR_INVALCALLSTATE");
break;
case LINEERR_INVALCALLSTATELIST:
strcpy(szErrText,"LINEERR_INVALCALLSTATELIST");
break;
case LINEERR_INVALCARD:
strcpy(szErrText,"LINEERR_INVALCARD");
break;
case LINEERR_INVALCOMPLETIONID:
strcpy(szErrText,"LINEERR_INVALCOMPLETIONID");
break;
case LINEERR_INVALCONFCALLHANDLE:
strcpy(szErrText,"LINEERR_INVALCONFCALLHANDLE");
break;
case LINEERR_INVALCONSULTCALLHANDLE:
strcpy(szErrText,"LINEERR_INVALCONSULTCALLHANDLE");
break;
case LINEERR_INVALCOUNTRYCODE:
strcpy(szErrText,"LINEERR_INVALCOUNTRYCODE");
break;
case LINEERR_INVALDEVICECLASS:
strcpy(szErrText,"LINEERR_INVALDEVICECLASS");
break;
case LINEERR_INVALDEVICEHANDLE:
strcpy(szErrText,"LINEERR_INVALDEVICEHANDLE");
break;
case LINEERR_INVALDIALPARAMS:
strcpy(szErrText,"LINEERR_INVALDIALPARAMS");
break;
case LINEERR_INVALDIGITLIST:
strcpy(szErrText,"LINEERR_INVALDIGITLIST");
break;
case LINEERR_INVALDIGITMODE:
strcpy(szErrText,"LINEERR_INVALDIGITMODE");
break;
case LINEERR_INVALDIGITS:
strcpy(szErrText,"LINEERR_INVALDIGITS");
break;
case LINEERR_INVALEXTVERSION:
strcpy(szErrText,"LINEERR_INVALEXTVERSION");
break;
case LINEERR_INVALGROUPID:
strcpy(szErrText,"LINEERR_INVALGROUPID");
break;
case LINEERR_INVALLINEHANDLE:
strcpy(szErrText,"LINEERR_INVALLINEHANDLE");
break;
case LINEERR_INVALLINESTATE:
strcpy(szErrText,"LINEERR_INVALLINESTATE");
break;
case LINEERR_INVALLOCATION:
strcpy(szErrText,"LINEERR_INVALLOCATION");
break;
case LINEERR_INVALMEDIALIST:
strcpy(szErrText,"LINEERR_INVALMEDIALIST");
break;
case LINEERR_INVALMEDIAMODE:
strcpy(szErrText,"LINEERR_INVALMEDIAMODE");
break;
case LINEERR_INVALMESSAGEID:
strcpy(szErrText,"LINEERR_INVALMESSAGEID");
break;
case LINEERR_INVALPARAM:
strcpy(szErrText,"LINEERR_INVALPARAM");
break;
case LINEERR_INVALPARKID:
strcpy(szErrText,"LINEERR_INVALPARKID");
break;
case LINEERR_INVALPARKMODE:
strcpy(szErrText,"LINEERR_INVALPARKMODE");
break;
case LINEERR_INVALPOINTER:
strcpy(szErrText,"LINEERR_INVALPOINTER");
break;
case LINEERR_INVALPRIVSELECT:
strcpy(szErrText,"LINEERR_INVALPRIVSELECT");
break;
case LINEERR_INVALRATE:
strcpy(szErrText,"LINEERR_INVALRATE");
break;
case LINEERR_INVALREQUESTMODE:
strcpy(szErrText,"LINEERR_INVALREQUESTMODE");
break;
case LINEERR_INVALTERMINALID:
strcpy(szErrText,"LINEERR_INVALTERMINALID");
break;
case LINEERR_INVALTERMINALMODE:
strcpy(szErrText,"LINEERR_INVALTERMINALMODE");
break;
case LINEERR_INVALTIMEOUT:
strcpy(szErrText,"LINEERR_INVALTIMEOUT");
break;
case LINEERR_INVALTONE:
strcpy(szErrText,"LINEERR_INVALTONE");
break;
case LINEERR_INVALTONELIST:
strcpy(szErrText,"LINEERR_INVALTONELIST");
break;
case LINEERR_INVALTONEMODE:
strcpy(szErrText,"LINEERR_INVALTONEMODE");
break;
case LINEERR_INVALTRANSFERMODE:
strcpy(szErrText,"LINEERR_INVALTRANSFERMODE");
break;
case LINEERR_LINEMAPPERFAILED:
strcpy(szErrText,"LINEERR_LINEMAPPERFAILED");
break;
case LINEERR_NOCONFERENCE:
strcpy(szErrText,"LINEERR_NOCONFERENCE");
break;
case LINEERR_NODEVICE:
strcpy(szErrText,"LINEERR_NODEVICE");
break;
case LINEERR_NODRIVER:
strcpy(szErrText,"LINEERR_NODRIVER");
break;
case LINEERR_NOMEM:
strcpy(szErrText,"LINEERR_NOMEM");
break;
case LINEERR_NOREQUEST:
strcpy(szErrText,"LINEERR_NOREQUEST");
break;
case LINEERR_NOTOWNER:
strcpy(szErrText,"LINEERR_NOTOWNER");
break;
case LINEERR_NOTREGISTERED:
strcpy(szErrText,"LINEERR_NOTREGISTERED");
break;
case LINEERR_OPERATIONFAILED:
strcpy(szErrText,"LINEERR_OPERATIONFAILED");
break;
case LINEERR_OPERATIONUNAVAIL:
strcpy(szErrText,"LINEERR_OPERATIONUNAVAIL");
break;
case LINEERR_RATEUNAVAIL:
strcpy(szErrText,"LINEERR_RATEUNAVAIL");
break;
case LINEERR_RESOURCEUNAVAIL:
strcpy(szErrText,"LINEERR_RESOURCEUNAVAIL");
break;
case LINEERR_REQUESTOVERRUN:
strcpy(szErrText,"LINEERR_REQUESTOVERRUN");
break;
case LINEERR_STRUCTURETOOSMALL:
strcpy(szErrText,"LINEERR_STRUCTURETOOSMALL");
break;
case LINEERR_TARGETNOTFOUND:
strcpy(szErrText,"LINEERR_TARGETNOTFOUND");
break;
case LINEERR_TARGETSELF:
strcpy(szErrText,"LINEERR_TARGETSELF");
break;
case LINEERR_UNINITIALIZED:
strcpy(szErrText,"LINEERR_UNINITIALIZED");
break;
case LINEERR_USERUSERINFOTOOBIG:
strcpy(szErrText,"LINEERR_USERUSERINFOTOOBIG");
break;
case LINEERR_REINIT:
strcpy(szErrText,"LINEERR_REINIT");
break;
case LINEERR_ADDRESSBLOCKED:
strcpy(szErrText,"LINEERR_ADDRESSBLOCKED");
break;
case LINEERR_BILLINGREJECTED:
strcpy(szErrText,"LINEERR_BILLINGREJECTED");
break;
case LINEERR_INVALFEATURE:
strcpy(szErrText,"LINEERR_INVALFEATURE");
break;
case LINEERR_NOMULTIPLEINSTANCE:
strcpy(szErrText,"LINEERR_NOMULTIPLEINSTANCE");
break;
case LINEERR_INVALAGENTID:
strcpy(szErrText,"LINEERR_INVALAGENTID");
break;
case LINEERR_INVALAGENTGROUP:
strcpy(szErrText,"LINEERR_INVALAGENTGROUP");
break;
case LINEERR_INVALPASSWORD:
strcpy(szErrText,"LINEERR_INVALPASSWORD");
break;
case LINEERR_INVALAGENTSTATE:
strcpy(szErrText,"LINEERR_INVALAGENTSTATE");
break;
case LINEERR_INVALAGENTACTIVITY:
strcpy(szErrText,"LINEERR_INVALAGENTACTIVITY");
break;
case LINEERR_DIALVOICEDETECT:
strcpy(szErrText,"LINEERR_DIALVOICEDETECT");
break;
default:
free(szErrText);
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS,NULL,nError,0,(LPTSTR)&szErrText,0,NULL);
};
}