Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

4520 lines
134 KiB

  1. /****************************************************************************
  2. *
  3. * $Archive: S:/STURGEON/SRC/CALLCONT/VCS/callcont.c_v $
  4. *
  5. * INTEL Corporation Prorietary Information
  6. *
  7. * This listing is supplied under the terms of a license agreement
  8. * with INTEL Corporation and may not be copied nor disclosed except
  9. * in accordance with the terms of that agreement.
  10. *
  11. * Copyright (c) 1993-1994 Intel Corporation.
  12. *
  13. * $Revision: 1.208 $
  14. * $Date: 03 Mar 1997 19:40:58 $
  15. * $Author: MANDREWS $
  16. *
  17. * Deliverable:
  18. *
  19. * Abstract:
  20. *
  21. *
  22. * Notes:
  23. *
  24. ***************************************************************************/
  25. #define CALL_CONTROL_EXPORT
  26. #include "precomp.h"
  27. #include "apierror.h"
  28. #include "incommon.h"
  29. #include "callcont.h"
  30. #ifdef FORCE_SERIALIZE_CALL_CONTROL
  31. #include "cclock.h"
  32. #endif // FORCE_SERIALIZE_CALL_CONTROL
  33. #include "q931.h"
  34. #include "ccmain.h"
  35. #include "confman.h"
  36. #include "listman.h"
  37. #include "q931man.h"
  38. #include "h245man.h"
  39. #include "callman.h"
  40. #include "userman.h"
  41. #include "chanman.h"
  42. #include "hangman.h"
  43. #include "linkapi.h"
  44. #include "h245api.h"
  45. #include "ccutils.h"
  46. #ifdef GATEKEEPER
  47. HRESULT InitGkiManager(void);
  48. void DeInitGkiManager(void);
  49. extern HRESULT GkiRegister(void);
  50. extern HRESULT GkiListenAddr(SOCKADDR_IN* psin);
  51. extern HRESULT GkiUnregister(void);
  52. extern VOID GKI_SetGKAddress(PSOCKADDR_IN pAddr);
  53. extern BOOL fGKEnabled;
  54. extern RASNOTIFYPROC gpRasNotifyProc;
  55. #define GKI_MAX_BANDWIDTH (0xFFFFFFFF / 100)
  56. #endif // GATEKEEPER
  57. VOID InitCallControl();
  58. CALL_CONTROL_STATE CallControlState = INITIALIZING_STATE;
  59. BOOL bISDMLoaded = FALSE;
  60. static HRESULT InitStatus;
  61. // NumThreads counts the number of threads which are executing code within this DLL.
  62. // NumThreads must be incremented at each DLL entry point (which includes each API
  63. // call, the Q931 callback location and the H245 callback location).
  64. // NumThreads must be decremented upon DLL exit. The macro LeaveCallControlTop()
  65. // is used to facilitate this operation. Note that LeaveCallControlTop may accept
  66. // a function call as a parameter; we must call the function first, save its return
  67. // value, then decrement NumThreads, and finally return the saved value.
  68. THREADCOUNT ThreadCount;
  69. extern CC_CONFERENCEID InvalidConferenceID;
  70. #define _Unicode(x) L ## x
  71. #define Unicode(x) _Unicode(x)
  72. WORD ADDRToInetPort(CC_ADDR *pAddr);
  73. DWORD ADDRToInetAddr(CC_ADDR *pAddr);
  74. #ifdef _DEBUG
  75. static const PSTR c_apszDbgZones[] =
  76. {
  77. "CallCont",
  78. DEFAULT_ZONES
  79. };
  80. #endif // _DEBUG
  81. BOOL WINAPI DllMain( HINSTANCE hInstDll,
  82. DWORD fdwReason,
  83. LPVOID lpvReserved)
  84. {
  85. switch (fdwReason) {
  86. case DLL_PROCESS_ATTACH:
  87. // The DLL is being mapped into the process's address space
  88. ASSERT(CallControlState == INITIALIZING_STATE);
  89. ASSERT(CC_OK == CS_OK);
  90. ASSERT(CC_OK == H245_ERROR_OK);
  91. #ifdef _DEBUG
  92. MLZ_DbgInit((PSTR *) &c_apszDbgZones[0],
  93. (sizeof(c_apszDbgZones) / sizeof(c_apszDbgZones[0])) - 1);
  94. #endif
  95. DBG_INIT_MEMORY_TRACKING(hInstDll);
  96. InitializeLock(&ThreadCount.Lock);
  97. ThreadCount.wNumThreads = 0;
  98. // 6/25/98 InitCallControl();
  99. H245_InitModule();
  100. break;
  101. case DLL_THREAD_ATTACH:
  102. // A thread is being created
  103. break;
  104. case DLL_THREAD_DETACH:
  105. // A thread is exiting cleanly
  106. break;
  107. case DLL_PROCESS_DETACH:
  108. // The DLL is being unmapped from the process's address space
  109. H245_TermModule();
  110. DeleteLock(&ThreadCount.Lock);
  111. DBG_CHECK_MEMORY_TRACKING(hInstDll);
  112. #ifdef _DEBUG
  113. MLZ_DbgDeInit();
  114. #endif
  115. break;
  116. }
  117. return TRUE;
  118. }
  119. VOID InitCallControl()
  120. {
  121. #ifdef FORCE_SERIALIZE_CALL_CONTROL
  122. InitStatus = InitializeCCLock();
  123. if (InitStatus != CC_OK)
  124. return;
  125. #endif
  126. InitStatus = H225Init();
  127. if (InitStatus != CC_OK)
  128. return;
  129. #ifdef GATEKEEPER
  130. InitStatus = InitGkiManager();
  131. // an error return is OK for now. Run totally gatekeeper-less
  132. // if (InitStatus != CC_OK)
  133. //
  134. #endif // GATEKEEPER
  135. InitStatus = InitConferenceManager();
  136. if (InitStatus != CC_OK)
  137. return;
  138. InitStatus = InitCallManager();
  139. if (InitStatus != CC_OK)
  140. return;
  141. InitStatus = InitChannelManager();
  142. if (InitStatus != CC_OK)
  143. return;
  144. InitStatus = InitH245Manager();
  145. if (InitStatus != CC_OK)
  146. return;
  147. InitStatus = InitListenManager();
  148. if (InitStatus != CC_OK)
  149. return;
  150. InitStatus = InitQ931Manager();
  151. if (InitStatus != CC_OK)
  152. return;
  153. InitStatus = InitUserManager();
  154. if (InitStatus != CC_OK)
  155. return;
  156. InitStatus = InitHangupManager();
  157. if (InitStatus != CC_OK)
  158. return;
  159. InitStatus = Q931Init();
  160. if (InitStatus != CS_OK)
  161. return;
  162. CallControlState = OPERATIONAL_STATE;
  163. }
  164. CC_API
  165. HRESULT CC_Initialize()
  166. {
  167. if (CallControlState == OPERATIONAL_STATE)
  168. {
  169. return (CC_OK);
  170. }
  171. else if((CallControlState == INITIALIZING_STATE) || (CallControlState == SHUTDOWN_STATE))
  172. {
  173. InitCallControl();
  174. }
  175. return (InitStatus);
  176. }
  177. CC_API
  178. HRESULT CC_AcceptCall( CC_HCONFERENCE hConference,
  179. PCC_NONSTANDARDDATA pNonStandardData,
  180. PWSTR pszDisplay,
  181. CC_HCALL hCall,
  182. DWORD dwBandwidth,
  183. DWORD_PTR dwUserToken)
  184. {
  185. HRESULT status;
  186. PCALL pCall;
  187. PCONFERENCE pConference;
  188. HQ931CALL hQ931Call;
  189. WORD wNumCalls;
  190. CC_ADDR AlternateAddr;
  191. PCC_ADDR pAlternateAddr;
  192. BOOL bAccept = FALSE;
  193. BYTE bRejectReason = CC_REJECT_UNDEFINED_REASON;
  194. CC_CONFERENCEID ConferenceID;
  195. EnterCallControlTop();
  196. if (InitStatus != CC_OK)
  197. LeaveCallControlTop(InitStatus);
  198. if (CallControlState != OPERATIONAL_STATE)
  199. LeaveCallControlTop(CC_INTERNAL_ERROR);
  200. // validate parameters
  201. if (hConference == CC_INVALID_HANDLE)
  202. LeaveCallControlTop(CC_BAD_PARAM);
  203. if (hCall == CC_INVALID_HANDLE)
  204. LeaveCallControlTop(CC_BAD_PARAM);
  205. status = ValidateNonStandardData(pNonStandardData);
  206. if (status != CC_OK)
  207. LeaveCallControlTop(status);
  208. status = LockCall(hCall, &pCall);
  209. if (status != CC_OK)
  210. // note that we can't even tell Q931 to reject the call
  211. LeaveCallControlTop(status);
  212. if (pCall->CallState != INCOMING) {
  213. UnlockCall(pCall);
  214. LeaveCallControlTop(CC_BAD_PARAM);
  215. }
  216. ASSERT(pCall->hConference == CC_INVALID_HANDLE);
  217. hQ931Call = pCall->hQ931Call;
  218. ConferenceID = pCall->ConferenceID;
  219. status = AddLocalNonStandardDataToCall(pCall, pNonStandardData);
  220. if (status != CC_OK) {
  221. FreeCall(pCall);
  222. Q931RejectCall(hQ931Call, // Q931 call handle
  223. CC_REJECT_UNDEFINED_REASON, // reject reason
  224. &ConferenceID,
  225. NULL, // alternate address
  226. pNonStandardData); // non-standard data
  227. LeaveCallControlTop(status);
  228. }
  229. status = AddLocalDisplayToCall(pCall, pszDisplay);
  230. if (status != CC_OK) {
  231. FreeCall(pCall);
  232. Q931RejectCall(hQ931Call, // Q931 call handle
  233. CC_REJECT_UNDEFINED_REASON, // reject reason
  234. &ConferenceID,
  235. NULL, // alternate address
  236. pNonStandardData); // non-standard data
  237. LeaveCallControlTop(status);
  238. }
  239. UnlockCall(pCall);
  240. status = LockConferenceEx(hConference,
  241. &pConference,
  242. TS_FALSE); // bDeferredDelete
  243. if (status == CC_OK) {
  244. status = LockCall(hCall, &pCall);
  245. if (status != CC_OK) {
  246. UnlockConference(pConference);
  247. LeaveCallControlTop(status);
  248. }
  249. } else
  250. LeaveCallControlTop(status);
  251. if ((pCall->bCallerIsMC == TRUE) &&
  252. ((pConference->tsMultipointController == TS_TRUE) ||
  253. (pConference->bMultipointCapable == FALSE))) {
  254. FreeCall(pCall);
  255. UnlockConference(pConference);
  256. Q931RejectCall(hQ931Call, // Q931 call handle
  257. CC_REJECT_UNDEFINED_REASON, // reject reason
  258. &ConferenceID,
  259. NULL, // alternate address
  260. pNonStandardData); // non-standard data
  261. if (pConference->bMultipointCapable == FALSE) {
  262. LeaveCallControlTop(CC_BAD_PARAM);
  263. } else {
  264. LeaveCallControlTop(CC_NOT_MULTIPOINT_CAPABLE);
  265. }
  266. }
  267. EnumerateCallsInConference(&wNumCalls, NULL, pConference, REAL_CALLS);
  268. if ((wNumCalls > 0) &&
  269. (pConference->bMultipointCapable == FALSE)) {
  270. FreeCall(pCall);
  271. UnlockConference(pConference);
  272. Q931RejectCall(hQ931Call, // Q931 call handle
  273. CC_REJECT_UNDEFINED_REASON, // reject reason
  274. &ConferenceID,
  275. NULL, // alternate address
  276. pNonStandardData); // non-standard data
  277. LeaveCallControlTop(CC_NOT_MULTIPOINT_CAPABLE);
  278. }
  279. pAlternateAddr = NULL;
  280. if (EqualConferenceIDs(&pCall->ConferenceID, &pConference->ConferenceID)) {
  281. if (wNumCalls > 0) {
  282. if (pConference->tsMultipointController == TS_TRUE) {
  283. // Accept Call
  284. status = CC_OK;
  285. bAccept = TRUE;
  286. } else { // we're not the MC
  287. if (pConference->bMultipointCapable) {
  288. if (pConference->pMultipointControllerAddr != NULL) {
  289. // Reject Call - route to MC
  290. status = CC_OK;
  291. bAccept = FALSE;
  292. bRejectReason = CC_REJECT_ROUTE_TO_MC;
  293. AlternateAddr = *pConference->pMultipointControllerAddr;
  294. pAlternateAddr = &AlternateAddr;
  295. } else { // we don't have the MC's address
  296. // XXX -- we may eventually want to enqueue the request
  297. // and set an expiration timer
  298. // Error - no MC
  299. status = CC_NOT_MULTIPOINT_CAPABLE;
  300. }
  301. } else { // we're not multipoint capable
  302. // Error - bad param
  303. status = CC_BAD_PARAM;
  304. }
  305. }
  306. } else { // wNumCalls == 0
  307. // Accept Call
  308. status = CC_OK;
  309. bAccept = TRUE;
  310. }
  311. } else { // pCall->ConferenceID != pConference->ConferenceID
  312. if (EqualConferenceIDs(&pConference->ConferenceID, &InvalidConferenceID)) {
  313. // Accept Call
  314. status = CC_OK;
  315. bAccept = TRUE;
  316. } else { // pConferenceID != InvalidConferenceID
  317. if (pConference->tsMultipointController == TS_TRUE) {
  318. // Reject Call - route to MC
  319. status = CC_OK;
  320. bAccept = FALSE;
  321. bRejectReason = CC_REJECT_ROUTE_TO_MC;
  322. pAlternateAddr = &AlternateAddr;
  323. if (GetLastListenAddress(pAlternateAddr) != CC_OK) {
  324. pAlternateAddr = NULL;
  325. bRejectReason = CC_REJECT_UNDEFINED_REASON;
  326. }
  327. } else { // we're not the MC
  328. if (pConference->bMultipointCapable) {
  329. if (pConference->pMultipointControllerAddr) {
  330. // Reject Call - route to MC
  331. status = CC_OK;
  332. bAccept = FALSE;
  333. bRejectReason = CC_REJECT_ROUTE_TO_MC;
  334. AlternateAddr = *pConference->pMultipointControllerAddr;
  335. pAlternateAddr = &AlternateAddr;
  336. } else { // we don't have the MC's address
  337. // XXX -- we may eventually want to enqueue the request
  338. // and set an expiration timer
  339. // Error - no MC
  340. status = CC_NOT_MULTIPOINT_CAPABLE;
  341. }
  342. } else { // we're not multipoint capable
  343. // Error - bad param
  344. status = CC_BAD_PARAM;
  345. }
  346. }
  347. }
  348. }
  349. if (status != CC_OK) {
  350. FreeCall(pCall);
  351. UnlockConference(pConference);
  352. LeaveCallControlTop(status);
  353. }
  354. if (bAccept) {
  355. pCall->dwUserToken = dwUserToken;
  356. #ifdef GATEKEEPER
  357. if(GKIExists())
  358. {
  359. pCall->hConference = hConference;
  360. // Fill in Gatekeeper Call fields
  361. memset(&pCall->GkiCall, 0, sizeof(pCall->GkiCall));
  362. pCall->GkiCall.pCall = pCall;
  363. pCall->GkiCall.hCall = hCall;
  364. pCall->GkiCall.pConferenceId = pCall->ConferenceID.buffer;
  365. pCall->GkiCall.bActiveMC = pCall->bCallerIsMC;
  366. pCall->GkiCall.bAnswerCall = TRUE;
  367. if(pCall->pSourceCallSignalAddress)
  368. {
  369. pCall->GkiCall.dwIpAddress = ADDRToInetAddr(pCall->pSourceCallSignalAddress);
  370. pCall->GkiCall.wPort = pCall->pSourceCallSignalAddress->Addr.IP_Binary.wPort;
  371. }
  372. else
  373. {
  374. pCall->GkiCall.dwIpAddress = ADDRToInetAddr(pCall->pQ931PeerConnectAddr);
  375. pCall->GkiCall.wPort = pCall->pQ931PeerConnectAddr->Addr.IP_Binary.wPort;
  376. }
  377. pCall->GkiCall.CallIdentifier = pCall->CallIdentifier;
  378. if (pConference->bMultipointCapable)
  379. pCall->GkiCall.CallType = MANY_TO_MANY;
  380. else
  381. pCall->GkiCall.CallType = POINT_TO_POINT;
  382. pCall->GkiCall.uBandwidthRequested = dwBandwidth / 100;
  383. status = GkiOpenCall(&pCall->GkiCall, pConference);
  384. // GkiOpenCall may or may not have called AcceptCall, which unlocks
  385. // call and conference and may or may not free the call
  386. if (ValidateCall(hCall) == CC_OK)
  387. if (status == CC_OK)
  388. UnlockCall(pCall);
  389. else
  390. FreeCall(pCall);
  391. if (ValidateConference(hConference) == CC_OK)
  392. UnlockConference(pConference);
  393. if (status != CC_OK)
  394. {
  395. Q931RejectCall( hQ931Call, // Q931 call handle
  396. CC_REJECT_GATEKEEPER_RESOURCES, // reject reason
  397. &ConferenceID,
  398. NULL, // alternate address
  399. pNonStandardData); // non-standard data
  400. }
  401. }
  402. else
  403. {
  404. status = AcceptCall(pCall, pConference);
  405. }
  406. #else // GATEKEEPER
  407. status = AcceptCall(pCall, pConference);
  408. #endif // GATEKEEPER
  409. LeaveCallControlTop(status);
  410. } else { // bAccept == FALSE
  411. FreeCall(pCall);
  412. if (bRejectReason == CC_REJECT_ROUTE_TO_MC) {
  413. ASSERT(pAlternateAddr != NULL);
  414. ConferenceID = pConference->ConferenceID;
  415. } else
  416. pAlternateAddr = NULL;
  417. UnlockConference(pConference);
  418. status = Q931RejectCall(hQ931Call, // Q931 call handle
  419. bRejectReason, // reject reason
  420. &ConferenceID,
  421. pAlternateAddr, // alternate address
  422. pNonStandardData); // non-standard data
  423. LeaveCallControlTop(status);
  424. }
  425. }
  426. CC_API
  427. HRESULT CC_AcceptChannel( CC_HCHANNEL hChannel,
  428. PCC_ADDR pRTPAddr,
  429. PCC_ADDR pRTCPAddr,
  430. DWORD dwChannelBitRate)
  431. {
  432. HRESULT status;
  433. PCHANNEL pChannel;
  434. PCONFERENCE pConference;
  435. CC_HCALL hCall;
  436. PCALL pCall;
  437. //#ifndef GATEKEEPER
  438. H245_MUX_T H245MuxTable;
  439. WORD i;
  440. CC_ACCEPT_CHANNEL_CALLBACK_PARAMS Params;
  441. CC_HCONFERENCE hConference;
  442. //#endif // !GATEKEEPER
  443. EnterCallControlTop();
  444. if (InitStatus != CC_OK)
  445. LeaveCallControlTop(InitStatus);
  446. if (CallControlState != OPERATIONAL_STATE)
  447. LeaveCallControlTop(CC_INTERNAL_ERROR);
  448. if (hChannel == CC_INVALID_HANDLE)
  449. LeaveCallControlTop(CC_BAD_PARAM);
  450. if (pRTCPAddr != NULL)
  451. if ((pRTCPAddr->nAddrType != CC_IP_BINARY) ||
  452. (pRTCPAddr->bMulticast == TRUE))
  453. LeaveCallControlTop(CC_BAD_PARAM);
  454. status = LockChannelAndConference(hChannel, &pChannel, &pConference);
  455. if (status != CC_OK)
  456. LeaveCallControlTop(status);
  457. // Make sure that hChannel is a receive or proxy channel that
  458. // hasn't already been accepted
  459. if (((pChannel->bChannelType != RX_CHANNEL) &&
  460. (pChannel->bChannelType != PROXY_CHANNEL)) ||
  461. (pChannel->tsAccepted != TS_UNKNOWN)) {
  462. UnlockChannel(pChannel);
  463. UnlockConference(pConference);
  464. LeaveCallControlTop(CC_BAD_PARAM);
  465. }
  466. if (pChannel->bMultipointChannel) {
  467. if ((pRTPAddr != NULL) || (pRTCPAddr != NULL)) {
  468. UnlockChannel(pChannel);
  469. UnlockConference(pConference);
  470. LeaveCallControlTop(CC_BAD_PARAM);
  471. }
  472. } else
  473. if ((pRTPAddr == NULL) || (pRTCPAddr == NULL)) {
  474. UnlockChannel(pChannel);
  475. UnlockConference(pConference);
  476. LeaveCallControlTop(CC_BAD_PARAM);
  477. }
  478. if (pConference->LocalEndpointAttached != ATTACHED) {
  479. UnlockChannel(pChannel);
  480. UnlockConference(pConference);
  481. LeaveCallControlTop(CC_BAD_PARAM);
  482. }
  483. hCall = pChannel->hCall;
  484. status = LockCall(hCall, &pCall);
  485. if (status != CC_OK) {
  486. UnlockChannel(pChannel);
  487. UnlockConference(pConference);
  488. LeaveCallControlTop(status);
  489. }
  490. if (pChannel->bMultipointChannel == FALSE) {
  491. status = AddLocalAddrPairToChannel(pRTPAddr, pRTCPAddr, pChannel);
  492. if (status != CC_OK) {
  493. UnlockCall(pCall);
  494. UnlockChannel(pChannel);
  495. UnlockConference(pConference);
  496. LeaveCallControlTop(status);
  497. }
  498. }
  499. #ifdef GATEKEEPER
  500. if(GKIExists())
  501. {
  502. pChannel->dwChannelBitRate = dwChannelBitRate;
  503. UnlockChannel(pChannel);
  504. UnlockConference(pConference);
  505. status = GkiOpenChannel(&pCall->GkiCall, dwChannelBitRate, hChannel, RX);
  506. if (ValidateCall(hCall) == CC_OK)
  507. UnlockCall(pCall);
  508. }
  509. else
  510. {
  511. if (pChannel->wNumOutstandingRequests != 0)
  512. {
  513. if ((pChannel->bMultipointChannel) &&
  514. (pConference->tsMultipointController == TS_TRUE))
  515. {
  516. // Supply the RTP and RTCP addresses in the OpenLogicalChannelAck
  517. if (pConference->pSessionTable != NULL) {
  518. for (i = 0; i < pConference->pSessionTable->wLength; i++) {
  519. if (pConference->pSessionTable->SessionInfoArray[i].bSessionID ==
  520. pChannel->bSessionID) {
  521. pRTPAddr = pConference->pSessionTable->SessionInfoArray[i].pRTPAddr;
  522. pRTCPAddr = pConference->pSessionTable->SessionInfoArray[i].pRTCPAddr;
  523. break;
  524. }
  525. }
  526. }
  527. }
  528. H245MuxTable.Kind = H245_H2250ACK;
  529. H245MuxTable.u.H2250ACK.nonStandardList = NULL;
  530. if (pRTPAddr != NULL) {
  531. if (pRTPAddr->bMulticast)
  532. H245MuxTable.u.H2250ACK.mediaChannel.type = H245_IP_MULTICAST;
  533. else
  534. H245MuxTable.u.H2250ACK.mediaChannel.type = H245_IP_UNICAST;
  535. H245MuxTable.u.H2250ACK.mediaChannel.u.ip.tsapIdentifier =
  536. pRTPAddr->Addr.IP_Binary.wPort;
  537. HostToH245IPNetwork(H245MuxTable.u.H2250ACK.mediaChannel.u.ip.network,
  538. pRTPAddr->Addr.IP_Binary.dwAddr);
  539. H245MuxTable.u.H2250ACK.mediaChannelPresent = TRUE;
  540. } else
  541. H245MuxTable.u.H2250ACK.mediaChannelPresent = FALSE;
  542. if (pRTCPAddr != NULL) {
  543. if (pRTCPAddr->bMulticast)
  544. H245MuxTable.u.H2250ACK.mediaControlChannel.type = H245_IP_MULTICAST;
  545. else
  546. H245MuxTable.u.H2250ACK.mediaControlChannel.type = H245_IP_UNICAST;
  547. H245MuxTable.u.H2250ACK.mediaControlChannel.u.ip.tsapIdentifier =
  548. pRTCPAddr->Addr.IP_Binary.wPort;
  549. HostToH245IPNetwork(H245MuxTable.u.H2250ACK.mediaControlChannel.u.ip.network,
  550. pRTCPAddr->Addr.IP_Binary.dwAddr);
  551. H245MuxTable.u.H2250ACK.mediaControlChannelPresent = TRUE;
  552. } else
  553. H245MuxTable.u.H2250ACK.mediaControlChannelPresent = FALSE;
  554. H245MuxTable.u.H2250ACK.dynamicRTPPayloadTypePresent = FALSE;
  555. H245MuxTable.u.H2250ACK.sessionIDPresent = TRUE;
  556. H245MuxTable.u.H2250ACK.sessionID = pChannel->bSessionID;
  557. status = H245OpenChannelAccept(pCall->H245Instance,
  558. 0, // dwTransId
  559. pChannel->wRemoteChannelNumber, // Rx channel
  560. &H245MuxTable,
  561. 0, // Tx channel
  562. NULL, // Tx mux
  563. H245_INVALID_PORT_NUMBER,// Port
  564. pChannel->pSeparateStack);
  565. if (status == CC_OK)
  566. pChannel->wNumOutstandingRequests = 0;
  567. else
  568. --(pChannel->wNumOutstandingRequests);
  569. }
  570. pChannel->tsAccepted = TS_TRUE;
  571. Params.hChannel = hChannel;
  572. if (status == CC_OK)
  573. UnlockChannel(pChannel);
  574. else
  575. FreeChannel(pChannel);
  576. UnlockCall(pCall);
  577. hConference = pConference->hConference;
  578. InvokeUserConferenceCallback(pConference,
  579. CC_ACCEPT_CHANNEL_INDICATION,
  580. status,
  581. &Params);
  582. if (ValidateConference(hConference) == CC_OK)
  583. UnlockConference(pConference);
  584. }
  585. #else // GATEKEEPER
  586. if (pChannel->wNumOutstandingRequests != 0) {
  587. if ((pChannel->bMultipointChannel) &&
  588. (pConference->tsMultipointController == TS_TRUE)) {
  589. // Supply the RTP and RTCP addresses in the OpenLogicalChannelAck
  590. if (pConference->pSessionTable != NULL) {
  591. for (i = 0; i < pConference->pSessionTable->wLength; i++) {
  592. if (pConference->pSessionTable->SessionInfoArray[i].bSessionID ==
  593. pChannel->bSessionID) {
  594. pRTPAddr = pConference->pSessionTable->SessionInfoArray[i].pRTPAddr;
  595. pRTCPAddr = pConference->pSessionTable->SessionInfoArray[i].pRTCPAddr;
  596. break;
  597. }
  598. }
  599. }
  600. }
  601. H245MuxTable.Kind = H245_H2250ACK;
  602. H245MuxTable.u.H2250ACK.nonStandardList = NULL;
  603. if (pRTPAddr != NULL) {
  604. if (pRTPAddr->bMulticast)
  605. H245MuxTable.u.H2250ACK.mediaChannel.type = H245_IP_MULTICAST;
  606. else
  607. H245MuxTable.u.H2250ACK.mediaChannel.type = H245_IP_UNICAST;
  608. H245MuxTable.u.H2250ACK.mediaChannel.u.ip.tsapIdentifier =
  609. pRTPAddr->Addr.IP_Binary.wPort;
  610. HostToH245IPNetwork(H245MuxTable.u.H2250ACK.mediaChannel.u.ip.network,
  611. pRTPAddr->Addr.IP_Binary.dwAddr);
  612. H245MuxTable.u.H2250ACK.mediaChannelPresent = TRUE;
  613. } else
  614. H245MuxTable.u.H2250ACK.mediaChannelPresent = FALSE;
  615. if (pRTCPAddr != NULL) {
  616. if (pRTCPAddr->bMulticast)
  617. H245MuxTable.u.H2250ACK.mediaControlChannel.type = H245_IP_MULTICAST;
  618. else
  619. H245MuxTable.u.H2250ACK.mediaControlChannel.type = H245_IP_UNICAST;
  620. H245MuxTable.u.H2250ACK.mediaControlChannel.u.ip.tsapIdentifier =
  621. pRTCPAddr->Addr.IP_Binary.wPort;
  622. HostToH245IPNetwork(H245MuxTable.u.H2250ACK.mediaControlChannel.u.ip.network,
  623. pRTCPAddr->Addr.IP_Binary.dwAddr);
  624. H245MuxTable.u.H2250ACK.mediaControlChannelPresent = TRUE;
  625. } else
  626. H245MuxTable.u.H2250ACK.mediaControlChannelPresent = FALSE;
  627. H245MuxTable.u.H2250ACK.dynamicRTPPayloadTypePresent = FALSE;
  628. H245MuxTable.u.H2250ACK.sessionIDPresent = TRUE;
  629. H245MuxTable.u.H2250ACK.sessionID = pChannel->bSessionID;
  630. status = H245OpenChannelAccept(pCall->H245Instance,
  631. 0, // dwTransId
  632. pChannel->wRemoteChannelNumber, // Rx channel
  633. &H245MuxTable,
  634. 0, // Tx channel
  635. NULL, // Tx mux
  636. H245_INVALID_PORT_NUMBER,// Port
  637. pChannel->pSeparateStack);
  638. if (status == CC_OK)
  639. pChannel->wNumOutstandingRequests = 0;
  640. else
  641. --(pChannel->wNumOutstandingRequests);
  642. }
  643. pChannel->tsAccepted = TS_TRUE;
  644. Params.hChannel = hChannel;
  645. if (status == CC_OK)
  646. UnlockChannel(pChannel);
  647. else
  648. FreeChannel(pChannel);
  649. UnlockCall(pCall);
  650. hConference = pConference->hConference;
  651. InvokeUserConferenceCallback(pConference,
  652. CC_ACCEPT_CHANNEL_INDICATION,
  653. status,
  654. &Params);
  655. if (ValidateConference(hConference) == CC_OK)
  656. UnlockConference(pConference);
  657. #endif // GATEKEEPER
  658. LeaveCallControlTop(status);
  659. }
  660. CC_API
  661. HRESULT CC_AcceptT120Channel( CC_HCHANNEL hChannel,
  662. BOOL bAssociateConference,
  663. PCC_OCTETSTRING pExternalReference,
  664. PCC_ADDR pAddr)
  665. {
  666. HRESULT status;
  667. PCHANNEL pChannel;
  668. PCALL pCall;
  669. PCONFERENCE pConference;
  670. H245_ACCESS_T SeparateStack;
  671. H245_ACCESS_T *pSeparateStack;
  672. H245_MUX_T H245MuxTable;
  673. WORD i;
  674. WORD wNumCalls;
  675. PCC_HCALL CallList;
  676. EnterCallControlTop();
  677. if (InitStatus != CC_OK)
  678. LeaveCallControlTop(InitStatus);
  679. if (CallControlState != OPERATIONAL_STATE)
  680. LeaveCallControlTop(CC_INTERNAL_ERROR);
  681. if (hChannel == CC_INVALID_HANDLE)
  682. LeaveCallControlTop(CC_BAD_PARAM);
  683. if (pAddr != NULL)
  684. if ((pAddr->nAddrType != CC_IP_BINARY) ||
  685. (pAddr->bMulticast == TRUE))
  686. LeaveCallControlTop(CC_BAD_PARAM);
  687. status = LockChannelAndConference(hChannel, &pChannel, &pConference);
  688. if (status != CC_OK)
  689. LeaveCallControlTop(status);
  690. // Make sure that hChannel is a bidirectional channel that was
  691. // not opened locally and hasn't already been accepted or rejected
  692. if ((pChannel->bChannelType != TXRX_CHANNEL) ||
  693. (pChannel->tsAccepted != TS_UNKNOWN) ||
  694. (pChannel->bLocallyOpened == TRUE)) {
  695. UnlockChannel(pChannel);
  696. UnlockConference(pConference);
  697. LeaveCallControlTop(CC_BAD_PARAM);
  698. }
  699. // If the remote endpoint specified a channel address, it will
  700. // be contained in the SeparateStack field, and we are not
  701. // allowed to specify another address in pAddr;
  702. // if the remote endpoint did not specify a channel address,
  703. // we must specify one now
  704. if (((pChannel->pSeparateStack == NULL) && (pAddr == NULL)) ||
  705. ((pChannel->pSeparateStack != NULL) && (pAddr != NULL))) {
  706. UnlockChannel(pChannel);
  707. UnlockConference(pConference);
  708. LeaveCallControlTop(CC_BAD_PARAM);
  709. }
  710. if (pConference->LocalEndpointAttached != ATTACHED) {
  711. UnlockChannel(pChannel);
  712. UnlockConference(pConference);
  713. LeaveCallControlTop(CC_BAD_PARAM);
  714. }
  715. // Add the SeparateStack field to the channel, if necessary
  716. if (pAddr != NULL) {
  717. SeparateStack.bit_mask = distribution_present;
  718. SeparateStack.distribution.choice = unicast_chosen;
  719. if (pExternalReference != NULL) {
  720. SeparateStack.bit_mask |= externalReference_present;
  721. SeparateStack.externalReference.length = pExternalReference->wOctetStringLength;
  722. memcpy(SeparateStack.externalReference.value,
  723. pExternalReference->pOctetString,
  724. pExternalReference->wOctetStringLength);
  725. }
  726. SeparateStack.networkAddress.choice = localAreaAddress_chosen;
  727. SeparateStack.networkAddress.u.localAreaAddress.choice = unicastAddress_chosen;
  728. SeparateStack.networkAddress.u.localAreaAddress.u.unicastAddress.choice = UnicastAddress_iPAddress_chosen;
  729. SeparateStack.networkAddress.u.localAreaAddress.u.unicastAddress.u.UnicastAddress_iPAddress.tsapIdentifier =
  730. pAddr->Addr.IP_Binary.wPort;
  731. SeparateStack.networkAddress.u.localAreaAddress.u.unicastAddress.u.UnicastAddress_iPAddress.network.length = 4;
  732. HostToH245IPNetwork(SeparateStack.networkAddress.u.localAreaAddress.u.unicastAddress.u.UnicastAddress_iPAddress.network.value,
  733. pAddr->Addr.IP_Binary.dwAddr);
  734. SeparateStack.associateConference = (char) bAssociateConference;
  735. pSeparateStack = &SeparateStack;
  736. AddSeparateStackToChannel(pSeparateStack, pChannel);
  737. } else
  738. pSeparateStack = NULL;
  739. // Send an ACK to the endpoint which requested the channel
  740. status = LockCall(pChannel->hCall, &pCall);
  741. if (status != CC_OK) {
  742. UnlockChannel(pChannel);
  743. UnlockConference(pConference);
  744. LeaveCallControlTop(status);
  745. }
  746. H245MuxTable.Kind = H245_H2250ACK;
  747. H245MuxTable.u.H2250ACK.nonStandardList = NULL;
  748. H245MuxTable.u.H2250ACK.mediaChannelPresent = FALSE;
  749. H245MuxTable.u.H2250ACK.mediaControlChannelPresent = FALSE;
  750. H245MuxTable.u.H2250ACK.dynamicRTPPayloadTypePresent = FALSE;
  751. H245MuxTable.u.H2250ACK.sessionIDPresent = FALSE;
  752. status = H245OpenChannelAccept(pCall->H245Instance, // dwInst
  753. 0, // dwTransId
  754. pChannel->wRemoteChannelNumber, // remote channel
  755. &H245MuxTable, // Rx Mux
  756. pChannel->wLocalChannelNumber, // local channel
  757. NULL, // Tx mux
  758. H245_INVALID_PORT_NUMBER,// Port
  759. pSeparateStack);
  760. if (status != CC_OK) {
  761. FreeChannel(pChannel);
  762. UnlockCall(pCall);
  763. UnlockConference(pConference);
  764. LeaveCallControlTop(status);
  765. }
  766. pChannel->tsAccepted = TS_TRUE;
  767. --(pChannel->wNumOutstandingRequests);
  768. UnlockCall(pCall);
  769. // If we're the MC in a multipoint conference, forward the
  770. // open T.120 channel request to all other endpoints in the conference
  771. if ((pConference->ConferenceMode == MULTIPOINT_MODE) &&
  772. (pConference->tsMultipointController == TS_TRUE)) {
  773. EnumerateCallsInConference(&wNumCalls, &CallList, pConference, ESTABLISHED_CALL);
  774. for (i = 0; i < wNumCalls; i++) {
  775. if (CallList[i] != pChannel->hCall) {
  776. if (LockCall(CallList[i], &pCall) == CC_OK) {
  777. status = H245OpenChannel(pCall->H245Instance, // H245 instance
  778. pChannel->hChannel, // dwTransId
  779. pChannel->wLocalChannelNumber,
  780. pChannel->pTxH245TermCap, // TxMode
  781. pChannel->pTxMuxTable, // TxMux
  782. H245_INVALID_PORT_NUMBER, // TxPort
  783. pChannel->pRxH245TermCap, // RxMode
  784. pChannel->pRxMuxTable, // RxMux
  785. pChannel->pSeparateStack);
  786. UnlockCall(pCall);
  787. }
  788. }
  789. }
  790. MemFree(CallList);
  791. }
  792. UnlockChannel(pChannel);
  793. UnlockConference(pConference);
  794. LeaveCallControlTop(CC_OK);
  795. }
  796. CC_API
  797. HRESULT CC_CallListen( PCC_HLISTEN phListen,
  798. PCC_ADDR pListenAddr,
  799. PCC_ALIASNAMES pLocalAliasNames,
  800. DWORD_PTR dwListenToken,
  801. CC_LISTEN_CALLBACK ListenCallback)
  802. {
  803. HRESULT status;
  804. PLISTEN pListen;
  805. HQ931LISTEN hQ931Listen;
  806. EnterCallControlTop();
  807. if (InitStatus != CC_OK)
  808. LeaveCallControlTop(InitStatus);
  809. if (CallControlState != OPERATIONAL_STATE)
  810. LeaveCallControlTop(CC_INTERNAL_ERROR);
  811. // validate parameters
  812. if (phListen == NULL)
  813. LeaveCallControlTop(CC_BAD_PARAM);
  814. // set phListen now, in case we encounter an error
  815. *phListen = CC_INVALID_HANDLE;
  816. if (pListenAddr == NULL)
  817. LeaveCallControlTop(CC_BAD_PARAM);
  818. status = ValidateAddr(pListenAddr);
  819. if (status != CC_OK)
  820. LeaveCallControlTop(status);
  821. status = Q931ValidateAliasNames(pLocalAliasNames);
  822. if (status != CS_OK)
  823. LeaveCallControlTop(status);
  824. if (ListenCallback == NULL)
  825. LeaveCallControlTop(CC_BAD_PARAM);
  826. status = SetQ931Port(pListenAddr);
  827. if (status != CS_OK)
  828. LeaveCallControlTop(status);
  829. status = AllocAndLockListen(phListen,
  830. pListenAddr,
  831. 0, // hQ931Listen
  832. pLocalAliasNames,
  833. dwListenToken,
  834. ListenCallback,
  835. &pListen);
  836. if (status != CC_OK)
  837. LeaveCallControlTop(status);
  838. // Unlock the listen object to prevent deadlock when calling Q931
  839. UnlockListen(pListen);
  840. status = Q931Listen(&hQ931Listen, pListenAddr,
  841. (DWORD)*phListen, (Q931_CALLBACK)Q931Callback);
  842. if (status != CS_OK) {
  843. if (LockListen(*phListen, &pListen) == CC_OK)
  844. FreeListen(pListen);
  845. *phListen = CC_INVALID_HANDLE;
  846. LeaveCallControlTop(status);
  847. }
  848. status = LockListen(*phListen, &pListen);
  849. if (status != CC_OK) {
  850. Q931CancelListen(hQ931Listen);
  851. LeaveCallControlTop(status);
  852. }
  853. ASSERT(pListenAddr != NULL);
  854. ASSERT(pListenAddr->nAddrType == CC_IP_BINARY);
  855. pListen->hQ931Listen = hQ931Listen;
  856. // Copy the binary form of the listen address into the listen object
  857. pListen->ListenAddr = *pListenAddr;
  858. #ifdef GATEKEEPER
  859. if (GkiOpenListen(*phListen,
  860. pLocalAliasNames,
  861. pListenAddr->Addr.IP_Binary.dwAddr,
  862. pListenAddr->Addr.IP_Binary.wPort) != NOERROR)
  863. {
  864. WARNING_OUT(("CC_CallListen - Gatekeeper init failed (GkiOpenListen), but still support H.323 calls"));
  865. }
  866. UnlockListen(pListen);
  867. #else
  868. status = UnlockListen(pListen);
  869. #endif // GATEKEEPER
  870. LeaveCallControlTop(status);
  871. }
  872. CC_API
  873. HRESULT CC_EnableGKRegistration(
  874. BOOL fEnable,
  875. PSOCKADDR_IN pAddr,
  876. PCC_ALIASNAMES pLocalAliasNames,
  877. PCC_VENDORINFO pVendorInfo,
  878. DWORD dwMultipointConfiguration,
  879. RASNOTIFYPROC pRasNotifyProc)
  880. {
  881. HRESULT status = CC_OK;
  882. if(!pRasNotifyProc)
  883. return CC_BAD_PARAM;
  884. gpRasNotifyProc = pRasNotifyProc;
  885. EnterCallControlTop();
  886. if(fEnable)
  887. {
  888. ASSERT(pLocalAliasNames && pAddr && pVendorInfo);
  889. if(!pLocalAliasNames || !pAddr)
  890. LeaveCallControlTop(CC_BAD_PARAM);
  891. status = GkiSetRegistrationAliases(pLocalAliasNames);
  892. if(status != CC_OK)
  893. LeaveCallControlTop(status);
  894. status = GkiSetVendorConfig(pVendorInfo, dwMultipointConfiguration);
  895. if(status != CC_OK)
  896. LeaveCallControlTop(status);
  897. GKI_SetGKAddress(pAddr);
  898. GkiListenAddr(pAddr);
  899. status = GkiRegister();
  900. fGKEnabled = TRUE;
  901. }
  902. else
  903. {
  904. status = GkiUnregister();
  905. fGKEnabled = FALSE;
  906. GkiSetRegistrationAliases(NULL);
  907. GkiSetVendorConfig(NULL, 0);
  908. }
  909. LeaveCallControlTop(status);
  910. }
  911. CC_API
  912. HRESULT CC_CancelCall( CC_HCALL hCall)
  913. {
  914. HRESULT status;
  915. PCALL pCall;
  916. PCONFERENCE pConference;
  917. HRESULT SaveStatus;
  918. H245_INST_T H245Instance;
  919. HQ931CALL hQ931Call;
  920. WORD wNumCalls;
  921. EnterCallControlTop();
  922. if (InitStatus != CC_OK)
  923. LeaveCallControlTop(InitStatus);
  924. if (CallControlState != OPERATIONAL_STATE)
  925. LeaveCallControlTop(CC_INTERNAL_ERROR);
  926. if (hCall == CC_INVALID_HANDLE)
  927. LeaveCallControlTop(CC_BAD_PARAM);
  928. status = LockCallAndConference(hCall, &pCall, &pConference);
  929. if (status != CC_OK)
  930. LeaveCallControlTop(status);
  931. if ((pCall->CallState != ENQUEUED) &&
  932. (pCall->CallState != PLACED) &&
  933. (pCall->CallState != RINGING) &&
  934. (pCall->CallState != TERMCAP)) {
  935. UnlockCall(pCall);
  936. UnlockConference(pConference);
  937. LeaveCallControlTop(CC_BAD_PARAM);
  938. }
  939. #ifdef GATEKEEPER
  940. if(GKIExists())
  941. {
  942. if (pCall->GkiCall.uGkiCallState != 0)
  943. {
  944. GkiCloseCall(&pCall->GkiCall);
  945. }
  946. }
  947. #endif // GATEKEEPER
  948. H245Instance = pCall->H245Instance;
  949. hQ931Call = pCall->hQ931Call;
  950. FreeCall(pCall);
  951. if (H245Instance != H245_INVALID_ID)
  952. SaveStatus = H245ShutDown(H245Instance);
  953. else
  954. SaveStatus = H245_ERROR_OK;
  955. if (hQ931Call != 0) {
  956. if (SaveStatus == H245_ERROR_OK) {
  957. SaveStatus = Q931Hangup(hQ931Call, CC_REJECT_UNDEFINED_REASON);
  958. // Q931Hangup may legitimately return CS_BAD_PARAM, because the Q.931 call object
  959. // may have been deleted at this point
  960. if (SaveStatus == CS_BAD_PARAM)
  961. SaveStatus = CC_OK;
  962. } else
  963. Q931Hangup(hQ931Call, CC_REJECT_UNDEFINED_REASON);
  964. }
  965. for ( ; ; ) {
  966. // Start up an enqueued call, if one exists
  967. status = RemoveEnqueuedCallFromConference(pConference, &hCall);
  968. if ((status != CC_OK) || (hCall == CC_INVALID_HANDLE))
  969. break;
  970. status = LockCall(hCall, &pCall);
  971. if (status == CC_OK) {
  972. pCall->CallState = PLACED;
  973. status = PlaceCall(pCall, pConference);
  974. UnlockCall(pCall);
  975. if (status == CC_OK)
  976. break;
  977. }
  978. }
  979. EnumerateCallsInConference(&wNumCalls, NULL, pConference, REAL_CALLS);
  980. if (wNumCalls == 0) {
  981. if (pConference->bDeferredDelete) {
  982. ASSERT(pConference->LocalEndpointAttached == DETACHED);
  983. FreeConference(pConference);
  984. } else {
  985. if ((pConference->ConferenceMode != MULTIPOINT_MODE) ||
  986. (pConference->tsMultipointController != TS_TRUE))
  987. ReInitializeConference(pConference);
  988. UnlockConference(pConference);
  989. }
  990. } else {
  991. UnlockConference(pConference);
  992. }
  993. if (SaveStatus != CC_OK)
  994. status = SaveStatus;
  995. LeaveCallControlTop(status);
  996. }
  997. CC_API
  998. HRESULT CC_CancelListen( CC_HLISTEN hListen)
  999. {
  1000. HRESULT status;
  1001. PLISTEN pListen;
  1002. HQ931LISTEN hQ931Listen;
  1003. EnterCallControlTop();
  1004. if (InitStatus != CC_OK)
  1005. LeaveCallControlTop(InitStatus);
  1006. if (CallControlState != OPERATIONAL_STATE)
  1007. LeaveCallControlTop(CC_INTERNAL_ERROR);
  1008. // validate parameters
  1009. if (hListen == CC_INVALID_HANDLE)
  1010. LeaveCallControlTop(CC_BAD_PARAM);
  1011. status = LockListen(hListen, &pListen);
  1012. if (status != CC_OK)
  1013. LeaveCallControlTop(status);
  1014. hQ931Listen = pListen->hQ931Listen;
  1015. // Unlock the listen object to prevent deadlock when calling Q931
  1016. UnlockListen(pListen);
  1017. #ifdef GATEKEEPER
  1018. status = GkiCloseListen(hListen);
  1019. #endif // GATEKEEPER
  1020. status = Q931CancelListen(hQ931Listen);
  1021. if (status != CS_OK)
  1022. LeaveCallControlTop(status);
  1023. status = LockListen(hListen, &pListen);
  1024. if (status == CC_OK) {
  1025. LeaveCallControlTop(FreeListen(pListen));
  1026. } else
  1027. LeaveCallControlTop(status);
  1028. }
  1029. CC_API
  1030. HRESULT CC_CloseChannel( CC_HCHANNEL hChannel)
  1031. {
  1032. HRESULT status;
  1033. HRESULT SaveStatus = CC_OK;
  1034. PCHANNEL pChannel;
  1035. PCONFERENCE pConference;
  1036. PCALL pCall;
  1037. WORD wNumCalls;
  1038. PCC_HCALL CallList;
  1039. WORD i;
  1040. BOOL bChannelCloseRequest;
  1041. CC_HCALL hCall;
  1042. #ifdef GATEKEEPER
  1043. unsigned uBandwidth = 0;
  1044. #endif // GATEKEEPER
  1045. EnterCallControlTop();
  1046. if (InitStatus != CC_OK)
  1047. LeaveCallControlTop(InitStatus);
  1048. if (CallControlState != OPERATIONAL_STATE)
  1049. LeaveCallControlTop(CC_INTERNAL_ERROR);
  1050. // validate parameters
  1051. if (hChannel == CC_INVALID_HANDLE)
  1052. LeaveCallControlTop(CC_BAD_PARAM);
  1053. status = LockChannelAndConference(hChannel, &pChannel, &pConference);
  1054. if (status != CC_OK)
  1055. LeaveCallControlTop(status);
  1056. if (pChannel->tsAccepted != TS_TRUE) {
  1057. UnlockChannel(pChannel);
  1058. UnlockConference(pConference);
  1059. LeaveCallControlTop(CC_BAD_PARAM);
  1060. }
  1061. if (pConference->LocalEndpointAttached != ATTACHED) {
  1062. UnlockChannel(pChannel);
  1063. UnlockConference(pConference);
  1064. LeaveCallControlTop(CC_BAD_PARAM);
  1065. }
  1066. status = EnumerateCallsInConference(&wNumCalls, &CallList, pConference, ESTABLISHED_CALL);
  1067. if (status != CC_OK) {
  1068. UnlockConference(pConference);
  1069. UnlockChannel(pChannel);
  1070. LeaveCallControlTop(status);
  1071. }
  1072. if ((pChannel->bChannelType == RX_CHANNEL) ||
  1073. (pChannel->bChannelType == PROXY_CHANNEL) ||
  1074. ((pChannel->bChannelType == TXRX_CHANNEL) &&
  1075. (pChannel->bLocallyOpened == FALSE))) {
  1076. // Generate a channel close request
  1077. bChannelCloseRequest = TRUE;
  1078. } else {
  1079. bChannelCloseRequest = FALSE;
  1080. while (DequeueRequest(&pChannel->pCloseRequests, &hCall) == CC_OK) {
  1081. if (LockCall(hCall, &pCall) == CC_OK) {
  1082. H245CloseChannelReqResp(pCall->H245Instance,
  1083. H245_ACC,
  1084. pChannel->wLocalChannelNumber);
  1085. UnlockCall(pCall);
  1086. }
  1087. }
  1088. #ifdef GATEKEEPER
  1089. if(GKIExists())
  1090. {
  1091. if (pChannel->bChannelType != TXRX_CHANNEL)
  1092. {
  1093. if (pChannel->bMultipointChannel)
  1094. {
  1095. // Multicast channel bandwidth is assigned to arbitrary call
  1096. uBandwidth = pChannel->dwChannelBitRate / 100;
  1097. }
  1098. else
  1099. {
  1100. // Channel bandwidth is assigned to a specific call
  1101. ASSERT(pChannel->hCall != CC_INVALID_HANDLE);
  1102. if (LockCall(pChannel->hCall, &pCall) == CC_OK)
  1103. {
  1104. SaveStatus = GkiCloseChannel(&pCall->GkiCall, pChannel->dwChannelBitRate, hChannel);
  1105. UnlockCall(pCall);
  1106. }
  1107. }
  1108. }
  1109. }
  1110. #endif // GATEKEEPER
  1111. }
  1112. for (i = 0; i < wNumCalls; i++) {
  1113. if (LockCall(CallList[i], &pCall) == CC_OK) {
  1114. if (bChannelCloseRequest) {
  1115. if ((pChannel->bChannelType != PROXY_CHANNEL) ||
  1116. (pChannel->hCall == pCall->hCall)) {
  1117. // Note that dwTransID is set to the call handle of
  1118. // the peer who initiated the close channel request.
  1119. // When the close channel response is received,
  1120. // the dwTransID gives us back the call handle to which
  1121. // the response must be forwarded. In this case,
  1122. // the local endpoint initiated the close channel request,
  1123. // so we'll use CC_INVALID_HANDLE as the dwTransId
  1124. // to note this fact.
  1125. status = H245CloseChannelReq(pCall->H245Instance, // H245 instance
  1126. CC_INVALID_HANDLE, // dwTransId
  1127. pChannel->wRemoteChannelNumber);
  1128. }
  1129. } else {
  1130. status = H245CloseChannel(pCall->H245Instance, // H245 instance
  1131. 0, // dwTransId
  1132. pChannel->wLocalChannelNumber);
  1133. #ifdef GATEKEEPER
  1134. if(GKIExists())
  1135. {
  1136. if (uBandwidth && uBandwidth <= pCall->GkiCall.uBandwidthUsed)
  1137. {
  1138. // Since the bandwidth is multicast, only subtract it from
  1139. // a single call (does not really matter which one)
  1140. SaveStatus = GkiCloseChannel(&pCall->GkiCall, pChannel->dwChannelBitRate, hChannel);
  1141. if (SaveStatus == CC_OK)
  1142. uBandwidth = 0;
  1143. }
  1144. }
  1145. #endif // GATEKEEPER
  1146. }
  1147. // Note that this channel may not have been accepted on all of the calls,
  1148. // so we could get an H245_ERROR_INVALID_CHANNEL error
  1149. if ((status != H245_ERROR_OK) && (status != H245_ERROR_INVALID_CHANNEL))
  1150. SaveStatus = status;
  1151. UnlockCall(pCall);
  1152. }
  1153. }
  1154. if (CallList != NULL)
  1155. MemFree(CallList);
  1156. if (pChannel->bChannelType == PROXY_CHANNEL) {
  1157. // If this is a PROXY channel, keep the channel object around
  1158. // until the channel owner closes it
  1159. pChannel->tsAccepted = TS_FALSE;
  1160. UnlockChannel(pChannel);
  1161. } else {
  1162. // FreeChannel(pChannel);
  1163. // this is asynchronously released in _ConfClose(), in h245man.c
  1164. }
  1165. UnlockConference(pConference);
  1166. LeaveCallControlTop(SaveStatus);
  1167. }
  1168. CC_API
  1169. HRESULT CC_CloseChannelResponse( CC_HCHANNEL hChannel,
  1170. BOOL bWillCloseChannel)
  1171. {
  1172. HRESULT status;
  1173. PCHANNEL pChannel;
  1174. PCONFERENCE pConference;
  1175. CC_HCALL hCall;
  1176. PCALL pCall;
  1177. H245_ACC_REJ_T AccRej;
  1178. WORD wNumRequests;
  1179. EnterCallControlTop();
  1180. if (InitStatus != CC_OK)
  1181. LeaveCallControlTop(InitStatus);
  1182. if (CallControlState != OPERATIONAL_STATE)
  1183. LeaveCallControlTop(CC_INTERNAL_ERROR);
  1184. if (hChannel == CC_INVALID_HANDLE)
  1185. LeaveCallControlTop(CC_BAD_PARAM);
  1186. status = LockChannelAndConference(hChannel, &pChannel, &pConference);
  1187. if (status != CC_OK)
  1188. LeaveCallControlTop(status);
  1189. if (((pChannel->bChannelType != TX_CHANNEL) &&
  1190. (pChannel->bChannelType != TXRX_CHANNEL)) ||
  1191. (pChannel->bLocallyOpened == FALSE)) {
  1192. UnlockChannel(pChannel);
  1193. UnlockConference(pConference);
  1194. LeaveCallControlTop(CC_BAD_PARAM);
  1195. }
  1196. if (bWillCloseChannel)
  1197. AccRej = H245_ACC;
  1198. else
  1199. AccRej = H245_REJ;
  1200. wNumRequests = 0;
  1201. while (DequeueRequest(&pChannel->pCloseRequests, &hCall) == CC_OK) {
  1202. wNumRequests++;
  1203. if (LockCall(hCall, &pCall) == CC_OK) {
  1204. H245CloseChannelReqResp(pCall->H245Instance,
  1205. AccRej,
  1206. pChannel->wLocalChannelNumber);
  1207. UnlockCall(pCall);
  1208. }
  1209. }
  1210. UnlockChannel(pChannel);
  1211. UnlockConference(pConference);
  1212. if (wNumRequests == 0)
  1213. status = CC_BAD_PARAM;
  1214. else
  1215. status = CC_OK;
  1216. LeaveCallControlTop(status);
  1217. }
  1218. CC_API
  1219. HRESULT CC_ChangeConferenceCapabilities(
  1220. CC_HCONFERENCE hConference,
  1221. PCC_TERMCAPLIST pTermCapList,
  1222. PCC_TERMCAPDESCRIPTORS pTermCapDescriptors)
  1223. {
  1224. HRESULT status;
  1225. PCONFERENCE pConference;
  1226. PCALL pCall;
  1227. PCC_HCALL CallList;
  1228. WORD wNumCalls;
  1229. WORD i;
  1230. BOOL bConferenceTermCapsChanged;
  1231. EnterCallControlTop();
  1232. if (InitStatus != CC_OK)
  1233. LeaveCallControlTop(InitStatus);
  1234. if (CallControlState != OPERATIONAL_STATE)
  1235. LeaveCallControlTop(CC_INTERNAL_ERROR);
  1236. if (hConference == CC_INVALID_HANDLE)
  1237. LeaveCallControlTop(CC_BAD_PARAM);
  1238. if (pTermCapList == NULL)
  1239. LeaveCallControlTop(CC_BAD_PARAM);
  1240. status = ValidateTermCapList(pTermCapList);
  1241. if (status != CC_OK)
  1242. LeaveCallControlTop(status);
  1243. status = ValidateTermCapDescriptors(pTermCapDescriptors, pTermCapList);
  1244. if (status != CC_OK)
  1245. LeaveCallControlTop(status);
  1246. status = LockConference(hConference, &pConference);
  1247. if (status != CC_OK)
  1248. LeaveCallControlTop(status);
  1249. if (pConference->LocalEndpointAttached == DETACHED) {
  1250. UnlockConference(pConference);
  1251. LeaveCallControlTop(CC_BAD_PARAM);
  1252. }
  1253. status = UnregisterTermCapListFromH245(pConference,
  1254. pConference->pLocalH245TermCapList);
  1255. if (status != CC_OK) {
  1256. UnlockConference(pConference);
  1257. LeaveCallControlTop(status);
  1258. }
  1259. DestroyH245TermCapList(&pConference->pLocalH245TermCapList);
  1260. status = CopyH245TermCapList(&pConference->pLocalH245TermCapList,
  1261. pTermCapList);
  1262. if (status != CC_OK) {
  1263. UnlockConference(pConference);
  1264. LeaveCallControlTop(status);
  1265. }
  1266. status = UnregisterTermCapDescriptorsFromH245(pConference,
  1267. pConference->pLocalH245TermCapDescriptors);
  1268. if (status != CC_OK) {
  1269. UnlockConference(pConference);
  1270. LeaveCallControlTop(status);
  1271. }
  1272. DestroyH245TermCapDescriptors(&pConference->pLocalH245TermCapDescriptors);
  1273. // create a new descriptor list if one was not supplied
  1274. if (pTermCapDescriptors == NULL)
  1275. status = CreateH245DefaultTermCapDescriptors(&pConference->pLocalH245TermCapDescriptors,
  1276. pConference->pLocalH245TermCapList);
  1277. else
  1278. // make a local copy of pTermCapDescriptors
  1279. status = CopyH245TermCapDescriptors(&pConference->pLocalH245TermCapDescriptors,
  1280. pTermCapDescriptors);
  1281. if (status != CC_OK) {
  1282. UnlockConference(pConference);
  1283. LeaveCallControlTop(status);
  1284. }
  1285. if ((pConference->ConferenceMode == MULTIPOINT_MODE) &&
  1286. (pConference->tsMultipointController == TS_TRUE))
  1287. CreateConferenceTermCaps(pConference, &bConferenceTermCapsChanged);
  1288. else
  1289. bConferenceTermCapsChanged = TRUE;
  1290. if (bConferenceTermCapsChanged) {
  1291. EnumerateCallsInConference(&wNumCalls, &CallList, pConference, ESTABLISHED_CALL);
  1292. for (i = 0; i < wNumCalls; i++) {
  1293. if (LockCall(CallList[i], &pCall) == CC_OK) {
  1294. SendTermCaps(pCall, pConference);
  1295. UnlockCall(pCall);
  1296. }
  1297. }
  1298. if (CallList != NULL)
  1299. MemFree(CallList);
  1300. }
  1301. UnlockConference(pConference);
  1302. LeaveCallControlTop(CC_OK);
  1303. }
  1304. CC_API
  1305. HRESULT CC_CreateConference( PCC_HCONFERENCE phConference,
  1306. PCC_CONFERENCEID pConferenceID,
  1307. DWORD dwConferenceConfiguration,
  1308. PCC_TERMCAPLIST pTermCapList,
  1309. PCC_TERMCAPDESCRIPTORS pTermCapDescriptors,
  1310. PCC_VENDORINFO pVendorInfo,
  1311. PCC_OCTETSTRING pTerminalID,
  1312. DWORD_PTR dwConferenceToken,
  1313. CC_TERMCAP_CONSTRUCTOR TermCapConstructor,
  1314. CC_SESSIONTABLE_CONSTRUCTOR SessionTableConstructor,
  1315. CC_CONFERENCE_CALLBACK ConferenceCallback)
  1316. {
  1317. PCONFERENCE pConference;
  1318. HRESULT status;
  1319. BOOL bMultipointCapable;
  1320. BOOL bForceMultipointController;
  1321. EnterCallControlTop();
  1322. if (InitStatus != CC_OK)
  1323. LeaveCallControlTop(InitStatus);
  1324. if (CallControlState != OPERATIONAL_STATE)
  1325. LeaveCallControlTop(CC_INTERNAL_ERROR);
  1326. // validate parameters
  1327. if (phConference == NULL)
  1328. LeaveCallControlTop(CC_BAD_PARAM);
  1329. // set phConference now, in case we encounter an error
  1330. *phConference = CC_INVALID_HANDLE;
  1331. bMultipointCapable =
  1332. (dwConferenceConfiguration & CC_CONFIGURE_MULTIPOINT_CAPABLE) != 0 ? TRUE : FALSE;
  1333. bForceMultipointController =
  1334. (dwConferenceConfiguration & CC_CONFIGURE_FORCE_MC) != 0 ? TRUE : FALSE;
  1335. if ((bMultipointCapable == FALSE) &&
  1336. (bForceMultipointController == TRUE))
  1337. LeaveCallControlTop(CC_BAD_PARAM);
  1338. if (pTermCapList == NULL)
  1339. LeaveCallControlTop(CC_BAD_PARAM);
  1340. status = ValidateTermCapList(pTermCapList);
  1341. if (status != CC_OK)
  1342. LeaveCallControlTop(status);
  1343. status = ValidateTermCapDescriptors(pTermCapDescriptors, pTermCapList);
  1344. if (status != CC_OK)
  1345. LeaveCallControlTop(status);
  1346. if (pVendorInfo == NULL)
  1347. LeaveCallControlTop(CC_BAD_PARAM);
  1348. status = ValidateVendorInfo(pVendorInfo);
  1349. if (status != CC_OK)
  1350. LeaveCallControlTop(status);
  1351. status = ValidateTerminalID(pTerminalID);
  1352. if (status != CC_OK)
  1353. LeaveCallControlTop(status);
  1354. if (ConferenceCallback == NULL)
  1355. LeaveCallControlTop(CC_BAD_PARAM);
  1356. if (SessionTableConstructor == NULL)
  1357. SessionTableConstructor = DefaultSessionTableConstructor;
  1358. if (TermCapConstructor == NULL)
  1359. TermCapConstructor = DefaultTermCapConstructor;
  1360. status = AllocAndLockConference(phConference,
  1361. pConferenceID,
  1362. bMultipointCapable,
  1363. bForceMultipointController,
  1364. pTermCapList,
  1365. pTermCapDescriptors,
  1366. pVendorInfo,
  1367. pTerminalID,
  1368. dwConferenceToken,
  1369. SessionTableConstructor,
  1370. TermCapConstructor,
  1371. ConferenceCallback,
  1372. &pConference);
  1373. if (status != CC_OK)
  1374. LeaveCallControlTop(status);
  1375. LeaveCallControlTop(UnlockConference(pConference));
  1376. }
  1377. CC_API
  1378. HRESULT CC_DestroyConference( CC_HCONFERENCE hConference,
  1379. BOOL bAutoAccept)
  1380. {
  1381. HRESULT status;
  1382. EnterCallControlTop();
  1383. if (InitStatus != CC_OK)
  1384. LeaveCallControlTop(InitStatus);
  1385. if (CallControlState != OPERATIONAL_STATE)
  1386. LeaveCallControlTop(CC_INTERNAL_ERROR);
  1387. // validate parameters
  1388. if (hConference == CC_INVALID_HANDLE)
  1389. LeaveCallControlTop(CC_BAD_PARAM);
  1390. status = AsynchronousDestroyConference(hConference, bAutoAccept);
  1391. LeaveCallControlTop(status);
  1392. }
  1393. CC_API
  1394. HRESULT CC_EnumerateConferences( PWORD pwNumConferences,
  1395. CC_HCONFERENCE ConferenceList[])
  1396. {
  1397. HRESULT status;
  1398. EnterCallControlTop();
  1399. if (InitStatus != CC_OK)
  1400. LeaveCallControlTop(InitStatus);
  1401. if (CallControlState != OPERATIONAL_STATE)
  1402. LeaveCallControlTop(CC_INTERNAL_ERROR);
  1403. if ((*pwNumConferences != 0) && (ConferenceList == NULL))
  1404. LeaveCallControlTop(CC_BAD_PARAM);
  1405. if ((*pwNumConferences == 0) && (ConferenceList != NULL))
  1406. LeaveCallControlTop(CC_BAD_PARAM);
  1407. status = EnumerateConferences(pwNumConferences, ConferenceList);
  1408. LeaveCallControlTop(status);
  1409. }
  1410. CC_API
  1411. HRESULT CC_FlowControl( CC_HCHANNEL hChannel,
  1412. DWORD dwRate)
  1413. {
  1414. HRESULT status;
  1415. PCHANNEL pChannel;
  1416. PCALL pCall;
  1417. PCONFERENCE pConference;
  1418. EnterCallControlTop();
  1419. if (InitStatus != CC_OK)
  1420. LeaveCallControlTop(InitStatus);
  1421. if (CallControlState != OPERATIONAL_STATE)
  1422. LeaveCallControlTop(CC_INTERNAL_ERROR);
  1423. if (hChannel == CC_INVALID_HANDLE)
  1424. LeaveCallControlTop(CC_BAD_PARAM);
  1425. status = LockChannelAndConference(hChannel, &pChannel, &pConference);
  1426. if (status != CC_OK)
  1427. LeaveCallControlTop(status);
  1428. if ((pConference->LocalEndpointAttached != ATTACHED) ||
  1429. ((pChannel->bChannelType != RX_CHANNEL) &&
  1430. (pChannel->bChannelType != PROXY_CHANNEL)) ||
  1431. (pChannel->tsAccepted != TS_TRUE)) {
  1432. UnlockChannel(pChannel);
  1433. UnlockConference(pConference);
  1434. LeaveCallControlTop(CC_BAD_PARAM);
  1435. }
  1436. status = LockCall(pChannel->hCall, &pCall);
  1437. if (status != CC_OK) {
  1438. UnlockChannel(pChannel);
  1439. UnlockConference(pConference);
  1440. LeaveCallControlTop(status);
  1441. }
  1442. status = H245FlowControl(pCall->H245Instance,
  1443. H245_SCOPE_CHANNEL_NUMBER,
  1444. pChannel->wRemoteChannelNumber,
  1445. 0, // wResourceID, not used here
  1446. dwRate); // H245_NO_RESTRICTION if no restriction
  1447. UnlockCall(pCall);
  1448. UnlockChannel(pChannel);
  1449. UnlockConference(pConference);
  1450. LeaveCallControlTop(status);
  1451. }
  1452. CC_API
  1453. HRESULT CC_GetCallControlVersion( WORD wArraySize,
  1454. PWSTR pszVersion)
  1455. {
  1456. WCHAR pszCCversion[256];
  1457. WCHAR pszQ931version[256];
  1458. EnterCallControlTop();
  1459. if (CallControlState != OPERATIONAL_STATE)
  1460. LeaveCallControlTop(CC_INTERNAL_ERROR);
  1461. // validate parameters
  1462. if (wArraySize == 0)
  1463. LeaveCallControlTop(CC_BAD_PARAM);
  1464. if (pszVersion == NULL)
  1465. LeaveCallControlTop(CC_BAD_PARAM);
  1466. wcscpy(pszCCversion, L"Call Control ");
  1467. wcscat(pszCCversion, Unicode(__DATE__));
  1468. wcscat(pszCCversion, L" ");
  1469. wcscat(pszCCversion, Unicode(__TIME__));
  1470. wcscat(pszCCversion, L"\n");
  1471. Q931GetVersion(sizeof(pszQ931version)/sizeof(WCHAR), pszQ931version);
  1472. wcscat(pszCCversion, pszQ931version);
  1473. if (wcslen(pszCCversion) >= wArraySize) {
  1474. memcpy(pszVersion, pszCCversion, (wArraySize-1)*sizeof(WCHAR));
  1475. pszVersion[wArraySize-1] = L'\0';
  1476. LeaveCallControlTop(CC_BAD_SIZE);
  1477. }
  1478. wcscpy(pszVersion, pszCCversion);
  1479. LeaveCallControlTop(CC_OK);
  1480. }
  1481. CC_API
  1482. HRESULT CC_GetConferenceAttributes( CC_HCONFERENCE hConference,
  1483. PCC_CONFERENCEATTRIBUTES pConferenceAttributes)
  1484. {
  1485. HRESULT status;
  1486. PCONFERENCE pConference;
  1487. WORD wNumCalls;
  1488. BOOL bLocallyAttached;
  1489. PCC_HCALL CallList;
  1490. PCALL pCall;
  1491. WORD wLimit;
  1492. WORD wIndex;
  1493. WORD wOctetStringLength;
  1494. EnterCallControlTop();
  1495. if (InitStatus != CC_OK)
  1496. LeaveCallControlTop(InitStatus);
  1497. if (CallControlState != OPERATIONAL_STATE)
  1498. LeaveCallControlTop(CC_INTERNAL_ERROR);
  1499. // validate parameters
  1500. if (hConference == CC_INVALID_HANDLE)
  1501. LeaveCallControlTop(CC_BAD_PARAM);
  1502. if (pConferenceAttributes == NULL)
  1503. LeaveCallControlTop(CC_BAD_PARAM);
  1504. status = LockConference(hConference, &pConference);
  1505. if (status != CC_OK)
  1506. LeaveCallControlTop(status);
  1507. pConferenceAttributes->bMaster =
  1508. (pConference->tsMaster == TS_TRUE ? TRUE : FALSE);
  1509. pConferenceAttributes->bMultipointController =
  1510. (pConference->tsMultipointController == TS_TRUE ? TRUE : FALSE);
  1511. pConferenceAttributes->bMultipointConference =
  1512. (pConference->ConferenceMode == MULTIPOINT_MODE ? TRUE : FALSE);
  1513. pConferenceAttributes->ConferenceID = pConference->ConferenceID;
  1514. pConferenceAttributes->LocalTerminalLabel = pConference->LocalParticipantInfo.ParticipantInfo.TerminalLabel;
  1515. if (pConference->LocalEndpointAttached == ATTACHED)
  1516. bLocallyAttached = TRUE;
  1517. else
  1518. bLocallyAttached = FALSE;
  1519. if ((pConference->tsMultipointController == TS_TRUE) ||
  1520. (pConference->ConferenceMode == POINT_TO_POINT_MODE))
  1521. EnumerateCallsInConference(&wNumCalls, &CallList, pConference, ESTABLISHED_CALL);
  1522. else
  1523. EnumerateCallsInConference(&wNumCalls, &CallList, pConference, VIRTUAL_CALL);
  1524. pConferenceAttributes->dwConferenceToken = pConference->dwConferenceToken;
  1525. UnlockConference(pConference);
  1526. if (bLocallyAttached)
  1527. pConferenceAttributes->wNumCalls = (WORD)(wNumCalls + 1);
  1528. else
  1529. pConferenceAttributes->wNumCalls = wNumCalls;
  1530. #ifdef GATEKEEPER
  1531. if(GKIExists())
  1532. {
  1533. pConferenceAttributes->dwBandwidthAllocated = 0;
  1534. pConferenceAttributes->dwBandwidthUsed = 0;
  1535. for (wIndex = 0; wIndex < wNumCalls; ++wIndex) {
  1536. if (LockCall(CallList[wIndex], &pCall) == CC_OK) {
  1537. pConferenceAttributes->dwBandwidthAllocated += pCall->GkiCall.uBandwidthAllocated;
  1538. if (pConferenceAttributes->dwBandwidthAllocated > GKI_MAX_BANDWIDTH)
  1539. pConferenceAttributes->dwBandwidthAllocated = GKI_MAX_BANDWIDTH;
  1540. pConferenceAttributes->dwBandwidthUsed += pCall->GkiCall.uBandwidthUsed;
  1541. if (pConferenceAttributes->dwBandwidthUsed > GKI_MAX_BANDWIDTH)
  1542. pConferenceAttributes->dwBandwidthUsed = GKI_MAX_BANDWIDTH;
  1543. UnlockCall(pCall);
  1544. }
  1545. }
  1546. pConferenceAttributes->dwBandwidthAllocated *= 100;
  1547. pConferenceAttributes->dwBandwidthUsed *= 100;
  1548. }
  1549. #endif // GATEKEEPER
  1550. if (pConferenceAttributes->pParticipantList != NULL) {
  1551. wLimit = pConferenceAttributes->pParticipantList->wLength;
  1552. pConferenceAttributes->pParticipantList->wLength = 0;
  1553. for (wIndex = 0; wIndex < wNumCalls; wIndex++) {
  1554. if (LockCall(CallList[wIndex], &pCall) == CC_OK) {
  1555. if (pCall->pPeerParticipantInfo != NULL) {
  1556. if (pConferenceAttributes->pParticipantList->wLength < wLimit) {
  1557. pConferenceAttributes->pParticipantList->ParticipantInfoArray[pConferenceAttributes->pParticipantList->wLength].TerminalLabel =
  1558. pCall->pPeerParticipantInfo->ParticipantInfo.TerminalLabel;
  1559. if ((pCall->pPeerParticipantInfo->TerminalIDState == TERMINAL_ID_VALID) &&
  1560. (pCall->pPeerParticipantInfo->ParticipantInfo.TerminalID.wOctetStringLength != 0) &&
  1561. (pCall->pPeerParticipantInfo->ParticipantInfo.TerminalID.pOctetString != NULL) &&
  1562. (pConferenceAttributes->pParticipantList->ParticipantInfoArray[pConferenceAttributes->pParticipantList->wLength].TerminalID.pOctetString != NULL)) {
  1563. if (pConferenceAttributes->pParticipantList->ParticipantInfoArray[pConferenceAttributes->pParticipantList->wLength].TerminalID.wOctetStringLength <
  1564. pCall->pPeerParticipantInfo->ParticipantInfo.TerminalID.wOctetStringLength) {
  1565. wOctetStringLength = pConferenceAttributes->pParticipantList->ParticipantInfoArray[pConferenceAttributes->pParticipantList->wLength].TerminalID.wOctetStringLength;
  1566. } else {
  1567. wOctetStringLength = pCall->pPeerParticipantInfo->ParticipantInfo.TerminalID.wOctetStringLength;
  1568. pConferenceAttributes->pParticipantList->ParticipantInfoArray[pConferenceAttributes->pParticipantList->wLength].TerminalID.wOctetStringLength = wOctetStringLength;
  1569. }
  1570. memcpy(pConferenceAttributes->pParticipantList->ParticipantInfoArray[pConferenceAttributes->pParticipantList->wLength].TerminalID.pOctetString,
  1571. pCall->pPeerParticipantInfo->ParticipantInfo.TerminalID.pOctetString,
  1572. wOctetStringLength);
  1573. } else {
  1574. pConferenceAttributes->pParticipantList->ParticipantInfoArray[pConferenceAttributes->pParticipantList->wLength].TerminalID.wOctetStringLength = 0;
  1575. pConferenceAttributes->pParticipantList->ParticipantInfoArray[pConferenceAttributes->pParticipantList->wLength].TerminalID.pOctetString = NULL;
  1576. }
  1577. }
  1578. pConferenceAttributes->pParticipantList->wLength++;
  1579. }
  1580. UnlockCall(pCall);
  1581. }
  1582. }
  1583. if (bLocallyAttached) {
  1584. if (LockConference(hConference, &pConference) == CC_OK) {
  1585. if (pConferenceAttributes->pParticipantList->wLength < wLimit) {
  1586. pConferenceAttributes->pParticipantList->ParticipantInfoArray[pConferenceAttributes->pParticipantList->wLength].TerminalLabel =
  1587. pConference->LocalParticipantInfo.ParticipantInfo.TerminalLabel;
  1588. if ((pConference->LocalParticipantInfo.TerminalIDState == TERMINAL_ID_VALID) &&
  1589. (pConference->LocalParticipantInfo.ParticipantInfo.TerminalID.wOctetStringLength != 0) &&
  1590. (pConference->LocalParticipantInfo.ParticipantInfo.TerminalID.pOctetString != NULL) &&
  1591. (pConferenceAttributes->pParticipantList->ParticipantInfoArray[pConferenceAttributes->pParticipantList->wLength].TerminalID.pOctetString != NULL)) {
  1592. if (pConferenceAttributes->pParticipantList->ParticipantInfoArray[pConferenceAttributes->pParticipantList->wLength].TerminalID.wOctetStringLength <
  1593. pConference->LocalParticipantInfo.ParticipantInfo.TerminalID.wOctetStringLength) {
  1594. wOctetStringLength = pConferenceAttributes->pParticipantList->ParticipantInfoArray[pConferenceAttributes->pParticipantList->wLength].TerminalID.wOctetStringLength;
  1595. } else {
  1596. wOctetStringLength = pConference->LocalParticipantInfo.ParticipantInfo.TerminalID.wOctetStringLength;
  1597. pConferenceAttributes->pParticipantList->ParticipantInfoArray[pConferenceAttributes->pParticipantList->wLength].TerminalID.wOctetStringLength = wOctetStringLength;
  1598. }
  1599. memcpy(pConferenceAttributes->pParticipantList->ParticipantInfoArray[pConferenceAttributes->pParticipantList->wLength].TerminalID.pOctetString,
  1600. pConference->LocalParticipantInfo.ParticipantInfo.TerminalID.pOctetString,
  1601. wOctetStringLength);
  1602. } else {
  1603. pConferenceAttributes->pParticipantList->ParticipantInfoArray[pConferenceAttributes->pParticipantList->wLength].TerminalID.wOctetStringLength = 0;
  1604. pConferenceAttributes->pParticipantList->ParticipantInfoArray[pConferenceAttributes->pParticipantList->wLength].TerminalID.pOctetString = NULL;
  1605. }
  1606. }
  1607. pConferenceAttributes->pParticipantList->wLength++;
  1608. UnlockConference(pConference);
  1609. }
  1610. }
  1611. }
  1612. if (CallList != NULL)
  1613. MemFree(CallList);
  1614. LeaveCallControlTop(CC_OK);
  1615. }
  1616. CC_API
  1617. HRESULT CC_H245ConferenceRequest( CC_HCALL hCall,
  1618. H245_CONFER_REQ_ENUM_T RequestType,
  1619. CC_TERMINAL_LABEL TerminalLabel)
  1620. {
  1621. HRESULT status;
  1622. PCALL pCall;
  1623. PCONFERENCE pConference;
  1624. EnterCallControlTop();
  1625. if (InitStatus != CC_OK)
  1626. LeaveCallControlTop(InitStatus);
  1627. if (CallControlState != OPERATIONAL_STATE)
  1628. LeaveCallControlTop(CC_INTERNAL_ERROR);
  1629. if (hCall == CC_INVALID_HANDLE)
  1630. LeaveCallControlTop(CC_BAD_PARAM);
  1631. if ((RequestType != H245_REQ_MAKE_ME_CHAIR) &&
  1632. (RequestType != H245_REQ_CANCEL_MAKE_ME_CHAIR) &&
  1633. (RequestType != H245_REQ_DROP_TERMINAL) &&
  1634. (RequestType != H245_REQ_ENTER_H243_TERMINAL_ID) &&
  1635. (RequestType != H245_REQ_ENTER_H243_CONFERENCE_ID))
  1636. LeaveCallControlTop(CC_BAD_PARAM);
  1637. status = LockCallAndConference(hCall, &pCall, &pConference);
  1638. if (status != CC_OK)
  1639. LeaveCallControlTop(status);
  1640. if ((pConference->LocalEndpointAttached != ATTACHED) ||
  1641. (pCall->CallState != CALL_COMPLETE) ||
  1642. (pCall->CallType == VIRTUAL_CALL)) {
  1643. UnlockCall(pCall);
  1644. UnlockConference(pConference);
  1645. LeaveCallControlTop(CC_BAD_PARAM);
  1646. }
  1647. status = H245ConferenceRequest(pCall->H245Instance,
  1648. RequestType,
  1649. TerminalLabel.bMCUNumber,
  1650. TerminalLabel.bTerminalNumber);
  1651. UnlockCall(pCall);
  1652. UnlockConference(pConference);
  1653. LeaveCallControlTop(status);
  1654. }
  1655. CC_API
  1656. HRESULT CC_H245ConferenceResponse( CC_HCALL hCall,
  1657. H245_CONFER_RSP_ENUM_T ResponseType,
  1658. CC_TERMINAL_LABEL CC_TerminalLabel,
  1659. PCC_OCTETSTRING pOctetString,
  1660. CC_TERMINAL_LABEL *pCC_TerminalList,
  1661. WORD wTerminalListCount)
  1662. {
  1663. HRESULT status;
  1664. PCALL pCall;
  1665. PCONFERENCE pConference;
  1666. WORD i;
  1667. TerminalLabel *pH245TerminalList;
  1668. BYTE *pH245OctetString;
  1669. BYTE bH245OctetStringLength;
  1670. EnterCallControlTop();
  1671. if (InitStatus != CC_OK)
  1672. LeaveCallControlTop(InitStatus);
  1673. if (CallControlState != OPERATIONAL_STATE)
  1674. LeaveCallControlTop(CC_INTERNAL_ERROR);
  1675. if (hCall == CC_INVALID_HANDLE)
  1676. LeaveCallControlTop(CC_BAD_PARAM);
  1677. if ((ResponseType != H245_RSP_CONFERENCE_ID) &&
  1678. (ResponseType != H245_RSP_PASSWORD) &&
  1679. (ResponseType != H245_RSP_VIDEO_COMMAND_REJECT) &&
  1680. (ResponseType != H245_RSP_TERMINAL_DROP_REJECT) &&
  1681. (ResponseType != H245_RSP_DENIED_CHAIR_TOKEN) &&
  1682. (ResponseType != H245_RSP_GRANTED_CHAIR_TOKEN))
  1683. LeaveCallControlTop(CC_BAD_PARAM);
  1684. if (wTerminalListCount != 0)
  1685. LeaveCallControlTop(CC_BAD_PARAM);
  1686. if (pCC_TerminalList == NULL)
  1687. LeaveCallControlTop(CC_BAD_PARAM);
  1688. status = ValidateOctetString(pOctetString);
  1689. if (status != CC_OK)
  1690. LeaveCallControlTop(status);
  1691. if (pOctetString != NULL)
  1692. if (pOctetString->wOctetStringLength > 255)
  1693. LeaveCallControlTop(CC_BAD_PARAM);
  1694. status = LockCallAndConference(hCall, &pCall, &pConference);
  1695. if (status != CC_OK)
  1696. LeaveCallControlTop(status);
  1697. if ((pConference->LocalEndpointAttached != ATTACHED) ||
  1698. (pCall->CallState != CALL_COMPLETE) ||
  1699. (pCall->CallType == VIRTUAL_CALL)) {
  1700. UnlockCall(pCall);
  1701. UnlockConference(pConference);
  1702. LeaveCallControlTop(CC_BAD_PARAM);
  1703. }
  1704. if (wTerminalListCount == 0) {
  1705. pH245TerminalList = NULL;
  1706. } else {
  1707. pH245TerminalList = (TerminalLabel *)MemAlloc(sizeof(TerminalLabel) * wTerminalListCount);
  1708. if (pH245TerminalList == NULL) {
  1709. UnlockCall(pCall);
  1710. UnlockConference(pConference);
  1711. LeaveCallControlTop(CC_NO_MEMORY);
  1712. }
  1713. for (i = 0; i < wTerminalListCount; i++) {
  1714. pH245TerminalList[i].mcuNumber = pCC_TerminalList[i].bMCUNumber;
  1715. pH245TerminalList[i].terminalNumber = pCC_TerminalList[i].bTerminalNumber;
  1716. }
  1717. }
  1718. if (pOctetString == NULL) {
  1719. pH245OctetString = NULL;
  1720. bH245OctetStringLength = 0;
  1721. } else {
  1722. pH245OctetString = pOctetString->pOctetString;
  1723. bH245OctetStringLength = (BYTE)pOctetString->wOctetStringLength;
  1724. }
  1725. status = H245ConferenceResponse(pCall->H245Instance,
  1726. ResponseType,
  1727. CC_TerminalLabel.bMCUNumber,
  1728. CC_TerminalLabel.bTerminalNumber,
  1729. pH245OctetString,
  1730. bH245OctetStringLength,
  1731. pH245TerminalList,
  1732. wTerminalListCount);
  1733. if (pH245TerminalList != NULL)
  1734. MemFree(pH245TerminalList);
  1735. UnlockCall(pCall);
  1736. UnlockConference(pConference);
  1737. LeaveCallControlTop(status);
  1738. }
  1739. CC_API
  1740. HRESULT CC_H245ConferenceCommand( CC_HCALL hCall,
  1741. CC_HCHANNEL hChannel,
  1742. H245_CONFER_CMD_ENUM_T CommandType,
  1743. CC_TERMINAL_LABEL TerminalLabel)
  1744. {
  1745. HRESULT status;
  1746. PCALL pCall;
  1747. PCONFERENCE pConference;
  1748. PCHANNEL pChannel;
  1749. WORD wChannelNumber;
  1750. EnterCallControlTop();
  1751. if (InitStatus != CC_OK)
  1752. LeaveCallControlTop(InitStatus);
  1753. if (CallControlState != OPERATIONAL_STATE)
  1754. LeaveCallControlTop(CC_INTERNAL_ERROR);
  1755. if (hCall == CC_INVALID_HANDLE)
  1756. LeaveCallControlTop(CC_BAD_PARAM);
  1757. if ((CommandType != H245_CMD_BROADCAST_CHANNEL) &&
  1758. (CommandType != H245_CMD_CANCEL_BROADCAST_CHANNEL) &&
  1759. (CommandType != H245_CMD_BROADCASTER) &&
  1760. (CommandType != H245_CMD_CANCEL_BROADCASTER) &&
  1761. (CommandType != H245_CMD_SEND_THIS_SOURCE) &&
  1762. (CommandType != H245_CMD_CANCEL_SEND_THIS_SOURCE) &&
  1763. (CommandType != H245_CMD_DROP_CONFERENCE))
  1764. LeaveCallControlTop(CC_BAD_PARAM);
  1765. status = LockCallAndConference(hCall, &pCall, &pConference);
  1766. if (status != CC_OK)
  1767. LeaveCallControlTop(status);
  1768. if ((pConference->LocalEndpointAttached != ATTACHED) ||
  1769. (pCall->CallState != CALL_COMPLETE) ||
  1770. (pCall->CallType == VIRTUAL_CALL)) {
  1771. UnlockCall(pCall);
  1772. UnlockConference(pConference);
  1773. LeaveCallControlTop(CC_BAD_PARAM);
  1774. }
  1775. if (hChannel == CC_INVALID_HANDLE) {
  1776. wChannelNumber = 1;
  1777. } else {
  1778. status = LockChannel(hChannel, &pChannel);
  1779. if (status != CC_OK) {
  1780. UnlockCall(pCall);
  1781. UnlockConference(pConference);
  1782. LeaveCallControlTop(status);
  1783. }
  1784. switch (pChannel->bChannelType) {
  1785. case TX_CHANNEL:
  1786. wChannelNumber = pChannel->wLocalChannelNumber;
  1787. break;
  1788. case RX_CHANNEL:
  1789. wChannelNumber = pChannel->wRemoteChannelNumber;
  1790. break;
  1791. case TXRX_CHANNEL:
  1792. wChannelNumber = pChannel->wRemoteChannelNumber;
  1793. break;
  1794. case PROXY_CHANNEL:
  1795. if (pChannel->hCall == hCall)
  1796. wChannelNumber = pChannel->wRemoteChannelNumber;
  1797. else
  1798. wChannelNumber = pChannel->wLocalChannelNumber;
  1799. break;
  1800. default:
  1801. ASSERT(0);
  1802. break;
  1803. }
  1804. UnlockChannel(pChannel);
  1805. }
  1806. status = H245ConferenceCommand(pCall->H245Instance,
  1807. CommandType,
  1808. wChannelNumber,
  1809. TerminalLabel.bMCUNumber,
  1810. TerminalLabel.bTerminalNumber);
  1811. UnlockCall(pCall);
  1812. UnlockConference(pConference);
  1813. LeaveCallControlTop(status);
  1814. }
  1815. CC_API
  1816. HRESULT CC_H245ConferenceIndication(CC_HCALL hCall,
  1817. H245_CONFER_IND_ENUM_T IndicationType,
  1818. BYTE bSBENumber,
  1819. CC_TERMINAL_LABEL TerminalLabel)
  1820. {
  1821. HRESULT status;
  1822. PCALL pCall;
  1823. PCONFERENCE pConference;
  1824. EnterCallControlTop();
  1825. if (InitStatus != CC_OK)
  1826. LeaveCallControlTop(InitStatus);
  1827. if (CallControlState != OPERATIONAL_STATE)
  1828. LeaveCallControlTop(CC_INTERNAL_ERROR);
  1829. if (hCall == CC_INVALID_HANDLE)
  1830. LeaveCallControlTop(CC_BAD_PARAM);
  1831. if ((IndicationType != H245_IND_SBE_NUMBER) &&
  1832. (IndicationType != H245_IND_SEEN_BY_ONE_OTHER) &&
  1833. (IndicationType != H245_IND_CANCEL_SEEN_BY_ONE_OTHER) &&
  1834. (IndicationType != H245_IND_SEEN_BY_ALL) &&
  1835. (IndicationType != H245_IND_CANCEL_SEEN_BY_ALL) &&
  1836. (IndicationType != H245_IND_TERMINAL_YOU_ARE_SEEING) &&
  1837. (IndicationType != H245_IND_REQUEST_FOR_FLOOR))
  1838. LeaveCallControlTop(CC_BAD_PARAM);
  1839. status = LockCallAndConference(hCall, &pCall, &pConference);
  1840. if (status != CC_OK)
  1841. LeaveCallControlTop(status);
  1842. if ((pConference->LocalEndpointAttached != ATTACHED) ||
  1843. (pCall->CallState != CALL_COMPLETE) ||
  1844. (pCall->CallType == VIRTUAL_CALL)) {
  1845. UnlockCall(pCall);
  1846. UnlockConference(pConference);
  1847. LeaveCallControlTop(CC_BAD_PARAM);
  1848. }
  1849. status = H245ConferenceIndication(pCall->H245Instance,
  1850. IndicationType,
  1851. bSBENumber,
  1852. TerminalLabel.bMCUNumber,
  1853. TerminalLabel.bTerminalNumber);
  1854. UnlockCall(pCall);
  1855. UnlockConference(pConference);
  1856. LeaveCallControlTop(status);
  1857. }
  1858. CC_API
  1859. HRESULT CC_H245MiscellaneousCommand(CC_HCALL hCall,
  1860. CC_HCHANNEL hChannel,
  1861. MiscellaneousCommand *pMiscellaneousCommand)
  1862. {
  1863. HRESULT status;
  1864. PCALL pCall;
  1865. PCONFERENCE pConference;
  1866. PCHANNEL pChannel;
  1867. WORD wChannelNumber;
  1868. PDU_T Pdu;
  1869. EnterCallControlTop();
  1870. if (InitStatus != CC_OK)
  1871. LeaveCallControlTop(InitStatus);
  1872. if (CallControlState != OPERATIONAL_STATE)
  1873. LeaveCallControlTop(CC_INTERNAL_ERROR);
  1874. if (hCall == CC_INVALID_HANDLE)
  1875. LeaveCallControlTop(CC_BAD_PARAM);
  1876. if (pMiscellaneousCommand == NULL)
  1877. LeaveCallControlTop(CC_BAD_PARAM);
  1878. if ((pMiscellaneousCommand->type.choice == multipointModeCommand_chosen) ||
  1879. (pMiscellaneousCommand->type.choice == cnclMltpntMdCmmnd_chosen))
  1880. LeaveCallControlTop(CC_BAD_PARAM);
  1881. status = LockCallAndConference(hCall, &pCall, &pConference);
  1882. if (status != CC_OK)
  1883. LeaveCallControlTop(status);
  1884. if ((pConference->LocalEndpointAttached != ATTACHED) ||
  1885. (pCall->CallState != CALL_COMPLETE) ||
  1886. (pCall->CallType == VIRTUAL_CALL)) {
  1887. UnlockCall(pCall);
  1888. UnlockConference(pConference);
  1889. LeaveCallControlTop(CC_BAD_PARAM);
  1890. }
  1891. if (hChannel == CC_INVALID_HANDLE) {
  1892. wChannelNumber = 1;
  1893. } else {
  1894. status = LockChannel(hChannel, &pChannel);
  1895. if (status != CC_OK) {
  1896. UnlockCall(pCall);
  1897. UnlockConference(pConference);
  1898. LeaveCallControlTop(status);
  1899. }
  1900. switch (pChannel->bChannelType) {
  1901. case TX_CHANNEL:
  1902. wChannelNumber = pChannel->wLocalChannelNumber;
  1903. break;
  1904. case RX_CHANNEL:
  1905. wChannelNumber = pChannel->wRemoteChannelNumber;
  1906. break;
  1907. case TXRX_CHANNEL:
  1908. wChannelNumber = pChannel->wRemoteChannelNumber;
  1909. break;
  1910. case PROXY_CHANNEL:
  1911. if (pChannel->hCall == hCall)
  1912. wChannelNumber = pChannel->wRemoteChannelNumber;
  1913. else
  1914. wChannelNumber = pChannel->wLocalChannelNumber;
  1915. break;
  1916. default:
  1917. ASSERT(0);
  1918. break;
  1919. }
  1920. UnlockChannel(pChannel);
  1921. }
  1922. // Construct an H.245 PDU to hold a miscellaneous command
  1923. Pdu.choice = MSCMg_cmmnd_chosen;
  1924. Pdu.u.MSCMg_cmmnd.choice = miscellaneousCommand_chosen;
  1925. Pdu.u.MSCMg_cmmnd.u.miscellaneousCommand = *pMiscellaneousCommand;
  1926. Pdu.u.MSCMg_cmmnd.u.miscellaneousCommand.logicalChannelNumber = wChannelNumber;
  1927. status = H245SendPDU(pCall->H245Instance, // H245 instance
  1928. &Pdu);
  1929. UnlockCall(pCall);
  1930. UnlockConference(pConference);
  1931. LeaveCallControlTop(status);
  1932. }
  1933. CC_API
  1934. HRESULT CC_H245MiscellaneousIndication(
  1935. CC_HCALL hCall,
  1936. CC_HCHANNEL hChannel,
  1937. MiscellaneousIndication *pMiscellaneousIndication)
  1938. {
  1939. HRESULT status;
  1940. PCALL pCall;
  1941. PCONFERENCE pConference;
  1942. PCHANNEL pChannel;
  1943. WORD wChannelNumber;
  1944. PDU_T Pdu;
  1945. EnterCallControlTop();
  1946. if (InitStatus != CC_OK)
  1947. LeaveCallControlTop(InitStatus);
  1948. if (CallControlState != OPERATIONAL_STATE)
  1949. LeaveCallControlTop(CC_INTERNAL_ERROR);
  1950. if (hCall == CC_INVALID_HANDLE)
  1951. LeaveCallControlTop(CC_BAD_PARAM);
  1952. if (pMiscellaneousIndication == NULL)
  1953. LeaveCallControlTop(CC_BAD_PARAM);
  1954. if ((pMiscellaneousIndication->type.choice == logicalChannelActive_chosen) ||
  1955. (pMiscellaneousIndication->type.choice == logicalChannelInactive_chosen))
  1956. LeaveCallControlTop(CC_BAD_PARAM);
  1957. status = LockCallAndConference(hCall, &pCall, &pConference);
  1958. if (status != CC_OK)
  1959. LeaveCallControlTop(status);
  1960. if ((pConference->LocalEndpointAttached != ATTACHED) ||
  1961. (pCall->CallState != CALL_COMPLETE) ||
  1962. (pCall->CallType == VIRTUAL_CALL)) {
  1963. UnlockCall(pCall);
  1964. UnlockConference(pConference);
  1965. LeaveCallControlTop(CC_BAD_PARAM);
  1966. }
  1967. if (hChannel == CC_INVALID_HANDLE) {
  1968. wChannelNumber = 1;
  1969. } else {
  1970. status = LockChannel(hChannel, &pChannel);
  1971. if (status != CC_OK) {
  1972. UnlockCall(pCall);
  1973. UnlockConference(pConference);
  1974. LeaveCallControlTop(status);
  1975. }
  1976. switch (pChannel->bChannelType) {
  1977. case TX_CHANNEL:
  1978. wChannelNumber = pChannel->wLocalChannelNumber;
  1979. break;
  1980. case RX_CHANNEL:
  1981. wChannelNumber = pChannel->wRemoteChannelNumber;
  1982. break;
  1983. case TXRX_CHANNEL:
  1984. wChannelNumber = pChannel->wRemoteChannelNumber;
  1985. break;
  1986. case PROXY_CHANNEL:
  1987. if (pChannel->hCall == hCall)
  1988. wChannelNumber = pChannel->wRemoteChannelNumber;
  1989. else
  1990. wChannelNumber = pChannel->wLocalChannelNumber;
  1991. break;
  1992. default:
  1993. ASSERT(0);
  1994. break;
  1995. }
  1996. UnlockChannel(pChannel);
  1997. }
  1998. // Construct an H.245 PDU to hold a miscellaneous indication
  1999. Pdu.choice = indication_chosen;
  2000. Pdu.u.indication.choice = miscellaneousIndication_chosen;
  2001. Pdu.u.indication.u.miscellaneousIndication = *pMiscellaneousIndication;
  2002. Pdu.u.indication.u.miscellaneousIndication.logicalChannelNumber = wChannelNumber;
  2003. status = H245SendPDU(pCall->H245Instance, // H245 instance
  2004. &Pdu);
  2005. UnlockCall(pCall);
  2006. UnlockConference(pConference);
  2007. LeaveCallControlTop(status);
  2008. }
  2009. CC_API
  2010. HRESULT CC_Hangup( CC_HCONFERENCE hConference,
  2011. BOOL bTerminateConference,
  2012. DWORD_PTR dwUserToken)
  2013. {
  2014. HRESULT status;
  2015. HRESULT SaveStatus;
  2016. HHANGUP hHangup;
  2017. PHANGUP pHangup;
  2018. PCHANNEL pChannel;
  2019. PCALL pCall;
  2020. PCONFERENCE pConference;
  2021. CC_HANGUP_CALLBACK_PARAMS HangupCallbackParams;
  2022. HQ931CALL hQ931Call;
  2023. WORD wNumChannels;
  2024. PCC_HCHANNEL ChannelList;
  2025. WORD wNumCalls;
  2026. PCC_HCALL CallList;
  2027. WORD i;
  2028. H245_INST_T H245Instance;
  2029. CALLSTATE CallState;
  2030. EnterCallControlTop();
  2031. if (InitStatus != CC_OK)
  2032. LeaveCallControlTop(InitStatus);
  2033. if (CallControlState != OPERATIONAL_STATE)
  2034. LeaveCallControlTop(CC_INTERNAL_ERROR);
  2035. // validate parameters
  2036. if (hConference == CC_INVALID_HANDLE)
  2037. LeaveCallControlTop(CC_BAD_PARAM);
  2038. status = LockConference(hConference, &pConference);
  2039. if (status != CC_OK)
  2040. LeaveCallControlTop(status);
  2041. // If the local endpoint is not attached, we will only allow a hangup if
  2042. // the local endpoint is the MC in a multipoint conference and
  2043. // conference termination is being requested
  2044. if ((pConference->LocalEndpointAttached != ATTACHED) &&
  2045. ((bTerminateConference == FALSE) ||
  2046. (pConference->ConferenceMode != MULTIPOINT_MODE) ||
  2047. (pConference->tsMultipointController != TS_TRUE))) {
  2048. UnlockConference(pConference);
  2049. LeaveCallControlTop(CC_BAD_PARAM);
  2050. }
  2051. HangupCallbackParams.dwUserToken = dwUserToken;
  2052. if ((pConference->ConferenceMode == MULTIPOINT_MODE) &&
  2053. (pConference->tsMultipointController == TS_TRUE) &&
  2054. (bTerminateConference == FALSE)) {
  2055. // Send TerminalLeftConference (this call) to all established calls
  2056. EnumerateCallsInConference(&wNumCalls, &CallList, pConference, ESTABLISHED_CALL);
  2057. for (i = 0; i < wNumCalls; i++) {
  2058. if (LockCall(CallList[i], &pCall) == CC_OK) {
  2059. H245ConferenceIndication(pCall->H245Instance,
  2060. H245_IND_TERMINAL_LEFT, // Indication Type
  2061. 0, // SBE number; ignored here
  2062. pConference->LocalParticipantInfo.ParticipantInfo.TerminalLabel.bMCUNumber, // MCU number
  2063. pConference->LocalParticipantInfo.ParticipantInfo.TerminalLabel.bTerminalNumber); // terminal number
  2064. UnlockCall(pCall);
  2065. }
  2066. }
  2067. if (CallList != NULL)
  2068. MemFree(CallList);
  2069. // Delete all TX, RX and bi-directional channels on this conference
  2070. // Leave PROXY_CHANNELs intact
  2071. EnumerateChannelsInConference(&wNumChannels,
  2072. &ChannelList,
  2073. pConference,
  2074. TX_CHANNEL | RX_CHANNEL | TXRX_CHANNEL);
  2075. for (i = 0; i < wNumChannels; i++) {
  2076. if (LockChannel(ChannelList[i], &pChannel) == CC_OK)
  2077. // Notice that since we're going to hangup, we don't need to
  2078. // close any channels
  2079. FreeChannel(pChannel);
  2080. }
  2081. if (ChannelList != NULL)
  2082. MemFree(ChannelList);
  2083. if (pConference->bDeferredDelete)
  2084. {
  2085. ASSERT(pConference->LocalEndpointAttached == DETACHED);
  2086. FreeConference(pConference);
  2087. }
  2088. else
  2089. {
  2090. //
  2091. // Set DETACHED _before_ callback; that will call
  2092. // CC_DestroyConference, which will call AsynchronousDestroyConference,
  2093. // which will not do anything if we are still sttached.
  2094. //
  2095. if (pConference->LocalEndpointAttached != DETACHED)
  2096. {
  2097. pConference->LocalEndpointAttached = DETACHED;
  2098. if (pConference->ConferenceCallback)
  2099. {
  2100. pConference->ConferenceCallback(CC_HANGUP_INDICATION, CC_OK,
  2101. pConference->hConference, pConference->dwConferenceToken,
  2102. &HangupCallbackParams);
  2103. }
  2104. }
  2105. if (ValidateConference(hConference) == CC_OK)
  2106. {
  2107. UnlockConference(pConference);
  2108. }
  2109. }
  2110. LeaveCallControlTop(CC_OK);
  2111. }
  2112. status = EnumerateChannelsInConference(&wNumChannels,
  2113. &ChannelList,
  2114. pConference,
  2115. ALL_CHANNELS);
  2116. if (status != CC_OK) {
  2117. UnlockConference(pConference);
  2118. LeaveCallControlTop(status);
  2119. }
  2120. // free all the channels
  2121. for (i = 0; i < wNumChannels; i++) {
  2122. if (LockChannel(ChannelList[i], &pChannel) == CC_OK)
  2123. // Notice that since we're going to hangup, we don't need to
  2124. // close any channels
  2125. FreeChannel(pChannel);
  2126. }
  2127. if (ChannelList != NULL)
  2128. MemFree(ChannelList);
  2129. status = EnumerateCallsInConference(&wNumCalls, &CallList, pConference, REAL_CALLS);
  2130. if (status != CC_OK) {
  2131. UnlockConference(pConference);
  2132. LeaveCallControlTop(status);
  2133. }
  2134. if ((pConference->ConferenceMode == MULTIPOINT_MODE) &&
  2135. (pConference->tsMultipointController == TS_FALSE) &&
  2136. (bTerminateConference == TRUE)) {
  2137. ASSERT(wNumCalls == 1);
  2138. if (LockCall(CallList[0], &pCall) == CC_OK) {
  2139. // Send DropConference command to MC
  2140. H245ConferenceCommand (
  2141. pCall->H245Instance,
  2142. H245_CMD_DROP_CONFERENCE, // Command type
  2143. 1, // Channel
  2144. 0, // byMcuNumber
  2145. 0); // byTerminalNumber
  2146. UnlockCall(pCall);
  2147. }
  2148. }
  2149. status = AllocAndLockHangup(&hHangup,
  2150. hConference,
  2151. dwUserToken,
  2152. &pHangup);
  2153. if (status != CC_OK) {
  2154. if (CallList != NULL)
  2155. MemFree(CallList);
  2156. UnlockConference(pConference);
  2157. LeaveCallControlTop(status);
  2158. }
  2159. // Now close all calls
  2160. SaveStatus = H245_ERROR_OK;
  2161. for (i = 0; i < wNumCalls; i++) {
  2162. if (LockCall(CallList[i], &pCall) == CC_OK) {
  2163. H245Instance = pCall->H245Instance;
  2164. hQ931Call = pCall->hQ931Call;
  2165. CallState = pCall->CallState;
  2166. FreeCall(pCall);
  2167. if (CallState != ENQUEUED) {
  2168. if (H245Instance != H245_INVALID_ID) {
  2169. status = H245ShutDown(H245Instance);
  2170. if (status == H245_ERROR_OK)
  2171. pHangup->wNumCalls++;
  2172. else
  2173. // The link may already be shut down; if so, don't return an error
  2174. if (status != LINK_INVALID_STATE)
  2175. SaveStatus = status;
  2176. }
  2177. if (SaveStatus == H245_ERROR_OK) {
  2178. if ((CallState == PLACED) ||
  2179. (CallState == RINGING))
  2180. SaveStatus = Q931RejectCall(hQ931Call,
  2181. CC_REJECT_UNDEFINED_REASON,
  2182. &pConference->ConferenceID,
  2183. NULL, // alternate address
  2184. NULL); // pNonStandardData
  2185. else
  2186. SaveStatus = Q931Hangup(hQ931Call, CC_REJECT_NORMAL_CALL_CLEARING);
  2187. // Q931Hangup may legitimately return CS_BAD_PARAM or LINK_INVALID_STATE,
  2188. // because the Q.931 call object may have been deleted at this point
  2189. if ((SaveStatus == CS_BAD_PARAM) ||
  2190. (SaveStatus == LINK_INVALID_STATE))
  2191. SaveStatus = CC_OK;
  2192. } else
  2193. if ((CallState == PLACED) ||
  2194. (CallState == RINGING))
  2195. Q931RejectCall(hQ931Call,
  2196. CC_REJECT_UNDEFINED_REASON,
  2197. &pConference->ConferenceID,
  2198. NULL, // alternate address
  2199. NULL); // pNonStandardData
  2200. else
  2201. Q931Hangup(hQ931Call, CC_REJECT_NORMAL_CALL_CLEARING);
  2202. }
  2203. }
  2204. }
  2205. if (CallList != NULL)
  2206. MemFree(CallList);
  2207. // Need to validate the conference object; H245ShutDown may cause us to re-enter
  2208. // Call Control, which may result in deletion of the conference object
  2209. if (ValidateConference(hConference) != CC_OK)
  2210. LeaveCallControlTop(SaveStatus);
  2211. // Delete the virtual calls (if any)
  2212. EnumerateCallsInConference(&wNumCalls, &CallList, pConference, VIRTUAL_CALL);
  2213. for (i = 0; i < wNumCalls; i++)
  2214. if (LockCall(CallList[i], &pCall) == CC_OK) {
  2215. FreeCall(pCall);
  2216. }
  2217. if (CallList != NULL)
  2218. MemFree(CallList);
  2219. // XXX -- for sync 2, H245ShutDown() is synchronous, so change wNumCalls
  2220. // to cause the user callback and associated cleanup to occur synchronously
  2221. pHangup->wNumCalls = 0;
  2222. if (pHangup->wNumCalls == 0)
  2223. {
  2224. if (pConference->bDeferredDelete)
  2225. {
  2226. ASSERT(pConference->LocalEndpointAttached == DETACHED);
  2227. FreeConference(pConference);
  2228. }
  2229. else
  2230. {
  2231. //
  2232. // Set DETACHED _before_ callback; that will call
  2233. // CC_DestroyConference, which will call AsynchronousDestroyConference,
  2234. // which will not do anything if we are still sttached.
  2235. //
  2236. if (pConference->LocalEndpointAttached != DETACHED)
  2237. {
  2238. pConference->LocalEndpointAttached = DETACHED;
  2239. if (pConference->ConferenceCallback)
  2240. {
  2241. pConference->ConferenceCallback(CC_HANGUP_INDICATION, SaveStatus,
  2242. pConference->hConference, pConference->dwConferenceToken,
  2243. &HangupCallbackParams);
  2244. }
  2245. }
  2246. if (ValidateConference(hConference) == CC_OK)
  2247. {
  2248. ReInitializeConference(pConference);
  2249. UnlockConference(pConference);
  2250. }
  2251. }
  2252. if (ValidateHangup(hHangup) == CC_OK)
  2253. FreeHangup(pHangup);
  2254. LeaveCallControlTop(SaveStatus);
  2255. } else {
  2256. UnlockHangup(pHangup);
  2257. LeaveCallControlTop(SaveStatus);
  2258. }
  2259. }
  2260. CC_API
  2261. HRESULT CC_MaximumAudioVideoSkew( CC_HCHANNEL hChannelAudio,
  2262. CC_HCHANNEL hChannelVideo,
  2263. WORD wMaximumSkew)
  2264. {
  2265. HRESULT status;
  2266. PCALL pCall;
  2267. PCONFERENCE pConference;
  2268. PCHANNEL pChannelAudio;
  2269. PCHANNEL pChannelVideo;
  2270. PCC_HCALL CallList;
  2271. WORD wNumCalls;
  2272. WORD i;
  2273. WORD wNumSuccesses;
  2274. EnterCallControlTop();
  2275. if (InitStatus != CC_OK)
  2276. LeaveCallControlTop(InitStatus);
  2277. if (CallControlState != OPERATIONAL_STATE)
  2278. LeaveCallControlTop(CC_INTERNAL_ERROR);
  2279. if ((hChannelAudio == CC_INVALID_HANDLE) || (hChannelVideo == CC_INVALID_HANDLE))
  2280. LeaveCallControlTop(CC_BAD_PARAM);
  2281. status = LockChannelAndConference(hChannelAudio, &pChannelAudio, &pConference);
  2282. if (status != CC_OK)
  2283. LeaveCallControlTop(status);
  2284. status = LockChannel(hChannelVideo, &pChannelVideo);
  2285. if (status != CC_OK) {
  2286. UnlockChannel(pChannelAudio);
  2287. UnlockConference(pConference);
  2288. LeaveCallControlTop(status);
  2289. }
  2290. if ((pChannelAudio->hConference != pChannelVideo->hConference) ||
  2291. (pChannelAudio->bChannelType != TX_CHANNEL) ||
  2292. (pChannelAudio->wNumOutstandingRequests != 0) ||
  2293. (pChannelVideo->bChannelType != TX_CHANNEL) ||
  2294. (pChannelVideo->wNumOutstandingRequests != 0)) {
  2295. UnlockChannel(pChannelAudio);
  2296. UnlockChannel(pChannelVideo);
  2297. UnlockConference(pConference);
  2298. LeaveCallControlTop(CC_BAD_PARAM);
  2299. }
  2300. EnumerateCallsInConference(&wNumCalls, &CallList, pConference, ESTABLISHED_CALL);
  2301. wNumSuccesses = 0;
  2302. for (i = 0; i < wNumCalls; i++) {
  2303. if (LockCall(CallList[i], &pCall) == CC_OK) {
  2304. status = H245H2250MaximumSkewIndication(pCall->H245Instance,
  2305. pChannelAudio->wLocalChannelNumber,
  2306. pChannelVideo->wLocalChannelNumber,
  2307. wMaximumSkew);
  2308. UnlockCall(pCall);
  2309. if (status == H245_ERROR_OK)
  2310. wNumSuccesses++;
  2311. }
  2312. }
  2313. if (CallList != NULL)
  2314. MemFree(CallList);
  2315. UnlockChannel(pChannelAudio);
  2316. UnlockChannel(pChannelVideo);
  2317. UnlockConference(pConference);
  2318. if (wNumSuccesses == 0) {
  2319. LeaveCallControlTop(status);
  2320. } else {
  2321. LeaveCallControlTop(CC_OK);
  2322. }
  2323. }
  2324. CC_API
  2325. HRESULT CC_Mute( CC_HCHANNEL hChannel)
  2326. {
  2327. HRESULT status;
  2328. HRESULT SaveStatus;
  2329. PCHANNEL pChannel;
  2330. PCONFERENCE pConference;
  2331. PCALL pCall;
  2332. PDU_T Pdu;
  2333. WORD wNumCalls;
  2334. PCC_HCALL CallList;
  2335. WORD i;
  2336. EnterCallControlTop();
  2337. if (InitStatus != CC_OK)
  2338. LeaveCallControlTop(InitStatus);
  2339. if (CallControlState != OPERATIONAL_STATE)
  2340. LeaveCallControlTop(CC_INTERNAL_ERROR);
  2341. if (hChannel == CC_INVALID_HANDLE)
  2342. LeaveCallControlTop(CC_BAD_PARAM);
  2343. status = LockChannelAndConference(hChannel, &pChannel, &pConference);
  2344. if (status != CC_OK)
  2345. LeaveCallControlTop(status);
  2346. if (pChannel->bChannelType != TX_CHANNEL) {
  2347. // can only mute transmit channels
  2348. UnlockChannel(pChannel);
  2349. UnlockConference(pConference);
  2350. LeaveCallControlTop(CC_BAD_PARAM);
  2351. }
  2352. if (pConference->LocalEndpointAttached != ATTACHED) {
  2353. UnlockChannel(pChannel);
  2354. UnlockConference(pConference);
  2355. LeaveCallControlTop(CC_BAD_PARAM);
  2356. }
  2357. status = EnumerateCallsInConference(&wNumCalls, &CallList, pConference, ESTABLISHED_CALL);
  2358. if (status != CC_OK) {
  2359. UnlockConference(pConference);
  2360. UnlockChannel(pChannel);
  2361. LeaveCallControlTop(status);
  2362. }
  2363. // Construct an H.245 PDU to hold a miscellaneous indication
  2364. // of "logical channel inactive"
  2365. Pdu.choice = indication_chosen;
  2366. Pdu.u.indication.choice = miscellaneousIndication_chosen;
  2367. Pdu.u.indication.u.miscellaneousIndication.logicalChannelNumber =
  2368. pChannel->wLocalChannelNumber;
  2369. Pdu.u.indication.u.miscellaneousIndication.type.choice = logicalChannelInactive_chosen;
  2370. SaveStatus = CC_OK;
  2371. for (i = 0; i < wNumCalls; i++) {
  2372. if (LockCall(CallList[i], &pCall) == CC_OK) {
  2373. status = H245SendPDU(pCall->H245Instance, // H245 instance
  2374. &Pdu);
  2375. // Note that this channel may not have been accepted on all of the calls,
  2376. // so we could get an H245_ERROR_INVALID_CHANNEL error
  2377. if ((status != H245_ERROR_OK) && (status != H245_ERROR_INVALID_CHANNEL))
  2378. SaveStatus = status;
  2379. UnlockCall(pCall);
  2380. }
  2381. }
  2382. if (CallList != NULL)
  2383. MemFree(CallList);
  2384. UnlockConference(pConference);
  2385. UnlockChannel(pChannel);
  2386. LeaveCallControlTop(SaveStatus);
  2387. }
  2388. CC_API
  2389. HRESULT CC_OpenChannel( CC_HCONFERENCE hConference,
  2390. PCC_HCHANNEL phChannel,
  2391. BYTE bSessionID,
  2392. BYTE bAssociatedSessionID,
  2393. BOOL bSilenceSuppression,
  2394. PCC_TERMCAP pTermCap,
  2395. PCC_ADDR pLocalRTCPAddr,
  2396. BYTE bDynamicRTPPayloadType,
  2397. DWORD dwChannelBitRate,
  2398. DWORD_PTR dwUserToken)
  2399. {
  2400. HRESULT status;
  2401. PCONFERENCE pConference;
  2402. PCHANNEL pChannel;
  2403. CC_HCALL hCall;
  2404. PCALL pCall;
  2405. H245_MUX_T H245MuxTable;
  2406. WORD i;
  2407. PCC_ADDR pLocalRTPAddr;
  2408. PCC_ADDR pPeerRTPAddr;
  2409. PCC_ADDR pPeerRTCPAddr;
  2410. BOOL bFoundSession;
  2411. WORD wNumCalls;
  2412. PCC_HCALL CallList;
  2413. //#ifndef GATEKEEPER
  2414. HRESULT SaveStatus;
  2415. //#endif // !GATEKEEPER
  2416. EnterCallControlTop();
  2417. if (InitStatus != CC_OK)
  2418. LeaveCallControlTop(InitStatus);
  2419. if (CallControlState != OPERATIONAL_STATE)
  2420. LeaveCallControlTop(CC_INTERNAL_ERROR);
  2421. // validate parameters
  2422. if (phChannel == NULL)
  2423. LeaveCallControlTop(CC_BAD_PARAM);
  2424. // set phChannel now, in case we encounter an error
  2425. *phChannel = CC_INVALID_HANDLE;
  2426. if (hConference == CC_INVALID_HANDLE)
  2427. LeaveCallControlTop(CC_BAD_PARAM);
  2428. if (pLocalRTCPAddr != NULL)
  2429. if (pLocalRTCPAddr->nAddrType != CC_IP_BINARY)
  2430. LeaveCallControlTop(CC_BAD_PARAM);
  2431. if (pTermCap == NULL)
  2432. LeaveCallControlTop(CC_BAD_PARAM);
  2433. if ((bDynamicRTPPayloadType != 0) &&
  2434. ((bDynamicRTPPayloadType < 96) || (bDynamicRTPPayloadType > 127)))
  2435. LeaveCallControlTop(CC_BAD_PARAM);
  2436. status = LockConferenceEx(hConference,
  2437. &pConference,
  2438. TS_FALSE); // bDeferredDelete
  2439. if (status != CC_OK)
  2440. LeaveCallControlTop(status);
  2441. // XXX -- we may eventually want to support dynamic session generation
  2442. if (bSessionID == 0)
  2443. if ((pConference->tsMaster == TS_TRUE) ||
  2444. (pConference->ConferenceMode == MULTIPOINT_MODE)) {
  2445. UnlockConference(pConference);
  2446. LeaveCallControlTop(CC_BAD_PARAM);
  2447. }
  2448. if (((pConference->ConferenceMode == MULTIPOINT_MODE) &&
  2449. (pLocalRTCPAddr != NULL)) ||
  2450. ((pConference->ConferenceMode != MULTIPOINT_MODE) &&
  2451. (pLocalRTCPAddr == NULL))) {
  2452. UnlockConference(pConference);
  2453. LeaveCallControlTop(CC_BAD_PARAM);
  2454. }
  2455. if (pConference->LocalEndpointAttached != ATTACHED) {
  2456. UnlockConference(pConference);
  2457. LeaveCallControlTop(CC_BAD_PARAM);
  2458. }
  2459. if (pConference->ConferenceMode == MULTIPOINT_MODE) {
  2460. // XXX -- We should be able to dynamically create a new session if needed
  2461. // Validate session ID
  2462. pLocalRTPAddr = NULL;
  2463. pLocalRTCPAddr = NULL;
  2464. bFoundSession = FALSE;
  2465. if (pConference->pSessionTable != NULL) {
  2466. for (i = 0; i < pConference->pSessionTable->wLength; i++) {
  2467. if (bSessionID == pConference->pSessionTable->SessionInfoArray[i].bSessionID) {
  2468. bFoundSession = TRUE;
  2469. if (pConference->tsMultipointController == TS_TRUE) {
  2470. pLocalRTPAddr = pConference->pSessionTable->SessionInfoArray[i].pRTPAddr;
  2471. pLocalRTCPAddr = pConference->pSessionTable->SessionInfoArray[i].pRTCPAddr;
  2472. }
  2473. break;
  2474. }
  2475. }
  2476. }
  2477. if (bFoundSession == FALSE) {
  2478. UnlockConference(pConference);
  2479. LeaveCallControlTop(CC_BAD_PARAM);
  2480. }
  2481. pPeerRTPAddr = pLocalRTPAddr;
  2482. pPeerRTCPAddr = pLocalRTCPAddr;
  2483. } else {
  2484. pLocalRTPAddr = NULL;
  2485. pPeerRTPAddr = NULL;
  2486. pPeerRTCPAddr = NULL;
  2487. }
  2488. H245MuxTable.Kind = H245_H2250;
  2489. H245MuxTable.u.H2250.nonStandardList = NULL;
  2490. if (pLocalRTPAddr != NULL) {
  2491. if (pLocalRTPAddr->bMulticast)
  2492. H245MuxTable.u.H2250.mediaChannel.type = H245_IP_MULTICAST;
  2493. else
  2494. H245MuxTable.u.H2250.mediaChannel.type = H245_IP_UNICAST;
  2495. H245MuxTable.u.H2250.mediaChannel.u.ip.tsapIdentifier =
  2496. pLocalRTPAddr->Addr.IP_Binary.wPort;
  2497. HostToH245IPNetwork(H245MuxTable.u.H2250.mediaChannel.u.ip.network,
  2498. pLocalRTPAddr->Addr.IP_Binary.dwAddr);
  2499. H245MuxTable.u.H2250.mediaChannelPresent = TRUE;
  2500. } else
  2501. H245MuxTable.u.H2250.mediaChannelPresent = FALSE;
  2502. if (pLocalRTCPAddr != NULL) {
  2503. if (pLocalRTCPAddr->bMulticast)
  2504. H245MuxTable.u.H2250.mediaControlChannel.type = H245_IP_MULTICAST;
  2505. else
  2506. H245MuxTable.u.H2250.mediaControlChannel.type = H245_IP_UNICAST;
  2507. H245MuxTable.u.H2250.mediaControlChannel.u.ip.tsapIdentifier =
  2508. pLocalRTCPAddr->Addr.IP_Binary.wPort;
  2509. HostToH245IPNetwork(H245MuxTable.u.H2250.mediaControlChannel.u.ip.network,
  2510. pLocalRTCPAddr->Addr.IP_Binary.dwAddr);
  2511. H245MuxTable.u.H2250.mediaControlChannelPresent = TRUE;
  2512. } else
  2513. H245MuxTable.u.H2250.mediaControlChannelPresent = FALSE;
  2514. if (bDynamicRTPPayloadType == 0)
  2515. H245MuxTable.u.H2250.dynamicRTPPayloadTypePresent = FALSE;
  2516. else {
  2517. H245MuxTable.u.H2250.dynamicRTPPayloadTypePresent = TRUE;
  2518. H245MuxTable.u.H2250.dynamicRTPPayloadType = bDynamicRTPPayloadType;
  2519. }
  2520. H245MuxTable.u.H2250.sessionID = bSessionID;
  2521. if (bAssociatedSessionID == 0)
  2522. H245MuxTable.u.H2250.associatedSessionIDPresent = FALSE;
  2523. else {
  2524. H245MuxTable.u.H2250.associatedSessionIDPresent = TRUE;
  2525. H245MuxTable.u.H2250.associatedSessionID = bAssociatedSessionID;
  2526. }
  2527. H245MuxTable.u.H2250.mediaGuaranteed = FALSE;
  2528. H245MuxTable.u.H2250.mediaGuaranteedPresent = TRUE;
  2529. H245MuxTable.u.H2250.mediaControlGuaranteed = FALSE;
  2530. H245MuxTable.u.H2250.mediaControlGuaranteedPresent = TRUE;
  2531. // The silence suppression field must be present if and only if
  2532. // the channel is an audio channel
  2533. if (pTermCap->DataType == H245_DATA_AUDIO) {
  2534. H245MuxTable.u.H2250.silenceSuppressionPresent = TRUE;
  2535. H245MuxTable.u.H2250.silenceSuppression = (char) bSilenceSuppression;
  2536. } else
  2537. H245MuxTable.u.H2250.silenceSuppressionPresent = FALSE;
  2538. if (pConference->ConferenceMode == POINT_TO_POINT_MODE)
  2539. H245MuxTable.u.H2250.destinationPresent = FALSE;
  2540. else {
  2541. H245MuxTable.u.H2250.destinationPresent = TRUE;
  2542. H245MuxTable.u.H2250.destination.mcuNumber = pConference->LocalParticipantInfo.ParticipantInfo.TerminalLabel.bMCUNumber;
  2543. H245MuxTable.u.H2250.destination.terminalNumber = pConference->LocalParticipantInfo.ParticipantInfo.TerminalLabel.bTerminalNumber;
  2544. }
  2545. H245MuxTable.u.H2250.h261aVideoPacketization = FALSE;
  2546. // Set hCall in the channel object to indicate which call object
  2547. // the channel is being opened to; if we're in multipoint mode,
  2548. // the channel may be opened to multiple calls, to set hCall
  2549. // to CC_INVALID_HANDLE. If the channel is opened in point-to-point
  2550. // mode, and we later switch to multipoint mode and this peer hangs
  2551. // up, hCall will be used to determine whether this call object
  2552. // should be deleted
  2553. if (pConference->ConferenceMode == POINT_TO_POINT_MODE) {
  2554. EnumerateCallsInConference(&wNumCalls, &CallList, pConference, ESTABLISHED_CALL);
  2555. ASSERT(wNumCalls == 1);
  2556. hCall = CallList[0];
  2557. MemFree(CallList);
  2558. } else {
  2559. hCall = CC_INVALID_HANDLE;
  2560. }
  2561. status = AllocAndLockChannel(phChannel,
  2562. pConference,
  2563. hCall, // hCall
  2564. pTermCap, // Tx term cap
  2565. NULL, // Rx term cap
  2566. &H245MuxTable, // Tx mux table
  2567. NULL, // Rx mux table
  2568. NULL, // separate stack
  2569. dwUserToken,
  2570. TX_CHANNEL,
  2571. bSessionID,
  2572. bAssociatedSessionID,
  2573. 0, // remote channel number
  2574. pLocalRTPAddr,
  2575. pLocalRTCPAddr,
  2576. pPeerRTPAddr,
  2577. pPeerRTCPAddr,
  2578. TRUE, // locally opened
  2579. &pChannel);
  2580. if (status != CC_OK) {
  2581. UnlockConference(pConference);
  2582. LeaveCallControlTop(status);
  2583. }
  2584. status = AddChannelToConference(pChannel, pConference);
  2585. if (status != CC_OK) {
  2586. FreeChannel(pChannel);
  2587. UnlockConference(pConference);
  2588. *phChannel = CC_INVALID_HANDLE;
  2589. LeaveCallControlTop(status);
  2590. }
  2591. status = EnumerateCallsInConference(&wNumCalls, &CallList, pConference, ESTABLISHED_CALL);
  2592. if (status != CC_OK) {
  2593. FreeChannel(pChannel);
  2594. UnlockConference(pConference);
  2595. *phChannel = CC_INVALID_HANDLE;
  2596. LeaveCallControlTop(status);
  2597. }
  2598. #ifdef GATEKEEPER
  2599. if(GKIExists())
  2600. {
  2601. pChannel->dwChannelBitRate = dwChannelBitRate;
  2602. UnlockChannel(pChannel);
  2603. UnlockConference(pConference);
  2604. // If point-to-point mode, than wNumCalls == 1 and CallList[0] == hCall
  2605. // If multipoint, choice of which channel to assign TX bandwidth to
  2606. // is arbitrary. Either way, CallList[0] works.
  2607. status = LockCall(CallList[0], &pCall);
  2608. if (status == CC_OK)
  2609. {
  2610. status = GkiOpenChannel(&pCall->GkiCall, dwChannelBitRate, *phChannel, TX);
  2611. if (ValidateCall(CallList[0]) == CC_OK)
  2612. UnlockCall(pCall);
  2613. }
  2614. MemFree(CallList);
  2615. LeaveCallControlTop(status);
  2616. }
  2617. else
  2618. {
  2619. SaveStatus = CC_OK;
  2620. for (i = 0; i < wNumCalls; i++)
  2621. {
  2622. if (LockCall(CallList[i], &pCall) == CC_OK)
  2623. {
  2624. status = H245OpenChannel(pCall->H245Instance, // H245 instance
  2625. pChannel->hChannel, // dwTransId
  2626. pChannel->wLocalChannelNumber,
  2627. pChannel->pTxH245TermCap, // TxMode
  2628. pChannel->pTxMuxTable, // TxMux
  2629. H245_INVALID_PORT_NUMBER, // TxPort
  2630. pChannel->pRxH245TermCap, // RxMode
  2631. pChannel->pRxMuxTable, // RxMux
  2632. pChannel->pSeparateStack);
  2633. if (status == H245_ERROR_OK)
  2634. (pChannel->wNumOutstandingRequests)++;
  2635. else
  2636. SaveStatus = status;
  2637. UnlockCall(pCall);
  2638. }
  2639. }
  2640. if (CallList != NULL)
  2641. MemFree(CallList);
  2642. if (pChannel->wNumOutstandingRequests == 0)
  2643. {
  2644. // all open channel requests failed
  2645. FreeChannel(pChannel);
  2646. UnlockConference(pConference);
  2647. *phChannel = CC_INVALID_HANDLE;
  2648. LeaveCallControlTop(SaveStatus);
  2649. }
  2650. UnlockChannel(pChannel);
  2651. UnlockConference(pConference);
  2652. LeaveCallControlTop(CC_OK);
  2653. }
  2654. #else // GATEKEEPER
  2655. // Open a logical channel for each established call
  2656. SaveStatus = CC_OK;
  2657. for (i = 0; i < wNumCalls; i++) {
  2658. if (LockCall(CallList[i], &pCall) == CC_OK) {
  2659. status = H245OpenChannel(pCall->H245Instance, // H245 instance
  2660. pChannel->hChannel, // dwTransId
  2661. pChannel->wLocalChannelNumber,
  2662. pChannel->pTxH245TermCap, // TxMode
  2663. pChannel->pTxMuxTable, // TxMux
  2664. H245_INVALID_PORT_NUMBER, // TxPort
  2665. pChannel->pRxH245TermCap, // RxMode
  2666. pChannel->pRxMuxTable, // RxMux
  2667. pChannel->pSeparateStack);
  2668. if (status == H245_ERROR_OK)
  2669. (pChannel->wNumOutstandingRequests)++;
  2670. else
  2671. SaveStatus = status;
  2672. UnlockCall(pCall);
  2673. }
  2674. }
  2675. if (CallList != NULL)
  2676. MemFree(CallList);
  2677. if (pChannel->wNumOutstandingRequests == 0) {
  2678. // all open channel requests failed
  2679. FreeChannel(pChannel);
  2680. UnlockConference(pConference);
  2681. *phChannel = CC_INVALID_HANDLE;
  2682. LeaveCallControlTop(SaveStatus);
  2683. }
  2684. UnlockChannel(pChannel);
  2685. UnlockConference(pConference);
  2686. LeaveCallControlTop(CC_OK);
  2687. #endif // GATEKEEPER
  2688. }
  2689. HRESULT CC_OpenT120Channel( CC_HCONFERENCE hConference,
  2690. PCC_HCHANNEL phChannel,
  2691. BOOL bAssociateConference,
  2692. PCC_OCTETSTRING pExternalReference,
  2693. PCC_ADDR pAddr,
  2694. DWORD dwChannelBitRate,
  2695. DWORD_PTR dwUserToken)
  2696. {
  2697. HRESULT status;
  2698. PCALL pCall;
  2699. PCONFERENCE pConference;
  2700. PCHANNEL pChannel;
  2701. H245_MUX_T H245MuxTable;
  2702. CC_TERMCAP TermCap;
  2703. H245_ACCESS_T SeparateStack;
  2704. H245_ACCESS_T *pSeparateStack;
  2705. BYTE bSessionID;
  2706. WORD wNumCalls;
  2707. PCC_HCALL CallList;
  2708. HRESULT SaveStatus;
  2709. int i;
  2710. EnterCallControlTop();
  2711. if (InitStatus != CC_OK)
  2712. LeaveCallControlTop(InitStatus);
  2713. if (CallControlState != OPERATIONAL_STATE)
  2714. LeaveCallControlTop(CC_INTERNAL_ERROR);
  2715. // validate parameters
  2716. if (hConference == CC_INVALID_HANDLE)
  2717. LeaveCallControlTop(CC_BAD_PARAM);
  2718. if (pAddr != NULL)
  2719. if ((pAddr->nAddrType != CC_IP_BINARY) ||
  2720. (pAddr->bMulticast == TRUE))
  2721. LeaveCallControlTop(CC_BAD_PARAM);
  2722. if (pExternalReference != NULL)
  2723. if (pExternalReference->wOctetStringLength > 255)
  2724. LeaveCallControlTop(CC_BAD_PARAM);
  2725. status = LockConference(hConference, &pConference);
  2726. if (status != CC_OK)
  2727. LeaveCallControlTop(status);
  2728. if (pConference->LocalEndpointAttached != ATTACHED) {
  2729. UnlockConference(pConference);
  2730. LeaveCallControlTop(CC_BAD_PARAM);
  2731. }
  2732. // Assume that T.120 channels are always opened with a session ID of 0
  2733. bSessionID = 0;
  2734. H245MuxTable.Kind = H245_H2250;
  2735. H245MuxTable.u.H2250.nonStandardList = NULL;
  2736. H245MuxTable.u.H2250.mediaChannelPresent = FALSE;
  2737. H245MuxTable.u.H2250.mediaControlChannelPresent = FALSE;
  2738. H245MuxTable.u.H2250.dynamicRTPPayloadTypePresent = FALSE;
  2739. H245MuxTable.u.H2250.sessionID = bSessionID;
  2740. H245MuxTable.u.H2250.associatedSessionIDPresent = FALSE;
  2741. H245MuxTable.u.H2250.mediaGuaranteedPresent = FALSE;
  2742. H245MuxTable.u.H2250.mediaControlGuaranteedPresent = FALSE;
  2743. H245MuxTable.u.H2250.silenceSuppressionPresent = FALSE;
  2744. if (pConference->ConferenceMode == POINT_TO_POINT_MODE)
  2745. H245MuxTable.u.H2250.destinationPresent = FALSE;
  2746. else {
  2747. H245MuxTable.u.H2250.destinationPresent = TRUE;
  2748. H245MuxTable.u.H2250.destination.mcuNumber = pConference->LocalParticipantInfo.ParticipantInfo.TerminalLabel.bMCUNumber;
  2749. H245MuxTable.u.H2250.destination.terminalNumber = pConference->LocalParticipantInfo.ParticipantInfo.TerminalLabel.bTerminalNumber;
  2750. }
  2751. H245MuxTable.u.H2250.h261aVideoPacketization = FALSE;
  2752. TermCap.Dir = H245_CAPDIR_LCLRXTX;
  2753. TermCap.DataType = H245_DATA_DATA;
  2754. TermCap.ClientType = H245_CLIENT_DAT_T120;
  2755. TermCap.CapId = 0;
  2756. TermCap.Cap.H245Dat_T120.maxBitRate = dwChannelBitRate;
  2757. TermCap.Cap.H245Dat_T120.application.choice = DACy_applctn_t120_chosen;
  2758. TermCap.Cap.H245Dat_T120.application.u.DACy_applctn_t120.choice = separateLANStack_chosen;
  2759. if (pAddr != NULL) {
  2760. SeparateStack.bit_mask = distribution_present;
  2761. SeparateStack.distribution.choice = unicast_chosen;
  2762. if (pExternalReference != NULL) {
  2763. SeparateStack.bit_mask |= externalReference_present;
  2764. SeparateStack.externalReference.length = pExternalReference->wOctetStringLength;
  2765. memcpy(SeparateStack.externalReference.value,
  2766. pExternalReference->pOctetString,
  2767. pExternalReference->wOctetStringLength);
  2768. }
  2769. SeparateStack.networkAddress.choice = localAreaAddress_chosen;
  2770. SeparateStack.networkAddress.u.localAreaAddress.choice = unicastAddress_chosen;
  2771. SeparateStack.networkAddress.u.localAreaAddress.u.unicastAddress.choice = UnicastAddress_iPAddress_chosen;
  2772. SeparateStack.networkAddress.u.localAreaAddress.u.unicastAddress.u.UnicastAddress_iPAddress.tsapIdentifier =
  2773. pAddr->Addr.IP_Binary.wPort;
  2774. SeparateStack.networkAddress.u.localAreaAddress.u.unicastAddress.u.UnicastAddress_iPAddress.network.length = 4;
  2775. HostToH245IPNetwork(SeparateStack.networkAddress.u.localAreaAddress.u.unicastAddress.u.UnicastAddress_iPAddress.network.value,
  2776. pAddr->Addr.IP_Binary.dwAddr);
  2777. SeparateStack.associateConference = (char) bAssociateConference;
  2778. pSeparateStack = &SeparateStack;
  2779. } else {
  2780. pSeparateStack = NULL;
  2781. }
  2782. status = AllocAndLockChannel(phChannel,
  2783. pConference,
  2784. CC_INVALID_HANDLE, // hCall
  2785. &TermCap, // Tx term cap
  2786. &TermCap, // Rx term cap
  2787. &H245MuxTable, // Tx mux table
  2788. &H245MuxTable, // Rx mux table
  2789. pSeparateStack, // separate stack
  2790. dwUserToken,
  2791. TXRX_CHANNEL,
  2792. bSessionID,
  2793. 0, // associated session ID
  2794. 0, // remote channel
  2795. NULL, // local RTP addr
  2796. NULL, // local RTCP addr
  2797. NULL, // peer RTP addr
  2798. NULL, // peer RTCP addr
  2799. TRUE, // locally opened
  2800. &pChannel);
  2801. if (status != CC_OK) {
  2802. UnlockConference(pConference);
  2803. LeaveCallControlTop(status);
  2804. }
  2805. pChannel->tsAccepted = TS_TRUE;
  2806. status = AddChannelToConference(pChannel, pConference);
  2807. if (status != CC_OK) {
  2808. FreeChannel(pChannel);
  2809. UnlockConference(pConference);
  2810. LeaveCallControlTop(status);
  2811. }
  2812. EnumerateCallsInConference(&wNumCalls, &CallList, pConference, ESTABLISHED_CALL);
  2813. SaveStatus = CC_OK;
  2814. for (i = 0; i < wNumCalls; i++) {
  2815. if (LockCall(CallList[i], &pCall) == CC_OK) {
  2816. status = H245OpenChannel(pCall->H245Instance, // H245 instance
  2817. pChannel->hChannel, // dwTransId
  2818. pChannel->wLocalChannelNumber,
  2819. pChannel->pTxH245TermCap, // TxMode
  2820. pChannel->pTxMuxTable, // TxMux
  2821. H245_INVALID_PORT_NUMBER, // TxPort
  2822. pChannel->pRxH245TermCap, // RxMode
  2823. pChannel->pRxMuxTable, // RxMux
  2824. pChannel->pSeparateStack);
  2825. if (status == H245_ERROR_OK)
  2826. (pChannel->wNumOutstandingRequests)++;
  2827. else
  2828. SaveStatus = status;
  2829. UnlockCall(pCall);
  2830. }
  2831. }
  2832. MemFree(CallList);
  2833. if (pChannel->wNumOutstandingRequests == 0) {
  2834. // All open channel requests failed
  2835. FreeChannel(pChannel);
  2836. status = SaveStatus;
  2837. } else {
  2838. UnlockChannel(pChannel);
  2839. status = CC_OK;
  2840. }
  2841. UnlockConference(pConference);
  2842. LeaveCallControlTop(status);
  2843. }
  2844. HRESULT CC_Ping( CC_HCALL hCall,
  2845. DWORD dwTimeout)
  2846. {
  2847. PCALL pCall;
  2848. HRESULT status;
  2849. EnterCallControlTop();
  2850. if (InitStatus != CC_OK)
  2851. LeaveCallControlTop(InitStatus);
  2852. if (CallControlState != OPERATIONAL_STATE)
  2853. LeaveCallControlTop(CC_INTERNAL_ERROR);
  2854. // validate parameters
  2855. if (hCall == CC_INVALID_HANDLE)
  2856. LeaveCallControlTop(CC_BAD_PARAM);
  2857. status = LockCall(hCall, &pCall);
  2858. if (status != CC_OK)
  2859. LeaveCallControlTop(status);
  2860. if ((pCall->CallState != CALL_COMPLETE) ||
  2861. (pCall->CallType == VIRTUAL_CALL)) {
  2862. UnlockCall(pCall);
  2863. LeaveCallControlTop(CC_BAD_PARAM);
  2864. }
  2865. // Set the T105 timeout value as specified by the user;
  2866. // note that the previous timeout value is returned in this parameter
  2867. H245SystemControl(0, H245_SYSCON_SET_FSM_T105, &dwTimeout);
  2868. status = H245RoundTripDelayRequest(pCall->H245Instance,
  2869. 0); // dwTransId
  2870. // Reset the T105 timeout value to its original setting
  2871. H245SystemControl(0, H245_SYSCON_SET_FSM_T105, &dwTimeout);
  2872. UnlockCall(pCall);
  2873. LeaveCallControlTop(status);
  2874. }
  2875. CC_API
  2876. HRESULT CC_PlaceCall( CC_HCONFERENCE hConference,
  2877. PCC_HCALL phCall,
  2878. PCC_ALIASNAMES pLocalAliasNames,
  2879. PCC_ALIASNAMES pCalleeAliasNames,
  2880. PCC_ALIASNAMES pCalleeExtraAliasNames,
  2881. PCC_ALIASITEM pCalleeExtension,
  2882. PCC_NONSTANDARDDATA pNonStandardData,
  2883. PWSTR pszDisplay,
  2884. PCC_ADDR pDestinationAddr,
  2885. PCC_ADDR pConnectAddr,
  2886. DWORD dwBandwidth,
  2887. DWORD_PTR dwUserToken)
  2888. {
  2889. PCALL pCall;
  2890. CC_HCALL hCall;
  2891. PCONFERENCE pConference;
  2892. HRESULT status;
  2893. CALLTYPE CallType = CALLER;
  2894. CALLSTATE CallState = PLACED;
  2895. WORD wNumCalls;
  2896. BOOL bCallerIsMC;
  2897. GUID CallIdent;
  2898. EnterCallControlTop();
  2899. if (InitStatus != CC_OK)
  2900. LeaveCallControlTop(InitStatus);
  2901. if (CallControlState != OPERATIONAL_STATE)
  2902. LeaveCallControlTop(CC_INTERNAL_ERROR);
  2903. // validate parameters
  2904. if (phCall == NULL)
  2905. LeaveCallControlTop(CC_BAD_PARAM);
  2906. // set hCall now, in case we encounter an error
  2907. *phCall = CC_INVALID_HANDLE;
  2908. if (hConference == CC_INVALID_HANDLE)
  2909. LeaveCallControlTop(CC_BAD_PARAM);
  2910. status = Q931ValidateAliasNames(pLocalAliasNames);
  2911. if (status != CS_OK)
  2912. LeaveCallControlTop(status);
  2913. status = Q931ValidateAliasNames(pCalleeAliasNames);
  2914. if (status != CS_OK)
  2915. LeaveCallControlTop(status);
  2916. status = Q931ValidateAliasNames(pCalleeExtraAliasNames);
  2917. if (status != CS_OK)
  2918. LeaveCallControlTop(status);
  2919. status = Q931ValidateAliasItem(pCalleeExtension);
  2920. if (status != CS_OK)
  2921. LeaveCallControlTop(status);
  2922. status = ValidateNonStandardData(pNonStandardData);
  2923. if (status != CC_OK)
  2924. LeaveCallControlTop(status);
  2925. status = ValidateDisplay(pszDisplay);
  2926. if (status != CC_OK)
  2927. LeaveCallControlTop(status);
  2928. if ((pDestinationAddr == NULL) &&
  2929. (pConnectAddr == NULL) &&
  2930. (pCalleeAliasNames == NULL))
  2931. LeaveCallControlTop(CC_BAD_PARAM);
  2932. status = ValidateAddr(pDestinationAddr);
  2933. if (status != CC_OK)
  2934. LeaveCallControlTop(status);
  2935. status = ValidateAddr(pConnectAddr);
  2936. if (status != CC_OK)
  2937. LeaveCallControlTop(status);
  2938. status = SetQ931Port(pDestinationAddr);
  2939. if (status != CS_OK)
  2940. LeaveCallControlTop(status);
  2941. status = SetQ931Port(pConnectAddr);
  2942. if (status != CS_OK)
  2943. LeaveCallControlTop(status);
  2944. status = LockConferenceEx(hConference,
  2945. &pConference,
  2946. TS_FALSE); // bDeferredDelete
  2947. if (status != CC_OK)
  2948. LeaveCallControlTop(status);
  2949. EnumerateCallsInConference(&wNumCalls, NULL, pConference, REAL_CALLS);
  2950. if (wNumCalls > 0) {
  2951. if (pConference->tsMultipointController == TS_TRUE) {
  2952. // Place Call directly to callee
  2953. status = CC_OK;
  2954. ASSERT(!EqualConferenceIDs(&pConference->ConferenceID, &InvalidConferenceID));
  2955. CallType = CALLER;
  2956. CallState = PLACED;
  2957. } else { // we're not the MC
  2958. if (pConference->bMultipointCapable) {
  2959. if (pConference->pMultipointControllerAddr != NULL) {
  2960. // Place Call to MC
  2961. status = CC_OK;
  2962. if (pDestinationAddr == NULL)
  2963. pDestinationAddr = pConnectAddr;
  2964. pConnectAddr = pConference->pMultipointControllerAddr;
  2965. ASSERT(!EqualConferenceIDs(&pConference->ConferenceID, &InvalidConferenceID));
  2966. CallType = THIRD_PARTY_INVITOR;
  2967. CallState = PLACED;
  2968. } else { // we don't have an MC address
  2969. if (pConference->tsMaster == TS_UNKNOWN) {
  2970. ASSERT(pConference->tsMultipointController == TS_UNKNOWN);
  2971. status = CC_OK;
  2972. CallType = CALLER;
  2973. CallState = ENQUEUED;
  2974. } else {
  2975. ASSERT(pConference->tsMultipointController == TS_FALSE);
  2976. // Error, no MC
  2977. // XXX -- we may eventually want to enqueue the request
  2978. // and set an expiration timer
  2979. status = CC_NOT_MULTIPOINT_CAPABLE;
  2980. CallType = THIRD_PARTY_INVITOR;
  2981. CallState = ENQUEUED;
  2982. }
  2983. }
  2984. } else { // we're not multipoint capable
  2985. // Error - bad param
  2986. ASSERT(wNumCalls == 1);
  2987. status = CC_BAD_PARAM;
  2988. }
  2989. }
  2990. } else { // wNumCalls == 0
  2991. // Place Call directly to callee
  2992. status = CC_OK;
  2993. CallType = CALLER;
  2994. CallState = PLACED;
  2995. }
  2996. if (status != CC_OK) {
  2997. UnlockConference(pConference);
  2998. LeaveCallControlTop(status);
  2999. }
  3000. if (pConference->tsMultipointController == TS_TRUE)
  3001. bCallerIsMC = TRUE;
  3002. else
  3003. bCallerIsMC = FALSE;
  3004. // generate CallIdentifier
  3005. status = CoCreateGuid(&CallIdent);
  3006. if(status != S_OK)
  3007. {
  3008. // forget what MSDN and other MS documentation says about this
  3009. // -- If there is no net card, some rev's of OS return an error
  3010. // in cases where a reasonable GUID is generated, but not GUARANTEED
  3011. // to be GLOBALLY unique.
  3012. // if that's not good enough, then just use the uninitialized
  3013. // value of CallIdent - whatever was on the stack is our GUID!!
  3014. // But I want to know in debug builds
  3015. ASSERT(0);
  3016. }
  3017. status = AllocAndLockCall(&hCall,
  3018. hConference,
  3019. CC_INVALID_HANDLE, // hQ931Call
  3020. CC_INVALID_HANDLE, // hQ931CallInvitor
  3021. pLocalAliasNames, // local alias names
  3022. pCalleeAliasNames, // remote alias names
  3023. pCalleeExtraAliasNames,// remote extra alias names
  3024. pCalleeExtension, // remote extension
  3025. pNonStandardData, // local non-standard data
  3026. NULL, // remote non-standard data
  3027. pszDisplay, // local display
  3028. NULL, // remote display
  3029. NULL, // remote vendor info
  3030. NULL, // local connect address
  3031. pConnectAddr, // peer connect address
  3032. pDestinationAddr, // peer destination address
  3033. NULL, // pSourceCallSignalAddress,
  3034. CallType, // call type
  3035. bCallerIsMC,
  3036. dwUserToken, // user token
  3037. CallState, // call state
  3038. &CallIdent, // H225 CallIdentifier
  3039. &pConference->ConferenceID,
  3040. &pCall);
  3041. if (status != CC_OK) {
  3042. UnlockConference(pConference);
  3043. LeaveCallControlTop(status);
  3044. }
  3045. #ifdef GATEKEEPER
  3046. if(GKIExists())
  3047. {
  3048. // Fill in Gatekeeper Call fields
  3049. memset(&pCall->GkiCall, 0, sizeof(pCall->GkiCall));
  3050. if (pCalleeAliasNames != NULL) {
  3051. // make a local copy of the peer alias names
  3052. status = Q931CopyAliasNames(&pCall->GkiCall.pCalleeAliasNames, pCalleeAliasNames);
  3053. if (status != CS_OK) {
  3054. FreeCall(pCall);
  3055. UnlockConference(pConference);
  3056. LeaveCallControlTop(status);
  3057. }
  3058. }
  3059. if (pCalleeExtraAliasNames != NULL) {
  3060. // make a local copy of the peer alias names
  3061. status = Q931CopyAliasNames(&pCall->GkiCall.pCalleeExtraAliasNames,
  3062. pCalleeExtraAliasNames);
  3063. if (status != CS_OK) {
  3064. FreeCall(pCall);
  3065. UnlockConference(pConference);
  3066. LeaveCallControlTop(status);
  3067. }
  3068. }
  3069. pCall->GkiCall.pCall = pCall;
  3070. pCall->GkiCall.hCall = hCall;
  3071. pCall->GkiCall.pConferenceId = pCall->ConferenceID.buffer;
  3072. pCall->GkiCall.bActiveMC = pCall->bCallerIsMC;
  3073. pCall->GkiCall.bAnswerCall = FALSE;
  3074. pCall->GkiCall.CallIdentifier = pCall->CallIdentifier;
  3075. if (pCall->pQ931PeerConnectAddr) {
  3076. pCall->GkiCall.dwIpAddress = ADDRToInetAddr(pCall->pQ931PeerConnectAddr);
  3077. pCall->GkiCall.wPort = ADDRToInetPort(pCall->pQ931PeerConnectAddr);
  3078. } else if (pCall->pQ931DestinationAddr) {
  3079. pCall->GkiCall.dwIpAddress = ADDRToInetAddr(pCall->pQ931DestinationAddr);
  3080. pCall->GkiCall.wPort = ADDRToInetPort(pCall->pQ931DestinationAddr);
  3081. }
  3082. if (pCall->GkiCall.wPort == 0)
  3083. pCall->GkiCall.wPort = CC_H323_HOST_CALL;
  3084. pCall->GkiCall.wPort = (WORD)((pCall->GkiCall.wPort<<8)|(pCall->GkiCall.wPort>>8));
  3085. if (pConference->bMultipointCapable)
  3086. pCall->GkiCall.CallType = MANY_TO_MANY;
  3087. else
  3088. pCall->GkiCall.CallType = POINT_TO_POINT;
  3089. pCall->GkiCall.uBandwidthRequested = dwBandwidth / 100;
  3090. status = GkiOpenCall(&pCall->GkiCall, pConference);
  3091. if (ValidateCall(hCall) == CC_OK) {
  3092. if (status == CC_OK) {
  3093. UnlockCall(pCall);
  3094. *phCall = hCall;
  3095. } else {
  3096. FreeCall(pCall);
  3097. }
  3098. }
  3099. if (ValidateConference(hConference) == CC_OK)
  3100. UnlockConference(pConference);
  3101. }
  3102. else
  3103. {
  3104. // clean GkiCall structure just to be safe.
  3105. memset(&pCall->GkiCall, 0, sizeof(pCall->GkiCall));
  3106. status = PlaceCall(pCall, pConference);
  3107. if (status == CC_OK)
  3108. {
  3109. UnlockCall(pCall);
  3110. *phCall = hCall;
  3111. }
  3112. else
  3113. {
  3114. FreeCall(pCall);
  3115. }
  3116. UnlockConference(pConference);
  3117. }
  3118. #else // GATEKEEPER
  3119. status = PlaceCall(pCall, pConference);
  3120. if (status == CC_OK) {
  3121. UnlockCall(pCall);
  3122. *phCall = hCall;
  3123. } else {
  3124. FreeCall(pCall);
  3125. }
  3126. UnlockConference(pConference);
  3127. #endif // GATEKEEPER
  3128. LeaveCallControlTop(status);
  3129. }
  3130. CC_API
  3131. HRESULT CC_RejectCall( BYTE bRejectReason,
  3132. PCC_NONSTANDARDDATA pNonStandardData,
  3133. CC_HCALL hCall)
  3134. {
  3135. HRESULT status;
  3136. HRESULT SaveStatus;
  3137. PCALL pCall;
  3138. HQ931CALL hQ931Call;
  3139. CC_CONFERENCEID ConferenceID;
  3140. EnterCallControlTop();
  3141. if (InitStatus != CC_OK)
  3142. LeaveCallControlTop(InitStatus);
  3143. if (CallControlState != OPERATIONAL_STATE)
  3144. LeaveCallControlTop(CC_INTERNAL_ERROR);
  3145. SaveStatus = CC_OK;
  3146. // validate parameters
  3147. if ((bRejectReason != CC_REJECT_IN_CONF) &&
  3148. (bRejectReason != CC_REJECT_UNDEFINED_REASON) &&
  3149. (bRejectReason != CC_REJECT_DESTINATION_REJECTION) &&
  3150. (bRejectReason != CC_REJECT_NO_ANSWER) &&
  3151. (bRejectReason != CC_REJECT_NOT_IMPLEMENTED) &&
  3152. (bRejectReason != CC_REJECT_SECURITY_DENIED) &&
  3153. (bRejectReason != CC_REJECT_USER_BUSY)) {
  3154. bRejectReason = CC_REJECT_UNDEFINED_REASON;
  3155. SaveStatus = CC_BAD_PARAM;
  3156. }
  3157. status = ValidateNonStandardData(pNonStandardData);
  3158. if (status != CC_OK)
  3159. LeaveCallControlTop(status);
  3160. if (hCall == CC_INVALID_HANDLE)
  3161. LeaveCallControlTop(CC_BAD_PARAM);
  3162. status = LockCall(hCall, &pCall);
  3163. if (status != CC_OK)
  3164. // note that we can't even tell Q931 to reject the call
  3165. LeaveCallControlTop(status);
  3166. if (pCall->CallState != INCOMING) {
  3167. UnlockCall(pCall);
  3168. LeaveCallControlTop(CC_BAD_PARAM);
  3169. }
  3170. hQ931Call = pCall->hQ931Call;
  3171. ConferenceID = pCall->ConferenceID;
  3172. FreeCall(pCall);
  3173. Q931RejectCall(hQ931Call, // Q931 call handle
  3174. bRejectReason, // reject reason
  3175. &ConferenceID,
  3176. NULL, // alternate address
  3177. pNonStandardData); // non-standard data
  3178. LeaveCallControlTop(SaveStatus);
  3179. }
  3180. CC_API
  3181. HRESULT CC_RejectChannel( CC_HCHANNEL hChannel,
  3182. DWORD dwRejectReason)
  3183. {
  3184. HRESULT status;
  3185. PCHANNEL pChannel;
  3186. PCALL pCall;
  3187. PCONFERENCE pConference;
  3188. EnterCallControlTop();
  3189. if (InitStatus != CC_OK)
  3190. LeaveCallControlTop(InitStatus);
  3191. if (CallControlState != OPERATIONAL_STATE)
  3192. LeaveCallControlTop(CC_INTERNAL_ERROR);
  3193. if (hChannel == CC_INVALID_HANDLE)
  3194. LeaveCallControlTop(CC_BAD_PARAM);
  3195. if ((dwRejectReason != H245_REJ) &&
  3196. (dwRejectReason != H245_REJ_TYPE_NOTSUPPORT) &&
  3197. (dwRejectReason != H245_REJ_TYPE_NOTAVAIL) &&
  3198. (dwRejectReason != H245_REJ_TYPE_UNKNOWN) &&
  3199. (dwRejectReason != H245_REJ_AL_COMB) &&
  3200. (dwRejectReason != H245_REJ_MULTICAST) &&
  3201. (dwRejectReason != H245_REJ_SESSION_ID) &&
  3202. (dwRejectReason != H245_REJ_MASTER_SLAVE_CONFLICT))
  3203. LeaveCallControlTop(CC_BAD_PARAM);
  3204. status = LockChannelAndConference(hChannel, &pChannel, &pConference);
  3205. if (status != CC_OK)
  3206. LeaveCallControlTop(status);
  3207. // Make sure that hChannel is a receive, proxy or bi-directional
  3208. // channel that hasn't already been accepted
  3209. if (((pChannel->bChannelType != RX_CHANNEL) &&
  3210. (pChannel->bChannelType != PROXY_CHANNEL) &&
  3211. (pChannel->bChannelType != TXRX_CHANNEL)) ||
  3212. (pChannel->tsAccepted != TS_UNKNOWN)) {
  3213. UnlockConference(pConference);
  3214. UnlockChannel(pChannel);
  3215. LeaveCallControlTop(CC_BAD_PARAM);
  3216. }
  3217. if (pConference->LocalEndpointAttached != ATTACHED) {
  3218. UnlockChannel(pChannel);
  3219. UnlockConference(pConference);
  3220. LeaveCallControlTop(CC_BAD_PARAM);
  3221. }
  3222. pChannel->tsAccepted = TS_FALSE;
  3223. if (pChannel->wNumOutstandingRequests == 0) {
  3224. ASSERT(pChannel->bMultipointChannel == TRUE);
  3225. ASSERT(pChannel->bChannelType == PROXY_CHANNEL);
  3226. ASSERT(pConference->ConferenceMode == MULTIPOINT_MODE);
  3227. ASSERT(pConference->tsMultipointController == TS_TRUE);
  3228. UnlockConference(pConference);
  3229. UnlockChannel(pChannel);
  3230. LeaveCallControlTop(CC_OK);
  3231. }
  3232. (pChannel->wNumOutstandingRequests)--;
  3233. if (pChannel->wNumOutstandingRequests == 0) {
  3234. status = LockCall(pChannel->hCall, &pCall);
  3235. if (status != CC_OK) {
  3236. UnlockConference(pConference);
  3237. FreeChannel(pChannel);
  3238. LeaveCallControlTop(status);
  3239. }
  3240. status = H245OpenChannelReject(pCall->H245Instance,
  3241. pChannel->wRemoteChannelNumber, // Rx channel
  3242. (WORD)dwRejectReason); // rejection reason
  3243. UnlockCall(pCall);
  3244. FreeChannel(pChannel);
  3245. UnlockConference(pConference);
  3246. LeaveCallControlTop(status);
  3247. }
  3248. // Don't free the channel; it is a PROXY_CHANNEL and we're the MC,
  3249. // so we need to keep the channel object around until the peer that
  3250. // opened it closes it.
  3251. ASSERT(pChannel->bMultipointChannel == TRUE);
  3252. ASSERT(pChannel->bChannelType == PROXY_CHANNEL);
  3253. ASSERT(pConference->ConferenceMode == MULTIPOINT_MODE);
  3254. ASSERT(pConference->tsMultipointController == TS_TRUE);
  3255. UnlockChannel(pChannel);
  3256. UnlockConference(pConference);
  3257. LeaveCallControlTop(status);
  3258. }
  3259. CC_API
  3260. HRESULT CC_RequestMode( CC_HCALL hCall,
  3261. WORD wNumModeDescriptions,
  3262. ModeDescription ModeDescriptions[])
  3263. {
  3264. HRESULT status;
  3265. PCALL pCall;
  3266. PCONFERENCE pConference;
  3267. EnterCallControlTop();
  3268. if (InitStatus != CC_OK)
  3269. LeaveCallControlTop(InitStatus);
  3270. if (CallControlState != OPERATIONAL_STATE)
  3271. LeaveCallControlTop(CC_INTERNAL_ERROR);
  3272. if (hCall == CC_INVALID_HANDLE)
  3273. LeaveCallControlTop(CC_BAD_PARAM);
  3274. if (wNumModeDescriptions == 0)
  3275. LeaveCallControlTop(CC_BAD_PARAM);
  3276. if (ModeDescriptions == NULL)
  3277. LeaveCallControlTop(CC_BAD_PARAM);
  3278. status = LockCallAndConference(hCall, &pCall, &pConference);
  3279. if (status != CC_OK)
  3280. LeaveCallControlTop(status);
  3281. if ((pConference->LocalEndpointAttached != ATTACHED) ||
  3282. (pCall->CallState != CALL_COMPLETE) ||
  3283. (pCall->CallType == VIRTUAL_CALL)) {
  3284. UnlockCall(pCall);
  3285. UnlockConference(pConference);
  3286. LeaveCallControlTop(CC_BAD_PARAM);
  3287. }
  3288. status = H245RequestMode(pCall->H245Instance,
  3289. pCall->H245Instance, // trans ID
  3290. ModeDescriptions,
  3291. wNumModeDescriptions);
  3292. UnlockCall(pCall);
  3293. UnlockConference(pConference);
  3294. LeaveCallControlTop(status);
  3295. }
  3296. CC_API
  3297. HRESULT CC_RequestModeResponse( CC_HCALL hCall,
  3298. CC_REQUEST_MODE_RESPONSE RequestModeResponse)
  3299. {
  3300. HRESULT status;
  3301. PCALL pCall;
  3302. PCONFERENCE pConference;
  3303. BOOL bAccept;
  3304. EnterCallControlTop();
  3305. if (InitStatus != CC_OK)
  3306. LeaveCallControlTop(InitStatus);
  3307. if (CallControlState != OPERATIONAL_STATE)
  3308. LeaveCallControlTop(CC_INTERNAL_ERROR);
  3309. if (hCall == CC_INVALID_HANDLE)
  3310. LeaveCallControlTop(CC_BAD_PARAM);
  3311. switch (RequestModeResponse) {
  3312. case CC_WILL_TRANSMIT_PREFERRED_MODE:
  3313. RequestModeResponse = wllTrnsmtMstPrfrrdMd_chosen;
  3314. bAccept = TRUE;
  3315. break;
  3316. case CC_WILL_TRANSMIT_LESS_PREFERRED_MODE:
  3317. RequestModeResponse = wllTrnsmtLssPrfrrdMd_chosen;
  3318. bAccept = TRUE;
  3319. break;
  3320. case CC_MODE_UNAVAILABLE:
  3321. RequestModeResponse = H245_REJ_UNAVAILABLE;
  3322. bAccept = FALSE;
  3323. break;
  3324. case CC_MULTIPOINT_CONSTRAINT:
  3325. RequestModeResponse = H245_REJ_MULTIPOINT;
  3326. bAccept = FALSE;
  3327. break;
  3328. case CC_REQUEST_DENIED:
  3329. RequestModeResponse = H245_REJ_DENIED;
  3330. bAccept = FALSE;
  3331. break;
  3332. default:
  3333. LeaveCallControlTop(CC_BAD_PARAM);
  3334. }
  3335. status = LockCallAndConference(hCall, &pCall, &pConference);
  3336. if (status != CC_OK)
  3337. LeaveCallControlTop(status);
  3338. status = DequeueSpecificRequest(&pConference->pEnqueuedRequestModeCalls,
  3339. hCall);
  3340. if (status != CC_OK) {
  3341. UnlockCall(pCall);
  3342. UnlockConference(pConference);
  3343. LeaveCallControlTop(status);
  3344. }
  3345. if (bAccept == TRUE) {
  3346. status = H245RequestModeAck(pCall->H245Instance,
  3347. (WORD)RequestModeResponse);
  3348. } else {
  3349. status = H245RequestModeReject(pCall->H245Instance,
  3350. (WORD)RequestModeResponse);
  3351. }
  3352. UnlockCall(pCall);
  3353. UnlockConference(pConference);
  3354. LeaveCallControlTop(status);
  3355. }
  3356. CC_API
  3357. HRESULT CC_SendNonStandardMessage( CC_HCALL hCall,
  3358. BYTE bH245MessageType,
  3359. CC_NONSTANDARDDATA NonStandardData)
  3360. {
  3361. HRESULT status;
  3362. PCALL pCall;
  3363. PCONFERENCE pConference;
  3364. H245_MESSAGE_TYPE_T H245MessageType;
  3365. EnterCallControlTop();
  3366. if (InitStatus != CC_OK)
  3367. LeaveCallControlTop(InitStatus);
  3368. if (CallControlState != OPERATIONAL_STATE)
  3369. LeaveCallControlTop(CC_INTERNAL_ERROR);
  3370. // validate parameters
  3371. if (hCall == CC_INVALID_HANDLE)
  3372. LeaveCallControlTop(CC_BAD_PARAM);
  3373. switch (bH245MessageType) {
  3374. case CC_H245_MESSAGE_REQUEST:
  3375. H245MessageType = H245_MESSAGE_REQUEST;
  3376. break;
  3377. case CC_H245_MESSAGE_RESPONSE:
  3378. H245MessageType = H245_MESSAGE_RESPONSE;
  3379. break;
  3380. case CC_H245_MESSAGE_COMMAND:
  3381. H245MessageType = H245_MESSAGE_COMMAND;
  3382. break;
  3383. case CC_H245_MESSAGE_INDICATION:
  3384. H245MessageType = H245_MESSAGE_INDICATION;
  3385. break;
  3386. default:
  3387. LeaveCallControlTop(CC_BAD_PARAM);
  3388. }
  3389. status = ValidateNonStandardData(&NonStandardData);
  3390. if (status != CC_OK)
  3391. LeaveCallControlTop(status);
  3392. status = LockCallAndConference(hCall,
  3393. &pCall,
  3394. &pConference);
  3395. if (status != CC_OK)
  3396. LeaveCallControlTop(status);
  3397. if ((pConference->LocalEndpointAttached != ATTACHED) ||
  3398. (pCall->CallState != CALL_COMPLETE) ||
  3399. (pCall->CallType == VIRTUAL_CALL)) {
  3400. UnlockCall(pCall);
  3401. UnlockConference(pConference);
  3402. LeaveCallControlTop(CC_BAD_PARAM);
  3403. }
  3404. status = H245NonStandardH221(pCall->H245Instance,
  3405. H245MessageType,
  3406. NonStandardData.sData.pOctetString,
  3407. NonStandardData.sData.wOctetStringLength,
  3408. NonStandardData.bCountryCode,
  3409. NonStandardData.bExtension,
  3410. NonStandardData.wManufacturerCode);
  3411. UnlockCall(pCall);
  3412. UnlockConference(pConference);
  3413. LeaveCallControlTop(status);
  3414. }
  3415. CC_API
  3416. HRESULT CC_SendVendorID( CC_HCALL hCall,
  3417. CC_NONSTANDARDDATA NonStandardData,
  3418. PCC_OCTETSTRING pProductNumber,
  3419. PCC_OCTETSTRING pVersionNumber)
  3420. {
  3421. HRESULT status;
  3422. PCALL pCall;
  3423. PCONFERENCE pConference;
  3424. BYTE *pH245ProductNumber;
  3425. BYTE bProductNumberLength;
  3426. BYTE *pH245VersionNumber;
  3427. BYTE bVersionNumberLength;
  3428. H245_NONSTANDID_T H245Identifier;
  3429. EnterCallControlTop();
  3430. if (InitStatus != CC_OK)
  3431. LeaveCallControlTop(InitStatus);
  3432. if (CallControlState != OPERATIONAL_STATE)
  3433. LeaveCallControlTop(CC_INTERNAL_ERROR);
  3434. // validate parameters
  3435. if (hCall == CC_INVALID_HANDLE)
  3436. LeaveCallControlTop(CC_BAD_PARAM);
  3437. status = ValidateNonStandardData(&NonStandardData);
  3438. if (status != CC_OK)
  3439. LeaveCallControlTop(status);
  3440. status = ValidateOctetString(pProductNumber);
  3441. if (status != CC_OK)
  3442. LeaveCallControlTop(status);
  3443. if (pProductNumber != NULL)
  3444. if (pProductNumber->wOctetStringLength > 255)
  3445. LeaveCallControlTop(CC_BAD_PARAM);
  3446. status = ValidateOctetString(pVersionNumber);
  3447. if (status != CC_OK)
  3448. LeaveCallControlTop(status);
  3449. if (pVersionNumber != NULL)
  3450. if (pVersionNumber->wOctetStringLength > 255)
  3451. LeaveCallControlTop(CC_BAD_PARAM);
  3452. status = LockCallAndConference(hCall,
  3453. &pCall,
  3454. &pConference);
  3455. if (status != CC_OK)
  3456. LeaveCallControlTop(status);
  3457. if ((pConference->LocalEndpointAttached != ATTACHED) ||
  3458. (pCall->CallState != CALL_COMPLETE) ||
  3459. (pCall->CallType == VIRTUAL_CALL)) {
  3460. UnlockCall(pCall);
  3461. UnlockConference(pConference);
  3462. LeaveCallControlTop(CC_BAD_PARAM);
  3463. }
  3464. H245Identifier.choice = h221NonStandard_chosen;
  3465. H245Identifier.u.h221NonStandard.t35CountryCode = NonStandardData.bCountryCode;
  3466. H245Identifier.u.h221NonStandard.t35Extension = NonStandardData.bExtension;
  3467. H245Identifier.u.h221NonStandard.manufacturerCode = NonStandardData.wManufacturerCode;
  3468. if (pProductNumber == NULL) {
  3469. pH245ProductNumber = NULL;
  3470. bProductNumberLength = 0;
  3471. } else {
  3472. pH245ProductNumber = pProductNumber->pOctetString;
  3473. bProductNumberLength = (BYTE)pProductNumber->wOctetStringLength;
  3474. }
  3475. if (pVersionNumber == NULL) {
  3476. pH245VersionNumber = NULL;
  3477. bVersionNumberLength = 0;
  3478. } else {
  3479. pH245VersionNumber = pVersionNumber->pOctetString;
  3480. bVersionNumberLength = (BYTE)pVersionNumber->wOctetStringLength;
  3481. }
  3482. status = H245VendorIdentification(pCall->H245Instance,
  3483. &H245Identifier,
  3484. pH245ProductNumber,
  3485. bProductNumberLength,
  3486. pH245VersionNumber,
  3487. bVersionNumberLength);
  3488. UnlockCall(pCall);
  3489. UnlockConference(pConference);
  3490. LeaveCallControlTop(status);
  3491. }
  3492. CC_API
  3493. HRESULT CC_SetCallControlTimeout( WORD wType,
  3494. DWORD dwDuration)
  3495. {
  3496. HRESULT status;
  3497. DWORD dwRequest;
  3498. DWORD dwSaveDuration;
  3499. EnterCallControlTop();
  3500. if (CallControlState != OPERATIONAL_STATE)
  3501. LeaveCallControlTop(CC_INTERNAL_ERROR);
  3502. status = CC_OK;
  3503. switch (wType) {
  3504. case CC_Q931_ALERTING_TIMEOUT:
  3505. status = Q931SetAlertingTimeout(dwDuration);
  3506. break;
  3507. case CC_H245_RETRY_COUNT:
  3508. status = H245SystemControl(0, H245_SYSCON_SET_FSM_N100, &dwDuration);
  3509. break;
  3510. case CC_H245_TIMEOUT:
  3511. dwRequest = H245_SYSCON_SET_FSM_T101;
  3512. dwSaveDuration = dwDuration;
  3513. while ((dwRequest <= H245_SYSCON_SET_FSM_T109) && (status == CC_OK)) {
  3514. dwDuration = dwSaveDuration;
  3515. // Note -- the following call resets dwDuration
  3516. status = H245SystemControl(0, dwRequest, &dwDuration);
  3517. dwRequest += (H245_SYSCON_SET_FSM_T102 - H245_SYSCON_SET_FSM_T101);
  3518. }
  3519. break;
  3520. default :
  3521. LeaveCallControlTop(CC_BAD_PARAM);
  3522. break;
  3523. }
  3524. LeaveCallControlTop(status);
  3525. }
  3526. CC_API
  3527. HRESULT CC_SetTerminalID( CC_HCONFERENCE hConference,
  3528. PCC_OCTETSTRING pTerminalID)
  3529. {
  3530. HRESULT status;
  3531. PCONFERENCE pConference;
  3532. CC_HCALL hCall;
  3533. PCALL pCall;
  3534. if (InitStatus != CC_OK)
  3535. LeaveCallControlTop(InitStatus);
  3536. if (CallControlState != OPERATIONAL_STATE)
  3537. LeaveCallControlTop(CC_INTERNAL_ERROR);
  3538. // validate parameters
  3539. if (hConference == CC_INVALID_HANDLE)
  3540. LeaveCallControlTop(CC_BAD_PARAM);
  3541. status = ValidateTerminalID(pTerminalID);
  3542. if (status != CC_OK)
  3543. LeaveCallControlTop(status);
  3544. status = LockConference(hConference, &pConference);
  3545. if (status != CC_OK)
  3546. LeaveCallControlTop(status);
  3547. if (pConference->LocalParticipantInfo.TerminalIDState == TERMINAL_ID_VALID) {
  3548. pConference->LocalParticipantInfo.TerminalIDState = TERMINAL_ID_INVALID;
  3549. MemFree(pConference->LocalParticipantInfo.ParticipantInfo.TerminalID.pOctetString);
  3550. pConference->LocalParticipantInfo.ParticipantInfo.TerminalID.pOctetString = NULL;
  3551. pConference->LocalParticipantInfo.ParticipantInfo.TerminalID.wOctetStringLength = 0;
  3552. }
  3553. if ((pTerminalID == NULL) ||
  3554. (pTerminalID->pOctetString == NULL) ||
  3555. (pTerminalID->wOctetStringLength == 0)) {
  3556. UnlockConference(pConference);
  3557. LeaveCallControlTop(CC_OK);
  3558. }
  3559. pConference->LocalParticipantInfo.ParticipantInfo.TerminalID.pOctetString =
  3560. (BYTE *)MemAlloc(pTerminalID->wOctetStringLength);
  3561. if (pConference->LocalParticipantInfo.ParticipantInfo.TerminalID.pOctetString == NULL) {
  3562. UnlockConference(pConference);
  3563. LeaveCallControlTop(CC_NO_MEMORY);
  3564. }
  3565. memcpy(pConference->LocalParticipantInfo.ParticipantInfo.TerminalID.pOctetString,
  3566. pTerminalID->pOctetString,
  3567. pTerminalID->wOctetStringLength);
  3568. pConference->LocalParticipantInfo.ParticipantInfo.TerminalID.wOctetStringLength =
  3569. pTerminalID->wOctetStringLength;
  3570. pConference->LocalParticipantInfo.TerminalIDState = TERMINAL_ID_VALID;
  3571. while (DequeueRequest(&pConference->LocalParticipantInfo.pEnqueuedRequestsForTerminalID,
  3572. &hCall) == CC_OK) {
  3573. if (LockCall(hCall, &pCall) == CC_OK) {
  3574. H245ConferenceResponse(pCall->H245Instance,
  3575. H245_RSP_TERMINAL_ID,
  3576. pConference->LocalParticipantInfo.ParticipantInfo.TerminalLabel.bMCUNumber,
  3577. pConference->LocalParticipantInfo.ParticipantInfo.TerminalLabel.bTerminalNumber,
  3578. pConference->LocalParticipantInfo.ParticipantInfo.TerminalID.pOctetString,
  3579. (BYTE)pConference->LocalParticipantInfo.ParticipantInfo.TerminalID.wOctetStringLength,
  3580. NULL, // terminal list
  3581. 0); // terminal list count
  3582. UnlockCall(pCall);
  3583. }
  3584. }
  3585. UnlockConference(pConference);
  3586. LeaveCallControlTop(CC_OK);
  3587. }
  3588. CC_API
  3589. HRESULT CC_Shutdown()
  3590. {
  3591. if (InitStatus != CC_OK)
  3592. return InitStatus;
  3593. if (CallControlState != OPERATIONAL_STATE)
  3594. return CC_BAD_PARAM;
  3595. // Don't allow any additional threads to enter this DLL
  3596. CallControlState = SHUTDOWN_STATE;
  3597. Q931DeInit();
  3598. DeInitHangupManager();
  3599. DeInitUserManager();
  3600. DeInitQ931Manager();
  3601. DeInitListenManager();
  3602. DeInitH245Manager();
  3603. DeInitChannelManager();
  3604. DeInitCallManager();
  3605. DeInitConferenceManager();
  3606. #ifdef GATEKEEPER
  3607. DeInitGkiManager();
  3608. #endif // GATEKEEPER
  3609. H225DeInit();
  3610. #ifdef FORCE_SERIALIZE_CALL_CONTROL
  3611. UnInitializeCCLock();
  3612. #endif
  3613. return CC_OK;
  3614. }
  3615. CC_API
  3616. HRESULT CC_UnMute( CC_HCHANNEL hChannel)
  3617. {
  3618. HRESULT status;
  3619. HRESULT SaveStatus;
  3620. PCHANNEL pChannel;
  3621. PCONFERENCE pConference;
  3622. PCALL pCall;
  3623. PDU_T Pdu;
  3624. WORD wNumCalls;
  3625. PCC_HCALL CallList;
  3626. WORD i;
  3627. EnterCallControlTop();
  3628. if (InitStatus != CC_OK)
  3629. LeaveCallControlTop(InitStatus);
  3630. if (CallControlState != OPERATIONAL_STATE)
  3631. LeaveCallControlTop(CC_INTERNAL_ERROR);
  3632. if (hChannel == CC_INVALID_HANDLE)
  3633. LeaveCallControlTop(CC_BAD_PARAM);
  3634. status = LockChannelAndConference(hChannel, &pChannel, &pConference);
  3635. if (status != CC_OK)
  3636. LeaveCallControlTop(status);
  3637. if (pChannel->bChannelType != TX_CHANNEL) {
  3638. // can only unmute transmit channels
  3639. UnlockConference(pConference);
  3640. UnlockChannel(pChannel);
  3641. LeaveCallControlTop(CC_BAD_PARAM);
  3642. }
  3643. if (pConference->LocalEndpointAttached != ATTACHED) {
  3644. UnlockChannel(pChannel);
  3645. UnlockConference(pConference);
  3646. LeaveCallControlTop(CC_BAD_PARAM);
  3647. }
  3648. status = EnumerateCallsInConference(&wNumCalls, &CallList, pConference, ESTABLISHED_CALL);
  3649. if (status != CC_OK) {
  3650. UnlockConference(pConference);
  3651. UnlockChannel(pChannel);
  3652. LeaveCallControlTop(status);
  3653. }
  3654. // Construct an H.245 PDU to hold a miscellaneous indication
  3655. // of "logical channel active"
  3656. Pdu.choice = indication_chosen;
  3657. Pdu.u.indication.choice = miscellaneousIndication_chosen;
  3658. Pdu.u.indication.u.miscellaneousIndication.logicalChannelNumber =
  3659. pChannel->wLocalChannelNumber;
  3660. Pdu.u.indication.u.miscellaneousIndication.type.choice = logicalChannelActive_chosen;
  3661. SaveStatus = CC_OK;
  3662. for (i = 0; i < wNumCalls; i++) {
  3663. if (LockCall(CallList[i], &pCall) == CC_OK) {
  3664. status = H245SendPDU(pCall->H245Instance, // H245 instance
  3665. &Pdu);
  3666. // Note that this channel may not have been accepted on all of the calls,
  3667. // so we could get an H245_ERROR_INVALID_CHANNEL error
  3668. if ((status != H245_ERROR_OK) && (status != H245_ERROR_INVALID_CHANNEL))
  3669. SaveStatus = status;
  3670. UnlockCall(pCall);
  3671. }
  3672. }
  3673. if (CallList != NULL)
  3674. MemFree(CallList);
  3675. UnlockConference(pConference);
  3676. UnlockChannel(pChannel);
  3677. LeaveCallControlTop(SaveStatus);
  3678. }
  3679. CC_API
  3680. HRESULT CC_UpdatePeerList( CC_HCONFERENCE hConference)
  3681. {
  3682. HRESULT status;
  3683. PCONFERENCE pConference;
  3684. PCALL pCall;
  3685. WORD wNumCalls;
  3686. WORD i;
  3687. PCC_HCALL CallList;
  3688. CC_PEER_ADD_CALLBACK_PARAMS PeerAddCallbackParams;
  3689. EnterCallControlTop();
  3690. if (InitStatus != CC_OK)
  3691. LeaveCallControlTop(InitStatus);
  3692. if (CallControlState != OPERATIONAL_STATE)
  3693. LeaveCallControlTop(CC_INTERNAL_ERROR);
  3694. if (hConference == CC_INVALID_HANDLE)
  3695. LeaveCallControlTop(CC_BAD_PARAM);
  3696. status = LockConference(hConference, &pConference);
  3697. if (status != CC_OK)
  3698. LeaveCallControlTop(status);
  3699. if ((pConference->ConferenceMode != MULTIPOINT_MODE) ||
  3700. (pConference->LocalEndpointAttached != ATTACHED)) {
  3701. UnlockConference(pConference);
  3702. LeaveCallControlTop(CC_BAD_PARAM);
  3703. }
  3704. if (pConference->tsMultipointController == TS_TRUE) {
  3705. EnumerateCallsInConference(&wNumCalls, &CallList, pConference, ESTABLISHED_CALL);
  3706. for (i = 0; i < wNumCalls; i++) {
  3707. if (LockCall(CallList[i], &pCall) == CC_OK) {
  3708. if (pCall->pPeerParticipantInfo != NULL) {
  3709. PeerAddCallbackParams.hCall = pCall->hCall;
  3710. PeerAddCallbackParams.TerminalLabel =
  3711. pCall->pPeerParticipantInfo->ParticipantInfo.TerminalLabel;
  3712. if (pCall->pPeerParticipantInfo->TerminalIDState == TERMINAL_ID_VALID)
  3713. PeerAddCallbackParams.pPeerTerminalID =
  3714. &pCall->pPeerParticipantInfo->ParticipantInfo.TerminalID;
  3715. else
  3716. PeerAddCallbackParams.pPeerTerminalID = NULL;
  3717. InvokeUserConferenceCallback(pConference,
  3718. CC_PEER_ADD_INDICATION,
  3719. CC_OK,
  3720. &PeerAddCallbackParams);
  3721. if (ValidateCall(CallList[i]) == CC_OK)
  3722. UnlockCall(pCall);
  3723. if (ValidateConference(hConference) != CC_OK) {
  3724. MemFree(CallList);
  3725. LeaveCallControlTop(CC_OK);
  3726. }
  3727. } else // pCall->pPeerParticipantInfo == NULL
  3728. UnlockCall(pCall);
  3729. }
  3730. }
  3731. status = CC_OK;
  3732. } else { // pConference->tsMultipointController != TS_TRUE
  3733. EnumerateCallsInConference(&wNumCalls, &CallList, pConference, VIRTUAL_CALL);
  3734. for (i = 0; i < wNumCalls; i++) {
  3735. if (LockCall(CallList[i], &pCall) == CC_OK) {
  3736. FreeCall(pCall);
  3737. }
  3738. }
  3739. if (CallList != NULL)
  3740. MemFree(CallList);
  3741. EnumerateCallsInConference(&wNumCalls, &CallList, pConference, ESTABLISHED_CALL);
  3742. ASSERT((wNumCalls == 0) || (wNumCalls == 1));
  3743. if (wNumCalls == 1) {
  3744. if (LockCall(CallList[0], &pCall) == CC_OK) {
  3745. // Send TerminalListRequest
  3746. status = H245ConferenceRequest(pCall->H245Instance,
  3747. H245_REQ_TERMINAL_LIST,
  3748. pConference->LocalParticipantInfo.ParticipantInfo.TerminalLabel.bMCUNumber,
  3749. pConference->LocalParticipantInfo.ParticipantInfo.TerminalLabel.bTerminalNumber);
  3750. UnlockCall(pCall);
  3751. }
  3752. }
  3753. }
  3754. if (CallList != NULL)
  3755. MemFree(CallList);
  3756. UnlockConference(pConference);
  3757. LeaveCallControlTop(status);
  3758. }
  3759. CC_API
  3760. HRESULT CC_UserInput( CC_HCALL hCall,
  3761. PWSTR pszUserInput)
  3762. {
  3763. HRESULT status;
  3764. PCALL pCall;
  3765. PCONFERENCE pConference;
  3766. EnterCallControlTop();
  3767. if (InitStatus != CC_OK)
  3768. LeaveCallControlTop(InitStatus);
  3769. if (CallControlState != OPERATIONAL_STATE)
  3770. LeaveCallControlTop(CC_INTERNAL_ERROR);
  3771. if (hCall == CC_INVALID_HANDLE)
  3772. LeaveCallControlTop(CC_BAD_PARAM);
  3773. if (pszUserInput == NULL)
  3774. LeaveCallControlTop(CC_BAD_PARAM);
  3775. if (wcslen(pszUserInput) == 0)
  3776. LeaveCallControlTop(CC_BAD_PARAM);
  3777. status = LockCallAndConference(hCall, &pCall, &pConference);
  3778. if (status != CC_OK)
  3779. LeaveCallControlTop(status);
  3780. if ((pConference->LocalEndpointAttached != ATTACHED) ||
  3781. (pCall->CallState != CALL_COMPLETE) ||
  3782. (pCall->CallType == VIRTUAL_CALL)) {
  3783. UnlockCall(pCall);
  3784. UnlockConference(pConference);
  3785. LeaveCallControlTop(CC_BAD_PARAM);
  3786. }
  3787. status = H245UserInput(pCall->H245Instance,
  3788. pszUserInput,
  3789. NULL);
  3790. UnlockCall(pCall);
  3791. UnlockConference(pConference);
  3792. LeaveCallControlTop(status);
  3793. }
  3794.