-
Notifications
You must be signed in to change notification settings - Fork 21
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
Add PulseAudio backend to SuperCollider #11
base: main
Are you sure you want to change the base?
Conversation
Initial draft of RFC for pulseaudio
At some point I was interested in the option to use SC on Linux without JACK. I haven't tried but I was wondering whether building with PortAudio would allow to achieve that? (I'm not a primarily a Linux user and I haven't followed any possible PortAudio - PulseAudio incompatibilities). |
If I understand correctly, the currently experimental PortAudio backend would connect directly to ALSA. For the casual user (e.g. somebody who is interested in live coding but who is not interested in esoteric Linux configuration, who installed TidalCycles or FoxDot, and then found out that they have to do extra stuff, potentially complex stuff, to get any sound at all), ALSA configuration is not simpler than JACK configuration. So PA does (potentially) have the benefit of a shorter sequence between installation and making noise. I think a PA backend would also require the server devices primitive in sclang. Currently The factors as I see them are the maintenance burden (which I think will be higher than the estimate in this RFC but probably not terribly high) vs the support cost of the bug reports filed by Tidal/FoxDot/Sonic Pi users who can't get sound right away. The latter would be very very nice to resolve and good public relations for the SC community, so I'd lean in favor of having the option of a SC/PA build that might be easier to bundle with various live coding environments. |
As I've dug a little into this, it seems PortAudio -> PulseAudio is possible through the ALSA compatibility layer (albeit not an ideal case), based on this report.
I think this should already be implemented - I've added PortAudio device listing to be used on Windows (since 3.11). This code is enabled based on backend choice, and not on the platform itself, so if PortAudio backend is chosen, sclang should also use PA for listing devices. Looking up "portaudio pulseadio" in a search engine brings out https://github.com/bkgood/portaudio-pulseaudio |
The analyses of the problem isn't very good I think. Tell me on which Linux distribution JACK is not available please. Configuration isn't that hard as well, with the good resources. Ardour uses ALSA as default now, but it has it's focus on plugins, not external programs. Pulseaudio is a option now too maybe, for cheap (bluetooth?) devices? But afaik that's not for serious work as what you would expect with SuperCollider. But at least you can ask the Ardour team on advise. Pipewire seems to want to bridge the different audio sytems on Linux: https://pipewire.org/ I'm a happy JACK user though. |
Having portaudio on Linux or Jack on windows is mostly done, only a few tweaks are needed for that. Another path to consider is to add an RtAudio backend which works on Linux, Window and Macintosh OS X. |
Thank you for the feedback. Just some comments below.
I had considered going the rtaudio route, but I thought a direct native approach would have more perfrmance. For example, the rtaudio pulseaudio is using the "simple" API on pulseaudio, not the full async one.
|
@jamshark70 , thank you for your feedback. Yes, I take it there might be some more work to do on other fronts as well, but in general this seems quite well contained. I am happy to make the necessary changes in sclang or other places, with a bit of guidance from someone that knows those areas. I think you hit the nail in the head with how much this would help other communities that are using SuperCollider as the backend. These people are normally not SC experts, nor audio experts, nor linux experts, so configuring things that do not work out of the box is a big barrier of entry for them. That's why I believe such a PulseAudio backend will help spread SC in those places. And according to the basic proof of concept I have, supporting a basic configuration would not be that difficult. |
@grammoboy2 , thanks for your comment. The thing is that there are Linux distributions where using Jack involves making changes to the system, it does not work out of the box. Now, for someone tech-savvy, those things probably amount to nothing, but for the majority of people using those systems, it can be something next to impossible to do. The idea is not to remove Jack and use PulseAudio, this is about giving the chance to use PulseAudio on the systems where Jack is hard to configure and use. So for people like you, which are happy with Jack, there will be no change at all. To reiterate, this just to lower the barrier of entry to SuperCollider (and SW that uses SC as a backend), on systems where Jack is hard. |
Just an example: On Ubuntu, the default audio backend is PulseAudio, and while you can use Jack, from what I know, configuring it is not straightforward for someone that is not tech-oriented. Keep in mind that a lot of people using Ubuntu and related systems are not experts, they are just everyday users that want to get some work (or music ;)) done. If we could give them a user experience where they could just start using SuperCollider, Tidal, Sonic Pi, whatever, without having to go hunting around forums for how to use Jack in there, I believe the SuperCollider adoption would be quite higher. |
The best thing with RtAudio is that it is very alive and responsive repo: thestk/rtaudio#213 and other issues and additions. And given that portaudio is not an alive project it could break in the near future so that RtAudio would be a good replacement that unifies the three major OSes. Perhaps a longer but very productive path (for all the opensource community) would be: apply your async PulseAudio knowledge to extend RtAudio and then make an RtAudio backend to SC?
I can only elaborate for Jack on windows : supercollider/supercollider#3692 |
@sonoro1234, I think what I'll do is finish my simple proof of concept using pure pulseaudio and then try using it through rtaudio, and then see which one looks better |
Hi, so I think I have got this in a mature enough state in my branch, and the code is ready for a Pull Request. I have asked around in the dev channel, but mention it here too. |
I think making SuperCollider more widely available is a good thing, but I worry that PulseAudio users could mistake the poor performance of PulseAudio for SuperCollider problems. Once you get beyond the simple kinds of livecoding use cases then users will likely run into timing, latency and dropout issues. And while you could do a live gig using Pulse Audio, it's probably not the greatest idea. Maybe some documentation could be added both in the downloads/install section of the website, and in the SuperCollider documentation that makes it clear that if the user is experiencing performance issues, and they're using the JACK version, then they should switch to the JACK version. |
Thats great!!. So if I correctly understand SC has now a RtAudio interface (not only for PulseAudio). |
I just used the already existing one. The limitations of the RtAudio
implementation will not affect the usage on SuperCollider, so I am happy
about that.
Just a clarification to your comment: the RtAudio instantiation is limited
to PulseAudio in the implementation (I mean that it is instantiating a
PulseAudio backend). For now, I believe that's the best way, to make sure
that the changes are self-contained and do not affect other architectures.
But yes, in the future it should be very simple to use this same RtAudio
implementation for Windows and Mac, and it will use the native backends in
there. That is not mandatory, though, and if people are happy with the
current implementations in those architectures, then there is no need to do
anything, and the PulseAudio feature will not interfere at all with them.
|
Or may be also in Linux with OSS, ALSA or Jack. |
Yes, perhaps. But for now, I prefer not to touch the jack backend at all, since that will require much more thought and consensus within the group. I want to keep this specific RFC very focused on providing an alternative pulseaudio backend on systems where jack is hard to set up. Not more, not less. That it might perhaps be used in the future to consolidate work (and ease maintenance), is a bonus, but I don't want to center the discussion around that. |
For a discussion of why we should have a PulseAudio backend for SuperCollider on Linux, see supercollider/rfcs#11. It is important to understand that this is not meant to be a replacement for jack at all. This is just to give an option on systems where jack is difficult to set up. jack will continue to be the default. This PR adds support for PulseAudio, both inputs and outputs. The device selection is done outside SC, as per PulseAudio philosophy, where applications output to a default sink, and get input from a default source, and the actual connections happen on the system's setup / PulseAudio control applications. The changes are pretty self contained, with just one C++ file added, and then some changes to CMakeLists and READMEs as required. The selection of frontend is done at build time, and by default the backend will continue to be jack. This will only try to use the PulseAudio backend if instructed explicitly to do so, using the AUDIOAPI cmake variable. So, for users that are currently happy with their setup, using jack, this change will not affect them at all and will be completely transparent. On systems where it is difficult to use jack, the user / maintainer can set the cmake variable to pulseaudio, and then, and only then, it will use the PulseAudio backend. As you can see the code is not too complex, and should be easy to maintain. Note that the expectation is that the PulseAudio backend will be used in simple-ish systems, so we may not want to support complex / exotic audio configurations, and encourage people to use jack for that.
Yes, of course, in the future |
I support making PulseAudio usable for people who can't install and configure JACK on their system. Assuming of course that performance is reasonably acceptable, that we clearly communicate PulseAudio as an experimental feature, and that we do our utmost to help users make use of JACK by way of documentation and community support. |
Hey @llloret , just read the RFC and this discussion, i'm definitely in support of this. I have a few questions and concerns for you and for some other people in this thread. First, i think this should be documented in the RFC text: on which systems can Jack not be obtained, and on which systems is it difficult to configure (and why?). you've answered that here but it's a big question mark for me when i first read the RFC. I have concerns about using rtaudio for this, after seeing the comment in this issue:
even if rtaudio is responsive, i'm not sure i trust their implementation at the moment. i think i'd recommend to use PulseAudio's API directly. to quote from my comment on the PR:
|
@brianlheim, thanks for the feedback. Let me try to address your concerns. In the testing I have done so far, I have not found any issues regarding stability, dropouts, etc. Yes, there is a mutex in the audio callback, but the only contention points are in calls related to starting, stopping or aborting the stream, which is something that we are not doing while streaming, so I am not too worried about that. The audio callback will be able to fetch the mutext instantly every time it needs to. If we went the direct pulseaudio way, it is very possible we would have to implement the same mutexes to make sure that it does not break while you are starting or stopping the stream. On things about performance, I tend to believe that the proof is trying and testing. I don't think that mutex there will hurt at all. Also, my initial concern about RtAudio using the "simple" pulseaudio API turned out to be unfounded. That API is enough to deal with one stream (multi-channel in and out) of audio per application, which is all that we need. I was confused by the meaning of one stream, thinking it was just in OR out, but it turns out it can do both. What I would suggest is people try the current implementation and see how well it is working for them. |
That's brilliant. Really glad to hear that. |
yes, yaml-cpp is an example of this. |
I cant understand the motivation of package maintainers for wanting us to take care of devendored dependency when we are not touching installation but just use vendored dependency for statically linking. What I am missing? |
Going from memory, the steps include:
Much of this could be scripted, but if something goes wrong, AFAICS the fallback is manual. I'm not intimate enough with shell scripting to know how robust a script would be. (Even installing JACK itself -- jack1 and jack2 are mutually incompatible; if our script mandates one and not the other, it can cause serious dependency hell in some environments.) If we could be reasonably sure a script would be reliable in a large percentage of environments, I'd be ok with that too. |
@sonoro1234 , @dvzrv is usually the one to request devendoring so i will let him answer in more detail. regardless, i do not want this dependency in our codebase at all, at least when there are viable alternatives. i am saying this as the person who is typically coordinating and managing our vendored dependencies. |
Adding some documentation, while certainly helping a number of users, will not help much the non tech oriented people that we would to like to help with this new backend. I am thinking about people that are not tech savvy at all, so that anything that is not working out of the box might be too much for them. I agree that they could perhaps run a simple script (if you can get them to find that script in the first place), but if things do not work as expected, then they are completely blocked and unable to use the SW. Apart from having to maintain those scripts on different platforms, it seems the kind of thing where we could potentially be getting lots of question about specific steps in such scripts not working as expected.
I think that the PulseAudio backend is the way to go in this regard, because it can offer a decent SuperCollider experience out of the box, that integrates nicely with what a lot of Linux distributions are working with regarding audio. Whether we like it or not, most Linux distributions are using PulseAudio as the audio backend, so offering something that works with that is a worthwhile goal, in my view. Of course, we want users that have the skills to be able to continue using the jack backend, but adding the PulseAudio backend does not detract from that at all. |
just wanted to leave a note that i haven't given up on this RFC, just kinda busy right now with non-SC related personal issues. this is at the top of my priority list when i can make time again! |
coming back to this now, i'm of the opinion that (1) this should be runtime selected, and (2) should be achieved without any new vendored dependencies. i'm going to use the term 'server-backend' to refer to what is called a "backend" in scsynth and supernova to disambiguate it from the other meanings of 'backend'. the server-backend should be runtime selectable because package maintainers shouldn't have extra work to do, and users shouldn't have to build an alternate configuration themselves if the point is to provide options to technologically incapable users. the PulseAudio server-backend should be implemented without any new vendored dependencies because it seems that would be an easy thing to do, and because maintainers don't want to manage more vendored dependencies. if rtaudio is not reliably obtainable from package managers, then i would recommend using something else or writing this server-backend directly against the PulseAudio API. |
FWIW I agree with both of these. Practically speaking, it won't be released otherwise. |
if runtime selection is to be done, it will be a major change: As for the vendoring issue I have not any new feedback from @dvzrv #11 (comment) |
I suppose an alternative might be to ship two scsynth binaries in Linux. The main points are: We can't ask novice users to build scsynth for PulseAudio, and we can't ask release managers to issue two separate releases for Linux. That means either one scsynth binary that can choose the backend at launch time, or two binaries (which could be just adding another build target). I'm not sure it does have to be extended to Mac. The specific purpose is to allow Linux users to skip JACK installation and configuration. Adding a command line option for that purpose doesn't absolutely require implementing it in all OSes. (macOS users don't have to deal with RT privileges, thread priority and interfacing with non-JACK apps.) |
adding a new target in the build system and getting all the logic and documentation around that right would seem to be comparable difficulty to making the scsynth-backend runtime selectable. in order to do the latter, as @sonoro1234 and @scztt have pointed out there's one function that has to change a bit and possibly take a new parameter, then update some uses of the preprocessor and make some changes in the build system. i'm happy to give people pointers on implementation and to review the PRs. the virtual class hierarchy to support this is already there, and it will be adding a feature several people already want. this is the solution we'd want long term, and all the alternative solutions proposed would require a similar amount of effort. is it easier to do this only on Linux or on all platforms at once? not sure, that would probably be up to the implementer. i agree with @jamshark70 that it doesn't have to happen everywhere.
this thread has some context around the problem. we don't need to wait for him to reply here, because i'm saying it's not going to happen. |
I understand that. |
Sorry for the late reply. I'm on too many bug trackers and tickets... In regards to the vendored (aka. bundled) libraries I'll just refer to Fedora's excellent writeup on that topic: https://fedoraproject.org/wiki/Bundled_Libraries?rd=Packaging:Bundled_Libraries In regards to the general notion of this pull request: I'm happy to see, that time is invested in an alternative backend for Linux, as portaudio as a project is pretty much dead. @llloret as you have spent some time with this, what made you choose rtaudio over directly implementing against libpulse? I'm curious (from an implementational point of view) as the direct dependants of libpulse outweigh the direct dependants of rtaudio by far (on Arch at least). Also, pipewire lurks on the horizon. :) |
That's fine. I am happy with that. I will work with the system's rtaudio version, that seems to offer enough functionality at the moment, and will be improving in the future. Regarding the build time vs launch time (I prefer to be specific about the selection being at launch time, not at runtime - we will not be supporting changing the backend while SC is already running, since that introduces what I think is unnecessary complexity - people will know what server backend they want to use at lauch time)... for what it's worth, I have done some prototyping about it, and it is doable witout too much new code. It would be easier if the selection is done with an environment variable, instead of with a program argument, because that way there is no need to pass that argument around the different SC layers, which I am not familiar with. Besides, having an environment variable might be an easier way for distributors to select the default backend. Thoughts? |
I tried a pilot implementation with both libpulse and rtaudio and the rtaudio one felt more natural and maintainable. That's the main reason. Don't get me wrong, I think that the libpulse library is great, but using it directly introduces a number of complexities like having to convert from asynchronous operations to synchronous ones, which is quite tedious. rtaudio did this for me and covered all the functionality that we wanted to start with, so I went with it. Another potential advantage (although I prefer to decouple that from this PR), is that in the future, it might allow us to use it for other OSs (for example Windows) is we feel it is good enough. |
it should be a program argument. a couple reasons why:
i don't understand why that would be easier, but regardless the default scsynth-backend should remain jack, without qualification. that's what we've already agreed on, correct? |
I would always prefer explicit implementation (i.e. a flag parameter to scsynth) over implicit implementation (i.e. an environment variable that may or may not be set). Also, environment variables really don't help too much (as a default), because there are many different desktop environments and/or window management systems in use. It's very hard to get that right and e.g. the desktop entry specification also only points at "the desktop environment" for setting environment variables. At this point this could be your shell, logind, or any of the various desktop environments. However, environment variables as an additional way of setting the backend could be useful. |
Ok, so the default behaviour, which is when no environment variable is selected would of course be to run Jack, no changes there; this is one of the hard constraints of my design. But if a distribution (or a user), prefers to use pulseaudio, then it is a matter of setting that specific environment variable at a system level, and then users do not need to know that they have to launch with a specific flag on scsynth, which will make it easier to use out of the box for these users.
I generally agree, but keep in mind that there are environment variables already being used to control the behaviour on other parts of SuperCollider, so this would not go against the alrady existing ethos. People would not generally need to see this variables, the distributor could take care of that for them, right?
The reorganizing needs to be done regardless of whether we end up controlling through a program argument or environment variables. What I do not like is that if it is a program argument, I believe there will be a need to carry that through a number of functions / methods, so that it reaches the instantiation of the specific backend, which will require a number of simple changes along the path. With an environment variable, we just need to check it in one place and there is no need to carry that information around.
As you said, almost all of them are taken as options; in this case I believe there is a compelling case to use an enviroment variable itself. It simplifies the use case that we are looking for (where a non technical user would not need to do anything special when launching), and it simplifies the implementation. This would also apply to 3rd party music applications that use SC in the background since the backend woul d be configured at the system level, without a need to check what flags need to be used to launch. |
So, would it not be possible to have something at the (for example) raspbian (or other) distribution that configured a given environment variable for terminals (including ssh) or desktop launches? |
My two cents: We already have at least these environment variables: SC_SYSAPPSUP_PATH Other way setting the command line wouldnt be to much work: in scsynth_main we have
|
No, not every distribution applies extreme modification to everything they package (such as Debian and derivatives).
Especially in the case of The When looking at the
I see no reason why not to add a flag for setting an audio backend there.
@llloret Still, someone has to configure this. I don't want to make the choice for all users of a distribution. Sorry, but environment variables (as the only option) for setting an audio backend makes no sense. Auto-detecting running backends or giving the user choice is. To give a great example of a similar mess in regards to environment variables: By default jack2 is auto-started by whichever variant that is configured as default during compile-time (jackd or jack-dbus) when a jack client triggers it. |
i agree 100% with what @dvzrv wrote, he said it much better than i could. perhaps we add an environment variable later if there's a demonstrated need, but for a first implementation a command-line option is a must-have. |
FYI: Pipewire looks to become the near future on the Linux platform Abstract: PipeWire is a low-level multimedia library and daemon that facili-tates negotiation and low-latency transport of multimedia content be-tween applications, filters and devices. It is built using modern Linuxinfrastructure and has both performance and security as its core de-sign guidelines. The goal is to provide services such as JACK andPulseAudio on top of this common infrastructure. PipeWire is mediaagnostic and supports arbitrary compressed and uncompressed for-mats. A common audio infrastructure with backwards compatibilitythat can support Pro Audio and Desktop Audio use cases can poten-tially unify the currently fractured audio landscape on Linux desk-tops and workstations and give users and developers a much betteraudio experience. |
Not to derail completely from the PulseAudio subject here. Or maybe I am :) Latency
|
This would be so nice to have. A small @brianlheim @dvzrv @llloret how is this coming along? Anything that can be done to help? |
I think this a/ is expected and b/ doesn't matter for the proposed use case. An alternate audio backend is for users who want to get sound out of scsynth quickly, with minimum configuration -- users testing out Tidal or FoxDot. These users don't have a commitment to attain low latencies -- and if their needs change ("how can I live code along with my guitar?"), then the advice should be "you really need JACK for this." |
As far as I understand it, Pipewire will solve this issue in about a year (if they can accomplish what they think they can). So people might not get the same latency as with JACK, but they don't have to launch JACK to work with SC anymore. PipeWire handles it for them. JACK and PulseAudio will coexist under Pipewire. |
I think that the proposal retains its relevance, although certain contextual elements have evolved:
See more recent latency benchmarks here : https://gitlab.freedesktop.org/pipewire/pipewire/-/wikis/Performance#latency
|
Summary:
On some Linux systems Jack is either not available or difficult to configure.
Users and distribution maintainers should have the option to use a PulseAudio backend instead.
This RFC is about adding a new PulseAudio backend to SuperCollider.
Jack will remain the default choice since it has technical advantages.