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.

1810 lines
47 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. // acm.c - audio compression manager functions
  24. ////
  25. #include "winlocal.h"
  26. #include <stdlib.h>
  27. #include "acm.h"
  28. #include <msacm.h>
  29. #include "loadlib.h"
  30. // On some Win31 and WinNT systems, the audio compresion manager
  31. // is not installed. Therefore, we use a thunking layer to more
  32. // gracefully handle this situation. See acmthunk.c for details
  33. //
  34. #ifdef ACMTHUNK
  35. #include "acmthunk.h"
  36. #endif
  37. #ifdef AVPCM
  38. #include "pcm.h"
  39. #endif
  40. #include "mem.h"
  41. #include "str.h"
  42. #include "trace.h"
  43. ////
  44. // private definitions
  45. ////
  46. // acm control struct
  47. //
  48. typedef struct ACM
  49. {
  50. DWORD dwVersion;
  51. HINSTANCE hInst;
  52. HTASK hTask;
  53. DWORD dwFlags;
  54. UINT nLastError;
  55. #ifdef AVPCM
  56. HPCM hPcm;
  57. #endif
  58. LPWAVEFORMATEX lpwfxSrc;
  59. LPWAVEFORMATEX lpwfxInterm1;
  60. LPWAVEFORMATEX lpwfxInterm2;
  61. LPWAVEFORMATEX lpwfxDst;
  62. HACMSTREAM hAcmStream1;
  63. HACMSTREAM hAcmStream2;
  64. HACMSTREAM hAcmStream3;
  65. #ifdef ACMTHUNK
  66. BOOL fAcmThunkInitialized;
  67. #endif
  68. } ACM, FAR *LPACM;
  69. // acm driver control struct
  70. //
  71. typedef struct ACMDRV
  72. {
  73. HACM hAcm;
  74. HINSTANCE hInstLib;
  75. HACMDRIVERID hadid;
  76. WORD wMid;
  77. WORD wPid;
  78. UINT nLastError;
  79. DWORD dwFlags;
  80. } ACMDRV, FAR *LPACMDRV;
  81. // <dwFlags> values in ACMDRV
  82. //
  83. #define ACMDRV_REMOVEDRIVER 0x00001000
  84. #ifdef _WIN32
  85. #define ACM_VERSION_MIN 0x03320000
  86. #else
  87. #define ACM_VERSION_MIN 0x02000000
  88. #endif
  89. // <dwFlags> values in AcmStreamSize
  90. //
  91. #define ACM_SOURCE 0x00010000
  92. #define ACM_DESTINATION 0x00020000
  93. // helper functions
  94. //
  95. static LPACM AcmGetPtr(HACM hAcm);
  96. static HACM AcmGetHandle(LPACM lpAcm);
  97. static LPACMDRV AcmDrvGetPtr(HACMDRV hAcmDrv);
  98. static HACMDRV AcmDrvGetHandle(LPACMDRV lpAcmDrv);
  99. static HACMSTREAM WINAPI AcmStreamOpen(HACM hAcm, LPWAVEFORMATEX lpwfxSrc,
  100. LPWAVEFORMATEX lpwfxDst, LPWAVEFILTER lpwfltr, DWORD dwFlags);
  101. static int WINAPI AcmStreamClose(HACM hAcm, HACMSTREAM hAcmStream);
  102. static long WINAPI AcmStreamSize(HACM hAcm, HACMSTREAM hAcmStream, long sizBuf, DWORD dwFlags);
  103. static long WINAPI AcmStreamConvert(HACM hAcm, HACMSTREAM hAcmStream,
  104. void _huge *hpBufSrc, long sizBufSrc,
  105. void _huge *hpBufDst, long sizBufDst,
  106. DWORD dwFlags);
  107. BOOL CALLBACK AcmDriverLoadEnumCallback(HACMDRIVERID hadid,
  108. DWORD dwInstance, DWORD fdwSupport);
  109. ////
  110. // public functions
  111. ////
  112. // AcmInit - initialize audio compression manager engine
  113. // <dwVersion> (i) must be ACM_VERSION
  114. // <hInst> (i) instance handle of calling module
  115. // <dwFlags> (i) control flags
  116. #ifdef AVPCM
  117. // ACM_NOACM use internal pcm engine rather than acm
  118. #endif
  119. // return handle (NULL if error)
  120. //
  121. HACM DLLEXPORT WINAPI AcmInit(DWORD dwVersion, HINSTANCE hInst, DWORD dwFlags)
  122. {
  123. BOOL fSuccess = TRUE;
  124. LPACM lpAcm = NULL;
  125. #ifndef AVPCM
  126. // turn off ACM_NOACM flag if not allowed
  127. //
  128. dwFlags &= ~ACM_NOACM;
  129. #endif
  130. if (dwVersion != ACM_VERSION)
  131. fSuccess = TraceFALSE(NULL);
  132. else if (hInst == NULL)
  133. fSuccess = TraceFALSE(NULL);
  134. else if ((lpAcm = (LPACM) MemAlloc(NULL, sizeof(ACM), 0)) == NULL)
  135. fSuccess = TraceFALSE(NULL);
  136. else
  137. {
  138. lpAcm->dwVersion = dwVersion;
  139. lpAcm->hInst = hInst;
  140. lpAcm->hTask = GetCurrentTask();
  141. lpAcm->dwFlags = dwFlags;
  142. lpAcm->nLastError = 0;
  143. #ifdef AVPCM
  144. lpAcm->hPcm = NULL;
  145. #endif
  146. lpAcm->lpwfxSrc = NULL;
  147. lpAcm->lpwfxInterm1 = NULL;
  148. lpAcm->lpwfxInterm2 = NULL;
  149. lpAcm->lpwfxDst = NULL;
  150. lpAcm->hAcmStream1 = NULL;
  151. lpAcm->hAcmStream2 = NULL;
  152. lpAcm->hAcmStream3 = NULL;
  153. #ifdef ACMTHUNK
  154. lpAcm->fAcmThunkInitialized = FALSE;
  155. if (!(lpAcm->dwFlags & ACM_NOACM))
  156. {
  157. // initialize acm thunking layer
  158. //
  159. if (!acmThunkInitialize())
  160. {
  161. #ifdef AVPCM
  162. fSuccess = TraceFALSE(NULL);
  163. #else
  164. // NOTE: this is not considered an error
  165. //
  166. fSuccess = TraceTRUE(NULL);
  167. // failure means we cannot call any acm functions
  168. //
  169. lpAcm->dwFlags |= ACM_NOACM;
  170. #endif
  171. }
  172. else
  173. {
  174. // remember so we can shut down later
  175. //
  176. lpAcm->fAcmThunkInitialized = TRUE;
  177. }
  178. }
  179. #endif
  180. #if 0 // for testing
  181. lpAcm->dwFlags |= ACM_NOACM;
  182. #endif
  183. if (!(lpAcm->dwFlags & ACM_NOACM))
  184. {
  185. // verify minimum acm version
  186. //
  187. if (acmGetVersion() < ACM_VERSION_MIN)
  188. fSuccess = TraceFALSE(NULL);
  189. }
  190. #ifdef AVPCM
  191. else if (lpAcm->dwFlags & ACM_NOACM)
  192. {
  193. // initialize PCM engine
  194. //
  195. if ((lpAcm->hPcm = PcmInit(PCM_VERSION, hInst, 0)) == NULL)
  196. fSuccess = TraceFALSE(NULL);
  197. }
  198. #endif
  199. }
  200. if (!fSuccess || (dwFlags & ACM_QUERY))
  201. {
  202. if (lpAcm != NULL && AcmTerm(AcmGetHandle(lpAcm)) != 0)
  203. fSuccess = TraceFALSE(NULL);
  204. else
  205. lpAcm = NULL;
  206. }
  207. return fSuccess ? AcmGetHandle(lpAcm) : NULL;
  208. }
  209. // AcmTerm - shut down audio compression manager engine
  210. // <hAcm> (i) handle returned from AcmInit
  211. // return 0 if success
  212. //
  213. int DLLEXPORT WINAPI AcmTerm(HACM hAcm)
  214. {
  215. BOOL fSuccess = TRUE;
  216. LPACM lpAcm;
  217. if ((lpAcm = AcmGetPtr(hAcm)) == NULL)
  218. fSuccess = TraceFALSE(NULL);
  219. else if (AcmConvertTerm(hAcm) != 0)
  220. fSuccess = TraceFALSE(NULL);
  221. // $FIXUP - call to acmThunkTerminate is disabled so that AcmInit/AcmTerm
  222. // can be called mutltiple times. This means the array of acm function
  223. // pointers is not freed and FreeLibrary is not called on msacm.dll
  224. //
  225. #if 0
  226. #ifdef ACMTHUNK
  227. // shut down acm thunking layer
  228. //
  229. else if (lpAcm->fAcmThunkInitialized && !acmThunkTerminate())
  230. fSuccess = TraceFALSE(NULL);
  231. else if (lpAcm->fAcmThunkInitialized = FALSE, FALSE)
  232. ;
  233. #endif
  234. #endif
  235. #ifdef AVPCM
  236. // shut down pcm engine
  237. //
  238. else if (lpAcm->hPcm != NULL && PcmTerm(lpAcm->hPcm) != 0)
  239. fSuccess = TraceFALSE(NULL);
  240. else if (lpAcm->hPcm = NULL, FALSE)
  241. ;
  242. #endif
  243. else if ((lpAcm = MemFree(NULL, lpAcm)) != NULL)
  244. fSuccess = TraceFALSE(NULL);
  245. return fSuccess ? 0 : -1;
  246. }
  247. // AcmFormatGetSizeMax - get size of largest acm WAVEFORMATEX struct
  248. // <hAcm> (i) handle returned from AcmInit
  249. //
  250. // return size of largest format struct, -1 if error
  251. //
  252. int DLLEXPORT WINAPI AcmFormatGetSizeMax(HACM hAcm)
  253. {
  254. BOOL fSuccess = TRUE;
  255. LPACM lpAcm = NULL;
  256. DWORD dwSizeMax = 0;
  257. if ((lpAcm = AcmGetPtr(hAcm)) == NULL)
  258. fSuccess = TraceFALSE(NULL);
  259. #ifdef AVPCM
  260. else if (lpAcm->dwFlags & ACM_NOACM)
  261. dwSizeMax = sizeof(WAVEFORMATEX);
  262. #endif
  263. // query largest format size
  264. //
  265. else if ((lpAcm->nLastError = acmMetrics(NULL,
  266. ACM_METRIC_MAX_SIZE_FORMAT, (LPVOID) &dwSizeMax)) != 0)
  267. {
  268. fSuccess = TraceFALSE(NULL);
  269. TracePrintf_1(NULL, 5,
  270. TEXT("acmMetrics failed (%u)\n"),
  271. (unsigned) lpAcm->nLastError);
  272. }
  273. return fSuccess ? (int) dwSizeMax : -1;
  274. }
  275. // AcmFormatChoose - choose audio format from dialog box
  276. // <hAcm> (i) handle returned from AcmInit
  277. // <hwndOwner> (i) owner of dialog box
  278. // NULL no owner
  279. // <lpszTitle> (i) title of the dialog box
  280. // NULL use default title ("Sound Selection")
  281. // <lpwfx> (i) initialize dialog with this format
  282. // NULL no initial format
  283. // <dwFlags> (i) control flags
  284. // ACM_FORMATPLAY restrict choices to playback formats
  285. // ACM_FORMATRECORD restrict choices to recording formats
  286. // return pointer to chosen format, NULL if error or none chosen
  287. //
  288. // NOTE: the format structure returned is dynamically allocated.
  289. // Use WavFormatFree() to free the buffer.
  290. //
  291. LPWAVEFORMATEX DLLEXPORT WINAPI AcmFormatChooseEx(HACM hAcm,
  292. HWND hwndOwner, LPCTSTR lpszTitle, LPWAVEFORMATEX lpwfx, DWORD dwFlags)
  293. {
  294. BOOL fSuccess = TRUE;
  295. LPACM lpAcm;
  296. ACMFORMATCHOOSE afc;
  297. int nFormatSize = 0;
  298. int nFormatSizeMax;
  299. LPWAVEFORMATEX lpwfxNew = NULL;
  300. if ((lpAcm = AcmGetPtr(hAcm)) == NULL)
  301. fSuccess = TraceFALSE(NULL);
  302. // make sure current format is valid
  303. //
  304. else if (lpwfx != NULL && !WavFormatIsValid(lpwfx))
  305. fSuccess = TraceFALSE(NULL);
  306. // calc how big is the initial format struct
  307. //
  308. else if (lpwfx != NULL && (nFormatSize = WavFormatGetSize(lpwfx)) <= 0)
  309. fSuccess = TraceFALSE(NULL);
  310. // calc how big is the largest format struct in the acm
  311. //
  312. else if ((nFormatSizeMax = AcmFormatGetSizeMax(hAcm)) <= 0)
  313. fSuccess = TraceFALSE(NULL);
  314. // alloc a new format struct that is sure to be big enough
  315. //
  316. else if ((lpwfxNew = WavFormatAlloc((WORD)
  317. max(nFormatSize, nFormatSizeMax))) == NULL)
  318. {
  319. fSuccess = TraceFALSE(NULL);
  320. }
  321. #ifdef AVPCM
  322. else if (lpAcm->dwFlags & ACM_NOACM)
  323. {
  324. // no standard dialog available; just return a valid format
  325. //
  326. if (lpwfx == NULL && WavFormatPcm(-1, -1, -1, lpwfxNew) == NULL)
  327. fSuccess = TraceFALSE(NULL);
  328. else if (lpwfx != NULL && WavFormatCopy(lpwfxNew, lpwfx) != 0)
  329. fSuccess = TraceFALSE(NULL);
  330. }
  331. #endif
  332. else
  333. {
  334. // initialize the format struct
  335. //
  336. MemSet(&afc, 0, sizeof(afc));
  337. afc.cbStruct = sizeof(afc);
  338. afc.fdwStyle = 0;
  339. afc.hwndOwner = hwndOwner;
  340. afc.pwfx = lpwfxNew;
  341. afc.cbwfx = WavFormatGetSize(lpwfxNew);
  342. afc.pszTitle = lpszTitle;
  343. afc.szFormatTag[0] = '\0';
  344. afc.szFormat[0] = '\0';
  345. afc.pszName = NULL;
  346. afc.cchName = 0;
  347. afc.fdwEnum = 0;
  348. afc.pwfxEnum = NULL;
  349. afc.hInstance = NULL;
  350. afc.pszTemplateName = NULL;
  351. afc.lCustData = 0L;
  352. afc.pfnHook = NULL;
  353. if (lpwfx != NULL)
  354. {
  355. // supply initial format to dialog if possible
  356. //
  357. afc.fdwStyle |= ACMFORMATCHOOSE_STYLEF_INITTOWFXSTRUCT;
  358. if (WavFormatCopy(lpwfxNew, lpwfx) != 0)
  359. fSuccess = TraceFALSE(NULL);
  360. }
  361. // restrict choices if necessary
  362. //
  363. if (dwFlags & ACM_FORMATPLAY)
  364. afc.fdwEnum |= ACM_FORMATENUMF_OUTPUT;
  365. if (dwFlags & ACM_FORMATRECORD)
  366. afc.fdwEnum |= ACM_FORMATENUMF_INPUT;
  367. // do the dialog box, fill in lpwfxNew with chosen format
  368. //
  369. if ((lpAcm->nLastError = acmFormatChoose(&afc)) != 0)
  370. {
  371. if (lpAcm->nLastError == ACMERR_CANCELED)
  372. {
  373. fSuccess = FALSE;
  374. }
  375. else
  376. {
  377. fSuccess = TraceFALSE(NULL);
  378. TracePrintf_1(NULL, 5,
  379. TEXT("acmFormatChoose failed (%u)\n"),
  380. (unsigned) lpAcm->nLastError);
  381. }
  382. }
  383. }
  384. if (!fSuccess && lpwfxNew != NULL)
  385. {
  386. if (WavFormatFree(lpwfxNew) != 0)
  387. fSuccess = TraceFALSE(NULL);
  388. }
  389. return fSuccess ? lpwfxNew : NULL;
  390. }
  391. // AcmFormatSuggest - suggest a new format
  392. // <hAcm> (i) handle returned from AcmInit
  393. // <lpwfxSrc> (i) source format
  394. // <nFormatTag> (i) suggested format must match this format tag
  395. // -1 suggestion need not match
  396. // <nSamplesPerSec> (i) suggested format must match this sample rate
  397. // -1 suggestion need not match
  398. // <nBitsPerSample> (i) suggested format must match this sample size
  399. // -1 suggestion need not match
  400. // <nChannels> (i) suggested format must match this channels
  401. // -1 suggestion need not match
  402. // <dwFlags> (i) control flags
  403. // 0 reserved; must be zero
  404. // return pointer to suggested format, NULL if error
  405. //
  406. // NOTE: the format structure returned is dynamically allocated.
  407. // Use WavFormatFree() to free the buffer.
  408. //
  409. LPWAVEFORMATEX DLLEXPORT WINAPI AcmFormatSuggestEx(HACM hAcm,
  410. LPWAVEFORMATEX lpwfxSrc, long nFormatTag, long nSamplesPerSec,
  411. int nBitsPerSample, int nChannels, DWORD dwFlags)
  412. {
  413. BOOL fSuccess = TRUE;
  414. LPACM lpAcm;
  415. int nFormatSize = 0;
  416. int nFormatSizeMax;
  417. LPWAVEFORMATEX lpwfxNew = NULL;
  418. if ((lpAcm = AcmGetPtr(hAcm)) == NULL)
  419. fSuccess = TraceFALSE(NULL);
  420. // make sure source format is valid
  421. //
  422. else if (!WavFormatIsValid(lpwfxSrc))
  423. fSuccess = TraceFALSE(NULL);
  424. // calc how big is the source format struct
  425. //
  426. else if ((nFormatSize = WavFormatGetSize(lpwfxSrc)) <= 0)
  427. fSuccess = TraceFALSE(NULL);
  428. // calc how big is the largest format struct in the acm
  429. //
  430. else if ((nFormatSizeMax = AcmFormatGetSizeMax(hAcm)) <= 0)
  431. fSuccess = TraceFALSE(NULL);
  432. // alloc a new format struct that is sure to be big enough
  433. //
  434. else if ((lpwfxNew = WavFormatAlloc((WORD)
  435. max(nFormatSize, nFormatSizeMax))) == NULL)
  436. {
  437. fSuccess = TraceFALSE(NULL);
  438. }
  439. // copy source format to new format
  440. //
  441. else if (WavFormatCopy(lpwfxNew, lpwfxSrc) != 0)
  442. fSuccess = TraceFALSE(NULL);
  443. else if (!(lpAcm->dwFlags & ACM_NOACM))
  444. {
  445. DWORD dwFlagsSuggest = 0;
  446. // restrict suggestions if necessary
  447. //
  448. if (nFormatTag != -1)
  449. {
  450. lpwfxNew->wFormatTag = (WORD) nFormatTag;
  451. dwFlagsSuggest |= ACM_FORMATSUGGESTF_WFORMATTAG;
  452. }
  453. if (nSamplesPerSec != -1)
  454. {
  455. lpwfxNew->nSamplesPerSec = (DWORD) nSamplesPerSec;
  456. dwFlagsSuggest |= ACM_FORMATSUGGESTF_NSAMPLESPERSEC;
  457. }
  458. if (nBitsPerSample != -1)
  459. {
  460. lpwfxNew->wBitsPerSample = (WORD) nBitsPerSample;
  461. dwFlagsSuggest |= ACM_FORMATSUGGESTF_WBITSPERSAMPLE;
  462. }
  463. if (nChannels != -1)
  464. {
  465. lpwfxNew->nChannels = (WORD) nChannels;
  466. dwFlagsSuggest |= ACM_FORMATSUGGESTF_NCHANNELS;
  467. }
  468. if ((lpAcm->nLastError = acmFormatSuggest(NULL, lpwfxSrc,
  469. lpwfxNew, max(nFormatSize, nFormatSizeMax), dwFlagsSuggest)) != 0)
  470. {
  471. fSuccess = TraceFALSE(NULL);
  472. TracePrintf_1(NULL, 5,
  473. TEXT("acmFormatSuggest failed (%u)\n"),
  474. (unsigned) lpAcm->nLastError);
  475. }
  476. }
  477. #ifdef AVPCM
  478. else if (lpAcm->dwFlags & ACM_NOACM)
  479. {
  480. // make a suggested format based on source
  481. // $FIXUP - this code should be in pcm.c
  482. //
  483. if (nFormatTag != -1)
  484. lpwfxNew->wFormatTag = (WORD) nFormatTag;
  485. else
  486. lpwfxNew->wFormatTag = WAVE_FORMAT_PCM;
  487. if (nSamplesPerSec != -1)
  488. lpwfxNew->nSamplesPerSec = (DWORD) nSamplesPerSec;
  489. else if (lpwfxNew->nSamplesPerSec < 8000)
  490. lpwfxNew->nSamplesPerSec = 6000;
  491. else if (lpwfxNew->nSamplesPerSec < 11025)
  492. lpwfxNew->nSamplesPerSec = 8000;
  493. else if (lpwfxNew->nSamplesPerSec < 22050)
  494. lpwfxNew->nSamplesPerSec = 11025;
  495. else if (lpwfxNew->nSamplesPerSec < 44100)
  496. lpwfxNew->nSamplesPerSec = 22050;
  497. else
  498. lpwfxNew->nSamplesPerSec = 44100;
  499. if (nBitsPerSample != -1)
  500. lpwfxNew->wBitsPerSample = (WORD) nBitsPerSample;
  501. else if (lpwfxNew->wBitsPerSample < 16)
  502. lpwfxNew->wBitsPerSample = 8;
  503. else
  504. lpwfxNew->wBitsPerSample = 16;
  505. if (nChannels != -1)
  506. lpwfxNew->nChannels = (WORD) nChannels;
  507. else
  508. lpwfxNew->nChannels = 1;
  509. // recalculate nBlockAlign and nAvgBytesPerSec
  510. //
  511. if (WavFormatPcm(lpwfxNew->nSamplesPerSec,
  512. lpwfxNew->wBitsPerSample,
  513. lpwfxNew->nChannels, lpwfxNew) == NULL)
  514. fSuccess = TraceFALSE(NULL);
  515. }
  516. #endif
  517. if (!fSuccess && lpwfxNew != NULL)
  518. {
  519. if (WavFormatFree(lpwfxNew) != 0)
  520. fSuccess = TraceFALSE(NULL);
  521. }
  522. return fSuccess ? lpwfxNew : NULL;
  523. }
  524. // AcmFormatGetText - get text describing the specified format
  525. // <hAcm> (i) handle returned from AcmInit
  526. // <lpwfx> (i) format
  527. // <lpszText> (o) buffer to hold text
  528. // <sizText> (i) size of buffer, in characters
  529. // <dwFlags> (i) control flags
  530. // 0 reserved; must be zero
  531. // return 0 if success
  532. //
  533. int DLLEXPORT WINAPI AcmFormatGetText(HACM hAcm, LPWAVEFORMATEX lpwfx,
  534. LPTSTR lpszText, int sizText, DWORD dwFlags)
  535. {
  536. BOOL fSuccess = TRUE;
  537. LPACM lpAcm;
  538. TCHAR szFormat[ACMFORMATDETAILS_FORMAT_CHARS];
  539. TCHAR szFormatTag[ACMFORMATTAGDETAILS_FORMATTAG_CHARS];
  540. //
  541. // We have to initialize szFormatTag
  542. //
  543. _tcscpy( szFormatTag, _T("") );
  544. if ((lpAcm = AcmGetPtr(hAcm)) == NULL)
  545. fSuccess = TraceFALSE(NULL);
  546. // make sure format is valid
  547. //
  548. else if (!WavFormatIsValid(lpwfx))
  549. fSuccess = TraceFALSE(NULL);
  550. else if (lpszText == NULL)
  551. fSuccess = TraceFALSE(NULL);
  552. if (fSuccess && !(lpAcm->dwFlags & ACM_NOACM))
  553. {
  554. ACMFORMATTAGDETAILS atd;
  555. // initialize the details struct
  556. //
  557. MemSet(&atd, 0, sizeof(atd));
  558. atd.cbStruct = sizeof(atd);
  559. atd.dwFormatTagIndex = 0;
  560. atd.dwFormatTag = lpwfx->wFormatTag;
  561. atd.cbFormatSize = WavFormatGetSize(lpwfx);
  562. atd.fdwSupport = 0;
  563. atd.cStandardFormats = 0;
  564. atd.szFormatTag[0] = '\0';
  565. // get format tag details
  566. //
  567. if ((lpAcm->nLastError = acmFormatTagDetails(NULL,
  568. &atd, ACM_FORMATTAGDETAILSF_FORMATTAG)) != 0)
  569. {
  570. fSuccess = TraceFALSE(NULL);
  571. TracePrintf_1(NULL, 5,
  572. TEXT("acmFormatTagDetails failed (%u)\n"),
  573. (unsigned) lpAcm->nLastError);
  574. }
  575. else
  576. StrNCpy(szFormatTag, atd.szFormatTag, SIZEOFARRAY(szFormatTag));
  577. }
  578. #ifdef AVPCM
  579. if (fSuccess && (lpAcm->dwFlags & ACM_NOACM))
  580. {
  581. if (lpwfx->wFormatTag != WAVE_FORMAT_PCM)
  582. StrNCpy(szFormatTag, TEXT("*** Non-PCM ***"), SIZEOFARRAY(szFormatTag));
  583. else
  584. StrNCpy(szFormatTag, TEXT("PCM"), SIZEOFARRAY(szFormatTag));
  585. }
  586. #endif
  587. if (fSuccess && !(lpAcm->dwFlags & ACM_NOACM))
  588. {
  589. ACMFORMATDETAILS afd;
  590. // initialize the details struct
  591. //
  592. MemSet(&afd, 0, sizeof(afd));
  593. afd.cbStruct = sizeof(afd);
  594. afd.dwFormatIndex = 0;
  595. afd.dwFormatTag = lpwfx->wFormatTag;
  596. afd.fdwSupport = 0;
  597. afd.pwfx = lpwfx;
  598. afd.cbwfx = WavFormatGetSize(lpwfx);
  599. afd.szFormat[0] = '\0';
  600. // get format details
  601. //
  602. if ((lpAcm->nLastError = acmFormatDetails(NULL,
  603. &afd, ACM_FORMATDETAILSF_FORMAT)) != 0)
  604. {
  605. fSuccess = TraceFALSE(NULL);
  606. TracePrintf_1(NULL, 5,
  607. TEXT("acmFormatDetails failed (%u)\n"),
  608. (unsigned) lpAcm->nLastError);
  609. }
  610. else
  611. StrNCpy(szFormat, afd.szFormat, SIZEOFARRAY(szFormat));
  612. }
  613. #ifdef AVPCM
  614. if (fSuccess && (lpAcm->dwFlags & ACM_NOACM))
  615. {
  616. TCHAR szTemp[64];
  617. wsprintf(szTemp, TEXT("%d.%03d kHz, %d Bit, %s"),
  618. (int) lpwfx->nSamplesPerSec / 1000,
  619. (int) lpwfx->nSamplesPerSec % 1000,
  620. (int) lpwfx->wBitsPerSample,
  621. (LPTSTR) (lpwfx->nChannels == 1 ? TEXT("Mono") : TEXT("Stereo")));
  622. StrNCpy(szFormat, szTemp, SIZEOFARRAY(szFormat));
  623. }
  624. #endif
  625. // fill output buffer with results
  626. //
  627. if (fSuccess)
  628. {
  629. StrNCpy(lpszText, szFormatTag, sizText);
  630. StrNCat(lpszText, TEXT("\t"), sizText);
  631. StrNCat(lpszText, szFormat, sizText);
  632. }
  633. return fSuccess ? 0 : -1;
  634. }
  635. // AcmConvertInit - initialize acm conversion engine
  636. // <hAcm> (i) handle returned from AcmInit
  637. // <lpwfxSrc> (i) pointer to source WAVEFORMATEX struct
  638. // <lpwfxDst> (i) pointer to destination WAVEFORMATEX struct
  639. // <lpwfltr> (i) pointer to WAVEFILTER struct
  640. // NULL reserved; must be NULL
  641. // <dwFlags> (i) control flags
  642. // ACM_NONREALTIME realtime conversion conversion not required
  643. // ACM_QUERY return 0 if conversion would be supported
  644. // return 0 if success
  645. //
  646. int DLLEXPORT WINAPI AcmConvertInit(HACM hAcm, LPWAVEFORMATEX lpwfxSrc,
  647. LPWAVEFORMATEX lpwfxDst, LPWAVEFILTER lpwfltr, DWORD dwFlags)
  648. {
  649. BOOL fSuccess = TRUE;
  650. LPACM lpAcm;
  651. if ((lpAcm = AcmGetPtr(hAcm)) == NULL)
  652. fSuccess = TraceFALSE(NULL);
  653. else if (AcmConvertTerm(hAcm) != 0)
  654. fSuccess = TraceFALSE(NULL);
  655. // make sure formats are valid
  656. //
  657. else if (!WavFormatIsValid(lpwfxSrc))
  658. fSuccess = TraceFALSE(NULL);
  659. else if (!WavFormatIsValid(lpwfxDst))
  660. fSuccess = TraceFALSE(NULL);
  661. // save a copy of source and destination formats
  662. //
  663. else if ((lpAcm->lpwfxSrc = WavFormatDup(lpwfxSrc)) == NULL)
  664. fSuccess = TraceFALSE(NULL);
  665. else if ((lpAcm->lpwfxDst = WavFormatDup(lpwfxDst)) == NULL)
  666. fSuccess = TraceFALSE(NULL);
  667. else
  668. {
  669. if (!(lpAcm->dwFlags & ACM_NOACM))
  670. {
  671. // PCM source --> PCM destination
  672. //
  673. if (lpwfxSrc->wFormatTag == WAVE_FORMAT_PCM &&
  674. lpwfxDst->wFormatTag == WAVE_FORMAT_PCM)
  675. {
  676. // open the acm conversion stream
  677. //
  678. if ((lpAcm->hAcmStream1 = AcmStreamOpen(AcmGetHandle(lpAcm),
  679. lpwfxSrc, lpwfxDst, NULL, dwFlags)) == NULL)
  680. {
  681. fSuccess = TraceFALSE(NULL);
  682. }
  683. }
  684. // non-PCM source --> non-PCM destination
  685. //
  686. else if (lpwfxSrc->wFormatTag != WAVE_FORMAT_PCM &&
  687. lpwfxDst->wFormatTag != WAVE_FORMAT_PCM)
  688. {
  689. // find a suitable intermediate PCM source format
  690. //
  691. if ((lpAcm->lpwfxInterm1 = AcmFormatSuggest(hAcm,
  692. lpwfxSrc, WAVE_FORMAT_PCM, -1, -1, -1, 0)) == NULL)
  693. {
  694. fSuccess = TraceFALSE(NULL);
  695. }
  696. // open the first acm conversion stream
  697. //
  698. else if ((lpAcm->hAcmStream1 = AcmStreamOpen(AcmGetHandle(lpAcm),
  699. lpAcm->lpwfxSrc, lpAcm->lpwfxInterm1, NULL, dwFlags)) == NULL)
  700. {
  701. fSuccess = TraceFALSE(NULL);
  702. }
  703. // find a suitable intermediate PCM destination format
  704. //
  705. else if ((lpAcm->lpwfxInterm2 = AcmFormatSuggest(hAcm,
  706. lpwfxDst, WAVE_FORMAT_PCM, -1, -1, -1, 0)) == NULL)
  707. {
  708. fSuccess = TraceFALSE(NULL);
  709. }
  710. // open the second acm conversion stream
  711. //
  712. else if (WavFormatCmp(lpAcm->lpwfxInterm1,
  713. lpAcm->lpwfxInterm2) == 0 &&
  714. (lpAcm->hAcmStream2 = AcmStreamOpen(AcmGetHandle(lpAcm),
  715. lpAcm->lpwfxInterm1, lpAcm->lpwfxDst, NULL, dwFlags)) == NULL)
  716. {
  717. fSuccess = TraceFALSE(NULL);
  718. }
  719. // open the second acm conversion stream
  720. //
  721. else if (WavFormatCmp(lpAcm->lpwfxInterm1,
  722. lpAcm->lpwfxInterm2) != 0 &&
  723. (lpAcm->hAcmStream2 = AcmStreamOpen(AcmGetHandle(lpAcm),
  724. lpAcm->lpwfxInterm1, lpAcm->lpwfxInterm2, NULL, dwFlags)) == NULL)
  725. {
  726. fSuccess = TraceFALSE(NULL);
  727. }
  728. // open the third acm conversion stream if necessary
  729. //
  730. else if (WavFormatCmp(lpAcm->lpwfxInterm1,
  731. lpAcm->lpwfxInterm2) != 0 &&
  732. (lpAcm->hAcmStream3 = AcmStreamOpen(AcmGetHandle(lpAcm),
  733. lpAcm->lpwfxInterm2, lpAcm->lpwfxDst, NULL, dwFlags)) == NULL)
  734. {
  735. fSuccess = TraceFALSE(NULL);
  736. }
  737. }
  738. // non-PCM source --> PCM destination
  739. //
  740. else if (lpwfxSrc->wFormatTag != WAVE_FORMAT_PCM &&
  741. lpwfxDst->wFormatTag == WAVE_FORMAT_PCM)
  742. {
  743. // find a suitable intermediate PCM format
  744. //
  745. if ((lpAcm->lpwfxInterm1 = AcmFormatSuggest(hAcm,
  746. lpwfxSrc, WAVE_FORMAT_PCM, -1, -1, -1, 0)) == NULL)
  747. {
  748. fSuccess = TraceFALSE(NULL);
  749. }
  750. // open the first acm conversion stream
  751. //
  752. else if ((lpAcm->hAcmStream1 = AcmStreamOpen(AcmGetHandle(lpAcm),
  753. lpAcm->lpwfxSrc, lpAcm->lpwfxInterm1, NULL, dwFlags)) == NULL)
  754. {
  755. fSuccess = TraceFALSE(NULL);
  756. }
  757. // open the second acm conversion stream if necessary
  758. //
  759. else if (WavFormatCmp(lpAcm->lpwfxInterm1,
  760. lpAcm->lpwfxDst) != 0 &&
  761. (lpAcm->hAcmStream2 = AcmStreamOpen(AcmGetHandle(lpAcm),
  762. lpAcm->lpwfxInterm1, lpAcm->lpwfxDst, NULL, dwFlags)) == NULL)
  763. {
  764. fSuccess = TraceFALSE(NULL);
  765. }
  766. }
  767. // PCM source --> non-PCM destination
  768. //
  769. else if (lpwfxSrc->wFormatTag == WAVE_FORMAT_PCM &&
  770. lpwfxDst->wFormatTag != WAVE_FORMAT_PCM)
  771. {
  772. // find a suitable intermediate PCM format
  773. //
  774. if ((lpAcm->lpwfxInterm1 = AcmFormatSuggest(hAcm,
  775. lpwfxDst, WAVE_FORMAT_PCM, -1, -1, -1, 0)) == NULL)
  776. {
  777. fSuccess = TraceFALSE(NULL);
  778. }
  779. // open the first acm conversion stream
  780. //
  781. else if ((lpAcm->hAcmStream1 = AcmStreamOpen(AcmGetHandle(lpAcm),
  782. lpAcm->lpwfxSrc, lpAcm->lpwfxInterm1, NULL, dwFlags)) == NULL)
  783. {
  784. fSuccess = TraceFALSE(NULL);
  785. }
  786. // open the second acm conversion stream
  787. //
  788. else if ((lpAcm->hAcmStream2 = AcmStreamOpen(AcmGetHandle(lpAcm),
  789. lpAcm->lpwfxInterm1, lpAcm->lpwfxDst, NULL, dwFlags)) == NULL)
  790. {
  791. fSuccess = TraceFALSE(NULL);
  792. }
  793. }
  794. }
  795. #ifdef AVPCM
  796. else if (lpAcm->dwFlags & ACM_NOACM)
  797. {
  798. // if we do not have the acm, we are limited to
  799. // the sub-set of PCM formats handled by pcm.c
  800. // $FIXUP - move this code to pcm.c
  801. //
  802. if (lpwfxSrc->wFormatTag != WAVE_FORMAT_PCM)
  803. fSuccess = TraceFALSE(NULL);
  804. else if (lpwfxSrc->nChannels != 1)
  805. fSuccess = TraceFALSE(NULL);
  806. else if (lpwfxSrc->nSamplesPerSec != 6000 &&
  807. lpwfxSrc->nSamplesPerSec != 8000 &&
  808. lpwfxSrc->nSamplesPerSec != 11025 &&
  809. lpwfxSrc->nSamplesPerSec != 22050 &&
  810. lpwfxSrc->nSamplesPerSec != 44100)
  811. fSuccess = TraceFALSE(NULL);
  812. else if (lpwfxDst->wFormatTag != WAVE_FORMAT_PCM)
  813. fSuccess = TraceFALSE(NULL);
  814. else if (lpwfxDst->nChannels != 1)
  815. fSuccess = TraceFALSE(NULL);
  816. else if (lpwfxDst->nSamplesPerSec != 6000 &&
  817. lpwfxDst->nSamplesPerSec != 8000 &&
  818. lpwfxDst->nSamplesPerSec != 11025 &&
  819. lpwfxDst->nSamplesPerSec != 22050 &&
  820. lpwfxDst->nSamplesPerSec != 44100)
  821. fSuccess = TraceFALSE(NULL);
  822. }
  823. #endif
  824. }
  825. if (!fSuccess || (dwFlags & ACM_QUERY))
  826. {
  827. if (AcmConvertTerm(hAcm) != 0)
  828. fSuccess = TraceFALSE(NULL);
  829. }
  830. return fSuccess ? 0 : -1;
  831. }
  832. // AcmConvertTerm - shut down acm conversion engine
  833. // <hAcm> (i) handle returned from AcmInit
  834. // return 0 if success
  835. //
  836. int DLLEXPORT WINAPI AcmConvertTerm(HACM hAcm)
  837. {
  838. BOOL fSuccess = TRUE;
  839. LPACM lpAcm;
  840. if ((lpAcm = AcmGetPtr(hAcm)) == NULL)
  841. fSuccess = TraceFALSE(NULL);
  842. // close the acm conversion stream
  843. //
  844. else if (lpAcm->hAcmStream1 != NULL &&
  845. AcmStreamClose(hAcm, lpAcm->hAcmStream1) != 0)
  846. {
  847. fSuccess = TraceFALSE(NULL);
  848. }
  849. else if (lpAcm->hAcmStream1 = NULL, FALSE)
  850. ;
  851. // close the acm conversion stream
  852. //
  853. else if (lpAcm->hAcmStream2 != NULL &&
  854. AcmStreamClose(hAcm, lpAcm->hAcmStream2) != 0)
  855. {
  856. fSuccess = TraceFALSE(NULL);
  857. }
  858. else if (lpAcm->hAcmStream2 = NULL, FALSE)
  859. ;
  860. // close the acm conversion stream
  861. //
  862. else if (lpAcm->hAcmStream3 != NULL &&
  863. AcmStreamClose(hAcm, lpAcm->hAcmStream3) != 0)
  864. {
  865. fSuccess = TraceFALSE(NULL);
  866. }
  867. else if (lpAcm->hAcmStream3 = NULL, FALSE)
  868. ;
  869. // free source and destination formats
  870. //
  871. else if (lpAcm->lpwfxSrc != NULL && WavFormatFree(lpAcm->lpwfxSrc) != 0)
  872. fSuccess = TraceFALSE(NULL);
  873. else if (lpAcm->lpwfxSrc = NULL, FALSE)
  874. ;
  875. else if (lpAcm->lpwfxInterm1 != NULL && WavFormatFree(lpAcm->lpwfxInterm1) != 0)
  876. fSuccess = TraceFALSE(NULL);
  877. else if (lpAcm->lpwfxInterm1 = NULL, FALSE)
  878. ;
  879. else if (lpAcm->lpwfxInterm2 != NULL && WavFormatFree(lpAcm->lpwfxInterm2) != 0)
  880. fSuccess = TraceFALSE(NULL);
  881. else if (lpAcm->lpwfxInterm2 = NULL, FALSE)
  882. ;
  883. else if (lpAcm->lpwfxDst != NULL && WavFormatFree(lpAcm->lpwfxDst) != 0)
  884. fSuccess = TraceFALSE(NULL);
  885. else if (lpAcm->lpwfxDst = NULL, FALSE)
  886. ;
  887. return fSuccess ? 0 : -1;
  888. }
  889. // AcmConvertGetSizeSrc - calculate source buffer size
  890. // <hAcm> (i) handle returned from AcmInit
  891. // <sizBufDst> (i) size of destination buffer in bytes
  892. // return source buffer size, -1 if error
  893. //
  894. long DLLEXPORT WINAPI AcmConvertGetSizeSrc(HACM hAcm, long sizBufDst)
  895. {
  896. BOOL fSuccess = TRUE;
  897. LPACM lpAcm;
  898. //
  899. // We should intialize local variable
  900. long sizBufSrc = -1;
  901. if ((lpAcm = AcmGetPtr(hAcm)) == NULL)
  902. fSuccess = TraceFALSE(NULL);
  903. else if (!(lpAcm->dwFlags & ACM_NOACM))
  904. {
  905. if (lpAcm->hAcmStream1 == NULL)
  906. fSuccess = TraceFALSE(NULL);
  907. if (fSuccess && lpAcm->hAcmStream3 != NULL &&
  908. (sizBufDst = AcmStreamSize(hAcm, lpAcm->hAcmStream3,
  909. (DWORD) sizBufDst, ACM_DESTINATION)) < 0)
  910. {
  911. fSuccess = TraceFALSE(NULL);
  912. }
  913. if (fSuccess && lpAcm->hAcmStream2 != NULL &&
  914. (sizBufDst = AcmStreamSize(hAcm, lpAcm->hAcmStream2,
  915. (DWORD) sizBufDst, ACM_DESTINATION)) < 0)
  916. {
  917. fSuccess = TraceFALSE(NULL);
  918. }
  919. if (fSuccess &&
  920. (sizBufSrc = AcmStreamSize(hAcm, lpAcm->hAcmStream1,
  921. (DWORD) sizBufDst, ACM_DESTINATION)) < 0)
  922. {
  923. fSuccess = TraceFALSE(NULL);
  924. }
  925. }
  926. #ifdef AVPCM
  927. else if (lpAcm->dwFlags & ACM_NOACM)
  928. {
  929. if ((sizBufSrc = PcmCalcSizBufSrc(lpAcm->hPcm, sizBufDst,
  930. lpAcm->lpwfxSrc, lpAcm->lpwfxDst)) < 0)
  931. {
  932. fSuccess = TraceFALSE(NULL);
  933. }
  934. }
  935. #endif
  936. return fSuccess ? sizBufSrc : -1;
  937. }
  938. // AcmConvertGetSizeDst - calculate destination buffer size
  939. // <hAcm> (i) handle returned from AcmInit
  940. // <sizBufSrc> (i) size of source buffer in bytes
  941. // return destination buffer size, -1 if error
  942. //
  943. long DLLEXPORT WINAPI AcmConvertGetSizeDst(HACM hAcm, long sizBufSrc)
  944. {
  945. BOOL fSuccess = TRUE;
  946. LPACM lpAcm;
  947. //
  948. // We should initialize the ocal variable
  949. //
  950. long sizBufDst = -1;
  951. if ((lpAcm = AcmGetPtr(hAcm)) == NULL)
  952. fSuccess = TraceFALSE(NULL);
  953. else if (!(lpAcm->dwFlags & ACM_NOACM))
  954. {
  955. if (lpAcm->hAcmStream1 == NULL)
  956. fSuccess = TraceFALSE(NULL);
  957. if (fSuccess && lpAcm->hAcmStream3 != NULL &&
  958. (sizBufSrc = AcmStreamSize(hAcm, lpAcm->hAcmStream3,
  959. (DWORD) sizBufSrc, ACM_SOURCE)) < 0)
  960. {
  961. fSuccess = TraceFALSE(NULL);
  962. }
  963. if (fSuccess && lpAcm->hAcmStream2 != NULL &&
  964. (sizBufSrc = AcmStreamSize(hAcm, lpAcm->hAcmStream2,
  965. (DWORD) sizBufSrc, ACM_SOURCE)) < 0)
  966. {
  967. fSuccess = TraceFALSE(NULL);
  968. }
  969. if (fSuccess &&
  970. (sizBufDst = AcmStreamSize(hAcm, lpAcm->hAcmStream1,
  971. (DWORD) sizBufSrc, ACM_SOURCE)) < 0)
  972. {
  973. fSuccess = TraceFALSE(NULL);
  974. }
  975. }
  976. #ifdef AVPCM
  977. else if (lpAcm->dwFlags & ACM_NOACM)
  978. {
  979. if ((sizBufDst = PcmCalcSizBufDst(lpAcm->hPcm, sizBufSrc,
  980. lpAcm->lpwfxSrc, lpAcm->lpwfxDst)) < 0)
  981. {
  982. fSuccess = TraceFALSE(NULL);
  983. }
  984. }
  985. #endif
  986. return fSuccess ? sizBufDst : -1;
  987. }
  988. // AcmConvert - convert wav data from one format to another
  989. // <hAcm> (i) handle returned from AcmInit
  990. // <hpBufSrc> (i) buffer containing bytes to reformat
  991. // <sizBufSrc> (i) size of buffer in bytes
  992. // <hpBufDst> (o) buffer to contain new format
  993. // <sizBufDst> (i) size of buffer in bytes
  994. // <dwFlags> (i) control flags
  995. // 0 reserved; must be zero
  996. // return count of bytes in destination buffer (-1 if error)
  997. //
  998. // NOTE: the destination buffer must be large enough to hold the result
  999. //
  1000. long DLLEXPORT WINAPI AcmConvert(HACM hAcm,
  1001. void _huge *hpBufSrc, long sizBufSrc,
  1002. void _huge *hpBufDst, long sizBufDst,
  1003. DWORD dwFlags)
  1004. {
  1005. BOOL fSuccess = TRUE;
  1006. LPACM lpAcm;
  1007. //
  1008. // We should initialize local variable
  1009. //
  1010. long cbDst = -1;
  1011. if ((lpAcm = AcmGetPtr(hAcm)) == NULL)
  1012. fSuccess = TraceFALSE(NULL);
  1013. else if (!(lpAcm->dwFlags & ACM_NOACM))
  1014. {
  1015. if (lpAcm->hAcmStream1 == NULL)
  1016. fSuccess = TraceFALSE(NULL);
  1017. else if (lpAcm->hAcmStream2 == NULL)
  1018. {
  1019. if ((cbDst = AcmStreamConvert(hAcm, lpAcm->hAcmStream1,
  1020. hpBufSrc, sizBufSrc, hpBufDst, sizBufDst, dwFlags)) < 0)
  1021. {
  1022. fSuccess = TraceFALSE(NULL);
  1023. }
  1024. }
  1025. else if (lpAcm->hAcmStream3 == NULL)
  1026. {
  1027. long sizBufInterm;
  1028. long cbInterm;
  1029. void _huge *hpBufInterm = NULL;
  1030. if ((sizBufInterm = AcmStreamSize(hAcm, lpAcm->hAcmStream1,
  1031. (DWORD) sizBufSrc, ACM_SOURCE)) < 0)
  1032. {
  1033. fSuccess = TraceFALSE(NULL);
  1034. }
  1035. else if (sizBufInterm == 0)
  1036. cbDst = 0; // nothing to do
  1037. else if ((hpBufInterm = (void _huge *) MemAlloc(NULL,
  1038. sizBufInterm, 0)) == NULL)
  1039. {
  1040. fSuccess = TraceFALSE(NULL);
  1041. }
  1042. else if ((cbInterm = AcmStreamConvert(hAcm, lpAcm->hAcmStream1,
  1043. hpBufSrc, sizBufSrc, hpBufInterm, sizBufInterm, dwFlags)) < 0)
  1044. {
  1045. fSuccess = TraceFALSE(NULL);
  1046. }
  1047. else if ((cbDst = AcmStreamConvert(hAcm, lpAcm->hAcmStream2,
  1048. hpBufInterm, cbInterm, hpBufDst, sizBufDst, dwFlags)) < 0)
  1049. {
  1050. fSuccess = TraceFALSE(NULL);
  1051. }
  1052. if (hpBufInterm != NULL &&
  1053. (hpBufInterm = MemFree(NULL, hpBufInterm)) != NULL)
  1054. fSuccess = TraceFALSE(NULL);
  1055. }
  1056. else // if (lpAcm->hAcmStream3 !== NULL)
  1057. {
  1058. long sizBufInterm1;
  1059. long cbInterm1;
  1060. void _huge *hpBufInterm1 = NULL;
  1061. long sizBufInterm2;
  1062. long cbInterm2;
  1063. void _huge *hpBufInterm2 = NULL;
  1064. if ((sizBufInterm1 = AcmStreamSize(hAcm, lpAcm->hAcmStream1,
  1065. (DWORD) sizBufSrc, ACM_SOURCE)) < 0)
  1066. {
  1067. fSuccess = TraceFALSE(NULL);
  1068. }
  1069. else if (sizBufInterm1 == 0)
  1070. cbDst = 0; // nothing to do
  1071. else if ((hpBufInterm1 = (void _huge *) MemAlloc(NULL,
  1072. sizBufInterm1, 0)) == NULL)
  1073. {
  1074. fSuccess = TraceFALSE(NULL);
  1075. }
  1076. else if ((sizBufInterm2 = AcmStreamSize(hAcm, lpAcm->hAcmStream2,
  1077. (DWORD) sizBufInterm1, ACM_SOURCE)) < 0)
  1078. {
  1079. fSuccess = TraceFALSE(NULL);
  1080. }
  1081. else if (sizBufInterm2 == 0)
  1082. cbDst = 0; // nothing to do
  1083. else if ((hpBufInterm2 = (void _huge *) MemAlloc(NULL,
  1084. sizBufInterm2, 0)) == NULL)
  1085. {
  1086. fSuccess = TraceFALSE(NULL);
  1087. }
  1088. else if ((cbInterm1 = AcmStreamConvert(hAcm, lpAcm->hAcmStream1,
  1089. hpBufSrc, sizBufSrc, hpBufInterm1, sizBufInterm1, dwFlags)) < 0)
  1090. {
  1091. fSuccess = TraceFALSE(NULL);
  1092. }
  1093. else if ((cbInterm2 = AcmStreamConvert(hAcm, lpAcm->hAcmStream2,
  1094. hpBufInterm1, cbInterm1, hpBufInterm2, sizBufInterm2, dwFlags)) < 0)
  1095. {
  1096. fSuccess = TraceFALSE(NULL);
  1097. }
  1098. else if ((cbDst = AcmStreamConvert(hAcm, lpAcm->hAcmStream3,
  1099. hpBufInterm2, cbInterm2, hpBufDst, sizBufDst, dwFlags)) < 0)
  1100. {
  1101. fSuccess = TraceFALSE(NULL);
  1102. }
  1103. if (hpBufInterm1 != NULL &&
  1104. (hpBufInterm1 = MemFree(NULL, hpBufInterm1)) != NULL)
  1105. fSuccess = TraceFALSE(NULL);
  1106. if (hpBufInterm2 != NULL &&
  1107. (hpBufInterm2 = MemFree(NULL, hpBufInterm2)) != NULL)
  1108. fSuccess = TraceFALSE(NULL);
  1109. }
  1110. }
  1111. #ifdef AVPCM
  1112. else if (lpAcm->dwFlags & ACM_NOACM)
  1113. {
  1114. // perform the conversion
  1115. //
  1116. if ((cbDst = PcmConvert(lpAcm->hPcm,
  1117. hpBufSrc, sizBufSrc, lpAcm->lpwfxSrc,
  1118. hpBufDst, sizBufDst, lpAcm->lpwfxDst, 0)) < 0)
  1119. {
  1120. fSuccess = TraceFALSE(NULL);
  1121. }
  1122. }
  1123. #endif
  1124. return fSuccess ? cbDst : -1;
  1125. }
  1126. // AcmDriverLoad - load an acm driver for use by this process
  1127. // <hAcm> (i) handle returned from AcmInit
  1128. // <wMid> (i) manufacturer id
  1129. // <wPid> (i) product id
  1130. // <lpszDriver> (i) name of driver module
  1131. // <lpszDriverProc> (i) name of driver proc function
  1132. // <dwFlags> (i) control flags
  1133. // 0 reserved; must be zero
  1134. // return handle (NULL if error)
  1135. //
  1136. HACMDRV DLLEXPORT WINAPI AcmDriverLoad(HACM hAcm, WORD wMid, WORD wPid,
  1137. LPTSTR lpszDriver, LPSTR lpszDriverProc, DWORD dwFlags)
  1138. {
  1139. BOOL fSuccess = TRUE;
  1140. LPACM lpAcm;
  1141. LPACMDRV lpAcmDrv = NULL;
  1142. DRIVERPROC lpfnDriverProc;
  1143. ACMDRIVERENUMCB lpfnAcmDriverLoadEnumCallback;
  1144. if ((lpAcm = AcmGetPtr(hAcm)) == NULL)
  1145. fSuccess = TraceFALSE(NULL);
  1146. else if (lpszDriver == NULL)
  1147. fSuccess = TraceFALSE(NULL);
  1148. else if (lpszDriverProc == NULL)
  1149. fSuccess = TraceFALSE(NULL);
  1150. else if ((lpAcmDrv = (LPACMDRV) MemAlloc(NULL, sizeof(ACMDRV), 0)) == NULL)
  1151. fSuccess = TraceFALSE(NULL);
  1152. else
  1153. {
  1154. lpAcmDrv->hAcm = hAcm;
  1155. lpAcmDrv->hInstLib = NULL;
  1156. lpAcmDrv->hadid = NULL;
  1157. lpAcmDrv->wMid = wMid;
  1158. lpAcmDrv->wPid = wPid;
  1159. lpAcmDrv->nLastError = 0;
  1160. lpAcmDrv->dwFlags = 0;
  1161. if ((lpfnAcmDriverLoadEnumCallback = (ACMDRIVERENUMCB)
  1162. MakeProcInstance((FARPROC) AcmDriverLoadEnumCallback,
  1163. lpAcm->hInst)) == NULL)
  1164. fSuccess = TraceFALSE(NULL);
  1165. // enumerate all drivers to see if specified driver is already loaded
  1166. //
  1167. else if ((lpAcmDrv->nLastError = acmDriverEnum(lpfnAcmDriverLoadEnumCallback, PtrToUlong(lpAcmDrv), 0)) != 0)
  1168. {
  1169. fSuccess = TraceFALSE(NULL);
  1170. TracePrintf_1(NULL, 5,
  1171. TEXT("acmDriverEnum failed (%u)\n"),
  1172. (unsigned) lpAcmDrv->nLastError);
  1173. }
  1174. // if error or driver is already loaded, we are done
  1175. //
  1176. if (!fSuccess || lpAcmDrv->hadid != NULL)
  1177. ;
  1178. // load the driver module if possible
  1179. //
  1180. else if ((lpAcmDrv->hInstLib = LoadLibraryPath(lpszDriver,
  1181. lpAcm->hInst, 0)) == NULL)
  1182. fSuccess = TraceFALSE(NULL);
  1183. // get address of driver proc function
  1184. //
  1185. else if ((lpfnDriverProc = (DRIVERPROC)
  1186. GetProcAddress(lpAcmDrv->hInstLib, lpszDriverProc)) == NULL)
  1187. fSuccess = TraceFALSE(NULL);
  1188. // add driver to list of available acm drivers
  1189. //
  1190. else if ((lpAcmDrv->nLastError = acmDriverAdd(&lpAcmDrv->hadid,
  1191. lpAcmDrv->hInstLib, (LPARAM) lpfnDriverProc, 0,
  1192. ACM_DRIVERADDF_FUNCTION | ACM_DRIVERADDF_LOCAL)) != 0)
  1193. {
  1194. fSuccess = TraceFALSE(NULL);
  1195. TracePrintf_1(NULL, 5,
  1196. TEXT("acmDriverAdd failed (%u)\n"),
  1197. (unsigned) lpAcmDrv->nLastError);
  1198. }
  1199. // set flag so we know to call acmDriverRemove
  1200. //
  1201. else
  1202. lpAcmDrv->dwFlags |= ACMDRV_REMOVEDRIVER;
  1203. }
  1204. if (!fSuccess && lpAcmDrv != NULL &&
  1205. (lpAcmDrv = MemFree(NULL, lpAcmDrv)) != NULL)
  1206. fSuccess = TraceFALSE(NULL);
  1207. return fSuccess ? AcmDrvGetHandle(lpAcmDrv) : NULL;
  1208. }
  1209. // AcmDriverUnload - unload an acm driver
  1210. // <hAcm> (i) handle returned from AcmInit
  1211. // <hAcmDrv> (i) handle returned from AcmDriverLoad
  1212. // return 0 if success
  1213. //
  1214. int DLLEXPORT WINAPI AcmDriverUnload(HACM hAcm, HACMDRV hAcmDrv)
  1215. {
  1216. BOOL fSuccess = TRUE;
  1217. LPACMDRV lpAcmDrv;
  1218. LPACM lpAcm;
  1219. if ((lpAcm = AcmGetPtr(hAcm)) == NULL)
  1220. fSuccess = TraceFALSE(NULL);
  1221. else if ((lpAcmDrv = AcmDrvGetPtr(hAcmDrv)) == NULL)
  1222. fSuccess = TraceFALSE(NULL);
  1223. else if (hAcm != lpAcmDrv->hAcm)
  1224. fSuccess = TraceFALSE(NULL);
  1225. else
  1226. {
  1227. // remove driver from acm if necessary
  1228. //
  1229. if ((lpAcmDrv->dwFlags & ACMDRV_REMOVEDRIVER) &&
  1230. lpAcmDrv->hadid != NULL &&
  1231. (lpAcmDrv->nLastError =
  1232. acmDriverRemove(lpAcmDrv->hadid, 0)) != 0)
  1233. {
  1234. fSuccess = TraceFALSE(NULL);
  1235. TracePrintf_1(NULL, 5,
  1236. TEXT("acmDriverRemove failed (%u)\n"),
  1237. (unsigned) lpAcmDrv->nLastError);
  1238. }
  1239. else
  1240. lpAcmDrv->hadid = NULL;
  1241. // driver module no longer needed
  1242. //
  1243. if (lpAcmDrv->hInstLib != NULL)
  1244. {
  1245. FreeLibrary(lpAcmDrv->hInstLib);
  1246. lpAcmDrv->hInstLib = NULL;
  1247. }
  1248. if ((lpAcmDrv = MemFree(NULL, lpAcmDrv)) != NULL)
  1249. fSuccess = TraceFALSE(NULL);
  1250. }
  1251. return fSuccess ? 0 : -1;
  1252. }
  1253. ////
  1254. // helper functions
  1255. ////
  1256. // AcmGetPtr - verify that acm handle is valid,
  1257. // <hAcm> (i) handle returned from AcmInit
  1258. // return corresponding acm pointer (NULL if error)
  1259. //
  1260. static LPACM AcmGetPtr(HACM hAcm)
  1261. {
  1262. BOOL fSuccess = TRUE;
  1263. LPACM lpAcm;
  1264. if ((lpAcm = (LPACM) hAcm) == NULL)
  1265. fSuccess = TraceFALSE(NULL);
  1266. else if (IsBadWritePtr(lpAcm, sizeof(ACM)))
  1267. fSuccess = TraceFALSE(NULL);
  1268. #ifdef CHECKTASK
  1269. // make sure current task owns the acm handle
  1270. //
  1271. else if (lpAcm->hTask != GetCurrentTask())
  1272. fSuccess = TraceFALSE(NULL);
  1273. #endif
  1274. return fSuccess ? lpAcm : NULL;
  1275. }
  1276. // AcmGetHandle - verify that acm pointer is valid,
  1277. // <lpAcm> (i) pointer to ACM struct
  1278. // return corresponding acm handle (NULL if error)
  1279. //
  1280. static HACM AcmGetHandle(LPACM lpAcm)
  1281. {
  1282. BOOL fSuccess = TRUE;
  1283. HACM hAcm;
  1284. if ((hAcm = (HACM) lpAcm) == NULL)
  1285. fSuccess = TraceFALSE(NULL);
  1286. return fSuccess ? hAcm : NULL;
  1287. }
  1288. // AcmDrvGetPtr - verify that acmdrv handle is valid,
  1289. // <hAcmDrv> (i) handle returned from AcmDrvLoad
  1290. // return corresponding acmdrv pointer (NULL if error)
  1291. //
  1292. static LPACMDRV AcmDrvGetPtr(HACMDRV hAcmDrv)
  1293. {
  1294. BOOL fSuccess = TRUE;
  1295. LPACMDRV lpAcmDrv;
  1296. if ((lpAcmDrv = (LPACMDRV) hAcmDrv) == NULL)
  1297. fSuccess = TraceFALSE(NULL);
  1298. else if (IsBadWritePtr(lpAcmDrv, sizeof(ACMDRV)))
  1299. fSuccess = TraceFALSE(NULL);
  1300. return fSuccess ? lpAcmDrv : NULL;
  1301. }
  1302. // AcmDrvGetHandle - verify that acmdrv pointer is valid,
  1303. // <lpAcm> (i) pointer to ACM struct
  1304. // return corresponding acmdrv handle (NULL if error)
  1305. //
  1306. static HACMDRV AcmDrvGetHandle(LPACMDRV lpAcmDrv)
  1307. {
  1308. BOOL fSuccess = TRUE;
  1309. HACMDRV hAcmDrv;
  1310. if ((hAcmDrv = (HACMDRV) lpAcmDrv) == NULL)
  1311. fSuccess = TraceFALSE(NULL);
  1312. return fSuccess ? hAcmDrv : NULL;
  1313. }
  1314. // AcmStreamOpen - open acm conversion stream
  1315. // <hAcm> (i) handle returned from AcmInit
  1316. // <lpwfxSrc> (i) pointer to source WAVEFORMATEX struct
  1317. // <lpwfxDst> (i) pointer to destination WAVEFORMATEX struct
  1318. // <lpwfltr> (i) pointer to WAVEFILTER struct
  1319. // <dwFlags> (i) control flags
  1320. // ACM_NONREALTIME realtime stream conversion not required
  1321. // ACM_QUERY return TRUE if conversion would be supported
  1322. // return handle (NULL if error)
  1323. //
  1324. static HACMSTREAM WINAPI AcmStreamOpen(HACM hAcm, LPWAVEFORMATEX lpwfxSrc,
  1325. LPWAVEFORMATEX lpwfxDst, LPWAVEFILTER lpwfltr, DWORD dwFlags)
  1326. {
  1327. BOOL fSuccess = TRUE;
  1328. HACMSTREAM hAcmStream = NULL;
  1329. LPACM lpAcm;
  1330. if ((lpAcm = AcmGetPtr(hAcm)) == NULL)
  1331. fSuccess = TraceFALSE(NULL);
  1332. else if (!WavFormatIsValid(lpwfxSrc))
  1333. fSuccess = TraceFALSE(NULL);
  1334. else if (!WavFormatIsValid(lpwfxDst))
  1335. fSuccess = TraceFALSE(NULL);
  1336. else
  1337. {
  1338. DWORD dwFlagsStreamOpen = 0;
  1339. // set non-realtime flag if necessary
  1340. //
  1341. if (dwFlags & ACM_NONREALTIME)
  1342. dwFlagsStreamOpen |= ACM_STREAMOPENF_NONREALTIME;
  1343. // set query flag if necessary
  1344. //
  1345. if (dwFlags & ACM_QUERY)
  1346. dwFlagsStreamOpen |= ACM_STREAMOPENF_QUERY;
  1347. // open (or query) the acm conversion stream
  1348. //
  1349. if ((lpAcm->nLastError = acmStreamOpen(&hAcmStream,
  1350. NULL, lpwfxSrc, lpwfxDst, lpwfltr, 0, 0, dwFlagsStreamOpen)) != 0)
  1351. {
  1352. if ((dwFlags & ACM_QUERY) &&
  1353. lpAcm->nLastError == ACMERR_NOTPOSSIBLE)
  1354. {
  1355. fSuccess = FALSE;
  1356. }
  1357. else
  1358. {
  1359. fSuccess = TraceFALSE(NULL);
  1360. TracePrintf_1(NULL, 5,
  1361. TEXT("acmStreamOpen failed (%u)\n"),
  1362. (unsigned) lpAcm->nLastError);
  1363. }
  1364. }
  1365. }
  1366. // close stream if we are finished with it
  1367. //
  1368. if (!fSuccess || (dwFlags & ACM_QUERY))
  1369. {
  1370. if (AcmStreamClose(hAcm, hAcmStream) != 0)
  1371. fSuccess = TraceFALSE(NULL);
  1372. }
  1373. if (dwFlags & ACM_QUERY)
  1374. return fSuccess ? (HACMSTREAM) TRUE : (HACMSTREAM) FALSE;
  1375. else
  1376. return fSuccess ? hAcmStream : NULL;
  1377. }
  1378. // AcmStreamClose - close acm conversion stream
  1379. // <hAcm> (i) handle returned from AcmInit
  1380. // <hAcmStream> (i) handle returned from AcmStreamOpen
  1381. // return 0 if success
  1382. //
  1383. static int WINAPI AcmStreamClose(HACM hAcm, HACMSTREAM hAcmStream)
  1384. {
  1385. BOOL fSuccess = TRUE;
  1386. LPACM lpAcm;
  1387. if ((lpAcm = AcmGetPtr(hAcm)) == NULL)
  1388. fSuccess = TraceFALSE(NULL);
  1389. // close the acm conversion stream
  1390. //
  1391. else if (hAcmStream != NULL &&
  1392. (lpAcm->nLastError = acmStreamClose(hAcmStream, 0)) != 0)
  1393. {
  1394. fSuccess = TraceFALSE(NULL);
  1395. TracePrintf_1(NULL, 5,
  1396. TEXT("acmStreamClose failed (%u)\n"),
  1397. (unsigned) lpAcm->nLastError);
  1398. }
  1399. else if (hAcmStream = NULL, FALSE)
  1400. ;
  1401. return fSuccess ? 0 : -1;
  1402. }
  1403. // AcmStreamSize - calculate stream buffer size
  1404. // <hAcm> (i) handle returned from AcmInit
  1405. // <hAcmStream> (i) handle returned from AcmStreamOpen
  1406. // <sizBuf> (i) size of buffer in bytes
  1407. // <dwFlags> (i) control flags
  1408. // ACM_SOURCE sizBuf is source, calc destination
  1409. // ACM_DESTINATION sizBuf is destination, calc source
  1410. // return buffer size, -1 if error
  1411. //
  1412. static long WINAPI AcmStreamSize(HACM hAcm, HACMSTREAM hAcmStream, long sizBuf, DWORD dwFlags)
  1413. {
  1414. BOOL fSuccess = TRUE;
  1415. LPACM lpAcm = NULL;
  1416. DWORD sizBufRet = 0;
  1417. if ((lpAcm = AcmGetPtr(hAcm)) == NULL)
  1418. fSuccess = TraceFALSE(NULL);
  1419. else if (hAcmStream == NULL)
  1420. fSuccess = TraceFALSE(NULL);
  1421. else if (sizBuf == 0)
  1422. sizBufRet = 0;
  1423. else
  1424. {
  1425. DWORD dwFlagsSize = 0;
  1426. if (dwFlags & ACM_SOURCE)
  1427. dwFlagsSize |= ACM_STREAMSIZEF_SOURCE;
  1428. if (dwFlags & ACM_DESTINATION)
  1429. dwFlagsSize |= ACM_STREAMSIZEF_DESTINATION;
  1430. if ((lpAcm->nLastError = acmStreamSize(hAcmStream,
  1431. (DWORD) sizBuf, &sizBufRet, dwFlagsSize)) != 0)
  1432. {
  1433. if (lpAcm->nLastError == ACMERR_NOTPOSSIBLE)
  1434. {
  1435. // not a fatal error; just return buffer size as zero
  1436. //
  1437. fSuccess = TraceTRUE(NULL);
  1438. sizBufRet = 0;
  1439. }
  1440. else
  1441. {
  1442. fSuccess = TraceFALSE(NULL);
  1443. TracePrintf_1(NULL, 5,
  1444. TEXT("acmStreamSize failed (%u)\n"),
  1445. (unsigned) lpAcm->nLastError);
  1446. }
  1447. }
  1448. }
  1449. return fSuccess ? (long) sizBufRet : -1;
  1450. }
  1451. // AcmStreamConvert - convert wav data from one format to another
  1452. // <hAcm> (i) handle returned from AcmInit
  1453. // <hAcmStream> (i) handle returned from AcmStreamOpen
  1454. // <hpBufSrc> (i) buffer containing bytes to reformat
  1455. // <sizBufSrc> (i) size of buffer in bytes
  1456. // <hpBufDst> (o) buffer to contain new format
  1457. // <sizBufDst> (i) size of buffer in bytes
  1458. // <dwFlags> (i) control flags
  1459. // 0 reserved; must be zero
  1460. // return count of bytes in destination buffer (-1 if error)
  1461. //
  1462. // NOTE: the destination buffer must be large enough to hold the result
  1463. //
  1464. static long WINAPI AcmStreamConvert(HACM hAcm, HACMSTREAM hAcmStream,
  1465. void _huge *hpBufSrc, long sizBufSrc,
  1466. void _huge *hpBufDst, long sizBufDst,
  1467. DWORD dwFlags)
  1468. {
  1469. BOOL fSuccess = TRUE;
  1470. LPACM lpAcm;
  1471. long cbDst;
  1472. if ((lpAcm = AcmGetPtr(hAcm)) == NULL)
  1473. fSuccess = TraceFALSE(NULL);
  1474. else if (hAcmStream == NULL)
  1475. fSuccess = TraceFALSE(NULL);
  1476. else
  1477. {
  1478. ACMSTREAMHEADER ash;
  1479. MemSet(&ash, 0, sizeof(ash));
  1480. // initialize stream header
  1481. //
  1482. ash.cbStruct = sizeof(ash);
  1483. ash.pbSrc = (LPBYTE) hpBufSrc;
  1484. ash.cbSrcLength = (DWORD) sizBufSrc;
  1485. ash.pbDst = (LPBYTE) hpBufDst;
  1486. ash.cbDstLength = (DWORD) sizBufDst;
  1487. // prepare stream header
  1488. //
  1489. if ((lpAcm->nLastError = acmStreamPrepareHeader(hAcmStream,
  1490. &ash, 0)) != 0)
  1491. {
  1492. fSuccess = TraceFALSE(NULL);
  1493. TracePrintf_1(NULL, 5,
  1494. TEXT("acmStreamPrepareHeader failed (%u)\n"),
  1495. (unsigned) lpAcm->nLastError);
  1496. }
  1497. else
  1498. {
  1499. // perform the conversion
  1500. //
  1501. if ((lpAcm->nLastError = acmStreamConvert(hAcmStream,
  1502. &ash, ACM_STREAMCONVERTF_BLOCKALIGN)) != 0)
  1503. {
  1504. fSuccess = TraceFALSE(NULL);
  1505. TracePrintf_1(NULL, 5,
  1506. TEXT("acmStreamConvert failed (%u)\n"),
  1507. (unsigned) lpAcm->nLastError);
  1508. }
  1509. else
  1510. {
  1511. // save count of bytes in destination buffer
  1512. //
  1513. cbDst = (long) ash.cbDstLengthUsed;
  1514. }
  1515. // reset these to original values before unprepare
  1516. //
  1517. ash.cbSrcLength = (DWORD) sizBufSrc;
  1518. ash.cbDstLength = (DWORD) sizBufDst;
  1519. // unprepare stream header (even if conversion failed)
  1520. //
  1521. if ((lpAcm->nLastError = acmStreamUnprepareHeader(hAcmStream,
  1522. &ash, 0)) != 0)
  1523. {
  1524. fSuccess = TraceFALSE(NULL);
  1525. TracePrintf_1(NULL, 5,
  1526. TEXT("acmStreamUnprepareHeader failed (%u)\n"),
  1527. (unsigned) lpAcm->nLastError);
  1528. }
  1529. }
  1530. }
  1531. return fSuccess ? cbDst : -1;
  1532. }
  1533. BOOL CALLBACK AcmDriverLoadEnumCallback(HACMDRIVERID hadid,
  1534. DWORD dwInstance, DWORD fdwSupport)
  1535. {
  1536. BOOL fSuccess = TRUE;
  1537. LPACMDRV lpAcmDrv;
  1538. ACMDRIVERDETAILS add;
  1539. MemSet(&add, 0, sizeof(add));
  1540. add.cbStruct = sizeof(ACMDRIVERDETAILS);
  1541. if (hadid == NULL)
  1542. fSuccess = TraceFALSE(NULL);
  1543. else if ((lpAcmDrv = (LPACMDRV)(DWORD_PTR)dwInstance) == NULL)
  1544. fSuccess = TraceFALSE(NULL);
  1545. // get information about this driver
  1546. //
  1547. else if ((lpAcmDrv->nLastError = acmDriverDetails(hadid, &add, 0)) != 0)
  1548. {
  1549. fSuccess = TraceFALSE(NULL);
  1550. TracePrintf_1(NULL, 5,
  1551. TEXT("acmDriverDetails failed (%u)\n"),
  1552. (unsigned) lpAcmDrv->nLastError);
  1553. }
  1554. // check for match on manufacturer id and product id
  1555. //
  1556. else if (add.wMid == lpAcmDrv->wMid && add.wPid == lpAcmDrv->wPid)
  1557. {
  1558. lpAcmDrv->hadid = hadid; // pass driver id handle back to caller
  1559. return FALSE; // we are finished enumerating
  1560. }
  1561. return TRUE; // continue enumeration
  1562. }