Leaked source code of windows server 2003
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.

754 lines
21 KiB

  1. #include "precomp.h"
  2. #include <mixer.h>
  3. //
  4. // private APIs
  5. //
  6. #define MAX_MICROPHONE_DEVS 10
  7. static MMRESULT mixerGetControlValue ( HMIXER, DWORD *, DWORD, UINT );
  8. static MMRESULT mixerSetControlValue ( HMIXER, DWORD *, DWORD, UINT );
  9. static MMRESULT mixerGetControlId ( HMIXER, DWORD *, DWORD, DWORD );
  10. static MMRESULT mixerGetControlByType ( HMIXER, DWORD, DWORD, MIXERCONTROL *pMixerControl);
  11. struct AGCDetails
  12. {
  13. WORD wMID; // manufacturer ID
  14. WORD wPID; // product ID
  15. DWORD dwAGCID; // AGC ID
  16. };
  17. static const AGCDetails AGCList[] =
  18. {
  19. // MID PID AGCID
  20. {1, 323, 27}, // Creative Labs (NT)
  21. {1, 104, 21}, // Creative Labs (NT 5)
  22. {2, 409, 27}, // Creative Labs
  23. {21, 42, 13}, // Turtle Beach Tropez
  24. {132, 3, 2072}, // Crystal MMX
  25. {384, 7, 28}, // Xitel Storm 3d PCI
  26. {385, 32, 35} // Aztech PCI-331
  27. };
  28. static BOOL GetAGCID(WORD wMID, WORD wPID, DWORD *pdwAGCID)
  29. {
  30. int nIndex;
  31. int nAGCEntries = sizeof(AGCList) / sizeof(AGCDetails);
  32. for (nIndex = 0; nIndex < nAGCEntries; nIndex++)
  33. {
  34. if ( (AGCList[nIndex].wMID == wMID) &&
  35. (AGCList[nIndex].wPID == wPID))
  36. {
  37. *pdwAGCID = AGCList[nIndex].dwAGCID;
  38. return TRUE;
  39. }
  40. }
  41. return FALSE;
  42. }
  43. //
  44. // Init
  45. //
  46. // Enumerate all existing mixers in the system. For each mixer,
  47. // we enumerate all lines with destination Speaker and WaveIn.
  48. // For each such line, we cache the control id and control value
  49. // of volume control. An invalid flag will be tagged to any control
  50. // not supported by this mixer.
  51. // When an application is finished with all mixers operations,
  52. // it must call ReleaseAllMixers to free all memory resources and
  53. // mixers.
  54. //
  55. // THIS MUST BE THE FIRST API TO CALL TO START MIXER OPERATIONS.
  56. //
  57. // Input: The handle of the window which will handle all callback
  58. // messages MM_MIXM_CONTROL_CHANGE and MM_MIXM_LINE_CHANGE.
  59. //
  60. // Output: TRUE if success; otherwise, FALSE.
  61. //
  62. BOOL CMixerDevice::Init( HWND hWnd, UINT_PTR uWaveDevId, DWORD dwFlags)
  63. {
  64. UINT uDstIdx, uSrcIdx, uMixerIdCheck, uMixerIdx;
  65. MMRESULT mmr = MMSYSERR_NOERROR;
  66. MIXERLINE mlDst, mlSrc;
  67. UINT_PTR nMixers, nWaveInDevs, uIndex;
  68. //get the mixer device corresponding to the wave device
  69. mmr = mixerGetID((HMIXEROBJ)uWaveDevId, &uMixerIdx, dwFlags);
  70. if ((mmr != MMSYSERR_NOERROR) && (mmr != MMSYSERR_NODRIVER)) {
  71. return FALSE;
  72. }
  73. // a simple fix for cheesy sound cards that don't make a
  74. // direct mapping between waveDevice and mixer device
  75. // e.g. MWAVE cards and newer SB NT 4 drivers
  76. // If there is only ONE mixer device and if no other waveIn device
  77. // uses it, then it is probably valid.
  78. if ((mmr == MMSYSERR_NODRIVER) && (dwFlags == MIXER_OBJECTF_WAVEIN))
  79. {
  80. nMixers = mixerGetNumDevs();
  81. nWaveInDevs = waveInGetNumDevs();
  82. if (nMixers == 1)
  83. {
  84. uMixerIdx = 0;
  85. for (uIndex = 0; uIndex < nWaveInDevs; uIndex++)
  86. {
  87. mmr = mixerGetID((HMIXEROBJ)uIndex, &uMixerIdCheck, dwFlags);
  88. if ((mmr == MMSYSERR_NOERROR) && (uMixerIdCheck == uMixerIdx))
  89. {
  90. return FALSE; // the mixer belongs to another waveIn Device
  91. }
  92. }
  93. }
  94. else
  95. {
  96. return FALSE;
  97. }
  98. }
  99. // open the mixer such that we can get notification messages
  100. mmr = mixerOpen (
  101. &m_hMixer,
  102. uMixerIdx,
  103. (DWORD_PTR) hWnd,
  104. 0,
  105. (hWnd ? CALLBACK_WINDOW : 0) | MIXER_OBJECTF_MIXER);
  106. if (mmr != MMSYSERR_NOERROR) {
  107. return FALSE;
  108. }
  109. // get mixer caps
  110. mmr = mixerGetDevCaps (uMixerIdx, &(m_mixerCaps), sizeof (MIXERCAPS));
  111. if ((mmr != MMSYSERR_NOERROR) || (0 == m_mixerCaps.cDestinations)) {
  112. mixerClose(m_hMixer);
  113. return FALSE;
  114. }
  115. for (uDstIdx = 0; uDstIdx < m_mixerCaps.cDestinations; uDstIdx++)
  116. {
  117. ZeroMemory (&mlDst, sizeof (mlDst));
  118. mlDst.cbStruct = sizeof (mlDst);
  119. mlDst.dwDestination = uDstIdx;
  120. // get the mixer line for this destination
  121. mmr = mixerGetLineInfo ((HMIXEROBJ)m_hMixer, &mlDst,
  122. MIXER_GETLINEINFOF_DESTINATION | MIXER_OBJECTF_HMIXER);
  123. if (mmr != MMSYSERR_NOERROR) continue;
  124. // examine the type of this destination line
  125. if (((MIXER_OBJECTF_WAVEOUT == dwFlags) &&
  126. (MIXERLINE_COMPONENTTYPE_DST_SPEAKERS == mlDst.dwComponentType)) ||
  127. ((MIXER_OBJECTF_WAVEIN == dwFlags) &&
  128. (MIXERLINE_COMPONENTTYPE_DST_WAVEIN == mlDst.dwComponentType)))
  129. {
  130. // fill in more info about DstLine
  131. m_DstLine.ucChannels = mlDst.cChannels;
  132. if (!(mlDst.fdwLine & MIXERLINE_LINEF_DISCONNECTED))
  133. {
  134. // get id and value of volume control
  135. mmr = mixerGetControlId (
  136. m_hMixer,
  137. &m_DstLine.dwControlId,
  138. mlDst.dwLineID,
  139. MIXERCONTROL_CONTROLTYPE_VOLUME);
  140. m_DstLine.fIdValid = (mmr == MMSYSERR_NOERROR);
  141. m_DstLine.dwLineId = mlDst.dwLineID;
  142. m_DstLine.dwCompType = mlDst.dwComponentType;
  143. m_DstLine.dwConnections = mlDst.cConnections;
  144. // -----------------------------------------------------
  145. // enumerate all sources for this destination
  146. for (uSrcIdx = 0; uSrcIdx < mlDst.cConnections; uSrcIdx++)
  147. {
  148. // get the info of the line with specific src and dst...
  149. ZeroMemory (&mlSrc, sizeof (mlSrc));
  150. mlSrc.cbStruct = sizeof (mlSrc);
  151. mlSrc.dwDestination = uDstIdx;
  152. mlSrc.dwSource = uSrcIdx;
  153. mmr = mixerGetLineInfo (
  154. (HMIXEROBJ)m_hMixer,
  155. &mlSrc,
  156. MIXER_GETLINEINFOF_SOURCE | MIXER_OBJECTF_HMIXER);
  157. if (mmr == MMSYSERR_NOERROR)
  158. {
  159. if (((MIXERLINE_COMPONENTTYPE_DST_SPEAKERS == mlDst.dwComponentType) &&
  160. (MIXERLINE_COMPONENTTYPE_SRC_WAVEOUT == mlSrc.dwComponentType)) ||
  161. ((MIXERLINE_COMPONENTTYPE_DST_WAVEIN == mlDst.dwComponentType) &&
  162. (MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE == mlSrc.dwComponentType)))
  163. {
  164. // fill in more info about this source
  165. m_SrcLine.ucChannels = mlSrc.cChannels;
  166. // get id and value of volume control
  167. mmr = mixerGetControlId (
  168. m_hMixer,
  169. &m_SrcLine.dwControlId,
  170. mlSrc.dwLineID,
  171. MIXERCONTROL_CONTROLTYPE_VOLUME);
  172. m_SrcLine.fIdValid = (mmr == MMSYSERR_NOERROR);
  173. m_SrcLine.dwLineId = mlSrc.dwLineID;
  174. m_SrcLine.dwCompType = mlSrc.dwComponentType;
  175. m_SrcLine.dwConnections = mlSrc.cConnections;
  176. break;
  177. }
  178. }
  179. }
  180. }
  181. break;
  182. }
  183. }
  184. return TRUE;
  185. }
  186. CMixerDevice* CMixerDevice::GetMixerForWaveDevice( HWND hWnd, UINT uWaveDevId, DWORD dwFlags)
  187. {
  188. DBG_SAVE_FILE_LINE
  189. CMixerDevice* pMixerDev = new CMixerDevice;
  190. if (NULL != pMixerDev)
  191. {
  192. if (!pMixerDev->Init(hWnd, uWaveDevId, dwFlags))
  193. {
  194. delete pMixerDev;
  195. pMixerDev = NULL;
  196. }
  197. }
  198. return pMixerDev;
  199. }
  200. BOOL CMixerDevice::SetMainVolume(DWORD dwVolume)
  201. {
  202. MMRESULT mmr = MMSYSERR_ERROR;
  203. DWORD adwVolume[2];
  204. adwVolume[0] = adwVolume[1] = (DWORD) LOWORD (dwVolume);
  205. if (m_DstLine.fIdValid) {
  206. mmr = mixerSetControlValue (
  207. m_hMixer,
  208. adwVolume,
  209. m_DstLine.dwControlId,
  210. 2);
  211. }
  212. return (mmr == MMSYSERR_NOERROR);
  213. }
  214. BOOL CMixerDevice::SetSubVolume(DWORD dwVolume)
  215. {
  216. MMRESULT mmr = MMSYSERR_ERROR;
  217. DWORD adwVolume[2];
  218. adwVolume[0] = adwVolume[1] = (DWORD) LOWORD (dwVolume);
  219. if (m_SrcLine.fIdValid)
  220. {
  221. mmr = mixerSetControlValue (
  222. m_hMixer,
  223. adwVolume,
  224. m_SrcLine.dwControlId,
  225. m_SrcLine.ucChannels);
  226. }
  227. return (mmr == MMSYSERR_NOERROR);
  228. }
  229. //
  230. // Gets the volume (0 - 65535) of the master volume
  231. // returns TRUE if succesful,
  232. // returns FALSE if it fails or if this control is not available
  233. //
  234. BOOL CMixerDevice::GetMainVolume(LPDWORD pdwVolume)
  235. {
  236. BOOL fRet = FALSE;
  237. if (m_DstLine.fIdValid)
  238. {
  239. DWORD adwVolume[2];
  240. MMRESULT mmr = ::mixerGetControlValue(
  241. m_hMixer,
  242. adwVolume,
  243. m_DstLine.dwControlId,
  244. 2);
  245. fRet = (mmr == MMSYSERR_NOERROR);
  246. if (fRet)
  247. {
  248. // BUGBUG: is this the left channel only?
  249. *pdwVolume = LOWORD(adwVolume[0]);
  250. }
  251. }
  252. return fRet;
  253. }
  254. //
  255. // Gets the volume (0 - 65535) of the sub volume
  256. // returns TRUE if succesful,
  257. // returns FALSE if it fails or if this control is not available
  258. //
  259. BOOL CMixerDevice::GetSubVolume(LPDWORD pdwVolume)
  260. {
  261. BOOL fRet = FALSE;
  262. if (m_SrcLine.fIdValid)
  263. {
  264. DWORD adwVolume[2];
  265. MMRESULT mmr = ::mixerGetControlValue(
  266. m_hMixer,
  267. adwVolume,
  268. m_SrcLine.dwControlId,
  269. m_SrcLine.ucChannels);
  270. fRet = (mmr == MMSYSERR_NOERROR);
  271. if (fRet)
  272. {
  273. // BUGBUG: is this the left channel only?
  274. *pdwVolume = LOWORD(adwVolume[0]);
  275. }
  276. }
  277. return fRet;
  278. }
  279. // Return the value of the Auto Gain Control on SB16/AWE32 cards
  280. // Returns FALSE if the control is not supported.
  281. // pfOn is OUTPUT, OPTIONAL - value of AGC
  282. BOOL CMixerDevice::GetAGC(BOOL *pfOn)
  283. {
  284. MMRESULT mmr;
  285. DWORD dwAGCId;
  286. DWORD dwValue;
  287. if (FALSE == GetAGCID(m_mixerCaps.wMid, m_mixerCaps.wPid, &dwAGCId))
  288. return FALSE;
  289. mmr = mixerGetControlValue(m_hMixer, &dwValue, dwAGCId, 1);
  290. if (mmr != MMSYSERR_NOERROR)
  291. return FALSE;
  292. if (pfOn)
  293. *pfOn = dwValue;
  294. return TRUE;
  295. }
  296. /*
  297. Hack API to turn MIC Auto Gain Control on or off.
  298. Its a hack because it only works on SB16/AWE32 cards.
  299. */
  300. BOOL CMixerDevice::SetAGC(BOOL fOn)
  301. {
  302. DWORD dwAGCId;
  303. DWORD dwValue;
  304. MMRESULT mmr;
  305. if (FALSE == GetAGCID(m_mixerCaps.wMid, m_mixerCaps.wPid, &dwAGCId))
  306. return FALSE;
  307. mmr = mixerGetControlValue(m_hMixer, &dwValue, dwAGCId, 1);
  308. if (mmr != MMSYSERR_NOERROR)
  309. return FALSE;
  310. if (dwValue == (DWORD)fOn)
  311. return TRUE;
  312. dwValue = fOn;
  313. mmr = mixerSetControlValue(m_hMixer, &dwValue, dwAGCId, 1);
  314. return (mmr == MMSYSERR_NOERROR);
  315. }
  316. BOOL CMixerDevice::EnableMicrophone()
  317. {
  318. MIXERLINE mixerLine;
  319. MIXERCONTROL mixerControl;
  320. MIXERCONTROLDETAILS mixerControlDetails, mixerControlDetailsOrig;
  321. UINT uIndex, numItems, numMics, numMicsSet, fMicFound;
  322. UINT uMicIndex = 0;
  323. UINT aMicIndices[MAX_MICROPHONE_DEVS];
  324. MIXERCONTROLDETAILS_LISTTEXT *aListText = NULL;
  325. MIXERCONTROLDETAILS_BOOLEAN *aEnableList = NULL;
  326. MMRESULT mmr;
  327. // check to see if component type is valid (which means the line exists!)
  328. // even if the volume control doesn't exist or isn't slidable,
  329. // there may still be a select switch
  330. if ((m_SrcLine.dwCompType != MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE) ||
  331. (m_DstLine.dwCompType != MIXERLINE_COMPONENTTYPE_DST_WAVEIN))
  332. {
  333. return FALSE;
  334. }
  335. // try to find the mixer list
  336. if ( (MMSYSERR_NOERROR != mixerGetControlByType(m_hMixer, m_DstLine.dwLineId, MIXERCONTROL_CT_CLASS_LIST, &mixerControl))
  337. && (MMSYSERR_NOERROR != mixerGetControlByType(m_hMixer, m_DstLine.dwLineId, MIXERCONTROL_CONTROLTYPE_MIXER, &mixerControl))
  338. && (MMSYSERR_NOERROR != mixerGetControlByType(m_hMixer, m_DstLine.dwLineId, MIXERCONTROL_CONTROLTYPE_MULTIPLESELECT, &mixerControl))
  339. && (MMSYSERR_NOERROR != mixerGetControlByType(m_hMixer, m_DstLine.dwLineId, MIXERCONTROL_CONTROLTYPE_MUX, &mixerControl))
  340. && (MMSYSERR_NOERROR != mixerGetControlByType(m_hMixer, m_DstLine.dwLineId, MIXERCONTROL_CONTROLTYPE_SINGLESELECT, &mixerControl))
  341. )
  342. {
  343. TRACE_OUT(("CMixerDevice::EnableMicrophone-Unable to find mixer list!"));
  344. return FALSE;
  345. }
  346. ZeroMemory(&mixerControlDetails, sizeof(MIXERCONTROLDETAILS));
  347. mixerControlDetails.cbStruct = sizeof(MIXERCONTROLDETAILS);
  348. mixerControlDetails.dwControlID = mixerControl.dwControlID;
  349. if (MIXERCONTROL_CONTROLF_UNIFORM & mixerControl.fdwControl)
  350. mixerControlDetails.cChannels = 1;
  351. else
  352. mixerControlDetails.cChannels = m_DstLine.ucChannels;
  353. if (MIXERCONTROL_CONTROLF_MULTIPLE & mixerControl.fdwControl)
  354. mixerControlDetails.cMultipleItems = (UINT)mixerControl.cMultipleItems;
  355. else
  356. mixerControlDetails.cMultipleItems = 1;
  357. // weirdness - you have to set cbDetails to the size of a single LISTTEXT item
  358. // setting it to anything larger will make the call fail
  359. mixerControlDetails.cbDetails = sizeof(MIXERCONTROLDETAILS_LISTTEXT);
  360. numItems = mixerControlDetails.cMultipleItems;
  361. if (m_DstLine.dwConnections > numItems)
  362. numItems = m_DstLine.dwConnections;
  363. DBG_SAVE_FILE_LINE
  364. aListText = new MIXERCONTROLDETAILS_LISTTEXT[numItems];
  365. DBG_SAVE_FILE_LINE
  366. aEnableList = new MIXERCONTROLDETAILS_BOOLEAN[numItems];
  367. if ((aListText == NULL) || (aEnableList == NULL))
  368. {
  369. WARNING_OUT(("CMixerDevice::EnableMicrophone-Out of memory"));
  370. return FALSE;
  371. }
  372. ZeroMemory(aListText, sizeof(MIXERCONTROLDETAILS_LISTTEXT)*numItems);
  373. ZeroMemory(aEnableList, sizeof(MIXERCONTROLDETAILS_BOOLEAN)*numItems);
  374. mixerControlDetails.paDetails = aListText;
  375. // preserve the settings, some values will change after this call
  376. mixerControlDetailsOrig = mixerControlDetails;
  377. // query for the text of the list
  378. mmr = mixerGetControlDetails((HMIXEROBJ)m_hMixer, &mixerControlDetails,
  379. MIXER_GETCONTROLDETAILSF_LISTTEXT
  380. |MIXER_OBJECTF_HMIXER);
  381. // some sound cards don't specify CONTROLF_MULTIPLE
  382. // try doing what sndvol32 does for MUX controls
  383. if (mmr != MMSYSERR_NOERROR)
  384. {
  385. mixerControlDetails = mixerControlDetailsOrig;
  386. mixerControlDetails.cChannels = 1;
  387. mixerControlDetails.cMultipleItems = m_DstLine.dwConnections;
  388. mixerControlDetailsOrig = mixerControlDetails;
  389. mmr = mixerGetControlDetails((HMIXEROBJ)m_hMixer, &mixerControlDetails,
  390. MIXER_GETCONTROLDETAILSF_LISTTEXT
  391. |MIXER_OBJECTF_HMIXER);
  392. }
  393. if (mmr != MMSYSERR_NOERROR)
  394. {
  395. delete [] aListText;
  396. delete [] aEnableList;
  397. return FALSE;
  398. }
  399. // enumerate for the microphone
  400. numMics = 0;
  401. fMicFound = FALSE;
  402. for (uIndex = 0; uIndex < mixerControlDetails.cMultipleItems; uIndex++)
  403. {
  404. // dwParam1 of the listText structure is the LineID of the source
  405. // dwParam2 should be the component type, but unfoturnately not
  406. // all sound cards obey this rule.
  407. ZeroMemory (&mixerLine, sizeof(MIXERLINE));
  408. mixerLine.cbStruct = sizeof(MIXERLINE);
  409. mixerLine.dwLineID = aListText[uIndex].dwParam1;
  410. mmr = mixerGetLineInfo ((HMIXEROBJ)m_hMixer, &mixerLine,
  411. MIXER_GETLINEINFOF_LINEID | MIXER_OBJECTF_HMIXER);
  412. if ((mmr == MMSYSERR_NOERROR) &&
  413. (mixerLine.dwComponentType == m_SrcLine.dwCompType) &&
  414. (numMics < MAX_MICROPHONE_DEVS))
  415. {
  416. aMicIndices[numMics] = uIndex;
  417. numMics++;
  418. }
  419. if (aListText[uIndex].dwParam1 == m_SrcLine.dwLineId)
  420. {
  421. uMicIndex = uIndex;
  422. fMicFound = TRUE; // can't rely on uIndex or uNumMics not zero
  423. }
  424. }
  425. if (fMicFound == FALSE)
  426. {
  427. delete [] aListText;
  428. delete [] aEnableList;
  429. return FALSE;
  430. }
  431. // now we know which position in the array to set, let's do it.
  432. mixerControlDetails = mixerControlDetailsOrig;
  433. mixerControlDetails.paDetails = aEnableList;
  434. mixerControlDetails.cbDetails = sizeof(MIXERCONTROLDETAILS_BOOLEAN);
  435. // find out what's already marked as set.
  436. mmr = mixerGetControlDetails((HMIXEROBJ)m_hMixer, &mixerControlDetails,
  437. MIXER_SETCONTROLDETAILSF_VALUE|MIXER_OBJECTF_HMIXER);
  438. if ((mmr == MMSYSERR_NOERROR) && (aEnableList[uMicIndex].fValue != 1))
  439. {
  440. // how many microphone's are already enabled ?
  441. // if another microphone is already enabled and if the device is MUX type
  442. // we won't attempt to turn one on.
  443. numMicsSet = 0;
  444. for (uIndex = 0; uIndex < numMics; uIndex++)
  445. {
  446. if ((aEnableList[aMicIndices[uIndex]].fValue == 1) &&
  447. (uIndex != uMicIndex))
  448. {
  449. numMicsSet++;
  450. }
  451. }
  452. if ( (mixerControl.dwControlType == MIXERCONTROL_CONTROLTYPE_MUX)
  453. ||(mixerControl.dwControlType == MIXERCONTROL_CONTROLTYPE_SINGLESELECT))
  454. {
  455. ZeroMemory(aEnableList, sizeof(aEnableList)*numItems);
  456. aEnableList[uMicIndex].fValue = 1;
  457. if (numMicsSet == 0)
  458. {
  459. mmr = mixerSetControlDetails((HMIXEROBJ)m_hMixer, &mixerControlDetails,
  460. MIXER_SETCONTROLDETAILSF_VALUE|MIXER_OBJECTF_HMIXER);
  461. }
  462. else
  463. {
  464. mmr = MMSYSERR_ERROR; // a mike has already been enabled
  465. }
  466. }
  467. else
  468. {
  469. mixerControlDetails = mixerControlDetailsOrig;
  470. mixerControlDetails.paDetails = aEnableList;
  471. mixerControlDetails.cbDetails = sizeof(MIXERCONTROLDETAILS_BOOLEAN);
  472. aEnableList[uMicIndex].fValue = 1;
  473. mmr = mixerSetControlDetails((HMIXEROBJ)m_hMixer, &mixerControlDetails,
  474. MIXER_GETCONTROLDETAILSF_VALUE|MIXER_OBJECTF_HMIXER);
  475. }
  476. }
  477. delete []aEnableList;
  478. delete []aListText;
  479. return (mmr == MMSYSERR_NOERROR);
  480. }
  481. BOOL CMixerDevice::UnMuteVolume()
  482. {
  483. MIXERCONTROL mixerControl;
  484. MIXERCONTROLDETAILS mixerControlDetails;
  485. MIXERCONTROLDETAILS_BOOLEAN mcdb;
  486. MMRESULT mmrMaster, mmrSub;
  487. // try to unmute the master volume
  488. // this could be used on both the recording and playback mixers
  489. mmrMaster = mixerGetControlByType(m_hMixer,
  490. m_DstLine.dwLineId, MIXERCONTROL_CONTROLTYPE_MUTE,
  491. &mixerControl);
  492. if (mmrMaster == MMSYSERR_NOERROR)
  493. {
  494. ZeroMemory(&mixerControlDetails, sizeof(MIXERCONTROLDETAILS));
  495. mixerControlDetails.cbStruct = sizeof(MIXERCONTROLDETAILS);
  496. mixerControlDetails.dwControlID = mixerControl.dwControlID;
  497. mixerControlDetails.cChannels = 1;
  498. mixerControlDetails.cMultipleItems = 0;
  499. mcdb.fValue = 0;
  500. mixerControlDetails.paDetails = &mcdb;
  501. mixerControlDetails.cbDetails = sizeof(MIXERCONTROLDETAILS_BOOLEAN);
  502. mmrMaster = mixerSetControlDetails((HMIXEROBJ)m_hMixer,
  503. &mixerControlDetails,
  504. MIXER_SETCONTROLDETAILSF_VALUE|MIXER_OBJECTF_HMIXER);
  505. }
  506. // only try to unmute waveOut
  507. if ( (m_DstLine.dwCompType != MIXERLINE_COMPONENTTYPE_DST_SPEAKERS)
  508. || (m_SrcLine.dwCompType == 0))
  509. {
  510. return (mmrMaster == MMSYSERR_NOERROR);
  511. }
  512. mmrSub = mixerGetControlByType(m_hMixer,
  513. m_SrcLine.dwLineId, MIXERCONTROL_CONTROLTYPE_MUTE,
  514. &mixerControl);
  515. if (mmrSub == MMSYSERR_NOERROR)
  516. {
  517. ZeroMemory(&mixerControlDetails, sizeof(MIXERCONTROLDETAILS));
  518. mixerControlDetails.cbStruct = sizeof(MIXERCONTROLDETAILS);
  519. mixerControlDetails.dwControlID = mixerControl.dwControlID;
  520. mixerControlDetails.cChannels = 1;
  521. mixerControlDetails.cMultipleItems = 0;
  522. mcdb.fValue = 0;
  523. mixerControlDetails.paDetails = &mcdb;
  524. mixerControlDetails.cbDetails = sizeof(MIXERCONTROLDETAILS_BOOLEAN);
  525. mmrSub = mixerSetControlDetails((HMIXEROBJ)m_hMixer,
  526. &mixerControlDetails,
  527. MIXER_SETCONTROLDETAILSF_VALUE|MIXER_OBJECTF_HMIXER);
  528. }
  529. return ((mmrSub == MMSYSERR_NOERROR) || (mmrMaster == MMSYSERR_NOERROR));
  530. }
  531. //////////////////////////////////////////////////
  532. //
  533. // The following are private APIs
  534. //
  535. static MMRESULT mixerGetControlValue ( HMIXER hMixer, DWORD *pdwValue,
  536. DWORD dwControlId, UINT ucChannels )
  537. {
  538. MIXERCONTROLDETAILS mxcd;
  539. MMRESULT mmr;
  540. ZeroMemory (&mxcd, sizeof (mxcd));
  541. mxcd.cbStruct = sizeof (mxcd);
  542. mxcd.dwControlID = dwControlId;
  543. mxcd.cChannels = ucChannels;
  544. mxcd.cbDetails = sizeof (DWORD);
  545. mxcd.paDetails = (PVOID) pdwValue;
  546. mmr = mixerGetControlDetails ((HMIXEROBJ) hMixer, &mxcd,
  547. MIXER_GETCONTROLDETAILSF_VALUE | MIXER_OBJECTF_HMIXER);
  548. return mmr;
  549. }
  550. static MMRESULT mixerSetControlValue ( HMIXER hMixer, DWORD *pdwValue,
  551. DWORD dwControlId, UINT ucChannels )
  552. {
  553. MIXERCONTROLDETAILS mxcd;
  554. MMRESULT mmr;
  555. ZeroMemory (&mxcd, sizeof (mxcd));
  556. mxcd.cbStruct = sizeof (mxcd);
  557. mxcd.dwControlID = dwControlId;
  558. mxcd.cChannels = ucChannels;
  559. mxcd.cbDetails = sizeof (DWORD);
  560. mxcd.paDetails = (PVOID) pdwValue;
  561. mmr = mixerSetControlDetails ((HMIXEROBJ) hMixer, &mxcd,
  562. MIXER_SETCONTROLDETAILSF_VALUE | MIXER_OBJECTF_HMIXER);
  563. return mmr;
  564. }
  565. static MMRESULT mixerGetControlId ( HMIXER hMixer, DWORD *pdwControlId,
  566. DWORD dwLineId, DWORD dwControlType )
  567. {
  568. MIXERLINECONTROLS mxlc;
  569. MIXERCONTROL mxc;
  570. MMRESULT mmr;
  571. ZeroMemory (&mxlc, sizeof (mxlc));
  572. ZeroMemory (&mxc, sizeof (mxc));
  573. mxlc.cbStruct = sizeof (mxlc);
  574. mxlc.dwLineID = dwLineId;
  575. mxlc.dwControlType = dwControlType;
  576. mxlc.cControls = 1;
  577. mxlc.cbmxctrl = sizeof (mxc);
  578. mxlc.pamxctrl = &mxc;
  579. mmr = mixerGetLineControls ((HMIXEROBJ) hMixer, &mxlc,
  580. MIXER_GETLINECONTROLSF_ONEBYTYPE | MIXER_OBJECTF_HMIXER);
  581. *pdwControlId = mxc.dwControlID;
  582. return mmr;
  583. }
  584. // similar to above, except returns the whole control
  585. static MMRESULT mixerGetControlByType ( HMIXER hMixer, DWORD dwLineId, DWORD dwControlType, MIXERCONTROL *pMixerControl)
  586. {
  587. MIXERLINECONTROLS mxlc;
  588. MMRESULT mmr;
  589. ZeroMemory (&mxlc, sizeof (mxlc));
  590. ZeroMemory (pMixerControl, sizeof (MIXERCONTROL));
  591. mxlc.cbStruct = sizeof (mxlc);
  592. mxlc.dwLineID = dwLineId;
  593. mxlc.dwControlType = dwControlType;
  594. mxlc.cControls = 1;
  595. mxlc.cbmxctrl = sizeof (MIXERCONTROL);
  596. mxlc.pamxctrl = pMixerControl;
  597. mmr = mixerGetLineControls ((HMIXEROBJ) hMixer, &mxlc,
  598. MIXER_GETLINECONTROLSF_ONEBYTYPE | MIXER_OBJECTF_HMIXER);
  599. return mmr;
  600. }
  601. // IUnknown stuff
  602. ULONG __stdcall CMixerDevice::AddRef()
  603. {
  604. InterlockedIncrement(&m_lRefCount);
  605. return m_lRefCount;
  606. }
  607. ULONG __stdcall CMixerDevice::Release()
  608. {
  609. if (0 == InterlockedDecrement(&m_lRefCount))
  610. {
  611. delete this;
  612. return 0;
  613. }
  614. return m_lRefCount;
  615. }
  616. HRESULT __stdcall CMixerDevice::QueryInterface(const IID& iid, void **ppVoid)
  617. {
  618. if ((iid == IID_IUnknown) || (iid == IID_IMixer))
  619. {
  620. *ppVoid = this;
  621. }
  622. else
  623. {
  624. *ppVoid = NULL;
  625. return E_NOINTERFACE;
  626. }
  627. AddRef();
  628. return S_OK;
  629. }
  630.