[CMAKE]
[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 DbgBreakPoint();
344 return MM_STATUS_INVALID_PARAMETER;
345 }
346
347 Value = VolumeData->Values[Index];
348 }
349
350 /* set control details */
351 if (bSet)
352 {
353 /* TODO */
354 Status = MMixerSetGetControlDetails(MixerContext, MixerInfo->hMixer, NodeId, bSet, KSPROPERTY_AUDIO_VOLUMELEVEL, 0, &Value);
355 Status = MMixerSetGetControlDetails(MixerContext, MixerInfo->hMixer, NodeId, bSet, KSPROPERTY_AUDIO_VOLUMELEVEL, 1, &Value);
356 }
357 else
358 {
359 Status = MMixerSetGetControlDetails(MixerContext, MixerInfo->hMixer, NodeId, bSet, KSPROPERTY_AUDIO_VOLUMELEVEL, Channel, &Value);
360 }
361
362 if (!bSet)
363 {
364 dwValue = MMixerGetVolumeControlIndex(VolumeData, (LONG)Value);
365 /* FIXME SEH */
366 Input->dwValue = dwValue;
367 }
368 else
369 {
370 /* notify clients of a line change MM_MIXM_CONTROL_CHANGE with MixerControl->dwControlID */
371 MMixerNotifyControlChange(MixerContext, MixerInfo, MM_MIXM_CONTROL_CHANGE, MixerControl->dwControlID);
372 }
373 return Status;
374 }
375
376 LPMIXER_DATA
377 MMixerGetDataByDeviceId(
378 IN PMIXER_LIST MixerList,
379 IN ULONG DeviceId)
380 {
381 PLIST_ENTRY Entry;
382 LPMIXER_DATA MixerData;
383
384 Entry = MixerList->MixerData.Flink;
385 while(Entry != &MixerList->MixerData)
386 {
387 MixerData = (LPMIXER_DATA)CONTAINING_RECORD(Entry, MIXER_DATA, Entry);
388 if (MixerData->DeviceId == DeviceId)
389 {
390 return MixerData;
391 }
392 Entry = Entry->Flink;
393 }
394 return NULL;
395 }
396
397 LPMIXER_DATA
398 MMixerGetDataByDeviceName(
399 IN PMIXER_LIST MixerList,
400 IN LPWSTR DeviceName)
401 {
402 PLIST_ENTRY Entry;
403 LPMIXER_DATA MixerData;
404
405 Entry = MixerList->MixerData.Flink;
406 while(Entry != &MixerList->MixerData)
407 {
408 MixerData = (LPMIXER_DATA)CONTAINING_RECORD(Entry, MIXER_DATA, Entry);
409 if (wcsicmp(&DeviceName[2], &MixerData->DeviceName[2]) == 0)
410 {
411 /* found entry */
412 return MixerData;
413 }
414 Entry = Entry->Flink;
415 }
416 return NULL;
417 }
418
419 MIXER_STATUS
420 MMixerCreateMixerData(
421 IN PMIXER_CONTEXT MixerContext,
422 IN PMIXER_LIST MixerList,
423 IN ULONG DeviceId,
424 IN LPWSTR DeviceName,
425 IN HANDLE hDevice,
426 IN HANDLE hKey)
427 {
428 LPMIXER_DATA MixerData;
429
430 MixerData = (LPMIXER_DATA)MixerContext->Alloc(sizeof(MIXER_DATA));
431 if (!MixerData)
432 return MM_STATUS_NO_MEMORY;
433
434 MixerData->DeviceId = DeviceId;
435 MixerData->DeviceName = DeviceName;
436 MixerData->hDevice = hDevice;
437 MixerData->hDeviceInterfaceKey = hKey;
438 MixerData->Topology = NULL;
439
440 InsertTailList(&MixerList->MixerData, &MixerData->Entry);
441 MixerList->MixerDataCount++;
442 return MM_STATUS_SUCCESS;
443 }
444
445 MIXER_STATUS
446 MMixerGetDeviceName(
447 IN PMIXER_CONTEXT MixerContext,
448 IN LPMIXER_INFO MixerInfo,
449 IN HANDLE hKey)
450 {
451 LPWSTR Name;
452 HANDLE hTemp;
453 ULONG Length;
454 ULONG Type;
455 MIXER_STATUS Status;
456
457 Status = MixerContext->QueryKeyValue(hKey, L"FriendlyName", (PVOID*)&Name, &Length, &Type);
458 if (Status == MM_STATUS_SUCCESS)
459 {
460 /* copy device name */
461 MixerContext->Copy(MixerInfo->MixCaps.szPname, Name, min(wcslen(Name), MAXPNAMELEN-1) * sizeof(WCHAR));
462
463 /* make sure its null terminated */
464 MixerInfo->MixCaps.szPname[MAXPNAMELEN-1] = L'\0';
465
466 /* free device name */
467 MixerContext->Free(Name);
468
469 /* done */
470 return Status;
471 }
472
473 Status = MixerContext->OpenKey(hKey, L"Device Parameters", KEY_READ, &hTemp);
474 if (Status != MM_STATUS_SUCCESS)
475 return Status;
476
477 Status = MixerContext->QueryKeyValue(hKey, L"FriendlyName", (PVOID*)&Name, &Length, &Type);
478 if (Status == MM_STATUS_SUCCESS)
479 {
480 /* copy device name */
481 MixerContext->Copy(MixerInfo->MixCaps.szPname, Name, min(wcslen(Name), MAXPNAMELEN-1) * sizeof(WCHAR));
482
483 /* make sure its null terminated */
484 MixerInfo->MixCaps.szPname[MAXPNAMELEN-1] = L'\0';
485
486 /* free device name */
487 MixerContext->Free(Name);
488 }
489
490 MixerContext->CloseKey(hTemp);
491 return Status;
492 }