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