|
|
/****************************************************************************
* * $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; }
|