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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 * COPYRIGHT: See COPYING in the top level directory
22 * PROJECT: ReactOS Sound Volume Control
23 * FILE: subsys/system/sndvol32/mixer.c
24 * 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
)
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
, 0);
91 SndMixerDestroy(PSND_MIXER Mixer
)
94 HeapFree(GetProcessHeap(),
100 SndMixerClose(PSND_MIXER Mixer
)
102 if (Mixer
->hmx
!= NULL
)
104 mixerClose(Mixer
->hmx
);
106 Mixer
->MixerId
= NO_MIXER_SELECTED
;
111 SndMixerQueryControls(PSND_MIXER Mixer
,
112 PUINT DisplayControls
,
113 LPMIXERLINE LineInfo
,
114 LPMIXERCONTROL
*Controls
)
116 if (LineInfo
->cControls
> 0)
118 *Controls
= (MIXERCONTROL
*) HeapAlloc(GetProcessHeap(),
120 LineInfo
->cControls
* sizeof(MIXERCONTROL
));
121 if (*Controls
!= NULL
)
123 MIXERLINECONTROLS LineControls
;
127 LineControls
.cbStruct
= sizeof(LineControls
);
128 LineControls
.dwLineID
= LineInfo
->dwLineID
;
129 LineControls
.cControls
= LineInfo
->cControls
;
130 LineControls
.cbmxctrl
= sizeof(MIXERCONTROL
);
131 LineControls
.pamxctrl
= (MIXERCONTROL
*)(*Controls
);
133 Result
= mixerGetLineControls((HMIXEROBJ
)Mixer
->hmx
,
135 MIXER_GETLINECONTROLSF_ALL
);
136 if (Result
== MMSYSERR_NOERROR
)
138 for (j
= 0; j
< LineControls
.cControls
; j
++)
140 if (SndMixerIsDisplayControl(Mixer
,
143 (*DisplayControls
)++;
146 DPRINT("Line control: %ws (0x%x, 0x%x)\n", (*Controls
)[j
].szName
, (*Controls
)[j
].fdwControl
, (*Controls
)[j
].dwControlType
);
153 HeapFree(GetProcessHeap(),
157 DPRINT("Failed to get line (ID: 0x%x) controls: %d\n", LineInfo
->dwLineID
, Result
);
162 DPRINT("Failed to allocate memory for %d line (ID: 0x%x) controls!\n", LineInfo
->dwLineID
, LineInfo
->cControls
);
174 SndMixerQueryConnections(PSND_MIXER Mixer
,
175 PSND_MIXER_DESTINATION Line
)
177 UINT i
, DispControls
;
182 LineInfo
.cbStruct
= sizeof(LineInfo
);
183 for (i
= Line
->Info
.cConnections
; i
> 0; i
--)
185 LineInfo
.dwDestination
= Line
->Info
.dwDestination
;
186 LineInfo
.dwSource
= i
- 1;
187 Result
= mixerGetLineInfo((HMIXEROBJ
)Mixer
->hmx
,
189 MIXER_GETLINEINFOF_SOURCE
);
190 if (Result
== MMSYSERR_NOERROR
)
192 LPMIXERCONTROL Controls
;
193 PSND_MIXER_CONNECTION Con
;
195 DPRINT("++ Source: %ws\n", LineInfo
.szName
);
199 if (!SndMixerQueryControls(Mixer
,
204 DPRINT("Failed to query connection controls\n");
209 Con
= (SND_MIXER_CONNECTION
*) HeapAlloc(GetProcessHeap(),
211 sizeof(SND_MIXER_CONNECTION
));
214 Con
->Info
= LineInfo
;
215 Con
->Controls
= Controls
;
216 Con
->DisplayControls
= DispControls
;
217 Con
->Next
= Line
->Connections
;
218 Line
->Connections
= Con
;
222 HeapFree(GetProcessHeap(),
229 DPRINT("Failed to get connection information: %d\n", Result
);
239 SndMixerQueryDestinations(PSND_MIXER Mixer
)
244 for (i
= Mixer
->Caps
.cDestinations
; i
> 0; i
--)
246 PSND_MIXER_DESTINATION Line
;
248 Line
= (SND_MIXER_DESTINATION
*) HeapAlloc(GetProcessHeap(),
250 sizeof(SND_MIXER_DESTINATION
));
253 Line
->Info
.cbStruct
= sizeof(Line
->Info
);
254 Line
->Info
.dwDestination
= i
- 1;
255 if (mixerGetLineInfo((HMIXEROBJ
)Mixer
->hmx
,
257 MIXER_GETLINEINFOF_DESTINATION
) == MMSYSERR_NOERROR
)
259 DPRINT("+ Destination: %ws (0x%x, %d)\n", Line
->Info
.szName
, Line
->Info
.dwLineID
, Line
->Info
.dwComponentType
);
261 if (!SndMixerQueryControls(Mixer
,
262 &Line
->DisplayControls
,
266 DPRINT("Failed to query mixer controls!\n");
271 if (!SndMixerQueryConnections(Mixer
, Line
))
273 DPRINT("Failed to query mixer connections!\n");
278 Line
->Next
= Mixer
->Lines
;
283 DPRINT("Failed to get line information for id %d!\n", i
);
284 HeapFree(GetProcessHeap(),
293 DPRINT("Allocation of SND_MIXER_DEST structure for id %d failed!\n", i
);
303 SndMixerSelect(PSND_MIXER Mixer
,
306 if (MixerId
>= Mixer
->MixersCount
)
311 SndMixerClose(Mixer
);
313 if (mixerOpen(&Mixer
->hmx
,
315 (DWORD_PTR
)Mixer
->hWndNotification
,
317 CALLBACK_WINDOW
| MIXER_OBJECTF_MIXER
) == MMSYSERR_NOERROR
||
318 mixerOpen(&Mixer
->hmx
,
320 (DWORD_PTR
)Mixer
->hWndNotification
,
322 CALLBACK_WINDOW
) == MMSYSERR_NOERROR
||
323 mixerOpen(&Mixer
->hmx
,
327 0) == MMSYSERR_NOERROR
)
329 if (mixerGetDevCaps(MixerId
,
331 sizeof(Mixer
->Caps
)) == MMSYSERR_NOERROR
)
335 Mixer
->MixerId
= MixerId
;
337 ClearMixerCache(Mixer
);
339 Ret
= SndMixerQueryDestinations(Mixer
);
343 ClearMixerCache(Mixer
);
350 mixerClose(Mixer
->hmx
);
355 Mixer
->MixerId
= NO_MIXER_SELECTED
;
360 SndMixerGetSelection(PSND_MIXER Mixer
)
362 return Mixer
->MixerId
;
366 SndMixerGetProductName(PSND_MIXER Mixer
,
372 UINT lnsz
= (UINT
) lstrlen(Mixer
->Caps
.szPname
);
379 memcpy(lpBuffer
, Mixer
->Caps
.szPname
, lnsz
* sizeof(TCHAR
));
380 lpBuffer
[lnsz
] = _T('\0');
389 SndMixerGetLineName(PSND_MIXER Mixer
,
398 PSND_MIXER_DESTINATION Line
;
399 LPMIXERLINE lpl
= NULL
;
401 for (Line
= Mixer
->Lines
; Line
!= NULL
; Line
= Line
->Next
)
403 if (Line
->Info
.dwLineID
== LineID
)
412 lnsz
= (UINT
) lstrlen(LongName
? lpl
->szName
: lpl
->szShortName
);
419 memcpy(lpBuffer
, LongName
? lpl
->szName
: lpl
->szShortName
, lnsz
* sizeof(TCHAR
));
420 lpBuffer
[lnsz
] = _T('\0');
430 SndMixerEnumProducts(PSND_MIXER Mixer
,
431 PFNSNDMIXENUMPRODUCTS EnumProc
,
439 for (i
= 0; i
< Mixer
->MixersCount
; i
++)
441 if (mixerOpen(&hMixer
,
445 0) == MMSYSERR_NOERROR
)
447 if (mixerGetDevCaps(i
,
449 sizeof(Caps
)) == MMSYSERR_NOERROR
)
463 DPRINT("Failed to get device capabilities for mixer id %d!\n", i
);
473 SndMixerGetDestinationCount(PSND_MIXER Mixer
)
475 return (Mixer
->hmx
? Mixer
->Caps
.cDestinations
: -1);
479 SndMixerEnumLines(PSND_MIXER Mixer
,
480 PFNSNDMIXENUMLINES EnumProc
,
485 PSND_MIXER_DESTINATION Line
;
487 for (Line
= Mixer
->Lines
; Line
!= NULL
; Line
= Line
->Next
)
491 Line
->DisplayControls
,
505 SndMixerEnumConnections(PSND_MIXER Mixer
,
507 PFNSNDMIXENUMCONNECTIONS EnumProc
,
512 PSND_MIXER_DESTINATION Line
;
514 for (Line
= Mixer
->Lines
; Line
!= NULL
; Line
= Line
->Next
)
516 if (Line
->Info
.dwLineID
== LineID
)
518 PSND_MIXER_CONNECTION Connection
;
520 if (Line
->DisplayControls
!= 0)
531 for (Connection
= Line
->Connections
; Connection
!= NULL
; Connection
= Connection
->Next
)
551 SndMixerIsDisplayControl(PSND_MIXER Mixer
,
552 LPMIXERCONTROL Control
)
554 if (Mixer
->hmx
&& !(Control
->fdwControl
& MIXERCONTROL_CONTROLF_DISABLED
))
556 switch (Control
->dwControlType
& MIXERCONTROL_CT_CLASS_MASK
)
558 case MIXERCONTROL_CT_CLASS_FADER
:
559 case MIXERCONTROL_CT_CLASS_SWITCH
: