PortAudio / portaudio

PortAudio is a cross-platform, open-source C language library for real-time audio input and output.
Other
1.43k stars 295 forks source link

PortAudio ASIO driver scan #696

Open jjYBdx4IL opened 2 years ago

jjYBdx4IL commented 2 years ago

Looks like ASIO drivers aren't meant to be loaded automatically. Please don't automatically load the drivers. Every ASIO app I know loads the driver only when the user selects it. Or at least add an option to disable that. ASIO drivers are configured using their own UIs. And those may want to pop up on driver load (you can try the free ASIO Link Pro drivers, which allow for device sharing).

jjYBdx4IL commented 2 years ago

Also, there seems to be no functionality to open the ASIO driver settings/configuration dialog. The standard seems to be (from what I know by using DAWs under Windows):

So, PortAudio would also need a way to call that config dialog and a way to retrieve the ASIO driver list.

RossBencina commented 2 years ago

I understand your request. However what you're suggesting is to change the global PortAudio device enumeration behavior that has been part of PortAudio since 2005 or earlier. It's not going to change any time soon.

PortAudio enumerates all devices when Pa_Initialize is called. We considered enumerating devices lazily but this causes other issues such as non-deterministic crashing (e.g. when a bad device is present that crashes when loaded). We decided it's better to have deterministic crashing at the time that Pa_Initialize is called. This is all ancient history now and is unlikely to change any time soon.

The function to display the ASIO settings dialog is declared in pa_asio.h. Note that it has limitations (you can't show settings for device A while device B is open).

jjYBdx4IL commented 2 years ago

How about handling ASIO independently from the generic API? Would probably still be better than building PortAudio without ASIO support, and then adding ASIO support separately in every program just to have proper support for it.

dechamps commented 2 years ago

FWIW I believe there should be very big warnings/documentation when building PortAudio with ASIO support, on the grounds that just having a faulty ASIO driver installed anywhere on the system can make the entire application process crash (or more generally trigger undefined behavior, which could be even worse) as soon as it tries to initialize PortAudio, even if the user did not intend to use any ASIO devices at all. I suspect many people building PortAudio are not aware that PortAudio's ASIO support is a giant footgun in that regard. The fact that this is just a consequence of PortAudio's design doesn't make it any less dangerous.

Basically, if you're not okay with loading potentially unbounded amounts of potentially crash-happy third-party code from random sources (a lot of which are not known for writing high-quality, reliable code) at initialization time, then don't enable ASIO support when building PortAudio. That's really asking for trouble.

jmelas commented 2 years ago

Apart from crashing, enumerating ASIO devices when the application starts adds significant delay in the startup-time of the Application.

oifii commented 1 year ago

Since I switched to portaudio version 19, portaudio master branch git cloned on 2021july27, built enabling all audio API defines, including the asio one, every time I launch any of my many portaudio-based apps , the global windows 10 audio shuts for a second or two (while Pa_Initialize(); is being called. The audio streaming from youtube/chrome browser on a USB device (id=3, hostapi=MME, devicename=Line (USB AUDIO CODEC) is interrupted for a second or two. On my windows 10 system, I do have one asio audio device (id=26, hostapi=ASIO, devicename=Realtek ASIO) that is a dummy asio device. On this same system with the same connected audio devices, this situation was not occurring when launching my portaudio -based audio apps relying on previous portaudio library version (i.e. source code snapshot from before 2016). Is it portaudio asio code that has changed? Must a more recent asio SDK be used? more recent than the 2.0 asio SDK? Or is it windows that changed something around the audio drivers access mechanism/behavior? Note: I fixed my problem for my system only hardcoding pa_asio.cpp with a one liner to have my "Realtek ASIO" driver excluded from being opened (so it is now part of the others blacklisted asio driver.

syntaro commented 4 months ago

hello there.

Im from japan. And oifii, Im having same problem. My note pc have RealTekASIO installed. Cant remove. and When I uninstall ASIO4All it semms no problem.

904 have code that skip open and get detail.

so no detail in app life time.

but My PC work fine . My PC RealTek +ASIO4ALL both installed.

Just missing samplerate etc.And it work.

I Just comment out 3 lines. Its all from me.

Could it help something?

mirh commented 4 weeks ago

I suspect many people building PortAudio are not aware that PortAudio's ASIO support is a giant footgun in that regard.

You can't just build it by accident, when you have to provide yourself the SDK?

Basically, if you're not okay with loading potentially unbounded amounts of potentially crash-happy third-party code from random sources at initialization time

I mean, that's just all device drivers ever though, isn't it? Though admittedly the ASIO drivers quality is more of a mixed bag. But if any, the real universal trouble is the startup delay (for as much as that seems to have been far smaller in the past?)

How about just adding some kind of runtime knob, that then programs can just ship disabled by default to avoid querying even though the api is compiled in? Syntaro's INIT_NOT_DETAIL hack in #904 already seeming kind of this.

dechamps commented 4 weeks ago

You can't just build it by accident, when you have to provide yourself the SDK?

Well if you use CMake, it's downloaded for you automatically.

Regardless of how easy it is to enable ASIO in a PortAudio build, I suspect many users who do this do not understand the implications. An unsuspecting PortAudio user would not necessarily expect that just enabling ASIO at build time could result in potentially severe and wide-ranging consequences with regard to the PortAudio initialization process, even if ASIO ends up not being used, in ways that are quite situation-dependent (and can thus easily go unnoticed during development).

It's worth noting that the ASIO PortAudio backend is very much unique in this aspect. Other backends (e.g. MME, DS, WASAPI) only call into purely OS-provided APIs that behave in reliable and predictable ways - they do not load third-party code. This is another reason why the PortAudio ASIO behavior is surprising.

One example of a surprised PortAudio user is spatialaudio/python-sounddevice#496 who removed ASIO support from their default build as soon as they found out about this.

I mean, that's just all device drivers ever though, isn't it?

In most ASIO applications, an ASIO driver is not loaded until the user has specifically expressed an intent to use it (e.g. by explicitly selecting it from a driver list). This makes it easy to determine if a particular ASIO driver is faulty, which is much harder to do if drivers are being loaded silently in the background like PortAudio is doing at init time.

Some ASIO drivers make the reasonable assumption that if they're being loaded and initialized then the end user actually intends to use the driver. This means they will not pay particular attention to load time, and some of them may even do disruptive operations such as taking over the audio device, which results in user-noticeable problems if audio happened to be playing while the driver is being loaded. There have been user reports of "initializing PortAudio interrupts my audio system-wide" problems for precisely this reason - e.g. spatialaudio/python-sounddevice#496.

I know of end users who have lots of ASIO drivers installed in their system, for good reason (e.g. they are musicians roaming between various audio setups with various hardware). If a user has, say, 10 ASIO drivers installed, then it is utterly unreasonable for any code, including PortAudio, to attempt to load all of them at once without the user explicitly asking for it (with PortAudio it's even worse: that will happen even if the end user does not want to use ASIO at all). It's going to take forever, it may disrupt the ongoing operation of audio hardware, and (most scarily in my opinion) if any of these 10 drivers does anything that could crash, corrupt or otherwise interfere with the host process (not that unlikely given the poor quality of many ASIO drivers), the end user will end up in a perilous situation with no indication of where the problem is coming from (they have no idea what's going on - it's all happening in the background). I don't think many application authors would find this behavior even remotely acceptable. I certainly don't. It's a recipe for frustration.

Though admittedly the ASIO drivers quality is more of a mixed bag.

Precisely. I would not equate ASIO drivers with, say, Windows WDM drivers, which are held to a much higher standard and go through stringent verification requirements. ASIO drivers are not really "drivers" in the OS sense of the term. Rather, they should be seen as random third-party plugin DLLs than anyone and their dog can produce and distribute, with absolutely zero promises of quality or stability whatsoever.

mirh commented 4 weeks ago

Well if you use CMake, it's downloaded for you automatically.

Lool. Touché (even though it's disabled by default).

An unsuspecting PortAudio user would not necessarily expect that just enabling ASIO at build time

I don't think "users" are the sort of people that randomly plays around with compile flags..

I do agree on the possible unsuspectingness though, for the average developer that is at least.

which is much harder to do if drivers are being loaded silently in the background like PortAudio is doing at init time.

Right.. So I suppose here the bigger problem is kinda the lack of lazy loading... Or perhaps, maybe I get portaudio's point in having/pre-loading a list of all the available devices. But couldn't it be possible to just query/list the names of the registered ASIO drivers, without actually even loading their dlls?

only call into purely OS-provided APIs that behave in reliable and predictable ways - they do not load third-party code.

I was actually thinking that likely biggest difference (aside of stability, amateurishness, or whatever) - is that for the OS native apis it would always have itself a cached list that it can then immediately return to applications (and if there were to be any problems with something, they would show even on the desktop with nothing else opened). With asio instead (unless perhaps having asiomulti in-between?) you are effectively also initializing the driver.

dechamps commented 3 weeks ago

I don't think "users" are the sort of people that randomly plays around with compile flags..

To be clear, by "users" I mean users of PortAudio, i.e. application developers. I use the term "end user" to refer to the users of the apps.

But couldn't it be possible to just query/list the names of the registered ASIO drivers, without actually even loading their dlls?

Oh that is absolutely possible, but the problem is, that's not enough. Due to the way the PortAudio API works, it's not just the names you need to know at PortAudio initialization time - you also need to know things like default sample rates and maximum channel counts as well, and that definitely requires loading the driver. That is the root cause of the problem and a fundamental limitation of PortAudio that cannot easily be fixed without rethinking the API. For this reason, I would not expect the issue described in this thread to be resolved anytime soon.

mirh commented 3 weeks ago

Uh, damn. And I suppose it's not possible to just report N/A, null or 0 in those fields? Or somehow ASIO just be a single one entry, which then triggers the rest of its own enumeration only when specifically selected? (like.. surely portaudio has its own way to add or remove devices in the middle of execution?)

Otherwise I mean, I don't see why the simple start_asio idea (an extra property that you have to toggle on at runtime to actually have ASIO to initialize at all) couldn't work. (putting aside that the old as the hills excuse for not having lazy discovery, seems to come from a time when apis were legitimately talking straight with the hardware which I feel should merit a modern round of inquiry from the upper echelons here)

dechamps commented 3 weeks ago

(like.. surely portaudio has its own way to add or remove devices in the middle of execution?)

No it does not.

mirh commented 3 weeks ago

Holy moly... Well then, so I suppose the only thing doable for the time being is guarding PaAsio_Initialize? Or is there also some wacky reason that you can't read/accept parameters until devices are enumerated?