-
Notifications
You must be signed in to change notification settings - Fork 544
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support for XAudio2 via the Wine-4.2 compatibility layer #997
Comments
I'm making progress towards the XAudio2 goal with the old WINE 4.2 libraries. I have successfully compiled them in MSYS2 MINGW-W32 using both the Visual Studio LIB file and the linux SO file for linking libraries. So I've set out to crosscompile another libopenal-1.dll using msys2 with JACK enabled. |
I have now successfully cross-compiled msys-libopenal-1.dll for use with the cross-comipled Wine-4.2 XAudio2 DLLs. My instructions for doing so are below: To cross-compile OpenAL Soft 1.23.1 with JACK support to Windows using i686-w64-mingw32 in MSYS2 on Windows, follow these steps:
My built files and source code used can be found here: Programs still crash with an access violation, back to the drawing board. |
When running tests: Using native Microsoft XACT DLL files.
MSVS OpenAL32.lib linked XACT DLLs with no libopenal-1.dll present
MSVS OpenAL32.lib linked XACT DLLs with MSVS compiled OpenAL32.dll (renamed libopenal-1.dll)
libopenal.dll.a linked XACT DLLs with cross-compiled msys-openal-1.dll (renamed libopenal-1.dll) (SAME AS ABOVE)
|
I have a new theory and some results. Previously the Wine-4.2 XAudio2 files built with the library file specified with the variable ac_cv_lib_soname_openal would always define the dependency of libopenal-1.dll as named with the default files installed with pacman -S mingw-w64-i686-openal within MSYS2. After successfully cross-compiling OpenAL in MSYS2 using i686-w64-mingw32 and creating a massive 28MB msys-openal-1.dll, I was also left with a new version of libopenal.dll.a derived from that build. I can compile wine-4.2 with this new libopenal.dll.a and the dependency filename for the Wine-4.2 XAudio2 files changes to msys-openal-1.dll. This convinces me that I am selecting the correct file to link the Wine-4.2 XAudio2 files to OpenAL Soft. All the XAudio2 DLLs paired with the cross-compiled msys-openal-1.dll and tested with xaudio2_7_tests.exe continue to only spit out an ACCESS VIOLATION. I have used another tool DEPENDENCY WALKER to cross-reference with DependencyGUI. The new files are available here: wine-4.2-xact-msys-openal-1.dll-linked-bin+src.zip msys-openal-1-soft-1.23.1+jack-bin+src.zip I've had the privilege to talk with Andrew Eikum, creator of the code for the XAudio2 reimplementation based on the OpenAL Soft. On Mon, May 13, 2024, at 4:57 PM, Alex Schroedsen wrote:
Hi Alex! Interesting to see this old code being brought back to life! Hahah. I figured it was completely obsolete when we switched over to FAudio. I have to admit I'm not 100% sure what your goal is here. Wine's XAudio2 and FAudio should work on Windows, I believe with support for spatial audio & surround sound. I think the project is fairly feature-complete at this point. Is there something you get from OpenAL that FAudio can't provide?
For debugging these failures, are you familiar with the WINEDEBUG environment variable for getting Wine trace logs? That will hopefully give you more information about what is failing. Andrew I asked a few questions and he got back to me with useful info. On Tue, May 14, 2024, at 11:19 AM, Alex Schroedsen wrote:
All right. I would still suggest avoiding the old code. It's definitely buggy and doesn't have the benefit of 5+ years of work on FAudio and Wine's integration with it. Instead, I think you could try writing an OpenAL backend for FAudio, like it already has for SDL and WASAPI. I'd look at how those FAudio_platform* files interact with the public XAudio2 interface, and then implement a platform that targets OpenAL. Make sure it passes FAudio's and Wine's tests. If needed, you could then extend the connection between the internal platform API and the XAudio2 API, to meet your spatial audio needs (e.g. pass positional data from the XAudio2 interface through to OpenAL, or whatever is you'd like to achieve with it).
Yes, it looks like that program only shows static dependencies, not libraries loaded at runtime. COM stuff, like XAudio2, is loaded at runtime so won't show up as a static dependency.
I know it's something people do, but I've actually almost never used Wine libraries on Windows. So I don't know the details of how to do that. Hopefully there are Wine docs that can help you there, or maybe you can ask for help from someone else.
Some games are picky about device names (especially if they're trying to use several audio APIs at once and correlate the devices across them), but it's fairly uncommon for XAudio2 clients. Mostly they just open the default device. I think you're on the right path with running the Wine test suite against your implementation; if there are requirements there, then there should be tests to validate them.
Oohhh unfortunately I've long forgotten. Skyrim was definitely one, DOOM 2016 was another. You could maybe dig through the Wine bug tracker and bug URLs from the Git log around that era.
Sure. Happy to help.
Yeah, WINEDEBUG is how you get the output from all those TRACEs and WARNs and ERRs you see in the code. I wrote a blog post about it you might find helpful (be warned, some of this series is definitely out of date by now): https://www.codeweavers.com/blog/aeikum/2019/1/15/working-on-wine-part-4-debugging-wine Andrew Thus I am currently working on learning to use the WINE debugging environment variable. I do not know how to code in c, c++ or much ore about these audio APIs so I'm continuing with my goal to compile the old code. I am also working on learning how to use GDB and GDBserver in order to debug xaudio2_7.dll using xaudio2_7_tests.exe. I will report back with news as I have it. |
Honestly I'd have considered starting a bit more fresh, ala DSOAL. Start by building a native Windows DLL for xaudio2, exporting the functions it's supposed to export (empty to start with, just do nothing and return error), then link to and use the OpenAL Soft Windows DLL to start implementing it (using the old Wine xaudio2 code as a basis). There shouldn't be a need to cross-compile anything if you're on Windows, and only cross-compile the new XAudio2 dll and OpenAL Soft to Windows on other systems. You shouldn't need Wine if you're on Windows (and on Linux using Wine, it can use normal Windows DLLs, so the build process doesn't need Wine). |
I have made more progress and had new discoveries. I would start from scratch on this, but I am currently so novice that I am doing what I can, which is looking at references in the current code and seeing what does not match up. I am able to learn by fiddling with an existing implementation and seeing how its pieces interact whereas learning three languages (C, XAudio2, OpenAL) at once and needing to correctly implement them all simultaneously is a far more ominous task. Yesterday I dived into creating a wrapper that would hopefully pull the name of the device that audio2_7.dll would request OpenAL Soft to open. Following the instructions here API Interception via DLL Redirection. I successfully created a stub that would pass on all communications to the real OpenAL32.dll. I then fiddled with trying to convert the device name called with alcOpenDevice to a string and put up a message box with the device name. However I had a realization as I sifted through the code of xaudio_dll.c that it never calls the alcOpenDevice function. It instead calls the alcLoopbackOpenDeviceSOFT function. Sidenote-I also noticed that the function is specified to open the default OpenAL Soft device by specifying NULL in the device name parameter. So the original device naming convention problem is off the table. I looked up alcLoopbackOpenDeviceSOFT to learn it’s similarities and differences to the classic alcOpenDevice and found this article openalext/ALC_SOFT_loopback.txt at master · openalext/openalext. Issues
So far I see a few challenges to be tackled in order to make this implementation work. In order to modify it to support the alcOpenDevice rather than alcLoopbackOpenDeviceSOFT.
At this point I am wondering if all of this work will amount to OpenAL Soft not actually rendering positional data for height speakers, but only acting as an upmixer for the same set of channel masks that XAudio2 supports in this implementation. If you have an idea of how to solve these issues and get this implementation working, any help is appreciated. I remain interested in seeing this through to the point where we can at least see this existing implementation work and then perhaps be inspired to explore further, creating an improved implementation with the new and more feature complete FAudio or building something completely new. Here is the file I've been looking through |
The biggest problem will be the processing callbacks. I don't know if OpenAL Soft's callback buffers will be enough to handle
Depending on what XAudio allows apps to do with the audio, it may be as simple as ignoring the device's channel mask (store it and report it back if queried, but set whatever output you want with OpenAL Soft regardless). If the app expects to have access to or control of the individual output channels, though, it can get more complicated depending on what exactly it does. |
Thank you so much for explaining why the alcLoopbackOpenDeviceSOFT and alcRenderSamplesSOFT functions are used in this case. So -correct me if I'm wrong- xaudio_dll.c makes a request to OpenAL Soft to render audio data, OpenAL Soft hands the rendered audio data back to xaudio_dll.c and xaudio_dll.c then interacts with a WASAPI audio endpoint to output the rendered audio. The problem with this setup is that with every single chunk of audio data that is rendered, there is a start and stop by the API, which would usually not exist in practically all other audio backends (than WASAPI). Those other backends, I am guessing, specify channel mask, word format, frequency, subsequently the tedious callbacks for buffering would normally be abstracted behind the backend library and driver where applicable. Assuming the above is correct, looking at the channel mask code in xaudio_dll.c
The above speaker configurations may be able to be augmented according to this KSAUDIO_CHANNEL_CONFIG structure (ksmedia.h) there is also the KSAUDIO_SPEAKER_DIRECTOUT configuration. Perhaps we could avoid messing with the way that xaudio_dll.c and OpenAL Soft interact and instead just widen the pipe through xaudio_dll.c. Something like this (and other associated parts of the code):
Now if this is using WASAPI specifically, we might run into that 8 channel issue again, but if it can be forced to use Kernel Streaming instead, we can likely get away with it. If I had a convenient way to loopback 16 channels of audio using Kernel Streaming, I’d just do that and use ASIO4ALL to bridge it into a VST host, but I don’t know of a free solution at this time. Thin Audio Gateway seems like a potential solution, unfortunately it is closed source and proprietary.
-OR-
Thinking about this a little more, the client application accessing xaudio_dll.c probably wouldn’t like seeing (or be able to request) an undefined speaker config… Perhaps the returning audio data can be classified with a different set of handles/variables or something to keep the client application happy. Given my guesses turn out to be correct. Do either of these sound like a better way to avoid dealing with the callbacks? Or perhaps they just move the work of dealing with the unique callback behavior to another area… Thank you again for your time and effort in guiding and teaching me on this journey. |
Today I dug more into how xaudio_dll.c sends audio to WASAPI after receiving it back from OpenAL Soft. I am currently brainstorming how to replace the WASAPI backend in xaudio_dll.c with JACK. I have noticed a few things that I am interested in clearing up. On lines 1792 to 1821 xaudio_dll.c tries to open a context with OpenAL Soft and specific channel configurations are referenced in the code:
So now we have a set of WASAPI/KERNEL STREAMING channel masks and the above designations for OpenAL Soft. Searching for ALC_7POINT1_SOFT in the project files of OpenAL Soft 1.23.1, I found references to it in alc.cpp, alext.h and alloopback.c. Looking in alc.cpp, I found some references to the channel masks in lines 1496 through 1512 and a couple others elsewhere.
I’m guessing that to handle the 16 channel signal of a third order ambisonic signal, ALC_BFORMAT3D_SOFT would need to be added as a supported format in the xaudio_dll.c file. Additional to this, however, I am guessing that an app would also need to specifically ask for ambisonic 3D through the XAudio API, which is not implemented. My first question is: when channels=ambi3 is set in %appdata%\alsoft.ini; does this override the channel mask being rendered to a loopback interface? Does an OpenAL Soft loopback interface support the ALC_BFORMAT3D_SOFT channel format? Towards the goal of modifying xaudio_dll.c rather than OpenaL Soft. It seems to me that in order to make the channel mask format requested by XAudio and the channel mask format output/returned from OpenAL Soft loopback to coexist, functionality needs to be implemented to emulate support (return whatever the XAudio app is asking for, like you said) on the This->fmt.dwChannelMask, pChannelMask and This->fmt.Format.nChannels designators and a separate set of designators created to specify the output channel count negotiated with JACK (ignoring channel mask). Somehow OpenAL Soft would need to share the current channel count specified in channels=ambi3 within %appdata%\alsoft.ini with xaudio_dll.c. (references to the channel mask storing variables from xaudio_dll.c seen below)
I am still working on learning what the function of these IXAudio2EngineCallback_OnProcessingPassStart/End callbacks are and why they're going to be a challenge to deal with. I have been looking at JACK-AUDIO-CONNECTION-KIT: Setting Client Callbacks and asking carefully formulated questions to Meta AI to try to learn a bit more about how the WASAPI backend code works and on the sequence of transactions between xaudio_dll.c, OpenAL Soft and WASAPI. Meta AI suggested using jack_set_process_callback (jack_client_t *client, JackProcessCallback process_callback, void *arg) to interface with XAudio’s callbacks. I read the Microsoft page for the IXAudio2EngineCallback_OnProcessingPassStart/End callbacks and they seem like they're for buffer underrun reporting and compensation. Can you explain a bit more about when they happen, why they happen and what about OpenAL Soft would make working with them difficult? I'm also curious to know if you think the JACK jack_set_process_callback has any value in this situation? |
For creating the OpenAL context, you basically need to ignore attr[0] = ALC_FORMAT_CHANNELS_SOFT;
attr[1] = ALC_BFORMAT3D_SOFT;
attr[2] = ALC_AMBISONIC_LAYOUT_SOFT;
attr[3] = ALC_ACN_SOFT; // or ALC_FUMA_SOFT
attr[4] = ALC_AMBISONIC_SCALING_SOFT;
attr[5] = ALC_SN3D_SOFT; // or ALC_N3D_SOFT or ALC_FUMA_SOFT
attr[6] = ALC_AMBISONIC_ORDER_SOFT;
attr[7] = 3;
... (make sure to update the indices for the remaining attributes, and the size of the Interfacing with JACK is going to be pretty tricky. The problem is that JACK's process callback runs in a real-time thread, which isn't allowed to do things that could block or waste too much time. Since XAudio allows apps to set their own callbacks to run when processing, and |
It's not like openal-soft ain't still using WASAPI under the hood?
It might, but so then? Shouldn't your effort quite more focused on first figuring this one out?
Or even better perhaps, why aren't just trying to repurpose FAudio, period? Like.. I can see the merits of not replicating code, but I feel importing OAL's hrtf code in there would be somehow less hacky than stacking audio layers on top of audio layers. And why aren't you starting by resurrecting the late x3daudio1_7_hrtf project btw? |
I previously made the post about Obtaining Ambisonic output in Windows #984. I started getting off topic with the goal of supporting XAudio2 through cross-compiling the Wine-4.2 DLLs (XAudio2_7.dll etc.). This seems like a project that will take a while to bring to fruition if it ends up working at all. I'm creating this area to document how to cross-compile the Wine-4.2 XAudio2 DLLs and how to compile a JACK-backend-capable version of libopenal-1.dll that can interface with those cross-compiled Wine DLLs.
Commands for crosscompiling wine-4.2 with i686-mingw-w64 with OpenAL
Run MSYS2 MINGW32
To cross-compile WINE 4.2 DLLs to Windows using i686-w64-mingw32 in MSYS2 on Windows, follow these steps:
6a. Additionally one may copy OpenAL32.lib from a compiled MSVS version of OpenAL Soft into C;\msys64\mingw32\lib continue with step 7a if you take this path.
7a. Alternatively configure WINE for cross-compilation: ac_cv_lib_soname_openal=./lib/OpenAL32.lib ./configure --prefix=/usr --host=i686-w64-mingw32 --without-freetype
This will take an hour to compile the tools. Afterwards you'll have many cross-compiled DLLs XAudio2_7.dll etc. There will also be a testing program in C:/msys64/home/username/wine-4.2/dlls/xaudio2_7/tests/ that can be used to test the functionality of XAudio2_7.dll. It errors out when using a Visual Studio compiled version of OpenAL Soft 1.23.1 (renamed to libopenal-1.dll)
but completes tests when used with the MSYS version of libopenal-1.dll.EDIT: The tests run correctly because they are defaulting to the official Microsoft XAudio2 files.My built files and source code used can be found here:
wine-4.2-xact-bin+src.tar.xz.zip
The text was updated successfully, but these errors were encountered: