From 9114169b5eb19abe8b46b8ac4576310458a45cf6 Mon Sep 17 00:00:00 2001 From: Johannes Anderwald Date: Mon, 5 Oct 2009 17:00:59 +0000 Subject: [PATCH 1/1] - Implement setting / getting volume level svn path=/trunk/; revision=43305 --- .../drivers/wdm/audio/legacy/wdmaud/mixer.c | 252 ++++++++++++++++-- .../drivers/wdm/audio/legacy/wdmaud/wdmaud.h | 20 ++ 2 files changed, 245 insertions(+), 27 deletions(-) diff --git a/reactos/drivers/wdm/audio/legacy/wdmaud/mixer.c b/reactos/drivers/wdm/audio/legacy/wdmaud/mixer.c index 8bd09bdfe42..4fc4775dcf0 100644 --- a/reactos/drivers/wdm/audio/legacy/wdmaud/mixer.c +++ b/reactos/drivers/wdm/audio/legacy/wdmaud/mixer.c @@ -50,6 +50,29 @@ GetSourceMixerLine( return NULL; } +LPMIXERCONTROL_DATA +GetMixerControlDataById( + 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; +} + NTSTATUS GetMixerControlById( LPMIXER_INFO MixerInfo, @@ -101,7 +124,7 @@ GetSourceMixerLineByLineId( while(Entry != &MixerInfo->LineList) { MixerLineSrc = (LPMIXERLINE_EXT)CONTAINING_RECORD(Entry, MIXERLINE_EXT, Entry); - DPRINT1("dwLineID %x dwLineID %x\n", MixerLineSrc->Line.dwLineID, dwLineID); + DPRINT("dwLineID %x dwLineID %x\n", MixerLineSrc->Line.dwLineID, dwLineID); if (MixerLineSrc->Line.dwLineID == dwLineID) return MixerLineSrc; @@ -889,6 +912,7 @@ AddMixerControl( IN PFILE_OBJECT FileObject, IN PKSMULTIPLE_ITEM NodeTypes, IN ULONG NodeIndex, + IN LPMIXERLINE_EXT MixerLine, OUT LPMIXERCONTROLW MixerControl) { LPGUID NodeType; @@ -897,7 +921,6 @@ AddMixerControl( NTSTATUS Status; LPWSTR Name; - /* initialize mixer control */ MixerControl->cbStruct = sizeof(MIXERCONTROLW); MixerControl->dwControlID = MixerInfo->ControlId; @@ -959,6 +982,77 @@ AddMixerControl( MixerInfo->ControlId++; + if (MixerControl->dwControlType == MIXERCONTROL_CONTROLTYPE_VOLUME) + { + KSNODEPROPERTY_AUDIO_CHANNEL Property; + ULONG Length; + PKSPROPERTY_DESCRIPTION Desc; + PKSPROPERTY_MEMBERSHEADER Members; + PKSPROPERTY_STEPPING_LONG Range; + + Length = sizeof(KSPROPERTY_DESCRIPTION) + sizeof(KSPROPERTY_MEMBERSHEADER) + sizeof(KSPROPERTY_STEPPING_LONG); + Desc = ExAllocatePool(NonPagedPool, Length); + ASSERT(Desc); + RtlZeroMemory(Desc, Length); + + /* setup the request */ + RtlZeroMemory(&Property, sizeof(KSNODEPROPERTY_AUDIO_CHANNEL)); + + Property.NodeProperty.NodeId = NodeIndex; + Property.NodeProperty.Property.Id = KSPROPERTY_AUDIO_VOLUMELEVEL; + Property.NodeProperty.Property.Flags = KSPROPERTY_TYPE_BASICSUPPORT; + Property.NodeProperty.Property.Set = KSPROPSETID_Audio; + + /* get node volume level info */ + Status = KsSynchronousIoControlDevice(FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSNODEPROPERTY_AUDIO_CHANNEL), Desc, Length, &BytesReturned); + + if (NT_SUCCESS(Status)) + { + LPMIXERVOLUME_DATA VolumeData; + ULONG Steps, MaxRange, Index; + LONG Value; + + Members = (PKSPROPERTY_MEMBERSHEADER)(Desc + 1); + Range = (PKSPROPERTY_STEPPING_LONG)(Members + 1); //98304 + + DPRINT("NodeIndex %u Range Min %d Max %d Steps %x UMin %x UMax %x\n", NodeIndex, Range->Bounds.SignedMinimum, Range->Bounds.SignedMaximum, Range->SteppingDelta, Range->Bounds.UnsignedMinimum, Range->Bounds.UnsignedMaximum); + + VolumeData = ExAllocatePool(NonPagedPool, sizeof(MIXERVOLUME_DATA)); + if (!VolumeData) + return STATUS_INSUFFICIENT_RESOURCES; + + MaxRange = (abs(Range->Bounds.SignedMinimum) + abs(Range->Bounds.SignedMaximum)); + Steps = MaxRange / Range->SteppingDelta + 1; + + /* store mixer control info there */ + VolumeData->Header.dwControlID = MixerControl->dwControlID; + VolumeData->SignedMaximum = Range->Bounds.SignedMaximum; + VolumeData->SignedMinimum = Range->Bounds.SignedMinimum; + VolumeData->SteppingDelta = Range->SteppingDelta; + VolumeData->ValuesCount = Steps; + VolumeData->InputSteppingDelta = 0x10000 / Steps; + + VolumeData->Values = ExAllocatePool(NonPagedPool, sizeof(LONG) * Steps); + if (!VolumeData->Values) + { + ExFreePool(Desc); + ExFreePool(VolumeData); + + return STATUS_INSUFFICIENT_RESOURCES; + } + + Value = Range->Bounds.SignedMinimum; + for(Index = 0; Index < Steps; Index++) + { + VolumeData->Values[Index] = Value; + Value += Range->SteppingDelta; + } + InsertTailList(&MixerLine->LineControlsExtraData, &VolumeData->Header.Entry); + } + ExFreePool(Desc); + } + + DPRINT("Status %x Name %S\n", Status, MixerControl->szName); return STATUS_SUCCESS; } @@ -1026,6 +1120,7 @@ AddMixerSourceLine( SrcLine->Line.Target.wMid = MixerInfo->MixCaps.wMid; SrcLine->Line.Target.wPid = MixerInfo->MixCaps.wPid; SrcLine->Line.Target.vDriverVersion = MixerInfo->MixCaps.vDriverVersion; + InitializeListHead(&SrcLine->LineControlsExtraData); wcscpy(SrcLine->Line.Target.szPname, MixerInfo->MixCaps.szPname); } @@ -1107,7 +1202,7 @@ AddMixerSourceLine( /* store the node index for retrieving / setting details */ SrcLine->NodeIds[ControlCount] = Index; - Status = AddMixerControl(MixerInfo, FileObject, NodeTypes, Index, &SrcLine->LineControls[ControlCount]); + Status = AddMixerControl(MixerInfo, FileObject, NodeTypes, Index, SrcLine, &SrcLine->LineControls[ControlCount]); if (NT_SUCCESS(Status)) { /* increment control count on success */ @@ -1430,6 +1525,7 @@ InitializeMixer( /* initialize source line list */ InitializeListHead(&MixerInfo->LineList); + InitializeListHead(&DestinationLine->LineControlsExtraData); /* insert destination line */ InsertHeadList(&MixerInfo->LineList, &DestinationLine->Entry); @@ -1781,13 +1877,14 @@ WdmAudGetLineControls( Index = 0; for(Index = 0; Index < MixerLineSrc->Line.cControls; Index++) { + DPRINT1("dwControlType %x\n", MixerLineSrc->LineControls[Index].dwControlType); if (DeviceInfo->u.MixControls.dwControlType == MixerLineSrc->LineControls[Index].dwControlType) { RtlMoveMemory(DeviceInfo->u.MixControls.pamxctrl, &MixerLineSrc->LineControls[Index], sizeof(MIXERCONTROLW)); return SetIrpIoStatus(Irp, STATUS_SUCCESS, sizeof(WDMAUD_DEVICE_INFO)); } } - DPRINT1("DeviceInfo->u.MixControls.dwControlType %x not found in Line %x\n", DeviceInfo->u.MixControls.dwControlType, DeviceInfo->u.MixControls.dwLineID); + DPRINT1("DeviceInfo->u.MixControls.dwControlType %x not found in Line %x cControls %u \n", DeviceInfo->u.MixControls.dwControlType, DeviceInfo->u.MixControls.dwLineID, MixerLineSrc->Line.cControls); return SetIrpIoStatus(Irp, STATUS_UNSUCCESSFUL, sizeof(WDMAUD_DEVICE_INFO)); } @@ -1798,33 +1895,25 @@ WdmAudGetLineControls( } NTSTATUS -SetGetMuteControlDetails( +SetGetControlDetails( IN PDEVICE_OBJECT DeviceObject, IN ULONG DeviceId, IN ULONG NodeId, IN PWDMAUD_DEVICE_INFO DeviceInfo, - IN ULONG bSet) + IN ULONG bSet, + IN ULONG PropertyId, + IN ULONG Channel, + IN PLONG InputValue) { KSNODEPROPERTY_AUDIO_CHANNEL Property; NTSTATUS Status; HANDLE hDevice; PFILE_OBJECT FileObject; - BOOL Value; + LONG Value; ULONG BytesReturned; - LPMIXERCONTROLDETAILS_BOOLEAN Input; - - if (DeviceInfo->u.MixDetails.cbDetails != sizeof(MIXERCONTROLDETAILS_BOOLEAN)) - return STATUS_INVALID_PARAMETER; - - /* get input */ - Input = (LPMIXERCONTROLDETAILS_BOOLEAN)DeviceInfo->u.MixDetails.paDetails; - - // - // FIXME SEH!!! - // if (bSet) - Value = Input->fValue; + Value = *InputValue; /* open virtual audio device */ Status = OpenSysAudioDeviceByIndex(DeviceObject, DeviceId, &hDevice, &FileObject); @@ -1839,10 +1928,10 @@ SetGetMuteControlDetails( RtlZeroMemory(&Property, sizeof(KSNODEPROPERTY_AUDIO_CHANNEL)); Property.NodeProperty.NodeId = NodeId; - Property.NodeProperty.Property.Id = KSPROPERTY_AUDIO_MUTE; + Property.NodeProperty.Property.Id = PropertyId; Property.NodeProperty.Property.Flags = KSPROPERTY_TYPE_TOPOLOGY; Property.NodeProperty.Property.Set = KSPROPSETID_Audio; - Property.Channel = MAXULONG; + Property.Channel = Channel; if (bSet) Property.NodeProperty.Property.Flags |= KSPROPERTY_TYPE_SET; @@ -1850,18 +1939,119 @@ SetGetMuteControlDetails( Property.NodeProperty.Property.Flags |= KSPROPERTY_TYPE_GET; /* send the request */ - Status = KsSynchronousIoControlDevice(FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSNODEPROPERTY_AUDIO_CHANNEL), (PVOID)&Value, sizeof(BOOL), &BytesReturned); + Status = KsSynchronousIoControlDevice(FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSNODEPROPERTY_AUDIO_CHANNEL), (PVOID)&Value, sizeof(LONG), &BytesReturned); ObDereferenceObject(FileObject); ZwClose(hDevice); if (!bSet) { - // FIXME SEH !!! + *InputValue = Value; + } + + DPRINT1("Status %x bSet %u NodeId %u Value %d PropertyId %u\n", Status, bSet, NodeId, Value, PropertyId); + return Status; +} + +NTSTATUS +SetGetMuteControlDetails( + IN PDEVICE_OBJECT DeviceObject, + IN ULONG DeviceId, + IN ULONG NodeId, + IN PWDMAUD_DEVICE_INFO DeviceInfo, + IN ULONG bSet) +{ + LPMIXERCONTROLDETAILS_BOOLEAN Input; + LONG Value; + NTSTATUS Status; + + if (DeviceInfo->u.MixDetails.cbDetails != sizeof(MIXERCONTROLDETAILS_BOOLEAN)) + return STATUS_INVALID_PARAMETER; + + /* get input */ + Input = (LPMIXERCONTROLDETAILS_BOOLEAN)DeviceInfo->u.MixDetails.paDetails; + + /* FIXME SEH */ + if (bSet) + Value = Input->fValue; + + /* set control details */ + Status = SetGetControlDetails(DeviceObject, DeviceId, NodeId, DeviceInfo, bSet, KSPROPERTY_AUDIO_MUTE, MAXULONG, &Value); + + /* FIXME SEH */ + if (!bSet) Input->fValue = Value; + + return Status; +} + +NTSTATUS +SetGetVolumeControlDetails( + IN PDEVICE_OBJECT DeviceObject, + IN ULONG DeviceId, + IN ULONG NodeId, + IN PWDMAUD_DEVICE_INFO DeviceInfo, + IN ULONG bSet, + LPMIXERCONTROLW MixerControl, + LPMIXERLINE_EXT MixerLine) +{ + LPMIXERCONTROLDETAILS_UNSIGNED Input; + LONG Value, Index, Channel = 0; + NTSTATUS Status; + LPMIXERVOLUME_DATA VolumeData; + + if (DeviceInfo->u.MixDetails.cbDetails != sizeof(MIXERCONTROLDETAILS_SIGNED)) + return STATUS_INVALID_PARAMETER; + + VolumeData = (LPMIXERVOLUME_DATA)GetMixerControlDataById(&MixerLine->LineControlsExtraData, MixerControl->dwControlID); + if (!VolumeData) + return STATUS_INSUFFICIENT_RESOURCES; + + + /* get input */ + Input = (LPMIXERCONTROLDETAILS_UNSIGNED)DeviceInfo->u.MixDetails.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 STATUS_INVALID_PARAMETER; + } + + Value = VolumeData->Values[Index]; + } + + /* set control details */ + if (bSet) + { + Status = SetGetControlDetails(DeviceObject, DeviceId, NodeId, DeviceInfo, bSet, KSPROPERTY_AUDIO_VOLUMELEVEL, 0, &Value); + Status = SetGetControlDetails(DeviceObject, DeviceId, NodeId, DeviceInfo, bSet, KSPROPERTY_AUDIO_VOLUMELEVEL, 1, &Value); + } + else + { + Status = SetGetControlDetails(DeviceObject, DeviceId, NodeId, DeviceInfo, bSet, KSPROPERTY_AUDIO_VOLUMELEVEL, Channel, &Value); + } + + if (!bSet) + { + for(Index = 0; Index < VolumeData->ValuesCount; Index++) + { + if (VolumeData->Values[Index] < Value) + { + /* FIXME SEH */ + Input->dwValue = VolumeData->InputSteppingDelta * Index; + return Status; + } + } + Input->dwValue = VolumeData->InputSteppingDelta * (VolumeData->ValuesCount-1); } - DPRINT("Status %x bSet %u NodeId %u Value %u\n", Status, bSet, NodeId, Value); return Status; } @@ -1879,7 +2069,7 @@ WdmAudSetControlDetails( PWDMAUD_DEVICE_EXTENSION DeviceExtension; NTSTATUS Status; - DPRINT1("cbStruct %u Expected %u dwControlID %u cChannels %u cMultipleItems %u cbDetails %u paDetails %p Flags %x\n", + DPRINT("cbStruct %u Expected %u dwControlID %u cChannels %u cMultipleItems %u cbDetails %u paDetails %p Flags %x\n", DeviceInfo->u.MixDetails.cbStruct, sizeof(MIXERCONTROLDETAILS), DeviceInfo->u.MixDetails.dwControlID, DeviceInfo->u.MixDetails.cChannels, DeviceInfo->u.MixDetails.cMultipleItems, DeviceInfo->u.MixDetails.cbDetails, DeviceInfo->u.MixDetails.paDetails, DeviceInfo->Flags); if (DeviceInfo->Flags & MIXER_GETCONTROLDETAILSF_LISTTEXT) @@ -1901,12 +2091,16 @@ WdmAudSetControlDetails( } Status = STATUS_NOT_IMPLEMENTED; + DPRINT("dwLineId %x dwControlID %x dwControlType %x\n", MixerLine->Line.dwLineID, MixerControl->dwControlID, MixerControl->dwControlType); if (MixerControl->dwControlType == MIXERCONTROL_CONTROLTYPE_MUTE) { /* send the request */ Status = SetGetMuteControlDetails(DeviceObject, MixerLine->DeviceIndex, NodeId, DeviceInfo, TRUE); } - + else if (MixerControl->dwControlType == MIXERCONTROL_CONTROLTYPE_VOLUME) + { + Status = SetGetVolumeControlDetails(DeviceObject, MixerLine->DeviceIndex, NodeId, DeviceInfo, TRUE, MixerControl, MixerLine); + } return SetIrpIoStatus(Irp, Status, sizeof(WDMAUD_DEVICE_INFO)); } @@ -1925,7 +2119,7 @@ WdmAudGetControlDetails( PWDMAUD_DEVICE_EXTENSION DeviceExtension; NTSTATUS Status; - DPRINT1("cbStruct %u Expected %u dwControlID %u cChannels %u cMultipleItems %u cbDetails %u paDetails %p Flags %x\n", + DPRINT("cbStruct %u Expected %u dwControlID %u cChannels %u cMultipleItems %u cbDetails %u paDetails %p Flags %x\n", DeviceInfo->u.MixDetails.cbStruct, sizeof(MIXERCONTROLDETAILS), DeviceInfo->u.MixDetails.dwControlID, DeviceInfo->u.MixDetails.cChannels, DeviceInfo->u.MixDetails.cMultipleItems, DeviceInfo->u.MixDetails.cbDetails, DeviceInfo->u.MixDetails.paDetails, DeviceInfo->Flags); if (DeviceInfo->Flags & MIXER_GETCONTROLDETAILSF_LISTTEXT) @@ -1952,6 +2146,10 @@ WdmAudGetControlDetails( /* send the request */ Status = SetGetMuteControlDetails(DeviceObject, MixerLine->DeviceIndex, NodeId, DeviceInfo, FALSE); } + else if (MixerControl->dwControlType == MIXERCONTROL_CONTROLTYPE_VOLUME) + { + Status = SetGetVolumeControlDetails(DeviceObject, MixerLine->DeviceIndex, NodeId, DeviceInfo, FALSE, MixerControl, MixerLine); + } return SetIrpIoStatus(Irp, Status, sizeof(WDMAUD_DEVICE_INFO)); diff --git a/reactos/drivers/wdm/audio/legacy/wdmaud/wdmaud.h b/reactos/drivers/wdm/audio/legacy/wdmaud/wdmaud.h index 6941dcb53dd..0b91e1541cf 100644 --- a/reactos/drivers/wdm/audio/legacy/wdmaud/wdmaud.h +++ b/reactos/drivers/wdm/audio/legacy/wdmaud/wdmaud.h @@ -33,6 +33,25 @@ typedef struct }WDMAUD_CLIENT, *PWDMAUD_CLIENT; +typedef struct +{ + LIST_ENTRY Entry; + ULONG dwControlID; +}MIXERCONTROL_DATA, *LPMIXERCONTROL_DATA; + +typedef struct +{ + MIXERCONTROL_DATA Header; + LONG SignedMinimum; + LONG SignedMaximum; + LONG SteppingDelta; + ULONG InputSteppingDelta; + ULONG ValuesCount; + PLONG Values; +}MIXERVOLUME_DATA, *LPMIXERVOLUME_DATA; + + + typedef struct { LIST_ENTRY Entry; @@ -41,6 +60,7 @@ typedef struct MIXERLINEW Line; LPMIXERCONTROLW LineControls; PULONG NodeIds; + LIST_ENTRY LineControlsExtraData; }MIXERLINE_EXT, *LPMIXERLINE_EXT; -- 2.17.1