windows-nt/Source/XPSP1/NT/enduser/netmeeting/av/h323/capsctl.cpp
2020-09-26 16:20:57 +08:00

1641 lines
51 KiB
C++

/*
* File: capsctl.cpp
*
* capability control object implementations
*
*
* Revision History:
*
* 10/10/96 mikeg created
* 06/24/97 mikev - Added T.120 capability to serialized caps and simcaps (interim hack until a
* T120 resolver is implemented)
* - Retired ResolveEncodeFormat(Audio,Video) and implemented a data-independent
* resolution algorithm and exposed method ResolveFormats(). Added support
* routines ResolvePermutations(), TestSimultaneousCaps() and
* AreSimcaps().
*/
#include "precomp.h"
UINT g_AudioPacketDurationMs = AUDIO_PACKET_DURATION_LONG; // preferred packet duration
BOOL g_fRegAudioPacketDuration = FALSE; // AudioPacketDurationMs from registry
PCC_TERMCAPDESCRIPTORS CapsCtl::pAdvertisedSets=NULL;
DWORD CapsCtl::dwConSpeed = 0;
UINT CapsCtl::uStaticGlobalRefCount=0;
UINT CapsCtl::uAdvertizedSize=0;
extern HRESULT WINAPI CreateMediaCapability(REFGUID, LPIH323MediaCap *);
LPIH323MediaCap CapsCtl::FindHostForID(MEDIA_FORMAT_ID id)
{
if(pAudCaps && pAudCaps->IsHostForCapID(id))
{
return (pAudCaps);
}
else if (pVidCaps && pVidCaps->IsHostForCapID(id))
{
return (pVidCaps);
}
return NULL;
}
LPIH323MediaCap CapsCtl::FindHostForMediaType(PCC_TERMCAP pCapability)
{
if(pCapability->DataType == H245_DATA_AUDIO)
{
return (pAudCaps);
}
else if(pCapability->DataType == H245_DATA_VIDEO)
{
return (pVidCaps);
}
return NULL;
}
LPIH323MediaCap CapsCtl::FindHostForMediaGuid(LPGUID pMediaGuid)
{
if(MEDIA_TYPE_H323VIDEO == *pMediaGuid)
{
return (pVidCaps);
}
else if(MEDIA_TYPE_H323AUDIO == *pMediaGuid)
{
return (pAudCaps);
}
else
return NULL;
}
ULONG CapsCtl::AddRef()
{
uRef++;
return uRef;
}
ULONG CapsCtl::Release()
{
uRef--;
if(uRef == 0)
{
delete this;
return 0;
}
return uRef;
}
STDMETHODIMP CapsCtl::QueryInterface( REFIID iid, void ** ppvObject)
{
// this breaks the rules for the official COM QueryInterface because
// the interfaces that are queried for are not necessarily real COM
// interfaces. The reflexive property of QueryInterface would be broken in
// that case.
HRESULT hr = E_NOINTERFACE;
if(!ppvObject)
return hr;
*ppvObject = 0;
if(iid == IID_IDualPubCap)// satisfy symmetric property of QI
{
*ppvObject = (IDualPubCap *)this;
hr = hrSuccess;
AddRef();
}
else if(iid == IID_IAppAudioCap )
{
if(pAudCaps)
{
return pAudCaps->QueryInterface(iid, ppvObject);
}
}
else if(iid == IID_IAppVidCap )
{
if(pVidCaps)
{
return pVidCaps->QueryInterface(iid, ppvObject);
}
}
return hr;
}
CapsCtl::CapsCtl () :
uRef(1),
pVidCaps(NULL),
pAudCaps(NULL),
pACapsBuf(NULL),
pVCapsBuf(NULL),
dwNumInUse(0),
bAudioPublicize(TRUE),
bVideoPublicize(TRUE),
bT120Publicize(TRUE),
m_localT120cap(INVALID_MEDIA_FORMAT),
m_remoteT120cap(INVALID_MEDIA_FORMAT),
m_remoteT120bitrate(0),
m_pAudTermCaps(NULL),
m_pVidTermCaps(NULL),
pSetIDs(NULL),
pRemAdvSets(NULL)
{
uStaticGlobalRefCount++;
}
CapsCtl::~CapsCtl ()
{
if (pACapsBuf) {
MemFree (pACapsBuf);
}
if (pVCapsBuf) {
MemFree (pVCapsBuf);
}
if (pAudCaps) {
pAudCaps->Release();
}
if (pVidCaps) {
pVidCaps->Release();
}
uStaticGlobalRefCount--;
if (uStaticGlobalRefCount == 0) {
//Free up the sim. caps array
if (pAdvertisedSets) {
while (pAdvertisedSets->wLength) {
//wLength is Zero based
MemFree ((VOID *)pAdvertisedSets->pTermCapDescriptorArray[--pAdvertisedSets->wLength]);
}
MemFree ((VOID *)pAdvertisedSets->pTermCapDescriptorArray);
pAdvertisedSets->pTermCapDescriptorArray = NULL;
MemFree ((void *) pAdvertisedSets);
pAdvertisedSets=NULL;
dwNumInUse=0;
}
}
//And the remote array
if (pRemAdvSets) {
while (pRemAdvSets->wLength) {
MemFree ((VOID *)pRemAdvSets->pTermCapDescriptorArray[--pRemAdvSets->wLength]);
}
MemFree ((void *) pRemAdvSets->pTermCapDescriptorArray);
pRemAdvSets->pTermCapDescriptorArray = NULL;
MemFree ((void *) pRemAdvSets);
pRemAdvSets=NULL;
}
MemFree (pSetIDs);
pSetIDs=NULL;
}
BOOL CapsCtl::Init()
{
HRESULT hrLast;
int iBase = 1;
if (g_capFlags & CAPFLAGS_AV_STREAMS)
{
hrLast = ::CreateMediaCapability(MEDIA_TYPE_H323AUDIO, &pAudCaps);
if(!HR_SUCCEEDED(hrLast))
{
goto InitDone;
}
}
if (g_capFlags & CAPFLAGS_AV_STREAMS)
{
hrLast = ::CreateMediaCapability(MEDIA_TYPE_H323VIDEO, &pVidCaps);
if(!HR_SUCCEEDED(hrLast))
{
goto InitDone;
}
}
if (pAudCaps)
{
// Base the capability IDs beginning at 1 (zero is an invalid capability ID!)
pAudCaps->SetCapIDBase(iBase);
iBase += pAudCaps->GetNumCaps();
}
if (pVidCaps)
{
pVidCaps->SetCapIDBase(iBase);
iBase += pVidCaps->GetNumCaps();
}
InitDone:
m_localT120cap = iBase;
return TRUE;
}
HRESULT CapsCtl::ReInitialize()
{
HRESULT hr = hrSuccess;
int iBase = 1;
if (pAudCaps && !pAudCaps->ReInit())
{
hr = CAPS_E_SYSTEM_ERROR;
goto EXIT;
}
if (pVidCaps && !pVidCaps->ReInit())
{
hr = CAPS_E_SYSTEM_ERROR;
goto EXIT;
}
// Base the capability IDs beginning at 1 (zero is an invalid capability ID!)
if (pAudCaps)
{
pAudCaps->SetCapIDBase(iBase);
iBase += pAudCaps->GetNumCaps();
}
if (pVidCaps)
{
pVidCaps->SetCapIDBase(iBase);
iBase += pVidCaps->GetNumCaps();
}
m_localT120cap = iBase;
EXIT:
return hr;
}
const char szNMProdNum[] = "Microsoft\256 NetMeeting(TM)\0";
const char szNM20VerNum[] = "Version 2.0\0";
HRESULT CapsCtl::AddRemoteDecodeCaps(PCC_TERMCAPLIST pTermCapList,PCC_TERMCAPDESCRIPTORS pTermCapDescriptors, PCC_VENDORINFO pVendorInfo)
{
FX_ENTRY("CapsCtl::AddRemoteDecodeCaps");
HRESULT hr;
void *pData=NULL;
UINT uSize,x,y,z;
//WLength is # of capabilities, not structure length
WORD wNDesc;
LPIH323MediaCap pMediaCap;
if(!pTermCapList && !pTermCapDescriptors) // additional capability descriptors may be added
{ // at any time
return CAPS_E_INVALID_PARAM;
}
// Check for NM version 2.0
m_fNM20 = FALSE;
ASSERT(pVendorInfo);
if (pVendorInfo->bCountryCode == USA_H221_COUNTRY_CODE
&& pVendorInfo->wManufacturerCode == MICROSOFT_H_221_MFG_CODE
&& pVendorInfo->pProductNumber && pVendorInfo->pVersionNumber
&& pVendorInfo->pProductNumber->wOctetStringLength == sizeof(szNMProdNum)
&& pVendorInfo->pVersionNumber->wOctetStringLength == sizeof(szNM20VerNum)
&& memcmp(pVendorInfo->pProductNumber->pOctetString, szNMProdNum, sizeof(szNMProdNum)) == 0
&& memcmp(pVendorInfo->pVersionNumber->pOctetString, szNM20VerNum, sizeof(szNM20VerNum)) == 0
)
{
m_fNM20 = TRUE;
}
// cleanup old term caps if term caps are being added and old caps exist
if (pAudCaps)
pAudCaps->FlushRemoteCaps();
if (pVidCaps)
pVidCaps->FlushRemoteCaps();
m_remoteT120cap = INVALID_MEDIA_FORMAT; // note there is no T120 cap resolver and
// this CapsCtl holds exactly one local and remote T120 cap
// Copy pTermcapDescriptors to a local copy, (and free any old one)
if (pRemAdvSets) {
while (pRemAdvSets->wLength) {
//0 based
MemFree ((VOID *)pRemAdvSets->pTermCapDescriptorArray[--pRemAdvSets->wLength]);
}
MemFree ((VOID *)pRemAdvSets->pTermCapDescriptorArray);
pRemAdvSets->pTermCapDescriptorArray = NULL;
MemFree ((VOID *)pRemAdvSets);
pRemAdvSets=NULL;
}
//Ok, walk through the PCC_TERMCAPDESCRIPTORS list, first, allocate memory for the Master PCC_TERMCAPDESCRIPTORS
//structure, then each simcap, and the altcaps therin, then copy the data.
if (!(pRemAdvSets=(PCC_TERMCAPDESCRIPTORS) MemAlloc (sizeof (CC_TERMCAPDESCRIPTORS) ))){
return CAPS_E_SYSTEM_ERROR;
}
//How many Descriptors?
pRemAdvSets->wLength=pTermCapDescriptors->wLength;
if (!(pRemAdvSets->pTermCapDescriptorArray=((H245_TOTCAPDESC_T **)MemAlloc (sizeof (H245_TOTCAPDESC_T*)*pTermCapDescriptors->wLength))) ) {
return CAPS_E_SYSTEM_ERROR;
}
//Once per descriptor...
for (x=0;x < pTermCapDescriptors->wLength;x++) {
//Allocate memory for the descriptor entry
if (!(pRemAdvSets->pTermCapDescriptorArray[x]=(H245_TOTCAPDESC_T *)MemAlloc (sizeof (H245_TOTCAPDESC_T)))) {
return CAPS_E_SYSTEM_ERROR;
}
//BUGBUG for beta 2 Copy en masse.
memcpy (pRemAdvSets->pTermCapDescriptorArray[x],pTermCapDescriptors->pTermCapDescriptorArray[x],sizeof (H245_TOTCAPDESC_T));
/* post beta 2?
//Copy the capability ID
pRemAdvSets->pTermCapDescriptorArray[x].CapID=pTermCapDescriptors[x].CapID
//Walk the simcaps, then altcaps and copy entries */
}
for (wNDesc=0;wNDesc <pTermCapList->wLength;wNDesc++) {
pData=NULL;
pMediaCap = FindHostForMediaType(pTermCapList->pTermCapArray[wNDesc]);
if(!pMediaCap)
{
// special case: there is no T120 resolver. THIS IS A TEMPORARY
// SITUATION. We cannot track bitrate limits on multiple T120 capability
// instances because of this. As of now, we (NetMeeting) do not advertise
// more than one T.120 capability.
//This code will keep the last T.120 capability encountered.
if(((pTermCapList->pTermCapArray[wNDesc])->DataType == H245_DATA_DATA)
&& ((pTermCapList->pTermCapArray[wNDesc])->Cap.H245Dat_T120.application.choice
== DACy_applctn_t120_chosen)
&& ((pTermCapList->pTermCapArray[wNDesc])->Cap.H245Dat_T120.application.u.DACy_applctn_t120.choice
== separateLANStack_chosen))
{
// it's data data
m_remoteT120cap = (pTermCapList->pTermCapArray[wNDesc])->CapId;
m_remoteT120bitrate =
(pTermCapList->pTermCapArray[wNDesc])->Cap.H245Dat_T120.maxBitRate;
}
// continue;
// handled it in-line
}
else if(pMediaCap->IsCapabilityRecognized(pTermCapList->pTermCapArray[wNDesc]))
{
hr = pMediaCap->AddRemoteDecodeFormat(pTermCapList->pTermCapArray[wNDesc]);
#ifdef DEBUG
if(!HR_SUCCEEDED(hr))
{
ERRORMESSAGE(("%s:AddRemoteDecodeFormat returned 0x%08lx\r\n",_fx_, hr));
}
#endif // DEBUG
}
}
return (hrSuccess);
}
HRESULT CapsCtl::CreateCapList(PCC_TERMCAPLIST *ppCapBuf, PCC_TERMCAPDESCRIPTORS *ppCombinations)
{
PCC_TERMCAPLIST pTermCapList = NULL, pTermListAud=NULL, pTermListVid=NULL;
PCC_TERMCAPDESCRIPTORS pCombinations;
UINT uCount = 0, uSize = 0, uT120Size = 0;
HRESULT hr;
WORD wc;
UINT x=0,y=0,z=0,uNumAud=0,uNumVid=0;
H245_TOTCAPDESC_T *pTotCaps, **ppThisDescriptor;
PPCC_TERMCAP ppCCThisTermCap;
PCC_TERMCAP pCCT120Cap = NULL;
uCount = GetNumCaps(TRUE);
ASSERT((NULL == m_pAudTermCaps) && (NULL == m_pVidTermCaps));
// calc size of CC_TERMCAPLIST header + CC_TERMCAPDESCRIPTORS + array of PCC_TERMCAP
// allocate mem for the master CC_TERMCAPLIST, including the array of pointers to all CC_TERMCAPs
uSize = sizeof(CC_TERMCAPLIST)
+ sizeof (CC_TERMCAPDESCRIPTORS) + (uCount * sizeof(PCC_TERMCAP));
if((m_localT120cap != INVALID_MEDIA_FORMAT) && bT120Publicize)
{
uSize += sizeof(CC_TERMCAP);
}
pTermCapList = (PCC_TERMCAPLIST)MemAlloc(uSize);
if(pTermCapList == NULL)
{
hr = CAPS_E_NOMEM;
goto ERROR_EXIT;
}
// divide up the buffer, CC_TERMCAPLIST first, followed by array of PCC_TERMCAP.
// The array of PCC_TERMCAP follows fixed size CC_TERMCAPLIST structure and the fixed size
// CC_TERMCAP structure that holds the one T.120 cap.
if((m_localT120cap != INVALID_MEDIA_FORMAT) && bT120Publicize)
{
pCCT120Cap = (PCC_TERMCAP)(((BYTE *)pTermCapList) + sizeof(CC_TERMCAPLIST));
ppCCThisTermCap = (PPCC_TERMCAP) (((BYTE *)pTermCapList) + sizeof(CC_TERMCAPLIST) +
sizeof(CC_TERMCAP));
}
else
ppCCThisTermCap = (PPCC_TERMCAP) (((BYTE *)pTermCapList) + sizeof(CC_TERMCAPLIST));
// allocate mem for the simultaneous caps
// get size of cached advertised sets if it exists and more than one media
// type is enabled for publication
if(bAudioPublicize && bVideoPublicize && pAdvertisedSets)
{
// use size of cached buffer
uSize = uAdvertizedSize;
}
else if (pAdvertisedSets)
{
// This case needs to be fixed. If media types are disabled, the simultaneous capability
// descriptors in pAdvertisedSets should be rebuilt at that time. There should be no need to test
// if(bAudioPublicize && bVideoPublicize && pAdvertisedSets)
// calculate size of capability descriptors and simultaneous capability structures.
#pragma message ("Figure out the size this needs to be...")
#define NUMBER_TERMCAP_DESCRIPTORS 1
uSize = sizeof(H245_TOTCAPDESC_T) * NUMBER_TERMCAP_DESCRIPTORS+
sizeof (CC_TERMCAPDESCRIPTORS)+NUMBER_TERMCAP_DESCRIPTORS*
sizeof (H245_TOTCAPDESC_T *);
}
else
{
uSize = 0;
}
if (uSize)
{
pCombinations = (PCC_TERMCAPDESCRIPTORS)MemAlloc(uSize);
// skip the CC_TERMCAPDESCRIPTORS, which has a variable length array of (H245_TOTCAPDESC_T *) following it
// the total size of that glob is uSimCapsSize
// The actual array of [H245_TOTCAPDESC_T *] follows the CC_TERMCAPDESCRIPTORS structure
// anchor the pCombinations->pTermCapDescriptorArray to this point.
if(pCombinations == NULL)
{
hr = CAPS_E_NOMEM;
goto ERROR_EXIT;
}
ppThisDescriptor = pCombinations->pTermCapDescriptorArray
= (H245_TOTCAPDESC_T **)((BYTE *)pCombinations + sizeof(CC_TERMCAPDESCRIPTORS));
// the first H245_TOTCAPDESC_T follows the array of [H245_TOTCAPDESC_T *]
pTotCaps = (H245_TOTCAPDESC_T *)((BYTE *)ppThisDescriptor + pCombinations->wLength*sizeof(H245_TOTCAPDESC_T **));
if(pAudCaps && bAudioPublicize)
{
hr=pAudCaps->CreateCapList((LPVOID *)&pTermListAud);
if(!HR_SUCCEEDED(hr))
goto ERROR_EXIT;
ASSERT(pTermListAud != NULL);
}
if(pVidCaps && bVideoPublicize)
{
hr=pVidCaps->CreateCapList((LPVOID *)&pTermListVid);
if(!HR_SUCCEEDED(hr))
goto ERROR_EXIT;
ASSERT(pTermListVid != NULL);
}
}
else
{
pCombinations = NULL;
}
// fix pointers in the master caps list
// Now need to fixup the CC_TERMCAPLIST to refer to the individual capabilities
// Anchor the CC_TERMCAPLIST member pTermCapArray at the array of PCC_TERMCAP, and
// start partying on the array.
pTermCapList->wLength =0;
pTermCapList->pTermCapArray = ppCCThisTermCap;
if(pCCT120Cap)
{
*ppCCThisTermCap++ = pCCT120Cap;
// set T120 capability parameters
pCCT120Cap->DataType = H245_DATA_DATA;
pCCT120Cap->ClientType = H245_CLIENT_DAT_T120;
pCCT120Cap->Dir = H245_CAPDIR_LCLRXTX;
pCCT120Cap->Cap.H245Dat_T120.application.choice = DACy_applctn_t120_chosen;
pCCT120Cap->Cap.H245Dat_T120.application.u.DACy_applctn_t120.choice= separateLANStack_chosen;
pCCT120Cap->Cap.H245Dat_T120.maxBitRate = dwConSpeed;
pCCT120Cap->CapId = (H245_CAPID_T)m_localT120cap;
pTermCapList->wLength++;
}
if(pAudCaps && pTermListAud)
{
for(wc = 0; wc < pTermListAud->wLength; wc++)
{
// copy the array of "pointers to CC_TERMCAP"
*ppCCThisTermCap++ = pTermListAud->pTermCapArray[wc];
pTermCapList->wLength++;
}
}
if(pVidCaps && pTermListVid)
{
for(wc = 0; wc < pTermListVid->wLength; wc++)
{
// copy the array of "pointers to CC_TERMCAP"
*ppCCThisTermCap++ = pTermListVid->pTermCapArray[wc];
pTermCapList->wLength++;
}
}
// fixup the simultaneous capability descriptors
// Create a default set if necessary
//
if(bAudioPublicize && bVideoPublicize && pAdvertisedSets)
{
pCombinations->wLength = pAdvertisedSets->wLength;
// point pCombinations->pTermCapDescriptorArray past the header (CC_TERMCAPDESCRIPTORS)
pCombinations->pTermCapDescriptorArray
= (H245_TOTCAPDESC_T **)((BYTE *)pCombinations + sizeof(CC_TERMCAPDESCRIPTORS));
// the first H245_TOTCAPDESC_T follows the array of [H245_TOTCAPDESC_T *]
pTotCaps = (H245_TOTCAPDESC_T *)((BYTE *)pCombinations->pTermCapDescriptorArray +
pAdvertisedSets->wLength*sizeof(H245_TOTCAPDESC_T **));
for(x = 0; x < pAdvertisedSets->wLength; x++)
{
// write into the array of descriptor pointers. pointer[x] = this one
pCombinations->pTermCapDescriptorArray[x] = pTotCaps;
pTotCaps->CapDescId= pAdvertisedSets->pTermCapDescriptorArray[x]->CapDescId;
pTotCaps->CapDesc.Length=pAdvertisedSets->pTermCapDescriptorArray[x]->CapDesc.Length;
for(y = 0; y < pTotCaps->CapDesc.Length;y++)
{
//Copy the length field.
pTotCaps->CapDesc.SimCapArray[y].Length=
pAdvertisedSets->pTermCapDescriptorArray[x]->CapDesc.SimCapArray[y].Length;
for(z=0;
z < pAdvertisedSets->pTermCapDescriptorArray[x]->CapDesc.SimCapArray[y].Length;
z++)
{
pTotCaps->CapDesc.SimCapArray[y].AltCaps[z] =
pAdvertisedSets->pTermCapDescriptorArray[x]->CapDesc.SimCapArray[y].AltCaps[z];
}
}
pTotCaps++;
}
}
else if (pAdvertisedSets)
{
// descriptors in pAdvertisedSets should be rebuilt at that time. There should be no need to test
// if(bAudioPublicize && bVideoPublicize && pAdvertisedSets)
// HACK - put all audio or video caps in one AltCaps[], the T.120 cap in another AltCaps[]
// and put both of those in one single capability descriptor (H245_TOTCAPDESC_T)
// This hack will not extend past the assumption of one audio channel, one video channel, and
// one T.120 channel. If arbitrary media is supported, or multiple audio channels are supported,
// this code will be wrong
pCombinations->wLength=1;
// point pCombinations->pTermCapDescriptorArray past the header (CC_TERMCAPDESCRIPTORS)
pCombinations->pTermCapDescriptorArray
= (H245_TOTCAPDESC_T **)((BYTE *)pCombinations + sizeof(CC_TERMCAPDESCRIPTORS));
// the first H245_TOTCAPDESC_T follows the array of [H245_TOTCAPDESC_T *]
pTotCaps = (H245_TOTCAPDESC_T *)((BYTE *)pCombinations->pTermCapDescriptorArray +
pAdvertisedSets->wLength*sizeof(H245_TOTCAPDESC_T **));
pTotCaps->CapDescId=(H245_CAPDESCID_T)x;
pTotCaps->CapDesc.Length=0;
if(pTermListAud)
{
uNumAud = min(pTermListAud->wLength, H245_MAX_ALTCAPS);
pTotCaps->CapDesc.SimCapArray[x].Length=(unsigned short)uNumAud;
for(y = 0; y<uNumAud;y++)
{
pTotCaps->CapDesc.SimCapArray[x].AltCaps[y] = pTermListAud->pTermCapArray[y]->CapId;
}
x++;
pTotCaps->CapDesc.Length++;
}
if(pTermListVid && pTermListVid->wLength)
{
uNumVid = min(pTermListVid->wLength, H245_MAX_ALTCAPS);
pTotCaps->CapDesc.SimCapArray[x].Length=(unsigned short)uNumVid;
for(y = 0; y<uNumVid;y++)
{
pTotCaps->CapDesc.SimCapArray[x].AltCaps[y] = pTermListVid->pTermCapArray[y]->CapId;
}
x++;
pTotCaps->CapDesc.Length++;
}
// the T.120 cap
if((m_localT120cap != INVALID_MEDIA_FORMAT) && bT120Publicize)
{
pTotCaps->CapDesc.SimCapArray[x].Length=1;
pTotCaps->CapDesc.SimCapArray[x].AltCaps[0] = (H245_CAPID_T)m_localT120cap;
pTotCaps->CapDesc.Length++;
}
// write into the array of descriptor pointers. pointer[x] = this one
*ppThisDescriptor = pTotCaps;
}
m_pVidTermCaps = pTermListVid;
m_pAudTermCaps = pTermListAud;
*ppCapBuf = pTermCapList;
*ppCombinations = pCombinations;
return hrSuccess;
ERROR_EXIT:
m_pAudTermCaps = NULL;
m_pVidTermCaps = NULL;
if(pTermCapList)
MemFree(pTermCapList);
if(pCombinations)
MemFree(pCombinations);
if(pAudCaps && pTermListAud)
{
hr=pAudCaps->DeleteCapList(pTermListAud);
}
if(pVidCaps && pTermListVid)
{
hr=pVidCaps->DeleteCapList(pTermListVid);
}
return hr;
}
HRESULT CapsCtl::DeleteCapList(PCC_TERMCAPLIST pCapBuf, PCC_TERMCAPDESCRIPTORS pCombinations)
{
MemFree(pCapBuf);
MemFree(pCombinations);
if(m_pAudTermCaps && pAudCaps)
{
pAudCaps->DeleteCapList(m_pAudTermCaps);
}
if(m_pVidTermCaps)
{
pVidCaps->DeleteCapList(m_pVidTermCaps);
}
m_pAudTermCaps = NULL;
m_pVidTermCaps = NULL;
return hrSuccess;
}
HRESULT CapsCtl::GetEncodeParams(LPVOID pBufOut, UINT uBufSize,LPVOID pLocalParams, UINT uLocalSize,DWORD idRemote, DWORD idLocal)
{
LPIH323MediaCap pMediaCap = FindHostForID(idLocal);
if(!pMediaCap)
return CAPS_E_INVALID_PARAM;
// HACK
// Adjust audio packetization depending on call scenario
// unless there is an overriding registry setting
if (pMediaCap == pAudCaps)
{
VIDEO_FORMAT_ID vidLocal=INVALID_MEDIA_FORMAT, vidRemote=INVALID_MEDIA_FORMAT;
VIDEO_CHANNEL_PARAMETERS vidParams;
CC_TERMCAP vidCaps;
UINT audioPacketLength;
// modify the audio packetization parameters based on local bandwidth
// and presence of video
audioPacketLength = AUDIO_PACKET_DURATION_LONG;
// the registry setting overrides, if it is present
if (g_fRegAudioPacketDuration)
audioPacketLength = g_AudioPacketDurationMs;
else if (!m_fNM20) // dont try smaller packets for NM20 because it cant handle them
{
if (pVidCaps && pVidCaps->ResolveEncodeFormat(&vidLocal,&vidRemote) == S_OK
&& (pVidCaps->GetEncodeParams(&vidCaps,sizeof(vidCaps), &vidParams, sizeof(vidParams), vidRemote, vidLocal) == S_OK))
{
// we may potentially send video
if (vidParams.ns_params.maxBitRate*100 > BW_ISDN_BITS)
audioPacketLength = AUDIO_PACKET_DURATION_SHORT;
}
else
{
// no video
// since we dont know the actual connection bandwidth we use
// the local user setting.
// Note: if the remote is on a slow-speed net and the local is on a LAN
// we may end up with an inappropriate setting.
if (dwConSpeed > BW_288KBS_BITS)
audioPacketLength = AUDIO_PACKET_DURATION_SHORT;
else if (dwConSpeed > BW_144KBS_BITS)
audioPacketLength = AUDIO_PACKET_DURATION_MEDIUM;
}
}
// Setting the AudioPacketDurationMs affects the subsequent GetEncodeParams call
pMediaCap->SetAudioPacketDuration(audioPacketLength);
}
return pMediaCap->GetEncodeParams (pBufOut,uBufSize, pLocalParams,
uLocalSize,idRemote,idLocal);
}
HRESULT CapsCtl::GetPublicDecodeParams(LPVOID pBufOut, UINT uBufSize, VIDEO_FORMAT_ID id)
{
LPIH323MediaCap pMediaCap = FindHostForID(id);
if(!pMediaCap)
return CAPS_E_INVALID_PARAM;
return pMediaCap->GetPublicDecodeParams (pBufOut,uBufSize,id);
}
HRESULT CapsCtl::GetDecodeParams(PCC_RX_CHANNEL_REQUEST_CALLBACK_PARAMS pChannelParams,DWORD * pFormatID, LPVOID lpvBuf, UINT uBufSize)
{
LPIH323MediaCap pMediaCap = FindHostForMediaType(pChannelParams->pChannelCapability);
if(!pMediaCap)
return CAPS_E_INVALID_PARAM;
return pMediaCap->GetDecodeParams (pChannelParams,pFormatID,lpvBuf,uBufSize);
}
HRESULT CapsCtl::ResolveToLocalFormat(MEDIA_FORMAT_ID FormatIDLocal,
MEDIA_FORMAT_ID * pFormatIDRemote)
{
LPIH323MediaCap pMediaCap = FindHostForID(FormatIDLocal);
if(!pMediaCap)
return CAPS_E_INVALID_PARAM;
return pMediaCap->ResolveToLocalFormat (FormatIDLocal,pFormatIDRemote);
}
UINT CapsCtl::GetSimCapBufSize (BOOL bRxCaps)
{
UINT uSize;
// get size of cached advertised sets if it exists and more than one media
// type is enabled for publication
if(bAudioPublicize && bVideoPublicize && pAdvertisedSets)
{
// use size of cached buffer
uSize = uAdvertizedSize;
}
else
{
// calculate size of capability descriptors and simultaneous capability structures.
#pragma message ("Figure out the size this needs to be...")
#define NUMBER_TERMCAP_DESCRIPTORS 1
uSize = sizeof(H245_TOTCAPDESC_T) * NUMBER_TERMCAP_DESCRIPTORS+
sizeof (CC_TERMCAPDESCRIPTORS)+NUMBER_TERMCAP_DESCRIPTORS*
sizeof (H245_TOTCAPDESC_T *);
}
return uSize;
}
UINT CapsCtl::GetNumCaps(BOOL bRXCaps)
{
UINT u=0;
if(pAudCaps && bAudioPublicize)
{
u = pAudCaps->GetNumCaps(bRXCaps);
}
if(pVidCaps && bVideoPublicize)
{
u += pVidCaps->GetNumCaps(bRXCaps);
}
if(bT120Publicize)
u++;
return u;
}
UINT CapsCtl::GetLocalSendParamSize(MEDIA_FORMAT_ID dwID)
{
LPIH323MediaCap pMediaCap = FindHostForID(dwID);
if(!pMediaCap)
return 0;
return (pMediaCap->GetLocalSendParamSize(dwID));
}
UINT CapsCtl::GetLocalRecvParamSize(PCC_TERMCAP pCapability)
{
LPIH323MediaCap pMediaCap = FindHostForMediaType(pCapability);
if(!pMediaCap)
return 0;
return (pMediaCap->GetLocalRecvParamSize(pCapability));
}
STDMETHODIMP CapsCtl::GetEncodeFormatDetails(MEDIA_FORMAT_ID FormatID, VOID **ppFormat, UINT *puSize)
{
LPIH323MediaCap pMediaCap = FindHostForID(FormatID);
if(!pMediaCap)
{
*ppFormat = NULL;
*puSize = 0;
return E_INVALIDARG;
}
return pMediaCap->GetEncodeFormatDetails (FormatID, ppFormat, puSize);
}
STDMETHODIMP CapsCtl::GetDecodeFormatDetails(MEDIA_FORMAT_ID FormatID, VOID **ppFormat, UINT *puSize)
{
LPIH323MediaCap pMediaCap = FindHostForID(FormatID);
if(!pMediaCap)
{
*ppFormat = NULL;
*puSize = 0;
return E_INVALIDARG;
}
return pMediaCap->GetDecodeFormatDetails (FormatID, ppFormat, puSize);
}
//
// EnableMediaType controls whether or not capabilities for that media type
// are publicized. In a general implementation (next version?) w/ arbitrary
// number of media types, each of the media capability objects would keep
// track of their own state. This version of Capsctl tracks h323 audio and
// video only
//
HRESULT CapsCtl::EnableMediaType(BOOL bEnable, LPGUID pGuid)
{
if(!pGuid)
return CAPS_E_INVALID_PARAM;
if(*pGuid == MEDIA_TYPE_H323AUDIO)
{
bAudioPublicize = bEnable;
}
else if (*pGuid == MEDIA_TYPE_H323VIDEO)
{
bVideoPublicize = bEnable;
}
else
{
return CAPS_E_INVALID_PARAM;
}
return hrSuccess;
}
//
// Build the PCC_TERMCAPDESCRIPTORS list that we will advertise.
//
// puAudioFormatList/puVideoFormatList MUST BE sorted by preference!
//
//
HRESULT CapsCtl::AddCombinedEntry (MEDIA_FORMAT_ID *puAudioFormatList,UINT uAudNumEntries,MEDIA_FORMAT_ID *puVideoFormatList, UINT uVidNumEntries,DWORD *pIDOut)
{
static USHORT dwLastIDUsed;
DWORD x,y;
BOOL bAllEnabled=TRUE,bRecv,bSend;
unsigned short Length =0;
*pIDOut= (ULONG )CCO_E_SYSTEM_ERROR;
//Validate the Input
if ((!puAudioFormatList && uAudNumEntries > 0 ) || (!puVideoFormatList && uVidNumEntries > 0 ) || (uVidNumEntries == 0 && uAudNumEntries == 0 )) {
//What error code should we return here?
return CCO_E_SYSTEM_ERROR;
}
for (x=0;x<uAudNumEntries;x++)
{
ASSERT(pAudCaps);
pAudCaps->IsFormatEnabled (puAudioFormatList[x],&bRecv,&bSend);
bAllEnabled &= bRecv;
}
for (x=0;x<uVidNumEntries;x++) {
ASSERT(pVidCaps);
pVidCaps->IsFormatEnabled (puAudioFormatList[x],&bRecv,&bSend);
bAllEnabled &= bRecv;
}
if (!bAllEnabled) {
return CCO_E_INVALID_PARAM;
}
if (uAudNumEntries > H245_MAX_ALTCAPS || uVidNumEntries > H245_MAX_ALTCAPS) {
DEBUGMSG (1,("WARNING: Exceeding callcontrol limits!! \r\n"));
return CCO_E_INVALID_PARAM;
}
//If this is the first call, allocate space
if (!pAdvertisedSets){
pAdvertisedSets=(PCC_TERMCAPDESCRIPTORS)MemAlloc (sizeof (CC_TERMCAPDESCRIPTORS));
if (!pAdvertisedSets){
//Error code?
return CCO_E_SYSTEM_ERROR;
}
uAdvertizedSize = sizeof (CC_TERMCAPDESCRIPTORS);
//Allocate space of NUM_SIMCAP_SETS
pAdvertisedSets->pTermCapDescriptorArray=(H245_TOTCAPDESC_T **)
MemAlloc (sizeof (H245_TOTCAPDESC_T *)*NUM_SIMCAP_SETS);
if (!pAdvertisedSets->pTermCapDescriptorArray) {
//Error code?
return CCO_E_SYSTEM_ERROR;
}
//Update the indicies
uAdvertizedSize += sizeof (H245_TOTCAPDESC_T *)*NUM_SIMCAP_SETS;
dwNumInUse=NUM_SIMCAP_SETS;
pAdvertisedSets->wLength=0;
}
//Find an Index to use.
for (x=0;x<pAdvertisedSets->wLength;x++){
if (pAdvertisedSets->pTermCapDescriptorArray[x] == NULL){
break;
}
}
//Did we find space, or do we need a new one?
if (x >= dwNumInUse) {
//Increment the number in use
dwNumInUse++;
PVOID pTempTermCapDescriptorArray = NULL;
pTempTermCapDescriptorArray = MemReAlloc(pAdvertisedSets->pTermCapDescriptorArray, sizeof(H245_TOTCAPDESC_T *)*(dwNumInUse));
if(pTempTermCapDescriptorArray)
{
pAdvertisedSets->pTermCapDescriptorArray = (H245_TOTCAPDESC_T **)pTempTermCapDescriptorArray;
}
else
{
return CCO_E_SYSTEM_ERROR;
}
uAdvertizedSize += (sizeof (H245_TOTCAPDESC_T *)*(dwNumInUse))+sizeof (CC_TERMCAPDESCRIPTORS);
//Index is 0 based, point at the new entry
x=dwNumInUse-1;
}
//x is now the element we are using. Allocate space for a TermCapDescriptorArray
pAdvertisedSets->pTermCapDescriptorArray[x]=(H245_TOTCAPDESC_T *)MemAlloc (sizeof (H245_TOTCAPDESC_T));
if (!pAdvertisedSets->pTermCapDescriptorArray[x]){
return CCO_E_SYSTEM_ERROR;
}
uAdvertizedSize += sizeof (H245_TOTCAPDESC_T);
//Need to update the SetID. (start at 1)...
pAdvertisedSets->pTermCapDescriptorArray[x]->CapDescId=++dwLastIDUsed;
//Set the # of sets
if((m_localT120cap != INVALID_MEDIA_FORMAT) && bT120Publicize)
Length++;
if(uVidNumEntries)
Length++;
if(uAudNumEntries)
Length++;
pAdvertisedSets->pTermCapDescriptorArray[x]->CapDesc.Length= Length;
//Copy the Audio into SimCapArray[0], Video into SimCapArray[1] (if both)
if ((uVidNumEntries > 0 && uAudNumEntries > 0)) {
pAdvertisedSets->pTermCapDescriptorArray[x]->CapDesc.SimCapArray[0].Length=(unsigned short)uAudNumEntries;
pAdvertisedSets->pTermCapDescriptorArray[x]->CapDesc.SimCapArray[1].Length=(unsigned short)uVidNumEntries;
if((m_localT120cap != INVALID_MEDIA_FORMAT) && bT120Publicize)
pAdvertisedSets->pTermCapDescriptorArray[x]->CapDesc.SimCapArray[2].Length=1;
//Copy the format IDs
for (y=0;y<uAudNumEntries;y++) {
pAdvertisedSets->pTermCapDescriptorArray[x]->CapDesc.SimCapArray[0].AltCaps[y]=(USHORT)puAudioFormatList[y];
}
for (y=0;y<uVidNumEntries;y++) {
pAdvertisedSets->pTermCapDescriptorArray[x]->CapDesc.SimCapArray[1].AltCaps[y]=(USHORT)puVideoFormatList[y];
}
if((m_localT120cap != INVALID_MEDIA_FORMAT) && bT120Publicize)
pAdvertisedSets->pTermCapDescriptorArray[x]->CapDesc.SimCapArray[2].AltCaps[0]= (H245_CAPID_T)m_localT120cap;
} else {
if (uAudNumEntries > 0) {
pAdvertisedSets->pTermCapDescriptorArray[x]->CapDesc.SimCapArray[0].Length=(unsigned short)uAudNumEntries;
if((m_localT120cap != INVALID_MEDIA_FORMAT) && bT120Publicize)
pAdvertisedSets->pTermCapDescriptorArray[x]->CapDesc.SimCapArray[1].Length=1;
//Copy Audio only
for (y=0;y<uAudNumEntries;y++) {
pAdvertisedSets->pTermCapDescriptorArray[x]->CapDesc.SimCapArray[0].AltCaps[y]=(USHORT)puAudioFormatList[y];
}
if((m_localT120cap != INVALID_MEDIA_FORMAT) && bT120Publicize)
pAdvertisedSets->pTermCapDescriptorArray[x]->CapDesc.SimCapArray[1].AltCaps[0]= (H245_CAPID_T)m_localT120cap;
} else {
pAdvertisedSets->pTermCapDescriptorArray[x]->CapDesc.SimCapArray[0].Length=(unsigned short)uVidNumEntries;
if((m_localT120cap != INVALID_MEDIA_FORMAT) && bT120Publicize)
pAdvertisedSets->pTermCapDescriptorArray[x]->CapDesc.SimCapArray[1].Length=1;
//copy video entries
for (y=0;y<uVidNumEntries;y++) {
pAdvertisedSets->pTermCapDescriptorArray[x]->CapDesc.SimCapArray[0].AltCaps[y]=(USHORT)puVideoFormatList[y];
}
if((m_localT120cap != INVALID_MEDIA_FORMAT) && bT120Publicize)
pAdvertisedSets->pTermCapDescriptorArray[x]->CapDesc.SimCapArray[1].AltCaps[0]= (H245_CAPID_T)m_localT120cap;
}
}
//Need to update the wLength
pAdvertisedSets->wLength++;
*pIDOut=dwLastIDUsed;
return hrSuccess;
}
HRESULT CapsCtl::RemoveCombinedEntry (DWORD ID)
{
DWORD x;
if (!pAdvertisedSets) {
return CAPS_E_INVALID_PARAM;
}
for (x=0;x<dwNumInUse;x++) {
if (pAdvertisedSets->pTermCapDescriptorArray[x]) {
if (pAdvertisedSets->pTermCapDescriptorArray[x]->CapDescId == ID) {
//Found the one to remove
MemFree ((VOID *)pAdvertisedSets->pTermCapDescriptorArray[x]);
uAdvertizedSize -= sizeof (H245_TOTCAPDESC_T *);
if (x != (dwNumInUse -1)) {
//Not the last one, swap the two pointers
pAdvertisedSets->pTermCapDescriptorArray[x]=pAdvertisedSets->pTermCapDescriptorArray[dwNumInUse-1];
pAdvertisedSets->pTermCapDescriptorArray[dwNumInUse-1]=NULL;
}
//Decrement the number in use, and set the wLengthField
dwNumInUse--;
pAdvertisedSets->wLength--;
return hrSuccess;
}
}
}
//Shouldn't get here, unless it was not found.
return CAPS_E_NOCAPS;
}
// Given a sized list of capability IDs (pointer to array of H245_CAPID_T)
// and a sized list of alternate capabilities (AltCaps) within a single simultaneous
// capability set, (pointer to an array of pointers to H245_SIMCAP_T)
// Determine if the entire list of capability IDs can simultaneously coexist
// with respect to the given set of AltCaps.
BOOL CapsCtl::AreSimCaps(
H245_CAPID_T* pIDArray, UINT uIDArraySize,
H245_SIMCAP_T **ppAltCapArray,UINT uAltCapArraySize)
{
UINT i, u;
SHORT j;
BOOL bSim;
H245_SIMCAP_T *pAltCapEntry, *pFirstAltCapEntry;
// If there are fewer AltCaps than capabilities, doom is obvious. Don't bother searching.
if(uAltCapArraySize < uIDArraySize)
return FALSE;
// find an altcaps entry containing the first ID in the list
for (i=0;i<uAltCapArraySize;i++)
{
pAltCapEntry = *(ppAltCapArray+i);
// scan this altcaps entry for a matching ID
for(j=0;j<pAltCapEntry->Length;j++)
{
if(*pIDArray == pAltCapEntry->AltCaps[j])
{
// found a spot for this capability!
if(uIDArraySize ==1)
return TRUE; // Done! all the capabilities have been found to coexist
// Otherwise, look for the next capability in the *remaining* AltCaps
// *This* AltCaps contains the capability we were looking for
// So, we "used up" this AltCaps and can't select from it anymore
// Pack the array of H245_SIMCAP_T pointers in place so that
// "used" entries are at the beginning and "unused" at the end
// (a la shell sort swap pointers)
if(i != 0) // if not already the same, swap
{
pFirstAltCapEntry = *ppAltCapArray;
*ppAltCapArray = pAltCapEntry;
*(ppAltCapArray+i) = pFirstAltCapEntry;
}
// continue the quest using the remaining capabilities
// and the remaining AltCaps
bSim = AreSimCaps(pIDArray + 1, uIDArraySize - 1,
ppAltCapArray + 1, uAltCapArraySize - 1);
if(bSim)
{
return bSim;// success
}
else // why not? Either a fit does not exist (common), or the altcaps contain
// an odd pattern of multiple instances of some capability IDs, and another
// search order *might* fit. Do not blindly try all permutations of search
// order.
{
// If it failed simply because the recently grabbed slot in the altcaps
// (the one in *(ppAltCapArray+i)) could have been needed by subsequent
// capability IDs, give this one up and look for another instance.
// If not, we know for sure that the n! approach will not yield
// fruit and can be avoided.
for(u=1;(bSim == FALSE)&&(u<uAltCapArraySize);u++)
{
for(j=0;(bSim == FALSE)&&(j<pAltCapEntry->Length);j++)
{ // another capability needed the altcaps we grabbed ?
if(*(pIDArray+u) == pAltCapEntry->AltCaps[j])
{
bSim=TRUE;
break; // look no more here, bail to try again because a fit *might* exist
}
}
}
if(bSim) // going to continue searching - Swap pointers back if they were swapped above
{
if(i != 0) // if not the same, swap back
{
*ppAltCapArray = *(ppAltCapArray+i);
*(ppAltCapArray+i) = pAltCapEntry;
}
break; // next i
}
else // don't waste CPU - a fit does not exist
{
return bSim;
}
}
}
}
}
return FALSE;
}
// Given a sized list of capability IDs (pointer to array of H245_CAPID_T)
// and a list of simultaneous capabilities, try each simultaneous capability
// and determine if the entire list of capability IDs can simultaneously coexist.
BOOL CapsCtl::TestSimultaneousCaps(H245_CAPID_T* pIDArray, UINT uIDArraySize,
PCC_TERMCAPDESCRIPTORS pTermCaps)
{
int iSimSet, iAltSet;
BOOL bResolved = FALSE;
H245_SIMCAP_T * pAltCapArray[H245_MAX_SIMCAPS];
if (!pAdvertisedSets)
return(TRUE);
// try each independent local SimCaps set (each descriptor) until success
for (iSimSet=0; (bResolved == FALSE) && (iSimSet < pTermCaps->wLength);iSimSet++)
{
// EXTRA STEP:
// Build a sortable representation of the AltCaps set. This step will not be necessary if
// and when we change the native representation of a capability descriptor to a variable
// length list of pointers to AltCaps. In the meantime, we know that there are no more
// than H245_MAX_SIMCAPS AltCaps in this SimCaps. This is imposed by the 2 dimensional
// arrays of hardcoded size forced upon us by CALLCONT.DLL.
for (iAltSet=0;iAltSet < pTermCaps->pTermCapDescriptorArray[iSimSet]->CapDesc.Length;iAltSet++)
{
pAltCapArray[iAltSet] = &pTermCaps->pTermCapDescriptorArray[iSimSet]->CapDesc.SimCapArray[iAltSet];
}
// do the work
bResolved = AreSimCaps(pIDArray, uIDArraySize,
(H245_SIMCAP_T **)&pAltCapArray,
MAKELONG(pTermCaps->pTermCapDescriptorArray[iSimSet]->CapDesc.Length, 0));
}
return bResolved;
}
// Function: CapsCtl::ResolvePermutations(PRES_CONTEXT pResContext, UINT uNumFixedColumns)
//
// This functions as both a combination generator and a validation mechanism for the
// combinations it generates.
//
// Given a pointer to a resolution context and the number of fixed (i.e. not permutable,
// if "permutable" is even a real word) columns, generate one combination at a time.
// Try each combination until a working combination is found or until all combinations
// have been tried.
//
// The resolution context structure contains a variable number of columns of variable
// length media format ID lists. Each column tracks its current index. When this
// function returns TRUE, the winning combination is indicated by the current column
// indices.
//
// The caller can control which combinations are tried first by arranging the columns
// in descending importance.
//
// Incremental searches can be performed without redundant comparisons by adding 1 format
// at a time to a column, arranging the column order so that the appended column is
// first, and "fixing" that one column at the newly added format. For example,
// some calling function could force evaluations on a round-robin column basis by
// calling this function inside a loop which does the following:
// 1 - adds one format at a time to the rightmost column and sets the current index
// of that column to the new entry
// 2 - rotates the column order so that the rightmost column is now the leftmost
// 3 - fixing the new leftmost column before calling this function again
// The result will be that only the permutations which contain the newly added format
// will be generated.
BOOL CapsCtl::ResolvePermutations(PRES_CONTEXT pResContext, UINT uNumFixedColumns)
{
RES_PAIR *pResolvedPair;
BOOL bResolved = FALSE;
UINT i, uColumns;
UINT uPairIndex;
// converge on one combination in the permutation
if(uNumFixedColumns != pResContext->uColumns)
{
RES_PAIR_LIST *pThisColumn;
// take the first non-fixed column, make that column fixed and
// iterate on it (loop through indices), and try each sub-permutation
// of remaining columns. (until success or all permutations tried)
pThisColumn = *(pResContext->ppPairLists+uNumFixedColumns);
for (i=0; (bResolved == FALSE) && (i<pThisColumn->uSize); i++)
{
pThisColumn->uCurrentIndex = i;
bResolved = ResolvePermutations(pResContext, uNumFixedColumns+1);
}
return bResolved;
}
else
{
// Bottomed out on the final column. Test the viability of this combination
// Build array of local IDs that contians the combination and test the
// combination against local simultaneous capabilities, then against
// remote simultaneous capabilities
// NOTE: be sure to skip empty columns (which represent unresolvable
// or unsupported/nonexistent media types or unsupported additional
// instances of media types)
for(i=0, uColumns=0;i<pResContext->uColumns;i++)
{
if(((*pResContext->ppPairLists)+i)->uSize)
{
// get index (row #) for this column
uPairIndex = ((*pResContext->ppPairLists)+i)->uCurrentIndex;
// get the row
pResolvedPair = ((*pResContext->ppPairLists)+i)->pResolvedPairs+uPairIndex;
// add the ID to the array
*(pResContext->pIDScratch+uColumns) = (H245_CAPID_T)pResolvedPair->idPublicLocal;
uColumns++;
}
// else empty column
}
// Determine if this combination can exist simultaneously
if(TestSimultaneousCaps(pResContext->pIDScratch,
uColumns, pResContext->pTermCapsLocal))
{
// now test remote
// build array of remote IDs and test those against remote
// simultaneous capabilities
for(i=0, uColumns=0;i<pResContext->uColumns;i++)
{
if(((*pResContext->ppPairLists)+i)->uSize)
{
// get index (row #) for this column
uPairIndex = ((*pResContext->ppPairLists)+i)->uCurrentIndex;
// get the row
pResolvedPair = ((*pResContext->ppPairLists)+i)->pResolvedPairs+uPairIndex;
// add the ID to the array
*(pResContext->pIDScratch+uColumns) =(H245_CAPID_T) pResolvedPair->idRemote;
uColumns++;
}
// else empty column
}
bResolved = TestSimultaneousCaps(pResContext->pIDScratch,
uColumns, pResContext->pTermCapsRemote);
}
return bResolved;
// if(bResolved == TRUE)
// The resolved combination of pairs is indicated by the current indices
// of **ppPairList;
}
}
//
// Given a counted list of desired instances of media, produce an output array of
// resolved media format IDs which correspond to the input media type IDs.
// This function returns success if at least one media instance is resolved.
// When an instance of media is unresolveable, the output corresponding to that
// instance contains the value INVALID_MEDIA_FORMAT for local and remote media
// format IDs.
//
// The input is treated as being in preferential order: permutations of the latter
// media type instance are varied first. If all permutations do not yield success,
// then one media type instance at a time is removed from the end.
//
HRESULT CapsCtl::ResolveFormats (LPGUID pMediaGuidArray, UINT uNumMedia,
PRES_PAIR pResOutput)
{
HRESULT hr = hrSuccess;
PRES_PAIR_LIST pResColumnArray = NULL;
PRES_PAIR_LIST *ppPairLists;
RES_PAIR *pResPair;
PRES_CONTEXT pResContext;
LPIH323MediaCap pMediaResolver;
UINT i;
UINT uMaxFormats = 0;
UINT uFixedColumns =0;
UINT uFailedMediaCount = 0;
BOOL bResolved = FALSE;
RES_PAIR UnresolvedPair = {INVALID_MEDIA_FORMAT, INVALID_MEDIA_FORMAT, INVALID_MEDIA_FORMAT};
// create a context structure for the resolution
pResContext = (PRES_CONTEXT)MemAlloc(sizeof(RES_CONTEXT)+ (uNumMedia*sizeof(H245_CAPID_T)));
if(!pResContext)
{
hr = CAPS_E_NOMEM;
goto ERROR_OUT;
}
// initialize resolution context
pResContext->uColumns = 0;
pResContext->pIDScratch = (H245_CAPID_T*)(pResContext+1);
pResContext->pTermCapsLocal = pAdvertisedSets;
pResContext->pTermCapsRemote = pRemAdvSets;
// allocate array of RES_PAIR_LIST (one per column/media type) and
// array of pointers to same
pResColumnArray = (PRES_PAIR_LIST)MemAlloc((sizeof(RES_PAIR_LIST) * uNumMedia)
+ (sizeof(PRES_PAIR_LIST) * uNumMedia));
if(!pResColumnArray)
{
hr = CAPS_E_NOMEM;
goto ERROR_OUT;
}
pResContext->ppPairLists = ppPairLists = (PRES_PAIR_LIST*)(pResColumnArray+uNumMedia);
// build columns of media capabilities
for(i=0;i<uNumMedia;i++)
{
// build array of pointers to RES_PAIR_LIST
*(ppPairLists+i) = pResColumnArray+i;
// initialize RES_PAIR_LIST members
(pResColumnArray+i)->pResolvedPairs = NULL;
(pResColumnArray+i)->uSize =0;
(pResColumnArray+i)->uCurrentIndex = 0;
// Get resolver for this media. Special case: there is no T120 resolver.
// T120 caps are handled right here in this object
if(MEDIA_TYPE_H323_T120 == *(pMediaGuidArray+i))
{
pMediaResolver = NULL;
if((m_localT120cap != INVALID_MEDIA_FORMAT) &&(m_remoteT120cap != INVALID_MEDIA_FORMAT) )
{
(pResColumnArray+i)->uSize =1;
uMaxFormats = 1; // only one T.120 cap
pResPair = (pResColumnArray+i)->pResolvedPairs =
(RES_PAIR *)MemAlloc(uMaxFormats * sizeof(RES_PAIR));
if(!pResPair)
{
hr = CAPS_E_NOMEM;
goto ERROR_OUT;
}
//
pResPair->idLocal = m_localT120cap;
pResPair->idRemote = m_remoteT120cap;
pResPair->idPublicLocal = pResPair->idLocal;
}
}
else
{
pMediaResolver = FindHostForMediaGuid(pMediaGuidArray+i);
}
pResContext->uColumns++;
(pResColumnArray+i)->pMediaResolver = pMediaResolver;
if(pMediaResolver)
{
uMaxFormats = pMediaResolver->GetNumCaps(FALSE); // get transmit format count
if(uMaxFormats)
{
pResPair = (pResColumnArray+i)->pResolvedPairs =
(RES_PAIR *)MemAlloc(uMaxFormats * sizeof(RES_PAIR));
if(!pResPair)
{
hr = CAPS_E_NOMEM;
goto ERROR_OUT;
}
// resolve the best choice for each media type (gotta start somewhere)
pResPair->idLocal = INVALID_MEDIA_FORMAT;
pResPair->idRemote = INVALID_MEDIA_FORMAT;
hr=pMediaResolver->ResolveEncodeFormat (&pResPair->idLocal,&pResPair->idRemote);
if(!HR_SUCCEEDED(hr))
{
if((hr == CAPS_W_NO_MORE_FORMATS)
|| (hr == CAPS_E_NOMATCH)
|| (hr == CAPS_E_NOCAPS))
{
// No resolved format for this media type. Remove this "column"
(pResColumnArray+i)->pResolvedPairs = NULL;
MemFree(pResPair);
(pResColumnArray+i)->uSize =0;
hr = hrSuccess;
}
else
{
goto ERROR_OUT;
}
}
else
{
// this column has one resolved format
pResPair->idPublicLocal = pMediaResolver->GetPublicID(pResPair->idLocal);
(pResColumnArray+i)->uSize =1;
}
}
// else // No formats exist for this media type. this "column" has zero size
}
}
// Special case test simultaneous caps for the most preferred combination:
uFixedColumns = pResContext->uColumns; // << make all columns fixed
bResolved = ResolvePermutations(pResContext, uFixedColumns);
// if the single most preferred combination can't be used, need to handle
// the general case and try permutations until a workable combination is found
while(!bResolved)
{
// make one column at a time permutable, starting with the least-critical media
// type. (e.g. it would be typical for the last column to be video because
// audio+data are more important. Then we try less and less
// preferable video formats before doing anything that would degrade the audio)
if(uFixedColumns > 0) // if not already at the end of the rope...
{
uFixedColumns--; // make another column permutable
}
else
{
// wow - tried all permutations and still no luck ......
// nuke the least important remaining media type (e.g. try it w/o video)
if(pResContext->uColumns <= 1) // already down to one media type?
{
hr = CAPS_E_NOMATCH;
goto ERROR_OUT;
}
// Remove the end column (representing the least important media type)
// and try it with the remaining columns
uFixedColumns = --pResContext->uColumns; // one less column
// set the formats of the nuked column to the unresolved state
(pResColumnArray+uFixedColumns)->uSize =0;
(pResColumnArray+uFixedColumns)->uCurrentIndex =0;
pResPair = (pResColumnArray+uFixedColumns)->pResolvedPairs;
if (NULL != pResPair)
{
pResPair->idLocal = INVALID_MEDIA_FORMAT;
pResPair->idRemote = INVALID_MEDIA_FORMAT;
pResPair->idPublicLocal = INVALID_MEDIA_FORMAT;
}
uFailedMediaCount++; // track the nuking of a column to avoid
// redundantly grabbing all the formats again
// ... would not be here if all permutations
// had not been tried!
// reset the combination indices
for(i=0;i<uFixedColumns;i++)
{
(pResColumnArray+i)->uCurrentIndex = 0;
}
}
// get the rest of the formats for the last known fixed column, make that column
// permutable, etc.
pMediaResolver = (pResColumnArray+uFixedColumns)->pMediaResolver;
if(!pMediaResolver || ((pResColumnArray+uFixedColumns)->uSize ==0))
{
continue; // this media type has no further possibility
}
if(uFailedMediaCount ==0) // If all of the possible resolved pairs
// have not yet been obtained, get them!
{
// get resolved pair IDs for every mutual format of this media type
// first: get pointer to array of pair IDs, then use ResolveEncodeFormat()
// to fill up the array
pResPair = (pResColumnArray+uFixedColumns)->pResolvedPairs;
// Get total # of formats less the one that was already obtained
uMaxFormats = pMediaResolver->GetNumCaps(FALSE) -1;
while(uMaxFormats--) // never exceed the # of remaining local formats...
{
RES_PAIR *pResPairNext;
// recall that ResolveEncodeFormat parameters are I/O - the input
// is the local ID of the last resolved mutual format. (remote id
// is ignored as input). Fixup the input.
pResPairNext = pResPair+1;
// start where the previous resolve stopped
pResPairNext->idLocal = pResPair->idLocal;
// not necessary, ignored ->>> pResPairNext->idRemote = pResPair->idRemote
pResPair = pResPairNext;
hr=pMediaResolver->ResolveEncodeFormat (&pResPair->idLocal,&pResPair->idRemote);
if((hr == CAPS_W_NO_MORE_FORMATS)
|| (hr == CAPS_E_NOMATCH))
// got all of the formats, but not an error
{ // this is likely when less than 100% of local formats have a remote match
hr = hrSuccess;
break;
}
if(!HR_SUCCEEDED(hr))
goto ERROR_OUT;
// get the public ID of the local format (it's *usually* the same, but not always)
pResPair->idPublicLocal = pMediaResolver->GetPublicID(pResPair->idLocal);
// this column has another format - count it!
(pResColumnArray+uFixedColumns)->uSize++;
}
}
// now try the new permutations
bResolved = ResolvePermutations(pResContext, uFixedColumns);
}
if(bResolved)
{
// spew the output
for(i=0;i<uNumMedia;i++)
{
if((pResColumnArray+i)->uSize)
{
pResPair = (pResColumnArray+i)->pResolvedPairs
+ (pResColumnArray+i)->uCurrentIndex;
}
else
{
pResPair = &UnresolvedPair;
}
*(pResOutput+i) = *pResPair;
}
}
else
{
// if there was some error, preserve that error code,
if(HR_SUCCEEDED(hr))
// otherwise the error is....
hr = CAPS_E_NOMATCH;
}
ERROR_OUT: // well, the success case falls out here too
if(pResColumnArray)
{
for(i=0;i<uNumMedia;i++)
{
if((pResColumnArray+i)->pResolvedPairs)
MemFree((pResColumnArray+i)->pResolvedPairs);
}
MemFree(pResColumnArray);
}
if(pResContext)
{
MemFree(pResContext);
}
return hr;
}
HRESULT CapsCtl::ResetCombinedEntries (void)
{
DWORD x;
if (pAdvertisedSets)
{
for (x = 0; x < pAdvertisedSets->wLength; x++)
{
if (pAdvertisedSets->pTermCapDescriptorArray[x])
{
MemFree (pAdvertisedSets->pTermCapDescriptorArray[x]);
}
}
MemFree (pAdvertisedSets->pTermCapDescriptorArray);
pAdvertisedSets->wLength=0;
MemFree (pAdvertisedSets);
pAdvertisedSets = NULL;
}
if (pSetIDs)
{
MemFree(pSetIDs);
pSetIDs = NULL;
}
dwNumInUse=0;
uAdvertizedSize=0;
return hrSuccess;
}