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.

1818 lines
53 KiB

  1. /*
  2. * File: msiacaps.cpp
  3. *
  4. * ACM implementation of Microsoft Network Audio capability object.
  5. *
  6. * Revision History:
  7. *
  8. * 06/06/96 mikev created
  9. */
  10. #include "precomp.h"
  11. //Prototypes....
  12. ULONG ReadRegistryFormats (LPCSTR lpszKeyName,CHAR ***pppName,BYTE ***pppData,PUINT pnFormats,DWORD dwDebugSize);
  13. void FreeRegistryFormats (PRRF_INFO pRegFmts);
  14. static BOOL bUseDefault;
  15. #define szRegMSIPAndH323Encodings TEXT("ACMH323Encodings")
  16. AUDCAP_DETAILS default_id_table[] =
  17. {
  18. {WAVE_FORMAT_ADPCM, NONSTD_TERMCAP, STD_CHAN_PARAMS, {RTP_DYNAMIC_MIN, 0, 8000, 4},
  19. 0, TRUE, TRUE, 500, 32000,32000,50,0,PREF_ORDER_UNASSIGNED,0,NULL,0, NULL,
  20. "Microsoft ADPCM"},
  21. {WAVE_FORMAT_LH_CELP, NONSTD_TERMCAP, STD_CHAN_PARAMS,{RTP_DYNAMIC_MIN, 0, 8000, 16},
  22. 0, TRUE, TRUE, 640, 5600,5600,LNH_48_CPU,0,3,0,NULL,0,NULL,
  23. "Lernout & Hauspie CELP 4.8kbit/s"},
  24. {WAVE_FORMAT_LH_SB8, NONSTD_TERMCAP, STD_CHAN_PARAMS,{RTP_DYNAMIC_MIN, 0, 8000, 16},
  25. 0, TRUE, TRUE, 640, 8000,8000,LNH_8_CPU,0,0,0,NULL,0,NULL,
  26. "Lernout & Hauspie SBC 8kbit/s"},
  27. {WAVE_FORMAT_LH_SB12, NONSTD_TERMCAP, STD_CHAN_PARAMS, {RTP_DYNAMIC_MIN, 0, 8000, 16},
  28. 0, TRUE, TRUE, 640, 12000,12000,LNH_12_CPU,0,1,0,NULL,0,NULL,
  29. "Lernout & Hauspie SBC 12kbit/s"},
  30. {WAVE_FORMAT_LH_SB16, NONSTD_TERMCAP, STD_CHAN_PARAMS,{RTP_DYNAMIC_MIN, 0, 8000, 16},
  31. 0, TRUE, TRUE, 640, 16000,16000,LNH_16_CPU,0,2,0,NULL,0,NULL,
  32. "Lernout & Hauspie SBC 16kbit/s"},
  33. {WAVE_FORMAT_MSRT24, NONSTD_TERMCAP, STD_CHAN_PARAMS,{RTP_DYNAMIC_MIN, 0, 8000, 16},
  34. 0, TRUE, TRUE, 720, 2400,2400,MSRT24_CPU,0,4,0,NULL,0,NULL,
  35. "Voxware RT 2.4kbit/s"},
  36. {WAVE_FORMAT_MSG723, STD_TERMCAP(H245_CLIENT_AUD_G723), // client type H245_CLIENT_AUD_G723,
  37. STD_CHAN_PARAMS, {RTP_PAYLOAD_G723, 0, 8000, 0},
  38. 0, TRUE, TRUE, 960, 5600,5600,MS_G723_CPU,0,
  39. 0, // priority
  40. 0,NULL,0,NULL, "Microsoft G.723.1"},
  41. {WAVE_FORMAT_ALAW, STD_TERMCAP( H245_CLIENT_AUD_G711_ALAW64),
  42. STD_CHAN_PARAMS, {RTP_PAYLOAD_G711_ALAW, 0, 8000, 8},
  43. 0, TRUE, TRUE, 500, 64000,64000,CCITT_A_CPU,0,0,
  44. 0, NULL, 0, NULL, "CCITT A-Law"},
  45. {WAVE_FORMAT_MULAW, STD_TERMCAP( H245_CLIENT_AUD_G711_ULAW64),
  46. STD_CHAN_PARAMS, {RTP_PAYLOAD_G711_MULAW, 0, 8000, 8},
  47. 0, TRUE, TRUE, 500, 64000,64000,CCITT_U_CPU,0,0,
  48. 0, NULL, 0, NULL, "CCITT u-Law"},
  49. #if(0)
  50. // do not use this version of the G.723 codec
  51. {WAVE_FORMAT_INTELG723, STD_TERMCAP(H245_CLIENT_AUD_G723), // client type H245_CLIENT_AUD_G723,
  52. STD_CHAN_PARAMS, {RTP_DYNAMIC_MIN, 0, 8000, 0},
  53. 0, TRUE, TRUE, 960, 16000,16000,99,0,
  54. 0, // priority
  55. 0,NULL,0,NULL, "G.723"},
  56. {WAVE_FORMAT_DSPGROUP_TRUESPEECH, {
  57. NONSTD_TERMCAP, {RTP_DYNAMIC_MIN, 0, 5510, 4},
  58. 0, TRUE, TRUE, 500, 5510,5510,50,0,0,0,NULL},
  59. "DSP Group TrueSpeech(TM)"},
  60. {WAVE_FORMAT_PCM, {{RTP_DYNAMIC_MIN, 0, 8000, 8}, TRUE, TRUE, 160, 64000,64000,50,0,0,0,NULL,0,NULL}, "MS-ADPCM"},
  61. {WAVE_FORMAT_PCM, {{RTP_DYNAMIC_MIN, 0, 5510, 8}, TRUE, TRUE, 160, 44080,44080,50,0,0,0,NULL,0,NULL}, "MS-ADPCM"},
  62. {WAVE_FORMAT_PCM, {{RTP_DYNAMIC_MIN, 0, 11025, 8}, TRUE, TRUE, 160, 88200,88200,50,0,0,0,NULL,0,NULL},"MS-ADPCM"},
  63. {WAVE_FORMAT_PCM, {{RTP_DYNAMIC_MIN, 0, 8000, 16}, TRUE, TRUE, 160, 128000,128000,50,0,0,0,NULL,0,NULL},"MS-ADPCM"},
  64. {WAVE_FORMAT_ADPCM, {{RTP_DYNAMIC_MIN, 0, 8000, 4}, TRUE, TRUE, 500, 16000,16000,50,0,,0,0,NULL,0,NULL}, "MS-ADPCM"},
  65. {WAVE_FORMAT_GSM610, STD_CHAN_PARAMS,{RTP_DYNAMIC_MIN, 0, 8000, 0},
  66. 0, TRUE, TRUE, 320, 8000,8000,96,0,PREF_ORDER_UNASSIGNED,0,NULL,0,NULL,
  67. //"Microsoft GSM 6.10"
  68. "GSM 6.10"},
  69. #endif // DEF_USE_ALLPCM
  70. };
  71. UINT uDefTableEntries = sizeof(default_id_table) /sizeof(AUDCAP_DETAILS);
  72. static BOOL bCreateDefTable = FALSE;
  73. //
  74. // static members of CMsiaCapability
  75. //
  76. MEDIA_FORMAT_ID CMsiaCapability::IDsByRank[MAX_CAPS_PRESORT];
  77. UINT CMsiaCapability::uNumLocalFormats = 0; // # of active entries in pLocalFormats
  78. UINT CMsiaCapability::uStaticRef = 0; // global ref count
  79. UINT CMsiaCapability::uCapIDBase = 0; // rebase capability ID to index into IDsByRank
  80. UINT CMsiaCapability::uLocalFormatCapacity = 0; // size of pLocalFormats (in multiples of AUDCAP_DETAILS)
  81. AUDCAP_DETAILS * CMsiaCapability::pLocalFormats = NULL;
  82. CMsiaCapability::CMsiaCapability()
  83. :uRef(1),
  84. wMaxCPU(95),
  85. m_uPacketDuration(90),
  86. uNumRemoteDecodeFormats(0),
  87. uRemoteDecodeFormatCapacity(0),
  88. pRemoteDecodeFormats(NULL),
  89. bPublicizeTXCaps(FALSE),
  90. bPublicizeTSTradeoff(FALSE),
  91. pRegFmts(NULL)
  92. {
  93. m_IAppCap.Init(this);
  94. }
  95. CMsiaCapability::~CMsiaCapability()
  96. {
  97. CloseACMDriver();
  98. UINT u;
  99. AUDCAP_DETAILS *pDetails;
  100. // release global static memory (the local capabilities) if this is the last delete
  101. if(uStaticRef <= 1)
  102. {
  103. if (pLocalFormats)
  104. {
  105. pDetails = pLocalFormats;
  106. for(u=0; u <uNumLocalFormats; u++)
  107. {
  108. if(pDetails->lpLocalFormatDetails)
  109. {
  110. MEMFREE(pDetails->lpLocalFormatDetails);
  111. }
  112. // there really should never be remote details associated with the local
  113. // formats........
  114. if(pDetails->lpRemoteFormatDetails)
  115. {
  116. MEMFREE(pDetails->lpRemoteFormatDetails);
  117. }
  118. pDetails++;
  119. }
  120. MEMFREE(pLocalFormats);
  121. pLocalFormats=NULL;
  122. uLocalFormatCapacity = 0;
  123. }
  124. uStaticRef--;
  125. //Clean up the format cache. - This was the audio format information that
  126. //Was in the registry. A list of names, ptrs to AUDCAP_DETAILS blocks
  127. //and a count of formats. Memory is allocated in ReadRegistryFormats,
  128. //called from ReInit()
  129. }
  130. else
  131. {
  132. uStaticRef--;
  133. }
  134. if (pRemoteDecodeFormats)
  135. {
  136. pDetails = pRemoteDecodeFormats;
  137. for(u=0; u <uNumRemoteDecodeFormats; u++)
  138. {
  139. if(pDetails->lpLocalFormatDetails)
  140. {
  141. MEMFREE(pDetails->lpLocalFormatDetails);
  142. }
  143. // there really should never be remote details associated with the local
  144. // formats........
  145. if(pDetails->lpRemoteFormatDetails)
  146. {
  147. MEMFREE(pDetails->lpRemoteFormatDetails);
  148. }
  149. pDetails++;
  150. }
  151. MEMFREE(pRemoteDecodeFormats);
  152. pRemoteDecodeFormats=NULL;
  153. uRemoteDecodeFormatCapacity = 0;
  154. }
  155. FreeRegistryFormats(pRegFmts);
  156. }
  157. BOOL CMsiaCapability::Init()
  158. {
  159. BOOL bRet;
  160. if(uStaticRef == 0)
  161. {
  162. if(bRet = ReInit())
  163. {
  164. uStaticRef++;
  165. }
  166. }
  167. else
  168. {
  169. uStaticRef++;
  170. bRet = TRUE;
  171. }
  172. return bRet;
  173. }
  174. BOOL CMsiaCapability::ReInit()
  175. {
  176. SYSTEM_INFO si;
  177. DWORD dwDisposition;
  178. BOOL bRet = TRUE;
  179. ACM_APP_PARAM sAppParam={this, NULL, ACMAPP_FORMATENUMHANDLER_ENUM, NULL, NULL, 0, NULL};
  180. ACMFORMATTAGDETAILS aftd;
  181. AUDCAP_DETAILS audcapDetails;
  182. UINT i;
  183. ZeroMemory(&IDsByRank, sizeof(IDsByRank));
  184. // LOOKLOOK - this supports a hack to disable CPU intensive codecs if not running on a pentium
  185. GetSystemInfo(&si);
  186. #ifdef _M_IX86
  187. wMaxCPU = (si.dwProcessorType == PROCESSOR_INTEL_PENTIUM )? 100 : 50;
  188. #endif
  189. #ifdef _ALPHA_
  190. wMaxCPU = 100;
  191. #endif
  192. if (pLocalFormats)
  193. {
  194. UINT u;
  195. AUDCAP_DETAILS *pDetails = pLocalFormats;
  196. for(u=0; u <uNumLocalFormats; u++)
  197. {
  198. if(pDetails->lpLocalFormatDetails)
  199. {
  200. MEMFREE(pDetails->lpLocalFormatDetails);
  201. }
  202. // there really should never be remote details associated with the local
  203. // formats........
  204. if(pDetails->lpRemoteFormatDetails)
  205. {
  206. MEMFREE(pDetails->lpRemoteFormatDetails);
  207. }
  208. pDetails++;
  209. }
  210. MEMFREE(pLocalFormats);
  211. pLocalFormats = NULL;
  212. uLocalFormatCapacity = 0;
  213. }
  214. uNumLocalFormats = 0;
  215. uCapIDBase=0;
  216. /*
  217. * Format cache
  218. */
  219. if (!pRegFmts) {
  220. if (!(pRegFmts=(PRRF_INFO)MemAlloc (sizeof (RRF_INFO)))) {
  221. bRet = FALSE;
  222. goto RELEASE_AND_EXIT;
  223. }
  224. bUseDefault=FALSE;
  225. if (ReadRegistryFormats (szRegInternetPhone TEXT("\\") szRegMSIPAndH323Encodings,
  226. &pRegFmts->pNames,(BYTE ***)&pRegFmts->pData,&pRegFmts->nFormats,sizeof (AUDCAP_DETAILS)) != ERROR_SUCCESS) {
  227. bUseDefault=TRUE;
  228. MemFree ((void *) pRegFmts);
  229. pRegFmts=NULL;
  230. }
  231. }
  232. // pass the registry formats through ACM to the handler
  233. sAppParam.pRegCache=pRegFmts;
  234. if(!DriverEnum((DWORD_PTR) &sAppParam))
  235. {
  236. bRet = FALSE;
  237. goto RELEASE_AND_EXIT;
  238. }
  239. SortEncodeCaps(SortByAppPref);
  240. RELEASE_AND_EXIT:
  241. return bRet;
  242. }
  243. STDMETHODIMP CMsiaCapability::QueryInterface( REFIID iid, void ** ppvObject)
  244. {
  245. // this breaks the rules for the official COM QueryInterface because
  246. // the interfaces that are queried for are not necessarily real COM
  247. // interfaces. The reflexive property of QueryInterface would be broken in
  248. // that case.
  249. HRESULT hr = E_NOINTERFACE;
  250. if(!ppvObject)
  251. return hr;
  252. *ppvObject = 0;
  253. if(iid == IID_IAppAudioCap )
  254. {
  255. *ppvObject = (LPAPPCAPPIF)&m_IAppCap;
  256. AddRef();
  257. hr = hrSuccess;
  258. }
  259. else if(iid == IID_IH323MediaCap)
  260. {
  261. *ppvObject = (IH323MediaCap *)this;
  262. AddRef();
  263. hr = hrSuccess;
  264. }
  265. else if (iid == IID_IUnknown)
  266. {
  267. *ppvObject = this;
  268. AddRef();
  269. hr = hrSuccess;
  270. }
  271. return hr;
  272. }
  273. ULONG CMsiaCapability::AddRef()
  274. {
  275. uRef++;
  276. return uRef;
  277. }
  278. ULONG CMsiaCapability::Release()
  279. {
  280. uRef--;
  281. if(uRef == 0)
  282. {
  283. delete this;
  284. return 0;
  285. }
  286. return uRef;
  287. }
  288. VOID CMsiaCapability::FreeRegistryKeyName(LPTSTR lpszKeyName)
  289. {
  290. if (lpszKeyName)
  291. {
  292. LocalFree(lpszKeyName);
  293. }
  294. }
  295. LPTSTR CMsiaCapability::AllocRegistryKeyName(LPTSTR lpDriverName,
  296. UINT uSampleRate, UINT uBitsPerSample, UINT uBytesPerSec)
  297. {
  298. FX_ENTRY(("MsiaCapability::AllocRegistryKeyName"));
  299. BOOL bRet = FALSE;
  300. LPTSTR lpszKeyName = NULL;
  301. if(!lpDriverName)
  302. {
  303. return NULL;
  304. }
  305. // build a subkey name (drivername_samplerate_bitspersample)
  306. // allow room for THREE underscore chars + 2x17 bytes of string returned
  307. // from _itoa
  308. // NOTE: use wsprintf instead of itoa - because of dependency on runtime lib
  309. lpszKeyName = (LPTSTR)LocalAlloc (LPTR, lstrlen(lpDriverName) * sizeof(*lpDriverName)+3*20);
  310. if (!lpszKeyName)
  311. {
  312. ERRORMESSAGE(("%s: LocalAlloc failed\r\n",_fx_));
  313. return(NULL);
  314. }
  315. // build a subkey name ("drivername_samplerate_bitspersample")
  316. wsprintf(lpszKeyName,
  317. "%s_%u_%u_%u",
  318. lpDriverName,
  319. uSampleRate,
  320. uBitsPerSample,
  321. uBytesPerSec);
  322. return (lpszKeyName);
  323. }
  324. VOID CMsiaCapability::SortEncodeCaps(SortMode sortmode)
  325. {
  326. UINT iSorted=0;
  327. UINT iInsert = 0;
  328. UINT iCache=0;
  329. UINT iTemp =0;
  330. BOOL bInsert;
  331. AUDCAP_DETAILS *pDetails1, *pDetails2;
  332. if(!uNumLocalFormats)
  333. return;
  334. if(uNumLocalFormats ==1)
  335. {
  336. IDsByRank[0]=0;
  337. return;
  338. }
  339. // look at every cached format, build index array
  340. for(iCache=0;iCache<uNumLocalFormats;iCache++)
  341. {
  342. pDetails1 = pLocalFormats+iCache;
  343. for(iInsert=0;iInsert < iSorted; iInsert++)
  344. {
  345. pDetails2 = pLocalFormats+IDsByRank[iInsert];
  346. // if existing stuff is less than new stuff....
  347. bInsert = FALSE;
  348. switch(sortmode)
  349. {
  350. case SortByAppPref:
  351. if(pDetails2->wApplicationPrefOrder > pDetails1->wApplicationPrefOrder)
  352. bInsert = TRUE;
  353. break;
  354. default:
  355. break;
  356. }
  357. if(bInsert)
  358. {
  359. if(iSorted < MAX_CAPS_PRESORT)
  360. {
  361. iSorted++;
  362. }
  363. // make room, if there is something in the last element,
  364. // it gets overwritten
  365. for(iTemp = iSorted-1; iTemp > iInsert; iTemp--)
  366. {
  367. IDsByRank[iTemp] = IDsByRank[iTemp-1];
  368. }
  369. // insert at iInsert
  370. IDsByRank[iInsert] = iCache;
  371. break;
  372. }
  373. }
  374. // check end boundary
  375. if((iInsert == iSorted) && (iInsert < MAX_CAPS_PRESORT))
  376. {
  377. IDsByRank[iInsert] = iCache;
  378. iSorted++;
  379. }
  380. }
  381. }
  382. STDMETHODIMP CMsiaCapability::GetDecodeFormatDetails(MEDIA_FORMAT_ID FormatID, VOID **ppFormat, UINT *puSize)
  383. {
  384. // validate input
  385. UINT uIndex = IDToIndex(FormatID);
  386. if(uIndex >= (UINT)uNumLocalFormats)
  387. {
  388. *puSize = 0;
  389. *ppFormat = NULL;
  390. return E_INVALIDARG;
  391. }
  392. *ppFormat = (pLocalFormats + uIndex)->lpLocalFormatDetails;
  393. *puSize = SIZEOF_WAVEFORMATEX((WAVEFORMATEX*)(*ppFormat));
  394. return S_OK;
  395. }
  396. STDMETHODIMP CMsiaCapability::GetEncodeFormatDetails(MEDIA_FORMAT_ID FormatID, VOID **ppFormat, UINT *puSize)
  397. {
  398. // same as GetDecodeFormatDetails
  399. return GetDecodeFormatDetails(FormatID, ppFormat, puSize);
  400. }
  401. VOID CMsiaCapability::CalculateFormatProperties(AUDCAP_DETAILS *pFmtBuf,LPWAVEFORMATEX lpwfx)
  402. {
  403. WORD wFrames;
  404. if(!pFmtBuf)
  405. {
  406. return;
  407. }
  408. // use actual bits per sample unless the bps field is zero, in which case
  409. // assume 16 bits (worst case). This is a typical GSM scenario
  410. UINT uBitrateIn = (pFmtBuf->audio_params.uSamplesPerSec) *
  411. ((pFmtBuf->audio_params.uBitsPerSample)
  412. ? pFmtBuf->audio_params.uBitsPerSample
  413. :16);
  414. // set the maximum bitrate (uMaxBitrate). we're not setting the average bitrate (uAvgBitrate),
  415. // since the nAvgBytesPerSec reported by ACM is really worst case. uAvgBitrate will be set
  416. // from the hardcoded numbers for our known codecs and from the provided AUDCAP_INFO for
  417. // installable codecs
  418. pFmtBuf->uMaxBitrate = (lpwfx->nAvgBytesPerSec)? lpwfx->nAvgBytesPerSec*8:uBitrateIn;
  419. pFmtBuf->dwDefaultSamples = MinSampleSize(lpwfx);
  420. // nonstandard channel parameters. This
  421. // might be a good point to calculate values that don't have valid defaults set.
  422. wFrames = pFmtBuf->nonstd_params.wFramesPerPktMax;
  423. if(!pFmtBuf->nonstd_params.wFramesPerPktMax)
  424. {
  425. pFmtBuf->nonstd_params.wFramesPerPktMax=
  426. wFrames = LOWORD(MaxFramesPerPacket(lpwfx));
  427. }
  428. // if the preferred frames/packet is 0 or greater than the max, set it to min
  429. if((pFmtBuf->nonstd_params.wFramesPerPkt ==0) ||
  430. (pFmtBuf->nonstd_params.wFramesPerPkt > wFrames))
  431. {
  432. pFmtBuf->nonstd_params.wFramesPerPkt =
  433. LOWORD(MinFramesPerPacket(lpwfx));
  434. }
  435. // if the min is more than preferred, fix it
  436. if(pFmtBuf->nonstd_params.wFramesPerPktMin > pFmtBuf->nonstd_params.wFramesPerPkt)
  437. {
  438. pFmtBuf->nonstd_params.wFramesPerPktMin =
  439. LOWORD(MinFramesPerPacket(lpwfx));
  440. }
  441. pFmtBuf->nonstd_params.wDataRate =0; // default
  442. pFmtBuf->nonstd_params.wFrameSize = (pFmtBuf->nonstd_params.wFramesPerPkt)
  443. ? LOWORD(pFmtBuf->dwDefaultSamples / pFmtBuf->nonstd_params.wFramesPerPkt): 0;
  444. pFmtBuf->nonstd_params.UsePostFilter = 0;
  445. pFmtBuf->nonstd_params.UseSilenceDet = 0;
  446. }
  447. AUDIO_FORMAT_ID CMsiaCapability::AddFormat(AUDCAP_DETAILS *pFmtBuf,LPVOID lpvMappingData, UINT uSize)
  448. {
  449. FX_ENTRY(("CMsiaCapability::AddFormat"));
  450. AUDCAP_DETAILS *pTemp;
  451. WORD wFrames;
  452. UINT uSamples;
  453. if(!pFmtBuf || !lpvMappingData || !uSize)
  454. {
  455. return INVALID_AUDIO_FORMAT;
  456. }
  457. // check room
  458. if(uLocalFormatCapacity <= uNumLocalFormats)
  459. {
  460. // get more mem, realloc memory by CAP_CHUNK_SIZE for pLocalFormats
  461. pTemp = (AUDCAP_DETAILS *)MEMALLOC((uNumLocalFormats + CAP_CHUNK_SIZE)*sizeof(AUDCAP_DETAILS));
  462. if(!pTemp)
  463. goto ERROR_EXIT;
  464. // remember how much capacity we now have
  465. uLocalFormatCapacity = uNumLocalFormats + CAP_CHUNK_SIZE;
  466. #ifdef DEBUG
  467. if((uNumLocalFormats && !pLocalFormats) || (!uNumLocalFormats && pLocalFormats))
  468. {
  469. ERRORMESSAGE(("%s:leak! uNumLocalFormats:0x%08lX, pLocalFormats:0x%08lX\r\n",
  470. _fx_, uNumLocalFormats,pLocalFormats));
  471. }
  472. #endif
  473. // copy old stuff, discard old mem
  474. if(uNumLocalFormats && pLocalFormats)
  475. {
  476. memcpy(pTemp, pLocalFormats, uNumLocalFormats*sizeof(AUDCAP_DETAILS));
  477. MEMFREE(pLocalFormats);
  478. }
  479. pLocalFormats = pTemp;
  480. }
  481. // pTemp is where the stuff is cached
  482. pTemp = pLocalFormats+uNumLocalFormats;
  483. memcpy(pTemp, pFmtBuf, sizeof(AUDCAP_DETAILS));
  484. pTemp->uLocalDetailsSize = 0; // clear this now
  485. //if(uSize && lpvMappingData)
  486. //{
  487. pTemp->lpLocalFormatDetails = MEMALLOC(uSize);
  488. if(pTemp->lpLocalFormatDetails)
  489. {
  490. memcpy(pTemp->lpLocalFormatDetails, lpvMappingData, uSize);
  491. pTemp->uLocalDetailsSize = uSize;
  492. }
  493. #ifdef DEBUG
  494. else
  495. {
  496. ERRORMESSAGE(("%s:allocation failed!\r\n",_fx_));
  497. }
  498. #endif
  499. //}
  500. //else
  501. //{
  502. //}
  503. // in all cases, fixup channel parameters.
  504. pTemp->dwDefaultSamples = uSamples =pTemp->dwDefaultSamples;
  505. wFrames = pTemp->nonstd_params.wFramesPerPktMax;
  506. if(!pTemp->nonstd_params.wFramesPerPktMax)
  507. {
  508. pTemp->nonstd_params.wFramesPerPktMax=
  509. wFrames = LOWORD(MaxFramesPerPacket((LPWAVEFORMATEX)lpvMappingData));
  510. }
  511. // if the preferred frames/packet is 0 or greater than the max, set it to min
  512. if((pTemp->nonstd_params.wFramesPerPkt ==0) ||
  513. (pTemp->nonstd_params.wFramesPerPkt > wFrames))
  514. {
  515. pTemp->nonstd_params.wFramesPerPkt =
  516. LOWORD(MinFramesPerPacket((LPWAVEFORMATEX)lpvMappingData));
  517. }
  518. // if the min is more than preferred, fix it
  519. if(pTemp->nonstd_params.wFramesPerPktMin > pTemp->nonstd_params.wFramesPerPkt)
  520. {
  521. pTemp->nonstd_params.wFramesPerPktMin =
  522. LOWORD(MinFramesPerPacket((LPWAVEFORMATEX)lpvMappingData));
  523. }
  524. pTemp->nonstd_params.wDataRate =0; // default
  525. pTemp->nonstd_params.wFrameSize = (pTemp->nonstd_params.wFramesPerPkt)
  526. ?uSamples / pTemp->nonstd_params.wFramesPerPkt: 0;
  527. if(pTemp->nonstd_params.wFrameSizeMax < pTemp->nonstd_params.wFrameSize)
  528. pTemp->nonstd_params.wFrameSizeMax = pTemp->nonstd_params.wFrameSize;
  529. pTemp->nonstd_params.UsePostFilter = 0;
  530. pTemp->nonstd_params.UseSilenceDet = 0;
  531. // fixup the H245 parameters. Use the REBASED index of the cap entry as the cap ID
  532. pTemp->H245TermCap.CapId = (USHORT)IndexToId(uNumLocalFormats);
  533. if(pTemp->H245TermCap.ClientType ==0
  534. || pTemp->H245TermCap.ClientType ==H245_CLIENT_AUD_NONSTD)
  535. {
  536. LPWAVEFORMATEX lpwfx;
  537. lpwfx = (LPWAVEFORMATEX)pTemp->lpLocalFormatDetails;
  538. if(lpwfx)
  539. {
  540. pTemp->H245TermCap.ClientType = H245_CLIENT_AUD_NONSTD;
  541. // all nonstandard identifier fields are unsigned short
  542. // two possibilities for choice are "h221NonStandard_chosen" and "object_chosen"
  543. pTemp->H245TermCap.H245Aud_NONSTD.nonStandardIdentifier.choice = h221NonStandard_chosen;
  544. pTemp->H245TermCap.H245Aud_NONSTD.nonStandardIdentifier.u.h221NonStandard.t35CountryCode = USA_H221_COUNTRY_CODE;
  545. pTemp->H245TermCap.H245Aud_NONSTD.nonStandardIdentifier.u.h221NonStandard.t35Extension = USA_H221_COUNTRY_EXTENSION;
  546. pTemp->H245TermCap.H245Aud_NONSTD.nonStandardIdentifier.u.h221NonStandard.manufacturerCode = MICROSOFT_H_221_MFG_CODE;
  547. // Set the nonstandard data fields to null for now. The nonstandard cap data will be
  548. // created when capabilities are serialized.
  549. // set size of buffer
  550. pTemp->H245TermCap.H245Aud_NONSTD.data.length = 0;
  551. pTemp->H245TermCap.H245Aud_NONSTD.data.value = NULL;
  552. }
  553. }
  554. else
  555. {
  556. // the following should already have been set in *pFmtBuf by the calling function
  557. // and it should have already been copied to *pTemp
  558. //pTemp->ClientType = (H245_CLIENT_T)pDecodeDetails->H245Cap.ClientType;
  559. //pTemp->DataType = H245_DATA_AUDIO;
  560. //pTemp->Dir = H245_CAPDIR_LCLTX; // should this be H245_CAPDIR_LCLRX for receive caps?
  561. // issue:special case G723 params ???
  562. if(pTemp->H245TermCap.ClientType == H245_CLIENT_AUD_G723)
  563. {
  564. pTemp->H245TermCap.H245Aud_G723.maxAl_sduAudioFrames = 4;
  565. // mikev 9/10/96 - we may NOT want to advertise silence suppression capability of
  566. // the codec because our silence detection scheme works out-of-band for any codec
  567. // 9/29/96 - this gets overwritten in SerializeH323DecodeFormats() anyway
  568. pTemp->H245TermCap.H245Aud_G723.silenceSuppression = 0;
  569. }
  570. // check for pre-existing capability with the same standard ID.
  571. pTemp->dwPublicRefIndex = 0; // forget old association, assume that there
  572. // is no pre-existing capability with the same
  573. //standard ID.
  574. UINT i;
  575. AUDCAP_DETAILS *pFmtExisting = pLocalFormats;
  576. BOOL bRefFound = FALSE; // this var needed only to support backward
  577. // compatibility with Netmeeting 2.0 Beta 1
  578. if(uNumLocalFormats && pLocalFormats)
  579. {
  580. for(i=0; i<uNumLocalFormats; i++)
  581. {
  582. pFmtExisting = pLocalFormats + i;
  583. // see if it is the same defined codepoint
  584. if(pFmtExisting->H245TermCap.ClientType == pTemp->H245TermCap.ClientType)
  585. {
  586. // mark this capability entry as being publically advertised
  587. // by the existing entry. If the existing entry also refs
  588. // another, follow the reference
  589. pTemp->dwPublicRefIndex = (pFmtExisting->dwPublicRefIndex)?
  590. pFmtExisting->dwPublicRefIndex : i;
  591. bRefFound = TRUE;
  592. break;
  593. }
  594. }
  595. }
  596. }
  597. uNumLocalFormats++;
  598. // return the capability ID.
  599. //return (uNumLocalFormats-1);
  600. return pTemp->H245TermCap.CapId;
  601. ERROR_EXIT:
  602. return INVALID_AUDIO_FORMAT;
  603. }
  604. UINT CMsiaCapability::GetNumCaps(BOOL bRXCaps)
  605. {
  606. UINT u, uOut=0;
  607. AUDCAP_DETAILS *pDecodeDetails = pLocalFormats;
  608. if(bRXCaps)
  609. {
  610. for(u=0; u <uNumLocalFormats; u++)
  611. {
  612. if(pDecodeDetails->bRecvEnabled)
  613. uOut++;
  614. pDecodeDetails++;
  615. }
  616. return uOut;
  617. }
  618. else
  619. return uNumLocalFormats;
  620. }
  621. VOID CMsiaCapability::FlushRemoteCaps()
  622. {
  623. if(pRemoteDecodeFormats)
  624. {
  625. MEMFREE(pRemoteDecodeFormats);
  626. pRemoteDecodeFormats = NULL;
  627. uNumRemoteDecodeFormats = 0;
  628. uRemoteDecodeFormatCapacity = 0;
  629. }
  630. }
  631. HRESULT CMsiaCapability::GetNumFormats(UINT *puNumFmtOut)
  632. {
  633. *puNumFmtOut = uNumLocalFormats;
  634. return hrSuccess;
  635. }
  636. /***************************************************************************
  637. Name : CMsiaCapability::FormatEnumHandler
  638. Purpose : Enumerate ACM formats coming from ACM, and see if they
  639. are ones that we use.
  640. Parameters: Standard ACM EnumFormatCallback parameters
  641. Returns : BOOL
  642. Comment :
  643. ***************************************************************************/
  644. BOOL CMsiaCapability::FormatEnumHandler(HACMDRIVERID hadid,
  645. LPACMFORMATDETAILS pafd, DWORD_PTR dwInstance, DWORD fdwSupport)
  646. {
  647. PACM_APP_PARAM pAppParam = (PACM_APP_PARAM) dwInstance;
  648. LPACMFORMATTAGDETAILS paftd = pAppParam->paftd;
  649. AUDCAP_DETAILS audcap_entry;
  650. // look at the passed in dwInstance. this will tell us which format handler
  651. // to call
  652. if ((pAppParam->dwFlags && ACMAPP_FORMATENUMHANDLER_MASK) == ACMAPP_FORMATENUMHANDLER_ADD)
  653. {
  654. // this one was called for add format purposes
  655. return AddFormatEnumHandler(hadid, pafd, dwInstance, fdwSupport);
  656. }
  657. // evaluate the details
  658. if(pafd->pwfx->nChannels ==1)
  659. {
  660. if(IsFormatSpecified(pafd->pwfx, pafd, paftd, &audcap_entry))
  661. {
  662. DEBUGMSG(ZONE_ACM,("FormatEnumHandler: tag 0x%04X, nChannels %d\r\n",
  663. pafd->pwfx->wFormatTag, pafd->pwfx->nChannels));
  664. DEBUGMSG(ZONE_ACM,("FormatEnumHandler: nSamplesPerSec 0x%08lX, nAvgBytesPerSec 0x%08lX,\r\n",
  665. pafd->pwfx->nSamplesPerSec, pafd->pwfx->nAvgBytesPerSec));
  666. DEBUGMSG(ZONE_ACM,("FormatEnumHandler: nBlockAlign 0x%04X, wBitsPerSample 0x%04X, cbSize 0x%04X\r\n",
  667. pafd->pwfx->nBlockAlign, pafd->pwfx->wBitsPerSample, pafd->pwfx->cbSize));
  668. DEBUGMSG(ZONE_ACM,("FormatEnumHandler: szFormat %s,\r\n",
  669. pafd->szFormat));
  670. // done inside IsFormatSpecified and/or whatever it calls
  671. // CalculateFormatProperties(&audcap_details, pafd->pwfx);
  672. AddFormat(&audcap_entry, (LPVOID)pafd->pwfx,
  673. (pafd->pwfx) ? (sizeof(WAVEFORMATEX)+pafd->pwfx->cbSize):0);
  674. }
  675. //#define BUILD_TEST_ENTRIES
  676. #ifdef BUILD_TEST_ENTRIES
  677. else
  678. {
  679. AUDCAP_INFO sAudCapInfo;
  680. if(paftd)
  681. {
  682. if((lstrcmp(paftd->szFormatTag, "G.723" ) ==0)
  683. /* || (lstrcmp(paftd->szFormatTag, "MSN Audio" ) ==0) */
  684. || (lstrcmp(paftd->szFormatTag, "GSM 6.10" ) ==0))
  685. {
  686. lstrcpyn(audcap_entry.szFormat, paftd->szFormatTag,
  687. sizeof(audcap_entry.szFormat));
  688. int iLen = lstrlen(audcap_entry.szFormat);
  689. if(iLen < (sizeof(audcap_entry.szFormat) + 8*sizeof(TCHAR)))
  690. {
  691. // ok to concatenate
  692. lstrcat(audcap_entry.szFormat,", ");
  693. // must check for truncation. so do the final concatenation via lstrcpyn
  694. // lstrcat(audcap_entry.szFormat, pafd->szFormat);
  695. iLen = lstrlen(audcap_entry.szFormat);
  696. lstrcpyn(&audcap_entry.szFormat[iLen], pafd->szFormat,
  697. sizeof(audcap_entry.szFormat) - iLen - sizeof(TCHAR));
  698. }
  699. lstrcpyn(sAudCapInfo.szFormat, audcap_entry.szFormat,
  700. sizeof(sAudCapInfo.szFormat);
  701. AddACMFormat (pafd->pwfx, &sAudCapInfo);
  702. }
  703. }
  704. }
  705. #endif // BUILD_TEST_ENTRIES
  706. }
  707. return TRUE;
  708. }
  709. /***************************************************************************
  710. Name : CMsiaCapability::BuildFormatName
  711. Purpose : Builds a format name for a format, from the format name and
  712. the tag name
  713. Parameters: pAudcapDetails [out] - pointer to an AUDCAP_DETAILS structure, where the
  714. created value name will be stored
  715. pszFormatTagName [in] - pointer to the name of the format tag
  716. pszFormatName [in] - pointer to the name of the format
  717. Returns : BOOL
  718. Comment :
  719. ***************************************************************************/
  720. BOOL CMsiaCapability::BuildFormatName( AUDCAP_DETAILS *pAudcapDetails,
  721. char *pszFormatTagName,
  722. char *pszFormatName)
  723. {
  724. BOOL bRet = TRUE;
  725. int iLen=0;
  726. if (!pAudcapDetails ||
  727. !pszFormatTagName ||
  728. !pszFormatName)
  729. {
  730. bRet = FALSE;
  731. goto out;
  732. }
  733. // concatenate ACM strings to form the first part of the registry key - the
  734. // format is szFormatTag (actually pAudcapDetails->szFormat)
  735. // (the string which describes the format tag followed by szFormatDetails
  736. // (the string which describes parameters, e.g. sample rate)
  737. lstrcpyn(pAudcapDetails->szFormat, pszFormatTagName, sizeof(pAudcapDetails->szFormat));
  738. iLen = lstrlen(pAudcapDetails->szFormat);
  739. // if the format tag description string takes up all the space, don't
  740. // bother with the format details (need space for ", " also).
  741. // we're going to say that if we don't have room for 4 characters
  742. // of the format details string + " ,", then it's not worth it if the
  743. // point is generating a unique string -if it is not unique by now, it
  744. // will be because some ACM driver writer was misinformed
  745. if(iLen < (sizeof(pAudcapDetails->szFormat) + 8*sizeof(TCHAR)))
  746. {
  747. // ok to concatenate
  748. lstrcat(pAudcapDetails->szFormat,", ");
  749. // must check for truncation. so do the final concatenation via lstrcpyn
  750. // lstrcat(pFormatPrefsBuf->szFormat, pafd->szFormat);
  751. iLen = lstrlen(pAudcapDetails->szFormat);
  752. lstrcpyn(pAudcapDetails->szFormat+iLen, pszFormatName,
  753. sizeof(pAudcapDetails->szFormat) - iLen - sizeof(TCHAR));
  754. }
  755. out:
  756. return bRet;
  757. }
  758. // Free a a structure of registry formats info (PRRF_INFO), including memory pointed
  759. // from this structure
  760. void FreeRegistryFormats (PRRF_INFO pRegFmts)
  761. {
  762. UINT u;
  763. if (pRegFmts) {
  764. for (u=0;u<pRegFmts->nFormats;u++) {
  765. MemFree ((void *) pRegFmts->pNames[u]);
  766. MemFree ((void *) pRegFmts->pData[u]);
  767. }
  768. MemFree ((void *) pRegFmts->pNames);
  769. MemFree ((void *) pRegFmts->pData);
  770. MemFree ((void *) pRegFmts);
  771. }
  772. }
  773. ULONG ReadRegistryFormats (LPCSTR lpszKeyName,CHAR ***pppName,BYTE ***pppData,PUINT pnFormats,DWORD dwDebugSize)
  774. {
  775. HKEY hKeyParent;
  776. DWORD nSubKey,nMaxSubLen,nValues=0,nValNamelen,nValDatalen,nValTemp,nDataTemp,i;
  777. ULONG hRes;
  778. //Not neccessary but makes life easier
  779. CHAR **pNames=NULL;
  780. BYTE **pData=NULL;
  781. *pnFormats=0;
  782. //Get the top level node.
  783. hRes=RegOpenKeyEx (HKEY_LOCAL_MACHINE,lpszKeyName,0,KEY_READ,&hKeyParent);
  784. if (hRes != ERROR_SUCCESS)
  785. {
  786. return hRes;
  787. }
  788. //Get some info about this key
  789. hRes=RegQueryInfoKey (hKeyParent,NULL,NULL,NULL,&nSubKey,&nMaxSubLen,NULL,&nValues,&nValNamelen,&nValDatalen,NULL,NULL);
  790. if (hRes != ERROR_SUCCESS)
  791. {
  792. goto Error_Out;
  793. }
  794. if (nValDatalen != dwDebugSize) {
  795. DEBUGMSG (ZONE_ACM,("Largest Data Value not expected size!\r\n"));
  796. hRes=ERROR_INVALID_DATA;
  797. goto Error_Out;
  798. }
  799. //Allocate some memory for the various pointers.
  800. if (!(pNames=(char **) MemAlloc (sizeof(char *)*nValues))) {
  801. hRes=ERROR_OUTOFMEMORY;
  802. goto Error_Out;
  803. }
  804. ZeroMemory (pNames,sizeof (char *)*nValues);
  805. if (!(pData = (BYTE **) MemAlloc (sizeof(BYTE *)*nValues))) {
  806. hRes=ERROR_OUTOFMEMORY;
  807. goto Error_Out;
  808. }
  809. ZeroMemory (pData,sizeof (BYTE *)*nValues);
  810. //Walk the value list.
  811. for (i=0;i<nValues;i++)
  812. {
  813. //Yes, we're wasting memory here, oh well it's not a lot.
  814. //probably 40 bytes. We free it later
  815. if (!(pNames[i] = (char *)MemAlloc (nValNamelen))) {
  816. hRes=ERROR_OUTOFMEMORY;
  817. goto Error_Out;
  818. }
  819. if (!(pData[i] = (BYTE *)MemAlloc (nValDatalen))) {
  820. hRes=ERROR_OUTOFMEMORY;
  821. goto Error_Out;
  822. }
  823. //This needs to be able to be smashed, but is an in/out param.
  824. nValTemp=nValNamelen;
  825. nDataTemp=nValDatalen;
  826. hRes=RegEnumValue (hKeyParent,i,(pNames[i]),&nValTemp,NULL,NULL,(pData[i]),&nDataTemp);
  827. #ifdef DEBUG
  828. if (nDataTemp != dwDebugSize) {
  829. DEBUGMSG (ZONE_ACM, ("ReadRegistryFormats: Data block not expected size!\r\n"));
  830. //Return?
  831. }
  832. #endif
  833. }
  834. //Fill in the output.
  835. *pnFormats=nValues;
  836. *pppName=pNames;
  837. *pppData=pData;
  838. RegCloseKey (hKeyParent);
  839. return (ERROR_SUCCESS);
  840. Error_Out:
  841. RegCloseKey (hKeyParent);
  842. //Free any allocations
  843. if(pNames)
  844. {
  845. for (i=0;i<nValues;i++)
  846. {
  847. if (pNames[i])
  848. {
  849. MemFree (pNames[i]);
  850. }
  851. }
  852. MemFree (pNames);
  853. }
  854. if (pData)
  855. {
  856. for (i=0;i<nValues;i++)
  857. {
  858. if (pData[i])
  859. {
  860. MemFree (pData[i]);
  861. }
  862. }
  863. MemFree (pData);
  864. }
  865. return hRes;
  866. }
  867. BOOL CMsiaCapability::IsFormatSpecified(LPWAVEFORMATEX lpwfx, LPACMFORMATDETAILS pafd,
  868. LPACMFORMATTAGDETAILS paftd, AUDCAP_DETAILS *pAudcapDetails)
  869. {
  870. AUDCAP_DETAILS cap_entry;
  871. BOOL bRet = FALSE;
  872. LPTSTR lpszValueName = NULL;
  873. DWORD dwRes;
  874. UINT i;
  875. if(!lpwfx || !pAudcapDetails)
  876. {
  877. return FALSE;
  878. }
  879. if (!bUseDefault) {
  880. for (i=0;i<pRegFmts->nFormats;i++) {
  881. // do a quick sanity check on the contents
  882. if ( (lpwfx->wFormatTag == ((AUDCAP_DETAILS *)pRegFmts->pData[i])->wFormatTag) &&
  883. (lpwfx->nSamplesPerSec == ((DWORD)((AUDCAP_DETAILS *)pRegFmts->pData[i])->audio_params.uSamplesPerSec)) &&
  884. ((lpwfx->nAvgBytesPerSec * 8) == (((AUDCAP_DETAILS *)pRegFmts->pData[i])->uMaxBitrate))) {
  885. break;
  886. }
  887. }
  888. if (i == pRegFmts->nFormats) {
  889. //Check the case that some (but not all) of the default formats are missing.
  890. for (i=0;i<uDefTableEntries;i++) {
  891. if ((paftd->dwFormatTag == default_id_table[i].wFormatTag)
  892. && (lpwfx->nSamplesPerSec == (DWORD)default_id_table[i].audio_params.uSamplesPerSec)
  893. && (lpwfx->wBitsPerSample == LOWORD(default_id_table[i].audio_params.uBitsPerSample))) {
  894. //Arrgh!! Jump down, and rebuild this format
  895. goto RebuildFormat;
  896. }
  897. }
  898. if (i==uDefTableEntries) {
  899. //We don't care about this format, it's not in the cache, or default list
  900. return FALSE;
  901. }
  902. }
  903. memcpy(pAudcapDetails, pRegFmts->pData[i], sizeof(AUDCAP_DETAILS));
  904. bRet=TRUE;
  905. } else {
  906. RebuildFormat:
  907. RtlZeroMemory((PVOID) pAudcapDetails, sizeof(AUDCAP_DETAILS));
  908. // fixup the bits per sample and sample rate fields of audio_params so that the key name can be built
  909. pAudcapDetails->audio_params.uSamplesPerSec = lpwfx->nSamplesPerSec;
  910. pAudcapDetails->audio_params.uBitsPerSample = MAKELONG(lpwfx->wBitsPerSample,0);
  911. pAudcapDetails->uMaxBitrate = lpwfx->nAvgBytesPerSec * 8;
  912. if (!paftd ||
  913. (!BuildFormatName( pAudcapDetails,
  914. paftd->szFormatTag,
  915. pafd->szFormat)))
  916. {
  917. ERRORMESSAGE(("IsFormatSpecified: Couldn't build format name\r\n"));
  918. return(FALSE);
  919. }
  920. for(i=0;i< uDefTableEntries; i++)
  921. {
  922. if((lpwfx->wFormatTag == default_id_table[i].wFormatTag)
  923. && (lpwfx->nSamplesPerSec == (DWORD)default_id_table[i].audio_params.uSamplesPerSec)
  924. && (lpwfx->wBitsPerSample == LOWORD(default_id_table[i].audio_params.uBitsPerSample)))
  925. //&& strnicmp(lpwfx->szFormat, default_id_table[i].szFormat)
  926. {
  927. // found matching default entry - copy stuff from table
  928. // (but don't overwrite the string)
  929. memcpy(pAudcapDetails, &default_id_table[i],
  930. sizeof(AUDCAP_DETAILS) - sizeof(pAudcapDetails->szFormat));
  931. // LOOKLOOK - test against CPU limitations.
  932. // this supports a hack to disable CPU intensive codecs if not running
  933. //on a pentium
  934. if(default_id_table[i].wCPUUtilizationEncode > wMaxCPU)
  935. {
  936. pAudcapDetails->bSendEnabled = FALSE;
  937. }
  938. if(default_id_table[i].wCPUUtilizationDecode > wMaxCPU)
  939. {
  940. pAudcapDetails->bRecvEnabled = FALSE;
  941. }
  942. // add this to the registry
  943. CalculateFormatProperties(pAudcapDetails, lpwfx);
  944. bRet = UpdateFormatInRegistry(pAudcapDetails);
  945. break;
  946. }
  947. }
  948. }
  949. return bRet;
  950. }
  951. /***************************************************************************
  952. Name : CMsiaCapability::CopyAudcapInfo
  953. Purpose : Copies basic audio info from an AUDCAP_INFO structure to an
  954. AUDCAP_DETAILS structure, or vice versa. AUDCAP_INFO is external
  955. representation. AUDCAP_DETAILS is internal one.
  956. Parameters: pDetails - pointer to an AUDCAP_DETAILS structure
  957. pInfo - pointer to an AUDCAP_INFO structure
  958. bDirection - 0 = ->, 1 = <-
  959. Returns : HRESULT
  960. Comment :
  961. ***************************************************************************/
  962. HRESULT CMsiaCapability::CopyAudcapInfo (PAUDCAP_DETAILS pDetails,
  963. PAUDCAP_INFO pInfo, BOOL bDirection)
  964. {
  965. WORD wSortIndex;
  966. UINT uIndex;
  967. AUDIO_FORMAT_ID Id;
  968. HRESULT hr=NOERROR;
  969. if(!pInfo || !pDetails)
  970. {
  971. hr = CAPS_E_INVALID_PARAM;
  972. goto out;
  973. }
  974. if (bDirection)
  975. {
  976. // AUDCAP_INFO -> AUDCAP_DETAILS
  977. // the caller cannot modify szFormat, Id, wSortIndex and uMaxBitrate, all calculated fields
  978. pDetails->wFormatTag = pInfo->wFormatTag;
  979. pDetails->uAvgBitrate = pInfo->uAvgBitrate;
  980. pDetails->wCPUUtilizationEncode = pInfo->wCPUUtilizationEncode;
  981. pDetails->wCPUUtilizationDecode = pInfo->wCPUUtilizationDecode;
  982. pDetails->bSendEnabled = pInfo->bSendEnabled;
  983. pDetails->bRecvEnabled = pInfo->bRecvEnabled;
  984. }
  985. else
  986. {
  987. // find the sort index.
  988. uIndex = (UINT)(pDetails - pLocalFormats);
  989. Id = IndexToId(uIndex);
  990. for(wSortIndex=0; wSortIndex<uNumLocalFormats && wSortIndex < MAX_CAPS_PRESORT; wSortIndex++)
  991. {
  992. if (uIndex == IDsByRank[wSortIndex])
  993. break; // found it
  994. }
  995. // note: recall that only MAX_CAPS_PRESORT are sorted and the rest are in random order.
  996. // the rest all have a value of MAX_CAPS_PRESORT for the sort index
  997. memcpy(pInfo->szFormat, pDetails->szFormat, sizeof(pInfo->szFormat));
  998. // AUDCAP_DETAILS -> AUDCAP_INFO
  999. pInfo->wFormatTag = pDetails->wFormatTag;
  1000. pInfo->Id = Id;
  1001. pInfo->uMaxBitrate = pDetails->uMaxBitrate;
  1002. pInfo->uAvgBitrate = pDetails->uAvgBitrate;
  1003. pInfo->wCPUUtilizationEncode = pDetails->wCPUUtilizationEncode;
  1004. pInfo->wCPUUtilizationDecode = pDetails->wCPUUtilizationDecode;
  1005. pInfo->bSendEnabled = pDetails->bSendEnabled;
  1006. pInfo->bRecvEnabled = pDetails->bRecvEnabled;
  1007. pInfo->wSortIndex = wSortIndex;
  1008. }
  1009. out:
  1010. return hr;
  1011. }
  1012. HRESULT CMsiaCapability::EnumCommonFormats(PBASIC_AUDCAP_INFO pFmtBuf, UINT uBufsize,
  1013. UINT *uNumFmtOut, BOOL bTXCaps)
  1014. {
  1015. UINT u, uNumOut =0;
  1016. HRESULT hr = hrSuccess;
  1017. MEDIA_FORMAT_ID FormatIDRemote;
  1018. HRESULT hrIsCommon;
  1019. AUDCAP_DETAILS *pDetails = pLocalFormats;
  1020. // validate input
  1021. if(!pFmtBuf || !uNumFmtOut || (uBufsize < (sizeof(BASIC_AUDCAP_INFO)*uNumLocalFormats)))
  1022. {
  1023. return CAPS_E_INVALID_PARAM;
  1024. }
  1025. if(!uNumLocalFormats || !pDetails)
  1026. {
  1027. return CAPS_E_NOCAPS;
  1028. }
  1029. // temporary - enumerating requestable receive formats is not yet supported
  1030. if(!bTXCaps)
  1031. return CAPS_E_NOT_SUPPORTED;
  1032. for(u=0; (u <uNumLocalFormats) && (u <MAX_CAPS_PRESORT); u++)
  1033. {
  1034. pDetails = pLocalFormats + IDsByRank[u];
  1035. // if there is a session, then return formats that are common to local and remote.
  1036. if(uNumRemoteDecodeFormats)
  1037. {
  1038. hrIsCommon = ResolveToLocalFormat(IndexToId(IDsByRank[u]), &FormatIDRemote);
  1039. if(HR_SUCCEEDED(hrIsCommon))
  1040. {
  1041. hr = CopyAudcapInfo (pDetails, pFmtBuf, 0);
  1042. if(!HR_SUCCEEDED(hr))
  1043. goto EXIT;
  1044. uNumOut++;
  1045. pFmtBuf++;
  1046. }
  1047. }
  1048. else // no remote capabilities exist because there is no current session
  1049. {
  1050. hr = CAPS_E_NOCAPS;
  1051. }
  1052. }
  1053. *uNumFmtOut = uNumOut;
  1054. EXIT:
  1055. return hr;
  1056. }
  1057. HRESULT CMsiaCapability::EnumFormats(PBASIC_AUDCAP_INFO pFmtBuf, UINT uBufsize,
  1058. UINT *uNumFmtOut)
  1059. {
  1060. UINT u;
  1061. HRESULT hr = hrSuccess;
  1062. AUDCAP_DETAILS *pDetails = pLocalFormats;
  1063. // validate input
  1064. if(!pFmtBuf || !uNumFmtOut || (uBufsize < (sizeof(BASIC_AUDCAP_INFO)*uNumLocalFormats)))
  1065. {
  1066. return CAPS_E_INVALID_PARAM;
  1067. }
  1068. if(!uNumLocalFormats || !pDetails)
  1069. {
  1070. return CAPS_E_NOCAPS;
  1071. }
  1072. for(u=0; (u <uNumLocalFormats) && (u <MAX_CAPS_PRESORT); u++)
  1073. {
  1074. pDetails = pLocalFormats + IDsByRank[u];
  1075. hr = CopyAudcapInfo (pDetails, pFmtBuf, 0);
  1076. if(!HR_SUCCEEDED(hr))
  1077. goto EXIT;
  1078. pFmtBuf++;
  1079. }
  1080. *uNumFmtOut = min(uNumLocalFormats, MAX_CAPS_PRESORT);
  1081. EXIT:
  1082. return hr;
  1083. }
  1084. HRESULT CMsiaCapability::GetBasicAudcapInfo (AUDIO_FORMAT_ID Id, PBASIC_AUDCAP_INFO pFormatPrefsBuf)
  1085. {
  1086. AUDCAP_DETAILS *pFmt;
  1087. UINT uIndex = IDToIndex(Id);
  1088. if(!pFormatPrefsBuf || (uNumLocalFormats <= uIndex))
  1089. {
  1090. return CAPS_E_INVALID_PARAM;
  1091. }
  1092. pFmt = pLocalFormats + uIndex;
  1093. return (CopyAudcapInfo(pFmt,pFormatPrefsBuf, 0));
  1094. }
  1095. HRESULT CMsiaCapability::ApplyAppFormatPrefs (PBASIC_AUDCAP_INFO pFormatPrefsBuf,
  1096. UINT uNumFormatPrefs)
  1097. {
  1098. FX_ENTRY ("CMsiaCapability::ApplyAppFormatPrefs");
  1099. UINT u, v;
  1100. PBASIC_AUDCAP_INFO pTemp;
  1101. AUDCAP_DETAILS *pFmt;
  1102. if(!pFormatPrefsBuf || (uNumLocalFormats != uNumFormatPrefs))
  1103. {
  1104. ERRORMESSAGE(("%s invalid param: pFbuf:0x%08lx, uNumIN:%d, uNum:%d\r\n",
  1105. _fx_, pFormatPrefsBuf, uNumFormatPrefs, uNumLocalFormats));
  1106. return CAPS_E_INVALID_PARAM;
  1107. }
  1108. // validate
  1109. for(u=0; u <uNumLocalFormats; u++)
  1110. {
  1111. pTemp = pFormatPrefsBuf+u;
  1112. // make sure that the format ID is real
  1113. if(IDToIndex(pTemp->Id) >= uNumLocalFormats)
  1114. {
  1115. return CAPS_E_INVALID_PARAM;
  1116. }
  1117. // look for bad sort indices, duplicate sort indices and duplicate format IDs
  1118. if(pTemp->wSortIndex >= uNumLocalFormats)
  1119. return CAPS_E_INVALID_PARAM;
  1120. for(v=u+1; v <uNumLocalFormats; v++)
  1121. {
  1122. if((pTemp->wSortIndex == pFormatPrefsBuf[v].wSortIndex)
  1123. || (pTemp->Id == pFormatPrefsBuf[v].Id))
  1124. {
  1125. ERRORMESSAGE(("%s invalid param: wSI1:0x%04x, wSI2:0x%04x, ID1:%d, ID2:%d\r\n",
  1126. _fx_, pTemp->wSortIndex, pFormatPrefsBuf[v].wSortIndex, pTemp->Id,
  1127. pFormatPrefsBuf[v].Id));
  1128. return CAPS_E_INVALID_PARAM;
  1129. }
  1130. }
  1131. }
  1132. // all seems well
  1133. for(u=0; u <uNumLocalFormats; u++)
  1134. {
  1135. pTemp = pFormatPrefsBuf+u; // next entry of the input
  1136. pFmt = pLocalFormats + IDToIndex(pTemp->Id); // identifies this local format
  1137. // apply the new sort order
  1138. pFmt->wApplicationPrefOrder = pTemp->wSortIndex;
  1139. // update the updatable parameters (CPU utilization, bitrate)
  1140. pFmt->bSendEnabled = pTemp->bSendEnabled;
  1141. pFmt->bRecvEnabled = pTemp->bRecvEnabled;
  1142. // only the tuning wizard or other profiling app can write these (via other apis only)
  1143. pFmt->wCPUUtilizationEncode = pTemp->wCPUUtilizationEncode;
  1144. pFmt->wCPUUtilizationDecode = pTemp->wCPUUtilizationDecode;
  1145. // pFmt->wApplicationPrefOrder = pTemp->wApplicationPrefOrder;
  1146. // pFmt->uAvgBitrate = pTemp->
  1147. // pFmt->wCompressionRatio = pTemp->
  1148. // update the registry
  1149. UpdateFormatInRegistry(pFmt);
  1150. // now update the sort order contained in IDsByRank
  1151. // note: recall that only MAX_CAPS_PRESORT are sorted and the rest are in random order.
  1152. // LOOKLOOK - maybe need a separate sort order array? - the order in IDsByRank
  1153. // is being overriden here
  1154. // the array holds the sorted indices into the array of formats in pLocalFormats
  1155. if(pTemp->wSortIndex < MAX_CAPS_PRESORT)
  1156. {
  1157. // insert the format at the position indicated by the input
  1158. IDsByRank[pTemp->wSortIndex] = (MEDIA_FORMAT_ID)(pFmt - pLocalFormats);
  1159. }
  1160. }
  1161. #ifdef DEBUG
  1162. for(u=0; u <uNumLocalFormats; u++) {
  1163. pTemp = pFormatPrefsBuf+u; // next entry of the input
  1164. pFmt = pLocalFormats + IDToIndex(pTemp->Id); // identifies this local format
  1165. DEBUGMSG (ZONE_ACM,("Format %s: Sort Index: %d\r\n",pTemp->szFormat,pTemp->wSortIndex));
  1166. }
  1167. #endif
  1168. return hrSuccess;
  1169. }
  1170. // update the registry
  1171. BOOL CMsiaCapability::UpdateFormatInRegistry(AUDCAP_DETAILS *pAudcapDetails)
  1172. {
  1173. FX_ENTRY(("CMsiaCapability::UpdateFormatInRegistry"));
  1174. LPTSTR lpszKeyName = NULL;
  1175. BOOL bRet;
  1176. UINT i;
  1177. if(!pAudcapDetails)
  1178. {
  1179. return FALSE;
  1180. }
  1181. //Update the CACHE info!!!
  1182. if (pRegFmts) {
  1183. for (i=0;i<pRegFmts->nFormats;i++) {
  1184. if (!lstrcmp (((AUDCAP_DETAILS *)pRegFmts->pData[i])->szFormat,pAudcapDetails->szFormat) &&
  1185. pAudcapDetails->audio_params.uSamplesPerSec == ((AUDCAP_DETAILS *)pRegFmts->pData[i])->audio_params.uSamplesPerSec &&
  1186. pAudcapDetails->audio_params.uBitsPerSample == ((AUDCAP_DETAILS *)pRegFmts->pData[i])->audio_params.uBitsPerSample &&
  1187. pAudcapDetails->uMaxBitrate == ((AUDCAP_DETAILS *)pRegFmts->pData[i])->uMaxBitrate) {
  1188. memcpy (pRegFmts->pData[i],pAudcapDetails,sizeof (AUDCAP_DETAILS));
  1189. break;
  1190. }
  1191. }
  1192. }
  1193. lpszKeyName = AllocRegistryKeyName( pAudcapDetails->szFormat,
  1194. pAudcapDetails->audio_params.uSamplesPerSec,
  1195. pAudcapDetails->audio_params.uBitsPerSample,
  1196. pAudcapDetails->uMaxBitrate);
  1197. if (!lpszKeyName)
  1198. {
  1199. ERRORMESSAGE(("%s:Alloc failed\r\n",_fx_));
  1200. return(FALSE);
  1201. }
  1202. DEBUGMSG(ZONE_ACM,("%s:updating %s, wPref:0x%04x, bS:%d, bR:%d\r\n",
  1203. _fx_, lpszKeyName, pAudcapDetails->wApplicationPrefOrder,
  1204. pAudcapDetails->bSendEnabled, pAudcapDetails->bRecvEnabled));
  1205. // add this to the registry
  1206. RegEntry reAudCaps(szRegInternetPhone TEXT("\\") szRegMSIPAndH323Encodings,
  1207. HKEY_LOCAL_MACHINE);
  1208. bRet = (ERROR_SUCCESS == reAudCaps.SetValue(lpszKeyName,
  1209. pAudcapDetails,
  1210. sizeof(AUDCAP_DETAILS)));
  1211. FreeRegistryKeyName(lpszKeyName);
  1212. return(bRet);
  1213. }
  1214. /***************************************************************************
  1215. Name : CMsiaCapability::AddFormatEnumHandler
  1216. Purpose : Enumerates the ACM formats for the case in which we want
  1217. to see all formats, and find the one we need. Used for installable
  1218. codecs when we want to find more info on the format being added
  1219. Parameters: Standard ACM EnumFormatCallback parameters
  1220. Returns : BOOL (somewhat upside down logic)
  1221. TRUE - not out format. keep calling.
  1222. FALSE - found our format. don't call anymore
  1223. Comment :
  1224. ***************************************************************************/
  1225. BOOL CMsiaCapability::AddFormatEnumHandler(HACMDRIVERID hadid,
  1226. LPACMFORMATDETAILS pafd, DWORD_PTR dwInstance, DWORD fdwSupport)
  1227. {
  1228. PACM_APP_PARAM pAppParam = (PACM_APP_PARAM) dwInstance;
  1229. LPWAVEFORMATEX lpwfx = pAppParam->lpwfx;
  1230. LPACMFORMATTAGDETAILS paftd = pAppParam->paftd;
  1231. AUDCAP_DETAILS *pAudcapDetails = pAppParam->pAudcapDetails;
  1232. BOOL bRet = TRUE;
  1233. if (pAppParam->hr == NOERROR)
  1234. {
  1235. // already got what we wanted
  1236. bRet = FALSE;
  1237. goto out;
  1238. }
  1239. // check to see if this is the format we're looking for
  1240. if ((lpwfx->cbSize != pafd->pwfx->cbSize) ||
  1241. !RtlEqualMemory(lpwfx, pafd->pwfx, sizeof(WAVEFORMATEX)+lpwfx->cbSize))
  1242. {
  1243. // not the one. out of here asap, but tell ACM to keep calling us
  1244. bRet = TRUE;
  1245. goto out;
  1246. }
  1247. // this is the format tag we're looking for
  1248. if (BuildFormatName(pAudcapDetails,
  1249. paftd->szFormatTag,
  1250. pafd->szFormat))
  1251. {
  1252. pAppParam->hr = NOERROR;
  1253. }
  1254. // either an error or we found what we want. tell ACM not to call us anymore
  1255. bRet = FALSE;
  1256. out:
  1257. return bRet;
  1258. }
  1259. /***************************************************************************
  1260. Name : NormalizeCPUUtilization
  1261. Purpose : Normalize CPU utilization numbers for an audio format
  1262. Parameters: pAudcapDetails [in/out] pointer to an AUDCAP_DETAILS structure
  1263. with the wCPUUtilizationEncode and wCPUUtilizationDecode
  1264. correctly initialized. These fields will be scaled in place
  1265. per the machine CPU.
  1266. Returns : FALSE for error
  1267. ***************************************************************************/
  1268. BOOL NormalizeCPUUtilization (PAUDCAP_DETAILS pAudcapDetails)
  1269. {
  1270. #define wCPUEncode pAudcapDetails->wCPUUtilizationEncode
  1271. #define wCPUDecode pAudcapDetails->wCPUUtilizationDecode
  1272. #define BASE_PENTIUM 90
  1273. int nNormalizedSpeed, iFamily=0;
  1274. if (!pAudcapDetails)
  1275. {
  1276. ASSERT(pAudcapDetails);
  1277. return FALSE;
  1278. }
  1279. #ifdef _M_IX86
  1280. GetNormalizedCPUSpeed (&nNormalizedSpeed,&iFamily);
  1281. #else
  1282. // profile the CPU on, say, an Alpha
  1283. // see ui\conf\audiocpl.cpp
  1284. iFamily=5;
  1285. nNormalizedSpeed=300;
  1286. #endif
  1287. // base is Pentium 90Mhz.
  1288. if (iFamily < 5)
  1289. { // 486 or below, inlcuding Cyrix parts
  1290. if (nNormalizedSpeed > 50)
  1291. { // Cyrix or friends. 1.5 the utilization of a P5-90. Make it so.
  1292. wCPUEncode += max(1, wCPUEncode / 2);
  1293. wCPUDecode += max(1, wCPUDecode / 2);
  1294. }
  1295. else
  1296. { // 486 is half a P5-90. This is not accurate, but good enough
  1297. wCPUEncode = max(1, wCPUEncode * 2);
  1298. wCPUDecode = max(1, wCPUDecode * 2);
  1299. }
  1300. }
  1301. else
  1302. { // it's a Pentium or TNGs
  1303. // nNormalizedSpeed ALREADY accounts for P-Pro and later families
  1304. wCPUEncode=max(1,((wCPUEncode*BASE_PENTIUM)/nNormalizedSpeed));
  1305. wCPUDecode=max(1,((wCPUDecode*BASE_PENTIUM)/nNormalizedSpeed));
  1306. }
  1307. // disable this format if encode utilization is too high
  1308. // we compare to 80%, since there's no QoS CPU utilization number at
  1309. // this point, and if there was, it would usually select 81%
  1310. if (wCPUEncode > 80)
  1311. pAudcapDetails->bSendEnabled = FALSE;
  1312. return TRUE;
  1313. }
  1314. /***************************************************************************
  1315. Name : CMsiaCapability::AddACMFormat
  1316. Purpose : Adds an ACM format to the list of formats we support
  1317. Parameters: lpwfx - pointer to the waveformat structure for the added codec
  1318. pAudCapInfo - additional format info that is not in the waveformat
  1319. structure
  1320. Returns : HRESULT
  1321. Comment :
  1322. ***************************************************************************/
  1323. HRESULT CMsiaCapability::AddACMFormat (LPWAVEFORMATEX lpwfx, PBASIC_AUDCAP_INFO pAudcapInfo)
  1324. {
  1325. HRESULT hr = hrSuccess;
  1326. // initialize cap entry with default values
  1327. AUDCAP_DETAILS cap_entry =
  1328. {WAVE_FORMAT_UNKNOWN, NONSTD_TERMCAP, STD_CHAN_PARAMS,
  1329. {RTP_DYNAMIC_MIN, 0, 8000, 16},
  1330. 0, TRUE, TRUE,
  1331. 960, // default number of samples per packet
  1332. 16000, // default to 16kbs bitrate
  1333. 0, // unknown average bitrate
  1334. 90, 90, // default CPU utilization
  1335. PREF_ORDER_UNASSIGNED, // unassigned sort order
  1336. 0,NULL,0,NULL,
  1337. ""};
  1338. ACM_APP_PARAM sAppParam = { this, &cap_entry, ACMAPP_FORMATENUMHANDLER_ADD,
  1339. lpwfx, NULL, CAPS_E_SYSTEM_ERROR, NULL};
  1340. /*
  1341. * Parameter validation
  1342. */
  1343. if (!lpwfx || !pAudcapInfo)
  1344. {
  1345. hr = CAPS_E_INVALID_PARAM;
  1346. goto out;
  1347. }
  1348. // nBlockAlign of 0 is illegal and will crash NAC
  1349. if (lpwfx->nBlockAlign == 0)
  1350. {
  1351. hr = CAPS_E_INVALID_PARAM;
  1352. goto out;
  1353. }
  1354. // only supporting formats with one audio channel
  1355. if (lpwfx->nChannels != 1)
  1356. {
  1357. hr = CAPS_E_INVALID_PARAM;
  1358. goto out;
  1359. }
  1360. /*
  1361. * Build the AUDCAP_DETALS structure for this format
  1362. */
  1363. // WAVEFORMAT info first
  1364. // fixup the bits per sample and sample rate fields of audio_params so that
  1365. // the key name can be built
  1366. cap_entry.audio_params.uSamplesPerSec = lpwfx->nSamplesPerSec;
  1367. cap_entry.audio_params.uBitsPerSample = MAKELONG(lpwfx->wBitsPerSample,0);
  1368. // fill in info given in lpwfx, calculate whatever parameters can be calculated
  1369. // use actual bits per sample unless the bps field is zero, in which case
  1370. // assume 16 bits (worst case).
  1371. cap_entry.wFormatTag = lpwfx->wFormatTag;
  1372. // now add in the caller AUDCAP_INFO information
  1373. CopyAudcapInfo(&cap_entry, pAudcapInfo, 1);
  1374. // normalize the encode and decode CPU utilization numbers
  1375. NormalizeCPUUtilization(&cap_entry);
  1376. // get the values we need to get from the WAVEFORMATEX structure
  1377. CalculateFormatProperties(&cap_entry, lpwfx);
  1378. // set the RTP payload number. We are using a random number from the dynamic range
  1379. // for the installable codecs
  1380. cap_entry.audio_params.RTPPayload = RTP_DYNAMIC_MIN;
  1381. // get ACM to enumerate all formats, and see if we can find this one
  1382. // this call will make ACM call into AddFormatEnumHandler, which will try to
  1383. // match formats returned by ACM with the added format, and if successful,
  1384. // will create a format name for it into cap_entry.szFormat;
  1385. if(!DriverEnum((DWORD_PTR) &sAppParam))
  1386. {
  1387. hr = CAPS_E_NOMATCH;
  1388. goto out;
  1389. }
  1390. if (HR_FAILED(sAppParam.hr))
  1391. {
  1392. ERRORMESSAGE(("CMsiaCapability::AddACMFormat: format enum problem\r\n"));
  1393. hr = CAPS_E_NOMATCH;
  1394. goto out;
  1395. }
  1396. // add this to the registry
  1397. if(!UpdateFormatInRegistry(&cap_entry))
  1398. {
  1399. ERRORMESSAGE(("CMsiaCapability::AddACMFormat: can't update registry\r\n"));
  1400. hr = CAPS_E_SYSTEM_ERROR;
  1401. goto out;
  1402. }
  1403. // free the old format cache...
  1404. FreeRegistryFormats(pRegFmts);
  1405. pRegFmts=NULL;
  1406. // reinit to update the list of local formats
  1407. if (!ReInit())
  1408. {
  1409. ERRORMESSAGE(("CMsiaCapability::AddACMFormat: Reinit failed\r\n"));
  1410. hr = CAPS_E_SYSTEM_ERROR;
  1411. goto out;
  1412. }
  1413. out:
  1414. return hr;
  1415. }
  1416. /***************************************************************************
  1417. Name : CMsiaCapability::RemoveACMFormat
  1418. Purpose : Removes an ACM format from the list of formats we support
  1419. Parameters: lpwfx - pointer to the waveformat structure for the added codec
  1420. Returns : HRESULT
  1421. Comment :
  1422. ***************************************************************************/
  1423. HRESULT CMsiaCapability::RemoveACMFormat (LPWAVEFORMATEX lpwfx)
  1424. {
  1425. HRESULT hr = hrSuccess;
  1426. HKEY hKey = NULL;
  1427. LPTSTR lpszValueName = NULL;
  1428. DWORD dwErr;
  1429. AUDCAP_DETAILS cap_entry;
  1430. ACM_APP_PARAM sAppParam = { this, &cap_entry, ACMAPP_FORMATENUMHANDLER_ADD,
  1431. lpwfx, NULL, CAPS_E_SYSTEM_ERROR, NULL};
  1432. /*
  1433. * Parameter validation
  1434. */
  1435. if(!lpwfx)
  1436. {
  1437. ERRORMESSAGE(("CMsiaCapability::RemoveACMFormat: NULL WAVEFORMAT pointer\r\n"));
  1438. return CAPS_E_INVALID_PARAM;
  1439. }
  1440. // nBlockAlign of 0 is illegal and will crash NAC
  1441. if (lpwfx->nBlockAlign == 0)
  1442. {
  1443. hr = CAPS_E_INVALID_PARAM;
  1444. goto out;
  1445. }
  1446. // only supporting formats with one audio channel
  1447. if (lpwfx->nChannels != 1)
  1448. {
  1449. hr = CAPS_E_INVALID_PARAM;
  1450. goto out;
  1451. }
  1452. /*
  1453. * Enumerate ACM formats
  1454. */
  1455. if(!DriverEnum((DWORD_PTR) &sAppParam))
  1456. {
  1457. ERRORMESSAGE(("CMsiaCapability::RemoveACMFormat: Couldn't find format\r\n"));
  1458. hr = CAPS_E_NOMATCH;
  1459. goto out;
  1460. }
  1461. if (HR_FAILED(sAppParam.hr))
  1462. {
  1463. ERRORMESSAGE(("CMsiaCapability::RemoveACMFormat: format enum problem\r\n"));
  1464. hr = CAPS_E_SYSTEM_ERROR;
  1465. goto out;
  1466. }
  1467. lpszValueName = AllocRegistryKeyName(cap_entry.szFormat,
  1468. lpwfx->nSamplesPerSec,
  1469. MAKELONG(lpwfx->wBitsPerSample,0),
  1470. lpwfx->nAvgBytesPerSec * 8);
  1471. if (!lpszValueName)
  1472. {
  1473. ERRORMESSAGE(("CMsiaCapability::RemoveACMFormat: Alloc failed\r\n"));
  1474. hr = CAPS_E_SYSTEM_ERROR;
  1475. goto out;
  1476. }
  1477. // Get the key handle
  1478. if (dwErr = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  1479. szRegInternetPhone TEXT("\\") szRegMSIPAndH323Encodings, 0,
  1480. KEY_ALL_ACCESS, &hKey))
  1481. {
  1482. ERRORMESSAGE(("CMsiaCapability::RemoveACMFormat: can't open key to delete\r\n"));
  1483. hr = CAPS_E_SYSTEM_ERROR;
  1484. goto out;
  1485. }
  1486. dwErr = RegDeleteValue(hKey, lpszValueName );
  1487. if(dwErr != ERROR_SUCCESS)
  1488. {
  1489. hr = CAPS_E_SYSTEM_ERROR;
  1490. goto out;
  1491. }
  1492. // free the old format cache...
  1493. FreeRegistryFormats(pRegFmts);
  1494. pRegFmts=NULL;
  1495. // reinit to update the list of local formats
  1496. if (!ReInit())
  1497. {
  1498. hr = CAPS_E_SYSTEM_ERROR;
  1499. goto out;
  1500. }
  1501. out:
  1502. if (hKey)
  1503. RegCloseKey(hKey);
  1504. if(lpszValueName)
  1505. MEMFREE(lpszValueName);
  1506. return hr;
  1507. }
  1508. HRESULT CMsiaCapability::SetCapIDBase (UINT uNewBase)
  1509. {
  1510. uCapIDBase = uNewBase;
  1511. UINT u;
  1512. for (u=0;u<uNumLocalFormats;u++)
  1513. {
  1514. pLocalFormats[u].H245TermCap.CapId = u + uCapIDBase;
  1515. }
  1516. return hrSuccess;
  1517. }
  1518. BOOL CMsiaCapability::IsHostForCapID(MEDIA_FORMAT_ID CapID)
  1519. {
  1520. if((CapID >= uCapIDBase) && ((CapID - uCapIDBase) < uNumLocalFormats))
  1521. return TRUE;
  1522. else
  1523. return FALSE;
  1524. }
  1525.