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.

1259 lines
28 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. H323strm.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. #include "rtp.h" // for RTP events.
  14. /* State Transition Table
  15. States:
  16. RO - Running whithout terminal. This is the initial state.
  17. PO - Paused without terminal
  18. SO - Stopped without terminal.
  19. RT - Runing with terminal.
  20. PT - Paused with termianl.
  21. ST - Stopped with terminal.
  22. Actions:
  23. S - Stop graph.
  24. P - Pause graph.
  25. C - Change graph.
  26. D - Disonnect terminals.
  27. F - Free extra references to filters and terminals.
  28. R - Run Graph.
  29. NIU - Not in use.
  30. Note: the same graph operation can be called multiple times, the graph
  31. just returns S_OK if it is already in desired state.
  32. NOTE: if the stream is not configured, the transition will happen without
  33. really doing anything to the graph.
  34. CONFIG will only be called for NC streams.
  35. CONFIG Select Unselect Run Pause Stop ShutDown
  36. RO OK C/R FAIL OK OK OK F
  37. RO RT RO RO PO SO -
  38. PO OK C/P FAIL OK OK OK F
  39. PO PT PO RO PO SO -
  40. SO OK C FAIL OK OK OK F
  41. SO ST SO RO PO SO -
  42. RT C/R S/C/R S/C/(R) R P S S/D/F
  43. RT RT RT,RO RT PT ST -
  44. PT C/P S/C/P S/C/(P) R P S S/D/F
  45. PT PT PT,PO RT PT ST -
  46. ST C C C R P S D/F
  47. ST ST ST,SO RT PT ST -
  48. */
  49. CH323MSPStream::CH323MSPStream()
  50. : CMSPStream(),
  51. m_szName(NULL),
  52. m_pClsidPHFilter(NULL),
  53. m_pClsidCodecFilter(NULL),
  54. m_pRPHInputMinorType(NULL),
  55. m_fNeedsToOpenChannel(FALSE),
  56. m_fIsConfigured(FALSE),
  57. m_pEdgeFilter(NULL),
  58. m_htChannel(NULL)
  59. {
  60. // The default state is always running.
  61. m_dwState = STRM_RUNNING;
  62. ZeroMemory(&m_Settings, sizeof m_Settings);
  63. }
  64. #ifdef DEBUG_REFCOUNT
  65. LONG g_lStreamObjects = 0;
  66. ULONG CH323MSPStream::InternalAddRef()
  67. {
  68. InterlockedIncrement(&g_lStreamObjects);
  69. ULONG lRef = CMSPStream::InternalAddRef();
  70. LOG((MSP_TRACE, "%ws Addref, ref = %d", m_szName, lRef));
  71. return lRef;
  72. }
  73. ULONG CH323MSPStream::InternalRelease()
  74. {
  75. InterlockedDecrement(&g_lStreamObjects);
  76. ULONG lRef = CMSPStream::InternalRelease();
  77. LOG((MSP_TRACE, "%ws Release, ref = %d", m_szName, lRef));
  78. return lRef;
  79. }
  80. #endif
  81. HANDLE CH323MSPStream::TSPChannel()
  82. {
  83. CLock lock(m_lock);
  84. return m_htChannel;
  85. }
  86. BOOL CH323MSPStream::IsTerminalSelected()
  87. {
  88. CLock lock(m_lock);
  89. return m_Terminals.GetSize() > 0;
  90. }
  91. BOOL CH323MSPStream::IsConfigured()
  92. {
  93. CLock lock(m_lock);
  94. return m_fIsConfigured;
  95. }
  96. VOID CH323MSPStream::CallConnect()
  97. {
  98. CLock lock(m_lock);
  99. m_fNeedsToOpenChannel = TRUE;
  100. }
  101. STDMETHODIMP CH323MSPStream::get_Name(
  102. OUT BSTR * ppName
  103. )
  104. /*++
  105. Routine Description:
  106. Get the name of this stream.
  107. Arguments:
  108. ppName - the mem address to store a BSTR.
  109. Return Value:
  110. HRESULT.
  111. */
  112. {
  113. LOG((MSP_TRACE, "CIPH323MSPStream::get_Name - enter"));
  114. if (IsBadWritePtr(ppName, sizeof(BSTR)))
  115. {
  116. LOG((MSP_ERROR, "CMSPStream::get_Name - exit E_POINTER"));
  117. return E_POINTER;
  118. }
  119. DWORD dwID;
  120. if (m_dwMediaType == TAPIMEDIATYPE_AUDIO)
  121. {
  122. if (m_Direction == TD_CAPTURE)
  123. {
  124. dwID = IDS_AUDIO_CAPTURE_STREAM;
  125. }
  126. else
  127. {
  128. dwID = IDS_AUDIO_RENDER_STREAM;
  129. }
  130. }
  131. else
  132. {
  133. if (m_Direction == TD_CAPTURE)
  134. {
  135. dwID = IDS_VIDEO_CAPTURE_STREAM;
  136. }
  137. else
  138. {
  139. dwID = IDS_VIDEO_RENDER_STREAM;
  140. }
  141. }
  142. const int BUFSIZE = 1024;
  143. WCHAR wszName[BUFSIZE];
  144. if (LoadStringW(
  145. _Module.GetModuleInstance(),
  146. dwID,
  147. wszName,
  148. BUFSIZE - 1 ) == 0)
  149. {
  150. *ppName = NULL;
  151. LOG((MSP_ERROR, "CMSPStream::get_Name - "
  152. "LoadString failed - returning E_UNEXPECTED"));
  153. return E_UNEXPECTED;
  154. }
  155. //
  156. // Convert to a BSTR and return the BSTR.
  157. //
  158. BSTR pName = SysAllocString(wszName);
  159. if (pName == NULL)
  160. {
  161. LOG((MSP_ERROR, "CMSPStream::get_Name - exit out of mem"));
  162. return E_OUTOFMEMORY;
  163. }
  164. *ppName = pName;
  165. return S_OK;
  166. }
  167. HRESULT CH323MSPStream::SendStreamEvent(
  168. IN MSP_CALL_EVENT Event,
  169. IN MSP_CALL_EVENT_CAUSE Cause,
  170. IN HRESULT hrError = 0,
  171. IN ITTerminal * pTerminal = NULL
  172. )
  173. /*++
  174. Routine Description:
  175. Send a stream event to the app.
  176. */
  177. {
  178. CLock lock(m_lock);
  179. if (m_pMSPCall == NULL)
  180. {
  181. LOG((MSP_WARN, "The call has shut down the stream."));
  182. return S_OK;
  183. }
  184. ITStream * pITStream;
  185. HRESULT hr = this->_InternalQueryInterface(
  186. IID_ITStream,
  187. (void **)&pITStream
  188. );
  189. if (FAILED(hr))
  190. {
  191. LOG((MSP_ERROR, "SendStreamEvent:QueryInterface failed: %x", hr));
  192. return hr;
  193. }
  194. MSPEVENTITEM* pEventItem = AllocateEventItem();
  195. if (pEventItem == NULL)
  196. {
  197. LOG((MSP_ERROR, "No memory for the TSPMSP data, size: %d", sizeof(MSPEVENTITEM)));
  198. pITStream->Release();
  199. return E_OUTOFMEMORY;
  200. }
  201. // Fill in the necessary fields for the event structure.
  202. pEventItem->MSPEventInfo.dwSize = sizeof(MSP_EVENT_INFO);
  203. pEventItem->MSPEventInfo.Event = ME_CALL_EVENT;
  204. pEventItem->MSPEventInfo.MSP_CALL_EVENT_INFO.Type = Event;
  205. pEventItem->MSPEventInfo.MSP_CALL_EVENT_INFO.Cause = Cause;
  206. // pITStream has a refcount becaust it was from QI.
  207. pEventItem->MSPEventInfo.MSP_CALL_EVENT_INFO.pStream = pITStream;
  208. // the terminal needs to be addrefed.
  209. if (pTerminal) pTerminal->AddRef();
  210. pEventItem->MSPEventInfo.MSP_CALL_EVENT_INFO.pTerminal = pTerminal;
  211. pEventItem->MSPEventInfo.MSP_CALL_EVENT_INFO.hrError= hrError;
  212. hr = m_pMSPCall->HandleStreamEvent(pEventItem);
  213. if (FAILED(hr))
  214. {
  215. LOG((MSP_ERROR, "Post event failed %x", hr));
  216. pITStream->Release();
  217. FreeEventItem(pEventItem);
  218. return hr;
  219. }
  220. return S_OK;
  221. }
  222. HRESULT CH323MSPStream::CleanUpFilters()
  223. /*++
  224. Routine Description:
  225. remove all the filters in the graph.
  226. Arguments:
  227. Return Value:
  228. HRESULT.
  229. --*/
  230. {
  231. LOG((MSP_TRACE, "CleanUpFilters for %ws %p", m_szName, this));
  232. if (m_pEdgeFilter)
  233. {
  234. m_pEdgeFilter->Release();
  235. m_pEdgeFilter = NULL;
  236. }
  237. for(;;)
  238. {
  239. // Because the enumerator is invalid after removing a filter from
  240. // the graph, we have to try to get all the filters in one shot.
  241. // If there are still more, we loop again.
  242. // Enumerate the filters in the graph.
  243. CComPtr<IEnumFilters>pEnum;
  244. HRESULT hr = m_pIGraphBuilder->EnumFilters(&pEnum);
  245. if (FAILED(hr))
  246. {
  247. LOG((MSP_ERROR, "cleanup filters, enumfilters failed: %x", hr));
  248. return hr;
  249. }
  250. const DWORD MAXFILTERS = 40;
  251. IBaseFilter * Filters[MAXFILTERS];
  252. DWORD dwFetched = 0;
  253. hr = pEnum->Next(MAXFILTERS, Filters, &dwFetched);
  254. if (FAILED(hr))
  255. {
  256. LOG((MSP_ERROR, "get next filter failed: %x", hr));
  257. return hr;
  258. }
  259. for (DWORD i = 0; i< dwFetched; i ++)
  260. {
  261. m_pIGraphBuilder->RemoveFilter(Filters[i]);
  262. Filters[i]->Release();
  263. }
  264. if (hr != S_OK)
  265. {
  266. break;
  267. }
  268. }
  269. return S_OK;
  270. }
  271. HRESULT DisableGraphClock(
  272. IGraphBuilder *pIGraphBuilder
  273. )
  274. {
  275. // Get the graph builder interface on the graph.
  276. IMediaFilter *pFilter;
  277. HRESULT hr = pIGraphBuilder->QueryInterface(
  278. IID_IMediaFilter, (void **) &pFilter);
  279. if(FAILED(hr))
  280. {
  281. LOG((MSP_ERROR, "get IFilter interface, %x", hr));
  282. return hr;
  283. }
  284. hr = pFilter->SetSyncSource(NULL);
  285. pFilter->Release();
  286. LOG((MSP_TRACE, "SetSyncSource returned, %x", hr));
  287. return hr;
  288. }
  289. HRESULT CH323MSPStream::InternalConfigure()
  290. /*++
  291. Routine Description:
  292. This method is called by the derived streams to handle the state
  293. transition needed for configure. It should be called after the
  294. stream finished configuring itself.
  295. Arguments:
  296. Return Value:
  297. HRESULT.
  298. --*/
  299. {
  300. _ASSERTE(m_fIsConfigured == TRUE);
  301. // Disable the graph clock to save us a thread. don't care the result.
  302. // DisableGraphClock(m_pIGraphBuilder);
  303. // if there is no terminal selected, just return.
  304. if (m_Terminals.GetSize() == 0)
  305. {
  306. LOG((MSP_INFO, "stream %ws %p needs terminal", m_szName, this));
  307. return S_OK;
  308. }
  309. // set up the filters and the terminals.
  310. HRESULT hr = SetUpFilters();
  311. if (FAILED(hr))
  312. {
  313. SendStreamEvent(CALL_STREAM_FAIL, CALL_CAUSE_CONNECT_FAIL, hr);
  314. LOG((MSP_ERROR, "stream %ws %p set up filters failed, %x",
  315. m_szName, this, hr));
  316. return hr;
  317. }
  318. switch (m_dwState)
  319. {
  320. case STRM_RUNNING:
  321. // start the graph.
  322. hr = CMSPStream::StartStream();
  323. if (FAILED(hr))
  324. {
  325. // if the stream failed to start, let the app now.
  326. SendStreamEvent(CALL_STREAM_FAIL, CALL_CAUSE_UNKNOWN, hr);
  327. LOG((MSP_ERROR, "stream %ws %p failed to start, %x", m_szName, this, hr));
  328. return hr;
  329. }
  330. SendStreamEvent(CALL_STREAM_ACTIVE, CALL_CAUSE_LOCAL_REQUEST);
  331. LOG((MSP_INFO, "stream %ws %p started", m_szName, this));
  332. break;
  333. case STRM_PAUSED:
  334. // pause the graph.
  335. hr = CMSPStream::PauseStream();
  336. if (FAILED(hr))
  337. {
  338. // if the stream failed to start, let the app now.
  339. SendStreamEvent(CALL_STREAM_FAIL, CALL_CAUSE_UNKNOWN, hr);
  340. LOG((MSP_ERROR, "stream %ws %p failed to start, %x", m_szName, this, hr));
  341. return hr;
  342. }
  343. LOG((MSP_INFO, "stream %ws %p paused", m_szName, this));
  344. break;
  345. case STRM_STOPPED:
  346. break;
  347. }
  348. LOG((MSP_INFO, "stream %ws %p configure exit S_OK", m_szName, this));
  349. return S_OK;
  350. }
  351. STDMETHODIMP CH323MSPStream::StartStream()
  352. /*++
  353. Routine Description:
  354. Start the stream. This is the basic state machine for all the derived
  355. streams.
  356. Arguments:
  357. Return Value:
  358. HRESULT.
  359. --*/
  360. {
  361. CLock lock(m_lock);
  362. // if there is no terminal selected
  363. if (m_Terminals.GetSize() == 0)
  364. {
  365. LOG((MSP_INFO, "stream %ws %p needs terminal", m_szName, this));
  366. // Enter Runing state. (RO)
  367. m_dwState = STRM_RUNNING;
  368. return S_OK;
  369. }
  370. if (!m_fIsConfigured)
  371. {
  372. LOG((MSP_INFO, "stream %ws %p is not configured yet", m_szName, this));
  373. // Enter Runing state. (RO, RT)
  374. m_dwState = STRM_RUNNING;
  375. return S_OK;
  376. }
  377. // Start the stream.
  378. HRESULT hr = CMSPStream::StartStream();
  379. if (FAILED(hr))
  380. {
  381. LOG((MSP_ERROR, "stream %ws %p failed to start, %x", m_szName, this, hr));
  382. return hr;
  383. }
  384. SendStreamEvent(CALL_STREAM_ACTIVE, CALL_CAUSE_LOCAL_REQUEST);
  385. LOG((MSP_INFO, "stream %ws %p started", m_szName, this));
  386. // Enter Runing state.(RT)
  387. m_dwState = STRM_RUNNING;
  388. return S_OK;
  389. }
  390. STDMETHODIMP CH323MSPStream::PauseStream()
  391. /*++
  392. Routine Description:
  393. Pause the stream. This is the basic state machine for all the derived
  394. streams.
  395. Arguments:
  396. Return Value:
  397. HRESULT.
  398. --*/
  399. {
  400. CLock lock(m_lock);
  401. // if there is no terminal selected
  402. if (m_Terminals.GetSize() == 0)
  403. {
  404. LOG((MSP_INFO, "stream %ws %p needs terminal", m_szName, this));
  405. // Enter paused state. (PO)
  406. m_dwState = STRM_PAUSED;
  407. return S_OK;
  408. }
  409. if (!m_fIsConfigured)
  410. {
  411. LOG((MSP_INFO, "stream %ws %p is not configured yet", m_szName, this));
  412. // Enter paused state. (PO, PT)
  413. m_dwState = STRM_PAUSED;
  414. return S_OK;
  415. }
  416. // Start the stream.
  417. HRESULT hr = CMSPStream::PauseStream();
  418. if (FAILED(hr))
  419. {
  420. LOG((MSP_ERROR, "stream %ws %p failed to pause, %x", m_szName, this, hr));
  421. return hr;
  422. }
  423. LOG((MSP_INFO, "stream %ws %p paused", m_szName, this));
  424. // Enter paused state.(PT)
  425. m_dwState = STRM_PAUSED;
  426. return S_OK;
  427. }
  428. STDMETHODIMP CH323MSPStream::StopStream()
  429. /*++
  430. Routine Description:
  431. Stop the stream. This is the basic state machine for all the derived
  432. streams.
  433. Arguments:
  434. Return Value:
  435. HRESULT.
  436. --*/
  437. {
  438. CLock lock(m_lock);
  439. // if there is no terminal selected
  440. if (m_Terminals.GetSize() == 0)
  441. {
  442. LOG((MSP_INFO, "stream %ws %p needs terminal", m_szName, this));
  443. // Enter stopped state. (SO)
  444. m_dwState = STRM_STOPPED;
  445. return S_OK;
  446. }
  447. if (!m_fIsConfigured)
  448. {
  449. LOG((MSP_INFO, "stream %ws %p is not configured yet", m_szName, this));
  450. // Enter stopped state. (SO, ST)
  451. m_dwState = STRM_STOPPED;
  452. return S_OK;
  453. }
  454. // Stop the graph.
  455. HRESULT hr = CMSPStream::StopStream();
  456. if (FAILED(hr))
  457. {
  458. LOG((MSP_ERROR, "stream %ws %p failed to stop, %x", m_szName, this, hr));
  459. return hr;
  460. }
  461. SendStreamEvent(CALL_STREAM_INACTIVE, CALL_CAUSE_LOCAL_REQUEST);
  462. LOG((MSP_INFO, "stream %ws %p stopped", m_szName, this));
  463. // Enter stopped state.(ST)
  464. m_dwState = STRM_STOPPED;
  465. return S_OK;
  466. }
  467. HRESULT CH323MSPStream::CheckTerminalTypeAndDirection(
  468. IN ITTerminal * pTerminal
  469. )
  470. /*++
  471. Routine Description:
  472. The implementation in this class checks to see if the terminal
  473. is th right type and direction and it only allows on terminal per
  474. stream.
  475. Arguments:
  476. pTerminal - the terminal object.
  477. */
  478. {
  479. // check the media type of this terminal.
  480. long lMediaType;
  481. HRESULT hr = pTerminal->get_MediaType(&lMediaType);
  482. if (FAILED(hr))
  483. {
  484. LOG((MSP_ERROR, "can't get terminal media type. %x", hr));
  485. return TAPI_E_INVALIDTERMINAL;
  486. }
  487. if ((DWORD)lMediaType != m_dwMediaType)
  488. {
  489. return TAPI_E_INVALIDTERMINAL;
  490. }
  491. // check the direction of this terminal.
  492. TERMINAL_DIRECTION Direction;
  493. hr = pTerminal->get_Direction(&Direction);
  494. if (FAILED(hr))
  495. {
  496. LOG((MSP_ERROR, "can't get terminal direction. %x", hr));
  497. return TAPI_E_INVALIDTERMINAL;
  498. }
  499. if (Direction != m_Direction)
  500. {
  501. return TAPI_E_INVALIDTERMINAL;
  502. }
  503. // By default, only one terminal is supported per stream.
  504. if (m_Terminals.GetSize() > 0)
  505. {
  506. return TAPI_E_MAXTERMINALS;
  507. }
  508. return S_OK;
  509. }
  510. HRESULT CH323MSPStream::SelectTerminal(
  511. IN ITTerminal * pTerminal
  512. )
  513. /*++
  514. Routine Description:
  515. Select a terminal on the stream. The stream will start itself if it
  516. was in running state. See the state transition table at the beginning
  517. of this file.
  518. Arguments:
  519. pTerminal - the terminal object.
  520. Return Value:
  521. S_OK
  522. E_POINTER
  523. E_OUTOFMEMORY
  524. TAPI_E_MAXTERMINALS
  525. TAPI_E_INVALIDTERMINAL
  526. --*/
  527. {
  528. LOG((MSP_TRACE, "CMSPStream::SelectTerminal, %p", pTerminal));
  529. //
  530. // Check parameter.
  531. //
  532. if ( IsBadReadPtr(pTerminal, sizeof(ITTerminal) ) )
  533. {
  534. LOG((MSP_ERROR, "CMSPStream::SelectTerminal - exit E_POINTER"));
  535. return E_POINTER;
  536. }
  537. CLock lock(m_lock);
  538. // validate the terminal.
  539. HRESULT hr = CheckTerminalTypeAndDirection(pTerminal);
  540. if (FAILED(hr))
  541. {
  542. LOG((MSP_ERROR, "wrong terminal. %x", hr));
  543. return hr;
  544. }
  545. // put the terminal into our list.
  546. hr = CMSPStream::SelectTerminal(pTerminal);
  547. if (FAILED(hr))
  548. {
  549. LOG((MSP_ERROR, "CMSPStream::SelectTerminal - failed, %x", hr));
  550. return hr;
  551. }
  552. // At this point, the select terminal opration succeeded. All the
  553. // failure cases are handled by sending events after this.
  554. if (!m_fIsConfigured)
  555. {
  556. LOG((MSP_INFO, "stream %ws %p is not configured yet", m_szName, this));
  557. // if the call is connected, send an open channel request if the stream
  558. // is an outgoing stream.
  559. if ((m_Direction == TD_CAPTURE) && m_fNeedsToOpenChannel)
  560. {
  561. // Send an open Channel request for outgoing channels.
  562. ((CH323MSPCall*)m_pMSPCall)->SendTSPMessage(
  563. H323MSP_OPEN_CHANNEL_REQUEST,
  564. (ITStream *)this,
  565. NULL,
  566. (m_dwMediaType == TAPIMEDIATYPE_AUDIO) ? MEDIA_AUDIO : MEDIA_VIDEO
  567. );
  568. m_fNeedsToOpenChannel = FALSE;
  569. }
  570. return S_OK;
  571. }
  572. // stop the graph before making changes.
  573. hr = CMSPStream::StopStream();
  574. if (FAILED(hr))
  575. {
  576. LOG((MSP_ERROR, "stream %ws %p failed to stop, %x", m_szName, this, hr));
  577. SendStreamEvent(CALL_STREAM_FAIL, CALL_CAUSE_UNKNOWN, hr);
  578. return S_OK;
  579. }
  580. // connect the new terminal into the graph.
  581. // this method will send events if the terminal failed.
  582. hr = ConnectTerminal(pTerminal);
  583. if (FAILED(hr))
  584. {
  585. LOG((MSP_ERROR, "stream %ws %p connect to terminal failed, %x",
  586. m_szName, this, hr));
  587. SendStreamEvent(CALL_STREAM_FAIL, CALL_CAUSE_CONNECT_FAIL, hr);
  588. return S_OK;
  589. }
  590. // after connecting the termanal, go back to the original state.
  591. switch (m_dwState)
  592. {
  593. case STRM_RUNNING:
  594. // start the stream.
  595. hr = CMSPStream::StartStream();
  596. if (FAILED(hr))
  597. {
  598. LOG((MSP_ERROR, "stream %ws %p failed, %x", m_szName, this, hr));
  599. SendStreamEvent(CALL_STREAM_FAIL, CALL_CAUSE_UNKNOWN, hr);
  600. break;
  601. }
  602. SendStreamEvent(CALL_STREAM_ACTIVE, CALL_CAUSE_LOCAL_REQUEST);
  603. LOG((MSP_INFO, "stream %ws %p started", m_szName, this));
  604. break;
  605. case STRM_PAUSED:
  606. // pause the stream.
  607. hr = CMSPStream::PauseStream();
  608. if (FAILED(hr))
  609. {
  610. LOG((MSP_ERROR, "stream %ws %p failed, %x", m_szName, this, hr));
  611. SendStreamEvent(CALL_STREAM_FAIL, CALL_CAUSE_UNKNOWN, hr);
  612. }
  613. LOG((MSP_INFO, "stream %ws %p paused", m_szName, this));
  614. break;
  615. }
  616. return S_OK;
  617. }
  618. STDMETHODIMP CH323MSPStream::UnselectTerminal(
  619. IN ITTerminal * pTerminal
  620. )
  621. /*++
  622. Routine Description:
  623. Unselect a terminal from the stream. It handles changing the graph and
  624. going back to the original state.
  625. Arguments:
  626. Return Value:
  627. S_OK
  628. E_POINTER
  629. E_OUTOFMEMORY
  630. TAPI_E_MAXTERMINALS
  631. TAPI_E_INVALIDTERMINAL
  632. --*/
  633. {
  634. LOG((MSP_TRACE,
  635. "CH323MSPStream::UnselectTerminal, pTerminal %p", pTerminal));
  636. CLock lock(m_lock);
  637. int index;
  638. if ((index = m_Terminals.Find(pTerminal)) < 0)
  639. {
  640. LOG((MSP_ERROR, "UnselectTerminal - exit TAPI_E_INVALIDTERMINAL"));
  641. return TAPI_E_INVALIDTERMINAL;
  642. }
  643. // if the stream is not configured, just remove it and return.
  644. if (!m_fIsConfigured)
  645. {
  646. if (!m_Terminals.RemoveAt(index))
  647. {
  648. LOG((MSP_ERROR, "CMSPStream::UnselectTerminal - "
  649. "exit E_UNEXPECTED"));
  650. return E_UNEXPECTED;
  651. }
  652. // release the refcount that was in our list.
  653. pTerminal->Release();
  654. LOG((MSP_INFO, "stream %ws %p is not configured yet", m_szName, this));
  655. return S_OK;
  656. }
  657. // stop the graph before making changes.
  658. HRESULT hr = CMSPStream::StopStream();
  659. if (FAILED(hr))
  660. {
  661. LOG((MSP_ERROR, "stream %ws %p failed to stop, %x", m_szName, this, hr));
  662. return hr;
  663. }
  664. SendStreamEvent(CALL_STREAM_INACTIVE, CALL_CAUSE_LOCAL_REQUEST);
  665. // disconnect the terminal from the graph.
  666. // this method will send events if the terminal failed.
  667. hr = DisconnectTerminal(pTerminal);
  668. if (FAILED(hr))
  669. {
  670. LOG((MSP_ERROR, "stream %ws %p disconnectTerminal failed, %x",
  671. m_szName, this, hr));
  672. return hr;
  673. }
  674. if (!m_Terminals.RemoveAt(index))
  675. {
  676. LOG((MSP_ERROR, "CMSPStream::UnselectTerminal - "
  677. "exit E_UNEXPECTED"));
  678. return E_UNEXPECTED;
  679. }
  680. // release the refcount that was in our list.
  681. pTerminal->Release();
  682. // if there is no terminal selected, just return and wait for terminals.
  683. if (m_Terminals.GetSize() == 0)
  684. {
  685. LOG((MSP_INFO, "stream %ws %p needs terminal", m_szName, this));
  686. return S_OK;
  687. }
  688. // At this point, the Unselect terminal opration succeeded. All the
  689. // failure cases are handled by sending events after this.
  690. // after disconnecting the termanal, go back to the original state.
  691. switch (m_dwState)
  692. {
  693. case STRM_RUNNING:
  694. // start the stream.
  695. hr = CMSPStream::StartStream();
  696. if (FAILED(hr))
  697. {
  698. // if the stream failed to start, let the app now.
  699. SendStreamEvent(CALL_STREAM_FAIL, CALL_CAUSE_UNKNOWN, hr);
  700. LOG((MSP_ERROR, "stream %ws %p failed to start, %x", m_szName, this, hr));
  701. return hr;
  702. }
  703. SendStreamEvent(CALL_STREAM_ACTIVE, CALL_CAUSE_LOCAL_REQUEST);
  704. LOG((MSP_INFO, "stream %ws %p started", m_szName, this));
  705. break;
  706. case STRM_PAUSED:
  707. // pause the stream.
  708. hr = CMSPStream::PauseStream();
  709. if (FAILED(hr))
  710. {
  711. // if the stream failed to start, let the app now.
  712. SendStreamEvent(CALL_STREAM_FAIL, CALL_CAUSE_UNKNOWN, hr);
  713. LOG((MSP_ERROR, "stream %ws %p failed to pause, %x", m_szName, this, hr));
  714. return hr;
  715. }
  716. LOG((MSP_INFO, "stream %ws %p paused", m_szName, this));
  717. break;
  718. }
  719. return S_OK;
  720. }
  721. HRESULT CH323MSPStream::ShutDown()
  722. /*++
  723. Routine Description:
  724. Shut down the stream. It release the filters and terminals.
  725. Arguments:
  726. Return Value:
  727. S_OK
  728. --*/
  729. {
  730. LOG((MSP_TRACE, "CH323MSPStream::Shutdown %ws- enter", m_szName));
  731. CLock lock(m_lock);
  732. if (m_pMSPCall)
  733. {
  734. m_pMSPCall->MSPCallRelease();
  735. m_pMSPCall = NULL;
  736. }
  737. m_fNeedsToOpenChannel = FALSE;
  738. m_htChannel = NULL;
  739. // free the extra filter reference.
  740. if (m_pEdgeFilter)
  741. {
  742. m_pEdgeFilter->Release();
  743. m_pEdgeFilter = NULL;
  744. }
  745. // If the stream is not configured, just free the terminals.
  746. if (!m_fIsConfigured)
  747. {
  748. LOG((MSP_INFO, "stream %ws %p is not configured yet", m_szName, this));
  749. for ( int i = 0; i < m_Terminals.GetSize(); i ++ )
  750. {
  751. m_Terminals[i]->Release();
  752. }
  753. m_Terminals.RemoveAll();
  754. return S_OK;
  755. }
  756. m_fIsConfigured = FALSE;
  757. // if there are terminals and configured, we need to disconnect
  758. // the terminals.
  759. if (m_Terminals.GetSize() > 0)
  760. {
  761. // Stop the graph before disconnecting the terminals.
  762. HRESULT hr = CMSPStream::StopStream();
  763. if (FAILED(hr))
  764. {
  765. LOG((MSP_ERROR,
  766. "stream %ws %p failed to stop, %x", m_szName, this, hr));
  767. return hr;
  768. }
  769. for ( int i = 0; i < m_Terminals.GetSize(); i ++ )
  770. {
  771. hr = DisconnectTerminal(m_Terminals[i]);
  772. LOG((MSP_TRACE, "Disconnect terminal returned %x", hr));
  773. m_Terminals[i]->Release();
  774. }
  775. m_Terminals.RemoveAll();
  776. }
  777. LOG((MSP_TRACE, "CH323MSPStream::Shutdown - exit S_OK"));
  778. return S_OK;
  779. }
  780. HRESULT CH323MSPStream::DisconnectTerminal(
  781. IN ITTerminal * pITTerminal
  782. )
  783. /*++
  784. Routine Description:
  785. Disconnect a terminal. It will remove its filters from the graph and
  786. also release its references to the graph.
  787. Arguments:
  788. pITTerminal - the terminal.
  789. Return Value:
  790. HRESULT.
  791. --*/
  792. {
  793. CComQIPtr<ITTerminalControl, &IID_ITTerminalControl>
  794. pTerminalControl(pITTerminal);
  795. if (pTerminalControl == NULL)
  796. {
  797. LOG((MSP_ERROR, "can't get Terminal Control interface"));
  798. return E_NOINTERFACE;
  799. }
  800. HRESULT hr = pTerminalControl->DisconnectTerminal(m_pIGraphBuilder, 0);
  801. LOG((MSP_TRACE, "terminal %p is disonnected. hr:%x", pITTerminal, hr));
  802. return hr;
  803. }
  804. HRESULT CH323MSPStream::ProcessQOSEvent(
  805. IN long lEventCode
  806. )
  807. {
  808. CLock lock(m_lock);
  809. if (m_pMSPCall == NULL)
  810. {
  811. LOG((MSP_WARN, "The call has shut down the stream."));
  812. return S_OK;
  813. }
  814. switch (lEventCode)
  815. {
  816. case DXMRTP_QOSEVENT_NOQOS:
  817. ((CH323MSPCall*)m_pMSPCall)->SendTSPMessage(
  818. H323MSP_QOS_Evnet,
  819. NULL,
  820. NULL,
  821. (m_dwMediaType == TAPIMEDIATYPE_AUDIO) ? MEDIA_AUDIO : MEDIA_VIDEO,
  822. QE_NOQOS
  823. );
  824. break;
  825. case DXMRTP_QOSEVENT_RECEIVERS:
  826. case DXMRTP_QOSEVENT_SENDERS:
  827. case DXMRTP_QOSEVENT_NO_SENDERS:
  828. case DXMRTP_QOSEVENT_NO_RECEIVERS:
  829. break;
  830. case DXMRTP_QOSEVENT_REQUEST_CONFIRMED:
  831. break;
  832. case DXMRTP_QOSEVENT_ADMISSION_FAILURE:
  833. ((CH323MSPCall*)m_pMSPCall)->SendTSPMessage(
  834. H323MSP_QOS_Evnet,
  835. NULL,
  836. m_htChannel,
  837. (m_dwMediaType == TAPIMEDIATYPE_AUDIO) ? MEDIA_AUDIO : MEDIA_VIDEO,
  838. QE_ADMISSIONFAILURE
  839. );
  840. break;
  841. case DXMRTP_QOSEVENT_POLICY_FAILURE:
  842. ((CH323MSPCall*)m_pMSPCall)->SendTSPMessage(
  843. H323MSP_QOS_Evnet,
  844. NULL,
  845. m_htChannel,
  846. (m_dwMediaType == TAPIMEDIATYPE_AUDIO) ? MEDIA_AUDIO : MEDIA_VIDEO,
  847. QE_POLICYFAILURE
  848. );
  849. break;
  850. case DXMRTP_QOSEVENT_BAD_STYLE:
  851. case DXMRTP_QOSEVENT_BAD_OBJECT:
  852. case DXMRTP_QOSEVENT_TRAFFIC_CTRL_ERROR:
  853. case DXMRTP_QOSEVENT_GENERIC_ERROR:
  854. ((CH323MSPCall*)m_pMSPCall)->SendTSPMessage(
  855. H323MSP_QOS_Evnet,
  856. NULL,
  857. m_htChannel,
  858. (m_dwMediaType == TAPIMEDIATYPE_AUDIO) ? MEDIA_AUDIO : MEDIA_VIDEO,
  859. QE_GENERICERROR
  860. );
  861. break;
  862. case DXMRTP_QOSEVENT_NOT_ALLOWEDTOSEND:
  863. SendStreamEvent(CALL_STREAM_INACTIVE, CALL_CAUSE_REMOTE_REQUEST);
  864. break;
  865. case DXMRTP_QOSEVENT_ALLOWEDTOSEND:
  866. SendStreamEvent(CALL_STREAM_ACTIVE, CALL_CAUSE_REMOTE_REQUEST);
  867. break;
  868. }
  869. return S_OK;
  870. }
  871. HRESULT CH323MSPStream::HandlePacketReceiveLoss(
  872. IN DWORD dwLossRate
  873. )
  874. {
  875. return S_OK;
  876. }
  877. HRESULT CH323MSPStream::HandlePacketTransmitLoss(
  878. IN DWORD dwLossRate
  879. )
  880. {
  881. return S_OK;
  882. }
  883. HRESULT CH323MSPStream::ProcessGraphEvent(
  884. IN long lEventCode,
  885. IN long lParam1,
  886. IN long lParam2
  887. )
  888. {
  889. LOG((MSP_TRACE, "%ws ProcessGraphEvent %d", m_szName, lEventCode));
  890. if ((lEventCode >= DXMRTP_QOSEVENTBASE + DXMRTP_QOSEVENT_NOQOS)
  891. && (lEventCode < DXMRTP_QOSEVENTBASE + DXMRTP_QOSEVENT_LAST))
  892. {
  893. ProcessQOSEvent(lEventCode - DXMRTP_QOSEVENTBASE);
  894. }
  895. else
  896. {
  897. switch (lEventCode)
  898. {
  899. case EC_COMPLETE:
  900. SendStreamEvent(CALL_STREAM_INACTIVE, CALL_CAUSE_UNKNOWN);
  901. break;
  902. case EC_USERABORT:
  903. SendStreamEvent(CALL_STREAM_INACTIVE, CALL_CAUSE_UNKNOWN);
  904. break;
  905. case EC_ERRORABORT:
  906. case EC_STREAM_ERROR_STOPPED:
  907. case EC_STREAM_ERROR_STILLPLAYING:
  908. case EC_ERROR_STILLPLAYING:
  909. SendStreamEvent(CALL_STREAM_FAIL, CALL_CAUSE_UNKNOWN, (HRESULT)lParam1);
  910. break;
  911. case DXMRTP_EVENTBASE + DXMRTP_INACTIVE_EVENT:
  912. SendStreamEvent(CALL_STREAM_INACTIVE, CALL_CAUSE_MEDIA_TIMEOUT);
  913. break;
  914. case DXMRTP_EVENTBASE + DXMRTP_ACTIVE_AGAIN_EVENT:
  915. SendStreamEvent(CALL_STREAM_ACTIVE, CALL_CAUSE_MEDIA_RECOVERED);
  916. break;
  917. // Packet loss event.
  918. case DXMRTP_EVENTBASE + DXMRTP_LOSS_RATE_LOCAL_EVENT:
  919. HandlePacketReceiveLoss((HRESULT)lParam1);
  920. break;
  921. case DXMRTP_EVENTBASE + DXMRTP_LOSS_RATE_RR_EVENT:
  922. HandlePacketTransmitLoss((HRESULT)lParam1);
  923. break;
  924. }
  925. }
  926. LOG((MSP_TRACE, "TRACE:CIPConfMSPStream::ProcessGraphEvent - exit S_OK"));
  927. return S_OK;
  928. }