Skip to content
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

Pa_Initialize() interrupts other audio streams on Windows #858

Closed
arkrow opened this issue Oct 26, 2023 · 7 comments
Closed

Pa_Initialize() interrupts other audio streams on Windows #858

arkrow opened this issue Oct 26, 2023 · 7 comments
Labels
src-asio Steinberg ASIO Host API /src/hostapi/asio

Comments

@arkrow
Copy link

arkrow commented Oct 26, 2023

Describe the bug
Calling Pa_Initialize() to initialize PortAudio interrupts any currently playing audio streams momentarily on Windows if exclusive mode is enabled on the default sound device. Strangely, this issue only occurs if the PortAudio binary being used was compiled with ASIO, otherwise this bug does not occur.

To Reproduce

  1. On Windows 10/11, enable exclusive mode on the default sound device
  2. Use a PortAudio binary compiled with ASIO, and call Pa_Initialize()

Expected behavior
Other audio streams are uninterrupted while PortAudio is initializing.

Actual behavior
All other audio streams are interrupted while PortAudio is initializing, sometimes without recovery.

Desktop:

  • OS: Windows 11 (22H2)
  • PortAudio version: both stable and nightly
  • Host API: If build with ASIO

Additional context
An initial discussion of this issue was started on python-sounddevice, which can be seen here: spatialaudio/python-sounddevice#496

@dechamps
Copy link
Contributor

Strangely, this issue only occurs if the PortAudio binary being used was compiled with ASIO

This is not surprising. The way PortAudio initialization works is fundamentally flawed when ASIO is involved, and always has been. See #696.

My suggestion would be stop building PortAudio with ASIO support, and instead use the ASIO API directly from your code if you absolutely require ASIO support.

@dechamps
Copy link
Contributor

dechamps commented Oct 26, 2023

Though thinking about this a bit more, I find it a bit odd that you're describing a bug that is triggered specifically by exclusive mode being enabled on the default Windows audio device - I never heard of that particular failure mode before. Is this bug reproducible even with no ASIO drivers installed on the system? If not, can you pinpoint precisely which ASIO driver is causing it?

@arkrow
Copy link
Author

arkrow commented Oct 26, 2023

This is not surprising. The way PortAudio initialization works is fundamentally flawed when ASIO is involved, and always has been. See #696.

My suggestion would be stop building PortAudio with ASIO support, and instead use the ASIO API directly from your code if you absolutely require ASIO support.

I see. It's unfortunate that the issue is upstream, but your suggestion is understandable. Thanks for the quick response.

Though thinking about this a bit more, I find it a bit odd that you're describing a bug that is triggered specifically by exclusive mode being enabled on the default Windows audio device - I never heard of that particular failure mode before.

I'd imagine disabling exclusive mode--and thus having all audio streams only run in shared mode--incidentally prevents the conditions for the issue to happen, as no application can exclusively control the audio device and consequently kill other active audio streams, if improperly initialized/interfaced with.

Is this bug reproducible even with no ASIO drivers installed on the system? If not, can you pinpoint precisely which ASIO driver is causing it?

I'm a complete amateur when it comes to low-level audio interfaces; that said, I don't believe I have any ASIO drivers installed, unless the default audio driver counts. In that case, I believe it would be the RTHDASIO64.dll binary provided by Realtek on my system.

@dechamps
Copy link
Contributor

I'd imagine disabling exclusive mode--and thus having all audio streams only run in shared mode--incidentally prevents the conditions for the issue to happen, as no application can exclusively control the audio device and consequently kill other active audio streams, if improperly initialized/interfaced with

The thing is, that concept of "exclusive mode" is only relevant to the Windows Audio Engine. Not every audio code path goes through the Windows Audio Engine. WDM-KS doesn't, for example, and will therefore completely ignore that setting. I wouldn't expect a manufacturer-provided ASIO driver to go through the Windows Audio Engine. Instead, I would expect it to bypass the entire stack and talk to the hardware directly through some side channel.

However, it is definitely true that the author of an ASIO driver technically doesn't have to bypass the Windows Audio Engine - they could simply use it like any other app (especially if they're lazy…).

I don't believe I have any ASIO drivers installed, unless the default audio driver counts

There is no such thing as a "default ASIO driver". Windows doesn't come with any ASIO drivers. That said, I guess it's possible a manufacturer-provided audio driver that comes bundled with your computer (or perhaps even installed through Windows Update) could come with an ASIO driver that gets installed as a side effect of installing the Windows audio driver.

You can remove ASIO drivers by removing subkeys from the HKEY_LOCAL_MACHINE\SOFTWARE\ASIO registry key (for 64-bit apps - if your app is 32-bit that's HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\ASIO). This should allow you to test any combination of installed drivers. You can make a backup of the key by exporting it and then restore it later when you're done.

In that case, I believe it would be the RTHDASIO64.dll binary provided by Realtek on my system.

My main hypothesis at this point is that Realtek implemented that ASIO driver by simply making it use WASAPI Exclusive behind the scenes, and as a result it takes over exclusive mode when it's initialized. That would explain your symptoms. To be fair, implementing an ASIO driver that way is perfectly reasonable and Realtek is likely blameless here; it's PortAudio that's being unreasonable by attempting to load every single ASIO driver in the system in its initialization sequence, as explained in #696.

@arkrow
Copy link
Author

arkrow commented Oct 26, 2023

My main hypothesis at this point is that Realtek implemented that ASIO driver by simply making it use WASAPI Exclusive behind the scenes, and as a result it takes over exclusive mode when it's initialized. That would explain your symptoms. To be fair, implementing an ASIO driver that way is perfectly reasonable and Realtek is likely blameless here; it's PortAudio that's being unreasonable by attempting to load every single ASIO driver in the system in its initialization sequence, as explained in #696.

I've removed the Realtek ASIO driver and installed the FlexASIO driver instead to test if the behaviour persists. I can confirm that the issue doesn't occur, which is great news. In the end, it comes down to the host ASIO driver(s)' implementation, as you mentioned previously, which is unfortunately unpredictable and outside the control of application developers.

Would it be possible to extend Pa_Initialize() with optional parameters, to enable/disable support for certain host APIs at runtime? Or, is shipping two separate differently compiled binaries to enable/disable ASIO support the only solution for developers using PortAudio?

Thanks for the detailed and informative replies, both here and in the other threads.

@RossBencina
Copy link
Collaborator

So would I be correct to say that this issue is actually an issue in the Realtek ASIO driver and the problem is resolved?

As for your suggestion, it is covered here: #10

@RossBencina RossBencina added the src-asio Steinberg ASIO Host API /src/hostapi/asio label Dec 8, 2023
@arkrow
Copy link
Author

arkrow commented Dec 9, 2023

Yes, correct. The Realtek ASIO driver turned out to be the root cause of this issue. I'll be closing this issue since the problem's origin has been identified and lies outside this project.

That said, thanks for the progress on #10. Providing more granular control and the ability to selectively enable host APIs at run-time rather than build-time--depending on the host environment and the Pa_Initialize() caller's needs--would be a great addition to the API.

@arkrow arkrow closed this as completed Dec 9, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
src-asio Steinberg ASIO Host API /src/hostapi/asio
Projects
None yet
Development

No branches or pull requests

3 participants