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
19 * VMware is a registered trademark of VMware, Inc.
23 * COPYRIGHT: See COPYING in the top level directory
24 * PROJECT: ReactOS Sound Volume Control
25 * FILE: subsys/system/sndvol32/mixer.c
26 * PROGRAMMERS: Thomas Weidenmueller <w3seek@reactos.com>
30 #define NO_MIXER_SELECTED (~0)
33 ClearMixerCache(PSND_MIXER Mixer
)
35 PSND_MIXER_DESTINATION Line
, NextLine
;
36 PSND_MIXER_CONNECTION Con
, NextCon
;
38 for (Line
= Mixer
->Lines
; Line
!= NULL
; Line
= NextLine
)
40 if (Line
->Controls
!= NULL
)
42 HeapFree(GetProcessHeap(),
47 for (Con
= Line
->Connections
; Con
!= NULL
; Con
= NextCon
)
49 if (Con
->Controls
!= NULL
)
51 HeapFree(GetProcessHeap(),
57 HeapFree(GetProcessHeap(),
62 NextLine
= Line
->Next
;
63 HeapFree(GetProcessHeap(),
71 SndMixerCreate(HWND hWndNotification
)
73 PSND_MIXER Mixer
= HeapAlloc(GetProcessHeap(),
78 Mixer
->hWndNotification
= hWndNotification
;
79 Mixer
->MixersCount
= mixerGetNumDevs();
80 Mixer
->MixerId
= NO_MIXER_SELECTED
;
82 if (Mixer
->MixersCount
> 0)
84 /* select the first mixer by default */
85 SndMixerSelect(Mixer
, 0);
93 SndMixerDestroy(PSND_MIXER Mixer
)
96 HeapFree(GetProcessHeap(),
102 SndMixerClose(PSND_MIXER Mixer
)
104 if (Mixer
->hmx
!= NULL
)
106 mixerClose(Mixer
->hmx
);
108 Mixer
->MixerId
= NO_MIXER_SELECTED
;
113 SndMixerQueryControls(PSND_MIXER Mixer
,
114 LPMIXERLINE LineInfo
,
115 LPMIXERCONTROL
*Controls
)
117 if (LineInfo
->cControls
> 0)
119 *Controls
= 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
= (PVOID
)(*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 DPRINT("Line control: %ws\n", (*Controls
)[j
].szName
);
148 HeapFree(GetProcessHeap(),
152 DPRINT("Failed to get line (ID: 0x%x) controls: %d\n", LineInfo
->dwLineID
, Result
);
157 DPRINT("Failed to allocate memory for %d line (ID: 0x%x) controls!\n", LineInfo
->dwLineID
, LineInfo
->cControls
);
169 SndMixerQueryConnections(PSND_MIXER Mixer
,
170 PSND_MIXER_DESTINATION Line
)
177 LineInfo
.cbStruct
= sizeof(LineInfo
);
178 for (i
= Line
->Info
.cConnections
; i
> 0; i
--)
180 LineInfo
.dwDestination
= Line
->Info
.dwDestination
;
181 LineInfo
.dwSource
= i
- 1;
182 Result
= mixerGetLineInfo((HMIXEROBJ
)Mixer
->hmx
,
184 MIXER_GETLINEINFOF_SOURCE
);
185 if (Result
== MMSYSERR_NOERROR
)
187 LPMIXERCONTROL Controls
;
188 PSND_MIXER_CONNECTION Con
;
190 DPRINT("++ Source: %ws\n", LineInfo
.szName
);
192 if (!SndMixerQueryControls(Mixer
,
196 DPRINT("Failed to query connection controls\n");
201 Con
= HeapAlloc(GetProcessHeap(),
203 sizeof(SND_MIXER_CONNECTION
));
206 Con
->Info
= LineInfo
;
207 Con
->Controls
= Controls
;
208 Con
->Next
= Line
->Connections
;
209 Line
->Connections
= Con
;
213 HeapFree(GetProcessHeap(),
220 DPRINT("Failed to get connection information: %d\n", Result
);
230 SndMixerQueryDestinations(PSND_MIXER Mixer
)
235 for (i
= Mixer
->Caps
.cDestinations
; i
> 0; i
--)
237 PSND_MIXER_DESTINATION Line
;
239 Line
= HeapAlloc(GetProcessHeap(),
241 sizeof(SND_MIXER_DESTINATION
));
244 Line
->Info
.cbStruct
= sizeof(Line
->Info
);
245 Line
->Info
.dwDestination
= i
- 1;
246 if (mixerGetLineInfo((HMIXEROBJ
)Mixer
->hmx
,
248 MIXER_GETLINEINFOF_DESTINATION
) == MMSYSERR_NOERROR
)
250 DPRINT("+ Destination: %ws (%d)\n", Line
->Info
.szName
, Line
->Info
.dwComponentType
);
252 if (!SndMixerQueryConnections(Mixer
, Line
))
254 DPRINT("Failed to query mixer connections!\n");
258 if (!SndMixerQueryControls(Mixer
,
262 DPRINT("Failed to query mixer controls!\n");
267 Line
->Next
= Mixer
->Lines
;
272 DPRINT("Failed to get line information for id %d!\n", i
);
273 HeapFree(GetProcessHeap(),
282 DPRINT("Allocation of SND_MIXER_DEST structure for id %d failed!\n", i
);
292 SndMixerSelect(PSND_MIXER Mixer
,
295 if (MixerId
>= Mixer
->MixersCount
)
300 SndMixerClose(Mixer
);
302 if (mixerOpen(&Mixer
->hmx
,
304 (DWORD_PTR
)Mixer
->hWndNotification
,
306 CALLBACK_WINDOW
| MIXER_OBJECTF_MIXER
) == MMSYSERR_NOERROR
||
307 mixerOpen(&Mixer
->hmx
,
309 (DWORD_PTR
)Mixer
->hWndNotification
,
311 CALLBACK_WINDOW
) == MMSYSERR_NOERROR
||
312 mixerOpen(&Mixer
->hmx
,
316 0) == MMSYSERR_NOERROR
)
318 if (mixerGetDevCaps(MixerId
,
320 sizeof(Mixer
->Caps
)) == MMSYSERR_NOERROR
)
324 Mixer
->MixerId
= MixerId
;
326 ClearMixerCache(Mixer
);
328 Ret
= SndMixerQueryDestinations(Mixer
);
332 ClearMixerCache(Mixer
);
339 mixerClose(Mixer
->hmx
);
344 Mixer
->MixerId
= NO_MIXER_SELECTED
;
349 SndMixerGetSelection(PSND_MIXER Mixer
)
351 return Mixer
->MixerId
;
355 SndMixerGetProductName(PSND_MIXER Mixer
,
361 int lnsz
= lstrlen(Mixer
->Caps
.szPname
);
368 memcpy(lpBuffer
, Mixer
->Caps
.szPname
, lnsz
* sizeof(TCHAR
));
369 lpBuffer
[lnsz
] = _T('\0');
378 SndMixerEnumProducts(PSND_MIXER Mixer
,
379 PFNSNDMIXENUMPRODUCTS EnumProc
,
387 for (i
= 0; i
< Mixer
->MixersCount
; i
++)
389 if (mixerOpen(&hMixer
,
393 0) == MMSYSERR_NOERROR
)
395 if (mixerGetDevCaps(i
,
397 sizeof(Caps
)) == MMSYSERR_NOERROR
)
411 DPRINT("Failed to get device capabilities for mixer id %d!\n", i
);
421 SndMixerGetDestinationCount(PSND_MIXER Mixer
)
423 return (Mixer
->hmx
? Mixer
->Caps
.cDestinations
: -1);
427 SndMixerEnumLines(PSND_MIXER Mixer
,
428 PFNSNDMIXENUMLINES EnumProc
,
433 PSND_MIXER_DESTINATION Line
;
435 for (Line
= Mixer
->Lines
; Line
!= NULL
; Line
= Line
->Next
)
452 SndMixerEnumConnections(PSND_MIXER Mixer
,
454 PFNSNDMIXENUMCONNECTIONS EnumProc
,
459 PSND_MIXER_DESTINATION Line
;
461 for (Line
= Mixer
->Lines
; Line
!= NULL
; Line
= Line
->Next
)
463 if (Line
->Info
.dwLineID
== LineID
)
465 PSND_MIXER_CONNECTION Connection
;
467 for (Connection
= Line
->Connections
; Connection
!= NULL
; Connection
= Connection
->Next
)