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