sync with trunk (r49238)
[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 DPRINT1("Num Pins %lu NumNodes %lu\n", Topology->TopologyPinsCount, Topology->TopologyNodesCount);
18
19 for(Index = 0; Index < Topology->TopologyPinsCount; Index++)
20 {
21 DPRINT1("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 DPRINT1("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 DPRINT1("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 DPRINT1("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 /* add them to node array */
749 MMixerAddPinIndexToArray(MixerContext, Node->NodeIndex, Topology->TopologyNodesCount, OutNodeCount, OutNodes);
750
751 /* recursively visit them */
752 MMixerGetUpOrDownstreamNodes(MixerContext, Topology, TopologyNodes[Index], bUpStream, OutNodeCount, OutNodes);
753 }
754
755 /* mark node as visited */
756 TopologyNode->Visited = TRUE;
757
758 }
759
760 MIXER_STATUS
761 MMixerGetAllUpOrDownstreamNodesFromNodeIndex(
762 IN PMIXER_CONTEXT MixerContext,
763 IN PTOPOLOGY Topology,
764 IN ULONG NodeIndex,
765 IN ULONG bUpStream,
766 OUT PULONG OutNodesCount,
767 OUT PULONG OutNodes)
768 {
769 PTOPOLOGY_NODE TopologyNode;
770
771 /* reset visited status */
772 MMixerResetTopologyVisitStatus(Topology);
773
774 /* sanity check */
775 ASSERT(Topology->TopologyNodesCount > NodeIndex);
776
777 /* get topology node */
778 TopologyNode = &Topology->TopologyNodes[NodeIndex];
779
780 /* now visit all upstream pins & nodes */
781 MMixerGetUpOrDownstreamNodes(MixerContext, Topology, TopologyNode, bUpStream, OutNodesCount, OutNodes);
782
783 /* done */
784 return MM_STATUS_SUCCESS;
785
786 }
787
788 MIXER_STATUS
789 MMixerGetAllUpOrDownstreamPinsFromPinIndex(
790 IN PMIXER_CONTEXT MixerContext,
791 IN PTOPOLOGY Topology,
792 IN ULONG PinIndex,
793 IN ULONG bUpStream,
794 OUT PULONG OutPinsCount,
795 OUT PULONG OutPins)
796 {
797 ULONG Index, TopologyNodesCount, TopologyPinsCount;
798 PPIN Pin;
799 PTOPOLOGY_NODE *TopologyNodes;
800 PULONG TopologyPins;
801
802 /* get pin */
803 Pin = &Topology->TopologyPins[PinIndex];
804
805 if (bUpStream)
806 {
807 /* use nodes to which this pin is attached to */
808 TopologyNodes = Pin->NodesConnectedFrom;
809 TopologyNodesCount = Pin->NodesConnectedFromCount;
810
811 /* use pins to which this pin is attached to */
812 TopologyPins = Pin->PinConnectedFrom;
813 TopologyPinsCount = Pin->PinConnectedFromCount;
814
815 }
816 else
817 {
818 /* use nodes which are attached to a pin */
819 TopologyNodes = Pin->NodesConnectedTo;
820 TopologyNodesCount = Pin->NodesConnectedToCount;
821
822 /* use pins which are attached to this pin */
823 TopologyPins = Pin->PinConnectedTo;
824 TopologyPinsCount = Pin->PinConnectedToCount;
825 }
826
827
828 /* reset visited status */
829 MMixerResetTopologyVisitStatus(Topology);
830
831 /* sanity check */
832 ASSERT(Topology->TopologyPinsCount > PinIndex);
833
834 /* add pins which are directly connected to this pin */
835 for(Index = 0; Index < TopologyPinsCount; Index++)
836 {
837 /* add them to pin array */
838 MMixerAddPinIndexToArray(MixerContext, TopologyPins[Index], Topology->TopologyPinsCount, OutPinsCount, OutPins);
839 }
840
841 /* now visit all up / down stream pins & nodes */
842 for(Index = 0; Index < TopologyNodesCount; Index++)
843 {
844 /* explore all connected pins with helper */
845 MMixerGetAllUpOrDownstreamPinsFromNodeIndex(MixerContext, Topology, TopologyNodes[Index]->NodeIndex, bUpStream, OutPinsCount, OutPins);
846 }
847
848 /* done */
849 return MM_STATUS_SUCCESS;
850
851 }
852
853 VOID
854 MMixerGetAllUpOrDownstreamNodesFromPinIndex(
855 IN PMIXER_CONTEXT MixerContext,
856 IN PTOPOLOGY Topology,
857 IN ULONG PinIndex,
858 IN ULONG bUpStream,
859 OUT PULONG OutNodesCount,
860 OUT PULONG OutNodes)
861 {
862 ULONG Index, TopologyNodesCount;
863 PPIN Pin;
864 PTOPOLOGY_NODE *TopologyNodes;
865
866 /* mark them as empty */
867 *OutNodesCount = 0;
868
869 /* get pin */
870 Pin = &Topology->TopologyPins[PinIndex];
871
872 if (bUpStream)
873 {
874 /* use nodes to which a pin is attached to */
875 TopologyNodes = Pin->NodesConnectedFrom;
876 TopologyNodesCount = Pin->NodesConnectedFromCount;
877 }
878 else
879 {
880 /* use nodes which are attached to a node */
881 TopologyNodes = Pin->NodesConnectedTo;
882 TopologyNodesCount = Pin->NodesConnectedToCount;
883 }
884
885
886 /* reset visited status */
887 MMixerResetTopologyVisitStatus(Topology);
888
889 /* sanity check */
890 ASSERT(Topology->TopologyPinsCount > PinIndex);
891
892 /* now visit all up / down stream pins & nodes */
893 for(Index = 0; Index < TopologyNodesCount; Index++)
894 {
895 /* add node to array */
896 MMixerAddPinIndexToArray(MixerContext, TopologyNodes[Index]->NodeIndex, Topology->TopologyNodesCount, OutNodesCount, OutNodes);
897
898 /* explore all connected nodes with helper */
899 MMixerGetAllUpOrDownstreamNodesFromNodeIndex(MixerContext, Topology, TopologyNodes[Index]->NodeIndex, bUpStream, OutNodesCount, OutNodes);
900 }
901 }
902
903
904 VOID
905 MMixerGetNextNodesFromPinIndex(
906 IN PMIXER_CONTEXT MixerContext,
907 IN PTOPOLOGY Topology,
908 IN ULONG PinIndex,
909 IN ULONG bUpStream,
910 OUT PULONG OutNodesCount,
911 OUT PULONG OutNodes)
912 {
913 PPIN Pin;
914 TOPOLOGY_NODE **TopologyNodes;
915 ULONG TopologyNodesCount;
916 ULONG Index;
917
918 /* sanity check */
919 ASSERT(PinIndex < Topology->TopologyPinsCount);
920
921 /* get pin */
922 Pin = &Topology->TopologyPins[PinIndex];
923
924 if (bUpStream)
925 {
926 /* get up stream nodes */
927 TopologyNodes = Pin->NodesConnectedFrom;
928 TopologyNodesCount = Pin->NodesConnectedFromCount;
929 }
930 else
931 {
932 /* get down stream nodes */
933 TopologyNodes = Pin->NodesConnectedTo;
934 TopologyNodesCount = Pin->NodesConnectedToCount;
935 }
936
937 /* store topology nodes ids */
938 for(Index = 0; Index < TopologyNodesCount; Index++)
939 {
940 OutNodes[Index] = TopologyNodes[Index]->NodeIndex;
941 }
942
943 /* store topology nodes count */
944 *OutNodesCount = TopologyNodesCount;
945 }
946
947 VOID
948 MMixerGetNextNodesFromNodeIndex(
949 IN PMIXER_CONTEXT MixerContext,
950 IN PTOPOLOGY Topology,
951 IN ULONG NodeIndex,
952 IN ULONG bUpStream,
953 OUT PULONG OutNodesCount,
954 OUT PULONG OutNodes)
955 {
956 TOPOLOGY_NODE **TopologyNodes;
957 ULONG TopologyNodesCount;
958 ULONG Index;
959
960 /* sanity check */
961 ASSERT(NodeIndex < Topology->TopologyNodesCount);
962
963 if (bUpStream)
964 {
965 /* get up stream nodes */
966 TopologyNodes = Topology->TopologyNodes[NodeIndex].NodeConnectedFrom;
967 TopologyNodesCount = Topology->TopologyNodes[NodeIndex].NodeConnectedFromCount;
968 }
969 else
970 {
971 /* get down stream nodes */
972 TopologyNodes = Topology->TopologyNodes[NodeIndex].NodeConnectedTo;
973 TopologyNodesCount = Topology->TopologyNodes[NodeIndex].NodeConnectedToCount;
974 }
975
976 /* store topology nodes ids */
977 for(Index = 0; Index < TopologyNodesCount; Index++)
978 {
979 OutNodes[Index] = TopologyNodes[Index]->NodeIndex;
980 }
981
982 /* store topology nodes count */
983 *OutNodesCount = TopologyNodesCount;
984 }
985
986 MIXER_STATUS
987 MMixerAllocateTopologyPinArray(
988 IN PMIXER_CONTEXT MixerContext,
989 IN PTOPOLOGY Topology,
990 OUT PULONG * OutPins)
991 {
992 PULONG Pins;
993 ULONG Index;
994
995 /* sanity check */
996 ASSERT(Topology->TopologyPinsCount != 0);
997
998 /* allocate topology pins */
999 Pins = MixerContext->Alloc(Topology->TopologyPinsCount * sizeof(ULONG));
1000
1001 if (!Pins)
1002 {
1003 /* out of memory */
1004 return MM_STATUS_NO_MEMORY;
1005 }
1006
1007 /* mark index as unused */
1008 for(Index = 0; Index < Topology->TopologyPinsCount; Index++)
1009 Pins[Index] = MAXULONG;
1010
1011 /* store result */
1012 *OutPins = Pins;
1013
1014 /* done */
1015 return MM_STATUS_SUCCESS;
1016 }
1017
1018 MIXER_STATUS
1019 MMixerAllocateTopologyNodeArray(
1020 IN PMIXER_CONTEXT MixerContext,
1021 IN PTOPOLOGY Topology,
1022 OUT PULONG * OutNodes)
1023 {
1024 PULONG Nodes;
1025 ULONG Index;
1026
1027 /* sanity check */
1028 ASSERT(Topology->TopologyNodesCount != 0);
1029
1030 /* allocate topology pins */
1031 Nodes = MixerContext->Alloc(Topology->TopologyNodesCount * sizeof(ULONG));
1032
1033 if (!Nodes)
1034 {
1035 /* out of memory */
1036 return MM_STATUS_NO_MEMORY;
1037 }
1038
1039 /* mark index as unused */
1040 for(Index = 0; Index < Topology->TopologyNodesCount; Index++)
1041 Nodes[Index] = MAXULONG;
1042
1043 /* store result */
1044 *OutNodes = Nodes;
1045
1046 /* done */
1047 return MM_STATUS_SUCCESS;
1048 }
1049
1050 VOID
1051 MMixerIsNodeTerminator(
1052 IN PTOPOLOGY Topology,
1053 IN ULONG NodeIndex,
1054 OUT ULONG * bTerminator)
1055 {
1056 /* sanity check */
1057 ASSERT(NodeIndex < Topology->TopologyNodesCount);
1058
1059 /* check if node has multiple parents */
1060 if (Topology->TopologyNodes[NodeIndex].NodeConnectedFromCount > 1)
1061 {
1062 /* node is connected to multiple other nodes */
1063 *bTerminator = TRUE;
1064
1065 /* done */
1066 return;
1067 }
1068
1069 /* check if node is mux / sum node */
1070 if (IsEqualGUIDAligned(&Topology->TopologyNodes[NodeIndex].NodeType, &KSNODETYPE_SUM) ||
1071 IsEqualGUIDAligned(&Topology->TopologyNodes[NodeIndex].NodeType, &KSNODETYPE_MUX))
1072 {
1073 /* classic terminator */
1074 *bTerminator = TRUE;
1075
1076 /* done */
1077 return;
1078
1079 }
1080
1081 /* node is not a terminator */
1082 *bTerminator = FALSE;
1083 }
1084
1085 MIXER_STATUS
1086 MMixerIsNodeConnectedToPin(
1087 IN PMIXER_CONTEXT MixerContext,
1088 IN PTOPOLOGY Topology,
1089 IN ULONG NodeIndex,
1090 IN ULONG PinId,
1091 IN ULONG bUpStream,
1092 OUT PULONG bConnected)
1093 {
1094 MIXER_STATUS Status;
1095 ULONG Index, PinsCount;
1096 PULONG Pins;
1097
1098 /* allocate pin index array */
1099 Status = MMixerAllocateTopologyPinArray(MixerContext, Topology, &Pins);
1100
1101 if (Status != MM_STATUS_SUCCESS)
1102 {
1103 /* failed to allocate */
1104 return Status;
1105 }
1106
1107 /* now get connected pins */
1108 PinsCount = 0;
1109 MMixerGetAllUpOrDownstreamPinsFromNodeIndex(MixerContext, Topology, NodeIndex, bUpStream, &PinsCount, Pins);
1110
1111 /* set to false */
1112 *bConnected = FALSE;
1113
1114 for(Index = 0; Index < PinsCount; Index++)
1115 {
1116 if (Pins[Index] == PinId)
1117 {
1118 /* pin is connected */
1119 *bConnected = TRUE;
1120 break;
1121 }
1122 }
1123
1124 /* free pin index array */
1125 MixerContext->Free(Pins);
1126
1127 /* done */
1128 return MM_STATUS_SUCCESS;
1129 }
1130
1131 LPGUID
1132 MMixerGetNodeTypeFromTopology(
1133 IN PTOPOLOGY Topology,
1134 IN ULONG NodeIndex)
1135 {
1136 /* sanity check */
1137 ASSERT(NodeIndex < Topology->TopologyNodesCount);
1138
1139 return &Topology->TopologyNodes[NodeIndex].NodeType;
1140 }
1141
1142 VOID
1143 MMixerSetTopologyNodeReserved(
1144 IN PTOPOLOGY Topology,
1145 IN ULONG NodeIndex)
1146 {
1147 /* sanity check */
1148 ASSERT(NodeIndex < Topology->TopologyNodesCount);
1149
1150 /* set reserved */
1151 Topology->TopologyNodes[NodeIndex].Reserved = TRUE;
1152 }
1153
1154 VOID
1155 MMixerIsTopologyNodeReserved(
1156 IN PTOPOLOGY Topology,
1157 IN ULONG NodeIndex,
1158 OUT PULONG bReserved)
1159 {
1160 /* sanity check */
1161 ASSERT(NodeIndex < Topology->TopologyNodesCount);
1162
1163 /* get reserved status */
1164 *bReserved = Topology->TopologyNodes[NodeIndex].Reserved;
1165 }
1166
1167
1168 MIXER_STATUS
1169 MMixerCreateTopology(
1170 IN PMIXER_CONTEXT MixerContext,
1171 IN ULONG PinCount,
1172 IN PKSMULTIPLE_ITEM NodeConnections,
1173 IN PKSMULTIPLE_ITEM NodeTypes,
1174 OUT PTOPOLOGY *OutTopology)
1175 {
1176 MIXER_STATUS Status;
1177 PTOPOLOGY Topology;
1178
1179 /* allocate topology */
1180 Status = MMixerAllocateTopology(MixerContext, NodeTypes->Count, PinCount, &Topology);
1181
1182 if (Status != MM_STATUS_SUCCESS)
1183 {
1184 /* failed to allocate topology */
1185 return Status;
1186 }
1187
1188 /* initialize topology nodes */
1189 MMixerInitializeTopologyNodes(MixerContext, NodeTypes, Topology);
1190
1191 /* explore topology */
1192 Status = MMixerExploreTopology(MixerContext, NodeConnections, NodeTypes, Topology);
1193
1194 if (Status != MM_STATUS_SUCCESS)
1195 {
1196 /* failed to allocate topology */
1197 return Status;
1198 }
1199
1200 MMixerPrintTopology(Topology);
1201
1202 /* store result */
1203 *OutTopology = Topology;
1204
1205 /* done */
1206 return MM_STATUS_SUCCESS;
1207 }
1208
1209
1210
1211
1212