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

1191 lines
30 KiB

  1. /*******************************************************************************
  2. Module Name:
  3. bgapp.cpp
  4. Abstract:
  5. Implements class CBridgeApp
  6. Author:
  7. Qianbo Huai (qhuai) Jan 27 2000
  8. *******************************************************************************/
  9. #include "stdafx.h"
  10. #include <bridge.h>
  11. extern LPSTR glpCmdLine;
  12. /*//////////////////////////////////////////////////////////////////////////////
  13. hard coded SDP
  14. ////*/
  15. const WCHAR * const MySDP = L"\
  16. v=0\n\
  17. o=qhuai 0 0 IN IP4 157.55.89.115\n\
  18. s=BridgeTestConf\n\
  19. c=IN IP4 239.9.20.26/15\n\
  20. t=0 0\n\
  21. m=video 20000 RTP/AVP 34 31\n\
  22. m=audio 20040 RTP/AVP 0 4\n\
  23. ";
  24. const WCHAR * const MySDP2 = L"\
  25. v=0\n\
  26. o=qhuai 0 0 IN IP4 157.55.89.115\n\
  27. s=BridgeTestConf2\n\
  28. c=IN IP4 239.9.20.26/15\n\
  29. t=0 0\n\
  30. m=video 20000 RTP/AVP 34 31\n\
  31. m=audio 20040 RTP/AVP 3\n\
  32. ";
  33. WCHAR *SelfAlias = L"Conference";
  34. /*//////////////////////////////////////////////////////////////////////////////
  35. initiates tapi and listens at h323 address
  36. ////*/
  37. CBridgeApp::CBridgeApp (HRESULT *phr)
  38. {
  39. ENTER_FUNCTION ("CBridgeApp::CBridgeApp");
  40. LOG ((BG_TRACE, "%s entered", __fxName));
  41. *phr = S_OK;
  42. // init members
  43. m_pTapi = NULL;
  44. m_pH323Addr = NULL;
  45. m_pSDPAddr = NULL;
  46. m_pList = new CBridgeItemList ();
  47. if (NULL == m_pList)
  48. {
  49. *phr = E_FAIL;
  50. return;
  51. }
  52. // create tapi
  53. *phr = CoCreateInstance (
  54. CLSID_TAPI,
  55. NULL,
  56. CLSCTX_INPROC_SERVER,
  57. IID_ITTAPI,
  58. (LPVOID *)&m_pTapi
  59. );
  60. if (FAILED(*phr))
  61. return;
  62. // tapi initiate
  63. *phr = m_pTapi->Initialize ();
  64. if (FAILED(*phr))
  65. return;
  66. // associate event with listener
  67. CTAPIEventNotification *pEventNotif = NULL;
  68. IConnectionPointContainer *pContainer = NULL;
  69. IConnectionPoint *pPoint = NULL;
  70. IH323LineEx *pIH323LineEx = NULL;
  71. ULONG ulTapiEventAdvise;
  72. long lCallNotif;
  73. BSTR bstrAddrName = NULL;
  74. // create event notification
  75. pEventNotif = new CTAPIEventNotification;
  76. if (!pEventNotif)
  77. {
  78. *phr = E_OUTOFMEMORY;
  79. goto Error;
  80. }
  81. // get pointer container from tapi
  82. *phr = m_pTapi->QueryInterface (
  83. IID_IConnectionPointContainer,
  84. (void **)&pContainer
  85. );
  86. if (FAILED(*phr))
  87. goto Error;
  88. // get connection point from container
  89. *phr = pContainer->FindConnectionPoint (
  90. IID_ITTAPIEventNotification,
  91. &pPoint
  92. );
  93. if (FAILED(*phr))
  94. goto Error;
  95. // advise event notification on connection pointer
  96. *phr = pPoint->Advise (
  97. pEventNotif,
  98. &ulTapiEventAdvise
  99. );
  100. if (FAILED(*phr))
  101. goto Error;
  102. // put event filter on tapi
  103. *phr = m_pTapi->put_EventFilter (
  104. TE_CALLNOTIFICATION |
  105. TE_CALLSTATE |
  106. TE_CALLMEDIA |
  107. TE_PRIVATE
  108. );
  109. if (FAILED(*phr))
  110. goto Error;
  111. // find h323 address
  112. bstrAddrName = SysAllocString (L"H323 Line");
  113. *phr = FindAddress (
  114. 0,
  115. bstrAddrName,
  116. TAPIMEDIATYPE_AUDIO,
  117. &m_pH323Addr
  118. );
  119. SysFreeString (bstrAddrName);
  120. if (FAILED(*phr))
  121. goto Error;
  122. // check if it supports video
  123. BOOL fSupportsVideo;
  124. if (AddressSupportsMediaType (m_pH323Addr, TAPIMEDIATYPE_VIDEO))
  125. m_lH323MediaType = TAPIMEDIATYPE_AUDIO | TAPIMEDIATYPE_VIDEO;
  126. else
  127. m_lH323MediaType = TAPIMEDIATYPE_AUDIO;
  128. *phr = m_pH323Addr->QueryInterface(&pIH323LineEx);
  129. if (SUCCEEDED(*phr))
  130. {
  131. *phr = pIH323LineEx->SetExternalT120Address(TRUE, INADDR_ANY, 1503);
  132. H245_CAPABILITY Capabilities[] =
  133. {HC_G711, HC_G723, HC_H263QCIF, HC_H261QCIF};
  134. DWORD Weights[] = {200, 100, 100, 0};
  135. *phr = pIH323LineEx->SetDefaultCapabilityPreferrence(
  136. 4, Capabilities, Weights
  137. );
  138. *phr = pIH323LineEx->SetAlias (SelfAlias, wcslen (SelfAlias));
  139. }
  140. // register call notification
  141. *phr = m_pTapi->RegisterCallNotifications (
  142. m_pH323Addr,
  143. VARIANT_TRUE,
  144. VARIANT_TRUE,
  145. m_lH323MediaType,
  146. ulTapiEventAdvise,
  147. &lCallNotif
  148. );
  149. if (FAILED(*phr))
  150. goto Error;
  151. // find sdp address
  152. *phr = FindAddress (
  153. LINEADDRESSTYPE_SDP,
  154. NULL,
  155. TAPIMEDIATYPE_AUDIO,
  156. &m_pSDPAddr
  157. );
  158. if (FAILED(*phr))
  159. goto Error;
  160. // check if it supports video
  161. if (AddressSupportsMediaType (m_pSDPAddr, TAPIMEDIATYPE_VIDEO))
  162. m_lSDPMediaType = TAPIMEDIATYPE_AUDIO | TAPIMEDIATYPE_VIDEO;
  163. else
  164. m_lSDPMediaType = TAPIMEDIATYPE_AUDIO;
  165. Cleanup:
  166. if (pEventNotif)
  167. pEventNotif->Release ();
  168. if (pPoint)
  169. pPoint->Release ();
  170. if (pContainer)
  171. pContainer->Release ();
  172. if (pIH323LineEx)
  173. pIH323LineEx->Release ();
  174. LOG ((BG_TRACE, "%s returns", __fxName));
  175. return;
  176. Error:
  177. if (m_pH323Addr)
  178. {
  179. m_pH323Addr->Release ();
  180. m_pH323Addr = NULL;
  181. }
  182. if (m_pSDPAddr)
  183. {
  184. m_pSDPAddr->Release ();
  185. m_pSDPAddr = NULL;
  186. }
  187. if (m_pTapi)
  188. {
  189. m_pTapi->Release ();
  190. m_pTapi = NULL;
  191. }
  192. if (m_pList)
  193. {
  194. delete m_pList;
  195. }
  196. goto Cleanup;
  197. }
  198. /*//////////////////////////////////////////////////////////////////////////////
  199. ////*/
  200. CBridgeApp::~CBridgeApp ()
  201. {
  202. if (m_pList)
  203. {
  204. // all calls should already been disconnected
  205. delete m_pList;
  206. }
  207. if (m_pSDPAddr)
  208. {
  209. m_pSDPAddr->Release ();
  210. }
  211. if (m_pH323Addr)
  212. {
  213. m_pH323Addr->Release ();
  214. }
  215. if (m_pTapi)
  216. {
  217. m_pTapi->Release ();
  218. }
  219. }
  220. /*///////////////////////////////////////////////////////////////////////////////
  221. ////*/
  222. HRESULT
  223. CBridgeApp::CreateH323Call (IDispatch *pEvent)
  224. {
  225. ENTER_FUNCTION ("CBridgeApp::CreateH323Call");
  226. LOG ((BG_TRACE, "%s entered", __fxName));
  227. HRESULT hr;
  228. BSTR bstrID = NULL;
  229. BSTR bstrName = NULL;
  230. BSTR CallerIDNumber = NULL;
  231. ITCallNotificationEvent *pNotify = NULL;
  232. ITCallInfo *pCallInfo = NULL;
  233. ITBasicCallControl *pCallControl = NULL;
  234. IUnknown *pIUnknown = NULL;
  235. CBridgeItem *pItem = NULL;
  236. // check privilege
  237. CALL_PRIVILEGE privilege;
  238. // get call event interface
  239. hr = pEvent->QueryInterface (
  240. IID_ITCallNotificationEvent,
  241. (void **)&pNotify
  242. );
  243. if (FAILED(hr))
  244. return hr;
  245. // get call info
  246. hr = pNotify->get_Call (&pCallInfo);
  247. if (FAILED(hr))
  248. goto Error;
  249. // if we own the call
  250. hr = pCallInfo->get_Privilege (&privilege);
  251. if (FAILED(hr))
  252. goto Error;
  253. if (CP_OWNER != privilege)
  254. {
  255. hr = E_UNEXPECTED;
  256. goto Error;
  257. }
  258. // get call info string
  259. hr = pCallInfo->get_CallInfoString(CIS_CALLERIDNAME, &bstrName);
  260. if (FAILED (hr))
  261. goto Error;
  262. hr = pCallInfo->get_CallInfoString(CIS_CALLERIDNUMBER, &CallerIDNumber);
  263. if (FAILED(hr))
  264. goto Error;
  265. // construct the caller id
  266. bstrID = SysAllocStringLen(NULL,
  267. SysStringLen(bstrName) + SysStringLen(CallerIDNumber) + 2);
  268. wsprintfW(bstrID, L"%ws@%ws", bstrName, CallerIDNumber);
  269. hr = pCallInfo->QueryInterface (
  270. IID_ITBasicCallControl,
  271. (void **)&pCallControl
  272. );
  273. if (FAILED(hr))
  274. goto Error;
  275. // check if there is an item with same id
  276. if (FAILED (hr = pCallInfo->QueryInterface (IID_IUnknown, (void**)&pIUnknown)))
  277. goto Error;
  278. pItem = m_pList->FindByH323 (pIUnknown);
  279. pIUnknown->Release ();
  280. pIUnknown = NULL;
  281. if (NULL != pItem)
  282. {
  283. // @@ we are already in a call from the same ID
  284. // @@ should have some debug info and feedback?
  285. hr = pCallControl->Disconnect (DC_REJECTED);
  286. // don't care the return value of diconnect
  287. hr = E_ABORT;
  288. goto Error;
  289. }
  290. // everything is right, store the call
  291. pItem = new CBridgeItem;
  292. if (NULL == pItem)
  293. {
  294. hr = E_OUTOFMEMORY;
  295. goto Error;
  296. }
  297. pItem->bstrID = bstrID;
  298. pItem->bstrName = bstrName;
  299. pItem->pCallH323 = pCallControl;
  300. m_pList->Append (pItem);
  301. Cleanup:
  302. if (pNotify) pNotify->Release ();
  303. if (pCallInfo) pCallInfo->Release();
  304. if (CallerIDNumber) SysFreeString(CallerIDNumber);
  305. LOG ((BG_TRACE, "%s returns, %x", __fxName, hr));
  306. return hr;
  307. Error:
  308. if (bstrID) SysFreeString (bstrID);
  309. if (bstrName) SysFreeString (bstrName);
  310. if (pCallControl) pCallControl->Release ();
  311. goto Cleanup;
  312. }
  313. /*///////////////////////////////////////////////////////////////////////////////
  314. ////*/
  315. HRESULT
  316. CBridgeApp::CreateSDPCall (CBridgeItem *pItem)
  317. {
  318. ENTER_FUNCTION ("CBridgeApp::CreateSDPCall");
  319. LOG ((BG_TRACE, "%s entered", __fxName));
  320. HRESULT hr;
  321. // create call, ignore bstrDestAddr, hardcode it here
  322. ITBasicCallControl *pCall = NULL;
  323. BSTR bstrFixedDest;
  324. if (glpCmdLine[0] == '\0')
  325. bstrFixedDest = SysAllocString (MySDP);
  326. else
  327. bstrFixedDest = SysAllocString (MySDP2);
  328. hr = m_pSDPAddr->CreateCall (
  329. bstrFixedDest, // bstrDestAddr,
  330. LINEADDRESSTYPE_SDP,
  331. m_lSDPMediaType,
  332. &pCall
  333. );
  334. SysFreeString (bstrFixedDest);
  335. if (FAILED(hr))
  336. return hr;
  337. // store the call
  338. pItem->pCallSDP = pCall;
  339. LOG ((BG_TRACE, "%s returns", __fxName));
  340. return hr;
  341. }
  342. /*///////////////////////////////////////////////////////////////////////////////
  343. ////*/
  344. HRESULT
  345. CBridgeApp::BridgeCalls (CBridgeItem *pItem)
  346. {
  347. ENTER_FUNCTION ("CBridgeApp::BridgeCalls");
  348. LOG ((BG_TRACE, "%s entered", __fxName));
  349. HRESULT hr;
  350. hr = SetupParticipantInfo (pItem);
  351. if (FAILED(hr))
  352. return hr;
  353. hr = SetMulticastMode (pItem);
  354. if (FAILED(hr))
  355. return hr;
  356. if (FAILED (hr = CreateBridgeTerminals (pItem)))
  357. return hr;
  358. if (FAILED (hr = GetStreams (pItem)))
  359. return hr;
  360. if (FAILED (hr = SelectBridgeTerminals (pItem)))
  361. return hr;
  362. // connect h323 call
  363. if (FAILED (hr = pItem->pCallH323->Answer ()))
  364. return hr;
  365. // connect sdp call
  366. if (FAILED (hr = pItem->pCallSDP->Connect (VARIANT_TRUE)))
  367. {
  368. pItem->pCallH323->Disconnect (DC_NORMAL);
  369. return hr;
  370. }
  371. LOG ((BG_TRACE, "%s returns", __fxName));
  372. return S_OK;
  373. }
  374. /*///////////////////////////////////////////////////////////////////////////////
  375. ////*/
  376. HRESULT
  377. CBridgeApp::DisconnectCall (CBridgeItem *pItem, DISCONNECT_CODE dc)
  378. {
  379. // disconnect
  380. if (pItem->pCallH323)
  381. pItem->pCallH323->Disconnect (dc);
  382. if (pItem->pCallSDP)
  383. pItem->pCallSDP->Disconnect (dc);
  384. return S_OK;
  385. }
  386. /*///////////////////////////////////////////////////////////////////////////////
  387. ////*/
  388. HRESULT
  389. CBridgeApp::DisconnectAllCalls (DISCONNECT_CODE dc)
  390. {
  391. // i should have a better way to traverse each call
  392. CBridgeItem ** pItemArray;
  393. int num, i;
  394. // out of memory
  395. if (!m_pList->GetAllItems (&pItemArray, &num))
  396. return E_OUTOFMEMORY;
  397. // no calls
  398. if (num == 0)
  399. return S_OK;
  400. for (i=0; i<num; i++)
  401. {
  402. // disconnect each call
  403. if (pItemArray[i]->pCallH323)
  404. pItemArray[i]->pCallH323->Disconnect (dc);
  405. if (pItemArray[i]->pCallSDP)
  406. pItemArray[i]->pCallSDP->Disconnect (dc);
  407. // do not delete item
  408. }
  409. free (pItemArray);
  410. return S_OK;
  411. }
  412. /*//////////////////////////////////////////////////////////////////////////////
  413. ////*/
  414. HRESULT
  415. CBridgeApp::RemoveCall (CBridgeItem *pItem)
  416. {
  417. m_pList->TakeOut (pItem);
  418. return S_OK;
  419. }
  420. /*///////////////////////////////////////////////////////////////////////////////
  421. ////*/
  422. HRESULT
  423. CBridgeApp::HasH323Call (IDispatch *pEvent, CBridgeItem **ppItem)
  424. {
  425. HRESULT hr;
  426. ITCallStateEvent *pState = NULL;
  427. ITCallInfo *pCallInfo = NULL;
  428. IUnknown * pIUnknown = NULL;
  429. // ignore null checking
  430. if (*ppItem)
  431. {
  432. delete *ppItem;
  433. *ppItem = NULL;
  434. }
  435. // get call state event
  436. hr = pEvent->QueryInterface (
  437. IID_ITCallStateEvent,
  438. (void **)&pState
  439. );
  440. if (FAILED(hr))
  441. return hr;
  442. // check privilege
  443. CALL_PRIVILEGE privilege;
  444. // get call event interface
  445. hr = pState->get_Call (&pCallInfo);
  446. if (FAILED(hr))
  447. return hr;
  448. // if we own the call
  449. hr = pCallInfo->get_Privilege (&privilege);
  450. if (FAILED(hr))
  451. goto Error;
  452. if (CP_OWNER != privilege)
  453. {
  454. hr = E_UNEXPECTED;
  455. goto Error;
  456. }
  457. // get IUnknown
  458. if (FAILED (hr = pCallInfo->QueryInterface (IID_IUnknown, (void **)&pIUnknown)))
  459. goto Error;
  460. *ppItem = m_pList->FindByH323 (pIUnknown);
  461. Cleanup:
  462. if (pCallInfo) pCallInfo->Release ();
  463. if (pIUnknown) pIUnknown->Release ();
  464. if (pState) pState->Release ();
  465. return hr;
  466. Error:
  467. goto Cleanup;
  468. }
  469. /*//////////////////////////////////////////////////////////////////////////////
  470. ////*/
  471. HRESULT
  472. CBridgeApp::HasCalls ()
  473. {
  474. if (m_pList->IsEmpty ())
  475. return S_FALSE;
  476. else
  477. return S_OK;
  478. }
  479. /*///////////////////////////////////////////////////////////////////////////////
  480. ////*/
  481. HRESULT
  482. CBridgeApp::CreateBridgeTerminals (CBridgeItem *pItem)
  483. {
  484. HRESULT hr;
  485. IConfBridge *pConfBridge = NULL;
  486. // create CConfBridge
  487. hr = CoCreateInstance (
  488. __uuidof(ConfBridge),
  489. NULL,
  490. CLSCTX_INPROC_SERVER,
  491. IID_IConfBridge,
  492. (LPVOID *)&pConfBridge
  493. );
  494. if (FAILED(hr))
  495. return hr;
  496. // create terminal: video H323->SDP
  497. hr = pConfBridge->CreateBridgeTerminal (
  498. TAPIMEDIATYPE_VIDEO,
  499. &(pItem->pTermHSVid)
  500. );
  501. if (FAILED(hr))
  502. goto Error;
  503. // create terminal: audio H323->SDP
  504. hr = pConfBridge->CreateBridgeTerminal (
  505. TAPIMEDIATYPE_AUDIO,
  506. &(pItem->pTermHSAud)
  507. );
  508. if (FAILED(hr))
  509. goto Error;
  510. // create terminal: video SDP->H323
  511. hr = pConfBridge->CreateBridgeTerminal (
  512. TAPIMEDIATYPE_VIDEO,
  513. &(pItem->pTermSHVid)
  514. );
  515. if (FAILED(hr))
  516. goto Error;
  517. // create terminal: audio SDP->H323
  518. hr = pConfBridge->CreateBridgeTerminal (
  519. TAPIMEDIATYPE_AUDIO,
  520. &(pItem->pTermSHAud)
  521. );
  522. if (FAILED(hr))
  523. goto Error;
  524. Cleanup:
  525. pConfBridge->Release ();
  526. pConfBridge = NULL;
  527. return hr;
  528. Error:
  529. goto Cleanup;
  530. }
  531. /*///////////////////////////////////////////////////////////////////////////////
  532. ////*/
  533. HRESULT
  534. CBridgeApp::GetStreams (CBridgeItem *pItem)
  535. {
  536. ITStreamControl *pStreamControl = NULL;
  537. IEnumStream *pEnumStreams = NULL;
  538. ITStream *pStream = NULL;
  539. // get stream control on H323
  540. HRESULT hr = pItem->pCallH323->QueryInterface (
  541. IID_ITStreamControl,
  542. (void **)&pStreamControl
  543. );
  544. if (FAILED(hr))
  545. return hr;
  546. // get enum stream on H323
  547. hr = pStreamControl->EnumerateStreams (&pEnumStreams);
  548. pStreamControl->Release ();
  549. pStreamControl = NULL;
  550. if (FAILED(hr))
  551. return hr;
  552. // iterate each stream on H323
  553. while (S_OK == pEnumStreams->Next (1, &pStream, NULL))
  554. {
  555. if (IsStream (pStream, TAPIMEDIATYPE_VIDEO, TD_CAPTURE))
  556. pItem->pStreamHVidCap = pStream;
  557. else if (IsStream (pStream, TAPIMEDIATYPE_VIDEO, TD_RENDER))
  558. {
  559. pItem->pStreamHVidRen = pStream;
  560. IKeyFrameControl* pIKeyFrameControl = NULL;
  561. hr = pStream->QueryInterface(&pIKeyFrameControl);
  562. if (SUCCEEDED(hr))
  563. {
  564. hr = pIKeyFrameControl->PeriodicUpdatePicture(TRUE, 5);
  565. pIKeyFrameControl->Release();
  566. }
  567. }
  568. else if (IsStream (pStream, TAPIMEDIATYPE_AUDIO, TD_CAPTURE))
  569. pItem->pStreamHAudCap = pStream;
  570. else if (IsStream (pStream, TAPIMEDIATYPE_AUDIO, TD_RENDER))
  571. pItem->pStreamHAudRen = pStream;
  572. else
  573. {
  574. pEnumStreams->Release ();
  575. // @@ IsStream doesn't return hresult
  576. return E_FAIL;
  577. }
  578. }
  579. // don't release pStream, it's stored in pItem
  580. pEnumStreams->Release ();
  581. pEnumStreams = NULL;
  582. //========================================
  583. // get stream control on SDP
  584. hr = pItem->pCallSDP->QueryInterface (
  585. IID_ITStreamControl,
  586. (void **)&pStreamControl
  587. );
  588. if (FAILED(hr))
  589. return hr;
  590. // get enum stream on SDP
  591. hr = pStreamControl->EnumerateStreams (&pEnumStreams);
  592. pStreamControl->Release ();
  593. pStreamControl = NULL;
  594. if (FAILED(hr))
  595. return hr;
  596. // iterate each stream on SDP
  597. while (S_OK == pEnumStreams->Next (1, &pStream, NULL))
  598. {
  599. if (IsStream (pStream, TAPIMEDIATYPE_VIDEO, TD_CAPTURE))
  600. pItem->pStreamSVidCap = pStream;
  601. else if (IsStream (pStream, TAPIMEDIATYPE_VIDEO, TD_RENDER))
  602. pItem->pStreamSVidRen = pStream;
  603. else if (IsStream (pStream, TAPIMEDIATYPE_AUDIO, TD_CAPTURE))
  604. pItem->pStreamSAudCap = pStream;
  605. else if (IsStream (pStream, TAPIMEDIATYPE_AUDIO, TD_RENDER))
  606. pItem->pStreamSAudRen = pStream;
  607. else
  608. {
  609. pEnumStreams->Release ();
  610. // @@ IsStream doesn't return hresult
  611. return E_FAIL;
  612. }
  613. }
  614. // don't release pStream, it's stored in pItem
  615. pEnumStreams->Release ();
  616. pEnumStreams = NULL;
  617. return S_OK;
  618. }
  619. /*///////////////////////////////////////////////////////////////////////////////
  620. ////*/
  621. HRESULT
  622. CBridgeApp::SelectBridgeTerminals (CBridgeItem *pItem)
  623. {
  624. HRESULT hr;
  625. // sdp->h323 audio pair
  626. if (FAILED (hr = pItem->pStreamHAudCap->SelectTerminal (pItem->pTermSHAud)))
  627. return hr;
  628. if (FAILED (hr = pItem->pStreamSAudRen->SelectTerminal (pItem->pTermSHAud)))
  629. return hr;
  630. // h323->sdp audio pair
  631. if (FAILED (hr = pItem->pStreamSAudCap->SelectTerminal (pItem->pTermHSAud)))
  632. return hr;
  633. if (FAILED (hr = pItem->pStreamHAudRen->SelectTerminal (pItem->pTermHSAud)))
  634. return hr;
  635. // sdp->h323 video pair
  636. if (FAILED (hr = pItem->pStreamHVidCap->SelectTerminal (pItem->pTermSHVid)))
  637. return hr;
  638. if (FAILED (hr = pItem->pStreamSVidRen->SelectTerminal (pItem->pTermSHVid)))
  639. return hr;
  640. // h323->sdp video pair
  641. if (FAILED (hr = pItem->pStreamSVidCap->SelectTerminal (pItem->pTermHSVid)))
  642. return hr;
  643. if (FAILED (hr = pItem->pStreamHVidRen->SelectTerminal (pItem->pTermHSVid)))
  644. return hr;
  645. return S_OK;
  646. }
  647. /*///////////////////////////////////////////////////////////////////////////////
  648. ////*/
  649. HRESULT
  650. CBridgeApp::SetupParticipantInfo (CBridgeItem *pItem)
  651. {
  652. HRESULT hr = S_OK;
  653. ITLocalParticipant *pLocalParticipant = NULL;
  654. // set the CName on the SDP side.
  655. hr = pItem->pCallSDP->QueryInterface(&pLocalParticipant);
  656. if (FAILED(hr)) goto Cleanup;
  657. hr = pLocalParticipant->put_LocalParticipantTypedInfo(
  658. PTI_CANONICALNAME, pItem->bstrID
  659. );
  660. if (FAILED(hr)) goto Cleanup;
  661. hr = pLocalParticipant->put_LocalParticipantTypedInfo(
  662. PTI_NAME, pItem->bstrName
  663. );
  664. if (FAILED(hr)) goto Cleanup;
  665. Cleanup:
  666. if (pLocalParticipant) pLocalParticipant->Release();
  667. return hr;
  668. }
  669. /*///////////////////////////////////////////////////////////////////////////////
  670. ////*/
  671. HRESULT
  672. CBridgeApp::SetMulticastMode (CBridgeItem *pItem)
  673. {
  674. IMulticastControl * pIMulticastControl = NULL;
  675. HRESULT hr = pItem->pCallSDP->QueryInterface(&pIMulticastControl);
  676. if (FAILED(hr)) return hr;
  677. hr = pIMulticastControl->put_LoopbackMode(MM_SELECTIVE_LOOPBACK);
  678. pIMulticastControl->Release();
  679. return hr;
  680. }
  681. /*///////////////////////////////////////////////////////////////////////////////
  682. ////*/
  683. HRESULT
  684. CBridgeApp::FindAddress (long dwAddrType, BSTR bstrAddrName, long lMediaType, ITAddress **ppAddr)
  685. {
  686. HRESULT hr;
  687. IEnumAddress *pEnumAddr = NULL;
  688. ITAddress *pAddr = NULL;
  689. ITAddressCapabilities *pAddrCaps = NULL;
  690. BOOL fFound = false;
  691. long lTypeFound;
  692. BSTR bstrAddrNameFound = NULL;
  693. // clear output address
  694. if ((*ppAddr))
  695. {
  696. (*ppAddr)->Release ();
  697. (*ppAddr) = NULL;
  698. }
  699. // enumerate the address
  700. hr = m_pTapi->EnumerateAddresses (&pEnumAddr);
  701. if (FAILED(hr))
  702. {
  703. // @@ should have some debug info here
  704. goto Error;
  705. }
  706. // loop to find the right address
  707. while (!fFound)
  708. {
  709. // next address
  710. if (pAddr)
  711. {
  712. pAddr->Release ();
  713. pAddr = NULL;
  714. }
  715. hr = pEnumAddr->Next (1, &pAddr, NULL);
  716. if (S_OK != hr)
  717. break;
  718. if (dwAddrType != 0)
  719. {
  720. // addr type is valid, ignore addr name
  721. if (pAddrCaps)
  722. {
  723. pAddrCaps->Release ();
  724. pAddrCaps = NULL;
  725. }
  726. hr = pAddr->QueryInterface (
  727. IID_ITAddressCapabilities,
  728. (void **)&pAddrCaps
  729. );
  730. if (FAILED(hr))
  731. {
  732. // @@ debug info here
  733. // DoMessage (L"Failed to retrieve address capabilities");
  734. goto Error;
  735. }
  736. // find address type supported
  737. hr = pAddrCaps->get_AddressCapability (AC_ADDRESSTYPES, &lTypeFound);
  738. if (FAILED(hr))
  739. {
  740. // DoMessage (L"Failed to get address type");
  741. goto Error;
  742. }
  743. // check if the type we wanted
  744. if (dwAddrType != lTypeFound)
  745. continue;
  746. }
  747. else if (bstrAddrName != NULL)
  748. {
  749. hr = pAddr->get_AddressName (&bstrAddrNameFound);
  750. if (FAILED(hr))
  751. {
  752. // DoMessage (L"Failed to get address name");
  753. goto Error;
  754. }
  755. if (wcscmp(bstrAddrName, bstrAddrNameFound) != 0)
  756. continue;
  757. }
  758. else
  759. {
  760. // DoMessage (L"Both address type and name are null. Internal error");
  761. hr = E_UNEXPECTED;
  762. goto Error;
  763. }
  764. // now check media type
  765. if (AddressSupportsMediaType (pAddr, lMediaType))
  766. fFound = true;
  767. } // end of while (!fFound)
  768. if (fFound)
  769. {
  770. (*ppAddr) = pAddr;
  771. (*ppAddr)->AddRef ();
  772. }
  773. Cleanup:
  774. if (pAddrCaps)
  775. pAddrCaps->Release ();
  776. if (pAddr)
  777. pAddr->Release ();
  778. if (pEnumAddr)
  779. pEnumAddr->Release ();
  780. return hr;
  781. Error:
  782. goto Cleanup;
  783. }
  784. /*///////////////////////////////////////////////////////////////////////////////
  785. ////*/
  786. BOOL
  787. CBridgeApp::AddressSupportsMediaType (ITAddress *pAddr, long lMediaType)
  788. {
  789. VARIANT_BOOL vbSupport = VARIANT_FALSE;
  790. ITMediaSupport * pMediaSupport;
  791. if (SUCCEEDED(pAddr->QueryInterface (IID_ITMediaSupport, (void**)&pMediaSupport)))
  792. {
  793. pMediaSupport->QueryMediaType (lMediaType, &vbSupport);
  794. pMediaSupport->Release ();
  795. }
  796. return (vbSupport==VARIANT_TRUE);
  797. }
  798. /*///////////////////////////////////////////////////////////////////////////////
  799. ////*/
  800. BOOL
  801. CBridgeApp::IsStream (ITStream *pStream, long lMediaType, TERMINAL_DIRECTION tdDirection)
  802. {
  803. long mediatype;
  804. TERMINAL_DIRECTION direction;
  805. if (FAILED (pStream->get_Direction(&direction)))
  806. return false;
  807. if (FAILED (pStream->get_MediaType(&mediatype)))
  808. return false;
  809. return ((direction == tdDirection) &&
  810. (mediatype == lMediaType));
  811. }
  812. /*//////////////////////////////////////////////////////////////////////////////
  813. ////*/
  814. HRESULT
  815. CBridgeApp::NextSubStream ()
  816. {
  817. HRESULT hr = S_OK;
  818. CBridgeItem **ItemArray = NULL;
  819. int num, i;
  820. ITSubStreamControl *pSubControl = NULL;
  821. IEnumSubStream *pEnumSub = NULL;
  822. ULONG fetched;
  823. ITSubStream *pSubStream = NULL;
  824. BOOL fActive = FALSE; // if active stream found
  825. ITSubStream *pSubInactive = NULL;
  826. ITSubStream *pSubFirstInactive = NULL;
  827. IEnumTerminal *pEnumTerminal = NULL;
  828. ITParticipantSubStreamControl *pSwitcher = NULL;
  829. // get all stored call items
  830. if (FAILED (hr = m_pList->GetAllItems (&ItemArray, &num)))
  831. return hr;
  832. if (num == 0)
  833. return S_OK;
  834. // for each call item
  835. for (i=0; i<num; i++)
  836. {
  837. // get substream control
  838. if (NULL == ItemArray[i]->pStreamSVidRen)
  839. continue;
  840. if (FAILED (hr = ItemArray[i]->pStreamSVidRen->QueryInterface (&pSubControl)))
  841. goto Error;
  842. // get substreams on sdp video render
  843. if (FAILED (hr = pSubControl->EnumerateSubStreams (&pEnumSub)))
  844. goto Error;
  845. pSubControl->Release ();
  846. pSubControl = NULL;
  847. // for each substream, if !(both active & inactive substream stored)
  848. // the algo tries to be as fair as possible in switching.
  849. // it switches the inactive substream just after the active one
  850. // if the active one is the last in the enum, the first inactive one is chosen
  851. while (!pSubInactive &&
  852. (S_OK == (hr = pEnumSub->Next (1, &pSubStream, &fetched)))
  853. )
  854. {
  855. // get terminal enumerator
  856. if (FAILED (hr = pSubStream->EnumerateTerminals (&pEnumTerminal)))
  857. goto Error;
  858. // if the substream active, store the substream
  859. if (S_OK == pEnumTerminal->Skip (1))
  860. {
  861. if (fActive)
  862. ;
  863. // printf ("oops, another active substream on SDP video render stream");
  864. else
  865. fActive = TRUE;
  866. }
  867. else
  868. {
  869. // if inactive, store the substream
  870. if (!pSubFirstInactive)
  871. {
  872. // the first inactive substream
  873. pSubFirstInactive = pSubStream;
  874. pSubFirstInactive->AddRef ();
  875. }
  876. else
  877. {
  878. // store the inactive only if the active was found
  879. if (fActive)
  880. {
  881. pSubInactive = pSubStream;
  882. pSubInactive->AddRef ();
  883. }
  884. }
  885. }
  886. // release
  887. pEnumTerminal->Release ();
  888. pEnumTerminal = NULL;
  889. pSubStream->Release ();
  890. pSubStream = NULL;
  891. }
  892. pEnumSub->Release ();
  893. pEnumSub = NULL;
  894. // if only first inactive is found
  895. if (pSubFirstInactive && !pSubInactive)
  896. {
  897. pSubInactive = pSubFirstInactive;
  898. pSubFirstInactive = NULL;
  899. }
  900. // if not found two substreams, do nothing
  901. if (pSubInactive && ItemArray[i]->pStreamSVidRen && ItemArray[i]->pTermSHVid)
  902. {
  903. if (FAILED (hr = ItemArray[i]->pStreamSVidRen->QueryInterface (&pSwitcher)))
  904. goto Error;
  905. // switch terminal on substream
  906. if (FAILED (hr = pSwitcher->SwitchTerminalToSubStream
  907. (ItemArray[i]->pTermSHVid, pSubInactive)))
  908. goto Error;
  909. pSwitcher->Release ();
  910. pSwitcher = NULL;
  911. }
  912. if (pSubFirstInactive)
  913. {
  914. pSubFirstInactive->Release ();
  915. pSubFirstInactive = NULL;
  916. }
  917. if (pSubInactive)
  918. {
  919. pSubInactive->Release ();
  920. pSubInactive = NULL;
  921. }
  922. }
  923. Cleanup:
  924. if (ItemArray) free (ItemArray);
  925. return hr;
  926. Error:
  927. if (pSubControl) pSubControl->Release ();
  928. if (pEnumSub) pEnumSub->Release ();
  929. if (pSubStream) pSubStream->Release ();
  930. if (pSubInactive) pSubInactive->Release ();
  931. if (pSubFirstInactive) pSubFirstInactive->Release ();
  932. if (pEnumTerminal) pEnumTerminal->Release ();
  933. if (pSwitcher) pSwitcher->Release ();
  934. goto Cleanup;
  935. }
  936. /*//////////////////////////////////////////////////////////////////////////////
  937. ////*/
  938. HRESULT
  939. CBridgeApp::ShowParticipant (ITBasicCallControl *pSDPCall, ITParticipant *pParticipant)
  940. {
  941. ENTER_FUNCTION ("CBridgeApp::ShowParticipant");
  942. HRESULT hr;
  943. IUnknown *pIUnknown = NULL;
  944. CBridgeItem *pItem = NULL;
  945. ITParticipantSubStreamControl *pSwitcher = NULL;
  946. ITSubStream *pSubStream = NULL;
  947. // get IUnknown
  948. if (FAILED (hr = pSDPCall->QueryInterface (IID_IUnknown, (void**)&pIUnknown)))
  949. {
  950. LOG ((BG_ERROR, "%s failed to query interface IUnknown, %x", __fxName, hr));
  951. return hr;
  952. }
  953. // find the item matches pSDPCall
  954. pItem = m_pList->FindBySDP (pIUnknown);
  955. pIUnknown->Release ();
  956. pIUnknown = NULL;
  957. // oops, no match
  958. if (NULL == pItem)
  959. return S_FALSE;
  960. // get participant substream control interface
  961. if (NULL == pItem->pStreamSVidRen)
  962. return S_OK;
  963. if (FAILED (hr = pItem->pStreamSVidRen->QueryInterface (&pSwitcher)))
  964. {
  965. LOG ((BG_ERROR, "%s failed to query interface ITParticipantSubStreamControl, %x", __fxName, hr));
  966. return hr;
  967. }
  968. // get substream from participant
  969. if (FAILED (hr = pSwitcher->get_SubStreamFromParticipant (pParticipant, &pSubStream)))
  970. {
  971. pSwitcher->Release ();
  972. pSwitcher = NULL;
  973. LOG ((BG_WARN, "%s failed to get substream from participant, %x", __fxName, hr));
  974. // stream from h323 side does not have substream, report false
  975. return S_FALSE;
  976. }
  977. // switch
  978. if (pItem->pTermSHVid)
  979. hr = pSwitcher->SwitchTerminalToSubStream (pItem->pTermSHVid, pSubStream);
  980. pSubStream->Release ();
  981. pSubStream = NULL;
  982. pSwitcher->Release ();
  983. pSwitcher = NULL;
  984. return hr;
  985. }