spatialaudio / python-sounddevice

:sound: Play and Record Sound with Python :snake:
https://python-sounddevice.readthedocs.io/
MIT License
980 stars 145 forks source link

Add an environ flag to load an alternative PortAudio Windows binary compiled without ASIO #498

Closed arkrow closed 1 month ago

arkrow commented 8 months ago

This PR provides a very simple and minimal workaround for loading an alternative PortAudio Windows binary compiled without ASIO, to address issue #496. Since this issue only affects Windows, as far as I know, no changes have been made to the other platforms.

An alternative PortAudio binary will need to be added to the _sounddevice_data repository (e.g. named libportaudio64bit-noasio.dll). It will then be bundled like the other binaries in the built package and can then be used instead of the default using the os.environ["SD_WIN_DISABLE_ASIO"] flag.

pep8speaks commented 8 months ago

Hello @arkrow! Thanks for opening this PR. We checked the lines you've touched for PEP 8 issues, and found:

Line 78:80: E501 line too long (83 > 79 characters)

mgeier commented 8 months ago

Thanks for this PR!

I was hoping for a more general solution for choosing the DLL/dylib/so, similar to how it was discussed in #130.

But before even going down the environment variable path, I would like to know how ctypes.util.find_library() would find a user-provided DLL without having to use an env var.

I know that this works on Linux and I assume that it works on macOS as well and it would be good to know how to make this work on Windows as well. Maybe that would already be enough for selecting a custom DLL?

arkrow commented 8 months ago

I was hoping for a more general solution for choosing the DLL/dylib/so, similar to how it was discussed in #130.

I think the most promising approach would be building libportaudio as part of the wheel build process, as mentioned in #130, and accepting ASIO as a flag in package extras as I mentioned in #496. If that can work on all systems without additional prerequisites, that would be the ideal solution. If I can get the solution up and running, I'll open a new PR.

Alternatively, as part of the suggested solutions in #130, I've opened a PR (#499) that loads a user-specified PortAudio binary during runtime, which is more general than this PR and has been requested by other users.

But before even going down the environment variable path, I would like to know how ctypes.util.find_library() would find a user-provided DLL without having to use an env var.

That would be difficult to do dynamically (without hard-coding) unless the values is retrieved from somewhere, which is why os.environ is a viable and often used approach. os.environ is also not permanent and its scope extends to the current python process only, avoiding any problematic PATH changes, so it should be safe to use on all platforms.

mgeier commented 8 months ago

That would be difficult to do dynamically (without hard-coding)

Do you mean hard-coding the absolute path to the DLL? What about just hard-coding a file name?

According to https://docs.python.org/3/library/ctypes.html#finding-shared-libraries:

On Windows, find_library() searches along the system search path, and returns the full pathname, but since there is no predefined naming scheme a call like find_library("c") will fail and return None.

So if you put a correctly named DLL somewhere into the system search path (whatever that means exactly), it should be found, right? Do you know what the system search path is?

In case this hasn't been obvious already: I'm not a Windows user, so you can assume zero knowledge from my side.

mgeier commented 5 months ago

See my comment https://github.com/spatialaudio/python-sounddevice/issues/496#issuecomment-1902706025

This doesn't provide an environment variable, but it involves downloading the appropriate DLL, renaming it and moving it into a specific folder.

I think that would still be easy enough for the (few?) people who need ASIO, what do you think?

mgeier commented 1 month ago

In #539, I'll switch to DLLs without ASIO by default. This also adds documentation for how to download and use DLLs with ASIO, if needed.

I think this makes this PR obsolete, right?

arkrow commented 1 month ago

Since the default behavior is without ASIO, this PR is now obsolete. Though it's inverse can be considered if both binaries are to be shipped together and enabled conditionally; that might be a good middle-ground for developers depending on ASIO support with this library. That said, the PR will be closed for now.