windows-nt/Source/XPSP1/NT/net/tapi/skywalker/cc/callcont/callcont.c
2020-09-26 16:20:57 +08:00

4211 lines
120 KiB
C

/****************************************************************************
*
* $Archive: S:/STURGEON/SRC/CALLCONT/VCS/callcont.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.208.1.6 $
* $Date: 30 Jun 1997 18:21:36 $
* $Author: MANDREWS $
*
* Deliverable:
*
* Abstract:
*
*
* Notes:
*
***************************************************************************/
#define CALL_CONTROL_EXPORT
#pragma warning ( disable : 4057 4100 4115 4201 4214)
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <windows.h>
#pragma warning ( default : 4115 4201 4214)
#include "apierror.h"
#include "incommon.h"
#include "callcont.h"
#ifdef FORCE_SERIALIZE_CALL_CONTROL
#include "cclock.h"
#endif // FORCE_SERIALIZE_CALL_CONTROL
#include "q931.h"
#include "ccmain.h"
#include "confman.h"
#include "listman.h"
#include "q931man.h"
#include "h245man.h"
#include "callman.h"
#include "userman.h"
#include "chanman.h"
#include "hangman.h"
#include "linkapi.h"
#include "h245api.h"
#include "ccutils.h"
#ifdef GATEKEEPER
HRESULT InitGkiManager(void);
void DeInitGkiManager(void);
#define GKI_MAX_BANDWIDTH (0xFFFFFFFF / 100)
#endif // GATEKEEPER
CALL_CONTROL_STATE CallControlState = INITIALIZING_STATE;
BOOL bISDMLoaded = FALSE;
static HRESULT InitStatus;
// NumThreads counts the number of threads which are executing code within this DLL.
// NumThreads must be incremented at each DLL entry point (which includes each API
// call, the Q931 callback location and the H245 callback location).
// NumThreads must be decremented upon DLL exit. The macro LeaveCallControlTop()
// is used to facilitate this operation. Note that LeaveCallControlTop may accept
// a function call as a parameter; we must call the function first, save its return
// value, then decrement NumThreads, and finally return the saved value.
THREADCOUNT ThreadCount;
HINSTANCE ghCallControlInstance;
extern CC_CONFERENCEID InvalidConferenceID;
#define _Unicode(x) L ## x
#define Unicode(x) _Unicode(x)
WORD ADDRToInetPort(CC_ADDR *pAddr);
DWORD ADDRToInetAddr(CC_ADDR *pAddr);
BOOL WINAPI CCDllMain( HINSTANCE hInstDll,
DWORD fdwReason,
LPVOID lpvReserved)
{
switch (fdwReason) {
case DLL_PROCESS_ATTACH:
// The DLL is being mapped into the process's address space
ASSERT(CallControlState == INITIALIZING_STATE);
ASSERT(CC_OK == CS_OK);
ASSERT(CC_OK == H245_ERROR_OK);
InitializeLock(&ThreadCount.Lock);
ThreadCount.wNumThreads = 0;
ghCallControlInstance = hInstDll;
#ifdef GATEKEEPER
InitStatus = InitGkiManager();
if (InitStatus != CC_OK)
break;
#endif // GATEKEEPER
// create Q.931 ASN.1 global structure
InitStatus = Q931InitPER();
if (InitStatus != CC_OK)
break;
// create H.245 ASN.1 global structure
if (H245_InitModule() != ASN1_SUCCESS) {
InitStatus = CC_NO_MEMORY;
break;
}
InitStatus = InitConferenceManager();
if (InitStatus != CC_OK)
break;
InitStatus = InitCallManager();
if (InitStatus != CC_OK)
break;
InitStatus = InitChannelManager();
if (InitStatus != CC_OK)
break;
InitStatus = InitH245Manager();
if (InitStatus != CC_OK)
break;
InitStatus = InitListenManager();
if (InitStatus != CC_OK)
break;
InitStatus = InitQ931Manager();
if (InitStatus != CC_OK)
break;
InitStatus = InitUserManager();
if (InitStatus != CC_OK)
break;
InitStatus = InitHangupManager();
if (InitStatus != CC_OK)
break;
InitStatus = Q931Init();
if (InitStatus != CS_OK)
break;
CallControlState = OPERATIONAL_STATE;
break;
case DLL_THREAD_ATTACH:
// A thread is being created
break;
case DLL_THREAD_DETACH:
// A thread is exiting cleanly
break;
case DLL_PROCESS_DETACH:
// The DLL is being unmapped from the process's address space
CC_Shutdown();
// destroy ASN.1 global structures
H245_TermModule();
Q931DeInitPER();
DeleteLock(&ThreadCount.Lock);
break;
}
return TRUE;
}
CC_API
HRESULT CC_AcceptCall( CC_HCONFERENCE hConference,
PCC_NONSTANDARDDATA pNonStandardData,
PWSTR pszDisplay,
CC_HCALL hCall,
DWORD dwBandwidth,
DWORD dwUserToken)
{
HRESULT status;
PCALL pCall;
PCONFERENCE pConference;
HQ931CALL hQ931Call;
WORD wNumCalls;
CC_ADDR AlternateAddr;
PCC_ADDR pAlternateAddr;
BOOL bAccept = FALSE;
BYTE bRejectReason = CC_REJECT_UNDEFINED_REASON;
CC_CONFERENCEID ConferenceID;
EnterCallControlTop();
if (InitStatus != CC_OK)
LeaveCallControlTop(InitStatus);
if (CallControlState != OPERATIONAL_STATE)
LeaveCallControlTop(CC_INTERNAL_ERROR);
// validate parameters
if (hConference == CC_INVALID_HANDLE)
LeaveCallControlTop(CC_BAD_PARAM);
if (hCall == CC_INVALID_HANDLE)
LeaveCallControlTop(CC_BAD_PARAM);
status = ValidateNonStandardData(pNonStandardData);
if (status != CC_OK)
LeaveCallControlTop(status);
status = LockCall(hCall, &pCall);
if (status != CC_OK)
// note that we can't even tell Q931 to reject the call
LeaveCallControlTop(status);
if (pCall->CallState != INCOMING) {
UnlockCall(pCall);
LeaveCallControlTop(CC_BAD_PARAM);
}
ASSERT(pCall->hConference == CC_INVALID_HANDLE);
hQ931Call = pCall->hQ931Call;
ConferenceID = pCall->ConferenceID;
status = AddLocalNonStandardDataToCall(pCall, pNonStandardData);
if (status != CC_OK) {
FreeCall(pCall);
Q931RejectCall(hQ931Call, // Q931 call handle
CC_REJECT_UNDEFINED_REASON, // reject reason
&ConferenceID,
NULL, // alternate address
pNonStandardData); // non-standard data
LeaveCallControlTop(status);
}
status = AddLocalDisplayToCall(pCall, pszDisplay);
if (status != CC_OK) {
FreeCall(pCall);
Q931RejectCall(hQ931Call, // Q931 call handle
CC_REJECT_UNDEFINED_REASON, // reject reason
&ConferenceID,
NULL, // alternate address
pNonStandardData); // non-standard data
LeaveCallControlTop(status);
}
UnlockCall(pCall);
status = LockConferenceEx(hConference,
&pConference,
TS_FALSE); // bDeferredDelete
if (status == CC_OK) {
status = LockCall(hCall, &pCall);
if (status != CC_OK) {
UnlockConference(pConference);
LeaveCallControlTop(status);
}
} else
LeaveCallControlTop(status);
if ((pCall->bCallerIsMC == TRUE) &&
((pConference->tsMultipointController == TS_TRUE) ||
(pConference->bMultipointCapable == FALSE))) {
FreeCall(pCall);
UnlockConference(pConference);
Q931RejectCall(hQ931Call, // Q931 call handle
CC_REJECT_UNDEFINED_REASON, // reject reason
&ConferenceID,
NULL, // alternate address
pNonStandardData); // non-standard data
if (pConference->bMultipointCapable == FALSE) {
LeaveCallControlTop(CC_BAD_PARAM);
} else {
LeaveCallControlTop(CC_NOT_MULTIPOINT_CAPABLE);
}
}
EnumerateCallsInConference(&wNumCalls, NULL, pConference, REAL_CALLS);
if ((wNumCalls > 0) &&
(pConference->bMultipointCapable == FALSE)) {
FreeCall(pCall);
UnlockConference(pConference);
Q931RejectCall(hQ931Call, // Q931 call handle
CC_REJECT_UNDEFINED_REASON, // reject reason
&ConferenceID,
NULL, // alternate address
pNonStandardData); // non-standard data
LeaveCallControlTop(CC_NOT_MULTIPOINT_CAPABLE);
}
pAlternateAddr = NULL;
if (EqualConferenceIDs(&pCall->ConferenceID, &pConference->ConferenceID)) {
if (wNumCalls > 0) {
if (pConference->tsMultipointController == TS_TRUE) {
// Accept Call
status = CC_OK;
bAccept = TRUE;
} else { // we're not the MC
if (pConference->bMultipointCapable) {
if (pConference->pMultipointControllerAddr != NULL) {
// Reject Call - route to MC
status = CC_OK;
bAccept = FALSE;
bRejectReason = CC_REJECT_ROUTE_TO_MC;
AlternateAddr = *pConference->pMultipointControllerAddr;
pAlternateAddr = &AlternateAddr;
} else { // we don't have the MC's address
// XXX -- we may eventually want to enqueue the request
// and set an expiration timer
// Error - no MC
status = CC_NOT_MULTIPOINT_CAPABLE;
}
} else { // we're not multipoint capable
// Error - bad param
status = CC_BAD_PARAM;
}
}
} else { // wNumCalls == 0
// Accept Call
status = CC_OK;
bAccept = TRUE;
}
} else { // pCall->ConferenceID != pConference->ConferenceID
if (EqualConferenceIDs(&pConference->ConferenceID, &InvalidConferenceID)) {
// Accept Call
status = CC_OK;
bAccept = TRUE;
} else { // pConferenceID != InvalidConferenceID
if (pConference->tsMultipointController == TS_TRUE) {
// Reject Call - route to MC
status = CC_OK;
bAccept = FALSE;
bRejectReason = CC_REJECT_ROUTE_TO_MC;
pAlternateAddr = &AlternateAddr;
if (GetLastListenAddress(pAlternateAddr) != CC_OK) {
pAlternateAddr = NULL;
bRejectReason = CC_REJECT_UNDEFINED_REASON;
}
} else { // we're not the MC
if (pConference->bMultipointCapable) {
if (pConference->pMultipointControllerAddr) {
// Reject Call - route to MC
status = CC_OK;
bAccept = FALSE;
bRejectReason = CC_REJECT_ROUTE_TO_MC;
AlternateAddr = *pConference->pMultipointControllerAddr;
pAlternateAddr = &AlternateAddr;
} else { // we don't have the MC's address
// XXX -- we may eventually want to enqueue the request
// and set an expiration timer
// Error - no MC
status = CC_NOT_MULTIPOINT_CAPABLE;
}
} else { // we're not multipoint capable
// Error - bad param
status = CC_BAD_PARAM;
}
}
}
}
if (status != CC_OK) {
FreeCall(pCall);
UnlockConference(pConference);
LeaveCallControlTop(status);
}
if (bAccept) {
pCall->dwUserToken = dwUserToken;
#ifdef GATEKEEPER
pCall->hConference = hConference;
// Fill in Gatekeeper Call fields
memset(&pCall->GkiCall, 0, sizeof(pCall->GkiCall));
pCall->GkiCall.pCall = pCall;
pCall->GkiCall.hCall = hCall;
pCall->GkiCall.pConferenceId = pCall->ConferenceID.buffer;
pCall->GkiCall.bActiveMC = pCall->bCallerIsMC;
pCall->GkiCall.bAnswerCall = TRUE;
if (pCall->pSourceCallSignalAddr) {
pCall->GkiCall.dwSrcCallSignalIpAddress = ADDRToInetAddr(pCall->pSourceCallSignalAddr);
pCall->GkiCall.wSrcCallSignalPort = ADDRToInetPort(pCall->pSourceCallSignalAddr);
} else {
pCall->GkiCall.dwSrcCallSignalIpAddress = 0;
pCall->GkiCall.wSrcCallSignalPort = 0;
}
pCall->GkiCall.wSrcCallSignalPort =
(WORD)((pCall->GkiCall.wSrcCallSignalPort<<8)|(pCall->GkiCall.wSrcCallSignalPort>>8));
pCall->GkiCall.dwIpAddress = ADDRToInetAddr(pCall->pQ931PeerConnectAddr);
pCall->GkiCall.wPort = ADDRToInetPort(pCall->pQ931PeerConnectAddr);
pCall->GkiCall.wPort = (WORD)((pCall->GkiCall.wPort<<8)|(pCall->GkiCall.wPort>>8));
if (pConference->bMultipointCapable)
pCall->GkiCall.CallType = MANY_TO_MANY;
else
pCall->GkiCall.CallType = POINT_TO_POINT;
pCall->GkiCall.uBandwidthRequested = dwBandwidth / 100;
status = GkiOpenCall(&pCall->GkiCall, pConference);
// GkiOpenCall may or may not have called AcceptCall, which unlocks
// call and conference and may or may not free the call
if (ValidateCall(hCall) == CC_OK)
if (status == CC_OK)
UnlockCall(pCall);
else
FreeCall(pCall);
if (ValidateConference(hConference) == CC_OK)
UnlockConference(pConference);
if (status != CC_OK)
{
Q931RejectCall( hQ931Call, // Q931 call handle
CC_REJECT_GATEKEEPER_RESOURCES, // reject reason
&ConferenceID,
NULL, // alternate address
pNonStandardData); // non-standard data
}
#else // GATEKEEPER
status = AcceptCall(pCall, pConference);
#endif // GATEKEEPER
LeaveCallControlTop(status);
} else { // bAccept == FALSE
FreeCall(pCall);
if (bRejectReason == CC_REJECT_ROUTE_TO_MC) {
ASSERT(pAlternateAddr != NULL);
ConferenceID = pConference->ConferenceID;
} else
pAlternateAddr = NULL;
UnlockConference(pConference);
status = Q931RejectCall(hQ931Call, // Q931 call handle
bRejectReason, // reject reason
&ConferenceID,
pAlternateAddr, // alternate address
pNonStandardData); // non-standard data
LeaveCallControlTop(status);
}
}
CC_API
HRESULT CC_AcceptChannel( CC_HCHANNEL hChannel,
PCC_ADDR pRTPAddr,
PCC_ADDR pRTCPAddr,
DWORD dwBandwidth)
{
HRESULT status;
PCHANNEL pChannel;
PCONFERENCE pConference;
CC_HCALL hCall;
PCALL pCall;
#ifndef GATEKEEPER
H245_MUX_T H245MuxTable;
WORD i;
CC_ACCEPT_CHANNEL_CALLBACK_PARAMS Params;
CC_HCONFERENCE hConference;
#endif // !GATEKEEPER
EnterCallControlTop();
if (InitStatus != CC_OK)
LeaveCallControlTop(InitStatus);
if (CallControlState != OPERATIONAL_STATE)
LeaveCallControlTop(CC_INTERNAL_ERROR);
if (hChannel == CC_INVALID_HANDLE)
LeaveCallControlTop(CC_BAD_PARAM);
if (pRTCPAddr != NULL)
if ((pRTCPAddr->nAddrType != CC_IP_BINARY) ||
(pRTCPAddr->bMulticast == TRUE))
LeaveCallControlTop(CC_BAD_PARAM);
status = LockChannelAndConference(hChannel, &pChannel, &pConference);
if (status != CC_OK)
LeaveCallControlTop(status);
// Make sure that hChannel is a receive or proxy channel that
// hasn't already been accepted
if (((pChannel->bChannelType != RX_CHANNEL) &&
(pChannel->bChannelType != PROXY_CHANNEL)) ||
(pChannel->tsAccepted != TS_UNKNOWN)) {
UnlockChannel(pChannel);
UnlockConference(pConference);
LeaveCallControlTop(CC_BAD_PARAM);
}
if (pChannel->bMultipointChannel) {
if ((pRTPAddr != NULL) || (pRTCPAddr != NULL)) {
UnlockChannel(pChannel);
UnlockConference(pConference);
LeaveCallControlTop(CC_BAD_PARAM);
}
} else
if ((pRTPAddr == NULL) || (pRTCPAddr == NULL)) {
UnlockChannel(pChannel);
UnlockConference(pConference);
LeaveCallControlTop(CC_BAD_PARAM);
}
if (pConference->LocalEndpointAttached != ATTACHED) {
UnlockChannel(pChannel);
UnlockConference(pConference);
LeaveCallControlTop(CC_BAD_PARAM);
}
hCall = pChannel->hCall;
status = LockCall(hCall, &pCall);
if (status != CC_OK) {
UnlockChannel(pChannel);
UnlockConference(pConference);
LeaveCallControlTop(status);
}
if (pChannel->bMultipointChannel == FALSE) {
status = AddLocalAddrPairToChannel(pRTPAddr, pRTCPAddr, pChannel);
if (status != CC_OK) {
UnlockCall(pCall);
UnlockChannel(pChannel);
UnlockConference(pConference);
LeaveCallControlTop(status);
}
}
#ifdef GATEKEEPER
pChannel->dwBandwidth = dwBandwidth;
UnlockChannel(pChannel);
UnlockConference(pConference);
status = GkiOpenChannel(&pCall->GkiCall, dwBandwidth, hChannel, RX);
if (ValidateCall(hCall) == CC_OK)
UnlockCall(pCall);
#else // GATEKEEPER
if (pChannel->wNumOutstandingRequests != 0) {
if ((pChannel->bMultipointChannel) &&
(pConference->tsMultipointController == TS_TRUE)) {
// Supply the RTP and RTCP addresses in the OpenLogicalChannelAck
if (pConference->pSessionTable != NULL) {
for (i = 0; i < pConference->pSessionTable->wLength; i++) {
if (pConference->pSessionTable->SessionInfoArray[i].bSessionID ==
pChannel->bSessionID) {
pRTPAddr = pConference->pSessionTable->SessionInfoArray[i].pRTPAddr;
pRTCPAddr = pConference->pSessionTable->SessionInfoArray[i].pRTCPAddr;
break;
}
}
}
}
H245MuxTable.Kind = H245_H2250ACK;
H245MuxTable.u.H2250ACK.nonStandardList = NULL;
if (pRTPAddr != NULL) {
if (pRTPAddr->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 =
pRTPAddr->Addr.IP_Binary.wPort;
HostToH245IPNetwork(H245MuxTable.u.H2250ACK.mediaChannel.u.ip.network,
pRTPAddr->Addr.IP_Binary.dwAddr);
H245MuxTable.u.H2250ACK.mediaChannelPresent = TRUE;
} else
H245MuxTable.u.H2250ACK.mediaChannelPresent = FALSE;
if (pRTCPAddr != NULL) {
if (pRTCPAddr->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 =
pRTCPAddr->Addr.IP_Binary.wPort;
HostToH245IPNetwork(H245MuxTable.u.H2250ACK.mediaControlChannel.u.ip.network,
pRTCPAddr->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
pChannel->pSeparateStack);
if (status == CC_OK)
pChannel->wNumOutstandingRequests = 0;
else
--(pChannel->wNumOutstandingRequests);
}
pChannel->tsAccepted = TS_TRUE;
Params.hChannel = hChannel;
if (status == CC_OK)
UnlockChannel(pChannel);
else
FreeChannel(pChannel);
UnlockCall(pCall);
hConference = pConference->hConference;
InvokeUserConferenceCallback(pConference,
CC_ACCEPT_CHANNEL_INDICATION,
status,
&Params);
if (ValidateConference(hConference) == CC_OK)
UnlockConference(pConference);
#endif // GATEKEEPER
LeaveCallControlTop(status);
}
CC_API
HRESULT CC_AcceptT120Channel( CC_HCHANNEL hChannel,
BOOL bAssociateConference,
PCC_OCTETSTRING pExternalReference,
PCC_ADDR pAddr)
{
HRESULT status;
PCHANNEL pChannel;
PCALL pCall;
PCONFERENCE pConference;
H245_ACCESS_T SeparateStack;
H245_ACCESS_T *pSeparateStack;
H245_MUX_T H245MuxTable;
WORD i;
WORD wNumCalls;
PCC_HCALL CallList;
EnterCallControlTop();
if (InitStatus != CC_OK)
LeaveCallControlTop(InitStatus);
if (CallControlState != OPERATIONAL_STATE)
LeaveCallControlTop(CC_INTERNAL_ERROR);
if (hChannel == CC_INVALID_HANDLE)
LeaveCallControlTop(CC_BAD_PARAM);
if (pAddr != NULL)
if ((pAddr->nAddrType != CC_IP_BINARY) ||
(pAddr->bMulticast == TRUE))
LeaveCallControlTop(CC_BAD_PARAM);
status = LockChannelAndConference(hChannel, &pChannel, &pConference);
if (status != CC_OK)
LeaveCallControlTop(status);
// Make sure that hChannel is a bidirectional channel that was
// not opened locally and hasn't already been accepted or rejected
if ((pChannel->bChannelType != TXRX_CHANNEL) ||
(pChannel->tsAccepted != TS_UNKNOWN) ||
(pChannel->bLocallyOpened == TRUE)) {
UnlockChannel(pChannel);
UnlockConference(pConference);
LeaveCallControlTop(CC_BAD_PARAM);
}
// If the remote endpoint specified a channel address, it will
// be contained in the SeparateStack field, and we are not
// allowed to specify another address in pAddr;
// if the remote endpoint did not specify a channel address,
// we must specify one now
if (((pChannel->pSeparateStack == NULL) && (pAddr == NULL)) ||
((pChannel->pSeparateStack != NULL) && (pAddr != NULL))) {
UnlockChannel(pChannel);
UnlockConference(pConference);
LeaveCallControlTop(CC_BAD_PARAM);
}
if (pConference->LocalEndpointAttached != ATTACHED) {
UnlockChannel(pChannel);
UnlockConference(pConference);
LeaveCallControlTop(CC_BAD_PARAM);
}
// Add the SeparateStack field to the channel, if necessary
if (pAddr != NULL) {
SeparateStack.bit_mask = distribution_present;
SeparateStack.distribution.choice = unicast_chosen;
if (pExternalReference != NULL) {
SeparateStack.bit_mask |= externalReference_present;
SeparateStack.externalReference.length = pExternalReference->wOctetStringLength;
memcpy(SeparateStack.externalReference.value,
pExternalReference->pOctetString,
pExternalReference->wOctetStringLength);
}
SeparateStack.networkAddress.choice = localAreaAddress_chosen;
SeparateStack.networkAddress.u.localAreaAddress.choice = unicastAddress_chosen;
SeparateStack.networkAddress.u.localAreaAddress.u.unicastAddress.choice = UnicastAddress_iPAddress_chosen;
SeparateStack.networkAddress.u.localAreaAddress.u.unicastAddress.u.UnicastAddress_iPAddress.tsapIdentifier =
pAddr->Addr.IP_Binary.wPort;
SeparateStack.networkAddress.u.localAreaAddress.u.unicastAddress.u.UnicastAddress_iPAddress.network.length = 4;
HostToH245IPNetwork(SeparateStack.networkAddress.u.localAreaAddress.u.unicastAddress.u.UnicastAddress_iPAddress.network.value,
pAddr->Addr.IP_Binary.dwAddr);
SeparateStack.associateConference = (char) bAssociateConference;
pSeparateStack = &SeparateStack;
AddSeparateStackToChannel(pSeparateStack, pChannel);
} else
pSeparateStack = NULL;
// Send an ACK to the endpoint which requested the channel
status = LockCall(pChannel->hCall, &pCall);
if (status != CC_OK) {
UnlockChannel(pChannel);
UnlockConference(pConference);
LeaveCallControlTop(status);
}
H245MuxTable.Kind = H245_H2250ACK;
H245MuxTable.u.H2250ACK.nonStandardList = NULL;
H245MuxTable.u.H2250ACK.mediaChannelPresent = FALSE;
H245MuxTable.u.H2250ACK.mediaControlChannelPresent = FALSE;
H245MuxTable.u.H2250ACK.dynamicRTPPayloadTypePresent = FALSE;
H245MuxTable.u.H2250ACK.sessionIDPresent = FALSE;
status = H245OpenChannelAccept(pCall->H245Instance, // dwInst
0, // dwTransId
pChannel->wRemoteChannelNumber, // remote channel
&H245MuxTable, // Rx Mux
pChannel->wLocalChannelNumber, // local channel
NULL, // Tx mux
H245_INVALID_PORT_NUMBER,// Port
pSeparateStack);
if (status != CC_OK) {
FreeChannel(pChannel);
UnlockCall(pCall);
UnlockConference(pConference);
LeaveCallControlTop(status);
}
pChannel->tsAccepted = TS_TRUE;
--(pChannel->wNumOutstandingRequests);
UnlockCall(pCall);
// If we're the MC in a multipoint conference, forward the
// open T.120 channel request to all other endpoints in the conference
if ((pConference->ConferenceMode == MULTIPOINT_MODE) &&
(pConference->tsMultipointController == TS_TRUE)) {
EnumerateCallsInConference(&wNumCalls, &CallList, pConference, ESTABLISHED_CALL);
for (i = 0; i < wNumCalls; i++) {
if (CallList[i] != pChannel->hCall) {
if (LockCall(CallList[i], &pCall) == CC_OK) {
status = H245OpenChannel(pCall->H245Instance, // H245 instance
pChannel->hChannel, // dwTransId
pChannel->wLocalChannelNumber,
pChannel->pTxH245TermCap, // TxMode
pChannel->pTxMuxTable, // TxMux
H245_INVALID_PORT_NUMBER, // TxPort
pChannel->pRxH245TermCap, // RxMode
pChannel->pRxMuxTable, // RxMux
pChannel->pSeparateStack);
UnlockCall(pCall);
}
}
}
Free(CallList);
}
UnlockChannel(pChannel);
UnlockConference(pConference);
LeaveCallControlTop(CC_OK);
}
CC_API
HRESULT CC_CallListen( PCC_HLISTEN phListen,
PCC_ADDR pListenAddr,
PCC_ALIASNAMES pLocalAliasNames,
DWORD dwListenToken,
CC_LISTEN_CALLBACK ListenCallback)
{
HRESULT status;
PLISTEN pListen;
HQ931LISTEN hQ931Listen;
EnterCallControlTop();
if (InitStatus != CC_OK)
LeaveCallControlTop(InitStatus);
if (CallControlState != OPERATIONAL_STATE)
LeaveCallControlTop(CC_INTERNAL_ERROR);
// validate parameters
if (phListen == NULL)
LeaveCallControlTop(CC_BAD_PARAM);
// set phListen now, in case we encounter an error
*phListen = CC_INVALID_HANDLE;
if (pListenAddr == NULL)
LeaveCallControlTop(CC_BAD_PARAM);
status = ValidateAddr(pListenAddr);
if (status != CC_OK)
LeaveCallControlTop(status);
status = Q931ValidateAliasNames(pLocalAliasNames);
if (status != CS_OK)
LeaveCallControlTop(status);
if (ListenCallback == NULL)
LeaveCallControlTop(CC_BAD_PARAM);
status = SetQ931Port(pListenAddr);
if (status != CS_OK)
LeaveCallControlTop(status);
status = AllocAndLockListen(phListen,
pListenAddr,
0, // hQ931Listen
pLocalAliasNames,
dwListenToken,
ListenCallback,
&pListen);
if (status != CC_OK)
LeaveCallControlTop(status);
// Unlock the listen object to prevent deadlock when calling Q931
UnlockListen(pListen);
status = Q931Listen(&hQ931Listen, pListenAddr,
(DWORD)*phListen, (Q931_CALLBACK)Q931Callback);
if (status != CS_OK) {
if (LockListen(*phListen, &pListen) == CC_OK)
FreeListen(pListen);
*phListen = CC_INVALID_HANDLE;
LeaveCallControlTop(status);
}
status = LockListen(*phListen, &pListen);
if (status != CC_OK) {
Q931CancelListen(hQ931Listen);
LeaveCallControlTop(status);
}
ASSERT(pListenAddr != NULL);
ASSERT(pListenAddr->nAddrType == CC_IP_BINARY);
pListen->hQ931Listen = hQ931Listen;
// Copy the binary form of the listen address into the listen object
pListen->ListenAddr = *pListenAddr;
#ifdef GATEKEEPER
status = GkiOpenListen(*phListen,
pLocalAliasNames,
pListenAddr->Addr.IP_Binary.dwAddr,
pListenAddr->Addr.IP_Binary.wPort);
if (status != NOERROR) {
Q931CancelListen(hQ931Listen);
FreeListen(pListen);
} else {
UnlockListen(pListen);
}
#else
status = UnlockListen(pListen);
#endif // GATEKEEPER
LeaveCallControlTop(status);
}
CC_API
HRESULT CC_CancelCall( CC_HCALL hCall)
{
HRESULT status;
PCALL pCall;
PCONFERENCE pConference;
HRESULT SaveStatus;
H245_INST_T H245Instance;
HQ931CALL hQ931Call;
WORD wNumCalls;
EnterCallControlTop();
if (InitStatus != CC_OK)
LeaveCallControlTop(InitStatus);
if (CallControlState != OPERATIONAL_STATE)
LeaveCallControlTop(CC_INTERNAL_ERROR);
if (hCall == CC_INVALID_HANDLE)
LeaveCallControlTop(CC_BAD_PARAM);
status = LockCallAndConference(hCall, &pCall, &pConference);
if (status != CC_OK)
LeaveCallControlTop(status);
if ((pCall->CallState != ENQUEUED) &&
(pCall->CallState != PLACED) &&
(pCall->CallState != RINGING) &&
(pCall->CallState != TERMCAP)) {
UnlockCall(pCall);
UnlockConference(pConference);
LeaveCallControlTop(CC_BAD_PARAM);
}
#ifdef GATEKEEPER
if (pCall->GkiCall.uGkiCallState != 0)
{
GkiCloseCall(&pCall->GkiCall);
}
#endif // GATEKEEPER
H245Instance = pCall->H245Instance;
hQ931Call = pCall->hQ931Call;
FreeCall(pCall);
if (H245Instance != H245_INVALID_ID)
SaveStatus = H245ShutDown(H245Instance);
else
SaveStatus = H245_ERROR_OK;
if (hQ931Call != 0) {
if (SaveStatus == H245_ERROR_OK) {
SaveStatus = 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 (SaveStatus == CS_BAD_PARAM)
SaveStatus = CC_OK;
} else
Q931Hangup(hQ931Call, CC_REJECT_UNDEFINED_REASON);
}
for ( ; ; ) {
// Start up an enqueued call, if one exists
status = RemoveEnqueuedCallFromConference(pConference, &hCall);
if ((status != CC_OK) || (hCall == CC_INVALID_HANDLE))
break;
status = LockCall(hCall, &pCall);
if (status == CC_OK) {
pCall->CallState = PLACED;
status = PlaceCall(pCall, pConference);
UnlockCall(pCall);
if (status == CC_OK)
break;
}
}
EnumerateCallsInConference(&wNumCalls, NULL, pConference, REAL_CALLS);
if (wNumCalls == 0) {
if (pConference->bDeferredDelete) {
ASSERT(pConference->LocalEndpointAttached == DETACHED);
FreeConference(pConference);
} else {
if ((pConference->ConferenceMode != MULTIPOINT_MODE) ||
(pConference->tsMultipointController != TS_TRUE))
ReInitializeConference(pConference);
UnlockConference(pConference);
}
} else {
UnlockConference(pConference);
}
if (SaveStatus != CC_OK)
status = SaveStatus;
LeaveCallControlTop(status);
}
CC_API
HRESULT CC_CancelListen( CC_HLISTEN hListen)
{
HRESULT status;
PLISTEN pListen;
HQ931LISTEN hQ931Listen;
EnterCallControlTop();
if (InitStatus != CC_OK)
LeaveCallControlTop(InitStatus);
if (CallControlState != OPERATIONAL_STATE)
LeaveCallControlTop(CC_INTERNAL_ERROR);
// validate parameters
if (hListen == CC_INVALID_HANDLE)
LeaveCallControlTop(CC_BAD_PARAM);
status = LockListen(hListen, &pListen);
if (status != CC_OK)
LeaveCallControlTop(status);
hQ931Listen = pListen->hQ931Listen;
// Unlock the listen object to prevent deadlock when calling Q931
UnlockListen(pListen);
#ifdef GATEKEEPER
status = GkiCloseListen(hListen);
#endif // GATEKEEPER
status = Q931CancelListen(hQ931Listen);
if (status != CS_OK)
LeaveCallControlTop(status);
status = LockListen(hListen, &pListen);
if (status == CC_OK) {
LeaveCallControlTop(FreeListen(pListen));
} else
LeaveCallControlTop(status);
}
CC_API
HRESULT CC_CloseChannel( CC_HCHANNEL hChannel)
{
HRESULT status;
HRESULT SaveStatus = CC_OK;
PCHANNEL pChannel;
PCONFERENCE pConference;
PCALL pCall;
WORD wNumCalls;
PCC_HCALL CallList;
WORD i;
BOOL bChannelCloseRequest;
CC_HCALL hCall;
#ifdef GATEKEEPER
unsigned uBandwidth = 0;
#endif // GATEKEEPER
EnterCallControlTop();
if (InitStatus != CC_OK)
LeaveCallControlTop(InitStatus);
if (CallControlState != OPERATIONAL_STATE)
LeaveCallControlTop(CC_INTERNAL_ERROR);
// validate parameters
if (hChannel == CC_INVALID_HANDLE)
LeaveCallControlTop(CC_BAD_PARAM);
status = LockChannelAndConference(hChannel, &pChannel, &pConference);
if (status != CC_OK)
LeaveCallControlTop(status);
if (pChannel->tsAccepted != TS_TRUE) {
UnlockChannel(pChannel);
UnlockConference(pConference);
LeaveCallControlTop(CC_BAD_PARAM);
}
if (pConference->LocalEndpointAttached != ATTACHED) {
UnlockChannel(pChannel);
UnlockConference(pConference);
LeaveCallControlTop(CC_BAD_PARAM);
}
status = EnumerateCallsInConference(&wNumCalls, &CallList, pConference, ESTABLISHED_CALL);
if (status != CC_OK) {
UnlockConference(pConference);
UnlockChannel(pChannel);
LeaveCallControlTop(status);
}
if ((pChannel->bChannelType == RX_CHANNEL) ||
(pChannel->bChannelType == PROXY_CHANNEL) ||
((pChannel->bChannelType == TXRX_CHANNEL) &&
(pChannel->bLocallyOpened == FALSE))) {
// Generate a channel close request
bChannelCloseRequest = TRUE;
} else {
bChannelCloseRequest = FALSE;
while (DequeueRequest(&pChannel->pCloseRequests, &hCall) == CC_OK) {
if (LockCall(hCall, &pCall) == CC_OK) {
H245CloseChannelReqResp(pCall->H245Instance,
H245_ACC,
pChannel->wLocalChannelNumber);
UnlockCall(pCall);
}
}
#ifdef GATEKEEPER
if (pChannel->bChannelType != TXRX_CHANNEL) {
if (pChannel->bMultipointChannel) {
// Multicast channel bandwidth is assigned to arbitrary call
uBandwidth = pChannel->dwBandwidth / 100;
} else {
// Channel bandwidth is assigned to a specific call
ASSERT(pChannel->hCall != CC_INVALID_HANDLE);
if (LockCall(pChannel->hCall, &pCall) == CC_OK) {
SaveStatus = GkiCloseChannel(&pCall->GkiCall, pChannel->dwBandwidth, hChannel);
UnlockCall(pCall);
}
}
}
#endif // GATEKEEPER
}
for (i = 0; i < wNumCalls; i++) {
if (LockCall(CallList[i], &pCall) == CC_OK) {
if (bChannelCloseRequest) {
if ((pChannel->bChannelType != PROXY_CHANNEL) ||
(pChannel->hCall == pCall->hCall)) {
// 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. In this case,
// the local endpoint initiated the close channel request,
// so we'll use CC_INVALID_HANDLE as the dwTransId
// to note this fact.
status = H245CloseChannelReq(pCall->H245Instance, // H245 instance
CC_INVALID_HANDLE, // dwTransId
pChannel->wRemoteChannelNumber);
}
} else {
status = H245CloseChannel(pCall->H245Instance, // H245 instance
0, // dwTransId
pChannel->wLocalChannelNumber);
#ifdef GATEKEEPER
if (uBandwidth && uBandwidth <= pCall->GkiCall.uBandwidthUsed) {
// Since the bandwidth is multicast, only subtract it from
// a single call (does not really matter which one)
SaveStatus = GkiCloseChannel(&pCall->GkiCall, pChannel->dwBandwidth, hChannel);
if (SaveStatus == CC_OK)
uBandwidth = 0;
}
#endif // GATEKEEPER
}
// Note that this channel may not have been accepted on all of the calls,
// so we could get an H245_ERROR_INVALID_CHANNEL error
if ((status != H245_ERROR_OK) && (status != H245_ERROR_INVALID_CHANNEL))
SaveStatus = status;
UnlockCall(pCall);
}
}
if (CallList != NULL)
Free(CallList);
if (pChannel->bChannelType == PROXY_CHANNEL) {
// If this is a PROXY channel, keep the channel object around
// until the channel owner closes it
pChannel->tsAccepted = TS_FALSE;
UnlockChannel(pChannel);
} else {
FreeChannel(pChannel);
}
UnlockConference(pConference);
LeaveCallControlTop(SaveStatus);
}
CC_API
HRESULT CC_CloseChannelResponse( CC_HCHANNEL hChannel,
BOOL bWillCloseChannel)
{
HRESULT status;
PCHANNEL pChannel;
PCONFERENCE pConference;
CC_HCALL hCall;
PCALL pCall;
H245_ACC_REJ_T AccRej;
WORD wNumRequests;
EnterCallControlTop();
if (InitStatus != CC_OK)
LeaveCallControlTop(InitStatus);
if (CallControlState != OPERATIONAL_STATE)
LeaveCallControlTop(CC_INTERNAL_ERROR);
if (hChannel == CC_INVALID_HANDLE)
LeaveCallControlTop(CC_BAD_PARAM);
status = LockChannelAndConference(hChannel, &pChannel, &pConference);
if (status != CC_OK)
LeaveCallControlTop(status);
if (((pChannel->bChannelType != TX_CHANNEL) &&
(pChannel->bChannelType != TXRX_CHANNEL)) ||
(pChannel->bLocallyOpened == FALSE)) {
UnlockChannel(pChannel);
UnlockConference(pConference);
LeaveCallControlTop(CC_BAD_PARAM);
}
if (bWillCloseChannel)
AccRej = H245_ACC;
else
AccRej = H245_REJ;
wNumRequests = 0;
while (DequeueRequest(&pChannel->pCloseRequests, &hCall) == CC_OK) {
wNumRequests++;
if (LockCall(hCall, &pCall) == CC_OK) {
H245CloseChannelReqResp(pCall->H245Instance,
AccRej,
pChannel->wLocalChannelNumber);
UnlockCall(pCall);
}
}
UnlockChannel(pChannel);
UnlockConference(pConference);
if (wNumRequests == 0)
status = CC_BAD_PARAM;
else
status = CC_OK;
LeaveCallControlTop(status);
}
CC_API
HRESULT CC_ChangeConferenceCapabilities(
CC_HCONFERENCE hConference,
PCC_TERMCAPLIST pTermCapList,
PCC_TERMCAPDESCRIPTORS pTermCapDescriptors)
{
HRESULT status;
PCONFERENCE pConference;
PCALL pCall;
PCC_HCALL CallList;
WORD wNumCalls;
WORD i;
BOOL bConferenceTermCapsChanged;
EnterCallControlTop();
if (InitStatus != CC_OK)
LeaveCallControlTop(InitStatus);
if (CallControlState != OPERATIONAL_STATE)
LeaveCallControlTop(CC_INTERNAL_ERROR);
if (hConference == CC_INVALID_HANDLE)
LeaveCallControlTop(CC_BAD_PARAM);
if (pTermCapList == NULL)
LeaveCallControlTop(CC_BAD_PARAM);
status = ValidateTermCapList(pTermCapList);
if (status != CC_OK)
LeaveCallControlTop(status);
status = ValidateTermCapDescriptors(pTermCapDescriptors, pTermCapList);
if (status != CC_OK)
LeaveCallControlTop(status);
status = LockConference(hConference, &pConference);
if (status != CC_OK)
LeaveCallControlTop(status);
if (pConference->LocalEndpointAttached == DETACHED) {
UnlockConference(pConference);
LeaveCallControlTop(CC_BAD_PARAM);
}
status = UnregisterTermCapListFromH245(pConference,
pConference->pLocalH245TermCapList);
if (status != CC_OK) {
UnlockConference(pConference);
LeaveCallControlTop(status);
}
DestroyH245TermCapList(&pConference->pLocalH245TermCapList);
status = CopyH245TermCapList(&pConference->pLocalH245TermCapList,
pTermCapList);
if (status != CC_OK) {
UnlockConference(pConference);
LeaveCallControlTop(status);
}
status = UnregisterTermCapDescriptorsFromH245(pConference,
pConference->pLocalH245TermCapDescriptors);
if (status != CC_OK) {
UnlockConference(pConference);
LeaveCallControlTop(status);
}
DestroyH245TermCapDescriptors(&pConference->pLocalH245TermCapDescriptors);
// create a new descriptor list if one was not supplied
if (pTermCapDescriptors == NULL)
status = CreateH245DefaultTermCapDescriptors(&pConference->pLocalH245TermCapDescriptors,
pConference->pLocalH245TermCapList);
else
// make a local copy of pTermCapDescriptors
status = CopyH245TermCapDescriptors(&pConference->pLocalH245TermCapDescriptors,
pTermCapDescriptors);
if (status != CC_OK) {
UnlockConference(pConference);
LeaveCallControlTop(status);
}
if ((pConference->ConferenceMode == MULTIPOINT_MODE) &&
(pConference->tsMultipointController == TS_TRUE))
CreateConferenceTermCaps(pConference, &bConferenceTermCapsChanged);
else
bConferenceTermCapsChanged = TRUE;
if (bConferenceTermCapsChanged) {
EnumerateCallsInConference(&wNumCalls, &CallList, pConference, ESTABLISHED_CALL);
for (i = 0; i < wNumCalls; i++) {
if (LockCall(CallList[i], &pCall) == CC_OK) {
SendTermCaps(pCall, pConference);
UnlockCall(pCall);
}
}
if (CallList != NULL)
Free(CallList);
}
UnlockConference(pConference);
LeaveCallControlTop(CC_OK);
}
CC_API
HRESULT CC_CreateConference( PCC_HCONFERENCE phConference,
PCC_CONFERENCEID pConferenceID,
DWORD dwConferenceConfiguration,
PCC_TERMCAPLIST pTermCapList,
PCC_TERMCAPDESCRIPTORS pTermCapDescriptors,
PCC_VENDORINFO pVendorInfo,
PCC_OCTETSTRING pTerminalID,
DWORD dwConferenceToken,
CC_TERMCAP_CONSTRUCTOR TermCapConstructor,
CC_SESSIONTABLE_CONSTRUCTOR SessionTableConstructor,
CC_CONFERENCE_CALLBACK ConferenceCallback)
{
PCONFERENCE pConference;
HRESULT status;
BOOL bMultipointCapable;
BOOL bForceMultipointController;
EnterCallControlTop();
if (InitStatus != CC_OK)
LeaveCallControlTop(InitStatus);
if (CallControlState != OPERATIONAL_STATE)
LeaveCallControlTop(CC_INTERNAL_ERROR);
// validate parameters
if (phConference == NULL)
LeaveCallControlTop(CC_BAD_PARAM);
// set phConference now, in case we encounter an error
*phConference = CC_INVALID_HANDLE;
bMultipointCapable =
(dwConferenceConfiguration & CC_CONFIGURE_MULTIPOINT_CAPABLE) != 0 ? TRUE : FALSE;
bForceMultipointController =
(dwConferenceConfiguration & CC_CONFIGURE_FORCE_MC) != 0 ? TRUE : FALSE;
if ((bMultipointCapable == FALSE) &&
(bForceMultipointController == TRUE))
LeaveCallControlTop(CC_BAD_PARAM);
if (pTermCapList == NULL)
LeaveCallControlTop(CC_BAD_PARAM);
status = ValidateTermCapList(pTermCapList);
if (status != CC_OK)
LeaveCallControlTop(status);
status = ValidateTermCapDescriptors(pTermCapDescriptors, pTermCapList);
if (status != CC_OK)
LeaveCallControlTop(status);
if (pVendorInfo == NULL)
LeaveCallControlTop(CC_BAD_PARAM);
status = ValidateVendorInfo(pVendorInfo);
if (status != CC_OK)
LeaveCallControlTop(status);
status = ValidateTerminalID(pTerminalID);
if (status != CC_OK)
LeaveCallControlTop(status);
if (ConferenceCallback == NULL)
LeaveCallControlTop(CC_BAD_PARAM);
if (SessionTableConstructor == NULL)
SessionTableConstructor = DefaultSessionTableConstructor;
if (TermCapConstructor == NULL)
TermCapConstructor = DefaultTermCapConstructor;
status = AllocAndLockConference(phConference,
pConferenceID,
bMultipointCapable,
bForceMultipointController,
pTermCapList,
pTermCapDescriptors,
pVendorInfo,
pTerminalID,
dwConferenceToken,
SessionTableConstructor,
TermCapConstructor,
ConferenceCallback,
&pConference);
if (status != CC_OK)
LeaveCallControlTop(status);
LeaveCallControlTop(UnlockConference(pConference));
}
CC_API
HRESULT CC_DestroyConference( CC_HCONFERENCE hConference,
BOOL bAutoAccept)
{
HRESULT status;
EnterCallControlTop();
if (InitStatus != CC_OK)
LeaveCallControlTop(InitStatus);
if (CallControlState != OPERATIONAL_STATE)
LeaveCallControlTop(CC_INTERNAL_ERROR);
// validate parameters
if (hConference == CC_INVALID_HANDLE)
LeaveCallControlTop(CC_BAD_PARAM);
status = AsynchronousDestroyConference(hConference, bAutoAccept);
LeaveCallControlTop(status);
}
CC_API
HRESULT CC_EnumerateConferences( PWORD pwNumConferences,
CC_HCONFERENCE ConferenceList[])
{
HRESULT status;
EnterCallControlTop();
if (InitStatus != CC_OK)
LeaveCallControlTop(InitStatus);
if (CallControlState != OPERATIONAL_STATE)
LeaveCallControlTop(CC_INTERNAL_ERROR);
if ((*pwNumConferences != 0) && (ConferenceList == NULL))
LeaveCallControlTop(CC_BAD_PARAM);
if ((*pwNumConferences == 0) && (ConferenceList != NULL))
LeaveCallControlTop(CC_BAD_PARAM);
status = EnumerateConferences(pwNumConferences, ConferenceList);
LeaveCallControlTop(status);
}
CC_API
HRESULT CC_FlowControl( CC_HCHANNEL hChannel,
DWORD dwRate)
{
HRESULT status;
PCHANNEL pChannel;
PCALL pCall;
PCONFERENCE pConference;
EnterCallControlTop();
if (InitStatus != CC_OK)
LeaveCallControlTop(InitStatus);
if (CallControlState != OPERATIONAL_STATE)
LeaveCallControlTop(CC_INTERNAL_ERROR);
if (hChannel == CC_INVALID_HANDLE)
LeaveCallControlTop(CC_BAD_PARAM);
status = LockChannelAndConference(hChannel, &pChannel, &pConference);
if (status != CC_OK)
LeaveCallControlTop(status);
if ((pConference->LocalEndpointAttached != ATTACHED) ||
((pChannel->bChannelType != RX_CHANNEL) &&
(pChannel->bChannelType != PROXY_CHANNEL)) ||
(pChannel->tsAccepted != TS_TRUE)) {
UnlockChannel(pChannel);
UnlockConference(pConference);
LeaveCallControlTop(CC_BAD_PARAM);
}
status = LockCall(pChannel->hCall, &pCall);
if (status != CC_OK) {
UnlockChannel(pChannel);
UnlockConference(pConference);
LeaveCallControlTop(status);
}
// H.245 expects flow rate in units of 100 bps
if (dwRate != H245_NO_RESTRICTION)
dwRate /= 100;
status = H245FlowControl(pCall->H245Instance,
H245_SCOPE_CHANNEL_NUMBER,
pChannel->wRemoteChannelNumber,
0, // wResourceID, not used here
dwRate); // H245_NO_RESTRICTION if no restriction
UnlockCall(pCall);
UnlockChannel(pChannel);
UnlockConference(pConference);
LeaveCallControlTop(status);
}
CC_API
HRESULT CC_GetCallControlVersion( WORD wArraySize,
PWSTR pszVersion)
{
WCHAR pszCCversion[256];
WCHAR pszQ931version[256];
EnterCallControlTop();
if (CallControlState != OPERATIONAL_STATE)
LeaveCallControlTop(CC_INTERNAL_ERROR);
// validate parameters
if (wArraySize == 0)
LeaveCallControlTop(CC_BAD_PARAM);
if (pszVersion == NULL)
LeaveCallControlTop(CC_BAD_PARAM);
wcscpy(pszCCversion, L"Call Control ");
wcscat(pszCCversion, Unicode(__DATE__));
wcscat(pszCCversion, L" ");
wcscat(pszCCversion, Unicode(__TIME__));
wcscat(pszCCversion, L"\n");
Q931GetVersion(sizeof(pszQ931version)/sizeof(WCHAR), pszQ931version);
wcscat(pszCCversion, pszQ931version);
if (wcslen(pszCCversion) >= wArraySize) {
memcpy(pszVersion, pszCCversion, (wArraySize-1)*sizeof(WCHAR));
pszVersion[wArraySize-1] = L'\0';
LeaveCallControlTop(CC_BAD_SIZE);
}
wcscpy(pszVersion, pszCCversion);
LeaveCallControlTop(CC_OK);
}
CC_API
HRESULT CC_GetConferenceAttributes( CC_HCONFERENCE hConference,
PCC_CONFERENCEATTRIBUTES pConferenceAttributes)
{
HRESULT status;
PCONFERENCE pConference;
WORD wNumCalls;
BOOL bLocallyAttached;
PCC_HCALL CallList;
PCALL pCall;
WORD wLimit;
WORD wIndex;
WORD wOctetStringLength;
EnterCallControlTop();
if (InitStatus != CC_OK)
LeaveCallControlTop(InitStatus);
if (CallControlState != OPERATIONAL_STATE)
LeaveCallControlTop(CC_INTERNAL_ERROR);
// validate parameters
if (hConference == CC_INVALID_HANDLE)
LeaveCallControlTop(CC_BAD_PARAM);
if (pConferenceAttributes == NULL)
LeaveCallControlTop(CC_BAD_PARAM);
status = LockConference(hConference, &pConference);
if (status != CC_OK)
LeaveCallControlTop(status);
pConferenceAttributes->bMaster =
(pConference->tsMaster == TS_TRUE ? TRUE : FALSE);
pConferenceAttributes->bMultipointController =
(pConference->tsMultipointController == TS_TRUE ? TRUE : FALSE);
pConferenceAttributes->bMultipointConference =
(pConference->ConferenceMode == MULTIPOINT_MODE ? TRUE : FALSE);
pConferenceAttributes->ConferenceID = pConference->ConferenceID;
pConferenceAttributes->LocalTerminalLabel = pConference->LocalParticipantInfo.ParticipantInfo.TerminalLabel;
if (pConference->LocalEndpointAttached == ATTACHED)
bLocallyAttached = TRUE;
else
bLocallyAttached = FALSE;
if ((pConference->tsMultipointController == TS_TRUE) ||
(pConference->ConferenceMode == POINT_TO_POINT_MODE))
EnumerateCallsInConference(&wNumCalls, &CallList, pConference, ESTABLISHED_CALL);
else
EnumerateCallsInConference(&wNumCalls, &CallList, pConference, VIRTUAL_CALL);
pConferenceAttributes->dwConferenceToken = pConference->dwConferenceToken;
UnlockConference(pConference);
if (bLocallyAttached)
pConferenceAttributes->wNumCalls = (WORD)(wNumCalls + 1);
else
pConferenceAttributes->wNumCalls = wNumCalls;
#ifdef GATEKEEPER
pConferenceAttributes->dwBandwidthAllocated = 0;
pConferenceAttributes->dwBandwidthUsed = 0;
for (wIndex = 0; wIndex < wNumCalls; ++wIndex) {
if (LockCall(CallList[wIndex], &pCall) == CC_OK) {
pConferenceAttributes->dwBandwidthAllocated += pCall->GkiCall.uBandwidthAllocated;
if (pConferenceAttributes->dwBandwidthAllocated > GKI_MAX_BANDWIDTH)
pConferenceAttributes->dwBandwidthAllocated = GKI_MAX_BANDWIDTH;
pConferenceAttributes->dwBandwidthUsed += pCall->GkiCall.uBandwidthUsed;
if (pConferenceAttributes->dwBandwidthUsed > GKI_MAX_BANDWIDTH)
pConferenceAttributes->dwBandwidthUsed = GKI_MAX_BANDWIDTH;
UnlockCall(pCall);
}
}
pConferenceAttributes->dwBandwidthAllocated *= 100;
pConferenceAttributes->dwBandwidthUsed *= 100;
#endif // GATEKEEPER
if (pConferenceAttributes->pParticipantList != NULL) {
wLimit = pConferenceAttributes->pParticipantList->wLength;
pConferenceAttributes->pParticipantList->wLength = 0;
for (wIndex = 0; wIndex < wNumCalls; wIndex++) {
if (LockCall(CallList[wIndex], &pCall) == CC_OK) {
if (pCall->pPeerParticipantInfo != NULL) {
if (pConferenceAttributes->pParticipantList->wLength < wLimit) {
pConferenceAttributes->pParticipantList->ParticipantInfoArray[pConferenceAttributes->pParticipantList->wLength].TerminalLabel =
pCall->pPeerParticipantInfo->ParticipantInfo.TerminalLabel;
if ((pCall->pPeerParticipantInfo->TerminalIDState == TERMINAL_ID_VALID) &&
(pCall->pPeerParticipantInfo->ParticipantInfo.TerminalID.wOctetStringLength != 0) &&
(pCall->pPeerParticipantInfo->ParticipantInfo.TerminalID.pOctetString != NULL) &&
(pConferenceAttributes->pParticipantList->ParticipantInfoArray[pConferenceAttributes->pParticipantList->wLength].TerminalID.pOctetString != NULL)) {
if (pConferenceAttributes->pParticipantList->ParticipantInfoArray[pConferenceAttributes->pParticipantList->wLength].TerminalID.wOctetStringLength <
pCall->pPeerParticipantInfo->ParticipantInfo.TerminalID.wOctetStringLength) {
wOctetStringLength = pConferenceAttributes->pParticipantList->ParticipantInfoArray[pConferenceAttributes->pParticipantList->wLength].TerminalID.wOctetStringLength;
} else {
wOctetStringLength = pCall->pPeerParticipantInfo->ParticipantInfo.TerminalID.wOctetStringLength;
pConferenceAttributes->pParticipantList->ParticipantInfoArray[pConferenceAttributes->pParticipantList->wLength].TerminalID.wOctetStringLength = wOctetStringLength;
}
memcpy(pConferenceAttributes->pParticipantList->ParticipantInfoArray[pConferenceAttributes->pParticipantList->wLength].TerminalID.pOctetString,
pCall->pPeerParticipantInfo->ParticipantInfo.TerminalID.pOctetString,
wOctetStringLength);
} else {
pConferenceAttributes->pParticipantList->ParticipantInfoArray[pConferenceAttributes->pParticipantList->wLength].TerminalID.wOctetStringLength = 0;
pConferenceAttributes->pParticipantList->ParticipantInfoArray[pConferenceAttributes->pParticipantList->wLength].TerminalID.pOctetString = NULL;
}
}
pConferenceAttributes->pParticipantList->wLength++;
}
UnlockCall(pCall);
}
}
if (bLocallyAttached) {
if (LockConference(hConference, &pConference) == CC_OK) {
if (pConferenceAttributes->pParticipantList->wLength < wLimit) {
pConferenceAttributes->pParticipantList->ParticipantInfoArray[pConferenceAttributes->pParticipantList->wLength].TerminalLabel =
pConference->LocalParticipantInfo.ParticipantInfo.TerminalLabel;
if ((pConference->LocalParticipantInfo.TerminalIDState == TERMINAL_ID_VALID) &&
(pConference->LocalParticipantInfo.ParticipantInfo.TerminalID.wOctetStringLength != 0) &&
(pConference->LocalParticipantInfo.ParticipantInfo.TerminalID.pOctetString != NULL) &&
(pConferenceAttributes->pParticipantList->ParticipantInfoArray[pConferenceAttributes->pParticipantList->wLength].TerminalID.pOctetString != NULL)) {
if (pConferenceAttributes->pParticipantList->ParticipantInfoArray[pConferenceAttributes->pParticipantList->wLength].TerminalID.wOctetStringLength <
pConference->LocalParticipantInfo.ParticipantInfo.TerminalID.wOctetStringLength) {
wOctetStringLength = pConferenceAttributes->pParticipantList->ParticipantInfoArray[pConferenceAttributes->pParticipantList->wLength].TerminalID.wOctetStringLength;
} else {
wOctetStringLength = pConference->LocalParticipantInfo.ParticipantInfo.TerminalID.wOctetStringLength;
pConferenceAttributes->pParticipantList->ParticipantInfoArray[pConferenceAttributes->pParticipantList->wLength].TerminalID.wOctetStringLength = wOctetStringLength;
}
memcpy(pConferenceAttributes->pParticipantList->ParticipantInfoArray[pConferenceAttributes->pParticipantList->wLength].TerminalID.pOctetString,
pConference->LocalParticipantInfo.ParticipantInfo.TerminalID.pOctetString,
wOctetStringLength);
} else {
pConferenceAttributes->pParticipantList->ParticipantInfoArray[pConferenceAttributes->pParticipantList->wLength].TerminalID.wOctetStringLength = 0;
pConferenceAttributes->pParticipantList->ParticipantInfoArray[pConferenceAttributes->pParticipantList->wLength].TerminalID.pOctetString = NULL;
}
}
pConferenceAttributes->pParticipantList->wLength++;
UnlockConference(pConference);
}
}
}
if (CallList != NULL)
Free(CallList);
LeaveCallControlTop(CC_OK);
}
CC_API
HRESULT CC_H245ConferenceRequest( CC_HCALL hCall,
H245_CONFER_REQ_ENUM_T RequestType,
CC_TERMINAL_LABEL TerminalLabel)
{
HRESULT status;
PCALL pCall;
PCONFERENCE pConference;
EnterCallControlTop();
if (InitStatus != CC_OK)
LeaveCallControlTop(InitStatus);
if (CallControlState != OPERATIONAL_STATE)
LeaveCallControlTop(CC_INTERNAL_ERROR);
if (hCall == CC_INVALID_HANDLE)
LeaveCallControlTop(CC_BAD_PARAM);
if ((RequestType != H245_REQ_MAKE_ME_CHAIR) &&
(RequestType != H245_REQ_CANCEL_MAKE_ME_CHAIR) &&
(RequestType != H245_REQ_DROP_TERMINAL) &&
(RequestType != H245_REQ_ENTER_H243_TERMINAL_ID) &&
(RequestType != H245_REQ_ENTER_H243_CONFERENCE_ID))
LeaveCallControlTop(CC_BAD_PARAM);
status = LockCallAndConference(hCall, &pCall, &pConference);
if (status != CC_OK)
LeaveCallControlTop(status);
if ((pConference->LocalEndpointAttached != ATTACHED) ||
(pCall->CallState != CALL_COMPLETE) ||
(pCall->CallType == VIRTUAL_CALL)) {
UnlockCall(pCall);
UnlockConference(pConference);
LeaveCallControlTop(CC_BAD_PARAM);
}
status = H245ConferenceRequest(pCall->H245Instance,
RequestType,
TerminalLabel.bMCUNumber,
TerminalLabel.bTerminalNumber);
UnlockCall(pCall);
UnlockConference(pConference);
LeaveCallControlTop(status);
}
CC_API
HRESULT CC_H245ConferenceResponse( CC_HCALL hCall,
H245_CONFER_RSP_ENUM_T ResponseType,
CC_TERMINAL_LABEL CC_TerminalLabel,
PCC_OCTETSTRING pOctetString,
CC_TERMINAL_LABEL *pCC_TerminalList,
WORD wTerminalListCount)
{
HRESULT status;
PCALL pCall;
PCONFERENCE pConference;
WORD i;
TerminalLabel *pH245TerminalList;
BYTE *pH245OctetString;
BYTE bH245OctetStringLength;
EnterCallControlTop();
if (InitStatus != CC_OK)
LeaveCallControlTop(InitStatus);
if (CallControlState != OPERATIONAL_STATE)
LeaveCallControlTop(CC_INTERNAL_ERROR);
if (hCall == CC_INVALID_HANDLE)
LeaveCallControlTop(CC_BAD_PARAM);
if ((ResponseType != H245_RSP_CONFERENCE_ID) &&
(ResponseType != H245_RSP_PASSWORD) &&
(ResponseType != H245_RSP_VIDEO_COMMAND_REJECT) &&
(ResponseType != H245_RSP_TERMINAL_DROP_REJECT) &&
(ResponseType != H245_RSP_DENIED_CHAIR_TOKEN) &&
(ResponseType != H245_RSP_GRANTED_CHAIR_TOKEN))
LeaveCallControlTop(CC_BAD_PARAM);
if (wTerminalListCount != 0)
LeaveCallControlTop(CC_BAD_PARAM);
if (pCC_TerminalList == NULL)
LeaveCallControlTop(CC_BAD_PARAM);
status = ValidateOctetString(pOctetString);
if (status != CC_OK)
LeaveCallControlTop(status);
if (pOctetString != NULL)
if (pOctetString->wOctetStringLength > 255)
LeaveCallControlTop(CC_BAD_PARAM);
status = LockCallAndConference(hCall, &pCall, &pConference);
if (status != CC_OK)
LeaveCallControlTop(status);
if ((pConference->LocalEndpointAttached != ATTACHED) ||
(pCall->CallState != CALL_COMPLETE) ||
(pCall->CallType == VIRTUAL_CALL)) {
UnlockCall(pCall);
UnlockConference(pConference);
LeaveCallControlTop(CC_BAD_PARAM);
}
if (wTerminalListCount == 0) {
pH245TerminalList = NULL;
} else {
pH245TerminalList = (TerminalLabel *)Malloc(sizeof(TerminalLabel) * wTerminalListCount);
if (pH245TerminalList == NULL) {
UnlockCall(pCall);
UnlockConference(pConference);
LeaveCallControlTop(CC_NO_MEMORY);
}
for (i = 0; i < wTerminalListCount; i++) {
pH245TerminalList[i].mcuNumber = pCC_TerminalList[i].bMCUNumber;
pH245TerminalList[i].terminalNumber = pCC_TerminalList[i].bTerminalNumber;
}
}
if (pOctetString == NULL) {
pH245OctetString = NULL;
bH245OctetStringLength = 0;
} else {
pH245OctetString = pOctetString->pOctetString;
bH245OctetStringLength = (BYTE)pOctetString->wOctetStringLength;
}
status = H245ConferenceResponse(pCall->H245Instance,
ResponseType,
CC_TerminalLabel.bMCUNumber,
CC_TerminalLabel.bTerminalNumber,
pH245OctetString,
bH245OctetStringLength,
pH245TerminalList,
wTerminalListCount);
if (pH245TerminalList != NULL)
Free(pH245TerminalList);
UnlockCall(pCall);
UnlockConference(pConference);
LeaveCallControlTop(status);
}
CC_API
HRESULT CC_H245ConferenceCommand( CC_HCALL hCall,
CC_HCHANNEL hChannel,
H245_CONFER_CMD_ENUM_T CommandType,
CC_TERMINAL_LABEL TerminalLabel)
{
HRESULT status;
PCALL pCall;
PCONFERENCE pConference;
PCHANNEL pChannel;
WORD wChannelNumber;
EnterCallControlTop();
if (InitStatus != CC_OK)
LeaveCallControlTop(InitStatus);
if (CallControlState != OPERATIONAL_STATE)
LeaveCallControlTop(CC_INTERNAL_ERROR);
if (hCall == CC_INVALID_HANDLE)
LeaveCallControlTop(CC_BAD_PARAM);
if ((CommandType != H245_CMD_BROADCAST_CHANNEL) &&
(CommandType != H245_CMD_CANCEL_BROADCAST_CHANNEL) &&
(CommandType != H245_CMD_BROADCASTER) &&
(CommandType != H245_CMD_CANCEL_BROADCASTER) &&
(CommandType != H245_CMD_SEND_THIS_SOURCE) &&
(CommandType != H245_CMD_CANCEL_SEND_THIS_SOURCE) &&
(CommandType != H245_CMD_DROP_CONFERENCE))
LeaveCallControlTop(CC_BAD_PARAM);
status = LockCallAndConference(hCall, &pCall, &pConference);
if (status != CC_OK)
LeaveCallControlTop(status);
if ((pConference->LocalEndpointAttached != ATTACHED) ||
(pCall->CallState != CALL_COMPLETE) ||
(pCall->CallType == VIRTUAL_CALL)) {
UnlockCall(pCall);
UnlockConference(pConference);
LeaveCallControlTop(CC_BAD_PARAM);
}
if (hChannel == CC_INVALID_HANDLE) {
wChannelNumber = 1;
} else {
status = LockChannel(hChannel, &pChannel);
if (status != CC_OK) {
UnlockCall(pCall);
UnlockConference(pConference);
LeaveCallControlTop(status);
}
switch (pChannel->bChannelType) {
case TX_CHANNEL:
wChannelNumber = pChannel->wLocalChannelNumber;
break;
case RX_CHANNEL:
wChannelNumber = pChannel->wRemoteChannelNumber;
break;
case TXRX_CHANNEL:
wChannelNumber = pChannel->wRemoteChannelNumber;
break;
case PROXY_CHANNEL:
if (pChannel->hCall == hCall)
wChannelNumber = pChannel->wRemoteChannelNumber;
else
wChannelNumber = pChannel->wLocalChannelNumber;
break;
default:
ASSERT(0);
break;
}
UnlockChannel(pChannel);
}
status = H245ConferenceCommand(pCall->H245Instance,
CommandType,
wChannelNumber,
TerminalLabel.bMCUNumber,
TerminalLabel.bTerminalNumber);
UnlockCall(pCall);
UnlockConference(pConference);
LeaveCallControlTop(status);
}
CC_API
HRESULT CC_H245ConferenceIndication(CC_HCALL hCall,
H245_CONFER_IND_ENUM_T IndicationType,
BYTE bSBENumber,
CC_TERMINAL_LABEL TerminalLabel)
{
HRESULT status;
PCALL pCall;
PCONFERENCE pConference;
EnterCallControlTop();
if (InitStatus != CC_OK)
LeaveCallControlTop(InitStatus);
if (CallControlState != OPERATIONAL_STATE)
LeaveCallControlTop(CC_INTERNAL_ERROR);
if (hCall == CC_INVALID_HANDLE)
LeaveCallControlTop(CC_BAD_PARAM);
if ((IndicationType != H245_IND_SBE_NUMBER) &&
(IndicationType != H245_IND_SEEN_BY_ONE_OTHER) &&
(IndicationType != H245_IND_CANCEL_SEEN_BY_ONE_OTHER) &&
(IndicationType != H245_IND_SEEN_BY_ALL) &&
(IndicationType != H245_IND_CANCEL_SEEN_BY_ALL) &&
(IndicationType != H245_IND_TERMINAL_YOU_ARE_SEEING) &&
(IndicationType != H245_IND_REQUEST_FOR_FLOOR))
LeaveCallControlTop(CC_BAD_PARAM);
status = LockCallAndConference(hCall, &pCall, &pConference);
if (status != CC_OK)
LeaveCallControlTop(status);
if ((pConference->LocalEndpointAttached != ATTACHED) ||
(pCall->CallState != CALL_COMPLETE) ||
(pCall->CallType == VIRTUAL_CALL)) {
UnlockCall(pCall);
UnlockConference(pConference);
LeaveCallControlTop(CC_BAD_PARAM);
}
status = H245ConferenceIndication(pCall->H245Instance,
IndicationType,
bSBENumber,
TerminalLabel.bMCUNumber,
TerminalLabel.bTerminalNumber);
UnlockCall(pCall);
UnlockConference(pConference);
LeaveCallControlTop(status);
}
CC_API
HRESULT CC_H245MiscellaneousCommand(CC_HCALL hCall,
CC_HCHANNEL hChannel,
MiscellaneousCommand *pMiscellaneousCommand)
{
HRESULT status;
PCALL pCall;
PCONFERENCE pConference;
PCHANNEL pChannel;
WORD wChannelNumber;
PDU_T Pdu;
EnterCallControlTop();
if (InitStatus != CC_OK)
LeaveCallControlTop(InitStatus);
if (CallControlState != OPERATIONAL_STATE)
LeaveCallControlTop(CC_INTERNAL_ERROR);
if (hCall == CC_INVALID_HANDLE)
LeaveCallControlTop(CC_BAD_PARAM);
if (pMiscellaneousCommand == NULL)
LeaveCallControlTop(CC_BAD_PARAM);
if ((pMiscellaneousCommand->type.choice == multipointModeCommand_chosen) ||
(pMiscellaneousCommand->type.choice == cnclMltpntMdCmmnd_chosen))
LeaveCallControlTop(CC_BAD_PARAM);
status = LockCallAndConference(hCall, &pCall, &pConference);
if (status != CC_OK)
LeaveCallControlTop(status);
if ((pConference->LocalEndpointAttached != ATTACHED) ||
(pCall->CallState != CALL_COMPLETE) ||
(pCall->CallType == VIRTUAL_CALL)) {
UnlockCall(pCall);
UnlockConference(pConference);
LeaveCallControlTop(CC_BAD_PARAM);
}
if (hChannel == CC_INVALID_HANDLE) {
wChannelNumber = 1;
} else {
status = LockChannel(hChannel, &pChannel);
if (status != CC_OK) {
UnlockCall(pCall);
UnlockConference(pConference);
LeaveCallControlTop(status);
}
switch (pChannel->bChannelType) {
case TX_CHANNEL:
wChannelNumber = pChannel->wLocalChannelNumber;
break;
case RX_CHANNEL:
wChannelNumber = pChannel->wRemoteChannelNumber;
break;
case TXRX_CHANNEL:
wChannelNumber = pChannel->wRemoteChannelNumber;
break;
case PROXY_CHANNEL:
if (pChannel->hCall == hCall)
wChannelNumber = pChannel->wRemoteChannelNumber;
else
wChannelNumber = pChannel->wLocalChannelNumber;
break;
default:
ASSERT(0);
break;
}
UnlockChannel(pChannel);
}
// Construct an H.245 PDU to hold a miscellaneous command
Pdu.choice = MSCMg_cmmnd_chosen;
Pdu.u.MSCMg_cmmnd.choice = miscellaneousCommand_chosen;
Pdu.u.MSCMg_cmmnd.u.miscellaneousCommand = *pMiscellaneousCommand;
Pdu.u.MSCMg_cmmnd.u.miscellaneousCommand.logicalChannelNumber = wChannelNumber;
status = H245SendPDU(pCall->H245Instance, // H245 instance
&Pdu);
UnlockCall(pCall);
UnlockConference(pConference);
LeaveCallControlTop(status);
}
CC_API
HRESULT CC_H245MiscellaneousIndication(
CC_HCALL hCall,
CC_HCHANNEL hChannel,
MiscellaneousIndication *pMiscellaneousIndication)
{
HRESULT status;
PCALL pCall;
PCONFERENCE pConference;
PCHANNEL pChannel;
WORD wChannelNumber;
PDU_T Pdu;
EnterCallControlTop();
if (InitStatus != CC_OK)
LeaveCallControlTop(InitStatus);
if (CallControlState != OPERATIONAL_STATE)
LeaveCallControlTop(CC_INTERNAL_ERROR);
if (hCall == CC_INVALID_HANDLE)
LeaveCallControlTop(CC_BAD_PARAM);
if (pMiscellaneousIndication == NULL)
LeaveCallControlTop(CC_BAD_PARAM);
if ((pMiscellaneousIndication->type.choice == logicalChannelActive_chosen) ||
(pMiscellaneousIndication->type.choice == logicalChannelInactive_chosen))
LeaveCallControlTop(CC_BAD_PARAM);
status = LockCallAndConference(hCall, &pCall, &pConference);
if (status != CC_OK)
LeaveCallControlTop(status);
if ((pConference->LocalEndpointAttached != ATTACHED) ||
(pCall->CallState != CALL_COMPLETE) ||
(pCall->CallType == VIRTUAL_CALL)) {
UnlockCall(pCall);
UnlockConference(pConference);
LeaveCallControlTop(CC_BAD_PARAM);
}
if (hChannel == CC_INVALID_HANDLE) {
wChannelNumber = 1;
} else {
status = LockChannel(hChannel, &pChannel);
if (status != CC_OK) {
UnlockCall(pCall);
UnlockConference(pConference);
LeaveCallControlTop(status);
}
switch (pChannel->bChannelType) {
case TX_CHANNEL:
wChannelNumber = pChannel->wLocalChannelNumber;
break;
case RX_CHANNEL:
wChannelNumber = pChannel->wRemoteChannelNumber;
break;
case TXRX_CHANNEL:
wChannelNumber = pChannel->wRemoteChannelNumber;
break;
case PROXY_CHANNEL:
if (pChannel->hCall == hCall)
wChannelNumber = pChannel->wRemoteChannelNumber;
else
wChannelNumber = pChannel->wLocalChannelNumber;
break;
default:
ASSERT(0);
break;
}
UnlockChannel(pChannel);
}
// Construct an H.245 PDU to hold a miscellaneous indication
Pdu.choice = indication_chosen;
Pdu.u.indication.choice = miscellaneousIndication_chosen;
Pdu.u.indication.u.miscellaneousIndication = *pMiscellaneousIndication;
Pdu.u.indication.u.miscellaneousIndication.logicalChannelNumber = wChannelNumber;
status = H245SendPDU(pCall->H245Instance, // H245 instance
&Pdu);
UnlockCall(pCall);
UnlockConference(pConference);
LeaveCallControlTop(status);
}
CC_API
HRESULT CC_Hangup( CC_HCONFERENCE hConference,
BOOL bTerminateConference,
DWORD dwUserToken)
{
HRESULT status;
HRESULT SaveStatus;
HHANGUP hHangup;
PHANGUP pHangup;
PCHANNEL pChannel;
PCALL pCall;
PCONFERENCE pConference;
CC_HANGUP_CALLBACK_PARAMS HangupCallbackParams;
HQ931CALL hQ931Call;
WORD wNumChannels;
PCC_HCHANNEL ChannelList;
WORD wNumCalls;
PCC_HCALL CallList;
WORD i;
H245_INST_T H245Instance;
CALLSTATE CallState;
EnterCallControlTop();
if (InitStatus != CC_OK)
LeaveCallControlTop(InitStatus);
if (CallControlState != OPERATIONAL_STATE)
LeaveCallControlTop(CC_INTERNAL_ERROR);
// validate parameters
if (hConference == CC_INVALID_HANDLE)
LeaveCallControlTop(CC_BAD_PARAM);
status = LockConference(hConference, &pConference);
if (status != CC_OK)
LeaveCallControlTop(status);
// If the local endpoint is not attached, we will only allow a hangup if
// the local endpoint is the MC in a multipoint conference and
// conference termination is being requested
if ((pConference->LocalEndpointAttached != ATTACHED) &&
((bTerminateConference == FALSE) ||
(pConference->ConferenceMode != MULTIPOINT_MODE) ||
(pConference->tsMultipointController != TS_TRUE))) {
UnlockConference(pConference);
LeaveCallControlTop(CC_BAD_PARAM);
}
HangupCallbackParams.dwUserToken = dwUserToken;
if ((pConference->ConferenceMode == MULTIPOINT_MODE) &&
(pConference->tsMultipointController == TS_TRUE) &&
(bTerminateConference == FALSE)) {
// Send TerminalLeftConference (this call) to all established calls
EnumerateCallsInConference(&wNumCalls, &CallList, pConference, ESTABLISHED_CALL);
for (i = 0; i < wNumCalls; i++) {
if (LockCall(CallList[i], &pCall) == CC_OK) {
H245ConferenceIndication(pCall->H245Instance,
H245_IND_TERMINAL_LEFT, // Indication Type
0, // SBE number; ignored here
pConference->LocalParticipantInfo.ParticipantInfo.TerminalLabel.bMCUNumber, // MCU number
pConference->LocalParticipantInfo.ParticipantInfo.TerminalLabel.bTerminalNumber); // terminal number
UnlockCall(pCall);
}
}
if (CallList != NULL)
Free(CallList);
// Delete all TX, RX and bi-directional channels on this conference
// Leave PROXY_CHANNELs intact
EnumerateChannelsInConference(&wNumChannels,
&ChannelList,
pConference,
TX_CHANNEL | RX_CHANNEL | TXRX_CHANNEL);
for (i = 0; i < wNumChannels; i++) {
if (LockChannel(ChannelList[i], &pChannel) == CC_OK)
// Notice that since we're going to hangup, we don't need to
// close any channels
FreeChannel(pChannel);
}
if (ChannelList != NULL)
Free(ChannelList);
if (pConference->bDeferredDelete) {
ASSERT(pConference->LocalEndpointAttached == DETACHED);
FreeConference(pConference);
} else {
InvokeUserConferenceCallback(pConference,
CC_HANGUP_INDICATION,
CC_OK,
&HangupCallbackParams);
if (ValidateConference(hConference) == CC_OK) {
pConference->LocalEndpointAttached = DETACHED;
UnlockConference(pConference);
}
}
LeaveCallControlTop(CC_OK);
}
status = EnumerateChannelsInConference(&wNumChannels,
&ChannelList,
pConference,
ALL_CHANNELS);
if (status != CC_OK) {
UnlockConference(pConference);
LeaveCallControlTop(status);
}
// free all the channels
for (i = 0; i < wNumChannels; i++) {
if (LockChannel(ChannelList[i], &pChannel) == CC_OK)
// Notice that since we're going to hangup, we don't need to
// close any channels
FreeChannel(pChannel);
}
if (ChannelList != NULL)
Free(ChannelList);
status = EnumerateCallsInConference(&wNumCalls, &CallList, pConference, REAL_CALLS);
if (status != CC_OK) {
UnlockConference(pConference);
LeaveCallControlTop(status);
}
if ((pConference->ConferenceMode == MULTIPOINT_MODE) &&
(pConference->tsMultipointController == TS_FALSE) &&
(bTerminateConference == TRUE)) {
ASSERT(wNumCalls == 1);
if (LockCall(CallList[0], &pCall) == CC_OK) {
// Send DropConference command to MC
H245ConferenceCommand (
pCall->H245Instance,
H245_CMD_DROP_CONFERENCE, // Command type
1, // Channel
0, // byMcuNumber
0); // byTerminalNumber
UnlockCall(pCall);
}
}
status = AllocAndLockHangup(&hHangup,
hConference,
dwUserToken,
&pHangup);
if (status != CC_OK) {
if (CallList != NULL)
Free(CallList);
UnlockConference(pConference);
LeaveCallControlTop(status);
}
// Now close all calls
SaveStatus = H245_ERROR_OK;
for (i = 0; i < wNumCalls; i++) {
if (LockCall(CallList[i], &pCall) == CC_OK) {
H245Instance = pCall->H245Instance;
hQ931Call = pCall->hQ931Call;
CallState = pCall->CallState;
FreeCall(pCall);
if (CallState != ENQUEUED) {
if (H245Instance != H245_INVALID_ID) {
status = H245ShutDown(H245Instance);
if (status == H245_ERROR_OK)
pHangup->wNumCalls++;
else
// The link may already be shut down; if so, don't return an error
if (status != LINK_INVALID_STATE)
SaveStatus = status;
}
if (SaveStatus == H245_ERROR_OK) {
if ((CallState == PLACED) ||
(CallState == RINGING))
SaveStatus = Q931RejectCall(hQ931Call,
CC_REJECT_UNDEFINED_REASON,
&pConference->ConferenceID,
NULL, // alternate address
NULL); // pNonStandardData
else
SaveStatus = Q931Hangup(hQ931Call, CC_REJECT_NORMAL_CALL_CLEARING);
// Q931Hangup may legitimately return CS_BAD_PARAM or LINK_INVALID_STATE,
// because the Q.931 call object may have been deleted at this point
if ((SaveStatus == CS_BAD_PARAM) ||
(SaveStatus == LINK_INVALID_STATE))
SaveStatus = CC_OK;
} else
if ((CallState == PLACED) ||
(CallState == RINGING))
Q931RejectCall(hQ931Call,
CC_REJECT_UNDEFINED_REASON,
&pConference->ConferenceID,
NULL, // alternate address
NULL); // pNonStandardData
else
Q931Hangup(hQ931Call, CC_REJECT_NORMAL_CALL_CLEARING);
}
}
}
if (CallList != NULL)
Free(CallList);
// Need to validate the conference object; H245ShutDown may cause us to re-enter
// Call Control, which may result in deletion of the conference object
if (ValidateConference(hConference) != CC_OK)
LeaveCallControlTop(SaveStatus);
// Delete the virtual calls (if any)
EnumerateCallsInConference(&wNumCalls, &CallList, pConference, VIRTUAL_CALL);
for (i = 0; i < wNumCalls; i++)
if (LockCall(CallList[i], &pCall) == CC_OK) {
FreeCall(pCall);
}
if (CallList != NULL)
Free(CallList);
// XXX -- for sync 2, H245ShutDown() is synchronous, so change wNumCalls
// to cause the user callback and associated cleanup to occur synchronously
pHangup->wNumCalls = 0;
if (pHangup->wNumCalls == 0) {
if (pConference->bDeferredDelete) {
ASSERT(pConference->LocalEndpointAttached == DETACHED);
FreeConference(pConference);
} else {
InvokeUserConferenceCallback(pConference,
CC_HANGUP_INDICATION,
SaveStatus,
&HangupCallbackParams);
if (ValidateConference(hConference) == CC_OK) {
ReInitializeConference(pConference);
UnlockConference(pConference);
}
}
if (ValidateHangup(hHangup) == CC_OK)
FreeHangup(pHangup);
LeaveCallControlTop(SaveStatus);
} else {
UnlockHangup(pHangup);
LeaveCallControlTop(SaveStatus);
}
}
CC_API
HRESULT CC_MaximumAudioVideoSkew( CC_HCHANNEL hChannelAudio,
CC_HCHANNEL hChannelVideo,
WORD wMaximumSkew)
{
HRESULT status;
PCALL pCall;
PCONFERENCE pConference;
PCHANNEL pChannelAudio;
PCHANNEL pChannelVideo;
PCC_HCALL CallList;
WORD wNumCalls;
WORD i;
WORD wNumSuccesses;
EnterCallControlTop();
if (InitStatus != CC_OK)
LeaveCallControlTop(InitStatus);
if (CallControlState != OPERATIONAL_STATE)
LeaveCallControlTop(CC_INTERNAL_ERROR);
if ((hChannelAudio == CC_INVALID_HANDLE) || (hChannelVideo == CC_INVALID_HANDLE))
LeaveCallControlTop(CC_BAD_PARAM);
status = LockChannelAndConference(hChannelAudio, &pChannelAudio, &pConference);
if (status != CC_OK)
LeaveCallControlTop(status);
status = LockChannel(hChannelVideo, &pChannelVideo);
if (status != CC_OK) {
UnlockChannel(pChannelAudio);
UnlockConference(pConference);
LeaveCallControlTop(status);
}
if ((pChannelAudio->hConference != pChannelVideo->hConference) ||
(pChannelAudio->bChannelType != TX_CHANNEL) ||
(pChannelAudio->wNumOutstandingRequests != 0) ||
(pChannelVideo->bChannelType != TX_CHANNEL) ||
(pChannelVideo->wNumOutstandingRequests != 0)) {
UnlockChannel(pChannelAudio);
UnlockChannel(pChannelVideo);
UnlockConference(pConference);
LeaveCallControlTop(CC_BAD_PARAM);
}
EnumerateCallsInConference(&wNumCalls, &CallList, pConference, ESTABLISHED_CALL);
wNumSuccesses = 0;
for (i = 0; i < wNumCalls; i++) {
if (LockCall(CallList[i], &pCall) == CC_OK) {
status = H245H2250MaximumSkewIndication(pCall->H245Instance,
pChannelAudio->wLocalChannelNumber,
pChannelVideo->wLocalChannelNumber,
wMaximumSkew);
UnlockCall(pCall);
if (status == H245_ERROR_OK)
wNumSuccesses++;
}
}
if (CallList != NULL)
Free(CallList);
UnlockChannel(pChannelAudio);
UnlockChannel(pChannelVideo);
UnlockConference(pConference);
if (wNumSuccesses == 0) {
LeaveCallControlTop(status);
} else {
LeaveCallControlTop(CC_OK);
}
}
CC_API
HRESULT CC_Mute( CC_HCHANNEL hChannel)
{
HRESULT status;
HRESULT SaveStatus;
PCHANNEL pChannel;
PCONFERENCE pConference;
PCALL pCall;
PDU_T Pdu;
WORD wNumCalls;
PCC_HCALL CallList;
WORD i;
EnterCallControlTop();
if (InitStatus != CC_OK)
LeaveCallControlTop(InitStatus);
if (CallControlState != OPERATIONAL_STATE)
LeaveCallControlTop(CC_INTERNAL_ERROR);
if (hChannel == CC_INVALID_HANDLE)
LeaveCallControlTop(CC_BAD_PARAM);
status = LockChannelAndConference(hChannel, &pChannel, &pConference);
if (status != CC_OK)
LeaveCallControlTop(status);
if (pChannel->bChannelType != TX_CHANNEL) {
// can only mute transmit channels
UnlockChannel(pChannel);
UnlockConference(pConference);
LeaveCallControlTop(CC_BAD_PARAM);
}
if (pConference->LocalEndpointAttached != ATTACHED) {
UnlockChannel(pChannel);
UnlockConference(pConference);
LeaveCallControlTop(CC_BAD_PARAM);
}
status = EnumerateCallsInConference(&wNumCalls, &CallList, pConference, ESTABLISHED_CALL);
if (status != CC_OK) {
UnlockConference(pConference);
UnlockChannel(pChannel);
LeaveCallControlTop(status);
}
// Construct an H.245 PDU to hold a miscellaneous indication
// of "logical channel inactive"
Pdu.choice = indication_chosen;
Pdu.u.indication.choice = miscellaneousIndication_chosen;
Pdu.u.indication.u.miscellaneousIndication.logicalChannelNumber =
pChannel->wLocalChannelNumber;
Pdu.u.indication.u.miscellaneousIndication.type.choice = logicalChannelInactive_chosen;
SaveStatus = CC_OK;
for (i = 0; i < wNumCalls; i++) {
if (LockCall(CallList[i], &pCall) == CC_OK) {
status = H245SendPDU(pCall->H245Instance, // H245 instance
&Pdu);
// Note that this channel may not have been accepted on all of the calls,
// so we could get an H245_ERROR_INVALID_CHANNEL error
if ((status != H245_ERROR_OK) && (status != H245_ERROR_INVALID_CHANNEL))
SaveStatus = status;
UnlockCall(pCall);
}
}
if (CallList != NULL)
Free(CallList);
UnlockConference(pConference);
UnlockChannel(pChannel);
LeaveCallControlTop(SaveStatus);
}
CC_API
HRESULT CC_OpenChannel( CC_HCONFERENCE hConference,
PCC_HCHANNEL phChannel,
BYTE bSessionID,
BYTE bAssociatedSessionID,
BOOL bSilenceSuppression,
PCC_TERMCAP pTermCap,
PCC_ADDR pLocalRTCPAddr,
BYTE bDynamicRTPPayloadType,
DWORD dwBandwidth,
DWORD dwUserToken)
{
HRESULT status;
PCONFERENCE pConference;
PCHANNEL pChannel;
CC_HCALL hCall;
PCALL pCall;
H245_MUX_T H245MuxTable;
WORD i;
PCC_ADDR pLocalRTPAddr;
PCC_ADDR pPeerRTPAddr;
PCC_ADDR pPeerRTCPAddr;
BOOL bFoundSession;
WORD wNumCalls;
PCC_HCALL CallList;
#ifndef GATEKEEPER
HRESULT SaveStatus;
#endif // !GATEKEEPER
EnterCallControlTop();
if (InitStatus != CC_OK)
LeaveCallControlTop(InitStatus);
if (CallControlState != OPERATIONAL_STATE)
LeaveCallControlTop(CC_INTERNAL_ERROR);
// validate parameters
if (phChannel == NULL)
LeaveCallControlTop(CC_BAD_PARAM);
// set phChannel now, in case we encounter an error
*phChannel = CC_INVALID_HANDLE;
if (hConference == CC_INVALID_HANDLE)
LeaveCallControlTop(CC_BAD_PARAM);
if (pLocalRTCPAddr != NULL)
if (pLocalRTCPAddr->nAddrType != CC_IP_BINARY)
LeaveCallControlTop(CC_BAD_PARAM);
if (pTermCap == NULL)
LeaveCallControlTop(CC_BAD_PARAM);
if ((bDynamicRTPPayloadType != 0) &&
((bDynamicRTPPayloadType < 96) || (bDynamicRTPPayloadType > 127)))
LeaveCallControlTop(CC_BAD_PARAM);
status = LockConferenceEx(hConference,
&pConference,
TS_FALSE); // bDeferredDelete
if (status != CC_OK)
LeaveCallControlTop(status);
// XXX -- we may eventually want to support dynamic session generation
if (bSessionID == 0)
if ((pConference->tsMaster == TS_TRUE) ||
(pConference->ConferenceMode == MULTIPOINT_MODE)) {
UnlockConference(pConference);
LeaveCallControlTop(CC_BAD_PARAM);
}
if (((pConference->ConferenceMode == MULTIPOINT_MODE) &&
(pLocalRTCPAddr != NULL)) ||
((pConference->ConferenceMode != MULTIPOINT_MODE) &&
(pLocalRTCPAddr == NULL))) {
UnlockConference(pConference);
LeaveCallControlTop(CC_BAD_PARAM);
}
if (pConference->LocalEndpointAttached != ATTACHED) {
UnlockConference(pConference);
LeaveCallControlTop(CC_BAD_PARAM);
}
if (pConference->ConferenceMode == MULTIPOINT_MODE) {
// XXX -- We should be able to dynamically create a new session if needed
// Validate session ID
pLocalRTPAddr = NULL;
pLocalRTCPAddr = NULL;
bFoundSession = FALSE;
if (pConference->pSessionTable != NULL) {
for (i = 0; i < pConference->pSessionTable->wLength; i++) {
if (bSessionID == pConference->pSessionTable->SessionInfoArray[i].bSessionID) {
bFoundSession = TRUE;
if (pConference->tsMultipointController == TS_TRUE) {
pLocalRTPAddr = pConference->pSessionTable->SessionInfoArray[i].pRTPAddr;
pLocalRTCPAddr = pConference->pSessionTable->SessionInfoArray[i].pRTCPAddr;
}
break;
}
}
}
if (bFoundSession == FALSE) {
UnlockConference(pConference);
LeaveCallControlTop(CC_BAD_PARAM);
}
pPeerRTPAddr = pLocalRTPAddr;
pPeerRTCPAddr = pLocalRTCPAddr;
} else {
pLocalRTPAddr = NULL;
pPeerRTPAddr = NULL;
pPeerRTCPAddr = NULL;
}
H245MuxTable.Kind = H245_H2250;
H245MuxTable.u.H2250.nonStandardList = NULL;
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 (bDynamicRTPPayloadType == 0)
H245MuxTable.u.H2250.dynamicRTPPayloadTypePresent = FALSE;
else {
H245MuxTable.u.H2250.dynamicRTPPayloadTypePresent = TRUE;
H245MuxTable.u.H2250.dynamicRTPPayloadType = bDynamicRTPPayloadType;
}
H245MuxTable.u.H2250.sessionID = bSessionID;
if (bAssociatedSessionID == 0)
H245MuxTable.u.H2250.associatedSessionIDPresent = FALSE;
else {
H245MuxTable.u.H2250.associatedSessionIDPresent = TRUE;
H245MuxTable.u.H2250.associatedSessionID = bAssociatedSessionID;
}
H245MuxTable.u.H2250.mediaGuaranteed = FALSE;
H245MuxTable.u.H2250.mediaGuaranteedPresent = TRUE;
H245MuxTable.u.H2250.mediaControlGuaranteed = FALSE;
H245MuxTable.u.H2250.mediaControlGuaranteedPresent = TRUE;
// The silence suppression field must be present if and only if
// the channel is an audio channel
if (pTermCap->DataType == H245_DATA_AUDIO) {
H245MuxTable.u.H2250.silenceSuppressionPresent = TRUE;
H245MuxTable.u.H2250.silenceSuppression = (char) bSilenceSuppression;
} else
H245MuxTable.u.H2250.silenceSuppressionPresent = FALSE;
if (pConference->ConferenceMode == POINT_TO_POINT_MODE)
H245MuxTable.u.H2250.destinationPresent = FALSE;
else {
H245MuxTable.u.H2250.destinationPresent = TRUE;
H245MuxTable.u.H2250.destination.mcuNumber = pConference->LocalParticipantInfo.ParticipantInfo.TerminalLabel.bMCUNumber;
H245MuxTable.u.H2250.destination.terminalNumber = pConference->LocalParticipantInfo.ParticipantInfo.TerminalLabel.bTerminalNumber;
}
H245MuxTable.u.H2250.h261aVideoPacketization = FALSE;
// Set hCall in the channel object to indicate which call object
// the channel is being opened to; if we're in multipoint mode,
// the channel may be opened to multiple calls, to set hCall
// to CC_INVALID_HANDLE. If the channel is opened in point-to-point
// mode, and we later switch to multipoint mode and this peer hangs
// up, hCall will be used to determine whether this call object
// should be deleted
if (pConference->ConferenceMode == POINT_TO_POINT_MODE) {
EnumerateCallsInConference(&wNumCalls, &CallList, pConference, ESTABLISHED_CALL);
ASSERT(wNumCalls == 1);
hCall = CallList[0];
Free(CallList);
} else {
hCall = CC_INVALID_HANDLE;
}
status = AllocAndLockChannel(phChannel,
pConference,
hCall, // hCall
pTermCap, // Tx term cap
NULL, // Rx term cap
&H245MuxTable, // Tx mux table
NULL, // Rx mux table
NULL, // separate stack
dwUserToken,
TX_CHANNEL,
bSessionID,
bAssociatedSessionID,
0, // remote channel number
pLocalRTPAddr,
pLocalRTCPAddr,
pPeerRTPAddr,
pPeerRTCPAddr,
TRUE, // locally opened
dwBandwidth,
&pChannel);
if (status != CC_OK) {
UnlockConference(pConference);
LeaveCallControlTop(status);
}
status = AddChannelToConference(pChannel, pConference);
if (status != CC_OK) {
FreeChannel(pChannel);
UnlockConference(pConference);
*phChannel = CC_INVALID_HANDLE;
LeaveCallControlTop(status);
}
status = EnumerateCallsInConference(&wNumCalls, &CallList, pConference, ESTABLISHED_CALL);
if (status != CC_OK) {
FreeChannel(pChannel);
UnlockConference(pConference);
*phChannel = CC_INVALID_HANDLE;
LeaveCallControlTop(status);
}
#ifdef GATEKEEPER
UnlockChannel(pChannel);
UnlockConference(pConference);
// If point-to-point mode, than wNumCalls == 1 and CallList[0] == hCall
// If multipoint, choice of which channel to assign TX bandwidth to
// is arbitrary. Either way, CallList[0] works.
status = LockCall(CallList[0], &pCall);
if (status == CC_OK) {
status = GkiOpenChannel(&pCall->GkiCall, dwBandwidth, *phChannel, TX);
if (ValidateCall(CallList[0]) == CC_OK)
UnlockCall(pCall);
}
Free(CallList);
LeaveCallControlTop(status);
#else // GATEKEEPER
// Open a logical channel for each established call
SaveStatus = CC_OK;
for (i = 0; i < wNumCalls; i++) {
if (LockCall(CallList[i], &pCall) == CC_OK) {
status = H245OpenChannel(pCall->H245Instance, // H245 instance
pChannel->hChannel, // dwTransId
pChannel->wLocalChannelNumber,
pChannel->pTxH245TermCap, // TxMode
pChannel->pTxMuxTable, // TxMux
H245_INVALID_PORT_NUMBER, // TxPort
pChannel->pRxH245TermCap, // RxMode
pChannel->pRxMuxTable, // RxMux
pChannel->pSeparateStack);
if (status == H245_ERROR_OK)
(pChannel->wNumOutstandingRequests)++;
else
SaveStatus = status;
UnlockCall(pCall);
}
}
if (CallList != NULL)
Free(CallList);
if (pChannel->wNumOutstandingRequests == 0) {
// all open channel requests failed
FreeChannel(pChannel);
UnlockConference(pConference);
*phChannel = CC_INVALID_HANDLE;
LeaveCallControlTop(SaveStatus);
}
UnlockChannel(pChannel);
UnlockConference(pConference);
LeaveCallControlTop(CC_OK);
#endif // GATEKEEPER
}
HRESULT CC_OpenT120Channel( CC_HCONFERENCE hConference,
PCC_HCHANNEL phChannel,
BOOL bAssociateConference,
PCC_OCTETSTRING pExternalReference,
PCC_ADDR pAddr,
DWORD dwBandwidth,
DWORD dwUserToken)
{
HRESULT status;
PCALL pCall;
PCONFERENCE pConference;
PCHANNEL pChannel;
H245_MUX_T H245MuxTable;
CC_TERMCAP TermCap;
H245_ACCESS_T SeparateStack;
H245_ACCESS_T *pSeparateStack;
BYTE bSessionID;
WORD wNumCalls;
PCC_HCALL CallList;
HRESULT SaveStatus;
int i;
EnterCallControlTop();
if (InitStatus != CC_OK)
LeaveCallControlTop(InitStatus);
if (CallControlState != OPERATIONAL_STATE)
LeaveCallControlTop(CC_INTERNAL_ERROR);
// validate parameters
if (hConference == CC_INVALID_HANDLE)
LeaveCallControlTop(CC_BAD_PARAM);
if (pAddr != NULL)
if ((pAddr->nAddrType != CC_IP_BINARY) ||
(pAddr->bMulticast == TRUE))
LeaveCallControlTop(CC_BAD_PARAM);
if (pExternalReference != NULL)
if (pExternalReference->wOctetStringLength > 255)
LeaveCallControlTop(CC_BAD_PARAM);
status = LockConference(hConference, &pConference);
if (status != CC_OK)
LeaveCallControlTop(status);
if (pConference->LocalEndpointAttached != ATTACHED) {
UnlockConference(pConference);
LeaveCallControlTop(CC_BAD_PARAM);
}
// Assume that T.120 channels are always opened with a session ID of 0
bSessionID = 0;
H245MuxTable.Kind = H245_H2250;
H245MuxTable.u.H2250.nonStandardList = NULL;
H245MuxTable.u.H2250.mediaChannelPresent = FALSE;
H245MuxTable.u.H2250.mediaControlChannelPresent = FALSE;
H245MuxTable.u.H2250.dynamicRTPPayloadTypePresent = FALSE;
H245MuxTable.u.H2250.sessionID = bSessionID;
H245MuxTable.u.H2250.associatedSessionIDPresent = FALSE;
H245MuxTable.u.H2250.mediaGuaranteedPresent = FALSE;
H245MuxTable.u.H2250.mediaControlGuaranteedPresent = FALSE;
H245MuxTable.u.H2250.silenceSuppressionPresent = FALSE;
if (pConference->ConferenceMode == POINT_TO_POINT_MODE)
H245MuxTable.u.H2250.destinationPresent = FALSE;
else {
H245MuxTable.u.H2250.destinationPresent = TRUE;
H245MuxTable.u.H2250.destination.mcuNumber = pConference->LocalParticipantInfo.ParticipantInfo.TerminalLabel.bMCUNumber;
H245MuxTable.u.H2250.destination.terminalNumber = pConference->LocalParticipantInfo.ParticipantInfo.TerminalLabel.bTerminalNumber;
}
H245MuxTable.u.H2250.h261aVideoPacketization = FALSE;
TermCap.Dir = H245_CAPDIR_LCLRXTX;
TermCap.DataType = H245_DATA_DATA;
TermCap.ClientType = H245_CLIENT_DAT_T120;
TermCap.CapId = 0;
TermCap.Cap.H245Dat_T120.maxBitRate = dwBandwidth;
TermCap.Cap.H245Dat_T120.application.choice = DACy_applctn_t120_chosen;
TermCap.Cap.H245Dat_T120.application.u.DACy_applctn_t120.choice = separateLANStack_chosen;
if (pAddr != NULL) {
SeparateStack.bit_mask = distribution_present;
SeparateStack.distribution.choice = unicast_chosen;
if (pExternalReference != NULL) {
SeparateStack.bit_mask |= externalReference_present;
SeparateStack.externalReference.length = pExternalReference->wOctetStringLength;
memcpy(SeparateStack.externalReference.value,
pExternalReference->pOctetString,
pExternalReference->wOctetStringLength);
}
SeparateStack.networkAddress.choice = localAreaAddress_chosen;
SeparateStack.networkAddress.u.localAreaAddress.choice = unicastAddress_chosen;
SeparateStack.networkAddress.u.localAreaAddress.u.unicastAddress.choice = UnicastAddress_iPAddress_chosen;
SeparateStack.networkAddress.u.localAreaAddress.u.unicastAddress.u.UnicastAddress_iPAddress.tsapIdentifier =
pAddr->Addr.IP_Binary.wPort;
SeparateStack.networkAddress.u.localAreaAddress.u.unicastAddress.u.UnicastAddress_iPAddress.network.length = 4;
HostToH245IPNetwork(SeparateStack.networkAddress.u.localAreaAddress.u.unicastAddress.u.UnicastAddress_iPAddress.network.value,
pAddr->Addr.IP_Binary.dwAddr);
SeparateStack.associateConference = (char) bAssociateConference;
pSeparateStack = &SeparateStack;
} else {
pSeparateStack = NULL;
}
status = AllocAndLockChannel(phChannel,
pConference,
CC_INVALID_HANDLE, // hCall
&TermCap, // Tx term cap
&TermCap, // Rx term cap
&H245MuxTable, // Tx mux table
&H245MuxTable, // Rx mux table
pSeparateStack, // separate stack
dwUserToken,
TXRX_CHANNEL,
bSessionID,
0, // associated session ID
0, // remote channel
NULL, // local RTP addr
NULL, // local RTCP addr
NULL, // peer RTP addr
NULL, // peer RTCP addr
TRUE, // locally opened
dwBandwidth,
&pChannel);
if (status != CC_OK) {
UnlockConference(pConference);
LeaveCallControlTop(status);
}
pChannel->tsAccepted = TS_TRUE;
status = AddChannelToConference(pChannel, pConference);
if (status != CC_OK) {
FreeChannel(pChannel);
UnlockConference(pConference);
LeaveCallControlTop(status);
}
EnumerateCallsInConference(&wNumCalls, &CallList, pConference, ESTABLISHED_CALL);
SaveStatus = CC_OK;
for (i = 0; i < wNumCalls; i++) {
if (LockCall(CallList[i], &pCall) == CC_OK) {
status = H245OpenChannel(pCall->H245Instance, // H245 instance
pChannel->hChannel, // dwTransId
pChannel->wLocalChannelNumber,
pChannel->pTxH245TermCap, // TxMode
pChannel->pTxMuxTable, // TxMux
H245_INVALID_PORT_NUMBER, // TxPort
pChannel->pRxH245TermCap, // RxMode
pChannel->pRxMuxTable, // RxMux
pChannel->pSeparateStack);
if (status == H245_ERROR_OK)
(pChannel->wNumOutstandingRequests)++;
else
SaveStatus = status;
UnlockCall(pCall);
}
}
Free(CallList);
if (pChannel->wNumOutstandingRequests == 0) {
// All open channel requests failed
FreeChannel(pChannel);
status = SaveStatus;
} else {
UnlockChannel(pChannel);
status = CC_OK;
}
UnlockConference(pConference);
LeaveCallControlTop(status);
}
HRESULT CC_Ping( CC_HCALL hCall,
DWORD dwTimeout)
{
PCALL pCall;
HRESULT status;
EnterCallControlTop();
if (InitStatus != CC_OK)
LeaveCallControlTop(InitStatus);
if (CallControlState != OPERATIONAL_STATE)
LeaveCallControlTop(CC_INTERNAL_ERROR);
// validate parameters
if (hCall == CC_INVALID_HANDLE)
LeaveCallControlTop(CC_BAD_PARAM);
status = LockCall(hCall, &pCall);
if (status != CC_OK)
LeaveCallControlTop(status);
if ((pCall->CallState != CALL_COMPLETE) ||
(pCall->CallType == VIRTUAL_CALL)) {
UnlockCall(pCall);
LeaveCallControlTop(CC_BAD_PARAM);
}
// Set the T105 timeout value as specified by the user;
// note that the previous timeout value is returned in this parameter
H245SystemControl(0, H245_SYSCON_SET_FSM_T105, &dwTimeout);
status = H245RoundTripDelayRequest(pCall->H245Instance,
0); // dwTransId
// Reset the T105 timeout value to its original setting
H245SystemControl(0, H245_SYSCON_SET_FSM_T105, &dwTimeout);
UnlockCall(pCall);
LeaveCallControlTop(status);
}
CC_API
HRESULT CC_PlaceCall( CC_HCONFERENCE hConference,
PCC_HCALL phCall,
PCC_ALIASNAMES pLocalAliasNames,
PCC_ALIASNAMES pCalleeAliasNames,
PCC_ALIASNAMES pCalleeExtraAliasNames,
PCC_ALIASITEM pCalleeExtension,
PCC_NONSTANDARDDATA pNonStandardData,
PWSTR pszDisplay,
PCC_ADDR pDestinationAddr,
PCC_ADDR pConnectAddr,
DWORD dwBandwidth,
DWORD dwUserToken)
{
PCALL pCall;
CC_HCALL hCall;
PCONFERENCE pConference;
HRESULT status;
CALLTYPE CallType = CALLER;
CALLSTATE CallState = PLACED;
WORD wNumCalls;
BOOL bCallerIsMC;
EnterCallControlTop();
if (InitStatus != CC_OK)
LeaveCallControlTop(InitStatus);
if (CallControlState != OPERATIONAL_STATE)
LeaveCallControlTop(CC_INTERNAL_ERROR);
// validate parameters
if (phCall == NULL)
LeaveCallControlTop(CC_BAD_PARAM);
// set hCall now, in case we encounter an error
*phCall = CC_INVALID_HANDLE;
if (hConference == CC_INVALID_HANDLE)
LeaveCallControlTop(CC_BAD_PARAM);
status = Q931ValidateAliasNames(pLocalAliasNames);
if (status != CS_OK)
LeaveCallControlTop(status);
status = Q931ValidateAliasNames(pCalleeAliasNames);
if (status != CS_OK)
LeaveCallControlTop(status);
status = Q931ValidateAliasNames(pCalleeExtraAliasNames);
if (status != CS_OK)
LeaveCallControlTop(status);
status = Q931ValidateAliasItem(pCalleeExtension);
if (status != CS_OK)
LeaveCallControlTop(status);
status = ValidateNonStandardData(pNonStandardData);
if (status != CC_OK)
LeaveCallControlTop(status);
status = ValidateDisplay(pszDisplay);
if (status != CC_OK)
LeaveCallControlTop(status);
if ((pDestinationAddr == NULL) &&
(pConnectAddr == NULL) &&
(pCalleeAliasNames == NULL))
LeaveCallControlTop(CC_BAD_PARAM);
status = ValidateAddr(pDestinationAddr);
if (status != CC_OK)
LeaveCallControlTop(status);
status = ValidateAddr(pConnectAddr);
if (status != CC_OK)
LeaveCallControlTop(status);
status = SetQ931Port(pDestinationAddr);
if (status != CS_OK)
LeaveCallControlTop(status);
status = SetQ931Port(pConnectAddr);
if (status != CS_OK)
LeaveCallControlTop(status);
status = LockConferenceEx(hConference,
&pConference,
TS_FALSE); // bDeferredDelete
if (status != CC_OK)
LeaveCallControlTop(status);
EnumerateCallsInConference(&wNumCalls, NULL, pConference, REAL_CALLS);
if (wNumCalls > 0) {
if (pConference->tsMultipointController == TS_TRUE) {
// Place Call directly to callee
status = CC_OK;
ASSERT(!EqualConferenceIDs(&pConference->ConferenceID, &InvalidConferenceID));
CallType = CALLER;
CallState = PLACED;
} else { // we're not the MC
if (pConference->bMultipointCapable) {
if (pConference->pMultipointControllerAddr != NULL) {
// Place Call to MC
status = CC_OK;
if (pDestinationAddr == NULL)
pDestinationAddr = pConnectAddr;
pConnectAddr = pConference->pMultipointControllerAddr;
ASSERT(!EqualConferenceIDs(&pConference->ConferenceID, &InvalidConferenceID));
CallType = THIRD_PARTY_INVITOR;
CallState = PLACED;
} else { // we don't have an MC address
if (pConference->tsMaster == TS_UNKNOWN) {
ASSERT(pConference->tsMultipointController == TS_UNKNOWN);
status = CC_OK;
CallType = CALLER;
CallState = ENQUEUED;
} else {
ASSERT(pConference->tsMultipointController == TS_FALSE);
// Error, no MC
// XXX -- we may eventually want to enqueue the request
// and set an expiration timer
status = CC_NOT_MULTIPOINT_CAPABLE;
CallType = THIRD_PARTY_INVITOR;
CallState = ENQUEUED;
}
}
} else { // we're not multipoint capable
// Error - bad param
ASSERT(wNumCalls == 1);
status = CC_BAD_PARAM;
}
}
} else { // wNumCalls == 0
// Place Call directly to callee
status = CC_OK;
CallType = CALLER;
CallState = PLACED;
}
if (status != CC_OK) {
UnlockConference(pConference);
LeaveCallControlTop(status);
}
if (pConference->tsMultipointController == TS_TRUE)
bCallerIsMC = TRUE;
else
bCallerIsMC = FALSE;
status = AllocAndLockCall(&hCall,
hConference,
CC_INVALID_HANDLE, // hQ931Call
CC_INVALID_HANDLE, // hQ931CallInvitor
pLocalAliasNames, // local alias names
pCalleeAliasNames, // remote alias names
pCalleeExtraAliasNames,// remote extra alias names
pCalleeExtension, // remote extension
pNonStandardData, // local non-standard data
NULL, // remote non-standard data
pszDisplay, // local display
NULL, // remote display
NULL, // remote vendor info
NULL, // local connect address
pConnectAddr, // peer connect address
pDestinationAddr, // peer destination address
NULL, // source call signal address
CallType, // call type
bCallerIsMC,
dwUserToken, // user token
CallState, // call state
dwBandwidth,
&pConference->ConferenceID,
&pCall);
if (status != CC_OK) {
UnlockConference(pConference);
LeaveCallControlTop(status);
}
#ifdef GATEKEEPER
// Fill in Gatekeeper Call fields
memset(&pCall->GkiCall, 0, sizeof(pCall->GkiCall));
if (pCalleeAliasNames != NULL) {
// make a local copy of the peer alias names
status = Q931CopyAliasNames(&pCall->GkiCall.pCalleeAliasNames, pCalleeAliasNames);
if (status != CS_OK) {
FreeCall(pCall);
UnlockConference(pConference);
LeaveCallControlTop(status);
}
}
if (pCalleeExtraAliasNames != NULL) {
// make a local copy of the peer alias names
status = Q931CopyAliasNames(&pCall->GkiCall.pCalleeExtraAliasNames,
pCalleeExtraAliasNames);
if (status != CS_OK) {
FreeCall(pCall);
UnlockConference(pConference);
LeaveCallControlTop(status);
}
}
pCall->GkiCall.pCall = pCall;
pCall->GkiCall.hCall = hCall;
pCall->GkiCall.pConferenceId = pCall->ConferenceID.buffer;
pCall->GkiCall.bActiveMC = pCall->bCallerIsMC;
pCall->GkiCall.bAnswerCall = FALSE;
if (pCall->pQ931PeerConnectAddr) {
pCall->GkiCall.dwIpAddress = ADDRToInetAddr(pCall->pQ931PeerConnectAddr);
pCall->GkiCall.wPort = ADDRToInetPort(pCall->pQ931PeerConnectAddr);
} else if (pCall->pQ931DestinationAddr) {
pCall->GkiCall.dwIpAddress = ADDRToInetAddr(pCall->pQ931DestinationAddr);
pCall->GkiCall.wPort = ADDRToInetPort(pCall->pQ931DestinationAddr);
}
pCall->GkiCall.wPort = (WORD)((pCall->GkiCall.wPort<<8)|(pCall->GkiCall.wPort>>8));
if (pConference->bMultipointCapable)
pCall->GkiCall.CallType = MANY_TO_MANY;
else
pCall->GkiCall.CallType = POINT_TO_POINT;
pCall->GkiCall.uBandwidthRequested = dwBandwidth / 100;
status = GkiOpenCall(&pCall->GkiCall, pConference);
if (ValidateCall(hCall) == CC_OK) {
if (status == CC_OK) {
UnlockCall(pCall);
*phCall = hCall;
} else {
FreeCall(pCall);
}
}
if (ValidateConference(hConference) == CC_OK)
UnlockConference(pConference);
#else // GATEKEEPER
status = PlaceCall(pCall, pConference);
if (status == CC_OK) {
UnlockCall(pCall);
*phCall = hCall;
} else {
FreeCall(pCall);
}
UnlockConference(pConference);
#endif // GATEKEEPER
LeaveCallControlTop(status);
}
CC_API
HRESULT CC_RejectCall( BYTE bRejectReason,
PCC_NONSTANDARDDATA pNonStandardData,
CC_HCALL hCall)
{
HRESULT status;
HRESULT SaveStatus;
PCALL pCall;
HQ931CALL hQ931Call;
CC_CONFERENCEID ConferenceID;
EnterCallControlTop();
if (InitStatus != CC_OK)
LeaveCallControlTop(InitStatus);
if (CallControlState != OPERATIONAL_STATE)
LeaveCallControlTop(CC_INTERNAL_ERROR);
SaveStatus = CC_OK;
// validate parameters
if ((bRejectReason != CC_REJECT_IN_CONF) &&
(bRejectReason != CC_REJECT_UNDEFINED_REASON) &&
(bRejectReason != CC_REJECT_DESTINATION_REJECTION) &&
(bRejectReason != CC_REJECT_NO_ANSWER) &&
(bRejectReason != CC_REJECT_NOT_IMPLEMENTED) &&
(bRejectReason != CC_REJECT_USER_BUSY)) {
bRejectReason = CC_REJECT_UNDEFINED_REASON;
SaveStatus = CC_BAD_PARAM;
}
status = ValidateNonStandardData(pNonStandardData);
if (status != CC_OK)
LeaveCallControlTop(status);
if (hCall == CC_INVALID_HANDLE)
LeaveCallControlTop(CC_BAD_PARAM);
status = LockCall(hCall, &pCall);
if (status != CC_OK)
// note that we can't even tell Q931 to reject the call
LeaveCallControlTop(status);
if (pCall->CallState != INCOMING) {
UnlockCall(pCall);
LeaveCallControlTop(CC_BAD_PARAM);
}
hQ931Call = pCall->hQ931Call;
ConferenceID = pCall->ConferenceID;
FreeCall(pCall);
Q931RejectCall(hQ931Call, // Q931 call handle
bRejectReason, // reject reason
&ConferenceID,
NULL, // alternate address
pNonStandardData); // non-standard data
LeaveCallControlTop(SaveStatus);
}
CC_API
HRESULT CC_RejectChannel( CC_HCHANNEL hChannel,
DWORD dwRejectReason)
{
HRESULT status;
PCHANNEL pChannel;
PCALL pCall;
PCONFERENCE pConference;
EnterCallControlTop();
if (InitStatus != CC_OK)
LeaveCallControlTop(InitStatus);
if (CallControlState != OPERATIONAL_STATE)
LeaveCallControlTop(CC_INTERNAL_ERROR);
if (hChannel == CC_INVALID_HANDLE)
LeaveCallControlTop(CC_BAD_PARAM);
if ((dwRejectReason != H245_REJ) &&
(dwRejectReason != H245_REJ_TYPE_NOTSUPPORT) &&
(dwRejectReason != H245_REJ_TYPE_NOTAVAIL) &&
(dwRejectReason != H245_REJ_TYPE_UNKNOWN) &&
(dwRejectReason != H245_REJ_AL_COMB) &&
(dwRejectReason != H245_REJ_MULTICAST) &&
(dwRejectReason != H245_REJ_BANDWIDTH) &&
(dwRejectReason != H245_REJ_SESSION_ID) &&
(dwRejectReason != H245_REJ_MASTER_SLAVE_CONFLICT))
LeaveCallControlTop(CC_BAD_PARAM);
status = LockChannelAndConference(hChannel, &pChannel, &pConference);
if (status != CC_OK)
LeaveCallControlTop(status);
// Make sure that hChannel is a receive, proxy or bi-directional
// channel that hasn't already been accepted
if (((pChannel->bChannelType != RX_CHANNEL) &&
(pChannel->bChannelType != PROXY_CHANNEL) &&
(pChannel->bChannelType != TXRX_CHANNEL)) ||
(pChannel->tsAccepted != TS_UNKNOWN)) {
UnlockConference(pConference);
UnlockChannel(pChannel);
LeaveCallControlTop(CC_BAD_PARAM);
}
if (pConference->LocalEndpointAttached != ATTACHED) {
UnlockChannel(pChannel);
UnlockConference(pConference);
LeaveCallControlTop(CC_BAD_PARAM);
}
pChannel->tsAccepted = TS_FALSE;
if (pChannel->wNumOutstandingRequests == 0) {
ASSERT(pChannel->bMultipointChannel == TRUE);
ASSERT(pChannel->bChannelType == PROXY_CHANNEL);
ASSERT(pConference->ConferenceMode == MULTIPOINT_MODE);
ASSERT(pConference->tsMultipointController == TS_TRUE);
UnlockConference(pConference);
UnlockChannel(pChannel);
LeaveCallControlTop(CC_OK);
}
(pChannel->wNumOutstandingRequests)--;
if (pChannel->wNumOutstandingRequests == 0) {
status = LockCall(pChannel->hCall, &pCall);
if (status != CC_OK) {
UnlockConference(pConference);
FreeChannel(pChannel);
LeaveCallControlTop(status);
}
status = H245OpenChannelReject(pCall->H245Instance,
pChannel->wRemoteChannelNumber, // Rx channel
(WORD)dwRejectReason); // rejection reason
UnlockCall(pCall);
FreeChannel(pChannel);
UnlockConference(pConference);
LeaveCallControlTop(status);
}
// Don't free the channel; it is a PROXY_CHANNEL and we're the MC,
// so we need to keep the channel object around until the peer that
// opened it closes it.
ASSERT(pChannel->bMultipointChannel == TRUE);
ASSERT(pChannel->bChannelType == PROXY_CHANNEL);
ASSERT(pConference->ConferenceMode == MULTIPOINT_MODE);
ASSERT(pConference->tsMultipointController == TS_TRUE);
UnlockChannel(pChannel);
UnlockConference(pConference);
LeaveCallControlTop(status);
}
CC_API
HRESULT CC_RequestMode( CC_HCALL hCall,
WORD wNumModeDescriptions,
ModeDescription ModeDescriptions[])
{
HRESULT status;
PCALL pCall;
PCONFERENCE pConference;
EnterCallControlTop();
if (InitStatus != CC_OK)
LeaveCallControlTop(InitStatus);
if (CallControlState != OPERATIONAL_STATE)
LeaveCallControlTop(CC_INTERNAL_ERROR);
if (hCall == CC_INVALID_HANDLE)
LeaveCallControlTop(CC_BAD_PARAM);
if (wNumModeDescriptions == 0)
LeaveCallControlTop(CC_BAD_PARAM);
if (ModeDescriptions == NULL)
LeaveCallControlTop(CC_BAD_PARAM);
status = LockCallAndConference(hCall, &pCall, &pConference);
if (status != CC_OK)
LeaveCallControlTop(status);
if ((pConference->LocalEndpointAttached != ATTACHED) ||
(pCall->CallState != CALL_COMPLETE) ||
(pCall->CallType == VIRTUAL_CALL)) {
UnlockCall(pCall);
UnlockConference(pConference);
LeaveCallControlTop(CC_BAD_PARAM);
}
status = H245RequestMode(pCall->H245Instance,
pCall->H245Instance, // trans ID
ModeDescriptions,
wNumModeDescriptions);
UnlockCall(pCall);
UnlockConference(pConference);
LeaveCallControlTop(status);
}
CC_API
HRESULT CC_RequestModeResponse( CC_HCALL hCall,
CC_REQUEST_MODE_RESPONSE RequestModeResponse)
{
HRESULT status;
PCALL pCall;
PCONFERENCE pConference;
BOOL bAccept;
EnterCallControlTop();
if (InitStatus != CC_OK)
LeaveCallControlTop(InitStatus);
if (CallControlState != OPERATIONAL_STATE)
LeaveCallControlTop(CC_INTERNAL_ERROR);
if (hCall == CC_INVALID_HANDLE)
LeaveCallControlTop(CC_BAD_PARAM);
switch (RequestModeResponse) {
case CC_WILL_TRANSMIT_PREFERRED_MODE:
RequestModeResponse = wllTrnsmtMstPrfrrdMd_chosen;
bAccept = TRUE;
break;
case CC_WILL_TRANSMIT_LESS_PREFERRED_MODE:
RequestModeResponse = wllTrnsmtLssPrfrrdMd_chosen;
bAccept = TRUE;
break;
case CC_MODE_UNAVAILABLE:
RequestModeResponse = H245_REJ_UNAVAILABLE;
bAccept = FALSE;
break;
case CC_MULTIPOINT_CONSTRAINT:
RequestModeResponse = H245_REJ_MULTIPOINT;
bAccept = FALSE;
break;
case CC_REQUEST_DENIED:
RequestModeResponse = H245_REJ_DENIED;
bAccept = FALSE;
break;
default:
LeaveCallControlTop(CC_BAD_PARAM);
}
status = LockCallAndConference(hCall, &pCall, &pConference);
if (status != CC_OK)
LeaveCallControlTop(status);
status = DequeueSpecificRequest(&pConference->pEnqueuedRequestModeCalls,
hCall);
if (status != CC_OK) {
UnlockCall(pCall);
UnlockConference(pConference);
LeaveCallControlTop(status);
}
if (bAccept == TRUE) {
status = H245RequestModeAck(pCall->H245Instance,
(WORD)RequestModeResponse);
} else {
status = H245RequestModeReject(pCall->H245Instance,
(WORD)RequestModeResponse);
}
UnlockCall(pCall);
UnlockConference(pConference);
LeaveCallControlTop(status);
}
CC_API
HRESULT CC_SendNonStandardMessage( CC_HCALL hCall,
BYTE bH245MessageType,
PCC_NONSTANDARDDATA pNonStandardData)
{
HRESULT status;
PCALL pCall;
PCONFERENCE pConference;
H245_MESSAGE_TYPE_T H245MessageType;
EnterCallControlTop();
if (InitStatus != CC_OK)
LeaveCallControlTop(InitStatus);
if (CallControlState != OPERATIONAL_STATE)
LeaveCallControlTop(CC_INTERNAL_ERROR);
// validate parameters
if (hCall == CC_INVALID_HANDLE)
LeaveCallControlTop(CC_BAD_PARAM);
switch (bH245MessageType) {
case CC_H245_MESSAGE_REQUEST:
H245MessageType = H245_MESSAGE_REQUEST;
break;
case CC_H245_MESSAGE_RESPONSE:
H245MessageType = H245_MESSAGE_RESPONSE;
break;
case CC_H245_MESSAGE_COMMAND:
H245MessageType = H245_MESSAGE_COMMAND;
break;
case CC_H245_MESSAGE_INDICATION:
H245MessageType = H245_MESSAGE_INDICATION;
break;
default:
LeaveCallControlTop(CC_BAD_PARAM);
}
status = ValidateNonStandardData(pNonStandardData);
if (status != CC_OK)
LeaveCallControlTop(status);
status = LockCallAndConference(hCall,
&pCall,
&pConference);
if (status != CC_OK)
LeaveCallControlTop(status);
if ((pConference->LocalEndpointAttached != ATTACHED) ||
(pCall->CallState != CALL_COMPLETE) ||
(pCall->CallType == VIRTUAL_CALL)) {
UnlockCall(pCall);
UnlockConference(pConference);
LeaveCallControlTop(CC_BAD_PARAM);
}
status = H245NonStandardH221(pCall->H245Instance,
H245MessageType,
pNonStandardData->sData.pOctetString,
pNonStandardData->sData.wOctetStringLength,
pNonStandardData->bCountryCode,
pNonStandardData->bExtension,
pNonStandardData->wManufacturerCode);
UnlockCall(pCall);
UnlockConference(pConference);
LeaveCallControlTop(status);
}
CC_API
HRESULT CC_SendVendorID( CC_HCALL hCall,
CC_NONSTANDARDDATA NonStandardData,
PCC_OCTETSTRING pProductNumber,
PCC_OCTETSTRING pVersionNumber)
{
HRESULT status;
PCALL pCall;
PCONFERENCE pConference;
BYTE *pH245ProductNumber;
BYTE bProductNumberLength;
BYTE *pH245VersionNumber;
BYTE bVersionNumberLength;
H245_NONSTANDID_T H245Identifier;
EnterCallControlTop();
if (InitStatus != CC_OK)
LeaveCallControlTop(InitStatus);
if (CallControlState != OPERATIONAL_STATE)
LeaveCallControlTop(CC_INTERNAL_ERROR);
// validate parameters
if (hCall == CC_INVALID_HANDLE)
LeaveCallControlTop(CC_BAD_PARAM);
status = ValidateNonStandardData(&NonStandardData);
if (status != CC_OK)
LeaveCallControlTop(status);
status = ValidateOctetString(pProductNumber);
if (status != CC_OK)
LeaveCallControlTop(status);
if (pProductNumber != NULL)
if (pProductNumber->wOctetStringLength > 255)
LeaveCallControlTop(CC_BAD_PARAM);
status = ValidateOctetString(pVersionNumber);
if (status != CC_OK)
LeaveCallControlTop(status);
if (pVersionNumber != NULL)
if (pVersionNumber->wOctetStringLength > 255)
LeaveCallControlTop(CC_BAD_PARAM);
status = LockCallAndConference(hCall,
&pCall,
&pConference);
if (status != CC_OK)
LeaveCallControlTop(status);
if ((pConference->LocalEndpointAttached != ATTACHED) ||
(pCall->CallState != CALL_COMPLETE) ||
(pCall->CallType == VIRTUAL_CALL)) {
UnlockCall(pCall);
UnlockConference(pConference);
LeaveCallControlTop(CC_BAD_PARAM);
}
H245Identifier.choice = h221NonStandard_chosen;
H245Identifier.u.h221NonStandard.t35CountryCode = NonStandardData.bCountryCode;
H245Identifier.u.h221NonStandard.t35Extension = NonStandardData.bExtension;
H245Identifier.u.h221NonStandard.manufacturerCode = NonStandardData.wManufacturerCode;
if (pProductNumber == NULL) {
pH245ProductNumber = NULL;
bProductNumberLength = 0;
} else {
pH245ProductNumber = pProductNumber->pOctetString;
bProductNumberLength = (BYTE)pProductNumber->wOctetStringLength;
}
if (pVersionNumber == NULL) {
pH245VersionNumber = NULL;
bVersionNumberLength = 0;
} else {
pH245VersionNumber = pVersionNumber->pOctetString;
bVersionNumberLength = (BYTE)pVersionNumber->wOctetStringLength;
}
status = H245VendorIdentification(pCall->H245Instance,
&H245Identifier,
pH245ProductNumber,
bProductNumberLength,
pH245VersionNumber,
bVersionNumberLength);
UnlockCall(pCall);
UnlockConference(pConference);
LeaveCallControlTop(status);
}
CC_API
HRESULT CC_SetCallControlTimeout( WORD wType,
DWORD dwDuration)
{
HRESULT status;
DWORD dwRequest;
DWORD dwSaveDuration;
EnterCallControlTop();
if (CallControlState != OPERATIONAL_STATE)
LeaveCallControlTop(CC_INTERNAL_ERROR);
status = CC_OK;
switch (wType) {
case CC_Q931_ALERTING_TIMEOUT:
status = Q931SetAlertingTimeout(dwDuration);
break;
case CC_H245_RETRY_COUNT:
status = H245SystemControl(0, H245_SYSCON_SET_FSM_N100, &dwDuration);
break;
case CC_H245_TIMEOUT:
dwRequest = H245_SYSCON_SET_FSM_T101;
dwSaveDuration = dwDuration;
while ((dwRequest <= H245_SYSCON_SET_FSM_T109) && (status == CC_OK)) {
dwDuration = dwSaveDuration;
// Note -- the following call resets dwDuration
status = H245SystemControl(0, dwRequest, &dwDuration);
dwRequest += (H245_SYSCON_SET_FSM_T102 - H245_SYSCON_SET_FSM_T101);
}
break;
default :
LeaveCallControlTop(CC_BAD_PARAM);
break;
}
LeaveCallControlTop(status);
}
CC_API
HRESULT CC_SetTerminalID( CC_HCONFERENCE hConference,
PCC_OCTETSTRING pTerminalID)
{
HRESULT status;
PCONFERENCE pConference;
CC_HCALL hCall;
PCALL pCall;
if (InitStatus != CC_OK)
LeaveCallControlTop(InitStatus);
if (CallControlState != OPERATIONAL_STATE)
LeaveCallControlTop(CC_INTERNAL_ERROR);
// validate parameters
if (hConference == CC_INVALID_HANDLE)
LeaveCallControlTop(CC_BAD_PARAM);
status = ValidateTerminalID(pTerminalID);
if (status != CC_OK)
LeaveCallControlTop(status);
status = LockConference(hConference, &pConference);
if (status != CC_OK)
LeaveCallControlTop(status);
if (pConference->LocalParticipantInfo.TerminalIDState == TERMINAL_ID_VALID) {
pConference->LocalParticipantInfo.TerminalIDState = TERMINAL_ID_INVALID;
Free(pConference->LocalParticipantInfo.ParticipantInfo.TerminalID.pOctetString);
pConference->LocalParticipantInfo.ParticipantInfo.TerminalID.pOctetString = NULL;
pConference->LocalParticipantInfo.ParticipantInfo.TerminalID.wOctetStringLength = 0;
}
if ((pTerminalID == NULL) ||
(pTerminalID->pOctetString == NULL) ||
(pTerminalID->wOctetStringLength == 0)) {
UnlockConference(pConference);
LeaveCallControlTop(CC_OK);
}
pConference->LocalParticipantInfo.ParticipantInfo.TerminalID.pOctetString =
(BYTE *)Malloc(pTerminalID->wOctetStringLength);
if (pConference->LocalParticipantInfo.ParticipantInfo.TerminalID.pOctetString == NULL) {
UnlockConference(pConference);
LeaveCallControlTop(CC_NO_MEMORY);
}
memcpy(pConference->LocalParticipantInfo.ParticipantInfo.TerminalID.pOctetString,
pTerminalID->pOctetString,
pTerminalID->wOctetStringLength);
pConference->LocalParticipantInfo.ParticipantInfo.TerminalID.wOctetStringLength =
pTerminalID->wOctetStringLength;
pConference->LocalParticipantInfo.TerminalIDState = TERMINAL_ID_VALID;
while (DequeueRequest(&pConference->LocalParticipantInfo.pEnqueuedRequestsForTerminalID,
&hCall) == CC_OK) {
if (LockCall(hCall, &pCall) == CC_OK) {
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);
LeaveCallControlTop(CC_OK);
}
CC_API
HRESULT CC_Shutdown()
{
if (InitStatus != CC_OK)
LeaveCallControlTop(InitStatus);
if (CallControlState == SHUTDOWN_STATE)
LeaveCallControlTop(CC_OK);
if (CallControlState != OPERATIONAL_STATE)
LeaveCallControlTop(CC_BAD_PARAM);
#ifdef GATEKEEPER
DeInitGkiManager();
#endif // GATEKEEPER
// Don't allow any additional threads to enter this DLL
CallControlState = SHUTDOWN_STATE;
Q931DeInit();
DeInitHangupManager();
DeInitUserManager();
DeInitQ931Manager();
DeInitListenManager();
DeInitH245Manager();
DeInitChannelManager();
DeInitCallManager();
DeInitConferenceManager();
LeaveCallControlTop(CC_OK);
}
CC_API
HRESULT CC_UnMute( CC_HCHANNEL hChannel)
{
HRESULT status;
HRESULT SaveStatus;
PCHANNEL pChannel;
PCONFERENCE pConference;
PCALL pCall;
PDU_T Pdu;
WORD wNumCalls;
PCC_HCALL CallList;
WORD i;
EnterCallControlTop();
if (InitStatus != CC_OK)
LeaveCallControlTop(InitStatus);
if (CallControlState != OPERATIONAL_STATE)
LeaveCallControlTop(CC_INTERNAL_ERROR);
if (hChannel == CC_INVALID_HANDLE)
LeaveCallControlTop(CC_BAD_PARAM);
status = LockChannelAndConference(hChannel, &pChannel, &pConference);
if (status != CC_OK)
LeaveCallControlTop(status);
if (pChannel->bChannelType != TX_CHANNEL) {
// can only unmute transmit channels
UnlockConference(pConference);
UnlockChannel(pChannel);
LeaveCallControlTop(CC_BAD_PARAM);
}
if (pConference->LocalEndpointAttached != ATTACHED) {
UnlockChannel(pChannel);
UnlockConference(pConference);
LeaveCallControlTop(CC_BAD_PARAM);
}
status = EnumerateCallsInConference(&wNumCalls, &CallList, pConference, ESTABLISHED_CALL);
if (status != CC_OK) {
UnlockConference(pConference);
UnlockChannel(pChannel);
LeaveCallControlTop(status);
}
// Construct an H.245 PDU to hold a miscellaneous indication
// of "logical channel active"
Pdu.choice = indication_chosen;
Pdu.u.indication.choice = miscellaneousIndication_chosen;
Pdu.u.indication.u.miscellaneousIndication.logicalChannelNumber =
pChannel->wLocalChannelNumber;
Pdu.u.indication.u.miscellaneousIndication.type.choice = logicalChannelActive_chosen;
SaveStatus = CC_OK;
for (i = 0; i < wNumCalls; i++) {
if (LockCall(CallList[i], &pCall) == CC_OK) {
status = H245SendPDU(pCall->H245Instance, // H245 instance
&Pdu);
// Note that this channel may not have been accepted on all of the calls,
// so we could get an H245_ERROR_INVALID_CHANNEL error
if ((status != H245_ERROR_OK) && (status != H245_ERROR_INVALID_CHANNEL))
SaveStatus = status;
UnlockCall(pCall);
}
}
if (CallList != NULL)
Free(CallList);
UnlockConference(pConference);
UnlockChannel(pChannel);
LeaveCallControlTop(SaveStatus);
}
CC_API
HRESULT CC_UpdatePeerList( CC_HCONFERENCE hConference)
{
HRESULT status;
PCONFERENCE pConference;
PCALL pCall;
WORD wNumCalls;
WORD i;
PCC_HCALL CallList;
CC_PEER_ADD_CALLBACK_PARAMS PeerAddCallbackParams;
EnterCallControlTop();
if (InitStatus != CC_OK)
LeaveCallControlTop(InitStatus);
if (CallControlState != OPERATIONAL_STATE)
LeaveCallControlTop(CC_INTERNAL_ERROR);
if (hConference == CC_INVALID_HANDLE)
LeaveCallControlTop(CC_BAD_PARAM);
status = LockConference(hConference, &pConference);
if (status != CC_OK)
LeaveCallControlTop(status);
if ((pConference->ConferenceMode != MULTIPOINT_MODE) ||
(pConference->LocalEndpointAttached != ATTACHED)) {
UnlockConference(pConference);
LeaveCallControlTop(CC_BAD_PARAM);
}
if (pConference->tsMultipointController == TS_TRUE) {
EnumerateCallsInConference(&wNumCalls, &CallList, pConference, ESTABLISHED_CALL);
for (i = 0; i < wNumCalls; i++) {
if (LockCall(CallList[i], &pCall) == CC_OK) {
if (pCall->pPeerParticipantInfo != NULL) {
PeerAddCallbackParams.hCall = pCall->hCall;
PeerAddCallbackParams.TerminalLabel =
pCall->pPeerParticipantInfo->ParticipantInfo.TerminalLabel;
if (pCall->pPeerParticipantInfo->TerminalIDState == TERMINAL_ID_VALID)
PeerAddCallbackParams.pPeerTerminalID =
&pCall->pPeerParticipantInfo->ParticipantInfo.TerminalID;
else
PeerAddCallbackParams.pPeerTerminalID = NULL;
InvokeUserConferenceCallback(pConference,
CC_PEER_ADD_INDICATION,
CC_OK,
&PeerAddCallbackParams);
if (ValidateCall(CallList[i]) == CC_OK)
UnlockCall(pCall);
if (ValidateConference(hConference) != CC_OK) {
Free(CallList);
LeaveCallControlTop(CC_OK);
}
} else // pCall->pPeerParticipantInfo == NULL
UnlockCall(pCall);
}
}
status = CC_OK;
} else { // pConference->tsMultipointController != TS_TRUE
EnumerateCallsInConference(&wNumCalls, &CallList, pConference, VIRTUAL_CALL);
for (i = 0; i < wNumCalls; i++) {
if (LockCall(CallList[i], &pCall) == CC_OK) {
FreeCall(pCall);
}
}
if (CallList != NULL)
Free(CallList);
EnumerateCallsInConference(&wNumCalls, &CallList, pConference, ESTABLISHED_CALL);
ASSERT((wNumCalls == 0) || (wNumCalls == 1));
if (wNumCalls == 1) {
if (LockCall(CallList[0], &pCall) == CC_OK) {
// Send TerminalListRequest
status = H245ConferenceRequest(pCall->H245Instance,
H245_REQ_TERMINAL_LIST,
pConference->LocalParticipantInfo.ParticipantInfo.TerminalLabel.bMCUNumber,
pConference->LocalParticipantInfo.ParticipantInfo.TerminalLabel.bTerminalNumber);
UnlockCall(pCall);
}
}
}
if (CallList != NULL)
Free(CallList);
UnlockConference(pConference);
LeaveCallControlTop(status);
}
CC_API
HRESULT CC_UserInput( CC_HCALL hCall,
PWSTR pszUserInput)
{
HRESULT status;
PCALL pCall;
PCONFERENCE pConference;
EnterCallControlTop();
if (InitStatus != CC_OK)
LeaveCallControlTop(InitStatus);
if (CallControlState != OPERATIONAL_STATE)
LeaveCallControlTop(CC_INTERNAL_ERROR);
if (hCall == CC_INVALID_HANDLE)
LeaveCallControlTop(CC_BAD_PARAM);
if (pszUserInput == NULL)
LeaveCallControlTop(CC_BAD_PARAM);
if (wcslen(pszUserInput) == 0)
LeaveCallControlTop(CC_BAD_PARAM);
status = LockCallAndConference(hCall, &pCall, &pConference);
if (status != CC_OK)
LeaveCallControlTop(status);
if ((pConference->LocalEndpointAttached != ATTACHED) ||
(pCall->CallState != CALL_COMPLETE) ||
(pCall->CallType == VIRTUAL_CALL)) {
UnlockCall(pCall);
UnlockConference(pConference);
LeaveCallControlTop(CC_BAD_PARAM);
}
status = H245UserInput(pCall->H245Instance,
pszUserInput,
NULL);
UnlockCall(pCall);
UnlockConference(pConference);
LeaveCallControlTop(status);
}