VolumeOutWave.cpp
上传用户:oldpeter23
上传日期:2013-01-09
资源大小:1111k
文件大小:14k
源码类别:

IP电话/视频会议

开发平台:

Visual C++

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