Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

4284 lines
100 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. confvid.cpp
  5. Abstract:
  6. This module contains implementation of the video send and receive
  7. stream implementations.
  8. Author:
  9. Mu Han (muhan) 15-September-1999
  10. --*/
  11. #include "stdafx.h"
  12. #include "common.h"
  13. #include <irtprph.h> // for IRTPRPHFilter
  14. #include <irtpsph.h> // for IRTPSPHFilter
  15. #include <amrtpuid.h> // AMRTP media types
  16. #include <amrtpnet.h> // rtp guids
  17. #include <ih26xcd.h> // for the h26X encoder filter
  18. #include <initguid.h>
  19. #include <amrtpdmx.h> // demux guid
  20. #include <viduids.h> // for video CLSIDs
  21. /////////////////////////////////////////////////////////////////////////////
  22. //
  23. // CStreamVideoRecv
  24. //
  25. /////////////////////////////////////////////////////////////////////////////
  26. CStreamVideoRecv::CStreamVideoRecv()
  27. : CIPConfMSPStream(),
  28. m_pIRTPDemux(NULL)
  29. {
  30. m_szName = L"VideoRecv";
  31. }
  32. HRESULT CStreamVideoRecv::Init(
  33. IN HANDLE hAddress,
  34. IN CMSPCallBase * pMSPCall,
  35. IN IMediaEvent * pIGraphBuilder,
  36. IN DWORD dwMediaType,
  37. IN TERMINAL_DIRECTION Direction
  38. )
  39. /*++
  40. Routine Description:
  41. Init our substream array and then call the base class' Init.
  42. Arguments:
  43. hAddress - a handle to the address, used in identify terminals.
  44. pMSPCall - the call object that owns the stream.
  45. pIGraphBuilder - the filter graph object.
  46. dwMediaType - the mediatype of this stream.
  47. Direction - the direction of this stream.
  48. Return Value:
  49. S_OK,
  50. E_OUTOFMEMORY
  51. --*/
  52. {
  53. LOG((MSP_TRACE, "CSubStreamVideoRecvVideoSend::Init - enter"));
  54. // initialize the stream array so that the array is not NULL.
  55. if (!m_SubStreams.Grow())
  56. {
  57. LOG((MSP_TRACE, "CSubStreamVideoRecvVideoSend::Init - return out of memory"));
  58. return E_OUTOFMEMORY;
  59. }
  60. return CIPConfMSPStream::Init(
  61. hAddress, pMSPCall, pIGraphBuilder,dwMediaType, Direction
  62. );
  63. }
  64. HRESULT CStreamVideoRecv::ShutDown()
  65. /*++
  66. Routine Description:
  67. Shut down the stream.
  68. Arguments:
  69. Return Value:
  70. S_OK
  71. --*/
  72. {
  73. CLock lock(m_lock);
  74. // Release the memory for the local participant info items.
  75. for (int j = 0; j < RTCP_SDES_LAST - 1; j ++)
  76. {
  77. if (m_InfoItems[j])
  78. {
  79. free(m_InfoItems[j]);
  80. m_InfoItems[j] = NULL;
  81. }
  82. }
  83. // Release the refcount on the call object.
  84. if (m_pMSPCall)
  85. {
  86. m_pMSPCall->MSPCallRelease();
  87. m_pMSPCall = NULL;
  88. }
  89. // if there are branches and configured, we need to disconnect
  90. // the terminals and remove the branches.
  91. if (m_Branches.GetSize() > 0)
  92. {
  93. // Stop the graph before disconnecting the terminals.
  94. HRESULT hr = CMSPStream::StopStream();
  95. if (FAILED(hr))
  96. {
  97. LOG((MSP_ERROR,
  98. "stream %ws %p failed to stop, %x", m_szName, this, hr));
  99. return hr;
  100. }
  101. for (int i = 0; i < m_Branches.GetSize(); i ++)
  102. {
  103. RemoveOneBranch(&m_Branches[i]);
  104. }
  105. m_Branches.RemoveAll();
  106. }
  107. // free the extra filter reference.
  108. if (m_pEdgeFilter)
  109. {
  110. m_pEdgeFilter->Release();
  111. m_pEdgeFilter = NULL;
  112. }
  113. if (m_pIRTPDemux)
  114. {
  115. m_pIRTPDemux->Release();
  116. m_pIRTPDemux = NULL;
  117. }
  118. if (m_pRTPFilter)
  119. {
  120. m_pRTPFilter->Release();
  121. m_pRTPFilter = NULL;
  122. }
  123. // release all the substream objects.
  124. for (int i = 0; i < m_SubStreams.GetSize(); i ++)
  125. {
  126. m_SubStreams[i]->Release();
  127. }
  128. m_SubStreams.RemoveAll();
  129. // release all the terminals.
  130. for (i = 0; i < m_Terminals.GetSize(); i ++ )
  131. {
  132. m_Terminals[i]->Release();
  133. }
  134. m_Terminals.RemoveAll();
  135. // release all the participants.
  136. for (i = 0; i < m_Participants.GetSize(); i ++)
  137. {
  138. m_Participants[i]->Release();
  139. }
  140. m_Participants.RemoveAll();
  141. LOG((MSP_TRACE, "CStreamVideoRecv::Shutdown - exit S_OK"));
  142. return S_OK;
  143. }
  144. HRESULT CStreamVideoRecv::InternalCreateSubStream(
  145. OUT ITSubStream ** ppSubStream
  146. )
  147. /*++
  148. Routine Description:
  149. This method creat a substream object and add it into out list.
  150. Arguments:
  151. ppSubStream - the memory location that will store the returned SubStream.
  152. Return Value:
  153. S_OK
  154. E_OUTOFMEMORY
  155. E_NOINTERFACE
  156. --*/
  157. {
  158. CComObject<CSubStreamVideoRecv> * pCOMSubStream;
  159. HRESULT hr = CComObject<CSubStreamVideoRecv>::CreateInstance(&pCOMSubStream);
  160. if (NULL == pCOMSubStream)
  161. {
  162. LOG((MSP_ERROR, "could not create video recv sub stream:%x", hr));
  163. return hr;
  164. }
  165. ITSubStream* pSubStream;
  166. // get the interface pointer.
  167. hr = pCOMSubStream->_InternalQueryInterface(
  168. IID_ITSubStream,
  169. (void **)&pSubStream
  170. );
  171. if (FAILED(hr))
  172. {
  173. LOG((MSP_ERROR, "Create VideoRecv Substream QueryInterface failed: %x", hr));
  174. delete pCOMSubStream;
  175. return hr;
  176. }
  177. // Initialize the object.
  178. hr = pCOMSubStream->Init(this);
  179. if (FAILED(hr))
  180. {
  181. LOG((MSP_ERROR, "CreateMSPSubStream:call init failed: %x", hr));
  182. pSubStream->Release();
  183. return hr;
  184. }
  185. // Add the SubStream into our list of SubStreams. This takes a refcount.
  186. if (!m_SubStreams.Add(pSubStream))
  187. {
  188. pSubStream->Release();
  189. LOG((MSP_ERROR, "out of memory in adding a SubStream."));
  190. return E_OUTOFMEMORY;
  191. }
  192. // AddRef the interface pointer and return it.
  193. pSubStream->AddRef();
  194. *ppSubStream = pSubStream;
  195. return S_OK;
  196. }
  197. // ITSubStreamControl methods, called by the app.
  198. STDMETHODIMP CStreamVideoRecv::CreateSubStream(
  199. IN OUT ITSubStream ** ppSubStream
  200. )
  201. /*++
  202. Routine Description:
  203. This method creates a new substream on this video receive stream. Since
  204. the substreams are created based on the participants, this function
  205. returns only TAPI_E_NOTSUPPORTED.
  206. Arguments:
  207. ppSubStream - the memory location that will store the returned SubStream.
  208. Return Value:
  209. TAPI_E_NOTSUPPORTED
  210. --*/
  211. {
  212. return TAPI_E_NOTSUPPORTED;
  213. }
  214. STDMETHODIMP CStreamVideoRecv::RemoveSubStream(
  215. IN ITSubStream * pSubStream
  216. )
  217. /*++
  218. Routine Description:
  219. This method remove substream on this video receive stream. Since
  220. the substreams are created based on the participants, this function
  221. returns only TAPI_E_NOTSUPPORTED.
  222. Arguments:
  223. pSubStream - the SubStream to be removed.
  224. Return Value:
  225. TAPI_E_NOTSUPPORTED
  226. --*/
  227. {
  228. return TAPI_E_NOTSUPPORTED;
  229. }
  230. STDMETHODIMP CStreamVideoRecv::EnumerateSubStreams(
  231. OUT IEnumSubStream ** ppEnumSubStream
  232. )
  233. /*++
  234. Routine Description:
  235. This method returns an enumerator of the substreams.
  236. Arguments:
  237. ppEnumSubStream - the memory location to store the returned pointer.
  238. Return Value:
  239. S_OK
  240. E_POINTER
  241. E_UNEXPECTED
  242. E_OUTOFMEMORY
  243. --*/
  244. {
  245. LOG((MSP_TRACE,
  246. "EnumerateSubStreams entered. ppEnumSubStream:%x", ppEnumSubStream));
  247. //
  248. // Check parameters.
  249. //
  250. if (IsBadWritePtr(ppEnumSubStream, sizeof(VOID *)))
  251. {
  252. LOG((MSP_ERROR, "CMSPCallBase::EnumerateSubStreams - "
  253. "bad pointer argument - exit E_POINTER"));
  254. return E_POINTER;
  255. }
  256. //
  257. // First see if this call has been shut down.
  258. // acquire the lock before accessing the SubStream object list.
  259. //
  260. CLock lock(m_lock);
  261. if (m_SubStreams.GetData() == NULL)
  262. {
  263. LOG((MSP_ERROR, "CMSPCallBase::EnumerateSubStreams - "
  264. "call appears to have been shut down - exit E_UNEXPECTED"));
  265. // This call has been shut down.
  266. return E_UNEXPECTED;
  267. }
  268. //
  269. // Create an enumerator object.
  270. //
  271. typedef _CopyInterface<ITSubStream> CCopy;
  272. typedef CSafeComEnum<IEnumSubStream, &IID_IEnumSubStream,
  273. ITSubStream *, CCopy> CEnumerator;
  274. HRESULT hr;
  275. CComObject<CEnumerator> *pEnum = NULL;
  276. hr = CComObject<CEnumerator>::CreateInstance(&pEnum);
  277. if (pEnum == NULL)
  278. {
  279. LOG((MSP_ERROR, "CMSPCallBase::EnumerateSubStreams - "
  280. "Could not create enumerator object, %x", hr));
  281. return hr;
  282. }
  283. //
  284. // query for the IID_IEnumSubStream i/f
  285. //
  286. IEnumSubStream * pEnumSubStream;
  287. hr = pEnum->_InternalQueryInterface(IID_IEnumSubStream, (void**)&pEnumSubStream);
  288. if (FAILED(hr))
  289. {
  290. LOG((MSP_ERROR, "CMSPCallBase::EnumerateSubStreams - "
  291. "query enum interface failed, %x", hr));
  292. delete pEnum;
  293. return hr;
  294. }
  295. //
  296. // Init the enumerator object. The CSafeComEnum can handle zero-sized array.
  297. //
  298. hr = pEnum->Init(
  299. m_SubStreams.GetData(), // the begin itor
  300. m_SubStreams.GetData() + m_SubStreams.GetSize(), // the end itor,
  301. NULL, // IUnknown
  302. AtlFlagCopy // copy the data.
  303. );
  304. if (FAILED(hr))
  305. {
  306. LOG((MSP_ERROR, "CMSPCallBase::EnumerateSubStreams - "
  307. "init enumerator object failed, %x", hr));
  308. pEnumSubStream->Release();
  309. return hr;
  310. }
  311. LOG((MSP_TRACE, "CMSPCallBase::EnumerateSubStreams - exit S_OK"));
  312. *ppEnumSubStream = pEnumSubStream;
  313. return hr;
  314. }
  315. STDMETHODIMP CStreamVideoRecv::get_SubStreams(
  316. OUT VARIANT * pVariant
  317. )
  318. /*++
  319. Routine Description:
  320. This method returns a collection of the substreams.
  321. Arguments:
  322. pVariant - a variant structure.
  323. Return Value:
  324. S_OK
  325. E_POINTER
  326. E_UNEXPECTED
  327. E_OUTOFMEMORY
  328. --*/
  329. {
  330. LOG((MSP_TRACE, "CStreamVideoRecv::get_SubStreams - enter"));
  331. //
  332. // Check parameters.
  333. //
  334. if ( IsBadWritePtr(pVariant, sizeof(VARIANT) ) )
  335. {
  336. LOG((MSP_ERROR, "CStreamVideoRecv::get_SubStreams - "
  337. "bad pointer argument - exit E_POINTER"));
  338. return E_POINTER;
  339. }
  340. //
  341. // See if this call has been shut down. Acquire the lock before accessing
  342. // the SubStream object list.
  343. //
  344. CLock lock(m_lock);
  345. if (m_SubStreams.GetData() == NULL)
  346. {
  347. LOG((MSP_ERROR, "CStreamVideoRecv::get_SubStreams - "
  348. "call appears to have been shut down - exit E_UNEXPECTED"));
  349. // This call has been shut down.
  350. return E_UNEXPECTED;
  351. }
  352. //
  353. // create the collection object - see mspcoll.h
  354. //
  355. typedef CTapiIfCollection< ITSubStream * > SubStreamCollection;
  356. CComObject<SubStreamCollection> * pCollection;
  357. HRESULT hr = CComObject<SubStreamCollection>::CreateInstance( &pCollection );
  358. if ( FAILED(hr) )
  359. {
  360. LOG((MSP_ERROR, "CStreamVideoRecv::get_SubStreams - "
  361. "can't create collection - exit 0x%08x", hr));
  362. return hr;
  363. }
  364. //
  365. // get the Collection's IDispatch interface
  366. //
  367. IDispatch * pDispatch;
  368. hr = pCollection->_InternalQueryInterface(IID_IDispatch,
  369. (void **) &pDispatch );
  370. if ( FAILED(hr) )
  371. {
  372. LOG((MSP_ERROR, "CStreamVideoRecv::get_SubStreams - "
  373. "QI for IDispatch on collection failed - exit 0x%08x", hr));
  374. delete pCollection;
  375. return hr;
  376. }
  377. //
  378. // Init the collection using an iterator -- pointers to the beginning and
  379. // the ending element plus one.
  380. //
  381. hr = pCollection->Initialize( m_SubStreams.GetSize(),
  382. m_SubStreams.GetData(),
  383. m_SubStreams.GetData() + m_SubStreams.GetSize() );
  384. if (FAILED(hr))
  385. {
  386. LOG((MSP_ERROR, "CStreamVideoRecv::get_SubStreams - "
  387. "Initialize on collection failed - exit 0x%08x", hr));
  388. pDispatch->Release();
  389. return hr;
  390. }
  391. //
  392. // put the IDispatch interface pointer into the variant
  393. //
  394. VariantInit(pVariant);
  395. pVariant->vt = VT_DISPATCH;
  396. pVariant->pdispVal = pDispatch;
  397. LOG((MSP_TRACE, "CStreamVideoRecv::get_SubStreams - exit S_OK"));
  398. return S_OK;
  399. }
  400. HRESULT CStreamVideoRecv::Configure(
  401. IN STREAMSETTINGS &StreamSettings
  402. )
  403. /*++
  404. Routine Description:
  405. Configure the settings of this stream.
  406. Arguments:
  407. StreamSettings - The setting structure got from the SDP blob.
  408. Return Value:
  409. HRESULT.
  410. --*/
  411. {
  412. LOG((MSP_TRACE, "VideoRecv configure entered."));
  413. CLock lock(m_lock);
  414. _ASSERTE(m_fIsConfigured == FALSE);
  415. switch (StreamSettings.dwPayloadType)
  416. {
  417. case PAYLOAD_H261:
  418. m_pClsidCodecFilter = &CLSID_H261_DECODE_FILTER;
  419. m_pRPHInputMinorType = &MEDIASUBTYPE_RTP_Payload_H261;
  420. m_pClsidPHFilter = &CLSID_INTEL_RPHH26X;
  421. break;
  422. case PAYLOAD_H263:
  423. m_pClsidCodecFilter = &CLSID_H263_DECODE_FILTER;
  424. m_pRPHInputMinorType = &MEDIASUBTYPE_RTP_Payload_H263;
  425. m_pClsidPHFilter = &CLSID_INTEL_RPHH26X;
  426. break;
  427. default:
  428. LOG((MSP_ERROR, "unknow payload type, %x", StreamSettings.dwPayloadType));
  429. return E_FAIL;
  430. }
  431. m_Settings = StreamSettings;
  432. m_fIsConfigured = TRUE;
  433. return InternalConfigure();
  434. }
  435. HRESULT CStreamVideoRecv::CheckTerminalTypeAndDirection(
  436. IN ITTerminal * pTerminal
  437. )
  438. /*++
  439. Routine Description:
  440. Check to see if the terminal is allowed on this stream. Only video
  441. render terminal is allowed.
  442. Arguments:
  443. pTerminal - the terminal.
  444. Return value:
  445. S_OK
  446. TAPI_E_INVALIDTERMINAL
  447. */
  448. {
  449. LOG((MSP_TRACE, "VideoRecv.CheckTerminalTypeAndDirection"));
  450. // check the media type of this terminal.
  451. long lMediaType;
  452. HRESULT hr = pTerminal->get_MediaType(&lMediaType);
  453. if (FAILED(hr))
  454. {
  455. LOG((MSP_ERROR, "can't get terminal media type. %x", hr));
  456. return TAPI_E_INVALIDTERMINAL;
  457. }
  458. if ((DWORD)lMediaType != m_dwMediaType)
  459. {
  460. return TAPI_E_INVALIDTERMINAL;
  461. }
  462. // check the direction of this terminal.
  463. TERMINAL_DIRECTION Direction;
  464. hr = pTerminal->get_Direction(&Direction);
  465. if (FAILED(hr))
  466. {
  467. LOG((MSP_ERROR, "can't get terminal direction. %x", hr));
  468. return TAPI_E_INVALIDTERMINAL;
  469. }
  470. if (Direction != m_Direction)
  471. {
  472. return TAPI_E_INVALIDTERMINAL;
  473. }
  474. return S_OK;
  475. }
  476. HRESULT CStreamVideoRecv::SubStreamSelectTerminal(
  477. IN ITSubStream * pITSubStream,
  478. IN ITTerminal * pITTerminal
  479. )
  480. /*++
  481. Routine Description:
  482. handle terminals being selected on the sub streams. It gives the terminal
  483. to one free branch and then sets up a mapping between the branch and the
  484. substream, so that the participant in the substream is displayed on the
  485. terminal selected.
  486. Arguments:
  487. pITSubStream - the Substream that got a terminal selected.
  488. pITTerminal - the terminal object.
  489. Return Value:
  490. S_OK
  491. --*/
  492. {
  493. LOG((MSP_TRACE, "VideoRecv SubStreamSelectTerminal"));
  494. HRESULT hr;
  495. CLock lock(m_lock);
  496. // Call the base class's select terminal first. The terminal will be put
  497. // into the terminal pool and a branch of filters will be created for it.
  498. hr = CIPConfMSPStream::SelectTerminal(pITTerminal);
  499. if (FAILED(hr))
  500. {
  501. return hr;
  502. }
  503. // Find out which branch got the terminal.
  504. int i;
  505. for (i = 0; i < m_Branches.GetSize(); i ++)
  506. {
  507. if (m_Branches[i].pITTerminal == pITTerminal)
  508. {
  509. break;
  510. }
  511. }
  512. _ASSERTE(i < m_Branches.GetSize());
  513. if (i >= m_Branches.GetSize())
  514. {
  515. return E_UNEXPECTED;
  516. }
  517. // Find out the participant on the SubStream.
  518. ITParticipant *pITParticipant = NULL;
  519. DWORD dwSSRC;
  520. if (((CSubStreamVideoRecv*)m_SubStreams[i])->GetCurrentParticipant(
  521. &dwSSRC,
  522. &pITParticipant
  523. ) == FALSE)
  524. {
  525. return E_UNEXPECTED;
  526. }
  527. pITParticipant->Release();
  528. if (m_pIRTPDemux == NULL)
  529. {
  530. LOG((MSP_ERROR, "no demux filter"));
  531. return E_UNEXPECTED;
  532. }
  533. // map the pin to this SSRC only.
  534. hr = m_pIRTPDemux->MapSSRCToPin(dwSSRC, m_Branches[i].pIPin);
  535. if (FAILED(hr))
  536. {
  537. LOG((MSP_ERROR, "map SSRC %x to pin %p returned %x",
  538. dwSSRC, m_Branches[i].pIPin, hr));
  539. return hr;
  540. }
  541. _ASSERTE(m_Branches[i].pITSubStream == NULL);
  542. pITSubStream->AddRef();
  543. m_Branches[i].pITSubStream = pITSubStream;
  544. m_Branches[i].dwSSRC = dwSSRC;
  545. return hr;
  546. }
  547. HRESULT CStreamVideoRecv::ConfigureRTPFilter(
  548. IN IBaseFilter * pIBaseFilter
  549. )
  550. /*++
  551. Routine Description:
  552. Configure the source RTP filter. Including set the address, port, TTL,
  553. QOS, thread priority, clockrate, etc.
  554. Arguments:
  555. pIBaseFilter - The source RTP Filter.
  556. Return Value:
  557. HRESULT.
  558. --*/
  559. {
  560. LOG((MSP_TRACE, "VideoRecv ConfigureRTPFilter"));
  561. HRESULT hr;
  562. // Get the IRTPStream interface pointer on the filter.
  563. CComQIPtr<IRTPStream, &IID_IRTPStream> pIRTPStream(pIBaseFilter);
  564. if (pIRTPStream == NULL)
  565. {
  566. LOG((MSP_ERROR, "get RTP Stream interface"));
  567. return E_NOINTERFACE;
  568. }
  569. LOG((MSP_INFO, "set remote Address:%x, port:%d",
  570. m_Settings.dwIPRemote, m_Settings.wRTPPortRemote));
  571. // Set the address and port used in the filter.
  572. if (FAILED(hr = pIRTPStream->SetAddress(
  573. htons(m_Settings.wRTPPortRemote), // local port to listen on.
  574. 0, // remote port.
  575. htonl(m_Settings.dwIPRemote) // remote address.
  576. )))
  577. {
  578. LOG((MSP_ERROR, "set remote Address, hr:%x", hr));
  579. return hr;
  580. }
  581. // Set the TTL used in the filter.
  582. if (FAILED(hr = pIRTPStream->SetMulticastScope(m_Settings.dwTTL)))
  583. {
  584. LOG((MSP_ERROR, "set TTL. %x", hr));
  585. return hr;
  586. }
  587. if (m_Settings.dwIPLocal != INADDR_ANY)
  588. {
  589. // set the local interface that the socket should bind to
  590. LOG((MSP_INFO, "set locol Address:%x", m_Settings.dwIPLocal));
  591. if (FAILED(hr = pIRTPStream->SelectLocalIPAddress(
  592. htonl(m_Settings.dwIPLocal)
  593. )))
  594. {
  595. LOG((MSP_ERROR, "set locol Address, hr:%x", hr));
  596. return hr;
  597. }
  598. }
  599. // Set the priority of the session
  600. if (FAILED(hr = pIRTPStream->SetSessionClassPriority(
  601. RTP_CLASS_VIDEO,
  602. g_dwVideoThreadPriority
  603. )))
  604. {
  605. LOG((MSP_ERROR, "set session class and priority. %x", hr));
  606. }
  607. // Set the sample rate of the session
  608. LOG((MSP_INFO, "setting session sample rate to %d", g_dwVideoSampleRate));
  609. if (FAILED(hr = pIRTPStream->SetDataClock(g_dwVideoSampleRate)))
  610. {
  611. LOG((MSP_ERROR, "set session sample rate. %x", hr));
  612. }
  613. // Enable the RTCP events
  614. if (FAILED(hr = ::EnableRTCPEvents(pIBaseFilter)))
  615. {
  616. LOG((MSP_WARN, "can not enable RTCP events %x", hr));
  617. }
  618. DWORD dwLoopback = 0;
  619. if (TRUE == ::GetRegValue(gszMSPLoopback, &dwLoopback)
  620. && dwLoopback != 0)
  621. {
  622. // Loopback is required.
  623. if (FAILED(hr = ::SetLoopbackOption(pIBaseFilter, dwLoopback)))
  624. {
  625. LOG((MSP_ERROR, "set loopback option. %x", hr));
  626. return hr;
  627. }
  628. }
  629. if (m_Settings.dwQOSLevel != QSL_BEST_EFFORT)
  630. {
  631. if (FAILED(hr = ::SetQOSOption(
  632. pIBaseFilter,
  633. m_Settings.dwPayloadType, // payload
  634. -1, // use the default bitrate
  635. (m_Settings.dwQOSLevel == QSL_NEEDED), // fail if no qos.
  636. TRUE, // receive stream.
  637. g_dwVideoChannels, // number of streams reserved.
  638. m_Settings.fCIF
  639. )))
  640. {
  641. LOG((MSP_ERROR, "set QOS option. %x", hr));
  642. return hr;
  643. }
  644. }
  645. SetLocalInfoOnRTPFilter(pIBaseFilter);
  646. return S_OK;
  647. }
  648. HRESULT CStreamVideoRecv::SetUpInternalFilters()
  649. /*++
  650. Routine Description:
  651. set up the filters used in the stream.
  652. RTP->Demux->RPH->DECODER->Render terminal
  653. This function only creates the RTP and demux filter and the rest of the
  654. graph is connected in ConnectTerminal.
  655. Arguments:
  656. Return Value:
  657. HRESULT.
  658. --*/
  659. {
  660. LOG((MSP_TRACE, "VideoRecv.SetUpInternalFilters"));
  661. CComPtr<IBaseFilter> pSourceFilter;
  662. HRESULT hr;
  663. // create and add the source fitler.
  664. if (FAILED(hr = ::AddFilter(
  665. m_pIGraphBuilder,
  666. CLSID_RTPSourceFilter,
  667. L"RtpSource",
  668. &pSourceFilter)))
  669. {
  670. LOG((MSP_ERROR, "adding source filter. %x", hr));
  671. return hr;
  672. }
  673. if (FAILED(hr = ConfigureRTPFilter(pSourceFilter)))
  674. {
  675. LOG((MSP_ERROR, "configure RTP source filter. %x", hr));
  676. return hr;
  677. }
  678. CComPtr<IBaseFilter> pDemuxFilter;
  679. // create and add the demux fitler.
  680. if (FAILED(hr = ::AddFilter(
  681. m_pIGraphBuilder,
  682. CLSID_IntelRTPDemux,
  683. L"RtpDemux",
  684. &pDemuxFilter)))
  685. {
  686. LOG((MSP_ERROR, "adding demux filter. %x", hr));
  687. return hr;
  688. }
  689. // Connect the source filter and the demux filter.
  690. if (FAILED(hr = ::ConnectFilters(
  691. m_pIGraphBuilder,
  692. (IBaseFilter *)pSourceFilter,
  693. (IBaseFilter *)pDemuxFilter)))
  694. {
  695. LOG((MSP_ERROR, "connect source filter and demux filter. %x", hr));
  696. return hr;
  697. }
  698. // Get the IRTPParticipant interface pointer on the RTP filter.
  699. CComQIPtr<IRTPParticipant,
  700. &IID_IRTPParticipant> pIRTPParticipant(pSourceFilter);
  701. if (pIRTPParticipant == NULL)
  702. {
  703. LOG((MSP_ERROR, "can't get RTP participant interface"));
  704. return E_NOINTERFACE;
  705. }
  706. CComQIPtr<IRTPDemuxFilter, &IID_IRTPDemuxFilter> pIRTPDemux(pDemuxFilter);
  707. if (pIRTPDemux == NULL)
  708. {
  709. LOG((MSP_ERROR, "get RTP Demux interface"));
  710. return E_NOINTERFACE;
  711. }
  712. m_pEdgeFilter = pDemuxFilter;
  713. m_pEdgeFilter->AddRef();
  714. _ASSERTE(m_pIRTPDemux == NULL);
  715. m_pIRTPDemux = pIRTPDemux;
  716. m_pIRTPDemux->AddRef();
  717. m_pRTPFilter = pIRTPParticipant;
  718. m_pRTPFilter->AddRef();
  719. return hr;
  720. }
  721. HRESULT CStreamVideoRecv::AddOneBranch(
  722. BRANCH * pBranch
  723. )
  724. /*++
  725. Routine Description:
  726. Create a new branch of filters off the demux.
  727. Arguments:
  728. pBranch - a pointer to a structure that remembers the info about the branch.
  729. Return Value:
  730. HRESULT.
  731. --*/
  732. {
  733. LOG((MSP_TRACE, "AddOneBranch entered."));
  734. _ASSERTE(m_pIRTPDemux != NULL);
  735. // Find the next output pin on the demux fitler.
  736. CComPtr<IPin> pIPinOutput;
  737. HRESULT hr;
  738. // Set the media type on this output pin.
  739. if (FAILED(hr = ::FindPin(
  740. (IBaseFilter *)m_pEdgeFilter,
  741. (IPin**)&pIPinOutput,
  742. PINDIR_OUTPUT
  743. )))
  744. {
  745. LOG((MSP_ERROR, "find free pin on demux, %x", hr));
  746. return hr;
  747. }
  748. // Set the media type on this output pin.
  749. if (FAILED(hr = m_pIRTPDemux->SetPinTypeInfo(
  750. pIPinOutput,
  751. (BYTE)m_Settings.dwPayloadType,
  752. *m_pRPHInputMinorType
  753. )))
  754. {
  755. LOG((MSP_ERROR, "set demux output pin type info, %x", hr));
  756. return hr;
  757. }
  758. LOG((MSP_INFO, "set demux output pin payload type to %d",
  759. m_Settings.dwPayloadType));
  760. // Set the default timeout on this output pin.
  761. if (FAILED(hr = m_pIRTPDemux->SetPinSourceTimeout(
  762. pIPinOutput,
  763. g_dwVideoPinTimeOut
  764. )))
  765. {
  766. LOG((MSP_ERROR, "set demux output pin type info, %x", hr));
  767. return hr;
  768. }
  769. LOG((MSP_INFO, "set demux output pin timeout to %dms", g_dwVideoPinTimeOut));
  770. // Create and add the payload handler into the filtergraph.
  771. CComPtr<IBaseFilter> pIRPHFilter;
  772. if (FAILED(hr = ::AddFilter(
  773. m_pIGraphBuilder,
  774. *m_pClsidPHFilter,
  775. L"RPH",
  776. &pIRPHFilter
  777. )))
  778. {
  779. LOG((MSP_ERROR, "add RPH filter. %x", hr));
  780. return hr;
  781. }
  782. // Get the IRPHH26XSettings interface used in configuring the RPH
  783. // filter to the right image size.
  784. CComQIPtr<IRPHH26XSettings,
  785. &IID_IRPHH26XSettings> pIRPHH26XSettings(pIRPHFilter);
  786. if (pIRPHH26XSettings == NULL)
  787. {
  788. LOG((MSP_WARN, "can't get IRPHH26XSettings interface"));
  789. }
  790. else if (FAILED(pIRPHH26XSettings->SetCIF(m_Settings.fCIF)))
  791. {
  792. LOG((MSP_WARN, "can't set CIF or QCIF"));
  793. }
  794. // Connect the payload handler to the output pin on the demux.
  795. if (FAILED(hr = ::ConnectFilters(
  796. m_pIGraphBuilder,
  797. (IPin *)pIPinOutput,
  798. (IBaseFilter *)pIRPHFilter
  799. )))
  800. {
  801. LOG((MSP_ERROR, "connect demux and RPH filter. %x", hr));
  802. m_pIGraphBuilder->RemoveFilter(pIRPHFilter);
  803. return hr;
  804. }
  805. CComPtr<IBaseFilter> pCodecFilter;
  806. if (FAILED(hr = ::AddFilter(
  807. m_pIGraphBuilder,
  808. *m_pClsidCodecFilter,
  809. L"codec",
  810. &pCodecFilter
  811. )))
  812. {
  813. LOG((MSP_ERROR, "add Codec filter. %x", hr));
  814. return hr;
  815. }
  816. // Connect the payload handler to the output pin on the demux.
  817. if (FAILED(hr = ::ConnectFilters(
  818. m_pIGraphBuilder,
  819. (IBaseFilter *)pIRPHFilter,
  820. (IBaseFilter *)pCodecFilter
  821. )))
  822. {
  823. LOG((MSP_ERROR, "connect RPH filter and codec. %x", hr));
  824. m_pIGraphBuilder->RemoveFilter(pIRPHFilter);
  825. m_pIGraphBuilder->RemoveFilter(pCodecFilter);
  826. return hr;
  827. }
  828. pBranch->pIPin = pIPinOutput;
  829. pBranch->pRPHFilter = pIRPHFilter;
  830. pBranch->pCodecFilter = pCodecFilter;
  831. pBranch->pIPin->AddRef();
  832. pBranch->pRPHFilter->AddRef();
  833. pBranch->pCodecFilter->AddRef();
  834. LOG((MSP_TRACE, "AddOneBranch exits ok."));
  835. return S_OK;
  836. }
  837. HRESULT CStreamVideoRecv::RemoveOneBranch(
  838. BRANCH * pBranch
  839. )
  840. /*++
  841. Routine Description:
  842. Remove all the filters in a branch and release all the pointers.
  843. the caller of this function should not use any member of this branch
  844. after this function call.
  845. Arguments:
  846. pBranch - a pointer to a structure that has the info about the branch.
  847. Return Value:
  848. HRESULT.
  849. --*/
  850. {
  851. LOG((MSP_TRACE, "RemoveOneBranch entered."));
  852. if (pBranch->pIPin)
  853. {
  854. pBranch->pIPin->Release();
  855. }
  856. if (pBranch->pRPHFilter)
  857. {
  858. m_pIGraphBuilder->RemoveFilter(pBranch->pRPHFilter);
  859. pBranch->pRPHFilter->Release();
  860. }
  861. if (pBranch->pCodecFilter)
  862. {
  863. m_pIGraphBuilder->RemoveFilter(pBranch->pCodecFilter);
  864. pBranch->pCodecFilter->Release();
  865. }
  866. if (pBranch->pITTerminal)
  867. {
  868. // get the terminal control interface.
  869. CComQIPtr<ITTerminalControl, &IID_ITTerminalControl>
  870. pTerminal(pBranch->pITTerminal);
  871. _ASSERTE(pTerminal != NULL);
  872. if (pTerminal != NULL)
  873. {
  874. HRESULT hr = pTerminal->DisconnectTerminal(m_pIGraphBuilder, 0);
  875. LOG((MSP_TRACE,
  876. "terminal %p is disonnected. hr:%x", pBranch->pITTerminal, hr));
  877. }
  878. pBranch->pITTerminal->Release();
  879. }
  880. if (pBranch->pITSubStream)
  881. {
  882. ((CSubStreamVideoRecv*)pBranch->pITSubStream)->
  883. ClearCurrentTerminal();
  884. pBranch->pITSubStream->Release();
  885. }
  886. LOG((MSP_TRACE, "RemoveOneBranch exits ok."));
  887. return S_OK;
  888. }
  889. HRESULT CStreamVideoRecv::ConnectCodecToTerminal(
  890. IN IBaseFilter * pCodecFilter,
  891. IN ITTerminal * pITTerminal
  892. )
  893. /*++
  894. Routine Description:
  895. Connect the codec filter to the render filter inside the terminal.
  896. Arguments:
  897. pCodecFilter - a pointer to the Codec filter.
  898. pITTerminal - the terminal object.
  899. Return Value:
  900. HRESULT.
  901. --*/
  902. {
  903. // get the terminal control interface.
  904. CComQIPtr<ITTerminalControl, &IID_ITTerminalControl>
  905. pTerminal(pITTerminal);
  906. if (pTerminal == NULL)
  907. {
  908. LOG((MSP_ERROR, "can't get Terminal Control interface"));
  909. SendStreamEvent(CALL_TERMINAL_FAIL,
  910. CALL_CAUSE_BAD_DEVICE, E_NOINTERFACE, pITTerminal);
  911. return E_NOINTERFACE;
  912. }
  913. // try to disable DDraw because our decoders can't handle DDraw.
  914. HRESULT hr2;
  915. IDrawVideoImage *pIDrawVideoImage;
  916. hr2 = pTerminal->QueryInterface(IID_IDrawVideoImage, (void **)&pIDrawVideoImage);
  917. if (SUCCEEDED(hr2))
  918. {
  919. hr2 = pIDrawVideoImage->DrawVideoImageBegin();
  920. if (FAILED(hr2))
  921. {
  922. LOG((MSP_WARN, "Can't disable DDraw. %x", hr2));
  923. }
  924. else
  925. {
  926. LOG((MSP_INFO, "DDraw disabled."));
  927. }
  928. pIDrawVideoImage->Release();
  929. }
  930. else
  931. {
  932. LOG((MSP_WARN, "Can't get IDrawVideoImage. %x", hr2));
  933. }
  934. const DWORD MAXPINS = 8;
  935. DWORD dwNumPins = MAXPINS;
  936. IPin * Pins[MAXPINS];
  937. HRESULT hr = pTerminal->ConnectTerminal(m_pIGraphBuilder, 0, &dwNumPins, Pins);
  938. if (FAILED(hr))
  939. {
  940. LOG((MSP_ERROR, "can't connect to terminal, %x", hr));
  941. SendStreamEvent(CALL_TERMINAL_FAIL,
  942. CALL_CAUSE_CONNECT_FAIL, hr, pITTerminal);
  943. return hr;
  944. }
  945. // the number of pins should never be 0.
  946. if (dwNumPins == 0)
  947. {
  948. LOG((MSP_ERROR, "terminal has no pins."));
  949. SendStreamEvent(CALL_TERMINAL_FAIL,
  950. CALL_CAUSE_BAD_DEVICE, hr, pITTerminal);
  951. pTerminal->DisconnectTerminal(m_pIGraphBuilder, 0);
  952. m_lock.Unlock();
  953. return E_UNEXPECTED;
  954. }
  955. // Connect the codec filter to the video render terminal.
  956. hr = ::ConnectFilters(
  957. m_pIGraphBuilder,
  958. (IBaseFilter *)pCodecFilter,
  959. (IPin *)Pins[0],
  960. FALSE // use Connect instead of ConnectDirect.
  961. );
  962. // release the refcounts on the pins.
  963. for (DWORD i = 0; i < dwNumPins; i ++)
  964. {
  965. Pins[i]->Release();
  966. }
  967. if (FAILED(hr))
  968. {
  969. LOG((MSP_ERROR, "connect to the codec filter. %x", hr));
  970. pTerminal->DisconnectTerminal(m_pIGraphBuilder, 0);
  971. return hr;
  972. }
  973. //
  974. // Now we are actually connected. Update our state and perform postconnection
  975. // (ignore postconnection error code).
  976. //
  977. pTerminal->CompleteConnectTerminal();
  978. return hr;
  979. }
  980. HRESULT CStreamVideoRecv::ConnectTerminal(
  981. IN ITTerminal * pITTerminal
  982. )
  983. /*++
  984. Routine Description:
  985. connect video render terminal.
  986. Arguments:
  987. pITTerminal - The terminal to be connected.
  988. Return Value:
  989. HRESULT.
  990. --*/
  991. {
  992. LOG((MSP_TRACE, "VideoRecv.ConnectTerminal, pTerminal %p", pITTerminal));
  993. HRESULT hr;
  994. // if our filters have not been contructed, do it now.
  995. if (m_pEdgeFilter == NULL)
  996. {
  997. hr = SetUpInternalFilters();
  998. if (FAILED(hr))
  999. {
  1000. LOG((MSP_ERROR, "Set up internal filter failed, %x", hr));
  1001. CleanUpFilters();
  1002. return hr;
  1003. }
  1004. }
  1005. // first create the RPH and CODEC filter needed before the terminal.
  1006. BRANCH aBranch;
  1007. ZeroMemory(&aBranch, sizeof BRANCH);
  1008. hr = AddOneBranch(&aBranch);
  1009. if (FAILED(hr))
  1010. {
  1011. LOG((MSP_ERROR, "Set up a new decode branch failed, %x", hr));
  1012. return hr;
  1013. }
  1014. // finish the connection.
  1015. hr = ConnectCodecToTerminal(aBranch.pCodecFilter, pITTerminal);
  1016. if (FAILED(hr))
  1017. {
  1018. LOG((MSP_ERROR, "connecting codec to terminal failed, %x", hr));
  1019. // remove the added filters from the graph.
  1020. RemoveOneBranch(&aBranch);
  1021. return hr;
  1022. }
  1023. pITTerminal->AddRef();
  1024. aBranch.pITTerminal = pITTerminal;
  1025. if (!m_Branches.Add(aBranch))
  1026. {
  1027. RemoveOneBranch(&aBranch);
  1028. return E_OUTOFMEMORY;
  1029. }
  1030. return S_OK;
  1031. }
  1032. HRESULT CStreamVideoRecv::DisconnectTerminal(
  1033. IN ITTerminal * pITTerminal
  1034. )
  1035. /*++
  1036. Routine Description:
  1037. Disconnect a terminal. It will remove its filters from the graph and
  1038. also release its references to the graph. A branch of filters is also
  1039. released.
  1040. Arguments:
  1041. pITTerminal - the terminal.
  1042. Return Value:
  1043. HRESULT.
  1044. --*/
  1045. {
  1046. for (int i = 0; i < m_Branches.GetSize(); i ++)
  1047. {
  1048. if (m_Branches[i].pITTerminal == pITTerminal)
  1049. {
  1050. break;
  1051. }
  1052. }
  1053. if (i < m_Branches.GetSize())
  1054. {
  1055. RemoveOneBranch(&m_Branches[i]);
  1056. m_Branches.RemoveAt(i);
  1057. }
  1058. return S_OK;
  1059. }
  1060. HRESULT CStreamVideoRecv::SetUpFilters()
  1061. /*++
  1062. Routine Description:
  1063. Insert filters into the graph and connect to the terminals.
  1064. Arguments:
  1065. Return Value:
  1066. HRESULT.
  1067. --*/
  1068. {
  1069. LOG((MSP_TRACE, "VideoRecv.SetUpFilters"));
  1070. // if our filters have not been contructed, do it now.
  1071. if (m_pEdgeFilter == NULL)
  1072. {
  1073. HRESULT hr = SetUpInternalFilters();
  1074. if (FAILED(hr))
  1075. {
  1076. LOG((MSP_ERROR, "Set up internal filter failed, %x", hr));
  1077. CleanUpFilters();
  1078. return hr;
  1079. }
  1080. }
  1081. for (int i = 0; i < m_Terminals.GetSize(); i ++)
  1082. {
  1083. HRESULT hr = ConnectTerminal(m_Terminals[i]);
  1084. if (FAILED(hr))
  1085. {
  1086. return hr;
  1087. }
  1088. }
  1089. return S_OK;
  1090. }
  1091. // ITParticipantSubStreamControl methods, called by the app.
  1092. STDMETHODIMP CStreamVideoRecv::get_SubStreamFromParticipant(
  1093. IN ITParticipant * pITParticipant,
  1094. OUT ITSubStream ** ppITSubStream
  1095. )
  1096. /*++
  1097. Routine Description:
  1098. Find out which substream is rendering the participant.
  1099. Arguments:
  1100. pITParticipant - the participant.
  1101. ppITSubStream - the returned sub stream.
  1102. Return Value:
  1103. S_OK,
  1104. TAPI_E_NOITEMS,
  1105. E_UNEXPECTED
  1106. --*/
  1107. {
  1108. LOG((MSP_TRACE, "get substream from participant:%p", pITParticipant));
  1109. if (IsBadWritePtr(ppITSubStream, sizeof(VOID *)))
  1110. {
  1111. LOG((MSP_ERROR, "ppITSubStream is a bad pointer"));
  1112. return E_POINTER;
  1113. }
  1114. CLock lock(m_lock);
  1115. ITSubStream * pITSubStream = NULL;
  1116. // find out which substream has the participant.
  1117. for (int i = 0; i < m_SubStreams.GetSize(); i ++)
  1118. {
  1119. ITParticipant *pTempParticipant;
  1120. DWORD dwSSRC;
  1121. ((CSubStreamVideoRecv*)m_SubStreams[i])->GetCurrentParticipant(
  1122. &dwSSRC, &pTempParticipant
  1123. );
  1124. _ASSERTE(pTempParticipant != NULL);
  1125. pTempParticipant->Release(); // we dont' need the ref here.
  1126. if (pITParticipant == pTempParticipant)
  1127. {
  1128. pITSubStream = m_SubStreams[i];
  1129. pITSubStream->AddRef();
  1130. break;
  1131. }
  1132. }
  1133. if (pITSubStream == NULL)
  1134. {
  1135. return TAPI_E_NOITEMS;
  1136. }
  1137. *ppITSubStream = pITSubStream;
  1138. return S_OK;
  1139. }
  1140. STDMETHODIMP CStreamVideoRecv::get_ParticipantFromSubStream(
  1141. IN ITSubStream * pITSubStream,
  1142. OUT ITParticipant ** ppITParticipant
  1143. )
  1144. /*++
  1145. Routine Description:
  1146. Find out which participant the substream is rendering.
  1147. Arguments:
  1148. pITSubStream - the sub stream.
  1149. ppITParticipant - the returned participant
  1150. Return Value:
  1151. S_OK,
  1152. TAPI_E_NOITEMS,
  1153. E_UNEXPECTED
  1154. --*/
  1155. {
  1156. LOG((MSP_TRACE, "get participant from substream:%p", pITSubStream));
  1157. if (IsBadWritePtr(ppITParticipant, sizeof(VOID *)))
  1158. {
  1159. LOG((MSP_ERROR, "ppITParticipant is a bad pointer"));
  1160. return E_POINTER;
  1161. }
  1162. CLock lock(m_lock);
  1163. int i;
  1164. // check to see if the substream is in our list.
  1165. if ((i = m_SubStreams.Find(pITSubStream)) < 0)
  1166. {
  1167. LOG((MSP_ERROR, "wrong SubStream handle %p", pITSubStream));
  1168. return E_INVALIDARG;
  1169. }
  1170. ITParticipant *pITParticipant;
  1171. DWORD dwSSRC;
  1172. if (((CSubStreamVideoRecv*)m_SubStreams[i])->GetCurrentParticipant(
  1173. &dwSSRC, &pITParticipant
  1174. ) == FALSE)
  1175. {
  1176. return TAPI_E_NOITEMS;
  1177. }
  1178. *ppITParticipant = pITParticipant;
  1179. return S_OK;
  1180. }
  1181. STDMETHODIMP CStreamVideoRecv::SwitchTerminalToSubStream(
  1182. IN ITTerminal * pITTerminal,
  1183. IN ITSubStream * pITSubStream
  1184. )
  1185. /*++
  1186. Routine Description:
  1187. Switch terminal to a substream to display the participant that is on the
  1188. substream.
  1189. Arguments:
  1190. pITTerminal - the terminal.
  1191. pITSubStream - the sub stream.
  1192. Return Value:
  1193. S_OK,
  1194. E_INVALIDARG,
  1195. E_UNEXPECTED
  1196. --*/
  1197. {
  1198. LOG((MSP_TRACE, "switch terminal %p to substream:%p",
  1199. pITTerminal, pITSubStream));
  1200. CLock lock(m_lock);
  1201. if (m_pIRTPDemux == NULL)
  1202. {
  1203. LOG((MSP_ERROR, "the demux filter doesn't exist."));
  1204. return E_UNEXPECTED;
  1205. }
  1206. // first, find out which branch has the terminal now.
  1207. for (int i = 0; i < m_Branches.GetSize(); i ++)
  1208. {
  1209. if (m_Branches[i].pITTerminal == pITTerminal)
  1210. {
  1211. break;
  1212. }
  1213. }
  1214. if (i >= m_Branches.GetSize())
  1215. {
  1216. LOG((MSP_TRACE, "terminal %p doesn't exist", pITTerminal));
  1217. return E_INVALIDARG;
  1218. }
  1219. // second, find out if the substream exists.
  1220. if (m_SubStreams.Find(pITSubStream) < 0)
  1221. {
  1222. LOG((MSP_TRACE, "SubStream %p doesn't exist", pITSubStream));
  1223. return E_INVALIDARG;
  1224. }
  1225. // thrid, find the participant on the substream and configure the demux
  1226. // filter to render the participant on the chosen branch.
  1227. ITParticipant *pITParticipant = NULL;
  1228. DWORD dwSSRC;
  1229. ((CSubStreamVideoRecv*)pITSubStream)->GetCurrentParticipant(
  1230. &dwSSRC, &pITParticipant
  1231. ) ;
  1232. _ASSERTE(pITParticipant != NULL);
  1233. // we don't need the reference here.
  1234. pITParticipant->Release();
  1235. // map the pin to this SSRC only.
  1236. HRESULT hr = m_pIRTPDemux->MapSSRCToPin(dwSSRC, m_Branches[i].pIPin);
  1237. if (FAILED(hr))
  1238. {
  1239. LOG((MSP_ERROR, "map SSRC %x to pin %p returned %x",
  1240. dwSSRC, m_Branches[i].pIPin, hr));
  1241. return hr;
  1242. }
  1243. DWORD dwOldSSRC = 0;
  1244. // Finally, set up the mappings among the branch, the substream and
  1245. // the terminal
  1246. // release the refcount on the old branch that the substream was on.
  1247. for (int j = 0; j < m_Branches.GetSize(); j ++)
  1248. {
  1249. if (m_Branches[j].pITSubStream == pITSubStream)
  1250. {
  1251. m_Branches[j].pITSubStream->Release();
  1252. m_Branches[j].pITSubStream = NULL;
  1253. break;
  1254. }
  1255. }
  1256. if (m_Branches[i].pITSubStream != NULL)
  1257. {
  1258. ((CSubStreamVideoRecv*)m_Branches[i].pITSubStream)->
  1259. ClearCurrentTerminal();
  1260. m_Branches[i].pITSubStream->Release();
  1261. dwOldSSRC = m_Branches[i].dwSSRC;
  1262. }
  1263. pITSubStream->AddRef();
  1264. m_Branches[i].pITSubStream = pITSubStream;
  1265. m_Branches[i].dwSSRC = dwSSRC;
  1266. ((CSubStreamVideoRecv*)pITSubStream)->ClearCurrentTerminal();
  1267. ((CSubStreamVideoRecv*)pITSubStream)->SetCurrentTerminal(
  1268. m_Branches[i].pITTerminal
  1269. );
  1270. // After all the steps, we still have to change QOS reservation.
  1271. if (dwOldSSRC != 0)
  1272. {
  1273. // cancel QOS for the old participant.
  1274. if (FAILED(hr = m_pRTPFilter->SetParticipantQOSstate(dwOldSSRC, 0)))
  1275. {
  1276. LOG((MSP_ERROR, "disabling QOS for %x. hr:%x", dwOldSSRC, hr));
  1277. }
  1278. else
  1279. {
  1280. LOG((MSP_INFO, "disabled video QOS for %x.", dwOldSSRC));
  1281. }
  1282. }
  1283. // reserve QOS for the new participant.
  1284. if (FAILED(hr = m_pRTPFilter->SetParticipantQOSstate(dwSSRC, 1)))
  1285. {
  1286. LOG((MSP_ERROR, "enabling video QOS for %x. hr:%x", dwSSRC, hr));
  1287. }
  1288. else
  1289. {
  1290. LOG((MSP_INFO, "enabled video QOS for %x.", dwSSRC));
  1291. }
  1292. return S_OK;
  1293. }
  1294. HRESULT CStreamVideoRecv::ProcessNewSender(
  1295. IN DWORD dwSSRC,
  1296. IN ITParticipant *pITParticipant
  1297. )
  1298. /*++
  1299. Routine Description:
  1300. A sender has just joined. A substream needs to be created for the
  1301. participant.
  1302. A pin mapped event might have happended when we didn't have the
  1303. participant's name so it was queued in a list. Now that we have a new
  1304. participant, let's check if this is the same participant. If it is,
  1305. we complete the pin mapped event by sending the app an notification.
  1306. Arguments:
  1307. dwSSRC - the SSRC of the participant.
  1308. pITParticipant - the participant object.
  1309. Return Value:
  1310. S_OK,
  1311. E_UNEXPECTED
  1312. --*/
  1313. {
  1314. CLock lock(m_lock);
  1315. if (m_pRTPFilter == NULL)
  1316. {
  1317. LOG((MSP_ERROR, "the network filter doesn't exist."));
  1318. return E_UNEXPECTED;
  1319. }
  1320. // Find out if a substream has been created for this participant when we
  1321. // processed PinMapped event and receiver reports.
  1322. for (int i = 0; i < m_SubStreams.GetSize(); i ++)
  1323. {
  1324. ITParticipant *pTempParticipant = NULL;
  1325. DWORD dwSSRC;
  1326. ((CSubStreamVideoRecv*)m_SubStreams[i])->GetCurrentParticipant(
  1327. &dwSSRC, &pTempParticipant
  1328. );
  1329. _ASSERTE(pTempParticipant != NULL);
  1330. pTempParticipant->Release(); // we dont' need the ref here.
  1331. if (pITParticipant == pTempParticipant)
  1332. {
  1333. // the participant has been created.
  1334. return S_OK;
  1335. }
  1336. }
  1337. ITSubStream * pITSubStream;
  1338. HRESULT hr = InternalCreateSubStream(&pITSubStream);
  1339. if (FAILED(hr))
  1340. {
  1341. LOG((MSP_ERROR, "%ls can't create a SubStream, %x", m_szName, hr));
  1342. return hr;
  1343. }
  1344. ((CSubStreamVideoRecv*)pITSubStream)->SetCurrentParticipant(
  1345. dwSSRC, pITParticipant
  1346. );
  1347. ((CIPConfMSPCall *)m_pMSPCall)->SendParticipantEvent(
  1348. PE_NEW_SUBSTREAM,
  1349. pITParticipant,
  1350. pITSubStream
  1351. );
  1352. // look at the pending SSRC list and find out if this report
  1353. // fits in the list.
  1354. IPin *pIPin = NULL;
  1355. for (i = 0; i < m_PinMappedEvents.GetSize(); i ++)
  1356. {
  1357. if (m_PinMappedEvents[i].dwSSRC == dwSSRC)
  1358. {
  1359. pIPin = m_PinMappedEvents[i].pIPin;
  1360. break;
  1361. }
  1362. }
  1363. if (!pIPin)
  1364. {
  1365. // the SSRC is not in the list of pending PinMappedEvents.
  1366. LOG((MSP_TRACE, "the SSRC %x is not in the pending list", dwSSRC));
  1367. pITSubStream->Release();
  1368. return S_OK;;
  1369. }
  1370. // get rid of the peding event.
  1371. m_PinMappedEvents.RemoveAt(i);
  1372. // reserve QOS since we are rendering this sender.
  1373. if (FAILED(hr = m_pRTPFilter->SetParticipantQOSstate(dwSSRC, 1)))
  1374. {
  1375. LOG((MSP_ERROR, "enabling video QOS for %x. hr:%x", dwSSRC, hr));
  1376. }
  1377. else
  1378. {
  1379. LOG((MSP_INFO, "enabled video QOS for %x.", dwSSRC));
  1380. }
  1381. // tell the app about the newly mapped sender.
  1382. for (i = 0; i < m_Branches.GetSize(); i ++)
  1383. {
  1384. if (m_Branches[i].pIPin == pIPin)
  1385. {
  1386. if (m_Branches[i].pITSubStream != NULL)
  1387. {
  1388. ((CSubStreamVideoRecv*)m_Branches[i].pITSubStream)
  1389. ->ClearCurrentTerminal();
  1390. m_Branches[i].pITSubStream->Release();
  1391. }
  1392. m_Branches[i].dwSSRC = dwSSRC;
  1393. m_Branches[i].pITSubStream = pITSubStream;
  1394. pITSubStream->AddRef();
  1395. ((CSubStreamVideoRecv*)pITSubStream)->
  1396. SetCurrentTerminal(m_Branches[i].pITTerminal);
  1397. ((CIPConfMSPCall *)m_pMSPCall)->SendParticipantEvent(
  1398. PE_SUBSTREAM_MAPPED,
  1399. pITParticipant,
  1400. pITSubStream
  1401. );
  1402. break;
  1403. }
  1404. }
  1405. pITSubStream->Release();
  1406. return S_OK;
  1407. }
  1408. HRESULT CStreamVideoRecv::NewParticipantPostProcess(
  1409. IN DWORD dwSSRC,
  1410. IN ITParticipant *pITParticipant
  1411. )
  1412. /*++
  1413. Routine Description:
  1414. A pin mapped event might have happended when we didn't have the
  1415. participant's name so it was queued in a list. Now that we have a new
  1416. participant, let's check if this is the same participant. If it is,
  1417. we complete the pin mapped event by creating a substream and send
  1418. the app a notification.
  1419. Arguments:
  1420. dwSSRC - the SSRC of the participant.
  1421. pITParticipant - the participant object.
  1422. Return Value:
  1423. S_OK,
  1424. E_UNEXPECTED
  1425. --*/
  1426. {
  1427. LOG((MSP_TRACE, "%ls Check pending mapped event, dwSSRC: %x", m_szName, dwSSRC));
  1428. // look at the pending SSRC list and find out if this report
  1429. // fits in the list.
  1430. IPin *pIPin = NULL;
  1431. for (int i = 0; i < m_PinMappedEvents.GetSize(); i ++)
  1432. {
  1433. if (m_PinMappedEvents[i].dwSSRC == dwSSRC)
  1434. {
  1435. pIPin = m_PinMappedEvents[i].pIPin;
  1436. break;
  1437. }
  1438. }
  1439. if (!pIPin)
  1440. {
  1441. // the SSRC is not in the list of pending PinMappedEvents.
  1442. LOG((MSP_TRACE, "the SSRC %x is not in the pending list", dwSSRC));
  1443. return S_OK;;
  1444. }
  1445. ITSubStream * pITSubStream;
  1446. HRESULT hr = InternalCreateSubStream(&pITSubStream);
  1447. if (FAILED(hr))
  1448. {
  1449. LOG((MSP_ERROR, "%ls can't create a SubStream, %x", m_szName, hr));
  1450. return hr;
  1451. }
  1452. ((CSubStreamVideoRecv*)pITSubStream)->SetCurrentParticipant(
  1453. dwSSRC, pITParticipant
  1454. );
  1455. ((CIPConfMSPCall *)m_pMSPCall)->SendParticipantEvent(
  1456. PE_NEW_SUBSTREAM,
  1457. pITParticipant,
  1458. pITSubStream
  1459. );
  1460. // get rid of the peding event.
  1461. m_PinMappedEvents.RemoveAt(i);
  1462. if (FAILED(hr = m_pRTPFilter->SetParticipantQOSstate(dwSSRC, 1)))
  1463. {
  1464. LOG((MSP_ERROR, "enabling video QOS for %x. hr:%x", dwSSRC, hr));
  1465. }
  1466. else
  1467. {
  1468. LOG((MSP_INFO, "enabled video QOS for %x.", dwSSRC));
  1469. }
  1470. // Now we get the participant, the substream, and the pin. Establish a mapping
  1471. // between the decoding branch and the substream.
  1472. for (i = 0; i < m_Branches.GetSize(); i ++)
  1473. {
  1474. if (m_Branches[i].pIPin == pIPin)
  1475. {
  1476. if (m_Branches[i].pITSubStream != NULL)
  1477. {
  1478. ((CSubStreamVideoRecv*)m_Branches[i].pITSubStream)
  1479. ->ClearCurrentTerminal();
  1480. m_Branches[i].pITSubStream->Release();
  1481. }
  1482. m_Branches[i].dwSSRC = dwSSRC;
  1483. m_Branches[i].pITSubStream = pITSubStream;
  1484. pITSubStream->AddRef();
  1485. ((CSubStreamVideoRecv*)pITSubStream)->
  1486. SetCurrentTerminal(m_Branches[i].pITTerminal);
  1487. ((CIPConfMSPCall *)m_pMSPCall)->SendParticipantEvent(
  1488. PE_SUBSTREAM_MAPPED,
  1489. pITParticipant,
  1490. pITSubStream
  1491. );
  1492. break;
  1493. }
  1494. }
  1495. _ASSERTE(i < m_Branches.GetSize());
  1496. pITSubStream->Release();
  1497. return S_OK;
  1498. }
  1499. HRESULT CStreamVideoRecv::ProcessPinMappedEvent(
  1500. IN IPin * pIPin
  1501. )
  1502. /*++
  1503. Routine Description:
  1504. A pin just got a new SSRC mapped to it. If the participant doesn't exist,
  1505. put the event in a pending queue and wait for a RTCP report that has the
  1506. participant's name. If the participant exists, check to see if a SubStream
  1507. has been created for the stream. If not, a SubStream is created. Then a
  1508. Particiapnt substream event is fired.
  1509. Arguments:
  1510. pIPin - the output pin of the demux filter that just got a new SSRC.
  1511. Return Value:
  1512. S_OK,
  1513. E_UNEXPECTED
  1514. --*/
  1515. {
  1516. LOG((MSP_TRACE, "%ls Process pin mapped event, pIPin: %p", m_szName, pIPin));
  1517. CLock lock(m_lock);
  1518. if (m_pIRTPDemux == NULL)
  1519. {
  1520. LOG((MSP_ERROR, "the demux filter doesn't exist."));
  1521. return E_UNEXPECTED;
  1522. }
  1523. for (int iBranch = 0; iBranch < m_Branches.GetSize(); iBranch ++)
  1524. {
  1525. if (m_Branches[iBranch].pIPin == pIPin)
  1526. {
  1527. break;
  1528. }
  1529. }
  1530. LOG((MSP_INFO, "Branch %d has the pin", iBranch));
  1531. if (iBranch >= m_Branches.GetSize())
  1532. {
  1533. LOG((MSP_ERROR, "Wrong pin is mapped. %p", pIPin));
  1534. return E_UNEXPECTED;
  1535. }
  1536. BYTE PayloadType;
  1537. DWORD dwSSRC;
  1538. BOOL fAutoMapping;
  1539. DWORD dwTimeOut;
  1540. HRESULT hr = m_pIRTPDemux->GetPinInfo(
  1541. pIPin,
  1542. &dwSSRC,
  1543. &PayloadType,
  1544. &fAutoMapping,
  1545. &dwTimeOut
  1546. );
  1547. if (FAILED(hr))
  1548. {
  1549. LOG((MSP_ERROR, "can't get info for pin:%p, hr:%x", pIPin, hr));
  1550. return E_UNEXPECTED;
  1551. }
  1552. // sometimes we might get a mapped event for branches that are still
  1553. // in use.
  1554. if (m_Branches[iBranch].pITSubStream != NULL)
  1555. {
  1556. // sometimes we might get duplicated map events
  1557. if (m_Branches[iBranch].dwSSRC == dwSSRC)
  1558. {
  1559. LOG((MSP_ERROR, "The same pin mapped twice. %p", pIPin));
  1560. return E_UNEXPECTED;
  1561. }
  1562. else
  1563. {
  1564. LOG((MSP_ERROR, "The branch is in use. Cleaning up."));
  1565. ((CSubStreamVideoRecv*)m_Branches[iBranch].pITSubStream)->
  1566. ClearCurrentTerminal();
  1567. m_Branches[iBranch].pITSubStream->Release();
  1568. m_Branches[iBranch].pITSubStream = NULL;
  1569. m_Branches[iBranch].dwSSRC = 0;
  1570. }
  1571. }
  1572. ITParticipant * pITParticipant = NULL;
  1573. // find the SSRC in our participant list.
  1574. for (int i = 0; i < m_Participants.GetSize(); i ++)
  1575. {
  1576. if (((CParticipant *)m_Participants[i])->
  1577. HasSSRC((ITStream *)this, dwSSRC))
  1578. {
  1579. pITParticipant = m_Participants[i];
  1580. break;
  1581. }
  1582. }
  1583. // if the participant is not there yet, put the event in a queue and it
  1584. // will be fired when we have the CName fo the participant.
  1585. if (!pITParticipant)
  1586. {
  1587. LOG((MSP_INFO, "can't find a participant that has SSRC %x", dwSSRC));
  1588. PINMAPEVENT Event;
  1589. Event.pIPin = pIPin;
  1590. Event.dwSSRC = dwSSRC;
  1591. m_PinMappedEvents.Add(Event);
  1592. LOG((MSP_INFO, "added the event to pending list, new list size:%d",
  1593. m_PinMappedEvents.GetSize()));
  1594. return S_OK;
  1595. }
  1596. // Enable QOS for the participant since it is being rendered.
  1597. if (FAILED(hr = m_pRTPFilter->SetParticipantQOSstate(dwSSRC, 1)))
  1598. {
  1599. LOG((MSP_ERROR, "enabling vidoe QOS for %x. hr:%x", dwSSRC, hr));
  1600. }
  1601. else
  1602. {
  1603. LOG((MSP_INFO, "enabled video QOS for %x.", dwSSRC));
  1604. }
  1605. // Find out if a substream has been created for this participant who might
  1606. // have been a receiver only and hasn't got a substream.
  1607. ITSubStream * pITSubStream = NULL;
  1608. for (i = 0; i < m_SubStreams.GetSize(); i ++)
  1609. {
  1610. ITParticipant *pTempParticipant;
  1611. DWORD dwSSRC;
  1612. ((CSubStreamVideoRecv*)m_SubStreams[i])->GetCurrentParticipant(
  1613. &dwSSRC, &pTempParticipant
  1614. );
  1615. _ASSERTE(pTempParticipant != NULL);
  1616. pTempParticipant->Release(); // we dont' need the ref here.
  1617. if (pITParticipant == pTempParticipant)
  1618. {
  1619. pITSubStream = m_SubStreams[i];
  1620. pITSubStream->AddRef();
  1621. break;
  1622. }
  1623. }
  1624. if (pITSubStream == NULL)
  1625. {
  1626. // we need to create a substream for this participant since he has
  1627. // started sending.
  1628. hr = InternalCreateSubStream(&pITSubStream);
  1629. if (FAILED(hr))
  1630. {
  1631. LOG((MSP_ERROR, "%ls can't create a SubStream, %x", m_szName, hr));
  1632. return hr;
  1633. }
  1634. ((CSubStreamVideoRecv*)pITSubStream)->SetCurrentParticipant(
  1635. dwSSRC, pITParticipant
  1636. );
  1637. ((CIPConfMSPCall *)m_pMSPCall)->SendParticipantEvent(
  1638. PE_NEW_SUBSTREAM,
  1639. pITParticipant,
  1640. pITSubStream
  1641. );
  1642. }
  1643. if (((CSubStreamVideoRecv*)pITSubStream)->ClearCurrentTerminal())
  1644. {
  1645. // The substrem has a terminal before. This is an error.
  1646. LOG((MSP_ERROR, "SubStream %p has already got a terminal", pITSubStream));
  1647. // remove the mapping if the substream was mapped to a branch.
  1648. for (i = 0; i < m_Branches.GetSize(); i ++)
  1649. {
  1650. if (m_Branches[i].pITSubStream == pITSubStream)
  1651. {
  1652. m_Branches[i].pITSubStream->Release();
  1653. m_Branches[i].pITSubStream = NULL;
  1654. m_Branches[i].dwSSRC = 0;
  1655. LOG((MSP_ERROR, "SubStream %p was mapped to branch %d", i));
  1656. break;
  1657. }
  1658. }
  1659. }
  1660. // Now we get the participant, the substream, and the pin. Establish a mapping
  1661. // between the decoding branch and the substream.
  1662. m_Branches[iBranch].dwSSRC = dwSSRC;
  1663. m_Branches[iBranch].pITSubStream = pITSubStream;
  1664. pITSubStream->AddRef();
  1665. ((CSubStreamVideoRecv*)pITSubStream)->
  1666. SetCurrentTerminal(m_Branches[iBranch].pITTerminal);
  1667. ((CIPConfMSPCall *)m_pMSPCall)->SendParticipantEvent(
  1668. PE_SUBSTREAM_MAPPED,
  1669. pITParticipant,
  1670. pITSubStream
  1671. );
  1672. pITSubStream->Release();
  1673. return S_OK;
  1674. }
  1675. HRESULT CStreamVideoRecv::ProcessPinUnmapEvent(
  1676. IN IPin * pIPin
  1677. )
  1678. /*++
  1679. Routine Description:
  1680. A pin just got unmapped by the demux. Notify the app which substream
  1681. is not going to have any data.
  1682. Arguments:
  1683. pIPin - the output pin of the demux filter
  1684. Return Value:
  1685. S_OK,
  1686. E_UNEXPECTED
  1687. --*/
  1688. {
  1689. LOG((MSP_TRACE, "%ls Proces pin unmapped event, pIPin: %p", m_szName, pIPin));
  1690. CLock lock(m_lock);
  1691. if (m_pIRTPDemux == NULL)
  1692. {
  1693. LOG((MSP_ERROR, "the demux filter doesn't exist."));
  1694. return E_UNEXPECTED;
  1695. }
  1696. // look at the pending SSRC list and find out if the pin is in the
  1697. // pending list.
  1698. for (int i = 0; i < m_PinMappedEvents.GetSize(); i ++)
  1699. {
  1700. if (m_PinMappedEvents[i].pIPin == pIPin)
  1701. {
  1702. break;
  1703. }
  1704. }
  1705. // if the pin is in the pending list, just remove it.
  1706. if (i < m_PinMappedEvents.GetSize())
  1707. {
  1708. m_PinMappedEvents.RemoveAt(i);
  1709. return S_OK;
  1710. }
  1711. // find out which substream got unmapped.
  1712. ITSubStream * pITSubStream = NULL;
  1713. for (i = 0; i < m_Branches.GetSize(); i ++)
  1714. {
  1715. if (m_Branches[i].pIPin == pIPin)
  1716. {
  1717. pITSubStream = m_Branches[i].pITSubStream;
  1718. if (pITSubStream)
  1719. {
  1720. // Don't release the ref until the end of this function.
  1721. m_Branches[i].pITSubStream = NULL;
  1722. m_Branches[i].dwSSRC = 0;
  1723. }
  1724. break;
  1725. }
  1726. }
  1727. if (!pITSubStream)
  1728. {
  1729. LOG((MSP_ERROR, "can't find a substream that got unmapped."));
  1730. return TAPI_E_NOITEMS;
  1731. }
  1732. ((CSubStreamVideoRecv*)pITSubStream)->ClearCurrentTerminal();
  1733. ITParticipant *pITParticipant = NULL;
  1734. DWORD dwSSRC;
  1735. ((CSubStreamVideoRecv*)pITSubStream)->GetCurrentParticipant(
  1736. &dwSSRC, &pITParticipant
  1737. ) ;
  1738. _ASSERTE(pITParticipant != NULL);
  1739. if (pITParticipant != NULL)
  1740. {
  1741. // fire an event to tell the app that the substream is not used.
  1742. ((CIPConfMSPCall *)m_pMSPCall)->SendParticipantEvent(
  1743. PE_SUBSTREAM_UNMAPPED,
  1744. pITParticipant,
  1745. pITSubStream
  1746. );
  1747. pITParticipant->Release();
  1748. // cancel QOS for this participant.
  1749. HRESULT hr = m_pRTPFilter->SetParticipantQOSstate(dwSSRC, 0);
  1750. if (FAILED(hr))
  1751. {
  1752. LOG((MSP_ERROR, "disabling QOS for %x. hr:%x", dwSSRC, hr));
  1753. }
  1754. else
  1755. {
  1756. LOG((MSP_INFO, "disabled video QOS for %x.", dwSSRC));
  1757. }
  1758. }
  1759. pITSubStream->Release();
  1760. return S_OK;
  1761. }
  1762. HRESULT CStreamVideoRecv::ProcessParticipantLeave(
  1763. IN DWORD dwSSRC
  1764. )
  1765. /*++
  1766. Routine Description:
  1767. When participant left the session, remove the stream from the participant
  1768. object's list of streams. If all streams are removed, remove the
  1769. participant from the call object's list too.
  1770. Arguments:
  1771. dwSSRC - the SSRC of the participant left.
  1772. Return Value:
  1773. HRESULT.
  1774. --*/
  1775. {
  1776. LOG((MSP_TRACE, "%ls ProcessParticipantLeave, SSRC: %x", m_szName, dwSSRC));
  1777. CLock lock(m_lock);
  1778. if (m_pRTPFilter == NULL)
  1779. {
  1780. LOG((MSP_ERROR, "the network filter doesn't exist."));
  1781. return E_UNEXPECTED;
  1782. }
  1783. CParticipant *pParticipant;
  1784. BOOL fLast = FALSE;
  1785. HRESULT hr = E_FAIL;
  1786. // first try to find the SSRC in our participant list.
  1787. for (int iParticipant = 0;
  1788. iParticipant < m_Participants.GetSize(); iParticipant ++)
  1789. {
  1790. pParticipant = (CParticipant *)m_Participants[iParticipant];
  1791. hr = pParticipant->RemoveStream(
  1792. (ITStream *)this,
  1793. dwSSRC,
  1794. &fLast
  1795. );
  1796. if (SUCCEEDED(hr))
  1797. {
  1798. break;
  1799. }
  1800. }
  1801. // if the participant is not found
  1802. if (FAILED(hr))
  1803. {
  1804. LOG((MSP_ERROR, "%ws, can't find the SSRC %x", m_szName, dwSSRC));
  1805. return hr;
  1806. }
  1807. ITParticipant *pITParticipant = m_Participants[iParticipant];
  1808. // cancel QOS for this participant.
  1809. if (FAILED(hr = m_pRTPFilter->SetParticipantQOSstate(dwSSRC, 0)))
  1810. {
  1811. LOG((MSP_ERROR, "disabling QOS for %x. hr:%x", dwSSRC, hr));
  1812. }
  1813. else
  1814. {
  1815. LOG((MSP_INFO, "disabled video QOS for %x.", dwSSRC));
  1816. }
  1817. // find out which substream is going away.
  1818. ITSubStream * pITSubStream = NULL;
  1819. for (int i = 0; i < m_SubStreams.GetSize(); i ++)
  1820. {
  1821. // Find out the participant on the SubStream.
  1822. ITParticipant *pTempParticipant;
  1823. DWORD dwSSRC;
  1824. ((CSubStreamVideoRecv*)m_SubStreams[i])->GetCurrentParticipant(
  1825. &dwSSRC, &pTempParticipant
  1826. );
  1827. _ASSERTE(pTempParticipant != NULL);
  1828. pTempParticipant->Release(); // we dont' need the ref here.
  1829. if (pTempParticipant == pITParticipant)
  1830. {
  1831. pITSubStream = m_SubStreams[i];
  1832. break;
  1833. }
  1834. }
  1835. if (pITSubStream)
  1836. {
  1837. // remove the mapping if the substream was mapped to a branch.
  1838. for (int i = 0; i < m_Branches.GetSize(); i ++)
  1839. {
  1840. if (m_Branches[i].pITSubStream == pITSubStream)
  1841. {
  1842. m_Branches[i].pITSubStream->Release();
  1843. m_Branches[i].pITSubStream = NULL;
  1844. m_Branches[i].dwSSRC = 0;
  1845. // fire an event to tell the app that the substream is not used.
  1846. ((CIPConfMSPCall *)m_pMSPCall)->SendParticipantEvent(
  1847. PE_SUBSTREAM_UNMAPPED,
  1848. pITParticipant,
  1849. pITSubStream
  1850. );
  1851. break;
  1852. }
  1853. }
  1854. ((CIPConfMSPCall *)m_pMSPCall)->SendParticipantEvent(
  1855. PE_SUBSTREAM_REMOVED,
  1856. pITParticipant,
  1857. pITSubStream
  1858. );
  1859. if (m_SubStreams.Remove(pITSubStream))
  1860. {
  1861. pITSubStream->Release();
  1862. }
  1863. }
  1864. m_Participants.RemoveAt(iParticipant);
  1865. // if this stream is the last stream that the participant is on,
  1866. // tell the call object to remove it from its list.
  1867. if (fLast)
  1868. {
  1869. ((CIPConfMSPCall *)m_pMSPCall)->ParticipantLeft(pITParticipant);
  1870. }
  1871. pITParticipant->Release();
  1872. return S_OK;
  1873. }
  1874. HRESULT CStreamVideoRecv::ProcessGraphEvent(
  1875. IN long lEventCode,
  1876. IN long lParam1,
  1877. IN long lParam2
  1878. )
  1879. {
  1880. LOG((MSP_TRACE, "%ws ProcessGraphEvent %d", m_szName, lEventCode));
  1881. switch (lEventCode)
  1882. {
  1883. // These events are designed to solve the problem of mapping video
  1884. // windows to incoming streams. The app needs to know which window
  1885. // should be painted. Whenever the demux starts using a RPH pin to
  1886. // stream data, it sends a MAPPED event. The first parameter is the
  1887. // input pin on the RPH, the second parameter is the payload type.
  1888. // When the demux stops using a pin, it sends a UNMAPPED event.
  1889. case RTPDMX_EVENTBASE + RTPDEMUX_PIN_MAPPED:
  1890. LOG((MSP_INFO, "handling pin mapped event, Pin%x", lParam1));
  1891. ProcessPinMappedEvent((IPin *)lParam1);
  1892. break;
  1893. case RTPDMX_EVENTBASE + RTPDEMUX_PIN_UNMAPPED:
  1894. LOG((MSP_INFO, "handling pin unmap event, Pin%x", lParam1));
  1895. ProcessPinUnmapEvent((IPin *)lParam1);
  1896. break;
  1897. default:
  1898. return CIPConfMSPStream::ProcessGraphEvent(
  1899. lEventCode, lParam1, lParam2
  1900. );
  1901. }
  1902. return S_OK;
  1903. }
  1904. /////////////////////////////////////////////////////////////////////////////
  1905. //
  1906. // CStreamVideoSend
  1907. //
  1908. /////////////////////////////////////////////////////////////////////////////
  1909. CStreamVideoSend::CStreamVideoSend()
  1910. : CIPConfMSPStream()
  1911. {
  1912. m_szName = L"VideoSend";
  1913. }
  1914. HRESULT CStreamVideoSend::Configure(
  1915. IN STREAMSETTINGS &StreamSettings
  1916. )
  1917. /*++
  1918. Routine Description:
  1919. Configure this stream.
  1920. Arguments:
  1921. StreamSettings - The setting structure got from the SDP blob.
  1922. Return Value:
  1923. HRESULT.
  1924. --*/
  1925. {
  1926. LOG((MSP_TRACE, "VideoSend.Configure"));
  1927. CLock lock(m_lock);
  1928. _ASSERTE(m_fIsConfigured == FALSE);
  1929. switch (StreamSettings.dwPayloadType)
  1930. {
  1931. case PAYLOAD_H261:
  1932. m_pClsidCodecFilter = &CLSID_H261_ENCODE_FILTER;
  1933. m_pRPHInputMinorType = &MEDIASUBTYPE_RTP_Payload_H261;
  1934. m_pClsidPHFilter = &CLSID_INTEL_SPHH26X;
  1935. break;
  1936. case PAYLOAD_H263:
  1937. m_pClsidCodecFilter = &CLSID_H263_ENCODE_FILTER;
  1938. m_pRPHInputMinorType = &MEDIASUBTYPE_RTP_Payload_H263;
  1939. m_pClsidPHFilter = &CLSID_INTEL_SPHH26X;
  1940. break;
  1941. default:
  1942. LOG((MSP_ERROR, "unknow payload type, %x", StreamSettings.dwPayloadType));
  1943. return E_FAIL;
  1944. }
  1945. m_Settings = StreamSettings;
  1946. m_fIsConfigured = TRUE;
  1947. if (!GetRegValue(L"FrameRate", &m_dwFrameRate))
  1948. {
  1949. m_dwFrameRate = g_dwVideoSampleRate;
  1950. }
  1951. return InternalConfigure();
  1952. }
  1953. HRESULT
  1954. SetVideoFormat(
  1955. IN IUnknown * pIUnknown,
  1956. IN BOOL bCIF,
  1957. IN DWORD dwFramesPerSecond
  1958. )
  1959. /*++
  1960. Routine Description:
  1961. Set the video format to be CIF or QCIF and also set the frames per second.
  1962. Arguments:
  1963. pIUnknown - a capture terminal.
  1964. bCIF - CIF or QCIF.
  1965. dwFramesPerSecond - Frames per second.
  1966. Return Value:
  1967. HRESULT
  1968. --*/
  1969. {
  1970. LOG((MSP_TRACE, "SetVideoFormat"));
  1971. HRESULT hr;
  1972. // first get eht IAMStreamConfig interface.
  1973. CComPtr<IAMStreamConfig> pIAMStreamConfig;
  1974. if (FAILED(hr = pIUnknown->QueryInterface(
  1975. IID_IAMStreamConfig,
  1976. (void **)&pIAMStreamConfig
  1977. )))
  1978. {
  1979. LOG((MSP_ERROR, "Can't get IAMStreamConfig interface.%8x", hr));
  1980. return hr;
  1981. }
  1982. // get the current format of the video capture terminal.
  1983. AM_MEDIA_TYPE *pmt;
  1984. if (FAILED(hr = pIAMStreamConfig->GetFormat(&pmt)))
  1985. {
  1986. LOG((MSP_ERROR, "GetFormat returns error: %8x", hr));
  1987. return hr;
  1988. }
  1989. VIDEOINFO *pVideoInfo = (VIDEOINFO *)pmt->pbFormat;
  1990. if (pVideoInfo == NULL)
  1991. {
  1992. MSPDeleteMediaType(pmt);
  1993. return E_UNEXPECTED;
  1994. }
  1995. BITMAPINFOHEADER *pHeader = HEADER(pmt->pbFormat);
  1996. if (pHeader == NULL)
  1997. {
  1998. MSPDeleteMediaType(pmt);
  1999. return E_UNEXPECTED;
  2000. }
  2001. LOG((MSP_INFO,
  2002. "Video capture: Format BitRate: %d, TimePerFrame: %d",
  2003. pVideoInfo->dwBitRate,
  2004. pVideoInfo->AvgTimePerFrame));
  2005. LOG((MSP_INFO, "Video capture: Format Compression:%c%c%c%c %dbit %dx%d",
  2006. (DWORD)pHeader->biCompression & 0xff,
  2007. ((DWORD)pHeader->biCompression >> 8) & 0xff,
  2008. ((DWORD)pHeader->biCompression >> 16) & 0xff,
  2009. ((DWORD)pHeader->biCompression >> 24) & 0xff,
  2010. pHeader->biBitCount,
  2011. pHeader->biWidth,
  2012. pHeader->biHeight));
  2013. // The time is in 100ns unit.
  2014. pVideoInfo->AvgTimePerFrame = (DWORD) 1e7 / dwFramesPerSecond;
  2015. if (bCIF)
  2016. {
  2017. pHeader->biWidth = CIFWIDTH;
  2018. pHeader->biHeight = CIFHEIGHT;
  2019. }
  2020. else
  2021. {
  2022. pHeader->biWidth = QCIFWIDTH;
  2023. pHeader->biHeight = QCIFHEIGHT;
  2024. }
  2025. #if defined(ALPHA)
  2026. // update bmiSize with new Width/Height
  2027. pHeader->biSizeImage = DIBSIZE( ((VIDEOINFOHEADER *)pmt->pbFormat)->bmiHeader );
  2028. #endif
  2029. if (FAILED(hr = pIAMStreamConfig->SetFormat(pmt)))
  2030. {
  2031. LOG((MSP_ERROR, "putMediaFormat returns error: %8x", hr));
  2032. }
  2033. else
  2034. {
  2035. LOG((MSP_INFO,
  2036. "Video capture: Format BitRate: %d, TimePerFrame: %d",
  2037. pVideoInfo->dwBitRate,
  2038. pVideoInfo->AvgTimePerFrame));
  2039. LOG((MSP_INFO, "Video capture: Format Compression:%c%c%c%c %dbit %dx%d",
  2040. (DWORD)pHeader->biCompression & 0xff,
  2041. ((DWORD)pHeader->biCompression >> 8) & 0xff,
  2042. ((DWORD)pHeader->biCompression >> 16) & 0xff,
  2043. ((DWORD)pHeader->biCompression >> 24) & 0xff,
  2044. pHeader->biBitCount,
  2045. pHeader->biWidth,
  2046. pHeader->biHeight));
  2047. }
  2048. MSPDeleteMediaType(pmt);
  2049. return hr;
  2050. }
  2051. HRESULT
  2052. SetVideoBufferSize(
  2053. IN IUnknown *pIUnknown
  2054. )
  2055. /*++
  2056. Routine Description:
  2057. Set the video capture terminal's buffersize.
  2058. Arguments:
  2059. pIUnknown - a capture terminal.
  2060. Return Value:
  2061. HRESULT
  2062. --*/
  2063. {
  2064. // The number of capture buffers is four for now.
  2065. #define NUMCAPTUREBUFFER 4
  2066. LOG((MSP_TRACE, "SetVideoBufferSize"));
  2067. HRESULT hr;
  2068. CComPtr<IAMBufferNegotiation> pBN;
  2069. if (FAILED(hr = pIUnknown->QueryInterface(
  2070. IID_IAMBufferNegotiation,
  2071. (void **)&pBN
  2072. )))
  2073. {
  2074. LOG((MSP_ERROR, "Can't get buffer negotiation interface.%8x", hr));
  2075. return hr;
  2076. }
  2077. ALLOCATOR_PROPERTIES prop;
  2078. #if 0 // Get allocator property is not working.
  2079. if (FAILED(hr = pBN->GetAllocatorProperties(&prop)))
  2080. {
  2081. LOG((MSP_ERROR, "GetAllocatorProperties returns error: %8x", hr));
  2082. return hr;
  2083. }
  2084. // Set the number of buffers.
  2085. if (prop.cBuffers > NUMCAPTUREBUFFER)
  2086. {
  2087. prop.cBuffers = NUMCAPTUREBUFFER;
  2088. }
  2089. #endif
  2090. DWORD dwBuffers = NUMCAPTUREBUFFER;
  2091. GetRegValue(gszNumVideoCaptureBuffers, &dwBuffers);
  2092. prop.cBuffers = dwBuffers;
  2093. prop.cbBuffer = -1;
  2094. prop.cbAlign = -1;
  2095. prop.cbPrefix = -1;
  2096. if (FAILED(hr = pBN->SuggestAllocatorProperties(&prop)))
  2097. {
  2098. LOG((MSP_ERROR, "SuggestAllocatorProperties returns error: %8x", hr));
  2099. }
  2100. else
  2101. {
  2102. LOG((MSP_INFO,
  2103. "SetVidedobuffersize"
  2104. " buffers: %d, buffersize: %d, align: %d, Prefix: %d",
  2105. prop.cBuffers,
  2106. prop.cbBuffer,
  2107. prop.cbAlign,
  2108. prop.cbPrefix
  2109. ));
  2110. }
  2111. return hr;
  2112. }
  2113. HRESULT CStreamVideoSend::ConfigureVideoCaptureTerminal(
  2114. IN ITTerminalControl* pTerminal,
  2115. IN WCHAR * szPinName,
  2116. OUT IPin ** ppIPin
  2117. )
  2118. /*++
  2119. Routine Description:
  2120. Given a terminal, find the capture pin and configure it.
  2121. Arguments:
  2122. pTerminal - a capture terminal.
  2123. szPinName - the name of the pin needed.
  2124. ppIPin - the address to store a pointer to a IPin interface.
  2125. Return Value:
  2126. HRESULT
  2127. --*/
  2128. {
  2129. LOG((MSP_TRACE, "ConfigureVideoCaptureTerminal, pTerminal %x", pTerminal));
  2130. // Get the pins from the first terminal because we only use on terminal
  2131. // on this stream.
  2132. const DWORD MAXPINS = 8;
  2133. DWORD dwNumPins = MAXPINS;
  2134. IPin * Pins[MAXPINS];
  2135. HRESULT hr = pTerminal->ConnectTerminal(
  2136. m_pIGraphBuilder, 0, &dwNumPins, Pins
  2137. );
  2138. if (FAILED(hr))
  2139. {
  2140. LOG((MSP_ERROR, "can't connect to terminal, %x", hr));
  2141. return hr;
  2142. }
  2143. if (dwNumPins == 0)
  2144. {
  2145. LOG((MSP_ERROR, "terminal has no pins."));
  2146. return hr;
  2147. }
  2148. CComPtr <IPin> pIPin;
  2149. /*
  2150. // look through the pins to find the right one.
  2151. for (DWORD i = 0; i < dwNumPins; i ++)
  2152. {
  2153. LPWSTR szName;
  2154. hr = Pins[i]->QueryId(&szName);
  2155. if (FAILED(hr))
  2156. {
  2157. continue;
  2158. }
  2159. LOG((MSP_INFO, "Pin name: %ws", szName));
  2160. BOOL fEqual = (lstrcmpiW(szName, szPinName) == 0);
  2161. CoTaskMemFree(szName);
  2162. if (fEqual)
  2163. {
  2164. pIPin = Pins[i];
  2165. break;
  2166. }
  2167. }
  2168. */
  2169. // we only need the first pin
  2170. pIPin = Pins[0];
  2171. // release the refcount because we don't need them.
  2172. for (DWORD i = 0; i < dwNumPins; i ++)
  2173. {
  2174. Pins[i]->Release();
  2175. }
  2176. if (!pIPin)
  2177. {
  2178. LOG((MSP_ERROR, "can't find %ws pin", szPinName));
  2179. return E_UNEXPECTED;
  2180. }
  2181. // set the video format. 7 Frames/Sec. QCIF.
  2182. hr = SetVideoFormat(
  2183. pIPin,
  2184. m_Settings.fCIF,
  2185. m_dwFrameRate
  2186. );
  2187. if (FAILED(hr))
  2188. {
  2189. LOG((MSP_ERROR, "can't set video format, %x", hr));
  2190. return hr;
  2191. }
  2192. // set the video buffer size.
  2193. hr = SetVideoBufferSize(
  2194. pIPin
  2195. );
  2196. if (FAILED(hr))
  2197. {
  2198. LOG((MSP_ERROR, "can't set aduio capture buffer size, %x", hr));
  2199. return hr;
  2200. }
  2201. pIPin->AddRef();
  2202. *ppIPin = pIPin;
  2203. return hr;
  2204. }
  2205. HRESULT CStreamVideoSend::FindPreviewInputPin(
  2206. IN ITTerminalControl* pTerminal,
  2207. OUT IPin ** ppIPin
  2208. )
  2209. /*++
  2210. Routine Description:
  2211. Find the input pin on a preview terminal.
  2212. Arguments:
  2213. pTerminal - a video render terminal.
  2214. ppIPin - the address to store a pointer to a IPin interface.
  2215. Return Value:
  2216. HRESULT
  2217. --*/
  2218. {
  2219. LOG((MSP_TRACE, "VideoSend.FindPreviewInputPin, pTerminal %x", pTerminal));
  2220. // try to disable DDraw because our decoders can't handle DDraw.
  2221. HRESULT hr2;
  2222. IDrawVideoImage *pIDrawVideoImage;
  2223. hr2 = pTerminal->QueryInterface(IID_IDrawVideoImage, (void **)&pIDrawVideoImage);
  2224. if (SUCCEEDED(hr2))
  2225. {
  2226. hr2 = pIDrawVideoImage->DrawVideoImageBegin();
  2227. if (FAILED(hr2))
  2228. {
  2229. LOG((MSP_WARN, "Can't disable DDraw. %x", hr2));
  2230. }
  2231. else
  2232. {
  2233. LOG((MSP_INFO, "DDraw disabled."));
  2234. }
  2235. pIDrawVideoImage->Release();
  2236. }
  2237. else
  2238. {
  2239. LOG((MSP_WARN, "Can't get IDrawVideoImage. %x", hr2));
  2240. }
  2241. // Get the pins from the first terminal because we only use on terminal
  2242. // on this stream.
  2243. const DWORD MAXPINS = 8;
  2244. DWORD dwNumPins = MAXPINS;
  2245. IPin * Pins[MAXPINS];
  2246. HRESULT hr = pTerminal->ConnectTerminal(
  2247. m_pIGraphBuilder, 0, &dwNumPins, Pins
  2248. );
  2249. if (FAILED(hr))
  2250. {
  2251. LOG((MSP_ERROR, "can't connect to terminal, %x", hr));
  2252. return hr;
  2253. }
  2254. if (dwNumPins == 0)
  2255. {
  2256. LOG((MSP_ERROR, "terminal has no pins."));
  2257. return hr;
  2258. }
  2259. // Save the first pin and release the others.
  2260. CComPtr <IPin> pIPin = Pins[0];
  2261. for (DWORD i = 0; i < dwNumPins; i ++)
  2262. {
  2263. Pins[i]->Release();
  2264. }
  2265. pIPin->AddRef();
  2266. *ppIPin = pIPin;
  2267. return hr;
  2268. }
  2269. HRESULT CStreamVideoSend::CheckTerminalTypeAndDirection(
  2270. IN ITTerminal * pTerminal
  2271. )
  2272. /*++
  2273. Routine Description:
  2274. Check if the terminal is allowed on this stream.
  2275. VideoSend allows both a capture terminal and a preivew terminal.
  2276. Arguments:
  2277. pTerminal - the terminal.
  2278. Return value:
  2279. HRESULT.
  2280. S_OK means the terminal is OK.
  2281. */
  2282. {
  2283. LOG((MSP_TRACE, "VideoSend.CheckTerminalTypeAndDirection"));
  2284. // This stream only support one capture + one preview terminal
  2285. if (m_Terminals.GetSize() > 1)
  2286. {
  2287. return TAPI_E_MAXTERMINALS;
  2288. }
  2289. // check the media type of this terminal.
  2290. long lMediaType;
  2291. HRESULT hr = pTerminal->get_MediaType(&lMediaType);
  2292. if (FAILED(hr))
  2293. {
  2294. LOG((MSP_ERROR, "can't get terminal media type. %x", hr));
  2295. return TAPI_E_INVALIDTERMINAL;
  2296. }
  2297. if ((DWORD)lMediaType != m_dwMediaType)
  2298. {
  2299. return TAPI_E_INVALIDTERMINAL;
  2300. }
  2301. // check the direction of this terminal.
  2302. TERMINAL_DIRECTION Direction;
  2303. hr = pTerminal->get_Direction(&Direction);
  2304. if (FAILED(hr))
  2305. {
  2306. LOG((MSP_ERROR, "can't get terminal direction. %x", hr));
  2307. return TAPI_E_INVALIDTERMINAL;
  2308. }
  2309. if (m_Terminals.GetSize() > 0)
  2310. {
  2311. // check the direction of this terminal.
  2312. TERMINAL_DIRECTION Direction2;
  2313. hr = m_Terminals[0]->get_Direction(&Direction2);
  2314. if (FAILED(hr))
  2315. {
  2316. LOG((MSP_ERROR, "can't get terminal direction. %x", hr));
  2317. return TAPI_E_INVALIDTERMINAL;
  2318. }
  2319. if (Direction == Direction2)
  2320. {
  2321. LOG((MSP_ERROR,
  2322. "can't have two terminals with the same direction. %x", hr));
  2323. return TAPI_E_MAXTERMINALS;
  2324. }
  2325. }
  2326. return S_OK;
  2327. }
  2328. HRESULT CStreamVideoSend::SetUpFilters()
  2329. /*++
  2330. Routine Description:
  2331. Insert filters into the graph and connect to the terminals.
  2332. Arguments:
  2333. Return Value:
  2334. HRESULT.
  2335. --*/
  2336. {
  2337. LOG((MSP_TRACE, "VideoSend.SetUpFilters"));
  2338. // we only support one capture terminal and one preview
  2339. // window on this stream.
  2340. if (m_Terminals.GetSize() > 2)
  2341. {
  2342. return E_UNEXPECTED;
  2343. }
  2344. int iCaptureIndex = -1, iPreviewIndex = -1;
  2345. // Find out which terminal is capture and which is preview.
  2346. HRESULT hr;
  2347. for (int i = 0; i < m_Terminals.GetSize(); i ++)
  2348. {
  2349. TERMINAL_DIRECTION Direction;
  2350. hr = m_Terminals[i]->get_Direction(&Direction);
  2351. if (FAILED(hr))
  2352. {
  2353. LOG((MSP_ERROR, "can't get terminal direction. %x", hr));
  2354. SendStreamEvent(CALL_TERMINAL_FAIL, CALL_CAUSE_BAD_DEVICE, hr, m_Terminals[i]);
  2355. return hr;
  2356. }
  2357. if (Direction == TD_CAPTURE)
  2358. {
  2359. iCaptureIndex = i;
  2360. }
  2361. else
  2362. {
  2363. iPreviewIndex = i;
  2364. }
  2365. }
  2366. // the stream will not work without a capture terminal.
  2367. if (iCaptureIndex == -1)
  2368. {
  2369. LOG((MSP_ERROR, "no capture terminal selected."));
  2370. return E_UNEXPECTED;
  2371. }
  2372. // Connect the capture filter to the terminal.
  2373. if (FAILED(hr = ConnectTerminal(
  2374. m_Terminals[iCaptureIndex]
  2375. )))
  2376. {
  2377. LOG((MSP_ERROR, "connect the codec filter to terminal. %x", hr));
  2378. return hr;
  2379. }
  2380. if (iPreviewIndex != -1)
  2381. {
  2382. // Connect the preview filter to the terminal.
  2383. if (FAILED(hr = ConnectTerminal(
  2384. m_Terminals[iPreviewIndex]
  2385. )))
  2386. {
  2387. LOG((MSP_ERROR, "connect the codec filter to terminal. %x", hr));
  2388. return hr;
  2389. }
  2390. }
  2391. return hr;
  2392. }
  2393. HRESULT CStreamVideoSend::ConfigureRTPFilter(
  2394. IN IBaseFilter * pIBaseFilter
  2395. )
  2396. /*++
  2397. Routine Description:
  2398. Configure the source RTP filter. Including set the address, port, TTL,
  2399. QOS, thread priority, clockrate, etc.
  2400. Arguments:
  2401. pIBaseFilter - The source RTP Filter.
  2402. Return Value:
  2403. HRESULT.
  2404. --*/
  2405. {
  2406. LOG((MSP_TRACE, "VideoSend.ConfigureRTPFilter"));
  2407. HRESULT hr;
  2408. // Get the IRTPStream interface pointer on the filter.
  2409. CComQIPtr<IRTPStream, &IID_IRTPStream> pIRTPStream(pIBaseFilter);
  2410. if (pIRTPStream == NULL)
  2411. {
  2412. LOG((MSP_ERROR, "get RTP Stream interface"));
  2413. return E_NOINTERFACE;
  2414. }
  2415. LOG((MSP_INFO, "set remote Address:%x, port:%d, TTL:%d",
  2416. m_Settings.dwIPRemote, m_Settings.wRTPPortRemote, m_Settings.dwTTL));
  2417. // Set the remote address and port used in the filter.
  2418. if (FAILED(hr = pIRTPStream->SetAddress(
  2419. 0, // local port.
  2420. htons(m_Settings.wRTPPortRemote), // remote port.
  2421. htonl(m_Settings.dwIPRemote)
  2422. )))
  2423. {
  2424. LOG((MSP_ERROR, "set remote Address, hr:%x", hr));
  2425. return hr;
  2426. }
  2427. // Set the TTL used in the filter.
  2428. if (FAILED(hr = pIRTPStream->SetMulticastScope(m_Settings.dwTTL)))
  2429. {
  2430. LOG((MSP_ERROR, "set TTL. %x", hr));
  2431. return hr;
  2432. }
  2433. if (m_Settings.dwIPLocal != INADDR_ANY)
  2434. {
  2435. // set the local interface that the socket should bind to
  2436. LOG((MSP_INFO, "set locol Address:%x", m_Settings.dwIPLocal));
  2437. if (FAILED(hr = pIRTPStream->SelectLocalIPAddress(
  2438. htonl(m_Settings.dwIPLocal)
  2439. )))
  2440. {
  2441. LOG((MSP_ERROR, "set local Address, hr:%x", hr));
  2442. return hr;
  2443. }
  2444. }
  2445. // Set the priority of the session
  2446. if (FAILED(hr = pIRTPStream->SetSessionClassPriority(
  2447. RTP_CLASS_VIDEO,
  2448. g_dwVideoThreadPriority
  2449. )))
  2450. {
  2451. LOG((MSP_ERROR, "set session class and priority. %x", hr));
  2452. }
  2453. // Set the sample rate of the session
  2454. LOG((MSP_INFO, "setting session sample rate to %d", m_dwFrameRate));
  2455. if (FAILED(hr = pIRTPStream->SetDataClock(m_dwFrameRate)))
  2456. {
  2457. LOG((MSP_ERROR, "set session sample rate. %x", hr));
  2458. }
  2459. // Enable the RTCP events
  2460. if (FAILED(hr = ::EnableRTCPEvents(pIBaseFilter)))
  2461. {
  2462. LOG((MSP_WARN, "can not enable RTCP events %x", hr));
  2463. }
  2464. if (m_Settings.dwQOSLevel != QSL_BEST_EFFORT)
  2465. {
  2466. if (FAILED(hr = ::SetQOSOption(
  2467. pIBaseFilter,
  2468. m_Settings.dwPayloadType, // payload
  2469. -1, // use the default bitrate
  2470. (m_Settings.dwQOSLevel == QSL_NEEDED), // fail if no qos.
  2471. FALSE, // this is the send stream.
  2472. 1, // only one stream
  2473. m_Settings.fCIF
  2474. )))
  2475. {
  2476. LOG((MSP_ERROR, "set QOS option. %x", hr));
  2477. return hr;
  2478. }
  2479. }
  2480. SetLocalInfoOnRTPFilter(pIBaseFilter);
  2481. return S_OK;
  2482. }
  2483. HRESULT CStreamVideoSend::ConnectTerminal(
  2484. IN ITTerminal * pITTerminal
  2485. )
  2486. /*++
  2487. Routine Description:
  2488. connect the video terminals to the stream.
  2489. Arguments:
  2490. Return Value:
  2491. HRESULT.
  2492. --*/
  2493. {
  2494. LOG((MSP_TRACE, "VideoSend.ConnectTerminal %x", pITTerminal));
  2495. // Get the TerminalControl interface on the terminal
  2496. CComQIPtr<ITTerminalControl, &IID_ITTerminalControl>
  2497. pTerminal(pITTerminal);
  2498. if (pTerminal == NULL)
  2499. {
  2500. LOG((MSP_ERROR, "can't get Terminal Control interface"));
  2501. SendStreamEvent(CALL_TERMINAL_FAIL, CALL_CAUSE_BAD_DEVICE, E_NOINTERFACE, pITTerminal);
  2502. return E_NOINTERFACE;
  2503. }
  2504. // Find out the direction of the terminal.
  2505. TERMINAL_DIRECTION Direction;
  2506. HRESULT hr = pITTerminal->get_Direction(&Direction);
  2507. if (FAILED(hr))
  2508. {
  2509. LOG((MSP_ERROR, "can't get terminal direction. %x", hr));
  2510. SendStreamEvent(CALL_TERMINAL_FAIL, CALL_CAUSE_BAD_DEVICE, hr, pITTerminal);
  2511. return hr;
  2512. }
  2513. if (Direction == TD_CAPTURE)
  2514. {
  2515. // find the capture pin on the capture terminal and configure it.
  2516. CComPtr<IPin> pCapturePin;
  2517. hr = ConfigureVideoCaptureTerminal(pTerminal, L"Capture", &pCapturePin);
  2518. if (FAILED(hr))
  2519. {
  2520. LOG((MSP_ERROR, "configure video capture termianl failed. %x", hr));
  2521. SendStreamEvent(CALL_TERMINAL_FAIL, CALL_CAUSE_BAD_DEVICE, hr, pITTerminal);
  2522. return hr;
  2523. }
  2524. hr = CreateSendFilters(pCapturePin);
  2525. if (FAILED(hr))
  2526. {
  2527. LOG((MSP_ERROR, "Create video send filters failed. %x", hr));
  2528. // disconnect the terminal.
  2529. pTerminal->DisconnectTerminal(m_pIGraphBuilder, 0);
  2530. // clean up internal filters as well.
  2531. CleanUpFilters();
  2532. return hr;
  2533. }
  2534. //
  2535. // Now we are actually connected. Update our state and perform postconnection
  2536. // (ignore postconnection error code).
  2537. //
  2538. pTerminal->CompleteConnectTerminal();
  2539. #if 0 // We don't have the preview pin now, enable this code later when we
  2540. // the have preview pin.
  2541. if (FAILED(hr))
  2542. {
  2543. // find the preview pin on the capture terminal and configure it.
  2544. CComPtr<IPin> pCapturePin;
  2545. hr = ConfigureVideoCaptureTerminal(pTerminal, L"Preview", &pCapturePin);
  2546. if (FAILED(hr))
  2547. {
  2548. LOG((MSP_ERROR, "configure video capture termianl failed. %x", hr));
  2549. SendStreamEvent(CALL_TERMINAL_FAIL, CALL_CAUSE_BAD_DEVICE, hr, pITTerminal);
  2550. return hr;
  2551. }
  2552. hr = CreateSendFilters(pCapturePin);
  2553. if (FAILED(hr))
  2554. {
  2555. LOG((MSP_ERROR, "Create video send filters failed. %x", hr));
  2556. // disconnect the terminal.
  2557. pTerminal->DisconnectTerminal(m_pIGraphBuilder, 0);
  2558. // clean up internal filters as well.
  2559. CleanUpFilters();
  2560. return hr;
  2561. }
  2562. //
  2563. // Now we are actually connected. Update our state and perform postconnection
  2564. // (ignore postconnection error code).
  2565. //
  2566. pTerminal->CompleteConnectTerminal();
  2567. }
  2568. #endif
  2569. }
  2570. else
  2571. {
  2572. // find the input pin on the preview window. If there is no preview window,
  2573. // we just pass in NULL for the next function.
  2574. CComPtr<IPin> pPreviewInputPin;
  2575. hr = FindPreviewInputPin(pTerminal, &pPreviewInputPin);
  2576. if (FAILED(hr))
  2577. {
  2578. LOG((MSP_ERROR, "find preview input pin failed. %x", hr));
  2579. SendStreamEvent(CALL_TERMINAL_FAIL, CALL_CAUSE_BAD_DEVICE, hr, pITTerminal);
  2580. return hr;
  2581. }
  2582. hr = ConnectPreview(pPreviewInputPin);
  2583. if (FAILED(hr))
  2584. {
  2585. LOG((MSP_ERROR, "Create video send filters failed. %x", hr));
  2586. pTerminal->DisconnectTerminal(m_pIGraphBuilder, 0);
  2587. return hr;
  2588. }
  2589. //
  2590. // Now we are actually connected. Update our state and perform postconnection
  2591. // (ignore postconnection error code).
  2592. //
  2593. pTerminal->CompleteConnectTerminal();
  2594. }
  2595. return hr;
  2596. }
  2597. HRESULT CStreamVideoSend::ConnectPreview(
  2598. IN IPin *pPreviewInputPin
  2599. )
  2600. /*++
  2601. Routine Description:
  2602. connect the preview pin the the TEE filter.
  2603. Capturepin->TEE+->Encoder->SPH->RTPRender
  2604. +->PreviewInputPin
  2605. Arguments:
  2606. pPin - The output pin on the capture filter.
  2607. Return Value:
  2608. HRESULT.
  2609. --*/
  2610. {
  2611. HRESULT hr;
  2612. if (m_pEdgeFilter == NULL)
  2613. {
  2614. LOG((MSP_ERROR, "no capture to preview"));
  2615. return E_UNEXPECTED;
  2616. }
  2617. // Create the AVI decompressor filter and add it into the graph.
  2618. // This will make the graph construction faster for since the AVI
  2619. // decompressor are always needed for the preview
  2620. CComPtr<IBaseFilter> pAviFilter;
  2621. if (FAILED(hr = ::AddFilter(
  2622. m_pIGraphBuilder,
  2623. CLSID_AVIDec,
  2624. L"Avi",
  2625. &pAviFilter)))
  2626. {
  2627. LOG((MSP_ERROR, "add Avi filter. %x", hr));
  2628. return hr;
  2629. }
  2630. // connect the preview input pin with the smart tee filter.
  2631. if (FAILED(hr = ::ConnectFilters(
  2632. m_pIGraphBuilder,
  2633. (IBaseFilter *)m_pEdgeFilter,
  2634. (IPin *)pPreviewInputPin,
  2635. FALSE // not direct connect
  2636. )))
  2637. {
  2638. LOG((MSP_ERROR, "connect preview input pin with the tee. %x", hr));
  2639. return hr;
  2640. }
  2641. return hr;
  2642. }
  2643. HRESULT
  2644. ConfigureEncoder(
  2645. IN IBaseFilter * pIFilter,
  2646. IN BOOL bCIF,
  2647. IN DWORD dwFramesPerSecond
  2648. )
  2649. /*++
  2650. Routine Description:
  2651. Set the video capture terminal's buffersize.
  2652. Arguments:
  2653. pIFilter - a H26x encoder.
  2654. bCIF - CIF or QCIF.
  2655. pdwFramesPerSecond - Frames per second.
  2656. Return Value:
  2657. HRESULT
  2658. --*/
  2659. {
  2660. LOG((MSP_TRACE, "ConfigureEncoder"));
  2661. HRESULT hr;
  2662. CComPtr<IH26XEncoderControl> pIH26XEncoderControl;
  2663. if (FAILED(hr = pIFilter->QueryInterface(
  2664. IID_IH26XEncoderControl,
  2665. (void **)&pIH26XEncoderControl
  2666. )))
  2667. {
  2668. LOG((MSP_ERROR, "Can't get pIH26XEncoderControl interface.%8x", hr));
  2669. return hr;
  2670. }
  2671. // get the current encoder properties of the video capture terminal.
  2672. ENC_CMP_DATA prop;
  2673. if (FAILED(hr = pIH26XEncoderControl->get_EncodeCompression(&prop)))
  2674. {
  2675. LOG((MSP_ERROR, "get_EncodeCompression returns error: %8x", hr));
  2676. return hr;
  2677. }
  2678. LOG((MSP_INFO,
  2679. "Video encoder::get_EncodeCompression"
  2680. " FrameRate: %d, BitRate: %d, Width %d, bSendKey: %s, Quality: %d",
  2681. prop.dwFrameRate,
  2682. prop.dwDataRate,
  2683. prop.dwWidth,
  2684. prop.bSendKey ? "TRUE" : "FALSE",
  2685. prop.dwQuality
  2686. ));
  2687. // Set the key frame interval.
  2688. prop.bSendKey = TRUE;
  2689. prop.dwFrameRate = dwFramesPerSecond;
  2690. prop.dwKeyFramePeriod = 5000; // a key frame every five seconds.
  2691. prop.dwQuality = 7500;
  2692. #define SETBITRATE
  2693. #ifdef SETBITRATE
  2694. DWORD dwBitRate = 0;
  2695. if (GetRegValue(L"BitRate", &dwBitRate))
  2696. {
  2697. prop.bFrameSizeBRC = FALSE; // control bit rate
  2698. prop.dwDataRate = dwBitRate;
  2699. if (dwBitRate < 100)
  2700. {
  2701. prop.dwQuality = 0;
  2702. prop.dwKeyFrameInterval = 100;
  2703. }
  2704. }
  2705. DWORD dwQuality = 0;
  2706. if (GetRegValue(L"Quality", &dwQuality))
  2707. {
  2708. prop.dwQuality = dwQuality;
  2709. }
  2710. #endif
  2711. if (bCIF)
  2712. {
  2713. prop.dwWidth = CIFWIDTH;
  2714. }
  2715. else
  2716. {
  2717. prop.dwWidth = QCIFWIDTH;
  2718. }
  2719. if (FAILED(hr = pIH26XEncoderControl->set_EncodeCompression(&prop)))
  2720. {
  2721. LOG((MSP_ERROR, "set_EncodeCompression returns error: %8x", hr));
  2722. }
  2723. else
  2724. {
  2725. LOG((MSP_INFO,
  2726. "Video encoder::set_EncodeCompression"
  2727. " FrameRate: %d, BitRate: %d, Width %d, bSendKey: %s, Quality: %d",
  2728. prop.dwFrameRate,
  2729. prop.dwDataRate,
  2730. prop.dwWidth,
  2731. prop.bSendKey ? "TRUE" : "FALSE",
  2732. prop.dwQuality
  2733. ));
  2734. }
  2735. return hr;
  2736. }
  2737. HRESULT CStreamVideoSend::CreateSendFilters(
  2738. IN IPin *pCapturePin
  2739. )
  2740. /*++
  2741. Routine Description:
  2742. Insert filters into the graph and connect to the capture pin.
  2743. Capturepin->TEE+->Encoder->SPH->RTPRender
  2744. Arguments:
  2745. pPin - The output pin on the capture filter.
  2746. Return Value:
  2747. HRESULT.
  2748. --*/
  2749. {
  2750. HRESULT hr;
  2751. if (m_pEdgeFilter)
  2752. {
  2753. // connect the capture pin with the smart tee filter.
  2754. if (FAILED(hr = ::ConnectFilters(
  2755. m_pIGraphBuilder,
  2756. (IPin *)pCapturePin,
  2757. (IBaseFilter *)m_pEdgeFilter
  2758. )))
  2759. {
  2760. LOG((MSP_ERROR, "connect capture pin with the tee. %x", hr));
  2761. return hr;
  2762. }
  2763. return hr;
  2764. }
  2765. // Create the tee filter and add it into the graph.
  2766. CComPtr<IBaseFilter> pTeeFilter;
  2767. if (FAILED(hr = ::AddFilter(
  2768. m_pIGraphBuilder,
  2769. CLSID_SmartTee,
  2770. // CLSID_InfTee,
  2771. L"tee",
  2772. &pTeeFilter)))
  2773. {
  2774. LOG((MSP_ERROR, "add smart tee filter. %x", hr));
  2775. return hr;
  2776. }
  2777. // connect the capture pin with the tee filter.
  2778. if (FAILED(hr = ::ConnectFilters(
  2779. m_pIGraphBuilder,
  2780. (IPin *)pCapturePin,
  2781. (IBaseFilter *)pTeeFilter
  2782. )))
  2783. {
  2784. LOG((MSP_ERROR, "connect capture pin with the tee. %x", hr));
  2785. return hr;
  2786. }
  2787. // Create the codec filter and add it into the graph.
  2788. CComPtr<IBaseFilter> pCodecFilter;
  2789. if (FAILED(hr = ::AddFilter(
  2790. m_pIGraphBuilder,
  2791. *m_pClsidCodecFilter,
  2792. L"Encoder",
  2793. &pCodecFilter)))
  2794. {
  2795. LOG((MSP_ERROR, "add Codec filter. %x", hr));
  2796. return hr;
  2797. }
  2798. // tell the encoder to send key frame
  2799. if (FAILED(hr = ::ConfigureEncoder(
  2800. pCodecFilter,
  2801. m_Settings.fCIF,
  2802. m_dwFrameRate
  2803. )))
  2804. {
  2805. LOG((MSP_WARN, "Configure video encoder. %x", hr));
  2806. }
  2807. // connect the smart tee filter and the Codec filter.
  2808. if (FAILED(hr = ::ConnectFilters(
  2809. m_pIGraphBuilder,
  2810. (IBaseFilter *)pTeeFilter,
  2811. (IBaseFilter *)pCodecFilter
  2812. )))
  2813. {
  2814. LOG((MSP_ERROR, "connect Tee filter and codec filter. %x", hr));
  2815. return hr;
  2816. }
  2817. // Create the send payload handler and add it into the graph.
  2818. CComPtr<IBaseFilter> pISPHFilter;
  2819. if (FAILED(hr = ::AddFilter(
  2820. m_pIGraphBuilder,
  2821. *m_pClsidPHFilter,
  2822. L"SPH",
  2823. &pISPHFilter
  2824. )))
  2825. {
  2826. LOG((MSP_ERROR, "add SPH filter. %x", hr));
  2827. return hr;
  2828. }
  2829. // Connect the Codec filter with the SPH filter .
  2830. if (FAILED(hr = ::ConnectFilters(
  2831. m_pIGraphBuilder,
  2832. (IBaseFilter *)pCodecFilter,
  2833. (IBaseFilter *)pISPHFilter
  2834. )))
  2835. {
  2836. LOG((MSP_ERROR, "connect codec filter and SPH filter. %x", hr));
  2837. return hr;
  2838. }
  2839. // Get the IRTPSPHFilter interface.
  2840. CComQIPtr<IRTPSPHFilter,
  2841. &IID_IRTPSPHFilter> pIRTPSPHFilter(pISPHFilter);
  2842. if (pIRTPSPHFilter == NULL)
  2843. {
  2844. LOG((MSP_ERROR, "get IRTPSPHFilter interface"));
  2845. return E_NOINTERFACE;
  2846. }
  2847. // Create the RTP render filter and add it into the graph.
  2848. CComPtr<IBaseFilter> pRenderFilter;
  2849. if (FAILED(hr = ::AddFilter(
  2850. m_pIGraphBuilder,
  2851. CLSID_RTPRenderFilter,
  2852. L"RtpRender",
  2853. &pRenderFilter)))
  2854. {
  2855. LOG((MSP_ERROR, "adding render filter. %x", hr));
  2856. return hr;
  2857. }
  2858. // Set the address for the render fitler.
  2859. if (FAILED(hr = ConfigureRTPFilter(pRenderFilter)))
  2860. {
  2861. LOG((MSP_ERROR, "configure RTP Filter failed %x", hr));
  2862. return hr;
  2863. }
  2864. // Connect the SPH filter with the RTP Render filter.
  2865. if (FAILED(hr = ::ConnectFilters(
  2866. m_pIGraphBuilder,
  2867. (IBaseFilter *)pISPHFilter,
  2868. (IBaseFilter *)pRenderFilter
  2869. )))
  2870. {
  2871. LOG((MSP_ERROR, "connect SPH filter and Render filter. %x", hr));
  2872. return hr;
  2873. }
  2874. // remember the first filter after the terminal
  2875. m_pEdgeFilter = pTeeFilter;
  2876. m_pEdgeFilter->AddRef();
  2877. // Get the IRTPParticipant interface pointer on the RTP filter.
  2878. CComQIPtr<IRTPParticipant,
  2879. &IID_IRTPParticipant> pIRTPParticipant(pRenderFilter);
  2880. if (pIRTPParticipant == NULL)
  2881. {
  2882. LOG((MSP_WARN, "can't get RTP participant interface"));
  2883. }
  2884. else
  2885. {
  2886. m_pRTPFilter = pIRTPParticipant;
  2887. m_pRTPFilter->AddRef();
  2888. }
  2889. return S_OK;
  2890. }
  2891. CSubStreamVideoRecv::CSubStreamVideoRecv()
  2892. : m_pFTM(NULL),
  2893. m_pStream(NULL),
  2894. m_pCurrentParticipant(NULL)
  2895. {
  2896. }
  2897. // methods called by the videorecv object.
  2898. HRESULT CSubStreamVideoRecv::Init(
  2899. IN CStreamVideoRecv * pStream
  2900. )
  2901. /*++
  2902. Routine Description:
  2903. Initialize the substream object.
  2904. Arguments:
  2905. pStream - The pointer to the stream that owns this substream.
  2906. Return Value:
  2907. HRESULT.
  2908. --*/
  2909. {
  2910. LOG((MSP_TRACE,
  2911. "CSubStreamVideoRecv::Init, pStream %p", pStream));
  2912. // This method is called only once when the object is created. No other
  2913. // method will be called until this function succeeds. No need to lock.
  2914. _ASSERTE(m_pStream == NULL);
  2915. // initialize the terminal array so that the array is not NULL. Used for
  2916. // generating an empty enumerator if no terminal is selected.
  2917. if (!m_Terminals.Grow())
  2918. {
  2919. LOG((MSP_ERROR, "CSubStreamVideoRecv::Init - exit E_OUTOFMEMORY"));
  2920. return E_OUTOFMEMORY;
  2921. }
  2922. // create the marshaler.
  2923. HRESULT hr;
  2924. hr = CoCreateFreeThreadedMarshaler(GetControllingUnknown(), &m_pFTM);
  2925. if (FAILED(hr))
  2926. {
  2927. LOG((MSP_ERROR, "create marshaler failed, %x", hr));
  2928. return hr;
  2929. }
  2930. // save the stream reference.
  2931. m_pStream = pStream;
  2932. (pStream->GetControllingUnknown())->AddRef();
  2933. LOG((MSP_TRACE, "CSubStreamVideoRecv::Init returns S_OK"));
  2934. return S_OK;
  2935. }
  2936. #ifdef DEBUG_REFCOUNT
  2937. ULONG CSubStreamVideoRecv::InternalAddRef()
  2938. {
  2939. ULONG lRef = CComObjectRootEx<CComMultiThreadModelNoCS>::InternalAddRef();
  2940. LOG((MSP_TRACE, "SubStreamVideoRecv %p Addref, ref = %d", this, lRef));
  2941. return lRef;
  2942. }
  2943. ULONG CSubStreamVideoRecv::InternalRelease()
  2944. {
  2945. ULONG lRef = CComObjectRootEx<CComMultiThreadModelNoCS>::InternalRelease();
  2946. LOG((MSP_TRACE, "SubStreamVideoRecv %p Release, ref = %d", this, lRef));
  2947. return lRef;
  2948. }
  2949. #endif
  2950. void CSubStreamVideoRecv::FinalRelease()
  2951. /*++
  2952. Routine Description:
  2953. release everything before being deleted.
  2954. Arguments:
  2955. Return Value:
  2956. --*/
  2957. {
  2958. LOG((MSP_TRACE, "CSubStreamVideoRecv::FinalRelease - enter"));
  2959. if (m_pCurrentParticipant)
  2960. {
  2961. m_pCurrentParticipant->Release();
  2962. }
  2963. for ( int i = 0; i < m_Terminals.GetSize(); i ++ )
  2964. {
  2965. m_Terminals[i]->Release();
  2966. }
  2967. m_Terminals.RemoveAll();
  2968. if (m_pStream)
  2969. {
  2970. (m_pStream->GetControllingUnknown())->Release();
  2971. }
  2972. if (m_pFTM)
  2973. {
  2974. m_pFTM->Release();
  2975. }
  2976. LOG((MSP_TRACE, "CSubStreamVideoRecv::FinalRelease - exit"));
  2977. }
  2978. STDMETHODIMP CSubStreamVideoRecv::SelectTerminal(
  2979. IN ITTerminal * pTerminal
  2980. )
  2981. /*++
  2982. Routine Description:
  2983. Select a terminal on this substream. This method calls the same method
  2984. on the stream object to handle that.
  2985. Arguments:
  2986. pTerminal - the terminal to be selected.
  2987. Return Value:
  2988. --*/
  2989. {
  2990. LOG((MSP_TRACE,
  2991. "CSubStreamVideoRecv::SelectTerminal, pTerminal %p", pTerminal));
  2992. HRESULT hr;
  2993. m_lock.Lock();
  2994. if (m_Terminals.GetSize() > 0)
  2995. {
  2996. m_lock.Unlock();
  2997. return TAPI_E_MAXTERMINALS;
  2998. }
  2999. BOOL bFlag = m_Terminals.Add(pTerminal);
  3000. _ASSERTE(bFlag);
  3001. m_lock.Unlock();
  3002. if (!bFlag)
  3003. {
  3004. return E_OUTOFMEMORY;
  3005. }
  3006. // This is the refcount for the pointer in m_Terminals.
  3007. pTerminal->AddRef();
  3008. // Call the stream's select terminal to handle the state changes and also
  3009. // make sure that locking happens only from the stream to substream.
  3010. hr = m_pStream->SubStreamSelectTerminal(this, pTerminal);
  3011. if (FAILED(hr))
  3012. {
  3013. LOG((MSP_ERROR,
  3014. "CSubStreamVideoRecv::SelectTerminal failed, hr:%x", hr));
  3015. m_lock.Lock();
  3016. m_Terminals.Remove(pTerminal);
  3017. pTerminal->Release();
  3018. m_lock.Unlock();
  3019. }
  3020. return hr;
  3021. }
  3022. STDMETHODIMP CSubStreamVideoRecv::UnselectTerminal(
  3023. IN ITTerminal * pTerminal
  3024. )
  3025. /*++
  3026. Routine Description:
  3027. Unselect a terminal on this substream. This method calls the same method
  3028. on the stream object to handle that.
  3029. Arguments:
  3030. pTerminal - the terminal to be unselected.
  3031. Return Value:
  3032. --*/
  3033. {
  3034. LOG((MSP_TRACE,
  3035. "CSubStreamVideoRecv::UnSelectTerminal, pTerminal %p", pTerminal));
  3036. m_lock.Lock();
  3037. if (!m_Terminals.Remove(pTerminal))
  3038. {
  3039. m_lock.Unlock();
  3040. LOG((MSP_ERROR, "SubStreamVideoRecv::UnselectTerminal, invalid terminal."));
  3041. return TAPI_E_INVALIDTERMINAL;
  3042. }
  3043. pTerminal->Release();
  3044. m_lock.Unlock();
  3045. HRESULT hr;
  3046. // Call the stream's unselect terminal to handle the state changes and also
  3047. // make sure that locking happens only from the stream to substream.
  3048. hr = m_pStream->UnselectTerminal(pTerminal);
  3049. if (FAILED(hr))
  3050. {
  3051. LOG((MSP_ERROR,
  3052. "CSubStreamVideoRecv::UnSelectTerminal failed, hr:%x", hr));
  3053. }
  3054. return hr;
  3055. }
  3056. STDMETHODIMP CSubStreamVideoRecv::EnumerateTerminals(
  3057. OUT IEnumTerminal ** ppEnumTerminal
  3058. )
  3059. {
  3060. LOG((MSP_TRACE,
  3061. "EnumerateTerminals entered. ppEnumTerminal:%x", ppEnumTerminal));
  3062. if (IsBadWritePtr(ppEnumTerminal, sizeof(VOID *)))
  3063. {
  3064. LOG((MSP_ERROR, "ppEnumTerminal is a bad pointer"));
  3065. return E_POINTER;
  3066. }
  3067. // acquire the lock before accessing the Terminal object list.
  3068. CLock lock(m_lock);
  3069. if (m_Terminals.GetData() == NULL)
  3070. {
  3071. LOG((MSP_ERROR, "CSubStreamVideoRecv::EnumerateTerminals - "
  3072. "stream appears to have been shut down - exit E_UNEXPECTED"));
  3073. return E_UNEXPECTED;
  3074. }
  3075. typedef _CopyInterface<ITTerminal> CCopy;
  3076. typedef CSafeComEnum<IEnumTerminal, &IID_IEnumTerminal,
  3077. ITTerminal *, CCopy> CEnumerator;
  3078. HRESULT hr;
  3079. CMSPComObject<CEnumerator> *pEnum = NULL;
  3080. hr = CMSPComObject<CEnumerator>::CreateInstance(&pEnum);
  3081. if (pEnum == NULL)
  3082. {
  3083. LOG((MSP_ERROR, "Could not create enumerator object, %x", hr));
  3084. return hr;
  3085. }
  3086. // query for the IID_IEnumTerminal i/f
  3087. IEnumTerminal * pEnumTerminal;
  3088. hr = pEnum->_InternalQueryInterface(IID_IEnumTerminal, (void**)&pEnumTerminal);
  3089. if (FAILED(hr))
  3090. {
  3091. LOG((MSP_ERROR, "query enum interface failed, %x", hr));
  3092. delete pEnum;
  3093. return hr;
  3094. }
  3095. // The CSafeComEnum can handle zero-sized array.
  3096. hr = pEnum->Init(
  3097. m_Terminals.GetData(), // the begin itor
  3098. m_Terminals.GetData() + m_Terminals.GetSize(), // the end itor,
  3099. NULL, // IUnknown
  3100. AtlFlagCopy // copy the data.
  3101. );
  3102. if (FAILED(hr))
  3103. {
  3104. LOG((MSP_ERROR, "init enumerator object failed, %x", hr));
  3105. pEnumTerminal->Release();
  3106. return hr;
  3107. }
  3108. LOG((MSP_TRACE, "CSubStreamVideoRecv::EnumerateTerminals - exit S_OK"));
  3109. *ppEnumTerminal = pEnumTerminal;
  3110. return hr;
  3111. }
  3112. STDMETHODIMP CSubStreamVideoRecv::get_Terminals(
  3113. OUT VARIANT * pVariant
  3114. )
  3115. {
  3116. LOG((MSP_TRACE, "CSubStreamVideoRecv::get_Terminals - enter"));
  3117. //
  3118. // Check parameters.
  3119. //
  3120. if ( IsBadWritePtr(pVariant, sizeof(VARIANT) ) )
  3121. {
  3122. LOG((MSP_ERROR, "CSubStreamVideoRecv::get_Terminals - "
  3123. "bad pointer argument - exit E_POINTER"));
  3124. return E_POINTER;
  3125. }
  3126. //
  3127. // See if this stream has been shut down. Acquire the lock before accessing
  3128. // the terminal object list.
  3129. //
  3130. CLock lock(m_lock);
  3131. if (m_Terminals.GetData() == NULL)
  3132. {
  3133. LOG((MSP_ERROR, "CSubStreamVideoRecv::get_Terminals - "
  3134. "stream appears to have been shut down - exit E_UNEXPECTED"));
  3135. return E_UNEXPECTED;
  3136. }
  3137. //
  3138. // create the collection object - see mspcoll.h
  3139. //
  3140. HRESULT hr;
  3141. typedef CTapiIfCollection< ITTerminal * > TerminalCollection;
  3142. CComObject<TerminalCollection> * pCollection;
  3143. hr = CComObject<TerminalCollection>::CreateInstance( &pCollection );
  3144. if ( FAILED(hr) )
  3145. {
  3146. LOG((MSP_ERROR, "CSubStreamVideoRecv::get_Terminals - "
  3147. "can't create collection - exit 0x%08x", hr));
  3148. return hr;
  3149. }
  3150. //
  3151. // get the Collection's IDispatch interface
  3152. //
  3153. IDispatch * pDispatch;
  3154. hr = pCollection->_InternalQueryInterface(IID_IDispatch,
  3155. (void **) &pDispatch );
  3156. if ( FAILED(hr) )
  3157. {
  3158. LOG((MSP_ERROR, "CSubStreamVideoRecv::get_Terminals - "
  3159. "QI for IDispatch on collection failed - exit 0x%08x", hr));
  3160. delete pCollection;
  3161. return hr;
  3162. }
  3163. //
  3164. // Init the collection using an iterator -- pointers to the beginning and
  3165. // the ending element plus one.
  3166. //
  3167. hr = pCollection->Initialize( m_Terminals.GetSize(),
  3168. m_Terminals.GetData(),
  3169. m_Terminals.GetData() + m_Terminals.GetSize() );
  3170. if (FAILED(hr))
  3171. {
  3172. LOG((MSP_ERROR, "CSubStreamVideoRecv::get_Terminals - "
  3173. "Initialize on collection failed - exit 0x%08x", hr));
  3174. pDispatch->Release();
  3175. return hr;
  3176. }
  3177. //
  3178. // put the IDispatch interface pointer into the variant
  3179. //
  3180. LOG((MSP_ERROR, "CSubStreamVideoRecv::get_Terminals - "
  3181. "placing IDispatch value %08x in variant", pDispatch));
  3182. VariantInit(pVariant);
  3183. pVariant->vt = VT_DISPATCH;
  3184. pVariant->pdispVal = pDispatch;
  3185. LOG((MSP_TRACE, "CSubStreamVideoRecv::get_Terminals - exit S_OK"));
  3186. return S_OK;
  3187. }
  3188. STDMETHODIMP CSubStreamVideoRecv::get_Stream (
  3189. OUT ITStream ** ppITStream
  3190. )
  3191. {
  3192. LOG((MSP_TRACE,
  3193. "VideoRecvSubStream.get_Stream, ppITStream %x", ppITStream));
  3194. if (IsBadWritePtr(ppITStream, sizeof (VOID *)))
  3195. {
  3196. LOG((MSP_ERROR, "Bad pointer, ppITStream:%x",ppITStream));
  3197. return E_POINTER;
  3198. }
  3199. ITStream * pITStream;
  3200. HRESULT hr = m_pStream->_InternalQueryInterface(
  3201. IID_ITStream,
  3202. (void **)&pITStream
  3203. );
  3204. if (FAILED(hr))
  3205. {
  3206. LOG((MSP_ERROR, "get_Stream:QueryInterface failed: %x", hr));
  3207. return hr;
  3208. }
  3209. *ppITStream = pITStream;
  3210. return S_OK;
  3211. }
  3212. STDMETHODIMP CSubStreamVideoRecv::StartSubStream()
  3213. {
  3214. return TAPI_E_NOTSUPPORTED;
  3215. }
  3216. STDMETHODIMP CSubStreamVideoRecv::PauseSubStream()
  3217. {
  3218. return TAPI_E_NOTSUPPORTED;
  3219. }
  3220. STDMETHODIMP CSubStreamVideoRecv::StopSubStream()
  3221. {
  3222. return TAPI_E_NOTSUPPORTED;
  3223. }
  3224. BOOL CSubStreamVideoRecv::GetCurrentParticipant(
  3225. DWORD * pdwSSRC,
  3226. ITParticipant** ppITParticipant
  3227. )
  3228. {
  3229. CLock lock(m_lock);
  3230. if (m_pCurrentParticipant)
  3231. {
  3232. m_pCurrentParticipant->AddRef();
  3233. *ppITParticipant = m_pCurrentParticipant;
  3234. ((CParticipant *)m_pCurrentParticipant)->GetSSRC(
  3235. (ITStream*)m_pStream,
  3236. pdwSSRC
  3237. );
  3238. return TRUE;
  3239. }
  3240. return FALSE;
  3241. }
  3242. VOID CSubStreamVideoRecv::SetCurrentParticipant(
  3243. DWORD dwSSRC,
  3244. ITParticipant * pParticipant
  3245. )
  3246. {
  3247. CLock lock(m_lock);
  3248. if (m_pCurrentParticipant)
  3249. {
  3250. m_pCurrentParticipant->Release();
  3251. }
  3252. m_pCurrentParticipant = pParticipant;
  3253. if (m_pCurrentParticipant)
  3254. {
  3255. m_pCurrentParticipant->AddRef();
  3256. }
  3257. }
  3258. BOOL CSubStreamVideoRecv::ClearCurrentTerminal()
  3259. {
  3260. CLock lock(m_lock);
  3261. if (m_Terminals.GetSize() > 0)
  3262. {
  3263. m_Terminals[0]->Release();
  3264. m_Terminals.RemoveAt(0);
  3265. return TRUE;
  3266. }
  3267. return FALSE;
  3268. }
  3269. BOOL CSubStreamVideoRecv::SetCurrentTerminal(ITTerminal * pTerminal)
  3270. {
  3271. CLock lock(m_lock);
  3272. if (m_Terminals.GetSize() > 0)
  3273. {
  3274. _ASSERTE(FALSE);
  3275. return FALSE;
  3276. }
  3277. BOOL bFlag = m_Terminals.Add(pTerminal);
  3278. // This should never fail since the terminal array has been grown
  3279. // at the init time.
  3280. _ASSERTE(bFlag);
  3281. if (bFlag)
  3282. {
  3283. pTerminal->AddRef();
  3284. return TRUE;
  3285. }
  3286. return FALSE;
  3287. }