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