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.

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