2b0ced2042478bdfa9149c557616c044bdc83b2e
[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.cConnections; 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
1009 if (MixerControl->dwControlType == MIXERCONTROL_CONTROLTYPE_VOLUME)
1010 {
1011 KSNODEPROPERTY_AUDIO_CHANNEL Property;
1012 ULONG Length;
1013 PKSPROPERTY_DESCRIPTION Desc;
1014 PKSPROPERTY_MEMBERSHEADER Members;
1015 PKSPROPERTY_STEPPING_LONG Range;
1016
1017 Length = sizeof(KSPROPERTY_DESCRIPTION) + sizeof(KSPROPERTY_MEMBERSHEADER) + sizeof(KSPROPERTY_STEPPING_LONG);
1018 Desc = ExAllocatePool(NonPagedPool, Length);
1019 ASSERT(Desc);
1020 RtlZeroMemory(Desc, Length);
1021
1022 /* setup the request */
1023 RtlZeroMemory(&Property, sizeof(KSNODEPROPERTY_AUDIO_CHANNEL));
1024
1025 Property.NodeProperty.NodeId = NodeIndex;
1026 Property.NodeProperty.Property.Id = KSPROPERTY_AUDIO_VOLUMELEVEL;
1027 Property.NodeProperty.Property.Flags = KSPROPERTY_TYPE_BASICSUPPORT;
1028 Property.NodeProperty.Property.Set = KSPROPSETID_Audio;
1029
1030 /* get node volume level info */
1031 Status = KsSynchronousIoControlDevice(FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSNODEPROPERTY_AUDIO_CHANNEL), Desc, Length, &BytesReturned);
1032
1033 if (NT_SUCCESS(Status))
1034 {
1035 LPMIXERVOLUME_DATA VolumeData;
1036 ULONG Steps, MaxRange, Index;
1037 LONG Value;
1038
1039 Members = (PKSPROPERTY_MEMBERSHEADER)(Desc + 1);
1040 Range = (PKSPROPERTY_STEPPING_LONG)(Members + 1); //98304
1041
1042 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);
1043
1044 VolumeData = ExAllocatePool(NonPagedPool, sizeof(MIXERVOLUME_DATA));
1045 if (!VolumeData)
1046 return STATUS_INSUFFICIENT_RESOURCES;
1047
1048 MaxRange = (abs(Range->Bounds.SignedMinimum) + abs(Range->Bounds.SignedMaximum));
1049 Steps = MaxRange / Range->SteppingDelta + 1;
1050
1051 /* store mixer control info there */
1052 VolumeData->Header.dwControlID = MixerControl->dwControlID;
1053 VolumeData->SignedMaximum = Range->Bounds.SignedMaximum;
1054 VolumeData->SignedMinimum = Range->Bounds.SignedMinimum;
1055 VolumeData->SteppingDelta = Range->SteppingDelta;
1056 VolumeData->ValuesCount = Steps;
1057 VolumeData->InputSteppingDelta = 0x10000 / Steps;
1058
1059 VolumeData->Values = ExAllocatePool(NonPagedPool, sizeof(LONG) * Steps);
1060 if (!VolumeData->Values)
1061 {
1062 ExFreePool(Desc);
1063 ExFreePool(VolumeData);
1064
1065 return STATUS_INSUFFICIENT_RESOURCES;
1066 }
1067
1068 Value = Range->Bounds.SignedMinimum;
1069 for(Index = 0; Index < Steps; Index++)
1070 {
1071 VolumeData->Values[Index] = Value;
1072 Value += Range->SteppingDelta;
1073 }
1074 InsertTailList(&MixerLine->LineControlsExtraData, &VolumeData->Header.Entry);
1075 }
1076 ExFreePool(Desc);
1077 }
1078
1079
1080 DPRINT("Status %x Name %S\n", Status, MixerControl->szName);
1081 return STATUS_SUCCESS;
1082 }
1083
1084 NTSTATUS
1085 AddMixerSourceLine(
1086 IN OUT LPMIXER_INFO MixerInfo,
1087 IN PFILE_OBJECT FileObject,
1088 IN PKSMULTIPLE_ITEM NodeConnections,
1089 IN PKSMULTIPLE_ITEM NodeTypes,
1090 IN ULONG DeviceIndex,
1091 IN ULONG PinId,
1092 IN ULONG bBridgePin,
1093 IN ULONG bTargetPin)
1094 {
1095 LPMIXERLINE_EXT SrcLine, DstLine;
1096 NTSTATUS Status;
1097 KSP_PIN Pin;
1098 LPWSTR PinName;
1099 GUID NodeType;
1100 ULONG BytesReturned, ControlCount, Index;
1101 PULONG Nodes;
1102
1103 if (!bTargetPin)
1104 {
1105 /* allocate src mixer line */
1106 SrcLine = (LPMIXERLINE_EXT)ExAllocatePool(NonPagedPool, sizeof(MIXERLINE_EXT));
1107
1108 if (!SrcLine)
1109 return STATUS_INSUFFICIENT_RESOURCES;
1110
1111 /* zero struct */
1112 RtlZeroMemory(SrcLine, sizeof(MIXERLINE_EXT));
1113
1114 }
1115 else
1116 {
1117 ASSERT(!IsListEmpty(&MixerInfo->LineList));
1118 SrcLine = GetSourceMixerLineByLineId(MixerInfo, DESTINATION_LINE);
1119 }
1120
1121 /* get destination line */
1122 DstLine = GetSourceMixerLineByLineId(MixerInfo, DESTINATION_LINE);
1123 ASSERT(DstLine);
1124
1125
1126 if (!bTargetPin)
1127 {
1128 /* initialize mixer src line */
1129 SrcLine->DeviceIndex = DeviceIndex;
1130 SrcLine->PinId = PinId;
1131 SrcLine->Line.cbStruct = sizeof(MIXERLINEW);
1132
1133 /* initialize mixer destination line */
1134 SrcLine->Line.cbStruct = sizeof(MIXERLINEW);
1135 SrcLine->Line.dwDestination = 0;
1136 SrcLine->Line.dwSource = DstLine->Line.cConnections;
1137 SrcLine->Line.dwLineID = (DstLine->Line.cConnections * 0x10000);
1138 SrcLine->Line.fdwLine = MIXERLINE_LINEF_ACTIVE | MIXERLINE_LINEF_SOURCE;
1139 SrcLine->Line.dwUser = 0;
1140 SrcLine->Line.cChannels = DstLine->Line.cChannels;
1141 SrcLine->Line.cConnections = 0;
1142 SrcLine->Line.Target.dwType = 1;
1143 SrcLine->Line.Target.dwDeviceID = DstLine->Line.Target.dwDeviceID;
1144 SrcLine->Line.Target.wMid = MixerInfo->MixCaps.wMid;
1145 SrcLine->Line.Target.wPid = MixerInfo->MixCaps.wPid;
1146 SrcLine->Line.Target.vDriverVersion = MixerInfo->MixCaps.vDriverVersion;
1147 InitializeListHead(&SrcLine->LineControlsExtraData);
1148 wcscpy(SrcLine->Line.Target.szPname, MixerInfo->MixCaps.szPname);
1149
1150 }
1151
1152 /* allocate a node arrary */
1153 Nodes = ExAllocatePool(NonPagedPool, sizeof(ULONG) * NodeTypes->Count);
1154
1155 if (!Nodes)
1156 {
1157 /* not enough memory */
1158 if (!bTargetPin)
1159 {
1160 ExFreePool(SrcLine);
1161 }
1162 return STATUS_INSUFFICIENT_RESOURCES;
1163 }
1164
1165 /* clear nodes array */
1166 RtlZeroMemory(Nodes, sizeof(ULONG) * NodeTypes->Count);
1167
1168 Status = GetControlsFromPin(NodeConnections, NodeTypes, PinId, bTargetPin, Nodes);
1169 if (!NT_SUCCESS(Status))
1170 {
1171 /* something went wrong */
1172 if (!bTargetPin)
1173 {
1174 ExFreePool(SrcLine);
1175 }
1176 ExFreePool(Nodes);
1177 return Status;
1178 }
1179
1180 /* now count all nodes controlled by that pin */
1181 ControlCount = 0;
1182 for(Index = 0; Index < NodeTypes->Count; Index++)
1183 {
1184 if (Nodes[Index])
1185 ControlCount++;
1186 }
1187
1188 /* now allocate the line controls */
1189 if (ControlCount)
1190 {
1191 SrcLine->LineControls = ExAllocatePool(NonPagedPool, sizeof(MIXERCONTROLW) * ControlCount);
1192
1193 if (!SrcLine->LineControls)
1194 {
1195 /* no memory available */
1196 if (!bTargetPin)
1197 {
1198 ExFreePool(SrcLine);
1199 }
1200 ExFreePool(Nodes);
1201 return STATUS_INSUFFICIENT_RESOURCES;
1202 }
1203
1204 SrcLine->NodeIds = ExAllocatePool(NonPagedPool, sizeof(ULONG) * ControlCount);
1205 if (!SrcLine->NodeIds)
1206 {
1207 /* no memory available */
1208 ExFreePool(SrcLine->LineControls);
1209 if (!bTargetPin)
1210 {
1211 ExFreePool(SrcLine);
1212 }
1213 ExFreePool(Nodes);
1214 return STATUS_INSUFFICIENT_RESOURCES;
1215 }
1216
1217 /* zero line controls */
1218 RtlZeroMemory(SrcLine->LineControls, sizeof(MIXERCONTROLW) * ControlCount);
1219 RtlZeroMemory(SrcLine->NodeIds, sizeof(ULONG) * ControlCount);
1220
1221 ControlCount = 0;
1222 for(Index = 0; Index < NodeTypes->Count; Index++)
1223 {
1224 if (Nodes[Index])
1225 {
1226 /* store the node index for retrieving / setting details */
1227 SrcLine->NodeIds[ControlCount] = Index;
1228
1229 Status = AddMixerControl(MixerInfo, FileObject, NodeTypes, Index, SrcLine, &SrcLine->LineControls[ControlCount]);
1230 if (NT_SUCCESS(Status))
1231 {
1232 /* increment control count on success */
1233 ControlCount++;
1234 }
1235 }
1236 }
1237 /* store control count */
1238 SrcLine->Line.cControls = ControlCount;
1239 }
1240
1241 /* release nodes array */
1242 ExFreePool(Nodes);
1243
1244 /* get pin category */
1245 Pin.PinId = PinId;
1246 Pin.Reserved = 0;
1247 Pin.Property.Flags = KSPROPERTY_TYPE_GET;
1248 Pin.Property.Set = KSPROPSETID_Pin;
1249 Pin.Property.Id = KSPROPERTY_PIN_CATEGORY;
1250
1251 /* try get pin category */
1252 Status = KsSynchronousIoControlDevice(FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSP_PIN), (LPVOID)&NodeType, sizeof(GUID), &BytesReturned);
1253 if (NT_SUCCESS(Status))
1254 {
1255 //FIXME
1256 //map component type
1257 }
1258
1259 /* retrieve pin name */
1260 Pin.PinId = PinId;
1261 Pin.Reserved = 0;
1262 Pin.Property.Flags = KSPROPERTY_TYPE_GET;
1263 Pin.Property.Set = KSPROPSETID_Pin;
1264 Pin.Property.Id = KSPROPERTY_PIN_NAME;
1265
1266 /* try get pin name size */
1267 Status = KsSynchronousIoControlDevice(FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSP_PIN), NULL, 0, &BytesReturned);
1268
1269 if (Status != STATUS_MORE_ENTRIES)
1270 {
1271 SrcLine->Line.szShortName[0] = L'\0';
1272 SrcLine->Line.szName[0] = L'\0';
1273 }
1274 else
1275 {
1276 PinName = (LPWSTR)ExAllocatePool(NonPagedPool, BytesReturned);
1277 if (PinName)
1278 {
1279 /* try get pin name */
1280 Status = KsSynchronousIoControlDevice(FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSP_PIN), (LPVOID)PinName, BytesReturned, &BytesReturned);
1281
1282 if (NT_SUCCESS(Status))
1283 {
1284 RtlMoveMemory(SrcLine->Line.szShortName, PinName, (min(MIXER_SHORT_NAME_CHARS, wcslen(PinName)+1)) * sizeof(WCHAR));
1285 SrcLine->Line.szShortName[MIXER_SHORT_NAME_CHARS-1] = L'\0';
1286
1287 RtlMoveMemory(SrcLine->Line.szName, PinName, (min(MIXER_LONG_NAME_CHARS, wcslen(PinName)+1)) * sizeof(WCHAR));
1288 SrcLine->Line.szName[MIXER_LONG_NAME_CHARS-1] = L'\0';
1289 }
1290 ExFreePool(PinName);
1291 }
1292 }
1293
1294 /* insert src line */
1295 if (!bTargetPin)
1296 {
1297 InsertTailList(&MixerInfo->LineList, &SrcLine->Entry);
1298 DstLine->Line.cConnections++;
1299 }
1300
1301 return STATUS_SUCCESS;
1302 }
1303
1304
1305 NTSTATUS
1306 AddMixerSourceLines(
1307 IN OUT LPMIXER_INFO MixerInfo,
1308 IN PFILE_OBJECT FileObject,
1309 IN PKSMULTIPLE_ITEM NodeConnections,
1310 IN PKSMULTIPLE_ITEM NodeTypes,
1311 IN ULONG DeviceIndex,
1312 IN ULONG PinsCount,
1313 IN ULONG BridgePinIndex,
1314 IN ULONG TargetPinIndex,
1315 IN PULONG Pins)
1316 {
1317 ULONG Index;
1318 NTSTATUS Status = STATUS_SUCCESS;
1319
1320 for(Index = PinsCount; Index > 0; Index--)
1321 {
1322 if (Pins[Index-1])
1323 {
1324 AddMixerSourceLine(MixerInfo, FileObject, NodeConnections, NodeTypes, DeviceIndex, Index-1, (Index -1 == BridgePinIndex), (Index -1 == TargetPinIndex));
1325 }
1326 }
1327 return Status;
1328 }
1329
1330
1331
1332 NTSTATUS
1333 HandlePhysicalConnection(
1334 IN OUT LPMIXER_INFO MixerInfo,
1335 IN PDEVICE_OBJECT DeviceObject,
1336 IN ULONG bInput,
1337 IN PKSPIN_PHYSICALCONNECTION OutConnection)
1338 {
1339 PULONG PinsRef = NULL, PinConnectionIndex = NULL, PinsSrcRef;
1340 ULONG PinsRefCount, Index, PinConnectionIndexCount, DeviceIndex;
1341 NTSTATUS Status;
1342 HANDLE hDevice = NULL;
1343 PFILE_OBJECT FileObject = NULL;
1344 PKSMULTIPLE_ITEM NodeTypes = NULL;
1345 PKSMULTIPLE_ITEM NodeConnections = NULL;
1346 PULONG MixerControls;
1347 ULONG MixerControlsCount;
1348
1349
1350 /* open the connected filter */
1351 Status = OpenDevice(OutConnection->SymbolicLinkName, &hDevice, &FileObject);
1352 if (!NT_SUCCESS(Status))
1353 {
1354 DPRINT1("OpenDevice failed with %x\n", Status);
1355 return Status;
1356 }
1357
1358 /* get device index */
1359 DeviceIndex = GetDeviceIndexFromPnpName(DeviceObject, OutConnection->SymbolicLinkName);
1360
1361 /* get connected filter pin count */
1362 PinsRefCount = GetPinCount(FileObject);
1363 ASSERT(PinsRefCount);
1364
1365 PinsRef = AllocatePinArray(PinsRefCount);
1366 if (!PinsRef)
1367 {
1368 /* no memory */
1369 Status = STATUS_INSUFFICIENT_RESOURCES;
1370 goto cleanup;
1371 }
1372
1373 /* get topology node types */
1374 Status = GetFilterNodeProperty(FileObject, KSPROPERTY_TOPOLOGY_NODES, &NodeTypes);
1375 if (!NT_SUCCESS(Status))
1376 {
1377 DPRINT1("GetFilterNodeProperty failed with %x\n", Status);
1378 goto cleanup;
1379 }
1380
1381 /* get topology connections */
1382 Status = GetFilterNodeProperty(FileObject, KSPROPERTY_TOPOLOGY_CONNECTIONS, &NodeConnections);
1383 if (!NT_SUCCESS(Status))
1384 {
1385 DPRINT1("GetFilterNodeProperty failed with %x\n", Status);
1386 goto cleanup;
1387 }
1388 /* gets connection index of the bridge pin which connects to a node */
1389 DPRINT("Pin %u\n", OutConnection->Pin);
1390 Status = GetNodeIndexes(NodeConnections, OutConnection->Pin, FALSE, !bInput, &PinConnectionIndexCount, &PinConnectionIndex);
1391 if (!NT_SUCCESS(Status))
1392 {
1393 DPRINT1("GetNodeIndexes failed with %x\n", Status);
1394 goto cleanup;
1395 }
1396
1397 /* there should be no split in the bride pin */
1398 ASSERT(PinConnectionIndexCount == 1);
1399
1400 /* find all target pins of this connection */
1401 Status = GetTargetPinsByNodeConnectionIndex(NodeConnections, NodeTypes, FALSE, PinConnectionIndex[0], PinsRef);
1402 if (!NT_SUCCESS(Status))
1403 {
1404 DPRINT1("GetTargetPinsByNodeConnectionIndex failed with %x\n", Status);
1405 goto cleanup;
1406 }
1407
1408 for(Index = 0; Index < PinsRefCount; Index++)
1409 {
1410 if (PinsRef[Index])
1411 {
1412
1413 /* found a target pin, now get all references */
1414 Status = GetNodeIndexes(NodeConnections, Index, FALSE, FALSE, &MixerControlsCount, &MixerControls);
1415 if (!NT_SUCCESS(Status))
1416 break;
1417
1418 /* sanity check */
1419 ASSERT(MixerControlsCount == 1);
1420
1421
1422 PinsSrcRef = AllocatePinArray(PinsRefCount);
1423 if (!PinsSrcRef)
1424 {
1425 /* no memory */
1426 ExFreePool(MixerControls);
1427 Status = STATUS_INSUFFICIENT_RESOURCES;
1428 goto cleanup;
1429 }
1430 /* now get all connected source pins */
1431 Status = GetTargetPinsByNodeConnectionIndex(NodeConnections, NodeTypes, TRUE, MixerControls[0], PinsSrcRef);
1432 if (!NT_SUCCESS(Status))
1433 {
1434 /* no memory */
1435 ExFreePool(MixerControls);
1436 ExFreePool(PinsSrcRef);
1437 Status = STATUS_INSUFFICIENT_RESOURCES;
1438 goto cleanup;
1439 }
1440
1441 /* add pins from target line */
1442 if (!bInput)
1443 {
1444 // dont add bridge pin for input mixers
1445 PinsSrcRef[Index] = TRUE;
1446 PinsSrcRef[OutConnection->Pin] = TRUE;
1447 }
1448
1449 Status = AddMixerSourceLines(MixerInfo, FileObject, NodeConnections, NodeTypes, DeviceIndex, PinsRefCount, OutConnection->Pin, Index, PinsSrcRef);
1450
1451 ExFreePool(MixerControls);
1452 ExFreePool(PinsSrcRef);
1453 }
1454 }
1455
1456 cleanup:
1457
1458 if (PinsRef)
1459 ExFreePool(PinsRef);
1460
1461 if (NodeConnections)
1462 ExFreePool(NodeConnections);
1463
1464 if (NodeTypes)
1465 ExFreePool(NodeTypes);
1466
1467 if (FileObject)
1468 ObDereferenceObject(FileObject);
1469
1470 if (hDevice)
1471 ZwClose(hDevice);
1472
1473 if (PinConnectionIndex)
1474 ExFreePool(PinConnectionIndex);
1475
1476
1477 return Status;
1478 }
1479
1480
1481
1482 NTSTATUS
1483 InitializeMixer(
1484 IN PDEVICE_OBJECT DeviceObject,
1485 IN ULONG DeviceIndex,
1486 IN OUT LPMIXER_INFO MixerInfo,
1487 IN HANDLE hDevice,
1488 IN PFILE_OBJECT FileObject,
1489 IN ULONG PinCount,
1490 IN PKSMULTIPLE_ITEM NodeTypes,
1491 IN PKSMULTIPLE_ITEM NodeConnections,
1492 IN ULONG NodeIndex,
1493 IN ULONG bInput)
1494 {
1495 WCHAR Buffer[100];
1496 LPWSTR Device;
1497 NTSTATUS Status;
1498 PULONG Pins;
1499 ULONG Index;
1500 PKSPIN_PHYSICALCONNECTION OutConnection;
1501 LPMIXERLINE_EXT DestinationLine;
1502
1503 DestinationLine = ExAllocatePool(NonPagedPool, sizeof(MIXERLINE_EXT));
1504 if (!DestinationLine)
1505 return STATUS_INSUFFICIENT_RESOURCES;
1506
1507 /* intialize mixer caps */
1508 MixerInfo->MixCaps.wMid = MM_MICROSOFT; //FIXME
1509 MixerInfo->MixCaps.wPid = MM_PID_UNMAPPED; //FIXME
1510 MixerInfo->MixCaps.vDriverVersion = 1; //FIXME
1511 MixerInfo->MixCaps.fdwSupport = 0;
1512 MixerInfo->MixCaps.cDestinations = 1;
1513
1514 /* get target pnp name */
1515 Status = GetSysAudioDevicePnpName(DeviceObject, DeviceIndex, &Device);
1516 if (NT_SUCCESS(Status))
1517 {
1518 /* find product name */
1519 Status = FindProductName(Device, sizeof(Buffer) / sizeof(WCHAR), Buffer);
1520 if (NT_SUCCESS(Status))
1521 {
1522 if (bInput)
1523 wcscat(Buffer, L" Input");
1524 else
1525 wcscat(Buffer, L" output");
1526 RtlMoveMemory(MixerInfo->MixCaps.szPname, Buffer, min(MAXPNAMELEN, wcslen(Buffer)+1) * sizeof(WCHAR));
1527 MixerInfo->MixCaps.szPname[MAXPNAMELEN-1] = L'\0';
1528 }
1529 ExFreePool(Device);
1530 }
1531
1532 /* initialize mixer destination line */
1533 RtlZeroMemory(DestinationLine, sizeof(MIXERLINEW));
1534 DestinationLine->Line.cbStruct = sizeof(MIXERLINEW);
1535 DestinationLine->Line.dwSource = MAXULONG;
1536 DestinationLine->Line.dwLineID = DESTINATION_LINE;
1537 DestinationLine->Line.fdwLine = MIXERLINE_LINEF_ACTIVE;
1538 DestinationLine->Line.dwUser = 0;
1539 DestinationLine->Line.dwComponentType = (bInput == 0 ? MIXERLINE_COMPONENTTYPE_DST_SPEAKERS : MIXERLINE_COMPONENTTYPE_DST_WAVEIN);
1540 DestinationLine->Line.cChannels = 2; //FIXME
1541 wcscpy(DestinationLine->Line.szShortName, L"Summe"); //FIXME
1542 wcscpy(DestinationLine->Line.szName, L"Summe"); //FIXME
1543 DestinationLine->Line.Target.dwType = (bInput == 0 ? MIXERLINE_TARGETTYPE_WAVEOUT : MIXERLINE_TARGETTYPE_WAVEIN);
1544 DestinationLine->Line.Target.dwDeviceID = !bInput;
1545 DestinationLine->Line.Target.wMid = MixerInfo->MixCaps.wMid;
1546 DestinationLine->Line.Target.wPid = MixerInfo->MixCaps.wPid;
1547 DestinationLine->Line.Target.vDriverVersion = MixerInfo->MixCaps.vDriverVersion;
1548 wcscpy(DestinationLine->Line.Target.szPname, MixerInfo->MixCaps.szPname);
1549
1550 /* initialize source line list */
1551 InitializeListHead(&MixerInfo->LineList);
1552 InitializeListHead(&DestinationLine->LineControlsExtraData);
1553
1554 /* insert destination line */
1555 InsertHeadList(&MixerInfo->LineList, &DestinationLine->Entry);
1556
1557 Pins = AllocatePinArray(PinCount);
1558 if (!Pins)
1559 return STATUS_INSUFFICIENT_RESOURCES;
1560
1561 if (bInput)
1562 {
1563 Status = GetTargetPins(NodeTypes, NodeConnections, NodeIndex, TRUE, Pins, PinCount);
1564 }
1565 else
1566 {
1567 Status = GetTargetPins(NodeTypes, NodeConnections, NodeIndex, FALSE, Pins, PinCount);
1568 }
1569
1570 for(Index = 0; Index < PinCount; Index++)
1571 {
1572 if (Pins[Index])
1573 {
1574 Status = GetPhysicalConnection(FileObject, Index, &OutConnection);
1575 if (NT_SUCCESS(Status))
1576 {
1577 Status = HandlePhysicalConnection(MixerInfo, DeviceObject, bInput, OutConnection);
1578 ExFreePool(OutConnection);
1579 }
1580 }
1581 }
1582 ExFreePool(Pins);
1583
1584 return STATUS_SUCCESS;
1585 }
1586
1587 NTSTATUS
1588 WdmAudMixerInitialize(
1589 IN PDEVICE_OBJECT DeviceObject)
1590 {
1591 ULONG DeviceCount, Index, Count, NodeIndex, PinCount;
1592 NTSTATUS Status;
1593 HANDLE hDevice;
1594 PFILE_OBJECT FileObject;
1595 PKSMULTIPLE_ITEM NodeTypes, NodeConnections;
1596 PWDMAUD_DEVICE_EXTENSION DeviceExtension;
1597
1598 /* get device extension */
1599 DeviceExtension = (PWDMAUD_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
1600
1601
1602 /* get number of devices */
1603 DeviceCount = GetSysAudioDeviceCount(DeviceObject);
1604
1605 if (!DeviceCount)
1606 {
1607 /* no audio devices available atm */
1608 DeviceExtension->MixerInfoCount = 0;
1609 DeviceExtension->MixerInfo = NULL;
1610 return STATUS_SUCCESS;
1611 }
1612
1613 /* each virtual audio device can at most have an input + output mixer */
1614 DeviceExtension->MixerInfo = ExAllocatePool(NonPagedPool, sizeof(MIXER_INFO) * DeviceCount * 2);
1615 if (!DeviceExtension->MixerInfo)
1616 {
1617 /* not enough memory */
1618 return STATUS_INSUFFICIENT_RESOURCES;
1619 }
1620
1621 /* clear mixer info */
1622 RtlZeroMemory(DeviceExtension->MixerInfo, sizeof(MIXER_INFO) * DeviceCount * 2);
1623
1624 Index = 0;
1625 Count = 0;
1626 do
1627 {
1628 /* open the virtual audio device */
1629 Status = OpenSysAudioDeviceByIndex(DeviceObject, Index, &hDevice, &FileObject);
1630
1631 if (NT_SUCCESS(Status))
1632 {
1633 /* retrieve all available node types */
1634 Status = GetFilterNodeProperty(FileObject, KSPROPERTY_TOPOLOGY_NODES, &NodeTypes);
1635 if (!NT_SUCCESS(Status))
1636 {
1637 ObDereferenceObject(FileObject);
1638 ZwClose(hDevice);
1639 break;
1640 }
1641
1642 Status = GetFilterNodeProperty(FileObject, KSPROPERTY_TOPOLOGY_CONNECTIONS, &NodeConnections);
1643 if (!NT_SUCCESS(Status))
1644 {
1645 ObDereferenceObject(FileObject);
1646 ZwClose(hDevice);
1647 ExFreePool(NodeTypes);
1648 break;
1649 }
1650
1651 /* get num of pins */
1652 PinCount = GetPinCount(FileObject);
1653 /* get the first available dac node index */
1654 NodeIndex = GetNodeTypeIndex(NodeTypes, (LPGUID)&KSNODETYPE_DAC);
1655 if (NodeIndex != (ULONG)-1)
1656 {
1657 Status = InitializeMixer(DeviceObject, Index, &DeviceExtension->MixerInfo[Count], hDevice, FileObject, PinCount, NodeTypes, NodeConnections, NodeIndex, FALSE);
1658 if (NT_SUCCESS(Status))
1659 {
1660 /* increment mixer offset */
1661 Count++;
1662 }
1663 }
1664
1665 /* get the first available adc node index */
1666 NodeIndex = GetNodeTypeIndex(NodeTypes, (LPGUID)&KSNODETYPE_ADC);
1667 if (NodeIndex != (ULONG)-1)
1668 {
1669 Status = InitializeMixer(DeviceObject, Index, &DeviceExtension->MixerInfo[Count], hDevice, FileObject, PinCount, NodeTypes, NodeConnections, NodeIndex, TRUE);
1670 if (NT_SUCCESS(Status))
1671 {
1672 /* increment mixer offset */
1673 Count++;
1674 }
1675 }
1676
1677 /* free node connections array */
1678 ExFreePool(NodeTypes);
1679 ExFreePool(NodeConnections);
1680
1681 /* close virtual audio device */
1682 ObDereferenceObject(FileObject);
1683 ZwClose(hDevice);
1684
1685 }
1686 /* increment virtual audio device index */
1687 Index++;
1688 }while(Index < DeviceCount);
1689
1690 /* store mixer count */
1691 DeviceExtension->MixerInfoCount = Count;
1692
1693 return Status;
1694 }
1695
1696
1697
1698 NTSTATUS
1699 WdmAudMixerCapabilities(
1700 IN PDEVICE_OBJECT DeviceObject,
1701 IN PWDMAUD_DEVICE_INFO DeviceInfo,
1702 IN PWDMAUD_CLIENT ClientInfo,
1703 IN PWDMAUD_DEVICE_EXTENSION DeviceExtension)
1704 {
1705 if ((ULONG)DeviceInfo->hDevice >= DeviceExtension->MixerInfoCount)
1706 {
1707 /* invalid parameter */
1708 return STATUS_INVALID_PARAMETER;
1709 }
1710
1711 /* copy cached mixer caps */
1712 RtlMoveMemory(&DeviceInfo->u.MixCaps, &DeviceExtension->MixerInfo[(ULONG)DeviceInfo->hDevice].MixCaps, sizeof(MIXERCAPSW));
1713
1714 return STATUS_SUCCESS;
1715 }
1716
1717
1718 NTSTATUS
1719 WdmAudControlOpenMixer(
1720 IN PDEVICE_OBJECT DeviceObject,
1721 IN PIRP Irp,
1722 IN PWDMAUD_DEVICE_INFO DeviceInfo,
1723 IN PWDMAUD_CLIENT ClientInfo)
1724 {
1725 ULONG Index;
1726 PWDMAUD_HANDLE Handels;
1727 PWDMAUD_DEVICE_EXTENSION DeviceExtension;
1728
1729 DPRINT("WdmAudControlOpenMixer\n");
1730
1731 DeviceExtension = (PWDMAUD_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
1732
1733
1734 if (DeviceInfo->DeviceIndex >= DeviceExtension->MixerInfoCount)
1735 {
1736 /* mixer index doesnt exist */
1737 return SetIrpIoStatus(Irp, STATUS_UNSUCCESSFUL, 0);
1738 }
1739
1740 for(Index = 0; Index < ClientInfo->NumPins; Index++)
1741 {
1742 if (ClientInfo->hPins[Index].Handle == (HANDLE)DeviceInfo->DeviceIndex && ClientInfo->hPins[Index].Type == MIXER_DEVICE_TYPE)
1743 {
1744 /* re-use pseudo handle */
1745 DeviceInfo->hDevice = (HANDLE)DeviceInfo->DeviceIndex;
1746 return SetIrpIoStatus(Irp, STATUS_SUCCESS, sizeof(WDMAUD_DEVICE_INFO));
1747 }
1748 }
1749
1750 Handels = ExAllocatePool(NonPagedPool, sizeof(WDMAUD_HANDLE) * (ClientInfo->NumPins+1));
1751
1752 if (Handels)
1753 {
1754 if (ClientInfo->NumPins)
1755 {
1756 RtlMoveMemory(Handels, ClientInfo->hPins, sizeof(WDMAUD_HANDLE) * ClientInfo->NumPins);
1757 ExFreePool(ClientInfo->hPins);
1758 }
1759
1760 ClientInfo->hPins = Handels;
1761 ClientInfo->hPins[ClientInfo->NumPins].Handle = (HANDLE)DeviceInfo->DeviceIndex;
1762 ClientInfo->hPins[ClientInfo->NumPins].Type = MIXER_DEVICE_TYPE;
1763 ClientInfo->NumPins++;
1764 }
1765 else
1766 {
1767 return SetIrpIoStatus(Irp, STATUS_UNSUCCESSFUL, sizeof(WDMAUD_DEVICE_INFO));
1768 }
1769 DeviceInfo->hDevice = (HANDLE)DeviceInfo->DeviceIndex;
1770
1771 return SetIrpIoStatus(Irp, STATUS_SUCCESS, sizeof(WDMAUD_DEVICE_INFO));
1772 }
1773
1774 NTSTATUS
1775 NTAPI
1776 WdmAudGetLineInfo(
1777 IN PDEVICE_OBJECT DeviceObject,
1778 IN PIRP Irp,
1779 IN PWDMAUD_DEVICE_INFO DeviceInfo,
1780 IN PWDMAUD_CLIENT ClientInfo)
1781 {
1782 PWDMAUD_DEVICE_EXTENSION DeviceExtension;
1783 LPMIXERLINE_EXT MixerLineSrc;
1784
1785 /* get device extension */
1786 DeviceExtension = (PWDMAUD_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
1787
1788 DeviceInfo->Flags &= ~MIXER_OBJECTF_HMIXER;
1789
1790 if (DeviceInfo->Flags == MIXER_GETLINEINFOF_DESTINATION)
1791 {
1792 if ((ULONG)DeviceInfo->hDevice >= DeviceExtension->MixerInfoCount)
1793 {
1794 /* invalid parameter */
1795 return SetIrpIoStatus(Irp, STATUS_INVALID_PARAMETER, 0);
1796 }
1797
1798 if (DeviceInfo->u.MixLine.dwDestination != 0)
1799 {
1800 /* invalid parameter */
1801 return SetIrpIoStatus(Irp, STATUS_INVALID_PARAMETER, 0);
1802 }
1803 MixerLineSrc = GetSourceMixerLineByLineId(&DeviceExtension->MixerInfo[(ULONG)DeviceInfo->hDevice], DESTINATION_LINE);
1804 ASSERT(MixerLineSrc);
1805
1806 /* copy cached data */
1807 RtlCopyMemory(&DeviceInfo->u.MixLine, &MixerLineSrc->Line, sizeof(MIXERLINEW));
1808 return SetIrpIoStatus(Irp, STATUS_SUCCESS, sizeof(WDMAUD_DEVICE_INFO));
1809 }
1810 else if (DeviceInfo->Flags == MIXER_GETLINEINFOF_SOURCE)
1811 {
1812 if ((ULONG)DeviceInfo->hDevice >= DeviceExtension->MixerInfoCount)
1813 {
1814 /* invalid parameter */
1815 return SetIrpIoStatus(Irp, STATUS_INVALID_PARAMETER, 0);
1816 }
1817
1818 MixerLineSrc = GetSourceMixerLineByLineId(&DeviceExtension->MixerInfo[(ULONG)DeviceInfo->hDevice], DESTINATION_LINE);
1819 ASSERT(MixerLineSrc);
1820
1821 if (DeviceInfo->u.MixLine.dwSource >= MixerLineSrc->Line.cConnections)
1822 {
1823 DPRINT1("dwSource %u Destinations %u\n", DeviceInfo->u.MixLine.dwSource, MixerLineSrc->Line.cConnections);
1824 /* invalid parameter */
1825 return SetIrpIoStatus(Irp, STATUS_INVALID_PARAMETER, 0);
1826 }
1827
1828 MixerLineSrc = GetSourceMixerLine(&DeviceExtension->MixerInfo[(ULONG)DeviceInfo->hDevice], DeviceInfo->u.MixLine.dwSource);
1829 if (MixerLineSrc)
1830 {
1831 DPRINT("Line %u Name %S\n", MixerLineSrc->Line.dwSource, MixerLineSrc->Line.szName);
1832 RtlCopyMemory(&DeviceInfo->u.MixLine, &MixerLineSrc->Line, sizeof(MIXERLINEW));
1833 }
1834 return SetIrpIoStatus(Irp, STATUS_SUCCESS, sizeof(WDMAUD_DEVICE_INFO));
1835 }
1836 else if (DeviceInfo->Flags == MIXER_GETLINEINFOF_LINEID)
1837 {
1838 if ((ULONG)DeviceInfo->hDevice >= DeviceExtension->MixerInfoCount)
1839 {
1840 /* invalid parameter */
1841 return SetIrpIoStatus(Irp, STATUS_INVALID_PARAMETER, 0);
1842 }
1843
1844 MixerLineSrc = GetSourceMixerLineByLineId(&DeviceExtension->MixerInfo[(ULONG)DeviceInfo->hDevice], DeviceInfo->u.MixLine.dwLineID);
1845 ASSERT(MixerLineSrc);
1846
1847 /* copy cached data */
1848 RtlCopyMemory(&DeviceInfo->u.MixLine, &MixerLineSrc->Line, sizeof(MIXERLINEW));
1849 return SetIrpIoStatus(Irp, STATUS_SUCCESS, sizeof(WDMAUD_DEVICE_INFO));
1850 }
1851 else if (DeviceInfo->Flags == MIXER_GETLINEINFOF_COMPONENTTYPE)
1852 {
1853 if ((ULONG)DeviceInfo->hDevice >= DeviceExtension->MixerInfoCount)
1854 {
1855 /* invalid parameter */
1856 return SetIrpIoStatus(Irp, STATUS_INVALID_PARAMETER, 0);
1857 }
1858
1859 MixerLineSrc = GetSourceMixerLineByComponentType(&DeviceExtension->MixerInfo[(ULONG)DeviceInfo->hDevice], DeviceInfo->u.MixLine.dwComponentType);
1860 ASSERT(MixerLineSrc);
1861
1862 /* copy cached data */
1863 RtlCopyMemory(&DeviceInfo->u.MixLine, &MixerLineSrc->Line, sizeof(MIXERLINEW));
1864 return SetIrpIoStatus(Irp, STATUS_SUCCESS, sizeof(WDMAUD_DEVICE_INFO));
1865 }
1866
1867 DPRINT1("Flags %x\n", DeviceInfo->Flags);
1868 UNIMPLEMENTED;
1869
1870 //DbgBreakPoint();
1871 return SetIrpIoStatus(Irp, STATUS_NOT_IMPLEMENTED, 0);
1872
1873 }
1874
1875 NTSTATUS
1876 NTAPI
1877 WdmAudGetLineControls(
1878 IN PDEVICE_OBJECT DeviceObject,
1879 IN PIRP Irp,
1880 IN PWDMAUD_DEVICE_INFO DeviceInfo,
1881 IN PWDMAUD_CLIENT ClientInfo)
1882 {
1883 LPMIXERLINE_EXT MixerLineSrc;
1884 LPMIXERCONTROLW MixerControl;
1885 PWDMAUD_DEVICE_EXTENSION DeviceExtension;
1886 ULONG Index;
1887 NTSTATUS Status;
1888
1889 /* get device extension */
1890 DeviceExtension = (PWDMAUD_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
1891
1892 DeviceInfo->Flags &= ~MIXER_OBJECTF_HMIXER;
1893
1894 if (DeviceInfo->Flags == MIXER_GETLINECONTROLSF_ALL)
1895 {
1896 if ((ULONG)DeviceInfo->hDevice >= DeviceExtension->MixerInfoCount)
1897 {
1898 /* invalid parameter */
1899 return SetIrpIoStatus(Irp, STATUS_INVALID_PARAMETER, 0);
1900 }
1901
1902 MixerLineSrc = GetSourceMixerLineByLineId(&DeviceExtension->MixerInfo[(ULONG)DeviceInfo->hDevice], DeviceInfo->u.MixControls.dwLineID);
1903 ASSERT(MixerLineSrc);
1904 if (MixerLineSrc)
1905 {
1906 RtlMoveMemory(DeviceInfo->u.MixControls.pamxctrl, MixerLineSrc->LineControls, min(MixerLineSrc->Line.cControls, DeviceInfo->u.MixControls.cControls) * sizeof(MIXERCONTROLW));
1907 }
1908 return SetIrpIoStatus(Irp, STATUS_SUCCESS, sizeof(WDMAUD_DEVICE_INFO));
1909 }
1910 else if (DeviceInfo->Flags == MIXER_GETLINECONTROLSF_ONEBYTYPE)
1911 {
1912 if ((ULONG)DeviceInfo->hDevice >= DeviceExtension->MixerInfoCount)
1913 {
1914 /* invalid parameter */
1915 return SetIrpIoStatus(Irp, STATUS_INVALID_PARAMETER, 0);
1916 }
1917
1918 MixerLineSrc = GetSourceMixerLineByLineId(&DeviceExtension->MixerInfo[(ULONG)DeviceInfo->hDevice], DeviceInfo->u.MixControls.dwLineID);
1919 ASSERT(MixerLineSrc);
1920
1921 Index = 0;
1922 for(Index = 0; Index < MixerLineSrc->Line.cControls; Index++)
1923 {
1924 DPRINT1("dwControlType %x\n", MixerLineSrc->LineControls[Index].dwControlType);
1925 if (DeviceInfo->u.MixControls.dwControlType == MixerLineSrc->LineControls[Index].dwControlType)
1926 {
1927 RtlMoveMemory(DeviceInfo->u.MixControls.pamxctrl, &MixerLineSrc->LineControls[Index], sizeof(MIXERCONTROLW));
1928 return SetIrpIoStatus(Irp, STATUS_SUCCESS, sizeof(WDMAUD_DEVICE_INFO));
1929 }
1930 }
1931 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);
1932 return SetIrpIoStatus(Irp, STATUS_UNSUCCESSFUL, sizeof(WDMAUD_DEVICE_INFO));
1933 }
1934 else if (DeviceInfo->Flags == MIXER_GETLINECONTROLSF_ONEBYID)
1935 {
1936 if ((ULONG)DeviceInfo->hDevice >= DeviceExtension->MixerInfoCount)
1937 {
1938 /* invalid parameter */
1939 return SetIrpIoStatus(Irp, STATUS_INVALID_PARAMETER, 0);
1940 }
1941
1942 Status = GetMixerControlById(&DeviceExtension->MixerInfo[(ULONG)DeviceInfo->hDevice], DeviceInfo->u.MixControls.dwControlID, NULL, &MixerControl, NULL);
1943 if (NT_SUCCESS(Status))
1944 {
1945 RtlMoveMemory(DeviceInfo->u.MixControls.pamxctrl, MixerControl, sizeof(MIXERCONTROLW));
1946 }
1947 return SetIrpIoStatus(Irp, Status, sizeof(WDMAUD_DEVICE_INFO));
1948 }
1949
1950
1951 UNIMPLEMENTED;
1952 //DbgBreakPoint();
1953 return SetIrpIoStatus(Irp, STATUS_NOT_IMPLEMENTED, 0);
1954
1955 }
1956
1957 NTSTATUS
1958 SetGetControlDetails(
1959 IN PDEVICE_OBJECT DeviceObject,
1960 IN ULONG DeviceId,
1961 IN ULONG NodeId,
1962 IN PWDMAUD_DEVICE_INFO DeviceInfo,
1963 IN ULONG bSet,
1964 IN ULONG PropertyId,
1965 IN ULONG Channel,
1966 IN PLONG InputValue)
1967 {
1968 KSNODEPROPERTY_AUDIO_CHANNEL Property;
1969 NTSTATUS Status;
1970 HANDLE hDevice;
1971 PFILE_OBJECT FileObject;
1972 LONG Value;
1973 ULONG BytesReturned;
1974
1975 if (bSet)
1976 Value = *InputValue;
1977
1978 /* open virtual audio device */
1979 Status = OpenSysAudioDeviceByIndex(DeviceObject, DeviceId, &hDevice, &FileObject);
1980
1981 if (!NT_SUCCESS(Status))
1982 {
1983 /* failed */
1984 return Status;
1985 }
1986
1987 /* setup the request */
1988 RtlZeroMemory(&Property, sizeof(KSNODEPROPERTY_AUDIO_CHANNEL));
1989
1990 Property.NodeProperty.NodeId = NodeId;
1991 Property.NodeProperty.Property.Id = PropertyId;
1992 Property.NodeProperty.Property.Flags = KSPROPERTY_TYPE_TOPOLOGY;
1993 Property.NodeProperty.Property.Set = KSPROPSETID_Audio;
1994 Property.Channel = Channel;
1995
1996 if (bSet)
1997 Property.NodeProperty.Property.Flags |= KSPROPERTY_TYPE_SET;
1998 else
1999 Property.NodeProperty.Property.Flags |= KSPROPERTY_TYPE_GET;
2000
2001 /* send the request */
2002 Status = KsSynchronousIoControlDevice(FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSNODEPROPERTY_AUDIO_CHANNEL), (PVOID)&Value, sizeof(LONG), &BytesReturned);
2003
2004 ObDereferenceObject(FileObject);
2005 ZwClose(hDevice);
2006
2007 if (!bSet)
2008 {
2009 *InputValue = Value;
2010 }
2011
2012 DPRINT1("Status %x bSet %u NodeId %u Value %d PropertyId %u\n", Status, bSet, NodeId, Value, PropertyId);
2013 return Status;
2014 }
2015
2016 NTSTATUS
2017 SetGetMuteControlDetails(
2018 IN PDEVICE_OBJECT DeviceObject,
2019 IN ULONG DeviceId,
2020 IN ULONG NodeId,
2021 IN PWDMAUD_DEVICE_INFO DeviceInfo,
2022 IN ULONG bSet)
2023 {
2024 LPMIXERCONTROLDETAILS_BOOLEAN Input;
2025 LONG Value;
2026 NTSTATUS Status;
2027
2028 if (DeviceInfo->u.MixDetails.cbDetails != sizeof(MIXERCONTROLDETAILS_BOOLEAN))
2029 return STATUS_INVALID_PARAMETER;
2030
2031 /* get input */
2032 Input = (LPMIXERCONTROLDETAILS_BOOLEAN)DeviceInfo->u.MixDetails.paDetails;
2033
2034 /* FIXME SEH */
2035 if (bSet)
2036 Value = Input->fValue;
2037
2038 /* set control details */
2039 Status = SetGetControlDetails(DeviceObject, DeviceId, NodeId, DeviceInfo, bSet, KSPROPERTY_AUDIO_MUTE, MAXULONG, &Value);
2040
2041 /* FIXME SEH */
2042 if (!bSet)
2043 Input->fValue = Value;
2044
2045 return Status;
2046 }
2047
2048 NTSTATUS
2049 SetGetVolumeControlDetails(
2050 IN PDEVICE_OBJECT DeviceObject,
2051 IN ULONG DeviceId,
2052 IN ULONG NodeId,
2053 IN PWDMAUD_DEVICE_INFO DeviceInfo,
2054 IN ULONG bSet,
2055 LPMIXERCONTROLW MixerControl,
2056 LPMIXERLINE_EXT MixerLine)
2057 {
2058 LPMIXERCONTROLDETAILS_UNSIGNED Input;
2059 LONG Value, Index, Channel = 0;
2060 NTSTATUS Status;
2061 LPMIXERVOLUME_DATA VolumeData;
2062
2063 if (DeviceInfo->u.MixDetails.cbDetails != sizeof(MIXERCONTROLDETAILS_SIGNED))
2064 return STATUS_INVALID_PARAMETER;
2065
2066 VolumeData = (LPMIXERVOLUME_DATA)GetMixerControlDataById(&MixerLine->LineControlsExtraData, MixerControl->dwControlID);
2067 if (!VolumeData)
2068 return STATUS_INSUFFICIENT_RESOURCES;
2069
2070
2071 /* get input */
2072 Input = (LPMIXERCONTROLDETAILS_UNSIGNED)DeviceInfo->u.MixDetails.paDetails;
2073
2074 if (bSet)
2075 {
2076 /* FIXME SEH */
2077 Value = Input->dwValue;
2078 Index = Value / VolumeData->InputSteppingDelta;
2079
2080 if (Index >= VolumeData->ValuesCount)
2081 {
2082 DPRINT1("Index %u out of bounds %u \n", Index, VolumeData->ValuesCount);
2083 DbgBreakPoint();
2084 return STATUS_INVALID_PARAMETER;
2085 }
2086
2087 Value = VolumeData->Values[Index];
2088 }
2089
2090 /* set control details */
2091 if (bSet)
2092 {
2093 Status = SetGetControlDetails(DeviceObject, DeviceId, NodeId, DeviceInfo, bSet, KSPROPERTY_AUDIO_VOLUMELEVEL, 0, &Value);
2094 Status = SetGetControlDetails(DeviceObject, DeviceId, NodeId, DeviceInfo, bSet, KSPROPERTY_AUDIO_VOLUMELEVEL, 1, &Value);
2095 }
2096 else
2097 {
2098 Status = SetGetControlDetails(DeviceObject, DeviceId, NodeId, DeviceInfo, bSet, KSPROPERTY_AUDIO_VOLUMELEVEL, Channel, &Value);
2099 }
2100
2101 if (!bSet)
2102 {
2103 for(Index = 0; Index < VolumeData->ValuesCount; Index++)
2104 {
2105 if (VolumeData->Values[Index] > Value)
2106 {
2107 /* FIXME SEH */
2108 Input->dwValue = VolumeData->InputSteppingDelta * Index;
2109 return Status;
2110 }
2111 }
2112 Input->dwValue = VolumeData->InputSteppingDelta * (VolumeData->ValuesCount-1);
2113 }
2114
2115 return Status;
2116 }
2117
2118 NTSTATUS
2119 NTAPI
2120 WdmAudSetControlDetails(
2121 IN PDEVICE_OBJECT DeviceObject,
2122 IN PIRP Irp,
2123 IN PWDMAUD_DEVICE_INFO DeviceInfo,
2124 IN PWDMAUD_CLIENT ClientInfo)
2125 {
2126 LPMIXERLINE_EXT MixerLine;
2127 LPMIXERCONTROLW MixerControl;
2128 ULONG NodeId;
2129 PWDMAUD_DEVICE_EXTENSION DeviceExtension;
2130 NTSTATUS Status;
2131
2132 DeviceInfo->Flags &= ~MIXER_OBJECTF_HMIXER;
2133
2134 DPRINT("cbStruct %u Expected %u dwControlID %u cChannels %u cMultipleItems %u cbDetails %u paDetails %p Flags %x\n",
2135 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);
2136
2137 if (DeviceInfo->Flags & MIXER_GETCONTROLDETAILSF_LISTTEXT)
2138 {
2139 UNIMPLEMENTED;
2140 return SetIrpIoStatus(Irp, STATUS_NOT_IMPLEMENTED, 0);
2141 }
2142
2143 /* get device extension */
2144 DeviceExtension = (PWDMAUD_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
2145
2146 /* get mixer control */
2147 Status = GetMixerControlById(&DeviceExtension->MixerInfo[(ULONG)DeviceInfo->hDevice], DeviceInfo->u.MixDetails.dwControlID, &MixerLine, &MixerControl, &NodeId);
2148
2149 if (!NT_SUCCESS(Status))
2150 {
2151 DPRINT1("MixerControl %x not found\n", DeviceInfo->u.MixDetails.dwControlID);
2152 return SetIrpIoStatus(Irp, STATUS_INVALID_PARAMETER, 0);
2153 }
2154
2155 Status = STATUS_NOT_IMPLEMENTED;
2156 DPRINT("dwLineId %x dwControlID %x dwControlType %x\n", MixerLine->Line.dwLineID, MixerControl->dwControlID, MixerControl->dwControlType);
2157 if (MixerControl->dwControlType == MIXERCONTROL_CONTROLTYPE_MUTE)
2158 {
2159 /* send the request */
2160 Status = SetGetMuteControlDetails(DeviceObject, MixerLine->DeviceIndex, NodeId, DeviceInfo, TRUE);
2161 }
2162 else if (MixerControl->dwControlType == MIXERCONTROL_CONTROLTYPE_VOLUME)
2163 {
2164 Status = SetGetVolumeControlDetails(DeviceObject, MixerLine->DeviceIndex, NodeId, DeviceInfo, TRUE, MixerControl, MixerLine);
2165 }
2166 return SetIrpIoStatus(Irp, Status, sizeof(WDMAUD_DEVICE_INFO));
2167
2168 }
2169
2170 NTSTATUS
2171 NTAPI
2172 WdmAudGetControlDetails(
2173 IN PDEVICE_OBJECT DeviceObject,
2174 IN PIRP Irp,
2175 IN PWDMAUD_DEVICE_INFO DeviceInfo,
2176 IN PWDMAUD_CLIENT ClientInfo)
2177 {
2178 LPMIXERLINE_EXT MixerLine;
2179 LPMIXERCONTROLW MixerControl;
2180 ULONG NodeId;
2181 PWDMAUD_DEVICE_EXTENSION DeviceExtension;
2182 NTSTATUS Status;
2183
2184 DeviceInfo->Flags &= ~MIXER_OBJECTF_HMIXER;
2185
2186 DPRINT("cbStruct %u Expected %u dwControlID %u cChannels %u cMultipleItems %u cbDetails %u paDetails %p Flags %x\n",
2187 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);
2188
2189 if (DeviceInfo->Flags & MIXER_GETCONTROLDETAILSF_LISTTEXT)
2190 {
2191 UNIMPLEMENTED;
2192 return SetIrpIoStatus(Irp, STATUS_NOT_IMPLEMENTED, 0);
2193 }
2194
2195 /* get device extension */
2196 DeviceExtension = (PWDMAUD_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
2197
2198 /* get mixer control */
2199 Status = GetMixerControlById(&DeviceExtension->MixerInfo[(ULONG)DeviceInfo->hDevice], DeviceInfo->u.MixDetails.dwControlID, &MixerLine, &MixerControl, &NodeId);
2200
2201 if (!NT_SUCCESS(Status))
2202 {
2203 DPRINT1("MixerControl %x not found\n", DeviceInfo->u.MixDetails.dwControlID);
2204 return SetIrpIoStatus(Irp, STATUS_INVALID_PARAMETER, 0);
2205 }
2206
2207 Status = STATUS_NOT_IMPLEMENTED;
2208 if (MixerControl->dwControlType == MIXERCONTROL_CONTROLTYPE_MUTE)
2209 {
2210 /* send the request */
2211 Status = SetGetMuteControlDetails(DeviceObject, MixerLine->DeviceIndex, NodeId, DeviceInfo, FALSE);
2212 }
2213 else if (MixerControl->dwControlType == MIXERCONTROL_CONTROLTYPE_VOLUME)
2214 {
2215 Status = SetGetVolumeControlDetails(DeviceObject, MixerLine->DeviceIndex, NodeId, DeviceInfo, FALSE, MixerControl, MixerLine);
2216 }
2217
2218 return SetIrpIoStatus(Irp, Status, sizeof(WDMAUD_DEVICE_INFO));
2219
2220 }
2221