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.

1610 lines
49 KiB

  1. /****************************************************************************
  2. *
  3. * $Archive: S:/STURGEON/SRC/CALLCONT/VCS/confman.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.91 $
  14. * $Date: 04 Mar 1997 17:35:06 $
  15. * $Author: MANDREWS $
  16. *
  17. * Deliverable:
  18. *
  19. * Abstract:
  20. *
  21. *
  22. * Notes:
  23. *
  24. ***************************************************************************/
  25. #pragma warning ( disable : 4115 4201 4214 )
  26. #include <nt.h>
  27. #include <ntrtl.h>
  28. #include <nturtl.h>
  29. #include <windows.h>
  30. #pragma warning ( default : 4115 4201 4214 )
  31. #include "apierror.h"
  32. #include "incommon.h"
  33. #include "callcont.h"
  34. #include "q931.h"
  35. #include "ccmain.h"
  36. #include "confman.h"
  37. #include "ccutils.h"
  38. #include "chanman.h"
  39. #include "callman.h"
  40. static BOOL bConferenceInited = FALSE;
  41. static struct {
  42. PCONFERENCE pHead;
  43. LOCK Lock;
  44. } ConferenceTable;
  45. static struct {
  46. CC_HCONFERENCE hConference;
  47. LOCK Lock;
  48. } ConferenceHandle;
  49. CC_CONFERENCEID InvalidConferenceID;
  50. HRESULT InitConferenceManager()
  51. {
  52. ASSERT(bConferenceInited == FALSE);
  53. ConferenceTable.pHead = NULL;
  54. InitializeLock(&ConferenceTable.Lock);
  55. ConferenceHandle.hConference = CC_INVALID_HANDLE + 1;
  56. InitializeLock(&ConferenceHandle.Lock);
  57. memset(&InvalidConferenceID, 0, sizeof(InvalidConferenceID));
  58. bConferenceInited = TRUE;
  59. return CC_OK;
  60. }
  61. HRESULT DeInitConferenceManager()
  62. {
  63. PCONFERENCE pConference;
  64. PCONFERENCE pNextConference;
  65. if (bConferenceInited == FALSE)
  66. return CC_OK;
  67. pConference = ConferenceTable.pHead;
  68. while (pConference != NULL) {
  69. AcquireLock(&pConference->Lock);
  70. pNextConference = pConference->pNextInTable;
  71. FreeConference(pConference);
  72. pConference = pNextConference;
  73. }
  74. DeleteLock(&ConferenceHandle.Lock);
  75. DeleteLock(&ConferenceTable.Lock);
  76. bConferenceInited = FALSE;
  77. return CC_OK;
  78. }
  79. HRESULT _CreateLocalH245H2250MuxCapability(
  80. PCONFERENCE pConference)
  81. {
  82. HRESULT status;
  83. CC_TERMCAP TermCap;
  84. struct MultipointCapability_mediaDistributionCapability RXMediaDistributionCapability;
  85. struct MultipointCapability_mediaDistributionCapability TXMediaDistributionCapability;
  86. struct MultipointCapability_mediaDistributionCapability RXTXMediaDistributionCapability;
  87. ASSERT(pConference != NULL);
  88. if (pConference->pLocalH245H2250MuxCapability != NULL)
  89. H245FreeCap(pConference->pLocalH245H2250MuxCapability);
  90. TermCap.Dir = H245_CAPDIR_LCLRXTX;
  91. TermCap.DataType = H245_DATA_MUX;
  92. TermCap.ClientType = H245_CLIENT_MUX_H2250;
  93. TermCap.CapId = 0; // CapId = 0 is a special case for mux capabilities
  94. TermCap.Cap.H245Mux_H2250.maximumAudioDelayJitter = 60;
  95. TermCap.Cap.H245Mux_H2250.receiveMultipointCapability.multicastCapability = (char)pConference->bMultipointCapable;
  96. TermCap.Cap.H245Mux_H2250.receiveMultipointCapability.multiUniCastConference = FALSE;
  97. TermCap.Cap.H245Mux_H2250.receiveMultipointCapability.mediaDistributionCapability = &RXMediaDistributionCapability;
  98. TermCap.Cap.H245Mux_H2250.receiveMultipointCapability.mediaDistributionCapability->next = NULL;
  99. TermCap.Cap.H245Mux_H2250.receiveMultipointCapability.mediaDistributionCapability->value.bit_mask = 0;
  100. TermCap.Cap.H245Mux_H2250.receiveMultipointCapability.mediaDistributionCapability->value.centralizedControl = FALSE;
  101. TermCap.Cap.H245Mux_H2250.receiveMultipointCapability.mediaDistributionCapability->value.distributedControl = (char)pConference->bMultipointCapable;
  102. TermCap.Cap.H245Mux_H2250.receiveMultipointCapability.mediaDistributionCapability->value.centralizedAudio = FALSE;
  103. TermCap.Cap.H245Mux_H2250.receiveMultipointCapability.mediaDistributionCapability->value.distributedAudio = (char)pConference->bMultipointCapable;
  104. TermCap.Cap.H245Mux_H2250.receiveMultipointCapability.mediaDistributionCapability->value.centralizedVideo = FALSE;
  105. TermCap.Cap.H245Mux_H2250.receiveMultipointCapability.mediaDistributionCapability->value.distributedVideo = (char)pConference->bMultipointCapable;
  106. TermCap.Cap.H245Mux_H2250.receiveMultipointCapability.mediaDistributionCapability->value.centralizedData = NULL;
  107. TermCap.Cap.H245Mux_H2250.receiveMultipointCapability.mediaDistributionCapability->value.distributedData = NULL;
  108. TermCap.Cap.H245Mux_H2250.transmitMultipointCapability.multicastCapability = (char)pConference->bMultipointCapable;
  109. TermCap.Cap.H245Mux_H2250.transmitMultipointCapability.multiUniCastConference = FALSE;
  110. TermCap.Cap.H245Mux_H2250.transmitMultipointCapability.mediaDistributionCapability = &TXMediaDistributionCapability;
  111. TermCap.Cap.H245Mux_H2250.transmitMultipointCapability.mediaDistributionCapability->next = NULL;
  112. TermCap.Cap.H245Mux_H2250.transmitMultipointCapability.mediaDistributionCapability->value.bit_mask = 0;
  113. TermCap.Cap.H245Mux_H2250.transmitMultipointCapability.mediaDistributionCapability->value.centralizedControl = FALSE;
  114. TermCap.Cap.H245Mux_H2250.transmitMultipointCapability.mediaDistributionCapability->value.distributedControl = (char)pConference->bMultipointCapable;
  115. TermCap.Cap.H245Mux_H2250.transmitMultipointCapability.mediaDistributionCapability->value.centralizedAudio = FALSE;
  116. TermCap.Cap.H245Mux_H2250.transmitMultipointCapability.mediaDistributionCapability->value.distributedAudio = (char)pConference->bMultipointCapable;
  117. TermCap.Cap.H245Mux_H2250.transmitMultipointCapability.mediaDistributionCapability->value.centralizedVideo = FALSE;
  118. TermCap.Cap.H245Mux_H2250.transmitMultipointCapability.mediaDistributionCapability->value.distributedVideo = (char)pConference->bMultipointCapable;
  119. TermCap.Cap.H245Mux_H2250.transmitMultipointCapability.mediaDistributionCapability->value.centralizedData = NULL;
  120. TermCap.Cap.H245Mux_H2250.transmitMultipointCapability.mediaDistributionCapability->value.distributedData = NULL;
  121. TermCap.Cap.H245Mux_H2250.rcvAndTrnsmtMltpntCpblty.multicastCapability = (char)pConference->bMultipointCapable;
  122. TermCap.Cap.H245Mux_H2250.rcvAndTrnsmtMltpntCpblty.multiUniCastConference = FALSE;
  123. TermCap.Cap.H245Mux_H2250.rcvAndTrnsmtMltpntCpblty.mediaDistributionCapability = &RXTXMediaDistributionCapability;
  124. TermCap.Cap.H245Mux_H2250.rcvAndTrnsmtMltpntCpblty.mediaDistributionCapability->next = NULL;
  125. TermCap.Cap.H245Mux_H2250.rcvAndTrnsmtMltpntCpblty.mediaDistributionCapability->value.bit_mask = 0;
  126. TermCap.Cap.H245Mux_H2250.rcvAndTrnsmtMltpntCpblty.mediaDistributionCapability->value.centralizedControl = FALSE;
  127. TermCap.Cap.H245Mux_H2250.rcvAndTrnsmtMltpntCpblty.mediaDistributionCapability->value.distributedControl = (char)pConference->bMultipointCapable;
  128. TermCap.Cap.H245Mux_H2250.rcvAndTrnsmtMltpntCpblty.mediaDistributionCapability->value.centralizedAudio = FALSE;
  129. TermCap.Cap.H245Mux_H2250.rcvAndTrnsmtMltpntCpblty.mediaDistributionCapability->value.distributedAudio = (char)pConference->bMultipointCapable;
  130. TermCap.Cap.H245Mux_H2250.rcvAndTrnsmtMltpntCpblty.mediaDistributionCapability->value.centralizedVideo = FALSE;
  131. TermCap.Cap.H245Mux_H2250.rcvAndTrnsmtMltpntCpblty.mediaDistributionCapability->value.distributedVideo = (char)pConference->bMultipointCapable;
  132. TermCap.Cap.H245Mux_H2250.rcvAndTrnsmtMltpntCpblty.mediaDistributionCapability->value.centralizedData = NULL;
  133. TermCap.Cap.H245Mux_H2250.rcvAndTrnsmtMltpntCpblty.mediaDistributionCapability->value.distributedData = NULL;
  134. TermCap.Cap.H245Mux_H2250.mcCapability.centralizedConferenceMC = FALSE;
  135. TermCap.Cap.H245Mux_H2250.mcCapability.decentralizedConferenceMC = (char)pConference->bMultipointCapable;
  136. TermCap.Cap.H245Mux_H2250.rtcpVideoControlCapability = FALSE;
  137. TermCap.Cap.H245Mux_H2250.mediaPacketizationCapability.h261aVideoPacketization = FALSE;
  138. status = H245CopyCap(&pConference->pLocalH245H2250MuxCapability,
  139. &TermCap);
  140. return status;
  141. }
  142. HRESULT _AddConferenceToTable( PCONFERENCE pConference)
  143. {
  144. PCONFERENCE pCurrent;
  145. ASSERT(pConference != NULL);
  146. ASSERT(pConference->hConference != CC_INVALID_HANDLE);
  147. ASSERT(pConference->bInTable == FALSE);
  148. AcquireLock(&ConferenceTable.Lock);
  149. // If a valid non-zero conference ID was specified, make sure
  150. // there's not a duplicate in the conference table
  151. if (!EqualConferenceIDs(&pConference->ConferenceID, &InvalidConferenceID)) {
  152. pCurrent = ConferenceTable.pHead;
  153. while (pCurrent != NULL) {
  154. if (EqualConferenceIDs(&pCurrent->ConferenceID,
  155. &pConference->ConferenceID)) {
  156. RelinquishLock(&ConferenceTable.Lock);
  157. return CC_DUPLICATE_CONFERENCE_ID;
  158. }
  159. pCurrent = pCurrent->pNextInTable;
  160. }
  161. }
  162. pConference->pNextInTable = ConferenceTable.pHead;
  163. pConference->pPrevInTable = NULL;
  164. if (ConferenceTable.pHead != NULL)
  165. ConferenceTable.pHead->pPrevInTable = pConference;
  166. ConferenceTable.pHead = pConference;
  167. pConference->bInTable = TRUE;
  168. RelinquishLock(&ConferenceTable.Lock);
  169. return CC_OK;
  170. }
  171. HRESULT _RemoveConferenceFromTable( PCONFERENCE pConference)
  172. {
  173. CC_HCONFERENCE hConference;
  174. BOOL bTimedOut;
  175. ASSERT(pConference != NULL);
  176. ASSERT(pConference->bInTable == TRUE);
  177. // Caller must have a lock on the conference object;
  178. // in order to avoid deadlock, we must:
  179. // 1. unlock the conference object,
  180. // 2. lock the ConferenceTable,
  181. // 3. locate the conference object in the ConferenceTable (note that
  182. // after step 2, the conference object may be deleted from the
  183. // ConferenceTable by another thread),
  184. // 4. lock the conference object (someone else may have the lock)
  185. // 5. remove the conference object from the ConferenceTable,
  186. // 6. unlock the ConferenceTable
  187. //
  188. // The caller can now safely unlock and destroy the conference object,
  189. // since no other thread will be able to find the object (its been
  190. // removed from the ConferenceTable), and therefore no other thread will
  191. // be able to lock it.
  192. // Save the conference handle; its the only way to look up
  193. // the conference object in the ConferenceTable. Note that we
  194. // can't use pConference to find the conference object, since
  195. // pConference may be free'd up, and another conference object
  196. // allocated at the same address
  197. hConference = pConference->hConference;
  198. // step 1
  199. RelinquishLock(&pConference->Lock);
  200. step2:
  201. // step 2
  202. AcquireLock(&ConferenceTable.Lock);
  203. // step 3
  204. pConference = ConferenceTable.pHead;
  205. while ((pConference != NULL) && (pConference->hConference != hConference))
  206. pConference = pConference->pNextInTable;
  207. if (pConference != NULL) {
  208. // step 4
  209. AcquireTimedLock(&pConference->Lock,10,&bTimedOut);
  210. if (bTimedOut) {
  211. RelinquishLock(&ConferenceTable.Lock);
  212. Sleep(0);
  213. goto step2;
  214. }
  215. // step 5
  216. if (pConference->pPrevInTable == NULL)
  217. ConferenceTable.pHead = pConference->pNextInTable;
  218. else
  219. pConference->pPrevInTable->pNextInTable = pConference->pNextInTable;
  220. if (pConference->pNextInTable != NULL)
  221. pConference->pNextInTable->pPrevInTable = pConference->pPrevInTable;
  222. pConference->pNextInTable = NULL;
  223. pConference->pPrevInTable = NULL;
  224. pConference->bInTable = FALSE;
  225. }
  226. // step 6
  227. RelinquishLock(&ConferenceTable.Lock);
  228. if (pConference == NULL)
  229. return CC_BAD_PARAM;
  230. else
  231. return CC_OK;
  232. }
  233. HRESULT _MakeConferenceHandle( PCC_HCONFERENCE phConference)
  234. {
  235. AcquireLock(&ConferenceHandle.Lock);
  236. *phConference = ConferenceHandle.hConference++;
  237. RelinquishLock(&ConferenceHandle.Lock);
  238. return CC_OK;
  239. }
  240. HRESULT AllocateTerminalNumber( PCONFERENCE pConference,
  241. H245_TERMINAL_LABEL_T *pH245TerminalLabel)
  242. {
  243. unsigned i, j;
  244. BYTE bMask;
  245. ASSERT(pConference != NULL);
  246. ASSERT(pH245TerminalLabel != NULL);
  247. ASSERT(pConference->ConferenceMode == MULTIPOINT_MODE);
  248. ASSERT(pConference->tsMultipointController == TS_TRUE);
  249. for (i = 0; i < NUM_TERMINAL_ALLOCATION_SLOTS; i++) {
  250. bMask = 0x01;
  251. if (pConference->TerminalNumberAllocation[i] != 0xFF) {
  252. for (j = 0; j < 8; j++) {
  253. if ((pConference->TerminalNumberAllocation[i] & bMask) == 0) {
  254. pConference->TerminalNumberAllocation[i] |= bMask;
  255. pH245TerminalLabel->mcuNumber = pConference->LocalParticipantInfo.ParticipantInfo.TerminalLabel.bMCUNumber;
  256. pH245TerminalLabel->terminalNumber = (TerminalNumber)((i * 8) + j + 1);
  257. return CC_OK;
  258. }
  259. bMask *= 2;
  260. }
  261. }
  262. }
  263. // No more terminal numbers are available for this conference
  264. return CC_BAD_PARAM;
  265. }
  266. HRESULT FreeTerminalNumber( PCONFERENCE pConference,
  267. BYTE bTerminalNumber)
  268. {
  269. unsigned i, j;
  270. BYTE bMask;
  271. ASSERT(pConference != NULL);
  272. if (bTerminalNumber > NUM_TERMINAL_ALLOCATION_SLOTS * 8)
  273. return CC_BAD_PARAM;
  274. --bTerminalNumber;
  275. i = bTerminalNumber / 8;
  276. j = bTerminalNumber % 8;
  277. bMask = (BYTE)(0x01 << j);
  278. if ((pConference->TerminalNumberAllocation[i] & bMask) == 0)
  279. return CC_BAD_PARAM;
  280. pConference->TerminalNumberAllocation[i] &= ~bMask;
  281. return CC_OK;
  282. }
  283. HRESULT AllocateChannelNumber( PCONFERENCE pConference,
  284. WORD *pwChannelNumber)
  285. {
  286. unsigned i, j;
  287. BYTE bMask;
  288. ASSERT(pConference != NULL);
  289. ASSERT(pwChannelNumber != NULL);
  290. for (i = 0; i < NUM_CHANNEL_ALLOCATION_SLOTS; i++) {
  291. bMask = 0x01;
  292. if (pConference->ChannelNumberAllocation[i] != 0xFF) {
  293. for (j = 0; j < 8; j++) {
  294. if ((pConference->ChannelNumberAllocation[i] & bMask) == 0) {
  295. pConference->ChannelNumberAllocation[i] |= bMask;
  296. *pwChannelNumber = (WORD) (((i * 8) + j) +
  297. (pConference->LocalParticipantInfo.ParticipantInfo.TerminalLabel.bMCUNumber << 8));
  298. return CC_OK;
  299. }
  300. bMask *= 2;
  301. }
  302. }
  303. }
  304. // No more channel numbers are available for this conference
  305. *pwChannelNumber = 0;
  306. return CC_BAD_PARAM;
  307. }
  308. HRESULT FreeChannelNumber( PCONFERENCE pConference,
  309. WORD wChannelNumber)
  310. {
  311. unsigned i, j;
  312. BYTE bMask;
  313. ASSERT(pConference != NULL);
  314. wChannelNumber &= 0xFF;
  315. if ((wChannelNumber > NUM_CHANNEL_ALLOCATION_SLOTS * 8) ||
  316. (wChannelNumber == 0))
  317. return CC_BAD_PARAM;
  318. i = wChannelNumber / 8;
  319. j = wChannelNumber % 8;
  320. bMask = (BYTE)(0x01 << j);
  321. if ((pConference->ChannelNumberAllocation[i] & bMask) == 0)
  322. return CC_BAD_PARAM;
  323. pConference->ChannelNumberAllocation[i] &= ~bMask;
  324. return CC_OK;
  325. }
  326. HRESULT AllocAndLockConference( PCC_HCONFERENCE phConference,
  327. PCC_CONFERENCEID pConferenceID,
  328. BOOL bMultipointCapable,
  329. BOOL bForceMultipointController,
  330. PCC_TERMCAPLIST pLocalTermCapList,
  331. PCC_TERMCAPDESCRIPTORS pLocalTermCapDescriptors,
  332. PCC_VENDORINFO pVendorInfo,
  333. PCC_OCTETSTRING pTerminalID,
  334. DWORD dwConferenceToken,
  335. CC_SESSIONTABLE_CONSTRUCTOR SessionTableConstructor,
  336. CC_TERMCAP_CONSTRUCTOR TermCapConstructor,
  337. CC_CONFERENCE_CALLBACK ConferenceCallback,
  338. PPCONFERENCE ppConference)
  339. {
  340. WORD i;
  341. HRESULT status;
  342. TRISTATE tsMultipointController;
  343. ASSERT(bConferenceInited == TRUE);
  344. // all parameters should have been validated by the caller
  345. ASSERT(phConference != NULL);
  346. ASSERT(pLocalTermCapList != NULL);
  347. #ifdef DBG
  348. if (pLocalTermCapList->wLength != 0)
  349. ASSERT(pLocalTermCapList->pTermCapArray != NULL);
  350. for (i = 0; i < pLocalTermCapList->wLength; i++)
  351. ASSERT(pLocalTermCapList->pTermCapArray[i] != NULL);
  352. if (pLocalTermCapDescriptors != NULL) {
  353. ASSERT(pLocalTermCapDescriptors->pTermCapDescriptorArray != NULL);
  354. for (i = 0; i < pLocalTermCapDescriptors->wLength; i++)
  355. ASSERT(pLocalTermCapDescriptors->pTermCapDescriptorArray[i] != NULL);
  356. }
  357. #endif
  358. ASSERT(pVendorInfo != NULL);
  359. ASSERT(SessionTableConstructor != NULL);
  360. ASSERT(TermCapConstructor != NULL);
  361. ASSERT(ConferenceCallback != NULL);
  362. ASSERT(ppConference != NULL);
  363. // set phConference now, in case we encounter an error
  364. *phConference = CC_INVALID_HANDLE;
  365. *ppConference = (PCONFERENCE)Malloc(sizeof(CONFERENCE));
  366. if (*ppConference == NULL)
  367. return CC_NO_MEMORY;
  368. if (bForceMultipointController == TRUE)
  369. tsMultipointController = TS_TRUE;
  370. else if (bMultipointCapable == TRUE)
  371. tsMultipointController = TS_UNKNOWN;
  372. else
  373. tsMultipointController = TS_FALSE;
  374. (*ppConference)->bInTable = FALSE;
  375. (*ppConference)->LocalParticipantInfo.TerminalIDState = TERMINAL_ID_INVALID;
  376. (*ppConference)->LocalParticipantInfo.ParticipantInfo.TerminalLabel.bMCUNumber = 1;
  377. (*ppConference)->LocalParticipantInfo.ParticipantInfo.TerminalLabel.bTerminalNumber = 255;
  378. (*ppConference)->LocalParticipantInfo.ParticipantInfo.TerminalID.pOctetString = NULL;
  379. (*ppConference)->LocalParticipantInfo.ParticipantInfo.TerminalID.wOctetStringLength = 0;
  380. (*ppConference)->LocalParticipantInfo.pEnqueuedRequestsForTerminalID = NULL;
  381. for (i = 0; i < NUM_TERMINAL_ALLOCATION_SLOTS; i++)
  382. (*ppConference)->TerminalNumberAllocation[i] = 0;
  383. // Channel 0 is reserved for the H.245 control channel
  384. (*ppConference)->ChannelNumberAllocation[0] = 0x01;
  385. for (i = 1; i < NUM_CHANNEL_ALLOCATION_SLOTS; i++)
  386. (*ppConference)->ChannelNumberAllocation[i] = 0;
  387. (*ppConference)->bMultipointCapable = bMultipointCapable;
  388. (*ppConference)->bForceMC = bForceMultipointController;
  389. (*ppConference)->SessionTableConstructor = SessionTableConstructor;
  390. (*ppConference)->TermCapConstructor = TermCapConstructor;
  391. (*ppConference)->dwConferenceToken = dwConferenceToken;
  392. (*ppConference)->bDeferredDelete = FALSE;
  393. (*ppConference)->bAutoAccept = FALSE; // ignored unless ConferenceCallback is NULL
  394. (*ppConference)->LocalEndpointAttached = NEVER_ATTACHED;
  395. (*ppConference)->ConferenceCallback = ConferenceCallback;
  396. (*ppConference)->SaveConferenceCallback = ConferenceCallback;
  397. (*ppConference)->bSessionTableInternallyConstructed = FALSE;
  398. (*ppConference)->pSessionTable = NULL;
  399. (*ppConference)->pConferenceH245H2250MuxCapability = NULL;
  400. (*ppConference)->pConferenceTermCapList = NULL;
  401. (*ppConference)->pConferenceTermCapDescriptors = NULL;
  402. (*ppConference)->pLocalH245H2250MuxCapability = NULL;
  403. (*ppConference)->pLocalH245TermCapList = NULL;
  404. (*ppConference)->pLocalH245TermCapDescriptors = NULL;
  405. (*ppConference)->pEnqueuedCalls = NULL;
  406. (*ppConference)->pPlacedCalls = NULL;
  407. (*ppConference)->pEstablishedCalls = NULL;
  408. (*ppConference)->pVirtualCalls = NULL;
  409. (*ppConference)->pChannels = NULL;
  410. (*ppConference)->tsMultipointController = tsMultipointController;
  411. (*ppConference)->tsMaster = TS_UNKNOWN;
  412. (*ppConference)->pMultipointControllerAddr = NULL;
  413. (*ppConference)->ConferenceMode = UNCONNECTED_MODE;
  414. (*ppConference)->pVendorInfo = NULL;
  415. (*ppConference)->pEnqueuedRequestModeCalls = NULL;
  416. (*ppConference)->pNextInTable = NULL;
  417. (*ppConference)->pPrevInTable = NULL;
  418. if (pConferenceID == NULL) {
  419. pConferenceID = &InvalidConferenceID;
  420. (*ppConference)->bDynamicConferenceID = TRUE;
  421. } else
  422. (*ppConference)->bDynamicConferenceID = FALSE;
  423. (*ppConference)->ConferenceID = *pConferenceID;
  424. InitializeLock(&(*ppConference)->Lock);
  425. AcquireLock(&(*ppConference)->Lock);
  426. status = _MakeConferenceHandle(&(*ppConference)->hConference);
  427. if (status != CC_OK) {
  428. FreeConference(*ppConference);
  429. return status;
  430. }
  431. if (pTerminalID != NULL) {
  432. (*ppConference)->bDynamicTerminalID = FALSE;
  433. (*ppConference)->LocalParticipantInfo.TerminalIDState = TERMINAL_ID_VALID;
  434. (*ppConference)->LocalParticipantInfo.ParticipantInfo.TerminalID.wOctetStringLength =
  435. pTerminalID->wOctetStringLength;
  436. (*ppConference)->LocalParticipantInfo.ParticipantInfo.TerminalID.pOctetString =
  437. (BYTE *)Malloc(pTerminalID->wOctetStringLength);
  438. if ((*ppConference)->LocalParticipantInfo.ParticipantInfo.TerminalID.pOctetString == NULL) {
  439. FreeConference(*ppConference);
  440. return CC_NO_MEMORY;
  441. }
  442. memcpy((*ppConference)->LocalParticipantInfo.ParticipantInfo.TerminalID.pOctetString,
  443. pTerminalID->pOctetString,
  444. pTerminalID->wOctetStringLength);
  445. } else {
  446. (*ppConference)->bDynamicTerminalID = TRUE;
  447. }
  448. status = _CreateLocalH245H2250MuxCapability(*ppConference);
  449. if (status != CC_OK) {
  450. FreeConference(*ppConference);
  451. return status;
  452. }
  453. // make a local copy of pTermCapList
  454. status = CopyH245TermCapList(&(*ppConference)->pLocalH245TermCapList,
  455. pLocalTermCapList);
  456. if (status != CC_OK) {
  457. FreeConference(*ppConference);
  458. return CC_NO_MEMORY;
  459. }
  460. // create a new descriptor list if one was not supplied
  461. if (pLocalTermCapDescriptors == NULL)
  462. status = CreateH245DefaultTermCapDescriptors(&(*ppConference)->pLocalH245TermCapDescriptors,
  463. (*ppConference)->pLocalH245TermCapList);
  464. else
  465. // make a local copy of pTermCapDescriptors
  466. status = CopyH245TermCapDescriptors(&(*ppConference)->pLocalH245TermCapDescriptors,
  467. pLocalTermCapDescriptors);
  468. if (status != CC_OK) {
  469. FreeConference(*ppConference);
  470. return CC_NO_MEMORY;
  471. }
  472. status = CopyVendorInfo(&((*ppConference)->pVendorInfo), pVendorInfo);
  473. if (status != CC_OK) {
  474. FreeConference(*ppConference);
  475. return status;
  476. }
  477. *phConference = (*ppConference)->hConference;
  478. // add the conference to the conference table
  479. status = _AddConferenceToTable(*ppConference);
  480. if (status != CC_OK)
  481. FreeConference(*ppConference);
  482. // CreateConferenceTermCaps() must be called after _AddConferenceToTable(),
  483. // since it will re-lock the conference object
  484. if ((*ppConference)->tsMultipointController == TS_TRUE) {
  485. status = CreateConferenceTermCaps(*ppConference, NULL);
  486. if (status != CC_OK) {
  487. FreeConference(*ppConference);
  488. return status;
  489. }
  490. }
  491. return status;
  492. }
  493. HRESULT RemoveCallFromConference( PCALL pCall,
  494. PCONFERENCE pConference)
  495. {
  496. ASSERT(pCall != NULL);
  497. ASSERT(pConference != NULL);
  498. // The call object must have been removed from the call table
  499. // prior to removing it from the associated conference object.
  500. // This assures us that no other thread is waiting for a lock on it.
  501. ASSERT(pCall->bInTable == FALSE);
  502. if (pCall->pPrev == NULL) {
  503. // the call object is either at the head of the enqueued call list,
  504. // the head of the placed call list, the head of the established
  505. // call list, the head of the virtual call list, or is detached
  506. // from the conference
  507. if (pConference->pEnqueuedCalls == pCall)
  508. // The call is on the enqueued call list
  509. pConference->pEnqueuedCalls = pCall->pNext;
  510. else if (pConference->pPlacedCalls == pCall)
  511. // the call is on the placed call list
  512. pConference->pPlacedCalls = pCall->pNext;
  513. else if (pConference->pEstablishedCalls == pCall)
  514. // the call is on the established call list
  515. pConference->pEstablishedCalls = pCall->pNext;
  516. else if (pConference->pVirtualCalls == pCall)
  517. pConference->pVirtualCalls = pCall->pNext;
  518. } else
  519. pCall->pPrev->pNext = pCall->pNext;
  520. if (pCall->pNext != NULL)
  521. pCall->pNext->pPrev = pCall->pPrev;
  522. pCall->pNext = NULL;
  523. pCall->pPrev = NULL;
  524. return CC_OK;
  525. }
  526. HRESULT RemoveEnqueuedCallFromConference(
  527. PCONFERENCE pConference,
  528. PCC_HCALL phCall)
  529. {
  530. ASSERT(pConference != NULL);
  531. ASSERT(phCall != NULL);
  532. if (pConference->pEnqueuedCalls == NULL) {
  533. // No enqueued calls; this is not an error, since the caller can't tell
  534. // whether there are any enqueued calls in this conference
  535. *phCall = CC_INVALID_HANDLE;
  536. return CC_OK;
  537. }
  538. // Move the call object from the enqueued call list to the placed
  539. // call list.
  540. // Note that another thread may have a lock on the enqueued call
  541. // object, and may be trying to delete it; they will first need to
  542. // lock the conference object (which this thread has locked), remove
  543. // the call object from the enqueued call list, then free the call object.
  544. // We are therefore safe in creating a pointer to the call object, although
  545. // we may not examine or change any of its contents other than hCall (read-only),
  546. // pNext and pPrev.
  547. *phCall = pConference->pEnqueuedCalls->hCall;
  548. pConference->pEnqueuedCalls = pConference->pEnqueuedCalls->pNext;
  549. if (pConference->pEnqueuedCalls != NULL)
  550. pConference->pEnqueuedCalls->pPrev = NULL;
  551. return CC_OK;
  552. }
  553. HRESULT RemoveChannelFromConference(PCHANNEL pChannel,
  554. PCONFERENCE pConference)
  555. {
  556. ASSERT(pChannel != NULL);
  557. ASSERT(pConference != NULL);
  558. // The channel object must have been removed from the channel table
  559. // prior to removing it from the associated conference object.
  560. // This assures us that no other thread is waiting for a lock on it.
  561. ASSERT(pChannel->bInTable == FALSE);
  562. if (pChannel->pPrev == NULL) {
  563. // the channel object is at the head of the channel list,
  564. // or has been detached from the conference
  565. if (pConference->pChannels == pChannel)
  566. pConference->pChannels = pChannel->pNext;
  567. } else
  568. pChannel->pPrev->pNext = pChannel->pNext;
  569. if (pChannel->pNext != NULL)
  570. pChannel->pNext->pPrev = pChannel->pPrev;
  571. pChannel->pNext = NULL;
  572. pChannel->pPrev = NULL;
  573. return CC_OK;
  574. }
  575. HRESULT AddEnqueuedCallToConference(PCALL pCall,
  576. PCONFERENCE pConference)
  577. {
  578. ASSERT(pCall != NULL);
  579. ASSERT(pConference != NULL);
  580. ASSERT(EqualConferenceIDs(&pCall->ConferenceID, &InvalidConferenceID));
  581. ASSERT(EqualConferenceIDs(&pConference->ConferenceID, &InvalidConferenceID));
  582. ASSERT(pConference->pPlacedCalls != NULL);
  583. // Call cannot already be associated with the conference
  584. ASSERT(pCall->pNext == NULL);
  585. ASSERT(pCall->pPrev == NULL);
  586. pCall->hConference = pConference->hConference;
  587. pCall->pNext = pConference->pEnqueuedCalls;
  588. pCall->pPrev = NULL;
  589. if (pConference->pEnqueuedCalls != NULL) {
  590. ASSERT(pConference->pEnqueuedCalls->pPrev == NULL);
  591. pConference->pEnqueuedCalls->pPrev = pCall;
  592. }
  593. pConference->pEnqueuedCalls = pCall;
  594. return CC_OK;
  595. }
  596. HRESULT AddPlacedCallToConference( PCALL pCall,
  597. PCONFERENCE pConference)
  598. {
  599. ASSERT(pCall != NULL);
  600. ASSERT(pConference != NULL);
  601. if (EqualConferenceIDs(&pConference->ConferenceID,
  602. &InvalidConferenceID)) {
  603. // If a conference ID has not been assigned, but there are
  604. // placed or enqueued calls on the conference, the conference ID
  605. // will be assigned by a callee when the first of these calls completes.
  606. // Since pCall has an assigned conference ID (which will differ from
  607. // the ID to be assigned to this conference), we cannot assign pCall
  608. // to this conference.
  609. ASSERT(pConference->pEstablishedCalls == NULL);
  610. if (pConference->pPlacedCalls != NULL)
  611. return CC_BAD_PARAM;
  612. else
  613. pConference->ConferenceID = pCall->ConferenceID;
  614. } else
  615. if (!EqualConferenceIDs(&pConference->ConferenceID,
  616. &pCall->ConferenceID))
  617. return CC_BAD_PARAM;
  618. pCall->hConference = pConference->hConference;
  619. // Unlink pCall from pConference, if necessary
  620. if (pCall->pPrev == NULL) {
  621. // pCall is at the head of either the enqueued call list,
  622. // the placed call list, or the established call list, or
  623. // is not yet associated with the conference object
  624. if (pConference->pEnqueuedCalls == pCall)
  625. pConference->pEnqueuedCalls = pCall->pNext;
  626. else if (pConference->pPlacedCalls == pCall)
  627. pConference->pPlacedCalls = pCall->pNext;
  628. else if (pConference->pEstablishedCalls == pCall)
  629. pConference->pEstablishedCalls = pCall->pNext;
  630. } else
  631. pCall->pPrev->pNext = pCall->pNext;
  632. if (pCall->pNext != NULL)
  633. pCall->pNext->pPrev = pCall->pPrev;
  634. // Now link pCall into the placed call list
  635. pCall->pNext = pConference->pPlacedCalls;
  636. pCall->pPrev = NULL;
  637. if (pConference->pPlacedCalls != NULL) {
  638. ASSERT(pConference->pPlacedCalls->pPrev == NULL);
  639. pConference->pPlacedCalls->pPrev = pCall;
  640. }
  641. pConference->pPlacedCalls = pCall;
  642. return CC_OK;
  643. }
  644. HRESULT AddEstablishedCallToConference(
  645. PCALL pCall,
  646. PCONFERENCE pConference)
  647. {
  648. ASSERT(pCall != NULL);
  649. ASSERT(pConference != NULL);
  650. ASSERT((EqualConferenceIDs(&pConference->ConferenceID, &InvalidConferenceID)) ||
  651. (EqualConferenceIDs(&pCall->ConferenceID, &pConference->ConferenceID)));
  652. if (EqualConferenceIDs(&pConference->ConferenceID, &InvalidConferenceID)) {
  653. // If a conference ID has not been assigned, but there are
  654. // placed or enqueued calls on the conference, the conference ID
  655. // will be assigned by a callee when the first of these calls completes.
  656. // Since pCall has an assigned conference ID (which will differ from
  657. // the ID to be assigned to this conference), we cannot assign pCall
  658. // to this conference.
  659. ASSERT(pConference->pEstablishedCalls == NULL);
  660. pConference->ConferenceID = pCall->ConferenceID;
  661. } else if (!EqualConferenceIDs(&pConference->ConferenceID, &pCall->ConferenceID))
  662. return CC_BAD_PARAM;
  663. pCall->hConference = pConference->hConference;
  664. // Unlink pCall from pConference, if necessary
  665. if (pCall->pPrev == NULL) {
  666. // pCall is at the head of either the enqueued call list,
  667. // the placed call list, or the established call list, or
  668. // is not yet associated with the conference object
  669. if (pConference->pEnqueuedCalls == pCall)
  670. pConference->pEnqueuedCalls = pCall->pNext;
  671. else if (pConference->pPlacedCalls == pCall)
  672. pConference->pPlacedCalls = pCall->pNext;
  673. else if (pConference->pEstablishedCalls == pCall)
  674. pConference->pEstablishedCalls = pCall->pNext;
  675. } else
  676. pCall->pPrev->pNext = pCall->pNext;
  677. if (pCall->pNext != NULL)
  678. pCall->pNext->pPrev = pCall->pPrev;
  679. // Now link pCall into the established call list
  680. pCall->pNext = pConference->pEstablishedCalls;
  681. pCall->pPrev = NULL;
  682. if (pConference->pEstablishedCalls != NULL) {
  683. ASSERT(pConference->pEstablishedCalls->pPrev == NULL);
  684. pConference->pEstablishedCalls->pPrev = pCall;
  685. }
  686. pConference->pEstablishedCalls = pCall;
  687. return CC_OK;
  688. }
  689. HRESULT AddVirtualCallToConference( PCALL pCall,
  690. PCONFERENCE pConference)
  691. {
  692. ASSERT(pCall != NULL);
  693. ASSERT(pConference != NULL);
  694. ASSERT(pConference->ConferenceMode == MULTIPOINT_MODE);
  695. ASSERT(pConference->tsMultipointController == TS_FALSE);
  696. // Call cannot already be associated with the conference
  697. ASSERT(pCall->pNext == NULL);
  698. ASSERT(pCall->pPrev == NULL);
  699. pCall->hConference = pConference->hConference;
  700. pCall->pNext = pConference->pVirtualCalls;
  701. pCall->pPrev = NULL;
  702. if (pConference->pVirtualCalls != NULL) {
  703. ASSERT(pConference->pVirtualCalls->pPrev == NULL);
  704. pConference->pVirtualCalls->pPrev = pCall;
  705. }
  706. pConference->pVirtualCalls = pCall;
  707. return CC_OK;
  708. }
  709. HRESULT AddChannelToConference( PCHANNEL pChannel,
  710. PCONFERENCE pConference)
  711. {
  712. PPCHANNEL ppChannel;
  713. ASSERT(pChannel != NULL);
  714. ASSERT((pChannel->bChannelType == TX_CHANNEL) ||
  715. (pChannel->bChannelType == RX_CHANNEL) ||
  716. (pChannel->bChannelType == TXRX_CHANNEL) ||
  717. (pChannel->bChannelType == PROXY_CHANNEL));
  718. ASSERT(pConference != NULL);
  719. ASSERT(pChannel->hConference == pConference->hConference);
  720. ASSERT(pChannel->pNext == NULL);
  721. ASSERT(pChannel->pPrev == NULL);
  722. ASSERT(pConference->ConferenceMode != UNCONNECTED_MODE);
  723. if (pConference->pEstablishedCalls == NULL)
  724. // Can't open a channel unless we have at least one established call
  725. return CC_BAD_PARAM;
  726. ppChannel = &pConference->pChannels;
  727. pChannel->pNext = *ppChannel;
  728. pChannel->pPrev = NULL;
  729. if (*ppChannel != NULL) {
  730. ASSERT((*ppChannel)->pPrev == NULL);
  731. (*ppChannel)->pPrev = pChannel;
  732. }
  733. *ppChannel = pChannel;
  734. if (pConference->ConferenceMode == POINT_TO_POINT_MODE)
  735. pChannel->bMultipointChannel = FALSE;
  736. else
  737. pChannel->bMultipointChannel = TRUE;
  738. return CC_OK;
  739. }
  740. // Caller must have a lock on the conference object
  741. // There must be no calls on this conference object
  742. // (previous calls must have been cleared by calling Hangup())
  743. HRESULT FreeConference( PCONFERENCE pConference)
  744. {
  745. CC_HCONFERENCE hConference;
  746. PCALL pVirtualCall;
  747. WORD wNumCalls;
  748. WORD i;
  749. PCC_HCALL CallList;
  750. WORD wNumChannels;
  751. PCC_HCHANNEL ChannelList;
  752. PCHANNEL pChannel;
  753. ASSERT(pConference != NULL);
  754. ASSERT(pConference->pEnqueuedCalls == NULL);
  755. ASSERT(pConference->pPlacedCalls == NULL);
  756. ASSERT(pConference->pEstablishedCalls == NULL);
  757. // caller must have a lock on the conference object,
  758. // so there's no need to re-lock it
  759. hConference = pConference->hConference;
  760. if (pConference->bInTable == TRUE)
  761. if (_RemoveConferenceFromTable(pConference) == CC_BAD_PARAM)
  762. // the conference object was deleted by another thread,
  763. // so just return CC_OK
  764. return CC_OK;
  765. if (pConference->pLocalH245H2250MuxCapability != NULL)
  766. H245FreeCap(pConference->pLocalH245H2250MuxCapability);
  767. // free up the LocalTermCapList elements
  768. DestroyH245TermCapList(&pConference->pLocalH245TermCapList);
  769. // free up the local terminal capability descriptors
  770. DestroyH245TermCapDescriptors(&pConference->pLocalH245TermCapDescriptors);
  771. if (pConference->pMultipointControllerAddr != NULL)
  772. Free(pConference->pMultipointControllerAddr);
  773. if (pConference->pVendorInfo != NULL)
  774. FreeVendorInfo(pConference->pVendorInfo);
  775. if (pConference->pSessionTable != NULL)
  776. FreeConferenceSessionTable(pConference);
  777. if (pConference->pConferenceH245H2250MuxCapability != NULL)
  778. H245FreeCap(pConference->pConferenceH245H2250MuxCapability);
  779. if ((pConference->pConferenceTermCapList != NULL) ||
  780. (pConference->pConferenceTermCapDescriptors != NULL))
  781. FreeConferenceTermCaps(pConference);
  782. if (pConference->LocalParticipantInfo.ParticipantInfo.TerminalID.pOctetString != NULL)
  783. Free(pConference->LocalParticipantInfo.ParticipantInfo.TerminalID.pOctetString);
  784. while (DequeueRequest(&pConference->LocalParticipantInfo.pEnqueuedRequestsForTerminalID, NULL) == CC_OK);
  785. EnumerateCallsInConference(&wNumCalls, &CallList, pConference, VIRTUAL_CALL);
  786. for (i = 0; i < wNumCalls; i++)
  787. if (LockCall(CallList[i], &pVirtualCall) == CC_OK)
  788. FreeCall(pVirtualCall);
  789. if (CallList != NULL)
  790. Free(CallList);
  791. EnumerateChannelsInConference(&wNumChannels, &ChannelList, pConference, ALL_CHANNELS);
  792. for (i = 0; i < wNumChannels; i++)
  793. if (LockChannel(ChannelList[i], &pChannel) == CC_OK)
  794. FreeChannel(pChannel);
  795. if (ChannelList != NULL)
  796. Free(ChannelList);
  797. while (DequeueRequest(&pConference->pEnqueuedRequestModeCalls, NULL) == CC_OK);
  798. // since the conference object has been removed from the ConferenceTable,
  799. // no other thread will be able to find the conference object and obtain
  800. // a lock, so its safe to unlock the conference object and delete it here
  801. RelinquishLock(&pConference->Lock);
  802. DeleteLock(&pConference->Lock);
  803. Free(pConference);
  804. return CC_OK;
  805. }
  806. HRESULT LockConference( CC_HCONFERENCE hConference,
  807. PPCONFERENCE ppConference)
  808. {
  809. BOOL bTimedOut;
  810. ASSERT(hConference != CC_INVALID_HANDLE);
  811. ASSERT(ppConference != NULL);
  812. step1:
  813. AcquireLock(&ConferenceTable.Lock);
  814. *ppConference = ConferenceTable.pHead;
  815. while ((*ppConference != NULL) && ((*ppConference)->hConference != hConference))
  816. *ppConference = (*ppConference)->pNextInTable;
  817. if (*ppConference != NULL) {
  818. AcquireTimedLock(&(*ppConference)->Lock,10,&bTimedOut);
  819. if (bTimedOut) {
  820. RelinquishLock(&ConferenceTable.Lock);
  821. Sleep(0);
  822. goto step1;
  823. }
  824. }
  825. RelinquishLock(&ConferenceTable.Lock);
  826. if (*ppConference == NULL)
  827. return CC_BAD_PARAM;
  828. else
  829. return CC_OK;
  830. }
  831. HRESULT LockConferenceEx( CC_HCONFERENCE hConference,
  832. PPCONFERENCE ppConference,
  833. TRISTATE tsDeferredDelete)
  834. {
  835. BOOL bTimedOut;
  836. ASSERT(hConference != CC_INVALID_HANDLE);
  837. ASSERT(ppConference != NULL);
  838. step1:
  839. AcquireLock(&ConferenceTable.Lock);
  840. *ppConference = ConferenceTable.pHead;
  841. while ((*ppConference != NULL) && ((*ppConference)->hConference != hConference))
  842. *ppConference = (*ppConference)->pNextInTable;
  843. if (*ppConference != NULL) {
  844. AcquireTimedLock(&(*ppConference)->Lock,10,&bTimedOut);
  845. if (bTimedOut) {
  846. RelinquishLock(&ConferenceTable.Lock);
  847. Sleep(0);
  848. goto step1;
  849. }
  850. if (tsDeferredDelete == TS_TRUE) {
  851. if ((*ppConference)->bDeferredDelete != TRUE) {
  852. RelinquishLock(&(*ppConference)->Lock);
  853. *ppConference = NULL;
  854. }
  855. } else if (tsDeferredDelete == TS_FALSE) {
  856. if ((*ppConference)->bDeferredDelete != FALSE) {
  857. RelinquishLock(&(*ppConference)->Lock);
  858. *ppConference = NULL;
  859. }
  860. }
  861. }
  862. RelinquishLock(&ConferenceTable.Lock);
  863. if (*ppConference == NULL)
  864. return CC_BAD_PARAM;
  865. else
  866. return CC_OK;
  867. }
  868. HRESULT ValidateConference( CC_HCONFERENCE hConference)
  869. {
  870. PCONFERENCE pConference;
  871. ASSERT(hConference != CC_INVALID_HANDLE);
  872. AcquireLock(&ConferenceTable.Lock);
  873. pConference = ConferenceTable.pHead;
  874. while ((pConference != NULL) && (pConference->hConference != hConference))
  875. pConference = pConference->pNextInTable;
  876. RelinquishLock(&ConferenceTable.Lock);
  877. if (pConference == NULL)
  878. return CC_BAD_PARAM;
  879. else
  880. return CC_OK;
  881. }
  882. HRESULT LockConferenceID( PCC_CONFERENCEID pConferenceID,
  883. PPCONFERENCE ppConference)
  884. {
  885. BOOL bTimedOut;
  886. ASSERT(!EqualConferenceIDs(pConferenceID, &InvalidConferenceID));
  887. ASSERT(ppConference != NULL);
  888. // There may be many conference objects in the table with unassigned
  889. // conference IDs (ConferenceID = InvalidConferenceID). The caller may
  890. // never ask us to search for an unassigned conference ID.
  891. step1:
  892. AcquireLock(&ConferenceTable.Lock);
  893. *ppConference = ConferenceTable.pHead;
  894. while ((*ppConference != NULL) &&
  895. (!EqualConferenceIDs(&(*ppConference)->ConferenceID, pConferenceID)))
  896. *ppConference = (*ppConference)->pNextInTable;
  897. if (*ppConference != NULL) {
  898. AcquireTimedLock(&(*ppConference)->Lock,10,&bTimedOut);
  899. if (bTimedOut) {
  900. RelinquishLock(&ConferenceTable.Lock);
  901. Sleep(0);
  902. goto step1;
  903. }
  904. }
  905. RelinquishLock(&ConferenceTable.Lock);
  906. if (*ppConference == NULL)
  907. return CC_BAD_PARAM;
  908. else
  909. return CC_OK;
  910. }
  911. HRESULT FindChannelInConference( WORD wChannel,
  912. BOOL bLocalChannel,
  913. BYTE bChannelType,
  914. CC_HCALL hCall,
  915. PCC_HCHANNEL phChannel,
  916. PCONFERENCE pConference)
  917. {
  918. PCHANNEL pChannel;
  919. WORD wChannelNumber;
  920. ASSERT(wChannel != 0);
  921. ASSERT(phChannel != NULL);
  922. ASSERT(pConference != NULL);
  923. *phChannel = CC_INVALID_HANDLE;
  924. pChannel = pConference->pChannels;
  925. while (pChannel != NULL) {
  926. if (bLocalChannel)
  927. wChannelNumber = pChannel->wLocalChannelNumber;
  928. else
  929. wChannelNumber = pChannel->wRemoteChannelNumber;
  930. if ((wChannelNumber == wChannel) &&
  931. ((pChannel->bChannelType & bChannelType) != 0) &&
  932. ((hCall == CC_INVALID_HANDLE) ||
  933. (pChannel->hCall == hCall)))
  934. break;
  935. pChannel = pChannel->pNext;
  936. }
  937. if (pChannel == NULL)
  938. return CC_BAD_PARAM;
  939. *phChannel = pChannel->hChannel;
  940. return CC_OK;
  941. }
  942. HRESULT EnumerateConferences( PWORD pwNumConferences,
  943. CC_HCONFERENCE ConferenceList[])
  944. {
  945. WORD wIndexLimit;
  946. PCONFERENCE pConference;
  947. if ((*pwNumConferences != 0) && (ConferenceList == NULL))
  948. return CC_BAD_PARAM;
  949. if ((*pwNumConferences == 0) && (ConferenceList != NULL))
  950. return CC_BAD_PARAM;
  951. wIndexLimit = *pwNumConferences;
  952. *pwNumConferences = 0;
  953. AcquireLock(&ConferenceTable.Lock);
  954. pConference = ConferenceTable.pHead;
  955. while (pConference != NULL) {
  956. if (*pwNumConferences < wIndexLimit)
  957. ConferenceList[*pwNumConferences] = pConference->hConference;
  958. (*pwNumConferences)++;
  959. pConference = pConference->pNextInTable;
  960. }
  961. RelinquishLock(&ConferenceTable.Lock);
  962. return CC_OK;
  963. }
  964. HRESULT EnumerateCallsInConference( WORD *pwNumCalls,
  965. PCC_HCALL pCallList[],
  966. PCONFERENCE pConference,
  967. BYTE bCallType)
  968. {
  969. WORD i;
  970. PCALL pCall;
  971. ASSERT(pwNumCalls != NULL);
  972. ASSERT(pConference != NULL);
  973. *pwNumCalls = 0;
  974. if (bCallType & ENQUEUED_CALL) {
  975. pCall = pConference->pEnqueuedCalls;
  976. while (pCall != NULL) {
  977. (*pwNumCalls)++;
  978. pCall = pCall->pNext;
  979. }
  980. }
  981. if (bCallType & PLACED_CALL) {
  982. pCall = pConference->pPlacedCalls;
  983. while (pCall != NULL) {
  984. (*pwNumCalls)++;
  985. pCall = pCall->pNext;
  986. }
  987. }
  988. if (bCallType & ESTABLISHED_CALL) {
  989. pCall = pConference->pEstablishedCalls;
  990. while (pCall != NULL) {
  991. (*pwNumCalls)++;
  992. pCall = pCall->pNext;
  993. }
  994. }
  995. if (bCallType & VIRTUAL_CALL) {
  996. pCall = pConference->pVirtualCalls;
  997. while (pCall != NULL) {
  998. (*pwNumCalls)++;
  999. pCall = pCall->pNext;
  1000. }
  1001. }
  1002. if (pCallList == NULL)
  1003. return CC_OK;
  1004. if (*pwNumCalls == 0) {
  1005. *pCallList = NULL;
  1006. return CC_OK;
  1007. }
  1008. *pCallList = (PCC_HCALL)Malloc(sizeof(CC_HCALL) * (*pwNumCalls));
  1009. if (*pCallList == NULL)
  1010. return CC_NO_MEMORY;
  1011. i = 0;
  1012. if (bCallType & ENQUEUED_CALL) {
  1013. pCall = pConference->pEnqueuedCalls;
  1014. while (pCall != NULL) {
  1015. (*pCallList)[i] = pCall->hCall;
  1016. i++;
  1017. pCall = pCall->pNext;
  1018. }
  1019. }
  1020. if (bCallType & PLACED_CALL) {
  1021. pCall = pConference->pPlacedCalls;
  1022. while (pCall != NULL) {
  1023. (*pCallList)[i] = pCall->hCall;
  1024. i++;
  1025. pCall = pCall->pNext;
  1026. }
  1027. }
  1028. if (bCallType & ESTABLISHED_CALL) {
  1029. pCall = pConference->pEstablishedCalls;
  1030. while (pCall != NULL) {
  1031. (*pCallList)[i] = pCall->hCall;
  1032. i++;
  1033. pCall = pCall->pNext;
  1034. }
  1035. }
  1036. if (bCallType & VIRTUAL_CALL) {
  1037. pCall = pConference->pVirtualCalls;
  1038. while (pCall != NULL) {
  1039. (*pCallList)[i] = pCall->hCall;
  1040. i++;
  1041. pCall = pCall->pNext;
  1042. }
  1043. }
  1044. return CC_OK;
  1045. }
  1046. HRESULT EnumerateChannelsInConference(
  1047. WORD *pwNumChannels,
  1048. PCC_HCHANNEL pChannelList[],
  1049. PCONFERENCE pConference,
  1050. BYTE bChannelType)
  1051. {
  1052. WORD i;
  1053. PCHANNEL pChannel;
  1054. ASSERT(pwNumChannels != NULL);
  1055. ASSERT(pConference != NULL);
  1056. *pwNumChannels = 0;
  1057. pChannel = pConference->pChannels;
  1058. while (pChannel != NULL) {
  1059. if (pChannel->bChannelType & bChannelType)
  1060. (*pwNumChannels)++;
  1061. pChannel = pChannel->pNext;
  1062. }
  1063. if (pChannelList == NULL)
  1064. return CC_OK;
  1065. if (*pwNumChannels == 0) {
  1066. *pChannelList = NULL;
  1067. return CC_OK;
  1068. }
  1069. *pChannelList = (PCC_HCHANNEL)Malloc(sizeof(CC_HCHANNEL) * (*pwNumChannels));
  1070. if (*pChannelList == NULL)
  1071. return CC_NO_MEMORY;
  1072. i = 0;
  1073. pChannel = pConference->pChannels;
  1074. while (pChannel != NULL) {
  1075. if (pChannel->bChannelType & bChannelType) {
  1076. (*pChannelList)[i] = pChannel->hChannel;
  1077. i++;
  1078. }
  1079. pChannel = pChannel->pNext;
  1080. }
  1081. return CC_OK;
  1082. }
  1083. HRESULT EnumerateTerminalLabelsInConference(
  1084. WORD *pwNumTerminalLabels,
  1085. H245_TERMINAL_LABEL_T *pH245TerminalLabelList[],
  1086. PCONFERENCE pConference)
  1087. {
  1088. WORD i, j;
  1089. WORD wIndex;
  1090. BYTE bMask;
  1091. ASSERT(pwNumTerminalLabels != NULL);
  1092. ASSERT(pConference != NULL);
  1093. // First count the number of known terminals
  1094. *pwNumTerminalLabels = 0;
  1095. for (i = 0; i < NUM_TERMINAL_ALLOCATION_SLOTS; i++) {
  1096. if (pConference->TerminalNumberAllocation[i] != 0) {
  1097. bMask = 0x01;
  1098. for (j = 0; j < 8; j++) {
  1099. if ((pConference->TerminalNumberAllocation[i] & bMask) != 0)
  1100. (*pwNumTerminalLabels)++;
  1101. bMask *= 2;
  1102. }
  1103. }
  1104. }
  1105. if (pConference->LocalEndpointAttached == ATTACHED)
  1106. (*pwNumTerminalLabels)++;
  1107. if (pH245TerminalLabelList == NULL)
  1108. return CC_OK;
  1109. if (*pwNumTerminalLabels == 0)
  1110. *pH245TerminalLabelList = NULL;
  1111. *pH245TerminalLabelList = (H245_TERMINAL_LABEL_T *)Malloc(sizeof(H245_TERMINAL_LABEL_T) *
  1112. (*pwNumTerminalLabels));
  1113. if (*pH245TerminalLabelList == NULL)
  1114. return CC_NO_MEMORY;
  1115. wIndex = 0;
  1116. for (i = 0; i < NUM_TERMINAL_ALLOCATION_SLOTS; i++) {
  1117. if (pConference->TerminalNumberAllocation[i] != 0) {
  1118. bMask = 0x01;
  1119. for (j = 0; j < 8; j++) {
  1120. if ((pConference->TerminalNumberAllocation[i] & bMask) != 0) {
  1121. (*pH245TerminalLabelList)[wIndex].mcuNumber = pConference->LocalParticipantInfo.ParticipantInfo.TerminalLabel.bMCUNumber;
  1122. (*pH245TerminalLabelList)[wIndex].terminalNumber = (TerminalNumber) ((i * 8) + j + 1);
  1123. wIndex++;
  1124. }
  1125. bMask *= 2;
  1126. }
  1127. }
  1128. }
  1129. if (pConference->LocalEndpointAttached == ATTACHED) {
  1130. (*pH245TerminalLabelList)[wIndex].mcuNumber = pConference->LocalParticipantInfo.ParticipantInfo.TerminalLabel.bMCUNumber;
  1131. (*pH245TerminalLabelList)[wIndex].terminalNumber = 0;
  1132. }
  1133. return CC_OK;
  1134. }
  1135. HRESULT UnlockConference( PCONFERENCE pConference)
  1136. {
  1137. ASSERT(pConference != NULL);
  1138. RelinquishLock(&pConference->Lock);
  1139. return CC_OK;
  1140. }
  1141. HRESULT AsynchronousDestroyConference(
  1142. CC_HCONFERENCE hConference,
  1143. BOOL bAutoAccept)
  1144. {
  1145. HRESULT status;
  1146. PCONFERENCE pConference;
  1147. WORD wNumCalls;
  1148. WORD wNumChannels;
  1149. WORD i;
  1150. PCHANNEL pChannel;
  1151. PCC_HCHANNEL ChannelList;
  1152. status = LockConference(hConference, &pConference);
  1153. if (status != CC_OK)
  1154. return status;
  1155. status = EnumerateCallsInConference(&wNumCalls, NULL, pConference, REAL_CALLS);
  1156. if (status != CC_OK) {
  1157. UnlockConference(pConference);
  1158. return status;
  1159. }
  1160. // This is an illegal call if:
  1161. // 1. The local endpoint is currently attached;
  1162. // 2. The local endpoint has never been attached, but is in the
  1163. // process of placing a call
  1164. if ((pConference->LocalEndpointAttached == ATTACHED) ||
  1165. ((pConference->LocalEndpointAttached == NEVER_ATTACHED) &&
  1166. (wNumCalls > 0))) {
  1167. UnlockConference(pConference);
  1168. return CC_BAD_PARAM;
  1169. }
  1170. pConference->ConferenceCallback = NULL;
  1171. // can't destroy a conference if there are active calls
  1172. if (wNumCalls != 0) {
  1173. pConference->bDeferredDelete = TRUE;
  1174. pConference->bAutoAccept = bAutoAccept;
  1175. UnlockConference(pConference);
  1176. return CC_OK;
  1177. }
  1178. status = EnumerateChannelsInConference(&wNumChannels,
  1179. &ChannelList,
  1180. pConference,
  1181. ALL_CHANNELS);
  1182. if (status != CC_OK) {
  1183. UnlockConference(pConference);
  1184. return status;
  1185. }
  1186. // free all the channels
  1187. for (i = 0; i < wNumChannels; i++) {
  1188. if (LockChannel(ChannelList[i], &pChannel) == CC_OK)
  1189. // Notice that since we're going to hangup, we don't need to
  1190. // close any channels
  1191. FreeChannel(pChannel);
  1192. }
  1193. if (ChannelList != NULL)
  1194. Free(ChannelList);
  1195. FreeConference(pConference);
  1196. return CC_OK;
  1197. }
  1198. HRESULT FindPeerParticipantInfo( H245_TERMINAL_LABEL_T H245TerminalLabel,
  1199. PCONFERENCE pConference,
  1200. BYTE bCallType,
  1201. PCALL *ppCall)
  1202. {
  1203. WORD wNumCalls;
  1204. PCC_HCALL CallList;
  1205. WORD i;
  1206. HRESULT status;
  1207. ASSERT(pConference != NULL);
  1208. ASSERT(ppCall != NULL);
  1209. status = EnumerateCallsInConference(&wNumCalls,
  1210. &CallList,
  1211. pConference,
  1212. bCallType);
  1213. if (status != CC_OK)
  1214. return status;
  1215. for (i = 0; i < wNumCalls; i++) {
  1216. if (LockCall(CallList[i], ppCall) == CC_OK) {
  1217. if ((*ppCall)->pPeerParticipantInfo != NULL)
  1218. if (((*ppCall)->pPeerParticipantInfo->ParticipantInfo.TerminalLabel.bMCUNumber ==
  1219. H245TerminalLabel.mcuNumber) &&
  1220. ((*ppCall)->pPeerParticipantInfo->ParticipantInfo.TerminalLabel.bTerminalNumber ==
  1221. H245TerminalLabel.terminalNumber)) {
  1222. Free(CallList);
  1223. return CC_OK;
  1224. }
  1225. UnlockCall(*ppCall);
  1226. }
  1227. }
  1228. if (CallList != NULL)
  1229. Free(CallList);
  1230. *ppCall = NULL;
  1231. return CC_BAD_PARAM;
  1232. }
  1233. HRESULT ReInitializeConference( PCONFERENCE pConference)
  1234. {
  1235. PCALL pCall;
  1236. WORD wNumCalls;
  1237. WORD i;
  1238. PCC_HCALL CallList;
  1239. PCHANNEL pChannel;
  1240. WORD wNumChannels;
  1241. PCC_HCHANNEL ChannelList;
  1242. HRESULT status;
  1243. ASSERT(pConference != NULL);
  1244. if (pConference->bDynamicConferenceID == TRUE)
  1245. pConference->ConferenceID = InvalidConferenceID;
  1246. pConference->LocalParticipantInfo.ParticipantInfo.TerminalLabel.bMCUNumber = 1;
  1247. pConference->LocalParticipantInfo.ParticipantInfo.TerminalLabel.bTerminalNumber = 255;
  1248. if (pConference->bDynamicTerminalID == TRUE) {
  1249. pConference->LocalParticipantInfo.TerminalIDState = TERMINAL_ID_INVALID;
  1250. Free(pConference->LocalParticipantInfo.ParticipantInfo.TerminalID.pOctetString);
  1251. pConference->LocalParticipantInfo.ParticipantInfo.TerminalID.pOctetString = NULL;
  1252. pConference->LocalParticipantInfo.ParticipantInfo.TerminalID.wOctetStringLength = 0;
  1253. }
  1254. while (DequeueRequest(&pConference->LocalParticipantInfo.pEnqueuedRequestsForTerminalID, NULL) == CC_OK);
  1255. for (i = 0; i < NUM_TERMINAL_ALLOCATION_SLOTS; i++)
  1256. pConference->TerminalNumberAllocation[i] = 0;
  1257. // Channel 0 is reserved for the H.245 control channel
  1258. pConference->ChannelNumberAllocation[0] = 0x01;
  1259. for (i = 1; i < NUM_CHANNEL_ALLOCATION_SLOTS; i++)
  1260. pConference->ChannelNumberAllocation[i] = 0;
  1261. pConference->bDeferredDelete = FALSE;
  1262. pConference->bAutoAccept = FALSE; // ignored unless ConferenceCallback is NULL
  1263. pConference->LocalEndpointAttached = NEVER_ATTACHED;
  1264. if (pConference->pSessionTable != NULL)
  1265. FreeConferenceSessionTable(pConference);
  1266. _CreateLocalH245H2250MuxCapability(pConference);
  1267. if (pConference->pConferenceH245H2250MuxCapability != NULL) {
  1268. H245FreeCap(pConference->pConferenceH245H2250MuxCapability);
  1269. pConference->pConferenceH245H2250MuxCapability = NULL;
  1270. }
  1271. if ((pConference->pConferenceTermCapList != NULL) ||
  1272. (pConference->pConferenceTermCapDescriptors != NULL))
  1273. FreeConferenceTermCaps(pConference);
  1274. pConference->bSessionTableInternallyConstructed = FALSE;
  1275. pConference->ConferenceCallback = pConference->SaveConferenceCallback;
  1276. EnumerateCallsInConference(&wNumCalls, &CallList, pConference, ALL_CALLS);
  1277. for (i = 0; i < wNumCalls; i++)
  1278. if (LockCall(CallList[i], &pCall) == CC_OK)
  1279. FreeCall(pCall);
  1280. if (CallList != NULL)
  1281. Free(CallList);
  1282. EnumerateChannelsInConference(&wNumChannels, &ChannelList, pConference, ALL_CHANNELS);
  1283. for (i = 0; i < wNumChannels; i++)
  1284. if (LockChannel(ChannelList[i], &pChannel) == CC_OK)
  1285. FreeChannel(pChannel);
  1286. if (ChannelList != NULL)
  1287. Free(ChannelList);
  1288. if (pConference->bForceMC == TRUE)
  1289. pConference->tsMultipointController = TS_TRUE;
  1290. else if (pConference->bMultipointCapable == TRUE)
  1291. pConference->tsMultipointController = TS_UNKNOWN;
  1292. else
  1293. pConference->tsMultipointController = TS_FALSE;
  1294. pConference->tsMaster = TS_UNKNOWN;
  1295. pConference->ConferenceMode = UNCONNECTED_MODE;
  1296. if (pConference->pMultipointControllerAddr != NULL) {
  1297. Free(pConference->pMultipointControllerAddr);
  1298. pConference->pMultipointControllerAddr = NULL;
  1299. }
  1300. while (DequeueRequest(&pConference->pEnqueuedRequestModeCalls, NULL) == CC_OK);
  1301. if (pConference->tsMultipointController == TS_TRUE)
  1302. status = CreateConferenceTermCaps(pConference, NULL);
  1303. else
  1304. status = CC_OK;
  1305. return status;
  1306. }