Counter Strike : Global Offensive Source Code
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.

553 lines
15 KiB

  1. //========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include "audio_pch.h"
  8. // memdbgon must be the last include file in a .cpp file!!!
  9. #include "tier0/memdbgon.h"
  10. #ifdef _PS3
  11. #include "voice_mixer_controls.h"
  12. IMixerControls* g_pMixerControls = NULL;
  13. void InitMixerControls()
  14. {
  15. if ( !g_pMixerControls )
  16. {
  17. Warning( "InitMixerControls is not implemented on PS3\n" );
  18. }
  19. }
  20. void ShutdownMixerControls()
  21. {
  22. delete g_pMixerControls;
  23. g_pMixerControls = NULL;
  24. }
  25. #else
  26. // NOTE: Vista deprecated these APIs
  27. // Under vista these settings are per-session (not persistent)
  28. // The correct method is to use the AudioEndpoint COM objects to manage controls like this
  29. // The interface is not 1:1 so for now we'll just back the state with convars and reapply it
  30. // on init of the mixer controls. In the future when XP is no longer the majority of our user base
  31. // we should revisit this and move to the new API.
  32. // http://msdn.microsoft.com/en-us/library/aa964574(VS.85).aspx
  33. ConVar voice_mixer_mute("voice_mixer_mute", "0", FCVAR_ARCHIVE);
  34. ConVar voice_mixer_boost("voice_mixer_boost", "0", FCVAR_ARCHIVE);
  35. ConVar voice_mixer_volume("voice_mixer_volume", "1.0", FCVAR_ARCHIVE);
  36. class CMixerControls : public IMixerControls
  37. {
  38. public:
  39. CMixerControls();
  40. virtual ~CMixerControls();
  41. virtual bool GetValue_Float(Control iControl, float &value);
  42. virtual bool SetValue_Float(Control iControl, float value);
  43. virtual bool SelectMicrophoneForWaveInput();
  44. private:
  45. bool Init();
  46. void Term();
  47. void Clear();
  48. bool GetControlOption_Bool(DWORD dwControlID, DWORD cMultipleItems, bool &bValue);
  49. bool SetControlOption_Bool(DWORD dwControlID, DWORD cMultipleItems, const bool bValue);
  50. bool GetControlOption_Unsigned(DWORD dwControlID, DWORD cMultipleItems, DWORD &value);
  51. bool SetControlOption_Unsigned(DWORD dwControlID, DWORD cMultipleItems, const DWORD value);
  52. bool GetLineControls( DWORD dwLineID, MIXERCONTROL *controls, DWORD nControls );
  53. void FindMicSelectControl( DWORD dwLineID, DWORD nControls );
  54. private:
  55. HMIXER m_hMixer;
  56. class ControlInfo
  57. {
  58. public:
  59. DWORD m_dwControlID;
  60. DWORD m_cMultipleItems;
  61. bool m_bFound;
  62. };
  63. DWORD m_dwMicSelectControlID;
  64. DWORD m_dwMicSelectMultipleItems;
  65. DWORD m_dwMicSelectControlType;
  66. DWORD m_dwMicSelectIndex;
  67. // Info about the controls we found.
  68. ControlInfo m_ControlInfos[NumControls];
  69. };
  70. CMixerControls::CMixerControls()
  71. {
  72. m_dwMicSelectControlID = 0xFFFFFFFF;
  73. Clear();
  74. Init();
  75. }
  76. CMixerControls::~CMixerControls()
  77. {
  78. Term();
  79. }
  80. bool CMixerControls::Init()
  81. {
  82. Term();
  83. MMRESULT mmr;
  84. bool bFoundMixer = false;
  85. bool bFoundConnectionWithMicVolume = false;
  86. CUtlVectorFixedGrowable<MIXERCONTROL, 64> controls;
  87. // Iterate over all the devices
  88. // This is done in reverse so the 0th device is our fallback if none of them had the correct MicVolume control
  89. for ( int iDevice = static_cast<int>( mixerGetNumDevs() ) - 1; iDevice >= 0 && !bFoundConnectionWithMicVolume; --iDevice )
  90. {
  91. // Open the mixer.
  92. mmr = mixerOpen(&m_hMixer, (DWORD)iDevice, 0, 0, 0 );
  93. if(mmr != MMSYSERR_NOERROR)
  94. {
  95. continue;
  96. }
  97. // Iterate over each destination line, looking for Play Controls.
  98. MIXERCAPS mxcaps;
  99. mmr = mixerGetDevCaps((UINT)m_hMixer, &mxcaps, sizeof(mxcaps));
  100. if(mmr != MMSYSERR_NOERROR)
  101. {
  102. continue;
  103. }
  104. bFoundMixer = true;
  105. for(UINT u = 0; u < mxcaps.cDestinations; u++)
  106. {
  107. MIXERLINE recordLine;
  108. recordLine.cbStruct = sizeof(recordLine);
  109. recordLine.dwDestination = u;
  110. mmr = mixerGetLineInfo((HMIXEROBJ)m_hMixer, &recordLine, MIXER_GETLINEINFOF_DESTINATION);
  111. if(mmr != MMSYSERR_NOERROR)
  112. continue;
  113. // Go through the controls that aren't attached to a specific src connection.
  114. // We're looking for the checkbox that enables the user's microphone for waveIn.
  115. if( recordLine.dwComponentType == MIXERLINE_COMPONENTTYPE_DST_WAVEIN )
  116. {
  117. FindMicSelectControl( recordLine.dwLineID, recordLine.cControls );
  118. }
  119. // Now iterate over each connection (things like wave out, microphone, speaker, CD audio), looking for Microphone.
  120. UINT cConnections = (UINT)recordLine.cConnections;
  121. for (UINT v = 0; v < cConnections; v++)
  122. {
  123. MIXERLINE micLine;
  124. micLine.cbStruct = sizeof(micLine);
  125. micLine.dwDestination = u;
  126. micLine.dwSource = v;
  127. mmr = mixerGetLineInfo((HMIXEROBJ)m_hMixer, &micLine, MIXER_GETLINEINFOF_SOURCE);
  128. if(mmr != MMSYSERR_NOERROR)
  129. continue;
  130. // Now look at all the controls (volume, mute, boost, etc).
  131. controls.RemoveAll();
  132. controls.SetCount(micLine.cControls);
  133. if( !GetLineControls( micLine.dwLineID, controls.Base(), micLine.cControls ) )
  134. continue;
  135. for(UINT i=0; i < micLine.cControls; i++)
  136. {
  137. MIXERCONTROL *pControl = &controls[i];
  138. if(micLine.dwComponentType == MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE)
  139. {
  140. if( pControl->dwControlType == MIXERCONTROL_CONTROLTYPE_ONOFF &&
  141. (
  142. strstr(pControl->szShortName, "Gain") ||
  143. strstr(pControl->szShortName, "Boos") ||
  144. strstr(pControl->szShortName, "+20d")
  145. )
  146. )
  147. {
  148. // This is the (record) boost option.
  149. m_ControlInfos[MicBoost].m_bFound = true;
  150. m_ControlInfos[MicBoost].m_dwControlID = pControl->dwControlID;
  151. m_ControlInfos[MicBoost].m_cMultipleItems = pControl->cMultipleItems;
  152. }
  153. if(recordLine.dwComponentType == MIXERLINE_COMPONENTTYPE_DST_SPEAKERS &&
  154. pControl->dwControlType == MIXERCONTROL_CONTROLTYPE_MUTE)
  155. {
  156. // This is the mute button.
  157. m_ControlInfos[MicMute].m_bFound = true;
  158. m_ControlInfos[MicMute].m_dwControlID = pControl->dwControlID;
  159. m_ControlInfos[MicMute].m_cMultipleItems = pControl->cMultipleItems;
  160. }
  161. if(recordLine.dwComponentType == MIXERLINE_COMPONENTTYPE_DST_WAVEIN &&
  162. pControl->dwControlType == MIXERCONTROL_CONTROLTYPE_VOLUME)
  163. {
  164. // This is the mic input level.
  165. m_ControlInfos[MicVolume].m_bFound = true;
  166. m_ControlInfos[MicVolume].m_dwControlID = pControl->dwControlID;
  167. m_ControlInfos[MicVolume].m_cMultipleItems = pControl->cMultipleItems;
  168. // We found a good recording device and can stop looking throught the available devices
  169. bFoundConnectionWithMicVolume = true;
  170. }
  171. }
  172. }
  173. }
  174. }
  175. }
  176. if ( !bFoundMixer )
  177. {
  178. // Failed to find any mixer (MixVolume or not)
  179. Term();
  180. return false;
  181. }
  182. if ( m_ControlInfos[MicBoost].m_bFound )
  183. {
  184. SetControlOption_Bool(m_ControlInfos[MicBoost].m_dwControlID, m_ControlInfos[MicBoost].m_cMultipleItems, voice_mixer_boost.GetBool());
  185. }
  186. if ( m_ControlInfos[MicMute].m_bFound )
  187. {
  188. SetControlOption_Bool(m_ControlInfos[MicMute].m_dwControlID, m_ControlInfos[MicMute].m_cMultipleItems, voice_mixer_mute.GetBool());
  189. }
  190. if ( m_ControlInfos[MicVolume].m_bFound )
  191. {
  192. DWORD dwValue = (DWORD)(voice_mixer_volume.GetFloat() * 65535.0f);
  193. SetControlOption_Unsigned(m_ControlInfos[MicVolume].m_dwControlID, m_ControlInfos[MicVolume].m_cMultipleItems, dwValue);
  194. }
  195. return true;
  196. }
  197. void CMixerControls::Term()
  198. {
  199. if(m_hMixer)
  200. {
  201. mixerClose(m_hMixer);
  202. m_hMixer = 0;
  203. }
  204. Clear();
  205. }
  206. bool CMixerControls::GetValue_Float( Control iControl, float &flValue )
  207. {
  208. if( iControl < 0 || iControl >= NumControls || !m_ControlInfos[iControl].m_bFound )
  209. return false;
  210. switch( iControl )
  211. {
  212. case MicBoost:
  213. {
  214. bool bValue = voice_mixer_boost.GetBool();
  215. flValue = (float)bValue;
  216. return true;
  217. }
  218. break;
  219. case MicMute:
  220. {
  221. bool bValue = voice_mixer_mute.GetBool();
  222. flValue = (float)bValue;
  223. return true;
  224. }
  225. break;
  226. case MicVolume:
  227. flValue= voice_mixer_volume.GetFloat();
  228. return true;
  229. }
  230. return false;
  231. }
  232. bool CMixerControls::SetValue_Float(Control iControl, float flValue )
  233. {
  234. if(iControl < 0 || iControl >= NumControls || !m_ControlInfos[iControl].m_bFound)
  235. return false;
  236. if ( iControl == MicBoost )
  237. {
  238. bool bValue = !!flValue;
  239. voice_mixer_boost.SetValue( bValue );
  240. return SetControlOption_Bool(m_ControlInfos[iControl].m_dwControlID, m_ControlInfos[iControl].m_cMultipleItems, bValue);
  241. }
  242. if(iControl == MicMute)
  243. {
  244. bool bValue = !!flValue;
  245. voice_mixer_mute.SetValue( bValue );
  246. return SetControlOption_Bool(m_ControlInfos[iControl].m_dwControlID, m_ControlInfos[iControl].m_cMultipleItems, bValue);
  247. }
  248. else if(iControl == MicVolume)
  249. {
  250. voice_mixer_volume.SetValue( flValue );
  251. DWORD dwValue = (DWORD)(flValue * 65535.0f);
  252. return SetControlOption_Unsigned(m_ControlInfos[iControl].m_dwControlID, m_ControlInfos[iControl].m_cMultipleItems, dwValue);
  253. }
  254. return false;
  255. }
  256. bool CMixerControls::SelectMicrophoneForWaveInput()
  257. {
  258. if( m_dwMicSelectControlID == 0xFFFFFFFF )
  259. return false;
  260. MIXERCONTROLDETAILS_BOOLEAN *pmxcdSelectValue =
  261. (MIXERCONTROLDETAILS_BOOLEAN*)_alloca( sizeof(MIXERCONTROLDETAILS_BOOLEAN) * m_dwMicSelectMultipleItems );
  262. MIXERCONTROLDETAILS mxcd;
  263. mxcd.cbStruct = sizeof(MIXERCONTROLDETAILS);
  264. mxcd.dwControlID = m_dwMicSelectControlID;
  265. mxcd.cChannels = 1;
  266. mxcd.cMultipleItems = m_dwMicSelectMultipleItems;
  267. mxcd.cbDetails = sizeof(MIXERCONTROLDETAILS_BOOLEAN);
  268. mxcd.paDetails = pmxcdSelectValue;
  269. if (mixerGetControlDetails(reinterpret_cast<HMIXEROBJ>(m_hMixer),
  270. &mxcd,
  271. MIXER_OBJECTF_HMIXER |
  272. MIXER_GETCONTROLDETAILSF_VALUE)
  273. == MMSYSERR_NOERROR)
  274. {
  275. // MUX restricts the line selection to one source line at a time.
  276. if( m_dwMicSelectControlType == MIXERCONTROL_CONTROLTYPE_MUX )
  277. {
  278. ZeroMemory(pmxcdSelectValue,
  279. m_dwMicSelectMultipleItems * sizeof(MIXERCONTROLDETAILS_BOOLEAN));
  280. }
  281. // set the Microphone value
  282. pmxcdSelectValue[m_dwMicSelectIndex].fValue = 1;
  283. mxcd.cbStruct = sizeof(MIXERCONTROLDETAILS);
  284. mxcd.dwControlID = m_dwMicSelectControlID;
  285. mxcd.cChannels = 1;
  286. mxcd.cMultipleItems = m_dwMicSelectMultipleItems;
  287. mxcd.cbDetails = sizeof(MIXERCONTROLDETAILS_BOOLEAN);
  288. mxcd.paDetails = pmxcdSelectValue;
  289. if (mixerSetControlDetails(reinterpret_cast<HMIXEROBJ>(m_hMixer),
  290. &mxcd,
  291. MIXER_OBJECTF_HMIXER |
  292. MIXER_SETCONTROLDETAILSF_VALUE) == MMSYSERR_NOERROR)
  293. {
  294. return true;
  295. }
  296. }
  297. return false;
  298. }
  299. void CMixerControls::Clear()
  300. {
  301. m_hMixer = 0;
  302. memset(m_ControlInfos, 0, sizeof(m_ControlInfos));
  303. }
  304. bool CMixerControls::GetControlOption_Bool(DWORD dwControlID, DWORD cMultipleItems, bool &bValue)
  305. {
  306. MIXERCONTROLDETAILS details;
  307. MIXERCONTROLDETAILS_BOOLEAN controlValue;
  308. details.cbStruct = sizeof(details);
  309. details.dwControlID = dwControlID;
  310. details.cChannels = 1; // uniform..
  311. details.cMultipleItems = cMultipleItems;
  312. details.cbDetails = sizeof(MIXERCONTROLDETAILS_BOOLEAN);
  313. details.paDetails = &controlValue;
  314. MMRESULT mmr = mixerGetControlDetails((HMIXEROBJ)m_hMixer, &details, 0L);
  315. if(mmr == MMSYSERR_NOERROR)
  316. {
  317. bValue = !!controlValue.fValue;
  318. return true;
  319. }
  320. else
  321. {
  322. return false;
  323. }
  324. }
  325. bool CMixerControls::SetControlOption_Bool(DWORD dwControlID, DWORD cMultipleItems, const bool bValue)
  326. {
  327. MIXERCONTROLDETAILS details;
  328. MIXERCONTROLDETAILS_BOOLEAN controlValue;
  329. details.cbStruct = sizeof(details);
  330. details.dwControlID = dwControlID;
  331. details.cChannels = 1; // uniform..
  332. details.cMultipleItems = cMultipleItems;
  333. details.cbDetails = sizeof(MIXERCONTROLDETAILS_BOOLEAN);
  334. details.paDetails = &controlValue;
  335. controlValue.fValue = bValue;
  336. MMRESULT mmr = mixerSetControlDetails((HMIXEROBJ)m_hMixer, &details, 0L);
  337. return mmr == MMSYSERR_NOERROR;
  338. }
  339. bool CMixerControls::GetControlOption_Unsigned(DWORD dwControlID, DWORD cMultipleItems, DWORD &value)
  340. {
  341. MIXERCONTROLDETAILS details;
  342. MIXERCONTROLDETAILS_UNSIGNED controlValue;
  343. details.cbStruct = sizeof(details);
  344. details.dwControlID = dwControlID;
  345. details.cChannels = 1; // uniform..
  346. details.cMultipleItems = cMultipleItems;
  347. details.cbDetails = sizeof(MIXERCONTROLDETAILS_UNSIGNED);
  348. details.paDetails = &controlValue;
  349. MMRESULT mmr = mixerGetControlDetails((HMIXEROBJ)m_hMixer, &details, 0L);
  350. if(mmr == MMSYSERR_NOERROR)
  351. {
  352. value = controlValue.dwValue;
  353. return true;
  354. }
  355. else
  356. {
  357. return false;
  358. }
  359. }
  360. bool CMixerControls::SetControlOption_Unsigned(DWORD dwControlID, DWORD cMultipleItems, const DWORD value)
  361. {
  362. MIXERCONTROLDETAILS details;
  363. MIXERCONTROLDETAILS_UNSIGNED controlValue;
  364. details.cbStruct = sizeof(details);
  365. details.dwControlID = dwControlID;
  366. details.cChannels = 1; // uniform..
  367. details.cMultipleItems = cMultipleItems;
  368. details.cbDetails = sizeof(MIXERCONTROLDETAILS_UNSIGNED);
  369. details.paDetails = &controlValue;
  370. controlValue.dwValue = value;
  371. MMRESULT mmr = mixerSetControlDetails((HMIXEROBJ)m_hMixer, &details, 0L);
  372. return mmr == MMSYSERR_NOERROR;
  373. }
  374. bool CMixerControls::GetLineControls( DWORD dwLineID, MIXERCONTROL *controls, DWORD nControls )
  375. {
  376. MIXERLINECONTROLS mxlc;
  377. mxlc.cbStruct = sizeof(mxlc);
  378. mxlc.dwLineID = dwLineID;
  379. mxlc.cControls = nControls;
  380. mxlc.cbmxctrl = sizeof(MIXERCONTROL);
  381. mxlc.pamxctrl = controls;
  382. MMRESULT mmr = mixerGetLineControls((HMIXEROBJ)m_hMixer, &mxlc, MIXER_GETLINECONTROLSF_ALL);
  383. return mmr == MMSYSERR_NOERROR;
  384. }
  385. void CMixerControls::FindMicSelectControl( DWORD dwLineID, DWORD nControls )
  386. {
  387. m_dwMicSelectControlID = 0xFFFFFFFF;
  388. MIXERCONTROL *recControls = (MIXERCONTROL*)_alloca( sizeof(MIXERCONTROL) * nControls );
  389. if( !GetLineControls( dwLineID, recControls, nControls ) )
  390. return;
  391. for( UINT iRecControl=0; iRecControl < nControls; iRecControl++ )
  392. {
  393. if( recControls[iRecControl].dwControlType == MIXERCONTROL_CONTROLTYPE_MIXER ||
  394. recControls[iRecControl].dwControlType == MIXERCONTROL_CONTROLTYPE_MUX )
  395. {
  396. m_dwMicSelectControlID = recControls[iRecControl].dwControlID;
  397. m_dwMicSelectControlType = recControls[iRecControl].dwControlType;
  398. m_dwMicSelectMultipleItems = recControls[iRecControl].cMultipleItems;
  399. m_dwMicSelectIndex = iRecControl;
  400. // Get the index of the one that selects the mic.
  401. MIXERCONTROLDETAILS_LISTTEXT *pmxcdSelectText =
  402. (MIXERCONTROLDETAILS_LISTTEXT*)_alloca( sizeof(MIXERCONTROLDETAILS_LISTTEXT) * m_dwMicSelectMultipleItems );
  403. MIXERCONTROLDETAILS mxcd;
  404. mxcd.cbStruct = sizeof(MIXERCONTROLDETAILS);
  405. mxcd.dwControlID = m_dwMicSelectControlID;
  406. mxcd.cChannels = 1;
  407. mxcd.cMultipleItems = m_dwMicSelectMultipleItems;
  408. mxcd.cbDetails = sizeof(MIXERCONTROLDETAILS_LISTTEXT);
  409. mxcd.paDetails = pmxcdSelectText;
  410. if (mixerGetControlDetails((HMIXEROBJ)m_hMixer,
  411. &mxcd,
  412. MIXER_OBJECTF_HMIXER |
  413. MIXER_GETCONTROLDETAILSF_LISTTEXT) == MMSYSERR_NOERROR)
  414. {
  415. // determine which controls the Microphone source line
  416. for (DWORD dwi = 0; dwi < m_dwMicSelectMultipleItems; dwi++)
  417. {
  418. // get the line information
  419. MIXERLINE mxl;
  420. mxl.cbStruct = sizeof(MIXERLINE);
  421. mxl.dwLineID = pmxcdSelectText[dwi].dwParam1;
  422. if (mixerGetLineInfo((HMIXEROBJ)m_hMixer,
  423. &mxl,
  424. MIXER_OBJECTF_HMIXER |
  425. MIXER_GETLINEINFOF_LINEID) == MMSYSERR_NOERROR &&
  426. mxl.dwComponentType == MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE)
  427. {
  428. // found, dwi is the index.
  429. m_dwMicSelectIndex = dwi;
  430. break;
  431. }
  432. }
  433. }
  434. break;
  435. }
  436. }
  437. }
  438. IMixerControls* g_pMixerControls = NULL;
  439. void InitMixerControls()
  440. {
  441. if ( !g_pMixerControls )
  442. {
  443. g_pMixerControls = new CMixerControls;
  444. }
  445. }
  446. void ShutdownMixerControls()
  447. {
  448. delete g_pMixerControls;
  449. g_pMixerControls = NULL;
  450. }
  451. #endif