|
|
/****************************************************************************
* * $Archive: S:/STURGEON/SRC/CALLCONT/VCS/h245man.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.225 $ * $Date: 03 Mar 1997 09:08:10 $ * $Author: MANDREWS $ * * Deliverable: * * Abstract: * * * Notes: * ***************************************************************************/
#include "precomp.h"
#include "apierror.h"
#include "incommon.h"
#include "callcont.h"
#include "q931.h"
#include "ccmain.h"
#include "listman.h"
#include "q931man.h"
#include "userman.h"
#include "callman.h"
#include "confman.h"
#include "h245man.h"
#include "chanman.h"
#include "hangman.h"
#include "ccutils.h"
#include "linkapi.h"
#include "h245com.h"
extern CALL_CONTROL_STATE CallControlState; extern THREADCOUNT ThreadCount;
static BOOL bH245ManagerInited = FALSE;
static struct { DWORD dwPhysicalID; LOCK Lock; } PhysicalID;
HRESULT InitH245Manager() { ASSERT(bH245ManagerInited == FALSE);
// Note -- don't use a physical ID of 0; the physical ID gets mapped
// to an H245 instance of the same value, and an H245 instance of
// 0 is invalid
PhysicalID.dwPhysicalID = 1; InitializeLock(&PhysicalID.Lock); bH245ManagerInited = H245SysInit(); return CC_OK; }
HRESULT DeInitH245Manager() { if (bH245ManagerInited == FALSE) return CC_OK;
H245SysDeInit(); H245WSShutdown(); DeleteLock(&PhysicalID.Lock); bH245ManagerInited = FALSE; return CC_OK; }
HRESULT MakeH245PhysicalID( DWORD *pdwH245PhysicalID) { AcquireLock(&PhysicalID.Lock); *pdwH245PhysicalID = PhysicalID.dwPhysicalID++; RelinquishLock(&PhysicalID.Lock); return CC_OK; }
HRESULT _ConstructTermCapList( PCC_TERMCAPLIST *ppTermCapList, PCC_TERMCAP *ppH2250MuxCap, PCC_TERMCAPDESCRIPTORS *ppTermCapDescriptors, PCALL pCall) { #define MAX_TERM_CAPS 257
#define MAX_TERM_CAP_DESC 255
H245_TOTCAP_T * pTermCapArray[MAX_TERM_CAPS]; H245_TOTCAPDESC_T * pTermCapDescriptorArray[MAX_TERM_CAP_DESC]; unsigned long CapArrayLength; unsigned long CapDescriptorArrayLength; unsigned long i, j; HRESULT status;
ASSERT(ppTermCapList != NULL); ASSERT(*ppTermCapList == NULL); ASSERT(ppH2250MuxCap != NULL); ASSERT(*ppH2250MuxCap == NULL); ASSERT(ppTermCapDescriptors != NULL); ASSERT(*ppTermCapDescriptors == NULL); ASSERT(pCall != NULL);
CapArrayLength = MAX_TERM_CAPS; CapDescriptorArrayLength = MAX_TERM_CAP_DESC;
status = H245GetCaps(pCall->H245Instance, H245_CAPDIR_RMTRXTX, H245_DATA_DONTCARE, H245_CLIENT_DONTCARE, pTermCapArray, &CapArrayLength, pTermCapDescriptorArray, &CapDescriptorArrayLength); if (status != H245_ERROR_OK) { *ppTermCapList = NULL; *ppH2250MuxCap = NULL; *ppTermCapDescriptors = NULL; return status; }
// Check the term cap list to see if an H.225.0 mux capability is present;
// this capability is treated as a special case
*ppH2250MuxCap = NULL; for (i = 0; i < CapArrayLength; i++) { ASSERT(pTermCapArray[i] != NULL); if (pTermCapArray[i]->CapId == 0) { *ppH2250MuxCap = pTermCapArray[i]; --CapArrayLength; for (j = i; j < CapArrayLength; j++) pTermCapArray[j] = pTermCapArray[j+1]; break; } }
if (CapArrayLength == 0) *ppTermCapList = NULL; else { *ppTermCapList = (PCC_TERMCAPLIST)MemAlloc(sizeof(CC_TERMCAPLIST)); if (*ppTermCapList == NULL) { for (i = 0; i < CapArrayLength; i++) H245FreeCap(pTermCapArray[i]); if (*ppH2250MuxCap != NULL) H245FreeCap(*ppH2250MuxCap); for (i = 0; i < CapDescriptorArrayLength; i++) H245FreeCapDescriptor(pTermCapDescriptorArray[i]); return CC_NO_MEMORY; }
(*ppTermCapList)->wLength = (WORD)CapArrayLength; (*ppTermCapList)->pTermCapArray = (H245_TOTCAP_T **)MemAlloc(sizeof(H245_TOTCAP_T *) * CapArrayLength); if ((*ppTermCapList)->pTermCapArray == NULL) { MemFree(*ppTermCapList); for (i = 0; i < CapArrayLength; i++) H245FreeCap(pTermCapArray[i]); if (*ppH2250MuxCap != NULL) H245FreeCap(*ppH2250MuxCap); for (i = 0; i < CapDescriptorArrayLength; i++) H245FreeCapDescriptor(pTermCapDescriptorArray[i]); *ppTermCapList = NULL; *ppH2250MuxCap = NULL; *ppTermCapDescriptors = NULL; return CC_NO_MEMORY; }
for (i = 0; i < CapArrayLength; i++) (*ppTermCapList)->pTermCapArray[i] = pTermCapArray[i]; }
if (CapDescriptorArrayLength == 0) *ppTermCapDescriptors = NULL; else { *ppTermCapDescriptors = (PCC_TERMCAPDESCRIPTORS)MemAlloc(sizeof(CC_TERMCAPDESCRIPTORS)); if (*ppTermCapDescriptors == NULL) { for (i = 0; i < CapArrayLength; i++) H245FreeCap(pTermCapArray[i]); if (*ppH2250MuxCap != NULL) H245FreeCap(*ppH2250MuxCap); for (i = 0; i < CapDescriptorArrayLength; i++) H245FreeCapDescriptor(pTermCapDescriptorArray[i]); if (*ppTermCapList != NULL) { MemFree((*ppTermCapList)->pTermCapArray); MemFree(*ppTermCapList); } *ppTermCapList = NULL; *ppH2250MuxCap = NULL; *ppTermCapDescriptors = NULL; return CC_NO_MEMORY; }
(*ppTermCapDescriptors)->wLength = (WORD)CapDescriptorArrayLength; (*ppTermCapDescriptors)->pTermCapDescriptorArray = (H245_TOTCAPDESC_T **)MemAlloc(sizeof(H245_TOTCAPDESC_T *) * CapDescriptorArrayLength); if ((*ppTermCapDescriptors)->pTermCapDescriptorArray == NULL) { for (i = 0; i < CapArrayLength; i++) H245FreeCap(pTermCapArray[i]); if (*ppH2250MuxCap != NULL) H245FreeCap(*ppH2250MuxCap); for (i = 0; i < CapDescriptorArrayLength; i++) H245FreeCapDescriptor(pTermCapDescriptorArray[i]); if (*ppTermCapList != NULL) { MemFree((*ppTermCapList)->pTermCapArray); MemFree(*ppTermCapList); } MemFree(*ppTermCapDescriptors); *ppTermCapList = NULL; *ppH2250MuxCap = NULL; *ppTermCapDescriptors = NULL; return CC_NO_MEMORY; }
for (i = 0; i < CapDescriptorArrayLength; i++) (*ppTermCapDescriptors)->pTermCapDescriptorArray[i] = pTermCapDescriptorArray[i]; } return CC_OK; }
HRESULT _ProcessConnectionComplete( PCONFERENCE pConference, PCALL pCall) { CC_HCONFERENCE hConference; CC_HCALL hCall; HQ931CALL hQ931Call; HQ931CALL hQ931CallInvitor; HRESULT status; CC_CONNECT_CALLBACK_PARAMS ConnectCallbackParams; CC_MULTIPOINT_CALLBACK_PARAMS MultipointCallbackParams; CC_PEER_CHANGE_CAP_CALLBACK_PARAMS PeerChangeCapCallbackParams; CC_PEER_ADD_CALLBACK_PARAMS PeerAddCallbackParams; WORD i; BOOL bMultipointConference; H245_TRANSPORT_ADDRESS_T Q931Address; PDU_T *pPdu = NULL; // Too big to be local variable (70K)
CALLTYPE CallType; WORD wNumCalls; PCC_HCALL CallList; WORD wNumChannels; PCC_HCHANNEL ChannelList; PCHANNEL pChannel; PCALL pOldCall; CC_HCALL hOldCall; BYTE bNewTerminalNumber; BYTE bNewMCUNumber; CC_ENDPOINTTYPE DestinationEndpointType; H245_COMM_MODE_ENTRY_T *pH245CommunicationTable; BYTE bCommunicationTableCount; BOOL bSessionTableChanged; CONFMODE PreviousConferenceMode; CC_ADDR MCAddress; BOOL bConferenceTermCapsChanged; H245_INST_T H245Instance; PCC_TERMCAP pTxTermCap; PCC_TERMCAP pRxTermCap; H245_MUX_T *pTxMuxTable; H245_MUX_T *pRxMuxTable;
ASSERT(pConference != NULL); ASSERT(pCall != NULL); ASSERT(pCall->hConference == pConference->hConference); hConference = pConference->hConference; hCall = pCall->hCall; hQ931Call = pCall->hQ931Call; hQ931CallInvitor = pCall->hQ931CallInvitor; H245Instance = pCall->H245Instance; CallType = pCall->CallType;
// Note that pConference->ConferenceMode refers to the conference mode BEFORE
// this connection attempt completes. If the current conference mode is
// point-to-point, this connection (if successful) will result in a multipoint
// conference. We want to reflect in the CONNECT callback the connection mode
// that would exist if the connect attempt is successful.
if ((pConference->ConferenceMode == POINT_TO_POINT_MODE) || (pConference->ConferenceMode == MULTIPOINT_MODE) || (pCall->bCallerIsMC)) bMultipointConference = TRUE; else bMultipointConference = FALSE;
// Initialize all fields of ConnectCallbackParams now
ConnectCallbackParams.pNonStandardData = pCall->pPeerNonStandardData; ConnectCallbackParams.pszPeerDisplay = pCall->pszPeerDisplay; ConnectCallbackParams.bRejectReason = CC_REJECT_UNDEFINED_REASON; ConnectCallbackParams.pTermCapList = pCall->pPeerH245TermCapList; ConnectCallbackParams.pH2250MuxCapability = pCall->pPeerH245H2250MuxCapability; ConnectCallbackParams.pTermCapDescriptors = pCall->pPeerH245TermCapDescriptors; ConnectCallbackParams.pLocalAddr = pCall->pQ931LocalConnectAddr; if (pCall->pQ931DestinationAddr == NULL) ConnectCallbackParams.pPeerAddr = pCall->pQ931PeerConnectAddr; else ConnectCallbackParams.pPeerAddr = pCall->pQ931DestinationAddr; ConnectCallbackParams.pVendorInfo = pCall->pPeerVendorInfo; ConnectCallbackParams.bMultipointConference = bMultipointConference; ConnectCallbackParams.pConferenceID = &pConference->ConferenceID; ConnectCallbackParams.pMCAddress = pConference->pMultipointControllerAddr; ConnectCallbackParams.pAlternateAddress = NULL; ConnectCallbackParams.dwUserToken = pCall->dwUserToken;
status = AddEstablishedCallToConference(pCall, pConference); if (status != CC_OK) { MarkCallForDeletion(pCall);
if (CallType == THIRD_PARTY_INTERMEDIARY) Q931RejectCall(hQ931CallInvitor, CC_REJECT_UNDEFINED_REASON, &pCall->ConferenceID, NULL, // alternate address
pCall->pPeerNonStandardData);
if ((CallType == CALLER) || (CallType == THIRD_PARTY_INVITOR) || ((CallType == CALLEE) && (pConference->LocalEndpointAttached == NEVER_ATTACHED))) InvokeUserConferenceCallback(pConference, CC_CONNECT_INDICATION, status, &ConnectCallbackParams);
if (ValidateCallMarkedForDeletion(hCall) == CC_OK) FreeCall(pCall); H245ShutDown(H245Instance); Q931Hangup(hQ931Call, CC_REJECT_UNDEFINED_REASON); if (ValidateConference(hConference) == CC_OK) UnlockConference(pConference);
return status; }
if (((pConference->ConferenceMode == POINT_TO_POINT_MODE) || (pConference->ConferenceMode == MULTIPOINT_MODE)) && (pConference->tsMultipointController == TS_TRUE)) status = CreateConferenceTermCaps(pConference, &bConferenceTermCapsChanged); else { status = CC_OK; bConferenceTermCapsChanged = FALSE; } if (status != CC_OK) { MarkCallForDeletion(pCall);
if (CallType == THIRD_PARTY_INTERMEDIARY) Q931RejectCall(pCall->hQ931CallInvitor, CC_REJECT_UNDEFINED_REASON, &pCall->ConferenceID, NULL, // alternate address
pCall->pPeerNonStandardData);
if ((CallType == CALLER) || (CallType == THIRD_PARTY_INVITOR) || ((CallType == CALLEE) && (pConference->LocalEndpointAttached == NEVER_ATTACHED))) InvokeUserConferenceCallback(pConference, CC_CONNECT_INDICATION, status, &ConnectCallbackParams);
if (ValidateCallMarkedForDeletion(hCall) == CC_OK) FreeCall(pCall); H245ShutDown(H245Instance); Q931Hangup(hQ931Call, CC_REJECT_UNDEFINED_REASON); if (ValidateConference(hConference) == CC_OK) UnlockConference(pConference);
return status; }
if (pConference->tsMultipointController == TS_TRUE) { // Send MCLocationIndication
status = GetLastListenAddress(&MCAddress); if (status == CC_OK) { ASSERT(MCAddress.nAddrType == CC_IP_BINARY); Q931Address.type = H245_IP_UNICAST; Q931Address.u.ip.tsapIdentifier = MCAddress.Addr.IP_Binary.wPort; HostToH245IPNetwork(Q931Address.u.ip.network, MCAddress.Addr.IP_Binary.dwAddr); H245MCLocationIndication(pCall->H245Instance, &Q931Address); } }
EnumerateCallsInConference(&wNumCalls, &CallList, pConference, ESTABLISHED_CALL);
if (pConference->ConferenceMode == UNCONNECTED_MODE) { ASSERT(pConference->pSessionTable == NULL); ASSERT(wNumCalls == 1);
pConference->ConferenceMode = POINT_TO_POINT_MODE; } else { // we're currently in point-to-point mode or multipoint mode
if (pConference->tsMultipointController == TS_TRUE) { PreviousConferenceMode = pConference->ConferenceMode; pConference->ConferenceMode = MULTIPOINT_MODE;
// In the future, we may want to construct a new session table
// each time a new peer is added to the conference
if (PreviousConferenceMode == POINT_TO_POINT_MODE) { // Assign a terminal label to ourselves
// Note that we reserve a terminal number of 0 for ourselves
// if we're the MC
ASSERT(pConference->LocalParticipantInfo.ParticipantInfo.TerminalLabel.bTerminalNumber == 255); pConference->LocalParticipantInfo.ParticipantInfo.TerminalLabel.bTerminalNumber = 0;
// Create a new session table
CreateConferenceSessionTable( pConference, &bSessionTableChanged); } else // For the current implementation, don't cause a new
// CommunicationModeCommand to be issued when a new peer is added
// unless we're switching from point-to-point to multipoint mode
// (in which case bSessionTableChanged is ignored)
bSessionTableChanged = FALSE;
if (bSessionTableChanged) SessionTableToH245CommunicationTable(pConference->pSessionTable, &pH245CommunicationTable, &bCommunicationTableCount); else pH245CommunicationTable = NULL;
// Send MultipointModeCommand to new call
pPdu = (PDU_T *)MemAlloc(sizeof(PDU_T)); if(NULL != pPdu) { pPdu->choice = MSCMg_cmmnd_chosen; pPdu->u.MSCMg_cmmnd.choice = miscellaneousCommand_chosen; // logical channel number is irrelavent but needs to be filled in
pPdu->u.MSCMg_cmmnd.u.miscellaneousCommand.logicalChannelNumber = 1; pPdu->u.MSCMg_cmmnd.u.miscellaneousCommand.type.choice = multipointModeCommand_chosen; H245SendPDU(pCall->H245Instance, pPdu); MemFree(pPdu); pPdu = NULL; } status = AllocatePeerParticipantInfo(pConference, &pCall->pPeerParticipantInfo); if (status == CC_OK) { bNewMCUNumber = pCall->pPeerParticipantInfo->ParticipantInfo.TerminalLabel.bMCUNumber; bNewTerminalNumber = pCall->pPeerParticipantInfo->ParticipantInfo.TerminalLabel.bTerminalNumber; // Send TerminalNumberAssign to new call
H245ConferenceIndication(pCall->H245Instance, H245_IND_TERMINAL_NUMBER_ASSIGN,// Indication Type
0, // SBE number; ignored here
pCall->pPeerParticipantInfo->ParticipantInfo.TerminalLabel.bMCUNumber, // MCU number
pCall->pPeerParticipantInfo->ParticipantInfo.TerminalLabel.bTerminalNumber); // terminal number
// Send EnterH243TerminalID to new call
H245ConferenceRequest(pCall->H245Instance, H245_REQ_ENTER_H243_TERMINAL_ID, pCall->pPeerParticipantInfo->ParticipantInfo.TerminalLabel.bMCUNumber, pCall->pPeerParticipantInfo->ParticipantInfo.TerminalLabel.bTerminalNumber); pCall->pPeerParticipantInfo->TerminalIDState = TERMINAL_ID_REQUESTED; } else { // Unable to assign a terminal number to the new call
bNewMCUNumber = 0; bNewTerminalNumber = 0; }
if (pH245CommunicationTable != NULL) { // Send CommunicationModeCommand to new call
status = H245CommunicationModeCommand(pCall->H245Instance, pH245CommunicationTable, bCommunicationTableCount); }
if (PreviousConferenceMode == POINT_TO_POINT_MODE) { // Generate MULTIPOINT callback
MultipointCallbackParams.pTerminalInfo = &pConference->LocalParticipantInfo.ParticipantInfo; MultipointCallbackParams.pSessionTable = pConference->pSessionTable; InvokeUserConferenceCallback(pConference, CC_MULTIPOINT_INDICATION, CC_OK, &MultipointCallbackParams); if (ValidateConference(hConference) != CC_OK) { if (ValidateCall(hCall) == CC_OK) { pCall->CallState = CALL_COMPLETE; UnlockCall(pCall); } MemFree(CallList); return CC_OK; }
// Generate CC_PEER_CHANGE_CAP callback
PeerChangeCapCallbackParams.pTermCapList = pConference->pConferenceTermCapList; PeerChangeCapCallbackParams.pH2250MuxCapability = pConference->pConferenceH245H2250MuxCapability; PeerChangeCapCallbackParams.pTermCapDescriptors = pConference->pConferenceTermCapDescriptors; InvokeUserConferenceCallback(pConference, CC_PEER_CHANGE_CAP_INDICATION, CC_OK, &PeerChangeCapCallbackParams); if (ValidateConference(hConference) != CC_OK) { if (ValidateCall(hCall) == CC_OK) { pCall->CallState = CALL_COMPLETE; UnlockCall(pCall); } MemFree(CallList); return CC_OK; }
ASSERT(wNumCalls == 2); // one existing call and new call
if (CallList[0] == hCall) hOldCall = CallList[1]; else hOldCall = CallList[0];
if (LockCall(hOldCall, &pOldCall) == CC_OK) { // Send MultipointModeCommand to old call
pPdu = (PDU_T *)MemAlloc(sizeof(PDU_T)); if(NULL != pPdu) { pPdu->choice = MSCMg_cmmnd_chosen; pPdu->u.MSCMg_cmmnd.choice = miscellaneousCommand_chosen; // logical channel number is irrelavent but needs to be filled in
pPdu->u.MSCMg_cmmnd.u.miscellaneousCommand.logicalChannelNumber = 1; pPdu->u.MSCMg_cmmnd.u.miscellaneousCommand.type.choice = multipointModeCommand_chosen; H245SendPDU(pOldCall->H245Instance, pPdu); MemFree(pPdu); pPdu = NULL; }
status = AllocatePeerParticipantInfo(pConference, &pOldCall->pPeerParticipantInfo); if (status == CC_OK) { // Send TerminalNumberAssign to old call
H245ConferenceIndication(pOldCall->H245Instance, H245_IND_TERMINAL_NUMBER_ASSIGN,// Indication Type
0, // SBE number; ignored here
pOldCall->pPeerParticipantInfo->ParticipantInfo.TerminalLabel.bMCUNumber, // MCU number
pOldCall->pPeerParticipantInfo->ParticipantInfo.TerminalLabel.bTerminalNumber); // terminal number
// Send EnterH243TerminalID to old call
H245ConferenceRequest(pOldCall->H245Instance, H245_REQ_ENTER_H243_TERMINAL_ID, pOldCall->pPeerParticipantInfo->ParticipantInfo.TerminalLabel.bMCUNumber, pOldCall->pPeerParticipantInfo->ParticipantInfo.TerminalLabel.bTerminalNumber); pOldCall->pPeerParticipantInfo->TerminalIDState = TERMINAL_ID_REQUESTED; }
if (pH245CommunicationTable != NULL) { // Send CommunicationModeCommand to old call
status = H245CommunicationModeCommand(pOldCall->H245Instance, pH245CommunicationTable, bCommunicationTableCount); FreeH245CommunicationTable(pH245CommunicationTable, bCommunicationTableCount); }
// Send TerminalJoinedConference (this call) to old call
H245ConferenceIndication(pOldCall->H245Instance, H245_IND_TERMINAL_JOINED, // Indication Type
0, // SBE number; ignored here
pConference->LocalParticipantInfo.ParticipantInfo.TerminalLabel.bMCUNumber, // MCU number
pConference->LocalParticipantInfo.ParticipantInfo.TerminalLabel.bTerminalNumber); // terminal number // terminal number of MC
if (bNewTerminalNumber != 0) { // Send TerminalJoinedConference (new call) to old call
H245ConferenceIndication(pOldCall->H245Instance, H245_IND_TERMINAL_JOINED, // Indication Type
0, // SBE number; ignored here
bNewMCUNumber, // MCU number
bNewTerminalNumber); // terminal number
// Generate PEER_ADD callback for old call
PeerAddCallbackParams.hCall = pOldCall->hCall; PeerAddCallbackParams.TerminalLabel = pOldCall->pPeerParticipantInfo->ParticipantInfo.TerminalLabel; PeerAddCallbackParams.pPeerTerminalID = NULL; InvokeUserConferenceCallback(pConference, CC_PEER_ADD_INDICATION, CC_OK, &PeerAddCallbackParams); if (ValidateConference(hConference) != CC_OK) { if (ValidateCall(hOldCall) == CC_OK) UnlockCall(pCall); if (ValidateCall(hCall) == CC_OK) { pCall->CallState = CALL_COMPLETE; UnlockCall(pCall); } MemFree(CallList); return CC_OK; } }
// Send new term caps to old call
SendTermCaps(pOldCall, pConference);
UnlockCall(pOldCall); } } else { // we're currently in multipoint mode
EnumerateChannelsInConference(&wNumChannels, &ChannelList, pConference, TX_CHANNEL | PROXY_CHANNEL | TXRX_CHANNEL); for (i = 0; i < wNumChannels; i++) { if (LockChannel(ChannelList[i], &pChannel) == CC_OK) { if (pChannel->bMultipointChannel) { if ((pChannel->bChannelType == TX_CHANNEL) || ((pChannel->bChannelType == TXRX_CHANNEL) && (pChannel->bLocallyOpened == TRUE))) { pTxTermCap = pChannel->pTxH245TermCap; pTxMuxTable = pChannel->pTxMuxTable; pRxTermCap = pChannel->pRxH245TermCap; pRxMuxTable = pChannel->pRxMuxTable; } else { // Note: since this is a proxy or remotely-opened
// bi-directional channel, RxTermCap and RxMuxTable
// contain the channel's term cap and mux table,
// and must be sent to other endpoints as the
// Tx term cap and mux table;
// TxTermCap and TxMuxTable should be NULL
pTxTermCap = pChannel->pRxH245TermCap; pTxMuxTable = pChannel->pRxMuxTable; pRxTermCap = pChannel->pTxH245TermCap; pRxMuxTable = pChannel->pTxMuxTable; } status = H245OpenChannel( pCall->H245Instance, pChannel->hChannel, // dwTransId
pChannel->wLocalChannelNumber, pTxTermCap, // TxMode
pTxMuxTable, // TxMux
H245_INVALID_PORT_NUMBER, // TxPort
pRxTermCap, // RxMode
pRxMuxTable, // RxMux
pChannel->pSeparateStack); if ((status == CC_OK) && (pChannel->wNumOutstandingRequests != 0)) (pChannel->wNumOutstandingRequests)++; } UnlockChannel(pChannel); } } MemFree(ChannelList);
for (i = 0; i < wNumCalls; i++) { // Don't send a message to the endpoint that just joined the conference!
if (CallList[i] != hCall) { if (LockCall(CallList[i], &pOldCall) == CC_OK) { if (bNewTerminalNumber != 0) // Send TerminalJoinedConference (new call) to old call
H245ConferenceIndication(pOldCall->H245Instance, H245_IND_TERMINAL_JOINED, // Indication Type
0, // SBE number; ignored here
bNewMCUNumber, // MCU number
bNewTerminalNumber); // terminal number
// Send CommunicationModeCommand, if necessary
if (pH245CommunicationTable != NULL) status = H245CommunicationModeCommand(pOldCall->H245Instance, pH245CommunicationTable, bCommunicationTableCount); if (bConferenceTermCapsChanged) // Send new term caps
SendTermCaps(pOldCall, pConference);
UnlockCall(pOldCall); } } } if (bConferenceTermCapsChanged) { // Generate CC_PEER_CHANGE_CAP callback
PeerChangeCapCallbackParams.pTermCapList = pConference->pConferenceTermCapList; PeerChangeCapCallbackParams.pH2250MuxCapability = pConference->pConferenceH245H2250MuxCapability; PeerChangeCapCallbackParams.pTermCapDescriptors = pConference->pConferenceTermCapDescriptors; InvokeUserConferenceCallback(pConference, CC_PEER_CHANGE_CAP_INDICATION, CC_OK, &PeerChangeCapCallbackParams); if (ValidateConference(hConference) != CC_OK) { if (ValidateCall(hCall) == CC_OK) { pCall->CallState = CALL_COMPLETE; UnlockCall(pCall); } MemFree(CallList); return CC_OK; } } }
// Generate PEER_ADD callback
PeerAddCallbackParams.hCall = pCall->hCall; PeerAddCallbackParams.TerminalLabel = pCall->pPeerParticipantInfo->ParticipantInfo.TerminalLabel; PeerAddCallbackParams.pPeerTerminalID = NULL; InvokeUserConferenceCallback(pConference, CC_PEER_ADD_INDICATION, CC_OK, &PeerAddCallbackParams); if (ValidateConference(hConference) != CC_OK) { if (ValidateCall(hCall) == CC_OK) { pCall->CallState = CALL_COMPLETE; UnlockCall(pCall); MemFree(CallList); return CC_OK; } }
if (CallType == THIRD_PARTY_INTERMEDIARY) { DestinationEndpointType.pVendorInfo = pCall->pPeerVendorInfo; DestinationEndpointType.bIsTerminal = TRUE; DestinationEndpointType.bIsGateway = FALSE;
status = Q931AcceptCall(pCall->hQ931CallInvitor, pCall->pszPeerDisplay, pCall->pPeerNonStandardData, &DestinationEndpointType, NULL, pCall->hCall); Q931Hangup(pCall->hQ931CallInvitor, CC_REJECT_NORMAL_CALL_CLEARING); } } // if (pConference->tsMultipointController == TS_TRUE)
}
MemFree(CallList);
if (ValidateConference(hConference) == CC_OK) if ((CallType == CALLER) || (CallType == THIRD_PARTY_INVITOR) || ((CallType == CALLEE) && (pConference->LocalEndpointAttached == NEVER_ATTACHED))) { // This CONNECT must apply to the local endpoint
pConference->LocalEndpointAttached = ATTACHED; InvokeUserConferenceCallback(pConference, CC_CONNECT_INDICATION, CC_OK, &ConnectCallbackParams); } // Need to validate the conference and call handles; the associated
// objects may have been deleted during user callback on this thread
if (ValidateConference(hConference) == CC_OK) UnlockConference(pConference);
if (ValidateCall(hCall) == CC_OK) { pCall->CallState = CALL_COMPLETE; UnlockCall(pCall); } return status; }
HRESULT _IndUnimplemented( H245_CONF_IND_T *pH245ConfIndData) { return H245_ERROR_NOSUP; }
HRESULT _IndFlowControl( H245_CONF_IND_T *pH245ConfIndData) { HRESULT status; CC_HCALL hCall; PCALL pCall; PCONFERENCE pConference; CC_HCONFERENCE hConference; CC_HCHANNEL hChannel; PCHANNEL pChannel; CC_FLOW_CONTROL_CALLBACK_PARAMS FlowControlCallbackParams;
if (pH245ConfIndData->u.Indication.u.IndFlowControl.Scope != H245_SCOPE_CHANNEL_NUMBER) return H245_ERROR_NOSUP;
hCall = pH245ConfIndData->u.Indication.dwPreserved; status = LockCallAndConference(hCall, &pCall, &pConference); if (status != CC_OK) { // This may be OK, if the call was cancelled while
// call setup was in progress.
return H245_ERROR_OK; }
hConference = pCall->hConference; UnlockCall(pCall);
if (FindChannelInConference(pH245ConfIndData->u.Indication.u.IndFlowControl.Channel, TRUE, // local channel number
TX_CHANNEL | PROXY_CHANNEL, CC_INVALID_HANDLE, &hChannel, pConference) != CC_OK) { UnlockConference(pConference); return H245_ERROR_OK; }
if (LockChannel(hChannel, &pChannel) != CC_OK) { UnlockConference(pConference); return H245_ERROR_OK; } if (pChannel->bChannelType == TX_CHANNEL) { UnlockChannel(pChannel); FlowControlCallbackParams.hChannel = hChannel; FlowControlCallbackParams.dwRate = pH245ConfIndData->u.Indication.u.IndFlowControl.dwRestriction; InvokeUserConferenceCallback(pConference, CC_FLOW_CONTROL_INDICATION, CC_OK, &FlowControlCallbackParams); if (ValidateConference(hConference) == CC_OK) UnlockConference(pConference); } else { // pChannel->bChannelType == PROXY_CHANNEL
if (LockCall(pChannel->hCall, &pCall) == CC_OK) { H245FlowControl(pCall->H245Instance, pH245ConfIndData->u.Indication.u.IndFlowControl.Scope, pChannel->wRemoteChannelNumber, pH245ConfIndData->u.Indication.u.IndFlowControl.wResourceID, pH245ConfIndData->u.Indication.u.IndFlowControl.dwRestriction); UnlockCall(pCall); } UnlockChannel(pChannel); UnlockConference(pConference); } return H245_ERROR_OK; }
HRESULT _IndEndSession( H245_CONF_IND_T *pH245ConfIndData) { CC_HCALL hCall;
hCall = pH245ConfIndData->u.Indication.dwPreserved; if (hCall != CC_INVALID_HANDLE) ProcessRemoteHangup(hCall, CC_INVALID_HANDLE, CC_REJECT_NORMAL_CALL_CLEARING); return H245_ERROR_OK; }
HRESULT _IndCapability( H245_CONF_IND_T *pH245ConfIndData) { CC_HCALL hCall; PCALL pCall; HRESULT status; PCONFERENCE pConference; CC_HCONFERENCE hConference; CC_PEER_CHANGE_CAP_CALLBACK_PARAMS PeerChangeCapCallbackParams; BOOL bConferenceTermCapsChanged; WORD wNumCalls; PCC_HCALL CallList; PCALL pOldCall; WORD i;
// We received a TerminalCapabilitySet message from a peer
hCall = pH245ConfIndData->u.Indication.dwPreserved; status = LockCallAndConference(hCall, &pCall, &pConference); if (status != CC_OK) { // This may be OK, if the call was cancelled while
// call setup was in progress.
return H245_ERROR_OK; }
hConference = pCall->hConference;
if ((pConference->ConferenceMode == MULTIPOINT_MODE) && (pConference->tsMultipointController == TS_TRUE)) CreateConferenceTermCaps(pConference, &bConferenceTermCapsChanged); else bConferenceTermCapsChanged = FALSE;
pCall->bLinkEstablished = TRUE;
pCall->IncomingTermCapState = TERMCAP_COMPLETE;
if (pCall->CallState == TERMCAP) { ASSERT(pCall->pPeerH245TermCapList == NULL); ASSERT(pCall->pPeerH245H2250MuxCapability == NULL); ASSERT(pCall->pPeerH245TermCapDescriptors == NULL); } else { DestroyH245TermCapList(&pCall->pPeerH245TermCapList); DestroyH245TermCap(&pCall->pPeerH245H2250MuxCapability); DestroyH245TermCapDescriptors(&pCall->pPeerH245TermCapDescriptors); }
_ConstructTermCapList(&(pCall->pPeerH245TermCapList), &(pCall->pPeerH245H2250MuxCapability), &(pCall->pPeerH245TermCapDescriptors), pCall);
if ((pCall->OutgoingTermCapState == TERMCAP_COMPLETE) && (pCall->IncomingTermCapState == TERMCAP_COMPLETE) && (pCall->CallState == TERMCAP) && (pCall->MasterSlaveState == MASTER_SLAVE_COMPLETE)) { // Note that _ProcessConnectionComplete() returns with pConference and pCall unlocked
_ProcessConnectionComplete(pConference, pCall); return H245_ERROR_OK; }
if (pCall->CallState == CALL_COMPLETE) { if ((pConference->ConferenceMode == MULTIPOINT_MODE) && (pConference->tsMultipointController == TS_TRUE)) { CreateConferenceTermCaps(pConference, &bConferenceTermCapsChanged); if (bConferenceTermCapsChanged) { EnumerateCallsInConference(&wNumCalls, &CallList, pConference, ESTABLISHED_CALL); for (i = 0; i < wNumCalls; i++) { // Don't send a message to the endpoint that just joined the conference!
if (CallList[i] != hCall) { if (LockCall(CallList[i], &pOldCall) == CC_OK) { // Send new term caps
SendTermCaps(pOldCall, pConference); UnlockCall(pOldCall); } } } if (CallList != NULL) MemFree(CallList);
// Generate CC_PEER_CHANGE_CAP callback
PeerChangeCapCallbackParams.pTermCapList = pConference->pConferenceTermCapList; PeerChangeCapCallbackParams.pH2250MuxCapability = pConference->pConferenceH245H2250MuxCapability; PeerChangeCapCallbackParams.pTermCapDescriptors = pConference->pConferenceTermCapDescriptors; InvokeUserConferenceCallback(pConference, CC_PEER_CHANGE_CAP_INDICATION, CC_OK, &PeerChangeCapCallbackParams); } } else { PeerChangeCapCallbackParams.pTermCapList = pCall->pPeerH245TermCapList; PeerChangeCapCallbackParams.pH2250MuxCapability = pCall->pPeerH245H2250MuxCapability; PeerChangeCapCallbackParams.pTermCapDescriptors = pCall->pPeerH245TermCapDescriptors; InvokeUserConferenceCallback(pConference, CC_PEER_CHANGE_CAP_INDICATION, CC_OK, &PeerChangeCapCallbackParams); } if (ValidateConference(hConference) == CC_OK) UnlockConference(pConference); if (ValidateCall(hCall) == CC_OK) UnlockCall(pCall); return H245_ERROR_OK; }
UnlockCall(pCall); UnlockConference(pConference); return H245_ERROR_OK; }
HRESULT _IndOpenT120( H245_CONF_IND_T *pH245ConfIndData) { BOOL bFailed; CC_T120_CHANNEL_REQUEST_CALLBACK_PARAMS T120ChannelRequestCallbackParams; CC_HCALL hCall; PCALL pCall; CC_HCONFERENCE hConference; PCONFERENCE pConference; CC_HCHANNEL hChannel; PCHANNEL pChannel; CC_TERMCAP *pRxTermCap = NULL; // Too big to be local variable (9K)
CC_TERMCAP *pTxTermCap = NULL; // Too big to be local variable (9K)
H245_MUX_T RxH245MuxTable; H245_MUX_T TxH245MuxTable; CC_ADDR T120Addr; CC_OCTETSTRING ExternalReference;
hCall = pH245ConfIndData->u.Indication.dwPreserved; if (LockCallAndConference(hCall, &pCall, &pConference) != CC_OK) { // Can't cancel with H245, because we don't have the H245 instance
return H245_ERROR_OK; }
hConference = pCall->hConference; if (pH245ConfIndData->u.Indication.u.IndOpen.RxDataType != H245_DATA_DATA || pH245ConfIndData->u.Indication.u.IndOpen.RxClientType != H245_CLIENT_DAT_T120 || pH245ConfIndData->u.Indication.u.IndOpen.pRxCap == NULL || pH245ConfIndData->u.Indication.u.IndOpen.pRxCap->H245Dat_T120.application.choice != DACy_applctn_t120_chosen || pH245ConfIndData->u.Indication.u.IndOpen.pRxCap->H245Dat_T120.application.u.DACy_applctn_t120.choice != separateLANStack_chosen || pH245ConfIndData->u.Indication.u.IndOpen.TxDataType != H245_DATA_DATA || pH245ConfIndData->u.Indication.u.IndOpen.TxClientType != H245_CLIENT_DAT_T120 || pH245ConfIndData->u.Indication.u.IndOpen.pTxCap == NULL || pH245ConfIndData->u.Indication.u.IndOpen.pTxCap->H245Dat_T120.application.choice != DACy_applctn_t120_chosen || pH245ConfIndData->u.Indication.u.IndOpen.pTxCap->H245Dat_T120.application.u.DACy_applctn_t120.choice != separateLANStack_chosen) { bFailed = TRUE; } else { bFailed = FALSE; }
if (pH245ConfIndData->u.Indication.u.IndOpen.pSeparateStack) { if ((pH245ConfIndData->u.Indication.u.IndOpen.pSeparateStack->networkAddress.choice == localAreaAddress_chosen) && (pH245ConfIndData->u.Indication.u.IndOpen.pSeparateStack->networkAddress.u.localAreaAddress.choice == unicastAddress_chosen) && (pH245ConfIndData->u.Indication.u.IndOpen.pSeparateStack->networkAddress.u.localAreaAddress.u.unicastAddress.choice == UnicastAddress_iPAddress_chosen)) { T120Addr.nAddrType = CC_IP_BINARY; T120Addr.bMulticast = FALSE; T120Addr.Addr.IP_Binary.wPort = pH245ConfIndData->u.Indication.u.IndOpen.pSeparateStack->networkAddress.u.localAreaAddress.u.unicastAddress.u.UnicastAddress_iPAddress.tsapIdentifier; H245IPNetworkToHost(&T120Addr.Addr.IP_Binary.dwAddr, pH245ConfIndData->u.Indication.u.IndOpen.pSeparateStack->networkAddress.u.localAreaAddress.u.unicastAddress.u.UnicastAddress_iPAddress.network.value); } else { bFailed = TRUE; } }
if (bFailed) { H245OpenChannelReject(pCall->H245Instance, // H245 instance
pH245ConfIndData->u.Indication.u.IndOpen.RxChannel, H245_REJ); // rejection reason
UnlockConference(pConference); UnlockCall(pCall); return H245_ERROR_OK; }
// These will be freed immediatly after their use (AllocAndLockChannel)
pRxTermCap = (CC_TERMCAP *)MemAlloc(sizeof(CC_TERMCAP)); pTxTermCap = (CC_TERMCAP *)MemAlloc(sizeof(CC_TERMCAP)); if((NULL == pRxTermCap) || (NULL == pTxTermCap)) { MemFree(pRxTermCap); MemFree(pTxTermCap);
H245OpenChannelReject(pCall->H245Instance, // H245 instance
pH245ConfIndData->u.Indication.u.IndOpen.RxChannel, H245_REJ); // rejection reason
UnlockConference(pConference); UnlockCall(pCall); return H245_ERROR_NOMEM; } pRxTermCap->Dir = H245_CAPDIR_RMTTX; pRxTermCap->DataType = pH245ConfIndData->u.Indication.u.IndOpen.RxDataType; pRxTermCap->ClientType = pH245ConfIndData->u.Indication.u.IndOpen.RxClientType; pRxTermCap->CapId = 0; // not used for channels
pRxTermCap->Cap = *pH245ConfIndData->u.Indication.u.IndOpen.pRxCap;
pTxTermCap->Dir = H245_CAPDIR_RMTTX; pTxTermCap->DataType = pH245ConfIndData->u.Indication.u.IndOpen.TxDataType; pTxTermCap->ClientType = pH245ConfIndData->u.Indication.u.IndOpen.TxClientType; pTxTermCap->CapId = 0; // not used for channels
pTxTermCap->Cap = *pH245ConfIndData->u.Indication.u.IndOpen.pTxCap;
RxH245MuxTable = *pH245ConfIndData->u.Indication.u.IndOpen.pRxMux; if ((pCall->pPeerParticipantInfo != NULL) && (pCall->pPeerParticipantInfo->TerminalIDState == TERMINAL_ID_VALID)) { RxH245MuxTable.u.H2250.destinationPresent = TRUE; RxH245MuxTable.u.H2250.destination.mcuNumber = pCall->pPeerParticipantInfo->ParticipantInfo.TerminalLabel.bMCUNumber; RxH245MuxTable.u.H2250.destination.terminalNumber = pCall->pPeerParticipantInfo->ParticipantInfo.TerminalLabel.bTerminalNumber; } else RxH245MuxTable.u.H2250.destinationPresent = FALSE;
if(pH245ConfIndData->u.Indication.u.IndOpen.pTxMux) { TxH245MuxTable = *pH245ConfIndData->u.Indication.u.IndOpen.pTxMux; TxH245MuxTable.u.H2250.destinationPresent = FALSE; }
bFailed = (AllocAndLockChannel(&hChannel, pConference, hCall, pTxTermCap, // Tx terminal capability
pRxTermCap, // Rx terminal capability
(pH245ConfIndData->u.Indication.u.IndOpen.pTxMux)? &TxH245MuxTable: NULL, // Tx H245 mux table
&RxH245MuxTable, // Rx H245 mux table
pH245ConfIndData->u.Indication.u.IndOpen.pSeparateStack, // separate stack
0, // user token
TXRX_CHANNEL, // channel type
0, // session ID
0, // associated session ID
pH245ConfIndData->u.Indication.u.IndOpen.RxChannel, // remote bi-dir channel number
NULL, // pLocalRTPAddr
NULL, // pLocalRTCPAddr
NULL, // pPeerRTPAddr
NULL, // pPeerRTCPAddr
FALSE, // locally opened
&pChannel) != CC_OK);
MemFree(pRxTermCap); pRxTermCap = NULL; MemFree(pTxTermCap); pTxTermCap = NULL; if(bFailed) {
H245OpenChannelReject(pCall->H245Instance, // H245 instance
pH245ConfIndData->u.Indication.u.IndOpen.RxChannel, H245_REJ); // rejection reason
UnlockConference(pConference); UnlockCall(pCall); return H245_ERROR_OK; }
if (AddChannelToConference(pChannel, pConference) != CC_OK) { H245OpenChannelReject(pCall->H245Instance, // H245 instance
pH245ConfIndData->u.Indication.u.IndOpen.RxChannel, H245_REJ); // rejection reason
UnlockConference(pConference); UnlockCall(pCall); FreeChannel(pChannel); return H245_ERROR_OK; }
T120ChannelRequestCallbackParams.hChannel = hChannel; if (pH245ConfIndData->u.Indication.u.IndOpen.pSeparateStack == NULL) { T120ChannelRequestCallbackParams.bAssociateConference = FALSE; T120ChannelRequestCallbackParams.pExternalReference = NULL; T120ChannelRequestCallbackParams.pAddr = NULL; } else { T120ChannelRequestCallbackParams.bAssociateConference = pH245ConfIndData->u.Indication.u.IndOpen.pSeparateStack->associateConference; if (pH245ConfIndData->u.Indication.u.IndOpen.pSeparateStack->bit_mask & externalReference_present) { ExternalReference.wOctetStringLength = (WORD) pH245ConfIndData->u.Indication.u.IndOpen.pSeparateStack->externalReference.length; ExternalReference.pOctetString = pH245ConfIndData->u.Indication.u.IndOpen.pSeparateStack->externalReference.value; T120ChannelRequestCallbackParams.pExternalReference = &ExternalReference; } else T120ChannelRequestCallbackParams.pExternalReference = NULL; T120ChannelRequestCallbackParams.pAddr = &T120Addr; } if ((pConference->ConferenceMode == MULTIPOINT_MODE) && (pConference->tsMultipointController == TS_TRUE)) T120ChannelRequestCallbackParams.bMultipointController = TRUE; else T120ChannelRequestCallbackParams.bMultipointController = FALSE; if (pH245ConfIndData->u.Indication.u.IndOpen.pRxMux->u.H2250.destinationPresent) { T120ChannelRequestCallbackParams.TerminalLabel.bMCUNumber = (BYTE)pH245ConfIndData->u.Indication.u.IndOpen.pRxMux->u.H2250.destination.mcuNumber; T120ChannelRequestCallbackParams.TerminalLabel.bTerminalNumber = (BYTE)pH245ConfIndData->u.Indication.u.IndOpen.pRxMux->u.H2250.destination.terminalNumber; } else { T120ChannelRequestCallbackParams.TerminalLabel.bMCUNumber = 255; T120ChannelRequestCallbackParams.TerminalLabel.bTerminalNumber = 255; }
pChannel->wNumOutstandingRequests = 1;
InvokeUserConferenceCallback(pConference, CC_T120_CHANNEL_REQUEST_INDICATION, CC_OK, &T120ChannelRequestCallbackParams);
if (ValidateChannel(hChannel) == CC_OK) UnlockChannel(pChannel); if (ValidateCall(hCall) == CC_OK) UnlockCall(pCall); if (ValidateConference(hConference) == CC_OK) UnlockConference(pConference);
return H245_ERROR_OK; }
HRESULT _IndOpen( H245_CONF_IND_T *pH245ConfIndData) { CC_HCALL hCall; PCALL pCall; PCALL pOldCall; CC_HCONFERENCE hConference; PCONFERENCE pConference; WORD wNumCalls; PCC_HCALL CallList; CC_HCHANNEL hChannel; PCHANNEL pChannel; CC_TERMCAP TermCap; CC_ADDR PeerRTPAddr; CC_ADDR PeerRTCPAddr; CC_RX_CHANNEL_REQUEST_CALLBACK_PARAMS RxChannelRequestCallbackParams; BYTE bChannelType; WORD i; H245_MUX_T H245MuxTable; PCC_ADDR pLocalRTPAddr; PCC_ADDR pLocalRTCPAddr; PCC_ADDR pPeerRTPAddr; PCC_ADDR pPeerRTCPAddr; BOOL bFoundSession; HRESULT status;
// First check to see if this is a T.120 channel request,
// as T.120 channels are handled differently then other channels
if (pH245ConfIndData->u.Indication.u.IndOpen.RxClientType == H245_CLIENT_DAT_T120) { status = _IndOpenT120(pH245ConfIndData); return status; }
hCall = pH245ConfIndData->u.Indication.dwPreserved; if (LockCallAndConference(hCall, &pCall, &pConference) != CC_OK) { // Can't cancel with H245, because we don't have the H245 instance
return H245_ERROR_OK; }
// Make sure that this is not a bi-directional channel
if (pH245ConfIndData->u.Indication.u.IndOpen.pTxMux != NULL) { H245OpenChannelReject(pCall->H245Instance, // H245 instance
pH245ConfIndData->u.Indication.u.IndOpen.RxChannel, H245_REJ); // rejection reason
UnlockConference(pConference); UnlockCall(pCall); return H245_ERROR_OK; }
hConference = pCall->hConference; TermCap.Dir = H245_CAPDIR_RMTTX; TermCap.DataType = pH245ConfIndData->u.Indication.u.IndOpen.RxDataType; TermCap.ClientType = pH245ConfIndData->u.Indication.u.IndOpen.RxClientType; TermCap.CapId = 0; // not used for Rx channels
TermCap.Cap = *pH245ConfIndData->u.Indication.u.IndOpen.pRxCap; RxChannelRequestCallbackParams.pChannelCapability = &TermCap;
if ((pH245ConfIndData->u.Indication.u.IndOpen.pRxMux != NULL) && (pH245ConfIndData->u.Indication.u.IndOpen.pRxMux->Kind == H245_H2250)) { RxChannelRequestCallbackParams.bSessionID = pH245ConfIndData->u.Indication.u.IndOpen.pRxMux->u.H2250.sessionID; if (pH245ConfIndData->u.Indication.u.IndOpen.pRxMux->u.H2250.associatedSessionIDPresent) RxChannelRequestCallbackParams.bAssociatedSessionID = pH245ConfIndData->u.Indication.u.IndOpen.pRxMux->u.H2250.associatedSessionID; else RxChannelRequestCallbackParams.bAssociatedSessionID = 0; if (pH245ConfIndData->u.Indication.u.IndOpen.pRxMux->u.H2250.silenceSuppressionPresent) RxChannelRequestCallbackParams.bSilenceSuppression = pH245ConfIndData->u.Indication.u.IndOpen.pRxMux->u.H2250.silenceSuppression; else RxChannelRequestCallbackParams.bSilenceSuppression = FALSE; if ((pH245ConfIndData->u.Indication.u.IndOpen.pRxMux->u.H2250.mediaChannelPresent) && ((pH245ConfIndData->u.Indication.u.IndOpen.pRxMux->u.H2250.mediaChannel.type == H245_IP_MULTICAST) || (pH245ConfIndData->u.Indication.u.IndOpen.pRxMux->u.H2250.mediaChannel.type == H245_IP_UNICAST))) { RxChannelRequestCallbackParams.pPeerRTPAddr = &PeerRTPAddr; PeerRTPAddr.nAddrType = CC_IP_BINARY; if (pH245ConfIndData->u.Indication.u.IndOpen.pRxMux->u.H2250.mediaChannel.type == H245_IP_MULTICAST) PeerRTPAddr.bMulticast = TRUE; else PeerRTPAddr.bMulticast = FALSE; PeerRTPAddr.Addr.IP_Binary.wPort = pH245ConfIndData->u.Indication.u.IndOpen.pRxMux->u.H2250.mediaChannel.u.ip.tsapIdentifier; H245IPNetworkToHost(&PeerRTPAddr.Addr.IP_Binary.dwAddr, pH245ConfIndData->u.Indication.u.IndOpen.pRxMux->u.H2250.mediaChannel.u.ip.network); } else RxChannelRequestCallbackParams.pPeerRTPAddr = NULL;
if ((pH245ConfIndData->u.Indication.u.IndOpen.pRxMux->u.H2250.mediaControlChannelPresent) && ((pH245ConfIndData->u.Indication.u.IndOpen.pRxMux->u.H2250.mediaControlChannel.type == H245_IP_MULTICAST) || (pH245ConfIndData->u.Indication.u.IndOpen.pRxMux->u.H2250.mediaControlChannel.type == H245_IP_UNICAST))) { RxChannelRequestCallbackParams.pPeerRTCPAddr = &PeerRTCPAddr; PeerRTCPAddr.nAddrType = CC_IP_BINARY; if (pH245ConfIndData->u.Indication.u.IndOpen.pRxMux->u.H2250.mediaControlChannel.type == H245_IP_MULTICAST) PeerRTCPAddr.bMulticast = TRUE; else PeerRTCPAddr.bMulticast = FALSE; PeerRTCPAddr.Addr.IP_Binary.wPort = pH245ConfIndData->u.Indication.u.IndOpen.pRxMux->u.H2250.mediaControlChannel.u.ip.tsapIdentifier; H245IPNetworkToHost(&PeerRTCPAddr.Addr.IP_Binary.dwAddr, pH245ConfIndData->u.Indication.u.IndOpen.pRxMux->u.H2250.mediaControlChannel.u.ip.network); } else RxChannelRequestCallbackParams.pPeerRTCPAddr = NULL;
if (pH245ConfIndData->u.Indication.u.IndOpen.pRxMux->u.H2250.destinationPresent) { RxChannelRequestCallbackParams.TerminalLabel.bMCUNumber = (BYTE)pH245ConfIndData->u.Indication.u.IndOpen.pRxMux->u.H2250.destination.mcuNumber; RxChannelRequestCallbackParams.TerminalLabel.bTerminalNumber = (BYTE)pH245ConfIndData->u.Indication.u.IndOpen.pRxMux->u.H2250.destination.terminalNumber; } else { RxChannelRequestCallbackParams.TerminalLabel.bMCUNumber = 255; RxChannelRequestCallbackParams.TerminalLabel.bTerminalNumber = 255; }
if (pH245ConfIndData->u.Indication.u.IndOpen.pRxMux->u.H2250.dynamicRTPPayloadTypePresent) RxChannelRequestCallbackParams.bRTPPayloadType = pH245ConfIndData->u.Indication.u.IndOpen.pRxMux->u.H2250.dynamicRTPPayloadType; else RxChannelRequestCallbackParams.bRTPPayloadType = 0; } else { H245OpenChannelReject(pCall->H245Instance, // H245 instance
pH245ConfIndData->u.Indication.u.IndOpen.RxChannel, H245_REJ); // rejection reason
UnlockConference(pConference); UnlockCall(pCall); return H245_ERROR_OK; }
// XXX -- someday we should allow dynamic sessions to be created on the MC
if (pH245ConfIndData->u.Indication.u.IndOpen.pRxMux->u.H2250.sessionID == 0) { H245OpenChannelReject(pCall->H245Instance, // H245 instance
pH245ConfIndData->u.Indication.u.IndOpen.RxChannel, H245_REJ); // rejection reason
UnlockConference(pConference); UnlockCall(pCall); return H245_ERROR_OK; }
if (pConference->ConferenceMode == MULTIPOINT_MODE) { if ((pConference->tsMultipointController == TS_TRUE) && ((RxChannelRequestCallbackParams.pPeerRTPAddr != NULL) || (RxChannelRequestCallbackParams.pPeerRTCPAddr != NULL)) || ((pConference->tsMultipointController == TS_FALSE) && ((RxChannelRequestCallbackParams.pPeerRTPAddr == NULL) || (RxChannelRequestCallbackParams.pPeerRTCPAddr == NULL) || (RxChannelRequestCallbackParams.bSessionID == 0)))) { H245OpenChannelReject(pCall->H245Instance, // H245 instance
pH245ConfIndData->u.Indication.u.IndOpen.RxChannel, H245_REJ); // rejection reason
UnlockConference(pConference); UnlockCall(pCall); return H245_ERROR_OK; }
// Validate session ID
pLocalRTPAddr = NULL; pLocalRTCPAddr = NULL; bFoundSession = FALSE; if (pConference->pSessionTable != NULL) { for (i = 0; i < pConference->pSessionTable->wLength; i++) { if (pH245ConfIndData->u.Indication.u.IndOpen.pRxMux->u.H2250.sessionID == pConference->pSessionTable->SessionInfoArray[i].bSessionID) { bFoundSession = TRUE; pLocalRTPAddr = pConference->pSessionTable->SessionInfoArray[i].pRTPAddr; pLocalRTCPAddr = pConference->pSessionTable->SessionInfoArray[i].pRTCPAddr; break; } } } if (bFoundSession == FALSE) { H245OpenChannelReject(pCall->H245Instance, // H245 instance
pH245ConfIndData->u.Indication.u.IndOpen.RxChannel, H245_REJ); // rejection reason
UnlockConference(pConference); UnlockCall(pCall); return H245_ERROR_OK; }
ASSERT(pLocalRTPAddr != NULL); ASSERT(pLocalRTCPAddr != NULL);
if (pConference->tsMultipointController == TS_TRUE) { pPeerRTPAddr = pLocalRTPAddr; pPeerRTCPAddr = pLocalRTCPAddr; RxChannelRequestCallbackParams.pPeerRTPAddr = pLocalRTPAddr; RxChannelRequestCallbackParams.pPeerRTCPAddr = pLocalRTCPAddr; bChannelType = PROXY_CHANNEL; } else { // multipoint mode, not MC
pLocalRTPAddr = RxChannelRequestCallbackParams.pPeerRTPAddr; pLocalRTCPAddr = RxChannelRequestCallbackParams.pPeerRTCPAddr; pPeerRTPAddr = RxChannelRequestCallbackParams.pPeerRTPAddr; pPeerRTCPAddr = RxChannelRequestCallbackParams.pPeerRTCPAddr; bChannelType = RX_CHANNEL; } } else { // not multipoint mode
pLocalRTPAddr = NULL; pLocalRTCPAddr = NULL; pPeerRTPAddr = RxChannelRequestCallbackParams.pPeerRTPAddr; pPeerRTCPAddr = RxChannelRequestCallbackParams.pPeerRTCPAddr; bChannelType = RX_CHANNEL; }
H245MuxTable = *pH245ConfIndData->u.Indication.u.IndOpen.pRxMux; if ((pCall->pPeerParticipantInfo != NULL) && (pCall->pPeerParticipantInfo->TerminalIDState == TERMINAL_ID_VALID)) { H245MuxTable.u.H2250.destinationPresent = TRUE; H245MuxTable.u.H2250.destination.mcuNumber = pCall->pPeerParticipantInfo->ParticipantInfo.TerminalLabel.bMCUNumber; H245MuxTable.u.H2250.destination.terminalNumber = pCall->pPeerParticipantInfo->ParticipantInfo.TerminalLabel.bTerminalNumber; } else H245MuxTable.u.H2250.destinationPresent = FALSE; if (pLocalRTPAddr != NULL) { if (pLocalRTPAddr->bMulticast) H245MuxTable.u.H2250.mediaChannel.type = H245_IP_MULTICAST; else H245MuxTable.u.H2250.mediaChannel.type = H245_IP_UNICAST; H245MuxTable.u.H2250.mediaChannel.u.ip.tsapIdentifier = pLocalRTPAddr->Addr.IP_Binary.wPort; HostToH245IPNetwork(H245MuxTable.u.H2250.mediaChannel.u.ip.network, pLocalRTPAddr->Addr.IP_Binary.dwAddr); H245MuxTable.u.H2250.mediaChannelPresent = TRUE; } else H245MuxTable.u.H2250.mediaChannelPresent = FALSE; if (pLocalRTCPAddr != NULL) { if (pLocalRTCPAddr->bMulticast) H245MuxTable.u.H2250.mediaControlChannel.type = H245_IP_MULTICAST; else H245MuxTable.u.H2250.mediaControlChannel.type = H245_IP_UNICAST; H245MuxTable.u.H2250.mediaControlChannel.u.ip.tsapIdentifier = pLocalRTCPAddr->Addr.IP_Binary.wPort; HostToH245IPNetwork(H245MuxTable.u.H2250.mediaControlChannel.u.ip.network, pLocalRTCPAddr->Addr.IP_Binary.dwAddr); H245MuxTable.u.H2250.mediaControlChannelPresent = TRUE; } else H245MuxTable.u.H2250.mediaControlChannelPresent = FALSE;
if (AllocAndLockChannel(&hChannel, pConference, hCall, NULL, // Tx terminal capability
&TermCap, // Rx terminal capability
NULL, // Tx H245 mux table
&H245MuxTable, // Rx H245 mux table
NULL, // separate stack
0, // user token
bChannelType, pH245ConfIndData->u.Indication.u.IndOpen.pRxMux->u.H2250.sessionID, RxChannelRequestCallbackParams.bAssociatedSessionID, pH245ConfIndData->u.Indication.u.IndOpen.RxChannel, pLocalRTPAddr, // pLocalRTPAddr
pLocalRTCPAddr, // pLocalRTCPAddr
pPeerRTPAddr, // pPeerRTPAddr
pPeerRTCPAddr, // pPeerRTCPAddr
FALSE, // locally opened
&pChannel) != CC_OK) {
H245OpenChannelReject(pCall->H245Instance, // H245 instance
pH245ConfIndData->u.Indication.u.IndOpen.RxChannel, H245_REJ); // rejection reason
UnlockConference(pConference); UnlockCall(pCall); return H245_ERROR_OK; }
if (AddChannelToConference(pChannel, pConference) != CC_OK) { H245OpenChannelReject(pCall->H245Instance, // H245 instance
pH245ConfIndData->u.Indication.u.IndOpen.RxChannel, H245_REJ); // rejection reason
UnlockConference(pConference); UnlockCall(pCall); FreeChannel(pChannel); return H245_ERROR_OK; }
RxChannelRequestCallbackParams.hChannel = hChannel; if ((pConference->ConferenceMode == MULTIPOINT_MODE) && (pConference->tsMultipointController == TS_TRUE)) { // Open this channel to each peer in the conference (except the peer
// that requested this channel)
EnumerateCallsInConference(&wNumCalls, &CallList, pConference, ESTABLISHED_CALL); for (i = 0; i < wNumCalls; i++) { if (CallList[i] != hCall) { if (LockCall(CallList[i], &pOldCall) == CC_OK) { ASSERT(pChannel->bChannelType == PROXY_CHANNEL); // Note: since this is a proxy channel, RxTermCap and RxMuxTable
// contain the channel's term cap and mux table, and must be sent
// to other endpoints as the Tx term cap and mux table;
// TxTermCap and TxMuxTable should be NULL
if (H245OpenChannel(pOldCall->H245Instance, pChannel->hChannel, // dwTransId
pChannel->wLocalChannelNumber, pChannel->pRxH245TermCap, // TxMode
pChannel->pRxMuxTable, // TxMux
H245_INVALID_PORT_NUMBER, // TxPort
pChannel->pTxH245TermCap, // RxMode
pChannel->pTxMuxTable, // RxMux
pChannel->pSeparateStack) == CC_OK) (pChannel->wNumOutstandingRequests)++; UnlockCall(pOldCall); } } } MemFree(CallList); if (pConference->LocalEndpointAttached == ATTACHED) (pChannel->wNumOutstandingRequests)++; if (pChannel->wNumOutstandingRequests == 0) { H245OpenChannelReject(pCall->H245Instance, // H245 instance
pH245ConfIndData->u.Indication.u.IndOpen.RxChannel, H245_REJ); // rejection reason
UnlockConference(pConference); UnlockCall(pCall); FreeChannel(pChannel); return H245_ERROR_OK; } } else pChannel->wNumOutstandingRequests = 1; InvokeUserConferenceCallback(pConference, CC_RX_CHANNEL_REQUEST_INDICATION, CC_OK, &RxChannelRequestCallbackParams);
if (ValidateChannel(hChannel) == CC_OK) UnlockChannel(pChannel); if (ValidateCall(hCall) == CC_OK) UnlockCall(pCall); if (ValidateConference(hConference) == CC_OK) UnlockConference(pConference);
return H245_ERROR_OK; }
HRESULT _IndOpenConf( H245_CONF_IND_T *pH245ConfIndData) { CC_HCALL hCall; PCALL pCall; CC_HCONFERENCE hConference; PCONFERENCE pConference; CC_HCHANNEL hChannel; CC_ACCEPT_CHANNEL_CALLBACK_PARAMS AcceptChannelCallbackParams;
// Bi-directional channel open initiated by remote peer is now complete.
// Local peer may now send data over this channel.
hCall = pH245ConfIndData->u.Indication.dwPreserved; if (LockCallAndConference(hCall, &pCall, &pConference) != CC_OK) return H245_ERROR_OK;
hConference = pConference->hConference; UnlockCall(pCall);
if (FindChannelInConference(pH245ConfIndData->u.Indication.u.IndOpenConf.TxChannel, FALSE, // remote channel number
TXRX_CHANNEL, hCall, &hChannel, pConference) != CC_OK) { UnlockConference(pConference); return H245_ERROR_OK; }
AcceptChannelCallbackParams.hChannel = hChannel; InvokeUserConferenceCallback(pConference, CC_ACCEPT_CHANNEL_INDICATION, CC_OK, &AcceptChannelCallbackParams);
if (ValidateConference(hConference) == CC_OK) UnlockConference(pConference);
return H245_ERROR_OK; }
HRESULT _IndMstslv( H245_CONF_IND_T *pH245ConfIndData) { CC_HCALL hCall; PCALL pCall; PCONFERENCE pConference; CC_CONNECT_CALLBACK_PARAMS ConnectCallbackParams; CC_HCALL hEnqueuedCall; PCALL pEnqueuedCall; CC_HCONFERENCE hConference; HRESULT status;
hCall = pH245ConfIndData->u.Indication.dwPreserved; if (LockCallAndConference(hCall, &pCall, &pConference) != CC_OK) { // Can't cancel with H245, because we don't have the H245 instance
return H245_ERROR_OK; }
ASSERT(pCall->MasterSlaveState != MASTER_SLAVE_COMPLETE);
switch (pH245ConfIndData->u.Indication.u.IndMstSlv) { case H245_MASTER: pConference->tsMaster = TS_TRUE; if (pConference->tsMultipointController == TS_UNKNOWN) { ASSERT(pConference->bMultipointCapable == TRUE); pConference->tsMultipointController = TS_TRUE;
// place all calls enqueued on this conference object
for ( ; ; ) { // Start up all enqueued calls, if any exist
status = RemoveEnqueuedCallFromConference(pConference, &hEnqueuedCall); if ((status != CC_OK) || (hEnqueuedCall == CC_INVALID_HANDLE)) break;
status = LockCall(hEnqueuedCall, &pEnqueuedCall); if (status == CC_OK) { pEnqueuedCall->CallState = PLACED;
status = PlaceCall(pEnqueuedCall, pConference); UnlockCall(pEnqueuedCall); } } } break;
case H245_SLAVE: ASSERT(pConference->tsMaster != TS_TRUE); ASSERT(pConference->tsMultipointController != TS_TRUE); pConference->tsMaster = TS_FALSE; pConference->tsMultipointController = TS_FALSE;
// XXX -- we may eventually want to re-enqueue these requests
// and set an expiration timer
hConference = pConference->hConference; for ( ; ; ) { status = RemoveEnqueuedCallFromConference(pConference, &hEnqueuedCall); if ((status != CC_OK) || (hEnqueuedCall == CC_INVALID_HANDLE)) break;
status = LockCall(hEnqueuedCall, &pEnqueuedCall); if (status == CC_OK) { MarkCallForDeletion(pEnqueuedCall); ConnectCallbackParams.pNonStandardData = pEnqueuedCall->pPeerNonStandardData; ConnectCallbackParams.pszPeerDisplay = pEnqueuedCall->pszPeerDisplay; ConnectCallbackParams.bRejectReason = CC_REJECT_UNDEFINED_REASON; ConnectCallbackParams.pTermCapList = pEnqueuedCall->pPeerH245TermCapList; ConnectCallbackParams.pH2250MuxCapability = pEnqueuedCall->pPeerH245H2250MuxCapability; ConnectCallbackParams.pTermCapDescriptors = pEnqueuedCall->pPeerH245TermCapDescriptors; ConnectCallbackParams.pLocalAddr = pEnqueuedCall->pQ931LocalConnectAddr; if (pEnqueuedCall->pQ931DestinationAddr == NULL) ConnectCallbackParams.pPeerAddr = pEnqueuedCall->pQ931PeerConnectAddr; else ConnectCallbackParams.pPeerAddr = pEnqueuedCall->pQ931DestinationAddr; ConnectCallbackParams.pVendorInfo = pEnqueuedCall->pPeerVendorInfo; ConnectCallbackParams.bMultipointConference = TRUE; ConnectCallbackParams.pConferenceID = &pConference->ConferenceID; ConnectCallbackParams.pMCAddress = pConference->pMultipointControllerAddr; ConnectCallbackParams.pAlternateAddress = NULL; ConnectCallbackParams.dwUserToken = pEnqueuedCall->dwUserToken;
InvokeUserConferenceCallback(pConference, CC_CONNECT_INDICATION, CC_NOT_MULTIPOINT_CAPABLE, &ConnectCallbackParams); if (ValidateCallMarkedForDeletion(hEnqueuedCall) == CC_OK) FreeCall(pEnqueuedCall); if (ValidateConference(hConference) != CC_OK) { if (ValidateCall(hCall) == CC_OK) UnlockCall(pCall); return H245_ERROR_OK; } } } break;
default: // H245_INDETERMINATE
UnlockConference(pConference); if (++pCall->wMasterSlaveRetry < MASTER_SLAVE_RETRY_MAX) { H245InitMasterSlave(pCall->H245Instance, pCall->H245Instance); UnlockCall(pCall); } else { UnlockCall(pCall); ProcessRemoteHangup(hCall, CC_INVALID_HANDLE, CC_REJECT_UNDEFINED_REASON); } return H245_ERROR_OK; } // switch
pCall->MasterSlaveState = MASTER_SLAVE_COMPLETE;
if ((pCall->OutgoingTermCapState == TERMCAP_COMPLETE) && (pCall->IncomingTermCapState == TERMCAP_COMPLETE) && (pCall->CallState == TERMCAP) && (pCall->MasterSlaveState == MASTER_SLAVE_COMPLETE)) { // Note that _ProcessConnectionComplete() returns with pConference and pCall unlocked
_ProcessConnectionComplete(pConference, pCall); return H245_ERROR_OK; } UnlockCall(pCall); UnlockConference(pConference); return H245_ERROR_OK; }
HRESULT _IndClose( H245_CONF_IND_T *pH245ConfIndData) { CC_HCALL hCall; PCALL pCall; CC_HCONFERENCE hConference; PCONFERENCE pConference; CC_HCHANNEL hChannel; PCHANNEL pChannel; WORD i; WORD wNumCalls; PCC_HCALL CallList; CC_RX_CHANNEL_CLOSE_CALLBACK_PARAMS RxChannelCloseCallbackParams; #ifdef GATEKEEPER
unsigned uBandwidth; #endif // GATEKEEPER
hCall = pH245ConfIndData->u.Indication.dwPreserved; if (LockCallAndConference(hCall, &pCall, &pConference) != CC_OK) return H245_ERROR_OK;
hConference = pCall->hConference; UnlockCall(pCall);
if (FindChannelInConference(pH245ConfIndData->u.Indication.u.IndClose.Channel, FALSE, // remote channel number
RX_CHANNEL | TXRX_CHANNEL | PROXY_CHANNEL, hCall, &hChannel, pConference) != CC_OK) { UnlockConference(pConference); return H245_ERROR_OK; }
if (LockChannel(hChannel, &pChannel) != CC_OK) return H245_ERROR_OK;
EnumerateCallsInConference(&wNumCalls, &CallList, pConference, ESTABLISHED_CALL);
#ifdef GATEKEEPER
if(GKIExists()) { if (pChannel->bChannelType != TXRX_CHANNEL) { uBandwidth = pChannel->dwChannelBitRate / 100; for (i = 0; i < wNumCalls; i++) { if (LockCall(CallList[i], &pCall) == CC_OK) { if (uBandwidth && pCall->GkiCall.uBandwidthUsed >= uBandwidth) { if (GkiCloseChannel(&pCall->GkiCall, pChannel->dwChannelBitRate, hChannel) == CC_OK) { uBandwidth = 0; UnlockCall(pCall); break; } } UnlockCall(pCall); } } // for
} } #endif // GATEKEEPER
if (pChannel->bChannelType == PROXY_CHANNEL) { ASSERT(pConference->ConferenceMode == MULTIPOINT_MODE); ASSERT(pConference->tsMultipointController == TS_TRUE); ASSERT(pChannel->bMultipointChannel == TRUE);
for (i = 0; i < wNumCalls; i++) { if (CallList[i] != hCall) { if (LockCall(CallList[i], &pCall) == CC_OK) { H245CloseChannel(pCall->H245Instance, // H245 instance
0, // dwTransId
pChannel->wLocalChannelNumber); UnlockCall(pCall); } } } }
if (CallList != NULL) MemFree(CallList);
if (pChannel->tsAccepted == TS_TRUE) { RxChannelCloseCallbackParams.hChannel = hChannel; InvokeUserConferenceCallback(pConference, CC_RX_CHANNEL_CLOSE_INDICATION, CC_OK, &RxChannelCloseCallbackParams); }
if (ValidateChannel(hChannel) == CC_OK) FreeChannel(pChannel); if (ValidateConference(hConference) == CC_OK) UnlockConference(pConference); return H245_ERROR_OK; }
HRESULT _IndRequestClose( H245_CONF_IND_T *pH245ConfIndData) { CC_HCALL hCall; PCALL pCall; CC_HCONFERENCE hConference; PCONFERENCE pConference; CC_HCHANNEL hChannel; PCHANNEL pChannel; CC_TX_CHANNEL_CLOSE_REQUEST_CALLBACK_PARAMS TxChannelCloseRequestCallbackParams;
hCall = pH245ConfIndData->u.Indication.dwPreserved; if (LockCallAndConference(hCall, &pCall, &pConference) != CC_OK) return H245_ERROR_OK;
hConference = pCall->hConference; UnlockCall(pCall);
if (FindChannelInConference(pH245ConfIndData->u.Indication.u.IndClose.Channel, TRUE, // local channel number
TX_CHANNEL | TXRX_CHANNEL | PROXY_CHANNEL, CC_INVALID_HANDLE, &hChannel, pConference) != CC_OK) { UnlockConference(pConference); return H245_ERROR_OK; }
if (LockChannel(hChannel, &pChannel) != CC_OK) { UnlockConference(pConference); return H245_ERROR_OK; } if ((pChannel->bChannelType == TX_CHANNEL) || (pChannel->bChannelType == TXRX_CHANNEL)) { EnqueueRequest(&pChannel->pCloseRequests, hCall); UnlockChannel(pChannel); TxChannelCloseRequestCallbackParams.hChannel = hChannel; InvokeUserConferenceCallback(pConference, CC_TX_CHANNEL_CLOSE_REQUEST_INDICATION, CC_OK, &TxChannelCloseRequestCallbackParams); if (ValidateConference(hConference) == CC_OK) UnlockConference(pConference); } else { // pChannel->bChannelType == PROXY_CHANNEL
if (LockCall(pChannel->hCall, &pCall) == CC_OK) { // Note that dwTransID is set to the call handle of the peer who
// initiated the close channel request. When the close channel response
// is received, the dwTransID gives us back the call handle to which
// the response must be forwarded
H245CloseChannelReq(pCall->H245Instance, hCall, // dwTransID
pChannel->wRemoteChannelNumber); UnlockCall(pCall); } UnlockChannel(pChannel); UnlockConference(pConference); } return H245_ERROR_OK; }
HRESULT _IndNonStandard( H245_CONF_IND_T *pH245ConfIndData) { CC_HCALL hCall; PCALL pCall; CC_HCONFERENCE hConference; PCONFERENCE pConference; CC_RX_NONSTANDARD_MESSAGE_CALLBACK_PARAMS RxNonStandardMessageCallbackParams;
// We only handle H221 non-standard messages; if pwObjectId is non-NULL,
// ignore the message
if (pH245ConfIndData->u.Indication.u.IndNonstandard.pwObjectId != NULL) return H245_ERROR_OK;
hCall = pH245ConfIndData->u.Indication.dwPreserved; if (LockCallAndConference(hCall, &pCall, &pConference) != CC_OK) return H245_ERROR_OK;
hConference = pCall->hConference;
switch (pH245ConfIndData->u.Indication.Indicator) { case H245_IND_NONSTANDARD_REQUEST: RxNonStandardMessageCallbackParams.bH245MessageType = CC_H245_MESSAGE_REQUEST; break; case H245_IND_NONSTANDARD_RESPONSE: RxNonStandardMessageCallbackParams.bH245MessageType = CC_H245_MESSAGE_RESPONSE; break; case H245_IND_NONSTANDARD_COMMAND: RxNonStandardMessageCallbackParams.bH245MessageType = CC_H245_MESSAGE_COMMAND; break; case H245_IND_NONSTANDARD: RxNonStandardMessageCallbackParams.bH245MessageType = CC_H245_MESSAGE_INDICATION; break; default: UnlockConference(pConference); return H245_ERROR_NOSUP; }
RxNonStandardMessageCallbackParams.NonStandardData.sData.pOctetString = pH245ConfIndData->u.Indication.u.IndNonstandard.pData; RxNonStandardMessageCallbackParams.NonStandardData.sData.wOctetStringLength = (WORD)pH245ConfIndData->u.Indication.u.IndNonstandard.dwDataLength; RxNonStandardMessageCallbackParams.NonStandardData.bCountryCode = pH245ConfIndData->u.Indication.u.IndNonstandard.byCountryCode; RxNonStandardMessageCallbackParams.NonStandardData.bExtension = pH245ConfIndData->u.Indication.u.IndNonstandard.byExtension; RxNonStandardMessageCallbackParams.NonStandardData.wManufacturerCode = pH245ConfIndData->u.Indication.u.IndNonstandard.wManufacturerCode; RxNonStandardMessageCallbackParams.hCall = pCall->hCall; if (pCall->pPeerParticipantInfo != NULL) RxNonStandardMessageCallbackParams.InitiatorTerminalLabel = pCall->pPeerParticipantInfo->ParticipantInfo.TerminalLabel; else { RxNonStandardMessageCallbackParams.InitiatorTerminalLabel.bMCUNumber = 255; RxNonStandardMessageCallbackParams.InitiatorTerminalLabel.bTerminalNumber = 255; } InvokeUserConferenceCallback(pConference, CC_RX_NONSTANDARD_MESSAGE_INDICATION, CC_OK, &RxNonStandardMessageCallbackParams);
if (ValidateConference(hConference) == CC_OK) UnlockConference(pConference); if (ValidateCall(hCall) == CC_OK) UnlockCall(pCall); return H245_ERROR_OK; }
HRESULT _IndMiscellaneous( H245_CONF_IND_T *pH245ConfIndData, MiscellaneousIndication *pMiscellaneousIndication) { HRESULT status = CC_OK; CC_HCALL hCall; PCALL pCall; PCALL pOldCall; CC_HCONFERENCE hConference; PCONFERENCE pConference; CC_HCHANNEL hChannel; PCHANNEL pChannel; WORD i; WORD wNumCalls; PCC_HCALL CallList; PDU_T *pPdu = NULL; CC_MUTE_CALLBACK_PARAMS MuteCallbackParams; CC_UNMUTE_CALLBACK_PARAMS UnMuteCallbackParams; CC_H245_MISCELLANEOUS_INDICATION_CALLBACK_PARAMS H245MiscellaneousIndicationCallbackParams;
if (pMiscellaneousIndication == NULL) // Should never hit this case
return H245_ERROR_NOSUP;
hCall = pH245ConfIndData->u.Indication.dwPreserved; if (LockCallAndConference(hCall, &pCall, &pConference) != CC_OK) return H245_ERROR_OK;
hConference = pCall->hConference;
switch (pMiscellaneousIndication->type.choice) { case logicalChannelActive_chosen: case logicalChannelInactive_chosen:
UnlockCall(pCall);
if (FindChannelInConference(pMiscellaneousIndication->logicalChannelNumber, FALSE, // remote channel number
RX_CHANNEL | PROXY_CHANNEL, hCall, &hChannel, pConference) != CC_OK) { UnlockConference(pConference); return H245_ERROR_OK; }
if (LockChannel(hChannel, &pChannel) != CC_OK) { UnlockConference(pConference); return H245_ERROR_OK; }
if (pChannel->bChannelType == PROXY_CHANNEL) { ASSERT(pConference->ConferenceMode == MULTIPOINT_MODE); ASSERT(pConference->tsMultipointController == TS_TRUE); ASSERT(pChannel->bMultipointChannel == TRUE);
// Construct an H.245 PDU to hold a miscellaneous indication
// of "logical channel inactive" (mute) or "logical channel active" (unmute)
pPdu = (PDU_T *)MemAlloc(sizeof(PDU_T)); if(NULL != pPdu) { pPdu->choice = indication_chosen; pPdu->u.indication.choice = miscellaneousIndication_chosen; pPdu->u.indication.u.miscellaneousIndication.logicalChannelNumber = pChannel->wLocalChannelNumber; pPdu->u.indication.u.miscellaneousIndication.type.choice = pMiscellaneousIndication->type.choice;
EnumerateCallsInConference(&wNumCalls, &CallList, pConference, ESTABLISHED_CALL); for (i = 0; i < wNumCalls; i++) { if (CallList[i] != hCall) { if (LockCall(CallList[i], &pCall) == CC_OK) { H245SendPDU(pCall->H245Instance, pPdu); UnlockCall(pCall); } } } MemFree(CallList); MemFree(pPdu); pPdu = NULL; } }
if (pMiscellaneousIndication->type.choice == logicalChannelActive_chosen) { if (pChannel->tsAccepted == TS_TRUE) { UnMuteCallbackParams.hChannel = hChannel; InvokeUserConferenceCallback(pConference, CC_UNMUTE_INDICATION, CC_OK, &UnMuteCallbackParams); } } else { if (pChannel->tsAccepted == TS_TRUE) { MuteCallbackParams.hChannel = hChannel; InvokeUserConferenceCallback(pConference, CC_MUTE_INDICATION, CC_OK, &MuteCallbackParams); } }
if (ValidateChannel(hChannel) == CC_OK) UnlockChannel(pChannel); if (ValidateConference(hConference) == CC_OK) UnlockConference(pConference); status = H245_ERROR_OK; break;
case multipointConference_chosen: case cnclMltpntCnfrnc_chosen: // We're required to support receipt of this indication, but I have no
// idea what we're supposed to do with it
UnlockCall(pCall); UnlockConference(pConference); status = H245_ERROR_OK; break;
case vdIndctRdyTActvt_chosen: case MIn_tp_vdTmprlSptlTrdOff_chosen: if (FindChannelInConference(pMiscellaneousIndication->logicalChannelNumber, FALSE, // remote channel number
RX_CHANNEL | PROXY_CHANNEL, hCall, &hChannel, pConference) != CC_OK) { UnlockCall(pCall); UnlockConference(pConference); return H245_ERROR_OK; }
if (LockChannel(hChannel, &pChannel) != CC_OK) { UnlockCall(pCall); UnlockConference(pConference); return H245_ERROR_OK; }
if (pChannel->bChannelType == PROXY_CHANNEL) { ASSERT(pConference->ConferenceMode == MULTIPOINT_MODE); ASSERT(pConference->tsMultipointController == TS_TRUE); ASSERT(pChannel->bMultipointChannel == TRUE);
// Construct an H.245 PDU to hold a miscellaneous indication
// of "video indicate ready to activate" or
// "video temporal spatial tradeoff"
pPdu = (PDU_T *)MemAlloc(sizeof(PDU_T)); if(NULL != pPdu) { pPdu->choice = indication_chosen; pPdu->u.indication.choice = miscellaneousIndication_chosen; pPdu->u.indication.u.miscellaneousIndication.logicalChannelNumber = pChannel->wLocalChannelNumber; pPdu->u.indication.u.miscellaneousIndication.type.choice = pMiscellaneousIndication->type.choice;
EnumerateCallsInConference(&wNumCalls, &CallList, pConference, ESTABLISHED_CALL); for (i = 0; i < wNumCalls; i++) { if (CallList[i] != hCall) { if (LockCall(CallList[i], &pOldCall) == CC_OK) { H245SendPDU(pOldCall->H245Instance, pPdu); UnlockCall(pOldCall); } } } MemFree(CallList); MemFree(pPdu); pPdu = NULL; } }
if (pChannel->tsAccepted == TS_TRUE) { H245MiscellaneousIndicationCallbackParams.hCall = hCall; if (pCall->pPeerParticipantInfo == NULL) { H245MiscellaneousIndicationCallbackParams.InitiatorTerminalLabel.bMCUNumber = 255; H245MiscellaneousIndicationCallbackParams.InitiatorTerminalLabel.bTerminalNumber = 255; } else H245MiscellaneousIndicationCallbackParams.InitiatorTerminalLabel = pCall->pPeerParticipantInfo->ParticipantInfo.TerminalLabel; H245MiscellaneousIndicationCallbackParams.hChannel = hChannel; H245MiscellaneousIndicationCallbackParams.pMiscellaneousIndication = pMiscellaneousIndication;
status = InvokeUserConferenceCallback(pConference, CC_H245_MISCELLANEOUS_INDICATION_INDICATION, CC_OK, &H245MiscellaneousIndicationCallbackParams); if (status != CC_OK) status = H245_ERROR_NOSUP; } else status = H245_ERROR_OK;
if (ValidateChannel(hChannel) == CC_OK) UnlockChannel(pChannel); if (ValidateCall(hCall) == CC_OK) UnlockCall(pCall); if (ValidateConference(hConference) == CC_OK) UnlockConference(pConference); break;
case videoNotDecodedMBs_chosen: if (FindChannelInConference(pMiscellaneousIndication->logicalChannelNumber, TRUE, // local channel number
TX_CHANNEL | PROXY_CHANNEL, CC_INVALID_HANDLE, &hChannel, pConference) != CC_OK) { UnlockCall(pCall); UnlockConference(pConference); return H245_ERROR_OK; }
if (LockChannel(hChannel, &pChannel) != CC_OK) { UnlockCall(pCall); UnlockConference(pConference); return H245_ERROR_OK; }
if (pChannel->bChannelType == TX_CHANNEL) { H245MiscellaneousIndicationCallbackParams.hCall = hCall; if (pCall->pPeerParticipantInfo == NULL) { H245MiscellaneousIndicationCallbackParams.InitiatorTerminalLabel.bMCUNumber = 255; H245MiscellaneousIndicationCallbackParams.InitiatorTerminalLabel.bTerminalNumber = 255; } else H245MiscellaneousIndicationCallbackParams.InitiatorTerminalLabel = pCall->pPeerParticipantInfo->ParticipantInfo.TerminalLabel; H245MiscellaneousIndicationCallbackParams.hChannel = hChannel; H245MiscellaneousIndicationCallbackParams.pMiscellaneousIndication = pMiscellaneousIndication;
status = InvokeUserConferenceCallback(pConference, CC_H245_MISCELLANEOUS_INDICATION_INDICATION, CC_OK, &H245MiscellaneousIndicationCallbackParams); if (status != CC_OK) status = H245_ERROR_NOSUP;
if (ValidateChannel(hChannel) == CC_OK) UnlockChannel(pChannel); if (ValidateCall(hCall) == CC_OK) UnlockCall(pCall); if (ValidateConference(hConference) == CC_OK) UnlockConference(pConference); return H245_ERROR_OK; } else { // Proxy channel; forward the request to the transmitter
ASSERT(pConference->ConferenceMode == MULTIPOINT_MODE); ASSERT(pConference->tsMultipointController == TS_TRUE); ASSERT(pChannel->bMultipointChannel == TRUE);
// Construct an H.245 PDU to hold a miscellaneous indication
// of "video not decoded MBs"
pPdu = (PDU_T *)MemAlloc(sizeof(PDU_T)); if(NULL != pPdu) { pPdu->choice = indication_chosen; pPdu->u.indication.choice = miscellaneousIndication_chosen; pPdu->u.indication.u.miscellaneousIndication.logicalChannelNumber = pChannel->wRemoteChannelNumber; pPdu->u.indication.u.miscellaneousIndication.type.choice = pMiscellaneousIndication->type.choice;
if (LockCall(pChannel->hCall, &pOldCall) == CC_OK) { H245SendPDU(pOldCall->H245Instance, pPdu); UnlockCall(pOldCall); }
MemFree(pPdu); pPdu = NULL; } UnlockChannel(pChannel); UnlockCall(pCall); UnlockConference(pConference); return H245_ERROR_OK; } // We should never reach here
ASSERT(0);
default: // Miscellaneous indication not containing channel information
// Pass it up to the client
H245MiscellaneousIndicationCallbackParams.hCall = hCall; if (pCall->pPeerParticipantInfo == NULL) { H245MiscellaneousIndicationCallbackParams.InitiatorTerminalLabel.bMCUNumber = 255; H245MiscellaneousIndicationCallbackParams.InitiatorTerminalLabel.bTerminalNumber = 255; } else H245MiscellaneousIndicationCallbackParams.InitiatorTerminalLabel = pCall->pPeerParticipantInfo->ParticipantInfo.TerminalLabel; H245MiscellaneousIndicationCallbackParams.hChannel = CC_INVALID_HANDLE;; H245MiscellaneousIndicationCallbackParams.pMiscellaneousIndication = pMiscellaneousIndication;
status = InvokeUserConferenceCallback(pConference, CC_H245_MISCELLANEOUS_INDICATION_INDICATION, CC_OK, &H245MiscellaneousIndicationCallbackParams);
if (status != CC_OK) status = H245_ERROR_NOSUP; if (ValidateCall(hCall) == CC_OK) UnlockCall(pCall); if (ValidateConference(hConference) == CC_OK) UnlockConference(pConference); break; }
return status;
// We should never reach this point
ASSERT(0); }
HRESULT _IndMiscellaneousCommand( H245_CONF_IND_T *pH245ConfIndData, MiscellaneousCommand *pMiscellaneousCommand) { CC_HCALL hCall; PCALL pCall; PCALL pOldCall; CC_HCONFERENCE hConference; PCONFERENCE pConference; HRESULT status = CC_OK; WORD wChoice; CC_HCHANNEL hChannel; PCHANNEL pChannel; CC_H245_MISCELLANEOUS_COMMAND_CALLBACK_PARAMS H245MiscellaneousCommandCallbackParams;
if (pMiscellaneousCommand == NULL) // Should never hit this case
return H245_ERROR_NOSUP;
hCall = pH245ConfIndData->u.Indication.dwPreserved; if (LockCallAndConference(hCall, &pCall, &pConference) != CC_OK) return H245_ERROR_OK;
hConference = pConference->hConference;
switch (pMiscellaneousCommand->type.choice) { case multipointModeCommand_chosen: //
// from this point on, expect CommunicationModeCommand
// also, theoretically, channels shouldn't be opened until at
// least one CommunicationModeCommand is received.
// It's only by examining CommunicationModeCommand contents
// that we can determine if a conference has decentralized
// media.
// I'm commenting this out on 6/4/98 because it's bogus: all
// endpoints have centralized media distribution. Set
// pConference->ConferenceMode = MULTIPOINT_MODE; only after
// CommunicationModeCommand is received and the multiplex table has
// been examined and decentralized media is found
#if(0)
if (pConference->bMultipointCapable == FALSE) { // We can't support multipoint operation, so treat this as if
// we received a remote hangup indication
UnlockConference(pConference); UnlockCall(pCall); ProcessRemoteHangup(hCall, CC_INVALID_HANDLE, CC_REJECT_NORMAL_CALL_CLEARING); return H245_ERROR_OK; } else { pConference->ConferenceMode = MULTIPOINT_MODE;
// Send TerminalListRequest
H245ConferenceRequest(pCall->H245Instance, H245_REQ_TERMINAL_LIST, pConference->LocalParticipantInfo.ParticipantInfo.TerminalLabel.bMCUNumber, pConference->LocalParticipantInfo.ParticipantInfo.TerminalLabel.bTerminalNumber); } #else
// Send TerminalListRequest
H245ConferenceRequest(pCall->H245Instance, H245_REQ_TERMINAL_LIST, pConference->LocalParticipantInfo.ParticipantInfo.TerminalLabel.bMCUNumber, pConference->LocalParticipantInfo.ParticipantInfo.TerminalLabel.bTerminalNumber); #endif
status = H245_ERROR_OK; break;
case cnclMltpntMdCmmnd_chosen: // We're required to support receipt of this command, but I have no
// idea what we're supposed to do with it
status = H245_ERROR_OK; break;
case videoFreezePicture_chosen: case videoFastUpdatePicture_chosen: case videoFastUpdateGOB_chosen: case MCd_tp_vdTmprlSptlTrdOff_chosen: case videoSendSyncEveryGOB_chosen: case videoFastUpdateMB_chosen: case vdSndSyncEvryGOBCncl_chosen: if (FindChannelInConference(pMiscellaneousCommand->logicalChannelNumber, TRUE, // local channel number
TX_CHANNEL | PROXY_CHANNEL, CC_INVALID_HANDLE, &hChannel, pConference) != CC_OK) { UnlockCall(pCall); UnlockConference(pConference); return H245_ERROR_OK; }
if (LockChannel(hChannel, &pChannel) != CC_OK) { UnlockCall(pCall); UnlockConference(pConference); return H245_ERROR_OK; }
if (pChannel->bChannelType == TX_CHANNEL) { H245MiscellaneousCommandCallbackParams.hCall = hCall; if (pCall->pPeerParticipantInfo == NULL) { H245MiscellaneousCommandCallbackParams.InitiatorTerminalLabel.bMCUNumber = 255; H245MiscellaneousCommandCallbackParams.InitiatorTerminalLabel.bTerminalNumber = 255; } else H245MiscellaneousCommandCallbackParams.InitiatorTerminalLabel = pCall->pPeerParticipantInfo->ParticipantInfo.TerminalLabel; H245MiscellaneousCommandCallbackParams.hChannel = hChannel; wChoice = pMiscellaneousCommand->type.choice; if ((wChoice == videoFreezePicture_chosen) || (wChoice == videoFastUpdatePicture_chosen) || (wChoice == videoFastUpdateGOB_chosen) || (wChoice == videoFastUpdateMB_chosen)) H245MiscellaneousCommandCallbackParams.bH323ActionRequired = TRUE; else H245MiscellaneousCommandCallbackParams.bH323ActionRequired = FALSE; H245MiscellaneousCommandCallbackParams.pMiscellaneousCommand = pMiscellaneousCommand;
status = InvokeUserConferenceCallback(pConference, CC_H245_MISCELLANEOUS_COMMAND_INDICATION, CC_OK, &H245MiscellaneousCommandCallbackParams); if (status != CC_OK) status = H245_ERROR_NOSUP;
if (ValidateChannel(hChannel) == CC_OK) UnlockChannel(pChannel); if (ValidateCall(hCall) == CC_OK) UnlockCall(pCall); if (ValidateConference(hConference) == CC_OK) UnlockConference(pConference); return H245_ERROR_OK; } else { // Proxy channel; forward the request to the transmitter
ASSERT(pConference->ConferenceMode == MULTIPOINT_MODE); ASSERT(pConference->tsMultipointController == TS_TRUE); ASSERT(pChannel->bMultipointChannel == TRUE);
if (LockCall(pChannel->hCall, &pOldCall) == CC_OK) { PDU_T *pPdu = (PDU_T *) MemAlloc(sizeof(PDU_T));
if(NULL != pPdu) { pPdu->choice = MSCMg_cmmnd_chosen; pPdu->u.MSCMg_cmmnd.choice = miscellaneousCommand_chosen; pPdu->u.MSCMg_cmmnd.u.miscellaneousCommand.logicalChannelNumber = pChannel->wRemoteChannelNumber; pPdu->u.MSCMg_cmmnd.u.miscellaneousCommand = *pMiscellaneousCommand; H245SendPDU(pOldCall->H245Instance, pPdu); MemFree(pPdu); pPdu = NULL; } UnlockCall(pOldCall); } UnlockChannel(pChannel); UnlockCall(pCall); UnlockConference(pConference); return H245_ERROR_OK; } // We should never reach here
ASSERT(0);
default: // Unrecognized miscellaneous command
// Pass it up to the client
H245MiscellaneousCommandCallbackParams.hCall = hCall; if (pCall->pPeerParticipantInfo == NULL) { H245MiscellaneousCommandCallbackParams.InitiatorTerminalLabel.bMCUNumber = 255; H245MiscellaneousCommandCallbackParams.InitiatorTerminalLabel.bTerminalNumber = 255; } else H245MiscellaneousCommandCallbackParams.InitiatorTerminalLabel = pCall->pPeerParticipantInfo->ParticipantInfo.TerminalLabel; H245MiscellaneousCommandCallbackParams.hChannel = CC_INVALID_HANDLE; H245MiscellaneousCommandCallbackParams.bH323ActionRequired = FALSE; H245MiscellaneousCommandCallbackParams.pMiscellaneousCommand = pMiscellaneousCommand; status = InvokeUserConferenceCallback(pConference, CC_H245_MISCELLANEOUS_COMMAND_INDICATION, CC_OK, &H245MiscellaneousCommandCallbackParams); if (status != CC_OK) status = H245_ERROR_NOSUP; if (ValidateCall(hCall) == CC_OK) UnlockCall(pCall); if (ValidateConference(hConference) == CC_OK) UnlockConference(pConference); return status; }
if (ValidateCall(hCall) == CC_OK) UnlockCall(pCall); if (ValidateConference(hConference) == CC_OK) UnlockConference(pConference);
return status;
// We should never reach this point
ASSERT(0); }
HRESULT _IndMCLocation( H245_CONF_IND_T *pH245ConfIndData) { CC_HCALL hCall; PCALL pCall; PCONFERENCE pConference; CC_CONNECT_CALLBACK_PARAMS ConnectCallbackParams; PCALL pEnqueuedCall; CC_HCALL hEnqueuedCall; HRESULT status; CC_HCONFERENCE hConference;
if (pH245ConfIndData->u.Indication.u.IndMcLocation.type != H245_IP_UNICAST) return H245_ERROR_OK;
hCall = pH245ConfIndData->u.Indication.dwPreserved;
if (LockCallAndConference(hCall, &pCall, &pConference) != CC_OK) return H245_ERROR_OK;
UnlockCall(pCall);
hConference = pConference->hConference;
if (pConference->tsMultipointController != TS_FALSE) { // We don't expect to receive an MCLocationIndication until master/slave
// has completed, at which time tsMultipointController will change from
// TS_UNKNOWN to either TS_TRUE or TS_FALSE.
UnlockConference(pConference); return H245_ERROR_NOSUP; }
if (pConference->pMultipointControllerAddr == NULL) { pConference->pMultipointControllerAddr = (PCC_ADDR)MemAlloc(sizeof(CC_ADDR)); if (pConference->pMultipointControllerAddr == NULL) { UnlockConference(pConference); return H245_ERROR_OK; } } pConference->pMultipointControllerAddr->nAddrType = CC_IP_BINARY; pConference->pMultipointControllerAddr->bMulticast = FALSE; pConference->pMultipointControllerAddr->Addr.IP_Binary.wPort = pH245ConfIndData->u.Indication.u.IndMcLocation.u.ip.tsapIdentifier; H245IPNetworkToHost(&pConference->pMultipointControllerAddr->Addr.IP_Binary.dwAddr, pH245ConfIndData->u.Indication.u.IndMcLocation.u.ip.network);
// place all calls enqueued on this conference object
for ( ; ; ) { // Start up all enqueued calls, if any exist
status = RemoveEnqueuedCallFromConference(pConference, &hEnqueuedCall); if ((status != CC_OK) || (hEnqueuedCall == CC_INVALID_HANDLE)) break;
status = LockCall(hEnqueuedCall, &pEnqueuedCall); if (status == CC_OK) { // Place Call to MC
pEnqueuedCall->CallState = PLACED; pEnqueuedCall->CallType = THIRD_PARTY_INVITOR; if (pEnqueuedCall->pQ931DestinationAddr == NULL) pEnqueuedCall->pQ931DestinationAddr = pEnqueuedCall->pQ931PeerConnectAddr; if (pEnqueuedCall->pQ931PeerConnectAddr == NULL) pEnqueuedCall->pQ931PeerConnectAddr = (PCC_ADDR)MemAlloc(sizeof(CC_ADDR)); if (pEnqueuedCall->pQ931PeerConnectAddr == NULL) { MarkCallForDeletion(pEnqueuedCall); ConnectCallbackParams.pNonStandardData = pEnqueuedCall->pPeerNonStandardData; ConnectCallbackParams.pszPeerDisplay = pEnqueuedCall->pszPeerDisplay; ConnectCallbackParams.bRejectReason = CC_REJECT_UNDEFINED_REASON; ConnectCallbackParams.pTermCapList = pEnqueuedCall->pPeerH245TermCapList; ConnectCallbackParams.pH2250MuxCapability = pEnqueuedCall->pPeerH245H2250MuxCapability; ConnectCallbackParams.pTermCapDescriptors = pEnqueuedCall->pPeerH245TermCapDescriptors; ConnectCallbackParams.pLocalAddr = pEnqueuedCall->pQ931LocalConnectAddr; if (pEnqueuedCall->pQ931DestinationAddr == NULL) ConnectCallbackParams.pPeerAddr = pEnqueuedCall->pQ931PeerConnectAddr; else ConnectCallbackParams.pPeerAddr = pEnqueuedCall->pQ931DestinationAddr; ConnectCallbackParams.pVendorInfo = pEnqueuedCall->pPeerVendorInfo; ConnectCallbackParams.bMultipointConference = TRUE; ConnectCallbackParams.pConferenceID = &pConference->ConferenceID; ConnectCallbackParams.pMCAddress = pConference->pMultipointControllerAddr; ConnectCallbackParams.pAlternateAddress = NULL; ConnectCallbackParams.dwUserToken = pEnqueuedCall->dwUserToken;
InvokeUserConferenceCallback(pConference, CC_CONNECT_INDICATION, CC_NO_MEMORY, &ConnectCallbackParams);
if (ValidateCallMarkedForDeletion(hEnqueuedCall) == CC_OK) FreeCall(pEnqueuedCall); if (ValidateConference(hConference) != CC_OK) return H245_ERROR_OK; } pEnqueuedCall->pQ931PeerConnectAddr = pConference->pMultipointControllerAddr;
status = PlaceCall(pEnqueuedCall, pConference); UnlockCall(pEnqueuedCall); } }
UnlockConference(pConference); return H245_ERROR_OK; }
HRESULT _IndConferenceRequest( H245_CONF_IND_T *pH245ConfIndData) { CC_HCALL hCall; PCALL pCall; PCALL pPeerCall; CC_HCONFERENCE hConference; PCONFERENCE pConference; HRESULT status; H245_TERMINAL_LABEL_T *H245TerminalLabelList; H245_TERMINAL_LABEL_T H245TerminalLabel; WORD wNumTerminalLabels; CC_H245_CONFERENCE_REQUEST_CALLBACK_PARAMS H245ConferenceRequestCallbackParams;
hCall = pH245ConfIndData->u.Indication.dwPreserved; if (LockCallAndConference(hCall, &pCall, &pConference) != CC_OK) return H245_ERROR_OK;
hConference = pConference->hConference;
switch (pH245ConfIndData->u.Indication.u.IndConferReq.RequestType) { case H245_REQ_ENTER_H243_TERMINAL_ID: switch (pConference->LocalParticipantInfo.TerminalIDState) { case TERMINAL_ID_INVALID: UnlockCall(pCall); EnqueueRequest(&pConference->LocalParticipantInfo.pEnqueuedRequestsForTerminalID, hCall); pConference->LocalParticipantInfo.TerminalIDState = TERMINAL_ID_REQUESTED; InvokeUserConferenceCallback(pConference, CC_TERMINAL_ID_REQUEST_INDICATION, CC_OK, NULL); if (ValidateConference(hConference) == CC_OK) UnlockConference(pConference); return H245_ERROR_OK;
case TERMINAL_ID_REQUESTED: UnlockCall(pCall); EnqueueRequest(&pConference->LocalParticipantInfo.pEnqueuedRequestsForTerminalID, hCall); UnlockConference(pConference); return H245_ERROR_OK;
case TERMINAL_ID_VALID: H245ConferenceResponse(pCall->H245Instance, H245_RSP_TERMINAL_ID, pConference->LocalParticipantInfo.ParticipantInfo.TerminalLabel.bMCUNumber, pConference->LocalParticipantInfo.ParticipantInfo.TerminalLabel.bTerminalNumber, pConference->LocalParticipantInfo.ParticipantInfo.TerminalID.pOctetString, (BYTE)pConference->LocalParticipantInfo.ParticipantInfo.TerminalID.wOctetStringLength, NULL, // terminal list
0); // terminal list count
UnlockCall(pCall); UnlockConference(pConference); return H245_ERROR_OK;
default: ASSERT(0); }
case H245_REQ_TERMINAL_LIST: if ((pConference->ConferenceMode == MULTIPOINT_MODE) && (pConference->tsMultipointController == TS_TRUE)) { status = EnumerateTerminalLabelsInConference(&wNumTerminalLabels, &H245TerminalLabelList, pConference); if (status == CC_OK) H245ConferenceResponse(pCall->H245Instance, H245_RSP_TERMINAL_LIST, pConference->LocalParticipantInfo.ParticipantInfo.TerminalLabel.bMCUNumber, pConference->LocalParticipantInfo.ParticipantInfo.TerminalLabel.bTerminalNumber, pConference->LocalParticipantInfo.ParticipantInfo.TerminalID.pOctetString, (BYTE)pConference->LocalParticipantInfo.ParticipantInfo.TerminalID.wOctetStringLength, H245TerminalLabelList, // terminal list
wNumTerminalLabels); // terminal list count
if (H245TerminalLabelList != NULL) MemFree(H245TerminalLabelList); status = H245_ERROR_OK; } else status = H245_ERROR_NOSUP; break;
case H245_REQ_TERMINAL_ID: if (pConference->tsMultipointController != TS_TRUE) { status = H245_ERROR_NOSUP; break; }
if (pConference->LocalParticipantInfo.ParticipantInfo.TerminalLabel.bMCUNumber != pH245ConfIndData->u.Indication.u.IndConferReq.byMcuNumber) { // This terminal ID wasn't allocated by this MC, so return without a response
status = H245_ERROR_OK; break; }
// First check to see whether the requested terminal ID is ours
if (pConference->LocalParticipantInfo.ParticipantInfo.TerminalLabel.bTerminalNumber == pH245ConfIndData->u.Indication.u.IndConferReq.byTerminalNumber) { if (pConference->LocalEndpointAttached != ATTACHED) { status = H245_ERROR_OK; break; }
switch (pConference->LocalParticipantInfo.TerminalIDState) { case TERMINAL_ID_INVALID: UnlockCall(pCall); EnqueueRequest(&pConference->LocalParticipantInfo.pEnqueuedRequestsForTerminalID, hCall); pConference->LocalParticipantInfo.TerminalIDState = TERMINAL_ID_REQUESTED; InvokeUserConferenceCallback(pConference, CC_TERMINAL_ID_REQUEST_INDICATION, CC_OK, NULL); if (ValidateConference(hConference) == CC_OK) UnlockConference(pConference); return H245_ERROR_OK;
case TERMINAL_ID_REQUESTED: UnlockCall(pCall); EnqueueRequest(&pConference->LocalParticipantInfo.pEnqueuedRequestsForTerminalID, hCall); UnlockConference(pConference); return H245_ERROR_OK;
case TERMINAL_ID_VALID: H245ConferenceResponse(pCall->H245Instance, H245_RSP_MC_TERMINAL_ID, pConference->LocalParticipantInfo.ParticipantInfo.TerminalLabel.bMCUNumber, pConference->LocalParticipantInfo.ParticipantInfo.TerminalLabel.bTerminalNumber, pConference->LocalParticipantInfo.ParticipantInfo.TerminalID.pOctetString, (BYTE)pConference->LocalParticipantInfo.ParticipantInfo.TerminalID.wOctetStringLength, NULL, // terminal list
0); // terminal list count
UnlockCall(pCall); UnlockConference(pConference); return H245_ERROR_OK;
default: ASSERT(0); } }
H245TerminalLabel.mcuNumber = pH245ConfIndData->u.Indication.u.IndConferReq.byMcuNumber; H245TerminalLabel.terminalNumber = pH245ConfIndData->u.Indication.u.IndConferReq.byTerminalNumber;
FindPeerParticipantInfo(H245TerminalLabel, pConference, ESTABLISHED_CALL, &pPeerCall); if (pPeerCall == NULL) { // We don't know about the existance of this terminal ID, so return without a response
status = H245_ERROR_OK; break; }
if (pPeerCall->pPeerParticipantInfo == NULL) { UnlockCall(pPeerCall); status = H245_ERROR_OK; break; }
switch (pPeerCall->pPeerParticipantInfo->TerminalIDState) { case TERMINAL_ID_INVALID: EnqueueRequest(&pPeerCall->pPeerParticipantInfo->pEnqueuedRequestsForTerminalID, hCall); pPeerCall->pPeerParticipantInfo->TerminalIDState = TERMINAL_ID_REQUESTED; H245ConferenceRequest(pPeerCall->H245Instance, H245_REQ_ENTER_H243_TERMINAL_ID, pPeerCall->pPeerParticipantInfo->ParticipantInfo.TerminalLabel.bMCUNumber, pPeerCall->pPeerParticipantInfo->ParticipantInfo.TerminalLabel.bTerminalNumber); break;
case TERMINAL_ID_REQUESTED: EnqueueRequest(&pPeerCall->pPeerParticipantInfo->pEnqueuedRequestsForTerminalID, hCall); break;
case TERMINAL_ID_VALID: H245ConferenceResponse(pCall->H245Instance, H245_RSP_MC_TERMINAL_ID, pPeerCall->pPeerParticipantInfo->ParticipantInfo.TerminalLabel.bMCUNumber, pPeerCall->pPeerParticipantInfo->ParticipantInfo.TerminalLabel.bTerminalNumber, pPeerCall->pPeerParticipantInfo->ParticipantInfo.TerminalID.pOctetString, (BYTE)pPeerCall->pPeerParticipantInfo->ParticipantInfo.TerminalID.wOctetStringLength, NULL, // terminal list
0); // terminal list count
break;
default: ASSERT(0); break; } UnlockCall(pPeerCall); status = H245_ERROR_OK; break;
default: H245ConferenceRequestCallbackParams.hCall = hCall; if (pCall->pPeerParticipantInfo == NULL) { H245ConferenceRequestCallbackParams.InitiatorTerminalLabel.bMCUNumber = 255; H245ConferenceRequestCallbackParams.InitiatorTerminalLabel.bTerminalNumber = 255; } else H245ConferenceRequestCallbackParams.InitiatorTerminalLabel = pCall->pPeerParticipantInfo->ParticipantInfo.TerminalLabel; H245ConferenceRequestCallbackParams.RequestType = pH245ConfIndData->u.Indication.u.IndConferReq.RequestType; H245ConferenceRequestCallbackParams.TerminalLabel.bMCUNumber = pH245ConfIndData->u.Indication.u.IndConferReq.byMcuNumber; H245ConferenceRequestCallbackParams.TerminalLabel.bTerminalNumber = pH245ConfIndData->u.Indication.u.IndConferReq.byTerminalNumber; status = InvokeUserConferenceCallback(pConference, CC_H245_CONFERENCE_REQUEST_INDICATION, CC_OK, &H245ConferenceRequestCallbackParams); if (status != CC_OK) status = H245_ERROR_NOSUP; break; }
if (ValidateCall(hCall) == CC_OK) UnlockCall(pCall); if (ValidateConference(hConference) == CC_OK) UnlockConference(pConference); return status; }
HRESULT _IndConferenceResponse( H245_CONF_IND_T *pH245ConfIndData) { CC_HCALL hCall; PCALL pCall; PCALL pPeerCall; CC_HCALL hEnqueuedCall; PCALL pEnqueuedCall; CC_HCALL hVirtualCall; CC_HCALL hPeerCall; PCALL pVirtualCall; PCONFERENCE pConference; CC_HCONFERENCE hConference; HRESULT status; WORD i; PPARTICIPANTINFO pPeerParticipantInfo; H245_TERMINAL_LABEL_T TerminalLabel; CC_PEER_ADD_CALLBACK_PARAMS PeerAddCallbackParams; CC_PEER_UPDATE_CALLBACK_PARAMS PeerUpdateCallbackParams; CC_H245_CONFERENCE_RESPONSE_CALLBACK_PARAMS H245ConferenceResponseCallbackParams; CC_OCTETSTRING OctetString;
hCall = pH245ConfIndData->u.Indication.dwPreserved; if (LockCallAndConference(hCall, &pCall, &pConference) != CC_OK) return H245_ERROR_OK;
hConference = pConference->hConference;
switch (pH245ConfIndData->u.Indication.u.IndConferRsp.ResponseType) { case H245_RSP_TERMINAL_LIST: if (pConference->tsMultipointController == TS_FALSE) { for (i = 0; i < pH245ConfIndData->u.Indication.u.IndConferRsp.wTerminalListCount; i++) { if ((pH245ConfIndData->u.Indication.u.IndConferRsp.pTerminalList[i].mcuNumber == pConference->LocalParticipantInfo.ParticipantInfo.TerminalLabel.bMCUNumber) && (pH245ConfIndData->u.Indication.u.IndConferRsp.pTerminalList[i].terminalNumber == pConference->LocalParticipantInfo.ParticipantInfo.TerminalLabel.bTerminalNumber)) // This terminal number refers to us
continue; FindPeerParticipantInfo(pH245ConfIndData->u.Indication.u.IndConferRsp.pTerminalList[i], pConference, VIRTUAL_CALL, &pPeerCall); if (pPeerCall != NULL) { // We already know this peer's terminal label, and we
// eithet know its terminal ID or we have a pending request
// to obtain it
UnlockCall(pPeerCall); continue; }
// We don't know about this peer.
// Create a virtual call object for it, and issue a request
// for its terminal ID
status = AllocAndLockCall(&hVirtualCall, pConference->hConference, CC_INVALID_HANDLE, // hQ931Call
CC_INVALID_HANDLE, // hQ931CallInvitor,
NULL, // pLocalAliasNames,
NULL, // pPeerAliasNames,
NULL, // pPeerExtraAliasNames
NULL, // pPeerExtension
NULL, // pLocalNonStandardData,
NULL, // pPeerNonStandardData,
NULL, // pszLocalDisplay,
NULL, // pszPeerDisplay,
NULL, // pPeerVendorInfo,
NULL, // pQ931LocalConnectAddr,
NULL, // pQ931PeerConnectAddr,
NULL, // pQ931DestinationAddr,
NULL, // pSourceCallSignalAddress
VIRTUAL, // CallType,
FALSE, // bCallerIsMC,
0, // dwUserToken,
CALL_COMPLETE, // InitialCallState,
NULL, // no CallIdentifier
&pConference->ConferenceID, &pVirtualCall); if (status == CC_OK) { status = AllocatePeerParticipantInfo(NULL, &pPeerParticipantInfo); if (status == CC_OK) { pVirtualCall->pPeerParticipantInfo = pPeerParticipantInfo; pPeerParticipantInfo->ParticipantInfo.TerminalLabel.bMCUNumber = (BYTE)pH245ConfIndData->u.Indication.u.IndConferRsp.pTerminalList[i].mcuNumber; pPeerParticipantInfo->ParticipantInfo.TerminalLabel.bTerminalNumber = (BYTE)pH245ConfIndData->u.Indication.u.IndConferRsp.pTerminalList[i].terminalNumber; AddVirtualCallToConference(pVirtualCall, pConference); // Send RequestTerminalID
H245ConferenceRequest(pCall->H245Instance, H245_REQ_TERMINAL_ID, (BYTE)pH245ConfIndData->u.Indication.u.IndConferRsp.pTerminalList[i].mcuNumber, (BYTE)pH245ConfIndData->u.Indication.u.IndConferRsp.pTerminalList[i].terminalNumber); pPeerParticipantInfo->TerminalIDState = TERMINAL_ID_REQUESTED;
// Generate PEER_ADD callback
PeerAddCallbackParams.hCall = hVirtualCall; PeerAddCallbackParams.TerminalLabel = pVirtualCall->pPeerParticipantInfo->ParticipantInfo.TerminalLabel; PeerAddCallbackParams.pPeerTerminalID = NULL; InvokeUserConferenceCallback(pConference, CC_PEER_ADD_INDICATION, CC_OK, &PeerAddCallbackParams); if (ValidateCall(hVirtualCall) == CC_OK) UnlockCall(pVirtualCall); } else FreeCall(pVirtualCall); } } } status = H245_ERROR_OK; break;
case H245_RSP_MC_TERMINAL_ID: if (pConference->tsMultipointController == TS_FALSE) { TerminalLabel.mcuNumber = pH245ConfIndData->u.Indication.u.IndConferRsp.byMcuNumber; TerminalLabel.terminalNumber = pH245ConfIndData->u.Indication.u.IndConferRsp.byTerminalNumber; FindPeerParticipantInfo(TerminalLabel, pConference, VIRTUAL_CALL, &pPeerCall); if (pPeerCall != NULL) { hPeerCall = pPeerCall->hCall; if (pPeerCall->pPeerParticipantInfo->TerminalIDState != TERMINAL_ID_VALID) { pPeerCall->pPeerParticipantInfo->ParticipantInfo.TerminalID.pOctetString = (BYTE *)MemAlloc(pH245ConfIndData->u.Indication.u.IndConferRsp.byOctetStringLength); if (pPeerCall->pPeerParticipantInfo->ParticipantInfo.TerminalID.pOctetString == NULL) { UnlockCall(pPeerCall); status = H245_ERROR_OK; break; } memcpy(pPeerCall->pPeerParticipantInfo->ParticipantInfo.TerminalID.pOctetString, pH245ConfIndData->u.Indication.u.IndConferRsp.pOctetString, pH245ConfIndData->u.Indication.u.IndConferRsp.byOctetStringLength); pPeerCall->pPeerParticipantInfo->ParticipantInfo.TerminalID.wOctetStringLength = pH245ConfIndData->u.Indication.u.IndConferRsp.byOctetStringLength; pPeerCall->pPeerParticipantInfo->TerminalIDState = TERMINAL_ID_VALID; PeerUpdateCallbackParams.hCall = hPeerCall; PeerUpdateCallbackParams.TerminalLabel = pPeerCall->pPeerParticipantInfo->ParticipantInfo.TerminalLabel; PeerUpdateCallbackParams.pPeerTerminalID = &pPeerCall->pPeerParticipantInfo->ParticipantInfo.TerminalID; InvokeUserConferenceCallback(pConference, CC_PEER_UPDATE_INDICATION, CC_OK, &PeerUpdateCallbackParams); } if (ValidateCall(hPeerCall) == CC_OK) UnlockCall(pPeerCall); } } status = H245_ERROR_OK; break;
case H245_RSP_TERMINAL_ID: if ((pConference->ConferenceMode == MULTIPOINT_MODE) && (pConference->tsMultipointController == TS_TRUE)) { TerminalLabel.mcuNumber = pH245ConfIndData->u.Indication.u.IndConferRsp.byMcuNumber; TerminalLabel.terminalNumber = pH245ConfIndData->u.Indication.u.IndConferRsp.byTerminalNumber; FindPeerParticipantInfo(TerminalLabel, pConference, ESTABLISHED_CALL, &pPeerCall); if (pPeerCall != NULL) { hPeerCall = pPeerCall->hCall; if (pPeerCall->pPeerParticipantInfo->TerminalIDState != TERMINAL_ID_VALID) { pPeerCall->pPeerParticipantInfo->ParticipantInfo.TerminalID.pOctetString = (BYTE *)MemAlloc(pH245ConfIndData->u.Indication.u.IndConferRsp.byOctetStringLength); if (pPeerCall->pPeerParticipantInfo->ParticipantInfo.TerminalID.pOctetString == NULL) { UnlockCall(pPeerCall); status = H245_ERROR_OK; break; } memcpy(pPeerCall->pPeerParticipantInfo->ParticipantInfo.TerminalID.pOctetString, pH245ConfIndData->u.Indication.u.IndConferRsp.pOctetString, pH245ConfIndData->u.Indication.u.IndConferRsp.byOctetStringLength); pPeerCall->pPeerParticipantInfo->ParticipantInfo.TerminalID.wOctetStringLength = pH245ConfIndData->u.Indication.u.IndConferRsp.byOctetStringLength; pPeerCall->pPeerParticipantInfo->TerminalIDState = TERMINAL_ID_VALID; // Dequeue and respond to each enqueued request for this terminal ID
while (DequeueRequest(&pPeerCall->pPeerParticipantInfo->pEnqueuedRequestsForTerminalID, &hEnqueuedCall) == CC_OK) { if (LockCall(hEnqueuedCall, &pEnqueuedCall) == CC_OK) { H245ConferenceResponse(pEnqueuedCall->H245Instance, H245_RSP_MC_TERMINAL_ID, pPeerCall->pPeerParticipantInfo->ParticipantInfo.TerminalLabel.bMCUNumber, pPeerCall->pPeerParticipantInfo->ParticipantInfo.TerminalLabel.bTerminalNumber, pPeerCall->pPeerParticipantInfo->ParticipantInfo.TerminalID.pOctetString, (BYTE)pPeerCall->pPeerParticipantInfo->ParticipantInfo.TerminalID.wOctetStringLength, NULL, // terminal list
0); // terminal list count
UnlockCall(pEnqueuedCall); } }
// Generate a CC_PEER_UPDATE_INDICATION callback
PeerUpdateCallbackParams.hCall = hPeerCall; PeerUpdateCallbackParams.TerminalLabel = pPeerCall->pPeerParticipantInfo->ParticipantInfo.TerminalLabel; PeerUpdateCallbackParams.pPeerTerminalID = &pPeerCall->pPeerParticipantInfo->ParticipantInfo.TerminalID; InvokeUserConferenceCallback(pConference, CC_PEER_UPDATE_INDICATION, CC_OK, &PeerUpdateCallbackParams); } if (ValidateCall(hPeerCall) == CC_OK) UnlockCall(pPeerCall); } } status = H245_ERROR_OK; break;
default: H245ConferenceResponseCallbackParams.hCall = hCall; if (pCall->pPeerParticipantInfo == NULL) { H245ConferenceResponseCallbackParams.InitiatorTerminalLabel.bMCUNumber = 255; H245ConferenceResponseCallbackParams.InitiatorTerminalLabel.bTerminalNumber = 255; } else H245ConferenceResponseCallbackParams.InitiatorTerminalLabel = pCall->pPeerParticipantInfo->ParticipantInfo.TerminalLabel; H245ConferenceResponseCallbackParams.ResponseType = pH245ConfIndData->u.Indication.u.IndConferRsp.ResponseType; H245ConferenceResponseCallbackParams.TerminalLabel.bMCUNumber = pH245ConfIndData->u.Indication.u.IndConferRsp.byMcuNumber; H245ConferenceResponseCallbackParams.TerminalLabel.bTerminalNumber = pH245ConfIndData->u.Indication.u.IndConferRsp.byTerminalNumber; if ((pH245ConfIndData->u.Indication.u.IndConferRsp.pOctetString == NULL) || (pH245ConfIndData->u.Indication.u.IndConferRsp.byOctetStringLength == 0)) { H245ConferenceResponseCallbackParams.pOctetString = NULL; } else { OctetString.pOctetString = pH245ConfIndData->u.Indication.u.IndConferRsp.pOctetString; OctetString.wOctetStringLength = pH245ConfIndData->u.Indication.u.IndConferRsp.byOctetStringLength; H245ConferenceResponseCallbackParams.pOctetString = &OctetString; } if (pH245ConfIndData->u.Indication.u.IndConferRsp.wTerminalListCount == 0) { H245ConferenceResponseCallbackParams.pTerminalList = NULL; H245ConferenceResponseCallbackParams.wTerminalListCount = 0; status = CC_OK; } else { H245ConferenceResponseCallbackParams.pTerminalList = (CC_TERMINAL_LABEL *)MemAlloc(sizeof(CC_TERMINAL_LABEL) * pH245ConfIndData->u.Indication.u.IndConferRsp.wTerminalListCount); if (H245ConferenceResponseCallbackParams.pTerminalList == NULL) { H245ConferenceResponseCallbackParams.wTerminalListCount = 0; status = CC_NO_MEMORY; } else { for (i = 0; i < pH245ConfIndData->u.Indication.u.IndConferRsp.wTerminalListCount; i++) { H245ConferenceResponseCallbackParams.pTerminalList[i].bMCUNumber = (BYTE)pH245ConfIndData->u.Indication.u.IndConferRsp.pTerminalList[i].mcuNumber; H245ConferenceResponseCallbackParams.pTerminalList[i].bMCUNumber = (BYTE)pH245ConfIndData->u.Indication.u.IndConferRsp.pTerminalList[i].terminalNumber; } H245ConferenceResponseCallbackParams.wTerminalListCount = pH245ConfIndData->u.Indication.u.IndConferRsp.wTerminalListCount; status = CC_OK; } } status = InvokeUserConferenceCallback(pConference, CC_H245_CONFERENCE_RESPONSE_INDICATION, status, &H245ConferenceResponseCallbackParams); if (status != CC_OK) status = H245_ERROR_NOSUP; if (H245ConferenceResponseCallbackParams.pTerminalList != NULL) MemFree(H245ConferenceResponseCallbackParams.pTerminalList); break; }
if (ValidateCall(hCall) == CC_OK) UnlockCall(pCall); if (ValidateConference(hConference) == CC_OK) UnlockConference(pConference); return status; }
HRESULT _IndConferenceCommand( H245_CONF_IND_T *pH245ConfIndData) { CC_HCALL hCall; PCALL pCall; PCALL pOldCall; PCONFERENCE pConference; CC_HCONFERENCE hConference; WORD i; WORD wNumCalls; PCC_HCALL CallList; WORD wNumChannels; PCC_HCHANNEL ChannelList; PCHANNEL pChannel; CC_HCHANNEL hChannel; CALLSTATE CallState; HQ931CALL hQ931Call; H245_INST_T H245Instance; HRESULT status = CC_OK; CC_H245_CONFERENCE_COMMAND_CALLBACK_PARAMS H245ConferenceCommandCallbackParams;
hCall = pH245ConfIndData->u.Indication.dwPreserved; if (LockCallAndConference(hCall, &pCall, &pConference) != CC_OK) return H245_ERROR_OK;
hConference = pConference->hConference;
switch (pH245ConfIndData->u.Indication.u.IndConferCmd.CommandType) { case H245_CMD_DROP_CONFERENCE: if ((pConference->ConferenceMode == MULTIPOINT_MODE) && (pConference->tsMultipointController == TS_TRUE)) { UnlockCall(pCall); EnumerateCallsInConference(&wNumCalls, &CallList, pConference, ALL_CALLS); for (i = 0; i < wNumCalls; i++) { if (LockCall(CallList[i], &pCall) == CC_OK) { hQ931Call = pCall->hQ931Call; H245Instance = pCall->H245Instance; CallState = pCall->CallState; FreeCall(pCall); switch (CallState) { case ENQUEUED: break;
case PLACED: case RINGING: Q931Hangup(hQ931Call, CC_REJECT_NORMAL_CALL_CLEARING); break;
default: H245ShutDown(H245Instance); Q931Hangup(hQ931Call, CC_REJECT_NORMAL_CALL_CLEARING); break; } } } 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); InvokeUserConferenceCallback( pConference, CC_CONFERENCE_TERMINATION_INDICATION, CC_OK, NULL); if (ValidateConference(hConference) == CC_OK) { if (pConference->bDeferredDelete) FreeConference(pConference); else { ReInitializeConference(pConference); UnlockConference(pConference); } } return H245_ERROR_OK; } status = H245_ERROR_OK; break;
case brdcstMyLgclChnnl_chosen: case cnclBrdcstMyLgclChnnl_chosen: if (FindChannelInConference(pH245ConfIndData->u.Indication.u.IndConferCmd.Channel, FALSE, // remote channel number
RX_CHANNEL | PROXY_CHANNEL, hCall, &hChannel, pConference) != CC_OK) { UnlockCall(pCall); UnlockConference(pConference); return H245_ERROR_OK; }
if (LockChannel(hChannel, &pChannel) != CC_OK) { UnlockCall(pCall); UnlockConference(pConference); return H245_ERROR_OK; } if (pChannel->bChannelType == PROXY_CHANNEL) { ASSERT(pConference->ConferenceMode == MULTIPOINT_MODE); ASSERT(pConference->tsMultipointController == TS_TRUE); ASSERT(pChannel->bMultipointChannel == TRUE);
EnumerateCallsInConference(&wNumCalls, &CallList, pConference, ESTABLISHED_CALL); for (i = 0; i < wNumCalls; i++) { if (CallList[i] != hCall) { if (LockCall(CallList[i], &pOldCall) == CC_OK) { H245ConferenceCommand(pOldCall->H245Instance, pH245ConfIndData->u.Indication.u.IndConferCmd.CommandType, pChannel->wLocalChannelNumber, pH245ConfIndData->u.Indication.u.IndConferCmd.byMcuNumber, pH245ConfIndData->u.Indication.u.IndConferCmd.byTerminalNumber); UnlockCall(pOldCall); } } } MemFree(CallList); }
if (pChannel->tsAccepted == TS_TRUE) { H245ConferenceCommandCallbackParams.hCall = hCall; H245ConferenceCommandCallbackParams.hChannel = hChannel; if (pCall->pPeerParticipantInfo == NULL) { H245ConferenceCommandCallbackParams.InitiatorTerminalLabel.bMCUNumber = 255; H245ConferenceCommandCallbackParams.InitiatorTerminalLabel.bTerminalNumber = 255; } else H245ConferenceCommandCallbackParams.InitiatorTerminalLabel = pCall->pPeerParticipantInfo->ParticipantInfo.TerminalLabel; H245ConferenceCommandCallbackParams.CommandType = pH245ConfIndData->u.Indication.u.IndConferCmd.CommandType; H245ConferenceCommandCallbackParams.TerminalLabel.bMCUNumber = pH245ConfIndData->u.Indication.u.IndConferCmd.byMcuNumber; H245ConferenceCommandCallbackParams.TerminalLabel.bTerminalNumber = pH245ConfIndData->u.Indication.u.IndConferCmd.byTerminalNumber; status = InvokeUserConferenceCallback(pConference, CC_H245_CONFERENCE_COMMAND_INDICATION, CC_OK, &H245ConferenceCommandCallbackParams); if (status != CC_OK) status = H245_ERROR_NOSUP; } else status = H245_ERROR_OK;
if (ValidateChannel(hChannel) == CC_OK) UnlockChannel(pChannel); if (ValidateCall(hCall) == CC_OK) UnlockCall(pCall); if (ValidateConference(hConference) == CC_OK) UnlockConference(pConference); return status;
default: // Unrecognized conference command
// Pass it up to the client
H245ConferenceCommandCallbackParams.hCall = hCall; if (pCall->pPeerParticipantInfo == NULL) { H245ConferenceCommandCallbackParams.InitiatorTerminalLabel.bMCUNumber = 255; H245ConferenceCommandCallbackParams.InitiatorTerminalLabel.bTerminalNumber = 255; } else H245ConferenceCommandCallbackParams.InitiatorTerminalLabel = pCall->pPeerParticipantInfo->ParticipantInfo.TerminalLabel; H245ConferenceCommandCallbackParams.CommandType = pH245ConfIndData->u.Indication.u.IndConferCmd.CommandType; H245ConferenceCommandCallbackParams.TerminalLabel.bMCUNumber = pH245ConfIndData->u.Indication.u.IndConferCmd.byMcuNumber; H245ConferenceCommandCallbackParams.TerminalLabel.bTerminalNumber = pH245ConfIndData->u.Indication.u.IndConferCmd.byTerminalNumber; H245ConferenceCommandCallbackParams.hChannel = CC_INVALID_HANDLE; status = InvokeUserConferenceCallback(pConference, CC_H245_CONFERENCE_COMMAND_INDICATION, CC_OK, &H245ConferenceCommandCallbackParams); if (status != CC_OK) status = H245_ERROR_NOSUP; if (ValidateCall(hCall) == CC_OK) UnlockCall(pCall); if (ValidateConference(hConference) == CC_OK) UnlockConference(pConference); return status; }
if (ValidateCall(hCall) == CC_OK) UnlockCall(pCall); if (ValidateConference(hConference) == CC_OK) UnlockConference(pConference); return status; }
HRESULT _IndConference( H245_CONF_IND_T *pH245ConfIndData) { CC_HCALL hCall; PCALL pCall; PCALL pPeerCall; PCONFERENCE pConference; CC_HCONFERENCE hConference; H245_TERMINAL_LABEL_T H245TerminalLabel; PPARTICIPANTINFO pPeerParticipantInfo; HRESULT status; CC_HCALL hVirtualCall; PCALL pVirtualCall; CC_PEER_ADD_CALLBACK_PARAMS PeerAddCallbackParams; CC_PEER_DROP_CALLBACK_PARAMS PeerDropCallbackParams; CC_H245_CONFERENCE_INDICATION_CALLBACK_PARAMS H245ConferenceIndicationCallbackParams;
hCall = pH245ConfIndData->u.Indication.dwPreserved; if (LockCallAndConference(hCall, &pCall, &pConference) != CC_OK) return H245_ERROR_OK;
hConference = pConference->hConference;
switch (pH245ConfIndData->u.Indication.u.IndConfer.IndicationType) { case H245_IND_TERMINAL_NUMBER_ASSIGN: if (pConference->tsMultipointController == TS_FALSE) { pConference->LocalParticipantInfo.ParticipantInfo.TerminalLabel.bMCUNumber = pH245ConfIndData->u.Indication.u.IndConfer.byMcuNumber; pConference->LocalParticipantInfo.ParticipantInfo.TerminalLabel.bTerminalNumber = pH245ConfIndData->u.Indication.u.IndConfer.byTerminalNumber;
hConference = pConference->hConference; // Generate a CC_TERMINAL_NUMBER_ASSIGN callback
InvokeUserConferenceCallback(pConference, CC_TERMINAL_NUMBER_INDICATION, CC_OK, &pConference->LocalParticipantInfo.ParticipantInfo.TerminalLabel);
if (ValidateConference(hConference) == CC_OK) UnlockConference(pConference); UnlockCall(pCall); return H245_ERROR_OK; } status = H245_ERROR_OK; break;
case H245_IND_TERMINAL_JOINED: if (pConference->tsMultipointController == TS_FALSE) { if ((pH245ConfIndData->u.Indication.u.IndConfer.byMcuNumber == pConference->LocalParticipantInfo.ParticipantInfo.TerminalLabel.bMCUNumber) && (pH245ConfIndData->u.Indication.u.IndConfer.byTerminalNumber == pConference->LocalParticipantInfo.ParticipantInfo.TerminalLabel.bTerminalNumber)) { // This message refers to us
status = H245_ERROR_OK; break; }
H245TerminalLabel.mcuNumber = pH245ConfIndData->u.Indication.u.IndConfer.byMcuNumber; H245TerminalLabel.terminalNumber = pH245ConfIndData->u.Indication.u.IndConfer.byTerminalNumber; FindPeerParticipantInfo(H245TerminalLabel, pConference, VIRTUAL_CALL, &pPeerCall); if (pPeerCall != NULL) { // We already know this peer's terminal label, and we
// eithet know its terminal ID or we have a pending request
// to obtain it
UnlockCall(pPeerCall); status = H245_ERROR_OK; break; }
// We don't know about this peer.
// Create a virtual call object for it, and issue a request
// for its terminal ID
status = AllocAndLockCall(&hVirtualCall, pConference->hConference, CC_INVALID_HANDLE, // hQ931Call
CC_INVALID_HANDLE, // hQ931CallInvitor,
NULL, // pLocalAliasNames,
NULL, // pPeerAliasNames,
NULL, // pPeerExtraAliasNames
NULL, // pPeerExtension
NULL, // pLocalNonStandardData,
NULL, // pPeerNonStandardData,
NULL, // pszLocalDisplay,
NULL, // pszPeerDisplay,
NULL, // pPeerVendorInfo,
NULL, // pQ931LocalConnectAddr,
NULL, // pQ931PeerConnectAddr,
NULL, // pQ931DestinationAddr,
NULL, // pSourceCallSignalAddress
VIRTUAL, // CallType,
FALSE, // bCallerIsMC,
0, // dwUserToken,
CALL_COMPLETE, // InitialCallState,
NULL, // no CallIdentifier
&pConference->ConferenceID, &pVirtualCall); if (status == CC_OK) { status = AllocatePeerParticipantInfo(NULL, &pPeerParticipantInfo); if (status == CC_OK) { pVirtualCall->pPeerParticipantInfo = pPeerParticipantInfo; pPeerParticipantInfo->ParticipantInfo.TerminalLabel.bMCUNumber = (BYTE)H245TerminalLabel.mcuNumber; pPeerParticipantInfo->ParticipantInfo.TerminalLabel.bTerminalNumber = (BYTE)H245TerminalLabel.terminalNumber; AddVirtualCallToConference(pVirtualCall, pConference); // Send RequestTerminalID
H245ConferenceRequest(pCall->H245Instance, H245_REQ_TERMINAL_ID, (BYTE)H245TerminalLabel.mcuNumber, (BYTE)H245TerminalLabel.terminalNumber); pPeerParticipantInfo->TerminalIDState = TERMINAL_ID_REQUESTED;
// Generate PEER_ADD callback
PeerAddCallbackParams.hCall = hVirtualCall; PeerAddCallbackParams.TerminalLabel = pVirtualCall->pPeerParticipantInfo->ParticipantInfo.TerminalLabel; PeerAddCallbackParams.pPeerTerminalID = NULL; InvokeUserConferenceCallback(pConference, CC_PEER_ADD_INDICATION, CC_OK, &PeerAddCallbackParams); if (ValidateCall(hVirtualCall) == CC_OK) UnlockCall(pVirtualCall); if (ValidateConference(hConference) == CC_OK) UnlockConference(pConference); UnlockCall(pCall); return H245_ERROR_OK; } else FreeCall(pVirtualCall); } } status = H245_ERROR_OK; break;
case H245_IND_TERMINAL_LEFT: if (pConference->tsMultipointController == TS_FALSE) { H245TerminalLabel.mcuNumber = pH245ConfIndData->u.Indication.u.IndConfer.byMcuNumber; H245TerminalLabel.terminalNumber = pH245ConfIndData->u.Indication.u.IndConfer.byTerminalNumber; status = FindPeerParticipantInfo(H245TerminalLabel, pConference, VIRTUAL_CALL, &pVirtualCall); if (status == CC_OK) { ASSERT(pVirtualCall != NULL); ASSERT(pVirtualCall->pPeerParticipantInfo != NULL); // Save the virtual call handle; we'll need to validate the virtual
// call object after returning from the conference callback
hVirtualCall = pVirtualCall->hCall; PeerDropCallbackParams.hCall = hVirtualCall; PeerDropCallbackParams.TerminalLabel = pVirtualCall->pPeerParticipantInfo->ParticipantInfo.TerminalLabel; if (pVirtualCall->pPeerParticipantInfo->TerminalIDState == TERMINAL_ID_VALID) PeerDropCallbackParams.pPeerTerminalID = &pVirtualCall->pPeerParticipantInfo->ParticipantInfo.TerminalID; else PeerDropCallbackParams.pPeerTerminalID = NULL; } else { // Set pVirtualCall to NULL to indicate that we don't have
// a virtual call object that needs to be free'd up later
pVirtualCall = NULL; PeerDropCallbackParams.hCall = CC_INVALID_HANDLE; PeerDropCallbackParams.TerminalLabel.bMCUNumber = pH245ConfIndData->u.Indication.u.IndConfer.byMcuNumber; PeerDropCallbackParams.TerminalLabel.bTerminalNumber = pH245ConfIndData->u.Indication.u.IndConfer.byTerminalNumber; PeerDropCallbackParams.pPeerTerminalID = NULL; }
hConference = pConference->hConference;
// Generate a CC_PEER_DROP_INDICATION callback
InvokeUserConferenceCallback(pConference, CC_PEER_DROP_INDICATION, CC_OK, &PeerDropCallbackParams); if (ValidateConference(hConference) == CC_OK) UnlockConference(pConference); // Check to see if we have a virtual call object that needs to be free'd up
if (pVirtualCall != NULL) if (ValidateCall(hVirtualCall) == CC_OK) FreeCall(pVirtualCall); UnlockCall(pCall); return H245_ERROR_OK; } status = H245_ERROR_OK; break;
default: H245ConferenceIndicationCallbackParams.hCall = hCall; if (pCall->pPeerParticipantInfo == NULL) { H245ConferenceIndicationCallbackParams.InitiatorTerminalLabel.bMCUNumber = 255; H245ConferenceIndicationCallbackParams.InitiatorTerminalLabel.bTerminalNumber = 255; } else H245ConferenceIndicationCallbackParams.InitiatorTerminalLabel = pCall->pPeerParticipantInfo->ParticipantInfo.TerminalLabel; H245ConferenceIndicationCallbackParams.IndicationType = pH245ConfIndData->u.Indication.u.IndConfer.IndicationType; H245ConferenceIndicationCallbackParams.bSBENumber = pH245ConfIndData->u.Indication.u.IndConfer.bySbeNumber; H245ConferenceIndicationCallbackParams.TerminalLabel.bMCUNumber = pH245ConfIndData->u.Indication.u.IndConfer.byMcuNumber; H245ConferenceIndicationCallbackParams.TerminalLabel.bTerminalNumber = pH245ConfIndData->u.Indication.u.IndConfer.byTerminalNumber; status = InvokeUserConferenceCallback(pConference, CC_H245_CONFERENCE_INDICATION_INDICATION, CC_OK, &H245ConferenceIndicationCallbackParams); if (status != CC_OK) status = H245_ERROR_NOSUP; break; } if (ValidateCall(hCall) == CC_OK) UnlockCall(pCall); if (ValidateConference(hConference) == CC_OK) UnlockConference(pConference); return status; }
HRESULT _IndCommunicationModeCommand( H245_CONF_IND_T *pH245ConfIndData) { CC_HCALL hCall; PCALL pCall; CC_HCONFERENCE hConference; PCONFERENCE pConference; CC_MULTIPOINT_CALLBACK_PARAMS MultipointCallbackParams;
hCall = pH245ConfIndData->u.Indication.dwPreserved; if (LockCallAndConference(hCall, &pCall, &pConference) != CC_OK) return H245_ERROR_OK;
if (pConference->tsMultipointController == TS_TRUE) { UnlockCall(pCall); UnlockConference(pConference); return H245_ERROR_OK; }
hConference = pConference->hConference;
// Destroy the old session table
FreeConferenceSessionTable(pConference);
H245CommunicationTableToSessionTable( pH245ConfIndData->u.Indication.u.IndCommRsp.pTable, pH245ConfIndData->u.Indication.u.IndCommRsp.byTableCount, &pConference->pSessionTable); pConference->bSessionTableInternallyConstructed = TRUE;
// Generate MULTIPOINT callback
MultipointCallbackParams.pTerminalInfo = &pConference->LocalParticipantInfo.ParticipantInfo; MultipointCallbackParams.pSessionTable = pConference->pSessionTable; InvokeUserConferenceCallback(pConference, CC_MULTIPOINT_INDICATION, CC_OK, &MultipointCallbackParams);
if (ValidateCall(hCall) == CC_OK) UnlockCall(pCall); if (ValidateConference(hConference) == CC_OK) UnlockConference(pConference); return H245_ERROR_OK; }
HRESULT _IndVendorIdentification( H245_CONF_IND_T *pH245ConfIndData, VendorIdentification *pVendorIdentification) { CC_HCALL hCall; PCALL pCall; CC_HCONFERENCE hConference; PCONFERENCE pConference; CC_NONSTANDARDDATA NonStandardData; CC_OCTETSTRING ProductNumber; CC_OCTETSTRING VersionNumber; CC_VENDOR_ID_CALLBACK_PARAMS VendorIDCallbackParams;
hCall = pH245ConfIndData->u.Indication.dwPreserved; if (LockCallAndConference(hCall, &pCall, &pConference) != CC_OK) return H245_ERROR_OK;
hConference = pConference->hConference;
VendorIDCallbackParams.hCall = hCall; if (pCall->pPeerParticipantInfo == NULL) { VendorIDCallbackParams.InitiatorTerminalLabel.bMCUNumber = 255; VendorIDCallbackParams.InitiatorTerminalLabel.bTerminalNumber = 255; } else VendorIDCallbackParams.InitiatorTerminalLabel = pCall->pPeerParticipantInfo->ParticipantInfo.TerminalLabel;
if (pVendorIdentification->vendor.choice == h221NonStandard_chosen) { NonStandardData.sData.pOctetString = NULL; NonStandardData.sData.wOctetStringLength = 0; NonStandardData.bCountryCode = (BYTE)pVendorIdentification->vendor.u.h221NonStandard.t35CountryCode; NonStandardData.bExtension = (BYTE)pVendorIdentification->vendor.u.h221NonStandard.t35Extension; NonStandardData.wManufacturerCode = pVendorIdentification->vendor.u.h221NonStandard.manufacturerCode; VendorIDCallbackParams.pNonStandardData = &NonStandardData; } else VendorIDCallbackParams.pNonStandardData = NULL;
if (pVendorIdentification->bit_mask & productNumber_present) { ProductNumber.pOctetString = pVendorIdentification->productNumber.value; ProductNumber.wOctetStringLength = (WORD) pVendorIdentification->productNumber.length; VendorIDCallbackParams.pProductNumber = &ProductNumber; } else VendorIDCallbackParams.pProductNumber = NULL; if (pVendorIdentification->bit_mask & versionNumber_present) { VersionNumber.pOctetString = pVendorIdentification->versionNumber.value; VersionNumber.wOctetStringLength = (WORD) pVendorIdentification->versionNumber.length; VendorIDCallbackParams.pVersionNumber = &VersionNumber; } else VendorIDCallbackParams.pVersionNumber = NULL;
InvokeUserConferenceCallback(pConference, CC_VENDOR_ID_INDICATION, CC_OK, &VendorIDCallbackParams); if (ValidateCall(hCall) == CC_OK) UnlockCall(pCall); if (ValidateConference(hConference) == CC_OK) UnlockConference(pConference); return H245_ERROR_OK; }
HRESULT _IndH2250MaximumSkew( H245_CONF_IND_T *pH245ConfIndData) { HRESULT status; CC_HCONFERENCE hConference; PCONFERENCE pConference; CC_HCALL hCall; PCC_HCALL CallList; WORD wNumCalls; WORD i; PCALL pCall; PCALL pOldCall; CC_HCHANNEL hChannel1; PCHANNEL pChannel1; CC_HCHANNEL hChannel2; PCHANNEL pChannel2; CC_MAXIMUM_AUDIO_VIDEO_SKEW_CALLBACK_PARAMS MaximumAudioVideoSkewCallbackParams;
hCall = pH245ConfIndData->u.Indication.dwPreserved; status = LockCallAndConference(hCall, &pCall, &pConference); if (status != CC_OK) { // This may be OK, if the call was cancelled while
// call setup was in progress.
return H245_ERROR_OK; }
hConference = pCall->hConference; UnlockCall(pCall);
if (FindChannelInConference(pH245ConfIndData->u.Indication.u.IndH2250MaxSkew.LogicalChannelNumber1, FALSE, // remote channel number
RX_CHANNEL | PROXY_CHANNEL, hCall, &hChannel1, pConference) != CC_OK) { UnlockConference(pConference); return H245_ERROR_OK; }
if (LockChannel(hChannel1, &pChannel1) != CC_OK) { UnlockConference(pConference); return H245_ERROR_OK; } if (pChannel1->bChannelType == RX_CHANNEL) { UnlockChannel(pChannel1); if (FindChannelInConference(pH245ConfIndData->u.Indication.u.IndH2250MaxSkew.LogicalChannelNumber2, FALSE, // remote channel number
RX_CHANNEL, hCall, &hChannel2, pConference) != CC_OK) { UnlockConference(pConference); return H245_ERROR_OK; } if (LockChannel(hChannel2, &pChannel2) != CC_OK) { UnlockConference(pConference); return H245_ERROR_OK; } if (pChannel2->bChannelType != RX_CHANNEL) { UnlockChannel(pChannel2); UnlockConference(pConference); return H245_ERROR_OK; } UnlockChannel(pChannel2);
MaximumAudioVideoSkewCallbackParams.hChannel1 = hChannel1; MaximumAudioVideoSkewCallbackParams.hChannel2 = hChannel2; MaximumAudioVideoSkewCallbackParams.wMaximumSkew = pH245ConfIndData->u.Indication.u.IndH2250MaxSkew.wSkew; InvokeUserConferenceCallback(pConference, CC_MAXIMUM_AUDIO_VIDEO_SKEW_INDICATION, CC_OK, &MaximumAudioVideoSkewCallbackParams); if (ValidateConference(hConference) == CC_OK) UnlockConference(pConference); } else { // pChannel1->bChannelType == PROXY_CHANNEL
if (FindChannelInConference(pH245ConfIndData->u.Indication.u.IndH2250MaxSkew.LogicalChannelNumber2, FALSE, // remote channel number
PROXY_CHANNEL, hCall, &hChannel2, pConference) != CC_OK) { UnlockChannel(pChannel1); UnlockConference(pConference); return H245_ERROR_OK; } if (LockChannel(hChannel2, &pChannel2) != CC_OK) { UnlockChannel(pChannel1); UnlockConference(pConference); return H245_ERROR_OK; } if (pChannel1->hCall != pChannel2->hCall) { UnlockChannel(pChannel1); UnlockChannel(pChannel2); UnlockConference(pConference); return H245_ERROR_OK; }
EnumerateCallsInConference(&wNumCalls, &CallList, pConference, ESTABLISHED_CALL); for (i = 0; i < wNumCalls; i++) { if (CallList[i] != hCall) { if (LockCall(CallList[i], &pOldCall) == CC_OK) { H245H2250MaximumSkewIndication(pOldCall->H245Instance, pChannel1->wLocalChannelNumber, pChannel2->wLocalChannelNumber, pH245ConfIndData->u.Indication.u.IndH2250MaxSkew.wSkew); UnlockCall(pCall); } } }
if (CallList != NULL) MemFree(CallList);
if ((pChannel1->tsAccepted == TS_TRUE) && (pChannel2->tsAccepted == TS_TRUE)) { MaximumAudioVideoSkewCallbackParams.hChannel1 = hChannel1; MaximumAudioVideoSkewCallbackParams.hChannel2 = hChannel2; MaximumAudioVideoSkewCallbackParams.wMaximumSkew = pH245ConfIndData->u.Indication.u.IndH2250MaxSkew.wSkew; InvokeUserConferenceCallback(pConference, CC_MAXIMUM_AUDIO_VIDEO_SKEW_INDICATION, CC_OK, &MaximumAudioVideoSkewCallbackParams); }
if (ValidateChannel(hChannel1) == CC_OK) UnlockChannel(pChannel1); if (ValidateChannel(hChannel2) == CC_OK) UnlockChannel(pChannel2); if (ValidateConference(hConference) == CC_OK) UnlockConference(pConference); } return H245_ERROR_OK; }
HRESULT _IndUserInput( H245_CONF_IND_T *pH245ConfIndData) { return H245_ERROR_OK; }
HRESULT _IndSendTerminalCapabilitySet( H245_CONF_IND_T *pH245ConfIndData) { HRESULT status; CC_HCALL hCall; PCALL pCall; PCONFERENCE pConference;
hCall = pH245ConfIndData->u.Indication.dwPreserved; status = LockCallAndConference(hCall, &pCall, &pConference); if (status != CC_OK) { // This may be OK, if the call was cancelled while
// call setup was in progress.
return H245_ERROR_OK; }
SendTermCaps(pCall, pConference); UnlockCall(pCall); UnlockConference(pConference); return H245_ERROR_OK; }
HRESULT _IndModeRequest( H245_CONF_IND_T *pH245ConfIndData) { HRESULT status; CC_HCALL hCall; PCALL pCall; CC_HCONFERENCE hConference; PCONFERENCE pConference; CC_REQUEST_MODE_CALLBACK_PARAMS RequestModeCallbackParams;
hCall = pH245ConfIndData->u.Indication.dwPreserved; status = LockCallAndConference(hCall, &pCall, &pConference); if (status != CC_OK) { // This may be OK, if the call was cancelled while
// call setup was in progress.
return H245_ERROR_OK; }
hConference = pConference->hConference;
EnqueueRequest(&pConference->pEnqueuedRequestModeCalls, hCall);
RequestModeCallbackParams.hCall = hCall; if (pCall->pPeerParticipantInfo == NULL) { RequestModeCallbackParams.InitiatorTerminalLabel.bMCUNumber = 255; RequestModeCallbackParams.InitiatorTerminalLabel.bTerminalNumber = 255; } else RequestModeCallbackParams.InitiatorTerminalLabel = pCall->pPeerParticipantInfo->ParticipantInfo.TerminalLabel; RequestModeCallbackParams.pRequestedModes = pH245ConfIndData->u.Indication.u.IndMrse.pRequestedModes;
InvokeUserConferenceCallback(pConference, CC_REQUEST_MODE_INDICATION, CC_OK, &RequestModeCallbackParams); if (ValidateCall(hCall) == CC_OK) UnlockCall(pCall); if (ValidateConference(hConference) == CC_OK) UnlockConference(pConference); return H245_ERROR_OK; }
HRESULT _ConfUnimplemented( H245_CONF_IND_T *pH245ConfIndData) { return H245_ERROR_NOSUP; }
HRESULT _ConfBiDirectionalOpen( H245_CONF_IND_T *pH245ConfIndData) { CC_HCALL hCall; CC_HCHANNEL hChannel; CC_HCONFERENCE hConference; PCHANNEL pChannel; PCONFERENCE pConference; BOOL bAccept; HRESULT status; CC_ADDR T120Addr; CC_OCTETSTRING ExternalReference; CC_T120_CHANNEL_OPEN_CALLBACK_PARAMS T120ChannelOpenCallbackParams;
hCall = pH245ConfIndData->u.Confirm.dwPreserved; if (hCall == CC_INVALID_HANDLE) return H245_ERROR_OK;
hChannel = pH245ConfIndData->u.Confirm.dwTransId; if (hChannel == CC_INVALID_HANDLE) return H245_ERROR_OK;
if (LockChannelAndConference(hChannel, &pChannel, &pConference) != CC_OK) return H245_ERROR_OK;
hConference = pConference->hConference;
if (pChannel->bChannelType != TXRX_CHANNEL) { UnlockChannel(pChannel); UnlockConference(pConference); return H245_ERROR_OK; }
if ((pH245ConfIndData->u.Confirm.u.ConfOpenNeedRsp.AccRej == H245_ACC) && (pH245ConfIndData->u.Confirm.Error == H245_ERROR_OK)) { pChannel->wNumOutstandingRequests = 0; bAccept = TRUE; } else { (pChannel->wNumOutstandingRequests)--; bAccept = FALSE; }
T120ChannelOpenCallbackParams.hChannel = hChannel; T120ChannelOpenCallbackParams.hCall = hCall; T120ChannelOpenCallbackParams.dwUserToken = pChannel->dwUserToken; T120ChannelOpenCallbackParams.dwRejectReason = 0;
if (bAccept) { status = CC_OK; if (pH245ConfIndData->u.Confirm.u.ConfOpenNeedRsp.pSeparateStack) { if ((pH245ConfIndData->u.Confirm.u.ConfOpenNeedRsp.pSeparateStack->networkAddress.choice == localAreaAddress_chosen) && (pH245ConfIndData->u.Confirm.u.ConfOpenNeedRsp.pSeparateStack->networkAddress.u.localAreaAddress.choice == unicastAddress_chosen) && (pH245ConfIndData->u.Confirm.u.ConfOpenNeedRsp.pSeparateStack->networkAddress.u.localAreaAddress.u.unicastAddress.choice == UnicastAddress_iPAddress_chosen)) { T120Addr.nAddrType = CC_IP_BINARY; T120Addr.bMulticast = FALSE; T120Addr.Addr.IP_Binary.wPort = pH245ConfIndData->u.Confirm.u.ConfOpenNeedRsp.pSeparateStack->networkAddress.u.localAreaAddress.u.unicastAddress.u.UnicastAddress_iPAddress.tsapIdentifier; H245IPNetworkToHost(&T120Addr.Addr.IP_Binary.dwAddr, pH245ConfIndData->u.Confirm.u.ConfOpenNeedRsp.pSeparateStack->networkAddress.u.localAreaAddress.u.unicastAddress.u.UnicastAddress_iPAddress.network.value); T120ChannelOpenCallbackParams.pAddr = &T120Addr; } else { T120ChannelOpenCallbackParams.pAddr = NULL; } T120ChannelOpenCallbackParams.bAssociateConference = pH245ConfIndData->u.Confirm.u.ConfOpenNeedRsp.pSeparateStack->associateConference; if (pH245ConfIndData->u.Confirm.u.ConfOpenNeedRsp.pSeparateStack->bit_mask & externalReference_present) { ExternalReference.wOctetStringLength = (WORD) pH245ConfIndData->u.Confirm.u.ConfOpenNeedRsp.pSeparateStack->externalReference.length; ExternalReference.pOctetString = pH245ConfIndData->u.Confirm.u.ConfOpenNeedRsp.pSeparateStack->externalReference.value; T120ChannelOpenCallbackParams.pExternalReference = &ExternalReference; } else T120ChannelOpenCallbackParams.pExternalReference = NULL; } else { T120ChannelOpenCallbackParams.pAddr = NULL; T120ChannelOpenCallbackParams.bAssociateConference = FALSE; T120ChannelOpenCallbackParams.pExternalReference = NULL; } } else { // bAccept == FALSE
if (pH245ConfIndData->u.Confirm.Error == H245_ERROR_OK) status = CC_PEER_REJECT; else status = pH245ConfIndData->u.Confirm.Error; T120ChannelOpenCallbackParams.pAddr = NULL; T120ChannelOpenCallbackParams.bAssociateConference = FALSE; T120ChannelOpenCallbackParams.pExternalReference = NULL; T120ChannelOpenCallbackParams.dwRejectReason = pH245ConfIndData->u.Confirm.u.ConfOpenNeedRsp.AccRej; }
InvokeUserConferenceCallback(pConference, CC_T120_CHANNEL_OPEN_INDICATION, status, &T120ChannelOpenCallbackParams);
if (ValidateChannel(hChannel) == CC_OK) if (bAccept) UnlockChannel(pChannel); else FreeChannel(pChannel); if (ValidateConference(hConference) == CC_OK) UnlockConference(pConference);
return H245_ERROR_OK; }
HRESULT _ConfOpenT120( H245_CONF_IND_T *pH245ConfIndData) { CC_HCALL hCall; CC_HCHANNEL hChannel; CC_HCONFERENCE hConference; PCHANNEL pChannel; PCONFERENCE pConference; HRESULT status; CC_T120_CHANNEL_OPEN_CALLBACK_PARAMS T120ChannelOpenCallbackParams;
hCall = pH245ConfIndData->u.Confirm.dwPreserved; if (hCall == CC_INVALID_HANDLE) return H245_ERROR_OK;
hChannel = pH245ConfIndData->u.Confirm.dwTransId; if (hChannel == CC_INVALID_HANDLE) return H245_ERROR_OK;
if (LockChannelAndConference(hChannel, &pChannel, &pConference) != CC_OK) return H245_ERROR_OK;
hConference = pConference->hConference;
if (pChannel->bChannelType != TXRX_CHANNEL) { UnlockChannel(pChannel); UnlockConference(pConference); return H245_ERROR_OK; }
if ((pH245ConfIndData->u.Confirm.u.ConfOpen.AccRej == H245_ACC) && (pH245ConfIndData->u.Confirm.Error == H245_ERROR_OK)) { // We expect to get a ConfOpenNeedRsp callback for this case;
// Since we're not sure how we got here, just bail out
UnlockChannel(pChannel); UnlockConference(pConference); return H245_ERROR_OK; }
T120ChannelOpenCallbackParams.hChannel = hChannel; T120ChannelOpenCallbackParams.hCall = hCall; T120ChannelOpenCallbackParams.dwUserToken = pChannel->dwUserToken;
if (pH245ConfIndData->u.Confirm.Error == H245_ERROR_OK) status = CC_PEER_REJECT; else status = pH245ConfIndData->u.Confirm.Error; T120ChannelOpenCallbackParams.pAddr = NULL; T120ChannelOpenCallbackParams.bAssociateConference = FALSE; T120ChannelOpenCallbackParams.pExternalReference = NULL; T120ChannelOpenCallbackParams.dwRejectReason = pH245ConfIndData->u.Confirm.u.ConfOpenNeedRsp.AccRej;
InvokeUserConferenceCallback(pConference, CC_T120_CHANNEL_OPEN_INDICATION, status, &T120ChannelOpenCallbackParams);
if (ValidateChannel(hChannel) == CC_OK) FreeChannel(pChannel); if (ValidateConference(hConference) == CC_OK) UnlockConference(pConference);
return H245_ERROR_OK; }
HRESULT _ConfOpen( H245_CONF_IND_T *pH245ConfIndData) { HRESULT status; CC_ADDR PeerRTPAddr; PCC_ADDR pPeerRTPAddr; CC_ADDR PeerRTCPAddr; PCC_ADDR pPeerRTCPAddr; CC_HCHANNEL hChannel; PCHANNEL pChannel; CC_HCONFERENCE hConference; PCONFERENCE pConference; CC_TX_CHANNEL_OPEN_CALLBACK_PARAMS TxChannelOpenCallbackParams; PCALL pCall; BOOL bAccept; H245_MUX_T H245MuxTable; WORD i; #ifdef GATEKEEPER
unsigned uBandwidth; WORD wNumCalls; PCC_HCALL CallList; #endif // GATEKEEPER
// a channel was opened
hChannel = pH245ConfIndData->u.Confirm.dwTransId; if (hChannel == CC_INVALID_HANDLE) return H245_ERROR_OK;
if (LockChannelAndConference(hChannel, &pChannel, &pConference) != CC_OK) return H245_ERROR_OK;
if (pChannel->bChannelType == TXRX_CHANNEL) { UnlockChannel(pChannel); UnlockConference(pConference); return _ConfOpenT120(pH245ConfIndData); }
hConference = pConference->hConference;
if (pChannel->wNumOutstandingRequests == 0) { UnlockChannel(pChannel); UnlockConference(pConference); return H245_ERROR_OK; }
if ((pH245ConfIndData->u.Confirm.u.ConfOpen.AccRej == H245_ACC) && (pH245ConfIndData->u.Confirm.Error == H245_ERROR_OK)) { pChannel->wNumOutstandingRequests = 0; bAccept = TRUE; } else { (pChannel->wNumOutstandingRequests)--; bAccept = FALSE; #ifdef GATEKEEPER
if(GKIExists()) { uBandwidth = pChannel->dwChannelBitRate / 100; if (uBandwidth != 0 && pChannel->bChannelType != TXRX_CHANNEL) { EnumerateCallsInConference(&wNumCalls, &CallList, pConference, ESTABLISHED_CALL); for (i = 0; i < wNumCalls; ++i) { if (LockCall(CallList[i], &pCall) == CC_OK) { if (pCall->GkiCall.uBandwidthUsed >= uBandwidth) { if (GkiCloseChannel(&pCall->GkiCall, pChannel->dwChannelBitRate, hChannel) == CC_OK) { UnlockCall(pCall); break; } } UnlockCall(pCall); } } // for
if (CallList != NULL) MemFree(CallList); } } #endif // GATEKEEPER
} if (pChannel->wNumOutstandingRequests == 0) {
if (pH245ConfIndData->u.Confirm.u.ConfOpen.pTxMux == NULL) { pPeerRTPAddr = NULL; pPeerRTCPAddr = NULL; } else { ASSERT(pH245ConfIndData->u.Confirm.u.ConfOpen.pTxMux->Kind == H245_H2250ACK); if ((pH245ConfIndData->u.Confirm.u.ConfOpen.pTxMux->u.H2250ACK.mediaChannelPresent) && ((pH245ConfIndData->u.Confirm.u.ConfOpen.pTxMux->u.H2250ACK.mediaChannel.type == H245_IP_MULTICAST) || (pH245ConfIndData->u.Confirm.u.ConfOpen.pTxMux->u.H2250ACK.mediaChannel.type == H245_IP_UNICAST))) { pPeerRTPAddr = &PeerRTPAddr; PeerRTPAddr.nAddrType = CC_IP_BINARY; if (pH245ConfIndData->u.Confirm.u.ConfOpen.pTxMux->u.H2250ACK.mediaChannel.type == H245_IP_MULTICAST) PeerRTPAddr.bMulticast = TRUE; else PeerRTPAddr.bMulticast = FALSE; H245IPNetworkToHost(&PeerRTPAddr.Addr.IP_Binary.dwAddr, pH245ConfIndData->u.Confirm.u.ConfOpen.pTxMux->u.H2250ACK.mediaChannel.u.ip.network); PeerRTPAddr.Addr.IP_Binary.wPort = pH245ConfIndData->u.Confirm.u.ConfOpen.pTxMux->u.H2250ACK.mediaChannel.u.ip.tsapIdentifier; } else pPeerRTPAddr = NULL;
if ((pH245ConfIndData->u.Confirm.u.ConfOpen.pTxMux->u.H2250ACK.mediaControlChannelPresent) && ((pH245ConfIndData->u.Confirm.u.ConfOpen.pTxMux->u.H2250ACK.mediaControlChannel.type == H245_IP_MULTICAST) || (pH245ConfIndData->u.Confirm.u.ConfOpen.pTxMux->u.H2250ACK.mediaControlChannel.type == H245_IP_UNICAST))) { pPeerRTCPAddr = &PeerRTCPAddr; PeerRTCPAddr.nAddrType = CC_IP_BINARY; if (pH245ConfIndData->u.Confirm.u.ConfOpen.pTxMux->u.H2250ACK.mediaControlChannel.type == H245_IP_MULTICAST) PeerRTCPAddr.bMulticast = TRUE; else PeerRTCPAddr.bMulticast = FALSE; H245IPNetworkToHost(&PeerRTCPAddr.Addr.IP_Binary.dwAddr, pH245ConfIndData->u.Confirm.u.ConfOpen.pTxMux->u.H2250ACK.mediaControlChannel.u.ip.network); PeerRTCPAddr.Addr.IP_Binary.wPort = pH245ConfIndData->u.Confirm.u.ConfOpen.pTxMux->u.H2250ACK.mediaControlChannel.u.ip.tsapIdentifier; } else pPeerRTCPAddr = NULL; }
if ((pPeerRTPAddr == NULL) || (pPeerRTCPAddr == NULL)) { if (pConference->pSessionTable != NULL) { for (i = 0; i < pConference->pSessionTable->wLength; i++) { if (pConference->pSessionTable->SessionInfoArray[i].bSessionID == pChannel->bSessionID) { if (pPeerRTPAddr == NULL) pPeerRTPAddr = pConference->pSessionTable->SessionInfoArray[i].pRTPAddr; if (pPeerRTCPAddr == NULL) pPeerRTCPAddr = pConference->pSessionTable->SessionInfoArray[i].pRTCPAddr; break; } } } }
if ((pChannel->pPeerRTPAddr == NULL) && (pPeerRTPAddr != NULL)) CopyAddr(&pChannel->pPeerRTPAddr, pPeerRTPAddr); if ((pChannel->pPeerRTCPAddr == NULL) && (pPeerRTCPAddr != NULL)) CopyAddr(&pChannel->pPeerRTCPAddr, pPeerRTCPAddr);
if (pChannel->bChannelType == PROXY_CHANNEL) { if (LockCall(pChannel->hCall, &pCall) == CC_OK) { if (bAccept) { H245MuxTable.Kind = H245_H2250ACK; H245MuxTable.u.H2250ACK.nonStandardList = NULL;
if (pPeerRTPAddr != NULL) { if (pPeerRTPAddr->bMulticast) H245MuxTable.u.H2250ACK.mediaChannel.type = H245_IP_MULTICAST; else H245MuxTable.u.H2250ACK.mediaChannel.type = H245_IP_UNICAST; H245MuxTable.u.H2250ACK.mediaChannel.u.ip.tsapIdentifier = pPeerRTPAddr->Addr.IP_Binary.wPort; HostToH245IPNetwork(H245MuxTable.u.H2250ACK.mediaChannel.u.ip.network, pPeerRTPAddr->Addr.IP_Binary.dwAddr); H245MuxTable.u.H2250ACK.mediaChannelPresent = TRUE; } else H245MuxTable.u.H2250ACK.mediaChannelPresent = FALSE;
if (pPeerRTCPAddr != NULL) { if (pPeerRTCPAddr->bMulticast) H245MuxTable.u.H2250ACK.mediaControlChannel.type = H245_IP_MULTICAST; else H245MuxTable.u.H2250ACK.mediaControlChannel.type = H245_IP_UNICAST; H245MuxTable.u.H2250ACK.mediaControlChannel.u.ip.tsapIdentifier = pPeerRTCPAddr->Addr.IP_Binary.wPort; HostToH245IPNetwork(H245MuxTable.u.H2250ACK.mediaControlChannel.u.ip.network, pPeerRTCPAddr->Addr.IP_Binary.dwAddr); H245MuxTable.u.H2250ACK.mediaControlChannelPresent = TRUE; } else H245MuxTable.u.H2250ACK.mediaControlChannelPresent = FALSE;
H245MuxTable.u.H2250ACK.dynamicRTPPayloadTypePresent = FALSE; H245MuxTable.u.H2250ACK.sessionIDPresent = TRUE; H245MuxTable.u.H2250ACK.sessionID = pChannel->bSessionID; status = H245OpenChannelAccept(pCall->H245Instance, 0, // dwTransId
pChannel->wRemoteChannelNumber, // Rx channel
&H245MuxTable, 0, // Tx channel
NULL, // Tx mux
H245_INVALID_PORT_NUMBER,// Port
NULL); } else { // bAccept == FALSE
status = H245OpenChannelReject(pCall->H245Instance, pChannel->wRemoteChannelNumber, // Rx channel
(unsigned short)pH245ConfIndData->u.Confirm.u.ConfOpen.AccRej); // rejection reason
} UnlockCall(pCall); } }
TxChannelOpenCallbackParams.hChannel = hChannel; TxChannelOpenCallbackParams.pPeerRTPAddr = pPeerRTPAddr; TxChannelOpenCallbackParams.pPeerRTCPAddr = pPeerRTCPAddr; TxChannelOpenCallbackParams.dwUserToken = pChannel->dwUserToken;
if (bAccept) { status = CC_OK; TxChannelOpenCallbackParams.dwRejectReason = H245_ACC; } else { // bAccept = FALSE
if (pH245ConfIndData->u.Confirm.Error == H245_ERROR_OK) status = CC_PEER_REJECT; else status = pH245ConfIndData->u.Confirm.Error; TxChannelOpenCallbackParams.dwRejectReason = pH245ConfIndData->u.Confirm.u.ConfOpen.AccRej; }
if ((pChannel->bCallbackInvoked == FALSE) && ((pChannel->bChannelType == TX_CHANNEL) || ((pChannel->bChannelType == TXRX_CHANNEL) && (pChannel->bLocallyOpened == TRUE)))) { pChannel->bCallbackInvoked = TRUE;
InvokeUserConferenceCallback(pConference, CC_TX_CHANNEL_OPEN_INDICATION, status, &TxChannelOpenCallbackParams); }
if (ValidateChannel(hChannel) == CC_OK) if (bAccept) UnlockChannel(pChannel); else FreeChannel(pChannel); } else UnlockChannel(pChannel);
if (ValidateConference(hConference) == CC_OK) UnlockConference(pConference); return H245_ERROR_OK; }
HRESULT _ConfClose( H245_CONF_IND_T *pH245ConfIndData) {
CC_HCALL hCall; CC_HCHANNEL hChannel; PCHANNEL pChannel; CC_HCONFERENCE hConference; PCONFERENCE pConference; PCALL pCall; H245_ACC_REJ_T AccRej;
hCall = pH245ConfIndData->u.Confirm.dwPreserved; if (LockCallAndConference(hCall, &pCall, &pConference) != CC_OK) return H245_ERROR_OK;
hConference = pCall->hConference; UnlockCall(pCall);
if (pH245ConfIndData->u.Confirm.Error != H245_ERROR_OK) { // TBD - Report error to Call Control client
// but wait! CC_CloseChannel() is a synchronous API! Until/unless that
// changes, the buck stops here.
if (FindChannelInConference(pH245ConfIndData->u.Confirm.u.ConfReqClose.Channel, TRUE, // local channel number
TX_CHANNEL | PROXY_CHANNEL, hCall, &hChannel, pConference) != CC_OK) { UnlockConference(pConference); return H245_ERROR_OK; } if (LockChannel(hChannel, &pChannel) != CC_OK) { UnlockConference(pConference); return H245_ERROR_OK; } // NOTE STOPGAP MEASURE : short term intentional "leak" of channel number.
// The channel number is actually a bit in a per-conference bitmap, so there
// is no real memory leak.
// This case is rare. The most likely error that leads here is a timeout.
// Calling FreeChannel() will normally recycle the logical channel
// number, and a new channel could reuse this number very quickly. If the error
// is a timeout, chances are that a late CloseLogicalChannelAck is on its
// way up the wire. We don't want that late CloseLogicalChannelAck to be
// associated with a completely new unrelated channel.
// set channel number to zero so that FreeChannel() does not recycle the number
pChannel->wLocalChannelNumber = 0;
FreeChannel(pChannel); UnlockConference(pConference);
} else { if(pH245ConfIndData->u.Confirm.u.ConfClose.AccRej == H245_ACC) { if (FindChannelInConference(pH245ConfIndData->u.Confirm.u.ConfReqClose.Channel, TRUE, // local channel number
TX_CHANNEL | PROXY_CHANNEL, hCall, &hChannel, pConference) != CC_OK) { UnlockConference(pConference); return H245_ERROR_OK; } if (LockChannel(hChannel, &pChannel) != CC_OK) { UnlockConference(pConference); return H245_ERROR_OK; } FreeChannel(pChannel); UnlockConference(pConference); } else { // At the time the ASSERT(0) was added here, the path that leads here
// always set pH245ConfIndData->u.Confirm.u.ConfClose.AccRej = H245_ACC
// at the same point it set ConfInd.u.Confirm.Error = H245_ERROR_OK;
// if that is ever changed, this also needs to change.
// see ..\h245\src\api_up.c, function H245FsmConfirm(), case H245_CONF_CLOSE:
ASSERT(0); }
} return H245_ERROR_OK; }
HRESULT _ConfRequestClose( H245_CONF_IND_T *pH245ConfIndData) { CC_HCALL hCall; CC_HCHANNEL hChannel; PCHANNEL pChannel; CC_HCONFERENCE hConference; PCONFERENCE pConference; PCALL pCall; H245_ACC_REJ_T AccRej;
hCall = pH245ConfIndData->u.Confirm.dwPreserved; if (LockCallAndConference(hCall, &pCall, &pConference) != CC_OK) return H245_ERROR_OK;
hConference = pCall->hConference; UnlockCall(pCall);
if (pH245ConfIndData->u.Confirm.Error == H245_ERROR_OK) AccRej = pH245ConfIndData->u.Confirm.u.ConfReqClose.AccRej; else AccRej = H245_REJ;
// Note: the only time we need to take any real action is when the channel
// is a proxy channel, and the local endpoint is not the one which requested
// the channel closure; in this case, we simply forward the closure response
// on to the endpoint which initiated the request.
// If the channel is an RX or TXRX channel, the channel object was deleted
// when our client requested the channel closure, so there's no real work to
// be done.
// If the channel is a proxy channel which our client requested be closed,
// the channel object will remain around until closed by the TX side, but we
// don't need (nor do we have a mechanism) to inform our client of receipt
// of this channel closure response.
if (FindChannelInConference(pH245ConfIndData->u.Confirm.u.ConfReqClose.Channel, FALSE, // remote channel number
PROXY_CHANNEL, hCall, &hChannel, pConference) != CC_OK) { UnlockConference(pConference); return H245_ERROR_OK; }
// Set hCall to the peer which initiated the close channel request
hCall = pH245ConfIndData->u.Confirm.dwTransId; if (hCall == CC_INVALID_HANDLE) { // The local endpoint was the one who requested the channel closure,
// so there's no one to forwards this response onto. We don't provide
// a callback for informing our client of receipt of this response,
// so we can simply clean up and return
UnlockConference(pConference); return H245_ERROR_OK; }
if (LockChannel(hChannel, &pChannel) != CC_OK) { UnlockConference(pConference); return H245_ERROR_OK; }
// Forward this response onto the endpoint which requested the channel closure
if (LockCall(hCall, &pCall) == CC_OK) { H245CloseChannelReqResp(pCall->H245Instance, AccRej, pChannel->wLocalChannelNumber); UnlockCall(pCall); }
UnlockChannel(pChannel); UnlockConference(pConference); return H245_ERROR_OK; }
#if 0
HRESULT _ConfShutdown( H245_CONF_IND_T *pH245ConfIndData) { CC_HCALL hCall; PCALL pCall; CC_HCONFERENCE hConference; PCONFERENCE pConference; HRESULT status; HQ931CALL hQ931Call; H245_INST_T H245Instance;
#if 1
// Sync 2 - specific code
hCall = pH245ConfIndData->u.Confirm.dwPreserved; if (LockCallAndConference(hCall, &pCall, &pConference) != CC_OK) return H245_ERROR_OK;
hConference = pCall->hConference;
if (pConference->tsMultipointController == TS_TRUE) { // XXX -- invoke user callback with "peer drop indication"
} else { H245Instance = pCall->H245Instance; hQ931Call = pCall->hQ931Call; FreeCall(pCall);
if (H245Instance != H245_INVALID_ID) status = H245ShutDown(H245Instance); else status = H245_ERROR_OK;
if (status == H245_ERROR_OK) { status = Q931Hangup(hQ931Call, CC_REJECT_UNDEFINED_REASON); // Q931Hangup may legitimately return CS_BAD_PARAM, because the Q.931 call object
// may have been deleted at this point
if (status == CS_BAD_PARAM) status = CC_OK; } else Q931Hangup(hQ931Call, CC_REJECT_UNDEFINED_REASON);
InvokeUserConferenceCallback(pConference, CC_CONFERENCE_TERMINATION_INDICATION, status, NULL);
if (ValidateConference(hConference) == CC_OK) UnlockConference(pConference);
return H245_ERROR_OK; } #else
// Probably sync 3 code
HHANGUP hHangup; PHANGUP pHangup; CC_HANGUP_CALLBACK_PARAMS HangupCallbackParams;
hHangup = pH245ConfIndData->u.Confirm.dwTransId; if (hHangup == CC_INVALID_HANDLE) return H245_ERROR_OK;
if (LockHangup(hHangup, &pHangup) != CC_OK) return H245_ERROR_OK;
pHangup->wNumCalls--; if (pHangup->wNumCalls == 0) { hConference = pHangup->hConference; if (LockConference(hConference, &pConference) != CC_OK) { UnlockHangup(pHangup); return H245_ERROR_OK; } HangupCallbackParams.dwUserToken = pHangup->dwUserToken; InvokeUserConferenceCallback(pConference->ConferenceCallback, CC_HANGUP_INDICATION, CC_OK, hConference, pConference->dwConferenceToken, &HangupCallbackParams); if (ValidateConference(hConference) == CC_OK) UnlockConference(pConference); if (ValidateHangup(hHangup) == CC_OK) FreeHangup(pHangup); return H245_ERROR_OK; } else UnlockHangup(pHangup); return H245_ERROR_OK; #endif // Sync 3 code
}
#endif
HRESULT _ConfInitMstslv( H245_CONF_IND_T *pH245ConfIndData) { CC_HCALL hCall; PCALL pCall; PCONFERENCE pConference; CC_CONNECT_CALLBACK_PARAMS ConnectCallbackParams; CC_HCALL hEnqueuedCall; PCALL pEnqueuedCall; CC_HCONFERENCE hConference; HRESULT status;
hCall = pH245ConfIndData->u.Confirm.dwPreserved; if (LockCallAndConference(hCall, &pCall, &pConference) != CC_OK) return H245_ERROR_OK;
ASSERT(pCall->MasterSlaveState != MASTER_SLAVE_COMPLETE);
switch (pH245ConfIndData->u.Confirm.u.ConfMstSlv) { case H245_MASTER: pConference->tsMaster = TS_TRUE; if (pConference->tsMultipointController == TS_UNKNOWN) { ASSERT(pConference->bMultipointCapable == TRUE); pConference->tsMultipointController = TS_TRUE;
// place all calls enqueued on this conference object
for ( ; ; ) { // Start up all enqueued calls, if any exist
status = RemoveEnqueuedCallFromConference(pConference, &hEnqueuedCall); if ((status != CC_OK) || (hEnqueuedCall == CC_INVALID_HANDLE)) break;
status = LockCall(hEnqueuedCall, &pEnqueuedCall); if (status == CC_OK) { pEnqueuedCall->CallState = PLACED;
status = PlaceCall(pEnqueuedCall, pConference); UnlockCall(pEnqueuedCall); } } } break;
case H245_SLAVE: ASSERT(pConference->tsMaster != TS_TRUE); ASSERT(pConference->tsMultipointController != TS_TRUE); pConference->tsMaster = TS_FALSE; pConference->tsMultipointController = TS_FALSE;
// XXX -- we may eventually want to re-enqueue these requests
// and set an expiration timer
hConference = pConference->hConference; for ( ; ; ) { status = RemoveEnqueuedCallFromConference(pConference, &hEnqueuedCall); if ((status != CC_OK) || (hEnqueuedCall == CC_INVALID_HANDLE)) break;
status = LockCall(hEnqueuedCall, &pEnqueuedCall); if (status == CC_OK) { MarkCallForDeletion(pEnqueuedCall); ConnectCallbackParams.pNonStandardData = pEnqueuedCall->pPeerNonStandardData; ConnectCallbackParams.pszPeerDisplay = pEnqueuedCall->pszPeerDisplay; ConnectCallbackParams.bRejectReason = CC_REJECT_UNDEFINED_REASON; ConnectCallbackParams.pTermCapList = pEnqueuedCall->pPeerH245TermCapList; ConnectCallbackParams.pH2250MuxCapability = pEnqueuedCall->pPeerH245H2250MuxCapability; ConnectCallbackParams.pTermCapDescriptors = pEnqueuedCall->pPeerH245TermCapDescriptors; ConnectCallbackParams.pLocalAddr = pEnqueuedCall->pQ931LocalConnectAddr; if (pEnqueuedCall->pQ931DestinationAddr == NULL) ConnectCallbackParams.pPeerAddr = pEnqueuedCall->pQ931PeerConnectAddr; else ConnectCallbackParams.pPeerAddr = pEnqueuedCall->pQ931DestinationAddr; ConnectCallbackParams.pVendorInfo = pEnqueuedCall->pPeerVendorInfo; ConnectCallbackParams.bMultipointConference = TRUE; ConnectCallbackParams.pConferenceID = &pConference->ConferenceID; ConnectCallbackParams.pMCAddress = pConference->pMultipointControllerAddr; ConnectCallbackParams.pAlternateAddress = NULL; ConnectCallbackParams.dwUserToken = pEnqueuedCall->dwUserToken;
InvokeUserConferenceCallback(pConference, CC_CONNECT_INDICATION, CC_NOT_MULTIPOINT_CAPABLE, &ConnectCallbackParams); if (ValidateCallMarkedForDeletion(hEnqueuedCall) == CC_OK) FreeCall(pEnqueuedCall); if (ValidateConference(hConference) != CC_OK) { if (ValidateCall(hCall) == CC_OK) UnlockCall(pCall); return H245_ERROR_OK; } } } break;
default: // H245_INDETERMINATE
UnlockConference(pConference); if (++pCall->wMasterSlaveRetry < MASTER_SLAVE_RETRY_MAX) { H245InitMasterSlave(pCall->H245Instance, pCall->H245Instance); UnlockCall(pCall); } else { UnlockCall(pCall); ProcessRemoteHangup(hCall, CC_INVALID_HANDLE, CC_REJECT_UNDEFINED_REASON); } return H245_ERROR_OK; } // switch
pCall->MasterSlaveState = MASTER_SLAVE_COMPLETE;
if ((pCall->OutgoingTermCapState == TERMCAP_COMPLETE) && (pCall->IncomingTermCapState == TERMCAP_COMPLETE) && (pCall->CallState == TERMCAP) && (pCall->MasterSlaveState == MASTER_SLAVE_COMPLETE)) { // Note that _ProcessConnectionComplete() returns with pConference and pCall unlocked
_ProcessConnectionComplete(pConference, pCall); return H245_ERROR_OK; }
UnlockCall(pCall); UnlockConference(pConference); return H245_ERROR_OK; }
HRESULT _ConfSendTermCap( H245_CONF_IND_T *pH245ConfIndData) { CC_HCALL hCall; PCALL pCall; HRESULT status; PCONFERENCE pConference;
// A TerminalCapabilitySet message was successfully sent from this endpoint
hCall = pH245ConfIndData->u.Confirm.dwPreserved; status = LockCallAndConference(hCall, &pCall, &pConference); if (status != CC_OK) { // This may be OK, if the call was cancelled while
// call setup was in progress.
return H245_ERROR_OK; }
if (pH245ConfIndData->u.Confirm.Error == H245_ERROR_OK && pH245ConfIndData->u.Confirm.u.ConfSndTcap.AccRej == H245_ACC) { pCall->OutgoingTermCapState = TERMCAP_COMPLETE; if ((pCall->IncomingTermCapState == TERMCAP_COMPLETE) && (pCall->CallState == TERMCAP) && (pCall->MasterSlaveState == MASTER_SLAVE_COMPLETE)) { // Note that _ProcessConnectionComplete() returns with pConference and pCall unlocked
_ProcessConnectionComplete(pConference, pCall); return H245_ERROR_OK; } } else if (pCall->CallState == TERMCAP) { // Report error to Call Control client
UnlockConference(pConference); UnlockCall(pCall); ProcessRemoteHangup(hCall, CC_INVALID_HANDLE, CC_REJECT_UNDEFINED_REASON); return H245_ERROR_OK; }
UnlockConference(pConference); UnlockCall(pCall); return H245_ERROR_OK; }
HRESULT _ConfRequestMode( H245_CONF_IND_T *pH245ConfIndData) { HRESULT status; CC_HCALL hCall; PCALL pCall; CC_HCONFERENCE hConference; PCONFERENCE pConference; CC_REQUEST_MODE_RESPONSE_CALLBACK_PARAMS RequestModeResponseCallbackParams;
hCall = pH245ConfIndData->u.Confirm.dwPreserved; status = LockCallAndConference(hCall, &pCall, &pConference); if (status != CC_OK) { // This may be OK, if the call was cancelled while
// call setup was in progress.
return H245_ERROR_OK; } hConference = pConference->hConference;
RequestModeResponseCallbackParams.hCall = hCall; if (pCall->pPeerParticipantInfo == NULL) { RequestModeResponseCallbackParams.TerminalLabel.bMCUNumber = 255; RequestModeResponseCallbackParams.TerminalLabel.bTerminalNumber = 255; } else RequestModeResponseCallbackParams.TerminalLabel = pCall->pPeerParticipantInfo->ParticipantInfo.TerminalLabel; switch (pH245ConfIndData->u.Confirm.u.ConfMrse) { case wllTrnsmtMstPrfrrdMd_chosen: RequestModeResponseCallbackParams.RequestModeResponse = CC_WILL_TRANSMIT_PREFERRED_MODE; break; case wllTrnsmtLssPrfrrdMd_chosen: RequestModeResponseCallbackParams.RequestModeResponse = CC_WILL_TRANSMIT_LESS_PREFERRED_MODE; break; default: RequestModeResponseCallbackParams.RequestModeResponse = CC_REQUEST_DENIED; break; } InvokeUserConferenceCallback(pConference, CC_REQUEST_MODE_RESPONSE_INDICATION, pH245ConfIndData->u.Confirm.Error, &RequestModeResponseCallbackParams); if (ValidateCall(hCall) == CC_OK) UnlockCall(pCall); if (ValidateConference(hConference) == CC_OK) UnlockConference(pConference); return H245_ERROR_OK; }
HRESULT _ConfRequestModeReject( H245_CONF_IND_T *pH245ConfIndData) { HRESULT status; CC_HCALL hCall; PCALL pCall; CC_HCONFERENCE hConference; PCONFERENCE pConference; CC_REQUEST_MODE_RESPONSE_CALLBACK_PARAMS RequestModeResponseCallbackParams;
hCall = pH245ConfIndData->u.Confirm.dwPreserved; status = LockCallAndConference(hCall, &pCall, &pConference); if (status != CC_OK) { // This may be OK, if the call was cancelled while
// call setup was in progress.
return H245_ERROR_OK; } hConference = pConference->hConference;
RequestModeResponseCallbackParams.hCall = hCall; if (pCall->pPeerParticipantInfo == NULL) { RequestModeResponseCallbackParams.TerminalLabel.bMCUNumber = 255; RequestModeResponseCallbackParams.TerminalLabel.bTerminalNumber = 255; } else RequestModeResponseCallbackParams.TerminalLabel = pCall->pPeerParticipantInfo->ParticipantInfo.TerminalLabel; switch (pH245ConfIndData->u.Confirm.u.ConfMrseReject) { case H245_REJ_UNAVAILABLE: RequestModeResponseCallbackParams.RequestModeResponse = CC_MODE_UNAVAILABLE; break; case H245_REJ_MULTIPOINT: RequestModeResponseCallbackParams.RequestModeResponse = CC_MULTIPOINT_CONSTRAINT; break; case H245_REJ_DENIED: RequestModeResponseCallbackParams.RequestModeResponse = CC_REQUEST_DENIED; break; default: RequestModeResponseCallbackParams.RequestModeResponse = CC_REQUEST_DENIED; break; } InvokeUserConferenceCallback(pConference, CC_REQUEST_MODE_RESPONSE_INDICATION, pH245ConfIndData->u.Confirm.Error, &RequestModeResponseCallbackParams); if (ValidateCall(hCall) == CC_OK) UnlockCall(pCall); if (ValidateConference(hConference) == CC_OK) UnlockConference(pConference); return H245_ERROR_OK; }
HRESULT _ConfRequestModeExpired( H245_CONF_IND_T *pH245ConfIndData) { HRESULT status; CC_HCALL hCall; PCALL pCall; CC_HCONFERENCE hConference; PCONFERENCE pConference; CC_REQUEST_MODE_RESPONSE_CALLBACK_PARAMS RequestModeResponseCallbackParams;
hCall = pH245ConfIndData->u.Confirm.dwPreserved; status = LockCallAndConference(hCall, &pCall, &pConference); if (status != CC_OK) { // This may be OK, if the call was cancelled while
// call setup was in progress.
return H245_ERROR_OK; } hConference = pConference->hConference;
RequestModeResponseCallbackParams.hCall = hCall; if (pCall->pPeerParticipantInfo == NULL) { RequestModeResponseCallbackParams.TerminalLabel.bMCUNumber = 255; RequestModeResponseCallbackParams.TerminalLabel.bTerminalNumber = 255; } else RequestModeResponseCallbackParams.TerminalLabel = pCall->pPeerParticipantInfo->ParticipantInfo.TerminalLabel; RequestModeResponseCallbackParams.RequestModeResponse = CC_REQUEST_DENIED; InvokeUserConferenceCallback(pConference, CC_REQUEST_MODE_RESPONSE_INDICATION, pH245ConfIndData->u.Confirm.Error, &RequestModeResponseCallbackParams); if (ValidateCall(hCall) == CC_OK) UnlockCall(pCall); if (ValidateConference(hConference) == CC_OK) UnlockConference(pConference); return H245_ERROR_OK; }
HRESULT _ConfRoundTrip( H245_CONF_IND_T *pH245ConfIndData) { CC_HCALL hCall; PCALL pCall; CC_HCONFERENCE hConference; PCONFERENCE pConference; HRESULT status; CC_PING_RESPONSE_CALLBACK_PARAMS PingCallbackParams;
hCall = pH245ConfIndData->u.Confirm.dwPreserved; status = LockCallAndConference(hCall, &pCall, &pConference); if (status != CC_OK) { // This may be OK, if the call was cancelled while
// call setup was in progress.
return H245_ERROR_OK; } hConference = pConference->hConference;
PingCallbackParams.hCall = hCall; if (pCall->pPeerParticipantInfo == NULL) { PingCallbackParams.TerminalLabel.bMCUNumber = 255; PingCallbackParams.TerminalLabel.bTerminalNumber = 255; } else PingCallbackParams.TerminalLabel = pCall->pPeerParticipantInfo->ParticipantInfo.TerminalLabel; PingCallbackParams.bResponse = TRUE; InvokeUserConferenceCallback(pConference, CC_PING_RESPONSE_INDICATION, pH245ConfIndData->u.Confirm.Error, &PingCallbackParams); if (ValidateCall(hCall) == CC_OK) UnlockCall(pCall); if (ValidateConference(hConference) == CC_OK) UnlockConference(pConference); return H245_ERROR_OK; }
HRESULT _ConfRoundTripExpired( H245_CONF_IND_T *pH245ConfIndData) { CC_HCALL hCall; PCALL pCall; CC_HCONFERENCE hConference; PCONFERENCE pConference; HRESULT status; CC_PING_RESPONSE_CALLBACK_PARAMS PingCallbackParams;
hCall = pH245ConfIndData->u.Confirm.dwPreserved; status = LockCallAndConference(hCall, &pCall, &pConference); if (status != CC_OK) { // This may be OK, if the call was cancelled while
// call setup was in progress.
return H245_ERROR_OK; } hConference = pConference->hConference;
PingCallbackParams.hCall = hCall; if (pCall->pPeerParticipantInfo == NULL) { PingCallbackParams.TerminalLabel.bMCUNumber = 255; PingCallbackParams.TerminalLabel.bTerminalNumber = 255; } else PingCallbackParams.TerminalLabel = pCall->pPeerParticipantInfo->ParticipantInfo.TerminalLabel; PingCallbackParams.bResponse = FALSE; InvokeUserConferenceCallback(pConference, CC_PING_RESPONSE_INDICATION, pH245ConfIndData->u.Confirm.Error, &PingCallbackParams); if (ValidateCall(hCall) == CC_OK) UnlockCall(pCall); if (ValidateConference(hConference) == CC_OK) UnlockConference(pConference); return H245_ERROR_OK; }
HRESULT H245Callback( H245_CONF_IND_T *pH245ConfIndData, void *pMisc) { HRESULT status = H245_ERROR_OK;
EnterCallControl();
if (CallControlState != OPERATIONAL_STATE) HResultLeaveCallControl(H245_ERROR_OK);
if (pH245ConfIndData == NULL) HResultLeaveCallControl(H245_ERROR_OK);
if (pH245ConfIndData->Kind == H245_CONF) { switch (pH245ConfIndData->u.Confirm.Confirm) { case H245_CONF_INIT_MSTSLV: status = _ConfInitMstslv(pH245ConfIndData); break;
case H245_CONF_SEND_TERMCAP: status = _ConfSendTermCap(pH245ConfIndData); break;
case H245_CONF_OPEN: status = _ConfOpen(pH245ConfIndData); break;
case H245_CONF_NEEDRSP_OPEN: status = _ConfBiDirectionalOpen(pH245ConfIndData); break;
case H245_CONF_CLOSE: status = _ConfClose(pH245ConfIndData); break;
case H245_CONF_REQ_CLOSE: status = _ConfRequestClose(pH245ConfIndData); break;
// case H245_CONF_MUXTBL_SND: not valid for H.323 MuliplexEntrySend
// case H245_CONF_RMESE: not valid for H.323 RequestMultiplexEntry
// case H245_CONF_RMESE_REJECT: not valid for H.323 RequestMultiplexEntryReject
// case H245_CONF_RMESE_EXPIRED: not valid for H.323
case H245_CONF_MRSE: status = _ConfRequestMode(pH245ConfIndData); break;
case H245_CONF_MRSE_REJECT: status = _ConfRequestModeReject(pH245ConfIndData); break;
case H245_CONF_MRSE_EXPIRED: status = _ConfRequestModeExpired(pH245ConfIndData); break;
case H245_CONF_RTDSE: status = _ConfRoundTrip(pH245ConfIndData); break;
case H245_CONF_RTDSE_EXPIRED: status = _ConfRoundTripExpired(pH245ConfIndData); break;
default: status = _ConfUnimplemented(pH245ConfIndData); break; } } else if (pH245ConfIndData->Kind == H245_IND) { switch (pH245ConfIndData->u.Indication.Indicator) { case H245_IND_MSTSLV: status = _IndMstslv(pH245ConfIndData); break;
case H245_IND_CAP: status = _IndCapability(pH245ConfIndData); break;
case H245_IND_CESE_RELEASE: // Remote has abandoned TerminalCapabilitySet
// No longer need to send TerminalCapabilitySetAck
// We can probably get away with ignoring this,
// but we should NOT return FunctionNotSupported!
break;
case H245_IND_OPEN: status = _IndOpen(pH245ConfIndData); break;
case H245_IND_OPEN_CONF: // Bi-directionl channel open complete
status = _IndOpenConf(pH245ConfIndData); break;
case H245_IND_CLOSE: status = _IndClose(pH245ConfIndData); break;
case H245_IND_REQ_CLOSE: status = _IndRequestClose(pH245ConfIndData); break;
case H245_IND_CLCSE_RELEASE: // Remote has abandoned RequestChannelClose
// No longer need to send RequestChannelCloseAck and CloseLogicalChannel
// We can probably get away with ignoring this,
// but we should NOT return FunctionNotSupported!
break;
// case H245_IND_MUX_TBL: not valid in H.323 MuliplexEntrySend
// case H245_IND_MTSE_RELEASE not valid in H.323 MuliplexEntrySendRelease
// case H245_IND_RMESE not valid in H.323 RequestMuliplexEntry
// case H245_IND_RMESE_RELEASE not valid in H.323 RequestMuliplexEntryRelease
case H245_IND_MRSE: status = _IndModeRequest(pH245ConfIndData); break;
case H245_IND_MRSE_RELEASE: // Remote has abandoned RequestMode
// No longer need to send RequestModeAck or RequestModeReject
// We can probably get away with ignoring this,
// but we should NOT return FunctionNotSupported!
break;
// case H245_IND_MLSE: We don't support looping back data
case H245_IND_MLSE_RELEASE: // Required to accept this message
break;
case H245_IND_NONSTANDARD_REQUEST: case H245_IND_NONSTANDARD_RESPONSE: case H245_IND_NONSTANDARD_COMMAND: case H245_IND_NONSTANDARD: status = _IndNonStandard(pH245ConfIndData); break;
case H245_IND_MISC_COMMAND: status = _IndMiscellaneousCommand(pH245ConfIndData, pMisc); break;
case H245_IND_MISC: status = _IndMiscellaneous(pH245ConfIndData, pMisc); break; case H245_IND_COMM_MODE_REQUEST: status = _IndUnimplemented(pH245ConfIndData); // TBD
break;
// case H245_IND_COMM_MODE_RESPONSE: We never send request!
case H245_IND_COMM_MODE_COMMAND: status = _IndCommunicationModeCommand(pH245ConfIndData); break;
case H245_IND_CONFERENCE_REQUEST: status = _IndConferenceRequest(pH245ConfIndData); break;
case H245_IND_CONFERENCE_RESPONSE: status = _IndConferenceResponse(pH245ConfIndData); break;
case H245_IND_CONFERENCE_COMMAND: status = _IndConferenceCommand(pH245ConfIndData); break;
case H245_IND_CONFERENCE: status = _IndConference(pH245ConfIndData); break; case H245_IND_SEND_TERMCAP: status = _IndSendTerminalCapabilitySet(pH245ConfIndData); break;
// case H245_IND_ENCRYPTION: Not valid in H.323
case H245_IND_FLOW_CONTROL: status = _IndFlowControl(pH245ConfIndData); break;
case H245_IND_ENDSESSION: status = _IndEndSession(pH245ConfIndData); break;
case H245_IND_FUNCTION_NOT_UNDERSTOOD: // We don't do anything with this but we still want to
// return H245_ERROR_OK so H.245 does not sent
// FunctionNotSupported back to remote peer!
break;
case H245_IND_JITTER: // It is ok to ignore this; no response is expected
break;
// case H245_IND_H223_SKEW: Not valid in H.323
// case H245_IND_NEW_ATM_VC: Not valid in H.323
case H245_IND_USERINPUT: status = _IndUserInput(pH245ConfIndData); break;
case H245_IND_H2250_MAX_SKEW: status = _IndH2250MaximumSkew(pH245ConfIndData); break;
case H245_IND_MC_LOCATION: status = _IndMCLocation(pH245ConfIndData); break;
case H245_IND_VENDOR_ID: status = _IndVendorIdentification(pH245ConfIndData, pMisc); break;
case H245_IND_FUNCTION_NOT_SUPPORTED: // We don't do anything with this but we still want to
// return H245_ERROR_OK so H.245 does not sent
// FunctionNotSupported back to remote peer!
break;
// case H245_IND_H223_RECONFIG: Not valid in H.323
// case H245_IND_H223_RECONFIG_ACK: Not valid in H.323
// case H245_IND_H223_RECONFIG_REJECT: Not valid in H.323
default: status = _IndUnimplemented(pH245ConfIndData); break; } } HResultLeaveCallControl(status); }
|