db59c0b25a984969d9ca77d080c73a2b7820f54f
[reactos.git] / reactos / drivers / wdm / audio / legacy / wdmaud / mixer.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Kernel Streaming
4 * FILE: drivers/wdm/audio/legacy/wdmaud/mixer.c
5 * PURPOSE: System Audio graph builder
6 * PROGRAMMER: Andrew Greenwood
7 * Johannes Anderwald
8 */
9 #include "wdmaud.h"
10
11 const GUID KSNODETYPE_DAC = {0x507AE360L, 0xC554, 0x11D0, {0x8A, 0x2B, 0x00, 0xA0, 0xC9, 0x25, 0x5A, 0xC1}};
12 const GUID KSNODETYPE_ADC = {0x4D837FE0L, 0xC555, 0x11D0, {0x8A, 0x2B, 0x00, 0xA0, 0xC9, 0x25, 0x5A, 0xC1}};
13 const GUID KSNODETYPE_AGC = {0xE88C9BA0L, 0xC557, 0x11D0, {0x8A, 0x2B, 0x00, 0xA0, 0xC9, 0x25, 0x5A, 0xC1}};
14 const GUID KSNODETYPE_LOUDNESS = {0x41887440L, 0xC558, 0x11D0, {0x8A, 0x2B, 0x00, 0xA0, 0xC9, 0x25, 0x5A, 0xC1}};
15 const GUID KSNODETYPE_MUTE = {0x02B223C0L, 0xC557, 0x11D0, {0x8A, 0x2B, 0x00, 0xA0, 0xC9, 0x25, 0x5A, 0xC1}};
16 const GUID KSNODETYPE_TONE = {0x7607E580L, 0xC557, 0x11D0, {0x8A, 0x2B, 0x00, 0xA0, 0xC9, 0x25, 0x5A, 0xC1}};
17 const GUID KSNODETYPE_VOLUME = {0x3A5ACC00L, 0xC557, 0x11D0, {0x8A, 0x2B, 0x00, 0xA0, 0xC9, 0x25, 0x5A, 0xC1}};
18 const GUID KSNODETYPE_PEAKMETER = {0xa085651e, 0x5f0d, 0x4b36, {0xa8, 0x69, 0xd1, 0x95, 0xd6, 0xab, 0x4b, 0x9e}};
19 const GUID KSNODETYPE_MUX = {0x2CEAF780, 0xC556, 0x11D0, {0x8A, 0x2B, 0x00, 0xA0, 0xC9, 0x25, 0x5A, 0xC1}};
20 const GUID KSNODETYPE_STEREO_WIDE = {0xA9E69800L, 0xC558, 0x11D0, {0x8A, 0x2B, 0x00, 0xA0, 0xC9, 0x25, 0x5A, 0xC1}};
21 const GUID KSNODETYPE_CHORUS = {0x20173F20L, 0xC559, 0x11D0, {0x8A, 0x2B, 0x00, 0xA0, 0xC9, 0x25, 0x5A, 0xC1}};
22 const GUID KSNODETYPE_REVERB = {0xEF0328E0L, 0xC558, 0x11D0, {0x8A, 0x2B, 0x00, 0xA0, 0xC9, 0x25, 0x5A, 0xC1}};
23 const GUID KSNODETYPE_SUPERMIX = {0xE573ADC0L, 0xC555, 0x11D0, {0x8A, 0x2B, 0x00, 0xA0, 0xC9, 0x25, 0x5A, 0xC1}};
24 const GUID KSNODETYPE_SUM = {0xDA441A60L, 0xC556, 0x11D0, {0x8A, 0x2B, 0x00, 0xA0, 0xC9, 0x25, 0x5A, 0xC1}};
25 const GUID KSPROPSETID_Audio = {0x45FFAAA0L, 0x6E1B, 0x11D0, {0xBC, 0xF2, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}};
26
27 #define DESTINATION_LINE 0xFFFF0000
28
29 LPMIXERLINE_EXT
30 GetSourceMixerLine(
31 LPMIXER_INFO MixerInfo,
32 DWORD dwSource)
33 {
34 PLIST_ENTRY Entry;
35 LPMIXERLINE_EXT MixerLineSrc;
36
37 /* get first entry */
38 Entry = MixerInfo->LineList.Flink;
39
40 while(Entry != &MixerInfo->LineList)
41 {
42 MixerLineSrc = (LPMIXERLINE_EXT)CONTAINING_RECORD(Entry, MIXERLINE_EXT, Entry);
43 DPRINT("dwSource %x dwSource %x\n", MixerLineSrc->Line.dwSource, dwSource);
44 if (MixerLineSrc->Line.dwSource == dwSource)
45 return MixerLineSrc;
46
47 Entry = Entry->Flink;
48 }
49
50 return NULL;
51 }
52
53 LPMIXERCONTROL_DATA
54 GetMixerControlDataById(
55 PLIST_ENTRY ListHead,
56 DWORD dwControlId)
57 {
58 PLIST_ENTRY Entry;
59 LPMIXERCONTROL_DATA Control;
60
61 /* get first entry */
62 Entry = ListHead->Flink;
63
64 while(Entry != ListHead)
65 {
66 Control = (LPMIXERCONTROL_DATA)CONTAINING_RECORD(Entry, MIXERCONTROL_DATA, Entry);
67 DPRINT("dwSource %x dwSource %x\n", Control->dwControlID, dwControlId);
68 if (Control->dwControlID == dwControlId)
69 return Control;
70
71 Entry = Entry->Flink;
72 }
73 return NULL;
74 }
75
76 NTSTATUS
77 GetMixerControlById(
78 LPMIXER_INFO MixerInfo,
79 DWORD dwControlID,
80 LPMIXERLINE_EXT *MixerLine,
81 LPMIXERCONTROLW *MixerControl,
82 PULONG NodeId)
83 {
84 PLIST_ENTRY Entry;
85 LPMIXERLINE_EXT MixerLineSrc;
86 ULONG Index;
87
88 /* get first entry */
89 Entry = MixerInfo->LineList.Flink;
90
91 while(Entry != &MixerInfo->LineList)
92 {
93 MixerLineSrc = (LPMIXERLINE_EXT)CONTAINING_RECORD(Entry, MIXERLINE_EXT, Entry);
94
95 for(Index = 0; Index < MixerLineSrc->Line.cControls; Index++)
96 {
97 if (MixerLineSrc->LineControls[Index].dwControlID == dwControlID)
98 {
99 if (MixerLine)
100 *MixerLine = MixerLineSrc;
101 if (MixerControl)
102 *MixerControl = &MixerLineSrc->LineControls[Index];
103 if (NodeId)
104 *NodeId = MixerLineSrc->NodeIds[Index];
105 return STATUS_SUCCESS;
106 }
107 }
108 Entry = Entry->Flink;
109 }
110
111 return STATUS_NOT_FOUND;
112 }
113
114 LPMIXERLINE_EXT
115 GetSourceMixerLineByComponentType(
116 LPMIXER_INFO MixerInfo,
117 DWORD dwComponentType)
118 {
119 PLIST_ENTRY Entry;
120 LPMIXERLINE_EXT MixerLineSrc;
121
122 /* get first entry */
123 Entry = MixerInfo->LineList.Flink;
124
125 while(Entry != &MixerInfo->LineList)
126 {
127 MixerLineSrc = (LPMIXERLINE_EXT)CONTAINING_RECORD(Entry, MIXERLINE_EXT, Entry);
128 if (MixerLineSrc->Line.dwComponentType == dwComponentType)
129 return MixerLineSrc;
130
131 Entry = Entry->Flink;
132 }
133
134 return NULL;
135 }
136
137 LPMIXERLINE_EXT
138 GetSourceMixerLineByLineId(
139 LPMIXER_INFO MixerInfo,
140 DWORD dwLineID)
141 {
142 PLIST_ENTRY Entry;
143 LPMIXERLINE_EXT MixerLineSrc;
144
145 /* get first entry */
146 Entry = MixerInfo->LineList.Flink;
147
148 while(Entry != &MixerInfo->LineList)
149 {
150 MixerLineSrc = (LPMIXERLINE_EXT)CONTAINING_RECORD(Entry, MIXERLINE_EXT, Entry);
151 DPRINT("dwLineID %x dwLineID %x\n", MixerLineSrc->Line.dwLineID, dwLineID);
152 if (MixerLineSrc->Line.dwLineID == dwLineID)
153 return MixerLineSrc;
154
155 Entry = Entry->Flink;
156 }
157
158 return NULL;
159 }
160
161
162
163 ULONG
164 GetPinCount(
165 IN PFILE_OBJECT FileObject)
166 {
167 KSPROPERTY Pin;
168 NTSTATUS Status;
169 ULONG NumPins, BytesReturned;
170
171 Pin.Flags = KSPROPERTY_TYPE_GET;
172 Pin.Set = KSPROPSETID_Pin;
173 Pin.Id = KSPROPERTY_PIN_CTYPES;
174
175 Status = KsSynchronousIoControlDevice(FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSPROPERTY), (PVOID)&NumPins, sizeof(ULONG), &BytesReturned);
176 if (!NT_SUCCESS(Status))
177 return 0;
178
179 return NumPins;
180 }
181
182
183 ULONG
184 GetSysAudioDeviceCount(
185 IN PDEVICE_OBJECT DeviceObject)
186 {
187 PWDMAUD_DEVICE_EXTENSION DeviceExtension;
188 KSPROPERTY Pin;
189 ULONG Count, BytesReturned;
190 NTSTATUS Status;
191
192 /* setup the query request */
193 Pin.Set = KSPROPSETID_Sysaudio;
194 Pin.Id = KSPROPERTY_SYSAUDIO_DEVICE_COUNT;
195 Pin.Flags = KSPROPERTY_TYPE_GET;
196
197 DeviceExtension = (PWDMAUD_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
198
199 /* query sysaudio for the device count */
200 Status = KsSynchronousIoControlDevice(DeviceExtension->FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSPROPERTY), (PVOID)&Count, sizeof(ULONG), &BytesReturned);
201 if (!NT_SUCCESS(Status))
202 return 0;
203
204 return Count;
205 }
206
207 NTSTATUS
208 GetSysAudioDevicePnpName(
209 IN PDEVICE_OBJECT DeviceObject,
210 IN ULONG DeviceIndex,
211 OUT LPWSTR * Device)
212 {
213 ULONG BytesReturned;
214 KSP_PIN Pin;
215 NTSTATUS Status;
216 PWDMAUD_DEVICE_EXTENSION DeviceExtension;
217
218 /* first check if the device index is within bounds */
219 if (DeviceIndex >= GetSysAudioDeviceCount(DeviceObject))
220 return STATUS_INVALID_PARAMETER;
221
222 /* setup the query request */
223 Pin.Property.Set = KSPROPSETID_Sysaudio;
224 Pin.Property.Id = KSPROPERTY_SYSAUDIO_DEVICE_INTERFACE_NAME;
225 Pin.Property.Flags = KSPROPERTY_TYPE_GET;
226 Pin.PinId = DeviceIndex;
227
228 DeviceExtension = (PWDMAUD_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
229
230 /* query sysaudio for the device path */
231 Status = KsSynchronousIoControlDevice(DeviceExtension->FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSPROPERTY) + sizeof(ULONG), NULL, 0, &BytesReturned);
232
233 /* check if the request failed */
234 if (Status != STATUS_BUFFER_TOO_SMALL || BytesReturned == 0)
235 return STATUS_UNSUCCESSFUL;
236
237 /* allocate buffer for the device */
238 *Device = ExAllocatePool(NonPagedPool, BytesReturned);
239 if (!Device)
240 return STATUS_INSUFFICIENT_RESOURCES;
241
242 /* query sysaudio again for the device path */
243 Status = KsSynchronousIoControlDevice(DeviceExtension->FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSPROPERTY) + sizeof(ULONG), (PVOID)*Device, BytesReturned, &BytesReturned);
244
245 if (!NT_SUCCESS(Status))
246 {
247 /* failed */
248 ExFreePool(*Device);
249 return Status;
250 }
251
252 return Status;
253 }
254
255 ULONG
256 GetDeviceIndexFromPnpName(
257 IN PDEVICE_OBJECT DeviceObject,
258 LPWSTR Device)
259 {
260 ULONG Count, Index;
261 LPWSTR DeviceName;
262 NTSTATUS Status;
263
264 /* get device count */
265 Count = GetSysAudioDeviceCount(DeviceObject);
266
267 if (!Count)
268 return MAXULONG;
269
270 for(Index = 0; Index < Count; Index++)
271 {
272 /* get device name */
273 Status = GetSysAudioDevicePnpName(DeviceObject, Index, &DeviceName);
274 if (NT_SUCCESS(Status))
275 {
276 if (!wcsicmp(Device, DeviceName))
277 {
278 /* found device index */
279 ExFreePool(DeviceName);
280 return Index;
281 }
282 ExFreePool(DeviceName);
283 }
284 }
285
286 return MAXULONG;
287 }
288
289
290 NTSTATUS
291 OpenDevice(
292 IN LPWSTR Device,
293 OUT PHANDLE DeviceHandle,
294 OUT PFILE_OBJECT * FileObject)
295 {
296 NTSTATUS Status;
297 HANDLE hDevice;
298
299 /* now open the device */
300 Status = WdmAudOpenSysAudioDevice(Device, &hDevice);
301
302 if (!NT_SUCCESS(Status))
303 {
304 return Status;
305 }
306
307 *DeviceHandle = hDevice;
308
309 if (FileObject)
310 {
311 Status = ObReferenceObjectByHandle(hDevice, FILE_READ_DATA | FILE_WRITE_DATA, IoFileObjectType, KernelMode, (PVOID*)FileObject, NULL);
312
313 if (!NT_SUCCESS(Status))
314 {
315 ZwClose(hDevice);
316 }
317 }
318
319 return Status;
320
321 }
322
323
324 NTSTATUS
325 OpenSysAudioDeviceByIndex(
326 IN PDEVICE_OBJECT DeviceObject,
327 IN ULONG DeviceIndex,
328 IN PHANDLE DeviceHandle,
329 IN PFILE_OBJECT * FileObject)
330 {
331 LPWSTR Device = NULL;
332 NTSTATUS Status;
333
334 Status = GetSysAudioDevicePnpName(DeviceObject, DeviceIndex, &Device);
335 if (!NT_SUCCESS(Status))
336 return Status;
337
338 Status = OpenDevice(Device, DeviceHandle, FileObject);
339
340 /* free device buffer */
341 ExFreePool(Device);
342
343 return Status;
344 }
345
346 NTSTATUS
347 GetFilterNodeProperty(
348 IN PFILE_OBJECT FileObject,
349 IN ULONG PropertyId,
350 PKSMULTIPLE_ITEM * Item)
351 {
352 NTSTATUS Status;
353 ULONG BytesReturned;
354 PKSMULTIPLE_ITEM MultipleItem;
355 KSPROPERTY Property;
356
357 /* setup query request */
358 Property.Id = PropertyId;
359 Property.Flags = KSPROPERTY_TYPE_GET;
360 Property.Set = KSPROPSETID_Topology;
361
362 /* query for required size */
363 Status = KsSynchronousIoControlDevice(FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), NULL, 0, &BytesReturned);
364
365 /* check for success */
366 if (Status != STATUS_MORE_ENTRIES)
367 return Status;
368
369 /* allocate buffer */
370 MultipleItem = (PKSMULTIPLE_ITEM)ExAllocatePool(NonPagedPool, BytesReturned);
371 if (!MultipleItem)
372 return STATUS_INSUFFICIENT_RESOURCES;
373
374 /* query for required size */
375 Status = KsSynchronousIoControlDevice(FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)MultipleItem, BytesReturned, &BytesReturned);
376
377 if (!NT_SUCCESS(Status))
378 {
379 /* failed */
380 ExFreePool(MultipleItem);
381 return Status;
382 }
383
384 *Item = MultipleItem;
385 return Status;
386 }
387
388 ULONG
389 CountNodeType(
390 PKSMULTIPLE_ITEM MultipleItem,
391 LPGUID NodeType)
392 {
393 ULONG Count;
394 ULONG Index;
395 LPGUID Guid;
396
397 Count = 0;
398 Guid = (LPGUID)(MultipleItem+1);
399
400 /* iterate through node type array */
401 for(Index = 0; Index < MultipleItem->Count; Index++)
402 {
403 if (IsEqualGUIDAligned(NodeType, Guid))
404 {
405 /* found matching guid */
406 Count++;
407 }
408 Guid++;
409 }
410 return Count;
411 }
412
413 ULONG
414 GetNodeTypeIndex(
415 PKSMULTIPLE_ITEM MultipleItem,
416 LPGUID NodeType)
417 {
418 ULONG Index;
419 LPGUID Guid;
420
421 Guid = (LPGUID)(MultipleItem+1);
422
423 /* iterate through node type array */
424 for(Index = 0; Index < MultipleItem->Count; Index++)
425 {
426 if (IsEqualGUIDAligned(NodeType, Guid))
427 {
428 /* found matching guid */
429 return Index;
430 }
431 Guid++;
432 }
433 return MAXULONG;
434 }
435
436 ULONG
437 GetControlTypeFromTopologyNode(
438 IN LPGUID NodeType)
439 {
440 if (IsEqualGUIDAligned(NodeType, (LPGUID)&KSNODETYPE_AGC))
441 {
442 // automatic gain control
443 return MIXERCONTROL_CONTROLTYPE_ONOFF;
444 }
445 else if (IsEqualGUIDAligned(NodeType, (LPGUID)&KSNODETYPE_LOUDNESS))
446 {
447 // loudness control
448 return MIXERCONTROL_CONTROLTYPE_LOUDNESS;
449 }
450 else if (IsEqualGUIDAligned(NodeType, (LPGUID)&KSNODETYPE_MUTE ))
451 {
452 // mute control
453 return MIXERCONTROL_CONTROLTYPE_MUTE;
454 }
455 else if (IsEqualGUIDAligned(NodeType, (LPGUID)&KSNODETYPE_TONE))
456 {
457 // tpne control
458 //FIXME
459 // MIXERCONTROL_CONTROLTYPE_ONOFF if KSPROPERTY_AUDIO_BASS_BOOST is supported
460 // MIXERCONTROL_CONTROLTYPE_BASS if KSPROPERTY_AUDIO_BASS is supported
461 // MIXERCONTROL_CONTROLTYPE_TREBLE if KSPROPERTY_AUDIO_TREBLE is supported
462 UNIMPLEMENTED;
463 return MIXERCONTROL_CONTROLTYPE_ONOFF;
464 }
465 else if (IsEqualGUIDAligned(NodeType, (LPGUID)&KSNODETYPE_VOLUME))
466 {
467 // volume control
468 return MIXERCONTROL_CONTROLTYPE_VOLUME;
469 }
470 else if (IsEqualGUIDAligned(NodeType, (LPGUID)&KSNODETYPE_PEAKMETER))
471 {
472 // peakmeter control
473 return MIXERCONTROL_CONTROLTYPE_PEAKMETER;
474 }
475 else if (IsEqualGUIDAligned(NodeType, (LPGUID)&KSNODETYPE_MUX))
476 {
477 // mux control
478 return MIXERCONTROL_CONTROLTYPE_MUX;
479 }
480 else if (IsEqualGUIDAligned(NodeType, (LPGUID)&KSNODETYPE_MUX))
481 {
482 // mux control
483 return MIXERCONTROL_CONTROLTYPE_MUX;
484 }
485 else if (IsEqualGUIDAligned(NodeType, (LPGUID)&KSNODETYPE_STEREO_WIDE))
486 {
487 // stero wide control
488 return MIXERCONTROL_CONTROLTYPE_FADER;
489 }
490 else if (IsEqualGUIDAligned(NodeType, (LPGUID)&KSNODETYPE_CHORUS))
491 {
492 // chorus control
493 return MIXERCONTROL_CONTROLTYPE_FADER;
494 }
495 else if (IsEqualGUIDAligned(NodeType, (LPGUID)&KSNODETYPE_REVERB))
496 {
497 // reverb control
498 return MIXERCONTROL_CONTROLTYPE_FADER;
499 }
500 else if (IsEqualGUIDAligned(NodeType, (LPGUID)&KSNODETYPE_SUPERMIX))
501 {
502 // supermix control
503 // MIXERCONTROL_CONTROLTYPE_MUTE if KSPROPERTY_AUDIO_MUTE is supported
504 UNIMPLEMENTED;
505 return MIXERCONTROL_CONTROLTYPE_VOLUME;
506 }
507 UNIMPLEMENTED
508 return 0;
509 }
510
511 NTSTATUS
512 GetPhysicalConnection(
513 IN PFILE_OBJECT FileObject,
514 IN ULONG PinId,
515 OUT PKSPIN_PHYSICALCONNECTION *OutConnection)
516 {
517 KSP_PIN Pin;
518 NTSTATUS Status;
519 ULONG BytesReturned;
520 PKSPIN_PHYSICALCONNECTION Connection;
521
522 /* setup the request */
523 Pin.Property.Flags = KSPROPERTY_TYPE_GET;
524 Pin.Property.Id = KSPROPERTY_PIN_PHYSICALCONNECTION;
525 Pin.Property.Set = KSPROPSETID_Pin;
526 Pin.PinId = PinId;
527
528 /* query the pin for the physical connection */
529 Status = KsSynchronousIoControlDevice(FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSP_PIN), NULL, 0, &BytesReturned);
530
531 if (Status == STATUS_NOT_FOUND)
532 {
533 /* pin does not have a physical connection */
534 return Status;
535 }
536
537 Connection = ExAllocatePool(NonPagedPool, BytesReturned);
538 if (!Connection)
539 {
540 /* not enough memory */
541 return STATUS_INSUFFICIENT_RESOURCES;
542 }
543
544 /* query the pin for the physical connection */
545 Status = KsSynchronousIoControlDevice(FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSP_PIN), (PVOID)Connection, BytesReturned, &BytesReturned);
546 if (!NT_SUCCESS(Status))
547 {
548 /* failed to query the physical connection */
549 ExFreePool(Connection);
550 return Status;
551 }
552
553 /* store connection */
554 *OutConnection = Connection;
555 return Status;
556 }
557
558 NTSTATUS
559 GetNodeIndexes(
560 IN PKSMULTIPLE_ITEM MultipleItem,
561 IN ULONG NodeIndex,
562 IN ULONG bNode,
563 IN ULONG bFrom,
564 OUT PULONG NodeReferenceCount,
565 OUT PULONG *NodeReference)
566 {
567 ULONG Index, Count = 0;
568 PKSTOPOLOGY_CONNECTION Connection;
569 PULONG Refs;
570
571 /* KSMULTIPLE_ITEM is followed by several KSTOPOLOGY_CONNECTION */
572 Connection = (PKSTOPOLOGY_CONNECTION)(MultipleItem + 1);
573
574 /* first count all referenced nodes */
575 for(Index = 0; Index < MultipleItem->Count; Index++)
576 {
577 //DbgPrint("FromPin %u FromNode %u ToPin %u ToNode %u\n", Connection->FromNodePin, Connection->FromNode, Connection->ToNodePin, Connection->ToNode);
578 if (bNode)
579 {
580 if (bFrom)
581 {
582 if (Connection->FromNode == NodeIndex)
583 {
584 /* node id has a connection */
585 Count++;
586 }
587 }
588 else
589 {
590 if (Connection->ToNode == NodeIndex)
591 {
592 /* node id has a connection */
593 Count++;
594 }
595 }
596 }
597 else
598 {
599 if (bFrom)
600 {
601 if (Connection->FromNodePin == NodeIndex && Connection->FromNode == KSFILTER_NODE)
602 {
603 /* node id has a connection */
604 Count++;
605 }
606 }
607 else
608 {
609 if (Connection->ToNodePin == NodeIndex && Connection->ToNode == KSFILTER_NODE)
610 {
611 /* node id has a connection */
612 Count++;
613 }
614 }
615 }
616
617
618 /* move to next connection */
619 Connection++;
620 }
621
622 ASSERT(Count != 0);
623
624 /* now allocate node index array */
625 Refs = ExAllocatePool(NonPagedPool, sizeof(ULONG) * Count);
626 if (!Refs)
627 {
628 /* not enough memory */
629 return STATUS_INSUFFICIENT_RESOURCES;
630 }
631
632 /* clear node index array */
633 RtlZeroMemory(Refs, Count * sizeof(ULONG));
634
635 Count = 0;
636 Connection = (PKSTOPOLOGY_CONNECTION)(MultipleItem + 1);
637 for(Index = 0; Index < MultipleItem->Count; Index++)
638 {
639 if (bNode)
640 {
641 if (bFrom)
642 {
643 if (Connection->FromNode == NodeIndex)
644 {
645 /* node id has a connection */
646 Refs[Count] = Index;
647 Count++;
648 }
649 }
650 else
651 {
652 if (Connection->ToNode == NodeIndex)
653 {
654 /* node id has a connection */
655 Refs[Count] = Index;
656 Count++;
657 }
658 }
659 }
660 else
661 {
662 if (bFrom)
663 {
664 if (Connection->FromNodePin == NodeIndex && Connection->FromNode == KSFILTER_NODE)
665 {
666 /* node id has a connection */
667 Refs[Count] = Index;
668 Count++;
669 }
670 }
671 else
672 {
673 if (Connection->ToNodePin == NodeIndex && Connection->ToNode == KSFILTER_NODE)
674 {
675 /* node id has a connection */
676 Refs[Count] = Index;
677 Count++;
678 }
679 }
680 }
681
682 /* move to next connection */
683 Connection++;
684 }
685
686 /* store result */
687 *NodeReference = Refs;
688 *NodeReferenceCount = Count;
689
690 return STATUS_SUCCESS;
691 }
692
693
694 NTSTATUS
695 GetTargetPinsByNodeConnectionIndex(
696 IN PKSMULTIPLE_ITEM NodeConnections,
697 IN PKSMULTIPLE_ITEM NodeTypes,
698 IN ULONG bUpDirection,
699 IN ULONG NodeConnectionIndex,
700 OUT PULONG Pins)
701 {
702 PKSTOPOLOGY_CONNECTION Connection;
703 ULONG PinId, NodeConnectionCount, Index;
704 PULONG NodeConnection;
705 NTSTATUS Status;
706
707
708 /* sanity check */
709 ASSERT(NodeConnectionIndex < NodeConnections->Count);
710
711 Connection = (PKSTOPOLOGY_CONNECTION)(NodeConnections + 1);
712
713 DPRINT("FromNode %u FromNodePin %u -> ToNode %u ToNodePin %u\n", Connection[NodeConnectionIndex].FromNode, Connection[NodeConnectionIndex].FromNodePin, Connection[NodeConnectionIndex].ToNode, Connection[NodeConnectionIndex].ToNodePin );
714
715 if ((Connection[NodeConnectionIndex].ToNode == KSFILTER_NODE && bUpDirection == FALSE) ||
716 (Connection[NodeConnectionIndex].FromNode == KSFILTER_NODE && bUpDirection == TRUE))
717 {
718 /* iteration stops here */
719 if (bUpDirection)
720 PinId = Connection[NodeConnectionIndex].FromNodePin;
721 else
722 PinId = Connection[NodeConnectionIndex].ToNodePin;
723
724 DPRINT("GetTargetPinsByNodeIndex FOUND Target Pin %u Parsed %u\n", PinId, Pins[PinId]);
725
726 /* mark pin index as a target pin */
727 Pins[PinId] = TRUE;
728 return STATUS_SUCCESS;
729 }
730
731 /* get all node indexes referenced by that node */
732 if (bUpDirection)
733 {
734 Status = GetNodeIndexes(NodeConnections, Connection[NodeConnectionIndex].FromNode, TRUE, FALSE, &NodeConnectionCount, &NodeConnection);
735 }
736 else
737 {
738 Status = GetNodeIndexes(NodeConnections, Connection[NodeConnectionIndex].ToNode, TRUE, TRUE, &NodeConnectionCount, &NodeConnection);
739 }
740
741 if (NT_SUCCESS(Status))
742 {
743 for(Index = 0; Index < NodeConnectionCount; Index++)
744 {
745 /* iterate recursively into the nodes */
746 Status = GetTargetPinsByNodeConnectionIndex(NodeConnections, NodeTypes, bUpDirection, NodeConnection[Index], Pins);
747 ASSERT(Status == STATUS_SUCCESS);
748 }
749 /* free node connection indexes */
750 ExFreePool(NodeConnection);
751 }
752
753 return Status;
754 }
755
756
757
758 NTSTATUS
759 GetTargetPins(
760 PKSMULTIPLE_ITEM NodeTypes,
761 PKSMULTIPLE_ITEM NodeConnections,
762 IN ULONG NodeIndex,
763 IN ULONG bUpDirection,
764 PULONG Pins,
765 ULONG PinCount)
766 {
767 ULONG NodeConnectionCount, Index;
768 NTSTATUS Status;
769 PULONG NodeConnection;
770
771 /* sanity check */
772 ASSERT(NodeIndex != (ULONG)-1);
773
774 /* get all node indexes referenced by that pin */
775 if (bUpDirection)
776 Status = GetNodeIndexes(NodeConnections, NodeIndex, TRUE, FALSE, &NodeConnectionCount, &NodeConnection);
777 else
778 Status = GetNodeIndexes(NodeConnections, NodeIndex, TRUE, TRUE, &NodeConnectionCount, &NodeConnection);
779
780 DPRINT("NodeIndex %u Status %x Count %u\n", NodeIndex, Status, NodeConnectionCount);
781
782 if (NT_SUCCESS(Status))
783 {
784 for(Index = 0; Index < NodeConnectionCount; Index++)
785 {
786 Status = GetTargetPinsByNodeConnectionIndex(NodeConnections, NodeTypes, bUpDirection, NodeConnection[Index], Pins);
787 ASSERT(Status == STATUS_SUCCESS);
788 }
789 ExFreePool(NodeConnection);
790 }
791
792 return Status;
793 }
794
795 PULONG
796 AllocatePinArray(
797 ULONG PinCount)
798 {
799 PULONG Pins = ExAllocatePool(NonPagedPool, PinCount * sizeof(ULONG));
800 if (!Pins)
801 return NULL;
802
803 RtlZeroMemory(Pins, sizeof(ULONG) * PinCount);
804
805 return Pins;
806 }
807
808 PKSTOPOLOGY_CONNECTION
809 GetConnectionByIndex(
810 IN PKSMULTIPLE_ITEM MultipleItem,
811 IN ULONG Index)
812 {
813 PKSTOPOLOGY_CONNECTION Descriptor;
814
815 ASSERT(Index < MultipleItem->Count);
816
817 Descriptor = (PKSTOPOLOGY_CONNECTION)(MultipleItem + 1);
818 return &Descriptor[Index];
819 }
820
821 LPGUID
822 GetNodeType(
823 IN PKSMULTIPLE_ITEM MultipleItem,
824 IN ULONG Index)
825 {
826 LPGUID NodeType;
827
828 ASSERT(Index < MultipleItem->Count);
829
830 NodeType = (LPGUID)(MultipleItem + 1);
831 return &NodeType[Index];
832 }
833
834 NTSTATUS
835 GetControlsFromPinByConnectionIndex(
836 IN PKSMULTIPLE_ITEM NodeConnections,
837 IN PKSMULTIPLE_ITEM NodeTypes,
838 IN ULONG bUpDirection,
839 IN ULONG NodeConnectionIndex,
840 OUT PULONG Nodes)
841 {
842 PKSTOPOLOGY_CONNECTION CurConnection;
843 LPGUID NodeType;
844 ULONG NodeIndex;
845 NTSTATUS Status;
846 ULONG NodeConnectionCount, Index;
847 PULONG NodeConnection;
848
849
850 /* get current connection */
851 CurConnection = GetConnectionByIndex(NodeConnections, NodeConnectionIndex);
852
853 if (bUpDirection)
854 NodeIndex = CurConnection->FromNode;
855 else
856 NodeIndex = CurConnection->ToNode;
857
858 /* get target node type of current connection */
859 NodeType = GetNodeType(NodeTypes, NodeIndex);
860
861 if (IsEqualGUIDAligned(NodeType, &KSNODETYPE_SUM) || IsEqualGUIDAligned(NodeType, &KSNODETYPE_MUX))
862 {
863 if (bUpDirection)
864 {
865 /* add the sum / mux node to destination line */
866 Nodes[NodeIndex] = TRUE;
867 }
868
869 return STATUS_SUCCESS;
870 }
871
872 /* now add the node */
873 Nodes[NodeIndex] = TRUE;
874
875
876 /* get all node indexes referenced by that node */
877 if (bUpDirection)
878 {
879 Status = GetNodeIndexes(NodeConnections, NodeIndex, TRUE, FALSE, &NodeConnectionCount, &NodeConnection);
880 }
881 else
882 {
883 Status = GetNodeIndexes(NodeConnections, NodeIndex, TRUE, TRUE, &NodeConnectionCount, &NodeConnection);
884 }
885
886 if (NT_SUCCESS(Status))
887 {
888 for(Index = 0; Index < NodeConnectionCount; Index++)
889 {
890 /* iterate recursively into the nodes */
891 Status = GetControlsFromPinByConnectionIndex(NodeConnections, NodeTypes, bUpDirection, NodeConnection[Index], Nodes);
892 ASSERT(Status == STATUS_SUCCESS);
893 }
894 /* free node connection indexes */
895 ExFreePool(NodeConnection);
896 }
897
898 return Status;
899 }
900
901 NTSTATUS
902 GetControlsFromPin(
903 IN PKSMULTIPLE_ITEM NodeConnections,
904 IN PKSMULTIPLE_ITEM NodeTypes,
905 IN ULONG PinId,
906 IN ULONG bUpDirection,
907 OUT PULONG Nodes)
908 {
909 ULONG NodeConnectionCount, Index;
910 NTSTATUS Status;
911 PULONG NodeConnection;
912
913 /* sanity check */
914 ASSERT(PinId != (ULONG)-1);
915
916 /* get all node indexes referenced by that pin */
917 if (bUpDirection)
918 Status = GetNodeIndexes(NodeConnections, PinId, FALSE, FALSE, &NodeConnectionCount, &NodeConnection);
919 else
920 Status = GetNodeIndexes(NodeConnections, PinId, FALSE, TRUE, &NodeConnectionCount, &NodeConnection);
921
922 for(Index = 0; Index < NodeConnectionCount; Index++)
923 {
924 /* get all associated controls */
925 Status = GetControlsFromPinByConnectionIndex(NodeConnections, NodeTypes, bUpDirection, NodeConnection[Index], Nodes);
926 }
927
928 ExFreePool(NodeConnection);
929
930 return Status;
931 }
932
933 NTSTATUS
934 AddMixerControl(
935 IN LPMIXER_INFO MixerInfo,
936 IN PFILE_OBJECT FileObject,
937 IN PKSMULTIPLE_ITEM NodeTypes,
938 IN ULONG NodeIndex,
939 IN LPMIXERLINE_EXT MixerLine,
940 OUT LPMIXERCONTROLW MixerControl)
941 {
942 LPGUID NodeType;
943 KSP_NODE Node;
944 ULONG BytesReturned;
945 NTSTATUS Status;
946 LPWSTR Name;
947
948 /* initialize mixer control */
949 MixerControl->cbStruct = sizeof(MIXERCONTROLW);
950 MixerControl->dwControlID = MixerInfo->ControlId;
951
952 /* get node type */
953 NodeType = GetNodeType(NodeTypes, NodeIndex);
954 /* store control type */
955 MixerControl->dwControlType = GetControlTypeFromTopologyNode(NodeType);
956
957 MixerControl->fdwControl = MIXERCONTROL_CONTROLF_UNIFORM; //FIXME
958 MixerControl->cMultipleItems = 0; //FIXME
959
960 if (MixerControl->dwControlType == MIXERCONTROL_CONTROLTYPE_MUTE)
961 {
962 MixerControl->Bounds.dwMinimum = 0;
963 MixerControl->Bounds.dwMaximum = 1;
964 }
965 else if (MixerControl->dwControlType == MIXERCONTROL_CONTROLTYPE_VOLUME)
966 {
967 MixerControl->Bounds.dwMinimum = 0;
968 MixerControl->Bounds.dwMaximum = 0xFFFF;
969 MixerControl->Metrics.cSteps = 0xC0; //FIXME
970 }
971
972 /* setup request to retrieve name */
973 Node.NodeId = NodeIndex;
974 Node.Property.Id = KSPROPERTY_TOPOLOGY_NAME;
975 Node.Property.Flags = KSPROPERTY_TYPE_GET;
976 Node.Property.Set = KSPROPSETID_Topology;
977 Node.Reserved = 0;
978
979 /* get node name size */
980 Status = KsSynchronousIoControlDevice(FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&Node, sizeof(KSP_NODE), NULL, 0, &BytesReturned);
981
982 if (Status == STATUS_BUFFER_TOO_SMALL)
983 {
984 ASSERT(BytesReturned != 0);
985 Name = ExAllocatePool(NonPagedPool, BytesReturned);
986 if (!Name)
987 {
988 /* not enough memory */
989 return STATUS_INSUFFICIENT_RESOURCES;
990 }
991
992 /* get node name */
993 Status = KsSynchronousIoControlDevice(FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&Node, sizeof(KSP_NODE), (LPVOID)Name, BytesReturned, &BytesReturned);
994 if (NT_SUCCESS(Status))
995 {
996 RtlMoveMemory(MixerControl->szShortName, Name, (min(MIXER_SHORT_NAME_CHARS, wcslen(Name)+1)) * sizeof(WCHAR));
997 MixerControl->szShortName[MIXER_SHORT_NAME_CHARS-1] = L'\0';
998
999 RtlMoveMemory(MixerControl->szName, Name, (min(MIXER_LONG_NAME_CHARS, wcslen(Name)+1)) * sizeof(WCHAR));
1000 MixerControl->szName[MIXER_LONG_NAME_CHARS-1] = L'\0';
1001 }
1002
1003 /* free name buffer */
1004 ExFreePool(Name);
1005 }
1006
1007 MixerInfo->ControlId++;
1008 #if 0
1009 if (MixerControl->dwControlType == MIXERCONTROL_CONTROLTYPE_MUX)
1010 {
1011 KSNODEPROPERTY Property;
1012 ULONG PinId = 2;
1013
1014 /* setup the request */
1015 RtlZeroMemory(&Property, sizeof(KSNODEPROPERTY));
1016
1017 Property.NodeId = NodeIndex;
1018 Property.Property.Id = KSPROPERTY_AUDIO_MUX_SOURCE;
1019 Property.Property.Flags = KSPROPERTY_TYPE_SET;
1020 Property.Property.Set = KSPROPSETID_Audio;
1021
1022 /* get node volume level info */
1023 Status = KsSynchronousIoControlDevice(FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSNODEPROPERTY), (PVOID)&PinId, sizeof(ULONG), &BytesReturned);
1024
1025 DPRINT1("Status %x NodeIndex %u PinId %u\n", Status, NodeIndex, PinId);
1026 //DbgBreakPoint();
1027 }else
1028 #endif
1029 if (MixerControl->dwControlType == MIXERCONTROL_CONTROLTYPE_VOLUME)
1030 {
1031 KSNODEPROPERTY_AUDIO_CHANNEL Property;
1032 ULONG Length;
1033 PKSPROPERTY_DESCRIPTION Desc;
1034 PKSPROPERTY_MEMBERSHEADER Members;
1035 PKSPROPERTY_STEPPING_LONG Range;
1036
1037 Length = sizeof(KSPROPERTY_DESCRIPTION) + sizeof(KSPROPERTY_MEMBERSHEADER) + sizeof(KSPROPERTY_STEPPING_LONG);
1038 Desc = ExAllocatePool(NonPagedPool, Length);
1039 ASSERT(Desc);
1040 RtlZeroMemory(Desc, Length);
1041
1042 /* setup the request */
1043 RtlZeroMemory(&Property, sizeof(KSNODEPROPERTY_AUDIO_CHANNEL));
1044
1045 Property.NodeProperty.NodeId = NodeIndex;
1046 Property.NodeProperty.Property.Id = KSPROPERTY_AUDIO_VOLUMELEVEL;
1047 Property.NodeProperty.Property.Flags = KSPROPERTY_TYPE_BASICSUPPORT;
1048 Property.NodeProperty.Property.Set = KSPROPSETID_Audio;
1049
1050 /* get node volume level info */
1051 Status = KsSynchronousIoControlDevice(FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSNODEPROPERTY_AUDIO_CHANNEL), Desc, Length, &BytesReturned);
1052
1053 if (NT_SUCCESS(Status))
1054 {
1055 LPMIXERVOLUME_DATA VolumeData;
1056 ULONG Steps, MaxRange, Index;
1057 LONG Value;
1058
1059 Members = (PKSPROPERTY_MEMBERSHEADER)(Desc + 1);
1060 Range = (PKSPROPERTY_STEPPING_LONG)(Members + 1); //98304
1061
1062 DPRINT("NodeIndex %u Range Min %d Max %d Steps %x UMin %x UMax %x\n", NodeIndex, Range->Bounds.SignedMinimum, Range->Bounds.SignedMaximum, Range->SteppingDelta, Range->Bounds.UnsignedMinimum, Range->Bounds.UnsignedMaximum);
1063
1064 MaxRange = Range->Bounds.UnsignedMaximum - Range->Bounds.UnsignedMinimum;
1065
1066 if (MaxRange)
1067 {
1068 ASSERT(MaxRange);
1069 VolumeData = ExAllocatePool(NonPagedPool, sizeof(MIXERVOLUME_DATA));
1070 if (!VolumeData)
1071 return STATUS_INSUFFICIENT_RESOURCES;
1072
1073 Steps = MaxRange / Range->SteppingDelta + 1;
1074
1075 /* store mixer control info there */
1076 VolumeData->Header.dwControlID = MixerControl->dwControlID;
1077 VolumeData->SignedMaximum = Range->Bounds.SignedMaximum;
1078 VolumeData->SignedMinimum = Range->Bounds.SignedMinimum;
1079 VolumeData->SteppingDelta = Range->SteppingDelta;
1080 VolumeData->ValuesCount = Steps;
1081 VolumeData->InputSteppingDelta = 0x10000 / Steps;
1082
1083 VolumeData->Values = ExAllocatePool(NonPagedPool, sizeof(LONG) * Steps);
1084 if (!VolumeData->Values)
1085 {
1086 ExFreePool(Desc);
1087 ExFreePool(VolumeData);
1088
1089 return STATUS_INSUFFICIENT_RESOURCES;
1090 }
1091
1092 Value = Range->Bounds.SignedMinimum;
1093 for(Index = 0; Index < Steps; Index++)
1094 {
1095 VolumeData->Values[Index] = Value;
1096 Value += Range->SteppingDelta;
1097 }
1098 InsertTailList(&MixerLine->LineControlsExtraData, &VolumeData->Header.Entry);
1099 }
1100 }
1101 ExFreePool(Desc);
1102 }
1103
1104
1105 DPRINT("Status %x Name %S\n", Status, MixerControl->szName);
1106 return STATUS_SUCCESS;
1107 }
1108
1109 NTSTATUS
1110 AddMixerSourceLine(
1111 IN OUT LPMIXER_INFO MixerInfo,
1112 IN PFILE_OBJECT FileObject,
1113 IN PKSMULTIPLE_ITEM NodeConnections,
1114 IN PKSMULTIPLE_ITEM NodeTypes,
1115 IN ULONG DeviceIndex,
1116 IN ULONG PinId,
1117 IN ULONG bBridgePin,
1118 IN ULONG bTargetPin)
1119 {
1120 LPMIXERLINE_EXT SrcLine, DstLine;
1121 NTSTATUS Status;
1122 KSP_PIN Pin;
1123 LPWSTR PinName;
1124 GUID NodeType;
1125 ULONG BytesReturned, ControlCount, Index;
1126 PULONG Nodes;
1127
1128 if (!bTargetPin)
1129 {
1130 /* allocate src mixer line */
1131 SrcLine = (LPMIXERLINE_EXT)ExAllocatePool(NonPagedPool, sizeof(MIXERLINE_EXT));
1132
1133 if (!SrcLine)
1134 return STATUS_INSUFFICIENT_RESOURCES;
1135
1136 /* zero struct */
1137 RtlZeroMemory(SrcLine, sizeof(MIXERLINE_EXT));
1138
1139 }
1140 else
1141 {
1142 ASSERT(!IsListEmpty(&MixerInfo->LineList));
1143 SrcLine = GetSourceMixerLineByLineId(MixerInfo, DESTINATION_LINE);
1144 }
1145
1146 /* get destination line */
1147 DstLine = GetSourceMixerLineByLineId(MixerInfo, DESTINATION_LINE);
1148 ASSERT(DstLine);
1149
1150
1151 if (!bTargetPin)
1152 {
1153 /* initialize mixer src line */
1154 SrcLine->DeviceIndex = DeviceIndex;
1155 SrcLine->PinId = PinId;
1156 SrcLine->Line.cbStruct = sizeof(MIXERLINEW);
1157
1158 /* initialize mixer destination line */
1159 SrcLine->Line.cbStruct = sizeof(MIXERLINEW);
1160 SrcLine->Line.dwDestination = 0;
1161 SrcLine->Line.dwSource = DstLine->Line.cConnections;
1162 SrcLine->Line.dwLineID = (DstLine->Line.cConnections * 0x10000);
1163 SrcLine->Line.fdwLine = MIXERLINE_LINEF_ACTIVE | MIXERLINE_LINEF_SOURCE;
1164 SrcLine->Line.dwUser = 0;
1165 SrcLine->Line.cChannels = DstLine->Line.cChannels;
1166 SrcLine->Line.cConnections = 0;
1167 SrcLine->Line.Target.dwType = 1;
1168 SrcLine->Line.Target.dwDeviceID = DstLine->Line.Target.dwDeviceID;
1169 SrcLine->Line.Target.wMid = MixerInfo->MixCaps.wMid;
1170 SrcLine->Line.Target.wPid = MixerInfo->MixCaps.wPid;
1171 SrcLine->Line.Target.vDriverVersion = MixerInfo->MixCaps.vDriverVersion;
1172 InitializeListHead(&SrcLine->LineControlsExtraData);
1173 wcscpy(SrcLine->Line.Target.szPname, MixerInfo->MixCaps.szPname);
1174
1175 }
1176
1177 /* allocate a node arrary */
1178 Nodes = ExAllocatePool(NonPagedPool, sizeof(ULONG) * NodeTypes->Count);
1179
1180 if (!Nodes)
1181 {
1182 /* not enough memory */
1183 if (!bTargetPin)
1184 {
1185 ExFreePool(SrcLine);
1186 }
1187 return STATUS_INSUFFICIENT_RESOURCES;
1188 }
1189
1190 /* clear nodes array */
1191 RtlZeroMemory(Nodes, sizeof(ULONG) * NodeTypes->Count);
1192
1193 Status = GetControlsFromPin(NodeConnections, NodeTypes, PinId, bTargetPin, Nodes);
1194 if (!NT_SUCCESS(Status))
1195 {
1196 /* something went wrong */
1197 if (!bTargetPin)
1198 {
1199 ExFreePool(SrcLine);
1200 }
1201 ExFreePool(Nodes);
1202 return Status;
1203 }
1204
1205 /* now count all nodes controlled by that pin */
1206 ControlCount = 0;
1207 for(Index = 0; Index < NodeTypes->Count; Index++)
1208 {
1209 if (Nodes[Index])
1210 ControlCount++;
1211 }
1212
1213 /* now allocate the line controls */
1214 if (ControlCount)
1215 {
1216 SrcLine->LineControls = ExAllocatePool(NonPagedPool, sizeof(MIXERCONTROLW) * ControlCount);
1217
1218 if (!SrcLine->LineControls)
1219 {
1220 /* no memory available */
1221 if (!bTargetPin)
1222 {
1223 ExFreePool(SrcLine);
1224 }
1225 ExFreePool(Nodes);
1226 return STATUS_INSUFFICIENT_RESOURCES;
1227 }
1228
1229 SrcLine->NodeIds = ExAllocatePool(NonPagedPool, sizeof(ULONG) * ControlCount);
1230 if (!SrcLine->NodeIds)
1231 {
1232 /* no memory available */
1233 ExFreePool(SrcLine->LineControls);
1234 if (!bTargetPin)
1235 {
1236 ExFreePool(SrcLine);
1237 }
1238 ExFreePool(Nodes);
1239 return STATUS_INSUFFICIENT_RESOURCES;
1240 }
1241
1242 /* zero line controls */
1243 RtlZeroMemory(SrcLine->LineControls, sizeof(MIXERCONTROLW) * ControlCount);
1244 RtlZeroMemory(SrcLine->NodeIds, sizeof(ULONG) * ControlCount);
1245
1246 ControlCount = 0;
1247 for(Index = 0; Index < NodeTypes->Count; Index++)
1248 {
1249 if (Nodes[Index])
1250 {
1251 /* store the node index for retrieving / setting details */
1252 SrcLine->NodeIds[ControlCount] = Index;
1253
1254 Status = AddMixerControl(MixerInfo, FileObject, NodeTypes, Index, SrcLine, &SrcLine->LineControls[ControlCount]);
1255 if (NT_SUCCESS(Status))
1256 {
1257 /* increment control count on success */
1258 ControlCount++;
1259 }
1260 }
1261 }
1262 /* store control count */
1263 SrcLine->Line.cControls = ControlCount;
1264 }
1265
1266 /* release nodes array */
1267 ExFreePool(Nodes);
1268
1269 /* get pin category */
1270 Pin.PinId = PinId;
1271 Pin.Reserved = 0;
1272 Pin.Property.Flags = KSPROPERTY_TYPE_GET;
1273 Pin.Property.Set = KSPROPSETID_Pin;
1274 Pin.Property.Id = KSPROPERTY_PIN_CATEGORY;
1275
1276 /* try get pin category */
1277 Status = KsSynchronousIoControlDevice(FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSP_PIN), (LPVOID)&NodeType, sizeof(GUID), &BytesReturned);
1278 if (NT_SUCCESS(Status))
1279 {
1280 //FIXME
1281 //map component type
1282 }
1283
1284 /* retrieve pin name */
1285 Pin.PinId = PinId;
1286 Pin.Reserved = 0;
1287 Pin.Property.Flags = KSPROPERTY_TYPE_GET;
1288 Pin.Property.Set = KSPROPSETID_Pin;
1289 Pin.Property.Id = KSPROPERTY_PIN_NAME;
1290
1291 /* try get pin name size */
1292 Status = KsSynchronousIoControlDevice(FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSP_PIN), NULL, 0, &BytesReturned);
1293
1294 if (Status != STATUS_MORE_ENTRIES)
1295 {
1296 SrcLine->Line.szShortName[0] = L'\0';
1297 SrcLine->Line.szName[0] = L'\0';
1298 }
1299 else
1300 {
1301 PinName = (LPWSTR)ExAllocatePool(NonPagedPool, BytesReturned);
1302 if (PinName)
1303 {
1304 /* try get pin name */
1305 Status = KsSynchronousIoControlDevice(FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSP_PIN), (LPVOID)PinName, BytesReturned, &BytesReturned);
1306
1307 if (NT_SUCCESS(Status))
1308 {
1309 RtlMoveMemory(SrcLine->Line.szShortName, PinName, (min(MIXER_SHORT_NAME_CHARS, wcslen(PinName)+1)) * sizeof(WCHAR));
1310 SrcLine->Line.szShortName[MIXER_SHORT_NAME_CHARS-1] = L'\0';
1311
1312 RtlMoveMemory(SrcLine->Line.szName, PinName, (min(MIXER_LONG_NAME_CHARS, wcslen(PinName)+1)) * sizeof(WCHAR));
1313 SrcLine->Line.szName[MIXER_LONG_NAME_CHARS-1] = L'\0';
1314 }
1315 ExFreePool(PinName);
1316 }
1317 }
1318
1319 /* insert src line */
1320 if (!bTargetPin)
1321 {
1322 InsertTailList(&MixerInfo->LineList, &SrcLine->Entry);
1323 DstLine->Line.cConnections++;
1324 }
1325
1326 return STATUS_SUCCESS;
1327 }
1328
1329
1330 NTSTATUS
1331 AddMixerSourceLines(
1332 IN OUT LPMIXER_INFO MixerInfo,
1333 IN PFILE_OBJECT FileObject,
1334 IN PKSMULTIPLE_ITEM NodeConnections,
1335 IN PKSMULTIPLE_ITEM NodeTypes,
1336 IN ULONG DeviceIndex,
1337 IN ULONG PinsCount,
1338 IN ULONG BridgePinIndex,
1339 IN ULONG TargetPinIndex,
1340 IN PULONG Pins)
1341 {
1342 ULONG Index;
1343 NTSTATUS Status = STATUS_SUCCESS;
1344
1345 for(Index = PinsCount; Index > 0; Index--)
1346 {
1347 if (Pins[Index-1])
1348 {
1349 AddMixerSourceLine(MixerInfo, FileObject, NodeConnections, NodeTypes, DeviceIndex, Index-1, (Index -1 == BridgePinIndex), (Index -1 == TargetPinIndex));
1350 }
1351 }
1352 return Status;
1353 }
1354
1355
1356
1357 NTSTATUS
1358 HandlePhysicalConnection(
1359 IN OUT LPMIXER_INFO MixerInfo,
1360 IN PDEVICE_OBJECT DeviceObject,
1361 IN ULONG bInput,
1362 IN PKSPIN_PHYSICALCONNECTION OutConnection)
1363 {
1364 PULONG PinsRef = NULL, PinConnectionIndex = NULL, PinsSrcRef;
1365 ULONG PinsRefCount, Index, PinConnectionIndexCount, DeviceIndex;
1366 NTSTATUS Status;
1367 HANDLE hDevice = NULL;
1368 PFILE_OBJECT FileObject = NULL;
1369 PKSMULTIPLE_ITEM NodeTypes = NULL;
1370 PKSMULTIPLE_ITEM NodeConnections = NULL;
1371 PULONG MixerControls;
1372 ULONG MixerControlsCount;
1373
1374
1375 /* open the connected filter */
1376 Status = OpenDevice(OutConnection->SymbolicLinkName, &hDevice, &FileObject);
1377 if (!NT_SUCCESS(Status))
1378 {
1379 DPRINT1("OpenDevice failed with %x\n", Status);
1380 return Status;
1381 }
1382
1383 /* get device index */
1384 DeviceIndex = GetDeviceIndexFromPnpName(DeviceObject, OutConnection->SymbolicLinkName);
1385
1386 /* get connected filter pin count */
1387 PinsRefCount = GetPinCount(FileObject);
1388 ASSERT(PinsRefCount);
1389
1390 PinsRef = AllocatePinArray(PinsRefCount);
1391 if (!PinsRef)
1392 {
1393 /* no memory */
1394 Status = STATUS_INSUFFICIENT_RESOURCES;
1395 goto cleanup;
1396 }
1397
1398 /* get topology node types */
1399 Status = GetFilterNodeProperty(FileObject, KSPROPERTY_TOPOLOGY_NODES, &NodeTypes);
1400 if (!NT_SUCCESS(Status))
1401 {
1402 DPRINT1("GetFilterNodeProperty failed with %x\n", Status);
1403 goto cleanup;
1404 }
1405
1406 /* get topology connections */
1407 Status = GetFilterNodeProperty(FileObject, KSPROPERTY_TOPOLOGY_CONNECTIONS, &NodeConnections);
1408 if (!NT_SUCCESS(Status))
1409 {
1410 DPRINT1("GetFilterNodeProperty failed with %x\n", Status);
1411 goto cleanup;
1412 }
1413 /* gets connection index of the bridge pin which connects to a node */
1414 DPRINT("Pin %u\n", OutConnection->Pin);
1415 Status = GetNodeIndexes(NodeConnections, OutConnection->Pin, FALSE, !bInput, &PinConnectionIndexCount, &PinConnectionIndex);
1416 if (!NT_SUCCESS(Status))
1417 {
1418 DPRINT1("GetNodeIndexes failed with %x\n", Status);
1419 goto cleanup;
1420 }
1421
1422 /* there should be no split in the bride pin */
1423 ASSERT(PinConnectionIndexCount == 1);
1424
1425 /* find all target pins of this connection */
1426 Status = GetTargetPinsByNodeConnectionIndex(NodeConnections, NodeTypes, FALSE, PinConnectionIndex[0], PinsRef);
1427 if (!NT_SUCCESS(Status))
1428 {
1429 DPRINT1("GetTargetPinsByNodeConnectionIndex failed with %x\n", Status);
1430 goto cleanup;
1431 }
1432
1433 for(Index = 0; Index < PinsRefCount; Index++)
1434 {
1435 if (PinsRef[Index])
1436 {
1437
1438 /* found a target pin, now get all references */
1439 Status = GetNodeIndexes(NodeConnections, Index, FALSE, FALSE, &MixerControlsCount, &MixerControls);
1440 if (!NT_SUCCESS(Status))
1441 break;
1442
1443 /* sanity check */
1444 ASSERT(MixerControlsCount == 1);
1445
1446
1447 PinsSrcRef = AllocatePinArray(PinsRefCount);
1448 if (!PinsSrcRef)
1449 {
1450 /* no memory */
1451 ExFreePool(MixerControls);
1452 Status = STATUS_INSUFFICIENT_RESOURCES;
1453 goto cleanup;
1454 }
1455 /* now get all connected source pins */
1456 Status = GetTargetPinsByNodeConnectionIndex(NodeConnections, NodeTypes, TRUE, MixerControls[0], PinsSrcRef);
1457 if (!NT_SUCCESS(Status))
1458 {
1459 /* no memory */
1460 ExFreePool(MixerControls);
1461 ExFreePool(PinsSrcRef);
1462 Status = STATUS_INSUFFICIENT_RESOURCES;
1463 goto cleanup;
1464 }
1465
1466 /* add pins from target line */
1467 if (!bInput)
1468 {
1469 // dont add bridge pin for input mixers
1470 PinsSrcRef[Index] = TRUE;
1471 PinsSrcRef[OutConnection->Pin] = TRUE;
1472 }
1473 PinsSrcRef[OutConnection->Pin] = TRUE;
1474
1475 Status = AddMixerSourceLines(MixerInfo, FileObject, NodeConnections, NodeTypes, DeviceIndex, PinsRefCount, OutConnection->Pin, Index, PinsSrcRef);
1476
1477 ExFreePool(MixerControls);
1478 ExFreePool(PinsSrcRef);
1479 }
1480 }
1481
1482 cleanup:
1483
1484 if (PinsRef)
1485 ExFreePool(PinsRef);
1486
1487 if (NodeConnections)
1488 ExFreePool(NodeConnections);
1489
1490 if (NodeTypes)
1491 ExFreePool(NodeTypes);
1492
1493 if (FileObject)
1494 ObDereferenceObject(FileObject);
1495
1496 if (hDevice)
1497 ZwClose(hDevice);
1498
1499 if (PinConnectionIndex)
1500 ExFreePool(PinConnectionIndex);
1501
1502
1503 return Status;
1504 }
1505
1506
1507
1508 NTSTATUS
1509 InitializeMixer(
1510 IN PDEVICE_OBJECT DeviceObject,
1511 IN ULONG DeviceIndex,
1512 IN OUT LPMIXER_INFO MixerInfo,
1513 IN HANDLE hDevice,
1514 IN PFILE_OBJECT FileObject,
1515 IN ULONG PinCount,
1516 IN PKSMULTIPLE_ITEM NodeTypes,
1517 IN PKSMULTIPLE_ITEM NodeConnections,
1518 IN ULONG NodeIndex,
1519 IN ULONG bInput)
1520 {
1521 WCHAR Buffer[100];
1522 LPWSTR Device;
1523 NTSTATUS Status;
1524 PULONG Pins;
1525 ULONG Index;
1526 PKSPIN_PHYSICALCONNECTION OutConnection;
1527 LPMIXERLINE_EXT DestinationLine;
1528
1529 DestinationLine = ExAllocatePool(NonPagedPool, sizeof(MIXERLINE_EXT));
1530 if (!DestinationLine)
1531 return STATUS_INSUFFICIENT_RESOURCES;
1532
1533 /* intialize mixer caps */
1534 MixerInfo->MixCaps.wMid = MM_MICROSOFT; //FIXME
1535 MixerInfo->MixCaps.wPid = MM_PID_UNMAPPED; //FIXME
1536 MixerInfo->MixCaps.vDriverVersion = 1; //FIXME
1537 MixerInfo->MixCaps.fdwSupport = 0;
1538 MixerInfo->MixCaps.cDestinations = 1;
1539
1540 /* get target pnp name */
1541 Status = GetSysAudioDevicePnpName(DeviceObject, DeviceIndex, &Device);
1542 if (NT_SUCCESS(Status))
1543 {
1544 /* find product name */
1545 Status = FindProductName(Device, sizeof(Buffer) / sizeof(WCHAR), Buffer);
1546 if (NT_SUCCESS(Status))
1547 {
1548 if (bInput)
1549 wcscat(Buffer, L" Input");
1550 else
1551 wcscat(Buffer, L" output");
1552 RtlMoveMemory(MixerInfo->MixCaps.szPname, Buffer, min(MAXPNAMELEN, wcslen(Buffer)+1) * sizeof(WCHAR));
1553 MixerInfo->MixCaps.szPname[MAXPNAMELEN-1] = L'\0';
1554 }
1555 ExFreePool(Device);
1556 }
1557
1558 /* initialize mixer destination line */
1559 RtlZeroMemory(DestinationLine, sizeof(MIXERLINE_EXT));
1560 DestinationLine->Line.cbStruct = sizeof(MIXERLINEW);
1561 DestinationLine->Line.dwSource = MAXULONG;
1562 DestinationLine->Line.dwLineID = DESTINATION_LINE;
1563 DestinationLine->Line.fdwLine = MIXERLINE_LINEF_ACTIVE;
1564 DestinationLine->Line.dwUser = 0;
1565 DestinationLine->Line.dwComponentType = (bInput == 0 ? MIXERLINE_COMPONENTTYPE_DST_SPEAKERS : MIXERLINE_COMPONENTTYPE_DST_WAVEIN);
1566 DestinationLine->Line.cChannels = 2; //FIXME
1567 wcscpy(DestinationLine->Line.szShortName, L"Summe"); //FIXME
1568 wcscpy(DestinationLine->Line.szName, L"Summe"); //FIXME
1569 DestinationLine->Line.Target.dwType = (bInput == 0 ? MIXERLINE_TARGETTYPE_WAVEOUT : MIXERLINE_TARGETTYPE_WAVEIN);
1570 DestinationLine->Line.Target.dwDeviceID = !bInput;
1571 DestinationLine->Line.Target.wMid = MixerInfo->MixCaps.wMid;
1572 DestinationLine->Line.Target.wPid = MixerInfo->MixCaps.wPid;
1573 DestinationLine->Line.Target.vDriverVersion = MixerInfo->MixCaps.vDriverVersion;
1574 wcscpy(DestinationLine->Line.Target.szPname, MixerInfo->MixCaps.szPname);
1575
1576 /* initialize source line list */
1577 InitializeListHead(&MixerInfo->LineList);
1578 InitializeListHead(&DestinationLine->LineControlsExtraData);
1579
1580 /* insert destination line */
1581 InsertHeadList(&MixerInfo->LineList, &DestinationLine->Entry);
1582
1583 Pins = AllocatePinArray(PinCount);
1584 if (!Pins)
1585 return STATUS_INSUFFICIENT_RESOURCES;
1586
1587 if (bInput)
1588 {
1589 Status = GetTargetPins(NodeTypes, NodeConnections, NodeIndex, TRUE, Pins, PinCount);
1590 }
1591 else
1592 {
1593 Status = GetTargetPins(NodeTypes, NodeConnections, NodeIndex, FALSE, Pins, PinCount);
1594 }
1595
1596 for(Index = 0; Index < PinCount; Index++)
1597 {
1598 if (Pins[Index])
1599 {
1600 Status = GetPhysicalConnection(FileObject, Index, &OutConnection);
1601 if (NT_SUCCESS(Status))
1602 {
1603 Status = HandlePhysicalConnection(MixerInfo, DeviceObject, bInput, OutConnection);
1604 ExFreePool(OutConnection);
1605 }
1606 }
1607 }
1608 ExFreePool(Pins);
1609
1610 return STATUS_SUCCESS;
1611 }
1612
1613 NTSTATUS
1614 WdmAudMixerInitialize(
1615 IN PDEVICE_OBJECT DeviceObject)
1616 {
1617 ULONG DeviceCount, Index, Count, NodeIndex, PinCount;
1618 NTSTATUS Status;
1619 HANDLE hDevice;
1620 PFILE_OBJECT FileObject;
1621 PKSMULTIPLE_ITEM NodeTypes, NodeConnections;
1622 PWDMAUD_DEVICE_EXTENSION DeviceExtension;
1623
1624 /* get device extension */
1625 DeviceExtension = (PWDMAUD_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
1626
1627
1628 /* get number of devices */
1629 DeviceCount = GetSysAudioDeviceCount(DeviceObject);
1630
1631 if (!DeviceCount)
1632 {
1633 /* no audio devices available atm */
1634 DeviceExtension->MixerInfoCount = 0;
1635 DeviceExtension->MixerInfo = NULL;
1636 return STATUS_SUCCESS;
1637 }
1638
1639 /* each virtual audio device can at most have an input + output mixer */
1640 DeviceExtension->MixerInfo = ExAllocatePool(NonPagedPool, sizeof(MIXER_INFO) * DeviceCount * 2);
1641 if (!DeviceExtension->MixerInfo)
1642 {
1643 /* not enough memory */
1644 return STATUS_INSUFFICIENT_RESOURCES;
1645 }
1646
1647 /* clear mixer info */
1648 RtlZeroMemory(DeviceExtension->MixerInfo, sizeof(MIXER_INFO) * DeviceCount * 2);
1649
1650 Index = 0;
1651 Count = 0;
1652 do
1653 {
1654 /* open the virtual audio device */
1655 Status = OpenSysAudioDeviceByIndex(DeviceObject, Index, &hDevice, &FileObject);
1656
1657 if (NT_SUCCESS(Status))
1658 {
1659 /* retrieve all available node types */
1660 Status = GetFilterNodeProperty(FileObject, KSPROPERTY_TOPOLOGY_NODES, &NodeTypes);
1661 if (!NT_SUCCESS(Status))
1662 {
1663 ObDereferenceObject(FileObject);
1664 ZwClose(hDevice);
1665 break;
1666 }
1667
1668 Status = GetFilterNodeProperty(FileObject, KSPROPERTY_TOPOLOGY_CONNECTIONS, &NodeConnections);
1669 if (!NT_SUCCESS(Status))
1670 {
1671 ObDereferenceObject(FileObject);
1672 ZwClose(hDevice);
1673 ExFreePool(NodeTypes);
1674 break;
1675 }
1676
1677 /* get num of pins */
1678 PinCount = GetPinCount(FileObject);
1679 /* get the first available dac node index */
1680 NodeIndex = GetNodeTypeIndex(NodeTypes, (LPGUID)&KSNODETYPE_DAC);
1681 if (NodeIndex != (ULONG)-1)
1682 {
1683 Status = InitializeMixer(DeviceObject, Index, &DeviceExtension->MixerInfo[Count], hDevice, FileObject, PinCount, NodeTypes, NodeConnections, NodeIndex, FALSE);
1684 if (NT_SUCCESS(Status))
1685 {
1686 /* increment mixer offset */
1687 Count++;
1688 }
1689 }
1690
1691 /* get the first available adc node index */
1692 NodeIndex = GetNodeTypeIndex(NodeTypes, (LPGUID)&KSNODETYPE_ADC);
1693 if (NodeIndex != (ULONG)-1)
1694 {
1695 Status = InitializeMixer(DeviceObject, Index, &DeviceExtension->MixerInfo[Count], hDevice, FileObject, PinCount, NodeTypes, NodeConnections, NodeIndex, TRUE);
1696 if (NT_SUCCESS(Status))
1697 {
1698 /* increment mixer offset */
1699 Count++;
1700 }
1701 }
1702
1703 /* free node connections array */
1704 ExFreePool(NodeTypes);
1705 ExFreePool(NodeConnections);
1706
1707 /* close virtual audio device */
1708 ObDereferenceObject(FileObject);
1709 ZwClose(hDevice);
1710
1711 }
1712 /* increment virtual audio device index */
1713 Index++;
1714 }while(Index < DeviceCount);
1715
1716 /* store mixer count */
1717 DeviceExtension->MixerInfoCount = Count;
1718
1719 return Status;
1720 }
1721
1722
1723
1724 NTSTATUS
1725 WdmAudMixerCapabilities(
1726 IN PDEVICE_OBJECT DeviceObject,
1727 IN PWDMAUD_DEVICE_INFO DeviceInfo,
1728 IN PWDMAUD_CLIENT ClientInfo,
1729 IN PWDMAUD_DEVICE_EXTENSION DeviceExtension)
1730 {
1731 if ((ULONG)DeviceInfo->DeviceIndex >= DeviceExtension->MixerInfoCount)
1732 {
1733 /* invalid parameter */
1734 return STATUS_INVALID_PARAMETER;
1735 }
1736
1737 /* copy cached mixer caps */
1738 RtlMoveMemory(&DeviceInfo->u.MixCaps, &DeviceExtension->MixerInfo[(ULONG)DeviceInfo->DeviceIndex].MixCaps, sizeof(MIXERCAPSW));
1739
1740 return STATUS_SUCCESS;
1741 }
1742
1743
1744 NTSTATUS
1745 WdmAudControlOpenMixer(
1746 IN PDEVICE_OBJECT DeviceObject,
1747 IN PIRP Irp,
1748 IN PWDMAUD_DEVICE_INFO DeviceInfo,
1749 IN PWDMAUD_CLIENT ClientInfo)
1750 {
1751 ULONG Index;
1752 PWDMAUD_HANDLE Handels;
1753 PWDMAUD_DEVICE_EXTENSION DeviceExtension;
1754
1755 DPRINT("WdmAudControlOpenMixer\n");
1756
1757 DeviceExtension = (PWDMAUD_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
1758
1759
1760 if (DeviceInfo->DeviceIndex >= DeviceExtension->MixerInfoCount)
1761 {
1762 /* mixer index doesnt exist */
1763 return SetIrpIoStatus(Irp, STATUS_UNSUCCESSFUL, 0);
1764 }
1765
1766 for(Index = 0; Index < ClientInfo->NumPins; Index++)
1767 {
1768 if (ClientInfo->hPins[Index].Handle == (HANDLE)DeviceInfo->DeviceIndex && ClientInfo->hPins[Index].Type == MIXER_DEVICE_TYPE)
1769 {
1770 /* re-use pseudo handle */
1771 DeviceInfo->hDevice = (HANDLE)DeviceInfo->DeviceIndex;
1772 return SetIrpIoStatus(Irp, STATUS_SUCCESS, sizeof(WDMAUD_DEVICE_INFO));
1773 }
1774 }
1775
1776 Handels = ExAllocatePool(NonPagedPool, sizeof(WDMAUD_HANDLE) * (ClientInfo->NumPins+1));
1777
1778 if (Handels)
1779 {
1780 if (ClientInfo->NumPins)
1781 {
1782 RtlMoveMemory(Handels, ClientInfo->hPins, sizeof(WDMAUD_HANDLE) * ClientInfo->NumPins);
1783 ExFreePool(ClientInfo->hPins);
1784 }
1785
1786 ClientInfo->hPins = Handels;
1787 ClientInfo->hPins[ClientInfo->NumPins].Handle = (HANDLE)DeviceInfo->DeviceIndex;
1788 ClientInfo->hPins[ClientInfo->NumPins].Type = MIXER_DEVICE_TYPE;
1789 ClientInfo->NumPins++;
1790 }
1791 else
1792 {
1793 return SetIrpIoStatus(Irp, STATUS_UNSUCCESSFUL, sizeof(WDMAUD_DEVICE_INFO));
1794 }
1795 DeviceInfo->hDevice = (HANDLE)DeviceInfo->DeviceIndex;
1796
1797 return SetIrpIoStatus(Irp, STATUS_SUCCESS, sizeof(WDMAUD_DEVICE_INFO));
1798 }
1799
1800 NTSTATUS
1801 NTAPI
1802 WdmAudGetLineInfo(
1803 IN PDEVICE_OBJECT DeviceObject,
1804 IN PIRP Irp,
1805 IN PWDMAUD_DEVICE_INFO DeviceInfo,
1806 IN PWDMAUD_CLIENT ClientInfo)
1807 {
1808 PWDMAUD_DEVICE_EXTENSION DeviceExtension;
1809 LPMIXERLINE_EXT MixerLineSrc;
1810
1811 /* get device extension */
1812 DeviceExtension = (PWDMAUD_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
1813
1814 DeviceInfo->Flags &= ~MIXER_OBJECTF_HMIXER;
1815
1816 if (DeviceInfo->Flags == MIXER_GETLINEINFOF_DESTINATION)
1817 {
1818 if ((ULONG_PTR)DeviceInfo->hDevice >= DeviceExtension->MixerInfoCount)
1819 {
1820 /* invalid parameter */
1821 return SetIrpIoStatus(Irp, STATUS_INVALID_PARAMETER, 0);
1822 }
1823
1824 if (DeviceInfo->u.MixLine.dwDestination != 0)
1825 {
1826 /* invalid parameter */
1827 return SetIrpIoStatus(Irp, STATUS_INVALID_PARAMETER, 0);
1828 }
1829 MixerLineSrc = GetSourceMixerLineByLineId(&DeviceExtension->MixerInfo[(ULONG_PTR)DeviceInfo->hDevice], DESTINATION_LINE);
1830 ASSERT(MixerLineSrc);
1831
1832 /* copy cached data */
1833 RtlCopyMemory(&DeviceInfo->u.MixLine, &MixerLineSrc->Line, sizeof(MIXERLINEW));
1834 return SetIrpIoStatus(Irp, STATUS_SUCCESS, sizeof(WDMAUD_DEVICE_INFO));
1835 }
1836 else if (DeviceInfo->Flags == MIXER_GETLINEINFOF_SOURCE)
1837 {
1838 if ((ULONG_PTR)DeviceInfo->hDevice >= DeviceExtension->MixerInfoCount)
1839 {
1840 /* invalid parameter */
1841 return SetIrpIoStatus(Irp, STATUS_INVALID_PARAMETER, 0);
1842 }
1843
1844 MixerLineSrc = GetSourceMixerLineByLineId(&DeviceExtension->MixerInfo[(ULONG_PTR)DeviceInfo->hDevice], DESTINATION_LINE);
1845 ASSERT(MixerLineSrc);
1846
1847 if (DeviceInfo->u.MixLine.dwSource >= MixerLineSrc->Line.cConnections)
1848 {
1849 DPRINT1("dwSource %u Destinations %u\n", DeviceInfo->u.MixLine.dwSource, MixerLineSrc->Line.cConnections);
1850 /* invalid parameter */
1851 return SetIrpIoStatus(Irp, STATUS_INVALID_PARAMETER, 0);
1852 }
1853
1854 MixerLineSrc = GetSourceMixerLine(&DeviceExtension->MixerInfo[(ULONG_PTR)DeviceInfo->hDevice], DeviceInfo->u.MixLine.dwSource);
1855 if (MixerLineSrc)
1856 {
1857 DPRINT("Line %u Name %S\n", MixerLineSrc->Line.dwSource, MixerLineSrc->Line.szName);
1858 RtlCopyMemory(&DeviceInfo->u.MixLine, &MixerLineSrc->Line, sizeof(MIXERLINEW));
1859 }
1860 return SetIrpIoStatus(Irp, STATUS_SUCCESS, sizeof(WDMAUD_DEVICE_INFO));
1861 }
1862 else if (DeviceInfo->Flags == MIXER_GETLINEINFOF_LINEID)
1863 {
1864 if ((ULONG_PTR)DeviceInfo->hDevice >= DeviceExtension->MixerInfoCount)
1865 {
1866 /* invalid parameter */
1867 return SetIrpIoStatus(Irp, STATUS_INVALID_PARAMETER, 0);
1868 }
1869
1870 MixerLineSrc = GetSourceMixerLineByLineId(&DeviceExtension->MixerInfo[(ULONG_PTR)DeviceInfo->hDevice], DeviceInfo->u.MixLine.dwLineID);
1871 if (!MixerLineSrc)
1872 {
1873 DPRINT1("Failed to find Line with id %u\n", DeviceInfo->u.MixLine.dwLineID);
1874 return SetIrpIoStatus(Irp, STATUS_INVALID_PARAMETER, 0);
1875 }
1876
1877 /* copy cached data */
1878 RtlCopyMemory(&DeviceInfo->u.MixLine, &MixerLineSrc->Line, sizeof(MIXERLINEW));
1879 return SetIrpIoStatus(Irp, STATUS_SUCCESS, sizeof(WDMAUD_DEVICE_INFO));
1880 }
1881 else if (DeviceInfo->Flags == MIXER_GETLINEINFOF_COMPONENTTYPE)
1882 {
1883 if ((ULONG_PTR)DeviceInfo->hDevice >= DeviceExtension->MixerInfoCount)
1884 {
1885 /* invalid parameter */
1886 return SetIrpIoStatus(Irp, STATUS_INVALID_PARAMETER, 0);
1887 }
1888
1889 MixerLineSrc = GetSourceMixerLineByComponentType(&DeviceExtension->MixerInfo[(ULONG_PTR)DeviceInfo->hDevice], DeviceInfo->u.MixLine.dwComponentType);
1890 ASSERT(MixerLineSrc);
1891
1892 /* copy cached data */
1893 RtlCopyMemory(&DeviceInfo->u.MixLine, &MixerLineSrc->Line, sizeof(MIXERLINEW));
1894 return SetIrpIoStatus(Irp, STATUS_SUCCESS, sizeof(WDMAUD_DEVICE_INFO));
1895 }
1896
1897 DPRINT1("Flags %x\n", DeviceInfo->Flags);
1898 UNIMPLEMENTED;
1899
1900 //DbgBreakPoint();
1901 return SetIrpIoStatus(Irp, STATUS_NOT_IMPLEMENTED, 0);
1902
1903 }
1904
1905 NTSTATUS
1906 NTAPI
1907 WdmAudGetLineControls(
1908 IN PDEVICE_OBJECT DeviceObject,
1909 IN PIRP Irp,
1910 IN PWDMAUD_DEVICE_INFO DeviceInfo,
1911 IN PWDMAUD_CLIENT ClientInfo)
1912 {
1913 LPMIXERLINE_EXT MixerLineSrc;
1914 LPMIXERCONTROLW MixerControl;
1915 PWDMAUD_DEVICE_EXTENSION DeviceExtension;
1916 ULONG Index;
1917 NTSTATUS Status;
1918
1919 /* get device extension */
1920 DeviceExtension = (PWDMAUD_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
1921
1922 DeviceInfo->Flags &= ~MIXER_OBJECTF_HMIXER;
1923
1924 if (DeviceInfo->Flags == MIXER_GETLINECONTROLSF_ALL)
1925 {
1926 if ((ULONG_PTR)DeviceInfo->hDevice >= DeviceExtension->MixerInfoCount)
1927 {
1928 /* invalid parameter */
1929 return SetIrpIoStatus(Irp, STATUS_INVALID_PARAMETER, 0);
1930 }
1931
1932 MixerLineSrc = GetSourceMixerLineByLineId(&DeviceExtension->MixerInfo[(ULONG_PTR)DeviceInfo->hDevice], DeviceInfo->u.MixControls.dwLineID);
1933 ASSERT(MixerLineSrc);
1934 if (MixerLineSrc)
1935 {
1936 RtlMoveMemory(DeviceInfo->u.MixControls.pamxctrl, MixerLineSrc->LineControls, min(MixerLineSrc->Line.cControls, DeviceInfo->u.MixControls.cControls) * sizeof(MIXERCONTROLW));
1937 }
1938 return SetIrpIoStatus(Irp, STATUS_SUCCESS, sizeof(WDMAUD_DEVICE_INFO));
1939 }
1940 else if (DeviceInfo->Flags == MIXER_GETLINECONTROLSF_ONEBYTYPE)
1941 {
1942 if ((ULONG_PTR)DeviceInfo->hDevice >= DeviceExtension->MixerInfoCount)
1943 {
1944 /* invalid parameter */
1945 return SetIrpIoStatus(Irp, STATUS_INVALID_PARAMETER, 0);
1946 }
1947
1948 MixerLineSrc = GetSourceMixerLineByLineId(&DeviceExtension->MixerInfo[(ULONG_PTR)DeviceInfo->hDevice], DeviceInfo->u.MixControls.dwLineID);
1949 ASSERT(MixerLineSrc);
1950
1951 Index = 0;
1952 for(Index = 0; Index < MixerLineSrc->Line.cControls; Index++)
1953 {
1954 DPRINT1("dwControlType %x\n", MixerLineSrc->LineControls[Index].dwControlType);
1955 if (DeviceInfo->u.MixControls.dwControlType == MixerLineSrc->LineControls[Index].dwControlType)
1956 {
1957 RtlMoveMemory(DeviceInfo->u.MixControls.pamxctrl, &MixerLineSrc->LineControls[Index], sizeof(MIXERCONTROLW));
1958 return SetIrpIoStatus(Irp, STATUS_SUCCESS, sizeof(WDMAUD_DEVICE_INFO));
1959 }
1960 }
1961 DPRINT1("DeviceInfo->u.MixControls.dwControlType %x not found in Line %x cControls %u \n", DeviceInfo->u.MixControls.dwControlType, DeviceInfo->u.MixControls.dwLineID, MixerLineSrc->Line.cControls);
1962 return SetIrpIoStatus(Irp, STATUS_UNSUCCESSFUL, sizeof(WDMAUD_DEVICE_INFO));
1963 }
1964 else if (DeviceInfo->Flags == MIXER_GETLINECONTROLSF_ONEBYID)
1965 {
1966 if ((ULONG_PTR)DeviceInfo->hDevice >= DeviceExtension->MixerInfoCount)
1967 {
1968 /* invalid parameter */
1969 return SetIrpIoStatus(Irp, STATUS_INVALID_PARAMETER, 0);
1970 }
1971 DPRINT1("MixerId %u ControlId %u\n",(ULONG_PTR)DeviceInfo->hDevice, DeviceInfo->u.MixControls.dwControlID);
1972 Status = GetMixerControlById(&DeviceExtension->MixerInfo[(ULONG_PTR)DeviceInfo->hDevice], DeviceInfo->u.MixControls.dwControlID, NULL, &MixerControl, NULL);
1973 if (NT_SUCCESS(Status))
1974 {
1975 RtlMoveMemory(DeviceInfo->u.MixControls.pamxctrl, MixerControl, sizeof(MIXERCONTROLW));
1976 }
1977 return SetIrpIoStatus(Irp, Status, sizeof(WDMAUD_DEVICE_INFO));
1978 }
1979
1980 UNIMPLEMENTED;
1981 //DbgBreakPoint();
1982 return SetIrpIoStatus(Irp, STATUS_NOT_IMPLEMENTED, 0);
1983
1984 }
1985
1986 NTSTATUS
1987 SetGetControlDetails(
1988 IN PDEVICE_OBJECT DeviceObject,
1989 IN ULONG DeviceId,
1990 IN ULONG NodeId,
1991 IN PWDMAUD_DEVICE_INFO DeviceInfo,
1992 IN ULONG bSet,
1993 IN ULONG PropertyId,
1994 IN ULONG Channel,
1995 IN PLONG InputValue)
1996 {
1997 KSNODEPROPERTY_AUDIO_CHANNEL Property;
1998 NTSTATUS Status;
1999 HANDLE hDevice;
2000 PFILE_OBJECT FileObject;
2001 LONG Value;
2002 ULONG BytesReturned;
2003
2004 if (bSet)
2005 Value = *InputValue;
2006
2007 /* open virtual audio device */
2008 Status = OpenSysAudioDeviceByIndex(DeviceObject, DeviceId, &hDevice, &FileObject);
2009
2010 if (!NT_SUCCESS(Status))
2011 {
2012 /* failed */
2013 return Status;
2014 }
2015
2016 /* setup the request */
2017 RtlZeroMemory(&Property, sizeof(KSNODEPROPERTY_AUDIO_CHANNEL));
2018
2019 Property.NodeProperty.NodeId = NodeId;
2020 Property.NodeProperty.Property.Id = PropertyId;
2021 Property.NodeProperty.Property.Flags = KSPROPERTY_TYPE_TOPOLOGY;
2022 Property.NodeProperty.Property.Set = KSPROPSETID_Audio;
2023 Property.Channel = Channel;
2024
2025 if (bSet)
2026 Property.NodeProperty.Property.Flags |= KSPROPERTY_TYPE_SET;
2027 else
2028 Property.NodeProperty.Property.Flags |= KSPROPERTY_TYPE_GET;
2029
2030 /* send the request */
2031 Status = KsSynchronousIoControlDevice(FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSNODEPROPERTY_AUDIO_CHANNEL), (PVOID)&Value, sizeof(LONG), &BytesReturned);
2032
2033 ObDereferenceObject(FileObject);
2034 ZwClose(hDevice);
2035
2036 if (!bSet)
2037 {
2038 *InputValue = Value;
2039 }
2040
2041 DPRINT1("Status %x bSet %u NodeId %u Value %d PropertyId %u\n", Status, bSet, NodeId, Value, PropertyId);
2042 return Status;
2043 }
2044
2045 NTSTATUS
2046 SetGetMuteControlDetails(
2047 IN PDEVICE_OBJECT DeviceObject,
2048 IN ULONG DeviceId,
2049 IN ULONG NodeId,
2050 IN PWDMAUD_DEVICE_INFO DeviceInfo,
2051 IN ULONG bSet)
2052 {
2053 LPMIXERCONTROLDETAILS_BOOLEAN Input;
2054 LONG Value;
2055 NTSTATUS Status;
2056
2057 if (DeviceInfo->u.MixDetails.cbDetails != sizeof(MIXERCONTROLDETAILS_BOOLEAN))
2058 return STATUS_INVALID_PARAMETER;
2059
2060 /* get input */
2061 Input = (LPMIXERCONTROLDETAILS_BOOLEAN)DeviceInfo->u.MixDetails.paDetails;
2062
2063 /* FIXME SEH */
2064 if (bSet)
2065 Value = Input->fValue;
2066
2067 /* set control details */
2068 Status = SetGetControlDetails(DeviceObject, DeviceId, NodeId, DeviceInfo, bSet, KSPROPERTY_AUDIO_MUTE, MAXULONG, &Value);
2069
2070 /* FIXME SEH */
2071 if (!bSet)
2072 Input->fValue = Value;
2073
2074 return Status;
2075 }
2076
2077 NTSTATUS
2078 SetGetVolumeControlDetails(
2079 IN PDEVICE_OBJECT DeviceObject,
2080 IN ULONG DeviceId,
2081 IN ULONG NodeId,
2082 IN PWDMAUD_DEVICE_INFO DeviceInfo,
2083 IN ULONG bSet,
2084 LPMIXERCONTROLW MixerControl,
2085 LPMIXERLINE_EXT MixerLine)
2086 {
2087 LPMIXERCONTROLDETAILS_UNSIGNED Input;
2088 LONG Value, Index, Channel = 0;
2089 NTSTATUS Status;
2090 LPMIXERVOLUME_DATA VolumeData;
2091
2092 if (DeviceInfo->u.MixDetails.cbDetails != sizeof(MIXERCONTROLDETAILS_SIGNED))
2093 return STATUS_INVALID_PARAMETER;
2094
2095 VolumeData = (LPMIXERVOLUME_DATA)GetMixerControlDataById(&MixerLine->LineControlsExtraData, MixerControl->dwControlID);
2096 if (!VolumeData)
2097 return STATUS_INSUFFICIENT_RESOURCES;
2098
2099
2100 /* get input */
2101 Input = (LPMIXERCONTROLDETAILS_UNSIGNED)DeviceInfo->u.MixDetails.paDetails;
2102
2103 if (bSet)
2104 {
2105 /* FIXME SEH */
2106 Value = Input->dwValue;
2107 Index = Value / VolumeData->InputSteppingDelta;
2108
2109 if (Index >= VolumeData->ValuesCount)
2110 {
2111 DPRINT1("Index %u out of bounds %u \n", Index, VolumeData->ValuesCount);
2112 DbgBreakPoint();
2113 return STATUS_INVALID_PARAMETER;
2114 }
2115
2116 Value = VolumeData->Values[Index];
2117 }
2118
2119 /* set control details */
2120 if (bSet)
2121 {
2122 Status = SetGetControlDetails(DeviceObject, DeviceId, NodeId, DeviceInfo, bSet, KSPROPERTY_AUDIO_VOLUMELEVEL, 0, &Value);
2123 Status = SetGetControlDetails(DeviceObject, DeviceId, NodeId, DeviceInfo, bSet, KSPROPERTY_AUDIO_VOLUMELEVEL, 1, &Value);
2124 }
2125 else
2126 {
2127 Status = SetGetControlDetails(DeviceObject, DeviceId, NodeId, DeviceInfo, bSet, KSPROPERTY_AUDIO_VOLUMELEVEL, Channel, &Value);
2128 }
2129
2130 if (!bSet)
2131 {
2132 for(Index = 0; Index < VolumeData->ValuesCount; Index++)
2133 {
2134 if (VolumeData->Values[Index] > Value)
2135 {
2136 /* FIXME SEH */
2137 Input->dwValue = VolumeData->InputSteppingDelta * Index;
2138 return Status;
2139 }
2140 }
2141 Input->dwValue = VolumeData->InputSteppingDelta * (VolumeData->ValuesCount-1);
2142 }
2143
2144 return Status;
2145 }
2146
2147 NTSTATUS
2148 NTAPI
2149 WdmAudSetControlDetails(
2150 IN PDEVICE_OBJECT DeviceObject,
2151 IN PIRP Irp,
2152 IN PWDMAUD_DEVICE_INFO DeviceInfo,
2153 IN PWDMAUD_CLIENT ClientInfo)
2154 {
2155 LPMIXERLINE_EXT MixerLine;
2156 LPMIXERCONTROLW MixerControl;
2157 ULONG NodeId;
2158 PWDMAUD_DEVICE_EXTENSION DeviceExtension;
2159 NTSTATUS Status;
2160
2161 DeviceInfo->Flags &= ~MIXER_OBJECTF_HMIXER;
2162
2163 DPRINT("cbStruct %u Expected %u dwControlID %u cChannels %u cMultipleItems %u cbDetails %u paDetails %p Flags %x\n",
2164 DeviceInfo->u.MixDetails.cbStruct, sizeof(MIXERCONTROLDETAILS), DeviceInfo->u.MixDetails.dwControlID, DeviceInfo->u.MixDetails.cChannels, DeviceInfo->u.MixDetails.cMultipleItems, DeviceInfo->u.MixDetails.cbDetails, DeviceInfo->u.MixDetails.paDetails, DeviceInfo->Flags);
2165
2166 if (DeviceInfo->Flags & MIXER_GETCONTROLDETAILSF_LISTTEXT)
2167 {
2168 UNIMPLEMENTED;
2169 return SetIrpIoStatus(Irp, STATUS_NOT_IMPLEMENTED, 0);
2170 }
2171
2172 /* get device extension */
2173 DeviceExtension = (PWDMAUD_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
2174
2175 /* get mixer control */
2176 Status = GetMixerControlById(&DeviceExtension->MixerInfo[(ULONG_PTR)DeviceInfo->hDevice], DeviceInfo->u.MixDetails.dwControlID, &MixerLine, &MixerControl, &NodeId);
2177
2178 if (!NT_SUCCESS(Status))
2179 {
2180 DPRINT1("MixerControl %x not found\n", DeviceInfo->u.MixDetails.dwControlID);
2181 return SetIrpIoStatus(Irp, STATUS_INVALID_PARAMETER, 0);
2182 }
2183
2184 Status = STATUS_NOT_IMPLEMENTED;
2185 DPRINT("dwLineId %x dwControlID %x dwControlType %x\n", MixerLine->Line.dwLineID, MixerControl->dwControlID, MixerControl->dwControlType);
2186 if (MixerControl->dwControlType == MIXERCONTROL_CONTROLTYPE_MUTE)
2187 {
2188 /* send the request */
2189 Status = SetGetMuteControlDetails(DeviceObject, MixerLine->DeviceIndex, NodeId, DeviceInfo, TRUE);
2190 }
2191 else if (MixerControl->dwControlType == MIXERCONTROL_CONTROLTYPE_VOLUME)
2192 {
2193 Status = SetGetVolumeControlDetails(DeviceObject, MixerLine->DeviceIndex, NodeId, DeviceInfo, TRUE, MixerControl, MixerLine);
2194 }
2195 return SetIrpIoStatus(Irp, Status, sizeof(WDMAUD_DEVICE_INFO));
2196
2197 }
2198
2199 NTSTATUS
2200 NTAPI
2201 WdmAudGetControlDetails(
2202 IN PDEVICE_OBJECT DeviceObject,
2203 IN PIRP Irp,
2204 IN PWDMAUD_DEVICE_INFO DeviceInfo,
2205 IN PWDMAUD_CLIENT ClientInfo)
2206 {
2207 LPMIXERLINE_EXT MixerLine;
2208 LPMIXERCONTROLW MixerControl;
2209 ULONG NodeId;
2210 PWDMAUD_DEVICE_EXTENSION DeviceExtension;
2211 NTSTATUS Status;
2212
2213 DeviceInfo->Flags &= ~MIXER_OBJECTF_HMIXER;
2214
2215 DPRINT("cbStruct %u Expected %u dwControlID %u cChannels %u cMultipleItems %u cbDetails %u paDetails %p Flags %x\n",
2216 DeviceInfo->u.MixDetails.cbStruct, sizeof(MIXERCONTROLDETAILS), DeviceInfo->u.MixDetails.dwControlID, DeviceInfo->u.MixDetails.cChannels, DeviceInfo->u.MixDetails.cMultipleItems, DeviceInfo->u.MixDetails.cbDetails, DeviceInfo->u.MixDetails.paDetails, DeviceInfo->Flags);
2217
2218 if (DeviceInfo->Flags & MIXER_GETCONTROLDETAILSF_LISTTEXT)
2219 {
2220 UNIMPLEMENTED;
2221 return SetIrpIoStatus(Irp, STATUS_NOT_IMPLEMENTED, 0);
2222 }
2223
2224 /* get device extension */
2225 DeviceExtension = (PWDMAUD_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
2226
2227 /* get mixer control */
2228 Status = GetMixerControlById(&DeviceExtension->MixerInfo[(ULONG_PTR)DeviceInfo->hDevice], DeviceInfo->u.MixDetails.dwControlID, &MixerLine, &MixerControl, &NodeId);
2229
2230 if (!NT_SUCCESS(Status))
2231 {
2232 DPRINT1("MixerControl %x not found\n", DeviceInfo->u.MixDetails.dwControlID);
2233 return SetIrpIoStatus(Irp, STATUS_INVALID_PARAMETER, 0);
2234 }
2235
2236 Status = STATUS_NOT_IMPLEMENTED;
2237 DPRINT("dwLineId %x dwControlID %x dwControlType %x\n", MixerLine->Line.dwLineID, MixerControl->dwControlID, MixerControl->dwControlType);
2238 if (MixerControl->dwControlType == MIXERCONTROL_CONTROLTYPE_MUTE)
2239 {
2240 /* send the request */
2241 Status = SetGetMuteControlDetails(DeviceObject, MixerLine->DeviceIndex, NodeId, DeviceInfo, FALSE);
2242 }
2243 else if (MixerControl->dwControlType == MIXERCONTROL_CONTROLTYPE_VOLUME)
2244 {
2245 Status = SetGetVolumeControlDetails(DeviceObject, MixerLine->DeviceIndex, NodeId, DeviceInfo, FALSE, MixerControl, MixerLine);
2246 }
2247
2248 return SetIrpIoStatus(Irp, Status, sizeof(WDMAUD_DEVICE_INFO));
2249
2250 }
2251