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.

2948 lines
72 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. confcall.cpp
  5. Abstract:
  6. This module contains implementation of CIPConfMSPCall.
  7. Author:
  8. Mu Han (muhan) 5-September-1998
  9. --*/
  10. #include "stdafx.h"
  11. #include <confpdu.h>
  12. CIPConfMSPCall::CIPConfMSPCall()
  13. : m_fLocalInfoRetrieved(FALSE),
  14. m_fShutDown(FALSE),
  15. m_dwIPInterface(INADDR_ANY),
  16. m_LoopbackMode(MM_NO_LOOPBACK),
  17. m_hAudioRTPSession(NULL),
  18. m_hVideoRTPSession(NULL),
  19. m_pIAudioDuplexController(NULL),
  20. m_fCallStarted(FALSE),
  21. m_pApplicationID(NULL),
  22. m_pApplicationGUID(NULL),
  23. m_pSubIDs(NULL),
  24. m_pCallQCRelay(NULL)
  25. {
  26. ZeroMemory(m_InfoItems, sizeof(m_InfoItems));
  27. }
  28. CIPConfMSPCall::~CIPConfMSPCall()
  29. {
  30. if (m_pApplicationID)
  31. {
  32. SysFreeString(m_pApplicationID);
  33. }
  34. if (m_pApplicationGUID)
  35. {
  36. SysFreeString(m_pApplicationGUID);
  37. }
  38. if (m_pSubIDs)
  39. {
  40. SysFreeString(m_pSubIDs);
  41. }
  42. if (m_pCallQCRelay)
  43. {
  44. delete m_pCallQCRelay;
  45. }
  46. }
  47. STDMETHODIMP CIPConfMSPCall::CreateStream(
  48. IN long lMediaType,
  49. IN TERMINAL_DIRECTION Direction,
  50. IN OUT ITStream ** ppStream
  51. )
  52. {
  53. // This MSP doesn't support creating new streams on the fly.
  54. return TAPI_E_NOTSUPPORTED;
  55. }
  56. STDMETHODIMP CIPConfMSPCall::RemoveStream(
  57. IN ITStream * pStream
  58. )
  59. {
  60. // This MSP doesn't support removing streams either.
  61. return TAPI_E_NOTSUPPORTED;
  62. }
  63. HRESULT CIPConfMSPCall::InitializeLocalParticipant()
  64. /*++
  65. Routine Description:
  66. This function uses the RTP filter to find out the local information that
  67. will be used in the call. The infomation is stored in a local participant
  68. object.
  69. Arguments:
  70. Return Value:
  71. HRESULT.
  72. --*/
  73. {
  74. m_fLocalInfoRetrieved = FALSE;
  75. // Create the RTP fitler.
  76. IRtpSession *pIRtpSession;
  77. HRESULT hr = CoCreateInstance(
  78. __uuidof(MSRTPSourceFilter),
  79. NULL,
  80. CLSCTX_INPROC_SERVER | CLSCTX_NO_CODE_DOWNLOAD,
  81. __uuidof(IRtpSession),
  82. (void **) &pIRtpSession
  83. );
  84. if (FAILED(hr))
  85. {
  86. LOG((MSP_ERROR, "can't create RTP filter for local info. %x", hr));
  87. return hr;
  88. }
  89. // Get the available local SDES info from the filter.
  90. WCHAR Buffer[MAX_PARTICIPANT_TYPED_INFO_LENGTH + 1];
  91. for (int i = 0; i < NUM_SDES_ITEMS; i ++)
  92. {
  93. DWORD dwLen = MAX_PARTICIPANT_TYPED_INFO_LENGTH;
  94. hr = pIRtpSession->GetSdesInfo(
  95. RTPSDES_CNAME + i,
  96. Buffer,
  97. &dwLen,
  98. 0 // local participant
  99. );
  100. if (SUCCEEDED(hr) && dwLen > 0)
  101. {
  102. _ASSERT(dwLen <= MAX_PARTICIPANT_TYPED_INFO_LENGTH);
  103. // allocate memory to store the string.
  104. m_InfoItems[i] = (WCHAR *)malloc((dwLen) * sizeof(WCHAR));
  105. if (m_InfoItems[i] == NULL)
  106. {
  107. LOG((MSP_ERROR, "out of mem for local info"));
  108. pIRtpSession->Release();
  109. return E_OUTOFMEMORY;
  110. }
  111. lstrcpynW(m_InfoItems[i], Buffer, dwLen);
  112. }
  113. }
  114. pIRtpSession->Release();
  115. m_fLocalInfoRetrieved = TRUE;
  116. return S_OK;
  117. }
  118. HRESULT CIPConfMSPCall::Init(
  119. IN CMSPAddress * pMSPAddress,
  120. IN MSP_HANDLE htCall,
  121. IN DWORD dwReserved,
  122. IN DWORD dwMediaType
  123. )
  124. /*++
  125. Routine Description:
  126. This method is called when the call is first created. It sets
  127. up the streams based on the mediatype specified.
  128. Arguments:
  129. pMSPAddress - The pointer to the address object.
  130. htCall - The handle to the Call in TAPI's space.
  131. Used in sending events.
  132. dwReserved - Reserved.
  133. dwMediaType - The media type of this call.
  134. Return Value:
  135. HRESULT.
  136. --*/
  137. {
  138. LOG((MSP_TRACE,
  139. "IPConfMSP call %x initialize entered,"
  140. " pMSPAddress:%x, htCall %x, dwMediaType %x",
  141. this, pMSPAddress, htCall, dwMediaType
  142. ));
  143. #ifdef DEBUG_REFCOUNT
  144. if (g_lStreamObjects != 0)
  145. {
  146. LOG((MSP_ERROR, "Number of Streams alive: %d", g_lStreamObjects));
  147. // DebugBreak();
  148. }
  149. #endif
  150. // initialize the participant array so that the array is not NULL.
  151. if (!m_Participants.Grow())
  152. {
  153. LOG((MSP_ERROR, "out of mem for participant list"));
  154. return E_OUTOFMEMORY;
  155. }
  156. // Call the base class's init.
  157. HRESULT hr= CMSPCallMultiGraph::Init(
  158. pMSPAddress,
  159. htCall,
  160. dwReserved,
  161. dwMediaType
  162. );
  163. if (FAILED(hr))
  164. {
  165. LOG((MSP_ERROR, "MSPCallMultiGraph init failed:%x", hr));
  166. return hr;
  167. }
  168. // create the quality control relay for this call.
  169. m_pCallQCRelay = new CCallQualityControlRelay ();
  170. if (NULL == m_pCallQCRelay)
  171. {
  172. LOG((MSP_ERROR, "call init: failed to create call quality control relay:%x", hr));
  173. return E_OUTOFMEMORY;
  174. }
  175. // initialize qc relay, a thread will be started
  176. if (FAILED (hr = m_pCallQCRelay->Initialize (this)))
  177. {
  178. LOG ((MSP_ERROR, "call init: failed to initialize qc relay. %x", hr));
  179. return hr;
  180. }
  181. // create streams based on the media types.
  182. if (dwMediaType & TAPIMEDIATYPE_AUDIO)
  183. {
  184. ITStream * pStream;
  185. // create a stream object.
  186. hr = InternalCreateStream(TAPIMEDIATYPE_AUDIO, TD_RENDER, &pStream);
  187. if (FAILED(hr))
  188. {
  189. LOG((MSP_ERROR, "create audio render stream failed:%x", hr));
  190. return hr;
  191. }
  192. // The stream is already in our array, we don't need this pointer.
  193. pStream->Release();
  194. // create a stream object.
  195. hr = InternalCreateStream(TAPIMEDIATYPE_AUDIO, TD_CAPTURE, &pStream);
  196. if (FAILED(hr))
  197. {
  198. LOG((MSP_ERROR, "create audio capture stream failed:%x", hr));
  199. return hr;
  200. }
  201. // The stream is already in our array, we don't need this pointer.
  202. pStream->Release();
  203. }
  204. if (dwMediaType & TAPIMEDIATYPE_VIDEO)
  205. {
  206. ITStream * pStream;
  207. // create a stream object.
  208. hr = InternalCreateStream(TAPIMEDIATYPE_VIDEO, TD_RENDER, &pStream);
  209. if (FAILED(hr))
  210. {
  211. LOG((MSP_ERROR, "create video render stream failed:%x", hr));
  212. return hr;
  213. }
  214. // The stream is already in our array, we don't need this pointer.
  215. pStream->Release();
  216. // create a stream object.
  217. hr = InternalCreateStream(TAPIMEDIATYPE_VIDEO, TD_CAPTURE, &pStream);
  218. if (FAILED(hr))
  219. {
  220. LOG((MSP_ERROR, "create video capture stream failed:%x", hr));
  221. return hr;
  222. }
  223. // The stream is already in our array, we don't need this pointer.
  224. pStream->Release();
  225. }
  226. DWORD dwLoopback = 0;
  227. if (TRUE == ::GetRegValue(gszMSPLoopback, &dwLoopback) && dwLoopback != 0)
  228. {
  229. m_LoopbackMode = MULTICAST_LOOPBACK_MODE(dwLoopback);
  230. }
  231. m_fShutDown = FALSE;
  232. return S_OK;
  233. }
  234. HRESULT CIPConfMSPCall::ShutDown()
  235. /*++
  236. Routine Description:
  237. Shutdown the call.
  238. Arguments:
  239. Return Value:
  240. HRESULT.
  241. --*/
  242. {
  243. InternalShutDown();
  244. // acquire the lock on call.
  245. m_lock.Lock();
  246. for (int i = 0; i < NUM_SDES_ITEMS; i ++)
  247. {
  248. if (m_InfoItems[i])
  249. {
  250. free(m_InfoItems[i]);
  251. m_InfoItems[i] = NULL;
  252. }
  253. }
  254. m_lock.Unlock();
  255. return S_OK;
  256. }
  257. HRESULT CIPConfMSPCall::InternalShutDown()
  258. /*++
  259. Routine Description:
  260. First call the base class's shutdown and then release all the participant
  261. objects.
  262. Arguments:
  263. Return Value:
  264. HRESULT.
  265. --*/
  266. {
  267. LOG((MSP_TRACE, "ConfMSPCall.InternalShutdown, entered"));
  268. // acquire the lock on the call.
  269. m_lock.Lock();
  270. if (m_fShutDown)
  271. {
  272. LOG((MSP_TRACE, "ConfMSPCall::InterShutdown, already shutdown"));
  273. m_lock.Unlock ();
  274. return S_OK;
  275. }
  276. m_fShutDown = TRUE;
  277. if (m_pCallQCRelay)
  278. {
  279. m_pCallQCRelay->Shutdown ();
  280. }
  281. int i;
  282. // Shutdown all the streams
  283. for (i = m_Streams.GetSize() - 1; i >= 0; i --)
  284. {
  285. UnregisterWaitEvent(i);
  286. ((CMSPStream*)m_Streams[i])->ShutDown();
  287. }
  288. m_ThreadPoolWaitBlocks.RemoveAll();
  289. // release all the streams
  290. for (i = m_Streams.GetSize() - 1; i >= 0; i --)
  291. {
  292. m_Streams[i]->Release();
  293. }
  294. m_Streams.RemoveAll();
  295. if (m_pIAudioDuplexController)
  296. {
  297. m_pIAudioDuplexController->Release();
  298. m_pIAudioDuplexController = NULL;
  299. }
  300. m_lock.Unlock();
  301. // release all the participants
  302. m_ParticipantLock.Lock();
  303. for (i = 0; i < m_Participants.GetSize(); i ++)
  304. {
  305. m_Participants[i]->Release();
  306. }
  307. m_Participants.RemoveAll();
  308. m_ParticipantLock.Unlock();
  309. return S_OK;
  310. }
  311. template <class T>
  312. HRESULT CreateStreamHelper(
  313. IN T * pT,
  314. IN HANDLE hAddress,
  315. IN CIPConfMSPCall* pMSPCall,
  316. IN IMediaEvent * pGraph,
  317. IN DWORD dwMediaType,
  318. IN TERMINAL_DIRECTION Direction,
  319. OUT ITStream ** ppITStream
  320. )
  321. /*++
  322. Routine Description:
  323. Create a stream object and initialize it. This method is called internally
  324. to create a stream object of different class.
  325. Arguments:
  326. hAddress - the handle to the address object.
  327. pCall - the call object.
  328. pGraph - the filter graph for this stream.
  329. dwMediaType - the media type of the stream.
  330. Direction - the direction of the steam.
  331. ppITStream - the interface on this stream object.
  332. Return Value:
  333. HRESULT.
  334. --*/
  335. {
  336. ENTER_FUNCTION ("CreateStreamHelper");
  337. CComObject<T> * pCOMMSPStream;
  338. HRESULT hr;
  339. hr = ::CreateCComObjectInstance(&pCOMMSPStream);
  340. if (NULL == pCOMMSPStream)
  341. {
  342. LOG((MSP_ERROR, "CreateMSPStream:could not create stream:%x", hr));
  343. return hr;
  344. }
  345. // get the interface pointer.
  346. hr = pCOMMSPStream->_InternalQueryInterface(
  347. __uuidof(ITStream),
  348. (void **)ppITStream
  349. );
  350. if (FAILED(hr))
  351. {
  352. LOG((MSP_ERROR, "CreateMSPStream:QueryInterface failed: %x", hr));
  353. delete pCOMMSPStream;
  354. return hr;
  355. }
  356. // Initialize the object.
  357. hr = pCOMMSPStream->Init(
  358. hAddress,
  359. pMSPCall,
  360. pGraph,
  361. dwMediaType,
  362. Direction
  363. );
  364. if (FAILED(hr))
  365. {
  366. LOG((MSP_ERROR, "CreateMSPStream:call init failed: %x", hr));
  367. (*ppITStream)->Release();
  368. return hr;
  369. }
  370. // retrieve inner call quality control
  371. IInnerCallQualityControl * pIInnerCallQC;
  372. if (FAILED (hr = pMSPCall->_InternalQueryInterface (
  373. __uuidof (IInnerCallQualityControl),
  374. (void **)&pIInnerCallQC
  375. )))
  376. {
  377. LOG ((MSP_ERROR, "%s failed to retrieve inner call qc relay: %x", __fxName, hr));
  378. (*ppITStream)->Release ();
  379. return hr;
  380. }
  381. // retrieve inner stream quality control
  382. IInnerStreamQualityControl *pIInnerStreamQC;
  383. if (FAILED (hr = (*ppITStream)->QueryInterface (
  384. __uuidof (IInnerStreamQualityControl),
  385. (void **)&pIInnerStreamQC
  386. )))
  387. {
  388. LOG ((MSP_ERROR, "%s failed to retrieve inner stream qc relay: %x", __fxName, hr));
  389. pIInnerCallQC->Release ();
  390. (*ppITStream)->Release ();
  391. return hr;
  392. }
  393. // store inner call qc
  394. if (FAILED (hr = pIInnerStreamQC->LinkInnerCallQC (pIInnerCallQC)))
  395. {
  396. LOG ((MSP_ERROR, "%s failed to setup inner call qc on stream, %x", __fxName, hr));
  397. pIInnerCallQC->Release ();
  398. pIInnerStreamQC->Release ();
  399. (*ppITStream)->Release ();
  400. return hr;
  401. }
  402. // register inner stream qc on the call
  403. hr = pIInnerCallQC->RegisterInnerStreamQC (pIInnerStreamQC);
  404. pIInnerStreamQC->Release ();
  405. pIInnerCallQC->Release ();
  406. if (FAILED (hr))
  407. {
  408. LOG ((MSP_ERROR, "%s failed to register inner stream qc relay: %x", __fxName, hr));
  409. (*ppITStream)->Release ();
  410. return hr;
  411. }
  412. return S_OK;
  413. }
  414. HRESULT CIPConfMSPCall::CreateStreamObject(
  415. IN DWORD dwMediaType,
  416. IN TERMINAL_DIRECTION Direction,
  417. IN IMediaEvent * pGraph,
  418. IN ITStream ** ppStream
  419. )
  420. /*++
  421. Routine Description:
  422. Create a media stream object based on the mediatype and direction.
  423. Arguments:
  424. pMediaType - TAPI3 media type.
  425. Direction - direction of this stream.
  426. IMediaEvent - The filter graph used in this stream.
  427. ppStream - the return pointer of the stream interface
  428. Return Value:
  429. HRESULT.
  430. --*/
  431. {
  432. LOG((MSP_TRACE, "CreateStreamObject, entered"));
  433. HRESULT hr = S_OK;
  434. ITStream * pIMSPStream = NULL;
  435. // Create a stream object based on the media type.
  436. if (dwMediaType == TAPIMEDIATYPE_AUDIO)
  437. {
  438. if (Direction == TD_RENDER)
  439. {
  440. CStreamAudioRecv *pAudioRecv = NULL;
  441. hr = ::CreateStreamHelper(
  442. pAudioRecv,
  443. m_pMSPAddress,
  444. this,
  445. pGraph,
  446. TAPIMEDIATYPE_AUDIO,
  447. TD_RENDER,
  448. &pIMSPStream
  449. );
  450. LOG((MSP_TRACE, "create audio receive:%x, hr:%x", pIMSPStream,hr));
  451. if (FAILED(hr))
  452. {
  453. LOG((MSP_ERROR, "create stream failed. %x", hr));
  454. return hr;
  455. }
  456. if (FAILED(hr = InitFullDuplexControler()))
  457. {
  458. LOG((MSP_ERROR, "Create full duplex controller failed. %x", hr));
  459. }
  460. else
  461. {
  462. ((CStreamAudioRecv *)pIMSPStream)->
  463. SetFullDuplexController(m_pIAudioDuplexController);
  464. }
  465. }
  466. else if (Direction == TD_CAPTURE)
  467. {
  468. CStreamAudioSend *pAudioSend = NULL;
  469. hr = ::CreateStreamHelper(
  470. pAudioSend,
  471. m_pMSPAddress,
  472. this,
  473. pGraph,
  474. TAPIMEDIATYPE_AUDIO,
  475. TD_CAPTURE,
  476. &pIMSPStream
  477. );
  478. LOG((MSP_TRACE, "create audio send:%x, hr:%x", pIMSPStream,hr));
  479. if (FAILED(hr))
  480. {
  481. LOG((MSP_ERROR, "create stream failed. %x", hr));
  482. return hr;
  483. }
  484. if (FAILED(hr = InitFullDuplexControler()))
  485. {
  486. LOG((MSP_ERROR, "Create full duplex controller failed. %x", hr));
  487. }
  488. else
  489. {
  490. ((CStreamAudioSend *)pIMSPStream)->
  491. SetFullDuplexController(m_pIAudioDuplexController);
  492. }
  493. }
  494. else
  495. {
  496. return TAPI_E_INVALIDDIRECTION;
  497. }
  498. }
  499. else if (dwMediaType == TAPIMEDIATYPE_VIDEO)
  500. {
  501. if (Direction == TD_RENDER)
  502. {
  503. CStreamVideoRecv *pVideoRecv = NULL;
  504. hr = ::CreateStreamHelper(
  505. pVideoRecv,
  506. m_pMSPAddress,
  507. this,
  508. pGraph,
  509. TAPIMEDIATYPE_VIDEO,
  510. TD_RENDER,
  511. &pIMSPStream
  512. );
  513. LOG((MSP_TRACE, "create video Recv:%x, hr:%x", pIMSPStream,hr));
  514. if (FAILED(hr))
  515. {
  516. LOG((MSP_ERROR, "create stream failed. %x", hr));
  517. return hr;
  518. }
  519. }
  520. else if (Direction == TD_CAPTURE)
  521. {
  522. CStreamVideoSend *pVideoSend = NULL;
  523. hr = ::CreateStreamHelper(
  524. pVideoSend,
  525. m_pMSPAddress,
  526. this,
  527. pGraph,
  528. TAPIMEDIATYPE_VIDEO,
  529. TD_CAPTURE,
  530. &pIMSPStream
  531. );
  532. LOG((MSP_TRACE, "create video send:%x, hr:%x", pIMSPStream,hr));
  533. if (FAILED(hr))
  534. {
  535. LOG((MSP_ERROR, "create stream failed. %x", hr));
  536. return hr;
  537. }
  538. }
  539. else
  540. {
  541. return TAPI_E_INVALIDDIRECTION;
  542. }
  543. }
  544. else
  545. {
  546. return TAPI_E_INVALIDMEDIATYPE;
  547. }
  548. *ppStream = pIMSPStream;
  549. return S_OK;
  550. }
  551. DWORD CIPConfMSPCall::FindInterfaceByName(IN WCHAR *pMachineName)
  552. /*++
  553. Routine Description:
  554. Given the machine name of the originator, find out which local interface
  555. can be used to reach that machine.
  556. Arguments:
  557. pMachineName - The machine name of the originator.
  558. Return Value:
  559. INADDR_NONE - nothing can be found.
  560. valid IP - succeeded.
  561. --*/
  562. {
  563. char buffer[MAXIPADDRLEN + 1];
  564. if (WideCharToMultiByte(
  565. GetACP(),
  566. 0,
  567. pMachineName,
  568. -1,
  569. buffer,
  570. MAXIPADDRLEN,
  571. NULL,
  572. NULL
  573. ) == 0)
  574. {
  575. LOG((MSP_ERROR, "can't convert originator's address:%ws", pMachineName));
  576. return INADDR_NONE;
  577. }
  578. DWORD dwAddr;
  579. if ((dwAddr = inet_addr(buffer)) != INADDR_NONE)
  580. {
  581. dwAddr = ntohl(dwAddr);
  582. LOG((MSP_INFO, "originator's IP:%x", dwAddr));
  583. return ((CIPConfMSP *)m_pMSPAddress)->FindLocalInterface(dwAddr);
  584. }
  585. struct hostent * pHost;
  586. // attempt to lookup hostname
  587. pHost = gethostbyname(buffer);
  588. // validate pointer
  589. if (pHost == NULL)
  590. {
  591. LOG((MSP_WARN, "can't resolve address:%s", buffer));
  592. return INADDR_NONE;
  593. }
  594. // for each of the addresses returned, find the local interface.
  595. for (DWORD i = 0; TRUE; i ++)
  596. {
  597. if (pHost->h_addr_list[i] == NULL)
  598. {
  599. break;
  600. }
  601. // retrieve host address from structure
  602. dwAddr = ntohl(*(unsigned long *)pHost->h_addr_list[i]);
  603. LOG((MSP_INFO, "originator's IP:%x", dwAddr));
  604. DWORD dwInterface =
  605. ((CIPConfMSP *)m_pMSPAddress)->FindLocalInterface(dwAddr);
  606. if (dwInterface != INADDR_NONE)
  607. {
  608. return dwInterface;
  609. }
  610. }
  611. return INADDR_NONE;
  612. }
  613. HRESULT CIPConfMSPCall::CheckOrigin(
  614. IN ITSdp * pITSdp,
  615. OUT BOOL * pFlag,
  616. OUT DWORD * pdwIP
  617. )
  618. /*++
  619. Routine Description:
  620. Check to see if the current user is the originator of the conference.
  621. If he is, he can send to a receive only conference.
  622. Arguments:
  623. pITSdp - a pointer to the ITSdp interface.
  624. pFlag - The result.
  625. pdwIP - The local IP interface that should be used to reach the originator.
  626. Return Value:
  627. HRESULT.
  628. --*/
  629. {
  630. const DWORD MAXUSERNAMELEN = 127;
  631. DWORD dwUserNameLen = MAXUSERNAMELEN;
  632. WCHAR szUserName[MAXUSERNAMELEN+1];
  633. // determine the name of the current user
  634. if (!GetUserNameW(szUserName, &dwUserNameLen))
  635. {
  636. LOG((MSP_ERROR, "cant' get user name. %x", GetLastError()));
  637. return E_UNEXPECTED;
  638. }
  639. LOG((MSP_INFO, "current user: %ws", szUserName));
  640. // find out if the current user is the originator of the conference.
  641. BSTR Originator = NULL;
  642. HRESULT hr = pITSdp->get_Originator(&Originator);
  643. if (FAILED(hr))
  644. {
  645. LOG((MSP_ERROR, "cant' get originator. %x", hr));
  646. return hr;
  647. }
  648. LOG((MSP_INFO, "originator: %ws", Originator));
  649. *pFlag = (_wcsnicmp(szUserName, Originator, lstrlenW(szUserName)) == 0);
  650. SysFreeString(Originator);
  651. // Get the machine IP address of the originator.
  652. BSTR MachineAddress = NULL;
  653. hr = pITSdp->get_MachineAddress(&MachineAddress);
  654. if (FAILED(hr))
  655. {
  656. LOG((MSP_ERROR, "cant' get MachineAddress. %x", hr));
  657. return hr;
  658. }
  659. LOG((MSP_INFO, "MachineAddress: %ws", MachineAddress));
  660. DWORD dwIP = FindInterfaceByName(MachineAddress);
  661. SysFreeString(MachineAddress);
  662. *pdwIP = dwIP;
  663. LOG((MSP_INFO, "Interface to use:%x", *pdwIP));
  664. return S_OK;
  665. }
  666. HRESULT GetAddress(
  667. IN IUnknown * pIUnknown,
  668. OUT DWORD * pdwAddress,
  669. OUT DWORD * pdwTTL,
  670. OUT BSTR * ppKey,
  671. OUT LONG * plBandwidth,
  672. OUT LONG * plConfBandwidth = NULL
  673. )
  674. /*++
  675. Routine Description:
  676. Get the IP address and TTL value from a connection. It is a "c=" line
  677. in the SDP blob.
  678. Arguments:
  679. pIUnknow - an object that might contain connection information.
  680. pdwAddress - the mem address to store the IP address.
  681. pdwTTL - the mem address to store the TTL value.
  682. plBandwidth - maximum bandwidth
  683. Return Value:
  684. HRESULT.
  685. --*/
  686. {
  687. // query for the ITConnection i/f
  688. CComPtr<ITConnection> pITConnection;
  689. HRESULT hr = pIUnknown->QueryInterface(__uuidof(ITConnection), (void **)&pITConnection);
  690. if (FAILED(hr))
  691. {
  692. LOG((MSP_ERROR, "get connection interface. %x", hr));
  693. return hr;
  694. }
  695. // clear
  696. if (plConfBandwidth != NULL) *plConfBandwidth = QCDEFAULT_QUALITY_UNSET;
  697. // get bandwidth
  698. const WCHAR * const AS = L"AS";
  699. const WCHAR * const CT = L"CT";
  700. BSTR pModifier = NULL;
  701. DOUBLE bandwidth;
  702. if (FAILED (hr = pITConnection->get_BandwidthModifier (&pModifier)))
  703. {
  704. *plBandwidth = QCDEFAULT_QUALITY_UNSET;
  705. // bandwidth modifier may not be presented
  706. // LOG ((MSP_TRACE, "get bandwidth modifiler. %x", hr));
  707. }
  708. else if (_wcsnicmp (AS, pModifier, lstrlenW (AS)) != 0)
  709. {
  710. // if not application specific
  711. *plBandwidth = QCDEFAULT_QUALITY_UNSET;
  712. // check conference-wide bandwidth limit
  713. if (_wcsnicmp (CT, pModifier, lstrlenW (CT)) == 0)
  714. {
  715. if (plConfBandwidth)
  716. {
  717. if (FAILED (hr = pITConnection->get_Bandwidth (&bandwidth)))
  718. {
  719. *plConfBandwidth = QCDEFAULT_QUALITY_UNSET;
  720. LOG ((MSP_ERROR, "get conf bandwidth. %x", hr));
  721. }
  722. else
  723. *plConfBandwidth = (LONG)(bandwidth * 1000);
  724. }
  725. }
  726. }
  727. else if (FAILED (hr = pITConnection->get_Bandwidth (&bandwidth)))
  728. {
  729. *plBandwidth = QCDEFAULT_QUALITY_UNSET;
  730. LOG ((MSP_ERROR, "get bandwidth. %x", hr));
  731. }
  732. else
  733. *plBandwidth = (LONG)(bandwidth * 1000);
  734. if (pModifier)
  735. {
  736. SysFreeString (pModifier);
  737. pModifier = NULL;
  738. }
  739. // get the start address,
  740. BSTR StartAddress = NULL;
  741. hr = pITConnection->get_StartAddress(&StartAddress);
  742. if (FAILED(hr))
  743. {
  744. LOG((MSP_WARN, "get start address. %x", hr));
  745. return hr;
  746. }
  747. // Get the IP address from the string.
  748. const DWORD MAXIPADDRLEN = 20;
  749. char Buffer[MAXIPADDRLEN+1];
  750. // first convert the string to ascii.
  751. Buffer[0] = '\0';
  752. if (!WideCharToMultiByte(
  753. CP_ACP,
  754. 0,
  755. StartAddress,
  756. -1,
  757. Buffer,
  758. MAXIPADDRLEN,
  759. NULL,
  760. NULL
  761. ))
  762. {
  763. LOG((MSP_ERROR, "converting address. %ws", StartAddress));
  764. SysFreeString(StartAddress);
  765. return E_UNEXPECTED;
  766. }
  767. SysFreeString(StartAddress);
  768. // convert the string to DWORD IP address.
  769. DWORD dwIP = ntohl(inet_addr(Buffer));
  770. if (dwIP == INADDR_NONE)
  771. {
  772. LOG((MSP_ERROR, "invalid IP address. %s", Buffer));
  773. return E_UNEXPECTED;
  774. }
  775. // get the TTL value.
  776. BYTE Ttl;
  777. hr = pITConnection->get_Ttl(&Ttl);
  778. if (FAILED(hr))
  779. {
  780. LOG((MSP_ERROR, "can't get TTL."));
  781. return hr;
  782. }
  783. // get the Encryption key.
  784. const WCHAR * const CLEAR = L"clear";
  785. VARIANT_BOOL fKeyValid;
  786. BSTR bstrKeyType = NULL;
  787. if (*ppKey)
  788. SysFreeString (*ppKey);
  789. *ppKey = NULL;
  790. if (FAILED (hr = pITConnection->GetEncryptionKey (&bstrKeyType, &fKeyValid, ppKey)))
  791. {
  792. LOG((MSP_WARN, "can't get EncryptionKey. %x", hr));
  793. }
  794. else if (_wcsnicmp (CLEAR, bstrKeyType, lstrlenW (CLEAR)) != 0)
  795. {
  796. if (*ppKey)
  797. {
  798. SysFreeString (*ppKey);
  799. *ppKey = NULL;
  800. }
  801. }
  802. if (bstrKeyType)
  803. SysFreeString (bstrKeyType);
  804. *pdwAddress = dwIP;
  805. *pdwTTL = Ttl;
  806. return S_OK;
  807. }
  808. HRESULT CheckAttributes(
  809. IN IUnknown * pIUnknown,
  810. OUT BOOL * pbSendOnly,
  811. OUT BOOL * pbRecvOnly,
  812. OUT DWORD * pdwMSPerPacket,
  813. OUT BOOL * pbCIF
  814. )
  815. /*++
  816. Routine Description:
  817. Check the direction of the media, find out if it is send only or
  818. receive only.
  819. Arguments:
  820. pIUnknow - an object that might have a attribute list.
  821. pbSendOnly - the mem address to store the returned BOOL.
  822. pbRecvOnly - the mem address to store the returned BOOL.
  823. pbCIF - if CIF is used for video.
  824. Return Value:
  825. HRESULT.
  826. --*/
  827. {
  828. // query for the ITAttributeList i/f
  829. CComPtr<ITAttributeList> pIAttList;
  830. HRESULT hr = pIUnknown->QueryInterface(__uuidof(ITAttributeList), (void **)&pIAttList);
  831. if (FAILED(hr))
  832. {
  833. LOG((MSP_ERROR, "get attribute interface. %x", hr));
  834. return hr;
  835. }
  836. // get the number of attributes
  837. long lCount;
  838. hr = pIAttList->get_Count(&lCount);
  839. if (FAILED(hr))
  840. {
  841. LOG((MSP_ERROR, "get attribute count. %x", hr));
  842. return hr;
  843. }
  844. *pbRecvOnly = FALSE;
  845. *pbSendOnly = FALSE;
  846. *pdwMSPerPacket = 0;
  847. *pbCIF = FALSE;
  848. const WCHAR * const SENDONLY = L"sendonly";
  849. const WCHAR * const RECVONLY = L"recvonly";
  850. const WCHAR * const FORMAT = L"fmtp";
  851. const WCHAR * const PTIME = L"ptime:";
  852. const WCHAR * const CIF = L" CIF=";
  853. for (long i = 1; i <= lCount; i ++)
  854. {
  855. // get the attributes and check if sendonly of recvonly is specified.
  856. BSTR Attribute = NULL;
  857. hr = pIAttList->get_Item(i, &Attribute);
  858. if (FAILED(hr))
  859. {
  860. LOG((MSP_ERROR, "get attribute item. %x", hr));
  861. return hr;
  862. }
  863. if (_wcsnicmp(SENDONLY, Attribute, lstrlen(SENDONLY)) == 0)
  864. {
  865. *pbSendOnly = TRUE;
  866. }
  867. else if (_wcsnicmp(RECVONLY, Attribute, lstrlen(RECVONLY)) == 0)
  868. {
  869. *pbRecvOnly = TRUE;
  870. }
  871. else if (_wcsnicmp(PTIME, Attribute, lstrlen(PTIME)) == 0)
  872. {
  873. // read the number of milliseconds per packet.
  874. *pdwMSPerPacket = (DWORD)_wtol(Attribute + lstrlen(PTIME));
  875. // RFC 1890 only requires an app to support 200ms packets.
  876. if (*pdwMSPerPacket > 200)
  877. {
  878. // invalid tag, we just use our default.
  879. *pdwMSPerPacket = 0;
  880. }
  881. }
  882. else if (_wcsnicmp(FORMAT, Attribute, lstrlen(FORMAT)) == 0)
  883. {
  884. if (wcsstr(Attribute, CIF))
  885. {
  886. *pbCIF = TRUE;
  887. }
  888. }
  889. SysFreeString(Attribute);
  890. }
  891. return S_OK;
  892. }
  893. HRESULT CIPConfMSPCall::ProcessMediaItem(
  894. IN ITMedia * pITMedia,
  895. IN DWORD dwMediaTypeMask,
  896. OUT DWORD * pdwMediaType,
  897. OUT WORD * pwPort,
  898. OUT DWORD * pdwPayloadTypes,
  899. IN OUT DWORD * pdwNumPayLoadType
  900. )
  901. /*++
  902. Routine Description:
  903. Process a "m=" line, find out the media type, port, and payload type.
  904. Arguments:
  905. dwMediaTypeMask - the media type of this call.
  906. pdwMediaType - return the media type of this media item.
  907. pwPort - return the port number used for this media.
  908. pdwPayloadType - an array to store the RTP payload types.
  909. pdwNumPayLoadType - The size of the above array. When return, it is the
  910. number of payload types read.
  911. Return Value:
  912. HRESULT.
  913. S_FALSE - everything is all right but the media type is not needed.
  914. --*/
  915. {
  916. // get the name of the media.
  917. BSTR MediaName = NULL;
  918. HRESULT hr = pITMedia->get_MediaName(&MediaName);
  919. if (FAILED(hr))
  920. {
  921. LOG((MSP_ERROR, "get media name. %x", hr));
  922. return hr;
  923. }
  924. LOG((MSP_INFO, "media name: %ws", MediaName));
  925. // check if the media is audio or video.
  926. const WCHAR * const AUDIO = L"audio";
  927. const WCHAR * const VIDEO = L"video";
  928. const DWORD NAMELEN = 5;
  929. DWORD dwMediaType = 0;
  930. if (_wcsnicmp(AUDIO, MediaName, NAMELEN) == 0)
  931. {
  932. dwMediaType = TAPIMEDIATYPE_AUDIO;
  933. }
  934. else if (_wcsnicmp(VIDEO, MediaName, NAMELEN) == 0)
  935. {
  936. dwMediaType = TAPIMEDIATYPE_VIDEO;
  937. }
  938. SysFreeString(MediaName);
  939. // check if the call wants this media type.
  940. if ((dwMediaType & dwMediaTypeMask) == 0)
  941. {
  942. // We don't need this media type in this call.
  943. LOG((MSP_INFO, "media skipped."));
  944. return S_FALSE;
  945. }
  946. // get start port
  947. long lStartPort;
  948. hr = pITMedia->get_StartPort(&lStartPort);
  949. if (FAILED(hr))
  950. {
  951. LOG((MSP_ERROR, "get start port. %x", hr));
  952. return hr;
  953. }
  954. // get the transport Protocol
  955. BSTR TransportProtocol = NULL;
  956. hr = pITMedia->get_TransportProtocol(&TransportProtocol);
  957. if (FAILED(hr))
  958. {
  959. LOG((MSP_ERROR, "get transport Protocol. %x", hr));
  960. return hr;
  961. }
  962. // varify that the protocol is RTP.
  963. const WCHAR * const RTP = L"RTP";
  964. const DWORD PROTOCOLLEN = 3;
  965. if (_wcsnicmp(RTP, TransportProtocol, PROTOCOLLEN) != 0)
  966. {
  967. LOG((MSP_ERROR, "wrong transport Protocol:%ws", TransportProtocol));
  968. SysFreeString(TransportProtocol);
  969. return S_FALSE;
  970. }
  971. SysFreeString(TransportProtocol);
  972. // get the format code list
  973. VARIANT Variant;
  974. VariantInit(&Variant);
  975. hr = pITMedia->get_FormatCodes(&Variant);
  976. if (FAILED(hr))
  977. {
  978. LOG((MSP_ERROR, "get format codes. %x", hr));
  979. return hr;
  980. }
  981. // Verify that the SafeArray is in proper shape.
  982. if(SafeArrayGetDim(V_ARRAY(&Variant)) != 1)
  983. {
  984. LOG((MSP_ERROR, "wrong dimension for the format code. %x", hr));
  985. VariantClear(&Variant);
  986. return E_UNEXPECTED;
  987. }
  988. long lLowerBound;
  989. long lUpperBound;
  990. if (FAILED(hr = SafeArrayGetLBound(V_ARRAY(&Variant), 1, &lLowerBound))
  991. || FAILED(hr = SafeArrayGetUBound(V_ARRAY(&Variant), 1, &lUpperBound)))
  992. {
  993. LOG((MSP_ERROR, "Can't get the array bounds. %x", hr));
  994. VariantClear(&Variant);
  995. return E_UNEXPECTED;
  996. }
  997. DWORD dwNumFormats = 0;
  998. for (long l = lLowerBound; l <= lUpperBound && dwNumFormats < *pdwNumPayLoadType; l ++)
  999. {
  1000. BSTR Format = NULL;
  1001. hr = SafeArrayGetElement(V_ARRAY(&Variant), &l, &Format);
  1002. if (FAILED(hr))
  1003. {
  1004. LOG((MSP_ERROR, "get format code. %x", hr));
  1005. continue;
  1006. }
  1007. LOG((MSP_INFO, "format code: %ws", Format));
  1008. pdwPayloadTypes[dwNumFormats] = (DWORD)_wtoi(Format);
  1009. // ignore unsupported codec, including G723
  1010. if (IsPayloadSupported(pdwPayloadTypes[dwNumFormats]))
  1011. {
  1012. dwNumFormats ++;
  1013. }
  1014. SysFreeString(Format);
  1015. }
  1016. // clear the variant because we don't need it any more
  1017. VariantClear(&Variant);
  1018. *pdwMediaType = dwMediaType;
  1019. *pwPort = (WORD)lStartPort;
  1020. *pdwNumPayLoadType = dwNumFormats;
  1021. return S_OK;
  1022. }
  1023. HRESULT CIPConfMSPCall::ConfigStreamsBasedOnSDP(
  1024. IN ITSdp * pITSdp,
  1025. IN DWORD dwAudioQOSLevel,
  1026. IN DWORD dwVideoQOSLevel
  1027. )
  1028. /*++
  1029. Routine Description:
  1030. Configure the streams based on the information in the SDP blob.
  1031. Arguments:
  1032. pITSdp - the SDP object. It contains parsed information.
  1033. Return Value:
  1034. HRESULT.
  1035. --*/
  1036. {
  1037. // find out if the current user is the originator of the conference.
  1038. BOOL fIsOriginator;
  1039. DWORD dwLocalInterface = INADDR_NONE;
  1040. HRESULT hr = CheckOrigin(pITSdp, &fIsOriginator, &dwLocalInterface);
  1041. if (FAILED(hr))
  1042. {
  1043. LOG((MSP_ERROR, "check origin. %x", hr));
  1044. return hr;
  1045. }
  1046. LOG((MSP_INFO, "Local interface: %x", dwLocalInterface));
  1047. // get the start IP address and TTL value from the connection.
  1048. DWORD dwIPGlobal, dwTTLGlobal;
  1049. BSTR bstrKeyGlobal = NULL;
  1050. LONG lbandwidth, lConfBandwidth;
  1051. hr = GetAddress(pITSdp, &dwIPGlobal, &dwTTLGlobal, &bstrKeyGlobal, &lbandwidth, &lConfBandwidth);
  1052. if (FAILED(hr))
  1053. {
  1054. LOG((MSP_ERROR, "get global address. %x", hr));
  1055. return hr;
  1056. }
  1057. CLock lock(m_lock);
  1058. // store conference bandwidth
  1059. if (FAILED (m_pCallQCRelay->SetConfBitrate (lConfBandwidth)))
  1060. {
  1061. LOG ((MSP_ERROR, "bandwidth is out of range %d", lConfBandwidth));
  1062. }
  1063. // find out if this conference is sendonly or recvonly.
  1064. BOOL fSendOnlyGlobal = FALSE, fRecvOnlyGlobal = FALSE, fCIF = FALSE;
  1065. DWORD dwMSPerPacket;
  1066. hr = CheckAttributes(
  1067. pITSdp, &fSendOnlyGlobal, &fRecvOnlyGlobal, &dwMSPerPacket, &fCIF);
  1068. if (FAILED(hr))
  1069. {
  1070. LOG((MSP_ERROR, "check global attributes. %x", hr));
  1071. return hr;
  1072. }
  1073. // get the media information
  1074. CComPtr<ITMediaCollection> pICollection;
  1075. hr = pITSdp->get_MediaCollection(&pICollection);
  1076. if (FAILED(hr))
  1077. {
  1078. LOG((MSP_ERROR, "get the media collection. %x", hr));
  1079. return hr;
  1080. }
  1081. // find out how many media sessions are in the blobl.
  1082. long lCount;
  1083. hr = pICollection->get_Count(&lCount);
  1084. if (FAILED(hr))
  1085. {
  1086. LOG((MSP_ERROR, "get number of media items. %x", hr));
  1087. return hr;
  1088. }
  1089. if (lCount > 0)
  1090. {
  1091. // change the call into connected state since the SDP is OK.
  1092. // We are going to set up each every streams next.
  1093. SendTSPMessage(CALL_CONNECTED, 0);
  1094. }
  1095. DWORD dwNumSucceeded = 0;
  1096. // for each media session, get info configure a stream.
  1097. for(long i=1; i <= lCount; i++)
  1098. {
  1099. // get the media item first.
  1100. ITMedia *pITMedia;
  1101. hr = pICollection->get_Item(i, &pITMedia);
  1102. if (FAILED(hr))
  1103. {
  1104. LOG((MSP_ERROR, "get media item. %x", hr));
  1105. continue;
  1106. }
  1107. DWORD dwMediaType;
  1108. STREAMSETTINGS Setting;
  1109. ZeroMemory(&Setting, sizeof(STREAMSETTINGS));
  1110. // find out the information about the media. Here we pass in the media
  1111. // type of call so that we won't wasting time reading the attributes
  1112. // for a media type we don't need.
  1113. DWORD dwNumPayloadTypes = sizeof(Setting.PayloadTypes)
  1114. / sizeof(Setting.PayloadTypes[0]);
  1115. hr = ProcessMediaItem(
  1116. pITMedia,
  1117. m_dwMediaType,
  1118. &dwMediaType,
  1119. &Setting.wRTPPortRemote,
  1120. Setting.PayloadTypes,
  1121. &dwNumPayloadTypes
  1122. );
  1123. if (FAILED(hr))
  1124. {
  1125. LOG((MSP_ERROR, "process media. %x", hr));
  1126. continue;
  1127. }
  1128. Setting.dwNumPayloadTypes = dwNumPayloadTypes;
  1129. // if the return value is S_FALSE from the previous call, this media
  1130. // type is not needed for the call.
  1131. if (hr != S_OK || dwNumPayloadTypes == 0)
  1132. {
  1133. // the media is not needed.
  1134. continue;
  1135. }
  1136. if (dwMediaType == TAPIMEDIATYPE_AUDIO)
  1137. {
  1138. Setting.dwQOSLevel = dwAudioQOSLevel;
  1139. Setting.phRTPSession = &m_hAudioRTPSession;
  1140. }
  1141. else
  1142. {
  1143. Setting.dwQOSLevel = dwVideoQOSLevel;
  1144. Setting.phRTPSession = &m_hVideoRTPSession;
  1145. }
  1146. // Get the local connect information.
  1147. DWORD dwIP, dwTTL;
  1148. BSTR bstrKey = NULL;
  1149. hr = GetAddress(pITMedia, &dwIP, &dwTTL, &bstrKey, &lbandwidth);
  1150. if (FAILED(hr))
  1151. {
  1152. LOG((MSP_WARN, "no local address, use global one", hr));
  1153. Setting.dwIPRemote = dwIPGlobal;
  1154. Setting.dwTTL = dwTTLGlobal;
  1155. Setting.lBandwidth = QCDEFAULT_QUALITY_UNSET;
  1156. }
  1157. else
  1158. {
  1159. Setting.dwIPRemote = dwIP;
  1160. Setting.dwTTL = dwTTL;
  1161. Setting.lBandwidth = lbandwidth;
  1162. }
  1163. // find out if this media is sendonly or recvonly.
  1164. BOOL fSendOnly = FALSE, fRecvOnly = FALSE, fCIF = FALSE;
  1165. hr = CheckAttributes(
  1166. pITMedia, &fSendOnly, &fRecvOnly, &dwMSPerPacket, &fCIF);
  1167. if (FAILED(hr))
  1168. {
  1169. LOG((MSP_ERROR, "check local attributes. %x", hr));
  1170. }
  1171. fSendOnly = fSendOnly || fSendOnlyGlobal;
  1172. fRecvOnly = (fRecvOnly || fRecvOnlyGlobal) && (!fIsOriginator);
  1173. Setting.dwMSPerPacket = dwMSPerPacket;
  1174. Setting.fCIF = fCIF;
  1175. // The media item is not needed after this point.
  1176. pITMedia->Release();
  1177. // Go through the existing streams and find out if any stream
  1178. // can be configured.
  1179. // Note: we are not creating any new streams now. We might want to
  1180. // do it in the future if we want to support two sessions of the
  1181. // same media type.
  1182. m_fCallStarted = TRUE;
  1183. for (long j = 0; j < m_Streams.GetSize(); j ++)
  1184. {
  1185. CIPConfMSPStream* pStream = (CIPConfMSPStream*)m_Streams[j];
  1186. if ((pStream->MediaType() != dwMediaType)
  1187. || pStream->IsConfigured()
  1188. || (fSendOnly && pStream->Direction() == TD_RENDER)
  1189. || (fRecvOnly && pStream->Direction() == TD_CAPTURE)
  1190. )
  1191. {
  1192. // this stream should not be configured.
  1193. continue;
  1194. }
  1195. // set the local interface that the call should bind to.
  1196. Setting.dwIPLocal = m_dwIPInterface;
  1197. if ((m_dwIPInterface == INADDR_ANY)
  1198. && (dwLocalInterface != INADDR_NONE))
  1199. {
  1200. Setting.dwIPLocal = dwLocalInterface;
  1201. }
  1202. // set the loopback mode of the stream.
  1203. Setting.LoopbackMode = m_LoopbackMode;
  1204. // set the qos application IDS.
  1205. Setting.pApplicationID = m_pApplicationID;
  1206. Setting.pApplicationGUID = m_pApplicationGUID;
  1207. Setting.pSubIDs = m_pSubIDs;
  1208. // configure the stream, it will not be started.
  1209. hr = pStream->Configure(Setting, (bstrKey) ? bstrKey : bstrKeyGlobal);
  1210. if (FAILED(hr))
  1211. {
  1212. LOG((MSP_ERROR, "configure stream failed. %x", hr));
  1213. }
  1214. }
  1215. SysFreeString(bstrKey);
  1216. }
  1217. SysFreeString(bstrKeyGlobal);
  1218. // after configuring the streams, start them.
  1219. for (int j = 0; j < m_Streams.GetSize(); j ++)
  1220. {
  1221. CIPConfMSPStream* pStream = (CIPConfMSPStream*)m_Streams[j];
  1222. // start the stream.
  1223. hr = pStream->FinishConfigure();
  1224. if (SUCCEEDED(hr))
  1225. {
  1226. dwNumSucceeded ++;
  1227. }
  1228. }
  1229. if (dwNumSucceeded == 0)
  1230. {
  1231. LOG((MSP_ERROR, "No media succeeded."));
  1232. return E_FAIL;
  1233. }
  1234. return S_OK;
  1235. }
  1236. HRESULT CIPConfMSPCall::ParseSDP(
  1237. IN WCHAR * pSDP,
  1238. IN DWORD dwAudioQOSLevel,
  1239. IN DWORD dwVideoQOSLevel
  1240. )
  1241. /*++
  1242. Routine Description:
  1243. Parse the SDP string. The function uses the SdpConferenceBlob object
  1244. to parse the string.
  1245. Arguments:
  1246. pSDP - the SDP string.
  1247. dwAudioQOSLevel - the QOS requirement for audio.
  1248. dwVideoQOSLevel - the QOS requirement for video.
  1249. Return Value:
  1250. HRESULT.
  1251. --*/
  1252. {
  1253. // co-create an sdp conference blob component
  1254. // query for the ITConferenceBlob interface
  1255. CComPtr<ITConferenceBlob> pIConfBlob;
  1256. HRESULT hr = ::CoCreateInstance(
  1257. CLSID_SdpConferenceBlob,
  1258. NULL,
  1259. CLSCTX_INPROC_SERVER | CLSCTX_NO_CODE_DOWNLOAD,
  1260. __uuidof(ITConferenceBlob),
  1261. (void **)&pIConfBlob
  1262. );
  1263. if (FAILED(hr))
  1264. {
  1265. LOG((MSP_ERROR, "creating a SDPBlob object. %x", hr));
  1266. return hr;
  1267. }
  1268. // conver the sdp into a BSTR to use the interface.
  1269. BSTR bstrSDP = SysAllocString(pSDP);
  1270. if (bstrSDP == NULL)
  1271. {
  1272. LOG((MSP_ERROR, "out of mem converting SDP to a BSTR."));
  1273. return E_OUTOFMEMORY;
  1274. }
  1275. // Parse the SDP string.
  1276. hr = pIConfBlob->Init(NULL, BCS_ASCII, bstrSDP);
  1277. // the string is not needed any more.
  1278. SysFreeString(bstrSDP);
  1279. if (FAILED(hr))
  1280. {
  1281. LOG((MSP_ERROR, "parse the SDPBlob object. %x", hr));
  1282. return hr;
  1283. }
  1284. // Get the ITSdp interface.
  1285. CComPtr<ITSdp> pITSdp;
  1286. hr = pIConfBlob->QueryInterface(__uuidof(ITSdp), (void **)&pITSdp);
  1287. if (FAILED(hr))
  1288. {
  1289. LOG((MSP_ERROR, "can't get the ITSdp interface. %x", hr));
  1290. return hr;
  1291. }
  1292. // check main sdp validity
  1293. VARIANT_BOOL IsValid;
  1294. hr = pITSdp->get_IsValid(&IsValid);
  1295. if (FAILED(hr))
  1296. {
  1297. LOG((MSP_ERROR, "can't get the valid flag on the SDP %x", hr));
  1298. return hr;
  1299. }
  1300. if (!IsValid)
  1301. {
  1302. LOG((MSP_ERROR, "the SDP is not valid %x", hr));
  1303. return E_FAIL;
  1304. }
  1305. return ConfigStreamsBasedOnSDP(
  1306. pITSdp,
  1307. dwAudioQOSLevel,
  1308. dwVideoQOSLevel
  1309. );
  1310. }
  1311. HRESULT CIPConfMSPCall::SendTSPMessage(
  1312. IN TSP_MSP_COMMAND command,
  1313. IN DWORD dwParam1,
  1314. IN DWORD dwParam2
  1315. ) const
  1316. /*++
  1317. Routine Description:
  1318. Send the TSP a message from the MSP.
  1319. Arguments:
  1320. command - the command to be sent.
  1321. dwParam1 - the first DWORD used in the command.
  1322. dwParam2 - the second DWORD used in the command.
  1323. Return Value:
  1324. HRESULT.
  1325. --*/
  1326. {
  1327. LOG((MSP_TRACE, "SendTSPMessage, command %d, dwParam1 %d, dwParam2",
  1328. command, dwParam1, dwParam2));
  1329. // first allocate the memory.
  1330. MSPEVENTITEM* pEventItem = AllocateEventItem(sizeof(MSG_TSPMSPDATA));
  1331. if (pEventItem == NULL)
  1332. {
  1333. LOG((MSP_ERROR, "No memory for the TSPMSP data"));
  1334. return E_OUTOFMEMORY;
  1335. }
  1336. // Fill in the necessary fields for the event structure.
  1337. pEventItem->MSPEventInfo.dwSize =
  1338. sizeof(MSP_EVENT_INFO) + sizeof(MSG_TSPMSPDATA);
  1339. pEventItem->MSPEventInfo.Event = ME_TSP_DATA;
  1340. pEventItem->MSPEventInfo.hCall = m_htCall;
  1341. // Fill in the data for the TSP.
  1342. pEventItem->MSPEventInfo.MSP_TSP_DATA.dwBufferSize = sizeof(MSG_TSPMSPDATA);
  1343. MSG_TSPMSPDATA *pData = (MSG_TSPMSPDATA *)
  1344. pEventItem->MSPEventInfo.MSP_TSP_DATA.pBuffer;
  1345. pData->command = command;
  1346. switch (command)
  1347. {
  1348. case CALL_DISCONNECTED:
  1349. pData->CallDisconnected.dwReason = dwParam1;
  1350. break;
  1351. case CALL_QOS_EVENT:
  1352. pData->QosEvent.dwEvent = dwParam1;
  1353. pData->QosEvent.dwMediaMode = dwParam2;
  1354. break;
  1355. case CALL_CONNECTED:
  1356. break;
  1357. default:
  1358. LOG((MSP_ERROR, "Wrong command type for TSP"));
  1359. FreeEventItem(pEventItem);
  1360. return E_UNEXPECTED;
  1361. }
  1362. HRESULT hr = m_pMSPAddress->PostEvent(pEventItem);
  1363. if (FAILED(hr))
  1364. {
  1365. LOG((MSP_ERROR, "Post event failed %x", hr));
  1366. FreeEventItem(pEventItem);
  1367. return hr;
  1368. }
  1369. return S_OK;
  1370. }
  1371. HRESULT CIPConfMSPCall::CheckUnusedStreams()
  1372. /*++
  1373. Routine Description:
  1374. Find out which streams are not used and send tapi events about them.
  1375. Arguments:
  1376. Return Value:
  1377. HRESULT.
  1378. --*/
  1379. {
  1380. LOG((MSP_TRACE, "CheckUnusedStreams"));
  1381. CLock lock(m_lock);
  1382. for (long j = 0; j < m_Streams.GetSize(); j ++)
  1383. {
  1384. CIPConfMSPStream* pStream = (CIPConfMSPStream*)m_Streams[j];
  1385. if (pStream->IsConfigured())
  1386. {
  1387. // find the next.
  1388. continue;
  1389. }
  1390. MSPEVENTITEM* pEventItem = AllocateEventItem();
  1391. if (pEventItem == NULL)
  1392. {
  1393. LOG((MSP_ERROR, "No memory for the TSPMSP data"));
  1394. return E_OUTOFMEMORY;
  1395. }
  1396. // Fill in the necessary fields for the event structure.
  1397. pEventItem->MSPEventInfo.dwSize = sizeof(MSP_EVENT_INFO);;
  1398. pEventItem->MSPEventInfo.Event = ME_CALL_EVENT;
  1399. pEventItem->MSPEventInfo.hCall = m_htCall;
  1400. pEventItem->MSPEventInfo.MSP_CALL_EVENT_INFO.Type = CALL_STREAM_NOT_USED;
  1401. pEventItem->MSPEventInfo.MSP_CALL_EVENT_INFO.Cause = CALL_CAUSE_REMOTE_REQUEST;
  1402. pEventItem->MSPEventInfo.MSP_CALL_EVENT_INFO.pStream = m_Streams[j];
  1403. // Addref to prevent it from going away.
  1404. m_Streams[j]->AddRef();
  1405. pEventItem->MSPEventInfo.MSP_CALL_EVENT_INFO.pTerminal = NULL;
  1406. pEventItem->MSPEventInfo.MSP_CALL_EVENT_INFO.hrError= 0;
  1407. // send the event to tapi.
  1408. HRESULT hr = m_pMSPAddress->PostEvent(pEventItem);
  1409. if (FAILED(hr))
  1410. {
  1411. LOG((MSP_ERROR, "Post event failed %x", hr));
  1412. FreeEventItem(pEventItem);
  1413. return hr;
  1414. }
  1415. }
  1416. return S_OK;
  1417. }
  1418. DWORD WINAPI CIPConfMSPCall::WorkerCallbackDispatcher(VOID *pContext)
  1419. /*++
  1420. Routine Description:
  1421. Because Parsing the SDP and configure the streams uses a lot of COM
  1422. stuff, we can't rely on the RPC thread the calls into the MSP to
  1423. receive the TSP data. So, we let our own working thread do the work.
  1424. This method is the callback function for the queued work item. It
  1425. just gets the call object from the context structure and calls a method
  1426. on the call object to handle the work item.
  1427. Arguments:
  1428. pContext - A pointer to a CALLWORKITEM structure.
  1429. Return Value:
  1430. HRESULT.
  1431. --*/
  1432. {
  1433. _ASSERTE(!IsBadReadPtr(pContext, sizeof CALLWORKITEM));
  1434. CALLWORKITEM *pItem = (CALLWORKITEM *)pContext;
  1435. pItem->pCall->ProcessWorkerCallBack(pItem->Buffer, pItem->dwLen);
  1436. pItem->pCall->MSPCallRelease();
  1437. free(pItem);
  1438. return NOERROR;
  1439. }
  1440. DWORD CIPConfMSPCall::ProcessWorkerCallBack(
  1441. IN PBYTE pBuffer,
  1442. IN DWORD dwSize
  1443. )
  1444. /*++
  1445. Routine Description:
  1446. This function handles the work item given by the TSP.
  1447. Arguments:
  1448. pBuffer - a buffer that contains a TSP_MSP command block.
  1449. dwSize - the size of the buffer.
  1450. Return Value:
  1451. NOERROR.
  1452. --*/
  1453. {
  1454. LOG((MSP_TRACE, "PreocessWorkerCallBAck"));
  1455. _ASSERTE(!IsBadReadPtr(pBuffer, dwSize));
  1456. MSG_TSPMSPDATA * pData = (MSG_TSPMSPDATA *)pBuffer;
  1457. HRESULT hr;
  1458. switch (pData->command)
  1459. {
  1460. case CALL_START:
  1461. // Parse the SDP contained in the command block.
  1462. hr = ParseSDP(pData->CallStart.szSDP,
  1463. pData->CallStart.dwAudioQOSLevel,
  1464. pData->CallStart.dwVideoQOSLevel
  1465. );
  1466. if (FAILED(hr))
  1467. {
  1468. // disconnect the call if someting terrible happend.
  1469. SendTSPMessage(CALL_DISCONNECTED, 0);
  1470. LOG((MSP_ERROR, "parsing theSDPBlob object. %x", hr));
  1471. return NOERROR;
  1472. }
  1473. // go through the streams and send events if they are not used.
  1474. hr = CheckUnusedStreams();
  1475. if (FAILED(hr))
  1476. {
  1477. LOG((MSP_ERROR, "start the streams failed. %x", hr));
  1478. }
  1479. break;
  1480. case CALL_STOP:
  1481. InternalShutDown();
  1482. break;
  1483. }
  1484. return NOERROR;
  1485. }
  1486. HRESULT CIPConfMSPCall::ReceiveTSPCallData(
  1487. IN PBYTE pBuffer,
  1488. IN DWORD dwSize
  1489. )
  1490. /*++
  1491. Routine Description:
  1492. This function handles the work item given by the TSP.
  1493. Arguments:
  1494. pBuffer - a buffer that contains a TSP_MSP command block.
  1495. dwSize - the size of the buffer.
  1496. Return Value:
  1497. NOERROR.
  1498. --*/
  1499. {
  1500. LOG((MSP_TRACE,
  1501. "ReceiveTSPCallData, pBuffer %x, dwSize %d", pBuffer, dwSize));
  1502. MSG_TSPMSPDATA * pData = (MSG_TSPMSPDATA *)pBuffer;
  1503. switch (pData->command)
  1504. {
  1505. case CALL_START:
  1506. // make sure the string is valid.
  1507. if ((IsBadReadPtr(pData->CallStart.szSDP,
  1508. (pData->CallStart.dwSDPLen + 1) * sizeof (WCHAR)))
  1509. || (pData->CallStart.szSDP[pData->CallStart.dwSDPLen] != 0))
  1510. {
  1511. LOG((MSP_ERROR, "the TSP data is invalid."));
  1512. return E_UNEXPECTED;
  1513. }
  1514. LOG((MSP_INFO, "SDP string\n%ws", pData->CallStart.szSDP));
  1515. break;
  1516. case CALL_STOP:
  1517. break;
  1518. default:
  1519. LOG((MSP_ERROR,
  1520. "wrong command received from the TSP:%x", pData->command));
  1521. return E_UNEXPECTED;
  1522. }
  1523. // allocate a work item structure for our worker thread.
  1524. CALLWORKITEM *pItem = (CALLWORKITEM *)malloc(sizeof(CALLWORKITEM) + dwSize);
  1525. if (pItem == NULL)
  1526. {
  1527. // Disconnect the call because of out of memory.
  1528. SendTSPMessage(CALL_DISCONNECTED, 0);
  1529. LOG((MSP_ERROR, "out of memory for work item."));
  1530. return E_OUTOFMEMORY;
  1531. }
  1532. this->MSPCallAddRef();
  1533. pItem->pCall = this;
  1534. pItem->dwLen = dwSize;
  1535. CopyMemory(pItem->Buffer, pBuffer, dwSize);
  1536. // post a work item to our worker thread.
  1537. HRESULT hr = g_Thread.QueueWorkItem(
  1538. WorkerCallbackDispatcher, // the callback
  1539. pItem, // the context.
  1540. FALSE // sync (FALSE means asyn)
  1541. );
  1542. if (FAILED(hr))
  1543. {
  1544. if (pData->command == CALL_START)
  1545. {
  1546. // Disconnect the call because we can't handle the work.
  1547. SendTSPMessage(CALL_DISCONNECTED, 0);
  1548. }
  1549. this->MSPCallRelease();
  1550. free(pItem);
  1551. LOG((MSP_ERROR, "queue work item failed."));
  1552. }
  1553. return hr;
  1554. }
  1555. STDMETHODIMP CIPConfMSPCall::EnumerateParticipants(
  1556. OUT IEnumParticipant ** ppEnumParticipant
  1557. )
  1558. /*++
  1559. Routine Description:
  1560. This method returns an enumerator to the participants.
  1561. Arguments:
  1562. ppEnumParticipant - the memory location to store the returned pointer.
  1563. Return Value:
  1564. S_OK
  1565. E_POINTER
  1566. E_OUTOFMEMORY
  1567. --*/
  1568. {
  1569. LOG((MSP_TRACE,
  1570. "EnumerateParticipants entered. ppEnumParticipant:%p", ppEnumParticipant));
  1571. //
  1572. // Check parameters.
  1573. //
  1574. if (IsBadWritePtr(ppEnumParticipant, sizeof(VOID *)))
  1575. {
  1576. LOG((MSP_ERROR, "CIPConfMSPCall::EnumerateParticipants - "
  1577. "bad pointer argument - exit E_POINTER"));
  1578. return E_POINTER;
  1579. }
  1580. //
  1581. // First see if this call has been shut down.
  1582. // acquire the lock before accessing the Participant object list.
  1583. //
  1584. CLock lock(m_ParticipantLock);
  1585. if (m_Participants.GetData() == NULL)
  1586. {
  1587. LOG((MSP_ERROR, "CIPConfMSPCall::EnumerateParticipants - "
  1588. "call appears to have been shut down - exit E_UNEXPECTED"));
  1589. // This call has been shut down.
  1590. return E_UNEXPECTED;
  1591. }
  1592. //
  1593. // Create an enumerator object.
  1594. //
  1595. HRESULT hr = CreateParticipantEnumerator(
  1596. m_Participants.GetData(), // the begin itor
  1597. m_Participants.GetData() + m_Participants.GetSize(), // the end itor,
  1598. ppEnumParticipant
  1599. );
  1600. if (FAILED(hr))
  1601. {
  1602. LOG((MSP_ERROR, "CIPConfMSPCall::EnumerateParticipants - "
  1603. "create enumerator object failed, %x", hr));
  1604. return hr;
  1605. }
  1606. LOG((MSP_TRACE, "CIPConfMSPCall::EnumerateParticipants - exit S_OK"));
  1607. return hr;
  1608. }
  1609. STDMETHODIMP CIPConfMSPCall::get_Participants(
  1610. OUT VARIANT * pVariant
  1611. )
  1612. {
  1613. LOG((MSP_TRACE, "CIPConfMSPCall::get_Participants - enter"));
  1614. //
  1615. // Check parameters.
  1616. //
  1617. if ( IsBadWritePtr(pVariant, sizeof(VARIANT) ) )
  1618. {
  1619. LOG((MSP_ERROR, "CIPConfMSPCall::get_Participants - "
  1620. "bad pointer argument - exit E_POINTER"));
  1621. return E_POINTER;
  1622. }
  1623. //
  1624. // See if this call has been shut down. Acquire the lock before accessing
  1625. // the Participant object list.
  1626. //
  1627. CLock lock(m_ParticipantLock);
  1628. if (m_Participants.GetData() == NULL)
  1629. {
  1630. LOG((MSP_ERROR, "CIPConfMSPCall::get_Participants - "
  1631. "call appears to have been shut down - exit E_UNEXPECTED"));
  1632. // This call has been shut down.
  1633. return E_UNEXPECTED;
  1634. }
  1635. //
  1636. // create the collection object - see mspcoll.h
  1637. //
  1638. HRESULT hr = CreateParticipantCollection(
  1639. m_Participants.GetData(), // the begin itor
  1640. m_Participants.GetData() + m_Participants.GetSize(), // the end itor,
  1641. m_Participants.GetSize(), // the size
  1642. pVariant
  1643. );
  1644. if (FAILED(hr))
  1645. {
  1646. LOG((MSP_ERROR, "CIPConfMSPCall::get_Participants - "
  1647. "create collection failed - exit 0x%08x", hr));
  1648. return hr;
  1649. }
  1650. LOG((MSP_TRACE, "CIPConfMSPCall::get_Participants - exit S_OK"));
  1651. return S_OK;
  1652. }
  1653. // IMulticastControl methods
  1654. STDMETHODIMP CIPConfMSPCall::get_LoopbackMode (
  1655. OUT MULTICAST_LOOPBACK_MODE * pMode
  1656. )
  1657. {
  1658. if (pMode == NULL)
  1659. {
  1660. return E_INVALIDARG;
  1661. }
  1662. *pMode = m_LoopbackMode;
  1663. return S_OK;
  1664. }
  1665. STDMETHODIMP CIPConfMSPCall::put_LoopbackMode (
  1666. IN MULTICAST_LOOPBACK_MODE mode
  1667. )
  1668. {
  1669. if (mode < MM_NO_LOOPBACK || mode > MM_SELECTIVE_LOOPBACK)
  1670. {
  1671. return E_INVALIDARG;
  1672. }
  1673. m_LoopbackMode = mode;
  1674. return S_OK;
  1675. }
  1676. // ITLocalParticipant methods, called by the app.
  1677. STDMETHODIMP CIPConfMSPCall::get_LocalParticipantTypedInfo(
  1678. IN PARTICIPANT_TYPED_INFO InfoType,
  1679. OUT BSTR * ppInfo
  1680. )
  1681. /*++
  1682. Routine Description:
  1683. Get a information item for the local participant. This information is
  1684. sent out to other participants in the conference.
  1685. Arguments:
  1686. InfoType - The type of the information asked.
  1687. ppInfo - the mem address to store a BSTR.
  1688. Return Value:
  1689. S_OK,
  1690. E_INVALIDARG,
  1691. E_POINTER,
  1692. E_OUTOFMEMORY,
  1693. TAPI_E_NOITEMS
  1694. */
  1695. {
  1696. LOG((MSP_TRACE, "CParticipant get info, type:%d", InfoType));
  1697. if (InfoType > PTI_PRIVATE || InfoType < PTI_CANONICALNAME)
  1698. {
  1699. LOG((MSP_ERROR, "CParticipant get info - invalid type:%d", InfoType));
  1700. return E_INVALIDARG;
  1701. }
  1702. if (IsBadWritePtr(ppInfo, sizeof(BSTR)))
  1703. {
  1704. LOG((MSP_ERROR, "CParticipant get info - exit E_POINTER"));
  1705. return E_POINTER;
  1706. }
  1707. // check if we have that info.
  1708. CLock lock(m_lock);
  1709. if (!m_fLocalInfoRetrieved)
  1710. {
  1711. HRESULT hr = InitializeLocalParticipant();
  1712. if (FAILED(hr))
  1713. {
  1714. return hr;
  1715. }
  1716. }
  1717. int index = (int)InfoType;
  1718. if (m_InfoItems[index] == NULL)
  1719. {
  1720. LOG((MSP_INFO, "no local participant info item for %d", InfoType));
  1721. return TAPI_E_NOITEMS;
  1722. }
  1723. // make a BSTR out of it.
  1724. BSTR pName = SysAllocString(m_InfoItems[index]);
  1725. if (pName == NULL)
  1726. {
  1727. LOG((MSP_ERROR, "CParticipant get info - exit out of mem"));
  1728. return E_POINTER;
  1729. }
  1730. // return the BSTR.
  1731. *ppInfo = pName;
  1732. return S_OK;
  1733. }
  1734. // ITLocalParticipant methods, called by the app.
  1735. STDMETHODIMP CIPConfMSPCall::put_LocalParticipantTypedInfo(
  1736. IN PARTICIPANT_TYPED_INFO InfoType,
  1737. IN BSTR pInfo
  1738. )
  1739. /*++
  1740. Routine Description:
  1741. Set a information item for the local participant. This information is
  1742. sent out to other participants in the conference.
  1743. Arguments:
  1744. InfoType - The type of the information item.
  1745. pInfo - the information item.
  1746. Return Value:
  1747. S_OK,
  1748. E_INVALIDARG,
  1749. E_POINTER,
  1750. E_OUTOFMEMORY,
  1751. TAPI_E_NOITEMS
  1752. */
  1753. {
  1754. LOG((MSP_TRACE, "set local info, type:%d", InfoType));
  1755. if (InfoType > PTI_PRIVATE || InfoType < PTI_CANONICALNAME)
  1756. {
  1757. LOG((MSP_ERROR, "set local info - invalid type:%d", InfoType));
  1758. return E_INVALIDARG;
  1759. }
  1760. if (IsBadStringPtr(pInfo, MAX_PARTICIPANT_TYPED_INFO_LENGTH))
  1761. {
  1762. LOG((MSP_ERROR, "set local info, bad ptr:%p", pInfo));
  1763. return E_POINTER;
  1764. }
  1765. DWORD dwStringLen = lstrlenW(pInfo);
  1766. if (dwStringLen > MAX_PARTICIPANT_TYPED_INFO_LENGTH)
  1767. {
  1768. LOG((MSP_ERROR, "local info too long"));
  1769. return E_INVALIDARG;
  1770. }
  1771. // check if we have that info.
  1772. CLock lock(m_lock);
  1773. if (m_fCallStarted)
  1774. {
  1775. return TAPI_E_INVALCALLSTATE;
  1776. }
  1777. if (!m_fLocalInfoRetrieved)
  1778. {
  1779. HRESULT hr = InitializeLocalParticipant();
  1780. if (FAILED(hr))
  1781. {
  1782. return hr;
  1783. }
  1784. }
  1785. int index = (int)InfoType;
  1786. if (m_InfoItems[index] != NULL)
  1787. {
  1788. if (lstrcmpW(m_InfoItems[index], pInfo) == 0)
  1789. {
  1790. // The info is the same as what we are using.
  1791. return S_OK;
  1792. }
  1793. // the infomation is different, release the old info.
  1794. free(m_InfoItems[index]);
  1795. m_InfoItems[index] = NULL;
  1796. }
  1797. // save the info.
  1798. m_InfoItems[index] = (WCHAR *)malloc((dwStringLen + 1)* sizeof(WCHAR));
  1799. if (m_InfoItems[index] == NULL)
  1800. {
  1801. LOG((MSP_ERROR, "out of mem for local info"));
  1802. return E_OUTOFMEMORY;
  1803. }
  1804. lstrcpynW(m_InfoItems[index], pInfo, dwStringLen + 1);
  1805. //
  1806. // The info is new, we need to set it on the streams.
  1807. //
  1808. for (int i = 0; i < m_Streams.GetSize(); i ++)
  1809. {
  1810. ((CIPConfMSPStream*)m_Streams[i])->SetLocalParticipantInfo(
  1811. InfoType,
  1812. m_InfoItems[index],
  1813. dwStringLen
  1814. );
  1815. }
  1816. return S_OK;
  1817. }
  1818. STDMETHODIMP CIPConfMSPCall::SetQOSApplicationID (
  1819. IN BSTR pApplicationID,
  1820. IN BSTR pApplicationGUID,
  1821. IN BSTR pSubIDs
  1822. )
  1823. /*++
  1824. Routine Description:
  1825. This method is called by the App to set the QOS specific application ID.
  1826. It can only be called before the call is connected.
  1827. Arguments:
  1828. pApplicationID - the Application ID.
  1829. pSubIDs - the SubIDs that will be appended to the end of policy locator.
  1830. Return Value:
  1831. S_OK
  1832. E_OUTOFMEMORY
  1833. --*/
  1834. {
  1835. CLock lock(m_lock);
  1836. if (m_fCallStarted)
  1837. {
  1838. return TAPI_E_INVALCALLSTATE;
  1839. }
  1840. if (pSubIDs!=NULL && lstrlenW(pSubIDs)>MAX_QOS_ID_LEN)
  1841. {
  1842. return E_INVALIDARG;
  1843. }
  1844. if (pApplicationID!=NULL && lstrlenW(pApplicationID)>MAX_QOS_ID_LEN)
  1845. {
  1846. return E_INVALIDARG;
  1847. }
  1848. try
  1849. {
  1850. if (m_pApplicationID) SysFreeString(m_pApplicationID);
  1851. m_pApplicationID = SysAllocString(pApplicationID);
  1852. }
  1853. catch(...)
  1854. {
  1855. return E_POINTER;
  1856. }
  1857. if (m_pApplicationID == NULL)
  1858. {
  1859. return E_OUTOFMEMORY;
  1860. }
  1861. try
  1862. {
  1863. if (m_pApplicationGUID)
  1864. {
  1865. SysFreeString(m_pApplicationGUID);
  1866. m_pApplicationGUID = NULL;
  1867. }
  1868. if (m_pSubIDs)
  1869. {
  1870. SysFreeString(m_pSubIDs);
  1871. m_pSubIDs = NULL;
  1872. }
  1873. if (pApplicationGUID)
  1874. {
  1875. m_pApplicationGUID = SysAllocString(pApplicationGUID);
  1876. }
  1877. if (pSubIDs)
  1878. {
  1879. m_pSubIDs = SysAllocString(pSubIDs);
  1880. }
  1881. }
  1882. catch(...)
  1883. {
  1884. SysFreeString(m_pApplicationID);
  1885. m_pApplicationID = NULL;
  1886. if (m_pApplicationGUID)
  1887. {
  1888. SysFreeString(m_pApplicationGUID);
  1889. }
  1890. m_pApplicationGUID = NULL;
  1891. if (m_pSubIDs)
  1892. {
  1893. SysFreeString(m_pSubIDs);
  1894. }
  1895. m_pSubIDs = NULL;
  1896. return E_POINTER;
  1897. }
  1898. if ((pApplicationGUID!=NULL && m_pApplicationGUID==NULL) ||
  1899. (pSubIDs!=NULL && m_pSubIDs==NULL))
  1900. {
  1901. return E_OUTOFMEMORY;
  1902. }
  1903. return S_OK;
  1904. }
  1905. HRESULT CIPConfMSPCall::NewParticipant(
  1906. IN ITStream * pITStream,
  1907. IN DWORD dwSSRC,
  1908. IN DWORD dwSendRecv,
  1909. IN DWORD dwMediaType,
  1910. IN WCHAR * szCName,
  1911. OUT ITParticipant ** ppITParticipant
  1912. )
  1913. /*++
  1914. Routine Description:
  1915. This method is called by a stream object when a new participant appears.
  1916. It looks throught the call's participant list, if the partcipant is
  1917. already in the list, it returns the pointer to the object. If it is not
  1918. found, a new object will be created and added into the list.
  1919. Arguments:
  1920. pITStream - the stream object.
  1921. dwSSRC - the SSRC of the participant in the stream.
  1922. dwSendRecv - a sender or a receiver.
  1923. dwMediaType - the media type of the stream.
  1924. szCName - the canonical name of the participant.
  1925. ppITParticipant - the address to store the returned pointer.
  1926. Return Value:
  1927. S_OK
  1928. E_OUTOFMEMORY
  1929. --*/
  1930. {
  1931. CLock lock(m_ParticipantLock);
  1932. HRESULT hr;
  1933. // First check to see if the participant is in our list. If he is already
  1934. // in the list, just return the object.
  1935. int index;
  1936. if (m_Participants.FindByCName(szCName, &index))
  1937. {
  1938. hr = ((CParticipant *)m_Participants[index])->
  1939. AddStream(pITStream, dwSSRC, dwSendRecv, dwMediaType);
  1940. if (FAILED(hr))
  1941. {
  1942. LOG((MSP_ERROR, "can not add a stream to a participant:%x", hr));
  1943. return hr;
  1944. }
  1945. *ppITParticipant = m_Participants[index];
  1946. (*ppITParticipant)->AddRef();
  1947. return S_OK;
  1948. }
  1949. // create a new participant object.
  1950. CComObject<CParticipant> * pCOMParticipant;
  1951. hr = ::CreateCComObjectInstance(&pCOMParticipant);
  1952. if (NULL == pCOMParticipant)
  1953. {
  1954. LOG((MSP_ERROR, "can not create a new participant:%x", hr));
  1955. return hr;
  1956. }
  1957. ITParticipant* pITParticipant;
  1958. // get the interface pointer.
  1959. hr = pCOMParticipant->_InternalQueryInterface(
  1960. __uuidof(ITParticipant),
  1961. (void **)&pITParticipant
  1962. );
  1963. if (FAILED(hr))
  1964. {
  1965. LOG((MSP_ERROR, "Participant QueryInterface failed: %x", hr));
  1966. delete pCOMParticipant;
  1967. return hr;
  1968. }
  1969. // Initialize the object.
  1970. hr = pCOMParticipant->Init(
  1971. szCName, pITStream, dwSSRC, dwSendRecv, dwMediaType
  1972. );
  1973. if (FAILED(hr))
  1974. {
  1975. LOG((MSP_ERROR, "Create participant:call init failed: %x", hr));
  1976. pITParticipant->Release();
  1977. return hr;
  1978. }
  1979. // Add the Participant into our list of Participants.
  1980. if (!m_Participants.InsertAt(index, pITParticipant))
  1981. {
  1982. pITParticipant->Release();
  1983. LOG((MSP_ERROR, "out of memory in adding a Participant."));
  1984. return E_OUTOFMEMORY;
  1985. }
  1986. // AddRef the interface pointer and return it.
  1987. pITParticipant->AddRef();
  1988. *ppITParticipant = pITParticipant;
  1989. SendParticipantEvent(PE_NEW_PARTICIPANT, pITParticipant);
  1990. return S_OK;
  1991. }
  1992. HRESULT CIPConfMSPCall::ParticipantLeft(
  1993. IN ITParticipant * pITParticipant
  1994. )
  1995. /*++
  1996. Routine Description:
  1997. This method is called by a stream object when a participant left the
  1998. conference.
  1999. Arguments:
  2000. pITParticipant - the participant that left.
  2001. Return Value:
  2002. S_OK
  2003. --*/
  2004. {
  2005. m_ParticipantLock.Lock();
  2006. BOOL fRemoved = m_Participants.Remove(pITParticipant);
  2007. m_ParticipantLock.Unlock();
  2008. if (fRemoved)
  2009. {
  2010. SendParticipantEvent(PE_PARTICIPANT_LEAVE, pITParticipant);
  2011. pITParticipant->Release();
  2012. }
  2013. else
  2014. {
  2015. LOG((MSP_ERROR, "can't remove Participant %p", pITParticipant));
  2016. }
  2017. return S_OK;
  2018. }
  2019. void CIPConfMSPCall::SendParticipantEvent(
  2020. IN PARTICIPANT_EVENT Event,
  2021. IN ITParticipant * pITParticipant,
  2022. IN ITSubStream * pITSubStream
  2023. ) const
  2024. /*++
  2025. Routine Description:
  2026. This method is called by a stream object to send a participant related
  2027. event to the app.
  2028. Arguments:
  2029. Event - the event code.
  2030. pITParticipant - the participant object.
  2031. pITSubStream - the substream object, if any.
  2032. Return Value:
  2033. nothing.
  2034. --*/
  2035. {
  2036. if (pITParticipant)
  2037. {
  2038. LOG((MSP_TRACE, "SendParticipantEvent, event %s, participant:%ws",
  2039. ParticipantEventString[Event],
  2040. ((CParticipant*)pITParticipant)->Name()
  2041. ));
  2042. }
  2043. else
  2044. {
  2045. LOG((MSP_TRACE, "SendParticipantEvent, event %s, participant: null (local)",
  2046. ParticipantEventString[Event]
  2047. ));
  2048. }
  2049. // Create a private event object.
  2050. CComPtr<IDispatch> pEvent;
  2051. HRESULT hr = CreateParticipantEvent(
  2052. Event,
  2053. pITParticipant,
  2054. pITSubStream,
  2055. &pEvent
  2056. );
  2057. if (FAILED(hr))
  2058. {
  2059. LOG((MSP_ERROR, "create event returned: %x", hr));
  2060. return;
  2061. }
  2062. MSPEVENTITEM* pEventItem = AllocateEventItem();
  2063. if (pEventItem == NULL)
  2064. {
  2065. LOG((MSP_ERROR, "No memory for the TSPMSP data"));
  2066. return;
  2067. }
  2068. // Fill in the necessary fields for the event structure.
  2069. pEventItem->MSPEventInfo.dwSize = sizeof(MSP_EVENT_INFO);;
  2070. pEventItem->MSPEventInfo.Event = ME_PRIVATE_EVENT;
  2071. pEventItem->MSPEventInfo.hCall = m_htCall;
  2072. pEventItem->MSPEventInfo.MSP_PRIVATE_EVENT_INFO.pEvent = pEvent;
  2073. pEventItem->MSPEventInfo.MSP_PRIVATE_EVENT_INFO.lEventCode = Event;
  2074. pEvent.p->AddRef();
  2075. // send the event to tapi.
  2076. hr = m_pMSPAddress->PostEvent(pEventItem);
  2077. if (FAILED(hr))
  2078. {
  2079. LOG((MSP_ERROR, "Post event failed %x", hr));
  2080. pEvent.Release();
  2081. FreeEventItem(pEventItem);
  2082. }
  2083. }
  2084. VOID CIPConfMSPCall::HandleGraphEvent(
  2085. IN MSPSTREAMCONTEXT * pContext
  2086. )
  2087. {
  2088. long lEventCode;
  2089. LONG_PTR lParam1, lParam2; // win64 fix
  2090. HRESULT hr = pContext->pIMediaEvent->GetEvent(&lEventCode, &lParam1, &lParam2, 0);
  2091. if (FAILED(hr))
  2092. {
  2093. LOG((MSP_ERROR, "Can not get the actual event. %x", hr));
  2094. return;
  2095. }
  2096. LOG((MSP_EVENT, "ProcessGraphEvent, code:%d param1:%x param2:%x",
  2097. lEventCode, lParam1, lParam2));
  2098. if (lEventCode == EC_PALETTE_CHANGED
  2099. || lEventCode == EC_VIDEO_SIZE_CHANGED)
  2100. {
  2101. LOG((MSP_EVENT, "event %d ignored", lEventCode));
  2102. return;
  2103. }
  2104. //
  2105. // Create an event data structure that we will pass to the worker thread.
  2106. //
  2107. MULTI_GRAPH_EVENT_DATA * pData;
  2108. pData = new MULTI_GRAPH_EVENT_DATA;
  2109. if (pData == NULL)
  2110. {
  2111. LOG((MSP_ERROR, "Out of memory for event data."));
  2112. return;
  2113. }
  2114. pData->pCall = this;
  2115. pData->pITStream = pContext->pITStream;
  2116. pData->lEventCode = lEventCode;
  2117. pData->lParam1 = lParam1;
  2118. pData->lParam2 = lParam2;
  2119. //
  2120. // also pass an addref'ed pointer to IMediaEvent, so that whoever processes
  2121. // the message has the opportunity to free event parameters
  2122. //
  2123. pData->pIMediaEvent = pContext->pIMediaEvent;
  2124. pData->pIMediaEvent->AddRef();
  2125. //
  2126. // Make sure the call and stream don't go away while we handle the event.
  2127. // but use our special inner object addref for the call
  2128. //
  2129. pData->pCall->MSPCallAddRef();
  2130. pData->pITStream->AddRef();
  2131. //
  2132. // Queue an async work item to call ProcessGraphEvent.
  2133. //
  2134. hr = g_Thread.QueueWorkItem(AsyncMultiGraphEvent,
  2135. (void *) pData,
  2136. FALSE); // asynchronous
  2137. if (FAILED(hr))
  2138. {
  2139. LOG((MSP_ERROR, "QueueWorkItem failed, return code:%x", hr));
  2140. pData->pCall->MSPCallRelease();
  2141. pData->pITStream->Release();
  2142. //
  2143. // no one is going to free event params and release the IMediaEvent
  2144. // pointer, so do it here
  2145. //
  2146. pContext->pIMediaEvent->FreeEventParams(lEventCode, lParam1, lParam2);
  2147. pData->pIMediaEvent->Release();
  2148. delete pData;
  2149. }
  2150. }
  2151. HRESULT CIPConfMSPCall::InitFullDuplexControler()
  2152. /*++
  2153. Routine Description:
  2154. This method creates the full-duplex controller object used to control
  2155. audio devices.
  2156. Arguments:
  2157. NONE
  2158. Return Value:
  2159. HRESULT.
  2160. --*/
  2161. {
  2162. ENTER_FUNCTION("CIPConfMSPCall::InitFullDuplexControler");
  2163. LOG((MSP_TRACE, "%s entered", __fxName));
  2164. CLock lock(m_lock);
  2165. if (m_pIAudioDuplexController != NULL)
  2166. {
  2167. return S_OK;
  2168. }
  2169. HRESULT hr;
  2170. IAudioDuplexController *pIAudioDuplexController;
  2171. if (FAILED(hr = CoCreateInstance(
  2172. __uuidof(TAPIAudioDuplexController),
  2173. NULL,
  2174. CLSCTX_INPROC_SERVER | CLSCTX_NO_CODE_DOWNLOAD,
  2175. __uuidof(IAudioDuplexController),
  2176. (void **) &pIAudioDuplexController
  2177. )))
  2178. {
  2179. LOG((MSP_ERROR, "%s, create AudioDuplexController failed. hr=%x",
  2180. __fxName, hr));
  2181. return hr;
  2182. }
  2183. m_pIAudioDuplexController = pIAudioDuplexController;
  2184. return S_OK;
  2185. }
  2186. /*++
  2187. Routine Description:
  2188. ITCallQualityControl method. Delegated to quality control relay
  2189. --*/
  2190. STDMETHODIMP
  2191. CIPConfMSPCall::GetRange (
  2192. IN CallQualityProperty Property,
  2193. OUT long *plMin,
  2194. OUT long *plMax,
  2195. OUT long *plSteppingDelta,
  2196. OUT long *plDefault,
  2197. OUT TAPIControlFlags *plFlags
  2198. )
  2199. {
  2200. return m_pCallQCRelay->GetRange (Property, plMin, plMax, plSteppingDelta, plDefault, plFlags);
  2201. }
  2202. /*++
  2203. Routine Description:
  2204. ITCallQualityControl method. Delegated to quality control relay
  2205. --*/
  2206. STDMETHODIMP
  2207. CIPConfMSPCall::Get (
  2208. IN CallQualityProperty Property,
  2209. OUT long *plValue,
  2210. OUT TAPIControlFlags *plFlags
  2211. )
  2212. {
  2213. return m_pCallQCRelay->Get (Property, plValue, plFlags);
  2214. }
  2215. /*++
  2216. Routine Description:
  2217. ITCallQualityControl method. Delegated to quality control relay
  2218. --*/
  2219. STDMETHODIMP
  2220. CIPConfMSPCall::Set (
  2221. IN CallQualityProperty Property,
  2222. IN long lValue,
  2223. IN TAPIControlFlags lFlags
  2224. )
  2225. {
  2226. return m_pCallQCRelay->Set (Property, lValue, lFlags);
  2227. }
  2228. /*++
  2229. Routine Description:
  2230. IInnerCallQualityControl method. Delegated to quality control relay
  2231. --*/
  2232. STDMETHODIMP_(ULONG)
  2233. CIPConfMSPCall::InnerCallAddRef (VOID)
  2234. {
  2235. return this->MSPCallAddRef ();
  2236. }
  2237. STDMETHODIMP_(ULONG)
  2238. CIPConfMSPCall::InnerCallRelease (VOID)
  2239. {
  2240. return this->MSPCallRelease ();
  2241. }
  2242. STDMETHODIMP
  2243. CIPConfMSPCall::RegisterInnerStreamQC (
  2244. IN IInnerStreamQualityControl *pIInnerStreamQC
  2245. )
  2246. {
  2247. return m_pCallQCRelay->RegisterInnerStreamQC (
  2248. pIInnerStreamQC
  2249. );
  2250. }
  2251. /*++
  2252. Routine Description:
  2253. IInnerCallQualityControl method. Delegated to quality control relay
  2254. --*/
  2255. STDMETHODIMP
  2256. CIPConfMSPCall::DeRegisterInnerStreamQC (
  2257. IN IInnerStreamQualityControl *pIInnerStreamQC
  2258. )
  2259. {
  2260. return m_pCallQCRelay->DeRegisterInnerStreamQC (
  2261. pIInnerStreamQC
  2262. );
  2263. }
  2264. /*++
  2265. Routine Description:
  2266. IInnerCallQualityControl method. Delegated to quality control relay
  2267. --*/
  2268. STDMETHODIMP
  2269. CIPConfMSPCall::ProcessQCEvent (
  2270. IN QCEvent event,
  2271. IN DWORD dwParam
  2272. )
  2273. {
  2274. return m_pCallQCRelay->ProcessQCEvent (event, dwParam);
  2275. }