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