Open knappador opened 5 years ago
Mainloop not being thread safe and including an RC is quite a pain. Implementation in the case that there are several possible reader threads (I have this use case) will require some form of thread parking or possibly scoped threads to hold a mainloop for any length of time. Multiple contexts seems bad style. Basically to make non-blocking calls from an application, you have to poll or implement callbacks into your own event loop mechanism and still pseudo-serialize the calls to pulse or implement a state tracking API around the API :shell: :shell: :shell:
Technically, when cpal
is using ALSA on the properly configured system with PulseAudio installed and running, it's most likely passing the data through to the pulse via the plugin.
See https://wiki.debian.org/PulseAudio (Dynamically enable/disable
section).
That said, I definetly see the value of talking to Pulse directly without going through asla-lib, becuase it adds just another layer of bugs and latency.
it's most likely passing the data through to the pulse via the plugin
Is "it" Cpal or ALSA?
I read the wiki but did not come away understanding an obviously related set of implications. It seems implications could exist both for extending CPAL or configuring PA & ALSA so that CPAL uses PA without libpulse.
On my config, playback is exclusive to either ALSA & cpal or Pulse & all other programs can play at one time. I'm interested in exploring and documenting the topic of how the playback device, ALSA, and PA can interact particular to my use case, but would like to verify what end states I should be trying to reach.
it
is ALSA.
Here's the source of the plugin for more context: https://github.com/alsa-project/alsa-plugins/tree/master/pulse
This is how it works in Ubuntu 18.04, and probably what you'd like to setup to test:
cpal
-> libasound2
(ALSA) -> libasound_module_pcm_pulse
(ALSA plugin) -> libpulse
(PulseAudio).
Obviously, using pulse directly is less bug-prone:
cpal
-> libpulse
(PulseAudio).
That that's not supported by cpal
yet.
Currently, we're suffering from a weird bug that occurs at Ubuntu 18.04 - see #215 - and it seems it's due to that long chain. For me it blocks shipping of the app for linux users, but I weren't able to find a solution or workaround so far.
Wouldn't using ALSA instead of Pulse be preferable, though? Systems with PulseAudio are typically configured to use the alsa plugin, while systems without PulseAudio only have alsa, so software using alsa for output would have the benefit of working on both kinds of systems.
It is reasonable to assume that - after all it's less maintenance that way. However:
as mentioned above, in practice the existing "pulse audio via ALSA" implementation is broken and simply doesn't work on one of the major platforms
This is a practical blocker for shipping the code relying solely on cpal
- as it's not going to work too.
when doing low-latency stuff (which is often the case in audio) it's often preferable to have as few layers of abstraction over the hardware as possible
This is because even if the code is quick it's often doing some extra work that's not really necessary, but adds a bit of latency to the processing. Obviously, this is, in theory, an easy cut for cpal
.
That said, implementing pulse backend also has it's downsides:
In my view it's worth it though because:
The beep demo experiences erratic popping artifacts on my system unless I manually turn up pulse's latency. Other software on my system, generally using pulse natively, doesn't seem to have this problem, so native pulse support seems like it would have good chances of fixing it.
e: Actually, setting the latency did not solve the problem; the artifacts are very erratic so it's hard to tell.
@Ralith is there any chance that there were any applications streaming audio to/from Pulse Audio while you ran the beep example? I believe the default ALSA API (without any plugins) expects the user to have exclusive access to the device, so it's common to get glitches if there is some other stream open accessing the same device via Pulse Audio for example. It can be incredibly difficult to test this as Pulse Audio is really good at magically starting again any time some application wants to play a noise (e.g. even desktop or browser notifications).
Pulse Audio support would be great and is pretty essential to get CPAL used in day-to-day Linux applications, but we must implement something along the lines of #204 to allow the user to select between multiple available APIs on a single system (e.g. ALSA/Pulse/Jack). The ASIO PR #221 makes a start at this in order to allow for selecting between WDM or ASIO on Windows.
is there any chance that there were any applications streaming audio to/from Pulse Audio while you ran the beep example?
I don't think so, though it's hard to be certain. #272 indicates that the issue exists on other platforms, too, so perhaps it's not anything to do with pulse/alsa.
I would be surprised if both those cases were the same problem as almost everything other than the API calls are implemented differently for each backend (e.g. I don't believe there is any looping or timing code shared by the backends).
I don't think so, though it's hard to be certain.
Yeah, I'm using GNOME and in the short time I've had to test I haven't yet worked out a way to confidently and consistently disable pulseaudio without some random background application or notification turning it on again, I think the only way to test for sure is to log out of the DE entirely. I'm not sure if it is the same case for other DEs.
I successfully reproduced the popping with pasystray reporting no clients other than the demo.
Are you able to test ALSA without using pulseaudio at all - e.g. completely disabling it? And making sure that the CPAL application is the only application accessing the audio device? I'm still not convinced it isn't some conflict between pulseaudio access to the device and some (perhaps incorrect) access to the device from the CPAL implementation.
Reproduced the popping with pulse disabled (ps aux |rg pulse
displayed nothing while sound was playing). Still hard to tell whether anything else was accessing the device; alsa empirically doesn't seem to prevent it, as I was able to intentionally play other sounds simultaneously.
This will be obsolete soon. I recommend to invest the effort into PipeWire instead (#554).
Considering the ugly technical challenges with PulseAudio's design (which is why it is being deprecated) discussed above and that PulseAudio will be obsolete soon, I suggest to close this issue in favor of PipeWire #554.
I am not sure if that's a good idea, since not everyone will jump on Pipewire from day one. The question is, what kind of software era this lib wants to support, and if it is anything before "tomorrow" and "cutting edge", then PulseAudio is a must-have in my book.
If there were unlimited labor available, sure, support the legacy API. But there is not, so let's focus on PipeWire. By the time that is done and robust, PulseAudio will be on the way out.
Also, the end result will be much better with PipeWire than PulseAudio and it will probably be easier to implement PipeWire with CPAL's architecture.
Bear in mind that the existing generally-functional alsa backend works decently on top of pulse. The question is whether we need to go to the effort of developing and maintaining a specialized backend in addition to that.
That depends on the application. A simple music player application that only needs to output a stereo signal to whatever is configured as the default output in PulseAudio can make do with that. But creative applications that require user control of multichannel routing to arbitrary destinations cannot choose the devices used with the pulse
virtual ALSA device. It is the same situation with the PipeWire ALSA virtual device.
This issue is about PulseAudio, not PipeWire.
As a user of this library, I would want this to work with Pulse now AND PipeWire in the future. They are separate things.
(As an aside, I have zero interest in using PipeWire in the next 10 years.)
Hi, I've implemented the PulseAudio protocol in rust, continuing a previous abandoned effort: https://github.com/colinmarc/pulseaudio-rs/
Playback is working - here's an example: https://github.com/colinmarc/pulseaudio-rs/blob/main/examples/playback.rs
If there's interest from the maintainers, I'd be willing to contribute an adapter to integrate it into cpal.
As far as the pulse/pw question goes, I think the Pulse API is actually much simpler and easier to use, at least for simple playback, and PipeWire has an embedded pulse server (my library has integration tests that run against both the actual PulseAudio daemon and pipewire-pulse
). A native rust implementation of the Pulse protocol will work on both systems, and is probably the easiest option to maintain in the long run.
Please let me know your thoughts!
I think pipewire considers pulse clients first-class, so that's a fine approach for the foreseeable future, and surely an improvement over the status quo regardless. Thanks for taking this up, and I hope we can see it integrated!
Tagging #250 regarding the sibling Linux sound server. I'm about to release a program under LGPL3 to which I own the full copyright (for now), but I don't want to discourage anyone from harvesting any bits and pieces in the name of getting all sound server API's under one roof, so I released an MIT licensed gist.
The main value of this gist for consumption is having a bit more abstract example than the documentation libpulse. Likely I'm going to overhaul it in the owning repo within the month.
My goal was not to get down to the rust libpulse bindings sys crate or talk directly to the server, but must mention that I quickly developed strong antipathy for the mainloop threaded API, which is inherited from the C client. Possibly the client-server interaction scheme has a deep pathological will to make pseudo-synchronous operations rely on libpulse's behavior and polling loop. Attempting to circumvent libpulse may involve worse hazards than managing them.
Playing directly to ALSA is a bad idea on Linux as it takes exclusive access to devices, and it's a bit weird to create monitors to listen to what other programs play.