From f371bfea810260f1a9329eda18783ca0986dfe9e Mon Sep 17 00:00:00 2001 From: Oleg Dubinskiy Date: Mon, 29 Apr 2024 15:46:07 +0200 Subject: [PATCH] [AUDIO] Implement retreiving audio playback position Implement GetWavePosition API for both Legacy and MMixer modes. [WDMAUD.DRV] - Fix wrong I/O control code passed to DeviceIoControl for Legacy mode. Use IOCTL_GETPOS instead of IOCTL_OPEN_WDMAUD, to use the correct routine. - Implement WdmAudGetWavePosition for MMixer mode, as it was completely unimplemented there. Call an appropiate MMixer routine and return back resulting wave position. [WDMAUD] - Implement WdmAudGetPostion routine, which is used by Legacy mode, and call the same MMixer routine from it too. - Handle it in IOCTL_GETPOS I/O control request of dispatch routine. [MMIXER] - Implement MMixerGetWavePosition internal routine, which is called by both Legacy and MMixer modes, and does the actual work of retrieving playback position. - Call an apporpriate KSPROPERTY_AUDIO_POSITION property from it, and return in the output resulting KSAUDIO_POSITION.PlayOffset member, which contains the current playback position offset, to be returned to the caller. This fixes a failure retreiving the current audio playback position snd subsequent playing the audio data by several 3rd-party applications which are using this API (for example, some Gecko based browsers by @roytam1: Basilisk (Serpent) 52.9.0 IA-32 build, NewMoon 28.10.7 IA-32 build and KMeleon 76.5.3 Goanna engine). CORE-19542 --- dll/win32/wdmaud.drv/legacy.c | 2 +- dll/win32/wdmaud.drv/mmixer.c | 28 +++++++++++++++- drivers/wdm/audio/legacy/wdmaud/control.c | 1 + drivers/wdm/audio/legacy/wdmaud/mmixer.c | 21 ++++++++++++ drivers/wdm/audio/legacy/wdmaud/wdmaud.h | 7 ++++ sdk/lib/drivers/sound/mmixer/mmixer.h | 6 ++++ sdk/lib/drivers/sound/mmixer/wave.c | 40 +++++++++++++++++++++++ 7 files changed, 103 insertions(+), 2 deletions(-) diff --git a/dll/win32/wdmaud.drv/legacy.c b/dll/win32/wdmaud.drv/legacy.c index f1ada7cdd3b95..95d38c3c43a80 100644 --- a/dll/win32/wdmaud.drv/legacy.c +++ b/dll/win32/wdmaud.drv/legacy.c @@ -832,7 +832,7 @@ WdmAudGetWavePositionByLegacy( DeviceInfo.DeviceType = DeviceType; Result = SyncOverlappedDeviceIoControl(KernelHandle, - IOCTL_OPEN_WDMAUD, + IOCTL_GETPOS, (LPVOID) &DeviceInfo, sizeof(WDMAUD_DEVICE_INFO), (LPVOID) &DeviceInfo, diff --git a/dll/win32/wdmaud.drv/mmixer.c b/dll/win32/wdmaud.drv/mmixer.c index 8fc2ed6309c9b..b114a57359bae 100644 --- a/dll/win32/wdmaud.drv/mmixer.c +++ b/dll/win32/wdmaud.drv/mmixer.c @@ -776,7 +776,33 @@ WdmAudGetWavePositionByMMixer( IN struct _SOUND_DEVICE_INSTANCE* SoundDeviceInstance, IN MMTIME* Time) { - /* FIXME */ + PSOUND_DEVICE SoundDevice; + MMDEVICE_TYPE DeviceType; + MIXER_STATUS Status; + MMRESULT Result; + DWORD Position; + + Result = GetSoundDeviceFromInstance(SoundDeviceInstance, &SoundDevice); + + if (!MMSUCCESS(Result)) + return TranslateInternalMmResult(Result); + + Result = GetSoundDeviceType(SoundDevice, &DeviceType); + SND_ASSERT(Result == MMSYSERR_NOERROR); + + if (DeviceType == WAVE_IN_DEVICE_TYPE || DeviceType == WAVE_OUT_DEVICE_TYPE) + { + Status = MMixerGetWavePosition(&MixerContext, SoundDeviceInstance->Handle, &Position); + if (Status == MM_STATUS_SUCCESS) + { + /* Store position */ + Time->wType = TIME_BYTES; + Time->u.cb = Position; + + /* Completed successfully */ + return MMSYSERR_NOERROR; + } + } return MMSYSERR_NOTSUPPORTED; } diff --git a/drivers/wdm/audio/legacy/wdmaud/control.c b/drivers/wdm/audio/legacy/wdmaud/control.c index f9ae9a323396b..5aecad326d086 100644 --- a/drivers/wdm/audio/legacy/wdmaud/control.c +++ b/drivers/wdm/audio/legacy/wdmaud/control.c @@ -366,6 +366,7 @@ WdmAudDeviceControl( case IOCTL_RESET_STREAM: return WdmAudResetStream(DeviceObject, Irp, DeviceInfo); case IOCTL_GETPOS: + return WdmAudGetPosition(DeviceObject, Irp, DeviceInfo); case IOCTL_GETDEVID: case IOCTL_GETVOLUME: case IOCTL_SETVOLUME: diff --git a/drivers/wdm/audio/legacy/wdmaud/mmixer.c b/drivers/wdm/audio/legacy/wdmaud/mmixer.c index dbf97ba56081d..d5e9fa847d101 100644 --- a/drivers/wdm/audio/legacy/wdmaud/mmixer.c +++ b/drivers/wdm/audio/legacy/wdmaud/mmixer.c @@ -769,6 +769,27 @@ WdmAudMidiCapabilities( return STATUS_UNSUCCESSFUL; } +NTSTATUS +NTAPI +WdmAudGetPosition( + _In_ PDEVICE_OBJECT DeviceObject, + _In_ PIRP Irp, + _In_ PWDMAUD_DEVICE_INFO DeviceInfo) +{ + MIXER_STATUS Status; + DWORD Position; + + /* get position */ + Status = MMixerGetWavePosition(&MixerContext, DeviceInfo->hDevice, &Position); + + DeviceInfo->u.Position = (ULONGLONG)Position; + + if (Status == MM_STATUS_SUCCESS) + return SetIrpIoStatus(Irp, STATUS_SUCCESS, sizeof(WDMAUD_DEVICE_INFO)); + else + return SetIrpIoStatus(Irp, STATUS_UNSUCCESSFUL, sizeof(WDMAUD_DEVICE_INFO)); +} + MIXER_STATUS CreatePinCallback( diff --git a/drivers/wdm/audio/legacy/wdmaud/wdmaud.h b/drivers/wdm/audio/legacy/wdmaud/wdmaud.h index 4c56a87e21ea8..12588f0a2a56d 100644 --- a/drivers/wdm/audio/legacy/wdmaud/wdmaud.h +++ b/drivers/wdm/audio/legacy/wdmaud/wdmaud.h @@ -198,6 +198,13 @@ WdmAudMidiCapabilities( IN PWDMAUD_CLIENT ClientInfo, IN PWDMAUD_DEVICE_EXTENSION DeviceExtension); +NTSTATUS +NTAPI +WdmAudGetPosition( + _In_ PDEVICE_OBJECT DeviceObject, + _In_ PIRP Irp, + _In_ PWDMAUD_DEVICE_INFO DeviceInfo); + NTSTATUS NTAPI WdmAudFrameSize( diff --git a/sdk/lib/drivers/sound/mmixer/mmixer.h b/sdk/lib/drivers/sound/mmixer/mmixer.h index 7d88125ce369b..5c728447c71ce 100644 --- a/sdk/lib/drivers/sound/mmixer/mmixer.h +++ b/sdk/lib/drivers/sound/mmixer/mmixer.h @@ -207,6 +207,12 @@ MMixerOpenWave( IN PVOID Context, OUT PHANDLE PinHandle); +MIXER_STATUS +MMixerGetWavePosition( + _In_ PMIXER_CONTEXT MixerContext, + _In_ HANDLE PinHandle, + _Out_ DWORD * Position); + MIXER_STATUS MMixerSetWaveStatus( IN PMIXER_CONTEXT MixerContext, diff --git a/sdk/lib/drivers/sound/mmixer/wave.c b/sdk/lib/drivers/sound/mmixer/wave.c index cdf9a78d92f46..e929efababf43 100644 --- a/sdk/lib/drivers/sound/mmixer/wave.c +++ b/sdk/lib/drivers/sound/mmixer/wave.c @@ -614,6 +614,46 @@ MMixerGetWaveOutCount( return MixerList->WaveOutListCount; } +MIXER_STATUS +MMixerGetWavePosition( + _In_ PMIXER_CONTEXT MixerContext, + _In_ HANDLE PinHandle, + _Out_ DWORD * Position) +{ + KSAUDIO_POSITION AudioPosition; + KSPROPERTY Property; + MIXER_STATUS Status; + ULONG Length; + + /* verify mixer context */ + Status = MMixerVerifyContext(MixerContext); + + if (Status != MM_STATUS_SUCCESS) + { + /* invalid context passed */ + return Status; + } + + Property.Id = KSPROPERTY_AUDIO_POSITION; + Property.Set = KSPROPSETID_Audio; + Property.Flags = KSPROPERTY_TYPE_GET; + + Status = MixerContext->Control(PinHandle, IOCTL_KS_PROPERTY, &Property, sizeof(KSPROPERTY), &AudioPosition, sizeof(KSAUDIO_POSITION), &Length); + + if (Status == MM_STATUS_SUCCESS) + { + /* store audio position */ + *Position = (DWORD)AudioPosition.PlayOffset; + } + else + { + /* failed */ + *Position = 0; + } + + return Status; +} + MIXER_STATUS MMixerSetWaveStatus( IN PMIXER_CONTEXT MixerContext,