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.

880 lines
25 KiB

  1. /*++
  2. Copyright (c) 1998-1999 Microsoft Corporation
  3. Module Name:
  4. msptrmar.cpp
  5. Abstract:
  6. MSP base classes: implementation of audio render terminal.
  7. --*/
  8. #include "precomp.h"
  9. #pragma hdrstop
  10. #include <mmsystem.h>
  11. // Filter volume level ranges
  12. const long AX_MIN_VOLUME = -9640; // -10000;
  13. const long AX_MAX_VOLUME = 0;
  14. //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  15. //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  16. CAudioRenderTerminal::CAudioRenderTerminal()
  17. {
  18. m_TerminalDirection = TD_RENDER;
  19. m_TerminalType = TT_STATIC;
  20. m_szName[0] = L'\0'; // real name is copied in on creation
  21. m_bResourceReserved = false;
  22. LOG((MSP_TRACE, "CAudioRenderTerminal::CAudioRenderTerminal() finished"));
  23. }
  24. CAudioRenderTerminal::~CAudioRenderTerminal()
  25. {
  26. LOG((MSP_TRACE, "CAudioRenderTerminal::~CAudioRenderTerminal() finished"));
  27. }
  28. //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  29. //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  30. // This function determines if the terminal associated with a given
  31. // moniker is "good". A good terminal returns S_OK; a bad terminal returns an
  32. // error.
  33. //
  34. // A good terminal has the following properties:
  35. // * has a friendly name
  36. // * is not a WAVE_MAPPER terminal
  37. // * is not a DirectSound terminal (unless USE_DIRECT_SOUND is pound-defined)
  38. //
  39. static inline HRESULT TerminalAllowed(IMoniker * pMoniker)
  40. {
  41. HRESULT hr;
  42. CComPtr<IPropertyBag> pBag;
  43. hr = pMoniker->BindToStorage(0, 0, IID_IPropertyBag, (void **)&pBag);
  44. if (FAILED(hr))
  45. {
  46. LOG((MSP_ERROR, "audio render TerminalAllowed (IMoniker::BindToStorage) "
  47. "- returning %8x", hr));
  48. return hr;
  49. }
  50. VARIANT var;
  51. // we make sure creation is not going to fail on
  52. // account of a nonexistent friendly name
  53. VariantInit(&var);
  54. var.vt = VT_BSTR;
  55. hr = pBag->Read(L"FriendlyName", &var, 0);
  56. if (FAILED(hr))
  57. {
  58. LOG((MSP_ERROR, "audio render TerminalAllowed "
  59. "(IPropertyBag::Read on FriendlyName) - got %8x; skipping terminal", hr));
  60. return hr;
  61. }
  62. // Fix for memory leak!
  63. SysFreeString(var.bstrVal);
  64. // NOTE: Magic code selects only wave devices
  65. VariantInit(&var);
  66. var.vt = VT_I4;
  67. hr = pBag->Read(L"WaveOutId", &var, 0);
  68. if (hr != S_OK)
  69. {
  70. #ifndef USE_DIRECT_SOUND
  71. // This is most likely a DirectSound terminal
  72. LOG((MSP_WARN, "audio render TerminalAllowed - "
  73. "this is a DirectSound terminal "
  74. "so we are skipping it - note that this is a routine "
  75. "occurance - returning %8x", hr));
  76. #else // we do use DirectSound
  77. return S_OK;
  78. #endif
  79. }
  80. else if (var.lVal == WAVE_MAPPER)
  81. {
  82. // hack: if the value is equal to WAVE_MAPPER then don't use it....
  83. hr = E_FAIL; // random failure code :)
  84. LOG((MSP_WARN, "audio render TerminalAllowed - "
  85. "this is a WAVE_MAPPER terminal "
  86. "so we are skipping it - note that this is a routine "
  87. "occurance - returning %8x", hr));
  88. }
  89. return hr;
  90. }
  91. //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  92. //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  93. HRESULT CAudioRenderTerminal::CreateTerminal(
  94. IN CComPtr<IMoniker> pMoniker,
  95. IN MSP_HANDLE htAddress,
  96. OUT ITTerminal **ppTerm
  97. )
  98. {
  99. // Enable ATL string conversion macros.
  100. USES_CONVERSION;
  101. LOG((MSP_TRACE, "CAudioRenderTerminal::CreateTerminal - enter"));
  102. //
  103. // Validate the parameters
  104. //
  105. if ( MSPB_IsBadWritePtr(ppTerm, sizeof(ITTerminal *) ) )
  106. {
  107. LOG((MSP_ERROR, "CAudioRenderTerminal::CreateTerminal : "
  108. "bad terminal pointer; returning E_POINTER"));
  109. return E_POINTER;
  110. }
  111. if ( IsBadReadPtr(pMoniker, sizeof(IMoniker) ) )
  112. {
  113. LOG((MSP_ERROR, "CAudioRenderTerminal::CreateTerminal : "
  114. "bad moniker pointer; returning E_POINTER"));
  115. return E_POINTER;
  116. }
  117. //
  118. // We return a NULL terminal if we fail.
  119. //
  120. *ppTerm = NULL;
  121. HRESULT hr;
  122. // Refuse to work with DirectSound or WAVE_MAPPER terminals.
  123. // or if we can't read the friendlyName...
  124. if (FAILED(hr = TerminalAllowed(pMoniker))) return hr;
  125. //
  126. // Get the name for this filter out of the property bag.
  127. //
  128. CComPtr<IPropertyBag> pBag;
  129. hr = pMoniker->BindToStorage(0, 0, IID_IPropertyBag, (void **)&pBag);
  130. if (FAILED(hr))
  131. {
  132. LOG((MSP_ERROR, "CAudioRenderTerminal::CreateTerminal (IMoniker::BindToStorage) - returning %8x", hr));
  133. return hr;
  134. }
  135. VARIANT var;
  136. VariantInit(&var);
  137. var.vt = VT_BSTR;
  138. hr = pBag->Read(L"FriendlyName", &var, 0);
  139. if (FAILED(hr))
  140. {
  141. LOG((MSP_WARN, "CAudioRenderTerminal::CreateTerminal "
  142. "(IPropertyBag::Read) - got %8x - we are therefore skipping "
  143. "this terminal; note that this is fairly routine", hr));
  144. return hr;
  145. }
  146. //
  147. // Create the terminal.
  148. //
  149. CMSPComObject<CAudioRenderTerminal> *pLclTerm = new CMSPComObject<CAudioRenderTerminal>;
  150. if (pLclTerm == NULL)
  151. {
  152. LOG((MSP_ERROR, "CAudioRenderTerminal::CreateTerminal - returning E_OUTOFMEMORY"));
  153. return E_OUTOFMEMORY;
  154. }
  155. //
  156. // Save some stuff in the terminal.
  157. //
  158. pLclTerm->m_pMoniker = pMoniker;
  159. lstrcpyn(pLclTerm->m_szName, OLE2T(var.bstrVal), MAX_PATH);
  160. SysFreeString(var.bstrVal);
  161. //
  162. // Get the ITTerminal interface that we were asked for.
  163. //
  164. hr = pLclTerm->_InternalQueryInterface(IID_ITTerminal, (void**)ppTerm);
  165. if ( FAILED(hr) )
  166. {
  167. LOG((MSP_ERROR, "CAudioRenderTerminal::CreateTerminal - "
  168. "Internal QI failed; returning 0x%08x", hr));
  169. delete pLclTerm;
  170. *ppTerm = NULL; // just in case
  171. return hr;
  172. }
  173. //
  174. // Finish initializing the terminal.
  175. //
  176. hr = pLclTerm->Initialize(CLSID_SpeakersTerminal,
  177. TAPIMEDIATYPE_AUDIO,
  178. TD_RENDER,
  179. htAddress
  180. );
  181. if ( FAILED(hr) )
  182. {
  183. LOG((MSP_ERROR, "CAudioRenderTerminal::CreateTerminal - "
  184. "Initialize failed; returning 0x%08x", hr));
  185. (*ppTerm)->Release();
  186. *ppTerm = NULL; // just in case
  187. return hr;
  188. }
  189. LOG((MSP_TRACE, "CAudioRenderTerminal::CreateTerminal - exit S_OK"));
  190. return S_OK;
  191. }
  192. //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  193. //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  194. // Create the filters used by this terminal
  195. HRESULT CAudioRenderTerminal::CreateFilters()
  196. {
  197. LOG((MSP_TRACE, "CAudioRenderTerminal::CreateFilters - enter"));
  198. HRESULT hr;
  199. //
  200. // We used to recreate the audio render filter every time, but we don't
  201. // have any real reason for doing so. Just return S_OK if the filter
  202. // has already been created.
  203. //
  204. if ( m_pIFilter != NULL )
  205. {
  206. _ASSERTE( m_pIPin != NULL );
  207. LOG((MSP_TRACE, "CAudioRenderTerminal::CreateFilters - "
  208. "filter already created - exit S_OK"));
  209. return S_OK;
  210. }
  211. _ASSERTE ( m_pIBasicAudio == NULL );
  212. _ASSERTE ( m_pIPin == NULL );
  213. //
  214. // Sanity checks.
  215. //
  216. if ( m_pMoniker == NULL )
  217. {
  218. LOG((MSP_ERROR, "CAudioRenderTerminal::CreateFilters - "
  219. "no moniker present - returning E_UNEXPECTED"));
  220. return E_UNEXPECTED;
  221. }
  222. //
  223. // Create a new instance of the filter.
  224. //
  225. hr = m_pMoniker->BindToObject(0, 0, IID_IBaseFilter, (void**)&m_pIFilter);
  226. if ( FAILED(hr) )
  227. {
  228. LOG((MSP_ERROR, "CAudioRenderTerminal::CreateFilters - "
  229. "BindToObject failed; returning %8x", hr));
  230. return hr;
  231. }
  232. //
  233. // Get the basic audio interface for the filter. If it doesn't exist, we
  234. // can live with that, but all our IBasicAudio methods will fail.
  235. //
  236. hr = m_pIFilter->QueryInterface(IID_IBasicAudio,
  237. (void **) &m_pIBasicAudio);
  238. if ( FAILED(hr) )
  239. {
  240. LOG((MSP_WARN, "CAudioRenderTerminal::CreateFilters - "
  241. "QI for IBasicAudio failed: %8x", hr));
  242. }
  243. hr = FindTerminalPin();
  244. if ( FAILED(hr) )
  245. {
  246. LOG((MSP_ERROR, "CAudioRenderTerminal::CreateFilters - "
  247. "FindTerminalPin failed; returning 0x%08x", hr));
  248. m_pIFilter = NULL; // does an implicit release
  249. if ( m_pIBasicAudio )
  250. {
  251. m_pIBasicAudio = NULL; // does an implicit release
  252. }
  253. return hr;
  254. }
  255. LOG((MSP_TRACE, "CAudioRenderTerminal::CreateFilters - exit S_OK"));
  256. return S_OK;
  257. }
  258. //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  259. //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  260. HRESULT
  261. CAudioRenderTerminal::FindTerminalPin(
  262. )
  263. {
  264. LOG((MSP_TRACE, "CAudioRenderTerminal::FindTerminalPin - enter"));
  265. //
  266. // Sanity checks so we don't AV.
  267. //
  268. if (m_pIPin != NULL)
  269. {
  270. LOG((MSP_TRACE, "CAudioRenderTerminal::FindTerminalPin - "
  271. "we've already got a pin; exit E_UNEXPECTED"));
  272. return E_UNEXPECTED;
  273. }
  274. if (m_pIFilter == NULL)
  275. {
  276. LOG((MSP_TRACE, "CAudioRenderTerminal::FindTerminalPin - "
  277. "we don't have a filter; exit E_UNEXPECTED"));
  278. return E_UNEXPECTED;
  279. }
  280. HRESULT hr;
  281. CComPtr<IEnumPins> pIEnumPins;
  282. ULONG cFetched;
  283. //
  284. // Find the render pin for the filter.
  285. //
  286. hr = m_pIFilter->EnumPins(&pIEnumPins);
  287. if (FAILED(hr))
  288. {
  289. LOG((MSP_ERROR,
  290. "CAudioRenderTerminal::FindTerminalPin - can't enum pins 0x%08x",
  291. hr));
  292. return hr;
  293. }
  294. IPin * pIPin;
  295. // Enumerate all the pins and break on the
  296. // first pin that meets requirement.
  297. for (;;)
  298. {
  299. if (pIEnumPins->Next(1, &pIPin, &cFetched) != S_OK)
  300. {
  301. LOG((MSP_ERROR,
  302. "CAudioRenderTerminal::FindTerminalPin - can't get a pin %8x",
  303. hr));
  304. return (hr == S_FALSE) ? E_FAIL : hr;
  305. }
  306. if (0 == cFetched)
  307. {
  308. LOG((MSP_ERROR, "CAudioRenderTerminal::FindTerminalPin - got zero pins"));
  309. return E_FAIL;
  310. }
  311. PIN_DIRECTION dir;
  312. if (FAILED(hr = pIPin->QueryDirection(&dir)))
  313. {
  314. LOG((MSP_ERROR,
  315. "CAudioRenderTerminal::FindTerminalPin - can't query pin direction %8x",
  316. hr));
  317. pIPin->Release();
  318. return hr;
  319. }
  320. if (PINDIR_INPUT == dir)
  321. {
  322. break;
  323. }
  324. pIPin->Release();
  325. }
  326. m_pIPin = pIPin;
  327. LOG((MSP_TRACE, "CAudioRenderTerminal::FindTerminalPin - exit S_OK"));
  328. return S_OK;
  329. }
  330. //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  331. //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  332. HRESULT CAudioRenderTerminal::AddFiltersToGraph(
  333. )
  334. {
  335. LOG((MSP_TRACE, "CAudioRenderTerminal::AddFiltersToGraph - enter"));
  336. if (m_pGraph == NULL)
  337. {
  338. LOG((MSP_ERROR, "CAudioRenderTerminal::AddFiltersToGraph - "
  339. "haven't got a filter graph; return E_UNEXPECTED"));
  340. return E_UNEXPECTED;
  341. }
  342. //
  343. // Create the filters if this is the first connection with this terminal.
  344. //
  345. HRESULT hr = CreateFilters();
  346. if ( FAILED(hr) )
  347. {
  348. LOG((MSP_ERROR, "CAudioRenderTerminal::AddFiltersToGraph - "
  349. "CreateFilters failed; returning 0x%08x", hr));
  350. return hr;
  351. }
  352. //
  353. // Add the filter to the graph.
  354. //
  355. // A word about names:
  356. // If a filter has already been added with the same name (which will
  357. // happen if we have more than one audio render terminal in the same
  358. // graph) then that will return VFW_S_DUPLICATE_NAME, which is not
  359. // a failure.
  360. //
  361. hr = m_pGraph->AddFilter(m_pIFilter, WAVEOUT_NAME);
  362. if ( FAILED(hr) )
  363. {
  364. LOG((MSP_ERROR, "CAudioRenderTerminal::AddFiltersToGraph - "
  365. "returning 0x%08x", hr));
  366. return hr;
  367. }
  368. LOG((MSP_TRACE, "CAudioRenderTerminal::AddFiltersToGraph - exit S_OK"));
  369. return S_OK;
  370. }
  371. //////////////////////////////////////////////////////////////////////////////
  372. // we override this here so we can do some stuff
  373. // right after the filter gets connected
  374. STDMETHODIMP CAudioRenderTerminal::CompleteConnectTerminal(void)
  375. {
  376. LOG((MSP_TRACE, "CAudioRenderTerminal::CompleteConnectTerminal - enter"));
  377. // By default, we need not unreserve later.
  378. m_bResourceReserved = false;
  379. // Don't clobber the base class' machinations (currently nothing...)
  380. HRESULT hr = CSingleFilterTerminal::CompleteConnectTerminal();
  381. if (FAILED(hr))
  382. {
  383. LOG((MSP_TRACE, "CAudioRenderTerminal::CompleteConnectTerminal: "
  384. "CSingleFilterTerminal method failed"));
  385. return hr;
  386. }
  387. // So here we are, after our filter has been added to the filter graph and connected up.
  388. // We need to use the filter's
  389. // IAMResourceControl::Reserve method to make sure the filter opens the waveOut device
  390. // now (and keeps it open).
  391. //////////////////////////////////////////////////////////////////////////
  392. // we must inform the filter that we want it to grab the wave device.
  393. // We do this after connecting because the filter needs to negotiate the
  394. // media type before it can open a wave device.
  395. CComPtr <IAMResourceControl> pIResource;
  396. hr = m_pIFilter->QueryInterface(IID_IAMResourceControl, (void **) &pIResource);
  397. if (FAILED(hr))
  398. {
  399. LOG((MSP_ERROR, "CAudioRenderTerminal::CompleteConnectTerminal - QI failed: %8x", hr));
  400. // This is a nonesential operation so we do not fail.
  401. return S_OK;
  402. }
  403. // The QueryInterface didn't fail...
  404. hr = pIResource->Reserve(AMRESCTL_RESERVEFLAGS_RESERVE, NULL);
  405. if (FAILED(hr))
  406. {
  407. LOG((MSP_ERROR, "CAudioRenderTerminal::CompleteConnectTerminal - "
  408. "device reservation failed: %8x", hr));
  409. return hr;
  410. }
  411. else if (hr == S_FALSE)
  412. {
  413. // Well, in this case either another application is already using the wave out device,
  414. // or we are running half-duplex and we've got both wavein and waveout terminals
  415. // selected.
  416. LOG((MSP_ERROR, "CAudioRenderTerminal::CompleteConnectTerminal - "
  417. "device already in use: %8x", hr));
  418. return hr;
  419. } // {if the driver is half-duplex}
  420. // We have succeeded in reserving, so we will want to unreserve later.
  421. m_bResourceReserved = true;
  422. LOG((MSP_TRACE, "CAudioRenderTerminal::CompleteConnectTerminal - exit S_OK"));
  423. return S_OK;
  424. }
  425. //////////////////////////////////////////////////////////////////////////////////
  426. // We override this here so we can unreserve the resource when we are done.
  427. // removes filters from the filter graph and resets member variables
  428. // Disconnect may be called anytime after Connect succeeds (it need not be called
  429. // if CompleteConnect fails)
  430. STDMETHODIMP CAudioRenderTerminal::DisconnectTerminal(
  431. IN IGraphBuilder * pGraph,
  432. IN DWORD dwReserved
  433. )
  434. {
  435. LOG((MSP_TRACE, "CAudioRenderTerminal::DisconnectTerminal - enter"));
  436. HRESULT hr;
  437. //
  438. // First call the base class method, to make sure we validate everything
  439. // and don't mess with our resource reservation unless this is a valid
  440. // disconnection (e.g., the filter graph pointersmatch).
  441. //
  442. hr = CSingleFilterTerminal::DisconnectTerminal(pGraph, dwReserved);
  443. if (FAILED(hr))
  444. {
  445. LOG((MSP_TRACE, "CAudioRenderTerminal::DisconnectTerminal : "
  446. "CSingleFilterTerminal method failed; hr = %d", hr));
  447. return hr;
  448. }
  449. // if we need to release the resource
  450. if (m_bResourceReserved)
  451. {
  452. CComPtr <IAMResourceControl> pIResource;
  453. hr = m_pIFilter->QueryInterface(IID_IAMResourceControl, (void **) &pIResource);
  454. if (FAILED(hr))
  455. {
  456. LOG((MSP_ERROR, "CAudioRenderTerminal::DisconnectTerminal - QI failed: %8x", hr));
  457. // This is a nonesential operation so we do not "return hr;" here.
  458. }
  459. else
  460. {
  461. // QueryInterface didn't fail, and we have reserved WaveOut, so we must
  462. // unreserve now.
  463. hr = pIResource->Reserve(AMRESCTL_RESERVEFLAGS_UNRESERVE, NULL);
  464. if (FAILED(hr))
  465. {
  466. LOG((MSP_ERROR, "CAudioRenderTerminal::DisconnectTerminal - "
  467. "device unreservation failed: %8x", hr));
  468. // no reason to completely die at this point, so we just continue
  469. }
  470. // if other things fail we may be called again, but we should not try
  471. // to unreserve again.
  472. m_bResourceReserved = false;
  473. } // {if QI succeeded}
  474. } // {if need to release resource}
  475. LOG((MSP_TRACE, "CAudioRenderTerminal::DisconnectTerminal - exit S_OK"));
  476. return S_OK;
  477. }
  478. //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  479. //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  480. // private helper method:
  481. static HRESULT RangeConvert(long lInput,
  482. long lInputMin,
  483. long lInputMax,
  484. long * plOutput,
  485. long lOutputMin,
  486. long lOutputMax)
  487. {
  488. _ASSERTE( lInputMin < lInputMax );
  489. _ASSERTE( lOutputMin < lOutputMax );
  490. _ASSERTE( ! MSPB_IsBadWritePtr(plOutput, sizeof(long)) );
  491. if (lInput < lInputMin)
  492. {
  493. LOG((MSP_ERROR, "RangeConvert - value out of range - "
  494. "%d < %d; returning E_INVALIDARG",
  495. lInput, lInputMin));
  496. return E_INVALIDARG;
  497. }
  498. if (lInput > lInputMax)
  499. {
  500. LOG((MSP_ERROR, "RangeConvert - value out of range - "
  501. "%d > %d; returning E_INVALIDARG",
  502. lInput, lInputMax));
  503. return E_INVALIDARG;
  504. }
  505. // This is how much we are going to expand the range of the input.
  506. double dRangeWidthRatio = (double) (lOutputMax - lOutputMin) /
  507. (double) (lInputMax - lInputMin);
  508. *plOutput = (long) ((lInput - lInputMin) * dRangeWidthRatio) + lOutputMin;
  509. return S_OK;
  510. }
  511. //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  512. //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  513. STDMETHODIMP CAudioRenderTerminal::get_Volume(long * plVolume)
  514. {
  515. CLock lock(m_CritSec);
  516. LOG((MSP_TRACE, "CAudioRenderTerminal::get_Volume - enter"));
  517. //
  518. // Parameter checks.
  519. //
  520. if ( MSPB_IsBadWritePtr(plVolume, sizeof(long)) )
  521. {
  522. LOG((MSP_ERROR, "CAudioRenderTerminal::get_Volume - "
  523. "bad pointer argument"));
  524. return E_POINTER;
  525. }
  526. if (m_pIBasicAudio == NULL)
  527. {
  528. LOG((MSP_ERROR, "CAudioRenderTerminal::get_Volume - "
  529. "don't have necessary interface - exit E_FAIL"));
  530. return E_FAIL;
  531. }
  532. //
  533. // Let the filter do the work.
  534. //
  535. HRESULT hr = m_pIBasicAudio->get_Volume(plVolume);
  536. if (FAILED(hr))
  537. {
  538. LOG((MSP_ERROR, "CAudioRenderTerminal::get_Volume - "
  539. "filter call failed: %08x", hr));
  540. return hr;
  541. }
  542. //
  543. // Asjust the range of the value returned to match the range specified
  544. // by the TAPI APIs.
  545. //
  546. hr = RangeConvert(*plVolume, AX_MIN_VOLUME, AX_MAX_VOLUME,
  547. plVolume, 0, 0xFFFF);
  548. if (FAILED(hr))
  549. {
  550. LOG((MSP_ERROR, "CAudioRenderTerminal::get_Volume - "
  551. "RangeConvert call failed: %08x", hr));
  552. return hr;
  553. }
  554. LOG((MSP_TRACE, "CAudioRenderTerminal::get_Volume - exit S_OK"));
  555. return S_OK;
  556. }
  557. //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  558. //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  559. STDMETHODIMP CAudioRenderTerminal::put_Volume(long lVolume)
  560. {
  561. CLock lock(m_CritSec);
  562. LOG((MSP_TRACE, "CAudioRenderTerminal::put_Volume - enter"));
  563. if (m_pIBasicAudio == NULL)
  564. {
  565. LOG((MSP_ERROR, "CAudioRenderTerminal::put_Volume - "
  566. "don't have necessary interface - exit E_FAIL"));
  567. return E_FAIL;
  568. }
  569. //
  570. // Asjust the range of the value returned to match the range needed
  571. // by the WaveOut filter.
  572. //
  573. HRESULT hr = RangeConvert(lVolume, 0, 0xFFFF,
  574. &lVolume, AX_MIN_VOLUME, AX_MAX_VOLUME);
  575. if (FAILED(hr))
  576. {
  577. LOG((MSP_ERROR, "CAudioRenderTerminal::put_Volume - "
  578. "RangeConvert call failed: %08x", hr));
  579. return hr;
  580. }
  581. //
  582. // Let the filter do the work.
  583. //
  584. hr = m_pIBasicAudio->put_Volume(lVolume);
  585. if (FAILED(hr))
  586. {
  587. LOG((MSP_ERROR, "CAudioRenderTerminal::put_Volume - "
  588. "filter call failed: %08x", hr));
  589. return hr;
  590. }
  591. LOG((MSP_TRACE, "CAudioRenderTerminal::put_Volume - exit S_OK"));
  592. return S_OK;
  593. }
  594. //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  595. //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  596. STDMETHODIMP CAudioRenderTerminal::get_Balance(long * plBalance)
  597. {
  598. HRESULT hr = E_NOTIMPL;
  599. LOG((MSP_TRACE, "CAudioRenderTerminal::get_Balance - enter"));
  600. LOG((MSP_TRACE, "CAudioRenderTerminal::get_Balance - exit 0x%08x", hr));
  601. return hr;
  602. }
  603. //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  604. //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  605. STDMETHODIMP CAudioRenderTerminal::put_Balance(long lBalance)
  606. {
  607. HRESULT hr = E_NOTIMPL;
  608. LOG((MSP_TRACE, "CAudioRenderTerminal::put_Balance - enter"));
  609. LOG((MSP_TRACE, "CAudioRenderTerminal::put_Balance - exit 0x%08x", hr));
  610. return hr;
  611. }
  612. //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  613. //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  614. STDMETHODIMP
  615. CAudioRenderTerminal::get_WaveId(
  616. OUT long * plWaveId
  617. )
  618. {
  619. LOG((MSP_TRACE, "CAudioRenderTerminal::get_WaveId - enter"));
  620. CLock lock(m_CritSec);
  621. //
  622. // Parameter checks.
  623. //
  624. if ( MSPB_IsBadWritePtr(plWaveId, sizeof(long)) )
  625. {
  626. LOG((MSP_ERROR, "CAudioRenderTerminal::get_WaveId - "
  627. "bad pointer argument"));
  628. return E_POINTER;
  629. }
  630. //
  631. // Check the moniker pointer.
  632. //
  633. if ( IsBadReadPtr( m_pMoniker, sizeof(IMoniker) ) )
  634. {
  635. LOG((MSP_ERROR, "CAudioRenderTerminal::get_WaveId - "
  636. "bad moniker pointer - exit E_UNEXPECTED"));
  637. return E_UNEXPECTED;
  638. }
  639. //
  640. // Get a property bag from the moniker.
  641. //
  642. IPropertyBag * pBag;
  643. HRESULT hr = m_pMoniker->BindToStorage(0,
  644. 0,
  645. IID_IPropertyBag,
  646. (void **) &pBag);
  647. if ( FAILED(hr) )
  648. {
  649. LOG((MSP_ERROR, "CAudioRenderTerminal::get_WaveId - "
  650. "can't get property bag - exit 0x%08x", hr));
  651. return hr;
  652. }
  653. //
  654. // Get the ID from the property bag.
  655. //
  656. VARIANT var;
  657. var.vt = VT_I4;
  658. hr = pBag->Read(
  659. L"WaveOutId",
  660. &var,
  661. 0);
  662. pBag->Release();
  663. if ( FAILED(hr) )
  664. {
  665. LOG((MSP_ERROR, "CAudioRenderTerminal::get_WaveId - "
  666. "can't read wave ID - exit 0x%08x", hr));
  667. return hr;
  668. }
  669. *plWaveId = (long) var.lVal;
  670. LOG((MSP_TRACE, "CAudioRenderTerminal::get_WaveId - exit S_OK"));
  671. return S_OK;
  672. }