572afbee24e47086604b82a9f56444ffeb629459
[reactos.git] / lib / drivers / sound / mmixer / sup.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Kernel Streaming
4 * FILE: lib/drivers/sound/mmixer/sup.c
5 * PURPOSE: Mixer Support Functions
6 * PROGRAMMER: Johannes Anderwald
7 */
8
9
10
11 #include "priv.h"
12
13 const GUID KSNODETYPE_SUM = {0xDA441A60L, 0xC556, 0x11D0, {0x8A, 0x2B, 0x00, 0xA0, 0xC9, 0x25, 0x5A, 0xC1}};
14 const GUID KSNODETYPE_DAC = {0x507AE360L, 0xC554, 0x11D0, {0x8A, 0x2B, 0x00, 0xA0, 0xC9, 0x25, 0x5A, 0xC1}};
15 const GUID KSNODETYPE_ADC = {0x4D837FE0L, 0xC555, 0x11D0, {0x8A, 0x2B, 0x00, 0xA0, 0xC9, 0x25, 0x5A, 0xC1}};
16 const GUID KSNODETYPE_AGC = {0xE88C9BA0L, 0xC557, 0x11D0, {0x8A, 0x2B, 0x00, 0xA0, 0xC9, 0x25, 0x5A, 0xC1}};
17 const GUID KSNODETYPE_LOUDNESS = {0x41887440L, 0xC558, 0x11D0, {0x8A, 0x2B, 0x00, 0xA0, 0xC9, 0x25, 0x5A, 0xC1}};
18 const GUID KSNODETYPE_MUTE = {0x02B223C0L, 0xC557, 0x11D0, {0x8A, 0x2B, 0x00, 0xA0, 0xC9, 0x25, 0x5A, 0xC1}};
19 const GUID KSNODETYPE_TONE = {0x7607E580L, 0xC557, 0x11D0, {0x8A, 0x2B, 0x00, 0xA0, 0xC9, 0x25, 0x5A, 0xC1}};
20 const GUID KSNODETYPE_VOLUME = {0x3A5ACC00L, 0xC557, 0x11D0, {0x8A, 0x2B, 0x00, 0xA0, 0xC9, 0x25, 0x5A, 0xC1}};
21 const GUID KSNODETYPE_PEAKMETER = {0xa085651e, 0x5f0d, 0x4b36, {0xa8, 0x69, 0xd1, 0x95, 0xd6, 0xab, 0x4b, 0x9e}};
22 const GUID KSNODETYPE_MUX = {0x2CEAF780, 0xC556, 0x11D0, {0x8A, 0x2B, 0x00, 0xA0, 0xC9, 0x25, 0x5A, 0xC1}};
23 const GUID KSNODETYPE_STEREO_WIDE = {0xA9E69800L, 0xC558, 0x11D0, {0x8A, 0x2B, 0x00, 0xA0, 0xC9, 0x25, 0x5A, 0xC1}};
24 const GUID KSNODETYPE_CHORUS = {0x20173F20L, 0xC559, 0x11D0, {0x8A, 0x2B, 0x00, 0xA0, 0xC9, 0x25, 0x5A, 0xC1}};
25 const GUID KSNODETYPE_REVERB = {0xEF0328E0L, 0xC558, 0x11D0, {0x8A, 0x2B, 0x00, 0xA0, 0xC9, 0x25, 0x5A, 0xC1}};
26 const GUID KSNODETYPE_SUPERMIX = {0xE573ADC0L, 0xC555, 0x11D0, {0x8A, 0x2B, 0x00, 0xA0, 0xC9, 0x25, 0x5A, 0xC1}};
27
28 const GUID KSPROPSETID_Audio = {0x45FFAAA0L, 0x6E1B, 0x11D0, {0xBC, 0xF2, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}};
29 const GUID KSPROPSETID_Pin = {0x8C134960L, 0x51AD, 0x11CF, {0x87, 0x8A, 0x94, 0xF8, 0x01, 0xC1, 0x00, 0x00}};
30 const GUID KSPROPSETID_General = {0x1464EDA5L, 0x6A8F, 0x11D1, {0x9A, 0xA7, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
31 const GUID KSPROPSETID_Topology = {0x720D4AC0L, 0x7533, 0x11D0, {0xA5, 0xD6, 0x28, 0xDB, 0x04, 0xC1, 0x00, 0x00}};
32 const GUID KSEVENTSETID_AudioControlChange = {0xE85E9698L, 0xFA2F, 0x11D1, {0x95, 0xBD, 0x00, 0xC0, 0x4F, 0xB9, 0x25, 0xD3}};
33
34 MIXER_STATUS
35 MMixerVerifyContext(
36 IN PMIXER_CONTEXT MixerContext)
37 {
38 if (MixerContext->SizeOfStruct != sizeof(MIXER_CONTEXT))
39 return MM_STATUS_INVALID_PARAMETER;
40
41 if (!MixerContext->Alloc || !MixerContext->Control || !MixerContext->Free || !MixerContext->Open ||
42 !MixerContext->AllocEventData || !MixerContext->FreeEventData ||
43 !MixerContext->Close || !MixerContext->OpenKey || !MixerContext->QueryKeyValue || !MixerContext->CloseKey)
44 return MM_STATUS_INVALID_PARAMETER;
45
46 if (!MixerContext->MixerContext)
47 return MM_STATUS_INVALID_PARAMETER;
48
49 return MM_STATUS_SUCCESS;
50 }
51
52 VOID
53 MMixerFreeMixerInfo(
54 IN PMIXER_CONTEXT MixerContext,
55 IN LPMIXER_INFO MixerInfo)
56 {
57 /* UNIMPLEMENTED
58 * FIXME
59 * free all lines
60 */
61
62 MixerContext->Free((PVOID)MixerInfo);
63 }
64
65 LPMIXER_INFO
66 MMixerGetMixerInfoByIndex(
67 IN PMIXER_CONTEXT MixerContext,
68 IN ULONG MixerIndex)
69 {
70 LPMIXER_INFO MixerInfo;
71 PLIST_ENTRY Entry;
72 PMIXER_LIST MixerList;
73 ULONG Index = 0;
74
75 /* get mixer list */
76 MixerList = (PMIXER_LIST)MixerContext->MixerContext;
77
78 if (!MixerList->MixerListCount)
79 return NULL;
80
81 Entry = MixerList->MixerList.Flink;
82
83 while(Entry != &MixerList->MixerList)
84 {
85 MixerInfo = (LPMIXER_INFO)CONTAINING_RECORD(Entry, MIXER_INFO, Entry);
86
87 if (Index == MixerIndex)
88 return MixerInfo;
89
90 /* move to next mixer entry */
91 Index++;
92 Entry = Entry->Flink;
93 }
94
95 return NULL;
96 }
97
98 LPMIXERCONTROL_DATA
99 MMixerGetMixerControlDataById(
100 PLIST_ENTRY ListHead,
101 DWORD dwControlId)
102 {
103 PLIST_ENTRY Entry;
104 LPMIXERCONTROL_DATA Control;
105
106 /* get first entry */
107 Entry = ListHead->Flink;
108
109 while(Entry != ListHead)
110 {
111 Control = (LPMIXERCONTROL_DATA)CONTAINING_RECORD(Entry, MIXERCONTROL_DATA, Entry);
112 DPRINT("dwSource %x dwSource %x\n", Control->dwControlID, dwControlId);
113 if (Control->dwControlID == dwControlId)
114 return Control;
115
116 Entry = Entry->Flink;
117 }
118 return NULL;
119 }
120
121 LPMIXERLINE_EXT
122 MMixerGetSourceMixerLineByLineId(
123 LPMIXER_INFO MixerInfo,
124 DWORD dwLineID)
125 {
126 PLIST_ENTRY Entry;
127 LPMIXERLINE_EXT MixerLineSrc;
128
129 /* get first entry */
130 Entry = MixerInfo->LineList.Flink;
131
132 while(Entry != &MixerInfo->LineList)
133 {
134 MixerLineSrc = (LPMIXERLINE_EXT)CONTAINING_RECORD(Entry, MIXERLINE_EXT, Entry);
135 DPRINT("dwLineID %x dwLineID %x MixerLineSrc %p\n", MixerLineSrc->Line.dwLineID, dwLineID, MixerLineSrc);
136 if (MixerLineSrc->Line.dwLineID == dwLineID)
137 return MixerLineSrc;
138
139 Entry = Entry->Flink;
140 }
141
142 return NULL;
143 }
144
145 LPGUID
146 MMixerGetNodeType(
147 IN PKSMULTIPLE_ITEM MultipleItem,
148 IN ULONG Index)
149 {
150 LPGUID NodeType;
151
152 ASSERT(Index < MultipleItem->Count);
153
154 NodeType = (LPGUID)(MultipleItem + 1);
155 return &NodeType[Index];
156 }
157
158 LPMIXERLINE_EXT
159 MMixerGetSourceMixerLineByComponentType(
160 LPMIXER_INFO MixerInfo,
161 DWORD dwComponentType)
162 {
163 PLIST_ENTRY Entry;
164 LPMIXERLINE_EXT MixerLineSrc;
165
166 /* get first entry */
167 Entry = MixerInfo->LineList.Flink;
168
169 while(Entry != &MixerInfo->LineList)
170 {
171 MixerLineSrc = (LPMIXERLINE_EXT)CONTAINING_RECORD(Entry, MIXERLINE_EXT, Entry);
172 if (MixerLineSrc->Line.dwComponentType == dwComponentType)
173 return MixerLineSrc;
174
175 Entry = Entry->Flink;
176 }
177
178 return NULL;
179 }
180
181 MIXER_STATUS
182 MMixerGetMixerControlById(
183 LPMIXER_INFO MixerInfo,
184 DWORD dwControlID,
185 LPMIXERLINE_EXT *MixerLine,
186 LPMIXERCONTROLW *MixerControl,
187 PULONG NodeId)
188 {
189 PLIST_ENTRY Entry;
190 LPMIXERLINE_EXT MixerLineSrc;
191 ULONG Index;
192
193 /* get first entry */
194 Entry = MixerInfo->LineList.Flink;
195
196 while(Entry != &MixerInfo->LineList)
197 {
198 MixerLineSrc = (LPMIXERLINE_EXT)CONTAINING_RECORD(Entry, MIXERLINE_EXT, Entry);
199
200 for(Index = 0; Index < MixerLineSrc->Line.cControls; Index++)
201 {
202 if (MixerLineSrc->LineControls[Index].dwControlID == dwControlID)
203 {
204 if (MixerLine)
205 *MixerLine = MixerLineSrc;
206 if (MixerControl)
207 *MixerControl = &MixerLineSrc->LineControls[Index];
208 if (NodeId)
209 *NodeId = MixerLineSrc->NodeIds[Index];
210 return MM_STATUS_SUCCESS;
211 }
212 }
213 Entry = Entry->Flink;
214 }
215
216 return MM_STATUS_UNSUCCESSFUL;
217 }
218
219 ULONG
220 MMixerGetVolumeControlIndex(
221 LPMIXERVOLUME_DATA VolumeData,
222 LONG Value)
223 {
224 ULONG Index;
225
226 for(Index = 0; Index < VolumeData->ValuesCount; Index++)
227 {
228 if (VolumeData->Values[Index] > Value)
229 {
230 return VolumeData->InputSteppingDelta * Index;
231 }
232 }
233 return VolumeData->InputSteppingDelta * (VolumeData->ValuesCount-1);
234 }
235
236 VOID
237 MMixerNotifyControlChange(
238 IN PMIXER_CONTEXT MixerContext,
239 IN LPMIXER_INFO MixerInfo,
240 IN ULONG NotificationType,
241 IN ULONG Value)
242 {
243 PLIST_ENTRY Entry;
244 PEVENT_NOTIFICATION_ENTRY NotificationEntry;
245
246 /* enumerate list and add a notification entry */
247 Entry = MixerInfo->LineList.Flink;
248 while(Entry != &MixerInfo->EventList)
249 {
250 /* get notification entry offset */
251 NotificationEntry = (PEVENT_NOTIFICATION_ENTRY)CONTAINING_RECORD(Entry, EVENT_NOTIFICATION_ENTRY, Entry);
252
253 if (NotificationEntry->MixerEventRoutine)
254 {
255 /* now perform the callback */
256 NotificationEntry->MixerEventRoutine(NotificationEntry->MixerEventContext, (HANDLE)MixerInfo, NotificationType, Value);
257 }
258
259 /* move to next notification entry */
260 Entry = Entry->Flink;
261 }
262 }
263
264 MIXER_STATUS
265 MMixerSetGetMuteControlDetails(
266 IN PMIXER_CONTEXT MixerContext,
267 IN LPMIXER_INFO MixerInfo,
268 IN ULONG NodeId,
269 IN ULONG dwLineID,
270 IN LPMIXERCONTROLDETAILS MixerControlDetails,
271 IN ULONG bSet)
272 {
273 LPMIXERCONTROLDETAILS_BOOLEAN Input;
274 LONG Value;
275 MIXER_STATUS Status;
276
277 if (MixerControlDetails->cbDetails != sizeof(MIXERCONTROLDETAILS_BOOLEAN))
278 return MM_STATUS_INVALID_PARAMETER;
279
280 /* get input */
281 Input = (LPMIXERCONTROLDETAILS_BOOLEAN)MixerControlDetails->paDetails;
282
283 /* FIXME SEH */
284 if (bSet)
285 Value = Input->fValue;
286
287 /* set control details */
288 Status = MMixerSetGetControlDetails(MixerContext, MixerInfo->hMixer, NodeId, bSet, KSPROPERTY_AUDIO_MUTE, 0, &Value);
289
290 if (Status != MM_STATUS_SUCCESS)
291 return Status;
292
293 /* FIXME SEH */
294 if (!bSet)
295 {
296 Input->fValue = Value;
297 return Status;
298 }
299 else
300 {
301 /* notify wdmaud clients MM_MIXM_LINE_CHANGE dwLineID */
302 MMixerNotifyControlChange(MixerContext, MixerInfo, MM_MIXM_LINE_CHANGE, dwLineID);
303 }
304
305 return Status;
306 }
307
308 MIXER_STATUS
309 MMixerSetGetVolumeControlDetails(
310 IN PMIXER_CONTEXT MixerContext,
311 IN LPMIXER_INFO MixerInfo,
312 IN ULONG NodeId,
313 IN ULONG bSet,
314 LPMIXERCONTROLW MixerControl,
315 IN LPMIXERCONTROLDETAILS MixerControlDetails,
316 LPMIXERLINE_EXT MixerLine)
317 {
318 LPMIXERCONTROLDETAILS_UNSIGNED Input;
319 LONG Value, Index, Channel = 0;
320 ULONG dwValue;
321 MIXER_STATUS Status;
322 LPMIXERVOLUME_DATA VolumeData;
323
324 if (MixerControlDetails->cbDetails != sizeof(MIXERCONTROLDETAILS_SIGNED))
325 return MM_STATUS_INVALID_PARAMETER;
326
327 VolumeData = (LPMIXERVOLUME_DATA)MMixerGetMixerControlDataById(&MixerLine->LineControlsExtraData, MixerControl->dwControlID);
328 if (!VolumeData)
329 return MM_STATUS_UNSUCCESSFUL;
330
331 /* get input */
332 Input = (LPMIXERCONTROLDETAILS_UNSIGNED)MixerControlDetails->paDetails;
333
334 if (bSet)
335 {
336 /* FIXME SEH */
337 Value = Input->dwValue;
338 Index = Value / VolumeData->InputSteppingDelta;
339
340 if (Index >= VolumeData->ValuesCount)
341 {
342 DPRINT1("Index %u out of bounds %u \n", Index, VolumeData->ValuesCount);
343 return MM_STATUS_INVALID_PARAMETER;
344 }
345
346 Value = VolumeData->Values[Index];
347 }
348
349 /* set control details */
350 if (bSet)
351 {
352 /* TODO */
353 Status = MMixerSetGetControlDetails(MixerContext, MixerInfo->hMixer, NodeId, bSet, KSPROPERTY_AUDIO_VOLUMELEVEL, 0, &Value);
354 Status = MMixerSetGetControlDetails(MixerContext, MixerInfo->hMixer, NodeId, bSet, KSPROPERTY_AUDIO_VOLUMELEVEL, 1, &Value);
355 }
356 else
357 {
358 Status = MMixerSetGetControlDetails(MixerContext, MixerInfo->hMixer, NodeId, bSet, KSPROPERTY_AUDIO_VOLUMELEVEL, Channel, &Value);
359 }
360
361 if (!bSet)
362 {
363 dwValue = MMixerGetVolumeControlIndex(VolumeData, (LONG)Value);
364 /* FIXME SEH */
365 Input->dwValue = dwValue;
366 }
367 else
368 {
369 /* notify clients of a line change MM_MIXM_CONTROL_CHANGE with MixerControl->dwControlID */
370 MMixerNotifyControlChange(MixerContext, MixerInfo, MM_MIXM_CONTROL_CHANGE, MixerControl->dwControlID);
371 }
372 return Status;
373 }
374
375 LPMIXER_DATA
376 MMixerGetDataByDeviceId(
377 IN PMIXER_LIST MixerList,
378 IN ULONG DeviceId)
379 {
380 PLIST_ENTRY Entry;
381 LPMIXER_DATA MixerData;
382
383 Entry = MixerList->MixerData.Flink;
384 while(Entry != &MixerList->MixerData)
385 {
386 MixerData = (LPMIXER_DATA)CONTAINING_RECORD(Entry, MIXER_DATA, Entry);
387 if (MixerData->DeviceId == DeviceId)
388 {
389 return MixerData;
390 }
391 Entry = Entry->Flink;
392 }
393 return NULL;
394 }
395
396 LPMIXER_DATA
397 MMixerGetDataByDeviceName(
398 IN PMIXER_LIST MixerList,
399 IN LPWSTR DeviceName)
400 {
401 PLIST_ENTRY Entry;
402 LPMIXER_DATA MixerData;
403
404 Entry = MixerList->MixerData.Flink;
405 while(Entry != &MixerList->MixerData)
406 {
407 MixerData = (LPMIXER_DATA)CONTAINING_RECORD(Entry, MIXER_DATA, Entry);
408 if (wcsicmp(&DeviceName[2], &MixerData->DeviceName[2]) == 0)
409 {
410 /* found entry */
411 return MixerData;
412 }
413 Entry = Entry->Flink;
414 }
415 return NULL;
416 }
417
418 MIXER_STATUS
419 MMixerCreateMixerData(
420 IN PMIXER_CONTEXT MixerContext,
421 IN PMIXER_LIST MixerList,
422 IN ULONG DeviceId,
423 IN LPWSTR DeviceName,
424 IN HANDLE hDevice,
425 IN HANDLE hKey)
426 {
427 LPMIXER_DATA MixerData;
428
429 MixerData = (LPMIXER_DATA)MixerContext->Alloc(sizeof(MIXER_DATA));
430 if (!MixerData)
431 return MM_STATUS_NO_MEMORY;
432
433 MixerData->DeviceId = DeviceId;
434 MixerData->DeviceName = DeviceName;
435 MixerData->hDevice = hDevice;
436 MixerData->hDeviceInterfaceKey = hKey;
437 MixerData->Topology = NULL;
438
439 InsertTailList(&MixerList->MixerData, &MixerData->Entry);
440 MixerList->MixerDataCount++;
441 return MM_STATUS_SUCCESS;
442 }
443
444 MIXER_STATUS
445 MMixerGetDeviceName(
446 IN PMIXER_CONTEXT MixerContext,
447 IN LPMIXER_INFO MixerInfo,
448 IN HANDLE hKey)
449 {
450 LPWSTR Name;
451 HANDLE hTemp;
452 ULONG Length;
453 ULONG Type;
454 MIXER_STATUS Status;
455
456 Status = MixerContext->QueryKeyValue(hKey, L"FriendlyName", (PVOID*)&Name, &Length, &Type);
457 if (Status == MM_STATUS_SUCCESS)
458 {
459 /* copy device name */
460 MixerContext->Copy(MixerInfo->MixCaps.szPname, Name, min(wcslen(Name), MAXPNAMELEN-1) * sizeof(WCHAR));
461
462 /* make sure its null terminated */
463 MixerInfo->MixCaps.szPname[MAXPNAMELEN-1] = L'\0';
464
465 /* free device name */
466 MixerContext->Free(Name);
467
468 /* done */
469 return Status;
470 }
471
472 Status = MixerContext->OpenKey(hKey, L"Device Parameters", KEY_READ, &hTemp);
473 if (Status != MM_STATUS_SUCCESS)
474 return Status;
475
476 Status = MixerContext->QueryKeyValue(hKey, L"FriendlyName", (PVOID*)&Name, &Length, &Type);
477 if (Status == MM_STATUS_SUCCESS)
478 {
479 /* copy device name */
480 MixerContext->Copy(MixerInfo->MixCaps.szPname, Name, min(wcslen(Name), MAXPNAMELEN-1) * sizeof(WCHAR));
481
482 /* make sure its null terminated */
483 MixerInfo->MixCaps.szPname[MAXPNAMELEN-1] = L'\0';
484
485 /* free device name */
486 MixerContext->Free(Name);
487 }
488
489 MixerContext->CloseKey(hTemp);
490 return Status;
491 }