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.

2520 lines
85 KiB

  1. //==========================================================================;
  2. //
  3. // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
  4. // KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  5. // IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
  6. // PURPOSE.
  7. //
  8. // Copyright (c) 1993-1999 Microsoft Corporation
  9. //
  10. //--------------------------------------------------------------------------;
  11. //
  12. // codec.c
  13. //
  14. // Description:
  15. // This file contains the DriverProc and other routines which respond
  16. // to ACM messages.
  17. //
  18. // Throughout this module, 'g711' refers to both the A-law and u-law
  19. // coding standards. When the context requires that these coding
  20. // standards be differentiated we use 'alaw' and 'mulaw' or a similar
  21. // variation.
  22. //
  23. //
  24. //==========================================================================;
  25. #include <windows.h>
  26. #include <windowsx.h>
  27. #include <mmsystem.h>
  28. #include <mmddk.h>
  29. #include <mmreg.h>
  30. #include <msacm.h>
  31. #include <msacmdrv.h>
  32. #include <memory.h>
  33. #include "codec.h"
  34. #include "g711.h"
  35. #include "debug.h"
  36. const UINT gauFormatTagIndexToTag[] =
  37. {
  38. WAVE_FORMAT_PCM,
  39. WAVE_FORMAT_ALAW,
  40. WAVE_FORMAT_MULAW
  41. };
  42. #define ACM_DRIVER_MAX_FORMAT_TAGS SIZEOF_ARRAY(gauFormatTagIndexToTag)
  43. #define ACM_DRIVER_MAX_FILTER_TAGS 0
  44. //
  45. // array of sample rates supported
  46. //
  47. //
  48. const UINT gauFormatIndexToSampleRate[] =
  49. {
  50. 8000,
  51. 11025,
  52. 22050,
  53. 44100
  54. };
  55. #define ACM_DRIVER_MAX_SAMPLE_RATES SIZEOF_ARRAY(gauFormatIndexToSampleRate)
  56. #define ACM_DRIVER_MAX_CHANNELS G711_MAX_CHANNELS
  57. //
  58. // bits per sample supported
  59. //
  60. //
  61. #define ACM_DRIVER_MAX_BITSPERSAMPLE_PCM 1 // only 16 bit
  62. #define ACM_DRIVER_MAX_BITSPERSAMPLE_G711 1 // only 8 bit
  63. //
  64. // number of formats we enumerate per channel is number of sample rates
  65. // times number of channels times number of types (bits per sample).
  66. //
  67. #define ACM_DRIVER_MAX_FORMATS_PCM (ACM_DRIVER_MAX_SAMPLE_RATES * \
  68. ACM_DRIVER_MAX_CHANNELS * \
  69. ACM_DRIVER_MAX_BITSPERSAMPLE_PCM)
  70. #define ACM_DRIVER_MAX_FORMATS_G711 (ACM_DRIVER_MAX_SAMPLE_RATES * \
  71. ACM_DRIVER_MAX_CHANNELS * \
  72. ACM_DRIVER_MAX_BITSPERSAMPLE_G711)
  73. //==========================================================================;
  74. //
  75. //
  76. //
  77. //
  78. //==========================================================================;
  79. //--------------------------------------------------------------------------;
  80. //
  81. // int LoadStringCodec
  82. //
  83. // Description:
  84. // This function should be used by all codecs to load resource strings
  85. // which will be passed back to the ACM. It works correctly for all
  86. // platforms, as follows:
  87. //
  88. // Win16: Compiled to LoadString to load ANSI strings.
  89. //
  90. // Win32: The 32-bit ACM always expects Unicode strings. Therefore,
  91. // when UNICODE is defined, this function is compiled to
  92. // LoadStringW to load a Unicode string. When UNICODE is
  93. // not defined, this function loads an ANSI string, converts
  94. // it to Unicode, and returns the Unicode string to the
  95. // codec.
  96. //
  97. // Note that you may use LoadString for other strings (strings which
  98. // will not be passed back to the ACM), because these strings will
  99. // always be consistent with the definition of UNICODE.
  100. //
  101. // Arguments:
  102. // Same as LoadString, except that it expects an LPSTR for Win16 and a
  103. // LPWSTR for Win32.
  104. //
  105. // Return (int):
  106. // Same as LoadString.
  107. //
  108. //--------------------------------------------------------------------------;
  109. #ifndef _WIN32
  110. #define LoadStringCodec LoadString
  111. #else
  112. #ifdef UNICODE
  113. #define LoadStringCodec LoadStringW
  114. #else
  115. int FNGLOBAL LoadStringCodec
  116. (
  117. HINSTANCE hinst,
  118. UINT uID,
  119. LPWSTR lpwstr,
  120. int cch)
  121. {
  122. LPSTR lpstr;
  123. int iReturn;
  124. lpstr = (LPSTR)GlobalAlloc(GPTR, cch);
  125. if (NULL == lpstr)
  126. {
  127. return 0;
  128. }
  129. iReturn = LoadStringA(hinst, uID, lpstr, cch);
  130. if (0 == iReturn)
  131. {
  132. if (0 != cch)
  133. {
  134. lpwstr[0] = '\0';
  135. }
  136. }
  137. else
  138. {
  139. MultiByteToWideChar( GetACP(), 0, lpstr, cch, lpwstr, cch );
  140. }
  141. GlobalFree((HGLOBAL)lpstr);
  142. return iReturn;
  143. }
  144. #endif // UNICODE
  145. #endif // _WIN32
  146. //==========================================================================;
  147. //
  148. //
  149. //
  150. //
  151. //==========================================================================;
  152. //--------------------------------------------------------------------------;
  153. //
  154. // BOOL pcmIsValidFormat
  155. //
  156. // Description:
  157. // This function verifies that a wave format header is a valid PCM
  158. // header that _this_ ACM driver can deal with.
  159. //
  160. // Arguments:
  161. // LPWAVEFORMATEX pwfx: Pointer to format header to verify.
  162. //
  163. // Return (BOOL):
  164. // The return value is non-zero if the format header looks valid. A
  165. // zero return means the header is not valid.
  166. //
  167. //--------------------------------------------------------------------------;
  168. BOOL FNLOCAL pcmIsValidFormat
  169. (
  170. LPWAVEFORMATEX pwfx
  171. )
  172. {
  173. if (NULL == pwfx)
  174. return (FALSE);
  175. if (WAVE_FORMAT_PCM != pwfx->wFormatTag)
  176. return (FALSE);
  177. //
  178. // verify nChannels member is within the allowed range
  179. //
  180. if ((pwfx->nChannels < 1) || (pwfx->nChannels > ACM_DRIVER_MAX_CHANNELS))
  181. return (FALSE);
  182. //
  183. // only allow the bits per sample that we can encode and decode with
  184. //
  185. if (16 != pwfx->wBitsPerSample)
  186. return (FALSE);
  187. //
  188. // now verify that the block alignment is correct..
  189. //
  190. if (PCM_BLOCKALIGNMENT((LPPCMWAVEFORMAT)pwfx) != pwfx->nBlockAlign)
  191. return (FALSE);
  192. //
  193. // finally, verify that avg bytes per second is correct
  194. //
  195. if (PCM_AVGBYTESPERSEC((LPPCMWAVEFORMAT)pwfx) != pwfx->nAvgBytesPerSec)
  196. return (FALSE);
  197. return (TRUE);
  198. } // pcmIsValidFormat()
  199. //--------------------------------------------------------------------------;
  200. //
  201. // BOOL g711IsValidFormat
  202. //
  203. // Description:
  204. // This function verifies that a wave format header is a valid
  205. // G711 format header that _this_ ACM driver can deal with.
  206. //
  207. // Arguments:
  208. // LPWAVEFORMATEX pwfx: Pointer to format header to verify.
  209. //
  210. // Return (BOOL):
  211. // The return value is non-zero if the format header looks valid. A
  212. // zero return means the header is not valid.
  213. //
  214. //--------------------------------------------------------------------------;
  215. BOOL FNLOCAL g711IsValidFormat
  216. (
  217. LPWAVEFORMATEX pwfx
  218. )
  219. {
  220. if (NULL == pwfx)
  221. return (FALSE);
  222. if ((WAVE_FORMAT_MULAW != pwfx->wFormatTag) &&
  223. (WAVE_FORMAT_ALAW != pwfx->wFormatTag))
  224. return (FALSE);
  225. //
  226. // check channels
  227. //
  228. if ((pwfx->nChannels < 1) || (pwfx->nChannels > ACM_DRIVER_MAX_CHANNELS))
  229. return (FALSE);
  230. //
  231. // now verify that the block alignment is correct..
  232. //
  233. #if 0
  234. if (G711_BLOCKALIGNMENT(pwfx) != (UINT)pwfx->nBlockAlign)
  235. return (FALSE);
  236. #else
  237. //
  238. // unfortunately there has been at least one company who didn't
  239. // understand what the block alignment was really for and authored
  240. // a bunch of files incorrectly. to allow those files to work, we
  241. // will just make sure that whole samples remain...
  242. //
  243. // this codec will only author G711 formats with correct block
  244. // alignments however.
  245. //
  246. if (0 != (pwfx->nBlockAlign % G711_BLOCKALIGNMENT(pwfx)))
  247. return (FALSE);
  248. #endif
  249. //
  250. // verify that avg bytes per second is correct
  251. //
  252. if (G711_AVGBYTESPERSEC(pwfx) != pwfx->nAvgBytesPerSec)
  253. return (FALSE);
  254. //
  255. // check wBitsPerSample
  256. //
  257. if (G711_BITS_PER_SAMPLE != pwfx->wBitsPerSample)
  258. return (FALSE);
  259. //
  260. // cbSize must be validated also..
  261. //
  262. if (G711_WFX_EXTRA_BYTES != pwfx->cbSize)
  263. return (FALSE);
  264. return (TRUE);
  265. } // g711IsValidFormat()
  266. //==========================================================================;
  267. //
  268. //
  269. //
  270. //
  271. //==========================================================================;
  272. //--------------------------------------------------------------------------;
  273. //
  274. // LRESULT acmdDriverOpen
  275. //
  276. // Description:
  277. // This function is used to handle the DRV_OPEN message for the ACM
  278. // driver. The driver is 'opened' for many reasons with the most common
  279. // being in preperation for conversion work. It is very important that
  280. // the driver be able to correctly handle multiple open driver
  281. // instances.
  282. //
  283. // Read the comments for this function carefully!
  284. //
  285. // Note that multiple _streams_ can (and will) be opened on a single
  286. // open _driver instance_. Do not store/create instance data that must
  287. // be unique for each stream in this function. See the acmdStreamOpen
  288. // function for information on conversion streams.
  289. //
  290. // Arguments:
  291. // HDRVR hdrvr: Driver handle that will be returned to caller of the
  292. // OpenDriver function. Normally, this will be the ACM--but this is
  293. // not guaranteed. For example, if an ACM driver is implemented within
  294. // a waveform driver, then the driver will be opened by both MMSYSTEM
  295. // and the ACM.
  296. //
  297. // LPACMDRVOPENDESC paod: Open description defining how the ACM driver
  298. // is being opened. This argument may be NULL--see the comments below
  299. // for more information.
  300. //
  301. // Return (LRESULT):
  302. // The return value is non-zero if the open is successful. A zero
  303. // return signifies that the driver cannot be opened.
  304. //
  305. //--------------------------------------------------------------------------;
  306. LRESULT FNLOCAL acmdDriverOpen
  307. (
  308. HDRVR hdrvr,
  309. LPACMDRVOPENDESC paod
  310. )
  311. {
  312. PDRIVERINSTANCE pdi;
  313. //
  314. // the [optional] open description that is passed to this driver can
  315. // be from multiple 'managers.' for example, AVI looks for installable
  316. // drivers that are tagged with 'vidc' and 'vcap'. we need to verify
  317. // that we are being opened as an Audio Compression Manager driver.
  318. //
  319. // if paod is NULL, then the driver is being opened for some purpose
  320. // other than converting (that is, there will be no stream open
  321. // requests for this instance of being opened). the most common case
  322. // of this is the Control Panel's Drivers option checking for config
  323. // support (DRV_[QUERY]CONFIGURE).
  324. //
  325. // we want to succeed this open, but be able to know that this
  326. // open instance is bogus for creating streams. for this purpose we
  327. // leave most of the members of our instance structure that we
  328. // allocate below as zero...
  329. //
  330. if (NULL != paod)
  331. {
  332. //
  333. // refuse to open if we are not being opened as an ACM driver.
  334. // note that we do NOT modify the value of paod->dwError in this
  335. // case.
  336. //
  337. if (ACMDRIVERDETAILS_FCCTYPE_AUDIOCODEC != paod->fccType)
  338. {
  339. return (0L);
  340. }
  341. }
  342. //
  343. // we are being opened as an installable driver--we can allocate some
  344. // instance data to be returned in dwId argument of the DriverProc;
  345. // or simply return non-zero to succeed the open.
  346. //
  347. // this driver allocates a small instance structure. note that we
  348. // rely on allocating the memory as zero-initialized!
  349. //
  350. pdi = (PDRIVERINSTANCE)LocalAlloc(LPTR, sizeof(*pdi));
  351. if (NULL == pdi)
  352. {
  353. //
  354. // if this open attempt was as an ACM driver, then return the
  355. // reason we are failing in the open description structure..
  356. //
  357. if (NULL != paod)
  358. {
  359. paod->dwError = MMSYSERR_NOMEM;
  360. }
  361. //
  362. // fail to open
  363. //
  364. return (0L);
  365. }
  366. //
  367. // fill in our instance structure... note that this instance data
  368. // can be anything that the ACM driver wishes to maintain the
  369. // open driver instance. this data should not contain any information
  370. // that must be maintained per open stream since multiple streams
  371. // can be opened on a single driver instance.
  372. //
  373. // also note that we do _not_ check the version of the ACM opening
  374. // us (paod->dwVersion) to see if it is at least new enough to work
  375. // with this driver (for example, if this driver required Version 3.0
  376. // of the ACM and a Version 2.0 installation tried to open us). the
  377. // reason we do not fail is to allow the ACM to get the driver details
  378. // which contains the version of the ACM that is _required_ by this
  379. // driver. the ACM will examine that value (in padd->vdwACM) and
  380. // do the right thing for this driver... like not load it and inform
  381. // the user of the problem.
  382. //
  383. pdi->hdrvr = hdrvr;
  384. pdi->hinst = GetDriverModuleHandle(hdrvr); // Module handle.
  385. if (NULL != paod)
  386. {
  387. pdi->fnDriverProc = NULL;
  388. pdi->fccType = paod->fccType;
  389. pdi->vdwACM = paod->dwVersion;
  390. pdi->fdwOpen = paod->dwFlags;
  391. pdi->fdwConfig = 0L;
  392. paod->dwError = MMSYSERR_NOERROR;
  393. }
  394. //
  395. // non-zero return is success for DRV_OPEN
  396. //
  397. return ((LRESULT)(UINT_PTR)pdi);
  398. } // acmdDriverOpen()
  399. //--------------------------------------------------------------------------;
  400. //
  401. // LRESULT acmdDriverClose
  402. //
  403. // Description:
  404. // This function handles the DRV_CLOSE message for the ACM driver. The
  405. // driver receives a DRV_CLOSE message for each succeeded DRV_OPEN
  406. // message (see acmdDriverOpen). The driver will only receive a close
  407. // message for _successful_ opens.
  408. //
  409. // Arguments:
  410. // PDRIVERINSTANCE pdi: Pointer to private ACM driver instance structure.
  411. // This structure is [optionally] allocated during the DRV_OPEN message
  412. // which is handled by the acmdDriverOpen function.
  413. //
  414. // Return (LRESULT):
  415. // The return value is non-zero if the open instance can be closed.
  416. // A zero return signifies that the ACM driver instance could not be
  417. // closed.
  418. //
  419. // NOTE! It is _strongly_ recommended that the driver never fail to
  420. // close. Note that the ACM will never allow a driver instance to
  421. // be closed if there are open streams. An ACM driver does not need
  422. // to check for this case.
  423. //
  424. //--------------------------------------------------------------------------;
  425. LRESULT FNLOCAL acmdDriverClose
  426. (
  427. PDRIVERINSTANCE pdi
  428. )
  429. {
  430. //
  431. // check to see if we allocated instance data. if we did not, then
  432. // immediately succeed.
  433. //
  434. if (NULL != pdi)
  435. {
  436. //
  437. // close down the driver instance. this driver simply needs
  438. // to free the instance data structure... note that if this
  439. // 'free' fails, then this ACM driver probably trashed its
  440. // heap; assume we didn't do that.
  441. //
  442. LocalFree((HLOCAL)pdi);
  443. }
  444. //
  445. // non-zero return is success for DRV_CLOSE
  446. //
  447. return (1L);
  448. } // acmdDriverClose()
  449. //--------------------------------------------------------------------------;
  450. //
  451. // LRESULT acmdDriverConfigure
  452. //
  453. // Description:
  454. // This function is called to handle the DRV_[QUERY]CONFIGURE messages.
  455. // These messages are for 'configuration' support of the driver.
  456. // Normally this will be for 'hardware'--that is, a dialog should be
  457. // displayed to configure ports, IRQ's, memory mappings, etc if it
  458. // needs to. However, a software only ACM driver may also require
  459. // configuration for 'what is real time' or other quality vs time
  460. // issues.
  461. //
  462. // The most common way that these messages are generated under Win 3.1
  463. // and NT Product 1 is from the Control Panel's Drivers option. Other
  464. // sources may generate these messages in future versions of Windows.
  465. //
  466. // Arguments:
  467. // PDRIVERINSTANCE pdi: Pointer to private ACM driver instance structure.
  468. // This structure is [optionally] allocated during the DRV_OPEN message
  469. // which is handled by the acmdDriverOpen function.
  470. //
  471. // HWND hwnd: Handle to parent window to use when displaying the
  472. // configuration dialog box. An ACM driver is _required_ to display a
  473. // modal dialog box using this hwnd argument as the parent. This
  474. // argument may be (HWND)-1 which tells the driver that it is only
  475. // being queried for configuration support.
  476. //
  477. // LPDRVCONFIGINFO pdci: Pointer to optional DRVCONFIGINFO structure.
  478. // If this argument is NULL, then the ACM driver should invent its own
  479. // storage location.
  480. //
  481. // Return (LRESULT):
  482. // If the driver is being 'queried' for configuration support (that is,
  483. // hwnd == (HWND)-1), then non-zero should be returned specifying
  484. // the driver does support a configuration dialog--or zero should be
  485. // returned specifying that no configuration dialog is supported.
  486. //
  487. // If the driver is being called to display the configuration dialog
  488. // (that is, hwnd != (HWND)-1), then one of the following values
  489. // should be returned:
  490. //
  491. // DRVCNF_CANCEL (0x0000): specifies that the dialog was displayed
  492. // and canceled by the user. this value should also be returned if
  493. // no configuration information was modified.
  494. //
  495. // DRVCNF_OK (0x0001): specifies that the dialog was displayed and
  496. // the user pressed OK. This value should be returned even if the
  497. // user didn't change anything - otherwise, the driver may not
  498. // install properly.
  499. //
  500. // DRVCNF_RESTART (0x0002): specifies that the dialog was displayed
  501. // and some configuration information was changed that requires
  502. // Windows to be restarted before the changes take affect. the driver
  503. // should remain configured with current values until the driver
  504. // has been 'rebooted'.
  505. //
  506. //--------------------------------------------------------------------------;
  507. LRESULT FNLOCAL acmdDriverConfigure
  508. (
  509. PDRIVERINSTANCE pdi,
  510. HWND hwnd,
  511. LPDRVCONFIGINFO pdci
  512. )
  513. {
  514. //
  515. // first check to see if we are only being queried for configuration
  516. // support. if hwnd == (HWND)-1 then we are being queried and should
  517. // return zero for 'not supported' and non-zero for 'supported'.
  518. //
  519. if ((HWND)-1 == hwnd)
  520. {
  521. //
  522. // this ACM driver does NOT support a configuration dialog box, so
  523. // return zero...
  524. //
  525. return (0L);
  526. }
  527. //
  528. // we are being asked to bring up our configuration dialog. if this
  529. // driver supports a configuration dialog box, then after the dialog
  530. // is dismissed we must return one of the following values:
  531. //
  532. // DRVCNF_CANCEL (0x0000): specifies that the dialog was displayed
  533. // and canceled by the user. this value should also be returned if
  534. // no configuration information was modified.
  535. //
  536. // DRVCNF_OK (0x0001): specifies that the dialog was displayed and
  537. // the user pressed OK. This value should be returned even if the
  538. // user didn't change anything - otherwise, the driver may not
  539. // install properly.
  540. //
  541. // DRVCNF_RESTART (0x0002): specifies that the dialog was displayed
  542. // and some configuration information was changed that requires
  543. // Windows to be restarted before the changes take affect. the driver
  544. // should remain configured with current values until the driver
  545. // has been 'rebooted'.
  546. //
  547. //
  548. // return DRVCNF_CANCEL--this ACM driver does not support configuration
  549. //
  550. return (DRVCNF_CANCEL);
  551. } // acmdDriverConfigure()
  552. //--------------------------------------------------------------------------;
  553. //
  554. // LRESULT acmdDriverDetails
  555. //
  556. // Description:
  557. // This function handles the ACMDM_DRIVER_DETAILS message. The ACM
  558. // driver is responsible for filling in the ACMDRIVERDETAILS structure
  559. // with various information.
  560. //
  561. // NOTE! It is *VERY* important that you fill in your ACMDRIVERDETAILS
  562. // structure correctly. The ACM and applications must be able to
  563. // rely on this information.
  564. //
  565. // WARNING! The _reserved_ bits of any fields of the ACMDRIVERDETAILS
  566. // structure are _exactly that_: RESERVED. Do NOT use any extra
  567. // flag bits, etc. for custom information. The proper way to add
  568. // custom capabilities to your ACM driver is this:
  569. //
  570. // o define a new message in the ACMDM_USER range.
  571. //
  572. // o an application that wishes to use one of these extra features
  573. // should then:
  574. //
  575. // o open the driver with acmDriverOpen.
  576. //
  577. // o check for the proper wMid and wPid using acmDriverDetails.
  578. //
  579. // o send the 'user defined' message with acmDriverMessage
  580. // to retrieve additional information, etc.
  581. //
  582. // o close the driver with acmDriverClose.
  583. //
  584. // Arguments:
  585. // PDRIVERINSTANCE pdi: Pointer to private ACM driver instance structure.
  586. // This structure is [optionally] allocated during the DRV_OPEN message
  587. // which is handled by the acmdDriverOpen function.
  588. //
  589. // LPACMDRIVERDETAILS padd: Pointer to ACMDRIVERDETAILS structure to
  590. // fill in for the caller. This structure may be larger or smaller than
  591. // the current definition of ACMDRIVERDETAILS--cbStruct specifies the
  592. // valid size.
  593. //
  594. // Return (LRESULT):
  595. // The return value is zero (MMSYSERR_NOERROR) for success. Non-zero
  596. // signifies that the driver details could not be retrieved.
  597. //
  598. // NOTE THAT THIS FUNCTION SHOULD NEVER FAIL! There are two possible
  599. // error conditions:
  600. //
  601. // o if padd is NULL or an invalid pointer.
  602. //
  603. // o if cbStruct is less than four; in this case, there is not enough
  604. // room to return the number of bytes filled in.
  605. //
  606. // Because these two error conditions are easily defined, the ACM
  607. // will catch these errors. The driver does NOT need to check for these
  608. // conditions.
  609. //
  610. //--------------------------------------------------------------------------;
  611. LRESULT FNLOCAL acmdDriverDetails
  612. (
  613. PDRIVERINSTANCE pdi,
  614. LPACMDRIVERDETAILS padd
  615. )
  616. {
  617. ACMDRIVERDETAILS add;
  618. DWORD cbStruct;
  619. //
  620. // it is easiest to fill in a temporary structure with valid info
  621. // and then copy the requested number of bytes to the destination
  622. // buffer.
  623. //
  624. cbStruct = min(padd->cbStruct, sizeof(ACMDRIVERDETAILS));
  625. add.cbStruct = cbStruct;
  626. //
  627. // for the current implementation of an ACM driver, the fccType and
  628. // fccComp members *MUST* always be ACMDRIVERDETAILS_FCCTYPE_AUDIOCODEC
  629. // ('audc') and ACMDRIVERDETAILS_FCCCOMP_UNDEFINED (0) respectively.
  630. //
  631. add.fccType = ACMDRIVERDETAILS_FCCTYPE_AUDIOCODEC;
  632. add.fccComp = ACMDRIVERDETAILS_FCCCOMP_UNDEFINED;
  633. //
  634. // the manufacturer id (wMid) and product id (wPid) must be filled
  635. // in with your company's _registered_ identifier's. for more
  636. // information on these identifier's and how to get them registered
  637. // contact Microsoft and get the Multimedia Developer Registration Kit:
  638. //
  639. // Microsoft Corporation
  640. // Multimedia Technology Group
  641. // One Microsoft Way
  642. // Redmond, WA 98052-6399
  643. //
  644. // Developer Services Phone: (800) 227-4679 x11771
  645. //
  646. // note that during the development phase or your ACM driver, you may
  647. // use the reserved value of '0' for both wMid and wPid. however it
  648. // is not acceptable to ship a driver with these values.
  649. //
  650. add.wMid = MM_MICROSOFT;
  651. add.wPid = MM_MSFT_ACM_G711;
  652. //
  653. // the vdwACM and vdwDriver members contain version information for
  654. // the driver.
  655. //
  656. // vdwACM: must contain the version of the *ACM* that the driver was
  657. // _designed_ for. this is the _minimum_ version number of the ACM
  658. // that the driver will work with. this value must be >= V2.00.000.
  659. //
  660. // vdwDriver: the version of this ACM driver.
  661. //
  662. // ACM driver versions are 32 bit numbers broken into three parts as
  663. // follows (note these parts are displayed as decimal values):
  664. //
  665. // bits 24 - 31: 8 bit _major_ version number
  666. // bits 16 - 23: 8 bit _minor_ version number
  667. // bits 0 - 15: 16 bit build number
  668. //
  669. add.vdwACM = VERSION_MSACM;
  670. add.vdwDriver = VERSION_ACM_DRIVER;
  671. //
  672. // the following flags are used to specify the type of conversion(s)
  673. // that the ACM driver supports. note that a driver may support one or
  674. // more of these flags in any combination.
  675. //
  676. // ACMDRIVERDETAILS_SUPPORTF_CODEC: this flag is set if the driver
  677. // supports conversions from one format tag to another format tag. for
  678. // example, if a converter compresses or decompresses WAVE_FORMAT_PCM
  679. // and WAVE_FORMAT_IMA_ADPCM, then this bit should be set. this is
  680. // true even if the data is not actually changed in size--for example
  681. // a conversion from u-Law to A-Law will still set this bit because
  682. // the format tags differ.
  683. //
  684. // ACMDRIVERDETAILS_SUPPORTF_CONVERTER: this flags is set if the
  685. // driver supports conversions on the same format tag. as an example,
  686. // the PCM converter that is built into the ACM sets this bit (and only
  687. // this bit) because it converts only between PCM formats (bits, sample
  688. // rate).
  689. //
  690. // ACMDRIVERDETAILS_SUPPORTF_FILTER: this flag is set if the driver
  691. // supports transformations on a single format tag but does change
  692. // the base characteristics of the format (bit depth, sample rate, etc
  693. // will remain the same). for example, a driver that changed the
  694. // 'volume' of PCM data or applied a low pass filter would set this bit.
  695. //
  696. add.fdwSupport = ACMDRIVERDETAILS_SUPPORTF_CODEC;
  697. //
  698. // the number of individual format tags this ACM driver supports. for
  699. // example, if a driver uses the WAVE_FORMAT_IMA_ADPCM and
  700. // WAVE_FORMAT_PCM format tags, then this value would be two. if the
  701. // driver only supports filtering on WAVE_FORMAT_PCM, then this value
  702. // would be one. if this driver supported WAVE_FORMAT_ALAW,
  703. // WAVE_FORMAT_MULAW and WAVE_FORMAT_PCM, then this value would be
  704. // three. etc, etc.
  705. //
  706. add.cFormatTags = ACM_DRIVER_MAX_FORMAT_TAGS;
  707. //
  708. // the number of individual filter tags this ACM driver supports. if
  709. // a driver supports no filters (ACMDRIVERDETAILS_SUPPORTF_FILTER is
  710. // NOT set in the fdwSupport member), then this value must be zero.
  711. //
  712. add.cFilterTags = ACM_DRIVER_MAX_FILTER_TAGS;
  713. //
  714. // the remaining members in the ACMDRIVERDETAILS structure are sometimes
  715. // not needed. because of this we make a quick check to see if we
  716. // should go through the effort of filling in these members.
  717. //
  718. if (FIELD_OFFSET(ACMDRIVERDETAILS, hicon) < cbStruct)
  719. {
  720. //
  721. // fill in the hicon member will a handle to a custom icon for
  722. // the ACM driver. this allows the driver to be represented by
  723. // an application graphically (usually this will be a company
  724. // logo or something). if a driver does not wish to have a custom
  725. // icon displayed, then simply set this member to NULL and a
  726. // generic icon will be displayed instead.
  727. //
  728. // See the MSFILTER sample for a codec which contains a custom icon.
  729. //
  730. add.hicon = NULL;
  731. //
  732. // the short name and long name are used to represent the driver
  733. // in a unique description. the short name is intended for small
  734. // display areas (for example, in a menu or combo box). the long
  735. // name is intended for more descriptive displays (for example,
  736. // in an 'about box').
  737. //
  738. // NOTE! an ACM driver should never place formatting characters
  739. // of any sort in these strings (for example CR/LF's, etc). it
  740. // is up to the application to format the text.
  741. //
  742. LoadStringCodec(pdi->hinst, IDS_ACM_DRIVER_SHORTNAME, add.szShortName, SIZEOFACMSTR(add.szShortName));
  743. LoadStringCodec(pdi->hinst, IDS_ACM_DRIVER_LONGNAME, add.szLongName, SIZEOFACMSTR(add.szLongName));
  744. //
  745. // the last three members are intended for 'about box' information.
  746. // these members are optional and may be zero length strings if
  747. // the driver wishes.
  748. //
  749. // NOTE! an ACM driver should never place formatting characters
  750. // of any sort in these strings (for example CR/LF's, etc). it
  751. // is up to the application to format the text.
  752. //
  753. if (FIELD_OFFSET(ACMDRIVERDETAILS, szCopyright) < cbStruct)
  754. {
  755. LoadStringCodec(pdi->hinst, IDS_ACM_DRIVER_COPYRIGHT, add.szCopyright, SIZEOFACMSTR(add.szCopyright));
  756. LoadStringCodec(pdi->hinst, IDS_ACM_DRIVER_LICENSING, add.szLicensing, SIZEOFACMSTR(add.szLicensing));
  757. LoadStringCodec(pdi->hinst, IDS_ACM_DRIVER_FEATURES, add.szFeatures, SIZEOFACMSTR(add.szFeatures));
  758. }
  759. }
  760. //
  761. // now copy the correct number of bytes to the caller's buffer
  762. //
  763. _fmemcpy(padd, &add, (UINT)add.cbStruct);
  764. //
  765. // success!
  766. //
  767. return (MMSYSERR_NOERROR);
  768. } // acmdDriverDetails()
  769. //--------------------------------------------------------------------------;
  770. //
  771. // LRESULT acmdDriverAbout
  772. //
  773. // Description:
  774. // This function is called to handle the ACMDM_DRIVER_ABOUT message.
  775. // An ACM driver has the option of displaying its own 'about box' or
  776. // letting the ACM (or calling application) display one for it. This
  777. // message is normally sent by the Control Panel's Sound Mapper
  778. // option.
  779. //
  780. // It is recommended that an ACM driver allow a default about box
  781. // be displayed for it--there should be no reason to bloat the size
  782. // of a driver to simply display copyright, etc information when that
  783. // information is contained in the ACMDRIVERDETAILS structure.
  784. //
  785. // Arguments:
  786. // PDRIVERINSTANCE pdi: Pointer to private ACM driver instance structure.
  787. // This structure is [optionally] allocated during the DRV_OPEN message
  788. // which is handled by the acmdDriverOpen function.
  789. //
  790. // HWND hwnd: Handle to parent window to use when displaying the
  791. // configuration dialog box. An ACM driver is _required_ to display a
  792. // modal dialog box using this hwnd argument as the parent. This
  793. // argument may be (HWND)-1 which tells the driver that it is only
  794. // being queried for about box support.
  795. //
  796. // Return (LRESULT):
  797. // The return value is MMSYSERR_NOTSUPPORTED if the ACM driver does
  798. // not support a custom dialog box. In this case, the ACM or calling
  799. // application will display a generic about box using the information
  800. // contained in the ACMDRIVERDETAILS structure returned by the
  801. // ACMDM_DRIVER_DETAILS message.
  802. //
  803. // If the driver chooses to display its own dialog box, then after
  804. // the dialog is dismissed by the user, MMSYSERR_NOERROR should be
  805. // returned.
  806. //
  807. // If the hwnd argument is equal to (HWND)-1, then no dialog should
  808. // be displayed (the driver is only being queried for support). The
  809. // driver must still return MMSYSERR_NOERROR (supported) or
  810. // MMSYSERR_NOTSUPPORTED (no custom about box supported).
  811. //
  812. //--------------------------------------------------------------------------;
  813. LRESULT FNLOCAL acmdDriverAbout
  814. (
  815. PDRIVERINSTANCE pdi,
  816. HWND hwnd
  817. )
  818. {
  819. //
  820. // first check to see if we are only being queried for custom about
  821. // box support. if hwnd == (HWND)-1 then we are being queried and
  822. // should return MMSYSERR_NOTSUPPORTED for 'not supported' and
  823. // MMSYSERR_NOERROR for 'supported'.
  824. //
  825. if ((HWND)-1 == hwnd)
  826. {
  827. //
  828. // this ACM driver does NOT support a custom about box, so
  829. // return MMSYSERR_NOTSUPPORTED...
  830. //
  831. return (MMSYSERR_NOTSUPPORTED);
  832. }
  833. //
  834. // this driver does not support a custom dialog, so tell the ACM or
  835. // calling application to display one for us. note that this is the
  836. // _recommended_ method for consistency and simplicity of ACM drivers.
  837. // why write code when you don't have to?
  838. //
  839. return (MMSYSERR_NOTSUPPORTED);
  840. } // acmdDriverAbout()
  841. //==========================================================================;
  842. //
  843. //
  844. //
  845. //
  846. //==========================================================================;
  847. //--------------------------------------------------------------------------;
  848. //
  849. // LRESULT acmdFormatSuggest
  850. //
  851. // Description:
  852. // This function handles the ACMDM_FORMAT_SUGGEST message. The purpose
  853. // of this function is to provide a way for the ACM, a wave mapper or
  854. // an application to quickly get a destination format that this driver
  855. // can convert the source format to. The 'suggested' format should
  856. // be as close to a common format as possible. This message is normally
  857. // sent in response to an acmFormatSuggest function call.
  858. //
  859. // Another way to think about this message is: what format would this
  860. // driver like to convert the source format to?
  861. //
  862. // The caller may place restrictions on the destination format that
  863. // should be suggested. The padfs->fdwSuggest member contains the
  864. // restriction bits passed by the caller--see the description for
  865. // the return value for more information.
  866. //
  867. // Arguments:
  868. // PDRIVERINSTANCE pdi: Pointer to private ACM driver instance structure.
  869. // This structure is [optionally] allocated during the DRV_OPEN message
  870. // which is handled by the acmdDriverOpen function.
  871. //
  872. // LPACMDRVFORMATSUGGEST padfs: Pointer to an ACMDRVFORMATSUGGEST
  873. // structure that describes the source and destination (possibly with
  874. // restrictions) for a conversion.
  875. //
  876. // Return (LRESULT):
  877. // The return value is zero (MMSYSERR_NOERROR) if this function
  878. // succeeds with no errors. The return value is a non-zero error code
  879. // if the function fails.
  880. //
  881. // The driver should return MMSYSERR_NOTSUPPORTED if one or more of
  882. // the destination restriction bits is not supported. It is strongly
  883. // recommended that the driver support at least the following suggestion
  884. // restriction bits:
  885. //
  886. // ACM_FORMATSUGGESTF_WFORMATTAG: The destination format tag must be
  887. // the same as the wFormatTag member in the destination format header.
  888. //
  889. // ACM_FORMATSUGGESTF_NCHANNELS: The destination channel count must be
  890. // the same as the nChannels member in the destination format header.
  891. //
  892. // ACM_FORMATSUGGESTF_NSAMPLESPERSEC: The destination samples per
  893. // second must be the same as the nSamplesPerSec member in the
  894. // destination format header.
  895. //
  896. // ACM_FORMATSUGGESTF_WBITSPERSAMPLE: The destination bits per sample
  897. // must be the same as the wBitsPerSample member in the destination
  898. // format header.
  899. //
  900. // If no destintation format can be suggested, then the driver should
  901. // return ACMERR_NOTPOSSIBLE.
  902. //
  903. //--------------------------------------------------------------------------;
  904. LRESULT FNLOCAL acmdFormatSuggest
  905. (
  906. PDRIVERINSTANCE pdi,
  907. LPACMDRVFORMATSUGGEST padfs
  908. )
  909. {
  910. #define ACMD_FORMAT_SUGGEST_SUPPORT (ACM_FORMATSUGGESTF_WFORMATTAG | \
  911. ACM_FORMATSUGGESTF_NCHANNELS | \
  912. ACM_FORMATSUGGESTF_NSAMPLESPERSEC |\
  913. ACM_FORMATSUGGESTF_WBITSPERSAMPLE)
  914. LPWAVEFORMATEX pwfxSrc;
  915. LPWAVEFORMATEX pwfxDst;
  916. DWORD fdwSuggest;
  917. //
  918. // grab the suggestion restriction bits and verify that we support
  919. // the ones that are specified... an ACM driver must return the
  920. // MMSYSERR_NOTSUPPORTED if the suggestion restriction bits specified
  921. // are not supported.
  922. //
  923. fdwSuggest = (ACM_FORMATSUGGESTF_TYPEMASK & padfs->fdwSuggest);
  924. if (~ACMD_FORMAT_SUGGEST_SUPPORT & fdwSuggest)
  925. return (MMSYSERR_NOTSUPPORTED);
  926. //
  927. // get the source and destination formats in more convenient variables
  928. //
  929. pwfxSrc = padfs->pwfxSrc;
  930. pwfxDst = padfs->pwfxDst;
  931. //
  932. //
  933. //
  934. //
  935. switch (pwfxSrc->wFormatTag)
  936. {
  937. case WAVE_FORMAT_PCM:
  938. //
  939. // strictly verify that the source format is acceptable for
  940. // this driver
  941. //
  942. if (!pcmIsValidFormat(pwfxSrc))
  943. break;
  944. //
  945. // if the destination format tag is restricted, verify that
  946. // it is within our capabilities...
  947. //
  948. // this driver is able to encode to A-Law and u-Law
  949. //
  950. if (ACM_FORMATSUGGESTF_WFORMATTAG & fdwSuggest)
  951. {
  952. if ((WAVE_FORMAT_ALAW != pwfxDst->wFormatTag) &&
  953. (WAVE_FORMAT_MULAW != pwfxDst->wFormatTag))
  954. return (ACMERR_NOTPOSSIBLE);
  955. }
  956. else
  957. {
  958. pwfxDst->wFormatTag = WAVE_FORMAT_ALAW;
  959. }
  960. //
  961. // if the destination channel count is restricted, verify that
  962. // it is within our capabilities...
  963. //
  964. // this driver is not able to change the number of channels
  965. //
  966. if (ACM_FORMATSUGGESTF_NCHANNELS & fdwSuggest)
  967. {
  968. if (pwfxSrc->nChannels != pwfxDst->nChannels)
  969. return (ACMERR_NOTPOSSIBLE);
  970. }
  971. else
  972. {
  973. pwfxDst->nChannels = pwfxSrc->nChannels;
  974. }
  975. //
  976. // if the destination samples per second is restricted, verify
  977. // that it is within our capabilities...
  978. //
  979. // this driver is not able to change the sample rate
  980. //
  981. if (ACM_FORMATSUGGESTF_NSAMPLESPERSEC & fdwSuggest)
  982. {
  983. if (pwfxSrc->nSamplesPerSec != pwfxDst->nSamplesPerSec)
  984. return (ACMERR_NOTPOSSIBLE);
  985. }
  986. else
  987. {
  988. pwfxDst->nSamplesPerSec = pwfxSrc->nSamplesPerSec;
  989. }
  990. //
  991. // if the destination bits per sample is restricted, verify
  992. // that it is within our capabilities...
  993. //
  994. // this driver is only able to encode to 8 bit
  995. //
  996. if (ACM_FORMATSUGGESTF_WBITSPERSAMPLE & fdwSuggest)
  997. {
  998. if (G711_BITS_PER_SAMPLE != pwfxDst->wBitsPerSample)
  999. return (ACMERR_NOTPOSSIBLE);
  1000. }
  1001. else
  1002. {
  1003. pwfxDst->wBitsPerSample = G711_BITS_PER_SAMPLE;
  1004. }
  1005. //
  1006. // at this point, we have filled in all fields except the
  1007. // following for our 'suggested' destination format:
  1008. //
  1009. // nAvgBytesPerSec
  1010. // nBlockAlign
  1011. // cbSize
  1012. //
  1013. pwfxDst->nBlockAlign = G711_BLOCKALIGNMENT(pwfxDst);
  1014. pwfxDst->nAvgBytesPerSec = G711_AVGBYTESPERSEC(pwfxDst);
  1015. pwfxDst->cbSize = G711_WFX_EXTRA_BYTES;
  1016. return (MMSYSERR_NOERROR);
  1017. case WAVE_FORMAT_ALAW:
  1018. case WAVE_FORMAT_MULAW:
  1019. //
  1020. // strictly verify that the source format is acceptable for
  1021. // this driver
  1022. //
  1023. if (!g711IsValidFormat(pwfxSrc))
  1024. return (ACMERR_NOTPOSSIBLE);
  1025. //
  1026. // if the destination format tag is restricted, verify that
  1027. // it is within our capabilities...
  1028. //
  1029. // this driver is able to decode to PCM from u-Law and A-Law
  1030. // as well as convert between u-Law and A-Law
  1031. //
  1032. if (ACM_FORMATSUGGESTF_WFORMATTAG & fdwSuggest)
  1033. {
  1034. switch (pwfxDst->wFormatTag)
  1035. {
  1036. case WAVE_FORMAT_PCM:
  1037. break;
  1038. case WAVE_FORMAT_ALAW:
  1039. if (WAVE_FORMAT_MULAW != pwfxSrc->wFormatTag)
  1040. return (ACMERR_NOTPOSSIBLE);
  1041. break;
  1042. case WAVE_FORMAT_MULAW:
  1043. if (WAVE_FORMAT_ALAW != pwfxSrc->wFormatTag)
  1044. return (ACMERR_NOTPOSSIBLE);
  1045. break;
  1046. default:
  1047. return (ACMERR_NOTPOSSIBLE);
  1048. }
  1049. if (WAVE_FORMAT_PCM == pwfxDst->wFormatTag)
  1050. {
  1051. //
  1052. // if the destination bits per sample is restricted,
  1053. // verify that it is within our capabilities...
  1054. //
  1055. // this driver is only able to decode to 16 bit
  1056. //
  1057. if (ACM_FORMATSUGGESTF_WBITSPERSAMPLE & fdwSuggest)
  1058. {
  1059. if (16 != pwfxDst->wBitsPerSample)
  1060. return (ACMERR_NOTPOSSIBLE);
  1061. }
  1062. else
  1063. {
  1064. pwfxDst->wBitsPerSample = 16;
  1065. }
  1066. }
  1067. else
  1068. {
  1069. //
  1070. // if the destination bits per sample is restricted,
  1071. // verify that it is within our capabilities...
  1072. //
  1073. // this driver is only able to convert between u-Law and
  1074. // A-Law at the same bit depth (8 bit)
  1075. //
  1076. if (ACM_FORMATSUGGESTF_WBITSPERSAMPLE & fdwSuggest)
  1077. {
  1078. if (G711_BITS_PER_SAMPLE != pwfxDst->wBitsPerSample)
  1079. return (ACMERR_NOTPOSSIBLE);
  1080. }
  1081. else
  1082. {
  1083. pwfxDst->wBitsPerSample = G711_BITS_PER_SAMPLE;
  1084. }
  1085. }
  1086. }
  1087. else
  1088. {
  1089. if (ACM_FORMATSUGGESTF_WBITSPERSAMPLE & fdwSuggest)
  1090. {
  1091. if (16 == pwfxDst->wBitsPerSample)
  1092. {
  1093. pwfxDst->wFormatTag = WAVE_FORMAT_PCM;
  1094. }
  1095. else if (8 == pwfxDst->wBitsPerSample)
  1096. {
  1097. if (WAVE_FORMAT_ALAW == pwfxSrc->wFormatTag)
  1098. {
  1099. pwfxDst->wFormatTag = WAVE_FORMAT_MULAW;
  1100. }
  1101. else if (WAVE_FORMAT_MULAW == pwfxSrc->wFormatTag)
  1102. {
  1103. pwfxDst->wFormatTag = WAVE_FORMAT_ALAW;
  1104. }
  1105. else
  1106. {
  1107. return (ACMERR_NOTPOSSIBLE);
  1108. }
  1109. }
  1110. else
  1111. {
  1112. return (ACMERR_NOTPOSSIBLE);
  1113. }
  1114. }
  1115. else
  1116. {
  1117. pwfxDst->wFormatTag = WAVE_FORMAT_PCM;
  1118. pwfxDst->wBitsPerSample = 16;
  1119. }
  1120. }
  1121. //
  1122. // if the destination channel count is restricted, verify that
  1123. // it is within our capabilities...
  1124. //
  1125. // this driver is not able to change the number of channels
  1126. //
  1127. if (ACM_FORMATSUGGESTF_NCHANNELS & fdwSuggest)
  1128. {
  1129. if (pwfxSrc->nChannels != pwfxDst->nChannels)
  1130. return (ACMERR_NOTPOSSIBLE);
  1131. }
  1132. else
  1133. {
  1134. pwfxDst->nChannels = pwfxSrc->nChannels;
  1135. }
  1136. //
  1137. // if the destination samples per second is restricted, verify
  1138. // that it is within our capabilities...
  1139. //
  1140. // this driver is not able to change the sample rate
  1141. //
  1142. if (ACM_FORMATSUGGESTF_NSAMPLESPERSEC & fdwSuggest)
  1143. {
  1144. if (pwfxSrc->nSamplesPerSec != pwfxDst->nSamplesPerSec)
  1145. return (ACMERR_NOTPOSSIBLE);
  1146. }
  1147. else
  1148. {
  1149. pwfxDst->nSamplesPerSec = pwfxSrc->nSamplesPerSec;
  1150. }
  1151. //
  1152. //
  1153. //
  1154. //
  1155. if (WAVE_FORMAT_PCM == pwfxDst->wFormatTag)
  1156. {
  1157. //
  1158. // at this point, we have filled in all fields except the
  1159. // following for our 'suggested' destination format:
  1160. //
  1161. // nAvgBytesPerSec
  1162. // nBlockAlign
  1163. // cbSize !!! not used for PCM !!!
  1164. //
  1165. pwfxDst->nBlockAlign = PCM_BLOCKALIGNMENT((LPPCMWAVEFORMAT)pwfxDst);
  1166. pwfxDst->nAvgBytesPerSec = PCM_AVGBYTESPERSEC((LPPCMWAVEFORMAT)pwfxDst);
  1167. // pwfxDst->cbSize = not used;
  1168. }
  1169. //
  1170. // the suggested destination format tag is not PCM
  1171. //
  1172. else
  1173. {
  1174. //
  1175. // at this point, we have filled in all fields except the
  1176. // following for our 'suggested' destination format:
  1177. //
  1178. // nAvgBytesPerSec
  1179. // nBlockAlign
  1180. // cbSize
  1181. //
  1182. pwfxDst->nBlockAlign = G711_BLOCKALIGNMENT(pwfxDst);
  1183. pwfxDst->nAvgBytesPerSec = G711_AVGBYTESPERSEC(pwfxDst);
  1184. pwfxDst->cbSize = G711_WFX_EXTRA_BYTES;
  1185. }
  1186. return (MMSYSERR_NOERROR);
  1187. }
  1188. //
  1189. // can't suggest anything because either the source format is foreign
  1190. // or the destination format has restrictions that this ACM driver
  1191. // cannot deal with.
  1192. //
  1193. return (ACMERR_NOTPOSSIBLE);
  1194. } // acmdFormatSuggest()
  1195. //==========================================================================;
  1196. //
  1197. //
  1198. //
  1199. //
  1200. //==========================================================================;
  1201. //--------------------------------------------------------------------------;
  1202. //
  1203. // LRESULT acmdFormatTagDetails
  1204. //
  1205. // Description:
  1206. // This function handles the ACMDM_FORMATTAG_DETAILS message. This
  1207. // message is normally sent in response to an acmFormatTagDetails or
  1208. // acmFormatTagEnum function call. The purpose of this function is
  1209. // to get details about a specific format tag supported by this ACM
  1210. // driver.
  1211. //
  1212. // Arguments:
  1213. // PDRIVERINSTANCE pdi: Pointer to private ACM driver instance structure.
  1214. // This structure is [optionally] allocated during the DRV_OPEN message
  1215. // which is handled by the acmdDriverOpen function.
  1216. //
  1217. // LPACMFORMATTAGDETAILS padft: Pointer to an ACMFORMATTAGDETAILS
  1218. // structure that describes what format tag to retrieve details for.
  1219. //
  1220. // DWORD fdwDetails: Flags defining what format tag to retrieve the
  1221. // details for.
  1222. //
  1223. // Return (LRESULT):
  1224. // The return value is zero (MMSYSERR_NOERROR) if this function
  1225. // succeeds with no errors. The return value is a non-zero error code
  1226. // if the function fails.
  1227. //
  1228. // The driver should return MMSYSERR_NOTSUPPORTED if the query type
  1229. // specified in fdwDetails is not supported. An ACM driver must
  1230. // support at least the following query types:
  1231. //
  1232. // ACM_FORMATTAGDETAILSF_INDEX: Indicates that a format tag index
  1233. // was given in the dwFormatTagIndex member of the ACMFORMATTAGDETAILS
  1234. // structure. The format tag and details must be returned in the
  1235. // structure specified by padft. The index ranges from zero to one less
  1236. // than the cFormatTags member returned in the ACMDRIVERDETAILS
  1237. // structure for this driver.
  1238. //
  1239. // ACM_FORMATTAGDETAILSF_FORMATTAG: Indicates that a format tag
  1240. // was given in the dwFormatTag member of the ACMFORMATTAGDETAILS
  1241. // structure. The format tag details must be returned in the structure
  1242. // specified by padft.
  1243. //
  1244. // ACM_FORMATTAGDETAILSF_LARGESTSIZE: Indicates that the details
  1245. // on the format tag with the largest format size in bytes must be
  1246. // returned. The dwFormatTag member will either be WAVE_FORMAT_UNKNOWN
  1247. // or the format tag to find the largest size for.
  1248. //
  1249. // If the details for the specified format tag cannot be retrieved
  1250. // from this driver, then ACMERR_NOTPOSSIBLE should be returned.
  1251. //
  1252. //--------------------------------------------------------------------------;
  1253. LRESULT FNLOCAL acmdFormatTagDetails
  1254. (
  1255. PDRIVERINSTANCE pdi,
  1256. LPACMFORMATTAGDETAILS padft,
  1257. DWORD fdwDetails
  1258. )
  1259. {
  1260. UINT uFormatTag;
  1261. //
  1262. //
  1263. //
  1264. //
  1265. //
  1266. switch (ACM_FORMATTAGDETAILSF_QUERYMASK & fdwDetails)
  1267. {
  1268. case ACM_FORMATTAGDETAILSF_INDEX:
  1269. //
  1270. // if the index is too large, then they are asking for a
  1271. // non-existant format. return error.
  1272. //
  1273. if (ACM_DRIVER_MAX_FORMAT_TAGS <= padft->dwFormatTagIndex)
  1274. return (ACMERR_NOTPOSSIBLE);
  1275. uFormatTag = gauFormatTagIndexToTag[(UINT)padft->dwFormatTagIndex];
  1276. break;
  1277. case ACM_FORMATTAGDETAILSF_LARGESTSIZE:
  1278. switch (padft->dwFormatTag)
  1279. {
  1280. case WAVE_FORMAT_UNKNOWN:
  1281. case WAVE_FORMAT_ALAW:
  1282. uFormatTag = WAVE_FORMAT_ALAW;
  1283. break;
  1284. case WAVE_FORMAT_MULAW:
  1285. uFormatTag = WAVE_FORMAT_MULAW;
  1286. break;
  1287. case WAVE_FORMAT_PCM:
  1288. uFormatTag = WAVE_FORMAT_PCM;
  1289. break;
  1290. default:
  1291. return (ACMERR_NOTPOSSIBLE);
  1292. }
  1293. break;
  1294. case ACM_FORMATTAGDETAILSF_FORMATTAG:
  1295. switch (padft->dwFormatTag)
  1296. {
  1297. case WAVE_FORMAT_ALAW:
  1298. uFormatTag = WAVE_FORMAT_ALAW;
  1299. break;
  1300. case WAVE_FORMAT_MULAW:
  1301. uFormatTag = WAVE_FORMAT_MULAW;
  1302. break;
  1303. case WAVE_FORMAT_PCM:
  1304. uFormatTag = WAVE_FORMAT_PCM;
  1305. break;
  1306. default:
  1307. return (ACMERR_NOTPOSSIBLE);
  1308. }
  1309. break;
  1310. //
  1311. // if this ACM driver does not understand a query type, then
  1312. // return 'not supported'
  1313. //
  1314. default:
  1315. return (MMSYSERR_NOTSUPPORTED);
  1316. }
  1317. //
  1318. //
  1319. //
  1320. //
  1321. switch (uFormatTag)
  1322. {
  1323. case WAVE_FORMAT_PCM:
  1324. padft->dwFormatTagIndex = 0;
  1325. padft->dwFormatTag = WAVE_FORMAT_PCM;
  1326. padft->cbFormatSize = sizeof(PCMWAVEFORMAT);
  1327. padft->fdwSupport = ACMDRIVERDETAILS_SUPPORTF_CODEC;
  1328. padft->cStandardFormats = ACM_DRIVER_MAX_FORMATS_PCM;
  1329. //
  1330. // the ACM is responsible for the PCM format tag name
  1331. //
  1332. padft->szFormatTag[0] = '\0';
  1333. break;
  1334. case WAVE_FORMAT_ALAW:
  1335. padft->dwFormatTagIndex = 1;
  1336. padft->dwFormatTag = WAVE_FORMAT_ALAW;
  1337. padft->cbFormatSize = sizeof(WAVEFORMATEX) +
  1338. G711_WFX_EXTRA_BYTES;
  1339. padft->fdwSupport = ACMDRIVERDETAILS_SUPPORTF_CODEC;
  1340. padft->cStandardFormats = ACM_DRIVER_MAX_FORMATS_G711;
  1341. LoadStringCodec(pdi->hinst,
  1342. IDS_ACM_DRIVER_TAG_NAME_ALAW,
  1343. padft->szFormatTag,
  1344. SIZEOFACMSTR(padft->szFormatTag));
  1345. break;
  1346. case WAVE_FORMAT_MULAW:
  1347. padft->dwFormatTagIndex = 2;
  1348. padft->dwFormatTag = WAVE_FORMAT_MULAW;
  1349. padft->cbFormatSize = sizeof(WAVEFORMATEX) +
  1350. G711_WFX_EXTRA_BYTES;
  1351. padft->fdwSupport = ACMDRIVERDETAILS_SUPPORTF_CODEC;
  1352. padft->cStandardFormats = ACM_DRIVER_MAX_FORMATS_G711;
  1353. LoadStringCodec(pdi->hinst,
  1354. IDS_ACM_DRIVER_TAG_NAME_MULAW,
  1355. padft->szFormatTag,
  1356. SIZEOFACMSTR(padft->szFormatTag));
  1357. break;
  1358. default:
  1359. return (ACMERR_NOTPOSSIBLE);
  1360. }
  1361. //
  1362. // return only the requested info
  1363. //
  1364. // the ACM will guarantee that the ACMFORMATTAGDETAILS structure
  1365. // passed is at least large enough to hold the base information of
  1366. // the details structure
  1367. //
  1368. padft->cbStruct = min(padft->cbStruct, sizeof(*padft));
  1369. //
  1370. //
  1371. //
  1372. return (MMSYSERR_NOERROR);
  1373. } // acmdFormatTagDetails()
  1374. //--------------------------------------------------------------------------;
  1375. //
  1376. // LRESULT acmdFormatDetails
  1377. //
  1378. // Description:
  1379. // This function handles the ACMDM_FORMAT_DETAILS message. This
  1380. // message is normally sent in response to an acmFormatDetails or
  1381. // acmFormatEnum function call. The purpose of this function is
  1382. // to get details about a specific format for a specified format tag
  1383. // supported by this ACM driver.
  1384. //
  1385. // Note that an ACM driver can return a zero length string for the
  1386. // format name if it wishes to have the ACM create a format string
  1387. // for it. This is strongly recommended to simplify internationalizing
  1388. // the driver--the ACM will automatically take care of that. The
  1389. // following formula is used to format a string by the ACM:
  1390. //
  1391. // <nSamplesPerSec> kHz, <bit depth> bit, [Mono | Stereo | nChannels]
  1392. //
  1393. // <bit depth> = <nAvgBytesPerSec> * 8 / nSamplesPerSec / nChannels;
  1394. //
  1395. // Arguments:
  1396. // PDRIVERINSTANCE pdi: Pointer to private ACM driver instance structure.
  1397. // This structure is [optionally] allocated during the DRV_OPEN message
  1398. // which is handled by the acmdDriverOpen function.
  1399. //
  1400. // LPACMFORMATDETAILS padf: Pointer to an ACMFORMATDETAILS structure
  1401. // that describes what format (for a specified format tag) to retrieve
  1402. // details for.
  1403. //
  1404. // DWORD fdwDetails: Flags defining what format for a specified format
  1405. // tag to retrieve the details for.
  1406. //
  1407. // Return (LRESULT):
  1408. // The return value is zero (MMSYSERR_NOERROR) if this function
  1409. // succeeds with no errors. The return value is a non-zero error code
  1410. // if the function fails.
  1411. //
  1412. // The driver should return MMSYSERR_NOTSUPPORTED if the query type
  1413. // specified in fdwDetails is not supported. An ACM driver must
  1414. // support at least the following query types:
  1415. //
  1416. // ACM_FORMATDETAILSF_INDEX: Indicates that a format index for the
  1417. // format tag was given in the dwFormatIndex member of the
  1418. // ACMFORMATDETAILS structure. The format details must be returned in
  1419. // the structure specified by padf. The index ranges from zero to one
  1420. // less than the cStandardFormats member returned in the
  1421. // ACMFORMATTAGDETAILS structure for a format tag.
  1422. //
  1423. // ACM_FORMATDETAILSF_FORMAT: Indicates that a WAVEFORMATEX structure
  1424. // pointed to by pwfx of the ACMFORMATDETAILS structure was given and
  1425. // the remaining details should be returned. The dwFormatTag member
  1426. // of the ACMFORMATDETAILS will be initialized to the same format
  1427. // tag as the pwfx member specifies. This query type may be used to
  1428. // get a string description of an arbitrary format structure.
  1429. //
  1430. // If the details for the specified format cannot be retrieved
  1431. // from this driver, then ACMERR_NOTPOSSIBLE should be returned.
  1432. //
  1433. //--------------------------------------------------------------------------;
  1434. LRESULT FNLOCAL acmdFormatDetails
  1435. (
  1436. PDRIVERINSTANCE pdi,
  1437. LPACMFORMATDETAILS padf,
  1438. DWORD fdwDetails
  1439. )
  1440. {
  1441. LPWAVEFORMATEX pwfx;
  1442. UINT uFormatIndex;
  1443. UINT u;
  1444. //
  1445. //
  1446. //
  1447. //
  1448. //
  1449. switch (ACM_FORMATDETAILSF_QUERYMASK & fdwDetails)
  1450. {
  1451. //
  1452. // enumerate by index
  1453. //
  1454. // verify that the format tag is something we know about and
  1455. // return the details on the 'standard format' supported by
  1456. // this driver at the specified index...
  1457. //
  1458. case ACM_FORMATDETAILSF_INDEX:
  1459. //
  1460. // put some stuff in more accessible variables--note that we
  1461. // bring variable sizes down to a reasonable size for 16 bit
  1462. // code...
  1463. //
  1464. pwfx = padf->pwfx;
  1465. uFormatIndex = (UINT)padf->dwFormatIndex;
  1466. switch (padf->dwFormatTag)
  1467. {
  1468. case WAVE_FORMAT_PCM:
  1469. if (ACM_DRIVER_MAX_FORMATS_PCM <= padf->dwFormatIndex)
  1470. return (ACMERR_NOTPOSSIBLE);
  1471. //
  1472. // now fill in the format structure
  1473. //
  1474. pwfx->wFormatTag = WAVE_FORMAT_PCM;
  1475. u = uFormatIndex / (ACM_DRIVER_MAX_BITSPERSAMPLE_PCM * ACM_DRIVER_MAX_CHANNELS);
  1476. pwfx->nSamplesPerSec = gauFormatIndexToSampleRate[u];
  1477. u = uFormatIndex % ACM_DRIVER_MAX_CHANNELS;
  1478. pwfx->nChannels = u + 1;
  1479. pwfx->wBitsPerSample = 16;
  1480. pwfx->nBlockAlign = PCM_BLOCKALIGNMENT((LPPCMWAVEFORMAT)pwfx);
  1481. pwfx->nAvgBytesPerSec = PCM_AVGBYTESPERSEC((LPPCMWAVEFORMAT)pwfx);
  1482. //
  1483. // note that the cbSize field is NOT valid for PCM
  1484. // formats
  1485. //
  1486. // pwfx->cbSize = 0;
  1487. break;
  1488. case WAVE_FORMAT_MULAW:
  1489. case WAVE_FORMAT_ALAW:
  1490. if (ACM_DRIVER_MAX_FORMATS_G711 <= padf->dwFormatIndex)
  1491. return (ACMERR_NOTPOSSIBLE);
  1492. pwfx->wFormatTag = LOWORD(padf->dwFormatTag);
  1493. u = uFormatIndex / (ACM_DRIVER_MAX_BITSPERSAMPLE_G711 * ACM_DRIVER_MAX_CHANNELS);
  1494. pwfx->nSamplesPerSec = gauFormatIndexToSampleRate[u];
  1495. u = uFormatIndex % ACM_DRIVER_MAX_CHANNELS;
  1496. pwfx->nChannels = u + 1;
  1497. pwfx->wBitsPerSample = G711_BITS_PER_SAMPLE;
  1498. pwfx->nBlockAlign = G711_BLOCKALIGNMENT(pwfx);
  1499. pwfx->nAvgBytesPerSec = G711_AVGBYTESPERSEC(pwfx);
  1500. pwfx->cbSize = G711_WFX_EXTRA_BYTES;
  1501. break;
  1502. default:
  1503. return (ACMERR_NOTPOSSIBLE);
  1504. }
  1505. //
  1506. // return details on specified format
  1507. //
  1508. // the caller normally uses this to verify that the format is
  1509. // supported and to retrieve a string description...
  1510. //
  1511. case ACM_FORMATDETAILSF_FORMAT:
  1512. pwfx = padf->pwfx;
  1513. switch (pwfx->wFormatTag)
  1514. {
  1515. case WAVE_FORMAT_PCM:
  1516. if (!pcmIsValidFormat(pwfx))
  1517. return (ACMERR_NOTPOSSIBLE);
  1518. break;
  1519. case WAVE_FORMAT_ALAW:
  1520. case WAVE_FORMAT_MULAW:
  1521. if (!g711IsValidFormat(pwfx))
  1522. return (ACMERR_NOTPOSSIBLE);
  1523. break;
  1524. default:
  1525. return (ACMERR_NOTPOSSIBLE);
  1526. }
  1527. break;
  1528. default:
  1529. //
  1530. // don't know how to do the query type passed--return 'not
  1531. // supported'.
  1532. //
  1533. return (MMSYSERR_NOTSUPPORTED);
  1534. }
  1535. //
  1536. // return the size of the valid information we are returning
  1537. //
  1538. // the ACM will guarantee that the ACMFORMATDETAILS structure
  1539. // passed is at least large enough to hold the base structure
  1540. //
  1541. // note that we let the ACM create the format string for us since
  1542. // we require no special formatting (and don't want to deal with
  1543. // internationalization issues, etc). simply set the string to
  1544. // a zero length.
  1545. //
  1546. padf->cbStruct = min(padf->cbStruct, sizeof(*padf));
  1547. padf->fdwSupport = ACMDRIVERDETAILS_SUPPORTF_CODEC;
  1548. padf->szFormat[0] = '\0';
  1549. //
  1550. //
  1551. //
  1552. return (MMSYSERR_NOERROR);
  1553. } // acmdFormatDetails()
  1554. //==========================================================================;
  1555. //
  1556. //
  1557. //
  1558. //
  1559. //==========================================================================;
  1560. //--------------------------------------------------------------------------;
  1561. //
  1562. // LRESULT acmdStreamOpen
  1563. //
  1564. // Description:
  1565. // This function handles the ACMDM_STREAM_OPEN message. This message
  1566. // is sent to initiate a new conversion stream. This is usually caused
  1567. // by an application calling acmStreamOpen. If this function is
  1568. // successful, then one or more ACMDM_STREAM_CONVERT messages will be
  1569. // sent to convert individual buffers (user calls acmStreamConvert).
  1570. //
  1571. // Note that an ACM driver will not receive open requests for ASYNC
  1572. // or FILTER operations unless the ACMDRIVERDETAILS_SUPPORTF_ASYNC
  1573. // or ACMDRIVERDETAILS_SUPPORTF_FILTER flags are set in the
  1574. // ACMDRIVERDETAILS structure. There is no need for the driver to
  1575. // check for these requests unless it sets those support bits.
  1576. //
  1577. // If the ACM_STREAMOPENF_QUERY flag is set in the padsi->fdwOpen
  1578. // member, then no resources should be allocated. Just verify that
  1579. // the conversion request is possible by this driver and return the
  1580. // appropriate error (either ACMERR_NOTPOSSIBLE or MMSYSERR_NOERROR).
  1581. // The driver will NOT receive an ACMDM_STREAM_CLOSE for queries.
  1582. //
  1583. // If the ACM_STREAMOPENF_NONREALTIME bit is NOT set, then conversion
  1584. // must be done in 'real-time'. This is a tough one to describe
  1585. // exactly. If the driver may have trouble doing the conversion without
  1586. // breaking up the audio, then a configuration dialog might be used
  1587. // to allow the user to specify whether the real-time conversion
  1588. // request should be succeeded. DO NOT SUCCEED THE CALL UNLESS YOU
  1589. // ACTUALLY CAN DO REAL-TIME CONVERSIONS! There may be another driver
  1590. // installed that can--so if you succeed the call you are hindering
  1591. // the performance of the user's system!
  1592. //
  1593. // Arguments:
  1594. // PDRIVERINSTANCE pdi: Pointer to private ACM driver instance structure.
  1595. // This structure is [optionally] allocated during the DRV_OPEN message
  1596. // which is handled by the acmdDriverOpen function.
  1597. //
  1598. // LPACMDRVSTREAMINSTANCE padsi: Pointer to instance data for the
  1599. // conversion stream. This structure was allocated by the ACM and
  1600. // filled with the most common instance data needed for conversions.
  1601. // This structure will be passed back to all future stream messages
  1602. // if the open succeeds. The information in this structure will never
  1603. // change during the lifetime of the stream--so it is not necessary
  1604. // to re-verify the information referenced by this structure.
  1605. //
  1606. // Return (LRESULT):
  1607. // The return value is zero (MMSYSERR_NOERROR) if this function
  1608. // succeeds with no errors. The return value is a non-zero error code
  1609. // if the function fails.
  1610. //
  1611. // A driver should return ACMERR_NOTPOSSIBLE if the conversion cannot
  1612. // be performed due to incompatible source and destination formats.
  1613. //
  1614. // A driver should return MMSYSERR_NOTSUPPORTED if the conversion
  1615. // cannot be performed in real-time and the request does not specify
  1616. // the ACM_STREAMOPENF_NONREALTIME flag.
  1617. //
  1618. //--------------------------------------------------------------------------;
  1619. LRESULT FNLOCAL acmdStreamOpen
  1620. (
  1621. PDRIVERINSTANCE pdi,
  1622. LPACMDRVSTREAMINSTANCE padsi
  1623. )
  1624. {
  1625. LPWAVEFORMATEX pwfxSrc;
  1626. LPWAVEFORMATEX pwfxDst;
  1627. BOOL fRealTime;
  1628. STREAMCONVERTPROC fnConvert;
  1629. PSTREAMINSTANCE psi;
  1630. //
  1631. //
  1632. //
  1633. pwfxSrc = padsi->pwfxSrc;
  1634. pwfxDst = padsi->pwfxDst;
  1635. fRealTime = (0 == (padsi->fdwOpen & ACM_STREAMOPENF_NONREALTIME));
  1636. //
  1637. // the most important condition to check before doing anything else
  1638. // is that this ACM driver can actually perform the conversion we are
  1639. // being opened for. this check should fail as quickly as possible
  1640. // if the conversion is not possible by this driver.
  1641. //
  1642. // it is VERY important to fail quickly so the ACM can attempt to
  1643. // find a driver that is suitable for the conversion. also note that
  1644. // the ACM may call this driver several times with slightly different
  1645. // format specifications before giving up.
  1646. //
  1647. // this driver first verifies that the source and destination formats
  1648. // are acceptable...
  1649. //
  1650. switch (pwfxSrc->wFormatTag)
  1651. {
  1652. case WAVE_FORMAT_PCM:
  1653. if (!pcmIsValidFormat(pwfxSrc))
  1654. return (ACMERR_NOTPOSSIBLE);
  1655. if (!g711IsValidFormat(pwfxDst))
  1656. return (ACMERR_NOTPOSSIBLE);
  1657. //
  1658. //
  1659. //
  1660. if (WAVE_FORMAT_ALAW == pwfxDst->wFormatTag)
  1661. fnConvert = PcmToAlaw;
  1662. else
  1663. fnConvert = PcmToUlaw;
  1664. break;
  1665. case WAVE_FORMAT_ALAW:
  1666. case WAVE_FORMAT_MULAW:
  1667. if (!g711IsValidFormat(pwfxSrc))
  1668. return (ACMERR_NOTPOSSIBLE);
  1669. if (WAVE_FORMAT_PCM == pwfxDst->wFormatTag)
  1670. {
  1671. if (!pcmIsValidFormat(pwfxDst))
  1672. return (ACMERR_NOTPOSSIBLE);
  1673. //
  1674. //
  1675. //
  1676. if (WAVE_FORMAT_ALAW == pwfxSrc->wFormatTag)
  1677. fnConvert = AlawToPcm;
  1678. else
  1679. fnConvert = UlawToPcm;
  1680. }
  1681. else
  1682. {
  1683. if (!g711IsValidFormat(pwfxDst))
  1684. return (ACMERR_NOTPOSSIBLE);
  1685. //
  1686. // we are not a converter for equivelant format tags
  1687. //
  1688. if (pwfxSrc->wFormatTag == pwfxDst->wFormatTag)
  1689. return (ACMERR_NOTPOSSIBLE);
  1690. //
  1691. //
  1692. //
  1693. if (WAVE_FORMAT_ALAW == pwfxSrc->wFormatTag)
  1694. fnConvert = AlawToUlaw;
  1695. else
  1696. fnConvert = UlawToAlaw;
  1697. }
  1698. break;
  1699. default:
  1700. return (ACMERR_NOTPOSSIBLE);
  1701. }
  1702. //
  1703. // for this driver, we must also verify that the nChannels and
  1704. // nSamplesPerSec members are the same between the source and
  1705. // destination formats.
  1706. //
  1707. if (pwfxSrc->nChannels != pwfxDst->nChannels)
  1708. return (MMSYSERR_NOTSUPPORTED);
  1709. if (pwfxSrc->nSamplesPerSec != pwfxDst->nSamplesPerSec)
  1710. return (MMSYSERR_NOTSUPPORTED);
  1711. //
  1712. // we have determined that the conversion requested is possible by
  1713. // this driver. now check if we are just being queried for support.
  1714. // if this is just a query, then do NOT allocate any instance data
  1715. // or create tables, etc. just succeed the call.
  1716. //
  1717. if (0 != (ACM_STREAMOPENF_QUERY & padsi->fdwOpen))
  1718. {
  1719. return (MMSYSERR_NOERROR);
  1720. }
  1721. //
  1722. // we have decided that this driver can handle the conversion stream.
  1723. // so we want to do _AS MUCH WORK AS POSSIBLE_ right now to prepare
  1724. // for converting data. any resource allocation, table building, etc
  1725. // that can be dealt with at this time should be done.
  1726. //
  1727. // THIS IS VERY IMPORTANT! all ACMDM_STREAM_CONVERT messages need to
  1728. // be handled as quickly as possible.
  1729. //
  1730. // this driver allocates a small instance structure for each stream
  1731. //
  1732. //
  1733. psi = (PSTREAMINSTANCE)LocalAlloc(LPTR, sizeof(*psi));
  1734. if (NULL == psi)
  1735. {
  1736. return (MMSYSERR_NOMEM);
  1737. }
  1738. //
  1739. // fill out our instance structure
  1740. //
  1741. // this driver stores a pointer to the conversion function that will
  1742. // be used for each conversion on this stream. we also store a
  1743. // copy of the _current_ configuration of the driver instance we
  1744. // are opened on. this must not change during the life of the stream
  1745. // instance.
  1746. //
  1747. // this is also very important! if the user is able to configure how
  1748. // the driver performs conversions, the changes should only affect
  1749. // future open streams. all current open streams should behave as
  1750. // they were configured during the open.
  1751. //
  1752. psi->fnConvert = fnConvert;
  1753. psi->fdwConfig = pdi->fdwConfig;
  1754. //
  1755. // fill in our instance data--this will be passed back to all stream
  1756. // messages in the ACMDRVSTREAMINSTANCE structure. it is entirely
  1757. // up to the driver what gets stored (and maintained) in the
  1758. // fdwDriver and dwDriver members.
  1759. //
  1760. padsi->fdwDriver = 0L;
  1761. padsi->dwDriver = (DWORD_PTR)psi;
  1762. return (MMSYSERR_NOERROR);
  1763. } // acmdStreamOpen()
  1764. //--------------------------------------------------------------------------;
  1765. //
  1766. // LRESULT acmdStreamClose
  1767. //
  1768. // Description:
  1769. // This function is called to handle the ACMDM_STREAM_CLOSE message.
  1770. // This message is sent when a conversion stream is no longer being
  1771. // used (the stream is being closed; usually by an application
  1772. // calling acmStreamClose). The ACM driver should clean up any resources
  1773. // that were allocated for the stream.
  1774. //
  1775. // Arguments:
  1776. // LPACMDRVSTREAMINSTANCE padsi: Pointer to instance data for the
  1777. // conversion stream. This structure was allocated by the ACM and
  1778. // filled with the most common instance data needed for conversions.
  1779. // The information in this structure is exactly the same as it was
  1780. // during the ACMDM_STREAM_OPEN message--so it is not necessary
  1781. // to re-verify the information referenced by this structure.
  1782. //
  1783. // Return (LRESULT):
  1784. // The return value is zero (MMSYSERR_NOERROR) if this function
  1785. // succeeds with no errors. The return value is a non-zero error code
  1786. // if the function fails.
  1787. //
  1788. // NOTE! It is _strongly_ recommended that a driver not fail to close
  1789. // a conversion stream.
  1790. //
  1791. // An asyncronous conversion stream may fail with ACMERR_BUSY if there
  1792. // are pending buffers. An application may call acmStreamReset to
  1793. // force all pending buffers to be posted.
  1794. //
  1795. //--------------------------------------------------------------------------;
  1796. LRESULT FNLOCAL acmdStreamClose
  1797. (
  1798. LPACMDRVSTREAMINSTANCE padsi
  1799. )
  1800. {
  1801. PSTREAMINSTANCE psi;
  1802. //
  1803. // the driver should clean up all privately allocated resources that
  1804. // were created for maintaining the stream instance. if no resources
  1805. // were allocated, then simply succeed.
  1806. //
  1807. // in the case of this driver, we need to free the stream instance
  1808. // structure that we allocated during acmdStreamOpen.
  1809. //
  1810. psi = (PSTREAMINSTANCE)padsi->dwDriver;
  1811. if (NULL != psi)
  1812. {
  1813. //
  1814. // free the stream instance structure
  1815. //
  1816. LocalFree((HLOCAL)psi);
  1817. }
  1818. return (MMSYSERR_NOERROR);
  1819. } // acmdStreamClose()
  1820. //--------------------------------------------------------------------------;
  1821. //
  1822. // LRESULT acmdStreamSize
  1823. //
  1824. // Description:
  1825. // This function handles the ACMDM_STREAM_SIZE message. The purpose
  1826. // of this function is to provide the _largest size in bytes_ that
  1827. // the source or destination buffer needs to be given the input and
  1828. // output formats and the size in bytes of the source or destination
  1829. // data buffer.
  1830. //
  1831. // In other words: how big does my destination buffer need to be to
  1832. // hold the converted data? (ACM_STREAMSIZEF_SOURCE)
  1833. //
  1834. // Or: how big can my source buffer be given the destination buffer?
  1835. // (ACM_STREAMSIZEF_DESTINATION)
  1836. //
  1837. // Arguments:
  1838. // LPACMDRVSTREAMINSTANCE padsi: Pointer to instance data for the
  1839. // conversion stream. This structure was allocated by the ACM and
  1840. // filled with the most common instance data needed for conversions.
  1841. // The information in this structure is exactly the same as it was
  1842. // during the ACMDM_STREAM_OPEN message--so it is not necessary
  1843. // to re-verify the information referenced by this structure.
  1844. //
  1845. // LPACMDRVSTREAMSIZE padss: Specifies a pointer to the ACMDRVSTREAMSIZE
  1846. // structure that defines the conversion stream size query attributes.
  1847. //
  1848. // Return (LRESULT):
  1849. // The return value is zero (MMSYSERR_NOERROR) if this function
  1850. // succeeds with no errors. The return value is a non-zero error code
  1851. // if the function fails.
  1852. //
  1853. // An ACM driver should return MMSYSERR_NOTSUPPORTED if a query type
  1854. // is requested that the driver does not understand. Note that a driver
  1855. // must support both the ACM_STREAMSIZEF_DESTINATION and
  1856. // ACM_STREAMSIZEF_SOURCE queries.
  1857. //
  1858. // If the conversion would be 'out of range' given the input arguments,
  1859. // then ACMERR_NOTPOSSIBLE should be returned.
  1860. //
  1861. //--------------------------------------------------------------------------;
  1862. LRESULT FNLOCAL acmdStreamSize
  1863. (
  1864. LPACMDRVSTREAMINSTANCE padsi,
  1865. LPACMDRVSTREAMSIZE padss
  1866. )
  1867. {
  1868. PSTREAMINSTANCE psi;
  1869. LPWAVEFORMATEX pwfxSrc;
  1870. LPWAVEFORMATEX pwfxDst;
  1871. DWORD cb;
  1872. pwfxSrc = padsi->pwfxSrc;
  1873. pwfxDst = padsi->pwfxDst;
  1874. psi = (PSTREAMINSTANCE)padsi->dwDriver;
  1875. //
  1876. //
  1877. //
  1878. //
  1879. //
  1880. switch (ACM_STREAMSIZEF_QUERYMASK & padss->fdwSize)
  1881. {
  1882. //
  1883. // how many destination bytes are needed to hold the source data
  1884. // of padss->cbSrcLength bytes
  1885. //
  1886. // always round UP (since G711 can be computed exactly, don't
  1887. // round. it is simply a 2:1 compression ratio--and we drop partial
  1888. // samples)
  1889. //
  1890. case ACM_STREAMSIZEF_SOURCE:
  1891. cb = padss->cbSrcLength;
  1892. switch (pwfxSrc->wFormatTag)
  1893. {
  1894. case WAVE_FORMAT_PCM:
  1895. cb = PCM_BYTESTOSAMPLES((LPPCMWAVEFORMAT)pwfxSrc, cb);
  1896. cb = PCM_SAMPLESTOBYTES((LPPCMWAVEFORMAT)pwfxSrc, cb);
  1897. if (0 == cb)
  1898. {
  1899. return (ACMERR_NOTPOSSIBLE);
  1900. }
  1901. cb = (cb / 2);
  1902. break;
  1903. case WAVE_FORMAT_ALAW:
  1904. case WAVE_FORMAT_MULAW:
  1905. cb = G711_BYTESTOSAMPLES(pwfxSrc, cb);
  1906. cb = G711_SAMPLESTOBYTES(pwfxSrc, cb);
  1907. if (0 == cb)
  1908. {
  1909. return (ACMERR_NOTPOSSIBLE);
  1910. }
  1911. if (WAVE_FORMAT_PCM == pwfxDst->wFormatTag)
  1912. {
  1913. // Make sure we won't overflow padss->cbDstLength
  1914. if ((0xFFFFFFFFL / 2) < cb)
  1915. {
  1916. return (ACMERR_NOTPOSSIBLE);
  1917. }
  1918. cb = (cb * 2);
  1919. }
  1920. break;
  1921. }
  1922. padss->cbDstLength = cb;
  1923. return (MMSYSERR_NOERROR);
  1924. //
  1925. // how many source bytes can be encoded into a
  1926. // destination buffer of padss->cbDstLength bytes
  1927. //
  1928. // always round DOWN (drop partial samples)
  1929. //
  1930. case ACM_STREAMSIZEF_DESTINATION:
  1931. cb = padss->cbDstLength;
  1932. switch (pwfxDst->wFormatTag)
  1933. {
  1934. case WAVE_FORMAT_PCM:
  1935. cb = PCM_BYTESTOSAMPLES((LPPCMWAVEFORMAT)pwfxDst, cb);
  1936. cb = PCM_SAMPLESTOBYTES((LPPCMWAVEFORMAT)pwfxDst, cb);
  1937. cb = (cb / 2);
  1938. if (0 == cb)
  1939. {
  1940. return (ACMERR_NOTPOSSIBLE);
  1941. }
  1942. break;
  1943. case WAVE_FORMAT_ALAW:
  1944. case WAVE_FORMAT_MULAW:
  1945. cb = G711_BYTESTOSAMPLES(pwfxDst, cb);
  1946. cb = G711_SAMPLESTOBYTES(pwfxDst, cb);
  1947. if (0 == cb)
  1948. {
  1949. return (ACMERR_NOTPOSSIBLE);
  1950. }
  1951. if (WAVE_FORMAT_PCM == pwfxSrc->wFormatTag)
  1952. {
  1953. // Make sure we won't overflow padss->cbDstLength
  1954. if ((0xFFFFFFFFL / 2) < cb)
  1955. {
  1956. return (ACMERR_NOTPOSSIBLE);
  1957. }
  1958. cb = (cb * 2);
  1959. }
  1960. break;
  1961. }
  1962. padss->cbSrcLength = cb;
  1963. return (MMSYSERR_NOERROR);
  1964. }
  1965. //
  1966. // if the query type is not understood by this driver, then we need
  1967. // to return MMSYSERR_NOTSUPPORTED.
  1968. //
  1969. return (MMSYSERR_NOTSUPPORTED);
  1970. } // acmdStreamSize()
  1971. //==========================================================================;
  1972. //
  1973. //
  1974. //
  1975. //
  1976. //==========================================================================;
  1977. //--------------------------------------------------------------------------;
  1978. //
  1979. // LRESULT DriverProc
  1980. //
  1981. // Description:
  1982. //
  1983. //
  1984. // Arguments:
  1985. // DWORD dwId: For most messages, dwId is the DWORD value that
  1986. // the driver returns in response to a DRV_OPEN message. Each time
  1987. // the driver is opened, through the OpenDriver API, the driver
  1988. // receives a DRV_OPEN message and can return an arbitrary, non-zero
  1989. // value. The installable driver interface saves this value and returns
  1990. // a unique driver handle to the application. Whenever the application
  1991. // sends a message to the driver using the driver handle, the interface
  1992. // routes the message to this entry point and passes the corresponding
  1993. // dwId. This mechanism allows the driver to use the same or different
  1994. // identifiers for multiple opens but ensures that driver handles are
  1995. // unique at the application interface layer.
  1996. //
  1997. // The following messages are not related to a particular open instance
  1998. // of the driver. For these messages, the dwId will always be zero.
  1999. //
  2000. // DRV_LOAD, DRV_FREE, DRV_ENABLE, DRV_DISABLE, DRV_OPEN
  2001. //
  2002. // HDRVR hdrvr: This is the handle returned to the application
  2003. // by the driver interface.
  2004. //
  2005. // UINT uMsg: The requested action to be performed. Message
  2006. // values below DRV_RESERVED are used for globally defined messages.
  2007. // Message values from DRV_RESERVED to DRV_USER are used for defined
  2008. // driver protocols. Messages above DRV_USER are used for driver
  2009. // specific messages.
  2010. //
  2011. // LPARAM lParam1: Data for this message. Defined separately for
  2012. // each message.
  2013. //
  2014. // LPARAM lParam2: Data for this message. Defined separately for
  2015. // each message.
  2016. //
  2017. // Return (LRESULT):
  2018. // Defined separately for each message.
  2019. //
  2020. //--------------------------------------------------------------------------;
  2021. EXTERN_C LRESULT FNEXPORT DriverProc
  2022. (
  2023. DWORD_PTR dwId,
  2024. HDRVR hdrvr,
  2025. UINT uMsg,
  2026. LPARAM lParam1,
  2027. LPARAM lParam2
  2028. )
  2029. {
  2030. LRESULT lr;
  2031. PDRIVERINSTANCE pdi;
  2032. //
  2033. // make pdi either NULL or a valid instance pointer. note that dwId
  2034. // is 0 for several of the DRV_* messages (ie DRV_LOAD, DRV_OPEN...)
  2035. // see acmdDriverOpen for information on what dwId is for other
  2036. // messages (instance data).
  2037. //
  2038. pdi = (PDRIVERINSTANCE)dwId;
  2039. switch (uMsg)
  2040. {
  2041. //
  2042. // lParam1: Unused.
  2043. //
  2044. // lParam2: Unused.
  2045. //
  2046. case DRV_LOAD:
  2047. #ifdef _WIN32
  2048. DbgInitialize(TRUE);
  2049. #endif
  2050. return(1L);
  2051. //
  2052. // lParam1: Unused.
  2053. //
  2054. // lParam2: Unused.
  2055. //
  2056. case DRV_FREE:
  2057. return (1L);
  2058. //
  2059. // lParam1: Not used. Ignore this argument.
  2060. //
  2061. // lParam2: Pointer to ACMDRVOPENDESC (or NULL).
  2062. //
  2063. case DRV_OPEN:
  2064. lr = acmdDriverOpen(hdrvr, (LPACMDRVOPENDESC)lParam2);
  2065. return (lr);
  2066. //
  2067. // lParam1: Unused.
  2068. //
  2069. // lParam2: Unused.
  2070. //
  2071. case DRV_CLOSE:
  2072. lr = acmdDriverClose(pdi);
  2073. return (lr);
  2074. //
  2075. // lParam1: Unused.
  2076. //
  2077. // lParam2: Unused.
  2078. //
  2079. case DRV_INSTALL:
  2080. return ((LRESULT)DRVCNF_RESTART);
  2081. //
  2082. // lParam1: Unused.
  2083. //
  2084. // lParam2: Unused.
  2085. //
  2086. case DRV_REMOVE:
  2087. return ((LRESULT)DRVCNF_RESTART);
  2088. //
  2089. // lParam1: Not used.
  2090. //
  2091. // lParam2: Not used.
  2092. //
  2093. case DRV_QUERYCONFIGURE:
  2094. //
  2095. // set up lParam1 and lParam2 to values that can be used by
  2096. // acmdDriverConfigure to know that it is being 'queried'
  2097. // for configuration support.
  2098. //
  2099. lParam1 = -1L;
  2100. lParam2 = 0L;
  2101. //--fall through--//
  2102. //
  2103. // lParam1: Handle to parent window for the configuration dialog
  2104. // box.
  2105. //
  2106. // lParam2: Optional pointer to DRVCONFIGINFO structure.
  2107. //
  2108. case DRV_CONFIGURE:
  2109. lr = acmdDriverConfigure(pdi, (HWND)lParam1, (LPDRVCONFIGINFO)lParam2);
  2110. return (lr);
  2111. //
  2112. // lParam1: Pointer to ACMDRIVERDETAILS structure.
  2113. //
  2114. // lParam2: Size in bytes of ACMDRIVERDETAILS stucture passed.
  2115. //
  2116. case ACMDM_DRIVER_DETAILS:
  2117. lr = acmdDriverDetails(pdi, (LPACMDRIVERDETAILS)lParam1);
  2118. return (lr);
  2119. //
  2120. // lParam1: Handle to parent window to use if displaying your own
  2121. // about box.
  2122. //
  2123. // lParam2: Not used.
  2124. //
  2125. case ACMDM_DRIVER_ABOUT:
  2126. lr = acmdDriverAbout(pdi, (HWND)lParam1);
  2127. return (lr);
  2128. //--------------------------------------------------------------------------;
  2129. //--------------------------------------------------------------------------;
  2130. //
  2131. // lParam1: Pointer to ACMDRVFORMATSUGGEST structure.
  2132. //
  2133. // lParam2: Not used.
  2134. //
  2135. case ACMDM_FORMAT_SUGGEST:
  2136. lr = acmdFormatSuggest(pdi, (LPACMDRVFORMATSUGGEST)lParam1);
  2137. return (lr);
  2138. //
  2139. // lParam1: Pointer to FORMATTAGDETAILS structure.
  2140. //
  2141. // lParam2: fdwDetails
  2142. //
  2143. case ACMDM_FORMATTAG_DETAILS:
  2144. lr = acmdFormatTagDetails(pdi, (LPACMFORMATTAGDETAILS)lParam1, (DWORD)lParam2);
  2145. return (lr);
  2146. //
  2147. // lParam1: Pointer to FORMATDETAILS structure.
  2148. //
  2149. // lParam2: fdwDetails
  2150. //
  2151. case ACMDM_FORMAT_DETAILS:
  2152. lr = acmdFormatDetails(pdi, (LPACMFORMATDETAILS)lParam1, (DWORD)lParam2);
  2153. return (lr);
  2154. //--------------------------------------------------------------------------;
  2155. //--------------------------------------------------------------------------;
  2156. //
  2157. // lParam1: Pointer to ACMDRVSTREAMINSTANCE structure.
  2158. //
  2159. // lParam2: Not used.
  2160. //
  2161. case ACMDM_STREAM_OPEN:
  2162. lr = acmdStreamOpen(pdi, (LPACMDRVSTREAMINSTANCE)lParam1);
  2163. return (lr);
  2164. //
  2165. // lParam1: Pointer to ACMDRVSTREAMINSTANCE structure.
  2166. //
  2167. // lParam2: Not Used.
  2168. //
  2169. case ACMDM_STREAM_CLOSE:
  2170. lr = acmdStreamClose((LPACMDRVSTREAMINSTANCE)lParam1);
  2171. return (lr);
  2172. //
  2173. // lParam1: Pointer to ACMDRVSTREAMINSTANCE structure.
  2174. //
  2175. // lParam2: Pointer to ACMDRVSTREAMSIZE structure.
  2176. //
  2177. case ACMDM_STREAM_SIZE:
  2178. lr = acmdStreamSize((LPACMDRVSTREAMINSTANCE)lParam1, (LPACMDRVSTREAMSIZE)lParam2);
  2179. return (lr);
  2180. //
  2181. // lParam1: Pointer to ACMDRVSTREAMINSTANCE structure.
  2182. //
  2183. // lParam2: Pointer to ACMDRVSTREAMHEADER structure.
  2184. //
  2185. case ACMDM_STREAM_CONVERT:
  2186. {
  2187. PSTREAMINSTANCE psi;
  2188. LPACMDRVSTREAMINSTANCE padsi;
  2189. LPACMDRVSTREAMHEADER padsh;
  2190. //
  2191. // our stream instance data is a pointer to the conversion
  2192. // procedure needed to convert the pwfxSrc data to pwfxDst.
  2193. // the correct procedure to use was decided in acmdStreamOpen
  2194. //
  2195. padsi = (LPACMDRVSTREAMINSTANCE)lParam1;
  2196. padsh = (LPACMDRVSTREAMHEADER)lParam2;
  2197. psi = (PSTREAMINSTANCE)padsi->dwDriver;
  2198. lr = psi->fnConvert(padsi, padsh);
  2199. return (lr);
  2200. }
  2201. }
  2202. //
  2203. // if we are executing the following code, then this ACM driver does not
  2204. // handle the message that was sent. there are two ranges of messages
  2205. // we need to deal with:
  2206. //
  2207. // o ACM specific driver messages: if an ACM driver does not answer a
  2208. // message sent in the ACM driver message range, then it must
  2209. // return MMSYSERR_NOTSUPPORTED. this applies to the 'user'
  2210. // range as well (for consistency).
  2211. //
  2212. // o other installable driver messages: if an ACM driver does not
  2213. // answer a message that is NOT in the ACM driver message range,
  2214. // then it must call DefDriverProc and return that result.
  2215. // the exception to this is ACM driver procedures installed as
  2216. // ACM_DRIVERADDF_FUNCTION through acmDriverAdd. in this case,
  2217. // the driver procedure should conform to the ACMDRIVERPROC
  2218. // prototype and also return zero instead of calling DefDriverProc.
  2219. //
  2220. if (uMsg >= ACMDM_USER)
  2221. return (MMSYSERR_NOTSUPPORTED);
  2222. else
  2223. return (DefDriverProc(dwId, hdrvr, uMsg, lParam1, lParam2));
  2224. } // DriverProc()