ciribob / DCS-SimpleRadioStandalone

An open source Stand alone Radio for DCS integrating with all clickable cockpits and FC3 Aircraft
GNU General Public License v3.0
470 stars 123 forks source link

[WINE] System.NotImplementedException on IAudioEndpointVolume.GetChannelCount #621

Closed Web-eWorks closed 2 years ago

Web-eWorks commented 2 years ago

Reviving this issue from #409 as the underlying cause of the issue reported in the comments is fairly clear after a bit of digging. Attempting to run SRS-Client on linux in a WINE 7.2 install with .NET 4.6.2 allows the user interface to fully start up, but the application errors and closes when attempting to preview microphone volume with the following error in the log:

2022-08-26 23:00:50.6020 | Ciribob.DCS.SimpleRadio.Standalone.Client.Audio.AudioPreview | Error starting audio Input - Quitting! The method or operation is not implemented. System.NotImplementedException: The method or operation is not implemented.
   at NAudio.CoreAudioApi.Interfaces.IAudioEndpointVolume.GetChannelCount(Int32& pnChannelCount)
   at NAudio.CoreAudioApi.AudioEndpointVolumeChannels..ctor(IAudioEndpointVolume parent) in G:\Dropbox\Dev\DCS\DCS-SRS\NAudio\CoreAudioApi\AudioEndpointVolumeChannels.cs:line 63
   at NAudio.CoreAudioApi.AudioEndpointVolume..ctor(IAudioEndpointVolume realEndpointVolume) in G:\Dropbox\Dev\DCS\DCS-SRS\NAudio\CoreAudioApi\AudioEndpointVolume.cs:line 160
   at NAudio.CoreAudioApi.MMDevice.GetAudioEndpointVolume() in G:\Dropbox\Dev\DCS\DCS-SRS\NAudio\CoreAudioApi\MMDevice.cs:line 90
   at Ciribob.DCS.SimpleRadio.Standalone.Client.Audio.AudioPreview.StartPreview(Boolean windowsN)

This is caused by the IAudioEndpointVolume method GetChannelCount (and more generally, all per-channel audio APIs in IAudioEndpointVolume) in WINE being currently unimplemented (most likely due to lack of common feature support in the underlying ALSA/PulseAudio/Jack platform backends that WASAPI delegates to under WINE).

The channel count information is still available to the application via the audio device MixFormat information, it's simply that NAudio throws an exception when GetChannelCount is unavailable when building an AudioEndpointChannels object.

2022-08-26 22:59:03.9807 | Ciribob.DCS.SimpleRadio.Standalone.Client.Singletons.AudioOutputSingleton | Building Microphone Audio Outputs 
2022-08-26 22:59:03.9807 | Ciribob.DCS.SimpleRadio.Standalone.Client.Singletons.AudioOutputSingleton | Mic Audio Output - Saved ID  
2022-08-26 22:59:03.9807 | Ciribob.DCS.SimpleRadio.Standalone.Client.Singletons.AudioOutputSingleton | Audio Output - PulseAudio {0.0.0.00000000}.{FD47D9CC-4218-4135-9CE2-0C195C87405B} CHN:2 Rate:44100

If support for setting/querying individual channel volume on an IAudioEndpointVolume is not used/needed in SRS, it may be a simple matter to work around this bug and regain the ability to run SRS in WINE; otherwise the channel-specific methods will have to be implemented on the WINE side beyond the scope of this issue.

Unfortunately, I'm not familiar with C# development, so I cannot provide a proof-of-concept of what a functional workaround would look like to implement.

ciribob commented 2 years ago

This comes from the NAudio library - though I do have a fork of NAudio and will have a quick look

Thanks for the detail investigation!

Web-eWorks commented 2 years ago

As a quick update, I managed to get SRS working under WINE by commenting out three lines in AudioEndpointVolume; will reply with the actual changed code in a few hours when not on mobile.

ciribob commented 2 years ago

Oh thats great news! I dont mess with the volume so can integrate that without any issues. Thanks!

Web-eWorks commented 2 years ago

Commented-out code as follows; I know for sure that AudioEndpointVolumeChannels and QueryHardwareSupport both cause NotImplementedExceptions and AudioEndpointVolumeStepInformation was questionable and unused by anything in the solution according to Visual Studio.

        /// <summary>
        /// Creates a new Audio endpoint volume
        /// </summary>
        /// <param name="realEndpointVolume">IAudioEndpointVolume COM interface</param>
        internal AudioEndpointVolume(IAudioEndpointVolume realEndpointVolume)
        {
            uint hardwareSupp;

            audioEndPointVolume = realEndpointVolume;
            //channels = new AudioEndpointVolumeChannels(audioEndPointVolume);
            //stepInformation = new AudioEndpointVolumeStepInformation(audioEndPointVolume);
            //Marshal.ThrowExceptionForHR(audioEndPointVolume.QueryHardwareSupport(out hardwareSupp));
            //hardwareSupport = (EEndpointHardwareSupport) hardwareSupp;
            volumeRange = new AudioEndpointVolumeVolumeRange(audioEndPointVolume);
            callBack = new AudioEndpointVolumeCallback(this);
            Marshal.ThrowExceptionForHR(audioEndPointVolume.RegisterControlChangeNotify(callBack));
        }

With this code patch and WPF hardware acceleration disabled in the registry (because constantly redrawing the preview UI on the GPU fights with DCS for limited available resources on older hardware such as my own) SRS works very well under WINE. There is an occasional issue with the SRS in-game script losing connection with the SRS client, but no pertinent information was present in any of the SRS logs and the issue appeared to resolve itself as long as I kept the client or overlay window open.

ciribob commented 2 years ago

Thanks! This will be part of the next release #622

TheZoq2 commented 2 years ago

I've flown with this for a few days now and it seems to work really well! I had to install dotnet462 and fix WPF using the instructions here https://www.reddit.com/r/linux4noobs/comments/firqs9/getting_windows_wpf_applications_to_run_with_wine/

My first flight, I kept being disconnected from the server, but after upgrading the game scripts to the latest version, it has been flawless.

Thanks to both of you for putting the effort into this for us linux users :heart:

Web-eWorks commented 2 years ago

@TheZoq2 just as an extra FYI to throw into the DCS on Linux guide, the winepulse driver will report an audio MixFormat for all devices based on the default recording device the "test" audio stream it creates happens to get assigned to - if the four-channel PS3 Eye camera happens to be the first in the list, winepulse will report to SRS that all input devices have 4 channels and SRS will silently fail to initialize a correct recording stream (it will log a single Recording Stopped in the client log due to attempting to pull 4-channel audio from a 1- or 2-channel device).

I solved this by setting the PS Eye camera's audio profile to Off in pavucontrol or pulsemixer, but given the utter lack of info about this and the prevalence of the PS3 camera in linux headtracking, figured I'd make a mention of it here for posterity.

image

TheZoq2 commented 2 years ago

Interesting, would you mind making a PR to update the DCS on linux repo with that info?

I could do it to, but since you know the problem and solution directly, you're probably in a better position to write it

Web-eWorks commented 2 years ago

I can definitely look into it when I get the time!

vsTerminus commented 1 year ago

For anyone stumbling on this thread in 2023, the dotnet version that SRS depends on has been bumped up. You still need the WPF fix mentioned here https://github.com/ciribob/DCS-SimpleRadioStandalone/issues/621#issuecomment-1255474316 but now you want dotnet48. You may also want "corefonts" otherwise the interface text is pretty ugly.

Finally, run SRS from its own prefix. Disable auto-launch in DCS and just manually launch it.

Basically, run these three commands:

WINEPREFIX=/path/to/srs/prefix winetricks -q dotnet48 corefonts
WINEPREFIX=/path/to/srs/prefix wine reg ADD 'HKCU\Software\Wine\DllOverrides' '/f' '/v' 'd3d9' '/t' 'REG_SZ' '/d' 'native'
WINEPREFIX=/path/to/srs/prefix wine SR-ClientRadio.exe

That worked for me on Arch Linux with wine-staging 8.18

NorseManGef commented 7 months ago

For anyone stumbling on this thread in 2023, the dotnet version that SRS depends on has been bumped up. You still need the WPF fix mentioned here #621 (comment) but now you want dotnet48. You may also want "corefonts" otherwise the interface text is pretty ugly.

Finally, run SRS from its own prefix. Disable auto-launch in DCS and just manually launch it.

Basically, run these three commands:

WINEPREFIX=/path/to/srs/prefix winetricks -q dotnet48 corefonts
WINEPREFIX=/path/to/srs/prefix wine reg ADD 'HKCU\Software\Wine\DllOverrides' '/f' '/v' 'd3d9' '/t' 'REG_SZ' '/d' 'native'
WINEPREFIX=/path/to/srs/prefix wine SR-ClientRadio.exe

That worked for me on Arch Linux with wine-staging 8.18

How would I actually go about connecting SRS to DCS while in a separate prefix? I have the SR-ClientRadio.exe running, but how do you link it to DCS?

TheZoq2 commented 7 months ago

SRS communicates with the game via sockets, so it doesn't need to run in a separate prefix. But, you need to install the game files manually. IIRC the readme has instructions for that

vsTerminus commented 7 months ago

I chose to run it in a different prefix because of the dotnet dependency. Maybe it's not an issue anymore but historically installing (or more specifically, removing dotnet) from a prefix could get messy and force you to have to recreate the whole thing. I determined that by running SRS in its own prefix I could easily recreate that prefix at any time without any repercussions should I need to.

You can install SRS into the DCS prefix without needing dotnet48, and then it places all the files you need automatically.

So at the end of the day I have two entries in Lutris:

But like I said you could probably just do it all from the DCS prefix if you wanted to.

badbabykosh commented 15 hours ago

Does anyone have screenshots that show how to do this with lutris?

vsTerminus commented 15 hours ago

Screenshot_20241115_154824

It's just two different entries

I run the auto-updater before I play, and then after I launch DCS I manually launch SRS.

I do the same thing for DCS VR and DCS flatscreen; Different Lutris entries and prefixes for each, allowing me to set different wine/proton runners and different companion apps (eg, the flatscreen prefix has Linuxtrack installed for TrackIR, the VR prefix does not)

Screenshot_20241115_160150

Definitely not necessary, but I've found it more convenient this way.

Edit: And in case you're curious, the DCS Updater entry looks like this:

Screenshot_20241115_160521

It's an easy way to run the updater without launching the game afterwards.