⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tapiwave.c

📁 演示使用tapi通过语音modem进行拨号并播放和录制wav文件的例子
💻 C
📖 第 1 页 / 共 3 页
字号:
/*----------------------------------------------------------*\
TapiWave

This sample console application is designed to demonstrate
how to use TAPI to play and record wave files using a voice modem.

\*----------------------------------------------------------*/

//#define UNICODE
//#define _UNICODE

#pragma comment(linker, "/subsystem:console")
#pragma comment(lib, "tapi32")

#include <windows.h>
#include <mmsystem.h>
#include <tchar.h>
#include <stdio.h>

#ifdef UNICODE
#define TAPI_CURRENT_VERSION 0x00020000
#else
#define TAPI_CURRENT_VERSION 0x00010004
#endif
#include <tapi.h>


TCHAR szAppName[] = TEXT("TapiWave");
TCHAR szAppFileName[] = TEXT("TapiWave.exe");


// TAPI constants; command line settable
DWORD dwDeviceID = 0;
DWORD dwAddressID = 0;

// TAPI global variables.
HINSTANCE hInstance;
HLINEAPP hLineApp = 0;
DWORD dwNumDevs;
DWORD dwAPIVersion;
HLINE hLine;
HCALL hCall = 0;
LINEEXTENSIONID LineExtensionID;


#if TAPI_CURRENT_VERSION >= 0x00020000
LINEINITIALIZEEXPARAMS lineInitializeExParams = {
   sizeof(lineInitializeExParams), 0, 0,
   LINEINITIALIZEEXOPTION_USEHIDDENWINDOW,
   NULL, 0
   };
#endif


TCHAR szPhoneNumber[256] = TEXT("45776");

#define BIGBUFF 8096

LPVARSTRING             pVarString        = NULL;
LPLINEDEVSTATUS         pLineDevStatus    = NULL;
LPLINECALLINFO          pLineCallInfo     = NULL;
LPLINECALLPARAMS        pLineCallParams   = NULL;
LPLINETRANSLATEOUTPUT   pTranslateOutput  = NULL;

// 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 bCommandLineError = FALSE;
BOOL bLogExtraInfo = FALSE;
BOOL bAnswer = TRUE;

// Variables so we can ^C to shutdown and clean up properly.
DWORD dwThreadID;
DWORD dwWaveThreadID;
DWORD dwTimeToWaitBeforePlaying = 5000;

// /// Waveaudio content ///

HANDLE hWaveThread = NULL;
UINT WaveInID = 0;
UINT WaveOutID = 0;
BOOL bWaveLocal = FALSE;
TCHAR szFileName[1024] = TEXT("greeting.wav");
DWORD dwWaveMapped = WAVE_MAPPED;


// Prototypes
void CALLBACK lineCallbackFunc(
    DWORD dwDevice, DWORD dwMsg, DWORD dwCallbackInstance, 
    DWORD dwParam1, DWORD dwParam2, DWORD dwParam3);
BOOL SetupEnvironment (int argc, LPTSTR argv[]);
void PrintHelp();
BOOL BreakHandlerRoutine(DWORD dwCtrlType);
BOOL GetCallInfo();
void StopEverything();
BOOL PumpMessages(BOOL bWaitForMessage);
DWORD WINAPI WaveThread(LPVOID pVoid);



void PlayFromMemory (LPSTR szWavData);
DWORD WINAPI ThreadRecorded (LPVOID pvThreadParam);
void RecordToMemory (LPSTR szWavData);
void BuildWavData (LPSTR szFilename, LPSTR szWavData, DWORD dwMaxBufferSize);

void __cdecl MyPrintf(LPCTSTR pszFormat, ...);
LPCTSTR FormatError(DWORD dwError);
LPCTSTR FormatErrorBuffer(DWORD dwError, LPTSTR pszBuff, DWORD dwNumChars);
BOOL WINAPI HandlerRoutine(DWORD dwCtrlType);
LPTSTR FormatTapiError (long lError);


// Console app starting place.
int __cdecl _tmain(int argc, _TCHAR *argv[], _TCHAR *envp[])
{
   LONG lRet;
   MSG msg;

   // Setup basic stuff.
   hInstance = GetModuleHandle(NULL);
   dwThreadID = GetCurrentThreadId();
   SetConsoleCtrlHandler((PHANDLER_ROUTINE) BreakHandlerRoutine, TRUE);	

   if (!SetupEnvironment(argc, argv))
      goto end;

   if (bWaveLocal)
   {
      hWaveThread = CreateThread(NULL, 0, WaveThread, NULL, 0, &dwWaveThreadID);
      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);

   pVarString       = LocalAlloc(LPTR, BIGBUFF);
   pLineDevStatus   = LocalAlloc(LPTR, BIGBUFF);
   pLineCallInfo    = LocalAlloc(LPTR, BIGBUFF);
   pLineCallParams  = LocalAlloc(LPTR, BIGBUFF);
   pTranslateOutput = LocalAlloc(LPTR, BIGBUFF);

   pVarString       -> dwTotalSize = BIGBUFF;
   pLineDevStatus   -> dwTotalSize = BIGBUFF;
   pLineCallInfo    -> dwTotalSize = BIGBUFF;
   pTranslateOutput -> dwTotalSize = BIGBUFF;

   pLineCallParams -> dwTotalSize = BIGBUFF;
   pLineCallParams -> dwBearerMode       = LINEBEARERMODE_VOICE;
   pLineCallParams -> dwMediaMode        = LINEMEDIAMODE_AUTOMATEDVOICE,
   pLineCallParams -> dwCallParamFlags   = 0;
   pLineCallParams -> dwAddressMode      = LINEADDRESSMODE_ADDRESSID;
   pLineCallParams -> dwAddressID        = dwAddressID;

#if TAPI_CURRENT_VERSION >= 0x00020000
   dwAPIVersion = TAPI_CURRENT_VERSION;
   lRet = lineInitializeEx(&hLineApp, hInstance, lineCallbackFunc, 
                         szAppName, &dwNumDevs, 
                         &dwAPIVersion, &lineInitializeExParams);
#else
   // Note that you can't use this function and be UNICODE
   lRet = lineInitialize(&hLineApp, hInstance, lineCallbackFunc, 
                         szAppName, &dwNumDevs);
#endif
   if (lRet)
   {
      MyPrintf(TEXT("lineInitialize failed: %s.\r\n"), FormatTapiError(lRet));
      goto end;
   }

   if (lRet = lineNegotiateAPIVersion(hLineApp, dwDeviceID, 
      0x00010004, 0x00010004, &dwAPIVersion, &LineExtensionID))
   {
      MyPrintf(TEXT("lineNegotiateAPIVersion failed: %s.\r\n"), FormatTapiError(lRet));
      goto end;
   }

   if (lRet = lineOpen(hLineApp, dwDeviceID, &hLine, dwAPIVersion, 0, 0,
            LINECALLPRIVILEGE_NONE, 0, NULL))
   {
      MyPrintf(TEXT("lineOpen failed: %s.\r\n"), FormatTapiError(lRet));
      goto end;
   }
   
   while (TRUE)
   {
      if (lRet = lineGetLineDevStatus(hLine, pLineDevStatus))
      {
         MyPrintf(TEXT("lineGetLineDevStatus failed: %s.\r\n"), FormatTapiError(lRet));
         goto end;
      }

      if (pLineDevStatus->dwNeededSize > pLineDevStatus->dwTotalSize)
      {
         LocalReAlloc(pLineDevStatus, pLineDevStatus->dwNeededSize, LMEM_MOVEABLE);
         pLineDevStatus->dwTotalSize = pLineDevStatus->dwNeededSize;
         continue;
      }
      break;
   }

   if (pLineDevStatus -> dwOpenMediaModes)
      MyPrintf(TEXT("!!!WARNING!!!  Another application is already waiting for calls.\r\n\r\n"));

   if (!((pLineDevStatus -> dwLineFeatures) & LINEFEATURE_MAKECALL))
      MyPrintf(TEXT("!!!WARNING!!!  No call appearances available at this time.\r\n\r\n"));

   if (bAnswer)
   {
      lineClose(hLine);

      if (lRet = lineOpen(hLineApp, dwDeviceID, &hLine, dwAPIVersion, 0, 0,
            LINECALLPRIVILEGE_OWNER, LINEMEDIAMODE_AUTOMATEDVOICE, NULL))
      {
         MyPrintf(TEXT("lineOpen failed: %s.\r\n"), FormatTapiError(lRet));
         goto end;
      }

      MyPrintf(TEXT("Waiting for a call on TAPI Line Device %lu\r\n"), dwDeviceID);
   }
   else
   {

      if (lRet = lineTranslateAddress(hLineApp, dwDeviceID, dwAPIVersion, szPhoneNumber,
                     0, 0, pTranslateOutput))
      {
         MyPrintf(TEXT("lineTranslateAddress failed: %s.\r\n"), FormatTapiError(lRet));
         goto end;
      }

      lRet = lineMakeCall(hLine, &hCall, szPhoneNumber, 0, pLineCallParams);
      if (lRet < 0)
      {
         MyPrintf(TEXT("lineMakeCall failed: %s.\r\n"), FormatTapiError(lRet));
         goto end;
      }
      else
      {
         dwMakeCallAsyncID = lRet;
      }
   }

   // TAPI callback is called only when messages are dispatched!
   while (PumpMessages(TRUE));

  end:

   StopEverything();

   if (hLineApp)
      lineShutdown(hLineApp);
   hLineApp = 0;

   if (pLineDevStatus)
      LocalFree(pLineDevStatus);
   if (pLineCallInfo)
      LocalFree(pLineCallInfo);
   if (pLineCallParams)
      LocalFree(pLineCallParams);
   if (pVarString)
      LocalFree(pVarString);
   if (pTranslateOutput)
      LocalFree(pTranslateOutput);

   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)
{
   LONG lRet;

   /*
   if (bLogExtraInfo)
      MyPrintf(TEXT("LCBF: %s\r\n"),    // LCBF stands for lineCallBackFunc
         FormatLineCallback(
               dwDevice, dwMsg, dwCallbackInstance, 
               dwParam1, dwParam2, dwParam3,
               szBuff));
               */

   switch(dwMsg)
   {
      case LINE_LINEDEVSTATE:
         if (dwParam1 == LINEDEVSTATE_REINIT)
         {
            MyPrintf(TEXT("LINEDEVSTATE_REINIT\r\n"));
            StopEverything();
         }
         break;

      case LINE_REPLY:
         if (dwParam2 == dwLineDropAsyncID)
         {
            if (dwParam2 != 0)
            {
               MyPrintf(TEXT("lineDrop LINE_REPLY with failure: %s.  Stopping.\r\r\n"), 
                  FormatTapiError((long) dwParam2));
               StopEverything();
            }
         }
         else if (dwParam2 == dwMakeCallAsyncID)
         {
            if (dwParam2 != 0)
            {
               MyPrintf(TEXT("lineMakeCall LINE_REPLY with failure: %s.  Stopping.\r\r\n"), 
                  FormatTapiError((long) dwParam2));
               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
               {
                  MyPrintf(TEXT("New call; %lu, but already managing one.  Dropping it.\r\r\n"),
                        dwDevice);
                  lineDrop((HCALL) dwDevice, NULL, 0);
               }
               break;
            }

            if (hCall)
               MyPrintf(
                  TEXT("Given OWNER privs to a call already owned?\r\n")
                  TEXT(" - Should only happen if handed a call already owned.\r\n"));
            else
            {
               hCall = (HCALL) dwDevice;
               MyPrintf(TEXT("New incoming hCall 0x%lx on TAPI Line Device.\r\r\n"),
                  hCall, dwDeviceID);
            }
         }

         if (hCall != (HCALL) dwDevice)
         {
            if (dwMsg == LINECALLSTATE_IDLE)
               lineDeallocateCall((HCALL) dwDevice);
            else
            {
               lineDrop((HCALL) dwDevice, NULL, 0);
               MyPrintf(TEXT("LINE_CALLSTATE 0x%lx for non-main hCall: 0x%lx.  Dropping.\r\n"), 
                  dwParam1, dwDevice);
            }
            break;
         }

         switch (dwParam1)
         {
            case LINECALLSTATE_IDLE:
            {
               MyPrintf(TEXT("IDLE.\n\r\n"));
               lRet = lineDeallocateCall(hCall);

               // Should make sure lineDeallocateCall succeeded

               hCall = 0;
               StopEverything();
               break;
            }

            case LINECALLSTATE_BUSY:
            case LINECALLSTATE_DISCONNECTED:
               if (dwParam1 == LINECALLSTATE_BUSY)
                  MyPrintf(TEXT("BUSY.  Hanging up.\r\n"));
               else
                  MyPrintf(TEXT("DISCONNECTED.  Hanging up.\r\n"));

               if (!bDropped)
                  dwLineDropAsyncID = lineDrop(hCall, NULL, 0);
               if (dwLineDropAsyncID < 0)
               {
                  MyPrintf(TEXT("lineDrop failed.  Terminating\r\n"));
                  hCall = 0;
                  StopEverything();
               }

               bDropped = TRUE;

               break;

            case LINECALLSTATE_OFFERING:
            case LINECALLSTATE_ACCEPTED:  // Could be handed off an accepted call
               if (bAnswered)
                  break;

               if (dwParam1 == LINECALLSTATE_OFFERING)
                  MyPrintf(TEXT("Answering an OFFERING call.\r\n\r\n"));
               else
                  MyPrintf(TEXT("Answering an ACCEPTED call.\r\n\r\n"));

               lRet = lineAnswer(hCall, NULL, 0);

               // Should check to make sure lineAnswer succeeded

               bAnswered = TRUE;

               break;

            case LINECALLSTATE_CONNECTED:
               if (!bConnected)
               {

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -