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