summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJaroslav Kysela <perex@perex.cz>2023-05-02 16:56:49 +0200
committerJaroslav Kysela <perex@perex.cz>2023-05-03 15:59:15 +0200
commite2d9e411744dede5a71e04a107cdc0ab7c1d0ed9 (patch)
tree412e10ce1479c1a860ace74209dd91bd86dbdf30
parent1de6f99c7d058634b5550fa59c01f3b6546f830a (diff)
downloadalsa-lib-e2d9e411744dede5a71e04a107cdc0ab7c1d0ed9.tar.gz
pcm: improve handling for snd_pcm_wait()
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>
-rw-r--r--include/pcm.h7
-rw-r--r--src/pcm/pcm.c44
-rw-r--r--src/pcm/pcm_dmix.c2
-rw-r--r--src/pcm/pcm_dshare.c2
-rw-r--r--src/pcm/pcm_dsnoop.c2
-rw-r--r--src/pcm/pcm_ioplug.c2
-rw-r--r--src/pcm/pcm_rate.c2
-rw-r--r--src/pcm/pcm_share.c2
-rw-r--r--src/pcm/pcm_shm.c2
9 files changed, 55 insertions, 10 deletions
diff --git a/include/pcm.h b/include/pcm.h
index 966d6ffd..25cd12d1 100644
--- a/include/pcm.h
+++ b/include/pcm.h
@@ -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;
diff --git a/src/pcm/pcm.c b/src/pcm/pcm.c
index 997a8a6a..01c624d3 100644
--- a/src/pcm/pcm.c
+++ b/src/pcm/pcm.c
@@ -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;
diff --git a/src/pcm/pcm_dmix.c b/src/pcm/pcm_dmix.c
index b93c955c..b0d0a43e 100644
--- a/src/pcm/pcm_dmix.c
+++ b/src/pcm/pcm_dmix.c
@@ -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 */
}
diff --git a/src/pcm/pcm_dshare.c b/src/pcm/pcm_dshare.c
index d7be8fbb..454b39a9 100644
--- a/src/pcm/pcm_dshare.c
+++ b/src/pcm/pcm_dshare.c
@@ -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)) {
diff --git a/src/pcm/pcm_dsnoop.c b/src/pcm/pcm_dsnoop.c
index cb2eee32..d3ce300c 100644
--- a/src/pcm/pcm_dsnoop.c
+++ b/src/pcm/pcm_dsnoop.c
@@ -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);
diff --git a/src/pcm/pcm_ioplug.c b/src/pcm/pcm_ioplug.c
index 98184398..09454a29 100644
--- a/src/pcm/pcm_ioplug.c
+++ b/src/pcm/pcm_ioplug.c
@@ -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;
}
diff --git a/src/pcm/pcm_rate.c b/src/pcm/pcm_rate.c
index c8076859..44d7e760 100644
--- a/src/pcm/pcm_rate.c
+++ b/src/pcm/pcm_rate.c
@@ -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) {
diff --git a/src/pcm/pcm_share.c b/src/pcm/pcm_share.c
index ac088472..677f4132 100644
--- a/src/pcm/pcm_share.c
+++ b/src/pcm/pcm_share.c
@@ -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);
diff --git a/src/pcm/pcm_shm.c b/src/pcm/pcm_shm.c
index 12828958..f0bfd934 100644
--- a/src/pcm/pcm_shm.c
+++ b/src/pcm/pcm_shm.c
@@ -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;
}