libretro / RetroArch

Cross-platform, sophisticated frontend for the libretro API. Licensed GPLv3.
http://www.libretro.com
GNU General Public License v3.0
10.15k stars 1.82k forks source link

Implementing WASAPI Audio driver in Windows #2771

Closed Ryunam closed 6 years ago

Ryunam commented 8 years ago

Further to this thread on the libretro boards: http://libretro.com/forums/showthread.php?t=5206

I'm inquiring about the possible implementation of a WASAPI audio driver for Windows builds of Retroarch. This kind of solution is very popular in both audio playback and production and it would provide the following benefits:

--- Want to back this issue? **[Post a bounty on it!](https://www.bountysource.com/issues/31558403-implementing-wasapi-audio-driver-in-windows?utm_campaign=plugin&utm_content=tracker%2F296058&utm_medium=issues&utm_source=github)** We accept bounties via [Bountysource](https://www.bountysource.com/?utm_campaign=plugin&utm_content=tracker%2F296058&utm_medium=issues&utm_source=github).
Ryunam commented 8 years ago

Has there been any progress concerning the request at hand? I would like to add that the original thread on the libretro boards included a reference by hunterk to the potential implementation of JACK on Windows, as a more viable alternative which I understand would yield similar results in terms of low-latency audio. Thank you in advance, any update on such a possibility is of course much appreciated.

Themaister commented 8 years ago

I don't think any of the main contributors use Windows as their main platform, so I think this is a case of "PRs welcome".

Ryunam commented 8 years ago

I definitely understand. Unfortunately I am no programmer, so I remain hopeful that someone else may intervene and create an option for this.

Having low-latency audio greatly contributes to an overall perception of responsiveness and, especially in the case of the very laggy SNES cores, it could benefit many players who are staying with the Windows platform for one reason or another.

I have checked and it seems that JACK now supports Windows x64. Since hunterk mentioned it as being most likely the "path of least resistance" and it seems to be implemented already on Retroarch's Linux builds, I wonder if that may be effectively considered more viable for this purpose.

Thank you, once again.

ghost commented 7 years ago

I have done some work on this. Source code. Precompiled binaries.

Ryunam commented 7 years ago

Wow, thanks a lot for your work! I will definitely take a look and test this thoroughly once I get back home later today. Just one question: does the WASAPI implementation you have coded work in Exclusive mode?

ghost commented 7 years ago

Yes, if it is available, otherwise falls back to shared mode. Similarly first tries float format then falls back to PCM format. Currently audio sync is always on (regardless of settings), and in shared mode latency is fixed (value is chosen by WASAPI audio engine). On my machine performs better in exclusive mode and with smaller latencies. And just to be clear, I did minimal testing so far, so be aware of that.

Ryunam commented 7 years ago

Is there an indication displayed (like an OSD notification) that the driver is working in either exclusive or shared mode?

ghost commented 7 years ago

Only in the log window (you have to enable logging to see it). If you did not disabled exclusive mode option in playback device properties (global Windows settings), you can safely assume that driver works in exclusive mode.

ghost commented 7 years ago

I forgot to mention one more scenario when exclusive mode is not available, and that is when another application already using the same audio device in exclusive mode.

Ryunam commented 7 years ago

I had the chance to briefly test your implementation based on the latest code, which I also see has been integrated into the Retroarch main repository. Here are my observations so far:

Thanks a lot for your efforts so far. Highly looking forward to seeing some improvements that could hopefully make this driver the ideal choice for Windows RA users.

ghost commented 7 years ago

If this is your device than exclusive float mode is not supported. Look at log, "...[WASAPI]: IAudioClient::Initialize failed with error 0x88890008" will confirm that. Exclusive float mode is probably not supported by majority of audio devices.

I will download those cores and try to find out what's going on. In the meantime try to lower latency as low as you want (0 is valid value). To find out actual latency you get, you will have to look at log window and search for something like "...[WASAPI]: Client initialized (max latency 20.0ms)."

Also, you can try shared mode by disabling exclusive mode in Windows playback device properties dialog. In shared mode you should get float support, but max latency will be fixed.

ghost commented 7 years ago

And for the fast-forwarding, I will look that too (I did not tested that at all).

ghost commented 7 years ago

I tested Nestopia and all three bsnes-mercury cores. Tests are done with this binaries. Tested on x86 Win7 SP1 and x64 Win10. Mode exclusive, format PCM, frame rate 48000Hz, max latency 4ms - 64ms.

In all cases audio was normal, no issues at all. I did not test fast-forwarding because I don't know how to use that feature (I tried). This will probably need more test on different machines, so it will be helpful if more people test this.

Post a log output If contains any WASAPI error(s).

hizzlekizzle commented 7 years ago

Fast-forward just means with vsync and audio sync disabled, so it can run as fast as possible. The default mapping to toggle vsync is with the spacebar.

Monroe88 commented 7 years ago

Nice work on this driver. :)

Unfortunately, it doesn't work at all on my hardware at the moment. I used both the x86 and x86_64 builds from the buildbot's current nightly builds and in both cases, RetroArch hangs during the core's initialization after loading content, which requires killing retroarch.exe in Task Manager to exit.

If I set audio_out_rate to something lower than 44100Hz, then the core will load but there will be no audio.

I'm running on Windows 7 x64, with an onboard Realtek HD Audio chipset.

Log when running with 48000Hz: https://hastebin.com/raw/xoyucejohe

Log when running less than 44100Hz: https://hastebin.com/raw/ivodakulaz

I'll try to get something from the debug exe with gdb later.

ghost commented 7 years ago

Currently driver has audio sync always on. This means that fast-forward operation in combination with WASAPI driver is, in programming terms, undefined behavior. I did coded driver that supported audio sync off option, but didn't worked correctly in that mode so I removed that part of code. I think it is better to put that feature on hold until most of as confirm that current implementation works correctly (with everything that don't depends on audio sync off option).

@Monroe88 First log says that WASAPI driver is successfully initialized. Second one shows unsupported format errors. This is probably because the frame rate was set to 32000Hz. Driver don't impose any restrictions on frame rate value, neither tries to adjust it, so don't try random values there (I suggest to leave it at default value of 48000Hz). Are you absolutely sure that WASAPI driver is causing these problems? Can you confirm that other audio drivers working correctly on your system?

ghost commented 7 years ago

wasapi drivers seems to be locked to use 48000 hz only. setting my system audio settings to anything lower than 48000hz will not initialize audio when running retroarch, but other audio devices can still play. tried other wasapi-capable emulator and i can choose there 41000hz

On Wed, Apr 12, 2017 at 5:23 PM, Zoran Vuckovic notifications@github.com wrote:

Currently driver have audio sync always on. This means that fast-forward operation in combination with WASAPI driver is, in programming terms, undefined behavior. I did coded driver that supported audio sync off option, but didn't worked correctly in that mode so I removed that part of code. I think it is better to put that feature on hold until most of as confirm that current implementation works correctly (with everything that don't depends on audio sync off option).

@Monroe88 https://github.com/Monroe88 First log says that WASAPI driver is successfully initialized. Second one shows unsupported format errors. This is probably because the frame rate was set to 32000Hz. Driver don't impose any restrictions on frame rate value, neither tries to adjust it, so don't try random values there (I suggest to leave it at default value of 48000Hz). Are you absolutely sure that WASAPI driver is causing these problems? Can you confirm that other audio drivers working correctly on your system?

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/libretro/RetroArch/issues/2771#issuecomment-293522456, or mute the thread https://github.com/notifications/unsubscribe-auth/AWPDtuZj69eMxQGwbiB4ou2O0uUAgomgks5rvJgrgaJpZM4HoUeu .

aliaspider commented 7 years ago

the WASAPI driver just needs to enumerate the available playback rates and choose the one that is closest to the user setting, that is how the other drivers currently work. regarding audio sync, when off, it just means that the audio write function will drop samples instead of blocking on buffer overrun.

ghost commented 7 years ago

@retro-wertz WASAPI driver is not "locked" to any frame rate, the audio device is. What you encountered is expected when WASAPI is used in exclusive mode. In that mode there is no "middleman" who will do frame rate conversion on the fly, so you have to know supported frame rates of audio device that you are using before making frame rate changes. If you don't know them, standard frame rates like 44100Hz, 48000Hz, 96000Hz should work with most audio devices. If you absolutely must have some non-standard frame rate, you will have to disable exclusive mode (in Windows playback device properties dialog), then audio driver will switch to shared mode and WASAPI audio engine will (hopefully) do frame rate conversion. These exclusive/shared mode and also float/pcm format settings should be (one day) exposed to the end user.

@aliaspider I'm aware of what should be done, just need some time. Are you sure that, when audio sync is off, audio driver should drop frames?

aliaspider commented 7 years ago

yes I'm sure. you don't drop all of course, just enough so you don't overrun.

ghost commented 7 years ago

I'm a little suspicious about that (sorry), I will have to check retroarch sources to see it myself.

aliaspider commented 7 years ago

...

Monroe88 commented 7 years ago

Are you absolutely sure that WASAPI driver is causing these problems? Can you confirm that other audio drivers working correctly on your system?

The hang doesn't occur with other audio drivers like xaudio or dsound, just with the WASAPI driver.

Ryunam commented 7 years ago

I have to chime in and partially retract my previous comment, since I had to time to test this more thoroughly. On my machine and device (Schiit Modi 2 Uber with the official drivers), I get crackly and garbled audio during normal gameplay all the time. This happens regardless of any value I declare for Audio Latency in Retroarch, although the higher it is the less cracks and pops I get. Setting my rate to either 44100 or 48000 from the Windows configuration does not seem to help at all.

ghost commented 7 years ago

I did some more work on this. Audio sync off is now supported (and fast-forward). Format negotiation is improved and mode/format settings are now available in retroarch.cfg. There are many changes in source code so some issues may be solved, some new introduced. https://github.com/casdevel/RetroArch/releases

inactive123 commented 7 years ago

I merged the latest changes from @casdevel back into RetroArch.

@Ryunam Time to test again I guess with the latest nightlies.

ghost commented 7 years ago

Hi @casdevel,

I just tried the driver on Windows 10 and I get a freeze upon starting a game:

RetroArch [INFO] :: Enumerating DInput joypads ...
RetroArch [INFO] :: Done enumerating DInput joypads ...
RetroArch [INFO] :: Found joypad driver: "dinput".
RetroArch [INFO] :: Using font rendering backend: freetype.
RetroArch [INFO] :: [WASAPI]: Initializing default device ...
RetroArch [INFO] :: [WASAPI]: Device initialized.
RetroArch [INFO] :: [WASAPI]: Initializing client (exclusive, float, 48000Hz, 64.0ms) ...
RetroArch [WARN] :: [WASAPI]: Unsupported format.
RetroArch [INFO] :: [WASAPI]: Initializing client (exclusive, float, 44100Hz, 64.0ms) ...
RetroArch [WARN] :: [WASAPI]: Unsupported format.
RetroArch [INFO] :: [WASAPI]: Initializing client (exclusive, float, 96000Hz, 64.0ms) ...
RetroArch [WARN] :: [WASAPI]: Unsupported format.
RetroArch [INFO] :: [WASAPI]: Initializing client (exclusive, float, 192000Hz, 64.0ms) ...
RetroArch [WARN] :: [WASAPI]: Unsupported format.
RetroArch [INFO] :: [WASAPI]: Initializing client (exclusive, pcm, 48000Hz, 64.0ms) ...
RetroArch [INFO] :: [WASAPI]: Client initialized (exclusive, pcm, 48000Hz, 64.0ms).
RetroArch [INFO] :: [WASAPI]: Enumerating active devices ....
RetroArch [INFO] :: [WASAPI]: Acer CB280HK (インテル(R) ディスプレイ用オーディオ) {0.0.0.00000000}.{47e68b18-0b6b-4315-bc3b-e304d2be916d}
RetroArch [INFO] :: [WASAPI]: Speakers (Realtek High Definition Audio) {0.0.0.00000000}.{93934cf8-f11c-4484-a0ae-eab26a573fc8}
RetroArch [INFO] :: [WASAPI]: Devices enumerated.
RetroArch [INFO] :: Found menu display driver: "menu_display_gl".
RetroArch [INFO] :: Using font rendering backend: freetype.
RetroArch [INFO] :: Using font rendering backend: freetype.
RetroArch [INFO] :: SRAM will not be saved.
RetroArch [INFO] :: Loading history file: [C:\Users\bp\Downloads\RetroArch\content_history.lpl].
RetroArch [INFO] :: Loading history file: [C:\Users\bp\Downloads\RetroArch\content_image_history.lpl].
RetroArch [INFO] :: [GL]: VSync => on
RetroArch [INFO] :: [WGL]: wglSwapInterval(1)
RetroArch [INFO] :: [WASAPI]: Sync on.
RetroArch [INFO] :: [GL]: VSync => on
RetroArch [INFO] :: [WGL]: wglSwapInterval(1)
RetroArch [INFO] :: Saved new config to "C:\Users\bp\Downloads\RetroArch\retroarch.cfg".
RetroArch [INFO] :: Trying to write to playlist file: C:\Users\bp\Downloads\RetroArch\content_history.lpl
RetroArch [INFO] :: Trying to write to playlist file: C:\Users\bp\Downloads\RetroArch\content_image_history.lpl
RetroArch [ERROR] :: [WASAPI]: Memory leak in wasapi_free.
RetroArch [INFO] :: Does not have enough samples for monitor refresh rate estimation. Requires to run for at least 4096 frames.
RetroArch [INFO] :: Does not have enough samples for monitor refresh rate estimation. Requires to run for at least 4096 frames.
ghost commented 7 years ago

@bparker06 Try with audio sync off.

Zarkovian commented 7 years ago

Hi casdevel,

Thank you for the development effort on this.

I have a mixed message after testing your latest build (downloaded as nightly build april 16th from buildbot). I'm on Windows 10 with a Soundblaster Audigy Rx.

Currently the only core wasapi shared works for me is the Mednafen PCE fast core. Shared mode works flawlessly with 10ms latency (latency in Retroarch set to 0). This is with audio sync ON. When I turn it off, the audio gets continiously interrupted.

I've also tested BSNES mercury balanced, Genesis Plux GX, and BlueMSX. But with those cores it does not work, audio seems initialized but is practically unhearable (it sounds like 56k6 modem sound almost... ;).

This happens with all latencies (0 to 200ms) and both audio sync ON and OFF, but with it ON, the video display gets VERY slow.

I did get a taste though of what your wasapi implemention is capable of when used with the Mednafen PCE Fast core, and it's absolutely fabulous.

Hopefully you can find out what is happening with the other cores.

NB. I have only tested shared mode, because that's how I want the emulator to work currently, and secondly because I think the Creative Soundblaster Rx driver doesn't correctly support wasapi exclusive mode (I noticed this when using exclusive mode with other programs in the past), and testing it would thus possibly lead you astray with the results.

Lastly, I could not find in retroarch.cfg where I can impose Float versus PCM. Currently shared mode is initialized as Float 48000hz, but I would like to try PCM, and see if the problematic cores mentioned will work better with it. Where / with what variable can I set it to PCM?

Hopefully this is of some help. Please let me know if can do more testing.

ghost commented 7 years ago

Settings are audio_wasapi_exclusive_mode and audio_wasapi_float_format (true/false). Note that these sets preferred values (driver may fallback to other mode and/or format). Also, in shared mode latency setting is ignored (value is chosen by the WASAPI engine).

I will try tomorrow those cores that you mentioned, to see if I can reproduce that behavior on my machine.

Zarkovian commented 7 years ago

I tried to "force" PCM, adding the following to retroarch.cfg (in root, where retroarch.exe resides):

audio_wasapi_exclusive_mode = "false" audio_wasapi_float_format = "false"

But these settings seem to be ignored, as the format stays float and the log is identical to not having these lines there. (As mentioned earlier tested with the april 16th buildbot exe). Tested with the bsnes-mercury-balanced core.

RetroArch [INFO] :: [WASAPI]: Initializing default device ... RetroArch [INFO] :: [WASAPI]: Device initialized. RetroArch [INFO] :: [WASAPI]: Initializing client (exclusive, float, 48000Hz, 72.0ms) ... RetroArch [WARN] :: [WASAPI]: Device allready in use. RetroArch [INFO] :: [WASAPI]: Initializing client (shared, float, 48000Hz) ... RetroArch [INFO] :: [WASAPI]: Client initialized (shared, float, 48000Hz, 10.0ms). RetroArch [INFO] :: [WASAPI]: Sync off. RetroArch [INFO] :: [WASAPI]: Enumerating active devices .... RetroArch [INFO] :: [WASAPI]: Luidsprekers (Sound Blaster Audigy 5/Rx) {0.0.0.00000000}.{658afacb-6564-407b-a297-5142fee4f097} RetroArch [INFO] :: [WASAPI]: Devices enumerated.

ghost commented 7 years ago

@rafan8 I managed to test Genesis Plus GX core (for others I will need more time to find out how to setup them). Test was done on Windows 10, with these binaries http://buildbot.libretro.com/nightly/windows/x86_64/2017-04-16_RetroArch.7z.

In shared mode, with both float and pcm format, driver worked correctly. Exclusive mode with pcm format was also fine. I didn't tested float format in exclusive mode since my hardware don't support that. Settings also worked as expected.

If, with these binaries, settings still don't work on your machine, let me know again (I can add more log messages to help us find out what's going on).

Exact setup (additional files required by core, game ...) may be helpful for reproducing same issues on my machine. Until those problems don't appear on my machine there is very little I can do.

I did go trough sources again and I didn't find anything suspicious. There is only one mixup with log messages ("Device already in use" and "Exclusive mode disabled" are swapped), as seen in log you posted, but they don't affect execution in any way.

Zarkovian commented 7 years ago

I've investigated further with the Genesis Plus GX core since that's working for you without issues.

We're using the same binary so that can't be it. I've now started with a blank config and guess what, wasapi shared works flawlessly for Genesis Plux GX. Then I did a file comparison with my old config, and old and new had a tiny difference in "audio_device" setting.

My old config for Genesis Plus GX (not working, did not initialize on further inspection) had: audio_device = " " note the space between the quotes the new config (working) has: audio_device = "" (no space between the quotes)

Changing this line in the old config now makes it initialize the wasapi device without issue and it works flawless.

So that's one down :)

But, for the bsnes-mercury-balanced, bluemsx, and vice_x64 cores this was already correct, so there's a different issue at play for these cores.... Hope you can find out.

I've now also managed to test them with PCM. I start all cores with a separate config via commandline, and the audio_wasapi_exclusive_mode and audio_wasapi_float_format values are saved to these separate configs, not the generic "retroarch.cfg". After changing the value for float to "false" I was able to test them with PCM, but it makes no difference to my earlier reported issue with bsnes_mercury_balanced and BlueMSX cores.

Currently I'm starting bsnes-mercury-balanced and BlueMSX via commandline like this: retroarch.exe -L "cores\bsnes_mercury_balanced_libretro.dll" -c "config\bsnes_mercury_balanced_libretro.cfg" "FULL\PATH\TO\ROM\FILE" retroarch.exe -L "cores\bluemsx_libretro.dll" -c "config\bluemsx_libretro.cfg" "FULL\PATH\TO\ROM\FILE"

If you have an issue setting up any of the problematic cores, i.e. bsnes-mercury-balanced, bluemsx, or vice_x64 (the commodore 64 core), please let me know and I'll try to help out.

Zarkovian commented 7 years ago

Hi casdevel,

Further to my previous comment I've tested some more cores. In Wasapi shared mode on Windows 10 with Creative Audigy Rx and sound sync ON the following cores work great with 10ms latency audio:

But, with Sound Sync OFF the above cores all have crackling audio. Looking at the log (buffer stats are shown when changing latency value) they seem to be underrunning the buffer constantly when sound sync is off. Is the sound stream synchronized correctly to the retroarch calibrated video display rate?

With XAudio or OpenAL all above cores run perfectly without any sound issues when Sound Sync is OFF, so this seems a Wasapi specific issue.

Could you possibly explain what the real difference is between sound sync ON and OFF? I find it extremely important that input latency is not affected by any frame skipping or any of that, that's why I have all my cores configured with sound sync OFF, so preferably I would want to use that with Wasapi too.

Cores that do not work properly in wasapi shared mode with either sound sync ON or OFF are the previously mentioned:

To summarize the issue I'll repeat my previous comment: with above cores audio gets initialized but is practically unhearable when audio sync is OFF (there is only light sound "ticking", no real audio), and with it ON, the audio sounds really strange and video display gets VERY slow.

ghost commented 7 years ago

Ok, I tested BSNES-mercury-balanced and Vice X64 cores and I get similar results. Now I have something to work with. In the meantime you can try exclusive mode with audio sync on as a workaround. With those settings both cores worked correctly on my machine (x86 Windows 7 this time, didn't tested on x64 Windows 10).

Audio sync on option shouldn't have any impact on input latency (I'm guessing here, this is the question for core developers). There is possibility that all these problems are caused by me not understanding the whole idea behind audio sync off option (I will probably find out that soon).

Monroe88 commented 7 years ago

Audio sync is something that should always be on unless you are using fast forward. Having it off means that the game will not be throttled to the audio rate, which often results in audio crackling.

I tried the WASAPI driver again with the latest x86_64 build of RetroArch and it runs with audio sync off but there is no sound at all. If I toggle audio sync on, when I close the menu to return to the game, RetroArch instantly freezes. This happens regardless of whether I use exclusive or shared mode.

RetroArch [INFO] :: === Build =======================================
Capabilities: MMX MMXEXT SSE1 SSE2 SSE3 SSSE3 SSE4 SSE4.2 AVX AES 
Built: Apr 20 2017
RetroArch [INFO] :: Version: 1.5.0
RetroArch [INFO] :: Git: 40411e5
RetroArch [INFO] :: =================================================
RetroArch [INFO] :: Done enumerating DInput joypads ...
RetroArch [INFO] :: Found joypad driver: "dinput".
RetroArch [INFO] :: Using font rendering backend: freetype.
RetroArch [INFO] :: [WASAPI]: Initializing default device ...
RetroArch [INFO] :: [WASAPI]: Device initialized.
RetroArch [INFO] :: [WASAPI]: Initializing client (exclusive, float, 48000Hz, 16.0ms) ...
RetroArch [WARN] :: [WASAPI]: Unsupported format.
RetroArch [INFO] :: [WASAPI]: Initializing client (exclusive, float, 44100Hz, 16.0ms) ...
RetroArch [WARN] :: [WASAPI]: Unsupported format.
RetroArch [INFO] :: [WASAPI]: Initializing client (exclusive, float, 96000Hz, 16.0ms) ...
RetroArch [WARN] :: [WASAPI]: Unsupported format.
RetroArch [INFO] :: [WASAPI]: Initializing client (exclusive, float, 192000Hz, 16.0ms) ...
RetroArch [WARN] :: [WASAPI]: Unsupported format.
RetroArch [INFO] :: [WASAPI]: Initializing client (exclusive, pcm, 48000Hz, 16.0ms) ...
RetroArch [INFO] :: [WASAPI]: Client initialized (exclusive, pcm, 48000Hz, 16.0ms).
RetroArch [INFO] :: [WASAPI]: Sync off.
RetroArch [INFO] :: [WASAPI]: Enumerating active devices ....
RetroArch [INFO] :: [WASAPI]: Speakers (Realtek High Definition Audio) {0.0.0.00000000}.{26a0f1ef-2c6d-4186-8309-66aa3bc69e75}
RetroArch [INFO] :: [WASAPI]: Realtek HD Audio 2nd output (Realtek High Definition Audio) {0.0.0.00000000}.{afb55122-acd5-49de-8904-44c0564785bf}
RetroArch [INFO] :: [WASAPI]: Devices enumerated.
RetroArch [INFO] :: [GL]: VSync => on
RetroArch [INFO] :: [WGL]: wglSwapInterval(1)
RetroArch [INFO] :: [WASAPI]: Sync off.
RetroArch [INFO] :: [GL]: VSync => on
RetroArch [INFO] :: [WGL]: wglSwapInterval(1)
RetroArch [INFO] :: [GL]: VSync => on
RetroArch [INFO] :: [WGL]: wglSwapInterval(1)
RetroArch [INFO] :: [WASAPI]: Sync on.
ghost commented 7 years ago

@Monroe88 Then I understood what audio sync on/off option is supposed to do. On my machine I didn't experienced freeze with any of the cores that I tried so far. On what core(s) do you get freeze?

@rafan8 I have partially solved issues with cores that didn't worked. Now they all work well on x86 Windows 7 (with sync on) in both exclusive and shared mode, but on x64 Windows 10 I still get occasional "pops". Currently I'm setting up build environment on my Windows 10 machine, so will see...

Monroe88 commented 7 years ago

It happens on every core I've tried, including Nestopia, bsnes-mercury, Genesis Plus GX, ParaLLEl N64, and Beetle PSX. It might be specific to Realtek drivers because @bparker06 appears to have the same issue since his log also shows a Realtek HD Audio device

ghost commented 7 years ago

I also have Realtek device (VID:PID 10EC:0662) on board and no issues so far. There is one place in driver where infinite blocking is allowed. I'll forbid that (possible) infinite blocking and upload binaries later for testing.

ghost commented 7 years ago

Since I didn't have freezes on my machine I uploaded x64 binaries that may help to find out why this is happening. They can be downloaded from https://github.com/casdevel/RetroArch/releases/download/v1.5.0-wasapi-debug-freeze/retroarch-mingw64-debug-freeze.7z.

Note: this binaries are for testing purposes only.

Zarkovian commented 7 years ago

@casdevel Great that you have made progress with the problematic cores. Looking forward to the next release and doing tests on my Windows 10 X64 machine.

With regards to the sync OFF behaviour, I'm interested to know, does it -generally- run glitch free audio for you?

As unfortunately for me the wasapi implementation has -continuous- audio crackle with sync OFF, whereas this doesn't happen with DSOUND, XAudio or OpenAL. With these audio API's I run ALL cores with glitch free audio when Sync is OFF. It seems something is not right with the Sync OFF implementation with Wasapi?

Sorry to bug you about that, but I think both Sync ON and sync OFF are there for a reason, and in my experience when using XAudio / DSound / OpenAL both (should) work well when the video refresh rate is set to the real calibrated screen refresh rate (as seen in video options). Possibly you can try these other API's with Sync OFF and see how that compares with your Wasapi Sync OFF behaviour?

Monroe88 commented 7 years ago

I think I found the issue.

I have "Pause when menu activated" turned OFF in User Interface > Menu so the game runs in the background when the menu is up. When I turned that setting back ON so that the menu pauses the game, WASAPI works perfectly without freezing upon loading a game. The only other issue I found is that it loses audio if you toggle fullscreen while the game is running, but not if you toggle while in the menu (when pause is enabled). If you toggle "Pause when menu activated" back OFF in the menu, WASAPI will continue to run, but will freeze next you load a game. Audio Sync OFF sounds bad but that is to be expected.

The mingw64-debug build you posted also works, and it also has the same issue with fullscreen toggling. However, instead of freezing when running with "Pause when menu is enabled" off, it resulted in no audio output. Running with --verbose results in no audio as well, with the following log:

RetroArch [INFO] :: [WASAPI]: Sync on.
RetroArch [ERROR] :: [WASAPI]: WaitForSingleObject failed with error 1.
RetroArch [ERROR] :: [WASAPI]: WaitForSingleObject failed with error 0.
RetroArch [ERROR] :: [WASAPI]: WaitForSingleObject failed with error 0.
RetroArch [ERROR] :: [WASAPI]: WaitForSingleObject failed with error 0.
RetroArch [ERROR] :: [WASAPI]: WaitForSingleObject failed with error 0.
RetroArch [ERROR] :: [WASAPI]: WaitForSingleObject failed with error 0.
RetroArch [ERROR] :: [WASAPI]: WaitForSingleObject failed with error 0.
RetroArch [ERROR] :: [WASAPI]: WaitForSingleObject failed with error 0.
RetroArch [ERROR] :: [WASAPI]: WaitForSingleObject failed with error 0.
RetroArch [ERROR] :: [WASAPI]: WaitForSingleObject failed with error 0

As a side note, I can definitely feel a large improvement in audio latency with WASAPI exclusive mode over XAudio2 when I tested it with audio_latency set at 1ms. :)

ghost commented 7 years ago

@rafan8 I tested SDL, OpenAL, XAudio, DirectSound and WASAPI drivers on my x86 Windows 7 machine and turns out that all have issues when audio sync is off. Some more than others, depending on the core used. So resulting audio quality, with audio sync off option, depends on driver-core-machine combination, not just a driver.

Based on what I've seen so far, audio sync off option is there only as a possible workaround for cores that have issues when audio sync is on. Internally it's also used for fast-forwarding but this is irrelevant for end users. Bottom line, don't use it unless you have to.

@Monroe88 That helps. I'll see what can be done...

inactive123 commented 7 years ago

Hi there guys, I cherry-picked the latest commits by @casdevel to master. So the next nightly in a few hours should have the most recent changes to the WASAPI driver.

ghost commented 7 years ago

@twinaphex I pushed changes for default value for shared mode buffering (this is workaround for some cores) to false as it may interfere with working cores. If it's not to late for nightly you can merge those changes.

@rafan8 Workaround option for some cores (in shared mode) is audio_wasapi_shared_mode_buffering. Set it to true and check if that helps with problematic cores.

inactive123 commented 7 years ago

@casdevel Thanks. Pushed this just now.

ghost commented 7 years ago

Note for users with multiple audio devices that want to use non-default device with WASAPI driver:

  1. Look at log to find out ID of that device. ID's are printed out after device name and they look something like this {0.0.0.00000000}.{559215d2-1073-4019-87e6-ead715ad8f5e}.
  2. Copy and paste ID of the device you wish to use to retroarch.cfg option audio_device and save the file.

USB audio devices can be safely unplugged and plugged back to same or another USB port and ID's should remain the same (not tested since I don't have USB audio device).

After reinstalling driver, device will probably get new ID, so you'll have to repeat steps mentioned above.

Zarkovian commented 7 years ago

@casdevel I'll keep your comment about sync off and on in mind thanks (I'll revert my cores to have ON as default for these).

I've tried the problematic cores with the 'audio_wasapi_shared_mode_buffering = "true"'. Tested with nightly version April 22nd 11:30.

In both BlueMSX and bsnes_mercury_balanced this setting initializes the stream with 21ms buffer (instead of default 10ms). It works much better in the sense that the video display now is at normal speed, but unfortunately audio is not glitch free. There are the occasional pops and clicks. I guess the same as you heard on your Windows 10 setup.

Would it be possible to have the 'audio_wasapi_shared_mode_buffering' value specified in flexible buffer size in milliseconds, instead of only "true" (adding fixed 11ms of buffer)? That way we could test for larger buffer sizes and see if that makes a difference.

I understand from MSDN Windows 10 documentation on wasapi that it should be possible to either call for a) minimum buffer value of the audio driver / hardware, or b) specify a buffer of your own, where Windows 10 will still try to run latency as low as possible.

With regards to a). Minimum buffer size is 10ms for most drivers. But there's a caveat. Windows 10 with default microsoft "high-definition audio device" support a much lower buffer value of close to 3ms (This is new Win 10 feature, not available in Windows 7). From what I've seen, the Windows 10 "High-Definition Audio Device" driver works with all Realtek on-board audio chips. You can try by uninstalling the realtek driver for your onboard audio in Windows 10 and let it install the Windows Update driver. Or alternatively go to device manager, choose update driver, choose "search my computer..", then "I want to choose from a list... ", then there's two posibilities and choose the "High Definition Audio Device", this is the new Windows 10 default driver that supports minimum latency of 3ms. As said this is extremely low, and I doubt it will ever work with emulation. (and thus cause future trouble for Windows 10 users that have onboard audio with default microsoft driver, and you set audio in shared mode to minimum value. It is almost quaranteed to not work as users expect it, causing lots of audio glitches in these setups).

Given the above, could you possibly consider to set the minimum value in shared mode only when user sets audio latency in Retroarch to "0" (this could be considered the lowest possible latency driver supports). In all other cases the shared mode latency is set to whatever buffer size the user specifies. This is also the way WinUAE has implemented low latency Wasapi, it has a "Min" setting for lowest possible driver latency (set by Windows / driver), or specifies user defined values when audio buffer is set to anything else than "Min".

A second thought I had is that maybe the issue with the audio crackles for the problematic cores are caused by the cores themselves? I once had a quick glance at the BlueMSX and Vice_X64 cores and noticed at some places that they have an internal audio buffer specified at 100ms (BlueMSX I think) and 200ms (Vice_C64). Maybe these values do nothing at all (or I'm dead wrong about it, it was some time ago), but I thought I'd just mention it, in case it could be of any value.

Anyway, hope the issue with the problematic cores can be solved, as the Wasapi implementation for the currently properly working cores is absolutely awesome.

ghost commented 7 years ago

I'll change shared buffering option from boolean to integer value to let the user specify length in ms. Since this buffer should be used only as a workaround, I think it's better to keep this option separate from latency settings.

Current implementation of the driver uses event driven buffering, in both exclusive and shared mode. This enables lowest possible latencies and lower CPU usage, but disables user defined buffer length for shared mode streams (explained in remarks section of IAudioClient::Initialize method at MSDN).

I didn't check problematic cores sources, but WASAPI shared mode definitely don't "like" the way they are operating.

Also, if you need low latency, and don't need system sounds while RetroArch is running, you can use driver in exclusive mode. On my machine lowest possible latency in exclusive mode is 4ms, and works without problems with all cores that I tried so far (some of them needs latency higher than 4ms). I remember that you mentioned problems in the past with some apps and exclusive mode, but I think it's worth trying. Also exclusive mode have lower CPU usage than shared mode.

Monroe88 commented 7 years ago

Regarding multiple audio devices, you can change them from within the menu by going to Audio -> Audio Device under the Settings tab and press left or right to cycle through available audio devices, and pressing Start or spacebar key will clear it and it will use the default audio device.

I found a small issue where it didn't update immediately when you changed the audio device until you did something else to trigger an audio driver reinit, but I fixed it and opened a pull request with the fix: https://github.com/libretro/RetroArch/pull/4836