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

📄 tapiwave.c

📁 演示使用tapi通过语音modem进行拨号并播放和录制wav文件的例子
💻 C
📖 第 1 页 / 共 3 页
字号:
                  bConnected = TRUE;
                  MyPrintf(TEXT("CONNECTED.\r\n"));

                  hWaveThread = CreateThread(NULL, 0, WaveThread, NULL, 0, &dwWaveThreadID);
               }
               break;
         }

         break;
      }
   }
}


BOOL GetCallInfo()
{
   LONG lRet;
   while (TRUE)
   {
      if (lRet = lineGetCallInfo(hCall, pLineCallInfo))
      {
         MyPrintf(TEXT("lineGetCallInfo failed: %s.\r\n"), FormatTapiError(lRet));
         return FALSE;
      }

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

      return TRUE;
   }
}


// Parse the command line and change the default settings.
BOOL SetupEnvironment (int argc, LPTSTR argv[])
{
   int i = 0, j;
   TCHAR chFlag;
   BOOL bMaxCallsSet = FALSE;

   if (argc == 1)
   {
      PrintHelp();
      return FALSE;
   }

   while (++i < argc)
   {
      j = 0;
      if ((argv[i][j] == TEXT('/')) || (argv[i][j] == TEXT('-')) || (argv[i][j] == TEXT('+')))
         j = 1;

      chFlag = argv[i][j++];

      if (argv[i][j] == TEXT(':'))
         j++;
      if (argv[i][j] == TEXT('\"'))
         j++;

      switch(tolower(chFlag))
      {
         case TEXT('?'):
            MyPrintf(TEXT("Runs a test of the TAPI and WAVE system.\r\n"));
            PrintHelp();
            return FALSE;

         case TEXT('l'):
            dwDeviceID = _ttoi(&argv[i][j]);
            if (!dwDeviceID)
            {
               MyPrintf(TEXT("Invalid [L]ine selection.\r\n"));
               bCommandLineError = TRUE;
               PrintHelp();
               return FALSE;
            }
            break;

         case TEXT('i'):
            dwAddressID = _ttoi(&argv[i][j]);
            if (!dwAddressID)
            {
               MyPrintf(TEXT("Invalid Address [I]D selection.\r\n"));
               bCommandLineError = TRUE;
               PrintHelp();
               return FALSE;
            }
            break;

         case TEXT('x'):
            bLogExtraInfo = TRUE;
            MyPrintf(TEXT("Extra call and data flow information will be displayed.\r\n"));
            break;

         case TEXT('a'):
            bAnswer = TRUE;
            break;

         case TEXT('d'):
            lstrcpy(szPhoneNumber, &argv[i][j]);
            bAnswer = FALSE;
            break;

         case TEXT('f'):
            lstrcpy(szFileName, &argv[i][j]);
            break;

         case TEXT('w'):
            WaveInID = _ttoi(&argv[i][j]);
            if (!WaveInID && (argv[i][j] != TEXT('0')))
            {
               MyPrintf(TEXT("Invalid [W]ave ID selection.\r\n"));
               bCommandLineError = TRUE;
               PrintHelp();
               return FALSE;
            }
            if (WaveInID == 99)
            {
               MyPrintf(TEXT("Using WAVE_MAPPER.\r\n"));
               WaveOutID = WaveInID = WAVE_MAPPER;
               dwWaveMapped = 0;
            }
            else
               WaveOutID = WaveInID;

            bWaveLocal = TRUE;
            break;

         case TEXT('z'):
            dwWaveMapped = 0;
            break;

         case TEXT('p'):
            dwTimeToWaitBeforePlaying = _ttoi(&argv[i][j]);
            break;
      }
   }

   return TRUE;
}


// Print the help screen.
void PrintHelp()
{
   MyPrintf(
TEXT("\r\n")
TEXT("%s [options]\r\n")
TEXT("\r\n")
TEXT("[Wave File]  File to record to or play back.\r\n")
TEXT("\r\n")
TEXT("Options:\r\n")
TEXT("/L:#        Line Device ID (dwDeviceID) to use.\r\n")
//TEXT("/I:#        Line Address ID to use.  Ignored when AutoAnswer is set.\r\n")
TEXT("/X          Display extra call and data flow information.\r\n")
TEXT("/F:file     Use file as the wave file\r\n")
TEXT("/D:[number] Dial number\r\n")
TEXT("/A          Answer a call\r\n")
TEXT("\r\n")
//TEXT("/W:#        Specify a wave ID to use for both IN and OUT.\r\n")
//TEXT("            If this flag is used, all TAPI is bypassed.\r\n")
//TEXT("            A wave ID of 99 means to use WAVE_MAPPER.\r\n")
TEXT("/Z          Don't use WAVE_MAPPED\r\n")
TEXT("/P:#        Pause # milliseconds after dialing, before playing.\r\n")
TEXT("\r\n")
TEXT("defaults: /L:%lu /I:%lu\n /F:%s /A\r\n"),
TEXT("\r\n"),
   szAppName, dwDeviceID, dwAddressID, szFileName);
}




// Break Hander: Try and terminate gracefully.
// Note that ^Break can call lineShutdown *DURING* a lineMakeCall.  Very
// unpredictable results; TAPI is not re-entrant and is *usually* protected by
// the Win16 Mutex.  However, a Break Handler is a special case.
BOOL BreakHandlerRoutine(DWORD dwCtrlType)
{
   // ^BREAK will always break.  
   // Use with care; it can mess up TAPI if in the middle of a TAPI API.
   if (dwCtrlType == CTRL_BREAK_EVENT)
   {
      MyPrintf(TEXT("\r\n^[Break] terminated!  TAPI may not be left in a usable state.\r\n\r\n"));

      lineShutdown(hLineApp);
      LocalFree(pLineDevStatus);
      LocalFree(pLineCallInfo);
      LocalFree(pLineCallParams);
      ExitProcess(1);
   }
   else
   {
      if (hCall)
         MyPrintf(TEXT("\r\n^C Dropping call in progress.\r\n\r\n"));
      else 
         MyPrintf(TEXT("\r\n^C stopped.\r\n\r\n"));

      StopEverything();
   }
   return TRUE;
}

BOOL PumpMessages(BOOL bWaitForMessage)
{
	static MSG msg;

   if (bReadyToEnd)
	   return FALSE;

   if (bWaitForMessage)
   {
      if (!GetMessage(&msg, NULL, 0, 0))
         return FALSE;
   }
   else
      if (!PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
         return TRUE;
      else
         if (msg.message == WM_QUIT)
            return FALSE;

   TranslateMessage(&msg);
   DispatchMessage(&msg);

   return TRUE;
}


void StopEverything()
{
   bReadyToEnd = TRUE;

   WaitForSingleObject(hWaveThread, INFINITE);

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

   // lets prime the pump with a message.
   PostThreadMessage(dwThreadID, WM_USER, 0, 0);
}


// ---------------

typedef struct MYWAVEDATA_tag
{
   struct MYWAVEDATA_tag * pNext;
   WAVEHDR wavehdr;
   BYTE data[1];
} MYWAVEDATA, *PMYWAVEDATA;

PrintWaveInfo(WaveInID, WaveOutID);
PMYWAVEDATA LoadWaveInfo(WAVEFORMATEX* pFormat);
LPTSTR FormatWaveOutError(MMRESULT mmResult);
LPTSTR FormatWaveInError(MMRESULT mmResult);


// CONNECTED!  Now do data steam testing.  Return FALSE to stop TAPI.
DWORD WINAPI WaveThread(LPVOID pVoid)
{
   DWORD i;
   HWAVEIN     hWaveIn = NULL;
   HWAVEOUT    hWaveOut = NULL;
   MMRESULT mmResult;
   PMYWAVEDATA pWaveData, pWaveCurr;
   BYTE WaveFormatBytes[4096];
   PWAVEFORMATEX  pFormat = (PWAVEFORMATEX) WaveFormatBytes;

   // Get the wave devices to use
   if (!bWaveLocal)
   {
      LONG lRet;

      if (lRet = lineGetID(0, 0, hCall, LINECALLSELECT_CALL, pVarString, TEXT("wave/in")))
      {
         MyPrintf(TEXT("lineGetID failed %s\r\n"), FormatTapiError(lRet));
         return FALSE;
      }

      WaveInID = *(UINT *)((LPBYTE)pVarString + pVarString->dwStringOffset);

      if (lRet = lineGetID(0, 0, hCall, LINECALLSELECT_CALL, pVarString, TEXT("wave/out")))
      {
         MyPrintf(TEXT("lineGetID failed %s\r\n"), FormatTapiError(lRet));
         return FALSE;
      }

      WaveOutID = *(UINT *)((LPBYTE)pVarString + pVarString->dwStringOffset);
   }

   MyPrintf(TEXT("Using WaveInID %lu and WaveOutID %lu\r\n"),
          (DWORD) WaveInID, (DWORD) WaveOutID);

   PrintWaveInfo(WaveInID, WaveOutID);


   // Load the wave data from file.  Yes, this assumes we are playing.
   pFormat->cbSize = sizeof(WaveFormatBytes);
   pWaveData = LoadWaveInfo(pFormat);
   if (pWaveData == NULL)
      return 0;


   // Open a waveform output device.
   mmResult = waveOutOpen(&hWaveOut, WaveOutID, pFormat, 0 , 0L, dwWaveMapped);
   if (mmResult)
   {
      MyPrintf(TEXT("waveOutOpen returned %s\r\n"), FormatWaveOutError(mmResult));
      goto end;
   }


   // First, sleep 5 seconds to give the other end time to answer.
   // This is an important step as modems have no idea when the other end actually answered.
   // A sleep isn't the best way to wait, but it works for now.
   MyPrintf(TEXT("Waiting %lu milliseconds for other end to answer because modems don't know when a VOICE call has answered\r\n"), 
      dwTimeToWaitBeforePlaying);
   for(i = dwTimeToWaitBeforePlaying; i; i-=100)
   {
      if (!(i%1000))
         MyPrintf(TEXT("%lu\r\n"), i/1000);
      if (bReadyToEnd)
         break;
      Sleep(100);
   }

   // Now start playing, looping through the wave file repeatedly.

   pWaveCurr = pWaveData;
   
   while(!bReadyToEnd)
   {
      // If a buffer is queued, wait till its done.
      if (pWaveCurr->wavehdr.dwFlags & WHDR_INQUEUE)
      {
         if (bLogExtraInfo)
            MyPrintf(TEXT("Waiting for wave buffer to finish rendering\r\n"));
         Sleep(250);
         continue;
      }

      // If we've used it, we need to unprepare the header
      if (pWaveCurr->wavehdr.dwFlags & WHDR_DONE )
      {
         if(mmResult = waveOutUnprepareHeader(hWaveOut, &pWaveCurr->wavehdr, sizeof(WAVEHDR)))
         {
            MyPrintf(TEXT("waveOutUnprepareHeader returned %s\r\n"), FormatWaveOutError(mmResult));
            break;
         }
      }

      pWaveCurr->wavehdr.dwFlags = 0;

      // prepare each WAVEHDR
      if(mmResult = waveOutPrepareHeader(hWaveOut, &pWaveCurr->wavehdr, sizeof(WAVEHDR)))
      {
         MyPrintf(TEXT("waveOutPrepareHeader returned %s\r\n"), FormatWaveOutError(mmResult));
         break;
      }

      // Send to the output device.
      if (mmResult = waveOutWrite(hWaveOut, &pWaveCurr->wavehdr, sizeof(WAVEHDR)))
      {
         MyPrintf(TEXT("waveOutWrite returned %s\r\n"), FormatWaveOutError(mmResult));
         break;
      }

      if (!(pWaveCurr->wavehdr.dwFlags & WHDR_INQUEUE))
      {
         MyPrintf(TEXT("waveOutWrite did not succesfully queue."));
         break;
      }

      if (bLogExtraInfo)
         MyPrintf(TEXT("Wave buffer successfully queued.\r\n"));

      pWaveCurr = pWaveCurr->pNext;
      if (!pWaveCurr)
         pWaveCurr = pWaveData;
   }

  end:

   if (hWaveOut)
   {
      if (mmResult = waveOutReset(hWaveOut))
         MyPrintf(TEXT("waveOutReset returned %s\r\n"), FormatWaveOutError(mmResult));

      Sleep(500);  // Give it 1/2 sec to actually reset.
   
      if(mmResult = waveOutClose(hWaveOut))
         MyPrintf(TEXT("waveOutClose returned %s\r\n"), FormatWaveOutError(mmResult));

      Sleep(500); // Give it 1/2 sec to clean up.
      hWaveOut = 0;
   }

   while(pWaveData)
   {
      pWaveCurr = pWaveData;
      pWaveData = pWaveCurr->pNext;

      LocalFree(pWaveCurr);
   }

   return FALSE;
}



PrintWaveInfo(WaveInID, WaveOutID)
{
   WAVEINCAPS in;
   WAVEOUTCAPS out;

⌨️ 快捷键说明

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