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.

2982 lines
70 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. /* State Transition Table
  13. States:
  14. RO - Running whithout terminal. This is the initial state.
  15. PO - Paused without terminal
  16. SO - Stopped without terminal.
  17. RT - Runing with terminal.
  18. PT - Paused with termianl.
  19. ST - Stopped with terminal.
  20. Actions:
  21. S - Stop graph.
  22. P - Pause graph.
  23. C - Change graph.
  24. D - Disonnect terminals.
  25. F - Free extra references to filters and terminals.
  26. R - Run Graph.
  27. NIU - Not in use.
  28. Note: the same graph operation can be called multiple times, the graph
  29. just returns S_OK if it is already in desired state.
  30. NOTE: if the stream is not configured, the transition will happen without
  31. really doing anything to the graph.
  32. CONFIG will only be called for NC streams.
  33. CONFIG Select Unselect Run Pause Stop ShutDown
  34. RO OK C/R FAIL OK OK OK F
  35. RO RT RO RO PO SO -
  36. PO OK C/P FAIL OK OK OK F
  37. PO PT PO RO PO SO -
  38. SO OK C FAIL OK OK OK F
  39. SO ST SO RO PO SO -
  40. RT C/R S/C/R S/C/(R) R P S S/D/F
  41. RT RT RT,RO RT PT ST -
  42. PT C/P S/C/P S/C/(P) R P S S/D/F
  43. PT PT PT,PO RT PT ST -
  44. ST C C C R P S D/F
  45. ST ST ST,SO RT PT ST -
  46. */
  47. CIPConfMSPStream::CIPConfMSPStream()
  48. : CMSPStream(),
  49. m_szName(L""),
  50. m_fIsConfigured(FALSE),
  51. m_pIRTPSession(NULL),
  52. m_pIRTPDemux(NULL),
  53. m_pIStreamConfig(NULL),
  54. m_szKey(NULL),
  55. m_pStreamQCRelay(NULL),
  56. m_fAccessingQC(FALSE)
  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 WCHAR * pInfo,
  121. IN DWORD dwStringLen
  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. dwStringLen - the length of the string(not 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] = (WCHAR *)malloc((dwStringLen + 1)* sizeof(WCHAR));
  144. if (m_InfoItems[index] == NULL)
  145. {
  146. return E_OUTOFMEMORY;
  147. }
  148. lstrcpynW(m_InfoItems[index], pInfo, dwStringLen + 1);
  149. if (!m_pIRTPSession)
  150. {
  151. return S_OK;
  152. }
  153. //
  154. // if the RTP filter has been created, apply the change to the fitler.
  155. //
  156. HRESULT hr = m_pIRTPSession->SetSdesInfo(
  157. RTPSDES_CNAME + index,
  158. pInfo
  159. );
  160. if (FAILED(hr))
  161. {
  162. LOG((MSP_ERROR, "%ls can't set item:%s", m_szName, pInfo));
  163. }
  164. return hr;
  165. }
  166. STDMETHODIMP CIPConfMSPStream::get_Name(
  167. OUT BSTR * ppName
  168. )
  169. /*++
  170. Routine Description:
  171. Get the name of this stream.
  172. Arguments:
  173. ppName - the mem address to store a BSTR.
  174. Return Value:
  175. HRESULT.
  176. */
  177. {
  178. LOG((MSP_TRACE, "CIPconfMSPStream::get_Name - enter"));
  179. if (IsBadWritePtr(ppName, sizeof(BSTR)))
  180. {
  181. LOG((MSP_ERROR, "CMSPStream::get_Name - exit E_POINTER"));
  182. return E_POINTER;
  183. }
  184. DWORD dwID;
  185. if (m_dwMediaType == TAPIMEDIATYPE_AUDIO)
  186. {
  187. if (m_Direction == TD_CAPTURE)
  188. {
  189. dwID = IDS_AUDIO_CAPTURE_STREAM;
  190. }
  191. else
  192. {
  193. dwID = IDS_AUDIO_RENDER_STREAM;
  194. }
  195. }
  196. else
  197. {
  198. if (m_Direction == TD_CAPTURE)
  199. {
  200. dwID = IDS_VIDEO_CAPTURE_STREAM;
  201. }
  202. else
  203. {
  204. dwID = IDS_VIDEO_RENDER_STREAM;
  205. }
  206. }
  207. const int BUFSIZE = 1024;
  208. WCHAR wszName[BUFSIZE];
  209. if (LoadStringW(
  210. _Module.GetModuleInstance(),
  211. dwID,
  212. wszName,
  213. BUFSIZE - 1 ) == 0)
  214. {
  215. *ppName = NULL;
  216. LOG((MSP_ERROR, "CMSPStream::get_Name - "
  217. "LoadString failed - returning E_UNEXPECTED"));
  218. return E_UNEXPECTED;
  219. }
  220. //
  221. // Convert to a BSTR and return the BSTR.
  222. //
  223. BSTR pName = SysAllocString(wszName);
  224. if (pName == NULL)
  225. {
  226. LOG((MSP_ERROR, "CMSPStream::get_Name - exit out of mem"));
  227. return E_OUTOFMEMORY;
  228. }
  229. *ppName = pName;
  230. return S_OK;
  231. }
  232. HRESULT CIPConfMSPStream::SendStreamEvent(
  233. IN MSP_CALL_EVENT Event,
  234. IN MSP_CALL_EVENT_CAUSE Cause,
  235. IN HRESULT hrError = 0,
  236. IN ITTerminal * pTerminal = NULL
  237. )
  238. /*++
  239. Routine Description:
  240. Send a event to the app.
  241. */
  242. {
  243. CLock lock(m_lock);
  244. LOG((MSP_TRACE, "SendStreamEvent entered: stream %p, event %d, cause %d", this, Event, Cause));
  245. if (m_pMSPCall == NULL)
  246. {
  247. LOG((MSP_WARN, "The call has shut down the stream."));
  248. return S_OK;
  249. }
  250. ITStream * pITStream;
  251. HRESULT hr = this->_InternalQueryInterface(
  252. __uuidof(ITStream),
  253. (void **)&pITStream
  254. );
  255. if (FAILED(hr))
  256. {
  257. LOG((MSP_ERROR, "SendStreamEvent:QueryInterface failed: %x", hr));
  258. return hr;
  259. }
  260. MSPEVENTITEM* pEventItem = AllocateEventItem();
  261. if (pEventItem == NULL)
  262. {
  263. LOG((MSP_ERROR, "No memory for the TSPMSP data"));
  264. pITStream->Release();
  265. return E_OUTOFMEMORY;
  266. }
  267. // Fill in the necessary fields for the event structure.
  268. pEventItem->MSPEventInfo.dwSize = sizeof(MSP_EVENT_INFO);
  269. pEventItem->MSPEventInfo.Event = ME_CALL_EVENT;
  270. pEventItem->MSPEventInfo.MSP_CALL_EVENT_INFO.Type = Event;
  271. pEventItem->MSPEventInfo.MSP_CALL_EVENT_INFO.Cause = Cause;
  272. // pITStream has a refcount becaust it was from QI.
  273. pEventItem->MSPEventInfo.MSP_CALL_EVENT_INFO.pStream = pITStream;
  274. // the terminal needs to be addrefed.
  275. if (pTerminal) pTerminal->AddRef();
  276. pEventItem->MSPEventInfo.MSP_CALL_EVENT_INFO.pTerminal = pTerminal;
  277. pEventItem->MSPEventInfo.MSP_CALL_EVENT_INFO.hrError= hrError;
  278. hr = m_pMSPCall->HandleStreamEvent(pEventItem);
  279. if (FAILED(hr))
  280. {
  281. LOG((MSP_ERROR, "Post event failed %x", hr));
  282. if (pTerminal) pTerminal->Release();
  283. pITStream->Release();
  284. FreeEventItem(pEventItem);
  285. return hr;
  286. }
  287. return S_OK;
  288. }
  289. HRESULT CIPConfMSPStream::CleanUpFilters()
  290. /*++
  291. Routine Description:
  292. remove all the filters in the graph.
  293. Arguments:
  294. Return Value:
  295. HRESULT.
  296. --*/
  297. {
  298. LOG((MSP_TRACE, "CleanUpFilters for %ws %p", m_szName, this));
  299. if (m_pIRTPDemux)
  300. {
  301. m_pIRTPDemux->Release();
  302. m_pIRTPDemux = NULL;
  303. }
  304. /*
  305. if (m_pIRTPSession)
  306. {
  307. m_pIRTPSession->Release();
  308. m_pIRTPSession = NULL;
  309. }
  310. */
  311. if (m_pIStreamConfig)
  312. {
  313. m_pIStreamConfig->Release();
  314. m_pIStreamConfig = NULL;
  315. }
  316. for(;;)
  317. {
  318. // Because the enumerator is invalid after removing a filter from
  319. // the graph, we have to try to get all the filters in one shot.
  320. // If there are still more, we loop again.
  321. // Enumerate the filters in the graph.
  322. CComPtr<IEnumFilters>pEnum;
  323. HRESULT hr = m_pIGraphBuilder->EnumFilters(&pEnum);
  324. if (FAILED(hr))
  325. {
  326. LOG((MSP_ERROR, "cleanup filters, enumfilters failed: %x", hr));
  327. return hr;
  328. }
  329. const DWORD MAXFILTERS = 40;
  330. IBaseFilter * Filters[MAXFILTERS];
  331. DWORD dwFetched;
  332. hr = pEnum->Next(MAXFILTERS, Filters, &dwFetched);
  333. if (FAILED(hr))
  334. {
  335. LOG((MSP_ERROR, "get next filter failed: %x", hr));
  336. return hr;
  337. }
  338. for (DWORD i = 0; i< dwFetched; i ++)
  339. {
  340. m_pIGraphBuilder->RemoveFilter(Filters[i]);
  341. Filters[i]->Release();
  342. }
  343. if (hr != S_OK)
  344. {
  345. break;
  346. }
  347. }
  348. return S_OK;
  349. }
  350. HRESULT SetGraphClock(
  351. IGraphBuilder *pIGraphBuilder
  352. )
  353. {
  354. HRESULT hr;
  355. // create the clock object first.
  356. CComObject<CMSPStreamClock> *pClock = NULL;
  357. hr = ::CreateCComObjectInstance(&pClock);
  358. if (pClock == NULL)
  359. {
  360. LOG((MSP_ERROR,
  361. "SetGraphClock Could not create clock object, %x", hr));
  362. return hr;
  363. }
  364. IReferenceClock* pIReferenceClock = NULL;
  365. hr = pClock->_InternalQueryInterface(
  366. __uuidof(IReferenceClock),
  367. (void**)&pIReferenceClock
  368. );
  369. if (FAILED(hr))
  370. {
  371. LOG((MSP_ERROR,
  372. "SetGraphClock query pIReferenceClock interface failed, %x", hr));
  373. delete pClock;
  374. return hr;
  375. }
  376. // Get the graph builder interface on the graph.
  377. IMediaFilter *pFilter;
  378. hr = pIGraphBuilder->QueryInterface(
  379. IID_IMediaFilter, (void **) &pFilter);
  380. if(FAILED(hr))
  381. {
  382. LOG((MSP_ERROR, "get IFilter interface, %x", hr));
  383. pIReferenceClock->Release();
  384. return hr;
  385. }
  386. hr = pFilter->SetSyncSource(pIReferenceClock);
  387. pIReferenceClock->Release();
  388. pFilter->Release();
  389. LOG((MSP_TRACE, "SetSyncSource returned, %x", hr));
  390. return hr;
  391. }
  392. HRESULT CIPConfMSPStream::Configure(
  393. IN STREAMSETTINGS &StreamSettings,
  394. IN WCHAR *pszKey
  395. )
  396. /*++
  397. Routine Description:
  398. Configure the settings of this stream.
  399. Arguments:
  400. StreamSettings - The setting structure got from the SDP blob.
  401. Return Value:
  402. HRESULT.
  403. --*/
  404. {
  405. LOG((MSP_TRACE, "CIPConfMSPStream configure entered."));
  406. CLock lock(m_lock);
  407. _ASSERTE(m_fIsConfigured == FALSE);
  408. // configure the graph with our own clock.
  409. SetGraphClock(m_pIGraphBuilder);
  410. if (pszKey != NULL)
  411. {
  412. m_szKey = (WCHAR *)malloc(sizeof(WCHAR) * (lstrlenW(pszKey) + 1));
  413. if (m_szKey == NULL)
  414. {
  415. LOG((MSP_ERROR, "stream %ws %p out of memeroy", m_szName, this));
  416. return E_OUTOFMEMORY;
  417. }
  418. lstrcpyW(m_szKey, pszKey);
  419. }
  420. m_Settings = StreamSettings;
  421. m_fIsConfigured = TRUE;
  422. // setup maximum bandwidth
  423. HRESULT hr;
  424. if (m_Settings.lBandwidth != QCDEFAULT_QUALITY_UNSET)
  425. {
  426. if (FAILED (hr = Set (StreamQuality_MaxBitrate, m_Settings.lBandwidth, TAPIControl_Flags_None)))
  427. {
  428. LOG((MSP_ERROR, "stream %ws %p failed to set maximum bitrate %d. %x", m_szName, this, m_Settings.lBandwidth, hr));
  429. }
  430. }
  431. // if there is no terminal selected, just return.
  432. if (m_Terminals.GetSize() == 0)
  433. {
  434. LOG((MSP_INFO, "stream %ws %p needs terminal", m_szName, this));
  435. return S_OK;
  436. }
  437. // set up the filters and the terminals.
  438. hr = SetUpFilters();
  439. if (FAILED(hr))
  440. {
  441. SendStreamEvent(CALL_STREAM_FAIL, CALL_CAUSE_CONNECT_FAIL, hr);
  442. LOG((MSP_ERROR, "stream %ws %p set up filters failed, %x",
  443. m_szName, this, hr));
  444. return hr;
  445. }
  446. LOG((MSP_INFO, "stream %ws %p configure exit S_OK", m_szName, this));
  447. return S_OK;
  448. }
  449. HRESULT CIPConfMSPStream::FinishConfigure()
  450. /*++
  451. Routine Description:
  452. Configure the settings of this stream.
  453. Arguments:
  454. Return Value:
  455. HRESULT.
  456. --*/
  457. {
  458. LOG((MSP_TRACE, "CIPConfMSPStream FinishConfigure entered."));
  459. CLock lock(m_lock);
  460. if (m_fIsConfigured == FALSE)
  461. {
  462. // this stream hasn't been configured.
  463. return E_FAIL;
  464. }
  465. HRESULT hr;
  466. switch (m_dwState)
  467. {
  468. case STRM_RUNNING:
  469. // start the graph.
  470. hr = CMSPStream::StartStream();
  471. if (FAILED(hr))
  472. {
  473. // if the stream failed to start, let the app now.
  474. SendStreamEvent(CALL_STREAM_FAIL, CALL_CAUSE_UNKNOWN, hr);
  475. LOG((MSP_ERROR, "stream %ws %p failed to start, %x", m_szName, this, hr));
  476. return hr;
  477. }
  478. if (m_Terminals.GetSize() > 0)
  479. {
  480. SendStreamEvent(CALL_STREAM_ACTIVE, CALL_CAUSE_REMOTE_REQUEST);
  481. }
  482. LOG((MSP_INFO, "stream %ws %p started", m_szName, this));
  483. break;
  484. case STRM_PAUSED:
  485. // pause the graph.
  486. hr = CMSPStream::PauseStream();
  487. if (FAILED(hr))
  488. {
  489. // if the stream failed to start, let the app now.
  490. SendStreamEvent(CALL_STREAM_FAIL, CALL_CAUSE_UNKNOWN, hr);
  491. LOG((MSP_ERROR, "stream %ws %p failed to pause, %x", m_szName, this, hr));
  492. return hr;
  493. }
  494. LOG((MSP_INFO, "stream %ws %p paused", m_szName, this));
  495. break;
  496. case STRM_STOPPED:
  497. break;
  498. }
  499. LOG((MSP_INFO, "stream %ws %p configure exit S_OK", m_szName, this));
  500. return S_OK;
  501. }
  502. STDMETHODIMP CIPConfMSPStream::StartStream()
  503. /*++
  504. Routine Description:
  505. Start the stream. This is the basic state machine for all the derived
  506. streams.
  507. Arguments:
  508. Return Value:
  509. HRESULT.
  510. --*/
  511. {
  512. CLock lock(m_lock);
  513. // if there is no terminal selected
  514. if (m_Terminals.GetSize() == 0)
  515. {
  516. LOG((MSP_INFO, "stream %ws %p needs terminal", m_szName, this));
  517. // Enter Runing state. (RO)
  518. m_dwState = STRM_RUNNING;
  519. return S_OK;
  520. }
  521. if (!m_fIsConfigured)
  522. {
  523. LOG((MSP_INFO, "stream %ws %p is not configured yet", m_szName, this));
  524. // Enter Runing state. (RO, RT)
  525. m_dwState = STRM_RUNNING;
  526. return S_OK;
  527. }
  528. // Start the stream.
  529. HRESULT hr = CMSPStream::StartStream();
  530. if (FAILED(hr))
  531. {
  532. LOG((MSP_ERROR, "stream %ws %p failed to start, %x", m_szName, this, hr));
  533. return hr;
  534. }
  535. SendStreamEvent(CALL_STREAM_ACTIVE, CALL_CAUSE_LOCAL_REQUEST);
  536. LOG((MSP_INFO, "stream %ws %p started", m_szName, this));
  537. // Enter Runing state.(RT)
  538. m_dwState = STRM_RUNNING;
  539. return S_OK;
  540. }
  541. STDMETHODIMP CIPConfMSPStream::PauseStream()
  542. /*++
  543. Routine Description:
  544. Pause the stream. This is the basic state machine for all the derived
  545. streams.
  546. Arguments:
  547. Return Value:
  548. HRESULT.
  549. --*/
  550. {
  551. CLock lock(m_lock);
  552. // if there is no terminal selected
  553. if (m_Terminals.GetSize() == 0)
  554. {
  555. LOG((MSP_INFO, "stream %ws %p needs terminal", m_szName, this));
  556. // Enter paused state. (PO)
  557. m_dwState = STRM_PAUSED;
  558. return S_OK;
  559. }
  560. if (!m_fIsConfigured)
  561. {
  562. LOG((MSP_INFO, "stream %ws %p is not configured yet", m_szName, this));
  563. // Enter paused state. (PO, PT)
  564. m_dwState = STRM_PAUSED;
  565. return S_OK;
  566. }
  567. // Start the stream.
  568. HRESULT hr = CMSPStream::PauseStream();
  569. if (FAILED(hr))
  570. {
  571. LOG((MSP_ERROR, "stream %ws %p failed to pause, %x", m_szName, this, hr));
  572. return hr;
  573. }
  574. LOG((MSP_INFO, "stream %ws %p paused", m_szName, this));
  575. // Enter paused state.(PT)
  576. m_dwState = STRM_PAUSED;
  577. return S_OK;
  578. }
  579. STDMETHODIMP CIPConfMSPStream::StopStream()
  580. /*++
  581. Routine Description:
  582. Stop the stream. This is the basic state machine for all the derived
  583. streams.
  584. Arguments:
  585. Return Value:
  586. HRESULT.
  587. --*/
  588. {
  589. CLock lock(m_lock);
  590. // if there is no terminal selected
  591. if (m_Terminals.GetSize() == 0)
  592. {
  593. LOG((MSP_INFO, "stream %ws %p needs terminal", m_szName, this));
  594. // Enter stopped state. (SO)
  595. m_dwState = STRM_STOPPED;
  596. return S_OK;
  597. }
  598. if (!m_fIsConfigured)
  599. {
  600. LOG((MSP_INFO, "stream %ws %p is not configured yet", m_szName, this));
  601. // Enter stopped state. (SO, ST)
  602. m_dwState = STRM_STOPPED;
  603. return S_OK;
  604. }
  605. // Stop the graph.
  606. HRESULT hr = CMSPStream::StopStream();
  607. if (FAILED(hr))
  608. {
  609. LOG((MSP_ERROR, "stream %ws %p failed to stop, %x", m_szName, this, hr));
  610. return hr;
  611. }
  612. SendStreamEvent(CALL_STREAM_INACTIVE, CALL_CAUSE_LOCAL_REQUEST);
  613. LOG((MSP_INFO, "stream %ws %p stopped", m_szName, this));
  614. // Enter stopped state.(ST)
  615. m_dwState = STRM_STOPPED;
  616. return S_OK;
  617. }
  618. HRESULT CIPConfMSPStream::CheckTerminalTypeAndDirection(
  619. IN ITTerminal * pTerminal
  620. )
  621. /*++
  622. Routine Description:
  623. The implementation in this class checks to see if the terminal
  624. is th right type and direction and it only allows on terminal per
  625. stream.
  626. Arguments:
  627. pTerminal - the terminal object.
  628. */
  629. {
  630. // check the media type of this terminal.
  631. long lMediaType;
  632. HRESULT hr = pTerminal->get_MediaType(&lMediaType);
  633. if (FAILED(hr))
  634. {
  635. LOG((MSP_ERROR, "can't get terminal media type. %x", hr));
  636. return TAPI_E_INVALIDTERMINAL;
  637. }
  638. if ((DWORD)lMediaType != m_dwMediaType)
  639. {
  640. return TAPI_E_INVALIDTERMINAL;
  641. }
  642. // check the direction of this terminal.
  643. TERMINAL_DIRECTION Direction;
  644. hr = pTerminal->get_Direction(&Direction);
  645. if (FAILED(hr))
  646. {
  647. LOG((MSP_ERROR, "can't get terminal direction. %x", hr));
  648. return TAPI_E_INVALIDTERMINAL;
  649. }
  650. if (Direction != TD_BIDIRECTIONAL && Direction != m_Direction)
  651. {
  652. return TAPI_E_INVALIDTERMINAL;
  653. }
  654. // By default, only one terminal is supported per stream.
  655. if (m_Terminals.GetSize() > 0)
  656. {
  657. return TAPI_E_MAXTERMINALS;
  658. }
  659. return S_OK;
  660. }
  661. HRESULT CIPConfMSPStream::SelectTerminal(
  662. IN ITTerminal * pTerminal
  663. )
  664. /*++
  665. Routine Description:
  666. Select a terminal on the stream. The stream will start itself if it
  667. was in running state. See the state transition table at the beginning
  668. of this file.
  669. Arguments:
  670. pTerminal - the terminal object.
  671. Return Value:
  672. S_OK
  673. E_POINTER
  674. E_OUTOFMEMORY
  675. TAPI_E_MAXTERMINALS
  676. TAPI_E_INVALIDTERMINAL
  677. --*/
  678. {
  679. LOG((MSP_TRACE, "CMSPStream::SelectTerminal, %p", pTerminal));
  680. //
  681. // Check parameter.
  682. //
  683. if ( IsBadReadPtr(pTerminal, sizeof(ITTerminal) ) )
  684. {
  685. LOG((MSP_ERROR, "CIPconfMSPStream.SelectTerminal - exit E_POINTER"));
  686. return E_POINTER;
  687. }
  688. CLock lock(m_lock);
  689. // validate the terminal.
  690. HRESULT hr = CheckTerminalTypeAndDirection(pTerminal);
  691. if (FAILED(hr))
  692. {
  693. LOG((MSP_ERROR, "wrong terminal. %x", hr));
  694. return hr;
  695. }
  696. // put the terminal into our list.
  697. hr = CMSPStream::SelectTerminal(pTerminal);
  698. if (FAILED(hr))
  699. {
  700. LOG((MSP_ERROR, "SelectTerminal on CMSPStream failed, %x", hr));
  701. return hr;
  702. }
  703. // At this point, the select terminal opration succeeded. All the
  704. // failure cases are handled by sending events after this.
  705. if (!m_fIsConfigured)
  706. {
  707. LOG((MSP_INFO, "stream %ws %p is not configured yet", m_szName, this));
  708. return S_OK;
  709. }
  710. // Query IFilterChain
  711. CComPtr<IFilterChain> pIFilterChain;
  712. hr = m_pIMediaControl->QueryInterface(
  713. __uuidof(IFilterChain),
  714. (void**)&pIFilterChain
  715. );
  716. if (FAILED (hr) && (hr != E_NOINTERFACE))
  717. {
  718. LOG ((MSP_ERROR, "stream %ws %p failted to get filter chain. %x", m_szName, this, hr));
  719. return hr;
  720. }
  721. //#ifdef DYNGRAPH
  722. OAFilterState FilterState;
  723. hr = m_pIMediaControl->GetState(0, &FilterState);
  724. if (FAILED(hr))
  725. {
  726. LOG((MSP_ERROR, "stream %ws %p GetState failed, %x", m_szName, this, hr));
  727. SendStreamEvent(CALL_STREAM_FAIL, CALL_CAUSE_UNKNOWN, hr);
  728. return S_OK;
  729. }
  730. //#endif
  731. // #ifndef DYNGRAPH
  732. if (!(m_dwMediaType == TAPIMEDIATYPE_VIDEO &&
  733. m_Direction == TD_RENDER &&
  734. pIFilterChain != NULL))
  735. {
  736. // stop the graph before making changes.
  737. hr = CMSPStream::StopStream();
  738. if (FAILED(hr))
  739. {
  740. LOG((MSP_ERROR, "stream %ws %p failed to stop, %x", m_szName, this, hr));
  741. SendStreamEvent(CALL_STREAM_FAIL, CALL_CAUSE_UNKNOWN, hr);
  742. return S_OK;
  743. }
  744. // do not duplicate stream inactive if it is inactive
  745. //if (FilterState == State_Running)
  746. //{
  747. // no need to send stream inactive at all
  748. // SendStreamEvent(CALL_STREAM_INACTIVE, CALL_CAUSE_LOCAL_REQUEST);
  749. //}
  750. }
  751. // #endif
  752. // connect the new terminal into the graph.
  753. // this method will send events if the terminal failed.
  754. hr = ConnectTerminal(pTerminal);
  755. if (FAILED(hr))
  756. {
  757. LOG((MSP_ERROR, "stream %ws %p connect to terminal failed, %x",
  758. m_szName, this, hr));
  759. SendStreamEvent(CALL_STREAM_FAIL, CALL_CAUSE_CONNECT_FAIL, hr);
  760. return S_OK;
  761. }
  762. // if not video receive or no dynamic graph
  763. // after connecting the termanal, go back to the original state.
  764. switch (m_dwState)
  765. {
  766. case STRM_RUNNING:
  767. {
  768. // if dynamic graph and was running, then do nothing
  769. if (m_dwMediaType == TAPIMEDIATYPE_VIDEO &&
  770. m_Direction == TD_RENDER &&
  771. pIFilterChain != NULL &&
  772. FilterState == State_Running)
  773. break;
  774. // start the stream.
  775. hr = CMSPStream::StartStream();
  776. if (FAILED(hr))
  777. {
  778. LOG((MSP_ERROR, "stream %ws %p failed, %x", m_szName, this, hr));
  779. SendStreamEvent(CALL_STREAM_FAIL, CALL_CAUSE_UNKNOWN, hr);
  780. break;
  781. }
  782. SendStreamEvent(CALL_STREAM_ACTIVE, CALL_CAUSE_LOCAL_REQUEST);
  783. }
  784. break;
  785. case STRM_PAUSED:
  786. {
  787. // pause the stream.
  788. hr = CMSPStream::PauseStream();
  789. if (FAILED(hr))
  790. {
  791. LOG((MSP_ERROR, "stream %ws %p failed, %x", m_szName, this, hr));
  792. SendStreamEvent(CALL_STREAM_FAIL, CALL_CAUSE_UNKNOWN, hr);
  793. }
  794. }
  795. break;
  796. }
  797. return S_OK;
  798. }
  799. STDMETHODIMP CIPConfMSPStream::UnselectTerminal(
  800. IN ITTerminal * pTerminal
  801. )
  802. /*++
  803. Routine Description:
  804. Unselect a terminal from the stream. It handles changing the graph and
  805. going back to the original state.
  806. Arguments:
  807. Return Value:
  808. S_OK
  809. E_POINTER
  810. E_OUTOFMEMORY
  811. TAPI_E_MAXTERMINALS
  812. TAPI_E_INVALIDTERMINAL
  813. --*/
  814. {
  815. LOG((MSP_TRACE,
  816. "CIPConfMSPStream::UnselectTerminal, pTerminal %p", pTerminal));
  817. CLock lock(m_lock);
  818. int index;
  819. if ((index = m_Terminals.Find(pTerminal)) < 0)
  820. {
  821. LOG((MSP_ERROR, "UnselectTerminal - exit TAPI_E_INVALIDTERMINAL"));
  822. return TAPI_E_INVALIDTERMINAL;
  823. }
  824. HRESULT hr;
  825. //
  826. // Unregister the PTEventSink object
  827. //
  828. hr = UnregisterPluggableTerminalEventSink( pTerminal );
  829. if( FAILED(hr) )
  830. {
  831. LOG((MSP_TRACE, "stream %ws %p something wrong in UnregisterPluggableTerminalEventSink, %x",
  832. m_szName, this, hr));
  833. }
  834. // if the stream is not configured, just remove it and return.
  835. if (!m_fIsConfigured)
  836. {
  837. if (!m_Terminals.RemoveAt(index))
  838. {
  839. LOG((MSP_ERROR, "CMSPStream::UnselectTerminal - "
  840. "exit E_UNEXPECTED"));
  841. return E_UNEXPECTED;
  842. }
  843. // release the refcount that was in our list.
  844. pTerminal->Release();
  845. LOG((MSP_INFO, "stream %ws %p is not configured yet", m_szName, this));
  846. return S_OK;
  847. }
  848. //#ifdef DYNGRAPH
  849. OAFilterState FilterState;
  850. hr = m_pIMediaControl->GetState(0, &FilterState);
  851. if (FAILED(hr))
  852. {
  853. LOG((MSP_ERROR, "stream %ws %p GetState failed, %x", m_szName, this, hr));
  854. SendStreamEvent(CALL_STREAM_FAIL, CALL_CAUSE_UNKNOWN, hr);
  855. return S_OK;
  856. }
  857. //#endif
  858. CComPtr <IFilterChain> pIFilterChain;
  859. hr = m_pIMediaControl->QueryInterface(
  860. __uuidof(IFilterChain),
  861. (void**)&pIFilterChain
  862. );
  863. if (FAILED (hr) && (hr != E_NOINTERFACE))
  864. {
  865. LOG ((MSP_ERROR, "stream %ws %p failted to get filter chain. %x", m_szName, this, hr));
  866. return hr;
  867. }
  868. // #ifndef DYNGRAPH
  869. if (!(m_dwMediaType == TAPIMEDIATYPE_VIDEO &&
  870. m_Direction == TD_RENDER &&
  871. pIFilterChain != NULL))
  872. {
  873. // stop the graph before making changes.
  874. hr = CMSPStream::StopStream();
  875. if (FAILED(hr))
  876. {
  877. LOG((MSP_ERROR, "stream %ws %p failed to stop, %x", m_szName, this, hr));
  878. return hr;
  879. }
  880. if (FilterState == State_Running)
  881. {
  882. SendStreamEvent(CALL_STREAM_INACTIVE, CALL_CAUSE_LOCAL_REQUEST);
  883. }
  884. }
  885. // #endif
  886. // disconnect the terminal from the graph.
  887. // this method will send events if the terminal failed.
  888. hr = DisconnectTerminal(pTerminal);
  889. if (FAILED(hr))
  890. {
  891. LOG((MSP_ERROR, "stream %ws %p disconnectTerminal failed, %x",
  892. m_szName, this, hr));
  893. return hr;
  894. }
  895. if (!m_Terminals.RemoveAt(index))
  896. {
  897. LOG((MSP_ERROR, "CMSPStream::UnselectTerminal - "
  898. "exit E_UNEXPECTED"));
  899. return E_UNEXPECTED;
  900. }
  901. // release the refcount that was in our list.
  902. pTerminal->Release();
  903. // if there is no terminal selected, just return and wait for terminals.
  904. if (m_Terminals.GetSize() == 0)
  905. {
  906. LOG((MSP_INFO, "stream %ws %p needs terminal", m_szName, this));
  907. return S_OK;
  908. }
  909. // At this point, the Unselect terminal opration succeeded. All the
  910. // failure cases are handled by sending events after this.
  911. // after disconnecting the termanal, go back to the original state.
  912. if (!(m_dwMediaType == TAPIMEDIATYPE_VIDEO &&
  913. m_Direction == TD_RENDER &&
  914. pIFilterChain != NULL))
  915. {
  916. switch (FilterState)
  917. {
  918. case State_Running:
  919. {
  920. // start the stream.
  921. hr = CMSPStream::StartStream();
  922. if (FAILED(hr))
  923. {
  924. LOG((MSP_ERROR, "stream %ws %p failed to start, %x", m_szName, this, hr));
  925. SendStreamEvent(CALL_STREAM_FAIL, CALL_CAUSE_UNKNOWN, hr);
  926. break;
  927. }
  928. SendStreamEvent(CALL_STREAM_ACTIVE, CALL_CAUSE_LOCAL_REQUEST);
  929. }
  930. break;
  931. case State_Paused:
  932. {
  933. // pause the stream.
  934. hr = CMSPStream::PauseStream();
  935. if (FAILED(hr))
  936. {
  937. LOG((MSP_ERROR, "stream %ws %p failed to pause, %x", m_szName, this, hr));
  938. SendStreamEvent(CALL_STREAM_FAIL, CALL_CAUSE_UNKNOWN, hr);
  939. }
  940. }
  941. break;
  942. }
  943. }
  944. return S_OK;
  945. }
  946. HRESULT CIPConfMSPStream::ShutDown()
  947. /*++
  948. Routine Description:
  949. Shut down the stream. It release the filters and terminals.
  950. Arguments:
  951. Return Value:
  952. S_OK
  953. --*/
  954. {
  955. LOG((MSP_TRACE, "CIPConfMSPStream::Shutdown %ws - enter", m_szName));
  956. CLock lock(m_lock);
  957. for (int j = 0; j < NUM_SDES_ITEMS; j ++)
  958. {
  959. if (m_InfoItems[j])
  960. {
  961. free(m_InfoItems[j]);
  962. m_InfoItems[j] = NULL;
  963. }
  964. }
  965. // unlink by stream
  966. HRESULT hr;
  967. if (FAILED (hr = UnlinkInnerCallQC (TRUE)))
  968. LOG ((MSP_ERROR, "CH323MSPStream::ShutDown failed to unlink on call qc, %x", hr));
  969. if (m_pMSPCall)
  970. {
  971. m_pMSPCall->MSPCallRelease();
  972. m_pMSPCall = NULL;
  973. }
  974. // free the extra filter reference.
  975. if (m_pIRTPDemux)
  976. {
  977. m_pIRTPDemux->Release();
  978. m_pIRTPDemux = NULL;
  979. }
  980. if (m_pIRTPSession)
  981. {
  982. m_pIRTPSession->Release();
  983. m_pIRTPSession = NULL;
  984. }
  985. if (m_pIStreamConfig)
  986. {
  987. m_pIStreamConfig->Release();
  988. m_pIStreamConfig = NULL;
  989. }
  990. if (m_szKey)
  991. {
  992. free(m_szKey);
  993. m_szKey = NULL;
  994. }
  995. // If the stream is not configured, just free the terminals.
  996. if (!m_fIsConfigured)
  997. {
  998. LOG((MSP_INFO, "stream %ws %p is not configured yet", m_szName, this));
  999. for ( int i = 0; i < m_Terminals.GetSize(); i ++ )
  1000. {
  1001. m_Terminals[i]->Release();
  1002. }
  1003. m_Terminals.RemoveAll();
  1004. return S_OK;
  1005. }
  1006. // if there are terminals and configured, we need to disconnect
  1007. // the terminals.
  1008. if (m_Terminals.GetSize() > 0)
  1009. {
  1010. // Stop the graph before disconnecting the terminals.
  1011. HRESULT hr = CMSPStream::StopStream();
  1012. if (FAILED(hr))
  1013. {
  1014. LOG((MSP_ERROR,
  1015. "stream %ws %p failed to stop, %x", m_szName, this, hr));
  1016. return hr;
  1017. }
  1018. for ( int i = 0; i < m_Terminals.GetSize(); i ++ )
  1019. {
  1020. hr = DisconnectTerminal(m_Terminals[i]);
  1021. LOG((MSP_TRACE, "Disconnect terminal returned %x", hr));
  1022. m_Terminals[i]->Release();
  1023. }
  1024. m_Terminals.RemoveAll();
  1025. }
  1026. for (int i = 0; i < m_Participants.GetSize(); i ++)
  1027. {
  1028. m_Participants[i]->Release();
  1029. }
  1030. m_Participants.RemoveAll();
  1031. LOG((MSP_TRACE, "CIPConfMSPStream::Shutdown - exit S_OK"));
  1032. return S_OK;
  1033. }
  1034. HRESULT CIPConfMSPStream::DisconnectTerminal(
  1035. IN ITTerminal * pITTerminal
  1036. )
  1037. /*++
  1038. Routine Description:
  1039. Disconnect a terminal. It will remove its filters from the graph and
  1040. also release its references to the graph.
  1041. Arguments:
  1042. pITTerminal - the terminal.
  1043. Return Value:
  1044. HRESULT.
  1045. --*/
  1046. {
  1047. CComQIPtr<ITTerminalControl, &__uuidof(ITTerminalControl)>
  1048. pTerminalControl(pITTerminal);
  1049. if (pTerminalControl == NULL)
  1050. {
  1051. LOG((MSP_ERROR, "can't get Terminal Control interface"));
  1052. return E_NOINTERFACE;
  1053. }
  1054. HRESULT hr = pTerminalControl->DisconnectTerminal(m_pIGraphBuilder, 0);
  1055. LOG((MSP_TRACE, "terminal %p is disonnected. hr:%x", pITTerminal, hr));
  1056. return hr;
  1057. }
  1058. HRESULT CIPConfMSPStream::EnableParticipantEvents(
  1059. IN IRtpSession * pRtpSession
  1060. )
  1061. /*++
  1062. Routine Description:
  1063. Enable participant information, such as join, leave, info change,
  1064. talking, silence, etc.
  1065. Arguments:
  1066. pRtpSession - The RTP sesion pointer.
  1067. Return Value:
  1068. HRESULT.
  1069. --*/
  1070. {
  1071. ENTER_FUNCTION("CIPConfMSPStream::EnableParticipantEvents");
  1072. LOG((MSP_TRACE, "%s entered for %ws", __fxName, m_szName));
  1073. HRESULT hr;
  1074. DWORD dwEnabledMask;
  1075. if (m_Direction == TD_RENDER)
  1076. {
  1077. // enable participant state events.
  1078. DWORD dwParticipantInfoMask =
  1079. RTPPARINFO_MASK_STALL |
  1080. RTPPARINFO_MASK_BYE |
  1081. RTPPARINFO_MASK_DEL;
  1082. if (m_dwMediaType == TAPIMEDIATYPE_AUDIO)
  1083. {
  1084. // watch for active talkers
  1085. dwParticipantInfoMask |=
  1086. RTPPARINFO_MASK_TALKING |
  1087. RTPPARINFO_MASK_WAS_TALKING;
  1088. }
  1089. else
  1090. {
  1091. // watch for video Senders
  1092. dwParticipantInfoMask |=
  1093. RTPPARINFO_MASK_TALKING |
  1094. RTPPARINFO_MASK_SILENT |
  1095. RTPPARINFO_MASK_MAPPED |
  1096. RTPPARINFO_MASK_UNMAPPED;
  1097. }
  1098. hr = pRtpSession->ModifySessionMask(
  1099. RTPMASK_PINFOR_EVENTS,
  1100. dwParticipantInfoMask,
  1101. 1,
  1102. &dwEnabledMask
  1103. );
  1104. if (FAILED(hr))
  1105. {
  1106. LOG((MSP_ERROR, "%s, modify pinfo failed. %x", __fxName, hr));
  1107. return hr;
  1108. }
  1109. // enable participant information events.
  1110. DWORD dwSDESMask =
  1111. RTPSDES_MASK_CNAME |
  1112. RTPSDES_MASK_NAME |
  1113. RTPSDES_MASK_EMAIL |
  1114. RTPSDES_MASK_PHONE |
  1115. RTPSDES_MASK_LOC |
  1116. RTPSDES_MASK_TOOL |
  1117. RTPSDES_MASK_NOTE |
  1118. RTPSDES_MASK_PRIV;
  1119. // tell RTP to save these items for retrieval
  1120. hr = pRtpSession->ModifySessionMask(
  1121. RTPMASK_SDES_REMMASK,
  1122. dwSDESMask,
  1123. 1,
  1124. &dwEnabledMask
  1125. );
  1126. if (FAILED(hr))
  1127. {
  1128. LOG((MSP_ERROR, "%s, modify sdes mask for receiver failed. %x",
  1129. __fxName, hr));
  1130. return hr;
  1131. }
  1132. // tell RTP to fire events when it gets these items.
  1133. hr = pRtpSession->ModifySessionMask(
  1134. RTPMASK_SDESRECV_EVENTS,
  1135. dwSDESMask,
  1136. 1,
  1137. &dwEnabledMask
  1138. );
  1139. if (FAILED(hr))
  1140. {
  1141. LOG((MSP_ERROR, "%s, modify sdes mask for receiver failed. %x",
  1142. __fxName, hr));
  1143. return hr;
  1144. }
  1145. }
  1146. else
  1147. {
  1148. // enable the sending of local SDES information.
  1149. DWORD dwLocalSDESMask =
  1150. RTPSDES_LOCMASK_CNAME |
  1151. RTPSDES_LOCMASK_NAME |
  1152. RTPSDES_LOCMASK_EMAIL |
  1153. RTPSDES_LOCMASK_PHONE |
  1154. RTPSDES_LOCMASK_LOC |
  1155. RTPSDES_LOCMASK_TOOL |
  1156. RTPSDES_LOCMASK_NOTE |
  1157. RTPSDES_LOCMASK_PRIV;
  1158. hr = pRtpSession->ModifySessionMask(
  1159. RTPMASK_SDES_LOCMASK,
  1160. dwLocalSDESMask,
  1161. 1,
  1162. &dwEnabledMask
  1163. );
  1164. if (FAILED(hr))
  1165. {
  1166. LOG((MSP_ERROR, "%s, modify sdes mask for local SDES failed. %x",
  1167. __fxName, hr));
  1168. return hr;
  1169. }
  1170. }
  1171. return hr;
  1172. }
  1173. HRESULT CIPConfMSPStream::EnableQOS(
  1174. IN IRtpSession * pRtpSession
  1175. )
  1176. /*++
  1177. Routine Description:
  1178. Enable qos reservation and qos events
  1179. Arguments:
  1180. pRtpSession - The RTP sesion pointer.
  1181. Return Value:
  1182. HRESULT.
  1183. --*/
  1184. {
  1185. ENTER_FUNCTION("CIPConfMSPStream::EnableQOS");
  1186. LOG((MSP_TRACE, "%s entered for %ws", __fxName, m_szName));
  1187. HRESULT hr;
  1188. // set the QOS application IDs.
  1189. if (m_Settings.pApplicationID ||
  1190. m_Settings.pSubIDs ||
  1191. m_Settings.pApplicationGUID)
  1192. {
  1193. if (FAILED(hr = pRtpSession->SetQosAppId(
  1194. m_Settings.pApplicationID,
  1195. m_Settings.pApplicationGUID,
  1196. m_Settings.pSubIDs
  1197. )))
  1198. {
  1199. LOG((MSP_ERROR, "%s, set qos application id. %x", __fxName, hr));
  1200. return hr;
  1201. }
  1202. }
  1203. TCHAR * szQOSName;
  1204. DWORD dwMaxParticipant = 5; // default to 5
  1205. switch (m_Settings.PayloadTypes[0])
  1206. {
  1207. case PAYLOAD_G711U:
  1208. case PAYLOAD_G711A:
  1209. szQOSName = RTPQOSNAME_G711;
  1210. break;
  1211. case PAYLOAD_GSM:
  1212. szQOSName = RTPQOSNAME_GSM6_10;
  1213. break;
  1214. case PAYLOAD_DVI4_8:
  1215. szQOSName = RTPQOSNAME_DVI4_8;
  1216. break;
  1217. case PAYLOAD_DVI4_16:
  1218. szQOSName = RTPQOSNAME_DVI4_16;
  1219. break;
  1220. case PAYLOAD_MSAUDIO:
  1221. szQOSName = RTPQOSNAME_MSAUDIO;
  1222. break;
  1223. case PAYLOAD_H261:
  1224. szQOSName = (m_Settings.fCIF) ? RTPQOSNAME_H261CIF : RTPQOSNAME_H261QCIF;
  1225. dwMaxParticipant = 40; // 40 for video
  1226. break;
  1227. case PAYLOAD_H263:
  1228. szQOSName = (m_Settings.fCIF) ? RTPQOSNAME_H263CIF : RTPQOSNAME_H263QCIF;
  1229. dwMaxParticipant = 40; // 40 for video
  1230. break;
  1231. default:
  1232. LOG((MSP_WARN, "Don't know the QOS name for payload type: %d",
  1233. m_Settings.PayloadTypes[0]));
  1234. return E_FAIL;
  1235. }
  1236. // use shared explicit for video.
  1237. DWORD dwStyle = (m_dwMediaType == TAPIMEDIATYPE_VIDEO)
  1238. ? RTPQOS_STYLE_SE : RTPQOS_STYLE_DEFAULT;
  1239. hr = pRtpSession->SetQosByName(
  1240. szQOSName,
  1241. dwStyle,
  1242. dwMaxParticipant, // start from 40 participant reservation.
  1243. RTPQOSSENDMODE_REDUCED_RATE,
  1244. m_Settings.dwMSPerPacket? m_Settings.dwMSPerPacket:~0
  1245. );
  1246. if (FAILED(hr))
  1247. {
  1248. LOG((MSP_ERROR, "%s, SetQosByName failed. %x", __fxName, hr));
  1249. return hr;
  1250. }
  1251. // enable qos events.
  1252. DWORD dwQOSEventMask =
  1253. RTPQOS_MASK_ADMISSION_FAILURE |
  1254. RTPQOS_MASK_POLICY_FAILURE |
  1255. RTPQOS_MASK_BAD_STYLE |
  1256. RTPQOS_MASK_BAD_OBJECT |
  1257. RTPQOS_MASK_TRAFFIC_CTRL_ERROR |
  1258. RTPQOS_MASK_GENERIC_ERROR |
  1259. RTPQOS_MASK_NOT_ALLOWEDTOSEND |
  1260. RTPQOS_MASK_ALLOWEDTOSEND;
  1261. DWORD dwEnabledMask;
  1262. hr = pRtpSession->ModifySessionMask(
  1263. (m_Direction == TD_RENDER) ? RTPMASK_QOSRECV_EVENTS : RTPMASK_QOSSEND_EVENTS,
  1264. dwQOSEventMask,
  1265. 1,
  1266. &dwEnabledMask
  1267. );
  1268. if (FAILED(hr))
  1269. {
  1270. LOG((MSP_ERROR, "%s, modify qos event mask failed. %x", __fxName, hr));
  1271. return hr;
  1272. }
  1273. return hr;
  1274. }
  1275. HRESULT CIPConfMSPStream::EnableEncryption(
  1276. IN IRtpSession * pRtpSession,
  1277. IN WCHAR *pPassPhrase
  1278. )
  1279. /*++
  1280. Routine Description:
  1281. Enable RTP encryption.
  1282. Arguments:
  1283. pRtpSession - The RTP sesion pointer.
  1284. pPassPhrase - the pass phrase to generate the key.
  1285. Return Value:
  1286. HRESULT.
  1287. --*/
  1288. {
  1289. ENTER_FUNCTION("CIPConfMSPStream::EnableEncryption");
  1290. LOG((MSP_TRACE, "%s entered for %ws", __fxName, m_szName));
  1291. // enable RTP payload encryption.
  1292. HRESULT hr = pRtpSession->SetEncryptionMode(
  1293. RTPCRYPTMODE_RTP,
  1294. RTPCRYPT_SAMEKEY
  1295. );
  1296. if (FAILED(hr))
  1297. {
  1298. LOG((MSP_ERROR, "%s, SetEncryptionMode failed. %x", __fxName, hr));
  1299. return hr;
  1300. }
  1301. // set the key
  1302. hr = pRtpSession->SetEncryptionKey(
  1303. pPassPhrase,
  1304. NULL, // default hash algorithm, MD5
  1305. NULL, // default encrypt algorithm, DES
  1306. FALSE // RTCP?
  1307. );
  1308. if (FAILED(hr))
  1309. {
  1310. LOG((MSP_ERROR, "%s, SetEncryptionKey. %x", __fxName, hr));
  1311. return hr;
  1312. }
  1313. return hr;
  1314. }
  1315. HRESULT CIPConfMSPStream::ConfigureRTPFilter(
  1316. IN IBaseFilter * pIBaseFilter
  1317. )
  1318. /*++
  1319. Routine Description:
  1320. Configure the source RTP filter. Including set the address, port, TTL,
  1321. QOS, thread priority, clcokrate, etc.
  1322. Arguments:
  1323. pIBaseFilter - The RTP Filter.
  1324. Return Value:
  1325. HRESULT.
  1326. --*/
  1327. {
  1328. ENTER_FUNCTION("CIPConfMSPStream::ConfigureRTPFilter");
  1329. LOG((MSP_TRACE, "%s entered for %ws", __fxName, m_szName));
  1330. _ASSERT (m_pIRTPSession == NULL);
  1331. // get the session interface pointer.
  1332. HRESULT hr = pIBaseFilter->QueryInterface(&m_pIRTPSession);
  1333. if (FAILED(hr))
  1334. {
  1335. LOG((MSP_ERROR, "%s, query IRtpSession failed. hr=%x", __fxName, hr));
  1336. return hr;
  1337. }
  1338. // Initialize the RTP session.
  1339. DWORD dwFlags;
  1340. switch(m_dwMediaType)
  1341. {
  1342. case TAPIMEDIATYPE_AUDIO:
  1343. dwFlags = RTPINIT_CLASS_AUDIO;
  1344. break;
  1345. case TAPIMEDIATYPE_VIDEO:
  1346. dwFlags = RTPINIT_CLASS_VIDEO;
  1347. break;
  1348. default:
  1349. dwFlags = RTPINIT_CLASS_DEFAULT;
  1350. }
  1351. dwFlags |= RTPINIT_ENABLE_QOS;
  1352. hr = m_pIRTPSession->Init(m_Settings.phRTPSession, dwFlags);
  1353. if (FAILED(hr))
  1354. {
  1355. LOG((MSP_ERROR, "%s, Init RTP session failed. hr=%x", __fxName, hr));
  1356. return hr;
  1357. }
  1358. // set the RTP/RTCP ports.
  1359. hr = m_pIRTPSession->SetPorts(
  1360. htons(m_Settings.wRTPPortRemote), // local RTP port.
  1361. htons(m_Settings.wRTPPortRemote), // remote RTP port.
  1362. htons(m_Settings.wRTPPortRemote + 1), // local RTCP port.
  1363. htons(m_Settings.wRTPPortRemote + 1) // remote RTCP port.
  1364. );
  1365. if (FAILED(hr))
  1366. {
  1367. LOG((MSP_ERROR, "%s, Set ports failed. hr=%x", __fxName, hr));
  1368. return hr;
  1369. }
  1370. // set the destination address.
  1371. hr = m_pIRTPSession->SetAddress(
  1372. htonl(m_Settings.dwIPLocal), // local IP.
  1373. htonl(m_Settings.dwIPRemote) // remote IP.
  1374. );
  1375. if (FAILED(hr))
  1376. {
  1377. LOG((MSP_ERROR, "%s, Set Address failed. hr=%x", __fxName, hr));
  1378. return hr;
  1379. }
  1380. // Set the TTL used in the filter.
  1381. if (FAILED(hr = m_pIRTPSession->SetScope(m_Settings.dwTTL, 3)))
  1382. {
  1383. LOG((MSP_ERROR, "%s, SetScope failed. %x", __fxName, hr));
  1384. return hr;
  1385. }
  1386. // Set the loopback mode used in the filter.
  1387. DWORD dwRTPLoopbackMode;
  1388. switch (m_Settings.LoopbackMode)
  1389. {
  1390. case MM_NO_LOOPBACK:
  1391. dwRTPLoopbackMode = RTPMCAST_LOOPBACKMODE_NONE;
  1392. break;
  1393. case MM_FULL_LOOPBACK:
  1394. dwRTPLoopbackMode = RTPMCAST_LOOPBACKMODE_FULL;
  1395. break;
  1396. case MM_SELECTIVE_LOOPBACK:
  1397. dwRTPLoopbackMode = RTPMCAST_LOOPBACKMODE_PARTIAL;
  1398. break;
  1399. default:
  1400. dwRTPLoopbackMode = RTPMCAST_LOOPBACKMODE_NONE;
  1401. break;
  1402. }
  1403. if (FAILED(hr = m_pIRTPSession->SetMcastLoopback(dwRTPLoopbackMode, 0)))
  1404. {
  1405. LOG((MSP_ERROR, "set loopback mode failed. %x", hr));
  1406. return hr;
  1407. }
  1408. // enable participant events
  1409. if (FAILED(hr = EnableParticipantEvents(m_pIRTPSession)))
  1410. {
  1411. LOG((MSP_ERROR, "%s, EnableParticipantEvents failed. %x", __fxName, hr));
  1412. return hr;
  1413. }
  1414. // Enable QOS.
  1415. if (m_Settings.dwQOSLevel != QSL_BEST_EFFORT)
  1416. {
  1417. if (FAILED(hr = EnableQOS(m_pIRTPSession)))
  1418. {
  1419. LOG((MSP_ERROR, "%s, EnableQOS failed. %x", __fxName, hr));
  1420. return hr;
  1421. }
  1422. }
  1423. // Enable Encryption.
  1424. if (m_szKey)
  1425. {
  1426. if (FAILED(hr = EnableEncryption(m_pIRTPSession, m_szKey)))
  1427. {
  1428. LOG((MSP_ERROR, "%s, EnableEncryption failed. %x", __fxName, hr));
  1429. return hr;
  1430. }
  1431. }
  1432. // Set local SDES info
  1433. if (FAILED(hr = SetLocalInfoOnRTPFilter(NULL)))
  1434. {
  1435. LOG((MSP_ERROR, "%s, SetLocalInfoOnRTPFilter failed. %x", __fxName, hr));
  1436. return hr;
  1437. }
  1438. return S_OK;
  1439. }
  1440. HRESULT CIPConfMSPStream::ProcessNewParticipant(
  1441. IN int index,
  1442. IN DWORD dwSSRC,
  1443. IN DWORD dwSendRecv,
  1444. IN WCHAR * szCName,
  1445. OUT ITParticipant ** ppITParticipant
  1446. )
  1447. {
  1448. if (!m_Participants.HasSpace())
  1449. {
  1450. if (!m_Participants.Grow())
  1451. {
  1452. LOG((MSP_ERROR, "Out of mem for participant list"));
  1453. return E_OUTOFMEMORY;
  1454. }
  1455. }
  1456. // create a new participant if it is not in the list.
  1457. HRESULT hr = ((CIPConfMSPCall *)m_pMSPCall)->NewParticipant(
  1458. (ITStream *)this,
  1459. dwSSRC,
  1460. dwSendRecv,
  1461. m_dwMediaType,
  1462. szCName,
  1463. ppITParticipant
  1464. );
  1465. if (FAILED(hr))
  1466. {
  1467. LOG((MSP_ERROR, "new participant returns %x", hr));
  1468. return hr;
  1469. }
  1470. // insert the new participant at the index where the search
  1471. // stopped. The list is ordered by CName. We know the list has
  1472. // space, this function will not fail.
  1473. m_Participants.InsertAt(index, *ppITParticipant);
  1474. LOG((MSP_INFO, "%ws new participant %s", m_szName, szCName));
  1475. (*ppITParticipant)->AddRef();
  1476. return S_OK;
  1477. }
  1478. HRESULT CIPConfMSPStream::ProcessSDESUpdate(
  1479. IN DWORD dwInfoItem,
  1480. IN DWORD dwSSRC
  1481. )
  1482. /*++
  1483. Routine Description:
  1484. Process SDES info updates, create a participant if necessary. If a new
  1485. participant is created, a new participant event will be fired. If the
  1486. participant already exists, the new report is compared with the current
  1487. information, if anything changes, a info change event will be fired.
  1488. Arguments:
  1489. dwInfoItem - the info type. of this participant.
  1490. dwSSRC - the SSRC of this participant.
  1491. dwSendRecv - a sender report or a receiver report.
  1492. Return Value:
  1493. HRESULT.
  1494. --*/
  1495. {
  1496. ENTER_FUNCTION("CIPConfMSPStream::ProcessSDESUpdate");
  1497. LOG((MSP_TRACE, "%s entered for %ws, SSRC:%x", __fxName, m_szName, dwSSRC));
  1498. if (dwInfoItem < RTPSDES_CNAME || RTPSDES_CNAME > RTPSDES_PRIV)
  1499. {
  1500. return E_INVALIDARG;
  1501. }
  1502. CLock Lock(m_lock);
  1503. if (m_pMSPCall == NULL)
  1504. {
  1505. LOG((MSP_WARN, "The call has shut down the stream."));
  1506. return S_OK;
  1507. }
  1508. if (m_pIRTPSession == NULL)
  1509. {
  1510. LOG((MSP_ERROR, "ProcessSDESUpdate RTP filter is NULL"));
  1511. return E_UNEXPECTED;
  1512. }
  1513. // first get the CName of the participant.
  1514. WCHAR Buffer[MAX_PARTICIPANT_TYPED_INFO_LENGTH + 1];
  1515. DWORD dwLen = MAX_PARTICIPANT_TYPED_INFO_LENGTH;
  1516. HRESULT hr = m_pIRTPSession->GetSdesInfo(
  1517. RTPSDES_CNAME,
  1518. Buffer,
  1519. &dwLen,
  1520. dwSSRC
  1521. );
  1522. if (FAILED(hr) || dwLen == 0)
  1523. {
  1524. LOG((MSP_ERROR, "can't get CName for ssrc:%x. %x", dwSSRC, hr));
  1525. return hr;
  1526. }
  1527. ITParticipant * pITParticipant;
  1528. BOOL fChanged = FALSE;
  1529. BOOL fNewParticipant = FALSE;
  1530. CParticipant * pParticipant;
  1531. // find out if the participant is in our list.
  1532. int index;
  1533. if (m_Participants.FindByCName(Buffer, &index))
  1534. {
  1535. pITParticipant = m_Participants[index];
  1536. // addref to keep it after unlock;
  1537. pITParticipant->AddRef();
  1538. pParticipant = (CParticipant *)pITParticipant;
  1539. }
  1540. else
  1541. {
  1542. hr = ProcessNewParticipant(
  1543. index,
  1544. dwSSRC,
  1545. PART_RECV,
  1546. Buffer,
  1547. &pITParticipant
  1548. );
  1549. if (FAILED(hr))
  1550. {
  1551. LOG((MSP_ERROR, "new participant returns %x", hr));
  1552. return hr;
  1553. }
  1554. pParticipant = (CParticipant *)pITParticipant;
  1555. // There might be things the stream needs to do with the new participant
  1556. NewParticipantPostProcess(dwSSRC, pITParticipant);
  1557. // a new stream is added into the participant's list
  1558. // fire a info changed event.
  1559. fChanged = TRUE;
  1560. fNewParticipant = TRUE;
  1561. }
  1562. // update the information of the participant.
  1563. // just in case the SSRC changed.
  1564. pParticipant->UpdateSSRC(
  1565. (ITStream *)this,
  1566. dwSSRC,
  1567. PART_RECV
  1568. );
  1569. if (dwInfoItem > RTPSDES_CNAME && dwInfoItem < RTPSDES_ANY)
  1570. {
  1571. dwLen = MAX_PARTICIPANT_TYPED_INFO_LENGTH;
  1572. hr = m_pIRTPSession->GetSdesInfo(
  1573. dwInfoItem,
  1574. Buffer,
  1575. &dwLen,
  1576. dwSSRC
  1577. );
  1578. if (FAILED(hr))
  1579. {
  1580. LOG((MSP_ERROR, "can't get sdes data for ssrc:%x. %x", dwSSRC, hr));
  1581. return hr;
  1582. }
  1583. fChanged = fChanged || pParticipant->UpdateInfo(
  1584. dwInfoItem,
  1585. dwLen,
  1586. Buffer
  1587. );
  1588. }
  1589. if(fChanged)
  1590. {
  1591. ((CIPConfMSPCall *)m_pMSPCall)->
  1592. SendParticipantEvent(PE_INFO_CHANGE, pITParticipant);
  1593. }
  1594. if (fNewParticipant &&
  1595. (m_dwMediaType & TAPIMEDIATYPE_VIDEO))
  1596. {
  1597. // check if participant is talking
  1598. DWORD dwState = 0;
  1599. hr = m_pIRTPSession->GetParticipantState(dwSSRC, &dwState);
  1600. if (FAILED(hr))
  1601. {
  1602. LOG((MSP_ERROR, "Get participant state. %x", hr));
  1603. }
  1604. else
  1605. {
  1606. if (dwState == (DWORD)RTPPARINFO_TALKING)
  1607. {
  1608. // was talking
  1609. ProcessTalkingEvent(dwSSRC);
  1610. }
  1611. }
  1612. }
  1613. pITParticipant->Release();
  1614. return S_OK;
  1615. }
  1616. HRESULT CIPConfMSPStream::ProcessParticipantLeave(
  1617. IN DWORD dwSSRC
  1618. )
  1619. /*++
  1620. Routine Description:
  1621. When participant left the session, remove the stream from the participant
  1622. object's list of streams. If all streams are removed, remove the
  1623. participant from the call object's list too.
  1624. Arguments:
  1625. dwSSRC - the SSRC of the participant left.
  1626. Return Value:
  1627. HRESULT.
  1628. --*/
  1629. {
  1630. return E_NOTIMPL;
  1631. #if 0
  1632. LOG((MSP_TRACE, "ProcessParticipantLeave, SSRC: %x", dwSSRC));
  1633. m_lock.Lock();
  1634. CParticipant *pParticipant;
  1635. BOOL fLast = FALSE;
  1636. HRESULT hr = E_FAIL;
  1637. // first try to find the SSRC in our participant list.
  1638. for (int i = 0; i < m_Participants.GetSize(); i ++)
  1639. {
  1640. pParticipant = (CParticipant *)m_Participants[i];
  1641. hr = pParticipant->RemoveStream(
  1642. (ITStream *)this,
  1643. dwSSRC,
  1644. &fLast
  1645. );
  1646. if (SUCCEEDED(hr))
  1647. {
  1648. break;
  1649. }
  1650. }
  1651. // if the participant is not found
  1652. if (FAILED(hr))
  1653. {
  1654. LOG((MSP_TRACE, "SSRC:%x had been removed.", dwSSRC));
  1655. m_lock.Unlock();
  1656. return hr;
  1657. }
  1658. ITParticipant *pITParticipant = m_Participants[i];
  1659. m_Participants.RemoveAt(i);
  1660. // if this stream is the last stream that the participant is on,
  1661. // tell the call object to remove it from its list.
  1662. if (fLast)
  1663. {
  1664. ((CIPConfMSPCall *)m_pMSPCall)->ParticipantLeft(pITParticipant);
  1665. }
  1666. m_lock.Unlock();
  1667. pITParticipant->Release();
  1668. return S_OK;
  1669. #endif
  1670. }
  1671. HRESULT CIPConfMSPStream::ProcessParticipantTimeOutOrRecovered(
  1672. IN BOOL fTimeOutOrRecovered,
  1673. IN DWORD dwSSRC
  1674. )
  1675. /*++
  1676. Routine Description:
  1677. When RTP detects a timeout for a certain participant, the msp needs to
  1678. notify the app about it.
  1679. Arguments:
  1680. dwSSRC - the SSRC of the participant that times out.
  1681. Return Value:
  1682. HRESULT.
  1683. --*/
  1684. {
  1685. LOG((MSP_TRACE, "ProcessParticipantTimeOutOrRecovered, SSRC: %x", dwSSRC));
  1686. ITParticipant *pITParticipant = NULL;
  1687. CLock Lock(m_lock);
  1688. // find the SSRC in our participant list.
  1689. for (int i = 0; i < m_Participants.GetSize(); i ++)
  1690. {
  1691. if (((CParticipant *)m_Participants[i])->
  1692. HasSSRC((ITStream *)this, dwSSRC))
  1693. {
  1694. pITParticipant = m_Participants[i];
  1695. pITParticipant->AddRef();
  1696. break;
  1697. }
  1698. }
  1699. // if the participant is not found
  1700. if (pITParticipant == NULL)
  1701. {
  1702. LOG((MSP_ERROR, "can't find the SSRC", dwSSRC));
  1703. return S_OK;
  1704. }
  1705. // get stream state
  1706. HRESULT hr;
  1707. DWORD prevState;
  1708. if (FAILED (hr = ((CParticipant *)m_Participants[i])->GetStreamState (
  1709. (ITStream *)this, &prevState)))
  1710. {
  1711. LOG ((MSP_ERROR, "failed to get stream state. %x", hr));
  1712. pITParticipant->Release ();
  1713. return S_OK;
  1714. }
  1715. // check if we need to change state
  1716. if (prevState & (fTimeOutOrRecovered ? PESTREAM_TIMEOUT : PESTREAM_RECOVER))
  1717. {
  1718. pITParticipant->Release ();
  1719. return S_OK;
  1720. }
  1721. // set stream state
  1722. hr = ((CParticipant *)m_Participants[i])->SetStreamState (
  1723. (ITStream *)this,
  1724. fTimeOutOrRecovered ? PESTREAM_TIMEOUT : PESTREAM_RECOVER);
  1725. if (FAILED (hr))
  1726. {
  1727. LOG ((MSP_ERROR, "failed to set stream state, %x", hr));
  1728. pITParticipant->Release ();
  1729. return S_OK;
  1730. }
  1731. // check if we need to report to app
  1732. INT iStreamCount = ((CParticipant *)m_Participants[i])->GetStreamCount (PART_SEND);
  1733. INT iTimeOutCount = ((CParticipant *)m_Participants[i])->GetStreamTimeOutCount (PART_SEND);
  1734. if ((fTimeOutOrRecovered && (iStreamCount == iTimeOutCount)) || // fire timeout event
  1735. (!fTimeOutOrRecovered && (iStreamCount == iTimeOutCount + 1))) // fire recover event
  1736. {
  1737. ((CIPConfMSPCall *)m_pMSPCall)->
  1738. SendParticipantEvent(
  1739. fTimeOutOrRecovered ? PE_PARTICIPANT_TIMEOUT : PE_PARTICIPANT_RECOVERED,
  1740. pITParticipant
  1741. );
  1742. }
  1743. pITParticipant->Release();
  1744. return S_OK;
  1745. }
  1746. HRESULT CIPConfMSPStream::NewParticipantPostProcess(
  1747. IN DWORD dwSSRC,
  1748. IN ITParticipant *pITParticipant
  1749. )
  1750. {
  1751. // This function does nothing. The derived class will do the work.
  1752. return S_OK;
  1753. }
  1754. HRESULT CIPConfMSPStream::ProcessQOSEvent(
  1755. IN long lEventCode
  1756. )
  1757. {
  1758. CLock lock(m_lock);
  1759. if (m_pMSPCall == NULL)
  1760. {
  1761. LOG((MSP_WARN, "The call has shut down the stream."));
  1762. return S_OK;
  1763. }
  1764. switch (lEventCode)
  1765. {
  1766. case RTPQOS_EVENT_NOQOS:
  1767. ((CIPConfMSPCall*)m_pMSPCall)->SendTSPMessage(
  1768. CALL_QOS_EVENT,
  1769. QE_NOQOS,
  1770. m_dwMediaType
  1771. );
  1772. break;
  1773. case RTPQOS_EVENT_RECEIVERS:
  1774. case RTPQOS_EVENT_SENDERS:
  1775. case RTPQOS_EVENT_NO_SENDERS:
  1776. case RTPQOS_EVENT_NO_RECEIVERS:
  1777. break;
  1778. case RTPQOS_EVENT_REQUEST_CONFIRMED:
  1779. break;
  1780. case RTPQOS_EVENT_ADMISSION_FAILURE:
  1781. ((CIPConfMSPCall*)m_pMSPCall)->SendTSPMessage(
  1782. CALL_QOS_EVENT,
  1783. QE_ADMISSIONFAILURE,
  1784. m_dwMediaType
  1785. );
  1786. break;
  1787. case RTPQOS_EVENT_POLICY_FAILURE:
  1788. ((CIPConfMSPCall*)m_pMSPCall)->SendTSPMessage(
  1789. CALL_QOS_EVENT,
  1790. QE_POLICYFAILURE,
  1791. m_dwMediaType
  1792. );
  1793. break;
  1794. case RTPQOS_EVENT_BAD_STYLE:
  1795. case RTPQOS_EVENT_BAD_OBJECT:
  1796. case RTPQOS_EVENT_TRAFFIC_CTRL_ERROR:
  1797. case RTPQOS_EVENT_GENERIC_ERROR:
  1798. ((CIPConfMSPCall*)m_pMSPCall)->SendTSPMessage(
  1799. CALL_QOS_EVENT,
  1800. QE_GENERICERROR,
  1801. m_dwMediaType
  1802. );
  1803. break;
  1804. case RTPQOS_EVENT_NOT_ALLOWEDTOSEND:
  1805. m_pStreamQCRelay->m_fQOSAllowedToSend = FALSE;
  1806. break;
  1807. case RTPQOS_EVENT_ALLOWEDTOSEND:
  1808. m_pStreamQCRelay->m_fQOSAllowedToSend = TRUE;
  1809. break;
  1810. }
  1811. return S_OK;
  1812. }
  1813. HRESULT CIPConfMSPStream::ProcessTalkingEvent(
  1814. IN DWORD dwSSRC
  1815. )
  1816. {
  1817. return S_OK;
  1818. }
  1819. HRESULT CIPConfMSPStream::ProcessWasTalkingEvent(
  1820. IN DWORD dwSSRC
  1821. )
  1822. {
  1823. return S_OK;
  1824. }
  1825. HRESULT CIPConfMSPStream::ProcessSilentEvent(
  1826. IN DWORD dwSSRC
  1827. )
  1828. {
  1829. return S_OK;
  1830. }
  1831. HRESULT CIPConfMSPStream::ProcessPinMappedEvent(
  1832. IN DWORD dwSSRC,
  1833. IN IPin * pIPin
  1834. )
  1835. {
  1836. return S_OK;
  1837. }
  1838. HRESULT CIPConfMSPStream::ProcessPinUnmapEvent(
  1839. IN DWORD dwSSRC,
  1840. IN IPin * pIPin
  1841. )
  1842. {
  1843. return S_OK;
  1844. }
  1845. HRESULT CIPConfMSPStream::ProcessGraphEvent(
  1846. IN long lEventCode,
  1847. IN LONG_PTR lParam1,
  1848. IN LONG_PTR lParam2
  1849. )
  1850. {
  1851. LOG((MSP_TRACE, "%ws ProcessGraphEvent %d 0x%x 0x%x", m_szName, lEventCode, lParam1, lParam2));
  1852. switch (lEventCode)
  1853. {
  1854. // These events are designed to solve the problem of mapping video
  1855. // windows to incoming streams. The app needs to know which window
  1856. // should be painted. Whenever the rtp outpin maps an SSRC to a pin to
  1857. // stream data, it sends a MAPPED event. The first parameter is the
  1858. // SSRC and the second parameter is the output pin of the demux.
  1859. // When the demux stops using a pin, it sends a UNMAPPED event.
  1860. case RTPPARINFO_EVENT_TALKING:
  1861. ProcessParticipantTimeOutOrRecovered(FALSE, (DWORD)lParam1);
  1862. ProcessTalkingEvent((DWORD)lParam1);
  1863. break;
  1864. case RTPPARINFO_EVENT_WAS_TALKING:
  1865. ProcessWasTalkingEvent((DWORD)lParam1);
  1866. break;
  1867. case RTPPARINFO_EVENT_SILENT:
  1868. ProcessSilentEvent((DWORD)lParam1);
  1869. break;
  1870. case RTPPARINFO_EVENT_MAPPED:
  1871. ProcessPinMappedEvent((DWORD)lParam1, (IPin *)lParam2);
  1872. break;
  1873. case RTPPARINFO_EVENT_UNMAPPED:
  1874. ProcessPinUnmapEvent((DWORD)lParam1, (IPin *)lParam2);
  1875. break;
  1876. case RTPPARINFO_EVENT_STALL:
  1877. ProcessParticipantTimeOutOrRecovered(TRUE, (DWORD)lParam1);
  1878. break;
  1879. case RTPPARINFO_EVENT_BYE:
  1880. case RTPPARINFO_EVENT_DEL:
  1881. // lparam1 is the SSRC
  1882. ProcessParticipantLeave((DWORD)lParam1);
  1883. break;
  1884. case EC_COMPLETE:
  1885. case EC_USERABORT:
  1886. SendStreamEvent(CALL_STREAM_INACTIVE, CALL_CAUSE_UNKNOWN);
  1887. break;
  1888. case EC_ERRORABORT:
  1889. case EC_STREAM_ERROR_STOPPED:
  1890. case EC_STREAM_ERROR_STILLPLAYING:
  1891. case EC_ERROR_STILLPLAYING:
  1892. SendStreamEvent(CALL_STREAM_FAIL, CALL_CAUSE_UNKNOWN, (HRESULT) lParam1);
  1893. break;
  1894. case RTPSDES_EVENT_CNAME:
  1895. case RTPSDES_EVENT_NAME:
  1896. case RTPSDES_EVENT_EMAIL:
  1897. case RTPSDES_EVENT_PHONE:
  1898. case RTPSDES_EVENT_LOC:
  1899. case RTPSDES_EVENT_TOOL:
  1900. case RTPSDES_EVENT_NOTE:
  1901. case RTPSDES_EVENT_PRIV:
  1902. case RTPSDES_EVENT_ANY:
  1903. ProcessSDESUpdate(lEventCode - RTPSDES_EVENTBASE, (DWORD)lParam1);
  1904. break;
  1905. case RTPQOS_EVENT_ALLOWEDTOSEND:
  1906. m_lock.Lock();
  1907. if (m_Terminals.GetSize() > 0)
  1908. {
  1909. SendStreamEvent(CALL_STREAM_ACTIVE, CALL_CAUSE_QUALITY_OF_SERVICE);
  1910. }
  1911. m_lock.Unlock();
  1912. ProcessQOSEvent (lEventCode);
  1913. break;
  1914. case RTPQOS_EVENT_NOT_ALLOWEDTOSEND:
  1915. m_lock.Lock();
  1916. if (m_Terminals.GetSize() > 0)
  1917. {
  1918. SendStreamEvent(CALL_STREAM_INACTIVE, CALL_CAUSE_QUALITY_OF_SERVICE);
  1919. }
  1920. m_lock.Unlock();
  1921. ProcessQOSEvent (lEventCode);
  1922. break;
  1923. default:
  1924. if ((lEventCode >= RTPQOS_EVENT_NOQOS)
  1925. && (lEventCode <= RTPQOS_EVENT_ALLOWEDTOSEND))
  1926. {
  1927. ProcessQOSEvent(lEventCode);
  1928. }
  1929. break;
  1930. }
  1931. LOG((MSP_TRACE, "TRACE:CIPConfMSPStream::ProcessGraphEvent - exit S_OK"));
  1932. return S_OK;
  1933. }
  1934. HRESULT CIPConfMSPStream::SetLocalInfoOnRTPFilter(
  1935. IN IBaseFilter * pRTPFilter
  1936. )
  1937. {
  1938. _ASSERT(m_pIRTPSession != NULL);
  1939. HRESULT hr = S_OK;
  1940. for (int i = 0; i < NUM_SDES_ITEMS; i ++)
  1941. {
  1942. if (m_InfoItems[i] != NULL)
  1943. {
  1944. hr = m_pIRTPSession->SetSdesInfo(
  1945. RTPSDES_CNAME + i,
  1946. m_InfoItems[i]
  1947. );
  1948. if (FAILED(hr))
  1949. {
  1950. LOG((MSP_WARN, "%ls can't set item:%s", m_szName, m_InfoItems[i]));
  1951. }
  1952. }
  1953. }
  1954. return hr;
  1955. }
  1956. HRESULT CIPConfMSPStream::EnableParticipant(
  1957. IN DWORD dwSSRC,
  1958. IN BOOL fEnable
  1959. )
  1960. {
  1961. ENTER_FUNCTION("CIPConfMSPStream::EnableParticipantEvents");
  1962. LOG((MSP_TRACE, "%s entered, ssrc:%x", __fxName, dwSSRC));
  1963. CLock Lock(m_lock);
  1964. if (m_pIRTPSession == NULL)
  1965. {
  1966. LOG((MSP_ERROR, "%s RTP filter is NULL", __fxName));
  1967. return E_UNEXPECTED;
  1968. }
  1969. HRESULT hr = m_pIRTPSession->SetMuteState(
  1970. dwSSRC,
  1971. fEnable
  1972. );
  1973. if (FAILED(hr))
  1974. {
  1975. LOG((MSP_ERROR, "%s, SetMuteState failed, hr=%x", __fxName, hr));
  1976. }
  1977. return hr;
  1978. }
  1979. HRESULT CIPConfMSPStream::GetParticipantStatus(
  1980. IN DWORD dwSSRC,
  1981. IN BOOL * pfEnable
  1982. )
  1983. {
  1984. ENTER_FUNCTION("CIPConfMSPStream::EnableParticipantEvents");
  1985. LOG((MSP_TRACE, "%s entered, ssrc:%x", __fxName, dwSSRC));
  1986. CLock Lock(m_lock);
  1987. if (m_pIRTPSession == NULL)
  1988. {
  1989. LOG((MSP_ERROR, "%s RTP filter is NULL", __fxName));
  1990. return E_UNEXPECTED;
  1991. }
  1992. HRESULT hr = m_pIRTPSession->GetMuteState(
  1993. dwSSRC,
  1994. pfEnable
  1995. );
  1996. if (FAILED(hr))
  1997. {
  1998. LOG((MSP_ERROR, "%s, SetMuteState failed, hr=%x", __fxName, hr));
  1999. }
  2000. return hr;
  2001. }
  2002. //
  2003. // ITStreamQualityControl methods.
  2004. //
  2005. STDMETHODIMP CIPConfMSPStream::GetRange(
  2006. IN StreamQualityProperty Property,
  2007. OUT long *plMin,
  2008. OUT long *plMax,
  2009. OUT long *plSteppingDelta,
  2010. OUT long *plDefault,
  2011. OUT TAPIControlFlags *plFlags
  2012. )
  2013. /*++
  2014. Routine Description:
  2015. Get the range for a quality control peroperty. Delegated to inner
  2016. stream quality control
  2017. Arguments:
  2018. Return Value:
  2019. HRESULT.
  2020. --*/
  2021. {
  2022. ENTER_FUNCTION ("CIPConfMSPStream::GetRange (StreamQualityProperty)");
  2023. CLock lock(m_lock);
  2024. if (IsBadWritePtr (plMin, sizeof (long)) ||
  2025. IsBadWritePtr (plMax, sizeof (long)) ||
  2026. IsBadWritePtr (plSteppingDelta, sizeof (long)) ||
  2027. IsBadWritePtr (plDefault, sizeof (long)) ||
  2028. IsBadWritePtr (plFlags, sizeof (TAPIControlFlags)))
  2029. {
  2030. LOG ((MSP_ERROR, "%s: bad write pointer", __fxName));
  2031. return E_POINTER;
  2032. }
  2033. *plMin = *plMax = *plSteppingDelta = *plDefault = 0;
  2034. *plFlags = TAPIControl_Flags_None;
  2035. // pointers is to be check by inner stream qc
  2036. InnerStreamQualityProperty prop;
  2037. switch (Property)
  2038. {
  2039. case StreamQuality_MaxBitrate:
  2040. prop = InnerStreamQuality_MaxBitrate;
  2041. break;
  2042. case StreamQuality_CurrBitrate:
  2043. prop = InnerStreamQuality_CurrBitrate;
  2044. break;
  2045. case StreamQuality_MinFrameInterval:
  2046. prop = InnerStreamQuality_MinFrameInterval;
  2047. break;
  2048. case StreamQuality_AvgFrameInterval:
  2049. prop = InnerStreamQuality_AvgFrameInterval;
  2050. break;
  2051. default:
  2052. LOG ((MSP_ERROR, "%s (%ws) received invalid property %d", __fxName, m_szName, Property));
  2053. return E_INVALIDARG;
  2054. }
  2055. return (GetRange (prop, plMin, plMax, plSteppingDelta, plDefault, plFlags));
  2056. }
  2057. STDMETHODIMP CIPConfMSPStream::Get(
  2058. IN StreamQualityProperty Property,
  2059. OUT long *plValue,
  2060. OUT TAPIControlFlags *plFlags
  2061. )
  2062. /*++
  2063. Routine Description:
  2064. Get the value for a quality control peroperty. Delegated to the inner quality
  2065. control.
  2066. Arguments:
  2067. Return Value:
  2068. HRESULT.
  2069. --*/
  2070. {
  2071. ENTER_FUNCTION ("CIPConfMSPStream::Get (StreamQualityProperty)");
  2072. CLock lock(m_lock);
  2073. if (IsBadWritePtr (plValue, sizeof (long)) ||
  2074. IsBadWritePtr (plFlags, sizeof (TAPIControlFlags)))
  2075. {
  2076. LOG ((MSP_ERROR, "%s: bad write pointer", __fxName));
  2077. return E_POINTER;
  2078. }
  2079. *plValue = 0;
  2080. *plFlags = TAPIControl_Flags_None;
  2081. // pointers is to be check by inner stream qc
  2082. InnerStreamQualityProperty prop;
  2083. switch (Property)
  2084. {
  2085. case StreamQuality_MaxBitrate:
  2086. prop = InnerStreamQuality_MaxBitrate;
  2087. break;
  2088. case StreamQuality_CurrBitrate:
  2089. prop = InnerStreamQuality_CurrBitrate;
  2090. break;
  2091. case StreamQuality_MinFrameInterval:
  2092. prop = InnerStreamQuality_MinFrameInterval;
  2093. break;
  2094. case StreamQuality_AvgFrameInterval:
  2095. prop = InnerStreamQuality_AvgFrameInterval;
  2096. break;
  2097. default:
  2098. LOG ((MSP_ERROR, "%s (%ws) received invalid property %d", __fxName, m_szName, Property));
  2099. return E_INVALIDARG;
  2100. }
  2101. return (Get (prop, plValue, plFlags));
  2102. }
  2103. STDMETHODIMP CIPConfMSPStream::Set(
  2104. IN StreamQualityProperty Property,
  2105. IN long lValue,
  2106. IN TAPIControlFlags lFlags
  2107. )
  2108. /*++
  2109. Routine Description:
  2110. Set the value for a quality control peroperty. Delegated to the quality
  2111. controller.
  2112. Arguments:
  2113. Return Value:
  2114. HRESULT.
  2115. --*/
  2116. {
  2117. ENTER_FUNCTION ("CIPConfMSPStream::Set (StreamQualityProperty)");
  2118. CLock lock(m_lock);
  2119. // pointers is to be check by inner stream qc
  2120. InnerStreamQualityProperty prop;
  2121. switch (Property)
  2122. {
  2123. case StreamQuality_MaxBitrate:
  2124. // request a prefered value
  2125. prop = InnerStreamQuality_PrefMaxBitrate;
  2126. break;
  2127. case StreamQuality_MinFrameInterval:
  2128. prop = InnerStreamQuality_PrefMinFrameInterval;
  2129. break;
  2130. default:
  2131. LOG ((MSP_ERROR, "%s (%ws) received invalid property %d", __fxName, m_szName, Property));
  2132. return E_NOTIMPL;
  2133. }
  2134. return (Set (prop, lValue, lFlags));
  2135. }
  2136. /*++
  2137. Routine Description:
  2138. This method is called by the create stream helper. It creates stream qc
  2139. relay, stores inner call qc in the relay if this method fails, the stream
  2140. creation should also fail.
  2141. --*/
  2142. STDMETHODIMP
  2143. CIPConfMSPStream::LinkInnerCallQC (
  2144. IN IInnerCallQualityControl *pIInnerCallQC
  2145. )
  2146. {
  2147. ENTER_FUNCTION ("CIPConfMSPStream::LinkInnerCallQC");
  2148. CLock lock(m_lock);
  2149. if (IsBadReadPtr (pIInnerCallQC, sizeof (IInnerCallQualityControl)))
  2150. {
  2151. LOG ((MSP_ERROR, "%s received bad read pointer", __fxName));
  2152. return E_POINTER;
  2153. }
  2154. // m_pStreamQCRelay is created here.
  2155. if (NULL != m_pStreamQCRelay)
  2156. {
  2157. LOG ((MSP_ERROR, "%s was called more than once", __fxName));
  2158. return E_UNEXPECTED;
  2159. }
  2160. m_pStreamQCRelay = new CStreamQualityControlRelay ();
  2161. if (NULL == m_pStreamQCRelay)
  2162. {
  2163. LOG ((MSP_ERROR, "%s failed to create qc relay", __fxName));
  2164. return E_OUTOFMEMORY;
  2165. }
  2166. // store inner call qc in stream relay
  2167. HRESULT hr = m_pStreamQCRelay->LinkInnerCallQC (pIInnerCallQC);
  2168. if (FAILED (hr))
  2169. {
  2170. LOG ((MSP_ERROR, "%s failed to call setup on qc relay. %x", __fxName, hr));
  2171. delete m_pStreamQCRelay;
  2172. return hr;
  2173. }
  2174. return S_OK;
  2175. }
  2176. /*++
  2177. Routine Description:
  2178. This method is called when the stream is shutdown. It destroys stream
  2179. quality control relay.
  2180. --*/
  2181. STDMETHODIMP
  2182. CIPConfMSPStream::UnlinkInnerCallQC (
  2183. IN BOOL fByStream
  2184. )
  2185. {
  2186. ENTER_FUNCTION ("CIPConfMSPStream::UnlinkInnerCallQC");
  2187. CLock lock(m_lock);
  2188. if (NULL == m_pStreamQCRelay)
  2189. {
  2190. LOG ((MSP_WARN, "%s: stream qc relay is null", __fxName));
  2191. return S_OK; // ignore
  2192. }
  2193. HRESULT hr;
  2194. if (!fByStream)
  2195. {
  2196. // if initiated by call
  2197. m_fAccessingQC = TRUE;
  2198. if (FAILED (hr = m_pStreamQCRelay->UnlinkInnerCallQC (NULL)))
  2199. LOG ((MSP_ERROR, "%s failed to unlink by call. %x", __fxName, hr));
  2200. m_fAccessingQC = FALSE;
  2201. }
  2202. else
  2203. {
  2204. // initiated by stream
  2205. IInnerStreamQualityControl *pIInnerStreamQC;
  2206. hr = this->_InternalQueryInterface (
  2207. __uuidof (IInnerStreamQualityControl),
  2208. (void **) &pIInnerStreamQC
  2209. );
  2210. if (FAILED (hr))
  2211. {
  2212. LOG ((MSP_ERROR, "%s failed to query inner stream qc interface, %d", __fxName, hr));
  2213. return hr;
  2214. }
  2215. m_fAccessingQC = TRUE;
  2216. if (FAILED (hr = m_pStreamQCRelay->UnlinkInnerCallQC (pIInnerStreamQC)))
  2217. LOG ((MSP_ERROR, "%s failed to unlink by stream. %x", __fxName, hr));
  2218. m_fAccessingQC = FALSE;
  2219. pIInnerStreamQC->Release ();
  2220. }
  2221. delete m_pStreamQCRelay;
  2222. m_pStreamQCRelay = NULL;
  2223. return hr;
  2224. }
  2225. /*++
  2226. Routine Description:
  2227. This method is implemented by each specific stream class
  2228. --*/
  2229. STDMETHODIMP
  2230. CIPConfMSPStream::GetRange (
  2231. IN InnerStreamQualityProperty property,
  2232. OUT LONG *plMin,
  2233. OUT LONG *plMax,
  2234. OUT LONG *plSteppingDelta,
  2235. OUT LONG *plDefault,
  2236. OUT TAPIControlFlags *plFlags
  2237. )
  2238. {
  2239. return E_NOTIMPL;
  2240. }
  2241. /*++
  2242. Routine Description:
  2243. This method is implemented by each specific stream class
  2244. --*/
  2245. STDMETHODIMP
  2246. CIPConfMSPStream::Get(
  2247. IN InnerStreamQualityProperty property,
  2248. OUT LONG *plValue,
  2249. OUT TAPIControlFlags *plFlags
  2250. )
  2251. {
  2252. if (m_pStreamQCRelay)
  2253. return m_pStreamQCRelay->Get (property, plValue, plFlags);
  2254. return E_NOTIMPL;
  2255. }
  2256. /*++
  2257. Routine Description:
  2258. This method is implemented by each specific stream class
  2259. --*/
  2260. STDMETHODIMP
  2261. CIPConfMSPStream::Set(
  2262. IN InnerStreamQualityProperty property,
  2263. IN LONG lValue,
  2264. IN TAPIControlFlags lFlags
  2265. )
  2266. {
  2267. if (m_pStreamQCRelay)
  2268. return m_pStreamQCRelay->Set (property, lValue, lFlags);
  2269. return E_NOTIMPL;
  2270. }