Source code of Windows XP (NT5)
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.

311 lines
9.5 KiB

  1. // SoundCtl.cpp : Implementation of CSoundCtl
  2. #include "stdafx.h"
  3. #include "Sndctl.h"
  4. #include "SoundCtl.h"
  5. #define SND_VALUE_MAX 0xffff
  6. //const DWORD gc_dwSoundTarget = MIXERLINE_COMPONENTTYPE_DST_SPEAKERS;
  7. //***************************************************************************************
  8. MMRESULT
  9. CSoundCtl::AdjustLineVolume(HMIXEROBJ hmx, MIXERCONTROL *pmxctrl, DWORD cChannels, DWORD dwValue)
  10. {
  11. if (dwValue > SND_VALUE_MAX)
  12. return MIXERR_INVALVALUE;
  13. MIXERCONTROLDETAILS mxcd;
  14. BYTE data[64];
  15. MIXERCONTROLDETAILS_UNSIGNED *pVolumeLeft, *pVolumeRight;
  16. MMRESULT mmResult;
  17. mxcd.cbStruct = sizeof(MIXERCONTROLDETAILS);
  18. mxcd.cChannels = cChannels;
  19. mxcd.dwControlID = pmxctrl->dwControlID;
  20. mxcd.cMultipleItems = pmxctrl->cMultipleItems; // should be 0!
  21. mxcd.cbDetails = sizeof(MIXERCONTROLDETAILS_UNSIGNED);
  22. mxcd.paDetails = (LPVOID)data; // 1st long=left channel, 2nd long=right channel
  23. mmResult = mixerGetControlDetails(hmx, &mxcd, MIXER_GETCONTROLDETAILSF_VALUE);
  24. if (mmResult != MMSYSERR_NOERROR)
  25. return mmResult;
  26. pVolumeLeft = (MIXERCONTROLDETAILS_UNSIGNED *)data;
  27. pVolumeRight = pVolumeLeft + 1;
  28. DWORD dwMin = pmxctrl->Bounds.dwMinimum;
  29. DWORD dwMax = pmxctrl->Bounds.dwMaximum;
  30. // dwValue is a volume expressed on the scale 0..SND_VALUE_MAX. Map this linearly
  31. // to the scale dwMin..dwMax
  32. DWORD dwDesiredVolume = dwMin + ((dwMax-dwMin)*dwValue)/SND_VALUE_MAX;
  33. pVolumeLeft->dwValue = dwDesiredVolume;
  34. pVolumeRight->dwValue = dwDesiredVolume;
  35. return mixerSetControlDetails(hmx, &mxcd, MIXER_SETCONTROLDETAILSF_VALUE);
  36. }
  37. //***************************************************************************************
  38. MMRESULT
  39. CSoundCtl::AdjustLineMute(HMIXEROBJ hmx, MIXERCONTROL *pmxctrl, DWORD cChannels, DWORD dwValue)
  40. {
  41. MIXERCONTROLDETAILS mxcd;
  42. BYTE data[64];
  43. MIXERCONTROLDETAILS_BOOLEAN *pMute;
  44. MMRESULT mmResult;
  45. mxcd.cbStruct = sizeof(MIXERCONTROLDETAILS);
  46. mxcd.cChannels = 1; // mixerGetControlDetails fails if this is cChannels
  47. mxcd.dwControlID = pmxctrl->dwControlID;
  48. mxcd.cMultipleItems = pmxctrl->cMultipleItems; // should be 0!
  49. mxcd.cbDetails = sizeof(MIXERCONTROLDETAILS_BOOLEAN);
  50. mxcd.paDetails = (LPVOID)data; // 1st bool=mute left, 2nd bool=mute right
  51. mmResult = mixerGetControlDetails(hmx, &mxcd, MIXER_GETCONTROLDETAILSF_VALUE);
  52. if (mmResult != MMSYSERR_NOERROR)
  53. return mmResult;
  54. pMute = (MIXERCONTROLDETAILS_BOOLEAN *)data;
  55. pMute->fValue = dwValue;
  56. return mixerSetControlDetails(hmx, &mxcd, MIXER_SETCONTROLDETAILSF_VALUE);
  57. }
  58. //***************************************************************************************
  59. MMRESULT
  60. CSoundCtl::AdjustLine(HMIXEROBJ hmx, MIXERLINE *pmxl, DWORD dwControlType, DWORD dwValue)
  61. {
  62. MMRESULT mmResult = MMSYSERR_NOERROR;
  63. switch (pmxl->dwComponentType)
  64. {
  65. // TBD: Only handling volume level output for these destinations from mixer!
  66. // Currently hardcoded.
  67. case MIXERLINE_COMPONENTTYPE_DST_SPEAKERS:
  68. case MIXERLINE_COMPONENTTYPE_DST_MONITOR:
  69. case MIXERLINE_COMPONENTTYPE_DST_HEADPHONES:
  70. case MIXERLINE_COMPONENTTYPE_DST_DIGITAL:
  71. case MIXERLINE_COMPONENTTYPE_SRC_WAVEOUT:
  72. case MIXERLINE_COMPONENTTYPE_SRC_COMPACTDISC:
  73. case MIXERLINE_COMPONENTTYPE_SRC_ANALOG:
  74. case MIXERLINE_COMPONENTTYPE_SRC_AUXILIARY:
  75. case MIXERLINE_COMPONENTTYPE_SRC_LINE:
  76. case MIXERLINE_COMPONENTTYPE_SRC_UNDEFINED:
  77. case MIXERLINE_COMPONENTTYPE_SRC_DIGITAL:
  78. case MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE:
  79. case MIXERLINE_COMPONENTTYPE_SRC_SYNTHESIZER:
  80. case MIXERLINE_COMPONENTTYPE_SRC_TELEPHONE:
  81. case MIXERLINE_COMPONENTTYPE_SRC_PCSPEAKER:
  82. MIXERLINECONTROLS mxlc;
  83. MIXERCONTROL amxctrl[10];
  84. mxlc.cbStruct = sizeof(MIXERLINECONTROLS);
  85. mxlc.dwLineID = pmxl->dwLineID;
  86. mxlc.cControls = pmxl->cControls;
  87. mxlc.cbmxctrl = sizeof(MIXERCONTROL);
  88. mxlc.pamxctrl = amxctrl;
  89. MMRESULT mmResult;
  90. mmResult = mixerGetLineControls((hmx),(LPMIXERLINECONTROLS)&mxlc,
  91. MIXER_GETLINECONTROLSF_ALL);
  92. if ( mmResult != MMSYSERR_NOERROR )
  93. return mmResult;
  94. DWORD iCtrl;
  95. for (iCtrl=0; iCtrl< pmxl->cControls; iCtrl++ )
  96. {
  97. if (amxctrl[iCtrl].dwControlType == dwControlType)
  98. {
  99. switch (dwControlType)
  100. {
  101. case MIXERCONTROL_CONTROLTYPE_VOLUME:
  102. return AdjustLineVolume(hmx, &amxctrl[iCtrl], pmxl->cChannels, dwValue);
  103. case MIXERCONTROL_CONTROLTYPE_MUTE:
  104. return AdjustLineMute(hmx, &amxctrl[iCtrl], pmxl->cChannels, dwValue);
  105. default:
  106. return MIXERR_INVALCONTROL;
  107. }
  108. }
  109. }
  110. // Couldn't find a control of the desired type in this line
  111. return MIXERR_INVALCONTROL;
  112. default:
  113. // We don't yet support changing volume on this type of line
  114. return MIXERR_INVALLINE;
  115. }
  116. // This statement is unreachable
  117. return MIXERR_INVALLINE;
  118. }
  119. //****************************************************************************************
  120. MMRESULT
  121. CSoundCtl::AdjustSound(DWORD dwComponentType, DWORD dwControlType, DWORD dwValue)
  122. {
  123. UINT nMixers = mixerGetNumDevs();
  124. if ( nMixers == 0 )
  125. {
  126. return MMSYSERR_NOERROR;
  127. }
  128. // Is the component we are changing parameters for one of the destinations of the
  129. // mixer?
  130. bool bComponentIsDestType = false;
  131. if (dwComponentType > MIXERLINE_COMPONENTTYPE_DST_FIRST &&
  132. dwComponentType <= MIXERLINE_COMPONENTTYPE_DST_LAST)
  133. {
  134. bComponentIsDestType = true;
  135. }
  136. for ( UINT iMixer=0; iMixer<nMixers; iMixer++ )
  137. {
  138. MIXERCAPS mxcaps;
  139. MMRESULT mmResult;
  140. mmResult = mixerGetDevCaps( iMixer, (LPMIXERCAPS)&mxcaps, sizeof(MIXERCAPS) );
  141. if ( mmResult != MMSYSERR_NOERROR )
  142. {
  143. return mmResult;
  144. }
  145. HMIXEROBJ hmx;
  146. // Idiosyncracy in the mixer API. mixerOpen returns HMIXER but other functions
  147. // take HMIXEROBJ. Both are handles.
  148. mmResult = mixerOpen((LPHMIXER)&hmx, iMixer, 0, 0, MIXER_OBJECTF_MIXER );
  149. if (mmResult != MMSYSERR_NOERROR)
  150. {
  151. mixerClose((HMIXER)hmx);
  152. return mmResult;
  153. }
  154. // To get the sources, one must enumerate the destinations first and then
  155. // enumerate the sources for each dest.
  156. for (DWORD iDest=0; iDest < mxcaps.cDestinations; iDest++)
  157. {
  158. MIXERLINE mxl;
  159. mxl.cbStruct = sizeof(MIXERLINE);
  160. mxl.dwDestination = iDest;
  161. mxl.dwSource = 0;
  162. mmResult = mixerGetLineInfo(hmx, &mxl, MIXER_GETLINEINFOF_DESTINATION);
  163. if ( mmResult != MMSYSERR_NOERROR )
  164. {
  165. mixerClose((HMIXER)hmx);
  166. return mmResult;
  167. }
  168. if (bComponentIsDestType)
  169. {
  170. // Adjust destination
  171. if (mxl.dwComponentType == dwComponentType)
  172. {
  173. mmResult = AdjustLine(hmx, &mxl, dwControlType, dwValue);
  174. }
  175. }
  176. else
  177. {
  178. // For each source connected to this destination that is of
  179. // the desired component type, adjust it.
  180. DWORD cConnections = mxl.cConnections;
  181. for (DWORD iSource=0; iSource < cConnections; iSource++)
  182. {
  183. mxl.dwDestination = iDest;
  184. mxl.dwSource = iSource;
  185. mmResult = mixerGetLineInfo(hmx, &mxl, MIXER_GETLINEINFOF_SOURCE);
  186. if ( mmResult != MMSYSERR_NOERROR )
  187. {
  188. mixerClose((HMIXER)hmx);
  189. return mmResult;
  190. }
  191. if (mxl.dwComponentType == dwComponentType)
  192. {
  193. mmResult = AdjustLine(hmx, &mxl, dwControlType, dwValue);
  194. }
  195. } // for over sources
  196. } // if bComponentIsDestType
  197. } // for over destinations
  198. mixerClose((HMIXER)hmx);
  199. } // for over mixers
  200. return MMSYSERR_NOERROR;
  201. }
  202. //****************************************************************************************
  203. CSoundCtl::CSoundCtl() :
  204. m_dwComponentType(MIXERLINE_COMPONENTTYPE_DST_SPEAKERS)
  205. {
  206. }
  207. /////////////////////////////////////////////////////////////////////////////
  208. // CSoundCtl
  209. STDMETHODIMP CSoundCtl::get_Volume(DWORD *pVal)
  210. {
  211. return S_OK;
  212. }
  213. STDMETHODIMP CSoundCtl::put_Volume(DWORD newVal)
  214. {
  215. MMRESULT mmResult;
  216. mmResult = AdjustSound(m_dwComponentType, MIXERCONTROL_CONTROLTYPE_VOLUME, newVal);
  217. if (mmResult == MMSYSERR_NOERROR)
  218. return S_OK;
  219. return E_FAIL;
  220. }
  221. STDMETHODIMP CSoundCtl::get_Mute(VARIANT_BOOL *pVal)
  222. {
  223. return S_OK;
  224. }
  225. STDMETHODIMP CSoundCtl::put_Mute(VARIANT_BOOL newVal)
  226. {
  227. MMRESULT mmResult;
  228. DWORD dwNewVal = (newVal == VARIANT_TRUE ? 1 : 0);
  229. mmResult = AdjustSound(m_dwComponentType, MIXERCONTROL_CONTROLTYPE_MUTE, dwNewVal);
  230. if (mmResult == MMSYSERR_NOERROR)
  231. return S_OK;
  232. return E_FAIL;
  233. }
  234. STDMETHODIMP CSoundCtl::get_ComponentType(long *pVal)
  235. {
  236. *pVal = m_dwComponentType;
  237. return S_OK;
  238. }
  239. STDMETHODIMP CSoundCtl::put_ComponentType(long newVal)
  240. {
  241. m_dwComponentType = newVal;
  242. return S_OK;
  243. }