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.

2259 lines
55 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. // wavout.c - wav output device functions
  24. ////
  25. #include "winlocal.h"
  26. #include "wavout.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 output functions if defined
  36. //
  37. #ifdef TELOUT
  38. #include "telout.h"
  39. static HTELOUT hTelOut = NULL;
  40. #endif
  41. ////
  42. // private definitions
  43. ////
  44. #define WAVOUTCLASS TEXT("WavOutClass")
  45. // wavout control struct
  46. //
  47. typedef struct WAVOUT
  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. HWAVEOUT hWaveOut;
  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. } WAVOUT, FAR *LPWAVOUT;
  72. #define VOLUME_MINLEVEL 0
  73. #define VOLUME_MAXLEVEL 100
  74. #define VOLUME_POSITIONS (VOLUME_MAXLEVEL - VOLUME_MINLEVEL)
  75. // helper functions
  76. //
  77. LRESULT DLLEXPORT CALLBACK WavOutCallback(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
  78. #ifdef MULTITHREAD
  79. DWORD WINAPI WavOutCallbackThread(LPVOID lpvThreadParameter);
  80. #endif
  81. static LPWAVOUT WavOutGetPtr(HWAVOUT hWavOut);
  82. static HWAVOUT WavOutGetHandle(LPWAVOUT lpWavOut);
  83. #ifdef MULTITHREAD
  84. static LRESULT SendThreadMessage(DWORD dwThreadId, UINT Msg, LPARAM lParam);
  85. #endif
  86. ////
  87. // public functions
  88. ////
  89. // WavOutGetDeviceCount - return number of wav output devices found
  90. // <void> this function takes no arguments
  91. // return number of wav output devices found (0 if none)
  92. //
  93. int DLLEXPORT WINAPI WavOutGetDeviceCount(void)
  94. {
  95. return waveOutGetNumDevs();
  96. }
  97. // WavOutDeviceIsOpen - check if output device is open
  98. // <idDev> (i) device id
  99. // -1 open any suitable output device
  100. // return TRUE if open
  101. //
  102. BOOL DLLEXPORT WINAPI WavOutDeviceIsOpen(int idDev)
  103. {
  104. BOOL fSuccess = TRUE;
  105. BOOL fIsOpen = FALSE;
  106. WAVEFORMATEX wfx;
  107. HWAVEOUT hWaveOut = NULL;
  108. int nLastError;
  109. #ifdef TELOUT
  110. if (idDev == TELOUT_DEVICEID)
  111. return TelOutDeviceIsOpen(idDev);
  112. #endif
  113. // try to open device
  114. //
  115. if ((nLastError = waveOutOpen(&hWaveOut, idDev,
  116. #ifndef _WIN32
  117. (LPWAVEFORMAT)
  118. #endif
  119. WavFormatPcm(-1, -1, -1, &wfx),
  120. 0, 0, WAVE_ALLOWSYNC)) != 0)
  121. {
  122. if (nLastError == MMSYSERR_ALLOCATED)
  123. fIsOpen = TRUE; // device in use
  124. else
  125. {
  126. fSuccess = TraceFALSE(NULL);
  127. TracePrintf_1(NULL, 5,
  128. TEXT("waveOutOpen failed (%u)\n"),
  129. (unsigned) nLastError);
  130. }
  131. }
  132. // close device
  133. //
  134. else if (waveOutClose(hWaveOut) != 0)
  135. fSuccess = TraceFALSE(NULL);
  136. return fSuccess ? fIsOpen : FALSE;
  137. }
  138. // WavOutOpen - open wav output device
  139. // <dwVersion> (i) must be WAVOUT_VERSION
  140. // <hInst> (i) instance handle of calling module
  141. // <idDev> (i) device id
  142. // -1 open any suitable output device
  143. // <lpwfx> (i) wave format
  144. // <hwndNotify> (i) notify this window of device events
  145. // NULL do not notify
  146. // <msTimeoutOpen> (i) device open timeout in milleseconds
  147. // 0 default timeout (30000)
  148. // <msTimeoutRetry> (i) device retry timeout in milleseconds
  149. // 0 default timeout (2000)
  150. // <dwFlags> (i) control flags
  151. // WAVOUT_NOSYNC do not open synchronous devices
  152. // WAVOUT_AUTOFREE free each buffer after playback
  153. // WAVOUT_OPENRETRY retry if device busy
  154. // WAVOUT_OPENASYNC return before notification of device open
  155. // WAVOUT_CLOSEASYNC return before notification of device close
  156. // WAVOUT_NOACM do not use audio compression manager
  157. // WAVOUT_TELRFILE telephone will play/record audio on server
  158. #ifdef MULTITHREAD
  159. // WAVOUT_MULTITHREAD support multiple threads
  160. #endif
  161. // return handle (NULL if error)
  162. //
  163. // NOTE: if <hwndNotify> is specified in WavOutOpen,
  164. // WM_WAVOUT_OPEN will be sent to <hwndNotify>,
  165. // when output device has been opened.
  166. //
  167. // NOTE: if WAVOUT_MULTITHREAD is specified in <dwFlags>,
  168. // it is assumed that <hwndNotify> is not a window handle,
  169. // but rather the id of the thread to receive notifications
  170. //
  171. HWAVOUT DLLEXPORT WINAPI WavOutOpen(DWORD dwVersion, HINSTANCE hInst,
  172. int idDev, LPWAVEFORMATEX lpwfx, HWND hwndNotify,
  173. DWORD msTimeoutOpen, DWORD msTimeoutRetry, DWORD dwFlags)
  174. {
  175. BOOL fSuccess = TRUE;
  176. LPWAVOUT lpWavOut = NULL;
  177. WNDCLASS wc;
  178. #ifdef TELOUT
  179. if (idDev == TELOUT_DEVICEID)
  180. {
  181. hTelOut = TelOutOpen(TELOUT_VERSION, hInst, idDev, lpwfx,
  182. hwndNotify, msTimeoutOpen, msTimeoutRetry, dwFlags);
  183. return (HWAVOUT) hTelOut;
  184. }
  185. #endif
  186. if (dwVersion != WAVOUT_VERSION)
  187. fSuccess = TraceFALSE(NULL);
  188. else if (hInst == NULL)
  189. fSuccess = TraceFALSE(NULL);
  190. else if ((lpWavOut = (LPWAVOUT) MemAlloc(NULL, sizeof(WAVOUT), 0)) == NULL)
  191. fSuccess = TraceFALSE(NULL);
  192. else
  193. {
  194. lpWavOut->dwVersion = dwVersion;
  195. lpWavOut->hInst = hInst;
  196. lpWavOut->hTask = GetCurrentTask();
  197. lpWavOut->idDev = (UINT) idDev;
  198. lpWavOut->lpwfx = NULL;
  199. lpWavOut->hwndNotify = hwndNotify;
  200. lpWavOut->dwFlags = dwFlags;
  201. lpWavOut->fIsOpen = FALSE;
  202. lpWavOut->hWaveOut = NULL;
  203. lpWavOut->wState = WAVOUT_STOPPED;
  204. lpWavOut->hwndCallback = NULL;
  205. #ifdef MULTITHREAD
  206. lpWavOut->hThreadCallback = NULL;
  207. lpWavOut->dwThreadId = 0;
  208. lpWavOut->hEventThreadCallbackStarted = NULL;
  209. lpWavOut->hEventDeviceOpened = NULL;
  210. lpWavOut->hEventDeviceClosed = NULL;
  211. lpWavOut->hEventDeviceStopped = NULL;
  212. #endif
  213. lpWavOut->nLastError = 0;
  214. lpWavOut->cBufsPending = 0;
  215. // memory is allocated such that the client app owns it
  216. //
  217. if ((lpWavOut->lpwfx = WavFormatDup(lpwfx)) == NULL)
  218. fSuccess = TraceFALSE(NULL);
  219. }
  220. #ifdef MULTITHREAD
  221. // handle WAVOUT_MULTITHREAD flag
  222. //
  223. if (fSuccess && (lpWavOut->dwFlags & WAVOUT_MULTITHREAD))
  224. {
  225. DWORD dwRet;
  226. InitializeCriticalSection(&(lpWavOut->critSectionStop));
  227. // we need to know when device has been opened
  228. //
  229. if ((lpWavOut->hEventDeviceOpened = CreateEvent(
  230. NULL, FALSE, FALSE, NULL)) == NULL)
  231. {
  232. fSuccess = TraceFALSE(NULL);
  233. }
  234. // we need to know when callback thread begins execution
  235. //
  236. else if ((lpWavOut->hEventThreadCallbackStarted = CreateEvent(
  237. NULL, FALSE, FALSE, NULL)) == NULL)
  238. {
  239. fSuccess = TraceFALSE(NULL);
  240. }
  241. // create the callback thread
  242. //
  243. else if ((lpWavOut->hThreadCallback = CreateThread(
  244. NULL,
  245. 0,
  246. WavOutCallbackThread,
  247. (LPVOID) lpWavOut,
  248. 0,
  249. &lpWavOut->dwThreadId)) == NULL)
  250. {
  251. fSuccess = TraceFALSE(NULL);
  252. }
  253. // wait for the callback thread to begin execution
  254. //
  255. else if ((dwRet = WaitForSingleObject(
  256. lpWavOut->hEventThreadCallbackStarted, 10000)) != WAIT_OBJECT_0)
  257. {
  258. fSuccess = TraceFALSE(NULL);
  259. }
  260. // clean up
  261. //
  262. if (lpWavOut->hEventThreadCallbackStarted != NULL)
  263. {
  264. if (!CloseHandle(lpWavOut->hEventThreadCallbackStarted))
  265. fSuccess = TraceFALSE(NULL);
  266. else
  267. lpWavOut->hEventThreadCallbackStarted = NULL;
  268. }
  269. }
  270. else
  271. #endif
  272. {
  273. // register callback class unless it has been already
  274. //
  275. if (fSuccess && GetClassInfo(lpWavOut->hInst, WAVOUTCLASS, &wc) == 0)
  276. {
  277. wc.hCursor = NULL;
  278. wc.hIcon = NULL;
  279. wc.lpszMenuName = NULL;
  280. wc.hInstance = lpWavOut->hInst;
  281. wc.lpszClassName = WAVOUTCLASS;
  282. wc.hbrBackground = NULL;
  283. wc.lpfnWndProc = WavOutCallback;
  284. wc.style = 0L;
  285. wc.cbWndExtra = sizeof(lpWavOut);
  286. wc.cbClsExtra = 0;
  287. if (!RegisterClass(&wc))
  288. fSuccess = TraceFALSE(NULL);
  289. }
  290. // create the callback window
  291. //
  292. if (fSuccess && (lpWavOut->hwndCallback = CreateWindowEx(
  293. 0L,
  294. WAVOUTCLASS,
  295. NULL,
  296. 0L,
  297. 0, 0, 0, 0,
  298. NULL,
  299. NULL,
  300. lpWavOut->hInst,
  301. lpWavOut)) == NULL)
  302. {
  303. fSuccess = TraceFALSE(NULL);
  304. }
  305. }
  306. if (fSuccess)
  307. {
  308. DWORD dwTimeout = SysGetTimerCount() +
  309. (msTimeoutRetry == 0 ? 2000L : msTimeoutRetry);
  310. DWORD dwCallback;
  311. DWORD dwFlags;
  312. #ifdef MULTITHREAD
  313. if (lpWavOut->dwFlags & WAVOUT_MULTITHREAD)
  314. {
  315. dwCallback = lpWavOut->dwThreadId;
  316. dwFlags = CALLBACK_THREAD;
  317. }
  318. else
  319. #endif
  320. {
  321. dwCallback = HandleToUlong(lpWavOut->hwndCallback);
  322. dwFlags = CALLBACK_WINDOW;
  323. }
  324. // allow synchronous device drivers unless WAVOUT_NOSYNC specified
  325. //
  326. if (!(lpWavOut->dwFlags & WAVOUT_NOSYNC))
  327. dwFlags |= WAVE_ALLOWSYNC;
  328. // open the device
  329. //
  330. while (fSuccess && (lpWavOut->nLastError = waveOutOpen(&lpWavOut->hWaveOut,
  331. (UINT) lpWavOut->idDev,
  332. #ifndef _WIN32
  333. (LPWAVEFORMAT)
  334. #endif
  335. lpWavOut->lpwfx, dwCallback, 0, dwFlags)) != 0)
  336. {
  337. // no need to retry unless the device is busy
  338. //
  339. if (lpWavOut->nLastError != MMSYSERR_ALLOCATED)
  340. {
  341. fSuccess = TraceFALSE(NULL);
  342. TracePrintf_1(NULL, 5,
  343. TEXT("waveOutOpen failed (%u)\n"),
  344. (unsigned) lpWavOut->nLastError);
  345. }
  346. // no need to retry if flag not set
  347. //
  348. else if (!(lpWavOut->dwFlags & WAVOUT_OPENRETRY))
  349. fSuccess = TraceFALSE(NULL);
  350. // no more retries if timeout occurred
  351. //
  352. else if (SysGetTimerCount() >= dwTimeout)
  353. fSuccess = TraceFALSE(NULL);
  354. else
  355. {
  356. MSG msg;
  357. if (PeekMessage(&msg, lpWavOut->hwndCallback, 0, 0, PM_REMOVE))
  358. {
  359. TranslateMessage(&msg);
  360. DispatchMessage(&msg);
  361. }
  362. else
  363. #ifdef _WIN32
  364. Sleep(100);
  365. #else
  366. WaitMessage();
  367. #endif
  368. }
  369. }
  370. }
  371. // make sure a handle was returned
  372. //
  373. if (fSuccess && lpWavOut->hWaveOut == NULL)
  374. fSuccess = TraceFALSE(NULL);
  375. // wait for device open notification or timeout
  376. //
  377. if (fSuccess && !(lpWavOut->dwFlags & WAVOUT_OPENASYNC))
  378. {
  379. DWORD dwTimeout = SysGetTimerCount() +
  380. (msTimeoutOpen == 0 ? 2000L : msTimeoutOpen);
  381. #ifdef MULTITHREAD
  382. if (lpWavOut->dwFlags & WAVOUT_MULTITHREAD)
  383. {
  384. DWORD dwRet;
  385. // wait for the device to be opened
  386. //
  387. if ((dwRet = WaitForSingleObject(
  388. lpWavOut->hEventDeviceOpened,
  389. (msTimeoutOpen == 0 ? 30000L : msTimeoutOpen))) != WAIT_OBJECT_0)
  390. {
  391. fSuccess = TraceFALSE(NULL);
  392. }
  393. }
  394. else
  395. #endif
  396. while (fSuccess && !lpWavOut->fIsOpen)
  397. {
  398. MSG msg;
  399. if (SysGetTimerCount() >= dwTimeout)
  400. fSuccess = TraceFALSE(NULL);
  401. else if (PeekMessage(&msg, lpWavOut->hwndCallback, 0, 0, PM_REMOVE))
  402. {
  403. TranslateMessage(&msg);
  404. DispatchMessage(&msg);
  405. }
  406. else
  407. WaitMessage();
  408. }
  409. }
  410. #ifdef MULTITHREAD
  411. // clean up
  412. //
  413. if (lpWavOut != NULL && lpWavOut->hEventDeviceOpened != NULL)
  414. {
  415. if (!CloseHandle(lpWavOut->hEventDeviceOpened))
  416. fSuccess = TraceFALSE(NULL);
  417. else
  418. lpWavOut->hEventDeviceOpened = NULL;
  419. }
  420. #endif
  421. if (fSuccess)
  422. {
  423. if ((lpWavOut->nLastError = waveOutGetID(lpWavOut->hWaveOut,
  424. &lpWavOut->idDev)) != 0)
  425. {
  426. fSuccess = TraceFALSE(NULL);
  427. TracePrintf_1(NULL, 5,
  428. TEXT("waveOutGetID failed (%u)\n"),
  429. (unsigned) lpWavOut->nLastError);
  430. }
  431. }
  432. if (!fSuccess)
  433. {
  434. WavOutClose(WavOutGetHandle(lpWavOut), 0);
  435. lpWavOut = NULL;
  436. }
  437. return fSuccess ? WavOutGetHandle(lpWavOut) : NULL;
  438. }
  439. // WavOutClose - close wav output device
  440. // <hWavOut> (i) handle returned from WavOutOpen
  441. // <msTimeoutClose> (i) device close timeout in milleseconds
  442. // 0 default timeout (30000)
  443. // return 0 if success
  444. //
  445. // NOTE: if <hwndNotify> was specified in WavOutOpen,
  446. // WM_WAVOUT_CLOSE will be sent to <hwndNotify>,
  447. // when output device has been closed.
  448. //
  449. int DLLEXPORT WINAPI WavOutClose(HWAVOUT hWavOut, DWORD msTimeoutClose)
  450. {
  451. BOOL fSuccess = TRUE;
  452. LPWAVOUT lpWavOut;
  453. #ifdef TELOUT
  454. if (hWavOut != NULL && hWavOut == (HWAVOUT) hTelOut)
  455. {
  456. int iRet = TelOutClose((HTELOUT) hWavOut, msTimeoutClose);
  457. hTelOut = NULL;
  458. return iRet;
  459. }
  460. #endif
  461. if ((lpWavOut = WavOutGetPtr(hWavOut)) == NULL)
  462. fSuccess = TraceFALSE(NULL);
  463. // stop the device
  464. //
  465. else if (WavOutStop(hWavOut, 0) != 0)
  466. fSuccess = TraceFALSE(NULL);
  467. #ifdef MULTITHREAD
  468. // we need to know when device has been closed
  469. //
  470. else if ((lpWavOut->dwFlags & WAVOUT_MULTITHREAD) &&
  471. (lpWavOut->hEventDeviceClosed = CreateEvent(
  472. NULL, FALSE, FALSE, NULL)) == NULL)
  473. {
  474. fSuccess = TraceFALSE(NULL);
  475. }
  476. #endif
  477. // close the device
  478. //
  479. else if (lpWavOut->hWaveOut != NULL &&
  480. (lpWavOut->nLastError = waveOutClose(lpWavOut->hWaveOut)) != 0)
  481. {
  482. fSuccess = TraceFALSE(NULL);
  483. TracePrintf_1(NULL, 5,
  484. TEXT("wavOutClose failed (%u)\n"),
  485. (unsigned) lpWavOut->nLastError);
  486. }
  487. // wait for device close notification or timeout
  488. //
  489. if (fSuccess && !(lpWavOut->dwFlags & WAVOUT_CLOSEASYNC))
  490. {
  491. DWORD dwTimeout = SysGetTimerCount() +
  492. (msTimeoutClose == 0 ? 30000L : msTimeoutClose);
  493. #ifdef MULTITHREAD
  494. if (lpWavOut->dwFlags & WAVOUT_MULTITHREAD)
  495. {
  496. DWORD dwRet;
  497. // wait for the device to be closed
  498. //
  499. if ((dwRet = WaitForSingleObject(
  500. lpWavOut->hEventDeviceClosed,
  501. (msTimeoutClose == 0 ? 30000L : msTimeoutClose))) != WAIT_OBJECT_0)
  502. {
  503. fSuccess = TraceFALSE(NULL);
  504. }
  505. }
  506. else
  507. #endif
  508. while (fSuccess && lpWavOut->fIsOpen)
  509. {
  510. MSG msg;
  511. if (SysGetTimerCount() >= dwTimeout)
  512. fSuccess = TraceFALSE(NULL);
  513. else if (PeekMessage(&msg, lpWavOut->hwndCallback, 0, 0, PM_REMOVE))
  514. {
  515. TranslateMessage(&msg);
  516. DispatchMessage(&msg);
  517. }
  518. else
  519. WaitMessage();
  520. }
  521. }
  522. #ifdef MULTITHREAD
  523. // clean up
  524. //
  525. if (lpWavOut != NULL && lpWavOut->hEventDeviceClosed != NULL)
  526. {
  527. if (!CloseHandle(lpWavOut->hEventDeviceClosed))
  528. fSuccess = TraceFALSE(NULL);
  529. else
  530. lpWavOut->hEventDeviceClosed = NULL;
  531. }
  532. if (lpWavOut != NULL && lpWavOut->hThreadCallback != NULL)
  533. {
  534. if (!CloseHandle(lpWavOut->hThreadCallback))
  535. fSuccess = TraceFALSE(NULL);
  536. else
  537. lpWavOut->hThreadCallback = NULL;
  538. }
  539. #endif
  540. if (fSuccess)
  541. {
  542. #ifdef MULTITHREAD
  543. if (lpWavOut->dwFlags & WAVOUT_MULTITHREAD)
  544. {
  545. while (lpWavOut->critSectionStop.OwningThread != NULL)
  546. Sleep(100L);
  547. DeleteCriticalSection(&(lpWavOut->critSectionStop));
  548. }
  549. #endif
  550. // device handle is no longer valid
  551. //
  552. lpWavOut->hWaveOut = NULL;
  553. // destroy callback window
  554. //
  555. if (lpWavOut->hwndCallback != NULL &&
  556. !DestroyWindow(lpWavOut->hwndCallback))
  557. fSuccess = TraceFALSE(NULL);
  558. else if (lpWavOut->hwndCallback = NULL, FALSE)
  559. fSuccess = TraceFALSE(NULL);
  560. else if (lpWavOut->lpwfx != NULL &&
  561. WavFormatFree(lpWavOut->lpwfx) != 0)
  562. fSuccess = TraceFALSE(NULL);
  563. else if (lpWavOut->lpwfx = NULL, FALSE)
  564. fSuccess = TraceFALSE(NULL);
  565. else if ((lpWavOut = MemFree(NULL, lpWavOut)) != NULL)
  566. fSuccess = TraceFALSE(NULL);
  567. }
  568. return fSuccess ? 0 : -1;
  569. }
  570. // WavOutPlay - submit buffer of samples to wav output device for playback
  571. // <hWavOut> (i) handle returned from WavOutOpen
  572. // <lpBuf> (i) pointer to buffer containing samples
  573. // <sizBuf> (i) size of buffer in bytes
  574. // return 0 if success
  575. //
  576. // NOTE: the buffer pointed to by <lpBuf> must have been allocated
  577. // using MemAlloc().
  578. //
  579. // NOTE: if <hwndNotify> is specified in WavOutOpen(), a WM_WAVOUT_PLAYDONE
  580. // message will be sent to <hwndNotify>, with <lParam> set to a pointer to
  581. // a PLAYDONE structure, when <lpBuf> has been played.
  582. //
  583. // NOTE: if WAVOUT_AUTOFREE flag is specified in WavOutOpen,
  584. // GlobalFreePtr(lpBuf) will be called when <lpBuf> has been played.
  585. //
  586. int DLLEXPORT WINAPI WavOutPlay(HWAVOUT hWavOut, LPVOID lpBuf, long sizBuf)
  587. {
  588. BOOL fSuccess = TRUE;
  589. LPWAVOUT lpWavOut;
  590. LPWAVEHDR lpWaveHdr = NULL;
  591. #ifdef TELOUT
  592. if (hWavOut != NULL && hWavOut == (HWAVOUT) hTelOut)
  593. return TelOutPlay((HTELOUT) hWavOut, lpBuf, sizBuf, -1);
  594. #endif
  595. if ((lpWavOut = WavOutGetPtr(hWavOut)) == NULL)
  596. fSuccess = TraceFALSE(NULL);
  597. else if (lpBuf == NULL)
  598. fSuccess = TraceFALSE(NULL);
  599. else if ((lpWaveHdr = (LPWAVEHDR) MemAlloc(NULL,
  600. sizeof(WAVEHDR), 0)) == NULL)
  601. {
  602. fSuccess = TraceFALSE(NULL);
  603. }
  604. else
  605. {
  606. lpWaveHdr->lpData = (LPSTR) lpBuf;
  607. lpWaveHdr->dwBufferLength = (DWORD) sizBuf;
  608. if ((lpWavOut->nLastError = waveOutPrepareHeader(lpWavOut->hWaveOut,
  609. lpWaveHdr, sizeof(WAVEHDR))) != 0)
  610. {
  611. fSuccess = TraceFALSE(NULL);
  612. TracePrintf_1(NULL, 5,
  613. TEXT("waveOutPrepareHeader failed (%u)\n"),
  614. (unsigned) lpWavOut->nLastError);
  615. }
  616. else if ((lpWavOut->nLastError = waveOutWrite(lpWavOut->hWaveOut,
  617. lpWaveHdr, sizeof(WAVEHDR))) != 0)
  618. {
  619. fSuccess = TraceFALSE(NULL);
  620. TracePrintf_1(NULL, 5,
  621. TEXT("waveOutWrite failed (%u)\n"),
  622. (unsigned) lpWavOut->nLastError);
  623. }
  624. else
  625. {
  626. ++lpWavOut->cBufsPending;
  627. lpWavOut->wState = WAVOUT_PLAYING;
  628. }
  629. }
  630. return fSuccess ? 0 : -1;
  631. }
  632. // WavOutStop - stop playback of buffer(s) sent to wav output device
  633. // <hWavOut> (i) handle returned from WavOutOpen
  634. // <msTimeoutStop> (i) device stop timeout in milleseconds
  635. // 0 default timeout (2000)
  636. // return 0 if success
  637. //
  638. int DLLEXPORT WINAPI WavOutStop(HWAVOUT hWavOut, DWORD msTimeoutStop)
  639. {
  640. BOOL fSuccess = TRUE;
  641. LPWAVOUT lpWavOut;
  642. #ifdef TELOUT
  643. if (hWavOut != NULL && hWavOut == (HWAVOUT) hTelOut)
  644. return TelOutStop((HTELOUT) hWavOut, msTimeoutStop);
  645. #endif
  646. if ((lpWavOut = WavOutGetPtr(hWavOut)) == NULL)
  647. fSuccess = TraceFALSE(NULL);
  648. #ifdef MULTITHREAD
  649. else if ((lpWavOut->dwFlags & WAVOUT_MULTITHREAD) &&
  650. (EnterCriticalSection(&(lpWavOut->critSectionStop)), FALSE))
  651. ;
  652. #endif
  653. // make sure device is playing or paused
  654. //
  655. else if (WavOutGetState(hWavOut) == WAVOUT_STOPPED ||
  656. WavOutGetState(hWavOut) == WAVOUT_STOPPING)
  657. ; // not an error to call this function when stopped or stopping
  658. else if (lpWavOut->wState = WAVOUT_STOPPING, FALSE)
  659. ;
  660. #ifdef MULTITHREAD
  661. // we need to know when device has been stopped
  662. //
  663. else if ((lpWavOut->dwFlags & WAVOUT_MULTITHREAD) &&
  664. (lpWavOut->hEventDeviceStopped = CreateEvent(
  665. NULL, FALSE, FALSE, NULL)) == NULL)
  666. {
  667. fSuccess = TraceFALSE(NULL);
  668. }
  669. #endif
  670. // stop the device
  671. //
  672. else if ((lpWavOut->nLastError = waveOutReset(lpWavOut->hWaveOut)) != 0)
  673. {
  674. fSuccess = TraceFALSE(NULL);
  675. TracePrintf_1(NULL, 5,
  676. TEXT("waveOutReset failed (%u)\n"),
  677. (unsigned) lpWavOut->nLastError);
  678. }
  679. // wait for device to be stopped
  680. //
  681. #ifdef MULTITHREAD
  682. else if (lpWavOut->dwFlags & WAVOUT_MULTITHREAD)
  683. {
  684. DWORD dwRet;
  685. LeaveCriticalSection(&(lpWavOut->critSectionStop));
  686. // wait for the device to be stopped
  687. //
  688. if ((dwRet = WaitForSingleObject(
  689. lpWavOut->hEventDeviceStopped,
  690. (msTimeoutStop == 0 ? 10000L : msTimeoutStop))) != WAIT_OBJECT_0)
  691. {
  692. fSuccess = TraceFALSE(NULL);
  693. }
  694. EnterCriticalSection(&(lpWavOut->critSectionStop));
  695. }
  696. #endif
  697. else
  698. {
  699. DWORD dwTimeout = SysGetTimerCount() +
  700. (msTimeoutStop == 0 ? 2000L : msTimeoutStop);
  701. while (fSuccess && WavOutGetState(hWavOut) != WAVOUT_STOPPED)
  702. {
  703. MSG msg;
  704. // check for timeout
  705. //
  706. if (SysGetTimerCount() >= dwTimeout)
  707. fSuccess = TraceFALSE(NULL);
  708. #if 0 // this version doesn't seem to work with TCP/IP protocol
  709. else if (PeekMessage(&msg, lpWavOut->hwndCallback, 0, 0, PM_REMOVE))
  710. #else
  711. else if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
  712. #endif
  713. {
  714. TranslateMessage(&msg);
  715. DispatchMessage(&msg);
  716. }
  717. else
  718. WaitMessage();
  719. }
  720. }
  721. #ifdef MULTITHREAD
  722. // clean up
  723. //
  724. if (lpWavOut != NULL && lpWavOut->hEventDeviceStopped != NULL)
  725. {
  726. if (!CloseHandle(lpWavOut->hEventDeviceStopped))
  727. fSuccess = TraceFALSE(NULL);
  728. else
  729. lpWavOut->hEventDeviceStopped = NULL;
  730. }
  731. if (lpWavOut != NULL && (lpWavOut->dwFlags & WAVOUT_MULTITHREAD))
  732. LeaveCriticalSection(&(lpWavOut->critSectionStop));
  733. #endif
  734. return fSuccess ? 0 : -1;
  735. }
  736. // WavOutPause - pause wav output device playback
  737. // <hWavOut> (i) handle returned from WavOutOpen
  738. // return 0 if success
  739. //
  740. int DLLEXPORT WINAPI WavOutPause(HWAVOUT hWavOut)
  741. {
  742. BOOL fSuccess = TRUE;
  743. LPWAVOUT lpWavOut;
  744. #ifdef TELOUT
  745. if (hWavOut != NULL && hWavOut == (HWAVOUT) hTelOut)
  746. return TelOutPause((HTELOUT) hWavOut);
  747. #endif
  748. if ((lpWavOut = WavOutGetPtr(hWavOut)) == NULL)
  749. fSuccess = TraceFALSE(NULL);
  750. // make sure device is playing or stopped
  751. //
  752. else if (WavOutGetState(hWavOut) == WAVOUT_PAUSED)
  753. ; // not an error to call this function when already paused
  754. // pause the device
  755. //
  756. else if ((lpWavOut->nLastError = waveOutPause(lpWavOut->hWaveOut)) != 0)
  757. {
  758. fSuccess = TraceFALSE(NULL);
  759. TracePrintf_1(NULL, 5,
  760. TEXT("waveOutPause failed (%u)\n"),
  761. (unsigned) lpWavOut->nLastError);
  762. }
  763. else
  764. lpWavOut->wState = WAVOUT_PAUSED;
  765. return fSuccess ? 0 : -1;
  766. }
  767. // WavOutResume - resume wav output device playback
  768. // <hWavOut> (i) handle returned from WavOutOpen
  769. // return 0 if success
  770. //
  771. int DLLEXPORT WINAPI WavOutResume(HWAVOUT hWavOut)
  772. {
  773. BOOL fSuccess = TRUE;
  774. LPWAVOUT lpWavOut;
  775. #ifdef TELOUT
  776. if (hWavOut != NULL && hWavOut == (HWAVOUT) hTelOut)
  777. return TelOutResume((HTELOUT) hWavOut);
  778. #endif
  779. if ((lpWavOut = WavOutGetPtr(hWavOut)) == NULL)
  780. fSuccess = TraceFALSE(NULL);
  781. // make sure the device is paused
  782. //
  783. else if (WavOutGetState(hWavOut) != WAVOUT_PAUSED)
  784. ; // not an error to call this function when already playing
  785. // restart the device
  786. //
  787. else if ((lpWavOut->nLastError = waveOutRestart(lpWavOut->hWaveOut)) != 0)
  788. {
  789. fSuccess = TraceFALSE(NULL);
  790. TracePrintf_1(NULL, 5,
  791. TEXT("waveOutRestart failed (%u)\n"),
  792. (unsigned) lpWavOut->nLastError);
  793. }
  794. else
  795. lpWavOut->wState = WAVOUT_PLAYING;
  796. return fSuccess ? 0 : -1;
  797. }
  798. // WavOutGetState - return current wav output device state
  799. // <hWavOut> (i) handle returned from WavOutOpen
  800. // return WAVOUT_STOPPED, WAVOUT_PLAYING, WAVOUT_PAUSED, or 0 if error
  801. //
  802. WORD DLLEXPORT WINAPI WavOutGetState(HWAVOUT hWavOut)
  803. {
  804. BOOL fSuccess = TRUE;
  805. LPWAVOUT lpWavOut;
  806. #ifdef TELOUT
  807. if (hWavOut != NULL && hWavOut == (HWAVOUT) hTelOut)
  808. return TelOutGetState((HTELOUT) hWavOut);
  809. #endif
  810. if ((lpWavOut = WavOutGetPtr(hWavOut)) == NULL)
  811. fSuccess = TraceFALSE(NULL);
  812. return fSuccess ? lpWavOut->wState : 0;
  813. }
  814. // WavOutGetPosition - get milleseconds of elapsed playback
  815. // <hWavOut> (i) handle returned from WavOutOpen
  816. // return 0 if success
  817. //
  818. long DLLEXPORT WINAPI WavOutGetPosition(HWAVOUT hWavOut)
  819. {
  820. BOOL fSuccess = TRUE;
  821. LPWAVOUT lpWavOut;
  822. MMTIME mmtime;
  823. long msPosition;
  824. #ifdef TELOUT
  825. if (hWavOut != NULL && hWavOut == (HWAVOUT) hTelOut)
  826. return TelOutGetPosition((HTELOUT) hWavOut);
  827. #endif
  828. MemSet(&mmtime, 0, sizeof(mmtime));
  829. // we will be requesting position in milleseconds
  830. //
  831. mmtime.wType = TIME_MS;
  832. if ((lpWavOut = WavOutGetPtr(hWavOut)) == NULL)
  833. fSuccess = TraceFALSE(NULL);
  834. // get device position
  835. //
  836. else if ((lpWavOut->nLastError = waveOutGetPosition(
  837. lpWavOut->hWaveOut, &mmtime, sizeof(MMTIME))) != 0)
  838. {
  839. fSuccess = TraceFALSE(NULL);
  840. TracePrintf_1(NULL, 5,
  841. TEXT("waveOutGetPosition failed (%u)\n"),
  842. (unsigned) lpWavOut->nLastError);
  843. }
  844. // see what type of position was returned
  845. //
  846. else switch (mmtime.wType)
  847. {
  848. case TIME_MS:
  849. {
  850. // we got milleseconds; no conversion required
  851. //
  852. msPosition = (long) mmtime.u.ms;
  853. }
  854. break;
  855. case TIME_SAMPLES:
  856. {
  857. // convert samples to millesconds
  858. //
  859. msPosition = (long) MULDIVU32(mmtime.u.sample,
  860. 1000L, lpWavOut->lpwfx->nSamplesPerSec);
  861. }
  862. break;
  863. case TIME_BYTES:
  864. {
  865. // convert bytes to millesconds
  866. //
  867. msPosition = (long) MULDIVU32(mmtime.u.cb,
  868. 1000L, lpWavOut->lpwfx->nAvgBytesPerSec);
  869. }
  870. break;
  871. case TIME_SMPTE:
  872. case TIME_MIDI:
  873. default:
  874. fSuccess = TraceFALSE(NULL);
  875. break;
  876. }
  877. return fSuccess ? msPosition : -1;
  878. }
  879. // WavOutGetId - return id of wav output device
  880. // <hWavOut> (i) handle returned from WavOutOpen
  881. // return device id (-1 if error)
  882. //
  883. int DLLEXPORT WINAPI WavOutGetId(HWAVOUT hWavOut)
  884. {
  885. BOOL fSuccess = TRUE;
  886. LPWAVOUT lpWavOut;
  887. #ifdef TELOUT
  888. if (hWavOut != NULL && hWavOut == (HWAVOUT) hTelOut)
  889. return TelOutGetId((HTELOUT) hWavOut);
  890. #endif
  891. if ((lpWavOut = WavOutGetPtr(hWavOut)) == NULL)
  892. fSuccess = TraceFALSE(NULL);
  893. return fSuccess ? lpWavOut->idDev : -1;
  894. }
  895. // WavOutGetName - get name of wav output device
  896. // <hWavOut> (i) handle returned from WavOutOpen
  897. // NULL use unopened device specified in <idDev>
  898. // <idDev> (i) device id (ignored if <hWavOut> is not NULL)
  899. // -1 any suitable output device
  900. // <lpszName> (o) buffer to hold device name
  901. // <sizName> (i) size of buffer
  902. // return 0 if success
  903. //
  904. int DLLEXPORT WINAPI WavOutGetName(HWAVOUT hWavOut, int idDev, LPTSTR lpszName, int sizName)
  905. {
  906. BOOL fSuccess = TRUE;
  907. LPWAVOUT lpWavOut;
  908. #ifdef TELOUT
  909. if (idDev == TELOUT_DEVICEID || (hWavOut != NULL && hWavOut == (HWAVOUT) hTelOut))
  910. return TelOutGetName((HTELOUT) hWavOut, idDev, lpszName, sizName);
  911. #endif
  912. if (hWavOut != NULL)
  913. {
  914. if ((lpWavOut = WavOutGetPtr(hWavOut)) == NULL)
  915. fSuccess = TraceFALSE(NULL);
  916. else
  917. idDev = lpWavOut->idDev;
  918. }
  919. if (fSuccess)
  920. {
  921. WAVEOUTCAPS woc;
  922. UINT nLastError;
  923. if ((nLastError = waveOutGetDevCaps(idDev, &woc, sizeof(WAVEOUTCAPS))) != 0)
  924. {
  925. fSuccess = TraceFALSE(NULL);
  926. TracePrintf_1(NULL, 5,
  927. TEXT("waveOutGetDevCaps failed (%u)\n"),
  928. (unsigned) nLastError);
  929. }
  930. else if (lpszName != NULL)
  931. StrNCpy(lpszName, woc.szPname, sizName);
  932. if (hWavOut != NULL && lpWavOut != NULL)
  933. lpWavOut->nLastError = nLastError;
  934. }
  935. return fSuccess ? 0 : -1;
  936. }
  937. // WavOutGetIdByName - get id of wav output device, lookup by name
  938. // <lpszName> (i) device name
  939. #ifdef _WIN32
  940. // NULL or TEXT("") get preferred device id
  941. #endif
  942. // <dwFlags> (i) reserved; must be zero
  943. // return device id (-1 if error)
  944. //
  945. int WINAPI WavOutGetIdByName(LPCTSTR lpszName, DWORD dwFlags)
  946. {
  947. UINT idDev;
  948. UINT cDev = (UINT) WavInGetDeviceCount();
  949. // If no device specified, get the preferred device
  950. if ( !lpszName || (_tcslen(lpszName) <= 0) )
  951. {
  952. DWORD dwTemp;
  953. DWORD dwRet = waveOutMessage( (HWAVEOUT)(DWORD_PTR)WAVE_MAPPER, DRVM_MAPPER_PREFERRED_GET, (DWORD_PTR) &idDev, (DWORD_PTR) &dwTemp );
  954. if ( dwRet == MMSYSERR_NOERROR )
  955. return idDev;
  956. }
  957. else
  958. {
  959. // Device specified, search by name
  960. for ( idDev = 0; idDev < cDev; ++idDev )
  961. {
  962. TCHAR szName[256];
  963. if ( WavOutGetName(NULL, idDev, szName, SIZEOFARRAY(szName)) == 0 )
  964. {
  965. if ( _tcsicmp(lpszName, szName) == 0 )
  966. return idDev;
  967. }
  968. }
  969. }
  970. // No match for device name
  971. TraceFALSE(NULL);
  972. return -1;
  973. }
  974. // WavOutSupportsFormat - return TRUE if device supports specified format
  975. // <hWavOut> (i) handle returned from WavOutOpen
  976. // NULL use unopened device specified in <idDev>
  977. // <idDev> (i) device id (ignored if <hWavOut> is not NULL)
  978. // -1 any suitable output device
  979. // <lpwfx> (i) wave format
  980. // return TRUE if device supports specified format
  981. //
  982. BOOL DLLEXPORT WINAPI WavOutSupportsFormat(HWAVOUT hWavOut, int idDev,
  983. LPWAVEFORMATEX lpwfx)
  984. {
  985. BOOL fSuccess = TRUE;
  986. LPWAVOUT lpWavOut;
  987. BOOL fSupportsFormat;
  988. #ifdef TELOUT
  989. if (idDev == TELOUT_DEVICEID || (hWavOut != NULL && hWavOut == (HWAVOUT) hTelOut))
  990. return TelOutSupportsFormat((HTELOUT) hWavOut, idDev, lpwfx);
  991. #endif
  992. if (hWavOut != NULL)
  993. {
  994. if ((lpWavOut = WavOutGetPtr(hWavOut)) == NULL)
  995. fSuccess = TraceFALSE(NULL);
  996. else
  997. idDev = lpWavOut->idDev;
  998. }
  999. if (fSuccess)
  1000. {
  1001. UINT nLastError;
  1002. // query the device
  1003. //
  1004. if ((nLastError = waveOutOpen(NULL, (UINT) idDev,
  1005. #ifndef _WIN32
  1006. (LPWAVEFORMAT)
  1007. #endif
  1008. lpwfx, 0, 0,
  1009. WAVE_FORMAT_QUERY | WAVE_ALLOWSYNC)) != 0)
  1010. {
  1011. fSupportsFormat = FALSE;
  1012. #if 1
  1013. if (TraceGetLevel(NULL) >= 9)
  1014. {
  1015. TracePrintf_0(NULL, 9,
  1016. TEXT("unsupported format:\n"));
  1017. WavFormatDump(lpwfx);
  1018. }
  1019. #endif
  1020. if (nLastError != WAVERR_BADFORMAT)
  1021. {
  1022. fSuccess = TraceFALSE(NULL);
  1023. TracePrintf_1(NULL, 5,
  1024. TEXT("waveOutOpen/FormatQuery failed (%u)\n"),
  1025. (unsigned) nLastError);
  1026. }
  1027. }
  1028. else
  1029. fSupportsFormat = TRUE;
  1030. if (hWavOut != NULL && lpWavOut != NULL)
  1031. lpWavOut->nLastError = nLastError;
  1032. }
  1033. return fSuccess ? fSupportsFormat : FALSE;
  1034. }
  1035. // WavOutFormatSuggest - suggest a new format which the device supports
  1036. // <hWavOut> (i) handle returned from WavOutOpen
  1037. // NULL use unopened device specified in <idDev>
  1038. // <idDev> (i) device id (ignored if <hWavOut> is not NULL)
  1039. // -1 any suitable output device
  1040. // <lpwfxSrc> (i) source format
  1041. // <dwFlags> (i) control flags
  1042. // WAVOUT_NOACM do not use audio compression manager
  1043. // return pointer to suggested format, NULL if error
  1044. //
  1045. // NOTE: the format structure returned is dynamically allocated.
  1046. // Use WavFormatFree() to free the buffer.
  1047. //
  1048. LPWAVEFORMATEX DLLEXPORT WINAPI WavOutFormatSuggest(
  1049. HWAVOUT hWavOut, int idDev, LPWAVEFORMATEX lpwfxSrc, DWORD dwFlags)
  1050. {
  1051. BOOL fSuccess = TRUE;
  1052. LPWAVOUT lpWavOut;
  1053. LPWAVEFORMATEX lpwfxSuggest = NULL;
  1054. LPWAVEFORMATEX lpwfxTemp = NULL;
  1055. HACM hAcm = NULL;
  1056. #ifdef TELOUT
  1057. if (idDev == TELOUT_DEVICEID || (hWavOut != NULL && hWavOut == (HWAVOUT) hTelOut))
  1058. return TelOutFormatSuggest((HTELOUT) hWavOut, idDev, lpwfxSrc, dwFlags);
  1059. #endif
  1060. if (hWavOut != NULL)
  1061. {
  1062. if ((lpWavOut = WavOutGetPtr(hWavOut)) == NULL)
  1063. fSuccess = TraceFALSE(NULL);
  1064. else
  1065. {
  1066. idDev = lpWavOut->idDev;
  1067. if (lpWavOut->dwFlags & WAVOUT_NOACM)
  1068. dwFlags |= WAVOUT_NOACM;
  1069. }
  1070. }
  1071. if ((hAcm = AcmInit(ACM_VERSION, SysGetTaskInstance(NULL),
  1072. (dwFlags & WAVOUT_NOACM) ? ACM_NOACM : 0)) == NULL)
  1073. fSuccess = TraceFALSE(NULL);
  1074. else if (!WavFormatIsValid(lpwfxSrc))
  1075. fSuccess = TraceFALSE(NULL);
  1076. else if ((lpwfxTemp = WavFormatDup(lpwfxSrc)) == NULL)
  1077. fSuccess = TraceFALSE(NULL);
  1078. // get suggested format, see if it is supported
  1079. //
  1080. if (fSuccess && lpwfxSuggest == NULL)
  1081. {
  1082. if ((lpwfxSuggest = AcmFormatSuggest(hAcm, lpwfxTemp,
  1083. -1, -1, -1, -1, 0)) == NULL)
  1084. fSuccess = TraceFALSE(NULL);
  1085. else if (WavFormatFree(lpwfxTemp) != 0)
  1086. fSuccess = TraceFALSE(NULL);
  1087. else if (!WavOutSupportsFormat(NULL, idDev, lpwfxSuggest))
  1088. {
  1089. lpwfxTemp = lpwfxSuggest;
  1090. lpwfxSuggest = NULL;
  1091. }
  1092. }
  1093. // get suggested PCM format, see if it is supported
  1094. //
  1095. if (fSuccess && lpwfxSuggest == NULL &&
  1096. lpwfxTemp->wFormatTag != WAVE_FORMAT_PCM)
  1097. {
  1098. if ((lpwfxSuggest = AcmFormatSuggest(hAcm, lpwfxTemp,
  1099. WAVE_FORMAT_PCM, -1, -1, -1, 0)) == NULL)
  1100. fSuccess = TraceFALSE(NULL);
  1101. else if (WavFormatFree(lpwfxTemp) != 0)
  1102. fSuccess = TraceFALSE(NULL);
  1103. else if (!WavOutSupportsFormat(NULL, idDev, lpwfxSuggest))
  1104. {
  1105. lpwfxTemp = lpwfxSuggest;
  1106. lpwfxSuggest = NULL;
  1107. }
  1108. }
  1109. // get suggested PCM mono format, see if it is supported
  1110. //
  1111. if (fSuccess && lpwfxSuggest == NULL &&
  1112. lpwfxTemp->nChannels != 1)
  1113. {
  1114. if ((lpwfxSuggest = AcmFormatSuggest(hAcm, lpwfxTemp,
  1115. WAVE_FORMAT_PCM, -1, -1, 1, 0)) == NULL)
  1116. fSuccess = TraceFALSE(NULL);
  1117. else if (WavFormatFree(lpwfxTemp) != 0)
  1118. fSuccess = TraceFALSE(NULL);
  1119. else if (!WavOutSupportsFormat(NULL, idDev, lpwfxSuggest))
  1120. {
  1121. lpwfxTemp = lpwfxSuggest;
  1122. lpwfxSuggest = NULL;
  1123. }
  1124. }
  1125. // get suggested PCM 8-bit mono format, see if it is supported
  1126. //
  1127. if (fSuccess && lpwfxSuggest == NULL &&
  1128. lpwfxTemp->wBitsPerSample != 8)
  1129. {
  1130. if ((lpwfxSuggest = AcmFormatSuggest(hAcm, lpwfxTemp,
  1131. WAVE_FORMAT_PCM, -1, 8, 1, 0)) == NULL)
  1132. fSuccess = TraceFALSE(NULL);
  1133. else if (WavFormatFree(lpwfxTemp) != 0)
  1134. fSuccess = TraceFALSE(NULL);
  1135. else if (!WavOutSupportsFormat(NULL, idDev, lpwfxSuggest))
  1136. {
  1137. lpwfxTemp = lpwfxSuggest;
  1138. lpwfxSuggest = NULL;
  1139. }
  1140. }
  1141. // get suggested PCM 11025Hz 8-bit mono format, see if it is supported
  1142. //
  1143. if (fSuccess && lpwfxSuggest == NULL &&
  1144. lpwfxTemp->nSamplesPerSec != 11025)
  1145. {
  1146. if ((lpwfxSuggest = AcmFormatSuggest(hAcm, lpwfxTemp,
  1147. WAVE_FORMAT_PCM, 11025, 8, 1, 0)) == NULL)
  1148. fSuccess = TraceFALSE(NULL);
  1149. else if (WavFormatFree(lpwfxTemp) != 0)
  1150. fSuccess = TraceFALSE(NULL);
  1151. else if (!WavOutSupportsFormat(NULL, idDev, lpwfxSuggest))
  1152. {
  1153. lpwfxTemp = lpwfxSuggest;
  1154. lpwfxSuggest = NULL;
  1155. }
  1156. }
  1157. // last resort; see if MULAW 8000Hz 8-bit mono format is supported
  1158. //
  1159. if (fSuccess && lpwfxSuggest == NULL)
  1160. {
  1161. #if 0
  1162. if ((lpwfxSuggest = AcmFormatSuggest(hAcm, lpwfxTemp,
  1163. WAVE_FORMAT_MULAW, 8000, 8, 1, 0)) == NULL)
  1164. #else
  1165. if ((lpwfxSuggest = WavFormatMulaw(NULL, 8000)) == NULL)
  1166. #endif
  1167. fSuccess = TraceFALSE(NULL);
  1168. else if (WavFormatFree(lpwfxTemp) != 0)
  1169. fSuccess = TraceFALSE(NULL);
  1170. else if (!WavOutSupportsFormat(NULL, idDev, lpwfxSuggest))
  1171. {
  1172. // no more chances for success
  1173. //
  1174. fSuccess = TraceFALSE(NULL);
  1175. if (WavFormatFree(lpwfxSuggest) != 0)
  1176. fSuccess = TraceFALSE(NULL);
  1177. }
  1178. }
  1179. // clean up
  1180. //
  1181. if (hAcm != NULL && AcmTerm(hAcm) != 0)
  1182. fSuccess = TraceFALSE(NULL);
  1183. else
  1184. hAcm = NULL;
  1185. return fSuccess ? lpwfxSuggest : NULL;
  1186. }
  1187. // WavOutIsSynchronous - return TRUE if wav output device is synchronous
  1188. // <hWavOut> (i) handle returned from WavOutOpen
  1189. // NULL use unopened device specified in <idDev>
  1190. // <idDev> (i) device id (ignored if <hWavOut> is not NULL)
  1191. // -1 any suitable output device
  1192. // return TRUE if wav output device is synchronous
  1193. //
  1194. BOOL DLLEXPORT WINAPI WavOutIsSynchronous(HWAVOUT hWavOut, int idDev)
  1195. {
  1196. BOOL fSuccess = TRUE;
  1197. LPWAVOUT lpWavOut;
  1198. BOOL fIsSynchronous;
  1199. #ifdef TELOUT
  1200. if (idDev == TELOUT_DEVICEID || (hWavOut != NULL && hWavOut == (HWAVOUT) hTelOut))
  1201. return TelOutIsSynchronous((HTELOUT) hWavOut, idDev);
  1202. #endif
  1203. if (hWavOut != NULL)
  1204. {
  1205. if ((lpWavOut = WavOutGetPtr(hWavOut)) == NULL)
  1206. fSuccess = TraceFALSE(NULL);
  1207. else
  1208. idDev = lpWavOut->idDev;
  1209. }
  1210. if (fSuccess)
  1211. {
  1212. WAVEOUTCAPS woc;
  1213. UINT nLastError;
  1214. if ((nLastError = waveOutGetDevCaps(idDev, &woc, sizeof(WAVEOUTCAPS))) != 0)
  1215. {
  1216. fSuccess = TraceFALSE(NULL);
  1217. TracePrintf_1(NULL, 5,
  1218. TEXT("waveOutGetDevCaps failed (%u)\n"),
  1219. (unsigned) nLastError);
  1220. }
  1221. else
  1222. fIsSynchronous = (BOOL) (woc.dwSupport & WAVECAPS_SYNC);
  1223. if (hWavOut != NULL && lpWavOut != NULL)
  1224. lpWavOut->nLastError = nLastError;
  1225. }
  1226. return fSuccess ? fIsSynchronous : FALSE;
  1227. }
  1228. // WavOutSupportsVolume - return TRUE if device supports volume control
  1229. // <hWavOut> (i) handle returned from WavOutOpen
  1230. // NULL use unopened device specified in <idDev>
  1231. // <idDev> (i) device id (ignored if <hWavOut> is not NULL)
  1232. // return TRUE if device supports volume control
  1233. //
  1234. BOOL DLLEXPORT WINAPI WavOutSupportsVolume(HWAVOUT hWavOut, int idDev)
  1235. {
  1236. BOOL fSuccess = TRUE;
  1237. LPWAVOUT lpWavOut;
  1238. BOOL fSupportsVolume;
  1239. #ifdef TELOUT
  1240. if (idDev == TELOUT_DEVICEID || (hWavOut != NULL && hWavOut == (HWAVOUT) hTelOut))
  1241. return TelOutSupportsVolume((HTELOUT) hWavOut, idDev);
  1242. #endif
  1243. if (hWavOut != NULL)
  1244. {
  1245. if ((lpWavOut = WavOutGetPtr(hWavOut)) == NULL)
  1246. fSuccess = TraceFALSE(NULL);
  1247. else
  1248. idDev = lpWavOut->idDev;
  1249. }
  1250. if (fSuccess)
  1251. {
  1252. WAVEOUTCAPS woc;
  1253. UINT nLastError;
  1254. if ((nLastError = waveOutGetDevCaps(idDev, &woc, sizeof(WAVEOUTCAPS))) != 0)
  1255. {
  1256. fSuccess = TraceFALSE(NULL);
  1257. TracePrintf_1(NULL, 5,
  1258. TEXT("waveOutGetDevCaps failed (%u)\n"),
  1259. (unsigned) nLastError);
  1260. }
  1261. else
  1262. fSupportsVolume = (BOOL) (woc.dwSupport & WAVECAPS_VOLUME);
  1263. if (hWavOut != NULL && lpWavOut != NULL)
  1264. lpWavOut->nLastError = nLastError;
  1265. }
  1266. return fSuccess ? fSupportsVolume : FALSE;
  1267. }
  1268. // WavOutSupportsSpeed - return TRUE if device supports speed control
  1269. // <hWavOut> (i) handle returned from WavOutOpen
  1270. // NULL use unopened device specified in <idDev>
  1271. // <idDev> (i) device id (ignored if <hWavOut> is not NULL)
  1272. // return TRUE if device supports speed control
  1273. //
  1274. BOOL DLLEXPORT WINAPI WavOutSupportsSpeed(HWAVOUT hWavOut, int idDev)
  1275. {
  1276. BOOL fSuccess = TRUE;
  1277. LPWAVOUT lpWavOut;
  1278. BOOL fSupportsSpeed;
  1279. #ifdef TELOUT
  1280. if (idDev == TELOUT_DEVICEID || (hWavOut != NULL && hWavOut == (HWAVOUT) hTelOut))
  1281. return TelOutSupportsSpeed((HTELOUT) hWavOut, idDev);
  1282. #endif
  1283. if (hWavOut != NULL)
  1284. {
  1285. if ((lpWavOut = WavOutGetPtr(hWavOut)) == NULL)
  1286. fSuccess = TraceFALSE(NULL);
  1287. else
  1288. idDev = lpWavOut->idDev;
  1289. }
  1290. if (fSuccess)
  1291. {
  1292. WAVEOUTCAPS woc;
  1293. UINT nLastError;
  1294. if ((nLastError = waveOutGetDevCaps(idDev, &woc, sizeof(WAVEOUTCAPS))) != 0)
  1295. {
  1296. fSuccess = TraceFALSE(NULL);
  1297. TracePrintf_1(NULL, 5,
  1298. TEXT("waveOutGetDevCaps failed (%u)\n"),
  1299. (unsigned) nLastError);
  1300. }
  1301. else
  1302. fSupportsSpeed = (BOOL) (woc.dwSupport & WAVECAPS_PLAYBACKRATE);
  1303. if (hWavOut != NULL && lpWavOut != NULL)
  1304. lpWavOut->nLastError = nLastError;
  1305. }
  1306. return fSuccess ? fSupportsSpeed : FALSE;
  1307. }
  1308. // WavOutSupportsPitch - return TRUE if device supports pitch control
  1309. // <hWavOut> (i) handle returned from WavOutOpen
  1310. // NULL use unopened device specified in <idDev>
  1311. // <idDev> (i) device id (ignored if <hWavOut> is not NULL)
  1312. // return TRUE if device supports pitch control
  1313. //
  1314. BOOL DLLEXPORT WINAPI WavOutSupportsPitch(HWAVOUT hWavOut, int idDev)
  1315. {
  1316. BOOL fSuccess = TRUE;
  1317. LPWAVOUT lpWavOut;
  1318. BOOL fSupportsPitch;
  1319. #ifdef TELOUT
  1320. if (idDev == TELOUT_DEVICEID || (hWavOut != NULL && hWavOut == (HWAVOUT) hTelOut))
  1321. return TelOutSupportsPitch((HTELOUT) hWavOut, idDev);
  1322. #endif
  1323. if (hWavOut != NULL)
  1324. {
  1325. if ((lpWavOut = WavOutGetPtr(hWavOut)) == NULL)
  1326. fSuccess = TraceFALSE(NULL);
  1327. else
  1328. idDev = lpWavOut->idDev;
  1329. }
  1330. if (fSuccess)
  1331. {
  1332. WAVEOUTCAPS woc;
  1333. UINT nLastError;
  1334. if ((nLastError = waveOutGetDevCaps(idDev, &woc, sizeof(WAVEOUTCAPS))) != 0)
  1335. {
  1336. fSuccess = TraceFALSE(NULL);
  1337. TracePrintf_1(NULL, 5,
  1338. TEXT("waveOutGetDevCaps failed (%u)\n"),
  1339. (unsigned) nLastError);
  1340. }
  1341. else
  1342. fSupportsPitch = (BOOL) (woc.dwSupport & WAVECAPS_PITCH);
  1343. if (hWavOut != NULL && lpWavOut != NULL)
  1344. lpWavOut->nLastError = nLastError;
  1345. }
  1346. return fSuccess ? fSupportsPitch : FALSE;
  1347. }
  1348. // WavOutGetVolume - get current volume level
  1349. // <hWavOut> (i) handle returned from WavOutOpen
  1350. // NULL use unopened device specified in <idDev>
  1351. // <idDev> (i) device id (ignored if <hWavOut> is not NULL)
  1352. // return volume level (0 minimum through 100 maximum, -1 if error)
  1353. //
  1354. int DLLEXPORT WINAPI WavOutGetVolume(HWAVOUT hWavOut, int idDev)
  1355. {
  1356. BOOL fSuccess = TRUE;
  1357. LPWAVOUT lpWavOut;
  1358. UINT nLastError;
  1359. DWORD dwVolume;
  1360. int nLevel;
  1361. #ifdef TELOUT
  1362. if (hWavOut != NULL && hWavOut == (HWAVOUT) hTelOut)
  1363. return TelOutGetVolume((HTELOUT) hWavOut);
  1364. #endif
  1365. if (hWavOut != NULL && (lpWavOut = WavOutGetPtr(hWavOut)) == NULL)
  1366. fSuccess = TraceFALSE(NULL);
  1367. else if ((nLastError = waveOutGetVolume(
  1368. #ifdef _WIN32
  1369. #if (WINVER < 0x0400)
  1370. (UINT)
  1371. #endif
  1372. (hWavOut == NULL ? (HWAVEOUT)IntToPtr(idDev) : lpWavOut->hWaveOut),
  1373. #else
  1374. (hWavOut == NULL ? (HWAVEOUT)IntToPtr(idDev) : (HWAVEOUT)IntToPtr(lpWavOut->idDev)),
  1375. #endif
  1376. &dwVolume)) != 0)
  1377. {
  1378. fSuccess = TraceFALSE(NULL);
  1379. TracePrintf_1(NULL, 5,
  1380. TEXT("waveOutGetVolume failed (%u)\n"),
  1381. (unsigned) nLastError);
  1382. }
  1383. else
  1384. {
  1385. nLevel = LOWORD(dwVolume) / (0xFFFF / VOLUME_POSITIONS);
  1386. TracePrintf_2(NULL, 5,
  1387. TEXT("WavOutGetVolume() = %d, 0x%08lX\n"),
  1388. (int) nLevel,
  1389. (unsigned long) dwVolume);
  1390. }
  1391. if (hWavOut != NULL && lpWavOut != NULL)
  1392. lpWavOut->nLastError = nLastError;
  1393. return fSuccess ? nLevel : -1;
  1394. }
  1395. // WavOutSetVolume - set current volume level
  1396. // <hWavOut> (i) handle returned from WavOutOpen
  1397. // NULL use unopened device specified in <idDev>
  1398. // <idDev> (i) device id (ignored if <hWavOut> is not NULL)
  1399. // <nLevel> (i) volume level
  1400. // 0 minimum volume
  1401. // 100 maximum volume
  1402. // return 0 if success
  1403. //
  1404. int DLLEXPORT WINAPI WavOutSetVolume(HWAVOUT hWavOut, int idDev, int nLevel)
  1405. {
  1406. BOOL fSuccess = TRUE;
  1407. LPWAVOUT lpWavOut;
  1408. DWORD dwVolume = MAKELONG(nLevel * (0xFFFF / VOLUME_POSITIONS),
  1409. nLevel * (0xFFFF / VOLUME_POSITIONS));
  1410. UINT nLastError;
  1411. #ifdef TELOUT
  1412. if (hWavOut != NULL && hWavOut == (HWAVOUT) hTelOut)
  1413. return TelOutSetVolume((HTELOUT) hWavOut, nLevel);
  1414. #endif
  1415. if (hWavOut != NULL && (lpWavOut = WavOutGetPtr(hWavOut)) == NULL)
  1416. fSuccess = TraceFALSE(NULL);
  1417. else if (nLevel < VOLUME_MINLEVEL || nLevel > VOLUME_MAXLEVEL)
  1418. fSuccess = TraceFALSE(NULL);
  1419. else if ((nLastError = waveOutSetVolume(
  1420. #ifdef _WIN32
  1421. #if (WINVER < 0x0400)
  1422. (UINT)
  1423. #endif
  1424. (hWavOut == NULL ? (HWAVEOUT)IntToPtr(idDev) : lpWavOut->hWaveOut),
  1425. #else
  1426. (hWavOut == NULL ? idDev : lpWavOut->idDev),
  1427. #endif
  1428. dwVolume)) != 0)
  1429. {
  1430. fSuccess = TraceFALSE(NULL);
  1431. TracePrintf_1(NULL, 5,
  1432. TEXT("waveOutSetVolume failed (%u)\n"),
  1433. (unsigned) nLastError);
  1434. }
  1435. else
  1436. {
  1437. TracePrintf_2(NULL, 5,
  1438. TEXT("WavOutSetVolume(%d) = 0x%08lX\n"),
  1439. (int) nLevel,
  1440. (unsigned long) dwVolume);
  1441. }
  1442. if (hWavOut != NULL && lpWavOut != NULL)
  1443. lpWavOut->nLastError = nLastError;
  1444. return fSuccess ? 0 : -1;
  1445. }
  1446. // WavOutGetSpeed - get current speed level
  1447. // <hWavOut> (i) handle returned from WavOutOpen
  1448. // return speed level (100 is normal, 50 is half, 200 is double, -1 if error)
  1449. //
  1450. int DLLEXPORT WINAPI WavOutGetSpeed(HWAVOUT hWavOut)
  1451. {
  1452. BOOL fSuccess = TRUE;
  1453. LPWAVOUT lpWavOut;
  1454. DWORD dwSpeed;
  1455. int nLevel;
  1456. #ifdef TELOUT
  1457. if (hWavOut != NULL && hWavOut == (HWAVOUT) hTelOut)
  1458. return TelOutGetSpeed((HTELOUT) hWavOut);
  1459. #endif
  1460. if ((lpWavOut = WavOutGetPtr(hWavOut)) == NULL)
  1461. fSuccess = TraceFALSE(NULL);
  1462. else if ((lpWavOut->nLastError = waveOutGetPlaybackRate(lpWavOut->hWaveOut,
  1463. &dwSpeed)) != 0)
  1464. {
  1465. fSuccess = TraceFALSE(NULL);
  1466. TracePrintf_1(NULL, 5,
  1467. TEXT("waveOutGetPlaybackRate failed (%u)\n"),
  1468. (unsigned) lpWavOut->nLastError);
  1469. }
  1470. else
  1471. {
  1472. WORD wSpeedInteger = HIWORD(dwSpeed);
  1473. WORD wSpeedFraction = LOWORD(dwSpeed);
  1474. nLevel = (int) (100 * wSpeedInteger) +
  1475. (int) ((DWORD) wSpeedFraction * (DWORD) 100 / 0x10000);
  1476. TracePrintf_2(NULL, 5,
  1477. TEXT("WavOutGetSpeed() = %d, 0x%08lX\n"),
  1478. (int) nLevel,
  1479. (unsigned long) dwSpeed);
  1480. }
  1481. return fSuccess ? nLevel : -1;
  1482. }
  1483. // WavOutSetSpeed - set current speed level
  1484. // <hWavOut> (i) handle returned from WavOutOpen
  1485. // <nLevel> (i) speed level
  1486. // 50 half speed
  1487. // 100 normal speed
  1488. // 200 double speed, etc.
  1489. // return 0 if success
  1490. //
  1491. int DLLEXPORT WINAPI WavOutSetSpeed(HWAVOUT hWavOut, int nLevel)
  1492. {
  1493. BOOL fSuccess = TRUE;
  1494. LPWAVOUT lpWavOut;
  1495. WORD wSpeedInteger = nLevel / 100;
  1496. WORD wSpeedFraction = (WORD) (0x10000 * (DWORD) (nLevel % 100L) / 100L);
  1497. DWORD dwSpeed = MAKELONG(wSpeedFraction, wSpeedInteger);
  1498. #ifdef TELOUT
  1499. if (hWavOut != NULL && hWavOut == (HWAVOUT) hTelOut)
  1500. return TelOutSetSpeed((HTELOUT) hWavOut, nLevel);
  1501. #endif
  1502. if ((lpWavOut = WavOutGetPtr(hWavOut)) == NULL)
  1503. fSuccess = TraceFALSE(NULL);
  1504. else if ((lpWavOut->nLastError = waveOutSetPlaybackRate(lpWavOut->hWaveOut,
  1505. dwSpeed)) != 0)
  1506. {
  1507. fSuccess = TraceFALSE(NULL);
  1508. TracePrintf_1(NULL, 5,
  1509. TEXT("waveOutSetPlaybackRate failed (%u)\n"),
  1510. (unsigned) lpWavOut->nLastError);
  1511. }
  1512. else
  1513. {
  1514. TracePrintf_2(NULL, 5,
  1515. TEXT("WavOutSetSpeed(%d) = 0x%08lX\n"),
  1516. (int) nLevel,
  1517. (unsigned long) dwSpeed);
  1518. }
  1519. return fSuccess ? 0 : -1;
  1520. }
  1521. // WavOutGetPitch - get current pitch level
  1522. // <hWavOut> (i) handle returned from WavOutOpen
  1523. // return pitch level (100 is normal, 50 is half, 200 is double, -1 if error)
  1524. //
  1525. int DLLEXPORT WINAPI WavOutGetPitch(HWAVOUT hWavOut)
  1526. {
  1527. BOOL fSuccess = TRUE;
  1528. LPWAVOUT lpWavOut;
  1529. DWORD dwPitch;
  1530. int nLevel;
  1531. #ifdef TELOUT
  1532. if (hWavOut != NULL && hWavOut == (HWAVOUT) hTelOut)
  1533. return TelOutGetPitch((HTELOUT) hWavOut);
  1534. #endif
  1535. if ((lpWavOut = WavOutGetPtr(hWavOut)) == NULL)
  1536. fSuccess = TraceFALSE(NULL);
  1537. else if ((lpWavOut->nLastError = waveOutGetPitch(lpWavOut->hWaveOut,
  1538. &dwPitch)) != 0)
  1539. {
  1540. fSuccess = TraceFALSE(NULL);
  1541. TracePrintf_1(NULL, 5,
  1542. TEXT("waveOutGetPitch failed (%u)\n"),
  1543. (unsigned) lpWavOut->nLastError);
  1544. }
  1545. else
  1546. {
  1547. WORD wPitchInteger = HIWORD(dwPitch);
  1548. WORD wPitchFraction = LOWORD(dwPitch);
  1549. nLevel = (int) (100 * wPitchInteger) +
  1550. (int) ((DWORD) wPitchFraction * (DWORD) 100 / 0x10000);
  1551. TracePrintf_2(NULL, 5,
  1552. TEXT("WavOutGetPitch() = %d, 0x%08lX\n"),
  1553. (int) nLevel,
  1554. (unsigned long) dwPitch);
  1555. }
  1556. return fSuccess ? nLevel : -1;
  1557. }
  1558. // WavOutSetPitch - set current pitch level
  1559. // <hWavOut> (i) handle returned from WavOutOpen
  1560. // <nLevel> (i) pitch level
  1561. // 50 half pitch
  1562. // 100 normal pitch
  1563. // 200 double pitch, etc.
  1564. // return 0 if success
  1565. //
  1566. int DLLEXPORT WINAPI WavOutSetPitch(HWAVOUT hWavOut, int nLevel)
  1567. {
  1568. BOOL fSuccess = TRUE;
  1569. LPWAVOUT lpWavOut;
  1570. WORD wPitchInteger = nLevel / 100;
  1571. WORD wPitchFraction = (WORD) (0x10000 * (DWORD) (nLevel % 100L) / 100L);
  1572. DWORD dwPitch = MAKELONG(wPitchFraction, wPitchInteger);
  1573. #ifdef TELOUT
  1574. if (hWavOut != NULL && hWavOut == (HWAVOUT) hTelOut)
  1575. return TelOutSetPitch((HTELOUT) hWavOut, nLevel);
  1576. #endif
  1577. if ((lpWavOut = WavOutGetPtr(hWavOut)) == NULL)
  1578. fSuccess = TraceFALSE(NULL);
  1579. else if ((lpWavOut->nLastError = waveOutSetPitch(lpWavOut->hWaveOut,
  1580. dwPitch)) != 0)
  1581. {
  1582. fSuccess = TraceFALSE(NULL);
  1583. TracePrintf_1(NULL, 5,
  1584. TEXT("waveOutSetPitch failed (%u)\n"),
  1585. (unsigned) lpWavOut->nLastError);
  1586. }
  1587. else
  1588. {
  1589. TracePrintf_2(NULL, 5,
  1590. TEXT("WavOutSetPitch(%d) = 0x%08lX\n"),
  1591. (int) nLevel,
  1592. (unsigned long) dwPitch);
  1593. }
  1594. return fSuccess ? 0 : -1;
  1595. }
  1596. // WavOutTerm - shut down wav output residuals, if any
  1597. // <hInst> (i) instance handle of calling module
  1598. // <dwFlags> (i) control flags
  1599. // WAV_TELTHUNK terminate telephone thunking layer
  1600. // return 0 if success
  1601. //
  1602. int DLLEXPORT WINAPI WavOutTerm(HINSTANCE hInst, DWORD dwFlags)
  1603. {
  1604. BOOL fSuccess = TRUE;
  1605. if (hInst == NULL)
  1606. fSuccess = TraceFALSE(NULL);
  1607. #ifdef TELOUT
  1608. else if ((dwFlags & WAV_TELTHUNK) &&
  1609. TelOutTerm(hInst, dwFlags) != 0)
  1610. fSuccess = TraceFALSE(NULL);
  1611. #endif
  1612. return fSuccess ? 0 : -1;
  1613. }
  1614. ////
  1615. // helper functions
  1616. ////
  1617. #ifdef MULTITHREAD
  1618. DWORD WINAPI WavOutCallbackThread(LPVOID lpvThreadParameter)
  1619. {
  1620. BOOL fSuccess = TRUE;
  1621. MSG msg;
  1622. LPWAVOUT lpWavOut = (LPWAVOUT) lpvThreadParameter;
  1623. // make sure message queue is created before calling SetEvent
  1624. //
  1625. PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE);
  1626. // notify main thread that callback thread has begun execution
  1627. //
  1628. if (!SetEvent(lpWavOut->hEventThreadCallbackStarted))
  1629. {
  1630. fSuccess = TraceFALSE(NULL);
  1631. }
  1632. while (fSuccess && GetMessage(&msg, NULL, 0, 0))
  1633. {
  1634. WavOutCallback((HWND) lpWavOut, msg.message, msg.wParam, msg.lParam);
  1635. // exit thread when when have processed last expected message
  1636. //
  1637. if (msg.message == MM_WOM_CLOSE)
  1638. break;
  1639. }
  1640. return 0;
  1641. }
  1642. #endif
  1643. // WavOutCallback - window procedure for wavout callback
  1644. //
  1645. LRESULT DLLEXPORT CALLBACK WavOutCallback(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
  1646. {
  1647. BOOL fSuccess = TRUE;
  1648. LRESULT lResult;
  1649. LPWAVOUT lpWavOut;
  1650. #ifdef MULTITHREAD
  1651. if (!IsWindow(hwnd))
  1652. lpWavOut = (LPWAVOUT) hwnd;
  1653. else
  1654. #endif
  1655. // retrieve lpWavOut from window extra bytes
  1656. //
  1657. lpWavOut = (LPWAVOUT) GetWindowLongPtr(hwnd, 0);
  1658. switch (msg)
  1659. {
  1660. case WM_NCCREATE:
  1661. {
  1662. LPCREATESTRUCT lpcs = (LPCREATESTRUCT) lParam;
  1663. LPWAVOUT lpWavOut = (LPWAVOUT) lpcs->lpCreateParams;
  1664. // store lpWavOut in window extra bytes
  1665. //
  1666. SetWindowLongPtr(hwnd, 0, (LONG_PTR) lpWavOut);
  1667. lResult = DefWindowProc(hwnd, msg, wParam, lParam);
  1668. }
  1669. break;
  1670. case MM_WOM_OPEN:
  1671. {
  1672. HWAVEOUT hWaveOut = (HWAVEOUT) wParam;
  1673. TraceOutput(NULL, 5,
  1674. TEXT("MM_WOM_OPEN\n"));
  1675. #ifdef MULTITHREAD
  1676. if (!(lpWavOut->dwFlags & WAVOUT_MULTITHREAD) &&
  1677. hWaveOut != lpWavOut->hWaveOut)
  1678. #else
  1679. if (hWaveOut != lpWavOut->hWaveOut)
  1680. #endif
  1681. fSuccess = TraceFALSE(NULL);
  1682. else
  1683. {
  1684. lpWavOut->fIsOpen = TRUE;
  1685. #ifdef MULTITHREAD
  1686. // notify main thread that device is open
  1687. //
  1688. if ((lpWavOut->dwFlags & WAVOUT_MULTITHREAD) &&
  1689. !SetEvent(lpWavOut->hEventDeviceOpened))
  1690. {
  1691. fSuccess = TraceFALSE(NULL);
  1692. }
  1693. #endif
  1694. // send notification of device opening
  1695. //
  1696. #ifdef MULTITHREAD
  1697. if (lpWavOut->dwFlags & WAVOUT_MULTITHREAD)
  1698. {
  1699. if ( lpWavOut->hwndNotify )
  1700. PostThreadMessage( HandleToUlong(lpWavOut->hwndNotify), WM_WAVOUT_OPEN, 0, 0);
  1701. }
  1702. else
  1703. #endif
  1704. {
  1705. if (lpWavOut->hwndNotify != NULL &&
  1706. IsWindow(lpWavOut->hwndNotify))
  1707. {
  1708. SendMessage(lpWavOut->hwndNotify, WM_WAVOUT_OPEN, 0, 0);
  1709. }
  1710. }
  1711. }
  1712. lResult = 0L;
  1713. }
  1714. break;
  1715. case MM_WOM_CLOSE:
  1716. {
  1717. HWAVEOUT hWaveOut = (HWAVEOUT) wParam;
  1718. TraceOutput(NULL, 5,
  1719. TEXT("MM_WOM_CLOSE\n"));
  1720. #ifdef MULTITHREAD
  1721. if (!(lpWavOut->dwFlags & WAVOUT_MULTITHREAD) &&
  1722. hWaveOut != lpWavOut->hWaveOut)
  1723. #else
  1724. if (hWaveOut != lpWavOut->hWaveOut)
  1725. #endif
  1726. fSuccess = TraceFALSE(NULL);
  1727. else
  1728. {
  1729. lpWavOut->fIsOpen = FALSE;
  1730. // send notification of device closing
  1731. //
  1732. #ifdef MULTITHREAD
  1733. if (lpWavOut->dwFlags & WAVOUT_MULTITHREAD)
  1734. {
  1735. if ( lpWavOut->hwndNotify )
  1736. PostThreadMessage(HandleToUlong(lpWavOut->hwndNotify), WM_WAVOUT_CLOSE, 0, 0);
  1737. }
  1738. else
  1739. #endif
  1740. {
  1741. if (lpWavOut->hwndNotify != NULL &&
  1742. IsWindow(lpWavOut->hwndNotify))
  1743. {
  1744. SendMessage(lpWavOut->hwndNotify, WM_WAVOUT_CLOSE, 0, 0);
  1745. }
  1746. }
  1747. #ifdef MULTITHREAD
  1748. // notify main thread that device is closed
  1749. //
  1750. if ((lpWavOut->dwFlags & WAVOUT_MULTITHREAD) &&
  1751. !SetEvent(lpWavOut->hEventDeviceClosed))
  1752. {
  1753. fSuccess = TraceFALSE(NULL);
  1754. }
  1755. #endif
  1756. }
  1757. lResult = 0L;
  1758. }
  1759. break;
  1760. case MM_WOM_DONE:
  1761. {
  1762. HWAVEOUT hWaveOut = (HWAVEOUT) wParam;
  1763. LPWAVEHDR lpWaveHdr = (LPWAVEHDR) lParam;
  1764. LPVOID lpBuf;
  1765. long sizBuf;
  1766. BOOL fAutoFree = (BOOL) (lpWavOut->dwFlags & WAVOUT_AUTOFREE);
  1767. TracePrintf_1(NULL, 5,
  1768. TEXT("MM_WOM_DONE (%lu)\n"),
  1769. (unsigned long) lpWaveHdr->dwBufferLength);
  1770. #ifdef MULTITHREAD
  1771. if (lpWavOut->dwFlags & WAVOUT_MULTITHREAD)
  1772. EnterCriticalSection(&(lpWavOut->critSectionStop));
  1773. #endif
  1774. #ifdef MULTITHREAD
  1775. if (!(lpWavOut->dwFlags & WAVOUT_MULTITHREAD) &&
  1776. hWaveOut != lpWavOut->hWaveOut)
  1777. #else
  1778. if (hWaveOut != lpWavOut->hWaveOut)
  1779. #endif
  1780. fSuccess = TraceFALSE(NULL);
  1781. else if (lpWaveHdr == NULL)
  1782. fSuccess = TraceFALSE(NULL);
  1783. // NULL buffer is possible with telephone, this is ok
  1784. //
  1785. else if ((lpBuf = (LPVOID) lpWaveHdr->lpData) == NULL, FALSE)
  1786. ;
  1787. else if (sizBuf = (long) lpWaveHdr->dwBufferLength, FALSE)
  1788. fSuccess = TraceFALSE(NULL);
  1789. else if (!(lpWaveHdr->dwFlags & WHDR_DONE))
  1790. fSuccess = TraceFALSE(NULL);
  1791. else if (!(lpWaveHdr->dwFlags & WHDR_PREPARED))
  1792. fSuccess = TraceFALSE(NULL);
  1793. else if ((lpWavOut->nLastError = waveOutUnprepareHeader(
  1794. lpWavOut->hWaveOut, lpWaveHdr, sizeof(WAVEHDR))) != 0)
  1795. {
  1796. fSuccess = TraceFALSE(NULL);
  1797. TracePrintf_1(NULL, 5,
  1798. TEXT("waveOutUnprepareHeader failed (%u)\n"),
  1799. (unsigned) lpWavOut->nLastError);
  1800. }
  1801. else if ((lpWaveHdr = MemFree(NULL, lpWaveHdr)) != NULL)
  1802. fSuccess = TraceFALSE(NULL);
  1803. else if (--lpWavOut->cBufsPending < 0)
  1804. fSuccess = TraceFALSE(NULL);
  1805. // device is no longer playing if no more buffers pending
  1806. //
  1807. else if (lpWavOut->cBufsPending == 0)
  1808. {
  1809. lpWavOut->wState = WAVOUT_STOPPED;
  1810. #ifdef MULTITHREAD
  1811. // notify main thread that device is stopped
  1812. //
  1813. if ((lpWavOut->dwFlags & WAVOUT_MULTITHREAD) &&
  1814. lpWavOut->hEventDeviceStopped != NULL &&
  1815. !SetEvent(lpWavOut->hEventDeviceStopped))
  1816. {
  1817. fSuccess = TraceFALSE(NULL);
  1818. }
  1819. #endif
  1820. }
  1821. if (fSuccess)
  1822. {
  1823. PLAYDONE playdone;
  1824. playdone.lpBuf = lpBuf;
  1825. playdone.sizBuf = sizBuf;
  1826. // send notification of playback completion
  1827. //
  1828. #ifdef MULTITHREAD
  1829. if (lpWavOut->dwFlags & WAVOUT_MULTITHREAD)
  1830. {
  1831. if ( lpWavOut->hwndNotify )
  1832. {
  1833. SendThreadMessage( HandleToUlong(lpWavOut->hwndNotify),
  1834. WM_WAVOUT_PLAYDONE, (LPARAM) (LPVOID) &playdone);
  1835. }
  1836. }
  1837. else
  1838. #endif
  1839. {
  1840. if (lpWavOut->hwndNotify != NULL &&
  1841. IsWindow(lpWavOut->hwndNotify))
  1842. {
  1843. SendMessage(lpWavOut->hwndNotify,
  1844. WM_WAVOUT_PLAYDONE, 0, (LPARAM) (LPVOID) &playdone);
  1845. }
  1846. }
  1847. }
  1848. // free data buffer if WAVOUT_AUTOFREE specified
  1849. //
  1850. if (fSuccess && fAutoFree)
  1851. {
  1852. if (lpBuf != NULL && (lpBuf = MemFree(NULL, lpBuf)) != NULL)
  1853. fSuccess = TraceFALSE(NULL);
  1854. }
  1855. lResult = 0L;
  1856. #ifdef MULTITHREAD
  1857. if (lpWavOut->dwFlags & WAVOUT_MULTITHREAD)
  1858. LeaveCriticalSection(&(lpWavOut->critSectionStop));
  1859. #endif
  1860. }
  1861. break;
  1862. default:
  1863. lResult = DefWindowProc(hwnd, msg, wParam, lParam);
  1864. break;
  1865. }
  1866. return lResult;
  1867. }
  1868. // WavOutGetPtr - verify that wavout handle is valid,
  1869. // <hWavOut> (i) handle returned from WavOutInit
  1870. // return corresponding wavout pointer (NULL if error)
  1871. //
  1872. static LPWAVOUT WavOutGetPtr(HWAVOUT hWavOut)
  1873. {
  1874. BOOL fSuccess = TRUE;
  1875. LPWAVOUT lpWavOut;
  1876. if ((lpWavOut = (LPWAVOUT) hWavOut) == NULL)
  1877. fSuccess = TraceFALSE(NULL);
  1878. else if (IsBadWritePtr(lpWavOut, sizeof(WAVOUT)))
  1879. fSuccess = TraceFALSE(NULL);
  1880. #ifdef CHECKTASK
  1881. // make sure current task owns the wavout handle
  1882. //
  1883. else if (lpWavOut->hTask != GetCurrentTask())
  1884. fSuccess = TraceFALSE(NULL);
  1885. #endif
  1886. return fSuccess ? lpWavOut : NULL;
  1887. }
  1888. // WavOutGetHandle - verify that wavout pointer is valid,
  1889. // <lpWavOut> (i) pointer to WAVOUT struct
  1890. // return corresponding wavout handle (NULL if error)
  1891. //
  1892. static HWAVOUT WavOutGetHandle(LPWAVOUT lpWavOut)
  1893. {
  1894. BOOL fSuccess = TRUE;
  1895. HWAVOUT hWavOut;
  1896. if ((hWavOut = (HWAVOUT) lpWavOut) == NULL)
  1897. fSuccess = TraceFALSE(NULL);
  1898. return fSuccess ? hWavOut : NULL;
  1899. }
  1900. #ifdef MULTITHREAD
  1901. static LRESULT SendThreadMessage(DWORD dwThreadId, UINT Msg, LPARAM lParam)
  1902. {
  1903. BOOL fSuccess = TRUE;
  1904. HANDLE hEventMessageProcessed = NULL;
  1905. DWORD dwRet;
  1906. // we need to know when message has been processed
  1907. //
  1908. if ((hEventMessageProcessed = CreateEvent(
  1909. NULL, FALSE, FALSE, NULL)) == NULL)
  1910. {
  1911. fSuccess = TraceFALSE(NULL);
  1912. }
  1913. // post message to thread, send event handle as wParam
  1914. //
  1915. else if (!PostThreadMessage(dwThreadId, Msg, (WPARAM) hEventMessageProcessed, lParam))
  1916. {
  1917. fSuccess = TraceFALSE(NULL);
  1918. }
  1919. // wait for the message to be processed
  1920. //
  1921. else if ((dwRet = WaitForSingleObject(
  1922. hEventMessageProcessed, INFINITE)) != WAIT_OBJECT_0)
  1923. {
  1924. fSuccess = TraceFALSE(NULL);
  1925. }
  1926. // clean up
  1927. //
  1928. if (hEventMessageProcessed != NULL)
  1929. {
  1930. if (!CloseHandle(hEventMessageProcessed))
  1931. fSuccess = TraceFALSE(NULL);
  1932. else
  1933. hEventMessageProcessed = NULL;
  1934. }
  1935. return 0L;
  1936. }
  1937. #endif