📄 tapi.cpp
字号:
BthAGOnNetworkEvent(NETWORK_EVENT_FAILED, (LPVOID)&CallFailInfo, sizeof(CallFailInfo));
TapiLock();
}
DeleteTapiCall(pMsg->dwParam1);
}
}
//
// This function is called when a TAPI call state changes
//
void TapiEventCallStateChange(LPLINEMESSAGE pMsg)
{
HCALL hCall = (HCALL) pMsg->hDevice;
if (ERROR_SUCCESS != GetCallInfo(hCall)) {
DEBUGMSG(ZONE_WARN, (L"BTAGSVC: Query for caller id failed.\n"));
goto exit;
}
// Make sure is of the correct media mode
if (LINEMEDIAMODE_INTERACTIVEVOICE != g_Data.pCallInfo->dwMediaMode) {
DEBUGMSG(ZONE_WARN, (L"BTAGSVC: Call is of wrong media mode: 0x%X\n", g_Data.pCallInfo->dwMediaMode));
goto exit;
}
if (LINECALLSTATE_DISCONNECTED == pMsg->dwParam1) {
if ((g_Data.hCall == hCall) || // active call disconnected or
(g_Data.hHoldCall == hCall) || // held call disconnected or
(g_Data.hOfferingCall == hCall)) { // offering call disconnected
if (g_Data.hCall == hCall) {
g_Data.hCall = NULL;
}
else if (g_Data.hHoldCall == hCall) {
g_Data.hHoldCall = NULL;
}
else if (g_Data.hOfferingCall == hCall) {
g_Data.hOfferingCall = NULL;
}
if (NETWORK_STATE_RINGING == g_Data.dwState) {
DEBUGMSG(ZONE_NETWORK, (L"BTAGSVC: Network - Reject call.\n"));
TapiUnlock();
BthAGOnNetworkEvent(NETWORK_EVENT_CALL_REJECT, NULL, 0);
TapiLock();
}
else {
DEBUGMSG(ZONE_NETWORK, (L"BTAGSVC: Network - Hang-up call.\n"));
DWORD dwCalls = (g_Data.hCall ? 1 : 0) + (g_Data.hHoldCall ? 1 : 0) + (g_Data.hOfferingCall ? 1 : 0);
TapiUnlock();
if (LINEDISCONNECTMODE_BUSY == pMsg->dwParam2) {
BthAGOnNetworkEvent(NETWORK_EVENT_CALL_BUSY, (LPVOID)dwCalls, sizeof(DWORD));
}
else {
BthAGOnNetworkEvent(NETWORK_EVENT_CALL_DISCONNECT, (LPVOID)dwCalls, sizeof(DWORD));
}
TapiLock();
}
if (g_Data.hCall) {
g_Data.dwState = NETWORK_STATE_INCALL;
}
else if (g_Data.hHoldCall) {
g_Data.dwState = NETWORK_STATE_ONHOLD;
}
else {
g_Data.dwState = NETWORK_STATE_DISCONNECTED;
}
}
}
else if (LINECALLSTATE_BUSY == pMsg->dwParam1) {
if (g_Data.hOfferingCall == hCall) {
// Busy
DEBUGMSG(ZONE_NETWORK, (L"BTAGSVC: Network - Busy signal.\n"));
g_Data.hOfferingCall = NULL;
DWORD dwCalls = (g_Data.hCall ? 1 : 0) + (g_Data.hHoldCall ? 1 : 0) + (g_Data.hOfferingCall ? 1 : 0);
TapiUnlock();
BthAGOnNetworkEvent(NETWORK_EVENT_CALL_BUSY, (LPVOID)dwCalls, sizeof(DWORD));
TapiLock();
if (g_Data.hHoldCall) {
g_Data.dwState = NETWORK_STATE_ONHOLD;
}
else {
g_Data.dwState = NETWORK_STATE_DISCONNECTED;
}
}
}
else if (LINECALLSTATE_CONNECTED == pMsg->dwParam1) {
if (g_Data.hOfferingCall == hCall) {
DEBUGMSG(ZONE_NETWORK, (L"BTAGSVC: Network - Offering call connected.\n"));
if (g_Data.hCall) {
// If we already have an active call, it will be going on hold
g_Data.hHoldCall = g_Data.hCall;
}
g_Data.hCall = hCall;
g_Data.hOfferingCall = NULL;
TapiUnlock();
BthAGOnNetworkEvent(NETWORK_EVENT_CALL_CONNECT, NULL, 0);
TapiLock();
g_Data.dwState = NETWORK_STATE_INCALL;
}
else if (g_Data.hHoldCall == hCall) {
DEBUGMSG(ZONE_NETWORK, (L"BTAGSVC: Network - Held call connected.\n"));
g_Data.hHoldCall = g_Data.hCall;
g_Data.hCall = hCall;
g_Data.dwState = NETWORK_STATE_INCALL;
}
else if (g_Data.hCall == hCall) {
g_Data.dwState = NETWORK_STATE_INCALL;
}
}
else if (LINECALLSTATE_ONHOLD == pMsg->dwParam1) {
// Call put on hold
DEBUGMSG(ZONE_NETWORK, (L"BTAGSVC: Network - Call put on hold.\n"));
if ((g_Data.hCall == hCall) && g_Data.hHoldCall) {
// If we already have a call on hold, it must be becoming active
g_Data.hCall = g_Data.hHoldCall;
}
else if (g_Data.hCall == hCall) {
// An active call is placed on hold
g_Data.hCall = NULL;
g_Data.dwState = NETWORK_STATE_ONHOLD;
}
g_Data.hHoldCall = hCall;
}
else if (LINECALLSTATE_DIALING == pMsg->dwParam1) {
// Outgoing call
DEBUGMSG(ZONE_NETWORK, (L"BTAGSVC: Network - outgoing call.\n"));
g_Data.hOfferingCall = hCall;
g_Data.dwLastRingTime = 0;
if (g_Data.dwState == NETWORK_STATE_DISCONNECTED) {
g_Data.dwState = NETWORK_STATE_CONNECTED;
}
LONG lErr = lineSetCallPrivilege(g_Data.hOfferingCall, LINECALLPRIVILEGE_OWNER);
if (0 != lErr) {
DEBUGMSG(ZONE_WARN, (L"BTAGSVC: Network - Error calling lineSetCallPrivilege: %d.\n", lErr));
}
TapiUnlock();
BthAGOnNetworkEvent(NETWORK_EVENT_CALL_OUT, NULL, 0);
TapiLock();
}
else if (LINECALLSTATE_OFFERING == pMsg->dwParam1) {
// Incoming call
DEBUGMSG(ZONE_NETWORK, (L"BTAGSVC: Network - incoming call.\n"));
CHAR szNumber[MAX_PHONE_NUMBER];
szNumber[0] = 0; // Null terminate
g_Data.fCallIdNotify = FALSE;
DWORD cbWritten = 0;
if (g_Data.pCallInfo->dwCallerIDOffset > 0) {
cbWritten = WideCharToMultiByte(CP_ACP, 0,
(WCHAR*)((BYTE*)g_Data.pCallInfo + g_Data.pCallInfo->dwCallerIDOffset),
g_Data.pCallInfo->dwCallerIDSize/2,
szNumber,
MAX_PHONE_NUMBER,
NULL, NULL);
g_Data.fCallIdNotify = TRUE;
}
g_Data.hOfferingCall = hCall;
g_Data.dwLastRingTime = 0;
if (g_Data.dwState == NETWORK_STATE_DISCONNECTED) {
g_Data.dwState = NETWORK_STATE_CONNECTED;
}
LONG lErr = lineSetCallPrivilege(g_Data.hOfferingCall, LINECALLPRIVILEGE_OWNER);
if (0 != lErr) {
DEBUGMSG(ZONE_WARN, (L"BTAGSVC: Network - Error calling lineSetCallPrivilege: %d.\n", lErr));
}
TapiUnlock();
BthAGOnNetworkEvent(NETWORK_EVENT_CALL_IN, szNumber, cbWritten);
TapiLock();
}
exit:
if ((LINECALLSTATE_IDLE == pMsg->dwParam1) ||
(LINECALLSTATE_DISCONNECTED == pMsg->dwParam1)) {
// Call has gone away - must deallocate the call handle that TAPI created for us in LINE_APPNEWCALL
lineDeallocateCall(hCall);
}
return;
}
typedef void (*PFNEVENTPROC)(LPLINEMESSAGE pMsg);
typedef struct _TAPI_EVENT_TBL {
DWORD dwCommand;
PFNEVENTPROC pfnHandler;
} TAPI_EVENT_TBL, *PTAPI_EVENT_TBL;
const TAPI_EVENT_TBL TapiEventTable[] = {
LINE_LINEDEVSTATE, TapiEventDevStateChange,
LINE_CALLINFO, TapiEventCallInfo,
LINE_REPLY, TapiEventLineReply,
LINE_CALLSTATE, TapiEventCallStateChange,
};
#define TAPI_EVENT_TBL_LENGTH (sizeof(TapiEventTable)/sizeof(TAPI_EVENT_TBL))
//
// This function is a thread that listens for messages from TAPI and processes them.
//
DWORD WINAPI TapiEventThread(LPVOID pv)
{
DEBUGMSG(ZONE_NETWORK, (L"BTAGSVC: ++TapiEventThread\n"));
TapiLock();
while (! g_Data.fShutdown) {
LONG lResult;
DWORD dwWait;
HANDLE h = g_Data.hTapiEvent;
LINEMESSAGE msg;
TapiUnlock();
dwWait = WaitForSingleObject(h, INFINITE);
TapiLock();
if (g_Data.fShutdown) {
DEBUGMSG(ZONE_NETWORK, (L"BTAGSVC: Network - Shutting down TapiEventThread.\n"));
break;
}
lResult = lineGetMessage(g_Data.hLineApp, &msg, 0);
if (lResult != 0) {
ASSERT(0);
continue;
}
for (int i = 0; i < TAPI_EVENT_TBL_LENGTH; i++) {
if (msg.dwMessageID == TapiEventTable[i].dwCommand) {
TapiEventTable[i].pfnHandler(&msg);
break;
}
}
}
if (g_Data.pCallInfo) {
delete[] g_Data.pCallInfo;
g_Data.pCallInfo = NULL;
}
TapiUnlock();
DEBUGMSG(ZONE_NETWORK, (L"BTAGSVC: --TapiEventThread\n"));
return 0;
}
//
// This function is called to initialize the AG's Network Component.
//
DWORD BthAGNetworkInit(HINSTANCE hInstance)
{
DWORD dwRetVal = ERROR_SUCCESS;
DWORD cLines;
HKEY hk;
unsigned int uiCellLine;
LINEINITIALIZEEXPARAMS LineInitializeExParams;
DWORD dwVersion = TAPI_API_HIGH_VERSION;
WCHAR wszName[MAX_PATH];
BOOL fUseDefaultLine = TRUE;
DEBUGMSG(ZONE_NETWORK, (L"BTAGSVC: ++BthAGNetworkInit\n"));
if (InterlockedExchange(&g_Inited, 1)) {
return dwRetVal;
}
TapiLock();
LineInitializeExParams.dwTotalSize = sizeof(LineInitializeExParams);
LineInitializeExParams.dwOptions = LINEINITIALIZEEXOPTION_USEEVENT;
dwRetVal = lineInitializeEx(&g_Data.hLineApp, hInstance, NULL, L"BTAGSVC", &cLines, &dwVersion, &LineInitializeExParams);
if (ERROR_SUCCESS != dwRetVal) {
ASSERT(0);
goto exit;
}
g_Data.hTapiEvent = LineInitializeExParams.Handles.hEvent;
g_Data.hThread = CreateThread(NULL, 0, TapiEventThread, NULL, 0, NULL);
if (! g_Data.hThread) {
ASSERT(0);
goto exit;
}
if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, RK_AUDIO_GATEWAY, 0, 0, &hk)) {
DWORD cdwBytes = MAX_PATH;
if (ERROR_SUCCESS == RegQueryValueEx(hk, _T("TapiLineName"), 0, NULL, (PBYTE)wszName, &cdwBytes)) {
fUseDefaultLine = FALSE;
}
RegCloseKey(hk);
}
if (fUseDefaultLine) {
dwRetVal = FindTSPLine(DEFAULT_TAPI_CELL_LINE, cLines, &uiCellLine);
}
else {
dwRetVal = FindTSPLine(wszName, cLines, &uiCellLine);
}
if (ERROR_SUCCESS != dwRetVal) {
DEBUGMSG(ZONE_ERROR, (L"BTAGSVC: Error finding cellular line: %d\n", dwRetVal));
goto exit;
}
dwRetVal = OpenLine(uiCellLine);
if (ERROR_SUCCESS != dwRetVal) {
DEBUGMSG(ZONE_ERROR, (L"BTAGSVC: Error opening line: %d\n", dwRetVal));
goto exit;
}
// Specify additional messages we would like to receive in TapiEventThread
dwRetVal = lineSetStatusMessages(g_Data.hLine,
LINEDEVSTATE_RINGING | LINEDEVSTATE_CONNECTED | LINEDEVSTATE_DISCONNECTED,
0);
if (ERROR_SUCCESS != dwRetVal) {
DEBUGMSG(ZONE_ERROR, (L"BTAGSVC: Error setting line status messages: %d\n", dwRetVal));
goto exit;
}
g_Data.dwWaitTimeout = TAPI_COMMAND_TIMEOUT;
if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, RK_AUDIO_GATEWAY, 0, 0, &hk)) {
DWORD dwData;
DWORD cdwBytes = sizeof(dwData);
if (ERROR_SUCCESS == RegQueryValueEx(hk, _T("TapiAsyncTimeoutSeconds"), 0, NULL, (PBYTE)&dwData, &cdwBytes)) {
g_Data.dwWaitTimeout = (dwData * 1000);
}
RegCloseKey(hk);
}
DEBUGMSG(ZONE_NETWORK, (L"BTAGSVC: Network Module was successfullly initialized.\n"));
exit:
TapiUnlock();
if (ERROR_SUCCESS != dwRetVal) {
BthAGNetworkDeinit();
}
DEBUGMSG(ZONE_NETWORK, (L"BTAGSVC: --BthAGNetworkInit\n"));
return dwRetVal;
}
//
// This function deinitializes the AG's Network Component.
//
void BthAGNetworkDeinit(void)
{
DEBUGMSG(ZONE_NETWORK, (L"BTAGSVC: ++BthAGNetworkDeinit\n"));
if (0 == g_Inited) {
return; // Not initialized
}
TapiLock();
if (g_Data.hThread) {
HANDLE h = g_Data.hThread;
g_Data.fShutdown = TRUE;
SetEvent(g_Data.hTapiEvent);
TapiUnlock();
WaitForSingleObject(h, INFINITE);
TapiLock();
while (g_Data.GetRefCount() > 1) {
DEBUGMSG(ZONE_NETWORK, (L"BTAGSVC: Sleeping while Tapi Network Component ref count is still active.\n"));
TapiUnlock();
Sleep(500);
TapiLock();
}
// Wait for all calls to return
int count = 0;
while ((count++ > 10) && g_Data.CallList.size()) {
DEBUGMSG(ZONE_NETWORK, (L"BTAGSVC: Sleeping a bit since all Tapi calls have not been returned.\n"));
TapiUnlock();
Sleep(500);
TapiLock();
}
// If not all calls have returned by this point, remove them
if (g_Data.CallList.size()) {
DEBUGMSG(ZONE_WARN, (L"BTAGSVC: Forcefully deleting remaining Tapi calls\n"));
g_Data.CallList.clear();
}
CloseHandle(h);
}
lineClose(g_Data.hLine);
lineShutdown(g_Data.hLineApp);
TapiUnlock();
InterlockedExchange(&g_Inited, 0);
DEBUGMSG(ZONE_NETWORK, (L"BTAGSVC: --BthAGNetworkDeinit\n"));
}
//
// This function dials a number through TAPI.
//
DWORD BthAGNetworkDialNumber(LPWSTR pwszNumber)
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -