mirror of
https://github.com/reactos/reactos.git
synced 2024-11-20 06:15:26 +00:00
ddb3d908c9
svn path=/branches/shell-experiments/; revision=62286
1291 lines
33 KiB
C
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;
|
|
}
|