[AUDIO-BRINGUP]
[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 const GUID KSDATAFORMAT_TYPE_MUSIC = {0xE725D360L, 0x62CC, 0x11CF, {0xA5, 0xD6, 0x28, 0xDB, 0x04, 0xC1, 0x00, 0x00}};
35 const GUID KSDATAFORMAT_SUBTYPE_MIDI = {0x1D262760L, 0xE957, 0x11CF, {0xA5, 0xD6, 0x28, 0xDB, 0x04, 0xC1, 0x00, 0x00}};
36 const GUID KSDATAFORMAT_SPECIFIER_NONE = {0x0F6417D6L, 0xC318, 0x11D0, {0xA4, 0x3F, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
37
38
39 MIXER_STATUS
40 MMixerVerifyContext(
41 IN PMIXER_CONTEXT MixerContext)
42 {
43 if (MixerContext->SizeOfStruct != sizeof(MIXER_CONTEXT))
44 return MM_STATUS_INVALID_PARAMETER;
45
46 if (!MixerContext->Alloc || !MixerContext->Control || !MixerContext->Free || !MixerContext->Open ||
47 !MixerContext->AllocEventData || !MixerContext->FreeEventData ||
48 !MixerContext->Close || !MixerContext->OpenKey || !MixerContext->QueryKeyValue || !MixerContext->CloseKey)
49 return MM_STATUS_INVALID_PARAMETER;
50
51 if (!MixerContext->MixerContext)
52 return MM_STATUS_INVALID_PARAMETER;
53
54 return MM_STATUS_SUCCESS;
55 }
56
57 VOID
58 MMixerFreeMixerInfo(
59 IN PMIXER_CONTEXT MixerContext,
60 IN LPMIXER_INFO MixerInfo)
61 {
62 /* UNIMPLEMENTED
63 * FIXME
64 * free all lines
65 */
66
67 MixerContext->Free((PVOID)MixerInfo);
68 }
69
70 LPMIXER_INFO
71 MMixerGetMixerInfoByIndex(
72 IN PMIXER_CONTEXT MixerContext,
73 IN ULONG MixerIndex)
74 {
75 LPMIXER_INFO MixerInfo;
76 PLIST_ENTRY Entry;
77 PMIXER_LIST MixerList;
78 ULONG Index = 0;
79
80 /* get mixer list */
81 MixerList = (PMIXER_LIST)MixerContext->MixerContext;
82
83 if (!MixerList->MixerListCount)
84 return NULL;
85
86 Entry = MixerList->MixerList.Flink;
87
88 while(Entry != &MixerList->MixerList)
89 {
90 MixerInfo = (LPMIXER_INFO)CONTAINING_RECORD(Entry, MIXER_INFO, Entry);
91
92 if (Index == MixerIndex)
93 return MixerInfo;
94
95 /* move to next mixer entry */
96 Index++;
97 Entry = Entry->Flink;
98 }
99
100 return NULL;
101 }
102
103 MIXER_STATUS
104 MMixerGetMixerByName(
105 IN PMIXER_LIST MixerList,
106 IN LPWSTR MixerName,
107 OUT LPMIXER_INFO *OutMixerInfo)
108 {
109 LPMIXER_INFO MixerInfo;
110 PLIST_ENTRY Entry;
111
112 Entry = MixerList->MixerList.Flink;
113 while(Entry != &MixerList->MixerList)
114 {
115 MixerInfo = (LPMIXER_INFO)CONTAINING_RECORD(Entry, MIXER_INFO, Entry);
116
117 DPRINT1("MixerName %S MixerName %S\n", MixerInfo->MixCaps.szPname, MixerName);
118 if (wcsicmp(MixerInfo->MixCaps.szPname, MixerName) == 0)
119 {
120 *OutMixerInfo = MixerInfo;
121 return MM_STATUS_SUCCESS;
122 }
123 /* move to next mixer entry */
124 Entry = Entry->Flink;
125 }
126
127 return MM_STATUS_UNSUCCESSFUL;
128 }
129
130 LPMIXERLINE_EXT
131 MMixerGetSourceMixerLineByLineId(
132 LPMIXER_INFO MixerInfo,
133 DWORD dwLineID)
134 {
135 PLIST_ENTRY Entry;
136 LPMIXERLINE_EXT MixerLineSrc;
137
138 /* get first entry */
139 Entry = MixerInfo->LineList.Flink;
140
141 while(Entry != &MixerInfo->LineList)
142 {
143 MixerLineSrc = (LPMIXERLINE_EXT)CONTAINING_RECORD(Entry, MIXERLINE_EXT, Entry);
144 DPRINT("dwLineID %x dwLineID %x MixerLineSrc %p\n", MixerLineSrc->Line.dwLineID, dwLineID, MixerLineSrc);
145 if (MixerLineSrc->Line.dwLineID == dwLineID)
146 return MixerLineSrc;
147
148 Entry = Entry->Flink;
149 }
150
151 return NULL;
152 }
153
154 LPGUID
155 MMixerGetNodeType(
156 IN PKSMULTIPLE_ITEM MultipleItem,
157 IN ULONG Index)
158 {
159 LPGUID NodeType;
160
161 ASSERT(Index < MultipleItem->Count);
162
163 NodeType = (LPGUID)(MultipleItem + 1);
164 return &NodeType[Index];
165 }
166
167 LPMIXERLINE_EXT
168 MMixerGetSourceMixerLineByComponentType(
169 LPMIXER_INFO MixerInfo,
170 DWORD dwComponentType)
171 {
172 PLIST_ENTRY Entry;
173 LPMIXERLINE_EXT MixerLineSrc;
174
175 /* get first entry */
176 Entry = MixerInfo->LineList.Flink;
177
178 while(Entry != &MixerInfo->LineList)
179 {
180 MixerLineSrc = (LPMIXERLINE_EXT)CONTAINING_RECORD(Entry, MIXERLINE_EXT, Entry);
181 if (MixerLineSrc->Line.dwComponentType == dwComponentType)
182 return MixerLineSrc;
183
184 Entry = Entry->Flink;
185 }
186
187 return NULL;
188 }
189
190 MIXER_STATUS
191 MMixerGetMixerControlById(
192 LPMIXER_INFO MixerInfo,
193 DWORD dwControlID,
194 LPMIXERLINE_EXT *OutMixerLine,
195 LPMIXERCONTROL_EXT *OutMixerControl,
196 PULONG NodeId)
197 {
198 PLIST_ENTRY Entry, ControlEntry;
199 LPMIXERLINE_EXT MixerLineSrc;
200 LPMIXERCONTROL_EXT MixerControl;
201
202 /* get first entry */
203 Entry = MixerInfo->LineList.Flink;
204
205 while(Entry != &MixerInfo->LineList)
206 {
207 MixerLineSrc = (LPMIXERLINE_EXT)CONTAINING_RECORD(Entry, MIXERLINE_EXT, Entry);
208
209 ControlEntry = MixerLineSrc->ControlsList.Flink;
210 while(ControlEntry != &MixerLineSrc->ControlsList)
211 {
212 MixerControl = (LPMIXERCONTROL_EXT)CONTAINING_RECORD(ControlEntry, MIXERCONTROL_EXT, Entry);
213 if (MixerControl->Control.dwControlID == dwControlID)
214 {
215 if (OutMixerLine)
216 *OutMixerLine = MixerLineSrc;
217 if (OutMixerControl)
218 *OutMixerControl = MixerControl;
219 if (NodeId)
220 *NodeId = MixerControl->NodeID;
221 return MM_STATUS_SUCCESS;
222 }
223 ControlEntry = ControlEntry->Flink;
224 }
225 Entry = Entry->Flink;
226 }
227
228 return MM_STATUS_UNSUCCESSFUL;
229 }
230
231 ULONG
232 MMixerGetVolumeControlIndex(
233 LPMIXERVOLUME_DATA VolumeData,
234 LONG Value)
235 {
236 ULONG Index;
237
238 for(Index = 0; Index < VolumeData->ValuesCount; Index++)
239 {
240 if (VolumeData->Values[Index] > Value)
241 {
242 return VolumeData->InputSteppingDelta * Index;
243 }
244 }
245 return VolumeData->InputSteppingDelta * (VolumeData->ValuesCount-1);
246 }
247
248 VOID
249 MMixerNotifyControlChange(
250 IN PMIXER_CONTEXT MixerContext,
251 IN LPMIXER_INFO MixerInfo,
252 IN ULONG NotificationType,
253 IN ULONG Value)
254 {
255 PLIST_ENTRY Entry;
256 PEVENT_NOTIFICATION_ENTRY NotificationEntry;
257
258 /* enumerate list and add a notification entry */
259 Entry = MixerInfo->LineList.Flink;
260 while(Entry != &MixerInfo->EventList)
261 {
262 /* get notification entry offset */
263 NotificationEntry = (PEVENT_NOTIFICATION_ENTRY)CONTAINING_RECORD(Entry, EVENT_NOTIFICATION_ENTRY, Entry);
264
265 if (NotificationEntry->MixerEventRoutine)
266 {
267 /* now perform the callback */
268 NotificationEntry->MixerEventRoutine(NotificationEntry->MixerEventContext, (HANDLE)MixerInfo, NotificationType, Value);
269 }
270
271 /* move to next notification entry */
272 Entry = Entry->Flink;
273 }
274 }
275
276 MIXER_STATUS
277 MMixerSetGetMuteControlDetails(
278 IN PMIXER_CONTEXT MixerContext,
279 IN LPMIXER_INFO MixerInfo,
280 IN LPMIXERCONTROL_EXT MixerControl,
281 IN ULONG dwLineID,
282 IN LPMIXERCONTROLDETAILS MixerControlDetails,
283 IN ULONG bSet)
284 {
285 LPMIXERCONTROLDETAILS_BOOLEAN Input;
286 LONG Value;
287 MIXER_STATUS Status;
288
289 if (MixerControlDetails->cbDetails != sizeof(MIXERCONTROLDETAILS_BOOLEAN))
290 return MM_STATUS_INVALID_PARAMETER;
291
292 /* get input */
293 Input = (LPMIXERCONTROLDETAILS_BOOLEAN)MixerControlDetails->paDetails;
294
295 /* FIXME SEH */
296 if (bSet)
297 Value = Input->fValue;
298
299 /* set control details */
300 Status = MMixerSetGetControlDetails(MixerContext, MixerControl->hDevice, MixerControl->NodeID, bSet, KSPROPERTY_AUDIO_MUTE, 0, &Value);
301
302 if (Status != MM_STATUS_SUCCESS)
303 return Status;
304
305 /* FIXME SEH */
306 if (!bSet)
307 {
308 Input->fValue = Value;
309 return Status;
310 }
311 else
312 {
313 /* notify wdmaud clients MM_MIXM_LINE_CHANGE dwLineID */
314 MMixerNotifyControlChange(MixerContext, MixerInfo, MM_MIXM_LINE_CHANGE, dwLineID);
315 }
316
317 return Status;
318 }
319
320 MIXER_STATUS
321 MMixerSetGetVolumeControlDetails(
322 IN PMIXER_CONTEXT MixerContext,
323 IN LPMIXER_INFO MixerInfo,
324 IN ULONG NodeId,
325 IN ULONG bSet,
326 LPMIXERCONTROL_EXT MixerControl,
327 IN LPMIXERCONTROLDETAILS MixerControlDetails,
328 LPMIXERLINE_EXT MixerLine)
329 {
330 LPMIXERCONTROLDETAILS_UNSIGNED Input;
331 LONG Value, Index, Channel = 0;
332 ULONG dwValue;
333 MIXER_STATUS Status;
334 LPMIXERVOLUME_DATA VolumeData;
335
336 if (MixerControlDetails->cbDetails != sizeof(MIXERCONTROLDETAILS_SIGNED))
337 return MM_STATUS_INVALID_PARAMETER;
338
339 VolumeData = (LPMIXERVOLUME_DATA)MixerControl->ExtraData;
340 if (!VolumeData)
341 return MM_STATUS_UNSUCCESSFUL;
342
343 /* get input */
344 Input = (LPMIXERCONTROLDETAILS_UNSIGNED)MixerControlDetails->paDetails;
345
346 if (bSet)
347 {
348 /* FIXME SEH */
349 Value = Input->dwValue;
350 Index = Value / VolumeData->InputSteppingDelta;
351
352 if (Index >= VolumeData->ValuesCount)
353 {
354 DPRINT1("Index %u out of bounds %u \n", Index, VolumeData->ValuesCount);
355 return MM_STATUS_INVALID_PARAMETER;
356 }
357
358 Value = VolumeData->Values[Index];
359 }
360
361 /* set control details */
362 if (bSet)
363 {
364 /* TODO */
365 Status = MMixerSetGetControlDetails(MixerContext, MixerControl->hDevice, NodeId, bSet, KSPROPERTY_AUDIO_VOLUMELEVEL, 0, &Value);
366 Status = MMixerSetGetControlDetails(MixerContext, MixerControl->hDevice, NodeId, bSet, KSPROPERTY_AUDIO_VOLUMELEVEL, 1, &Value);
367 }
368 else
369 {
370 Status = MMixerSetGetControlDetails(MixerContext, MixerControl->hDevice, NodeId, bSet, KSPROPERTY_AUDIO_VOLUMELEVEL, Channel, &Value);
371 }
372
373 if (!bSet)
374 {
375 dwValue = MMixerGetVolumeControlIndex(VolumeData, (LONG)Value);
376 /* FIXME SEH */
377 Input->dwValue = dwValue;
378 }
379 else
380 {
381 /* notify clients of a line change MM_MIXM_CONTROL_CHANGE with MixerControl->dwControlID */
382 MMixerNotifyControlChange(MixerContext, MixerInfo, MM_MIXM_CONTROL_CHANGE, MixerControl->Control.dwControlID);
383 }
384 return Status;
385 }
386
387 LPMIXER_DATA
388 MMixerGetDataByDeviceId(
389 IN PMIXER_LIST MixerList,
390 IN ULONG DeviceId)
391 {
392 PLIST_ENTRY Entry;
393 LPMIXER_DATA MixerData;
394
395 Entry = MixerList->MixerData.Flink;
396 while(Entry != &MixerList->MixerData)
397 {
398 MixerData = (LPMIXER_DATA)CONTAINING_RECORD(Entry, MIXER_DATA, Entry);
399 if (MixerData->DeviceId == DeviceId)
400 {
401 return MixerData;
402 }
403 Entry = Entry->Flink;
404 }
405 return NULL;
406 }
407
408 LPMIXER_DATA
409 MMixerGetDataByDeviceName(
410 IN PMIXER_LIST MixerList,
411 IN LPWSTR DeviceName)
412 {
413 PLIST_ENTRY Entry;
414 LPMIXER_DATA MixerData;
415
416 Entry = MixerList->MixerData.Flink;
417 while(Entry != &MixerList->MixerData)
418 {
419 MixerData = (LPMIXER_DATA)CONTAINING_RECORD(Entry, MIXER_DATA, Entry);
420 if (wcsicmp(&DeviceName[2], &MixerData->DeviceName[2]) == 0)
421 {
422 /* found entry */
423 return MixerData;
424 }
425 Entry = Entry->Flink;
426 }
427 return NULL;
428 }
429
430 MIXER_STATUS
431 MMixerCreateMixerData(
432 IN PMIXER_CONTEXT MixerContext,
433 IN PMIXER_LIST MixerList,
434 IN ULONG DeviceId,
435 IN LPWSTR DeviceName,
436 IN HANDLE hDevice,
437 IN HANDLE hKey)
438 {
439 LPMIXER_DATA MixerData;
440
441 MixerData = (LPMIXER_DATA)MixerContext->Alloc(sizeof(MIXER_DATA));
442 if (!MixerData)
443 return MM_STATUS_NO_MEMORY;
444
445 MixerData->DeviceId = DeviceId;
446 MixerData->DeviceName = DeviceName;
447 MixerData->hDevice = hDevice;
448 MixerData->hDeviceInterfaceKey = hKey;
449 MixerData->Topology = NULL;
450
451 InsertTailList(&MixerList->MixerData, &MixerData->Entry);
452 MixerList->MixerDataCount++;
453 return MM_STATUS_SUCCESS;
454 }
455
456 MIXER_STATUS
457 MMixerGetDeviceName(
458 IN PMIXER_CONTEXT MixerContext,
459 OUT LPWSTR DeviceName,
460 IN HANDLE hKey)
461 {
462 LPWSTR Name;
463 HANDLE hTemp;
464 ULONG Length;
465 ULONG Type;
466 MIXER_STATUS Status;
467
468 Status = MixerContext->QueryKeyValue(hKey, L"FriendlyName", (PVOID*)&Name, &Length, &Type);
469 if (Status == MM_STATUS_SUCCESS)
470 {
471 /* copy device name */
472 MixerContext->Copy(DeviceName, Name, min(wcslen(Name), MAXPNAMELEN-1) * sizeof(WCHAR));
473
474 /* make sure its null terminated */
475 DeviceName[MAXPNAMELEN-1] = L'\0';
476
477 /* free device name */
478 MixerContext->Free(Name);
479
480 /* done */
481 return Status;
482 }
483
484 Status = MixerContext->OpenKey(hKey, L"Device Parameters", KEY_READ, &hTemp);
485 if (Status != MM_STATUS_SUCCESS)
486 return Status;
487
488 Status = MixerContext->QueryKeyValue(hTemp, L"FriendlyName", (PVOID*)&Name, &Length, &Type);
489 if (Status == MM_STATUS_SUCCESS)
490 {
491 /* copy device name */
492 MixerContext->Copy(DeviceName, Name, min(wcslen(Name), MAXPNAMELEN-1) * sizeof(WCHAR));
493
494 /* make sure its null terminated */
495 DeviceName[MAXPNAMELEN-1] = L'\0';
496
497 /* free device name */
498 MixerContext->Free(Name);
499 }
500
501 MixerContext->CloseKey(hTemp);
502 return Status;
503 }
504
505 VOID
506 MMixerInitializePinConnect(
507 IN OUT PKSPIN_CONNECT PinConnect,
508 IN ULONG PinId)
509 {
510 PinConnect->Interface.Set = KSINTERFACESETID_Standard;
511 PinConnect->Interface.Id = KSINTERFACE_STANDARD_STREAMING;
512 PinConnect->Interface.Flags = 0;
513 PinConnect->Medium.Set = KSMEDIUMSETID_Standard;
514 PinConnect->Medium.Id = KSMEDIUM_TYPE_ANYINSTANCE;
515 PinConnect->Medium.Flags = 0;
516 PinConnect->PinToHandle = NULL;
517 PinConnect->PinId = PinId;
518 PinConnect->Priority.PriorityClass = KSPRIORITY_NORMAL;
519 PinConnect->Priority.PrioritySubClass = 1;
520 }
521