[MMIXER]
authorJohannes Anderwald <johannes.anderwald@reactos.org>
Fri, 15 Oct 2010 00:20:15 +0000 (00:20 +0000)
committerJohannes Anderwald <johannes.anderwald@reactos.org>
Fri, 15 Oct 2010 00:20:15 +0000 (00:20 +0000)
- Rewrite topology node enumeration algorithm
- Old algorithm didnt properly take in account sum/mux nodes, may assign nodes to multiple lines and was not able to detect circuits which may lead to infinite loops
- New algorithm properly partitions the nodes and also checks if nodes has already been assigned. As a plus, it is also faster
- Algorithm based on msdn http://msdn.microsoft.com/en-us/library/ff538873(v=VS.85).aspx
- Tested on VBox 3.28 (AC97)
- Please retest supported soundcards for regressions

svn path=/trunk/; revision=49150

reactos/lib/drivers/sound/mmixer/controls.c
reactos/lib/drivers/sound/mmixer/filter.c
reactos/lib/drivers/sound/mmixer/mixer.c
reactos/lib/drivers/sound/mmixer/mmixer.rbuild
reactos/lib/drivers/sound/mmixer/priv.h
reactos/lib/drivers/sound/mmixer/sup.c
reactos/lib/drivers/sound/mmixer/topology.c [new file with mode: 0644]
reactos/lib/drivers/sound/mmixer/wave.c

index 5b0ac71..543fb1e 100644 (file)
  
 #include "priv.h"
 
-MIXER_STATUS
-MMixerGetTargetPinsByNodeConnectionIndex(
-    IN PMIXER_CONTEXT MixerContext,
-    IN PKSMULTIPLE_ITEM NodeConnections,
-    IN PKSMULTIPLE_ITEM NodeTypes,
-    IN ULONG bUpDirection,
-    IN ULONG NodeConnectionIndex,
-    IN ULONG PinCount,
-    OUT PULONG Pins)
-{
-    PKSTOPOLOGY_CONNECTION Connection;
-    ULONG PinId, NodeConnectionCount, Index;
-    PULONG NodeConnection;
-    MIXER_STATUS Status;
-
-
-    /* sanity check */
-    ASSERT(NodeConnectionIndex < NodeConnections->Count);
-
-    Connection = (PKSTOPOLOGY_CONNECTION)(NodeConnections + 1);
-
-    //DPRINT("FromNode %u FromNodePin %u -> ToNode %u ToNodePin %u\n", Connection[NodeConnectionIndex].FromNode, Connection[NodeConnectionIndex].FromNodePin, Connection[NodeConnectionIndex].ToNode, Connection[NodeConnectionIndex].ToNodePin );
-
-    if ((Connection[NodeConnectionIndex].ToNode == KSFILTER_NODE && bUpDirection == FALSE) ||
-        (Connection[NodeConnectionIndex].FromNode == KSFILTER_NODE && bUpDirection == TRUE))
-    {
-        /* iteration stops here */
-       if (bUpDirection)
-           PinId = Connection[NodeConnectionIndex].FromNodePin;
-       else
-           PinId = Connection[NodeConnectionIndex].ToNodePin;
-
-       //DPRINT("GetTargetPinsByNodeIndex FOUND Target Pin %u Parsed %u\n", PinId, Pins[PinId]);
-
-       // sanity check
-       ASSERT(PinId < PinCount);
-
-       /* mark pin index as a target pin */
-       Pins[PinId] = TRUE;
-       return MM_STATUS_SUCCESS;
-    }
-
-    // get all node indexes referenced by that node
-    if (bUpDirection)
-    {
-        Status = MMixerGetNodeIndexes(MixerContext, NodeConnections, Connection[NodeConnectionIndex].FromNode, TRUE, FALSE, &NodeConnectionCount, &NodeConnection);
-    }
-    else
-    {
-        Status = MMixerGetNodeIndexes(MixerContext, NodeConnections, Connection[NodeConnectionIndex].ToNode, TRUE, TRUE, &NodeConnectionCount, &NodeConnection);
-    }
-
-    if (Status == MM_STATUS_SUCCESS)
-    {
-        for(Index = 0; Index < NodeConnectionCount; Index++)
-        {
-            // iterate recursively into the nodes
-            Status = MMixerGetTargetPinsByNodeConnectionIndex(MixerContext, NodeConnections, NodeTypes, bUpDirection, NodeConnection[Index], PinCount, Pins);
-            ASSERT(Status == MM_STATUS_SUCCESS);
-        }
-        // free node connection indexes
-        MixerContext->Free(NodeConnection);
-    }
-
-    return Status;
-}
-
-MIXER_STATUS
-MMixerGetControlsFromPinByConnectionIndex(
-    IN PMIXER_CONTEXT MixerContext,
-    IN PKSMULTIPLE_ITEM NodeConnections,
-    IN PKSMULTIPLE_ITEM NodeTypes,
-    IN ULONG bUpDirection,
-    IN ULONG NodeConnectionIndex,
-    OUT PULONG Nodes)
-{
-    PKSTOPOLOGY_CONNECTION CurConnection;
-    LPGUID NodeType;
-    ULONG NodeIndex;
-    MIXER_STATUS Status;
-    ULONG NodeConnectionCount, Index;
-    PULONG NodeConnection;
-
-
-    /* get current connection */
-    CurConnection = MMixerGetConnectionByIndex(NodeConnections, NodeConnectionIndex);
-
-    if (bUpDirection)
-        NodeIndex = CurConnection->FromNode;
-    else
-        NodeIndex = CurConnection->ToNode;
-
-    if (NodeIndex > NodeTypes->Count)
-    {
-        // reached end of pin connection
-        return MM_STATUS_SUCCESS;
-    }
-
-    /* get target node type of current connection */
-    NodeType = MMixerGetNodeType(NodeTypes, NodeIndex);
-
-    if (IsEqualGUIDAligned(NodeType, &KSNODETYPE_SUM) || IsEqualGUIDAligned(NodeType, &KSNODETYPE_MUX))
-    {
-        if (bUpDirection)
-        {
-            /* add the sum / mux node to destination line */
-            Nodes[NodeIndex] = TRUE;
-        }
-
-        return MM_STATUS_SUCCESS;
-    }
-
-    /* now add the node */
-    Nodes[NodeIndex] = TRUE;
-
-
-    /* get all node indexes referenced by that node */
-    if (bUpDirection)
-    {
-        Status = MMixerGetNodeIndexes(MixerContext, NodeConnections, NodeIndex, TRUE, FALSE, &NodeConnectionCount, &NodeConnection);
-    }
-    else
-    {
-        Status = MMixerGetNodeIndexes(MixerContext, NodeConnections, NodeIndex, TRUE, TRUE, &NodeConnectionCount, &NodeConnection);
-    }
-
-    if (Status == MM_STATUS_SUCCESS)
-    {
-        for(Index = 0; Index < NodeConnectionCount; Index++)
-        {
-            /* iterate recursively into the nodes */
-            Status = MMixerGetControlsFromPinByConnectionIndex(MixerContext, NodeConnections, NodeTypes, bUpDirection, NodeConnection[Index], Nodes);
-            ASSERT(Status == MM_STATUS_SUCCESS);
-        }
-        /* free node connection indexes */
-        MixerContext->Free(NodeConnection);
-    }
-
-    return Status;
-}
-
 MIXER_STATUS
 MMixerAddMixerControl(
     IN PMIXER_CONTEXT MixerContext,
     IN LPMIXER_INFO MixerInfo,
-    IN HANDLE hDevice,
-    IN PKSMULTIPLE_ITEM NodeTypes,
+    IN PTOPOLOGY Topology,
     IN ULONG NodeIndex,
     IN LPMIXERLINE_EXT MixerLine,
     OUT LPMIXERCONTROLW MixerControl)
@@ -170,12 +28,12 @@ MMixerAddMixerControl(
     MixerControl->dwControlID = MixerInfo->ControlId;
 
     /* get node type */
-    NodeType = MMixerGetNodeType(NodeTypes, NodeIndex);
+    NodeType = MMixerGetNodeTypeFromTopology(Topology, NodeIndex);
     /* store control type */
     MixerControl->dwControlType = MMixerGetControlTypeFromTopologyNode(NodeType);
 
-    MixerControl->fdwControl = MIXERCONTROL_CONTROLF_UNIFORM; //FIXME
-    MixerControl->cMultipleItems = 0; //FIXME
+    MixerControl->fdwControl = MIXERCONTROL_CONTROLF_UNIFORM; /* FIXME */
+    MixerControl->cMultipleItems = 0; /* FIXME */
 
     if (MixerControl->dwControlType == MIXERCONTROL_CONTROLTYPE_MUTE)
     {
@@ -186,7 +44,7 @@ MMixerAddMixerControl(
     {
         MixerControl->Bounds.dwMinimum = 0;
         MixerControl->Bounds.dwMaximum = 0xFFFF;
-        MixerControl->Metrics.cSteps = 0xC0; //FIXME
+        MixerControl->Metrics.cSteps = 0xC0; /* FIXME */
     }
 
     /* setup request to retrieve name */
@@ -197,7 +55,7 @@ MMixerAddMixerControl(
     Node.Reserved = 0;
 
     /* get node name size */
-    Status = MixerContext->Control(hDevice, IOCTL_KS_PROPERTY, (PVOID)&Node, sizeof(KSP_NODE), NULL, 0, &BytesReturned);
+    Status = MixerContext->Control(MixerInfo->hMixer, IOCTL_KS_PROPERTY, (PVOID)&Node, sizeof(KSP_NODE), NULL, 0, &BytesReturned);
 
     if (Status == MM_STATUS_MORE_ENTRIES)
     {
@@ -210,7 +68,7 @@ MMixerAddMixerControl(
         }
 
         /* get node name */
-        Status = MixerContext->Control(hDevice, IOCTL_KS_PROPERTY, (PVOID)&Node, sizeof(KSP_NODE), (LPVOID)Name, BytesReturned, &BytesReturned);
+        Status = MixerContext->Control(MixerInfo->hMixer, IOCTL_KS_PROPERTY, (PVOID)&Node, sizeof(KSP_NODE), (LPVOID)Name, BytesReturned, &BytesReturned);
 
         if (Status == MM_STATUS_SUCCESS)
         {
@@ -268,7 +126,7 @@ MMixerAddMixerControl(
         Property.NodeProperty.Property.Set = KSPROPSETID_Audio;
 
         /* get node volume level info */
-        Status = MixerContext->Control(hDevice, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSNODEPROPERTY_AUDIO_CHANNEL), Desc, Length, &BytesReturned);
+        Status = MixerContext->Control(MixerInfo->hMixer, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSNODEPROPERTY_AUDIO_CHANNEL), Desc, Length, &BytesReturned);
 
         if (Status == MM_STATUS_SUCCESS)
         {
@@ -325,495 +183,693 @@ MMixerAddMixerControl(
 }
 
 MIXER_STATUS
-MMixerAddMixerSourceLine(
+MMixerCreateDestinationLine(
     IN PMIXER_CONTEXT MixerContext,
-    IN OUT LPMIXER_INFO MixerInfo,
-    IN HANDLE hDevice,
-    IN PKSMULTIPLE_ITEM NodeConnections,
-    IN PKSMULTIPLE_ITEM NodeTypes,
+    IN LPMIXER_INFO MixerInfo,
+    IN ULONG bInputMixer,
+    IN LPWSTR LineName)
+{
+    LPMIXERLINE_EXT DestinationLine;
+
+    /* allocate a mixer destination line */
+    DestinationLine = (LPMIXERLINE_EXT) MixerContext->Alloc(sizeof(MIXERLINE_EXT));
+    if (!MixerInfo)
+    {
+        /* no memory */
+        return MM_STATUS_NO_MEMORY;
+    }
+
+    /* initialize mixer destination line */
+    DestinationLine->Line.cbStruct = sizeof(MIXERLINEW);
+    DestinationLine->Line.dwSource = MAXULONG;
+    DestinationLine->Line.dwLineID = DESTINATION_LINE;
+    DestinationLine->Line.fdwLine = MIXERLINE_LINEF_ACTIVE;
+    DestinationLine->Line.dwUser = 0;
+    DestinationLine->Line.dwComponentType = (bInputMixer == 0 ? MIXERLINE_COMPONENTTYPE_DST_SPEAKERS : MIXERLINE_COMPONENTTYPE_DST_WAVEIN);
+    DestinationLine->Line.cChannels = 2; /* FIXME */
+
+    if (LineName)
+    {
+        MixerContext->Copy(DestinationLine->Line.szShortName, LineName, (min(MIXER_SHORT_NAME_CHARS, wcslen(LineName)+1)) * sizeof(WCHAR));
+        DestinationLine->Line.szShortName[MIXER_SHORT_NAME_CHARS-1] = L'\0';
+
+        MixerContext->Copy(DestinationLine->Line.szName, LineName, (min(MIXER_LONG_NAME_CHARS, wcslen(LineName)+1)) * sizeof(WCHAR));
+        DestinationLine->Line.szName[MIXER_LONG_NAME_CHARS-1] = L'\0';
+
+    }
+
+    DestinationLine->Line.Target.dwType = (bInputMixer == 0 ? MIXERLINE_TARGETTYPE_WAVEOUT : MIXERLINE_TARGETTYPE_WAVEIN);
+    DestinationLine->Line.Target.dwDeviceID = !bInputMixer;
+    DestinationLine->Line.Target.wMid = MixerInfo->MixCaps.wMid;
+    DestinationLine->Line.Target.wPid = MixerInfo->MixCaps.wPid;
+    DestinationLine->Line.Target.vDriverVersion = MixerInfo->MixCaps.vDriverVersion;
+
+    ASSERT(MixerInfo->MixCaps.szPname[MAXPNAMELEN-1] == 0);
+    wcscpy(DestinationLine->Line.Target.szPname, MixerInfo->MixCaps.szPname);
+
+    /* initialize extra line */
+    InitializeListHead(&DestinationLine->LineControlsExtraData);
+
+    /* insert into mixer info */
+    InsertHeadList(&MixerInfo->LineList, &DestinationLine->Entry);
+
+    /* done */
+    return MM_STATUS_SUCCESS;
+}
+
+MIXER_STATUS
+MMixerGetPinName(
+    IN PMIXER_CONTEXT MixerContext,
+    IN LPMIXER_INFO MixerInfo,
     IN ULONG PinId,
-    IN ULONG bBridgePin,
-    IN ULONG bTargetPin)
+    IN OUT LPWSTR * OutBuffer)
 {
-    LPMIXERLINE_EXT SrcLine, DstLine;
-    MIXER_STATUS Status;
     KSP_PIN Pin;
-    LPWSTR PinName;
-    GUID NodeType;
-    ULONG BytesReturned, ControlCount, Index;
-    LPGUID Node;
-    PULONG Nodes;
+    ULONG BytesReturned;
+    LPWSTR Buffer;
+    MIXER_STATUS Status;
 
-    if (!bTargetPin)
-    {
-        /* allocate src mixer line */
-        SrcLine = (LPMIXERLINE_EXT)MixerContext->Alloc(sizeof(MIXERLINE_EXT));
+    /* prepare pin */
+    Pin.PinId = PinId;
+    Pin.Reserved = 0;
+    Pin.Property.Flags = KSPROPERTY_TYPE_GET;
+    Pin.Property.Set = KSPROPSETID_Pin;
+    Pin.Property.Id = KSPROPERTY_PIN_NAME;
+
+    /* try get pin name size */
+    Status = MixerContext->Control(MixerInfo->hMixer, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSP_PIN), NULL, 0, &BytesReturned);
 
-        if (!SrcLine)
+    /* check if buffer overflowed */
+    if (Status == MM_STATUS_MORE_ENTRIES)
+    {
+        /* allocate buffer */
+        Buffer = (LPWSTR)MixerContext->Alloc(BytesReturned);
+        if (!Buffer)
+        {
+            /* out of memory */
             return MM_STATUS_NO_MEMORY;
+        }
+
+        /* try get pin name */
+        Status = MixerContext->Control(MixerInfo->hMixer, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSP_PIN), (PVOID)Buffer, BytesReturned, &BytesReturned);
+        if (Status != MM_STATUS_SUCCESS)
+        {
+            /* failed to get pin name */
+            MixerContext->Free((PVOID)Buffer);
+            return Status;
+        }
+
+        /* successfully obtained pin name */
+        *OutBuffer = Buffer;
+        return MM_STATUS_SUCCESS;
+    }
+
+    /* failed to get pin name */
+    return Status;
+}
+
+MIXER_STATUS
+MMixerBuildMixerDestinationLine(
+    IN PMIXER_CONTEXT MixerContext,
+    IN OUT LPMIXER_INFO MixerInfo,
+    IN ULONG PinId,
+    IN ULONG bInput)
+{
+    LPWSTR PinName;
+    MIXER_STATUS Status;
+
+    /* try get pin name */
+    Status = MMixerGetPinName(MixerContext, MixerInfo, PinId, &PinName);
+    if (Status == MM_STATUS_SUCCESS)
+    {
+        /* create mixer destination line */
 
-        /* zero struct */
-        RtlZeroMemory(SrcLine, sizeof(MIXERLINE_EXT));
+        Status = MMixerCreateDestinationLine(MixerContext, MixerInfo, bInput, PinName);
 
+        /* free pin name */
+        MixerContext->Free(PinName);
     }
     else
     {
-        ASSERT(!IsListEmpty(&MixerInfo->LineList));
-        SrcLine = MMixerGetSourceMixerLineByLineId(MixerInfo, DESTINATION_LINE);
+        /* create mixer destination line unlocalized */
+        Status = MMixerCreateDestinationLine(MixerContext, MixerInfo, bInput, L"No Name");
     }
 
-    /* get destination line */
-    DstLine = MMixerGetSourceMixerLineByLineId(MixerInfo, DESTINATION_LINE);
-    ASSERT(DstLine);
+    return Status;
+}
 
+MIXER_STATUS
+MMixerBuildTopology(
+    IN PMIXER_CONTEXT MixerContext,
+    IN LPMIXER_DATA MixerData,
+    OUT PTOPOLOGY * OutTopology)
+{
+    ULONG PinsCount;
+    PKSMULTIPLE_ITEM NodeTypes = NULL;
+    PKSMULTIPLE_ITEM NodeConnections = NULL;
+    MIXER_STATUS Status;
 
-    if (!bTargetPin)
+    if (MixerData->Topology)
     {
-        /* initialize mixer src line */
-        SrcLine->hDevice = hDevice;
-        SrcLine->PinId = PinId;
-        SrcLine->Line.cbStruct = sizeof(MIXERLINEW);
-
-        /* initialize mixer destination line */
-        SrcLine->Line.cbStruct = sizeof(MIXERLINEW);
-        SrcLine->Line.dwDestination = 0;
-        SrcLine->Line.dwSource = DstLine->Line.cConnections;
-        SrcLine->Line.dwLineID = (DstLine->Line.cConnections * 0x10000);
-        SrcLine->Line.fdwLine = MIXERLINE_LINEF_ACTIVE | MIXERLINE_LINEF_SOURCE;
-        SrcLine->Line.dwUser = 0;
-        SrcLine->Line.cChannels = DstLine->Line.cChannels;
-        SrcLine->Line.cConnections = 0;
-        SrcLine->Line.Target.dwType = 1;
-        SrcLine->Line.Target.dwDeviceID = DstLine->Line.Target.dwDeviceID;
-        SrcLine->Line.Target.wMid = MixerInfo->MixCaps.wMid;
-        SrcLine->Line.Target.wPid = MixerInfo->MixCaps.wPid;
-        SrcLine->Line.Target.vDriverVersion = MixerInfo->MixCaps.vDriverVersion;
-        InitializeListHead(&SrcLine->LineControlsExtraData);
-
-        ASSERT(MixerInfo->MixCaps.szPname[MAXPNAMELEN-1] == L'\0');
-        wcscpy(SrcLine->Line.Target.szPname, MixerInfo->MixCaps.szPname);
+        /* re-use existing topology */
+        *OutTopology = MixerData->Topology;
 
+        return MM_STATUS_SUCCESS;
     }
 
-    /* allocate a node arrary */
-    Nodes = (PULONG)MixerContext->Alloc(sizeof(ULONG) * NodeTypes->Count);
+    /* get connected filter pin count */
+    PinsCount = MMixerGetFilterPinCount(MixerContext, MixerData->hDevice);
 
-    if (!Nodes)
+    if (!PinsCount)
     {
-        /* not enough memory */
-        if (!bTargetPin)
-        {
-            MixerContext->Free(SrcLine);
-        }
-        return MM_STATUS_NO_MEMORY;
+        /* referenced filter does not have any pins */
+        return MM_STATUS_UNSUCCESSFUL;
     }
 
-    Status = MMixerGetControlsFromPin(MixerContext, NodeConnections, NodeTypes, PinId, bTargetPin, Nodes);
+    /* get topology node types */
+    Status = MMixerGetFilterTopologyProperty(MixerContext, MixerData->hDevice, KSPROPERTY_TOPOLOGY_NODES, &NodeTypes);
     if (Status != MM_STATUS_SUCCESS)
     {
-        /* something went wrong */
-        if (!bTargetPin)
-        {
-            MixerContext->Free(SrcLine);
-        }
-        MixerContext->Free(Nodes);
+        /* failed to get topology node types */
         return Status;
     }
 
-    /* now count all nodes controlled by that pin */
-    ControlCount = 0;
-    for(Index = 0; Index < NodeTypes->Count; Index++)
+    /* get topology connections */
+    Status = MMixerGetFilterTopologyProperty(MixerContext, MixerData->hDevice, KSPROPERTY_TOPOLOGY_CONNECTIONS, &NodeConnections);
+    if (Status != MM_STATUS_SUCCESS)
     {
-        if (Nodes[Index])
-        {
-            // get node type
-            Node = MMixerGetNodeType(NodeTypes, Index);
+        /* failed to get topology connections */
+        MixerContext->Free(NodeTypes);
+        return Status;
+    }
 
-            if (MMixerGetControlTypeFromTopologyNode(Node))
-            {
-                // found a node which can be resolved to a type
-                ControlCount++;
-            }
-        }
+    /* create a topology */
+    Status = MMixerCreateTopology(MixerContext, PinsCount, NodeConnections, NodeTypes, OutTopology);
+
+    /* free node types & connections */
+    MixerContext->Free(NodeConnections);
+    MixerContext->Free(NodeTypes);
+
+    if (Status == MM_STATUS_SUCCESS)
+    {
+        /* store topology object */
+        MixerData->Topology = *OutTopology;
     }
 
-    /* now allocate the line controls */
-    if (ControlCount)
+    /* done */
+    return Status;
+}
+
+MIXER_STATUS
+MMixerCountMixerControls(
+    IN PMIXER_CONTEXT MixerContext,
+    IN PTOPOLOGY Topology,
+    IN ULONG PinId,
+    IN ULONG bUpStream,
+    OUT PULONG OutNodesCount,
+    OUT PULONG OutNodes,
+    OUT PULONG OutLineTerminator)
+{
+    PULONG Nodes;
+    ULONG NodesCount, NodeIndex, Count, bTerminator;
+    MIXER_STATUS Status;
+
+    /* allocate an array to store all nodes which are upstream of this pin */
+    Status = MMixerAllocateTopologyNodeArray(MixerContext, Topology, &Nodes);
+
+    if (Status != MM_STATUS_SUCCESS)
     {
-        SrcLine->LineControls = (LPMIXERCONTROLW)MixerContext->Alloc(sizeof(MIXERCONTROLW) * ControlCount);
+        /* out of memory */
+        return STATUS_NO_MEMORY;
+    }
 
-        if (!SrcLine->LineControls)
-        {
-            /* no memory available */
-            if (!bTargetPin)
-            {
-                MixerContext->Free(SrcLine);
-            }
-            MixerContext->Free(Nodes);
-            return MM_STATUS_NO_MEMORY;
-        }
+    /* mark result array as zero */
+    *OutNodesCount = 0;
+
+    /* get next nodes */
+    MMixerGetNextNodesFromPinIndex(MixerContext, Topology, PinId, bUpStream, &NodesCount, Nodes);
+
+    /* assume no topology split before getting line terminator */
+    ASSERT(NodesCount == 1);
+
+    /* get first node */
+    NodeIndex = Nodes[0];
+    Count = 0;
 
-        SrcLine->NodeIds = (PULONG)MixerContext->Alloc(sizeof(ULONG) * ControlCount);
-        if (!SrcLine->NodeIds)
+    do
+    {
+        /* check if the node is a terminator */
+        MMixerIsNodeTerminator(Topology, NodeIndex, &bTerminator);
+
+        if (bTerminator)
         {
-            /* no memory available */
-            MixerContext->Free(SrcLine->LineControls);
-            if (!bTargetPin)
-            {
-                MixerContext->Free(SrcLine);
-            }
-            MixerContext->Free(Nodes);
-            return MM_STATUS_NO_MEMORY;
+            /* found terminator */
+            break;
         }
 
-        /* zero line controls */
-        RtlZeroMemory(SrcLine->LineControls, sizeof(MIXERCONTROLW) * ControlCount);
-        RtlZeroMemory(SrcLine->NodeIds, sizeof(ULONG) * ControlCount);
+        /* store node id */
+        OutNodes[Count] = NodeIndex;
 
-        ControlCount = 0;
-        for(Index = 0; Index < NodeTypes->Count; Index++)
-        {
-            if (Nodes[Index])
-            {
-                // get node type
-                Node = MMixerGetNodeType(NodeTypes, Index);
+        /* increment node count */
+        Count++;
 
-                if (MMixerGetControlTypeFromTopologyNode(Node))
-                {
-                    /* store the node index for retrieving / setting details */
-                    SrcLine->NodeIds[ControlCount] = Index;
-
-                    Status = MMixerAddMixerControl(MixerContext, MixerInfo, hDevice, NodeTypes, Index, SrcLine, &SrcLine->LineControls[ControlCount]);
-                    if (Status == MM_STATUS_SUCCESS)
-                    {
-                        /* increment control count on success */
-                        ControlCount++;
-                    }
-                }
-            }
-        }
-        /* store control count */
-        SrcLine->Line.cControls = ControlCount;
-    }
+        /* get next nodes upstream */
+        MMixerGetNextNodesFromNodeIndex(MixerContext, Topology, NodeIndex, bUpStream, &NodesCount, Nodes);
+
+        /* assume there is a node connected */
+        ASSERT(NodesCount != 0);
+        ASSERT(NodesCount == 1);
+
+        /* use first index */
+        NodeIndex = Nodes[0];
+
+    }while(TRUE);
 
-    /* release nodes array */
+    /* free node index */
     MixerContext->Free(Nodes);
 
-    /* get pin category */
-    Pin.PinId = PinId;
-    Pin.Reserved = 0;
-    Pin.Property.Flags = KSPROPERTY_TYPE_GET;
-    Pin.Property.Set = KSPROPSETID_Pin;
-    Pin.Property.Id = KSPROPERTY_PIN_CATEGORY;
+    /* store nodes count */
+    *OutNodesCount = Count;
 
-    /* try get pin category */
-    Status = MixerContext->Control(hDevice, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSP_PIN), (LPVOID)&NodeType, sizeof(GUID), &BytesReturned);
-    if (Status != MM_STATUS_SUCCESS)
+    /* store line terminator */
+    *OutLineTerminator = NodeIndex;
+
+    /* done */
+    return MM_STATUS_SUCCESS;
+}
+
+MIXER_STATUS
+MMixerAddMixerControlsToMixerLineByNodeIndexArray(
+    IN PMIXER_CONTEXT MixerContext,
+    IN LPMIXER_INFO MixerInfo,
+    IN PTOPOLOGY Topology,
+    IN OUT LPMIXERLINE_EXT DstLine,
+    IN ULONG NodesCount,
+    IN PULONG Nodes)
+{
+    ULONG Index, Count, bReserved;
+    MIXER_STATUS Status;
+
+    /* store nodes array */
+    DstLine->NodeIds = Nodes;
+
+    /* allocate MIXERCONTROLSW array */
+    DstLine->LineControls = MixerContext->Alloc(NodesCount * sizeof(MIXERCONTROLW));
+
+    if (!DstLine->LineControls)
     {
-        //FIXME
-        //map component type
+        /* out of memory */
+        return MM_STATUS_NO_MEMORY;
     }
 
-    /* retrieve pin name */
-    Pin.PinId = PinId;
-    Pin.Reserved = 0;
-    Pin.Property.Flags = KSPROPERTY_TYPE_GET;
-    Pin.Property.Set = KSPROPSETID_Pin;
-    Pin.Property.Id = KSPROPERTY_PIN_NAME;
-
-    /* try get pin name size */
-    Status = MixerContext->Control(hDevice, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSP_PIN), NULL, 0, &BytesReturned);
+    /* initialize control count */
+    Count = 0;
 
-    if (Status == MM_STATUS_MORE_ENTRIES)
+    for(Index = 0; Index < NodesCount; Index++)
     {
-        PinName = (LPWSTR)MixerContext->Alloc(BytesReturned);
-        if (PinName)
+        /* check if the node has already been reserved to a line */
+        MMixerIsTopologyNodeReserved(Topology, Nodes[Index], &bReserved);
+
+        if (bReserved)
         {
-            /* try get pin name */
-            Status = MixerContext->Control(hDevice, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSP_PIN), (LPVOID)PinName, BytesReturned, &BytesReturned);
+            /* node is already used, skip it */
+            continue;
+        }
 
-            if (Status == MM_STATUS_SUCCESS)
-            {
-                MixerContext->Copy(SrcLine->Line.szShortName, PinName, (min(MIXER_SHORT_NAME_CHARS, wcslen(PinName)+1)) * sizeof(WCHAR));
-                SrcLine->Line.szShortName[MIXER_SHORT_NAME_CHARS-1] = L'\0';
+        /* set node status as used */
+        MMixerSetTopologyNodeReserved(Topology, Nodes[Index]);
 
-                MixerContext->Copy(SrcLine->Line.szName, PinName, (min(MIXER_LONG_NAME_CHARS, wcslen(PinName)+1)) * sizeof(WCHAR));
-                SrcLine->Line.szName[MIXER_LONG_NAME_CHARS-1] = L'\0';
-            }
-            MixerContext->Free(PinName);
+        /* now add the mixer control */
+        Status = MMixerAddMixerControl(MixerContext, MixerInfo, Topology, Nodes[Index], DstLine, &DstLine->LineControls[Count]);
+
+        if (Status == MM_STATUS_SUCCESS)
+        {
+            /* increment control count */
+            Count++;
         }
     }
 
-    /* insert src line */
-    if (!bTargetPin)
-    {
-        InsertTailList(&MixerInfo->LineList, &SrcLine->Entry);
-        DstLine->Line.cConnections++;
-    }
+    /* store control count */
+    DstLine->Line.cControls = Count;
 
+    /* done */
     return MM_STATUS_SUCCESS;
 }
 
 MIXER_STATUS
-MMixerCreateDestinationLine(
+MMixerBuildMixerSourceLine(
     IN PMIXER_CONTEXT MixerContext,
-    IN LPMIXER_INFO MixerInfo,
-    IN ULONG bInputMixer,
-    IN LPWSTR LineName)
+    IN OUT LPMIXER_INFO MixerInfo,
+    IN PTOPOLOGY Topology,
+    IN ULONG PinId,
+    IN ULONG NodesCount,
+    IN PULONG Nodes,
+    OUT LPMIXERLINE_EXT * OutSrcLine)
 {
-    LPMIXERLINE_EXT DestinationLine;
+    LPMIXERLINE_EXT SrcLine, DstLine;
+    LPWSTR PinName;
+    MIXER_STATUS Status;
 
-    // allocate a mixer destination line
-    DestinationLine = (LPMIXERLINE_EXT) MixerContext->Alloc(sizeof(MIXERLINE_EXT));
-    if (!MixerInfo)
+    /* construct source line */
+    SrcLine = (LPMIXERLINE_EXT)MixerContext->Alloc(sizeof(MIXERLINE_EXT));
+
+    if (!SrcLine)
     {
-        // no memory
+        /* no memory */
         return MM_STATUS_NO_MEMORY;
     }
 
-    /* initialize mixer destination line */
-    DestinationLine->Line.cbStruct = sizeof(MIXERLINEW);
-    DestinationLine->Line.dwSource = MAXULONG;
-    DestinationLine->Line.dwLineID = DESTINATION_LINE;
-    DestinationLine->Line.fdwLine = MIXERLINE_LINEF_ACTIVE;
-    DestinationLine->Line.dwUser = 0;
-    DestinationLine->Line.dwComponentType = (bInputMixer == 0 ? MIXERLINE_COMPONENTTYPE_DST_SPEAKERS : MIXERLINE_COMPONENTTYPE_DST_WAVEIN);
-    DestinationLine->Line.cChannels = 2; //FIXME
+    /* get destination line */
+    DstLine = MMixerGetSourceMixerLineByLineId(MixerInfo, DESTINATION_LINE);
+    ASSERT(DstLine);
 
-    if (LineName)
+    /* initialize mixer src line */
+    SrcLine->hDevice = MixerInfo->hMixer;
+    SrcLine->PinId = PinId;
+    SrcLine->NodeIds = Nodes;
+
+    /* initialize mixer line */
+    SrcLine->Line.cbStruct = sizeof(MIXERLINEW);
+    SrcLine->Line.dwDestination = 0;
+    SrcLine->Line.dwSource = DstLine->Line.cConnections;
+    SrcLine->Line.dwLineID = (DstLine->Line.cConnections * 0x10000);
+    SrcLine->Line.fdwLine = MIXERLINE_LINEF_ACTIVE | MIXERLINE_LINEF_SOURCE;
+    SrcLine->Line.dwUser = 0;
+    SrcLine->Line.cChannels = DstLine->Line.cChannels;
+    SrcLine->Line.cConnections = 0;
+    SrcLine->Line.Target.dwType = 1;
+    SrcLine->Line.Target.dwDeviceID = DstLine->Line.Target.dwDeviceID;
+    SrcLine->Line.Target.wMid = MixerInfo->MixCaps.wMid;
+    SrcLine->Line.Target.wPid = MixerInfo->MixCaps.wPid;
+    SrcLine->Line.Target.vDriverVersion = MixerInfo->MixCaps.vDriverVersion;
+    InitializeListHead(&SrcLine->LineControlsExtraData);
+
+    /* copy name */
+    ASSERT(MixerInfo->MixCaps.szPname[MAXPNAMELEN-1] == L'\0');
+    wcscpy(SrcLine->Line.Target.szPname, MixerInfo->MixCaps.szPname);
+
+    /* get pin name */
+    Status = MMixerGetPinName(MixerContext, MixerInfo, PinId, &PinName);
+
+    if (Status == MM_STATUS_SUCCESS)
     {
-        MixerContext->Copy(DestinationLine->Line.szShortName, LineName, (min(MIXER_SHORT_NAME_CHARS, wcslen(LineName)+1)) * sizeof(WCHAR));
-        DestinationLine->Line.szShortName[MIXER_SHORT_NAME_CHARS-1] = L'\0';
+        /* store pin name as line name */
+        MixerContext->Copy(SrcLine->Line.szShortName, PinName, (min(MIXER_SHORT_NAME_CHARS, wcslen(PinName)+1)) * sizeof(WCHAR));
+        SrcLine->Line.szShortName[MIXER_SHORT_NAME_CHARS-1] = L'\0';
 
-        MixerContext->Copy(DestinationLine->Line.szName, LineName, (min(MIXER_LONG_NAME_CHARS, wcslen(LineName)+1)) * sizeof(WCHAR));
-        DestinationLine->Line.szName[MIXER_LONG_NAME_CHARS-1] = L'\0';
+        MixerContext->Copy(SrcLine->Line.szName, PinName, (min(MIXER_LONG_NAME_CHARS, wcslen(PinName)+1)) * sizeof(WCHAR));
+        SrcLine->Line.szName[MIXER_LONG_NAME_CHARS-1] = L'\0';
 
+        /* free pin name buffer */
+        MixerContext->Free(PinName);
     }
-    else
+
+    /* add the controls to mixer line */
+    Status = MMixerAddMixerControlsToMixerLineByNodeIndexArray(MixerContext, MixerInfo, Topology, SrcLine, NodesCount, Nodes);
+    if (Status != MM_STATUS_SUCCESS)
     {
-        /* FIXME no name was found for pin */
-        wcscpy(DestinationLine->Line.szShortName, L"Summe");
-        wcscpy(DestinationLine->Line.szName, L"Summe");
+        /* failed */
+        return Status;
     }
 
-    DestinationLine->Line.Target.dwType = (bInputMixer == 0 ? MIXERLINE_TARGETTYPE_WAVEOUT : MIXERLINE_TARGETTYPE_WAVEIN);
-    DestinationLine->Line.Target.dwDeviceID = !bInputMixer;
-    DestinationLine->Line.Target.wMid = MixerInfo->MixCaps.wMid;
-    DestinationLine->Line.Target.wPid = MixerInfo->MixCaps.wPid;
-    DestinationLine->Line.Target.vDriverVersion = MixerInfo->MixCaps.vDriverVersion;
-
-    ASSERT(MixerInfo->MixCaps.szPname[MAXPNAMELEN-1] == 0);
-    wcscpy(DestinationLine->Line.Target.szPname, MixerInfo->MixCaps.szPname);
-
-    // initialize extra line
-    InitializeListHead(&DestinationLine->LineControlsExtraData);
+    /* store result */
+    *OutSrcLine = SrcLine;
 
-    // insert into mixer info
-    InsertHeadList(&MixerInfo->LineList, &DestinationLine->Entry);
-
-    // done
     return MM_STATUS_SUCCESS;
 }
 
 MIXER_STATUS
-MMixerGetControlsFromPin(
+MMixerAddMixerSourceLines(
     IN PMIXER_CONTEXT MixerContext,
-    IN PKSMULTIPLE_ITEM NodeConnections,
-    IN PKSMULTIPLE_ITEM NodeTypes,
-    IN ULONG PinId,
-    IN ULONG bUpDirection,
-    OUT PULONG Nodes)
+    IN OUT LPMIXER_INFO MixerInfo,
+    IN PTOPOLOGY Topology,
+    IN ULONG LineTerminator)
 {
-    ULONG NodeConnectionCount, Index;
+    PULONG AllNodes, AllPins, AllPinNodes;
+    ULONG AllNodesCount, AllPinsCount, AllPinNodesCount;
+    ULONG Index, SubIndex, PinId, CurNode, bConnected;
     MIXER_STATUS Status;
-    PULONG NodeConnection;
+    LPMIXERLINE_EXT DstLine, SrcLine;
 
-    /* sanity check */
-    ASSERT(PinId != (ULONG)-1);
+    /* get destination line */
+    DstLine = MMixerGetSourceMixerLineByLineId(MixerInfo, DESTINATION_LINE);
+    ASSERT(DstLine);
 
-    /* get all node indexes referenced by that pin */
-    if (bUpDirection)
-        Status = MMixerGetNodeIndexes(MixerContext, NodeConnections, PinId, FALSE, FALSE, &NodeConnectionCount, &NodeConnection);
-    else
-        Status = MMixerGetNodeIndexes(MixerContext, NodeConnections, PinId, FALSE, TRUE, &NodeConnectionCount, &NodeConnection);
+    /* allocate an array to store all nodes which are upstream of the line terminator */
+    Status = MMixerAllocateTopologyNodeArray(MixerContext, Topology, &AllNodes);
 
-    for(Index = 0; Index < NodeConnectionCount; Index++)
+    /* check for success */
+    if (Status != MM_STATUS_SUCCESS)
     {
-        /* get all associated controls */
-        Status = MMixerGetControlsFromPinByConnectionIndex(MixerContext, NodeConnections, NodeTypes, bUpDirection, NodeConnection[Index], Nodes);
+        /* out of memory */
+        return MM_STATUS_NO_MEMORY;
     }
 
-    MixerContext->Free(NodeConnection);
+    /* allocate an array to store all nodes which are downstream of a particular pin */
+    Status = MMixerAllocateTopologyNodeArray(MixerContext, Topology, &AllPinNodes);
 
-    return Status;
-}
+    /* allocate an array to store all pins which are upstream of this pin */
+    Status = MMixerAllocateTopologyPinArray(MixerContext, Topology, &AllPins);
+
+    /* check for success */
+    if (Status != MM_STATUS_SUCCESS)
+    {
+        /* out of memory */
+        MixerContext->Free(AllNodes);
+        return MM_STATUS_NO_MEMORY;
+    }
+
+     /* get all nodes which indirectly / directly connect to this node */
+    AllNodesCount = 0;
+    MMixerGetAllUpOrDownstreamNodesFromNodeIndex(MixerContext, Topology, LineTerminator, TRUE, &AllNodesCount, AllNodes);
 
+    /* get all pins which indirectly / directly connect to this node */
+    MMixerGetAllUpOrDownstreamPinsFromNodeIndex(MixerContext, Topology, LineTerminator, TRUE, &AllPinsCount, AllPins);
 
+    DPRINT("LineTerminator %lu\n", LineTerminator);
+    DPRINT("PinCount %lu\n", AllPinsCount);
+    DPRINT("AllNodesCount %lu\n", AllNodesCount);
+
+    /* now construct the source lines which are attached to the destination line */
+    Index = AllPinsCount;
+
+    do
+    {
+        /* get current pin id */
+        PinId = AllPins[Index - 1];
+
+        /* reset nodes count */
+        AllPinNodesCount = 0;
+
+        /* now scan all nodes and add them to AllPinNodes array when they are connected to this pin */
+        for(SubIndex = 0; SubIndex < AllNodesCount; SubIndex++)
+        {
+            /* get current node index */
+            CurNode = AllNodes[SubIndex];
+
+            if (CurNode != MAXULONG && CurNode != LineTerminator)
+            {
+                /* check if that node is connected in some way to the current pin */
+                Status = MMixerIsNodeConnectedToPin(MixerContext, Topology, CurNode, PinId, TRUE, &bConnected);
+
+                if (Status != MM_STATUS_SUCCESS)
+                    break;
+
+                if (bConnected)
+                {
+                    /* it is connected */
+                    AllPinNodes[AllPinNodesCount] = CurNode;
+                    AllPinNodesCount++;
+
+                    /* clear current index */
+                    AllNodes[SubIndex] = MAXULONG;
+                }
+            }
+        }
+
+        /* decrement pin index */
+        Index--;
+
+        if (AllPinNodesCount)
+        {
+            /* now build the mixer source line */
+            Status = MMixerBuildMixerSourceLine(MixerContext, MixerInfo, Topology, PinId, AllPinNodesCount, AllPinNodes, &SrcLine);
+
+             if (Status == MM_STATUS_SUCCESS)
+             {
+                 /* insert into line list */
+                 InsertTailList(&MixerInfo->LineList, &SrcLine->Entry);
+
+                 /* increment destination line count */
+                 DstLine->Line.cConnections++;
+             }
+        }
+
+    }while(Index != 0);
+
+    return MM_STATUS_SUCCESS;
+}
 
 
 MIXER_STATUS
-MMixerAddMixerSourceLines(
+MMixerAddMixerControlsToDestinationLine(
     IN PMIXER_CONTEXT MixerContext,
     IN OUT LPMIXER_INFO MixerInfo,
-    IN HANDLE hDevice,
-    IN PKSMULTIPLE_ITEM NodeConnections,
-    IN PKSMULTIPLE_ITEM NodeTypes,
-    IN ULONG PinsCount,
-    IN ULONG BridgePinIndex,
-    IN ULONG TargetPinIndex,
-    IN PULONG Pins)
+    IN PTOPOLOGY Topology,
+    IN ULONG PinId,
+    IN ULONG bInput,
+    OUT PULONG OutLineTerminator)
 {
-    ULONG Index;
+    PULONG Nodes;
+    ULONG NodesCount, LineTerminator;
+    MIXER_STATUS Status;
+    LPMIXERLINE_EXT DstLine;
+
+    /* allocate nodes index array */
+    Status = MMixerAllocateTopologyNodeArray(MixerContext, Topology, &Nodes);
+
+    /* check for success */
+    if (Status != MM_STATUS_SUCCESS)
+    {
+        /* out of memory */
+        return MM_STATUS_NO_MEMORY;
+    }
+
+    /* get all destination line controls */
+    Status = MMixerCountMixerControls(MixerContext, Topology, PinId, TRUE, &NodesCount, Nodes, &LineTerminator);
+
+    /* check for success */
+    if (Status != MM_STATUS_SUCCESS)
+    {
+        /* failed to count controls */
+        MixerContext->Free(Nodes);
+        return Status;
+    }
+
+    /* get destination mixer line */
+    DstLine = MMixerGetSourceMixerLineByLineId(MixerInfo, DESTINATION_LINE);
+
+    /* sanity check */
+    ASSERT(DstLine);
 
-    for(Index = PinsCount; Index > 0; Index--)
+    if (NodesCount > 0)
     {
-        DPRINT("MMixerAddMixerSourceLines Index %lu Pin %lu\n", Index-1, Pins[Index-1]);
-        if (Pins[Index-1])
+        /* add all nodes as mixer controls to the destination line */
+        Status = MMixerAddMixerControlsToMixerLineByNodeIndexArray(MixerContext, MixerInfo, Topology, DstLine, NodesCount, Nodes);
+        if (Status != MM_STATUS_SUCCESS)
         {
-            MMixerAddMixerSourceLine(MixerContext, MixerInfo, hDevice, NodeConnections, NodeTypes, Index-1, (Index -1 == BridgePinIndex), (Index -1 == TargetPinIndex));
+            /* failed to add controls */
+            MixerContext->Free(Nodes);
+            return Status;
         }
     }
-    return MM_STATUS_SUCCESS;
-}
 
+    /* store result */
+    *OutLineTerminator = LineTerminator;
+
+    /* return result */
+    return Status;
+}
 
 MIXER_STATUS
 MMixerHandlePhysicalConnection(
     IN PMIXER_CONTEXT MixerContext,
     IN PMIXER_LIST MixerList,
+    IN LPMIXER_DATA MixerData,
     IN OUT LPMIXER_INFO MixerInfo,
     IN ULONG bInput,
     IN PKSPIN_PHYSICALCONNECTION OutConnection)
 {
-    PULONG PinsRef = NULL, PinConnectionIndex = NULL, PinsSrcRef;
-    ULONG PinsRefCount, Index, PinConnectionIndexCount;
     MIXER_STATUS Status;
-    PKSMULTIPLE_ITEM NodeTypes = NULL;
-    PKSMULTIPLE_ITEM NodeConnections = NULL;
-    PULONG MixerControls;
-    ULONG MixerControlsCount;
-    LPMIXER_DATA MixerData;
-
+    ULONG PinsCount, LineTerminator;
+    PULONG Pins;
+    PTOPOLOGY Topology;
 
-    // open the connected filter
+    /* first try to open the connected filter */
     OutConnection->SymbolicLinkName[1] = L'\\';
     MixerData = MMixerGetDataByDeviceName(MixerList, OutConnection->SymbolicLinkName);
-    ASSERT(MixerData);
 
-    // store connected mixer handle
-    MixerInfo->hMixer = MixerData->hDevice;
-
-    // get connected filter pin count
-    PinsRefCount = MMixerGetFilterPinCount(MixerContext, MixerData->hDevice);
-    ASSERT(PinsRefCount);
+     /* check if the linked connection is found */
+     if (!MixerData)
+     {
+         /* filter references invalid physical connection */
+         return MM_STATUS_UNSUCCESSFUL;
+     }
 
-    PinsRef = (PULONG)MixerContext->Alloc(sizeof(ULONG) * PinsRefCount);
-    if (!PinsRef)
-    {
-        // no memory
-        return MM_STATUS_UNSUCCESSFUL;
-    }
+     DPRINT("Name %S, Pin %lu bInput %lu\n", OutConnection->SymbolicLinkName, OutConnection->Pin, bInput);
 
-    // get topology node types
-    Status = MMixerGetFilterTopologyProperty(MixerContext, MixerData->hDevice, KSPROPERTY_TOPOLOGY_NODES, &NodeTypes);
-    if (Status != MM_STATUS_SUCCESS)
-    {
-        MixerContext->Free(PinsRef);
-        return Status;
-    }
+    /* store connected mixer handle */
+    MixerInfo->hMixer = MixerData->hDevice;
 
-    // get topology connections
-    Status = MMixerGetFilterTopologyProperty(MixerContext, MixerData->hDevice, KSPROPERTY_TOPOLOGY_CONNECTIONS, &NodeConnections);
-    if (Status != MM_STATUS_SUCCESS)
-    {
-        MixerContext->Free(PinsRef);
-        MixerContext->Free(NodeTypes);
-        return Status;
-    }
-    //  gets connection index of the bridge pin which connects to a node
-    DPRINT("Pin %lu\n", OutConnection->Pin);
 
-    Status = MMixerGetNodeIndexes(MixerContext, NodeConnections, OutConnection->Pin, FALSE, !bInput, &PinConnectionIndexCount, &PinConnectionIndex);
+    Status = MMixerBuildTopology(MixerContext, MixerData, &Topology);
     if (Status != MM_STATUS_SUCCESS)
     {
-        MixerContext->Free(PinsRef);
-        MixerContext->Free(NodeTypes);
-        MixerContext->Free(NodeConnections);
+        /* failed to create topology */
         return Status;
     }
 
-    /* there should be no split in the bridge pin */
-    ASSERT(PinConnectionIndexCount == 1);
+    /* allocate pin index array which will hold all referenced pins */
+    Status = MMixerAllocateTopologyPinArray(MixerContext, Topology, &Pins);
+    ASSERT(Status == MM_STATUS_SUCCESS);
 
-    /* find all target pins of this connection */
-    Status = MMixerGetTargetPinsByNodeConnectionIndex(MixerContext, NodeConnections, NodeTypes, FALSE, PinConnectionIndex[0], PinsRefCount, PinsRef);
-    if (Status != MM_STATUS_SUCCESS)
+    if (!bInput)
     {
-        MixerContext->Free(PinsRef);
-        MixerContext->Free(NodeTypes);
-        MixerContext->Free(NodeConnections);
-        MixerContext->Free(PinConnectionIndex);
-        return Status;
-    }
+        /* the mixer is an output mixer
+         * find end pin of the node path
+         */
+        Status = MMixerGetAllUpOrDownstreamPinsFromPinIndex(MixerContext, Topology, OutConnection->Pin, FALSE, &PinsCount, Pins);
 
-    for(Index = 0; Index < PinsRefCount; Index++)
-    {
-        DPRINT("PinsRefCount %lu Index %lu Value %lu\n", PinsRefCount, Index, PinsRef[Index]);
-        if (PinsRef[Index])
+        /* check for success */
+        if (Status != MM_STATUS_SUCCESS)
         {
-            // found a target pin, now get all references
-            Status = MMixerGetNodeIndexes(MixerContext, NodeConnections, Index, FALSE, FALSE, &MixerControlsCount, &MixerControls);
-            if (Status != MM_STATUS_SUCCESS)
-            {
-                DPRINT("MMixerGetNodeIndexes failed with %u\n", Status);
-                break;
-            }
+            /* failed to get end pin */
+            MixerContext->Free(Pins);
+            //MMixerFreeTopology(Topology);
 
-            /* sanity check */
-            ASSERT(MixerControlsCount == 1);
+            /* return error code */
+            return Status;
+        }
 
-            PinsSrcRef = (PULONG)MixerContext->Alloc(PinsRefCount * sizeof(ULONG));
-            if (!PinsSrcRef)
-            {
-                /* no memory */
-                MixerContext->Free(PinsRef);
-                MixerContext->Free(NodeTypes);
-                MixerContext->Free(NodeConnections);
-                MixerContext->Free(PinConnectionIndex);
-                MixerContext->Free(MixerControls);
-                return MM_STATUS_NO_MEMORY;
-            }
+        /* sanity checks */
+        ASSERT(PinsCount != 0);
+        ASSERT(PinsCount == 1);
 
-            // now get all connected source pins
-            Status = MMixerGetTargetPinsByNodeConnectionIndex(MixerContext, NodeConnections, NodeTypes, TRUE, MixerControls[0], PinsRefCount, PinsSrcRef);
-            if (Status != MM_STATUS_SUCCESS)
-            {
-                // failed */
-                MixerContext->Free(PinsRef);
-                MixerContext->Free(NodeTypes);
-                MixerContext->Free(NodeConnections);
-                MixerContext->Free(PinConnectionIndex);
-                MixerContext->Free(MixerControls);
-                MixerContext->Free(PinsSrcRef);
-                return Status;
-            }
+        /* create destination line */
+        Status = MMixerBuildMixerDestinationLine(MixerContext, MixerInfo, Pins[0], bInput);
 
-            /* add pins from target line */
-            if (!bInput)
-            {
-                // dont add bridge pin for input mixers
-                PinsSrcRef[Index] = TRUE;
-                PinsSrcRef[OutConnection->Pin] = TRUE;
-            }
-            PinsSrcRef[OutConnection->Pin] = TRUE;
+        if (Status != MM_STATUS_SUCCESS)
+        {
+            MixerContext->Free(Pins);
+            //MMixerFreeTopology(Topology);
+
+            /* return error code */
+            return Status;
+        }
+
+        /* add mixer controls to destination line */
+        Status = MMixerAddMixerControlsToDestinationLine(MixerContext, MixerInfo, Topology, Pins[0], bInput, &LineTerminator);
 
-            Status = MMixerAddMixerSourceLines(MixerContext, MixerInfo, MixerData->hDevice, NodeConnections, NodeTypes, PinsRefCount, OutConnection->Pin, Index, PinsSrcRef);
+        if (Status == MM_STATUS_SUCCESS)
+        {
+            /* now add the rest of the source lines */
+            Status = MMixerAddMixerSourceLines(MixerContext, MixerInfo, Topology, LineTerminator);
+        }
+    }
+    else
+    {
+        Status = MMixerAddMixerControlsToDestinationLine(MixerContext, MixerInfo, Topology, OutConnection->Pin, bInput, &LineTerminator);
 
-            MixerContext->Free(MixerControls);
-            MixerContext->Free(PinsSrcRef);
+        if (Status == MM_STATUS_SUCCESS)
+        {
+            /* now add the rest of the source lines */
+            Status = MMixerAddMixerSourceLines(MixerContext, MixerInfo, Topology, LineTerminator);
         }
     }
 
+    /* free topology */
+    //MMixerFreeTopology(Topology);
+
     return Status;
 }
 
@@ -823,193 +879,137 @@ MMixerInitializeFilter(
     IN PMIXER_CONTEXT MixerContext,
     IN PMIXER_LIST MixerList,
     IN LPMIXER_DATA MixerData,
-    IN PKSMULTIPLE_ITEM NodeTypes,
-    IN PKSMULTIPLE_ITEM NodeConnections,
-    IN ULONG PinCount,
+    IN PTOPOLOGY Topology,
     IN ULONG NodeIndex,
     IN ULONG bInputMixer)
 {
     LPMIXER_INFO MixerInfo;
     MIXER_STATUS Status;
     PKSPIN_PHYSICALCONNECTION OutConnection;
-    ULONG Index;
     ULONG * Pins;
-    ULONG bUsed;
-    ULONG BytesReturned;
-    KSP_PIN Pin;
-    LPWSTR Buffer = NULL;
-    ULONG PinId;
+    ULONG PinsFound;
 
-    // allocate a mixer info struct
+    /* allocate a mixer info struct */
     MixerInfo = (LPMIXER_INFO) MixerContext->Alloc(sizeof(MIXER_INFO));
     if (!MixerInfo)
     {
-        // no memory
+        /* no memory */
         return MM_STATUS_NO_MEMORY;
     }
 
-    // intialize mixer caps */
-    MixerInfo->MixCaps.wMid = MM_MICROSOFT; //FIXME
-    MixerInfo->MixCaps.wPid = MM_PID_UNMAPPED; //FIXME
-    MixerInfo->MixCaps.vDriverVersion = 1; //FIXME
+    /* intialize mixer caps */
+    MixerInfo->MixCaps.wMid = MM_MICROSOFT; /* FIXME */
+    MixerInfo->MixCaps.wPid = MM_PID_UNMAPPED; /* FIXME */
+    MixerInfo->MixCaps.vDriverVersion = 1; /* FIXME */
     MixerInfo->MixCaps.fdwSupport = 0;
     MixerInfo->MixCaps.cDestinations = 1;
     MixerInfo->hMixer = MixerData->hDevice;
 
-    // get mixer name
+    /* get mixer name */
     MMixerGetDeviceName(MixerContext, MixerInfo, MixerData->hDeviceInterfaceKey);
 
-    // initialize line list
+    /* initialize line list */
     InitializeListHead(&MixerInfo->LineList);
     InitializeListHead(&MixerInfo->EventList);
 
-    // sanity check
-    ASSERT(PinCount);
+    /* now allocate an array which will receive the indices of the pin 
+     * which has a ADC / DAC nodetype in its path
+     */
+    Status = MMixerAllocateTopologyPinArray(MixerContext, Topology, &Pins);
+    ASSERT(Status == MM_STATUS_SUCCESS);
 
-    // now allocate an array which will receive the indices of the pin 
-    // which has a ADC / DAC nodetype in its path
-    Pins = (PULONG)MixerContext->Alloc(PinCount * sizeof(ULONG));
+    PinsFound = 0;
 
-    if (!Pins)
-    {
-        // no memory
-        MMixerFreeMixerInfo(MixerContext, MixerInfo);
-        return MM_STATUS_NO_MEMORY;
-    }
+    /* now get all sink / source pins, which are attached to the ADC / DAC node
+     * For sink pins (wave out) search up stream
+     * For source pins (wave in) search down stream
+     * The search direction is always the opposite of the current mixer type
+     */
+    MMixerGetAllUpOrDownstreamPinsFromNodeIndex(MixerContext, Topology, NodeIndex, !bInputMixer, &PinsFound, Pins);
 
-    // now get the target pins of the ADC / DAC node
-    Status = MMixerGetTargetPins(MixerContext, NodeTypes, NodeConnections, NodeIndex, !bInputMixer, Pins, PinCount);
+    /* if there is now pin found, we have a broken topology */
+    ASSERT(PinsFound != 0);
 
-    // find a target pin with a name
-    PinId = PinCount +1;
-    for(Index = 0; Index < PinCount; Index++)
+    /* now create a wave info struct */
+    Status = MMixerInitializeWaveInfo(MixerContext, MixerList, MixerData, MixerInfo->MixCaps.szPname, bInputMixer, PinsFound, Pins);
+    if (Status != MM_STATUS_SUCCESS)
     {
-        if (Pins[Index])
-        {
-            // store index of pin
-            PinId = Index;
-
-            /* retrieve pin name */
-            Pin.PinId = Index;
-            Pin.Reserved = 0;
-            Pin.Property.Flags = KSPROPERTY_TYPE_GET;
-            Pin.Property.Set = KSPROPSETID_Pin;
-            Pin.Property.Id = KSPROPERTY_PIN_NAME;
+        /* failed to create wave info struct */
+        MixerContext->Free(MixerInfo);
+        MixerContext->Free(Pins);
+        return Status;
+    }
 
-            /* try get pin name size */
-            Status = MixerContext->Control(MixerData->hDevice, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSP_PIN), NULL, 0, &BytesReturned);
+    if (bInputMixer)
+    {
+        /* pre create the mixer destination line for input mixers */
+        Status = MMixerBuildMixerDestinationLine(MixerContext, MixerInfo, Pins[0], bInputMixer);
 
-            if (Status == MM_STATUS_MORE_ENTRIES)
-            {
-                Buffer = (LPWSTR)MixerContext->Alloc(BytesReturned);
-                if (Buffer)
-                {
-                    /* try get pin name */
-                    Status = MixerContext->Control(MixerData->hDevice, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSP_PIN), (PVOID)Buffer, BytesReturned, &BytesReturned);
-                    if (Status != MM_STATUS_SUCCESS)
-                    {
-                        MixerContext->Free((PVOID)Buffer);
-                        Buffer = NULL;
-                    }
-                    else
-                    {
-                        // found name, done
-                        break;
-                    }
-                }
-            }
+        if (Status != MM_STATUS_SUCCESS)
+        {
+            /* failed to create mixer destination line */
+            return Status;
         }
     }
 
-    if (PinId < PinCount)
-    {
-        // create an wave info struct
-        MMixerInitializeWaveInfo(MixerContext, MixerList, MixerData, MixerInfo->MixCaps.szPname, bInputMixer, PinId);
-    }
 
-    Status = MMixerCreateDestinationLine(MixerContext, MixerInfo, bInputMixer, Buffer);
+    /* now get the bridge pin which is at the end of node path 
+     * For sink pins (wave out) search down stream
+     * For source pins (wave in) search up stream
+     */
+    MixerContext->Free(Pins);
+    Status = MMixerAllocateTopologyPinArray(MixerContext, Topology, &Pins);
+    ASSERT(Status == MM_STATUS_SUCCESS);
 
-    if (Buffer)
-    {
-        // free name
-        MixerContext->Free(Buffer);
-    }
+    MMixerGetAllUpOrDownstreamPinsFromNodeIndex(MixerContext, Topology, NodeIndex, bInputMixer, &PinsFound, Pins);
 
-    if (Status != MM_STATUS_SUCCESS)
-    {
-        // failed to create destination line
-        MixerContext->Free(MixerInfo);
-        MixerContext->Free(Pins);
+    /* if there is no pin found, we have a broken topology */
+    ASSERT(PinsFound != 0);
 
-        return Status;
-    }
+    /* there should be exactly one bridge pin */
+    ASSERT(PinsFound == 1);
 
-    RtlZeroMemory(Pins, sizeof(ULONG) * PinCount);
-    // now get the target pins of the ADC / DAC node
-    Status = MMixerGetTargetPins(MixerContext, NodeTypes, NodeConnections, NodeIndex, bInputMixer, Pins, PinCount);
+    DPRINT("BridgePin %lu bInputMixer %lu\n", Pins[0], bInputMixer);
 
-    if (Status != MM_STATUS_SUCCESS)
-    {
-        // failed to locate target pins
-        MixerContext->Free(Pins);
-        MMixerFreeMixerInfo(MixerContext, MixerInfo);
-        DPRINT("MMixerGetTargetPins failed with %u\n", Status);
-        return Status;
-    }
+    /* does the pin have a physical connection */
+    Status = MMixerGetPhysicalConnection(MixerContext, MixerData->hDevice, Pins[0], &OutConnection);
 
-    // filter hasnt been used
-    bUsed = FALSE;
+    if (Status == MM_STATUS_SUCCESS)
+    {
+        /* topology on the topoloy filter */
+        Status = MMixerHandlePhysicalConnection(MixerContext, MixerList, MixerData, MixerInfo, bInputMixer, OutConnection);
 
-    // now check all pins and generate new lines for destination lines
-    for(Index = 0; Index < PinCount; Index++)
+        /* free physical connection data */
+        MixerContext->Free(OutConnection);
+    }
+    else
     {
-        DPRINT("Index %lu TargetPin %lu\n", Index, Pins[Index]);
-        // is the current index a target pin
-        if (Pins[Index])
-        {
-            // check if the pin has a physical connection
-            Status = MMixerGetPhysicalConnection(MixerContext, MixerData->hDevice, Index, &OutConnection);
-            if (Status == MM_STATUS_SUCCESS)
-            {
-                // the pin has a physical connection
-                Status = MMixerHandlePhysicalConnection(MixerContext, MixerList, MixerInfo, bInputMixer, OutConnection);
-                DPRINT("MMixerHandlePhysicalConnection status %u\n", Status);
-                MixerContext->Free(OutConnection);
-                bUsed = TRUE;
-            }
-            else
-            {
-                // filter exposes the topology on the same filter
-                MMixerAddMixerSourceLine(MixerContext, MixerInfo, MixerData->hDevice, NodeConnections, NodeTypes, Index, FALSE, FALSE);
-                bUsed = TRUE;
-            }
-        }
+        /* FIXME
+         * handle drivers which expose their topology on the same filter
+         */
+        ASSERT(0);
     }
+
+    /* free pins */
     MixerContext->Free(Pins);
 
-    if (bUsed)
+    if (!bInputMixer && MixerList->MixerListCount == 1)
     {
-        // store mixer info in list
-        if (!bInputMixer && MixerList->MixerListCount == 1)
-        {
-            //FIXME preferred device should be inserted at front
-            //windows always inserts output mixer in front
-            InsertHeadList(&MixerList->MixerList, &MixerInfo->Entry);
-        }
-        else
-        {
-            InsertTailList(&MixerList->MixerList, &MixerInfo->Entry);
-        }
-        MixerList->MixerListCount++;
-        DPRINT("New MixerCount %lu\n", MixerList->MixerListCount);
+        /* FIXME preferred device should be inserted at front
+         * windows always inserts output mixer in front
+         */
+        InsertHeadList(&MixerList->MixerList, &MixerInfo->Entry);
     }
     else
     {
-        // failed to create a mixer topology
-        MMixerFreeMixerInfo(MixerContext, MixerInfo);
+        /* insert at back */
+        InsertTailList(&MixerList->MixerList, &MixerInfo->Entry);
     }
 
-    // done
+    /* increment mixer count */
+    MixerList->MixerListCount++;
+
+    /* done */
     return Status;
 }
 
@@ -1020,71 +1020,64 @@ MMixerSetupFilter(
     IN LPMIXER_DATA MixerData,
     IN PULONG DeviceCount)
 {
-    PKSMULTIPLE_ITEM NodeTypes = NULL, NodeConnections = NULL;
     MIXER_STATUS Status;
-    ULONG PinCount;
+    PTOPOLOGY Topology;
     ULONG NodeIndex;
 
-    // get number of pins
-    PinCount = MMixerGetFilterPinCount(MixerContext, MixerData->hDevice);
-    ASSERT(PinCount);
-    DPRINT("NumOfPins: %lu\n", PinCount);
-
-    // get filter node types
-    Status = MMixerGetFilterTopologyProperty(MixerContext, MixerData->hDevice, KSPROPERTY_TOPOLOGY_NODES, &NodeTypes);
-    if (Status != MM_STATUS_SUCCESS)
+    /* check if topology has already been built */
+    if (MixerData->Topology == NULL)
     {
-        // failed
-        return Status;
-    }
+        /* build topology */
+        Status = MMixerBuildTopology(MixerContext, MixerData, &Topology);
 
-    // get filter node connections
-    Status = MMixerGetFilterTopologyProperty(MixerContext, MixerData->hDevice, KSPROPERTY_TOPOLOGY_CONNECTIONS, &NodeConnections);
-    if (Status != MM_STATUS_SUCCESS)
+        if (Status != MM_STATUS_SUCCESS)
+        {
+            /* failed to build topology */
+            return Status;
+        }
+
+        /* store topology */
+        MixerData->Topology = Topology;
+    }
+    else
     {
-        // failed
-        MixerContext->Free(NodeTypes);
-        return Status;
+        /* re-use topology */
+        Topology = MixerData->Topology;
     }
 
-    // check if the filter has an wave out node
-
-    NodeIndex = MMixerGetIndexOfGuid(NodeTypes, &KSNODETYPE_DAC);
+    /* check if the filter has an wave out node */
+    NodeIndex = MMixerGetNodeIndexFromGuid(Topology, &KSNODETYPE_DAC);
     if (NodeIndex != MAXULONG)
     {
-        // it has
-        Status = MMixerInitializeFilter(MixerContext, MixerList, MixerData, NodeTypes, NodeConnections, PinCount, NodeIndex, FALSE);
-        DPRINT("MMixerInitializeFilter Status %u\n", Status);
-        // check for success
+        /* it has */
+        Status = MMixerInitializeFilter(MixerContext, MixerList, MixerData, Topology, NodeIndex, FALSE);
+
+        /* check for success */
         if (Status == MM_STATUS_SUCCESS)
         {
-            // increment mixer count
+            /* increment mixer count */
             (*DeviceCount)++;
         }
 
     }
 
-    // check if the filter has an wave in node
-    NodeIndex = MMixerGetIndexOfGuid(NodeTypes, &KSNODETYPE_ADC);
+    /* check if the filter has an wave in node */
+    NodeIndex = MMixerGetNodeIndexFromGuid(Topology, &KSNODETYPE_ADC);
     if (NodeIndex != MAXULONG)
     {
-        // it has
-        Status = MMixerInitializeFilter(MixerContext, MixerList, MixerData, NodeTypes, NodeConnections, PinCount, NodeIndex, TRUE);
-        DPRINT("MMixerInitializeFilter Status %u\n", Status);
-        // check for success
+        /* it has */
+        Status = MMixerInitializeFilter(MixerContext, MixerList, MixerData, Topology, NodeIndex, TRUE);
+
+        /* check for success */
         if (Status == MM_STATUS_SUCCESS)
         {
-            // increment mixer count
+            /* increment mixer count */
             (*DeviceCount)++;
         }
 
     }
 
-    //free resources
-    MixerContext->Free((PVOID)NodeTypes);
-    MixerContext->Free((PVOID)NodeConnections);
-
-    // done
+    /* done */
     return Status;
 }
 
@@ -1103,7 +1096,7 @@ MMixerAddEvent(
     EventData = (LPEVENT_ITEM)MixerContext->AllocEventData(sizeof(LIST_ENTRY));
     if (!EventData)
     {
-        // not enough memory
+        /* not enough memory */
         return MM_STATUS_NO_MEMORY;
     }
 
@@ -1118,12 +1111,12 @@ MMixerAddEvent(
     Status = MixerContext->Control(MixerInfo->hMixer, IOCTL_KS_ENABLE_EVENT, (PVOID)&Property, sizeof(KSP_NODE), (PVOID)EventData, sizeof(KSEVENTDATA), &BytesReturned);
     if (Status != MM_STATUS_SUCCESS)
     {
-        // failed to add event
+        /* failed to add event */
         MixerContext->FreeEventData(EventData);
         return Status;
     }
 
-    //store event
+    /* store event */
     InsertTailList(&MixerInfo->EventList, &EventData->Entry);
     return Status;
 }
@@ -1138,12 +1131,12 @@ MMixerAddEvents(
     MIXER_STATUS Status;
     LPGUID Guid;
 
-    // get filter node types
+    /* get filter node types */
     Status = MMixerGetFilterTopologyProperty(MixerContext, MixerInfo->hMixer, KSPROPERTY_TOPOLOGY_NODES, &NodeTypes);
 
     if (Status != MM_STATUS_SUCCESS)
     {
-        // failed
+        /* failed */
         return Status;
     }
 
@@ -1152,13 +1145,14 @@ MMixerAddEvents(
         Guid = MMixerGetNodeType(NodeTypes, Index);
         if (IsEqualGUID(&KSNODETYPE_VOLUME, Guid) || IsEqualGUID(&KSNODETYPE_MUTE, Guid))
         {
-            //add an event for volume / mute controls
-            //TODO: extra control types
+            /* add an event for volume / mute controls
+             * TODO: support extra control types
+             */
             MMixerAddEvent(MixerContext, MixerInfo, Index);
         }
     }
 
-    // free node types
+    /* free node types */
     MixerContext->Free(NodeTypes);
 
     return MM_STATUS_SUCCESS;
index 955fd27..9a2739e 100644 (file)
@@ -19,15 +19,15 @@ MMixerGetFilterPinCount(
     MIXER_STATUS Status;
     ULONG NumPins, BytesReturned;
 
-    // setup property request
+    /* setup property request */
     Pin.Flags = KSPROPERTY_TYPE_GET;
     Pin.Set = KSPROPSETID_Pin;
     Pin.Id = KSPROPERTY_PIN_CTYPES;
 
-    // query pin count
+    /* query pin count */
     Status = MixerContext->Control(hMixer, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSPROPERTY), (PVOID)&NumPins, sizeof(ULONG), (PULONG)&BytesReturned);
 
-    // check for success
+    /* check for success */
     if (Status != MM_STATUS_SUCCESS)
         return 0;
 
@@ -46,43 +46,43 @@ MMixerGetFilterTopologyProperty(
     MIXER_STATUS Status;
     ULONG BytesReturned;
 
-    // setup property request
+    /* setup property request */
     Property.Id = PropertyId;
     Property.Flags = KSPROPERTY_TYPE_GET;
     Property.Set = KSPROPSETID_Topology;
 
-    // query for the size
+    /* query for the size */
     Status = MixerContext->Control(hMixer, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), NULL, 0, &BytesReturned);
 
     if (Status != MM_STATUS_MORE_ENTRIES)
         return Status;
 
-    //sanity check
+    /* sanity check */
     ASSERT(BytesReturned);
 
-    // allocate an result buffer
+    /* allocate an result buffer */
     MultipleItem = (PKSMULTIPLE_ITEM)MixerContext->Alloc(BytesReturned);
 
     if (!MultipleItem)
     {
-        // not enough memory
+        /* not enough memory */
         return MM_STATUS_NO_MEMORY;
     }
 
-    // query again with allocated buffer
+    /* query again with allocated buffer */
     Status = MixerContext->Control(hMixer, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)MultipleItem, BytesReturned, &BytesReturned);
 
     if (Status != MM_STATUS_SUCCESS)
     {
-        // failed
+        /* failed */
         MixerContext->Free((PVOID)MultipleItem);
         return Status;
     }
 
-    // store result
+    /* store result */
     *OutMultipleItem = MultipleItem;
 
-    // done
+    /* done */
     return Status;
 }
 
@@ -109,24 +109,23 @@ MMixerGetPhysicalConnection(
 
     if (Status == MM_STATUS_UNSUCCESSFUL)
     {
-        // pin does not have a physical connection
+        /* pin does not have a physical connection */
         return Status;
     }
     DPRINT("Status %u BytesReturned %lu\n", Status, BytesReturned);
     Connection = (PKSPIN_PHYSICALCONNECTION)MixerContext->Alloc(BytesReturned);
     if (!Connection)
     {
-        // not enough memory
+        /* not enough memory */
         return MM_STATUS_NO_MEMORY;
     }
 
-    // query the pin for the physical connection
+    /* query the pin for the physical connection */
     Status = MixerContext->Control(hMixer, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSP_PIN), (PVOID)Connection, BytesReturned, &BytesReturned);
     if (Status != MM_STATUS_SUCCESS)
     {
-        // failed to query the physical connection
+        /* failed to query the physical connection */
         MixerContext->Free(Connection);
-        DPRINT("Status %u\n", Status);
         return Status;
     }
 
@@ -141,73 +140,76 @@ MMixerGetControlTypeFromTopologyNode(
 {
     if (IsEqualGUIDAligned(NodeType, (LPGUID)&KSNODETYPE_AGC))
     {
-        // automatic gain control
+        /* automatic gain control */
         return MIXERCONTROL_CONTROLTYPE_ONOFF;
     }
     else if (IsEqualGUIDAligned(NodeType, (LPGUID)&KSNODETYPE_LOUDNESS))
     {
-        // loudness control
+        /* loudness control */
         return MIXERCONTROL_CONTROLTYPE_LOUDNESS;
     }
-    else if (IsEqualGUIDAligned(NodeType, (LPGUID)&KSNODETYPE_MUTE ))
+    else if (IsEqualGUIDAligned(NodeType, (LPGUID)&KSNODETYPE_MUTE))
     {
-        // mute control
+        /* mute control */
         return MIXERCONTROL_CONTROLTYPE_MUTE;
     }
     else if (IsEqualGUIDAligned(NodeType, (LPGUID)&KSNODETYPE_TONE))
     {
-        // tpne control
-        //FIXME
-        // MIXERCONTROL_CONTROLTYPE_ONOFF if KSPROPERTY_AUDIO_BASS_BOOST is supported
-        // MIXERCONTROL_CONTROLTYPE_BASS if KSPROPERTY_AUDIO_BASS is supported
-        // MIXERCONTROL_CONTROLTYPE_TREBLE if KSPROPERTY_AUDIO_TREBLE is supported
+        /* tone control
+         * FIXME
+         * MIXERCONTROL_CONTROLTYPE_ONOFF if KSPROPERTY_AUDIO_BASS_BOOST is supported
+         * MIXERCONTROL_CONTROLTYPE_BASS if KSPROPERTY_AUDIO_BASS is supported
+         * MIXERCONTROL_CONTROLTYPE_TREBLE if KSPROPERTY_AUDIO_TREBLE is supported
+         */
         UNIMPLEMENTED;
         return MIXERCONTROL_CONTROLTYPE_ONOFF;
     }
     else if (IsEqualGUIDAligned(NodeType, (LPGUID)&KSNODETYPE_VOLUME))
     {
-        // volume control
+        /* volume control */
         return MIXERCONTROL_CONTROLTYPE_VOLUME;
     }
     else if (IsEqualGUIDAligned(NodeType, (LPGUID)&KSNODETYPE_PEAKMETER))
     {
-        // peakmeter control
+        /* peakmeter control */
         return MIXERCONTROL_CONTROLTYPE_PEAKMETER;
     }
     else if (IsEqualGUIDAligned(NodeType, (LPGUID)&KSNODETYPE_MUX))
     {
-        // mux control
+        /* mux control */
         return MIXERCONTROL_CONTROLTYPE_MUX;
     }
     else if (IsEqualGUIDAligned(NodeType, (LPGUID)&KSNODETYPE_MUX))
     {
-        // mux control
+        /* mux control */
         return MIXERCONTROL_CONTROLTYPE_MUX;
     }
     else if (IsEqualGUIDAligned(NodeType, (LPGUID)&KSNODETYPE_STEREO_WIDE))
     {
-        // stero wide control
+        /* stero wide control */
         return MIXERCONTROL_CONTROLTYPE_FADER;
     }
     else if (IsEqualGUIDAligned(NodeType, (LPGUID)&KSNODETYPE_CHORUS))
     {
-        // chorus control
+        /* chorus control */
         return MIXERCONTROL_CONTROLTYPE_FADER;
     }
     else if (IsEqualGUIDAligned(NodeType, (LPGUID)&KSNODETYPE_REVERB))
     {
-        // reverb control
+        /* reverb control */
         return MIXERCONTROL_CONTROLTYPE_FADER;
     }
     else if (IsEqualGUIDAligned(NodeType, (LPGUID)&KSNODETYPE_SUPERMIX))
     {
-        // supermix control
-        // MIXERCONTROL_CONTROLTYPE_MUTE if KSPROPERTY_AUDIO_MUTE is supported 
+        /* supermix control
+         * MIXERCONTROL_CONTROLTYPE_MUTE if KSPROPERTY_AUDIO_MUTE is supported 
+         */
         UNIMPLEMENTED;
         return MIXERCONTROL_CONTROLTYPE_VOLUME;
     }
-    //TODO
-    //check for other supported node types
+    /* TODO
+     * check for other supported node types
+     */
     //UNIMPLEMENTED
     return 0;
 }
@@ -279,4 +281,3 @@ MMixerGetPinInstanceCount(
     ASSERT(Status == MM_STATUS_SUCCESS);
     return PinInstances.CurrentCount;
 }
-
index 4ef2ea9..9b317ce 100644 (file)
@@ -17,16 +17,16 @@ MMixerGetCount(
     PMIXER_LIST MixerList;
     MIXER_STATUS Status;
 
-    // verify mixer context
+    /* verify mixer context */
     Status = MMixerVerifyContext(MixerContext);
 
     if (Status != MM_STATUS_SUCCESS)
     {
-        // invalid context passed
+        /* invalid context passed */
         return Status;
     }
 
-    // grab mixer list
+    /* grab mixer list */
     MixerList = (PMIXER_LIST)MixerContext->MixerContext;
 
     // return number of mixers
@@ -42,16 +42,16 @@ MMixerGetCapabilities(
     MIXER_STATUS Status;
     LPMIXER_INFO MixerInfo;
 
-    // verify mixer context
+    /* verify mixer context */
     Status = MMixerVerifyContext(MixerContext);
 
     if (Status != MM_STATUS_SUCCESS)
     {
-        // invalid context passed
+        /* invalid context passed */
         return Status;
     }
 
-    // get mixer info
+    /* get mixer info */
     MixerInfo = MMixerGetMixerInfoByIndex(MixerContext, MixerIndex);
 
     if (!MixerInfo)
@@ -83,29 +83,30 @@ MMixerOpen(
     MIXER_STATUS Status;
     LPMIXER_INFO MixerInfo;
 
-    // verify mixer context
+    /* verify mixer context */
     Status = MMixerVerifyContext(MixerContext);
 
     if (Status != MM_STATUS_SUCCESS)
     {
-        // invalid context passed
+        /* invalid context passed */
         return Status;
     }
 
     MixerInfo = (LPMIXER_INFO)MMixerGetMixerInfoByIndex(MixerContext, MixerId);
     if (!MixerInfo)
     {
-        // invalid mixer id
+        /* invalid mixer id */
         return MM_STATUS_INVALID_PARAMETER;
     }
 
-    // FIXME
-    // handle event notification
+    /* FIXME
+     * handle event notification
+     */
 
     Status = MMixerAddEvents(MixerContext, MixerInfo);
 
 
-    // store result
+    /* store result */
     *MixerHandle = (HANDLE)MixerInfo;
 
     return MM_STATUS_SUCCESS;
@@ -122,26 +123,26 @@ MMixerGetLineInfo(
     LPMIXER_INFO MixerInfo;
     LPMIXERLINE_EXT MixerLineSrc;
 
-    // verify mixer context
+    /* verify mixer context */
     Status = MMixerVerifyContext(MixerContext);
 
     if (Status != MM_STATUS_SUCCESS)
     {
-        // invalid context passed
+        /* invalid context passed */
         return Status;
     }
 
-    // clear hmixer from flags
+    /* clear hmixer from flags */
     Flags &=~MIXER_OBJECTF_HMIXER;
 
     if (Flags == MIXER_GETLINEINFOF_DESTINATION)
     {
-        // cast to mixer info
+        /* cast to mixer info */
         MixerInfo = (LPMIXER_INFO)MixerHandle;
 
         if (MixerLine->dwDestination != 0)
         {
-            // destination line member must be zero
+            /* destination line member must be zero */
             return MM_STATUS_INVALID_PARAMETER;
         }
 
@@ -153,7 +154,7 @@ MMixerGetLineInfo(
     }
     else if (Flags == MIXER_GETLINEINFOF_SOURCE)
     {
-        // cast to mixer info
+        /* cast to mixer info */
         MixerInfo = (LPMIXER_INFO)MixerHandle;
 
 
@@ -162,9 +163,9 @@ MMixerGetLineInfo(
 
         if (MixerLine->dwSource >= MixerLineSrc->Line.cConnections)
         {
-            DPRINT1("dwSource %u > Destinations %u\n", MixerLine->dwSource, MixerLineSrc->Line.cConnections);
+            DPRINT("dwSource %u > Destinations %u\n", MixerLine->dwSource, MixerLineSrc->Line.cConnections);
 
-            // invalid parameter
+            /* invalid parameter */
             return MM_STATUS_INVALID_PARAMETER;
         }
 
@@ -179,13 +180,13 @@ MMixerGetLineInfo(
     }
     else if (Flags == MIXER_GETLINEINFOF_LINEID)
     {
-        // cast to mixer info
+        /* cast to mixer info */
         MixerInfo = (LPMIXER_INFO)MixerHandle;
 
         MixerLineSrc = MMixerGetSourceMixerLineByLineId(MixerInfo, MixerLine->dwLineID);
         if (!MixerLineSrc)
         {
-            // invalid parameter
+            /* invalid parameter */
             return MM_STATUS_INVALID_PARAMETER;
         }
 
@@ -195,7 +196,7 @@ MMixerGetLineInfo(
     }
     else if (Flags == MIXER_GETLINEINFOF_COMPONENTTYPE)
     {
-        // cast to mixer info
+        /* cast to mixer info */
         MixerInfo = (LPMIXER_INFO)MixerHandle;
 
         MixerLineSrc = MMixerGetSourceMixerLineByComponentType(MixerInfo, MixerLine->dwComponentType);
@@ -228,12 +229,12 @@ MMixerGetLineControls(
     MIXER_STATUS Status;
     ULONG Index;
 
-    // verify mixer context
+    /* verify mixer context */
     Status = MMixerVerifyContext(MixerContext);
 
     if (Status != MM_STATUS_SUCCESS)
     {
-        // invalid context passed
+        /* invalid context passed */
         return Status;
     }
 
@@ -241,31 +242,31 @@ MMixerGetLineControls(
 
     if (Flags == MIXER_GETLINECONTROLSF_ALL)
     {
-        // cast to mixer info
+        /* cast to mixer info */
         MixerInfo = (LPMIXER_INFO)MixerHandle;
 
         MixerLineSrc = MMixerGetSourceMixerLineByLineId(MixerInfo, MixerLineControls->dwLineID);
 
         if (!MixerLineSrc)
         {
-            // invalid line id
+            /* invalid line id */
             return MM_STATUS_INVALID_PARAMETER;
         }
-        // copy line control(s)
+        /* copy line control(s) */
         MixerContext->Copy(MixerLineControls->pamxctrl, MixerLineSrc->LineControls, min(MixerLineSrc->Line.cControls, MixerLineControls->cControls) * sizeof(MIXERCONTROLW));
 
         return MM_STATUS_SUCCESS;
     }
     else if (Flags == MIXER_GETLINECONTROLSF_ONEBYTYPE)
     {
-        // cast to mixer info
+        /* cast to mixer info */
         MixerInfo = (LPMIXER_INFO)MixerHandle;
 
         MixerLineSrc = MMixerGetSourceMixerLineByLineId(MixerInfo, MixerLineControls->dwLineID);
 
         if (!MixerLineSrc)
         {
-            // invalid line id
+            /* invalid line id */
             return MM_STATUS_INVALID_PARAMETER;
         }
 
@@ -277,7 +278,7 @@ MMixerGetLineControls(
             DPRINT("dwControlType %x\n", MixerLineSrc->LineControls[Index].dwControlType);
             if (MixerLineControls->dwControlType == MixerLineSrc->LineControls[Index].dwControlType)
             {
-                // found a control with that type
+                /* found a control with that type */
                 MixerContext->Copy(MixerLineControls->pamxctrl, &MixerLineSrc->LineControls[Index], sizeof(MIXERCONTROLW));
                 return MM_STATUS_SUCCESS;
             }
@@ -287,18 +288,18 @@ MMixerGetLineControls(
     }
     else if (Flags == MIXER_GETLINECONTROLSF_ONEBYID)
     {
-        // cast to mixer info
+        /* cast to mixer info */
         MixerInfo = (LPMIXER_INFO)MixerHandle;
 
         Status = MMixerGetMixerControlById(MixerInfo, MixerLineControls->dwControlID, NULL, &MixerControl, NULL);
 
         if (Status != MM_STATUS_SUCCESS)
         {
-            // invalid parameter
+            /* invalid parameter */
             return MM_STATUS_INVALID_PARAMETER;
         }
 
-        // copy the controls
+        /* copy the controls */
         MixerContext->Copy(MixerLineControls->pamxctrl, MixerControl, sizeof(MIXERCONTROLW));
         return MM_STATUS_SUCCESS;
     }
@@ -320,25 +321,25 @@ MMixerSetControlDetails(
     LPMIXERLINE_EXT MixerLine;
     LPMIXERCONTROLW MixerControl;
 
-    // verify mixer context
+    /* verify mixer context */
     Status = MMixerVerifyContext(MixerContext);
 
     if (Status != MM_STATUS_SUCCESS)
     {
-        // invalid context passed
+        /* invalid context passed */
         return Status;
     }
 
-    // get mixer info
+    /* get mixer info */
     MixerInfo = (LPMIXER_INFO)MixerHandle;
 
-    // get mixer control
+    /* get mixer control */
      Status = MMixerGetMixerControlById(MixerInfo, MixerControlDetails->dwControlID, &MixerLine, &MixerControl, &NodeId);
 
-    // check for success
+    /* check for success */
     if (Status != MM_STATUS_SUCCESS)
     {
-        // failed to find control id
+        /* failed to find control id */
         return MM_STATUS_INVALID_PARAMETER;
     }
 
@@ -370,25 +371,25 @@ MMixerGetControlDetails(
     LPMIXERLINE_EXT MixerLine;
     LPMIXERCONTROLW MixerControl;
 
-    // verify mixer context
+    /* verify mixer context */
     Status = MMixerVerifyContext(MixerContext);
 
     if (Status != MM_STATUS_SUCCESS)
     {
-        // invalid context passed
+        /* invalid context passed */
         return Status;
     }
 
-    // get mixer info
+    /* get mixer info */
     MixerInfo = (LPMIXER_INFO)MixerHandle;
 
-    // get mixer control
+    /* get mixer control */
      Status = MMixerGetMixerControlById(MixerInfo, MixerControlDetails->dwControlID, &MixerLine, &MixerControl, &NodeId);
 
-    // check for success
+    /* check for success */
     if (Status != MM_STATUS_SUCCESS)
     {
-        // failed to find control id
+        /* failed to find control id */
         return MM_STATUS_INVALID_PARAMETER;
     }
 
@@ -423,7 +424,7 @@ MMixerInitialize(
 
     if (!MixerContext || !EnumFunction || !EnumContext)
     {
-        // invalid parameter
+        /* invalid parameter */
         return MM_STATUS_INVALID_PARAMETER;
     }
 
@@ -431,19 +432,19 @@ MMixerInitialize(
         !MixerContext->AllocEventData || !MixerContext->FreeEventData ||
         !MixerContext->Close || !MixerContext->OpenKey || !MixerContext->QueryKeyValue || !MixerContext->CloseKey)
     {
-        // invalid parameter
+        /* invalid parameter */
         return MM_STATUS_INVALID_PARAMETER;
     }
 
-    // allocate a mixer list
+    /* allocate a mixer list */
     MixerList = (PMIXER_LIST)MixerContext->Alloc(sizeof(MIXER_LIST));
     if (!MixerList)
     {
-        // no memory
+        /* no memory */
         return MM_STATUS_NO_MEMORY;
     }
 
-     //initialize mixer list
+     /* initialize mixer list */
      MixerList->MixerListCount = 0;
      MixerList->MixerDataCount = 0;
      MixerList->WaveInListCount = 0;
@@ -454,48 +455,49 @@ MMixerInitialize(
      InitializeListHead(&MixerList->WaveOutList);
 
 
-     // store mixer list
+     /* store mixer list */
      MixerContext->MixerContext = (PVOID)MixerList;
 
-    // start enumerating all available devices
+    /* start enumerating all available devices */
     Count = 0;
     DeviceIndex = 0;
 
     do
     {
-        // enumerate a device
+        /* enumerate a device */
         Status = EnumFunction(EnumContext, DeviceIndex, &DeviceName, &hMixer, &hKey);
 
         if (Status != MM_STATUS_SUCCESS)
         {
-            //check error code
+            /* check error code */
             if (Status == MM_STATUS_NO_MORE_DEVICES)
             {
-                // enumeration has finished
+                /* enumeration has finished */
                 break;
             }
             else
             {
                 DPRINT1("Failed to enumerate device %lu\n", DeviceIndex);
 
-                // TODO cleanup
+                /* TODO cleanup */
                 return Status;
             }
         }
         else
         {
-            // create a mixer data entry
+            /* create a mixer data entry */
             Status = MMixerCreateMixerData(MixerContext, MixerList, DeviceIndex, DeviceName, hMixer, hKey);
             if (Status != MM_STATUS_SUCCESS)
                 break;
         }
 
-        // increment device index
+        /* increment device index */
         DeviceIndex++;
     }while(TRUE);
 
-    //now all filters have been pre-opened
-    // lets enumerate the filters
+    /* now all filters have been pre-opened
+     * lets enumerate the filters
+     */
     Entry = MixerList->MixerData.Flink;
     while(Entry != &MixerList->MixerData)
     {
@@ -504,6 +506,6 @@ MMixerInitialize(
         Entry = Entry->Flink;
     }
 
-    // done
+    /* done */
     return MM_STATUS_SUCCESS;
 }
index 582868a..21d6551 100644 (file)
@@ -8,4 +8,5 @@
        <file>mixer.c</file>
        <file>sup.c</file>
        <file>wave.c</file>
+       <file>topology.c</file>
 </module>
index 1580c8a..489bd98 100644 (file)
 #define YDEBUG
 #include <debug.h>
 
+typedef struct __TOPOLOGY_NODE__
+{
+    GUID NodeType;
+    ULONG NodeIndex;
+
+    ULONG NodeConnectedToCount;
+    struct __TOPOLOGY_NODE__ ** NodeConnectedTo;
+
+    ULONG NodeConnectedFromCount;
+    struct __TOPOLOGY_NODE__ ** NodeConnectedFrom;
+
+    ULONG PinConnectedFromCount;
+    PULONG PinConnectedFrom;
+
+    ULONG PinConnectedToCount;
+    PULONG PinConnectedTo;
+
+    ULONG Visited;
+    ULONG Reserved;
+}TOPOLOGY_NODE, *PTOPOLOGY_NODE;
+
+typedef struct
+{
+    ULONG PinId;
+
+    ULONG NodesConnectedToCount;
+    PTOPOLOGY_NODE * NodesConnectedTo;
+
+    ULONG NodesConnectedFromCount;
+    PTOPOLOGY_NODE * NodesConnectedFrom;
+
+    ULONG Visited;
+}PIN, *PPIN;
+
+
+typedef struct
+{
+    ULONG TopologyPinsCount;
+    PPIN TopologyPins;
+
+    ULONG TopologyNodesCount;
+    PTOPOLOGY_NODE TopologyNodes;
+
+}TOPOLOGY, *PTOPOLOGY;
+
+
 typedef struct
 {
     KSEVENTDATA EventData;
@@ -68,6 +114,7 @@ typedef struct
     HANDLE hDevice;
     HANDLE hDeviceInterfaceKey;
     LPWSTR DeviceName;
+    PTOPOLOGY Topology;
 }MIXER_DATA, *LPMIXER_DATA;
 
 typedef struct
@@ -273,9 +320,122 @@ MMixerInitializeWaveInfo(
     IN LPMIXER_DATA MixerData,
     IN LPWSTR DeviceName,
     IN ULONG bWaveIn,
-    IN ULONG PinId);
+    IN ULONG PinCount,
+    IN PULONG Pins);
 
 MIXER_STATUS
 MMixerAddEvents(
     IN PMIXER_CONTEXT MixerContext,
     IN OUT LPMIXER_INFO MixerInfo);
+
+/* topology.c */
+
+MIXER_STATUS
+MMixerCreateTopology(
+    IN PMIXER_CONTEXT MixerContext,
+    IN ULONG PinCount,
+    IN PKSMULTIPLE_ITEM NodeConnections,
+    IN PKSMULTIPLE_ITEM NodeTypes,
+    OUT PTOPOLOGY *OutTopology);
+
+VOID
+MMixerGetAllUpOrDownstreamPinsFromNodeIndex(
+    IN PMIXER_CONTEXT MixerContext,
+    IN PTOPOLOGY Topology,
+    IN ULONG NodeIndex,
+    IN ULONG bUpStream,
+    OUT PULONG OutPinsCount,
+    OUT PULONG OutPins);
+
+MIXER_STATUS
+MMixerGetAllUpOrDownstreamPinsFromPinIndex(
+    IN PMIXER_CONTEXT MixerContext,
+    IN PTOPOLOGY Topology,
+    IN ULONG PinIndex,
+    IN ULONG bUpStream,
+    OUT PULONG OutPinsCount,
+    OUT PULONG OutPins);
+
+VOID
+MMixerGetNextNodesFromPinIndex(
+    IN PMIXER_CONTEXT MixerContext,
+    IN PTOPOLOGY Topology,
+    IN ULONG PinIndex,
+    IN ULONG bUpStream,
+    OUT PULONG OutNodesCount,
+    OUT PULONG OutNodes);
+
+MIXER_STATUS
+MMixerAllocateTopologyPinArray(
+    IN PMIXER_CONTEXT MixerContext,
+    IN PTOPOLOGY Topology,
+    OUT PULONG * OutPins);
+
+MIXER_STATUS
+MMixerAllocateTopologyNodeArray(
+    IN PMIXER_CONTEXT MixerContext,
+    IN PTOPOLOGY Topology,
+    OUT PULONG * OutPins);
+
+VOID
+MMixerGetAllUpOrDownstreamNodesFromPinIndex(
+    IN PMIXER_CONTEXT MixerContext,
+    IN PTOPOLOGY Topology,
+    IN ULONG PinIndex,
+    IN ULONG bUpStream,
+    OUT PULONG OutNodesCount,
+    OUT PULONG OutNodes);
+
+VOID
+MMixerIsNodeTerminator(
+    IN PTOPOLOGY Topology,
+    IN ULONG NodeIndex,
+    OUT ULONG * bTerminator);
+
+VOID
+MMixerGetNextNodesFromNodeIndex(
+    IN PMIXER_CONTEXT MixerContext,
+    IN PTOPOLOGY Topology,
+    IN ULONG NodeIndex,
+    IN ULONG bUpStream,
+    OUT PULONG OutNodesCount,
+    OUT PULONG OutNodes);
+
+LPGUID
+MMixerGetNodeTypeFromTopology(
+    IN PTOPOLOGY Topology,
+    IN ULONG NodeIndex);
+
+MIXER_STATUS
+MMixerGetAllUpOrDownstreamNodesFromNodeIndex(
+    IN PMIXER_CONTEXT MixerContext,
+    IN PTOPOLOGY Topology,
+    IN ULONG NodeIndex,
+    IN ULONG bUpStream,
+    OUT PULONG OutNodesCount,
+    OUT PULONG OutNodes);
+
+MIXER_STATUS
+MMixerIsNodeConnectedToPin(
+    IN PMIXER_CONTEXT MixerContext,
+    IN PTOPOLOGY Topology,
+    IN ULONG NodeIndex,
+    IN ULONG PinId,
+    IN ULONG bUpStream,
+    OUT PULONG bConnected);
+
+ULONG
+MMixerGetNodeIndexFromGuid(
+    IN PTOPOLOGY Topology,
+    IN const GUID *NodeType);
+
+VOID
+MMixerSetTopologyNodeReserved(
+    IN PTOPOLOGY Topology,
+    IN ULONG NodeIndex);
+
+VOID
+MMixerIsTopologyNodeReserved(
+    IN PTOPOLOGY Topology,
+    IN ULONG NodeIndex,
+    OUT PULONG bReserved);
index e864d1d..90aee6e 100644 (file)
@@ -54,9 +54,10 @@ MMixerFreeMixerInfo(
     IN PMIXER_CONTEXT MixerContext,
     IN LPMIXER_INFO MixerInfo)
 {
-    //UNIMPLEMENTED
-    // FIXME
-    // free all lines
+    /* UNIMPLEMENTED
+     * FIXME
+     * free all lines
+     */
 
     MixerContext->Free((PVOID)MixerInfo);
 }
@@ -71,7 +72,7 @@ MMixerGetMixerInfoByIndex(
     PMIXER_LIST MixerList;
     ULONG Index = 0;
 
-    // get mixer list
+    /* get mixer list */
     MixerList = (PMIXER_LIST)MixerContext->MixerContext;
 
     if (!MixerList->MixerListCount)
@@ -86,7 +87,7 @@ MMixerGetMixerInfoByIndex(
         if (Index == MixerIndex)
             return MixerInfo;
 
-        // move to next mixer entry
+        /* move to next mixer entry */
         Index++;
         Entry = Entry->Flink;
     }
@@ -141,42 +142,6 @@ MMixerGetSourceMixerLineByLineId(
     return NULL;
 }
 
-ULONG
-MMixerGetIndexOfGuid(
-    PKSMULTIPLE_ITEM MultipleItem,
-    LPCGUID NodeType)
-{
-    ULONG Index;
-    LPGUID Guid;
-
-    Guid = (LPGUID)(MultipleItem+1);
-
-    /* iterate through node type array */
-    for(Index = 0; Index < MultipleItem->Count; Index++)
-    {
-        if (IsEqualGUIDAligned(NodeType, Guid))
-        {
-            /* found matching guid */
-            return Index;
-        }
-        Guid++;
-    }
-    return MAXULONG;
-}
-
-PKSTOPOLOGY_CONNECTION
-MMixerGetConnectionByIndex(
-    IN PKSMULTIPLE_ITEM MultipleItem,
-    IN ULONG Index)
-{
-    PKSTOPOLOGY_CONNECTION Descriptor;
-
-    ASSERT(Index < MultipleItem->Count);
-
-    Descriptor = (PKSTOPOLOGY_CONNECTION)(MultipleItem + 1);
-    return &Descriptor[Index];
-}
-
 LPGUID
 MMixerGetNodeType(
     IN PKSMULTIPLE_ITEM MultipleItem,
@@ -190,183 +155,6 @@ MMixerGetNodeType(
     return &NodeType[Index];
 }
 
-MIXER_STATUS
-MMixerGetNodeIndexes(
-    IN PMIXER_CONTEXT MixerContext,
-    IN PKSMULTIPLE_ITEM MultipleItem,
-    IN ULONG NodeIndex,
-    IN ULONG bNode,
-    IN ULONG bFrom,
-    OUT PULONG NodeReferenceCount,
-    OUT PULONG *NodeReference)
-{
-    ULONG Index, Count = 0;
-    PKSTOPOLOGY_CONNECTION Connection;
-    PULONG Refs;
-
-    // KSMULTIPLE_ITEM is followed by several KSTOPOLOGY_CONNECTION
-    Connection = (PKSTOPOLOGY_CONNECTION)(MultipleItem + 1);
-
-    // first count all referenced nodes
-    for(Index = 0; Index < MultipleItem->Count; Index++)
-    {
-        if (bNode)
-        {
-            if (bFrom)
-            {
-                if (Connection->FromNode == NodeIndex)
-                {
-                    // node id has a connection
-                    Count++;
-                }
-            }
-            else
-            {
-                if (Connection->ToNode == NodeIndex)
-                {
-                    // node id has a connection
-                    Count++;
-                }
-            }
-        }
-        else
-        {
-            if (bFrom)
-            {
-                if (Connection->FromNodePin == NodeIndex && Connection->FromNode == KSFILTER_NODE)
-                {
-                    // node id has a connection
-                    Count++;
-                }
-            }
-            else
-            {
-                if (Connection->ToNodePin == NodeIndex && Connection->ToNode == KSFILTER_NODE)
-                {
-                    // node id has a connection
-                    Count++;
-                }
-            }
-        }
-
-
-        // move to next connection
-        Connection++;
-    }
-
-    if (!Count)
-    {
-        *NodeReferenceCount = 0;
-        *NodeReference = NULL;
-        return MM_STATUS_SUCCESS;
-    }
-
-    ASSERT(Count != 0);
-
-    /* now allocate node index array */
-    Refs = (PULONG)MixerContext->Alloc(sizeof(ULONG) * Count);
-    if (!Refs)
-    {
-        // not enough memory
-        return MM_STATUS_NO_MEMORY;
-    }
-
-    Count = 0;
-    Connection = (PKSTOPOLOGY_CONNECTION)(MultipleItem + 1);
-    for(Index = 0; Index < MultipleItem->Count; Index++)
-    {
-        if (bNode)
-        {
-            if (bFrom)
-            {
-                if (Connection->FromNode == NodeIndex)
-                {
-                    /* node id has a connection */
-                    Refs[Count] = Index;
-                    Count++;
-                }
-            }
-            else
-            {
-                if (Connection->ToNode == NodeIndex)
-                {
-                    /* node id has a connection */
-                    Refs[Count] = Index;
-                    Count++;
-                }
-            }
-        }
-        else
-        {
-            if (bFrom)
-            {
-                if (Connection->FromNodePin == NodeIndex && Connection->FromNode == KSFILTER_NODE)
-                {
-                    /* node id has a connection */
-                    Refs[Count] = Index;
-                    Count++;
-                }
-            }
-            else
-            {
-                if (Connection->ToNodePin == NodeIndex && Connection->ToNode == KSFILTER_NODE)
-                {
-                    /* node id has a connection */
-                    Refs[Count] = Index;
-                    Count++;
-                }
-            }
-        }
-
-        /* move to next connection */
-        Connection++;
-    }
-
-    /* store result */
-    *NodeReference = Refs;
-    *NodeReferenceCount = Count;
-
-    return MM_STATUS_SUCCESS;
-}
-
-MIXER_STATUS
-MMixerGetTargetPins(
-    IN PMIXER_CONTEXT MixerContext,
-    IN PKSMULTIPLE_ITEM NodeTypes,
-    IN PKSMULTIPLE_ITEM NodeConnections,
-    IN ULONG NodeIndex,
-    IN ULONG bUpDirection,
-    OUT PULONG Pins,
-    IN ULONG PinCount)
-{
-    ULONG NodeConnectionCount, Index;
-    MIXER_STATUS Status;
-    PULONG NodeConnection;
-
-    // sanity check */
-    ASSERT(NodeIndex != (ULONG)-1);
-
-    /* get all node indexes referenced by that pin */
-    if (bUpDirection)
-        Status = MMixerGetNodeIndexes(MixerContext, NodeConnections, NodeIndex, TRUE, FALSE, &NodeConnectionCount, &NodeConnection);
-    else
-        Status = MMixerGetNodeIndexes(MixerContext, NodeConnections, NodeIndex, TRUE, TRUE, &NodeConnectionCount, &NodeConnection);
-
-    //DPRINT("NodeIndex %u Status %x Count %u\n", NodeIndex, Status, NodeConnectionCount);
-
-    if (Status == MM_STATUS_SUCCESS)
-    {
-        for(Index = 0; Index < NodeConnectionCount; Index++)
-        {
-            Status = MMixerGetTargetPinsByNodeConnectionIndex(MixerContext, NodeConnections, NodeTypes, bUpDirection, NodeConnection[Index], PinCount, Pins);
-            ASSERT(Status == STATUS_SUCCESS);
-        }
-        MixerContext->Free((PVOID)NodeConnection);
-    }
-
-    return Status;
-}
-
 LPMIXERLINE_EXT
 MMixerGetSourceMixerLineByComponentType(
     LPMIXER_INFO MixerInfo,
@@ -482,7 +270,7 @@ MMixerSetGetMuteControlDetails(
     }
     else
     {
-        // FIXME notify wdmaud clients MM_MIXM_LINE_CHANGE dwLineID
+        /* FIXME notify wdmaud clients MM_MIXM_LINE_CHANGE dwLineID */
     }
 
     return Status;
@@ -590,7 +378,7 @@ MMixerGetDataByDeviceName(
         MixerData = (LPMIXER_DATA)CONTAINING_RECORD(Entry, MIXER_DATA, Entry);
         if (wcsicmp(&DeviceName[2], &MixerData->DeviceName[2]) == 0)
         {
-            // found entry
+            /* found entry */
             return MixerData;
         }
         Entry = Entry->Flink;
@@ -617,6 +405,9 @@ MMixerCreateMixerData(
     MixerData->DeviceName = DeviceName;
     MixerData->hDevice = hDevice;
     MixerData->hDeviceInterfaceKey = hKey;
+    MixerData->Topology = NULL;
+
+
 
     InsertTailList(&MixerList->MixerData, &MixerData->Entry);
     MixerList->MixerDataCount++;
@@ -638,16 +429,16 @@ MMixerGetDeviceName(
     Status = MixerContext->QueryKeyValue(hKey, L"FriendlyName", (PVOID*)&Name, &Length, &Type);
     if (Status == MM_STATUS_SUCCESS)
     {
-        // copy device name
+        /* copy device name */
         MixerContext->Copy(MixerInfo->MixCaps.szPname, Name, min(wcslen(Name), MAXPNAMELEN-1) * sizeof(WCHAR));
 
-        // make sure its null terminated
+        /* make sure its null terminated */
         MixerInfo->MixCaps.szPname[MAXPNAMELEN-1] = L'\0';
 
-        // free device name
+        /* free device name */
         MixerContext->Free(Name);
 
-        // done
+        /* done */
         return Status;
     }
 
@@ -658,13 +449,13 @@ MMixerGetDeviceName(
     Status = MixerContext->QueryKeyValue(hKey, L"FriendlyName", (PVOID*)&Name, &Length, &Type);
     if (Status == MM_STATUS_SUCCESS)
     {
-        // copy device name
+        /* copy device name */
         MixerContext->Copy(MixerInfo->MixCaps.szPname, Name, min(wcslen(Name), MAXPNAMELEN-1) * sizeof(WCHAR));
 
-        // make sure its null terminated
+        /* make sure its null terminated */
         MixerInfo->MixCaps.szPname[MAXPNAMELEN-1] = L'\0';
 
-        // free device name
+        /* free device name */
         MixerContext->Free(Name);
     }
 
diff --git a/reactos/lib/drivers/sound/mmixer/topology.c b/reactos/lib/drivers/sound/mmixer/topology.c
new file mode 100644 (file)
index 0000000..3c70ad3
--- /dev/null
@@ -0,0 +1,1097 @@
+/*
+ * 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 "priv.h"
+
+VOID
+MMixerPrintTopology(
+    PTOPOLOGY Topology)
+{
+    ULONG Index, SubIndex;
+
+    DPRINT1("Num Pins %lu NumNodes %lu\n", Topology->TopologyPinsCount, Topology->TopologyNodesCount);
+
+    for(Index = 0; Index < Topology->TopologyPinsCount; Index++)
+    {
+        DPRINT1("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++)
+            DPRINT1("NodesConnectedFrom Index %lu NodeId %lu\n", SubIndex, Topology->TopologyPins[Index].NodesConnectedFrom[SubIndex]->NodeIndex);
+
+        for(SubIndex = 0; SubIndex < Topology->TopologyPins[Index].NodesConnectedToCount; SubIndex++)
+            DPRINT1("NodesConnectedTo Index %lu NodeId %lu\n", SubIndex, Topology->TopologyPins[Index].NodesConnectedTo[SubIndex]->NodeIndex);
+    }
+
+    for(Index = 0; Index < Topology->TopologyNodesCount; Index++)
+    {
+        DPRINT1("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 */
+    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;
+    ULONG Count;
+
+    /* 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 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;
+    }
+
+    if (Count)
+    {
+        /* copy existing nodes */
+        MixerContext->Copy(NewNodes, OutNode->NodeConnectedFrom, sizeof(PTOPOLOGY) * Count);
+
+        /* release old nodes array */
+        MixerContext->Free(OutNode->NodeConnectedFrom);
+    }
+
+    /* add new topology node */
+    NewNodes[OutNode->NodeConnectedFromCount] = InNode;
+
+    /* replace old nodes array */
+    OutNode->NodeConnectedFrom = NewNodes;
+
+    /* 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
+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)
+    {
+        /* 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;
+    LPGUID Guids;
+    PKSTOPOLOGY_CONNECTION Connection;
+    MIXER_STATUS Status;
+
+    /* sanity check */
+    ASSERT(Topology->TopologyNodesCount == NodeTypes->Count);
+
+    /* get topology node types */
+    Guids = (LPGUID)(NodeTypes + 1);
+
+    /* 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);
+
+        /* 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;
+
+    /* mark them as empty */
+    *OutPinsCount = 0;
+
+    /* 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);
+
+        /* add them to node array */
+        MMixerAddPinIndexToArray(MixerContext, Node->NodeIndex, Topology->TopologyNodesCount, OutNodeCount, OutNodes);
+
+        /* recursively visit them */
+        MMixerGetUpOrDownstreamNodes(MixerContext, Topology, TopologyNodes[Index], bUpStream, OutNodeCount, OutNodes);
+    }
+
+    /* mark node as visited */
+    TopologyNode->Visited = TRUE;
+
+}
+
+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;
+    PPIN Pin;
+    PTOPOLOGY_NODE *TopologyNodes;
+
+    /* mark them as empty */
+    *OutPinsCount = 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++)
+    {
+        /* 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;
+}
+
+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 */
+    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;
+}
+
+LPGUID
+MMixerGetNodeTypeFromTopology(
+    IN PTOPOLOGY Topology,
+    IN ULONG NodeIndex)
+{
+    /* sanity check */
+    ASSERT(NodeIndex < Topology->TopologyNodesCount);
+
+    return &Topology->TopologyNodes[NodeIndex].NodeType;
+}
+
+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;
+}
+
+
+
+
+
index af29f45..ee720b0 100644 (file)
@@ -345,7 +345,8 @@ MMixerInitializeWaveInfo(
     IN LPMIXER_DATA MixerData,
     IN LPWSTR DeviceName,
     IN ULONG bWaveIn,
-    IN ULONG PinId)
+    IN ULONG PinCount,
+    IN PULONG Pins)
 {
     MIXER_STATUS Status;
     PKSMULTIPLE_ITEM MultipleItem;
@@ -356,11 +357,14 @@ MMixerInitializeWaveInfo(
     if (!WaveInfo)
         return MM_STATUS_NO_MEMORY;
 
+    /* FIXME support multiple pins for wave device */
+    ASSERT(PinCount == 1);
+
     /* initialize wave info */
     WaveInfo->DeviceId = MixerData->DeviceId;
-    WaveInfo->PinId = PinId;
+    WaveInfo->PinId = Pins[0];
 
-    // sanity check
+    /* sanity check */
     ASSERT(wcslen(DeviceName) < MAXPNAMELEN);
 
     /* copy device name */
@@ -388,7 +392,7 @@ MMixerInitializeWaveInfo(
     }
 
     /* get audio pin data ranges */
-    Status = MMixerGetAudioPinDataRanges(MixerContext, MixerData->hDevice, PinId, &MultipleItem);
+    Status = MMixerGetAudioPinDataRanges(MixerContext, MixerData->hDevice, Pins[0], &MultipleItem);
     if (Status != MM_STATUS_SUCCESS)
     {
         /* failed to get audio pin data ranges */
@@ -451,21 +455,21 @@ MMixerOpenWave(
     LPWAVE_INFO WaveInfo;
     ACCESS_MASK DesiredAccess = 0;
 
-    // verify mixer context
+    /* verify mixer context */
     Status = MMixerVerifyContext(MixerContext);
 
     if (Status != MM_STATUS_SUCCESS)
     {
-        // invalid context passed
+        /* invalid context passed */
         return Status;
     }
 
-    // grab mixer list
+    /* grab mixer list */
     MixerList = (PMIXER_LIST)MixerContext->MixerContext;
 
     if (WaveFormat->wFormatTag != WAVE_FORMAT_PCM)
     {
-        // not implemented
+        /* not implemented */
         return MM_STATUS_NOT_IMPLEMENTED;
     }
 
@@ -501,16 +505,16 @@ MMixerWaveInCapabilities(
     MIXER_STATUS Status;
     LPWAVE_INFO WaveInfo;
 
-    // verify mixer context
+    /* verify mixer context */
     Status = MMixerVerifyContext(MixerContext);
 
     if (Status != MM_STATUS_SUCCESS)
     {
-        // invalid context passed
+        /* invalid context passed */
         return Status;
     }
 
-    // grab mixer list
+    /* grab mixer list */
     MixerList = (PMIXER_LIST)MixerContext->MixerContext;
 
     /* find destination wave */
@@ -521,7 +525,7 @@ MMixerWaveInCapabilities(
         return MM_STATUS_UNSUCCESSFUL;
     }
 
-    //copy capabilities
+    /* copy capabilities */
     MixerContext->Copy(Caps, &WaveInfo->u.InCaps, sizeof(WAVEINCAPSW));
 
     return MM_STATUS_SUCCESS;
@@ -537,16 +541,16 @@ MMixerWaveOutCapabilities(
     MIXER_STATUS Status;
     LPWAVE_INFO WaveInfo;
 
-    // verify mixer context
+    /* verify mixer context */
     Status = MMixerVerifyContext(MixerContext);
 
     if (Status != MM_STATUS_SUCCESS)
     {
-        // invalid context passed
+        /* invalid context passed */
         return Status;
     }
 
-    // grab mixer list
+    /* grab mixer list */
     MixerList = (PMIXER_LIST)MixerContext->MixerContext;
 
     /* find destination wave */
@@ -557,7 +561,7 @@ MMixerWaveOutCapabilities(
         return MM_STATUS_UNSUCCESSFUL;
     }
 
-    //copy capabilities
+    /* copy capabilities */
     MixerContext->Copy(Caps, &WaveInfo->u.OutCaps, sizeof(WAVEOUTCAPSW));
 
     return MM_STATUS_SUCCESS;
@@ -570,16 +574,16 @@ MMixerGetWaveInCount(
     PMIXER_LIST MixerList;
     MIXER_STATUS Status;
 
-    // verify mixer context
+     /* verify mixer context */
     Status = MMixerVerifyContext(MixerContext);
 
     if (Status != MM_STATUS_SUCCESS)
     {
-        // invalid context passed
-        return 0;
+        /* invalid context passed */
+        return Status;
     }
 
-    // grab mixer list
+    /* grab mixer list */
     MixerList = (PMIXER_LIST)MixerContext->MixerContext;
 
     return MixerList->WaveInListCount;
@@ -592,16 +596,16 @@ MMixerGetWaveOutCount(
     PMIXER_LIST MixerList;
     MIXER_STATUS Status;
 
-    // verify mixer context
+    /* verify mixer context */
     Status = MMixerVerifyContext(MixerContext);
 
     if (Status != MM_STATUS_SUCCESS)
     {
-        // invalid context passed
-        return 0;
+        /* invalid context passed */
+        return Status;
     }
 
-    // grab mixer list
+    /* grab mixer list */
     MixerList = (PMIXER_LIST)MixerContext->MixerContext;
 
     return MixerList->WaveOutListCount;
@@ -637,16 +641,16 @@ MMixerGetWaveDevicePath(
     ULONG Length;
     MIXER_STATUS Status;
 
-    // verify mixer context
+    /* verify mixer context */
     Status = MMixerVerifyContext(MixerContext);
 
     if (Status != MM_STATUS_SUCCESS)
     {
-        // invalid context passed
+        /* invalid context passed */
         return Status;
     }
 
-    // grab mixer list
+    /* grab mixer list */
     MixerList = (PMIXER_LIST)MixerContext->MixerContext;
 
     /* find destination wave */