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

2022 lines
52 KiB

  1. /*++
  2. Copyright (c) 1998 Microsoft Corporation
  3. Module Name:
  4. wavestrm.cpp
  5. Abstract:
  6. This module contains implementation of CWaveMSPStream.
  7. Author:
  8. Zoltan Szilagyi (zoltans) September 7, 1998
  9. --*/
  10. #include "stdafx.h"
  11. #include <initguid.h>
  12. #include <g711uids.h>
  13. HRESULT
  14. TryCreateCSAFilter(
  15. IN GUID *PermanentGuid,
  16. OUT IBaseFilter **ppCSAFilter
  17. );
  18. ///////////////////////////////////////////////////////////////////////////////
  19. ///////////////////////////////////////////////////////////////////////////////
  20. //
  21. CWaveMSPStream::CWaveMSPStream() : CMSPStream()
  22. {
  23. LOG((MSP_TRACE, "CWaveMSPStream::CWaveMSPStream entered."));
  24. m_fTerminalConnected = FALSE;
  25. m_fHaveWaveID = FALSE;
  26. m_DesiredGraphState = State_Stopped;
  27. m_pFilter = NULL;
  28. m_pG711Filter = NULL;
  29. LOG((MSP_TRACE, "CWaveMSPStream::CWaveMSPStream exited."));
  30. }
  31. ///////////////////////////////////////////////////////////////////////////////
  32. ///////////////////////////////////////////////////////////////////////////////
  33. //
  34. CWaveMSPStream::~CWaveMSPStream()
  35. {
  36. LOG((MSP_TRACE, "CWaveMSPStream::~CWaveMSPStream entered."));
  37. LOG((MSP_TRACE, "CWaveMSPStream::~CWaveMSPStream exited."));
  38. }
  39. ///////////////////////////////////////////////////////////////////////////////
  40. ///////////////////////////////////////////////////////////////////////////////
  41. //
  42. void CWaveMSPStream::FinalRelease()
  43. {
  44. LOG((MSP_TRACE, "CWaveMSPStream::FinalRelease entered."));
  45. //
  46. // At this point we should have no terminals selected, since
  47. // Shutdown is supposed to be called before we are destructed.
  48. //
  49. _ASSERTE( 0 == m_Terminals.GetSize() );
  50. //
  51. // Remove out filter from the graph and release it.
  52. //
  53. if ( m_fHaveWaveID )
  54. {
  55. _ASSERTE( m_pFilter );
  56. m_pIGraphBuilder->RemoveFilter( m_pFilter );
  57. m_pFilter->Release();
  58. }
  59. if ( m_pG711Filter )
  60. {
  61. m_pIGraphBuilder->RemoveFilter( m_pG711Filter );
  62. m_pG711Filter->Release();
  63. }
  64. //
  65. // Call the base class method to clean up everything else.
  66. //
  67. CMSPStream::FinalRelease();
  68. LOG((MSP_TRACE, "CWaveMSPStream::FinalRelease exited."));
  69. }
  70. ///////////////////////////////////////////////////////////////////////////////
  71. ///////////////////////////////////////////////////////////////////////////////
  72. //
  73. STDMETHODIMP CWaveMSPStream::get_Name (
  74. OUT BSTR * ppName
  75. )
  76. {
  77. LOG((MSP_TRACE, "CWaveMSPStream::get_Name - enter"));
  78. //
  79. // Check argument.
  80. //
  81. if ( IsBadWritePtr(ppName, sizeof(BSTR) ) )
  82. {
  83. LOG((MSP_TRACE, "CWaveMSPStream::get_Name - "
  84. "bad return pointer - returning E_POINTER"));
  85. return E_POINTER;
  86. }
  87. //
  88. // Decide what string to return based on which stream this is.
  89. //
  90. ULONG ulID;
  91. if ( m_Direction == TD_CAPTURE )
  92. {
  93. ulID = IDS_CAPTURE_STREAM;
  94. }
  95. else
  96. {
  97. ulID = IDS_RENDER_STREAM;
  98. }
  99. //
  100. // Get the string from the string table.
  101. //
  102. const int ciAllocSize = 2048;
  103. WCHAR wszName[ciAllocSize];
  104. int iReturn = LoadString( _Module.GetModuleInstance(),
  105. ulID,
  106. wszName,
  107. ciAllocSize - 1 );
  108. if ( iReturn == 0 )
  109. {
  110. _ASSERTE( FALSE );
  111. *ppName = NULL;
  112. LOG((MSP_ERROR, "CWaveMSPStream::get_Name - "
  113. "LoadString failed - returning E_UNEXPECTED"));
  114. return E_UNEXPECTED;
  115. }
  116. //
  117. // Convert to a BSTR and return the BSTR.
  118. //
  119. *ppName = SysAllocString(wszName);
  120. if ( *ppName == NULL )
  121. {
  122. LOG((MSP_ERROR, "CWaveMSPStream::get_Name - "
  123. "SysAllocString failed - returning E_OUTOFMEMORY"));
  124. return E_OUTOFMEMORY;
  125. }
  126. LOG((MSP_TRACE, "CWaveMSPStream::get_Name - exit S_OK"));
  127. return S_OK;
  128. }
  129. ///////////////////////////////////////////////////////////////////////////////
  130. ///////////////////////////////////////////////////////////////////////////////
  131. //
  132. STDMETHODIMP CWaveMSPStream::SelectTerminal(
  133. IN ITTerminal * pTerminal
  134. )
  135. {
  136. LOG((MSP_TRACE, "CWaveMSPStream::SelectTerminal - enter"));
  137. //
  138. // We are going to access the terminal list -- grab the lock
  139. //
  140. CLock lock(m_lock);
  141. //
  142. // Reject if we already have a terminal selected.
  143. //
  144. if ( 0 != m_Terminals.GetSize() )
  145. {
  146. LOG((MSP_ERROR, "CWaveMSPStream::SelectTerminal - "
  147. "exit TAPI_E_MAXTERMINALS"));
  148. return TAPI_E_MAXTERMINALS;
  149. }
  150. //
  151. // Use base class method to add it to our list of terminals.
  152. //
  153. HRESULT hr = CMSPStream::SelectTerminal(pTerminal);
  154. if ( FAILED(hr) )
  155. {
  156. LOG((MSP_ERROR, "CWaveMSPStream::SelectTerminal - "
  157. "base class method failed - exit 0x%08x", hr));
  158. return hr;
  159. }
  160. //
  161. // Re-pause or re-start the stream if needed.
  162. //
  163. if ( m_DesiredGraphState == State_Paused )
  164. {
  165. hr = PauseStream();
  166. }
  167. else if ( m_DesiredGraphState == State_Running )
  168. {
  169. hr = StartStream();
  170. }
  171. else
  172. {
  173. _ASSERTE( m_DesiredGraphState == State_Stopped );
  174. hr = S_OK;
  175. }
  176. if ( FAILED(hr) )
  177. {
  178. LOG((MSP_TRACE, "CWaveMSPStream::SelectTerminal - "
  179. "can't regain old graph state - unselecting terminal - "
  180. "exit 0x%08x", hr));
  181. //
  182. // Unselect it to undo all of the above.
  183. //
  184. UnselectTerminal(pTerminal);
  185. return hr;
  186. }
  187. LOG((MSP_TRACE, "CWaveMSPStream::SelectTerminal - exit S_OK"));
  188. return S_OK;
  189. }
  190. ///////////////////////////////////////////////////////////////////////////////
  191. ///////////////////////////////////////////////////////////////////////////////
  192. //
  193. STDMETHODIMP CWaveMSPStream::UnselectTerminal (
  194. IN ITTerminal * pTerminal
  195. )
  196. {
  197. LOG((MSP_TRACE, "CWaveMSPStream::UnselectTerminal - enter"));
  198. CLock lock(m_lock);
  199. //
  200. // Add an extra reference to the terminal so it doesn't go away
  201. // after we call CMSPStream::UnselectTerminal. We need it later
  202. // in the function.
  203. //
  204. pTerminal->AddRef();
  205. //
  206. // Use base class method to remove terminal from our list of terminals.
  207. //
  208. HRESULT hr = CMSPStream::UnselectTerminal(pTerminal);
  209. if (FAILED(hr))
  210. {
  211. LOG((MSP_ERROR, "CWaveMSPStream::UnselectTerminal - "
  212. "base class method failed - exit 0x%08x", hr));
  213. pTerminal->Release();
  214. return hr;
  215. }
  216. //
  217. // If we've been given a waveid then we may not be stopped.
  218. // This does nothing if we are already stopped.
  219. //
  220. CMSPStream::StopStream();
  221. //
  222. // Disconnect the terminal if this call had it connected.
  223. //
  224. if ( m_fTerminalConnected )
  225. {
  226. //
  227. // Get the ITTerminalControl interface.
  228. //
  229. ITTerminalControl * pTerminalControl;
  230. hr = pTerminal->QueryInterface(IID_ITTerminalControl,
  231. (void **) &pTerminalControl);
  232. if ( FAILED(hr) )
  233. {
  234. LOG((MSP_ERROR, "CWaveMSPStream::UnselectTerminal - "
  235. "QI for ITTerminalControl failed - exit 0x%08x", hr));
  236. pTerminal->Release();
  237. return hr;
  238. }
  239. //
  240. // Disconnect the terminal.
  241. //
  242. hr = pTerminalControl->DisconnectTerminal(m_pIGraphBuilder, 0);
  243. pTerminalControl->Release();
  244. m_fTerminalConnected = FALSE;
  245. if ( FAILED(hr) )
  246. {
  247. LOG((MSP_ERROR, "CWaveMSPStream::UnselectTerminal - "
  248. "DisconnectTerminal failed - exit 0x%08x", hr));
  249. pTerminal->Release();
  250. return hr;
  251. }
  252. }
  253. LOG((MSP_TRACE, "CWaveMSPStream::UnselectTerminal - exit S_OK"));
  254. pTerminal->Release();
  255. return S_OK;
  256. }
  257. ///////////////////////////////////////////////////////////////////////////////
  258. ///////////////////////////////////////////////////////////////////////////////
  259. //
  260. STDMETHODIMP CWaveMSPStream::StartStream (void)
  261. {
  262. LOG((MSP_TRACE, "CWaveMSPStream::StartStream - enter"));
  263. CLock lock(m_lock);
  264. m_DesiredGraphState = State_Running;
  265. //
  266. // Can't start the stream if we don't know the waveid.
  267. // (We create our filters on discovery of the waveid.)
  268. //
  269. if ( ! m_fHaveWaveID )
  270. {
  271. LOG((MSP_WARN, "CWaveMSPStream::StartStream - "
  272. "no waveid so nothing to do yet - exit S_OK"));
  273. return S_OK;
  274. }
  275. //
  276. // Can't start the stream if no terminal has been selected.
  277. //
  278. if ( 0 == m_Terminals.GetSize() )
  279. {
  280. LOG((MSP_WARN, "CWaveMSPStream::StartStream - "
  281. "no Terminal so nothing to do yet - exit S_OK"));
  282. return S_OK;
  283. }
  284. //
  285. // Connect the terminal. This does nothing if this call already
  286. // connected the terminal and fails if another call has the
  287. // terminal connected.
  288. //
  289. HRESULT hr;
  290. hr = ConnectTerminal(m_Terminals[0]);
  291. if ( FAILED(hr) )
  292. {
  293. FireEvent(CALL_TERMINAL_FAIL, hr, CALL_CAUSE_CONNECT_FAIL);
  294. FireEvent(CALL_STREAM_FAIL, hr, CALL_CAUSE_CONNECT_FAIL);
  295. LOG((MSP_ERROR, "CWaveMSPStream::StartStream - "
  296. "our ConnectTerminal failed - exit 0x%08x", hr));
  297. return hr;
  298. }
  299. //
  300. // Run the stream via the base class method.
  301. //
  302. hr = CMSPStream::StartStream();
  303. if ( FAILED(hr) )
  304. {
  305. FireEvent(CALL_STREAM_FAIL, hr, CALL_CAUSE_UNKNOWN);
  306. LOG((MSP_ERROR, "CWaveMSPStream::StartStream - "
  307. "Run failed - exit 0x%08x", hr));
  308. return hr;
  309. }
  310. HRESULT hr2 = FireEvent(CALL_STREAM_ACTIVE, hr, CALL_CAUSE_LOCAL_REQUEST);
  311. if ( FAILED(hr2) )
  312. {
  313. LOG((MSP_ERROR, "CWaveMSPStream::StartStream - "
  314. "FireEvent failed - exit 0x%08x", hr2));
  315. return hr2;
  316. }
  317. LOG((MSP_TRACE, "CWaveMSPStream::StartStream - exit S_OK"));
  318. return S_OK;
  319. }
  320. ///////////////////////////////////////////////////////////////////////////////
  321. ///////////////////////////////////////////////////////////////////////////////
  322. //
  323. STDMETHODIMP CWaveMSPStream::PauseStream (void)
  324. {
  325. LOG((MSP_TRACE, "CWaveMSPStream::PauseStream - enter"));
  326. CLock lock(m_lock);
  327. m_DesiredGraphState = State_Paused;
  328. //
  329. // Can't pause the stream if we don't know the waveid.
  330. // (We create our filters on discovery of the waveid.)
  331. //
  332. if ( ! m_fHaveWaveID )
  333. {
  334. LOG((MSP_WARN, "CWaveMSPStream::PauseStream - "
  335. "no waveid so nothing to do yet - exit S_OK"));
  336. return S_OK;
  337. }
  338. //
  339. // Can't pause the stream if no terminal has been selected.
  340. //
  341. if ( 0 == m_Terminals.GetSize() )
  342. {
  343. LOG((MSP_WARN, "CWaveMSPStream::PauseStream - "
  344. "no Terminal so nothing to do yet - exit S_OK"));
  345. return S_OK;
  346. }
  347. //
  348. // Connect the terminal. This does nothing if this call already
  349. // connected the terminal and fails if another call has the
  350. // terminal connected.
  351. //
  352. HRESULT hr;
  353. hr = ConnectTerminal(m_Terminals[0]);
  354. if ( FAILED(hr) )
  355. {
  356. FireEvent(CALL_TERMINAL_FAIL, hr, CALL_CAUSE_CONNECT_FAIL);
  357. FireEvent(CALL_STREAM_FAIL, hr, CALL_CAUSE_CONNECT_FAIL);
  358. LOG((MSP_ERROR, "CWaveMSPStream::StartStream - "
  359. "our ConnectTerminal failed - exit 0x%08x", hr));
  360. return hr;
  361. }
  362. //
  363. // Pause the stream via the base class method.
  364. //
  365. hr = CMSPStream::PauseStream();
  366. if ( FAILED(hr) )
  367. {
  368. FireEvent(CALL_STREAM_FAIL, hr, CALL_CAUSE_UNKNOWN);
  369. LOG((MSP_ERROR, "CWaveMSPStream::PauseStream - "
  370. "Pause failed - exit 0x%08x", hr));
  371. return hr;
  372. }
  373. HRESULT hr2 = FireEvent(CALL_STREAM_INACTIVE, hr, CALL_CAUSE_LOCAL_REQUEST);
  374. if ( FAILED(hr2) )
  375. {
  376. LOG((MSP_ERROR, "CWaveMSPStream::PauseStream - "
  377. "FireEvent failed - exit 0x%08x", hr2));
  378. return hr2;
  379. }
  380. LOG((MSP_TRACE, "CWaveMSPStream::PauseStream - exit S_OK"));
  381. return S_OK;
  382. }
  383. ///////////////////////////////////////////////////////////////////////////////
  384. ///////////////////////////////////////////////////////////////////////////////
  385. //
  386. STDMETHODIMP CWaveMSPStream::StopStream (void)
  387. {
  388. LOG((MSP_TRACE, "CWaveMSPStream::StopStream - enter"));
  389. CLock lock(m_lock);
  390. m_DesiredGraphState = State_Stopped;
  391. //
  392. // Nothing to do if we don't know our waveid.
  393. //
  394. if ( ! m_fHaveWaveID )
  395. {
  396. LOG((MSP_WARN, "CWaveMSPStream::StopStream - "
  397. "no waveid - exit S_OK"));
  398. return S_OK;
  399. }
  400. //
  401. // Nothing to do if no terminal has been selected.
  402. //
  403. if ( 0 == m_Terminals.GetSize() )
  404. {
  405. LOG((MSP_WARN, "CWaveMSPStream::StopStream - "
  406. "no Terminal - exit S_OK"));
  407. return S_OK;
  408. }
  409. //
  410. // Stop the stream via the base class method.
  411. //
  412. HRESULT hr;
  413. hr = CMSPStream::StopStream();
  414. if ( FAILED(hr) )
  415. {
  416. FireEvent(CALL_STREAM_FAIL, hr, CALL_CAUSE_UNKNOWN);
  417. LOG((MSP_ERROR, "CWaveMSPStream::StopStream - "
  418. "Stop failed - exit 0x%08x", hr));
  419. return hr;
  420. }
  421. HRESULT hr2 = FireEvent(CALL_STREAM_INACTIVE, hr, CALL_CAUSE_LOCAL_REQUEST);
  422. if ( FAILED(hr2) )
  423. {
  424. LOG((MSP_ERROR, "CWaveMSPStream::StopStream - "
  425. "FireEvent failed - exit 0x%08x", hr2));
  426. return hr2;
  427. }
  428. LOG((MSP_TRACE, "CWaveMSPStream::StopStream - exit S_OK"));
  429. return S_OK;
  430. }
  431. ///////////////////////////////////////////////////////////////////////////////
  432. ///////////////////////////////////////////////////////////////////////////////
  433. //
  434. HRESULT CWaveMSPStream::SetWaveID(GUID * PermanentGuid)
  435. {
  436. LOG((MSP_TRACE, "CWaveMSPStream::SetWaveID - enter"));
  437. CLock lock(m_lock);
  438. //
  439. // create the correct wave filter
  440. //
  441. HRESULT hr;
  442. hr= TryCreateCSAFilter(
  443. PermanentGuid,
  444. &m_pFilter
  445. );
  446. if (!(SUCCEEDED(hr)))
  447. {
  448. LOG((MSP_ERROR, "CWaveMSPStream::SetWaveID - "
  449. "Filter creation failed - exit 0x%08x", hr));
  450. return hr;
  451. }
  452. //
  453. // Add the filter. Supply a name to make debugging easier.
  454. //
  455. WCHAR * pName = (m_Direction == TD_RENDER) ?
  456. (L"The Stream's WaveIn (on line device)") :
  457. (L"The Stream's WaveOut (on line device)");
  458. hr = m_pIGraphBuilder->AddFilter(m_pFilter, pName);
  459. if (!(SUCCEEDED(hr)))
  460. {
  461. LOG((MSP_ERROR, "CWaveMSPStream::SetWaveID - "
  462. "AddFilter failed - exit 0x%08x", hr));
  463. m_pFilter->Release();
  464. return hr;
  465. }
  466. //
  467. // We now have the wave ID.
  468. //
  469. m_fHaveWaveID = TRUE;
  470. LOG((MSP_TRACE, "CWaveMSPStream::SetWaveID - exit S_OK"));
  471. return S_OK;
  472. }
  473. #if 0
  474. //////////////////////////////////////////////////////////////////////////////
  475. //////////////////////////////////////////////////////////////////////////////
  476. //
  477. // Create the G711 filter, which we will try to connect if direct
  478. // connection fails.
  479. //
  480. void CWaveMSPStream::CreateAndAddG711(void)
  481. {
  482. //
  483. // Create the G711 filter.
  484. //
  485. HRESULT hr;
  486. hr = CoCreateInstance(
  487. CLSID_G711Codec,
  488. NULL,
  489. CLSCTX_INPROC_SERVER,
  490. IID_IBaseFilter,
  491. (void **) &m_pG711Filter
  492. );
  493. if (!(SUCCEEDED(hr)))
  494. {
  495. LOG((MSP_ERROR, "CWaveMSPStream - Failed to create G711 codec: %lx", hr));
  496. //
  497. // Method #2 for connection will not be available.
  498. //
  499. m_pG711Filter = NULL;
  500. return;
  501. }
  502. //
  503. // add the G711 filter
  504. //
  505. hr = m_pIGraphBuilder->AddFilter(
  506. m_pG711Filter,
  507. NULL
  508. );
  509. if (!(SUCCEEDED(hr)))
  510. {
  511. LOG((MSP_ERROR, "CWaveMSPStream - Failed to add G711 filter: %lx", hr));
  512. //
  513. // If we couldn't add it to the graph, then it's useless to us.
  514. // Method #2 for connection will not be available.
  515. //
  516. m_pG711Filter->Release();
  517. m_pG711Filter = NULL;
  518. }
  519. }
  520. //++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
  521. // This function suggests a reasonable buffer size
  522. // on the wave in filter's output pin. It is called right before
  523. // connection.
  524. //++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
  525. // Dialogic said something about small buffers causing problems for their wave
  526. // driver. 20 ms samples were ok on a dual-proc Pentium Pro but caused choppy
  527. // sound followed by silence on a single-proc 166 Pentium. I hate to do this
  528. // but we had better try raising this for compatibility... :(
  529. static const long DESIRED_BUFFER_SIZE_MS = 20; // milliseconds
  530. HRESULT CWaveMSPStream::DecideDesiredCaptureBufferSize(IUnknown * pUnknown,
  531. long * plDesiredSize)
  532. {
  533. LOG((MSP_TRACE, "CWaveMSPStream::DecideDesiredCaptureBufferSize - "
  534. "enter"));
  535. _ASSERTE( ! IsBadReadPtr(pUnknown, sizeof(IUnknown)) );
  536. _ASSERTE( ! IsBadWritePtr(plDesiredSize, sizeof(long)) );
  537. HRESULT hr;
  538. IAMStreamConfig * pConfig = NULL;
  539. hr = pUnknown->QueryInterface(IID_IAMStreamConfig,
  540. (void **) &pConfig
  541. );
  542. if ( FAILED(hr) )
  543. {
  544. LOG((MSP_ERROR, "CWaveMSPStream::DecideDesiredCaptureBufferSize"
  545. " - IAMStreamConfig QI failed on IUnknown 0x%08x; hr = 0x%08x",
  546. pUnknown, hr));
  547. return hr;
  548. }
  549. AM_MEDIA_TYPE * pMediaType;
  550. hr = pConfig->GetFormat(&pMediaType);
  551. pConfig->Release();
  552. if ( FAILED(hr) )
  553. {
  554. LOG((MSP_ERROR, "CWaveMSPStream::DecideDesiredCaptureBufferSize"
  555. " - GetFormat failed; hr = 0x%08x", hr));
  556. return hr;
  557. }
  558. _ASSERTE( pMediaType->cbFormat >= sizeof(WAVEFORMATEX) );
  559. *plDesiredSize = DESIRED_BUFFER_SIZE_MS *
  560. ((WAVEFORMATEX *) (pMediaType->pbFormat) )->nChannels *
  561. ( ((WAVEFORMATEX *) (pMediaType->pbFormat) )->nSamplesPerSec / 1000) *
  562. ( ((WAVEFORMATEX *) (pMediaType->pbFormat) )->wBitsPerSample / 8);
  563. DeleteMediaType(pMediaType);
  564. LOG((MSP_TRACE, "CWaveMSPStream::DecideDesiredCaptureBufferSize - "
  565. "exit S_OK"));
  566. return S_OK;
  567. }
  568. //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  569. // ManipulateAllocatorProperties
  570. //
  571. // This is a helper function that sets up the allocator properties on the
  572. // capture filter, given the interface pointer required for doing so and
  573. // an interface pointer that is used to discover downstream allocator
  574. // requirements.
  575. // we are already in a lock; no need to do locking here.
  576. //
  577. //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  578. HRESULT CWaveMSPStream::ManipulateAllocatorProperties
  579. (IAMBufferNegotiation * pNegotiation,
  580. IMemInputPin * pMemInputPin)
  581. {
  582. LOG((MSP_TRACE, "CWaveMSPStream::ManipulateAllocatorProperties - enter"));
  583. HRESULT hr;
  584. ALLOCATOR_PROPERTIES props;
  585. hr = pMemInputPin->GetAllocatorRequirements(&props);
  586. if ( SUCCEEDED(hr) )
  587. {
  588. LOG((MSP_TRACE, "CWaveMSPStream::ManipulateAllocatorProperties - "
  589. "using downstream allocator requirements"));
  590. }
  591. else
  592. {
  593. LOG((MSP_TRACE, "CWaveMSPStream::ManipulateAllocatorProperties - "
  594. "using our default allocator properties"));
  595. long lDesiredSize = 0;
  596. hr = DecideDesiredCaptureBufferSize(pNegotiation,
  597. &lDesiredSize);
  598. if ( FAILED(hr) )
  599. {
  600. LOG((MSP_ERROR, "CWaveMSPStream::ManipulateAllocatorProperties - "
  601. "DecideDesiredCaptureBufferSize failed - exit 0x%08x", hr));
  602. return hr;
  603. }
  604. props.cBuffers = 32; // we use 32 to avoid starvation, just as we do in the terminal manager.
  605. props.cbBuffer = lDesiredSize;
  606. props.cbAlign = -1; // means "default"
  607. props.cbPrefix = -1; // means "default"
  608. }
  609. hr = pNegotiation->SuggestAllocatorProperties(&props);
  610. if ( FAILED(hr) )
  611. {
  612. LOG((MSP_ERROR, "CWaveMSPStream::ManipulateAllocatorProperties - "
  613. "SuggestAllocatorProperties failed - exit 0x%08x", hr));
  614. return hr;
  615. }
  616. LOG((MSP_TRACE, "CWaveMSPStream::ManipulateAllocatorProperties - "
  617. "exit S_OK"));
  618. return S_OK;
  619. }
  620. //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  621. // SetupWaveIn
  622. //
  623. // This is a helper function that sets up the allocator properties on the
  624. // capture filter, given the terminal's pin and our filter's pin. This
  625. // involves deciding where the capture interfaces should be found, checkin
  626. // if the downstream filters have allocator requirements, and then applying
  627. // either these requirements or our default requirements to the capture
  628. // filter.
  629. // we are already in a lock; no need to do locking here.
  630. //
  631. //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  632. HRESULT CWaveMSPStream::SetupWaveIn( IPin * pOutputPin,
  633. IPin * pInputPin )
  634. {
  635. LOG((MSP_TRACE, "CWaveMSPStream::SetupWaveIn - enter"));
  636. //
  637. // Ask the output pin for its buffer negotiation interface.
  638. //
  639. HRESULT hr;
  640. IAMBufferNegotiation * pNegotiation;
  641. hr = pOutputPin->QueryInterface(IID_IAMBufferNegotiation,
  642. (void **) &pNegotiation);
  643. if ( FAILED(hr) )
  644. {
  645. LOG((MSP_ERROR, "IAMBufferNegotiation QI failed - hr = 0x%08x", hr));
  646. return hr;
  647. }
  648. //
  649. // Ask the input pin for its meminputpin interface.
  650. //
  651. IMemInputPin * pMemInputPin;
  652. hr = pInputPin->QueryInterface(IID_IMemInputPin,
  653. (void **) &pMemInputPin);
  654. if ( FAILED(hr) )
  655. {
  656. LOG((MSP_ERROR, "IMemInputPin QI failed - hr = 0x%08x", hr));
  657. pNegotiation->Release();
  658. return hr;
  659. }
  660. //
  661. // now set the properties on the negotiation interface, depending
  662. // on the properties that are set on the meminputpin interface
  663. //
  664. hr = ManipulateAllocatorProperties(pNegotiation, pMemInputPin);
  665. pNegotiation->Release();
  666. pMemInputPin->Release();
  667. if ( FAILED(hr) )
  668. {
  669. LOG((MSP_ERROR, "ManipulateAllocatorProperties - hr = 0x%08x", hr));
  670. return hr;
  671. }
  672. LOG((MSP_TRACE, "CWaveMSPStream::SetupWaveIn - exit S_OK"));
  673. return S_OK;
  674. }
  675. #endif
  676. //++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
  677. //
  678. // This function is for debugging purposes only. It pops up a
  679. // couple of message boxes telling you various information about
  680. // media formats and allocator properties. It's called after
  681. // connection has taken place. pPin is the output pin of the
  682. // wavein filter.
  683. //
  684. //++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
  685. HRESULT CWaveMSPStream::ExamineWaveInProperties(IPin *pPin)
  686. {
  687. LOG((MSP_TRACE, "CWaveMSPStream::ExamineWaveInProperties - enter"));
  688. HRESULT hr;
  689. IAMBufferNegotiation * pNegotiation = NULL;
  690. hr = pPin->QueryInterface(IID_IAMBufferNegotiation,
  691. (void **) &pNegotiation
  692. );
  693. if ( FAILED(hr) )
  694. {
  695. LOG((MSP_ERROR, "CWaveMSPStream::ExamineWaveInProperties - "
  696. "IAMBufferNegotiation QI failed on pin 0x%08x; hr = 0x%08x",
  697. pPin, hr));
  698. return hr;
  699. }
  700. ALLOCATOR_PROPERTIES prop;
  701. hr = pNegotiation->GetAllocatorProperties(&prop);
  702. pNegotiation->Release();
  703. if ( FAILED(hr) )
  704. {
  705. LOG((MSP_ERROR, "CWaveMSPStream::ExamineWaveInProperties - "
  706. "GetAllocatorProperties failed; hr = 0x%08x",
  707. hr));
  708. return hr;
  709. }
  710. LOG((MSP_TRACE, "GetAllocatorProperties info:\n"
  711. "buffer count: %d\n"
  712. "size of each buffer: %d bytes\n"
  713. "alignment multiple: %d\n"
  714. "each buffer has a prefix: %d bytes",
  715. prop.cBuffers,
  716. prop.cbBuffer,
  717. prop.cbAlign,
  718. prop.cbPrefix
  719. ));
  720. IAMStreamConfig * pConfig = NULL;
  721. hr = pPin->QueryInterface(IID_IAMStreamConfig,
  722. (void **) &pConfig
  723. );
  724. if ( FAILED(hr) )
  725. {
  726. LOG((MSP_ERROR, "CWaveMSPStream::ExamineWaveInProperties - "
  727. "IAMStreamConfig QI failed on pin 0x%08x; hr = 0x%08x", pPin, hr));
  728. return hr;
  729. }
  730. AM_MEDIA_TYPE * pMediaType;
  731. hr = pConfig->GetFormat(&pMediaType);
  732. pConfig->Release();
  733. if ( FAILED(hr) )
  734. {
  735. LOG((MSP_ERROR, "CWaveMSPStream::ExamineWaveInProperties - "
  736. "GetFormat failed; hr = 0x%08x", hr));
  737. return hr;
  738. }
  739. _ASSERTE( pMediaType->cbFormat >= sizeof(WAVEFORMATEX) );
  740. LOG((MSP_TRACE, "GetFormat info:\n"
  741. "sample size: %d bytes\n"
  742. "channels: %d\n"
  743. "samples per second: %d\n"
  744. "bits per sample: %d\n",
  745. pMediaType->lSampleSize,
  746. ((WAVEFORMATEX *) (pMediaType->pbFormat) )->nChannels,
  747. ((WAVEFORMATEX *) (pMediaType->pbFormat) )->nSamplesPerSec,
  748. ((WAVEFORMATEX *) (pMediaType->pbFormat) )->wBitsPerSample
  749. ));
  750. DeleteMediaType(pMediaType);
  751. LOG((MSP_TRACE, "CWaveMSPStream::ExamineWaveInProperties - "
  752. "exit S_OK"));
  753. return S_OK;
  754. }
  755. ///////////////////////////////////////////////////////////////////////////////
  756. ///////////////////////////////////////////////////////////////////////////////
  757. //
  758. // Add the terminal to the graph and connect it to our
  759. // filters, if it is not already in use.
  760. //
  761. HRESULT CWaveMSPStream::ConnectTerminal(ITTerminal * pTerminal)
  762. {
  763. LOG((MSP_TRACE, "CWaveMSPStream::ConnectTerminal - enter"));
  764. //
  765. // Find out the terminal's internal state.
  766. //
  767. TERMINAL_STATE state;
  768. HRESULT hr;
  769. hr = pTerminal->get_State( &state );
  770. if ( FAILED(hr) )
  771. {
  772. LOG((MSP_ERROR, "CWaveMSPStream::ConnectTerminal - "
  773. "get_State on terminal failed - exit 0x%08x", hr));
  774. return hr;
  775. }
  776. //
  777. // If we've already connected the terminal on this stream, then
  778. // there is nothing for us to do. Just assert that the terminal
  779. // also thinks it's connected.
  780. //
  781. if ( m_fTerminalConnected )
  782. {
  783. _ASSERTE( state == TS_INUSE );
  784. LOG((MSP_ERROR, "CWaveMSPStream::ConnectTerminal - "
  785. "terminal already connected on this stream - exit S_OK"));
  786. return S_OK;
  787. }
  788. //
  789. // Otherwise we need to connect the terminal on this call. If the
  790. // terminal is already connected on another call, we must fail. Note
  791. // that since we are making several calls on the terminal here, the
  792. // terminal could become connected on another call while we are
  793. // in the process of doing this. If this happens, the we will just fail
  794. // later.
  795. //
  796. if ( state == TS_INUSE )
  797. {
  798. LOG((MSP_ERROR, "CWaveMSPStream::ConnectTerminal - "
  799. "terminal in use - exit TAPI_E_TERMINALINUSE"));
  800. return TAPI_E_TERMINALINUSE;
  801. }
  802. //
  803. // Get the ITTerminalControl interface.
  804. //
  805. ITTerminalControl * pTerminalControl;
  806. hr = m_Terminals[0]->QueryInterface(IID_ITTerminalControl,
  807. (void **) &pTerminalControl);
  808. if ( FAILED(hr) )
  809. {
  810. LOG((MSP_ERROR, "CWaveMSPStream::ConnectTerminal - "
  811. "QI for ITTerminalControl failed - exit 0x%08x", hr));
  812. return hr;
  813. }
  814. //
  815. // Find out how many pins the terminal has. If not one then bail as
  816. // we have no idea what to do with multiple-pin terminals at this point.
  817. //
  818. DWORD dwNumPinsAvailable;
  819. hr = pTerminalControl->ConnectTerminal(m_pIGraphBuilder,
  820. m_Direction,
  821. &dwNumPinsAvailable,
  822. NULL);
  823. if ( FAILED(hr) )
  824. {
  825. LOG((MSP_ERROR, "CWaveMSPStream::ConnectTerminal - "
  826. "query for number of terminal pins failed - exit 0x%08x", hr));
  827. pTerminalControl->Release();
  828. return hr;
  829. }
  830. if ( 1 != dwNumPinsAvailable )
  831. {
  832. LOG((MSP_ERROR, "CWaveMSPStream::ConnectTerminal - "
  833. "unsupported number of terminal pins - exit E_FAIL"));
  834. pTerminalControl->Release();
  835. return E_FAIL;
  836. }
  837. IPin * pTerminalPin;
  838. //
  839. // Actually connect the terminal.
  840. //
  841. hr = pTerminalControl->ConnectTerminal(m_pIGraphBuilder,
  842. m_Direction,
  843. &dwNumPinsAvailable,
  844. &pTerminalPin);
  845. if ( FAILED(hr) )
  846. {
  847. pTerminalControl->Release();
  848. LOG((MSP_ERROR, "CWaveMSPStream::ConnectTerminal - "
  849. "ConnectTerminal on terminal failed - exit 0x%08x", hr));
  850. return hr;
  851. }
  852. if (IsBadReadPtr(pTerminalPin,sizeof(IPin))) {
  853. //
  854. // bad pin
  855. //
  856. pTerminalControl->Release();
  857. LOG((MSP_ERROR, "CWaveMSPStream::ConnectTerminal - "
  858. "bad IPin returned from ConnectTerminal"));
  859. return E_POINTER;
  860. }
  861. //
  862. // Now make the connection between our filters and the terminal's pin.
  863. //
  864. hr = ConnectToTerminalPin(pTerminalPin);
  865. pTerminalPin->Release();
  866. if ( FAILED(hr) )
  867. {
  868. pTerminalControl->DisconnectTerminal(m_pIGraphBuilder, 0);
  869. pTerminalControl->Release();
  870. LOG((MSP_ERROR, "CWaveMSPStream::ConnectTerminal - "
  871. "ConnectToTerminalPin failed - exit 0x%08x", hr));
  872. return hr;
  873. }
  874. //
  875. // Now we are actually connected. Update our state and perform postconnection
  876. // (ignore postconnection error code).
  877. //
  878. m_fTerminalConnected = TRUE;
  879. pTerminalControl->CompleteConnectTerminal();
  880. pTerminalControl->Release();
  881. LOG((MSP_TRACE, "CWaveMSPStream::ConnectTerminal - exit S_OK"));
  882. return S_OK;
  883. }
  884. //++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
  885. //
  886. // Tries to connect the waveOut filter. First it tries a
  887. // direct connection, then with an intermediate G711
  888. // codec, then an intelligent connect which may draw in
  889. // more filters.
  890. //++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
  891. void ShowMediaTypes(IEnumMediaTypes * pEnum)
  892. {
  893. AM_MEDIA_TYPE * pMediaType;
  894. while (pEnum->Next(1, &pMediaType, NULL) == S_OK)
  895. {
  896. if ( pMediaType->cbFormat < sizeof(WAVEFORMATEX) )
  897. {
  898. LOG((MSP_TRACE, "*** Media Type: *** non-wave"));
  899. }
  900. else
  901. {
  902. LOG((MSP_TRACE,"*** Media Type: *** "
  903. "sample size: %d bytes *** "
  904. "channels: %d *** "
  905. "samples per second: %d *** "
  906. "bits per sample: %d",
  907. pMediaType->lSampleSize,
  908. ((WAVEFORMATEX *) (pMediaType->pbFormat) )->nChannels,
  909. ((WAVEFORMATEX *) (pMediaType->pbFormat) )->nSamplesPerSec,
  910. ((WAVEFORMATEX *) (pMediaType->pbFormat) )->wBitsPerSample
  911. ));
  912. }
  913. DeleteMediaType(pMediaType);
  914. }
  915. }
  916. HRESULT CWaveMSPStream::TryToConnect(
  917. IPin * pOutputPin, // on the capture filter or terminal
  918. IPin * pInputPin // on the render filter or terminal
  919. )
  920. {
  921. LOG((MSP_TRACE, "TryToConnect - enter"));
  922. HRESULT hr;
  923. IEnumMediaTypes * pEnum;
  924. hr = pOutputPin->EnumMediaTypes(&pEnum);
  925. if (SUCCEEDED(hr))
  926. {
  927. LOG((MSP_TRACE, "Output pin media types:"));
  928. ShowMediaTypes(pEnum);
  929. pEnum->Release();
  930. }
  931. hr = pInputPin->EnumMediaTypes(&pEnum);
  932. if (SUCCEEDED(hr))
  933. {
  934. LOG((MSP_TRACE, "Input pin media types:"));
  935. ShowMediaTypes(pEnum);
  936. pEnum->Release();
  937. }
  938. //
  939. // Method 1: direct connection
  940. //
  941. hr = m_pIGraphBuilder->ConnectDirect(
  942. pOutputPin,
  943. pInputPin,
  944. NULL
  945. );
  946. if ( SUCCEEDED(hr) )
  947. {
  948. LOG((MSP_TRACE, "TryToConnect: direct connection worked - exit S_OK"));
  949. return S_OK;
  950. }
  951. LOG((MSP_ERROR, "TryToConnect - direct connection failed - %lx", hr));
  952. //
  953. // Method 1.5: work around DirectShow bug for Unimodem.
  954. // Try 8 KHz 16-bit mono explicitly
  955. //
  956. AM_MEDIA_TYPE MediaType;
  957. WAVEFORMATEX WaveFormatEx;
  958. MediaType.majortype = MEDIATYPE_Audio;
  959. MediaType.subtype = MEDIASUBTYPE_PCM;
  960. MediaType.bFixedSizeSamples = TRUE;
  961. MediaType.bTemporalCompression = FALSE;
  962. MediaType.lSampleSize = 2;
  963. MediaType.formattype = FORMAT_WaveFormatEx;
  964. MediaType.pUnk = NULL;
  965. MediaType.cbFormat = sizeof( WAVEFORMATEX );
  966. MediaType.pbFormat = (LPBYTE) & WaveFormatEx;
  967. WaveFormatEx.wFormatTag = WAVE_FORMAT_PCM;
  968. WaveFormatEx.nChannels = 1;
  969. WaveFormatEx.nSamplesPerSec = 8000;
  970. WaveFormatEx.nAvgBytesPerSec = 16000;
  971. WaveFormatEx.nBlockAlign = 2;
  972. WaveFormatEx.wBitsPerSample = 16;
  973. WaveFormatEx.cbSize = 0;
  974. IAMStreamConfig * pConfig;
  975. hr = pOutputPin->QueryInterface(IID_IAMStreamConfig,
  976. (void **) &pConfig
  977. );
  978. if ( FAILED(hr) )
  979. {
  980. LOG((MSP_ERROR, "CWaveMSPStream::TryToConnect"
  981. " - IAMStreamConfig QI failed on output pin 0x%08x; hr = 0x%08x",
  982. pOutputPin, hr));
  983. }
  984. else
  985. {
  986. AM_MEDIA_TYPE * pOldMediaType;
  987. hr = pConfig->GetFormat(&pOldMediaType);
  988. if ( FAILED(hr) )
  989. {
  990. LOG((MSP_ERROR, "CWaveMSPStream::TryToConnect - "
  991. "GetFormat failed - 0x%08x", hr));
  992. }
  993. else
  994. {
  995. // Suggest the new format. If it fails, we want to know about it
  996. // as something is wrong.
  997. hr = pConfig->SetFormat(&MediaType);
  998. if ( FAILED(hr) )
  999. {
  1000. LOG((MSP_ERROR, "CWaveMSPStream::TryToConnect - "
  1001. "SetFormat failed - 0x%08x", hr));
  1002. }
  1003. else
  1004. {
  1005. hr = m_pIGraphBuilder->ConnectDirect(
  1006. pOutputPin,
  1007. pInputPin,
  1008. &MediaType
  1009. );
  1010. if ( SUCCEEDED(hr) )
  1011. {
  1012. LOG((MSP_TRACE, "TryToConnect: direct connection with explicit "
  1013. "WaveIn 8KHz 16-bit setting worked - exit S_OK"));
  1014. DeleteMediaType(pOldMediaType);
  1015. pConfig->Release();
  1016. return S_OK;
  1017. }
  1018. else
  1019. {
  1020. // restore old type, best effort
  1021. hr = pConfig->SetFormat(pOldMediaType);
  1022. if ( FAILED(hr) )
  1023. {
  1024. LOG((MSP_ERROR, "CWaveMSPStream::TryToConnect - "
  1025. "SetFormat failed to restore old type - 0x%08x", hr));
  1026. }
  1027. }
  1028. }
  1029. DeleteMediaType(pOldMediaType);
  1030. }
  1031. pConfig->Release();
  1032. }
  1033. #if 0
  1034. LOG((MSP_ERROR, "TryToConnect - direct connection with explicit "
  1035. "WaveIn 8KHz 16-bit setting failed - %lx", hr));
  1036. //
  1037. // Method 2: direct connection with G711 filter in between.
  1038. // If we haven't created and added the G711 filter to the graph yet,
  1039. // do so now.
  1040. //
  1041. if ( ! m_pG711Filter )
  1042. {
  1043. CreateAndAddG711();
  1044. }
  1045. //
  1046. // If the CreateAndAddG711 method worked, now or previously, then try to
  1047. // use the G711.
  1048. //
  1049. if (m_pG711Filter)
  1050. {
  1051. IPin * pG711InputPin = NULL;
  1052. hr = FindPinInFilter(
  1053. false, // want input pin
  1054. m_pG711Filter,
  1055. &pG711InputPin
  1056. );
  1057. if ( SUCCEEDED(hr) )
  1058. {
  1059. hr = m_pIGraphBuilder->ConnectDirect(
  1060. pOutputPin,
  1061. pG711InputPin,
  1062. NULL
  1063. );
  1064. // We don't release the G711's input pin here because we must
  1065. // hang onto it in order to break the connection if any of the
  1066. // subsequent steps fail.
  1067. if ( SUCCEEDED(hr) )
  1068. {
  1069. IPin * pG711OutputPin = NULL;
  1070. hr = FindPinInFilter(
  1071. true, // want output pin
  1072. m_pG711Filter,
  1073. &pG711OutputPin
  1074. );
  1075. if ( SUCCEEDED(hr) )
  1076. {
  1077. hr = m_pIGraphBuilder->ConnectDirect(
  1078. pG711OutputPin,
  1079. pInputPin,
  1080. NULL
  1081. );
  1082. pG711OutputPin->Release();
  1083. if ( SUCCEEDED(hr) )
  1084. {
  1085. LOG((MSP_TRACE, "TryToConnect - G711 connection succeeded - exit S_OK"));
  1086. // Held onto this in case of failure... see above
  1087. pG711InputPin->Release();
  1088. return S_OK;
  1089. }
  1090. else
  1091. {
  1092. LOG((MSP_ERROR, "TryToConnect - could not connect "
  1093. "G711 codec's output pin - %lx", hr));
  1094. }
  1095. }
  1096. else
  1097. {
  1098. LOG((MSP_ERROR, "TryToConnect - could not find "
  1099. "G711 codec's input pin - %lx", hr));
  1100. }
  1101. if ( FAILED(hr) )
  1102. {
  1103. //
  1104. // The first G711 connection succeeded but something else
  1105. // subsequently failed. This means we must disconnect the left
  1106. // end of the G711 filter. Luckily, we held onto the G711 filter's
  1107. // input pin above. We must disconnect the them here, otherwise
  1108. // method #3 won't work.
  1109. //
  1110. hr = m_pIGraphBuilder->Disconnect(pOutputPin);
  1111. LOG((MSP_ERROR, "TryToConnect - error undoing what we did - could not "
  1112. "disconnect the wave filter's output pin! hr = 0x%08x", hr));
  1113. hr = m_pIGraphBuilder->Disconnect(pG711InputPin);
  1114. LOG((MSP_ERROR, "TryToConnect - error undoing what we did - could not "
  1115. "disconnect the wave filter's output pin! hr = 0x%08x", hr));
  1116. //
  1117. // Now we no longer need to talk to the pin...
  1118. //
  1119. pG711InputPin->Release();
  1120. //
  1121. // And the G711 filter itself sticks around in the graph for next time.
  1122. //
  1123. }
  1124. }
  1125. else
  1126. {
  1127. LOG((MSP_ERROR, "TryToConnect - could not connect "
  1128. "G711 codec's input pin - %lx", hr));
  1129. }
  1130. }
  1131. else
  1132. {
  1133. LOG((MSP_ERROR, "TryToConnect - could not find "
  1134. "G711 codec's input pin - %lx", hr));
  1135. }
  1136. }
  1137. else
  1138. {
  1139. hr = E_FAIL;
  1140. LOG((MSP_ERROR, "TryToConnect - G711 codec does not exist"));
  1141. }
  1142. LOG((MSP_TRACE, "TryToConnect - G711 connection failed - %lx", hr));
  1143. //
  1144. // Method 3: intelligent connection, which may pull in who knows what other filters
  1145. //
  1146. #ifdef ALLOW_INTELLIGENT_CONNECTION
  1147. hr = m_pIGraphBuilder->Connect(
  1148. pOutputPin,
  1149. pInputPin
  1150. );
  1151. #else // ALLOW_INTELLIGENT_CONNECTION
  1152. LOG((MSP_ERROR, "TryToConnect - NOTE: we never allow intelligent connection"));
  1153. hr = E_FAIL;
  1154. #endif // ALLOW_INTELLIGENT_CONNECTION
  1155. #endif
  1156. if ( FAILED(hr) )
  1157. {
  1158. LOG((MSP_ERROR, "TryToConnect - intelligent connection failed - %lx", hr));
  1159. return hr;
  1160. }
  1161. LOG((MSP_TRACE, "TryToConnect: intelligent connection worked - exit S_OK"));
  1162. return S_OK;
  1163. }
  1164. //////////////////////////////////////////////////////////////////////////////
  1165. //////////////////////////////////////////////////////////////////////////////
  1166. HRESULT CWaveMSPStream::ConnectToTerminalPin(IPin * pTerminalPin)
  1167. {
  1168. LOG((MSP_TRACE, "CWaveMSPStream::ConnectToTerminalPin - enter"));
  1169. HRESULT hr = S_OK;
  1170. IPin * pMyPin;
  1171. hr = FindPin( &pMyPin );
  1172. if (!SUCCEEDED(hr))
  1173. {
  1174. LOG((MSP_ERROR, "CWaveMSPStream::ConnectToTerminalPin - "
  1175. "could not find pin - exit 0x%08x", hr));
  1176. return hr; // we can't continue without this pin
  1177. }
  1178. // The OUTPUT pin from WAVEIN; the INPUT pin from WAVEOUT
  1179. IPin * pOutputPin = ( m_Direction == TD_RENDER ) ? pMyPin : pTerminalPin;
  1180. IPin * pInputPin = ( m_Direction == TD_CAPTURE ) ? pMyPin : pTerminalPin;
  1181. #if 0
  1182. // don't care if this fails
  1183. SetupWaveIn(pOutputPin,
  1184. pInputPin);
  1185. #endif
  1186. hr = TryToConnect(pOutputPin,
  1187. pInputPin);
  1188. if ( SUCCEEDED(hr) )
  1189. {
  1190. // don't care if this fails...
  1191. ExamineWaveInProperties(pOutputPin);
  1192. }
  1193. pMyPin->Release();
  1194. if ( FAILED(hr) )
  1195. {
  1196. LOG((MSP_ERROR, "CWaveMSPStream::ConnectToTerminalPin - "
  1197. "could not connect to pin - exit 0x%08x", hr));
  1198. return hr;
  1199. }
  1200. LOG((MSP_TRACE, "CWaveMSPStream::ConnectToTerminalPin - exit S_OK"));
  1201. return S_OK;
  1202. }
  1203. //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  1204. HRESULT CWaveMSPStream::FindPinInFilter(
  1205. BOOL bWantOutputPin, // IN: if false, we want the input pin
  1206. IBaseFilter * pFilter, // IN: the filter to examine
  1207. IPin ** ppPin // OUT: the pin we found
  1208. )
  1209. {
  1210. HRESULT hr;
  1211. IEnumPins * pEnumPins;
  1212. *ppPin = NULL;
  1213. // enumerate the pins on the filter
  1214. hr = pFilter->EnumPins( &pEnumPins );
  1215. if (!(SUCCEEDED(hr)))
  1216. {
  1217. return hr;
  1218. }
  1219. // go through the pins
  1220. while (TRUE)
  1221. {
  1222. PIN_DIRECTION pd;
  1223. hr = pEnumPins->Next( 1, ppPin, NULL );
  1224. if (S_OK != hr)
  1225. {
  1226. // didn't find a pin!
  1227. break;
  1228. }
  1229. // get the pin info
  1230. hr = (*ppPin)->QueryDirection( &pd );
  1231. // does it meet the criteria?
  1232. if (bWantOutputPin && (pd == PINDIR_OUTPUT))
  1233. {
  1234. // yes
  1235. break;
  1236. }
  1237. if ( ! bWantOutputPin && (pd == PINDIR_INPUT))
  1238. {
  1239. // yes
  1240. break;
  1241. }
  1242. (*ppPin)->Release();
  1243. *ppPin = NULL;
  1244. }
  1245. pEnumPins->Release();
  1246. if (NULL == *ppPin)
  1247. {
  1248. // error
  1249. return E_FAIL;
  1250. }
  1251. return S_OK;
  1252. }
  1253. //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  1254. // FindPin
  1255. //
  1256. // Finds the first pin in the filter that meets criteria.
  1257. // For bWaveIn == TRUE, the pin must be direction PINDIR_OUTPUT
  1258. // For bWaveIn == FALSE, the pin must be direction PINDIR_INPUT
  1259. //
  1260. //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  1261. HRESULT
  1262. CWaveMSPStream::FindPin(
  1263. IPin ** ppPin
  1264. )
  1265. {
  1266. return FindPinInFilter(m_Direction == TD_RENDER,
  1267. m_pFilter,
  1268. ppPin);
  1269. }
  1270. //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  1271. //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  1272. //
  1273. // ProcessGraphEvent
  1274. //
  1275. // Sends an event to the app when we get an event from the filter graph.
  1276. //
  1277. //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  1278. HRESULT CWaveMSPStream::ProcessGraphEvent(
  1279. IN long lEventCode,
  1280. IN LONG_PTR lParam1,
  1281. IN LONG_PTR lParam2
  1282. )
  1283. {
  1284. LOG((MSP_EVENT, "CWaveMSPStream::ProcessGraphEvent - enter"));
  1285. HRESULT hr = S_OK;
  1286. switch (lEventCode)
  1287. {
  1288. case EC_COMPLETE:
  1289. hr = FireEvent(CALL_STREAM_INACTIVE, (HRESULT) lParam1, CALL_CAUSE_UNKNOWN);
  1290. break;
  1291. case EC_USERABORT:
  1292. hr = FireEvent(CALL_STREAM_INACTIVE, S_OK, CALL_CAUSE_UNKNOWN);
  1293. break;
  1294. case EC_ERRORABORT:
  1295. case EC_STREAM_ERROR_STOPPED:
  1296. case EC_STREAM_ERROR_STILLPLAYING:
  1297. case EC_ERROR_STILLPLAYING:
  1298. hr = FireEvent(CALL_STREAM_FAIL, (HRESULT) lParam1, CALL_CAUSE_UNKNOWN);
  1299. break;
  1300. default:
  1301. LOG((MSP_EVENT, "CWaveMSPStream::ProcessGraphEvent - "
  1302. "ignoring event code %d", lEventCode));
  1303. break;
  1304. }
  1305. if ( FAILED(hr) )
  1306. {
  1307. LOG((MSP_ERROR, "CWaveMSPStream::ProcessGraphEvent - "
  1308. "FireEvent failed - exit 0x%08x", hr));
  1309. return hr;
  1310. }
  1311. LOG((MSP_EVENT, "CWaveMSPStream::ProcessGraphEvent - exit S_OK"));
  1312. return S_OK;
  1313. }
  1314. HRESULT CWaveMSPStream::FireEvent(
  1315. IN MSP_CALL_EVENT type,
  1316. IN HRESULT hrError,
  1317. IN MSP_CALL_EVENT_CAUSE cause
  1318. )
  1319. {
  1320. LOG((MSP_EVENT, "CWaveMSPStream::FireEvent - enter"));
  1321. //
  1322. // First, need to check if the call is shutting down. This is important
  1323. // because UnselectTerminal can fire an event, and UnselectTerminal can
  1324. // be called within ITStream::Shutdown. We can safely discard such
  1325. // events because there is nothing the app can do with them anyway.
  1326. //
  1327. // Note on locking: It is convenient to check the m_pMSPCall here
  1328. // and we don't use it until the end of the method, so we simply lock
  1329. // during the entire method. This could be optimized at the expense of
  1330. // some code complexity; note that we also need to lock while accessing
  1331. // m_Terminals.
  1332. //
  1333. CLock lock(m_lock);
  1334. if ( m_pMSPCall == NULL )
  1335. {
  1336. LOG((MSP_EVENT, "FireEvent - call is shutting down; dropping event - exit S_OK"));
  1337. return S_OK;
  1338. }
  1339. //
  1340. // Create the event structure. Must use "new" as it will be
  1341. // "delete"d later.
  1342. //
  1343. MSPEVENTITEM * pEventItem = AllocateEventItem();
  1344. if (pEventItem == NULL)
  1345. {
  1346. LOG((MSP_ERROR, "CWaveMSPStream::FireEvent - "
  1347. "can't create MSPEVENTITEM structure - exit E_OUTOFMEMORY"));
  1348. return E_OUTOFMEMORY;
  1349. }
  1350. //
  1351. // Fill in the necessary fields for the event structure.
  1352. //
  1353. pEventItem->MSPEventInfo.dwSize = sizeof(MSP_EVENT_INFO);
  1354. pEventItem->MSPEventInfo.Event = ME_CALL_EVENT;
  1355. ITTerminal * pTerminal = NULL;
  1356. if ( 0 != m_Terminals.GetSize() )
  1357. {
  1358. _ASSERTE( 1 == m_Terminals.GetSize() );
  1359. pTerminal = m_Terminals[0];
  1360. pTerminal->AddRef();
  1361. }
  1362. ITStream * pStream = (ITStream *) this;
  1363. pStream->AddRef();
  1364. pEventItem->MSPEventInfo.MSP_CALL_EVENT_INFO.Type = type;
  1365. pEventItem->MSPEventInfo.MSP_CALL_EVENT_INFO.Cause = cause;
  1366. pEventItem->MSPEventInfo.MSP_CALL_EVENT_INFO.pStream = pStream;
  1367. pEventItem->MSPEventInfo.MSP_CALL_EVENT_INFO.pTerminal = pTerminal;
  1368. pEventItem->MSPEventInfo.MSP_CALL_EVENT_INFO.hrError = hrError;
  1369. //
  1370. // Send the event to the app.
  1371. //
  1372. HRESULT hr = m_pMSPCall->HandleStreamEvent(pEventItem);
  1373. if (FAILED(hr))
  1374. {
  1375. LOG((MSP_ERROR, "CWaveMSPStream::FireEvent - "
  1376. "HandleStreamEvent failed - returning 0x%08x", hr));
  1377. pStream->Release();
  1378. pTerminal->Release();
  1379. FreeEventItem(pEventItem);
  1380. return hr;
  1381. }
  1382. LOG((MSP_EVENT, "CWaveMSPStream::FireEvent - exit S_OK"));
  1383. return S_OK;
  1384. }
  1385. DEFINE_GUID(CLSID_Proxy,
  1386. 0x17CCA71BL, 0xECD7, 0x11D0, 0xB9, 0x08, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96);
  1387. DEFINE_GUID(CLSID_WDM_RENDER,
  1388. 0x65E8773EL, 0x8F56, 0x11D0, 0xA3, 0xB9, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96);
  1389. // {F420CB9C-B19D-11d2-A286-00C04F8EC951}
  1390. DEFINE_GUID(KSPROPSETID_MODEMCSA,
  1391. 0xf420cb9c, 0xb19d, 0x11d2, 0xa2, 0x86, 0x0, 0xc0, 0x4f, 0x8e, 0xc9, 0x51);
  1392. HRESULT
  1393. CheckFilterPropery(
  1394. IBaseFilter *CsaFilter,
  1395. const GUID *GuidToMatch
  1396. )
  1397. {
  1398. IKsPropertySet *pKsPropSet = NULL;
  1399. HRESULT hr = S_OK;
  1400. GUID PermanentGuid;
  1401. hr = CsaFilter->QueryInterface(IID_IKsPropertySet,
  1402. (void **)&pKsPropSet);
  1403. if (SUCCEEDED(hr)) {
  1404. DWORD BytesReturned;
  1405. hr = pKsPropSet->Get(KSPROPSETID_MODEMCSA,
  1406. 0,
  1407. NULL,
  1408. 0,
  1409. (LPVOID)&PermanentGuid,
  1410. sizeof(PermanentGuid),
  1411. &BytesReturned
  1412. );
  1413. pKsPropSet->Release();
  1414. if (IsEqualGUID((PermanentGuid), *GuidToMatch)) {
  1415. hr=S_OK;
  1416. } else {
  1417. hr=E_FAIL;
  1418. }
  1419. }
  1420. return hr;
  1421. }
  1422. HRESULT
  1423. FindModemCSA(
  1424. IN GUID *PermanentGuid,
  1425. IBaseFilter ** ppFilter
  1426. )
  1427. {
  1428. ICreateDevEnum *pCreateDevEnum;
  1429. HRESULT hr;
  1430. //
  1431. // create system device enumerator
  1432. //
  1433. hr = CoCreateInstance(
  1434. CLSID_SystemDeviceEnum,
  1435. NULL,
  1436. CLSCTX_INPROC_SERVER,
  1437. IID_ICreateDevEnum,
  1438. (void**)&pCreateDevEnum
  1439. );
  1440. if (SUCCEEDED(hr)) {
  1441. IEnumMoniker *pEnumMoniker = NULL;
  1442. hr = pCreateDevEnum->CreateClassEnumerator(
  1443. CLSID_WDM_RENDER,
  1444. &pEnumMoniker,
  1445. 0
  1446. );
  1447. pCreateDevEnum->Release();
  1448. if (hr == S_OK) {
  1449. pEnumMoniker->Reset();
  1450. while( NULL == *ppFilter ) {
  1451. IMoniker *pMon;
  1452. VARIANT var;
  1453. hr = pEnumMoniker->Next(1, &pMon, NULL);
  1454. if ( S_OK != hr ) {
  1455. break;
  1456. }
  1457. // Bind to selected device
  1458. hr = pMon->BindToObject( 0, 0, IID_IBaseFilter, (void**)ppFilter );
  1459. pMon->Release();
  1460. if (SUCCEEDED(hr)) {
  1461. hr=CheckFilterPropery(
  1462. *ppFilter,
  1463. PermanentGuid
  1464. );
  1465. if (SUCCEEDED(hr)) {
  1466. break;
  1467. } else {
  1468. (*ppFilter)->Release();
  1469. *ppFilter=NULL;
  1470. }
  1471. }
  1472. }
  1473. }
  1474. }
  1475. return hr;
  1476. }
  1477. HRESULT
  1478. TryCreateCSAFilter(
  1479. IN GUID *PermanentGuid,
  1480. OUT IBaseFilter **ppCSAFilter
  1481. )
  1482. {
  1483. HRESULT hr = E_UNEXPECTED;
  1484. if (ppCSAFilter != NULL)
  1485. {
  1486. *ppCSAFilter=NULL;
  1487. hr = FindModemCSA(PermanentGuid,ppCSAFilter);
  1488. }
  1489. return hr;
  1490. }
  1491. // eof