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.

1640 lines
51 KiB

  1. /*
  2. * File: capsctl.cpp
  3. *
  4. * capability control object implementations
  5. *
  6. *
  7. * Revision History:
  8. *
  9. * 10/10/96 mikeg created
  10. * 06/24/97 mikev - Added T.120 capability to serialized caps and simcaps (interim hack until a
  11. * T120 resolver is implemented)
  12. * - Retired ResolveEncodeFormat(Audio,Video) and implemented a data-independent
  13. * resolution algorithm and exposed method ResolveFormats(). Added support
  14. * routines ResolvePermutations(), TestSimultaneousCaps() and
  15. * AreSimcaps().
  16. */
  17. #include "precomp.h"
  18. UINT g_AudioPacketDurationMs = AUDIO_PACKET_DURATION_LONG; // preferred packet duration
  19. BOOL g_fRegAudioPacketDuration = FALSE; // AudioPacketDurationMs from registry
  20. PCC_TERMCAPDESCRIPTORS CapsCtl::pAdvertisedSets=NULL;
  21. DWORD CapsCtl::dwConSpeed = 0;
  22. UINT CapsCtl::uStaticGlobalRefCount=0;
  23. UINT CapsCtl::uAdvertizedSize=0;
  24. extern HRESULT WINAPI CreateMediaCapability(REFGUID, LPIH323MediaCap *);
  25. LPIH323MediaCap CapsCtl::FindHostForID(MEDIA_FORMAT_ID id)
  26. {
  27. if(pAudCaps && pAudCaps->IsHostForCapID(id))
  28. {
  29. return (pAudCaps);
  30. }
  31. else if (pVidCaps && pVidCaps->IsHostForCapID(id))
  32. {
  33. return (pVidCaps);
  34. }
  35. return NULL;
  36. }
  37. LPIH323MediaCap CapsCtl::FindHostForMediaType(PCC_TERMCAP pCapability)
  38. {
  39. if(pCapability->DataType == H245_DATA_AUDIO)
  40. {
  41. return (pAudCaps);
  42. }
  43. else if(pCapability->DataType == H245_DATA_VIDEO)
  44. {
  45. return (pVidCaps);
  46. }
  47. return NULL;
  48. }
  49. LPIH323MediaCap CapsCtl::FindHostForMediaGuid(LPGUID pMediaGuid)
  50. {
  51. if(MEDIA_TYPE_H323VIDEO == *pMediaGuid)
  52. {
  53. return (pVidCaps);
  54. }
  55. else if(MEDIA_TYPE_H323AUDIO == *pMediaGuid)
  56. {
  57. return (pAudCaps);
  58. }
  59. else
  60. return NULL;
  61. }
  62. ULONG CapsCtl::AddRef()
  63. {
  64. uRef++;
  65. return uRef;
  66. }
  67. ULONG CapsCtl::Release()
  68. {
  69. uRef--;
  70. if(uRef == 0)
  71. {
  72. delete this;
  73. return 0;
  74. }
  75. return uRef;
  76. }
  77. STDMETHODIMP CapsCtl::QueryInterface( REFIID iid, void ** ppvObject)
  78. {
  79. // this breaks the rules for the official COM QueryInterface because
  80. // the interfaces that are queried for are not necessarily real COM
  81. // interfaces. The reflexive property of QueryInterface would be broken in
  82. // that case.
  83. HRESULT hr = E_NOINTERFACE;
  84. if(!ppvObject)
  85. return hr;
  86. *ppvObject = 0;
  87. if(iid == IID_IDualPubCap)// satisfy symmetric property of QI
  88. {
  89. *ppvObject = (IDualPubCap *)this;
  90. hr = hrSuccess;
  91. AddRef();
  92. }
  93. else if(iid == IID_IAppAudioCap )
  94. {
  95. if(pAudCaps)
  96. {
  97. return pAudCaps->QueryInterface(iid, ppvObject);
  98. }
  99. }
  100. else if(iid == IID_IAppVidCap )
  101. {
  102. if(pVidCaps)
  103. {
  104. return pVidCaps->QueryInterface(iid, ppvObject);
  105. }
  106. }
  107. return hr;
  108. }
  109. CapsCtl::CapsCtl () :
  110. uRef(1),
  111. pVidCaps(NULL),
  112. pAudCaps(NULL),
  113. pACapsBuf(NULL),
  114. pVCapsBuf(NULL),
  115. dwNumInUse(0),
  116. bAudioPublicize(TRUE),
  117. bVideoPublicize(TRUE),
  118. bT120Publicize(TRUE),
  119. m_localT120cap(INVALID_MEDIA_FORMAT),
  120. m_remoteT120cap(INVALID_MEDIA_FORMAT),
  121. m_remoteT120bitrate(0),
  122. m_pAudTermCaps(NULL),
  123. m_pVidTermCaps(NULL),
  124. pSetIDs(NULL),
  125. pRemAdvSets(NULL)
  126. {
  127. uStaticGlobalRefCount++;
  128. }
  129. CapsCtl::~CapsCtl ()
  130. {
  131. if (pACapsBuf) {
  132. MemFree (pACapsBuf);
  133. }
  134. if (pVCapsBuf) {
  135. MemFree (pVCapsBuf);
  136. }
  137. if (pAudCaps) {
  138. pAudCaps->Release();
  139. }
  140. if (pVidCaps) {
  141. pVidCaps->Release();
  142. }
  143. uStaticGlobalRefCount--;
  144. if (uStaticGlobalRefCount == 0) {
  145. //Free up the sim. caps array
  146. if (pAdvertisedSets) {
  147. while (pAdvertisedSets->wLength) {
  148. //wLength is Zero based
  149. MemFree ((VOID *)pAdvertisedSets->pTermCapDescriptorArray[--pAdvertisedSets->wLength]);
  150. }
  151. MemFree ((VOID *)pAdvertisedSets->pTermCapDescriptorArray);
  152. pAdvertisedSets->pTermCapDescriptorArray = NULL;
  153. MemFree ((void *) pAdvertisedSets);
  154. pAdvertisedSets=NULL;
  155. dwNumInUse=0;
  156. }
  157. }
  158. //And the remote array
  159. if (pRemAdvSets) {
  160. while (pRemAdvSets->wLength) {
  161. MemFree ((VOID *)pRemAdvSets->pTermCapDescriptorArray[--pRemAdvSets->wLength]);
  162. }
  163. MemFree ((void *) pRemAdvSets->pTermCapDescriptorArray);
  164. pRemAdvSets->pTermCapDescriptorArray = NULL;
  165. MemFree ((void *) pRemAdvSets);
  166. pRemAdvSets=NULL;
  167. }
  168. MemFree (pSetIDs);
  169. pSetIDs=NULL;
  170. }
  171. BOOL CapsCtl::Init()
  172. {
  173. HRESULT hrLast;
  174. int iBase = 1;
  175. if (g_capFlags & CAPFLAGS_AV_STREAMS)
  176. {
  177. hrLast = ::CreateMediaCapability(MEDIA_TYPE_H323AUDIO, &pAudCaps);
  178. if(!HR_SUCCEEDED(hrLast))
  179. {
  180. goto InitDone;
  181. }
  182. }
  183. if (g_capFlags & CAPFLAGS_AV_STREAMS)
  184. {
  185. hrLast = ::CreateMediaCapability(MEDIA_TYPE_H323VIDEO, &pVidCaps);
  186. if(!HR_SUCCEEDED(hrLast))
  187. {
  188. goto InitDone;
  189. }
  190. }
  191. if (pAudCaps)
  192. {
  193. // Base the capability IDs beginning at 1 (zero is an invalid capability ID!)
  194. pAudCaps->SetCapIDBase(iBase);
  195. iBase += pAudCaps->GetNumCaps();
  196. }
  197. if (pVidCaps)
  198. {
  199. pVidCaps->SetCapIDBase(iBase);
  200. iBase += pVidCaps->GetNumCaps();
  201. }
  202. InitDone:
  203. m_localT120cap = iBase;
  204. return TRUE;
  205. }
  206. HRESULT CapsCtl::ReInitialize()
  207. {
  208. HRESULT hr = hrSuccess;
  209. int iBase = 1;
  210. if (pAudCaps && !pAudCaps->ReInit())
  211. {
  212. hr = CAPS_E_SYSTEM_ERROR;
  213. goto EXIT;
  214. }
  215. if (pVidCaps && !pVidCaps->ReInit())
  216. {
  217. hr = CAPS_E_SYSTEM_ERROR;
  218. goto EXIT;
  219. }
  220. // Base the capability IDs beginning at 1 (zero is an invalid capability ID!)
  221. if (pAudCaps)
  222. {
  223. pAudCaps->SetCapIDBase(iBase);
  224. iBase += pAudCaps->GetNumCaps();
  225. }
  226. if (pVidCaps)
  227. {
  228. pVidCaps->SetCapIDBase(iBase);
  229. iBase += pVidCaps->GetNumCaps();
  230. }
  231. m_localT120cap = iBase;
  232. EXIT:
  233. return hr;
  234. }
  235. const char szNMProdNum[] = "Microsoft\256 NetMeeting(TM)\0";
  236. const char szNM20VerNum[] = "Version 2.0\0";
  237. HRESULT CapsCtl::AddRemoteDecodeCaps(PCC_TERMCAPLIST pTermCapList,PCC_TERMCAPDESCRIPTORS pTermCapDescriptors, PCC_VENDORINFO pVendorInfo)
  238. {
  239. FX_ENTRY("CapsCtl::AddRemoteDecodeCaps");
  240. HRESULT hr;
  241. void *pData=NULL;
  242. UINT uSize,x,y,z;
  243. //WLength is # of capabilities, not structure length
  244. WORD wNDesc;
  245. LPIH323MediaCap pMediaCap;
  246. if(!pTermCapList && !pTermCapDescriptors) // additional capability descriptors may be added
  247. { // at any time
  248. return CAPS_E_INVALID_PARAM;
  249. }
  250. // Check for NM version 2.0
  251. m_fNM20 = FALSE;
  252. ASSERT(pVendorInfo);
  253. if (pVendorInfo->bCountryCode == USA_H221_COUNTRY_CODE
  254. && pVendorInfo->wManufacturerCode == MICROSOFT_H_221_MFG_CODE
  255. && pVendorInfo->pProductNumber && pVendorInfo->pVersionNumber
  256. && pVendorInfo->pProductNumber->wOctetStringLength == sizeof(szNMProdNum)
  257. && pVendorInfo->pVersionNumber->wOctetStringLength == sizeof(szNM20VerNum)
  258. && memcmp(pVendorInfo->pProductNumber->pOctetString, szNMProdNum, sizeof(szNMProdNum)) == 0
  259. && memcmp(pVendorInfo->pVersionNumber->pOctetString, szNM20VerNum, sizeof(szNM20VerNum)) == 0
  260. )
  261. {
  262. m_fNM20 = TRUE;
  263. }
  264. // cleanup old term caps if term caps are being added and old caps exist
  265. if (pAudCaps)
  266. pAudCaps->FlushRemoteCaps();
  267. if (pVidCaps)
  268. pVidCaps->FlushRemoteCaps();
  269. m_remoteT120cap = INVALID_MEDIA_FORMAT; // note there is no T120 cap resolver and
  270. // this CapsCtl holds exactly one local and remote T120 cap
  271. // Copy pTermcapDescriptors to a local copy, (and free any old one)
  272. if (pRemAdvSets) {
  273. while (pRemAdvSets->wLength) {
  274. //0 based
  275. MemFree ((VOID *)pRemAdvSets->pTermCapDescriptorArray[--pRemAdvSets->wLength]);
  276. }
  277. MemFree ((VOID *)pRemAdvSets->pTermCapDescriptorArray);
  278. pRemAdvSets->pTermCapDescriptorArray = NULL;
  279. MemFree ((VOID *)pRemAdvSets);
  280. pRemAdvSets=NULL;
  281. }
  282. //Ok, walk through the PCC_TERMCAPDESCRIPTORS list, first, allocate memory for the Master PCC_TERMCAPDESCRIPTORS
  283. //structure, then each simcap, and the altcaps therin, then copy the data.
  284. if (!(pRemAdvSets=(PCC_TERMCAPDESCRIPTORS) MemAlloc (sizeof (CC_TERMCAPDESCRIPTORS) ))){
  285. return CAPS_E_SYSTEM_ERROR;
  286. }
  287. //How many Descriptors?
  288. pRemAdvSets->wLength=pTermCapDescriptors->wLength;
  289. if (!(pRemAdvSets->pTermCapDescriptorArray=((H245_TOTCAPDESC_T **)MemAlloc (sizeof (H245_TOTCAPDESC_T*)*pTermCapDescriptors->wLength))) ) {
  290. return CAPS_E_SYSTEM_ERROR;
  291. }
  292. //Once per descriptor...
  293. for (x=0;x < pTermCapDescriptors->wLength;x++) {
  294. //Allocate memory for the descriptor entry
  295. if (!(pRemAdvSets->pTermCapDescriptorArray[x]=(H245_TOTCAPDESC_T *)MemAlloc (sizeof (H245_TOTCAPDESC_T)))) {
  296. return CAPS_E_SYSTEM_ERROR;
  297. }
  298. //BUGBUG for beta 2 Copy en masse.
  299. memcpy (pRemAdvSets->pTermCapDescriptorArray[x],pTermCapDescriptors->pTermCapDescriptorArray[x],sizeof (H245_TOTCAPDESC_T));
  300. /* post beta 2?
  301. //Copy the capability ID
  302. pRemAdvSets->pTermCapDescriptorArray[x].CapID=pTermCapDescriptors[x].CapID
  303. //Walk the simcaps, then altcaps and copy entries */
  304. }
  305. for (wNDesc=0;wNDesc <pTermCapList->wLength;wNDesc++) {
  306. pData=NULL;
  307. pMediaCap = FindHostForMediaType(pTermCapList->pTermCapArray[wNDesc]);
  308. if(!pMediaCap)
  309. {
  310. // special case: there is no T120 resolver. THIS IS A TEMPORARY
  311. // SITUATION. We cannot track bitrate limits on multiple T120 capability
  312. // instances because of this. As of now, we (NetMeeting) do not advertise
  313. // more than one T.120 capability.
  314. //This code will keep the last T.120 capability encountered.
  315. if(((pTermCapList->pTermCapArray[wNDesc])->DataType == H245_DATA_DATA)
  316. && ((pTermCapList->pTermCapArray[wNDesc])->Cap.H245Dat_T120.application.choice
  317. == DACy_applctn_t120_chosen)
  318. && ((pTermCapList->pTermCapArray[wNDesc])->Cap.H245Dat_T120.application.u.DACy_applctn_t120.choice
  319. == separateLANStack_chosen))
  320. {
  321. // it's data data
  322. m_remoteT120cap = (pTermCapList->pTermCapArray[wNDesc])->CapId;
  323. m_remoteT120bitrate =
  324. (pTermCapList->pTermCapArray[wNDesc])->Cap.H245Dat_T120.maxBitRate;
  325. }
  326. // continue;
  327. // handled it in-line
  328. }
  329. else if(pMediaCap->IsCapabilityRecognized(pTermCapList->pTermCapArray[wNDesc]))
  330. {
  331. hr = pMediaCap->AddRemoteDecodeFormat(pTermCapList->pTermCapArray[wNDesc]);
  332. #ifdef DEBUG
  333. if(!HR_SUCCEEDED(hr))
  334. {
  335. ERRORMESSAGE(("%s:AddRemoteDecodeFormat returned 0x%08lx\r\n",_fx_, hr));
  336. }
  337. #endif // DEBUG
  338. }
  339. }
  340. return (hrSuccess);
  341. }
  342. HRESULT CapsCtl::CreateCapList(PCC_TERMCAPLIST *ppCapBuf, PCC_TERMCAPDESCRIPTORS *ppCombinations)
  343. {
  344. PCC_TERMCAPLIST pTermCapList = NULL, pTermListAud=NULL, pTermListVid=NULL;
  345. PCC_TERMCAPDESCRIPTORS pCombinations;
  346. UINT uCount = 0, uSize = 0, uT120Size = 0;
  347. HRESULT hr;
  348. WORD wc;
  349. UINT x=0,y=0,z=0,uNumAud=0,uNumVid=0;
  350. H245_TOTCAPDESC_T *pTotCaps, **ppThisDescriptor;
  351. PPCC_TERMCAP ppCCThisTermCap;
  352. PCC_TERMCAP pCCT120Cap = NULL;
  353. uCount = GetNumCaps(TRUE);
  354. ASSERT((NULL == m_pAudTermCaps) && (NULL == m_pVidTermCaps));
  355. // calc size of CC_TERMCAPLIST header + CC_TERMCAPDESCRIPTORS + array of PCC_TERMCAP
  356. // allocate mem for the master CC_TERMCAPLIST, including the array of pointers to all CC_TERMCAPs
  357. uSize = sizeof(CC_TERMCAPLIST)
  358. + sizeof (CC_TERMCAPDESCRIPTORS) + (uCount * sizeof(PCC_TERMCAP));
  359. if((m_localT120cap != INVALID_MEDIA_FORMAT) && bT120Publicize)
  360. {
  361. uSize += sizeof(CC_TERMCAP);
  362. }
  363. pTermCapList = (PCC_TERMCAPLIST)MemAlloc(uSize);
  364. if(pTermCapList == NULL)
  365. {
  366. hr = CAPS_E_NOMEM;
  367. goto ERROR_EXIT;
  368. }
  369. // divide up the buffer, CC_TERMCAPLIST first, followed by array of PCC_TERMCAP.
  370. // The array of PCC_TERMCAP follows fixed size CC_TERMCAPLIST structure and the fixed size
  371. // CC_TERMCAP structure that holds the one T.120 cap.
  372. if((m_localT120cap != INVALID_MEDIA_FORMAT) && bT120Publicize)
  373. {
  374. pCCT120Cap = (PCC_TERMCAP)(((BYTE *)pTermCapList) + sizeof(CC_TERMCAPLIST));
  375. ppCCThisTermCap = (PPCC_TERMCAP) (((BYTE *)pTermCapList) + sizeof(CC_TERMCAPLIST) +
  376. sizeof(CC_TERMCAP));
  377. }
  378. else
  379. ppCCThisTermCap = (PPCC_TERMCAP) (((BYTE *)pTermCapList) + sizeof(CC_TERMCAPLIST));
  380. // allocate mem for the simultaneous caps
  381. // get size of cached advertised sets if it exists and more than one media
  382. // type is enabled for publication
  383. if(bAudioPublicize && bVideoPublicize && pAdvertisedSets)
  384. {
  385. // use size of cached buffer
  386. uSize = uAdvertizedSize;
  387. }
  388. else if (pAdvertisedSets)
  389. {
  390. // This case needs to be fixed. If media types are disabled, the simultaneous capability
  391. // descriptors in pAdvertisedSets should be rebuilt at that time. There should be no need to test
  392. // if(bAudioPublicize && bVideoPublicize && pAdvertisedSets)
  393. // calculate size of capability descriptors and simultaneous capability structures.
  394. #pragma message ("Figure out the size this needs to be...")
  395. #define NUMBER_TERMCAP_DESCRIPTORS 1
  396. uSize = sizeof(H245_TOTCAPDESC_T) * NUMBER_TERMCAP_DESCRIPTORS+
  397. sizeof (CC_TERMCAPDESCRIPTORS)+NUMBER_TERMCAP_DESCRIPTORS*
  398. sizeof (H245_TOTCAPDESC_T *);
  399. }
  400. else
  401. {
  402. uSize = 0;
  403. }
  404. if (uSize)
  405. {
  406. pCombinations = (PCC_TERMCAPDESCRIPTORS)MemAlloc(uSize);
  407. // skip the CC_TERMCAPDESCRIPTORS, which has a variable length array of (H245_TOTCAPDESC_T *) following it
  408. // the total size of that glob is uSimCapsSize
  409. // The actual array of [H245_TOTCAPDESC_T *] follows the CC_TERMCAPDESCRIPTORS structure
  410. // anchor the pCombinations->pTermCapDescriptorArray to this point.
  411. if(pCombinations == NULL)
  412. {
  413. hr = CAPS_E_NOMEM;
  414. goto ERROR_EXIT;
  415. }
  416. ppThisDescriptor = pCombinations->pTermCapDescriptorArray
  417. = (H245_TOTCAPDESC_T **)((BYTE *)pCombinations + sizeof(CC_TERMCAPDESCRIPTORS));
  418. // the first H245_TOTCAPDESC_T follows the array of [H245_TOTCAPDESC_T *]
  419. pTotCaps = (H245_TOTCAPDESC_T *)((BYTE *)ppThisDescriptor + pCombinations->wLength*sizeof(H245_TOTCAPDESC_T **));
  420. if(pAudCaps && bAudioPublicize)
  421. {
  422. hr=pAudCaps->CreateCapList((LPVOID *)&pTermListAud);
  423. if(!HR_SUCCEEDED(hr))
  424. goto ERROR_EXIT;
  425. ASSERT(pTermListAud != NULL);
  426. }
  427. if(pVidCaps && bVideoPublicize)
  428. {
  429. hr=pVidCaps->CreateCapList((LPVOID *)&pTermListVid);
  430. if(!HR_SUCCEEDED(hr))
  431. goto ERROR_EXIT;
  432. ASSERT(pTermListVid != NULL);
  433. }
  434. }
  435. else
  436. {
  437. pCombinations = NULL;
  438. }
  439. // fix pointers in the master caps list
  440. // Now need to fixup the CC_TERMCAPLIST to refer to the individual capabilities
  441. // Anchor the CC_TERMCAPLIST member pTermCapArray at the array of PCC_TERMCAP, and
  442. // start partying on the array.
  443. pTermCapList->wLength =0;
  444. pTermCapList->pTermCapArray = ppCCThisTermCap;
  445. if(pCCT120Cap)
  446. {
  447. *ppCCThisTermCap++ = pCCT120Cap;
  448. // set T120 capability parameters
  449. pCCT120Cap->DataType = H245_DATA_DATA;
  450. pCCT120Cap->ClientType = H245_CLIENT_DAT_T120;
  451. pCCT120Cap->Dir = H245_CAPDIR_LCLRXTX;
  452. pCCT120Cap->Cap.H245Dat_T120.application.choice = DACy_applctn_t120_chosen;
  453. pCCT120Cap->Cap.H245Dat_T120.application.u.DACy_applctn_t120.choice= separateLANStack_chosen;
  454. pCCT120Cap->Cap.H245Dat_T120.maxBitRate = dwConSpeed;
  455. pCCT120Cap->CapId = (H245_CAPID_T)m_localT120cap;
  456. pTermCapList->wLength++;
  457. }
  458. if(pAudCaps && pTermListAud)
  459. {
  460. for(wc = 0; wc < pTermListAud->wLength; wc++)
  461. {
  462. // copy the array of "pointers to CC_TERMCAP"
  463. *ppCCThisTermCap++ = pTermListAud->pTermCapArray[wc];
  464. pTermCapList->wLength++;
  465. }
  466. }
  467. if(pVidCaps && pTermListVid)
  468. {
  469. for(wc = 0; wc < pTermListVid->wLength; wc++)
  470. {
  471. // copy the array of "pointers to CC_TERMCAP"
  472. *ppCCThisTermCap++ = pTermListVid->pTermCapArray[wc];
  473. pTermCapList->wLength++;
  474. }
  475. }
  476. // fixup the simultaneous capability descriptors
  477. // Create a default set if necessary
  478. //
  479. if(bAudioPublicize && bVideoPublicize && pAdvertisedSets)
  480. {
  481. pCombinations->wLength = pAdvertisedSets->wLength;
  482. // point pCombinations->pTermCapDescriptorArray past the header (CC_TERMCAPDESCRIPTORS)
  483. pCombinations->pTermCapDescriptorArray
  484. = (H245_TOTCAPDESC_T **)((BYTE *)pCombinations + sizeof(CC_TERMCAPDESCRIPTORS));
  485. // the first H245_TOTCAPDESC_T follows the array of [H245_TOTCAPDESC_T *]
  486. pTotCaps = (H245_TOTCAPDESC_T *)((BYTE *)pCombinations->pTermCapDescriptorArray +
  487. pAdvertisedSets->wLength*sizeof(H245_TOTCAPDESC_T **));
  488. for(x = 0; x < pAdvertisedSets->wLength; x++)
  489. {
  490. // write into the array of descriptor pointers. pointer[x] = this one
  491. pCombinations->pTermCapDescriptorArray[x] = pTotCaps;
  492. pTotCaps->CapDescId= pAdvertisedSets->pTermCapDescriptorArray[x]->CapDescId;
  493. pTotCaps->CapDesc.Length=pAdvertisedSets->pTermCapDescriptorArray[x]->CapDesc.Length;
  494. for(y = 0; y < pTotCaps->CapDesc.Length;y++)
  495. {
  496. //Copy the length field.
  497. pTotCaps->CapDesc.SimCapArray[y].Length=
  498. pAdvertisedSets->pTermCapDescriptorArray[x]->CapDesc.SimCapArray[y].Length;
  499. for(z=0;
  500. z < pAdvertisedSets->pTermCapDescriptorArray[x]->CapDesc.SimCapArray[y].Length;
  501. z++)
  502. {
  503. pTotCaps->CapDesc.SimCapArray[y].AltCaps[z] =
  504. pAdvertisedSets->pTermCapDescriptorArray[x]->CapDesc.SimCapArray[y].AltCaps[z];
  505. }
  506. }
  507. pTotCaps++;
  508. }
  509. }
  510. else if (pAdvertisedSets)
  511. {
  512. // descriptors in pAdvertisedSets should be rebuilt at that time. There should be no need to test
  513. // if(bAudioPublicize && bVideoPublicize && pAdvertisedSets)
  514. // HACK - put all audio or video caps in one AltCaps[], the T.120 cap in another AltCaps[]
  515. // and put both of those in one single capability descriptor (H245_TOTCAPDESC_T)
  516. // This hack will not extend past the assumption of one audio channel, one video channel, and
  517. // one T.120 channel. If arbitrary media is supported, or multiple audio channels are supported,
  518. // this code will be wrong
  519. pCombinations->wLength=1;
  520. // point pCombinations->pTermCapDescriptorArray past the header (CC_TERMCAPDESCRIPTORS)
  521. pCombinations->pTermCapDescriptorArray
  522. = (H245_TOTCAPDESC_T **)((BYTE *)pCombinations + sizeof(CC_TERMCAPDESCRIPTORS));
  523. // the first H245_TOTCAPDESC_T follows the array of [H245_TOTCAPDESC_T *]
  524. pTotCaps = (H245_TOTCAPDESC_T *)((BYTE *)pCombinations->pTermCapDescriptorArray +
  525. pAdvertisedSets->wLength*sizeof(H245_TOTCAPDESC_T **));
  526. pTotCaps->CapDescId=(H245_CAPDESCID_T)x;
  527. pTotCaps->CapDesc.Length=0;
  528. if(pTermListAud)
  529. {
  530. uNumAud = min(pTermListAud->wLength, H245_MAX_ALTCAPS);
  531. pTotCaps->CapDesc.SimCapArray[x].Length=(unsigned short)uNumAud;
  532. for(y = 0; y<uNumAud;y++)
  533. {
  534. pTotCaps->CapDesc.SimCapArray[x].AltCaps[y] = pTermListAud->pTermCapArray[y]->CapId;
  535. }
  536. x++;
  537. pTotCaps->CapDesc.Length++;
  538. }
  539. if(pTermListVid && pTermListVid->wLength)
  540. {
  541. uNumVid = min(pTermListVid->wLength, H245_MAX_ALTCAPS);
  542. pTotCaps->CapDesc.SimCapArray[x].Length=(unsigned short)uNumVid;
  543. for(y = 0; y<uNumVid;y++)
  544. {
  545. pTotCaps->CapDesc.SimCapArray[x].AltCaps[y] = pTermListVid->pTermCapArray[y]->CapId;
  546. }
  547. x++;
  548. pTotCaps->CapDesc.Length++;
  549. }
  550. // the T.120 cap
  551. if((m_localT120cap != INVALID_MEDIA_FORMAT) && bT120Publicize)
  552. {
  553. pTotCaps->CapDesc.SimCapArray[x].Length=1;
  554. pTotCaps->CapDesc.SimCapArray[x].AltCaps[0] = (H245_CAPID_T)m_localT120cap;
  555. pTotCaps->CapDesc.Length++;
  556. }
  557. // write into the array of descriptor pointers. pointer[x] = this one
  558. *ppThisDescriptor = pTotCaps;
  559. }
  560. m_pVidTermCaps = pTermListVid;
  561. m_pAudTermCaps = pTermListAud;
  562. *ppCapBuf = pTermCapList;
  563. *ppCombinations = pCombinations;
  564. return hrSuccess;
  565. ERROR_EXIT:
  566. m_pAudTermCaps = NULL;
  567. m_pVidTermCaps = NULL;
  568. if(pTermCapList)
  569. MemFree(pTermCapList);
  570. if(pCombinations)
  571. MemFree(pCombinations);
  572. if(pAudCaps && pTermListAud)
  573. {
  574. hr=pAudCaps->DeleteCapList(pTermListAud);
  575. }
  576. if(pVidCaps && pTermListVid)
  577. {
  578. hr=pVidCaps->DeleteCapList(pTermListVid);
  579. }
  580. return hr;
  581. }
  582. HRESULT CapsCtl::DeleteCapList(PCC_TERMCAPLIST pCapBuf, PCC_TERMCAPDESCRIPTORS pCombinations)
  583. {
  584. MemFree(pCapBuf);
  585. MemFree(pCombinations);
  586. if(m_pAudTermCaps && pAudCaps)
  587. {
  588. pAudCaps->DeleteCapList(m_pAudTermCaps);
  589. }
  590. if(m_pVidTermCaps)
  591. {
  592. pVidCaps->DeleteCapList(m_pVidTermCaps);
  593. }
  594. m_pAudTermCaps = NULL;
  595. m_pVidTermCaps = NULL;
  596. return hrSuccess;
  597. }
  598. HRESULT CapsCtl::GetEncodeParams(LPVOID pBufOut, UINT uBufSize,LPVOID pLocalParams, UINT uLocalSize,DWORD idRemote, DWORD idLocal)
  599. {
  600. LPIH323MediaCap pMediaCap = FindHostForID(idLocal);
  601. if(!pMediaCap)
  602. return CAPS_E_INVALID_PARAM;
  603. // HACK
  604. // Adjust audio packetization depending on call scenario
  605. // unless there is an overriding registry setting
  606. if (pMediaCap == pAudCaps)
  607. {
  608. VIDEO_FORMAT_ID vidLocal=INVALID_MEDIA_FORMAT, vidRemote=INVALID_MEDIA_FORMAT;
  609. VIDEO_CHANNEL_PARAMETERS vidParams;
  610. CC_TERMCAP vidCaps;
  611. UINT audioPacketLength;
  612. // modify the audio packetization parameters based on local bandwidth
  613. // and presence of video
  614. audioPacketLength = AUDIO_PACKET_DURATION_LONG;
  615. // the registry setting overrides, if it is present
  616. if (g_fRegAudioPacketDuration)
  617. audioPacketLength = g_AudioPacketDurationMs;
  618. else if (!m_fNM20) // dont try smaller packets for NM20 because it cant handle them
  619. {
  620. if (pVidCaps && pVidCaps->ResolveEncodeFormat(&vidLocal,&vidRemote) == S_OK
  621. && (pVidCaps->GetEncodeParams(&vidCaps,sizeof(vidCaps), &vidParams, sizeof(vidParams), vidRemote, vidLocal) == S_OK))
  622. {
  623. // we may potentially send video
  624. if (vidParams.ns_params.maxBitRate*100 > BW_ISDN_BITS)
  625. audioPacketLength = AUDIO_PACKET_DURATION_SHORT;
  626. }
  627. else
  628. {
  629. // no video
  630. // since we dont know the actual connection bandwidth we use
  631. // the local user setting.
  632. // Note: if the remote is on a slow-speed net and the local is on a LAN
  633. // we may end up with an inappropriate setting.
  634. if (dwConSpeed > BW_288KBS_BITS)
  635. audioPacketLength = AUDIO_PACKET_DURATION_SHORT;
  636. else if (dwConSpeed > BW_144KBS_BITS)
  637. audioPacketLength = AUDIO_PACKET_DURATION_MEDIUM;
  638. }
  639. }
  640. // Setting the AudioPacketDurationMs affects the subsequent GetEncodeParams call
  641. pMediaCap->SetAudioPacketDuration(audioPacketLength);
  642. }
  643. return pMediaCap->GetEncodeParams (pBufOut,uBufSize, pLocalParams,
  644. uLocalSize,idRemote,idLocal);
  645. }
  646. HRESULT CapsCtl::GetPublicDecodeParams(LPVOID pBufOut, UINT uBufSize, VIDEO_FORMAT_ID id)
  647. {
  648. LPIH323MediaCap pMediaCap = FindHostForID(id);
  649. if(!pMediaCap)
  650. return CAPS_E_INVALID_PARAM;
  651. return pMediaCap->GetPublicDecodeParams (pBufOut,uBufSize,id);
  652. }
  653. HRESULT CapsCtl::GetDecodeParams(PCC_RX_CHANNEL_REQUEST_CALLBACK_PARAMS pChannelParams,DWORD * pFormatID, LPVOID lpvBuf, UINT uBufSize)
  654. {
  655. LPIH323MediaCap pMediaCap = FindHostForMediaType(pChannelParams->pChannelCapability);
  656. if(!pMediaCap)
  657. return CAPS_E_INVALID_PARAM;
  658. return pMediaCap->GetDecodeParams (pChannelParams,pFormatID,lpvBuf,uBufSize);
  659. }
  660. HRESULT CapsCtl::ResolveToLocalFormat(MEDIA_FORMAT_ID FormatIDLocal,
  661. MEDIA_FORMAT_ID * pFormatIDRemote)
  662. {
  663. LPIH323MediaCap pMediaCap = FindHostForID(FormatIDLocal);
  664. if(!pMediaCap)
  665. return CAPS_E_INVALID_PARAM;
  666. return pMediaCap->ResolveToLocalFormat (FormatIDLocal,pFormatIDRemote);
  667. }
  668. UINT CapsCtl::GetSimCapBufSize (BOOL bRxCaps)
  669. {
  670. UINT uSize;
  671. // get size of cached advertised sets if it exists and more than one media
  672. // type is enabled for publication
  673. if(bAudioPublicize && bVideoPublicize && pAdvertisedSets)
  674. {
  675. // use size of cached buffer
  676. uSize = uAdvertizedSize;
  677. }
  678. else
  679. {
  680. // calculate size of capability descriptors and simultaneous capability structures.
  681. #pragma message ("Figure out the size this needs to be...")
  682. #define NUMBER_TERMCAP_DESCRIPTORS 1
  683. uSize = sizeof(H245_TOTCAPDESC_T) * NUMBER_TERMCAP_DESCRIPTORS+
  684. sizeof (CC_TERMCAPDESCRIPTORS)+NUMBER_TERMCAP_DESCRIPTORS*
  685. sizeof (H245_TOTCAPDESC_T *);
  686. }
  687. return uSize;
  688. }
  689. UINT CapsCtl::GetNumCaps(BOOL bRXCaps)
  690. {
  691. UINT u=0;
  692. if(pAudCaps && bAudioPublicize)
  693. {
  694. u = pAudCaps->GetNumCaps(bRXCaps);
  695. }
  696. if(pVidCaps && bVideoPublicize)
  697. {
  698. u += pVidCaps->GetNumCaps(bRXCaps);
  699. }
  700. if(bT120Publicize)
  701. u++;
  702. return u;
  703. }
  704. UINT CapsCtl::GetLocalSendParamSize(MEDIA_FORMAT_ID dwID)
  705. {
  706. LPIH323MediaCap pMediaCap = FindHostForID(dwID);
  707. if(!pMediaCap)
  708. return 0;
  709. return (pMediaCap->GetLocalSendParamSize(dwID));
  710. }
  711. UINT CapsCtl::GetLocalRecvParamSize(PCC_TERMCAP pCapability)
  712. {
  713. LPIH323MediaCap pMediaCap = FindHostForMediaType(pCapability);
  714. if(!pMediaCap)
  715. return 0;
  716. return (pMediaCap->GetLocalRecvParamSize(pCapability));
  717. }
  718. STDMETHODIMP CapsCtl::GetEncodeFormatDetails(MEDIA_FORMAT_ID FormatID, VOID **ppFormat, UINT *puSize)
  719. {
  720. LPIH323MediaCap pMediaCap = FindHostForID(FormatID);
  721. if(!pMediaCap)
  722. {
  723. *ppFormat = NULL;
  724. *puSize = 0;
  725. return E_INVALIDARG;
  726. }
  727. return pMediaCap->GetEncodeFormatDetails (FormatID, ppFormat, puSize);
  728. }
  729. STDMETHODIMP CapsCtl::GetDecodeFormatDetails(MEDIA_FORMAT_ID FormatID, VOID **ppFormat, UINT *puSize)
  730. {
  731. LPIH323MediaCap pMediaCap = FindHostForID(FormatID);
  732. if(!pMediaCap)
  733. {
  734. *ppFormat = NULL;
  735. *puSize = 0;
  736. return E_INVALIDARG;
  737. }
  738. return pMediaCap->GetDecodeFormatDetails (FormatID, ppFormat, puSize);
  739. }
  740. //
  741. // EnableMediaType controls whether or not capabilities for that media type
  742. // are publicized. In a general implementation (next version?) w/ arbitrary
  743. // number of media types, each of the media capability objects would keep
  744. // track of their own state. This version of Capsctl tracks h323 audio and
  745. // video only
  746. //
  747. HRESULT CapsCtl::EnableMediaType(BOOL bEnable, LPGUID pGuid)
  748. {
  749. if(!pGuid)
  750. return CAPS_E_INVALID_PARAM;
  751. if(*pGuid == MEDIA_TYPE_H323AUDIO)
  752. {
  753. bAudioPublicize = bEnable;
  754. }
  755. else if (*pGuid == MEDIA_TYPE_H323VIDEO)
  756. {
  757. bVideoPublicize = bEnable;
  758. }
  759. else
  760. {
  761. return CAPS_E_INVALID_PARAM;
  762. }
  763. return hrSuccess;
  764. }
  765. //
  766. // Build the PCC_TERMCAPDESCRIPTORS list that we will advertise.
  767. //
  768. // puAudioFormatList/puVideoFormatList MUST BE sorted by preference!
  769. //
  770. //
  771. HRESULT CapsCtl::AddCombinedEntry (MEDIA_FORMAT_ID *puAudioFormatList,UINT uAudNumEntries,MEDIA_FORMAT_ID *puVideoFormatList, UINT uVidNumEntries,DWORD *pIDOut)
  772. {
  773. static USHORT dwLastIDUsed;
  774. DWORD x,y;
  775. BOOL bAllEnabled=TRUE,bRecv,bSend;
  776. unsigned short Length =0;
  777. *pIDOut= (ULONG )CCO_E_SYSTEM_ERROR;
  778. //Validate the Input
  779. if ((!puAudioFormatList && uAudNumEntries > 0 ) || (!puVideoFormatList && uVidNumEntries > 0 ) || (uVidNumEntries == 0 && uAudNumEntries == 0 )) {
  780. //What error code should we return here?
  781. return CCO_E_SYSTEM_ERROR;
  782. }
  783. for (x=0;x<uAudNumEntries;x++)
  784. {
  785. ASSERT(pAudCaps);
  786. pAudCaps->IsFormatEnabled (puAudioFormatList[x],&bRecv,&bSend);
  787. bAllEnabled &= bRecv;
  788. }
  789. for (x=0;x<uVidNumEntries;x++) {
  790. ASSERT(pVidCaps);
  791. pVidCaps->IsFormatEnabled (puAudioFormatList[x],&bRecv,&bSend);
  792. bAllEnabled &= bRecv;
  793. }
  794. if (!bAllEnabled) {
  795. return CCO_E_INVALID_PARAM;
  796. }
  797. if (uAudNumEntries > H245_MAX_ALTCAPS || uVidNumEntries > H245_MAX_ALTCAPS) {
  798. DEBUGMSG (1,("WARNING: Exceeding callcontrol limits!! \r\n"));
  799. return CCO_E_INVALID_PARAM;
  800. }
  801. //If this is the first call, allocate space
  802. if (!pAdvertisedSets){
  803. pAdvertisedSets=(PCC_TERMCAPDESCRIPTORS)MemAlloc (sizeof (CC_TERMCAPDESCRIPTORS));
  804. if (!pAdvertisedSets){
  805. //Error code?
  806. return CCO_E_SYSTEM_ERROR;
  807. }
  808. uAdvertizedSize = sizeof (CC_TERMCAPDESCRIPTORS);
  809. //Allocate space of NUM_SIMCAP_SETS
  810. pAdvertisedSets->pTermCapDescriptorArray=(H245_TOTCAPDESC_T **)
  811. MemAlloc (sizeof (H245_TOTCAPDESC_T *)*NUM_SIMCAP_SETS);
  812. if (!pAdvertisedSets->pTermCapDescriptorArray) {
  813. //Error code?
  814. return CCO_E_SYSTEM_ERROR;
  815. }
  816. //Update the indicies
  817. uAdvertizedSize += sizeof (H245_TOTCAPDESC_T *)*NUM_SIMCAP_SETS;
  818. dwNumInUse=NUM_SIMCAP_SETS;
  819. pAdvertisedSets->wLength=0;
  820. }
  821. //Find an Index to use.
  822. for (x=0;x<pAdvertisedSets->wLength;x++){
  823. if (pAdvertisedSets->pTermCapDescriptorArray[x] == NULL){
  824. break;
  825. }
  826. }
  827. //Did we find space, or do we need a new one?
  828. if (x >= dwNumInUse) {
  829. //Increment the number in use
  830. dwNumInUse++;
  831. PVOID pTempTermCapDescriptorArray = NULL;
  832. pTempTermCapDescriptorArray = MemReAlloc(pAdvertisedSets->pTermCapDescriptorArray, sizeof(H245_TOTCAPDESC_T *)*(dwNumInUse));
  833. if(pTempTermCapDescriptorArray)
  834. {
  835. pAdvertisedSets->pTermCapDescriptorArray = (H245_TOTCAPDESC_T **)pTempTermCapDescriptorArray;
  836. }
  837. else
  838. {
  839. return CCO_E_SYSTEM_ERROR;
  840. }
  841. uAdvertizedSize += (sizeof (H245_TOTCAPDESC_T *)*(dwNumInUse))+sizeof (CC_TERMCAPDESCRIPTORS);
  842. //Index is 0 based, point at the new entry
  843. x=dwNumInUse-1;
  844. }
  845. //x is now the element we are using. Allocate space for a TermCapDescriptorArray
  846. pAdvertisedSets->pTermCapDescriptorArray[x]=(H245_TOTCAPDESC_T *)MemAlloc (sizeof (H245_TOTCAPDESC_T));
  847. if (!pAdvertisedSets->pTermCapDescriptorArray[x]){
  848. return CCO_E_SYSTEM_ERROR;
  849. }
  850. uAdvertizedSize += sizeof (H245_TOTCAPDESC_T);
  851. //Need to update the SetID. (start at 1)...
  852. pAdvertisedSets->pTermCapDescriptorArray[x]->CapDescId=++dwLastIDUsed;
  853. //Set the # of sets
  854. if((m_localT120cap != INVALID_MEDIA_FORMAT) && bT120Publicize)
  855. Length++;
  856. if(uVidNumEntries)
  857. Length++;
  858. if(uAudNumEntries)
  859. Length++;
  860. pAdvertisedSets->pTermCapDescriptorArray[x]->CapDesc.Length= Length;
  861. //Copy the Audio into SimCapArray[0], Video into SimCapArray[1] (if both)
  862. if ((uVidNumEntries > 0 && uAudNumEntries > 0)) {
  863. pAdvertisedSets->pTermCapDescriptorArray[x]->CapDesc.SimCapArray[0].Length=(unsigned short)uAudNumEntries;
  864. pAdvertisedSets->pTermCapDescriptorArray[x]->CapDesc.SimCapArray[1].Length=(unsigned short)uVidNumEntries;
  865. if((m_localT120cap != INVALID_MEDIA_FORMAT) && bT120Publicize)
  866. pAdvertisedSets->pTermCapDescriptorArray[x]->CapDesc.SimCapArray[2].Length=1;
  867. //Copy the format IDs
  868. for (y=0;y<uAudNumEntries;y++) {
  869. pAdvertisedSets->pTermCapDescriptorArray[x]->CapDesc.SimCapArray[0].AltCaps[y]=(USHORT)puAudioFormatList[y];
  870. }
  871. for (y=0;y<uVidNumEntries;y++) {
  872. pAdvertisedSets->pTermCapDescriptorArray[x]->CapDesc.SimCapArray[1].AltCaps[y]=(USHORT)puVideoFormatList[y];
  873. }
  874. if((m_localT120cap != INVALID_MEDIA_FORMAT) && bT120Publicize)
  875. pAdvertisedSets->pTermCapDescriptorArray[x]->CapDesc.SimCapArray[2].AltCaps[0]= (H245_CAPID_T)m_localT120cap;
  876. } else {
  877. if (uAudNumEntries > 0) {
  878. pAdvertisedSets->pTermCapDescriptorArray[x]->CapDesc.SimCapArray[0].Length=(unsigned short)uAudNumEntries;
  879. if((m_localT120cap != INVALID_MEDIA_FORMAT) && bT120Publicize)
  880. pAdvertisedSets->pTermCapDescriptorArray[x]->CapDesc.SimCapArray[1].Length=1;
  881. //Copy Audio only
  882. for (y=0;y<uAudNumEntries;y++) {
  883. pAdvertisedSets->pTermCapDescriptorArray[x]->CapDesc.SimCapArray[0].AltCaps[y]=(USHORT)puAudioFormatList[y];
  884. }
  885. if((m_localT120cap != INVALID_MEDIA_FORMAT) && bT120Publicize)
  886. pAdvertisedSets->pTermCapDescriptorArray[x]->CapDesc.SimCapArray[1].AltCaps[0]= (H245_CAPID_T)m_localT120cap;
  887. } else {
  888. pAdvertisedSets->pTermCapDescriptorArray[x]->CapDesc.SimCapArray[0].Length=(unsigned short)uVidNumEntries;
  889. if((m_localT120cap != INVALID_MEDIA_FORMAT) && bT120Publicize)
  890. pAdvertisedSets->pTermCapDescriptorArray[x]->CapDesc.SimCapArray[1].Length=1;
  891. //copy video entries
  892. for (y=0;y<uVidNumEntries;y++) {
  893. pAdvertisedSets->pTermCapDescriptorArray[x]->CapDesc.SimCapArray[0].AltCaps[y]=(USHORT)puVideoFormatList[y];
  894. }
  895. if((m_localT120cap != INVALID_MEDIA_FORMAT) && bT120Publicize)
  896. pAdvertisedSets->pTermCapDescriptorArray[x]->CapDesc.SimCapArray[1].AltCaps[0]= (H245_CAPID_T)m_localT120cap;
  897. }
  898. }
  899. //Need to update the wLength
  900. pAdvertisedSets->wLength++;
  901. *pIDOut=dwLastIDUsed;
  902. return hrSuccess;
  903. }
  904. HRESULT CapsCtl::RemoveCombinedEntry (DWORD ID)
  905. {
  906. DWORD x;
  907. if (!pAdvertisedSets) {
  908. return CAPS_E_INVALID_PARAM;
  909. }
  910. for (x=0;x<dwNumInUse;x++) {
  911. if (pAdvertisedSets->pTermCapDescriptorArray[x]) {
  912. if (pAdvertisedSets->pTermCapDescriptorArray[x]->CapDescId == ID) {
  913. //Found the one to remove
  914. MemFree ((VOID *)pAdvertisedSets->pTermCapDescriptorArray[x]);
  915. uAdvertizedSize -= sizeof (H245_TOTCAPDESC_T *);
  916. if (x != (dwNumInUse -1)) {
  917. //Not the last one, swap the two pointers
  918. pAdvertisedSets->pTermCapDescriptorArray[x]=pAdvertisedSets->pTermCapDescriptorArray[dwNumInUse-1];
  919. pAdvertisedSets->pTermCapDescriptorArray[dwNumInUse-1]=NULL;
  920. }
  921. //Decrement the number in use, and set the wLengthField
  922. dwNumInUse--;
  923. pAdvertisedSets->wLength--;
  924. return hrSuccess;
  925. }
  926. }
  927. }
  928. //Shouldn't get here, unless it was not found.
  929. return CAPS_E_NOCAPS;
  930. }
  931. // Given a sized list of capability IDs (pointer to array of H245_CAPID_T)
  932. // and a sized list of alternate capabilities (AltCaps) within a single simultaneous
  933. // capability set, (pointer to an array of pointers to H245_SIMCAP_T)
  934. // Determine if the entire list of capability IDs can simultaneously coexist
  935. // with respect to the given set of AltCaps.
  936. BOOL CapsCtl::AreSimCaps(
  937. H245_CAPID_T* pIDArray, UINT uIDArraySize,
  938. H245_SIMCAP_T **ppAltCapArray,UINT uAltCapArraySize)
  939. {
  940. UINT i, u;
  941. SHORT j;
  942. BOOL bSim;
  943. H245_SIMCAP_T *pAltCapEntry, *pFirstAltCapEntry;
  944. // If there are fewer AltCaps than capabilities, doom is obvious. Don't bother searching.
  945. if(uAltCapArraySize < uIDArraySize)
  946. return FALSE;
  947. // find an altcaps entry containing the first ID in the list
  948. for (i=0;i<uAltCapArraySize;i++)
  949. {
  950. pAltCapEntry = *(ppAltCapArray+i);
  951. // scan this altcaps entry for a matching ID
  952. for(j=0;j<pAltCapEntry->Length;j++)
  953. {
  954. if(*pIDArray == pAltCapEntry->AltCaps[j])
  955. {
  956. // found a spot for this capability!
  957. if(uIDArraySize ==1)
  958. return TRUE; // Done! all the capabilities have been found to coexist
  959. // Otherwise, look for the next capability in the *remaining* AltCaps
  960. // *This* AltCaps contains the capability we were looking for
  961. // So, we "used up" this AltCaps and can't select from it anymore
  962. // Pack the array of H245_SIMCAP_T pointers in place so that
  963. // "used" entries are at the beginning and "unused" at the end
  964. // (a la shell sort swap pointers)
  965. if(i != 0) // if not already the same, swap
  966. {
  967. pFirstAltCapEntry = *ppAltCapArray;
  968. *ppAltCapArray = pAltCapEntry;
  969. *(ppAltCapArray+i) = pFirstAltCapEntry;
  970. }
  971. // continue the quest using the remaining capabilities
  972. // and the remaining AltCaps
  973. bSim = AreSimCaps(pIDArray + 1, uIDArraySize - 1,
  974. ppAltCapArray + 1, uAltCapArraySize - 1);
  975. if(bSim)
  976. {
  977. return bSim;// success
  978. }
  979. else // why not? Either a fit does not exist (common), or the altcaps contain
  980. // an odd pattern of multiple instances of some capability IDs, and another
  981. // search order *might* fit. Do not blindly try all permutations of search
  982. // order.
  983. {
  984. // If it failed simply because the recently grabbed slot in the altcaps
  985. // (the one in *(ppAltCapArray+i)) could have been needed by subsequent
  986. // capability IDs, give this one up and look for another instance.
  987. // If not, we know for sure that the n! approach will not yield
  988. // fruit and can be avoided.
  989. for(u=1;(bSim == FALSE)&&(u<uAltCapArraySize);u++)
  990. {
  991. for(j=0;(bSim == FALSE)&&(j<pAltCapEntry->Length);j++)
  992. { // another capability needed the altcaps we grabbed ?
  993. if(*(pIDArray+u) == pAltCapEntry->AltCaps[j])
  994. {
  995. bSim=TRUE;
  996. break; // look no more here, bail to try again because a fit *might* exist
  997. }
  998. }
  999. }
  1000. if(bSim) // going to continue searching - Swap pointers back if they were swapped above
  1001. {
  1002. if(i != 0) // if not the same, swap back
  1003. {
  1004. *ppAltCapArray = *(ppAltCapArray+i);
  1005. *(ppAltCapArray+i) = pAltCapEntry;
  1006. }
  1007. break; // next i
  1008. }
  1009. else // don't waste CPU - a fit does not exist
  1010. {
  1011. return bSim;
  1012. }
  1013. }
  1014. }
  1015. }
  1016. }
  1017. return FALSE;
  1018. }
  1019. // Given a sized list of capability IDs (pointer to array of H245_CAPID_T)
  1020. // and a list of simultaneous capabilities, try each simultaneous capability
  1021. // and determine if the entire list of capability IDs can simultaneously coexist.
  1022. BOOL CapsCtl::TestSimultaneousCaps(H245_CAPID_T* pIDArray, UINT uIDArraySize,
  1023. PCC_TERMCAPDESCRIPTORS pTermCaps)
  1024. {
  1025. int iSimSet, iAltSet;
  1026. BOOL bResolved = FALSE;
  1027. H245_SIMCAP_T * pAltCapArray[H245_MAX_SIMCAPS];
  1028. if (!pAdvertisedSets)
  1029. return(TRUE);
  1030. // try each independent local SimCaps set (each descriptor) until success
  1031. for (iSimSet=0; (bResolved == FALSE) && (iSimSet < pTermCaps->wLength);iSimSet++)
  1032. {
  1033. // EXTRA STEP:
  1034. // Build a sortable representation of the AltCaps set. This step will not be necessary if
  1035. // and when we change the native representation of a capability descriptor to a variable
  1036. // length list of pointers to AltCaps. In the meantime, we know that there are no more
  1037. // than H245_MAX_SIMCAPS AltCaps in this SimCaps. This is imposed by the 2 dimensional
  1038. // arrays of hardcoded size forced upon us by CALLCONT.DLL.
  1039. for (iAltSet=0;iAltSet < pTermCaps->pTermCapDescriptorArray[iSimSet]->CapDesc.Length;iAltSet++)
  1040. {
  1041. pAltCapArray[iAltSet] = &pTermCaps->pTermCapDescriptorArray[iSimSet]->CapDesc.SimCapArray[iAltSet];
  1042. }
  1043. // do the work
  1044. bResolved = AreSimCaps(pIDArray, uIDArraySize,
  1045. (H245_SIMCAP_T **)&pAltCapArray,
  1046. MAKELONG(pTermCaps->pTermCapDescriptorArray[iSimSet]->CapDesc.Length, 0));
  1047. }
  1048. return bResolved;
  1049. }
  1050. // Function: CapsCtl::ResolvePermutations(PRES_CONTEXT pResContext, UINT uNumFixedColumns)
  1051. //
  1052. // This functions as both a combination generator and a validation mechanism for the
  1053. // combinations it generates.
  1054. //
  1055. // Given a pointer to a resolution context and the number of fixed (i.e. not permutable,
  1056. // if "permutable" is even a real word) columns, generate one combination at a time.
  1057. // Try each combination until a working combination is found or until all combinations
  1058. // have been tried.
  1059. //
  1060. // The resolution context structure contains a variable number of columns of variable
  1061. // length media format ID lists. Each column tracks its current index. When this
  1062. // function returns TRUE, the winning combination is indicated by the current column
  1063. // indices.
  1064. //
  1065. // The caller can control which combinations are tried first by arranging the columns
  1066. // in descending importance.
  1067. //
  1068. // Incremental searches can be performed without redundant comparisons by adding 1 format
  1069. // at a time to a column, arranging the column order so that the appended column is
  1070. // first, and "fixing" that one column at the newly added format. For example,
  1071. // some calling function could force evaluations on a round-robin column basis by
  1072. // calling this function inside a loop which does the following:
  1073. // 1 - adds one format at a time to the rightmost column and sets the current index
  1074. // of that column to the new entry
  1075. // 2 - rotates the column order so that the rightmost column is now the leftmost
  1076. // 3 - fixing the new leftmost column before calling this function again
  1077. // The result will be that only the permutations which contain the newly added format
  1078. // will be generated.
  1079. BOOL CapsCtl::ResolvePermutations(PRES_CONTEXT pResContext, UINT uNumFixedColumns)
  1080. {
  1081. RES_PAIR *pResolvedPair;
  1082. BOOL bResolved = FALSE;
  1083. UINT i, uColumns;
  1084. UINT uPairIndex;
  1085. // converge on one combination in the permutation
  1086. if(uNumFixedColumns != pResContext->uColumns)
  1087. {
  1088. RES_PAIR_LIST *pThisColumn;
  1089. // take the first non-fixed column, make that column fixed and
  1090. // iterate on it (loop through indices), and try each sub-permutation
  1091. // of remaining columns. (until success or all permutations tried)
  1092. pThisColumn = *(pResContext->ppPairLists+uNumFixedColumns);
  1093. for (i=0; (bResolved == FALSE) && (i<pThisColumn->uSize); i++)
  1094. {
  1095. pThisColumn->uCurrentIndex = i;
  1096. bResolved = ResolvePermutations(pResContext, uNumFixedColumns+1);
  1097. }
  1098. return bResolved;
  1099. }
  1100. else
  1101. {
  1102. // Bottomed out on the final column. Test the viability of this combination
  1103. // Build array of local IDs that contians the combination and test the
  1104. // combination against local simultaneous capabilities, then against
  1105. // remote simultaneous capabilities
  1106. // NOTE: be sure to skip empty columns (which represent unresolvable
  1107. // or unsupported/nonexistent media types or unsupported additional
  1108. // instances of media types)
  1109. for(i=0, uColumns=0;i<pResContext->uColumns;i++)
  1110. {
  1111. if(((*pResContext->ppPairLists)+i)->uSize)
  1112. {
  1113. // get index (row #) for this column
  1114. uPairIndex = ((*pResContext->ppPairLists)+i)->uCurrentIndex;
  1115. // get the row
  1116. pResolvedPair = ((*pResContext->ppPairLists)+i)->pResolvedPairs+uPairIndex;
  1117. // add the ID to the array
  1118. *(pResContext->pIDScratch+uColumns) = (H245_CAPID_T)pResolvedPair->idPublicLocal;
  1119. uColumns++;
  1120. }
  1121. // else empty column
  1122. }
  1123. // Determine if this combination can exist simultaneously
  1124. if(TestSimultaneousCaps(pResContext->pIDScratch,
  1125. uColumns, pResContext->pTermCapsLocal))
  1126. {
  1127. // now test remote
  1128. // build array of remote IDs and test those against remote
  1129. // simultaneous capabilities
  1130. for(i=0, uColumns=0;i<pResContext->uColumns;i++)
  1131. {
  1132. if(((*pResContext->ppPairLists)+i)->uSize)
  1133. {
  1134. // get index (row #) for this column
  1135. uPairIndex = ((*pResContext->ppPairLists)+i)->uCurrentIndex;
  1136. // get the row
  1137. pResolvedPair = ((*pResContext->ppPairLists)+i)->pResolvedPairs+uPairIndex;
  1138. // add the ID to the array
  1139. *(pResContext->pIDScratch+uColumns) =(H245_CAPID_T) pResolvedPair->idRemote;
  1140. uColumns++;
  1141. }
  1142. // else empty column
  1143. }
  1144. bResolved = TestSimultaneousCaps(pResContext->pIDScratch,
  1145. uColumns, pResContext->pTermCapsRemote);
  1146. }
  1147. return bResolved;
  1148. // if(bResolved == TRUE)
  1149. // The resolved combination of pairs is indicated by the current indices
  1150. // of **ppPairList;
  1151. }
  1152. }
  1153. //
  1154. // Given a counted list of desired instances of media, produce an output array of
  1155. // resolved media format IDs which correspond to the input media type IDs.
  1156. // This function returns success if at least one media instance is resolved.
  1157. // When an instance of media is unresolveable, the output corresponding to that
  1158. // instance contains the value INVALID_MEDIA_FORMAT for local and remote media
  1159. // format IDs.
  1160. //
  1161. // The input is treated as being in preferential order: permutations of the latter
  1162. // media type instance are varied first. If all permutations do not yield success,
  1163. // then one media type instance at a time is removed from the end.
  1164. //
  1165. HRESULT CapsCtl::ResolveFormats (LPGUID pMediaGuidArray, UINT uNumMedia,
  1166. PRES_PAIR pResOutput)
  1167. {
  1168. HRESULT hr = hrSuccess;
  1169. PRES_PAIR_LIST pResColumnArray = NULL;
  1170. PRES_PAIR_LIST *ppPairLists;
  1171. RES_PAIR *pResPair;
  1172. PRES_CONTEXT pResContext;
  1173. LPIH323MediaCap pMediaResolver;
  1174. UINT i;
  1175. UINT uMaxFormats = 0;
  1176. UINT uFixedColumns =0;
  1177. UINT uFailedMediaCount = 0;
  1178. BOOL bResolved = FALSE;
  1179. RES_PAIR UnresolvedPair = {INVALID_MEDIA_FORMAT, INVALID_MEDIA_FORMAT, INVALID_MEDIA_FORMAT};
  1180. // create a context structure for the resolution
  1181. pResContext = (PRES_CONTEXT)MemAlloc(sizeof(RES_CONTEXT)+ (uNumMedia*sizeof(H245_CAPID_T)));
  1182. if(!pResContext)
  1183. {
  1184. hr = CAPS_E_NOMEM;
  1185. goto ERROR_OUT;
  1186. }
  1187. // initialize resolution context
  1188. pResContext->uColumns = 0;
  1189. pResContext->pIDScratch = (H245_CAPID_T*)(pResContext+1);
  1190. pResContext->pTermCapsLocal = pAdvertisedSets;
  1191. pResContext->pTermCapsRemote = pRemAdvSets;
  1192. // allocate array of RES_PAIR_LIST (one per column/media type) and
  1193. // array of pointers to same
  1194. pResColumnArray = (PRES_PAIR_LIST)MemAlloc((sizeof(RES_PAIR_LIST) * uNumMedia)
  1195. + (sizeof(PRES_PAIR_LIST) * uNumMedia));
  1196. if(!pResColumnArray)
  1197. {
  1198. hr = CAPS_E_NOMEM;
  1199. goto ERROR_OUT;
  1200. }
  1201. pResContext->ppPairLists = ppPairLists = (PRES_PAIR_LIST*)(pResColumnArray+uNumMedia);
  1202. // build columns of media capabilities
  1203. for(i=0;i<uNumMedia;i++)
  1204. {
  1205. // build array of pointers to RES_PAIR_LIST
  1206. *(ppPairLists+i) = pResColumnArray+i;
  1207. // initialize RES_PAIR_LIST members
  1208. (pResColumnArray+i)->pResolvedPairs = NULL;
  1209. (pResColumnArray+i)->uSize =0;
  1210. (pResColumnArray+i)->uCurrentIndex = 0;
  1211. // Get resolver for this media. Special case: there is no T120 resolver.
  1212. // T120 caps are handled right here in this object
  1213. if(MEDIA_TYPE_H323_T120 == *(pMediaGuidArray+i))
  1214. {
  1215. pMediaResolver = NULL;
  1216. if((m_localT120cap != INVALID_MEDIA_FORMAT) &&(m_remoteT120cap != INVALID_MEDIA_FORMAT) )
  1217. {
  1218. (pResColumnArray+i)->uSize =1;
  1219. uMaxFormats = 1; // only one T.120 cap
  1220. pResPair = (pResColumnArray+i)->pResolvedPairs =
  1221. (RES_PAIR *)MemAlloc(uMaxFormats * sizeof(RES_PAIR));
  1222. if(!pResPair)
  1223. {
  1224. hr = CAPS_E_NOMEM;
  1225. goto ERROR_OUT;
  1226. }
  1227. //
  1228. pResPair->idLocal = m_localT120cap;
  1229. pResPair->idRemote = m_remoteT120cap;
  1230. pResPair->idPublicLocal = pResPair->idLocal;
  1231. }
  1232. }
  1233. else
  1234. {
  1235. pMediaResolver = FindHostForMediaGuid(pMediaGuidArray+i);
  1236. }
  1237. pResContext->uColumns++;
  1238. (pResColumnArray+i)->pMediaResolver = pMediaResolver;
  1239. if(pMediaResolver)
  1240. {
  1241. uMaxFormats = pMediaResolver->GetNumCaps(FALSE); // get transmit format count
  1242. if(uMaxFormats)
  1243. {
  1244. pResPair = (pResColumnArray+i)->pResolvedPairs =
  1245. (RES_PAIR *)MemAlloc(uMaxFormats * sizeof(RES_PAIR));
  1246. if(!pResPair)
  1247. {
  1248. hr = CAPS_E_NOMEM;
  1249. goto ERROR_OUT;
  1250. }
  1251. // resolve the best choice for each media type (gotta start somewhere)
  1252. pResPair->idLocal = INVALID_MEDIA_FORMAT;
  1253. pResPair->idRemote = INVALID_MEDIA_FORMAT;
  1254. hr=pMediaResolver->ResolveEncodeFormat (&pResPair->idLocal,&pResPair->idRemote);
  1255. if(!HR_SUCCEEDED(hr))
  1256. {
  1257. if((hr == CAPS_W_NO_MORE_FORMATS)
  1258. || (hr == CAPS_E_NOMATCH)
  1259. || (hr == CAPS_E_NOCAPS))
  1260. {
  1261. // No resolved format for this media type. Remove this "column"
  1262. (pResColumnArray+i)->pResolvedPairs = NULL;
  1263. MemFree(pResPair);
  1264. (pResColumnArray+i)->uSize =0;
  1265. hr = hrSuccess;
  1266. }
  1267. else
  1268. {
  1269. goto ERROR_OUT;
  1270. }
  1271. }
  1272. else
  1273. {
  1274. // this column has one resolved format
  1275. pResPair->idPublicLocal = pMediaResolver->GetPublicID(pResPair->idLocal);
  1276. (pResColumnArray+i)->uSize =1;
  1277. }
  1278. }
  1279. // else // No formats exist for this media type. this "column" has zero size
  1280. }
  1281. }
  1282. // Special case test simultaneous caps for the most preferred combination:
  1283. uFixedColumns = pResContext->uColumns; // << make all columns fixed
  1284. bResolved = ResolvePermutations(pResContext, uFixedColumns);
  1285. // if the single most preferred combination can't be used, need to handle
  1286. // the general case and try permutations until a workable combination is found
  1287. while(!bResolved)
  1288. {
  1289. // make one column at a time permutable, starting with the least-critical media
  1290. // type. (e.g. it would be typical for the last column to be video because
  1291. // audio+data are more important. Then we try less and less
  1292. // preferable video formats before doing anything that would degrade the audio)
  1293. if(uFixedColumns > 0) // if not already at the end of the rope...
  1294. {
  1295. uFixedColumns--; // make another column permutable
  1296. }
  1297. else
  1298. {
  1299. // wow - tried all permutations and still no luck ......
  1300. // nuke the least important remaining media type (e.g. try it w/o video)
  1301. if(pResContext->uColumns <= 1) // already down to one media type?
  1302. {
  1303. hr = CAPS_E_NOMATCH;
  1304. goto ERROR_OUT;
  1305. }
  1306. // Remove the end column (representing the least important media type)
  1307. // and try it with the remaining columns
  1308. uFixedColumns = --pResContext->uColumns; // one less column
  1309. // set the formats of the nuked column to the unresolved state
  1310. (pResColumnArray+uFixedColumns)->uSize =0;
  1311. (pResColumnArray+uFixedColumns)->uCurrentIndex =0;
  1312. pResPair = (pResColumnArray+uFixedColumns)->pResolvedPairs;
  1313. if (NULL != pResPair)
  1314. {
  1315. pResPair->idLocal = INVALID_MEDIA_FORMAT;
  1316. pResPair->idRemote = INVALID_MEDIA_FORMAT;
  1317. pResPair->idPublicLocal = INVALID_MEDIA_FORMAT;
  1318. }
  1319. uFailedMediaCount++; // track the nuking of a column to avoid
  1320. // redundantly grabbing all the formats again
  1321. // ... would not be here if all permutations
  1322. // had not been tried!
  1323. // reset the combination indices
  1324. for(i=0;i<uFixedColumns;i++)
  1325. {
  1326. (pResColumnArray+i)->uCurrentIndex = 0;
  1327. }
  1328. }
  1329. // get the rest of the formats for the last known fixed column, make that column
  1330. // permutable, etc.
  1331. pMediaResolver = (pResColumnArray+uFixedColumns)->pMediaResolver;
  1332. if(!pMediaResolver || ((pResColumnArray+uFixedColumns)->uSize ==0))
  1333. {
  1334. continue; // this media type has no further possibility
  1335. }
  1336. if(uFailedMediaCount ==0) // If all of the possible resolved pairs
  1337. // have not yet been obtained, get them!
  1338. {
  1339. // get resolved pair IDs for every mutual format of this media type
  1340. // first: get pointer to array of pair IDs, then use ResolveEncodeFormat()
  1341. // to fill up the array
  1342. pResPair = (pResColumnArray+uFixedColumns)->pResolvedPairs;
  1343. // Get total # of formats less the one that was already obtained
  1344. uMaxFormats = pMediaResolver->GetNumCaps(FALSE) -1;
  1345. while(uMaxFormats--) // never exceed the # of remaining local formats...
  1346. {
  1347. RES_PAIR *pResPairNext;
  1348. // recall that ResolveEncodeFormat parameters are I/O - the input
  1349. // is the local ID of the last resolved mutual format. (remote id
  1350. // is ignored as input). Fixup the input.
  1351. pResPairNext = pResPair+1;
  1352. // start where the previous resolve stopped
  1353. pResPairNext->idLocal = pResPair->idLocal;
  1354. // not necessary, ignored ->>> pResPairNext->idRemote = pResPair->idRemote
  1355. pResPair = pResPairNext;
  1356. hr=pMediaResolver->ResolveEncodeFormat (&pResPair->idLocal,&pResPair->idRemote);
  1357. if((hr == CAPS_W_NO_MORE_FORMATS)
  1358. || (hr == CAPS_E_NOMATCH))
  1359. // got all of the formats, but not an error
  1360. { // this is likely when less than 100% of local formats have a remote match
  1361. hr = hrSuccess;
  1362. break;
  1363. }
  1364. if(!HR_SUCCEEDED(hr))
  1365. goto ERROR_OUT;
  1366. // get the public ID of the local format (it's *usually* the same, but not always)
  1367. pResPair->idPublicLocal = pMediaResolver->GetPublicID(pResPair->idLocal);
  1368. // this column has another format - count it!
  1369. (pResColumnArray+uFixedColumns)->uSize++;
  1370. }
  1371. }
  1372. // now try the new permutations
  1373. bResolved = ResolvePermutations(pResContext, uFixedColumns);
  1374. }
  1375. if(bResolved)
  1376. {
  1377. // spew the output
  1378. for(i=0;i<uNumMedia;i++)
  1379. {
  1380. if((pResColumnArray+i)->uSize)
  1381. {
  1382. pResPair = (pResColumnArray+i)->pResolvedPairs
  1383. + (pResColumnArray+i)->uCurrentIndex;
  1384. }
  1385. else
  1386. {
  1387. pResPair = &UnresolvedPair;
  1388. }
  1389. *(pResOutput+i) = *pResPair;
  1390. }
  1391. }
  1392. else
  1393. {
  1394. // if there was some error, preserve that error code,
  1395. if(HR_SUCCEEDED(hr))
  1396. // otherwise the error is....
  1397. hr = CAPS_E_NOMATCH;
  1398. }
  1399. ERROR_OUT: // well, the success case falls out here too
  1400. if(pResColumnArray)
  1401. {
  1402. for(i=0;i<uNumMedia;i++)
  1403. {
  1404. if((pResColumnArray+i)->pResolvedPairs)
  1405. MemFree((pResColumnArray+i)->pResolvedPairs);
  1406. }
  1407. MemFree(pResColumnArray);
  1408. }
  1409. if(pResContext)
  1410. {
  1411. MemFree(pResContext);
  1412. }
  1413. return hr;
  1414. }
  1415. HRESULT CapsCtl::ResetCombinedEntries (void)
  1416. {
  1417. DWORD x;
  1418. if (pAdvertisedSets)
  1419. {
  1420. for (x = 0; x < pAdvertisedSets->wLength; x++)
  1421. {
  1422. if (pAdvertisedSets->pTermCapDescriptorArray[x])
  1423. {
  1424. MemFree (pAdvertisedSets->pTermCapDescriptorArray[x]);
  1425. }
  1426. }
  1427. MemFree (pAdvertisedSets->pTermCapDescriptorArray);
  1428. pAdvertisedSets->wLength=0;
  1429. MemFree (pAdvertisedSets);
  1430. pAdvertisedSets = NULL;
  1431. }
  1432. if (pSetIDs)
  1433. {
  1434. MemFree(pSetIDs);
  1435. pSetIDs = NULL;
  1436. }
  1437. dwNumInUse=0;
  1438. uAdvertizedSize=0;
  1439. return hrSuccess;
  1440. }