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.

2444 lines
63 KiB

  1. /*++
  2. Copyright (c) 1998-1999 Microsoft Corporation
  3. Module Name:
  4. rcastrm.cpp
  5. Abstract:
  6. This module contains implementation of CRCAMSPStream.
  7. Author:
  8. Zoltan Szilagyi (zoltans) September 7, 1998
  9. --*/
  10. #include "stdafx.h"
  11. #include <initguid.h>
  12. #include <g711uids.h>
  13. #define ID_BRIDGE_PIN 0 // From rca.h
  14. ///////////////////////////////////////////////////////////////////////////////
  15. ///////////////////////////////////////////////////////////////////////////////
  16. //
  17. // Global string constants -- absolutely MUST NOT be localized!!!
  18. //
  19. // SZ_RCAFILTER identifies filter in enumeration -- very important!
  20. #define SZ_RCAFILTER L"Raw Channel Access Capture/Render"
  21. // Friendly names for the above when added to the graph -- for debugging only
  22. #define SZ_RCAFILTER_FRIENDLY_CAPTURE L"The Stream's RCA capture (on line device)"
  23. #define SZ_RCAFILTER_FRIENDLY_RENDER L"The Stream's RCA render (on line device)"
  24. // SZ_G711FILTER is to name our g711 codec filter for debugging purpose only
  25. #define SZ_G711FILTER L"G711 codec filter inserted by RCA MSP"
  26. ///////////////////////////////////////////////////////////////////////////////
  27. ///////////////////////////////////////////////////////////////////////////////
  28. //
  29. // Custom logging helper macro, usable only within this class.
  30. //
  31. #ifdef MSPLOG
  32. #define STREAM_PREFIX(x) m_Direction == TD_RENDER ? \
  33. "CRCAMSPStream(RENDER )::" x : \
  34. "CRCAMSPStream(CAPTURE)::" x
  35. #endif
  36. ///////////////////////////////////////////////////////////////////////////////
  37. ///////////////////////////////////////////////////////////////////////////////
  38. //
  39. CRCAMSPStream::CRCAMSPStream() : CMSPStream()
  40. {
  41. LOG((MSP_TRACE, STREAM_PREFIX("CRCAMSPStream entered.")));
  42. m_fTerminalConnected = FALSE;
  43. m_dwBufferSizeOnWire = 0xfeedface;
  44. m_fHaveVCHandle = FALSE;
  45. m_DesiredGraphState = State_Stopped;
  46. m_pFilter = NULL;
  47. m_pG711Filter = NULL;
  48. LOG((MSP_TRACE, STREAM_PREFIX("CRCAMSPStream exited.")));
  49. }
  50. ///////////////////////////////////////////////////////////////////////////////
  51. ///////////////////////////////////////////////////////////////////////////////
  52. //
  53. CRCAMSPStream::~CRCAMSPStream()
  54. {
  55. LOG((MSP_TRACE, STREAM_PREFIX("~CRCAMSPStream entered.")));
  56. LOG((MSP_TRACE, STREAM_PREFIX("~CRCAMSPStream exited.")));
  57. }
  58. ///////////////////////////////////////////////////////////////////////////////
  59. ///////////////////////////////////////////////////////////////////////////////
  60. //
  61. void CRCAMSPStream::FinalRelease()
  62. {
  63. LOG((MSP_TRACE, STREAM_PREFIX("FinalRelease entered.")));
  64. //
  65. // At this point we should have no terminals selected, since
  66. // Shutdown is supposed to be called before we are destructed.
  67. //
  68. _ASSERTE( 0 == m_Terminals.GetSize() );
  69. //
  70. // Clean up our filters.
  71. //
  72. if ( m_fHaveVCHandle )
  73. {
  74. _ASSERTE( m_pFilter );
  75. m_pIGraphBuilder->RemoveFilter( m_pFilter );
  76. }
  77. if ( m_pFilter )
  78. {
  79. m_pFilter->Release();
  80. m_pFilter = NULL;
  81. }
  82. if ( m_pG711Filter )
  83. {
  84. m_pIGraphBuilder->RemoveFilter( m_pG711Filter );
  85. m_pG711Filter->Release();
  86. }
  87. //
  88. // Call the base class method to clean up everything else.
  89. //
  90. CMSPStream::FinalRelease();
  91. LOG((MSP_TRACE, STREAM_PREFIX("FinalRelease exited.")));
  92. }
  93. ///////////////////////////////////////////////////////////////////////////////
  94. ///////////////////////////////////////////////////////////////////////////////
  95. //
  96. // Override to allow us to create our filter on initialization.
  97. //
  98. HRESULT CRCAMSPStream::Init(
  99. IN HANDLE hAddress,
  100. IN CMSPCallBase * pMSPCall,
  101. IN IMediaEvent * pGraph,
  102. IN DWORD dwMediaType,
  103. IN TERMINAL_DIRECTION Direction
  104. )
  105. {
  106. LOG((MSP_TRACE, STREAM_PREFIX("Init - enter")));
  107. HRESULT hr;
  108. hr = CMSPStream::Init(hAddress,
  109. pMSPCall,
  110. pGraph,
  111. dwMediaType,
  112. Direction);
  113. if ( FAILED(hr) )
  114. {
  115. LOG((MSP_ERROR, STREAM_PREFIX("Init - "
  116. "base class Init failed - exit 0x%08x"), hr));
  117. return hr;
  118. }
  119. //
  120. // Create the RCA filter.
  121. //
  122. hr = CreateRCAFilter();
  123. if ( FAILED(hr) )
  124. {
  125. LOG((MSP_ERROR, STREAM_PREFIX("Init - "
  126. "CreateRCAFilter failed - exit 0x%08x"), hr));
  127. return hr;
  128. }
  129. //
  130. // Create the g711 codec filter and add it to the graph.
  131. //
  132. // We could just wait to do this on connection, and in fact on connection
  133. // we call the same method again to reset the G711 to a known state, but we
  134. // go ahead and do this now, for a couple reasons:
  135. //
  136. // * If the G711 codec is not available on the system, we are never going
  137. // to be able to do anything useful, so we might as well fail to init
  138. // the stream, and hence fail to create the call.
  139. // * If creating the G711 codec takes a while, it will be faster to
  140. // connect the call when it's time to do so. In practice this is not
  141. // a big deal.
  142. //
  143. hr = PrepareG711Filter();
  144. if ( FAILED(hr) )
  145. {
  146. LOG((MSP_ERROR, STREAM_PREFIX("Init - "
  147. "PrepareG711Filter failed - exit 0x%08x"), hr));
  148. return hr;
  149. }
  150. LOG((MSP_TRACE, STREAM_PREFIX("Init - exit S_OK")));
  151. return S_OK;
  152. }
  153. //////////////////////////////////////////////////////////////////////////////
  154. //////////////////////////////////////////////////////////////////////////////
  155. //
  156. // If the G711 filter has not yet been created, then create the G711 filter
  157. // and add it to the graph. Otherwise, remove it from the graph and readd it
  158. // to the graph.
  159. //
  160. // (Note that all failure cases maintain the invariant that either we have
  161. // a reference to the filter and it's in the graph or we don't have a
  162. // reference to the filter and it's not in the graph.)
  163. //
  164. HRESULT CRCAMSPStream::PrepareG711Filter(void)
  165. {
  166. LOG((MSP_TRACE, STREAM_PREFIX("PrepareG711Filter - enter")));
  167. HRESULT hr;
  168. if ( m_pG711Filter == NULL )
  169. {
  170. //
  171. // Create the G711 filter.
  172. //
  173. hr = CoCreateInstance(
  174. CLSID_G711Codec,
  175. NULL,
  176. CLSCTX_INPROC_SERVER,
  177. IID_IBaseFilter,
  178. (void **) &m_pG711Filter
  179. );
  180. if ( FAILED(hr) )
  181. {
  182. LOG((MSP_ERROR, STREAM_PREFIX("PrepareG711Filter - "
  183. "failed to create G711 codec - exit 0x%08x"), hr));
  184. m_pG711Filter = NULL;
  185. return hr;
  186. }
  187. }
  188. else
  189. {
  190. //
  191. // Remove the G711 codec filter from the graph, to break any previous
  192. // connections, and simplify the connection code.
  193. //
  194. hr = m_pIGraphBuilder->RemoveFilter( m_pG711Filter );
  195. if ( FAILED(hr) )
  196. {
  197. //
  198. // This is very strange indeed. We fail to connect, and can come
  199. // back and try again next time.
  200. //
  201. // (Note that failure case maintains the invariant that either we have
  202. // a reference to the filter and it's in the graph or we don't have a
  203. // reference to the filter and it's not in the graph.)
  204. //
  205. LOG((MSP_ERROR, STREAM_PREFIX("PrepareG711Filter - "
  206. "failed to remove G711 filter from graph - 0x%08x"), hr));
  207. return hr;
  208. }
  209. }
  210. //
  211. // Add the G711 filter to the graph.
  212. //
  213. hr = m_pIGraphBuilder->AddFilter(
  214. m_pG711Filter,
  215. SZ_G711FILTER
  216. );
  217. //
  218. // The name should be unique as we always have only one of these in the
  219. // graph at a time.
  220. //
  221. _ASSERTE( hr != VFW_S_DUPLICATE_NAME );
  222. _ASSERTE( hr != VFW_E_DUPLICATE_NAME );
  223. if ( FAILED(hr) )
  224. {
  225. //
  226. // (Note that failure case maintains the invariant that either we have
  227. // a reference to the filter and it's in the graph or we don't have a
  228. // reference to the filter and it's not in the graph.)
  229. //
  230. LOG((MSP_ERROR, STREAM_PREFIX("CRCAMSPStream - "
  231. "failed to add G711 filter to graph - exit 0x%08x"), hr));
  232. m_pG711Filter->Release();
  233. m_pG711Filter = NULL;
  234. return hr;
  235. }
  236. LOG((MSP_TRACE, STREAM_PREFIX("PrepareG711Filter - exit S_OK")));
  237. return S_OK;
  238. }
  239. //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  240. // CreateRCAFilter
  241. //
  242. // Creates a filter based on the clsid.
  243. //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  244. HRESULT CRCAMSPStream::CreateRCAFilter()
  245. {
  246. LOG((MSP_TRACE, STREAM_PREFIX("CreateRCAFilter - enter")));
  247. HRESULT hr;
  248. VARIANT var;
  249. ICreateDevEnum * pCreateDevEnum = NULL;
  250. IEnumMoniker * pEnumMoniker = NULL;
  251. IMoniker * pMon = NULL;
  252. IPropertyBag * pPropBag = NULL;
  253. hr = CoCreateInstance(
  254. CLSID_SystemDeviceEnum,
  255. NULL,
  256. CLSCTX_INPROC_SERVER,
  257. IID_ICreateDevEnum,
  258. (void**)&pCreateDevEnum
  259. );
  260. if(FAILED(hr))
  261. {
  262. LOG((MSP_ERROR, STREAM_PREFIX("CreateRCAFilter - "
  263. "can't create system device enumerator - exit 0x%08x"), hr));
  264. return hr;
  265. }
  266. hr = pCreateDevEnum->CreateClassEnumerator((m_Direction == TD_RENDER) ?
  267. KSCATEGORY_CAPTURE :
  268. KSCATEGORY_RENDER,
  269. &pEnumMoniker,
  270. 0);
  271. pCreateDevEnum->Release();
  272. //
  273. // here we MUST check against S_OK explicitly rather than just success
  274. // or failure, because hr == S_FALSE means the category does not exist (so
  275. // pEnumMoniker == NULL in that case and we would AV)
  276. //
  277. if ( hr != S_OK )
  278. {
  279. LOG((MSP_ERROR, STREAM_PREFIX("CreateRCAFilter - "
  280. "can't create class enumerator - exit 0x%08x"), hr));
  281. return hr;
  282. }
  283. pEnumMoniker->Reset();
  284. while( NULL == m_pFilter )
  285. {
  286. hr = pEnumMoniker->Next(1, &pMon, NULL);
  287. if( S_OK != hr )
  288. {
  289. break;
  290. }
  291. hr = pMon->BindToStorage(0, 0, IID_IPropertyBag, (void **)&pPropBag );
  292. if(FAILED(hr))
  293. {
  294. pMon->Release();
  295. LOG((MSP_ERROR, STREAM_PREFIX("CreateRCAFilter - "
  296. "BindToStorage failed - exit 0x%08x"), hr));
  297. continue;
  298. }
  299. VariantInit(&var);
  300. V_VT(&var) = VT_BSTR;
  301. hr = pPropBag->Read(L"FriendlyName", &var, 0 );
  302. pPropBag->Release();
  303. if(FAILED(hr))
  304. {
  305. pMon->Release();
  306. continue;
  307. }
  308. if(lstrcmpiW(var.bstrVal, SZ_RCAFILTER) != 0)
  309. {
  310. pMon->Release();
  311. continue;
  312. }
  313. // Bind to selected device
  314. hr = pMon->BindToObject( 0, 0, IID_IBaseFilter, (void**)&m_pFilter );
  315. pMon->Release();
  316. }
  317. pEnumMoniker->Release();
  318. if ( ( S_OK != hr ) || ( NULL == m_pFilter ) )
  319. {
  320. LOG((MSP_ERROR, STREAM_PREFIX("CreateRCAFilter - "
  321. "didn't find the filter - exit E_FAIL")));
  322. return E_FAIL;
  323. }
  324. LOG((MSP_TRACE, STREAM_PREFIX("CreateRCAFilter - exit S_OK")));
  325. return S_OK;
  326. }
  327. ///////////////////////////////////////////////////////////////////////////////
  328. ///////////////////////////////////////////////////////////////////////////////
  329. //
  330. STDMETHODIMP CRCAMSPStream::get_Name (
  331. OUT BSTR * ppName
  332. )
  333. {
  334. LOG((MSP_TRACE, STREAM_PREFIX("get_Name - enter")));
  335. //
  336. // Check argument.
  337. //
  338. if ( IsBadWritePtr(ppName, sizeof(BSTR) ) )
  339. {
  340. LOG((MSP_TRACE, STREAM_PREFIX("get_Name - "
  341. "bad return pointer - returning E_POINTER")));
  342. return E_POINTER;
  343. }
  344. //
  345. // Decide what string to return based on which stream this is.
  346. //
  347. ULONG ulID;
  348. if ( m_Direction == TD_CAPTURE )
  349. {
  350. ulID = IDS_CAPTURE_STREAM;
  351. }
  352. else
  353. {
  354. ulID = IDS_RENDER_STREAM;
  355. }
  356. //
  357. // Get the string from the string table.
  358. //
  359. const int ciAllocSize = 2048;
  360. WCHAR wszName[ciAllocSize];
  361. int iReturn = LoadStringW( _Module.GetModuleInstance(),
  362. ulID,
  363. wszName,
  364. ciAllocSize - 1 );
  365. if ( iReturn == 0 )
  366. {
  367. _ASSERTE( FALSE );
  368. *ppName = NULL;
  369. LOG((MSP_ERROR, STREAM_PREFIX("get_Name - "
  370. "LoadString failed - returning E_UNEXPECTED")));
  371. return E_UNEXPECTED;
  372. }
  373. //
  374. // Convert to a BSTR and return the BSTR.
  375. //
  376. *ppName = SysAllocString(wszName);
  377. if ( *ppName == NULL )
  378. {
  379. LOG((MSP_ERROR, STREAM_PREFIX("get_Name - "
  380. "SysAllocString failed - returning E_OUTOFMEMORY")));
  381. return E_OUTOFMEMORY;
  382. }
  383. LOG((MSP_TRACE, STREAM_PREFIX("get_Name - exit S_OK")));
  384. return S_OK;
  385. }
  386. ///////////////////////////////////////////////////////////////////////////////
  387. ///////////////////////////////////////////////////////////////////////////////
  388. //
  389. STDMETHODIMP CRCAMSPStream::SelectTerminal(
  390. IN ITTerminal * pTerminal
  391. )
  392. {
  393. LOG((MSP_TRACE, STREAM_PREFIX("SelectTerminal - enter")));
  394. //
  395. // We are going to access the terminal list -- grab the lock
  396. //
  397. CLock lock(m_lock);
  398. //
  399. // Reject if we already have a terminal selected.
  400. //
  401. if ( 0 != m_Terminals.GetSize() )
  402. {
  403. LOG((MSP_ERROR, STREAM_PREFIX("SelectTerminal - "
  404. "exit TAPI_E_MAXTERMINALS")));
  405. return TAPI_E_MAXTERMINALS;
  406. }
  407. //
  408. // Use base class method to add it to our list of terminals.
  409. //
  410. HRESULT hr = CMSPStream::SelectTerminal(pTerminal);
  411. if ( FAILED(hr) )
  412. {
  413. LOG((MSP_ERROR, STREAM_PREFIX("SelectTerminal - "
  414. "base class method failed - exit 0x%08x"), hr));
  415. return hr;
  416. }
  417. //
  418. // Re-pause or re-start the stream if needed.
  419. //
  420. if ( m_DesiredGraphState == State_Paused )
  421. {
  422. hr = PauseStream();
  423. }
  424. else if ( m_DesiredGraphState == State_Running )
  425. {
  426. hr = StartStream();
  427. }
  428. else
  429. {
  430. _ASSERTE( m_DesiredGraphState == State_Stopped );
  431. hr = S_OK;
  432. }
  433. if ( FAILED(hr) )
  434. {
  435. LOG((MSP_TRACE, STREAM_PREFIX("SelectTerminal - "
  436. "can't regain old graph state - unselecting terminal - "
  437. "exit 0x%08x"), hr));
  438. //
  439. // Unselect it to undo all of the above.
  440. //
  441. UnselectTerminal(pTerminal);
  442. return hr;
  443. }
  444. LOG((MSP_TRACE, STREAM_PREFIX("SelectTerminal - exit S_OK")));
  445. return S_OK;
  446. }
  447. ///////////////////////////////////////////////////////////////////////////////
  448. ///////////////////////////////////////////////////////////////////////////////
  449. //
  450. STDMETHODIMP CRCAMSPStream::UnselectTerminal (
  451. IN ITTerminal * pTerminal
  452. )
  453. {
  454. LOG((MSP_TRACE, STREAM_PREFIX("UnselectTerminal - enter")));
  455. //
  456. // check the argument -- it has to be a reasonably good pointer
  457. //
  458. if (IsBadReadPtr(pTerminal, sizeof(ITTerminal)))
  459. {
  460. LOG((MSP_ERROR, STREAM_PREFIX("UnselectTerminal - "
  461. "bad terminal pointer passed in. returning E_POINTER")));
  462. return E_POINTER;
  463. }
  464. CLock lock(m_lock);
  465. //
  466. // check the argument -- it has to be in the array of terminals
  467. //
  468. if (m_Terminals.Find(pTerminal) < 0)
  469. {
  470. LOG((MSP_ERROR, STREAM_PREFIX("UnselectTerminal - "
  471. "terminal [%p] is not selected on this stream. "
  472. "returning TAPI_E_INVALIDTERMINAL"), pTerminal));
  473. return TAPI_E_INVALIDTERMINAL;
  474. }
  475. //
  476. // Add an extra reference to the terminal so it doesn't go away
  477. // after we call CMSPStream::UnselectTerminal. We need it later
  478. // in the function.
  479. //
  480. pTerminal->AddRef();
  481. //
  482. // Use base class method to remove terminal from our list of terminals.
  483. //
  484. HRESULT hr = CMSPStream::UnselectTerminal(pTerminal);
  485. if (FAILED(hr))
  486. {
  487. LOG((MSP_ERROR, STREAM_PREFIX("UnselectTerminal - "
  488. "base class method failed - exit 0x%08x"), hr));
  489. pTerminal->Release();
  490. return hr;
  491. }
  492. //
  493. // If we've been given a vc handle then we may not be stopped.
  494. // This does nothing if we are already stopped.
  495. //
  496. if ( m_fHaveVCHandle )
  497. {
  498. CMSPStream::StopStream();
  499. }
  500. //
  501. // Disconnect the terminal if this call had it connected.
  502. //
  503. if ( m_fTerminalConnected )
  504. {
  505. //
  506. // Get the ITTerminalControl interface.
  507. //
  508. ITTerminalControl * pTerminalControl;
  509. hr = pTerminal->QueryInterface(IID_ITTerminalControl,
  510. (void **) &pTerminalControl);
  511. if ( FAILED(hr) )
  512. {
  513. LOG((MSP_ERROR, STREAM_PREFIX("UnselectTerminal - "
  514. "QI for ITTerminalControl failed - exit 0x%08x"), hr));
  515. pTerminal->Release();
  516. return hr;
  517. }
  518. //
  519. // Disconnect the terminal.
  520. //
  521. hr = pTerminalControl->DisconnectTerminal(m_pIGraphBuilder, 0);
  522. pTerminalControl->Release();
  523. m_fTerminalConnected = FALSE;
  524. if ( FAILED(hr) )
  525. {
  526. LOG((MSP_ERROR, STREAM_PREFIX("UnselectTerminal - "
  527. "DisconnectTerminal failed - exit 0x%08x"), hr));
  528. pTerminal->Release();
  529. return hr;
  530. }
  531. }
  532. pTerminal->Release();
  533. LOG((MSP_TRACE, STREAM_PREFIX("UnselectTerminal - exit S_OK")));
  534. return S_OK;
  535. }
  536. ///////////////////////////////////////////////////////////////////////////////
  537. ///////////////////////////////////////////////////////////////////////////////
  538. //
  539. STDMETHODIMP CRCAMSPStream::StartStream (void)
  540. {
  541. LOG((MSP_TRACE, STREAM_PREFIX("StartStream - enter")));
  542. CLock lock(m_lock);
  543. m_DesiredGraphState = State_Running;
  544. //
  545. // Can't start the stream if we don't know the vc handle.
  546. // (We create our filters on discovery of the vc handle.)
  547. //
  548. if ( ! m_fHaveVCHandle )
  549. {
  550. LOG((MSP_WARN, STREAM_PREFIX("StartStream - "
  551. "no vc handle so nothing to do yet - exit S_OK")));
  552. return S_OK;
  553. }
  554. //
  555. // Can't start the stream if no terminal has been selected.
  556. //
  557. if ( 0 == m_Terminals.GetSize() )
  558. {
  559. LOG((MSP_WARN, STREAM_PREFIX("StartStream - "
  560. "no Terminal so nothing to do yet - exit S_OK")));
  561. return S_OK;
  562. }
  563. //
  564. // Connect the terminal. This does nothing if this call already
  565. // connected the terminal and fails if another call has the
  566. // terminal connected.
  567. //
  568. HRESULT hr;
  569. hr = ConnectTerminal(m_Terminals[0]);
  570. if ( FAILED(hr) )
  571. {
  572. FireEvent(CALL_TERMINAL_FAIL, hr, CALL_CAUSE_CONNECT_FAIL);
  573. FireEvent(CALL_STREAM_FAIL, hr, CALL_CAUSE_CONNECT_FAIL);
  574. LOG((MSP_ERROR, STREAM_PREFIX("StartStream - "
  575. "our ConnectTerminal failed - exit 0x%08x"), hr));
  576. return hr;
  577. }
  578. //
  579. // Run the stream via the base class method.
  580. //
  581. hr = CMSPStream::StartStream();
  582. if ( FAILED(hr) )
  583. {
  584. FireEvent(CALL_STREAM_FAIL, hr, CALL_CAUSE_UNKNOWN);
  585. LOG((MSP_ERROR, STREAM_PREFIX("StartStream - "
  586. "Run failed - exit 0x%08x"), hr));
  587. return hr;
  588. }
  589. HRESULT hr2 = FireEvent(CALL_STREAM_ACTIVE, hr, CALL_CAUSE_LOCAL_REQUEST);
  590. if ( FAILED(hr2) )
  591. {
  592. LOG((MSP_ERROR, STREAM_PREFIX("StartStream - "
  593. "FireEvent failed - exit 0x%08x"), hr2));
  594. return hr2;
  595. }
  596. LOG((MSP_TRACE, STREAM_PREFIX("StartStream - exit S_OK")));
  597. return S_OK;
  598. }
  599. ///////////////////////////////////////////////////////////////////////////////
  600. ///////////////////////////////////////////////////////////////////////////////
  601. //
  602. STDMETHODIMP CRCAMSPStream::PauseStream (void)
  603. {
  604. LOG((MSP_TRACE, STREAM_PREFIX("PauseStream - enter")));
  605. CLock lock(m_lock);
  606. m_DesiredGraphState = State_Paused;
  607. //
  608. // Can't pause the stream if we don't know the vc handle.
  609. // (We create our filters on discovery of the vc handle.)
  610. //
  611. if ( ! m_fHaveVCHandle )
  612. {
  613. LOG((MSP_WARN, STREAM_PREFIX("PauseStream - "
  614. "no vc handle so nothing to do yet - exit S_OK")));
  615. return S_OK;
  616. }
  617. //
  618. // Can't pause the stream if no terminal has been selected.
  619. //
  620. if ( 0 == m_Terminals.GetSize() )
  621. {
  622. LOG((MSP_WARN, STREAM_PREFIX("PauseStream - "
  623. "no Terminal so nothing to do yet - exit S_OK")));
  624. return S_OK;
  625. }
  626. //
  627. // Connect the terminal. This does nothing if this call already
  628. // connected the terminal and fails if another call has the
  629. // terminal connected.
  630. //
  631. HRESULT hr;
  632. hr = ConnectTerminal(m_Terminals[0]);
  633. if ( FAILED(hr) )
  634. {
  635. FireEvent(CALL_TERMINAL_FAIL, hr, CALL_CAUSE_CONNECT_FAIL);
  636. FireEvent(CALL_STREAM_FAIL, hr, CALL_CAUSE_CONNECT_FAIL);
  637. LOG((MSP_ERROR, STREAM_PREFIX("StartStream - "
  638. "our ConnectTerminal failed - exit 0x%08x"), hr));
  639. return hr;
  640. }
  641. //
  642. // Pause the stream via the base class method.
  643. //
  644. hr = CMSPStream::PauseStream();
  645. if ( FAILED(hr) )
  646. {
  647. FireEvent(CALL_STREAM_FAIL, hr, CALL_CAUSE_UNKNOWN);
  648. LOG((MSP_ERROR, STREAM_PREFIX("PauseStream - "
  649. "Pause failed - exit 0x%08x"), hr));
  650. return hr;
  651. }
  652. HRESULT hr2 = FireEvent(CALL_STREAM_INACTIVE, hr, CALL_CAUSE_LOCAL_REQUEST);
  653. if ( FAILED(hr2) )
  654. {
  655. LOG((MSP_ERROR, STREAM_PREFIX("PauseStream - "
  656. "FireEvent failed - exit 0x%08x"), hr2));
  657. return hr2;
  658. }
  659. LOG((MSP_TRACE, STREAM_PREFIX("PauseStream - exit S_OK")));
  660. return S_OK;
  661. }
  662. ///////////////////////////////////////////////////////////////////////////////
  663. ///////////////////////////////////////////////////////////////////////////////
  664. //
  665. STDMETHODIMP CRCAMSPStream::StopStream (void)
  666. {
  667. LOG((MSP_TRACE, STREAM_PREFIX("StopStream - enter")));
  668. CLock lock(m_lock);
  669. m_DesiredGraphState = State_Stopped;
  670. //
  671. // Nothing to do if we don't know our vc handle.
  672. //
  673. if ( ! m_fHaveVCHandle )
  674. {
  675. LOG((MSP_WARN, STREAM_PREFIX("StopStream - "
  676. "no vc handle - exit S_OK")));
  677. return S_OK;
  678. }
  679. //
  680. // Nothing to do if no terminal has been selected.
  681. //
  682. if ( 0 == m_Terminals.GetSize() )
  683. {
  684. LOG((MSP_WARN, STREAM_PREFIX("StopStream - "
  685. "no Terminal - exit S_OK")));
  686. return S_OK;
  687. }
  688. //
  689. // Stop the stream via the base class method.
  690. //
  691. HRESULT hr;
  692. hr = CMSPStream::StopStream();
  693. if ( FAILED(hr) )
  694. {
  695. FireEvent(CALL_STREAM_FAIL, hr, CALL_CAUSE_UNKNOWN);
  696. LOG((MSP_ERROR, STREAM_PREFIX("StopStream - "
  697. "Stop failed - exit 0x%08x"), hr));
  698. return hr;
  699. }
  700. HRESULT hr2 = FireEvent(CALL_STREAM_INACTIVE, hr, CALL_CAUSE_LOCAL_REQUEST);
  701. if ( FAILED(hr2) )
  702. {
  703. LOG((MSP_ERROR, STREAM_PREFIX("StopStream - "
  704. "FireEvent failed - exit 0x%08x"), hr2));
  705. return hr2;
  706. }
  707. LOG((MSP_TRACE, STREAM_PREFIX("StopStream - exit S_OK")));
  708. return S_OK;
  709. }
  710. ///////////////////////////////////////////////////////////////////////////////
  711. ///////////////////////////////////////////////////////////////////////////////
  712. //
  713. HRESULT CRCAMSPStream::SetVCHandle(DWORD dwVCHandle)
  714. {
  715. LOG((MSP_TRACE, STREAM_PREFIX("SetVCHandle - enter")));
  716. CLock lock(m_lock);
  717. HRESULT hr;
  718. //
  719. // Save VC handle in the filter
  720. //
  721. if ( (dwVCHandle == 0) || (dwVCHandle == 0xffffffff) )
  722. {
  723. LOG((MSP_ERROR, STREAM_PREFIX("SetVCHandle - "
  724. "invalid vc handle %d - exit E_INVALIDARG"), dwVCHandle));
  725. return E_INVALIDARG;
  726. }
  727. WCHAR wszFileName[10];
  728. wsprintfW(wszFileName, L"%x", dwVCHandle);
  729. hr = SetVCHandleOnPin(wszFileName,
  730. KSDATAFORMAT_SPECIFIER_VC_ID);
  731. if ( FAILED(hr) )
  732. {
  733. LOG((MSP_ERROR, STREAM_PREFIX("SetVCHandle - "
  734. "SetVCHandleOnPin failed - exit 0x%08x"), hr));
  735. return hr;
  736. }
  737. //
  738. // Add the filter. Supply a name to make debugging easier.
  739. //
  740. WCHAR * pName = (m_Direction == TD_RENDER) ?
  741. SZ_RCAFILTER_FRIENDLY_CAPTURE :
  742. SZ_RCAFILTER_FRIENDLY_RENDER ;
  743. hr = m_pIGraphBuilder->AddFilter(m_pFilter, pName);
  744. //
  745. // The name should be unique as we always have only one of these in the
  746. // graph at a time.
  747. //
  748. _ASSERTE( hr != VFW_S_DUPLICATE_NAME );
  749. _ASSERTE( hr != VFW_E_DUPLICATE_NAME );
  750. if ( FAILED(hr) )
  751. {
  752. LOG((MSP_ERROR, STREAM_PREFIX("SetVCHandle - "
  753. "AddFilter failed - exit 0x%08x"), hr));
  754. m_pFilter->Release();
  755. m_pFilter = NULL;
  756. return hr;
  757. }
  758. //
  759. // We now have the vc handle.
  760. //
  761. m_fHaveVCHandle = TRUE;
  762. LOG((MSP_TRACE, STREAM_PREFIX("SetVCHandle - exit S_OK")));
  763. return S_OK;
  764. }
  765. HRESULT
  766. CRCAMSPStream::SetVCHandleOnPin(
  767. LPWSTR pszFileName,
  768. REFGUID formattype
  769. )
  770. {
  771. LOG((MSP_TRACE, STREAM_PREFIX("SetVCHandleOnPin - enter")));
  772. HRESULT hr;
  773. IEnumPins * pEnumPins;
  774. IPin * pPin = NULL;
  775. AM_MEDIA_TYPE * pAMT;
  776. BOOL bFound = FALSE;
  777. IEnumMediaTypes* pEMT;
  778. // enumerate the pins on the filter
  779. hr = m_pFilter->EnumPins( &pEnumPins );
  780. if (!(SUCCEEDED(hr)))
  781. {
  782. LOG((MSP_ERROR, STREAM_PREFIX("SetVCHandleOnPin - "
  783. "EnumPins failed - exit 0x%08x"), hr));
  784. return hr;
  785. }
  786. // go through the pins
  787. while ( S_OK == (hr = pEnumPins->Next( 1, &pPin, NULL ) ) )
  788. {
  789. PIN_DIRECTION pd;
  790. // get the pin info
  791. hr = pPin->QueryDirection( &pd );
  792. if ( FAILED(hr) )
  793. {
  794. pPin->Release();
  795. pEnumPins->Release();
  796. LOG((MSP_ERROR, STREAM_PREFIX("SetVCHandleOnPin - "
  797. "QueryDirection failed - exit 0x%08x"), hr));
  798. return hr;
  799. }
  800. // does it meet the criteria?
  801. if ( ( ( TD_CAPTURE == m_Direction ) && (pd == PINDIR_OUTPUT) ) ||
  802. ( ( TD_RENDER == m_Direction ) && (pd == PINDIR_INPUT ) ) )
  803. {
  804. // yes
  805. hr = pPin->EnumMediaTypes(&pEMT);
  806. if ( FAILED(hr) )
  807. {
  808. pPin->Release();
  809. pEnumPins->Release();
  810. LOG((MSP_ERROR, STREAM_PREFIX("SetVCHandleOnPin - "
  811. "EnumMediaTypes failed - exit 0x%08x"), hr));
  812. return hr;
  813. }
  814. while ( S_OK == (hr = pEMT->Next(1, &pAMT, NULL) ) )
  815. {
  816. if (IsEqualGUID(formattype, pAMT->formattype))
  817. {
  818. hr = SetMediaTypeFormat(
  819. pAMT,
  820. (BYTE*)(pszFileName),
  821. (lstrlenW(pszFileName) + 1)
  822. * sizeof(WCHAR)
  823. );
  824. if ( FAILED(hr) )
  825. {
  826. LOG((MSP_ERROR, STREAM_PREFIX("SetVCHandleOnPin - "
  827. "SetMediaTypeFormat failed - exit 0x%08x"), hr));
  828. ::DeleteMediaType(pAMT);
  829. continue;
  830. }
  831. hr = pPin->Connect( NULL, pAMT );
  832. ::DeleteMediaType(pAMT);
  833. if ( FAILED(hr) )
  834. {
  835. LOG((MSP_ERROR, STREAM_PREFIX("SetVCHandleOnPin - "
  836. "Connect failed - exit 0x%08x"), hr));
  837. continue;
  838. }
  839. bFound = TRUE;
  840. LOG((MSP_TRACE, STREAM_PREFIX("SetVCHandleOnPin - "
  841. "About to call SetDataFormatOnPin\n")));
  842. hr = SetDataFormatOnPin(pPin);
  843. if ( FAILED(hr) )
  844. {
  845. LOG((MSP_ERROR, STREAM_PREFIX("SetVCHandleOnPin - "
  846. "SetDataFormatOnPin failed with hr "
  847. "== 0x%08x, don't know what to do "
  848. "now..."), hr));
  849. }
  850. hr = GetBufferSizeFromPin( pPin,
  851. & m_dwBufferSizeOnWire );
  852. if ( FAILED(hr) )
  853. {
  854. LOG((MSP_ERROR, STREAM_PREFIX("SetVCHandleOnPin - "
  855. "GetBufferSizeFromPin failed - exit 0x%08x"), hr));
  856. return hr;
  857. }
  858. break;
  859. }
  860. ::DeleteMediaType(pAMT);
  861. } //while
  862. pEMT->Release();
  863. if ( bFound )
  864. {
  865. pPin->Release();
  866. break;
  867. } // if found
  868. } // if meets criteria
  869. pPin->Release();
  870. } // while got another pin
  871. pEnumPins->Release();
  872. if ( !bFound )
  873. {
  874. // error
  875. LOG((MSP_ERROR, STREAM_PREFIX("SetVCHandleOnPin - "
  876. "Couldn't find a pin - exit E_FAIL")));
  877. return E_FAIL;
  878. }
  879. LOG((MSP_TRACE, STREAM_PREFIX("SetVCHandleOnPin - exit S_OK")));
  880. return S_OK;
  881. }
  882. ///////////////////////////////////////////////////////////////////////////////
  883. ///////////////////////////////////////////////////////////////////////////////
  884. //
  885. HRESULT
  886. CRCAMSPStream::GetBufferSizeFromPin(
  887. IN IPin * pPin,
  888. OUT DWORD * pdwSize
  889. )
  890. {
  891. LOG((MSP_TRACE, STREAM_PREFIX("GetBufferSizeFromPin - enter")));
  892. _ASSERTE( ! IsBadReadPtr (pPin, sizeof(IPin) ) );
  893. _ASSERTE( ! IsBadWritePtr(pdwsize, sizeof(DWORD) ) );
  894. //
  895. // Get the IKsPropertySet interface on the pin.
  896. //
  897. HRESULT hr;
  898. IKsPropertySet * pKsPropSet;
  899. hr = pPin->QueryInterface(IID_IKsPropertySet,
  900. (void **)&pKsPropSet);
  901. if ( FAILED(hr) )
  902. {
  903. LOG((MSP_ERROR, STREAM_PREFIX("GetBufferSizeFromPin - "
  904. "couldn't get IKsPropertySet interface - exit 0x%08x"), hr));
  905. return hr;
  906. }
  907. //
  908. // Get allocator framing info from the property set interface.
  909. // This will fail if there is more than one framing item available, as
  910. // we only pass in enough space for one framing item. That's good, as we
  911. // don't know what to do with multiple framing items.
  912. //
  913. KSP_PIN InstanceData;
  914. KSALLOCATOR_FRAMING_EX AllocFraming;
  915. DWORD dwActualSize;
  916. hr = pKsPropSet->Get(
  917. KSPROPSETID_Connection, // [in] propset guid
  918. KSPROPERTY_CONNECTION_ALLOCATORFRAMING_EX, // [in] property id in set
  919. (LPVOID) & InstanceData, // [out] instance data
  920. sizeof(KSP_PIN), // [in] buffer size of ^^^
  921. (LPVOID) & AllocFraming, // [out] value of property
  922. sizeof(KSALLOCATOR_FRAMING_EX), // [in] buffer size of ^^^
  923. & dwActualSize); // [out] actual size of ^^^
  924. pKsPropSet->Release();
  925. if ( FAILED(hr) )
  926. {
  927. LOG((MSP_ERROR, STREAM_PREFIX("GetBufferSizeFromPin - "
  928. "cannot get allocator framing property - exit 0x%08x"), hr));
  929. return hr;
  930. }
  931. //
  932. // Return the size from the property data.
  933. //
  934. _ASSERTE( dwActualSize == sizeof(KSALLOCATOR_FRAMING_EX) );
  935. _ASSERTE( AllocFraming.CountItems == 1 );
  936. KS_FRAMING_RANGE * pRange;
  937. pRange = & (AllocFraming.FramingItem[0].FramingRange.Range);
  938. _ASSERTE( pRange->MaxFrameSize == pRange->MinFrameSize );
  939. *pdwSize = pRange->MaxFrameSize;
  940. LOG((MSP_TRACE, STREAM_PREFIX("GetBufferSizeFromPin - returned size %d"
  941. " - exit S_OK"), *pdwSize));
  942. return S_OK;
  943. }
  944. ///////////////////////////////////////////////////////////////////////////////
  945. ///////////////////////////////////////////////////////////////////////////////
  946. //
  947. HRESULT
  948. CRCAMSPStream::SetDataFormatOnPin(
  949. IPin *pBridgePin
  950. )
  951. {
  952. LOG((MSP_TRACE, STREAM_PREFIX("SetDataFormatOnPin - enter")));
  953. KSDATAFORMAT_WAVEFORMATEX PCMAudioFormat =
  954. {
  955. {
  956. sizeof(KSDATAFORMAT_WAVEFORMATEX),
  957. 0,
  958. 0,
  959. 0,
  960. STATIC_KSDATAFORMAT_TYPE_AUDIO,
  961. UseMulaw() ? STATIC_KSDATAFORMAT_SUBTYPE_MULAW :
  962. STATIC_KSDATAFORMAT_SUBTYPE_ALAW,
  963. STATIC_KSDATAFORMAT_SPECIFIER_WAVEFORMATEX
  964. },
  965. {
  966. // format tag, one of _PCM, _MULAW, _ALAW
  967. UseMulaw() ? WAVE_FORMAT_MULAW :
  968. WAVE_FORMAT_ALAW,
  969. 1, // number of channels (1 = mono)
  970. 8000, // number of samples per second
  971. 8000, // average bytes per second
  972. 1, // block alignment, in bytes, normally 1
  973. 8, // bits per sample (normally 8 or 16)
  974. 0 // size of extra format information, normally 0
  975. }
  976. };
  977. KSP_PIN InstanceData;
  978. IKsPropertySet *pKsPropSet = NULL;
  979. HRESULT hr = S_OK;
  980. InstanceData.Property.Set = KSPROPSETID_Pin;
  981. InstanceData.Property.Id = KSPROPERTY_PIN_PROPOSEDATAFORMAT;
  982. InstanceData.Property.Flags = KSPROPERTY_TYPE_SET;
  983. InstanceData.PinId = ID_BRIDGE_PIN;
  984. InstanceData.Reserved = 0;
  985. //
  986. // Bogus unreadable do-while accomplishes clever error logging economies.
  987. //
  988. do {
  989. hr = pBridgePin->QueryInterface(IID_IKsPropertySet,
  990. (void **)&pKsPropSet);
  991. if (FAILED(hr))
  992. {
  993. LOG((MSP_ERROR, STREAM_PREFIX("SetDataFormatOnPin - "
  994. "Couldn't get IKsPropertySet interface\n")));
  995. break;
  996. }
  997. hr = pKsPropSet->Set(KSPROPSETID_Pin,
  998. KSPROPERTY_PIN_PROPOSEDATAFORMAT,
  999. (LPVOID)&InstanceData,
  1000. sizeof(KSP_PIN),
  1001. (LPVOID)&PCMAudioFormat,
  1002. sizeof(KSDATAFORMAT_WAVEFORMATEX));
  1003. pKsPropSet->Release();
  1004. if (FAILED(hr))
  1005. {
  1006. LOG((MSP_ERROR, STREAM_PREFIX("SetDataFormatOnPin - "
  1007. "Couldn't set KSPROPERTY_PIN_PROPOSEDATAFORMAT\n")));
  1008. break;
  1009. }
  1010. } while (FALSE);
  1011. LOG((MSP_TRACE, STREAM_PREFIX("SetDataFormatOnPin - exit 0x%08x\n"),
  1012. hr));
  1013. return hr;
  1014. }
  1015. ///////////////////////////////////////////////////////////////////////////////
  1016. ///////////////////////////////////////////////////////////////////////////////
  1017. //
  1018. HRESULT
  1019. CRCAMSPStream::SetMediaTypeFormat(
  1020. AM_MEDIA_TYPE* pAmMediaType,
  1021. BYTE* pformat,
  1022. ULONG length)
  1023. {
  1024. // Is the current format buffer big enough?
  1025. if(pAmMediaType->cbFormat < length)
  1026. {
  1027. // allocate the new format buffer
  1028. BYTE *pNewFormat = (PBYTE)CoTaskMemAlloc(length);
  1029. if(pNewFormat == NULL)
  1030. {
  1031. return E_OUTOFMEMORY;
  1032. }
  1033. // delete the old format
  1034. if(pAmMediaType->pbFormat != NULL)
  1035. {
  1036. CoTaskMemFree((PVOID)pAmMediaType->pbFormat);
  1037. }
  1038. pAmMediaType->cbFormat = length;
  1039. pAmMediaType->pbFormat = pNewFormat;
  1040. }
  1041. memcpy(pAmMediaType->pbFormat, pformat, length);
  1042. return S_OK;
  1043. }
  1044. //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  1045. // ConfigureCapture
  1046. //
  1047. // This is a helper function that sets up the allocator properties on the
  1048. // capture filter, given the output pin on the capture filter or terminal and
  1049. // the input pin on the render filter or terminal.
  1050. //
  1051. // we are already in a lock; no need to do locking here.
  1052. //
  1053. //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  1054. HRESULT CRCAMSPStream::ConfigureCapture( IPin * pOutputPin,
  1055. IPin * pInputPin )
  1056. {
  1057. LOG((MSP_TRACE, STREAM_PREFIX("ConfigureCapture - enter")));
  1058. //
  1059. // If our RCA filter is the capturer, then we don't have anything
  1060. // to do.
  1061. //
  1062. if ( m_Direction == TD_RENDER )
  1063. {
  1064. LOG((MSP_TRACE, STREAM_PREFIX("ConfigureCapture - "
  1065. "not a capture stream so nothing to do - exit S_OK")));
  1066. return S_OK;
  1067. }
  1068. //
  1069. // The correct buffer size was obtained from the RCA filter's bridge pin
  1070. // during the VC Handle TSP data handling. Since we already have the VC
  1071. // handle before we get here, we know that m_dwBuffferSizeOnWire is valid.
  1072. //
  1073. _ASSERTE( m_fHaveVCHandle );
  1074. //
  1075. // Get the buffer negotiation interface on the capturer's output pin.
  1076. //
  1077. HRESULT hr;
  1078. IAMBufferNegotiation * pNegotiation;
  1079. hr = pOutputPin->QueryInterface(IID_IAMBufferNegotiation,
  1080. (void **) &pNegotiation);
  1081. if ( FAILED(hr) )
  1082. {
  1083. LOG((MSP_ERROR, STREAM_PREFIX("ConfigureCapture - "
  1084. "IAMBufferNegotiation QI failed - hr = 0x%08x"), hr));
  1085. return hr;
  1086. }
  1087. //
  1088. // Suggest allocator properties on the capturer.
  1089. // Since we insert the G711 codec when we connect, we actually want
  1090. // buffers on the capturer that are twice as big as the buffers we
  1091. // want to send out on the wire.
  1092. //
  1093. ALLOCATOR_PROPERTIES props;
  1094. props.cBuffers = 32; // we use 32 to try to avoid starvation
  1095. props.cbAlign = -1; // -1 means "default"
  1096. props.cbPrefix = -1; // -1 means "default"
  1097. props.cbBuffer = m_dwBufferSizeOnWire * 2; // see note above
  1098. hr = pNegotiation->SuggestAllocatorProperties(&props);
  1099. pNegotiation->Release();
  1100. if ( FAILED(hr) )
  1101. {
  1102. LOG((MSP_ERROR, STREAM_PREFIX("ConfigureCapture - "
  1103. "SuggestAllocatorProperties failed - exit 0x%08x"), hr));
  1104. return hr;
  1105. }
  1106. LOG((MSP_TRACE, STREAM_PREFIX("ConfigureCapture - exit S_OK")));
  1107. return S_OK;
  1108. }
  1109. //++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
  1110. //
  1111. // This function is for debugging purposes only. It prints
  1112. // some debug spew telling you various information about
  1113. // media formats and allocator properties. It's called after
  1114. // connection has taken place. pPin is the output pin of the
  1115. // capture filter.
  1116. //
  1117. //++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
  1118. HRESULT CRCAMSPStream::ExamineCaptureSettings(IPin *pPin)
  1119. {
  1120. LOG((MSP_TRACE, STREAM_PREFIX("ExamineCaptureSettings - enter")));
  1121. HRESULT hr;
  1122. IAMBufferNegotiation * pNegotiation = NULL;
  1123. hr = pPin->QueryInterface(IID_IAMBufferNegotiation,
  1124. (void **) &pNegotiation
  1125. );
  1126. if ( FAILED(hr) )
  1127. {
  1128. LOG((MSP_ERROR, STREAM_PREFIX("ExamineCaptureSettings - "
  1129. "IAMBufferNegotiation QI failed on pin 0x%08x; hr = 0x%08x"),
  1130. pPin, hr));
  1131. return hr;
  1132. }
  1133. ALLOCATOR_PROPERTIES prop;
  1134. hr = pNegotiation->GetAllocatorProperties(&prop);
  1135. pNegotiation->Release();
  1136. if ( FAILED(hr) )
  1137. {
  1138. LOG((MSP_ERROR, STREAM_PREFIX("ExamineCaptureSettings - "
  1139. "GetAllocatorProperties failed; hr = 0x%08x"),
  1140. hr));
  1141. return hr;
  1142. }
  1143. LOG((MSP_TRACE, "GetAllocatorProperties info:\n"
  1144. "buffer count: %d\n"
  1145. "size of each buffer: %d bytes\n"
  1146. "alignment multiple: %d\n"
  1147. "each buffer has a prefix: %d bytes",
  1148. prop.cBuffers,
  1149. prop.cbBuffer,
  1150. prop.cbAlign,
  1151. prop.cbPrefix
  1152. ));
  1153. IAMStreamConfig * pConfig = NULL;
  1154. hr = pPin->QueryInterface(IID_IAMStreamConfig,
  1155. (void **) &pConfig
  1156. );
  1157. if ( FAILED(hr) )
  1158. {
  1159. LOG((MSP_ERROR, STREAM_PREFIX("ExamineCaptureSettings - "
  1160. "IAMStreamConfig QI failed on pin 0x%08x; hr = 0x%08x"), pPin, hr));
  1161. return hr;
  1162. }
  1163. AM_MEDIA_TYPE * pMediaType;
  1164. hr = pConfig->GetFormat(&pMediaType);
  1165. pConfig->Release();
  1166. if ( FAILED(hr) )
  1167. {
  1168. LOG((MSP_ERROR, STREAM_PREFIX("ExamineCaptureSettings - "
  1169. "GetFormat failed; hr = 0x%08x"), hr));
  1170. return hr;
  1171. }
  1172. _ASSERTE( pMediaType->cbFormat >= sizeof(WAVEFORMATEX) );
  1173. LOG((MSP_TRACE, "GetFormat info:\n"
  1174. "sample size: %d bytes\n"
  1175. "channels: %d\n"
  1176. "samples per second: %d\n"
  1177. "bits per sample: %d\n",
  1178. pMediaType->lSampleSize,
  1179. ((WAVEFORMATEX *) (pMediaType->pbFormat) )->nChannels,
  1180. ((WAVEFORMATEX *) (pMediaType->pbFormat) )->nSamplesPerSec,
  1181. ((WAVEFORMATEX *) (pMediaType->pbFormat) )->wBitsPerSample
  1182. ));
  1183. DeleteMediaType(pMediaType);
  1184. LOG((MSP_TRACE, STREAM_PREFIX("ExamineCaptureSettings - "
  1185. "exit S_OK")));
  1186. return S_OK;
  1187. }
  1188. ///////////////////////////////////////////////////////////////////////////////
  1189. ///////////////////////////////////////////////////////////////////////////////
  1190. //
  1191. // Add the terminal to the graph and connect it to our
  1192. // filters, if it is not already in use.
  1193. //
  1194. HRESULT CRCAMSPStream::ConnectTerminal(ITTerminal * pTerminal)
  1195. {
  1196. LOG((MSP_TRACE, STREAM_PREFIX("ConnectTerminal - enter")));
  1197. //
  1198. // Find out the terminal's internal state.
  1199. //
  1200. TERMINAL_STATE state;
  1201. HRESULT hr;
  1202. hr = pTerminal->get_State( &state );
  1203. if ( FAILED(hr) )
  1204. {
  1205. LOG((MSP_ERROR, STREAM_PREFIX("ConnectTerminal - "
  1206. "get_State on terminal failed - exit 0x%08x"), hr));
  1207. return hr;
  1208. }
  1209. //
  1210. // If we've already connected the terminal on this stream, then
  1211. // there is nothing for us to do. Just assert that the terminal
  1212. // also thinks it's connected.
  1213. //
  1214. if ( m_fTerminalConnected )
  1215. {
  1216. _ASSERTE( state == TS_INUSE );
  1217. LOG((MSP_ERROR, STREAM_PREFIX("ConnectTerminal - "
  1218. "terminal already connected on this stream - exit S_OK")));
  1219. return S_OK;
  1220. }
  1221. //
  1222. // Otherwise we need to connect the terminal on this call. If the
  1223. // terminal is already connected on another call, we must fail. Note
  1224. // that since we are making several calls on the terminal here, the
  1225. // terminal could become connected on another call while we are
  1226. // in the process of doing this. If this happens, the we will just fail
  1227. // later.
  1228. //
  1229. if ( state == TS_INUSE )
  1230. {
  1231. LOG((MSP_ERROR, STREAM_PREFIX("ConnectTerminal - "
  1232. "terminal in use - exit TAPI_E_TERMINALINUSE")));
  1233. return TAPI_E_TERMINALINUSE;
  1234. }
  1235. //
  1236. // Get the ITTerminalControl interface.
  1237. //
  1238. ITTerminalControl * pTerminalControl;
  1239. hr = m_Terminals[0]->QueryInterface(IID_ITTerminalControl,
  1240. (void **) &pTerminalControl);
  1241. if ( FAILED(hr) )
  1242. {
  1243. LOG((MSP_ERROR, STREAM_PREFIX("ConnectTerminal - "
  1244. "QI for ITTerminalControl failed - exit 0x%08x"), hr));
  1245. return hr;
  1246. }
  1247. //
  1248. // Find out how many pins the terminal has. If not one then bail as
  1249. // we have no idea what to do with multiple-pin terminals at this point.
  1250. //
  1251. DWORD dwNumPinsAvailable;
  1252. hr = pTerminalControl->ConnectTerminal(m_pIGraphBuilder,
  1253. m_Direction,
  1254. &dwNumPinsAvailable,
  1255. NULL);
  1256. if ( FAILED(hr) )
  1257. {
  1258. LOG((MSP_ERROR, STREAM_PREFIX("ConnectTerminal - "
  1259. "query for number of terminal pins failed - exit 0x%08x"), hr));
  1260. pTerminalControl->Release();
  1261. return hr;
  1262. }
  1263. if ( 1 != dwNumPinsAvailable )
  1264. {
  1265. LOG((MSP_ERROR, STREAM_PREFIX("ConnectTerminal - "
  1266. "unsupported number of terminal pins - exit E_FAIL")));
  1267. pTerminalControl->Release();
  1268. return E_FAIL;
  1269. }
  1270. IPin * pTerminalPin;
  1271. //
  1272. // Actually connect the terminal.
  1273. //
  1274. hr = pTerminalControl->ConnectTerminal(m_pIGraphBuilder,
  1275. m_Direction,
  1276. &dwNumPinsAvailable,
  1277. &pTerminalPin);
  1278. if ( FAILED(hr) )
  1279. {
  1280. pTerminalControl->Release();
  1281. LOG((MSP_ERROR, STREAM_PREFIX("ConnectTerminal - "
  1282. "ConnectTerminal on terminal failed - exit 0x%08x"), hr));
  1283. return hr;
  1284. }
  1285. //
  1286. // also try to check if the terminal returned a bad pin.
  1287. //
  1288. if ( IsBadReadPtr(pTerminalPin, sizeof(IPin)) )
  1289. {
  1290. pTerminalControl->Release();
  1291. LOG((MSP_ERROR, STREAM_PREFIX("ConnectTerminal - "
  1292. "ConnectTerminal on terminal succeeded but returned a bad pin - "
  1293. "returning E_POINTER")));
  1294. return E_POINTER;
  1295. }
  1296. //
  1297. // Now make the connection between our filters and the terminal's pin.
  1298. //
  1299. hr = ConnectToTerminalPin(pTerminalPin);
  1300. pTerminalPin->Release();
  1301. if ( FAILED(hr) )
  1302. {
  1303. pTerminalControl->DisconnectTerminal(m_pIGraphBuilder, 0);
  1304. pTerminalControl->Release();
  1305. LOG((MSP_ERROR, STREAM_PREFIX("ConnectTerminal - "
  1306. "ConnectToTerminalPin failed - exit 0x%08x"), hr));
  1307. return hr;
  1308. }
  1309. //
  1310. // Now we are actually connected. Update our state and perform postconnection
  1311. // (ignore postconnection error code).
  1312. //
  1313. m_fTerminalConnected = TRUE;
  1314. pTerminalControl->CompleteConnectTerminal();
  1315. pTerminalControl->Release();
  1316. LOG((MSP_TRACE, STREAM_PREFIX("ConnectTerminal - exit S_OK")));
  1317. return S_OK;
  1318. }
  1319. HRESULT CRCAMSPStream::TryToConnect(
  1320. IPin * pOutputPin, // on the capture filter or terminal
  1321. IPin * pInputPin // on the render filter or terminal
  1322. )
  1323. {
  1324. LOG((MSP_TRACE, STREAM_PREFIX("TryToConnect - enter")));
  1325. //
  1326. // We must have our RCA filter at this point, because Init succeeded.
  1327. //
  1328. _ASSERTE( m_pFilter );
  1329. //
  1330. // Prepare the G711 filter (create and add or remove existing and readd).
  1331. //
  1332. HRESULT hr;
  1333. hr = PrepareG711Filter();
  1334. if ( FAILED(hr) )
  1335. {
  1336. LOG((MSP_ERROR, STREAM_PREFIX("TryToConnect - "
  1337. "failed to prepare G711 - exit 0x%08x"), hr));
  1338. return hr;
  1339. }
  1340. _ASSERTE( m_pG711Filter != NULL );
  1341. //
  1342. // Now connect.
  1343. //
  1344. hr = ConnectUsingG711(pOutputPin, pInputPin);
  1345. if ( FAILED(hr) )
  1346. {
  1347. LOG((MSP_ERROR, STREAM_PREFIX("TryToConnect - "
  1348. "failed to connect - exit 0x%08x"), hr));
  1349. return hr;
  1350. }
  1351. LOG((MSP_TRACE, STREAM_PREFIX("TryToConnect - exit S_OK")));
  1352. return S_OK;
  1353. }
  1354. //////////////////////////////////////////////////////////////////////////////
  1355. //
  1356. // ConnectUsingG711
  1357. //
  1358. // This method connects pOutputPin to pInputPin using the G711 codec and
  1359. // returns success if the connection was successful. If the connection was
  1360. // unsuccessful, it does its best to clean up its references, but makes no
  1361. // attempt to disconnect the filters, as we always break leftover connections
  1362. // by removing and readding the g711 filter.
  1363. //
  1364. // Assumptions:
  1365. // * direct connection has already failed
  1366. // * the g711 codec has been created and added to the graph
  1367. //
  1368. // Parameters:
  1369. // IN IPin * pOutputPin -- output pin on the capture filter or terminal
  1370. // IN IPin * pInputPin -- input pin on the render filter or terminal
  1371. //
  1372. //
  1373. HRESULT CRCAMSPStream::ConnectUsingG711(
  1374. IN IPin * pOutputPin,
  1375. IN IPin * pInputPin
  1376. )
  1377. {
  1378. HRESULT hr;
  1379. //
  1380. // Get the G711 codec filter's input pin.
  1381. //
  1382. IPin * pG711InputPin = NULL;
  1383. hr = FindPinInFilter(
  1384. false, // want input pin
  1385. m_pG711Filter,
  1386. &pG711InputPin
  1387. );
  1388. if ( FAILED(hr) )
  1389. {
  1390. LOG((MSP_ERROR, STREAM_PREFIX("ConnectUsingG711 - could not find "
  1391. "G711 codec's input pin - 0x%08x"), hr));
  1392. return hr;
  1393. }
  1394. AM_MEDIA_TYPE mt;
  1395. WAVEFORMATEX wfx;
  1396. AM_MEDIA_TYPE * pmt = NULL;
  1397. if ( m_Direction == TD_RENDER ) // capture filter is RCA
  1398. {
  1399. wfx.wFormatTag = UseMulaw() ? WAVE_FORMAT_MULAW :
  1400. WAVE_FORMAT_ALAW;
  1401. wfx.wBitsPerSample = 8;
  1402. wfx.nChannels = 1;
  1403. wfx.nSamplesPerSec = 8000;
  1404. wfx.nBlockAlign = wfx.wBitsPerSample * wfx.nChannels / 8;
  1405. wfx.nAvgBytesPerSec = ((DWORD) wfx.nBlockAlign * wfx.nSamplesPerSec);
  1406. wfx.cbSize = 0;
  1407. mt.majortype = MEDIATYPE_Audio;
  1408. mt.subtype = UseMulaw() ? MEDIASUBTYPE_MULAWAudio :
  1409. MEDIASUBTYPE_ALAWAudio;
  1410. mt.bFixedSizeSamples = TRUE;
  1411. mt.bTemporalCompression = FALSE;
  1412. mt.lSampleSize = 0;
  1413. mt.formattype = FORMAT_WaveFormatEx;
  1414. mt.pUnk = NULL;
  1415. mt.cbFormat = sizeof(WAVEFORMATEX);
  1416. mt.pbFormat = (BYTE*)&wfx;
  1417. pmt = &mt;
  1418. }
  1419. //
  1420. // Connect the capture filter's output pin to the G711 codec filter's
  1421. // input pin. Release reference to the pin when done.
  1422. //
  1423. hr = m_pIGraphBuilder->ConnectDirect(
  1424. pOutputPin,
  1425. pG711InputPin,
  1426. pmt
  1427. );
  1428. pG711InputPin->Release();
  1429. if ( FAILED(hr) )
  1430. {
  1431. LOG((MSP_ERROR, STREAM_PREFIX("ConnectUsingG711 - could not connect "
  1432. "G711 codec's input pin - 0x%08x"), hr));
  1433. return hr;
  1434. }
  1435. //
  1436. // Get the G711 codec filter's output pin.
  1437. //
  1438. IPin * pG711OutputPin = NULL;
  1439. hr = FindPinInFilter(
  1440. true, // want output pin
  1441. m_pG711Filter,
  1442. &pG711OutputPin
  1443. );
  1444. if ( FAILED(hr) )
  1445. {
  1446. LOG((MSP_ERROR, STREAM_PREFIX("ConnectUsingG711 - could not find "
  1447. "G711 codec's input pin - 0x%08x"), hr));
  1448. return hr;
  1449. }
  1450. //
  1451. // Connect the G711 codec filter's output pin to the render filter's
  1452. // input pin. Release reference to the pin when done.
  1453. //
  1454. hr = m_pIGraphBuilder->ConnectDirect(
  1455. pG711OutputPin,
  1456. pInputPin,
  1457. NULL
  1458. );
  1459. pG711OutputPin->Release();
  1460. if ( FAILED(hr) )
  1461. {
  1462. LOG((MSP_ERROR, STREAM_PREFIX("ConnectUsingG711 - could not connect "
  1463. "G711 codec's output pin - 0x%08x"), hr));
  1464. return hr;
  1465. }
  1466. LOG((MSP_TRACE, STREAM_PREFIX("ConnectUsingG711 - exit S_OK")));
  1467. return S_OK;
  1468. }
  1469. //////////////////////////////////////////////////////////////////////////////
  1470. //////////////////////////////////////////////////////////////////////////////
  1471. //
  1472. HRESULT CRCAMSPStream::ConnectToTerminalPin(IPin * pTerminalPin)
  1473. {
  1474. LOG((MSP_TRACE, STREAM_PREFIX("ConnectToTerminalPin - enter")));
  1475. HRESULT hr = S_OK;
  1476. if ( m_Direction == TD_CAPTURE )
  1477. {
  1478. //
  1479. // First set the audio format on a capture terminal's pin. If it
  1480. // doesn't work, we know that we won't be able to connect, so it
  1481. // saves us from getting in too deep in the failure case. If it
  1482. // does work, it will significantly speed up format negotiation
  1483. // during connection.
  1484. //
  1485. hr = ::SetAudioFormat(pTerminalPin,
  1486. BITS_PER_SAMPLE_AT_TERMINAL,
  1487. SAMPLE_RATE_AT_TERMINAL);
  1488. if ( FAILED(hr) )
  1489. {
  1490. LOG((MSP_ERROR, STREAM_PREFIX("ConnectToTerminalPin - "
  1491. "could not set audio format - exit 0x%08x"), hr));
  1492. return hr;
  1493. }
  1494. }
  1495. //
  1496. // Get the right pin on our own RCA transport filter.
  1497. //
  1498. IPin * pMyPin;
  1499. hr = FindPin( &pMyPin );
  1500. if ( FAILED(hr) )
  1501. {
  1502. LOG((MSP_ERROR, STREAM_PREFIX("ConnectToTerminalPin - "
  1503. "could not find pin - exit 0x%08x"), hr));
  1504. return hr;
  1505. }
  1506. //
  1507. // From here on, it's helpful to keep track of these pins according to
  1508. // directionality -- saves lots of conditionals later on.
  1509. // OUTPUT pin from CAPTURE filter; INPUT pin from RENDER filter
  1510. //
  1511. IPin * pOutputPin = ( m_Direction == TD_RENDER ) ? pMyPin : pTerminalPin;
  1512. IPin * pInputPin = ( m_Direction == TD_CAPTURE ) ? pMyPin : pTerminalPin;
  1513. //
  1514. // Configure the capturer with correct buffer sizes, etc.
  1515. //
  1516. hr = ConfigureCapture(pOutputPin,
  1517. pInputPin);
  1518. if ( SUCCEEDED(hr) )
  1519. {
  1520. //
  1521. // Connect the capturer to the renderer.
  1522. //
  1523. hr = TryToConnect(pOutputPin,
  1524. pInputPin);
  1525. if ( SUCCEEDED(hr) )
  1526. {
  1527. //
  1528. // dump some useful debug info
  1529. // don't care if this fails...
  1530. //
  1531. ExamineCaptureSettings(pOutputPin);
  1532. }
  1533. }
  1534. pMyPin->Release();
  1535. if ( FAILED(hr) )
  1536. {
  1537. LOG((MSP_ERROR, STREAM_PREFIX("ConnectToTerminalPin - "
  1538. "connection failure - exit 0x%08x"), hr));
  1539. return hr;
  1540. }
  1541. LOG((MSP_TRACE, STREAM_PREFIX("ConnectToTerminalPin - exit S_OK")));
  1542. return S_OK;
  1543. }
  1544. //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  1545. HRESULT CRCAMSPStream::FindPinInFilter(
  1546. BOOL bWantOutputPin, // IN: if false, we want the input pin
  1547. IBaseFilter * pFilter, // IN: the filter to examine
  1548. IPin ** ppPin // OUT: the pin we found
  1549. )
  1550. {
  1551. HRESULT hr;
  1552. IEnumPins * pEnumPins;
  1553. *ppPin = NULL;
  1554. // enumerate the pins on the filter
  1555. hr = pFilter->EnumPins( &pEnumPins );
  1556. if (!(SUCCEEDED(hr)))
  1557. {
  1558. return hr;
  1559. }
  1560. // go through the pins
  1561. while (TRUE)
  1562. {
  1563. PIN_DIRECTION pd;
  1564. hr = pEnumPins->Next( 1, ppPin, NULL );
  1565. if (S_OK != hr)
  1566. {
  1567. // didn't find a pin!
  1568. break;
  1569. }
  1570. // get the pin info
  1571. hr = (*ppPin)->QueryDirection( &pd );
  1572. // does it meet the criteria?
  1573. if (bWantOutputPin && (pd == PINDIR_OUTPUT))
  1574. {
  1575. // yes
  1576. break;
  1577. }
  1578. if ( ! bWantOutputPin && (pd == PINDIR_INPUT))
  1579. {
  1580. // yes
  1581. break;
  1582. }
  1583. (*ppPin)->Release();
  1584. *ppPin = NULL;
  1585. }
  1586. pEnumPins->Release();
  1587. if (NULL == *ppPin)
  1588. {
  1589. // error
  1590. return E_FAIL;
  1591. }
  1592. return S_OK;
  1593. }
  1594. //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  1595. // FindPin
  1596. //
  1597. // Finds the first pin in the filter that meets criteria.
  1598. // For TD_RENDER (render terminal, capture filter),
  1599. // the pin must be direction PINDIR_OUTPUT
  1600. // For TD_CAPTURE (capture terminal, render filter),
  1601. // the pin must be direction PINDIR_INPUT
  1602. //
  1603. //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  1604. HRESULT
  1605. CRCAMSPStream::FindPin(
  1606. IPin ** ppPin
  1607. )
  1608. {
  1609. return FindPinInFilter(m_Direction == TD_RENDER,
  1610. m_pFilter,
  1611. ppPin);
  1612. }
  1613. //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  1614. //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  1615. //
  1616. // ProcessGraphEvent
  1617. //
  1618. // Sends an event to the app when we get an event from the filter graph.
  1619. //
  1620. //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  1621. HRESULT CRCAMSPStream::ProcessGraphEvent(
  1622. IN long lEventCode,
  1623. IN LONG_PTR lParam1,
  1624. IN LONG_PTR lParam2
  1625. )
  1626. {
  1627. LOG((MSP_EVENT, STREAM_PREFIX("ProcessGraphEvent - enter")));
  1628. HRESULT hr = S_OK;
  1629. switch (lEventCode)
  1630. {
  1631. case EC_COMPLETE:
  1632. hr = FireEvent(CALL_STREAM_INACTIVE, (HRESULT) lParam1, CALL_CAUSE_UNKNOWN);
  1633. break;
  1634. case EC_USERABORT:
  1635. hr = FireEvent(CALL_STREAM_INACTIVE, S_OK, CALL_CAUSE_UNKNOWN);
  1636. break;
  1637. case EC_ERRORABORT:
  1638. case EC_STREAM_ERROR_STOPPED:
  1639. case EC_STREAM_ERROR_STILLPLAYING:
  1640. case EC_ERROR_STILLPLAYING:
  1641. hr = FireEvent(CALL_STREAM_FAIL, (HRESULT) lParam1, CALL_CAUSE_UNKNOWN);
  1642. break;
  1643. default:
  1644. LOG((MSP_EVENT, STREAM_PREFIX("ProcessGraphEvent - "
  1645. "ignoring event code %d"), lEventCode));
  1646. break;
  1647. }
  1648. if ( FAILED(hr) )
  1649. {
  1650. LOG((MSP_ERROR, STREAM_PREFIX("ProcessGraphEvent - "
  1651. "FireEvent failed - exit 0x%08x"), hr));
  1652. return hr;
  1653. }
  1654. LOG((MSP_EVENT, STREAM_PREFIX("ProcessGraphEvent - exit S_OK")));
  1655. return S_OK;
  1656. }
  1657. //////////////////////////////////////////////////////////////////////////////
  1658. //////////////////////////////////////////////////////////////////////////////
  1659. //
  1660. // FireEvent
  1661. //
  1662. // Fires an event to the application. Does its own locking.
  1663. //
  1664. HRESULT CRCAMSPStream::FireEvent(
  1665. IN MSP_CALL_EVENT type,
  1666. IN HRESULT hrError,
  1667. IN MSP_CALL_EVENT_CAUSE cause
  1668. )
  1669. {
  1670. LOG((MSP_EVENT, STREAM_PREFIX("FireEvent - enter")));
  1671. //
  1672. // First, need to check if the call is shutting down. This is important
  1673. // because UnselectTerminal can fire an event, and UnselectTerminal can
  1674. // be called within ITStream::Shutdown. We can safely discard such
  1675. // events because there is nothing the app can do with them anyway.
  1676. //
  1677. // Note on locking: It is convenient to check the m_pMSPCall here
  1678. // and we don't use it until the end of the method, so we simply lock
  1679. // during the entire method. This could be optimized at the expense of
  1680. // some code complexity; note that we also need to lock while accessing
  1681. // m_Terminals.
  1682. //
  1683. CLock lock(m_lock);
  1684. if ( m_pMSPCall == NULL )
  1685. {
  1686. LOG((MSP_EVENT, STREAM_PREFIX("FireEvent - "
  1687. "call is shutting down; dropping event - exit S_OK")));
  1688. return S_OK;
  1689. }
  1690. //
  1691. // Create the event structure. Must use "new" as it will be
  1692. // "delete"d later.
  1693. //
  1694. MSPEVENTITEM * pEventItem = AllocateEventItem();
  1695. if (pEventItem == NULL)
  1696. {
  1697. LOG((MSP_ERROR, STREAM_PREFIX("FireEvent - "
  1698. "can't create MSPEVENTITEM structure - exit E_OUTOFMEMORY")));
  1699. return E_OUTOFMEMORY;
  1700. }
  1701. //
  1702. // Fill in the necessary fields for the event structure.
  1703. //
  1704. pEventItem->MSPEventInfo.dwSize = sizeof(MSP_EVENT_INFO);
  1705. pEventItem->MSPEventInfo.Event = ME_CALL_EVENT;
  1706. ITTerminal * pTerminal = NULL;
  1707. if ( 0 != m_Terminals.GetSize() )
  1708. {
  1709. _ASSERTE( 1 == m_Terminals.GetSize() );
  1710. pTerminal = m_Terminals[0];
  1711. pTerminal->AddRef();
  1712. }
  1713. ITStream * pStream = (ITStream *) this;
  1714. pStream->AddRef();
  1715. pEventItem->MSPEventInfo.MSP_CALL_EVENT_INFO.Type = type;
  1716. pEventItem->MSPEventInfo.MSP_CALL_EVENT_INFO.Cause = cause;
  1717. pEventItem->MSPEventInfo.MSP_CALL_EVENT_INFO.pStream = pStream;
  1718. pEventItem->MSPEventInfo.MSP_CALL_EVENT_INFO.pTerminal = pTerminal;
  1719. pEventItem->MSPEventInfo.MSP_CALL_EVENT_INFO.hrError = hrError;
  1720. //
  1721. // Send the event to the app.
  1722. //
  1723. HRESULT hr = m_pMSPCall->HandleStreamEvent(pEventItem);
  1724. if (FAILED(hr))
  1725. {
  1726. LOG((MSP_ERROR, STREAM_PREFIX("FireEvent - "
  1727. "HandleStreamEvent failed - returning 0x%08x"), hr));
  1728. pStream->Release();
  1729. pTerminal->Release();
  1730. FreeEventItem(pEventItem);
  1731. return hr;
  1732. }
  1733. LOG((MSP_EVENT, STREAM_PREFIX("FireEvent - exit S_OK")));
  1734. return S_OK;
  1735. }
  1736. //////////////////////////////////////////////////////////////////////////////
  1737. //////////////////////////////////////////////////////////////////////////////
  1738. //
  1739. // UseMulaw
  1740. //
  1741. // Helper function called when we need to decide if to use Mulaw or Alaw.
  1742. // This is simply delegated to the call.
  1743. //
  1744. BOOL CRCAMSPStream::UseMulaw( void )
  1745. {
  1746. return ( (CRCAMSPCall *) m_pMSPCall )->UseMulaw();
  1747. }
  1748. //////////////////////////////////////////////////////////////////////////////
  1749. //////////////////////////////////////////////////////////////////////////////
  1750. //
  1751. // Helper functions -- non-class members.
  1752. //
  1753. HRESULT SetAudioFormat(
  1754. IN IUnknown* pIUnknown,
  1755. IN WORD wBitPerSample,
  1756. IN DWORD dwSampleRate
  1757. )
  1758. /*++
  1759. Routine Description:
  1760. Get the IAMStreamConfig interface on the object and config the
  1761. audio format by using WAVEFORMATEX.
  1762. Arguments:
  1763. pIPin - a capture terminal.
  1764. wBitPerSample - the number of bits in each sample.
  1765. dwSampleRate - number of samples per second.
  1766. Return Value:
  1767. HRESULT
  1768. --*/
  1769. {
  1770. LOG((MSP_TRACE, "SetAudioFormat - enter"));
  1771. HRESULT hr;
  1772. IAMStreamConfig * pIAMStreamConfig;
  1773. hr = pIUnknown->QueryInterface(
  1774. IID_IAMStreamConfig,
  1775. (void **)&pIAMStreamConfig
  1776. );
  1777. if ( FAILED(hr) )
  1778. {
  1779. LOG((MSP_ERROR, "SetAudioFormat - "
  1780. "Can't get IAMStreamConfig interface - exit 0x%08x", hr));
  1781. return hr;
  1782. }
  1783. AM_MEDIA_TYPE mt;
  1784. WAVEFORMATEX wfx;
  1785. wfx.wFormatTag = WAVE_FORMAT_PCM;
  1786. wfx.wBitsPerSample = wBitPerSample;
  1787. wfx.nChannels = 1;
  1788. wfx.nSamplesPerSec = dwSampleRate;
  1789. wfx.nBlockAlign = wfx.wBitsPerSample * wfx.nChannels / 8;
  1790. wfx.nAvgBytesPerSec = ((DWORD) wfx.nBlockAlign * wfx.nSamplesPerSec);
  1791. wfx.cbSize = 0;
  1792. mt.majortype = MEDIATYPE_Audio;
  1793. mt.subtype = MEDIASUBTYPE_PCM;
  1794. mt.bFixedSizeSamples = TRUE;
  1795. mt.bTemporalCompression = FALSE;
  1796. mt.lSampleSize = 0;
  1797. mt.formattype = FORMAT_WaveFormatEx;
  1798. mt.pUnk = NULL;
  1799. mt.cbFormat = sizeof(WAVEFORMATEX);
  1800. mt.pbFormat = (BYTE*)&wfx;
  1801. //
  1802. // set the format of the audio capture terminal.
  1803. //
  1804. hr = pIAMStreamConfig->SetFormat(&mt);
  1805. pIAMStreamConfig->Release();
  1806. if ( FAILED(hr) )
  1807. {
  1808. LOG((MSP_ERROR, "SetAudioFormat - SetFormat returns error: %8x", hr));
  1809. return hr;
  1810. }
  1811. LOG((MSP_TRACE, "SetAudioFormat - exit S_OK"));
  1812. return S_OK;
  1813. }
  1814. // eof