[AUDIO-BRINGUP]
[reactos.git] / 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 "priv.h"
10
11 VOID
12 MMixerPrintTopology(
13 PTOPOLOGY Topology)
14 {
15 ULONG Index, SubIndex;
16
17 DPRINT("Num Pins %lu NumNodes %lu\n", Topology->TopologyPinsCount, Topology->TopologyNodesCount);
18
19 for(Index = 0; Index < Topology->TopologyPinsCount; Index++)
20 {
21 DPRINT("PinId %lu NodesConnectedFromCount %lu NodesConnectedToCount %lu Visited %lu\n", Topology->TopologyPins[Index].PinId,
22 Topology->TopologyPins[Index].NodesConnectedFromCount, Topology->TopologyPins[Index].NodesConnectedToCount, Topology->TopologyPins[Index].Visited);
23
24 for(SubIndex = 0; SubIndex < Topology->TopologyPins[Index].NodesConnectedFromCount; SubIndex++)
25 DPRINT("NodesConnectedFrom Index %lu NodeId %lu\n", SubIndex, Topology->TopologyPins[Index].NodesConnectedFrom[SubIndex]->NodeIndex);
26
27 for(SubIndex = 0; SubIndex < Topology->TopologyPins[Index].NodesConnectedToCount; SubIndex++)
28 DPRINT("NodesConnectedTo Index %lu NodeId %lu\n", SubIndex, Topology->TopologyPins[Index].NodesConnectedTo[SubIndex]->NodeIndex);
29 }
30
31 for(Index = 0; Index < Topology->TopologyNodesCount; Index++)
32 {
33 DPRINT("NodeId %lu NodesConnectedFromCount %lu NodesConnectedToCount %lu Visited %lu PinConnectedFromCount %lu PinConnectedToCount %lu\n", Topology->TopologyNodes[Index].NodeIndex,
34 Topology->TopologyNodes[Index].NodeConnectedFromCount, Topology->TopologyNodes[Index].NodeConnectedToCount, Topology->TopologyNodes[Index].Visited,
35 Topology->TopologyNodes[Index].PinConnectedFromCount, Topology->TopologyNodes[Index].PinConnectedToCount);
36 }
37
38
39 }
40
41
42 MIXER_STATUS
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
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
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
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
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
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
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
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 LPGUID Guids;
529 PKSTOPOLOGY_CONNECTION Connection;
530 MIXER_STATUS Status;
531
532 /* sanity check */
533 ASSERT(Topology->TopologyNodesCount == NodeTypes->Count);
534
535 /* get topology node types */
536 Guids = (LPGUID)(NodeTypes + 1);
537
538 /* get node connections */
539 Connection = (PKSTOPOLOGY_CONNECTION)(NodeConnections + 1);
540
541 for(Index = 0; Index < NodeConnections->Count; Index++)
542 {
543 if (Connection[Index].FromNode == KSFILTER_NODE ||
544 Connection[Index].ToNode == KSFILTER_NODE)
545 {
546 /* handle connection from Pin -> Node / Node->Pin */
547 Status = MMixerHandleNodePinConnection(MixerContext,
548 &Connection[Index],
549 Topology);
550
551 }
552 else
553 {
554 /* handle connection from Node -> Node */
555 Status = MMixerHandleNodeToNodeConnection(MixerContext,
556 &Connection[Index],
557 Topology);
558 }
559
560 if (Status != MM_STATUS_SUCCESS)
561 {
562 /* failed to handle connection */
563 return Status;
564 }
565 }
566
567 /* done */
568 return MM_STATUS_SUCCESS;
569 }
570
571 VOID
572 MMixerAddPinIndexToArray(
573 IN PMIXER_CONTEXT MixerContext,
574 IN ULONG PinId,
575 IN ULONG MaxPins,
576 OUT PULONG OutPinCount,
577 OUT PULONG OutPins)
578 {
579 ULONG Index;
580
581 for(Index = 0; Index < MaxPins; Index++)
582 {
583 if (OutPins[Index] != MAXULONG)
584 {
585 if (OutPins[Index] > PinId)
586 {
587 /* shift entries up */
588 MixerContext->Copy(&OutPins[Index + 1], &OutPins[Index], (MaxPins - (Index + 1)) * sizeof(ULONG));
589
590 /* store pin id */
591 OutPins[Index] = PinId;
592
593 /* increment pin count */
594 (*OutPinCount)++;
595
596 /* done */
597 return;
598 }
599 }
600 else
601 {
602 /* store pin id */
603 OutPins[Index] = PinId;
604
605 /* increment pin count */
606 (*OutPinCount)++;
607
608 /* done */
609 return;
610 }
611 }
612 }
613
614 VOID
615 MMixerGetUpOrDownStreamPins(
616 IN PMIXER_CONTEXT MixerContext,
617 IN PTOPOLOGY Topology,
618 IN PTOPOLOGY_NODE TopologyNode,
619 IN ULONG bUpStream,
620 OUT PULONG OutPinCount,
621 OUT PULONG OutPins)
622 {
623 ULONG Index, TopologyNodesCount, PinsCount;
624 PTOPOLOGY_NODE *TopologyNodes;
625 PULONG Pins;
626 PPIN Pin;
627
628 /* sanity check */
629 ASSERT(TopologyNode->Visited == FALSE);
630
631 if (bUpStream)
632 {
633 /* use pins to which a node is attached to */
634 PinsCount = TopologyNode->PinConnectedFromCount;
635 Pins = TopologyNode->PinConnectedFrom;
636
637 TopologyNodesCount = TopologyNode->NodeConnectedFromCount;
638 TopologyNodes = TopologyNode->NodeConnectedFrom;
639 }
640 else
641 {
642 /* use pins which are attached to a node */
643 PinsCount = TopologyNode->PinConnectedToCount;
644 Pins = TopologyNode->PinConnectedTo;
645
646 TopologyNodesCount = TopologyNode->NodeConnectedToCount;
647 TopologyNodes = TopologyNode->NodeConnectedTo;
648 }
649
650 /* add all diretly connected pins */
651 for(Index = 0; Index < PinsCount; Index++)
652 {
653 /* sanity check */
654 ASSERT(Pins[Index] < Topology->TopologyPinsCount);
655
656 /* get pin */
657 Pin = &Topology->TopologyPins[Pins[Index]];
658
659 /* pin should not have been visited */
660 ASSERT(Pin->Visited == FALSE);
661 ASSERT(Pins[Index] == Pin->PinId);
662
663 /* FIXME support Pin -> Pin connections in iteration */
664 if (bUpStream)
665 {
666 /* indicates a very broken topology Pin -> Pin -> Node <-... */
667 ASSERT(Pin->PinConnectedFromCount == 0);
668 }
669 else
670 {
671 /* indicates a very broken topology -> Node -> Pin -> Pin */
672 ASSERT(Pin->PinConnectedToCount == 0);
673 }
674
675 /* add them to pin array */
676 MMixerAddPinIndexToArray(MixerContext, Pin->PinId, Topology->TopologyPinsCount, OutPinCount, OutPins);
677
678 /* mark pin as visited */
679 Pin->Visited = TRUE;
680 }
681
682 /* mark node as visited */
683 TopologyNode->Visited = TRUE;
684
685 /* now visit all connected nodes */
686 for(Index = 0; Index < TopologyNodesCount; Index++)
687 {
688 /* recursively visit them */
689 MMixerGetUpOrDownStreamPins(MixerContext, Topology, TopologyNodes[Index], bUpStream, OutPinCount, OutPins);
690 }
691
692 }
693
694 ULONG
695 MMixerGetNodeIndexFromGuid(
696 IN PTOPOLOGY Topology,
697 IN const GUID * NodeType)
698 {
699 ULONG Index;
700
701 for(Index = 0; Index < Topology->TopologyNodesCount; Index++)
702 {
703 if (IsEqualGUIDAligned(NodeType, &Topology->TopologyNodes[Index].NodeType))
704 {
705 return Index;
706 }
707 }
708
709 return MAXULONG;
710 }
711
712
713 VOID
714 MMixerGetAllUpOrDownstreamPinsFromNodeIndex(
715 IN PMIXER_CONTEXT MixerContext,
716 IN PTOPOLOGY Topology,
717 IN ULONG NodeIndex,
718 IN ULONG bUpStream,
719 OUT PULONG OutPinsCount,
720 OUT PULONG OutPins)
721 {
722 PTOPOLOGY_NODE TopologyNode;
723
724 /* reset visited status */
725 MMixerResetTopologyVisitStatus(Topology);
726
727 /* sanity check */
728 ASSERT(Topology->TopologyNodesCount > NodeIndex);
729
730 /* get topology node */
731 TopologyNode = &Topology->TopologyNodes[NodeIndex];
732
733 /* now visit all upstream pins & nodes */
734 MMixerGetUpOrDownStreamPins(MixerContext, Topology, TopologyNode, bUpStream, OutPinsCount, OutPins);
735 }
736
737 VOID
738 MMixerGetUpOrDownstreamNodes(
739 IN PMIXER_CONTEXT MixerContext,
740 IN PTOPOLOGY Topology,
741 IN PTOPOLOGY_NODE TopologyNode,
742 IN ULONG bUpStream,
743 OUT PULONG OutNodeCount,
744 OUT PULONG OutNodes)
745 {
746 ULONG Index, TopologyNodesCount;
747 PTOPOLOGY_NODE Node, *TopologyNodes;
748
749 if (bUpStream)
750 {
751 /* use nodes to which a node is attached to */
752 TopologyNodesCount = TopologyNode->NodeConnectedFromCount;
753 TopologyNodes = TopologyNode->NodeConnectedFrom;
754 }
755 else
756 {
757 /* use nodes which are attached to a node */
758 TopologyNodesCount = TopologyNode->NodeConnectedToCount;
759 TopologyNodes = TopologyNode->NodeConnectedTo;
760 }
761
762 /* sanity check */
763 ASSERT(TopologyNode->Visited == FALSE);
764
765 /* add all connected nodes */
766 for(Index = 0; Index < TopologyNodesCount; Index++)
767 {
768 /* get node */
769 Node = TopologyNodes[Index];
770
771 /* node should not have been visited */
772 ASSERT(Node->Visited == FALSE);
773
774 /* mark node as visited */
775 TopologyNode->Visited = TRUE;
776
777 /* add them to node array */
778 MMixerAddPinIndexToArray(MixerContext, Node->NodeIndex, Topology->TopologyNodesCount, OutNodeCount, OutNodes);
779
780 /* recursively visit them */
781 MMixerGetUpOrDownstreamNodes(MixerContext, Topology, TopologyNodes[Index], bUpStream, OutNodeCount, OutNodes);
782 }
783 }
784
785 MIXER_STATUS
786 MMixerGetAllUpOrDownstreamNodesFromNodeIndex(
787 IN PMIXER_CONTEXT MixerContext,
788 IN PTOPOLOGY Topology,
789 IN ULONG NodeIndex,
790 IN ULONG bUpStream,
791 OUT PULONG OutNodesCount,
792 OUT PULONG OutNodes)
793 {
794 PTOPOLOGY_NODE TopologyNode;
795
796 /* reset visited status */
797 MMixerResetTopologyVisitStatus(Topology);
798
799 /* sanity check */
800 ASSERT(Topology->TopologyNodesCount > NodeIndex);
801
802 /* get topology node */
803 TopologyNode = &Topology->TopologyNodes[NodeIndex];
804
805 /* now visit all upstream pins & nodes */
806 MMixerGetUpOrDownstreamNodes(MixerContext, Topology, TopologyNode, bUpStream, OutNodesCount, OutNodes);
807
808 /* done */
809 return MM_STATUS_SUCCESS;
810
811 }
812
813 MIXER_STATUS
814 MMixerGetAllUpOrDownstreamPinsFromPinIndex(
815 IN PMIXER_CONTEXT MixerContext,
816 IN PTOPOLOGY Topology,
817 IN ULONG PinIndex,
818 IN ULONG bUpStream,
819 OUT PULONG OutPinsCount,
820 OUT PULONG OutPins)
821 {
822 ULONG Index, TopologyNodesCount, TopologyPinsCount;
823 PPIN Pin;
824 PTOPOLOGY_NODE *TopologyNodes;
825 PULONG TopologyPins;
826
827 /* get pin */
828 Pin = &Topology->TopologyPins[PinIndex];
829
830 if (bUpStream)
831 {
832 /* use nodes to which this pin is attached to */
833 TopologyNodes = Pin->NodesConnectedFrom;
834 TopologyNodesCount = Pin->NodesConnectedFromCount;
835
836 /* use pins to which this pin is attached to */
837 TopologyPins = Pin->PinConnectedFrom;
838 TopologyPinsCount = Pin->PinConnectedFromCount;
839
840 }
841 else
842 {
843 /* use nodes which are attached to a pin */
844 TopologyNodes = Pin->NodesConnectedTo;
845 TopologyNodesCount = Pin->NodesConnectedToCount;
846
847 /* use pins which are attached to this pin */
848 TopologyPins = Pin->PinConnectedTo;
849 TopologyPinsCount = Pin->PinConnectedToCount;
850 }
851
852
853 /* reset visited status */
854 MMixerResetTopologyVisitStatus(Topology);
855
856 /* sanity check */
857 ASSERT(Topology->TopologyPinsCount > PinIndex);
858
859 /* add pins which are directly connected to this pin */
860 for(Index = 0; Index < TopologyPinsCount; Index++)
861 {
862 /* add them to pin array */
863 MMixerAddPinIndexToArray(MixerContext, TopologyPins[Index], Topology->TopologyPinsCount, OutPinsCount, OutPins);
864 }
865
866 /* now visit all up / down stream pins & nodes */
867 for(Index = 0; Index < TopologyNodesCount; Index++)
868 {
869 /* explore all connected pins with helper */
870 MMixerGetAllUpOrDownstreamPinsFromNodeIndex(MixerContext, Topology, TopologyNodes[Index]->NodeIndex, bUpStream, OutPinsCount, OutPins);
871 }
872
873 /* done */
874 return MM_STATUS_SUCCESS;
875
876 }
877
878 VOID
879 MMixerGetAllUpOrDownstreamNodesFromPinIndex(
880 IN PMIXER_CONTEXT MixerContext,
881 IN PTOPOLOGY Topology,
882 IN ULONG PinIndex,
883 IN ULONG bUpStream,
884 OUT PULONG OutNodesCount,
885 OUT PULONG OutNodes)
886 {
887 ULONG Index, TopologyNodesCount;
888 PPIN Pin;
889 PTOPOLOGY_NODE *TopologyNodes;
890
891 /* mark them as empty */
892 *OutNodesCount = 0;
893
894 /* get pin */
895 Pin = &Topology->TopologyPins[PinIndex];
896
897 if (bUpStream)
898 {
899 /* use nodes to which a pin is attached to */
900 TopologyNodes = Pin->NodesConnectedFrom;
901 TopologyNodesCount = Pin->NodesConnectedFromCount;
902 }
903 else
904 {
905 /* use nodes which are attached to a node */
906 TopologyNodes = Pin->NodesConnectedTo;
907 TopologyNodesCount = Pin->NodesConnectedToCount;
908 }
909
910
911 /* reset visited status */
912 MMixerResetTopologyVisitStatus(Topology);
913
914 /* sanity check */
915 ASSERT(Topology->TopologyPinsCount > PinIndex);
916
917 /* now visit all up / down stream pins & nodes */
918 for(Index = 0; Index < TopologyNodesCount; Index++)
919 {
920 /* add node to array */
921 MMixerAddPinIndexToArray(MixerContext, TopologyNodes[Index]->NodeIndex, Topology->TopologyNodesCount, OutNodesCount, OutNodes);
922
923 /* explore all connected nodes with helper */
924 MMixerGetAllUpOrDownstreamNodesFromNodeIndex(MixerContext, Topology, TopologyNodes[Index]->NodeIndex, bUpStream, OutNodesCount, OutNodes);
925 }
926 }
927
928
929 VOID
930 MMixerGetNextNodesFromPinIndex(
931 IN PMIXER_CONTEXT MixerContext,
932 IN PTOPOLOGY Topology,
933 IN ULONG PinIndex,
934 IN ULONG bUpStream,
935 OUT PULONG OutNodesCount,
936 OUT PULONG OutNodes)
937 {
938 PPIN Pin;
939 TOPOLOGY_NODE **TopologyNodes;
940 ULONG TopologyNodesCount;
941 ULONG Index;
942
943 /* sanity check */
944 ASSERT(PinIndex < Topology->TopologyPinsCount);
945
946 /* get pin */
947 Pin = &Topology->TopologyPins[PinIndex];
948
949 if (bUpStream)
950 {
951 /* get up stream nodes */
952 TopologyNodes = Pin->NodesConnectedFrom;
953 TopologyNodesCount = Pin->NodesConnectedFromCount;
954 }
955 else
956 {
957 /* get down stream nodes */
958 TopologyNodes = Pin->NodesConnectedTo;
959 TopologyNodesCount = Pin->NodesConnectedToCount;
960 }
961
962 /* store topology nodes ids */
963 for(Index = 0; Index < TopologyNodesCount; Index++)
964 {
965 OutNodes[Index] = TopologyNodes[Index]->NodeIndex;
966 }
967
968 /* store topology nodes count */
969 *OutNodesCount = TopologyNodesCount;
970 }
971
972 VOID
973 MMixerGetNextNodesFromNodeIndex(
974 IN PMIXER_CONTEXT MixerContext,
975 IN PTOPOLOGY Topology,
976 IN ULONG NodeIndex,
977 IN ULONG bUpStream,
978 OUT PULONG OutNodesCount,
979 OUT PULONG OutNodes)
980 {
981 TOPOLOGY_NODE **TopologyNodes;
982 ULONG TopologyNodesCount;
983 ULONG Index;
984
985 /* sanity check */
986 ASSERT(NodeIndex < Topology->TopologyNodesCount);
987
988 if (bUpStream)
989 {
990 /* get up stream nodes */
991 TopologyNodes = Topology->TopologyNodes[NodeIndex].NodeConnectedFrom;
992 TopologyNodesCount = Topology->TopologyNodes[NodeIndex].NodeConnectedFromCount;
993 }
994 else
995 {
996 /* get down stream nodes */
997 TopologyNodes = Topology->TopologyNodes[NodeIndex].NodeConnectedTo;
998 TopologyNodesCount = Topology->TopologyNodes[NodeIndex].NodeConnectedToCount;
999 }
1000
1001 /* store topology nodes ids */
1002 for(Index = 0; Index < TopologyNodesCount; Index++)
1003 {
1004 OutNodes[Index] = TopologyNodes[Index]->NodeIndex;
1005 }
1006
1007 /* store topology nodes count */
1008 *OutNodesCount = TopologyNodesCount;
1009 }
1010
1011 VOID
1012 MMixerGetTopologyPinCount(
1013 IN PTOPOLOGY Topology,
1014 OUT PULONG PinCount)
1015 {
1016 /* store pin count */
1017 *PinCount = Topology->TopologyPinsCount;
1018 }
1019
1020 MIXER_STATUS
1021 MMixerAllocateTopologyPinArray(
1022 IN PMIXER_CONTEXT MixerContext,
1023 IN PTOPOLOGY Topology,
1024 OUT PULONG * OutPins)
1025 {
1026 PULONG Pins;
1027 ULONG Index;
1028
1029 /* sanity check */
1030 ASSERT(Topology->TopologyPinsCount != 0);
1031
1032 /* allocate topology pins */
1033 Pins = MixerContext->Alloc(Topology->TopologyPinsCount * sizeof(ULONG));
1034
1035 if (!Pins)
1036 {
1037 /* out of memory */
1038 return MM_STATUS_NO_MEMORY;
1039 }
1040
1041 /* mark index as unused */
1042 for(Index = 0; Index < Topology->TopologyPinsCount; Index++)
1043 Pins[Index] = MAXULONG;
1044
1045 /* store result */
1046 *OutPins = Pins;
1047
1048 /* done */
1049 return MM_STATUS_SUCCESS;
1050 }
1051
1052 MIXER_STATUS
1053 MMixerAllocateTopologyNodeArray(
1054 IN PMIXER_CONTEXT MixerContext,
1055 IN PTOPOLOGY Topology,
1056 OUT PULONG * OutNodes)
1057 {
1058 PULONG Nodes;
1059 ULONG Index;
1060
1061 /* sanity check */
1062 ASSERT(Topology->TopologyNodesCount != 0);
1063
1064 /* allocate topology pins */
1065 Nodes = MixerContext->Alloc(Topology->TopologyNodesCount * sizeof(ULONG));
1066
1067 if (!Nodes)
1068 {
1069 /* out of memory */
1070 return MM_STATUS_NO_MEMORY;
1071 }
1072
1073 /* mark index as unused */
1074 for(Index = 0; Index < Topology->TopologyNodesCount; Index++)
1075 Nodes[Index] = MAXULONG;
1076
1077 /* store result */
1078 *OutNodes = Nodes;
1079
1080 /* done */
1081 return MM_STATUS_SUCCESS;
1082 }
1083
1084 VOID
1085 MMixerIsNodeTerminator(
1086 IN PTOPOLOGY Topology,
1087 IN ULONG NodeIndex,
1088 OUT ULONG * bTerminator)
1089 {
1090 /* sanity check */
1091 ASSERT(NodeIndex < Topology->TopologyNodesCount);
1092
1093 /* check if node has multiple parents */
1094 if (Topology->TopologyNodes[NodeIndex].NodeConnectedFromCount > 1)
1095 {
1096 /* node is connected to multiple other nodes */
1097 *bTerminator = TRUE;
1098
1099 /* done */
1100 return;
1101 }
1102
1103 /* check if node is mux / sum node */
1104 if (IsEqualGUIDAligned(&Topology->TopologyNodes[NodeIndex].NodeType, &KSNODETYPE_SUM) ||
1105 IsEqualGUIDAligned(&Topology->TopologyNodes[NodeIndex].NodeType, &KSNODETYPE_MUX))
1106 {
1107 /* classic terminator */
1108 *bTerminator = TRUE;
1109
1110 /* done */
1111 return;
1112
1113 }
1114
1115 /* node is not a terminator */
1116 *bTerminator = FALSE;
1117 }
1118
1119 MIXER_STATUS
1120 MMixerIsNodeConnectedToPin(
1121 IN PMIXER_CONTEXT MixerContext,
1122 IN PTOPOLOGY Topology,
1123 IN ULONG NodeIndex,
1124 IN ULONG PinId,
1125 IN ULONG bUpStream,
1126 OUT PULONG bConnected)
1127 {
1128 MIXER_STATUS Status;
1129 ULONG Index, PinsCount;
1130 PULONG Pins;
1131
1132 /* allocate pin index array */
1133 Status = MMixerAllocateTopologyPinArray(MixerContext, Topology, &Pins);
1134
1135 if (Status != MM_STATUS_SUCCESS)
1136 {
1137 /* failed to allocate */
1138 return Status;
1139 }
1140
1141 /* now get connected pins */
1142 PinsCount = 0;
1143 MMixerGetAllUpOrDownstreamPinsFromNodeIndex(MixerContext, Topology, NodeIndex, bUpStream, &PinsCount, Pins);
1144
1145 /* set to false */
1146 *bConnected = FALSE;
1147
1148 for(Index = 0; Index < PinsCount; Index++)
1149 {
1150 if (Pins[Index] == PinId)
1151 {
1152 /* pin is connected */
1153 *bConnected = TRUE;
1154 break;
1155 }
1156 }
1157
1158 /* free pin index array */
1159 MixerContext->Free(Pins);
1160
1161 /* done */
1162 return MM_STATUS_SUCCESS;
1163 }
1164
1165 LPGUID
1166 MMixerGetNodeTypeFromTopology(
1167 IN PTOPOLOGY Topology,
1168 IN ULONG NodeIndex)
1169 {
1170 /* sanity check */
1171 ASSERT(NodeIndex < Topology->TopologyNodesCount);
1172
1173 return &Topology->TopologyNodes[NodeIndex].NodeType;
1174 }
1175
1176 VOID
1177 MMixerSetTopologyNodeReserved(
1178 IN PTOPOLOGY Topology,
1179 IN ULONG NodeIndex)
1180 {
1181 /* sanity check */
1182 ASSERT(NodeIndex < Topology->TopologyNodesCount);
1183
1184 /* set reserved */
1185 Topology->TopologyNodes[NodeIndex].Reserved = TRUE;
1186 }
1187
1188 VOID
1189 MMixerIsTopologyNodeReserved(
1190 IN PTOPOLOGY Topology,
1191 IN ULONG NodeIndex,
1192 OUT PULONG bReserved)
1193 {
1194 /* sanity check */
1195 ASSERT(NodeIndex < Topology->TopologyNodesCount);
1196
1197 /* get reserved status */
1198 *bReserved = Topology->TopologyNodes[NodeIndex].Reserved;
1199 }
1200
1201
1202 MIXER_STATUS
1203 MMixerCreateTopology(
1204 IN PMIXER_CONTEXT MixerContext,
1205 IN ULONG PinCount,
1206 IN PKSMULTIPLE_ITEM NodeConnections,
1207 IN PKSMULTIPLE_ITEM NodeTypes,
1208 OUT PTOPOLOGY *OutTopology)
1209 {
1210 MIXER_STATUS Status;
1211 PTOPOLOGY Topology;
1212
1213 /* allocate topology */
1214 Status = MMixerAllocateTopology(MixerContext, NodeTypes->Count, PinCount, &Topology);
1215
1216 if (Status != MM_STATUS_SUCCESS)
1217 {
1218 /* failed to allocate topology */
1219 return Status;
1220 }
1221
1222 /* initialize topology nodes */
1223 MMixerInitializeTopologyNodes(MixerContext, NodeTypes, Topology);
1224
1225 /* explore topology */
1226 Status = MMixerExploreTopology(MixerContext, NodeConnections, NodeTypes, Topology);
1227
1228 if (Status != MM_STATUS_SUCCESS)
1229 {
1230 /* failed to allocate topology */
1231 return Status;
1232 }
1233
1234 MMixerPrintTopology(Topology);
1235
1236 /* store result */
1237 *OutTopology = Topology;
1238
1239 /* done */
1240 return MM_STATUS_SUCCESS;
1241 }
1242
1243
1244
1245
1246