Calling snd_pcm_drain and snd_pcm_prepare stops sound playback (snd_pcm_writei hangs in poll())
If you are filing this issue with a regular release please try master as it might already be fixed.
Version, Distribution, Desktop Environment:
- pipewire-git/pipewire-alsa-git 0.3.32.43.g44583367-1, commit 44583367 (current master)
- Arch Linux
- KDE Plasma X11
Description of Problem:
When testing RtAudio apps running under pipewire-alsa
, I found that when BambooTracker was set to use ALSA (the default
device aliasing to pipewire
), the audio thread would hang after I opened a document.
How Reproducible:
Always
Steps to Reproduce:
- Install pipewire[-git] and pipewire-alsa[-git] on a system, and uninstall pulseaudio-alsa if present. Start the pipewire daemon.
- On Arch, the pipewire-alsa[-git] package will produce "/etc/alsa/conf.d/99-pipewire-default.conf" which sets the
default
ALSA device to point topipewire
. If not present on your distro, copy/link it somehow. - Clone BambooTracker git master from https://github.com/BambooTracker/BambooTracker, and build and run it. (On Arch, you can install aur/bambootracker-git.)
- There are prebuilt binaries at https://github.com/BambooTracker/BambooTracker/releases/download/v0.4.6/BambooTracker-v0.4.6-linux.zip, but it's 124 megabytes and is some strange nix-os shell script thing.
- In File -> Configuration -> Sound, by default the API should be set to ALSA and Device to default. If not, set it that way. Then click OK to close the Configuration dialog.
- Press the "New" toolbar icon. The audio thread is now locked up.
- To hang the app UI (due to mutex contention), press the "New" icon a second time.
Actual Results:
Audio thread hangs when loading a new file.
Expected Results:
Audio thread continues working when loading a new file. This issue does not occur with pulseaudio-alsa (along with either pulseaudio or pipewire-pulse).
pw-dump -N > file
(As Attachment Please):
Additional Info Eg. pwdump (pw-dump output doesn't change between before/after the audio thread hangs, aside from pw-dump itself being a different process.)
Through breakpoints, debug logs, and ltrace, I traced this down to BambooTracker's UI thread calling:
-
RtApiAlsa::stopStream()
snd_pcm_drain
-
RtApiAlsa::startStream()
snd_pcm_prepare
This is followed by both function calls again. (The program is janky.) However, the hang still occurs if I modify the program to only call each method once, by commenting out "BambooTracker/gui/mainwindow.cpp" MainWindow::assignADPCMSamples()
's function body.
Meanwhile, the audio thread is repeatedly calling:
-
RtApiAlsa::callbackEvent()
-
snd_pcm_writei
among other functions
-
The first few calls to RtApiAlsa::callbackEvent()
would succeed, but then snd_pcm_writei
would hang in a poll
call:
#0 0x00007ffff66a0b2f in poll () from /usr/lib/libc.so.6
#1 0x00007ffff7e9d7de in snd1_pcm_wait_nocheck () from /usr/lib/libasound.so.2
#2 0x00007ffff7ea1842 in snd1_pcm_write_areas () from /usr/lib/libasound.so.2
#3 0x00007ffff7eabf3f in snd_pcm_mmap_writei () from /usr/lib/libasound.so.2
#4 0x00007ffff7ee34e2 in snd_pcm_ioplug_writei () from /usr/lib/libasound.so.2
#5 0x00005555557e9c36 in RtApiAlsa::callbackEvent() ()
#6 0x00005555557ea46f in alsaCallbackHandler(void*) ()
#7 0x00007ffff6af7259 in start_thread () from /usr/lib/libpthread.so.0
#8 0x00007ffff66ab5e3 in clone () from /usr/lib/libc.so.6
(I read that ALSA functions operating on handles are not thread-safe unless synchronized with mutexes. From my reading of the code, I think RtApiAlsa::stopStream()
, RtApiAlsa::startStream()
, and RtApiAlsa::callbackEvent()
all properly acquire mutexes while calling snd_pcm_*
functions, so I think it's following the ALSA contract.)
If I run PIPEWIRE_DEBUG=4 BambooTracker
, after the hang occurs, I see nonstop:
[D][13340.529630][ pcm_pipewire.c: 377 on_stream_drained()] alsa-plugin 0x556530a08170: drained
pipewire-debug I ran a trace of PIPEWIRE_DEBUG=4 BambooTracker
. (Higher levels would generate spam logs nonstop even before the hang occurred.) I think the relevant events are emitted by pcm_pipewire.c
, starting at snd_pcm_pipewire_drain
.
I suspect pipewire-alsa
is mismanaging its buffers such that calling snd_pcm_drain
and snd_pcm_prepare
causes snd_pcm_writei
to stop draining.
Notes
I found a similar but not identical issue from 2010, caused by snd_pcm_pause
rather than snd_pcm_drain
: [alsa-devel] Hang in snd_pcm_writei with alsa-pulse plugin