WASAPI low latency audio compatibility
Created by: Zarkovian
Hi sonninnos,
Thank you for the continued work on the PUAE libretro implementation.
I'm trying to use RA's low latency audio driver "WASAPI" with PUAE but I can't get it to work without a lot of audio glitches and frame pacing issues.
The benefit of using WASAPI as the driver for audio is that it allows for audio latency <10ms, which would be a huge improvement over the currently working XAudio driver latency.
To replicate the issue, set "Drivers -> Audio" to wasapi. Then exit RA and restart. Then go to menu "Audio -> Output" which will now show the wasapi settings "Exclusive Mode", "Float format" and "Shared buffer length", this last setting is only showing when the setting "User Interface -> Show advanced settings" is enabled.
You will notice that PUAE will experience sound crackling and frame pacing issues with any setting. Note that you have to have Frame Delay setting OFF / set to "0" as wasapi mode is not compatible with it.
Some further information
I noticed many libretro cores have issues when the WASAPI driver is enabled, and only a few seem to actually be compatible with it. Like for example the beetle PC-Engine fast core. It seems to work without issues for me when enabling "Exclusive" and setting the latency to 3 or lower. The log reports 3ms (!) latency when setting the latency to "0" which makes it open the lowest possible driver allowed latency. Another one that seems to work properly is the mesen (NES) core.
The developer that implemented the WASAPI driver said the following when asked about issue with certain cores:
Most important stat’s are average input chunk lengths and average blocking times. If input data duration is shorter than device period (reported after client initialization) and intermediate buffer is off, there probably will be issues. The same goes for blocking periods that are longer than device period. Unfortunately audio driver can’t influence either of those two things.
I tested bsnes-mercury-balanced core and data chunks are too small (below 100 frames) while device period is 480 frames (in shared-mode on my machine). This is why WASAPI driver have problems with this core.
So it seems like a core needs to be properly "tuned" to work with the wasapi low latency audio driver?
Since we have a good reference with WinUAE, which has a working WASAPI implementation I searched for the github commits that implement the WASAPI changes for RA and for WinUAE. Maybe they can be of help.
WinUAE WASAPI implementation was updated with the 3.4.0 release in 2016, see this commit: WASAPI sound improvements.
In this I see some buffer related changes, and things like:
// magic adjustment sd->sndbufsize = sd->sndbufsize * 2 / 3;
RA's WASAPI implementation was done in 2017 with the 1.6.0 release. See the initial commit here: add wasapi audio driver
(single RA wasapi.c here: retroarch/audio/drivers/wasapi.c )
A quick glance over the commits I see in the WinUAE update things like;
// wasapi
IMMDevice *pDevice;
- IAudioClient *pAudioClient;
+ IAudioClient3 *pAudioClient;
Whereas in RA's wasapi commit I don't see any reference to changes from IAudioClient to IAudioClient3.
Which I understand from https://docs.microsoft.com/en-us/windows-hardware/drivers/audio/low-latency-audio, if you look further down the page under the header "Windows Audio Session API (WASAPI)" makes quite a difference.
So maybe this will be as simple as a buffer size change on the PUAE libretro core, but to be honest I doubt it. This of course has the potential to be a rabbithole very deep, since incompatiblity issues could stem from the core side, RA's wasapi implementation or the interaction between them. Nonetheless I hope it has your interest to look into the issue, as the benefit could potentially be a much reduced audio latency for the PUAE core.