[AUDIO-BRINGUP]
authorJohannes Anderwald <johannes.anderwald@reactos.org>
Wed, 8 Dec 2010 19:49:28 +0000 (19:49 +0000)
committerJohannes Anderwald <johannes.anderwald@reactos.org>
Wed, 8 Dec 2010 19:49:28 +0000 (19:49 +0000)
- Implement MixerEvent callback in wdmaud.drv
- Comment out assert which is hit in VmWare
- Implement full support mux controls

svn path=/branches/audio-bringup/; revision=49990

dll/win32/wdmaud.drv/mmixer.c
lib/drivers/sound/mmixer/controls.c
lib/drivers/sound/mmixer/mixer.c
lib/drivers/sound/mmixer/mmixer.h
lib/drivers/sound/mmixer/priv.h
lib/drivers/sound/mmixer/sup.c
lib/drivers/sound/mmixer/topology.c

index 1e4043b..0047e8d 100644 (file)
@@ -663,6 +663,25 @@ WdmAudGetDeviceInterfaceStringByMMixer(
     return MMSYSERR_NOTSUPPORTED;
 }
 
+VOID
+CALLBACK
+MixerEventCallback(
+    IN PVOID MixerEventContext,
+    IN HANDLE hMixer,
+    IN ULONG NotificationType,
+    IN ULONG Value)
+{
+    PSOUND_DEVICE_INSTANCE Instance = (PSOUND_DEVICE_INSTANCE)MixerEventContext;
+
+    DriverCallback(Instance->WinMM.ClientCallback,
+                   HIWORD(Instance->WinMM.Flags),
+                   Instance->WinMM.Handle,
+                   NotificationType,
+                   Instance->WinMM.ClientCallbackInstanceData,
+                   (DWORD_PTR)Value,
+                   0);
+}
+
 MMRESULT
 WdmAudSetMixerDeviceFormatByMMixer(
     IN  PSOUND_DEVICE_INSTANCE Instance,
@@ -670,11 +689,7 @@ WdmAudSetMixerDeviceFormatByMMixer(
     IN  PWAVEFORMATEX WaveFormat,
     IN  DWORD WaveFormatSize)
 {
-    Instance->hNotifyEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
-    if ( ! Instance->hNotifyEvent )
-        return MMSYSERR_NOMEM;
-
-    if (MMixerOpen(&MixerContext, DeviceId, Instance->hNotifyEvent, NULL /* FIXME */, &Instance->Handle) == MM_STATUS_SUCCESS)
+    if (MMixerOpen(&MixerContext, DeviceId, (PVOID)Instance, MixerEventCallback, &Instance->Handle) == MM_STATUS_SUCCESS)
         return MMSYSERR_NOERROR;
 
     return MMSYSERR_BADDEVICEID;
index 6d57bd7..a0ba67a 100644 (file)
@@ -1570,7 +1570,7 @@ MMixerHandleAlternativeMixers(
         DPRINT("MixerName %S Available PinID %lu\n", MixerData->DeviceName, Index);
 
         /* sanity check */
-        ASSERT(MixerData->MixerInfo);
+        //ASSERT(MixerData->MixerInfo);
 
         if (!MixerData->MixerInfo)
         {
@@ -1730,7 +1730,7 @@ MMixerAddEvent(
 
     /* initialize notification entry */
     EventData->MixerEventContext = MixerEventContext;
-    EventData->MixerEventRoutine;
+    EventData->MixerEventRoutine = MixerEventRoutine;
 
     /* store event */
     InsertTailList(&MixerInfo->EventList, &EventData->Entry);
index 5a8e666..980a49e 100644 (file)
@@ -108,7 +108,6 @@ MMixerOpen(
 
     /* store result */
     *MixerHandle = (HANDLE)MixerInfo;
-
     return MM_STATUS_SUCCESS;
 }
 
@@ -243,7 +242,7 @@ MMixerGetLineInfo(
         if (!MixerLineSrc)
         {
             /* invalid parameter */
-            DPRINT1("MMixerGetLineInfo: MixerName %S Line not found %lu\n", MixerInfo->MixCaps.szPname, MixerLine->dwLineID);
+            DPRINT1("MMixerGetLineInfo: MixerName %S Line not found 0x%lx\n", MixerInfo->MixCaps.szPname, MixerLine->dwLineID);
             return MM_STATUS_INVALID_PARAMETER;
         }
 
@@ -519,8 +518,10 @@ MMixerSetControlDetails(
         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:
-            ASSERT(0);
             Status = MM_STATUS_NOT_IMPLEMENTED;
     }
 
@@ -583,9 +584,16 @@ MMixerGetControlDetails(
         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 %lu not implemented\n", MixerControl->Control.dwControlType);
+            DPRINT1("ControlType %lx not implemented\n", MixerControl->Control.dwControlType);
     }
 
     return Status;
index 9649706..4b7b146 100644 (file)
@@ -47,7 +47,7 @@ typedef MIXER_STATUS(*PMIXER_CLOSE)(
 typedef MIXER_STATUS(*PMIXER_CLOSEKEY)(
     IN HANDLE hKey);
 
-typedef VOID (*PMIXER_EVENT)(
+typedef VOID (CALLBACK *PMIXER_EVENT)(
     IN PVOID MixerEventContext,
     IN HANDLE hMixer,
     IN ULONG NotificationType,
index f794d71..3746f6d 100644 (file)
@@ -301,6 +301,18 @@ MMixerSetGetVolumeControlDetails(
     IN LPMIXERCONTROLDETAILS MixerControlDetails,
     LPMIXERLINE_EXT MixerLine);
 
+MIXER_STATUS
+MMixerSetGetMuxControlDetails(
+    IN PMIXER_CONTEXT MixerContext,
+    IN LPMIXER_INFO MixerInfo,
+    IN ULONG NodeId,
+    IN ULONG bSet,
+    IN ULONG Flags,
+    LPMIXERCONTROL_EXT MixerControl,
+    IN LPMIXERCONTROLDETAILS MixerControlDetails,
+    LPMIXERLINE_EXT MixerLine);
+
+
 MIXER_STATUS
 MMixerSetGetControlDetails(
     IN PMIXER_CONTEXT MixerContext,
@@ -507,3 +519,9 @@ MMixerGetTopologyPinCount(
     IN PTOPOLOGY Topology,
     OUT PULONG PinCount);
 
+VOID
+MMixerGetConnectedFromLogicalTopologyPins(
+    IN PTOPOLOGY Topology,
+    IN ULONG NodeIndex,
+    OUT PULONG OutPinCount,
+    OUT PULONG OutPins);
index 400dba8..7526ef6 100644 (file)
@@ -54,6 +54,63 @@ MMixerVerifyContext(
     return MM_STATUS_SUCCESS;
 }
 
+LPMIXERLINE_EXT
+MMixerGetMixerLineContainingNodeId(
+    IN LPMIXER_INFO MixerInfo,
+    IN ULONG NodeID)
+{
+    PLIST_ENTRY Entry, ControlEntry;
+    LPMIXERLINE_EXT MixerLineSrc;
+    LPMIXERCONTROL_EXT MixerControl;
+
+    /* get first entry */
+    Entry = MixerInfo->LineList.Flink;
+
+    while(Entry != &MixerInfo->LineList)
+    {
+        MixerLineSrc = (LPMIXERLINE_EXT)CONTAINING_RECORD(Entry, MIXERLINE_EXT, Entry);
+
+        ControlEntry = MixerLineSrc->ControlsList.Flink;
+        while(ControlEntry != &MixerLineSrc->ControlsList)
+        {
+            MixerControl = (LPMIXERCONTROL_EXT)CONTAINING_RECORD(ControlEntry, MIXERCONTROL_EXT, Entry);
+            if (MixerControl->NodeID == NodeID)
+            {
+                return MixerLineSrc;
+            }
+            ControlEntry = ControlEntry->Flink;
+        }
+        Entry = Entry->Flink;
+    }
+
+    return NULL;
+}
+
+VOID
+MMixerGetLowestLogicalTopologyPinOffsetFromArray(
+    IN ULONG LogicalPinArrayCount,
+    IN PULONG LogicalPinArray,
+    OUT PULONG PinOffset)
+{
+    ULONG Index;
+    ULONG LowestId = 0;
+
+    for(Index = 1; Index < LogicalPinArrayCount; Index++)
+    {
+        if (LogicalPinArray[Index] != MAXULONG)
+        {
+            /* sanity check: logical pin id must be unique */
+            ASSERT(LogicalPinArray[Index] != LogicalPinArray[LowestId]);
+        }
+
+        if (LogicalPinArray[Index] < LogicalPinArray[LowestId])
+            LowestId = Index;
+    }
+
+    /* store result */
+    *PinOffset = LowestId;
+}
+
 VOID
 MMixerFreeMixerInfo(
     IN PMIXER_CONTEXT MixerContext,
@@ -67,6 +124,38 @@ MMixerFreeMixerInfo(
     MixerContext->Free((PVOID)MixerInfo);
 }
 
+
+LPMIXER_DATA
+MMixerGetMixerDataByDeviceHandle(
+    IN PMIXER_CONTEXT MixerContext,
+    IN HANDLE hDevice)
+{
+    LPMIXER_DATA MixerData;
+    PLIST_ENTRY Entry;
+    PMIXER_LIST MixerList;
+
+    /* get mixer list */
+    MixerList = (PMIXER_LIST)MixerContext->MixerContext;
+
+    if (!MixerList->MixerDataCount)
+        return NULL;
+
+    Entry = MixerList->MixerData.Flink;
+
+    while(Entry != &MixerList->MixerData)
+    {
+        MixerData = (LPMIXER_DATA)CONTAINING_RECORD(Entry, MIXER_DATA, Entry);
+
+        if (MixerData->hDevice == hDevice)
+            return MixerData;
+
+        /* move to next mixer entry */
+        Entry = Entry->Flink;
+    }
+    return NULL;
+}
+
+
 LPMIXER_INFO
 MMixerGetMixerInfoByIndex(
     IN PMIXER_CONTEXT MixerContext,
@@ -255,7 +344,7 @@ MMixerNotifyControlChange(
     PLIST_ENTRY Entry;
     PEVENT_NOTIFICATION_ENTRY NotificationEntry;
 
-    /* enumerate list and add a notification entry */
+    /* enumerate list and perform notification */
     Entry = MixerInfo->EventList.Flink;
     while(Entry != &MixerInfo->EventList)
     {
@@ -317,6 +406,247 @@ MMixerSetGetMuteControlDetails(
     return Status;
 }
 
+MIXER_STATUS
+MMixerSetGetMuxControlDetails(
+    IN PMIXER_CONTEXT MixerContext,
+    IN LPMIXER_INFO MixerInfo,
+    IN ULONG NodeId,
+    IN ULONG bSet,
+    IN ULONG Flags,
+    IN LPMIXERCONTROL_EXT MixerControl,
+    IN LPMIXERCONTROLDETAILS MixerControlDetails,
+    IN LPMIXERLINE_EXT MixerLine)
+{
+    MIXER_STATUS Status;
+    PULONG LogicalNodes, ConnectedNodes;
+    ULONG LogicalNodesCount, ConnectedNodesCount, Index, CurLogicalPinOffset, BytesReturned, OldLogicalPinOffset;
+    LPMIXER_DATA MixerData;
+    LPMIXERCONTROLDETAILS_LISTTEXTW ListText;
+    LPMIXERCONTROLDETAILS_BOOLEAN Values;
+    LPMIXERLINE_EXT SourceLine;
+    KSNODEPROPERTY Request;
+
+    DPRINT("MixerControlDetails %p\n", MixerControlDetails);
+    DPRINT("bSet %lx\n", bSet);
+    DPRINT("Flags %lx\n", Flags);
+    DPRINT("NodeId %lu\n", MixerControl->NodeID);
+    DPRINT("MixerControlDetails dwControlID %lu\n", MixerControlDetails->dwControlID);
+    DPRINT("MixerControlDetails cChannels %lu\n", MixerControlDetails->cChannels);
+    DPRINT("MixerControlDetails cMultipleItems %lu\n", MixerControlDetails->cMultipleItems);
+    DPRINT("MixerControlDetails cbDetails %lu\n", MixerControlDetails->cbDetails);
+    DPRINT("MixerControlDetails paDetails %p\n", MixerControlDetails->paDetails);
+
+    if (MixerControl->Control.fdwControl & MIXERCONTROL_CONTROLF_UNIFORM)
+    {
+        /* control acts uniform */
+        if (MixerControlDetails->cChannels != 1)
+        {
+            /* expected 1 channel */
+            DPRINT1("Expected 1 channel but got %lu\n", MixerControlDetails->cChannels);
+            return MM_STATUS_UNSUCCESSFUL;
+        }
+    }
+
+    /* check if multiple items match */
+    if (MixerControlDetails->cMultipleItems != MixerControl->Control.cMultipleItems)
+    {
+        DPRINT1("MultipleItems mismatch %lu expected %lu\n", MixerControlDetails->cMultipleItems, MixerControl->Control.cMultipleItems);
+        return MM_STATUS_UNSUCCESSFUL;
+    }
+
+    if (bSet)
+    {
+        if ((Flags & MIXER_SETCONTROLDETAILSF_QUERYMASK) == MIXER_SETCONTROLDETAILSF_CUSTOM)
+        {
+            /* tell me when this is hit */
+            ASSERT(FALSE);
+        }
+        else if ((Flags & (MIXER_SETCONTROLDETAILSF_VALUE | MIXER_SETCONTROLDETAILSF_CUSTOM)) == MIXER_SETCONTROLDETAILSF_VALUE)
+        {
+            /* sanity check */
+            ASSERT(bSet == TRUE);
+            ASSERT(MixerControlDetails->cbDetails == sizeof(MIXERCONTROLDETAILS_BOOLEAN));
+
+            Values = (LPMIXERCONTROLDETAILS_BOOLEAN)MixerControlDetails->paDetails;
+            CurLogicalPinOffset = MAXULONG;
+            for(Index = 0; Index < MixerControlDetails->cMultipleItems; Index++)
+            {
+                if (Values[Index].fValue)
+                {
+                    /* mux can only activate one line at a time */
+                    ASSERT(CurLogicalPinOffset == MAXULONG);
+                    CurLogicalPinOffset = Index;
+                }
+            }
+
+            /* setup request */
+            Request.NodeId = NodeId;
+            Request.Reserved = 0;
+            Request.Property.Flags = KSPROPERTY_TYPE_TOPOLOGY | KSPROPERTY_TYPE_GET;
+            Request.Property.Id = KSPROPERTY_AUDIO_MUX_SOURCE;
+            Request.Property.Set = KSPROPSETID_Audio;
+
+            /* perform getting source */
+            Status = MixerContext->Control(MixerControl->hDevice, IOCTL_KS_PROPERTY, (PVOID)&Request, sizeof(KSNODEPROPERTY), &OldLogicalPinOffset, sizeof(ULONG), &BytesReturned);
+            if (Status != MM_STATUS_SUCCESS)
+            {
+                /* failed to get source */
+                return Status;
+            }
+
+            DPRINT("OldLogicalPinOffset %lu CurLogicalPinOffset %lu\n", OldLogicalPinOffset, CurLogicalPinOffset);
+
+            if (OldLogicalPinOffset == CurLogicalPinOffset)
+            {
+                /* cannot be unselected */
+                return MM_STATUS_UNSUCCESSFUL;
+            }
+
+            /* perform setting source */
+            Request.Property.Flags = KSPROPERTY_TYPE_TOPOLOGY | KSPROPERTY_TYPE_SET;
+            Status = MixerContext->Control(MixerControl->hDevice, IOCTL_KS_PROPERTY, (PVOID)&Request, sizeof(KSNODEPROPERTY), &CurLogicalPinOffset, sizeof(ULONG), &BytesReturned);
+            if (Status != MM_STATUS_SUCCESS)
+            {
+                /* failed to set source */
+                return Status;
+            }
+
+            /* notify control change */
+            MMixerNotifyControlChange(MixerContext, MixerInfo, MM_MIXM_CONTROL_CHANGE, MixerControl->Control.dwControlID );
+
+            return Status;
+        }
+    }
+    else
+    {
+        if ((Flags & MIXER_GETCONTROLDETAILSF_QUERYMASK) == MIXER_GETCONTROLDETAILSF_VALUE)
+        {
+            /* setup request */
+            Request.NodeId = NodeId;
+            Request.Reserved = 0;
+            Request.Property.Flags = KSPROPERTY_TYPE_TOPOLOGY | KSPROPERTY_TYPE_GET;
+            Request.Property.Id = KSPROPERTY_AUDIO_MUX_SOURCE;
+            Request.Property.Set = KSPROPSETID_Audio;
+
+            /* perform getting source */
+            Status = MixerContext->Control(MixerControl->hDevice, IOCTL_KS_PROPERTY, (PVOID)&Request, sizeof(KSNODEPROPERTY), &OldLogicalPinOffset, sizeof(ULONG), &BytesReturned);
+            if (Status != MM_STATUS_SUCCESS)
+            {
+                /* failed to get source */
+                return Status;
+            }
+
+            /* get logical pin nodes */
+            MMixerGetConnectedFromLogicalTopologyPins(MixerData->Topology, MixerControl->NodeID, &LogicalNodesCount, LogicalNodes);
+
+            /* sanity check */
+            ASSERT(LogicalNodesCount == MixerControlDetails->cMultipleItems);
+            ASSERT(LogicalNodesCount == MixerControl->Control.Metrics.dwReserved[0]);
+
+            Values = (LPMIXERCONTROLDETAILS_BOOLEAN)MixerControlDetails->paDetails;
+            for(Index = 0; Index < ConnectedNodesCount; Index++)
+            {
+                /* getting logical pin offset */
+                MMixerGetLowestLogicalTopologyPinOffsetFromArray(LogicalNodesCount, LogicalNodes, &CurLogicalPinOffset);
+
+                if (CurLogicalPinOffset == OldLogicalPinOffset)
+                {
+                    /* mark index as active */
+                    Values[Index].fValue = TRUE;
+                }
+                else
+                {
+                    /* index not active */
+                    Values[Index].fValue = FALSE;
+                }
+
+                /* mark offset as consumed */
+                LogicalNodes[CurLogicalPinOffset] = MAXULONG;
+            }
+
+            /* cleanup */
+            MixerContext->Free(LogicalNodes);
+
+            /* done */
+            return MM_STATUS_SUCCESS;
+        }
+        else if ((Flags & MIXER_GETCONTROLDETAILSF_QUERYMASK) == MIXER_GETCONTROLDETAILSF_LISTTEXT)
+        {
+            /* sanity check */
+            ASSERT(bSet == FALSE);
+
+            /* gets the corresponding mixer data */
+            MixerData = MMixerGetMixerDataByDeviceHandle(MixerContext, MixerControl->hDevice);
+
+            /* sanity check */
+            ASSERT(MixerData);
+            ASSERT(MixerData->Topology);
+            ASSERT(MixerData->MixerInfo == MixerInfo);
+
+            /* now allocate logical pin array */
+            Status = MMixerAllocateTopologyNodeArray(MixerContext, MixerData->Topology, &LogicalNodes);
+            if (Status != MM_STATUS_SUCCESS)
+            {
+                /* no memory */
+                return MM_STATUS_NO_MEMORY;
+            }
+
+            /* allocate connected node array */
+            Status = MMixerAllocateTopologyNodeArray(MixerContext, MixerData->Topology, &ConnectedNodes);
+            if (Status != MM_STATUS_SUCCESS)
+            {
+                /* no memory */
+                MixerContext->Free(LogicalNodes);
+                return MM_STATUS_NO_MEMORY;
+            }
+
+            /* get logical pin nodes */
+            MMixerGetConnectedFromLogicalTopologyPins(MixerData->Topology, MixerControl->NodeID, &LogicalNodesCount, LogicalNodes);
+
+            /* get connected nodes */
+            MMixerGetNextNodesFromNodeIndex(MixerContext, MixerData->Topology, MixerControl->NodeID, TRUE, &ConnectedNodesCount, ConnectedNodes);
+
+            /* sanity check */
+            ASSERT(ConnectedNodesCount == LogicalNodesCount);
+            ASSERT(ConnectedNodesCount == MixerControlDetails->cMultipleItems);
+            ASSERT(ConnectedNodesCount == MixerControl->Control.Metrics.dwReserved[0]);
+
+            ListText = (LPMIXERCONTROLDETAILS_LISTTEXTW)MixerControlDetails->paDetails;
+
+            for(Index = 0; Index < ConnectedNodesCount; Index++)
+            {
+                /* getting logical pin offset */
+                MMixerGetLowestLogicalTopologyPinOffsetFromArray(LogicalNodesCount, LogicalNodes, &CurLogicalPinOffset);
+
+                /* get mixer line with that node */
+                SourceLine = MMixerGetMixerLineContainingNodeId(MixerInfo, ConnectedNodes[CurLogicalPinOffset]);
+
+                /* sanity check */
+                ASSERT(SourceLine);
+
+                DPRINT1("PinOffset %lu LogicalPin %lu NodeId %lu LineName %S\n", CurLogicalPinOffset, LogicalNodes[CurLogicalPinOffset], ConnectedNodes[CurLogicalPinOffset], SourceLine->Line.szName);
+
+                /* copy details */
+                ListText[Index].dwParam1 = SourceLine->Line.dwLineID;
+                ListText[Index].dwParam2 = SourceLine->Line.dwComponentType;
+                MixerContext->Copy(ListText[Index].szName, SourceLine->Line.szName, (wcslen(SourceLine->Line.szName) + 1) * sizeof(WCHAR));
+
+                /* mark offset as consumed */
+                LogicalNodes[CurLogicalPinOffset] = MAXULONG;
+            }
+
+            /* cleanup */
+            MixerContext->Free(LogicalNodes);
+            MixerContext->Free(ConnectedNodes);
+
+            /* done */
+            return MM_STATUS_SUCCESS;
+        }
+    }
+
+    return MM_STATUS_NOT_IMPLEMENTED;
+}
+
 MIXER_STATUS
 MMixerSetGetVolumeControlDetails(
     IN PMIXER_CONTEXT MixerContext,
index ab04756..c1d4c3d 100644 (file)
@@ -1162,6 +1162,32 @@ MMixerIsNodeConnectedToPin(
     return MM_STATUS_SUCCESS;
 }
 
+VOID
+MMixerGetConnectedFromLogicalTopologyPins(
+    IN PTOPOLOGY Topology,
+    IN ULONG NodeIndex,
+    OUT PULONG OutPinCount,
+    OUT PULONG OutPins)
+{
+    ULONG Index;
+    PTOPOLOGY_NODE Node;
+
+    /* sanity check */
+    ASSERT(NodeIndex < Topology->TopologyNodesCount);
+
+    /* get node */
+    Node = &Topology->TopologyNodes[NodeIndex];
+
+    for(Index = 0; Index < Node->NodeConnectedFromCount; Index++)
+    {
+        /* copy logical pin id */
+        OutPins[Index] = Node->LogicalPinNodeConnectedFrom[Index];
+    }
+
+    /* store pin count */
+    *OutPinCount = Node->NodeConnectedFromCount;
+}
+
 LPGUID
 MMixerGetNodeTypeFromTopology(
     IN PTOPOLOGY Topology,