From 5e2f536e5cbc84d9e74a9ae5763ed623c871a044 Mon Sep 17 00:00:00 2001 From: Johannes Anderwald Date: Wed, 8 Dec 2010 19:49:28 +0000 Subject: [PATCH] [AUDIO-BRINGUP] - 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 | 25 ++- lib/drivers/sound/mmixer/controls.c | 4 +- lib/drivers/sound/mmixer/mixer.c | 16 +- lib/drivers/sound/mmixer/mmixer.h | 2 +- lib/drivers/sound/mmixer/priv.h | 18 ++ lib/drivers/sound/mmixer/sup.c | 332 +++++++++++++++++++++++++++- lib/drivers/sound/mmixer/topology.c | 26 +++ 7 files changed, 410 insertions(+), 13 deletions(-) diff --git a/dll/win32/wdmaud.drv/mmixer.c b/dll/win32/wdmaud.drv/mmixer.c index 1e4043b2821..0047e8d520f 100644 --- a/dll/win32/wdmaud.drv/mmixer.c +++ b/dll/win32/wdmaud.drv/mmixer.c @@ -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; diff --git a/lib/drivers/sound/mmixer/controls.c b/lib/drivers/sound/mmixer/controls.c index 6d57bd7f0d3..a0ba67ad403 100644 --- a/lib/drivers/sound/mmixer/controls.c +++ b/lib/drivers/sound/mmixer/controls.c @@ -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); diff --git a/lib/drivers/sound/mmixer/mixer.c b/lib/drivers/sound/mmixer/mixer.c index 5a8e666026b..980a49e6bce 100644 --- a/lib/drivers/sound/mmixer/mixer.c +++ b/lib/drivers/sound/mmixer/mixer.c @@ -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; diff --git a/lib/drivers/sound/mmixer/mmixer.h b/lib/drivers/sound/mmixer/mmixer.h index 96497062c43..4b7b1467788 100644 --- a/lib/drivers/sound/mmixer/mmixer.h +++ b/lib/drivers/sound/mmixer/mmixer.h @@ -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, diff --git a/lib/drivers/sound/mmixer/priv.h b/lib/drivers/sound/mmixer/priv.h index f794d7124f9..3746f6d247b 100644 --- a/lib/drivers/sound/mmixer/priv.h +++ b/lib/drivers/sound/mmixer/priv.h @@ -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); diff --git a/lib/drivers/sound/mmixer/sup.c b/lib/drivers/sound/mmixer/sup.c index 400dba89eb5..7526ef62043 100644 --- a/lib/drivers/sound/mmixer/sup.c +++ b/lib/drivers/sound/mmixer/sup.c @@ -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, diff --git a/lib/drivers/sound/mmixer/topology.c b/lib/drivers/sound/mmixer/topology.c index ab04756cc6b..c1d4c3d1051 100644 --- a/lib/drivers/sound/mmixer/topology.c +++ b/lib/drivers/sound/mmixer/topology.c @@ -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, -- 2.17.1