/* * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS Kernel Streaming * FILE: lib/drivers/sound/mmixer/topology.c * PURPOSE: Topology Handling Functions * PROGRAMMER: Johannes Anderwald */ #include "precomp.h" // #define NDEBUG #include VOID MMixerPrintTopology( PTOPOLOGY Topology) { ULONG Index, SubIndex; DPRINT("Num Pins %lu NumNodes %lu\n", Topology->TopologyPinsCount, Topology->TopologyNodesCount); for(Index = 0; Index < Topology->TopologyPinsCount; Index++) { DPRINT("PinId %lu NodesConnectedFromCount %lu NodesConnectedToCount %lu Visited %lu\n", Topology->TopologyPins[Index].PinId, Topology->TopologyPins[Index].NodesConnectedFromCount, Topology->TopologyPins[Index].NodesConnectedToCount, Topology->TopologyPins[Index].Visited); for(SubIndex = 0; SubIndex < Topology->TopologyPins[Index].NodesConnectedFromCount; SubIndex++) DPRINT("NodesConnectedFrom Index %lu NodeId %lu\n", SubIndex, Topology->TopologyPins[Index].NodesConnectedFrom[SubIndex]->NodeIndex); for(SubIndex = 0; SubIndex < Topology->TopologyPins[Index].NodesConnectedToCount; SubIndex++) DPRINT("NodesConnectedTo Index %lu NodeId %lu\n", SubIndex, Topology->TopologyPins[Index].NodesConnectedTo[SubIndex]->NodeIndex); } for(Index = 0; Index < Topology->TopologyNodesCount; Index++) { DPRINT("NodeId %lu NodesConnectedFromCount %lu NodesConnectedToCount %lu Visited %lu PinConnectedFromCount %lu PinConnectedToCount %lu\n", Topology->TopologyNodes[Index].NodeIndex, Topology->TopologyNodes[Index].NodeConnectedFromCount, Topology->TopologyNodes[Index].NodeConnectedToCount, Topology->TopologyNodes[Index].Visited, Topology->TopologyNodes[Index].PinConnectedFromCount, Topology->TopologyNodes[Index].PinConnectedToCount); } } MIXER_STATUS MMixerAllocateTopology( IN PMIXER_CONTEXT MixerContext, IN ULONG NodesCount, IN ULONG PinCount, OUT PTOPOLOGY * OutTopology) { PTOPOLOGY Topology; /* allocate topology */ Topology = (PTOPOLOGY)MixerContext->Alloc(sizeof(TOPOLOGY)); if (!Topology) { /* out of memory */ return MM_STATUS_NO_MEMORY; } /* allocate topology pins */ Topology->TopologyPins = (PPIN) MixerContext->Alloc(sizeof(PIN) * PinCount); if (!Topology->TopologyPins) { /* release memory */ MixerContext->Free(Topology); /* out of memory */ return MM_STATUS_NO_MEMORY; } /* allocate topology nodes */ if (NodesCount) { Topology->TopologyNodes = (PTOPOLOGY_NODE) MixerContext->Alloc(sizeof(TOPOLOGY_NODE) * NodesCount); if (!Topology->TopologyNodes) { /* release memory */ MixerContext->Free(Topology->TopologyPins); MixerContext->Free(Topology); /* out of memory */ return MM_STATUS_NO_MEMORY; } } /* initialize topology */ Topology->TopologyPinsCount = PinCount; Topology->TopologyNodesCount = NodesCount; /* store result */ *OutTopology = Topology; /* done */ return MM_STATUS_SUCCESS; } VOID MMixerResetTopologyVisitStatus( IN OUT PTOPOLOGY Topology) { ULONG Index; for(Index = 0; Index < Topology->TopologyNodesCount; Index++) { /* reset visited status */ Topology->TopologyNodes[Index].Visited = FALSE; } for(Index = 0; Index < Topology->TopologyPinsCount; Index++) { /* reset visited status */ Topology->TopologyPins[Index].Visited = FALSE; } } VOID MMixerInitializeTopologyNodes( IN PMIXER_CONTEXT MixerContext, IN PKSMULTIPLE_ITEM NodeTypes, IN OUT PTOPOLOGY Topology) { ULONG Index; LPGUID Guids; /* sanity check */ ASSERT(Topology->TopologyNodesCount == NodeTypes->Count); /* get topology node types */ Guids = (LPGUID)(NodeTypes + 1); for(Index = 0; Index < Topology->TopologyNodesCount; Index++) { /* store node connection index */ Topology->TopologyNodes[Index].NodeIndex = Index; /* store topology node type */ MixerContext->Copy(&Topology->TopologyNodes[Index].NodeType, &Guids[Index], sizeof(GUID)); } } MIXER_STATUS MMixerAddPinConnection( IN PMIXER_CONTEXT MixerContext, IN PPIN Pin, IN PTOPOLOGY_NODE Node, IN ULONG bPinToNode) { ULONG Count; PULONG NewPinsIndex, OldPinsIndex; PTOPOLOGY_NODE * NewNodes, *OldNodes; if (bPinToNode) { /* get existing count */ Count = Pin->NodesConnectedToCount; OldNodes = Pin->NodesConnectedTo; } else { /* get existing count */ Count = Pin->NodesConnectedFromCount; OldNodes = Pin->NodesConnectedFrom; } /* allocate new nodes array */ NewNodes = MixerContext->Alloc(sizeof(PTOPOLOGY_NODE) * (Count + 1)); if (!NewNodes) { /* out of memory */ return MM_STATUS_NO_MEMORY; } if (Count) { /* copy existing nodes */ MixerContext->Copy(NewNodes, OldNodes, sizeof(PTOPOLOGY) * Count); /* release old nodes array */ MixerContext->Free(OldNodes); } /* add new topology node */ NewNodes[Count] = Node; if (bPinToNode) { /* replace old nodes array */ Pin->NodesConnectedTo = NewNodes; /* increment nodes count */ Pin->NodesConnectedToCount++; /* now enlarge PinConnectedFromCount*/ Count = Node->PinConnectedFromCount; /* connected pin count for node */ OldPinsIndex = Node->PinConnectedFrom; } else { /* replace old nodes array */ Pin->NodesConnectedFrom = NewNodes; /* increment nodes count */ Pin->NodesConnectedFromCount++; /* now enlarge PinConnectedFromCount*/ Count = Node->PinConnectedToCount; /* connected pin count for node */ OldPinsIndex = Node->PinConnectedTo; } /* allocate pin connection index */ NewPinsIndex = MixerContext->Alloc(sizeof(ULONG) * (Count + 1)); if (!NewPinsIndex) { /* out of memory */ return MM_STATUS_NO_MEMORY; } if (Count) { /* copy existing nodes */ MixerContext->Copy(NewPinsIndex, OldPinsIndex, sizeof(ULONG) * Count); /* release old nodes array */ MixerContext->Free(OldPinsIndex); } /* add new topology node */ NewPinsIndex[Count] = Pin->PinId; if (bPinToNode) { /* replace old nodes array */ Node->PinConnectedFrom = NewPinsIndex; /* increment pin count */ Node->PinConnectedFromCount++; } else { /* replace old nodes array */ Node->PinConnectedTo = NewPinsIndex; /* increment pin count */ Node->PinConnectedToCount++; } /* done */ return MM_STATUS_SUCCESS; } MIXER_STATUS MMixerHandleNodeToNodeConnection( IN PMIXER_CONTEXT MixerContext, IN PKSTOPOLOGY_CONNECTION Connection, IN OUT PTOPOLOGY Topology) { PTOPOLOGY_NODE InNode, OutNode; PTOPOLOGY_NODE * NewNodes; PULONG NewLogicalPinNodeConnectedFrom; ULONG Count; ULONG LogicalPinId; /* sanity checks */ ASSERT(Topology->TopologyNodesCount > Connection->ToNode); ASSERT(Topology->TopologyNodesCount > Connection->FromNode); /* get node */ InNode = &Topology->TopologyNodes[Connection->FromNode]; OutNode = &Topology->TopologyNodes[Connection->ToNode]; /* get logical pin node id */ LogicalPinId = Connection->ToNodePin; /* get existing count */ Count = OutNode->NodeConnectedFromCount; /* allocate new nodes array */ NewNodes = MixerContext->Alloc(sizeof(PTOPOLOGY_NODE) * (Count + 1)); if (!NewNodes) { /* out of memory */ return MM_STATUS_NO_MEMORY; } /* allocate logical pin nodes array */ NewLogicalPinNodeConnectedFrom = MixerContext->Alloc((Count + 1) * sizeof(ULONG)); if (!NewLogicalPinNodeConnectedFrom) { /* out of memory */ MixerContext->Free(NewNodes); return MM_STATUS_NO_MEMORY; } if (Count) { /* copy existing nodes */ MixerContext->Copy(NewNodes, OutNode->NodeConnectedFrom, sizeof(PTOPOLOGY) * Count); /* copy existing logical pin node array */ MixerContext->Copy(NewLogicalPinNodeConnectedFrom, OutNode->LogicalPinNodeConnectedFrom, sizeof(ULONG) * Count); /* release old nodes array */ MixerContext->Free(OutNode->NodeConnectedFrom); /* release old logical pin node array */ MixerContext->Free(OutNode->LogicalPinNodeConnectedFrom); } /* add new topology node */ NewNodes[OutNode->NodeConnectedFromCount] = InNode; /* add logical node id */ NewLogicalPinNodeConnectedFrom[OutNode->NodeConnectedFromCount] = LogicalPinId; /* replace old nodes array */ OutNode->NodeConnectedFrom = NewNodes; /* replace old logical pin node array */ OutNode->LogicalPinNodeConnectedFrom = NewLogicalPinNodeConnectedFrom; /* increment nodes count */ OutNode->NodeConnectedFromCount++; /* get existing count */ Count = InNode->NodeConnectedToCount; /* allocate new nodes array */ NewNodes = MixerContext->Alloc(sizeof(PTOPOLOGY_NODE) * (Count + 1)); if (!NewNodes) { /* out of memory */ return MM_STATUS_NO_MEMORY; } if (Count) { /* copy existing nodes */ MixerContext->Copy(NewNodes, InNode->NodeConnectedTo, sizeof(PTOPOLOGY) * Count); /* release old nodes array */ MixerContext->Free(InNode->NodeConnectedTo); } /* add new topology node */ NewNodes[InNode->NodeConnectedToCount] = OutNode; /* replace old nodes array */ InNode->NodeConnectedTo = NewNodes; /* increment nodes count */ InNode->NodeConnectedToCount++; /* done */ return MM_STATUS_SUCCESS; } MIXER_STATUS MMixerAddPinToPinConnection( IN PMIXER_CONTEXT MixerContext, IN OUT PPIN InPin, IN OUT PPIN OutPin) { ULONG Count; PULONG NewPinsIndex; /* now enlarge PinConnectedTo */ Count = InPin->PinConnectedToCount; /* allocate pin connection index */ NewPinsIndex = MixerContext->Alloc(sizeof(ULONG) * (Count + 1)); if (!NewPinsIndex) { /* out of memory */ return MM_STATUS_NO_MEMORY; } if (Count) { /* copy existing nodes */ MixerContext->Copy(NewPinsIndex, InPin->PinConnectedTo, sizeof(ULONG) * Count); /* release old nodes array */ MixerContext->Free(InPin->PinConnectedTo); } /* add new topology node */ NewPinsIndex[Count] = OutPin->PinId; /* replace old nodes array */ InPin->PinConnectedTo = NewPinsIndex; /* increment pin count */ InPin->PinConnectedToCount++; /* now enlarge PinConnectedFrom */ Count = OutPin->PinConnectedFromCount; /* allocate pin connection index */ NewPinsIndex = MixerContext->Alloc(sizeof(ULONG) * (Count + 1)); if (!NewPinsIndex) { /* out of memory */ return MM_STATUS_NO_MEMORY; } if (Count) { /* copy existing nodes */ MixerContext->Copy(NewPinsIndex, OutPin->PinConnectedFrom, sizeof(ULONG) * Count); /* release old nodes array */ MixerContext->Free(OutPin->PinConnectedFrom); } /* add new topology node */ NewPinsIndex[Count] = InPin->PinId; /* replace old nodes array */ OutPin->PinConnectedFrom = NewPinsIndex; /* increment pin count */ OutPin->PinConnectedFromCount++; /* done */ return MM_STATUS_SUCCESS; } MIXER_STATUS MMixerHandleNodePinConnection( IN PMIXER_CONTEXT MixerContext, IN PKSTOPOLOGY_CONNECTION Connection, IN OUT PTOPOLOGY Topology) { PPIN Pin; PTOPOLOGY_NODE Node; /* check type */ if (Connection->FromNode == KSFILTER_NODE && Connection->ToNode == KSFILTER_NODE) { /* Pin -> Pin direction */ /* sanity checks */ ASSERT(Topology->TopologyPinsCount > Connection->FromNodePin); ASSERT(Topology->TopologyPinsCount > Connection->ToNodePin); /* add connection */ return MMixerAddPinToPinConnection(MixerContext, &Topology->TopologyPins[Connection->FromNodePin], &Topology->TopologyPins[Connection->ToNodePin]); } else if (Connection->FromNode == KSFILTER_NODE) { /* Pin -> Node direction */ /* sanity checks */ ASSERT(Topology->TopologyPinsCount > Connection->FromNodePin); ASSERT(Topology->TopologyNodesCount > Connection->ToNode); ASSERT(Connection->ToNode != KSFILTER_NODE); /* get pin */ Pin = &Topology->TopologyPins[Connection->FromNodePin]; /* get node */ Node = &Topology->TopologyNodes[Connection->ToNode]; /* initialize pin */ Pin->PinId = Connection->FromNodePin; /* mark as visited */ Pin->Visited = TRUE; Node->Visited = TRUE; /* add connection */ return MMixerAddPinConnection(MixerContext, Pin, Node, TRUE); } else if (Connection->ToNode == KSFILTER_NODE) { /* Node -> Pin direction */ /* sanity checks */ ASSERT(Topology->TopologyPinsCount > Connection->ToNodePin); ASSERT(Topology->TopologyNodesCount > Connection->FromNode); ASSERT(Connection->FromNode != KSFILTER_NODE); /* get pin */ Pin = &Topology->TopologyPins[Connection->ToNodePin]; /* get node */ Node = &Topology->TopologyNodes[Connection->FromNode]; /* initialize pin */ Pin->PinId = Connection->ToNodePin; /* mark as visited */ Pin->Visited = TRUE; Node->Visited = TRUE; /* add connection */ return MMixerAddPinConnection(MixerContext, Pin, Node, FALSE); } /* invalid call */ ASSERT(0); return MM_STATUS_INVALID_PARAMETER; } MIXER_STATUS MMixerExploreTopology( IN PMIXER_CONTEXT MixerContext, IN PKSMULTIPLE_ITEM NodeConnections, IN PKSMULTIPLE_ITEM NodeTypes, IN OUT PTOPOLOGY Topology) { ULONG Index; PKSTOPOLOGY_CONNECTION Connection; MIXER_STATUS Status; /* sanity check */ ASSERT(Topology->TopologyNodesCount == NodeTypes->Count); /* get node connections */ Connection = (PKSTOPOLOGY_CONNECTION)(NodeConnections + 1); for(Index = 0; Index < NodeConnections->Count; Index++) { if (Connection[Index].FromNode == KSFILTER_NODE || Connection[Index].ToNode == KSFILTER_NODE) { /* handle connection from Pin -> Node / Node->Pin */ Status = MMixerHandleNodePinConnection(MixerContext, &Connection[Index], Topology); } else { /* handle connection from Node -> Node */ Status = MMixerHandleNodeToNodeConnection(MixerContext, &Connection[Index], Topology); } if (Status != MM_STATUS_SUCCESS) { /* failed to handle connection */ return Status; } } /* done */ return MM_STATUS_SUCCESS; } VOID MMixerAddPinIndexToArray( IN PMIXER_CONTEXT MixerContext, IN ULONG PinId, IN ULONG MaxPins, OUT PULONG OutPinCount, OUT PULONG OutPins) { ULONG Index; for(Index = 0; Index < MaxPins; Index++) { if (OutPins[Index] != MAXULONG) { if (OutPins[Index] > PinId) { /* shift entries up */ MixerContext->Copy(&OutPins[Index + 1], &OutPins[Index], (MaxPins - (Index + 1)) * sizeof(ULONG)); /* store pin id */ OutPins[Index] = PinId; /* increment pin count */ (*OutPinCount)++; /* done */ return; } } else { /* store pin id */ OutPins[Index] = PinId; /* increment pin count */ (*OutPinCount)++; /* done */ return; } } } VOID MMixerGetUpOrDownStreamPins( IN PMIXER_CONTEXT MixerContext, IN PTOPOLOGY Topology, IN PTOPOLOGY_NODE TopologyNode, IN ULONG bUpStream, OUT PULONG OutPinCount, OUT PULONG OutPins) { ULONG Index, TopologyNodesCount, PinsCount; PTOPOLOGY_NODE *TopologyNodes; PULONG Pins; PPIN Pin; /* sanity check */ ASSERT(TopologyNode->Visited == FALSE); if (bUpStream) { /* use pins to which a node is attached to */ PinsCount = TopologyNode->PinConnectedFromCount; Pins = TopologyNode->PinConnectedFrom; TopologyNodesCount = TopologyNode->NodeConnectedFromCount; TopologyNodes = TopologyNode->NodeConnectedFrom; } else { /* use pins which are attached to a node */ PinsCount = TopologyNode->PinConnectedToCount; Pins = TopologyNode->PinConnectedTo; TopologyNodesCount = TopologyNode->NodeConnectedToCount; TopologyNodes = TopologyNode->NodeConnectedTo; } /* add all diretly connected pins */ for(Index = 0; Index < PinsCount; Index++) { /* sanity check */ ASSERT(Pins[Index] < Topology->TopologyPinsCount); /* get pin */ Pin = &Topology->TopologyPins[Pins[Index]]; /* pin should not have been visited */ ASSERT(Pin->Visited == FALSE); ASSERT(Pins[Index] == Pin->PinId); /* FIXME support Pin -> Pin connections in iteration */ if (bUpStream) { /* indicates a very broken topology Pin -> Pin -> Node <-... */ ASSERT(Pin->PinConnectedFromCount == 0); } else { /* indicates a very broken topology -> Node -> Pin -> Pin */ ASSERT(Pin->PinConnectedToCount == 0); } /* add them to pin array */ MMixerAddPinIndexToArray(MixerContext, Pin->PinId, Topology->TopologyPinsCount, OutPinCount, OutPins); /* mark pin as visited */ Pin->Visited = TRUE; } /* mark node as visited */ TopologyNode->Visited = TRUE; /* now visit all connected nodes */ for(Index = 0; Index < TopologyNodesCount; Index++) { /* recursively visit them */ MMixerGetUpOrDownStreamPins(MixerContext, Topology, TopologyNodes[Index], bUpStream, OutPinCount, OutPins); } } ULONG MMixerGetNodeIndexFromGuid( IN PTOPOLOGY Topology, IN const GUID * NodeType) { ULONG Index; for(Index = 0; Index < Topology->TopologyNodesCount; Index++) { if (IsEqualGUIDAligned(NodeType, &Topology->TopologyNodes[Index].NodeType)) { return Index; } } return MAXULONG; } VOID MMixerGetAllUpOrDownstreamPinsFromNodeIndex( IN PMIXER_CONTEXT MixerContext, IN PTOPOLOGY Topology, IN ULONG NodeIndex, IN ULONG bUpStream, OUT PULONG OutPinsCount, OUT PULONG OutPins) { PTOPOLOGY_NODE TopologyNode; /* reset visited status */ MMixerResetTopologyVisitStatus(Topology); /* sanity check */ ASSERT(Topology->TopologyNodesCount > NodeIndex); /* get topology node */ TopologyNode = &Topology->TopologyNodes[NodeIndex]; /* now visit all upstream pins & nodes */ MMixerGetUpOrDownStreamPins(MixerContext, Topology, TopologyNode, bUpStream, OutPinsCount, OutPins); } VOID MMixerGetUpOrDownstreamNodes( IN PMIXER_CONTEXT MixerContext, IN PTOPOLOGY Topology, IN PTOPOLOGY_NODE TopologyNode, IN ULONG bUpStream, OUT PULONG OutNodeCount, OUT PULONG OutNodes) { ULONG Index, TopologyNodesCount; PTOPOLOGY_NODE Node, *TopologyNodes; if (bUpStream) { /* use nodes to which a node is attached to */ TopologyNodesCount = TopologyNode->NodeConnectedFromCount; TopologyNodes = TopologyNode->NodeConnectedFrom; } else { /* use nodes which are attached to a node */ TopologyNodesCount = TopologyNode->NodeConnectedToCount; TopologyNodes = TopologyNode->NodeConnectedTo; } /* sanity check */ ASSERT(TopologyNode->Visited == FALSE); /* add all connected nodes */ for(Index = 0; Index < TopologyNodesCount; Index++) { /* get node */ Node = TopologyNodes[Index]; /* node should not have been visited */ ASSERT(Node->Visited == FALSE); /* mark node as visited */ TopologyNode->Visited = TRUE; /* add them to node array */ MMixerAddPinIndexToArray(MixerContext, Node->NodeIndex, Topology->TopologyNodesCount, OutNodeCount, OutNodes); /* recursively visit them */ MMixerGetUpOrDownstreamNodes(MixerContext, Topology, TopologyNodes[Index], bUpStream, OutNodeCount, OutNodes); } } MIXER_STATUS MMixerGetAllUpOrDownstreamNodesFromNodeIndex( IN PMIXER_CONTEXT MixerContext, IN PTOPOLOGY Topology, IN ULONG NodeIndex, IN ULONG bUpStream, OUT PULONG OutNodesCount, OUT PULONG OutNodes) { PTOPOLOGY_NODE TopologyNode; /* reset visited status */ MMixerResetTopologyVisitStatus(Topology); /* sanity check */ ASSERT(Topology->TopologyNodesCount > NodeIndex); /* get topology node */ TopologyNode = &Topology->TopologyNodes[NodeIndex]; /* now visit all upstream pins & nodes */ MMixerGetUpOrDownstreamNodes(MixerContext, Topology, TopologyNode, bUpStream, OutNodesCount, OutNodes); /* done */ return MM_STATUS_SUCCESS; } MIXER_STATUS MMixerGetAllUpOrDownstreamPinsFromPinIndex( IN PMIXER_CONTEXT MixerContext, IN PTOPOLOGY Topology, IN ULONG PinIndex, IN ULONG bUpStream, OUT PULONG OutPinsCount, OUT PULONG OutPins) { ULONG Index, TopologyNodesCount, TopologyPinsCount; PPIN Pin; PTOPOLOGY_NODE *TopologyNodes; PULONG TopologyPins; /* get pin */ Pin = &Topology->TopologyPins[PinIndex]; if (bUpStream) { /* use nodes to which this pin is attached to */ TopologyNodes = Pin->NodesConnectedFrom; TopologyNodesCount = Pin->NodesConnectedFromCount; /* use pins to which this pin is attached to */ TopologyPins = Pin->PinConnectedFrom; TopologyPinsCount = Pin->PinConnectedFromCount; } else { /* use nodes which are attached to a pin */ TopologyNodes = Pin->NodesConnectedTo; TopologyNodesCount = Pin->NodesConnectedToCount; /* use pins which are attached to this pin */ TopologyPins = Pin->PinConnectedTo; TopologyPinsCount = Pin->PinConnectedToCount; } /* reset visited status */ MMixerResetTopologyVisitStatus(Topology); /* sanity check */ ASSERT(Topology->TopologyPinsCount > PinIndex); /* add pins which are directly connected to this pin */ for(Index = 0; Index < TopologyPinsCount; Index++) { /* add them to pin array */ MMixerAddPinIndexToArray(MixerContext, TopologyPins[Index], Topology->TopologyPinsCount, OutPinsCount, OutPins); } /* now visit all up / down stream pins & nodes */ for(Index = 0; Index < TopologyNodesCount; Index++) { /* explore all connected pins with helper */ MMixerGetAllUpOrDownstreamPinsFromNodeIndex(MixerContext, Topology, TopologyNodes[Index]->NodeIndex, bUpStream, OutPinsCount, OutPins); } /* done */ return MM_STATUS_SUCCESS; } VOID MMixerGetAllUpOrDownstreamNodesFromPinIndex( IN PMIXER_CONTEXT MixerContext, IN PTOPOLOGY Topology, IN ULONG PinIndex, IN ULONG bUpStream, OUT PULONG OutNodesCount, OUT PULONG OutNodes) { ULONG Index, TopologyNodesCount; PPIN Pin; PTOPOLOGY_NODE *TopologyNodes; /* mark them as empty */ *OutNodesCount = 0; /* get pin */ Pin = &Topology->TopologyPins[PinIndex]; if (bUpStream) { /* use nodes to which a pin is attached to */ TopologyNodes = Pin->NodesConnectedFrom; TopologyNodesCount = Pin->NodesConnectedFromCount; } else { /* use nodes which are attached to a node */ TopologyNodes = Pin->NodesConnectedTo; TopologyNodesCount = Pin->NodesConnectedToCount; } /* reset visited status */ MMixerResetTopologyVisitStatus(Topology); /* sanity check */ ASSERT(Topology->TopologyPinsCount > PinIndex); /* now visit all up / down stream pins & nodes */ for(Index = 0; Index < TopologyNodesCount; Index++) { /* add node to array */ MMixerAddPinIndexToArray(MixerContext, TopologyNodes[Index]->NodeIndex, Topology->TopologyNodesCount, OutNodesCount, OutNodes); /* explore all connected nodes with helper */ MMixerGetAllUpOrDownstreamNodesFromNodeIndex(MixerContext, Topology, TopologyNodes[Index]->NodeIndex, bUpStream, OutNodesCount, OutNodes); } } VOID MMixerGetNextNodesFromPinIndex( IN PMIXER_CONTEXT MixerContext, IN PTOPOLOGY Topology, IN ULONG PinIndex, IN ULONG bUpStream, OUT PULONG OutNodesCount, OUT PULONG OutNodes) { PPIN Pin; TOPOLOGY_NODE **TopologyNodes; ULONG TopologyNodesCount; ULONG Index; /* sanity check */ ASSERT(PinIndex < Topology->TopologyPinsCount); /* get pin */ Pin = &Topology->TopologyPins[PinIndex]; if (bUpStream) { /* get up stream nodes */ TopologyNodes = Pin->NodesConnectedFrom; TopologyNodesCount = Pin->NodesConnectedFromCount; } else { /* get down stream nodes */ TopologyNodes = Pin->NodesConnectedTo; TopologyNodesCount = Pin->NodesConnectedToCount; } /* store topology nodes ids */ for(Index = 0; Index < TopologyNodesCount; Index++) { OutNodes[Index] = TopologyNodes[Index]->NodeIndex; } /* store topology nodes count */ *OutNodesCount = TopologyNodesCount; } VOID MMixerGetNextNodesFromNodeIndex( IN PMIXER_CONTEXT MixerContext, IN PTOPOLOGY Topology, IN ULONG NodeIndex, IN ULONG bUpStream, OUT PULONG OutNodesCount, OUT PULONG OutNodes) { TOPOLOGY_NODE **TopologyNodes; ULONG TopologyNodesCount; ULONG Index; /* sanity check */ ASSERT(NodeIndex < Topology->TopologyNodesCount); if (bUpStream) { /* get up stream nodes */ TopologyNodes = Topology->TopologyNodes[NodeIndex].NodeConnectedFrom; TopologyNodesCount = Topology->TopologyNodes[NodeIndex].NodeConnectedFromCount; } else { /* get down stream nodes */ TopologyNodes = Topology->TopologyNodes[NodeIndex].NodeConnectedTo; TopologyNodesCount = Topology->TopologyNodes[NodeIndex].NodeConnectedToCount; } /* store topology nodes ids */ for(Index = 0; Index < TopologyNodesCount; Index++) { OutNodes[Index] = TopologyNodes[Index]->NodeIndex; } /* store topology nodes count */ *OutNodesCount = TopologyNodesCount; } VOID MMixerGetTopologyPinCount( IN PTOPOLOGY Topology, OUT PULONG PinCount) { /* store pin count */ *PinCount = Topology->TopologyPinsCount; } MIXER_STATUS MMixerAllocateTopologyPinArray( IN PMIXER_CONTEXT MixerContext, IN PTOPOLOGY Topology, OUT PULONG * OutPins) { PULONG Pins; ULONG Index; /* sanity check */ ASSERT(Topology->TopologyPinsCount != 0); /* allocate topology pins */ Pins = MixerContext->Alloc(Topology->TopologyPinsCount * sizeof(ULONG)); if (!Pins) { /* out of memory */ return MM_STATUS_NO_MEMORY; } /* mark index as unused */ for(Index = 0; Index < Topology->TopologyPinsCount; Index++) Pins[Index] = MAXULONG; /* store result */ *OutPins = Pins; /* done */ return MM_STATUS_SUCCESS; } MIXER_STATUS MMixerAllocateTopologyNodeArray( IN PMIXER_CONTEXT MixerContext, IN PTOPOLOGY Topology, OUT PULONG * OutNodes) { PULONG Nodes; ULONG Index; /* sanity check */ ASSERT(Topology->TopologyNodesCount != 0); /* allocate topology pins */ Nodes = MixerContext->Alloc(Topology->TopologyNodesCount * sizeof(ULONG)); if (!Nodes) { /* out of memory */ return MM_STATUS_NO_MEMORY; } /* mark index as unused */ for(Index = 0; Index < Topology->TopologyNodesCount; Index++) Nodes[Index] = MAXULONG; /* store result */ *OutNodes = Nodes; /* done */ return MM_STATUS_SUCCESS; } VOID MMixerIsNodeTerminator( IN PTOPOLOGY Topology, IN ULONG NodeIndex, OUT ULONG * bTerminator) { /* sanity check */ ASSERT(NodeIndex < Topology->TopologyNodesCount); /* check if node has multiple parents */ if (Topology->TopologyNodes[NodeIndex].NodeConnectedFromCount > 1) { /* node is connected to multiple other nodes */ *bTerminator = TRUE; /* done */ return; } /* check if node is mux / sum node */ if (IsEqualGUIDAligned(&Topology->TopologyNodes[NodeIndex].NodeType, &KSNODETYPE_SUM) || IsEqualGUIDAligned(&Topology->TopologyNodes[NodeIndex].NodeType, &KSNODETYPE_MUX)) { /* classic terminator */ *bTerminator = TRUE; /* done */ return; } /* node is not a terminator */ *bTerminator = FALSE; } MIXER_STATUS MMixerIsNodeConnectedToPin( IN PMIXER_CONTEXT MixerContext, IN PTOPOLOGY Topology, IN ULONG NodeIndex, IN ULONG PinId, IN ULONG bUpStream, OUT PULONG bConnected) { MIXER_STATUS Status; ULONG Index, PinsCount; PULONG Pins; /* allocate pin index array */ Status = MMixerAllocateTopologyPinArray(MixerContext, Topology, &Pins); if (Status != MM_STATUS_SUCCESS) { /* failed to allocate */ return Status; } /* now get connected pins */ PinsCount = 0; MMixerGetAllUpOrDownstreamPinsFromNodeIndex(MixerContext, Topology, NodeIndex, bUpStream, &PinsCount, Pins); /* set to false */ *bConnected = FALSE; for(Index = 0; Index < PinsCount; Index++) { if (Pins[Index] == PinId) { /* pin is connected */ *bConnected = TRUE; break; } } /* free pin index array */ MixerContext->Free(Pins); /* done */ return MM_STATUS_SUCCESS; } VOID MMixerGetConnectedFromLogicalTopologyPins( IN PTOPOLOGY Topology, IN ULONG NodeIndex, OUT PULONG OutPinCount, OUT PULONG OutPins) { ULONG Index; PTOPOLOGY_NODE Node; /* sanity check */ ASSERT(NodeIndex < Topology->TopologyNodesCount); /* get node */ Node = &Topology->TopologyNodes[NodeIndex]; for(Index = 0; Index < Node->NodeConnectedFromCount; Index++) { /* copy logical pin id */ OutPins[Index] = Node->LogicalPinNodeConnectedFrom[Index]; } /* store pin count */ *OutPinCount = Node->NodeConnectedFromCount; } LPGUID MMixerGetNodeTypeFromTopology( IN PTOPOLOGY Topology, IN ULONG NodeIndex) { /* sanity check */ ASSERT(NodeIndex < Topology->TopologyNodesCount); return &Topology->TopologyNodes[NodeIndex].NodeType; } VOID MMixerSetTopologyPinReserved( IN PTOPOLOGY Topology, IN ULONG PinId) { /* sanity check */ ASSERT(PinId < Topology->TopologyPinsCount); /* set reserved */ Topology->TopologyPins[PinId].Reserved = TRUE; } VOID MMixerIsTopologyPinReserved( IN PTOPOLOGY Topology, IN ULONG PinId, OUT PULONG bReserved) { /* sanity check */ ASSERT(PinId < Topology->TopologyPinsCount); /* get reserved status */ *bReserved = Topology->TopologyPins[PinId].Reserved; } VOID MMixerSetTopologyNodeReserved( IN PTOPOLOGY Topology, IN ULONG NodeIndex) { /* sanity check */ ASSERT(NodeIndex < Topology->TopologyNodesCount); /* set reserved */ Topology->TopologyNodes[NodeIndex].Reserved = TRUE; } VOID MMixerIsTopologyNodeReserved( IN PTOPOLOGY Topology, IN ULONG NodeIndex, OUT PULONG bReserved) { /* sanity check */ ASSERT(NodeIndex < Topology->TopologyNodesCount); /* get reserved status */ *bReserved = Topology->TopologyNodes[NodeIndex].Reserved; } MIXER_STATUS MMixerCreateTopology( IN PMIXER_CONTEXT MixerContext, IN ULONG PinCount, IN PKSMULTIPLE_ITEM NodeConnections, IN PKSMULTIPLE_ITEM NodeTypes, OUT PTOPOLOGY *OutTopology) { MIXER_STATUS Status; PTOPOLOGY Topology; /* allocate topology */ Status = MMixerAllocateTopology(MixerContext, NodeTypes->Count, PinCount, &Topology); if (Status != MM_STATUS_SUCCESS) { /* failed to allocate topology */ return Status; } /* initialize topology nodes */ MMixerInitializeTopologyNodes(MixerContext, NodeTypes, Topology); /* explore topology */ Status = MMixerExploreTopology(MixerContext, NodeConnections, NodeTypes, Topology); if (Status != MM_STATUS_SUCCESS) { /* failed to allocate topology */ return Status; } MMixerPrintTopology(Topology); /* store result */ *OutTopology = Topology; /* done */ return MM_STATUS_SUCCESS; }