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.

912 lines
26 KiB

  1. #include "cabinet.h"
  2. #include "mixer.h"
  3. #include <dbt.h>
  4. #include "mmddkp.h"
  5. ///////////////////////////////////////
  6. // External interface
  7. //
  8. ///////////////////////////////////////
  9. // Definitions
  10. //
  11. #define MMHID_VOLUME_CONTROL 0
  12. #define MMHID_BASS_CONTROL 1
  13. #define MMHID_TREBLE_CONTROL 2
  14. #define MMHID_BALANCE_CONTROL 3
  15. #define MMHID_MUTE_CONTROL 4
  16. #define MMHID_LOUDNESS_CONTROL 5
  17. #define MMHID_BASSBOOST_CONTROL 6
  18. #define MMHID_NUM_CONTROLS 7
  19. typedef struct _LINE_DATA
  20. {
  21. MIXERLINE MixerLine; // The real deal MIXERLINE struct.
  22. DWORD ControlType[MMHID_NUM_CONTROLS];
  23. BOOL ControlPresent[MMHID_NUM_CONTROLS];
  24. MIXERCONTROL Control[MMHID_NUM_CONTROLS];
  25. } LINE_DATA, * PLINE_DATA, FAR * LPLINE_DATA;
  26. typedef struct _MIXER_DATA
  27. {
  28. HMIXER hMixer; // open handle to mixer
  29. HWND hwndCallback; // window to use for mixer callbacks
  30. LPWSTR DeviceInterface; // DeviceInterface that implements the mixer
  31. double* pdblCacheMix; // Dynamic array of relative channel level percentages
  32. LPDWORD pdwLastVolume; // Last volume level set on mixer
  33. MMRESULT mmr; // last result (iff dwReturn == MIXUI_MMSYSERR)
  34. LINE_DATA LineData; // BYDESIGN - putting this here assumes only one
  35. // mixer line for now. (first dest. line)
  36. } MIXER_DATA, *PMIXER_DATA, FAR *LPMIXER_DATA;
  37. /*++
  38. * Globals
  39. --*/
  40. BOOL g_fMixerStartup = TRUE;
  41. HWND g_hwndCallback;
  42. MIXER_DATA g_MixerData;
  43. BOOL g_fMixerPresent = FALSE;
  44. void Mixer_Close(MIXER_DATA *pMixerData);
  45. BOOL Mixer_CheckMissing(void);
  46. /*****************************************************************************
  47. *
  48. * ACTIVE GET/SET CODE
  49. *
  50. *****************************************************************************/
  51. #define VOLUME_MIN 0L
  52. #define VOLUME_MAX 65535L
  53. void RefreshMixCache (PMIXER_DATA pMixerData, LPDWORD padwVolume)
  54. {
  55. if (pMixerData && padwVolume)
  56. {
  57. DWORD cChannels = pMixerData -> LineData.MixerLine.cChannels;
  58. if (1 > cChannels)
  59. return; // Weird!
  60. // Create cache if necessary
  61. if (!pMixerData -> pdblCacheMix)
  62. pMixerData -> pdblCacheMix = (double *)LocalAlloc(LPTR, cChannels * sizeof (double));
  63. // Refresh cache
  64. if (pMixerData -> pdblCacheMix)
  65. {
  66. UINT uiIndx;
  67. double* pdblMixPercent;
  68. DWORD dwVolume;
  69. // Get the maximum volume
  70. DWORD dwMaxVol = 0;
  71. for (uiIndx = 0; uiIndx < cChannels; uiIndx++)
  72. dwMaxVol = max (dwMaxVol, *(padwVolume + uiIndx));
  73. // Caculate the percentage distance each channel is away from the max
  74. // value. Creating this cache allows us to maintain the relative distance
  75. // of the channel levels from each other as the user adjusts the master
  76. // volume level.
  77. for (uiIndx = 0; uiIndx < cChannels; uiIndx++)
  78. {
  79. dwVolume = *(padwVolume + uiIndx);
  80. pdblMixPercent = ((pMixerData -> pdblCacheMix) + uiIndx);
  81. // Caculate the percentage this value is from the max ...
  82. if (dwMaxVol == dwVolume)
  83. {
  84. *pdblMixPercent = 1.0F;
  85. }
  86. else
  87. {
  88. // Note: if 0 == dwMaxVol all values would be zero and this part
  89. // of the "if" statement will never execute.
  90. *pdblMixPercent = ((double) dwVolume / (double) dwMaxVol);
  91. }
  92. }
  93. }
  94. }
  95. }
  96. static
  97. MMRESULT
  98. Mixer_GetVolume(
  99. LPMIXER_DATA pMixerData,
  100. LPDWORD padwVolume
  101. )
  102. /*++
  103. Routine Description:
  104. --*/
  105. {
  106. MIXERCONTROLDETAILS mxcd;
  107. MMRESULT mmr;
  108. if (!pMixerData->LineData.ControlPresent[MMHID_VOLUME_CONTROL]) return MIXERR_INVALCONTROL;
  109. mxcd.cbStruct = sizeof(mxcd);
  110. mxcd.dwControlID = pMixerData->LineData.Control[MMHID_VOLUME_CONTROL].dwControlID;
  111. mxcd.cChannels = pMixerData->LineData.MixerLine.cChannels;
  112. mxcd.cMultipleItems = 0;
  113. mxcd.cbDetails = sizeof(DWORD);
  114. mxcd.paDetails = (LPVOID)padwVolume;
  115. mmr = mixerGetControlDetails((HMIXEROBJ)pMixerData->hMixer,
  116. &mxcd,
  117. MIXER_OBJECTF_HANDLE | MIXER_GETCONTROLDETAILSF_VALUE);
  118. return mmr;
  119. }
  120. MMRESULT
  121. Mixer_ToggleMute(void)
  122. /*++
  123. Routine Description:
  124. --*/
  125. {
  126. MIXERCONTROLDETAILS mxcd;
  127. DWORD fMute;
  128. MMRESULT mmr;
  129. MIXER_DATA *pMixerData = &g_MixerData;
  130. if (Mixer_CheckMissing())
  131. {
  132. return MMSYSERR_NODRIVER;
  133. }
  134. if (!pMixerData->LineData.ControlPresent[MMHID_MUTE_CONTROL]) return MMSYSERR_NOERROR;
  135. mxcd.cbStruct = sizeof(mxcd);
  136. mxcd.dwControlID = pMixerData->LineData.Control[MMHID_MUTE_CONTROL].dwControlID ;
  137. mxcd.cChannels = 1;
  138. mxcd.cMultipleItems = 0;
  139. mxcd.cbDetails = sizeof(fMute);
  140. mxcd.paDetails = (LPVOID)&fMute;
  141. mmr = mixerGetControlDetails((HMIXEROBJ)pMixerData->hMixer,
  142. &mxcd,
  143. MIXER_OBJECTF_HANDLE | MIXER_GETCONTROLDETAILSF_VALUE);
  144. if (!mmr) {
  145. fMute = fMute ? 0 : 1;
  146. mmr = mixerSetControlDetails((HMIXEROBJ)pMixerData->hMixer,
  147. &mxcd,
  148. MIXER_OBJECTF_HANDLE | MIXER_SETCONTROLDETAILSF_VALUE);
  149. }
  150. return mmr;
  151. }
  152. MMRESULT
  153. Mixer_ToggleLoudness(
  154. MIXER_DATA * pMixerData
  155. )
  156. /*++
  157. Routine Description:
  158. --*/
  159. {
  160. MIXERCONTROLDETAILS mxcd;
  161. DWORD fEnabled;
  162. MMRESULT mmr;
  163. if (!pMixerData->LineData.ControlPresent[MMHID_LOUDNESS_CONTROL]) return MMSYSERR_NOERROR;
  164. mxcd.cbStruct = sizeof(mxcd);
  165. mxcd.dwControlID = pMixerData->LineData.Control[MMHID_LOUDNESS_CONTROL].dwControlID ;
  166. mxcd.cChannels = 1;
  167. mxcd.cMultipleItems = 0;
  168. mxcd.cbDetails = sizeof(fEnabled);
  169. mxcd.paDetails = (LPVOID)&fEnabled;
  170. mmr = mixerGetControlDetails((HMIXEROBJ)pMixerData->hMixer,
  171. &mxcd,
  172. MIXER_OBJECTF_HANDLE | MIXER_GETCONTROLDETAILSF_VALUE);
  173. if (!mmr) {
  174. fEnabled = fEnabled ? 0 : 1;
  175. mmr = mixerSetControlDetails((HMIXEROBJ)pMixerData->hMixer,
  176. &mxcd,
  177. MIXER_OBJECTF_HANDLE | MIXER_SETCONTROLDETAILSF_VALUE);
  178. }
  179. return mmr;
  180. }
  181. MMRESULT Mixer_ToggleBassBoost(void)
  182. /*++
  183. Routine Description:
  184. --*/
  185. {
  186. MIXERCONTROLDETAILS mxcd;
  187. DWORD fEnabled;
  188. MMRESULT mmr;
  189. MIXER_DATA *pMixerData = &g_MixerData;
  190. if (Mixer_CheckMissing())
  191. {
  192. return MMSYSERR_NODRIVER;
  193. }
  194. if (!pMixerData->LineData.ControlPresent[MMHID_BASSBOOST_CONTROL]) return MMSYSERR_NOERROR;
  195. mxcd.cbStruct = sizeof(mxcd);
  196. mxcd.dwControlID = pMixerData->LineData.Control[MMHID_BASSBOOST_CONTROL].dwControlID ;
  197. mxcd.cChannels = 1;
  198. mxcd.cMultipleItems = 0;
  199. mxcd.cbDetails = sizeof(fEnabled);
  200. mxcd.paDetails = (LPVOID)&fEnabled;
  201. mmr = mixerGetControlDetails((HMIXEROBJ)pMixerData->hMixer,
  202. &mxcd,
  203. MIXER_OBJECTF_HANDLE | MIXER_GETCONTROLDETAILSF_VALUE);
  204. if (!mmr) {
  205. fEnabled = fEnabled ? 0 : 1;
  206. mmr = mixerSetControlDetails((HMIXEROBJ)pMixerData->hMixer,
  207. &mxcd,
  208. MIXER_OBJECTF_HANDLE | MIXER_SETCONTROLDETAILSF_VALUE);
  209. }
  210. return mmr;
  211. }
  212. MMRESULT
  213. Mixer_SetVolume(
  214. int Increment // amount of volume change
  215. )
  216. /*++
  217. Routine Description:
  218. Change a mixerControl in response to a user event
  219. --*/
  220. {
  221. MMRESULT mmr;
  222. MIXERCONTROLDETAILS mxcd;
  223. LPVOID pvVolume;
  224. UINT uiIndx;
  225. LPDWORD pdwVolume;
  226. double dblVolume;
  227. MIXER_DATA *pMixerData = &g_MixerData;
  228. PLINE_DATA pLineData;
  229. DWORD cChannels;
  230. if (Mixer_CheckMissing())
  231. {
  232. return MMSYSERR_NODRIVER;
  233. }
  234. pLineData = &pMixerData->LineData;
  235. cChannels = pMixerData -> LineData.MixerLine.cChannels;
  236. if (!pMixerData->LineData.ControlPresent[MMHID_VOLUME_CONTROL]) return MMSYSERR_NOERROR;
  237. //
  238. // get current volume
  239. //
  240. ZeroMemory (&mxcd, sizeof (mxcd));
  241. mxcd.cbDetails = sizeof (DWORD);
  242. mxcd.paDetails = LocalAlloc(LPTR, cChannels * sizeof (DWORD));
  243. if (!mxcd.paDetails)
  244. return MMSYSERR_NOMEM;
  245. pvVolume = LocalAlloc(LPTR, cChannels * sizeof (DWORD));
  246. if (!pvVolume)
  247. {
  248. LocalFree(mxcd.paDetails);
  249. return MMSYSERR_NOMEM;
  250. }
  251. // Note: From here on, do not return without freeing 'mxcd.paDetails'
  252. // and 'pvVolume'.
  253. // Get the current volume and any mix cache
  254. mmr = Mixer_GetVolume (pMixerData, (LPDWORD)mxcd.paDetails);
  255. if (MMSYSERR_NOERROR == mmr)
  256. {
  257. // Create cache if we don't already have one
  258. if (!pMixerData -> pdblCacheMix)
  259. {
  260. RefreshMixCache (pMixerData, (LPDWORD)mxcd.paDetails);
  261. if (!pMixerData -> pdblCacheMix)
  262. mmr = MMSYSERR_NOMEM;
  263. else
  264. {
  265. // Create last set volume cache
  266. if (!pMixerData -> pdwLastVolume)
  267. {
  268. pMixerData -> pdwLastVolume = (DWORD *)LocalAlloc(LPTR, cChannels * sizeof (DWORD));
  269. if (!pMixerData -> pdwLastVolume)
  270. mmr = MMSYSERR_NOMEM;
  271. }
  272. }
  273. }
  274. else
  275. {
  276. // HHMMM, speculating random ass fix for 167948/174466 since this
  277. // is the ONLY branch where pdwLastVolume can be NULL and not
  278. // generate an error. Will have to talk to FrankYe
  279. // -Fwong.
  280. if (!pMixerData -> pdwLastVolume)
  281. {
  282. pMixerData -> pdwLastVolume = (DWORD *)LocalAlloc(LPTR, cChannels * sizeof (DWORD));
  283. if (!pMixerData -> pdwLastVolume)
  284. mmr = MMSYSERR_NOMEM;
  285. }
  286. }
  287. }
  288. // Don't allow incrementing past max volume (channels meet at
  289. // min volume, so need to test that).
  290. if (0 < Increment && MMSYSERR_NOERROR == mmr)
  291. {
  292. for (uiIndx = 0; uiIndx < cChannels; uiIndx++)
  293. {
  294. pdwVolume = (((DWORD*)mxcd.paDetails) + uiIndx);
  295. dblVolume = (*(pMixerData -> pdblCacheMix + uiIndx) * (double) Increment);
  296. if (VOLUME_MAX <= (*pdwVolume) + dblVolume)
  297. Increment = min ((DWORD) Increment, VOLUME_MAX - (*pdwVolume));
  298. }
  299. }
  300. //
  301. // set the volume
  302. //
  303. if (0 != Increment && MMSYSERR_NOERROR == mmr)
  304. {
  305. // Back up the current settings
  306. memcpy (pvVolume, mxcd.paDetails, cChannels * sizeof (DWORD));
  307. // Caculate the new volume level for each of the channels. For volume levels
  308. // at the current max, we simply set the newly requested level (in this case
  309. // the cache value is 1.0). For those less than the max, we set a value that
  310. // is a percentage of the max. This maintains the relative distance of the
  311. // channel levels from each other.
  312. for (uiIndx = 0; uiIndx < cChannels; uiIndx++)
  313. {
  314. pdwVolume = (((DWORD*)mxcd.paDetails) + uiIndx);
  315. dblVolume = (*(pMixerData -> pdblCacheMix + uiIndx) * (double) Increment);
  316. // Ensure positive result
  317. if (VOLUME_MIN >= ((double)(*pdwVolume) + dblVolume))
  318. (*pdwVolume) = VOLUME_MIN;
  319. else
  320. (*pdwVolume) = (DWORD)((double)(*pdwVolume) + dblVolume);
  321. // Ensure that the new value is in range
  322. (*pdwVolume) = (DWORD) min (VOLUME_MAX, (*pdwVolume));
  323. // Disables pesky warning...
  324. #if (VOLUME_MIN != 0L)
  325. (*pdwVolume) = (DWORD) max (VOLUME_MIN, (*pdwVolume));
  326. #endif
  327. }
  328. // Cache last caculated volume..
  329. memcpy (pMixerData -> pdwLastVolume, mxcd.paDetails, cChannels * sizeof (DWORD));
  330. mxcd.cbStruct = sizeof(mxcd);
  331. mxcd.dwControlID = pLineData->Control[MMHID_VOLUME_CONTROL].dwControlID;
  332. mxcd.cChannels = cChannels;
  333. mxcd.cMultipleItems = 0;
  334. // Apply new value only if it is different. This prevents unessary calls to
  335. // mixerSetControlDetails() when we are pegged.
  336. if (memcmp (pvVolume, mxcd.paDetails, cChannels * sizeof (DWORD)))
  337. {
  338. //
  339. // Set the volume control at the mixer.
  340. //
  341. mmr = mixerSetControlDetails((HMIXEROBJ)pMixerData->hMixer,
  342. &mxcd,
  343. MIXER_OBJECTF_HANDLE | MIXER_SETCONTROLDETAILSF_VALUE);
  344. }
  345. }
  346. // Free 'mxcd.paDetails' and 'pvVolume'
  347. LocalFree(mxcd.paDetails);
  348. LocalFree(pvVolume);
  349. return mmr;
  350. }
  351. #define BASS_MIN 0L
  352. #define BASS_MAX 65535L
  353. MMRESULT
  354. Mixer_SetBass(
  355. int Increment // amount of change
  356. )
  357. /*++
  358. Routine Description:
  359. Change a mixerControl in response to a user event
  360. --*/
  361. {
  362. MMRESULT mmr;
  363. MIXERCONTROLDETAILS mxcd;
  364. MIXER_DATA *pMixerData = &g_MixerData;
  365. PLINE_DATA pLineData;
  366. if (Mixer_CheckMissing())
  367. {
  368. return MMSYSERR_NODRIVER;
  369. }
  370. pLineData = &pMixerData->LineData;
  371. LONG lLevel = 0;
  372. if (!pMixerData->LineData.ControlPresent[MMHID_BASS_CONTROL]) return MMSYSERR_NOERROR;
  373. mxcd.cbStruct = sizeof(mxcd);
  374. mxcd.dwControlID = pLineData->Control[MMHID_BASS_CONTROL].dwControlID;
  375. //
  376. // get current setting
  377. //
  378. mxcd.cChannels = 1;
  379. mxcd.cMultipleItems = 0;
  380. mxcd.cbDetails = sizeof(lLevel);
  381. mxcd.paDetails = (LPVOID)&lLevel;
  382. mmr = mixerGetControlDetails((HMIXEROBJ)pMixerData->hMixer,
  383. &mxcd,
  384. MIXER_OBJECTF_HANDLE | MIXER_GETCONTROLDETAILSF_VALUE);
  385. if (mmr) return mmr;
  386. lLevel += Increment;
  387. lLevel = min( BASS_MAX, lLevel);
  388. lLevel = max( BASS_MIN, lLevel);
  389. mxcd.cChannels = 1;
  390. mxcd.cMultipleItems = 0;
  391. mxcd.cbDetails = sizeof(lLevel);
  392. mxcd.paDetails = (LPVOID)&lLevel;
  393. //
  394. // Set the bass control at the mixer.
  395. //
  396. mmr = mixerSetControlDetails((HMIXEROBJ)pMixerData->hMixer,
  397. &mxcd,
  398. MIXER_OBJECTF_HANDLE | MIXER_SETCONTROLDETAILSF_VALUE);
  399. return mmr;
  400. }
  401. #define TREBLE_MIN 0L
  402. #define TREBLE_MAX 65535L
  403. MMRESULT
  404. Mixer_SetTreble(
  405. int Increment
  406. )
  407. /*++
  408. Routine Description:
  409. Change a mixerControl in response to a user event
  410. --*/
  411. {
  412. MMRESULT mmr;
  413. MIXERCONTROLDETAILS mxcd;
  414. MIXER_DATA *pMixerData = &g_MixerData;
  415. PLINE_DATA pLineData;
  416. if (Mixer_CheckMissing())
  417. {
  418. return MMSYSERR_NODRIVER;
  419. }
  420. pLineData = &pMixerData->LineData;
  421. LONG lLevel = 0;
  422. if (!pMixerData->LineData.ControlPresent[MMHID_TREBLE_CONTROL]) return MMSYSERR_NOERROR;
  423. mxcd.cbStruct = sizeof(mxcd);
  424. mxcd.dwControlID = pLineData->Control[MMHID_TREBLE_CONTROL].dwControlID;
  425. //
  426. // get current setting
  427. //
  428. mxcd.cChannels = 1;
  429. mxcd.cMultipleItems = 0;
  430. mxcd.cbDetails = sizeof(lLevel);
  431. mxcd.paDetails = (LPVOID)&lLevel;
  432. mmr = mixerGetControlDetails((HMIXEROBJ)pMixerData->hMixer,
  433. &mxcd,
  434. MIXER_OBJECTF_HANDLE | MIXER_GETCONTROLDETAILSF_VALUE);
  435. if (mmr) return mmr;
  436. lLevel += Increment;
  437. lLevel = min( TREBLE_MAX, lLevel);
  438. lLevel = max( TREBLE_MIN, lLevel);
  439. mxcd.cChannels = 1;
  440. mxcd.cMultipleItems = 0;
  441. mxcd.cbDetails = sizeof(lLevel);
  442. mxcd.paDetails = (LPVOID)&lLevel;
  443. //
  444. // Set the bass control at the mixer.
  445. //
  446. mmr = mixerSetControlDetails((HMIXEROBJ)pMixerData->hMixer,
  447. &mxcd,
  448. MIXER_OBJECTF_HANDLE | MIXER_SETCONTROLDETAILSF_VALUE);
  449. return mmr;
  450. }
  451. /*****************************************************************************
  452. *
  453. *
  454. *
  455. *****************************************************************************/
  456. MMRESULT
  457. Mixer_GetDefaultMixerID(
  458. int *pid
  459. )
  460. /*++
  461. Routine Description:
  462. Get the default mixer id. We only appear if there is a mixer associated
  463. with the default wave.
  464. --*/
  465. {
  466. MMRESULT mmr;
  467. UINT uWaveID, uMxID;
  468. DWORD dwFlags;
  469. if (0 == waveOutGetNumDevs()) return MMSYSERR_NODRIVER;
  470. mmr = waveOutMessage((HWAVEOUT)(UINT_PTR)WAVE_MAPPER, DRVM_MAPPER_PREFERRED_GET, (DWORD_PTR)&uWaveID, (DWORD_PTR)&dwFlags);
  471. if (MMSYSERR_NOERROR == mmr)
  472. {
  473. if (WAVE_MAPPER != uWaveID)
  474. {
  475. mmr = mixerGetID((HMIXEROBJ)(UINT_PTR)uWaveID, &uMxID, MIXER_OBJECTF_WAVEOUT);
  476. if (mmr == MMSYSERR_NOERROR)
  477. {
  478. *pid = uMxID;
  479. }
  480. } else {
  481. // Don't return a default mixer id if we don't have a default
  482. // audio driver
  483. mmr = MMSYSERR_NODRIVER;
  484. }
  485. }
  486. return mmr;
  487. }
  488. BOOL
  489. Mixer_GetDestLine(
  490. MIXER_DATA * pMixerData
  491. )
  492. /*++
  493. Routine Description:
  494. --*/
  495. {
  496. MIXERLINE * mlDst = &pMixerData->LineData.MixerLine;
  497. MMRESULT mmr;
  498. mlDst->cbStruct = sizeof ( MIXERLINE );
  499. mlDst->dwComponentType = MIXERLINE_COMPONENTTYPE_DST_SPEAKERS;
  500. mmr = mixerGetLineInfo((HMIXEROBJ)pMixerData->hMixer,
  501. mlDst,
  502. MIXER_OBJECTF_HANDLE | MIXER_GETLINEINFOF_COMPONENTTYPE);
  503. if (mmr != MMSYSERR_NOERROR){
  504. return FALSE;
  505. }
  506. return TRUE;
  507. }
  508. void
  509. Mixer_GetLineControls(
  510. MIXER_DATA * pMixerData,
  511. LINE_DATA * pLineData
  512. )
  513. /*++
  514. Routine Description:
  515. --*/
  516. {
  517. MIXERLINECONTROLS LineControls;
  518. MMRESULT mmr;
  519. DWORD i;
  520. for(i=0; i<MMHID_NUM_CONTROLS; i++){
  521. LineControls.cbStruct = sizeof(LineControls);
  522. LineControls.dwLineID = pLineData->MixerLine.dwLineID;
  523. LineControls.dwControlType = pLineData->ControlType[i];
  524. LineControls.cControls = 1;
  525. LineControls.cbmxctrl = sizeof(MIXERCONTROL);
  526. LineControls.pamxctrl = &pLineData->Control[i];
  527. mmr = mixerGetLineControls((HMIXEROBJ)pMixerData->hMixer,
  528. &LineControls,
  529. MIXER_OBJECTF_HANDLE | MIXER_GETLINECONTROLSF_ONEBYTYPE);
  530. pLineData->ControlPresent[i] = (MMSYSERR_NOERROR == mmr) ? TRUE : FALSE;
  531. if (mmr != MMSYSERR_NOERROR){
  532. //return mmr;
  533. }
  534. }
  535. return;
  536. }
  537. ///////////////////////////////////////
  538. //
  539. BOOL
  540. Mixer_Open(
  541. MIXER_DATA * pMixerData
  542. )
  543. /*++
  544. Routine Description:
  545. Finds the default mixer, opens it, and initializes
  546. all data.
  547. --*/
  548. {
  549. PWSTR pwstrDeviceInterface;
  550. ULONG cbDeviceInterface;
  551. int MixerId;
  552. MMRESULT mmr;
  553. BOOL result;
  554. ASSERT(!pMixerData->hMixer);
  555. // Get console mixer ID and open it.
  556. mmr = Mixer_GetDefaultMixerID(&MixerId);
  557. if(mmr) return FALSE;
  558. mmr = mixerOpen(&pMixerData->hMixer, MixerId, (DWORD_PTR)pMixerData->hwndCallback, 0, CALLBACK_WINDOW);
  559. if (!mmr) {
  560. //
  561. // Get our controls for the default destination line.
  562. //
  563. if (Mixer_GetDestLine(pMixerData)) {
  564. Mixer_GetLineControls(pMixerData, &pMixerData->LineData);
  565. // Free any mix cache & volume cache
  566. if (pMixerData->pdblCacheMix) LocalFree(pMixerData->pdblCacheMix);
  567. pMixerData->pdblCacheMix = NULL;
  568. if (pMixerData -> pdwLastVolume) LocalFree(pMixerData -> pdwLastVolume);
  569. pMixerData -> pdwLastVolume = NULL;
  570. // Get the DeviceInterface of the mixer in order to listen
  571. // for relevant PnP device messages
  572. if (pMixerData->DeviceInterface) LocalFree(pMixerData->DeviceInterface);
  573. pMixerData->DeviceInterface = NULL;
  574. mmr = (MMRESULT)mixerMessage(pMixerData->hMixer, DRV_QUERYDEVICEINTERFACESIZE, (DWORD_PTR)&cbDeviceInterface, 0);
  575. if (!mmr && (0 != cbDeviceInterface)) {
  576. pwstrDeviceInterface = (PWSTR)LocalAlloc(LPTR, cbDeviceInterface);
  577. if (pwstrDeviceInterface) {
  578. mmr = (MMRESULT)mixerMessage(pMixerData->hMixer, DRV_QUERYDEVICEINTERFACE, (DWORD_PTR)pwstrDeviceInterface, cbDeviceInterface);
  579. if (!mmr) {
  580. pMixerData->DeviceInterface = pwstrDeviceInterface;
  581. } else {
  582. LocalFree(pwstrDeviceInterface);
  583. }
  584. }
  585. }
  586. result = TRUE;
  587. } else {
  588. mixerClose(pMixerData->hMixer);
  589. pMixerData->hMixer = NULL;
  590. TraceMsg(TF_WARNING, "Mixer_Open : Could not find mixer destination line");
  591. result = FALSE;
  592. }
  593. }
  594. return result;
  595. }
  596. void Mixer_Close(MIXER_DATA *pMixerData)
  597. /*++
  598. Routine Description:
  599. Closes the mixer handle.
  600. --*/
  601. {
  602. if (pMixerData->DeviceInterface) LocalFree(pMixerData->DeviceInterface);
  603. pMixerData->DeviceInterface = NULL;
  604. if (pMixerData->pdblCacheMix) LocalFree(pMixerData->pdblCacheMix);
  605. pMixerData->pdblCacheMix = NULL;
  606. if (pMixerData->pdwLastVolume) LocalFree(pMixerData->pdwLastVolume);
  607. pMixerData->pdwLastVolume = NULL;
  608. if (pMixerData->hMixer){
  609. MMRESULT mmr;
  610. mmr = mixerClose(pMixerData->hMixer);
  611. if (mmr) TraceMsg(TF_ERROR, "Mixer_Close : error: mixerClose returned mmr=%08Xh", mmr);
  612. ASSERT(MMSYSERR_NOERROR == mmr);
  613. pMixerData->hMixer = NULL;
  614. }
  615. return;
  616. }
  617. void
  618. Mixer_Refresh(void)
  619. /*++
  620. Routine Description:
  621. Closes the current mixer handle (if one is open), then opens mixer
  622. again.
  623. --*/
  624. {
  625. Mixer_Close(&g_MixerData);
  626. g_fMixerPresent = Mixer_Open(&g_MixerData);
  627. }
  628. void Mixer_SetCallbackWindow(HWND hwndCallback)
  629. {
  630. g_hwndCallback = hwndCallback;
  631. }
  632. void Mixer_Startup(HWND hwndCallback)
  633. /*++
  634. Routine Description:
  635. --*/
  636. {
  637. MIXER_DATA *pMixerData = &g_MixerData;
  638. pMixerData->hMixer = NULL;
  639. pMixerData->hwndCallback = hwndCallback;
  640. pMixerData->DeviceInterface = NULL;
  641. pMixerData->pdblCacheMix = NULL;
  642. pMixerData->pdwLastVolume = NULL;
  643. pMixerData->LineData.ControlType[MMHID_VOLUME_CONTROL] = MIXERCONTROL_CONTROLTYPE_VOLUME;
  644. pMixerData->LineData.ControlType[MMHID_BASS_CONTROL] = MIXERCONTROL_CONTROLTYPE_BASS;
  645. pMixerData->LineData.ControlType[MMHID_TREBLE_CONTROL] = MIXERCONTROL_CONTROLTYPE_TREBLE;
  646. pMixerData->LineData.ControlType[MMHID_BALANCE_CONTROL] = MIXERCONTROL_CONTROLTYPE_PAN;
  647. pMixerData->LineData.ControlType[MMHID_MUTE_CONTROL] = MIXERCONTROL_CONTROLTYPE_MUTE;
  648. pMixerData->LineData.ControlType[MMHID_LOUDNESS_CONTROL] = MIXERCONTROL_CONTROLTYPE_LOUDNESS;
  649. pMixerData->LineData.ControlType[MMHID_BASSBOOST_CONTROL] = MIXERCONTROL_CONTROLTYPE_BASS_BOOST;
  650. pMixerData->LineData.ControlPresent[MMHID_VOLUME_CONTROL] = FALSE;
  651. pMixerData->LineData.ControlPresent[MMHID_BASS_CONTROL] = FALSE;
  652. pMixerData->LineData.ControlPresent[MMHID_TREBLE_CONTROL] = FALSE;
  653. pMixerData->LineData.ControlPresent[MMHID_BALANCE_CONTROL] = FALSE;
  654. pMixerData->LineData.ControlPresent[MMHID_MUTE_CONTROL] = FALSE;
  655. pMixerData->LineData.ControlPresent[MMHID_LOUDNESS_CONTROL] = FALSE;
  656. pMixerData->LineData.ControlPresent[MMHID_BASSBOOST_CONTROL] = FALSE;
  657. Mixer_Refresh();
  658. return;
  659. }
  660. BOOL Mixer_CheckMissing(void)
  661. {
  662. if (g_fMixerStartup)
  663. {
  664. Mixer_Startup(g_hwndCallback);
  665. g_fMixerStartup = FALSE;
  666. }
  667. return !g_fMixerPresent;
  668. }
  669. void Mixer_Shutdown(void)
  670. /*++
  671. Routine Description:
  672. Frees storage for mixer's DeviceInterface, then Mixer_Close().
  673. --*/
  674. {
  675. MIXER_DATA *pMixerData = &g_MixerData;
  676. if (pMixerData->DeviceInterface) LocalFree(pMixerData->DeviceInterface);
  677. pMixerData->DeviceInterface = NULL;
  678. if (pMixerData->pdblCacheMix) LocalFree(pMixerData->pdblCacheMix);
  679. pMixerData->pdblCacheMix = NULL;
  680. if (pMixerData->pdwLastVolume) LocalFree(pMixerData->pdwLastVolume);
  681. pMixerData->pdwLastVolume = NULL;
  682. Mixer_Close(pMixerData);
  683. return;
  684. }
  685. void Mixer_DeviceChange(WPARAM wParam, LPARAM lParam)
  686. {
  687. PDEV_BROADCAST_DEVICEINTERFACE dbdi = (PDEV_BROADCAST_DEVICEINTERFACE)lParam;
  688. if (!g_MixerData.DeviceInterface) return;
  689. switch (wParam) {
  690. case DBT_DEVICEQUERYREMOVE:
  691. case DBT_DEVICEREMOVEPENDING:
  692. if (dbdi->dbcc_devicetype != DBT_DEVTYP_DEVICEINTERFACE) return;
  693. if (lstrcmpi(dbdi->dbcc_name, g_MixerData.DeviceInterface)) return;
  694. Mixer_Close(&g_MixerData);
  695. return;
  696. case DBT_DEVICEQUERYREMOVEFAILED:
  697. if (dbdi->dbcc_devicetype != DBT_DEVTYP_DEVICEINTERFACE) return;
  698. if (lstrcmpi(dbdi->dbcc_name, g_MixerData.DeviceInterface)) return;
  699. Mixer_Refresh();
  700. return;
  701. }
  702. return;
  703. }
  704. void Mixer_ControlChange(
  705. WPARAM wParam,
  706. LPARAM lParam )
  707. /*++
  708. Routine Description:
  709. Handles mixer callback control change messages. Watches for changes on the
  710. master volume control and recalculates the last mix values.
  711. --*/
  712. {
  713. LPDWORD pdwVolume;
  714. HMIXER hMixer = (HMIXER)wParam;
  715. DWORD dwControlID = lParam;
  716. if (g_MixerData.hMixer != hMixer) return;
  717. if (dwControlID != g_MixerData.LineData.Control[MMHID_VOLUME_CONTROL].dwControlID) return;
  718. // DPF(1, "WinmmShellMixerControlChange");
  719. //
  720. // get current volume
  721. //
  722. pdwVolume = (DWORD *)LocalAlloc(LPTR, g_MixerData.LineData.MixerLine.cChannels * sizeof (DWORD));
  723. if (!pdwVolume)
  724. return;
  725. if (MMSYSERR_NOERROR == Mixer_GetVolume (&g_MixerData, pdwVolume))
  726. {
  727. // Refresh cache only if the volume values have changed (i.e. they
  728. // were set outside of Mixer_SetVolume()).
  729. if (!g_MixerData.pdwLastVolume || memcmp (g_MixerData.pdwLastVolume, pdwVolume, g_MixerData.LineData.MixerLine.cChannels * sizeof (DWORD)))
  730. RefreshMixCache (&g_MixerData, pdwVolume);
  731. }
  732. LocalFree(pdwVolume);
  733. }
  734. void Mixer_MMDeviceChange( void )
  735. {
  736. Mixer_Refresh();
  737. }