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 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 43 MMixerAllocateTopology( 44 IN PMIXER_CONTEXT MixerContext, 45 IN ULONG NodesCount, 46 IN ULONG PinCount, 47 OUT PTOPOLOGY * OutTopology) 48 { 49 PTOPOLOGY Topology; 50 51 /* allocate topology */ 52 Topology = (PTOPOLOGY)MixerContext->Alloc(sizeof(TOPOLOGY)); 53 54 if (!Topology) 55 { 56 /* out of memory */ 57 return MM_STATUS_NO_MEMORY; 58 } 59 60 /* allocate topology pins */ 61 Topology->TopologyPins = (PPIN) MixerContext->Alloc(sizeof(PIN) * PinCount); 62 63 if (!Topology->TopologyPins) 64 { 65 /* release memory */ 66 MixerContext->Free(Topology); 67 68 /* out of memory */ 69 return MM_STATUS_NO_MEMORY; 70 } 71 72 /* allocate topology nodes */ 73 if (NodesCount) 74 { 75 Topology->TopologyNodes = (PTOPOLOGY_NODE) MixerContext->Alloc(sizeof(TOPOLOGY_NODE) * NodesCount); 76 77 if (!Topology->TopologyNodes) 78 { 79 /* release memory */ 80 MixerContext->Free(Topology->TopologyPins); 81 MixerContext->Free(Topology); 82 83 /* out of memory */ 84 return MM_STATUS_NO_MEMORY; 85 } 86 } 87 88 /* initialize topology */ 89 Topology->TopologyPinsCount = PinCount; 90 Topology->TopologyNodesCount = NodesCount; 91 92 /* store result */ 93 *OutTopology = Topology; 94 95 /* done */ 96 return MM_STATUS_SUCCESS; 97 } 98 99 VOID 100 MMixerResetTopologyVisitStatus( 101 IN OUT PTOPOLOGY Topology) 102 { 103 ULONG Index; 104 105 for(Index = 0; Index < Topology->TopologyNodesCount; Index++) 106 { 107 /* reset visited status */ 108 Topology->TopologyNodes[Index].Visited = FALSE; 109 } 110 111 for(Index = 0; Index < Topology->TopologyPinsCount; Index++) 112 { 113 /* reset visited status */ 114 Topology->TopologyPins[Index].Visited = FALSE; 115 } 116 } 117 118 VOID 119 MMixerInitializeTopologyNodes( 120 IN PMIXER_CONTEXT MixerContext, 121 IN PKSMULTIPLE_ITEM NodeTypes, 122 IN OUT PTOPOLOGY Topology) 123 { 124 ULONG Index; 125 LPGUID Guids; 126 127 /* sanity check */ 128 ASSERT(Topology->TopologyNodesCount == NodeTypes->Count); 129 130 /* get topology node types */ 131 Guids = (LPGUID)(NodeTypes + 1); 132 133 for(Index = 0; Index < Topology->TopologyNodesCount; Index++) 134 { 135 /* store node connection index */ 136 Topology->TopologyNodes[Index].NodeIndex = Index; 137 138 /* store topology node type */ 139 MixerContext->Copy(&Topology->TopologyNodes[Index].NodeType, &Guids[Index], sizeof(GUID)); 140 } 141 } 142 143 MIXER_STATUS 144 MMixerAddPinConnection( 145 IN PMIXER_CONTEXT MixerContext, 146 IN PPIN Pin, 147 IN PTOPOLOGY_NODE Node, 148 IN ULONG bPinToNode) 149 { 150 ULONG Count; 151 PULONG NewPinsIndex, OldPinsIndex; 152 PTOPOLOGY_NODE * NewNodes, *OldNodes; 153 154 if (bPinToNode) 155 { 156 /* get existing count */ 157 Count = Pin->NodesConnectedToCount; 158 OldNodes = Pin->NodesConnectedTo; 159 } 160 else 161 { 162 /* get existing count */ 163 Count = Pin->NodesConnectedFromCount; 164 OldNodes = Pin->NodesConnectedFrom; 165 } 166 167 /* allocate new nodes array */ 168 NewNodes = MixerContext->Alloc(sizeof(PTOPOLOGY_NODE) * (Count + 1)); 169 170 if (!NewNodes) 171 { 172 /* out of memory */ 173 return MM_STATUS_NO_MEMORY; 174 } 175 176 if (Count) 177 { 178 /* copy existing nodes */ 179 MixerContext->Copy(NewNodes, OldNodes, sizeof(PTOPOLOGY) * Count); 180 181 /* release old nodes array */ 182 MixerContext->Free(OldNodes); 183 } 184 185 /* add new topology node */ 186 NewNodes[Count] = Node; 187 188 if (bPinToNode) 189 { 190 /* replace old nodes array */ 191 Pin->NodesConnectedTo = NewNodes; 192 193 /* increment nodes count */ 194 Pin->NodesConnectedToCount++; 195 196 /* now enlarge PinConnectedFromCount*/ 197 Count = Node->PinConnectedFromCount; 198 199 /* connected pin count for node */ 200 OldPinsIndex = Node->PinConnectedFrom; 201 } 202 else 203 { 204 /* replace old nodes array */ 205 Pin->NodesConnectedFrom = NewNodes; 206 207 /* increment nodes count */ 208 Pin->NodesConnectedFromCount++; 209 210 /* now enlarge PinConnectedFromCount*/ 211 Count = Node->PinConnectedToCount; 212 213 /* connected pin count for node */ 214 OldPinsIndex = Node->PinConnectedTo; 215 } 216 217 /* allocate pin connection index */ 218 NewPinsIndex = MixerContext->Alloc(sizeof(ULONG) * (Count + 1)); 219 220 if (!NewPinsIndex) 221 { 222 /* out of memory */ 223 return MM_STATUS_NO_MEMORY; 224 } 225 226 if (Count) 227 { 228 /* copy existing nodes */ 229 MixerContext->Copy(NewPinsIndex, OldPinsIndex, sizeof(ULONG) * Count); 230 231 /* release old nodes array */ 232 MixerContext->Free(OldPinsIndex); 233 } 234 235 /* add new topology node */ 236 NewPinsIndex[Count] = Pin->PinId; 237 238 if (bPinToNode) 239 { 240 /* replace old nodes array */ 241 Node->PinConnectedFrom = NewPinsIndex; 242 243 /* increment pin count */ 244 Node->PinConnectedFromCount++; 245 } 246 else 247 { 248 /* replace old nodes array */ 249 Node->PinConnectedTo = NewPinsIndex; 250 251 /* increment pin count */ 252 Node->PinConnectedToCount++; 253 } 254 255 /* done */ 256 return MM_STATUS_SUCCESS; 257 } 258 259 MIXER_STATUS 260 MMixerHandleNodeToNodeConnection( 261 IN PMIXER_CONTEXT MixerContext, 262 IN PKSTOPOLOGY_CONNECTION Connection, 263 IN OUT PTOPOLOGY Topology) 264 { 265 PTOPOLOGY_NODE InNode, OutNode; 266 PTOPOLOGY_NODE * NewNodes; 267 PULONG NewLogicalPinNodeConnectedFrom; 268 ULONG Count; 269 ULONG LogicalPinId; 270 271 /* sanity checks */ 272 ASSERT(Topology->TopologyNodesCount > Connection->ToNode); 273 ASSERT(Topology->TopologyNodesCount > Connection->FromNode); 274 275 /* get node */ 276 InNode = &Topology->TopologyNodes[Connection->FromNode]; 277 OutNode = &Topology->TopologyNodes[Connection->ToNode]; 278 279 /* get logical pin node id */ 280 LogicalPinId = Connection->ToNodePin; 281 282 /* get existing count */ 283 Count = OutNode->NodeConnectedFromCount; 284 285 /* allocate new nodes array */ 286 NewNodes = MixerContext->Alloc(sizeof(PTOPOLOGY_NODE) * (Count + 1)); 287 288 if (!NewNodes) 289 { 290 /* out of memory */ 291 return MM_STATUS_NO_MEMORY; 292 } 293 294 /* allocate logical pin nodes array */ 295 NewLogicalPinNodeConnectedFrom = MixerContext->Alloc((Count + 1) * sizeof(ULONG)); 296 if (!NewLogicalPinNodeConnectedFrom) 297 { 298 /* out of memory */ 299 MixerContext->Free(NewNodes); 300 return MM_STATUS_NO_MEMORY; 301 } 302 303 if (Count) 304 { 305 /* copy existing nodes */ 306 MixerContext->Copy(NewNodes, OutNode->NodeConnectedFrom, sizeof(PTOPOLOGY) * Count); 307 308 /* copy existing logical pin node array */ 309 MixerContext->Copy(NewLogicalPinNodeConnectedFrom, OutNode->LogicalPinNodeConnectedFrom, sizeof(ULONG) * Count); 310 311 /* release old nodes array */ 312 MixerContext->Free(OutNode->NodeConnectedFrom); 313 314 /* release old logical pin node array */ 315 MixerContext->Free(OutNode->LogicalPinNodeConnectedFrom); 316 } 317 318 /* add new topology node */ 319 NewNodes[OutNode->NodeConnectedFromCount] = InNode; 320 321 /* add logical node id */ 322 NewLogicalPinNodeConnectedFrom[OutNode->NodeConnectedFromCount] = LogicalPinId; 323 324 /* replace old nodes array */ 325 OutNode->NodeConnectedFrom = NewNodes; 326 327 /* replace old logical pin node array */ 328 OutNode->LogicalPinNodeConnectedFrom = NewLogicalPinNodeConnectedFrom; 329 330 /* increment nodes count */ 331 OutNode->NodeConnectedFromCount++; 332 333 /* get existing count */ 334 Count = InNode->NodeConnectedToCount; 335 336 /* allocate new nodes array */ 337 NewNodes = MixerContext->Alloc(sizeof(PTOPOLOGY_NODE) * (Count + 1)); 338 339 if (!NewNodes) 340 { 341 /* out of memory */ 342 return MM_STATUS_NO_MEMORY; 343 } 344 345 if (Count) 346 { 347 /* copy existing nodes */ 348 MixerContext->Copy(NewNodes, InNode->NodeConnectedTo, sizeof(PTOPOLOGY) * Count); 349 350 /* release old nodes array */ 351 MixerContext->Free(InNode->NodeConnectedTo); 352 } 353 354 /* add new topology node */ 355 NewNodes[InNode->NodeConnectedToCount] = OutNode; 356 357 /* replace old nodes array */ 358 InNode->NodeConnectedTo = NewNodes; 359 360 /* increment nodes count */ 361 InNode->NodeConnectedToCount++; 362 363 /* done */ 364 return MM_STATUS_SUCCESS; 365 } 366 367 MIXER_STATUS 368 MMixerAddPinToPinConnection( 369 IN PMIXER_CONTEXT MixerContext, 370 IN OUT PPIN InPin, 371 IN OUT PPIN OutPin) 372 { 373 ULONG Count; 374 PULONG NewPinsIndex; 375 376 /* now enlarge PinConnectedTo */ 377 Count = InPin->PinConnectedToCount; 378 379 /* allocate pin connection index */ 380 NewPinsIndex = MixerContext->Alloc(sizeof(ULONG) * (Count + 1)); 381 382 if (!NewPinsIndex) 383 { 384 /* out of memory */ 385 return MM_STATUS_NO_MEMORY; 386 } 387 388 if (Count) 389 { 390 /* copy existing nodes */ 391 MixerContext->Copy(NewPinsIndex, InPin->PinConnectedTo, sizeof(ULONG) * Count); 392 393 /* release old nodes array */ 394 MixerContext->Free(InPin->PinConnectedTo); 395 } 396 397 /* add new topology node */ 398 NewPinsIndex[Count] = OutPin->PinId; 399 400 /* replace old nodes array */ 401 InPin->PinConnectedTo = NewPinsIndex; 402 403 /* increment pin count */ 404 InPin->PinConnectedToCount++; 405 406 /* now enlarge PinConnectedFrom */ 407 Count = OutPin->PinConnectedFromCount; 408 409 /* allocate pin connection index */ 410 NewPinsIndex = MixerContext->Alloc(sizeof(ULONG) * (Count + 1)); 411 412 if (!NewPinsIndex) 413 { 414 /* out of memory */ 415 return MM_STATUS_NO_MEMORY; 416 } 417 418 if (Count) 419 { 420 /* copy existing nodes */ 421 MixerContext->Copy(NewPinsIndex, OutPin->PinConnectedFrom, sizeof(ULONG) * Count); 422 423 /* release old nodes array */ 424 MixerContext->Free(OutPin->PinConnectedFrom); 425 } 426 427 /* add new topology node */ 428 NewPinsIndex[Count] = InPin->PinId; 429 430 /* replace old nodes array */ 431 OutPin->PinConnectedFrom = NewPinsIndex; 432 433 /* increment pin count */ 434 OutPin->PinConnectedFromCount++; 435 436 /* done */ 437 return MM_STATUS_SUCCESS; 438 } 439 440 MIXER_STATUS 441 MMixerHandleNodePinConnection( 442 IN PMIXER_CONTEXT MixerContext, 443 IN PKSTOPOLOGY_CONNECTION Connection, 444 IN OUT PTOPOLOGY Topology) 445 { 446 PPIN Pin; 447 PTOPOLOGY_NODE Node; 448 449 /* check type */ 450 if (Connection->FromNode == KSFILTER_NODE && 451 Connection->ToNode == KSFILTER_NODE) 452 { 453 /* Pin -> Pin direction */ 454 455 /* sanity checks */ 456 ASSERT(Topology->TopologyPinsCount > Connection->FromNodePin); 457 ASSERT(Topology->TopologyPinsCount > Connection->ToNodePin); 458 459 /* add connection */ 460 return MMixerAddPinToPinConnection(MixerContext, 461 &Topology->TopologyPins[Connection->FromNodePin], 462 &Topology->TopologyPins[Connection->ToNodePin]); 463 464 } 465 else if (Connection->FromNode == KSFILTER_NODE) 466 { 467 /* Pin -> Node direction */ 468 469 /* sanity checks */ 470 ASSERT(Topology->TopologyPinsCount > Connection->FromNodePin); 471 ASSERT(Topology->TopologyNodesCount > Connection->ToNode); 472 ASSERT(Connection->ToNode != KSFILTER_NODE); 473 474 /* get pin */ 475 Pin = &Topology->TopologyPins[Connection->FromNodePin]; 476 477 /* get node */ 478 Node = &Topology->TopologyNodes[Connection->ToNode]; 479 480 /* initialize pin */ 481 Pin->PinId = Connection->FromNodePin; 482 483 /* mark as visited */ 484 Pin->Visited = TRUE; 485 Node->Visited = TRUE; 486 487 /* add connection */ 488 return MMixerAddPinConnection(MixerContext, Pin, Node, TRUE); 489 } 490 else if (Connection->ToNode == KSFILTER_NODE) 491 { 492 /* Node -> Pin direction */ 493 494 /* sanity checks */ 495 ASSERT(Topology->TopologyPinsCount > Connection->ToNodePin); 496 ASSERT(Topology->TopologyNodesCount > Connection->FromNode); 497 ASSERT(Connection->FromNode != KSFILTER_NODE); 498 499 /* get pin */ 500 Pin = &Topology->TopologyPins[Connection->ToNodePin]; 501 502 /* get node */ 503 Node = &Topology->TopologyNodes[Connection->FromNode]; 504 505 /* initialize pin */ 506 Pin->PinId = Connection->ToNodePin; 507 508 /* mark as visited */ 509 Pin->Visited = TRUE; 510 Node->Visited = TRUE; 511 512 /* add connection */ 513 return MMixerAddPinConnection(MixerContext, Pin, Node, FALSE); 514 } 515 /* invalid call */ 516 ASSERT(0); 517 return MM_STATUS_INVALID_PARAMETER; 518 } 519 520 MIXER_STATUS 521 MMixerExploreTopology( 522 IN PMIXER_CONTEXT MixerContext, 523 IN PKSMULTIPLE_ITEM NodeConnections, 524 IN PKSMULTIPLE_ITEM NodeTypes, 525 IN OUT PTOPOLOGY Topology) 526 { 527 ULONG Index; 528 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 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 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 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 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 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 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 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 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 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 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 1004 MMixerGetTopologyPinCount( 1005 IN PTOPOLOGY Topology, 1006 OUT PULONG PinCount) 1007 { 1008 /* store pin count */ 1009 *PinCount = Topology->TopologyPinsCount; 1010 } 1011 1012 MIXER_STATUS 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 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 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 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 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 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 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 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 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 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 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