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.

507 lines
11 KiB

  1. // File: audioctl.cpp
  2. #include "precomp.h"
  3. #include "resource.h"
  4. #include "audioctl.h"
  5. #include "mixer.h"
  6. #include "confpolicies.h"
  7. CAudioControl::CAudioControl(HWND hwnd) :
  8. m_pRecMixer(NULL),
  9. m_pSpkMixer(NULL),
  10. m_fMicMuted(FALSE),
  11. m_fSpkMuted(FALSE),
  12. m_pChannelMic(NULL),
  13. m_pChannelSpk(NULL),
  14. m_pAudioEvent(NULL),
  15. m_dwRecordDevice(0),
  16. m_dwPlaybackDevice(0),
  17. m_dwSilenceLevel(DEFAULT_MICROPHONE_SENSITIVITY * 10),
  18. m_hwndParent(hwnd)
  19. {
  20. m_dwMicVolume.leftVolume = 0xFFFFFFFF,
  21. m_dwMicVolume.rightVolume = 0xFFFFFFFF;
  22. m_dwSpkVolume.leftVolume = 0xFFFFFFFF;
  23. m_dwSpkVolume.rightVolume = 0xFFFFFFFF;
  24. m_dwSpkVolumeOld.leftVolume = 0xFFFFFFFF;
  25. m_dwSpkVolumeOld.rightVolume = 0xFFFFFFFF;
  26. LoadSettings();
  27. OnDeviceChanged();
  28. OnAGC_Changed();
  29. OnSilenceLevelChanged();
  30. }
  31. CAudioControl::~CAudioControl()
  32. {
  33. SaveSettings();
  34. // restore speaker volume
  35. if (m_pSpkMixer && (m_dwSpkVolumeOld.leftVolume <= 0x0000ffff || m_dwSpkVolumeOld.rightVolume <= 0x0000ffff))
  36. {
  37. m_pSpkMixer->SetVolume(&m_dwSpkVolumeOld);
  38. }
  39. delete m_pRecMixer;
  40. delete m_pSpkMixer;
  41. if (NULL != m_pChannelMic)
  42. {
  43. m_pChannelMic->Release();
  44. }
  45. if (NULL != m_pChannelSpk)
  46. {
  47. m_pChannelSpk->Release();
  48. }
  49. }
  50. /****************************************************************************
  51. *
  52. * CLASS: CAudioControl
  53. *
  54. * MEMBER: OnChannelChanged()
  55. *
  56. * PURPOSE: Tracks audio channel changes
  57. *
  58. ****************************************************************************/
  59. void CAudioControl::OnChannelChanged(NM_CHANNEL_NOTIFY uNotify, INmChannel *pChannel)
  60. {
  61. INmChannelAudio* pChannelAudio;
  62. if (SUCCEEDED(pChannel->QueryInterface(IID_INmChannelAudio, (void**)&pChannelAudio)))
  63. {
  64. if (S_OK == pChannelAudio->IsActive())
  65. {
  66. if (S_OK == pChannelAudio->IsIncoming())
  67. {
  68. if (NULL == m_pChannelSpk)
  69. {
  70. m_pChannelSpk = pChannelAudio;
  71. m_pChannelSpk->AddRef();
  72. m_pChannelSpk->SetProperty(NM_AUDPROP_PAUSE, m_fSpkMuted);
  73. m_pChannelSpk->SetProperty(NM_AUDPROP_WAVE_DEVICE, m_dwPlaybackDevice);
  74. }
  75. }
  76. else
  77. {
  78. if (NULL == m_pChannelMic)
  79. {
  80. m_pChannelMic = pChannelAudio;
  81. m_pChannelMic->AddRef();
  82. m_pChannelMic->SetProperty(NM_AUDPROP_PAUSE, m_fMicMuted);
  83. m_pChannelMic->SetProperty(NM_AUDPROP_LEVEL, m_dwSilenceLevel);
  84. m_pChannelMic->SetProperty(NM_AUDPROP_WAVE_DEVICE, m_dwRecordDevice);
  85. m_pChannelMic->SetProperty(NM_AUDPROP_AUTOMIX, m_fAutoMix);
  86. }
  87. }
  88. }
  89. else
  90. {
  91. if (S_OK == pChannelAudio->IsIncoming())
  92. {
  93. // were done with the speaker channel
  94. if (pChannelAudio == m_pChannelSpk)
  95. {
  96. m_pChannelSpk->Release();
  97. m_pChannelSpk = NULL;
  98. }
  99. }
  100. else
  101. {
  102. // were done with the speaker channel
  103. if (pChannelAudio == m_pChannelMic)
  104. {
  105. m_pChannelMic->Release();
  106. m_pChannelMic = NULL;
  107. }
  108. }
  109. }
  110. pChannelAudio->Release();
  111. }
  112. }
  113. /****************************************************************************
  114. *
  115. * CLASS: CAudioControl
  116. *
  117. * MEMBER: RefreshMixer()
  118. *
  119. * PURPOSE: Refreshes all controls that are mixer dependent
  120. *
  121. ****************************************************************************/
  122. void CAudioControl::RefreshMixer()
  123. {
  124. if (NULL != m_pSpkMixer)
  125. {
  126. MIXVOLUME dwVol;
  127. BOOL fValid;
  128. fValid = m_pSpkMixer->GetVolume(&dwVol);
  129. if (fValid && (dwVol.leftVolume != m_dwSpkVolume.leftVolume || dwVol.rightVolume != m_dwSpkVolume.rightVolume))
  130. {
  131. m_dwSpkVolume.leftVolume = dwVol.leftVolume;
  132. m_dwSpkVolume.rightVolume = dwVol.rightVolume;
  133. if (NULL != m_pAudioEvent)
  134. {
  135. m_pAudioEvent->OnLevelChange(TRUE /* fSpeaker */, max(m_dwSpkVolume.leftVolume , m_dwSpkVolume.rightVolume));
  136. }
  137. }
  138. }
  139. if (NULL != m_pRecMixer)
  140. {
  141. BOOL fChanged = FALSE;
  142. MIXVOLUME dwMainVol = {0,0};
  143. BOOL fValidMain = m_pRecMixer->GetMainVolume(&dwMainVol);
  144. MIXVOLUME dwMicVol = {0,0};
  145. BOOL fValidMic = m_pRecMixer->GetSubVolume(&dwMicVol);
  146. if (fValidMain && (m_dwMicVolume.leftVolume != dwMainVol.leftVolume || m_dwMicVolume.rightVolume != dwMainVol.rightVolume))
  147. {
  148. m_dwMicVolume.leftVolume = dwMainVol.leftVolume;
  149. m_dwMicVolume.rightVolume = dwMainVol.rightVolume;
  150. // Force the mic vol to equal the main vol
  151. SetRecorderVolume(&dwMainVol);
  152. fChanged = TRUE;
  153. }
  154. else if (fValidMic && (m_dwMicVolume.leftVolume != dwMicVol.leftVolume || m_dwMicVolume.rightVolume != dwMicVol.rightVolume))
  155. {
  156. m_dwMicVolume.leftVolume = dwMicVol.leftVolume;
  157. m_dwMicVolume.rightVolume = dwMicVol.rightVolume;
  158. // Force the main vol to equal the mic vol
  159. SetRecorderVolume(&dwMicVol);
  160. fChanged = TRUE;
  161. }
  162. if (fChanged)
  163. {
  164. if (NULL != m_pAudioEvent)
  165. {
  166. m_pAudioEvent->OnLevelChange(FALSE /* fSpeaker */, max(m_dwMicVolume.leftVolume , m_dwMicVolume.rightVolume));
  167. }
  168. }
  169. }
  170. }
  171. /****************************************************************************
  172. *
  173. * CLASS: CAudioControl
  174. *
  175. * MEMBER: MuteAudio(BOOL fSpeaker, BOOL fMute)
  176. *
  177. * PURPOSE: Internal routine to mute an audio device
  178. *
  179. ****************************************************************************/
  180. VOID CAudioControl::MuteAudio(BOOL fSpeaker, BOOL fMute)
  181. {
  182. INmChannelAudio *pChannel;
  183. if (fSpeaker)
  184. {
  185. m_fSpkMuted = fMute;
  186. pChannel = m_pChannelSpk;
  187. }
  188. else
  189. {
  190. m_fMicMuted = fMute;
  191. pChannel = m_pChannelMic;
  192. }
  193. if (NULL != pChannel)
  194. {
  195. pChannel->SetProperty(NM_AUDPROP_PAUSE, fMute);
  196. }
  197. if (NULL != m_pAudioEvent)
  198. {
  199. m_pAudioEvent->OnMuteChange(fSpeaker, fMute);
  200. }
  201. }
  202. /****************************************************************************
  203. *
  204. * CLASS: CAudioControl
  205. *
  206. * MEMBER: GetAudioSignalLevel(BOOL fSpeaker)
  207. *
  208. * PURPOSE: Internal routine to get the audio signal level
  209. *
  210. ****************************************************************************/
  211. DWORD CAudioControl::GetAudioSignalLevel(BOOL fSpeaker)
  212. {
  213. DWORD_PTR dwLevel = 0;
  214. INmChannelAudio *pChannel = fSpeaker ? m_pChannelSpk : m_pChannelMic;
  215. if (NULL != pChannel)
  216. {
  217. pChannel->GetProperty(NM_AUDPROP_LEVEL, &dwLevel);
  218. }
  219. return (DWORD)dwLevel;
  220. }
  221. BOOL CAudioControl::CanSetRecorderVolume()
  222. {
  223. if (NULL != m_pRecMixer)
  224. {
  225. return m_pRecMixer->CanSetVolume();
  226. }
  227. return FALSE;
  228. }
  229. BOOL CAudioControl::CanSetSpeakerVolume()
  230. {
  231. if (NULL != m_pSpkMixer)
  232. {
  233. return m_pSpkMixer->CanSetVolume();
  234. }
  235. return FALSE;
  236. }
  237. void CAudioControl::SetRecorderVolume(MIXVOLUME * pdwVolume)
  238. {
  239. if (NULL != m_pRecMixer)
  240. {
  241. m_pRecMixer->SetVolume(pdwVolume);
  242. }
  243. }
  244. void CAudioControl::SetSpeakerVolume(MIXVOLUME * pdwVolume)
  245. {
  246. if (NULL != m_pSpkMixer)
  247. {
  248. m_pSpkMixer->SetVolume(pdwVolume);
  249. }
  250. }
  251. void CAudioControl::GetRecorderVolume(MIXVOLUME * pdwVolume)
  252. {
  253. if (NULL != m_pRecMixer)
  254. {
  255. m_pRecMixer->GetVolume(pdwVolume);
  256. }
  257. }
  258. void CAudioControl::GetSpeakerVolume(MIXVOLUME * pdwVolume)
  259. {
  260. if (NULL != m_pSpkMixer)
  261. {
  262. m_pSpkMixer->GetVolume(pdwVolume);
  263. }
  264. }
  265. void CAudioControl::SetRecorderVolume(DWORD dwVolume)
  266. {
  267. MIXVOLUME mixVol;
  268. MIXVOLUME mixNewVol;
  269. GetRecorderVolume(&mixVol);
  270. NewMixVolume(&mixNewVol, mixVol, dwVolume);
  271. SetRecorderVolume(&mixNewVol);
  272. }
  273. void CAudioControl::SetSpeakerVolume(DWORD dwVolume)
  274. {
  275. MIXVOLUME mixVol;
  276. MIXVOLUME mixNewVol;
  277. GetSpeakerVolume(&mixVol);
  278. NewMixVolume(&mixNewVol, mixVol, dwVolume);
  279. SetSpeakerVolume(&mixNewVol);
  280. }
  281. void CAudioControl::OnDeviceChanged()
  282. {
  283. MIXVOLUME dwMicVolume;
  284. DWORD dwNewPlaybackDevice;
  285. RegEntry re( AUDIO_KEY, HKEY_CURRENT_USER );
  286. dwNewPlaybackDevice = re.GetNumber(REGVAL_WAVEOUTDEVICEID, 0);
  287. // restore the speaker setting before changing to the new device
  288. // verify that we aren't changing to the same device
  289. if (m_pSpkMixer && (m_dwSpkVolumeOld.leftVolume <= 0x0000ffff || m_dwSpkVolumeOld.rightVolume <= 0x0000ffff) &&
  290. (m_dwPlaybackDevice != dwNewPlaybackDevice) )
  291. {
  292. m_pSpkMixer->SetVolume(&m_dwSpkVolumeOld);
  293. }
  294. // Initialize the proper record/playback devices:
  295. delete m_pRecMixer;
  296. m_dwRecordDevice = re.GetNumber(REGVAL_WAVEINDEVICEID, 0);
  297. m_pRecMixer = CMixerDevice::GetMixerForWaveDevice(
  298. m_hwndParent,
  299. m_dwRecordDevice,
  300. MIXER_OBJECTF_WAVEIN);
  301. delete m_pSpkMixer;
  302. m_dwPlaybackDevice = dwNewPlaybackDevice;
  303. m_pSpkMixer = CMixerDevice::GetMixerForWaveDevice(
  304. m_hwndParent,
  305. m_dwPlaybackDevice,
  306. MIXER_OBJECTF_WAVEOUT);
  307. if (NULL != m_pChannelMic)
  308. {
  309. m_pChannelMic->SetProperty(NM_AUDPROP_WAVE_DEVICE, m_dwRecordDevice);
  310. }
  311. if (NULL != m_pChannelSpk)
  312. {
  313. m_pChannelSpk->SetProperty(NM_AUDPROP_WAVE_DEVICE, m_dwPlaybackDevice);
  314. }
  315. // restore the microphone setting from whatever it was in the tuning wizard
  316. if (m_pRecMixer)
  317. {
  318. dwMicVolume.leftVolume = dwMicVolume.rightVolume = re.GetNumber(REGVAL_CALIBRATEDVOL, 0x00ff);
  319. m_pRecMixer->SetVolume(&dwMicVolume);
  320. }
  321. // remember the old speaker volume
  322. if (m_pSpkMixer)
  323. {
  324. m_pSpkMixer->GetVolume(&m_dwSpkVolumeOld);
  325. }
  326. RefreshMixer();
  327. }
  328. void CAudioControl::OnAGC_Changed()
  329. {
  330. RegEntry reAudio( AUDIO_KEY, HKEY_CURRENT_USER );
  331. BOOL fAgc = ( reAudio.GetNumber(REGVAL_AUTOGAIN,AUTOGAIN_ENABLED) == AUTOGAIN_ENABLED );
  332. m_fAutoMix = (reAudio.GetNumber(REGVAL_AUTOMIX, AUTOMIX_ENABLED) == AUTOMIX_ENABLED);
  333. if (NULL != m_pRecMixer)
  334. {
  335. m_pRecMixer->SetAGC(fAgc);
  336. }
  337. if (NULL != m_pChannelMic)
  338. {
  339. m_pChannelMic->SetProperty(NM_AUDPROP_AUTOMIX, m_fAutoMix);
  340. }
  341. }
  342. void CAudioControl::OnSilenceLevelChanged()
  343. {
  344. RegEntry reAudio( AUDIO_KEY, HKEY_CURRENT_USER );
  345. if (MICROPHONE_AUTO_NO == reAudio.GetNumber(REGVAL_MICROPHONE_AUTO,
  346. MICROPHONE_AUTO_YES))
  347. {
  348. // Use "manual" mode:
  349. // BUGBUG - there is a mismatch in terminology between
  350. // "sensitivity" and "threshhold", which reverses the
  351. // sense of this value. A low threshhold implies a high
  352. // sensitivity, etc.
  353. // Reverse the sense of this value before setting the
  354. // Nac value, and resolve the terminology problem later.
  355. // PROP_SILENCE_LEVEL property is in units of 0.1%, so scale it.
  356. m_dwSilenceLevel = (MAX_MICROPHONE_SENSITIVITY -
  357. reAudio.GetNumber(REGVAL_MICROPHONE_SENSITIVITY,
  358. DEFAULT_MICROPHONE_SENSITIVITY))*10;
  359. }
  360. else
  361. {
  362. // Use "automatic" mode: This is actually controlled by
  363. // PROP_SILENCE_LEVEL. If at maximum (100%), then it is
  364. // in "automatic" mode
  365. m_dwSilenceLevel = 100*10; // remember units are 0.1%
  366. }
  367. if (NULL != m_pChannelMic)
  368. {
  369. m_pChannelMic->SetProperty(NM_AUDPROP_LEVEL, m_dwSilenceLevel);
  370. }
  371. }
  372. BOOL CAudioControl::LoadSettings()
  373. {
  374. RegEntry reAudio( AUDIO_KEY, HKEY_CURRENT_USER );
  375. m_fSpkMuted = reAudio.GetNumber(REGVAL_SPKMUTE, FALSE);
  376. m_fMicMuted = reAudio.GetNumber(REGVAL_RECMUTE, FALSE);
  377. return TRUE;
  378. }
  379. BOOL CAudioControl::SaveSettings()
  380. {
  381. RegEntry reAudio( AUDIO_KEY, HKEY_CURRENT_USER );
  382. reAudio.SetValue(REGVAL_SPKMUTE, m_fSpkMuted);
  383. reAudio.SetValue(REGVAL_RECMUTE, m_fMicMuted);
  384. //
  385. // Check if the microphone got changed during this section
  386. //
  387. if(m_pRecMixer)
  388. {
  389. MIXVOLUME dwMicVol = {0,0};
  390. m_pRecMixer->GetVolume(&dwMicVol);
  391. DWORD oldVolume = reAudio.GetNumber(REGVAL_CALIBRATEDVOL, 0x00ff);
  392. DWORD newVolume = max(dwMicVol.leftVolume,dwMicVol.rightVolume);
  393. if(oldVolume != newVolume)
  394. {
  395. reAudio.SetValue(REGVAL_CALIBRATEDVOL, newVolume);
  396. }
  397. }
  398. return TRUE;
  399. }
  400. HRESULT CAudioControl::SetProperty(BOOL fSpeaker, NM_AUDPROP uID, ULONG_PTR uValue)
  401. {
  402. INmChannelAudio *pChannel = fSpeaker ? m_pChannelSpk : m_pChannelMic;
  403. if (NULL != pChannel)
  404. {
  405. return(pChannel->SetProperty(uID, uValue));
  406. }
  407. return(E_UNEXPECTED);
  408. }
  409. HRESULT CAudioControl::GetProperty(BOOL fSpeaker, NM_AUDPROP uID, ULONG_PTR *puValue)
  410. {
  411. INmChannelAudio *pChannel = fSpeaker ? m_pChannelSpk : m_pChannelMic;
  412. if (NULL != pChannel)
  413. {
  414. return(pChannel->GetProperty(uID, puValue));
  415. }
  416. return(E_UNEXPECTED);
  417. }