Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1688 lines
40 KiB

  1. /////////////////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright (c) 1998 Active Voice Corporation. All Rights Reserved.
  4. //
  5. // Active Agent(r) and Unified Communications(tm) are trademarks of Active Voice Corporation.
  6. //
  7. // Other brand and product names used herein are trademarks of their respective owners.
  8. //
  9. // The entire program and user interface including the structure, sequence, selection,
  10. // and arrangement of the dialog, the exclusively "yes" and "no" choices represented
  11. // by "1" and "2," and each dialog message are protected by copyrights registered in
  12. // the United States and by international treaties.
  13. //
  14. // Protected by one or more of the following United States patents: 5,070,526, 5,488,650,
  15. // 5,434,906, 5,581,604, 5,533,102, 5,568,540, 5,625,676, 5,651,054.
  16. //
  17. // Active Voice Corporation
  18. // Seattle, Washington
  19. // USA
  20. //
  21. /////////////////////////////////////////////////////////////////////////////////////////
  22. ////
  23. // wavin.c - wav input device functions
  24. ////
  25. #include "winlocal.h"
  26. #include "wavin.h"
  27. #include "wav.h"
  28. #include "acm.h"
  29. #include "calc.h"
  30. #include "mem.h"
  31. #include "str.h"
  32. #include "sys.h"
  33. #include "trace.h"
  34. #include <mmddk.h>
  35. // allow telephone input functions if defined
  36. //
  37. #ifdef TELIN
  38. #include "telin.h"
  39. static HTELIN hTelIn = NULL;
  40. #endif
  41. ////
  42. // private definitions
  43. ////
  44. #define WAVINCLASS TEXT("WavInClass")
  45. // wavin control struct
  46. //
  47. typedef struct WAVIN
  48. {
  49. DWORD dwVersion;
  50. HINSTANCE hInst;
  51. HTASK hTask;
  52. UINT idDev;
  53. LPWAVEFORMATEX lpwfx;
  54. HWND hwndNotify;
  55. DWORD dwFlags;
  56. BOOL fIsOpen;
  57. HWAVEIN hWaveIn;
  58. WORD wState;
  59. HWND hwndCallback;
  60. #ifdef MULTITHREAD
  61. HANDLE hThreadCallback;
  62. DWORD dwThreadId;
  63. HANDLE hEventThreadCallbackStarted;
  64. HANDLE hEventDeviceOpened;
  65. HANDLE hEventDeviceClosed;
  66. HANDLE hEventDeviceStopped;
  67. CRITICAL_SECTION critSectionStop;
  68. #endif
  69. UINT nLastError;
  70. int cBufsPending;
  71. } WAVIN, FAR *LPWAVIN;
  72. // helper functions
  73. //
  74. LRESULT DLLEXPORT CALLBACK WavInCallback(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
  75. #ifdef MULTITHREAD
  76. DWORD WINAPI WavInCallbackThread(LPVOID lpvThreadParameter);
  77. #endif
  78. static LPWAVIN WavInGetPtr(HWAVIN hWavIn);
  79. static HWAVIN WavInGetHandle(LPWAVIN lpWavIn);
  80. #ifdef MULTITHREAD
  81. static LRESULT SendThreadMessage(DWORD dwThreadId, UINT Msg, LPARAM lParam);
  82. #endif
  83. ////
  84. // public functions
  85. ////
  86. // WavInGetDeviceCount - return number of wav input devices found
  87. // <void> this function takes no arguments
  88. // return number of wav input devices found (0 if none)
  89. //
  90. int DLLEXPORT WINAPI WavInGetDeviceCount(void)
  91. {
  92. return waveInGetNumDevs();
  93. }
  94. // WavInDeviceIsOpen - check if input device is open
  95. // <idDev> (i) device id
  96. // -1 open any suitable input device
  97. // return TRUE if open
  98. //
  99. BOOL DLLEXPORT WINAPI WavInDeviceIsOpen(int idDev)
  100. {
  101. BOOL fSuccess = TRUE;
  102. BOOL fIsOpen = FALSE;
  103. WAVEFORMATEX wfx;
  104. HWAVEIN hWaveIn = NULL;
  105. int nLastError;
  106. #ifdef TELIN
  107. if (idDev == TELIN_DEVICEID)
  108. return TelInDeviceIsOpen(idDev);
  109. #endif
  110. // try to open device
  111. //
  112. if ((nLastError = waveInOpen(&hWaveIn, idDev,
  113. #ifndef _WIN32
  114. (LPWAVEFORMAT)
  115. #endif
  116. WavFormatPcm(-1, -1, -1, &wfx),
  117. 0, 0, 0)) != 0)
  118. {
  119. if (nLastError == MMSYSERR_ALLOCATED)
  120. fIsOpen = TRUE; // device in use
  121. else
  122. {
  123. fSuccess = TraceFALSE(NULL);
  124. TracePrintf_1(NULL, 5,
  125. TEXT("waveInOpen failed (%u)\n"),
  126. (unsigned) nLastError);
  127. }
  128. }
  129. // close device
  130. //
  131. else if (waveInClose(hWaveIn) != 0)
  132. fSuccess = TraceFALSE(NULL);
  133. return fSuccess ? fIsOpen : FALSE;
  134. }
  135. // WavInOpen - open wav input device
  136. // <dwVersion> (i) must be WAVIN_VERSION
  137. // <hInst> (i) instance handle of calling module
  138. // <idDev> (i) device id
  139. // -1 open any suitable input device
  140. // <lpwfx> (i) wave format
  141. // <hwndNotify> (i) notify this window of device events
  142. // NULL do not notify
  143. // <msTimeoutOpen> (i) device open timeout in milleseconds
  144. // 0 default timeout (30000)
  145. // <msTimeoutRetry> (i) device retry timeout in milleseconds
  146. // 0 default timeout (2000)
  147. // <dwFlags> (i) control flags
  148. // WAVIN_NOSYNC do not open synchronous devices
  149. // WAVIN_OPENRETRY retry if device busy
  150. // WAVIN_OPENASYNC return before notification of device open
  151. // WAVIN_CLOSEASYNC return before notification of device close
  152. // WAVIN_NOACM do not use audio compression manager
  153. // WAVIN_TELRFILE telephone will record audio to file on server
  154. #ifdef MULTITHREAD
  155. // WAVIN_MULTITHREAD support multiple threads
  156. #endif
  157. // return handle (NULL if error)
  158. //
  159. // NOTE: if <hwndNotify> is specified in WavInOpen,
  160. // WM_WAVIN_OPEN will be sent to <hwndNotify>,
  161. // when input device has been opened.
  162. //
  163. // NOTE: if WAVIN_MULTITHREAD is specified in <dwFlags>,
  164. // it is assumed that <hwndNotify> is not a window handle,
  165. // but rather the id of the thread to receive notifications
  166. //
  167. HWAVIN DLLEXPORT WINAPI WavInOpen(DWORD dwVersion, HINSTANCE hInst,
  168. int idDev, LPWAVEFORMATEX lpwfx, HWND hwndNotify,
  169. DWORD msTimeoutOpen, DWORD msTimeoutRetry, DWORD dwFlags)
  170. {
  171. BOOL fSuccess = TRUE;
  172. LPWAVIN lpWavIn = NULL;
  173. WNDCLASS wc;
  174. #ifdef TELIN
  175. if (idDev == TELIN_DEVICEID)
  176. {
  177. hTelIn = TelInOpen(TELIN_VERSION, hInst, idDev, lpwfx,
  178. hwndNotify, msTimeoutOpen, msTimeoutRetry, dwFlags);
  179. return (HWAVIN) hTelIn;
  180. }
  181. #endif
  182. if (dwVersion != WAVIN_VERSION)
  183. fSuccess = TraceFALSE(NULL);
  184. else if (hInst == NULL)
  185. fSuccess = TraceFALSE(NULL);
  186. else if ((lpWavIn = (LPWAVIN) MemAlloc(NULL, sizeof(WAVIN), 0)) == NULL)
  187. fSuccess = TraceFALSE(NULL);
  188. else
  189. {
  190. lpWavIn->dwVersion = dwVersion;
  191. lpWavIn->hInst = hInst;
  192. lpWavIn->hTask = GetCurrentTask();
  193. lpWavIn->idDev = (UINT) idDev;
  194. lpWavIn->lpwfx = NULL;
  195. lpWavIn->hwndNotify = hwndNotify;
  196. lpWavIn->dwFlags = dwFlags;
  197. lpWavIn->fIsOpen = FALSE;
  198. lpWavIn->hWaveIn = NULL;
  199. lpWavIn->wState = WAVIN_STOPPED;
  200. lpWavIn->hwndCallback = NULL;
  201. #ifdef MULTITHREAD
  202. lpWavIn->hThreadCallback = NULL;
  203. lpWavIn->dwThreadId = 0;
  204. lpWavIn->hEventThreadCallbackStarted = NULL;
  205. lpWavIn->hEventDeviceOpened = NULL;
  206. lpWavIn->hEventDeviceClosed = NULL;
  207. lpWavIn->hEventDeviceStopped = NULL;
  208. #endif
  209. lpWavIn->nLastError = 0;
  210. lpWavIn->cBufsPending = 0;
  211. // memory is allocated such that the client app owns it
  212. //
  213. if ((lpWavIn->lpwfx = WavFormatDup(lpwfx)) == NULL)
  214. fSuccess = TraceFALSE(NULL);
  215. }
  216. #ifdef MULTITHREAD
  217. // handle WAVIN_MULTITHREAD flag
  218. //
  219. if (fSuccess && (lpWavIn->dwFlags & WAVIN_MULTITHREAD))
  220. {
  221. DWORD dwRet;
  222. InitializeCriticalSection(&(lpWavIn->critSectionStop));
  223. // we need to know when device has been opened
  224. //
  225. if ((lpWavIn->hEventDeviceOpened = CreateEvent(
  226. NULL, FALSE, FALSE, NULL)) == NULL)
  227. {
  228. fSuccess = TraceFALSE(NULL);
  229. }
  230. // we need to know when callback thread begins execution
  231. //
  232. else if ((lpWavIn->hEventThreadCallbackStarted = CreateEvent(
  233. NULL, FALSE, FALSE, NULL)) == NULL)
  234. {
  235. fSuccess = TraceFALSE(NULL);
  236. }
  237. // create the callback thread
  238. //
  239. else if ((lpWavIn->hThreadCallback = CreateThread(
  240. NULL,
  241. 0,
  242. WavInCallbackThread,
  243. (LPVOID) lpWavIn,
  244. 0,
  245. &lpWavIn->dwThreadId)) == NULL)
  246. {
  247. fSuccess = TraceFALSE(NULL);
  248. }
  249. // wait for the callback thread to begin execution
  250. //
  251. else if ((dwRet = WaitForSingleObject(
  252. lpWavIn->hEventThreadCallbackStarted, 10000)) != WAIT_OBJECT_0)
  253. {
  254. fSuccess = TraceFALSE(NULL);
  255. }
  256. // clean up
  257. //
  258. if (lpWavIn->hEventThreadCallbackStarted != NULL)
  259. {
  260. if (!CloseHandle(lpWavIn->hEventThreadCallbackStarted))
  261. fSuccess = TraceFALSE(NULL);
  262. else
  263. lpWavIn->hEventThreadCallbackStarted = NULL;
  264. }
  265. }
  266. else
  267. #endif
  268. {
  269. // register callback class unless it has been already
  270. //
  271. if (fSuccess && GetClassInfo(lpWavIn->hInst, WAVINCLASS, &wc) == 0)
  272. {
  273. wc.hCursor = NULL;
  274. wc.hIcon = NULL;
  275. wc.lpszMenuName = NULL;
  276. wc.hInstance = lpWavIn->hInst;
  277. wc.lpszClassName = WAVINCLASS;
  278. wc.hbrBackground = NULL;
  279. wc.lpfnWndProc = WavInCallback;
  280. wc.style = 0L;
  281. wc.cbWndExtra = sizeof(lpWavIn);
  282. wc.cbClsExtra = 0;
  283. if (!RegisterClass(&wc))
  284. fSuccess = TraceFALSE(NULL);
  285. }
  286. // create the callback window
  287. //
  288. if (fSuccess && (lpWavIn->hwndCallback = CreateWindowEx(
  289. 0L,
  290. WAVINCLASS,
  291. NULL,
  292. 0L,
  293. 0, 0, 0, 0,
  294. NULL,
  295. NULL,
  296. lpWavIn->hInst,
  297. lpWavIn)) == NULL)
  298. {
  299. fSuccess = TraceFALSE(NULL);
  300. }
  301. }
  302. if (fSuccess)
  303. {
  304. DWORD dwTimeout = SysGetTimerCount() +
  305. (msTimeoutRetry == 0 ? 2000L : msTimeoutRetry);
  306. DWORD dwCallback;
  307. DWORD dwFlags;
  308. #ifdef MULTITHREAD
  309. if (lpWavIn->dwFlags & WAVIN_MULTITHREAD)
  310. {
  311. dwCallback = lpWavIn->dwThreadId;
  312. dwFlags = CALLBACK_THREAD;
  313. }
  314. else
  315. #endif
  316. {
  317. dwCallback = HandleToUlong(lpWavIn->hwndCallback);
  318. dwFlags = CALLBACK_WINDOW;
  319. }
  320. // allow synchronous device drivers unless WAVIN_NOSYNC specified
  321. //
  322. if (!(lpWavIn->dwFlags & WAVIN_NOSYNC))
  323. dwFlags |= WAVE_ALLOWSYNC;
  324. // open the device
  325. //
  326. while (fSuccess && (lpWavIn->nLastError = waveInOpen(&lpWavIn->hWaveIn,
  327. (UINT) lpWavIn->idDev,
  328. #ifndef _WIN32
  329. (LPWAVEFORMAT)
  330. #endif
  331. lpWavIn->lpwfx, dwCallback, (DWORD) 0, dwFlags)) != 0)
  332. {
  333. // no need to retry unless the device is busy
  334. //
  335. if (lpWavIn->nLastError != MMSYSERR_ALLOCATED)
  336. {
  337. fSuccess = TraceFALSE(NULL);
  338. TracePrintf_1(NULL, 5,
  339. TEXT("waveInOpen failed (%u)\n"),
  340. (unsigned) lpWavIn->nLastError);
  341. }
  342. // no need to retry if flag not set
  343. //
  344. else if (!(lpWavIn->dwFlags & WAVIN_OPENRETRY))
  345. fSuccess = TraceFALSE(NULL);
  346. // no more retries if timeout occurred
  347. //
  348. else if (SysGetTimerCount() >= dwTimeout)
  349. fSuccess = TraceFALSE(NULL);
  350. else
  351. {
  352. MSG msg;
  353. if (PeekMessage(&msg, lpWavIn->hwndCallback, 0, 0, PM_REMOVE))
  354. {
  355. TranslateMessage(&msg);
  356. DispatchMessage(&msg);
  357. }
  358. else
  359. #ifdef _WIN32
  360. Sleep(100);
  361. #else
  362. WaitMessage();
  363. #endif
  364. }
  365. }
  366. }
  367. // make sure a handle was returned
  368. //
  369. if (fSuccess && lpWavIn->hWaveIn == NULL)
  370. fSuccess = TraceFALSE(NULL);
  371. // wait for device open notification or timeout
  372. //
  373. if (fSuccess && !(lpWavIn->dwFlags & WAVIN_OPENASYNC))
  374. {
  375. DWORD dwTimeout = SysGetTimerCount() +
  376. (msTimeoutOpen == 0 ? 2000L : msTimeoutOpen);
  377. #ifdef MULTITHREAD
  378. if (lpWavIn->dwFlags & WAVIN_MULTITHREAD)
  379. {
  380. DWORD dwRet;
  381. // wait for the device top be opened
  382. //
  383. if ((dwRet = WaitForSingleObject(
  384. lpWavIn->hEventDeviceOpened,
  385. (msTimeoutOpen == 0 ? 30000L : msTimeoutOpen))) != WAIT_OBJECT_0)
  386. {
  387. fSuccess = TraceFALSE(NULL);
  388. }
  389. }
  390. else
  391. #endif
  392. while (fSuccess && !lpWavIn->fIsOpen)
  393. {
  394. MSG msg;
  395. if (SysGetTimerCount() >= dwTimeout)
  396. fSuccess = TraceFALSE(NULL);
  397. else if (PeekMessage(&msg, lpWavIn->hwndCallback, 0, 0, PM_REMOVE))
  398. {
  399. TranslateMessage(&msg);
  400. DispatchMessage(&msg);
  401. }
  402. else
  403. WaitMessage();
  404. }
  405. }
  406. #ifdef MULTITHREAD
  407. // clean up
  408. //
  409. if (lpWavIn != NULL && lpWavIn->hEventDeviceOpened != NULL)
  410. {
  411. if (!CloseHandle(lpWavIn->hEventDeviceOpened))
  412. fSuccess = TraceFALSE(NULL);
  413. else
  414. lpWavIn->hEventDeviceOpened = NULL;
  415. }
  416. if (lpWavIn != NULL && lpWavIn->hThreadCallback != NULL)
  417. {
  418. if (!CloseHandle(lpWavIn->hThreadCallback))
  419. fSuccess = TraceFALSE(NULL);
  420. else
  421. lpWavIn->hThreadCallback = NULL;
  422. }
  423. #endif
  424. if (fSuccess)
  425. {
  426. if ((lpWavIn->nLastError = waveInGetID(lpWavIn->hWaveIn,
  427. &lpWavIn->idDev)) != 0)
  428. {
  429. fSuccess = TraceFALSE(NULL);
  430. TracePrintf_1(NULL, 5,
  431. TEXT("waveInGetID failed (%u)\n"),
  432. (unsigned) lpWavIn->nLastError);
  433. }
  434. }
  435. if (!fSuccess)
  436. {
  437. WavInClose(WavInGetHandle(lpWavIn), 0);
  438. lpWavIn = NULL;
  439. }
  440. return fSuccess ? WavInGetHandle(lpWavIn) : NULL;
  441. }
  442. // WavInClose - close wav input device
  443. // <hWavIn> (i) handle returned from WavInOpen
  444. // <msTimeoutClose> (i) device close timeout in milleseconds
  445. // 0 default timeout (30000)
  446. // return 0 if success
  447. //
  448. // NOTE: if <hwndNotify> was specified in WavInOpen,
  449. // WM_WAVIN_CLOSE will be sent to <hwndNotify>,
  450. // when input device has been closed.
  451. //
  452. int DLLEXPORT WINAPI WavInClose(HWAVIN hWavIn, DWORD msTimeoutClose)
  453. {
  454. BOOL fSuccess = TRUE;
  455. LPWAVIN lpWavIn;
  456. #ifdef TELIN
  457. if (hWavIn != NULL && hWavIn == (HWAVIN) hTelIn)
  458. {
  459. int iRet = TelInClose((HTELIN) hWavIn, msTimeoutClose);
  460. hTelIn = NULL;
  461. return iRet;
  462. }
  463. #endif
  464. if ((lpWavIn = WavInGetPtr(hWavIn)) == NULL)
  465. fSuccess = TraceFALSE(NULL);
  466. // stop the device
  467. //
  468. else if (WavInStop(hWavIn, 0) != 0)
  469. fSuccess = TraceFALSE(NULL);
  470. #ifdef MULTITHREAD
  471. // we need to know when device has been closed
  472. //
  473. else if ((lpWavIn->dwFlags & WAVIN_MULTITHREAD) &&
  474. (lpWavIn->hEventDeviceClosed = CreateEvent(
  475. NULL, FALSE, FALSE, NULL)) == NULL)
  476. {
  477. fSuccess = TraceFALSE(NULL);
  478. }
  479. #endif
  480. // close the device
  481. //
  482. else if (lpWavIn->hWaveIn != NULL &&
  483. (lpWavIn->nLastError = waveInClose(lpWavIn->hWaveIn)) != 0)
  484. {
  485. fSuccess = TraceFALSE(NULL);
  486. TracePrintf_1(NULL, 5,
  487. TEXT("wavInClose failed (%u)\n"),
  488. (unsigned) lpWavIn->nLastError);
  489. }
  490. // wait for device close notification or timeout
  491. //
  492. if (fSuccess && !(lpWavIn->dwFlags & WAVIN_CLOSEASYNC))
  493. {
  494. DWORD dwTimeout = SysGetTimerCount() +
  495. (msTimeoutClose == 0 ? 30000L : msTimeoutClose);
  496. #ifdef MULTITHREAD
  497. if (lpWavIn->dwFlags & WAVIN_MULTITHREAD)
  498. {
  499. DWORD dwRet;
  500. // wait for the device to be closed
  501. //
  502. if ((dwRet = WaitForSingleObject(
  503. lpWavIn->hEventDeviceClosed,
  504. (msTimeoutClose == 0 ? 30000L : msTimeoutClose))) != WAIT_OBJECT_0)
  505. {
  506. fSuccess = TraceFALSE(NULL);
  507. }
  508. }
  509. else
  510. #endif
  511. while (fSuccess && lpWavIn->fIsOpen)
  512. {
  513. MSG msg;
  514. if (SysGetTimerCount() >= dwTimeout)
  515. fSuccess = TraceFALSE(NULL);
  516. else if (PeekMessage(&msg, lpWavIn->hwndCallback, 0, 0, PM_REMOVE))
  517. {
  518. TranslateMessage(&msg);
  519. DispatchMessage(&msg);
  520. }
  521. else
  522. WaitMessage();
  523. }
  524. }
  525. #ifdef MULTITHREAD
  526. // clean up
  527. //
  528. if (lpWavIn != NULL && lpWavIn->hEventDeviceClosed != NULL)
  529. {
  530. if (!CloseHandle(lpWavIn->hEventDeviceClosed))
  531. fSuccess = TraceFALSE(NULL);
  532. else
  533. lpWavIn->hEventDeviceClosed = NULL;
  534. }
  535. #endif
  536. if (fSuccess)
  537. {
  538. #ifdef MULTITHREAD
  539. if (lpWavIn->dwFlags & WAVIN_MULTITHREAD)
  540. {
  541. while (lpWavIn->critSectionStop.OwningThread != NULL)
  542. Sleep(100L);
  543. DeleteCriticalSection(&(lpWavIn->critSectionStop));
  544. }
  545. #endif
  546. // device handle is no longer valid
  547. //
  548. lpWavIn->hWaveIn = NULL;
  549. // destroy callback window
  550. //
  551. if (lpWavIn->hwndCallback != NULL &&
  552. !DestroyWindow(lpWavIn->hwndCallback))
  553. fSuccess = TraceFALSE(NULL);
  554. else if (lpWavIn->hwndCallback = NULL, FALSE)
  555. fSuccess = TraceFALSE(NULL);
  556. else if (lpWavIn->lpwfx != NULL &&
  557. WavFormatFree(lpWavIn->lpwfx) != 0)
  558. fSuccess = TraceFALSE(NULL);
  559. else if (lpWavIn->lpwfx = NULL, FALSE)
  560. fSuccess = TraceFALSE(NULL);
  561. else if ((lpWavIn = MemFree(NULL, lpWavIn)) != NULL)
  562. fSuccess = TraceFALSE(NULL);
  563. }
  564. return fSuccess ? 0 : -1;
  565. }
  566. // WavInRecord - submit buffer of samples to wav input device for recording
  567. // <hWavIn> (i) handle returned from WavInOpen
  568. // <lpBuf> (o) pointer to buffer to be filled with samples
  569. // <sizBuf> (i) size of buffer in bytes
  570. // return 0 if success
  571. //
  572. // NOTE: the buffer pointed to by <lpBuf> must have been allocated
  573. // using MemAlloc().
  574. //
  575. // NOTE: if <hwndNotify> is specified in WavInOpen(), a WM_WAVIN_RECORDDONE
  576. // message will be sent to <hwndNotify>, with <lParam> set to a pointer to
  577. // a RECORDDONE structure, when <lpBuf> has been recorded.
  578. //
  579. int DLLEXPORT WINAPI WavInRecord(HWAVIN hWavIn, LPVOID lpBuf, long sizBuf)
  580. {
  581. BOOL fSuccess = TRUE;
  582. LPWAVIN lpWavIn;
  583. LPWAVEHDR lpWaveHdr = NULL;
  584. #ifdef TELIN
  585. if (hWavIn != NULL && hWavIn == (HWAVIN) hTelIn)
  586. return TelInRecord((HTELIN) hWavIn, lpBuf, sizBuf, -1);
  587. #endif
  588. if ((lpWavIn = WavInGetPtr(hWavIn)) == NULL)
  589. fSuccess = TraceFALSE(NULL);
  590. else if (lpBuf == NULL)
  591. fSuccess = TraceFALSE(NULL);
  592. else if ((lpWaveHdr = (LPWAVEHDR) MemAlloc(NULL,
  593. sizeof(WAVEHDR), 0)) == NULL)
  594. {
  595. fSuccess = TraceFALSE(NULL);
  596. }
  597. else
  598. {
  599. lpWaveHdr->lpData = (LPSTR) lpBuf;
  600. lpWaveHdr->dwBufferLength = (DWORD) sizBuf;
  601. if ((lpWavIn->nLastError = waveInPrepareHeader(lpWavIn->hWaveIn,
  602. lpWaveHdr, sizeof(WAVEHDR))) != 0)
  603. {
  604. fSuccess = TraceFALSE(NULL);
  605. TracePrintf_1(NULL, 5,
  606. TEXT("waveInPrepareHeader failed (%u)\n"),
  607. (unsigned) lpWavIn->nLastError);
  608. }
  609. else if ((lpWavIn->nLastError = waveInAddBuffer(lpWavIn->hWaveIn,
  610. lpWaveHdr, sizeof(WAVEHDR))) != 0)
  611. {
  612. fSuccess = TraceFALSE(NULL);
  613. TracePrintf_1(NULL, 5,
  614. TEXT("waveInAddBuffer failed (%u)\n"),
  615. (unsigned) lpWavIn->nLastError);
  616. }
  617. else if ((lpWavIn->nLastError = waveInStart(lpWavIn->hWaveIn)) != 0)
  618. {
  619. fSuccess = TraceFALSE(NULL);
  620. TracePrintf_1(NULL, 5,
  621. TEXT("waveInStart failed (%u)\n"),
  622. (unsigned) lpWavIn->nLastError);
  623. }
  624. else
  625. {
  626. ++lpWavIn->cBufsPending;
  627. lpWavIn->wState = WAVIN_RECORDING;
  628. }
  629. }
  630. return fSuccess ? 0 : -1;
  631. }
  632. // WavInStop - stop recording into buffer(s) sent to wav input device
  633. // <hWavIn> (i) handle returned from WavInOpen
  634. // <msTimeoutStop> (i) device stop timeout in milleseconds
  635. // 0 default timeout (2000)
  636. // return 0 if success
  637. //
  638. int DLLEXPORT WINAPI WavInStop(HWAVIN hWavIn, DWORD msTimeoutStop)
  639. {
  640. BOOL fSuccess = TRUE;
  641. LPWAVIN lpWavIn;
  642. #ifdef TELIN
  643. if (hWavIn != NULL && hWavIn == (HWAVIN) hTelIn)
  644. return TelInStop((HTELIN) hWavIn, msTimeoutStop);
  645. #endif
  646. if ((lpWavIn = WavInGetPtr(hWavIn)) == NULL)
  647. fSuccess = TraceFALSE(NULL);
  648. #ifdef MULTITHREAD
  649. else if ((lpWavIn->dwFlags & WAVIN_MULTITHREAD) &&
  650. (EnterCriticalSection(&(lpWavIn->critSectionStop)), FALSE))
  651. ;
  652. #endif
  653. // make sure device is recording
  654. //
  655. else if (WavInGetState(hWavIn) == WAVIN_STOPPED)
  656. ; // not an error to call this function when already stopped
  657. else if (lpWavIn->wState = WAVIN_STOPPING, FALSE)
  658. ;
  659. #ifdef MULTITHREAD
  660. // we need to know when device has been stopped
  661. //
  662. else if ((lpWavIn->dwFlags & WAVIN_MULTITHREAD) &&
  663. (lpWavIn->hEventDeviceStopped = CreateEvent(
  664. NULL, FALSE, FALSE, NULL)) == NULL)
  665. {
  666. fSuccess = TraceFALSE(NULL);
  667. }
  668. #endif
  669. // stop the device
  670. //
  671. else if ((lpWavIn->nLastError = waveInReset(lpWavIn->hWaveIn)) != 0)
  672. {
  673. fSuccess = TraceFALSE(NULL);
  674. TracePrintf_1(NULL, 5,
  675. TEXT("waveInReset failed (%u)\n"),
  676. (unsigned) lpWavIn->nLastError);
  677. }
  678. // wait for all pending buffers to complete
  679. //
  680. #ifdef MULTITHREAD
  681. else if (lpWavIn->dwFlags & WAVIN_MULTITHREAD)
  682. {
  683. DWORD dwRet;
  684. LeaveCriticalSection(&(lpWavIn->critSectionStop));
  685. // wait for the device to be stopped
  686. //
  687. if ((dwRet = WaitForSingleObject(
  688. lpWavIn->hEventDeviceStopped,
  689. (msTimeoutStop == 0 ? 10000L : msTimeoutStop))) != WAIT_OBJECT_0)
  690. {
  691. fSuccess = TraceFALSE(NULL);
  692. }
  693. EnterCriticalSection(&(lpWavIn->critSectionStop));
  694. }
  695. #endif
  696. else
  697. {
  698. DWORD dwTimeout = SysGetTimerCount() +
  699. (msTimeoutStop == 0 ? 2000L : msTimeoutStop);
  700. while (fSuccess && lpWavIn->cBufsPending > 0)
  701. {
  702. MSG msg;
  703. // check for timeout
  704. //
  705. if (SysGetTimerCount() >= dwTimeout)
  706. fSuccess = TraceFALSE(NULL);
  707. else if (PeekMessage(&msg, lpWavIn->hwndCallback, 0, 0, PM_REMOVE))
  708. {
  709. TranslateMessage(&msg);
  710. DispatchMessage(&msg);
  711. }
  712. else
  713. WaitMessage();
  714. }
  715. }
  716. #ifdef MULTITHREAD
  717. // clean up
  718. //
  719. if (lpWavIn != NULL && lpWavIn->hEventDeviceStopped != NULL)
  720. {
  721. if (!CloseHandle(lpWavIn->hEventDeviceStopped))
  722. fSuccess = TraceFALSE(NULL);
  723. else
  724. lpWavIn->hEventDeviceStopped = NULL;
  725. }
  726. if (lpWavIn != NULL && (lpWavIn->dwFlags & WAVIN_MULTITHREAD))
  727. LeaveCriticalSection(&(lpWavIn->critSectionStop));
  728. #endif
  729. return fSuccess ? 0 : -1;
  730. }
  731. // WavInGetState - return current wav input device state
  732. // <hWavIn> (i) handle returned from WavInOpen
  733. // return WAVIN_STOPPED, WAVIN_RECORDING, or 0 if error
  734. //
  735. WORD DLLEXPORT WINAPI WavInGetState(HWAVIN hWavIn)
  736. {
  737. BOOL fSuccess = TRUE;
  738. LPWAVIN lpWavIn;
  739. #ifdef TELIN
  740. if (hWavIn != NULL && hWavIn == (HWAVIN) hTelIn)
  741. return TelInGetState((HTELIN) hWavIn);
  742. #endif
  743. if ((lpWavIn = WavInGetPtr(hWavIn)) == NULL)
  744. fSuccess = TraceFALSE(NULL);
  745. return fSuccess ? lpWavIn->wState : 0;
  746. }
  747. // WavInGetPosition - get milleseconds of elapsed recording
  748. // <hWavIn> (i) handle returned from WavInOpen
  749. // return 0 if success
  750. //
  751. long DLLEXPORT WINAPI WavInGetPosition(HWAVIN hWavIn)
  752. {
  753. BOOL fSuccess = TRUE;
  754. LPWAVIN lpWavIn;
  755. MMTIME mmtime;
  756. long msPosition;
  757. #ifdef TELIN
  758. if (hWavIn != NULL && hWavIn == (HWAVIN) hTelIn)
  759. return TelInGetPosition((HTELIN) hWavIn);
  760. #endif
  761. MemSet(&mmtime, 0, sizeof(mmtime));
  762. // we will be requesting position in millesconds
  763. //
  764. mmtime.wType = TIME_MS;
  765. if ((lpWavIn = WavInGetPtr(hWavIn)) == NULL)
  766. fSuccess = TraceFALSE(NULL);
  767. // get device position
  768. //
  769. else if ((lpWavIn->nLastError = waveInGetPosition(
  770. lpWavIn->hWaveIn, &mmtime, sizeof(MMTIME))) != 0)
  771. {
  772. fSuccess = TraceFALSE(NULL);
  773. TracePrintf_1(NULL, 5,
  774. TEXT("waveInGetPosition failed (%u)\n"),
  775. (unsigned) lpWavIn->nLastError);
  776. }
  777. // see what type of position was returned
  778. //
  779. else switch (mmtime.wType)
  780. {
  781. case TIME_MS:
  782. {
  783. // we got milleseconds; no conversion required
  784. //
  785. msPosition = (long) mmtime.u.ms;
  786. }
  787. break;
  788. case TIME_SAMPLES:
  789. {
  790. // convert samples to millesconds
  791. //
  792. msPosition = (long) MULDIVU32(mmtime.u.sample,
  793. 1000L, lpWavIn->lpwfx->nSamplesPerSec);
  794. }
  795. break;
  796. case TIME_BYTES:
  797. {
  798. // convert bytes to millesconds
  799. //
  800. msPosition = (long) MULDIVU32(mmtime.u.cb,
  801. 1000L, lpWavIn->lpwfx->nAvgBytesPerSec);
  802. }
  803. break;
  804. case TIME_SMPTE:
  805. case TIME_MIDI:
  806. default:
  807. fSuccess = TraceFALSE(NULL);
  808. break;
  809. }
  810. return fSuccess ? msPosition : -1;
  811. }
  812. // WavInGetId - return id of wav input device
  813. // <hWavIn> (i) handle returned from WavInOpen
  814. // return device id (-1 if error)
  815. //
  816. int DLLEXPORT WINAPI WavInGetId(HWAVIN hWavIn)
  817. {
  818. BOOL fSuccess = TRUE;
  819. LPWAVIN lpWavIn;
  820. #ifdef TELIN
  821. if (hWavIn != NULL && hWavIn == (HWAVIN) hTelIn)
  822. return TelInGetId((HTELIN) hWavIn);
  823. #endif
  824. if ((lpWavIn = WavInGetPtr(hWavIn)) == NULL)
  825. fSuccess = TraceFALSE(NULL);
  826. return fSuccess ? lpWavIn->idDev : -1;
  827. }
  828. // WavInGetName - get name of wav input device
  829. // <hWavIn> (i) handle returned from WavInOpen
  830. // NULL use unopened device specified in <idDev>
  831. // <idDev> (i) device id (ignored if <hWavIn> is not NULL)
  832. // -1 any suitable input device
  833. // <lpszName> (o) buffer to hold device name
  834. // <sizName> (i) size of buffer
  835. // return 0 if success
  836. //
  837. int DLLEXPORT WINAPI WavInGetName(HWAVIN hWavIn, int idDev, LPTSTR lpszName, int sizName)
  838. {
  839. BOOL fSuccess = TRUE;
  840. LPWAVIN lpWavIn;
  841. #ifdef TELIN
  842. if (idDev == TELIN_DEVICEID || (hWavIn != NULL && hWavIn == (HWAVIN) hTelIn))
  843. return TelInGetName((HTELIN) hWavIn, idDev, lpszName, sizName);
  844. #endif
  845. if (hWavIn != NULL)
  846. {
  847. if ((lpWavIn = WavInGetPtr(hWavIn)) == NULL)
  848. fSuccess = TraceFALSE(NULL);
  849. else
  850. idDev = lpWavIn->idDev;
  851. }
  852. if (fSuccess)
  853. {
  854. WAVEINCAPS wic;
  855. UINT nLastError;
  856. if ((nLastError = waveInGetDevCaps(idDev, &wic, sizeof(WAVEINCAPS))) != 0)
  857. {
  858. fSuccess = TraceFALSE(NULL);
  859. TracePrintf_1(NULL, 5,
  860. TEXT("waveInGetDevCaps failed (%u)\n"),
  861. (unsigned) nLastError);
  862. }
  863. else if (lpszName != NULL)
  864. StrNCpy(lpszName, wic.szPname, sizName);
  865. if (hWavIn != NULL && lpWavIn != NULL)
  866. lpWavIn->nLastError = nLastError;
  867. }
  868. return fSuccess ? 0 : -1;
  869. }
  870. // WavInGetIdByName - get id of wav input device, lookup by name
  871. // <lpszName> (i) device name
  872. #ifdef _WIN32
  873. // NULL or TEXT("") get preferred device id
  874. #endif
  875. // <dwFlags> (i) reserved; must be zero
  876. // return device id (-1 if error)
  877. //
  878. int WINAPI WavInGetIdByName(LPCTSTR lpszName, DWORD dwFlags)
  879. {
  880. UINT idDev;
  881. UINT cDev = (UINT) WavInGetDeviceCount();
  882. // If no device specified, get the preferred device
  883. if ( !lpszName || (_tcslen(lpszName) <= 0) )
  884. {
  885. DWORD dwTemp;
  886. DWORD dwRet = waveInMessage( (HWAVEIN)(DWORD_PTR)WAVE_MAPPER, DRVM_MAPPER_PREFERRED_GET, (DWORD_PTR) &idDev, (DWORD_PTR) &dwTemp );
  887. if ( dwRet == MMSYSERR_NOERROR )
  888. return idDev;
  889. }
  890. else
  891. {
  892. // Device specified, search by name
  893. for ( idDev = 0; idDev < cDev; ++idDev )
  894. {
  895. TCHAR szName[256];
  896. if ( WavInGetName(NULL, idDev, szName, SIZEOFARRAY(szName)) == 0 )
  897. {
  898. if ( _tcsicmp(lpszName, szName) == 0 )
  899. return idDev;
  900. }
  901. }
  902. }
  903. // No match for device name
  904. TraceFALSE(NULL);
  905. return -1;
  906. }
  907. // WavInSupportsFormat - return TRUE if device supports specified format
  908. // <hWavIn> (i) handle returned from WavInOpen
  909. // NULL use unopened device specified in <idDev>
  910. // <idDev> (i) device id (ignored if <hWavIn> is not NULL)
  911. // -1 any suitable input device
  912. // <lpwfx> (i) wave format
  913. // return TRUE if device supports specified format
  914. //
  915. BOOL DLLEXPORT WINAPI WavInSupportsFormat(HWAVIN hWavIn, int idDev,
  916. LPWAVEFORMATEX lpwfx)
  917. {
  918. BOOL fSuccess = TRUE;
  919. LPWAVIN lpWavIn;
  920. BOOL fSupportsFormat;
  921. #ifdef TELIN
  922. if (idDev == TELIN_DEVICEID || (hWavIn != NULL && hWavIn == (HWAVIN) hTelIn))
  923. return TelInSupportsFormat((HTELIN) hWavIn, idDev, lpwfx);
  924. #endif
  925. if (hWavIn != NULL)
  926. {
  927. if ((lpWavIn = WavInGetPtr(hWavIn)) == NULL)
  928. fSuccess = TraceFALSE(NULL);
  929. else
  930. idDev = lpWavIn->idDev;
  931. }
  932. if (fSuccess)
  933. {
  934. UINT nLastError;
  935. // query the device
  936. //
  937. if ((nLastError = waveInOpen(NULL, (UINT) idDev,
  938. #ifndef _WIN32
  939. (LPWAVEFORMAT)
  940. #endif
  941. lpwfx, 0, 0,
  942. WAVE_FORMAT_QUERY)) != 0)
  943. {
  944. fSupportsFormat = FALSE;
  945. #if 1
  946. if (TraceGetLevel(NULL) >= 9)
  947. {
  948. TracePrintf_0(NULL, 9,
  949. TEXT("unsupported format:\n"));
  950. WavFormatDump(lpwfx);
  951. }
  952. #endif
  953. if (nLastError != WAVERR_BADFORMAT)
  954. {
  955. fSuccess = TraceFALSE(NULL);
  956. TracePrintf_1(NULL, 5,
  957. TEXT("waveInOpen/FormatQuery failed (%u)\n"),
  958. (unsigned) nLastError);
  959. }
  960. }
  961. else
  962. fSupportsFormat = TRUE;
  963. if (hWavIn != NULL && lpWavIn != NULL)
  964. lpWavIn->nLastError = nLastError;
  965. }
  966. return fSuccess ? fSupportsFormat : FALSE;
  967. }
  968. // WavInFormatSuggest - suggest a new format which the device supports
  969. // <hWavIn> (i) handle returned from WavInOpen
  970. // NULL use unopened device specified in <idDev>
  971. // <idDev> (i) device id (ignored if <hWavIn> is not NULL)
  972. // -1 any suitable input device
  973. // <lpwfxSrc> (i) source format
  974. // <dwFlags> (i) control flags
  975. // WAVIN_NOACM do not use audio compression manager
  976. // return pointer to suggested format, NULL if error
  977. //
  978. // NOTE: the format structure returned is dynamically allocated.
  979. // Use WavFormatFree() to free the buffer.
  980. //
  981. LPWAVEFORMATEX DLLEXPORT WINAPI WavInFormatSuggest(
  982. HWAVIN hWavIn, int idDev, LPWAVEFORMATEX lpwfxSrc, DWORD dwFlags)
  983. {
  984. BOOL fSuccess = TRUE;
  985. LPWAVIN lpWavIn;
  986. LPWAVEFORMATEX lpwfxSuggest = NULL;
  987. LPWAVEFORMATEX lpwfxTemp = NULL;
  988. HACM hAcm = NULL;
  989. #ifdef TELIN
  990. if (idDev == TELIN_DEVICEID || (hWavIn != NULL && hWavIn == (HWAVIN) hTelIn))
  991. return TelInFormatSuggest((HTELIN) hWavIn, idDev, lpwfxSrc, dwFlags);
  992. #endif
  993. if (hWavIn != NULL)
  994. {
  995. if ((lpWavIn = WavInGetPtr(hWavIn)) == NULL)
  996. fSuccess = TraceFALSE(NULL);
  997. else
  998. {
  999. idDev = lpWavIn->idDev;
  1000. if (lpWavIn->dwFlags & WAVIN_NOACM)
  1001. dwFlags |= WAVIN_NOACM;
  1002. }
  1003. }
  1004. if ((hAcm = AcmInit(ACM_VERSION, SysGetTaskInstance(NULL),
  1005. (dwFlags & WAVIN_NOACM) ? ACM_NOACM : 0)) == NULL)
  1006. fSuccess = TraceFALSE(NULL);
  1007. else if (!WavFormatIsValid(lpwfxSrc))
  1008. fSuccess = TraceFALSE(NULL);
  1009. else if ((lpwfxTemp = WavFormatDup(lpwfxSrc)) == NULL)
  1010. fSuccess = TraceFALSE(NULL);
  1011. // get suggested format, see if it is supported
  1012. //
  1013. if (fSuccess && lpwfxSuggest == NULL)
  1014. {
  1015. if ((lpwfxSuggest = AcmFormatSuggest(hAcm, lpwfxTemp,
  1016. -1, -1, -1, -1, 0)) == NULL)
  1017. fSuccess = TraceFALSE(NULL);
  1018. else if (WavFormatFree(lpwfxTemp) != 0)
  1019. fSuccess = TraceFALSE(NULL);
  1020. else if (!WavInSupportsFormat(NULL, idDev, lpwfxSuggest))
  1021. {
  1022. lpwfxTemp = lpwfxSuggest;
  1023. lpwfxSuggest = NULL;
  1024. }
  1025. }
  1026. // get suggested PCM format, see if it is supported
  1027. //
  1028. if (fSuccess && lpwfxSuggest == NULL &&
  1029. lpwfxTemp->wFormatTag != WAVE_FORMAT_PCM)
  1030. {
  1031. if ((lpwfxSuggest = AcmFormatSuggest(hAcm, lpwfxTemp,
  1032. WAVE_FORMAT_PCM, -1, -1, -1, 0)) == NULL)
  1033. fSuccess = TraceFALSE(NULL);
  1034. else if (WavFormatFree(lpwfxTemp) != 0)
  1035. fSuccess = TraceFALSE(NULL);
  1036. else if (!WavInSupportsFormat(NULL, idDev, lpwfxSuggest))
  1037. {
  1038. lpwfxTemp = lpwfxSuggest;
  1039. lpwfxSuggest = NULL;
  1040. }
  1041. }
  1042. // get suggested PCM mono format, see if it is supported
  1043. //
  1044. if (fSuccess && lpwfxSuggest == NULL &&
  1045. lpwfxTemp->nChannels != 1)
  1046. {
  1047. if ((lpwfxSuggest = AcmFormatSuggest(hAcm, lpwfxTemp,
  1048. WAVE_FORMAT_PCM, -1, -1, 1, 0)) == NULL)
  1049. fSuccess = TraceFALSE(NULL);
  1050. else if (WavFormatFree(lpwfxTemp) != 0)
  1051. fSuccess = TraceFALSE(NULL);
  1052. else if (!WavInSupportsFormat(NULL, idDev, lpwfxSuggest))
  1053. {
  1054. lpwfxTemp = lpwfxSuggest;
  1055. lpwfxSuggest = NULL;
  1056. }
  1057. }
  1058. // get suggested PCM 8-bit mono format, see if it is supported
  1059. //
  1060. if (fSuccess && lpwfxSuggest == NULL &&
  1061. lpwfxTemp->wBitsPerSample != 8)
  1062. {
  1063. if ((lpwfxSuggest = AcmFormatSuggest(hAcm, lpwfxTemp,
  1064. WAVE_FORMAT_PCM, -1, 8, 1, 0)) == NULL)
  1065. fSuccess = TraceFALSE(NULL);
  1066. else if (WavFormatFree(lpwfxTemp) != 0)
  1067. fSuccess = TraceFALSE(NULL);
  1068. else if (!WavInSupportsFormat(NULL, idDev, lpwfxSuggest))
  1069. {
  1070. lpwfxTemp = lpwfxSuggest;
  1071. lpwfxSuggest = NULL;
  1072. }
  1073. }
  1074. // get suggested PCM 11025Hz 8-bit mono format, see if it is supported
  1075. //
  1076. if (fSuccess && lpwfxSuggest == NULL &&
  1077. lpwfxTemp->nSamplesPerSec != 11025)
  1078. {
  1079. if ((lpwfxSuggest = AcmFormatSuggest(hAcm, lpwfxTemp,
  1080. WAVE_FORMAT_PCM, 11025, 8, 1, 0)) == NULL)
  1081. fSuccess = TraceFALSE(NULL);
  1082. else if (WavFormatFree(lpwfxTemp) != 0)
  1083. fSuccess = TraceFALSE(NULL);
  1084. else if (!WavInSupportsFormat(NULL, idDev, lpwfxSuggest))
  1085. {
  1086. lpwfxTemp = lpwfxSuggest;
  1087. lpwfxSuggest = NULL;
  1088. }
  1089. }
  1090. // last resort; see if MULAW 8000Hz 8-bit mono format is supported
  1091. //
  1092. if (fSuccess && lpwfxSuggest == NULL)
  1093. {
  1094. #if 0
  1095. if ((lpwfxSuggest = AcmFormatSuggest(hAcm, lpwfxTemp,
  1096. WAVE_FORMAT_MULAW, 8000, 8, 1, 0)) == NULL)
  1097. #else
  1098. if ((lpwfxSuggest = WavFormatMulaw(NULL, 8000)) == NULL)
  1099. #endif
  1100. fSuccess = TraceFALSE(NULL);
  1101. else if (WavFormatFree(lpwfxTemp) != 0)
  1102. fSuccess = TraceFALSE(NULL);
  1103. else if (!WavInSupportsFormat(NULL, idDev, lpwfxSuggest))
  1104. {
  1105. // no more chances for success
  1106. //
  1107. fSuccess = TraceFALSE(NULL);
  1108. if (WavFormatFree(lpwfxSuggest) != 0)
  1109. fSuccess = TraceFALSE(NULL);
  1110. }
  1111. }
  1112. // clean up
  1113. //
  1114. if (hAcm != NULL && AcmTerm(hAcm) != 0)
  1115. fSuccess = TraceFALSE(NULL);
  1116. else
  1117. hAcm = NULL;
  1118. return fSuccess ? lpwfxSuggest : NULL;
  1119. }
  1120. // WavInTerm - shut down wav input residuals, if any
  1121. // <hInst> (i) instance handle of calling module
  1122. // <dwFlags> (i) control flags
  1123. // WAV_TELTHUNK terminate telephone thunking layer
  1124. // return 0 if success
  1125. //
  1126. int DLLEXPORT WINAPI WavInTerm(HINSTANCE hInst, DWORD dwFlags)
  1127. {
  1128. BOOL fSuccess = TRUE;
  1129. if (hInst == NULL)
  1130. fSuccess = TraceFALSE(NULL);
  1131. #ifdef TELIN
  1132. else if ((dwFlags & WAV_TELTHUNK) &&
  1133. TelInTerm(hInst, dwFlags) != 0)
  1134. fSuccess = TraceFALSE(NULL);
  1135. #endif
  1136. return fSuccess ? 0 : -1;
  1137. }
  1138. ////
  1139. // helper functions
  1140. ////
  1141. #ifdef MULTITHREAD
  1142. DWORD WINAPI WavInCallbackThread(LPVOID lpvThreadParameter)
  1143. {
  1144. BOOL fSuccess = TRUE;
  1145. MSG msg;
  1146. LPWAVIN lpWavIn = (LPWAVIN) lpvThreadParameter;
  1147. // make sure message queue is created before calling SetEvent
  1148. //
  1149. PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE);
  1150. // notify main thread that callback thread has begun execution
  1151. //
  1152. if (!SetEvent(lpWavIn->hEventThreadCallbackStarted))
  1153. {
  1154. fSuccess = TraceFALSE(NULL);
  1155. }
  1156. while (fSuccess && GetMessage(&msg, NULL, 0, 0))
  1157. {
  1158. WavInCallback((HWND) lpWavIn, msg.message, msg.wParam, msg.lParam);
  1159. // exit thread when when have processed last expected message
  1160. //
  1161. if (msg.message == MM_WIM_CLOSE)
  1162. break;
  1163. }
  1164. return 0;
  1165. }
  1166. #endif
  1167. // WavInCallback - window procedure for wavin callback
  1168. //
  1169. LRESULT DLLEXPORT CALLBACK WavInCallback(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
  1170. {
  1171. BOOL fSuccess = TRUE;
  1172. LRESULT lResult;
  1173. LPWAVIN lpWavIn;
  1174. #ifdef MULTITHREAD
  1175. if (!IsWindow(hwnd))
  1176. lpWavIn = (LPWAVIN) hwnd;
  1177. else
  1178. #endif
  1179. // retrieve lpWavIn from window extra bytes
  1180. //
  1181. lpWavIn = (LPWAVIN) GetWindowLongPtr(hwnd, 0);
  1182. switch (msg)
  1183. {
  1184. case WM_NCCREATE:
  1185. {
  1186. LPCREATESTRUCT lpcs = (LPCREATESTRUCT) lParam;
  1187. LPWAVIN lpWavIn = (LPWAVIN) lpcs->lpCreateParams;
  1188. // store lpWavIn in window extra bytes
  1189. //
  1190. SetWindowLongPtr(hwnd, 0, (LONG_PTR) lpWavIn);
  1191. lResult = DefWindowProc(hwnd, msg, wParam, lParam);
  1192. }
  1193. break;
  1194. case MM_WIM_OPEN:
  1195. {
  1196. HWAVEIN hWaveIn = (HWAVEIN) wParam;
  1197. TraceOutput(NULL, 5,
  1198. TEXT("MM_WIM_OPEN\n"));
  1199. #ifdef MULTITHREAD
  1200. if (!(lpWavIn->dwFlags & WAVIN_MULTITHREAD) &&
  1201. hWaveIn != lpWavIn->hWaveIn)
  1202. #else
  1203. if (hWaveIn != lpWavIn->hWaveIn)
  1204. #endif
  1205. fSuccess = TraceFALSE(NULL);
  1206. else
  1207. {
  1208. lpWavIn->fIsOpen = TRUE;
  1209. #ifdef MULTITHREAD
  1210. // notify main thread that device is open
  1211. //
  1212. if ((lpWavIn->dwFlags & WAVIN_MULTITHREAD) &&
  1213. !SetEvent(lpWavIn->hEventDeviceOpened))
  1214. {
  1215. fSuccess = TraceFALSE(NULL);
  1216. }
  1217. #endif
  1218. // send notification of device opening
  1219. //
  1220. #ifdef MULTITHREAD
  1221. if (lpWavIn->dwFlags & WAVIN_MULTITHREAD)
  1222. {
  1223. if ( lpWavIn->hwndNotify )
  1224. PostThreadMessage( HandleToUlong(lpWavIn->hwndNotify), WM_WAVIN_OPEN, 0, 0);
  1225. }
  1226. else
  1227. #endif
  1228. {
  1229. if (lpWavIn->hwndNotify != NULL &&
  1230. IsWindow(lpWavIn->hwndNotify))
  1231. {
  1232. SendMessage(lpWavIn->hwndNotify, WM_WAVIN_OPEN, 0, 0);
  1233. }
  1234. }
  1235. }
  1236. lResult = 0L;
  1237. }
  1238. break;
  1239. case MM_WIM_CLOSE:
  1240. {
  1241. HWAVEIN hWaveIn = (HWAVEIN) wParam;
  1242. TraceOutput(NULL, 5,
  1243. TEXT("MM_WIM_CLOSE\n"));
  1244. #ifdef MULTITHREAD
  1245. if (!(lpWavIn->dwFlags & WAVIN_MULTITHREAD) &&
  1246. hWaveIn != lpWavIn->hWaveIn)
  1247. #else
  1248. if (hWaveIn != lpWavIn->hWaveIn)
  1249. #endif
  1250. fSuccess = TraceFALSE(NULL);
  1251. else
  1252. {
  1253. lpWavIn->fIsOpen = FALSE;
  1254. // send notification of device closure
  1255. //
  1256. #ifdef MULTITHREAD
  1257. if (lpWavIn->dwFlags & WAVIN_MULTITHREAD)
  1258. {
  1259. if ( lpWavIn->hwndNotify )
  1260. PostThreadMessage(HandleToUlong(lpWavIn->hwndNotify), WM_WAVIN_CLOSE, 0, 0);
  1261. }
  1262. else
  1263. #endif
  1264. {
  1265. if (lpWavIn->hwndNotify != NULL &&
  1266. IsWindow(lpWavIn->hwndNotify))
  1267. {
  1268. SendMessage(lpWavIn->hwndNotify, WM_WAVIN_CLOSE, 0, 0);
  1269. }
  1270. }
  1271. #ifdef MULTITHREAD
  1272. // notify main thread that device is closed
  1273. //
  1274. if ((lpWavIn->dwFlags & WAVIN_MULTITHREAD) &&
  1275. !SetEvent(lpWavIn->hEventDeviceClosed))
  1276. {
  1277. fSuccess = TraceFALSE(NULL);
  1278. }
  1279. #endif
  1280. }
  1281. lResult = 0L;
  1282. }
  1283. break;
  1284. case MM_WIM_DATA:
  1285. {
  1286. HWAVEIN hWaveIn = (HWAVEIN) wParam;
  1287. LPWAVEHDR lpWaveHdr = (LPWAVEHDR) lParam;
  1288. LPVOID lpBuf;
  1289. long sizBuf;
  1290. long lBytesRecorded;
  1291. TracePrintf_1(NULL, 5,
  1292. TEXT("MM_WIM_DATA (%lu)\n"),
  1293. (unsigned long) lpWaveHdr->dwBytesRecorded);
  1294. #ifdef MULTITHREAD
  1295. if (lpWavIn->dwFlags & WAVIN_MULTITHREAD)
  1296. EnterCriticalSection(&(lpWavIn->critSectionStop));
  1297. #endif
  1298. #ifdef MULTITHREAD
  1299. if (!(lpWavIn->dwFlags & WAVIN_MULTITHREAD) &&
  1300. hWaveIn != lpWavIn->hWaveIn)
  1301. #else
  1302. if (hWaveIn != lpWavIn->hWaveIn)
  1303. #endif
  1304. fSuccess = TraceFALSE(NULL);
  1305. else if (lpWaveHdr == NULL)
  1306. fSuccess = TraceFALSE(NULL);
  1307. // NULL buffer is possible with telephone, this is ok
  1308. //
  1309. else if ((lpBuf = (LPVOID) lpWaveHdr->lpData) == NULL, FALSE)
  1310. ;
  1311. else if (sizBuf = (long) lpWaveHdr->dwBufferLength, FALSE)
  1312. fSuccess = TraceFALSE(NULL);
  1313. else if (lBytesRecorded = (long) lpWaveHdr->dwBytesRecorded, FALSE)
  1314. fSuccess = TraceFALSE(NULL);
  1315. else if (!(lpWaveHdr->dwFlags & WHDR_DONE))
  1316. fSuccess = TraceFALSE(NULL);
  1317. else if (!(lpWaveHdr->dwFlags & WHDR_PREPARED))
  1318. fSuccess = TraceFALSE(NULL);
  1319. else if ((lpWavIn->nLastError = waveInUnprepareHeader(
  1320. lpWavIn->hWaveIn, lpWaveHdr, sizeof(WAVEHDR))) != 0)
  1321. {
  1322. fSuccess = TraceFALSE(NULL);
  1323. TracePrintf_1(NULL, 5,
  1324. TEXT("waveInUnprepareHeader failed (%u)\n"),
  1325. (unsigned) lpWavIn->nLastError);
  1326. }
  1327. else if ((lpWaveHdr = MemFree(NULL, lpWaveHdr)) != NULL)
  1328. fSuccess = TraceFALSE(NULL);
  1329. else if (--lpWavIn->cBufsPending < 0)
  1330. fSuccess = TraceFALSE(NULL);
  1331. // device is no longer recording if no more buffers pending
  1332. //
  1333. else if (lpWavIn->cBufsPending == 0)
  1334. {
  1335. lpWavIn->wState = WAVIN_STOPPED;
  1336. #ifdef MULTITHREAD
  1337. // notify main thread that device is stopped
  1338. //
  1339. if ((lpWavIn->dwFlags & WAVIN_MULTITHREAD) &&
  1340. lpWavIn->hEventDeviceStopped != NULL &&
  1341. !SetEvent(lpWavIn->hEventDeviceStopped))
  1342. {
  1343. fSuccess = TraceFALSE(NULL);
  1344. }
  1345. #endif
  1346. }
  1347. if (fSuccess)
  1348. {
  1349. RECORDDONE recorddone;
  1350. recorddone.lpBuf = lpBuf;
  1351. recorddone.sizBuf = sizBuf;
  1352. recorddone.lBytesRecorded = lBytesRecorded;
  1353. // send notification of recording completion
  1354. //
  1355. #ifdef MULTITHREAD
  1356. if (lpWavIn->dwFlags & WAVIN_MULTITHREAD)
  1357. {
  1358. if ( lpWavIn->hwndNotify )
  1359. {
  1360. SendThreadMessage(HandleToUlong(lpWavIn->hwndNotify),
  1361. WM_WAVIN_RECORDDONE, (LPARAM) (LPVOID) &recorddone);
  1362. }
  1363. }
  1364. else
  1365. #endif
  1366. {
  1367. if (lpWavIn->hwndNotify != NULL &&
  1368. IsWindow(lpWavIn->hwndNotify))
  1369. {
  1370. SendMessage(lpWavIn->hwndNotify,
  1371. WM_WAVIN_RECORDDONE, 0, (LPARAM) (LPVOID) &recorddone);
  1372. }
  1373. }
  1374. }
  1375. lResult = 0L;
  1376. #ifdef MULTITHREAD
  1377. if (lpWavIn->dwFlags & WAVIN_MULTITHREAD)
  1378. LeaveCriticalSection(&(lpWavIn->critSectionStop));
  1379. #endif
  1380. }
  1381. break;
  1382. default:
  1383. lResult = DefWindowProc(hwnd, msg, wParam, lParam);
  1384. break;
  1385. }
  1386. return lResult;
  1387. }
  1388. // WavInGetPtr - verify that wavin handle is valid,
  1389. // <hWavIn> (i) handle returned from WavInInit
  1390. // return corresponding wavin pointer (NULL if error)
  1391. //
  1392. static LPWAVIN WavInGetPtr(HWAVIN hWavIn)
  1393. {
  1394. BOOL fSuccess = TRUE;
  1395. LPWAVIN lpWavIn;
  1396. if ((lpWavIn = (LPWAVIN) hWavIn) == NULL)
  1397. fSuccess = TraceFALSE(NULL);
  1398. else if (IsBadWritePtr(lpWavIn, sizeof(WAVIN)))
  1399. fSuccess = TraceFALSE(NULL);
  1400. #ifdef CHECKTASK
  1401. // make sure current task owns the wavin handle
  1402. //
  1403. else if (lpWavIn->hTask != GetCurrentTask())
  1404. fSuccess = TraceFALSE(NULL);
  1405. #endif
  1406. return fSuccess ? lpWavIn : NULL;
  1407. }
  1408. // WavInGetHandle - verify that wavin pointer is valid,
  1409. // <lpWavIn> (i) pointer to WAVIN struct
  1410. // return corresponding wavin handle (NULL if error)
  1411. //
  1412. static HWAVIN WavInGetHandle(LPWAVIN lpWavIn)
  1413. {
  1414. BOOL fSuccess = TRUE;
  1415. HWAVIN hWavIn;
  1416. if ((hWavIn = (HWAVIN) lpWavIn) == NULL)
  1417. fSuccess = TraceFALSE(NULL);
  1418. return fSuccess ? hWavIn : NULL;
  1419. }
  1420. #ifdef MULTITHREAD
  1421. static LRESULT SendThreadMessage(DWORD dwThreadId, UINT Msg, LPARAM lParam)
  1422. {
  1423. BOOL fSuccess = TRUE;
  1424. HANDLE hEventMessageProcessed = NULL;
  1425. DWORD dwRet;
  1426. // we need to know when message has been processed
  1427. //
  1428. if ((hEventMessageProcessed = CreateEvent(
  1429. NULL, FALSE, FALSE, NULL)) == NULL)
  1430. {
  1431. fSuccess = TraceFALSE(NULL);
  1432. }
  1433. // post message to thread, send event handle as wParam
  1434. //
  1435. else if (!PostThreadMessage(dwThreadId, Msg, (WPARAM) hEventMessageProcessed, lParam))
  1436. {
  1437. fSuccess = TraceFALSE(NULL);
  1438. }
  1439. // wait for the message to be processed
  1440. //
  1441. else if ((dwRet = WaitForSingleObject(
  1442. hEventMessageProcessed, INFINITE)) != WAIT_OBJECT_0)
  1443. {
  1444. fSuccess = TraceFALSE(NULL);
  1445. }
  1446. // clean up
  1447. //
  1448. if (hEventMessageProcessed != NULL)
  1449. {
  1450. if (!CloseHandle(hEventMessageProcessed))
  1451. fSuccess = TraceFALSE(NULL);
  1452. else
  1453. hEventMessageProcessed = NULL;
  1454. }
  1455. return 0L;
  1456. }
  1457. #endif