/**************************************************************************** * * $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 $ * $Date: 03 Mar 1997 19:40:58 $ * $Author: MANDREWS $ * * Deliverable: * * Abstract: * * * Notes: * ***************************************************************************/ #define CALL_CONTROL_EXPORT #include "precomp.h" #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); extern HRESULT GkiRegister(void); extern HRESULT GkiListenAddr(SOCKADDR_IN* psin); extern HRESULT GkiUnregister(void); extern VOID GKI_SetGKAddress(PSOCKADDR_IN pAddr); extern BOOL fGKEnabled; extern RASNOTIFYPROC gpRasNotifyProc; #define GKI_MAX_BANDWIDTH (0xFFFFFFFF / 100) #endif // GATEKEEPER VOID InitCallControl(); 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; extern CC_CONFERENCEID InvalidConferenceID; #define _Unicode(x) L ## x #define Unicode(x) _Unicode(x) WORD ADDRToInetPort(CC_ADDR *pAddr); DWORD ADDRToInetAddr(CC_ADDR *pAddr); #ifdef _DEBUG static const PSTR c_apszDbgZones[] = { "CallCont", DEFAULT_ZONES }; #endif // _DEBUG BOOL WINAPI DllMain( 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); #ifdef _DEBUG MLZ_DbgInit((PSTR *) &c_apszDbgZones[0], (sizeof(c_apszDbgZones) / sizeof(c_apszDbgZones[0])) - 1); #endif DBG_INIT_MEMORY_TRACKING(hInstDll); InitializeLock(&ThreadCount.Lock); ThreadCount.wNumThreads = 0; // 6/25/98 InitCallControl(); H245_InitModule(); 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 H245_TermModule(); DeleteLock(&ThreadCount.Lock); DBG_CHECK_MEMORY_TRACKING(hInstDll); #ifdef _DEBUG MLZ_DbgDeInit(); #endif break; } return TRUE; } VOID InitCallControl() { #ifdef FORCE_SERIALIZE_CALL_CONTROL InitStatus = InitializeCCLock(); if (InitStatus != CC_OK) return; #endif InitStatus = H225Init(); if (InitStatus != CC_OK) return; #ifdef GATEKEEPER InitStatus = InitGkiManager(); // an error return is OK for now. Run totally gatekeeper-less // if (InitStatus != CC_OK) // #endif // GATEKEEPER InitStatus = InitConferenceManager(); if (InitStatus != CC_OK) return; InitStatus = InitCallManager(); if (InitStatus != CC_OK) return; InitStatus = InitChannelManager(); if (InitStatus != CC_OK) return; InitStatus = InitH245Manager(); if (InitStatus != CC_OK) return; InitStatus = InitListenManager(); if (InitStatus != CC_OK) return; InitStatus = InitQ931Manager(); if (InitStatus != CC_OK) return; InitStatus = InitUserManager(); if (InitStatus != CC_OK) return; InitStatus = InitHangupManager(); if (InitStatus != CC_OK) return; InitStatus = Q931Init(); if (InitStatus != CS_OK) return; CallControlState = OPERATIONAL_STATE; } CC_API HRESULT CC_Initialize() { if (CallControlState == OPERATIONAL_STATE) { return (CC_OK); } else if((CallControlState == INITIALIZING_STATE) || (CallControlState == SHUTDOWN_STATE)) { InitCallControl(); } return (InitStatus); } CC_API HRESULT CC_AcceptCall( CC_HCONFERENCE hConference, PCC_NONSTANDARDDATA pNonStandardData, PWSTR pszDisplay, CC_HCALL hCall, DWORD dwBandwidth, DWORD_PTR 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 if(GKIExists()) { 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->pSourceCallSignalAddress) { pCall->GkiCall.dwIpAddress = ADDRToInetAddr(pCall->pSourceCallSignalAddress); pCall->GkiCall.wPort = pCall->pSourceCallSignalAddress->Addr.IP_Binary.wPort; } else { pCall->GkiCall.dwIpAddress = ADDRToInetAddr(pCall->pQ931PeerConnectAddr); pCall->GkiCall.wPort = pCall->pQ931PeerConnectAddr->Addr.IP_Binary.wPort; } pCall->GkiCall.CallIdentifier = pCall->CallIdentifier; 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 { status = AcceptCall(pCall, pConference); } #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 dwChannelBitRate) { 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 if(GKIExists()) { pChannel->dwChannelBitRate = dwChannelBitRate; UnlockChannel(pChannel); UnlockConference(pConference); status = GkiOpenChannel(&pCall->GkiCall, dwChannelBitRate, hChannel, RX); if (ValidateCall(hCall) == CC_OK) UnlockCall(pCall); } else { 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); } #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); } } } MemFree(CallList); } UnlockChannel(pChannel); UnlockConference(pConference); LeaveCallControlTop(CC_OK); } CC_API HRESULT CC_CallListen( PCC_HLISTEN phListen, PCC_ADDR pListenAddr, PCC_ALIASNAMES pLocalAliasNames, DWORD_PTR 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 if (GkiOpenListen(*phListen, pLocalAliasNames, pListenAddr->Addr.IP_Binary.dwAddr, pListenAddr->Addr.IP_Binary.wPort) != NOERROR) { WARNING_OUT(("CC_CallListen - Gatekeeper init failed (GkiOpenListen), but still support H.323 calls")); } UnlockListen(pListen); #else status = UnlockListen(pListen); #endif // GATEKEEPER LeaveCallControlTop(status); } CC_API HRESULT CC_EnableGKRegistration( BOOL fEnable, PSOCKADDR_IN pAddr, PCC_ALIASNAMES pLocalAliasNames, PCC_VENDORINFO pVendorInfo, DWORD dwMultipointConfiguration, RASNOTIFYPROC pRasNotifyProc) { HRESULT status = CC_OK; if(!pRasNotifyProc) return CC_BAD_PARAM; gpRasNotifyProc = pRasNotifyProc; EnterCallControlTop(); if(fEnable) { ASSERT(pLocalAliasNames && pAddr && pVendorInfo); if(!pLocalAliasNames || !pAddr) LeaveCallControlTop(CC_BAD_PARAM); status = GkiSetRegistrationAliases(pLocalAliasNames); if(status != CC_OK) LeaveCallControlTop(status); status = GkiSetVendorConfig(pVendorInfo, dwMultipointConfiguration); if(status != CC_OK) LeaveCallControlTop(status); GKI_SetGKAddress(pAddr); GkiListenAddr(pAddr); status = GkiRegister(); fGKEnabled = TRUE; } else { status = GkiUnregister(); fGKEnabled = FALSE; GkiSetRegistrationAliases(NULL); GkiSetVendorConfig(NULL, 0); } 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(GKIExists()) { 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(GKIExists()) { if (pChannel->bChannelType != TXRX_CHANNEL) { if (pChannel->bMultipointChannel) { // Multicast channel bandwidth is assigned to arbitrary call uBandwidth = pChannel->dwChannelBitRate / 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->dwChannelBitRate, 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(GKIExists()) { 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->dwChannelBitRate, 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) MemFree(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); // this is asynchronously released in _ConfClose(), in h245man.c } 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) MemFree(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_PTR 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); } 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 if(GKIExists()) { 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) MemFree(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 *)MemAlloc(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) MemFree(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_PTR 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) MemFree(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) MemFree(ChannelList); if (pConference->bDeferredDelete) { ASSERT(pConference->LocalEndpointAttached == DETACHED); FreeConference(pConference); } else { // // Set DETACHED _before_ callback; that will call // CC_DestroyConference, which will call AsynchronousDestroyConference, // which will not do anything if we are still sttached. // if (pConference->LocalEndpointAttached != DETACHED) { pConference->LocalEndpointAttached = DETACHED; if (pConference->ConferenceCallback) { pConference->ConferenceCallback(CC_HANGUP_INDICATION, CC_OK, pConference->hConference, pConference->dwConferenceToken, &HangupCallbackParams); } } if (ValidateConference(hConference) == CC_OK) { 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) MemFree(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) MemFree(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) MemFree(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) MemFree(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 { // // Set DETACHED _before_ callback; that will call // CC_DestroyConference, which will call AsynchronousDestroyConference, // which will not do anything if we are still sttached. // if (pConference->LocalEndpointAttached != DETACHED) { pConference->LocalEndpointAttached = DETACHED; if (pConference->ConferenceCallback) { pConference->ConferenceCallback(CC_HANGUP_INDICATION, SaveStatus, pConference->hConference, pConference->dwConferenceToken, &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) MemFree(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) MemFree(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 dwChannelBitRate, DWORD_PTR 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]; MemFree(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 &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 if(GKIExists()) { pChannel->dwChannelBitRate = dwChannelBitRate; 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, dwChannelBitRate, *phChannel, TX); if (ValidateCall(CallList[0]) == CC_OK) UnlockCall(pCall); } MemFree(CallList); LeaveCallControlTop(status); } else { 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) MemFree(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); } #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) MemFree(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 dwChannelBitRate, DWORD_PTR 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 = dwChannelBitRate; 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 &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); } } MemFree(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_PTR dwUserToken) { PCALL pCall; CC_HCALL hCall; PCONFERENCE pConference; HRESULT status; CALLTYPE CallType = CALLER; CALLSTATE CallState = PLACED; WORD wNumCalls; BOOL bCallerIsMC; GUID CallIdent; 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; // generate CallIdentifier status = CoCreateGuid(&CallIdent); if(status != S_OK) { // forget what MSDN and other MS documentation says about this // -- If there is no net card, some rev's of OS return an error // in cases where a reasonable GUID is generated, but not GUARANTEED // to be GLOBALLY unique. // if that's not good enough, then just use the uninitialized // value of CallIdent - whatever was on the stack is our GUID!! // But I want to know in debug builds ASSERT(0); } 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, // pSourceCallSignalAddress, CallType, // call type bCallerIsMC, dwUserToken, // user token CallState, // call state &CallIdent, // H225 CallIdentifier &pConference->ConferenceID, &pCall); if (status != CC_OK) { UnlockConference(pConference); LeaveCallControlTop(status); } #ifdef GATEKEEPER if(GKIExists()) { // 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; pCall->GkiCall.CallIdentifier = pCall->CallIdentifier; 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); } if (pCall->GkiCall.wPort == 0) pCall->GkiCall.wPort = CC_H323_HOST_CALL; 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 { // clean GkiCall structure just to be safe. memset(&pCall->GkiCall, 0, sizeof(pCall->GkiCall)); status = PlaceCall(pCall, pConference); if (status == CC_OK) { UnlockCall(pCall); *phCall = hCall; } else { FreeCall(pCall); } 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_SECURITY_DENIED) && (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_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, CC_NONSTANDARDDATA NonStandardData) { 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(&NonStandardData); 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, NonStandardData.sData.pOctetString, NonStandardData.sData.wOctetStringLength, NonStandardData.bCountryCode, NonStandardData.bExtension, NonStandardData.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; MemFree(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 *)MemAlloc(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) return InitStatus; if (CallControlState != OPERATIONAL_STATE) return CC_BAD_PARAM; // Don't allow any additional threads to enter this DLL CallControlState = SHUTDOWN_STATE; Q931DeInit(); DeInitHangupManager(); DeInitUserManager(); DeInitQ931Manager(); DeInitListenManager(); DeInitH245Manager(); DeInitChannelManager(); DeInitCallManager(); DeInitConferenceManager(); #ifdef GATEKEEPER DeInitGkiManager(); #endif // GATEKEEPER H225DeInit(); #ifdef FORCE_SERIALIZE_CALL_CONTROL UnInitializeCCLock(); #endif return 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) MemFree(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) { MemFree(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) MemFree(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) MemFree(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); }