From fbd99fdec07c67b50843b9baf12615129f952ae3 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Sat, 22 Feb 2003 10:19:53 +0000 Subject: [PATCH] Added snd_pcm_hwptr() and enhanced snd_pcm_mmap_begin() for no xrun mode. --- aserver/aserver.c | 3 +++ include/aserver.h | 4 ++++ include/pcm.h | 1 + src/Versions | 10 +++++++++- src/pcm/pcm.c | 43 ++++++++++++++++++++++++++++++++++++++----- src/pcm/pcm_dmix.c | 21 ++++++++++++++++++++- src/pcm/pcm_file.c | 10 ++++++++++ src/pcm/pcm_hooks.c | 7 +++++++ src/pcm/pcm_hw.c | 29 ++++++++++++++++++++++++++++- src/pcm/pcm_jack.c | 19 +++++++++++++++++++ src/pcm/pcm_local.h | 3 +++ src/pcm/pcm_meter.c | 6 ++++++ src/pcm/pcm_multi.c | 18 +++++++++++++----- src/pcm/pcm_null.c | 18 ++++++++++++++++++ src/pcm/pcm_plugin.c | 7 +++++++ src/pcm/pcm_share.c | 31 +++++++++++++++++++++++++++++++ src/pcm/pcm_shm.c | 14 ++++++++++++++ 17 files changed, 231 insertions(+), 13 deletions(-) diff --git a/aserver/aserver.c b/aserver/aserver.c index 60af87bf..a6b4a4e2 100644 --- a/aserver/aserver.c +++ b/aserver/aserver.c @@ -471,6 +471,9 @@ static int pcm_shm_cmd(client_t *client) case SND_PCM_IOCTL_HWSYNC: ctrl->result = snd_pcm_hwsync(pcm); break; + case SND_PCM_IOCTL_HWPTR: + ctrl->result = snd_pcm_hwptr(pcm, (snd_pcm_uframes_t *) &ctrl->u.hwptr.frames); + break; case SNDRV_PCM_IOCTL_DELAY: ctrl->result = snd_pcm_delay(pcm, (snd_pcm_sframes_t *) &ctrl->u.delay.frames); break; diff --git a/include/aserver.h b/include/aserver.h index 0a2dfbeb..c6e9f957 100644 --- a/include/aserver.h +++ b/include/aserver.h @@ -50,6 +50,7 @@ typedef enum _snd_transport_type { #define SND_PCM_IOCTL_POLL_DESCRIPTOR _IO ('A', 0xf8) #define SND_PCM_IOCTL_HW_PTR_FD _IO ('A', 0xf9) #define SND_PCM_IOCTL_APPL_PTR_FD _IO ('A', 0xfa) +#define SND_PCM_IOCTL_HWPTR _IO ('A', 0xfb) typedef struct { snd_pcm_uframes_t ptr; @@ -73,6 +74,9 @@ typedef struct { snd_pcm_hw_params_t hw_params; snd_pcm_sw_params_t sw_params; snd_pcm_status_t status; + struct { + snd_pcm_uframes_t frames; + } hwptr; struct { snd_pcm_uframes_t frames; } avail; diff --git a/include/pcm.h b/include/pcm.h index eb7a91b8..0ea5012c 100644 --- a/include/pcm.h +++ b/include/pcm.h @@ -410,6 +410,7 @@ int snd_pcm_drain(snd_pcm_t *pcm); int snd_pcm_pause(snd_pcm_t *pcm, int enable); snd_pcm_state_t snd_pcm_state(snd_pcm_t *pcm); int snd_pcm_hwsync(snd_pcm_t *pcm); +int snd_pcm_hwptr(snd_pcm_t *pcm, snd_pcm_uframes_t *uframes); int snd_pcm_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp); int snd_pcm_resume(snd_pcm_t *pcm); snd_pcm_sframes_t snd_pcm_avail_update(snd_pcm_t *pcm); diff --git a/src/Versions b/src/Versions index 64cab9a9..6abc98e4 100644 --- a/src/Versions +++ b/src/Versions @@ -6,6 +6,7 @@ ALSA_0.9 { local: *; }; + ALSA_0.9.0rc4 { global: @@ -77,4 +78,11 @@ ALSA_0.9.0rc4 { snd_pcm_hw_params_set_tick_time_first; snd_pcm_hw_params_set_tick_time_last; -}ALSA_0.9; +} ALSA_0.9; + +ALSA_0.9.0rc8 { + global: + + snd_pcm_hwptr; + +} ALSA_0.9.0rc4; diff --git a/src/pcm/pcm.c b/src/pcm/pcm.c index 1b1daa44..9383346e 100644 --- a/src/pcm/pcm.c +++ b/src/pcm/pcm.c @@ -868,6 +868,30 @@ int snd_pcm_hwsync(snd_pcm_t *pcm) return pcm->fast_ops->hwsync(pcm->fast_op_arg); } +/** + * \brief Return hardware pointer + * \param pcm PCM handle + * \return 0 on success otherwise a negative error code + * + * The hardware pointer is in range 0 ... (boundary - 1). It contains + * count_of_ring_buffer_crosses * buffer_size + offset in the ring buffer. + * + * Note this function does not return the real hardware pointer. + * The function \link ::snd_pcm_hwsync \endlink have to be called + * before to obtain the real hardware position. + */ +#ifndef DOXYGEN +int INTERNAL(snd_pcm_hwptr)(snd_pcm_t *pcm, snd_pcm_uframes_t *hwptr) +#else +int snd_pcm_hwptr(snd_pcm_t *pcm, snd_pcm_uframes_t *hwptr) +#endif +{ + assert(pcm); + assert(pcm->setup); + return pcm->fast_ops->hwptr(pcm->fast_op_arg, hwptr); +} +default_symbol_version(__snd_pcm_hwptr, snd_pcm_hwptr, ALSA_0.9.0rc8); + /** * \brief Obtain delay for a running PCM handle * \param pcm PCM handle @@ -5792,7 +5816,7 @@ void snd_pcm_info_set_stream(snd_pcm_info_t *obj, snd_pcm_stream_t val) * \brief Application request to access a portion of direct (mmap) area * \param pcm PCM handle * \param areas Returned mmap channel areas - * \param offset Returned mmap area offset in area steps (== frames) + * \param offset mmap area offset in area steps (== frames) (wanted on entry (see note), returned on exit) * \param frames mmap area portion size in frames (wanted on entry, contiguous available on exit) * \return 0 on success otherwise a negative error code * @@ -5805,6 +5829,9 @@ void snd_pcm_info_set_stream(snd_pcm_info_t *obj, snd_pcm_stream_t val) * * See the snd_pcm_mmap_commit() function to finish the frame processing in * the direct areas. + * + * Note: The offset value is always overriden when stop_threshold < boundary. + * Otherwise, the application must specify it's own offset value. * */ int snd_pcm_mmap_begin(snd_pcm_t *pcm, @@ -5817,12 +5844,18 @@ int snd_pcm_mmap_begin(snd_pcm_t *pcm, snd_pcm_uframes_t avail; assert(pcm && areas && offset && frames); *areas = snd_pcm_mmap_areas(pcm); - *offset = *pcm->appl.ptr % pcm->buffer_size; + if (pcm->stop_threshold < pcm->boundary) { + *offset = *pcm->appl.ptr % pcm->buffer_size; + avail = snd_pcm_mmap_avail(pcm); + if (avail > pcm->buffer_size) + avail = pcm->buffer_size; + } else { + if (*offset >= pcm->buffer_size) + return -EINVAL; + avail = pcm->buffer_size; + } cont = pcm->buffer_size - *offset; f = *frames; - avail = snd_pcm_mmap_avail(pcm); - if (avail > pcm->buffer_size) - avail = pcm->buffer_size; if (f > avail) f = avail; if (f > cont) diff --git a/src/pcm/pcm_dmix.c b/src/pcm/pcm_dmix.c index 5ab09a7a..ca322b89 100644 --- a/src/pcm/pcm_dmix.c +++ b/src/pcm/pcm_dmix.c @@ -954,7 +954,6 @@ static int snd_pcm_dmix_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp) snd_pcm_dmix_t *dmix = pcm->private_data; int err; - assert(pcm && delayp); switch(dmix->state) { case SNDRV_PCM_STATE_DRAINING: case SNDRV_PCM_STATE_RUNNING: @@ -990,6 +989,25 @@ static int snd_pcm_dmix_hwsync(snd_pcm_t *pcm) } } +static int snd_pcm_dmix_hwptr(snd_pcm_t *pcm, snd_pcm_uframes_t *hwptr) +{ + snd_pcm_dmix_t *dmix = pcm->private_data; + + switch(dmix->state) { + case SNDRV_PCM_STATE_DRAINING: + case SNDRV_PCM_STATE_RUNNING: + case SNDRV_PCM_STATE_PREPARED: + case SNDRV_PCM_STATE_PAUSED: + case SNDRV_PCM_STATE_SUSPENDED: + *hwptr = *pcm->hw.ptr; + return 0; + case SNDRV_PCM_STATE_XRUN: + return -EPIPE; + default: + return -EBADFD; + } +} + static int snd_pcm_dmix_prepare(snd_pcm_t *pcm) { snd_pcm_dmix_t *dmix = pcm->private_data; @@ -1206,6 +1224,7 @@ static snd_pcm_fast_ops_t snd_pcm_dmix_fast_ops = { status: snd_pcm_dmix_status, state: snd_pcm_dmix_state, hwsync: snd_pcm_dmix_hwsync, + hwptr: snd_pcm_dmix_hwptr, delay: snd_pcm_dmix_delay, prepare: snd_pcm_dmix_prepare, reset: snd_pcm_dmix_reset, diff --git a/src/pcm/pcm_file.c b/src/pcm/pcm_file.c index e14217c8..4ecb44aa 100644 --- a/src/pcm/pcm_file.c +++ b/src/pcm/pcm_file.c @@ -168,6 +168,12 @@ static int snd_pcm_file_hwsync(snd_pcm_t *pcm) return snd_pcm_hwsync(file->slave); } +static int snd_pcm_file_hwptr(snd_pcm_t *pcm, snd_pcm_uframes_t *hwptr) +{ + snd_pcm_file_t *file = pcm->private_data; + return INTERNAL(snd_pcm_hwptr)(file->slave, hwptr); +} + static int snd_pcm_file_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp) { snd_pcm_file_t *file = pcm->private_data; @@ -366,6 +372,9 @@ static int snd_pcm_file_hw_free(snd_pcm_t *pcm) static int snd_pcm_file_sw_params(snd_pcm_t *pcm, snd_pcm_sw_params_t * params) { snd_pcm_file_t *file = pcm->private_data; + /* we don't support mode without xrun detection */ + if (params->stop_threshold >= params->boundary) + return -EINVAL; return snd_pcm_sw_params(file->slave, params); } @@ -413,6 +422,7 @@ static snd_pcm_fast_ops_t snd_pcm_file_fast_ops = { status: snd_pcm_file_status, state: snd_pcm_file_state, hwsync: snd_pcm_file_hwsync, + hwptr: snd_pcm_file_hwptr, 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 6f9cf98c..c4cbd0a9 100644 --- a/src/pcm/pcm_hooks.c +++ b/src/pcm/pcm_hooks.c @@ -122,6 +122,12 @@ static int snd_pcm_hooks_hwsync(snd_pcm_t *pcm) return snd_pcm_hwsync(h->slave); } +static int snd_pcm_hooks_hwptr(snd_pcm_t *pcm, snd_pcm_uframes_t *hwptr) +{ + snd_pcm_hooks_t *h = pcm->private_data; + return INTERNAL(snd_pcm_hwptr)(h->slave, hwptr); +} + static int snd_pcm_hooks_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp) { snd_pcm_hooks_t *h = pcm->private_data; @@ -299,6 +305,7 @@ static snd_pcm_fast_ops_t snd_pcm_hooks_fast_ops = { status: snd_pcm_hooks_status, state: snd_pcm_hooks_state, hwsync: snd_pcm_hooks_hwsync, + hwptr: snd_pcm_hooks_hwptr, 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 d4b58b8e..b04bc55a 100644 --- a/src/pcm/pcm_hw.c +++ b/src/pcm/pcm_hw.c @@ -345,6 +345,9 @@ static int snd_pcm_hw_sw_params(snd_pcm_t *pcm, snd_pcm_sw_params_t * params) hw->mmap_control->avail_min = params->avail_min; return 0; } + /* FIXME */ + if (hw->mmap_shm && params->stop_threshold >= params->boundary) + return -EINVAL; if (ioctl(fd, SNDRV_PCM_IOCTL_SW_PARAMS, params) < 0) { SYSERR("SNDRV_PCM_IOCTL_SW_PARAMS failed"); return -errno; @@ -428,6 +431,23 @@ static int snd_pcm_hw_hwsync(snd_pcm_t *pcm) return 0; } +static int snd_pcm_hw_hwptr(snd_pcm_t *pcm, snd_pcm_uframes_t *hwptr) +{ + switch (snd_pcm_state(pcm)) { + case SND_PCM_STATE_RUNNING: + case SND_PCM_STATE_DRAINING: + case SND_PCM_STATE_PREPARED: + case SND_PCM_STATE_PAUSED: + case SND_PCM_STATE_SUSPENDED: + *hwptr = *pcm->hw.ptr; + return 0; + case SND_PCM_STATE_XRUN: + return -EPIPE; + default: + return -EBADFD; + } +} + static int snd_pcm_hw_prepare(snd_pcm_t *pcm) { snd_pcm_hw_t *hw = pcm->private_data; @@ -690,7 +710,7 @@ static int snd_pcm_hw_close(snd_pcm_t *pcm) } static snd_pcm_sframes_t snd_pcm_hw_mmap_commit(snd_pcm_t *pcm, - snd_pcm_uframes_t offset ATTRIBUTE_UNUSED, + snd_pcm_uframes_t offset, snd_pcm_uframes_t size) { snd_pcm_hw_t *hw = pcm->private_data; @@ -698,6 +718,12 @@ static snd_pcm_sframes_t snd_pcm_hw_mmap_commit(snd_pcm_t *pcm, if (hw->mmap_shm) { if (pcm->stream == SND_PCM_STREAM_PLAYBACK) { snd_pcm_sframes_t result = 0, res; + snd_pcm_uframes_t last_offset; + + /* FIXME */ + last_offset = *pcm->appl.ptr - offset; + if (last_offset != offset) + return -EINVAL; do { res = snd_pcm_write_mmap(pcm, size); @@ -793,6 +819,7 @@ static snd_pcm_fast_ops_t snd_pcm_hw_fast_ops = { status: snd_pcm_hw_status, state: snd_pcm_hw_state, hwsync: snd_pcm_hw_hwsync, + hwptr: snd_pcm_hw_hwptr, delay: snd_pcm_hw_delay, prepare: snd_pcm_hw_prepare, reset: snd_pcm_hw_reset, diff --git a/src/pcm/pcm_jack.c b/src/pcm/pcm_jack.c index dc66dbdd..69625901 100644 --- a/src/pcm/pcm_jack.c +++ b/src/pcm/pcm_jack.c @@ -185,6 +185,24 @@ static int snd_pcm_jack_hwsync(snd_pcm_t *pcm ATTRIBUTE_UNUSED) return 0; } +static int snd_pcm_jack_hwptr(snd_pcm_t *pcm, snd_pcm_uframes_t *hwptr) +{ +#ifdef PCM_JACK_DEBUG + printf("snd_pcm_jack_hwptr\n"); fflush(stdout); +#endif + switch (snd_pcm_state(pcm)) { + case SND_PCM_STATE_RUNNING: + case SND_PCM_STATE_DRAINING: + case SND_PCM_STATE_PREPARED: + case SND_PCM_STATE_PAUSED: + case SND_PCM_STATE_SUSPENDED: + *hwptr = *pcm->hw.ptr; + return 0; + default: + return -EBADFD; + } +} + static int snd_pcm_jack_delay(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_sframes_t *delayp) { #ifdef PCM_JACK_DEBUG @@ -593,6 +611,7 @@ static snd_pcm_fast_ops_t snd_pcm_jack_fast_ops = { status: snd_pcm_jack_status, state: snd_pcm_jack_state, hwsync: snd_pcm_jack_hwsync, + hwptr: snd_pcm_jack_hwptr, delay: snd_pcm_jack_delay, prepare: snd_pcm_jack_prepare, reset: snd_pcm_jack_reset, diff --git a/src/pcm/pcm_local.h b/src/pcm/pcm_local.h index 5060b702..0866ca7b 100644 --- a/src/pcm/pcm_local.h +++ b/src/pcm/pcm_local.h @@ -147,6 +147,7 @@ typedef struct { int (*pause)(snd_pcm_t *pcm, int enable); snd_pcm_state_t (*state)(snd_pcm_t *pcm); int (*hwsync)(snd_pcm_t *pcm); + int (*hwptr)(snd_pcm_t *pcm, snd_pcm_uframes_t *hwptr); 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); @@ -549,6 +550,8 @@ int snd_pcm_hw_param_get_max(const snd_pcm_hw_params_t *params, unsigned int *val, int *dir); #ifdef INTERNAL +int INTERNAL(snd_pcm_hwptr)(snd_pcm_t *pcm, snd_pcm_uframes_t *hwptr); + int INTERNAL(snd_pcm_hw_params_get_access)(const snd_pcm_hw_params_t *params, snd_pcm_access_t *access); int snd_pcm_hw_params_test_access(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_access_t access); int snd_pcm_hw_params_set_access(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_access_t access); diff --git a/src/pcm/pcm_meter.c b/src/pcm/pcm_meter.c index 0eb6a07e..8d163b19 100644 --- a/src/pcm/pcm_meter.c +++ b/src/pcm/pcm_meter.c @@ -325,6 +325,12 @@ static int snd_pcm_meter_hwsync(snd_pcm_t *pcm) return snd_pcm_hwsync(meter->slave); } +static int snd_pcm_meter_hwptr(snd_pcm_t *pcm, snd_pcm_uframes_t *hwptr) +{ + snd_pcm_meter_t *meter = pcm->private_data; + return INTERNAL(snd_pcm_hwptr)(meter->slave, hwptr); +} + static int snd_pcm_meter_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp) { snd_pcm_meter_t *meter = pcm->private_data; diff --git a/src/pcm/pcm_multi.c b/src/pcm/pcm_multi.c index 0be87165..9373cdf1 100644 --- a/src/pcm/pcm_multi.c +++ b/src/pcm/pcm_multi.c @@ -89,7 +89,7 @@ static int snd_pcm_multi_nonblock(snd_pcm_t *pcm ATTRIBUTE_UNUSED, int nonblock static int snd_pcm_multi_async(snd_pcm_t *pcm, int sig, pid_t pid) { snd_pcm_multi_t *multi = pcm->private_data; - snd_pcm_t *slave_0 = multi->slaves[0].pcm; + snd_pcm_t *slave_0 = multi->slaves[multi->master_slave].pcm; return snd_pcm_async(slave_0, sig, pid); } @@ -340,28 +340,35 @@ static int snd_pcm_multi_sw_params(snd_pcm_t *pcm, snd_pcm_sw_params_t *params) static int snd_pcm_multi_status(snd_pcm_t *pcm, snd_pcm_status_t *status) { snd_pcm_multi_t *multi = pcm->private_data; - snd_pcm_t *slave = multi->slaves[0].pcm; + snd_pcm_t *slave = multi->slaves[multi->master_slave].pcm; return snd_pcm_status(slave, status); } static snd_pcm_state_t snd_pcm_multi_state(snd_pcm_t *pcm) { snd_pcm_multi_t *multi = pcm->private_data; - snd_pcm_t *slave = multi->slaves[0].pcm; + snd_pcm_t *slave = multi->slaves[multi->master_slave].pcm; return snd_pcm_state(slave); } static int snd_pcm_multi_hwsync(snd_pcm_t *pcm) { snd_pcm_multi_t *multi = pcm->private_data; - snd_pcm_t *slave = multi->slaves[0].pcm; + snd_pcm_t *slave = multi->slaves[multi->master_slave].pcm; return snd_pcm_hwsync(slave); } +static int snd_pcm_multi_hwptr(snd_pcm_t *pcm, snd_pcm_uframes_t *hwptr) +{ + snd_pcm_multi_t *multi = pcm->private_data; + snd_pcm_t *slave = multi->slaves[multi->master_slave].pcm; + return INTERNAL(snd_pcm_hwptr)(slave, hwptr); +} + static int snd_pcm_multi_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp) { snd_pcm_multi_t *multi = pcm->private_data; - snd_pcm_t *slave = multi->slaves[0].pcm; + snd_pcm_t *slave = multi->slaves[multi->master_slave].pcm; return snd_pcm_delay(slave, delayp); } @@ -602,6 +609,7 @@ static snd_pcm_fast_ops_t snd_pcm_multi_fast_ops = { status: snd_pcm_multi_status, state: snd_pcm_multi_state, hwsync: snd_pcm_multi_hwsync, + hwptr: snd_pcm_multi_hwptr, 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 a727f2b1..239e9166 100644 --- a/src/pcm/pcm_null.c +++ b/src/pcm/pcm_null.c @@ -105,6 +105,23 @@ static int snd_pcm_null_hwsync(snd_pcm_t *pcm ATTRIBUTE_UNUSED) return 0; } +static int snd_pcm_null_hwptr(snd_pcm_t *pcm, snd_pcm_uframes_t *hwptr) +{ + switch (snd_pcm_state(pcm)) { + case SND_PCM_STATE_RUNNING: + case SND_PCM_STATE_DRAINING: + case SND_PCM_STATE_PREPARED: + case SND_PCM_STATE_PAUSED: + case SND_PCM_STATE_SUSPENDED: + *hwptr = *pcm->hw.ptr; + return 0; + case SND_PCM_STATE_XRUN: + return -EPIPE; + default: + return -EBADFD; + } +} + static int snd_pcm_null_delay(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_sframes_t *delayp) { *delayp = 0; @@ -312,6 +329,7 @@ static snd_pcm_fast_ops_t snd_pcm_null_fast_ops = { status: snd_pcm_null_status, state: snd_pcm_null_state, hwsync: snd_pcm_null_hwsync, + hwptr: snd_pcm_null_hwptr, 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 b01d30f8..9be8ffbb 100644 --- a/src/pcm/pcm_plugin.c +++ b/src/pcm/pcm_plugin.c @@ -199,6 +199,12 @@ int snd_pcm_plugin_hwsync(snd_pcm_t *pcm) return snd_pcm_hwsync(plugin->slave); } +int snd_pcm_plugin_hwptr(snd_pcm_t *pcm, snd_pcm_uframes_t *hwptr) +{ + snd_pcm_plugin_t *plugin = pcm->private_data; + return INTERNAL(snd_pcm_hwptr)(plugin->slave, hwptr); +} + int snd_pcm_plugin_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp) { snd_pcm_plugin_t *plugin = pcm->private_data; @@ -626,6 +632,7 @@ snd_pcm_fast_ops_t snd_pcm_plugin_fast_ops = { status: snd_pcm_plugin_status, state: snd_pcm_plugin_state, hwsync: snd_pcm_plugin_hwsync, + hwptr: snd_pcm_plugin_hwptr, 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 7b82296c..02290df7 100644 --- a/src/pcm/pcm_share.c +++ b/src/pcm/pcm_share.c @@ -737,6 +737,36 @@ static int snd_pcm_share_hwsync(snd_pcm_t *pcm) return err; } +static int _snd_pcm_share_hwptr(snd_pcm_t *pcm, snd_pcm_uframes_t *hwptr) +{ + snd_pcm_share_t *share = pcm->private_data; + snd_pcm_share_slave_t *slave = share->slave; + switch (share->state) { + case SND_PCM_STATE_RUNNING: + case SND_PCM_STATE_DRAINING: + case SND_PCM_STATE_PREPARED: + case SND_PCM_STATE_PAUSED: + case SND_PCM_STATE_SUSPENDED: + *hwptr = *pcm->hw.ptr; + return 0; + case SND_PCM_STATE_XRUN: + return -EPIPE; + default: + return -EBADFD; + } +} + +static int snd_pcm_share_hwptr(snd_pcm_t *pcm, snd_pcm_uframes_t *hwptr) +{ + 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_hwptr(pcm, hwptr); + 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; @@ -1234,6 +1264,7 @@ static snd_pcm_fast_ops_t snd_pcm_share_fast_ops = { status: snd_pcm_share_status, state: snd_pcm_share_state, hwsync: snd_pcm_share_hwsync, + hwptr: snd_pcm_share_hwptr, 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 68786326..65194d14 100644 --- a/src/pcm/pcm_shm.c +++ b/src/pcm/pcm_shm.c @@ -451,6 +451,19 @@ static int snd_pcm_shm_hwsync(snd_pcm_t *pcm) return snd_pcm_shm_action(pcm); } +static int snd_pcm_shm_hwptr(snd_pcm_t *pcm, snd_pcm_uframes_t *uframes) +{ + snd_pcm_shm_t *shm = pcm->private_data; + volatile snd_pcm_shm_ctrl_t *ctrl = shm->ctrl; + int err; + ctrl->cmd = SND_PCM_IOCTL_HWPTR; + return snd_pcm_shm_action(pcm); + if (err < 0) + return err; + *uframes = ctrl->u.hwptr.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; @@ -619,6 +632,7 @@ static snd_pcm_fast_ops_t snd_pcm_shm_fast_ops = { status: snd_pcm_shm_status, state: snd_pcm_shm_state, hwsync: snd_pcm_shm_hwsync, + hwptr: snd_pcm_shm_hwptr, delay: snd_pcm_shm_delay, prepare: snd_pcm_shm_prepare, reset: snd_pcm_shm_reset, -- 2.47.1