Skip to content

Commit

Permalink
[AUDIO] Implement volume control support
Browse files Browse the repository at this point in the history
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 techically do the same things, but apart from the functions mentioned above.
CORE-14780
  • Loading branch information
oleg-dubinskiy committed May 22, 2024
1 parent a549a9d commit 4c26939
Show file tree
Hide file tree
Showing 9 changed files with 325 additions and 0 deletions.
19 changes: 19 additions & 0 deletions dll/win32/wdmaud.drv/legacy.c
Original file line number Diff line number Diff line change
Expand Up @@ -850,6 +850,25 @@ WdmAudGetWavePositionByLegacy(
return MMSYSERR_NOERROR;
}

MMRESULT
WdmAudGetVolumeByLegacy(
_In_ struct _SOUND_DEVICE_INSTANCE* SoundDeviceInstance,
_In_ DWORD DeviceId,
_Out_ PDWORD pdwVolume)
{
/* FIXME */
return MMSYSERR_NOTSUPPORTED;
}

MMRESULT
WdmAudSetVolumeByLegacy(
_In_ struct _SOUND_DEVICE_INSTANCE* SoundDeviceInstance,
_In_ DWORD DeviceId,
_In_ DWORD dwVolume)
{
/* FIXME */
return MMSYSERR_NOTSUPPORTED;
}

MMRESULT
WdmAudResetStreamByLegacy(
Expand Down
117 changes: 117 additions & 0 deletions dll/win32/wdmaud.drv/mmixer.c
Original file line number Diff line number Diff line change
Expand Up @@ -805,6 +805,123 @@ WdmAudGetWavePositionByMMixer(
return MMSYSERR_NOTSUPPORTED;
}

MMRESULT
WdmAudGetVolumeByMMixer(
_In_ struct _SOUND_DEVICE_INSTANCE* SoundDeviceInstance,
_In_ DWORD DeviceId,
_Out_ PDWORD pdwVolume)
{
MMRESULT Result;
MIXERLINE MixLine;
MIXERCONTROL MixControl;
MIXERLINECONTROLS MixLineControls;
MIXERCONTROLDETAILS MixControlDetails;
MIXERCONTROLDETAILS_UNSIGNED MixControlDetailsU[2];

MixLine.cbStruct = sizeof(MIXERLINE);
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(MIXERLINECONTROLS);
MixLineControls.dwLineID = MixLine.dwLineID;
MixLineControls.dwControlType = MIXERCONTROL_CONTROLTYPE_VOLUME;
MixLineControls.cControls = 1;
MixLineControls.cbmxctrl = sizeof(MIXERCONTROL);
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(MIXERCONTROLDETAILS);
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_ struct _SOUND_DEVICE_INSTANCE* SoundDeviceInstance,
_In_ DWORD DeviceId,
_In_ DWORD dwVolume)
{
MMRESULT Result;
MIXERLINE MixLine;
MIXERCONTROL MixControl;
MIXERLINECONTROLS MixLineControls;
MIXERCONTROLDETAILS MixControlDetails;
MIXERCONTROLDETAILS_UNSIGNED MixControlDetailsU[2];

MixLine.cbStruct = sizeof(MIXERLINE);
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(MIXERLINECONTROLS);
MixLineControls.dwLineID = MixLine.dwLineID;
MixLineControls.dwControlType = MIXERCONTROL_CONTROLTYPE_VOLUME;
MixLineControls.cControls = 1;
MixLineControls.cbmxctrl = sizeof(MIXERCONTROL);
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(MIXERCONTROLDETAILS);
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,
Expand Down
6 changes: 6 additions & 0 deletions dll/win32/wdmaud.drv/wdmaud.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
24 changes: 24 additions & 0 deletions dll/win32/wdmaud.drv/wdmaud.h
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,18 @@ WdmAudGetWavePositionByMMixer(
IN struct _SOUND_DEVICE_INSTANCE* SoundDeviceInstance,
IN MMTIME* Time);

MMRESULT
WdmAudGetVolumeByMMixer(
_In_ struct _SOUND_DEVICE_INSTANCE* SoundDeviceInstance,
_In_ DWORD DeviceId,
_Out_ PDWORD pdwVolume);

MMRESULT
WdmAudSetVolumeByMMixer(
_In_ struct _SOUND_DEVICE_INSTANCE* SoundDeviceInstance,
_In_ DWORD DeviceId,
_In_ DWORD dwVolume);

MMRESULT
WdmAudCommitWaveBufferByMMixer(
IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance,
Expand Down Expand Up @@ -224,6 +236,18 @@ WdmAudGetWavePositionByLegacy(
IN struct _SOUND_DEVICE_INSTANCE* SoundDeviceInstance,
IN MMTIME* Time);

MMRESULT
WdmAudGetVolumeByLegacy(
_In_ struct _SOUND_DEVICE_INSTANCE* SoundDeviceInstance,
_In_ DWORD DeviceId,
_Out_ PDWORD pdwVolume);

MMRESULT
WdmAudSetVolumeByLegacy(
_In_ struct _SOUND_DEVICE_INSTANCE* SoundDeviceInstance,
_In_ DWORD DeviceId,
_In_ DWORD dwVolume);

MMRESULT
WriteFileEx_Committer2(
IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance,
Expand Down
27 changes: 27 additions & 0 deletions sdk/include/reactos/libs/sound/mmebuddy.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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;
Expand Down Expand Up @@ -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_ PDWORD_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,
Expand Down
18 changes: 18 additions & 0 deletions sdk/lib/drivers/sound/mmebuddy/auxiliary/auxMessage.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
17 changes: 17 additions & 0 deletions sdk/lib/drivers/sound/mmebuddy/midi/modMessage.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
79 changes: 79 additions & 0 deletions sdk/lib/drivers/sound/mmebuddy/mmewrap.c
Original file line number Diff line number Diff line change
Expand Up @@ -365,3 +365,82 @@ MmeGetPosition(
return Result;
}

MMRESULT
MmeGetVolume(
_In_ MMDEVICE_TYPE DeviceType,
_In_ DWORD DeviceId,
_In_ DWORD_PTR PrivateHandle,
_Out_ PDWORD_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;
}
Loading

0 comments on commit 4c26939

Please sign in to comment.