diff options
author | Jaroslav Kysela <perex@perex.cz> | 2023-05-02 16:56:49 +0200 |
---|---|---|
committer | Jaroslav Kysela <perex@perex.cz> | 2023-05-03 15:59:15 +0200 |
commit | e2d9e411744dede5a71e04a107cdc0ab7c1d0ed9 (patch) | |
tree | 412e10ce1479c1a860ace74209dd91bd86dbdf30 | |
parent | 1de6f99c7d058634b5550fa59c01f3b6546f830a (diff) | |
download | alsa-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.h | 7 | ||||
-rw-r--r-- | src/pcm/pcm.c | 44 | ||||
-rw-r--r-- | src/pcm/pcm_dmix.c | 2 | ||||
-rw-r--r-- | src/pcm/pcm_dshare.c | 2 | ||||
-rw-r--r-- | src/pcm/pcm_dsnoop.c | 2 | ||||
-rw-r--r-- | src/pcm/pcm_ioplug.c | 2 | ||||
-rw-r--r-- | src/pcm/pcm_rate.c | 2 | ||||
-rw-r--r-- | src/pcm/pcm_share.c | 2 | ||||
-rw-r--r-- | src/pcm/pcm_shm.c | 2 |
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; } |