[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 LPMIXERLINE_EXT
104 MMixerGetSourceMixerLineByLineId(
105 LPMIXER_INFO MixerInfo,
106 DWORD dwLineID)
107 {
108 PLIST_ENTRY Entry;
109 LPMIXERLINE_EXT MixerLineSrc;
110
111 /* get first entry */
112 Entry = MixerInfo->LineList.Flink;
113
114 while(Entry != &MixerInfo->LineList)
115 {
116 MixerLineSrc = (LPMIXERLINE_EXT)CONTAINING_RECORD(Entry, MIXERLINE_EXT, Entry);
117 DPRINT("dwLineID %x dwLineID %x MixerLineSrc %p\n", MixerLineSrc->Line.dwLineID, dwLineID, MixerLineSrc);
118 if (MixerLineSrc->Line.dwLineID == dwLineID)
119 return MixerLineSrc;
120
121 Entry = Entry->Flink;
122 }
123
124 return NULL;
125 }
126
127 LPGUID
128 MMixerGetNodeType(
129 IN PKSMULTIPLE_ITEM MultipleItem,
130 IN ULONG Index)
131 {
132 LPGUID NodeType;
133
134 ASSERT(Index < MultipleItem->Count);
135
136 NodeType = (LPGUID)(MultipleItem + 1);
137 return &NodeType[Index];
138 }
139
140 LPMIXERLINE_EXT
141 MMixerGetSourceMixerLineByComponentType(
142 LPMIXER_INFO MixerInfo,
143 DWORD dwComponentType)
144 {
145 PLIST_ENTRY Entry;
146 LPMIXERLINE_EXT MixerLineSrc;
147
148 /* get first entry */
149 Entry = MixerInfo->LineList.Flink;
150
151 while(Entry != &MixerInfo->LineList)
152 {
153 MixerLineSrc = (LPMIXERLINE_EXT)CONTAINING_RECORD(Entry, MIXERLINE_EXT, Entry);
154 if (MixerLineSrc->Line.dwComponentType == dwComponentType)
155 return MixerLineSrc;
156
157 Entry = Entry->Flink;
158 }
159
160 return NULL;
161 }
162
163 MIXER_STATUS
164 MMixerGetMixerControlById(
165 LPMIXER_INFO MixerInfo,
166 DWORD dwControlID,
167 LPMIXERLINE_EXT *OutMixerLine,
168 LPMIXERCONTROL_EXT *OutMixerControl,
169 PULONG NodeId)
170 {
171 PLIST_ENTRY Entry, ControlEntry;
172 LPMIXERLINE_EXT MixerLineSrc;
173 LPMIXERCONTROL_EXT MixerControl;
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
182 ControlEntry = MixerLineSrc->ControlsList.Flink;
183 while(ControlEntry != &MixerLineSrc->ControlsList)
184 {
185 MixerControl = (LPMIXERCONTROL_EXT)CONTAINING_RECORD(ControlEntry, MIXERCONTROL_EXT, Entry);
186 if (MixerControl->Control.dwControlID == dwControlID)
187 {
188 if (OutMixerLine)
189 *OutMixerLine = MixerLineSrc;
190 if (OutMixerControl)
191 *OutMixerControl = MixerControl;
192 if (NodeId)
193 *NodeId = MixerControl->NodeID;
194 return MM_STATUS_SUCCESS;
195 }
196 ControlEntry = ControlEntry->Flink;
197 }
198 Entry = Entry->Flink;
199 }
200
201 return MM_STATUS_UNSUCCESSFUL;
202 }
203
204 ULONG
205 MMixerGetVolumeControlIndex(
206 LPMIXERVOLUME_DATA VolumeData,
207 LONG Value)
208 {
209 ULONG Index;
210
211 for(Index = 0; Index < VolumeData->ValuesCount; Index++)
212 {
213 if (VolumeData->Values[Index] > Value)
214 {
215 return VolumeData->InputSteppingDelta * Index;
216 }
217 }
218 return VolumeData->InputSteppingDelta * (VolumeData->ValuesCount-1);
219 }
220
221 VOID
222 MMixerNotifyControlChange(
223 IN PMIXER_CONTEXT MixerContext,
224 IN LPMIXER_INFO MixerInfo,
225 IN ULONG NotificationType,
226 IN ULONG Value)
227 {
228 PLIST_ENTRY Entry;
229 PEVENT_NOTIFICATION_ENTRY NotificationEntry;
230
231 /* enumerate list and add a notification entry */
232 Entry = MixerInfo->LineList.Flink;
233 while(Entry != &MixerInfo->EventList)
234 {
235 /* get notification entry offset */
236 NotificationEntry = (PEVENT_NOTIFICATION_ENTRY)CONTAINING_RECORD(Entry, EVENT_NOTIFICATION_ENTRY, Entry);
237
238 if (NotificationEntry->MixerEventRoutine)
239 {
240 /* now perform the callback */
241 NotificationEntry->MixerEventRoutine(NotificationEntry->MixerEventContext, (HANDLE)MixerInfo, NotificationType, Value);
242 }
243
244 /* move to next notification entry */
245 Entry = Entry->Flink;
246 }
247 }
248
249 MIXER_STATUS
250 MMixerSetGetMuteControlDetails(
251 IN PMIXER_CONTEXT MixerContext,
252 IN LPMIXER_INFO MixerInfo,
253 IN LPMIXERCONTROL_EXT MixerControl,
254 IN ULONG dwLineID,
255 IN LPMIXERCONTROLDETAILS MixerControlDetails,
256 IN ULONG bSet)
257 {
258 LPMIXERCONTROLDETAILS_BOOLEAN Input;
259 LONG Value;
260 MIXER_STATUS Status;
261
262 if (MixerControlDetails->cbDetails != sizeof(MIXERCONTROLDETAILS_BOOLEAN))
263 return MM_STATUS_INVALID_PARAMETER;
264
265 /* get input */
266 Input = (LPMIXERCONTROLDETAILS_BOOLEAN)MixerControlDetails->paDetails;
267
268 /* FIXME SEH */
269 if (bSet)
270 Value = Input->fValue;
271
272 /* set control details */
273 Status = MMixerSetGetControlDetails(MixerContext, MixerControl->hDevice, MixerControl->NodeID, bSet, KSPROPERTY_AUDIO_MUTE, 0, &Value);
274
275 if (Status != MM_STATUS_SUCCESS)
276 return Status;
277
278 /* FIXME SEH */
279 if (!bSet)
280 {
281 Input->fValue = Value;
282 return Status;
283 }
284 else
285 {
286 /* notify wdmaud clients MM_MIXM_LINE_CHANGE dwLineID */
287 MMixerNotifyControlChange(MixerContext, MixerInfo, MM_MIXM_LINE_CHANGE, dwLineID);
288 }
289
290 return Status;
291 }
292
293 MIXER_STATUS
294 MMixerSetGetVolumeControlDetails(
295 IN PMIXER_CONTEXT MixerContext,
296 IN LPMIXER_INFO MixerInfo,
297 IN ULONG NodeId,
298 IN ULONG bSet,
299 LPMIXERCONTROL_EXT MixerControl,
300 IN LPMIXERCONTROLDETAILS MixerControlDetails,
301 LPMIXERLINE_EXT MixerLine)
302 {
303 LPMIXERCONTROLDETAILS_UNSIGNED Input;
304 LONG Value, Index, Channel = 0;
305 ULONG dwValue;
306 MIXER_STATUS Status;
307 LPMIXERVOLUME_DATA VolumeData;
308
309 if (MixerControlDetails->cbDetails != sizeof(MIXERCONTROLDETAILS_SIGNED))
310 return MM_STATUS_INVALID_PARAMETER;
311
312 VolumeData = (LPMIXERVOLUME_DATA)MixerControl->ExtraData;
313 if (!VolumeData)
314 return MM_STATUS_UNSUCCESSFUL;
315
316 /* get input */
317 Input = (LPMIXERCONTROLDETAILS_UNSIGNED)MixerControlDetails->paDetails;
318
319 if (bSet)
320 {
321 /* FIXME SEH */
322 Value = Input->dwValue;
323 Index = Value / VolumeData->InputSteppingDelta;
324
325 if (Index >= VolumeData->ValuesCount)
326 {
327 DPRINT1("Index %u out of bounds %u \n", Index, VolumeData->ValuesCount);
328 return MM_STATUS_INVALID_PARAMETER;
329 }
330
331 Value = VolumeData->Values[Index];
332 }
333
334 /* set control details */
335 if (bSet)
336 {
337 /* TODO */
338 Status = MMixerSetGetControlDetails(MixerContext, MixerControl->hDevice, NodeId, bSet, KSPROPERTY_AUDIO_VOLUMELEVEL, 0, &Value);
339 Status = MMixerSetGetControlDetails(MixerContext, MixerControl->hDevice, NodeId, bSet, KSPROPERTY_AUDIO_VOLUMELEVEL, 1, &Value);
340 }
341 else
342 {
343 Status = MMixerSetGetControlDetails(MixerContext, MixerControl->hDevice, NodeId, bSet, KSPROPERTY_AUDIO_VOLUMELEVEL, Channel, &Value);
344 }
345
346 if (!bSet)
347 {
348 dwValue = MMixerGetVolumeControlIndex(VolumeData, (LONG)Value);
349 /* FIXME SEH */
350 Input->dwValue = dwValue;
351 }
352 else
353 {
354 /* notify clients of a line change MM_MIXM_CONTROL_CHANGE with MixerControl->dwControlID */
355 MMixerNotifyControlChange(MixerContext, MixerInfo, MM_MIXM_CONTROL_CHANGE, MixerControl->Control.dwControlID);
356 }
357 return Status;
358 }
359
360 LPMIXER_DATA
361 MMixerGetDataByDeviceId(
362 IN PMIXER_LIST MixerList,
363 IN ULONG DeviceId)
364 {
365 PLIST_ENTRY Entry;
366 LPMIXER_DATA MixerData;
367
368 Entry = MixerList->MixerData.Flink;
369 while(Entry != &MixerList->MixerData)
370 {
371 MixerData = (LPMIXER_DATA)CONTAINING_RECORD(Entry, MIXER_DATA, Entry);
372 if (MixerData->DeviceId == DeviceId)
373 {
374 return MixerData;
375 }
376 Entry = Entry->Flink;
377 }
378 return NULL;
379 }
380
381 LPMIXER_DATA
382 MMixerGetDataByDeviceName(
383 IN PMIXER_LIST MixerList,
384 IN LPWSTR DeviceName)
385 {
386 PLIST_ENTRY Entry;
387 LPMIXER_DATA MixerData;
388
389 Entry = MixerList->MixerData.Flink;
390 while(Entry != &MixerList->MixerData)
391 {
392 MixerData = (LPMIXER_DATA)CONTAINING_RECORD(Entry, MIXER_DATA, Entry);
393 if (wcsicmp(&DeviceName[2], &MixerData->DeviceName[2]) == 0)
394 {
395 /* found entry */
396 return MixerData;
397 }
398 Entry = Entry->Flink;
399 }
400 return NULL;
401 }
402
403 MIXER_STATUS
404 MMixerCreateMixerData(
405 IN PMIXER_CONTEXT MixerContext,
406 IN PMIXER_LIST MixerList,
407 IN ULONG DeviceId,
408 IN LPWSTR DeviceName,
409 IN HANDLE hDevice,
410 IN HANDLE hKey)
411 {
412 LPMIXER_DATA MixerData;
413
414 MixerData = (LPMIXER_DATA)MixerContext->Alloc(sizeof(MIXER_DATA));
415 if (!MixerData)
416 return MM_STATUS_NO_MEMORY;
417
418 MixerData->DeviceId = DeviceId;
419 MixerData->DeviceName = DeviceName;
420 MixerData->hDevice = hDevice;
421 MixerData->hDeviceInterfaceKey = hKey;
422 MixerData->Topology = NULL;
423
424 InsertTailList(&MixerList->MixerData, &MixerData->Entry);
425 MixerList->MixerDataCount++;
426 return MM_STATUS_SUCCESS;
427 }
428
429 MIXER_STATUS
430 MMixerGetDeviceName(
431 IN PMIXER_CONTEXT MixerContext,
432 OUT LPWSTR DeviceName,
433 IN HANDLE hKey)
434 {
435 LPWSTR Name;
436 HANDLE hTemp;
437 ULONG Length;
438 ULONG Type;
439 MIXER_STATUS Status;
440
441 Status = MixerContext->QueryKeyValue(hKey, L"FriendlyName", (PVOID*)&Name, &Length, &Type);
442 if (Status == MM_STATUS_SUCCESS)
443 {
444 /* copy device name */
445 MixerContext->Copy(DeviceName, Name, min(wcslen(Name), MAXPNAMELEN-1) * sizeof(WCHAR));
446
447 /* make sure its null terminated */
448 DeviceName[MAXPNAMELEN-1] = L'\0';
449
450 /* free device name */
451 MixerContext->Free(Name);
452
453 /* done */
454 return Status;
455 }
456
457 Status = MixerContext->OpenKey(hKey, L"Device Parameters", KEY_READ, &hTemp);
458 if (Status != MM_STATUS_SUCCESS)
459 return Status;
460
461 Status = MixerContext->QueryKeyValue(hTemp, L"FriendlyName", (PVOID*)&Name, &Length, &Type);
462 if (Status == MM_STATUS_SUCCESS)
463 {
464 /* copy device name */
465 MixerContext->Copy(DeviceName, Name, min(wcslen(Name), MAXPNAMELEN-1) * sizeof(WCHAR));
466
467 /* make sure its null terminated */
468 DeviceName[MAXPNAMELEN-1] = L'\0';
469
470 /* free device name */
471 MixerContext->Free(Name);
472 }
473
474 MixerContext->CloseKey(hTemp);
475 return Status;
476 }
477
478 VOID
479 MMixerInitializePinConnect(
480 IN OUT PKSPIN_CONNECT PinConnect,
481 IN ULONG PinId)
482 {
483 PinConnect->Interface.Set = KSINTERFACESETID_Standard;
484 PinConnect->Interface.Id = KSINTERFACE_STANDARD_STREAMING;
485 PinConnect->Interface.Flags = 0;
486 PinConnect->Medium.Set = KSMEDIUMSETID_Standard;
487 PinConnect->Medium.Id = KSMEDIUM_TYPE_ANYINSTANCE;
488 PinConnect->Medium.Flags = 0;
489 PinConnect->PinToHandle = NULL;
490 PinConnect->PinId = PinId;
491 PinConnect->Priority.PriorityClass = KSPRIORITY_NORMAL;
492 PinConnect->Priority.PrioritySubClass = 1;
493 }
494