WASAPI exclusive mode: unhandled exception of type 'CSCore.CoreAudioAPI.CoreAudioAPIException'

Jul 13, 2014 at 7:44 AM
Hello,

Wonderful project you have there. Thanks a lot for providing it. I've implemented it in my audio player. I just encountered this unhandled exception:
An unhandled exception of type 'CSCore.CoreAudioAPI.CoreAudioAPIException' occurred in CSCore.dll

Additional information: IAudioClient::GetCurrentPadding caused an error: 0x88890004, "Unknown HRESULT".
It happens when CSCore is playing sound through WASAPI in shared mode, at the moment that another application begins playing a sound in WASAPI exclusive mode.

The exception crashed my application.
Is there any way I could catch this?
Coordinator
Jul 13, 2014 at 8:46 AM
Edited Jul 13, 2014 at 8:48 AM
This discussion has been copied to a work item. Click here to go to the work item and continue the discussion.

First of all, thanks for reporting the bug. The same problem occurs whenever the device gets disconnected or deactivated. Since the Exception gets thrown on another thread there is no possibility to catch the exception and handle it correctly. I am currently working on a solution for that problem. I am going to release a fix within the next days or weeks.
Jul 17, 2014 at 11:14 AM
Hello,

I ran into that error myself in 2 work-flows:
  1. Unplugged or Disabled: worked around it by checking if any disabled/unplugged devices is the one I wanted. I'll disable the control that uses it or break the function, re-triggering it upon activating the device again.
  2. By mistake, trying to initialize wave in sounds when the recording device selected is wave out (aka speakers).
Hope it helps.

Great work btw :)
Coordinator
Jul 17, 2014 at 1:04 PM
Thank's for work. The problem should be fixed now: https://cscore.codeplex.com/workitem/7.
There won't be an exception on the playbackthread but the playback will stop anyway. You can get the exception with caused the error from the Stopped-event. If the device got removed, deactivated,... the playback has to get restarted. The WasapiOut class itself, won't try to recover the playback on an error.
Jul 18, 2014 at 12:56 PM
Edited Jul 18, 2014 at 1:12 PM
Hello, thanks a lot for fixing this so quickly. I'm able to fetch the exception in the stopped event, and make my player do a clean stop. I however encounter a nullreference exception in AudioClient.cs in the function ResetNative() when trying to play a new song once the other software has stopped using exclusive mode. This is what I'm getting:
public unsafe int ResetNative()
        {
            return InteropCalls.CallI(UnsafeBasePtr, ((void**)(*(void**)UnsafeBasePtr))[12]);
        }
Exception:

An unhandled exception of type 'System.NullReferenceException' occurred in CSCore.dll

Additional information: Object reference not set to an instance of an object._

After handling the Stopped event, I'm cleaning the resources the following way. But it doesn't seem to matter, the nullreference exception occurs whether I clean the resources or not.
Private Sub CloseSoundOut()
        If Me.mSoundOut IsNot Nothing Then

            Try
                Me.mSoundOut.[Stop]()

                If Me.mSoundOut.WaveSource IsNot Nothing Then
                    Me.mSoundOut.WaveSource.Dispose()
                End If

                If Me.mSoundOut IsNot Nothing Then
                    Me.mSoundOut.Dispose()
                End If

                Me.mSoundOut = Nothing
            Catch ex As Exception

            End Try
        End If
    End Sub
Should I execute some other steps when handling the stopped event to be able to play again once the other software has stopped using exclusive mode?
Coordinator
Jul 18, 2014 at 3:35 PM
Are you calling the CloseSoundOut sub from within the eventhandler of the Stopped-event? If yes: The event gets fired by the playback thread. Since the Stop method tries to stop the playback thread it is not allowed to call Stop from the playback thread (because the playbackthread would try to stop himself which can cause problems like deadlocks). The NullReferenceException occurs when the UnsafeBasePtr is IntPtr.Zero. The only way to set the UnsafeBasePtr to IntPtr.Zero is to dispose the com object. I've tested the WasapiOut class but I can't reproduce that exception. Could you please explain me what do I have to do to get the NullReferenceException?
Jul 18, 2014 at 5:26 PM
Edited Jul 18, 2014 at 5:48 PM
No I'm not calling the sub from the stopped event. The stopped event triggers actions in the man thread of my application. But it actually doesn't matter if I call the sub or not. Once another player has taken over WASAPI exclusive mode, when trying to play anything with CSCore once WASAPI is free again, triggers the exception. To demonstrate, I've put together a small console application which plays 1 mp3 every time you press a button on the keyboard (you an play as many times as you want, the play function is in a loop). The demo code contains the cscore code for easier debugging. How to use the demo app to reproduce the issue:
  • Start the demo app and press a button on the keyboard to start playing the mp3
  • While playing the mp3, start another player which plays something on WASAPI exclusive mode (I'm using the JRiver Media Center 19 demo version, which uses WASAPI exclusive mode by default) -> You'll notice the cscore console application then stops playing, without exception (= as expected).
  • Stop the player which uses exclusive mode
  • Go back to the console app and press a button on the keyboard -> the console app start playing the mp3 again (but crashes after a while with the above exception)
  • If the console app doesn't crash in the previous step, press a button on the keyboard a few times, the app eventually crashes
Here is the demo app: https://drive.google.com/folderview?id=0B-kioOJ2Tg7ScmcySE5GN19uWGM&usp=sharing

The zip file contains a solution with the demo app and cscore code (git clone from today). You can run the app from visual studio.

Edit: the demo app can produce 2 exceptions:
  • the exception mentioned above
  • a nullreference exception in WasapiOut.cs -> CleanupResources(), line 498 where the exception is thrown.
Coordinator
Jul 18, 2014 at 8:17 PM
Wow. Thanks for the demo app! That should not happen. Be sure that I am going to fix this as fast as possible (hopefully tomorrow).
Coordinator
Jul 19, 2014 at 2:02 PM
I've had a look at your code. There were a few little mistakes like initializing the same soundOut instance twice. I actually managed to fix one bug. But I still can't reproduce the NullReferenceException (I followed your instructions multiple times). I've made a few modifications to the WasapiOut class (not commited to the repo). You can download them here: https://www.dropbox.com/s/c8106xsat00ud9k/CSCore_WASAPI_Simulation.zip. Could you may try it out and give me some feedback whether the problem got fixed? I added some basic thread sync. It is the only reason I could imagine for the NullReferenceException.
Marked as answer by filoe on 7/24/2014 at 8:56 AM
Jul 19, 2014 at 4:37 PM
Thanks a lot for quickly fixing this and for reviewing my code. The double initialization is a result of adding the FFT provider after writing and testing the initial player class. I've now cleaned up the code in my full player also. Thanks for pointing that out.

I've tested the demo app with the modified wasapiout class and cannot reproduce any of the exceptions anymore. I've then compiled the cscore.dll with the wasapiout changes and added to my full player. Also in my player I cannot reproduce the exceptions anymore. It works as expected.