Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

894 lines
24 KiB

  1. #include <windows.h>
  2. #include <stdlib.h>
  3. #include <mmsystem.h>
  4. #include <mmreg.h>
  5. #include <msacm.h>
  6. #include <stdlib.h>
  7. #include <stdio.h>
  8. #define TSSND_NATIVE_BITSPERSAMPLE 16
  9. #define TSSND_NATIVE_CHANNELS 2
  10. #define TSSND_NATIVE_SAMPLERATE 22050
  11. #define TSSND_NATIVE_BLOCKALIGN ((TSSND_NATIVE_BITSPERSAMPLE * \
  12. TSSND_NATIVE_CHANNELS) / 8)
  13. #define TSSND_NATIVE_AVGBYTESPERSEC (TSSND_NATIVE_BLOCKALIGN * \
  14. TSSND_NATIVE_SAMPLERATE)
  15. #define TSSND_SAMPLESPERBLOCK 8192
  16. //
  17. // Defines
  18. //
  19. #undef ASSERT
  20. #ifdef DBG
  21. #define TRC _DebugMessage
  22. #define ASSERT(_x_) if (!(_x_)) \
  23. { TRC(FATAL, "ASSERT failed, line %d, file %s\n", \
  24. __LINE__, __FILE__); DebugBreak(); }
  25. #else // !DBG
  26. #define TRC
  27. #define ASSERT
  28. #endif // !DBG
  29. #define TSMALLOC( _x_ ) malloc( _x_ )
  30. #define TSFREE( _x_ ) free( _x_ )
  31. #ifndef G723MAGICWORD1
  32. #define G723MAGICWORD1 0xf7329ace
  33. #endif
  34. #ifndef G723MAGICWORD2
  35. #define G723MAGICWORD2 0xacdeaea2
  36. #endif
  37. #ifndef VOXWARE_KEY
  38. #define VOXWARE_KEY "35243410-F7340C0668-CD78867B74DAD857-AC71429AD8CAFCB5-E4E1A99E7FFD-371"
  39. #endif
  40. #ifndef WMAUDIO_KEY
  41. #define WMAUDIO_KEY "F6DC9830-BC79-11d2-A9D0-006097926036"
  42. #endif
  43. #ifndef WMAUDIO_DEC_KEY
  44. #define WMAUDIO_DEC_KEY "1A0F78F0-EC8A-11d2-BBBE-006008320064"
  45. #endif
  46. #define WAVE_FORMAT_WMAUDIO2 0x161
  47. const CHAR *ALV = "TSSNDD::ALV - ";
  48. const CHAR *INF = "TSSNDD::INF - ";
  49. const CHAR *WRN = "TSSNDD::WRN - ";
  50. const CHAR *ERR = "TSSNDD::ERR - ";
  51. const CHAR *FATAL = "TSSNDD::FATAL - ";
  52. typedef struct _VCSNDFORMATLIST {
  53. struct _VCSNDFORMATLIST *pNext;
  54. HACMDRIVERID hacmDriverId;
  55. WAVEFORMATEX Format;
  56. // additional data for the format
  57. } VCSNDFORMATLIST, *PVCSNDFORMATLIST;
  58. #ifdef _WIN32
  59. #include <pshpack1.h>
  60. #else
  61. #ifndef RC_INVOKED
  62. #pragma pack(1)
  63. #endif
  64. #endif
  65. typedef struct wmaudio2waveformat_tag {
  66. WAVEFORMATEX wfx;
  67. DWORD dwSamplesPerBlock; // only counting "new" samples "= half of what will be used due to overlapping
  68. WORD wEncodeOptions;
  69. DWORD dwSuperBlockAlign; // the big size... should be multiples of wfx.nBlockAlign.
  70. } WMAUDIO2WAVEFORMAT;
  71. typedef struct msg723waveformat_tag {
  72. WAVEFORMATEX wfx;
  73. WORD wConfigWord;
  74. DWORD dwCodeword1;
  75. DWORD dwCodeword2;
  76. } MSG723WAVEFORMAT;
  77. typedef struct intelg723waveformat_tag {
  78. WAVEFORMATEX wfx;
  79. WORD wConfigWord;
  80. DWORD dwCodeword1;
  81. DWORD dwCodeword2;
  82. } INTELG723WAVEFORMAT;
  83. typedef struct tagVOXACM_WAVEFORMATEX
  84. {
  85. WAVEFORMATEX wfx;
  86. DWORD dwCodecId;
  87. DWORD dwMode;
  88. char szKey[72];
  89. } VOXACM_WAVEFORMATEX, *PVOXACM_WAVEFORMATEX, FAR *LPVOXACM_WAVEFORMATEX;
  90. #ifdef _WIN32
  91. #include <poppack.h>
  92. #else
  93. #ifndef RC_INVOKED
  94. #pragma pack()
  95. #endif
  96. #endif
  97. /////////////////////////////////////////////////////////////////////
  98. //
  99. // Tracing
  100. //
  101. /////////////////////////////////////////////////////////////////////
  102. VOID
  103. _cdecl
  104. _DebugMessage(
  105. LPCSTR szLevel,
  106. LPCSTR szFormat,
  107. ...
  108. )
  109. {
  110. CHAR szBuffer[256];
  111. va_list arglist;
  112. if (szLevel == ALV)
  113. return;
  114. va_start (arglist, szFormat);
  115. _vsnprintf (szBuffer, sizeof(szBuffer), szFormat, arglist);
  116. va_end (arglist);
  117. // printf( "%s:%s", szLevel, szBuffer );
  118. OutputDebugStringA(szLevel);
  119. OutputDebugStringA(szBuffer);
  120. }
  121. /*
  122. * Function:
  123. * _VCSmdFindSuggestedConverter
  124. *
  125. * Description:
  126. * Searches for intermidiate converter
  127. *
  128. */
  129. BOOL
  130. _VCSndFindSuggestedConverter(
  131. HACMDRIVERID hadid,
  132. LPWAVEFORMATEX pDestFormat,
  133. LPWAVEFORMATEX pInterrimFmt
  134. )
  135. {
  136. BOOL rv = FALSE;
  137. MMRESULT mmres;
  138. HACMDRIVER hacmDriver = NULL;
  139. HACMSTREAM hacmStream = NULL;
  140. ASSERT( NULL != pDestFormat );
  141. ASSERT( NULL != hadid );
  142. ASSERT( NULL != pInterrimFmt );
  143. //
  144. // first, open the destination acm driver
  145. //
  146. mmres = acmDriverOpen(&hacmDriver, hadid, 0);
  147. if ( MMSYSERR_NOERROR != mmres )
  148. {
  149. TRC(ERR, "_VCSndFindSuggestedConverter: can't "
  150. "open the acm driver: %d\n",
  151. mmres);
  152. goto exitpt;
  153. }
  154. //
  155. // first probe with the native format
  156. // if it passes, we don't need intermidiate
  157. // format converter
  158. //
  159. pInterrimFmt->wFormatTag = WAVE_FORMAT_PCM;
  160. pInterrimFmt->nChannels = TSSND_NATIVE_CHANNELS;
  161. pInterrimFmt->nSamplesPerSec = TSSND_NATIVE_SAMPLERATE;
  162. pInterrimFmt->nAvgBytesPerSec = TSSND_NATIVE_AVGBYTESPERSEC;
  163. pInterrimFmt->nBlockAlign = TSSND_NATIVE_BLOCKALIGN;
  164. pInterrimFmt->wBitsPerSample = TSSND_NATIVE_BITSPERSAMPLE;
  165. pInterrimFmt->cbSize = 0;
  166. mmres = acmStreamOpen(
  167. &hacmStream,
  168. hacmDriver,
  169. pInterrimFmt,
  170. pDestFormat,
  171. NULL, // filter
  172. 0, // callback
  173. 0, // dwinstance
  174. ACM_STREAMOPENF_NONREALTIME
  175. );
  176. if ( MMSYSERR_NOERROR == mmres )
  177. {
  178. //
  179. // format is supported
  180. //
  181. rv = TRUE;
  182. goto exitpt;
  183. } else {
  184. TRC(ALV, "_VCSndFindSuggestedConverter: format is not supported\n");
  185. }
  186. //
  187. // find a suggested intermidiate PCM format
  188. //
  189. mmres = acmFormatSuggest(
  190. hacmDriver,
  191. pDestFormat,
  192. pInterrimFmt,
  193. sizeof( *pInterrimFmt ),
  194. ACM_FORMATSUGGESTF_WFORMATTAG
  195. );
  196. if ( MMSYSERR_NOERROR != mmres )
  197. {
  198. TRC(ALV, "_VCSndFindSuggestedConverter: can't find "
  199. "interrim format: %d\n",
  200. mmres);
  201. goto exitpt;
  202. }
  203. if ( 16 != pInterrimFmt->wBitsPerSample ||
  204. ( 1 != pInterrimFmt->nChannels &&
  205. 2 != pInterrimFmt->nChannels) ||
  206. ( 8000 != pInterrimFmt->nSamplesPerSec &&
  207. 11025 != pInterrimFmt->nSamplesPerSec &&
  208. 12000 != pInterrimFmt->nSamplesPerSec &&
  209. 16000 != pInterrimFmt->nSamplesPerSec &&
  210. 22050 != pInterrimFmt->nSamplesPerSec)
  211. )
  212. {
  213. TRC(ALV, "_VCSndFindSuggestedConverter: not supported "
  214. "interrim format. Details:\n");
  215. TRC(ALV, "Channels - %d\n", pInterrimFmt->nChannels);
  216. TRC(ALV, "SamplesPerSec - %d\n", pInterrimFmt->nSamplesPerSec);
  217. TRC(ALV, "AvgBytesPerSec - %d\n", pInterrimFmt->nAvgBytesPerSec);
  218. TRC(ALV, "BlockAlign - %d\n", pInterrimFmt->nBlockAlign);
  219. TRC(ALV, "BitsPerSample - %d\n", pInterrimFmt->wBitsPerSample);
  220. goto exitpt;
  221. }
  222. if ( 1 == pInterrimFmt->nChannels )
  223. {
  224. switch ( pInterrimFmt->nSamplesPerSec )
  225. {
  226. case 8000:
  227. case 11025:
  228. case 12000:
  229. case 16000:
  230. case 22050:
  231. break;
  232. default:
  233. ASSERT( 0 );
  234. }
  235. } else {
  236. switch ( pInterrimFmt->nSamplesPerSec )
  237. {
  238. case 8000:
  239. case 11025:
  240. case 12000:
  241. case 16000:
  242. case 22050:
  243. break;
  244. default:
  245. ASSERT( 0 );
  246. }
  247. }
  248. //
  249. // probe with this format
  250. //
  251. mmres = acmStreamOpen(
  252. &hacmStream,
  253. hacmDriver,
  254. pInterrimFmt,
  255. pDestFormat,
  256. NULL, // filter
  257. 0, // callback
  258. 0, // dwinstance
  259. ACM_STREAMOPENF_NONREALTIME
  260. );
  261. if ( MMSYSERR_NOERROR != mmres )
  262. {
  263. TRC(ALV, "_VCSndFindSuggestedConverter: probing the suggested "
  264. "format failed: %d\n",
  265. mmres);
  266. goto exitpt;
  267. }
  268. TRC(ALV, "_VCSndFindSuggestedConverter: found intermidiate PCM format\n");
  269. TRC(ALV, "Channels - %d\n", pInterrimFmt->nChannels);
  270. TRC(ALV, "SamplesPerSec - %d\n", pInterrimFmt->nSamplesPerSec);
  271. TRC(ALV, "AvgBytesPerSec - %d\n", pInterrimFmt->nAvgBytesPerSec);
  272. TRC(ALV, "BlockAlign - %d\n", pInterrimFmt->nBlockAlign);
  273. TRC(ALV, "BitsPerSample - %d\n", pInterrimFmt->wBitsPerSample);
  274. rv = TRUE;
  275. exitpt:
  276. if ( NULL != hacmStream )
  277. acmStreamClose( hacmStream, 0 );
  278. if ( NULL != hacmDriver )
  279. acmDriverClose( hacmDriver, 0 );
  280. return rv;
  281. }
  282. /*
  283. * Function:
  284. * _VCSndOrderFormatList
  285. *
  286. * Description:
  287. * Order all formats in descendant order
  288. *
  289. */
  290. VOID
  291. _VCSndOrderFormatList(
  292. PVCSNDFORMATLIST *ppFormatList,
  293. DWORD *pdwNum
  294. )
  295. {
  296. PVCSNDFORMATLIST pFormatList;
  297. PVCSNDFORMATLIST pLessThan;
  298. PVCSNDFORMATLIST pPrev;
  299. PVCSNDFORMATLIST pNext;
  300. PVCSNDFORMATLIST pIter;
  301. PVCSNDFORMATLIST pIter2;
  302. DWORD dwNum = 0;
  303. ASSERT ( NULL != ppFormatList );
  304. pFormatList = *ppFormatList;
  305. pLessThan = NULL;
  306. //
  307. // fill both lists
  308. //
  309. pIter = pFormatList;
  310. while ( NULL != pIter )
  311. {
  312. pNext = pIter->pNext;
  313. pIter->pNext = NULL;
  314. //
  315. // descending order
  316. //
  317. pIter2 = pLessThan;
  318. pPrev = NULL;
  319. while ( NULL != pIter2 &&
  320. pIter2->Format.nAvgBytesPerSec >
  321. pIter->Format.nAvgBytesPerSec )
  322. {
  323. pPrev = pIter2;
  324. pIter2 = pIter2->pNext;
  325. }
  326. pIter->pNext = pIter2;
  327. if ( NULL == pPrev )
  328. pLessThan = pIter;
  329. else
  330. pPrev->pNext = pIter;
  331. pIter = pNext;
  332. dwNum ++;
  333. }
  334. *ppFormatList = pLessThan;
  335. if ( NULL != pdwNum )
  336. *pdwNum = dwNum;
  337. }
  338. //
  339. // puts code licensing codes into the header
  340. //
  341. BOOL
  342. _VCSndFixHeader(
  343. PWAVEFORMATEX pFmt,
  344. PWAVEFORMATEX *ppNewFmt
  345. )
  346. {
  347. BOOL rv = FALSE;
  348. *ppNewFmt = NULL;
  349. switch (pFmt->wFormatTag)
  350. {
  351. case WAVE_FORMAT_MSG723:
  352. ASSERT(pFmt->cbSize == 10);
  353. ((MSG723WAVEFORMAT *) pFmt)->dwCodeword1 = G723MAGICWORD1;
  354. ((MSG723WAVEFORMAT *) pFmt)->dwCodeword2 = G723MAGICWORD2;
  355. rv = TRUE;
  356. break;
  357. case WAVE_FORMAT_MSRT24:
  358. //
  359. // assume call control will take care of the other
  360. // params ?
  361. //
  362. ASSERT(pFmt->cbSize == 80);
  363. strncpy(((VOXACM_WAVEFORMATEX *) pFmt)->szKey, VOXWARE_KEY, 80);
  364. rv = TRUE;
  365. break;
  366. case WAVE_FORMAT_WMAUDIO2:
  367. if ( ((WMAUDIO2WAVEFORMAT *)pFmt)->dwSamplesPerBlock > TSSND_SAMPLESPERBLOCK )
  368. {
  369. //
  370. // block is too big, too high latency
  371. //
  372. break;
  373. }
  374. ASSERT( pFmt->cbSize == sizeof( WMAUDIO2WAVEFORMAT ) - sizeof( WAVEFORMATEX ));
  375. *ppNewFmt = TSMALLOC( sizeof( WMAUDIO2WAVEFORMAT ) + sizeof( WMAUDIO_KEY ));
  376. if ( NULL == *ppNewFmt )
  377. {
  378. break;
  379. }
  380. memcpy( *ppNewFmt, pFmt, sizeof( WMAUDIO2WAVEFORMAT ));
  381. strncpy((CHAR *)(((WMAUDIO2WAVEFORMAT *) *ppNewFmt) + 1), WMAUDIO_KEY, sizeof( WMAUDIO_KEY ));
  382. (*ppNewFmt)->cbSize += sizeof( WMAUDIO_KEY );
  383. rv = TRUE;
  384. break;
  385. default:
  386. rv = TRUE;
  387. }
  388. return rv;
  389. }
  390. /*
  391. * Function:
  392. * acmFormatEnumCallback
  393. *
  394. * Description:
  395. * All formats enumerator
  396. *
  397. */
  398. BOOL
  399. CALLBACK
  400. acmFormatEnumCallback(
  401. HACMDRIVERID hadid,
  402. LPACMFORMATDETAILS pAcmFormatDetails,
  403. DWORD_PTR dwInstance,
  404. DWORD fdwSupport
  405. )
  406. {
  407. PVCSNDFORMATLIST *ppFormatList;
  408. PWAVEFORMATEX pEntry, pFixedEntry = NULL;
  409. ASSERT(0 != dwInstance);
  410. ASSERT(NULL != pAcmFormatDetails);
  411. ASSERT(NULL != pAcmFormatDetails->pwfx);
  412. if ( 0 == dwInstance ||
  413. NULL == pAcmFormatDetails ||
  414. NULL == pAcmFormatDetails->pwfx )
  415. {
  416. TRC( ERR, "acmFormatEnumCallback: Invalid parameters\n" );
  417. goto exitpt;
  418. }
  419. ppFormatList = (PVCSNDFORMATLIST *)dwInstance;
  420. if (( 0 != ( fdwSupport & ACMDRIVERDETAILS_SUPPORTF_CODEC ) ||
  421. 0 != ( fdwSupport & ACMDRIVERDETAILS_SUPPORTF_CONVERTER )) &&
  422. pAcmFormatDetails->pwfx->nAvgBytesPerSec < TSSND_NATIVE_AVGBYTESPERSEC
  423. )
  424. {
  425. //
  426. // this codec should be good, save it in the list
  427. // keep the list sorted in descended order
  428. //
  429. PVCSNDFORMATLIST pIter;
  430. PVCSNDFORMATLIST pPrev;
  431. PVCSNDFORMATLIST pNewEntry;
  432. WAVEFORMATEX WaveFormat; // dummy parameter
  433. DWORD itemsize;
  434. if (
  435. WAVE_FORMAT_PCM == pAcmFormatDetails->pwfx->wFormatTag ||
  436. !_VCSndFixHeader(pAcmFormatDetails->pwfx, &pFixedEntry )
  437. )
  438. {
  439. TRC(ALV, "acmFormatEnumCallback: unsupported format, "
  440. "don't use it\n");
  441. goto exitpt;
  442. }
  443. pEntry = ( NULL == pFixedEntry )?pAcmFormatDetails->pwfx:pFixedEntry;
  444. if (!_VCSndFindSuggestedConverter(
  445. hadid,
  446. pEntry,
  447. &WaveFormat
  448. ))
  449. {
  450. TRC(ALV, "acmFormatEnumCallback: unsupported format, "
  451. "don't use it\n");
  452. goto exitpt;
  453. }
  454. TRC(ALV, "acmFormatEnumCallback: codec found %S (%d b/s)\n",
  455. pAcmFormatDetails->szFormat,
  456. pEntry->nAvgBytesPerSec);
  457. itemsize = sizeof( *pNewEntry ) + pEntry->cbSize;
  458. pNewEntry = (PVCSNDFORMATLIST) TSMALLOC( itemsize );
  459. if (NULL == pNewEntry)
  460. {
  461. TRC(ERR, "acmFormatEnumCallback: can't allocate %d bytes\n",
  462. itemsize);
  463. goto exitpt;
  464. }
  465. memcpy( &pNewEntry->Format, pEntry,
  466. sizeof (pNewEntry->Format) + pEntry->cbSize );
  467. pNewEntry->hacmDriverId = hadid;
  468. pNewEntry->pNext = *ppFormatList;
  469. *ppFormatList = pNewEntry;
  470. }
  471. exitpt:
  472. if ( NULL != pFixedEntry )
  473. {
  474. TSFREE( pFixedEntry );
  475. }
  476. return TRUE;
  477. }
  478. //
  479. // returns true if this codec is shipped with windows
  480. // because we are testing only the these
  481. //
  482. BOOL
  483. AllowThisCodec(
  484. HACMDRIVERID hadid
  485. )
  486. {
  487. ACMDRIVERDETAILS Details;
  488. BOOL rv = FALSE;
  489. static DWORD AllowedCodecs[][2] =
  490. { MM_INTEL, 503,
  491. MM_MICROSOFT, MM_MSFT_ACM_IMAADPCM,
  492. MM_FRAUNHOFER_IIS, 12,
  493. MM_MICROSOFT, 90,
  494. MM_MICROSOFT, MM_MSFT_ACM_MSADPCM,
  495. MM_MICROSOFT, 39,
  496. MM_MICROSOFT, MM_MSFT_ACM_G711,
  497. MM_MICROSOFT, 82,
  498. MM_MICROSOFT, MM_MSFT_ACM_GSM610,
  499. MM_SIPROLAB, 1,
  500. MM_DSP_GROUP, 1,
  501. MM_MICROSOFT, MM_MSFT_ACM_PCM };
  502. RtlZeroMemory( &Details, sizeof( Details ));
  503. Details.cbStruct = sizeof( Details );
  504. if ( MMSYSERR_NOERROR ==
  505. acmDriverDetails( hadid, &Details, 0 ))
  506. {
  507. //
  508. // Is this one known
  509. //
  510. DWORD count;
  511. for ( count = 0; count < sizeof( AllowedCodecs ) / (2 * sizeof( DWORD )); count ++ )
  512. {
  513. if ( Details.wMid == AllowedCodecs[count][0] &&
  514. Details.wPid == AllowedCodecs[count][1] )
  515. {
  516. rv = TRUE;
  517. goto exitpt;
  518. }
  519. }
  520. }
  521. exitpt:
  522. if ( rv )
  523. TRC( ALV, "ACMDRV: +++++++++++++++++++++ CODEC ALLOWED +++++++++++++++++++++++\n" );
  524. else
  525. TRC( ALV, "ACMDRV: ------------------- CODEC DISALLOWED ----------------------\n" );
  526. TRC( ALV, "ACMDRV: Mid: %d\n", Details.wMid );
  527. TRC( ALV, "ACMDRV: Pid: %d\n", Details.wPid );
  528. TRC( ALV, "ACMDRV: ShortName: %S\n", Details.szShortName );
  529. TRC( ALV, "ACMDRV: LongName: %S\n", Details.szLongName );
  530. TRC( ALV, "ACMDRV: Copyright: %S\n", Details.szLicensing );
  531. TRC( ALV, "ACMDRV: Features: %S\n", Details.szFeatures );
  532. return rv;
  533. }
  534. /*
  535. * Function:
  536. * acmDriverEnumCallback
  537. *
  538. * Description:
  539. * All drivers enumerator
  540. *
  541. */
  542. BOOL
  543. CALLBACK
  544. acmDriverEnumCallback(
  545. HACMDRIVERID hadid,
  546. DWORD_PTR dwInstance,
  547. DWORD fdwSupport
  548. )
  549. {
  550. PVCSNDFORMATLIST *ppFormatList;
  551. MMRESULT mmres;
  552. ASSERT(dwInstance);
  553. ppFormatList = (PVCSNDFORMATLIST *)dwInstance;
  554. if ( (0 != ( fdwSupport & ACMDRIVERDETAILS_SUPPORTF_CODEC ) ||
  555. 0 != ( fdwSupport & ACMDRIVERDETAILS_SUPPORTF_CONVERTER )) &&
  556. AllowThisCodec(hadid) )
  557. {
  558. //
  559. // a codec found
  560. //
  561. HACMDRIVER had;
  562. mmres = acmDriverOpen(&had, hadid, 0);
  563. if (MMSYSERR_NOERROR == mmres)
  564. {
  565. PWAVEFORMATEX pWaveFormat;
  566. ACMFORMATDETAILS AcmFormatDetails;
  567. DWORD dwMaxFormatSize;
  568. //
  569. // first find the max size for the format
  570. //
  571. mmres = acmMetrics( (HACMOBJ)had,
  572. ACM_METRIC_MAX_SIZE_FORMAT,
  573. (LPVOID)&dwMaxFormatSize);
  574. if (MMSYSERR_NOERROR != mmres ||
  575. dwMaxFormatSize < sizeof( *pWaveFormat ))
  576. dwMaxFormatSize = sizeof( *pWaveFormat );
  577. //
  578. // Allocate the format structure
  579. //
  580. __try {
  581. pWaveFormat = (PWAVEFORMATEX) _alloca ( dwMaxFormatSize );
  582. } __except ( EXCEPTION_EXECUTE_HANDLER )
  583. {
  584. pWaveFormat = NULL;
  585. }
  586. if ( NULL == pWaveFormat )
  587. {
  588. TRC(ERR, "acmDriverEnumCallback: alloca failed for %d bytes\n",
  589. dwMaxFormatSize);
  590. goto close_acm_driver;
  591. }
  592. //
  593. // clear the extra format data
  594. //
  595. memset( pWaveFormat + 1, 0, dwMaxFormatSize - sizeof( *pWaveFormat ));
  596. //
  597. // create the format to convert from
  598. //
  599. pWaveFormat->wFormatTag = WAVE_FORMAT_PCM;
  600. pWaveFormat->nChannels = TSSND_NATIVE_CHANNELS;
  601. pWaveFormat->nSamplesPerSec = TSSND_NATIVE_SAMPLERATE;
  602. pWaveFormat->nAvgBytesPerSec = TSSND_NATIVE_AVGBYTESPERSEC;
  603. pWaveFormat->nBlockAlign = TSSND_NATIVE_BLOCKALIGN;
  604. pWaveFormat->wBitsPerSample = TSSND_NATIVE_BITSPERSAMPLE;
  605. pWaveFormat->cbSize = 0;
  606. AcmFormatDetails.cbStruct = sizeof( AcmFormatDetails );
  607. AcmFormatDetails.dwFormatIndex= 0;
  608. AcmFormatDetails.dwFormatTag = WAVE_FORMAT_PCM;
  609. AcmFormatDetails.fdwSupport = 0;
  610. AcmFormatDetails.pwfx = pWaveFormat;
  611. AcmFormatDetails.cbwfx = dwMaxFormatSize;
  612. //
  613. // enum all formats supported by this driver
  614. //
  615. mmres = acmFormatEnum(
  616. had,
  617. &AcmFormatDetails,
  618. acmFormatEnumCallback,
  619. (DWORD_PTR)ppFormatList,
  620. 0 //ACM_FORMATENUMF_CONVERT
  621. );
  622. if (MMSYSERR_NOERROR != mmres)
  623. {
  624. TRC(ERR, "acmDriverEnumCallback: acmFormatEnum failed %d\n",
  625. mmres);
  626. }
  627. close_acm_driver:
  628. acmDriverClose(had, 0);
  629. } else
  630. TRC(ALV, "acmDriverEnumCallback: acmDriverOpen failed: %d\n",
  631. mmres);
  632. }
  633. //
  634. // continue to the next driver
  635. //
  636. return TRUE;
  637. }
  638. /*
  639. * Function:
  640. * VCSndEnumAllCodecFormats
  641. *
  642. * Description:
  643. * Creates a list of all codecs/formats
  644. *
  645. */
  646. BOOL
  647. VCSndEnumAllCodecFormats(
  648. PVCSNDFORMATLIST *ppFormatList,
  649. DWORD *pdwNumberOfFormats
  650. )
  651. {
  652. BOOL rv = FALSE;
  653. PVCSNDFORMATLIST pIter;
  654. PVCSNDFORMATLIST pPrev;
  655. PVCSNDFORMATLIST pNext;
  656. MMRESULT mmres;
  657. DWORD dwNum = 0;
  658. ASSERT( ppFormatList );
  659. ASSERT( pdwNumberOfFormats );
  660. *ppFormatList = NULL;
  661. mmres = acmDriverEnum(
  662. acmDriverEnumCallback,
  663. (DWORD_PTR)ppFormatList,
  664. 0
  665. );
  666. if (NULL == *ppFormatList)
  667. {
  668. TRC(WRN, "VCSndEnumAllCodecFormats: acmDriverEnum failed: %d\n",
  669. mmres);
  670. goto exitpt;
  671. }
  672. _VCSndOrderFormatList( ppFormatList, &dwNum );
  673. pIter = *ppFormatList;
  674. //
  675. // number of formats is passed as UINT16, delete all after those
  676. //
  677. if ( dwNum > 0xffff )
  678. {
  679. DWORD dwLimit = 0xfffe;
  680. while ( 0 != dwLimit )
  681. {
  682. pIter = pIter->pNext;
  683. dwLimit --;
  684. }
  685. pNext = pIter->pNext;
  686. pIter->pNext = NULL;
  687. pIter = pNext;
  688. while( NULL != pIter )
  689. {
  690. pNext = pIter->pNext;
  691. TSFREE( pNext );
  692. pIter = pNext;
  693. }
  694. dwNum = 0xffff;
  695. }
  696. rv = TRUE;
  697. exitpt:
  698. if (!rv)
  699. {
  700. //
  701. // in case of error free the allocated list of formats
  702. //
  703. pIter = *ppFormatList;
  704. while( NULL != pIter )
  705. {
  706. PVCSNDFORMATLIST pNext = pIter->pNext;
  707. TSFREE( pIter );
  708. pIter = pNext;
  709. }
  710. *ppFormatList = NULL;
  711. }
  712. *pdwNumberOfFormats = dwNum;
  713. return rv;
  714. }
  715. int
  716. _cdecl
  717. wmain( void )
  718. {
  719. PVCSNDFORMATLIST pFormatList = NULL;
  720. DWORD dwNumberOfFormats = 0;
  721. printf( "// use dumpcod.c to generate this table\n" );
  722. printf( "//\n" );
  723. printf( "// FormatTag | Channels | SamplesPerSec | AvgBytesPerSec | BlockAlign | BitsPerSamepl | ExtraInfo\n" );
  724. printf( "// ================================================================================================\n" );
  725. printf( "//\n" );
  726. printf( "BYTE KnownFormats[] = {\n" );
  727. VCSndEnumAllCodecFormats( &pFormatList, &dwNumberOfFormats );
  728. for ( ;pFormatList != NULL; pFormatList = pFormatList->pNext )
  729. {
  730. PWAVEFORMATEX pSndFmt = &(pFormatList->Format);
  731. UINT i;
  732. printf( "// %.3d, %.2d, %.5d, %.5d, %.3d, %.2d\n",
  733. pSndFmt->wFormatTag,
  734. pSndFmt->nChannels,
  735. pSndFmt->nSamplesPerSec,
  736. pSndFmt->nAvgBytesPerSec,
  737. pSndFmt->nBlockAlign,
  738. pSndFmt->wBitsPerSample);
  739. for ( i = 0; i < sizeof( WAVEFORMATEX ); i ++ )
  740. {
  741. printf( "0x%02x", ((PBYTE)pSndFmt)[i]);
  742. if ( i + 1 < sizeof( WAVEFORMATEX ) || pSndFmt->cbSize )
  743. {
  744. printf( ", " );
  745. }
  746. }
  747. for ( i = 0; i < pSndFmt->cbSize; i++ )
  748. {
  749. printf( "0x%02x", (((PBYTE)pSndFmt) + sizeof( WAVEFORMATEX ))[i]);
  750. if ( i + 1 < pSndFmt->cbSize )
  751. {
  752. printf( ", " );
  753. }
  754. }
  755. if ( NULL != pFormatList->pNext )
  756. {
  757. printf ( ",\n" );
  758. } else {
  759. printf( " };\n" );
  760. }
  761. }
  762. return 0;
  763. }