Source code of Windows XP (NT5)
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.

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