VolumeInXXX.cpp
上传用户:lywczg
上传日期:2007-01-03
资源大小:15k
文件大小:18k
源码类别:

Audio

开发平台:

Visual C++

  1. // VolumeInXXX.cpp : Module interface implementation.
  2. // Developer : Alex Chmut
  3. // Created : 8/11/98
  4. #include "StdAfx.h"
  5. #include "VolumeInXXX.h"
  6. /////////////////////////////////////////////////////////////////////////////
  7. //  Defines
  8. #define BAD_DWORD (DWORD)-1
  9. #define WND_CLASS_NAME "Input Volume Msg Wnd Class"
  10. #define WND_NAME "Input Volume Msg Wnd"
  11. /////////////////////////////////////////////////////////////////////////////
  12. //  Globals
  13. PCVolumeInXXX g_pThis = NULL;
  14. ////////////////////////////////////////////////////////////
  15. //{{{ Audio specific functions
  16. #define AUDFREQ 22050 // Frequency
  17. #define AUDCHANNELS 1 // Number of channels
  18. #define AUDBITSMPL 16 // Number of bits per sample
  19. inline
  20. void SetDeviceType( WAVEFORMATEX* pwfe )
  21. {
  22. memset( pwfe, 0, sizeof(WAVEFORMATEX) );
  23. WORD  nBlockAlign = (AUDCHANNELS*AUDBITSMPL)/8;
  24. DWORD nSamplesPerSec = AUDFREQ;
  25. pwfe->wFormatTag = WAVE_FORMAT_PCM;
  26. pwfe->nChannels = AUDCHANNELS;
  27. pwfe->nBlockAlign = nBlockAlign;
  28. pwfe->nSamplesPerSec = nSamplesPerSec;
  29. pwfe->wBitsPerSample = AUDBITSMPL;
  30. pwfe->nAvgBytesPerSec = nSamplesPerSec*nBlockAlign;
  31. }
  32. //}}} Audio specific functions
  33. /////////////////////////////////////////////////////////////////////////////
  34. //  Implementation
  35. //////////////
  36. CVolumeInXXX::CVolumeInXXX( UINT uLineIndex )
  37. : m_bOK(false),
  38. m_bInitialized(false),
  39. m_bAvailable(false),
  40. m_uMixerID(0L),
  41. m_dwMixerHandle(0L),
  42. m_hWnd(NULL),
  43. m_uMicrophoneSourceLineIndex(BAD_DWORD),
  44. m_dwMinimalVolume(BAD_DWORD),
  45. m_dwMaximalVolume(BAD_DWORD),
  46. m_pfUserSink(NULL),
  47. m_dwUserValue(0L)
  48. {
  49. if ( m_bOK = Init() )
  50. {
  51. g_pThis = this;
  52. if ( !Initialize( uLineIndex ) )
  53. {
  54. Done();
  55. g_pThis = NULL;
  56. }
  57. }
  58. }
  59. //////////////
  60. CVolumeInXXX::~CVolumeInXXX()
  61. {
  62. if ( m_bOK )
  63. Done();
  64. g_pThis = NULL;
  65. }
  66. //////////////
  67. bool CVolumeInXXX::Init()
  68. {
  69. if ( !mixerGetNumDevs() )
  70. return false;
  71. // Getting Mixer ID
  72. HWAVEIN hwaveIn;
  73. MMRESULT mmResult;
  74. WAVEFORMATEX WaveFmt;
  75. SetDeviceType( &WaveFmt );
  76. mmResult = waveInOpen( &hwaveIn, WAVE_MAPPER, &WaveFmt, 0L, 0L, CALLBACK_NULL );
  77. if ( mmResult != MMSYSERR_NOERROR )
  78. {
  79. TRACE(".InputXxxVolume: FAILURE: Could not open WaveIn Mapper. mmResult=%dn", mmResult );
  80. return false;
  81. } else {
  82. mmResult = mixerGetID( (HMIXEROBJ)hwaveIn, &m_uMixerID, MIXER_OBJECTF_HWAVEIN );
  83. waveInClose( hwaveIn );
  84. if ( mmResult != MMSYSERR_NOERROR )
  85. {
  86. TRACE(".InputXxxVolume: FAILURE: WaveIn Mapper in Mixer is not available. mmResult=%dn", mmResult );
  87. return false;
  88. }
  89. }
  90. // Exposing Window to Mixer
  91. WNDCLASSEX wcx;
  92. memset( &wcx, 0, sizeof(WNDCLASSEX) );
  93. wcx.cbSize = sizeof(WNDCLASSEX);
  94. wcx.lpszClassName = WND_CLASS_NAME;
  95. wcx.lpfnWndProc = (WNDPROC)MixerWndProc;
  96. ::RegisterClassEx(&wcx);
  97. m_hWnd = CreateWindow( WND_CLASS_NAME,
  98. WND_NAME,
  99. WS_POPUP | WS_DISABLED,
  100. 0, 0, 0, 0,
  101. NULL, NULL, NULL, NULL );
  102. if ( !m_hWnd )
  103. {
  104. TRACE(".InputXxxVolume: FAILURE: Could not create internal window.n" );
  105. return false;
  106. }
  107. ::ShowWindow(m_hWnd, SW_HIDE);
  108. mmResult = mixerOpen( (LPHMIXER)&m_dwMixerHandle, m_uMixerID, (DWORD)m_hWnd, 0L, CALLBACK_WINDOW );
  109. if ( mmResult != MMSYSERR_NOERROR )
  110. {
  111. TRACE(".InputXxxVolume: FAILURE: Could not open Mixer. mmResult=%dn", mmResult );
  112. ::DestroyWindow( m_hWnd );
  113. return false;
  114. }
  115. return true;
  116. }
  117. //////////////
  118. void CVolumeInXXX::Done()
  119. {
  120. if ( mixerClose( (HMIXER)m_dwMixerHandle ) != MMSYSERR_NOERROR )
  121. {
  122. TRACE(".InputXxxVolume: WARNING: Could not close Mixer.n" );
  123. }
  124. ::DestroyWindow( m_hWnd );
  125. m_bInitialized = false;
  126. m_bOK = false;
  127. }
  128. //////////////
  129. void CVolumeInXXX::OnControlChanged( DWORD dwControlID )
  130. {
  131. if ( m_dwVolumeControlID == dwControlID )
  132. {
  133. DWORD dwVolume = GetCurrentVolume();
  134. if ( (dwVolume!=BAD_DWORD) && (m_pfUserSink) )
  135. {
  136. (*m_pfUserSink)( dwVolume, m_dwUserValue );
  137. }
  138. }
  139. }
  140. //////////////
  141. bool CVolumeInXXX::Initialize( UINT uLineIndex )
  142. {
  143. MMRESULT mmResult;
  144. if ( !m_bOK )
  145. return false;
  146. TRACE(".InputXxxVolume: Initializing for the Source Line (%d) ..n", uLineIndex );
  147. MIXERLINE MixerLine;
  148. memset( &MixerLine, 0, sizeof(MIXERLINE) );
  149. MixerLine.cbStruct = sizeof(MIXERLINE);
  150. MixerLine.dwComponentType = MIXERLINE_COMPONENTTYPE_DST_WAVEIN;
  151. mmResult = mixerGetLineInfo( (HMIXEROBJ)m_dwMixerHandle, &MixerLine, MIXER_GETLINEINFOF_COMPONENTTYPE );
  152. if ( mmResult != MMSYSERR_NOERROR )
  153. {
  154. TRACE(".InputXxxVolume: FAILURE: Could not get WaveIn Destionation Line for the requested source while initilaizing. mmResult=%dn", mmResult );
  155. return false;
  156. }
  157. MIXERCONTROL Control;
  158. memset( &Control, 0, sizeof(MIXERCONTROL) );
  159. Control.cbStruct = sizeof(MIXERCONTROL);
  160. MIXERLINECONTROLS LineControls;
  161. memset( &LineControls, 0, sizeof(MIXERLINECONTROLS) );
  162. LineControls.cbStruct = sizeof(MIXERLINECONTROLS);
  163. MIXERLINE Line;
  164. memset( &Line, 0, sizeof(MIXERLINE) );
  165. Line.cbStruct = sizeof(MIXERLINE);
  166. if ( ( uLineIndex < MixerLine.cConnections ) )
  167. {
  168. Line.dwDestination = MixerLine.dwDestination;
  169. Line.dwSource = uLineIndex;
  170. mmResult = mixerGetLineInfo( (HMIXEROBJ)m_dwMixerHandle, &Line, MIXER_GETLINEINFOF_SOURCE );
  171. if ( mmResult != MMSYSERR_NOERROR )
  172. {
  173. TRACE(".InputXxxVolume: FAILURE: Could not get the requested Source Line while initilaizing. mmResult=%dn", mmResult );
  174. return false;
  175. }
  176. TRACE(".InputXxxVolume: "%s" Source Line adopted.n", Line.szShortName );
  177. LineControls.dwControlType = MIXERCONTROL_CONTROLTYPE_VOLUME;
  178. LineControls.dwLineID = Line.dwLineID;
  179. LineControls.cControls = 1;
  180. LineControls.cbmxctrl = sizeof(MIXERCONTROL);
  181. LineControls.pamxctrl = &Control;
  182. mmResult = mixerGetLineControls( (HMIXEROBJ)m_dwMixerHandle, &LineControls, MIXER_GETLINECONTROLSF_ONEBYTYPE );
  183. if ( mmResult == MMSYSERR_NOERROR )
  184. {
  185. if ( !(Control.fdwControl & MIXERCONTROL_CONTROLF_DISABLED) )
  186. {
  187. m_bAvailable = true;
  188. TRACE(".InputXxxVolume: "%s" Volume control for the Source Line adoptedn", Control.szShortName );
  189. } else {
  190. TRACE(".InputXxxVolume: WARNING: The Volume Control is disabled.n" );
  191. }
  192. } else {
  193. TRACE(".InputXxxVolume: WARNING: Could not get the requested Source Line Volume Control for the requested line while initilaizing. mmResult=%dn", mmResult );
  194. }
  195. } else {
  196. TRACE(".InputXxxVolume: FAILURE: Invalid Source Line index passed.n" );
  197. return false;
  198. }
  199. // Retrieving Microphone Source Line
  200. for ( UINT uLine = 0; uLine < MixerLine.cConnections; uLine++ )
  201. {
  202. MIXERLINE MicrophoneLine;
  203. memset( &MicrophoneLine, 0, sizeof(MIXERLINE) );
  204. MicrophoneLine.cbStruct = sizeof(MIXERLINE);
  205. MicrophoneLine.dwDestination = MixerLine.dwDestination;
  206. MicrophoneLine.dwSource = uLine;
  207. mmResult = mixerGetLineInfo( (HMIXEROBJ)m_dwMixerHandle, &MicrophoneLine, MIXER_GETLINEINFOF_SOURCE );
  208. if ( mmResult == MMSYSERR_NOERROR )
  209. {
  210. if ( MicrophoneLine.dwComponentType == MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE )
  211. {
  212. m_uMicrophoneSourceLineIndex = MicrophoneLine.dwSource;
  213. TRACE(".InputXxxVolume: Microphone Source Line "%s" has been found.n", MicrophoneLine.szShortName );
  214. break;
  215. }
  216. }
  217. }
  218. if ( m_uMicrophoneSourceLineIndex == BAD_DWORD )
  219. {
  220. TRACE(".InputXxxVolume: WARNING: Could not retrieve Microphone Source Line.n" );
  221. }
  222. m_uSourceLineIndex = uLineIndex;
  223. m_nChannelCount = Line.cChannels;
  224. m_dwLineID = LineControls.dwLineID;
  225. m_dwVolumeControlID = Control.dwControlID;
  226. m_dwMinimalVolume = Control.Bounds.dwMinimum;
  227. m_dwMaximalVolume = Control.Bounds.dwMaximum;
  228. m_dwVolumeStep = Control.Metrics.cSteps;
  229. m_bInitialized = true;
  230. return true;
  231. }
  232. //////////////////////////////////////////////
  233. bool CVolumeInXXX::GetMicrophoneSourceLineIndex( UINT* puLineIndex )
  234. {
  235. if ( !puLineIndex || !m_bInitialized || (m_uMicrophoneSourceLineIndex==BAD_DWORD) )
  236. return false;
  237. *puLineIndex = m_uMicrophoneSourceLineIndex;
  238. return true;
  239. }
  240. //////////////////////////////////////////////
  241. // IVolume interface
  242. //////////////
  243. bool CVolumeInXXX::IsAvailable()
  244. {
  245. return m_bAvailable;
  246. }
  247. //////////////
  248. void CVolumeInXXX::Enable()
  249. {
  250. if ( !m_bInitialized )
  251. return;
  252. bool bAnyEnabled = false;
  253. MMRESULT mmResult;
  254. MIXERLINE lineDestination;
  255. memset( &lineDestination, 0, sizeof(MIXERLINE) );
  256. lineDestination.cbStruct = sizeof(MIXERLINE);
  257. lineDestination.dwComponentType = MIXERLINE_COMPONENTTYPE_DST_WAVEIN;
  258. mmResult = mixerGetLineInfo( (HMIXEROBJ)m_dwMixerHandle, &lineDestination, MIXER_GETLINEINFOF_COMPONENTTYPE );
  259. if ( mmResult != MMSYSERR_NOERROR )
  260. {
  261. TRACE(".InputXxxVolume: FAILURE: Could not get the Destination Line while enabling. mmResult=%dn", mmResult );
  262. return;
  263. }
  264. // Getting all line's controls
  265. int nControlCount = lineDestination.cControls;
  266. int nChannelCount = lineDestination.cChannels;
  267. MIXERLINECONTROLS LineControls;
  268. memset( &LineControls, 0, sizeof(MIXERLINECONTROLS) );
  269. MIXERCONTROL* aControls = (MIXERCONTROL*)malloc( nControlCount * sizeof(MIXERCONTROL) );
  270. if ( !aControls )
  271. {
  272. TRACE(".InputXxxVolume: FAILURE: Out of memory while enabling the line.n" );
  273. return;
  274. }
  275. memset( &aControls[0], 0, sizeof(nControlCount * sizeof(MIXERCONTROL)) );
  276. for ( int i = 0; i < nControlCount; i++ )
  277. {
  278. aControls[i].cbStruct = sizeof(MIXERCONTROL);
  279. }
  280. LineControls.cbStruct = sizeof(MIXERLINECONTROLS);
  281. LineControls.dwLineID = lineDestination.dwLineID;
  282. LineControls.cControls = nControlCount;
  283. LineControls.cbmxctrl = sizeof(MIXERCONTROL);
  284. LineControls.pamxctrl = &aControls[0];
  285. mmResult = mixerGetLineControls( (HMIXEROBJ)m_dwMixerHandle, &LineControls, MIXER_GETLINECONTROLSF_ALL );
  286. if ( mmResult == MMSYSERR_NOERROR )
  287. {
  288. for ( i = 0; i < nControlCount; i++ )
  289. {
  290. if ( aControls[i].dwControlType & MIXERCONTROL_CT_UNITS_BOOLEAN )
  291. {
  292. MIXERCONTROLDETAILS_BOOLEAN* aDetails = NULL;
  293. int nMultipleItems = aControls[i].cMultipleItems;
  294. int nChannels = nChannelCount;
  295. // MIXERCONTROLDETAILS
  296. MIXERCONTROLDETAILS ControlDetails;
  297. memset( &ControlDetails, 0, sizeof(MIXERCONTROLDETAILS) );
  298. ControlDetails.cbStruct = sizeof(MIXERCONTROLDETAILS);
  299. ControlDetails.dwControlID = aControls[i].dwControlID;
  300. if ( aControls[i].fdwControl & MIXERCONTROL_CONTROLF_UNIFORM )
  301. {
  302. nChannels = 1;
  303. }
  304. if ( aControls[i].fdwControl & MIXERCONTROL_CONTROLF_MULTIPLE )
  305. {
  306. nMultipleItems = aControls[i].cMultipleItems;
  307. aDetails = (MIXERCONTROLDETAILS_BOOLEAN*)malloc(nMultipleItems*nChannels*sizeof(MIXERCONTROLDETAILS_BOOLEAN));
  308. if ( !aDetails )
  309. {
  310. TRACE(".InputXxxVolume: FAILURE: Out of memory while enabling the line.n" );
  311. continue;
  312. }
  313. for ( int nItem = 0; nItem < nMultipleItems; nItem++ )
  314. {
  315. LONG lValue = FALSE;
  316. if ( nItem == (int)m_uSourceLineIndex )
  317. lValue = TRUE;
  318. for ( int nChannel = 0; nChannel < nChannels; nChannel++ )
  319. {
  320. aDetails[nItem+nChannel].fValue = lValue;
  321. }
  322. }
  323. } else {
  324. nMultipleItems = 0;
  325. aDetails = (MIXERCONTROLDETAILS_BOOLEAN*)malloc(nChannels*sizeof(MIXERCONTROLDETAILS_BOOLEAN));
  326. if ( !aDetails )
  327. {
  328. TRACE(".InputXxxVolume: FAILURE: Out of memory while enabling the line.n" );
  329. continue;
  330. }
  331. for ( int nChannel = 0; nChannel < nChannels; nChannel++ )
  332. {
  333. aDetails[nChannel].fValue = (LONG)TRUE;
  334. }
  335. }
  336. ControlDetails.cChannels = nChannels;
  337. ControlDetails.cMultipleItems = nMultipleItems;
  338. ControlDetails.cbDetails = sizeof(MIXERCONTROLDETAILS_BOOLEAN);
  339. ControlDetails.paDetails = &aDetails[0];
  340. mmResult = mixerSetControlDetails( (HMIXEROBJ)m_dwMixerHandle, &ControlDetails, 0L );
  341. if ( mmResult == MMSYSERR_NOERROR )
  342. {
  343. TRACE(".InputXxxVolume: Enabling Line: Line control "%s" has been enabled.n", aControls[i].szShortName );
  344. bAnyEnabled = true;
  345. }
  346. free( aDetails );
  347. }
  348. }
  349. } else {
  350. TRACE(".InputXxxVolume: FAILURE: Could not get the line's controls while enabling. mmResult=%dn", mmResult );
  351. }
  352. free( aControls );
  353. if ( !bAnyEnabled )
  354. {
  355. TRACE(".InputXxxVolume: WARNING: No controls were found for enabling the line.n" );
  356. }
  357. }
  358. //////////////
  359. void CVolumeInXXX::Disable()
  360. {
  361. TRACE(".InputXxxVolume: WARNING: Disable line has no sense. The function not implemented.n" );
  362. }
  363. //////////////
  364. DWORD CVolumeInXXX::GetVolumeMetric()
  365. {
  366. if ( !m_bAvailable )
  367. return BAD_DWORD;
  368. return m_dwVolumeStep;
  369. }
  370. //////////////
  371. DWORD CVolumeInXXX::GetMinimalVolume()
  372. {
  373. if ( !m_bAvailable )
  374. return BAD_DWORD;
  375. return m_dwMinimalVolume;
  376. }
  377. //////////////
  378. DWORD CVolumeInXXX::GetMaximalVolume()
  379. {
  380. if ( !m_bAvailable )
  381. return BAD_DWORD;
  382. return m_dwMaximalVolume;
  383. }
  384. //////////////
  385. DWORD CVolumeInXXX::GetCurrentVolume()
  386. {
  387. if ( !m_bAvailable )
  388. return BAD_DWORD;
  389. MIXERCONTROLDETAILS_UNSIGNED* aDetails = (MIXERCONTROLDETAILS_UNSIGNED*)malloc(m_nChannelCount*sizeof(MIXERCONTROLDETAILS_UNSIGNED));
  390. if ( !aDetails )
  391. return BAD_DWORD;
  392. MIXERCONTROLDETAILS ControlDetails;
  393. memset( &ControlDetails, 0, sizeof(MIXERCONTROLDETAILS) );
  394. ControlDetails.cbStruct = sizeof(MIXERCONTROLDETAILS);
  395. ControlDetails.dwControlID = m_dwVolumeControlID;
  396. ControlDetails.cChannels = m_nChannelCount;
  397. ControlDetails.cMultipleItems = 0;
  398. ControlDetails.cbDetails = sizeof(MIXERCONTROLDETAILS_UNSIGNED);
  399. ControlDetails.paDetails = &aDetails[0];
  400. MMRESULT mmResult = mixerGetControlDetails( (HMIXEROBJ)m_dwMixerHandle, &ControlDetails, MIXER_GETCONTROLDETAILSF_VALUE );
  401. DWORD dw = aDetails[0].dwValue;
  402. free( aDetails );
  403. if ( mmResult != MMSYSERR_NOERROR )
  404. {
  405. TRACE(".InputXxxVolume: FAILURE: Could not get volume. mmResult=%dn", mmResult );
  406. return BAD_DWORD;
  407. }
  408. return dw;
  409. }
  410. //////////////
  411. void CVolumeInXXX::SetCurrentVolume( DWORD dwValue )
  412. {
  413. if ( !m_bAvailable || (dwValue<m_dwMinimalVolume) || (dwValue>m_dwMaximalVolume) )
  414. return;
  415. MIXERCONTROLDETAILS_UNSIGNED* aDetails = (MIXERCONTROLDETAILS_UNSIGNED*)malloc(m_nChannelCount*sizeof(MIXERCONTROLDETAILS_UNSIGNED));
  416. if ( !aDetails )
  417. return;
  418. for ( int i = 0; i < m_nChannelCount; i++ )
  419. {
  420. aDetails[i].dwValue = dwValue;
  421. }
  422. MIXERCONTROLDETAILS ControlDetails;
  423. memset( &ControlDetails, 0, sizeof(MIXERCONTROLDETAILS) );
  424. ControlDetails.cbStruct = sizeof(MIXERCONTROLDETAILS);
  425. ControlDetails.dwControlID = m_dwVolumeControlID;
  426. ControlDetails.cChannels = m_nChannelCount;
  427. ControlDetails.cMultipleItems = 0;
  428. ControlDetails.cbDetails = sizeof(MIXERCONTROLDETAILS_UNSIGNED);
  429. ControlDetails.paDetails = &aDetails[0];
  430. MMRESULT mmResult = mixerSetControlDetails( (HMIXEROBJ)m_dwMixerHandle, &ControlDetails, MIXER_SETCONTROLDETAILSF_VALUE );
  431. free( aDetails );
  432. if ( mmResult != MMSYSERR_NOERROR )
  433. {
  434. TRACE(".InputXxxVolume: FAILURE: Could not set volume(%d) mmResult=%dn", dwValue, mmResult );
  435. }
  436. }
  437. //////////////
  438. void CVolumeInXXX::RegisterNotificationSink( PONMICVOULUMECHANGE pfUserSink, DWORD dwUserValue )
  439. {
  440. m_pfUserSink = pfUserSink;
  441. m_dwUserValue = dwUserValue;
  442. }
  443. ////////////////////////////////////////////////////////////////////////
  444. LRESULT CALLBACK CVolumeInXXX::MixerWndProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
  445. {
  446. if ( uMsg == MM_MIXM_CONTROL_CHANGE )
  447. {
  448. if ( g_pThis )
  449. {
  450. g_pThis->OnControlChanged( (DWORD)lParam );
  451. }
  452. }
  453. return ::DefWindowProc( hwnd, uMsg, wParam, lParam);
  454. }
  455. ////////////////////////////////////////////////////////////////////////
  456. bool CVolumeInXXX::EnumerateInputLines( PINPUTLINEPROC pUserCallback, DWORD dwUserValue )
  457. {
  458. if ( !pUserCallback )
  459. return false;
  460. MMRESULT mmResult;
  461. HWAVEIN hwaveIn;
  462. WAVEFORMATEX WaveFmt;
  463. SetDeviceType( &WaveFmt );
  464. mmResult = waveInOpen( &hwaveIn, WAVE_MAPPER, &WaveFmt, 0L, 0L, CALLBACK_NULL );
  465. if ( mmResult != MMSYSERR_NOERROR )
  466. {
  467. TRACE(".InputXxxVolume: FAILURE: Could not open WaveIn Mapper. mmResult=%dn", mmResult );
  468. return false;
  469. }
  470. UINT uMixerID;
  471. DWORD dwMixerHandle;
  472. mmResult = mixerGetID( (HMIXEROBJ)hwaveIn, &uMixerID, MIXER_OBJECTF_HWAVEIN );
  473. waveInClose( hwaveIn );
  474. if ( mmResult != MMSYSERR_NOERROR )
  475. {
  476. TRACE(".InputXxxVolume: FAILURE: WaveIn Mapper in Mixer is not available. mmResult=%dn", mmResult );
  477. return false;
  478. }
  479. mmResult = mixerOpen( (LPHMIXER)&dwMixerHandle, uMixerID, 0L, 0L, 0L );
  480. if ( mmResult != MMSYSERR_NOERROR )
  481. {
  482. mixerClose( (HMIXER)dwMixerHandle );
  483. TRACE(".InputXxxVolume: FAILURE: Could not open Mixer. mmResult=%dn", mmResult );
  484. return false;
  485. }
  486. MIXERLINE MixerLine;
  487. memset( &MixerLine, 0, sizeof(MIXERLINE) );
  488. MixerLine.cbStruct = sizeof(MIXERLINE);
  489. MixerLine.dwComponentType = MIXERLINE_COMPONENTTYPE_DST_WAVEIN;
  490. mmResult = mixerGetLineInfo( (HMIXEROBJ)dwMixerHandle, &MixerLine, MIXER_GETLINEINFOF_COMPONENTTYPE );
  491. if ( mmResult != MMSYSERR_NOERROR )
  492. {
  493. mixerClose( (HMIXER)dwMixerHandle );
  494. TRACE(".InputXxxVolume: FAILURE: Could not get WaveIn Destionation Line for the requested source while enumerating. mmResult=%dn", mmResult );
  495. return false;
  496. }
  497. MIXERLINE Line;
  498. for ( UINT uLineIndex = 0; uLineIndex < MixerLine.cConnections; uLineIndex++ )
  499. {
  500. memset( &Line, 0, sizeof(MIXERLINE) );
  501. Line.cbStruct = sizeof(MIXERLINE);
  502. Line.dwDestination = MixerLine.dwDestination;
  503. Line.dwSource = uLineIndex;
  504. mmResult = mixerGetLineInfo( (HMIXEROBJ)dwMixerHandle, &Line, MIXER_GETLINEINFOF_SOURCE );
  505. if ( mmResult != MMSYSERR_NOERROR )
  506. {
  507. mixerClose( (HMIXER)dwMixerHandle );
  508. TRACE(".InputXxxVolume: FAILURE: Could not get the interated Source Line while enumerating. mmResult=%dn", mmResult );
  509. return false;
  510. }
  511. if ( !((*pUserCallback)( uLineIndex, &Line, dwUserValue )) )
  512. {
  513. break;
  514. }
  515. }
  516. mixerClose( (HMIXER)dwMixerHandle );
  517. return true;
  518. }