-
-
Notifications
You must be signed in to change notification settings - Fork 367
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
Audio playback issue after device disconnect using WASAPI backend #717
Comments
Thanks for the report. I'm actually not entirely sure what's going on there or what I might be able to do to solve this. Those "CHANGING DEVICE" messages are actually from WASAPI itself when it wants to reroute. I'll try to replicate this when I get a chance and report back. |
Hi there, |
OK, I saw your pull request and perhaps I misinterpreted your situation. The state of a ma_sound object is decoupled from the engine. It's absolutely possible and intentional for ma_sound_is_playing() to return true even when the engine (and the underlying device) is in a stopped state. ma_sound_is_playing() is just a simple getter of an internal flag for determining if the sound itself is in an active state from it's own isolated perspective. This makes sense - it's common that you will want to pre-prepare your sounds by putting them into a started state (which is also their default state) before you've actually started the engine. This way you can start the engine and sounds will start playback atomically and they will stay in sync. With your PR, you will never be able to put your sound into a started state before starting the engine. Having said all that, having a ma_engine_is_started() might be a useful API. That would be a more appropriate way of determining whether or not audio as a whole is running. In the situation you're talking about in this ticket, does sound playback start working again after calling ma_engine_start()? |
Now this, is interesting. |
If it's possible, it would be handy to see the contents of your |
Interestingly, the WASAPI error seems to trigger when I attach a debugger and restart the device after waking up, regardless of build settings. The crash only happened the once, every other time it just hung because the device is trying to restart. |
So I tested the sleep/wakeup cycle with the deviceio test and it's working exactly as I would expect with the WASAPI backend. That test lets you pause and resume the device with the "P" key. It's successfully stopping the device when the computer is put to the sleep, and it's successfully resuming when I wakeup the machine and hit the "P" key in the program to resume it. You can test this out for yourself if you like (it's easy to compile). I'm assuming the |
Hello, If I may comment, and if that helps, I understand the source of this is indeed the ma_device being stopped by Windows going into sleep mode, and not being restarted by any mean. Experiencing the same issue, I somehow expected miniaudio to recover automatically from this (similarly to how it already handles device changes), maybe day-garwood did too, but there are good reasons for it not to do it as well. Calling periodically:
Or just before playing a new sound properly restarts the device and all sounds that were playing properly continue. I'm just not sure if that's correct to do such things with the high level API. Thank you! |
The deviceio test is giving me an error: Yes, the device_uninit is a result of engine_uninit. The only times I'm calling engine_uninit are:
|
Hi Louis, |
Hi day-garwood, Indeed, now that you mention it, calling this ma_device_start() seems to cause issues, one of them being a deadlock on stop, when calling ma_engine_uninit() at the end of the test. Deadlock was on WaitForSingleObject (though there is a timeout so possible called repeatedly):
The main thread calling ma_engine_uninit() was a the time blocked in ma_device_uninit(). For your own tests, did you try to build in debug mode with asserts? Once I started to call ma_device_start() from the main thread every 1sec (if state is not started), like in the code I mentioned previously, I started getting quite a lot of them related to device states, so maybe you'll get some too. Feels like one should not call ma_device_start() while miniaudio might be attempting to recover from device changes. |
I did build in debug mode. I got no assertion errors though. |
Hello, Just to try to isolate a bit the issue, I attempted to make a tiny console C++ example here: issue_717_restart_device_test.txt It requires "my_sound.wav" to be available (preferably a long one, so something continuously runs). You can type 'S' then press Enter to stop and uninit the test, and 'R' to stop and restart a new engine. Scenario 1):
Scenario 2)
@day-garwood Feel free to tell if your test looks different, I just attempted to make something easier for mackron to reproduce. Thank you, |
Ah, didn't realise you had to define ma_assert yourself. My test doesn't do that.
|
If the state miniaudio side of the device does not match the actual state of the backend side of it, such as when the device is stopped but the backend doesn't post a notification, attempting to stop the device might result in a deadlock. This is a just a quick workaround hack for the moment while a more robust solution is figured out. #717
Thanks team. It sounds like for some reason WASAPI isn't reporting your device as stopped. On my system, WASAPI is definitely reporting the device as invalid which miniaudio is detecting which then puts the Although I haven't yet been able to replicate any crash or deadlock, I've pushed an experimental hack to the dev branch to hopefully prevent the deadlock in uninit. It doesn't actually solve the underlying problem, and if my thinking is correct, would still result in a deadlock if I tested with DirectSound and WinMM backends, and both of these resume automatically upon wakeup. I guess the ideal solution would be for miniaudio to detect when the machine is put to sleep or woken up and cleanly handle it like DirectSound and WinMM are doing (they do this automatically - no direct involvement on miniaudio's part). I think the way to do this is to have a hidden window with a window proc running in a background thread which detects the power state changes. I'm not quite sure how to deal with that yet. Marking this one as a bug. |
Hello, On my side it unfortunately didn't help. I took the liberty of improving a bit the test of day-garwood to add thread_id + date/time in logs, and to print MA logs. With latest dev branch, I uncommented line restart_engine() of the test (otherwise there is no sound after waking up) and got the same behavior with an infinite loop when stopping. issue_717_updated_test.txt I documented the steps in the log. day-garwood made the test quite simple, and doesn't mix calls to device restarts while miniaudio is processing changes, so I'm thinking the test itself is not messing with miniaudio's state (at least not causing extra harm at the time it's called). @mackron: I'm thinking miniaudio properly detects the change, but maybe the issue lies that there is not only a single change when computer wakes but multiple ones? Thread ids are interesting to watch as well in the log (I attached another version as well with GetCurrentThreadId() instead of pthread_self() because I'm not so sure how posix works on Windows for thread ids - scenario is exactly the same). @day-garwood: just a quick note regarding asserts, you don't have to do it like I did to print them, the basic C assert() should work perfectly fine as long as NDEBUG is not defined (which is generally the case when building in debug mode). I just redefined it to bypass them (which is generally a wrong thing to do because they're here for a reason), but to see them at least. I'm available for further testing if needed! Thank you, |
An additional note: I just noticed that with the latest change in dev, basic scenario (without sleep mode/restart of device) also ends up in infinite loop when closing. |
The change in a47f065 has caused a hang for me in some circumstances. On Linux (I believe with the ALSA backend) setting a very small buffer (1ms) in exclusive mode will apparently succeed but no audio plays. Once the device is in this state, calling |
Hi there.
Thanks for your great work so far.
I made a Windows app recently and a friend of mine noticed a problem when coming out of sleep mode. When I tested I found this had something to do with MiniAudio.
A minimal test with debugging enabled showed that MA seems to make six attempts to change devices. This is likely due to the fact that, even after waking the computer from sleep, I have to press a few keys for the audio device to kick in again.
The result of this is that we now appear to be in an unknown state. Both loading and playing a sound return MA_SUCCESS but no audio actually plays, ma_sound_is_playing always returns true, and the cursor is stuck at 0.
I have attached the debug log for reference.
Thanks again.
The text was updated successfully, but these errors were encountered: