[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 ULONG Count;
268
269 /* sanity checks */
270 ASSERT(Topology->TopologyNodesCount > Connection->ToNode);
271 ASSERT(Topology->TopologyNodesCount > Connection->FromNode);
272
273 /* get node */
274 InNode = &Topology->TopologyNodes[Connection->FromNode];
275 OutNode = &Topology->TopologyNodes[Connection->ToNode];
276
277 /* get existing count */
278 Count = OutNode->NodeConnectedFromCount;
279
280 /* allocate new nodes array */
281 NewNodes = MixerContext->Alloc(sizeof(PTOPOLOGY_NODE) * (Count + 1));
282
283 if (!NewNodes)
284 {
285 /* out of memory */
286 return MM_STATUS_NO_MEMORY;
287 }
288
289 if (Count)
290 {
291 /* copy existing nodes */
292 MixerContext->Copy(NewNodes, OutNode->NodeConnectedFrom, sizeof(PTOPOLOGY) * Count);
293
294 /* release old nodes array */
295 MixerContext->Free(OutNode->NodeConnectedFrom);
296 }
297
298 /* add new topology node */
299 NewNodes[OutNode->NodeConnectedFromCount] = InNode;
300
301 /* replace old nodes array */
302 OutNode->NodeConnectedFrom = NewNodes;
303
304 /* increment nodes count */
305 OutNode->NodeConnectedFromCount++;
306
307 /* get existing count */
308 Count = InNode->NodeConnectedToCount;
309
310 /* allocate new nodes array */
311 NewNodes = MixerContext->Alloc(sizeof(PTOPOLOGY_NODE) * (Count + 1));
312
313 if (!NewNodes)
314 {
315 /* out of memory */
316 return MM_STATUS_NO_MEMORY;
317 }
318
319 if (Count)
320 {
321 /* copy existing nodes */
322 MixerContext->Copy(NewNodes, InNode->NodeConnectedTo, sizeof(PTOPOLOGY) * Count);
323
324 /* release old nodes array */
325 MixerContext->Free(InNode->NodeConnectedTo);
326 }
327
328 /* add new topology node */
329 NewNodes[InNode->NodeConnectedToCount] = OutNode;
330
331 /* replace old nodes array */
332 InNode->NodeConnectedTo = NewNodes;
333
334 /* increment nodes count */
335 InNode->NodeConnectedToCount++;
336
337 /* done */
338 return MM_STATUS_SUCCESS;
339 }
340
341 MIXER_STATUS
342 MMixerAddPinToPinConnection(
343 IN PMIXER_CONTEXT MixerContext,
344 IN OUT PPIN InPin,
345 IN OUT PPIN OutPin)
346 {
347 ULONG Count;
348 PULONG NewPinsIndex;
349
350 /* now enlarge PinConnectedTo */
351 Count = InPin->PinConnectedToCount;
352
353 /* allocate pin connection index */
354 NewPinsIndex = MixerContext->Alloc(sizeof(ULONG) * (Count + 1));
355
356 if (!NewPinsIndex)
357 {
358 /* out of memory */
359 return MM_STATUS_NO_MEMORY;
360 }
361
362 if (Count)
363 {
364 /* copy existing nodes */
365 MixerContext->Copy(NewPinsIndex, InPin->PinConnectedTo, sizeof(ULONG) * Count);
366
367 /* release old nodes array */
368 MixerContext->Free(InPin->PinConnectedTo);
369 }
370
371 /* add new topology node */
372 NewPinsIndex[Count] = OutPin->PinId;
373
374 /* replace old nodes array */
375 InPin->PinConnectedTo = NewPinsIndex;
376
377 /* increment pin count */
378 InPin->PinConnectedToCount++;
379
380 /* now enlarge PinConnectedFrom */
381 Count = OutPin->PinConnectedFromCount;
382
383 /* allocate pin connection index */
384 NewPinsIndex = MixerContext->Alloc(sizeof(ULONG) * (Count + 1));
385
386 if (!NewPinsIndex)
387 {
388 /* out of memory */
389 return MM_STATUS_NO_MEMORY;
390 }
391
392 if (Count)
393 {
394 /* copy existing nodes */
395 MixerContext->Copy(NewPinsIndex, OutPin->PinConnectedFrom, sizeof(ULONG) * Count);
396
397 /* release old nodes array */
398 MixerContext->Free(OutPin->PinConnectedFrom);
399 }
400
401 /* add new topology node */
402 NewPinsIndex[Count] = InPin->PinId;
403
404 /* replace old nodes array */
405 OutPin->PinConnectedFrom = NewPinsIndex;
406
407 /* increment pin count */
408 OutPin->PinConnectedFromCount++;
409
410 /* done */
411 return MM_STATUS_SUCCESS;
412 }
413
414 MIXER_STATUS
415 MMixerHandleNodePinConnection(
416 IN PMIXER_CONTEXT MixerContext,
417 IN PKSTOPOLOGY_CONNECTION Connection,
418 IN OUT PTOPOLOGY Topology)
419 {
420 PPIN Pin;
421 PTOPOLOGY_NODE Node;
422
423 /* check type */
424 if (Connection->FromNode == KSFILTER_NODE &&
425 Connection->ToNode == KSFILTER_NODE)
426 {
427 /* Pin -> Pin direction */
428
429 /* sanity checks */
430 ASSERT(Topology->TopologyPinsCount > Connection->FromNodePin);
431 ASSERT(Topology->TopologyPinsCount > Connection->ToNodePin);
432
433 /* add connection */
434 return MMixerAddPinToPinConnection(MixerContext,
435 &Topology->TopologyPins[Connection->FromNodePin],
436 &Topology->TopologyPins[Connection->ToNodePin]);
437
438 }
439 else if (Connection->FromNode == KSFILTER_NODE)
440 {
441 /* Pin -> Node direction */
442
443 /* sanity checks */
444 ASSERT(Topology->TopologyPinsCount > Connection->FromNodePin);
445 ASSERT(Topology->TopologyNodesCount > Connection->ToNode);
446 ASSERT(Connection->ToNode != KSFILTER_NODE);
447
448 /* get pin */
449 Pin = &Topology->TopologyPins[Connection->FromNodePin];
450
451 /* get node */
452 Node = &Topology->TopologyNodes[Connection->ToNode];
453
454 /* initialize pin */
455 Pin->PinId = Connection->FromNodePin;
456
457 /* mark as visited */
458 Pin->Visited = TRUE;
459 Node->Visited = TRUE;
460
461 /* add connection */
462 return MMixerAddPinConnection(MixerContext, Pin, Node, TRUE);
463 }
464 else if (Connection->ToNode == KSFILTER_NODE)
465 {
466 /* Node -> Pin direction */
467
468 /* sanity checks */
469 ASSERT(Topology->TopologyPinsCount > Connection->ToNodePin);
470 ASSERT(Topology->TopologyNodesCount > Connection->FromNode);
471 ASSERT(Connection->FromNode != KSFILTER_NODE);
472
473 /* get pin */
474 Pin = &Topology->TopologyPins[Connection->ToNodePin];
475
476 /* get node */
477 Node = &Topology->TopologyNodes[Connection->FromNode];
478
479 /* initialize pin */
480 Pin->PinId = Connection->ToNodePin;
481
482 /* mark as visited */
483 Pin->Visited = TRUE;
484 Node->Visited = TRUE;
485
486 /* add connection */
487 return MMixerAddPinConnection(MixerContext, Pin, Node, FALSE);
488 }
489 /* invalid call */
490 ASSERT(0);
491 return MM_STATUS_INVALID_PARAMETER;
492 }
493
494 MIXER_STATUS
495 MMixerExploreTopology(
496 IN PMIXER_CONTEXT MixerContext,
497 IN PKSMULTIPLE_ITEM NodeConnections,
498 IN PKSMULTIPLE_ITEM NodeTypes,
499 IN OUT PTOPOLOGY Topology)
500 {
501 ULONG Index;
502 LPGUID Guids;
503 PKSTOPOLOGY_CONNECTION Connection;
504 MIXER_STATUS Status;
505
506 /* sanity check */
507 ASSERT(Topology->TopologyNodesCount == NodeTypes->Count);
508
509 /* get topology node types */
510 Guids = (LPGUID)(NodeTypes + 1);
511
512 /* get node connections */
513 Connection = (PKSTOPOLOGY_CONNECTION)(NodeConnections + 1);
514
515 for(Index = 0; Index < NodeConnections->Count; Index++)
516 {
517 if (Connection[Index].FromNode == KSFILTER_NODE ||
518 Connection[Index].ToNode == KSFILTER_NODE)
519 {
520 /* handle connection from Pin -> Node / Node->Pin */
521 Status = MMixerHandleNodePinConnection(MixerContext,
522 &Connection[Index],
523 Topology);
524
525 }
526 else
527 {
528 /* handle connection from Node -> Node */
529 Status = MMixerHandleNodeToNodeConnection(MixerContext,
530 &Connection[Index],
531 Topology);
532 }
533
534 if (Status != MM_STATUS_SUCCESS)
535 {
536 /* failed to handle connection */
537 return Status;
538 }
539 }
540
541 /* done */
542 return MM_STATUS_SUCCESS;
543 }
544
545 VOID
546 MMixerAddPinIndexToArray(
547 IN PMIXER_CONTEXT MixerContext,
548 IN ULONG PinId,
549 IN ULONG MaxPins,
550 OUT PULONG OutPinCount,
551 OUT PULONG OutPins)
552 {
553 ULONG Index;
554
555 for(Index = 0; Index < MaxPins; Index++)
556 {
557 if (OutPins[Index] != MAXULONG)
558 {
559 if (OutPins[Index] > PinId)
560 {
561 /* shift entries up */
562 MixerContext->Copy(&OutPins[Index + 1], &OutPins[Index], (MaxPins - (Index + 1)) * sizeof(ULONG));
563
564 /* store pin id */
565 OutPins[Index] = PinId;
566
567 /* increment pin count */
568 (*OutPinCount)++;
569
570 /* done */
571 return;
572 }
573 }
574 else
575 {
576 /* store pin id */
577 OutPins[Index] = PinId;
578
579 /* increment pin count */
580 (*OutPinCount)++;
581
582 /* done */
583 return;
584 }
585 }
586 }
587
588 VOID
589 MMixerGetUpOrDownStreamPins(
590 IN PMIXER_CONTEXT MixerContext,
591 IN PTOPOLOGY Topology,
592 IN PTOPOLOGY_NODE TopologyNode,
593 IN ULONG bUpStream,
594 OUT PULONG OutPinCount,
595 OUT PULONG OutPins)
596 {
597 ULONG Index, TopologyNodesCount, PinsCount;
598 PTOPOLOGY_NODE *TopologyNodes;
599 PULONG Pins;
600 PPIN Pin;
601
602 /* sanity check */
603 ASSERT(TopologyNode->Visited == FALSE);
604
605 if (bUpStream)
606 {
607 /* use pins to which a node is attached to */
608 PinsCount = TopologyNode->PinConnectedFromCount;
609 Pins = TopologyNode->PinConnectedFrom;
610
611 TopologyNodesCount = TopologyNode->NodeConnectedFromCount;
612 TopologyNodes = TopologyNode->NodeConnectedFrom;
613 }
614 else
615 {
616 /* use pins which are attached to a node */
617 PinsCount = TopologyNode->PinConnectedToCount;
618 Pins = TopologyNode->PinConnectedTo;
619
620 TopologyNodesCount = TopologyNode->NodeConnectedToCount;
621 TopologyNodes = TopologyNode->NodeConnectedTo;
622 }
623
624 /* add all diretly connected pins */
625 for(Index = 0; Index < PinsCount; Index++)
626 {
627 /* sanity check */
628 ASSERT(Pins[Index] < Topology->TopologyPinsCount);
629
630 /* get pin */
631 Pin = &Topology->TopologyPins[Pins[Index]];
632
633 /* pin should not have been visited */
634 ASSERT(Pin->Visited == FALSE);
635 ASSERT(Pins[Index] == Pin->PinId);
636
637 /* FIXME support Pin -> Pin connections in iteration */
638 if (bUpStream)
639 {
640 /* indicates a very broken topology Pin -> Pin -> Node <-... */
641 ASSERT(Pin->PinConnectedFromCount == 0);
642 }
643 else
644 {
645 /* indicates a very broken topology -> Node -> Pin -> Pin */
646 ASSERT(Pin->PinConnectedToCount == 0);
647 }
648
649 /* add them to pin array */
650 MMixerAddPinIndexToArray(MixerContext, Pin->PinId, Topology->TopologyPinsCount, OutPinCount, OutPins);
651
652 /* mark pin as visited */
653 Pin->Visited = TRUE;
654 }
655
656 /* mark node as visited */
657 TopologyNode->Visited = TRUE;
658
659 /* now visit all connected nodes */
660 for(Index = 0; Index < TopologyNodesCount; Index++)
661 {
662 /* recursively visit them */
663 MMixerGetUpOrDownStreamPins(MixerContext, Topology, TopologyNodes[Index], bUpStream, OutPinCount, OutPins);
664 }
665
666 }
667
668 ULONG
669 MMixerGetNodeIndexFromGuid(
670 IN PTOPOLOGY Topology,
671 IN const GUID * NodeType)
672 {
673 ULONG Index;
674
675 for(Index = 0; Index < Topology->TopologyNodesCount; Index++)
676 {
677 if (IsEqualGUIDAligned(NodeType, &Topology->TopologyNodes[Index].NodeType))
678 {
679 return Index;
680 }
681 }
682
683 return MAXULONG;
684 }
685
686
687 VOID
688 MMixerGetAllUpOrDownstreamPinsFromNodeIndex(
689 IN PMIXER_CONTEXT MixerContext,
690 IN PTOPOLOGY Topology,
691 IN ULONG NodeIndex,
692 IN ULONG bUpStream,
693 OUT PULONG OutPinsCount,
694 OUT PULONG OutPins)
695 {
696 PTOPOLOGY_NODE TopologyNode;
697
698 /* reset visited status */
699 MMixerResetTopologyVisitStatus(Topology);
700
701 /* sanity check */
702 ASSERT(Topology->TopologyNodesCount > NodeIndex);
703
704 /* get topology node */
705 TopologyNode = &Topology->TopologyNodes[NodeIndex];
706
707 /* now visit all upstream pins & nodes */
708 MMixerGetUpOrDownStreamPins(MixerContext, Topology, TopologyNode, bUpStream, OutPinsCount, OutPins);
709 }
710
711 VOID
712 MMixerGetUpOrDownstreamNodes(
713 IN PMIXER_CONTEXT MixerContext,
714 IN PTOPOLOGY Topology,
715 IN PTOPOLOGY_NODE TopologyNode,
716 IN ULONG bUpStream,
717 OUT PULONG OutNodeCount,
718 OUT PULONG OutNodes)
719 {
720 ULONG Index, TopologyNodesCount;
721 PTOPOLOGY_NODE Node, *TopologyNodes;
722
723 if (bUpStream)
724 {
725 /* use nodes to which a node is attached to */
726 TopologyNodesCount = TopologyNode->NodeConnectedFromCount;
727 TopologyNodes = TopologyNode->NodeConnectedFrom;
728 }
729 else
730 {
731 /* use nodes which are attached to a node */
732 TopologyNodesCount = TopologyNode->NodeConnectedToCount;
733 TopologyNodes = TopologyNode->NodeConnectedTo;
734 }
735
736 /* sanity check */
737 ASSERT(TopologyNode->Visited == FALSE);
738
739 /* add all connected nodes */
740 for(Index = 0; Index < TopologyNodesCount; Index++)
741 {
742 /* get node */
743 Node = TopologyNodes[Index];
744
745 /* node should not have been visited */
746 ASSERT(Node->Visited == FALSE);
747
748 /* mark node as visited */
749 TopologyNode->Visited = TRUE;
750
751 /* add them to node array */
752 MMixerAddPinIndexToArray(MixerContext, Node->NodeIndex, Topology->TopologyNodesCount, OutNodeCount, OutNodes);
753
754 /* recursively visit them */
755 MMixerGetUpOrDownstreamNodes(MixerContext, Topology, TopologyNodes[Index], bUpStream, OutNodeCount, OutNodes);
756 }
757 }
758
759 MIXER_STATUS
760 MMixerGetAllUpOrDownstreamNodesFromNodeIndex(
761 IN PMIXER_CONTEXT MixerContext,
762 IN PTOPOLOGY Topology,
763 IN ULONG NodeIndex,
764 IN ULONG bUpStream,
765 OUT PULONG OutNodesCount,
766 OUT PULONG OutNodes)
767 {
768 PTOPOLOGY_NODE TopologyNode;
769
770 /* reset visited status */
771 MMixerResetTopologyVisitStatus(Topology);
772
773 /* sanity check */
774 ASSERT(Topology->TopologyNodesCount > NodeIndex);
775
776 /* get topology node */
777 TopologyNode = &Topology->TopologyNodes[NodeIndex];
778
779 /* now visit all upstream pins & nodes */
780 MMixerGetUpOrDownstreamNodes(MixerContext, Topology, TopologyNode, bUpStream, OutNodesCount, OutNodes);
781
782 /* done */
783 return MM_STATUS_SUCCESS;
784
785 }
786
787 MIXER_STATUS
788 MMixerGetAllUpOrDownstreamPinsFromPinIndex(
789 IN PMIXER_CONTEXT MixerContext,
790 IN PTOPOLOGY Topology,
791 IN ULONG PinIndex,
792 IN ULONG bUpStream,
793 OUT PULONG OutPinsCount,
794 OUT PULONG OutPins)
795 {
796 ULONG Index, TopologyNodesCount, TopologyPinsCount;
797 PPIN Pin;
798 PTOPOLOGY_NODE *TopologyNodes;
799 PULONG TopologyPins;
800
801 /* get pin */
802 Pin = &Topology->TopologyPins[PinIndex];
803
804 if (bUpStream)
805 {
806 /* use nodes to which this pin is attached to */
807 TopologyNodes = Pin->NodesConnectedFrom;
808 TopologyNodesCount = Pin->NodesConnectedFromCount;
809
810 /* use pins to which this pin is attached to */
811 TopologyPins = Pin->PinConnectedFrom;
812 TopologyPinsCount = Pin->PinConnectedFromCount;
813
814 }
815 else
816 {
817 /* use nodes which are attached to a pin */
818 TopologyNodes = Pin->NodesConnectedTo;
819 TopologyNodesCount = Pin->NodesConnectedToCount;
820
821 /* use pins which are attached to this pin */
822 TopologyPins = Pin->PinConnectedTo;
823 TopologyPinsCount = Pin->PinConnectedToCount;
824 }
825
826
827 /* reset visited status */
828 MMixerResetTopologyVisitStatus(Topology);
829
830 /* sanity check */
831 ASSERT(Topology->TopologyPinsCount > PinIndex);
832
833 /* add pins which are directly connected to this pin */
834 for(Index = 0; Index < TopologyPinsCount; Index++)
835 {
836 /* add them to pin array */
837 MMixerAddPinIndexToArray(MixerContext, TopologyPins[Index], Topology->TopologyPinsCount, OutPinsCount, OutPins);
838 }
839
840 /* now visit all up / down stream pins & nodes */
841 for(Index = 0; Index < TopologyNodesCount; Index++)
842 {
843 /* explore all connected pins with helper */
844 MMixerGetAllUpOrDownstreamPinsFromNodeIndex(MixerContext, Topology, TopologyNodes[Index]->NodeIndex, bUpStream, OutPinsCount, OutPins);
845 }
846
847 /* done */
848 return MM_STATUS_SUCCESS;
849
850 }
851
852 VOID
853 MMixerGetAllUpOrDownstreamNodesFromPinIndex(
854 IN PMIXER_CONTEXT MixerContext,
855 IN PTOPOLOGY Topology,
856 IN ULONG PinIndex,
857 IN ULONG bUpStream,
858 OUT PULONG OutNodesCount,
859 OUT PULONG OutNodes)
860 {
861 ULONG Index, TopologyNodesCount;
862 PPIN Pin;
863 PTOPOLOGY_NODE *TopologyNodes;
864
865 /* mark them as empty */
866 *OutNodesCount = 0;
867
868 /* get pin */
869 Pin = &Topology->TopologyPins[PinIndex];
870
871 if (bUpStream)
872 {
873 /* use nodes to which a pin is attached to */
874 TopologyNodes = Pin->NodesConnectedFrom;
875 TopologyNodesCount = Pin->NodesConnectedFromCount;
876 }
877 else
878 {
879 /* use nodes which are attached to a node */
880 TopologyNodes = Pin->NodesConnectedTo;
881 TopologyNodesCount = Pin->NodesConnectedToCount;
882 }
883
884
885 /* reset visited status */
886 MMixerResetTopologyVisitStatus(Topology);
887
888 /* sanity check */
889 ASSERT(Topology->TopologyPinsCount > PinIndex);
890
891 /* now visit all up / down stream pins & nodes */
892 for(Index = 0; Index < TopologyNodesCount; Index++)
893 {
894 /* add node to array */
895 MMixerAddPinIndexToArray(MixerContext, TopologyNodes[Index]->NodeIndex, Topology->TopologyNodesCount, OutNodesCount, OutNodes);
896
897 /* explore all connected nodes with helper */
898 MMixerGetAllUpOrDownstreamNodesFromNodeIndex(MixerContext, Topology, TopologyNodes[Index]->NodeIndex, bUpStream, OutNodesCount, OutNodes);
899 }
900 }
901
902
903 VOID
904 MMixerGetNextNodesFromPinIndex(
905 IN PMIXER_CONTEXT MixerContext,
906 IN PTOPOLOGY Topology,
907 IN ULONG PinIndex,
908 IN ULONG bUpStream,
909 OUT PULONG OutNodesCount,
910 OUT PULONG OutNodes)
911 {
912 PPIN Pin;
913 TOPOLOGY_NODE **TopologyNodes;
914 ULONG TopologyNodesCount;
915 ULONG Index;
916
917 /* sanity check */
918 ASSERT(PinIndex < Topology->TopologyPinsCount);
919
920 /* get pin */
921 Pin = &Topology->TopologyPins[PinIndex];
922
923 if (bUpStream)
924 {
925 /* get up stream nodes */
926 TopologyNodes = Pin->NodesConnectedFrom;
927 TopologyNodesCount = Pin->NodesConnectedFromCount;
928 }
929 else
930 {
931 /* get down stream nodes */
932 TopologyNodes = Pin->NodesConnectedTo;
933 TopologyNodesCount = Pin->NodesConnectedToCount;
934 }
935
936 /* store topology nodes ids */
937 for(Index = 0; Index < TopologyNodesCount; Index++)
938 {
939 OutNodes[Index] = TopologyNodes[Index]->NodeIndex;
940 }
941
942 /* store topology nodes count */
943 *OutNodesCount = TopologyNodesCount;
944 }
945
946 VOID
947 MMixerGetNextNodesFromNodeIndex(
948 IN PMIXER_CONTEXT MixerContext,
949 IN PTOPOLOGY Topology,
950 IN ULONG NodeIndex,
951 IN ULONG bUpStream,
952 OUT PULONG OutNodesCount,
953 OUT PULONG OutNodes)
954 {
955 TOPOLOGY_NODE **TopologyNodes;
956 ULONG TopologyNodesCount;
957 ULONG Index;
958
959 /* sanity check */
960 ASSERT(NodeIndex < Topology->TopologyNodesCount);
961
962 if (bUpStream)
963 {
964 /* get up stream nodes */
965 TopologyNodes = Topology->TopologyNodes[NodeIndex].NodeConnectedFrom;
966 TopologyNodesCount = Topology->TopologyNodes[NodeIndex].NodeConnectedFromCount;
967 }
968 else
969 {
970 /* get down stream nodes */
971 TopologyNodes = Topology->TopologyNodes[NodeIndex].NodeConnectedTo;
972 TopologyNodesCount = Topology->TopologyNodes[NodeIndex].NodeConnectedToCount;
973 }
974
975 /* store topology nodes ids */
976 for(Index = 0; Index < TopologyNodesCount; Index++)
977 {
978 OutNodes[Index] = TopologyNodes[Index]->NodeIndex;
979 }
980
981 /* store topology nodes count */
982 *OutNodesCount = TopologyNodesCount;
983 }
984
985 VOID
986 MMixerGetTopologyPinCount(
987 IN PTOPOLOGY Topology,
988 OUT PULONG PinCount)
989 {
990 /* store pin count */
991 *PinCount = Topology->TopologyPinsCount;
992 }
993
994 MIXER_STATUS
995 MMixerAllocateTopologyPinArray(
996 IN PMIXER_CONTEXT MixerContext,
997 IN PTOPOLOGY Topology,
998 OUT PULONG * OutPins)
999 {
1000 PULONG Pins;
1001 ULONG Index;
1002
1003 /* sanity check */
1004 ASSERT(Topology->TopologyPinsCount != 0);
1005
1006 /* allocate topology pins */
1007 Pins = MixerContext->Alloc(Topology->TopologyPinsCount * sizeof(ULONG));
1008
1009 if (!Pins)
1010 {
1011 /* out of memory */
1012 return MM_STATUS_NO_MEMORY;
1013 }
1014
1015 /* mark index as unused */
1016 for(Index = 0; Index < Topology->TopologyPinsCount; Index++)
1017 Pins[Index] = MAXULONG;
1018
1019 /* store result */
1020 *OutPins = Pins;
1021
1022 /* done */
1023 return MM_STATUS_SUCCESS;
1024 }
1025
1026 MIXER_STATUS
1027 MMixerAllocateTopologyNodeArray(
1028 IN PMIXER_CONTEXT MixerContext,
1029 IN PTOPOLOGY Topology,
1030 OUT PULONG * OutNodes)
1031 {
1032 PULONG Nodes;
1033 ULONG Index;
1034
1035 /* sanity check */
1036 ASSERT(Topology->TopologyNodesCount != 0);
1037
1038 /* allocate topology pins */
1039 Nodes = MixerContext->Alloc(Topology->TopologyNodesCount * sizeof(ULONG));
1040
1041 if (!Nodes)
1042 {
1043 /* out of memory */
1044 return MM_STATUS_NO_MEMORY;
1045 }
1046
1047 /* mark index as unused */
1048 for(Index = 0; Index < Topology->TopologyNodesCount; Index++)
1049 Nodes[Index] = MAXULONG;
1050
1051 /* store result */
1052 *OutNodes = Nodes;
1053
1054 /* done */
1055 return MM_STATUS_SUCCESS;
1056 }
1057
1058 VOID
1059 MMixerIsNodeTerminator(
1060 IN PTOPOLOGY Topology,
1061 IN ULONG NodeIndex,
1062 OUT ULONG * bTerminator)
1063 {
1064 /* sanity check */
1065 ASSERT(NodeIndex < Topology->TopologyNodesCount);
1066
1067 /* check if node has multiple parents */
1068 if (Topology->TopologyNodes[NodeIndex].NodeConnectedFromCount > 1)
1069 {
1070 /* node is connected to multiple other nodes */
1071 *bTerminator = TRUE;
1072
1073 /* done */
1074 return;
1075 }
1076
1077 /* check if node is mux / sum node */
1078 if (IsEqualGUIDAligned(&Topology->TopologyNodes[NodeIndex].NodeType, &KSNODETYPE_SUM) ||
1079 IsEqualGUIDAligned(&Topology->TopologyNodes[NodeIndex].NodeType, &KSNODETYPE_MUX))
1080 {
1081 /* classic terminator */
1082 *bTerminator = TRUE;
1083
1084 /* done */
1085 return;
1086
1087 }
1088
1089 /* node is not a terminator */
1090 *bTerminator = FALSE;
1091 }
1092
1093 MIXER_STATUS
1094 MMixerIsNodeConnectedToPin(
1095 IN PMIXER_CONTEXT MixerContext,
1096 IN PTOPOLOGY Topology,
1097 IN ULONG NodeIndex,
1098 IN ULONG PinId,
1099 IN ULONG bUpStream,
1100 OUT PULONG bConnected)
1101 {
1102 MIXER_STATUS Status;
1103 ULONG Index, PinsCount;
1104 PULONG Pins;
1105
1106 /* allocate pin index array */
1107 Status = MMixerAllocateTopologyPinArray(MixerContext, Topology, &Pins);
1108
1109 if (Status != MM_STATUS_SUCCESS)
1110 {
1111 /* failed to allocate */
1112 return Status;
1113 }
1114
1115 /* now get connected pins */
1116 PinsCount = 0;
1117 MMixerGetAllUpOrDownstreamPinsFromNodeIndex(MixerContext, Topology, NodeIndex, bUpStream, &PinsCount, Pins);
1118
1119 /* set to false */
1120 *bConnected = FALSE;
1121
1122 for(Index = 0; Index < PinsCount; Index++)
1123 {
1124 if (Pins[Index] == PinId)
1125 {
1126 /* pin is connected */
1127 *bConnected = TRUE;
1128 break;
1129 }
1130 }
1131
1132 /* free pin index array */
1133 MixerContext->Free(Pins);
1134
1135 /* done */
1136 return MM_STATUS_SUCCESS;
1137 }
1138
1139 LPGUID
1140 MMixerGetNodeTypeFromTopology(
1141 IN PTOPOLOGY Topology,
1142 IN ULONG NodeIndex)
1143 {
1144 /* sanity check */
1145 ASSERT(NodeIndex < Topology->TopologyNodesCount);
1146
1147 return &Topology->TopologyNodes[NodeIndex].NodeType;
1148 }
1149
1150 VOID
1151 MMixerSetTopologyNodeReserved(
1152 IN PTOPOLOGY Topology,
1153 IN ULONG NodeIndex)
1154 {
1155 /* sanity check */
1156 ASSERT(NodeIndex < Topology->TopologyNodesCount);
1157
1158 /* set reserved */
1159 Topology->TopologyNodes[NodeIndex].Reserved = TRUE;
1160 }
1161
1162 VOID
1163 MMixerIsTopologyNodeReserved(
1164 IN PTOPOLOGY Topology,
1165 IN ULONG NodeIndex,
1166 OUT PULONG bReserved)
1167 {
1168 /* sanity check */
1169 ASSERT(NodeIndex < Topology->TopologyNodesCount);
1170
1171 /* get reserved status */
1172 *bReserved = Topology->TopologyNodes[NodeIndex].Reserved;
1173 }
1174
1175
1176 MIXER_STATUS
1177 MMixerCreateTopology(
1178 IN PMIXER_CONTEXT MixerContext,
1179 IN ULONG PinCount,
1180 IN PKSMULTIPLE_ITEM NodeConnections,
1181 IN PKSMULTIPLE_ITEM NodeTypes,
1182 OUT PTOPOLOGY *OutTopology)
1183 {
1184 MIXER_STATUS Status;
1185 PTOPOLOGY Topology;
1186
1187 /* allocate topology */
1188 Status = MMixerAllocateTopology(MixerContext, NodeTypes->Count, PinCount, &Topology);
1189
1190 if (Status != MM_STATUS_SUCCESS)
1191 {
1192 /* failed to allocate topology */
1193 return Status;
1194 }
1195
1196 /* initialize topology nodes */
1197 MMixerInitializeTopologyNodes(MixerContext, NodeTypes, Topology);
1198
1199 /* explore topology */
1200 Status = MMixerExploreTopology(MixerContext, NodeConnections, NodeTypes, Topology);
1201
1202 if (Status != MM_STATUS_SUCCESS)
1203 {
1204 /* failed to allocate topology */
1205 return Status;
1206 }
1207
1208 MMixerPrintTopology(Topology);
1209
1210 /* store result */
1211 *OutTopology = Topology;
1212
1213 /* done */
1214 return MM_STATUS_SUCCESS;
1215 }
1216
1217
1218
1219
1220