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.

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