2 * ReactOS Sound Volume Control
3 * Copyright (C) 2004-2005 Thomas Weidenmueller
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 * COPYRIGHT: See COPYING in the top level directory
21 * PROJECT: ReactOS Sound Volume Control
22 * FILE: base/applications/sndvol32/mixer.c
23 * PROGRAMMERS: Thomas Weidenmueller <w3seek@reactos.com>
28 #define NO_MIXER_SELECTED ((UINT)(~0))
31 ClearMixerCache(PSND_MIXER Mixer
)
33 PSND_MIXER_DESTINATION Line
, NextLine
;
34 PSND_MIXER_CONNECTION Con
, NextCon
;
36 for (Line
= Mixer
->Lines
; Line
!= NULL
; Line
= NextLine
)
38 if (Line
->Controls
!= NULL
)
40 HeapFree(GetProcessHeap(),
45 for (Con
= Line
->Connections
; Con
!= NULL
; Con
= NextCon
)
47 if (Con
->Controls
!= NULL
)
49 HeapFree(GetProcessHeap(),
55 HeapFree(GetProcessHeap(),
60 NextLine
= Line
->Next
;
61 HeapFree(GetProcessHeap(),
69 SndMixerCreate(HWND hWndNotification
, UINT MixerId
)
71 PSND_MIXER Mixer
= (PSND_MIXER
) HeapAlloc(GetProcessHeap(),
76 Mixer
->hWndNotification
= hWndNotification
;
77 Mixer
->MixersCount
= mixerGetNumDevs();
78 Mixer
->MixerId
= NO_MIXER_SELECTED
;
80 if (Mixer
->MixersCount
> 0)
82 /* select the first mixer by default */
83 SndMixerSelect(Mixer
, MixerId
);
91 SndMixerDestroy(PSND_MIXER Mixer
)
93 ClearMixerCache(Mixer
);
95 HeapFree(GetProcessHeap(),
101 SndMixerClose(PSND_MIXER Mixer
)
103 if (Mixer
->hmx
!= NULL
)
105 mixerClose(Mixer
->hmx
);
107 Mixer
->MixerId
= NO_MIXER_SELECTED
;
112 SndMixerQueryControls(PSND_MIXER Mixer
,
113 PUINT DisplayControls
,
114 LPMIXERLINE LineInfo
,
115 LPMIXERCONTROL
*Controls
)
117 if (LineInfo
->cControls
> 0)
119 *Controls
= (MIXERCONTROL
*) HeapAlloc(GetProcessHeap(),
121 LineInfo
->cControls
* sizeof(MIXERCONTROL
));
122 if (*Controls
!= NULL
)
124 MIXERLINECONTROLS LineControls
;
128 LineControls
.cbStruct
= sizeof(LineControls
);
129 LineControls
.dwLineID
= LineInfo
->dwLineID
;
130 LineControls
.cControls
= LineInfo
->cControls
;
131 LineControls
.cbmxctrl
= sizeof(MIXERCONTROL
);
132 LineControls
.pamxctrl
= (MIXERCONTROL
*)(*Controls
);
134 Result
= mixerGetLineControls((HMIXEROBJ
)Mixer
->hmx
,
136 MIXER_GETLINECONTROLSF_ALL
);
137 if (Result
== MMSYSERR_NOERROR
)
139 for (j
= 0; j
< LineControls
.cControls
; j
++)
141 if (SndMixerIsDisplayControl(Mixer
,
144 (*DisplayControls
)++;
147 DPRINT("Line control: %ws (0x%x, 0x%x)\n", (*Controls
)[j
].szName
, (*Controls
)[j
].fdwControl
, (*Controls
)[j
].dwControlType
);
154 HeapFree(GetProcessHeap(),
158 DPRINT("Failed to get line (ID: 0x%x) controls: %d\n", LineInfo
->dwLineID
, Result
);
163 DPRINT("Failed to allocate memory for %d line (ID: 0x%x) controls!\n", LineInfo
->dwLineID
, LineInfo
->cControls
);
175 SndMixerQueryConnections(PSND_MIXER Mixer
,
176 PSND_MIXER_DESTINATION Line
)
178 UINT i
, DispControls
;
183 LineInfo
.cbStruct
= sizeof(LineInfo
);
184 for (i
= Line
->Info
.cConnections
; i
> 0; i
--)
186 LineInfo
.dwDestination
= Line
->Info
.dwDestination
;
187 LineInfo
.dwSource
= i
- 1;
188 Result
= mixerGetLineInfo((HMIXEROBJ
)Mixer
->hmx
,
190 MIXER_GETLINEINFOF_SOURCE
);
191 if (Result
== MMSYSERR_NOERROR
)
193 LPMIXERCONTROL Controls
= NULL
;
194 PSND_MIXER_CONNECTION Con
;
196 DPRINT("++ Source: %ws\n", LineInfo
.szName
);
200 if (!SndMixerQueryControls(Mixer
,
205 DPRINT("Failed to query connection controls\n");
210 Con
= (SND_MIXER_CONNECTION
*) HeapAlloc(GetProcessHeap(),
212 sizeof(SND_MIXER_CONNECTION
));
215 Con
->Info
= LineInfo
;
216 Con
->Controls
= Controls
;
217 Con
->DisplayControls
= DispControls
;
218 Con
->Next
= Line
->Connections
;
219 Line
->Connections
= Con
;
223 HeapFree(GetProcessHeap(),
230 DPRINT("Failed to get connection information: %d\n", Result
);
240 SndMixerQueryDestinations(PSND_MIXER Mixer
)
245 for (i
= Mixer
->Caps
.cDestinations
; i
> 0; i
--)
247 PSND_MIXER_DESTINATION Line
;
249 Line
= (SND_MIXER_DESTINATION
*) HeapAlloc(GetProcessHeap(),
251 sizeof(SND_MIXER_DESTINATION
));
254 Line
->Info
.cbStruct
= sizeof(Line
->Info
);
255 Line
->Info
.dwDestination
= i
- 1;
256 if (mixerGetLineInfo((HMIXEROBJ
)Mixer
->hmx
,
258 MIXER_GETLINEINFOF_DESTINATION
) == MMSYSERR_NOERROR
)
260 DPRINT("+ Destination: %ws (0x%x, %d)\n", Line
->Info
.szName
, Line
->Info
.dwLineID
, Line
->Info
.dwComponentType
);
262 if (!SndMixerQueryControls(Mixer
,
263 &Line
->DisplayControls
,
267 DPRINT("Failed to query mixer controls!\n");
272 if (!SndMixerQueryConnections(Mixer
, Line
))
274 DPRINT("Failed to query mixer connections!\n");
279 Line
->Next
= Mixer
->Lines
;
284 DPRINT("Failed to get line information for id %d!\n", i
);
285 HeapFree(GetProcessHeap(),
294 DPRINT("Allocation of SND_MIXER_DEST structure for id %d failed!\n", i
);
304 SndMixerSelect(PSND_MIXER Mixer
,
307 if (MixerId
>= Mixer
->MixersCount
)
312 SndMixerClose(Mixer
);
314 if (mixerOpen(&Mixer
->hmx
,
316 (DWORD_PTR
)Mixer
->hWndNotification
,
318 CALLBACK_WINDOW
| MIXER_OBJECTF_MIXER
) == MMSYSERR_NOERROR
||
319 mixerOpen(&Mixer
->hmx
,
321 (DWORD_PTR
)Mixer
->hWndNotification
,
323 CALLBACK_WINDOW
) == MMSYSERR_NOERROR
||
324 mixerOpen(&Mixer
->hmx
,
328 0) == MMSYSERR_NOERROR
)
330 if (mixerGetDevCaps(MixerId
,
332 sizeof(Mixer
->Caps
)) == MMSYSERR_NOERROR
)
336 Mixer
->MixerId
= MixerId
;
338 ClearMixerCache(Mixer
);
340 Ret
= SndMixerQueryDestinations(Mixer
);
344 ClearMixerCache(Mixer
);
351 mixerClose(Mixer
->hmx
);
356 Mixer
->MixerId
= NO_MIXER_SELECTED
;
361 SndMixerGetSelection(PSND_MIXER Mixer
)
363 return Mixer
->MixerId
;
367 SndMixerGetProductName(PSND_MIXER Mixer
,
373 UINT lnsz
= (UINT
) lstrlen(Mixer
->Caps
.szPname
);
380 memcpy(lpBuffer
, Mixer
->Caps
.szPname
, lnsz
* sizeof(TCHAR
));
381 lpBuffer
[lnsz
] = _T('\0');
390 SndMixerGetLineName(PSND_MIXER Mixer
,
399 PSND_MIXER_DESTINATION Line
;
400 LPMIXERLINE lpl
= NULL
;
402 for (Line
= Mixer
->Lines
; Line
!= NULL
; Line
= Line
->Next
)
404 if (Line
->Info
.dwLineID
== LineID
)
413 lnsz
= (UINT
) lstrlen(LongName
? lpl
->szName
: lpl
->szShortName
);
420 memcpy(lpBuffer
, LongName
? lpl
->szName
: lpl
->szShortName
, lnsz
* sizeof(TCHAR
));
421 lpBuffer
[lnsz
] = _T('\0');
431 SndMixerEnumProducts(PSND_MIXER Mixer
,
432 PFNSNDMIXENUMPRODUCTS EnumProc
,
440 for (i
= 0; i
< Mixer
->MixersCount
; i
++)
442 if (mixerOpen(&hMixer
,
446 0) == MMSYSERR_NOERROR
)
448 if (mixerGetDevCaps(i
,
450 sizeof(Caps
)) == MMSYSERR_NOERROR
)
464 DPRINT("Failed to get device capabilities for mixer id %d!\n", i
);
474 SndMixerSetVolumeControlDetails(PSND_MIXER Mixer
, DWORD dwControlID
, DWORD cbDetails
, LPVOID paDetails
)
476 MIXERCONTROLDETAILS MixerDetails
;
480 MixerDetails
.cbStruct
= sizeof(MIXERCONTROLDETAILS
);
481 MixerDetails
.dwControlID
= dwControlID
;
482 MixerDetails
.cChannels
= 1; //FIXME
483 MixerDetails
.cMultipleItems
= 0;
484 MixerDetails
.cbDetails
= cbDetails
;
485 MixerDetails
.paDetails
= paDetails
;
487 if (mixerSetControlDetails((HMIXEROBJ
)Mixer
->hmx
, &MixerDetails
, MIXER_GETCONTROLDETAILSF_VALUE
| MIXER_OBJECTF_HMIXER
) == MMSYSERR_NOERROR
)
498 SndMixerGetVolumeControlDetails(PSND_MIXER Mixer
, DWORD dwControlID
, DWORD cbDetails
, LPVOID paDetails
)
500 MIXERCONTROLDETAILS MixerDetails
;
504 MixerDetails
.cbStruct
= sizeof(MIXERCONTROLDETAILS
);
505 MixerDetails
.dwControlID
= dwControlID
;
506 MixerDetails
.cChannels
= 1; //FIXME
507 MixerDetails
.cMultipleItems
= 0;
508 MixerDetails
.cbDetails
= cbDetails
;
509 MixerDetails
.paDetails
= paDetails
;
511 if (mixerGetControlDetails((HMIXEROBJ
)Mixer
->hmx
, &MixerDetails
, MIXER_GETCONTROLDETAILSF_VALUE
| MIXER_OBJECTF_HMIXER
) == MMSYSERR_NOERROR
)
520 SndMixerGetDestinationCount(PSND_MIXER Mixer
)
522 return (Mixer
->hmx
? (INT
)Mixer
->Caps
.cDestinations
: -1);
526 SndMixerEnumLines(PSND_MIXER Mixer
,
527 PFNSNDMIXENUMLINES EnumProc
,
532 PSND_MIXER_DESTINATION Line
;
534 for (Line
= Mixer
->Lines
; Line
!= NULL
; Line
= Line
->Next
)
538 Line
->DisplayControls
,
552 SndMixerEnumConnections(PSND_MIXER Mixer
,
554 PFNSNDMIXENUMCONNECTIONS EnumProc
,
559 PSND_MIXER_DESTINATION Line
;
561 for (Line
= Mixer
->Lines
; Line
!= NULL
; Line
= Line
->Next
)
563 if (Line
->Info
.dwLineID
== LineID
)
565 PSND_MIXER_CONNECTION Connection
;
567 if (Line
->DisplayControls
!= 0)
578 for (Connection
= Line
->Connections
; Connection
!= NULL
; Connection
= Connection
->Next
)
598 SndMixerIsDisplayControl(PSND_MIXER Mixer
,
599 LPMIXERCONTROL Control
)
601 if (Mixer
->hmx
&& !(Control
->fdwControl
& MIXERCONTROL_CONTROLF_DISABLED
))
603 switch (Control
->dwControlType
& MIXERCONTROL_CT_CLASS_MASK
)
605 case MIXERCONTROL_CT_CLASS_FADER
:
606 case MIXERCONTROL_CT_CLASS_SWITCH
: