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

1709 lines
38 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. confstrm.cpp
  5. Abstract:
  6. This module contains implementation of CMSPStream. The object represents
  7. one stream in the filter graph.
  8. Author:
  9. Mu Han (muhan) 1-November-1997
  10. --*/
  11. #include "stdafx.h"
  12. #include "common.h"
  13. /* State Transition Table
  14. States:
  15. RO - Running whithout terminal. This is the initial state.
  16. PO - Paused without terminal
  17. SO - Stopped without terminal.
  18. RT - Runing with terminal.
  19. PT - Paused with termianl.
  20. ST - Stopped with terminal.
  21. Actions:
  22. S - Stop graph.
  23. P - Pause graph.
  24. C - Change graph.
  25. D - Disonnect terminals.
  26. F - Free extra references to filters and terminals.
  27. R - Run Graph.
  28. NIU - Not in use.
  29. Note: the same graph operation can be called multiple times, the graph
  30. just returns S_OK if it is already in desired state.
  31. NOTE: if the stream is not configured, the transition will happen without
  32. really doing anything to the graph.
  33. CONFIG will only be called for NC streams.
  34. CONFIG Select Unselect Run Pause Stop ShutDown
  35. RO OK C/R FAIL OK OK OK F
  36. RO RT RO RO PO SO -
  37. PO OK C/P FAIL OK OK OK F
  38. PO PT PO RO PO SO -
  39. SO OK C FAIL OK OK OK F
  40. SO ST SO RO PO SO -
  41. RT C/R S/C/R S/C/(R) R P S S/D/F
  42. RT RT RT,RO RT PT ST -
  43. PT C/P S/C/P S/C/(P) R P S S/D/F
  44. PT PT PT,PO RT PT ST -
  45. ST C C C R P S D/F
  46. ST ST ST,SO RT PT ST -
  47. */
  48. CIPConfMSPStream::CIPConfMSPStream()
  49. : CMSPStream(),
  50. m_szName(L""),
  51. m_pClsidPHFilter(NULL),
  52. m_pClsidCodecFilter(NULL),
  53. m_pRPHInputMinorType(NULL),
  54. m_fIsConfigured(FALSE),
  55. m_pEdgeFilter(NULL),
  56. m_pRTPFilter(NULL)
  57. {
  58. // The default state is always running.
  59. m_dwState = STRM_RUNNING;
  60. ZeroMemory(m_InfoItems, sizeof(m_InfoItems));
  61. ZeroMemory(&m_Settings, sizeof(m_Settings));
  62. }
  63. #ifdef DEBUG_REFCOUNT
  64. LONG g_lStreamObjects = 0;
  65. ULONG CIPConfMSPStream::InternalAddRef()
  66. {
  67. InterlockedIncrement(&g_lStreamObjects);
  68. ULONG lRef = CMSPStream::InternalAddRef();
  69. LOG((MSP_TRACE, "%ws Addref, ref = %d", m_szName, lRef));
  70. return lRef;
  71. }
  72. ULONG CIPConfMSPStream::InternalRelease()
  73. {
  74. InterlockedDecrement(&g_lStreamObjects);
  75. ULONG lRef = CMSPStream::InternalRelease();
  76. LOG((MSP_TRACE, "%ws Release, ref = %d", m_szName, lRef));
  77. return lRef;
  78. }
  79. #endif
  80. BOOL CIPConfMSPStream::IsConfigured()
  81. {
  82. CLock lock(m_lock);
  83. return m_fIsConfigured;
  84. }
  85. // methods called by the MSPCall object.
  86. HRESULT CIPConfMSPStream::Init(
  87. IN HANDLE hAddress,
  88. IN CMSPCallBase * pMSPCall,
  89. IN IMediaEvent * pGraph,
  90. IN DWORD dwMediaType,
  91. IN TERMINAL_DIRECTION Direction
  92. )
  93. /*++
  94. Routine Description:
  95. Initialize the stream object.
  96. Arguments:
  97. hAddress - a handle to the address, used in identify terminals.
  98. pMSPCall - the call object that owns the stream.
  99. pIGraphBuilder - the filter graph object.
  100. dwMediaType - the mediatype of this stream.
  101. Direction - the direction of this stream.
  102. Return Value:
  103. S_OK,
  104. E_OUTOFMEMORY
  105. --*/
  106. {
  107. LOG((MSP_TRACE, "CIPConfMSPStream::Init - enter"));
  108. // initialize the participant array so that the array is not NULL.
  109. if (!m_Participants.Grow())
  110. {
  111. LOG((MSP_ERROR, "out of mem for participant list"));
  112. return E_OUTOFMEMORY;
  113. }
  114. return CMSPStream::Init(
  115. hAddress, pMSPCall, pGraph, dwMediaType, Direction
  116. );
  117. }
  118. HRESULT CIPConfMSPStream::SetLocalParticipantInfo(
  119. IN PARTICIPANT_TYPED_INFO InfoType,
  120. IN char * pInfo,
  121. IN DWORD dwLen
  122. )
  123. /*++
  124. Routine Description:
  125. Get the name of this stream.
  126. Arguments:
  127. InfoType - the type of the information item.
  128. pInfo - the string containing the info.
  129. dwLen - the length of the string(including EOS).
  130. Return Value:
  131. HRESULT.
  132. */
  133. {
  134. CLock lock(m_lock);
  135. //
  136. // Save the information localy first.
  137. //
  138. int index = (int)InfoType;
  139. if (m_InfoItems[index] != NULL)
  140. {
  141. free(m_InfoItems[index]);
  142. }
  143. m_InfoItems[index] = (char *)malloc(dwLen);
  144. if (m_InfoItems[index] == NULL)
  145. {
  146. return E_OUTOFMEMORY;
  147. }
  148. lstrcpynA(m_InfoItems[index], pInfo, dwLen);
  149. if (!m_pRTPFilter)
  150. {
  151. return S_OK;
  152. }
  153. //
  154. // if the RTP filter has been created, apply the change to the fitler.
  155. //
  156. IRTCPStream *pIRTCPStream;
  157. HRESULT hr = m_pRTPFilter->QueryInterface(
  158. IID_IRTCPStream,
  159. (void **)&pIRTCPStream
  160. );
  161. if (FAILED(hr))
  162. {
  163. LOG((MSP_ERROR, "%ls can't get IRTCPStream interface %d", m_szName, hr));
  164. return hr;
  165. }
  166. hr = pIRTCPStream->SetLocalSDESItem(
  167. RTCP_SDES_CNAME + index,
  168. (BYTE*)pInfo,
  169. dwLen
  170. );
  171. if (FAILED(hr))
  172. {
  173. LOG((MSP_ERROR, "%ls can't set item:%s", pInfo));
  174. }
  175. pIRTCPStream->Release();
  176. return hr;
  177. }
  178. STDMETHODIMP CIPConfMSPStream::get_Name(
  179. OUT BSTR * ppName
  180. )
  181. /*++
  182. Routine Description:
  183. Get the name of this stream.
  184. Arguments:
  185. ppName - the mem address to store a BSTR.
  186. Return Value:
  187. HRESULT.
  188. */
  189. {
  190. LOG((MSP_TRACE, "CIPconfMSPStream::get_Name - enter"));
  191. if (IsBadWritePtr(ppName, sizeof(BSTR)))
  192. {
  193. LOG((MSP_ERROR, "CMSPStream::get_Name - exit E_POINTER"));
  194. return E_POINTER;
  195. }
  196. DWORD dwID;
  197. if (m_dwMediaType == TAPIMEDIATYPE_AUDIO)
  198. {
  199. if (m_Direction == TD_CAPTURE)
  200. {
  201. dwID = IDS_AUDIO_CAPTURE_STREAM;
  202. }
  203. else
  204. {
  205. dwID = IDS_AUDIO_RENDER_STREAM;
  206. }
  207. }
  208. else
  209. {
  210. if (m_Direction == TD_CAPTURE)
  211. {
  212. dwID = IDS_VIDEO_CAPTURE_STREAM;
  213. }
  214. else
  215. {
  216. dwID = IDS_VIDEO_RENDER_STREAM;
  217. }
  218. }
  219. const int BUFSIZE = 1024;
  220. WCHAR wszName[BUFSIZE];
  221. if (LoadStringW(
  222. _Module.GetModuleInstance(),
  223. dwID,
  224. wszName,
  225. BUFSIZE - 1 ) == 0)
  226. {
  227. *ppName = NULL;
  228. LOG((MSP_ERROR, "CMSPStream::get_Name - "
  229. "LoadString failed - returning E_UNEXPECTED"));
  230. return E_UNEXPECTED;
  231. }
  232. //
  233. // Convert to a BSTR and return the BSTR.
  234. //
  235. BSTR pName = SysAllocString(wszName);
  236. if (pName == NULL)
  237. {
  238. LOG((MSP_ERROR, "CMSPStream::get_Name - exit out of mem"));
  239. return E_OUTOFMEMORY;
  240. }
  241. *ppName = pName;
  242. return S_OK;
  243. }
  244. HRESULT CIPConfMSPStream::SendStreamEvent(
  245. IN MSP_CALL_EVENT Event,
  246. IN MSP_CALL_EVENT_CAUSE Cause,
  247. IN HRESULT hrError = 0,
  248. IN ITTerminal * pTerminal = NULL
  249. )
  250. /*++
  251. Routine Description:
  252. Send a event to the app to notify that this stream is not used.
  253. */
  254. {
  255. CLock lock(m_lock);
  256. if (m_pMSPCall == NULL)
  257. {
  258. LOG((MSP_WARN, "The call has shut down the stream."));
  259. return S_OK;
  260. }
  261. ITStream * pITStream;
  262. HRESULT hr = this->_InternalQueryInterface(
  263. IID_ITStream,
  264. (void **)&pITStream
  265. );
  266. if (FAILED(hr))
  267. {
  268. LOG((MSP_ERROR, "SendStreamEvent:QueryInterface failed: %x", hr));
  269. return hr;
  270. }
  271. MSPEVENTITEM* pEventItem = AllocateEventItem();
  272. if (pEventItem == NULL)
  273. {
  274. LOG((MSP_ERROR, "No memory for the TSPMSP data, size: %d", sizeof(MSPEVENTITEM)));
  275. pITStream->Release();
  276. return E_OUTOFMEMORY;
  277. }
  278. // Fill in the necessary fields for the event structure.
  279. pEventItem->MSPEventInfo.dwSize = sizeof(MSP_EVENT_INFO);
  280. pEventItem->MSPEventInfo.Event = ME_CALL_EVENT;
  281. pEventItem->MSPEventInfo.MSP_CALL_EVENT_INFO.Type = Event;
  282. pEventItem->MSPEventInfo.MSP_CALL_EVENT_INFO.Cause = Cause;
  283. // pITStream has a refcount becaust it was from QI.
  284. pEventItem->MSPEventInfo.MSP_CALL_EVENT_INFO.pStream = pITStream;
  285. // the terminal needs to be addrefed.
  286. if (pTerminal) pTerminal->AddRef();
  287. pEventItem->MSPEventInfo.MSP_CALL_EVENT_INFO.pTerminal = pTerminal;
  288. pEventItem->MSPEventInfo.MSP_CALL_EVENT_INFO.hrError= hrError;
  289. hr = m_pMSPCall->HandleStreamEvent(pEventItem);
  290. if (FAILED(hr))
  291. {
  292. LOG((MSP_ERROR, "Post event failed %x", hr));
  293. pITStream->Release();
  294. FreeEventItem(pEventItem);
  295. return hr;
  296. }
  297. return S_OK;
  298. }
  299. HRESULT CIPConfMSPStream::CleanUpFilters()
  300. /*++
  301. Routine Description:
  302. remove all the filters in the graph.
  303. Arguments:
  304. Return Value:
  305. HRESULT.
  306. --*/
  307. {
  308. LOG((MSP_TRACE, "CleanUpFilters for %ws %p", m_szName, this));
  309. if (m_pEdgeFilter)
  310. {
  311. m_pEdgeFilter->Release();
  312. m_pEdgeFilter = NULL;
  313. }
  314. if (m_pRTPFilter)
  315. {
  316. m_pRTPFilter->Release();
  317. m_pRTPFilter = NULL;
  318. }
  319. for(;;)
  320. {
  321. // Because the enumerator is invalid after removing a filter from
  322. // the graph, we have to try to get all the filters in one shot.
  323. // If there are still more, we loop again.
  324. // Enumerate the filters in the graph.
  325. CComPtr<IEnumFilters>pEnum;
  326. HRESULT hr = m_pIGraphBuilder->EnumFilters(&pEnum);
  327. if (FAILED(hr))
  328. {
  329. LOG((MSP_ERROR, "cleanup filters, enumfilters failed: %x", hr));
  330. return hr;
  331. }
  332. const DWORD MAXFILTERS = 40;
  333. IBaseFilter * Filters[MAXFILTERS];
  334. DWORD dwFetched;
  335. hr = pEnum->Next(MAXFILTERS, Filters, &dwFetched);
  336. if (FAILED(hr))
  337. {
  338. LOG((MSP_ERROR, "get next filter failed: %x", hr));
  339. return hr;
  340. }
  341. for (DWORD i = 0; i< dwFetched; i ++)
  342. {
  343. m_pIGraphBuilder->RemoveFilter(Filters[i]);
  344. Filters[i]->Release();
  345. }
  346. if (hr != S_OK)
  347. {
  348. break;
  349. }
  350. }
  351. return S_OK;
  352. }
  353. HRESULT CIPConfMSPStream::InternalConfigure()
  354. /*++
  355. Routine Description:
  356. This method is called by the derived streams to handle the state
  357. transition needed for configure. It should be called after the
  358. stream finished configuring itself.
  359. Arguments:
  360. Return Value:
  361. HRESULT.
  362. --*/
  363. {
  364. _ASSERTE(m_fIsConfigured == TRUE);
  365. // if there is no terminal selected, just return.
  366. if (m_Terminals.GetSize() == 0)
  367. {
  368. LOG((MSP_INFO, "stream %ws %p needs terminal", m_szName, this));
  369. return S_OK;
  370. }
  371. // set up the filters and the terminals.
  372. HRESULT hr = SetUpFilters();
  373. if (FAILED(hr))
  374. {
  375. SendStreamEvent(CALL_STREAM_FAIL, CALL_CAUSE_CONNECT_FAIL, hr);
  376. LOG((MSP_ERROR, "stream %ws %p set up filters failed, %x",
  377. m_szName, this, hr));
  378. return hr;
  379. }
  380. switch (m_dwState)
  381. {
  382. case STRM_RUNNING:
  383. // start the graph.
  384. hr = CMSPStream::StartStream();
  385. if (FAILED(hr))
  386. {
  387. // if the stream failed to start, let the app now.
  388. SendStreamEvent(CALL_STREAM_FAIL, CALL_CAUSE_UNKNOWN, hr);
  389. LOG((MSP_ERROR, "stream %ws %p failed to start, %x", m_szName, this, hr));
  390. return hr;
  391. }
  392. SendStreamEvent(CALL_STREAM_ACTIVE, CALL_CAUSE_REMOTE_REQUEST);
  393. LOG((MSP_INFO, "stream %ws %p started", m_szName, this));
  394. break;
  395. case STRM_PAUSED:
  396. // pause the graph.
  397. hr = CMSPStream::PauseStream();
  398. if (FAILED(hr))
  399. {
  400. // if the stream failed to start, let the app now.
  401. SendStreamEvent(CALL_STREAM_FAIL, CALL_CAUSE_UNKNOWN, hr);
  402. LOG((MSP_ERROR, "stream %ws %p failed to pause, %x", m_szName, this, hr));
  403. return hr;
  404. }
  405. LOG((MSP_INFO, "stream %ws %p paused", m_szName, this));
  406. break;
  407. case STRM_STOPPED:
  408. break;
  409. }
  410. LOG((MSP_INFO, "stream %ws %p configure exit S_OK", m_szName, this));
  411. return S_OK;
  412. }
  413. STDMETHODIMP CIPConfMSPStream::StartStream()
  414. /*++
  415. Routine Description:
  416. Start the stream. This is the basic state machine for all the derived
  417. streams.
  418. Arguments:
  419. Return Value:
  420. HRESULT.
  421. --*/
  422. {
  423. CLock lock(m_lock);
  424. // if there is no terminal selected
  425. if (m_Terminals.GetSize() == 0)
  426. {
  427. LOG((MSP_INFO, "stream %ws %p needs terminal", m_szName, this));
  428. // Enter Runing state. (RO)
  429. m_dwState = STRM_RUNNING;
  430. return S_OK;
  431. }
  432. if (!m_fIsConfigured)
  433. {
  434. LOG((MSP_INFO, "stream %ws %p is not configured yet", m_szName, this));
  435. // Enter Runing state. (RO, RT)
  436. m_dwState = STRM_RUNNING;
  437. return S_OK;
  438. }
  439. // Start the stream.
  440. HRESULT hr = CMSPStream::StartStream();
  441. if (FAILED(hr))
  442. {
  443. LOG((MSP_ERROR, "stream %ws %p failed to start, %x", m_szName, this, hr));
  444. return hr;
  445. }
  446. SendStreamEvent(CALL_STREAM_ACTIVE, CALL_CAUSE_LOCAL_REQUEST);
  447. LOG((MSP_INFO, "stream %ws %p started", m_szName, this));
  448. // Enter Runing state.(RT)
  449. m_dwState = STRM_RUNNING;
  450. return S_OK;
  451. }
  452. STDMETHODIMP CIPConfMSPStream::PauseStream()
  453. /*++
  454. Routine Description:
  455. Pause the stream. This is the basic state machine for all the derived
  456. streams.
  457. Arguments:
  458. Return Value:
  459. HRESULT.
  460. --*/
  461. {
  462. CLock lock(m_lock);
  463. // if there is no terminal selected
  464. if (m_Terminals.GetSize() == 0)
  465. {
  466. LOG((MSP_INFO, "stream %ws %p needs terminal", m_szName, this));
  467. // Enter paused state. (PO)
  468. m_dwState = STRM_PAUSED;
  469. return S_OK;
  470. }
  471. if (!m_fIsConfigured)
  472. {
  473. LOG((MSP_INFO, "stream %ws %p is not configured yet", m_szName, this));
  474. // Enter paused state. (PO, PT)
  475. m_dwState = STRM_PAUSED;
  476. return S_OK;
  477. }
  478. // Start the stream.
  479. HRESULT hr = CMSPStream::PauseStream();
  480. if (FAILED(hr))
  481. {
  482. LOG((MSP_ERROR, "stream %ws %p failed to pause, %x", m_szName, this, hr));
  483. return hr;
  484. }
  485. LOG((MSP_INFO, "stream %ws %p paused", m_szName, this));
  486. // Enter paused state.(PT)
  487. m_dwState = STRM_PAUSED;
  488. return S_OK;
  489. }
  490. STDMETHODIMP CIPConfMSPStream::StopStream()
  491. /*++
  492. Routine Description:
  493. Stop the stream. This is the basic state machine for all the derived
  494. streams.
  495. Arguments:
  496. Return Value:
  497. HRESULT.
  498. --*/
  499. {
  500. CLock lock(m_lock);
  501. // if there is no terminal selected
  502. if (m_Terminals.GetSize() == 0)
  503. {
  504. LOG((MSP_INFO, "stream %ws %p needs terminal", m_szName, this));
  505. // Enter stopped state. (SO)
  506. m_dwState = STRM_STOPPED;
  507. return S_OK;
  508. }
  509. if (!m_fIsConfigured)
  510. {
  511. LOG((MSP_INFO, "stream %ws %p is not configured yet", m_szName, this));
  512. // Enter stopped state. (SO, ST)
  513. m_dwState = STRM_STOPPED;
  514. return S_OK;
  515. }
  516. // Stop the graph.
  517. HRESULT hr = CMSPStream::StopStream();
  518. if (FAILED(hr))
  519. {
  520. LOG((MSP_ERROR, "stream %ws %p failed to stop, %x", m_szName, this, hr));
  521. return hr;
  522. }
  523. SendStreamEvent(CALL_STREAM_INACTIVE, CALL_CAUSE_LOCAL_REQUEST);
  524. LOG((MSP_INFO, "stream %ws %p stopped", m_szName, this));
  525. // Enter stopped state.(ST)
  526. m_dwState = STRM_STOPPED;
  527. return S_OK;
  528. }
  529. HRESULT CIPConfMSPStream::CheckTerminalTypeAndDirection(
  530. IN ITTerminal * pTerminal
  531. )
  532. /*++
  533. Routine Description:
  534. The implementation in this class checks to see if the terminal
  535. is th right type and direction and it only allows on terminal per
  536. stream.
  537. Arguments:
  538. pTerminal - the terminal object.
  539. */
  540. {
  541. // check the media type of this terminal.
  542. long lMediaType;
  543. HRESULT hr = pTerminal->get_MediaType(&lMediaType);
  544. if (FAILED(hr))
  545. {
  546. LOG((MSP_ERROR, "can't get terminal media type. %x", hr));
  547. return TAPI_E_INVALIDTERMINAL;
  548. }
  549. if ((DWORD)lMediaType != m_dwMediaType)
  550. {
  551. return TAPI_E_INVALIDTERMINAL;
  552. }
  553. // check the direction of this terminal.
  554. TERMINAL_DIRECTION Direction;
  555. hr = pTerminal->get_Direction(&Direction);
  556. if (FAILED(hr))
  557. {
  558. LOG((MSP_ERROR, "can't get terminal direction. %x", hr));
  559. return TAPI_E_INVALIDTERMINAL;
  560. }
  561. if (Direction != m_Direction)
  562. {
  563. return TAPI_E_INVALIDTERMINAL;
  564. }
  565. // By default, only one terminal is supported per stream.
  566. if (m_Terminals.GetSize() > 0)
  567. {
  568. return TAPI_E_MAXTERMINALS;
  569. }
  570. return S_OK;
  571. }
  572. HRESULT CIPConfMSPStream::SelectTerminal(
  573. IN ITTerminal * pTerminal
  574. )
  575. /*++
  576. Routine Description:
  577. Select a terminal on the stream. The stream will start itself if it
  578. was in running state. See the state transition table at the beginning
  579. of this file.
  580. Arguments:
  581. pTerminal - the terminal object.
  582. Return Value:
  583. S_OK
  584. E_POINTER
  585. E_OUTOFMEMORY
  586. TAPI_E_MAXTERMINALS
  587. TAPI_E_INVALIDTERMINAL
  588. --*/
  589. {
  590. LOG((MSP_TRACE, "CMSPStream::SelectTerminal, %p", pTerminal));
  591. //
  592. // Check parameter.
  593. //
  594. if ( IsBadReadPtr(pTerminal, sizeof(ITTerminal) ) )
  595. {
  596. LOG((MSP_ERROR, "CIPconfMSPStream.SelectTerminal - exit E_POINTER"));
  597. return E_POINTER;
  598. }
  599. CLock lock(m_lock);
  600. // validate the terminal.
  601. HRESULT hr = CheckTerminalTypeAndDirection(pTerminal);
  602. if (FAILED(hr))
  603. {
  604. LOG((MSP_ERROR, "wrong terminal. %x", hr));
  605. return hr;
  606. }
  607. // put the terminal into our list.
  608. hr = CMSPStream::SelectTerminal(pTerminal);
  609. if (FAILED(hr))
  610. {
  611. LOG((MSP_ERROR, "SelectTerminal on CMSPStream failed, %x", hr));
  612. return hr;
  613. }
  614. // At this point, the select terminal opration succeeded. All the
  615. // failure cases are handled by sending events after this.
  616. if (!m_fIsConfigured)
  617. {
  618. LOG((MSP_INFO, "stream %ws %p is not configured yet", m_szName, this));
  619. return S_OK;
  620. }
  621. // stop the graph before making changes.
  622. hr = CMSPStream::StopStream();
  623. if (FAILED(hr))
  624. {
  625. LOG((MSP_ERROR, "stream %ws %p failed to stop, %x", m_szName, this, hr));
  626. SendStreamEvent(CALL_STREAM_FAIL, CALL_CAUSE_UNKNOWN, hr);
  627. return S_OK;
  628. }
  629. // connect the new terminal into the graph.
  630. // this method will send events if the terminal failed.
  631. hr = ConnectTerminal(pTerminal);
  632. if (FAILED(hr))
  633. {
  634. LOG((MSP_ERROR, "stream %ws %p connect to terminal failed, %x",
  635. m_szName, this, hr));
  636. SendStreamEvent(CALL_STREAM_FAIL, CALL_CAUSE_CONNECT_FAIL, hr);
  637. return S_OK;
  638. }
  639. // after connecting the termanal, go back to the original state.
  640. switch (m_dwState)
  641. {
  642. case STRM_RUNNING:
  643. // start the stream.
  644. hr = CMSPStream::StartStream();
  645. if (FAILED(hr))
  646. {
  647. LOG((MSP_ERROR, "stream %ws %p failed, %x", m_szName, this, hr));
  648. SendStreamEvent(CALL_STREAM_FAIL, CALL_CAUSE_UNKNOWN, hr);
  649. break;
  650. }
  651. SendStreamEvent(CALL_STREAM_ACTIVE, CALL_CAUSE_LOCAL_REQUEST);
  652. break;
  653. case STRM_PAUSED:
  654. // pause the stream.
  655. hr = CMSPStream::PauseStream();
  656. if (FAILED(hr))
  657. {
  658. LOG((MSP_ERROR, "stream %ws %p failed, %x", m_szName, this, hr));
  659. SendStreamEvent(CALL_STREAM_FAIL, CALL_CAUSE_UNKNOWN, hr);
  660. }
  661. break;
  662. }
  663. return S_OK;
  664. }
  665. STDMETHODIMP CIPConfMSPStream::UnselectTerminal(
  666. IN ITTerminal * pTerminal
  667. )
  668. /*++
  669. Routine Description:
  670. Unselect a terminal from the stream. It handles changing the graph and
  671. going back to the original state.
  672. Arguments:
  673. Return Value:
  674. S_OK
  675. E_POINTER
  676. E_OUTOFMEMORY
  677. TAPI_E_MAXTERMINALS
  678. TAPI_E_INVALIDTERMINAL
  679. --*/
  680. {
  681. LOG((MSP_TRACE,
  682. "CIPConfMSPStream::UnselectTerminal, pTerminal %p", pTerminal));
  683. CLock lock(m_lock);
  684. int index;
  685. if ((index = m_Terminals.Find(pTerminal)) < 0)
  686. {
  687. LOG((MSP_ERROR, "UnselectTerminal - exit TAPI_E_INVALIDTERMINAL"));
  688. return TAPI_E_INVALIDTERMINAL;
  689. }
  690. // if the stream is not configured, just remove it and return.
  691. if (!m_fIsConfigured)
  692. {
  693. if (!m_Terminals.RemoveAt(index))
  694. {
  695. LOG((MSP_ERROR, "CMSPStream::UnselectTerminal - "
  696. "exit E_UNEXPECTED"));
  697. return E_UNEXPECTED;
  698. }
  699. // release the refcount that was in our list.
  700. pTerminal->Release();
  701. LOG((MSP_INFO, "stream %ws %p is not configured yet", m_szName, this));
  702. return S_OK;
  703. }
  704. // stop the graph before making changes.
  705. HRESULT hr = CMSPStream::StopStream();
  706. if (FAILED(hr))
  707. {
  708. LOG((MSP_ERROR, "stream %ws %p failed to stop, %x", m_szName, this, hr));
  709. return hr;
  710. }
  711. SendStreamEvent(CALL_STREAM_INACTIVE, CALL_CAUSE_LOCAL_REQUEST);
  712. // disconnect the terminal from the graph.
  713. // this method will send events if the terminal failed.
  714. hr = DisconnectTerminal(pTerminal);
  715. if (FAILED(hr))
  716. {
  717. LOG((MSP_ERROR, "stream %ws %p disconnectTerminal failed, %x",
  718. m_szName, this, hr));
  719. return hr;
  720. }
  721. if (!m_Terminals.RemoveAt(index))
  722. {
  723. LOG((MSP_ERROR, "CMSPStream::UnselectTerminal - "
  724. "exit E_UNEXPECTED"));
  725. return E_UNEXPECTED;
  726. }
  727. // release the refcount that was in our list.
  728. pTerminal->Release();
  729. // if there is no terminal selected, just return and wait for terminals.
  730. if (m_Terminals.GetSize() == 0)
  731. {
  732. LOG((MSP_INFO, "stream %ws %p needs terminal", m_szName, this));
  733. return S_OK;
  734. }
  735. // At this point, the Unselect terminal opration succeeded. All the
  736. // failure cases are handled by sending events after this.
  737. // after disconnecting the termanal, go back to the original state.
  738. switch (m_dwState)
  739. {
  740. case STRM_RUNNING:
  741. // start the stream.
  742. hr = CMSPStream::StartStream();
  743. if (FAILED(hr))
  744. {
  745. LOG((MSP_ERROR, "stream %ws %p failed to start, %x", m_szName, this, hr));
  746. SendStreamEvent(CALL_STREAM_FAIL, CALL_CAUSE_UNKNOWN, hr);
  747. break;
  748. }
  749. SendStreamEvent(CALL_STREAM_ACTIVE, CALL_CAUSE_LOCAL_REQUEST);
  750. break;
  751. case STRM_PAUSED:
  752. // pause the stream.
  753. hr = CMSPStream::PauseStream();
  754. if (FAILED(hr))
  755. {
  756. LOG((MSP_ERROR, "stream %ws %p failed to pause, %x", m_szName, this, hr));
  757. SendStreamEvent(CALL_STREAM_FAIL, CALL_CAUSE_UNKNOWN, hr);
  758. }
  759. break;
  760. }
  761. return S_OK;
  762. }
  763. HRESULT CIPConfMSPStream::ShutDown()
  764. /*++
  765. Routine Description:
  766. Shut down the stream. It release the filters and terminals.
  767. Arguments:
  768. Return Value:
  769. S_OK
  770. --*/
  771. {
  772. LOG((MSP_TRACE, "CIPConfMSPStream::Shutdown %ws - enter", m_szName));
  773. CLock lock(m_lock);
  774. for (int j = 0; j < RTCP_SDES_LAST - 1; j ++)
  775. {
  776. if (m_InfoItems[j])
  777. {
  778. free(m_InfoItems[j]);
  779. m_InfoItems[j] = NULL;
  780. }
  781. }
  782. if (m_pMSPCall)
  783. {
  784. m_pMSPCall->MSPCallRelease();
  785. m_pMSPCall = NULL;
  786. }
  787. // free the extra filter reference.
  788. if (m_pEdgeFilter)
  789. {
  790. m_pEdgeFilter->Release();
  791. m_pEdgeFilter = NULL;
  792. }
  793. if (m_pRTPFilter)
  794. {
  795. m_pRTPFilter->Release();
  796. m_pRTPFilter = NULL;
  797. }
  798. // If the stream is not configured, just free the terminals.
  799. if (!m_fIsConfigured)
  800. {
  801. LOG((MSP_INFO, "stream %ws %p is not configured yet", m_szName, this));
  802. for ( int i = 0; i < m_Terminals.GetSize(); i ++ )
  803. {
  804. m_Terminals[i]->Release();
  805. }
  806. m_Terminals.RemoveAll();
  807. return S_OK;
  808. }
  809. // if there are terminals and configured, we need to disconnect
  810. // the terminals.
  811. if (m_Terminals.GetSize() > 0)
  812. {
  813. // Stop the graph before disconnecting the terminals.
  814. HRESULT hr = CMSPStream::StopStream();
  815. if (FAILED(hr))
  816. {
  817. LOG((MSP_ERROR,
  818. "stream %ws %p failed to stop, %x", m_szName, this, hr));
  819. return hr;
  820. }
  821. for ( int i = 0; i < m_Terminals.GetSize(); i ++ )
  822. {
  823. hr = DisconnectTerminal(m_Terminals[i]);
  824. LOG((MSP_TRACE, "Disconnect terminal returned %x", hr));
  825. m_Terminals[i]->Release();
  826. }
  827. m_Terminals.RemoveAll();
  828. }
  829. for (int i = 0; i < m_Participants.GetSize(); i ++)
  830. {
  831. m_Participants[i]->Release();
  832. }
  833. m_Participants.RemoveAll();
  834. LOG((MSP_TRACE, "CIPConfMSPStream::Shutdown - exit S_OK"));
  835. return S_OK;
  836. }
  837. HRESULT CIPConfMSPStream::DisconnectTerminal(
  838. IN ITTerminal * pITTerminal
  839. )
  840. /*++
  841. Routine Description:
  842. Disconnect a terminal. It will remove its filters from the graph and
  843. also release its references to the graph.
  844. Arguments:
  845. pITTerminal - the terminal.
  846. Return Value:
  847. HRESULT.
  848. --*/
  849. {
  850. CComQIPtr<ITTerminalControl, &IID_ITTerminalControl>
  851. pTerminalControl(pITTerminal);
  852. if (pTerminalControl == NULL)
  853. {
  854. LOG((MSP_ERROR, "can't get Terminal Control interface"));
  855. return E_NOINTERFACE;
  856. }
  857. HRESULT hr = pTerminalControl->DisconnectTerminal(m_pIGraphBuilder, 0);
  858. LOG((MSP_TRACE, "terminal %p is disonnected. hr:%x", pITTerminal, hr));
  859. return hr;
  860. }
  861. HRESULT CIPConfMSPStream::ProcessNewSender(
  862. IN DWORD dwSSRC,
  863. IN ITParticipant *pITParticipant
  864. )
  865. {
  866. return S_OK;
  867. }
  868. HRESULT CIPConfMSPStream::ProcessNewParticipant(
  869. IN int index,
  870. IN DWORD dwSSRC,
  871. IN DWORD dwSendRecv,
  872. IN char * szCName,
  873. OUT ITParticipant ** ppITParticipant
  874. )
  875. {
  876. if (!m_Participants.HasSpace())
  877. {
  878. if (!m_Participants.Grow())
  879. {
  880. LOG((MSP_ERROR, "Out of mem for participant list"));
  881. return E_OUTOFMEMORY;
  882. }
  883. }
  884. // create a new participant if it is not in the list.
  885. HRESULT hr = ((CIPConfMSPCall *)m_pMSPCall)->NewParticipant(
  886. (ITStream *)this,
  887. dwSSRC,
  888. dwSendRecv,
  889. m_dwMediaType,
  890. szCName,
  891. ppITParticipant
  892. );
  893. if (FAILED(hr))
  894. {
  895. LOG((MSP_ERROR, "new participant returns %x", hr));
  896. return hr;
  897. }
  898. // insert the new participant at the index where the search
  899. // stopped. The list is ordered by CName. We know the list has
  900. // space, this function will not fail.
  901. m_Participants.InsertAt(index, *ppITParticipant);
  902. LOG((MSP_INFO, "%ws new participant %s", m_szName, szCName));
  903. (*ppITParticipant)->AddRef();
  904. return S_OK;
  905. }
  906. HRESULT CIPConfMSPStream::ProcessRTCPReport(
  907. IN DWORD dwSSRC,
  908. IN DWORD dwSendRecv
  909. )
  910. /*++
  911. Routine Description:
  912. Process a sender report, create a participant if necessary. If a new
  913. participant is created, a new participant event will be fired. If the
  914. participant already exists, the new report is compared with the current
  915. information, if anything change, a info change event will be fired.
  916. If there is a pending map event(new source without CName), compare its
  917. SSRC with lParam1. If it is the same, fire the map event as well.
  918. Arguments:
  919. dwSSRC - the SSRC of this participant.
  920. dwSendRecv - a sender report or a receiver report.
  921. Return Value:
  922. HRESULT.
  923. --*/
  924. {
  925. LOG((MSP_TRACE, "ProcessRTCPReport, SSRC: %x", dwSSRC));
  926. CLock Lock(m_lock);
  927. if (m_pRTPFilter == NULL)
  928. {
  929. LOG((MSP_ERROR, "ProcessRTCPReport RTP filter is NULL"));
  930. return E_UNEXPECTED;
  931. }
  932. // prepare the buffer to get the SDES_ITEMS.
  933. // We need all the items from CNAME to PRIV, see rtp.h.
  934. SDES_DATA SDESBuffer[RTCP_SDES_LAST - 1];
  935. for (int i = 0; i < RTCP_SDES_LAST - 1; i ++)
  936. {
  937. SDESBuffer[i].dwSdesType = RTCP_SDES_CNAME + i;
  938. SDESBuffer[i].dwSdesLength = 0;
  939. }
  940. // Ask the stream to get the SDES_ITEMS.
  941. HRESULT hr = m_pRTPFilter->GetParticipantSDESAll(
  942. dwSSRC, SDESBuffer, RTCP_SDES_LAST - 1
  943. );
  944. if (FAILED(hr))
  945. {
  946. LOG((MSP_ERROR, "can't get sdes data for ssrc:%x. %x", dwSSRC, hr));
  947. return hr;
  948. }
  949. // Check CName,
  950. if (SDESBuffer[0].dwSdesLength == 0)
  951. {
  952. LOG((MSP_WARN, "CName doesn't exist for SSRC %x", dwSSRC));
  953. return hr;
  954. }
  955. ITParticipant * pITParticipant;
  956. BOOL fChanged = FALSE;
  957. if (m_pMSPCall == NULL)
  958. {
  959. LOG((MSP_WARN, "The call has shut down the stream."));
  960. return S_OK;
  961. }
  962. CParticipant * pParticipant;
  963. // find out if the participant is in our list.
  964. int index;
  965. if (m_Participants.FindByCName(SDESBuffer[0].sdesBfr, &index))
  966. {
  967. pITParticipant = m_Participants[index];
  968. // addref to keep it after unlock;
  969. pITParticipant->AddRef();
  970. // check to see if this participant just turned into a sender.
  971. pParticipant = (CParticipant *)pITParticipant;
  972. if ((!(pParticipant->GetSendRecvStatus((ITStream *)this) & PART_SEND))
  973. && (dwSendRecv & PART_SEND))
  974. {
  975. ProcessNewSender(dwSSRC, pITParticipant);
  976. }
  977. }
  978. else
  979. {
  980. hr = ProcessNewParticipant(
  981. index,
  982. dwSSRC,
  983. dwSendRecv,
  984. SDESBuffer[0].sdesBfr,
  985. &pITParticipant
  986. );
  987. if (FAILED(hr))
  988. {
  989. LOG((MSP_ERROR, "new participant returns %x", hr));
  990. return hr;
  991. }
  992. pParticipant = (CParticipant *)pITParticipant;
  993. // Senders needs special attention.
  994. if (dwSendRecv & PART_SEND)
  995. {
  996. ProcessNewSender(dwSSRC, pITParticipant);
  997. }
  998. // There might be things the stream needs to do with the new participant
  999. NewParticipantPostProcess(dwSSRC, pITParticipant);
  1000. // a new stream is added into the participant's list
  1001. // fire a info changed event.
  1002. fChanged = TRUE;
  1003. }
  1004. // update the information of the participant.
  1005. // just in case the SSRC changed.
  1006. pParticipant->UpdateSSRC(
  1007. (ITStream *)this,
  1008. dwSSRC,
  1009. dwSendRecv
  1010. );
  1011. // start from the SDES_NAME, skip CNAME.
  1012. for (i = 1; i < RTCP_SDES_LAST - 1; i ++)
  1013. {
  1014. if (SDESBuffer[i].dwSdesLength > 0)
  1015. {
  1016. fChanged = fChanged || pParticipant->UpdateInfo(
  1017. RTCP_SDES_CNAME + i,
  1018. SDESBuffer[i].dwSdesLength,
  1019. (char *)SDESBuffer[i].sdesBfr
  1020. );
  1021. }
  1022. }
  1023. if(fChanged)
  1024. {
  1025. ((CIPConfMSPCall *)m_pMSPCall)->
  1026. SendParticipantEvent(PE_INFO_CHANGE, pITParticipant);
  1027. }
  1028. pITParticipant->Release();
  1029. return S_OK;
  1030. }
  1031. HRESULT CIPConfMSPStream::ProcessParticipantLeave(
  1032. IN DWORD dwSSRC
  1033. )
  1034. /*++
  1035. Routine Description:
  1036. When participant left the session, remove the stream from the participant
  1037. object's list of streams. If all streams are removed, remove the
  1038. participant from the call object's list too.
  1039. Arguments:
  1040. dwSSRC - the SSRC of the participant left.
  1041. Return Value:
  1042. HRESULT.
  1043. --*/
  1044. {
  1045. LOG((MSP_TRACE, "ProcessParticipantLeave, SSRC: %x", dwSSRC));
  1046. m_lock.Lock();
  1047. CParticipant *pParticipant;
  1048. BOOL fLast = FALSE;
  1049. HRESULT hr = E_FAIL;
  1050. // first try to find the SSRC in our participant list.
  1051. for (int i = 0; i < m_Participants.GetSize(); i ++)
  1052. {
  1053. pParticipant = (CParticipant *)m_Participants[i];
  1054. hr = pParticipant->RemoveStream(
  1055. (ITStream *)this,
  1056. dwSSRC,
  1057. &fLast
  1058. );
  1059. if (SUCCEEDED(hr))
  1060. {
  1061. break;
  1062. }
  1063. }
  1064. // if the participant is not found
  1065. if (FAILED(hr))
  1066. {
  1067. LOG((MSP_ERROR, "can't find the SSRC", dwSSRC));
  1068. m_lock.Unlock();
  1069. return hr;
  1070. }
  1071. ITParticipant *pITParticipant = m_Participants[i];
  1072. m_Participants.RemoveAt(i);
  1073. // if this stream is the last stream that the participant is on,
  1074. // tell the call object to remove it from its list.
  1075. if (fLast)
  1076. {
  1077. ((CIPConfMSPCall *)m_pMSPCall)->ParticipantLeft(pITParticipant);
  1078. }
  1079. m_lock.Unlock();
  1080. pITParticipant->Release();
  1081. return S_OK;
  1082. }
  1083. HRESULT CIPConfMSPStream::ProcessParticipantTimeOutOrRecovered(
  1084. IN BOOL fTimeOutOrRecovered,
  1085. IN DWORD dwSSRC
  1086. )
  1087. /*++
  1088. Routine Description:
  1089. When RTP detects a timeout for a certain participant, the msp needs to
  1090. notify the app about it.
  1091. Arguments:
  1092. dwSSRC - the SSRC of the participant that times out.
  1093. Return Value:
  1094. HRESULT.
  1095. --*/
  1096. {
  1097. LOG((MSP_TRACE, "ProcessParticipantTimeOutOrRecovered, SSRC: %x", dwSSRC));
  1098. ITParticipant *pITParticipant = NULL;
  1099. CLock Lock(m_lock);
  1100. // find the SSRC in our participant list.
  1101. for (int i = 0; i < m_Participants.GetSize(); i ++)
  1102. {
  1103. if (((CParticipant *)m_Participants[i])->
  1104. HasSSRC((ITStream *)this, dwSSRC))
  1105. {
  1106. pITParticipant = m_Participants[i];
  1107. pITParticipant->AddRef();
  1108. }
  1109. }
  1110. // if the participant is not found
  1111. if (pITParticipant == NULL)
  1112. {
  1113. LOG((MSP_ERROR, "can't find the SSRC", dwSSRC));
  1114. return S_OK;
  1115. }
  1116. ((CIPConfMSPCall *)m_pMSPCall)->
  1117. SendParticipantEvent(
  1118. fTimeOutOrRecovered ? PE_PARTICIPANT_TIMEOUT : PE_PARTICIPANT_RECOVERED,
  1119. pITParticipant
  1120. );
  1121. pITParticipant->Release();
  1122. return S_OK;
  1123. }
  1124. HRESULT CIPConfMSPStream::NewParticipantPostProcess(
  1125. IN DWORD dwSSRC,
  1126. IN ITParticipant *pITParticipant
  1127. )
  1128. {
  1129. // This function does nothing. The derived class will do the work.
  1130. return S_OK;
  1131. }
  1132. HRESULT CIPConfMSPStream::ProcessQOSEvent(
  1133. IN long lEventCode
  1134. )
  1135. {
  1136. CLock lock(m_lock);
  1137. if (m_pMSPCall == NULL)
  1138. {
  1139. LOG((MSP_WARN, "The call has shut down the stream."));
  1140. return S_OK;
  1141. }
  1142. switch (lEventCode)
  1143. {
  1144. case DXMRTP_QOSEVENT_NOQOS:
  1145. ((CIPConfMSPCall*)m_pMSPCall)->SendTSPMessage(
  1146. CALL_QOS_EVENT,
  1147. QE_NOQOS,
  1148. m_dwMediaType
  1149. );
  1150. break;
  1151. case DXMRTP_QOSEVENT_RECEIVERS:
  1152. case DXMRTP_QOSEVENT_SENDERS:
  1153. case DXMRTP_QOSEVENT_NO_SENDERS:
  1154. case DXMRTP_QOSEVENT_NO_RECEIVERS:
  1155. break;
  1156. case DXMRTP_QOSEVENT_REQUEST_CONFIRMED:
  1157. break;
  1158. case DXMRTP_QOSEVENT_ADMISSION_FAILURE:
  1159. ((CIPConfMSPCall*)m_pMSPCall)->SendTSPMessage(
  1160. CALL_QOS_EVENT,
  1161. QE_ADMISSIONFAILURE,
  1162. m_dwMediaType
  1163. );
  1164. break;
  1165. case DXMRTP_QOSEVENT_POLICY_FAILURE:
  1166. ((CIPConfMSPCall*)m_pMSPCall)->SendTSPMessage(
  1167. CALL_QOS_EVENT,
  1168. QE_POLICYFAILURE,
  1169. m_dwMediaType
  1170. );
  1171. break;
  1172. case DXMRTP_QOSEVENT_BAD_STYLE:
  1173. case DXMRTP_QOSEVENT_BAD_OBJECT:
  1174. case DXMRTP_QOSEVENT_TRAFFIC_CTRL_ERROR:
  1175. case DXMRTP_QOSEVENT_GENERIC_ERROR:
  1176. ((CIPConfMSPCall*)m_pMSPCall)->SendTSPMessage(
  1177. CALL_QOS_EVENT,
  1178. QE_GENERICERROR,
  1179. m_dwMediaType
  1180. );
  1181. break;
  1182. case DXMRTP_QOSEVENT_NOT_ALLOWEDTOSEND:
  1183. SendStreamEvent(CALL_STREAM_INACTIVE, CALL_CAUSE_REMOTE_REQUEST);
  1184. break;
  1185. case DXMRTP_QOSEVENT_ALLOWEDTOSEND:
  1186. SendStreamEvent(CALL_STREAM_ACTIVE, CALL_CAUSE_REMOTE_REQUEST);
  1187. break;
  1188. }
  1189. return S_OK;
  1190. }
  1191. HRESULT CIPConfMSPStream::ProcessGraphEvent(
  1192. IN long lEventCode,
  1193. IN long lParam1,
  1194. IN long lParam2
  1195. )
  1196. {
  1197. LOG((MSP_TRACE, "%ws ProcessGraphEvent %d", m_szName, lEventCode));
  1198. switch (lEventCode)
  1199. {
  1200. case DXMRTP_EVENTBASE + DXMRTP_RECV_RTCP_SNDR_REPORT_EVENT:
  1201. // lparam1 is the SSRC, lparam2 is the session ID
  1202. ProcessRTCPReport((DWORD)lParam1, PART_SEND);
  1203. break;
  1204. case DXMRTP_EVENTBASE + DXMRTP_RECV_RTCP_RECV_REPORT_EVENT:
  1205. // lparam1 is the SSRC, lparam2 is the session ID
  1206. ProcessRTCPReport((DWORD)lParam1, PART_RECV);
  1207. break;
  1208. case DXMRTP_EVENTBASE + DXMRTP_TIMEOUT_EVENT:
  1209. case DXMRTP_EVENTBASE + DXMRTP_BYE_EVENT:
  1210. // lparam1 is the SSRC, lparam2 is the source IP
  1211. ProcessParticipantLeave((DWORD)lParam1);
  1212. break;
  1213. case DXMRTP_EVENTBASE + DXMRTP_INACTIVE_EVENT:
  1214. // lparam1 is the SSRC, lparam2 is the source IP
  1215. ProcessParticipantTimeOutOrRecovered(TRUE, (DWORD)lParam1);
  1216. break;
  1217. case DXMRTP_EVENTBASE + DXMRTP_ACTIVE_AGAIN_EVENT:
  1218. // lparam1 is the SSRC, lparam2 is the source IP
  1219. ProcessParticipantTimeOutOrRecovered(FALSE, (DWORD)lParam1);
  1220. break;
  1221. case EC_COMPLETE:
  1222. SendStreamEvent(CALL_STREAM_INACTIVE, CALL_CAUSE_UNKNOWN);
  1223. break;
  1224. case EC_USERABORT:
  1225. SendStreamEvent(CALL_STREAM_INACTIVE, CALL_CAUSE_UNKNOWN);
  1226. break;
  1227. case EC_ERRORABORT:
  1228. case EC_STREAM_ERROR_STOPPED:
  1229. case EC_STREAM_ERROR_STILLPLAYING:
  1230. case EC_ERROR_STILLPLAYING:
  1231. SendStreamEvent(CALL_STREAM_FAIL, CALL_CAUSE_UNKNOWN, (HRESULT) lParam1);
  1232. break;
  1233. default:
  1234. if ((lEventCode >= DXMRTP_QOSEVENTBASE + DXMRTP_QOSEVENT_NOQOS)
  1235. && (lEventCode < DXMRTP_QOSEVENTBASE + DXMRTP_QOSEVENT_LAST))
  1236. {
  1237. ProcessQOSEvent(lEventCode - DXMRTP_QOSEVENTBASE);
  1238. }
  1239. break;
  1240. }
  1241. LOG((MSP_TRACE, "TRACE:CIPConfMSPStream::ProcessGraphEvent - exit S_OK"));
  1242. return S_OK;
  1243. }
  1244. HRESULT CIPConfMSPStream::SetLocalInfoOnRTPFilter(
  1245. IN IBaseFilter * pRTPFilter
  1246. )
  1247. {
  1248. IRTCPStream *pIRTCPStream;
  1249. HRESULT hr = pRTPFilter->QueryInterface(
  1250. IID_IRTCPStream,
  1251. (void **)&pIRTCPStream
  1252. );
  1253. if (FAILED(hr))
  1254. {
  1255. LOG((MSP_ERROR, "%ls can't get IRTCPStream interface %d", m_szName, hr));
  1256. return hr;
  1257. }
  1258. for (int i = 0; i < RTCP_SDES_LAST - 1; i ++)
  1259. {
  1260. if (m_InfoItems[i] != NULL)
  1261. {
  1262. hr = pIRTCPStream->SetLocalSDESItem(
  1263. RTCP_SDES_CNAME + i,
  1264. (BYTE *)m_InfoItems[i],
  1265. lstrlenA(m_InfoItems[i]) + 1
  1266. );
  1267. if (FAILED(hr))
  1268. {
  1269. LOG((MSP_WARN, "%ls can't set item:%s", m_InfoItems[i]));
  1270. }
  1271. }
  1272. }
  1273. pIRTCPStream->Release();
  1274. return hr;
  1275. }