📄 tapiwave.c
字号:
/*----------------------------------------------------------*\
TapiWave
This sample console application is designed to demonstrate
how to use TAPI to play and record wave files using a voice modem.
\*----------------------------------------------------------*/
#define TAPI_CURRENT_VERSION 0x00010004
#include <windows.h>
#include <tapi.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "TapiInfo.h"
#include <mmsystem.h>
char szAppName[] = "TapiWave";
char szAppFileName[] = "TapiWave.exe";
// TAPI constants; command line settable
DWORD dwDeviceID = 0;
DWORD dwAddressID = 0;
// TAPI global variables.
HINSTANCE hInstance;
HLINEAPP hLineApp = 0;
LINEEXTENSIONID LineExtensionID;
DWORD dwNumDevs;
DWORD dwAPIVersion;
HLINE hLine;
HCALL hCall = 0;
long lRet;
char szPhoneNumber[1024] = "45776";
LPVARSTRING lpVarString;
LPLINEDEVSTATUS lpLineDevStatus;
LPLINECALLINFO lpLineCallInfo;
LPLINECALLPARAMS lpLineCallParams;
// State machine information.
DWORD dwMakeCallAsyncID=0;
DWORD dwLineDropAsyncID=0;
BOOL bDropped = FALSE;
BOOL bConnected = FALSE;
BOOL bAnswered = FALSE;
BOOL bReadyToEnd = FALSE;
BOOL bPrintedEnd = FALSE;
// Constants in how the state machine behaves.
BOOL bDontClose = FALSE;
BOOL bCommandLineError = FALSE;
BOOL bLogExtraInfo = FALSE;
BOOL bAnswer = TRUE;
// Variables so we can ^C to shutdown and clean up properly.
DWORD dwThreadID;
HANDLE hSleep;
// Used to format data into.
char szBuff[4096];
// /// Waveaudio content ///
UINT WaveInID = 0;
UINT WaveOutID = 0;
BOOL bWaveLocal = FALSE;
char szFileName[1024] = "greeting.wav";
DWORD dwWaveBuffers = 10;
DWORD dwWaveBuffSize = 1024;
DWORD dwWaveMapped = WAVE_MAPPED;
HWAVEIN hWaveIn = NULL;
HWAVEOUT hWaveOut = NULL;
LPWAVEHDR lpWaveHdr = NULL;
LPSTR lpData = NULL; // waveform data block
LPSTR lpstrLoadStrBuf = NULL;
HMMIO hmmio;
MMCKINFO mmckinfoParent;
MMCKINFO mmckinfoSubchunk;
DWORD dwFmtSize;
WAVEFORMATEX *pFormat;
DWORD dwDataSize;
LPSTR hpch1, hpch2;
WORD wBlockSize;
// Prototypes
void CALLBACK lineCallbackFunc(
DWORD dwDevice, DWORD dwMsg, DWORD dwCallbackInstance,
DWORD dwParam1, DWORD dwParam2, DWORD dwParam3);
BOOL SetupEnvironment (int argc, char * argv[]);
void PrintHelp();
BOOL BreakHandlerRoutine(DWORD dwCtrlType);
BOOL GetCallInfo();
void StopEverything();
BOOL PumpMessages(BOOL bWaitForMessage);
BOOL DoConnectedStuff();
void StopConnectedStuff();
void PlayFromMemory (LPSTR szWavData);
DWORD WINAPI ThreadRecorded (LPVOID lpvThreadParam);
void RecordToMemory (LPSTR szWavData);
void BuildWavData (LPSTR szFilename, LPSTR szWavData, DWORD dwMaxBufferSize);
// Console app starting place.
int main (int argc, char * argv[], char * envp[])
{
MSG msg;
// Setup basic stuff.
hInstance = GetModuleHandle(NULL);
hSleep = CreateEvent(NULL, TRUE, FALSE, NULL);
dwThreadID = GetCurrentThreadId();
SetConsoleCtrlHandler((PHANDLER_ROUTINE) BreakHandlerRoutine, TRUE);
if (!SetupEnvironment(argc, argv))
goto end;
if (bWaveLocal)
{
DoConnectedStuff();
goto end;
}
// Prime the message queue. TAPI callback is called as a result
// of messages being dispatched. By default, console apps don't have
// a message queue to hold these messages. PeekMessage will create it.
PeekMessage(&msg, NULL, 0, 0, PM_REMOVE);
lpVarString = LocalAlloc(LPTR, 1024);
lpLineDevStatus = LocalAlloc(LPTR, 4096);
lpLineCallInfo = LocalAlloc(LPTR, 4096);
lpLineCallParams = LocalAlloc(LPTR, 4096);
lpVarString -> dwTotalSize = 1024;
lpLineDevStatus -> dwTotalSize = 4096;
lpLineCallInfo -> dwTotalSize = 4096;
lpLineCallParams -> dwTotalSize = 4096;
lpLineCallParams -> dwBearerMode = LINEBEARERMODE_VOICE;
lpLineCallParams -> dwMinRate = 300;
lpLineCallParams -> dwMaxRate = 64000;
lpLineCallParams -> dwMediaMode = LINEMEDIAMODE_AUTOMATEDVOICE,
lpLineCallParams -> dwCallParamFlags = 0;
lpLineCallParams -> dwAddressMode = LINEADDRESSMODE_ADDRESSID;
lpLineCallParams -> dwAddressID = dwAddressID;
if (lRet = lineInitialize(&hLineApp, hInstance, lineCallbackFunc,
szAppName, &dwNumDevs))
{
printf("lineInitialize failed: %s.\n", FormatTapiError(lRet, szBuff));
goto end;
}
if (lRet = lineNegotiateAPIVersion(hLineApp, dwDeviceID,
0x00010004, 0x00010004, &dwAPIVersion, &LineExtensionID))
{
if (lRet = LINEERR_INCOMPATIBLEAPIVERSION)
{
if (lRet = lineNegotiateAPIVersion(hLineApp, dwDeviceID,
0x00010003, 0x0FFF0FFF, &dwAPIVersion, &LineExtensionID))
{
printf("lineNegotiateAPIVersion failed: %s.\n", FormatTapiError(lRet, szBuff));
goto end;
}
if (bLogExtraInfo)
printf("lineNegotiateAPIVersion succeeded for API Version 0x%lx.\n"
"%s is designed for API Version 1.4, but 1.3 and 2.0 should be ok\n",
dwAPIVersion);
}
else
{
printf("lineNegotiateAPIVersion failed: %s.\n", FormatTapiError(lRet, szBuff));
goto end;
}
}
if (lRet = lineOpen(hLineApp, dwDeviceID, &hLine, dwAPIVersion, 0, 0,
LINECALLPRIVILEGE_NONE, 0, NULL))
{
printf("lineOpen failed: %s.\n", FormatTapiError(lRet, szBuff));
goto end;
}
while (TRUE)
{
if (lRet = lineGetLineDevStatus(hLine, lpLineDevStatus))
{
printf("lineGetLineDevStatus failed: %s.\n", FormatTapiError(lRet, szBuff));
goto end;
}
if (lpLineDevStatus->dwNeededSize > lpLineDevStatus->dwTotalSize)
{
LocalReAlloc(lpLineDevStatus, lpLineDevStatus->dwNeededSize, LMEM_MOVEABLE);
lpLineDevStatus->dwTotalSize = lpLineDevStatus->dwNeededSize;
continue;
}
break;
}
if (lpLineDevStatus -> dwOpenMediaModes)
printf("!!!WARNING!!! Another application is already waiting for calls.\n\n");
if (!((lpLineDevStatus -> dwLineFeatures) & LINEFEATURE_MAKECALL))
printf("!!!WARNING!!! No call appearances available at this time.\n\n");
if (bAnswer)
{
lineClose(hLine);
if (lRet = lineOpen(hLineApp, dwDeviceID, &hLine, dwAPIVersion, 0, 0,
LINECALLPRIVILEGE_OWNER, LINEMEDIAMODE_AUTOMATEDVOICE, NULL))
{
printf("lineOpen failed: %s.\n", FormatTapiError(lRet, szBuff));
goto end;
}
printf("Waiting for a call on TAPI Line Device %lu\n", dwDeviceID);
}
else
{
lRet = lineMakeCall(hLine, &hCall, szPhoneNumber, 0, lpLineCallParams);
if (lRet < 0)
{
printf("lineMakeCall failed: %s.\n", FormatTapiError(lRet, szBuff));
goto end;
}
else
{
dwMakeCallAsyncID = lRet;
}
}
// TAPI callback is called only when messages are dispatched!
while (!bReadyToEnd || hCall)
{
PumpMessages(TRUE);
}
end:
lineShutdown(hLineApp);
hLineApp = 0;
LocalFree(lpLineDevStatus);
LocalFree(lpLineCallInfo);
LocalFree(lpLineCallParams);
LocalFree(lpVarString);
if (bDontClose)
WaitForSingleObject(hSleep, INFINITE);
CloseHandle(hSleep);
return 1;
}
// Here's the TAPI callback. Mondo switch statement!
void CALLBACK lineCallbackFunc(
DWORD dwDevice, DWORD dwMsg, DWORD dwCallbackInstance,
DWORD dwParam1, DWORD dwParam2, DWORD dwParam3)
{
if (bLogExtraInfo)
printf("LCBF: %s\n", // LCBF stands for lineCallBackFunc
FormatLineCallback(
dwDevice, dwMsg, dwCallbackInstance,
dwParam1, dwParam2, dwParam3,
szBuff));
switch(dwMsg)
{
case LINE_LINEDEVSTATE:
if (dwParam1 == LINEDEVSTATE_REINIT)
{
printf("LINEDEVSTATE_REINIT\n");
StopEverything();
}
break;
case LINE_REPLY:
if (dwParam2 == dwLineDropAsyncID)
{
if (dwParam2 != 0)
{
printf("lineDrop LINE_REPLY with failure: %s. Stopping.\r\n",
FormatTapiError((long) dwParam2, szBuff));
StopEverything();
}
}
else if (dwParam2 == dwMakeCallAsyncID)
{
if (dwParam2 != 0)
{
printf("lineMakeCall LINE_REPLY with failure: %s. Stopping.\r\n",
FormatTapiError((long) dwParam2, szBuff));
StopEverything();
}
}
// else ignore it.
break;
case LINE_CALLSTATE:
{
// Is this a new call?
if (dwParam3 == LINECALLPRIVILEGE_OWNER)
{
// Do we already have a call?
if (hCall && (hCall != (HCALL) dwDevice))
{
if (dwMsg == LINECALLSTATE_IDLE)
lineDeallocateCall((HCALL) dwDevice);
else
{
printf("New call; %lu, but already managing one. Dropping it.\r\n",
dwDevice);
lineDrop((HCALL) dwDevice, NULL, 0);
}
break;
}
if (hCall)
printf("Given OWNER privs to a call already owned?\n"
" - Should only happen if handed a call already owned.\n");
else
{
hCall = (HCALL) dwDevice;
printf("New incoming hCall 0x%lx on TAPI Line Device.\r\n",
hCall, dwDeviceID);
}
}
if (hCall != (HCALL) dwDevice)
{
if (dwMsg == LINECALLSTATE_IDLE)
lineDeallocateCall((HCALL) dwDevice);
else
{
lineDrop((HCALL) dwDevice, NULL, 0);
printf("LINE_CALLSTATE 0x%lx for non-main hCall: 0x%lx. Dropping.\n",
dwParam1, dwDevice);
}
break;
}
switch (dwParam1)
{
case LINECALLSTATE_IDLE:
{
printf("IDLE.\n\n");
lRet = lineDeallocateCall(hCall);
// Should make sure lineDeallocateCall succeeded
hCall = 0;
StopEverything();
break;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -