windows-nt/Source/XPSP1/NT/enduser/netmeeting/av/callcont/confman.c
2020-09-26 16:20:57 +08:00

1616 lines
49 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/****************************************************************************
*
* $Archive: S:/STURGEON/SRC/CALLCONT/VCS/confman.c_v $
*
* INTEL Corporation Prorietary Information
*
* This listing is supplied under the terms of a license agreement
* with INTEL Corporation and may not be copied nor disclosed except
* in accordance with the terms of that agreement.
*
* Copyright (c) 1993-1994 Intel Corporation.
*
* $Revision: 1.91 $
* $Date: 04 Mar 1997 17:35:06 $
* $Author: MANDREWS $
*
* Deliverable:
*
* Abstract:
*
*
* Notes:
*
***************************************************************************/
#include "precomp.h"
#include "apierror.h"
#include "incommon.h"
#include "callcont.h"
#include "q931.h"
#include "ccmain.h"
#include "confman.h"
#include "ccutils.h"
#include "chanman.h"
#include "callman.h"
static BOOL bConferenceInited = FALSE;
static struct {
PCONFERENCE pHead;
LOCK Lock;
} ConferenceTable;
static struct {
CC_HCONFERENCE hConference;
LOCK Lock;
} ConferenceHandle;
CC_CONFERENCEID InvalidConferenceID;
HRESULT InitConferenceManager()
{
ASSERT(bConferenceInited == FALSE);
ConferenceTable.pHead = NULL;
InitializeLock(&ConferenceTable.Lock);
ConferenceHandle.hConference = CC_INVALID_HANDLE + 1;
InitializeLock(&ConferenceHandle.Lock);
memset(&InvalidConferenceID, 0, sizeof(InvalidConferenceID));
bConferenceInited = TRUE;
return CC_OK;
}
HRESULT DeInitConferenceManager()
{
PCONFERENCE pConference;
PCONFERENCE pNextConference;
if (bConferenceInited == FALSE)
return CC_OK;
pConference = ConferenceTable.pHead;
while (pConference != NULL) {
AcquireLock(&pConference->Lock);
pNextConference = pConference->pNextInTable;
FreeConference(pConference);
pConference = pNextConference;
}
DeleteLock(&ConferenceHandle.Lock);
DeleteLock(&ConferenceTable.Lock);
bConferenceInited = FALSE;
return CC_OK;
}
HRESULT _CreateLocalH245H2250MuxCapability(
PCONFERENCE pConference)
{
HRESULT status;
CC_TERMCAP TermCap;
struct MultipointCapability_mediaDistributionCapability RXMediaDistributionCapability;
struct MultipointCapability_mediaDistributionCapability TXMediaDistributionCapability;
struct MultipointCapability_mediaDistributionCapability RXTXMediaDistributionCapability;
ASSERT(pConference != NULL);
if (pConference->pLocalH245H2250MuxCapability != NULL)
H245FreeCap(pConference->pLocalH245H2250MuxCapability);
TermCap.Dir = H245_CAPDIR_LCLRXTX;
TermCap.DataType = H245_DATA_MUX;
TermCap.ClientType = H245_CLIENT_MUX_H2250;
TermCap.CapId = 0; // CapId = 0 is a special case for mux capabilities
TermCap.Cap.H245Mux_H2250.bit_mask = 0;
TermCap.Cap.H245Mux_H2250.maximumAudioDelayJitter = 60;
TermCap.Cap.H245Mux_H2250.receiveMultipointCapability.multicastCapability = (char)pConference->bMultipointCapable;
TermCap.Cap.H245Mux_H2250.receiveMultipointCapability.multiUniCastConference = FALSE;
TermCap.Cap.H245Mux_H2250.receiveMultipointCapability.mediaDistributionCapability = &RXMediaDistributionCapability;
TermCap.Cap.H245Mux_H2250.receiveMultipointCapability.mediaDistributionCapability->next = NULL;
TermCap.Cap.H245Mux_H2250.receiveMultipointCapability.mediaDistributionCapability->value.bit_mask = 0;
TermCap.Cap.H245Mux_H2250.receiveMultipointCapability.mediaDistributionCapability->value.centralizedControl = FALSE;
TermCap.Cap.H245Mux_H2250.receiveMultipointCapability.mediaDistributionCapability->value.distributedControl = (char)pConference->bMultipointCapable;
TermCap.Cap.H245Mux_H2250.receiveMultipointCapability.mediaDistributionCapability->value.centralizedAudio = FALSE;
TermCap.Cap.H245Mux_H2250.receiveMultipointCapability.mediaDistributionCapability->value.distributedAudio = (char)pConference->bMultipointCapable;
TermCap.Cap.H245Mux_H2250.receiveMultipointCapability.mediaDistributionCapability->value.centralizedVideo = FALSE;
TermCap.Cap.H245Mux_H2250.receiveMultipointCapability.mediaDistributionCapability->value.distributedVideo = (char)pConference->bMultipointCapable;
TermCap.Cap.H245Mux_H2250.receiveMultipointCapability.mediaDistributionCapability->value.centralizedData = NULL;
TermCap.Cap.H245Mux_H2250.receiveMultipointCapability.mediaDistributionCapability->value.distributedData = NULL;
TermCap.Cap.H245Mux_H2250.transmitMultipointCapability.multicastCapability = (char)pConference->bMultipointCapable;
TermCap.Cap.H245Mux_H2250.transmitMultipointCapability.multiUniCastConference = FALSE;
TermCap.Cap.H245Mux_H2250.transmitMultipointCapability.mediaDistributionCapability = &TXMediaDistributionCapability;
TermCap.Cap.H245Mux_H2250.transmitMultipointCapability.mediaDistributionCapability->next = NULL;
TermCap.Cap.H245Mux_H2250.transmitMultipointCapability.mediaDistributionCapability->value.bit_mask = 0;
TermCap.Cap.H245Mux_H2250.transmitMultipointCapability.mediaDistributionCapability->value.centralizedControl = FALSE;
TermCap.Cap.H245Mux_H2250.transmitMultipointCapability.mediaDistributionCapability->value.distributedControl = (char)pConference->bMultipointCapable;
TermCap.Cap.H245Mux_H2250.transmitMultipointCapability.mediaDistributionCapability->value.centralizedAudio = FALSE;
TermCap.Cap.H245Mux_H2250.transmitMultipointCapability.mediaDistributionCapability->value.distributedAudio = (char)pConference->bMultipointCapable;
TermCap.Cap.H245Mux_H2250.transmitMultipointCapability.mediaDistributionCapability->value.centralizedVideo = FALSE;
TermCap.Cap.H245Mux_H2250.transmitMultipointCapability.mediaDistributionCapability->value.distributedVideo = (char)pConference->bMultipointCapable;
TermCap.Cap.H245Mux_H2250.transmitMultipointCapability.mediaDistributionCapability->value.centralizedData = NULL;
TermCap.Cap.H245Mux_H2250.transmitMultipointCapability.mediaDistributionCapability->value.distributedData = NULL;
TermCap.Cap.H245Mux_H2250.rcvAndTrnsmtMltpntCpblty.multicastCapability = (char)pConference->bMultipointCapable;
TermCap.Cap.H245Mux_H2250.rcvAndTrnsmtMltpntCpblty.multiUniCastConference = FALSE;
TermCap.Cap.H245Mux_H2250.rcvAndTrnsmtMltpntCpblty.mediaDistributionCapability = &RXTXMediaDistributionCapability;
TermCap.Cap.H245Mux_H2250.rcvAndTrnsmtMltpntCpblty.mediaDistributionCapability->next = NULL;
TermCap.Cap.H245Mux_H2250.rcvAndTrnsmtMltpntCpblty.mediaDistributionCapability->value.bit_mask = 0;
TermCap.Cap.H245Mux_H2250.rcvAndTrnsmtMltpntCpblty.mediaDistributionCapability->value.centralizedControl = FALSE;
TermCap.Cap.H245Mux_H2250.rcvAndTrnsmtMltpntCpblty.mediaDistributionCapability->value.distributedControl = (char)pConference->bMultipointCapable;
TermCap.Cap.H245Mux_H2250.rcvAndTrnsmtMltpntCpblty.mediaDistributionCapability->value.centralizedAudio = FALSE;
TermCap.Cap.H245Mux_H2250.rcvAndTrnsmtMltpntCpblty.mediaDistributionCapability->value.distributedAudio = (char)pConference->bMultipointCapable;
TermCap.Cap.H245Mux_H2250.rcvAndTrnsmtMltpntCpblty.mediaDistributionCapability->value.centralizedVideo = FALSE;
TermCap.Cap.H245Mux_H2250.rcvAndTrnsmtMltpntCpblty.mediaDistributionCapability->value.distributedVideo = (char)pConference->bMultipointCapable;
TermCap.Cap.H245Mux_H2250.rcvAndTrnsmtMltpntCpblty.mediaDistributionCapability->value.centralizedData = NULL;
TermCap.Cap.H245Mux_H2250.rcvAndTrnsmtMltpntCpblty.mediaDistributionCapability->value.distributedData = NULL;
TermCap.Cap.H245Mux_H2250.mcCapability.centralizedConferenceMC = FALSE;
TermCap.Cap.H245Mux_H2250.mcCapability.decentralizedConferenceMC = (char)pConference->bMultipointCapable;
TermCap.Cap.H245Mux_H2250.rtcpVideoControlCapability = FALSE;
TermCap.Cap.H245Mux_H2250.mediaPacketizationCapability.bit_mask = 0;
TermCap.Cap.H245Mux_H2250.mediaPacketizationCapability.h261aVideoPacketization = FALSE;
status = H245CopyCap(&pConference->pLocalH245H2250MuxCapability,
&TermCap);
return status;
}
HRESULT _AddConferenceToTable( PCONFERENCE pConference)
{
PCONFERENCE pCurrent;
ASSERT(pConference != NULL);
ASSERT(pConference->hConference != CC_INVALID_HANDLE);
ASSERT(pConference->bInTable == FALSE);
AcquireLock(&ConferenceTable.Lock);
// If a valid non-zero conference ID was specified, make sure
// there's not a duplicate in the conference table
if (!EqualConferenceIDs(&pConference->ConferenceID, &InvalidConferenceID)) {
pCurrent = ConferenceTable.pHead;
while (pCurrent != NULL) {
if (EqualConferenceIDs(&pCurrent->ConferenceID,
&pConference->ConferenceID)) {
RelinquishLock(&ConferenceTable.Lock);
return CC_DUPLICATE_CONFERENCE_ID;
}
pCurrent = pCurrent->pNextInTable;
}
}
pConference->pNextInTable = ConferenceTable.pHead;
pConference->pPrevInTable = NULL;
if (ConferenceTable.pHead != NULL)
ConferenceTable.pHead->pPrevInTable = pConference;
ConferenceTable.pHead = pConference;
pConference->bInTable = TRUE;
RelinquishLock(&ConferenceTable.Lock);
return CC_OK;
}
HRESULT _RemoveConferenceFromTable( PCONFERENCE pConference)
{
CC_HCONFERENCE hConference;
BOOL bTimedOut;
ASSERT(pConference != NULL);
ASSERT(pConference->bInTable == TRUE);
// Caller must have a lock on the conference object;
// in order to avoid deadlock, we must:
// 1. unlock the conference object,
// 2. lock the ConferenceTable,
// 3. locate the conference object in the ConferenceTable (note that
// after step 2, the conference object may be deleted from the
// ConferenceTable by another thread),
// 4. lock the conference object (someone else may have the lock)
// 5. remove the conference object from the ConferenceTable,
// 6. unlock the ConferenceTable
//
// The caller can now safely unlock and destroy the conference object,
// since no other thread will be able to find the object (its been
// removed from the ConferenceTable), and therefore no other thread will
// be able to lock it.
// Save the conference handle; its the only way to look up
// the conference object in the ConferenceTable. Note that we
// can't use pConference to find the conference object, since
// pConference may be free'd up, and another conference object
// allocated at the same address
hConference = pConference->hConference;
// step 1
RelinquishLock(&pConference->Lock);
step2:
// step 2
AcquireLock(&ConferenceTable.Lock);
// step 3
pConference = ConferenceTable.pHead;
while ((pConference != NULL) && (pConference->hConference != hConference))
pConference = pConference->pNextInTable;
if (pConference != NULL) {
// step 4
AcquireTimedLock(&pConference->Lock,10,&bTimedOut);
if (bTimedOut) {
RelinquishLock(&ConferenceTable.Lock);
Sleep(0);
goto step2;
}
// step 5
if (pConference->pPrevInTable == NULL)
ConferenceTable.pHead = pConference->pNextInTable;
else
pConference->pPrevInTable->pNextInTable = pConference->pNextInTable;
if (pConference->pNextInTable != NULL)
pConference->pNextInTable->pPrevInTable = pConference->pPrevInTable;
pConference->pNextInTable = NULL;
pConference->pPrevInTable = NULL;
pConference->bInTable = FALSE;
}
// step 6
RelinquishLock(&ConferenceTable.Lock);
if (pConference == NULL)
return CC_BAD_PARAM;
else
return CC_OK;
}
HRESULT _MakeConferenceHandle( PCC_HCONFERENCE phConference)
{
AcquireLock(&ConferenceHandle.Lock);
*phConference = ConferenceHandle.hConference++;
RelinquishLock(&ConferenceHandle.Lock);
return CC_OK;
}
HRESULT AllocateTerminalNumber( PCONFERENCE pConference,
H245_TERMINAL_LABEL_T *pH245TerminalLabel)
{
unsigned i, j;
BYTE bMask;
ASSERT(pConference != NULL);
ASSERT(pH245TerminalLabel != NULL);
ASSERT(pConference->ConferenceMode == MULTIPOINT_MODE);
ASSERT(pConference->tsMultipointController == TS_TRUE);
for (i = 0; i < NUM_TERMINAL_ALLOCATION_SLOTS; i++) {
bMask = 0x01;
if (pConference->TerminalNumberAllocation[i] != 0xFF) {
for (j = 0; j < 8; j++) {
if ((pConference->TerminalNumberAllocation[i] & bMask) == 0) {
pConference->TerminalNumberAllocation[i] |= bMask;
pH245TerminalLabel->mcuNumber = pConference->LocalParticipantInfo.ParticipantInfo.TerminalLabel.bMCUNumber;
pH245TerminalLabel->terminalNumber = (TerminalNumber)((i * 8) + j + 1);
return CC_OK;
}
bMask *= 2;
}
}
}
// No more terminal numbers are available for this conference
return CC_BAD_PARAM;
}
HRESULT FreeTerminalNumber( PCONFERENCE pConference,
BYTE bTerminalNumber)
{
unsigned i, j;
BYTE bMask;
ASSERT(pConference != NULL);
if (bTerminalNumber > NUM_TERMINAL_ALLOCATION_SLOTS * 8)
return CC_BAD_PARAM;
--bTerminalNumber;
i = bTerminalNumber / 8;
j = bTerminalNumber % 8;
bMask = (BYTE)(0x01 << j);
if ((pConference->TerminalNumberAllocation[i] & bMask) == 0)
return CC_BAD_PARAM;
pConference->TerminalNumberAllocation[i] &= ~bMask;
return CC_OK;
}
HRESULT AllocateChannelNumber( PCONFERENCE pConference,
WORD *pwChannelNumber)
{
unsigned i, j;
BYTE bMask;
ASSERT(pConference != NULL);
ASSERT(pwChannelNumber != NULL);
for (i = 0; i < NUM_CHANNEL_ALLOCATION_SLOTS; i++) {
bMask = 0x01;
if (pConference->ChannelNumberAllocation[i] != 0xFF) {
for (j = 0; j < 8; j++) {
if ((pConference->ChannelNumberAllocation[i] & bMask) == 0) {
pConference->ChannelNumberAllocation[i] |= bMask;
*pwChannelNumber = (WORD) (((i * 8) + j) +
(pConference->LocalParticipantInfo.ParticipantInfo.TerminalLabel.bMCUNumber << 8));
return CC_OK;
}
bMask *= 2;
}
}
}
// No more channel numbers are available for this conference
*pwChannelNumber = 0;
return CC_BAD_PARAM;
}
HRESULT FreeChannelNumber( PCONFERENCE pConference,
WORD wChannelNumber)
{
unsigned i, j;
BYTE bMask;
ASSERT(pConference != NULL);
wChannelNumber &= 0xFF;
if ((wChannelNumber > NUM_CHANNEL_ALLOCATION_SLOTS * 8) ||
(wChannelNumber == 0))
return CC_BAD_PARAM;
i = wChannelNumber / 8;
j = wChannelNumber % 8;
bMask = (BYTE)(0x01 << j);
if ((pConference->ChannelNumberAllocation[i] & bMask) == 0)
return CC_BAD_PARAM;
pConference->ChannelNumberAllocation[i] &= ~bMask;
return CC_OK;
}
HRESULT AllocAndLockConference( PCC_HCONFERENCE phConference,
PCC_CONFERENCEID pConferenceID,
BOOL bMultipointCapable,
BOOL bForceMultipointController,
PCC_TERMCAPLIST pLocalTermCapList,
PCC_TERMCAPDESCRIPTORS pLocalTermCapDescriptors,
PCC_VENDORINFO pVendorInfo,
PCC_OCTETSTRING pTerminalID,
DWORD_PTR dwConferenceToken,
CC_SESSIONTABLE_CONSTRUCTOR SessionTableConstructor,
CC_TERMCAP_CONSTRUCTOR TermCapConstructor,
CC_CONFERENCE_CALLBACK ConferenceCallback,
PPCONFERENCE ppConference)
{
WORD i;
HRESULT status;
TRISTATE tsMultipointController;
ASSERT(bConferenceInited == TRUE);
// all parameters should have been validated by the caller
ASSERT(phConference != NULL);
ASSERT(pLocalTermCapList != NULL);
#ifdef _DEBUG
if (pLocalTermCapList->wLength != 0)
ASSERT(pLocalTermCapList->pTermCapArray != NULL);
for (i = 0; i < pLocalTermCapList->wLength; i++)
ASSERT(pLocalTermCapList->pTermCapArray[i] != NULL);
if (pLocalTermCapDescriptors != NULL) {
ASSERT(pLocalTermCapDescriptors->pTermCapDescriptorArray != NULL);
for (i = 0; i < pLocalTermCapDescriptors->wLength; i++)
ASSERT(pLocalTermCapDescriptors->pTermCapDescriptorArray[i] != NULL);
}
#endif
ASSERT(pVendorInfo != NULL);
ASSERT(SessionTableConstructor != NULL);
ASSERT(TermCapConstructor != NULL);
ASSERT(ConferenceCallback != NULL);
ASSERT(ppConference != NULL);
// set phConference now, in case we encounter an error
*phConference = CC_INVALID_HANDLE;
*ppConference = (PCONFERENCE)MemAlloc(sizeof(CONFERENCE));
if (*ppConference == NULL)
return CC_NO_MEMORY;
if (bForceMultipointController == TRUE)
tsMultipointController = TS_TRUE;
else if (bMultipointCapable == TRUE)
tsMultipointController = TS_UNKNOWN;
else
tsMultipointController = TS_FALSE;
(*ppConference)->bInTable = FALSE;
(*ppConference)->LocalParticipantInfo.TerminalIDState = TERMINAL_ID_INVALID;
(*ppConference)->LocalParticipantInfo.ParticipantInfo.TerminalLabel.bMCUNumber = 1;
(*ppConference)->LocalParticipantInfo.ParticipantInfo.TerminalLabel.bTerminalNumber = 255;
(*ppConference)->LocalParticipantInfo.ParticipantInfo.TerminalID.pOctetString = NULL;
(*ppConference)->LocalParticipantInfo.ParticipantInfo.TerminalID.wOctetStringLength = 0;
(*ppConference)->LocalParticipantInfo.pEnqueuedRequestsForTerminalID = NULL;
for (i = 0; i < NUM_TERMINAL_ALLOCATION_SLOTS; i++)
(*ppConference)->TerminalNumberAllocation[i] = 0;
// Channel 0 is reserved for the H.245 control channel
(*ppConference)->ChannelNumberAllocation[0] = 0x01;
for (i = 1; i < NUM_CHANNEL_ALLOCATION_SLOTS; i++)
(*ppConference)->ChannelNumberAllocation[i] = 0;
(*ppConference)->bMultipointCapable = bMultipointCapable;
(*ppConference)->bForceMC = bForceMultipointController;
(*ppConference)->SessionTableConstructor = SessionTableConstructor;
(*ppConference)->TermCapConstructor = TermCapConstructor;
(*ppConference)->dwConferenceToken = dwConferenceToken;
(*ppConference)->bDeferredDelete = FALSE;
(*ppConference)->bAutoAccept = FALSE; // ignored unless ConferenceCallback is NULL
(*ppConference)->LocalEndpointAttached = NEVER_ATTACHED;
(*ppConference)->ConferenceCallback = ConferenceCallback;
(*ppConference)->SaveConferenceCallback = ConferenceCallback;
(*ppConference)->bSessionTableInternallyConstructed = FALSE;
(*ppConference)->pSessionTable = NULL;
(*ppConference)->pConferenceH245H2250MuxCapability = NULL;
(*ppConference)->pConferenceTermCapList = NULL;
(*ppConference)->pConferenceTermCapDescriptors = NULL;
(*ppConference)->pLocalH245H2250MuxCapability = NULL;
(*ppConference)->pLocalH245TermCapList = NULL;
(*ppConference)->pLocalH245TermCapDescriptors = NULL;
(*ppConference)->pEnqueuedCalls = NULL;
(*ppConference)->pPlacedCalls = NULL;
(*ppConference)->pEstablishedCalls = NULL;
(*ppConference)->pVirtualCalls = NULL;
(*ppConference)->pChannels = NULL;
(*ppConference)->tsMultipointController = tsMultipointController;
(*ppConference)->tsMaster = TS_UNKNOWN;
(*ppConference)->pMultipointControllerAddr = NULL;
(*ppConference)->ConferenceMode = UNCONNECTED_MODE;
(*ppConference)->pVendorInfo = NULL;
(*ppConference)->pEnqueuedRequestModeCalls = NULL;
(*ppConference)->pNextInTable = NULL;
(*ppConference)->pPrevInTable = NULL;
if (pConferenceID == NULL) {
pConferenceID = &InvalidConferenceID;
(*ppConference)->bDynamicConferenceID = TRUE;
} else
(*ppConference)->bDynamicConferenceID = FALSE;
(*ppConference)->ConferenceID = *pConferenceID;
InitializeLock(&(*ppConference)->Lock);
AcquireLock(&(*ppConference)->Lock);
status = _MakeConferenceHandle(&(*ppConference)->hConference);
if (status != CC_OK) {
FreeConference(*ppConference);
return status;
}
if (pTerminalID != NULL) {
(*ppConference)->bDynamicTerminalID = FALSE;
(*ppConference)->LocalParticipantInfo.TerminalIDState = TERMINAL_ID_VALID;
(*ppConference)->LocalParticipantInfo.ParticipantInfo.TerminalID.wOctetStringLength =
pTerminalID->wOctetStringLength;
(*ppConference)->LocalParticipantInfo.ParticipantInfo.TerminalID.pOctetString =
(BYTE *)MemAlloc(pTerminalID->wOctetStringLength);
if ((*ppConference)->LocalParticipantInfo.ParticipantInfo.TerminalID.pOctetString == NULL) {
FreeConference(*ppConference);
return CC_NO_MEMORY;
}
memcpy((*ppConference)->LocalParticipantInfo.ParticipantInfo.TerminalID.pOctetString,
pTerminalID->pOctetString,
pTerminalID->wOctetStringLength);
} else {
(*ppConference)->bDynamicTerminalID = TRUE;
}
status = _CreateLocalH245H2250MuxCapability(*ppConference);
if (status != CC_OK) {
FreeConference(*ppConference);
return status;
}
// make a local copy of pTermCapList
status = CopyH245TermCapList(&(*ppConference)->pLocalH245TermCapList,
pLocalTermCapList);
if (status != CC_OK) {
FreeConference(*ppConference);
return CC_NO_MEMORY;
}
// create a new descriptor list if one was not supplied
if (pLocalTermCapDescriptors == NULL)
status = CreateH245DefaultTermCapDescriptors(&(*ppConference)->pLocalH245TermCapDescriptors,
(*ppConference)->pLocalH245TermCapList);
else
// make a local copy of pTermCapDescriptors
status = CopyH245TermCapDescriptors(&(*ppConference)->pLocalH245TermCapDescriptors,
pLocalTermCapDescriptors);
if (status != CC_OK) {
FreeConference(*ppConference);
return CC_NO_MEMORY;
}
status = CopyVendorInfo(&((*ppConference)->pVendorInfo), pVendorInfo);
if (status != CC_OK) {
FreeConference(*ppConference);
return status;
}
*phConference = (*ppConference)->hConference;
// add the conference to the conference table
status = _AddConferenceToTable(*ppConference);
if (status != CC_OK)
FreeConference(*ppConference);
// CreateConferenceTermCaps() must be called after _AddConferenceToTable(),
// since it will re-lock the conference object
if ((*ppConference)->tsMultipointController == TS_TRUE) {
status = CreateConferenceTermCaps(*ppConference, NULL);
if (status != CC_OK) {
FreeConference(*ppConference);
return status;
}
}
return status;
}
HRESULT RemoveCallFromConference( PCALL pCall,
PCONFERENCE pConference)
{
ASSERT(pCall != NULL);
ASSERT(pConference != NULL);
// The call object must have been removed from the call table
// prior to removing it from the associated conference object.
// This assures us that no other thread is waiting for a lock on it.
ASSERT(pCall->bInTable == FALSE);
if (pCall->pPrev == NULL) {
// the call object is either at the head of the enqueued call list,
// the head of the placed call list, the head of the established
// call list, the head of the virtual call list, or is detached
// from the conference
if (pConference->pEnqueuedCalls == pCall)
// The call is on the enqueued call list
pConference->pEnqueuedCalls = pCall->pNext;
else if (pConference->pPlacedCalls == pCall)
// the call is on the placed call list
pConference->pPlacedCalls = pCall->pNext;
else if (pConference->pEstablishedCalls == pCall)
// the call is on the established call list
pConference->pEstablishedCalls = pCall->pNext;
else if (pConference->pVirtualCalls == pCall)
pConference->pVirtualCalls = pCall->pNext;
} else
pCall->pPrev->pNext = pCall->pNext;
if (pCall->pNext != NULL)
pCall->pNext->pPrev = pCall->pPrev;
pCall->pNext = NULL;
pCall->pPrev = NULL;
return CC_OK;
}
HRESULT RemoveEnqueuedCallFromConference(
PCONFERENCE pConference,
PCC_HCALL phCall)
{
ASSERT(pConference != NULL);
ASSERT(phCall != NULL);
if (pConference->pEnqueuedCalls == NULL) {
// No enqueued calls; this is not an error, since the caller can't tell
// whether there are any enqueued calls in this conference
*phCall = CC_INVALID_HANDLE;
return CC_OK;
}
// Move the call object from the enqueued call list to the placed
// call list.
// Note that another thread may have a lock on the enqueued call
// object, and may be trying to delete it; they will first need to
// lock the conference object (which this thread has locked), remove
// the call object from the enqueued call list, then free the call object.
// We are therefore safe in creating a pointer to the call object, although
// we may not examine or change any of its contents other than hCall (read-only),
// pNext and pPrev.
*phCall = pConference->pEnqueuedCalls->hCall;
pConference->pEnqueuedCalls = pConference->pEnqueuedCalls->pNext;
if (pConference->pEnqueuedCalls != NULL)
pConference->pEnqueuedCalls->pPrev = NULL;
return CC_OK;
}
HRESULT RemoveChannelFromConference(PCHANNEL pChannel,
PCONFERENCE pConference)
{
ASSERT(pChannel != NULL);
ASSERT(pConference != NULL);
// The channel object must have been removed from the channel table
// prior to removing it from the associated conference object.
// This assures us that no other thread is waiting for a lock on it.
ASSERT(pChannel->bInTable == FALSE);
if (pChannel->pPrev == NULL) {
// the channel object is at the head of the channel list,
// or has been detached from the conference
if (pConference->pChannels == pChannel)
pConference->pChannels = pChannel->pNext;
} else
pChannel->pPrev->pNext = pChannel->pNext;
if (pChannel->pNext != NULL)
pChannel->pNext->pPrev = pChannel->pPrev;
pChannel->pNext = NULL;
pChannel->pPrev = NULL;
return CC_OK;
}
HRESULT AddEnqueuedCallToConference(PCALL pCall,
PCONFERENCE pConference)
{
ASSERT(pCall != NULL);
ASSERT(pConference != NULL);
ASSERT(EqualConferenceIDs(&pCall->ConferenceID, &InvalidConferenceID));
ASSERT(EqualConferenceIDs(&pConference->ConferenceID, &InvalidConferenceID));
ASSERT(pConference->pPlacedCalls != NULL);
// Call cannot already be associated with the conference
ASSERT(pCall->pNext == NULL);
ASSERT(pCall->pPrev == NULL);
pCall->hConference = pConference->hConference;
pCall->pNext = pConference->pEnqueuedCalls;
pCall->pPrev = NULL;
if (pConference->pEnqueuedCalls != NULL) {
ASSERT(pConference->pEnqueuedCalls->pPrev == NULL);
pConference->pEnqueuedCalls->pPrev = pCall;
}
pConference->pEnqueuedCalls = pCall;
return CC_OK;
}
HRESULT AddPlacedCallToConference( PCALL pCall,
PCONFERENCE pConference)
{
ASSERT(pCall != NULL);
ASSERT(pConference != NULL);
if (EqualConferenceIDs(&pConference->ConferenceID,
&InvalidConferenceID)) {
// If a conference ID has not been assigned, but there are
// placed or enqueued calls on the conference, the conference ID
// will be assigned by a callee when the first of these calls completes.
// Since pCall has an assigned conference ID (which will differ from
// the ID to be assigned to this conference), we cannot assign pCall
// to this conference.
ASSERT(pConference->pEstablishedCalls == NULL);
if (pConference->pPlacedCalls != NULL)
return CC_BAD_PARAM;
else
pConference->ConferenceID = pCall->ConferenceID;
} else
if (!EqualConferenceIDs(&pConference->ConferenceID,
&pCall->ConferenceID))
return CC_BAD_PARAM;
pCall->hConference = pConference->hConference;
// Unlink pCall from pConference, if necessary
if (pCall->pPrev == NULL) {
// pCall is at the head of either the enqueued call list,
// the placed call list, or the established call list, or
// is not yet associated with the conference object
if (pConference->pEnqueuedCalls == pCall)
pConference->pEnqueuedCalls = pCall->pNext;
else if (pConference->pPlacedCalls == pCall)
pConference->pPlacedCalls = pCall->pNext;
else if (pConference->pEstablishedCalls == pCall)
pConference->pEstablishedCalls = pCall->pNext;
} else
pCall->pPrev->pNext = pCall->pNext;
if (pCall->pNext != NULL)
pCall->pNext->pPrev = pCall->pPrev;
// Now link pCall into the placed call list
pCall->pNext = pConference->pPlacedCalls;
pCall->pPrev = NULL;
if (pConference->pPlacedCalls != NULL) {
ASSERT(pConference->pPlacedCalls->pPrev == NULL);
pConference->pPlacedCalls->pPrev = pCall;
}
pConference->pPlacedCalls = pCall;
return CC_OK;
}
HRESULT AddEstablishedCallToConference(
PCALL pCall,
PCONFERENCE pConference)
{
ASSERT(pCall != NULL);
ASSERT(pConference != NULL);
ASSERT((EqualConferenceIDs(&pConference->ConferenceID, &InvalidConferenceID)) ||
(EqualConferenceIDs(&pCall->ConferenceID, &pConference->ConferenceID)));
if (EqualConferenceIDs(&pConference->ConferenceID, &InvalidConferenceID)) {
// If a conference ID has not been assigned, but there are
// placed or enqueued calls on the conference, the conference ID
// will be assigned by a callee when the first of these calls completes.
// Since pCall has an assigned conference ID (which will differ from
// the ID to be assigned to this conference), we cannot assign pCall
// to this conference.
ASSERT(pConference->pEstablishedCalls == NULL);
pConference->ConferenceID = pCall->ConferenceID;
} else if (!EqualConferenceIDs(&pConference->ConferenceID, &pCall->ConferenceID))
return CC_BAD_PARAM;
pCall->hConference = pConference->hConference;
// Unlink pCall from pConference, if necessary
if (pCall->pPrev == NULL) {
// pCall is at the head of either the enqueued call list,
// the placed call list, or the established call list, or
// is not yet associated with the conference object
if (pConference->pEnqueuedCalls == pCall)
pConference->pEnqueuedCalls = pCall->pNext;
else if (pConference->pPlacedCalls == pCall)
pConference->pPlacedCalls = pCall->pNext;
else if (pConference->pEstablishedCalls == pCall)
pConference->pEstablishedCalls = pCall->pNext;
} else
pCall->pPrev->pNext = pCall->pNext;
if (pCall->pNext != NULL)
pCall->pNext->pPrev = pCall->pPrev;
// Now link pCall into the established call list
pCall->pNext = pConference->pEstablishedCalls;
pCall->pPrev = NULL;
if (pConference->pEstablishedCalls != NULL) {
ASSERT(pConference->pEstablishedCalls->pPrev == NULL);
pConference->pEstablishedCalls->pPrev = pCall;
}
pConference->pEstablishedCalls = pCall;
return CC_OK;
}
HRESULT AddVirtualCallToConference( PCALL pCall,
PCONFERENCE pConference)
{
ASSERT(pCall != NULL);
ASSERT(pConference != NULL);
// this is a bogus ASSERT --- ASSERT(pConference->ConferenceMode == MULTIPOINT_MODE);
ASSERT(pConference->tsMultipointController == TS_FALSE);
// Call cannot already be associated with the conference
ASSERT(pCall->pNext == NULL);
ASSERT(pCall->pPrev == NULL);
pCall->hConference = pConference->hConference;
pCall->pNext = pConference->pVirtualCalls;
pCall->pPrev = NULL;
if (pConference->pVirtualCalls != NULL) {
ASSERT(pConference->pVirtualCalls->pPrev == NULL);
pConference->pVirtualCalls->pPrev = pCall;
}
pConference->pVirtualCalls = pCall;
return CC_OK;
}
HRESULT AddChannelToConference( PCHANNEL pChannel,
PCONFERENCE pConference)
{
PPCHANNEL ppChannel;
ASSERT(pChannel != NULL);
ASSERT((pChannel->bChannelType == TX_CHANNEL) ||
(pChannel->bChannelType == RX_CHANNEL) ||
(pChannel->bChannelType == TXRX_CHANNEL) ||
(pChannel->bChannelType == PROXY_CHANNEL));
ASSERT(pConference != NULL);
ASSERT(pChannel->hConference == pConference->hConference);
ASSERT(pChannel->pNext == NULL);
ASSERT(pChannel->pPrev == NULL);
ASSERT(pConference->ConferenceMode != UNCONNECTED_MODE);
if (pConference->pEstablishedCalls == NULL)
// Can't open a channel unless we have at least one established call
return CC_BAD_PARAM;
ppChannel = &pConference->pChannels;
pChannel->pNext = *ppChannel;
pChannel->pPrev = NULL;
if (*ppChannel != NULL) {
ASSERT((*ppChannel)->pPrev == NULL);
(*ppChannel)->pPrev = pChannel;
}
*ppChannel = pChannel;
if (pConference->ConferenceMode == POINT_TO_POINT_MODE)
pChannel->bMultipointChannel = FALSE;
else
pChannel->bMultipointChannel = TRUE;
return CC_OK;
}
// Caller must have a lock on the conference object
// There must be no calls on this conference object
// (previous calls must have been cleared by calling Hangup())
HRESULT FreeConference( PCONFERENCE pConference)
{
CC_HCONFERENCE hConference;
PCALL pVirtualCall;
WORD wNumCalls;
WORD i;
PCC_HCALL CallList;
WORD wNumChannels;
PCC_HCHANNEL ChannelList;
PCHANNEL pChannel;
ASSERT(pConference != NULL);
ASSERT(pConference->pEnqueuedCalls == NULL);
ASSERT(pConference->pPlacedCalls == NULL);
ASSERT(pConference->pEstablishedCalls == NULL);
// caller must have a lock on the conference object,
// so there's no need to re-lock it
hConference = pConference->hConference;
if (pConference->bInTable == TRUE)
if (_RemoveConferenceFromTable(pConference) == CC_BAD_PARAM)
// the conference object was deleted by another thread,
// so just return CC_OK
return CC_OK;
if (pConference->pLocalH245H2250MuxCapability != NULL)
H245FreeCap(pConference->pLocalH245H2250MuxCapability);
// free up the LocalTermCapList elements
DestroyH245TermCapList(&pConference->pLocalH245TermCapList);
// free up the local terminal capability descriptors
DestroyH245TermCapDescriptors(&pConference->pLocalH245TermCapDescriptors);
if (pConference->pMultipointControllerAddr != NULL)
MemFree(pConference->pMultipointControllerAddr);
if (pConference->pVendorInfo != NULL)
FreeVendorInfo(pConference->pVendorInfo);
if (pConference->pSessionTable != NULL)
FreeConferenceSessionTable(pConference);
if (pConference->pConferenceH245H2250MuxCapability != NULL)
H245FreeCap(pConference->pConferenceH245H2250MuxCapability);
if ((pConference->pConferenceTermCapList != NULL) ||
(pConference->pConferenceTermCapDescriptors != NULL))
FreeConferenceTermCaps(pConference);
if (pConference->LocalParticipantInfo.ParticipantInfo.TerminalID.pOctetString != NULL)
{
MemFree(pConference->LocalParticipantInfo.ParticipantInfo.TerminalID.pOctetString);
pConference->LocalParticipantInfo.ParticipantInfo.TerminalID.pOctetString = NULL;
pConference->LocalParticipantInfo.ParticipantInfo.TerminalID.wOctetStringLength = 0;
}
while (DequeueRequest(&pConference->LocalParticipantInfo.pEnqueuedRequestsForTerminalID, NULL) == CC_OK);
EnumerateCallsInConference(&wNumCalls, &CallList, pConference, VIRTUAL_CALL);
for (i = 0; i < wNumCalls; i++)
if (LockCall(CallList[i], &pVirtualCall) == CC_OK)
FreeCall(pVirtualCall);
if (CallList != NULL)
MemFree(CallList);
EnumerateChannelsInConference(&wNumChannels, &ChannelList, pConference, ALL_CHANNELS);
for (i = 0; i < wNumChannels; i++)
if (LockChannel(ChannelList[i], &pChannel) == CC_OK)
FreeChannel(pChannel);
if (ChannelList != NULL)
MemFree(ChannelList);
while (DequeueRequest(&pConference->pEnqueuedRequestModeCalls, NULL) == CC_OK);
// since the conference object has been removed from the ConferenceTable,
// no other thread will be able to find the conference object and obtain
// a lock, so its safe to unlock the conference object and delete it here
RelinquishLock(&pConference->Lock);
DeleteLock(&pConference->Lock);
MemFree(pConference);
return CC_OK;
}
HRESULT LockConference( CC_HCONFERENCE hConference,
PPCONFERENCE ppConference)
{
BOOL bTimedOut;
ASSERT(hConference != CC_INVALID_HANDLE);
ASSERT(ppConference != NULL);
step1:
AcquireLock(&ConferenceTable.Lock);
*ppConference = ConferenceTable.pHead;
while ((*ppConference != NULL) && ((*ppConference)->hConference != hConference))
*ppConference = (*ppConference)->pNextInTable;
if (*ppConference != NULL) {
AcquireTimedLock(&(*ppConference)->Lock,10,&bTimedOut);
if (bTimedOut) {
RelinquishLock(&ConferenceTable.Lock);
Sleep(0);
goto step1;
}
}
RelinquishLock(&ConferenceTable.Lock);
if (*ppConference == NULL)
return CC_BAD_PARAM;
else
return CC_OK;
}
HRESULT LockConferenceEx( CC_HCONFERENCE hConference,
PPCONFERENCE ppConference,
TRISTATE tsDeferredDelete)
{
BOOL bTimedOut;
ASSERT(hConference != CC_INVALID_HANDLE);
ASSERT(ppConference != NULL);
step1:
AcquireLock(&ConferenceTable.Lock);
*ppConference = ConferenceTable.pHead;
while ((*ppConference != NULL) && ((*ppConference)->hConference != hConference))
*ppConference = (*ppConference)->pNextInTable;
if (*ppConference != NULL) {
AcquireTimedLock(&(*ppConference)->Lock,10,&bTimedOut);
if (bTimedOut) {
RelinquishLock(&ConferenceTable.Lock);
Sleep(0);
goto step1;
}
if (tsDeferredDelete == TS_TRUE) {
if ((*ppConference)->bDeferredDelete != TRUE) {
RelinquishLock(&(*ppConference)->Lock);
*ppConference = NULL;
}
} else if (tsDeferredDelete == TS_FALSE) {
if ((*ppConference)->bDeferredDelete != FALSE) {
RelinquishLock(&(*ppConference)->Lock);
*ppConference = NULL;
}
}
}
RelinquishLock(&ConferenceTable.Lock);
if (*ppConference == NULL)
return CC_BAD_PARAM;
else
return CC_OK;
}
HRESULT ValidateConference( CC_HCONFERENCE hConference)
{
PCONFERENCE pConference;
ASSERT(hConference != CC_INVALID_HANDLE);
AcquireLock(&ConferenceTable.Lock);
pConference = ConferenceTable.pHead;
while ((pConference != NULL) && (pConference->hConference != hConference))
pConference = pConference->pNextInTable;
RelinquishLock(&ConferenceTable.Lock);
if (pConference == NULL)
return CC_BAD_PARAM;
else
return CC_OK;
}
HRESULT LockConferenceID( PCC_CONFERENCEID pConferenceID,
PPCONFERENCE ppConference)
{
BOOL bTimedOut;
ASSERT(!EqualConferenceIDs(pConferenceID, &InvalidConferenceID));
ASSERT(ppConference != NULL);
// There may be many conference objects in the table with unassigned
// conference IDs (ConferenceID = InvalidConferenceID). The caller may
// never ask us to search for an unassigned conference ID.
step1:
AcquireLock(&ConferenceTable.Lock);
*ppConference = ConferenceTable.pHead;
while ((*ppConference != NULL) &&
(!EqualConferenceIDs(&(*ppConference)->ConferenceID, pConferenceID)))
*ppConference = (*ppConference)->pNextInTable;
if (*ppConference != NULL) {
AcquireTimedLock(&(*ppConference)->Lock,10,&bTimedOut);
if (bTimedOut) {
RelinquishLock(&ConferenceTable.Lock);
Sleep(0);
goto step1;
}
}
RelinquishLock(&ConferenceTable.Lock);
if (*ppConference == NULL)
return CC_BAD_PARAM;
else
return CC_OK;
}
HRESULT FindChannelInConference( WORD wChannel,
BOOL bLocalChannel,
BYTE bChannelType,
CC_HCALL hCall,
PCC_HCHANNEL phChannel,
PCONFERENCE pConference)
{
PCHANNEL pChannel;
WORD wChannelNumber;
ASSERT(wChannel != 0);
ASSERT(phChannel != NULL);
ASSERT(pConference != NULL);
*phChannel = CC_INVALID_HANDLE;
pChannel = pConference->pChannels;
while (pChannel != NULL) {
if (bLocalChannel)
wChannelNumber = pChannel->wLocalChannelNumber;
else
wChannelNumber = pChannel->wRemoteChannelNumber;
if ((wChannelNumber == wChannel) &&
((pChannel->bChannelType & bChannelType) != 0) &&
((hCall == CC_INVALID_HANDLE) ||
(pChannel->hCall == hCall)))
break;
pChannel = pChannel->pNext;
}
if (pChannel == NULL)
return CC_BAD_PARAM;
*phChannel = pChannel->hChannel;
return CC_OK;
}
HRESULT EnumerateConferences( PWORD pwNumConferences,
CC_HCONFERENCE ConferenceList[])
{
WORD wIndexLimit;
PCONFERENCE pConference;
if ((*pwNumConferences != 0) && (ConferenceList == NULL))
return CC_BAD_PARAM;
if ((*pwNumConferences == 0) && (ConferenceList != NULL))
return CC_BAD_PARAM;
wIndexLimit = *pwNumConferences;
*pwNumConferences = 0;
AcquireLock(&ConferenceTable.Lock);
pConference = ConferenceTable.pHead;
while (pConference != NULL) {
if (*pwNumConferences < wIndexLimit)
ConferenceList[*pwNumConferences] = pConference->hConference;
(*pwNumConferences)++;
pConference = pConference->pNextInTable;
}
RelinquishLock(&ConferenceTable.Lock);
return CC_OK;
}
HRESULT EnumerateCallsInConference( WORD *pwNumCalls,
PCC_HCALL pCallList[],
PCONFERENCE pConference,
BYTE bCallType)
{
WORD i;
PCALL pCall;
ASSERT(pwNumCalls != NULL);
ASSERT(pConference != NULL);
*pwNumCalls = 0;
if (bCallType & ENQUEUED_CALL) {
pCall = pConference->pEnqueuedCalls;
while (pCall != NULL) {
(*pwNumCalls)++;
pCall = pCall->pNext;
}
}
if (bCallType & PLACED_CALL) {
pCall = pConference->pPlacedCalls;
while (pCall != NULL) {
(*pwNumCalls)++;
pCall = pCall->pNext;
}
}
if (bCallType & ESTABLISHED_CALL) {
pCall = pConference->pEstablishedCalls;
while (pCall != NULL) {
(*pwNumCalls)++;
pCall = pCall->pNext;
}
}
if (bCallType & VIRTUAL_CALL) {
pCall = pConference->pVirtualCalls;
while (pCall != NULL) {
(*pwNumCalls)++;
pCall = pCall->pNext;
}
}
if (pCallList == NULL)
return CC_OK;
if (*pwNumCalls == 0) {
*pCallList = NULL;
return CC_OK;
}
*pCallList = (PCC_HCALL)MemAlloc(sizeof(CC_HCALL) * (*pwNumCalls));
if (*pCallList == NULL)
return CC_NO_MEMORY;
i = 0;
if (bCallType & ENQUEUED_CALL) {
pCall = pConference->pEnqueuedCalls;
while (pCall != NULL) {
(*pCallList)[i] = pCall->hCall;
i++;
pCall = pCall->pNext;
}
}
if (bCallType & PLACED_CALL) {
pCall = pConference->pPlacedCalls;
while (pCall != NULL) {
(*pCallList)[i] = pCall->hCall;
i++;
pCall = pCall->pNext;
}
}
if (bCallType & ESTABLISHED_CALL) {
pCall = pConference->pEstablishedCalls;
while (pCall != NULL) {
(*pCallList)[i] = pCall->hCall;
i++;
pCall = pCall->pNext;
}
}
if (bCallType & VIRTUAL_CALL) {
pCall = pConference->pVirtualCalls;
while (pCall != NULL) {
(*pCallList)[i] = pCall->hCall;
i++;
pCall = pCall->pNext;
}
}
return CC_OK;
}
HRESULT EnumerateChannelsInConference(
WORD *pwNumChannels,
PCC_HCHANNEL pChannelList[],
PCONFERENCE pConference,
BYTE bChannelType)
{
WORD i;
PCHANNEL pChannel;
ASSERT(pwNumChannels != NULL);
ASSERT(pConference != NULL);
*pwNumChannels = 0;
pChannel = pConference->pChannels;
while (pChannel != NULL) {
if (pChannel->bChannelType & bChannelType)
(*pwNumChannels)++;
pChannel = pChannel->pNext;
}
if (pChannelList == NULL)
return CC_OK;
if (*pwNumChannels == 0) {
*pChannelList = NULL;
return CC_OK;
}
*pChannelList = (PCC_HCHANNEL)MemAlloc(sizeof(CC_HCHANNEL) * (*pwNumChannels));
if (*pChannelList == NULL)
return CC_NO_MEMORY;
i = 0;
pChannel = pConference->pChannels;
while (pChannel != NULL) {
if (pChannel->bChannelType & bChannelType) {
(*pChannelList)[i] = pChannel->hChannel;
i++;
}
pChannel = pChannel->pNext;
}
return CC_OK;
}
HRESULT EnumerateTerminalLabelsInConference(
WORD *pwNumTerminalLabels,
H245_TERMINAL_LABEL_T *pH245TerminalLabelList[],
PCONFERENCE pConference)
{
WORD i, j;
WORD wIndex;
BYTE bMask;
ASSERT(pwNumTerminalLabels != NULL);
ASSERT(pConference != NULL);
// First count the number of known terminals
*pwNumTerminalLabels = 0;
for (i = 0; i < NUM_TERMINAL_ALLOCATION_SLOTS; i++) {
if (pConference->TerminalNumberAllocation[i] != 0) {
bMask = 0x01;
for (j = 0; j < 8; j++) {
if ((pConference->TerminalNumberAllocation[i] & bMask) != 0)
(*pwNumTerminalLabels)++;
bMask *= 2;
}
}
}
if (pConference->LocalEndpointAttached == ATTACHED)
(*pwNumTerminalLabels)++;
if (pH245TerminalLabelList == NULL)
return CC_OK;
if (*pwNumTerminalLabels == 0)
*pH245TerminalLabelList = NULL;
*pH245TerminalLabelList = (H245_TERMINAL_LABEL_T *)MemAlloc(sizeof(H245_TERMINAL_LABEL_T) *
(*pwNumTerminalLabels));
if (*pH245TerminalLabelList == NULL)
return CC_NO_MEMORY;
wIndex = 0;
for (i = 0; i < NUM_TERMINAL_ALLOCATION_SLOTS; i++) {
if (pConference->TerminalNumberAllocation[i] != 0) {
bMask = 0x01;
for (j = 0; j < 8; j++) {
if ((pConference->TerminalNumberAllocation[i] & bMask) != 0) {
(*pH245TerminalLabelList)[wIndex].mcuNumber = pConference->LocalParticipantInfo.ParticipantInfo.TerminalLabel.bMCUNumber;
(*pH245TerminalLabelList)[wIndex].terminalNumber = (TerminalNumber) ((i * 8) + j + 1);
wIndex++;
}
bMask *= 2;
}
}
}
if (pConference->LocalEndpointAttached == ATTACHED) {
(*pH245TerminalLabelList)[wIndex].mcuNumber = pConference->LocalParticipantInfo.ParticipantInfo.TerminalLabel.bMCUNumber;
(*pH245TerminalLabelList)[wIndex].terminalNumber = 0;
}
return CC_OK;
}
HRESULT UnlockConference( PCONFERENCE pConference)
{
ASSERT(pConference != NULL);
RelinquishLock(&pConference->Lock);
return CC_OK;
}
HRESULT AsynchronousDestroyConference(
CC_HCONFERENCE hConference,
BOOL bAutoAccept)
{
HRESULT status;
PCONFERENCE pConference;
WORD wNumCalls;
WORD wNumChannels;
WORD i;
PCHANNEL pChannel;
PCC_HCHANNEL ChannelList;
status = LockConference(hConference, &pConference);
if (status != CC_OK)
return status;
status = EnumerateCallsInConference(&wNumCalls, NULL, pConference, REAL_CALLS);
if (status != CC_OK) {
UnlockConference(pConference);
return status;
}
// This is an illegal call if:
// 1. The local endpoint is currently attached;
// 2. The local endpoint has never been attached, but is in the
// process of placing a call
if ((pConference->LocalEndpointAttached == ATTACHED) ||
((pConference->LocalEndpointAttached == NEVER_ATTACHED) &&
(wNumCalls > 0))) {
UnlockConference(pConference);
return CC_BAD_PARAM;
}
pConference->ConferenceCallback = NULL;
// can't destroy a conference if there are active calls
if (wNumCalls != 0) {
pConference->bDeferredDelete = TRUE;
pConference->bAutoAccept = bAutoAccept;
UnlockConference(pConference);
return CC_OK;
}
status = EnumerateChannelsInConference(&wNumChannels,
&ChannelList,
pConference,
ALL_CHANNELS);
if (status != CC_OK) {
UnlockConference(pConference);
return status;
}
// free all the channels
for (i = 0; i < wNumChannels; i++) {
if (LockChannel(ChannelList[i], &pChannel) == CC_OK)
// Notice that since we're going to hangup, we don't need to
// close any channels
FreeChannel(pChannel);
}
if (ChannelList != NULL)
MemFree(ChannelList);
FreeConference(pConference);
return CC_OK;
}
HRESULT FindPeerParticipantInfo( H245_TERMINAL_LABEL_T H245TerminalLabel,
PCONFERENCE pConference,
BYTE bCallType,
PCALL *ppCall)
{
WORD wNumCalls;
PCC_HCALL CallList;
WORD i;
HRESULT status;
ASSERT(pConference != NULL);
ASSERT(ppCall != NULL);
status = EnumerateCallsInConference(&wNumCalls,
&CallList,
pConference,
bCallType);
if (status != CC_OK)
return status;
for (i = 0; i < wNumCalls; i++) {
if (LockCall(CallList[i], ppCall) == CC_OK) {
if ((*ppCall)->pPeerParticipantInfo != NULL)
if (((*ppCall)->pPeerParticipantInfo->ParticipantInfo.TerminalLabel.bMCUNumber ==
H245TerminalLabel.mcuNumber) &&
((*ppCall)->pPeerParticipantInfo->ParticipantInfo.TerminalLabel.bTerminalNumber ==
H245TerminalLabel.terminalNumber)) {
MemFree(CallList);
return CC_OK;
}
UnlockCall(*ppCall);
}
}
if (CallList != NULL)
MemFree(CallList);
*ppCall = NULL;
return CC_BAD_PARAM;
}
HRESULT ReInitializeConference( PCONFERENCE pConference)
{
PCALL pCall;
WORD wNumCalls;
WORD i;
PCC_HCALL CallList;
PCHANNEL pChannel;
WORD wNumChannels;
PCC_HCHANNEL ChannelList;
HRESULT status;
ASSERT(pConference != NULL);
if (pConference->bDynamicConferenceID == TRUE)
pConference->ConferenceID = InvalidConferenceID;
pConference->LocalParticipantInfo.ParticipantInfo.TerminalLabel.bMCUNumber = 1;
pConference->LocalParticipantInfo.ParticipantInfo.TerminalLabel.bTerminalNumber = 255;
if (pConference->bDynamicTerminalID == TRUE) {
pConference->LocalParticipantInfo.TerminalIDState = TERMINAL_ID_INVALID;
if(pConference->LocalParticipantInfo.ParticipantInfo.TerminalID.pOctetString != NULL)
{
MemFree(pConference->LocalParticipantInfo.ParticipantInfo.TerminalID.pOctetString);
pConference->LocalParticipantInfo.ParticipantInfo.TerminalID.pOctetString = NULL;
pConference->LocalParticipantInfo.ParticipantInfo.TerminalID.wOctetStringLength = 0;
}
}
while (DequeueRequest(&pConference->LocalParticipantInfo.pEnqueuedRequestsForTerminalID, NULL) == CC_OK);
for (i = 0; i < NUM_TERMINAL_ALLOCATION_SLOTS; i++)
pConference->TerminalNumberAllocation[i] = 0;
// Channel 0 is reserved for the H.245 control channel
pConference->ChannelNumberAllocation[0] = 0x01;
for (i = 1; i < NUM_CHANNEL_ALLOCATION_SLOTS; i++)
pConference->ChannelNumberAllocation[i] = 0;
pConference->bDeferredDelete = FALSE;
pConference->bAutoAccept = FALSE; // ignored unless ConferenceCallback is NULL
pConference->LocalEndpointAttached = NEVER_ATTACHED;
if (pConference->pSessionTable != NULL)
FreeConferenceSessionTable(pConference);
_CreateLocalH245H2250MuxCapability(pConference);
if (pConference->pConferenceH245H2250MuxCapability != NULL) {
H245FreeCap(pConference->pConferenceH245H2250MuxCapability);
pConference->pConferenceH245H2250MuxCapability = NULL;
}
if ((pConference->pConferenceTermCapList != NULL) ||
(pConference->pConferenceTermCapDescriptors != NULL))
FreeConferenceTermCaps(pConference);
pConference->bSessionTableInternallyConstructed = FALSE;
pConference->ConferenceCallback = pConference->SaveConferenceCallback;
EnumerateCallsInConference(&wNumCalls, &CallList, pConference, ALL_CALLS);
for (i = 0; i < wNumCalls; i++)
if (LockCall(CallList[i], &pCall) == CC_OK)
FreeCall(pCall);
if (CallList != NULL)
MemFree(CallList);
EnumerateChannelsInConference(&wNumChannels, &ChannelList, pConference, ALL_CHANNELS);
for (i = 0; i < wNumChannels; i++)
if (LockChannel(ChannelList[i], &pChannel) == CC_OK)
FreeChannel(pChannel);
if (ChannelList != NULL)
MemFree(ChannelList);
if (pConference->bForceMC == TRUE)
pConference->tsMultipointController = TS_TRUE;
else if (pConference->bMultipointCapable == TRUE)
pConference->tsMultipointController = TS_UNKNOWN;
else
pConference->tsMultipointController = TS_FALSE;
pConference->tsMaster = TS_UNKNOWN;
pConference->ConferenceMode = UNCONNECTED_MODE;
if (pConference->pMultipointControllerAddr != NULL) {
MemFree(pConference->pMultipointControllerAddr);
pConference->pMultipointControllerAddr = NULL;
}
while (DequeueRequest(&pConference->pEnqueuedRequestModeCalls, NULL) == CC_OK);
if (pConference->tsMultipointController == TS_TRUE)
status = CreateConferenceTermCaps(pConference, NULL);
else
status = CC_OK;
return status;
}