reactos/lib/drivers/sound/mmixer/topology.c
Amine Khaldi ddb3d908c9 * Sync up to trunk HEAD (r62285). Branch guys deserve the significant speedups too ;)
svn path=/branches/shell-experiments/; revision=62286
2014-02-22 10:31:26 +00:00

1291 lines
33 KiB
C

/*
* 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 YDEBUG
#include <debug.h>
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;
}