Author: janderwald
Date: Wed Dec 9 17:00:28 2009
New Revision: 44482
URL:
http://svn.reactos.org/svn/reactos?rev=44482&view=rev
Log:
[MMIXER]
- Implement MMixerGetLineInfo, MMixerGetLineControls, MMixerSetControlDetails,
MMixerGetControlDetails, MMixerOpen
- MMixer library is now ready for testing
Modified:
trunk/reactos/lib/drivers/sound/mmixer/controls.c
trunk/reactos/lib/drivers/sound/mmixer/filter.c
trunk/reactos/lib/drivers/sound/mmixer/mixer.c
trunk/reactos/lib/drivers/sound/mmixer/mmixer.h
trunk/reactos/lib/drivers/sound/mmixer/priv.h
trunk/reactos/lib/drivers/sound/mmixer/sup.c
Modified: trunk/reactos/lib/drivers/sound/mmixer/controls.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/lib/drivers/sound/mmixer/c…
==============================================================================
--- trunk/reactos/lib/drivers/sound/mmixer/controls.c [iso-8859-1] (original)
+++ trunk/reactos/lib/drivers/sound/mmixer/controls.c [iso-8859-1] Wed Dec 9 17:00:28
2009
@@ -203,10 +203,10 @@
Status = MixerContext->Control(hDevice, IOCTL_KS_PROPERTY, (PVOID)&Node,
sizeof(KSP_NODE), (LPVOID)Name, BytesReturned, &BytesReturned);
if (Status != MM_STATUS_SUCCESS)
{
- RtlMoveMemory(MixerControl->szShortName, Name,
(min(MIXER_SHORT_NAME_CHARS, wcslen(Name)+1)) * sizeof(WCHAR));
+ MixerContext->Copy(MixerControl->szShortName, Name,
(min(MIXER_SHORT_NAME_CHARS, wcslen(Name)+1)) * sizeof(WCHAR));
MixerControl->szShortName[MIXER_SHORT_NAME_CHARS-1] = L'\0';
- RtlMoveMemory(MixerControl->szName, Name, (min(MIXER_LONG_NAME_CHARS,
wcslen(Name)+1)) * sizeof(WCHAR));
+ MixerContext->Copy(MixerControl->szName, Name,
(min(MIXER_LONG_NAME_CHARS, wcslen(Name)+1)) * sizeof(WCHAR));
MixerControl->szName[MIXER_LONG_NAME_CHARS-1] = L'\0';
}
@@ -512,10 +512,10 @@
if (Status != MM_STATUS_SUCCESS)
{
- RtlMoveMemory(SrcLine->Line.szShortName, PinName,
(min(MIXER_SHORT_NAME_CHARS, wcslen(PinName)+1)) * sizeof(WCHAR));
+ 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';
- RtlMoveMemory(SrcLine->Line.szName, PinName,
(min(MIXER_LONG_NAME_CHARS, wcslen(PinName)+1)) * sizeof(WCHAR));
+ 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);
Modified: trunk/reactos/lib/drivers/sound/mmixer/filter.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/lib/drivers/sound/mmixer/f…
==============================================================================
--- trunk/reactos/lib/drivers/sound/mmixer/filter.c [iso-8859-1] (original)
+++ trunk/reactos/lib/drivers/sound/mmixer/filter.c [iso-8859-1] Wed Dec 9 17:00:28 2009
@@ -205,3 +205,48 @@
UNIMPLEMENTED
return 0;
}
+
+MIXER_STATUS
+MMixerSetGetControlDetails(
+ IN PMIXER_CONTEXT MixerContext,
+ IN HANDLE hMixer,
+ IN ULONG NodeId,
+ IN ULONG bSet,
+ IN ULONG PropertyId,
+ IN ULONG Channel,
+ IN PLONG InputValue)
+{
+ KSNODEPROPERTY_AUDIO_CHANNEL Property;
+ MIXER_STATUS Status;
+ LONG Value;
+ ULONG BytesReturned;
+
+ if (bSet)
+ Value = *InputValue;
+
+ /* setup the request */
+ RtlZeroMemory(&Property, sizeof(KSNODEPROPERTY_AUDIO_CHANNEL));
+
+ Property.NodeProperty.NodeId = NodeId;
+ Property.NodeProperty.Property.Id = PropertyId;
+ Property.NodeProperty.Property.Flags = KSPROPERTY_TYPE_TOPOLOGY;
+ Property.NodeProperty.Property.Set = KSPROPSETID_Audio;
+ Property.Channel = Channel;
+ Property.Reserved = 0;
+
+ if (bSet)
+ Property.NodeProperty.Property.Flags |= KSPROPERTY_TYPE_SET;
+ else
+ Property.NodeProperty.Property.Flags |= KSPROPERTY_TYPE_GET;
+
+ /* send the request */
+ Status = MixerContext->Control(hMixer, IOCTL_KS_PROPERTY, (PVOID)&Property,
sizeof(KSNODEPROPERTY_AUDIO_CHANNEL), (PVOID)&Value, sizeof(LONG),
&BytesReturned);
+
+ if (!bSet && Status == MM_STATUS_SUCCESS)
+ {
+ *InputValue = Value;
+ }
+
+ DPRINT("Status %x bSet %u NodeId %u Value %d PropertyId %u\n", Status,
bSet, NodeId, Value, PropertyId);
+ return Status;
+}
Modified: trunk/reactos/lib/drivers/sound/mmixer/mixer.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/lib/drivers/sound/mmixer/m…
==============================================================================
--- trunk/reactos/lib/drivers/sound/mmixer/mixer.c [iso-8859-1] (original)
+++ trunk/reactos/lib/drivers/sound/mmixer/mixer.c [iso-8859-1] Wed Dec 9 17:00:28 2009
@@ -73,22 +73,37 @@
MIXER_STATUS
MMixerOpen(
IN PMIXER_CONTEXT MixerContext,
+ IN ULONG MixerId,
IN PVOID MixerEvent,
IN PMIXER_EVENT MixerEventRoutine,
OUT PHANDLE MixerHandle)
{
MIXER_STATUS Status;
-
- // verify mixer context
- Status = MMixerVerifyContext(MixerContext);
-
- if (Status != MM_STATUS_SUCCESS)
- {
- // invalid context passed
- return Status;
- }
-
- return MM_STATUS_NOT_IMPLEMENTED;
+ LPMIXER_INFO MixerInfo;
+
+ // verify mixer context
+ Status = MMixerVerifyContext(MixerContext);
+
+ if (Status != MM_STATUS_SUCCESS)
+ {
+ // invalid context passed
+ return Status;
+ }
+
+ MixerInfo = (LPMIXER_INFO)MMixerGetMixerInfoByIndex(MixerContext, MixerId);
+ if (!MixerInfo)
+ {
+ // invalid mixer id
+ return MM_STATUS_INVALID_PARAMETER;
+ }
+
+ // FIXME
+ // handle event notification
+
+ // store result
+ *MixerHandle = (HANDLE)MixerInfo;
+
+ return MM_STATUS_SUCCESS;
}
MIXER_STATUS
@@ -99,15 +114,99 @@
OUT LPMIXERLINEW MixerLine)
{
MIXER_STATUS Status;
-
- // verify mixer context
- Status = MMixerVerifyContext(MixerContext);
-
- if (Status != MM_STATUS_SUCCESS)
- {
- // invalid context passed
- return Status;
- }
+ LPMIXER_INFO MixerInfo;
+ LPMIXERLINE_EXT MixerLineSrc;
+
+ // verify mixer context
+ Status = MMixerVerifyContext(MixerContext);
+
+ if (Status != MM_STATUS_SUCCESS)
+ {
+ // invalid context passed
+ return Status;
+ }
+
+ // clear hmixer from flags
+ Flags &=~MIXER_OBJECTF_HMIXER;
+
+ if (Flags == MIXER_GETLINEINFOF_DESTINATION)
+ {
+ // cast to mixer info
+ MixerInfo = (LPMIXER_INFO)MixerHandle;
+
+ if (MixerLine->dwDestination != 0)
+ {
+ // destination line member must be zero
+ return MM_STATUS_INVALID_PARAMETER;
+ }
+
+ MixerLineSrc = MMixerGetSourceMixerLineByLineId(MixerInfo, DESTINATION_LINE);
+ ASSERT(MixerLineSrc);
+ MixerContext->Copy(MixerLine, &MixerLineSrc->Line,
sizeof(MIXERLINEW));
+
+ return MM_STATUS_SUCCESS;
+ }
+ else if (Flags == MIXER_GETLINEINFOF_SOURCE)
+ {
+ // cast to mixer info
+ MixerInfo = (LPMIXER_INFO)MixerHandle;
+
+
+ MixerLineSrc = MMixerGetSourceMixerLineByLineId(MixerInfo, DESTINATION_LINE);
+ ASSERT(MixerLineSrc);
+
+ if (MixerLine->dwSource >= MixerLineSrc->Line.cConnections)
+ {
+ DPRINT1("dwSource %u > Destinations %u\n",
MixerLine->dwSource, MixerLineSrc->Line.cConnections);
+
+ // invalid parameter
+ return MM_STATUS_INVALID_PARAMETER;
+ }
+
+ MixerLineSrc = MMixerGetSourceMixerLineByLineId(MixerInfo,
MixerLine->dwSource);
+ if (MixerLineSrc)
+ {
+ DPRINT("Line %u Name %S\n", MixerLineSrc->Line.dwSource,
MixerLineSrc->Line.szName);
+ MixerContext->Copy(MixerLine, &MixerLineSrc->Line,
sizeof(MIXERLINEW));
+ return MM_STATUS_SUCCESS;
+ }
+ return MM_STATUS_UNSUCCESSFUL;
+ }
+ else if (Flags == MIXER_GETLINEINFOF_LINEID)
+ {
+ // cast to mixer info
+ MixerInfo = (LPMIXER_INFO)MixerHandle;
+
+ MixerLineSrc = MMixerGetSourceMixerLineByLineId(MixerInfo,
MixerLine->dwLineID);
+ if (!MixerLineSrc)
+ {
+ // invalid parameter
+ return MM_STATUS_INVALID_PARAMETER;
+ }
+
+ /* copy cached data */
+ MixerContext->Copy(MixerLine, &MixerLineSrc->Line,
sizeof(MIXERLINEW));
+ return MM_STATUS_SUCCESS;
+ }
+ else if (Flags == MIXER_GETLINEINFOF_COMPONENTTYPE)
+ {
+ // cast to mixer info
+ MixerInfo = (LPMIXER_INFO)MixerHandle;
+
+ MixerLineSrc = MMixerGetSourceMixerLineByComponentType(MixerInfo,
MixerLine->dwComponentType);
+ if (!MixerLineSrc)
+ {
+ DPRINT1("Failed to find component type %x\n",
MixerLine->dwComponentType);
+ return MM_STATUS_UNSUCCESSFUL;
+ }
+
+ ASSERT(MixerLineSrc);
+
+ /* copy cached data */
+ MixerContext->Copy(MixerLine, &MixerLineSrc->Line,
sizeof(MIXERLINEW));
+ return MM_STATUS_SUCCESS;
+ }
+
return MM_STATUS_NOT_IMPLEMENTED;
}
@@ -118,16 +217,87 @@
IN ULONG Flags,
OUT LPMIXERLINECONTROLS MixerLineControls)
{
- MIXER_STATUS Status;
-
- // verify mixer context
- Status = MMixerVerifyContext(MixerContext);
-
- if (Status != MM_STATUS_SUCCESS)
- {
- // invalid context passed
- return Status;
- }
+ LPMIXER_INFO MixerInfo;
+ LPMIXERLINE_EXT MixerLineSrc;
+ LPMIXERCONTROLW MixerControl;
+ MIXER_STATUS Status;
+ ULONG Index;
+
+ // verify mixer context
+ Status = MMixerVerifyContext(MixerContext);
+
+ if (Status != MM_STATUS_SUCCESS)
+ {
+ // invalid context passed
+ return Status;
+ }
+
+ Flags &= ~MIXER_OBJECTF_HMIXER;
+
+ if (Flags == MIXER_GETLINECONTROLSF_ALL)
+ {
+ // cast to mixer info
+ MixerInfo = (LPMIXER_INFO)MixerHandle;
+
+ MixerLineSrc = MMixerGetSourceMixerLineByLineId(MixerInfo,
MixerLineControls->dwLineID);
+
+ if (!MixerLineSrc)
+ {
+ // invalid line id
+ return MM_STATUS_INVALID_PARAMETER;
+ }
+ // copy line control(s)
+ MixerContext->Copy(MixerLineControls->pamxctrl,
MixerLineSrc->LineControls, min(MixerLineSrc->Line.cControls,
MixerLineControls->cControls) * sizeof(MIXERCONTROLW));
+
+ return MM_STATUS_SUCCESS;
+ }
+ else if (Flags == MIXER_GETLINECONTROLSF_ONEBYTYPE)
+ {
+ // cast to mixer info
+ MixerInfo = (LPMIXER_INFO)MixerHandle;
+
+ MixerLineSrc = MMixerGetSourceMixerLineByLineId(MixerInfo,
MixerLineControls->dwLineID);
+
+ if (!MixerLineSrc)
+ {
+ // invalid line id
+ return MM_STATUS_INVALID_PARAMETER;
+ }
+
+ ASSERT(MixerLineSrc);
+
+ Index = 0;
+ for(Index = 0; Index < MixerLineSrc->Line.cControls; Index++)
+ {
+ DPRINT("dwControlType %x\n",
MixerLineSrc->LineControls[Index].dwControlType);
+ if (MixerLineControls->dwControlType ==
MixerLineSrc->LineControls[Index].dwControlType)
+ {
+ // found a control with that type
+ MixerContext->Copy(MixerLineControls->pamxctrl,
&MixerLineSrc->LineControls[Index], sizeof(MIXERCONTROLW));
+ return MM_STATUS_SUCCESS;
+ }
+ }
+ 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
+ return MM_STATUS_INVALID_PARAMETER;
+ }
+
+ // copy the controls
+ MixerContext->Copy(MixerLineControls->pamxctrl, MixerControl,
sizeof(MIXERCONTROLW));
+ return MM_STATUS_SUCCESS;
+ }
+
return MM_STATUS_NOT_IMPLEMENTED;
}
@@ -140,16 +310,46 @@
OUT LPMIXERCONTROLDETAILS MixerControlDetails)
{
MIXER_STATUS Status;
-
- // verify mixer context
- Status = MMixerVerifyContext(MixerContext);
-
- if (Status != MM_STATUS_SUCCESS)
- {
- // invalid context passed
- return Status;
- }
- return MM_STATUS_NOT_IMPLEMENTED;
+ ULONG NodeId;
+ LPMIXER_INFO MixerInfo;
+ LPMIXERLINE_EXT MixerLine;
+ LPMIXERCONTROLW MixerControl;
+
+ // verify mixer context
+ Status = MMixerVerifyContext(MixerContext);
+
+ if (Status != MM_STATUS_SUCCESS)
+ {
+ // invalid context passed
+ return Status;
+ }
+
+ // 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->dwControlType)
+ {
+ case MIXERCONTROL_CONTROLTYPE_MUTE:
+ Status = MMixerSetGetMuteControlDetails(MixerContext, MixerInfo->hMixer,
NodeId, MixerLine->Line.dwLineID, MixerControlDetails, TRUE);
+ break;
+ case MIXERCONTROL_CONTROLTYPE_VOLUME:
+ Status = MMixerSetGetVolumeControlDetails(MixerContext, MixerInfo->hMixer,
NodeId, TRUE, MixerControl, MixerControlDetails, MixerLine);
+ break;
+ default:
+ Status = MM_STATUS_NOT_IMPLEMENTED;
+ }
+
+ return Status;
}
MIXER_STATUS
@@ -160,17 +360,46 @@
OUT LPMIXERCONTROLDETAILS MixerControlDetails)
{
MIXER_STATUS Status;
-
- // verify mixer context
- Status = MMixerVerifyContext(MixerContext);
-
- if (Status != MM_STATUS_SUCCESS)
- {
- // invalid context passed
- return Status;
- }
-
- return MM_STATUS_NOT_IMPLEMENTED;
+ ULONG NodeId;
+ LPMIXER_INFO MixerInfo;
+ LPMIXERLINE_EXT MixerLine;
+ LPMIXERCONTROLW MixerControl;
+
+ // verify mixer context
+ Status = MMixerVerifyContext(MixerContext);
+
+ if (Status != MM_STATUS_SUCCESS)
+ {
+ // invalid context passed
+ return Status;
+ }
+
+ // 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->dwControlType)
+ {
+ case MIXERCONTROL_CONTROLTYPE_MUTE:
+ Status = MMixerSetGetMuteControlDetails(MixerContext, MixerInfo->hMixer,
NodeId, MixerLine->Line.dwLineID, MixerControlDetails, FALSE);
+ break;
+ case MIXERCONTROL_CONTROLTYPE_VOLUME:
+ Status = MMixerSetGetVolumeControlDetails(MixerContext, MixerInfo->hMixer,
NodeId, FALSE, MixerControl, MixerControlDetails, MixerLine);
+ break;
+ default:
+ Status = MM_STATUS_NOT_IMPLEMENTED;
+ }
+
+ return Status;
}
MIXER_STATUS
Modified: trunk/reactos/lib/drivers/sound/mmixer/mmixer.h
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/lib/drivers/sound/mmixer/m…
==============================================================================
--- trunk/reactos/lib/drivers/sound/mmixer/mmixer.h [iso-8859-1] (original)
+++ trunk/reactos/lib/drivers/sound/mmixer/mmixer.h [iso-8859-1] Wed Dec 9 17:00:28 2009
@@ -47,6 +47,11 @@
typedef VOID (*PMIXER_EVENT)(
IN PVOID MixerEvent);
+typedef VOID (*PMIXER_COPY)(
+ IN PVOID Dst,
+ IN PVOID Src,
+ IN ULONG Length);
+
typedef struct
{
@@ -58,6 +63,7 @@
PMIXER_FREE Free;
PMIXER_OPEN Open;
PMIXER_CLOSE Close;
+ PMIXER_COPY Copy;
}MIXER_CONTEXT, *PMIXER_CONTEXT;
MIXER_STATUS
@@ -79,6 +85,7 @@
MIXER_STATUS
MMixerOpen(
IN PMIXER_CONTEXT MixerContext,
+ IN ULONG MixerId,
IN PVOID MixerEvent,
IN PMIXER_EVENT MixerEventRoutine,
OUT PHANDLE MixerHandle);
Modified: trunk/reactos/lib/drivers/sound/mmixer/priv.h
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/lib/drivers/sound/mmixer/p…
==============================================================================
--- trunk/reactos/lib/drivers/sound/mmixer/priv.h [iso-8859-1] (original)
+++ trunk/reactos/lib/drivers/sound/mmixer/priv.h [iso-8859-1] Wed Dec 9 17:00:28 2009
@@ -164,5 +164,46 @@
IN PMIXER_CONTEXT MixerContext,
IN ULONG MixerIndex);
+LPMIXERLINE_EXT
+MMixerGetSourceMixerLineByComponentType(
+ LPMIXER_INFO MixerInfo,
+ DWORD dwComponentType);
+
+MIXER_STATUS
+MMixerGetMixerControlById(
+ LPMIXER_INFO MixerInfo,
+ DWORD dwControlID,
+ LPMIXERLINE_EXT *MixerLine,
+ LPMIXERCONTROLW *MixerControl,
+ PULONG NodeId);
+
+MIXER_STATUS
+MMixerSetGetMuteControlDetails(
+ IN PMIXER_CONTEXT MixerContext,
+ IN HANDLE hMixer,
+ IN ULONG NodeId,
+ IN ULONG dwLineID,
+ IN LPMIXERCONTROLDETAILS MixerControlDetails,
+ IN ULONG bSet);
+
+MIXER_STATUS
+MMixerSetGetVolumeControlDetails(
+ IN PMIXER_CONTEXT MixerContext,
+ IN HANDLE hMixer,
+ IN ULONG NodeId,
+ IN ULONG bSet,
+ LPMIXERCONTROLW MixerControl,
+ IN LPMIXERCONTROLDETAILS MixerControlDetails,
+ LPMIXERLINE_EXT MixerLine);
+
+MIXER_STATUS
+MMixerSetGetControlDetails(
+ IN PMIXER_CONTEXT MixerContext,
+ IN HANDLE hMixer,
+ IN ULONG NodeId,
+ IN ULONG bSet,
+ IN ULONG PropertyId,
+ IN ULONG Channel,
+ IN PLONG InputValue);
#endif
Modified: trunk/reactos/lib/drivers/sound/mmixer/sup.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/lib/drivers/sound/mmixer/s…
==============================================================================
--- trunk/reactos/lib/drivers/sound/mmixer/sup.c [iso-8859-1] (original)
+++ trunk/reactos/lib/drivers/sound/mmixer/sup.c [iso-8859-1] Wed Dec 9 17:00:28 2009
@@ -71,6 +71,28 @@
return NULL;
}
+LPMIXERCONTROL_DATA
+MMixerGetMixerControlDataById(
+ PLIST_ENTRY ListHead,
+ DWORD dwControlId)
+{
+ PLIST_ENTRY Entry;
+ LPMIXERCONTROL_DATA Control;
+
+ /* get first entry */
+ Entry = ListHead->Flink;
+
+ while(Entry != ListHead)
+ {
+ Control = (LPMIXERCONTROL_DATA)CONTAINING_RECORD(Entry, MIXERCONTROL_DATA,
Entry);
+ DPRINT("dwSource %x dwSource %x\n", Control->dwControlID,
dwControlId);
+ if (Control->dwControlID == dwControlId)
+ return Control;
+
+ Entry = Entry->Flink;
+ }
+ return NULL;
+}
LPMIXERLINE_EXT
MMixerGetSourceMixerLineByLineId(
@@ -314,3 +336,190 @@
return Status;
}
+
+LPMIXERLINE_EXT
+MMixerGetSourceMixerLineByComponentType(
+ LPMIXER_INFO MixerInfo,
+ DWORD dwComponentType)
+{
+ PLIST_ENTRY Entry;
+ LPMIXERLINE_EXT MixerLineSrc;
+
+ /* get first entry */
+ Entry = MixerInfo->LineList.Flink;
+
+ while(Entry != &MixerInfo->LineList)
+ {
+ MixerLineSrc = (LPMIXERLINE_EXT)CONTAINING_RECORD(Entry, MIXERLINE_EXT, Entry);
+ if (MixerLineSrc->Line.dwComponentType == dwComponentType)
+ return MixerLineSrc;
+
+ Entry = Entry->Flink;
+ }
+
+ return NULL;
+}
+
+MIXER_STATUS
+MMixerGetMixerControlById(
+ LPMIXER_INFO MixerInfo,
+ DWORD dwControlID,
+ LPMIXERLINE_EXT *MixerLine,
+ LPMIXERCONTROLW *MixerControl,
+ PULONG NodeId)
+{
+ PLIST_ENTRY Entry;
+ LPMIXERLINE_EXT MixerLineSrc;
+ ULONG Index;
+
+ /* get first entry */
+ Entry = MixerInfo->LineList.Flink;
+
+ while(Entry != &MixerInfo->LineList)
+ {
+ MixerLineSrc = (LPMIXERLINE_EXT)CONTAINING_RECORD(Entry, MIXERLINE_EXT, Entry);
+
+ for(Index = 0; Index < MixerLineSrc->Line.cControls; Index++)
+ {
+ if (MixerLineSrc->LineControls[Index].dwControlID == dwControlID)
+ {
+ if (MixerLine)
+ *MixerLine = MixerLineSrc;
+ if (MixerControl)
+ *MixerControl = &MixerLineSrc->LineControls[Index];
+ if (NodeId)
+ *NodeId = MixerLineSrc->NodeIds[Index];
+ return MM_STATUS_SUCCESS;
+ }
+ }
+ Entry = Entry->Flink;
+ }
+
+ return MM_STATUS_UNSUCCESSFUL;
+}
+
+ULONG
+MMixerGetVolumeControlIndex(
+ LPMIXERVOLUME_DATA VolumeData,
+ LONG Value)
+{
+ ULONG Index;
+
+ for(Index = 0; Index < VolumeData->ValuesCount; Index++)
+ {
+ if (VolumeData->Values[Index] > Value)
+ {
+ return VolumeData->InputSteppingDelta * Index;
+ }
+ }
+ return VolumeData->InputSteppingDelta * (VolumeData->ValuesCount-1);
+}
+
+MIXER_STATUS
+MMixerSetGetMuteControlDetails(
+ IN PMIXER_CONTEXT MixerContext,
+ IN HANDLE hMixer,
+ IN ULONG NodeId,
+ IN ULONG dwLineID,
+ IN LPMIXERCONTROLDETAILS MixerControlDetails,
+ IN ULONG bSet)
+{
+ LPMIXERCONTROLDETAILS_BOOLEAN Input;
+ LONG Value;
+ MIXER_STATUS Status;
+
+ if (MixerControlDetails->cbDetails != sizeof(MIXERCONTROLDETAILS_BOOLEAN))
+ return MM_STATUS_INVALID_PARAMETER;
+
+ /* get input */
+ Input = (LPMIXERCONTROLDETAILS_BOOLEAN)MixerControlDetails->paDetails;
+
+ /* FIXME SEH */
+ if (bSet)
+ Value = Input->fValue;
+
+ /* set control details */
+ Status = MMixerSetGetControlDetails(MixerContext, hMixer, NodeId, bSet,
KSPROPERTY_AUDIO_MUTE, 0, &Value);
+
+ if (Status != MM_STATUS_SUCCESS)
+ return Status;
+
+ /* FIXME SEH */
+ if (!bSet)
+ {
+ Input->fValue = Value;
+ return Status;
+ }
+ else
+ {
+ // FIXME notify wdmaud clients MM_MIXM_LINE_CHANGE dwLineID
+ }
+
+ return Status;
+}
+
+MIXER_STATUS
+MMixerSetGetVolumeControlDetails(
+ IN PMIXER_CONTEXT MixerContext,
+ IN HANDLE hMixer,
+ IN ULONG NodeId,
+ IN ULONG bSet,
+ LPMIXERCONTROLW MixerControl,
+ IN LPMIXERCONTROLDETAILS MixerControlDetails,
+ LPMIXERLINE_EXT MixerLine)
+{
+ LPMIXERCONTROLDETAILS_UNSIGNED Input;
+ LONG Value, Index, Channel = 0;
+ ULONG dwValue;
+ MIXER_STATUS Status;
+ LPMIXERVOLUME_DATA VolumeData;
+
+ if (MixerControlDetails->cbDetails != sizeof(MIXERCONTROLDETAILS_SIGNED))
+ return MM_STATUS_INVALID_PARAMETER;
+
+ VolumeData =
(LPMIXERVOLUME_DATA)MMixerGetMixerControlDataById(&MixerLine->LineControlsExtraData,
MixerControl->dwControlID);
+ if (!VolumeData)
+ return MM_STATUS_UNSUCCESSFUL;
+
+ /* get input */
+ Input = (LPMIXERCONTROLDETAILS_UNSIGNED)MixerControlDetails->paDetails;
+
+ if (bSet)
+ {
+ /* FIXME SEH */
+ Value = Input->dwValue;
+ Index = Value / VolumeData->InputSteppingDelta;
+
+ if (Index >= VolumeData->ValuesCount)
+ {
+ DPRINT1("Index %u out of bounds %u \n", Index,
VolumeData->ValuesCount);
+ DbgBreakPoint();
+ return MM_STATUS_INVALID_PARAMETER;
+ }
+
+ Value = VolumeData->Values[Index];
+ }
+
+ /* set control details */
+ if (bSet)
+ {
+ Status = MMixerSetGetControlDetails(MixerContext, hMixer, NodeId, bSet,
KSPROPERTY_AUDIO_VOLUMELEVEL, 0, &Value);
+ Status = MMixerSetGetControlDetails(MixerContext, hMixer, NodeId, bSet,
KSPROPERTY_AUDIO_VOLUMELEVEL, 1, &Value);
+ }
+ else
+ {
+ Status = MMixerSetGetControlDetails(MixerContext, hMixer, NodeId, bSet,
KSPROPERTY_AUDIO_VOLUMELEVEL, Channel, &Value);
+ }
+
+ if (!bSet)
+ {
+ dwValue = MMixerGetVolumeControlIndex(VolumeData, (LONG)Value);
+ /* FIXME SEH */
+ Input->dwValue = dwValue;
+ }
+ else
+ {
+ /* notify clients of a line change MM_MIXM_CONTROL_CHANGE with
MixerControl->dwControlID */
+ }
+ return Status;
+}