From e859cf26447fea6c1ef56baebb9c4ecb33a333dc Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Fri, 11 Oct 2002 18:39:24 +0000 Subject: [PATCH] Implemented snd_pcm_avail() function. More documentation updates for snd_pcm_avail_update() and snd_pcm_delay(). Updated behaviour of read/write functions (wait when buffer is full) to follow kernel. --- src/pcm/pcm.c | 102 +++++++++++++++++++++++++++---------------- src/pcm/pcm_file.c | 7 +++ src/pcm/pcm_hooks.c | 7 +++ src/pcm/pcm_hw.c | 34 ++++++++++++++- src/pcm/pcm_local.h | 24 ++-------- src/pcm/pcm_meter.c | 7 +++ src/pcm/pcm_multi.c | 8 ++++ src/pcm/pcm_null.c | 7 +++ src/pcm/pcm_plugin.c | 16 ++++++- src/pcm/pcm_share.c | 33 +++++++++++--- src/pcm/pcm_shm.c | 13 ++++++ 11 files changed, 189 insertions(+), 69 deletions(-) diff --git a/src/pcm/pcm.c b/src/pcm/pcm.c index 9ab753f0..137d2b16 100644 --- a/src/pcm/pcm.c +++ b/src/pcm/pcm.c @@ -359,9 +359,9 @@ network I/O etc.). If application wants to manage the ahead samples itself, the \link ::snd_pcm_rewind() \endlink function allows to forget the last samples in the stream. -\section pcm_status Obtaining device status +\section pcm_status Obtaining stream status -The device status is stored in \link ::snd_pcm_status_t \endlink structure. +The stream status is stored in \link ::snd_pcm_status_t \endlink structure. These parameters can be obtained: the current stream state - \link ::snd_pcm_status_get_state \endlink, timestamp of trigger - \link ::snd_pcm_status_get_trigger_tstamp \endlink, timestamp of last @@ -373,21 +373,33 @@ samples - \link ::snd_pcm_status_get_overrange \endlink. The last two parameters - avail_max and overrange are reset to zero after the status call. -\subsection pcm_status_fast Obtaining device status fast +\subsection pcm_status_fast Obtaining stream state fast and update r/w pointer The function \link ::snd_pcm_avail_update \endlink updates the current available count of samples for writing (playback) or filled samples for -reading (capture). It is a light version of -\link ::snd_pcm_status_get_avail \endlink, because it does not require -the user <-> kernel context switch, but the value is less accurate, -because ring buffer pointers are updated in kernel drivers only when -an interrupt occurs. +reading (capture). This call is mandatory for updating actual r/w pointer. +Using standalone, it is a light method to obtain current stream position, +because it does not require the user <-> kernel context switch, but the value +is less accurate, because ring buffer pointers are updated in kernel drivers +only when an interrupt occurs. If you want to get accurate stream state, +use functions \link ::snd_pcm_avail \endlink or \link ::snd_pcm_delay \endlink. +Note that both of these functions do not update the current r/w pointer +for applications, so the function \link ::snd_pcm_avail_update \endlink must +be called afterwards before any read/write begin+commit operations. +

+The function \link ::snd_pcm_avail \endlink returns current available space +in the ring buffer. Note that this function does not update the current r/w +pointer for applications, so the function \link ::snd_pcm_avail_update \endlink +must be called afterwards before any read/write/begin+commit operations.

The function \link ::snd_pcm_delay \endlink returns the delay in samples. For playback, it means count of samples in the ring buffer before the next sample will be sent to DAC. For capture, it means count of samples in the ring buffer before the next sample will be captured from ADC. It works -only when the stream is in the running or draining state. +only when the stream is in the running or draining (playback only) state. +Note that this function does not update the current r/w pointer for applications, +so the function \link ::snd_pcm_avail_update \endlink must be called afterwards +before any read/write begin+commit operations. \section pcm_action Managing the stream state @@ -811,6 +823,30 @@ snd_pcm_state_t snd_pcm_state(snd_pcm_t *pcm) return pcm->fast_ops->state(pcm->fast_op_arg); } +/** + * \brief Obtain available frames for a running PCM handle + * \param pcm PCM handle + * \param availp Returned available frames + * \return 0 on success otherwise a negative error code + * + * Returns available frames to be filled inside ring buffer. + * This value might be greater than buffer size when + * underrun (playback) or overrun (capture) occurs. + * + * This function returns accurate value, because it updates + * stream position from hardware. + * + * Note this function does not update the actual r/w pointer + * for applications. The function \link ::snd_pcm_avail_update \endlink + * have to be called before any read/write/begin+commit operation. + */ +int snd_pcm_avail(snd_pcm_t *pcm, snd_pcm_uframes_t *availp) +{ + assert(pcm); + assert(pcm->setup); + return pcm->fast_ops->avail(pcm->fast_op_arg, availp); +} + /** * \brief Obtain delay for a running PCM handle * \param pcm PCM handle @@ -822,6 +858,10 @@ snd_pcm_state_t snd_pcm_state(snd_pcm_t *pcm) * It's positive and less than buffer size in normal situation, * negative on playback underrun and greater than buffer size on * capture overrun. + * + * Note this function does not update the actual r/w pointer + * for applications. The function \link ::snd_pcm_avail_update \endlink + * have to be called before any read/write/begin+commit operation. */ int snd_pcm_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp) { @@ -5728,6 +5768,8 @@ snd_pcm_sframes_t snd_pcm_read_areas(snd_pcm_t *pcm, const snd_pcm_channel_area_ break; case SND_PCM_STATE_XRUN: return -EPIPE; + case SND_PCM_STATE_SUSPENDED: + return -ESTRPIPE; default: return -EBADFD; } @@ -5736,19 +5778,21 @@ snd_pcm_sframes_t snd_pcm_read_areas(snd_pcm_t *pcm, const snd_pcm_channel_area_ snd_pcm_uframes_t frames; snd_pcm_sframes_t avail; _again: + if (pcm->sleep_min == 0 && state == SND_PCM_STATE_RUNNING) { + snd_pcm_sframes_t delay; + /* update hw_ptr */ + err = snd_pcm_delay(pcm, &delay); + if (err < 0) + goto _end; + } avail = snd_pcm_avail_update(pcm); if (avail < 0) { err = avail; goto _end; } - if ((state == SND_PCM_STATE_PAUSED) || - (state == SND_PCM_STATE_DRAINING)) { - if ((snd_pcm_uframes_t)avail < pcm->xfer_align) { - err = -EPIPE; - goto _end; - } - } else if (((snd_pcm_uframes_t)avail < pcm->avail_min && size > (snd_pcm_uframes_t)avail) || - (size >= pcm->xfer_align && (snd_pcm_uframes_t)avail < pcm->xfer_align)) { + if (((snd_pcm_uframes_t)avail < pcm->avail_min && size > (snd_pcm_uframes_t)avail) || + (size >= pcm->xfer_align && (snd_pcm_uframes_t)avail < pcm->xfer_align)) { + if (pcm->mode & SND_PCM_NONBLOCK) { err = -EAGAIN; goto _end; @@ -5774,13 +5818,6 @@ snd_pcm_sframes_t snd_pcm_read_areas(snd_pcm_t *pcm, const snd_pcm_channel_area_ offset += frames; size -= frames; xfer += frames; -#if 0 - state = snd_pcm_state(pcm); - if (state == SND_PCM_STATE_XRUN) { - err = -EPIPE; - goto _end; - } -#endif } _end: return xfer > 0 ? (snd_pcm_sframes_t) xfer : err; @@ -5805,6 +5842,8 @@ snd_pcm_sframes_t snd_pcm_write_areas(snd_pcm_t *pcm, const snd_pcm_channel_area break; case SND_PCM_STATE_XRUN: return -EPIPE; + case SND_PCM_STATE_SUSPENDED: + return -ESTRPIPE; default: return -EBADFD; } @@ -5824,15 +5863,9 @@ snd_pcm_sframes_t snd_pcm_write_areas(snd_pcm_t *pcm, const snd_pcm_channel_area if (avail < 0) { err = avail; goto _end; - } - if (state == SND_PCM_STATE_PAUSED || - state == SND_PCM_STATE_PREPARED) { - if ((snd_pcm_uframes_t)avail < pcm->xfer_align) { - err = -EPIPE; - goto _end; - } } else if (((snd_pcm_uframes_t)avail < pcm->avail_min && size > (snd_pcm_uframes_t)avail) || (size >= pcm->xfer_align && (snd_pcm_uframes_t)avail < pcm->xfer_align)) { + if (pcm->mode & SND_PCM_NONBLOCK) { err = -EAGAIN; goto _end; @@ -5858,13 +5891,6 @@ snd_pcm_sframes_t snd_pcm_write_areas(snd_pcm_t *pcm, const snd_pcm_channel_area offset += frames; size -= frames; xfer += frames; -#if 0 - state = snd_pcm_state(pcm); - if (state == SND_PCM_STATE_XRUN) { - err = -EPIPE; - goto _end; - } -#endif if (state == SND_PCM_STATE_PREPARED) { snd_pcm_sframes_t hw_avail = pcm->buffer_size - avail; hw_avail += frames; diff --git a/src/pcm/pcm_file.c b/src/pcm/pcm_file.c index 30536ba3..d8ed59d8 100644 --- a/src/pcm/pcm_file.c +++ b/src/pcm/pcm_file.c @@ -162,6 +162,12 @@ static snd_pcm_state_t snd_pcm_file_state(snd_pcm_t *pcm) return snd_pcm_state(file->slave); } +static int snd_pcm_file_avail(snd_pcm_t *pcm, snd_pcm_uframes_t *availp) +{ + snd_pcm_file_t *file = pcm->private_data; + return snd_pcm_avail(file->slave, availp); +} + static int snd_pcm_file_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp) { snd_pcm_file_t *file = pcm->private_data; @@ -406,6 +412,7 @@ static snd_pcm_ops_t snd_pcm_file_ops = { static snd_pcm_fast_ops_t snd_pcm_file_fast_ops = { status: snd_pcm_file_status, state: snd_pcm_file_state, + avail: snd_pcm_file_avail, delay: snd_pcm_file_delay, prepare: snd_pcm_file_prepare, reset: snd_pcm_file_reset, diff --git a/src/pcm/pcm_hooks.c b/src/pcm/pcm_hooks.c index 946835de..0cd74de0 100644 --- a/src/pcm/pcm_hooks.c +++ b/src/pcm/pcm_hooks.c @@ -116,6 +116,12 @@ static snd_pcm_state_t snd_pcm_hooks_state(snd_pcm_t *pcm) return snd_pcm_state(h->slave); } +static int snd_pcm_hooks_avail(snd_pcm_t *pcm, snd_pcm_uframes_t *availp) +{ + snd_pcm_hooks_t *h = pcm->private_data; + return snd_pcm_avail(h->slave, availp); +} + static int snd_pcm_hooks_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp) { snd_pcm_hooks_t *h = pcm->private_data; @@ -292,6 +298,7 @@ static snd_pcm_ops_t snd_pcm_hooks_ops = { static snd_pcm_fast_ops_t snd_pcm_hooks_fast_ops = { status: snd_pcm_hooks_status, state: snd_pcm_hooks_state, + avail: snd_pcm_hooks_avail, delay: snd_pcm_hooks_delay, prepare: snd_pcm_hooks_prepare, reset: snd_pcm_hooks_reset, diff --git a/src/pcm/pcm_hw.c b/src/pcm/pcm_hw.c index 4f59aeb4..b2c872b6 100644 --- a/src/pcm/pcm_hw.c +++ b/src/pcm/pcm_hw.c @@ -77,9 +77,11 @@ struct sndrv_pcm_hw_params_old { #define SND_PCM_IOCTL_HW_REFINE_OLD _IOWR('A', 0x10, struct sndrv_pcm_hw_params_old) #define SND_PCM_IOCTL_HW_PARAMS_OLD _IOWR('A', 0x11, struct sndrv_pcm_hw_params_old) -#define SND_PCM_IOCTL_XRUN _IO('A', 0x48) +#define SND_PCM_IOCTL_AVAIL _IOR('A', 0x22, sndrv_pcm_uframes_t) +#define SND_PCM_IOCTL_XRUN _IO ('A', 0x48) static int use_old_hw_params_ioctl(int fd, unsigned int cmd, snd_pcm_hw_params_t *params); +static snd_pcm_sframes_t snd_pcm_hw_avail_update(snd_pcm_t *pcm); /* * @@ -101,7 +103,7 @@ typedef struct { #define SNDRV_FILE_PCM_STREAM_PLAYBACK "/dev/snd/pcmC%iD%ip" #define SNDRV_FILE_PCM_STREAM_CAPTURE "/dev/snd/pcmC%iD%ic" -#define SNDRV_PCM_VERSION_MAX SNDRV_PROTOCOL_VERSION(2, 0, 2) +#define SNDRV_PCM_VERSION_MAX SNDRV_PROTOCOL_VERSION(2, 0, 3) /* update appl_ptr with driver */ #define UPDATE_SHADOW_PTR(hw) \ @@ -393,6 +395,33 @@ static int snd_pcm_hw_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp) return 0; } +static int snd_pcm_hw_avail(snd_pcm_t *pcm, snd_pcm_uframes_t *availp) +{ + snd_pcm_hw_t *hw = pcm->private_data; + int fd = hw->fd; + if (SNDRV_PROTOCOL_VERSION(2, 0, 3) <= hw->version) { + if (ioctl(fd, SND_PCM_IOCTL_AVAIL, availp) < 0) { + // SYSERR("SND_PCM_IOCTL_AVAIL failed"); + return -errno; + } + } else { + snd_pcm_sframes_t delay; + int err = snd_pcm_hw_delay(pcm, &delay); + if (err < 0) { + delay = snd_pcm_hw_avail_update(pcm); + if (delay < 0) + return delay; + *availp = delay; + } else { + delay = pcm->stream == SND_PCM_STREAM_PLAYBACK ? pcm->buffer_size - delay : delay; + if (delay < 0) + delay = 0; + *availp = delay; + } + } + return 0; +} + static int snd_pcm_hw_prepare(snd_pcm_t *pcm) { snd_pcm_hw_t *hw = pcm->private_data; @@ -757,6 +786,7 @@ static snd_pcm_ops_t snd_pcm_hw_ops = { static snd_pcm_fast_ops_t snd_pcm_hw_fast_ops = { status: snd_pcm_hw_status, state: snd_pcm_hw_state, + avail: snd_pcm_hw_avail, delay: snd_pcm_hw_delay, prepare: snd_pcm_hw_prepare, reset: snd_pcm_hw_reset, diff --git a/src/pcm/pcm_local.h b/src/pcm/pcm_local.h index 2d8ab61f..b8a91ae7 100644 --- a/src/pcm/pcm_local.h +++ b/src/pcm/pcm_local.h @@ -144,6 +144,7 @@ typedef struct { int (*drain)(snd_pcm_t *pcm); int (*pause)(snd_pcm_t *pcm, int enable); snd_pcm_state_t (*state)(snd_pcm_t *pcm); + int (*avail)(snd_pcm_t *pcm, snd_pcm_uframes_t *availp); int (*delay)(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp); int (*resume)(snd_pcm_t *pcm); snd_pcm_sframes_t (*rewind)(snd_pcm_t *pcm, snd_pcm_uframes_t frames); @@ -323,31 +324,12 @@ static inline snd_pcm_uframes_t snd_pcm_mmap_hw_offset(snd_pcm_t *pcm) static inline snd_pcm_uframes_t snd_pcm_mmap_playback_delay(snd_pcm_t *pcm) { - snd_pcm_state_t state = snd_pcm_state(pcm); - - switch (state) { - case SND_PCM_STATE_RUNNING: - case SND_PCM_STATE_DRAINING: - return snd_pcm_mmap_playback_hw_avail(pcm); - case SND_PCM_STATE_XRUN: - return -EPIPE; - default: - return -EBADFD; - } + return snd_pcm_mmap_playback_hw_avail(pcm); } static inline snd_pcm_uframes_t snd_pcm_mmap_capture_delay(snd_pcm_t *pcm) { - snd_pcm_state_t state = snd_pcm_state(pcm); - - switch (state) { - case SND_PCM_STATE_RUNNING: - return snd_pcm_mmap_capture_hw_avail(pcm); - case SND_PCM_STATE_XRUN: - return -EPIPE; - default: - return -EBADFD; - } + return snd_pcm_mmap_capture_hw_avail(pcm); } static inline snd_pcm_sframes_t snd_pcm_mmap_delay(snd_pcm_t *pcm) diff --git a/src/pcm/pcm_meter.c b/src/pcm/pcm_meter.c index c3e41430..820f733f 100644 --- a/src/pcm/pcm_meter.c +++ b/src/pcm/pcm_meter.c @@ -319,6 +319,12 @@ static snd_pcm_state_t snd_pcm_meter_state(snd_pcm_t *pcm) return snd_pcm_state(meter->slave); } +static int snd_pcm_meter_avail(snd_pcm_t *pcm, snd_pcm_uframes_t *availp) +{ + snd_pcm_meter_t *meter = pcm->private_data; + return snd_pcm_avail(meter->slave, availp); +} + static int snd_pcm_meter_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp) { snd_pcm_meter_t *meter = pcm->private_data; @@ -593,6 +599,7 @@ static snd_pcm_ops_t snd_pcm_meter_ops = { static snd_pcm_fast_ops_t snd_pcm_meter_fast_ops = { status: snd_pcm_meter_status, state: snd_pcm_meter_state, + avail: snd_pcm_meter_avail, delay: snd_pcm_meter_delay, prepare: snd_pcm_meter_prepare, reset: snd_pcm_meter_reset, diff --git a/src/pcm/pcm_multi.c b/src/pcm/pcm_multi.c index 7f5caac6..57aca7d1 100644 --- a/src/pcm/pcm_multi.c +++ b/src/pcm/pcm_multi.c @@ -351,6 +351,13 @@ static snd_pcm_state_t snd_pcm_multi_state(snd_pcm_t *pcm) return snd_pcm_state(slave); } +static int snd_pcm_multi_avail(snd_pcm_t *pcm, snd_pcm_uframes_t *availp) +{ + snd_pcm_multi_t *multi = pcm->private_data; + snd_pcm_t *slave = multi->slaves[0].pcm; + return snd_pcm_avail(slave, availp); +} + static int snd_pcm_multi_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp) { snd_pcm_multi_t *multi = pcm->private_data; @@ -594,6 +601,7 @@ static snd_pcm_ops_t snd_pcm_multi_ops = { static snd_pcm_fast_ops_t snd_pcm_multi_fast_ops = { status: snd_pcm_multi_status, state: snd_pcm_multi_state, + avail: snd_pcm_multi_avail, delay: snd_pcm_multi_delay, prepare: snd_pcm_multi_prepare, reset: snd_pcm_multi_reset, diff --git a/src/pcm/pcm_null.c b/src/pcm/pcm_null.c index 338b58ae..3edd58df 100644 --- a/src/pcm/pcm_null.c +++ b/src/pcm/pcm_null.c @@ -102,6 +102,12 @@ static snd_pcm_state_t snd_pcm_null_state(snd_pcm_t *pcm) return null->state; } +static int snd_pcm_null_avail(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_uframes_t *availp) +{ + *availp = pcm->buffer_size; + return 0; +} + static int snd_pcm_null_delay(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_sframes_t *delayp) { *delayp = 0; @@ -320,6 +326,7 @@ static snd_pcm_ops_t snd_pcm_null_ops = { static snd_pcm_fast_ops_t snd_pcm_null_fast_ops = { status: snd_pcm_null_status, state: snd_pcm_null_state, + avail: snd_pcm_null_avail, delay: snd_pcm_null_delay, prepare: snd_pcm_null_prepare, reset: snd_pcm_null_reset, diff --git a/src/pcm/pcm_plugin.c b/src/pcm/pcm_plugin.c index 9cf4f048..656e41e9 100644 --- a/src/pcm/pcm_plugin.c +++ b/src/pcm/pcm_plugin.c @@ -188,6 +188,19 @@ snd_pcm_state_t snd_pcm_plugin_state(snd_pcm_t *pcm) return snd_pcm_state(plugin->slave); } +int snd_pcm_plugin_avail(snd_pcm_t *pcm, snd_pcm_uframes_t *availp) +{ + snd_pcm_plugin_t *plugin = pcm->private_data; + snd_pcm_uframes_t sd; + int err = snd_pcm_avail(plugin->slave, &sd); + if (err < 0) + return err; + if (plugin->client_frames) + sd = plugin->client_frames(pcm, sd); + *availp = sd; + return 0; +} + int snd_pcm_plugin_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp) { snd_pcm_plugin_t *plugin = pcm->private_data; @@ -197,7 +210,7 @@ int snd_pcm_plugin_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp) return err; if (plugin->client_frames) sd = plugin->client_frames(pcm, sd); - *delayp = sd + snd_pcm_mmap_delay(pcm); + *delayp = sd; return 0; } @@ -627,6 +640,7 @@ int snd_pcm_plugin_hw_params_slave(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) snd_pcm_fast_ops_t snd_pcm_plugin_fast_ops = { status: snd_pcm_plugin_status, state: snd_pcm_plugin_state, + avail: snd_pcm_plugin_avail, delay: snd_pcm_plugin_delay, prepare: snd_pcm_plugin_prepare, reset: snd_pcm_plugin_reset, diff --git a/src/pcm/pcm_share.c b/src/pcm/pcm_share.c index 89a1c4f4..2195f175 100644 --- a/src/pcm/pcm_share.c +++ b/src/pcm/pcm_share.c @@ -713,12 +713,34 @@ static snd_pcm_state_t snd_pcm_share_state(snd_pcm_t *pcm) return share->state; } +static int _snd_pcm_share_avail(snd_pcm_t *pcm, snd_pcm_uframes_t *availp) +{ + snd_pcm_share_t *share = pcm->private_data; + snd_pcm_share_slave_t *slave = share->slave; + switch (share->state) { + case SND_PCM_STATE_XRUN: + return -EPIPE; + default: + break; + } + return snd_pcm_avail(slave->pcm, availp); +} + +static int snd_pcm_share_avail(snd_pcm_t *pcm, snd_pcm_uframes_t *availp) +{ + snd_pcm_share_t *share = pcm->private_data; + snd_pcm_share_slave_t *slave = share->slave; + int err; + Pthread_mutex_lock(&slave->mutex); + err = _snd_pcm_share_avail(pcm, availp); + Pthread_mutex_unlock(&slave->mutex); + return err; +} + static int _snd_pcm_share_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp) { snd_pcm_share_t *share = pcm->private_data; snd_pcm_share_slave_t *slave = share->slave; - int err = 0; - snd_pcm_sframes_t sd; switch (share->state) { case SND_PCM_STATE_XRUN: return -EPIPE; @@ -731,11 +753,7 @@ static int _snd_pcm_share_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp) default: return -EBADFD; } - err = snd_pcm_delay(slave->pcm, &sd); - if (err < 0) - return err; - *delayp = sd + snd_pcm_mmap_delay(pcm); - return 0; + return snd_pcm_delay(slave->pcm, delayp); } static int snd_pcm_share_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp) @@ -1215,6 +1233,7 @@ static snd_pcm_ops_t snd_pcm_share_ops = { static snd_pcm_fast_ops_t snd_pcm_share_fast_ops = { status: snd_pcm_share_status, state: snd_pcm_share_state, + avail: snd_pcm_share_avail, delay: snd_pcm_share_delay, prepare: snd_pcm_share_prepare, reset: snd_pcm_share_reset, diff --git a/src/pcm/pcm_shm.c b/src/pcm/pcm_shm.c index 824bb8b9..cf126fbb 100644 --- a/src/pcm/pcm_shm.c +++ b/src/pcm/pcm_shm.c @@ -443,6 +443,19 @@ static snd_pcm_state_t snd_pcm_shm_state(snd_pcm_t *pcm) return snd_pcm_shm_action(pcm); } +static int snd_pcm_shm_avail(snd_pcm_t *pcm, snd_pcm_uframes_t *availp) +{ + snd_pcm_shm_t *shm = pcm->private_data; + volatile snd_pcm_shm_ctrl_t *ctrl = shm->ctrl; + int err; + ctrl->cmd = SND_PCM_IOCTL_AVAIL; + err = snd_pcm_shm_action(pcm); + if (err < 0) + return err; + *availp = ctrl->u.avail.frames; + return err; +} + static int snd_pcm_shm_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp) { snd_pcm_shm_t *shm = pcm->private_data; -- 2.47.1