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

Audio

开发平台:

Visual C++

  1. // VolumeOutMaster.cpp : Module interface implementation.
  2. // Developer : Alex Chmut
  3. // Created : 8/11/98
  4. #include "StdAfx.h"
  5. #include "VolumeOutMaster.h"
  6. /////////////////////////////////////////////////////////////////////////////
  7. //  Defines
  8. #define BAD_DWORD (DWORD)-1
  9. #define WND_CLASS_NAME "Master Output Volume Msg Wnd Class"
  10. #define WND_NAME "Master Output Volume Msg Wnd"
  11. /////////////////////////////////////////////////////////////////////////////
  12. //  Globals
  13. PCVolumeOutMaster 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. CVolumeOutMaster::CVolumeOutMaster()
  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_dwMinimalVolume(BAD_DWORD),
  44. m_dwMaximalVolume(BAD_DWORD),
  45. m_pfUserSink(NULL),
  46. m_dwUserValue(0L)
  47. {
  48. if ( m_bOK = Init() )
  49. {
  50. g_pThis = this;
  51. if ( !Initialize() )
  52. {
  53. Done();
  54. g_pThis = NULL;
  55. }
  56. }
  57. }
  58. //////////////
  59. CVolumeOutMaster::~CVolumeOutMaster()
  60. {
  61. if ( m_bOK )
  62. Done();
  63. g_pThis = NULL;
  64. }
  65. //////////////
  66. bool CVolumeOutMaster::Init()
  67. {
  68. if ( !mixerGetNumDevs() )
  69. return false;
  70. // Getting Mixer ID
  71. HWAVEOUT hwaveOut;
  72. MMRESULT mmResult;
  73. WAVEFORMATEX WaveFmt;
  74. SetDeviceType( &WaveFmt );
  75. mmResult = waveOutOpen( &hwaveOut, WAVE_MAPPER, &WaveFmt, 0L, 0L, CALLBACK_NULL );
  76. if ( mmResult != MMSYSERR_NOERROR )
  77. {
  78. TRACE(".MasterOutputVolume: FAILURE: Could not open WaveOut Mapper. mmResult=%dn", mmResult );
  79. return false;
  80. } else {
  81. mmResult = mixerGetID( (HMIXEROBJ)hwaveOut, &m_uMixerID, MIXER_OBJECTF_HWAVEOUT );
  82. waveOutClose( hwaveOut );
  83. if ( mmResult != MMSYSERR_NOERROR )
  84. {
  85. TRACE(".MasterOutputVolume: FAILURE: WaveOut Mapper in Mixer is not available. mmResult=%dn", mmResult );
  86. return false;
  87. }
  88. }
  89. // Exposing Window to Mixer
  90. WNDCLASSEX wcx;
  91. memset( &wcx, 0, sizeof(WNDCLASSEX) );
  92. wcx.cbSize = sizeof(WNDCLASSEX);
  93. wcx.lpszClassName = WND_CLASS_NAME;
  94. wcx.lpfnWndProc = (WNDPROC)MixerWndProc;
  95. ::RegisterClassEx(&wcx);
  96. m_hWnd = CreateWindow( WND_CLASS_NAME,
  97. WND_NAME,
  98. WS_POPUP | WS_DISABLED,
  99. 0, 0, 0, 0,
  100. NULL, NULL, NULL, NULL );
  101. if ( !m_hWnd )
  102. {
  103. TRACE(".MasterOutputVolume: FAILURE: Could not create internal window.n" );
  104. return false;
  105. }
  106. ::ShowWindow(m_hWnd, SW_HIDE);
  107. mmResult = mixerOpen( (LPHMIXER)&m_dwMixerHandle, m_uMixerID, (DWORD)m_hWnd, 0L, CALLBACK_WINDOW );
  108. if ( mmResult != MMSYSERR_NOERROR )
  109. {
  110. TRACE(".MasterOutputVolume: FAILURE: Could not open Mixer. mmResult=%dn", mmResult );
  111. ::DestroyWindow( m_hWnd );
  112. return false;
  113. }
  114. return true;
  115. }
  116. //////////////
  117. void CVolumeOutMaster::Done()
  118. {
  119. if ( mixerClose( (HMIXER)m_dwMixerHandle ) != MMSYSERR_NOERROR )
  120. {
  121. TRACE(".MasterOutputVolume: WARNING: Could not close Mixer.n" );
  122. }
  123. ::DestroyWindow( m_hWnd );
  124. m_bInitialized = false;
  125. m_bOK = false;
  126. }
  127. //////////////
  128. void CVolumeOutMaster::OnControlChanged( DWORD dwControlID )
  129. {
  130. if ( m_dwVolumeControlID == dwControlID )
  131. {
  132. DWORD dwVolume = GetCurrentVolume();
  133. if ( (dwVolume!=BAD_DWORD) && (m_pfUserSink) )
  134. {
  135. (*m_pfUserSink)( dwVolume, m_dwUserValue );
  136. }
  137. }
  138. }
  139. //////////////
  140. bool CVolumeOutMaster::Initialize()
  141. {
  142. MMRESULT mmResult;
  143. if ( !m_bOK )
  144. return false;
  145. TRACE(".MasterOutputVolume: Initializing for Source MasterOut Line ..n" );
  146. MIXERLINE MixerLine;
  147. memset( &MixerLine, 0, sizeof(MIXERLINE) );
  148. MixerLine.cbStruct = sizeof(MIXERLINE);
  149. MixerLine.dwComponentType = MIXERLINE_COMPONENTTYPE_DST_SPEAKERS;
  150. mmResult = mixerGetLineInfo( (HMIXEROBJ)m_dwMixerHandle, &MixerLine, MIXER_GETLINEINFOF_COMPONENTTYPE );
  151. if ( mmResult != MMSYSERR_NOERROR )
  152. {
  153. TRACE(".MasterOutputVolume: FAILURE: Could not get Speakers Destionation Line for the MasterOut Source Line while initilaizing. mmResult=%dn", mmResult );
  154. return false;
  155. }
  156. MIXERCONTROL Control;
  157. memset( &Control, 0, sizeof(MIXERCONTROL) );
  158. Control.cbStruct = sizeof(MIXERCONTROL);
  159. MIXERLINECONTROLS LineControls;
  160. memset( &LineControls, 0, sizeof(MIXERLINECONTROLS) );
  161. LineControls.cbStruct = sizeof(MIXERLINECONTROLS);
  162. LineControls.dwControlType = MIXERCONTROL_CONTROLTYPE_VOLUME;
  163. LineControls.dwLineID = MixerLine.dwLineID;
  164. LineControls.cControls = 1;
  165. LineControls.cbmxctrl = sizeof(MIXERCONTROL);
  166. LineControls.pamxctrl = &Control;
  167. mmResult = mixerGetLineControls( (HMIXEROBJ)m_dwMixerHandle, &LineControls, MIXER_GETLINECONTROLSF_ONEBYTYPE );
  168. if ( mmResult == MMSYSERR_NOERROR )
  169. {
  170. if ( !(Control.fdwControl & MIXERCONTROL_CONTROLF_DISABLED) )
  171. {
  172. m_bAvailable = true;
  173. TRACE(".MasterOutputVolume: "%s" Volume control for the Speakers Source Line adopted.n", Control.szShortName );
  174. } else {
  175. TRACE(".MasterOutputVolume: WARNING: The Volume Control is disabled.n" );
  176. }
  177. } else {
  178. TRACE(".MasterOutputVolume: WARNING: Could not get the Speakers Source line Volume Control while initilaizing. mmResult=%dn", mmResult );
  179. }
  180. m_nChannelCount = MixerLine.cChannels;
  181. m_dwLineID = LineControls.dwLineID;
  182. m_dwVolumeControlID = Control.dwControlID;
  183. m_dwMinimalVolume = Control.Bounds.dwMinimum;
  184. m_dwMaximalVolume = Control.Bounds.dwMaximum;
  185. m_dwVolumeStep = Control.Metrics.cSteps;
  186. m_bInitialized = true;
  187. return true;
  188. }
  189. //////////////
  190. void CVolumeOutMaster::EnableLine( bool bEnable )
  191. {
  192. if ( !m_bInitialized )
  193. return;
  194. bool bAnyEnabled = false;
  195. MMRESULT mmResult;
  196. MIXERLINE lineDestination;
  197. memset( &lineDestination, 0, sizeof(MIXERLINE) );
  198. lineDestination.cbStruct = sizeof(MIXERLINE);
  199. lineDestination.dwLineID = m_dwLineID;
  200. mmResult = mixerGetLineInfo( (HMIXEROBJ)m_dwMixerHandle, &lineDestination, MIXER_GETLINEINFOF_LINEID );
  201. if ( mmResult != MMSYSERR_NOERROR )
  202. {
  203. if ( bEnable )
  204. {
  205. TRACE(".MasterOutputVolume: FAILURE: Could not get the Speakers Destination Line while enabling. mmResult=%dn", mmResult );
  206. } else {
  207. TRACE(".MasterOutputVolume: FAILURE: Could not get the Speakers Destination Line while disabling. mmResult=%dn", mmResult );
  208. }
  209. return;
  210. }
  211. // Getting all line's controls
  212. int nControlCount = lineDestination.cControls;
  213. int nChannelCount = lineDestination.cChannels;
  214. MIXERLINECONTROLS LineControls;
  215. memset( &LineControls, 0, sizeof(MIXERLINECONTROLS) );
  216. MIXERCONTROL* aControls = (MIXERCONTROL*)malloc( nControlCount * sizeof(MIXERCONTROL) );
  217. if ( !aControls )
  218. {
  219. if ( bEnable )
  220. {
  221. TRACE(".MasterOutputVolume: FAILURE: Out of memory while enabling the line.n" );
  222. } else {
  223. TRACE(".MasterOutputVolume: FAILURE: Out of memory while disabling the line.n" );
  224. }
  225. return;
  226. }
  227. memset( &aControls[0], 0, sizeof(nControlCount * sizeof(MIXERCONTROL)) );
  228. for ( int i = 0; i < nControlCount; i++ )
  229. {
  230. aControls[i].cbStruct = sizeof(MIXERCONTROL);
  231. }
  232. LineControls.cbStruct = sizeof(MIXERLINECONTROLS);
  233. LineControls.dwLineID = lineDestination.dwLineID;
  234. LineControls.cControls = nControlCount;
  235. LineControls.cbmxctrl = sizeof(MIXERCONTROL);
  236. LineControls.pamxctrl = &aControls[0];
  237. mmResult = mixerGetLineControls( (HMIXEROBJ)m_dwMixerHandle, &LineControls, MIXER_GETLINECONTROLSF_ALL );
  238. if ( mmResult == MMSYSERR_NOERROR )
  239. {
  240. for ( i = 0; i < nControlCount; i++ )
  241. {
  242. LONG lValue;
  243. bool bReadyToSet = false;
  244. switch (aControls[i].dwControlType)
  245. {
  246. case MIXERCONTROL_CONTROLTYPE_MUTE:
  247. lValue = (BOOL)!bEnable;
  248. bReadyToSet = true;
  249. break;
  250. case MIXERCONTROL_CONTROLTYPE_SINGLESELECT:
  251. lValue = (BOOL)bEnable;
  252. bReadyToSet = true;
  253. break;
  254. case MIXERCONTROL_CONTROLTYPE_MUX:
  255. lValue = (BOOL)bEnable;
  256. bReadyToSet = true;
  257. break;
  258. case MIXERCONTROL_CONTROLTYPE_MULTIPLESELECT:
  259. lValue = (BOOL)bEnable;
  260. bReadyToSet = true;
  261. break;
  262. case MIXERCONTROL_CONTROLTYPE_MIXER:
  263. lValue = (BOOL)bEnable;
  264. bReadyToSet = true;
  265. break;
  266. }
  267. if ( bReadyToSet )
  268. {
  269. MIXERCONTROLDETAILS_BOOLEAN* aDetails = NULL;
  270. int nMultipleItems = aControls[i].cMultipleItems;
  271. int nChannels = nChannelCount;
  272. // MIXERCONTROLDETAILS
  273. MIXERCONTROLDETAILS ControlDetails;
  274. memset( &ControlDetails, 0, sizeof(MIXERCONTROLDETAILS) );
  275. ControlDetails.cbStruct = sizeof(MIXERCONTROLDETAILS);
  276. ControlDetails.dwControlID = aControls[i].dwControlID;
  277. if ( aControls[i].fdwControl & MIXERCONTROL_CONTROLF_UNIFORM )
  278. {
  279. nChannels = 1;
  280. }
  281. if ( aControls[i].fdwControl & MIXERCONTROL_CONTROLF_MULTIPLE )
  282. {
  283. nMultipleItems = aControls[i].cMultipleItems;
  284. aDetails = (MIXERCONTROLDETAILS_BOOLEAN*)malloc(nMultipleItems*nChannels*sizeof(MIXERCONTROLDETAILS_BOOLEAN));
  285. if ( !aDetails )
  286. {
  287. if ( bEnable )
  288. {
  289. TRACE(".MasterOutputVolume: FAILURE: Out of memory while enabling the line.n" );
  290. } else {
  291. TRACE(".MasterOutputVolume: FAILURE: Out of memory while disabling the line.n" );
  292. }
  293. continue;
  294. }
  295. for ( int nItem = 0; nItem < nMultipleItems; nItem++ )
  296. {
  297. /*
  298. if ( ( aControls[i].dwControlType & MIXERCONTROL_CONTROLTYPE_SINGLESELECT )
  299.   && ( nItem > 0 ) )
  300. {
  301. lValue = (LONG)!((BOOL)lValue);
  302. }
  303. */
  304. for ( int nChannel = 0; nChannel < nChannels; nChannel++ )
  305. {
  306. aDetails[nItem+nChannel].fValue = lValue;
  307. }
  308. }
  309. } else {
  310. nMultipleItems = 0;
  311. aDetails = (MIXERCONTROLDETAILS_BOOLEAN*)malloc(nChannels*sizeof(MIXERCONTROLDETAILS_BOOLEAN));
  312. if ( !aDetails )
  313. {
  314. if ( bEnable )
  315. {
  316. TRACE(".MasterOutputVolume: FAILURE: Out of memory while enabling the line.n" );
  317. } else {
  318. TRACE(".MasterOutputVolume: FAILURE: Out of memory while disabling the line.n" );
  319. }
  320. continue;
  321. }
  322. for ( int nChannel = 0; nChannel < nChannels; nChannel++ )
  323. {
  324. aDetails[nChannel].fValue = (LONG)lValue;
  325. }
  326. }
  327. ControlDetails.cChannels = nChannels;
  328. ControlDetails.cMultipleItems = nMultipleItems;
  329. ControlDetails.cbDetails = sizeof(MIXERCONTROLDETAILS_BOOLEAN);
  330. ControlDetails.paDetails = &aDetails[0];
  331. mmResult = mixerSetControlDetails( (HMIXEROBJ)m_dwMixerHandle, &ControlDetails, 0L );
  332. if ( mmResult == MMSYSERR_NOERROR )
  333. {
  334. if ( bEnable )
  335. {
  336. TRACE(".MasterOutputVolume: Enabling Line: Speakers Line control "%s"(0x%X) has been set to %d.n", aControls[i].szShortName, aControls[i].dwControlType, lValue );
  337. } else {
  338. TRACE(".MasterOutputVolume: Disabling Line: Speakers Line control "%s"(0x%X) has been set to %d.n", aControls[i].szShortName, aControls[i].dwControlType, lValue );
  339. }
  340. bAnyEnabled = true;
  341. }
  342. free( aDetails );
  343. }
  344. }
  345. } else {
  346. if ( bEnable )
  347. {
  348. TRACE(".MasterOutputVolume: FAILURE: Could not get the line controls while enabling. mmResult=%dn", mmResult );
  349. } else {
  350. TRACE(".MasterOutputVolume: FAILURE: Could not get the line controls while disabling. mmResult=%dn", mmResult );
  351. }
  352. }
  353. free( aControls );
  354. if ( !bAnyEnabled )
  355. {
  356. if ( bEnable )
  357. {
  358. TRACE(".MasterOutputVolume: WARNING: No controls were found for enabling the line.n" );
  359. } else {
  360. TRACE(".MasterOutputVolume: WARNING: No controls were found for disabling the line.n" );
  361. }
  362. }
  363. }
  364. //////////////////////////////////////////////
  365. // IVolume interface
  366. //////////////
  367. bool CVolumeOutMaster::IsAvailable()
  368. {
  369. return m_bAvailable;
  370. }
  371. //////////////
  372. void CVolumeOutMaster::Enable()
  373. {
  374. EnableLine( true );
  375. }
  376. void CVolumeOutMaster::Disable()
  377. {
  378. EnableLine( false );
  379. }
  380. //////////////
  381. DWORD CVolumeOutMaster::GetVolumeMetric()
  382. {
  383. if ( !m_bAvailable )
  384. return BAD_DWORD;
  385. return m_dwVolumeStep;
  386. }
  387. //////////////
  388. DWORD CVolumeOutMaster::GetMinimalVolume()
  389. {
  390. if ( !m_bAvailable )
  391. return BAD_DWORD;
  392. return m_dwMinimalVolume;
  393. }
  394. //////////////
  395. DWORD CVolumeOutMaster::GetMaximalVolume()
  396. {
  397. if ( !m_bAvailable )
  398. return BAD_DWORD;
  399. return m_dwMaximalVolume;
  400. }
  401. //////////////
  402. DWORD CVolumeOutMaster::GetCurrentVolume()
  403. {
  404. if ( !m_bAvailable )
  405. return BAD_DWORD;
  406. MIXERCONTROLDETAILS_UNSIGNED* aDetails = (MIXERCONTROLDETAILS_UNSIGNED*)malloc(m_nChannelCount*sizeof(MIXERCONTROLDETAILS_UNSIGNED));
  407. if ( !aDetails )
  408. return BAD_DWORD;
  409. MIXERCONTROLDETAILS ControlDetails;
  410. memset( &ControlDetails, 0, sizeof(MIXERCONTROLDETAILS) );
  411. ControlDetails.cbStruct = sizeof(MIXERCONTROLDETAILS);
  412. ControlDetails.dwControlID = m_dwVolumeControlID;
  413. ControlDetails.cChannels = m_nChannelCount;
  414. ControlDetails.cMultipleItems = 0;
  415. ControlDetails.cbDetails = sizeof(MIXERCONTROLDETAILS_UNSIGNED);
  416. ControlDetails.paDetails = &aDetails[0];
  417. MMRESULT mmResult = mixerGetControlDetails( (HMIXEROBJ)m_dwMixerHandle, &ControlDetails, MIXER_GETCONTROLDETAILSF_VALUE );
  418. DWORD dw = aDetails[0].dwValue;
  419. free( aDetails );
  420. if ( mmResult != MMSYSERR_NOERROR )
  421. {
  422. TRACE(".MasterOutputVolume: FAILURE: Could not get volume. mmResult=%dn", mmResult );
  423. return BAD_DWORD;
  424. }
  425. return dw;
  426. }
  427. //////////////
  428. void CVolumeOutMaster::SetCurrentVolume( DWORD dwValue )
  429. {
  430. if ( !m_bAvailable || (dwValue<m_dwMinimalVolume) || (dwValue>m_dwMaximalVolume) )
  431. return;
  432. MIXERCONTROLDETAILS_UNSIGNED* aDetails = (MIXERCONTROLDETAILS_UNSIGNED*)malloc(m_nChannelCount*sizeof(MIXERCONTROLDETAILS_UNSIGNED));
  433. if ( !aDetails )
  434. return;
  435. for ( int i = 0; i < m_nChannelCount; i++ )
  436. {
  437. aDetails[i].dwValue = dwValue;
  438. }
  439. MIXERCONTROLDETAILS ControlDetails;
  440. memset( &ControlDetails, 0, sizeof(MIXERCONTROLDETAILS) );
  441. ControlDetails.cbStruct = sizeof(MIXERCONTROLDETAILS);
  442. ControlDetails.dwControlID = m_dwVolumeControlID;
  443. ControlDetails.cChannels = m_nChannelCount;
  444. ControlDetails.cMultipleItems = 0;
  445. ControlDetails.cbDetails = sizeof(MIXERCONTROLDETAILS_UNSIGNED);
  446. ControlDetails.paDetails = &aDetails[0];
  447. MMRESULT mmResult = mixerSetControlDetails( (HMIXEROBJ)m_dwMixerHandle, &ControlDetails, MIXER_SETCONTROLDETAILSF_VALUE );
  448. free( aDetails );
  449. if ( mmResult != MMSYSERR_NOERROR )
  450. {
  451. TRACE(".MasterOutputVolume: FAILURE: Could not set volume(%d) mmResult=%dn", dwValue, mmResult );
  452. }
  453. }
  454. //////////////
  455. void CVolumeOutMaster::RegisterNotificationSink( PONMICVOULUMECHANGE pfUserSink, DWORD dwUserValue )
  456. {
  457. m_pfUserSink = pfUserSink;
  458. m_dwUserValue = dwUserValue;
  459. }
  460. ////////////////////////////////////////////////////////////////////////
  461. LRESULT CALLBACK CVolumeOutMaster::MixerWndProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
  462. {
  463. if ( uMsg == MM_MIXM_CONTROL_CHANGE )
  464. {
  465. if ( g_pThis )
  466. {
  467. g_pThis->OnControlChanged( (DWORD)lParam );
  468. }
  469. }
  470. return ::DefWindowProc( hwnd, uMsg, wParam, lParam);
  471. }