- Start implementing a mixer library. The mixer library is based directly on the...
authorJohannes Anderwald <johannes.anderwald@reactos.org>
Mon, 7 Dec 2009 10:28:49 +0000 (10:28 +0000)
committerJohannes Anderwald <johannes.anderwald@reactos.org>
Mon, 7 Dec 2009 10:28:49 +0000 (10:28 +0000)
svn path=/trunk/; revision=44452

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

diff --git a/reactos/lib/drivers/sound/mmixer/mixer.c b/reactos/lib/drivers/sound/mmixer/mixer.c
new file mode 100644 (file)
index 0000000..38c23c5
--- /dev/null
@@ -0,0 +1,376 @@
+/*
+ * 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 "priv.h"
+
+MIXER_STATUS
+MMixerVerifyContext(
+    IN PMIXER_CONTEXT MixerContext)
+{
+    if (MixerContext->SizeOfStruct != sizeof(MIXER_CONTEXT))
+        return MM_STATUS_INVALID_PARAMETER;
+
+    if (!MixerContext->Alloc || !MixerContext->Control || !MixerContext->Free)
+        return MM_STATUS_INVALID_PARAMETER;
+
+    if (!MixerContext->MixerContext)
+        return MM_STATUS_INVALID_PARAMETER;
+
+    return MM_STATUS_SUCCESS;
+}
+
+VOID
+MMixerFreeMixerInfo(
+    IN PMIXER_CONTEXT MixerContext,
+    IN LPMIXER_INFO MixerInfo)
+{
+    //UNIMPLEMENTED
+    // FIXME
+    // free all lines
+
+    MixerContext->Free((PVOID)MixerInfo);
+}
+
+ULONG
+MMixerGetFilterPinCount(
+    IN PMIXER_CONTEXT MixerContext,
+    IN HANDLE hMixer)
+{
+    KSPROPERTY Pin;
+    MIXER_STATUS Status;
+    ULONG NumPins, BytesReturned;
+
+    // setup property request
+    Pin.Flags = KSPROPERTY_TYPE_GET;
+    Pin.Set = KSPROPSETID_Pin;
+    Pin.Id = KSPROPERTY_PIN_CTYPES;
+
+    // query pin count
+    Status = MixerContext->Control(hMixer, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSPROPERTY), (PVOID)&NumPins, sizeof(ULONG), (PULONG)&BytesReturned);
+
+    // check for success
+    if (Status != MM_STATUS_SUCCESS)
+        return 0;
+
+    return NumPins;
+}
+
+ULONG
+MMixerGetIndexOfGuid(
+    PKSMULTIPLE_ITEM MultipleItem,
+    LPCGUID NodeType)
+{
+    ULONG Index;
+    LPGUID Guid;
+
+    Guid = (LPGUID)(MultipleItem+1);
+
+    /* iterate through node type array */
+    for(Index = 0; Index < MultipleItem->Count; Index++)
+    {
+        if (IsEqualGUIDAligned(NodeType, Guid))
+        {
+            /* found matching guid */
+            return Index;
+        }
+        Guid++;
+    }
+    return MAXULONG;
+}
+
+
+MIXER_STATUS
+MMixerGetFilterTopologyProperty(
+    IN PMIXER_CONTEXT MixerContext,
+    IN HANDLE hMixer,
+    IN ULONG PropertyId,
+    OUT PKSMULTIPLE_ITEM * OutMultipleItem)
+{
+    KSPROPERTY Property;
+    PKSMULTIPLE_ITEM MultipleItem;
+    MIXER_STATUS Status;
+    ULONG BytesReturned;
+
+    // setup property request
+    Property.Id = PropertyId;
+    Property.Flags = KSPROPERTY_TYPE_GET;
+    Property.Set = KSPROPSETID_Topology;
+
+    // query for the size
+    Status = MixerContext->Control(hMixer, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), NULL, 0, &BytesReturned);
+
+    if (Status != MM_STATUS_MORE_ENTRIES)
+        return Status;
+
+    // allocate an result buffer
+    MultipleItem = (PKSMULTIPLE_ITEM)MixerContext->Alloc(BytesReturned);
+
+    if (!MultipleItem)
+    {
+        // not enough memory
+        return MM_STATUS_NO_MEMORY;
+    }
+
+    // query again with allocated buffer
+    Status = MixerContext->Control(hMixer, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)MultipleItem, BytesReturned, &BytesReturned);
+
+    if (Status != MM_STATUS_SUCCESS)
+    {
+        // failed
+        MixerContext->Free((PVOID)MultipleItem);
+        return Status;
+    }
+
+    // store result
+    *OutMultipleItem = MultipleItem;
+
+    // done
+    return Status;
+}
+
+MIXER_STATUS
+MMixerCreateDestinationLine(
+    IN PMIXER_CONTEXT MixerContext,
+    IN LPMIXER_INFO MixerInfo,
+    IN ULONG bInputMixer)
+{
+    LPMIXERLINE_EXT DestinationLine;
+
+    // allocate a mixer destination line
+    DestinationLine = (LPMIXERLINE_EXT) MixerContext->Alloc(sizeof(MIXERLINE_EXT));
+    if (!MixerInfo)
+    {
+        // no memory
+        return MM_STATUS_NO_MEMORY;
+    }
+
+    /* initialize mixer destination line */
+    DestinationLine->Line.cbStruct = sizeof(MIXERLINEW);
+    DestinationLine->Line.dwSource = MAXULONG;
+    DestinationLine->Line.dwLineID = DESTINATION_LINE;
+    DestinationLine->Line.fdwLine = MIXERLINE_LINEF_ACTIVE;
+    DestinationLine->Line.dwUser = 0;
+    DestinationLine->Line.dwComponentType = (bInputMixer == 0 ? MIXERLINE_COMPONENTTYPE_DST_SPEAKERS : MIXERLINE_COMPONENTTYPE_DST_WAVEIN);
+    DestinationLine->Line.cChannels = 2; //FIXME
+    wcscpy(DestinationLine->Line.szShortName, L"Summe"); //FIXME
+    wcscpy(DestinationLine->Line.szName, L"Summe"); //FIXME
+    DestinationLine->Line.Target.dwType = (bInputMixer == 0 ? MIXERLINE_TARGETTYPE_WAVEOUT : MIXERLINE_TARGETTYPE_WAVEIN);
+    DestinationLine->Line.Target.dwDeviceID = !bInputMixer;
+    DestinationLine->Line.Target.wMid = MixerInfo->MixCaps.wMid;
+    DestinationLine->Line.Target.wPid = MixerInfo->MixCaps.wPid;
+    DestinationLine->Line.Target.vDriverVersion = MixerInfo->MixCaps.vDriverVersion;
+    wcscpy(DestinationLine->Line.Target.szPname, MixerInfo->MixCaps.szPname);
+
+
+    // insert into mixer info
+    InsertHeadList(&MixerInfo->LineList, &DestinationLine->Entry);
+
+    // done
+    return MM_STATUS_SUCCESS;
+}
+
+MIXER_STATUS
+MMixerInitializeFilter(
+    IN PMIXER_CONTEXT MixerContext,
+    IN HANDLE hMixer,
+    IN LPWSTR DeviceName,
+    IN PKSMULTIPLE_ITEM NodeTypes,
+    IN PKSMULTIPLE_ITEM NodeConnections,
+    IN ULONG PinCount,
+    IN ULONG NodeIndex,
+    IN ULONG bInputMixer)
+{
+    LPMIXER_INFO MixerInfo;
+    MIXER_STATUS Status;
+    ULONG * Pins;
+
+    // allocate a mixer info struct
+    MixerInfo = (LPMIXER_INFO) MixerContext->Alloc(sizeof(MIXER_INFO));
+    if (!MixerInfo)
+    {
+        // no memory
+        return MM_STATUS_NO_MEMORY;
+    }
+
+    // intialize mixer caps */
+    MixerInfo->MixCaps.wMid = MM_MICROSOFT; //FIXME
+    MixerInfo->MixCaps.wPid = MM_PID_UNMAPPED; //FIXME
+    MixerInfo->MixCaps.vDriverVersion = 1; //FIXME
+    MixerInfo->MixCaps.fdwSupport = 0;
+    MixerInfo->MixCaps.cDestinations = 1;
+    MixerInfo->hMixer = hMixer;
+
+    // initialize line list
+    InitializeListHead(&MixerInfo->LineList);
+
+    /* FIXME find mixer name */
+
+    Status = MMixerCreateDestinationLine(MixerContext, MixerInfo, bInputMixer);
+    if (Status != MM_STATUS_SUCCESS)
+    {
+        // failed to create destination line
+        MixerContext->Free(MixerInfo);
+        return Status;
+    }
+
+
+    // 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));
+
+    if (!Pins)
+    {
+        // no memory
+        MMixerFreeMixerInfo(MixerContext, MixerInfo);
+        return MM_STATUS_NO_MEMORY;
+    }
+
+
+    //UNIMPLEMENTED
+    // get target pins and find all nodes
+    return MM_STATUS_NOT_IMPLEMENTED;
+}
+
+MIXER_STATUS
+MMixerSetupFilter(
+    IN PMIXER_CONTEXT MixerContext, 
+    IN HANDLE hMixer,
+    IN PULONG DeviceCount,
+    IN LPWSTR DeviceName)
+{
+    PKSMULTIPLE_ITEM NodeTypes, NodeConnections;
+    MIXER_STATUS Status;
+    ULONG PinCount;
+    ULONG NodeIndex;
+
+    // get number of pins
+    PinCount = MMixerGetFilterPinCount(MixerContext, hMixer);
+    ASSERT(PinCount);
+
+
+    // get filter node types
+    Status = MMixerGetFilterTopologyProperty(MixerContext, hMixer, KSPROPERTY_TOPOLOGY_NODES, &NodeTypes);
+    if (Status != MM_STATUS_SUCCESS)
+    {
+        // failed
+        return Status;
+    }
+
+    // get filter node connections
+    Status = MMixerGetFilterTopologyProperty(MixerContext, hMixer, KSPROPERTY_TOPOLOGY_CONNECTIONS, &NodeConnections);
+    if (Status != MM_STATUS_SUCCESS)
+    {
+        // failed
+        MixerContext->Free(NodeTypes);
+        return Status;
+    }
+
+    // check if the filter has an wave out node
+    NodeIndex = MMixerGetIndexOfGuid(NodeTypes, &KSNODETYPE_DAC);
+    if (NodeIndex != MAXULONG)
+    {
+        // it has
+        Status = MMixerInitializeFilter(MixerContext, hMixer, DeviceName, NodeTypes, NodeConnections, PinCount, NodeIndex, FALSE);
+
+        // check for success
+        if (Status == MM_STATUS_SUCCESS)
+        {
+            // increment mixer count
+            (*DeviceCount)++;
+        }
+
+    }
+
+    // check if the filter has an wave in node
+    NodeIndex = MMixerGetIndexOfGuid(NodeTypes, &KSNODETYPE_ADC);
+    if (NodeIndex != MAXULONG)
+    {
+        // it has
+        Status = MMixerInitializeFilter(MixerContext, hMixer, DeviceName, NodeTypes, NodeConnections, PinCount, NodeIndex, TRUE);
+
+        // check for success
+        if (Status == MM_STATUS_SUCCESS)
+        {
+            // increment mixer count
+            (*DeviceCount)++;
+        }
+
+    }
+
+    //free resources
+    MixerContext->Free((PVOID)NodeTypes);
+    MixerContext->Free((PVOID)NodeConnections);
+
+    // done
+    return Status;
+}
+
+
+MIXER_STATUS
+MMixerInitialize(
+    IN PMIXER_CONTEXT MixerContext, 
+    IN PMIXER_ENUM EnumFunction,
+    IN PVOID EnumContext)
+{
+    MIXER_STATUS Status;
+    HANDLE hMixer;
+    ULONG DeviceIndex, Count;
+    LPWSTR DeviceName;
+
+    if (!MixerContext || !EnumFunction || !EnumContext)
+    {
+        // invalid parameter
+        return MM_STATUS_INVALID_PARAMETER;
+    }
+
+    if (!MixerContext->Alloc || !MixerContext->Control || !MixerContext->Free)
+    {
+        // invalid parameter
+        return MM_STATUS_INVALID_PARAMETER;
+    }
+
+
+    // start enumerating all available devices
+    Count = 0;
+    DeviceIndex = 0;
+
+    do
+    {
+        // enumerate a device
+        Status = EnumFunction(EnumContext, DeviceIndex, &DeviceName, &hMixer);
+
+        if (Status != MM_STATUS_SUCCESS)
+        {
+            //check error code
+            if (Status != MM_STATUS_NO_MORE_DEVICES)
+            {
+                // enumeration has failed
+                return Status;
+            }
+            // last device
+            break;
+        }
+
+
+        // increment device index
+        DeviceIndex++;
+
+        Status = MMixerSetupFilter(MixerContext, hMixer, &Count, DeviceName);
+
+        if (Status != MM_STATUS_SUCCESS)
+            break;
+
+    }while(TRUE);
+
+    // done
+    return Status;
+}
+
+
diff --git a/reactos/lib/drivers/sound/mmixer/mmixer.h b/reactos/lib/drivers/sound/mmixer/mmixer.h
new file mode 100644 (file)
index 0000000..6557b67
--- /dev/null
@@ -0,0 +1,108 @@
+#ifndef MIXER_H__
+#define MIXER_H__
+
+typedef enum
+{
+    MM_STATUS_SUCCESS = 0,
+    MM_STATUS_NOTINITIALIZED,
+    MM_STATUS_NOT_IMPLEMENTED,
+    MM_STATUS_NO_MORE_DEVICES,
+    MM_STATUS_MORE_ENTRIES,
+    MM_STATUS_INVALID_PARAMETER,
+    MM_STATUS_UNSUCCESSFUL,
+    MM_STATUS_NO_MEMORY
+
+
+}MIXER_STATUS;
+
+
+typedef PVOID (*PMIXER_ALLOC)(
+    IN ULONG NumberOfBytes);
+
+typedef VOID (*PMIXER_FREE)(
+    IN PVOID Block);
+
+typedef MIXER_STATUS (*PMIXER_ENUM)(
+    IN  PVOID EnumContext,
+    IN  ULONG DeviceIndex,
+    OUT LPWSTR * DeviceName,
+    OUT PHANDLE OutHandle);
+
+typedef MIXER_STATUS(*PMIXER_DEVICE_CONTROL)(
+    IN HANDLE hMixer,
+    IN ULONG dwIoControlCode,
+    IN PVOID lpInBuffer,
+    IN ULONG nInBufferSize,
+    OUT PVOID lpOutBuffer,
+    ULONG nOutBufferSize,
+    PULONG lpBytesReturned);
+
+
+
+typedef VOID (*PMIXER_EVENT)(
+    IN PVOID MixerEvent);
+
+
+typedef struct
+{
+     ULONG SizeOfStruct;
+     PVOID MixerContext;
+
+     PMIXER_ALLOC Alloc;
+     PMIXER_DEVICE_CONTROL Control;
+     PMIXER_FREE  Free;
+}MIXER_CONTEXT, *PMIXER_CONTEXT;
+
+
+
+
+
+MIXER_STATUS
+MMixerInitialize(
+    IN PMIXER_CONTEXT MixerContext, 
+    IN PMIXER_ENUM EnumFunction,
+    IN PVOID EnumContext);
+
+
+ULONG
+MMixerGetCount(
+    IN PMIXER_CONTEXT MixerContext);
+
+MIXER_STATUS
+MMixerGetCapabilities(
+    IN PMIXER_CONTEXT MixerContext,
+    IN ULONG MixerIndex,
+    OUT MIXERCAPSW MixerCaps);
+
+MIXER_STATUS
+MMixerOpen(
+    IN PMIXER_CONTEXT MixerContext,
+    IN PVOID MixerEvent,
+    IN PMIXER_EVENT MixerEventRoutine,
+    OUT PHANDLE MixerHandle);
+
+MIXER_STATUS
+MMixerGetLineInfo(
+    IN  HANDLE MixerHandle,
+    IN  ULONG Flags,
+    OUT LPMIXERLINEW MixerLine);
+
+MIXER_STATUS
+MMixerGetLineControls(
+    IN HANDLE MixerHandle,
+    IN ULONG Flags,
+    OUT LPMIXERLINECONTROLS MixerLineControls);
+
+MIXER_STATUS
+MMixerSetControlDetails(
+    IN HANDLE MixerHandle,
+    IN ULONG Flags,
+    OUT LPMIXERCONTROLDETAILS MixerControlDetails);
+
+MIXER_STATUS
+MMixerGetControlDetails(
+    IN HANDLE MixerHandle,
+    IN ULONG Flags,
+    OUT LPMIXERCONTROLDETAILS MixerControlDetails);
+
+#endif
diff --git a/reactos/lib/drivers/sound/mmixer/mmixer.rbuild b/reactos/lib/drivers/sound/mmixer/mmixer.rbuild
new file mode 100644 (file)
index 0000000..a54d4df
--- /dev/null
@@ -0,0 +1,7 @@
+<?xml version="1.0"?>
+<!DOCTYPE module SYSTEM "../../../../tools/rbuild/project.dtd">
+<module name="mmixer" type="staticlibrary" allowwarnings="false" unicode="yes">
+       <include base="ReactOS">include/reactos/libs/sound</include>
+       <define name="NDEBUG">1</define>
+       <file>mixer.c</file>
+</module>
diff --git a/reactos/lib/drivers/sound/mmixer/priv.h b/reactos/lib/drivers/sound/mmixer/priv.h
new file mode 100644 (file)
index 0000000..416b2f8
--- /dev/null
@@ -0,0 +1,38 @@
+#ifndef PRIV_H__
+#define PRIV_H__
+
+#include <pseh/pseh2.h>
+#include <ntddk.h>
+
+#include <windef.h>
+#define NOBITMAP
+#include <mmreg.h>
+#include <ks.h>
+#include <ksmedia.h>
+#include <mmreg.h>
+#include <mmsystem.h>
+
+#include "mmixer.h"
+
+typedef struct
+{
+    MIXERCAPSW    MixCaps;
+    HANDLE        hMixer;
+    LIST_ENTRY    LineList;
+    ULONG         ControlId;
+}MIXER_INFO, *LPMIXER_INFO;
+
+typedef struct
+{
+    LIST_ENTRY Entry;
+    ULONG PinId;
+    ULONG DeviceIndex;
+    MIXERLINEW Line;
+    LPMIXERCONTROLW LineControls;
+    PULONG          NodeIds;
+    LIST_ENTRY LineControlsExtraData;
+}MIXERLINE_EXT, *LPMIXERLINE_EXT;
+
+#define DESTINATION_LINE 0xFFFF0000
+
+#endif