[MMIXER]
[reactos.git] / reactos / lib / drivers / sound / mmixer / topology.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Kernel Streaming
4 * FILE: lib/drivers/sound/mmixer/topology.c
5 * PURPOSE: Topology Handling Functions
6 * PROGRAMMER: Johannes Anderwald
7 */
8
9 #include "precomp.h"
10
11 #define YDEBUG
12 #include <debug.h>
13
14 VOID
15 MMixerPrintTopology(
16 PTOPOLOGY Topology)
17 {
18 ULONG Index, SubIndex;
19
20 DPRINT("Num Pins %lu NumNodes %lu\n", Topology->TopologyPinsCount, Topology->TopologyNodesCount);
21
22 for(Index = 0; Index < Topology->TopologyPinsCount; Index++)
23 {
24 DPRINT("PinId %lu NodesConnectedFromCount %lu NodesConnectedToCount %lu Visited %lu\n", Topology->TopologyPins[Index].PinId,
25 Topology->TopologyPins[Index].NodesConnectedFromCount, Topology->TopologyPins[Index].NodesConnectedToCount, Topology->TopologyPins[Index].Visited);
26
27 for(SubIndex = 0; SubIndex < Topology->TopologyPins[Index].NodesConnectedFromCount; SubIndex++)
28 DPRINT("NodesConnectedFrom Index %lu NodeId %lu\n", SubIndex, Topology->TopologyPins[Index].NodesConnectedFrom[SubIndex]->NodeIndex);
29
30 for(SubIndex = 0; SubIndex < Topology->TopologyPins[Index].NodesConnectedToCount; SubIndex++)
31 DPRINT("NodesConnectedTo Index %lu NodeId %lu\n", SubIndex, Topology->TopologyPins[Index].NodesConnectedTo[SubIndex]->NodeIndex);
32 }
33
34 for(Index = 0; Index < Topology->TopologyNodesCount; Index++)
35 {
36 DPRINT("NodeId %lu NodesConnectedFromCount %lu NodesConnectedToCount %lu Visited %lu PinConnectedFromCount %lu PinConnectedToCount %lu\n", Topology->TopologyNodes[Index].NodeIndex,
37 Topology->TopologyNodes[Index].NodeConnectedFromCount, Topology->TopologyNodes[Index].NodeConnectedToCount, Topology->TopologyNodes[Index].Visited,
38 Topology->TopologyNodes[Index].PinConnectedFromCount, Topology->TopologyNodes[Index].PinConnectedToCount);
39 }
40
41
42 }
43
44
45 MIXER_STATUS
46 MMixerAllocateTopology(
47 IN PMIXER_CONTEXT MixerContext,
48 IN ULONG NodesCount,
49 IN ULONG PinCount,
50 OUT PTOPOLOGY * OutTopology)
51 {
52 PTOPOLOGY Topology;
53
54 /* allocate topology */
55 Topology = (PTOPOLOGY)MixerContext->Alloc(sizeof(TOPOLOGY));
56
57 if (!Topology)
58 {
59 /* out of memory */
60 return MM_STATUS_NO_MEMORY;
61 }
62
63 /* allocate topology pins */
64 Topology->TopologyPins = (PPIN) MixerContext->Alloc(sizeof(PIN) * PinCount);
65
66 if (!Topology->TopologyPins)
67 {
68 /* release memory */
69 MixerContext->Free(Topology);
70
71 /* out of memory */
72 return MM_STATUS_NO_MEMORY;
73 }
74
75 /* allocate topology nodes */
76 if (NodesCount)
77 {
78 Topology->TopologyNodes = (PTOPOLOGY_NODE) MixerContext->Alloc(sizeof(TOPOLOGY_NODE) * NodesCount);
79
80 if (!Topology->TopologyNodes)
81 {
82 /* release memory */
83 MixerContext->Free(Topology->TopologyPins);
84 MixerContext->Free(Topology);
85
86 /* out of memory */
87 return MM_STATUS_NO_MEMORY;
88 }
89 }
90
91 /* initialize topology */
92 Topology->TopologyPinsCount = PinCount;
93 Topology->TopologyNodesCount = NodesCount;
94
95 /* store result */
96 *OutTopology = Topology;
97
98 /* done */
99 return MM_STATUS_SUCCESS;
100 }
101
102 VOID
103 MMixerResetTopologyVisitStatus(
104 IN OUT PTOPOLOGY Topology)
105 {
106 ULONG Index;
107
108 for(Index = 0; Index < Topology->TopologyNodesCount; Index++)
109 {
110 /* reset visited status */
111 Topology->TopologyNodes[Index].Visited = FALSE;
112 }
113
114 for(Index = 0; Index < Topology->TopologyPinsCount; Index++)
115 {
116 /* reset visited status */
117 Topology->TopologyPins[Index].Visited = FALSE;
118 }
119 }
120
121 VOID
122 MMixerInitializeTopologyNodes(
123 IN PMIXER_CONTEXT MixerContext,
124 IN PKSMULTIPLE_ITEM NodeTypes,
125 IN OUT PTOPOLOGY Topology)
126 {
127 ULONG Index;
128 LPGUID Guids;
129
130 /* sanity check */
131 ASSERT(Topology->TopologyNodesCount == NodeTypes->Count);
132
133 /* get topology node types */
134 Guids = (LPGUID)(NodeTypes + 1);
135
136 for(Index = 0; Index < Topology->TopologyNodesCount; Index++)
137 {
138 /* store node connection index */
139 Topology->TopologyNodes[Index].NodeIndex = Index;
140
141 /* store topology node type */
142 MixerContext->Copy(&Topology->TopologyNodes[Index].NodeType, &Guids[Index], sizeof(GUID));
143 }
144 }
145
146 MIXER_STATUS
147 MMixerAddPinConnection(
148 IN PMIXER_CONTEXT MixerContext,
149 IN PPIN Pin,
150 IN PTOPOLOGY_NODE Node,
151 IN ULONG bPinToNode)
152 {
153 ULONG Count;
154 PULONG NewPinsIndex, OldPinsIndex;
155 PTOPOLOGY_NODE * NewNodes, *OldNodes;
156
157 if (bPinToNode)
158 {
159 /* get existing count */
160 Count = Pin->NodesConnectedToCount;
161 OldNodes = Pin->NodesConnectedTo;
162 }
163 else
164 {
165 /* get existing count */
166 Count = Pin->NodesConnectedFromCount;
167 OldNodes = Pin->NodesConnectedFrom;
168 }
169
170 /* allocate new nodes array */
171 NewNodes = MixerContext->Alloc(sizeof(PTOPOLOGY_NODE) * (Count + 1));
172
173 if (!NewNodes)
174 {
175 /* out of memory */
176 return MM_STATUS_NO_MEMORY;
177 }
178
179 if (Count)
180 {
181 /* copy existing nodes */
182 MixerContext->Copy(NewNodes, OldNodes, sizeof(PTOPOLOGY) * Count);
183
184 /* release old nodes array */
185 MixerContext->Free(OldNodes);
186 }
187
188 /* add new topology node */
189 NewNodes[Count] = Node;
190
191 if (bPinToNode)
192 {
193 /* replace old nodes array */
194 Pin->NodesConnectedTo = NewNodes;
195
196 /* increment nodes count */
197 Pin->NodesConnectedToCount++;
198
199 /* now enlarge PinConnectedFromCount*/
200 Count = Node->PinConnectedFromCount;
201
202 /* connected pin count for node */
203 OldPinsIndex = Node->PinConnectedFrom;
204 }
205 else
206 {
207 /* replace old nodes array */
208 Pin->NodesConnectedFrom = NewNodes;
209
210 /* increment nodes count */
211 Pin->NodesConnectedFromCount++;
212
213 /* now enlarge PinConnectedFromCount*/
214 Count = Node->PinConnectedToCount;
215
216 /* connected pin count for node */
217 OldPinsIndex = Node->PinConnectedTo;
218 }
219
220 /* allocate pin connection index */
221 NewPinsIndex = MixerContext->Alloc(sizeof(ULONG) * (Count + 1));
222
223 if (!NewPinsIndex)
224 {
225 /* out of memory */
226 return MM_STATUS_NO_MEMORY;
227 }
228
229 if (Count)
230 {
231 /* copy existing nodes */
232 MixerContext->Copy(NewPinsIndex, OldPinsIndex, sizeof(ULONG) * Count);
233
234 /* release old nodes array */
235 MixerContext->Free(OldPinsIndex);
236 }
237
238 /* add new topology node */
239 NewPinsIndex[Count] = Pin->PinId;
240
241 if (bPinToNode)
242 {
243 /* replace old nodes array */
244 Node->PinConnectedFrom = NewPinsIndex;
245
246 /* increment pin count */
247 Node->PinConnectedFromCount++;
248 }
249 else
250 {
251 /* replace old nodes array */
252 Node->PinConnectedTo = NewPinsIndex;
253
254 /* increment pin count */
255 Node->PinConnectedToCount++;
256 }
257
258 /* done */
259 return MM_STATUS_SUCCESS;
260 }
261
262 MIXER_STATUS
263 MMixerHandleNodeToNodeConnection(
264 IN PMIXER_CONTEXT MixerContext,
265 IN PKSTOPOLOGY_CONNECTION Connection,
266 IN OUT PTOPOLOGY Topology)
267 {
268 PTOPOLOGY_NODE InNode, OutNode;
269 PTOPOLOGY_NODE * NewNodes;
270 PULONG NewLogicalPinNodeConnectedFrom;
271 ULONG Count;
272 ULONG LogicalPinId;
273
274 /* sanity checks */
275 ASSERT(Topology->TopologyNodesCount > Connection->ToNode);
276 ASSERT(Topology->TopologyNodesCount > Connection->FromNode);
277
278 /* get node */
279 InNode = &Topology->TopologyNodes[Connection->FromNode];
280 OutNode = &Topology->TopologyNodes[Connection->ToNode];
281
282 /* get logical pin node id */
283 LogicalPinId = Connection->ToNodePin;
284
285 /* get existing count */
286 Count = OutNode->NodeConnectedFromCount;
287
288 /* allocate new nodes array */
289 NewNodes = MixerContext->Alloc(sizeof(PTOPOLOGY_NODE) * (Count + 1));
290
291 if (!NewNodes)
292 {
293 /* out of memory */
294 return MM_STATUS_NO_MEMORY;
295 }
296
297 /* allocate logical pin nodes array */
298 NewLogicalPinNodeConnectedFrom = MixerContext->Alloc((Count + 1) * sizeof(ULONG));
299 if (!NewLogicalPinNodeConnectedFrom)
300 {
301 /* out of memory */
302 MixerContext->Free(NewNodes);
303 return MM_STATUS_NO_MEMORY;
304 }
305
306 if (Count)
307 {
308 /* copy existing nodes */
309 MixerContext->Copy(NewNodes, OutNode->NodeConnectedFrom, sizeof(PTOPOLOGY) * Count);
310
311 /* copy existing logical pin node array */
312 MixerContext->Copy(NewLogicalPinNodeConnectedFrom, OutNode->LogicalPinNodeConnectedFrom, sizeof(ULONG) * Count);
313
314 /* release old nodes array */
315 MixerContext->Free(OutNode->NodeConnectedFrom);
316
317 /* release old logical pin node array */
318 MixerContext->Free(OutNode->LogicalPinNodeConnectedFrom);
319 }
320
321 /* add new topology node */
322 NewNodes[OutNode->NodeConnectedFromCount] = InNode;
323
324 /* add logical node id */
325 NewLogicalPinNodeConnectedFrom[OutNode->NodeConnectedFromCount] = LogicalPinId;
326
327 /* replace old nodes array */
328 OutNode->NodeConnectedFrom = NewNodes;
329
330 /* replace old logical pin node array */
331 OutNode->LogicalPinNodeConnectedFrom = NewLogicalPinNodeConnectedFrom;
332
333 /* increment nodes count */
334 OutNode->NodeConnectedFromCount++;
335
336 /* get existing count */
337 Count = InNode->NodeConnectedToCount;
338
339 /* allocate new nodes array */
340 NewNodes = MixerContext->Alloc(sizeof(PTOPOLOGY_NODE) * (Count + 1));
341
342 if (!NewNodes)
343 {
344 /* out of memory */
345 return MM_STATUS_NO_MEMORY;
346 }
347
348 if (Count)
349 {
350 /* copy existing nodes */
351 MixerContext->Copy(NewNodes, InNode->NodeConnectedTo, sizeof(PTOPOLOGY) * Count);
352
353 /* release old nodes array */
354 MixerContext->Free(InNode->NodeConnectedTo);
355 }
356
357 /* add new topology node */
358 NewNodes[InNode->NodeConnectedToCount] = OutNode;
359
360 /* replace old nodes array */
361 InNode->NodeConnectedTo = NewNodes;
362
363 /* increment nodes count */
364 InNode->NodeConnectedToCount++;
365
366 /* done */
367 return MM_STATUS_SUCCESS;
368 }
369
370 MIXER_STATUS
371 MMixerAddPinToPinConnection(
372 IN PMIXER_CONTEXT MixerContext,
373 IN OUT PPIN InPin,
374 IN OUT PPIN OutPin)
375 {
376 ULONG Count;
377 PULONG NewPinsIndex;
378
379 /* now enlarge PinConnectedTo */
380 Count = InPin->PinConnectedToCount;
381
382 /* allocate pin connection index */
383 NewPinsIndex = MixerContext->Alloc(sizeof(ULONG) * (Count + 1));
384
385 if (!NewPinsIndex)
386 {
387 /* out of memory */
388 return MM_STATUS_NO_MEMORY;
389 }
390
391 if (Count)
392 {
393 /* copy existing nodes */
394 MixerContext->Copy(NewPinsIndex, InPin->PinConnectedTo, sizeof(ULONG) * Count);
395
396 /* release old nodes array */
397 MixerContext->Free(InPin->PinConnectedTo);
398 }
399
400 /* add new topology node */
401 NewPinsIndex[Count] = OutPin->PinId;
402
403 /* replace old nodes array */
404 InPin->PinConnectedTo = NewPinsIndex;
405
406 /* increment pin count */
407 InPin->PinConnectedToCount++;
408
409 /* now enlarge PinConnectedFrom */
410 Count = OutPin->PinConnectedFromCount;
411
412 /* allocate pin connection index */
413 NewPinsIndex = MixerContext->Alloc(sizeof(ULONG) * (Count + 1));
414
415 if (!NewPinsIndex)
416 {
417 /* out of memory */
418 return MM_STATUS_NO_MEMORY;
419 }
420
421 if (Count)
422 {
423 /* copy existing nodes */
424 MixerContext->Copy(NewPinsIndex, OutPin->PinConnectedFrom, sizeof(ULONG) * Count);
425
426 /* release old nodes array */
427 MixerContext->Free(OutPin->PinConnectedFrom);
428 }
429
430 /* add new topology node */
431 NewPinsIndex[Count] = InPin->PinId;
432
433 /* replace old nodes array */
434 OutPin->PinConnectedFrom = NewPinsIndex;
435
436 /* increment pin count */
437 OutPin->PinConnectedFromCount++;
438
439 /* done */
440 return MM_STATUS_SUCCESS;
441 }
442
443 MIXER_STATUS
444 MMixerHandleNodePinConnection(
445 IN PMIXER_CONTEXT MixerContext,
446 IN PKSTOPOLOGY_CONNECTION Connection,
447 IN OUT PTOPOLOGY Topology)
448 {
449 PPIN Pin;
450 PTOPOLOGY_NODE Node;
451
452 /* check type */
453 if (Connection->FromNode == KSFILTER_NODE &&
454 Connection->ToNode == KSFILTER_NODE)
455 {
456 /* Pin -> Pin direction */
457
458 /* sanity checks */
459 ASSERT(Topology->TopologyPinsCount > Connection->FromNodePin);
460 ASSERT(Topology->TopologyPinsCount > Connection->ToNodePin);
461
462 /* add connection */
463 return MMixerAddPinToPinConnection(MixerContext,
464 &Topology->TopologyPins[Connection->FromNodePin],
465 &Topology->TopologyPins[Connection->ToNodePin]);
466
467 }
468 else if (Connection->FromNode == KSFILTER_NODE)
469 {
470 /* Pin -> Node direction */
471
472 /* sanity checks */
473 ASSERT(Topology->TopologyPinsCount > Connection->FromNodePin);
474 ASSERT(Topology->TopologyNodesCount > Connection->ToNode);
475 ASSERT(Connection->ToNode != KSFILTER_NODE);
476
477 /* get pin */
478 Pin = &Topology->TopologyPins[Connection->FromNodePin];
479
480 /* get node */
481 Node = &Topology->TopologyNodes[Connection->ToNode];
482
483 /* initialize pin */
484 Pin->PinId = Connection->FromNodePin;
485
486 /* mark as visited */
487 Pin->Visited = TRUE;
488 Node->Visited = TRUE;
489
490 /* add connection */
491 return MMixerAddPinConnection(MixerContext, Pin, Node, TRUE);
492 }
493 else if (Connection->ToNode == KSFILTER_NODE)
494 {
495 /* Node -> Pin direction */
496
497 /* sanity checks */
498 ASSERT(Topology->TopologyPinsCount > Connection->ToNodePin);
499 ASSERT(Topology->TopologyNodesCount > Connection->FromNode);
500 ASSERT(Connection->FromNode != KSFILTER_NODE);
501
502 /* get pin */
503 Pin = &Topology->TopologyPins[Connection->ToNodePin];
504
505 /* get node */
506 Node = &Topology->TopologyNodes[Connection->FromNode];
507
508 /* initialize pin */
509 Pin->PinId = Connection->ToNodePin;
510
511 /* mark as visited */
512 Pin->Visited = TRUE;
513 Node->Visited = TRUE;
514
515 /* add connection */
516 return MMixerAddPinConnection(MixerContext, Pin, Node, FALSE);
517 }
518 /* invalid call */
519 ASSERT(0);
520 return MM_STATUS_INVALID_PARAMETER;
521 }
522
523 MIXER_STATUS
524 MMixerExploreTopology(
525 IN PMIXER_CONTEXT MixerContext,
526 IN PKSMULTIPLE_ITEM NodeConnections,
527 IN PKSMULTIPLE_ITEM NodeTypes,
528 IN OUT PTOPOLOGY Topology)
529 {
530 ULONG Index;
531 PKSTOPOLOGY_CONNECTION Connection;
532 MIXER_STATUS Status;
533
534 /* sanity check */
535 ASSERT(Topology->TopologyNodesCount == NodeTypes->Count);
536
537 /* get node connections */
538 Connection = (PKSTOPOLOGY_CONNECTION)(NodeConnections + 1);
539
540 for(Index = 0; Index < NodeConnections->Count; Index++)
541 {
542 if (Connection[Index].FromNode == KSFILTER_NODE ||
543 Connection[Index].ToNode == KSFILTER_NODE)
544 {
545 /* handle connection from Pin -> Node / Node->Pin */
546 Status = MMixerHandleNodePinConnection(MixerContext,
547 &Connection[Index],
548 Topology);
549
550 }
551 else
552 {
553 /* handle connection from Node -> Node */
554 Status = MMixerHandleNodeToNodeConnection(MixerContext,
555 &Connection[Index],
556 Topology);
557 }
558
559 if (Status != MM_STATUS_SUCCESS)
560 {
561 /* failed to handle connection */
562 return Status;
563 }
564 }
565
566 /* done */
567 return MM_STATUS_SUCCESS;
568 }
569
570 VOID
571 MMixerAddPinIndexToArray(
572 IN PMIXER_CONTEXT MixerContext,
573 IN ULONG PinId,
574 IN ULONG MaxPins,
575 OUT PULONG OutPinCount,
576 OUT PULONG OutPins)
577 {
578 ULONG Index;
579
580 for(Index = 0; Index < MaxPins; Index++)
581 {
582 if (OutPins[Index] != MAXULONG)
583 {
584 if (OutPins[Index] > PinId)
585 {
586 /* shift entries up */
587 MixerContext->Copy(&OutPins[Index + 1], &OutPins[Index], (MaxPins - (Index + 1)) * sizeof(ULONG));
588
589 /* store pin id */
590 OutPins[Index] = PinId;
591
592 /* increment pin count */
593 (*OutPinCount)++;
594
595 /* done */
596 return;
597 }
598 }
599 else
600 {
601 /* store pin id */
602 OutPins[Index] = PinId;
603
604 /* increment pin count */
605 (*OutPinCount)++;
606
607 /* done */
608 return;
609 }
610 }
611 }
612
613 VOID
614 MMixerGetUpOrDownStreamPins(
615 IN PMIXER_CONTEXT MixerContext,
616 IN PTOPOLOGY Topology,
617 IN PTOPOLOGY_NODE TopologyNode,
618 IN ULONG bUpStream,
619 OUT PULONG OutPinCount,
620 OUT PULONG OutPins)
621 {
622 ULONG Index, TopologyNodesCount, PinsCount;
623 PTOPOLOGY_NODE *TopologyNodes;
624 PULONG Pins;
625 PPIN Pin;
626
627 /* sanity check */
628 ASSERT(TopologyNode->Visited == FALSE);
629
630 if (bUpStream)
631 {
632 /* use pins to which a node is attached to */
633 PinsCount = TopologyNode->PinConnectedFromCount;
634 Pins = TopologyNode->PinConnectedFrom;
635
636 TopologyNodesCount = TopologyNode->NodeConnectedFromCount;
637 TopologyNodes = TopologyNode->NodeConnectedFrom;
638 }
639 else
640 {
641 /* use pins which are attached to a node */
642 PinsCount = TopologyNode->PinConnectedToCount;
643 Pins = TopologyNode->PinConnectedTo;
644
645 TopologyNodesCount = TopologyNode->NodeConnectedToCount;
646 TopologyNodes = TopologyNode->NodeConnectedTo;
647 }
648
649 /* add all diretly connected pins */
650 for(Index = 0; Index < PinsCount; Index++)
651 {
652 /* sanity check */
653 ASSERT(Pins[Index] < Topology->TopologyPinsCount);
654
655 /* get pin */
656 Pin = &Topology->TopologyPins[Pins[Index]];
657
658 /* pin should not have been visited */
659 ASSERT(Pin->Visited == FALSE);
660 ASSERT(Pins[Index] == Pin->PinId);
661
662 /* FIXME support Pin -> Pin connections in iteration */
663 if (bUpStream)
664 {
665 /* indicates a very broken topology Pin -> Pin -> Node <-... */
666 ASSERT(Pin->PinConnectedFromCount == 0);
667 }
668 else
669 {
670 /* indicates a very broken topology -> Node -> Pin -> Pin */
671 ASSERT(Pin->PinConnectedToCount == 0);
672 }
673
674 /* add them to pin array */
675 MMixerAddPinIndexToArray(MixerContext, Pin->PinId, Topology->TopologyPinsCount, OutPinCount, OutPins);
676
677 /* mark pin as visited */
678 Pin->Visited = TRUE;
679 }
680
681 /* mark node as visited */
682 TopologyNode->Visited = TRUE;
683
684 /* now visit all connected nodes */
685 for(Index = 0; Index < TopologyNodesCount; Index++)
686 {
687 /* recursively visit them */
688 MMixerGetUpOrDownStreamPins(MixerContext, Topology, TopologyNodes[Index], bUpStream, OutPinCount, OutPins);
689 }
690
691 }
692
693 ULONG
694 MMixerGetNodeIndexFromGuid(
695 IN PTOPOLOGY Topology,
696 IN const GUID * NodeType)
697 {
698 ULONG Index;
699
700 for(Index = 0; Index < Topology->TopologyNodesCount; Index++)
701 {
702 if (IsEqualGUIDAligned(NodeType, &Topology->TopologyNodes[Index].NodeType))
703 {
704 return Index;
705 }
706 }
707
708 return MAXULONG;
709 }
710
711
712 VOID
713 MMixerGetAllUpOrDownstreamPinsFromNodeIndex(
714 IN PMIXER_CONTEXT MixerContext,
715 IN PTOPOLOGY Topology,
716 IN ULONG NodeIndex,
717 IN ULONG bUpStream,
718 OUT PULONG OutPinsCount,
719 OUT PULONG OutPins)
720 {
721 PTOPOLOGY_NODE TopologyNode;
722
723 /* reset visited status */
724 MMixerResetTopologyVisitStatus(Topology);
725
726 /* sanity check */
727 ASSERT(Topology->TopologyNodesCount > NodeIndex);
728
729 /* get topology node */
730 TopologyNode = &Topology->TopologyNodes[NodeIndex];
731
732 /* now visit all upstream pins & nodes */
733 MMixerGetUpOrDownStreamPins(MixerContext, Topology, TopologyNode, bUpStream, OutPinsCount, OutPins);
734 }
735
736 VOID
737 MMixerGetUpOrDownstreamNodes(
738 IN PMIXER_CONTEXT MixerContext,
739 IN PTOPOLOGY Topology,
740 IN PTOPOLOGY_NODE TopologyNode,
741 IN ULONG bUpStream,
742 OUT PULONG OutNodeCount,
743 OUT PULONG OutNodes)
744 {
745 ULONG Index, TopologyNodesCount;
746 PTOPOLOGY_NODE Node, *TopologyNodes;
747
748 if (bUpStream)
749 {
750 /* use nodes to which a node is attached to */
751 TopologyNodesCount = TopologyNode->NodeConnectedFromCount;
752 TopologyNodes = TopologyNode->NodeConnectedFrom;
753 }
754 else
755 {
756 /* use nodes which are attached to a node */
757 TopologyNodesCount = TopologyNode->NodeConnectedToCount;
758 TopologyNodes = TopologyNode->NodeConnectedTo;
759 }
760
761 /* sanity check */
762 ASSERT(TopologyNode->Visited == FALSE);
763
764 /* add all connected nodes */
765 for(Index = 0; Index < TopologyNodesCount; Index++)
766 {
767 /* get node */
768 Node = TopologyNodes[Index];
769
770 /* node should not have been visited */
771 ASSERT(Node->Visited == FALSE);
772
773 /* mark node as visited */
774 TopologyNode->Visited = TRUE;
775
776 /* add them to node array */
777 MMixerAddPinIndexToArray(MixerContext, Node->NodeIndex, Topology->TopologyNodesCount, OutNodeCount, OutNodes);
778
779 /* recursively visit them */
780 MMixerGetUpOrDownstreamNodes(MixerContext, Topology, TopologyNodes[Index], bUpStream, OutNodeCount, OutNodes);
781 }
782 }
783
784 MIXER_STATUS
785 MMixerGetAllUpOrDownstreamNodesFromNodeIndex(
786 IN PMIXER_CONTEXT MixerContext,
787 IN PTOPOLOGY Topology,
788 IN ULONG NodeIndex,
789 IN ULONG bUpStream,
790 OUT PULONG OutNodesCount,
791 OUT PULONG OutNodes)
792 {
793 PTOPOLOGY_NODE TopologyNode;
794
795 /* reset visited status */
796 MMixerResetTopologyVisitStatus(Topology);
797
798 /* sanity check */
799 ASSERT(Topology->TopologyNodesCount > NodeIndex);
800
801 /* get topology node */
802 TopologyNode = &Topology->TopologyNodes[NodeIndex];
803
804 /* now visit all upstream pins & nodes */
805 MMixerGetUpOrDownstreamNodes(MixerContext, Topology, TopologyNode, bUpStream, OutNodesCount, OutNodes);
806
807 /* done */
808 return MM_STATUS_SUCCESS;
809
810 }
811
812 MIXER_STATUS
813 MMixerGetAllUpOrDownstreamPinsFromPinIndex(
814 IN PMIXER_CONTEXT MixerContext,
815 IN PTOPOLOGY Topology,
816 IN ULONG PinIndex,
817 IN ULONG bUpStream,
818 OUT PULONG OutPinsCount,
819 OUT PULONG OutPins)
820 {
821 ULONG Index, TopologyNodesCount, TopologyPinsCount;
822 PPIN Pin;
823 PTOPOLOGY_NODE *TopologyNodes;
824 PULONG TopologyPins;
825
826 /* get pin */
827 Pin = &Topology->TopologyPins[PinIndex];
828
829 if (bUpStream)
830 {
831 /* use nodes to which this pin is attached to */
832 TopologyNodes = Pin->NodesConnectedFrom;
833 TopologyNodesCount = Pin->NodesConnectedFromCount;
834
835 /* use pins to which this pin is attached to */
836 TopologyPins = Pin->PinConnectedFrom;
837 TopologyPinsCount = Pin->PinConnectedFromCount;
838
839 }
840 else
841 {
842 /* use nodes which are attached to a pin */
843 TopologyNodes = Pin->NodesConnectedTo;
844 TopologyNodesCount = Pin->NodesConnectedToCount;
845
846 /* use pins which are attached to this pin */
847 TopologyPins = Pin->PinConnectedTo;
848 TopologyPinsCount = Pin->PinConnectedToCount;
849 }
850
851
852 /* reset visited status */
853 MMixerResetTopologyVisitStatus(Topology);
854
855 /* sanity check */
856 ASSERT(Topology->TopologyPinsCount > PinIndex);
857
858 /* add pins which are directly connected to this pin */
859 for(Index = 0; Index < TopologyPinsCount; Index++)
860 {
861 /* add them to pin array */
862 MMixerAddPinIndexToArray(MixerContext, TopologyPins[Index], Topology->TopologyPinsCount, OutPinsCount, OutPins);
863 }
864
865 /* now visit all up / down stream pins & nodes */
866 for(Index = 0; Index < TopologyNodesCount; Index++)
867 {
868 /* explore all connected pins with helper */
869 MMixerGetAllUpOrDownstreamPinsFromNodeIndex(MixerContext, Topology, TopologyNodes[Index]->NodeIndex, bUpStream, OutPinsCount, OutPins);
870 }
871
872 /* done */
873 return MM_STATUS_SUCCESS;
874
875 }
876
877 VOID
878 MMixerGetAllUpOrDownstreamNodesFromPinIndex(
879 IN PMIXER_CONTEXT MixerContext,
880 IN PTOPOLOGY Topology,
881 IN ULONG PinIndex,
882 IN ULONG bUpStream,
883 OUT PULONG OutNodesCount,
884 OUT PULONG OutNodes)
885 {
886 ULONG Index, TopologyNodesCount;
887 PPIN Pin;
888 PTOPOLOGY_NODE *TopologyNodes;
889
890 /* mark them as empty */
891 *OutNodesCount = 0;
892
893 /* get pin */
894 Pin = &Topology->TopologyPins[PinIndex];
895
896 if (bUpStream)
897 {
898 /* use nodes to which a pin is attached to */
899 TopologyNodes = Pin->NodesConnectedFrom;
900 TopologyNodesCount = Pin->NodesConnectedFromCount;
901 }
902 else
903 {
904 /* use nodes which are attached to a node */
905 TopologyNodes = Pin->NodesConnectedTo;
906 TopologyNodesCount = Pin->NodesConnectedToCount;
907 }
908
909
910 /* reset visited status */
911 MMixerResetTopologyVisitStatus(Topology);
912
913 /* sanity check */
914 ASSERT(Topology->TopologyPinsCount > PinIndex);
915
916 /* now visit all up / down stream pins & nodes */
917 for(Index = 0; Index < TopologyNodesCount; Index++)
918 {
919 /* add node to array */
920 MMixerAddPinIndexToArray(MixerContext, TopologyNodes[Index]->NodeIndex, Topology->TopologyNodesCount, OutNodesCount, OutNodes);
921
922 /* explore all connected nodes with helper */
923 MMixerGetAllUpOrDownstreamNodesFromNodeIndex(MixerContext, Topology, TopologyNodes[Index]->NodeIndex, bUpStream, OutNodesCount, OutNodes);
924 }
925 }
926
927
928 VOID
929 MMixerGetNextNodesFromPinIndex(
930 IN PMIXER_CONTEXT MixerContext,
931 IN PTOPOLOGY Topology,
932 IN ULONG PinIndex,
933 IN ULONG bUpStream,
934 OUT PULONG OutNodesCount,
935 OUT PULONG OutNodes)
936 {
937 PPIN Pin;
938 TOPOLOGY_NODE **TopologyNodes;
939 ULONG TopologyNodesCount;
940 ULONG Index;
941
942 /* sanity check */
943 ASSERT(PinIndex < Topology->TopologyPinsCount);
944
945 /* get pin */
946 Pin = &Topology->TopologyPins[PinIndex];
947
948 if (bUpStream)
949 {
950 /* get up stream nodes */
951 TopologyNodes = Pin->NodesConnectedFrom;
952 TopologyNodesCount = Pin->NodesConnectedFromCount;
953 }
954 else
955 {
956 /* get down stream nodes */
957 TopologyNodes = Pin->NodesConnectedTo;
958 TopologyNodesCount = Pin->NodesConnectedToCount;
959 }
960
961 /* store topology nodes ids */
962 for(Index = 0; Index < TopologyNodesCount; Index++)
963 {
964 OutNodes[Index] = TopologyNodes[Index]->NodeIndex;
965 }
966
967 /* store topology nodes count */
968 *OutNodesCount = TopologyNodesCount;
969 }
970
971 VOID
972 MMixerGetNextNodesFromNodeIndex(
973 IN PMIXER_CONTEXT MixerContext,
974 IN PTOPOLOGY Topology,
975 IN ULONG NodeIndex,
976 IN ULONG bUpStream,
977 OUT PULONG OutNodesCount,
978 OUT PULONG OutNodes)
979 {
980 TOPOLOGY_NODE **TopologyNodes;
981 ULONG TopologyNodesCount;
982 ULONG Index;
983
984 /* sanity check */
985 ASSERT(NodeIndex < Topology->TopologyNodesCount);
986
987 if (bUpStream)
988 {
989 /* get up stream nodes */
990 TopologyNodes = Topology->TopologyNodes[NodeIndex].NodeConnectedFrom;
991 TopologyNodesCount = Topology->TopologyNodes[NodeIndex].NodeConnectedFromCount;
992 }
993 else
994 {
995 /* get down stream nodes */
996 TopologyNodes = Topology->TopologyNodes[NodeIndex].NodeConnectedTo;
997 TopologyNodesCount = Topology->TopologyNodes[NodeIndex].NodeConnectedToCount;
998 }
999
1000 /* store topology nodes ids */
1001 for(Index = 0; Index < TopologyNodesCount; Index++)
1002 {
1003 OutNodes[Index] = TopologyNodes[Index]->NodeIndex;
1004 }
1005
1006 /* store topology nodes count */
1007 *OutNodesCount = TopologyNodesCount;
1008 }
1009
1010 VOID
1011 MMixerGetTopologyPinCount(
1012 IN PTOPOLOGY Topology,
1013 OUT PULONG PinCount)
1014 {
1015 /* store pin count */
1016 *PinCount = Topology->TopologyPinsCount;
1017 }
1018
1019 MIXER_STATUS
1020 MMixerAllocateTopologyPinArray(
1021 IN PMIXER_CONTEXT MixerContext,
1022 IN PTOPOLOGY Topology,
1023 OUT PULONG * OutPins)
1024 {
1025 PULONG Pins;
1026 ULONG Index;
1027
1028 /* sanity check */
1029 ASSERT(Topology->TopologyPinsCount != 0);
1030
1031 /* allocate topology pins */
1032 Pins = MixerContext->Alloc(Topology->TopologyPinsCount * sizeof(ULONG));
1033
1034 if (!Pins)
1035 {
1036 /* out of memory */
1037 return MM_STATUS_NO_MEMORY;
1038 }
1039
1040 /* mark index as unused */
1041 for(Index = 0; Index < Topology->TopologyPinsCount; Index++)
1042 Pins[Index] = MAXULONG;
1043
1044 /* store result */
1045 *OutPins = Pins;
1046
1047 /* done */
1048 return MM_STATUS_SUCCESS;
1049 }
1050
1051 MIXER_STATUS
1052 MMixerAllocateTopologyNodeArray(
1053 IN PMIXER_CONTEXT MixerContext,
1054 IN PTOPOLOGY Topology,
1055 OUT PULONG * OutNodes)
1056 {
1057 PULONG Nodes;
1058 ULONG Index;
1059
1060 /* sanity check */
1061 ASSERT(Topology->TopologyNodesCount != 0);
1062
1063 /* allocate topology pins */
1064 Nodes = MixerContext->Alloc(Topology->TopologyNodesCount * sizeof(ULONG));
1065
1066 if (!Nodes)
1067 {
1068 /* out of memory */
1069 return MM_STATUS_NO_MEMORY;
1070 }
1071
1072 /* mark index as unused */
1073 for(Index = 0; Index < Topology->TopologyNodesCount; Index++)
1074 Nodes[Index] = MAXULONG;
1075
1076 /* store result */
1077 *OutNodes = Nodes;
1078
1079 /* done */
1080 return MM_STATUS_SUCCESS;
1081 }
1082
1083 VOID
1084 MMixerIsNodeTerminator(
1085 IN PTOPOLOGY Topology,
1086 IN ULONG NodeIndex,
1087 OUT ULONG * bTerminator)
1088 {
1089 /* sanity check */
1090 ASSERT(NodeIndex < Topology->TopologyNodesCount);
1091
1092 /* check if node has multiple parents */
1093 if (Topology->TopologyNodes[NodeIndex].NodeConnectedFromCount > 1)
1094 {
1095 /* node is connected to multiple other nodes */
1096 *bTerminator = TRUE;
1097
1098 /* done */
1099 return;
1100 }
1101
1102 /* check if node is mux / sum node */
1103 if (IsEqualGUIDAligned(&Topology->TopologyNodes[NodeIndex].NodeType, &KSNODETYPE_SUM) ||
1104 IsEqualGUIDAligned(&Topology->TopologyNodes[NodeIndex].NodeType, &KSNODETYPE_MUX))
1105 {
1106 /* classic terminator */
1107 *bTerminator = TRUE;
1108
1109 /* done */
1110 return;
1111
1112 }
1113
1114 /* node is not a terminator */
1115 *bTerminator = FALSE;
1116 }
1117
1118 MIXER_STATUS
1119 MMixerIsNodeConnectedToPin(
1120 IN PMIXER_CONTEXT MixerContext,
1121 IN PTOPOLOGY Topology,
1122 IN ULONG NodeIndex,
1123 IN ULONG PinId,
1124 IN ULONG bUpStream,
1125 OUT PULONG bConnected)
1126 {
1127 MIXER_STATUS Status;
1128 ULONG Index, PinsCount;
1129 PULONG Pins;
1130
1131 /* allocate pin index array */
1132 Status = MMixerAllocateTopologyPinArray(MixerContext, Topology, &Pins);
1133
1134 if (Status != MM_STATUS_SUCCESS)
1135 {
1136 /* failed to allocate */
1137 return Status;
1138 }
1139
1140 /* now get connected pins */
1141 PinsCount = 0;
1142 MMixerGetAllUpOrDownstreamPinsFromNodeIndex(MixerContext, Topology, NodeIndex, bUpStream, &PinsCount, Pins);
1143
1144 /* set to false */
1145 *bConnected = FALSE;
1146
1147 for(Index = 0; Index < PinsCount; Index++)
1148 {
1149 if (Pins[Index] == PinId)
1150 {
1151 /* pin is connected */
1152 *bConnected = TRUE;
1153 break;
1154 }
1155 }
1156
1157 /* free pin index array */
1158 MixerContext->Free(Pins);
1159
1160 /* done */
1161 return MM_STATUS_SUCCESS;
1162 }
1163
1164 VOID
1165 MMixerGetConnectedFromLogicalTopologyPins(
1166 IN PTOPOLOGY Topology,
1167 IN ULONG NodeIndex,
1168 OUT PULONG OutPinCount,
1169 OUT PULONG OutPins)
1170 {
1171 ULONG Index;
1172 PTOPOLOGY_NODE Node;
1173
1174 /* sanity check */
1175 ASSERT(NodeIndex < Topology->TopologyNodesCount);
1176
1177 /* get node */
1178 Node = &Topology->TopologyNodes[NodeIndex];
1179
1180 for(Index = 0; Index < Node->NodeConnectedFromCount; Index++)
1181 {
1182 /* copy logical pin id */
1183 OutPins[Index] = Node->LogicalPinNodeConnectedFrom[Index];
1184 }
1185
1186 /* store pin count */
1187 *OutPinCount = Node->NodeConnectedFromCount;
1188 }
1189
1190 LPGUID
1191 MMixerGetNodeTypeFromTopology(
1192 IN PTOPOLOGY Topology,
1193 IN ULONG NodeIndex)
1194 {
1195 /* sanity check */
1196 ASSERT(NodeIndex < Topology->TopologyNodesCount);
1197
1198 return &Topology->TopologyNodes[NodeIndex].NodeType;
1199 }
1200
1201 VOID
1202 MMixerSetTopologyPinReserved(
1203 IN PTOPOLOGY Topology,
1204 IN ULONG PinId)
1205 {
1206 /* sanity check */
1207 ASSERT(PinId < Topology->TopologyPinsCount);
1208
1209 /* set reserved */
1210 Topology->TopologyPins[PinId].Reserved = TRUE;
1211 }
1212
1213 VOID
1214 MMixerIsTopologyPinReserved(
1215 IN PTOPOLOGY Topology,
1216 IN ULONG PinId,
1217 OUT PULONG bReserved)
1218 {
1219 /* sanity check */
1220 ASSERT(PinId < Topology->TopologyPinsCount);
1221
1222 /* get reserved status */
1223 *bReserved = Topology->TopologyPins[PinId].Reserved;
1224 }
1225
1226 VOID
1227 MMixerSetTopologyNodeReserved(
1228 IN PTOPOLOGY Topology,
1229 IN ULONG NodeIndex)
1230 {
1231 /* sanity check */
1232 ASSERT(NodeIndex < Topology->TopologyNodesCount);
1233
1234 /* set reserved */
1235 Topology->TopologyNodes[NodeIndex].Reserved = TRUE;
1236 }
1237
1238 VOID
1239 MMixerIsTopologyNodeReserved(
1240 IN PTOPOLOGY Topology,
1241 IN ULONG NodeIndex,
1242 OUT PULONG bReserved)
1243 {
1244 /* sanity check */
1245 ASSERT(NodeIndex < Topology->TopologyNodesCount);
1246
1247 /* get reserved status */
1248 *bReserved = Topology->TopologyNodes[NodeIndex].Reserved;
1249 }
1250
1251
1252 MIXER_STATUS
1253 MMixerCreateTopology(
1254 IN PMIXER_CONTEXT MixerContext,
1255 IN ULONG PinCount,
1256 IN PKSMULTIPLE_ITEM NodeConnections,
1257 IN PKSMULTIPLE_ITEM NodeTypes,
1258 OUT PTOPOLOGY *OutTopology)
1259 {
1260 MIXER_STATUS Status;
1261 PTOPOLOGY Topology;
1262
1263 /* allocate topology */
1264 Status = MMixerAllocateTopology(MixerContext, NodeTypes->Count, PinCount, &Topology);
1265
1266 if (Status != MM_STATUS_SUCCESS)
1267 {
1268 /* failed to allocate topology */
1269 return Status;
1270 }
1271
1272 /* initialize topology nodes */
1273 MMixerInitializeTopologyNodes(MixerContext, NodeTypes, Topology);
1274
1275 /* explore topology */
1276 Status = MMixerExploreTopology(MixerContext, NodeConnections, NodeTypes, Topology);
1277
1278 if (Status != MM_STATUS_SUCCESS)
1279 {
1280 /* failed to allocate topology */
1281 return Status;
1282 }
1283
1284 MMixerPrintTopology(Topology);
1285
1286 /* store result */
1287 *OutTopology = Topology;
1288
1289 /* done */
1290 return MM_STATUS_SUCCESS;
1291 }