[MMIXER] Fix NULL dereference CORE-17276
[reactos.git] / sdk / 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 #include "precomp.h"
10
11 #define YDEBUG
12 #include <debug.h>
13
14 const GUID KSNODETYPE_SUM = {0xDA441A60L, 0xC556, 0x11D0, {0x8A, 0x2B, 0x00, 0xA0, 0xC9, 0x25, 0x5A, 0xC1}};
15 const GUID KSNODETYPE_DAC = {0x507AE360L, 0xC554, 0x11D0, {0x8A, 0x2B, 0x00, 0xA0, 0xC9, 0x25, 0x5A, 0xC1}};
16 const GUID KSNODETYPE_ADC = {0x4D837FE0L, 0xC555, 0x11D0, {0x8A, 0x2B, 0x00, 0xA0, 0xC9, 0x25, 0x5A, 0xC1}};
17 const GUID KSNODETYPE_AGC = {0xE88C9BA0L, 0xC557, 0x11D0, {0x8A, 0x2B, 0x00, 0xA0, 0xC9, 0x25, 0x5A, 0xC1}};
18 const GUID KSNODETYPE_LOUDNESS = {0x41887440L, 0xC558, 0x11D0, {0x8A, 0x2B, 0x00, 0xA0, 0xC9, 0x25, 0x5A, 0xC1}};
19 const GUID KSNODETYPE_MUTE = {0x02B223C0L, 0xC557, 0x11D0, {0x8A, 0x2B, 0x00, 0xA0, 0xC9, 0x25, 0x5A, 0xC1}};
20 const GUID KSNODETYPE_TONE = {0x7607E580L, 0xC557, 0x11D0, {0x8A, 0x2B, 0x00, 0xA0, 0xC9, 0x25, 0x5A, 0xC1}};
21 const GUID KSNODETYPE_VOLUME = {0x3A5ACC00L, 0xC557, 0x11D0, {0x8A, 0x2B, 0x00, 0xA0, 0xC9, 0x25, 0x5A, 0xC1}};
22 const GUID KSNODETYPE_PEAKMETER = {0xa085651e, 0x5f0d, 0x4b36, {0xa8, 0x69, 0xd1, 0x95, 0xd6, 0xab, 0x4b, 0x9e}};
23 const GUID KSNODETYPE_MUX = {0x2CEAF780, 0xC556, 0x11D0, {0x8A, 0x2B, 0x00, 0xA0, 0xC9, 0x25, 0x5A, 0xC1}};
24 const GUID KSNODETYPE_STEREO_WIDE = {0xA9E69800L, 0xC558, 0x11D0, {0x8A, 0x2B, 0x00, 0xA0, 0xC9, 0x25, 0x5A, 0xC1}};
25 const GUID KSNODETYPE_CHORUS = {0x20173F20L, 0xC559, 0x11D0, {0x8A, 0x2B, 0x00, 0xA0, 0xC9, 0x25, 0x5A, 0xC1}};
26 const GUID KSNODETYPE_REVERB = {0xEF0328E0L, 0xC558, 0x11D0, {0x8A, 0x2B, 0x00, 0xA0, 0xC9, 0x25, 0x5A, 0xC1}};
27 const GUID KSNODETYPE_SUPERMIX = {0xE573ADC0L, 0xC555, 0x11D0, {0x8A, 0x2B, 0x00, 0xA0, 0xC9, 0x25, 0x5A, 0xC1}};
28
29 const GUID KSPROPSETID_Audio = {0x45FFAAA0L, 0x6E1B, 0x11D0, {0xBC, 0xF2, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}};
30 const GUID KSPROPSETID_Pin = {0x8C134960L, 0x51AD, 0x11CF, {0x87, 0x8A, 0x94, 0xF8, 0x01, 0xC1, 0x00, 0x00}};
31 const GUID KSPROPSETID_General = {0x1464EDA5L, 0x6A8F, 0x11D1, {0x9A, 0xA7, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
32 const GUID KSPROPSETID_Topology = {0x720D4AC0L, 0x7533, 0x11D0, {0xA5, 0xD6, 0x28, 0xDB, 0x04, 0xC1, 0x00, 0x00}};
33 const GUID KSEVENTSETID_AudioControlChange = {0xE85E9698L, 0xFA2F, 0x11D1, {0x95, 0xBD, 0x00, 0xC0, 0x4F, 0xB9, 0x25, 0xD3}};
34
35 const GUID KSDATAFORMAT_TYPE_MUSIC = {0xE725D360L, 0x62CC, 0x11CF, {0xA5, 0xD6, 0x28, 0xDB, 0x04, 0xC1, 0x00, 0x00}};
36 const GUID KSDATAFORMAT_SUBTYPE_MIDI = {0x1D262760L, 0xE957, 0x11CF, {0xA5, 0xD6, 0x28, 0xDB, 0x04, 0xC1, 0x00, 0x00}};
37 const GUID KSDATAFORMAT_SPECIFIER_NONE = {0x0F6417D6L, 0xC318, 0x11D0, {0xA4, 0x3F, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
38
39
40 MIXER_STATUS
41 MMixerVerifyContext(
42 IN PMIXER_CONTEXT MixerContext)
43 {
44 if (MixerContext->SizeOfStruct != sizeof(MIXER_CONTEXT))
45 return MM_STATUS_INVALID_PARAMETER;
46
47 if (!MixerContext->Alloc || !MixerContext->Control || !MixerContext->Free || !MixerContext->Open ||
48 !MixerContext->AllocEventData || !MixerContext->FreeEventData ||
49 !MixerContext->Close || !MixerContext->OpenKey || !MixerContext->QueryKeyValue || !MixerContext->CloseKey)
50 return MM_STATUS_INVALID_PARAMETER;
51
52 if (!MixerContext->MixerContext)
53 return MM_STATUS_INVALID_PARAMETER;
54
55 return MM_STATUS_SUCCESS;
56 }
57
58 LPMIXERLINE_EXT
59 MMixerGetMixerLineContainingNodeId(
60 IN LPMIXER_INFO MixerInfo,
61 IN ULONG NodeID)
62 {
63 PLIST_ENTRY Entry, ControlEntry;
64 LPMIXERLINE_EXT MixerLineSrc;
65 LPMIXERCONTROL_EXT MixerControl;
66
67 /* get first entry */
68 Entry = MixerInfo->LineList.Flink;
69
70 while(Entry != &MixerInfo->LineList)
71 {
72 MixerLineSrc = (LPMIXERLINE_EXT)CONTAINING_RECORD(Entry, MIXERLINE_EXT, Entry);
73
74 ControlEntry = MixerLineSrc->ControlsList.Flink;
75 while(ControlEntry != &MixerLineSrc->ControlsList)
76 {
77 MixerControl = (LPMIXERCONTROL_EXT)CONTAINING_RECORD(ControlEntry, MIXERCONTROL_EXT, Entry);
78 if (MixerControl->NodeID == NodeID)
79 {
80 return MixerLineSrc;
81 }
82 ControlEntry = ControlEntry->Flink;
83 }
84 Entry = Entry->Flink;
85 }
86
87 return NULL;
88 }
89
90 VOID
91 MMixerGetLowestLogicalTopologyPinOffsetFromArray(
92 IN ULONG LogicalPinArrayCount,
93 IN PULONG LogicalPinArray,
94 OUT PULONG PinOffset)
95 {
96 ULONG Index;
97 ULONG LowestId = 0;
98
99 for(Index = 1; Index < LogicalPinArrayCount; Index++)
100 {
101 if (LogicalPinArray[Index] != MAXULONG)
102 {
103 /* sanity check: logical pin id must be unique */
104 ASSERT(LogicalPinArray[Index] != LogicalPinArray[LowestId]);
105 }
106
107 if (LogicalPinArray[Index] < LogicalPinArray[LowestId])
108 LowestId = Index;
109 }
110
111 /* store result */
112 *PinOffset = LowestId;
113 }
114
115 VOID
116 MMixerFreeMixerInfo(
117 IN PMIXER_CONTEXT MixerContext,
118 IN LPMIXER_INFO MixerInfo)
119 {
120 /* UNIMPLEMENTED;
121 * FIXME
122 * free all lines
123 */
124
125 MixerContext->Free((PVOID)MixerInfo);
126 }
127
128
129 LPMIXER_DATA
130 MMixerGetMixerDataByDeviceHandle(
131 IN PMIXER_CONTEXT MixerContext,
132 IN HANDLE hDevice)
133 {
134 LPMIXER_DATA MixerData;
135 PLIST_ENTRY Entry;
136 PMIXER_LIST MixerList;
137
138 /* get mixer list */
139 MixerList = (PMIXER_LIST)MixerContext->MixerContext;
140
141 if (!MixerList->MixerDataCount)
142 return NULL;
143
144 Entry = MixerList->MixerData.Flink;
145
146 while(Entry != &MixerList->MixerData)
147 {
148 MixerData = (LPMIXER_DATA)CONTAINING_RECORD(Entry, MIXER_DATA, Entry);
149
150 if (MixerData->hDevice == hDevice)
151 return MixerData;
152
153 /* move to next mixer entry */
154 Entry = Entry->Flink;
155 }
156 return NULL;
157 }
158
159
160 LPMIXER_INFO
161 MMixerGetMixerInfoByIndex(
162 IN PMIXER_CONTEXT MixerContext,
163 IN ULONG MixerIndex)
164 {
165 LPMIXER_INFO MixerInfo;
166 PLIST_ENTRY Entry;
167 PMIXER_LIST MixerList;
168 ULONG Index = 0;
169
170 /* get mixer list */
171 MixerList = (PMIXER_LIST)MixerContext->MixerContext;
172
173 if (!MixerList->MixerListCount)
174 return NULL;
175
176 Entry = MixerList->MixerList.Flink;
177
178 while(Entry != &MixerList->MixerList)
179 {
180 MixerInfo = (LPMIXER_INFO)CONTAINING_RECORD(Entry, MIXER_INFO, Entry);
181
182 if (Index == MixerIndex)
183 return MixerInfo;
184
185 /* move to next mixer entry */
186 Index++;
187 Entry = Entry->Flink;
188 }
189
190 return NULL;
191 }
192
193 MIXER_STATUS
194 MMixerGetMixerByName(
195 IN PMIXER_LIST MixerList,
196 IN LPWSTR MixerName,
197 OUT LPMIXER_INFO *OutMixerInfo)
198 {
199 LPMIXER_INFO MixerInfo;
200 PLIST_ENTRY Entry;
201
202 Entry = MixerList->MixerList.Flink;
203 while(Entry != &MixerList->MixerList)
204 {
205 MixerInfo = (LPMIXER_INFO)CONTAINING_RECORD(Entry, MIXER_INFO, Entry);
206
207 DPRINT1("MixerName %S MixerName %S\n", MixerInfo->MixCaps.szPname, MixerName);
208 if (wcsicmp(MixerInfo->MixCaps.szPname, MixerName) == 0)
209 {
210 *OutMixerInfo = MixerInfo;
211 return MM_STATUS_SUCCESS;
212 }
213 /* move to next mixer entry */
214 Entry = Entry->Flink;
215 }
216
217 return MM_STATUS_UNSUCCESSFUL;
218 }
219
220 LPMIXERLINE_EXT
221 MMixerGetSourceMixerLineByLineId(
222 LPMIXER_INFO MixerInfo,
223 DWORD dwLineID)
224 {
225 PLIST_ENTRY Entry;
226 LPMIXERLINE_EXT MixerLineSrc;
227
228 /* get first entry */
229 Entry = MixerInfo->LineList.Flink;
230
231 while(Entry != &MixerInfo->LineList)
232 {
233 MixerLineSrc = (LPMIXERLINE_EXT)CONTAINING_RECORD(Entry, MIXERLINE_EXT, Entry);
234 DPRINT("dwLineID %x dwLineID %x MixerLineSrc %p\n", MixerLineSrc->Line.dwLineID, dwLineID, MixerLineSrc);
235 if (MixerLineSrc->Line.dwLineID == dwLineID)
236 return MixerLineSrc;
237
238 Entry = Entry->Flink;
239 }
240
241 return NULL;
242 }
243
244 LPGUID
245 MMixerGetNodeType(
246 IN PKSMULTIPLE_ITEM MultipleItem,
247 IN ULONG Index)
248 {
249 LPGUID NodeType;
250
251 ASSERT(Index < MultipleItem->Count);
252
253 NodeType = (LPGUID)(MultipleItem + 1);
254 return &NodeType[Index];
255 }
256
257 LPMIXERLINE_EXT
258 MMixerGetSourceMixerLineByComponentType(
259 LPMIXER_INFO MixerInfo,
260 DWORD dwComponentType)
261 {
262 PLIST_ENTRY Entry;
263 LPMIXERLINE_EXT MixerLineSrc;
264
265 /* get first entry */
266 Entry = MixerInfo->LineList.Flink;
267
268 while(Entry != &MixerInfo->LineList)
269 {
270 MixerLineSrc = (LPMIXERLINE_EXT)CONTAINING_RECORD(Entry, MIXERLINE_EXT, Entry);
271 if (MixerLineSrc->Line.dwComponentType == dwComponentType)
272 return MixerLineSrc;
273
274 Entry = Entry->Flink;
275 }
276
277 return NULL;
278 }
279
280 MIXER_STATUS
281 MMixerGetMixerControlById(
282 LPMIXER_INFO MixerInfo,
283 DWORD dwControlID,
284 LPMIXERLINE_EXT *OutMixerLine,
285 LPMIXERCONTROL_EXT *OutMixerControl,
286 PULONG NodeId)
287 {
288 PLIST_ENTRY Entry, ControlEntry;
289 LPMIXERLINE_EXT MixerLineSrc;
290 LPMIXERCONTROL_EXT MixerControl;
291
292 /* get first entry */
293 Entry = MixerInfo->LineList.Flink;
294
295 while(Entry != &MixerInfo->LineList)
296 {
297 MixerLineSrc = (LPMIXERLINE_EXT)CONTAINING_RECORD(Entry, MIXERLINE_EXT, Entry);
298
299 ControlEntry = MixerLineSrc->ControlsList.Flink;
300 while(ControlEntry != &MixerLineSrc->ControlsList)
301 {
302 MixerControl = (LPMIXERCONTROL_EXT)CONTAINING_RECORD(ControlEntry, MIXERCONTROL_EXT, Entry);
303 if (MixerControl->Control.dwControlID == dwControlID)
304 {
305 if (OutMixerLine)
306 *OutMixerLine = MixerLineSrc;
307 if (OutMixerControl)
308 *OutMixerControl = MixerControl;
309 if (NodeId)
310 *NodeId = MixerControl->NodeID;
311 return MM_STATUS_SUCCESS;
312 }
313 ControlEntry = ControlEntry->Flink;
314 }
315 Entry = Entry->Flink;
316 }
317
318 return MM_STATUS_UNSUCCESSFUL;
319 }
320
321 ULONG
322 MMixerGetVolumeControlIndex(
323 LPMIXERVOLUME_DATA VolumeData,
324 LONG Value)
325 {
326 ULONG Index;
327
328 for(Index = 0; Index < VolumeData->ValuesCount; Index++)
329 {
330 if (VolumeData->Values[Index] > Value)
331 {
332 return VolumeData->InputSteppingDelta * Index;
333 }
334 }
335 return VolumeData->InputSteppingDelta * (VolumeData->ValuesCount-1);
336 }
337
338 VOID
339 MMixerNotifyControlChange(
340 IN PMIXER_CONTEXT MixerContext,
341 IN LPMIXER_INFO MixerInfo,
342 IN ULONG NotificationType,
343 IN ULONG Value)
344 {
345 PLIST_ENTRY Entry;
346 PEVENT_NOTIFICATION_ENTRY NotificationEntry;
347
348 /* enumerate list and perform notification */
349 Entry = MixerInfo->EventList.Flink;
350 while(Entry != &MixerInfo->EventList)
351 {
352 /* get notification entry offset */
353 NotificationEntry = (PEVENT_NOTIFICATION_ENTRY)CONTAINING_RECORD(Entry, EVENT_NOTIFICATION_ENTRY, Entry);
354
355 if (NotificationEntry->MixerEventRoutine)
356 {
357 /* now perform the callback */
358 NotificationEntry->MixerEventRoutine(NotificationEntry->MixerEventContext, (HANDLE)MixerInfo, NotificationType, Value);
359 }
360
361 /* move to next notification entry */
362 Entry = Entry->Flink;
363 }
364 }
365
366 MIXER_STATUS
367 MMixerSetGetMuteControlDetails(
368 IN PMIXER_CONTEXT MixerContext,
369 IN LPMIXER_INFO MixerInfo,
370 IN LPMIXERCONTROL_EXT MixerControl,
371 IN ULONG dwLineID,
372 IN LPMIXERCONTROLDETAILS MixerControlDetails,
373 IN ULONG bSet)
374 {
375 LPMIXERCONTROLDETAILS_BOOLEAN Input;
376 LONG Value;
377 MIXER_STATUS Status;
378
379 if (MixerControlDetails->cbDetails != sizeof(MIXERCONTROLDETAILS_BOOLEAN))
380 return MM_STATUS_INVALID_PARAMETER;
381
382 /* get input */
383 Input = (LPMIXERCONTROLDETAILS_BOOLEAN)MixerControlDetails->paDetails;
384
385 /* FIXME SEH */
386 if (bSet)
387 Value = Input->fValue;
388
389 /* set control details */
390 Status = MMixerSetGetControlDetails(MixerContext, MixerControl->hDevice, MixerControl->NodeID, bSet, KSPROPERTY_AUDIO_MUTE, 0, &Value);
391
392 if (Status != MM_STATUS_SUCCESS)
393 return Status;
394
395 /* FIXME SEH */
396 if (!bSet)
397 {
398 Input->fValue = Value;
399 return Status;
400 }
401 else
402 {
403 /* notify wdmaud clients MM_MIXM_LINE_CHANGE dwLineID */
404 MMixerNotifyControlChange(MixerContext, MixerInfo, MM_MIXM_LINE_CHANGE, dwLineID);
405 }
406
407 return Status;
408 }
409
410 MIXER_STATUS
411 MMixerSetGetMuxControlDetails(
412 IN PMIXER_CONTEXT MixerContext,
413 IN LPMIXER_INFO MixerInfo,
414 IN ULONG NodeId,
415 IN ULONG bSet,
416 IN ULONG Flags,
417 IN LPMIXERCONTROL_EXT MixerControl,
418 IN LPMIXERCONTROLDETAILS MixerControlDetails,
419 IN LPMIXERLINE_EXT MixerLine)
420 {
421 MIXER_STATUS Status;
422 PULONG LogicalNodes, ConnectedNodes;
423 ULONG LogicalNodesCount, ConnectedNodesCount, Index, CurLogicalPinOffset, BytesReturned, OldLogicalPinOffset;
424 LPMIXER_DATA MixerData;
425 LPMIXERCONTROLDETAILS_LISTTEXTW ListText;
426 LPMIXERCONTROLDETAILS_BOOLEAN Values;
427 LPMIXERLINE_EXT SourceLine;
428 KSNODEPROPERTY Request;
429
430 DPRINT("MixerControlDetails %p\n", MixerControlDetails);
431 DPRINT("bSet %lx\n", bSet);
432 DPRINT("Flags %lx\n", Flags);
433 DPRINT("NodeId %lu\n", MixerControl->NodeID);
434 DPRINT("MixerControlDetails dwControlID %lu\n", MixerControlDetails->dwControlID);
435 DPRINT("MixerControlDetails cChannels %lu\n", MixerControlDetails->cChannels);
436 DPRINT("MixerControlDetails cMultipleItems %lu\n", MixerControlDetails->cMultipleItems);
437 DPRINT("MixerControlDetails cbDetails %lu\n", MixerControlDetails->cbDetails);
438 DPRINT("MixerControlDetails paDetails %p\n", MixerControlDetails->paDetails);
439
440 if (MixerControl->Control.fdwControl & MIXERCONTROL_CONTROLF_UNIFORM)
441 {
442 /* control acts uniform */
443 if (MixerControlDetails->cChannels != 1)
444 {
445 /* expected 1 channel */
446 DPRINT1("Expected 1 channel but got %lu\n", MixerControlDetails->cChannels);
447 return MM_STATUS_UNSUCCESSFUL;
448 }
449 }
450
451 /* check if multiple items match */
452 if (MixerControlDetails->cMultipleItems != MixerControl->Control.cMultipleItems)
453 {
454 DPRINT1("MultipleItems mismatch %lu expected %lu\n", MixerControlDetails->cMultipleItems, MixerControl->Control.cMultipleItems);
455 return MM_STATUS_UNSUCCESSFUL;
456 }
457
458 if (bSet)
459 {
460 if ((Flags & MIXER_SETCONTROLDETAILSF_QUERYMASK) == MIXER_SETCONTROLDETAILSF_CUSTOM)
461 {
462 /* tell me when this is hit */
463 ASSERT(FALSE);
464 }
465 else if ((Flags & (MIXER_SETCONTROLDETAILSF_VALUE | MIXER_SETCONTROLDETAILSF_CUSTOM)) == MIXER_SETCONTROLDETAILSF_VALUE)
466 {
467 /* sanity check */
468 ASSERT(bSet == TRUE);
469 ASSERT(MixerControlDetails->cbDetails == sizeof(MIXERCONTROLDETAILS_BOOLEAN));
470
471 Values = (LPMIXERCONTROLDETAILS_BOOLEAN)MixerControlDetails->paDetails;
472 CurLogicalPinOffset = MAXULONG;
473 for(Index = 0; Index < MixerControlDetails->cMultipleItems; Index++)
474 {
475 if (Values[Index].fValue)
476 {
477 /* mux can only activate one line at a time */
478 ASSERT(CurLogicalPinOffset == MAXULONG);
479 CurLogicalPinOffset = Index;
480 }
481 }
482
483 /* setup request */
484 Request.NodeId = NodeId;
485 Request.Reserved = 0;
486 Request.Property.Flags = KSPROPERTY_TYPE_TOPOLOGY | KSPROPERTY_TYPE_GET;
487 Request.Property.Id = KSPROPERTY_AUDIO_MUX_SOURCE;
488 Request.Property.Set = KSPROPSETID_Audio;
489
490 /* perform getting source */
491 Status = MixerContext->Control(MixerControl->hDevice, IOCTL_KS_PROPERTY, (PVOID)&Request, sizeof(KSNODEPROPERTY), &OldLogicalPinOffset, sizeof(ULONG), &BytesReturned);
492 if (Status != MM_STATUS_SUCCESS)
493 {
494 /* failed to get source */
495 return Status;
496 }
497
498 DPRINT("OldLogicalPinOffset %lu CurLogicalPinOffset %lu\n", OldLogicalPinOffset, CurLogicalPinOffset);
499
500 if (OldLogicalPinOffset == CurLogicalPinOffset)
501 {
502 /* cannot be unselected */
503 return MM_STATUS_UNSUCCESSFUL;
504 }
505
506 /* perform setting source */
507 Request.Property.Flags = KSPROPERTY_TYPE_TOPOLOGY | KSPROPERTY_TYPE_SET;
508 Status = MixerContext->Control(MixerControl->hDevice, IOCTL_KS_PROPERTY, (PVOID)&Request, sizeof(KSNODEPROPERTY), &CurLogicalPinOffset, sizeof(ULONG), &BytesReturned);
509 if (Status != MM_STATUS_SUCCESS)
510 {
511 /* failed to set source */
512 return Status;
513 }
514
515 /* notify control change */
516 MMixerNotifyControlChange(MixerContext, MixerInfo, MM_MIXM_CONTROL_CHANGE, MixerControl->Control.dwControlID );
517
518 return Status;
519 }
520 }
521 else
522 {
523 if ((Flags & MIXER_GETCONTROLDETAILSF_QUERYMASK) == MIXER_GETCONTROLDETAILSF_VALUE)
524 {
525 /* setup request */
526 Request.NodeId = NodeId;
527 Request.Reserved = 0;
528 Request.Property.Flags = KSPROPERTY_TYPE_TOPOLOGY | KSPROPERTY_TYPE_GET;
529 Request.Property.Id = KSPROPERTY_AUDIO_MUX_SOURCE;
530 Request.Property.Set = KSPROPSETID_Audio;
531
532 /* perform getting source */
533 Status = MixerContext->Control(MixerControl->hDevice, IOCTL_KS_PROPERTY, (PVOID)&Request, sizeof(KSNODEPROPERTY), &OldLogicalPinOffset, sizeof(ULONG), &BytesReturned);
534 if (Status != MM_STATUS_SUCCESS)
535 {
536 /* failed to get source */
537 return Status;
538 }
539
540 /* gets the corresponding mixer data */
541 MixerData = MMixerGetMixerDataByDeviceHandle(MixerContext, MixerControl->hDevice);
542
543 /* sanity check */
544 ASSERT(MixerData);
545 ASSERT(MixerData->Topology);
546 ASSERT(MixerData->MixerInfo == MixerInfo);
547
548 /* now allocate logical pin array */
549 Status = MMixerAllocateTopologyNodeArray(MixerContext, MixerData->Topology, &LogicalNodes);
550 if (Status != MM_STATUS_SUCCESS)
551 {
552 /* no memory */
553 return MM_STATUS_NO_MEMORY;
554 }
555
556 /* get logical pin nodes */
557 MMixerGetConnectedFromLogicalTopologyPins(MixerData->Topology, MixerControl->NodeID, &LogicalNodesCount, LogicalNodes);
558
559 /* sanity check */
560 ASSERT(LogicalNodesCount == MixerControlDetails->cMultipleItems);
561 ASSERT(LogicalNodesCount == MixerControl->Control.Metrics.dwReserved[0]);
562
563 Values = (LPMIXERCONTROLDETAILS_BOOLEAN)MixerControlDetails->paDetails;
564 for(Index = 0; Index < LogicalNodesCount; Index++)
565 {
566 /* getting logical pin offset */
567 MMixerGetLowestLogicalTopologyPinOffsetFromArray(LogicalNodesCount, LogicalNodes, &CurLogicalPinOffset);
568
569 if (CurLogicalPinOffset == OldLogicalPinOffset)
570 {
571 /* mark index as active */
572 Values[Index].fValue = TRUE;
573 }
574 else
575 {
576 /* index not active */
577 Values[Index].fValue = FALSE;
578 }
579
580 /* mark offset as consumed */
581 LogicalNodes[CurLogicalPinOffset] = MAXULONG;
582 }
583
584 /* cleanup */
585 MixerContext->Free(LogicalNodes);
586
587 /* done */
588 return MM_STATUS_SUCCESS;
589 }
590 else if ((Flags & MIXER_GETCONTROLDETAILSF_QUERYMASK) == MIXER_GETCONTROLDETAILSF_LISTTEXT)
591 {
592 /* sanity check */
593 ASSERT(bSet == FALSE);
594
595 /* gets the corresponding mixer data */
596 MixerData = MMixerGetMixerDataByDeviceHandle(MixerContext, MixerControl->hDevice);
597
598 /* sanity check */
599 ASSERT(MixerData);
600 ASSERT(MixerData->Topology);
601 ASSERT(MixerData->MixerInfo == MixerInfo);
602
603 /* now allocate logical pin array */
604 Status = MMixerAllocateTopologyNodeArray(MixerContext, MixerData->Topology, &LogicalNodes);
605 if (Status != MM_STATUS_SUCCESS)
606 {
607 /* no memory */
608 return MM_STATUS_NO_MEMORY;
609 }
610
611 /* allocate connected node array */
612 Status = MMixerAllocateTopologyNodeArray(MixerContext, MixerData->Topology, &ConnectedNodes);
613 if (Status != MM_STATUS_SUCCESS)
614 {
615 /* no memory */
616 MixerContext->Free(LogicalNodes);
617 return MM_STATUS_NO_MEMORY;
618 }
619
620 /* get logical pin nodes */
621 MMixerGetConnectedFromLogicalTopologyPins(MixerData->Topology, MixerControl->NodeID, &LogicalNodesCount, LogicalNodes);
622
623 /* get connected nodes */
624 MMixerGetNextNodesFromNodeIndex(MixerContext, MixerData->Topology, MixerControl->NodeID, TRUE, &ConnectedNodesCount, ConnectedNodes);
625
626 /* sanity check */
627 ASSERT(ConnectedNodesCount == LogicalNodesCount);
628 ASSERT(ConnectedNodesCount == MixerControlDetails->cMultipleItems);
629 ASSERT(ConnectedNodesCount == MixerControl->Control.Metrics.dwReserved[0]);
630
631 ListText = (LPMIXERCONTROLDETAILS_LISTTEXTW)MixerControlDetails->paDetails;
632
633 for(Index = 0; Index < ConnectedNodesCount; Index++)
634 {
635 /* getting logical pin offset */
636 MMixerGetLowestLogicalTopologyPinOffsetFromArray(LogicalNodesCount, LogicalNodes, &CurLogicalPinOffset);
637
638 /* get mixer line with that node */
639 SourceLine = MMixerGetMixerLineContainingNodeId(MixerInfo, ConnectedNodes[CurLogicalPinOffset]);
640
641 /* sanity check */
642 ASSERT(SourceLine);
643
644 DPRINT1("PinOffset %lu LogicalPin %lu NodeId %lu LineName %S\n", CurLogicalPinOffset, LogicalNodes[CurLogicalPinOffset], ConnectedNodes[CurLogicalPinOffset], SourceLine->Line.szName);
645
646 /* copy details */
647 ListText[Index].dwParam1 = SourceLine->Line.dwLineID;
648 ListText[Index].dwParam2 = SourceLine->Line.dwComponentType;
649 MixerContext->Copy(ListText[Index].szName, SourceLine->Line.szName, (wcslen(SourceLine->Line.szName) + 1) * sizeof(WCHAR));
650
651 /* mark offset as consumed */
652 LogicalNodes[CurLogicalPinOffset] = MAXULONG;
653 }
654
655 /* cleanup */
656 MixerContext->Free(LogicalNodes);
657 MixerContext->Free(ConnectedNodes);
658
659 /* done */
660 return MM_STATUS_SUCCESS;
661 }
662 }
663
664 return MM_STATUS_NOT_IMPLEMENTED;
665 }
666
667 MIXER_STATUS
668 MMixerSetGetVolumeControlDetails(
669 IN PMIXER_CONTEXT MixerContext,
670 IN LPMIXER_INFO MixerInfo,
671 IN ULONG NodeId,
672 IN ULONG bSet,
673 LPMIXERCONTROL_EXT MixerControl,
674 IN LPMIXERCONTROLDETAILS MixerControlDetails,
675 LPMIXERLINE_EXT MixerLine)
676 {
677 LPMIXERCONTROLDETAILS_UNSIGNED Input;
678 LONG Value;
679 ULONG Index, Channel = 0;
680 ULONG dwValue;
681 MIXER_STATUS Status;
682 LPMIXERVOLUME_DATA VolumeData;
683
684 if (MixerControlDetails->cbDetails != sizeof(MIXERCONTROLDETAILS_SIGNED))
685 return MM_STATUS_INVALID_PARAMETER;
686
687 VolumeData = (LPMIXERVOLUME_DATA)MixerControl->ExtraData;
688 if (!VolumeData)
689 return MM_STATUS_UNSUCCESSFUL;
690
691 /* get input */
692 Input = (LPMIXERCONTROLDETAILS_UNSIGNED)MixerControlDetails->paDetails;
693 if (!Input)
694 return MM_STATUS_UNSUCCESSFUL; /* to prevent dereferencing NULL */
695
696 if (bSet)
697 {
698 /* FIXME SEH */
699 Value = Input->dwValue;
700 Index = Value / VolumeData->InputSteppingDelta;
701
702 if (Index >= VolumeData->ValuesCount)
703 {
704 DPRINT1("Index %u out of bounds %u \n", Index, VolumeData->ValuesCount);
705 return MM_STATUS_INVALID_PARAMETER;
706 }
707
708 Value = VolumeData->Values[Index];
709 }
710
711 /* set control details */
712 if (bSet)
713 {
714 /* TODO */
715 Status = MMixerSetGetControlDetails(MixerContext, MixerControl->hDevice, NodeId, bSet, KSPROPERTY_AUDIO_VOLUMELEVEL, 0, &Value);
716 Status = MMixerSetGetControlDetails(MixerContext, MixerControl->hDevice, NodeId, bSet, KSPROPERTY_AUDIO_VOLUMELEVEL, 1, &Value);
717 }
718 else
719 {
720 Status = MMixerSetGetControlDetails(MixerContext, MixerControl->hDevice, NodeId, bSet, KSPROPERTY_AUDIO_VOLUMELEVEL, Channel, &Value);
721 }
722
723 if (!bSet)
724 {
725 dwValue = MMixerGetVolumeControlIndex(VolumeData, (LONG)Value);
726 /* FIXME SEH */
727 Input->dwValue = dwValue;
728 }
729 else
730 {
731 /* notify clients of a line change MM_MIXM_CONTROL_CHANGE with MixerControl->dwControlID */
732 MMixerNotifyControlChange(MixerContext, MixerInfo, MM_MIXM_CONTROL_CHANGE, MixerControl->Control.dwControlID);
733 }
734 return Status;
735 }
736
737 LPMIXER_DATA
738 MMixerGetDataByDeviceId(
739 IN PMIXER_LIST MixerList,
740 IN ULONG DeviceId)
741 {
742 PLIST_ENTRY Entry;
743 LPMIXER_DATA MixerData;
744
745 Entry = MixerList->MixerData.Flink;
746 while(Entry != &MixerList->MixerData)
747 {
748 MixerData = (LPMIXER_DATA)CONTAINING_RECORD(Entry, MIXER_DATA, Entry);
749 if (MixerData->DeviceId == DeviceId)
750 {
751 return MixerData;
752 }
753 Entry = Entry->Flink;
754 }
755 return NULL;
756 }
757
758 LPMIXER_DATA
759 MMixerGetDataByDeviceName(
760 IN PMIXER_LIST MixerList,
761 IN LPWSTR DeviceName)
762 {
763 PLIST_ENTRY Entry;
764 LPMIXER_DATA MixerData;
765
766 Entry = MixerList->MixerData.Flink;
767 while(Entry != &MixerList->MixerData)
768 {
769 MixerData = (LPMIXER_DATA)CONTAINING_RECORD(Entry, MIXER_DATA, Entry);
770 if (wcsicmp(&DeviceName[2], &MixerData->DeviceName[2]) == 0)
771 {
772 /* found entry */
773 return MixerData;
774 }
775 Entry = Entry->Flink;
776 }
777 return NULL;
778 }
779
780 MIXER_STATUS
781 MMixerCreateMixerData(
782 IN PMIXER_CONTEXT MixerContext,
783 IN PMIXER_LIST MixerList,
784 IN ULONG DeviceId,
785 IN LPWSTR DeviceName,
786 IN HANDLE hDevice,
787 IN HANDLE hKey)
788 {
789 LPMIXER_DATA MixerData;
790
791 MixerData = (LPMIXER_DATA)MixerContext->Alloc(sizeof(MIXER_DATA));
792 if (!MixerData)
793 return MM_STATUS_NO_MEMORY;
794
795 MixerData->DeviceId = DeviceId;
796 MixerData->DeviceName = DeviceName;
797 MixerData->hDevice = hDevice;
798 MixerData->hDeviceInterfaceKey = hKey;
799 MixerData->Topology = NULL;
800
801 InsertTailList(&MixerList->MixerData, &MixerData->Entry);
802 MixerList->MixerDataCount++;
803 return MM_STATUS_SUCCESS;
804 }
805
806 MIXER_STATUS
807 MMixerGetDeviceNameWithComponentId(
808 IN PMIXER_CONTEXT MixerContext,
809 IN HANDLE hMixer,
810 OUT LPWSTR OutDeviceName)
811 {
812 MIXER_STATUS Status;
813 KSPROPERTY Property;
814 KSCOMPONENTID ComponentId;
815 ULONG Length;
816 UNICODE_STRING GuidString;
817 ULONG ResultLength, KeyType;
818 HANDLE hMediaKey, hGuidKey;
819 LPWSTR DeviceName;
820
821 /* prepare property */
822 Property.Flags = KSPROPERTY_TYPE_GET;
823 Property.Set = KSPROPSETID_General;
824 Property.Id = KSPROPERTY_GENERAL_COMPONENTID;
825
826 /* try get component id */
827 Status = MixerContext->Control(hMixer, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), &ComponentId, sizeof(KSCOMPONENTID), &Length);
828
829 if (Status == MM_STATUS_SUCCESS)
830 {
831 Status = MixerContext->OpenKey(NULL, L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Control\\MediaCategories", KEY_READ, &hMediaKey);
832 if (Status == MM_STATUS_SUCCESS)
833 {
834 RtlStringFromGUID(&ComponentId.Name, &GuidString);
835 Status = MixerContext->OpenKey(hMediaKey, GuidString.Buffer, KEY_READ, &hGuidKey);
836 RtlFreeUnicodeString(&GuidString);
837 if (Status == MM_STATUS_SUCCESS)
838 {
839 Status = MixerContext->QueryKeyValue(hGuidKey, L"Name", (PVOID*)&DeviceName, &ResultLength, &KeyType);
840 if (Status == MM_STATUS_SUCCESS)
841 {
842 MixerContext->Copy(OutDeviceName, DeviceName, min(ResultLength, (MAXPNAMELEN-1)*2));
843 MixerContext->Free(DeviceName);
844 }
845
846 MixerContext->CloseKey(hGuidKey);
847 }
848 MixerContext->CloseKey(hMediaKey);
849 }
850 }
851 return Status;
852 }
853
854 MIXER_STATUS
855 MMixerGetDeviceName(
856 IN PMIXER_CONTEXT MixerContext,
857 OUT LPWSTR DeviceName,
858 IN HANDLE hKey)
859 {
860 LPWSTR Name;
861 HANDLE hTemp;
862 ULONG Length;
863 ULONG Type;
864 MIXER_STATUS Status;
865
866 Status = MixerContext->QueryKeyValue(hKey, L"FriendlyName", (PVOID*)&Name, &Length, &Type);
867 if (Status == MM_STATUS_SUCCESS)
868 {
869 /* copy device name */
870 MixerContext->Copy(DeviceName, Name, min(wcslen(Name), MAXPNAMELEN-1) * sizeof(WCHAR));
871
872 /* make sure its null terminated */
873 DeviceName[MAXPNAMELEN-1] = L'\0';
874
875 /* free device name */
876 MixerContext->Free(Name);
877
878 /* done */
879 return Status;
880 }
881
882 Status = MixerContext->OpenKey(hKey, L"Device Parameters", KEY_READ, &hTemp);
883 if (Status != MM_STATUS_SUCCESS)
884 return Status;
885
886 Status = MixerContext->QueryKeyValue(hTemp, L"FriendlyName", (PVOID*)&Name, &Length, &Type);
887 if (Status == MM_STATUS_SUCCESS)
888 {
889 /* copy device name */
890 MixerContext->Copy(DeviceName, Name, min(wcslen(Name), MAXPNAMELEN-1) * sizeof(WCHAR));
891
892 /* make sure its null terminated */
893 DeviceName[MAXPNAMELEN-1] = L'\0';
894
895 /* free device name */
896 MixerContext->Free(Name);
897 }
898
899 MixerContext->CloseKey(hTemp);
900 return Status;
901 }
902
903 VOID
904 MMixerInitializePinConnect(
905 IN OUT PKSPIN_CONNECT PinConnect,
906 IN ULONG PinId)
907 {
908 PinConnect->Interface.Set = KSINTERFACESETID_Standard;
909 PinConnect->Interface.Id = KSINTERFACE_STANDARD_STREAMING;
910 PinConnect->Interface.Flags = 0;
911 PinConnect->Medium.Set = KSMEDIUMSETID_Standard;
912 PinConnect->Medium.Id = KSMEDIUM_TYPE_ANYINSTANCE;
913 PinConnect->Medium.Flags = 0;
914 PinConnect->PinToHandle = NULL;
915 PinConnect->PinId = PinId;
916 PinConnect->Priority.PriorityClass = KSPRIORITY_NORMAL;
917 PinConnect->Priority.PrioritySubClass = 1;
918 }