[AUDIO-BRINGUP]
[reactos.git] / lib / drivers / sound / mmixer / controls.c
index 0b2e499..7cae426 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 PTOPOLOGY Topology,
     IN ULONG NodeIndex,
     IN LPMIXERLINE_EXT MixerLine,
     OUT LPMIXERCONTROLW MixerControl)
@@ -166,12 +48,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)
     {
@@ -182,7 +64,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 */
@@ -193,7 +75,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)
     {
@@ -206,7 +88,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)
         {
@@ -264,7 +146,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)
         {
@@ -320,234 +202,6 @@ MMixerAddMixerControl(
     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++;
-    }
-
-    return MM_STATUS_SUCCESS;
-}
-
 MIXER_STATUS
 MMixerCreateDestinationLine(
     IN PMIXER_CONTEXT MixerContext,
@@ -557,22 +211,23 @@ 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.dwSource = MAXULONG;
-    DestinationLine->Line.dwLineID = DESTINATION_LINE;
+    DestinationLine->Line.dwLineID = MixerInfo->MixCaps.cDestinations + DESTINATION_LINE;
     DestinationLine->Line.fdwLine = MIXERLINE_LINEF_ACTIVE;
     DestinationLine->Line.dwUser = 0;
+    DestinationLine->Line.dwDestination = MixerInfo->MixCaps.cDestinations;
     DestinationLine->Line.dwComponentType = (bInputMixer == 0 ? MIXERLINE_COMPONENTTYPE_DST_SPEAKERS : MIXERLINE_COMPONENTTYPE_DST_WAVEIN);
-    DestinationLine->Line.cChannels = 2; //FIXME
+    DestinationLine->Line.cChannels = 2; /* FIXME */
 
     if (LineName)
     {
@@ -583,497 +238,1189 @@ 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
+    /* initialize extra line */
     InitializeListHead(&DestinationLine->LineControlsExtraData);
 
-    // insert into mixer info
-    InsertHeadList(&MixerInfo->LineList, &DestinationLine->Entry);
+    /* insert into mixer info */
+    InsertTailList(&MixerInfo->LineList, &DestinationLine->Entry);
 
-    // done
+    /* increment destination count */
+    MixerInfo->MixCaps.cDestinations++;
+
+    /* 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 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(MixerInfo->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(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;
+        }
 
-    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 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, 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 MM_STATUS_SUCCESS;
-}
 
+    return Status;
+}
 
 MIXER_STATUS
-MMixerHandlePhysicalConnection(
+MMixerBuildTopology(
     IN PMIXER_CONTEXT MixerContext,
-    IN PMIXER_LIST MixerList,
-    IN OUT LPMIXER_INFO MixerInfo,
-    IN ULONG bInput,
-    IN PKSPIN_PHYSICALCONNECTION OutConnection)
+    IN LPMIXER_DATA MixerData,
+    OUT PTOPOLOGY * OutTopology)
 {
-    PULONG PinsRef = NULL, PinConnectionIndex = NULL, PinsSrcRef;
-    ULONG PinsRefCount, Index, PinConnectionIndexCount;
-    MIXER_STATUS Status;
+    ULONG PinsCount;
     PKSMULTIPLE_ITEM NodeTypes = NULL;
     PKSMULTIPLE_ITEM NodeConnections = NULL;
-    PULONG MixerControls;
-    ULONG MixerControlsCount;
-    LPMIXER_DATA MixerData;
-
+    MIXER_STATUS Status;
 
-    // open the connected filter
-    OutConnection->SymbolicLinkName[1] = L'\\';
-    MixerData = MMixerGetDataByDeviceName(MixerList, OutConnection->SymbolicLinkName);
-    ASSERT(MixerData);
+    if (MixerData->Topology)
+    {
+        /* re-use existing topology */
+        *OutTopology = MixerData->Topology;
 
-    // store connected mixer handle
-    MixerInfo->hMixer = MixerData->hDevice;
+        return MM_STATUS_SUCCESS;
+    }
 
-    // get connected filter pin count
-    PinsRefCount = MMixerGetFilterPinCount(MixerContext, MixerData->hDevice);
-    ASSERT(PinsRefCount);
+    /* get connected filter pin count */
+    PinsCount = MMixerGetFilterPinCount(MixerContext, MixerData->hDevice);
 
-    PinsRef = (PULONG)MixerContext->Alloc(sizeof(ULONG) * PinsRefCount);
-    if (!PinsRef)
+    if (!PinsCount)
     {
-        // no memory
+        /* referenced filter does not have any pins */
         return MM_STATUS_UNSUCCESSFUL;
     }
 
-    // get topology node types
+    /* get topology node types */
     Status = MMixerGetFilterTopologyProperty(MixerContext, MixerData->hDevice, KSPROPERTY_TOPOLOGY_NODES, &NodeTypes);
     if (Status != MM_STATUS_SUCCESS)
     {
-        MixerContext->Free(PinsRef);
+        /* failed to get topology node types */
         return Status;
     }
 
-    // get topology connections
+    /* get topology connections */
     Status = MMixerGetFilterTopologyProperty(MixerContext, MixerData->hDevice, KSPROPERTY_TOPOLOGY_CONNECTIONS, &NodeConnections);
     if (Status != MM_STATUS_SUCCESS)
     {
-        MixerContext->Free(PinsRef);
+        /* failed to get topology connections */
         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);
-    if (Status != MM_STATUS_SUCCESS)
-    {
-        MixerContext->Free(PinsRef);
-        MixerContext->Free(NodeTypes);
-        MixerContext->Free(NodeConnections);
-        return Status;
-    }
+    /* create a topology */
+    Status = MMixerCreateTopology(MixerContext, PinsCount, NodeConnections, NodeTypes, OutTopology);
 
-    /* there should be no split in the bride pin */
-    ASSERT(PinConnectionIndexCount == 1);
+    /* free node types & connections */
+    MixerContext->Free(NodeConnections);
+    MixerContext->Free(NodeTypes);
 
-    /* find all target pins of this connection */
-    Status = MMixerGetTargetPinsByNodeConnectionIndex(MixerContext, NodeConnections, NodeTypes, FALSE, PinConnectionIndex[0], PinsRef);
-    if (Status != MM_STATUS_SUCCESS)
+    if (Status == MM_STATUS_SUCCESS)
     {
-        MixerContext->Free(PinsRef);
-        MixerContext->Free(NodeTypes);
-        MixerContext->Free(NodeConnections);
-        MixerContext->Free(PinConnectionIndex);
-        return Status;
+        /* store topology object */
+        MixerData->Topology = *OutTopology;
     }
 
-    for(Index = 0; Index < PinsRefCount; Index++)
-    {
-        DPRINT("PinsRefCount %lu Index %lu Value %lu\n", PinsRefCount, Index, PinsRef[Index]);
-        if (PinsRef[Index])
-        {
-            // found a target pin, now get all references
-            Status = MMixerGetNodeIndexes(MixerContext, NodeConnections, Index, FALSE, FALSE, &MixerControlsCount, &MixerControls);
-            if (Status != MM_STATUS_SUCCESS)
+    /* 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)
             {
-                DPRINT("MMixerGetNodeIndexes failed with %u\n", Status);
-                break;
+                /* 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
+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)
+    {
+        /* out of memory */
+        return MM_STATUS_NO_MEMORY;
+    }
+
+    /* 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]);
+
+        /* 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++;
+        }
+    }
+
+    /* 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 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, MixerInfo->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(MixerInfo->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, MixerInfo->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;
 
-            /* sanity check */
-            ASSERT(MixerControlsCount == 1);
+            *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;
 
-            PinsSrcRef = (PULONG)MixerContext->Alloc(PinsRefCount * sizeof(ULONG));
-            if (!PinsSrcRef)
+            *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)
             {
-                /* no memory */
-                MixerContext->Free(PinsRef);
-                MixerContext->Free(NodeTypes);
-                MixerContext->Free(NodeConnections);
-                MixerContext->Free(PinConnectionIndex);
-                MixerContext->Free(MixerControls);
-                return MM_STATUS_NO_MEMORY;
+                *TargetType =  MIXERLINE_TARGETTYPE_WAVEOUT;
+                *ComponentType =  MIXERLINE_COMPONENTTYPE_DST_SPEAKERS;
             }
-
-            // now get all connected source pins
-            Status = MMixerGetTargetPinsByNodeConnectionIndex(MixerContext, NodeConnections, NodeTypes, TRUE, MixerControls[0], PinsSrcRef);
-            if (Status != MM_STATUS_SUCCESS)
+            else
             {
-                // failed */
-                MixerContext->Free(PinsRef);
-                MixerContext->Free(NodeTypes);
-                MixerContext->Free(NodeConnections);
-                MixerContext->Free(PinConnectionIndex);
-                MixerContext->Free(MixerControls);
-                MixerContext->Free(PinsSrcRef);
-                return Status;
+                *TargetType =  MIXERLINE_TARGETTYPE_WAVEIN;
+                *ComponentType =  MIXERLINE_COMPONENTTYPE_DST_WAVEIN;
             }
-
-            /* add pins from target line */
-            if (!bInput)
+        }
+        else if (IsEqualGUIDAligned(&Guid, &KSNODETYPE_SPDIF_INTERFACE))
+        {
+            /* type spdif */
+            if (BridgePin)
             {
-                // dont add bridge pin for input mixers
-                PinsSrcRef[Index] = TRUE;
-                PinsSrcRef[OutConnection->Pin] = TRUE;
+                *TargetType =  MIXERLINE_TARGETTYPE_WAVEOUT;
+                *ComponentType =  MIXERLINE_COMPONENTTYPE_DST_SPEAKERS;
+            }
+            else
+            {
+                *TargetType =  MIXERLINE_TARGETTYPE_WAVEIN;
+                *ComponentType =  MIXERLINE_COMPONENTTYPE_DST_WAVEIN;
             }
-            PinsSrcRef[OutConnection->Pin] = TRUE;
-
-            Status = MMixerAddMixerSourceLines(MixerContext, MixerInfo, MixerData->hDevice, NodeConnections, NodeTypes, PinsRefCount, OutConnection->Pin, Index, PinsSrcRef);
-
-            MixerContext->Free(MixerControls);
-            MixerContext->Free(PinsSrcRef);
+        }
+        else
+        {
+            /* unknown type */
+            *TargetType = MIXERLINE_TARGETTYPE_UNDEFINED;
+            *ComponentType = MIXERLINE_COMPONENTTYPE_DST_UNDEFINED;
+            DPRINT1("Unknown Category for PinId %lu BridgePin %lu\n", PinId, BridgePin);
         }
     }
 
-    return Status;
+    /* done */
+    return MM_STATUS_SUCCESS;
 }
 
-
 MIXER_STATUS
-MMixerInitializeFilter(
+MMixerBuildMixerSourceLine(
     IN PMIXER_CONTEXT MixerContext,
-    IN PMIXER_LIST MixerList,
-    IN LPMIXER_DATA MixerData,
-    IN PKSMULTIPLE_ITEM NodeTypes,
-    IN PKSMULTIPLE_ITEM NodeConnections,
-    IN ULONG PinCount,
-    IN ULONG NodeIndex,
-    IN ULONG bInputMixer)
+    IN OUT LPMIXER_INFO MixerInfo,
+    IN PTOPOLOGY Topology,
+    IN ULONG PinId,
+    IN ULONG NodesCount,
+    IN PULONG Nodes,
+    IN ULONG DestinationLineID,
+    OUT LPMIXERLINE_EXT * OutSrcLine)
 {
-    LPMIXER_INFO MixerInfo;
+    LPMIXERLINE_EXT SrcLine, DstLine;
+    LPWSTR PinName;
     MIXER_STATUS Status;
-    PKSPIN_PHYSICALCONNECTION OutConnection;
-    ULONG Index;
-    ULONG * Pins;
-    ULONG bUsed;
-    ULONG BytesReturned;
-    KSP_PIN Pin;
-    LPWSTR Buffer = NULL;
-    ULONG PinId;
+    ULONG ComponentType, TargetType;
 
-    // allocate a mixer info struct
-    MixerInfo = (LPMIXER_INFO) MixerContext->Alloc(sizeof(MIXER_INFO));
-    if (!MixerInfo)
+    /* get component and target type */
+    Status = MMixerGetComponentAndTargetType(MixerContext, MixerInfo, 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
+        /* 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;
+    /* get destination line */
+    DstLine = MMixerGetSourceMixerLineByLineId(MixerInfo, DestinationLineID);
+    ASSERT(DstLine);
 
-    // get mixer name
-    MMixerGetDeviceName(MixerContext, MixerInfo, MixerData->hDeviceInterfaceKey);
+    /* 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 = 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->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);
 
-    // initialize line list
-    InitializeListHead(&MixerInfo->LineList);
-    InitializeListHead(&MixerInfo->EventList);
+    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';
 
-    // 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));
+        /* free pin name buffer */
+        MixerContext->Free(PinName);
+    }
 
-    if (!Pins)
+    /* add the controls to mixer line */
+    Status = MMixerAddMixerControlsToMixerLineByNodeIndexArray(MixerContext, MixerInfo, Topology, SrcLine, NodesCount, Nodes);
+    if (Status != MM_STATUS_SUCCESS)
     {
-        // no memory
-        MMixerFreeMixerInfo(MixerContext, MixerInfo);
+        /* failed */
+        return Status;
+    }
+
+    /* store result */
+    *OutSrcLine = SrcLine;
+
+    return MM_STATUS_SUCCESS;
+}
+
+MIXER_STATUS
+MMixerAddMixerSourceLines(
+    IN PMIXER_CONTEXT MixerContext,
+    IN OUT LPMIXER_INFO MixerInfo,
+    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;
     }
 
-    // now get the target pins of the ADC / DAC node
-    Status = MMixerGetTargetPins(MixerContext, NodeTypes, NodeConnections, NodeIndex, !bInputMixer, Pins, PinCount);
+    /* 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);
 
-    // find a target pin with a name
-    PinId = PinCount +1;
-    for(Index = 0; Index < PinCount; Index++)
+    /* check for success */
+    if (Status != MM_STATUS_SUCCESS)
     {
-        if (Pins[Index])
-        {
-            // store index of pin
-            PinId = Index;
+        /* 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);
 
-            /* 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;
+    /* get all pins which indirectly / directly connect to this node */
+    AllPinsCount = 0;
+    MMixerGetAllUpOrDownstreamPinsFromNodeIndex(MixerContext, Topology, LineTerminator, TRUE, &AllPinsCount, AllPins);
 
-            /* try get pin name size */
-            Status = MixerContext->Control(MixerData->hDevice, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSP_PIN), NULL, 0, &BytesReturned);
+    DPRINT1("LineTerminator %lu\n", LineTerminator);
+    DPRINT1("PinCount %lu\n", AllPinsCount);
+    DPRINT1("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 (Status == MM_STATUS_MORE_ENTRIES)
+            if (CurNode != MAXULONG && CurNode != LineTerminator)
             {
-                Buffer = (LPWSTR)MixerContext->Alloc(BytesReturned);
-                if (Buffer)
+                /* 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)
                 {
-                    /* 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;
-                    }
+                    /* 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, 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++;
+#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
+MMixerAddMixerControlsToDestinationLine(
+    IN PMIXER_CONTEXT MixerContext,
+    IN OUT LPMIXER_INFO MixerInfo,
+    IN PTOPOLOGY Topology,
+    IN ULONG PinId,
+    IN ULONG bInput,
+    IN ULONG DestinationLineId,
+    OUT PULONG OutLineTerminator)
+{
+    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;
     }
 
-    if (PinId < PinCount)
+    /* get all destination line controls */
+    Status = MMixerCountMixerControls(MixerContext, Topology, PinId, bInput, TRUE, &NodesCount, Nodes, &LineTerminator);
+
+    /* check for success */
+    if (Status != MM_STATUS_SUCCESS)
     {
-        // create an wave info struct
-        MMixerInitializeWaveInfo(MixerContext, MixerList, MixerData, MixerInfo->MixCaps.szPname, bInputMixer, PinId);
+        /* failed to count controls */
+        MixerContext->Free(Nodes);
+        return Status;
     }
 
-    Status = MMixerCreateDestinationLine(MixerContext, MixerInfo, bInputMixer, Buffer);
+    /* get destination mixer line */
+    DstLine = MMixerGetSourceMixerLineByLineId(MixerInfo, DestinationLineId);
+
+    /* sanity check */
+    ASSERT(DstLine);
 
-    if (Buffer)
+    if (NodesCount > 0)
     {
-        // free name
-        MixerContext->Free(Buffer);
+        /* add all nodes as mixer controls to the destination line */
+        Status = MMixerAddMixerControlsToMixerLineByNodeIndexArray(MixerContext, MixerInfo, Topology, DstLine, NodesCount, Nodes);
+        if (Status != MM_STATUS_SUCCESS)
+        {
+            /* failed to add controls */
+            MixerContext->Free(Nodes);
+            return Status;
+        }
     }
 
-    if (Status != MM_STATUS_SUCCESS)
+    /* store result */
+    *OutLineTerminator = LineTerminator;
+
+    /* return result */
+    return Status;
+}
+
+VOID
+MMixerApplyOutputFilterHack(
+    IN PMIXER_CONTEXT MixerContext,
+    IN LPMIXER_DATA MixerData,
+    IN OUT PULONG PinsCount,
+    IN OUT PULONG Pins)
+{
+    ULONG Count = 0, Index;
+    MIXER_STATUS Status;
+    PKSPIN_PHYSICALCONNECTION Connection;
+
+    for(Index = 0; Index < *PinsCount; Index++)
     {
-        // failed to create destination line
-        MixerContext->Free(MixerInfo);
-        MixerContext->Free(Pins);
+        /* check if it has a physical connection */
+        Status = MMixerGetPhysicalConnection(MixerContext, MixerData->hDevice, Pins[Index], &Connection);
 
-        return Status;
+        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++;
+        }
     }
 
-    RtlZeroMemory(Pins, sizeof(ULONG) * PinCount);
-    // now get the target pins of the ADC / DAC node
-    Status = MMixerGetTargetPins(MixerContext, NodeTypes, NodeConnections, NodeIndex, bInputMixer, Pins, PinCount);
+    /* store result */
+    *PinsCount = Count;
+}
 
-    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;
+     }
+
+    DPRINT1("Name %S, Pin %lu bInput %lu\n", OutConnection->SymbolicLinkName, OutConnection->Pin, bInput);
+
+    if (MixerInfo->hMixer != NULL)
     {
-        // failed to locate target pins
-        MixerContext->Free(Pins);
-        MMixerFreeMixerInfo(MixerContext, MixerInfo);
-        DPRINT("MMixerGetTargetPins failed with %u\n", Status);
-        return Status;
+         /* dont replace mixer destination handles */
+         DPRINT1("MixerInfo hDevice %p MixerData hDevice %p\n", MixerInfo->hMixer, MixerData->hDevice);
+         ASSERT(MixerInfo->hMixer == MixerData->hDevice);
     }
 
-    // filter hasnt been used
-    bUsed = FALSE;
+    /* store connected mixer handle */
+    MixerInfo->hMixer = MixerData->hDevice;
 
-    // now check all pins and generate new lines for destination lines
-    for(Index = 0; Index < PinCount; Index++)
+    if (MixerData->Topology == NULL)
     {
-        DPRINT("Index %lu TargetPin %lu\n", Index, Pins[Index]);
-        // is the current index a target pin
-        if (Pins[Index])
+        /* construct new topology */
+        Status = MMixerBuildTopology(MixerContext, MixerData, &Topology);
+        if (Status != MM_STATUS_SUCCESS)
         {
-            // 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;
-            }
+            /* failed to create topology */
+            return Status;
         }
+
+        /* store topology */
+        MixerData->Topology = Topology;
     }
-    MixerContext->Free(Pins);
+    else
+    {
+        /* re-use existing topology */
+        Topology = MixerData->Topology;
+    }
+
+    /* allocate pin index array which will hold all referenced pins */
+    Status = MMixerAllocateTopologyPinArray(MixerContext, Topology, &Pins);
+    ASSERT(Status == MM_STATUS_SUCCESS);
 
-    if (bUsed)
+    if (!bInput)
     {
-        // store mixer info in list
-        if (!bInputMixer && MixerList->MixerListCount == 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);
+
+        /* check for success */
+        if (Status != MM_STATUS_SUCCESS)
         {
-            //FIXME preferred device should be inserted at front
-            //windows always inserts output mixer in front
-            InsertHeadList(&MixerList->MixerList, &MixerInfo->Entry);
+            /* failed to get end pin */
+            MixerContext->Free(Pins);
+            //MMixerFreeTopology(Topology);
+
+            /* return error code */
+            return Status;
         }
-        else
+        /* 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, &PinsCount, Pins);
+
+        /* sanity checks */
+        ASSERT(PinsCount != 0);
+        ASSERT(PinsCount == 1);
+
+        /* create destination line */
+        Status = MMixerBuildMixerDestinationLine(MixerContext, MixerInfo, Pins[0], bInput);
+
+        /* calculate destination line id */
+        DestinationLineID = (DESTINATION_LINE + MixerInfo->MixCaps.cDestinations-1);
+
+        if (Status != MM_STATUS_SUCCESS)
         {
-            InsertTailList(&MixerList->MixerList, &MixerInfo->Entry);
+            /* failed to build destination line */
+            MixerContext->Free(Pins);
+
+            /* return error code */
+            return Status;
+        }
+
+        /* add mixer controls to destination line */
+        Status = MMixerAddMixerControlsToDestinationLine(MixerContext, MixerInfo, Topology, Pins[0], bInput, DestinationLineID,  &LineTerminator);
+
+        if (Status == MM_STATUS_SUCCESS)
+        {
+            /* now add the rest of the source lines */
+            Status = MMixerAddMixerSourceLines(MixerContext, MixerInfo, Topology, DestinationLineID, LineTerminator);
         }
-        MixerList->MixerListCount++;
-        DPRINT("New MixerCount %lu\n", MixerList->MixerListCount);
     }
     else
     {
-        // failed to create a mixer topology
-        MMixerFreeMixerInfo(MixerContext, MixerInfo);
+        /* calculate destination line id */
+        DestinationLineID = (DESTINATION_LINE + MixerInfo->MixCaps.cDestinations-1);
+
+        /* add mixer controls */
+        Status = MMixerAddMixerControlsToDestinationLine(MixerContext, MixerInfo, Topology, OutConnection->Pin, bInput, DestinationLineID, &LineTerminator);
+
+        if (Status == MM_STATUS_SUCCESS)
+        {
+            /* now add the rest of the source lines */
+            Status = MMixerAddMixerSourceLines(MixerContext, MixerInfo, Topology, DestinationLineID, LineTerminator);
+        }
     }
 
-    // done
     return Status;
 }
 
 MIXER_STATUS
-MMixerSetupFilter(
+MMixerInitializeFilter(
     IN PMIXER_CONTEXT MixerContext,
     IN PMIXER_LIST MixerList,
     IN LPMIXER_DATA MixerData,
-    IN PULONG DeviceCount)
+    IN LPMIXER_INFO MixerInfo,
+    IN PTOPOLOGY Topology,
+    IN ULONG NodeIndex,
+    IN ULONG bInputMixer,
+    IN OUT LPMIXER_INFO * OutMixerInfo)
 {
-    PKSMULTIPLE_ITEM NodeTypes = NULL, NodeConnections = NULL;
+
     MIXER_STATUS Status;
-    ULONG PinCount;
-    ULONG NodeIndex;
+    PKSPIN_PHYSICALCONNECTION OutConnection;
+    ULONG * Pins;
+    ULONG PinsFound;
+    ULONG NewMixerInfo = FALSE;
+
+    if (MixerInfo == NULL)
+    {
+        /* allocate a mixer info struct */
+        MixerInfo = (LPMIXER_INFO) MixerContext->Alloc(sizeof(MIXER_INFO));
+        if (!MixerInfo)
+        {
+            /* no memory */
+            return MM_STATUS_NO_MEMORY;
+        }
 
-    // get number of pins
-    PinCount = MMixerGetFilterPinCount(MixerContext, MixerData->hDevice);
-    ASSERT(PinCount);
-    DPRINT("NumOfPins: %lu\n", PinCount);
+        /* new mixer info */
+        NewMixerInfo = TRUE;
 
-    // get filter node types
-    Status = MMixerGetFilterTopologyProperty(MixerContext, MixerData->hDevice, KSPROPERTY_TOPOLOGY_NODES, &NodeTypes);
+        /* 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;
+
+        /* get mixer name */
+        MMixerGetDeviceName(MixerContext, MixerInfo->MixCaps.szPname, MixerData->hDeviceInterfaceKey);
+
+        /* initialize line list */
+        InitializeListHead(&MixerInfo->LineList);
+        InitializeListHead(&MixerInfo->EventList);
+    }
+
+    /* store mixer info */
+    *OutMixerInfo = MixerInfo;
+
+    /* 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);
+
+    PinsFound = 0;
+
+    /* 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 there is no pin found, we have a broken topology */
+    ASSERT(PinsFound != 0);
+
+    /* now create a wave info struct */
+    Status = MMixerInitializeWaveInfo(MixerContext, MixerList, MixerData, MixerInfo->MixCaps.szPname, bInputMixer, PinsFound, Pins);
     if (Status != MM_STATUS_SUCCESS)
     {
-        // failed
+        /* failed to create wave info struct */
+        MixerContext->Free(MixerInfo);
+        MixerContext->Free(Pins);
         return Status;
     }
 
-    // get filter node connections
-    Status = MMixerGetFilterTopologyProperty(MixerContext, MixerData->hDevice, KSPROPERTY_TOPOLOGY_CONNECTIONS, &NodeConnections);
-    if (Status != MM_STATUS_SUCCESS)
+    if (bInputMixer)
     {
-        // failed
-        MixerContext->Free(NodeTypes);
-        return Status;
+        /* pre create the mixer destination line for input mixers */
+        Status = MMixerBuildMixerDestinationLine(MixerContext, MixerInfo, Pins[0], bInputMixer);
+
+        if (Status != MM_STATUS_SUCCESS)
+        {
+            /* failed to create mixer destination line */
+            return Status;
+        }
     }
 
-    // check if the filter has an wave out node
 
-    NodeIndex = MMixerGetIndexOfGuid(NodeTypes, &KSNODETYPE_DAC);
+    /* 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)
+    {
+        /* 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);
+        MixerInfo->hMixer = MixerData->hDevice;
+    }
+
+    /* free pins */
+    MixerContext->Free(Pins);
+
+    if (NewMixerInfo)
+    {
+        /* insert mixer */
+        InsertHeadList(&MixerList->MixerList, &MixerInfo->Entry);
+        /* increment mixer count */
+        MixerList->MixerListCount++;
+    }
+
+    /* done */
+    return Status;
+}
+
+MIXER_STATUS
+MMixerSetupFilter(
+    IN PMIXER_CONTEXT MixerContext,
+    IN PMIXER_LIST MixerList,
+    IN LPMIXER_DATA MixerData,
+    IN PULONG DeviceCount)
+{
+    MIXER_STATUS Status;
+    PTOPOLOGY Topology;
+    ULONG NodeIndex;
+    LPMIXER_INFO MixerInfo = NULL;
+
+    /* check if topology has already been built */
+    if (MixerData->Topology == NULL)
+    {
+        /* build topology */
+        Status = MMixerBuildTopology(MixerContext, MixerData, &Topology);
+
+        if (Status != MM_STATUS_SUCCESS)
+        {
+            /* failed to build topology */
+            return Status;
+        }
+
+        /* store topology */
+        MixerData->Topology = Topology;
+    }
+    else
+    {
+        /* re-use topology */
+        Topology = MixerData->Topology;
+    }
+
+    /* 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: handle alternative mixer types + apply hacks for Wave source line */
 
-    // done
+    /* activate midi devices */
+    MMixerInitializeMidiForFilter(MixerContext, MixerList, MixerData, Topology);
+
+    /* done */
     return Status;
 }
 
@@ -1082,20 +1429,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 +1456,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;
 
+    /* store event */
+    InsertTailList(&MixerInfo->EventList, &EventData->Entry);
     return MM_STATUS_SUCCESS;
 }
+