You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
5097 lines
182 KiB
5097 lines
182 KiB
/****************************************************************************
|
|
*
|
|
* $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);
|
|
}
|
|
|