From 0aadc0450d7ad24103cfb70b808ae1ed3c5099c7 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 2 Mar 2021 15:03:27 +0100 Subject: [PATCH] alsa: implement poll_descriptors In there we can evaluate the poll fd and make sure it blocks or not in the following poll based on the buffer filled levels. Some API is very sensitive about this, it seems. Fixes #433 --- pipewire-alsa/alsa-plugins/pcm_pipewire.c | 44 ++++++++++++++++++----- 1 file changed, 35 insertions(+), 9 deletions(-) diff --git a/pipewire-alsa/alsa-plugins/pcm_pipewire.c b/pipewire-alsa/alsa-plugins/pcm_pipewire.c index 55c68d5b9..51c6be026 100644 --- a/pipewire-alsa/alsa-plugins/pcm_pipewire.c +++ b/pipewire-alsa/alsa-plugins/pcm_pipewire.c @@ -94,22 +94,31 @@ typedef struct { static int snd_pcm_pipewire_stop(snd_pcm_ioplug_t *io); +static int block_check(snd_pcm_ioplug_t *io) +{ + snd_pcm_pipewire_t *pw = io->private_data; + snd_pcm_sframes_t avail; + uint64_t val; + + avail = snd_pcm_ioplug_avail(io, pw->hw_ptr, io->appl_ptr); + if (avail >= 0 && avail < (snd_pcm_sframes_t)pw->min_avail) { + spa_system_eventfd_read(pw->system, io->poll_fd, &val); + return 1; + } + return 0; +} + static int pcm_poll_block_check(snd_pcm_ioplug_t *io) { - uint64_t val; - snd_pcm_sframes_t avail; snd_pcm_pipewire_t *pw = io->private_data; if (io->state == SND_PCM_STATE_DRAINING) { + uint64_t val; spa_system_eventfd_read(pw->system, io->poll_fd, &val); return 0; } else if (io->state == SND_PCM_STATE_RUNNING || (io->state == SND_PCM_STATE_PREPARED && io->stream == SND_PCM_STREAM_CAPTURE)) { - avail = snd_pcm_avail_update(io->pcm); - if (avail >= 0 && avail < (snd_pcm_sframes_t)pw->min_avail) { - spa_system_eventfd_read(pw->system, io->poll_fd, &val); - return 1; - } + return block_check(io); } return 0; } @@ -117,8 +126,14 @@ static int pcm_poll_block_check(snd_pcm_ioplug_t *io) static inline int pcm_poll_unblock_check(snd_pcm_ioplug_t *io) { snd_pcm_pipewire_t *pw = io->private_data; - spa_system_eventfd_write(pw->system, pw->fd, 1); - return 1; + snd_pcm_uframes_t avail; + + avail = snd_pcm_ioplug_avail(io, pw->hw_ptr, io->appl_ptr); + if (avail >= pw->min_avail || io->state == SND_PCM_STATE_DRAINING) { + spa_system_eventfd_write(pw->system, pw->fd, 1); + return 1; + } + return 0; } static void snd_pcm_pipewire_free(snd_pcm_pipewire_t *pw) @@ -147,6 +162,15 @@ static int snd_pcm_pipewire_close(snd_pcm_ioplug_t *io) return 0; } +static int snd_pcm_pipewire_poll_descriptors(snd_pcm_ioplug_t *io, struct pollfd *pfds, unsigned int space) +{ + snd_pcm_pipewire_t *pw = io->private_data; + pcm_poll_unblock_check(io); /* unblock socket for polling if needed */ + pfds->fd = pw->fd; + pfds->events = POLLIN | POLLERR | POLLNVAL; + return 1; +} + static int snd_pcm_pipewire_poll_revents(snd_pcm_ioplug_t *io, struct pollfd *pfds, unsigned int nfds, unsigned short *revents) @@ -523,6 +547,7 @@ static int snd_pcm_pipewire_start(snd_pcm_ioplug_t *io) pw_thread_loop_lock(pw->main_loop); pw_log_debug(NAME" %p:", pw); pipewire_start(pw); + block_check(io); /* unblock socket for polling if needed */ pw_thread_loop_unlock(pw->main_loop); return 0; } @@ -771,6 +796,7 @@ static snd_pcm_ioplug_callback_t pipewire_pcm_callback = { .delay = snd_pcm_pipewire_delay, .drain = snd_pcm_pipewire_drain, .prepare = snd_pcm_pipewire_prepare, + .poll_descriptors = snd_pcm_pipewire_poll_descriptors, .poll_revents = snd_pcm_pipewire_poll_revents, .hw_params = snd_pcm_pipewire_hw_params, .set_chmap = snd_pcm_pipewire_set_chmap,