[AUDIO-BRINGUP]
[reactos.git] / lib / drivers / sound / mmixer / controls.c
index 0b2e499..e7bd288 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,
-    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]);
-
-       /* 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], 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;
-}
+const GUID KSNODETYPE_DESKTOP_MICROPHONE = {0xDFF21BE2, 0xF70F, 0x11D0, {0xB9, 0x17, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
+const GUID KSNODETYPE_LEGACY_AUDIO_CONNECTOR = {0xDFF21FE4, 0xF70F, 0x11D0, {0xB9, 0x17, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
+const GUID KSNODETYPE_TELEPHONE = {0xDFF21EE2, 0xF70F, 0x11D0, {0xB9, 0x17, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
+const GUID KSNODETYPE_PHONE_LINE = {0xDFF21EE1, 0xF70F, 0x11D0, {0xB9, 0x17, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
+const GUID KSNODETYPE_DOWN_LINE_PHONE = {0xDFF21EE3, 0xF70F, 0x11D0, {0xB9, 0x17, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
+const GUID KSNODETYPE_DESKTOP_SPEAKER = {0xDFF21CE4, 0xF70F, 0x11D0, {0xB9, 0x17, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
+const GUID KSNODETYPE_ROOM_SPEAKER = {0xDFF21CE5, 0xF70F, 0x11D0, {0xB9, 0x17, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
+const GUID KSNODETYPE_COMMUNICATION_SPEAKER = {0xDFF21CE6, 0xF70F, 0x11D0, {0xB9,0x17, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
+const GUID KSNODETYPE_HEADPHONES = {0xDFF21CE2, 0xF70F, 0x11D0, {0xB9, 0x17, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
+const GUID KSNODETYPE_HEAD_MOUNTED_DISPLAY_AUDIO = {0xDFF21CE3, 0xF70F, 0x11D0, {0xB9, 0x17, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
+const GUID KSNODETYPE_MICROPHONE = {0xDFF21BE1, 0xF70F, 0x11D0, {0xB9, 0x17, 0x00, 0xA0, 0xC9,0x22, 0x31, 0x96}};
+const GUID KSCATEGORY_AUDIO = {0x6994AD04L, 0x93EF, 0x11D0, {0xA3, 0xCC, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
+const GUID KSNODETYPE_SPDIF_INTERFACE = {0xDFF21FE5, 0xF70F, 0x11D0, {0xB9, 0x17, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
+const GUID KSNODETYPE_ANALOG_CONNECTOR = {0xDFF21FE1, 0xF70F, 0x11D0, {0xB9, 0x17, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
+const GUID KSNODETYPE_SPEAKER = {0xDFF21CE1, 0xF70F, 0x11D0, {0xB9, 0x17, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
+const GUID KSNODETYPE_CD_PLAYER = {0xDFF220E3, 0xF70F, 0x11D0, {0xB9, 0x17, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
+const GUID KSNODETYPE_SYNTHESIZER = {0xDFF220F3, 0xF70F, 0x11D0, {0xB9, 0x17, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
+const GUID KSNODETYPE_LINE_CONNECTOR = {0xDFF21FE3, 0xF70F, 0x11D0, {0xB9, 0x17, 0x00, 0xA0,0xC9, 0x22, 0x31, 0x96}};
+const GUID PINNAME_VIDEO_CAPTURE  = {0xfb6c4281, 0x353, 0x11d1, {0x90, 0x5f, 0x0, 0x0, 0xc0, 0xcc, 0x16, 0xba}};
 
 MIXER_STATUS
 MMixerAddMixerControl(
     IN PMIXER_CONTEXT MixerContext,
     IN LPMIXER_INFO MixerInfo,
-    IN HANDLE hDevice,
-    IN PKSMULTIPLE_ITEM NodeTypes,
+    IN HANDLE hMixer,
+    IN PTOPOLOGY Topology,
     IN ULONG NodeIndex,
     IN LPMIXERLINE_EXT MixerLine,
-    OUT LPMIXERCONTROLW MixerControl)
+    IN ULONG MaxChannels)
 {
     LPGUID NodeType;
     KSP_NODE Node;
     ULONG BytesReturned;
     MIXER_STATUS Status;
     LPWSTR Name;
+    LPMIXERCONTROL_EXT MixerControl;
+
+    /* allocate mixer control */
+    MixerControl = MixerContext->Alloc(sizeof(MIXERCONTROL_EXT));
+    if (!MixerControl)
+    {
+        /* no memory */
+        return MM_STATUS_NO_MEMORY;
+    }
+
 
     /* initialize mixer control */
-    MixerControl->cbStruct = sizeof(MIXERCONTROLW);
-    MixerControl->dwControlID = MixerInfo->ControlId;
+    MixerControl->hDevice = hMixer;
+    MixerControl->NodeID = NodeIndex;
+    MixerControl->ExtraData = NULL;
+
+    MixerControl->Control.cbStruct = sizeof(MIXERCONTROLW);
+    MixerControl->Control.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->Control.dwControlType = MMixerGetControlTypeFromTopologyNode(NodeType);
 
-    if (MixerControl->dwControlType == MIXERCONTROL_CONTROLTYPE_MUTE)
-    {
-        MixerControl->Bounds.dwMinimum = 0;
-        MixerControl->Bounds.dwMaximum = 1;
-    }
-    else if (MixerControl->dwControlType == MIXERCONTROL_CONTROLTYPE_VOLUME)
-    {
-        MixerControl->Bounds.dwMinimum = 0;
-        MixerControl->Bounds.dwMaximum = 0xFFFF;
-        MixerControl->Metrics.cSteps = 0xC0; //FIXME
-    }
+    MixerControl->Control.fdwControl = (MaxChannels > 1 ? 0 : MIXERCONTROL_CONTROLF_UNIFORM);
+    MixerControl->Control.cMultipleItems = 0;
 
     /* setup request to retrieve name */
     Node.NodeId = NodeIndex;
@@ -193,7 +78,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(hMixer, IOCTL_KS_PROPERTY, (PVOID)&Node, sizeof(KSP_NODE), NULL, 0, &BytesReturned);
 
     if (Status == MM_STATUS_MORE_ENTRIES)
     {
@@ -206,44 +91,66 @@ MMixerAddMixerControl(
         }
 
         /* get node name */
-        Status = MixerContext->Control(hDevice, IOCTL_KS_PROPERTY, (PVOID)&Node, sizeof(KSP_NODE), (LPVOID)Name, BytesReturned, &BytesReturned);
+        Status = MixerContext->Control(hMixer, IOCTL_KS_PROPERTY, (PVOID)&Node, sizeof(KSP_NODE), (LPVOID)Name, BytesReturned, &BytesReturned);
 
         if (Status == MM_STATUS_SUCCESS)
         {
-            MixerContext->Copy(MixerControl->szShortName, Name, (min(MIXER_SHORT_NAME_CHARS, wcslen(Name)+1)) * sizeof(WCHAR));
-            MixerControl->szShortName[MIXER_SHORT_NAME_CHARS-1] = L'\0';
+            MixerContext->Copy(MixerControl->Control.szShortName, Name, (min(MIXER_SHORT_NAME_CHARS, wcslen(Name)+1)) * sizeof(WCHAR));
+            MixerControl->Control.szShortName[MIXER_SHORT_NAME_CHARS-1] = L'\0';
 
-            MixerContext->Copy(MixerControl->szName, Name, (min(MIXER_LONG_NAME_CHARS, wcslen(Name)+1)) * sizeof(WCHAR));
-            MixerControl->szName[MIXER_LONG_NAME_CHARS-1] = L'\0';
+            MixerContext->Copy(MixerControl->Control.szName, Name, (min(MIXER_LONG_NAME_CHARS, wcslen(Name)+1)) * sizeof(WCHAR));
+            MixerControl->Control.szName[MIXER_LONG_NAME_CHARS-1] = L'\0';
         }
 
         /* free name buffer */
         MixerContext->Free(Name);
     }
 
+    /* increment control count */
     MixerInfo->ControlId++;
-#if 0
-    if (MixerControl->dwControlType == MIXERCONTROL_CONTROLTYPE_MUX)
+
+    /* insert control */
+    InsertTailList(&MixerLine->ControlsList, &MixerControl->Entry);
+
+    if (MixerControl->Control.dwControlType == MIXERCONTROL_CONTROLTYPE_MUX)
     {
-        KSNODEPROPERTY Property;
-        ULONG PinId = 2;
+        ULONG NodesCount;
+        PULONG Nodes;
 
-        /* setup the request */
-        RtlZeroMemory(&Property, sizeof(KSNODEPROPERTY));
+        /* allocate topology nodes array */
+        Status = MMixerAllocateTopologyNodeArray(MixerContext, Topology, &Nodes);
 
-        Property.NodeId = NodeIndex;
-        Property.Property.Id = KSPROPERTY_AUDIO_MUX_SOURCE;
-        Property.Property.Flags = KSPROPERTY_TYPE_SET;
-        Property.Property.Set = KSPROPSETID_Audio;
+        if (Status != MM_STATUS_SUCCESS)
+        {
+            /* out of memory */
+            return STATUS_NO_MEMORY;
+        }
 
-        /* get node volume level info */
-        Status = MixerContext->Control(hDevice, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSNODEPROPERTY), (PVOID)&PinId, sizeof(ULONG), &BytesReturned);
+        /* get connected node count */
+        MMixerGetNextNodesFromNodeIndex(MixerContext, Topology, NodeIndex, TRUE, &NodesCount, Nodes);
 
-        DPRINT1("Status %x NodeIndex %u PinId %u\n", Status, NodeIndex, PinId);
-        //DbgBreakPoint();
-    }else
-#endif
-    if (MixerControl->dwControlType == MIXERCONTROL_CONTROLTYPE_VOLUME)
+        /* TODO */
+        MixerContext->Free(Nodes);
+
+        /* setup mux bounds */
+        MixerControl->Control.Bounds.dwMinimum = 0;
+        MixerControl->Control.Bounds.dwMaximum = NodesCount - 1;
+        MixerControl->Control.Metrics.dwReserved[0] = NodesCount;
+        MixerControl->Control.cMultipleItems = NodesCount;
+        MixerControl->Control.fdwControl |= MIXERCONTROL_CONTROLF_UNIFORM | MIXERCONTROL_CONTROLF_MULTIPLE;
+    }
+    else if (MixerControl->Control.dwControlType == MIXERCONTROL_CONTROLTYPE_MUTE)
+    {
+        MixerControl->Control.Bounds.dwMinimum = 0;
+        MixerControl->Control.Bounds.dwMaximum = 1;
+    }
+    else if (MixerControl->Control.dwControlType == MIXERCONTROL_CONTROLTYPE_ONOFF)
+    {
+        /* only needs to set bounds */
+        MixerControl->Control.Bounds.dwMinimum = 0;
+        MixerControl->Control.Bounds.dwMaximum = 1;
+    }
+    else if (MixerControl->Control.dwControlType == MIXERCONTROL_CONTROLTYPE_VOLUME)
     {
         KSNODEPROPERTY_AUDIO_CHANNEL Property;
         ULONG Length;
@@ -251,6 +158,10 @@ MMixerAddMixerControl(
         PKSPROPERTY_MEMBERSHEADER Members;
         PKSPROPERTY_STEPPING_LONG Range;
 
+        MixerControl->Control.Bounds.dwMinimum = 0;
+        MixerControl->Control.Bounds.dwMaximum = 0xFFFF;
+        MixerControl->Control.Metrics.cSteps = 0xC0; /* FIXME */
+
         Length = sizeof(KSPROPERTY_DESCRIPTION) + sizeof(KSPROPERTY_MEMBERSHEADER) + sizeof(KSPROPERTY_STEPPING_LONG);
         Desc = (PKSPROPERTY_DESCRIPTION)MixerContext->Alloc(Length);
         ASSERT(Desc);
@@ -260,11 +171,11 @@ MMixerAddMixerControl(
 
         Property.NodeProperty.NodeId = NodeIndex;
         Property.NodeProperty.Property.Id = KSPROPERTY_AUDIO_VOLUMELEVEL;
-        Property.NodeProperty.Property.Flags = KSPROPERTY_TYPE_BASICSUPPORT;
+        Property.NodeProperty.Property.Flags = KSPROPERTY_TYPE_BASICSUPPORT | KSPROPERTY_TYPE_TOPOLOGY;
         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(hMixer, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSNODEPROPERTY_AUDIO_CHANNEL), Desc, Length, &BytesReturned);
 
         if (Status == MM_STATUS_SUCCESS)
         {
@@ -289,7 +200,7 @@ MMixerAddMixerControl(
                 Steps = MaxRange / Range->SteppingDelta + 1;
 
                 /* store mixer control info there */
-                VolumeData->Header.dwControlID = MixerControl->dwControlID;
+                VolumeData->Header.dwControlID = MixerControl->Control.dwControlID;
                 VolumeData->SignedMaximum = Range->Bounds.SignedMaximum;
                 VolumeData->SignedMinimum = Range->Bounds.SignedMinimum;
                 VolumeData->SteppingDelta = Range->SteppingDelta;
@@ -310,241 +221,13 @@ MMixerAddMixerControl(
                     VolumeData->Values[Index] = Value;
                     Value += Range->SteppingDelta;
                 }
-                InsertTailList(&MixerLine->LineControlsExtraData, &VolumeData->Header.Entry);
+                MixerControl->ExtraData = VolumeData;
            }
        }
        MixerContext->Free(Desc);
     }
 
-    DPRINT("Status %x Name %S\n", Status, MixerControl->szName);
-    return MM_STATUS_SUCCESS;
-}
-
-MIXER_STATUS
-MMixerAddMixerSourceLine(
-    IN PMIXER_CONTEXT MixerContext,
-    IN OUT LPMIXER_INFO MixerInfo,
-    IN HANDLE hDevice,
-    IN PKSMULTIPLE_ITEM NodeConnections,
-    IN PKSMULTIPLE_ITEM NodeTypes,
-    IN ULONG PinId,
-    IN ULONG bBridgePin,
-    IN ULONG bTargetPin)
-{
-    LPMIXERLINE_EXT SrcLine, DstLine;
-    MIXER_STATUS Status;
-    KSP_PIN Pin;
-    LPWSTR PinName;
-    GUID NodeType;
-    ULONG BytesReturned, ControlCount, Index;
-    LPGUID Node;
-    PULONG Nodes;
-
-    if (!bTargetPin)
-    {
-        /* allocate src mixer line */
-        SrcLine = (LPMIXERLINE_EXT)MixerContext->Alloc(sizeof(MIXERLINE_EXT));
-
-        if (!SrcLine)
-            return MM_STATUS_NO_MEMORY;
-
-        /* zero struct */
-        RtlZeroMemory(SrcLine, sizeof(MIXERLINE_EXT));
-
-    }
-    else
-    {
-        ASSERT(!IsListEmpty(&MixerInfo->LineList));
-        SrcLine = MMixerGetSourceMixerLineByLineId(MixerInfo, DESTINATION_LINE);
-    }
-
-    /* get destination line */
-    DstLine = MMixerGetSourceMixerLineByLineId(MixerInfo, DESTINATION_LINE);
-    ASSERT(DstLine);
-
-
-    if (!bTargetPin)
-    {
-        /* 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);
-        wcscpy(SrcLine->Line.Target.szPname, MixerInfo->MixCaps.szPname);
-
-    }
-
-    /* allocate a node arrary */
-    Nodes = (PULONG)MixerContext->Alloc(sizeof(ULONG) * NodeTypes->Count);
-
-    if (!Nodes)
-    {
-        /* not enough memory */
-        if (!bTargetPin)
-        {
-            MixerContext->Free(SrcLine);
-        }
-        return MM_STATUS_NO_MEMORY;
-    }
-
-    Status = MMixerGetControlsFromPin(MixerContext, NodeConnections, NodeTypes, PinId, bTargetPin, Nodes);
-    if (Status != MM_STATUS_SUCCESS)
-    {
-        /* something went wrong */
-        if (!bTargetPin)
-        {
-            MixerContext->Free(SrcLine);
-        }
-        MixerContext->Free(Nodes);
-        return Status;
-    }
-
-    /* now count all nodes controlled by that pin */
-    ControlCount = 0;
-    for(Index = 0; Index < NodeTypes->Count; Index++)
-    {
-        if (Nodes[Index])
-        {
-            // get node type
-            Node = MMixerGetNodeType(NodeTypes, Index);
-
-            if (MMixerGetControlTypeFromTopologyNode(Node))
-            {
-                // found a node which can be resolved to a type
-                ControlCount++;
-            }
-        }
-    }
-
-    /* now allocate the line controls */
-    if (ControlCount)
-    {
-        SrcLine->LineControls = (LPMIXERCONTROLW)MixerContext->Alloc(sizeof(MIXERCONTROLW) * ControlCount);
-
-        if (!SrcLine->LineControls)
-        {
-            /* no memory available */
-            if (!bTargetPin)
-            {
-                MixerContext->Free(SrcLine);
-            }
-            MixerContext->Free(Nodes);
-            return MM_STATUS_NO_MEMORY;
-        }
-
-        SrcLine->NodeIds = (PULONG)MixerContext->Alloc(sizeof(ULONG) * ControlCount);
-        if (!SrcLine->NodeIds)
-        {
-            /* no memory available */
-            MixerContext->Free(SrcLine->LineControls);
-            if (!bTargetPin)
-            {
-                MixerContext->Free(SrcLine);
-            }
-            MixerContext->Free(Nodes);
-            return MM_STATUS_NO_MEMORY;
-        }
-
-        /* zero line controls */
-        RtlZeroMemory(SrcLine->LineControls, sizeof(MIXERCONTROLW) * ControlCount);
-        RtlZeroMemory(SrcLine->NodeIds, sizeof(ULONG) * ControlCount);
-
-        ControlCount = 0;
-        for(Index = 0; Index < NodeTypes->Count; Index++)
-        {
-            if (Nodes[Index])
-            {
-                // get node type
-                Node = MMixerGetNodeType(NodeTypes, Index);
-
-                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;
-    }
-
-    /* release nodes array */
-    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;
-
-    /* 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)
-    {
-        //FIXME
-        //map component type
-    }
-
-    /* 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);
-
-    if (Status == MM_STATUS_MORE_ENTRIES)
-    {
-        PinName = (LPWSTR)MixerContext->Alloc(BytesReturned);
-        if (PinName)
-        {
-            /* try get pin name */
-            Status = MixerContext->Control(hDevice, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSP_PIN), (LPVOID)PinName, BytesReturned, &BytesReturned);
-
-            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';
-
-                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);
-        }
-    }
-
-    /* insert src line */
-    if (!bTargetPin)
-    {
-        InsertTailList(&MixerInfo->LineList, &SrcLine->Entry);
-        DstLine->Line.cConnections++;
-    }
-
+    DPRINT("Status %x Name %S\n", Status, MixerControl->Control.szName);
     return MM_STATUS_SUCCESS;
 }
 
@@ -557,22 +240,26 @@ MMixerCreateDestinationLine(
 {
     LPMIXERLINE_EXT DestinationLine;
 
-    // allocate a mixer destination line
+    /* allocate a mixer destination line */
     DestinationLine = (LPMIXERLINE_EXT) MixerContext->Alloc(sizeof(MIXERLINE_EXT));
     if (!MixerInfo)
     {
-        // no memory
+        /* no memory */
         return MM_STATUS_NO_MEMORY;
     }
 
     /* initialize mixer destination line */
     DestinationLine->Line.cbStruct = sizeof(MIXERLINEW);
+    DestinationLine->Line.cChannels = 2; /* FIXME */
+    DestinationLine->Line.cConnections = 0;
+    DestinationLine->Line.cControls = 0;
+    DestinationLine->Line.dwComponentType = (bInputMixer == 0 ? MIXERLINE_COMPONENTTYPE_DST_SPEAKERS : MIXERLINE_COMPONENTTYPE_DST_WAVEIN);
+    DestinationLine->Line.dwDestination = MixerInfo->MixCaps.cDestinations;
+    DestinationLine->Line.dwLineID = MixerInfo->MixCaps.cDestinations + DESTINATION_LINE;
     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
+    DestinationLine->Line.fdwLine = MIXERLINE_LINEF_ACTIVE;
+
 
     if (LineName)
     {
@@ -583,423 +270,1352 @@ MMixerCreateDestinationLine(
         DestinationLine->Line.szName[MIXER_LONG_NAME_CHARS-1] = L'\0';
 
     }
-    else
-    {
-        /* FIXME no name was found for pin */
-        wcscpy(DestinationLine->Line.szShortName, L"Summe");
-        wcscpy(DestinationLine->Line.szName, L"Summe");
-    }
 
     DestinationLine->Line.Target.dwType = (bInputMixer == 0 ? MIXERLINE_TARGETTYPE_WAVEOUT : MIXERLINE_TARGETTYPE_WAVEIN);
-    DestinationLine->Line.Target.dwDeviceID = !bInputMixer;
+    DestinationLine->Line.Target.dwDeviceID = 0; //FIXME
     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);
+    /* initialize extra line */
+    InitializeListHead(&DestinationLine->ControlsList);
+
+    /* insert into mixer info */
+    InsertTailList(&MixerInfo->LineList, &DestinationLine->Entry);
 
-    // insert into mixer info
-    InsertHeadList(&MixerInfo->LineList, &DestinationLine->Entry);
+    /* increment destination count */
+    MixerInfo->MixCaps.cDestinations++;
 
-    // done
+    /* done */
     return MM_STATUS_SUCCESS;
 }
 
 MIXER_STATUS
-MMixerGetControlsFromPin(
+MMixerGetPinName(
     IN PMIXER_CONTEXT MixerContext,
-    IN PKSMULTIPLE_ITEM NodeConnections,
-    IN PKSMULTIPLE_ITEM NodeTypes,
+    IN LPMIXER_INFO MixerInfo,
+    IN HANDLE hMixer,
     IN ULONG PinId,
-    IN ULONG bUpDirection,
-    OUT PULONG Nodes)
+    IN OUT LPWSTR * OutBuffer)
 {
-    ULONG NodeConnectionCount, Index;
+    KSP_PIN Pin;
+    ULONG BytesReturned;
+    LPWSTR Buffer;
     MIXER_STATUS Status;
-    PULONG NodeConnection;
 
-    /* sanity check */
-    ASSERT(PinId != (ULONG)-1);
+    /* 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;
 
-    /* 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);
+    /* try get pin name size */
+    Status = MixerContext->Control(hMixer, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSP_PIN), NULL, 0, &BytesReturned);
 
-    for(Index = 0; Index < NodeConnectionCount; Index++)
+    /* check if buffer overflowed */
+    if (Status == MM_STATUS_MORE_ENTRIES)
     {
-        /* get all associated controls */
-        Status = MMixerGetControlsFromPinByConnectionIndex(MixerContext, NodeConnections, NodeTypes, bUpDirection, NodeConnection[Index], Nodes);
-    }
+        /* allocate buffer */
+        Buffer = (LPWSTR)MixerContext->Alloc(BytesReturned);
+        if (!Buffer)
+        {
+            /* out of memory */
+            return MM_STATUS_NO_MEMORY;
+        }
+
+        /* try get pin name */
+        Status = MixerContext->Control(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;
+        }
 
-    MixerContext->Free(NodeConnection);
+        /* successfully obtained pin name */
+        *OutBuffer = Buffer;
+        return MM_STATUS_SUCCESS;
+    }
 
+    /* failed to get pin name */
     return Status;
 }
 
-
-
-
 MIXER_STATUS
-MMixerAddMixerSourceLines(
+MMixerBuildMixerDestinationLine(
     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 HANDLE hMixer,
+    IN ULONG PinId,
+    IN ULONG bInput)
 {
-    ULONG Index;
+    LPWSTR PinName;
+    MIXER_STATUS Status;
 
-    for(Index = PinsCount; Index > 0; Index--)
+    /* try get pin name */
+    Status = MMixerGetPinName(MixerContext, MixerInfo, hMixer, PinId, &PinName);
+    if (Status == MM_STATUS_SUCCESS)
     {
-        DPRINT("MMixerAddMixerSourceLines Index %lu Pin %lu\n", Index-1, Pins[Index-1]);
-        if (Pins[Index-1])
-        {
-            MMixerAddMixerSourceLine(MixerContext, MixerInfo, hDevice, NodeConnections, NodeTypes, Index-1, (Index -1 == BridgePinIndex), (Index -1 == TargetPinIndex));
-        }
+        /* create mixer destination line */
+
+        Status = MMixerCreateDestinationLine(MixerContext, MixerInfo, bInput, PinName);
+
+        /* free pin name */
+        MixerContext->Free(PinName);
     }
+    else
+    {
+        /* create mixer destination line unlocalized */
+        Status = MMixerCreateDestinationLine(MixerContext, MixerInfo, bInput, L"No Name");
+    }
+
+    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 (MixerData->Topology)
+    {
+        /* re-use existing topology */
+        *OutTopology = MixerData->Topology;
+
+        return MM_STATUS_SUCCESS;
+    }
+
+    /* get connected filter pin count */
+    PinsCount = MMixerGetFilterPinCount(MixerContext, MixerData->hDevice);
+
+    if (!PinsCount)
+    {
+        /* referenced filter does not have any pins */
+        return MM_STATUS_UNSUCCESSFUL;
+    }
+
+    /* get topology node types */
+    Status = MMixerGetFilterTopologyProperty(MixerContext, MixerData->hDevice, KSPROPERTY_TOPOLOGY_NODES, &NodeTypes);
+    if (Status != MM_STATUS_SUCCESS)
+    {
+        /* failed to get topology node types */
+        return Status;
+    }
+
+    /* get topology connections */
+    Status = MMixerGetFilterTopologyProperty(MixerContext, MixerData->hDevice, KSPROPERTY_TOPOLOGY_CONNECTIONS, &NodeConnections);
+    if (Status != MM_STATUS_SUCCESS)
+    {
+        /* failed to get topology connections */
+        MixerContext->Free(NodeTypes);
+        return Status;
+    }
+
+    /* 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;
+    }
+
+    /* done */
+    return Status;
+}
+
+MIXER_STATUS
+MMixerCountMixerControls(
+    IN PMIXER_CONTEXT MixerContext,
+    IN PTOPOLOGY Topology,
+    IN ULONG PinId,
+    IN ULONG bInputMixer,
+    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)
+    {
+        /* out of memory */
+        return 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;
+
+    do
+    {
+        /* check if the node is a terminator */
+        MMixerIsNodeTerminator(Topology, NodeIndex, &bTerminator);
+
+        if (bTerminator)
+        {
+            /* found terminator */
+            if (bInputMixer)
+            {
+                /* add mux source for source destination line */
+                OutNodes[Count] = NodeIndex;
+                Count++;
+            }
+            break;
+        }
+
+        /* store node id */
+        OutNodes[Count] = NodeIndex;
+
+        /* increment node count */
+        Count++;
+
+        /* 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);
+
+    /* free node index */
+    MixerContext->Free(Nodes);
+
+    /* store nodes count */
+    *OutNodesCount = Count;
+
+    /* store line terminator */
+    *OutLineTerminator = NodeIndex;
+
+    /* done */
+    return MM_STATUS_SUCCESS;
+}
+
+MIXER_STATUS
+MMixerGetChannelCountEnhanced(
+    IN PMIXER_CONTEXT MixerContext,
+    IN LPMIXER_INFO MixerInfo,
+    IN HANDLE hMixer,
+    IN ULONG NodeId,
+    OUT PULONG MaxChannels)
+{
+    KSPROPERTY_DESCRIPTION Description;
+    PKSPROPERTY_DESCRIPTION NewDescription;
+    PKSPROPERTY_MEMBERSHEADER Header;
+    ULONG BytesReturned;
+    KSP_NODE Request;
+    MIXER_STATUS Status;
+
+    /* try #1 obtain it via description */
+    Request.NodeId = NodeId;
+    Request.Reserved = 0;
+    Request.Property.Set = KSPROPSETID_Audio;
+    Request.Property.Flags = KSPROPERTY_TYPE_BASICSUPPORT | KSPROPERTY_TYPE_TOPOLOGY;
+    Request.Property.Id = KSPROPERTY_AUDIO_VOLUMELEVEL;
+
+
+    /* get description */
+    Status = MixerContext->Control(hMixer, IOCTL_KS_PROPERTY, (PVOID)&Request, sizeof(KSP_NODE), (PVOID)&Description, sizeof(KSPROPERTY_DESCRIPTION), &BytesReturned);
+    if (Status == MM_STATUS_SUCCESS)
+    {
+        if (Description.DescriptionSize >= sizeof(KSPROPERTY_DESCRIPTION) + sizeof(KSPROPERTY_MEMBERSHEADER) && (Description.MembersListCount > 0))
+        {
+            /* allocate new description */
+            NewDescription = MixerContext->Alloc(Description.DescriptionSize);
+
+            if (!NewDescription)
+            {
+                /* not enough memory */
+                return MM_STATUS_NO_MEMORY;
+            }
+
+            /* get description */
+            Status = MixerContext->Control(hMixer, IOCTL_KS_PROPERTY, (PVOID)&Request, sizeof(KSP_NODE), (PVOID)NewDescription, Description.DescriptionSize, &BytesReturned);
+            if (Status == MM_STATUS_SUCCESS)
+            {
+                /* get header */
+                Header = (PKSPROPERTY_MEMBERSHEADER)(NewDescription + 1);
+
+                if (Header->Flags & KSPROPERTY_MEMBER_FLAG_BASICSUPPORT_MULTICHANNEL)
+                {
+                    /* found enhanced flag */
+                    ASSERT(Header->MembersCount > 1);
+
+                    /* store channel count */
+                    *MaxChannels = Header->MembersCount;
+
+                    /* free description */
+                    MixerContext->Free(NewDescription);
+
+                    /* done */
+                    return MM_STATUS_SUCCESS;
+                }
+            }
+
+            /* free description */
+            MixerContext->Free(NewDescription);
+        }
+    }
+
+    /* failed to get channel count enhanced */
+    return MM_STATUS_UNSUCCESSFUL;
+}
+
+VOID
+MMixerGetChannelCountLegacy(
+    IN PMIXER_CONTEXT MixerContext,
+    IN LPMIXER_INFO MixerInfo,
+    IN HANDLE hMixer,
+    IN ULONG NodeId,
+    OUT PULONG MaxChannels)
+{
+    ULONG BytesReturned;
+    MIXER_STATUS Status;
+    KSNODEPROPERTY_AUDIO_CHANNEL Channel;
+    LONG Volume;
+
+    /* setup request */
+    Channel.Reserved = 0;
+    Channel.NodeProperty.NodeId = NodeId;
+    Channel.NodeProperty.Reserved = 0;
+    Channel.NodeProperty.Property.Flags = KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_TOPOLOGY;
+    Channel.NodeProperty.Property.Set = KSPROPSETID_Audio;
+    Channel.Channel = 0;
+    Channel.NodeProperty.Property.Id = KSPROPERTY_AUDIO_VOLUMELEVEL;
+
+    do
+    {
+        /* get channel volume */
+        Status = MixerContext->Control(hMixer, IOCTL_KS_PROPERTY, (PVOID)&Channel, sizeof(KSNODEPROPERTY_AUDIO_CHANNEL), (PVOID)&Volume, sizeof(LONG), &BytesReturned);
+        if (Status != MM_STATUS_SUCCESS)
+            break;
+
+        /* increment channel count */
+        Channel.Channel++;
+
+    }while(TRUE);
+
+    /* store channel count */
+    *MaxChannels = Channel.Channel;
+
+}
+
+VOID
+MMixerGetMaxChannelsForNode(
+    IN PMIXER_CONTEXT MixerContext,
+    IN LPMIXER_INFO MixerInfo,
+    IN HANDLE hMixer,
+    IN ULONG NodeId,
+    OUT PULONG MaxChannels)
+{
+    MIXER_STATUS Status;
+
+    /* try to get it enhanced */
+    Status = MMixerGetChannelCountEnhanced(MixerContext, MixerInfo, hMixer, NodeId, MaxChannels);
+
+    if (Status != MM_STATUS_SUCCESS)
+    {
+        /* get it old-fashioned way */
+        MMixerGetChannelCountLegacy(MixerContext, MixerInfo, hMixer, NodeId, MaxChannels);
+    }
+}
+
+MIXER_STATUS
+MMixerAddMixerControlsToMixerLineByNodeIndexArray(
+    IN PMIXER_CONTEXT MixerContext,
+    IN LPMIXER_INFO MixerInfo,
+    IN HANDLE hMixer,
+    IN PTOPOLOGY Topology,
+    IN OUT LPMIXERLINE_EXT DstLine,
+    IN ULONG NodesCount,
+    IN PULONG Nodes)
+{
+    ULONG Index, Count, bReserved;
+    MIXER_STATUS Status;
+    LPGUID NodeType;
+    ULONG MaxChannels;
+
+    /* initialize control count */
+    Count = 0;
+
+    for(Index = 0; Index < NodesCount; Index++)
+    {
+        /* check if the node has already been reserved to a line */
+        MMixerIsTopologyNodeReserved(Topology, Nodes[Index], &bReserved);
+#if 0 /* MS lies */
+        if (bReserved)
+        {
+            /* node is already used, skip it */
+            continue;
+        }
+#endif
+        /* set node status as used */
+        MMixerSetTopologyNodeReserved(Topology, Nodes[Index]);
+
+        /* query node type */
+        NodeType = MMixerGetNodeTypeFromTopology(Topology, Nodes[Index]);
+
+        if (IsEqualGUIDAligned(NodeType, &KSNODETYPE_VOLUME))
+        {
+            /* calculate maximum channel count for node */
+            MMixerGetMaxChannelsForNode(MixerContext, MixerInfo, hMixer, Nodes[Index], &MaxChannels);
+
+            DPRINT("NodeId %lu MaxChannels %lu Line %S Id %lu\n", Nodes[Index], MaxChannels, DstLine->Line.szName, DstLine->Line.dwLineID);
+            /* calculate maximum channels */
+            DstLine->Line.cChannels = min(DstLine->Line.cChannels, MaxChannels);
+        }
+        else
+        {
+            /* use default of one channel */
+            MaxChannels = 1;
+        }
+
+        /* now add the mixer control */
+        Status = MMixerAddMixerControl(MixerContext, MixerInfo, hMixer, Topology, Nodes[Index], DstLine, MaxChannels);
+
+        if (Status == MM_STATUS_SUCCESS)
+        {
+            /* increment control count */
+            Count++;
+        }
+    }
+
+    /* store control count */
+    DstLine->Line.cControls = Count;
+
+    /* done */
+    return MM_STATUS_SUCCESS;
+}
+
+MIXER_STATUS
+MMixerGetComponentAndTargetType(
+    IN PMIXER_CONTEXT MixerContext,
+    IN OUT LPMIXER_INFO MixerInfo,
+    IN HANDLE hMixer,
+    IN ULONG PinId,
+    OUT PULONG ComponentType,
+    OUT PULONG TargetType)
+{
+    KSPIN_DATAFLOW DataFlow;
+    KSPIN_COMMUNICATION Communication;
+    MIXER_STATUS Status;
+    KSP_PIN Request;
+    ULONG BytesReturned;
+    GUID Guid;
+    BOOLEAN BridgePin = FALSE;
+    PKSPIN_PHYSICALCONNECTION Connection;
+
+    /* first dataflow type */
+    Status = MMixerGetPinDataFlowAndCommunication(MixerContext, hMixer, PinId, &DataFlow, &Communication);
+
+    if (Status != MM_STATUS_SUCCESS)
+    {
+        /* failed to get dataflow */
+        return Status;
+    }
+
+    /* now get pin category guid */
+    Request.PinId = PinId;
+    Request.Reserved = 0;
+    Request.Property.Flags = KSPROPERTY_TYPE_GET;
+    Request.Property.Set = KSPROPSETID_Pin;
+    Request.Property.Id = KSPROPERTY_PIN_CATEGORY;
+
+
+    /* get pin category */
+    Status = MixerContext->Control(hMixer, IOCTL_KS_PROPERTY, (PVOID)&Request, sizeof(KSP_PIN), &Guid, sizeof(GUID), &BytesReturned);
+    if (Status != MM_STATUS_SUCCESS)
+    {
+        /* failed to get dataflow */
+        return Status;
+    }
+
+    /* check if it has a physical connection */
+    Status = MMixerGetPhysicalConnection(MixerContext, hMixer, PinId, &Connection);
+    if (Status == MM_STATUS_SUCCESS)
+    {
+        /* pin is a brige pin */
+        BridgePin = TRUE;
+
+        /* free physical connection */
+        MixerContext->Free(Connection);
+    }
+
+    if (DataFlow == KSPIN_DATAFLOW_IN)
+    {
+        if (IsEqualGUIDAligned(&Guid, &KSNODETYPE_MICROPHONE) ||
+            IsEqualGUIDAligned(&Guid, &KSNODETYPE_DESKTOP_MICROPHONE))
+        {
+            /* type microphone */
+            *TargetType = MIXERLINE_TARGETTYPE_WAVEIN;
+            *ComponentType = MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE;
+        }
+        else if (IsEqualGUIDAligned(&Guid, &KSNODETYPE_LEGACY_AUDIO_CONNECTOR) ||
+                 IsEqualGUIDAligned(&Guid, &KSCATEGORY_AUDIO) ||
+                 IsEqualGUIDAligned(&Guid, &KSNODETYPE_SPEAKER))
+        {
+            /* type waveout */
+            *TargetType = MIXERLINE_TARGETTYPE_WAVEOUT;
+            *ComponentType = MIXERLINE_COMPONENTTYPE_SRC_WAVEOUT;
+        }
+        else if (IsEqualGUIDAligned(&Guid, &KSNODETYPE_CD_PLAYER))
+        {
+            /* type cd player */
+            *TargetType = MIXERLINE_TARGETTYPE_UNDEFINED;
+            *ComponentType = MIXERLINE_COMPONENTTYPE_SRC_COMPACTDISC;
+        }
+        else if (IsEqualGUIDAligned(&Guid, &KSNODETYPE_SYNTHESIZER))
+        {
+            /* type synthesizer */
+            *TargetType = MIXERLINE_TARGETTYPE_MIDIOUT;
+            *ComponentType = MIXERLINE_COMPONENTTYPE_SRC_SYNTHESIZER;
+        }
+        else if (IsEqualGUIDAligned(&Guid, &KSNODETYPE_LINE_CONNECTOR))
+        {
+            /* type line */
+            *TargetType = MIXERLINE_TARGETTYPE_UNDEFINED;
+            *ComponentType = MIXERLINE_COMPONENTTYPE_SRC_LINE;
+        }
+        else if (IsEqualGUIDAligned(&Guid, &KSNODETYPE_TELEPHONE) ||
+                 IsEqualGUIDAligned(&Guid, &KSNODETYPE_PHONE_LINE) ||
+                 IsEqualGUIDAligned(&Guid, &KSNODETYPE_DOWN_LINE_PHONE))
+        {
+            /* type telephone */
+            *TargetType =  MIXERLINE_TARGETTYPE_UNDEFINED;
+            *ComponentType =  MIXERLINE_COMPONENTTYPE_SRC_TELEPHONE;
+        }
+        else if (IsEqualGUIDAligned(&Guid, &KSNODETYPE_ANALOG_CONNECTOR))
+        {
+            /* type analog */
+            if (BridgePin)
+                *TargetType = MIXERLINE_TARGETTYPE_WAVEIN;
+            else
+                *TargetType = MIXERLINE_TARGETTYPE_WAVEOUT;
+
+            *ComponentType = MIXERLINE_COMPONENTTYPE_SRC_ANALOG;
+        }
+        else if (IsEqualGUIDAligned(&Guid, &KSNODETYPE_SPDIF_INTERFACE))
+        {
+            /* type analog */
+            if (BridgePin)
+                *TargetType = MIXERLINE_TARGETTYPE_WAVEIN;
+            else
+                *TargetType = MIXERLINE_TARGETTYPE_WAVEOUT;
+
+            *ComponentType = MIXERLINE_COMPONENTTYPE_SRC_DIGITAL;
+        }
+        else
+        {
+            /* unknown type */
+            *TargetType = MIXERLINE_TARGETTYPE_UNDEFINED;
+            *ComponentType = MIXERLINE_COMPONENTTYPE_SRC_UNDEFINED;
+            DPRINT1("Unknown Category for PinId %lu BridgePin %lu\n", PinId, BridgePin);
+        }
+    }
+    else
+    {
+        if (IsEqualGUIDAligned(&Guid, &KSNODETYPE_SPEAKER) ||
+                 IsEqualGUIDAligned(&Guid, &KSNODETYPE_DESKTOP_SPEAKER) ||
+                 IsEqualGUIDAligned(&Guid, &KSNODETYPE_ROOM_SPEAKER) ||
+                 IsEqualGUIDAligned(&Guid, &KSNODETYPE_COMMUNICATION_SPEAKER))
+        {
+            /* type waveout */
+            *TargetType =  MIXERLINE_TARGETTYPE_WAVEOUT;
+            *ComponentType =  MIXERLINE_COMPONENTTYPE_DST_SPEAKERS;
+        }
+        else if (IsEqualGUIDAligned(&Guid, &KSCATEGORY_AUDIO) ||
+                 IsEqualGUIDAligned(&Guid, &PINNAME_CAPTURE))
+        {
+            /* type wavein */
+            *TargetType =  MIXERLINE_TARGETTYPE_WAVEIN;
+            *ComponentType =  MIXERLINE_COMPONENTTYPE_DST_WAVEIN;
+        }
+        else if (IsEqualGUIDAligned(&Guid, &KSNODETYPE_HEADPHONES) ||
+                 IsEqualGUIDAligned(&Guid, &KSNODETYPE_HEAD_MOUNTED_DISPLAY_AUDIO))
+        {
+            /* type head phones */
+            *TargetType =  MIXERLINE_TARGETTYPE_WAVEOUT;
+            *ComponentType =  MIXERLINE_COMPONENTTYPE_DST_HEADPHONES;
+        }
+        else if (IsEqualGUIDAligned(&Guid, &KSNODETYPE_TELEPHONE) ||
+                 IsEqualGUIDAligned(&Guid, &KSNODETYPE_PHONE_LINE) ||
+                 IsEqualGUIDAligned(&Guid, &KSNODETYPE_DOWN_LINE_PHONE))
+        {
+            /* type waveout */
+            *TargetType =   MIXERLINE_TARGETTYPE_UNDEFINED;
+            *ComponentType =   MIXERLINE_COMPONENTTYPE_DST_TELEPHONE;
+        }
+        else if (IsEqualGUIDAligned(&Guid, &KSNODETYPE_ANALOG_CONNECTOR))
+        {
+            /* type analog */
+            if (BridgePin)
+            {
+                *TargetType =  MIXERLINE_TARGETTYPE_WAVEOUT;
+                *ComponentType =  MIXERLINE_COMPONENTTYPE_DST_SPEAKERS;
+            }
+            else
+            {
+                *TargetType =  MIXERLINE_TARGETTYPE_WAVEIN;
+                *ComponentType =  MIXERLINE_COMPONENTTYPE_DST_WAVEIN;
+            }
+        }
+        else if (IsEqualGUIDAligned(&Guid, &KSNODETYPE_SPDIF_INTERFACE))
+        {
+            /* type spdif */
+            if (BridgePin)
+            {
+                *TargetType =  MIXERLINE_TARGETTYPE_WAVEOUT;
+                *ComponentType =  MIXERLINE_COMPONENTTYPE_DST_SPEAKERS;
+            }
+            else
+            {
+                *TargetType =  MIXERLINE_TARGETTYPE_WAVEIN;
+                *ComponentType =  MIXERLINE_COMPONENTTYPE_DST_WAVEIN;
+            }
+        }
+        else
+        {
+            /* unknown type */
+            *TargetType = MIXERLINE_TARGETTYPE_UNDEFINED;
+            *ComponentType = MIXERLINE_COMPONENTTYPE_DST_UNDEFINED;
+            DPRINT1("Unknown Category for PinId %lu BridgePin %lu\n", PinId, BridgePin);
+        }
+    }
+
+    /* done */
+    return MM_STATUS_SUCCESS;
+}
+
+MIXER_STATUS
+MMixerBuildMixerSourceLine(
+    IN PMIXER_CONTEXT MixerContext,
+    IN OUT LPMIXER_INFO MixerInfo,
+    IN HANDLE hMixer,
+    IN PTOPOLOGY Topology,
+    IN ULONG PinId,
+    IN ULONG NodesCount,
+    IN PULONG Nodes,
+    IN ULONG DestinationLineID,
+    OUT LPMIXERLINE_EXT * OutSrcLine)
+{
+    LPMIXERLINE_EXT SrcLine, DstLine;
+    LPWSTR PinName;
+    MIXER_STATUS Status;
+    ULONG ComponentType, TargetType;
+
+    /* get component and target type */
+    Status = MMixerGetComponentAndTargetType(MixerContext, MixerInfo, hMixer, PinId, &ComponentType, &TargetType);
+    if (Status != MM_STATUS_SUCCESS)
+    {
+        /* failed to get component status */
+        TargetType = MIXERLINE_TARGETTYPE_UNDEFINED;
+        ComponentType = MIXERLINE_COMPONENTTYPE_DST_UNDEFINED;
+    }
+
+    /* construct source line */
+    SrcLine = (LPMIXERLINE_EXT)MixerContext->Alloc(sizeof(MIXERLINE_EXT));
+
+    if (!SrcLine)
+    {
+        /* no memory */
+        return MM_STATUS_NO_MEMORY;
+    }
+
+    /* get destination line */
+    DstLine = MMixerGetSourceMixerLineByLineId(MixerInfo, DestinationLineID);
+    ASSERT(DstLine);
+
+    /* initialize mixer src line */
+    SrcLine->PinId = PinId;
+
+    /* initialize mixer line */
+    SrcLine->Line.cbStruct = sizeof(MIXERLINEW);
+    SrcLine->Line.dwDestination = MixerInfo->MixCaps.cDestinations-1;
+    SrcLine->Line.dwSource = DstLine->Line.cConnections;
+    SrcLine->Line.dwLineID = (DstLine->Line.cConnections * SOURCE_LINE)+ (MixerInfo->MixCaps.cDestinations-1);
+    SrcLine->Line.fdwLine = MIXERLINE_LINEF_ACTIVE | MIXERLINE_LINEF_SOURCE;
+    SrcLine->Line.dwComponentType = ComponentType;
+    SrcLine->Line.dwUser = 0;
+    SrcLine->Line.cChannels = DstLine->Line.cChannels;
+    SrcLine->Line.cConnections = 0;
+    SrcLine->Line.Target.dwType = TargetType;
+    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->ControlsList);
+
+    /* 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, hMixer, PinId, &PinName);
+
+    if (Status == MM_STATUS_SUCCESS)
+    {
+        /* 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(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);
+    }
+
+    /* add the controls to mixer line */
+    Status = MMixerAddMixerControlsToMixerLineByNodeIndexArray(MixerContext, MixerInfo, hMixer, Topology, SrcLine, NodesCount, Nodes);
+    if (Status != MM_STATUS_SUCCESS)
+    {
+        /* failed */
+        return Status;
+    }
+
+    /* store result */
+    *OutSrcLine = SrcLine;
+
+    return MM_STATUS_SUCCESS;
+}
+
+MIXER_STATUS
+MMixerAddMixerSourceLines(
+    IN PMIXER_CONTEXT MixerContext,
+    IN OUT LPMIXER_INFO MixerInfo,
+    IN HANDLE hMixer,
+    IN PTOPOLOGY Topology,
+    IN ULONG DestinationLineID,
+    IN ULONG LineTerminator)
+{
+    PULONG AllNodes, AllPins, AllPinNodes;
+    ULONG AllNodesCount, AllPinsCount, AllPinNodesCount;
+    ULONG Index, SubIndex, PinId, CurNode, bConnected;
+    MIXER_STATUS Status;
+    LPMIXERLINE_EXT DstLine, SrcLine;
+
+    /* get destination line */
+    DstLine = MMixerGetSourceMixerLineByLineId(MixerInfo, DestinationLineID);
+    ASSERT(DstLine);
+
+    /* allocate an array to store all nodes which are upstream of the line terminator */
+    Status = MMixerAllocateTopologyNodeArray(MixerContext, Topology, &AllNodes);
+
+    /* check for success */
+    if (Status != MM_STATUS_SUCCESS)
+    {
+        /* out of memory */
+        return MM_STATUS_NO_MEMORY;
+    }
+
+    /* allocate an array to store all nodes which are downstream of a particular pin */
+    Status = MMixerAllocateTopologyNodeArray(MixerContext, Topology, &AllPinNodes);
+
+    /* 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 */
+    AllPinsCount = 0;
+    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)
+        {
+#ifdef MMIXER_DEBUG
+            ULONG TempIndex;
+#endif
+            /* now build the mixer source line */
+            Status = MMixerBuildMixerSourceLine(MixerContext, MixerInfo, hMixer, Topology, PinId, AllPinNodesCount, AllPinNodes, DestinationLineID, &SrcLine);
+
+             if (Status == MM_STATUS_SUCCESS)
+             {
+                 /* insert into line list */
+                 InsertTailList(&MixerInfo->LineList, &SrcLine->Entry);
+
+                 /* increment destination line count */
+                 DstLine->Line.cConnections++;
+
+                 /* mark pin as reserved */
+                 MMixerSetTopologyPinReserved(Topology, PinId);
+
+#ifdef MMIXER_DEBUG
+                 DPRINT1("Adding PinId %lu AllPinNodesCount %lu to DestinationLine %lu\n", PinId, AllPinNodesCount, DestinationLineID);
+                 for(TempIndex = 0; TempIndex < AllPinNodesCount; TempIndex++)
+                     DPRINT1("NodeIndex %lu\n", AllPinNodes[TempIndex]);
+#endif
+             }
+        }
+        else
+        {
+#ifdef MMIXER_DEBUG
+            DPRINT1("Discarding DestinationLineID %lu PinId %lu NO NODES!\n", DestinationLineID, PinId);
+#endif
+        }
+
+    }while(Index != 0);
+
     return MM_STATUS_SUCCESS;
 }
 
 
 MIXER_STATUS
-MMixerHandlePhysicalConnection(
+MMixerAddMixerControlsToDestinationLine(
     IN PMIXER_CONTEXT MixerContext,
-    IN PMIXER_LIST MixerList,
     IN OUT LPMIXER_INFO MixerInfo,
+    IN HANDLE hMixer,
+    IN PTOPOLOGY Topology,
+    IN ULONG PinId,
     IN ULONG bInput,
-    IN PKSPIN_PHYSICALCONNECTION OutConnection)
+    IN ULONG DestinationLineId,
+    OUT PULONG OutLineTerminator)
 {
-    PULONG PinsRef = NULL, PinConnectionIndex = NULL, PinsSrcRef;
-    ULONG PinsRefCount, Index, PinConnectionIndexCount;
+    PULONG Nodes;
+    ULONG NodesCount, LineTerminator;
     MIXER_STATUS Status;
-    PKSMULTIPLE_ITEM NodeTypes = NULL;
-    PKSMULTIPLE_ITEM NodeConnections = NULL;
-    PULONG MixerControls;
-    ULONG MixerControlsCount;
-    LPMIXER_DATA MixerData;
-
+    LPMIXERLINE_EXT DstLine;
 
-    // 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);
+    /* allocate nodes index array */
+    Status = MMixerAllocateTopologyNodeArray(MixerContext, Topology, &Nodes);
 
-    PinsRef = (PULONG)MixerContext->Alloc(sizeof(ULONG) * PinsRefCount);
-    if (!PinsRef)
+    /* check for success */
+    if (Status != MM_STATUS_SUCCESS)
     {
-        // no memory
-        return MM_STATUS_UNSUCCESSFUL;
+        /* out of memory */
+        return MM_STATUS_NO_MEMORY;
     }
 
-    // get topology node types
-    Status = MMixerGetFilterTopologyProperty(MixerContext, MixerData->hDevice, KSPROPERTY_TOPOLOGY_NODES, &NodeTypes);
+    /* get all destination line controls */
+    Status = MMixerCountMixerControls(MixerContext, Topology, PinId, bInput, TRUE, &NodesCount, Nodes, &LineTerminator);
+
+    /* check for success */
     if (Status != MM_STATUS_SUCCESS)
     {
-        MixerContext->Free(PinsRef);
+        /* failed to count controls */
+        MixerContext->Free(Nodes);
         return Status;
     }
 
-    // get topology connections
-    Status = MMixerGetFilterTopologyProperty(MixerContext, MixerData->hDevice, KSPROPERTY_TOPOLOGY_CONNECTIONS, &NodeConnections);
-    if (Status != MM_STATUS_SUCCESS)
+    /* get destination mixer line */
+    DstLine = MMixerGetSourceMixerLineByLineId(MixerInfo, DestinationLineId);
+
+    /* sanity check */
+    ASSERT(DstLine);
+
+    if (NodesCount > 0)
     {
-        MixerContext->Free(PinsRef);
-        MixerContext->Free(NodeTypes);
-        return Status;
+        /* add all nodes as mixer controls to the destination line */
+        Status = MMixerAddMixerControlsToMixerLineByNodeIndexArray(MixerContext, MixerInfo, hMixer, Topology, DstLine, NodesCount, Nodes);
+        if (Status != MM_STATUS_SUCCESS)
+        {
+            /* failed to add controls */
+            MixerContext->Free(Nodes);
+            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);
-    if (Status != MM_STATUS_SUCCESS)
+    /* store result */
+    *OutLineTerminator = LineTerminator;
+
+    /* return result */
+    return Status;
+}
+
+VOID
+MMixerApplyOutputFilterHack(
+    IN PMIXER_CONTEXT MixerContext,
+    IN LPMIXER_DATA MixerData,
+    IN HANDLE hMixer,
+    IN OUT PULONG PinsCount,
+    IN OUT PULONG Pins)
+{
+    ULONG Count = 0, Index;
+    MIXER_STATUS Status;
+    PKSPIN_PHYSICALCONNECTION Connection;
+
+    for(Index = 0; Index < *PinsCount; Index++)
     {
-        MixerContext->Free(PinsRef);
-        MixerContext->Free(NodeTypes);
-        MixerContext->Free(NodeConnections);
-        return Status;
+        /* check if it has a physical connection */
+        Status = MMixerGetPhysicalConnection(MixerContext, hMixer, Pins[Index], &Connection);
+
+        if (Status == MM_STATUS_SUCCESS)
+        {
+            /* remove pin */
+            MixerContext->Copy(&Pins[Index], &Pins[Index + 1], (*PinsCount - (Index + 1)) * sizeof(ULONG));
+
+            /* free physical connection */
+            MixerContext->Free(Connection);
+
+            /* decrement index */
+            Index--;
+
+            /* decrement pin count */
+            (*PinsCount)--;
+        }
+        else
+        {
+            /* simple pin */
+            Count++;
+        }
     }
 
-    /* there should be no split in the bride pin */
-    ASSERT(PinConnectionIndexCount == 1);
+    /* store result */
+    *PinsCount = Count;
+}
 
-    /* find all target pins of this connection */
-    Status = MMixerGetTargetPinsByNodeConnectionIndex(MixerContext, NodeConnections, NodeTypes, FALSE, PinConnectionIndex[0], PinsRef);
-    if (Status != MM_STATUS_SUCCESS)
+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)
+{
+    MIXER_STATUS Status;
+    ULONG PinsCount, LineTerminator, DestinationLineID;
+    PULONG Pins;
+    PTOPOLOGY Topology;
+
+    /* first try to open the connected filter */
+    OutConnection->SymbolicLinkName[1] = L'\\';
+    MixerData = MMixerGetDataByDeviceName(MixerList, OutConnection->SymbolicLinkName);
+
+     /* check if the linked connection is found */
+     if (!MixerData)
+     {
+         /* filter references invalid physical connection */
+         return MM_STATUS_UNSUCCESSFUL;
+     }
+
+    DPRINT("Name %S, Pin %lu bInput %lu\n", OutConnection->SymbolicLinkName, OutConnection->Pin, bInput);
+
+    /* sanity check */
+    ASSERT(MixerData->MixerInfo == NULL || MixerData->MixerInfo == MixerInfo);
+
+    /* associate with mixer */
+    MixerData->MixerInfo = MixerInfo;
+
+    if (MixerData->Topology == NULL)
     {
-        MixerContext->Free(PinsRef);
-        MixerContext->Free(NodeTypes);
-        MixerContext->Free(NodeConnections);
-        MixerContext->Free(PinConnectionIndex);
-        return Status;
+        /* construct new topology */
+        Status = MMixerBuildTopology(MixerContext, MixerData, &Topology);
+        if (Status != MM_STATUS_SUCCESS)
+        {
+            /* failed to create topology */
+            return Status;
+        }
+
+        /* store topology */
+        MixerData->Topology = Topology;
+    }
+    else
+    {
+        /* re-use existing topology */
+        Topology = MixerData->Topology;
     }
 
-    for(Index = 0; Index < PinsRefCount; Index++)
+    /* mark pin as consumed */
+    MMixerSetTopologyPinReserved(Topology, OutConnection->Pin);
+
+    if (!bInput)
     {
-        DPRINT("PinsRefCount %lu Index %lu Value %lu\n", PinsRefCount, Index, PinsRef[Index]);
-        if (PinsRef[Index])
+        /* allocate pin index array which will hold all referenced pins */
+        Status = MMixerAllocateTopologyPinArray(MixerContext, Topology, &Pins);
+        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 create topology */
+            return Status;
+        }
 
-            /* sanity check */
-            ASSERT(MixerControlsCount == 1);
+        /* the mixer is an output mixer
+         * find end pin of the node path
+         */
+        PinsCount = 0;
+        Status = MMixerGetAllUpOrDownstreamPinsFromPinIndex(MixerContext, Topology, OutConnection->Pin, FALSE, &PinsCount, Pins);
 
-            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;
-            }
+        /* check for success */
+        if (Status != MM_STATUS_SUCCESS)
+        {
+            /* failed to get end pin */
+            MixerContext->Free(Pins);
+            //MMixerFreeTopology(Topology);
 
-            // now get all connected source pins
-            Status = MMixerGetTargetPinsByNodeConnectionIndex(MixerContext, NodeConnections, NodeTypes, TRUE, MixerControls[0], 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;
-            }
+            /* return error code */
+            return Status;
+        }
+        /* HACK:
+         * some topologies do not have strict boundaries
+         * WorkArround: remove all pin ids which have a physical connection
+         * because bridge pins may belong to different render paths
+         */
+        MMixerApplyOutputFilterHack(MixerContext, MixerData, MixerData->hDevice, &PinsCount, Pins);
 
-            /* 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;
+        /* sanity checks */
+        ASSERT(PinsCount != 0);
+        ASSERT(PinsCount == 1);
+
+        /* create destination line */
+        Status = MMixerBuildMixerDestinationLine(MixerContext, MixerInfo, MixerData->hDevice, Pins[0], bInput);
+
+        /* calculate destination line id */
+        DestinationLineID = (DESTINATION_LINE + MixerInfo->MixCaps.cDestinations-1);
+
+        if (Status != MM_STATUS_SUCCESS)
+        {
+            /* failed to build destination line */
+            MixerContext->Free(Pins);
+
+            /* return error code */
+            return Status;
+        }
+
+        /* add mixer controls to destination line */
+        Status = MMixerAddMixerControlsToDestinationLine(MixerContext, MixerInfo, MixerData->hDevice, Topology, Pins[0], bInput, DestinationLineID,  &LineTerminator);
+
+        if (Status == MM_STATUS_SUCCESS)
+        {
+            /* now add the rest of the source lines */
+            Status = MMixerAddMixerSourceLines(MixerContext, MixerInfo, MixerData->hDevice, Topology, DestinationLineID, LineTerminator);
+        }
 
-            Status = MMixerAddMixerSourceLines(MixerContext, MixerInfo, MixerData->hDevice, NodeConnections, NodeTypes, PinsRefCount, OutConnection->Pin, Index, PinsSrcRef);
+        /* mark pin as consumed */
+        MMixerSetTopologyPinReserved(Topology, Pins[0]);
 
-            MixerContext->Free(MixerControls);
-            MixerContext->Free(PinsSrcRef);
+        /* free topology pin array */
+        MixerContext->Free(Pins);
+    }
+    else
+    {
+        /* calculate destination line id */
+        DestinationLineID = (DESTINATION_LINE + MixerInfo->MixCaps.cDestinations-1);
+
+        /* add mixer controls */
+        Status = MMixerAddMixerControlsToDestinationLine(MixerContext, MixerInfo, MixerData->hDevice, Topology, OutConnection->Pin, bInput, DestinationLineID, &LineTerminator);
+
+        if (Status == MM_STATUS_SUCCESS)
+        {
+            /* now add the rest of the source lines */
+            Status = MMixerAddMixerSourceLines(MixerContext, MixerInfo, MixerData->hDevice, Topology, DestinationLineID, LineTerminator);
         }
     }
 
     return Status;
 }
 
-
 MIXER_STATUS
 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 LPMIXER_INFO MixerInfo,
+    IN PTOPOLOGY Topology,
     IN ULONG NodeIndex,
-    IN ULONG bInputMixer)
+    IN ULONG bInputMixer,
+    IN OUT LPMIXER_INFO * OutMixerInfo)
 {
-    LPMIXER_INFO MixerInfo;
+    ULONG Index;
     MIXER_STATUS Status;
     PKSPIN_PHYSICALCONNECTION OutConnection;
-    ULONG Index;
     ULONG * Pins;
-    ULONG bUsed;
-    ULONG BytesReturned;
-    KSP_PIN Pin;
-    LPWSTR Buffer = NULL;
-    ULONG PinId;
+    ULONG PinsFound;
+    ULONG NewMixerInfo = FALSE;
 
-    // allocate a mixer info struct
-    MixerInfo = (LPMIXER_INFO) MixerContext->Alloc(sizeof(MIXER_INFO));
-    if (!MixerInfo)
+    if (MixerInfo == NULL)
     {
-        // no memory
-        return MM_STATUS_NO_MEMORY;
-    }
+        /* allocate a mixer info struct */
+        MixerInfo = (LPMIXER_INFO) MixerContext->Alloc(sizeof(MIXER_INFO));
+        if (!MixerInfo)
+        {
+            /* 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
-    MixerInfo->MixCaps.fdwSupport = 0;
-    MixerInfo->MixCaps.cDestinations = 1;
-    MixerInfo->hMixer = MixerData->hDevice;
+        /* new mixer info */
+        NewMixerInfo = TRUE;
 
-    // get mixer name
-    MMixerGetDeviceName(MixerContext, MixerInfo, MixerData->hDeviceInterfaceKey);
+        /* 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 = 0;
 
-    // initialize line list
-    InitializeListHead(&MixerInfo->LineList);
-    InitializeListHead(&MixerInfo->EventList);
+        /* get mixer name */
+        MMixerGetDeviceName(MixerContext, MixerInfo->MixCaps.szPname, MixerData->hDeviceInterfaceKey);
 
-    // 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));
+        /* initialize line list */
+        InitializeListHead(&MixerInfo->LineList);
+        InitializeListHead(&MixerInfo->EventList);
 
-    if (!Pins)
-    {
-        // no memory
-        MMixerFreeMixerInfo(MixerContext, MixerInfo);
-        return MM_STATUS_NO_MEMORY;
+        /* associate with mixer data */
+        MixerData->MixerInfo = MixerInfo;
     }
 
-    // now get the target pins of the ADC / DAC node
-    Status = MMixerGetTargetPins(MixerContext, NodeTypes, NodeConnections, NodeIndex, !bInputMixer, Pins, PinCount);
+    /* store mixer info */
+    *OutMixerInfo = MixerInfo;
 
-    // find a target pin with a name
-    PinId = PinCount +1;
-    for(Index = 0; Index < PinCount; Index++)
-    {
-        if (Pins[Index])
-        {
-            // store index of pin
-            PinId = Index;
+    /* 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);
 
-            /* 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;
+    PinsFound = 0;
 
-            /* try get pin name size */
-            Status = MixerContext->Control(MixerData->hDevice, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSP_PIN), NULL, 0, &BytesReturned);
+    /* 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
+     */
+    PinsFound = 0;
+    MMixerGetAllUpOrDownstreamPinsFromNodeIndex(MixerContext, Topology, NodeIndex, !bInputMixer, &PinsFound, Pins);
 
-            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 there is no pin found, we have a broken topology */
+    ASSERT(PinsFound != 0);
 
-    if (PinId < PinCount)
+    /* now create a wave info struct */
+    Status = MMixerInitializeWaveInfo(MixerContext, MixerList, MixerData, MixerInfo->MixCaps.szPname, bInputMixer, PinsFound, Pins);
+    if (Status != MM_STATUS_SUCCESS)
     {
-        // create an wave info struct
-        MMixerInitializeWaveInfo(MixerContext, MixerList, MixerData, MixerInfo->MixCaps.szPname, bInputMixer, PinId);
+        /* failed to create wave info struct */
+        MixerContext->Free(MixerInfo);
+        MixerContext->Free(Pins);
+        return Status;
     }
 
-    Status = MMixerCreateDestinationLine(MixerContext, MixerInfo, bInputMixer, Buffer);
+    /* mark all found pins as reserved */
+    for(Index = 0; Index < PinsFound; Index++)
+    {
+        MMixerSetTopologyPinReserved(Topology, Pins[Index]);
+    }
 
-    if (Buffer)
+    if (bInputMixer)
     {
-        // free name
-        MixerContext->Free(Buffer);
+        /* pre create the mixer destination line for input mixers */
+        Status = MMixerBuildMixerDestinationLine(MixerContext, MixerInfo, MixerData->hDevice, Pins[0], bInputMixer);
+
+        if (Status != MM_STATUS_SUCCESS)
+        {
+            /* failed to create mixer destination line */
+            return Status;
+        }
     }
 
-    if (Status != MM_STATUS_SUCCESS)
+
+    /* 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);
+
+    PinsFound = 0;
+    MMixerGetAllUpOrDownstreamPinsFromNodeIndex(MixerContext, Topology, NodeIndex, bInputMixer, &PinsFound, Pins);
+
+    /* if there is no pin found, we have a broken topology */
+    ASSERT(PinsFound != 0);
+
+    /* there should be exactly one bridge pin */
+    ASSERT(PinsFound == 1);
+
+    DPRINT("BridgePin %lu bInputMixer %lu\n", Pins[0], bInputMixer);
+
+    /* does the pin have a physical connection */
+    Status = MMixerGetPhysicalConnection(MixerContext, MixerData->hDevice, Pins[0], &OutConnection);
+
+    if (Status == MM_STATUS_SUCCESS)
     {
-        // failed to create destination line
-        MixerContext->Free(MixerInfo);
-        MixerContext->Free(Pins);
+        /* mark pin as reserved */
+        MMixerSetTopologyPinReserved(Topology, Pins[0]);
 
-        return Status;
+        /* topology on the topoloy filter */
+        Status = MMixerHandlePhysicalConnection(MixerContext, MixerList, MixerData, MixerInfo, bInputMixer, OutConnection);
+
+        /* free physical connection data */
+        MixerContext->Free(OutConnection);
+    }
+    else
+    {
+        /* FIXME
+         * handle drivers which expose their topology on the same filter
+         */
+        ASSERT(0);
     }
 
-    RtlZeroMemory(Pins, sizeof(ULONG) * PinCount);
-    // now get the target pins of the ADC / DAC node
-    Status = MMixerGetTargetPins(MixerContext, NodeTypes, NodeConnections, NodeIndex, bInputMixer, Pins, PinCount);
+    /* free pins */
+    MixerContext->Free(Pins);
 
-    if (Status != MM_STATUS_SUCCESS)
+    if (NewMixerInfo)
     {
-        // failed to locate target pins
-        MixerContext->Free(Pins);
-        MMixerFreeMixerInfo(MixerContext, MixerInfo);
-        DPRINT("MMixerGetTargetPins failed with %u\n", Status);
-        return Status;
+        /* insert mixer */
+        InsertHeadList(&MixerList->MixerList, &MixerInfo->Entry);
+        /* increment mixer count */
+        MixerList->MixerListCount++;
     }
 
-    // filter hasnt been used
-    bUsed = FALSE;
+    /* done */
+    return Status;
+}
+
+VOID
+MMixerHandleAlternativeMixers(
+    IN PMIXER_CONTEXT MixerContext,
+    IN PMIXER_LIST MixerList,
+    IN LPMIXER_DATA MixerData,
+    IN PTOPOLOGY Topology)
+{
+    ULONG Index, PinCount, Reserved;
+    MIXER_STATUS Status;
+    ULONG DestinationLineID, LineTerminator;
+    LPMIXERLINE_EXT DstLine;
+
+    DPRINT("DeviceName %S\n", MixerData->DeviceName);
+
+    /* get topology pin count */
+    MMixerGetTopologyPinCount(Topology, &PinCount);
 
-    // now check all pins and generate new lines for destination lines
     for(Index = 0; Index < PinCount; Index++)
     {
-        DPRINT("Index %lu TargetPin %lu\n", Index, Pins[Index]);
-        // is the current index a target pin
-        if (Pins[Index])
+        MMixerIsTopologyPinReserved(Topology, Index, &Reserved);
+
+        /* check if it has already been reserved */
+        if (Reserved == TRUE)
         {
-            // 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;
-            }
+            /* pin has already been reserved */
+            continue;
         }
-    }
-    MixerContext->Free(Pins);
 
-    if (bUsed)
-    {
-        // store mixer info in list
-        if (!bInputMixer && MixerList->MixerListCount == 1)
+        DPRINT("MixerName %S Available PinID %lu\n", MixerData->DeviceName, Index);
+
+        /* sanity check */
+        //ASSERT(MixerData->MixerInfo);
+
+        if (!MixerData->MixerInfo)
         {
-            //FIXME preferred device should be inserted at front
-            //windows always inserts output mixer in front
-            InsertHeadList(&MixerList->MixerList, &MixerInfo->Entry);
+            DPRINT1("Expected mixer info\n");
+            continue;
         }
-        else
+
+        /* build the destination line */
+        Status = MMixerBuildMixerDestinationLine(MixerContext, MixerData->MixerInfo, MixerData->hDevice, Index, TRUE);
+        if (Status != MM_STATUS_SUCCESS)
         {
-            InsertTailList(&MixerList->MixerList, &MixerInfo->Entry);
+            /* failed to build destination line */
+            continue;
         }
-        MixerList->MixerListCount++;
-        DPRINT("New MixerCount %lu\n", MixerList->MixerListCount);
-    }
-    else
-    {
-        // failed to create a mixer topology
-        MMixerFreeMixerInfo(MixerContext, MixerInfo);
-    }
 
-    // done
-    return Status;
+        /* calculate destination line id */
+        DestinationLineID = (DESTINATION_LINE + MixerData->MixerInfo->MixCaps.cDestinations-1);
+
+        /* add mixer controls to destination line */
+        Status = MMixerAddMixerControlsToDestinationLine(MixerContext, MixerData->MixerInfo, MixerData->hDevice, MixerData->Topology, Index, TRUE, DestinationLineID,  &LineTerminator);
+        if (Status == MM_STATUS_SUCCESS)
+        {
+            /* now add the rest of the source lines */
+            Status = MMixerAddMixerSourceLines(MixerContext, MixerData->MixerInfo, MixerData->hDevice, MixerData->Topology, DestinationLineID, LineTerminator);
+        }
+
+        /* mark pin as consumed */
+        MMixerSetTopologyPinReserved(Topology, Index);
+
+        /* now grab destination line */
+        DstLine = MMixerGetSourceMixerLineByLineId(MixerData->MixerInfo, DestinationLineID);
+
+        /* set type and target as undefined */
+        DstLine->Line.dwComponentType = MIXERLINE_COMPONENTTYPE_DST_UNDEFINED;
+        DstLine->Line.Target.dwType = MIXERLINE_TARGETTYPE_UNDEFINED;
+        DstLine->Line.Target.vDriverVersion = 0;
+        DstLine->Line.Target.wMid = 0;
+        DstLine->Line.Target.wPid = 0;
+    }
 }
 
 MIXER_STATUS
@@ -1009,71 +1625,74 @@ MMixerSetupFilter(
     IN LPMIXER_DATA MixerData,
     IN PULONG DeviceCount)
 {
-    PKSMULTIPLE_ITEM NodeTypes = NULL, NodeConnections = NULL;
     MIXER_STATUS Status;
-    ULONG PinCount;
+    PTOPOLOGY Topology;
     ULONG NodeIndex;
+    LPMIXER_INFO MixerInfo = NULL;
 
-    // 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, NULL, Topology, NodeIndex, FALSE, &MixerInfo);
+
+        /* check for success */
         if (Status == MM_STATUS_SUCCESS)
         {
-            // increment mixer count
+            /* increment mixer count */
             (*DeviceCount)++;
         }
-
+        else
+        {
+            /* reset mixer info in case of error */
+            MixerInfo = NULL;
+        }
     }
 
-    // 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, MixerInfo, Topology, NodeIndex, TRUE, &MixerInfo);
+
+        /* 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);
+    /* TODO: apply hacks for Wave source line */
 
-    // done
+    /* activate midi devices */
+    //MMixerInitializeMidiForFilter(MixerContext, MixerList, MixerData, Topology);
+
+    /* done */
     return Status;
 }
 
@@ -1082,20 +1701,22 @@ MIXER_STATUS
 MMixerAddEvent(
     IN PMIXER_CONTEXT MixerContext,
     IN OUT LPMIXER_INFO MixerInfo,
-    IN ULONG NodeId)
+    IN PVOID MixerEventContext,
+    IN PMIXER_EVENT MixerEventRoutine)
 {
-    KSE_NODE Property;
-    LPEVENT_ITEM EventData;
-    ULONG BytesReturned;
-    MIXER_STATUS Status;
+    //KSE_NODE Property;
+    PEVENT_NOTIFICATION_ENTRY EventData;
+    //ULONG BytesReturned;
+    //MIXER_STATUS Status;
 
-    EventData = (LPEVENT_ITEM)MixerContext->AllocEventData(sizeof(LIST_ENTRY));
+    EventData = (PEVENT_NOTIFICATION_ENTRY)MixerContext->AllocEventData(sizeof(EVENT_NOTIFICATION_ENTRY));
     if (!EventData)
     {
-        // not enough memory
+        /* not enough memory */
         return MM_STATUS_NO_MEMORY;
     }
 
+#if 0
     /* setup request */
     Property.Event.Set = KSEVENTSETID_AudioControlChange;
     Property.Event.Flags = KSEVENT_TYPE_TOPOLOGY|KSEVENT_TYPE_ENABLE;
@@ -1107,48 +1728,18 @@ 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;
     }
+#endif
 
-    //store event
-    InsertTailList(&MixerInfo->EventList, &EventData->Entry);
-    return Status;
-}
-
-MIXER_STATUS
-MMixerAddEvents(
-    IN PMIXER_CONTEXT MixerContext,
-    IN OUT LPMIXER_INFO MixerInfo)
-{
-    PKSMULTIPLE_ITEM NodeTypes;
-    ULONG Index;
-    MIXER_STATUS Status;
-    LPGUID Guid;
-
-    // get filter node types
-    Status = MMixerGetFilterTopologyProperty(MixerContext, MixerInfo->hMixer, KSPROPERTY_TOPOLOGY_NODES, &NodeTypes);
-
-    if (Status != MM_STATUS_SUCCESS)
-    {
-        // failed
-        return Status;
-    }
-
-    for(Index = 0; Index < NodeTypes->Count; Index++)
-    {
-        Guid = MMixerGetNodeType(NodeTypes, Index);
-        if (IsEqualGUID(&KSNODETYPE_VOLUME, Guid) || IsEqualGUID(&KSNODETYPE_MUTE, Guid))
-        {
-            //add an event for volume / mute controls
-            //TODO: extra control types
-            MMixerAddEvent(MixerContext, MixerInfo, Index);
-        }
-    }
-
-    // free node types
-    MixerContext->Free(NodeTypes);
+    /* initialize notification entry */
+    EventData->MixerEventContext = MixerEventContext;
+    EventData->MixerEventRoutine = MixerEventRoutine;
 
+    /* store event */
+    InsertTailList(&MixerInfo->EventList, &EventData->Entry);
     return MM_STATUS_SUCCESS;
 }
+