diff options
-rw-r--r-- | aserver/aserver.c | 6 | ||||
-rw-r--r-- | include/aserver.h | 8 | ||||
-rw-r--r-- | include/pcm.h | 3 | ||||
-rw-r--r-- | src/Versions | 3 | ||||
-rw-r--r-- | src/pcm/pcm.c | 73 | ||||
-rw-r--r-- | src/pcm/pcm_dmix.c | 34 | ||||
-rw-r--r-- | src/pcm/pcm_file.c | 43 | ||||
-rw-r--r-- | src/pcm/pcm_hooks.c | 14 | ||||
-rw-r--r-- | src/pcm/pcm_hw.c | 53 | ||||
-rw-r--r-- | src/pcm/pcm_jack.c | 36 | ||||
-rw-r--r-- | src/pcm/pcm_local.h | 5 | ||||
-rw-r--r-- | src/pcm/pcm_meter.c | 16 | ||||
-rw-r--r-- | src/pcm/pcm_multi.c | 41 | ||||
-rw-r--r-- | src/pcm/pcm_null.c | 34 | ||||
-rw-r--r-- | src/pcm/pcm_plugin.c | 84 | ||||
-rw-r--r-- | src/pcm/pcm_share.c | 96 | ||||
-rw-r--r-- | src/pcm/pcm_shm.c | 24 |
17 files changed, 327 insertions, 246 deletions
diff --git a/aserver/aserver.c b/aserver/aserver.c index a6b4a4e2..cef3641c 100644 --- a/aserver/aserver.c +++ b/aserver/aserver.c @@ -471,9 +471,6 @@ 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; @@ -507,6 +504,9 @@ static int pcm_shm_cmd(client_t *client) case SNDRV_PCM_IOCTL_REWIND: ctrl->result = snd_pcm_rewind(pcm, ctrl->u.rewind.frames); break; + case SND_PCM_IOCTL_FORWARD: + ctrl->result = snd_pcm_forward(pcm, ctrl->u.forward.frames); + break; case SNDRV_PCM_IOCTL_LINK: { /* FIXME */ diff --git a/include/aserver.h b/include/aserver.h index c6e9f957..25868324 100644 --- a/include/aserver.h +++ b/include/aserver.h @@ -50,7 +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) +#define SND_PCM_IOCTL_FORWARD _IO ('A', 0xfb) typedef struct { snd_pcm_uframes_t ptr; @@ -76,9 +76,6 @@ typedef struct { snd_pcm_status_t status; struct { snd_pcm_uframes_t frames; - } hwptr; - struct { - snd_pcm_uframes_t frames; } avail; struct { snd_pcm_sframes_t frames; @@ -91,6 +88,9 @@ typedef struct { snd_pcm_uframes_t frames; } rewind; struct { + snd_pcm_uframes_t frames; + } forward; + struct { int fd; } link; struct { diff --git a/include/pcm.h b/include/pcm.h index 0ea5012c..e2121886 100644 --- a/include/pcm.h +++ b/include/pcm.h @@ -410,11 +410,12 @@ 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_hwdiff(snd_pcm_t *pcm, snd_pcm_uframes_t *diff, snd_pcm_uframes_t *old_pos); 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); snd_pcm_sframes_t snd_pcm_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t frames); +snd_pcm_sframes_t snd_pcm_forward(snd_pcm_t *pcm, snd_pcm_uframes_t frames); snd_pcm_sframes_t snd_pcm_writei(snd_pcm_t *pcm, const void *buffer, snd_pcm_uframes_t size); snd_pcm_sframes_t snd_pcm_readi(snd_pcm_t *pcm, void *buffer, snd_pcm_uframes_t size); snd_pcm_sframes_t snd_pcm_writen(snd_pcm_t *pcm, void **bufs, snd_pcm_uframes_t size); diff --git a/src/Versions b/src/Versions index 6abc98e4..ea45321a 100644 --- a/src/Versions +++ b/src/Versions @@ -83,6 +83,7 @@ ALSA_0.9.0rc4 { ALSA_0.9.0rc8 { global: - snd_pcm_hwptr; + snd_pcm_hwdiff; + snd_pcm_forward; } ALSA_0.9.0rc4; diff --git a/src/pcm/pcm.c b/src/pcm/pcm.c index 9383346e..b53c43c7 100644 --- a/src/pcm/pcm.c +++ b/src/pcm/pcm.c @@ -400,6 +400,12 @@ 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. +<p> +To determine the processed frames by hardware, the function \link ::snd_pcm_hwdiff \endlink +might be used. Note that this function returns cached value which is synchronized with +hardware using the \link ::snd_pcm_hwsync \endlink function. The application may +manage the right r/w pointer via \link ::snd_pcm_rewind \endlink and +\link ::snd_pcm_forward \endlink functions. \section pcm_action Managing the stream state @@ -869,28 +875,42 @@ int snd_pcm_hwsync(snd_pcm_t *pcm) } /** - * \brief Return hardware pointer + * \brief Return count of processed frames by hardware from last call * \param pcm PCM handle + * \param diff Difference between last position and current + * \param old_pos Old position on entry, actual position on exit * \return 0 on success otherwise a negative error code * - * The hardware pointer is in range 0 ... (boundary - 1). It contains + * The old_ptr parameter is in range 0 ... (boundary - 1). It contains * count_of_ring_buffer_crosses * buffer_size + offset in the ring buffer. + * Using this value is not intented * - * Note this function does not return the real hardware pointer. + * Note this function does not obtain the real position from hardware. * 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) +int INTERNAL(snd_pcm_hwdiff)(snd_pcm_t *pcm, snd_pcm_uframes_t *diff, snd_pcm_uframes_t *old_pos) #else -int snd_pcm_hwptr(snd_pcm_t *pcm, snd_pcm_uframes_t *hwptr) +int snd_pcm_hwdiff(snd_pcm_t *pcm, snd_pcm_uframes_t *diff, snd_pcm_uframes_t *old_pos) #endif { - assert(pcm); + snd_pcm_uframes_t d, hw_ptr; + + assert(pcm && diff && old_pos); assert(pcm->setup); - return pcm->fast_ops->hwptr(pcm->fast_op_arg, hwptr); + assert(*old_pos < pcm->boundary); + hw_ptr = *pcm->hw.ptr; + if (hw_ptr < *old_pos) { + d = (pcm->boundary - *old_pos) + hw_ptr; + } else { + d = hw_ptr - *old_pos; + } + *diff = d; + *old_pos = hw_ptr; + return 0; } -default_symbol_version(__snd_pcm_hwptr, snd_pcm_hwptr, ALSA_0.9.0rc8); +default_symbol_version(__snd_pcm_hwdiff, snd_pcm_hwdiff, ALSA_0.9.0rc8); /** * \brief Obtain delay for a running PCM handle @@ -1030,6 +1050,25 @@ snd_pcm_sframes_t snd_pcm_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t frames) } /** + * \brief Move application frame position forward + * \param pcm PCM handle + * \param frames wanted skip in frames + * \return a positive number for actual skip otherwise a negative error code + */ +#ifndef DOXYGEN +snd_pcm_sframes_t INTERNAL(snd_pcm_forward)(snd_pcm_t *pcm, snd_pcm_uframes_t frames) +#else +snd_pcm_sframes_t snd_pcm_forward(snd_pcm_t *pcm, snd_pcm_uframes_t frames) +#endif +{ + assert(pcm); + assert(pcm->setup); + assert(frames > 0); + return pcm->fast_ops->forward(pcm->fast_op_arg, frames); +} +default_symbol_version(__snd_pcm_forward, snd_pcm_forward, ALSA_0.9.0rc8); + +/** * \brief Write interleaved frames to a PCM * \param pcm PCM handle * \param buffer frames containing buffer @@ -5816,7 +5855,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 mmap area offset in area steps (== frames) (wanted on entry (see note), returned on exit) + * \param offset Returned mmap area offset in area steps (== frames) * \param frames mmap area portion size in frames (wanted on entry, contiguous available on exit) * \return 0 on success otherwise a negative error code * @@ -5829,10 +5868,6 @@ 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, const snd_pcm_channel_area_t **areas, @@ -5844,16 +5879,10 @@ 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); - 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; + *offset = *pcm->appl.ptr % pcm->buffer_size; + avail = snd_pcm_mmap_avail(pcm); + if (avail > pcm->buffer_size) avail = pcm->buffer_size; - } cont = pcm->buffer_size - *offset; f = *frames; if (f > avail) diff --git a/src/pcm/pcm_dmix.c b/src/pcm/pcm_dmix.c index ca322b89..588b3020 100644 --- a/src/pcm/pcm_dmix.c +++ b/src/pcm/pcm_dmix.c @@ -989,25 +989,6 @@ 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; @@ -1108,6 +1089,19 @@ static snd_pcm_sframes_t snd_pcm_dmix_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t f return frames; } +static snd_pcm_sframes_t snd_pcm_dmix_forward(snd_pcm_t *pcm, snd_pcm_uframes_t frames) +{ + snd_pcm_sframes_t avail; + + avail = snd_pcm_mmap_avail(pcm); + if (avail < 0) + return 0; + if (frames > avail) + frames = avail; + snd_pcm_mmap_appl_forward(pcm, frames); + return frames; +} + static int snd_pcm_dmix_resume(snd_pcm_t *pcm ATTRIBUTE_UNUSED) { // snd_pcm_dmix_t *dmix = pcm->private_data; @@ -1224,7 +1218,6 @@ 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, @@ -1233,6 +1226,7 @@ static snd_pcm_fast_ops_t snd_pcm_dmix_fast_ops = { drain: snd_pcm_dmix_drain, pause: snd_pcm_dmix_pause, rewind: snd_pcm_dmix_rewind, + forward: snd_pcm_dmix_forward, resume: snd_pcm_dmix_resume, writei: snd_pcm_mmap_writei, writen: snd_pcm_mmap_writen, diff --git a/src/pcm/pcm_file.c b/src/pcm/pcm_file.c index 4ecb44aa..bcedc0e2 100644 --- a/src/pcm/pcm_file.c +++ b/src/pcm/pcm_file.c @@ -168,12 +168,6 @@ 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; @@ -236,19 +230,37 @@ static int snd_pcm_file_pause(snd_pcm_t *pcm, int enable) static snd_pcm_sframes_t snd_pcm_file_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t frames) { snd_pcm_file_t *file = pcm->private_data; - snd_pcm_sframes_t err = snd_pcm_rewind(file->slave, frames); + snd_pcm_sframes_t err; + snd_pcm_uframes_t n; + + n = snd_pcm_frames_to_bytes(pcm, frames); + if (n > file->wbuf_used_bytes) + frames = snd_pcm_bytes_to_frames(pcm, file->wbuf_used_bytes); + err = snd_pcm_rewind(file->slave, frames); if (err > 0) { - snd_pcm_uframes_t n = snd_pcm_frames_to_bytes(pcm, frames); - snd_pcm_sframes_t ptr; - assert(n >= file->wbuf_used_bytes); - ptr = file->appl_ptr - err; - if (ptr < 0) - ptr += file->wbuf_size; + n = snd_pcm_frames_to_bytes(pcm, err); file->wbuf_used_bytes -= n; } return err; } +static snd_pcm_sframes_t snd_pcm_file_forward(snd_pcm_t *pcm, snd_pcm_uframes_t frames) +{ + snd_pcm_file_t *file = pcm->private_data; + snd_pcm_sframes_t err; + snd_pcm_uframes_t n; + + n = snd_pcm_frames_to_bytes(pcm, frames); + if (file->wbuf_used_bytes + n > file->wbuf_size_bytes) + frames = snd_pcm_bytes_to_frames(pcm, file->wbuf_size_bytes - file->wbuf_used_bytes); + err = snd_pcm_forward(file->slave, frames); + if (err > 0) { + snd_pcm_uframes_t n = snd_pcm_frames_to_bytes(pcm, err); + file->wbuf_used_bytes += n; + } + return err; +} + static int snd_pcm_file_resume(snd_pcm_t *pcm) { snd_pcm_file_t *file = pcm->private_data; @@ -372,9 +384,6 @@ 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); } @@ -422,7 +431,6 @@ 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, @@ -431,6 +439,7 @@ static snd_pcm_fast_ops_t snd_pcm_file_fast_ops = { drain: snd_pcm_file_drain, pause: snd_pcm_file_pause, rewind: snd_pcm_file_rewind, + forward: snd_pcm_file_forward, resume: snd_pcm_file_resume, writei: snd_pcm_file_writei, writen: snd_pcm_file_writen, diff --git a/src/pcm/pcm_hooks.c b/src/pcm/pcm_hooks.c index c4cbd0a9..dd88a564 100644 --- a/src/pcm/pcm_hooks.c +++ b/src/pcm/pcm_hooks.c @@ -122,12 +122,6 @@ 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; @@ -176,6 +170,12 @@ static snd_pcm_sframes_t snd_pcm_hooks_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t return snd_pcm_rewind(h->slave, frames); } +static snd_pcm_sframes_t snd_pcm_hooks_forward(snd_pcm_t *pcm, snd_pcm_uframes_t frames) +{ + snd_pcm_hooks_t *h = pcm->private_data; + return snd_pcm_forward(h->slave, frames); +} + static int snd_pcm_hooks_resume(snd_pcm_t *pcm) { snd_pcm_hooks_t *h = pcm->private_data; @@ -305,7 +305,6 @@ 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, @@ -314,6 +313,7 @@ static snd_pcm_fast_ops_t snd_pcm_hooks_fast_ops = { drain: snd_pcm_hooks_drain, pause: snd_pcm_hooks_pause, rewind: snd_pcm_hooks_rewind, + forward: snd_pcm_hooks_forward, resume: snd_pcm_hooks_resume, writei: snd_pcm_hooks_writei, writen: snd_pcm_hooks_writen, diff --git a/src/pcm/pcm_hw.c b/src/pcm/pcm_hw.c index b04bc55a..ef27ea84 100644 --- a/src/pcm/pcm_hw.c +++ b/src/pcm/pcm_hw.c @@ -345,9 +345,6 @@ 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; @@ -431,23 +428,6 @@ 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; @@ -534,6 +514,31 @@ static snd_pcm_sframes_t snd_pcm_hw_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t fra return frames; } +static snd_pcm_sframes_t snd_pcm_hw_forward(snd_pcm_t *pcm, snd_pcm_uframes_t frames) +{ + snd_pcm_hw_t *hw = pcm->private_data; + snd_pcm_sframes_t avail; + + switch (FAST_PCM_STATE(hw)) { + case SNDRV_PCM_STATE_RUNNING: + case SNDRV_PCM_STATE_DRAINING: + case SNDRV_PCM_STATE_PAUSED: + case SNDRV_PCM_STATE_PREPARED: + break; + case SNDRV_PCM_STATE_XRUN: + return -EPIPE; + default: + return -EBADFD; + } + avail = snd_pcm_mmap_avail(pcm); + if (avail < 0) + return 0; + if (frames > avail) + frames = avail; + snd_pcm_mmap_appl_forward(pcm, frames); + return frames; +} + static int snd_pcm_hw_resume(snd_pcm_t *pcm) { snd_pcm_hw_t *hw = pcm->private_data; @@ -718,12 +723,6 @@ 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); @@ -819,7 +818,6 @@ 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, @@ -828,6 +826,7 @@ static snd_pcm_fast_ops_t snd_pcm_hw_fast_ops = { drain: snd_pcm_hw_drain, pause: snd_pcm_hw_pause, rewind: snd_pcm_hw_rewind, + forward: snd_pcm_hw_forward, resume: snd_pcm_hw_resume, writei: snd_pcm_hw_writei, writen: snd_pcm_hw_writen, diff --git a/src/pcm/pcm_jack.c b/src/pcm/pcm_jack.c index 69625901..eebb496c 100644 --- a/src/pcm/pcm_jack.c +++ b/src/pcm/pcm_jack.c @@ -185,24 +185,6 @@ 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 @@ -460,6 +442,22 @@ static snd_pcm_sframes_t snd_pcm_jack_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t f return frames; } +static snd_pcm_sframes_t snd_pcm_jack_forward(snd_pcm_t *pcm, snd_pcm_uframes_t frames) +{ + snd_pcm_sframes_t avail; + +#ifdef PCM_JACK_DEBUG + printf("snd_pcm_jack_forward\n"); fflush(stdout); +#endif + avail = snd_pcm_mmap_avail(pcm); + if (avail < 0) + return 0; + if (frames > (snd_pcm_uframes_t) avail) + frames = (snd_pcm_uframes_t) avail; + snd_pcm_mmap_appl_forward(pcm, frames); + return frames; +} + static int snd_pcm_jack_resume(snd_pcm_t *pcm ATTRIBUTE_UNUSED) { return 0; @@ -611,7 +609,6 @@ 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, @@ -620,6 +617,7 @@ static snd_pcm_fast_ops_t snd_pcm_jack_fast_ops = { drain: snd_pcm_jack_drain, pause: snd_pcm_jack_pause, rewind: snd_pcm_jack_rewind, + forward: snd_pcm_jack_forward, resume: snd_pcm_jack_resume, writei: snd_pcm_mmap_writei, writen: snd_pcm_mmap_writen, diff --git a/src/pcm/pcm_local.h b/src/pcm/pcm_local.h index 0866ca7b..bc85ebc4 100644 --- a/src/pcm/pcm_local.h +++ b/src/pcm/pcm_local.h @@ -147,10 +147,10 @@ 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); + snd_pcm_sframes_t (*forward)(snd_pcm_t *pcm, snd_pcm_uframes_t frames); snd_pcm_sframes_t (*writei)(snd_pcm_t *pcm, const void *buffer, snd_pcm_uframes_t size); snd_pcm_sframes_t (*writen)(snd_pcm_t *pcm, void **bufs, snd_pcm_uframes_t size); snd_pcm_sframes_t (*readi)(snd_pcm_t *pcm, void *buffer, snd_pcm_uframes_t size); @@ -550,7 +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_hwdiff)(snd_pcm_t *pcm, snd_pcm_uframes_t *diff, snd_pcm_uframes_t *old_pos); +snd_pcm_sframes_t INTERNAL(snd_pcm_forward)(snd_pcm_t *pcm, snd_pcm_uframes_t frames); 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); diff --git a/src/pcm/pcm_meter.c b/src/pcm/pcm_meter.c index 8d163b19..0858382c 100644 --- a/src/pcm/pcm_meter.c +++ b/src/pcm/pcm_meter.c @@ -325,12 +325,6 @@ 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; @@ -402,6 +396,15 @@ static snd_pcm_sframes_t snd_pcm_meter_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t return err; } +static snd_pcm_sframes_t snd_pcm_meter_forward(snd_pcm_t *pcm, snd_pcm_uframes_t frames) +{ + snd_pcm_meter_t *meter = pcm->private_data; + snd_pcm_sframes_t err = snd_pcm_forward(meter->slave, frames); + if (err > 0 && pcm->stream == SND_PCM_STREAM_PLAYBACK) + meter->rptr = *pcm->appl.ptr; + return err; +} + static int snd_pcm_meter_resume(snd_pcm_t *pcm) { snd_pcm_meter_t *meter = pcm->private_data; @@ -614,6 +617,7 @@ static snd_pcm_fast_ops_t snd_pcm_meter_fast_ops = { drain: snd_pcm_meter_drain, pause: snd_pcm_meter_pause, rewind: snd_pcm_meter_rewind, + forward: snd_pcm_meter_forward, resume: snd_pcm_meter_resume, writei: snd_pcm_mmap_writei, writen: snd_pcm_mmap_writen, diff --git a/src/pcm/pcm_multi.c b/src/pcm/pcm_multi.c index 9373cdf1..84163313 100644 --- a/src/pcm/pcm_multi.c +++ b/src/pcm/pcm_multi.c @@ -358,13 +358,6 @@ static int snd_pcm_multi_hwsync(snd_pcm_t *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; @@ -512,7 +505,37 @@ static snd_pcm_sframes_t snd_pcm_multi_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t snd_pcm_uframes_t f = pos[i] - frames; snd_pcm_sframes_t result; if (f > 0) { - result = snd_pcm_mmap_commit(slave_i, snd_pcm_mmap_offset(slave_i), f); + result = snd_pcm_forward(slave_i, f); + if (result < 0) + return result; + if ((snd_pcm_uframes_t)result != f) + return -EIO; + } + } + return frames; +} + +static snd_pcm_sframes_t snd_pcm_multi_forward(snd_pcm_t *pcm, snd_pcm_uframes_t frames) +{ + snd_pcm_multi_t *multi = pcm->private_data; + unsigned int i; + snd_pcm_uframes_t pos[multi->slaves_count]; + memset(pos, 0, sizeof(pos)); + for (i = 0; i < multi->slaves_count; ++i) { + snd_pcm_t *slave_i = multi->slaves[i].pcm; + snd_pcm_sframes_t f = snd_pcm_forward(slave_i, frames); + if (f < 0) + return f; + pos[i] = f; + frames = f; + } + /* Realign the pointers */ + for (i = 0; i < multi->slaves_count; ++i) { + snd_pcm_t *slave_i = multi->slaves[i].pcm; + snd_pcm_uframes_t f = pos[i] - frames; + snd_pcm_sframes_t result; + if (f > 0) { + result = snd_pcm_rewind(slave_i, f); if (result < 0) return result; if ((snd_pcm_uframes_t)result != f) @@ -609,7 +632,6 @@ 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, @@ -622,6 +644,7 @@ static snd_pcm_fast_ops_t snd_pcm_multi_fast_ops = { readi: snd_pcm_mmap_readi, readn: snd_pcm_mmap_readn, rewind: snd_pcm_multi_rewind, + forward: snd_pcm_multi_forward, resume: snd_pcm_multi_resume, avail_update: snd_pcm_multi_avail_update, mmap_commit: snd_pcm_multi_mmap_commit, diff --git a/src/pcm/pcm_null.c b/src/pcm/pcm_null.c index 239e9166..79e21b08 100644 --- a/src/pcm/pcm_null.c +++ b/src/pcm/pcm_null.c @@ -105,23 +105,6 @@ 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; @@ -202,6 +185,21 @@ static snd_pcm_sframes_t snd_pcm_null_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t f } } +static snd_pcm_sframes_t snd_pcm_null_forward(snd_pcm_t *pcm, snd_pcm_uframes_t frames) +{ + snd_pcm_null_t *null = pcm->private_data; + switch (null->state) { + case SND_PCM_STATE_RUNNING: + snd_pcm_mmap_hw_forward(pcm, frames); + /* Fall through */ + case SND_PCM_STATE_PREPARED: + snd_pcm_mmap_appl_forward(pcm, frames); + return frames; + default: + return -EBADFD; + } +} + static int snd_pcm_null_resume(snd_pcm_t *pcm ATTRIBUTE_UNUSED) { return 0; @@ -329,7 +327,6 @@ 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, @@ -338,6 +335,7 @@ static snd_pcm_fast_ops_t snd_pcm_null_fast_ops = { drain: snd_pcm_null_drain, pause: snd_pcm_null_pause, rewind: snd_pcm_null_rewind, + forward: snd_pcm_null_forward, resume: snd_pcm_null_resume, writei: snd_pcm_null_writei, writen: snd_pcm_null_writen, diff --git a/src/pcm/pcm_plugin.c b/src/pcm/pcm_plugin.c index 9be8ffbb..51e56475 100644 --- a/src/pcm/pcm_plugin.c +++ b/src/pcm/pcm_plugin.c @@ -199,12 +199,6 @@ 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; @@ -288,34 +282,56 @@ snd_pcm_sframes_t snd_pcm_plugin_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t frames { snd_pcm_plugin_t *plugin = pcm->private_data; snd_pcm_sframes_t n = snd_pcm_mmap_hw_avail(pcm); - assert(n >= 0); - if (n > 0) { - if ((snd_pcm_uframes_t)n > frames) - n = frames; - frames -= n; + snd_pcm_sframes_t sframes; + + if ((snd_pcm_uframes_t)n > frames) + frames = n; + if (frames == 0) + return 0; + + /* FIXME: rate plugin */ + if (plugin->slave_frames) + sframes = plugin->slave_frames(pcm, (snd_pcm_sframes_t) frames); + else + sframes = frames; + snd_atomic_write_begin(&plugin->watom); + sframes = snd_pcm_rewind(plugin->slave, sframes); + if (sframes < 0) { + snd_atomic_write_end(&plugin->watom); + return sframes; } - if (frames > 0) { - snd_pcm_sframes_t err; - /* FIXME: rate plugin */ - if (plugin->slave_frames) - frames = plugin->slave_frames(pcm, (snd_pcm_sframes_t) frames); - snd_atomic_write_begin(&plugin->watom); - err = snd_pcm_rewind(plugin->slave, frames); - if (err < 0) { - if (n <= 0) { - snd_atomic_write_end(&plugin->watom); - return err; - } - goto _end; - } - if (plugin->client_frames) - err = plugin->client_frames(pcm, err); - snd_pcm_mmap_hw_backward(pcm, (snd_pcm_uframes_t) err); - n += err; - } else - snd_atomic_write_begin(&plugin->watom); - _end: - snd_pcm_mmap_appl_backward(pcm, (snd_pcm_uframes_t) n); + if (plugin->client_frames) + frames = plugin->client_frames(pcm, sframes); + snd_pcm_mmap_appl_backward(pcm, (snd_pcm_uframes_t) frames); + snd_atomic_write_end(&plugin->watom); + return n; +} + +snd_pcm_sframes_t snd_pcm_plugin_forward(snd_pcm_t *pcm, snd_pcm_uframes_t frames) +{ + snd_pcm_plugin_t *plugin = pcm->private_data; + snd_pcm_sframes_t n = snd_pcm_mmap_avail(pcm); + snd_pcm_uframes_t sframes; + + if ((snd_pcm_uframes_t)n > frames) + frames = n; + if (frames == 0) + return 0; + + /* FIXME: rate plugin */ + if (plugin->slave_frames) + sframes = plugin->slave_frames(pcm, (snd_pcm_sframes_t) frames); + else + sframes = frames; + snd_atomic_write_begin(&plugin->watom); + sframes = snd_pcm_forward(plugin->slave, (snd_pcm_uframes_t) sframes); + if (sframes < 0) { + snd_atomic_write_end(&plugin->watom); + return sframes; + } + if (plugin->client_frames) + frames = plugin->client_frames(pcm, sframes); + snd_pcm_mmap_appl_forward(pcm, (snd_pcm_uframes_t) frames); snd_atomic_write_end(&plugin->watom); return n; } @@ -632,7 +648,6 @@ 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, @@ -641,6 +656,7 @@ snd_pcm_fast_ops_t snd_pcm_plugin_fast_ops = { drain: snd_pcm_plugin_drain, pause: snd_pcm_plugin_pause, rewind: snd_pcm_plugin_rewind, + forward: snd_pcm_plugin_forward, resume: snd_pcm_plugin_resume, writei: snd_pcm_plugin_writei, writen: snd_pcm_plugin_writen, diff --git a/src/pcm/pcm_share.c b/src/pcm/pcm_share.c index 02290df7..eaa6402b 100644 --- a/src/pcm/pcm_share.c +++ b/src/pcm/pcm_share.c @@ -1,4 +1,4 @@ -/** +/* * \file pcm/pcm_share.c * \ingroup PCM_Plugins * \brief PCM Share Plugin Interface @@ -737,36 +737,6 @@ 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; @@ -1027,19 +997,15 @@ static snd_pcm_sframes_t _snd_pcm_share_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t } n = snd_pcm_mmap_hw_avail(pcm); assert(n >= 0); - if (n > 0) { - if ((snd_pcm_uframes_t)n > frames) - n = frames; - frames -= n; - } - if (share->state == SND_PCM_STATE_RUNNING && - frames > 0) { - int ret = snd_pcm_rewind(slave->pcm, frames); + if ((snd_pcm_uframes_t)n > frames) + frames = n; + if (share->state == SND_PCM_STATE_RUNNING && frames > 0) { + snd_pcm_sframes_t ret = snd_pcm_rewind(slave->pcm, frames); if (ret < 0) return ret; - n += ret; + frames = ret; } - snd_pcm_mmap_appl_backward(pcm, n); + snd_pcm_mmap_appl_backward(pcm, frames); _snd_pcm_share_update(pcm); return n; } @@ -1055,6 +1021,52 @@ static snd_pcm_sframes_t snd_pcm_share_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t return ret; } +static snd_pcm_sframes_t _snd_pcm_share_forward(snd_pcm_t *pcm, snd_pcm_uframes_t frames) +{ + snd_pcm_share_t *share = pcm->private_data; + snd_pcm_share_slave_t *slave = share->slave; + snd_pcm_sframes_t n; + switch (share->state) { + case SND_PCM_STATE_RUNNING: + break; + case SND_PCM_STATE_PREPARED: + if (pcm->stream != SND_PCM_STREAM_PLAYBACK) + return -EBADFD; + break; + case SND_PCM_STATE_DRAINING: + if (pcm->stream != SND_PCM_STREAM_CAPTURE) + return -EBADFD; + break; + case SND_PCM_STATE_XRUN: + return -EPIPE; + default: + return -EBADFD; + } + n = snd_pcm_mmap_avail(pcm); + if ((snd_pcm_uframes_t)n > frames) + frames = n; + if (share->state == SND_PCM_STATE_RUNNING && frames > 0) { + snd_pcm_sframes_t ret = snd_pcm_forward(slave->pcm, frames); + if (ret < 0) + return ret; + frames = ret; + } + snd_pcm_mmap_appl_forward(pcm, frames); + _snd_pcm_share_update(pcm); + return n; +} + +static snd_pcm_sframes_t snd_pcm_share_forward(snd_pcm_t *pcm, snd_pcm_uframes_t frames) +{ + snd_pcm_share_t *share = pcm->private_data; + snd_pcm_share_slave_t *slave = share->slave; + snd_pcm_sframes_t ret; + Pthread_mutex_lock(&slave->mutex); + ret = _snd_pcm_share_forward(pcm, frames); + Pthread_mutex_unlock(&slave->mutex); + return ret; +} + /* Warning: take the mutex before to call this */ static void _snd_pcm_share_stop(snd_pcm_t *pcm, snd_pcm_state_t state) { @@ -1264,7 +1276,6 @@ 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, @@ -1277,6 +1288,7 @@ static snd_pcm_fast_ops_t snd_pcm_share_fast_ops = { readi: snd_pcm_mmap_readi, readn: snd_pcm_mmap_readn, rewind: snd_pcm_share_rewind, + forward: snd_pcm_share_forward, resume: snd_pcm_share_resume, avail_update: snd_pcm_share_avail_update, mmap_commit: snd_pcm_share_mmap_commit, diff --git a/src/pcm/pcm_shm.c b/src/pcm/pcm_shm.c index 65194d14..619cdc52 100644 --- a/src/pcm/pcm_shm.c +++ b/src/pcm/pcm_shm.c @@ -451,19 +451,6 @@ 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; @@ -558,6 +545,15 @@ static snd_pcm_sframes_t snd_pcm_shm_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t fr return snd_pcm_shm_action(pcm); } +static snd_pcm_sframes_t snd_pcm_shm_forward(snd_pcm_t *pcm, snd_pcm_uframes_t frames) +{ + snd_pcm_shm_t *shm = pcm->private_data; + volatile snd_pcm_shm_ctrl_t *ctrl = shm->ctrl; + ctrl->cmd = SND_PCM_IOCTL_FORWARD; + ctrl->u.forward.frames = frames; + return snd_pcm_shm_action(pcm); +} + static int snd_pcm_shm_resume(snd_pcm_t *pcm) { snd_pcm_shm_t *shm = pcm->private_data; @@ -632,7 +628,6 @@ 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, @@ -641,6 +636,7 @@ static snd_pcm_fast_ops_t snd_pcm_shm_fast_ops = { drain: snd_pcm_shm_drain, pause: snd_pcm_shm_pause, rewind: snd_pcm_shm_rewind, + forward: snd_pcm_shm_forward, resume: snd_pcm_shm_resume, writei: snd_pcm_mmap_writei, writen: snd_pcm_mmap_writen, |