Git conversion: Make reactos the root directory, move rosapps, rostests, wallpapers...
[reactos.git] / sdk / lib / drivers / sound / mmixer / mixer.c
diff --git a/sdk/lib/drivers/sound/mmixer/mixer.c b/sdk/lib/drivers/sound/mmixer/mixer.c
new file mode 100644 (file)
index 0000000..3b8d900
--- /dev/null
@@ -0,0 +1,884 @@
+/*
+ * COPYRIGHT:       See COPYING in the top level directory
+ * PROJECT:         ReactOS Kernel Streaming
+ * FILE:            lib/drivers/sound/mmixer/mmixer.c
+ * PURPOSE:         Mixer Handling Functions
+ * PROGRAMMER:      Johannes Anderwald
+ */
+
+#include "precomp.h"
+
+#define YDEBUG
+#include <debug.h>
+
+ULONG
+MMixerGetCount(
+    IN PMIXER_CONTEXT MixerContext)
+{
+    PMIXER_LIST MixerList;
+    MIXER_STATUS Status;
+
+    /* verify mixer context */
+    Status = MMixerVerifyContext(MixerContext);
+
+    if (Status != MM_STATUS_SUCCESS)
+    {
+        /* invalid context passed */
+        return Status;
+    }
+
+    /* grab mixer list */
+    MixerList = (PMIXER_LIST)MixerContext->MixerContext;
+
+    // return number of mixers
+    return MixerList->MixerListCount;
+}
+
+MIXER_STATUS
+MMixerGetCapabilities(
+    IN PMIXER_CONTEXT MixerContext,
+    IN ULONG MixerIndex,
+    OUT LPMIXERCAPSW MixerCaps)
+{
+    MIXER_STATUS Status;
+    LPMIXER_INFO MixerInfo;
+
+    /* verify mixer context */
+    Status = MMixerVerifyContext(MixerContext);
+
+    if (Status != MM_STATUS_SUCCESS)
+    {
+        /* invalid context passed */
+        return Status;
+    }
+
+    /* get mixer info */
+    MixerInfo = MMixerGetMixerInfoByIndex(MixerContext, MixerIndex);
+
+    if (!MixerInfo)
+    {
+        // invalid device index
+        return MM_STATUS_INVALID_PARAMETER;
+    }
+
+    MixerCaps->wMid = MixerInfo->MixCaps.wMid;
+    MixerCaps->wPid = MixerInfo->MixCaps.wPid;
+    MixerCaps->vDriverVersion = MixerInfo->MixCaps.vDriverVersion;
+    MixerCaps->fdwSupport = MixerInfo->MixCaps.fdwSupport;
+    MixerCaps->cDestinations = MixerInfo->MixCaps.cDestinations;
+
+    ASSERT(MixerInfo->MixCaps.szPname[MAXPNAMELEN-1] == 0);
+    wcscpy(MixerCaps->szPname, MixerInfo->MixCaps.szPname);
+
+    return MM_STATUS_SUCCESS;
+}
+
+MIXER_STATUS
+MMixerOpen(
+    IN PMIXER_CONTEXT MixerContext,
+    IN ULONG MixerId,
+    IN PVOID MixerEventContext,
+    IN PMIXER_EVENT MixerEventRoutine,
+    OUT PHANDLE MixerHandle)
+{
+    MIXER_STATUS Status;
+    LPMIXER_INFO MixerInfo;
+
+    /* verify mixer context */
+    Status = MMixerVerifyContext(MixerContext);
+
+    if (Status != MM_STATUS_SUCCESS)
+    {
+        /* invalid context passed */
+        DPRINT1("invalid context\n");
+        return Status;
+    }
+
+    /* get mixer info */
+    MixerInfo = (LPMIXER_INFO)MMixerGetMixerInfoByIndex(MixerContext, MixerId);
+    if (!MixerInfo)
+    {
+        /* invalid mixer id */
+        DPRINT1("invalid mixer id %lu\n", MixerId);
+        return MM_STATUS_INVALID_PARAMETER;
+    }
+
+    /* add the event */
+    Status = MMixerAddEvent(MixerContext, MixerInfo, MixerEventContext, MixerEventRoutine);
+
+
+    /* store result */
+    *MixerHandle = (HANDLE)MixerInfo;
+    return MM_STATUS_SUCCESS;
+}
+
+MIXER_STATUS
+MMixerClose(
+    IN PMIXER_CONTEXT MixerContext,
+    IN ULONG MixerId,
+    IN PVOID MixerEventContext,
+    IN PMIXER_EVENT MixerEventRoutine)
+{
+    MIXER_STATUS Status;
+    LPMIXER_INFO MixerInfo;
+
+    /* verify mixer context */
+    Status = MMixerVerifyContext(MixerContext);
+
+    if (Status != MM_STATUS_SUCCESS)
+    {
+        /* invalid context passed */
+        DPRINT1("invalid context\n");
+        return Status;
+    }
+
+    /* get mixer info */
+    MixerInfo = MMixerGetMixerInfoByIndex(MixerContext, MixerId);
+    if (!MixerInfo)
+    {
+        /* invalid mixer id */
+        DPRINT1("invalid mixer id %lu\n", MixerId);
+        return MM_STATUS_INVALID_PARAMETER;
+    }
+
+    /* remove event from list */
+    return MMixerRemoveEvent(MixerContext, MixerInfo, MixerEventContext, MixerEventRoutine);
+}
+
+MIXER_STATUS
+MMixerGetLineInfo(
+    IN PMIXER_CONTEXT MixerContext,
+    IN HANDLE MixerHandle,
+    IN ULONG MixerId,
+    IN ULONG Flags,
+    OUT LPMIXERLINEW MixerLine)
+{
+    MIXER_STATUS Status;
+    LPMIXER_INFO MixerInfo;
+    LPMIXERLINE_EXT MixerLineSrc;
+    ULONG DestinationLineID;
+
+    /* verify mixer context */
+    Status = MMixerVerifyContext(MixerContext);
+
+    if (Status != MM_STATUS_SUCCESS)
+    {
+        /* invalid context passed */
+        return Status;
+    }
+    if ((Flags & (MIXER_OBJECTF_MIXER | MIXER_OBJECTF_HMIXER)) == MIXER_OBJECTF_MIXER)
+    {
+        /* caller passed mixer id */
+        MixerHandle = (HANDLE)MMixerGetMixerInfoByIndex(MixerContext, MixerId);
+
+        if (!MixerHandle)
+        {
+            /* invalid parameter */
+            return MM_STATUS_INVALID_PARAMETER;
+        }
+    }
+
+    if (MixerLine->cbStruct != sizeof(MIXERLINEW))
+    {
+        DPRINT1("MixerLine Expected %lu but got %lu\n", sizeof(MIXERLINEW), MixerLine->cbStruct);
+        return MM_STATUS_INVALID_PARAMETER;
+    }
+
+    /* clear hmixer from flags */
+    Flags &=~MIXER_OBJECTF_HMIXER;
+
+    DPRINT("MMixerGetLineInfo MixerId %lu Flags %lu\n", MixerId, Flags);
+
+    if (Flags == MIXER_GETLINEINFOF_DESTINATION)
+    {
+        /* cast to mixer info */
+        MixerInfo = (LPMIXER_INFO)MixerHandle;
+
+        /* calculate destination line id */
+        DestinationLineID = (MixerLine->dwDestination + DESTINATION_LINE);
+
+        /* get destination line */
+        MixerLineSrc = MMixerGetSourceMixerLineByLineId(MixerInfo, DestinationLineID);
+
+        if (MixerLineSrc == NULL)
+        {
+            DPRINT1("MixerCaps Name %S DestinationLineCount %lu dwDestination %lu not found\n", MixerInfo->MixCaps.szPname, MixerInfo->MixCaps.cDestinations, MixerLine->dwDestination);
+            return MM_STATUS_UNSUCCESSFUL;
+        }
+        /* copy mixer line */
+        MixerContext->Copy(MixerLine, &MixerLineSrc->Line, sizeof(MIXERLINEW));
+
+        /* make sure it is null terminated */
+        MixerLine->szName[MIXER_LONG_NAME_CHARS-1] = L'\0';
+        MixerLine->szShortName[MIXER_SHORT_NAME_CHARS-1] = L'\0';
+        MixerLine->Target.szPname[MAXPNAMELEN-1] = L'\0';
+
+        /* done */
+        return MM_STATUS_SUCCESS;
+    }
+    else if (Flags == MIXER_GETLINEINFOF_SOURCE)
+    {
+        /* cast to mixer info */
+        MixerInfo = (LPMIXER_INFO)MixerHandle;
+
+        /* calculate destination line id */
+        DestinationLineID = (MixerLine->dwDestination + DESTINATION_LINE);
+
+        /* get destination line */
+        MixerLineSrc = MMixerGetSourceMixerLineByLineId(MixerInfo, DestinationLineID);
+
+        if (MixerLineSrc == NULL)
+        {
+            DPRINT1("MixerCaps Name %S DestinationLineCount %lu dwDestination %lu not found\n", MixerInfo->MixCaps.szPname, MixerInfo->MixCaps.cDestinations, MixerLine->dwDestination);
+            return MM_STATUS_UNSUCCESSFUL;
+        }
+
+        /* check if dwSource is out of bounds */
+        if (MixerLine->dwSource >= MixerLineSrc->Line.cConnections)
+        {
+            DPRINT1("MixerCaps Name %S MixerLineName %S Connections %lu dwSource %lu not found\n", MixerInfo->MixCaps.szPname, MixerLineSrc->Line.szName, MixerLineSrc->Line.cConnections, MixerLine->dwSource);
+            return MM_STATUS_UNSUCCESSFUL;
+        }
+
+        /* calculate destination line id */
+        DestinationLineID = (MixerLine->dwSource * SOURCE_LINE) + MixerLine->dwDestination;
+
+        DPRINT("MixerName %S cDestinations %lu MixerLineName %S cConnections %lu dwSource %lu dwDestination %lu ID %lx\n", MixerInfo->MixCaps.szPname, MixerInfo->MixCaps.cDestinations,
+                                                                                                                            MixerLineSrc->Line.szName, MixerLineSrc->Line.cConnections,
+                                                                                                                            MixerLine->dwSource, MixerLine->dwDestination,
+                                                                                                                            DestinationLineID);
+        /* get target destination line id */
+        MixerLineSrc = MMixerGetSourceMixerLineByLineId(MixerInfo, DestinationLineID);
+
+        /* sanity check */
+        ASSERT(MixerLineSrc);
+
+        DPRINT("Line %u Name %S\n", MixerLineSrc->Line.dwSource, MixerLineSrc->Line.szName);
+
+        /* copy mixer line */
+        MixerContext->Copy(MixerLine, &MixerLineSrc->Line, sizeof(MIXERLINEW));
+
+        /* make sure it is null terminated */
+        MixerLine->szName[MIXER_LONG_NAME_CHARS-1] = L'\0';
+        MixerLine->szShortName[MIXER_SHORT_NAME_CHARS-1] = L'\0';
+        MixerLine->Target.szPname[MAXPNAMELEN-1] = L'\0';
+
+        /* done */
+        return MM_STATUS_SUCCESS;
+    }
+    else if (Flags == MIXER_GETLINEINFOF_LINEID)
+    {
+        /* cast to mixer info */
+        MixerInfo = (LPMIXER_INFO)MixerHandle;
+
+        /* try to find line */
+        MixerLineSrc = MMixerGetSourceMixerLineByLineId(MixerInfo, MixerLine->dwLineID);
+        if (!MixerLineSrc)
+        {
+            /* invalid parameter */
+            DPRINT1("MMixerGetLineInfo: MixerName %S Line not found 0x%lx\n", MixerInfo->MixCaps.szPname, MixerLine->dwLineID);
+            return MM_STATUS_INVALID_PARAMETER;
+        }
+
+        DPRINT("Line %u Name %S\n", MixerLineSrc->Line.dwSource, MixerLineSrc->Line.szName);
+
+        /* copy mixer line*/
+        MixerContext->Copy(MixerLine, &MixerLineSrc->Line, sizeof(MIXERLINEW));
+
+        /* make sure it is null terminated */
+        MixerLine->szName[MIXER_LONG_NAME_CHARS-1] = L'\0';
+        MixerLine->szShortName[MIXER_SHORT_NAME_CHARS-1] = L'\0';
+        MixerLine->Target.szPname[MAXPNAMELEN-1] = L'\0';
+
+        return MM_STATUS_SUCCESS;
+    }
+    else if (Flags == MIXER_GETLINEINFOF_COMPONENTTYPE)
+    {
+        /* cast to mixer info */
+        MixerInfo = (LPMIXER_INFO)MixerHandle;
+
+        /* find mixer line by component type */
+        MixerLineSrc = MMixerGetSourceMixerLineByComponentType(MixerInfo, MixerLine->dwComponentType);
+        if (!MixerLineSrc)
+        {
+            DPRINT1("Failed to find component type %x\n", MixerLine->dwComponentType);
+            return MM_STATUS_UNSUCCESSFUL;
+        }
+
+        /* copy mixer line */
+        MixerContext->Copy(MixerLine, &MixerLineSrc->Line, sizeof(MIXERLINEW));
+
+        /* make sure it is null terminated */
+        MixerLine->szName[MIXER_LONG_NAME_CHARS-1] = L'\0';
+        MixerLine->szShortName[MIXER_SHORT_NAME_CHARS-1] = L'\0';
+        MixerLine->Target.szPname[MAXPNAMELEN-1] = L'\0';
+
+        /* done */
+        return MM_STATUS_SUCCESS;
+    }
+    else if (Flags == MIXER_GETLINEINFOF_TARGETTYPE)
+    {
+        DPRINT1("MIXER_GETLINEINFOF_TARGETTYPE handling is unimplemented\n");
+    }
+    else
+    {
+        DPRINT1("Unknown Flags %lx handling is unimplemented\n", Flags);
+    }
+
+    return MM_STATUS_NOT_IMPLEMENTED;
+}
+
+MIXER_STATUS
+MMixerGetLineControls(
+    IN PMIXER_CONTEXT MixerContext,
+    IN HANDLE MixerHandle,
+    IN ULONG MixerId,
+    IN ULONG Flags,
+    OUT LPMIXERLINECONTROLSW MixerLineControls)
+{
+    LPMIXER_INFO MixerInfo;
+    LPMIXERLINE_EXT MixerLineSrc;
+    LPMIXERCONTROL_EXT MixerControl;
+    MIXER_STATUS Status;
+    PLIST_ENTRY Entry;
+    ULONG Index;
+
+    /* verify mixer context */
+    Status = MMixerVerifyContext(MixerContext);
+
+    if (Status != MM_STATUS_SUCCESS)
+    {
+        /* invalid context passed */
+        return Status;
+    }
+
+    if (MixerLineControls->cbStruct != sizeof(MIXERLINECONTROLSW))
+    {
+        DPRINT1("Invalid MixerLineControls cbStruct passed %lu expected %lu\n", MixerLineControls->cbStruct, sizeof(MIXERLINECONTROLSW));
+        /* invalid parameter */
+        return MM_STATUS_INVALID_PARAMETER;
+    }
+
+    if (MixerLineControls->cbmxctrl != sizeof(MIXERCONTROLW))
+    {
+        DPRINT1("Invalid MixerLineControls cbmxctrl passed %lu expected %lu\n", MixerLineControls->cbmxctrl, sizeof(MIXERCONTROLW));
+        /* invalid parameter */
+        return MM_STATUS_INVALID_PARAMETER;
+    }
+
+    if ((Flags & (MIXER_OBJECTF_MIXER | MIXER_OBJECTF_HMIXER)) == MIXER_OBJECTF_MIXER)
+    {
+        /* caller passed mixer id */
+        MixerHandle = (HANDLE)MMixerGetMixerInfoByIndex(MixerContext, MixerId);
+
+        if (!MixerHandle)
+        {
+            /* invalid parameter */
+            return MM_STATUS_INVALID_PARAMETER;
+        }
+    }
+
+    Flags &= ~MIXER_OBJECTF_HMIXER;
+
+    DPRINT("MMixerGetLineControls MixerId %lu Flags %lu\n", MixerId, Flags);
+
+    if (Flags == MIXER_GETLINECONTROLSF_ALL)
+    {
+        /* cast to mixer info */
+        MixerInfo = (LPMIXER_INFO)MixerHandle;
+
+        /* get mixer line */
+        MixerLineSrc = MMixerGetSourceMixerLineByLineId(MixerInfo, MixerLineControls->dwLineID);
+
+        if (!MixerLineSrc)
+        {
+            /* invalid line id */
+            DPRINT("MMixerGetLineControls Line not found %lx\n", MixerLineControls->dwLineID);
+            return MM_STATUS_INVALID_PARAMETER;
+        }
+
+        if (MixerLineSrc->Line.cControls != MixerLineControls->cControls)
+        {
+            /* invalid parameter */
+            DPRINT1("Invalid control count %lu expected %lu\n", MixerLineControls->cControls, MixerLineSrc->Line.cControls);
+            return MM_STATUS_INVALID_PARAMETER;
+        }
+
+        /* copy line control(s) */
+        Entry = MixerLineSrc->ControlsList.Flink;
+        Index = 0;
+        while(Entry != &MixerLineSrc->ControlsList)
+        {
+            /* get mixer control */
+            MixerControl = (LPMIXERCONTROL_EXT)CONTAINING_RECORD(Entry, MIXERCONTROL_EXT, Entry);
+
+            /* copy mixer control */
+            MixerContext->Copy(&MixerLineControls->pamxctrl[Index], &MixerControl->Control, sizeof(MIXERCONTROLW));
+
+            /* move to next */
+            Entry = Entry->Flink;
+
+            /* increment mixer control offset */
+            Index++;
+        }
+        return MM_STATUS_SUCCESS;
+    }
+    else if (Flags == MIXER_GETLINECONTROLSF_ONEBYTYPE)
+    {
+        /* cast to mixer info */
+        MixerInfo = (LPMIXER_INFO)MixerHandle;
+
+        /* get mixer line */
+        MixerLineSrc = MMixerGetSourceMixerLineByLineId(MixerInfo, MixerLineControls->dwLineID);
+
+        if (!MixerLineSrc)
+        {
+            /* invalid line id */
+            DPRINT1("MMixerGetLineControls Line not found %lx\n", MixerLineControls->dwLineID);
+            return MM_STATUS_INVALID_PARAMETER;
+        }
+
+        /* sanity checks */
+        ASSERT(MixerLineControls->cControls == 1);
+        ASSERT(MixerLineControls->cbmxctrl == sizeof(MIXERCONTROLW));
+        ASSERT(MixerLineControls->pamxctrl != NULL);
+
+        Entry = MixerLineSrc->ControlsList.Flink;
+        while(Entry != &MixerLineSrc->ControlsList)
+        {
+            MixerControl = (LPMIXERCONTROL_EXT)CONTAINING_RECORD(Entry, MIXERCONTROL_EXT, Entry);
+            if (MixerLineControls->dwControlType == MixerControl->Control.dwControlType)
+            {
+                /* found a control with that type */
+                MixerContext->Copy(MixerLineControls->pamxctrl, &MixerControl->Control, sizeof(MIXERCONTROLW));
+                return MM_STATUS_SUCCESS;
+            }
+
+            /* move to next entry */
+            Entry = Entry->Flink;
+         }
+
+         DPRINT("DeviceInfo->u.MixControls.dwControlType %x not found in Line %x cControls %u \n", MixerLineControls->dwControlType, MixerLineControls->dwLineID, MixerLineSrc->Line.cControls);
+         return MM_STATUS_UNSUCCESSFUL;
+    }
+    else if (Flags == MIXER_GETLINECONTROLSF_ONEBYID)
+    {
+        /* cast to mixer info */
+        MixerInfo = (LPMIXER_INFO)MixerHandle;
+
+        Status = MMixerGetMixerControlById(MixerInfo, MixerLineControls->dwControlID, NULL, &MixerControl, NULL);
+
+        if (Status != MM_STATUS_SUCCESS)
+        {
+            /* invalid parameter */
+            DPRINT("MMixerGetLineControls ControlID not found %lx\n", MixerLineControls->dwLineID);
+            return MM_STATUS_INVALID_PARAMETER;
+        }
+
+        ASSERT(MixerLineControls->cControls == 1);
+        ASSERT(MixerLineControls->cbmxctrl == sizeof(MIXERCONTROLW));
+        ASSERT(MixerLineControls->pamxctrl != NULL);
+
+       DPRINT("MMixerGetLineControls ControlID %lx ControlType %lx Name %S\n", MixerControl->Control.dwControlID, MixerControl->Control.dwControlType, MixerControl->Control.szName);
+
+        /* copy the controls */
+        MixerContext->Copy(MixerLineControls->pamxctrl, &MixerControl->Control, sizeof(MIXERCONTROLW));
+        MixerLineControls->pamxctrl->szName[MIXER_LONG_NAME_CHARS-1] = L'\0';
+        MixerLineControls->pamxctrl->szShortName[MIXER_SHORT_NAME_CHARS-1] = L'\0';
+
+        return MM_STATUS_SUCCESS;
+    }
+    UNIMPLEMENTED;
+    return MM_STATUS_NOT_IMPLEMENTED;
+}
+
+MIXER_STATUS
+MMixerSetControlDetails(
+    IN PMIXER_CONTEXT MixerContext,
+    IN HANDLE MixerHandle,
+    IN ULONG MixerId,
+    IN ULONG Flags,
+    OUT LPMIXERCONTROLDETAILS MixerControlDetails)
+{
+    MIXER_STATUS Status;
+    ULONG NodeId;
+    LPMIXER_INFO MixerInfo;
+    LPMIXERLINE_EXT MixerLine;
+    LPMIXERCONTROL_EXT MixerControl;
+
+    /* verify mixer context */
+    Status = MMixerVerifyContext(MixerContext);
+
+    if (Status != MM_STATUS_SUCCESS)
+    {
+        /* invalid context passed */
+        DPRINT1("invalid context\n");
+        return Status;
+    }
+
+    if ((Flags & (MIXER_OBJECTF_MIXER | MIXER_OBJECTF_HMIXER)) == MIXER_OBJECTF_MIXER)
+    {
+        /* caller passed mixer id */
+        MixerHandle = (HANDLE)MMixerGetMixerInfoByIndex(MixerContext, MixerId);
+
+        if (!MixerHandle)
+        {
+            /* invalid parameter */
+            DPRINT1("invalid handle\n");
+            return MM_STATUS_INVALID_PARAMETER;
+        }
+    }
+
+    /* get mixer info */
+    MixerInfo = (LPMIXER_INFO)MixerHandle;
+
+    /* get mixer control */
+     Status = MMixerGetMixerControlById(MixerInfo, MixerControlDetails->dwControlID, &MixerLine, &MixerControl, &NodeId);
+
+    /* check for success */
+    if (Status != MM_STATUS_SUCCESS)
+    {
+        /* failed to find control id */
+        DPRINT1("invalid control id %lu\n", MixerControlDetails->dwControlID);
+        return MM_STATUS_INVALID_PARAMETER;
+    }
+
+    DPRINT("MMixerSetControlDetails ControlType %lx MixerControlName %S MixerLineName %S NodeID %lu\n", MixerControl->Control.dwControlType, MixerControl->Control.szName, MixerLine->Line.szName, NodeId);
+    switch(MixerControl->Control.dwControlType)
+    {
+        case MIXERCONTROL_CONTROLTYPE_MUTE:
+            Status = MMixerSetGetMuteControlDetails(MixerContext, MixerInfo, MixerControl, MixerLine->Line.dwLineID, MixerControlDetails, TRUE);
+            break;
+        case MIXERCONTROL_CONTROLTYPE_VOLUME:
+            Status = MMixerSetGetVolumeControlDetails(MixerContext, MixerInfo, NodeId, TRUE, MixerControl, MixerControlDetails, MixerLine);
+            break;
+        case MIXERCONTROL_CONTROLTYPE_MUX:
+            Status = MMixerSetGetMuxControlDetails(MixerContext, MixerInfo, NodeId, TRUE, Flags, MixerControl, MixerControlDetails, MixerLine);
+            break;
+        default:
+            Status = MM_STATUS_NOT_IMPLEMENTED;
+    }
+
+    return Status;
+}
+
+MIXER_STATUS
+MMixerGetControlDetails(
+    IN PMIXER_CONTEXT MixerContext,
+    IN HANDLE MixerHandle,
+    IN ULONG MixerId,
+    IN ULONG Flags,
+    OUT LPMIXERCONTROLDETAILS MixerControlDetails)
+{
+    MIXER_STATUS Status;
+    ULONG NodeId;
+    LPMIXER_INFO MixerInfo;
+    LPMIXERLINE_EXT MixerLine;
+    LPMIXERCONTROL_EXT MixerControl;
+
+    /* verify mixer context */
+    Status = MMixerVerifyContext(MixerContext);
+
+    if (Status != MM_STATUS_SUCCESS)
+    {
+        /* invalid context passed */
+        return Status;
+    }
+
+    if ((Flags & (MIXER_OBJECTF_MIXER | MIXER_OBJECTF_HMIXER)) == MIXER_OBJECTF_MIXER)
+    {
+        /* caller passed mixer id */
+        MixerHandle = (HANDLE)MMixerGetMixerInfoByIndex(MixerContext, MixerId);
+
+        if (!MixerHandle)
+        {
+            /* invalid parameter */
+            return MM_STATUS_INVALID_PARAMETER;
+        }
+    }
+
+    /* get mixer info */
+    MixerInfo = (LPMIXER_INFO)MixerHandle;
+
+    /* get mixer control */
+     Status = MMixerGetMixerControlById(MixerInfo, MixerControlDetails->dwControlID, &MixerLine, &MixerControl, &NodeId);
+
+    /* check for success */
+    if (Status != MM_STATUS_SUCCESS)
+    {
+        /* failed to find control id */
+        return MM_STATUS_INVALID_PARAMETER;
+    }
+
+    switch(MixerControl->Control.dwControlType)
+    {
+        case MIXERCONTROL_CONTROLTYPE_MUTE:
+            Status = MMixerSetGetMuteControlDetails(MixerContext, MixerInfo, MixerControl, MixerLine->Line.dwLineID, MixerControlDetails, FALSE);
+            break;
+        case MIXERCONTROL_CONTROLTYPE_VOLUME:
+            Status = MMixerSetGetVolumeControlDetails(MixerContext, MixerInfo, NodeId, FALSE, MixerControl, MixerControlDetails, MixerLine);
+            break;
+        case MIXERCONTROL_CONTROLTYPE_ONOFF:
+            DPRINT1("Not Implemented MIXERCONTROL_CONTROLTYPE_ONOFF\n");
+            break;
+        case MIXERCONTROL_CONTROLTYPE_MUX:
+            Status = MMixerSetGetMuxControlDetails(MixerContext, MixerInfo, NodeId, FALSE, Flags, MixerControl, MixerControlDetails, MixerLine);
+            break;
+
+        default:
+            Status = MM_STATUS_NOT_IMPLEMENTED;
+            DPRINT1("ControlType %lx not implemented\n", MixerControl->Control.dwControlType);
+    }
+
+    return Status;
+}
+
+VOID
+MMixerPrintMixerLineControls(
+    IN LPMIXERLINE_EXT MixerLine)
+{
+    PLIST_ENTRY Entry;
+    LPMIXERCONTROL_EXT MixerControl;
+    ULONG Index = 0;
+
+    Entry = MixerLine->ControlsList.Flink;
+    while(Entry != &MixerLine->ControlsList)
+    {
+        MixerControl = (LPMIXERCONTROL_EXT)CONTAINING_RECORD(Entry, MIXERCONTROL_EXT, Entry);
+
+        DPRINT1("\n");
+        DPRINT1("Control Index: %lu\n", Index);
+        DPRINT("\n");
+        DPRINT1("cbStruct %u\n", MixerControl->Control.cbStruct);
+        DPRINT1("dwControlID %lu\n", MixerControl->Control.dwControlID);
+        DPRINT1("dwControlType %lx\n", MixerControl->Control.dwControlType);
+        DPRINT1("fdwControl %lu\n", MixerControl->Control.fdwControl);
+        DPRINT1("cMultipleItems %lu\n", MixerControl->Control.cMultipleItems);
+        DPRINT1("szShortName %S\n", MixerControl->Control.szShortName);
+        DPRINT1("szName %S\n", MixerControl->Control.szName);
+        DPRINT1("Bounds.dwMinimum %lu\n", MixerControl->Control.Bounds.dwMinimum);
+        DPRINT1("Bounds.dwMaximum %lu\n", MixerControl->Control.Bounds.dwMaximum);
+
+        DPRINT1("Metrics.Reserved[0] %lu\n", MixerControl->Control.Metrics.dwReserved[0]);
+        DPRINT1("Metrics.Reserved[1] %lu\n", MixerControl->Control.Metrics.dwReserved[1]);
+        DPRINT1("Metrics.Reserved[2] %lu\n", MixerControl->Control.Metrics.dwReserved[2]);
+        DPRINT1("Metrics.Reserved[3] %lu\n", MixerControl->Control.Metrics.dwReserved[3]);
+        DPRINT1("Metrics.Reserved[4] %lu\n", MixerControl->Control.Metrics.dwReserved[4]);
+        DPRINT1("Metrics.Reserved[5] %lu\n", MixerControl->Control.Metrics.dwReserved[5]);
+
+        Entry = Entry->Flink;
+        Index++;
+    }
+}
+
+VOID
+MMixerPrintMixers(
+    IN PMIXER_CONTEXT MixerContext,
+    IN PMIXER_LIST MixerList)
+{
+    ULONG Index, SubIndex, DestinationLineID, SrcIndex;
+    LPMIXER_INFO MixerInfo;
+    LPMIXERLINE_EXT DstMixerLine, SrcMixerLine;
+
+    DPRINT1("MixerList %p\n", MixerList);
+    DPRINT1("MidiInCount %lu\n", MixerList->MidiInListCount);
+    DPRINT1("MidiOutCount %lu\n", MixerList->MidiOutListCount);
+    DPRINT1("WaveInCount %lu\n", MixerList->WaveInListCount);
+    DPRINT1("WaveOutCount %lu\n", MixerList->WaveOutListCount);
+    DPRINT1("MixerCount %p\n", MixerList->MixerListCount);
+
+
+    for(Index = 0; Index < MixerList->MixerListCount; Index++)
+    {
+        /* get mixer info */
+        MixerInfo = MMixerGetMixerInfoByIndex(MixerContext, Index);
+
+        ASSERT(MixerInfo);
+        DPRINT1("\n");
+        DPRINT1("Name :%S\n", MixerInfo->MixCaps.szPname);
+        DPRINT1("cDestinations: %lu\n", MixerInfo->MixCaps.cDestinations);
+        DPRINT1("fdwSupport %lu\n", MixerInfo->MixCaps.fdwSupport);
+        DPRINT1("vDriverVersion %lx\n", MixerInfo->MixCaps.vDriverVersion);
+        DPRINT1("wMid %lx\n", MixerInfo->MixCaps.wMid);
+        DPRINT1("wPid %lx\n", MixerInfo->MixCaps.wPid);
+
+        for(SubIndex = 0; SubIndex < MixerInfo->MixCaps.cDestinations; SubIndex++)
+        {
+            /* calculate destination line id */
+            DestinationLineID = (SubIndex + DESTINATION_LINE);
+
+            /* get destination line */
+            DstMixerLine = MMixerGetSourceMixerLineByLineId(MixerInfo, DestinationLineID);
+            DPRINT1("//----------------------------------------------------------------------------------------------\n");
+            DPRINT1("\n");
+            DPRINT1("Destination Index %lu\n", SubIndex);
+            DPRINT1("\n");
+            DPRINT1("cChannels %lu\n", DstMixerLine->Line.cChannels);
+            DPRINT1("cConnections %lu\n", DstMixerLine->Line.cConnections);
+            DPRINT1("cControls %lu\n", DstMixerLine->Line.cControls);
+            DPRINT1("dwComponentType %lx\n", DstMixerLine->Line.dwComponentType);
+            DPRINT1("dwDestination %lu\n", DstMixerLine->Line.dwDestination);
+            DPRINT1("dwLineID %lx\n", DstMixerLine->Line.dwLineID);
+            DPRINT1("dwSource %lx\n", DstMixerLine->Line.dwSource);
+            DPRINT1("dwUser %lu\n", DstMixerLine->Line.dwUser);
+            DPRINT1("fdwLine %lu\n", DstMixerLine->Line.fdwLine);
+            DPRINT1("szName %S\n", DstMixerLine->Line.szName);
+            DPRINT1("szShortName %S\n", DstMixerLine->Line.szShortName);
+            DPRINT1("Target.dwDeviceId %lu\n", DstMixerLine->Line.Target.dwDeviceID);
+            DPRINT1("Target.dwType %lu\n", DstMixerLine->Line.Target.dwType);
+            DPRINT1("Target.szName %S\n", DstMixerLine->Line.Target.szPname);
+            DPRINT1("Target.vDriverVersion %lx\n", DstMixerLine->Line.Target.vDriverVersion);
+            DPRINT1("Target.wMid %lx\n", DstMixerLine->Line.Target.wMid );
+            DPRINT1("Target.wPid %lx\n", DstMixerLine->Line.Target.wPid);
+            MMixerPrintMixerLineControls(DstMixerLine);
+
+            for(SrcIndex = 0; SrcIndex < DstMixerLine->Line.cConnections; SrcIndex++)
+            {
+                /* calculate destination line id */
+                DestinationLineID = (SOURCE_LINE * SrcIndex) + SubIndex;
+
+                /* get source line */
+                SrcMixerLine = MMixerGetSourceMixerLineByLineId(MixerInfo, DestinationLineID);
+                DPRINT1("//==============================================================================================\n");
+                DPRINT1("\n");
+                DPRINT1("SrcLineIndex : %lu\n", SrcIndex);
+                DPRINT1("\n");
+                DPRINT1("cChannels %lu\n", SrcMixerLine->Line.cChannels);
+                DPRINT1("cConnections %lu\n", SrcMixerLine->Line.cConnections);
+                DPRINT1("cControls %lu\n", SrcMixerLine->Line.cControls);
+                DPRINT1("dwComponentType %lx\n", SrcMixerLine->Line.dwComponentType);
+                DPRINT1("dwDestination %lu\n", SrcMixerLine->Line.dwDestination);
+                DPRINT1("dwLineID %lx\n", SrcMixerLine->Line.dwLineID);
+                DPRINT1("dwSource %lx\n", SrcMixerLine->Line.dwSource);
+                DPRINT1("dwUser %lu\n", SrcMixerLine->Line.dwUser);
+                DPRINT1("fdwLine %lu\n", SrcMixerLine->Line.fdwLine);
+                DPRINT1("szName %S\n", SrcMixerLine->Line.szName);
+                DPRINT1("szShortName %S\n", SrcMixerLine->Line.szShortName);
+                DPRINT1("Target.dwDeviceId %lu\n", SrcMixerLine->Line.Target.dwDeviceID);
+                DPRINT1("Target.dwType %lu\n", SrcMixerLine->Line.Target.dwType);
+                DPRINT1("Target.szName %S\n", SrcMixerLine->Line.Target.szPname);
+                DPRINT1("Target.vDriverVersion %lx\n", SrcMixerLine->Line.Target.vDriverVersion);
+                DPRINT1("Target.wMid %lx\n", SrcMixerLine->Line.Target.wMid );
+                DPRINT1("Target.wPid %lx\n", SrcMixerLine->Line.Target.wPid);
+                MMixerPrintMixerLineControls(SrcMixerLine);
+            }
+        }
+    }
+}
+
+MIXER_STATUS
+MMixerInitialize(
+    IN PMIXER_CONTEXT MixerContext,
+    IN PMIXER_ENUM EnumFunction,
+    IN PVOID EnumContext)
+{
+    MIXER_STATUS Status;
+    HANDLE hMixer, hKey;
+    ULONG DeviceIndex, Count;
+    LPWSTR DeviceName;
+    LPMIXER_DATA MixerData;
+    PMIXER_LIST MixerList;
+    PLIST_ENTRY Entry;
+
+    if (!MixerContext || !EnumFunction || !EnumContext)
+    {
+        /* invalid parameter */
+        return MM_STATUS_INVALID_PARAMETER;
+    }
+
+    if (!MixerContext->Alloc || !MixerContext->Control || !MixerContext->Free || !MixerContext->Open ||
+        !MixerContext->AllocEventData || !MixerContext->FreeEventData ||
+        !MixerContext->Close || !MixerContext->OpenKey || !MixerContext->QueryKeyValue || !MixerContext->CloseKey)
+    {
+        /* invalid parameter */
+        return MM_STATUS_INVALID_PARAMETER;
+    }
+
+    /* allocate a mixer list */
+    MixerList = (PMIXER_LIST)MixerContext->Alloc(sizeof(MIXER_LIST));
+    if (!MixerList)
+    {
+        /* no memory */
+        return MM_STATUS_NO_MEMORY;
+    }
+
+     /* initialize mixer list */
+     MixerList->MixerListCount = 0;
+     MixerList->MixerDataCount = 0;
+     MixerList->WaveInListCount = 0;
+     MixerList->WaveOutListCount = 0;
+     MixerList->MidiInListCount = 0;
+     MixerList->MidiOutListCount = 0;
+     InitializeListHead(&MixerList->MixerList);
+     InitializeListHead(&MixerList->MixerData);
+     InitializeListHead(&MixerList->WaveInList);
+     InitializeListHead(&MixerList->WaveOutList);
+     InitializeListHead(&MixerList->MidiInList);
+     InitializeListHead(&MixerList->MidiOutList);
+
+     /* store mixer list */
+     MixerContext->MixerContext = (PVOID)MixerList;
+
+    /* start enumerating all available devices */
+    Count = 0;
+    DeviceIndex = 0;
+
+    do
+    {
+        /* enumerate a device */
+        Status = EnumFunction(EnumContext, DeviceIndex, &DeviceName, &hMixer, &hKey);
+
+        if (Status != MM_STATUS_SUCCESS)
+        {
+            /* check error code */
+            if (Status == MM_STATUS_NO_MORE_DEVICES)
+            {
+                /* enumeration has finished */
+                break;
+            }
+            else
+            {
+                DPRINT1("Failed to enumerate device %lu\n", DeviceIndex);
+
+                /* TODO cleanup */
+                return Status;
+            }
+        }
+        else
+        {
+            /* create a mixer data entry */
+            Status = MMixerCreateMixerData(MixerContext, MixerList, DeviceIndex, DeviceName, hMixer, hKey);
+            if (Status != MM_STATUS_SUCCESS)
+                break;
+        }
+
+        /* increment device index */
+        DeviceIndex++;
+    }while(TRUE);
+
+    /* now all filters have been pre-opened
+     * lets enumerate the filters
+     */
+    Entry = MixerList->MixerData.Flink;
+    while(Entry != &MixerList->MixerData)
+    {
+        MixerData = (LPMIXER_DATA)CONTAINING_RECORD(Entry, MIXER_DATA, Entry);
+        MMixerSetupFilter(MixerContext, MixerList, MixerData, &Count);
+        Entry = Entry->Flink;
+    }
+
+    Entry = MixerList->MixerData.Flink;
+    while(Entry != &MixerList->MixerData)
+    {
+        MixerData = (LPMIXER_DATA)CONTAINING_RECORD(Entry, MIXER_DATA, Entry);
+
+        /* now handle alternative mixer types */
+        MMixerHandleAlternativeMixers(MixerContext, MixerList, MixerData, MixerData->Topology);
+        Entry = Entry->Flink;
+    }
+
+    //MMixerPrintMixers(MixerContext, MixerList);
+
+    /* done */
+    return MM_STATUS_SUCCESS;
+}