]> git.alsa-project.org Git - alsa-lib.git/commitdiff
pcm: improve handling for snd_pcm_wait()
authorJaroslav Kysela <perex@perex.cz>
Tue, 2 May 2023 14:56:49 +0000 (16:56 +0200)
committerJaroslav Kysela <perex@perex.cz>
Wed, 3 May 2023 13:59:15 +0000 (15:59 +0200)
The snd_pcm_wait() function is called also internally from
the various plugins to wait for the drain with -1 and from i/o
routines in pcm.c.

Define two special negative timeout values to distinguish the
drain and i/o wait and calculate the maximal timeout according
the wait place.

Fixes: https://github.com/alsa-project/alsa-lib/issues/228
Signed-off-by: Jaroslav Kysela <perex@perex.cz>
include/pcm.h
src/pcm/pcm.c
src/pcm/pcm_dmix.c
src/pcm/pcm_dshare.c
src/pcm/pcm_dsnoop.c
src/pcm/pcm_ioplug.c
src/pcm/pcm_rate.c
src/pcm/pcm_share.c
src/pcm/pcm_shm.c

index 966d6ffd881f9c8565e27cfc15cc5255400922aa..25cd12d1e4a2d84b9a24b1499f3ab8e384165a6c 100644 (file)
@@ -498,6 +498,13 @@ typedef union _snd_pcm_sync_id {
        unsigned int id32[4];
 } snd_pcm_sync_id_t;
 
+/** Infinite wait for snd_pcm_wait() */
+#define SND_PCM_WAIT_INFINITE          (-1)
+/** Wait for next i/o in snd_pcm_wait() */
+#define SND_PCM_WAIT_IO                        (-10001)
+/** Wait for drain in snd_pcm_wait() */
+#define SND_PCM_WAIT_DRAIN             (-10002)
+
 /** #SND_PCM_TYPE_METER scope handle */
 typedef struct _snd_pcm_scope snd_pcm_scope_t;
 
index 997a8a6acddfc0f17117c32593d94ae6b39e2954..01c624d323bf06487c2b09f815f4d6c242556129 100644 (file)
@@ -2834,7 +2834,8 @@ int snd_pcm_open_named_slave(snd_pcm_t **pcmp, const char *name,
  * \brief Wait for a PCM to become ready
  * \param pcm PCM handle
  * \param timeout maximum time in milliseconds to wait,
- *        a negative value means infinity
+ *        a -1 value means infinity (SND_PCM_WAIT_INFINITE),
+ *            see also SND_PCM_WAIT_IO and SND_PCM_WAIT_DRAIN
  * \return a positive value on success otherwise a negative error code
  *         (-EPIPE for the xrun and -ESTRPIPE for the suspended status,
  *          others for general errors) 
@@ -2869,6 +2870,37 @@ int __snd_pcm_wait_in_lock(snd_pcm_t *pcm, int timeout)
        return snd_pcm_wait_nocheck(pcm, timeout);
 }
 
+static int __snd_pcm_wait_io_timeout(snd_pcm_t *pcm)
+{
+       int timeout;
+
+       /* period size is the time boundary */
+       timeout = (pcm->period_size * 1000ULL) / pcm->rate;
+       /* should not happen */
+       if (timeout < 0)
+               timeout = 0;
+       /* add extra time of 200 milliseconds */
+       timeout += 200;
+       return timeout;
+}
+
+static int __snd_pcm_wait_drain_timeout(snd_pcm_t *pcm)
+{
+       int timeout;
+
+       /* for capture, there's no reason to wait, just one iteration */
+       if (snd_pcm_stream(pcm) == SND_PCM_STREAM_CAPTURE)
+               return 0;
+       /* result is in milliseconds */
+       timeout = (snd_pcm_mmap_playback_delay(pcm) * 1000LL) / pcm->rate;
+       /* should not happen */
+       if (timeout < 0)
+               timeout = 0;
+       /* add extra time of 200 milliseconds */
+       timeout += 200;
+       return timeout;
+}
+
 /* 
  * like snd_pcm_wait() but doesn't check mmap_avail before calling poll()
  *
@@ -2895,6 +2927,12 @@ int snd_pcm_wait_nocheck(snd_pcm_t *pcm, int timeout)
                SNDMSG("invalid poll descriptors %d\n", err);
                return -EIO;
        }
+       if (timeout == SND_PCM_WAIT_IO)
+               timeout = __snd_pcm_wait_io_timeout(pcm);
+       else if (timeout == SND_PCM_WAIT_DRAIN)
+               timeout = __snd_pcm_wait_drain_timeout(pcm);
+       else if (timeout < -1)
+               SNDMSG("invalid snd_pcm_wait timeout argument %d\n", timeout);
        do {
                __snd_pcm_unlock(pcm->fast_op_arg);
                err_poll = poll(pfd, npfds, timeout);
@@ -7525,7 +7563,7 @@ snd_pcm_sframes_t snd_pcm_read_areas(snd_pcm_t *pcm, const snd_pcm_channel_area_
                                goto _end;
                        }
 
-                       err = __snd_pcm_wait_in_lock(pcm, -1);
+                       err = __snd_pcm_wait_in_lock(pcm, SND_PCM_WAIT_IO);
                        if (err < 0)
                                break;
                        goto _again;
@@ -7594,7 +7632,7 @@ snd_pcm_sframes_t snd_pcm_write_areas(snd_pcm_t *pcm, const snd_pcm_channel_area
                                        goto _end;
                                }
 
-                               err = snd_pcm_wait_nocheck(pcm, -1);
+                               err = snd_pcm_wait_nocheck(pcm, SND_PCM_WAIT_IO);
                                if (err < 0)
                                        break;
                                goto _again;
index b93c955cc623e24631ce438782e75fefc254d31f..b0d0a43e463651451b58e1ad6872be4f49f9b128 100644 (file)
@@ -623,7 +623,7 @@ static int __snd_pcm_dmix_drain(snd_pcm_t *pcm)
                if (dmix->state == SND_PCM_STATE_DRAINING) {
                        snd_pcm_dmix_sync_area(pcm);
                        if ((pcm->mode & SND_PCM_NONBLOCK) == 0) {
-                               snd_pcm_wait_nocheck(pcm, -1);
+                               snd_pcm_wait_nocheck(pcm, SND_PCM_WAIT_DRAIN);
                                snd_pcm_direct_clear_timer_queue(dmix); /* force poll to wait */
                        }
 
index d7be8fbb4dc2d72b5dff52b49eacb50afa52aaa5..454b39a9142962a1ec955c1648ec10e7e4367518 100644 (file)
@@ -400,7 +400,7 @@ static int __snd_pcm_dshare_drain(snd_pcm_t *pcm)
                }
                if (dshare->state == SND_PCM_STATE_DRAINING) {
                        snd_pcm_dshare_sync_area(pcm);
-                       snd_pcm_wait_nocheck(pcm, -1);
+                       snd_pcm_wait_nocheck(pcm, SND_PCM_WAIT_DRAIN);
                        snd_pcm_direct_clear_timer_queue(dshare); /* force poll to wait */
 
                        switch (snd_pcm_state(dshare->spcm)) {
index cb2eee32887978c10da0f092a8ac47bcee5ba557..d3ce300ce3b8258b7506bad23088ad38033e0abb 100644 (file)
@@ -301,7 +301,7 @@ static int __snd_pcm_dsnoop_drain(snd_pcm_t *pcm)
                        break;
                if (pcm->mode & SND_PCM_NONBLOCK)
                        return -EAGAIN;
-               __snd_pcm_wait_in_lock(pcm, -1);
+               __snd_pcm_wait_in_lock(pcm, SND_PCM_WAIT_DRAIN);
        }
        pcm->stop_threshold = stop_threshold;
        return snd_pcm_dsnoop_drop(pcm);
index 981843982caf8d66263c0241250db57ff7dca561..09454a29a1a5c112ec388115be52a3123f42ca3c 100644 (file)
@@ -522,7 +522,7 @@ static int ioplug_drain_via_poll(snd_pcm_t *pcm)
                /* in non-blocking mode, let application to poll() by itself */
                if (io->data->nonblock)
                        return -EAGAIN;
-               if (snd_pcm_wait_nocheck(pcm, -1) < 0)
+               if (snd_pcm_wait_nocheck(pcm, SND_PCM_WAIT_DRAIN) < 0)
                        break;
        }
 
index c807685909cb05dc642d66d1f8376c21a0640094..44d7e760b3eebedeb1d091d5a857ccde756632dd 100644 (file)
@@ -1146,7 +1146,7 @@ static int snd_pcm_rate_drain(snd_pcm_t *pcm)
                        snd_pcm_uframes_t psize, spsize;
                        int err;
 
-                       err = __snd_pcm_wait_in_lock(rate->gen.slave, -1);
+                       err = __snd_pcm_wait_in_lock(rate->gen.slave, SND_PCM_WAIT_DRAIN);
                        if (err < 0)
                                break;
                        if (size > pcm->period_size) {
index ac088472e67f29e43fbb11a471aa80e170399d9a..677f41328cb1c6216d063222ac997a60ce73c16c 100644 (file)
@@ -1194,7 +1194,7 @@ static int snd_pcm_share_drain(snd_pcm_t *pcm)
                        _snd_pcm_share_update(pcm);
                        Pthread_mutex_unlock(&slave->mutex);
                        if (!(pcm->mode & SND_PCM_NONBLOCK))
-                               snd_pcm_wait(pcm, -1);
+                               snd_pcm_wait(pcm, SND_PCM_WAIT_DRAIN);
                        return 0;
                default:
                        assert(0);
index 1282895843a5366f02b8e43abcb40a6292cbab5b..f0bfd934d335eb44c6eeaf1fcf8c5eded917d550 100644 (file)
@@ -495,7 +495,7 @@ static int snd_pcm_shm_drain(snd_pcm_t *pcm)
        if (err < 0)
                return err;
        if (!(pcm->mode & SND_PCM_NONBLOCK))
-               snd_pcm_wait(pcm, -1);
+               snd_pcm_wait(pcm, SND_PCM_WAIT_DRAIN);
        return err;
 }