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

5372 lines
134 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. /////////////////////////////////////////////////////////////////////////////
  13. //
  14. // CStreamVideoRecv
  15. //
  16. /////////////////////////////////////////////////////////////////////////////
  17. CStreamVideoRecv::CStreamVideoRecv()
  18. : CIPConfMSPStream()
  19. {
  20. m_szName = L"VideoRecv";
  21. }
  22. HRESULT CStreamVideoRecv::Init(
  23. IN HANDLE hAddress,
  24. IN CMSPCallBase * pMSPCall,
  25. IN IMediaEvent * pIGraphBuilder,
  26. IN DWORD dwMediaType,
  27. IN TERMINAL_DIRECTION Direction
  28. )
  29. /*++
  30. Routine Description:
  31. Init our substream array and then call the base class' Init.
  32. Arguments:
  33. hAddress - a handle to the address, used in identify terminals.
  34. pMSPCall - the call object that owns the stream.
  35. pIGraphBuilder - the filter graph object.
  36. dwMediaType - the mediatype of this stream.
  37. Direction - the direction of this stream.
  38. Return Value:
  39. S_OK,
  40. E_OUTOFMEMORY
  41. --*/
  42. {
  43. LOG((MSP_TRACE, "CStreamVideoRecvVideoSend::Init - enter"));
  44. // initialize the stream array so that the array is not NULL.
  45. if (!m_SubStreams.Grow())
  46. {
  47. LOG((MSP_TRACE, "CStreamVideoRecvVideoSend::Init - return out of memory"));
  48. return E_OUTOFMEMORY;
  49. }
  50. return CIPConfMSPStream::Init(
  51. hAddress, pMSPCall, pIGraphBuilder,dwMediaType, Direction
  52. );
  53. }
  54. HRESULT CStreamVideoRecv::ShutDown()
  55. /*++
  56. Routine Description:
  57. Shut down the stream.
  58. Arguments:
  59. Return Value:
  60. S_OK
  61. --*/
  62. {
  63. CLock lock(m_lock);
  64. // if there are terminals
  65. BOOL fHasTerminal = FALSE;
  66. if (m_Terminals.GetSize() > 0)
  67. {
  68. fHasTerminal = TRUE;
  69. }
  70. // if graph is running
  71. HRESULT hr;
  72. OAFilterState FilterState = State_Stopped;
  73. if (m_pIMediaControl)
  74. {
  75. if (FAILED (hr = m_pIMediaControl->GetState(0, &FilterState)))
  76. {
  77. LOG ((MSP_ERROR, "CStreamAudioRecv::ShutDown failed to query filter state. %d", hr));
  78. FilterState = State_Stopped;
  79. }
  80. }
  81. // if there are branches and configured, we need to disconnect
  82. // the terminals and remove the branches.
  83. if (m_Branches.GetSize() > 0)
  84. {
  85. // Stop the graph before disconnecting the terminals.
  86. hr = CMSPStream::StopStream();
  87. if (FAILED(hr))
  88. {
  89. LOG((MSP_ERROR,
  90. "stream %ws %p failed to stop, %x", m_szName, this, hr));
  91. return hr;
  92. }
  93. for (int i = 0; i < m_Branches.GetSize(); i ++)
  94. {
  95. RemoveOneBranch(&m_Branches[i]);
  96. }
  97. m_Branches.RemoveAll();
  98. }
  99. // release all the substream objects.
  100. for (int i = 0; i < m_SubStreams.GetSize(); i ++)
  101. {
  102. m_SubStreams[i]->Release();
  103. }
  104. m_SubStreams.RemoveAll();
  105. // fire event
  106. if (fHasTerminal && FilterState == State_Running)
  107. {
  108. SendStreamEvent(CALL_STREAM_INACTIVE, CALL_CAUSE_LOCAL_REQUEST, 0, NULL);
  109. }
  110. return CIPConfMSPStream::ShutDown();
  111. }
  112. HRESULT CStreamVideoRecv::InternalCreateSubStream(
  113. OUT ITSubStream ** ppSubStream
  114. )
  115. /*++
  116. Routine Description:
  117. This method creat a substream object and add it into out list.
  118. Arguments:
  119. ppSubStream - the memory location that will store the returned SubStream.
  120. Return Value:
  121. S_OK
  122. E_OUTOFMEMORY
  123. E_NOINTERFACE
  124. --*/
  125. {
  126. CComObject<CSubStreamVideoRecv> * pCOMSubStream;
  127. HRESULT hr;
  128. hr = ::CreateCComObjectInstance(&pCOMSubStream);
  129. if (NULL == pCOMSubStream)
  130. {
  131. LOG((MSP_ERROR, "could not create video recv sub stream:%x", hr));
  132. return hr;
  133. }
  134. ITSubStream* pSubStream;
  135. // get the interface pointer.
  136. hr = pCOMSubStream->_InternalQueryInterface(
  137. __uuidof(ITSubStream),
  138. (void **)&pSubStream
  139. );
  140. if (FAILED(hr))
  141. {
  142. LOG((MSP_ERROR, "Create VideoRecv Substream QueryInterface failed: %x", hr));
  143. delete pCOMSubStream;
  144. return hr;
  145. }
  146. // Initialize the object.
  147. hr = pCOMSubStream->Init(this);
  148. if (FAILED(hr))
  149. {
  150. LOG((MSP_ERROR, "CreateMSPSubStream:call init failed: %x", hr));
  151. pSubStream->Release();
  152. return hr;
  153. }
  154. // Add the SubStream into our list of SubStreams. This takes a refcount.
  155. if (!m_SubStreams.Add(pSubStream))
  156. {
  157. pSubStream->Release();
  158. LOG((MSP_ERROR, "out of memory in adding a SubStream."));
  159. return E_OUTOFMEMORY;
  160. }
  161. // AddRef the interface pointer and return it.
  162. pSubStream->AddRef();
  163. *ppSubStream = pSubStream;
  164. return S_OK;
  165. }
  166. // ITStream method
  167. STDMETHODIMP CStreamVideoRecv::StopStream ()
  168. {
  169. ENTER_FUNCTION ("CStreamVideoRecv::StopStream");
  170. HRESULT hr;
  171. CLock lock (m_lock);
  172. // copy stopstream from ipconfmsp because
  173. // we want to generate unmap event before stream inactive event
  174. // if there is no terminal selected
  175. if (m_Terminals.GetSize() == 0)
  176. {
  177. LOG((MSP_INFO, "stream %ws %p needs terminal", m_szName, this));
  178. // Enter stopped state. (SO)
  179. m_dwState = STRM_STOPPED;
  180. return S_OK;
  181. }
  182. if (!m_fIsConfigured)
  183. {
  184. LOG((MSP_INFO, "stream %ws %p is not configured yet", m_szName, this));
  185. // Enter stopped state. (SO, ST)
  186. m_dwState = STRM_STOPPED;
  187. return S_OK;
  188. }
  189. // Stop the graph.
  190. if (FAILED (hr = CMSPStream::StopStream()))
  191. {
  192. LOG((MSP_ERROR, "stream %ws %p failed to stop, %x", m_szName, this, hr));
  193. return hr;
  194. }
  195. // check if we have filter chain
  196. CComPtr <IFilterChain> pIFilterChain;
  197. // Query IFilterChain
  198. hr = m_pIMediaControl->QueryInterface(
  199. __uuidof(IFilterChain),
  200. (void**)&pIFilterChain
  201. );
  202. if (FAILED (hr) && (hr != E_NOINTERFACE))
  203. {
  204. LOG ((MSP_ERROR, "stream %ws %p failted to get filter chain. %x", m_szName, this, hr));
  205. return hr;
  206. }
  207. if (pIFilterChain)
  208. {
  209. DWORD dwSSRC = 0;
  210. ITParticipant *pParticipant = NULL;
  211. INT count, next;
  212. next = m_SubStreams.GetSize ();
  213. // generate participant leave
  214. while ((count = next) > 0)
  215. {
  216. if (!((CSubStreamVideoRecv*)m_SubStreams[0])->GetCurrentParticipant (&dwSSRC, &pParticipant))
  217. {
  218. LOG ((MSP_ERROR, "%s failed to get current participant on %p", __fxName, m_SubStreams[0]));
  219. return E_UNEXPECTED;
  220. }
  221. pParticipant->Release ();
  222. if (FAILED (hr = ProcessParticipantLeave (dwSSRC)))
  223. {
  224. LOG ((MSP_ERROR, "%s failed to process participant leave. ssrc=%x, hr=%x", __fxName, dwSSRC, hr));
  225. return hr;
  226. }
  227. next = m_SubStreams.GetSize ();
  228. if (next >= count)
  229. {
  230. // no substream was removed. we have big trouble
  231. LOG ((MSP_ERROR, "%s: not substream was removed", __fxName));
  232. return E_UNEXPECTED;
  233. }
  234. }
  235. for (int i = 0; i < m_Branches.GetSize(); i ++)
  236. {
  237. if (!m_Branches[i].pITSubStream) continue;
  238. if (FAILED (hr = ProcessPinUnmapEvent (
  239. m_Branches[i].dwSSRC, m_Branches[i].pIPin)))
  240. {
  241. LOG ((MSP_ERROR, "%s (%ws) failed to process pin unmap event. %x", __fxName, m_szName, hr));
  242. }
  243. }
  244. }
  245. SendStreamEvent(CALL_STREAM_INACTIVE, CALL_CAUSE_LOCAL_REQUEST, 0, NULL);
  246. LOG((MSP_INFO, "stream %ws %p stopped", m_szName, this));
  247. // Enter stopped state.(ST)
  248. m_dwState = STRM_STOPPED;
  249. return S_OK;
  250. }
  251. // ITSubStreamControl methods, called by the app.
  252. STDMETHODIMP CStreamVideoRecv::CreateSubStream(
  253. IN OUT ITSubStream ** ppSubStream
  254. )
  255. /*++
  256. Routine Description:
  257. This method creates a new substream on this video receive stream. Since
  258. the substreams are created based on the participants, this function
  259. returns only TAPI_E_NOTSUPPORTED.
  260. Arguments:
  261. ppSubStream - the memory location that will store the returned SubStream.
  262. Return Value:
  263. TAPI_E_NOTSUPPORTED
  264. --*/
  265. {
  266. return TAPI_E_NOTSUPPORTED;
  267. }
  268. STDMETHODIMP CStreamVideoRecv::RemoveSubStream(
  269. IN ITSubStream * pSubStream
  270. )
  271. /*++
  272. Routine Description:
  273. This method remove substream on this video receive stream. Since
  274. the substreams are created based on the participants, this function
  275. returns only TAPI_E_NOTSUPPORTED.
  276. Arguments:
  277. pSubStream - the SubStream to be removed.
  278. Return Value:
  279. TAPI_E_NOTSUPPORTED
  280. --*/
  281. {
  282. return TAPI_E_NOTSUPPORTED;
  283. }
  284. STDMETHODIMP CStreamVideoRecv::EnumerateSubStreams(
  285. OUT IEnumSubStream ** ppEnumSubStream
  286. )
  287. /*++
  288. Routine Description:
  289. This method returns an enumerator of the substreams.
  290. Arguments:
  291. ppEnumSubStream - the memory location to store the returned pointer.
  292. Return Value:
  293. S_OK
  294. E_POINTER
  295. E_UNEXPECTED
  296. E_OUTOFMEMORY
  297. --*/
  298. {
  299. LOG((MSP_TRACE,
  300. "EnumerateSubStreams entered. ppEnumSubStream:%x", ppEnumSubStream));
  301. //
  302. // Check parameters.
  303. //
  304. if (IsBadWritePtr(ppEnumSubStream, sizeof(VOID *)))
  305. {
  306. LOG((MSP_ERROR, "CMSPCallBase::EnumerateSubStreams - "
  307. "bad pointer argument - exit E_POINTER"));
  308. return E_POINTER;
  309. }
  310. //
  311. // First see if this call has been shut down.
  312. // acquire the lock before accessing the SubStream object list.
  313. //
  314. CLock lock(m_lock);
  315. if (m_SubStreams.GetData() == NULL)
  316. {
  317. LOG((MSP_ERROR, "CMSPCallBase::EnumerateSubStreams - "
  318. "call appears to have been shut down - exit E_UNEXPECTED"));
  319. // This call has been shut down.
  320. return E_UNEXPECTED;
  321. }
  322. //
  323. // Create an enumerator object.
  324. //
  325. HRESULT hr;
  326. typedef _CopyInterface<ITSubStream> CCopy;
  327. typedef CSafeComEnum<IEnumSubStream, &__uuidof(IEnumSubStream),
  328. ITSubStream *, CCopy> CEnumerator;
  329. CComObject<CEnumerator> *pEnum = NULL;
  330. hr = ::CreateCComObjectInstance(&pEnum);
  331. if (pEnum == NULL)
  332. {
  333. LOG((MSP_ERROR, "CMSPCallBase::EnumerateSubStreams - "
  334. "Could not create enumerator object, %x", hr));
  335. return hr;
  336. }
  337. //
  338. // query for the __uuidof(IEnumSubStream) i/f
  339. //
  340. IEnumSubStream * pEnumSubStream;
  341. hr = pEnum->_InternalQueryInterface(__uuidof(IEnumSubStream), (void**)&pEnumSubStream);
  342. if (FAILED(hr))
  343. {
  344. LOG((MSP_ERROR, "CMSPCallBase::EnumerateSubStreams - "
  345. "query enum interface failed, %x", hr));
  346. delete pEnum;
  347. return hr;
  348. }
  349. //
  350. // Init the enumerator object. The CSafeComEnum can handle zero-sized array.
  351. //
  352. hr = pEnum->Init(
  353. m_SubStreams.GetData(), // the begin itor
  354. m_SubStreams.GetData() + m_SubStreams.GetSize(), // the end itor,
  355. NULL, // IUnknown
  356. AtlFlagCopy // copy the data.
  357. );
  358. if (FAILED(hr))
  359. {
  360. LOG((MSP_ERROR, "CMSPCallBase::EnumerateSubStreams - "
  361. "init enumerator object failed, %x", hr));
  362. pEnumSubStream->Release();
  363. return hr;
  364. }
  365. LOG((MSP_TRACE, "CMSPCallBase::EnumerateSubStreams - exit S_OK"));
  366. *ppEnumSubStream = pEnumSubStream;
  367. return hr;
  368. }
  369. STDMETHODIMP CStreamVideoRecv::get_SubStreams(
  370. OUT VARIANT * pVariant
  371. )
  372. /*++
  373. Routine Description:
  374. This method returns a collection of the substreams.
  375. Arguments:
  376. pVariant - a variant structure.
  377. Return Value:
  378. S_OK
  379. E_POINTER
  380. E_UNEXPECTED
  381. E_OUTOFMEMORY
  382. --*/
  383. {
  384. LOG((MSP_TRACE, "CStreamVideoRecv::get_SubStreams - enter"));
  385. //
  386. // Check parameters.
  387. //
  388. if ( IsBadWritePtr(pVariant, sizeof(VARIANT) ) )
  389. {
  390. LOG((MSP_ERROR, "CStreamVideoRecv::get_SubStreams - "
  391. "bad pointer argument - exit E_POINTER"));
  392. return E_POINTER;
  393. }
  394. //
  395. // See if this call has been shut down. Acquire the lock before accessing
  396. // the SubStream object list.
  397. //
  398. CLock lock(m_lock);
  399. if (m_SubStreams.GetData() == NULL)
  400. {
  401. LOG((MSP_ERROR, "CStreamVideoRecv::get_SubStreams - "
  402. "call appears to have been shut down - exit E_UNEXPECTED"));
  403. // This call has been shut down.
  404. return E_UNEXPECTED;
  405. }
  406. //
  407. // create the collection object - see mspcoll.h
  408. //
  409. typedef CTapiIfCollection< ITSubStream * > SubStreamCollection;
  410. CComObject<SubStreamCollection> * pCollection;
  411. HRESULT hr;
  412. hr = ::CreateCComObjectInstance(&pCollection);
  413. if ( FAILED(hr) )
  414. {
  415. LOG((MSP_ERROR, "CStreamVideoRecv::get_SubStreams - "
  416. "can't create collection - exit 0x%08x", hr));
  417. return hr;
  418. }
  419. //
  420. // get the Collection's IDispatch interface
  421. //
  422. IDispatch * pDispatch;
  423. hr = pCollection->_InternalQueryInterface(__uuidof(IDispatch),
  424. (void **) &pDispatch );
  425. if ( FAILED(hr) )
  426. {
  427. LOG((MSP_ERROR, "CStreamVideoRecv::get_SubStreams - "
  428. "QI for IDispatch on collection failed - exit 0x%08x", hr));
  429. delete pCollection;
  430. return hr;
  431. }
  432. //
  433. // Init the collection using an iterator -- pointers to the beginning and
  434. // the ending element plus one.
  435. //
  436. hr = pCollection->Initialize( m_SubStreams.GetSize(),
  437. m_SubStreams.GetData(),
  438. m_SubStreams.GetData() + m_SubStreams.GetSize() );
  439. if (FAILED(hr))
  440. {
  441. LOG((MSP_ERROR, "CStreamVideoRecv::get_SubStreams - "
  442. "Initialize on collection failed - exit 0x%08x", hr));
  443. pDispatch->Release();
  444. return hr;
  445. }
  446. //
  447. // put the IDispatch interface pointer into the variant
  448. //
  449. VariantInit(pVariant);
  450. pVariant->vt = VT_DISPATCH;
  451. pVariant->pdispVal = pDispatch;
  452. LOG((MSP_TRACE, "CStreamVideoRecv::get_SubStreams - exit S_OK"));
  453. return S_OK;
  454. }
  455. HRESULT CStreamVideoRecv::CheckTerminalTypeAndDirection(
  456. IN ITTerminal * pTerminal
  457. )
  458. /*++
  459. Routine Description:
  460. Check to see if the terminal is allowed on this stream. Only video
  461. render terminal is allowed.
  462. Arguments:
  463. pTerminal - the terminal.
  464. Return value:
  465. S_OK
  466. TAPI_E_INVALIDTERMINAL
  467. */
  468. {
  469. LOG((MSP_TRACE, "VideoRecv.CheckTerminalTypeAndDirection"));
  470. // check the media type of this terminal.
  471. long lMediaType;
  472. HRESULT hr = pTerminal->get_MediaType(&lMediaType);
  473. if (FAILED(hr))
  474. {
  475. LOG((MSP_ERROR, "can't get terminal media type. %x", hr));
  476. return TAPI_E_INVALIDTERMINAL;
  477. }
  478. if ((DWORD)lMediaType != m_dwMediaType)
  479. {
  480. return TAPI_E_INVALIDTERMINAL;
  481. }
  482. // check the direction of this terminal.
  483. TERMINAL_DIRECTION Direction;
  484. hr = pTerminal->get_Direction(&Direction);
  485. if (FAILED(hr))
  486. {
  487. LOG((MSP_ERROR, "can't get terminal direction. %x", hr));
  488. return TAPI_E_INVALIDTERMINAL;
  489. }
  490. if (Direction != TD_BIDIRECTIONAL && Direction != m_Direction)
  491. {
  492. return TAPI_E_INVALIDTERMINAL;
  493. }
  494. return S_OK;
  495. }
  496. HRESULT CStreamVideoRecv::SubStreamSelectTerminal(
  497. IN ITSubStream * pITSubStream,
  498. IN ITTerminal * pITTerminal
  499. )
  500. /*++
  501. Routine Description:
  502. handle terminals being selected on the sub streams. It gives the terminal
  503. to one free branch and then sets up a mapping between the branch and the
  504. substream, so that the participant in the substream is displayed on the
  505. terminal selected.
  506. Arguments:
  507. pITSubStream - the Substream that got a terminal selected.
  508. pITTerminal - the terminal object.
  509. Return Value:
  510. S_OK
  511. --*/
  512. {
  513. LOG((MSP_TRACE, "VideoRecv SubStreamSelectTerminal"));
  514. HRESULT hr;
  515. CLock lock(m_lock);
  516. // Call the base class's select terminal first. The terminal will be put
  517. // into the terminal pool and a branch of filters will be created for it.
  518. hr = CIPConfMSPStream::SelectTerminal(pITTerminal);
  519. if (FAILED(hr))
  520. {
  521. return hr;
  522. }
  523. // Find out which branch got the terminal.
  524. int i;
  525. for (i = 0; i < m_Branches.GetSize(); i ++)
  526. {
  527. if (m_Branches[i].pITTerminal == pITTerminal)
  528. {
  529. break;
  530. }
  531. }
  532. _ASSERTE(i < m_Branches.GetSize());
  533. if (i >= m_Branches.GetSize())
  534. {
  535. return E_UNEXPECTED;
  536. }
  537. // Find out the participant on the SubStream.
  538. ITParticipant *pITParticipant = NULL;
  539. DWORD dwSSRC;
  540. if ((static_cast<CSubStreamVideoRecv*>(pITSubStream))->GetCurrentParticipant(
  541. &dwSSRC,
  542. &pITParticipant
  543. ) == FALSE)
  544. {
  545. return E_UNEXPECTED;
  546. }
  547. pITParticipant->Release();
  548. if (m_pIRTPDemux == NULL)
  549. {
  550. LOG((MSP_ERROR, "no demux filter"));
  551. return E_UNEXPECTED;
  552. }
  553. // map the pin to this SSRC only.
  554. hr = m_pIRTPDemux->SetMappingState(-1, m_Branches[i].pIPin, dwSSRC, TRUE);
  555. if (FAILED(hr))
  556. {
  557. LOG((MSP_ERROR, "map SSRC %x to pin %p returned %x",
  558. dwSSRC, m_Branches[i].pIPin, hr));
  559. return hr;
  560. }
  561. _ASSERTE(m_Branches[i].pITSubStream == NULL);
  562. pITSubStream->AddRef();
  563. m_Branches[i].pITSubStream = pITSubStream;
  564. m_Branches[i].dwSSRC = dwSSRC;
  565. return hr;
  566. }
  567. HRESULT CStreamVideoRecv::ConfigureRTPFormats(
  568. IN IBaseFilter * pIRTPFilter,
  569. IN IStreamConfig * pIStreamConfig
  570. )
  571. /*++
  572. Routine Description:
  573. Configure the RTP filter with RTP<-->AM media type mappings.
  574. Arguments:
  575. pIRTPFilter - The source RTP Filter.
  576. pIStreamConfig - The stream config interface that has the media info.
  577. Return Value:
  578. HRESULT.
  579. --*/
  580. {
  581. ENTER_FUNCTION("VideoRecv::ConfigureRTPFormats");
  582. LOG((MSP_TRACE, "%s enters", __fxName));
  583. HRESULT hr;
  584. CComPtr<IRtpMediaControl> pIRtpMediaControl;
  585. hr = pIRTPFilter->QueryInterface(&pIRtpMediaControl);
  586. if (FAILED(hr))
  587. {
  588. LOG((MSP_ERROR, "%s adding source filter. %x", __fxName, hr));
  589. return hr;
  590. }
  591. // find the number of capabilities supported.
  592. DWORD dwCount;
  593. hr = pIStreamConfig->GetNumberOfCapabilities(&dwCount);
  594. if (FAILED(hr))
  595. {
  596. LOG((MSP_ERROR, "%s GetNumberOfCapabilities. %x", __fxName, hr));
  597. return hr;
  598. }
  599. BOOL fFound = FALSE;
  600. for (int i = dwCount - 1; i >= 0; i --)
  601. {
  602. // TODO, a new interface is needed to resolve RTP to MediaType.
  603. AM_MEDIA_TYPE *pMediaType;
  604. DWORD dwPayloadType;
  605. hr = pIStreamConfig->GetStreamCaps(
  606. i, &pMediaType, NULL, &dwPayloadType
  607. );
  608. if (FAILED(hr))
  609. {
  610. LOG((MSP_ERROR, "%s GetStreamCaps. %x", __fxName, hr));
  611. return hr;
  612. }
  613. BITMAPINFOHEADER *pHeader = HEADER(pMediaType->pbFormat);
  614. if (pHeader == NULL)
  615. {
  616. MSPDeleteMediaType(pMediaType);
  617. continue;
  618. }
  619. // check the image size
  620. if (m_Settings.fCIF)
  621. {
  622. if (pHeader->biWidth != CIFWIDTH)
  623. {
  624. MSPDeleteMediaType(pMediaType);
  625. continue;
  626. }
  627. }
  628. else
  629. {
  630. if (pHeader->biWidth != QCIFWIDTH)
  631. {
  632. MSPDeleteMediaType(pMediaType);
  633. continue;
  634. }
  635. }
  636. for (DWORD dw2 = 0; dw2 < m_Settings.dwNumPayloadTypes; dw2 ++)
  637. {
  638. if (dwPayloadType == m_Settings.PayloadTypes[dw2])
  639. {
  640. hr = pIRtpMediaControl->SetFormatMapping(
  641. dwPayloadType,
  642. 90000, // default video clock rate.
  643. pMediaType
  644. );
  645. if (FAILED(hr))
  646. {
  647. MSPDeleteMediaType(pMediaType);
  648. LOG((MSP_ERROR, "%s SetFormatMapping. %x", __fxName, hr));
  649. return hr;
  650. }
  651. else
  652. {
  653. LOG((MSP_INFO, "%s Configured payload:%d", __fxName, dwPayloadType));
  654. }
  655. }
  656. }
  657. MSPDeleteMediaType(pMediaType);
  658. }
  659. return S_OK;
  660. }
  661. HRESULT CStreamVideoRecv::SetUpInternalFilters()
  662. /*++
  663. Routine Description:
  664. set up the filters used in the stream.
  665. RTP->DECODER->Render terminal
  666. This function only creates the RTP and demux filter and the rest of the
  667. graph is connected in ConnectTerminal.
  668. Arguments:
  669. Return Value:
  670. HRESULT.
  671. --*/
  672. {
  673. ENTER_FUNCTION("CStreamVideoRecv::SetUpInternalFilters");
  674. LOG((MSP_TRACE, "%s entered.", __fxName));
  675. HRESULT hr = S_OK;
  676. if (m_pIRTPDemux == NULL)
  677. {
  678. CComPtr<IBaseFilter> pSourceFilter;
  679. if (m_pIRTPSession == NULL)
  680. {
  681. // create and add the source fitler.
  682. if (FAILED(hr = ::AddFilter(
  683. m_pIGraphBuilder,
  684. __uuidof(MSRTPSourceFilter),
  685. L"RtpSource",
  686. &pSourceFilter)))
  687. {
  688. LOG((MSP_ERROR, "%s, adding source filter. %x", __fxName, hr));
  689. return hr;
  690. }
  691. if (FAILED(hr = ConfigureRTPFilter(pSourceFilter)))
  692. {
  693. LOG((MSP_ERROR, "%s, configure RTP source filter. %x", __fxName, hr));
  694. return hr;
  695. }
  696. }
  697. else
  698. {
  699. if (FAILED (hr = m_pIRTPSession->QueryInterface (&pSourceFilter)))
  700. {
  701. LOG ((MSP_ERROR, "%s failed to get filter from rtp session. %x", __fxName, hr));
  702. return hr;
  703. }
  704. if (FAILED (hr = m_pIGraphBuilder->AddFilter ((IBaseFilter *)pSourceFilter, L"RtpSource")))
  705. {
  706. LOG ((MSP_ERROR, "%s failed to add filter to graph. %x", __fxName, hr));
  707. return hr;
  708. }
  709. }
  710. // get the Demux interface pointer.
  711. hr = pSourceFilter->QueryInterface(&m_pIRTPDemux);
  712. if (FAILED(hr))
  713. {
  714. LOG((MSP_ERROR, "%s query IRtpDemux failed. %x", __fxName, hr));
  715. return hr;
  716. }
  717. }
  718. // hr = m_pIRTPDemux->SetPinCount(m_Terminals.GetSize(), RTPDMXMODE_AUTO);
  719. #define DEFAULT_PIN_SIZE 4
  720. int isize = m_Terminals.GetSize();
  721. if (isize < DEFAULT_PIN_SIZE)
  722. {
  723. isize = DEFAULT_PIN_SIZE;
  724. }
  725. hr = m_pIRTPDemux->SetPinCount(isize, RTPDMXMODE_AUTO);
  726. if (FAILED(hr))
  727. {
  728. LOG((MSP_ERROR, "%s query IRtpDemux failed. %x", __fxName, hr));
  729. return hr;
  730. }
  731. return hr;
  732. }
  733. HRESULT CStreamVideoRecv::AddOneBranch(
  734. BRANCH * pBranch,
  735. BOOL fFirstBranch,
  736. BOOL fDirectRTP
  737. )
  738. /*++
  739. Routine Description:
  740. Create a new branch of filters off the demux.
  741. Arguments:
  742. pBranch - a pointer to a structure that remembers the info about the branch.
  743. fFirstBranch - whether this is the first branch.
  744. fDirectRTP - whether to output RTP directly.
  745. Return Value:
  746. HRESULT.
  747. --*/
  748. {
  749. ENTER_FUNCTION("CStreamVideoRecv::AddOneBranch");
  750. LOG((MSP_TRACE, "%s entered.", __fxName));
  751. HRESULT hr;
  752. _ASSERT(m_pIRTPDemux != NULL);
  753. CComPtr<IBaseFilter> pRTPFilter;
  754. hr = m_pIRTPDemux->QueryInterface(
  755. __uuidof(IBaseFilter), (void**)&pRTPFilter);
  756. if (FAILED(hr))
  757. {
  758. LOG((MSP_ERROR, "%s, query IBaseFilter failed, %x", __fxName, hr));
  759. return hr;
  760. }
  761. // Find the next output pin on the demux fitler.
  762. CComPtr<IPin> pIPinOutput;
  763. if (FAILED(hr = ::FindPin(
  764. (IBaseFilter *)pRTPFilter,
  765. (IPin**)&pIPinOutput,
  766. PINDIR_OUTPUT
  767. )))
  768. {
  769. LOG((MSP_ERROR, "%s, find free pin on demux, %x", __fxName, hr));
  770. return hr;
  771. }
  772. // create and add the video decoder filter.
  773. CComPtr<IBaseFilter> pCodecFilter;
  774. if (fDirectRTP)
  775. {
  776. // only create the decoder and ask questions
  777. if (FAILED(hr = CoCreateInstance(
  778. __uuidof(TAPIVideoDecoder),
  779. NULL,
  780. CLSCTX_INPROC_SERVER | CLSCTX_NO_CODE_DOWNLOAD,
  781. __uuidof(IBaseFilter),
  782. (void **) &pCodecFilter
  783. )))
  784. {
  785. LOG((MSP_ERROR, "%s, create filter %x", __fxName, hr));
  786. return hr;
  787. }
  788. }
  789. else
  790. {
  791. // create the decoder and add it into the graph.
  792. if (FAILED(hr = ::AddFilter(
  793. m_pIGraphBuilder,
  794. __uuidof(TAPIVideoDecoder),
  795. L"codec",
  796. &pCodecFilter
  797. )))
  798. {
  799. LOG((MSP_ERROR, "%s, add Codec filter. %x", __fxName, hr));
  800. return hr;
  801. }
  802. }
  803. CComPtr<IPin> pIPinInput;
  804. if (FAILED(hr = ::FindPin(pCodecFilter, &pIPinInput, PINDIR_INPUT, TRUE)))
  805. {
  806. LOG((MSP_ERROR,
  807. "%s, find input pin on pCodecFilter failed. hr=%x", __fxName, hr));
  808. return hr;
  809. }
  810. if (fFirstBranch)
  811. {
  812. CComPtr<IStreamConfig> pIStreamConfig;
  813. hr = pIPinInput->QueryInterface(&pIStreamConfig);
  814. if (FAILED(hr))
  815. {
  816. LOG((MSP_ERROR, "%s, query IStreamConfig failed", __fxName));
  817. return hr;
  818. }
  819. // configure the format info on the RTP filter
  820. if (FAILED(hr = ConfigureRTPFormats(pRTPFilter, pIStreamConfig)))
  821. {
  822. LOG((MSP_ERROR, "%s configure RTP formats. %x", __fxName, hr));
  823. return hr;
  824. }
  825. }
  826. if (!fDirectRTP)
  827. {
  828. // Connect the decoder to the output pin of the source filter.
  829. if (FAILED(hr = ::ConnectFilters(
  830. m_pIGraphBuilder,
  831. (IPin *)pIPinOutput,
  832. (IBaseFilter *)pCodecFilter
  833. )))
  834. {
  835. LOG((MSP_ERROR, "%s, connect RTP filter and codec. %x", __fxName, hr));
  836. m_pIGraphBuilder->RemoveFilter(pCodecFilter);
  837. return hr;
  838. }
  839. pBranch->pCodecFilter = pCodecFilter;
  840. pBranch->pCodecFilter->AddRef();
  841. }
  842. pBranch->pIPin = pIPinOutput;
  843. pBranch->pIPin->AddRef();
  844. // retrieve IBitrateControl
  845. if (FAILED (hr = pIPinInput->QueryInterface (&(pBranch->pBitrateControl))))
  846. {
  847. LOG((MSP_ERROR, "%, query IBitrateControl failed. %x", __fxName, hr));
  848. pBranch->pBitrateControl = NULL;
  849. // return hr;
  850. }
  851. LOG((MSP_TRACE, "%s, AddOneBranch exits ok.", __fxName));
  852. return S_OK;
  853. }
  854. HRESULT CStreamVideoRecv::RemoveOneBranch(
  855. BRANCH * pBranch
  856. )
  857. /*++
  858. Routine Description:
  859. Remove all the filters in a branch and release all the pointers.
  860. the caller of this function should not use any member of this branch
  861. after this function call.
  862. Arguments:
  863. pBranch - a pointer to a structure that has the info about the branch.
  864. Return Value:
  865. HRESULT.
  866. --*/
  867. {
  868. ENTER_FUNCTION("VideoRecv::RemoveOneBranch");
  869. LOG((MSP_TRACE, "%s entered", __fxName));
  870. if (pBranch->pBitrateControl)
  871. {
  872. pBranch->pBitrateControl->Release();
  873. }
  874. if (pBranch->pIPin)
  875. {
  876. pBranch->pIPin->Release();
  877. }
  878. if (pBranch->pCodecFilter)
  879. {
  880. // #ifdef DYNGRAPH
  881. HRESULT hr;
  882. OAFilterState FilterState;
  883. CComPtr <IFilterChain> pIFilterChain;
  884. // Query IFilterChain
  885. hr = m_pIMediaControl->QueryInterface(
  886. __uuidof(IFilterChain),
  887. (void**)&pIFilterChain
  888. );
  889. if (FAILED (hr) && (hr != E_NOINTERFACE))
  890. {
  891. LOG ((MSP_ERROR, "stream %ws %p failted to get filter chain. %x", m_szName, this, hr));
  892. // return hr;
  893. }
  894. if (pIFilterChain)
  895. {
  896. hr = m_pIMediaControl->GetState(0, &FilterState);
  897. if (FAILED(hr))
  898. {
  899. LOG((MSP_ERROR, "%s get filter graph state failed, %x", __fxName, hr));
  900. }
  901. else
  902. {
  903. // stop the chain before removing filters.
  904. if (FilterState == State_Running)
  905. {
  906. // stop the chain if the graph is in running state.
  907. hr = pIFilterChain->StopChain(pBranch->pCodecFilter, NULL);
  908. if (FAILED(hr))
  909. {
  910. LOG((MSP_ERROR, "%s stop chain failed. hr=%x", __fxName, hr));
  911. }
  912. }
  913. }
  914. }
  915. // #endif
  916. m_pIGraphBuilder->RemoveFilter(pBranch->pCodecFilter);
  917. pBranch->pCodecFilter->Release();
  918. }
  919. if (pBranch->pITTerminal)
  920. {
  921. // get the terminal control interface.
  922. CComQIPtr<ITTerminalControl, &__uuidof(ITTerminalControl)>
  923. pTerminal(pBranch->pITTerminal);
  924. _ASSERTE(pTerminal != NULL);
  925. if (pTerminal != NULL)
  926. {
  927. HRESULT hr = pTerminal->DisconnectTerminal(m_pIGraphBuilder, 0);
  928. LOG((MSP_TRACE,
  929. "%s, terminal %p is disonnected. hr:%x",
  930. __fxName, pBranch->pITTerminal, hr));
  931. }
  932. pBranch->pITTerminal->Release();
  933. }
  934. if (pBranch->pITSubStream)
  935. {
  936. ((CSubStreamVideoRecv*)pBranch->pITSubStream)->
  937. ClearCurrentTerminal();
  938. pBranch->pITSubStream->Release();
  939. }
  940. LOG((MSP_TRACE, "%s, RemoveOneBranch exits ok.", __fxName));
  941. return S_OK;
  942. }
  943. HRESULT CStreamVideoRecv::ConnectPinToTerminal(
  944. IN IPin * pOutputPin,
  945. IN ITTerminal * pITTerminal
  946. )
  947. /*++
  948. Routine Description:
  949. Connect the codec filter to the render filter inside the terminal.
  950. Arguments:
  951. pOutputPin - The last pin before the terminal.
  952. pITTerminal - the terminal object.
  953. Return Value:
  954. HRESULT.
  955. --*/
  956. {
  957. // get the terminal control interface.
  958. CComQIPtr<ITTerminalControl, &__uuidof(ITTerminalControl)>
  959. pTerminal(pITTerminal);
  960. if (pTerminal == NULL)
  961. {
  962. LOG((MSP_ERROR, "can't get Terminal Control interface"));
  963. SendStreamEvent(CALL_TERMINAL_FAIL,
  964. CALL_CAUSE_BAD_DEVICE, E_NOINTERFACE, pITTerminal);
  965. return E_NOINTERFACE;
  966. }
  967. const DWORD MAXPINS = 8;
  968. DWORD dwNumPins = MAXPINS;
  969. IPin * Pins[MAXPINS];
  970. HRESULT hr = pTerminal->ConnectTerminal(
  971. m_pIGraphBuilder, TD_RENDER, &dwNumPins, Pins
  972. );
  973. if (FAILED(hr))
  974. {
  975. LOG((MSP_ERROR, "can't connect to terminal, %x", hr));
  976. SendStreamEvent(CALL_TERMINAL_FAIL,
  977. CALL_CAUSE_CONNECT_FAIL, hr, pITTerminal);
  978. return hr;
  979. }
  980. // the number of pins should never be 0.
  981. if (dwNumPins == 0)
  982. {
  983. LOG((MSP_ERROR, "terminal has no pins."));
  984. SendStreamEvent(CALL_TERMINAL_FAIL,
  985. CALL_CAUSE_BAD_DEVICE, hr, pITTerminal);
  986. pTerminal->DisconnectTerminal(m_pIGraphBuilder, 0);
  987. return E_UNEXPECTED;
  988. }
  989. if (IsBadReadPtr (Pins, dwNumPins * sizeof (IPin*)))
  990. {
  991. LOG((MSP_ERROR, "terminal returned bad pin array"));
  992. SendStreamEvent(CALL_TERMINAL_FAIL, CALL_CAUSE_BAD_DEVICE, hr, pITTerminal);
  993. pTerminal->DisconnectTerminal(m_pIGraphBuilder, 0);
  994. return E_POINTER;
  995. }
  996. for (DWORD i = 0; i < dwNumPins; i++)
  997. {
  998. if (IsBadReadPtr (Pins[i], sizeof (IPin)))
  999. {
  1000. LOG((MSP_ERROR, "terminal returned bad pin. # %d", i));
  1001. SendStreamEvent(CALL_TERMINAL_FAIL, CALL_CAUSE_BAD_DEVICE, hr, pITTerminal);
  1002. pTerminal->DisconnectTerminal(m_pIGraphBuilder, 0);
  1003. return E_POINTER;
  1004. }
  1005. }
  1006. // Connect the codec filter to the video render terminal.
  1007. hr = ::ConnectFilters(
  1008. m_pIGraphBuilder,
  1009. (IBaseFilter *)pOutputPin,
  1010. (IPin *)Pins[0],
  1011. FALSE // use Connect instead of ConnectDirect.
  1012. );
  1013. // release the refcounts on the pins.
  1014. for (DWORD i = 0; i < dwNumPins; i ++)
  1015. {
  1016. Pins[i]->Release();
  1017. }
  1018. if (FAILED(hr))
  1019. {
  1020. LOG((MSP_ERROR, "connect the pin to the terminal. %x", hr));
  1021. pTerminal->DisconnectTerminal(m_pIGraphBuilder, 0);
  1022. return hr;
  1023. }
  1024. //
  1025. // Now we are actually connected. Update our state and perform postconnection
  1026. // (ignore postconnection error code).
  1027. //
  1028. pTerminal->CompleteConnectTerminal();
  1029. return hr;
  1030. }
  1031. HRESULT CStreamVideoRecv::ConnectTerminal(
  1032. IN ITTerminal * pITTerminal
  1033. )
  1034. /*++
  1035. Routine Description:
  1036. connect video render terminal.
  1037. Arguments:
  1038. pITTerminal - The terminal to be connected.
  1039. Return Value:
  1040. HRESULT.
  1041. --*/
  1042. {
  1043. ENTER_FUNCTION("VideoRecv::ConnectTerminal");
  1044. LOG((MSP_TRACE, "%s enters, pTerminal %p", __fxName, pITTerminal));
  1045. HRESULT hr;
  1046. // #ifdef DYNGRAPH
  1047. OAFilterState FilterState;
  1048. CComPtr <IFilterChain> pIFilterChain;
  1049. // Query IFilterChain
  1050. hr = m_pIMediaControl->QueryInterface(
  1051. __uuidof(IFilterChain),
  1052. (void**)&pIFilterChain
  1053. );
  1054. if (FAILED (hr) && (hr != E_NOINTERFACE))
  1055. {
  1056. LOG ((MSP_ERROR, "stream %ws %p failted to get filter chain. %x", m_szName, this, hr));
  1057. return hr;
  1058. }
  1059. hr = m_pIMediaControl->GetState(0, &FilterState);
  1060. if (FAILED(hr))
  1061. {
  1062. LOG((MSP_ERROR, "%s get filter graph state failed, %x", __fxName, hr));
  1063. return hr;
  1064. }
  1065. // #endif
  1066. hr = SetUpInternalFilters();
  1067. if (FAILED(hr))
  1068. {
  1069. LOG((MSP_ERROR, "%s Set up internal filter failed, %x", __fxName, hr));
  1070. CleanUpFilters();
  1071. return hr;
  1072. }
  1073. // get the terminal control interface.
  1074. CComQIPtr<ITTerminalControl, &__uuidof(ITTerminalControl)>
  1075. pTerminal(pITTerminal);
  1076. if (pTerminal == NULL)
  1077. {
  1078. LOG((MSP_ERROR, "can't get Terminal Control interface"));
  1079. SendStreamEvent(CALL_TERMINAL_FAIL,
  1080. CALL_CAUSE_BAD_DEVICE, E_NOINTERFACE, pITTerminal);
  1081. return E_NOINTERFACE;
  1082. }
  1083. const DWORD MAXPINS = 8;
  1084. DWORD dwNumPins = MAXPINS;
  1085. IPin * Pins[MAXPINS];
  1086. hr = pTerminal->ConnectTerminal(
  1087. m_pIGraphBuilder, TD_RENDER, &dwNumPins, Pins
  1088. );
  1089. if (FAILED(hr))
  1090. {
  1091. LOG((MSP_ERROR, "can't connect to terminal, %x", hr));
  1092. SendStreamEvent(CALL_TERMINAL_FAIL,
  1093. CALL_CAUSE_CONNECT_FAIL, hr, pITTerminal);
  1094. return hr;
  1095. }
  1096. // the number of pins should never be 0.
  1097. if (dwNumPins == 0)
  1098. {
  1099. LOG((MSP_ERROR, "terminal has no pins."));
  1100. SendStreamEvent(CALL_TERMINAL_FAIL,
  1101. CALL_CAUSE_BAD_DEVICE, hr, pITTerminal);
  1102. pTerminal->DisconnectTerminal(m_pIGraphBuilder, 0);
  1103. return E_UNEXPECTED;
  1104. }
  1105. if (IsBadReadPtr (Pins, dwNumPins * sizeof (IPin*)))
  1106. {
  1107. LOG((MSP_ERROR, "terminal returned bad pin array"));
  1108. SendStreamEvent(CALL_TERMINAL_FAIL, CALL_CAUSE_BAD_DEVICE, hr, pITTerminal);
  1109. pTerminal->DisconnectTerminal(m_pIGraphBuilder, 0);
  1110. return E_POINTER;
  1111. }
  1112. DWORD i;
  1113. for (i = 0; i < dwNumPins; i++)
  1114. {
  1115. if (IsBadReadPtr (Pins[i], sizeof (IPin)))
  1116. {
  1117. LOG((MSP_ERROR, "terminal returned bad pin. # %d", i));
  1118. SendStreamEvent(CALL_TERMINAL_FAIL, CALL_CAUSE_BAD_DEVICE, hr, pITTerminal);
  1119. pTerminal->DisconnectTerminal(m_pIGraphBuilder, 0);
  1120. return E_POINTER;
  1121. }
  1122. }
  1123. // check the media type supported by input pin on terminal
  1124. BOOL fDirectRTP = FALSE;
  1125. if (S_OK == ::PinSupportsMediaType (
  1126. Pins[0], __uuidof(MEDIATYPE_RTP_Single_Stream)
  1127. ))
  1128. {
  1129. fDirectRTP = TRUE;
  1130. }
  1131. // first create the branch structure needed before the terminal.
  1132. BRANCH aBranch;
  1133. ZeroMemory(&aBranch, sizeof BRANCH);
  1134. hr = AddOneBranch(&aBranch, (m_Branches.GetSize() == 0), fDirectRTP);
  1135. if (FAILED(hr))
  1136. {
  1137. LOG((MSP_ERROR, "%s Set up a new decode branch failed, %x", __fxName, hr));
  1138. pTerminal->DisconnectTerminal(m_pIGraphBuilder, 0);
  1139. return hr;
  1140. }
  1141. CComPtr <IPin> pOutputPin;
  1142. if (fDirectRTP)
  1143. {
  1144. // connect the RTP output pin to the terminal's input pin.
  1145. hr = m_pIGraphBuilder->ConnectDirect(aBranch.pIPin, Pins[0], NULL);
  1146. if (FAILED(hr))
  1147. {
  1148. LOG((MSP_ERROR, "%s connecting codec to terminal failed, %x", __fxName, hr));
  1149. pTerminal->DisconnectTerminal(m_pIGraphBuilder, 0);
  1150. goto cleanup;
  1151. }
  1152. }
  1153. else
  1154. {
  1155. // connect the codec to the terminal
  1156. hr = ConnectFilters(m_pIGraphBuilder, aBranch.pCodecFilter, Pins[0]);
  1157. if (FAILED(hr))
  1158. {
  1159. LOG((MSP_ERROR, "%s connecting codec to terminal failed, %x", __fxName, hr));
  1160. pTerminal->DisconnectTerminal(m_pIGraphBuilder, 0);
  1161. goto cleanup;
  1162. }
  1163. }
  1164. // #ifdef DYNGRAPH
  1165. if (pIFilterChain)
  1166. {
  1167. if (FilterState == State_Running)
  1168. {
  1169. if (fDirectRTP)
  1170. {
  1171. hr = E_UNEXPECTED;
  1172. LOG((MSP_ERROR, "%s can't support this. %x", __fxName, hr));
  1173. goto cleanup;
  1174. }
  1175. hr = pIFilterChain->StartChain(aBranch.pCodecFilter, NULL);
  1176. if (FAILED(hr))
  1177. {
  1178. LOG((MSP_ERROR, "%s start chain failed. hr=%x", __fxName, hr));
  1179. goto cleanup;
  1180. }
  1181. }
  1182. }
  1183. // #endif
  1184. pITTerminal->AddRef();
  1185. aBranch.pITTerminal = pITTerminal;
  1186. if (!m_Branches.Add(aBranch))
  1187. {
  1188. LOG((MSP_ERROR, "%s out of mem.", __fxName));
  1189. hr = E_OUTOFMEMORY;
  1190. goto cleanup;
  1191. }
  1192. // release the refcounts on the pins.
  1193. for (i = 0; i < dwNumPins; i ++)
  1194. {
  1195. Pins[i]->Release();
  1196. }
  1197. //
  1198. // Now we are actually connected. Update our state and perform postconnection
  1199. // (ignore postconnection error code).
  1200. //
  1201. pTerminal->CompleteConnectTerminal();
  1202. return S_OK;
  1203. cleanup:
  1204. // release the refcounts on the pins.
  1205. for (i = 0; i < dwNumPins; i ++)
  1206. {
  1207. Pins[i]->Release();
  1208. }
  1209. // remove the added filters from the graph and disconnect the terminal.
  1210. RemoveOneBranch(&aBranch);
  1211. return hr;
  1212. }
  1213. HRESULT CStreamVideoRecv::DisconnectTerminal(
  1214. IN ITTerminal * pITTerminal
  1215. )
  1216. /*++
  1217. Routine Description:
  1218. Disconnect a terminal. It will remove its filters from the graph and
  1219. also release its references to the graph. A branch of filters is also
  1220. released.
  1221. Arguments:
  1222. pITTerminal - the terminal.
  1223. Return Value:
  1224. HRESULT.
  1225. --*/
  1226. {
  1227. for (int i = 0; i < m_Branches.GetSize(); i ++)
  1228. {
  1229. if (m_Branches[i].pITTerminal == pITTerminal)
  1230. {
  1231. break;
  1232. }
  1233. }
  1234. if (i < m_Branches.GetSize())
  1235. {
  1236. RemoveOneBranch(&m_Branches[i]);
  1237. m_Branches.RemoveAt(i);
  1238. }
  1239. return S_OK;
  1240. }
  1241. HRESULT CStreamVideoRecv::SetUpFilters()
  1242. /*++
  1243. Routine Description:
  1244. Insert filters into the graph and connect to the terminals.
  1245. Arguments:
  1246. Return Value:
  1247. HRESULT.
  1248. --*/
  1249. {
  1250. LOG((MSP_TRACE, "VideoRecv.SetUpFilters"));
  1251. HRESULT hr = SetUpInternalFilters();
  1252. if (FAILED(hr))
  1253. {
  1254. LOG((MSP_ERROR, "Set up internal filter failed, %x", hr));
  1255. CleanUpFilters();
  1256. return hr;
  1257. }
  1258. for (int i = 0; i < m_Terminals.GetSize(); i ++)
  1259. {
  1260. HRESULT hr = ConnectTerminal(m_Terminals[i]);
  1261. if (FAILED(hr))
  1262. {
  1263. return hr;
  1264. }
  1265. }
  1266. return S_OK;
  1267. }
  1268. // ITParticipantSubStreamControl methods, called by the app.
  1269. STDMETHODIMP CStreamVideoRecv::get_SubStreamFromParticipant(
  1270. IN ITParticipant * pITParticipant,
  1271. OUT ITSubStream ** ppITSubStream
  1272. )
  1273. /*++
  1274. Routine Description:
  1275. Find out which substream is rendering the participant.
  1276. Arguments:
  1277. pITParticipant - the participant.
  1278. ppITSubStream - the returned sub stream.
  1279. Return Value:
  1280. S_OK,
  1281. TAPI_E_NOITEMS,
  1282. E_UNEXPECTED
  1283. --*/
  1284. {
  1285. LOG((MSP_TRACE, "get substream from participant:%p", pITParticipant));
  1286. if (IsBadWritePtr(ppITSubStream, sizeof(VOID *)))
  1287. {
  1288. LOG((MSP_ERROR, "ppITSubStream is a bad pointer"));
  1289. return E_POINTER;
  1290. }
  1291. CLock lock(m_lock);
  1292. ITSubStream * pITSubStream = NULL;
  1293. // find out which substream has the participant.
  1294. for (int i = 0; i < m_SubStreams.GetSize(); i ++)
  1295. {
  1296. ITParticipant *pTempParticipant = NULL;
  1297. DWORD dwSSRC;
  1298. ((CSubStreamVideoRecv*)m_SubStreams[i])->GetCurrentParticipant(
  1299. &dwSSRC, &pTempParticipant
  1300. );
  1301. _ASSERTE(pTempParticipant != NULL);
  1302. pTempParticipant->Release(); // we dont' need the ref here.
  1303. if (pITParticipant == pTempParticipant)
  1304. {
  1305. pITSubStream = m_SubStreams[i];
  1306. pITSubStream->AddRef();
  1307. break;
  1308. }
  1309. }
  1310. if (pITSubStream == NULL)
  1311. {
  1312. return TAPI_E_NOITEMS;
  1313. }
  1314. *ppITSubStream = pITSubStream;
  1315. return S_OK;
  1316. }
  1317. STDMETHODIMP CStreamVideoRecv::get_ParticipantFromSubStream(
  1318. IN ITSubStream * pITSubStream,
  1319. OUT ITParticipant ** ppITParticipant
  1320. )
  1321. /*++
  1322. Routine Description:
  1323. Find out which participant the substream is rendering.
  1324. Arguments:
  1325. pITSubStream - the sub stream.
  1326. ppITParticipant - the returned participant
  1327. Return Value:
  1328. S_OK,
  1329. TAPI_E_NOITEMS,
  1330. E_UNEXPECTED
  1331. --*/
  1332. {
  1333. LOG((MSP_TRACE, "get participant from substream:%p", pITSubStream));
  1334. if (IsBadWritePtr(ppITParticipant, sizeof(VOID *)))
  1335. {
  1336. LOG((MSP_ERROR, "ppITParticipant is a bad pointer"));
  1337. return E_POINTER;
  1338. }
  1339. CLock lock(m_lock);
  1340. int i;
  1341. // check to see if the substream is in our list.
  1342. if ((i = m_SubStreams.Find(pITSubStream)) < 0)
  1343. {
  1344. LOG((MSP_ERROR, "wrong SubStream handle %p", pITSubStream));
  1345. return E_INVALIDARG;
  1346. }
  1347. ITParticipant *pITParticipant;
  1348. DWORD dwSSRC;
  1349. if (((CSubStreamVideoRecv*)m_SubStreams[i])->GetCurrentParticipant(
  1350. &dwSSRC, &pITParticipant
  1351. ) == FALSE)
  1352. {
  1353. return TAPI_E_NOITEMS;
  1354. }
  1355. *ppITParticipant = pITParticipant;
  1356. return S_OK;
  1357. }
  1358. STDMETHODIMP CStreamVideoRecv::SwitchTerminalToSubStream(
  1359. IN ITTerminal * pITTerminal,
  1360. IN ITSubStream * pITSubStream
  1361. )
  1362. /*++
  1363. Routine Description:
  1364. Switch terminal to a substream to display the participant that is on the
  1365. substream.
  1366. Arguments:
  1367. pITTerminal - the terminal.
  1368. pITSubStream - the sub stream.
  1369. Return Value:
  1370. S_OK,
  1371. E_INVALIDARG,
  1372. E_UNEXPECTED
  1373. --*/
  1374. {
  1375. LOG((MSP_TRACE, "switch terminal %p to substream:%p",
  1376. pITTerminal, pITSubStream));
  1377. CLock lock(m_lock);
  1378. if (m_pIRTPDemux == NULL)
  1379. {
  1380. LOG((MSP_ERROR, "the demux filter doesn't exist."));
  1381. return E_UNEXPECTED;
  1382. }
  1383. // first, find out which branch has the terminal now.
  1384. for (int i = 0; i < m_Branches.GetSize(); i ++)
  1385. {
  1386. if (m_Branches[i].pITTerminal == pITTerminal)
  1387. {
  1388. break;
  1389. }
  1390. }
  1391. if (i >= m_Branches.GetSize())
  1392. {
  1393. LOG((MSP_TRACE, "terminal %p doesn't exist", pITTerminal));
  1394. return E_INVALIDARG;
  1395. }
  1396. // second, find out if the substream exists.
  1397. if (m_SubStreams.Find(pITSubStream) < 0)
  1398. {
  1399. LOG((MSP_TRACE, "SubStream %p doesn't exist", pITSubStream));
  1400. return E_INVALIDARG;
  1401. }
  1402. // thrid, find the participant on the substream and configure the demux
  1403. // filter to render the participant on the chosen branch.
  1404. ITParticipant *pITParticipant = NULL;
  1405. DWORD dwSSRC;
  1406. ((CSubStreamVideoRecv*)pITSubStream)->GetCurrentParticipant(
  1407. &dwSSRC, &pITParticipant
  1408. ) ;
  1409. _ASSERTE(pITParticipant != NULL);
  1410. // we don't need the reference here.
  1411. pITParticipant->Release();
  1412. // map the pin to this SSRC only.
  1413. HRESULT hr = m_pIRTPDemux->SetMappingState(
  1414. -1, m_Branches[i].pIPin, dwSSRC, TRUE
  1415. );
  1416. if (FAILED(hr))
  1417. {
  1418. LOG((MSP_ERROR, "map SSRC %x to pin %p returned %x",
  1419. dwSSRC, m_Branches[i].pIPin, hr));
  1420. return hr;
  1421. }
  1422. DWORD dwOldSSRC = 0;
  1423. // Finally, set up the mappings among the branch, the substream and
  1424. // the terminal
  1425. // release the refcount on the old branch that the substream was on.
  1426. for (int j = 0; j < m_Branches.GetSize(); j ++)
  1427. {
  1428. if (m_Branches[j].pITSubStream == pITSubStream)
  1429. {
  1430. m_Branches[j].pITSubStream->Release();
  1431. m_Branches[j].pITSubStream = NULL;
  1432. break;
  1433. }
  1434. }
  1435. if (m_Branches[i].pITSubStream != NULL)
  1436. {
  1437. ((CSubStreamVideoRecv*)m_Branches[i].pITSubStream)->
  1438. ClearCurrentTerminal();
  1439. m_Branches[i].pITSubStream->Release();
  1440. dwOldSSRC = m_Branches[i].dwSSRC;
  1441. }
  1442. pITSubStream->AddRef();
  1443. m_Branches[i].pITSubStream = pITSubStream;
  1444. m_Branches[i].dwSSRC = dwSSRC;
  1445. ((CSubStreamVideoRecv*)pITSubStream)->ClearCurrentTerminal();
  1446. ((CSubStreamVideoRecv*)pITSubStream)->SetCurrentTerminal(
  1447. m_Branches[i].pITTerminal
  1448. );
  1449. // After all the steps, we still have to change QOS reservation.
  1450. if (dwOldSSRC != 0)
  1451. {
  1452. // cancel QOS for the old participant.
  1453. if (FAILED(hr = m_pIRTPSession->SetQosState(dwOldSSRC, FALSE)))
  1454. {
  1455. LOG((MSP_ERROR, "disabling QOS for %x. hr:%x", dwOldSSRC, hr));
  1456. }
  1457. else
  1458. {
  1459. LOG((MSP_INFO, "disabled video QOS for %x.", dwOldSSRC));
  1460. }
  1461. }
  1462. // reserve QOS for the new participant.
  1463. if (FAILED(hr = m_pIRTPSession->SetQosState(dwSSRC, TRUE)))
  1464. {
  1465. LOG((MSP_ERROR, "enabling video QOS for %x. hr:%x", dwSSRC, hr));
  1466. }
  1467. else
  1468. {
  1469. LOG((MSP_INFO, "enabled video QOS for %x.", dwSSRC));
  1470. }
  1471. return S_OK;
  1472. }
  1473. HRESULT CStreamVideoRecv::ProcessTalkingEvent(
  1474. IN DWORD dwSSRC
  1475. )
  1476. /*++
  1477. Routine Description:
  1478. A sender has just joined. A substream needs to be created for the
  1479. participant.
  1480. A pin mapped event might have happended when we didn't have the
  1481. participant's name so it was queued in a list. Now that we have a new
  1482. participant, let's check if this is the same participant. If it is,
  1483. we complete the pin mapped event by sending the app an notification.
  1484. Arguments:
  1485. dwSSRC - the SSRC of the participant.
  1486. pITParticipant - the participant object.
  1487. Return Value:
  1488. S_OK,
  1489. E_UNEXPECTED
  1490. --*/
  1491. {
  1492. ENTER_FUNCTION("CStreamVideoRecv::ProcessTalkingEvent");
  1493. LOG((MSP_TRACE, "%s entered. %x", __fxName, dwSSRC));
  1494. CLock lock(m_lock);
  1495. if (m_pIRTPSession == NULL)
  1496. {
  1497. LOG((MSP_ERROR, "the network filter doesn't exist."));
  1498. return E_UNEXPECTED;
  1499. }
  1500. // first find out if this participant object exists.
  1501. ITParticipant * pITParticipant = NULL;
  1502. int i;
  1503. // find the SSRC in our participant list.
  1504. for (i = 0; i < m_Participants.GetSize(); i ++)
  1505. {
  1506. if (((CParticipant *)m_Participants[i])->
  1507. HasSSRC((ITStream *)this, dwSSRC))
  1508. {
  1509. pITParticipant = m_Participants[i];
  1510. break;
  1511. }
  1512. }
  1513. // if the participant is not there yet, just return. It will be checked
  1514. // later when CName is available.
  1515. if (!pITParticipant)
  1516. {
  1517. LOG((MSP_TRACE, "%s participant not exist", __fxName));
  1518. return S_OK;
  1519. }
  1520. // Find out if a substream has been created for this participant when we
  1521. // processed PinMapped event and receiver reports.
  1522. for (i = 0; i < m_SubStreams.GetSize(); i ++)
  1523. {
  1524. ITParticipant *pTempParticipant;
  1525. DWORD dwSSRC;
  1526. ((CSubStreamVideoRecv*)m_SubStreams[i])->GetCurrentParticipant(
  1527. &dwSSRC, &pTempParticipant
  1528. );
  1529. _ASSERTE(pTempParticipant != NULL);
  1530. pTempParticipant->Release(); // we dont' need the ref here.
  1531. if (pITParticipant == pTempParticipant)
  1532. {
  1533. // the participant has been created.
  1534. return S_OK;
  1535. }
  1536. }
  1537. ITSubStream * pITSubStream;
  1538. HRESULT hr = InternalCreateSubStream(&pITSubStream);
  1539. if (FAILED(hr))
  1540. {
  1541. LOG((MSP_ERROR, "%ls can't create a SubStream, %x", m_szName, hr));
  1542. return hr;
  1543. }
  1544. ((CSubStreamVideoRecv*)pITSubStream)->SetCurrentParticipant(
  1545. dwSSRC, pITParticipant
  1546. );
  1547. ((CIPConfMSPCall *)m_pMSPCall)->SendParticipantEvent(
  1548. PE_NEW_SUBSTREAM,
  1549. pITParticipant,
  1550. pITSubStream
  1551. );
  1552. // look at the pending SSRC list and find out if this report
  1553. // fits in the list.
  1554. IPin *pIPin = NULL;
  1555. for (i = 0; i < m_PinMappedEvents.GetSize(); i ++)
  1556. {
  1557. if (m_PinMappedEvents[i].dwSSRC == dwSSRC)
  1558. {
  1559. pIPin = m_PinMappedEvents[i].pIPin;
  1560. break;
  1561. }
  1562. }
  1563. if (!pIPin)
  1564. {
  1565. // the SSRC is not in the list of pending PinMappedEvents.
  1566. LOG((MSP_TRACE, "the SSRC %x is not in the pending list", dwSSRC));
  1567. pITSubStream->Release();
  1568. return S_OK;;
  1569. }
  1570. // get rid of the peding event.
  1571. m_PinMappedEvents.RemoveAt(i);
  1572. // reserve QOS since we are rendering this sender.
  1573. if (FAILED(hr = m_pIRTPSession->SetQosState(dwSSRC, TRUE)))
  1574. {
  1575. LOG((MSP_ERROR, "enabling video QOS for %x. hr:%x", dwSSRC, hr));
  1576. }
  1577. else
  1578. {
  1579. LOG((MSP_INFO, "enabled video QOS for %x.", dwSSRC));
  1580. }
  1581. // tell the app about the newly mapped sender.
  1582. for (i = 0; i < m_Branches.GetSize(); i ++)
  1583. {
  1584. if (m_Branches[i].pIPin == pIPin)
  1585. {
  1586. if (m_Branches[i].pITSubStream != NULL)
  1587. {
  1588. ((CSubStreamVideoRecv*)m_Branches[i].pITSubStream)
  1589. ->ClearCurrentTerminal();
  1590. m_Branches[i].pITSubStream->Release();
  1591. }
  1592. m_Branches[i].dwSSRC = dwSSRC;
  1593. m_Branches[i].pITSubStream = pITSubStream;
  1594. pITSubStream->AddRef();
  1595. ((CSubStreamVideoRecv*)pITSubStream)->
  1596. SetCurrentTerminal(m_Branches[i].pITTerminal);
  1597. ((CIPConfMSPCall *)m_pMSPCall)->SendParticipantEvent(
  1598. PE_SUBSTREAM_MAPPED,
  1599. pITParticipant,
  1600. pITSubStream
  1601. );
  1602. break;
  1603. }
  1604. }
  1605. pITSubStream->Release();
  1606. return S_OK;
  1607. }
  1608. HRESULT CStreamVideoRecv::ProcessSilentEvent(
  1609. IN DWORD dwSSRC
  1610. )
  1611. /*++
  1612. Routine Description:
  1613. When participant left the session, remove the stream from the participant
  1614. object's list of streams. If all streams are removed, remove the
  1615. participant from the call object's list too.
  1616. Arguments:
  1617. dwSSRC - the SSRC of the participant left.
  1618. Return Value:
  1619. HRESULT.
  1620. --*/
  1621. {
  1622. LOG((MSP_TRACE, "%ls ProcessSilentEvent, SSRC: %x", m_szName, dwSSRC));
  1623. CLock lock(m_lock);
  1624. if (m_pIRTPSession == NULL)
  1625. {
  1626. LOG((MSP_ERROR, "the network filter doesn't exist."));
  1627. return E_UNEXPECTED;
  1628. }
  1629. // first find out if this participant object exists.
  1630. ITParticipant * pITParticipant = NULL;
  1631. int i;
  1632. // find the SSRC in our participant list.
  1633. for (i = 0; i < m_Participants.GetSize(); i ++)
  1634. {
  1635. if (((CParticipant *)m_Participants[i])->
  1636. HasSSRC((ITStream *)this, dwSSRC))
  1637. {
  1638. pITParticipant = m_Participants[i];
  1639. break;
  1640. }
  1641. }
  1642. // if the participant is not there, just return.
  1643. if (!pITParticipant)
  1644. {
  1645. return S_OK;
  1646. }
  1647. HRESULT hr;
  1648. // cancel QOS for this participant.
  1649. if (FAILED(hr = m_pIRTPSession->SetQosState(dwSSRC, FALSE)))
  1650. {
  1651. LOG((MSP_ERROR, "disabling QOS for %x. hr:%x", dwSSRC, hr));
  1652. }
  1653. else
  1654. {
  1655. LOG((MSP_INFO, "disabled video QOS for %x.", dwSSRC));
  1656. }
  1657. // find out which substream is going away.
  1658. ITSubStream * pITSubStream = NULL;
  1659. for (i = 0; i < m_SubStreams.GetSize(); i ++)
  1660. {
  1661. // Find out the participant on the SubStream.
  1662. ITParticipant *pTempParticipant;
  1663. DWORD dwSSRC;
  1664. ((CSubStreamVideoRecv*)m_SubStreams[i])->GetCurrentParticipant(
  1665. &dwSSRC, &pTempParticipant
  1666. );
  1667. _ASSERTE(pTempParticipant != NULL);
  1668. pTempParticipant->Release(); // we dont' need the ref here.
  1669. if (pTempParticipant == pITParticipant)
  1670. {
  1671. pITSubStream = m_SubStreams[i];
  1672. break;
  1673. }
  1674. }
  1675. if (pITSubStream)
  1676. {
  1677. // remove the mapping if the substream was mapped to a branch.
  1678. for (int i = 0; i < m_Branches.GetSize(); i ++)
  1679. {
  1680. if (m_Branches[i].pITSubStream == pITSubStream)
  1681. {
  1682. m_Branches[i].pITSubStream->Release();
  1683. m_Branches[i].pITSubStream = NULL;
  1684. m_Branches[i].dwSSRC = 0;
  1685. // fire an event to tell the app that the substream is not used.
  1686. ((CIPConfMSPCall *)m_pMSPCall)->SendParticipantEvent(
  1687. PE_SUBSTREAM_UNMAPPED,
  1688. pITParticipant,
  1689. pITSubStream
  1690. );
  1691. break;
  1692. }
  1693. }
  1694. ((CIPConfMSPCall *)m_pMSPCall)->SendParticipantEvent(
  1695. PE_SUBSTREAM_REMOVED,
  1696. pITParticipant,
  1697. pITSubStream
  1698. );
  1699. if (m_SubStreams.Remove(pITSubStream))
  1700. {
  1701. pITSubStream->Release();
  1702. }
  1703. }
  1704. return S_OK;
  1705. }
  1706. HRESULT CStreamVideoRecv::NewParticipantPostProcess(
  1707. IN DWORD dwSSRC,
  1708. IN ITParticipant *pITParticipant
  1709. )
  1710. /*++
  1711. Routine Description:
  1712. A pin mapped event might have happended when we didn't have the
  1713. participant's name so it was queued in a list. Now that we have a new
  1714. participant, let's check if this is the same participant. If it is,
  1715. we complete the pin mapped event by creating a substream and send
  1716. the app a notification.
  1717. Arguments:
  1718. dwSSRC - the SSRC of the participant.
  1719. pITParticipant - the participant object.
  1720. Return Value:
  1721. S_OK,
  1722. E_UNEXPECTED
  1723. --*/
  1724. {
  1725. LOG((MSP_TRACE, "%ls Check pending mapped event, dwSSRC: %x", m_szName, dwSSRC));
  1726. // look at the pending SSRC list and find out if this report
  1727. // fits in the list.
  1728. IPin *pIPin = NULL;
  1729. for (int i = 0; i < m_PinMappedEvents.GetSize(); i ++)
  1730. {
  1731. if (m_PinMappedEvents[i].dwSSRC == dwSSRC)
  1732. {
  1733. pIPin = m_PinMappedEvents[i].pIPin;
  1734. break;
  1735. }
  1736. }
  1737. if (!pIPin)
  1738. {
  1739. // the SSRC is not in the list of pending PinMappedEvents.
  1740. LOG((MSP_TRACE, "the SSRC %x is not in the pending list", dwSSRC));
  1741. // Find out if the participant is talking.
  1742. // if (ParticipantIsNotTalking)
  1743. {
  1744. return S_OK;;
  1745. }
  1746. }
  1747. ITSubStream * pITSubStream;
  1748. HRESULT hr = InternalCreateSubStream(&pITSubStream);
  1749. if (FAILED(hr))
  1750. {
  1751. LOG((MSP_ERROR, "%ls can't create a SubStream, %x", m_szName, hr));
  1752. return hr;
  1753. }
  1754. ((CSubStreamVideoRecv*)pITSubStream)->SetCurrentParticipant(
  1755. dwSSRC, pITParticipant
  1756. );
  1757. ((CIPConfMSPCall *)m_pMSPCall)->SendParticipantEvent(
  1758. PE_NEW_SUBSTREAM,
  1759. pITParticipant,
  1760. pITSubStream
  1761. );
  1762. if (pIPin)
  1763. {
  1764. // we got here because we had a pending mapped event.
  1765. // get rid of the peding event.
  1766. m_PinMappedEvents.RemoveAt(i);
  1767. if (FAILED(hr = m_pIRTPSession->SetQosState(dwSSRC, TRUE)))
  1768. {
  1769. LOG((MSP_ERROR, "enabling video QOS for %x. hr:%x", dwSSRC, hr));
  1770. }
  1771. else
  1772. {
  1773. LOG((MSP_INFO, "enabled video QOS for %x.", dwSSRC));
  1774. }
  1775. // Now we get the participant, the substream, and the pin. Establish a mapping
  1776. // between the decoding branch and the substream.
  1777. for (i = 0; i < m_Branches.GetSize(); i ++)
  1778. {
  1779. if (m_Branches[i].pIPin == pIPin)
  1780. {
  1781. if (m_Branches[i].pITSubStream != NULL)
  1782. {
  1783. ((CSubStreamVideoRecv*)m_Branches[i].pITSubStream)
  1784. ->ClearCurrentTerminal();
  1785. m_Branches[i].pITSubStream->Release();
  1786. }
  1787. m_Branches[i].dwSSRC = dwSSRC;
  1788. m_Branches[i].pITSubStream = pITSubStream;
  1789. pITSubStream->AddRef();
  1790. ((CSubStreamVideoRecv*)pITSubStream)->
  1791. SetCurrentTerminal(m_Branches[i].pITTerminal);
  1792. ((CIPConfMSPCall *)m_pMSPCall)->SendParticipantEvent(
  1793. PE_SUBSTREAM_MAPPED,
  1794. pITParticipant,
  1795. pITSubStream
  1796. );
  1797. break;
  1798. }
  1799. }
  1800. _ASSERT(i < m_Branches.GetSize());
  1801. }
  1802. pITSubStream->Release();
  1803. return S_OK;
  1804. }
  1805. HRESULT CStreamVideoRecv::ProcessPinMappedEvent(
  1806. IN DWORD dwSSRC,
  1807. IN IPin * pIPin
  1808. )
  1809. /*++
  1810. Routine Description:
  1811. A pin just got a new SSRC mapped to it. If the participant doesn't exist,
  1812. put the event in a pending queue and wait for a RTCP report that has the
  1813. participant's name. If the participant exists, check to see if a SubStream
  1814. has been created for the stream. If not, a SubStream is created. Then a
  1815. Particiapnt substream event is fired.
  1816. Arguments:
  1817. dwSSRC - the SSRC of the participant.
  1818. pIPin - the output pin of the demux filter that just got a new SSRC.
  1819. Return Value:
  1820. S_OK,
  1821. E_UNEXPECTED
  1822. --*/
  1823. {
  1824. LOG((MSP_TRACE, "%ls Process pin mapped event, pIPin: %p", m_szName, pIPin));
  1825. CLock lock(m_lock);
  1826. if (m_pIRTPDemux == NULL)
  1827. {
  1828. LOG((MSP_ERROR, "the demux filter doesn't exist."));
  1829. return E_UNEXPECTED;
  1830. }
  1831. for (int iBranch = 0; iBranch < m_Branches.GetSize(); iBranch ++)
  1832. {
  1833. if (m_Branches[iBranch].pIPin == pIPin)
  1834. {
  1835. break;
  1836. }
  1837. }
  1838. LOG((MSP_INFO, "Branch %d has the pin", iBranch));
  1839. if (iBranch >= m_Branches.GetSize())
  1840. {
  1841. LOG((MSP_ERROR, "Wrong pin is mapped. %p", pIPin));
  1842. return E_UNEXPECTED;
  1843. }
  1844. // sometimes we might get a mapped event for branches that are still
  1845. // in use.
  1846. if (m_Branches[iBranch].pITSubStream != NULL)
  1847. {
  1848. LOG((MSP_ERROR, "ProcessPinMappedEvent: Branch still in use"));
  1849. // sometimes we might get duplicated map events
  1850. if (m_Branches[iBranch].dwSSRC == dwSSRC)
  1851. {
  1852. // LOG((MSP_WARNING, "ProcessPinMappedEvent: Branch still in use"));
  1853. LOG((MSP_ERROR, "The same pin mapped twice. %p", pIPin));
  1854. return E_UNEXPECTED;
  1855. }
  1856. else
  1857. {
  1858. LOG((MSP_ERROR, "The branch is in use. Cleaning up."));
  1859. ((CSubStreamVideoRecv*)m_Branches[iBranch].pITSubStream)->
  1860. ClearCurrentTerminal();
  1861. // cancel QOS for the old participant.
  1862. m_pIRTPSession->SetQosState(m_Branches[iBranch].dwSSRC, FALSE);
  1863. m_Branches[iBranch].pITSubStream->Release();
  1864. m_Branches[iBranch].pITSubStream = NULL;
  1865. m_Branches[iBranch].dwSSRC = 0;
  1866. }
  1867. }
  1868. ITParticipant * pITParticipant = NULL;
  1869. // find the SSRC in our participant list.
  1870. for (int i = 0; i < m_Participants.GetSize(); i ++)
  1871. {
  1872. if (((CParticipant *)m_Participants[i])->
  1873. HasSSRC((ITStream *)this, dwSSRC))
  1874. {
  1875. pITParticipant = m_Participants[i];
  1876. break;
  1877. }
  1878. }
  1879. // if the participant is not there yet, put the event in a queue and it
  1880. // will be fired when we have the CName for the participant.
  1881. if (!pITParticipant)
  1882. {
  1883. LOG((MSP_INFO, "can't find a participant that has SSRC %x", dwSSRC));
  1884. PINMAPEVENT Event;
  1885. Event.pIPin = pIPin;
  1886. Event.dwSSRC = dwSSRC;
  1887. m_PinMappedEvents.Add(Event);
  1888. LOG((MSP_INFO, "added the event to pending list, new list size:%d",
  1889. m_PinMappedEvents.GetSize()));
  1890. return S_OK;
  1891. }
  1892. HRESULT hr;
  1893. // Enable QOS for the participant since it is being rendered.
  1894. if (FAILED(hr = m_pIRTPSession->SetQosState(dwSSRC, TRUE)))
  1895. {
  1896. LOG((MSP_ERROR, "enabling vidoe QOS for %x. hr:%x", dwSSRC, hr));
  1897. }
  1898. else
  1899. {
  1900. LOG((MSP_INFO, "enabled video QOS for %x.", dwSSRC));
  1901. }
  1902. // Find out if a substream has been created for this participant who might
  1903. // have been a receiver only and hasn't got a substream.
  1904. ITSubStream * pITSubStream = NULL;
  1905. for (i = 0; i < m_SubStreams.GetSize(); i ++)
  1906. {
  1907. ITParticipant *pTempParticipant;
  1908. DWORD dwSSRC;
  1909. ((CSubStreamVideoRecv*)m_SubStreams[i])->GetCurrentParticipant(
  1910. &dwSSRC, &pTempParticipant
  1911. );
  1912. _ASSERTE(pTempParticipant != NULL);
  1913. pTempParticipant->Release(); // we dont' need the ref here.
  1914. if (pITParticipant == pTempParticipant)
  1915. {
  1916. pITSubStream = m_SubStreams[i];
  1917. pITSubStream->AddRef();
  1918. break;
  1919. }
  1920. }
  1921. if (pITSubStream == NULL)
  1922. {
  1923. // we need to create a substream for this participant since he has
  1924. // started sending.
  1925. hr = InternalCreateSubStream(&pITSubStream);
  1926. if (FAILED(hr))
  1927. {
  1928. LOG((MSP_ERROR, "%ls can't create a SubStream, %x", m_szName, hr));
  1929. return hr;
  1930. }
  1931. ((CSubStreamVideoRecv*)pITSubStream)->SetCurrentParticipant(
  1932. dwSSRC, pITParticipant
  1933. );
  1934. ((CIPConfMSPCall *)m_pMSPCall)->SendParticipantEvent(
  1935. PE_NEW_SUBSTREAM,
  1936. pITParticipant,
  1937. pITSubStream
  1938. );
  1939. }
  1940. if (((CSubStreamVideoRecv*)pITSubStream)->ClearCurrentTerminal())
  1941. {
  1942. // The substrem has a terminal before. This is an error.
  1943. // _ASSERT(!"SubStream has a terminal already");
  1944. LOG((MSP_ERROR, "SubStream %p has already got a terminal", pITSubStream));
  1945. // remove the mapping if the substream was mapped to a branch.
  1946. for (i = 0; i < m_Branches.GetSize(); i ++)
  1947. {
  1948. if (m_Branches[i].pITSubStream == pITSubStream)
  1949. {
  1950. // cancel QOS for the old participant.
  1951. m_pIRTPSession->SetQosState(m_Branches[i].dwSSRC, FALSE);
  1952. m_Branches[i].pITSubStream->Release();
  1953. m_Branches[i].pITSubStream = NULL;
  1954. m_Branches[i].dwSSRC = 0;
  1955. LOG((MSP_ERROR, "SubStream %p was mapped to branch %d", i));
  1956. break;
  1957. }
  1958. }
  1959. }
  1960. // Now we get the participant, the substream, and the pin. Establish a mapping
  1961. // between the decoding branch and the substream.
  1962. m_Branches[iBranch].dwSSRC = dwSSRC;
  1963. m_Branches[iBranch].pITSubStream = pITSubStream;
  1964. pITSubStream->AddRef();
  1965. ((CSubStreamVideoRecv*)pITSubStream)->
  1966. SetCurrentTerminal(m_Branches[iBranch].pITTerminal);
  1967. ((CIPConfMSPCall *)m_pMSPCall)->SendParticipantEvent(
  1968. PE_SUBSTREAM_MAPPED,
  1969. pITParticipant,
  1970. pITSubStream
  1971. );
  1972. pITSubStream->Release();
  1973. return S_OK;
  1974. }
  1975. HRESULT CStreamVideoRecv::ProcessPinUnmapEvent(
  1976. IN DWORD dwSSRCOnPin,
  1977. IN IPin * pIPin
  1978. )
  1979. /*++
  1980. Routine Description:
  1981. A pin just got unmapped by the demux. Notify the app which substream
  1982. is not going to have any data.
  1983. Arguments:
  1984. dwSSRCOnPin - the SSRC of the participant.
  1985. pIPin - the output pin of the demux filter
  1986. Return Value:
  1987. S_OK,
  1988. E_UNEXPECTED
  1989. --*/
  1990. {
  1991. LOG((MSP_TRACE, "%ls Proces pin unmapped event, pIPin: %p", m_szName, pIPin));
  1992. CLock lock(m_lock);
  1993. if (m_pIRTPSession == NULL)
  1994. {
  1995. LOG((MSP_ERROR, "the demux filter doesn't exist."));
  1996. return E_UNEXPECTED;
  1997. }
  1998. // look at the pending SSRC list and find out if the pin is in the
  1999. // pending list.
  2000. for (int i = 0; i < m_PinMappedEvents.GetSize(); i ++)
  2001. {
  2002. if (m_PinMappedEvents[i].pIPin == pIPin)
  2003. {
  2004. break;
  2005. }
  2006. }
  2007. // if the pin is in the pending list, just remove it.
  2008. if (i < m_PinMappedEvents.GetSize())
  2009. {
  2010. m_PinMappedEvents.RemoveAt(i);
  2011. return S_OK;
  2012. }
  2013. // find out which substream got unmapped.
  2014. ITSubStream * pITSubStream = NULL;
  2015. for (i = 0; i < m_Branches.GetSize(); i ++)
  2016. {
  2017. if (m_Branches[i].pIPin == pIPin)
  2018. {
  2019. pITSubStream = m_Branches[i].pITSubStream;
  2020. if (pITSubStream)
  2021. {
  2022. // Don't release the ref until the end of this function.
  2023. m_Branches[i].pITSubStream = NULL;
  2024. m_Branches[i].dwSSRC = 0;
  2025. }
  2026. break;
  2027. }
  2028. }
  2029. if (!pITSubStream)
  2030. {
  2031. LOG((MSP_ERROR, "can't find a substream that got unmapped."));
  2032. return TAPI_E_NOITEMS;
  2033. }
  2034. ((CSubStreamVideoRecv*)pITSubStream)->ClearCurrentTerminal();
  2035. ITParticipant *pITParticipant = NULL;
  2036. DWORD dwSSRC;
  2037. ((CSubStreamVideoRecv*)pITSubStream)->GetCurrentParticipant(
  2038. &dwSSRC, &pITParticipant
  2039. ) ;
  2040. _ASSERTE(pITParticipant != NULL);
  2041. if (dwSSRCOnPin != dwSSRC)
  2042. {
  2043. LOG((MSP_ERROR, "SSRCs don't match, pin's SSRC:%x, mine:%x",
  2044. dwSSRCOnPin, dwSSRC));
  2045. }
  2046. if (pITParticipant != NULL)
  2047. {
  2048. // fire an event to tell the app that the substream is not used.
  2049. ((CIPConfMSPCall *)m_pMSPCall)->SendParticipantEvent(
  2050. PE_SUBSTREAM_UNMAPPED,
  2051. pITParticipant,
  2052. pITSubStream
  2053. );
  2054. pITParticipant->Release();
  2055. // cancel QOS for this participant.
  2056. HRESULT hr = m_pIRTPSession->SetQosState(dwSSRC, FALSE);
  2057. if (FAILED(hr))
  2058. {
  2059. LOG((MSP_ERROR, "disabling QOS for %x. hr:%x", dwSSRC, hr));
  2060. }
  2061. else
  2062. {
  2063. LOG((MSP_INFO, "disabled video QOS for %x.", dwSSRC));
  2064. }
  2065. }
  2066. pITSubStream->Release();
  2067. return S_OK;
  2068. }
  2069. HRESULT CStreamVideoRecv::ProcessParticipantLeave(
  2070. IN DWORD dwSSRC
  2071. )
  2072. /*++
  2073. Routine Description:
  2074. When participant left the session, remove the stream from the participant
  2075. object's list of streams. If all streams are removed, remove the
  2076. participant from the call object's list too.
  2077. Arguments:
  2078. dwSSRC - the SSRC of the participant left.
  2079. Return Value:
  2080. HRESULT.
  2081. --*/
  2082. {
  2083. LOG((MSP_TRACE, "%ls ProcessParticipantLeave, SSRC: %x", m_szName, dwSSRC));
  2084. CLock lock(m_lock);
  2085. if (m_pIRTPSession == NULL)
  2086. {
  2087. LOG((MSP_ERROR, "the network filter doesn't exist."));
  2088. return E_UNEXPECTED;
  2089. }
  2090. CParticipant *pParticipant;
  2091. BOOL fLast = FALSE;
  2092. HRESULT hr = E_FAIL;
  2093. // first try to find the SSRC in our participant list.
  2094. for (int iParticipant = 0;
  2095. iParticipant < m_Participants.GetSize(); iParticipant ++)
  2096. {
  2097. pParticipant = (CParticipant *)m_Participants[iParticipant];
  2098. hr = pParticipant->RemoveStream(
  2099. (ITStream *)this,
  2100. dwSSRC,
  2101. &fLast
  2102. );
  2103. if (SUCCEEDED(hr))
  2104. {
  2105. break;
  2106. }
  2107. }
  2108. // if the participant is not found
  2109. if (FAILED(hr))
  2110. {
  2111. LOG((MSP_TRACE, "SSRC:%x had been removed.", dwSSRC));
  2112. return hr;
  2113. }
  2114. ITParticipant *pITParticipant = m_Participants[iParticipant];
  2115. // cancel QOS for this participant.
  2116. if (FAILED(hr = m_pIRTPSession->SetQosState(dwSSRC, FALSE)))
  2117. {
  2118. // the stream might already been stopped
  2119. // so we just put a warning here
  2120. LOG((MSP_WARN, "disabling QOS for %x. hr:%x", dwSSRC, hr));
  2121. }
  2122. else
  2123. {
  2124. LOG((MSP_INFO, "disabled video QOS for %x.", dwSSRC));
  2125. }
  2126. // find out which substream is going away.
  2127. ITSubStream * pITSubStream = NULL;
  2128. for (int i = 0; i < m_SubStreams.GetSize(); i ++)
  2129. {
  2130. // Find out the participant on the SubStream.
  2131. ITParticipant *pTempParticipant;
  2132. DWORD dwSSRC;
  2133. ((CSubStreamVideoRecv*)m_SubStreams[i])->GetCurrentParticipant(
  2134. &dwSSRC, &pTempParticipant
  2135. );
  2136. _ASSERTE(pTempParticipant != NULL);
  2137. pTempParticipant->Release(); // we dont' need the ref here.
  2138. if (pTempParticipant == pITParticipant)
  2139. {
  2140. pITSubStream = m_SubStreams[i];
  2141. break;
  2142. }
  2143. }
  2144. if (pITSubStream)
  2145. {
  2146. // remove the mapping if the substream was mapped to a branch.
  2147. for (int i = 0; i < m_Branches.GetSize(); i ++)
  2148. {
  2149. if (m_Branches[i].pITSubStream == pITSubStream)
  2150. {
  2151. m_Branches[i].pITSubStream->Release();
  2152. m_Branches[i].pITSubStream = NULL;
  2153. m_Branches[i].dwSSRC = 0;
  2154. // fire an event to tell the app that the substream is not used.
  2155. ((CIPConfMSPCall *)m_pMSPCall)->SendParticipantEvent(
  2156. PE_SUBSTREAM_UNMAPPED,
  2157. pITParticipant,
  2158. pITSubStream
  2159. );
  2160. break;
  2161. }
  2162. }
  2163. ((CIPConfMSPCall *)m_pMSPCall)->SendParticipantEvent(
  2164. PE_SUBSTREAM_REMOVED,
  2165. pITParticipant,
  2166. pITSubStream
  2167. );
  2168. if (m_SubStreams.Remove(pITSubStream))
  2169. {
  2170. pITSubStream->Release();
  2171. }
  2172. }
  2173. m_Participants.RemoveAt(iParticipant);
  2174. // if this stream is the last stream that the participant is on,
  2175. // tell the call object to remove it from its list.
  2176. if (fLast)
  2177. {
  2178. ((CIPConfMSPCall *)m_pMSPCall)->ParticipantLeft(pITParticipant);
  2179. }
  2180. pITParticipant->Release();
  2181. return S_OK;
  2182. }
  2183. //
  2184. // ITStreamQualityControl methods
  2185. //
  2186. STDMETHODIMP CStreamVideoRecv::Set (
  2187. IN StreamQualityProperty Property,
  2188. IN long lValue,
  2189. IN TAPIControlFlags lFlags
  2190. )
  2191. {
  2192. return E_NOTIMPL;
  2193. }
  2194. STDMETHODIMP CStreamVideoRecv::Get(
  2195. IN InnerStreamQualityProperty property,
  2196. OUT LONG *plValue,
  2197. OUT TAPIControlFlags *plFlags
  2198. )
  2199. /*++
  2200. Routine Description:
  2201. Get the value for a quality control property. Delegated to the quality
  2202. controller.
  2203. Arguments:
  2204. Return Value:
  2205. HRESULT.
  2206. --*/
  2207. {
  2208. ENTER_FUNCTION("CStreamVideoRecv::Get(QualityControl)");
  2209. HRESULT hr;
  2210. int i;
  2211. LONG totalbps, bps;
  2212. CLock lock(m_lock);
  2213. switch (property)
  2214. {
  2215. case InnerStreamQuality_MaxBitrate:
  2216. bps = 0;
  2217. totalbps = 0;
  2218. for (i=0; i<m_Branches.GetSize (); i++)
  2219. {
  2220. if (NULL == m_Branches[i].pBitrateControl)
  2221. continue;
  2222. if (FAILED (hr = m_Branches[i].pBitrateControl->Get (BitrateControl_Maximum, &bps, plFlags, LAYERID)))
  2223. LOG ((MSP_ERROR, "%s failed to get maximum bitrate, %x", __fxName, hr));
  2224. else
  2225. totalbps += bps;
  2226. }
  2227. *plValue = totalbps;
  2228. hr = S_OK;
  2229. break;
  2230. case InnerStreamQuality_CurrBitrate:
  2231. bps = 0;
  2232. totalbps = 0;
  2233. for (i=0; i<m_Branches.GetSize (); i++)
  2234. {
  2235. if (NULL == m_Branches[i].pBitrateControl)
  2236. continue;
  2237. if (FAILED (hr = m_Branches[i].pBitrateControl->Get (BitrateControl_Current, &bps, plFlags, LAYERID)))
  2238. LOG ((MSP_ERROR, "%s failed to get current bitrate, %x", __fxName, hr));
  2239. else
  2240. totalbps += bps;
  2241. }
  2242. *plValue = totalbps;
  2243. hr = S_OK;
  2244. break;
  2245. default:
  2246. hr = CIPConfMSPStream::Get (property, plValue, plFlags);
  2247. break;
  2248. }
  2249. return hr;
  2250. }
  2251. /////////////////////////////////////////////////////////////////////////////
  2252. //
  2253. // CStreamVideoSend
  2254. //
  2255. /////////////////////////////////////////////////////////////////////////////
  2256. CStreamVideoSend::CStreamVideoSend()
  2257. : CIPConfMSPStream(),
  2258. m_pCaptureTerminal(NULL),
  2259. m_pPreviewTerminal(NULL),
  2260. m_pCaptureFilter(NULL),
  2261. m_pCapturePin(NULL),
  2262. m_pPreviewPin(NULL),
  2263. m_pRTPPin(NULL),
  2264. m_pCaptureBitrateControl(NULL),
  2265. m_pCaptureFrameRateControl(NULL),
  2266. m_pPreviewFrameRateControl(NULL)
  2267. {
  2268. m_szName = L"VideoSend";
  2269. }
  2270. CStreamVideoSend::~CStreamVideoSend()
  2271. {
  2272. CleanupCachedInterface();
  2273. }
  2274. void CStreamVideoSend::CleanupCachedInterface()
  2275. {
  2276. if (m_pCaptureFilter)
  2277. {
  2278. m_pCaptureFilter->Release();
  2279. m_pCaptureFilter = NULL;
  2280. }
  2281. if (m_pCapturePin)
  2282. {
  2283. m_pCapturePin->Release();
  2284. m_pCapturePin = NULL;
  2285. }
  2286. if (m_pIStreamConfig)
  2287. {
  2288. m_pIStreamConfig->Release();
  2289. m_pIStreamConfig = NULL;
  2290. }
  2291. if (m_pPreviewPin)
  2292. {
  2293. m_pPreviewPin->Release();
  2294. m_pPreviewPin = NULL;
  2295. }
  2296. if (m_pRTPPin)
  2297. {
  2298. m_pRTPPin->Release();
  2299. m_pRTPPin = NULL;
  2300. }
  2301. if (m_pCaptureFrameRateControl)
  2302. {
  2303. m_pCaptureFrameRateControl->Release();
  2304. m_pCaptureFrameRateControl = NULL;
  2305. }
  2306. if (m_pCaptureBitrateControl)
  2307. {
  2308. m_pCaptureBitrateControl->Release();
  2309. m_pCaptureBitrateControl = NULL;
  2310. }
  2311. if (m_pPreviewFrameRateControl)
  2312. {
  2313. m_pPreviewFrameRateControl->Release();
  2314. m_pPreviewFrameRateControl = NULL;
  2315. }
  2316. }
  2317. HRESULT CStreamVideoSend::ShutDown()
  2318. /*++
  2319. Routine Description:
  2320. Shut down the stream. Release our members and then calls the base class's
  2321. ShutDown method.
  2322. Arguments:
  2323. Return Value:
  2324. S_OK
  2325. --*/
  2326. {
  2327. CLock lock(m_lock);
  2328. // if there are terminals
  2329. BOOL fHasTerminal = FALSE;
  2330. if (m_Terminals.GetSize() > 0)
  2331. {
  2332. fHasTerminal = TRUE;
  2333. }
  2334. // if graph is running
  2335. HRESULT hr;
  2336. OAFilterState FilterState = State_Stopped;
  2337. if (m_pIMediaControl)
  2338. {
  2339. if (FAILED (hr = m_pIMediaControl->GetState(0, &FilterState)))
  2340. {
  2341. LOG ((MSP_ERROR, "CStreamAudioRecv::ShutDown failed to query filter state. %d", hr));
  2342. FilterState = State_Stopped;
  2343. }
  2344. }
  2345. if (m_pCaptureTerminal)
  2346. {
  2347. m_pCaptureTerminal->Release();
  2348. m_pCaptureTerminal = NULL;
  2349. }
  2350. if (m_pPreviewTerminal)
  2351. {
  2352. m_pPreviewTerminal->Release();
  2353. m_pPreviewTerminal = NULL;
  2354. }
  2355. CleanupCachedInterface();
  2356. // fire event
  2357. if (fHasTerminal && FilterState == State_Running)
  2358. {
  2359. SendStreamEvent(CALL_STREAM_INACTIVE, CALL_CAUSE_LOCAL_REQUEST, 0, NULL);
  2360. }
  2361. return CIPConfMSPStream::ShutDown();
  2362. }
  2363. HRESULT
  2364. SetVideoFormat(
  2365. IN IUnknown * pIUnknown,
  2366. IN BOOL bCIF,
  2367. IN DWORD dwFramesPerSecond
  2368. )
  2369. /*++
  2370. Routine Description:
  2371. Set the video format to be CIF or QCIF and also set the frames per second.
  2372. Arguments:
  2373. pIUnknown - a capture terminal.
  2374. bCIF - CIF or QCIF.
  2375. dwFramesPerSecond - Frames per second.
  2376. Return Value:
  2377. HRESULT
  2378. --*/
  2379. {
  2380. LOG((MSP_TRACE, "SetVideoFormat"));
  2381. HRESULT hr;
  2382. // first get eht IAMStreamConfig interface.
  2383. CComPtr<IAMStreamConfig> pIAMStreamConfig;
  2384. if (FAILED(hr = pIUnknown->QueryInterface(
  2385. __uuidof(IAMStreamConfig),
  2386. (void **)&pIAMStreamConfig
  2387. )))
  2388. {
  2389. LOG((MSP_ERROR, "Can't get IAMStreamConfig interface.%8x", hr));
  2390. return hr;
  2391. }
  2392. // get the current format of the video capture terminal.
  2393. AM_MEDIA_TYPE *pmt;
  2394. if (FAILED(hr = pIAMStreamConfig->GetFormat(&pmt)))
  2395. {
  2396. LOG((MSP_ERROR, "GetFormat returns error: %8x", hr));
  2397. return hr;
  2398. }
  2399. VIDEOINFO *pVideoInfo = (VIDEOINFO *)pmt->pbFormat;
  2400. if (pVideoInfo == NULL)
  2401. {
  2402. MSPDeleteMediaType(pmt);
  2403. return E_UNEXPECTED;
  2404. }
  2405. BITMAPINFOHEADER *pHeader = HEADER(pmt->pbFormat);
  2406. if (pHeader == NULL)
  2407. {
  2408. MSPDeleteMediaType(pmt);
  2409. return E_UNEXPECTED;
  2410. }
  2411. LOG((MSP_INFO,
  2412. "Video capture: Format BitRate: %d, TimePerFrame: %d",
  2413. pVideoInfo->dwBitRate,
  2414. pVideoInfo->AvgTimePerFrame));
  2415. LOG((MSP_INFO, "Video capture: Format Compression:%c%c%c%c %dbit %dx%d",
  2416. (DWORD)pHeader->biCompression & 0xff,
  2417. ((DWORD)pHeader->biCompression >> 8) & 0xff,
  2418. ((DWORD)pHeader->biCompression >> 16) & 0xff,
  2419. ((DWORD)pHeader->biCompression >> 24) & 0xff,
  2420. pHeader->biBitCount,
  2421. pHeader->biWidth,
  2422. pHeader->biHeight));
  2423. // The time is in 100ns unit.
  2424. pVideoInfo->AvgTimePerFrame = (DWORD) 1e7 / dwFramesPerSecond;
  2425. if (bCIF)
  2426. {
  2427. pHeader->biWidth = CIFWIDTH;
  2428. pHeader->biHeight = CIFHEIGHT;
  2429. }
  2430. else
  2431. {
  2432. pHeader->biWidth = QCIFWIDTH;
  2433. pHeader->biHeight = QCIFHEIGHT;
  2434. }
  2435. #if defined(ALPHA)
  2436. // update bmiSize with new Width/Height
  2437. pHeader->biSizeImage = DIBSIZE( ((VIDEOINFOHEADER *)pmt->pbFormat)->bmiHeader );
  2438. #endif
  2439. if (FAILED(hr = pIAMStreamConfig->SetFormat(pmt)))
  2440. {
  2441. LOG((MSP_ERROR, "putMediaFormat returns error: %8x", hr));
  2442. }
  2443. else
  2444. {
  2445. LOG((MSP_INFO,
  2446. "Video capture: Format BitRate: %d, TimePerFrame: %d",
  2447. pVideoInfo->dwBitRate,
  2448. pVideoInfo->AvgTimePerFrame));
  2449. LOG((MSP_INFO, "Video capture: Format Compression:%c%c%c%c %dbit %dx%d",
  2450. (DWORD)pHeader->biCompression & 0xff,
  2451. ((DWORD)pHeader->biCompression >> 8) & 0xff,
  2452. ((DWORD)pHeader->biCompression >> 16) & 0xff,
  2453. ((DWORD)pHeader->biCompression >> 24) & 0xff,
  2454. pHeader->biBitCount,
  2455. pHeader->biWidth,
  2456. pHeader->biHeight));
  2457. }
  2458. MSPDeleteMediaType(pmt);
  2459. return hr;
  2460. }
  2461. HRESULT
  2462. SetVideoBufferSize(
  2463. IN IUnknown *pIUnknown
  2464. )
  2465. /*++
  2466. Routine Description:
  2467. Set the video capture terminal's buffersize.
  2468. Arguments:
  2469. pIUnknown - a capture terminal.
  2470. Return Value:
  2471. HRESULT
  2472. --*/
  2473. {
  2474. // The number of capture buffers is four for now.
  2475. #define NUMCAPTUREBUFFER 4
  2476. LOG((MSP_TRACE, "SetVideoBufferSize"));
  2477. HRESULT hr;
  2478. CComPtr<IAMBufferNegotiation> pBN;
  2479. if (FAILED(hr = pIUnknown->QueryInterface(
  2480. __uuidof(IAMBufferNegotiation),
  2481. (void **)&pBN
  2482. )))
  2483. {
  2484. LOG((MSP_ERROR, "Can't get buffer negotiation interface.%8x", hr));
  2485. return hr;
  2486. }
  2487. ALLOCATOR_PROPERTIES prop;
  2488. #if 0 // Get allocator property is not working.
  2489. if (FAILED(hr = pBN->GetAllocatorProperties(&prop)))
  2490. {
  2491. LOG((MSP_ERROR, "GetAllocatorProperties returns error: %8x", hr));
  2492. return hr;
  2493. }
  2494. // Set the number of buffers.
  2495. if (prop.cBuffers > NUMCAPTUREBUFFER)
  2496. {
  2497. prop.cBuffers = NUMCAPTUREBUFFER;
  2498. }
  2499. #endif
  2500. DWORD dwBuffers = NUMCAPTUREBUFFER;
  2501. GetRegValue(gszNumVideoCaptureBuffers, &dwBuffers);
  2502. prop.cBuffers = dwBuffers;
  2503. prop.cbBuffer = -1;
  2504. prop.cbAlign = -1;
  2505. prop.cbPrefix = -1;
  2506. if (FAILED(hr = pBN->SuggestAllocatorProperties(&prop)))
  2507. {
  2508. LOG((MSP_ERROR, "SuggestAllocatorProperties returns error: %8x", hr));
  2509. }
  2510. else
  2511. {
  2512. LOG((MSP_INFO,
  2513. "SetVidedobuffersize"
  2514. " buffers: %d, buffersize: %d, align: %d, Prefix: %d",
  2515. prop.cBuffers,
  2516. prop.cbBuffer,
  2517. prop.cbAlign,
  2518. prop.cbPrefix
  2519. ));
  2520. }
  2521. return hr;
  2522. }
  2523. HRESULT CStreamVideoSend::FindPreviewInputPin(
  2524. IN ITTerminalControl* pTerminal,
  2525. OUT IPin ** ppIPin
  2526. )
  2527. /*++
  2528. Routine Description:
  2529. Find the input pin on a preview terminal.
  2530. Arguments:
  2531. pTerminal - a video render terminal.
  2532. ppIPin - the address to store a pointer to a IPin interface.
  2533. Return Value:
  2534. HRESULT
  2535. --*/
  2536. {
  2537. LOG((MSP_TRACE, "VideoSend.FindPreviewInputPin, pTerminal %x", pTerminal));
  2538. /*
  2539. // try to disable DDraw because we want to use DDraw for receive stream.
  2540. HRESULT hr2;
  2541. IDrawVideoImage *pIDrawVideoImage;
  2542. hr2 = pTerminal->QueryInterface(__uuidof(IDrawVideoImage), (void **)&pIDrawVideoImage);
  2543. if (SUCCEEDED(hr2))
  2544. {
  2545. hr2 = pIDrawVideoImage->DrawVideoImageBegin();
  2546. if (FAILED(hr2))
  2547. {
  2548. LOG((MSP_WARN, "Can't disable DDraw. %x", hr2));
  2549. }
  2550. else
  2551. {
  2552. LOG((MSP_INFO, "DDraw disabled."));
  2553. }
  2554. pIDrawVideoImage->Release();
  2555. }
  2556. else
  2557. {
  2558. LOG((MSP_WARN, "Can't get IDrawVideoImage. %x", hr2));
  2559. }
  2560. */
  2561. // Get the pins from the first terminal because we only use on terminal
  2562. // on this stream.
  2563. const DWORD MAXPINS = 8;
  2564. DWORD dwNumPins = MAXPINS;
  2565. IPin * Pins[MAXPINS];
  2566. HRESULT hr = pTerminal->ConnectTerminal(
  2567. m_pIGraphBuilder, TD_RENDER, &dwNumPins, Pins
  2568. );
  2569. if (FAILED(hr))
  2570. {
  2571. LOG((MSP_ERROR, "can't connect to terminal, %x", hr));
  2572. return hr;
  2573. }
  2574. if (dwNumPins == 0)
  2575. {
  2576. LOG((MSP_ERROR, "terminal has no pins."));
  2577. return hr;
  2578. }
  2579. if (IsBadReadPtr (Pins, dwNumPins * sizeof (IPin*)))
  2580. {
  2581. LOG((MSP_ERROR, "terminal returned bad pin array"));
  2582. return E_POINTER;
  2583. }
  2584. for (DWORD i = 0; i < dwNumPins; i++)
  2585. {
  2586. if (IsBadReadPtr (Pins[i], sizeof (IPin)))
  2587. {
  2588. LOG((MSP_ERROR, "terminal returned bad pin. # %d", i));
  2589. return E_POINTER;
  2590. }
  2591. }
  2592. // Save the first pin and release the others.
  2593. CComPtr <IPin> pIPin = Pins[0];
  2594. for (DWORD i = 0; i < dwNumPins; i ++)
  2595. {
  2596. Pins[i]->Release();
  2597. }
  2598. pIPin.p->AddRef();
  2599. *ppIPin = pIPin;
  2600. return hr;
  2601. }
  2602. HRESULT CStreamVideoSend::CheckTerminalTypeAndDirection(
  2603. IN ITTerminal * pTerminal
  2604. )
  2605. /*++
  2606. Routine Description:
  2607. Check if the terminal is allowed on this stream.
  2608. VideoSend allows both a capture terminal and a preivew terminal.
  2609. Arguments:
  2610. pTerminal - the terminal.
  2611. Return value:
  2612. HRESULT.
  2613. S_OK means the terminal is OK.
  2614. */
  2615. {
  2616. LOG((MSP_TRACE, "VideoSend.CheckTerminalTypeAndDirection"));
  2617. // This stream only support one capture + one preview terminal
  2618. if (m_Terminals.GetSize() > 1)
  2619. {
  2620. return TAPI_E_MAXTERMINALS;
  2621. }
  2622. // check the media type of this terminal.
  2623. long lMediaType;
  2624. HRESULT hr = pTerminal->get_MediaType(&lMediaType);
  2625. if (FAILED(hr))
  2626. {
  2627. LOG((MSP_ERROR, "can't get terminal media type. %x", hr));
  2628. return TAPI_E_INVALIDTERMINAL;
  2629. }
  2630. if ((DWORD)lMediaType != m_dwMediaType)
  2631. {
  2632. return TAPI_E_INVALIDTERMINAL;
  2633. }
  2634. // check the direction of this terminal.
  2635. TERMINAL_DIRECTION Direction;
  2636. hr = pTerminal->get_Direction(&Direction);
  2637. if (FAILED(hr))
  2638. {
  2639. LOG((MSP_ERROR, "can't get terminal direction. %x", hr));
  2640. return TAPI_E_INVALIDTERMINAL;
  2641. }
  2642. if (m_Terminals.GetSize() > 0)
  2643. {
  2644. // check the direction of this terminal.
  2645. TERMINAL_DIRECTION Direction2;
  2646. hr = m_Terminals[0]->get_Direction(&Direction2);
  2647. if (FAILED(hr))
  2648. {
  2649. LOG((MSP_ERROR, "can't get terminal direction. %x", hr));
  2650. return TAPI_E_INVALIDTERMINAL;
  2651. }
  2652. if (Direction == Direction2)
  2653. {
  2654. LOG((MSP_ERROR,
  2655. "can't have two terminals with the same direction. %x", hr));
  2656. return TAPI_E_MAXTERMINALS;
  2657. }
  2658. }
  2659. return S_OK;
  2660. }
  2661. HRESULT CStreamVideoSend::SetUpFilters()
  2662. /*++
  2663. Routine Description:
  2664. Insert filters into the graph and connect to the terminals.
  2665. Arguments:
  2666. Return Value:
  2667. HRESULT.
  2668. --*/
  2669. {
  2670. LOG((MSP_TRACE, "VideoSend.SetUpFilters"));
  2671. // we only support one capture terminal and one preview
  2672. // window on this stream.
  2673. if (m_Terminals.GetSize() > 2)
  2674. {
  2675. return E_UNEXPECTED;
  2676. }
  2677. int iCaptureIndex = -1, iPreviewIndex = -1;
  2678. // Find out which terminal is capture and which is preview.
  2679. HRESULT hr;
  2680. for (int i = 0; i < m_Terminals.GetSize(); i ++)
  2681. {
  2682. TERMINAL_DIRECTION Direction;
  2683. hr = m_Terminals[i]->get_Direction(&Direction);
  2684. if (FAILED(hr))
  2685. {
  2686. LOG((MSP_ERROR, "can't get terminal direction. %x", hr));
  2687. SendStreamEvent(CALL_TERMINAL_FAIL, CALL_CAUSE_BAD_DEVICE, hr, m_Terminals[i]);
  2688. return hr;
  2689. }
  2690. if (Direction == TD_CAPTURE || Direction == TD_BIDIRECTIONAL)
  2691. {
  2692. iCaptureIndex = i;
  2693. }
  2694. else
  2695. {
  2696. iPreviewIndex = i;
  2697. }
  2698. }
  2699. // the stream will not work without a capture terminal.
  2700. if (iCaptureIndex == -1)
  2701. {
  2702. LOG((MSP_ERROR, "no capture terminal selected."));
  2703. return E_UNEXPECTED;
  2704. }
  2705. // Connect the capture filter to the terminal.
  2706. if (FAILED(hr = ConnectTerminal(
  2707. m_Terminals[iCaptureIndex]
  2708. )))
  2709. {
  2710. LOG((MSP_ERROR, "connect the codec filter to terminal. %x", hr));
  2711. return hr;
  2712. }
  2713. if (iPreviewIndex != -1)
  2714. {
  2715. // Connect the preview filter to the terminal.
  2716. if (FAILED(hr = ConnectTerminal(
  2717. m_Terminals[iPreviewIndex]
  2718. )))
  2719. {
  2720. LOG((MSP_ERROR, "connect the codec filter to terminal. %x", hr));
  2721. return hr;
  2722. }
  2723. }
  2724. return hr;
  2725. }
  2726. HRESULT CStreamVideoSend::GetVideoCapturePins(
  2727. IN ITTerminalControl* pTerminal,
  2728. OUT BOOL *pfDirectRTP
  2729. )
  2730. /*++
  2731. Routine Description:
  2732. Given a video capture terminal, find all the pins we need, which will be
  2733. the capture pin, preview pin, and the RTP packetization pin.
  2734. Side effect: It changes the m_pCapturePin, m_pPreviewPin, m_pRTPPin
  2735. members, which needs to be cleaned up if the terminal is disconnected.
  2736. Arguments:
  2737. pTerminal - a pointer to the ITTerminalControl interface.
  2738. pfDirectRTP - whether this terminal support RTP directly.
  2739. Return Value:
  2740. HRESULT
  2741. --*/
  2742. {
  2743. ENTER_FUNCTION("CStreamVideoSend::GetVideoCapturePins");
  2744. LOG((MSP_TRACE, "%s enters", __fxName));
  2745. const DWORD MAXPINS = 4;
  2746. DWORD dwNumPins = MAXPINS;
  2747. IPin * Pins[MAXPINS];
  2748. HRESULT hr = pTerminal->ConnectTerminal(
  2749. m_pIGraphBuilder, TD_CAPTURE, &dwNumPins, Pins
  2750. );
  2751. if (FAILED(hr))
  2752. {
  2753. LOG((MSP_ERROR, "%s, can't connect to terminal, hr=%x", __fxName, hr));
  2754. return hr;
  2755. }
  2756. _ASSERT(m_pCapturePin == NULL && m_pPreviewPin == NULL && m_pRTPPin == NULL);
  2757. if (IsBadReadPtr (Pins, dwNumPins * sizeof (IPin*)))
  2758. {
  2759. LOG((MSP_ERROR, "terminal returned bad pin array"));
  2760. return E_POINTER;
  2761. }
  2762. // find the pins we need.
  2763. for (DWORD i = 0; i < dwNumPins; i ++)
  2764. {
  2765. if (IsBadReadPtr (Pins[i], sizeof (IPin)))
  2766. {
  2767. LOG((MSP_ERROR, "terminal returned bad pin. # %d", i));
  2768. hr = E_POINTER;
  2769. break;
  2770. }
  2771. PIN_INFO PinInfo;
  2772. hr = Pins[i]->QueryPinInfo(&PinInfo);
  2773. if (FAILED(hr))
  2774. {
  2775. LOG((MSP_ERROR, "%s, can't get pin info, hr=%x", __fxName, hr));
  2776. break;
  2777. }
  2778. if (lstrcmpW(PinInfo.achName, PNAME_CAPTURE) == 0)
  2779. {
  2780. m_pCapturePin = Pins[i];
  2781. // remember the capture filter as well.
  2782. m_pCaptureFilter = PinInfo.pFilter;
  2783. m_pCaptureFilter->AddRef();
  2784. }
  2785. else if (lstrcmpW(PinInfo.achName, PNAME_PREVIEW) == 0)
  2786. {
  2787. m_pPreviewPin = Pins[i];
  2788. }
  2789. else if (lstrcmpW(PinInfo.achName, PNAME_RTPPD) == 0)
  2790. {
  2791. m_pRTPPin = Pins[i];
  2792. }
  2793. else if (PinInfo.dir == PINDIR_OUTPUT)
  2794. {
  2795. // this must be the capture filter of some third party terminal.
  2796. m_pCapturePin = Pins[i];
  2797. // remember the capture filter as well.
  2798. m_pCaptureFilter = PinInfo.pFilter;
  2799. m_pCaptureFilter->AddRef();
  2800. }
  2801. else
  2802. {
  2803. Pins[i]->Release();
  2804. }
  2805. // we don't need the filter here.
  2806. PinInfo.pFilter->Release();
  2807. }
  2808. // check if we have got all the pins we need.
  2809. if (m_pCapturePin == NULL ||
  2810. m_pPreviewPin == NULL ||
  2811. m_pRTPPin == NULL)
  2812. {
  2813. if ((m_pCapturePin != NULL)
  2814. && (hr = ::PinSupportsMediaType(
  2815. m_pCapturePin, __uuidof(MEDIATYPE_RTP_Single_Stream))) == S_OK)
  2816. {
  2817. // This terminal generates RTP directly.
  2818. *pfDirectRTP = TRUE;
  2819. return S_OK;
  2820. }
  2821. LOG((MSP_ERROR,
  2822. "%s, can't find all the pins, Capture:%p, Preview:%p, RTP:%P",
  2823. __fxName, m_pCapturePin, m_pPreviewPin, m_pRTPPin));
  2824. hr = E_UNEXPECTED;
  2825. }
  2826. if (hr != S_OK)
  2827. {
  2828. // something is wrong, clean up
  2829. pTerminal->DisconnectTerminal(m_pIGraphBuilder, 0);
  2830. CleanupCachedInterface();
  2831. return hr;
  2832. }
  2833. // now get the optional video interfaces.
  2834. _ASSERT(m_pIStreamConfig == NULL);
  2835. hr = m_pCapturePin->QueryInterface(&m_pIStreamConfig);
  2836. if (FAILED(hr))
  2837. {
  2838. LOG((MSP_WARN, "%s, queryinterface failed", __fxName));
  2839. }
  2840. hr = m_pCapturePin->QueryInterface(&m_pCaptureFrameRateControl);
  2841. if (FAILED(hr))
  2842. {
  2843. LOG((MSP_WARN,
  2844. "%s:query capture pin's IFrameRateControl failed, hr=%x",
  2845. __fxName, hr));
  2846. }
  2847. hr = m_pCapturePin->QueryInterface(&m_pCaptureBitrateControl);
  2848. if (FAILED(hr))
  2849. {
  2850. LOG((MSP_WARN,
  2851. "%s:query capture pin's IBitRateControl failed, hr=%x",
  2852. __fxName, hr));
  2853. }
  2854. hr = m_pPreviewPin->QueryInterface(&m_pPreviewFrameRateControl);
  2855. if (FAILED(hr))
  2856. {
  2857. LOG((MSP_WARN,
  2858. "%s:query preview pin's IFrameRateControl failed, hr=%x",
  2859. __fxName, hr));
  2860. }
  2861. return S_OK;
  2862. }
  2863. HRESULT CStreamVideoSend::ConnectCaptureTerminal(
  2864. IN ITTerminal * pITTerminal
  2865. )
  2866. /*++
  2867. Routine Description:
  2868. The stream needs its capture pin, preview pin, and RTP packetization pin.
  2869. The capture pin and the preview pin are connected to the RTP sink filter
  2870. and the preview pin is connected to the preivew terminal. If the preview
  2871. terminal doesn't exist yet, the preview pin is remembered and used later
  2872. when the preview terminal is selected.
  2873. Arguments:
  2874. pITTerminal - the terminal being connected.
  2875. Return Value:
  2876. HRESULT.
  2877. --*/
  2878. {
  2879. ENTER_FUNCTION("CStreamVideoSend::ConnectCaptureTerminal");
  2880. LOG((MSP_TRACE, "%s enters, pITTerminal:%p", __fxName, pITTerminal));
  2881. // Get the TerminalControl interface on the terminal
  2882. CComPtr<ITTerminalControl> pTerminal;
  2883. HRESULT hr = pITTerminal->QueryInterface(&pTerminal);
  2884. if (FAILED(hr))
  2885. {
  2886. LOG((MSP_ERROR,
  2887. "%s, can't get Terminal Control interface", __fxName));
  2888. SendStreamEvent(CALL_TERMINAL_FAIL,
  2889. CALL_CAUSE_BAD_DEVICE, E_NOINTERFACE, pITTerminal);
  2890. return E_NOINTERFACE;
  2891. }
  2892. // Find the pins on the capture terminal. The pins will be stored in
  2893. // m_pCapturePin, m_pPreviewPin, m_pRTPPin
  2894. BOOL fDirectRTP = FALSE;
  2895. hr = GetVideoCapturePins(pTerminal, &fDirectRTP);
  2896. if (FAILED(hr))
  2897. {
  2898. LOG((MSP_ERROR,
  2899. "%s, Get capture pins failed. hr=%x", __fxName, hr));
  2900. SendStreamEvent(CALL_TERMINAL_FAIL,
  2901. CALL_CAUSE_BAD_DEVICE, hr, pITTerminal);
  2902. return hr;
  2903. }
  2904. hr = CreateSendFilters(m_pCapturePin, m_pRTPPin, fDirectRTP);
  2905. if (FAILED(hr))
  2906. {
  2907. LOG((MSP_ERROR,
  2908. "%s, Create video send filters failed. hr=%x", __fxName, hr));
  2909. goto cleanup;
  2910. }
  2911. //
  2912. // Now we are actually connected. Update our state and perform
  2913. // postconnection.
  2914. //
  2915. hr = pTerminal->CompleteConnectTerminal();
  2916. if (FAILED(hr))
  2917. {
  2918. LOG((MSP_ERROR,
  2919. "%s, Create video send filters failed. hr=%x", __fxName, hr));
  2920. SendStreamEvent(CALL_TERMINAL_FAIL,
  2921. CALL_CAUSE_BAD_DEVICE, hr, pITTerminal);
  2922. goto cleanup;
  2923. }
  2924. if (m_pPreviewTerminal != NULL)
  2925. {
  2926. // errors will be fired as events.
  2927. ConnectPreviewTerminal(m_pPreviewTerminal);
  2928. }
  2929. return S_OK;
  2930. cleanup:
  2931. // disconnect the terminal.
  2932. pTerminal->DisconnectTerminal(m_pIGraphBuilder, 0);
  2933. CleanupCachedInterface();
  2934. // clean up internal filters as well.
  2935. CleanUpFilters();
  2936. return hr;
  2937. }
  2938. HRESULT CStreamVideoSend::ConnectPreviewTerminal(
  2939. IN ITTerminal * pITTerminal
  2940. )
  2941. /*++
  2942. Routine Description:
  2943. If the capture terminal has been connected, this function connects the
  2944. capture terminal's preview pin with the preview terminal. Otherwise, the
  2945. preview terminal is just remembered and wait for the capture terminal.
  2946. Arguments:
  2947. pITTerminal - the terminal being connected.
  2948. Return Value:
  2949. HRESULT.
  2950. --*/
  2951. {
  2952. ENTER_FUNCTION("CStreamVideoSend::ConnectPreviewTerminal");
  2953. LOG((MSP_TRACE, "%s enters, pITTerminal:%p", __fxName, pITTerminal));
  2954. if (!m_pCapturePin)
  2955. {
  2956. LOG ((MSP_TRACE, "%s capture pin is null.", __fxName));
  2957. return E_FAIL;
  2958. }
  2959. if (!m_pPreviewPin)
  2960. {
  2961. // the capture terminal is not selected yet. We will just wait.
  2962. LOG((MSP_TRACE, "%s, capture is not ready yet.", __fxName));
  2963. return S_OK;
  2964. }
  2965. // Get the TerminalControl interface on the terminal
  2966. CComPtr<ITTerminalControl> pTerminal;
  2967. HRESULT hr = pITTerminal->QueryInterface(&pTerminal);
  2968. if (FAILED(hr))
  2969. {
  2970. LOG((MSP_ERROR,
  2971. "%s, can't get Terminal Control interface", __fxName));
  2972. SendStreamEvent(CALL_TERMINAL_FAIL,
  2973. CALL_CAUSE_BAD_DEVICE, E_NOINTERFACE, pITTerminal);
  2974. return E_NOINTERFACE;
  2975. }
  2976. // find the input pin on the preview window.
  2977. CComPtr<IPin> pPreviewInputPin;
  2978. hr = FindPreviewInputPin(pTerminal, &pPreviewInputPin);
  2979. if (FAILED(hr))
  2980. {
  2981. LOG((MSP_ERROR,
  2982. "%s, find preview input pin failed. hr=%x", __fxName, hr));
  2983. SendStreamEvent(CALL_TERMINAL_FAIL,
  2984. CALL_CAUSE_BAD_DEVICE, hr, pITTerminal);
  2985. return hr;
  2986. }
  2987. // connect the pins together.
  2988. hr = m_pIGraphBuilder->Connect(m_pPreviewPin, pPreviewInputPin);
  2989. if (FAILED(hr))
  2990. {
  2991. LOG((MSP_ERROR,
  2992. "%s, connect preview pins failed. hr=%x", __fxName, hr));
  2993. return hr;
  2994. }
  2995. //
  2996. // Now we are actually connected, perform postconnection.
  2997. //
  2998. hr = pTerminal->CompleteConnectTerminal();
  2999. if (FAILED(hr))
  3000. {
  3001. LOG((MSP_ERROR,
  3002. "%s, complete connect terminal failed. hr=%x", __fxName, hr));
  3003. SendStreamEvent(CALL_TERMINAL_FAIL,
  3004. CALL_CAUSE_BAD_DEVICE, hr, pITTerminal);
  3005. // disconnect the terminal.
  3006. pTerminal->DisconnectTerminal(m_pIGraphBuilder, 0);
  3007. return hr;
  3008. }
  3009. return S_OK;
  3010. }
  3011. HRESULT CStreamVideoSend::ConnectTerminal(
  3012. IN ITTerminal * pITTerminal
  3013. )
  3014. /*++
  3015. Routine Description:
  3016. connect the video terminals to the stream.
  3017. Arguments:
  3018. Return Value:
  3019. HRESULT.
  3020. --*/
  3021. {
  3022. ENTER_FUNCTION("CStreamVideoSend::ConnectTerminal");
  3023. LOG((MSP_TRACE, "%s enters, pITTerminal:%p", __fxName, pITTerminal));
  3024. // Find out the direction of the terminal.
  3025. TERMINAL_DIRECTION Direction;
  3026. HRESULT hr = pITTerminal->get_Direction(&Direction);
  3027. if (FAILED(hr))
  3028. {
  3029. LOG((MSP_ERROR,
  3030. "%s, can't get terminal direction. hr=%x", __fxName, hr));
  3031. SendStreamEvent(CALL_TERMINAL_FAIL,
  3032. CALL_CAUSE_BAD_DEVICE, hr, pITTerminal);
  3033. return hr;
  3034. }
  3035. if (Direction != TD_RENDER)
  3036. {
  3037. hr = ConnectCaptureTerminal(pITTerminal);
  3038. if (SUCCEEDED(hr))
  3039. {
  3040. // save the capture terminal.
  3041. _ASSERT(m_pCaptureTerminal == NULL);
  3042. m_pCaptureTerminal = pITTerminal;
  3043. m_pCaptureTerminal->AddRef();
  3044. }
  3045. }
  3046. else
  3047. {
  3048. hr = ConnectPreviewTerminal(pITTerminal);
  3049. if (SUCCEEDED(hr))
  3050. {
  3051. // save the preview terminal.
  3052. _ASSERT(m_pPreviewTerminal == NULL);
  3053. m_pPreviewTerminal = pITTerminal;
  3054. m_pPreviewTerminal->AddRef();
  3055. }
  3056. }
  3057. return hr;
  3058. }
  3059. HRESULT CStreamVideoSend::DisconnectTerminal(
  3060. IN ITTerminal * pITTerminal
  3061. )
  3062. /*++
  3063. Routine Description:
  3064. Disconnect a terminal. It will remove its filters from the graph and
  3065. also release its references to the graph.
  3066. If it is the capture terminal being disconnected, all the pins that the
  3067. stream cached need to be released too.
  3068. Arguments:
  3069. pITTerminal - the terminal.
  3070. Return Value:
  3071. HRESULT.
  3072. --*/
  3073. {
  3074. ENTER_FUNCTION("CStreamVideoSend::DisconnectTerminal");
  3075. LOG((MSP_TRACE, "%s enters, pITTerminal:%p", __fxName, pITTerminal));
  3076. HRESULT hr = CIPConfMSPStream::DisconnectTerminal(pITTerminal);
  3077. if (pITTerminal == m_pCaptureTerminal)
  3078. {
  3079. // release all the capture pins we cached.
  3080. CleanupCachedInterface();
  3081. m_pCaptureTerminal->Release();
  3082. m_pCaptureTerminal = NULL;
  3083. CleanUpFilters ();
  3084. // disconnect preview term as well
  3085. // when we connect capture,
  3086. // we always try to connect preview if one is available
  3087. if (m_pPreviewTerminal)
  3088. {
  3089. CIPConfMSPStream::DisconnectTerminal(m_pPreviewTerminal);
  3090. }
  3091. }
  3092. else if (pITTerminal == m_pPreviewTerminal)
  3093. {
  3094. m_pPreviewTerminal->Release();
  3095. m_pPreviewTerminal = NULL;
  3096. }
  3097. return hr;
  3098. }
  3099. HRESULT CStreamVideoSend::ConnectRTPFilter(
  3100. IN IGraphBuilder *pIGraphBuilder,
  3101. IN IPin *pCapturePin,
  3102. IN IPin *pRTPPin,
  3103. IN IBaseFilter *pRTPFilter
  3104. )
  3105. {
  3106. ENTER_FUNCTION("CStreamVideoSend::ConnectRTPFilters");
  3107. LOG((MSP_TRACE, "%s enters", __fxName));
  3108. HRESULT hr;
  3109. // find the capture pin on the RTP filter.
  3110. CComPtr <IPin> pRTPCapturePin;
  3111. hr = pRTPFilter->FindPin(PNAME_CAPTURE, &pRTPCapturePin);
  3112. if (FAILED(hr))
  3113. {
  3114. LOG((MSP_ERROR,
  3115. "%s, find capture pin on rtp filter. %x", __fxName, hr));
  3116. return hr;
  3117. }
  3118. // Connect the capture pin of the video capture filter with the capture pin
  3119. // of the rTP filter.
  3120. hr = pIGraphBuilder->ConnectDirect(pCapturePin, pRTPCapturePin, NULL);
  3121. if (FAILED(hr))
  3122. {
  3123. LOG((MSP_ERROR,
  3124. "%s, can't connect capture pins. %x", __fxName, hr));
  3125. return hr;
  3126. }
  3127. if (pRTPPin)
  3128. {
  3129. // find the packetization pin on the RTP filter.
  3130. CComPtr <IPin> pRTPRTPPin;
  3131. hr = pRTPFilter->FindPin(PNAME_RTPPD, &pRTPRTPPin);
  3132. if (FAILED(hr))
  3133. {
  3134. LOG((MSP_ERROR,
  3135. "%s, find capture pin on rtp filter. %x", __fxName, hr));
  3136. pIGraphBuilder->Disconnect(pRTPPin);
  3137. return hr;
  3138. }
  3139. // Connect the RTP pin of the video capture filter with the RTP pin
  3140. // of the rTP filter.
  3141. hr = pIGraphBuilder->ConnectDirect(pRTPPin, pRTPRTPPin, NULL);
  3142. if (FAILED(hr))
  3143. {
  3144. LOG((MSP_ERROR,
  3145. "%s, can't connect capture pins. %x", __fxName, hr));
  3146. pIGraphBuilder->Disconnect(pRTPPin);
  3147. return hr;
  3148. }
  3149. }
  3150. return hr;
  3151. }
  3152. HRESULT CStreamVideoSend::ConfigureRTPFormats(
  3153. IN IBaseFilter * pIRTPFilter,
  3154. IN IStreamConfig * pIStreamConfig
  3155. )
  3156. /*++
  3157. Routine Description:
  3158. Configure the RTP filter with RTP<-->AM media type mappings.
  3159. Arguments:
  3160. pIRTPFilter - The source RTP Filter.
  3161. pIStreamConfig - The stream config interface that has the media info.
  3162. Return Value:
  3163. HRESULT.
  3164. --*/
  3165. {
  3166. ENTER_FUNCTION("VideoSend::ConfigureRTPFormats");
  3167. LOG((MSP_TRACE, "%s enters", __fxName));
  3168. HRESULT hr;
  3169. CComPtr<IRtpMediaControl> pIRtpMediaControl;
  3170. hr = pIRTPFilter->QueryInterface(&pIRtpMediaControl);
  3171. if (FAILED(hr))
  3172. {
  3173. LOG((MSP_ERROR, "%s adding source filter. %x", __fxName, hr));
  3174. return hr;
  3175. }
  3176. // find the number of capabilities supported.
  3177. DWORD dwCount;
  3178. hr = pIStreamConfig->GetNumberOfCapabilities(&dwCount);
  3179. if (FAILED(hr))
  3180. {
  3181. LOG((MSP_ERROR, "%s GetNumberOfCapabilities. %x", __fxName, hr));
  3182. return hr;
  3183. }
  3184. BOOL fFound = FALSE;
  3185. BOOL fFormatSet = FALSE;
  3186. for (DWORD dw = 0; dw < dwCount; dw ++)
  3187. {
  3188. // TODO, a new interface is needed to resolve RTP to MediaType.
  3189. AM_MEDIA_TYPE *pMediaType;
  3190. DWORD dwPayloadType;
  3191. hr = pIStreamConfig->GetStreamCaps(
  3192. dw, &pMediaType, NULL, &dwPayloadType
  3193. );
  3194. if (FAILED(hr))
  3195. {
  3196. LOG((MSP_ERROR, "%s GetStreamCaps. %x", __fxName, hr));
  3197. return hr;
  3198. }
  3199. BITMAPINFOHEADER *pHeader = HEADER(pMediaType->pbFormat);
  3200. if (pHeader == NULL)
  3201. {
  3202. MSPDeleteMediaType(pMediaType);
  3203. continue;
  3204. }
  3205. // check the image size
  3206. if (m_Settings.fCIF)
  3207. {
  3208. if (pHeader->biWidth != CIFWIDTH)
  3209. {
  3210. MSPDeleteMediaType(pMediaType);
  3211. continue;
  3212. }
  3213. }
  3214. else
  3215. {
  3216. if (pHeader->biWidth != QCIFWIDTH)
  3217. {
  3218. MSPDeleteMediaType(pMediaType);
  3219. continue;
  3220. }
  3221. }
  3222. for (DWORD dw2 = 0; dw2 < m_Settings.dwNumPayloadTypes; dw2 ++)
  3223. {
  3224. if (dwPayloadType == m_Settings.PayloadTypes[dw2])
  3225. {
  3226. hr = pIRtpMediaControl->SetFormatMapping(
  3227. dwPayloadType,
  3228. 90000, // default video clock rate.
  3229. pMediaType
  3230. );
  3231. if (FAILED(hr))
  3232. {
  3233. MSPDeleteMediaType(pMediaType);
  3234. LOG((MSP_ERROR, "%s SetFormatMapping. %x", __fxName, hr));
  3235. return hr;
  3236. }
  3237. else
  3238. {
  3239. LOG((MSP_INFO, "%s Configured payload:%d", __fxName, dwPayloadType));
  3240. }
  3241. if (dw2 == 0 && !fFormatSet)
  3242. {
  3243. // tell the encoder to use this format.
  3244. // TODO, cache all the allowed mediatypes in the conference for
  3245. // future enumerations. It would be nice that we can get the SDP blob
  3246. // when the call object is created.
  3247. hr = pIStreamConfig->SetFormat(dwPayloadType, pMediaType);
  3248. if (FAILED(hr))
  3249. {
  3250. MSPDeleteMediaType(pMediaType);
  3251. LOG((MSP_ERROR, "%s SetFormat. %x", __fxName, hr));
  3252. return hr;
  3253. }
  3254. fFormatSet = TRUE;
  3255. }
  3256. }
  3257. }
  3258. MSPDeleteMediaType(pMediaType);
  3259. }
  3260. return S_OK;
  3261. }
  3262. HRESULT CStreamVideoSend::CreateSendFilters(
  3263. IN IPin *pCapturePin,
  3264. IN IPin *pRTPPin,
  3265. IN BOOL fDirectRTP
  3266. )
  3267. /*++
  3268. Routine Description:
  3269. Insert filters into the graph and connect to the capture pin.
  3270. Capturepin->[Encoder]->RTPRender
  3271. Arguments:
  3272. pCapturePin - the capture pin on the capture filter.
  3273. pRTPPin - the RTP packetization pin.
  3274. fDirectRTP - the capture pin supports RTP directly.
  3275. Return Value:
  3276. HRESULT.
  3277. --*/
  3278. {
  3279. ENTER_FUNCTION("CStreamVideoSend::CreateSendFilters");
  3280. LOG((MSP_TRACE, "%s enters", __fxName));
  3281. HRESULT hr;
  3282. // Create the RTP render filter and add it into the graph.
  3283. CComPtr<IBaseFilter> pRenderFilter;
  3284. if (m_pIRTPSession == NULL)
  3285. {
  3286. if (FAILED(hr = ::AddFilter(
  3287. m_pIGraphBuilder,
  3288. __uuidof(MSRTPRenderFilter),
  3289. L"RtpRender",
  3290. &pRenderFilter)))
  3291. {
  3292. LOG((MSP_ERROR, "%s, adding render filter. hr=%x", __fxName, hr));
  3293. return hr;
  3294. }
  3295. if (FAILED(hr = ConfigureRTPFilter(pRenderFilter)))
  3296. {
  3297. LOG((MSP_ERROR, "%s, configure RTP render filter failed. %x", __fxName, hr));
  3298. return hr;
  3299. }
  3300. }
  3301. else
  3302. {
  3303. if (FAILED (hr = m_pIRTPSession->QueryInterface (&pRenderFilter)))
  3304. {
  3305. LOG ((MSP_ERROR, "%s failed to get filter from rtp session. %x", __fxName, hr));
  3306. return hr;
  3307. }
  3308. if (FAILED (hr = m_pIGraphBuilder->AddFilter ((IBaseFilter *)pRenderFilter, L"RtpRender")))
  3309. {
  3310. LOG ((MSP_ERROR, "%s failed to add filter to graph. %x", __fxName, hr));
  3311. return hr;
  3312. }
  3313. }
  3314. if (!fDirectRTP)
  3315. {
  3316. CComPtr<IStreamConfig> pIStreamConfig;
  3317. hr = pCapturePin->QueryInterface(&pIStreamConfig);
  3318. if (FAILED(hr))
  3319. {
  3320. LOG((MSP_ERROR, "%s, query IStreamConfig. %x", __fxName, hr));
  3321. return hr;
  3322. }
  3323. // configure the format info on the RTP filter
  3324. if (FAILED(hr = ConfigureRTPFormats(pRenderFilter, pIStreamConfig)))
  3325. {
  3326. LOG((MSP_ERROR, "%s, configure RTP formats. %x", __fxName, hr));
  3327. return hr;
  3328. }
  3329. }
  3330. else
  3331. {
  3332. // configure RTP_SINGLE_STREAM to on the RTP filter.
  3333. }
  3334. if (FAILED(hr = ConnectRTPFilter(
  3335. m_pIGraphBuilder,
  3336. pCapturePin,
  3337. pRTPPin,
  3338. pRenderFilter
  3339. )))
  3340. {
  3341. LOG((MSP_ERROR,
  3342. "%s, connect capture pin and the Render filter. %x", __fxName, hr));
  3343. return hr;
  3344. }
  3345. return S_OK;
  3346. }
  3347. //
  3348. // IInnerStreamQualityControl methods.
  3349. //
  3350. STDMETHODIMP CStreamVideoSend::GetRange(
  3351. IN InnerStreamQualityProperty property,
  3352. OUT LONG *plMin,
  3353. OUT LONG *plMax,
  3354. OUT LONG *plSteppingDelta,
  3355. OUT LONG *plDefault,
  3356. OUT TAPIControlFlags *plFlags
  3357. )
  3358. /*++
  3359. Routine Description:
  3360. Get the range for a quality control property. Delegated to capture filter
  3361. for now.
  3362. Arguments:
  3363. Return Value:
  3364. HRESULT.
  3365. --*/
  3366. {
  3367. ENTER_FUNCTION("CStreamVideoSend::GetRange (InnerStreamQualityControl)");
  3368. HRESULT hr;
  3369. static BOOL fReported = FALSE;
  3370. CLock lock(m_lock);
  3371. switch (property)
  3372. {
  3373. case InnerStreamQuality_MinFrameInterval:
  3374. if (m_pCaptureFrameRateControl == NULL)
  3375. {
  3376. if (!fReported)
  3377. {
  3378. LOG((MSP_WARN, "%s, m_pCaptureFrameRateControl is NULL", __fxName));
  3379. fReported = TRUE;
  3380. }
  3381. hr = E_NOTIMPL;
  3382. }
  3383. else
  3384. {
  3385. hr = m_pCaptureFrameRateControl->GetRange(
  3386. FrameRateControl_Maximum, plMin, plMax, plSteppingDelta, plDefault, plFlags
  3387. );
  3388. }
  3389. break;
  3390. case InnerStreamQuality_AvgFrameInterval:
  3391. if (m_pCaptureFrameRateControl == NULL)
  3392. {
  3393. if (!fReported)
  3394. {
  3395. LOG((MSP_WARN, "%s, m_pCaptureFrameRateControl is NULL", __fxName));
  3396. fReported = TRUE;
  3397. }
  3398. hr = E_NOTIMPL;
  3399. }
  3400. else
  3401. {
  3402. hr = m_pCaptureFrameRateControl->GetRange(
  3403. FrameRateControl_Current, plMin, plMax, plSteppingDelta, plDefault, plFlags
  3404. );
  3405. }
  3406. break;
  3407. case InnerStreamQuality_MaxBitrate:
  3408. if (m_pCaptureBitrateControl == NULL)
  3409. {
  3410. if (!fReported)
  3411. {
  3412. LOG((MSP_WARN, "%s, m_pCaptureBitrateControl is NULL", __fxName));
  3413. fReported = TRUE;
  3414. }
  3415. hr = E_NOTIMPL;
  3416. }
  3417. else
  3418. {
  3419. hr = m_pCaptureBitrateControl->GetRange(
  3420. BitrateControl_Maximum, plMin, plMax, plSteppingDelta, plDefault, plFlags, LAYERID
  3421. );
  3422. if (S_OK == hr)
  3423. {
  3424. if (*plMax < QCLIMIT_MIN_BITRATE)
  3425. {
  3426. LOG ((MSP_WARN, "%s: max bitrate %d too low", __fxName, *plMax));
  3427. hr = E_UNEXPECTED;
  3428. }
  3429. else
  3430. {
  3431. // adjust the min and default value
  3432. if (*plMin < QCLIMIT_MIN_BITRATE)
  3433. *plMin = QCLIMIT_MIN_BITRATE;
  3434. if (*plDefault < QCLIMIT_MIN_BITRATE)
  3435. *plDefault = QCLIMIT_MIN_BITRATE;
  3436. }
  3437. }
  3438. }
  3439. break;
  3440. case InnerStreamQuality_CurrBitrate:
  3441. if (m_pCaptureBitrateControl == NULL)
  3442. {
  3443. if (!fReported)
  3444. {
  3445. LOG((MSP_WARN, "%s, m_pCaptureBitrateControl is NULL", __fxName));
  3446. fReported = TRUE;
  3447. }
  3448. hr = E_NOTIMPL;
  3449. }
  3450. else
  3451. {
  3452. hr = m_pCaptureBitrateControl->GetRange(
  3453. BitrateControl_Current, plMin, plMax, plSteppingDelta, plDefault, plFlags, LAYERID
  3454. );
  3455. if (S_OK == hr)
  3456. {
  3457. if (*plMax < QCLIMIT_MIN_BITRATE)
  3458. {
  3459. LOG ((MSP_WARN, "%s: max bitrate %d too low", __fxName, *plMax));
  3460. hr = E_UNEXPECTED;
  3461. }
  3462. else
  3463. {
  3464. // adjust the min and default value
  3465. if (*plMin < QCLIMIT_MIN_BITRATE)
  3466. *plMin = QCLIMIT_MIN_BITRATE;
  3467. if (*plDefault < QCLIMIT_MIN_BITRATE)
  3468. *plDefault = QCLIMIT_MIN_BITRATE;
  3469. }
  3470. }
  3471. }
  3472. break;
  3473. default:
  3474. hr = CIPConfMSPStream::GetRange (property, plMin, plMax, plSteppingDelta, plDefault, plFlags);
  3475. break;
  3476. }
  3477. return hr;
  3478. }
  3479. STDMETHODIMP CStreamVideoSend::Get(
  3480. IN InnerStreamQualityProperty property,
  3481. OUT LONG *plValue,
  3482. OUT TAPIControlFlags *plFlags
  3483. )
  3484. /*++
  3485. Routine Description:
  3486. Get the value for a quality control property. Delegated to the quality
  3487. controller.
  3488. Arguments:
  3489. Return Value:
  3490. HRESULT.
  3491. --*/
  3492. {
  3493. ENTER_FUNCTION("CStreamVideoSend::Get(QualityControl)");
  3494. HRESULT hr;
  3495. static BOOL fReported = FALSE;
  3496. CLock lock(m_lock);
  3497. switch (property)
  3498. {
  3499. case InnerStreamQuality_MinFrameInterval:
  3500. if (m_pCaptureFrameRateControl == NULL)
  3501. {
  3502. if (!fReported)
  3503. {
  3504. LOG((MSP_WARN, "%s, m_pCaptureFrameRateControl is NULL", __fxName));
  3505. fReported = TRUE;
  3506. }
  3507. hr = E_NOTIMPL;
  3508. }
  3509. else
  3510. {
  3511. hr = m_pCaptureFrameRateControl->Get(FrameRateControl_Maximum, plValue, plFlags);
  3512. }
  3513. break;
  3514. case InnerStreamQuality_AvgFrameInterval:
  3515. if (m_pCaptureFrameRateControl == NULL)
  3516. {
  3517. if (!fReported)
  3518. {
  3519. LOG((MSP_WARN, "%s, m_pCaptureFrameRateControl is NULL", __fxName));
  3520. fReported = TRUE;
  3521. }
  3522. hr = E_NOTIMPL;
  3523. }
  3524. else
  3525. {
  3526. hr = m_pCaptureFrameRateControl->Get(FrameRateControl_Current, plValue, plFlags);
  3527. }
  3528. break;
  3529. case InnerStreamQuality_MaxBitrate:
  3530. if( m_pCaptureBitrateControl == NULL )
  3531. {
  3532. if (!fReported)
  3533. {
  3534. LOG((MSP_WARN, "%s, m_pICaptureBitrateControl is NULL", __fxName));
  3535. fReported = TRUE;
  3536. }
  3537. hr = E_NOTIMPL;
  3538. }
  3539. else
  3540. {
  3541. hr = m_pCaptureBitrateControl->Get(BitrateControl_Maximum, plValue, plFlags, LAYERID);
  3542. }
  3543. break;
  3544. case InnerStreamQuality_CurrBitrate:
  3545. if (m_pCaptureBitrateControl == NULL)
  3546. {
  3547. if (!fReported)
  3548. {
  3549. LOG((MSP_WARN, "%s, m_pCaptureBitrateControl is NULL", __fxName));
  3550. fReported = TRUE;
  3551. }
  3552. hr = E_NOTIMPL;
  3553. }
  3554. else
  3555. {
  3556. hr = m_pCaptureBitrateControl->Get(BitrateControl_Current, plValue, plFlags, LAYERID);
  3557. }
  3558. break;
  3559. default:
  3560. hr = CIPConfMSPStream::Get (property, plValue, plFlags);
  3561. break;
  3562. }
  3563. return hr;
  3564. }
  3565. STDMETHODIMP CStreamVideoSend::Set(
  3566. IN InnerStreamQualityProperty property,
  3567. IN LONG lValue,
  3568. IN TAPIControlFlags lFlags
  3569. )
  3570. /*++
  3571. Routine Description:
  3572. Set the value for a quality control property. Delegated to the quality
  3573. controller.
  3574. Arguments:
  3575. Return Value:
  3576. HRESULT.
  3577. --*/
  3578. {
  3579. ENTER_FUNCTION("CStreamVideoSend::Set(InnerStreamQualityControl)");
  3580. CLock lock(m_lock);
  3581. HRESULT hr;
  3582. LONG l;
  3583. static BOOL fReported = FALSE;
  3584. LONG min, max, delta, Default;
  3585. TAPIControlFlags flags;
  3586. switch (property)
  3587. {
  3588. // adjusted frame rate by call qc
  3589. case InnerStreamQuality_AdjMinFrameInterval:
  3590. if (m_pCaptureFrameRateControl == NULL &&
  3591. m_pPreviewFrameRateControl == NULL)
  3592. {
  3593. if (!fReported)
  3594. {
  3595. LOG((MSP_WARN, "%s, Capture/Preview FrameRateControl is NULL", __fxName));
  3596. fReported = TRUE;
  3597. }
  3598. hr = E_NOTIMPL;
  3599. break;
  3600. }
  3601. // set capture frame rate control
  3602. if (m_pCaptureFrameRateControl)
  3603. {
  3604. // get valid range
  3605. if (FAILED (hr = m_pCaptureFrameRateControl->GetRange (
  3606. FrameRateControl_Current,
  3607. &min, &max, &delta, &Default, &flags)))
  3608. {
  3609. LOG ((MSP_ERROR, "%s failed to getrange on capture frame rate control. %x", __fxName, hr));
  3610. }
  3611. else
  3612. {
  3613. // adjust value
  3614. l = lValue;
  3615. // use current value - max - if input value not set
  3616. if (l==QCDEFAULT_QUALITY_UNSET) l = max;
  3617. else if (l<min) l = min;
  3618. else if (l>max) l = max;
  3619. // remember the value
  3620. m_pStreamQCRelay->Set (property, l, lFlags);
  3621. if (FAILED (hr = m_pCaptureFrameRateControl->Set(FrameRateControl_Maximum, l, lFlags)))
  3622. {
  3623. LOG ((MSP_ERROR, "%s failed to set on capture frame rate control. value %d, hr %x", __fxName, l, hr));
  3624. }
  3625. }
  3626. }
  3627. // set Preview frame rate control
  3628. if (m_pPreviewFrameRateControl)
  3629. {
  3630. // get valid range
  3631. if (FAILED (hr = m_pPreviewFrameRateControl->GetRange (
  3632. FrameRateControl_Current,
  3633. &min, &max, &delta, &Default, &flags)))
  3634. {
  3635. LOG ((MSP_ERROR, "%s failed to getrange on Preview frame rate control. %x", __fxName, hr));
  3636. }
  3637. else
  3638. {
  3639. // adjust value
  3640. l = lValue;
  3641. // use current value - max - if input value not set
  3642. if (l==QCDEFAULT_QUALITY_UNSET) l = max;
  3643. else if (l<min) l = min;
  3644. else if (l>max) l = max;
  3645. // remember the value
  3646. m_pStreamQCRelay->Set (property, l, lFlags);
  3647. if (FAILED (hr = m_pPreviewFrameRateControl->Set(FrameRateControl_Maximum, l, lFlags)))
  3648. {
  3649. LOG ((MSP_ERROR, "%s failed to set on Preview frame rate control. value %d, hr %x", __fxName, l, hr));
  3650. }
  3651. }
  3652. }
  3653. break;
  3654. // adjusted bitrate by call qc
  3655. case InnerStreamQuality_AdjMaxBitrate:
  3656. if (m_pCaptureBitrateControl == NULL)
  3657. {
  3658. if (!fReported)
  3659. {
  3660. LOG((MSP_WARN, "%s, Capture BitrateControl is NULL", __fxName));
  3661. fReported = TRUE;
  3662. }
  3663. hr = E_NOTIMPL;
  3664. break;
  3665. }
  3666. // set capture bitrate control
  3667. if (m_pCaptureBitrateControl)
  3668. {
  3669. // get valid range
  3670. if (FAILED (hr = m_pCaptureBitrateControl->GetRange (
  3671. BitrateControl_Current,
  3672. &min, &max, &delta, &Default, &flags, LAYERID)))
  3673. {
  3674. LOG ((MSP_ERROR, "%s failed to getrange on capture bitrate control. %x", __fxName, hr));
  3675. }
  3676. else
  3677. {
  3678. // adjust value
  3679. l = lValue;
  3680. if (!m_pStreamQCRelay->m_fQOSAllowedToSend)
  3681. if (l > QCLIMIT_MAX_QOSNOTALLOWEDTOSEND)
  3682. l = QCLIMIT_MAX_QOSNOTALLOWEDTOSEND;
  3683. // use current value - max - if input value not set
  3684. if (l==QCDEFAULT_QUALITY_UNSET) l = max;
  3685. else if (l<min) l = min;
  3686. else if (l>max) l = max;
  3687. // remember the value
  3688. m_pStreamQCRelay->Set (property, l, lFlags);
  3689. if (FAILED (hr = m_pCaptureBitrateControl->Set(BitrateControl_Maximum, l, lFlags, LAYERID)))
  3690. {
  3691. LOG ((MSP_ERROR, "%s failed to set on capture bit rate control. value %d, hr %x", __fxName, l, hr));
  3692. }
  3693. }
  3694. }
  3695. break;
  3696. case InnerStreamQuality_PrefMaxBitrate:
  3697. // check input value
  3698. if (m_pCaptureBitrateControl)
  3699. {
  3700. // get valid range
  3701. if (FAILED (hr = m_pCaptureBitrateControl->GetRange (
  3702. BitrateControl_Current,
  3703. &min, &max, &delta, &Default, &flags, LAYERID)))
  3704. {
  3705. LOG ((MSP_ERROR, "%s failed to getrange on capture bitrate control. %x", __fxName, hr));
  3706. }
  3707. else
  3708. {
  3709. if (lValue < min || lValue > max)
  3710. return E_INVALIDARG;
  3711. }
  3712. }
  3713. else
  3714. {
  3715. LOG((MSP_WARN, "%s no bitratecontrol to check bitrate input.", __fxName));
  3716. }
  3717. hr = CIPConfMSPStream::Set (property, lValue, lFlags);
  3718. break;
  3719. case InnerStreamQuality_PrefMinFrameInterval:
  3720. // check input value
  3721. if (m_pCaptureFrameRateControl)
  3722. {
  3723. // get valid range
  3724. if (FAILED (hr = m_pCaptureFrameRateControl->GetRange (
  3725. FrameRateControl_Current,
  3726. &min, &max, &delta, &Default, &flags)))
  3727. {
  3728. LOG ((MSP_ERROR, "%s failed to getrange on capture frame rate control. %x", __fxName, hr));
  3729. }
  3730. else
  3731. {
  3732. if (lValue < min || lValue > max)
  3733. return E_INVALIDARG;
  3734. }
  3735. }
  3736. else
  3737. {
  3738. LOG((MSP_WARN, "%s no framerate cntl to check input.", __fxName));
  3739. }
  3740. hr = CIPConfMSPStream::Set (property, lValue, lFlags);
  3741. break;
  3742. default:
  3743. hr = CIPConfMSPStream::Set (property, lValue, lFlags);
  3744. break;
  3745. }
  3746. return hr;
  3747. }
  3748. /////////////////////////////////////////////////////////////////////////////
  3749. //
  3750. // CSubStreamVideoRecv
  3751. //
  3752. /////////////////////////////////////////////////////////////////////////////
  3753. CSubStreamVideoRecv::CSubStreamVideoRecv()
  3754. : m_pFTM(NULL),
  3755. m_pStream(NULL),
  3756. m_pCurrentParticipant(NULL)
  3757. {
  3758. }
  3759. // methods called by the videorecv object.
  3760. HRESULT CSubStreamVideoRecv::Init(
  3761. IN CStreamVideoRecv * pStream
  3762. )
  3763. /*++
  3764. Routine Description:
  3765. Initialize the substream object.
  3766. Arguments:
  3767. pStream - The pointer to the stream that owns this substream.
  3768. Return Value:
  3769. HRESULT.
  3770. --*/
  3771. {
  3772. LOG((MSP_TRACE,
  3773. "CSubStreamVideoRecv::Init, pStream %p", pStream));
  3774. // This method is called only once when the object is created. No other
  3775. // method will be called until this function succeeds. No need to lock.
  3776. _ASSERTE(m_pStream == NULL);
  3777. // initialize the terminal array so that the array is not NULL. Used for
  3778. // generating an empty enumerator if no terminal is selected.
  3779. if (!m_Terminals.Grow())
  3780. {
  3781. LOG((MSP_ERROR, "CSubStreamVideoRecv::Init - exit E_OUTOFMEMORY"));
  3782. return E_OUTOFMEMORY;
  3783. }
  3784. // create the marshaler.
  3785. HRESULT hr;
  3786. hr = CoCreateFreeThreadedMarshaler(GetControllingUnknown(), &m_pFTM);
  3787. if (FAILED(hr))
  3788. {
  3789. LOG((MSP_ERROR, "create marshaler failed, %x", hr));
  3790. return hr;
  3791. }
  3792. // save the stream reference.
  3793. m_pStream = pStream;
  3794. (pStream->GetControllingUnknown())->AddRef();
  3795. LOG((MSP_TRACE, "CSubStreamVideoRecv::Init returns S_OK"));
  3796. return S_OK;
  3797. }
  3798. #ifdef DEBUG_REFCOUNT
  3799. ULONG CSubStreamVideoRecv::InternalAddRef()
  3800. {
  3801. ULONG lRef = CComObjectRootEx<CComMultiThreadModelNoCS>::InternalAddRef();
  3802. LOG((MSP_TRACE, "SubStreamVideoRecv %p Addref, ref = %d", this, lRef));
  3803. return lRef;
  3804. }
  3805. ULONG CSubStreamVideoRecv::InternalRelease()
  3806. {
  3807. ULONG lRef = CComObjectRootEx<CComMultiThreadModelNoCS>::InternalRelease();
  3808. LOG((MSP_TRACE, "SubStreamVideoRecv %p Release, ref = %d", this, lRef));
  3809. return lRef;
  3810. }
  3811. #endif
  3812. void CSubStreamVideoRecv::FinalRelease()
  3813. /*++
  3814. Routine Description:
  3815. release everything before being deleted.
  3816. Arguments:
  3817. Return Value:
  3818. --*/
  3819. {
  3820. LOG((MSP_TRACE, "CSubStreamVideoRecv::FinalRelease - enter"));
  3821. if (m_pCurrentParticipant)
  3822. {
  3823. m_pCurrentParticipant->Release();
  3824. }
  3825. for ( int i = 0; i < m_Terminals.GetSize(); i ++ )
  3826. {
  3827. m_Terminals[i]->Release();
  3828. }
  3829. m_Terminals.RemoveAll();
  3830. if (m_pStream)
  3831. {
  3832. (m_pStream->GetControllingUnknown())->Release();
  3833. }
  3834. if (m_pFTM)
  3835. {
  3836. m_pFTM->Release();
  3837. }
  3838. LOG((MSP_TRACE, "CSubStreamVideoRecv::FinalRelease - exit"));
  3839. }
  3840. STDMETHODIMP CSubStreamVideoRecv::SelectTerminal(
  3841. IN ITTerminal * pTerminal
  3842. )
  3843. /*++
  3844. Routine Description:
  3845. Select a terminal on this substream. This method calls the same method
  3846. on the stream object to handle that.
  3847. Arguments:
  3848. pTerminal - the terminal to be selected.
  3849. Return Value:
  3850. --*/
  3851. {
  3852. LOG((MSP_TRACE,
  3853. "CSubStreamVideoRecv::SelectTerminal, pTerminal %p", pTerminal));
  3854. HRESULT hr;
  3855. m_lock.Lock();
  3856. if (m_Terminals.GetSize() > 0)
  3857. {
  3858. m_lock.Unlock();
  3859. return TAPI_E_MAXTERMINALS;
  3860. }
  3861. BOOL bFlag = m_Terminals.Add(pTerminal);
  3862. _ASSERTE(bFlag);
  3863. m_lock.Unlock();
  3864. if (!bFlag)
  3865. {
  3866. return E_OUTOFMEMORY;
  3867. }
  3868. // This is the refcount for the pointer in m_Terminals.
  3869. pTerminal->AddRef();
  3870. // Call the stream's select terminal to handle the state changes and also
  3871. // make sure that locking happens only from the stream to substream.
  3872. hr = m_pStream->SubStreamSelectTerminal(this, pTerminal);
  3873. if (FAILED(hr))
  3874. {
  3875. LOG((MSP_ERROR,
  3876. "CSubStreamVideoRecv::SelectTerminal failed, hr:%x", hr));
  3877. m_lock.Lock();
  3878. m_Terminals.Remove(pTerminal);
  3879. pTerminal->Release();
  3880. m_lock.Unlock();
  3881. }
  3882. return hr;
  3883. }
  3884. STDMETHODIMP CSubStreamVideoRecv::UnselectTerminal(
  3885. IN ITTerminal * pTerminal
  3886. )
  3887. /*++
  3888. Routine Description:
  3889. Unselect a terminal on this substream. This method calls the same method
  3890. on the stream object to handle that.
  3891. Arguments:
  3892. pTerminal - the terminal to be unselected.
  3893. Return Value:
  3894. --*/
  3895. {
  3896. LOG((MSP_TRACE,
  3897. "CSubStreamVideoRecv::UnSelectTerminal, pTerminal %p", pTerminal));
  3898. m_lock.Lock();
  3899. if (!m_Terminals.Remove(pTerminal))
  3900. {
  3901. m_lock.Unlock();
  3902. LOG((MSP_ERROR, "SubStreamVideoRecv::UnselectTerminal, invalid terminal."));
  3903. return TAPI_E_INVALIDTERMINAL;
  3904. }
  3905. pTerminal->Release();
  3906. m_lock.Unlock();
  3907. HRESULT hr;
  3908. // Call the stream's unselect terminal to handle the state changes and also
  3909. // make sure that locking happens only from the stream to substream.
  3910. hr = m_pStream->UnselectTerminal(pTerminal);
  3911. if (FAILED(hr))
  3912. {
  3913. LOG((MSP_ERROR,
  3914. "CSubStreamVideoRecv::UnSelectTerminal failed, hr:%x", hr));
  3915. }
  3916. return hr;
  3917. }
  3918. STDMETHODIMP CSubStreamVideoRecv::EnumerateTerminals(
  3919. OUT IEnumTerminal ** ppEnumTerminal
  3920. )
  3921. {
  3922. LOG((MSP_TRACE,
  3923. "EnumerateTerminals entered. ppEnumTerminal:%x", ppEnumTerminal));
  3924. if (IsBadWritePtr(ppEnumTerminal, sizeof(VOID *)))
  3925. {
  3926. LOG((MSP_ERROR, "ppEnumTerminal is a bad pointer"));
  3927. return E_POINTER;
  3928. }
  3929. // acquire the lock before accessing the Terminal object list.
  3930. CLock lock(m_lock);
  3931. if (m_Terminals.GetData() == NULL)
  3932. {
  3933. LOG((MSP_ERROR, "CSubStreamVideoRecv::EnumerateTerminals - "
  3934. "stream appears to have been shut down - exit E_UNEXPECTED"));
  3935. return E_UNEXPECTED;
  3936. }
  3937. typedef _CopyInterface<ITTerminal> CCopy;
  3938. typedef CSafeComEnum<IEnumTerminal, &__uuidof(IEnumTerminal),
  3939. ITTerminal *, CCopy> CEnumerator;
  3940. HRESULT hr;
  3941. CMSPComObject<CEnumerator> *pEnum = NULL;
  3942. hr = ::CreateCComObjectInstance(&pEnum);
  3943. if (pEnum == NULL)
  3944. {
  3945. LOG((MSP_ERROR, "Could not create enumerator object, %x", hr));
  3946. return hr;
  3947. }
  3948. // query for the __uuidof(IEnumTerminal) i/f
  3949. IEnumTerminal * pEnumTerminal;
  3950. hr = pEnum->_InternalQueryInterface(__uuidof(IEnumTerminal), (void**)&pEnumTerminal);
  3951. if (FAILED(hr))
  3952. {
  3953. LOG((MSP_ERROR, "query enum interface failed, %x", hr));
  3954. delete pEnum;
  3955. return hr;
  3956. }
  3957. // The CSafeComEnum can handle zero-sized array.
  3958. hr = pEnum->Init(
  3959. m_Terminals.GetData(), // the begin itor
  3960. m_Terminals.GetData() + m_Terminals.GetSize(), // the end itor,
  3961. NULL, // IUnknown
  3962. AtlFlagCopy // copy the data.
  3963. );
  3964. if (FAILED(hr))
  3965. {
  3966. LOG((MSP_ERROR, "init enumerator object failed, %x", hr));
  3967. pEnumTerminal->Release();
  3968. return hr;
  3969. }
  3970. LOG((MSP_TRACE, "CSubStreamVideoRecv::EnumerateTerminals - exit S_OK"));
  3971. *ppEnumTerminal = pEnumTerminal;
  3972. return hr;
  3973. }
  3974. STDMETHODIMP CSubStreamVideoRecv::get_Terminals(
  3975. OUT VARIANT * pVariant
  3976. )
  3977. {
  3978. LOG((MSP_TRACE, "CSubStreamVideoRecv::get_Terminals - enter"));
  3979. //
  3980. // Check parameters.
  3981. //
  3982. if ( IsBadWritePtr(pVariant, sizeof(VARIANT) ) )
  3983. {
  3984. LOG((MSP_ERROR, "CSubStreamVideoRecv::get_Terminals - "
  3985. "bad pointer argument - exit E_POINTER"));
  3986. return E_POINTER;
  3987. }
  3988. //
  3989. // See if this stream has been shut down. Acquire the lock before accessing
  3990. // the terminal object list.
  3991. //
  3992. CLock lock(m_lock);
  3993. if (m_Terminals.GetData() == NULL)
  3994. {
  3995. LOG((MSP_ERROR, "CSubStreamVideoRecv::get_Terminals - "
  3996. "stream appears to have been shut down - exit E_UNEXPECTED"));
  3997. return E_UNEXPECTED;
  3998. }
  3999. //
  4000. // create the collection object - see mspcoll.h
  4001. //
  4002. HRESULT hr;
  4003. typedef CTapiIfCollection< ITTerminal * > TerminalCollection;
  4004. CComObject<TerminalCollection> * pCollection;
  4005. hr = ::CreateCComObjectInstance(&pCollection);
  4006. if ( FAILED(hr) )
  4007. {
  4008. LOG((MSP_ERROR, "CSubStreamVideoRecv::get_Terminals - "
  4009. "can't create collection - exit 0x%08x", hr));
  4010. return hr;
  4011. }
  4012. //
  4013. // get the Collection's IDispatch interface
  4014. //
  4015. IDispatch * pDispatch;
  4016. hr = pCollection->_InternalQueryInterface(__uuidof(IDispatch),
  4017. (void **) &pDispatch );
  4018. if ( FAILED(hr) )
  4019. {
  4020. LOG((MSP_ERROR, "CSubStreamVideoRecv::get_Terminals - "
  4021. "QI for IDispatch on collection failed - exit 0x%08x", hr));
  4022. delete pCollection;
  4023. return hr;
  4024. }
  4025. //
  4026. // Init the collection using an iterator -- pointers to the beginning and
  4027. // the ending element plus one.
  4028. //
  4029. hr = pCollection->Initialize( m_Terminals.GetSize(),
  4030. m_Terminals.GetData(),
  4031. m_Terminals.GetData() + m_Terminals.GetSize() );
  4032. if (FAILED(hr))
  4033. {
  4034. LOG((MSP_ERROR, "CSubStreamVideoRecv::get_Terminals - "
  4035. "Initialize on collection failed - exit 0x%08x", hr));
  4036. pDispatch->Release();
  4037. return hr;
  4038. }
  4039. //
  4040. // put the IDispatch interface pointer into the variant
  4041. //
  4042. LOG((MSP_ERROR, "CSubStreamVideoRecv::get_Terminals - "
  4043. "placing IDispatch value %08x in variant", pDispatch));
  4044. VariantInit(pVariant);
  4045. pVariant->vt = VT_DISPATCH;
  4046. pVariant->pdispVal = pDispatch;
  4047. LOG((MSP_TRACE, "CSubStreamVideoRecv::get_Terminals - exit S_OK"));
  4048. return S_OK;
  4049. }
  4050. STDMETHODIMP CSubStreamVideoRecv::get_Stream (
  4051. OUT ITStream ** ppITStream
  4052. )
  4053. {
  4054. LOG((MSP_TRACE,
  4055. "VideoRecvSubStream.get_Stream, ppITStream %x", ppITStream));
  4056. if (IsBadWritePtr(ppITStream, sizeof (VOID *)))
  4057. {
  4058. LOG((MSP_ERROR, "Bad pointer, ppITStream:%x",ppITStream));
  4059. return E_POINTER;
  4060. }
  4061. ITStream * pITStream;
  4062. HRESULT hr = m_pStream->_InternalQueryInterface(
  4063. __uuidof(ITStream),
  4064. (void **)&pITStream
  4065. );
  4066. if (FAILED(hr))
  4067. {
  4068. LOG((MSP_ERROR, "get_Stream:QueryInterface failed: %x", hr));
  4069. return hr;
  4070. }
  4071. *ppITStream = pITStream;
  4072. return S_OK;
  4073. }
  4074. STDMETHODIMP CSubStreamVideoRecv::StartSubStream()
  4075. {
  4076. return TAPI_E_NOTSUPPORTED;
  4077. }
  4078. STDMETHODIMP CSubStreamVideoRecv::PauseSubStream()
  4079. {
  4080. return TAPI_E_NOTSUPPORTED;
  4081. }
  4082. STDMETHODIMP CSubStreamVideoRecv::StopSubStream()
  4083. {
  4084. return TAPI_E_NOTSUPPORTED;
  4085. }
  4086. BOOL CSubStreamVideoRecv::GetCurrentParticipant(
  4087. DWORD * pdwSSRC,
  4088. ITParticipant** ppITParticipant
  4089. )
  4090. {
  4091. CLock lock(m_lock);
  4092. if (m_pCurrentParticipant)
  4093. {
  4094. m_pCurrentParticipant->AddRef();
  4095. *ppITParticipant = m_pCurrentParticipant;
  4096. ((CParticipant *)m_pCurrentParticipant)->GetSSRC(
  4097. (ITStream*)m_pStream,
  4098. pdwSSRC
  4099. );
  4100. return TRUE;
  4101. }
  4102. return FALSE;
  4103. }
  4104. VOID CSubStreamVideoRecv::SetCurrentParticipant(
  4105. DWORD dwSSRC,
  4106. ITParticipant * pParticipant
  4107. )
  4108. {
  4109. CLock lock(m_lock);
  4110. if (m_pCurrentParticipant)
  4111. {
  4112. m_pCurrentParticipant->Release();
  4113. }
  4114. m_pCurrentParticipant = pParticipant;
  4115. if (m_pCurrentParticipant)
  4116. {
  4117. m_pCurrentParticipant->AddRef();
  4118. }
  4119. }
  4120. BOOL CSubStreamVideoRecv::ClearCurrentTerminal()
  4121. {
  4122. CLock lock(m_lock);
  4123. if (m_Terminals.GetSize() > 0)
  4124. {
  4125. m_Terminals[0]->Release();
  4126. m_Terminals.RemoveAt(0);
  4127. return TRUE;
  4128. }
  4129. return FALSE;
  4130. }
  4131. BOOL CSubStreamVideoRecv::SetCurrentTerminal(ITTerminal * pTerminal)
  4132. {
  4133. CLock lock(m_lock);
  4134. if (m_Terminals.GetSize() > 0)
  4135. {
  4136. _ASSERTE(FALSE);
  4137. return FALSE;
  4138. }
  4139. BOOL bFlag = m_Terminals.Add(pTerminal);
  4140. // This should never fail since the terminal array has been grown
  4141. // at the init time.
  4142. _ASSERTE(bFlag);
  4143. if (bFlag)
  4144. {
  4145. pTerminal->AddRef();
  4146. return TRUE;
  4147. }
  4148. return FALSE;
  4149. }