From 9046cc97ee3f492d2f4e857638e6b23c6c5a001f Mon Sep 17 00:00:00 2001 From: Oleg Dubinskiy Date: Sat, 1 Jun 2024 12:30:33 +0200 Subject: [PATCH] [AUDIO] Implement volume control support (#6922) Implement volume level changing for Aux/MidiOut/WaveOut devices. It's represented the following WINMM functions: - auxGetVolume, - auxSetVolume, - midiOutGetVolume, - midiOutSetVolume, - waveOutGetVolume, - waveOutSetVolume, which are calling the followind messages appropriately: - AUXDM_GETVOLUME, - AUXDM_SETVOLUME, - MODM_GETVOLUME, - MODM_SETVOLUME, - WODM_GETVOLUME, - WODM_SETVOLUME. This fixes volume control for several 3rd-party programs (like Fox Audio Player 0.10.2 from Rapps, Winamp 2.95 with WaveOut plugin). However it does not fix changing the volume in system volume mixers (SndVol32, MMSys), since they are using their own functionality instead. They technically do the same things, but apart from the functions mentioned above. CORE-14780 --- dll/win32/wdmaud.drv/legacy.c | 19 +++ dll/win32/wdmaud.drv/mmixer.c | 115 ++++++++++++++++++ dll/win32/wdmaud.drv/wdmaud.c | 6 + dll/win32/wdmaud.drv/wdmaud.h | 24 ++++ sdk/include/reactos/libs/sound/mmebuddy.h | 27 ++++ .../sound/mmebuddy/auxiliary/auxMessage.c | 18 +++ .../drivers/sound/mmebuddy/midi/modMessage.c | 17 +++ sdk/lib/drivers/sound/mmebuddy/mmewrap.c | 79 ++++++++++++ .../drivers/sound/mmebuddy/wave/wodMessage.c | 18 +++ 9 files changed, 323 insertions(+) diff --git a/dll/win32/wdmaud.drv/legacy.c b/dll/win32/wdmaud.drv/legacy.c index 95d38c3c43a..5a8763d5f3c 100644 --- a/dll/win32/wdmaud.drv/legacy.c +++ b/dll/win32/wdmaud.drv/legacy.c @@ -850,6 +850,25 @@ WdmAudGetWavePositionByLegacy( return MMSYSERR_NOERROR; } +MMRESULT +WdmAudGetVolumeByLegacy( + _In_ PSOUND_DEVICE_INSTANCE SoundDeviceInstance, + _In_ DWORD DeviceId, + _Out_ PDWORD pdwVolume) +{ + /* FIXME */ + return MMSYSERR_NOTSUPPORTED; +} + +MMRESULT +WdmAudSetVolumeByLegacy( + _In_ PSOUND_DEVICE_INSTANCE SoundDeviceInstance, + _In_ DWORD DeviceId, + _In_ DWORD dwVolume) +{ + /* FIXME */ + return MMSYSERR_NOTSUPPORTED; +} MMRESULT WdmAudResetStreamByLegacy( diff --git a/dll/win32/wdmaud.drv/mmixer.c b/dll/win32/wdmaud.drv/mmixer.c index 3b032531026..f4f0fbd09ef 100644 --- a/dll/win32/wdmaud.drv/mmixer.c +++ b/dll/win32/wdmaud.drv/mmixer.c @@ -805,6 +805,121 @@ WdmAudGetWavePositionByMMixer( return MMSYSERR_NOTSUPPORTED; } +MMRESULT +WdmAudGetVolumeByMMixer( + _In_ PSOUND_DEVICE_INSTANCE SoundDeviceInstance, + _In_ DWORD DeviceId, + _Out_ PDWORD pdwVolume) +{ + MMRESULT Result; + MIXERLINE MixLine; + MIXERCONTROL MixControl; + MIXERLINECONTROLS MixLineControls; + MIXERCONTROLDETAILS MixControlDetails; + MIXERCONTROLDETAILS_UNSIGNED MixControlDetailsU[2]; // For 2 (stereo) channels + + MixLine.cbStruct = sizeof(MixLine); + MixLine.dwComponentType = MIXERLINE_COMPONENTTYPE_DST_SPEAKERS; + + /* Get line info */ + Result = WdmAudGetLineInfo(SoundDeviceInstance->Handle, + DeviceId, + &MixLine, + MIXER_OBJECTF_MIXER | MIXER_GETLINEINFOF_COMPONENTTYPE); + if (!MMSUCCESS(Result)) + return TranslateInternalMmResult(Result); + + MixLineControls.cbStruct = sizeof(MixLineControls); + MixLineControls.dwLineID = MixLine.dwLineID; + MixLineControls.dwControlType = MIXERCONTROL_CONTROLTYPE_VOLUME; + MixLineControls.cControls = 1; + MixLineControls.cbmxctrl = sizeof(MixControl); + MixLineControls.pamxctrl = &MixControl; + + /* Get line controls */ + Result = WdmAudGetLineControls(SoundDeviceInstance->Handle, + DeviceId, + &MixLineControls, + MIXER_OBJECTF_MIXER | MIXER_GETLINECONTROLSF_ONEBYTYPE); + if (!MMSUCCESS(Result)) + return TranslateInternalMmResult(Result); + + MixControlDetails.cbStruct = sizeof(MixControlDetails); + MixControlDetails.dwControlID = MixControl.dwControlID; + MixControlDetails.cChannels = MixLine.cChannels; + MixControlDetails.cMultipleItems = 0; + MixControlDetails.cbDetails = sizeof(MIXERCONTROLDETAILS_UNSIGNED); + MixControlDetails.paDetails = MixControlDetailsU; + + /* Get volume control details */ + Result = WdmAudGetControlDetails(SoundDeviceInstance->Handle, + DeviceId, + &MixControlDetails, + MIXER_OBJECTF_MIXER); + if (MMSUCCESS(Result)) + *pdwVolume = MAKELONG(LOWORD(MixControlDetailsU[0].dwValue), HIWORD(MixControlDetailsU[1].dwValue)); + + return Result; +} + +MMRESULT +WdmAudSetVolumeByMMixer( + _In_ PSOUND_DEVICE_INSTANCE SoundDeviceInstance, + _In_ DWORD DeviceId, + _In_ DWORD dwVolume) +{ + MMRESULT Result; + MIXERLINE MixLine; + MIXERCONTROL MixControl; + MIXERLINECONTROLS MixLineControls; + MIXERCONTROLDETAILS MixControlDetails; + MIXERCONTROLDETAILS_UNSIGNED MixControlDetailsU[2]; // For 2 (stereo) channels + + MixLine.cbStruct = sizeof(MixLine); + MixLine.dwComponentType = MIXERLINE_COMPONENTTYPE_DST_SPEAKERS; + + /* Get line info */ + Result = WdmAudGetLineInfo(SoundDeviceInstance->Handle, + DeviceId, + &MixLine, + MIXER_OBJECTF_MIXER | MIXER_GETLINEINFOF_COMPONENTTYPE); + if (!MMSUCCESS(Result)) + return TranslateInternalMmResult(Result); + + MixLineControls.cbStruct = sizeof(MixLineControls); + MixLineControls.dwLineID = MixLine.dwLineID; + MixLineControls.dwControlType = MIXERCONTROL_CONTROLTYPE_VOLUME; + MixLineControls.cControls = 1; + MixLineControls.cbmxctrl = sizeof(MixControl); + MixLineControls.pamxctrl = &MixControl; + + /* Get line controls */ + Result = WdmAudGetLineControls(SoundDeviceInstance->Handle, + DeviceId, + &MixLineControls, + MIXER_OBJECTF_MIXER | MIXER_GETLINECONTROLSF_ONEBYTYPE); + if (!MMSUCCESS(Result)) + return TranslateInternalMmResult(Result); + + /* Convert volume level to be set */ + MixControlDetailsU[0].dwValue = LOWORD(dwVolume); // Left channel + MixControlDetailsU[1].dwValue = HIWORD(dwVolume); // Right channel + + MixControlDetails.cbStruct = sizeof(MixControlDetails); + MixControlDetails.dwControlID = MixControl.dwControlID; + MixControlDetails.cChannels = MixLine.cChannels; + MixControlDetails.cMultipleItems = 0; + MixControlDetails.cbDetails = sizeof(MIXERCONTROLDETAILS_UNSIGNED); + MixControlDetails.paDetails = MixControlDetailsU; + + /* Set volume control details */ + Result = WdmAudSetControlDetails(SoundDeviceInstance->Handle, + DeviceId, + &MixControlDetails, + MIXER_OBJECTF_MIXER); + return Result; +} + static VOID WINAPI CommitWaveBufferApc(PVOID ApcContext, diff --git a/dll/win32/wdmaud.drv/wdmaud.c b/dll/win32/wdmaud.drv/wdmaud.c index 45308b3aff2..6b8561f19f3 100644 --- a/dll/win32/wdmaud.drv/wdmaud.c +++ b/dll/win32/wdmaud.drv/wdmaud.c @@ -76,6 +76,12 @@ PopulateWdmDeviceList( FuncTable.Close = FUNC_NAME(WdmAudCloseSoundDevice); FuncTable.GetDeviceInterfaceString = FUNC_NAME(WdmAudGetDeviceInterfaceString); + if (DeviceType == AUX_DEVICE_TYPE || DeviceType == MIDI_OUT_DEVICE_TYPE || DeviceType == WAVE_OUT_DEVICE_TYPE) + { + FuncTable.GetVolume = FUNC_NAME(WdmAudGetVolume); + FuncTable.SetVolume = FUNC_NAME(WdmAudSetVolume); + } + if (DeviceType == MIXER_DEVICE_TYPE) { FuncTable.SetWaveFormat = FUNC_NAME(WdmAudSetMixerDeviceFormat); diff --git a/dll/win32/wdmaud.drv/wdmaud.h b/dll/win32/wdmaud.drv/wdmaud.h index d3900b3adfa..dee7f2058eb 100644 --- a/dll/win32/wdmaud.drv/wdmaud.h +++ b/dll/win32/wdmaud.drv/wdmaud.h @@ -144,6 +144,18 @@ WdmAudGetWavePositionByMMixer( IN struct _SOUND_DEVICE_INSTANCE* SoundDeviceInstance, IN MMTIME* Time); +MMRESULT +WdmAudGetVolumeByMMixer( + _In_ PSOUND_DEVICE_INSTANCE SoundDeviceInstance, + _In_ DWORD DeviceId, + _Out_ PDWORD pdwVolume); + +MMRESULT +WdmAudSetVolumeByMMixer( + _In_ PSOUND_DEVICE_INSTANCE SoundDeviceInstance, + _In_ DWORD DeviceId, + _In_ DWORD dwVolume); + MMRESULT WdmAudCommitWaveBufferByMMixer( IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance, @@ -224,6 +236,18 @@ WdmAudGetWavePositionByLegacy( IN struct _SOUND_DEVICE_INSTANCE* SoundDeviceInstance, IN MMTIME* Time); +MMRESULT +WdmAudGetVolumeByLegacy( + _In_ PSOUND_DEVICE_INSTANCE SoundDeviceInstance, + _In_ DWORD DeviceId, + _Out_ PDWORD pdwVolume); + +MMRESULT +WdmAudSetVolumeByLegacy( + _In_ PSOUND_DEVICE_INSTANCE SoundDeviceInstance, + _In_ DWORD DeviceId, + _In_ DWORD dwVolume); + MMRESULT WriteFileEx_Committer2( IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance, diff --git a/sdk/include/reactos/libs/sound/mmebuddy.h b/sdk/include/reactos/libs/sound/mmebuddy.h index 4056621b181..e8775b1f7f1 100644 --- a/sdk/include/reactos/libs/sound/mmebuddy.h +++ b/sdk/include/reactos/libs/sound/mmebuddy.h @@ -190,6 +190,16 @@ typedef MMRESULT(*MMRESETSTREAM_FUNC)( IN MMDEVICE_TYPE DeviceType, IN BOOLEAN bStartReset); +typedef MMRESULT(*MMGETVOLUME_FUNC)( + _In_ struct _SOUND_DEVICE_INSTANCE* SoundDeviceInstance, + _In_ DWORD DeviceId, + _Out_ PDWORD pdwVolume); + +typedef MMRESULT(*MMSETVOLUME_FUNC)( + _In_ struct _SOUND_DEVICE_INSTANCE* SoundDeviceInstance, + _In_ DWORD DeviceId, + _In_ DWORD dwVolume); + typedef struct _MMFUNCTION_TABLE { union @@ -216,6 +226,9 @@ typedef struct _MMFUNCTION_TABLE MMQUERYDEVICEINTERFACESTRING_FUNC GetDeviceInterfaceString; MMRESETSTREAM_FUNC ResetStream; + MMGETVOLUME_FUNC GetVolume; + MMSETVOLUME_FUNC SetVolume; + // Redundant //MMWAVEHEADER_FUNC PrepareWaveHeader; //MMWAVEHEADER_FUNC UnprepareWaveHeader; @@ -369,6 +382,20 @@ MmeGetPosition( IN MMTIME* Time, IN DWORD Size); +MMRESULT +MmeGetVolume( + _In_ MMDEVICE_TYPE DeviceType, + _In_ DWORD DeviceId, + _In_ DWORD_PTR PrivateHandle, + _Out_ DWORD_PTR pdwVolume); + +MMRESULT +MmeSetVolume( + _In_ MMDEVICE_TYPE DeviceType, + _In_ DWORD DeviceId, + _In_ DWORD_PTR PrivateHandle, + _In_ DWORD_PTR dwVolume); + MMRESULT MmeGetDeviceInterfaceString( IN MMDEVICE_TYPE DeviceType, diff --git a/sdk/lib/drivers/sound/mmebuddy/auxiliary/auxMessage.c b/sdk/lib/drivers/sound/mmebuddy/auxiliary/auxMessage.c index 6a164de0c8b..db33696ad5a 100644 --- a/sdk/lib/drivers/sound/mmebuddy/auxiliary/auxMessage.c +++ b/sdk/lib/drivers/sound/mmebuddy/auxiliary/auxMessage.c @@ -45,6 +45,24 @@ auxMessage( Parameter2); break; } + + case AUXDM_GETVOLUME: + { + Result = MmeGetVolume(AUX_DEVICE_TYPE, + DeviceId, + PrivateHandle, + Parameter1); + break; + } + + case AUXDM_SETVOLUME: + { + Result = MmeSetVolume(AUX_DEVICE_TYPE, + DeviceId, + PrivateHandle, + Parameter1); + break; + } } SND_TRACE(L"auxMessage returning MMRESULT %d\n", Result); diff --git a/sdk/lib/drivers/sound/mmebuddy/midi/modMessage.c b/sdk/lib/drivers/sound/mmebuddy/midi/modMessage.c index e6c09004a5b..7a50f04c3f0 100644 --- a/sdk/lib/drivers/sound/mmebuddy/midi/modMessage.c +++ b/sdk/lib/drivers/sound/mmebuddy/midi/modMessage.c @@ -75,6 +75,23 @@ modMessage( break; } + case MODM_GETVOLUME: + { + Result = MmeGetVolume(MIDI_OUT_DEVICE_TYPE, + DeviceId, + PrivateHandle, + Parameter1); + break; + } + + case MODM_SETVOLUME: + { + Result = MmeSetVolume(MIDI_OUT_DEVICE_TYPE, + DeviceId, + PrivateHandle, + Parameter1); + break; + } } SND_TRACE(L"modMessage returning MMRESULT %d\n", Result); diff --git a/sdk/lib/drivers/sound/mmebuddy/mmewrap.c b/sdk/lib/drivers/sound/mmebuddy/mmewrap.c index 186b69a0c5e..6a2df3343c6 100644 --- a/sdk/lib/drivers/sound/mmebuddy/mmewrap.c +++ b/sdk/lib/drivers/sound/mmebuddy/mmewrap.c @@ -365,3 +365,82 @@ MmeGetPosition( return Result; } +MMRESULT +MmeGetVolume( + _In_ MMDEVICE_TYPE DeviceType, + _In_ DWORD DeviceId, + _In_ DWORD_PTR PrivateHandle, + _Out_ DWORD_PTR pdwVolume) +{ + MMRESULT Result; + PSOUND_DEVICE_INSTANCE SoundDeviceInstance; + PSOUND_DEVICE SoundDevice; + PMMFUNCTION_TABLE FunctionTable; + + /* Sanity check */ + SND_ASSERT(DeviceType == AUX_DEVICE_TYPE || + DeviceType == MIDI_OUT_DEVICE_TYPE || + DeviceType == WAVE_OUT_DEVICE_TYPE); + + VALIDATE_MMSYS_PARAMETER(PrivateHandle); + SoundDeviceInstance = (PSOUND_DEVICE_INSTANCE)PrivateHandle; + + if (!IsValidSoundDeviceInstance(SoundDeviceInstance)) + return MMSYSERR_INVALHANDLE; + + Result = GetSoundDeviceFromInstance(SoundDeviceInstance, &SoundDevice); + if (!MMSUCCESS(Result)) + return TranslateInternalMmResult(Result); + + Result = GetSoundDeviceFunctionTable(SoundDevice, &FunctionTable); + if (!MMSUCCESS(Result)) + return TranslateInternalMmResult(Result); + + if (!FunctionTable->GetVolume) + return MMSYSERR_NOTSUPPORTED; + + /* Call the driver */ + Result = FunctionTable->GetVolume(SoundDeviceInstance, DeviceId, (PDWORD)pdwVolume); + + return Result; +} + +MMRESULT +MmeSetVolume( + _In_ MMDEVICE_TYPE DeviceType, + _In_ DWORD DeviceId, + _In_ DWORD_PTR PrivateHandle, + _In_ DWORD_PTR dwVolume) +{ + MMRESULT Result; + PSOUND_DEVICE_INSTANCE SoundDeviceInstance; + PSOUND_DEVICE SoundDevice; + PMMFUNCTION_TABLE FunctionTable; + + /* Sanity check */ + SND_ASSERT(DeviceType == AUX_DEVICE_TYPE || + DeviceType == MIDI_OUT_DEVICE_TYPE || + DeviceType == WAVE_OUT_DEVICE_TYPE); + + VALIDATE_MMSYS_PARAMETER(PrivateHandle); + SoundDeviceInstance = (PSOUND_DEVICE_INSTANCE)PrivateHandle; + + if (!IsValidSoundDeviceInstance(SoundDeviceInstance)) + return MMSYSERR_INVALHANDLE; + + Result = GetSoundDeviceFromInstance(SoundDeviceInstance, &SoundDevice); + if (!MMSUCCESS(Result)) + return TranslateInternalMmResult(Result); + + Result = GetSoundDeviceFunctionTable(SoundDevice, &FunctionTable); + if (!MMSUCCESS(Result)) + return TranslateInternalMmResult(Result); + + if (!FunctionTable->SetVolume) + return MMSYSERR_NOTSUPPORTED; + + /* Call the driver */ + Result = FunctionTable->SetVolume(SoundDeviceInstance, DeviceId, (DWORD)dwVolume); + + return Result; +} diff --git a/sdk/lib/drivers/sound/mmebuddy/wave/wodMessage.c b/sdk/lib/drivers/sound/mmebuddy/wave/wodMessage.c index e73bdf0ecc8..8af0dc67283 100644 --- a/sdk/lib/drivers/sound/mmebuddy/wave/wodMessage.c +++ b/sdk/lib/drivers/sound/mmebuddy/wave/wodMessage.c @@ -118,6 +118,24 @@ wodMessage( break; } + case WODM_GETVOLUME: + { + Result = MmeGetVolume(WAVE_OUT_DEVICE_TYPE, + DeviceId, + PrivateHandle, + Parameter1); + break; + } + + case WODM_SETVOLUME: + { + Result = MmeSetVolume(WAVE_OUT_DEVICE_TYPE, + DeviceId, + PrivateHandle, + Parameter1); + break; + } + case DRV_QUERYDEVICEINTERFACESIZE : { Result = MmeGetDeviceInterfaceString(WAVE_OUT_DEVICE_TYPE, DeviceId, NULL, 0, (DWORD*)Parameter1); //FIXME DWORD_PTR