13ba3169cb85c1f5737d27b3f9f73b11343d1ea4
[reactos.git] / reactos / lib / drivers / sound / mmixer / controls.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Kernel Streaming
4 * FILE: lib/drivers/sound/mmixer/controls.c
5 * PURPOSE: Mixer Control Iteration Functions
6 * PROGRAMMER: Johannes Anderwald
7 */
8
9 #include "priv.h"
10
11 MIXER_STATUS
12 MMixerGetTargetPinsByNodeConnectionIndex(
13 IN PMIXER_CONTEXT MixerContext,
14 IN PKSMULTIPLE_ITEM NodeConnections,
15 IN PKSMULTIPLE_ITEM NodeTypes,
16 IN ULONG bUpDirection,
17 IN ULONG NodeConnectionIndex,
18 OUT PULONG Pins)
19 {
20 PKSTOPOLOGY_CONNECTION Connection;
21 ULONG PinId, NodeConnectionCount, Index;
22 PULONG NodeConnection;
23 MIXER_STATUS Status;
24
25
26 /* sanity check */
27 ASSERT(NodeConnectionIndex < NodeConnections->Count);
28
29 Connection = (PKSTOPOLOGY_CONNECTION)(NodeConnections + 1);
30
31 //DPRINT("FromNode %u FromNodePin %u -> ToNode %u ToNodePin %u\n", Connection[NodeConnectionIndex].FromNode, Connection[NodeConnectionIndex].FromNodePin, Connection[NodeConnectionIndex].ToNode, Connection[NodeConnectionIndex].ToNodePin );
32
33 if ((Connection[NodeConnectionIndex].ToNode == KSFILTER_NODE && bUpDirection == FALSE) ||
34 (Connection[NodeConnectionIndex].FromNode == KSFILTER_NODE && bUpDirection == TRUE))
35 {
36 /* iteration stops here */
37 if (bUpDirection)
38 PinId = Connection[NodeConnectionIndex].FromNodePin;
39 else
40 PinId = Connection[NodeConnectionIndex].ToNodePin;
41
42 //DPRINT("GetTargetPinsByNodeIndex FOUND Target Pin %u Parsed %u\n", PinId, Pins[PinId]);
43
44 /* mark pin index as a target pin */
45 Pins[PinId] = TRUE;
46 return MM_STATUS_SUCCESS;
47 }
48
49 // get all node indexes referenced by that node
50 if (bUpDirection)
51 {
52 Status = MMixerGetNodeIndexes(MixerContext, NodeConnections, Connection[NodeConnectionIndex].FromNode, TRUE, FALSE, &NodeConnectionCount, &NodeConnection);
53 }
54 else
55 {
56 Status = MMixerGetNodeIndexes(MixerContext, NodeConnections, Connection[NodeConnectionIndex].ToNode, TRUE, TRUE, &NodeConnectionCount, &NodeConnection);
57 }
58
59 if (Status == MM_STATUS_SUCCESS)
60 {
61 for(Index = 0; Index < NodeConnectionCount; Index++)
62 {
63 // iterate recursively into the nodes
64 Status = MMixerGetTargetPinsByNodeConnectionIndex(MixerContext, NodeConnections, NodeTypes, bUpDirection, NodeConnection[Index], Pins);
65 ASSERT(Status == MM_STATUS_SUCCESS);
66 }
67 // free node connection indexes
68 MixerContext->Free(NodeConnection);
69 }
70
71 return Status;
72 }
73
74 MIXER_STATUS
75 MMixerGetControlsFromPinByConnectionIndex(
76 IN PMIXER_CONTEXT MixerContext,
77 IN PKSMULTIPLE_ITEM NodeConnections,
78 IN PKSMULTIPLE_ITEM NodeTypes,
79 IN ULONG bUpDirection,
80 IN ULONG NodeConnectionIndex,
81 OUT PULONG Nodes)
82 {
83 PKSTOPOLOGY_CONNECTION CurConnection;
84 LPGUID NodeType;
85 ULONG NodeIndex;
86 MIXER_STATUS Status;
87 ULONG NodeConnectionCount, Index;
88 PULONG NodeConnection;
89
90
91 /* get current connection */
92 CurConnection = MMixerGetConnectionByIndex(NodeConnections, NodeConnectionIndex);
93
94 if (bUpDirection)
95 NodeIndex = CurConnection->FromNode;
96 else
97 NodeIndex = CurConnection->ToNode;
98
99 if (NodeIndex > NodeTypes->Count)
100 {
101 // reached end of pin connection
102 return MM_STATUS_SUCCESS;
103 }
104
105 /* get target node type of current connection */
106 NodeType = MMixerGetNodeType(NodeTypes, NodeIndex);
107
108 if (IsEqualGUIDAligned(NodeType, &KSNODETYPE_SUM) || IsEqualGUIDAligned(NodeType, &KSNODETYPE_MUX))
109 {
110 if (bUpDirection)
111 {
112 /* add the sum / mux node to destination line */
113 Nodes[NodeIndex] = TRUE;
114 }
115
116 return MM_STATUS_SUCCESS;
117 }
118
119 /* now add the node */
120 Nodes[NodeIndex] = TRUE;
121
122
123 /* get all node indexes referenced by that node */
124 if (bUpDirection)
125 {
126 Status = MMixerGetNodeIndexes(MixerContext, NodeConnections, NodeIndex, TRUE, FALSE, &NodeConnectionCount, &NodeConnection);
127 }
128 else
129 {
130 Status = MMixerGetNodeIndexes(MixerContext, NodeConnections, NodeIndex, TRUE, TRUE, &NodeConnectionCount, &NodeConnection);
131 }
132
133 if (Status == MM_STATUS_SUCCESS)
134 {
135 for(Index = 0; Index < NodeConnectionCount; Index++)
136 {
137 /* iterate recursively into the nodes */
138 Status = MMixerGetControlsFromPinByConnectionIndex(MixerContext, NodeConnections, NodeTypes, bUpDirection, NodeConnection[Index], Nodes);
139 ASSERT(Status == MM_STATUS_SUCCESS);
140 }
141 /* free node connection indexes */
142 MixerContext->Free(NodeConnection);
143 }
144
145 return Status;
146 }
147
148 MIXER_STATUS
149 MMixerAddMixerControl(
150 IN PMIXER_CONTEXT MixerContext,
151 IN LPMIXER_INFO MixerInfo,
152 IN HANDLE hDevice,
153 IN PKSMULTIPLE_ITEM NodeTypes,
154 IN ULONG NodeIndex,
155 IN LPMIXERLINE_EXT MixerLine,
156 OUT LPMIXERCONTROLW MixerControl)
157 {
158 LPGUID NodeType;
159 KSP_NODE Node;
160 ULONG BytesReturned;
161 MIXER_STATUS Status;
162 LPWSTR Name;
163
164 /* initialize mixer control */
165 MixerControl->cbStruct = sizeof(MIXERCONTROLW);
166 MixerControl->dwControlID = MixerInfo->ControlId;
167
168 /* get node type */
169 NodeType = MMixerGetNodeType(NodeTypes, NodeIndex);
170 /* store control type */
171 MixerControl->dwControlType = MMixerGetControlTypeFromTopologyNode(NodeType);
172
173 MixerControl->fdwControl = MIXERCONTROL_CONTROLF_UNIFORM; //FIXME
174 MixerControl->cMultipleItems = 0; //FIXME
175
176 if (MixerControl->dwControlType == MIXERCONTROL_CONTROLTYPE_MUTE)
177 {
178 MixerControl->Bounds.dwMinimum = 0;
179 MixerControl->Bounds.dwMaximum = 1;
180 }
181 else if (MixerControl->dwControlType == MIXERCONTROL_CONTROLTYPE_VOLUME)
182 {
183 MixerControl->Bounds.dwMinimum = 0;
184 MixerControl->Bounds.dwMaximum = 0xFFFF;
185 MixerControl->Metrics.cSteps = 0xC0; //FIXME
186 }
187
188 /* setup request to retrieve name */
189 Node.NodeId = NodeIndex;
190 Node.Property.Id = KSPROPERTY_TOPOLOGY_NAME;
191 Node.Property.Flags = KSPROPERTY_TYPE_GET;
192 Node.Property.Set = KSPROPSETID_Topology;
193 Node.Reserved = 0;
194
195 /* get node name size */
196 Status = MixerContext->Control(hDevice, IOCTL_KS_PROPERTY, (PVOID)&Node, sizeof(KSP_NODE), NULL, 0, &BytesReturned);
197
198 if (Status == MM_STATUS_MORE_ENTRIES)
199 {
200 ASSERT(BytesReturned != 0);
201 Name = (LPWSTR)MixerContext->Alloc(BytesReturned);
202 if (!Name)
203 {
204 /* not enough memory */
205 return MM_STATUS_NO_MEMORY;
206 }
207
208 /* get node name */
209 Status = MixerContext->Control(hDevice, IOCTL_KS_PROPERTY, (PVOID)&Node, sizeof(KSP_NODE), (LPVOID)Name, BytesReturned, &BytesReturned);
210 if (Status != MM_STATUS_SUCCESS)
211 {
212 MixerContext->Copy(MixerControl->szShortName, Name, (min(MIXER_SHORT_NAME_CHARS, wcslen(Name)+1)) * sizeof(WCHAR));
213 MixerControl->szShortName[MIXER_SHORT_NAME_CHARS-1] = L'\0';
214
215 MixerContext->Copy(MixerControl->szName, Name, (min(MIXER_LONG_NAME_CHARS, wcslen(Name)+1)) * sizeof(WCHAR));
216 MixerControl->szName[MIXER_LONG_NAME_CHARS-1] = L'\0';
217 }
218
219 /* free name buffer */
220 MixerContext->Free(Name);
221 }
222
223 MixerInfo->ControlId++;
224 #if 0
225 if (MixerControl->dwControlType == MIXERCONTROL_CONTROLTYPE_MUX)
226 {
227 KSNODEPROPERTY Property;
228 ULONG PinId = 2;
229
230 /* setup the request */
231 RtlZeroMemory(&Property, sizeof(KSNODEPROPERTY));
232
233 Property.NodeId = NodeIndex;
234 Property.Property.Id = KSPROPERTY_AUDIO_MUX_SOURCE;
235 Property.Property.Flags = KSPROPERTY_TYPE_SET;
236 Property.Property.Set = KSPROPSETID_Audio;
237
238 /* get node volume level info */
239 Status = MixerContext->Control(hDevice, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSNODEPROPERTY), (PVOID)&PinId, sizeof(ULONG), &BytesReturned);
240
241 DPRINT1("Status %x NodeIndex %u PinId %u\n", Status, NodeIndex, PinId);
242 //DbgBreakPoint();
243 }else
244 #endif
245 if (MixerControl->dwControlType == MIXERCONTROL_CONTROLTYPE_VOLUME)
246 {
247 KSNODEPROPERTY_AUDIO_CHANNEL Property;
248 ULONG Length;
249 PKSPROPERTY_DESCRIPTION Desc;
250 PKSPROPERTY_MEMBERSHEADER Members;
251 PKSPROPERTY_STEPPING_LONG Range;
252
253 Length = sizeof(KSPROPERTY_DESCRIPTION) + sizeof(KSPROPERTY_MEMBERSHEADER) + sizeof(KSPROPERTY_STEPPING_LONG);
254 Desc = (PKSPROPERTY_DESCRIPTION)MixerContext->Alloc(Length);
255 ASSERT(Desc);
256
257 /* setup the request */
258 RtlZeroMemory(&Property, sizeof(KSNODEPROPERTY_AUDIO_CHANNEL));
259
260 Property.NodeProperty.NodeId = NodeIndex;
261 Property.NodeProperty.Property.Id = KSPROPERTY_AUDIO_VOLUMELEVEL;
262 Property.NodeProperty.Property.Flags = KSPROPERTY_TYPE_BASICSUPPORT;
263 Property.NodeProperty.Property.Set = KSPROPSETID_Audio;
264
265 /* get node volume level info */
266 Status = MixerContext->Control(hDevice, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSNODEPROPERTY_AUDIO_CHANNEL), Desc, Length, &BytesReturned);
267
268 if (Status == MM_STATUS_SUCCESS)
269 {
270 LPMIXERVOLUME_DATA VolumeData;
271 ULONG Steps, MaxRange, Index;
272 LONG Value;
273
274 Members = (PKSPROPERTY_MEMBERSHEADER)(Desc + 1);
275 Range = (PKSPROPERTY_STEPPING_LONG)(Members + 1);
276
277 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);
278
279 MaxRange = Range->Bounds.UnsignedMaximum - Range->Bounds.UnsignedMinimum;
280
281 if (MaxRange)
282 {
283 ASSERT(MaxRange);
284 VolumeData = (LPMIXERVOLUME_DATA)MixerContext->Alloc(sizeof(MIXERVOLUME_DATA));
285 if (!VolumeData)
286 return MM_STATUS_NO_MEMORY;
287
288 Steps = MaxRange / Range->SteppingDelta + 1;
289
290 /* store mixer control info there */
291 VolumeData->Header.dwControlID = MixerControl->dwControlID;
292 VolumeData->SignedMaximum = Range->Bounds.SignedMaximum;
293 VolumeData->SignedMinimum = Range->Bounds.SignedMinimum;
294 VolumeData->SteppingDelta = Range->SteppingDelta;
295 VolumeData->ValuesCount = Steps;
296 VolumeData->InputSteppingDelta = 0x10000 / Steps;
297
298 VolumeData->Values = (PLONG)MixerContext->Alloc(sizeof(LONG) * Steps);
299 if (!VolumeData->Values)
300 {
301 MixerContext->Free(Desc);
302 MixerContext->Free(VolumeData);
303
304 return MM_STATUS_NO_MEMORY;
305 }
306
307 Value = Range->Bounds.SignedMinimum;
308 for(Index = 0; Index < Steps; Index++)
309 {
310 VolumeData->Values[Index] = Value;
311 Value += Range->SteppingDelta;
312 }
313 InsertTailList(&MixerLine->LineControlsExtraData, &VolumeData->Header.Entry);
314 }
315 }
316 MixerContext->Free(Desc);
317 }
318
319
320 DPRINT("Status %x Name %S\n", Status, MixerControl->szName);
321 return MM_STATUS_SUCCESS;
322 }
323
324 MIXER_STATUS
325 MMixerAddMixerSourceLine(
326 IN PMIXER_CONTEXT MixerContext,
327 IN OUT LPMIXER_INFO MixerInfo,
328 IN HANDLE hDevice,
329 IN PKSMULTIPLE_ITEM NodeConnections,
330 IN PKSMULTIPLE_ITEM NodeTypes,
331 IN ULONG PinId,
332 IN ULONG bBridgePin,
333 IN ULONG bTargetPin)
334 {
335 LPMIXERLINE_EXT SrcLine, DstLine;
336 MIXER_STATUS Status;
337 KSP_PIN Pin;
338 LPWSTR PinName;
339 GUID NodeType;
340 ULONG BytesReturned, ControlCount, Index;
341 LPGUID Node;
342 PULONG Nodes;
343
344 if (!bTargetPin)
345 {
346 /* allocate src mixer line */
347 SrcLine = (LPMIXERLINE_EXT)MixerContext->Alloc(sizeof(MIXERLINE_EXT));
348
349 if (!SrcLine)
350 return MM_STATUS_NO_MEMORY;
351
352 /* zero struct */
353 RtlZeroMemory(SrcLine, sizeof(MIXERLINE_EXT));
354
355 }
356 else
357 {
358 ASSERT(!IsListEmpty(&MixerInfo->LineList));
359 SrcLine = MMixerGetSourceMixerLineByLineId(MixerInfo, DESTINATION_LINE);
360 }
361
362 /* get destination line */
363 DstLine = MMixerGetSourceMixerLineByLineId(MixerInfo, DESTINATION_LINE);
364 ASSERT(DstLine);
365
366
367 if (!bTargetPin)
368 {
369 /* initialize mixer src line */
370 SrcLine->hDevice = hDevice;
371 SrcLine->PinId = PinId;
372 SrcLine->Line.cbStruct = sizeof(MIXERLINEW);
373
374 /* initialize mixer destination line */
375 SrcLine->Line.cbStruct = sizeof(MIXERLINEW);
376 SrcLine->Line.dwDestination = 0;
377 SrcLine->Line.dwSource = DstLine->Line.cConnections;
378 SrcLine->Line.dwLineID = (DstLine->Line.cConnections * 0x10000);
379 SrcLine->Line.fdwLine = MIXERLINE_LINEF_ACTIVE | MIXERLINE_LINEF_SOURCE;
380 SrcLine->Line.dwUser = 0;
381 SrcLine->Line.cChannels = DstLine->Line.cChannels;
382 SrcLine->Line.cConnections = 0;
383 SrcLine->Line.Target.dwType = 1;
384 SrcLine->Line.Target.dwDeviceID = DstLine->Line.Target.dwDeviceID;
385 SrcLine->Line.Target.wMid = MixerInfo->MixCaps.wMid;
386 SrcLine->Line.Target.wPid = MixerInfo->MixCaps.wPid;
387 SrcLine->Line.Target.vDriverVersion = MixerInfo->MixCaps.vDriverVersion;
388 InitializeListHead(&SrcLine->LineControlsExtraData);
389 wcscpy(SrcLine->Line.Target.szPname, MixerInfo->MixCaps.szPname);
390
391 }
392
393 /* allocate a node arrary */
394 Nodes = (PULONG)MixerContext->Alloc(sizeof(ULONG) * NodeTypes->Count);
395
396 if (!Nodes)
397 {
398 /* not enough memory */
399 if (!bTargetPin)
400 {
401 MixerContext->Free(SrcLine);
402 }
403 return MM_STATUS_NO_MEMORY;
404 }
405
406 Status = MMixerGetControlsFromPin(MixerContext, NodeConnections, NodeTypes, PinId, bTargetPin, Nodes);
407 if (Status != MM_STATUS_SUCCESS)
408 {
409 /* something went wrong */
410 if (!bTargetPin)
411 {
412 MixerContext->Free(SrcLine);
413 }
414 MixerContext->Free(Nodes);
415 return Status;
416 }
417
418 /* now count all nodes controlled by that pin */
419 ControlCount = 0;
420 for(Index = 0; Index < NodeTypes->Count; Index++)
421 {
422 if (Nodes[Index])
423 {
424 // get node type
425 Node = MMixerGetNodeType(NodeTypes, Index);
426
427 if (MMixerGetControlTypeFromTopologyNode(Node))
428 {
429 // found a node which can be resolved to a type
430 ControlCount++;
431 }
432 }
433 }
434
435 /* now allocate the line controls */
436 if (ControlCount)
437 {
438 SrcLine->LineControls = (LPMIXERCONTROLW)MixerContext->Alloc(sizeof(MIXERCONTROLW) * ControlCount);
439
440 if (!SrcLine->LineControls)
441 {
442 /* no memory available */
443 if (!bTargetPin)
444 {
445 MixerContext->Free(SrcLine);
446 }
447 MixerContext->Free(Nodes);
448 return MM_STATUS_NO_MEMORY;
449 }
450
451 SrcLine->NodeIds = (PULONG)MixerContext->Alloc(sizeof(ULONG) * ControlCount);
452 if (!SrcLine->NodeIds)
453 {
454 /* no memory available */
455 MixerContext->Free(SrcLine->LineControls);
456 if (!bTargetPin)
457 {
458 MixerContext->Free(SrcLine);
459 }
460 MixerContext->Free(Nodes);
461 return MM_STATUS_NO_MEMORY;
462 }
463
464 /* zero line controls */
465 RtlZeroMemory(SrcLine->LineControls, sizeof(MIXERCONTROLW) * ControlCount);
466 RtlZeroMemory(SrcLine->NodeIds, sizeof(ULONG) * ControlCount);
467
468 ControlCount = 0;
469 for(Index = 0; Index < NodeTypes->Count; Index++)
470 {
471 if (Nodes[Index])
472 {
473 // get node type
474 Node = MMixerGetNodeType(NodeTypes, Index);
475
476 if (MMixerGetControlTypeFromTopologyNode(Node))
477 {
478 /* store the node index for retrieving / setting details */
479 SrcLine->NodeIds[ControlCount] = Index;
480
481 Status = MMixerAddMixerControl(MixerContext, MixerInfo, hDevice, NodeTypes, Index, SrcLine, &SrcLine->LineControls[ControlCount]);
482 if (Status == MM_STATUS_SUCCESS)
483 {
484 /* increment control count on success */
485 ControlCount++;
486 }
487 }
488 }
489 }
490 /* store control count */
491 SrcLine->Line.cControls = ControlCount;
492 }
493
494 /* release nodes array */
495 MixerContext->Free(Nodes);
496
497 /* get pin category */
498 Pin.PinId = PinId;
499 Pin.Reserved = 0;
500 Pin.Property.Flags = KSPROPERTY_TYPE_GET;
501 Pin.Property.Set = KSPROPSETID_Pin;
502 Pin.Property.Id = KSPROPERTY_PIN_CATEGORY;
503
504 /* try get pin category */
505 Status = MixerContext->Control(hDevice, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSP_PIN), (LPVOID)&NodeType, sizeof(GUID), &BytesReturned);
506 if (Status != MM_STATUS_SUCCESS)
507 {
508 //FIXME
509 //map component type
510 }
511
512 /* retrieve pin name */
513 Pin.PinId = PinId;
514 Pin.Reserved = 0;
515 Pin.Property.Flags = KSPROPERTY_TYPE_GET;
516 Pin.Property.Set = KSPROPSETID_Pin;
517 Pin.Property.Id = KSPROPERTY_PIN_NAME;
518
519 /* try get pin name size */
520 Status = MixerContext->Control(hDevice, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSP_PIN), NULL, 0, &BytesReturned);
521
522 if (Status == MM_STATUS_MORE_ENTRIES)
523 {
524 PinName = (LPWSTR)MixerContext->Alloc(BytesReturned);
525 if (PinName)
526 {
527 /* try get pin name */
528 Status = MixerContext->Control(hDevice, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSP_PIN), (LPVOID)PinName, BytesReturned, &BytesReturned);
529
530 if (Status == MM_STATUS_SUCCESS)
531 {
532 MixerContext->Copy(SrcLine->Line.szShortName, PinName, (min(MIXER_SHORT_NAME_CHARS, wcslen(PinName)+1)) * sizeof(WCHAR));
533 SrcLine->Line.szShortName[MIXER_SHORT_NAME_CHARS-1] = L'\0';
534
535 MixerContext->Copy(SrcLine->Line.szName, PinName, (min(MIXER_LONG_NAME_CHARS, wcslen(PinName)+1)) * sizeof(WCHAR));
536 SrcLine->Line.szName[MIXER_LONG_NAME_CHARS-1] = L'\0';
537 }
538 MixerContext->Free(PinName);
539 }
540 }
541
542 /* insert src line */
543 if (!bTargetPin)
544 {
545 InsertTailList(&MixerInfo->LineList, &SrcLine->Entry);
546 DstLine->Line.cConnections++;
547 }
548
549 return MM_STATUS_SUCCESS;
550 }
551
552 MIXER_STATUS
553 MMixerCreateDestinationLine(
554 IN PMIXER_CONTEXT MixerContext,
555 IN LPMIXER_INFO MixerInfo,
556 IN ULONG bInputMixer,
557 IN LPWSTR LineName)
558 {
559 LPMIXERLINE_EXT DestinationLine;
560
561 // allocate a mixer destination line
562 DestinationLine = (LPMIXERLINE_EXT) MixerContext->Alloc(sizeof(MIXERLINE_EXT));
563 if (!MixerInfo)
564 {
565 // no memory
566 return MM_STATUS_NO_MEMORY;
567 }
568
569 /* initialize mixer destination line */
570 DestinationLine->Line.cbStruct = sizeof(MIXERLINEW);
571 DestinationLine->Line.dwSource = MAXULONG;
572 DestinationLine->Line.dwLineID = DESTINATION_LINE;
573 DestinationLine->Line.fdwLine = MIXERLINE_LINEF_ACTIVE;
574 DestinationLine->Line.dwUser = 0;
575 DestinationLine->Line.dwComponentType = (bInputMixer == 0 ? MIXERLINE_COMPONENTTYPE_DST_SPEAKERS : MIXERLINE_COMPONENTTYPE_DST_WAVEIN);
576 DestinationLine->Line.cChannels = 2; //FIXME
577
578 if (LineName)
579 {
580 wcscpy(DestinationLine->Line.szShortName, LineName);
581 wcscpy(DestinationLine->Line.szName, LineName);
582 }
583 else
584 {
585 /* FIXME no name was found for pin */
586 wcscpy(DestinationLine->Line.szShortName, L"Summe");
587 wcscpy(DestinationLine->Line.szName, L"Summe");
588 }
589
590 DestinationLine->Line.Target.dwType = (bInputMixer == 0 ? MIXERLINE_TARGETTYPE_WAVEOUT : MIXERLINE_TARGETTYPE_WAVEIN);
591 DestinationLine->Line.Target.dwDeviceID = !bInputMixer;
592 DestinationLine->Line.Target.wMid = MixerInfo->MixCaps.wMid;
593 DestinationLine->Line.Target.wPid = MixerInfo->MixCaps.wPid;
594 DestinationLine->Line.Target.vDriverVersion = MixerInfo->MixCaps.vDriverVersion;
595 wcscpy(DestinationLine->Line.Target.szPname, MixerInfo->MixCaps.szPname);
596
597
598 // insert into mixer info
599 InsertHeadList(&MixerInfo->LineList, &DestinationLine->Entry);
600
601 // done
602 return MM_STATUS_SUCCESS;
603 }
604
605 MIXER_STATUS
606 MMixerGetControlsFromPin(
607 IN PMIXER_CONTEXT MixerContext,
608 IN PKSMULTIPLE_ITEM NodeConnections,
609 IN PKSMULTIPLE_ITEM NodeTypes,
610 IN ULONG PinId,
611 IN ULONG bUpDirection,
612 OUT PULONG Nodes)
613 {
614 ULONG NodeConnectionCount, Index;
615 MIXER_STATUS Status;
616 PULONG NodeConnection;
617
618 /* sanity check */
619 ASSERT(PinId != (ULONG)-1);
620
621 /* get all node indexes referenced by that pin */
622 if (bUpDirection)
623 Status = MMixerGetNodeIndexes(MixerContext, NodeConnections, PinId, FALSE, FALSE, &NodeConnectionCount, &NodeConnection);
624 else
625 Status = MMixerGetNodeIndexes(MixerContext, NodeConnections, PinId, FALSE, TRUE, &NodeConnectionCount, &NodeConnection);
626
627 for(Index = 0; Index < NodeConnectionCount; Index++)
628 {
629 /* get all associated controls */
630 Status = MMixerGetControlsFromPinByConnectionIndex(MixerContext, NodeConnections, NodeTypes, bUpDirection, NodeConnection[Index], Nodes);
631 }
632
633 MixerContext->Free(NodeConnection);
634
635 return Status;
636 }
637
638
639
640
641 MIXER_STATUS
642 MMixerAddMixerSourceLines(
643 IN PMIXER_CONTEXT MixerContext,
644 IN OUT LPMIXER_INFO MixerInfo,
645 IN HANDLE hDevice,
646 IN PKSMULTIPLE_ITEM NodeConnections,
647 IN PKSMULTIPLE_ITEM NodeTypes,
648 IN ULONG PinsCount,
649 IN ULONG BridgePinIndex,
650 IN ULONG TargetPinIndex,
651 IN PULONG Pins)
652 {
653 ULONG Index;
654
655 for(Index = PinsCount; Index > 0; Index--)
656 {
657 DPRINT("MMixerAddMixerSourceLines Index %lu Pin %lu\n", Index-1, Pins[Index-1]);
658 if (Pins[Index-1])
659 {
660 MMixerAddMixerSourceLine(MixerContext, MixerInfo, hDevice, NodeConnections, NodeTypes, Index-1, (Index -1 == BridgePinIndex), (Index -1 == TargetPinIndex));
661 }
662 }
663 return MM_STATUS_SUCCESS;
664 }
665
666
667 MIXER_STATUS
668 MMixerHandlePhysicalConnection(
669 IN PMIXER_CONTEXT MixerContext,
670 IN OUT LPMIXER_INFO MixerInfo,
671 IN ULONG bInput,
672 IN PKSPIN_PHYSICALCONNECTION OutConnection)
673 {
674 PULONG PinsRef = NULL, PinConnectionIndex = NULL, PinsSrcRef;
675 ULONG PinsRefCount, Index, PinConnectionIndexCount;
676 MIXER_STATUS Status;
677 HANDLE hDevice = NULL;
678 PKSMULTIPLE_ITEM NodeTypes = NULL;
679 PKSMULTIPLE_ITEM NodeConnections = NULL;
680 PULONG MixerControls;
681 ULONG MixerControlsCount;
682
683
684 // open the connected filter
685 Status = MixerContext->Open(OutConnection->SymbolicLinkName, &hDevice);
686 if (Status != MM_STATUS_SUCCESS)
687 {
688 DPRINT("OpenDevice failed with %x\n", Status);
689 return Status;
690 }
691
692 // get connected filter pin count
693 PinsRefCount = MMixerGetFilterPinCount(MixerContext, hDevice);
694 ASSERT(PinsRefCount);
695
696 PinsRef = (PULONG)MixerContext->Alloc(sizeof(ULONG) * PinsRefCount);
697 if (!PinsRef)
698 {
699 // no memory
700 MixerContext->Close(hDevice);
701 return MM_STATUS_UNSUCCESSFUL;
702 }
703
704 // get topology node types
705 Status = MMixerGetFilterTopologyProperty(MixerContext, hDevice, KSPROPERTY_TOPOLOGY_NODES, &NodeTypes);
706 if (Status != MM_STATUS_SUCCESS)
707 {
708 MixerContext->Close(hDevice);
709 MixerContext->Free(PinsRef);
710 return Status;
711 }
712
713 // get topology connections
714 Status = MMixerGetFilterTopologyProperty(MixerContext, hDevice, KSPROPERTY_TOPOLOGY_CONNECTIONS, &NodeConnections);
715 if (Status != MM_STATUS_SUCCESS)
716 {
717 MixerContext->Close(hDevice);
718 MixerContext->Free(PinsRef);
719 MixerContext->Free(NodeTypes);
720 return Status;
721 }
722 // gets connection index of the bridge pin which connects to a node
723 DPRINT("Pin %lu\n", OutConnection->Pin);
724
725 Status = MMixerGetNodeIndexes(MixerContext, NodeConnections, OutConnection->Pin, FALSE, !bInput, &PinConnectionIndexCount, &PinConnectionIndex);
726 if (Status != MM_STATUS_SUCCESS)
727 {
728 MixerContext->Close(hDevice);
729 MixerContext->Free(PinsRef);
730 MixerContext->Free(NodeTypes);
731 MixerContext->Free(NodeConnections);
732 return Status;
733 }
734
735 /* there should be no split in the bride pin */
736 ASSERT(PinConnectionIndexCount == 1);
737
738 /* find all target pins of this connection */
739 Status = MMixerGetTargetPinsByNodeConnectionIndex(MixerContext, NodeConnections, NodeTypes, FALSE, PinConnectionIndex[0], PinsRef);
740 if (Status != MM_STATUS_SUCCESS)
741 {
742 MixerContext->Close(hDevice);
743 MixerContext->Free(PinsRef);
744 MixerContext->Free(NodeTypes);
745 MixerContext->Free(NodeConnections);
746 MixerContext->Free(PinConnectionIndex);
747 return Status;
748 }
749
750 for(Index = 0; Index < PinsRefCount; Index++)
751 {
752 DPRINT("PinsRefCount %lu Index %lu Value %lu\n", PinsRefCount, Index, PinsRef[Index]);
753 if (PinsRef[Index])
754 {
755 // found a target pin, now get all references
756 Status = MMixerGetNodeIndexes(MixerContext, NodeConnections, Index, FALSE, FALSE, &MixerControlsCount, &MixerControls);
757 if (Status != MM_STATUS_SUCCESS)
758 {
759 DPRINT("MMixerGetNodeIndexes failed with %u\n", Status);
760 break;
761 }
762
763 /* sanity check */
764 ASSERT(MixerControlsCount == 1);
765
766 PinsSrcRef = (PULONG)MixerContext->Alloc(PinsRefCount * sizeof(ULONG));
767 if (!PinsSrcRef)
768 {
769 /* no memory */
770 MixerContext->Close(hDevice);
771 MixerContext->Free(PinsRef);
772 MixerContext->Free(NodeTypes);
773 MixerContext->Free(NodeConnections);
774 MixerContext->Free(PinConnectionIndex);
775 MixerContext->Free(MixerControls);
776 return MM_STATUS_NO_MEMORY;
777 }
778
779 // now get all connected source pins
780 Status = MMixerGetTargetPinsByNodeConnectionIndex(MixerContext, NodeConnections, NodeTypes, TRUE, MixerControls[0], PinsSrcRef);
781 if (Status != MM_STATUS_SUCCESS)
782 {
783 // failed */
784 MixerContext->Close(hDevice);
785 MixerContext->Free(PinsRef);
786 MixerContext->Free(NodeTypes);
787 MixerContext->Free(NodeConnections);
788 MixerContext->Free(PinConnectionIndex);
789 MixerContext->Free(MixerControls);
790 MixerContext->Free(PinsSrcRef);
791 return Status;
792 }
793
794 /* add pins from target line */
795 if (!bInput)
796 {
797 // dont add bridge pin for input mixers
798 PinsSrcRef[Index] = TRUE;
799 PinsSrcRef[OutConnection->Pin] = TRUE;
800 }
801 PinsSrcRef[OutConnection->Pin] = TRUE;
802
803 Status = MMixerAddMixerSourceLines(MixerContext, MixerInfo, hDevice, NodeConnections, NodeTypes, PinsRefCount, OutConnection->Pin, Index, PinsSrcRef);
804
805 MixerContext->Free(MixerControls);
806 MixerContext->Free(PinsSrcRef);
807 }
808 }
809
810 return Status;
811 }
812
813
814 MIXER_STATUS
815 MMixerInitializeFilter(
816 IN PMIXER_CONTEXT MixerContext,
817 IN PMIXER_LIST MixerList,
818 IN HANDLE hMixer,
819 IN LPWSTR DeviceName,
820 IN PKSMULTIPLE_ITEM NodeTypes,
821 IN PKSMULTIPLE_ITEM NodeConnections,
822 IN ULONG PinCount,
823 IN ULONG NodeIndex,
824 IN ULONG bInputMixer)
825 {
826 LPMIXER_INFO MixerInfo;
827 MIXER_STATUS Status;
828 PKSPIN_PHYSICALCONNECTION OutConnection;
829 ULONG Index;
830 ULONG * Pins;
831 ULONG bUsed;
832 ULONG BytesReturned;
833 KSP_PIN Pin;
834 LPWSTR Buffer = NULL;
835
836 // allocate a mixer info struct
837 MixerInfo = (LPMIXER_INFO) MixerContext->Alloc(sizeof(MIXER_INFO));
838 if (!MixerInfo)
839 {
840 // no memory
841 return MM_STATUS_NO_MEMORY;
842 }
843
844 // intialize mixer caps */
845 MixerInfo->MixCaps.wMid = MM_MICROSOFT; //FIXME
846 MixerInfo->MixCaps.wPid = MM_PID_UNMAPPED; //FIXME
847 MixerInfo->MixCaps.vDriverVersion = 1; //FIXME
848 MixerInfo->MixCaps.fdwSupport = 0;
849 MixerInfo->MixCaps.cDestinations = 1;
850 MixerInfo->hMixer = hMixer;
851
852 // initialize line list
853 InitializeListHead(&MixerInfo->LineList);
854
855 /* FIXME find mixer name */
856
857 // now allocate an array which will receive the indices of the pin
858 // which has a ADC / DAC nodetype in its path
859 Pins = (PULONG)MixerContext->Alloc(PinCount * sizeof(ULONG));
860
861 if (!Pins)
862 {
863 // no memory
864 MMixerFreeMixerInfo(MixerContext, MixerInfo);
865 return MM_STATUS_NO_MEMORY;
866 }
867
868 // now get the target pins of the ADC / DAC node
869 Status = MMixerGetTargetPins(MixerContext, NodeTypes, NodeConnections, NodeIndex, !bInputMixer, Pins, PinCount);
870
871 for(Index = 0; Index < PinCount; Index++)
872 {
873 if (Pins[Index])
874 {
875 /* retrieve pin name */
876 Pin.PinId = Index;
877 Pin.Reserved = 0;
878 Pin.Property.Flags = KSPROPERTY_TYPE_GET;
879 Pin.Property.Set = KSPROPSETID_Pin;
880 Pin.Property.Id = KSPROPERTY_PIN_NAME;
881
882 /* try get pin name size */
883 Status = MixerContext->Control(hMixer, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSP_PIN), NULL, 0, &BytesReturned);
884
885 if (Status == MM_STATUS_MORE_ENTRIES)
886 {
887 Buffer = (LPWSTR)MixerContext->Alloc(BytesReturned);
888 if (Buffer)
889 {
890 /* try get pin name */
891 Status = MixerContext->Control(hMixer, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSP_PIN), (PVOID)Buffer, BytesReturned, &BytesReturned);
892 if (Status != MM_STATUS_SUCCESS)
893 {
894 MixerContext->Free((PVOID)Buffer);
895 Buffer = NULL;
896 }
897 else
898 {
899 // found name, done
900 break;
901 }
902 }
903 }
904 }
905 }
906
907 Status = MMixerCreateDestinationLine(MixerContext, MixerInfo, bInputMixer, Buffer);
908
909 if (Buffer)
910 {
911 // free name
912 MixerContext->Free(Buffer);
913 }
914
915 if (Status != MM_STATUS_SUCCESS)
916 {
917 // failed to create destination line
918 MixerContext->Free(MixerInfo);
919 MixerContext->Free(Pins);
920
921 return Status;
922 }
923
924 RtlZeroMemory(Pins, sizeof(ULONG) * PinCount);
925 // now get the target pins of the ADC / DAC node
926 Status = MMixerGetTargetPins(MixerContext, NodeTypes, NodeConnections, NodeIndex, bInputMixer, Pins, PinCount);
927
928 if (Status != MM_STATUS_SUCCESS)
929 {
930 // failed to locate target pins
931 MixerContext->Free(Pins);
932 MMixerFreeMixerInfo(MixerContext, MixerInfo);
933 DPRINT("MMixerGetTargetPins failed with %u\n", Status);
934 return Status;
935 }
936
937 // filter hasnt been used
938 bUsed = FALSE;
939
940 // now check all pins and generate new lines for destination lines
941 for(Index = 0; Index < PinCount; Index++)
942 {
943 DPRINT("Index %lu TargetPin %lu\n", Index, Pins[Index]);
944 // is the current index a target pin
945 if (Pins[Index])
946 {
947 // check if the pin has a physical connection
948 Status = MMixerGetPhysicalConnection(MixerContext, hMixer, Index, &OutConnection);
949 if (Status == MM_STATUS_SUCCESS)
950 {
951 // the pin has a physical connection
952 Status = MMixerHandlePhysicalConnection(MixerContext, MixerInfo, bInputMixer, OutConnection);
953 DPRINT("MMixerHandlePhysicalConnection status %u\n", Status);
954 MixerContext->Free(OutConnection);
955 bUsed = TRUE;
956 }
957 else
958 {
959 // filter exposes the topology on the same filter
960 MMixerAddMixerSourceLine(MixerContext, MixerInfo, hMixer, NodeConnections, NodeTypes, Index, FALSE, FALSE);
961 bUsed = TRUE;
962 }
963 }
964 }
965 MixerContext->Free(Pins);
966
967 if (bUsed)
968 {
969 // store mixer info in list
970 if (!bInputMixer && MixerList->MixerListCount == 1)
971 {
972 //FIXME preferred device should be inserted at front
973 //windows always inserts output mixer in front
974 InsertHeadList(&MixerList->MixerList, &MixerInfo->Entry);
975 }
976 else
977 {
978 InsertTailList(&MixerList->MixerList, &MixerInfo->Entry);
979 }
980 MixerList->MixerListCount++;
981 DPRINT("New MixerCount %lu\n", MixerList->MixerListCount);
982 }
983 else
984 {
985 // failed to create a mixer topology
986 MMixerFreeMixerInfo(MixerContext, MixerInfo);
987 }
988
989 // done
990 return Status;
991 }
992
993 MIXER_STATUS
994 MMixerSetupFilter(
995 IN PMIXER_CONTEXT MixerContext,
996 IN PMIXER_LIST MixerList,
997 IN HANDLE hMixer,
998 IN PULONG DeviceCount,
999 IN LPWSTR DeviceName)
1000 {
1001 PKSMULTIPLE_ITEM NodeTypes, NodeConnections;
1002 MIXER_STATUS Status;
1003 ULONG PinCount;
1004 ULONG NodeIndex;
1005
1006 // get number of pins
1007 PinCount = MMixerGetFilterPinCount(MixerContext, hMixer);
1008 ASSERT(PinCount);
1009 DPRINT("NumOfPins: %lu\n", PinCount);
1010
1011 // get filter node types
1012 Status = MMixerGetFilterTopologyProperty(MixerContext, hMixer, KSPROPERTY_TOPOLOGY_NODES, &NodeTypes);
1013 if (Status != MM_STATUS_SUCCESS)
1014 {
1015 // failed
1016 return Status;
1017 }
1018
1019 // get filter node connections
1020 Status = MMixerGetFilterTopologyProperty(MixerContext, hMixer, KSPROPERTY_TOPOLOGY_CONNECTIONS, &NodeConnections);
1021 if (Status != MM_STATUS_SUCCESS)
1022 {
1023 // failed
1024 MixerContext->Free(NodeTypes);
1025 return Status;
1026 }
1027
1028 // check if the filter has an wave out node
1029 NodeIndex = MMixerGetIndexOfGuid(NodeTypes, &KSNODETYPE_DAC);
1030 if (NodeIndex != MAXULONG)
1031 {
1032 // it has
1033 Status = MMixerInitializeFilter(MixerContext, MixerList, hMixer, DeviceName, NodeTypes, NodeConnections, PinCount, NodeIndex, FALSE);
1034 DPRINT("MMixerInitializeFilter Status %u\n", Status);
1035 // check for success
1036 if (Status == MM_STATUS_SUCCESS)
1037 {
1038 // increment mixer count
1039 (*DeviceCount)++;
1040 }
1041
1042 }
1043
1044 // check if the filter has an wave in node
1045 NodeIndex = MMixerGetIndexOfGuid(NodeTypes, &KSNODETYPE_ADC);
1046 if (NodeIndex != MAXULONG)
1047 {
1048 // it has
1049 Status = MMixerInitializeFilter(MixerContext, MixerList, hMixer, DeviceName, NodeTypes, NodeConnections, PinCount, NodeIndex, TRUE);
1050 DPRINT("MMixerInitializeFilter Status %u\n", Status);
1051 // check for success
1052 if (Status == MM_STATUS_SUCCESS)
1053 {
1054 // increment mixer count
1055 (*DeviceCount)++;
1056 }
1057
1058 }
1059
1060 //free resources
1061 MixerContext->Free((PVOID)NodeTypes);
1062 MixerContext->Free((PVOID)NodeConnections);
1063
1064 // done
1065 return Status;
1066 }