Source code of Windows XP (NT5)
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.

3023 lines
78 KiB

  1. //==========================================================================;
  2. //
  3. // msacmmap.c
  4. //
  5. // Copyright (c) 1992-1999 Microsoft Corporation
  6. //
  7. // Description:
  8. //
  9. //
  10. // History:
  11. // 9/18/93 cjp [curtisp]
  12. //
  13. //==========================================================================;
  14. #include <windows.h>
  15. #include <windowsx.h>
  16. #include <mmsystem.h>
  17. #include <mmddkp.h>
  18. #include <mmreg.h>
  19. #include <msacm.h>
  20. #include <msacmdrv.h>
  21. #include <memory.h>
  22. #include "muldiv32.h"
  23. #include "msacmmap.h"
  24. #include "debug.h"
  25. extern ACMGARB acmgarb;
  26. //
  27. //
  28. //
  29. ZYZPCMFORMAT gaPCMFormats[] =
  30. {
  31. { NULL, NULL, 5510},
  32. { NULL, NULL, 6620},
  33. { NULL, NULL, 8000},
  34. { NULL, NULL, 9600},
  35. { NULL, NULL, 11025},
  36. { NULL, NULL, 16000},
  37. { NULL, NULL, 18900},
  38. { NULL, NULL, 22050},
  39. { NULL, NULL, 27420},
  40. { NULL, NULL, 32000},
  41. { NULL, NULL, 33075},
  42. { NULL, NULL, 37800},
  43. { NULL, NULL, 44100},
  44. { NULL, NULL, 48000},
  45. { NULL, NULL, 0} // terminator
  46. // WARNING!!! WARNING!!!
  47. // If you change this array size update the size in:
  48. // init.c:mapSettingsRestore
  49. };
  50. //==========================================================================;
  51. //
  52. // -= INTERRUPT TIME CODE FOR WIN 16 =-
  53. //
  54. //
  55. //==========================================================================;
  56. //--------------------------------------------------------------------------;
  57. //
  58. // BOOL mapWaveDriverCallback
  59. //
  60. // Description:
  61. // This calls DriverCallback for a WAVEHDR.
  62. //
  63. // NOTE! this routine must be in a FIXED segment in Win 16.
  64. //
  65. // Arguments:
  66. // LPMAPSTREAM pms: Pointer to instance data.
  67. //
  68. // UINT uMsg: The message.
  69. //
  70. // DWORD dw1: Message DWORD (dw2 is always set to 0).
  71. //
  72. // Return (BOOL):
  73. // The result is non-zero if the function was able to do the callback.
  74. // Zero is returned if no callback was made.
  75. //
  76. // History:
  77. // 11/15/92 cjp [curtisp]
  78. //
  79. //--------------------------------------------------------------------------;
  80. #ifndef WIN32
  81. #pragma alloc_text(FIX_TEXT, mapWaveDriverCallback)
  82. //
  83. // NOTE! we *DO NOT* turn off optimization for Win 3.1 builds to keep the
  84. // compiler from using extended registers (we compile with -G3). this
  85. // function causes no extended registers to be used (like mapWaveCallback
  86. // does).
  87. //
  88. // !!! IF YOU TOUCH ANY OF THIS CODE, YOU MUST VERIFY THAT NO EXTENDED
  89. // !!! REGISTERS GET USED IN WIN 3.1 OR YOU WILL BREAK EVERYTHING !!!
  90. //
  91. // #if (WINVER <= 0x030A)
  92. // #pragma optimize("", off)
  93. // #endif
  94. //
  95. #endif
  96. EXTERN_C BOOL FNGLOBAL mapWaveDriverCallback
  97. (
  98. LPMAPSTREAM pms,
  99. UINT uMsg,
  100. DWORD_PTR dw1,
  101. DWORD_PTR dw2
  102. )
  103. {
  104. BOOL f;
  105. //
  106. // invoke the callback function, if it exists. dwFlags contains
  107. // wave driver specific flags in the LOWORD and generic driver
  108. // flags in the HIWORD
  109. //
  110. if (0L == pms->dwCallback)
  111. return (FALSE);
  112. f = DriverCallback(pms->dwCallback, // user's callback DWORD
  113. HIWORD(pms->fdwOpen), // callback flags
  114. (HDRVR)pms->hwClient, // handle to the wave device
  115. uMsg, // the message
  116. pms->dwInstance, // user's instance data
  117. dw1, // first DWORD
  118. dw2); // second DWORD
  119. return (f);
  120. } // mapWaveDriverCallback()
  121. //
  122. // #ifndef WIN32
  123. // #if (WINVER <= 0x030A)
  124. // #pragma optimize("", on)
  125. // #endif
  126. // #endif
  127. //
  128. //--------------------------------------------------------------------------;
  129. //
  130. // void mapWaveCallback
  131. //
  132. // Description:
  133. //
  134. //
  135. // Arguments:
  136. // HWAVE hw:
  137. //
  138. // UINT uMsg:
  139. //
  140. // DWORD dwUser:
  141. //
  142. // DWORD dwParam1:
  143. //
  144. // DWORD dwParam2:
  145. //
  146. // Return (void):
  147. //
  148. // History:
  149. // 08/02/93 cjp [curtisp]
  150. //
  151. //--------------------------------------------------------------------------;
  152. #ifndef WIN32
  153. #pragma alloc_text(FIX_TEXT, mapWaveCallback)
  154. //
  155. // NOTE! we turn off optimization for Win 3.1 builds to keep the compiler
  156. // from using extended registers (we compile with -G3). it is not safe
  157. // in Win 3.1 to use extended registers at DriverCallback time unless we
  158. // save them ourselves. i don't feel like writing the assembler code for
  159. // that when it buys us almost nothing..
  160. //
  161. // everything is cool under Win 4.0 since DriverCallback is 386 aware.
  162. //
  163. #if (WINVER <= 0x030A)
  164. #pragma optimize("", off)
  165. #endif
  166. #endif
  167. EXTERN_C void FNCALLBACK mapWaveCallback
  168. (
  169. HWAVE hw,
  170. UINT uMsg,
  171. DWORD_PTR dwUser,
  172. DWORD_PTR dwParam1,
  173. DWORD_PTR dwParam2
  174. )
  175. {
  176. LPWAVEHDR pwh;
  177. LPMAPSTREAM pms;
  178. #if !defined(WIN32) && (WINVER <= 0x030A)
  179. _asm _emit 0x66 ; pushad
  180. _asm _emit 0x60
  181. #endif
  182. //
  183. // WARNING DANGER WARNING DANGER WARNING DANGER WARNING DANGER WARNING
  184. //
  185. // THIS IS AT INTERRUPT TIME--DO NOT CALL ANY FUNCTIONS THAT
  186. // YOU ARE NOT ABSOLUTELY SURE YOU CAN CALL AT INTERRUPT TIME!
  187. //
  188. // out debugging 'DPF' stuff is NOT interrupt safe
  189. //
  190. // WARNING DANGER WARNING DANGER WARNING DANGER WARNING DANGER WARNING
  191. //
  192. pms = (LPMAPSTREAM)dwUser;
  193. //
  194. //
  195. //
  196. switch (uMsg)
  197. {
  198. //
  199. // eat the WIM_OPEN and WIM_CLOSE messages for 'mapped' input
  200. // since we must deal with them specially (due to our background
  201. // task).
  202. //
  203. case WIM_OPEN:
  204. case WIM_CLOSE:
  205. if (NULL != pms->has)
  206. break;
  207. mapWaveDriverCallback(pms, uMsg, 0L, 0L);
  208. break;
  209. //
  210. // eat the WOM_OPEN and WOM_CLOSE messages for 'mapped' output
  211. // because we deal with them specially in mapWaveOpen and
  212. // mapWaveClose. See comments in those functions.
  213. //
  214. // note that we're checking pms->had, not pms->has, cuz this message
  215. // may come thru on the physical device open after we've decidec that
  216. // we wish to map (using the acm driver represented by had) but
  217. // before we've opened a stream (which would be represented by has).
  218. //
  219. case WOM_OPEN:
  220. case WOM_CLOSE:
  221. if (NULL != pms->had)
  222. break;
  223. mapWaveDriverCallback(pms, uMsg, 0L, 0L);
  224. break;
  225. //
  226. // dwParam1 is the 'shadow' LPWAVEHDR that is done.
  227. //
  228. case WOM_DONE:
  229. //
  230. // get the shadow header
  231. //
  232. pwh = (LPWAVEHDR)dwParam1;
  233. //
  234. // passthrough mode?
  235. //
  236. if (NULL != pms->has)
  237. {
  238. //
  239. // get the client's header and set done bit
  240. //
  241. pwh = (LPWAVEHDR)pwh->dwUser;
  242. pwh->dwFlags |= WHDR_DONE;
  243. pwh->dwFlags &= ~WHDR_INQUEUE;
  244. }
  245. //
  246. // nofify the client that the block is done
  247. //
  248. mapWaveDriverCallback(pms, WOM_DONE, (DWORD_PTR)pwh, 0);
  249. break;
  250. //
  251. // dwParam1 is the 'shadow' LPWAVEHDR that is done.
  252. //
  253. case WIM_DATA:
  254. //DPF(2, "WIM_DATA: callback");
  255. if (NULL == pms->has)
  256. {
  257. //
  258. // passthrough mode--notify the client that the block is
  259. // done
  260. //
  261. mapWaveDriverCallback(pms, WIM_DATA, dwParam1, 0L);
  262. break;
  263. }
  264. //
  265. // convert mode--convert data then callback user.
  266. //
  267. if (!PostAppMessage(pms->htaskInput, WIM_DATA, 0, dwParam1))
  268. {
  269. //
  270. // !!! ERROR what can we do....?
  271. //
  272. //DPF(0, "!WIM_DATA: XXXXXXXXXXX ERROR Post message failed XXXXXX");
  273. } else {
  274. #ifdef WIN32
  275. InterlockedIncrement((LPLONG)&pms->nOutstanding);
  276. #endif // WIN32
  277. }
  278. break;
  279. default:
  280. mapWaveDriverCallback(pms, uMsg, dwParam1, dwParam2);
  281. break;
  282. }
  283. #if !defined(WIN32) && (WINVER <= 0x030A)
  284. _asm _emit 0x66 ; popad
  285. _asm _emit 0x61
  286. #endif
  287. } // mapWaveCallback()
  288. #if !defined(WIN32) && (WINVER <= 0x030A)
  289. #pragma optimize("", on)
  290. #endif
  291. //==========================================================================;
  292. //
  293. //
  294. //
  295. //
  296. //==========================================================================;
  297. //--------------------------------------------------------------------------;
  298. //
  299. // MMRESULT mapWaveGetPosition
  300. //
  301. // Description:
  302. // Get the stream position in samples or bytes.
  303. //
  304. // Arguments:
  305. // LPMAPSTREAM pms:
  306. //
  307. // LPMMTIME pmmt: Pointer to an MMTIME structure.
  308. //
  309. // UINT uSize: Size of the MMTIME structure.
  310. //
  311. // Return (DWORD):
  312. //
  313. // History:
  314. // 07/19/93 cjp [curtisp]
  315. //
  316. //--------------------------------------------------------------------------;
  317. MMRESULT FNLOCAL mapWaveGetPosition
  318. (
  319. LPMAPSTREAM pms,
  320. LPMMTIME pmmt,
  321. UINT cbmmt
  322. )
  323. {
  324. MMRESULT mmr;
  325. DWORD dw;
  326. if (cbmmt < sizeof(MMTIME))
  327. {
  328. DPF(0, "!mapWaveGetPosition: bad size passed for MMTIME (%u)", cbmmt);
  329. return (MMSYSERR_ERROR);
  330. }
  331. if ((TIME_SAMPLES != pmmt->wType) && (TIME_BYTES != pmmt->wType))
  332. {
  333. DPF(1, "mapWaveGetPosition: time format %u?!? forcing TIME_BYTES!", pmmt->wType);
  334. pmmt->wType = TIME_BYTES;
  335. }
  336. //
  337. // get the position in samples or bytes..
  338. //
  339. // if an error occured .OR. we are passthrough mode (has is NULL)
  340. // then just return result--otherwise we need to convert the real
  341. // time to the client's time...
  342. //
  343. mmr = pms->fnWaveGetPosition(pms->hwReal, pmmt, cbmmt);
  344. if (MMSYSERR_NOERROR != mmr)
  345. {
  346. DPF(0, "!mapWaveGetPosition: physical get position failed? mmr=%u", mmr);
  347. return (mmr);
  348. }
  349. //
  350. // in passthrough mode?
  351. //
  352. if (NULL == pms->has)
  353. {
  354. return (mmr);
  355. }
  356. //
  357. // convert real time to client's time
  358. //
  359. switch (pmmt->wType)
  360. {
  361. case TIME_SAMPLES:
  362. dw = pmmt->u.sample;
  363. pmmt->u.sample = MulDivRN(dw,
  364. pms->pwfxClient->nSamplesPerSec,
  365. pms->pwfxReal->nSamplesPerSec);
  366. DPF(4, "GetPos(SAMPLES) real=%lu, client=%lu", dw, pmmt->u.sample);
  367. break;
  368. case TIME_BYTES:
  369. dw = pmmt->u.cb;
  370. pmmt->u.cb = MulDivRN(dw,
  371. pms->pwfxClient->nAvgBytesPerSec,
  372. pms->pwfxReal->nAvgBytesPerSec);
  373. DPF(4, "GetPos(BYTES) real=%lu, client=%lu", dw, pmmt->u.cb);
  374. break;
  375. default:
  376. DPF(0, "!mapWaveGetPosition() received unrecognized return format!");
  377. return (MMSYSERR_ERROR);
  378. }
  379. return (MMSYSERR_NOERROR);
  380. } // mapWaveGetPosition()
  381. //==========================================================================;
  382. //
  383. // Notes on error code priorities FrankYe 09/28/94
  384. //
  385. // The error code that is returned to the client and the error code
  386. // that is returned by internal functions are not always the same. The
  387. // primary reason for this is the way we handle MMSYSERR_ALLOCATED and
  388. // WAVERR_BADFORMAT in multiple device situations.
  389. //
  390. // For example, suppose we have two devices. If one returns ALLOCATED and
  391. // the other returns BADFORMAT then we prefer to return ALLOCATED to the
  392. // client because BADFORMAT implies no devices understand the format. So,
  393. // for the client, we prefer to return ALLOCATED over BADFORMAT.
  394. //
  395. // On the other hand, we want the mapper to be able to take advantage of
  396. // situations where all the devices are allocated. If all devices are
  397. // allocated then there is no need to continue trying to find a workable
  398. // map stream. So, for internal use, we prefer BADFORMAT over ALLOCATED.
  399. // That way if we see ALLOCATED then we know _all_ devices are allocated
  400. // and we can abort trying to create a map stream. (If the client sees
  401. // ALLOCATED, it only means that at least one device is allocated.)
  402. //
  403. // Client return codes are usually stored in the mmrClient member of the
  404. // MAPSTREAM structure. Internal return codes are returned via
  405. // function return values.
  406. //
  407. // Below are functions that prioritize error codes and update error codes
  408. // given the last err, the current err, and the priorities of the errs.
  409. // Notice that the prioritization of the err codes for the client is very
  410. // similar to for internal use. The only difference is the ordering of
  411. // MMSYSERR_ALLOCATED and WAVERR_BADFORMAT for reasons stated above.
  412. //
  413. //==========================================================================;
  414. //--------------------------------------------------------------------------;
  415. //
  416. // UINT mapErrGetClientPriority
  417. //
  418. // Description:
  419. //
  420. // Arguments:
  421. // MMRESULT mmr :
  422. //
  423. // Return (VOID):
  424. //
  425. // History:
  426. // 09/29/94 Frankye Created
  427. //
  428. //--------------------------------------------------------------------------;
  429. UINT FNLOCAL mapErrGetClientPriority( MMRESULT mmr )
  430. {
  431. switch (mmr)
  432. {
  433. case MMSYSERR_NOERROR:
  434. return 6;
  435. case MMSYSERR_ALLOCATED:
  436. return 5;
  437. case WAVERR_BADFORMAT:
  438. return 4;
  439. case WAVERR_SYNC:
  440. return 3;
  441. case MMSYSERR_NOMEM:
  442. return 2;
  443. default:
  444. return 1;
  445. case MMSYSERR_ERROR:
  446. return 0;
  447. }
  448. }
  449. //--------------------------------------------------------------------------;
  450. //
  451. // VOID mapErrSetClientError
  452. //
  453. // Description:
  454. //
  455. // Arguments:
  456. // LPMMRESULT lpmmr :
  457. //
  458. // MMRESULT mmr :
  459. //
  460. // Return (VOID):
  461. //
  462. // History:
  463. // 09/29/94 Frankye Created
  464. //
  465. //--------------------------------------------------------------------------;
  466. VOID FNLOCAL mapErrSetClientError( LPMMRESULT lpmmr, MMRESULT mmr )
  467. {
  468. if (mapErrGetClientPriority(mmr) > mapErrGetClientPriority(*lpmmr))
  469. {
  470. *lpmmr = mmr;
  471. }
  472. }
  473. //--------------------------------------------------------------------------;
  474. //
  475. // UINT mapErrGetPriority
  476. //
  477. // Description:
  478. //
  479. // Arguments:
  480. // MMRESULT mmr :
  481. //
  482. // Return (VOID):
  483. //
  484. // History:
  485. // 09/29/94 Frankye Created
  486. //
  487. //--------------------------------------------------------------------------;
  488. UINT FNLOCAL mapErrGetPriority( MMRESULT mmr )
  489. {
  490. switch (mmr)
  491. {
  492. case MMSYSERR_NOERROR:
  493. return 6;
  494. case WAVERR_BADFORMAT:
  495. return 5;
  496. case MMSYSERR_ALLOCATED:
  497. return 4;
  498. case WAVERR_SYNC:
  499. return 3;
  500. case MMSYSERR_NOMEM:
  501. return 2;
  502. default:
  503. return 1;
  504. case MMSYSERR_ERROR:
  505. return 0;
  506. }
  507. }
  508. //--------------------------------------------------------------------------;
  509. //
  510. // VOID mapErrSetError
  511. //
  512. // Description:
  513. //
  514. // Arguments:
  515. // LPMMRESULT lpmmr :
  516. //
  517. // MMRESULT mmr :
  518. //
  519. // Return (VOID):
  520. //
  521. // History:
  522. // 09/29/94 Frankye Created
  523. //
  524. //--------------------------------------------------------------------------;
  525. VOID FNLOCAL mapErrSetError( LPMMRESULT lpmmr, MMRESULT mmr )
  526. {
  527. if (mapErrGetPriority(mmr) > mapErrGetPriority(*lpmmr))
  528. {
  529. *lpmmr = mmr;
  530. }
  531. }
  532. //--------------------------------------------------------------------------;
  533. //
  534. // UINT mapDriverOpenWave
  535. //
  536. // Description:
  537. //
  538. //
  539. // Arguments:
  540. // LPMAPSTREAM pms:
  541. //
  542. // LPWAVEFORMATEX pwfx:
  543. //
  544. // Return (UINT):
  545. //
  546. //
  547. //--------------------------------------------------------------------------;
  548. UINT FNLOCAL mapDriverOpenWave
  549. (
  550. LPMAPSTREAM pms,
  551. LPWAVEFORMATEX pwfx
  552. )
  553. {
  554. MMRESULT mmr;
  555. MMRESULT mmrReturn;
  556. BOOL fPrefOnly;
  557. BOOL fQuery;
  558. UINT uPrefDevId;
  559. UINT uDevId;
  560. UINT cNumDevs;
  561. BOOL fTriedMappableId;
  562. BOOL fFoundNonmappableId;
  563. fQuery = (0 != (WAVE_FORMAT_QUERY & pms->fdwOpen));
  564. //
  565. // there are four different cases we need to handle when trying
  566. // to open a compatible wave device (for either input or output):
  567. //
  568. // 1. the normal case is 'no preference'--which means that
  569. // the user has selected '[none]' in the combo box for
  570. // the preferred wave device. in this case, gpag->uIdPreferredXXX
  571. // will be -1 (and gpag->fPreferredOnly is ignored).
  572. //
  573. // 2. the next two cases are when a device has been chosen as the
  574. // 'preferred device'--so gpag->uIdPreferredXXX will be the device
  575. // id of this preferred device. so the two cases are then:
  576. //
  577. // a. if gpag->pSettings->fPreferredOnly is FALSE, then try the
  578. // 'preferred' device first, and if that fails, try all
  579. // remaining devices.
  580. //
  581. // b. if gpag->pSettings->fPreferredOnly is TRUE, then we will
  582. // ONLY try the preferred device--if that fails, we do NOT
  583. // continue.
  584. //
  585. // 3. a device ID to which the mapper should map may have been
  586. // specified using the WAVE_MAPPED flag.
  587. //
  588. //
  589. //
  590. // --== See if we are supposed to map to a specified device ==--
  591. //
  592. //
  593. if (pms->fdwOpen & WAVE_MAPPED)
  594. {
  595. DWORD fdwOpen;
  596. DPF(3, "mapDriverOpenWave: WAVE_MAPPED flag specified");
  597. //
  598. // The device ID to which to map was specified by MMSYSTEM in the
  599. // uMappedDeviceID member of the WAVEOPENDESC structure passed in
  600. // the WODM_OPEN message. It was saved in pms->uMappedDeviceID by
  601. // mapWaveOpen().
  602. //
  603. uDevId = pms->uMappedDeviceID;
  604. fdwOpen = CALLBACK_FUNCTION | LOWORD(pms->fdwOpen);
  605. fdwOpen &= ~WAVE_MAPPED;
  606. mmrReturn = pms->fnWaveOpen(&pms->hwReal,
  607. uDevId,
  608. pwfx,
  609. (DWORD_PTR)mapWaveCallback,
  610. (DWORD_PTR)pms,
  611. fdwOpen);
  612. DPF(3, "--->opening device %d--mmr=%u", uDevId, mmrReturn);
  613. if (MMSYSERR_NOERROR == mmrReturn)
  614. {
  615. pms->uIdReal = uDevId;
  616. }
  617. mapErrSetClientError(&pms->mmrClient, mmrReturn);
  618. return (mmrReturn);
  619. }
  620. //
  621. // --== ==--
  622. //
  623. //
  624. // Init some local vars
  625. //
  626. WAIT_FOR_MUTEX(gpag->hMutexSettings);
  627. if (pms->fInput)
  628. {
  629. uPrefDevId = gpag->pSettings->uIdPreferredIn;
  630. cNumDevs = gpag->cWaveInDevs;
  631. }
  632. else
  633. {
  634. uPrefDevId = gpag->pSettings->uIdPreferredOut;
  635. cNumDevs = gpag->cWaveOutDevs;
  636. }
  637. fTriedMappableId = FALSE;
  638. fFoundNonmappableId = FALSE;
  639. fPrefOnly = (WAVE_MAPPER == uPrefDevId) ? FALSE : gpag->pSettings->fPreferredOnly;
  640. mmrReturn = MMSYSERR_ERROR;
  641. RELEASE_MUTEX(gpag->hMutexSettings);
  642. //
  643. // --== If we have a prefered device Id, then try opening it ==--
  644. //
  645. if (WAVE_MAPPER != uPrefDevId)
  646. {
  647. mmr = MMSYSERR_NOERROR;
  648. if (!fQuery)
  649. {
  650. mmr = pms->fnWaveOpen(&pms->hwReal,
  651. uPrefDevId,
  652. pwfx,
  653. 0L,
  654. 0L,
  655. WAVE_FORMAT_QUERY | LOWORD(pms->fdwOpen));
  656. DPF(4, "---> querying preferred device %d--mmr=%u", uPrefDevId, mmr);
  657. DPF(4, "---> opened with flags = %08lx", WAVE_FORMAT_QUERY | LOWORD(pms->fdwOpen));
  658. }
  659. if (MMSYSERR_NOERROR == mmr)
  660. {
  661. mmr = pms->fnWaveOpen(&pms->hwReal,
  662. uPrefDevId,
  663. pwfx,
  664. (DWORD_PTR)mapWaveCallback,
  665. (DWORD_PTR)pms,
  666. CALLBACK_FUNCTION | LOWORD(pms->fdwOpen));
  667. }
  668. DPF(3, "---> opening preferred device %d--mmr=%u", uPrefDevId, mmr);
  669. DPF(3, "---> opened with flags = %08lx", CALLBACK_FUNCTION | LOWORD(pms->fdwOpen));
  670. mapErrSetClientError(&pms->mmrClient, mmr);
  671. mapErrSetError(&mmrReturn, mmr);
  672. if ((WAVERR_SYNC == mmr) && (fPrefOnly || (1 == cNumDevs)))
  673. {
  674. WAIT_FOR_MUTEX(gpag->hMutexSettings);
  675. if (pms->fInput)
  676. {
  677. DPF(1, "--->preferred only INPUT device is SYNCRONOUS!");
  678. gpag->pSettings->fSyncOnlyIn = TRUE;
  679. }
  680. else
  681. {
  682. DPF(1, "--->preferred only OUTPUT device is SYNCRONOUS!");
  683. gpag->pSettings->fSyncOnlyOut = TRUE;
  684. }
  685. RELEASE_MUTEX(gpag->hMutexSettings);
  686. return (mmrReturn);
  687. }
  688. if ((MMSYSERR_NOERROR == mmr) || fPrefOnly)
  689. {
  690. if (MMSYSERR_NOERROR == mmr)
  691. {
  692. pms->uIdReal = uPrefDevId;
  693. }
  694. return (mmrReturn);
  695. }
  696. fTriedMappableId = TRUE;
  697. }
  698. //
  699. // The prefered ID didn't work. Now we will step through each device
  700. // ID and try to open it. We'll skip the uPrefDevId since we already
  701. // tried it above. We will also skip device IDs that are not mappable
  702. // devices (determined by sending DRV_QUERYMAPPABLE to the ID).
  703. //
  704. for (uDevId = 0; uDevId < cNumDevs; uDevId++)
  705. {
  706. if (uDevId == uPrefDevId)
  707. continue;
  708. mmr = pms->fnWaveMessage((HWAVE)LongToHandle(uDevId), DRV_QUERYMAPPABLE, 0L, 0L);
  709. if (MMSYSERR_NOERROR != mmr)
  710. {
  711. DPF(3, "--->skipping non-mappable device %d", uDevId);
  712. fFoundNonmappableId = TRUE;
  713. continue;
  714. }
  715. if (!fQuery)
  716. {
  717. mmr = pms->fnWaveOpen(&pms->hwReal,
  718. uDevId,
  719. pwfx,
  720. 0L,
  721. 0L,
  722. WAVE_FORMAT_QUERY | LOWORD(pms->fdwOpen));
  723. DPF(4, "---> querying device %d--mmr=%u", uDevId, mmr);
  724. }
  725. if (MMSYSERR_NOERROR == mmr)
  726. {
  727. mmr = pms->fnWaveOpen(&pms->hwReal,
  728. uDevId,
  729. pwfx,
  730. (DWORD_PTR)mapWaveCallback,
  731. (DWORD_PTR)pms,
  732. CALLBACK_FUNCTION | LOWORD(pms->fdwOpen));
  733. DPF(3, "---> opening device %d--mmr=%u", uDevId, mmr);
  734. }
  735. mapErrSetClientError(&pms->mmrClient, mmr);
  736. mapErrSetError( &mmrReturn, mmr );
  737. if (MMSYSERR_NOERROR == mmr)
  738. {
  739. pms->uIdReal = uDevId;
  740. return (mmrReturn);
  741. }
  742. fTriedMappableId = TRUE;
  743. }
  744. if (fFoundNonmappableId && !fTriedMappableId)
  745. {
  746. mapErrSetClientError(&pms->mmrClient, MMSYSERR_ALLOCATED);
  747. mapErrSetError(&mmrReturn, MMSYSERR_ALLOCATED);
  748. }
  749. return (mmrReturn);
  750. } // mapDriverOpenWave()
  751. //--------------------------------------------------------------------------;
  752. //
  753. // BOOL FindBestPCMFormat
  754. //
  755. // Description:
  756. //
  757. //
  758. // Arguments:
  759. // LPWAVEFORMATEX pwfx:
  760. //
  761. // LPWAVEFORMATEX pwfPCM:
  762. //
  763. // BOOL fInput:
  764. //
  765. // UINT uDeviceId:
  766. //
  767. //
  768. // Return (BOOL):
  769. //
  770. // History:
  771. // 03/13/94 fdy [frankye]
  772. // Expanded interface and function to take uDeviceId which specifies
  773. // the wave device for which we want to FindBestPCMFormat. fInput
  774. // specifies whether this device is an input or output device.
  775. //
  776. //
  777. //--------------------------------------------------------------------------;
  778. BOOL FNLOCAL FindBestPCMFormat
  779. (
  780. LPWAVEFORMATEX pwfx,
  781. LPWAVEFORMATEX pwfxPCM,
  782. BOOL fInput,
  783. UINT uDeviceId
  784. )
  785. {
  786. BYTE bChannels;
  787. BYTE bBitsPerSample;
  788. UINT uBlockAlign;
  789. UINT i, j;
  790. UINT w;
  791. UINT uNeededBits;
  792. DWORD dwPrevError;
  793. DWORD dwError;
  794. DWORD dwSamplesPerSec;
  795. UINT uFlags;
  796. //
  797. // -= the PCM mis-mapper =-
  798. //
  799. // i'm sure this will generate all sorts of neat bug reports and
  800. // complaints, but this is the algorithm we use to choose a PCM
  801. // format:
  802. //
  803. // o we regard stereo as very important to maintain. the reason
  804. // for this is that if a file was authored as stereo, there
  805. // was probably a good reason for doing so...
  806. //
  807. // o the next most important component is the sample frequency;
  808. // we try to find the closest supported sample frequency
  809. //
  810. // o finally, we don't care about bits per sample
  811. // so we'll try to maintain the input size and change it if
  812. // we need to
  813. //
  814. dwSamplesPerSec = pwfx->nSamplesPerSec;
  815. bChannels = (BYTE)pwfx->nChannels;
  816. //
  817. // build a bit pattern that we can look for..
  818. //
  819. findbest_Loop:
  820. uNeededBits = ZYZPCMF_OUT_M08 | ZYZPCMF_OUT_M16;
  821. if (bChannels == 2)
  822. uNeededBits <<= 1;
  823. if (fInput)
  824. uNeededBits <<= 8;
  825. dwPrevError = (DWORD)-1;
  826. //
  827. // first find the closest sample rate that supports the current number
  828. // of channels
  829. //
  830. for (j = (UINT)-1, i = 0; gaPCMFormats[i].uSamplesPerSec; i++)
  831. {
  832. //
  833. // if no bits that we are looking for are set, then continue
  834. // searching--if any of our bits are set, then check if this
  835. // sample rate is better than our previous choice...
  836. //
  837. uFlags = fInput ? gaPCMFormats[i].uFlagsInput[uDeviceId] : gaPCMFormats[i].uFlagsOutput[uDeviceId];
  838. if (uFlags & uNeededBits)
  839. {
  840. if (dwSamplesPerSec > (DWORD)gaPCMFormats[i].uSamplesPerSec)
  841. dwError = dwSamplesPerSec - gaPCMFormats[i].uSamplesPerSec;
  842. else
  843. dwError = (DWORD)gaPCMFormats[i].uSamplesPerSec - dwSamplesPerSec;
  844. if (dwError < dwPrevError)
  845. {
  846. j = i;
  847. dwPrevError = dwError;
  848. }
  849. }
  850. }
  851. //
  852. // if we didn't find a format that will work, then shift the channels
  853. // around and try again...
  854. //
  855. if (j == (UINT)-1)
  856. {
  857. //
  858. // if we already tried channel shifting, then we're hosed... this
  859. // would probably mean that no wave devices are installed that
  860. // can go in fInput... like if the person only has the PC
  861. // Squeaker--you cannot record...
  862. //
  863. if ((BYTE)pwfx->nChannels != bChannels)
  864. {
  865. DPF(0, "!FindBestPCMFormat: failed to find suitable format!");
  866. return (FALSE);
  867. }
  868. //
  869. // shift the channels and try again
  870. //
  871. bChannels = (bChannels == (BYTE)2) ? (BYTE)1 : (BYTE)2;
  872. goto findbest_Loop;
  873. }
  874. //
  875. // j = the index to the format that we should be using
  876. // uNeededBits = the bits used to find 'j'
  877. // fInput = the direction we are trying to go with the data
  878. // bChannels = the number of channels that we need to use
  879. //
  880. uFlags = fInput ? gaPCMFormats[j].uFlagsInput[uDeviceId] : gaPCMFormats[j].uFlagsOutput[uDeviceId];
  881. w = uFlags & uNeededBits;
  882. //
  883. // normalize our bits to Mono Output--relative bit positions are the
  884. // same for input/output stereo/mono
  885. //
  886. if (fInput)
  887. w >>= 8;
  888. if (bChannels == 2)
  889. w >>= 1;
  890. //
  891. // if both 8 and 16 bit are supported by the out device AND the source
  892. // format is PCM, then use the one that matches the source format
  893. //
  894. if ((pwfx->wFormatTag == WAVE_FORMAT_PCM) && ((w & ZYZPCMF_OUT_MONO) == ZYZPCMF_OUT_MONO))
  895. {
  896. bBitsPerSample = (BYTE)pwfx->wBitsPerSample;
  897. }
  898. //
  899. // either not PCM source or device does not support both 8 and 16 bit;
  900. // so choose whatever is available for the destination
  901. //
  902. else
  903. {
  904. bBitsPerSample = (w & ZYZPCMF_OUT_M16) ? (BYTE)16 : (BYTE)8;
  905. }
  906. dwSamplesPerSec = gaPCMFormats[j].uSamplesPerSec;
  907. uBlockAlign = ((bBitsPerSample >> 3) << (bChannels >> 1));
  908. //
  909. // finally fill in the PCM destination format structure with the PCM
  910. // format we decided is 'best'
  911. //
  912. pwfxPCM->wFormatTag = WAVE_FORMAT_PCM;
  913. pwfxPCM->nChannels = bChannels;
  914. pwfxPCM->nBlockAlign = (WORD)uBlockAlign;
  915. pwfxPCM->nSamplesPerSec = dwSamplesPerSec;
  916. pwfxPCM->nAvgBytesPerSec = dwSamplesPerSec * uBlockAlign;
  917. pwfxPCM->wBitsPerSample = bBitsPerSample;
  918. return (TRUE);
  919. } // FindBestPCMFormat()
  920. //==========================================================================;
  921. //
  922. //
  923. //
  924. //
  925. //==========================================================================;
  926. //--------------------------------------------------------------------------;
  927. //
  928. // MMRESULT mapDriverFindMethod0
  929. //
  930. // Description:
  931. //
  932. //
  933. // Arguments:
  934. // LPMAPSTREAM pms:
  935. //
  936. // Return (MMRESULT):
  937. //
  938. // History:
  939. // 08/04/93 cjp [curtisp]
  940. //
  941. //--------------------------------------------------------------------------;
  942. MMRESULT FNLOCAL mapDriverFindMethod0
  943. (
  944. LPMAPSTREAM pms
  945. )
  946. {
  947. MMRESULT mmr;
  948. //
  949. // suggest anything!
  950. //
  951. mmr = acmFormatSuggest(pms->had,
  952. pms->pwfxClient,
  953. pms->pwfxReal,
  954. pms->cbwfxReal,
  955. 0L);
  956. if (MMSYSERR_NOERROR == mmr)
  957. {
  958. //
  959. // can it open real time?
  960. //
  961. mmr = acmStreamOpen(NULL,
  962. pms->had,
  963. pms->pwfxSrc,
  964. pms->pwfxDst,
  965. NULL,
  966. 0L,
  967. 0L,
  968. ACM_STREAMOPENF_QUERY);
  969. if (MMSYSERR_NOERROR != mmr)
  970. {
  971. return (WAVERR_BADFORMAT);
  972. }
  973. mmr = mapDriverOpenWave(pms, pms->pwfxReal);
  974. }
  975. else
  976. {
  977. mmr = WAVERR_BADFORMAT;
  978. }
  979. return (mmr);
  980. } // mapDriverFindMethod0()
  981. //--------------------------------------------------------------------------;
  982. //
  983. // MMRESULT mapDriverFindMethod1
  984. //
  985. // Description:
  986. //
  987. //
  988. // Arguments:
  989. // LPMAPSTREAM pms:
  990. //
  991. // Return (MMRESULT):
  992. //
  993. // History:
  994. // 08/04/93 cjp [curtisp]
  995. //
  996. //--------------------------------------------------------------------------;
  997. MMRESULT FNLOCAL mapDriverFindMethod1
  998. (
  999. LPMAPSTREAM pms
  1000. )
  1001. {
  1002. MMRESULT mmr;
  1003. //
  1004. // suggest PCM format for the Client
  1005. //
  1006. pms->pwfxReal->wFormatTag = WAVE_FORMAT_PCM;
  1007. mmr = acmFormatSuggest(pms->had,
  1008. pms->pwfxClient,
  1009. pms->pwfxReal,
  1010. pms->cbwfxReal,
  1011. ACM_FORMATSUGGESTF_WFORMATTAG);
  1012. if (MMSYSERR_NOERROR == mmr)
  1013. {
  1014. //
  1015. // can it open real time?
  1016. //
  1017. mmr = acmStreamOpen(NULL,
  1018. pms->had,
  1019. pms->pwfxSrc,
  1020. pms->pwfxDst,
  1021. NULL,
  1022. 0L,
  1023. 0L,
  1024. ACM_STREAMOPENF_QUERY);
  1025. if (MMSYSERR_NOERROR != mmr)
  1026. {
  1027. return (WAVERR_BADFORMAT);
  1028. }
  1029. mmr = mapDriverOpenWave(pms, pms->pwfxReal);
  1030. }
  1031. else
  1032. {
  1033. mmr = WAVERR_BADFORMAT;
  1034. }
  1035. return (mmr);
  1036. } // mapDriverFindMethod1()
  1037. //--------------------------------------------------------------------------;
  1038. //
  1039. // MMRESULT mapDriverFindMethod2
  1040. //
  1041. // Description:
  1042. //
  1043. //
  1044. // Arguments:
  1045. // LPMAPSTREAM pms:
  1046. //
  1047. // Return (MMRESULT):
  1048. //
  1049. // History:
  1050. // 08/04/93 cjp [curtisp]
  1051. //
  1052. //--------------------------------------------------------------------------;
  1053. MMRESULT FNLOCAL mapDriverFindMethod2
  1054. (
  1055. LPMAPSTREAM pms
  1056. )
  1057. {
  1058. MMRESULT mmr;
  1059. //
  1060. // suggest MONO PCM format for the Client
  1061. //
  1062. pms->pwfxReal->wFormatTag = WAVE_FORMAT_PCM;
  1063. pms->pwfxReal->nChannels = 1;
  1064. mmr = acmFormatSuggest(pms->had,
  1065. pms->pwfxClient,
  1066. pms->pwfxReal,
  1067. pms->cbwfxReal,
  1068. ACM_FORMATSUGGESTF_WFORMATTAG |
  1069. ACM_FORMATSUGGESTF_NCHANNELS);
  1070. if (MMSYSERR_NOERROR == mmr)
  1071. {
  1072. //
  1073. // can it open real time?
  1074. //
  1075. mmr = acmStreamOpen(NULL,
  1076. pms->had,
  1077. pms->pwfxSrc,
  1078. pms->pwfxDst,
  1079. NULL,
  1080. 0L,
  1081. 0L,
  1082. ACM_STREAMOPENF_QUERY);
  1083. if (MMSYSERR_NOERROR != mmr)
  1084. {
  1085. return (WAVERR_BADFORMAT);
  1086. }
  1087. mmr = mapDriverOpenWave(pms, pms->pwfxReal);
  1088. }
  1089. else
  1090. {
  1091. mmr = WAVERR_BADFORMAT;
  1092. }
  1093. return (mmr);
  1094. } // mapDriverFindMethod2()
  1095. //--------------------------------------------------------------------------;
  1096. //
  1097. // MMRESULT mapDriverFindMethod3
  1098. //
  1099. // Description:
  1100. //
  1101. //
  1102. // Arguments:
  1103. // LPMAPSTREAM pms:
  1104. //
  1105. // Return (MMRESULT):
  1106. //
  1107. // History:
  1108. // 08/04/93 cjp [curtisp]
  1109. //
  1110. //--------------------------------------------------------------------------;
  1111. MMRESULT FNLOCAL mapDriverFindMethod3
  1112. (
  1113. LPMAPSTREAM pms
  1114. )
  1115. {
  1116. MMRESULT mmr;
  1117. //
  1118. // suggest 8 bit PCM format for the Client
  1119. //
  1120. pms->pwfxReal->wFormatTag = WAVE_FORMAT_PCM;
  1121. pms->pwfxReal->wBitsPerSample = 8;
  1122. mmr = acmFormatSuggest(pms->had,
  1123. pms->pwfxClient,
  1124. pms->pwfxReal,
  1125. pms->cbwfxReal,
  1126. ACM_FORMATSUGGESTF_WFORMATTAG |
  1127. ACM_FORMATSUGGESTF_WBITSPERSAMPLE);
  1128. if (MMSYSERR_NOERROR == mmr)
  1129. {
  1130. //
  1131. // can it open real time?
  1132. //
  1133. mmr = acmStreamOpen(NULL,
  1134. pms->had,
  1135. pms->pwfxSrc,
  1136. pms->pwfxDst,
  1137. NULL,
  1138. 0L,
  1139. 0L,
  1140. ACM_STREAMOPENF_QUERY);
  1141. if (MMSYSERR_NOERROR != mmr)
  1142. {
  1143. return (WAVERR_BADFORMAT);
  1144. }
  1145. mmr = mapDriverOpenWave(pms, pms->pwfxReal);
  1146. }
  1147. else
  1148. {
  1149. mmr = WAVERR_BADFORMAT;
  1150. }
  1151. return (mmr);
  1152. } // mapDriverFindMethod3()
  1153. //--------------------------------------------------------------------------;
  1154. //
  1155. // MMRESULT mapDriverFindMethod4
  1156. //
  1157. // Description:
  1158. //
  1159. //
  1160. // Arguments:
  1161. // LPMAPSTREAM pms:
  1162. //
  1163. // Return (MMRESULT):
  1164. //
  1165. // History:
  1166. // 08/04/93 cjp [curtisp]
  1167. //
  1168. //--------------------------------------------------------------------------;
  1169. MMRESULT FNLOCAL mapDriverFindMethod4
  1170. (
  1171. LPMAPSTREAM pms
  1172. )
  1173. {
  1174. MMRESULT mmr;
  1175. //
  1176. // suggest 8 bit MONO PCM format for the Client
  1177. //
  1178. pms->pwfxReal->wFormatTag = WAVE_FORMAT_PCM;
  1179. pms->pwfxReal->nChannels = 1;
  1180. pms->pwfxReal->wBitsPerSample = 8;
  1181. mmr = acmFormatSuggest(pms->had,
  1182. pms->pwfxClient,
  1183. pms->pwfxReal,
  1184. pms->cbwfxReal,
  1185. ACM_FORMATSUGGESTF_WFORMATTAG |
  1186. ACM_FORMATSUGGESTF_NCHANNELS |
  1187. ACM_FORMATSUGGESTF_WBITSPERSAMPLE);
  1188. if (MMSYSERR_NOERROR == mmr)
  1189. {
  1190. //
  1191. // can it open real time?
  1192. //
  1193. mmr = acmStreamOpen(NULL,
  1194. pms->had,
  1195. pms->pwfxSrc,
  1196. pms->pwfxDst,
  1197. NULL,
  1198. 0L,
  1199. 0L,
  1200. ACM_STREAMOPENF_QUERY);
  1201. if (MMSYSERR_NOERROR != mmr)
  1202. {
  1203. return (WAVERR_BADFORMAT);
  1204. }
  1205. mmr = mapDriverOpenWave(pms, pms->pwfxReal);
  1206. }
  1207. else
  1208. {
  1209. mmr = WAVERR_BADFORMAT;
  1210. }
  1211. return (mmr);
  1212. } // mapDriverFindMethod4()
  1213. //--------------------------------------------------------------------------;
  1214. //
  1215. // MMRESULT mapDriverFindMethod5
  1216. //
  1217. // Description:
  1218. //
  1219. //
  1220. // Arguments:
  1221. // LPMAPSTREAM pms:
  1222. //
  1223. // Return (MMRESULT):
  1224. //
  1225. // History:
  1226. // 08/04/93 cjp [curtisp]
  1227. // 03/13/94 fdy [frankye]
  1228. // Modified function to first try to find the best pcm format for
  1229. // the prefered device, and if that fails, then try for each wave
  1230. // device that exists in the system.
  1231. //
  1232. //--------------------------------------------------------------------------;
  1233. MMRESULT FNLOCAL mapDriverFindMethod5
  1234. (
  1235. LPMAPSTREAM pms
  1236. )
  1237. {
  1238. MMRESULT mmr;
  1239. BOOL f;
  1240. UINT uPrefDevId;
  1241. UINT cNumDevs;
  1242. BOOL fPrefOnly;
  1243. UINT i;
  1244. //
  1245. //
  1246. //
  1247. WAIT_FOR_MUTEX(gpag->hMutexSettings);
  1248. if (pms->fInput)
  1249. {
  1250. uPrefDevId = gpag->pSettings->uIdPreferredIn;
  1251. cNumDevs = gpag->cWaveInDevs;
  1252. }
  1253. else
  1254. {
  1255. uPrefDevId = gpag->pSettings->uIdPreferredOut;
  1256. cNumDevs = gpag->cWaveOutDevs;
  1257. }
  1258. fPrefOnly = (WAVE_MAPPER == uPrefDevId) ? FALSE : gpag->pSettings->fPreferredOnly;
  1259. //
  1260. //
  1261. //
  1262. mmr = WAVERR_BADFORMAT;
  1263. if ((-1) != uPrefDevId)
  1264. {
  1265. f = FindBestPCMFormat(pms->pwfxClient, pms->pwfxReal, pms->fInput, uPrefDevId);
  1266. if (f)
  1267. {
  1268. mmr = acmStreamOpen(NULL,
  1269. pms->had,
  1270. pms->pwfxSrc,
  1271. pms->pwfxDst,
  1272. NULL,
  1273. 0L,
  1274. 0L,
  1275. ACM_STREAMOPENF_QUERY);
  1276. if (MMSYSERR_NOERROR == mmr)
  1277. {
  1278. mmr = mapDriverOpenWave(pms, pms->pwfxReal);
  1279. }
  1280. else
  1281. {
  1282. mmr = WAVERR_BADFORMAT;
  1283. }
  1284. }
  1285. }
  1286. if ( (MMSYSERR_NOERROR != mmr) && (!fPrefOnly) )
  1287. {
  1288. for (i=0; i < cNumDevs; i++)
  1289. {
  1290. if (i == uPrefDevId)
  1291. {
  1292. //
  1293. // Already tried this one.
  1294. //
  1295. continue;
  1296. }
  1297. f = FindBestPCMFormat(pms->pwfxClient, pms->pwfxReal, pms->fInput, i);
  1298. if (f)
  1299. {
  1300. mmr = acmStreamOpen(NULL,
  1301. pms->had,
  1302. pms->pwfxSrc,
  1303. pms->pwfxDst,
  1304. NULL,
  1305. 0L,
  1306. 0L,
  1307. ACM_STREAMOPENF_QUERY);
  1308. if (MMSYSERR_NOERROR == mmr)
  1309. {
  1310. mmr = mapDriverOpenWave(pms, pms->pwfxReal);
  1311. }
  1312. else
  1313. {
  1314. mmr = WAVERR_BADFORMAT;
  1315. }
  1316. }
  1317. if (MMSYSERR_NOERROR == mmr)
  1318. {
  1319. break;
  1320. }
  1321. }
  1322. }
  1323. RELEASE_MUTEX(gpag->hMutexSettings);
  1324. return (mmr);
  1325. } // mapDriverFindMethod5()
  1326. //--------------------------------------------------------------------------;
  1327. //
  1328. // BOOL mapDriverEnumCallback
  1329. //
  1330. // Description:
  1331. //
  1332. //
  1333. // Arguments:
  1334. // HACMDRIVERID hadid:
  1335. //
  1336. // DWORD_PTR dwInstance:
  1337. //
  1338. // DWORD fdwSupport:
  1339. //
  1340. // Return (BOOL):
  1341. //
  1342. // History:
  1343. // 09/18/93 cjp [curtisp]
  1344. //
  1345. //--------------------------------------------------------------------------;
  1346. BOOL FNCALLBACK mapDriverEnumCallback
  1347. (
  1348. HACMDRIVERID hadid,
  1349. DWORD_PTR dwInstance,
  1350. DWORD fdwSupport
  1351. )
  1352. {
  1353. LPMAPSTREAM pms;
  1354. MMRESULT mmr;
  1355. ACMFORMATTAGDETAILS aftd;
  1356. pms = (LPMAPSTREAM)dwInstance;
  1357. //
  1358. // check if support required
  1359. //
  1360. if (0 == (pms->fdwSupport & fdwSupport))
  1361. {
  1362. //
  1363. // skip to next driver..
  1364. //
  1365. return (TRUE);
  1366. }
  1367. aftd.cbStruct = sizeof(aftd);
  1368. aftd.dwFormatTag = pms->pwfxClient->wFormatTag;
  1369. aftd.fdwSupport = 0L;
  1370. mmr = acmFormatTagDetails((HACMDRIVER)hadid,
  1371. &aftd,
  1372. ACM_FORMATTAGDETAILSF_FORMATTAG);
  1373. if (MMSYSERR_NOERROR != mmr)
  1374. {
  1375. return (TRUE);
  1376. }
  1377. if (0 == (pms->fdwSupport & aftd.fdwSupport))
  1378. {
  1379. return (TRUE);
  1380. }
  1381. mmr = acmDriverOpen(&pms->had, hadid, 0L);
  1382. if (MMSYSERR_NOERROR != mmr)
  1383. {
  1384. return (TRUE);
  1385. }
  1386. switch (pms->uHeuristic)
  1387. {
  1388. case 0:
  1389. //
  1390. // try 'any' suggested destination
  1391. //
  1392. mmr = mapDriverFindMethod0(pms);
  1393. break;
  1394. case 1:
  1395. //
  1396. // try 'any PCM' suggested destination
  1397. //
  1398. mmr = mapDriverFindMethod1(pms);
  1399. break;
  1400. case 2:
  1401. //
  1402. // try 'any mono PCM' suggested destination
  1403. //
  1404. mmr = mapDriverFindMethod2(pms);
  1405. break;
  1406. case 3:
  1407. //
  1408. // try 'any 8 bit PCM' suggested destination
  1409. //
  1410. mmr = mapDriverFindMethod3(pms);
  1411. break;
  1412. case 4:
  1413. //
  1414. // try 'any mono 8 bit PCM' suggested destination
  1415. //
  1416. mmr = mapDriverFindMethod4(pms);
  1417. break;
  1418. case 5:
  1419. //
  1420. // search for best PCM format available by wave hardware
  1421. //
  1422. mmr = mapDriverFindMethod5(pms);
  1423. break;
  1424. }
  1425. pms->mmrClient = mmr;
  1426. if (MMSYSERR_NOERROR == mmr)
  1427. {
  1428. return (FALSE);
  1429. }
  1430. acmDriverClose(pms->had, 0L);
  1431. pms->had = NULL;
  1432. return (TRUE);
  1433. } // mapDriverEnumCallback()
  1434. //--------------------------------------------------------------------------;
  1435. //
  1436. // MMRESULT FindConverterMatch
  1437. //
  1438. // Description:
  1439. // Test all drivers to see if one can convert the requested format
  1440. // into a format supported by an available wave device
  1441. //
  1442. // Arguments:
  1443. // LPMAPSTREAM pms:
  1444. //
  1445. // Return (MMRESULT):
  1446. //
  1447. // History:
  1448. // 06/15/93 cjp [curtisp]
  1449. //
  1450. //--------------------------------------------------------------------------;
  1451. MMRESULT FNLOCAL FindConverterMatch
  1452. (
  1453. LPMAPSTREAM pms
  1454. )
  1455. {
  1456. MMRESULT mmr;
  1457. int iHeuristic;
  1458. DWORD fdwSupport;
  1459. //
  1460. // for the 'suggest PCM ' passes, allow what is needed
  1461. //
  1462. if (WAVE_FORMAT_PCM == pms->pwfxClient->wFormatTag)
  1463. {
  1464. fdwSupport = ACMDRIVERDETAILS_SUPPORTF_CONVERTER;
  1465. }
  1466. else
  1467. {
  1468. fdwSupport = ACMDRIVERDETAILS_SUPPORTF_CODEC;
  1469. }
  1470. //
  1471. //
  1472. //
  1473. //
  1474. //
  1475. pms->mmrClient = WAVERR_BADFORMAT;
  1476. pms->had = NULL;
  1477. for (iHeuristic = 0; iHeuristic < MAX_HEURISTIC; iHeuristic++)
  1478. {
  1479. pms->uHeuristic = iHeuristic;
  1480. if (0 == iHeuristic)
  1481. {
  1482. //
  1483. // for the 'suggest anything' pass, allow converters and codecs
  1484. //
  1485. pms->fdwSupport = ACMDRIVERDETAILS_SUPPORTF_CONVERTER |
  1486. ACMDRIVERDETAILS_SUPPORTF_CODEC;
  1487. }
  1488. else
  1489. {
  1490. //
  1491. // for the 'suggest PCM ' passes, allow what is needed
  1492. //
  1493. pms->fdwSupport = fdwSupport;
  1494. }
  1495. mmr = acmDriverEnum(mapDriverEnumCallback, (DWORD_PTR)pms, 0L);
  1496. if (MMSYSERR_NOERROR == mmr)
  1497. {
  1498. if (NULL != pms->had)
  1499. {
  1500. return (MMSYSERR_NOERROR);
  1501. }
  1502. }
  1503. }
  1504. return (pms->mmrClient);
  1505. } // FindConverterMatch()
  1506. //==========================================================================;
  1507. //
  1508. //
  1509. //
  1510. //
  1511. //==========================================================================;
  1512. //--------------------------------------------------------------------------;
  1513. //
  1514. // DWORD mapWaveClose
  1515. //
  1516. // Description:
  1517. //
  1518. //
  1519. // Arguments:
  1520. // LPMAPSTREAM pms:
  1521. //
  1522. // Return (DWORD):
  1523. //
  1524. // History:
  1525. // 06/15/93 cjp [curtisp]
  1526. //
  1527. //--------------------------------------------------------------------------;
  1528. DWORD FNLOCAL mapWaveClose
  1529. (
  1530. LPMAPSTREAM pms
  1531. )
  1532. {
  1533. MMRESULT mmr;
  1534. //
  1535. //
  1536. //
  1537. mmr = pms->fnWaveClose(pms->hwReal);
  1538. if (MMSYSERR_NOERROR != mmr)
  1539. {
  1540. DPF(0, "!mapWaveClose: physical device failed close! mmr=%u", mmr);
  1541. return (mmr);
  1542. }
  1543. //
  1544. // if this is input and its background task is alive, kill it
  1545. //
  1546. if (pms->fInput && (0 != pms->htaskInput))
  1547. {
  1548. #ifdef WIN32
  1549. PostAppMessage(pms->htaskInput, WM_QUIT, 0, 0L);
  1550. WaitForSingleObject(pms->hInput, INFINITE);
  1551. CloseHandle(pms->hInput);
  1552. CloseHandle(pms->hStoppedEvent);
  1553. #else
  1554. if ((0 == gpag->cInputStreams) || (NULL == gpag->htaskInput))
  1555. {
  1556. DPF(0, "!input mapping htask=%.04Xh, reference count=%u?!?",
  1557. gpag->htaskInput, gpag->cInputStreams);
  1558. //
  1559. // should NEVER happen, but if it does make sure we don't blow
  1560. //
  1561. gpag->cInputStreams = 0;
  1562. gpag->htaskInput = NULL;
  1563. pms->htaskInput = NULL;
  1564. }
  1565. else
  1566. {
  1567. #ifdef DEBUG
  1568. if (pms->htaskInput != gpag->htaskInput)
  1569. {
  1570. DPF(0, "!pms->htaskInput=%.04Xh != gpag->htaskInput%.04Xh!",
  1571. pms->htaskInput, gpag->htaskInput);
  1572. }
  1573. #endif
  1574. gpag->cInputStreams--;
  1575. if (0 != gpag->cInputStreams)
  1576. {
  1577. //
  1578. // yield to input mapping task--this will allow all
  1579. // unserviced messages to be processed. this could be made
  1580. // better and will have to be for win 32...
  1581. //
  1582. DPF(1, "YIELDING to background input mapping task=%.04Xh", gpag->htaskInput);
  1583. if (IsTask(gpag->htaskInput))
  1584. {
  1585. DirectedYield(gpag->htaskInput);
  1586. }
  1587. else
  1588. {
  1589. DPF(0, "!gpag->taskInput=%.04Xh is dead!", gpag->htaskInput);
  1590. gpag->cInputStreams = 0;
  1591. gpag->htaskInput = NULL;
  1592. }
  1593. DPF(1, "done YIELDING to background input mapping task=%.04Xh", gpag->htaskInput);
  1594. }
  1595. else
  1596. {
  1597. //
  1598. // destroy converter task and yield to it until all
  1599. // messages get pumped through...
  1600. //
  1601. DPF(1, "KILLING background input mapping task=%.04Xh", gpag->htaskInput);
  1602. if (gpag->htaskInput != NULL) {
  1603. PostAppMessage(gpag->htaskInput, WM_QUIT, 0, 0L);
  1604. while (IsTask(gpag->htaskInput))
  1605. {
  1606. DirectedYield(gpag->htaskInput);
  1607. }
  1608. }
  1609. DPF(1, "done killing background input mapping task=%.04Xh", gpag->htaskInput);
  1610. gpag->htaskInput = NULL;
  1611. }
  1612. pms->htaskInput = NULL;
  1613. }
  1614. #endif // !WIN32
  1615. }
  1616. //
  1617. // done with stream (and driver)...
  1618. //
  1619. if (NULL != pms->has)
  1620. {
  1621. acmStreamClose(pms->has, 0L);
  1622. acmDriverClose(pms->had, 0L);
  1623. if (pms->fInput)
  1624. {
  1625. //
  1626. // this must be done _AFTER_ destroying our background input
  1627. // mapping task
  1628. //
  1629. mapWaveDriverCallback(pms, WIM_CLOSE, 0L, 0L);
  1630. }
  1631. else
  1632. {
  1633. //
  1634. // this must be done _AFTER_ the calls the ACM APIs since
  1635. // some versions of the ACM will yield within its APIs.
  1636. // Otherwise, for MCIWAVE, the signal to the MCIWAVE background
  1637. // task would occur prematurely.
  1638. //
  1639. mapWaveDriverCallback(pms, WOM_CLOSE, 0L, 0L);
  1640. }
  1641. }
  1642. //
  1643. // free the allocated memory for our mapping stream instance
  1644. //
  1645. GlobalFreePtr(pms);
  1646. return (MMSYSERR_NOERROR);
  1647. } // mapWaveClose()
  1648. //--------------------------------------------------------------------------;
  1649. //
  1650. // DWORD mapWaveOpen
  1651. //
  1652. // Description:
  1653. //
  1654. //
  1655. // Arguments:
  1656. // BOOL fInput:
  1657. //
  1658. // UINT uId:
  1659. //
  1660. // DWORD dwUser:
  1661. //
  1662. // LPWAVEOPENDESC pwod:
  1663. //
  1664. // DWORD fdwOpen:
  1665. //
  1666. // Return (DWORD):
  1667. //
  1668. //
  1669. //--------------------------------------------------------------------------;
  1670. DWORD FNLOCAL mapWaveOpen
  1671. (
  1672. BOOL fInput,
  1673. UINT uId,
  1674. DWORD_PTR dwUser,
  1675. LPWAVEOPENDESC pwod,
  1676. DWORD fdwOpen
  1677. )
  1678. {
  1679. MMRESULT mmr;
  1680. LPMAPSTREAM pms; // pointer to per-instance info struct
  1681. LPMAPSTREAM pmsT; // temp stream pointer
  1682. DWORD cbms;
  1683. LPWAVEFORMATEX pwfx; // pointer to passed format
  1684. UINT cbwfxSrc;
  1685. DWORD cbwfxDst;
  1686. BOOL fQuery;
  1687. BOOL fAsync;
  1688. //
  1689. //
  1690. //
  1691. fQuery = (0 != (WAVE_FORMAT_QUERY & fdwOpen));
  1692. fAsync = (0 == (WAVE_ALLOWSYNC & fdwOpen));
  1693. pwfx = (LPWAVEFORMATEX)pwod->lpFormat;
  1694. DPF(2, "mapWaveOpen(%s,%s,%s): Tag=%u, %lu Hz, %u Bit, %u Channel(s)",
  1695. fInput ? (LPSTR)"in" : (LPSTR)"out",
  1696. fQuery ? (LPSTR)"query" : (LPSTR)"real",
  1697. fAsync ? (LPSTR)"async" : (LPSTR)"SYNC",
  1698. pwfx->wFormatTag,
  1699. pwfx->nSamplesPerSec,
  1700. pwfx->wBitsPerSample,
  1701. pwfx->nChannels);
  1702. if (gpag->fPrestoSyncAsync)
  1703. {
  1704. fdwOpen |= WAVE_ALLOWSYNC;
  1705. fAsync = FALSE;
  1706. }
  1707. WAIT_FOR_MUTEX(gpag->hMutexSettings);
  1708. if (fAsync)
  1709. {
  1710. if (fInput)
  1711. {
  1712. if (gpag->pSettings->fSyncOnlyIn)
  1713. {
  1714. DPF(1, "--->failing because input device is syncronous!");
  1715. RELEASE_MUTEX(gpag->hMutexSettings);
  1716. return (WAVERR_SYNC);
  1717. }
  1718. }
  1719. else
  1720. {
  1721. if (gpag->pSettings->fSyncOnlyOut)
  1722. {
  1723. DPF(1, "--->failing because output device is syncronous!");
  1724. RELEASE_MUTEX(gpag->hMutexSettings);
  1725. return (WAVERR_SYNC);
  1726. }
  1727. }
  1728. }
  1729. RELEASE_MUTEX(gpag->hMutexSettings);
  1730. //
  1731. // determine how big the complete wave format header is--this is the
  1732. // size of the extended waveformat structure plus the cbSize field.
  1733. // note that for PCM, this is only sizeof(PCMWAVEFORMAT)
  1734. //
  1735. if (WAVE_FORMAT_PCM == pwfx->wFormatTag)
  1736. {
  1737. cbwfxSrc = sizeof(PCMWAVEFORMAT);
  1738. }
  1739. else
  1740. {
  1741. //
  1742. // because MMSYSTEM does not (currently) validate for the extended
  1743. // format information, we validate this pointer--this will keep
  1744. // noelc and davidmay from crashing Windows with corrupt files.
  1745. //
  1746. cbwfxSrc = sizeof(WAVEFORMATEX) + pwfx->cbSize;
  1747. if (IsBadReadPtr(pwfx, cbwfxSrc))
  1748. {
  1749. return (MMSYSERR_INVALPARAM);
  1750. }
  1751. }
  1752. //
  1753. // allocate mapping stream instance structure
  1754. //
  1755. // for Win 16, this structure must be _page locked in global space_
  1756. // so our low level interrupt time callbacks can munge the headers
  1757. // without exploding
  1758. //
  1759. // size is the struct size + size of one known format + largest
  1760. // possible mapped destination format size. We don't determine
  1761. // the size of the largest possible mapped destination format until
  1762. // we know we do in fact have to map this format. When we make this
  1763. // determination, we will realloc this.
  1764. //
  1765. cbms = sizeof(*pms) + cbwfxSrc;
  1766. pms = (LPMAPSTREAM)GlobalAllocPtr(GMEM_FIXED|GMEM_SHARE|GMEM_ZEROINIT, cbms);
  1767. if (NULL == pms)
  1768. {
  1769. DPF(0, "!mapWaveOpen(): could not alloc %lu bytes for map stream!", cbms);
  1770. return (MMSYSERR_NOMEM);
  1771. }
  1772. //
  1773. // now fill it with info
  1774. //
  1775. pms->fInput = fInput;
  1776. pms->fdwOpen = fdwOpen;
  1777. pms->dwCallback = pwod->dwCallback;
  1778. pms->dwInstance = pwod->dwInstance;
  1779. pms->hwClient = pwod->hWave;
  1780. if (fdwOpen & WAVE_MAPPED)
  1781. {
  1782. pms->uMappedDeviceID = pwod->uMappedDeviceID;
  1783. }
  1784. pms->pwfxClient = (LPWAVEFORMATEX)(pms + 1);
  1785. pms->pwfxReal = NULL; // filled in later if needed
  1786. pms->cbwfxReal = 0; // filled in later if needed
  1787. pms->uIdReal = (UINT)-1;
  1788. _fmemcpy(pms->pwfxClient, pwfx, cbwfxSrc);
  1789. //
  1790. // set up our function jump table so we don't have to constantly
  1791. // check for input vs output--makes for smaller and faster code.
  1792. //
  1793. if (fInput)
  1794. {
  1795. pms->fnWaveOpen = (MAPPEDWAVEOPEN)waveInOpen;
  1796. pms->fnWaveClose = (MAPPEDWAVECLOSE)waveInClose;
  1797. pms->fnWavePrepareHeader = (MAPPEDWAVEPREPAREHEADER)waveInPrepareHeader;
  1798. pms->fnWaveUnprepareHeader = (MAPPEDWAVEUNPREPAREHEADER)waveInUnprepareHeader;
  1799. pms->fnWaveWrite = (MAPPEDWAVEWRITE)waveInAddBuffer;
  1800. pms->fnWaveGetPosition = (MAPPEDWAVEGETPOSITION)waveInGetPosition;
  1801. pms->fnWaveMessage = (MAPPEDWAVEMESSAGE)waveInMessage;
  1802. }
  1803. else
  1804. {
  1805. pms->fnWaveOpen = (MAPPEDWAVEOPEN)waveOutOpen;
  1806. pms->fnWaveClose = (MAPPEDWAVECLOSE)waveOutClose;
  1807. pms->fnWavePrepareHeader = (MAPPEDWAVEPREPAREHEADER)waveOutPrepareHeader;
  1808. pms->fnWaveUnprepareHeader = (MAPPEDWAVEUNPREPAREHEADER)waveOutUnprepareHeader;
  1809. pms->fnWaveWrite = (MAPPEDWAVEWRITE)waveOutWrite;
  1810. pms->fnWaveGetPosition = (MAPPEDWAVEGETPOSITION)waveOutGetPosition;
  1811. pms->fnWaveMessage = (MAPPEDWAVEMESSAGE)waveOutMessage;
  1812. }
  1813. //
  1814. // give mmsystem an instance dword that will be passed back to the
  1815. // mapper on all subsequent calls..
  1816. //
  1817. *((PDWORD_PTR)dwUser) = (DWORD_PTR)pms;
  1818. //
  1819. // try to open another *real* wave device with this format
  1820. // if another device can deal with the format we will do
  1821. // nothing but act as a pass through
  1822. //
  1823. // if someone could open the format, go into passthrough mode.
  1824. //
  1825. pms->mmrClient = MMSYSERR_ERROR;
  1826. mmr = mapDriverOpenWave(pms, pwfx);
  1827. if (MMSYSERR_NOERROR == mmr)
  1828. {
  1829. #ifdef DEBUG
  1830. {
  1831. if (DbgGetLevel() > 2)
  1832. {
  1833. if (fInput)
  1834. {
  1835. WAVEINCAPS wic;
  1836. waveInGetDevCaps(pms->uIdReal, &wic, sizeof(wic));
  1837. wic.szPname[SIZEOF(wic.szPname) - 1] = '\0';
  1838. DPF(3, "--->'" DEVFMT_STR "' native support succeeded.", (LPTSTR)wic.szPname);
  1839. }
  1840. else
  1841. {
  1842. WAVEOUTCAPS woc;
  1843. waveOutGetDevCaps(pms->uIdReal, &woc, sizeof(woc));
  1844. woc.szPname[SIZEOF(woc.szPname) - 1] = '\0';
  1845. DPF(3, "--->'" DEVFMT_STR "' native support succeeded.", (LPTSTR)woc.szPname);
  1846. }
  1847. }
  1848. }
  1849. #endif
  1850. if (fQuery)
  1851. {
  1852. GlobalFreePtr(pms);
  1853. }
  1854. return (MMSYSERR_NOERROR);
  1855. }
  1856. //
  1857. // If this was a WAVE_FORMAT_DIRECT then don't bother
  1858. // trying to setup a conversion stream. Note WAVE_FORMAT_DIRECT is
  1859. // new for Win95.
  1860. //
  1861. if (0 != (WAVE_FORMAT_DIRECT & pms->fdwOpen))
  1862. {
  1863. mmr = pms->mmrClient;
  1864. GlobalFreePtr(pms);
  1865. return mmr;
  1866. }
  1867. //
  1868. // If all devices are allocated, don't go on to try to create
  1869. // a conversion stream.
  1870. //
  1871. if (MMSYSERR_ALLOCATED == mmr)
  1872. {
  1873. mmr = pms->mmrClient;
  1874. GlobalFreePtr(pms);
  1875. return mmr;
  1876. }
  1877. //
  1878. // There was at least one unallocated device that could not open
  1879. // the format.
  1880. //
  1881. // determine size of largest possible mapped destination format and
  1882. // fill in all the necessary remaining pms information required
  1883. // for mapping.
  1884. //
  1885. mmr = acmMetrics(NULL, ACM_METRIC_MAX_SIZE_FORMAT, &cbwfxDst);
  1886. if (MMSYSERR_NOERROR != mmr)
  1887. {
  1888. DPF(0, "!mapWaveOpen() FAILING BECAUSE MAX FORMAT SIZE UNKNOWN?");
  1889. GlobalFreePtr(pms);
  1890. return (MMSYSERR_ERROR);
  1891. }
  1892. cbms = sizeof(*pms) + cbwfxSrc + cbwfxDst;
  1893. pmsT = pms;
  1894. pms = (LPMAPSTREAM)GlobalReAllocPtr(pmsT, cbms, GMEM_MOVEABLE|GMEM_ZEROINIT);
  1895. if (NULL == pms)
  1896. {
  1897. DPF(0, "!mapWaveOpen(): could not realloc %lu bytes for map stream!", cbms);
  1898. GlobalFreePtr(pmsT);
  1899. return (MMSYSERR_NOMEM);
  1900. }
  1901. //
  1902. // now fill in remaining info necessary for mapping.
  1903. //
  1904. pms->pwfxClient = (LPWAVEFORMATEX)(pms + 1);
  1905. pms->pwfxReal = (LPWAVEFORMATEX)((LPBYTE)(pms + 1) + cbwfxSrc);
  1906. pms->cbwfxReal = cbwfxDst;
  1907. if (fInput)
  1908. {
  1909. pms->pwfxSrc = pms->pwfxReal;
  1910. pms->pwfxDst = pms->pwfxClient;
  1911. }
  1912. else
  1913. {
  1914. pms->pwfxSrc = pms->pwfxClient;
  1915. pms->pwfxDst = pms->pwfxReal;
  1916. }
  1917. //
  1918. // give mmsystem an instance dword that will be passed back to the
  1919. // mapper on all subsequent calls. this was done earlier but pms
  1920. // may have changed since we've done a GlobalReAllocPtr.
  1921. //
  1922. *((PDWORD_PTR)dwUser) = (DWORD_PTR)pms;
  1923. //
  1924. // no one could open the format
  1925. //
  1926. mmr = FindConverterMatch(pms);
  1927. if (MMSYSERR_NOERROR != mmr)
  1928. {
  1929. DPF(2, "--->failing open, unable to find supporting ACM driver!");
  1930. //
  1931. // return the error we got when attempting to open a
  1932. // converter / wave driver...
  1933. //
  1934. GlobalFreePtr(pms);
  1935. return (mmr);
  1936. }
  1937. //
  1938. //
  1939. //
  1940. DPF(2, "--->MAPPING TO: Tag=%u, %lu Hz, %u Bit, %u Channel(s)",
  1941. pms->pwfxReal->wFormatTag,
  1942. pms->pwfxReal->nSamplesPerSec,
  1943. pms->pwfxReal->wBitsPerSample,
  1944. pms->pwfxReal->nChannels);
  1945. if (fQuery)
  1946. {
  1947. acmDriverClose(pms->had, 0L);
  1948. GlobalFreePtr(pms);
  1949. return (MMSYSERR_NOERROR);
  1950. }
  1951. //
  1952. //
  1953. //
  1954. mmr = acmStreamOpen(&pms->has,
  1955. pms->had,
  1956. pms->pwfxSrc,
  1957. pms->pwfxDst,
  1958. NULL,
  1959. 0L,
  1960. 0L,
  1961. 0L);
  1962. if (MMSYSERR_NOERROR != mmr)
  1963. {
  1964. DPF(0, "!mapWaveOpen: opening stream failed! mmr=%u", mmr);
  1965. pms->fnWaveClose(pms->hwReal);
  1966. acmDriverClose(pms->had, 0L);
  1967. GlobalFreePtr(pms);
  1968. if (mmr < WAVERR_BASE)
  1969. {
  1970. return (mmr);
  1971. }
  1972. return (WAVERR_BADFORMAT);
  1973. }
  1974. //
  1975. //
  1976. //
  1977. if (fInput)
  1978. {
  1979. #ifndef WIN32
  1980. if ((NULL == gpag->htaskInput) || !IsTask(gpag->htaskInput))
  1981. #endif
  1982. {
  1983. #ifndef WIN32
  1984. if (0 != gpag->cInputStreams)
  1985. {
  1986. DPF(0, "!cInputStreams=%u and should be zero! (gpag->htaskInput=%.04Xh)",
  1987. gpag->cInputStreams, gpag->htaskInput);
  1988. gpag->cInputStreams = 0;
  1989. }
  1990. #endif
  1991. #ifdef DEBUG
  1992. gpag->fFaultAndDie = (BOOL)GetPrivateProfileInt(TEXT("msacm.drv"), TEXT("FaultAndDie"), 0, TEXT("system.ini"));
  1993. #endif
  1994. //
  1995. // create the task to do the conversion in..
  1996. //
  1997. #ifdef WIN32
  1998. pms->nOutstanding = 0;
  1999. if ((pms->hStoppedEvent = CreateEvent(NULL, FALSE, FALSE, NULL))
  2000. == NULL ||
  2001. (pms->hInput =
  2002. CreateThread(NULL,
  2003. 300,
  2004. (LPTHREAD_START_ROUTINE)
  2005. mapWaveInputConvertProc,
  2006. (LPVOID)pms->hStoppedEvent,
  2007. 0,
  2008. (LPDWORD)&pms->htaskInput)) == NULL)
  2009. {
  2010. if (pms->hStoppedEvent != NULL)
  2011. {
  2012. CloseHandle(pms->hStoppedEvent);
  2013. }
  2014. #else
  2015. gpag->htaskInput = NULL;
  2016. if (mmTaskCreate((LPTASKCALLBACK)mapWaveInputConvertProc,
  2017. (HTASK FAR *)&gpag->htaskInput,
  2018. 0L))
  2019. {
  2020. #endif
  2021. DPF(0, "!mapWaveOpen: unable to create task for input mapping!");
  2022. pms->fnWaveClose(pms->hwReal);
  2023. acmStreamClose(pms->has, 0L);
  2024. acmDriverClose(pms->had, 0L);
  2025. GlobalFreePtr(pms);
  2026. return (MMSYSERR_NOMEM);
  2027. }
  2028. //
  2029. // make sure _at least one_ message is present in the background
  2030. // task's queue--this will keep DirectedYield from hanging
  2031. // in GetMessage if an app opens input with no callback and
  2032. // immediately closes the handle (like testing if the device
  2033. // is available--ACMAPP and WaveTst do this!).
  2034. //
  2035. #ifndef WIN32
  2036. PostAppMessage(gpag->htaskInput, WM_NULL, 0, 0L);
  2037. DirectedYield(gpag->htaskInput);
  2038. #else
  2039. //
  2040. // Make sure the thread has started - otherwise PostAppMessage
  2041. // won't work because the thread won't have a message queue.
  2042. //
  2043. WaitForSingleObject(pms->hStoppedEvent, INFINITE);
  2044. #endif // !WIN32
  2045. }
  2046. gpag->cInputStreams++;
  2047. #ifndef WIN32
  2048. pms->htaskInput = gpag->htaskInput;
  2049. #endif
  2050. //
  2051. // NOTE! we *MUST* send the WIM_OPEN callback _AFTER_ creating the
  2052. // input mapping task. our function callback (mapWaveCallback)
  2053. // simply eats the physical WIM_OPEN message. if this is not done
  2054. // this way, we get into a task lock with MCIWAVE's background
  2055. // task...
  2056. //
  2057. mapWaveDriverCallback(pms, WIM_OPEN, 0L, 0L);
  2058. }
  2059. else
  2060. {
  2061. //
  2062. // We send the WOM_OPEN callback here after opening the stream
  2063. // instead of in our function callback (mapWaveCallback). Some
  2064. // versions of the acm cause a yield to occur within its APIs, and
  2065. // this would allow a signal to reach the MCIWAVE background task
  2066. // prematurely (it would get to the MCIWAVE background task before
  2067. // its state had changed from TASKIDLE to TASKBUSY).
  2068. //
  2069. mapWaveDriverCallback(pms, WOM_OPEN, 0L, 0L);
  2070. }
  2071. //
  2072. // made it! succeed the open
  2073. //
  2074. return (MMSYSERR_NOERROR);
  2075. } // mapWaveOpen()
  2076. //--------------------------------------------------------------------------;
  2077. //
  2078. // DWORD mapWavePrepareHeader
  2079. //
  2080. // Description:
  2081. //
  2082. //
  2083. // Arguments:
  2084. // LPMAPSTREAM pms:
  2085. //
  2086. // LPWAVEHDR pwh:
  2087. //
  2088. // Return (DWORD):
  2089. //
  2090. // History:
  2091. // 06/15/93 cjp [curtisp]
  2092. //
  2093. //--------------------------------------------------------------------------;
  2094. DWORD FNLOCAL mapWavePrepareHeader
  2095. (
  2096. LPMAPSTREAM pms,
  2097. LPWAVEHDR pwh
  2098. )
  2099. {
  2100. MMRESULT mmr;
  2101. LPWAVEHDR pwhShadow;
  2102. LPACMSTREAMHEADER pash;
  2103. DWORD cbShadow;
  2104. DWORD dwLen;
  2105. DWORD fdwSize;
  2106. //
  2107. // if we are in convert mode, allocate a 'shadow' wave header
  2108. // and buffer to hold the converted wave bits
  2109. //
  2110. // we need to pagelock the callers header but *not* his buffer
  2111. // because we touch it in wXdWaveMapCallback (to set the DONE bit)
  2112. //
  2113. // here is the state of the dwUser and reserved fields in
  2114. // both buffers.
  2115. //
  2116. // client's header (sent to the wavemapper by the 'user')
  2117. //
  2118. // reserved points to the stream header used for
  2119. // conversions with the ACM. the wavemapper
  2120. // is the driver so we can use this.
  2121. // dwUser for use by the 'user' (client)
  2122. //
  2123. // shadow header (sent to the real device by the wavemapper)
  2124. //
  2125. // reserved for use by the real device
  2126. // dwUser points to the client's header. (the
  2127. // wavemapper is the user in this case)
  2128. //
  2129. // acm stream header (created by us for conversion work)
  2130. //
  2131. // dwUser points to mapper stream instance (pms)
  2132. // dwSrcUser points to shadow header
  2133. // dwDstUser original source buffer size (prepared with)
  2134. //
  2135. if (NULL == pms->has)
  2136. {
  2137. //
  2138. // no conversion required just pass through
  2139. //
  2140. mmr = pms->fnWavePrepareHeader(pms->hwReal, pwh, sizeof(WAVEHDR));
  2141. return (mmr);
  2142. }
  2143. //
  2144. //
  2145. //
  2146. //
  2147. dwLen = pwh->dwBufferLength;
  2148. if (pms->fInput)
  2149. {
  2150. UINT u;
  2151. #ifndef WIN32
  2152. if (!IsTask(pms->htaskInput))
  2153. {
  2154. DPF(0, "mapWavePrepareHeader: background task died! pms->htaskInput=%.04Xh", pms->htaskInput);
  2155. pms->htaskInput = NULL;
  2156. return (MMSYSERR_NOMEM);
  2157. }
  2158. #endif // !WIN32
  2159. //
  2160. // block align the destination buffer if the caller didn't read
  2161. // our documentation...
  2162. //
  2163. u = pms->pwfxClient->nBlockAlign;
  2164. dwLen = (dwLen / u) * u;
  2165. #ifdef DEBUG
  2166. if (dwLen != pwh->dwBufferLength)
  2167. {
  2168. DPF(1, "mapWavePrepareHeader: caller passed _unaligned_ buffer for recording (%lu->%lu)!",
  2169. pwh->dwBufferLength, dwLen);
  2170. }
  2171. #endif
  2172. //
  2173. // determine size for shadow buffer (the buffer that we will give
  2174. // to the _real_ device). give a _block aligned_ destination buffer
  2175. //
  2176. fdwSize = ACM_STREAMSIZEF_DESTINATION;
  2177. }
  2178. else
  2179. {
  2180. //
  2181. // determine size for the shadow buffer (this will be the buffer
  2182. // that we convert to before writing the data to the underlying
  2183. // device).
  2184. //
  2185. fdwSize = ACM_STREAMSIZEF_SOURCE;
  2186. }
  2187. mmr = acmStreamSize(pms->has, dwLen, &dwLen, fdwSize);
  2188. if (MMSYSERR_NOERROR != mmr)
  2189. {
  2190. DPF(0, "!mapWavePrepareHeader: failed to get conversion size! mmr=%u", mmr);
  2191. return (MMSYSERR_NOMEM);
  2192. }
  2193. //
  2194. //
  2195. //
  2196. DPF(2, "mapWavePrepareHeader(%s): Client=%lu Bytes, Shadow=%lu Bytes",
  2197. pms->fInput ? (LPSTR)"in" : (LPSTR)"out",
  2198. pwh->dwBufferLength,
  2199. dwLen);
  2200. //
  2201. // allocate the shadow WAVEHDR
  2202. //
  2203. // NOTE: add four bytes to guard against GP faulting with stos/lods
  2204. // code that accesses the last byte/word/dword in a segment--very
  2205. // easy to do...
  2206. //
  2207. cbShadow = sizeof(WAVEHDR) + sizeof(ACMSTREAMHEADER) + dwLen + 4;
  2208. pwhShadow = (LPWAVEHDR)GlobalAllocPtr(GMEM_MOVEABLE|GMEM_SHARE, cbShadow);
  2209. if (NULL == pwhShadow)
  2210. {
  2211. DPF(0, "!mapWavePrepareHeader(): could not alloc %lu bytes for shadow!", cbShadow);
  2212. return (MMSYSERR_NOMEM);
  2213. }
  2214. //
  2215. //
  2216. //
  2217. pash = (LPACMSTREAMHEADER)(pwhShadow + 1);
  2218. pash->cbStruct = sizeof(*pash);
  2219. pash->fdwStatus = 0L;
  2220. pash->dwUser = (DWORD_PTR)pms;
  2221. //
  2222. // fill in the shadow wave header, the dwUser field will point
  2223. // back to the original header, so we can get back to it
  2224. //
  2225. pwhShadow->lpData = (LPBYTE)(pash + 1);
  2226. pwhShadow->dwBufferLength = dwLen;
  2227. pwhShadow->dwBytesRecorded = 0;
  2228. pwhShadow->dwUser = (DWORD_PTR)pwh;
  2229. //
  2230. // now prepare the shadow wavehdr
  2231. //
  2232. if (pms->fInput)
  2233. {
  2234. pwhShadow->dwFlags = 0L;
  2235. pwhShadow->dwLoops = 0L;
  2236. //
  2237. // input: our source is the shadow (we get data from the
  2238. // physical device and convert it into the clients buffer)
  2239. //
  2240. pash->pbSrc = pwhShadow->lpData;
  2241. pash->cbSrcLength = pwhShadow->dwBufferLength;
  2242. pash->dwSrcUser = (DWORD_PTR)pwhShadow;
  2243. pash->pbDst = pwh->lpData;
  2244. pash->cbDstLength = pwh->dwBufferLength;
  2245. pash->dwDstUser = pwhShadow->dwBufferLength;
  2246. }
  2247. else
  2248. {
  2249. pwhShadow->dwFlags = pwh->dwFlags & (WHDR_BEGINLOOP|WHDR_ENDLOOP);
  2250. pwhShadow->dwLoops = pwh->dwLoops;
  2251. //
  2252. // output: our source is the client (we get data from the
  2253. // client and convert it into something for the physical
  2254. // device)
  2255. //
  2256. pash->pbSrc = pwh->lpData;
  2257. pash->cbSrcLength = pwh->dwBufferLength;
  2258. pash->dwSrcUser = (DWORD_PTR)pwhShadow;
  2259. pash->pbDst = pwhShadow->lpData;
  2260. pash->cbDstLength = pwhShadow->dwBufferLength;
  2261. pash->dwDstUser = pwh->dwBufferLength;
  2262. }
  2263. mmr = pms->fnWavePrepareHeader(pms->hwReal, pwhShadow, sizeof(WAVEHDR));
  2264. if (MMSYSERR_NOERROR == mmr)
  2265. {
  2266. mmr = acmStreamPrepareHeader(pms->has, pash, 0L);
  2267. if (MMSYSERR_NOERROR != mmr)
  2268. {
  2269. pms->fnWaveUnprepareHeader(pms->hwReal, pwhShadow, sizeof(WAVEHDR));
  2270. }
  2271. }
  2272. //
  2273. //
  2274. //
  2275. if (MMSYSERR_NOERROR != mmr)
  2276. {
  2277. GlobalFreePtr(pwhShadow);
  2278. return (mmr);
  2279. }
  2280. //
  2281. // now pagelock the callers header, only the header!!!
  2282. //
  2283. // globalpagelock will pagelock the complete object--and this could
  2284. // be bad if the caller allocated the header as the first part
  2285. // of a large memory block. also globalpagelock only works on the
  2286. // _first_ selector of the tile...
  2287. //
  2288. // not necessary in win 32.
  2289. //
  2290. #ifndef WIN32
  2291. acmHugePageLock((LPBYTE)pwh, sizeof(*pwh));
  2292. #endif
  2293. //
  2294. // the reserved field of the callers WAVEHDR will contain the
  2295. // shadow LPWAVEHDR
  2296. //
  2297. pwh->reserved = (DWORD_PTR)pash;
  2298. pwh->dwFlags |= WHDR_PREPARED;
  2299. return (MMSYSERR_NOERROR);
  2300. } // mapWavePrepareHeader()
  2301. //--------------------------------------------------------------------------;
  2302. //
  2303. // DWORD mapWaveUnprepareHeader
  2304. //
  2305. // Description:
  2306. //
  2307. //
  2308. // Arguments:
  2309. // LPMAPSTREAM pms:
  2310. //
  2311. // LPWAVEHDR pwh:
  2312. //
  2313. // Return (DWORD):
  2314. //
  2315. // History:
  2316. // 06/15/93 cjp [curtisp]
  2317. //
  2318. //--------------------------------------------------------------------------;
  2319. DWORD FNLOCAL mapWaveUnprepareHeader
  2320. (
  2321. LPMAPSTREAM pms,
  2322. LPWAVEHDR pwh
  2323. )
  2324. {
  2325. MMRESULT mmr;
  2326. LPWAVEHDR pwhShadow;
  2327. LPACMSTREAMHEADER pash;
  2328. DWORD cbShadowData;
  2329. //
  2330. // if we are not in convert mode, then passthrough to physical device
  2331. // otherwise, free the 'shadow' wave header and buffer, etc
  2332. //
  2333. if (NULL == pms->has)
  2334. {
  2335. //
  2336. // no conversion required just pass through
  2337. //
  2338. mmr = pms->fnWaveUnprepareHeader(pms->hwReal, pwh, sizeof(WAVEHDR));
  2339. return (mmr);
  2340. }
  2341. //
  2342. //
  2343. //
  2344. //
  2345. //
  2346. pash = (LPACMSTREAMHEADER)pwh->reserved;
  2347. pwhShadow = (LPWAVEHDR)pash->dwSrcUser;
  2348. if (pms->fInput)
  2349. {
  2350. cbShadowData = (DWORD)pash->dwDstUser;
  2351. pash->cbSrcLength = (DWORD)pash->dwDstUser;
  2352. ////////pash->cbDstLength = xxx; !!! don't touch this !!!
  2353. }
  2354. else
  2355. {
  2356. cbShadowData = pash->cbDstLength;
  2357. pash->cbSrcLength = (DWORD)pash->dwDstUser;
  2358. ////////pash->cbDstLength = xxx; !!! don't touch this !!!
  2359. }
  2360. acmStreamUnprepareHeader(pms->has, pash, 0L);
  2361. pwhShadow->dwBufferLength = cbShadowData;
  2362. pms->fnWaveUnprepareHeader(pms->hwReal, pwhShadow, sizeof(WAVEHDR));
  2363. //
  2364. // unprepare the shadow and caller's buffers (for the caller, this
  2365. // just means un-page lock the WAVEHDR)
  2366. //
  2367. // we only page lock stuff in Win 16--not Win 32.
  2368. //
  2369. #ifndef WIN32
  2370. acmHugePageUnlock((LPBYTE)pwh, sizeof(*pwh));
  2371. #endif
  2372. //
  2373. // free the shadow buffer--mark caller's wave header as unprepared
  2374. // and succeed the call
  2375. //
  2376. GlobalFreePtr(pwhShadow);
  2377. pwh->reserved = 0L;
  2378. pwh->dwFlags &= ~WHDR_PREPARED;
  2379. return (MMSYSERR_NOERROR);
  2380. } // mapWaveUnprepareHeader()
  2381. //--------------------------------------------------------------------------;
  2382. //
  2383. // DWORD mapWaveWriteBuffer
  2384. //
  2385. // Description:
  2386. //
  2387. //
  2388. // Arguments:
  2389. // LPMAPSTREAM pms:
  2390. //
  2391. // LPWAVEHDR pwh:
  2392. //
  2393. // Return (DWORD):
  2394. //
  2395. // History:
  2396. // 06/15/93 cjp [curtisp]
  2397. //
  2398. //--------------------------------------------------------------------------;
  2399. DWORD FNLOCAL mapWaveWriteBuffer
  2400. (
  2401. LPMAPSTREAM pms,
  2402. LPWAVEHDR pwh
  2403. )
  2404. {
  2405. MMRESULT mmr;
  2406. LPWAVEHDR pwhShadow;
  2407. LPACMSTREAMHEADER pash;
  2408. DWORD cbShadowData;
  2409. //
  2410. // no conversion required just pass through
  2411. //
  2412. if (NULL == pms->has)
  2413. {
  2414. mmr = pms->fnWaveWrite(pms->hwReal, pwh, sizeof(WAVEHDR));
  2415. return (mmr);
  2416. }
  2417. //
  2418. //
  2419. //
  2420. DPF(2, "mapWaveWriteBuffer(%s): Flags=%.08lXh, %lu Bytes, %lu Loops",
  2421. pms->fInput ? (LPSTR)"in" : (LPSTR)"out",
  2422. pwh->dwFlags,
  2423. pwh->dwBufferLength,
  2424. pwh->dwLoops);
  2425. //
  2426. // get the conversion stream header...
  2427. //
  2428. pash = (LPACMSTREAMHEADER)pwh->reserved;
  2429. if (NULL == pash)
  2430. {
  2431. DPF(0, "!mapWaveWriteBuffer: very strange--reserved field is 0???");
  2432. return (WAVERR_UNPREPARED);
  2433. }
  2434. pwhShadow = (LPWAVEHDR)pash->dwSrcUser;
  2435. if (pms->fInput)
  2436. {
  2437. UINT u;
  2438. #ifndef WIN32
  2439. if (!IsTask(pms->htaskInput))
  2440. {
  2441. DPF(0, "mapWaveWriteBuffer: background task died! pms->htaskInput=%.04Xh", pms->htaskInput);
  2442. pms->htaskInput = NULL;
  2443. return (MMSYSERR_NOMEM);
  2444. }
  2445. #endif // !WIN32
  2446. //
  2447. // again, we must block align the input buffer
  2448. //
  2449. //
  2450. u = pms->pwfxClient->nBlockAlign;
  2451. cbShadowData = (pwh->dwBufferLength / u) * u;
  2452. #ifdef DEBUG
  2453. if (cbShadowData != pwh->dwBufferLength)
  2454. {
  2455. DPF(1, "mapWaveWriteBuffer: caller passed _unaligned_ buffer for recording (%lu->%lu)!",
  2456. pwh->dwBufferLength, cbShadowData);
  2457. }
  2458. #endif
  2459. //
  2460. // determine amount of data we need from the _real_ device. give a
  2461. // _block aligned_ destination buffer...
  2462. //
  2463. mmr = acmStreamSize(pms->has,
  2464. cbShadowData,
  2465. &cbShadowData,
  2466. ACM_STREAMSIZEF_DESTINATION);
  2467. if (MMSYSERR_NOERROR != mmr)
  2468. {
  2469. DPF(0, "!mapWaveWriteBuffer: failed to get conversion size! mmr=%u", mmr);
  2470. return (MMSYSERR_NOMEM);
  2471. }
  2472. pwhShadow->dwBufferLength = cbShadowData;
  2473. pwhShadow->dwBytesRecorded = 0L;
  2474. //
  2475. // clear the done bit of the caller's wave header (not done) and
  2476. // add the shadow buffer to the real (maybe) device's queue...
  2477. //
  2478. // note that mmsystem _should_ be doing this for us, but alas
  2479. // it does not in win 3.1... i might fix this for chicago.
  2480. //
  2481. pwh->dwFlags &= ~WHDR_DONE;
  2482. }
  2483. else
  2484. {
  2485. //
  2486. // do the conversion
  2487. //
  2488. pash->cbDstLengthUsed = 0L;
  2489. if (0L != pwh->dwBufferLength)
  2490. {
  2491. pash->pbSrc = pwh->lpData;
  2492. pash->cbSrcLength = pwh->dwBufferLength;
  2493. pash->pbDst = pwhShadow->lpData;
  2494. ////////////pash->cbDstLength = xxx; !!! leave as is !!!
  2495. mmr = acmStreamConvert(pms->has, pash, 0L);
  2496. if (MMSYSERR_NOERROR != mmr)
  2497. {
  2498. DPF(0, "!waveOutWrite: conversion failed! mmr=%.04Xh", mmr);
  2499. pash->cbDstLengthUsed = 0L;
  2500. }
  2501. }
  2502. if (0L == pash->cbDstLengthUsed)
  2503. {
  2504. DPF(1, "waveOutWrite: nothing converted--no data in output buffer.");
  2505. }
  2506. pwhShadow->dwFlags = pwh->dwFlags;
  2507. pwhShadow->dwLoops = pwh->dwLoops;
  2508. pwhShadow->dwBufferLength = pash->cbDstLengthUsed;
  2509. }
  2510. pwh->dwFlags |= WHDR_INQUEUE;
  2511. mmr = pms->fnWaveWrite(pms->hwReal, pwhShadow, sizeof(WAVEHDR));
  2512. if (MMSYSERR_NOERROR != mmr)
  2513. {
  2514. pwh->dwFlags &= ~WHDR_INQUEUE;
  2515. DPF(0, "!pms->fnWaveWrite failed!, pms=%.08lXh, mmr=%u!", pms, mmr);
  2516. }
  2517. return (mmr);
  2518. } // mapWaveWriteBuffer()
  2519. //==========================================================================;
  2520. //
  2521. //
  2522. //
  2523. //
  2524. //==========================================================================;
  2525. //--------------------------------------------------------------------------;
  2526. //
  2527. // LRESULT DriverProc
  2528. //
  2529. // Description:
  2530. //
  2531. //
  2532. // Arguments:
  2533. // DWORD dwId: For most messages, dwId is the DWORD value that
  2534. // the driver returns in response to a DRV_OPEN message. Each time
  2535. // that the driver is opened, through the DrvOpen API, the driver
  2536. // receives a DRV_OPEN message and can return an arbitrary, non-zero
  2537. // value. The installable driver interface saves this value and returns
  2538. // a unique driver handle to the application. Whenever the application
  2539. // sends a message to the driver using the driver handle, the interface
  2540. // routes the message to this entry point and passes the corresponding
  2541. // dwId. This mechanism allows the driver to use the same or different
  2542. // identifiers for multiple opens but ensures that driver handles are
  2543. // unique at the application interface layer.
  2544. //
  2545. // The following messages are not related to a particular open instance
  2546. // of the driver. For these messages, the dwId will always be zero.
  2547. //
  2548. // DRV_LOAD, DRV_FREE, DRV_ENABLE, DRV_DISABLE, DRV_OPEN
  2549. //
  2550. // HDRVR hdrvr: This is the handle returned to the application
  2551. // by the driver interface.
  2552. //
  2553. // UINT uMsg: The requested action to be performed. Message
  2554. // values below DRV_RESERVED are used for globally defined messages.
  2555. // Message values from DRV_RESERVED to DRV_USER are used for defined
  2556. // driver protocols. Messages above DRV_USER are used for driver
  2557. // specific messages.
  2558. //
  2559. // LPARAM lParam1: Data for this message. Defined separately for
  2560. // each message.
  2561. //
  2562. // LPARAM lParam2: Data for this message. Defined separately for
  2563. // each message.
  2564. //
  2565. // Return (LRESULT):
  2566. // Defined separately for each message.
  2567. //
  2568. // History:
  2569. // 11/16/92 cjp [curtisp]
  2570. //
  2571. //--------------------------------------------------------------------------;
  2572. EXTERN_C LRESULT FNEXPORT DriverProc
  2573. (
  2574. DWORD_PTR dwId,
  2575. HDRVR hdrvr,
  2576. UINT uMsg,
  2577. LPARAM lParam1,
  2578. LPARAM lParam2
  2579. )
  2580. {
  2581. LRESULT lr;
  2582. LPDWORD pdw;
  2583. switch (uMsg)
  2584. {
  2585. case DRV_INSTALL:
  2586. lr = mapDriverInstall(hdrvr);
  2587. return (lr);
  2588. case DRV_REMOVE:
  2589. lr = mapDriverRemove(hdrvr);
  2590. return (lr);
  2591. case DRV_LOAD:
  2592. case DRV_FREE:
  2593. return (1L);
  2594. case DRV_OPEN:
  2595. case DRV_CLOSE:
  2596. return (1L);
  2597. case DRV_CONFIGURE:
  2598. case DRV_QUERYCONFIGURE:
  2599. return (0L);
  2600. case DRV_ENABLE:
  2601. lr = mapDriverEnable(hdrvr);
  2602. return (lr);
  2603. case DRV_DISABLE:
  2604. lr = mapDriverDisable(hdrvr);
  2605. return (lr);
  2606. #ifndef WIN32
  2607. case DRV_EXITAPPLICATION:
  2608. lr = acmApplicationExit(GetCurrentTask(), lParam1);
  2609. return (lr);
  2610. #endif
  2611. case DRV_MAPPER_PREFERRED_INPUT_GET:
  2612. pdw = (LPDWORD)lParam1;
  2613. if (NULL != pdw)
  2614. {
  2615. WAIT_FOR_MUTEX(gpag->hMutexSettings);
  2616. *pdw = MAKELONG(LOWORD(gpag->pSettings->uIdPreferredIn),
  2617. LOWORD(gpag->pSettings->fPreferredOnly));
  2618. RELEASE_MUTEX(gpag->hMutexSettings);
  2619. return (MMSYSERR_NOERROR);
  2620. }
  2621. return (MMSYSERR_INVALPARAM);
  2622. case DRV_MAPPER_PREFERRED_OUTPUT_GET:
  2623. pdw = (LPDWORD)lParam1;
  2624. if (NULL != pdw)
  2625. {
  2626. WAIT_FOR_MUTEX(gpag->hMutexSettings);
  2627. *pdw = MAKELONG(LOWORD(gpag->pSettings->uIdPreferredOut),
  2628. LOWORD(gpag->pSettings->fPreferredOnly));
  2629. RELEASE_MUTEX(gpag->hMutexSettings);
  2630. return (MMSYSERR_NOERROR);
  2631. }
  2632. return (MMSYSERR_INVALPARAM);
  2633. }
  2634. if (uMsg >= DRV_USER)
  2635. return (MMSYSERR_NOTSUPPORTED);
  2636. else
  2637. return (DefDriverProc(dwId, hdrvr, uMsg, lParam1, lParam2));
  2638. } // DriverProc()