From e128bf856ee1f0257a4d57ce6419aeb8676bb2cb Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Thu, 21 Feb 2002 15:01:34 +0000 Subject: [PATCH] Cleaned the mmap_commit implementations in plugins. Added undo callbacks for snd_pcm_plugin based plugins. - helpers when mmap_commit proceed only a partial transfer Fixes to avail_update implementation in pcm_hw.c. --- src/pcm/pcm.c | 20 +------ src/pcm/pcm_adpcm.c | 1 + src/pcm/pcm_alaw.c | 3 + src/pcm/pcm_copy.c | 3 + src/pcm/pcm_file.c | 18 +++--- src/pcm/pcm_hooks.c | 6 +- src/pcm/pcm_hw.c | 37 ++++++++---- src/pcm/pcm_ladspa.c | 3 + src/pcm/pcm_lfloat.c | 3 + src/pcm/pcm_linear.c | 3 + src/pcm/pcm_local.h | 2 +- src/pcm/pcm_meter.c | 10 ++-- src/pcm/pcm_mmap.c | 30 +++++----- src/pcm/pcm_mulaw.c | 3 + src/pcm/pcm_multi.c | 26 +++++--- src/pcm/pcm_null.c | 9 ++- src/pcm/pcm_plugin.c | 138 +++++++++++++++++++++++++++++++++---------- src/pcm/pcm_plugin.h | 26 +++++++- src/pcm/pcm_rate.c | 1 + src/pcm/pcm_route.c | 3 + src/pcm/pcm_share.c | 25 +++++--- src/pcm/pcm_shm.c | 10 ++-- 22 files changed, 260 insertions(+), 120 deletions(-) diff --git a/src/pcm/pcm.c b/src/pcm/pcm.c index e7d85a26..0aa1740a 100644 --- a/src/pcm/pcm.c +++ b/src/pcm/pcm.c @@ -5122,7 +5122,7 @@ int snd_pcm_mmap_begin(snd_pcm_t *pcm, f = *frames; avail = snd_pcm_mmap_avail(pcm); if (avail > pcm->buffer_size) - return -EPIPE; + avail = pcm->buffer_size; if (f > avail) f = avail; if (f > cont) @@ -5187,26 +5187,10 @@ snd_pcm_sframes_t snd_pcm_mmap_commit(snd_pcm_t *pcm, snd_pcm_uframes_t offset, snd_pcm_uframes_t frames) { - int res; - snd_pcm_uframes_t appl_ptr; - assert(pcm); assert(offset == *pcm->appl_ptr % pcm->buffer_size); assert(frames <= snd_pcm_mmap_avail(pcm)); - appl_ptr = *pcm->appl_ptr; - res = pcm->fast_ops->mmap_commit(pcm->fast_op_arg, offset, frames); - if (res < 0) { - snd_pcm_sframes_t diff; - - if (appl_ptr == *pcm->appl_ptr) - return res; - diff = *pcm->appl_ptr - appl_ptr; - if (diff < 0) - diff += pcm->boundary; - assert(diff >= 0 && (snd_pcm_uframes_t)diff < pcm->boundary); - return diff; - } - return frames; + return pcm->fast_ops->mmap_commit(pcm->fast_op_arg, offset, frames); } #ifndef DOC_HIDDEN diff --git a/src/pcm/pcm_adpcm.c b/src/pcm/pcm_adpcm.c index 6babec1e..1dae3976 100644 --- a/src/pcm/pcm_adpcm.c +++ b/src/pcm/pcm_adpcm.c @@ -553,6 +553,7 @@ int snd_pcm_adpcm_open(snd_pcm_t **pcmp, const char *name, snd_pcm_format_t sfor return -ENOMEM; } adpcm->sformat = sformat; + snd_pcm_plugin_init(&adpcm->plug); adpcm->plug.read = snd_pcm_adpcm_read_areas; adpcm->plug.write = snd_pcm_adpcm_write_areas; adpcm->plug.init = snd_pcm_adpcm_init; diff --git a/src/pcm/pcm_alaw.c b/src/pcm/pcm_alaw.c index 03641784..0566395d 100644 --- a/src/pcm/pcm_alaw.c +++ b/src/pcm/pcm_alaw.c @@ -424,9 +424,12 @@ int snd_pcm_alaw_open(snd_pcm_t **pcmp, const char *name, snd_pcm_format_t sform if (!alaw) { return -ENOMEM; } + snd_pcm_plugin_init(&alaw->plug); alaw->sformat = sformat; alaw->plug.read = snd_pcm_alaw_read_areas; alaw->plug.write = snd_pcm_alaw_write_areas; + alaw->plug.undo_read = snd_pcm_plugin_undo_read_generic; + alaw->plug.undo_write = snd_pcm_plugin_undo_write_generic; alaw->plug.slave = slave; alaw->plug.close_slave = close_slave; diff --git a/src/pcm/pcm_copy.c b/src/pcm/pcm_copy.c index a0c68fff..37e6131d 100644 --- a/src/pcm/pcm_copy.c +++ b/src/pcm/pcm_copy.c @@ -188,8 +188,11 @@ int snd_pcm_copy_open(snd_pcm_t **pcmp, const char *name, snd_pcm_t *slave, int if (!copy) { return -ENOMEM; } + snd_pcm_plugin_init(©->plug); copy->plug.read = snd_pcm_copy_read_areas; copy->plug.write = snd_pcm_copy_write_areas; + copy->plug.undo_read = snd_pcm_plugin_undo_read_generic; + copy->plug.undo_write = snd_pcm_plugin_undo_write_generic; copy->plug.slave = slave; copy->plug.close_slave = close_slave; diff --git a/src/pcm/pcm_file.c b/src/pcm/pcm_file.c index aaebad90..6f12d59f 100644 --- a/src/pcm/pcm_file.c +++ b/src/pcm/pcm_file.c @@ -86,7 +86,8 @@ static void snd_pcm_file_write_bytes(snd_pcm_t *pcm, size_t bytes) static void snd_pcm_file_add_frames(snd_pcm_t *pcm, const snd_pcm_channel_area_t *areas, - snd_pcm_uframes_t offset, snd_pcm_uframes_t frames) + snd_pcm_uframes_t offset, + snd_pcm_uframes_t frames) { snd_pcm_file_t *file = pcm->private_data; while (frames > 0) { @@ -290,19 +291,22 @@ static snd_pcm_sframes_t snd_pcm_file_readn(snd_pcm_t *pcm, void **bufs, snd_pcm return n; } -static int snd_pcm_file_mmap_commit(snd_pcm_t *pcm, - snd_pcm_uframes_t offset, - snd_pcm_uframes_t size) +static snd_pcm_sframes_t snd_pcm_file_mmap_commit(snd_pcm_t *pcm, + snd_pcm_uframes_t offset, + snd_pcm_uframes_t size) { snd_pcm_file_t *file = pcm->private_data; snd_pcm_uframes_t ofs; snd_pcm_uframes_t siz = size; const snd_pcm_channel_area_t *areas; + snd_pcm_sframes_t result; + snd_pcm_mmap_begin(file->slave, &areas, &ofs, &siz); assert(ofs == offset && siz == size); - snd_pcm_mmap_commit(file->slave, ofs, siz); - snd_pcm_file_add_frames(pcm, areas, ofs, siz); - return 0; + result = snd_pcm_mmap_commit(file->slave, ofs, siz); + if (result > 0) + snd_pcm_file_add_frames(pcm, areas, ofs, result); + return result; } static snd_pcm_sframes_t snd_pcm_file_avail_update(snd_pcm_t *pcm) diff --git a/src/pcm/pcm_hooks.c b/src/pcm/pcm_hooks.c index a1d1dd2f..6c204e17 100644 --- a/src/pcm/pcm_hooks.c +++ b/src/pcm/pcm_hooks.c @@ -194,9 +194,9 @@ static snd_pcm_sframes_t snd_pcm_hooks_readn(snd_pcm_t *pcm, void **bufs, snd_pc return snd_pcm_readn(h->slave, bufs, size); } -static int snd_pcm_hooks_mmap_commit(snd_pcm_t *pcm, - snd_pcm_uframes_t offset, - snd_pcm_uframes_t size) +static snd_pcm_sframes_t snd_pcm_hooks_mmap_commit(snd_pcm_t *pcm, + snd_pcm_uframes_t offset, + snd_pcm_uframes_t size) { snd_pcm_hooks_t *h = pcm->private_data; return snd_pcm_mmap_commit(h->slave, offset, size); diff --git a/src/pcm/pcm_hw.c b/src/pcm/pcm_hw.c index 1da50440..db4a828e 100644 --- a/src/pcm/pcm_hw.c +++ b/src/pcm/pcm_hw.c @@ -74,6 +74,8 @@ typedef struct { #define UPDATE_SHADOW_PTR(hw) \ do { if (hw->shadow_appl_ptr && !hw->avail_update_flag) \ hw->appl_ptr = hw->mmap_control->appl_ptr; } while (0) +#define FAST_PCM_STATE(hw) \ + ((enum sndrv_pcm_state) (hw)->mmap_status->state) #endif /* DOC_HIDDEN */ @@ -593,29 +595,31 @@ static int snd_pcm_hw_close(snd_pcm_t *pcm) return 0; } -static int snd_pcm_hw_mmap_commit(snd_pcm_t *pcm, - snd_pcm_uframes_t offset ATTRIBUTE_UNUSED, - snd_pcm_uframes_t size) +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 size) { snd_pcm_hw_t *hw = pcm->private_data; + if (hw->mmap_shm) { if (pcm->stream == SND_PCM_STREAM_PLAYBACK) { - snd_pcm_sframes_t res; + snd_pcm_sframes_t result = 0, res; do { res = snd_pcm_write_mmap(pcm, size); if (res < 0) - return res; + return result > 0 ? result : res; size -= res; + result += res; } while (size > 0); - return 0; + return result; } else { snd_pcm_hw_t *hw = pcm->private_data; assert(hw->shadow_appl_ptr); } } snd_pcm_mmap_appl_forward(pcm, size); - return 0; + return size; } static snd_pcm_sframes_t snd_pcm_hw_avail_update(snd_pcm_t *pcm) @@ -638,14 +642,21 @@ static snd_pcm_sframes_t snd_pcm_hw_avail_update(snd_pcm_t *pcm) return err; } } - if (avail >= pcm->stop_threshold) { - /* SNDRV_PCM_IOCTL_XRUN ioctl has been implemented since PCM kernel API 2.0.1 */ - if (SNDRV_PROTOCOL_VERSION(2, 0, 1) <= hw->version) { - if (ioctl(hw->fd, SND_PCM_IOCTL_XRUN) < 0) - return -errno; + switch (FAST_PCM_STATE(hw)) { + case SNDRV_PCM_STATE_RUNNING: + if (avail >= pcm->stop_threshold) { + /* SNDRV_PCM_IOCTL_XRUN ioctl has been implemented since PCM kernel API 2.0.1 */ + if (SNDRV_PROTOCOL_VERSION(2, 0, 1) <= hw->version) { + if (ioctl(hw->fd, SND_PCM_IOCTL_XRUN) < 0) + return -errno; + } + /* everything is ok, state == SND_PCM_STATE_XRUN at the moment */ + return -EPIPE; } - /* everything is ok, state == SND_PCM_STATE_XRUN at the moment */ + case SNDRV_PCM_STATE_XRUN: return -EPIPE; + default: + break; } return avail; } diff --git a/src/pcm/pcm_ladspa.c b/src/pcm/pcm_ladspa.c index 6e15ea3b..d932f0a2 100644 --- a/src/pcm/pcm_ladspa.c +++ b/src/pcm/pcm_ladspa.c @@ -1135,9 +1135,12 @@ int snd_pcm_ladspa_open(snd_pcm_t **pcmp, const char *name, ladspa = calloc(1, sizeof(snd_pcm_ladspa_t)); if (!ladspa) return -ENOMEM; + snd_pcm_plugin_init(&ladspa->plug); ladspa->plug.init = snd_pcm_ladspa_init; ladspa->plug.read = snd_pcm_ladspa_read_areas; ladspa->plug.write = snd_pcm_ladspa_write_areas; + ladspa->plug.undo_read = snd_pcm_plugin_undo_read_generic; + ladspa->plug.undo_write = snd_pcm_plugin_undo_write_generic; ladspa->plug.slave = slave; ladspa->plug.close_slave = close_slave; diff --git a/src/pcm/pcm_lfloat.c b/src/pcm/pcm_lfloat.c index 5b886a56..ba1047cd 100644 --- a/src/pcm/pcm_lfloat.c +++ b/src/pcm/pcm_lfloat.c @@ -389,9 +389,12 @@ int snd_pcm_lfloat_open(snd_pcm_t **pcmp, const char *name, snd_pcm_format_t sfo if (!lfloat) { return -ENOMEM; } + snd_pcm_plugin_init(&lfloat->plug); lfloat->sformat = sformat; lfloat->plug.read = snd_pcm_lfloat_read_areas; lfloat->plug.write = snd_pcm_lfloat_write_areas; + lfloat->plug.undo_read = snd_pcm_plugin_undo_read_generic; + lfloat->plug.undo_write = snd_pcm_plugin_undo_write_generic; lfloat->plug.slave = slave; lfloat->plug.close_slave = close_slave; diff --git a/src/pcm/pcm_linear.c b/src/pcm/pcm_linear.c index 3ce30c2f..4489cdb2 100644 --- a/src/pcm/pcm_linear.c +++ b/src/pcm/pcm_linear.c @@ -328,9 +328,12 @@ int snd_pcm_linear_open(snd_pcm_t **pcmp, const char *name, snd_pcm_format_t sfo if (!linear) { return -ENOMEM; } + snd_pcm_plugin_init(&linear->plug); linear->sformat = sformat; linear->plug.read = snd_pcm_linear_read_areas; linear->plug.write = snd_pcm_linear_write_areas; + linear->plug.undo_read = snd_pcm_plugin_undo_read_generic; + linear->plug.undo_write = snd_pcm_plugin_undo_write_generic; linear->plug.slave = slave; linear->plug.close_slave = close_slave; diff --git a/src/pcm/pcm_local.h b/src/pcm/pcm_local.h index 96de21b8..7dddd4ed 100644 --- a/src/pcm/pcm_local.h +++ b/src/pcm/pcm_local.h @@ -141,7 +141,7 @@ typedef struct { snd_pcm_sframes_t (*readi)(snd_pcm_t *pcm, void *buffer, snd_pcm_uframes_t size); snd_pcm_sframes_t (*readn)(snd_pcm_t *pcm, void **bufs, snd_pcm_uframes_t size); snd_pcm_sframes_t (*avail_update)(snd_pcm_t *pcm); - int (*mmap_commit)(snd_pcm_t *pcm, snd_pcm_uframes_t offset, snd_pcm_uframes_t size); + snd_pcm_sframes_t (*mmap_commit)(snd_pcm_t *pcm, snd_pcm_uframes_t offset, snd_pcm_uframes_t size); } snd_pcm_fast_ops_t; struct _snd_pcm { diff --git a/src/pcm/pcm_meter.c b/src/pcm/pcm_meter.c index 63b7d0eb..2775bc52 100644 --- a/src/pcm/pcm_meter.c +++ b/src/pcm/pcm_meter.c @@ -396,9 +396,9 @@ static int snd_pcm_meter_resume(snd_pcm_t *pcm) return snd_pcm_resume(meter->slave); } -static int snd_pcm_meter_mmap_commit(snd_pcm_t *pcm, - snd_pcm_uframes_t offset, - snd_pcm_uframes_t size) +static snd_pcm_sframes_t snd_pcm_meter_mmap_commit(snd_pcm_t *pcm, + snd_pcm_uframes_t offset, + snd_pcm_uframes_t size) { snd_pcm_meter_t *meter = pcm->private_data; snd_pcm_uframes_t old_rptr = *pcm->appl_ptr; @@ -406,10 +406,10 @@ static int snd_pcm_meter_mmap_commit(snd_pcm_t *pcm, if (result <= 0) return result; if (pcm->stream == SND_PCM_STREAM_PLAYBACK) { - snd_pcm_meter_add_frames(pcm, snd_pcm_mmap_areas(pcm), old_rptr, size); + snd_pcm_meter_add_frames(pcm, snd_pcm_mmap_areas(pcm), old_rptr, result); meter->rptr = *pcm->appl_ptr; } - return 0; + return result; } static snd_pcm_sframes_t snd_pcm_meter_avail_update(snd_pcm_t *pcm) diff --git a/src/pcm/pcm_mmap.c b/src/pcm/pcm_mmap.c index 5bb59e5f..89361644 100644 --- a/src/pcm/pcm_mmap.c +++ b/src/pcm/pcm_mmap.c @@ -86,24 +86,25 @@ static snd_pcm_sframes_t snd_pcm_mmap_write_areas(snd_pcm_t *pcm, snd_pcm_uframes_t size) { snd_pcm_uframes_t xfer = 0; - int err; assert(snd_pcm_mmap_playback_avail(pcm) >= size); while (size > 0) { const snd_pcm_channel_area_t *pcm_areas; snd_pcm_uframes_t pcm_offset; snd_pcm_uframes_t frames = size; + snd_pcm_sframes_t result; + snd_pcm_mmap_begin(pcm, &pcm_areas, &pcm_offset, &frames); snd_pcm_areas_copy(pcm_areas, pcm_offset, areas, offset, pcm->channels, frames, pcm->format); - err = snd_pcm_mmap_commit(pcm, pcm_offset, frames); - if (err < 0) - return xfer > 0 ? xfer : err; - offset += frames; - xfer += frames; - size -= frames; + result = snd_pcm_mmap_commit(pcm, pcm_offset, frames); + if (result < 0) + return xfer > 0 ? xfer : result; + offset += result; + xfer += result; + size -= result; } return xfer; } @@ -114,24 +115,25 @@ static snd_pcm_sframes_t snd_pcm_mmap_read_areas(snd_pcm_t *pcm, snd_pcm_uframes_t size) { snd_pcm_uframes_t xfer = 0; - int err; assert(snd_pcm_mmap_capture_avail(pcm) >= size); while (size > 0) { const snd_pcm_channel_area_t *pcm_areas; snd_pcm_uframes_t pcm_offset; snd_pcm_uframes_t frames = size; + snd_pcm_sframes_t result; + snd_pcm_mmap_begin(pcm, &pcm_areas, &pcm_offset, &frames); snd_pcm_areas_copy(areas, offset, pcm_areas, pcm_offset, pcm->channels, frames, pcm->format); - err = snd_pcm_mmap_commit(pcm, pcm_offset, frames); - if (err < 0) - return xfer > 0 ? xfer : err; - offset += frames; - xfer += frames; - size -= frames; + result = snd_pcm_mmap_commit(pcm, pcm_offset, frames); + if (result < 0) + return xfer > 0 ? xfer : result; + offset += result; + xfer += result; + size -= result; } return xfer; } diff --git a/src/pcm/pcm_mulaw.c b/src/pcm/pcm_mulaw.c index 1039af2e..d6b53047 100644 --- a/src/pcm/pcm_mulaw.c +++ b/src/pcm/pcm_mulaw.c @@ -439,9 +439,12 @@ int snd_pcm_mulaw_open(snd_pcm_t **pcmp, const char *name, snd_pcm_format_t sfor if (!mulaw) { return -ENOMEM; } + snd_pcm_plugin_init(&mulaw->plug); mulaw->sformat = sformat; mulaw->plug.read = snd_pcm_mulaw_read_areas; mulaw->plug.write = snd_pcm_mulaw_write_areas; + mulaw->plug.undo_read = snd_pcm_plugin_undo_read_generic; + mulaw->plug.undo_write = snd_pcm_plugin_undo_write_generic; mulaw->plug.slave = slave; mulaw->plug.close_slave = close_slave; diff --git a/src/pcm/pcm_multi.c b/src/pcm/pcm_multi.c index 3a486d76..64459758 100644 --- a/src/pcm/pcm_multi.c +++ b/src/pcm/pcm_multi.c @@ -496,8 +496,14 @@ static snd_pcm_sframes_t snd_pcm_multi_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t 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; - if (f > 0) - snd_pcm_mmap_commit(slave_i, snd_pcm_mmap_offset(slave_i), f); + snd_pcm_sframes_t result; + if (f > 0) { + result = snd_pcm_mmap_commit(slave_i, snd_pcm_mmap_offset(slave_i), f); + if (result < 0) + return result; + if ((snd_pcm_uframes_t)result != f) + return -EIO; + } } return frames; } @@ -517,20 +523,22 @@ static int snd_pcm_multi_resume(snd_pcm_t *pcm) return err; } -static int snd_pcm_multi_mmap_commit(snd_pcm_t *pcm, - snd_pcm_uframes_t offset, - snd_pcm_uframes_t size) +static snd_pcm_sframes_t snd_pcm_multi_mmap_commit(snd_pcm_t *pcm, + snd_pcm_uframes_t offset, + snd_pcm_uframes_t size) { snd_pcm_multi_t *multi = pcm->private_data; snd_pcm_t *slave; unsigned int i; - int err; + snd_pcm_sframes_t result; for (i = 0; i < multi->slaves_count; ++i) { slave = multi->slaves[i].pcm; - err = snd_pcm_mmap_commit(slave, offset, size); - if (err < 0) - return err; + result = snd_pcm_mmap_commit(slave, offset, size); + if (result < 0) + return result; + if ((snd_pcm_uframes_t)result != size) + return -EIO; } return 0; } diff --git a/src/pcm/pcm_null.c b/src/pcm/pcm_null.c index 8c96213c..ce981dd5 100644 --- a/src/pcm/pcm_null.c +++ b/src/pcm/pcm_null.c @@ -230,17 +230,16 @@ static snd_pcm_sframes_t snd_pcm_null_readn(snd_pcm_t *pcm, void **bufs ATTRIBUT return snd_pcm_read_areas(pcm, NULL, 0, size, snd_pcm_null_xfer_areas); } -static int snd_pcm_null_mmap_commit(snd_pcm_t *pcm, - snd_pcm_uframes_t offset ATTRIBUTE_UNUSED, - snd_pcm_uframes_t size) +static snd_pcm_sframes_t snd_pcm_null_mmap_commit(snd_pcm_t *pcm, + snd_pcm_uframes_t offset ATTRIBUTE_UNUSED, + snd_pcm_uframes_t size) { snd_pcm_sframes_t res; res = snd_pcm_null_fwd(pcm, size); if (res < 0) return res; - assert((snd_pcm_uframes_t)res == size); - return 0; + return res; } static snd_pcm_sframes_t snd_pcm_null_avail_update(snd_pcm_t *pcm) diff --git a/src/pcm/pcm_plugin.c b/src/pcm/pcm_plugin.c index 4ef3789c..bbc065c7 100644 --- a/src/pcm/pcm_plugin.c +++ b/src/pcm/pcm_plugin.c @@ -89,6 +89,53 @@ pcm.rate44100Hz { #ifndef DOC_HIDDEN +static snd_pcm_sframes_t +snd_pcm_plugin_undo_read(snd_pcm_t *pcm ATTRIBUTE_UNUSED, + const snd_pcm_channel_area_t *res_areas ATTRIBUTE_UNUSED, + snd_pcm_uframes_t res_offset ATTRIBUTE_UNUSED, + snd_pcm_uframes_t res_size ATTRIBUTE_UNUSED, + snd_pcm_uframes_t slave_undo_size ATTRIBUTE_UNUSED) +{ + return -EIO; +} + +static snd_pcm_sframes_t +snd_pcm_plugin_undo_write(snd_pcm_t *pcm ATTRIBUTE_UNUSED, + const snd_pcm_channel_area_t *res_areas ATTRIBUTE_UNUSED, + snd_pcm_uframes_t res_offset ATTRIBUTE_UNUSED, + snd_pcm_uframes_t res_size ATTRIBUTE_UNUSED, + snd_pcm_uframes_t slave_undo_size ATTRIBUTE_UNUSED) +{ + return -EIO; +} + +snd_pcm_sframes_t +snd_pcm_plugin_undo_read_generic(snd_pcm_t *pcm ATTRIBUTE_UNUSED, + const snd_pcm_channel_area_t *res_areas ATTRIBUTE_UNUSED, + snd_pcm_uframes_t res_offset ATTRIBUTE_UNUSED, + snd_pcm_uframes_t res_size ATTRIBUTE_UNUSED, + snd_pcm_uframes_t slave_undo_size) +{ + return slave_undo_size; +} + +snd_pcm_sframes_t +snd_pcm_plugin_undo_write_generic(snd_pcm_t *pcm ATTRIBUTE_UNUSED, + const snd_pcm_channel_area_t *res_areas ATTRIBUTE_UNUSED, + snd_pcm_uframes_t res_offset ATTRIBUTE_UNUSED, + snd_pcm_uframes_t res_size ATTRIBUTE_UNUSED, + snd_pcm_uframes_t slave_undo_size) +{ + return slave_undo_size; +} + +void snd_pcm_plugin_init(snd_pcm_plugin_t *plugin) +{ + memset(plugin, 0, sizeof(snd_pcm_plugin_t)); + plugin->undo_read = snd_pcm_plugin_undo_read; + plugin->undo_write = snd_pcm_plugin_undo_write; +} + int snd_pcm_plugin_close(snd_pcm_t *pcm) { snd_pcm_plugin_t *plugin = pcm->private_data; @@ -270,7 +317,7 @@ static snd_pcm_sframes_t snd_pcm_plugin_write_areas(snd_pcm_t *pcm, snd_pcm_plugin_t *plugin = pcm->private_data; snd_pcm_t *slave = plugin->slave; snd_pcm_uframes_t xfer = 0; - snd_pcm_sframes_t err; + snd_pcm_sframes_t result; while (size > 0) { snd_pcm_uframes_t frames = size; @@ -283,13 +330,13 @@ static snd_pcm_sframes_t snd_pcm_plugin_write_areas(snd_pcm_t *pcm, assert(slave_frames <= snd_pcm_mmap_playback_avail(slave)); snd_atomic_write_begin(&plugin->watom); snd_pcm_mmap_appl_forward(pcm, frames); - err = snd_pcm_mmap_commit(slave, slave_offset, slave_frames); + result = snd_pcm_mmap_commit(slave, slave_offset, slave_frames); snd_atomic_write_end(&plugin->watom); - if (err < 0) - return xfer > 0 ? xfer : err; - offset += frames; - xfer += frames; - size -= frames; + if (result < 0) + return xfer > 0 ? xfer : result; + offset += result; + xfer += result; + size -= result; } return xfer; } @@ -302,7 +349,7 @@ static snd_pcm_sframes_t snd_pcm_plugin_read_areas(snd_pcm_t *pcm, snd_pcm_plugin_t *plugin = pcm->private_data; snd_pcm_t *slave = plugin->slave; snd_pcm_uframes_t xfer = 0; - snd_pcm_sframes_t err; + snd_pcm_sframes_t result; while (size > 0) { snd_pcm_uframes_t frames = size; @@ -315,13 +362,13 @@ static snd_pcm_sframes_t snd_pcm_plugin_read_areas(snd_pcm_t *pcm, assert(slave_frames <= snd_pcm_mmap_capture_avail(slave)); snd_atomic_write_begin(&plugin->watom); snd_pcm_mmap_appl_forward(pcm, frames); - err = snd_pcm_mmap_commit(slave, slave_offset, slave_frames); + result = snd_pcm_mmap_commit(slave, slave_offset, slave_frames); snd_atomic_write_end(&plugin->watom); - if (err < 0) - return xfer > 0 ? xfer : err; - offset += frames; - xfer += frames; - size -= frames; + if (result < 0) + return xfer > 0 ? xfer : result; + offset += result; + xfer += result; + size -= result; } return xfer; } @@ -359,15 +406,16 @@ snd_pcm_sframes_t snd_pcm_plugin_readn(snd_pcm_t *pcm, void **bufs, snd_pcm_ufra snd_pcm_plugin_read_areas); } -int snd_pcm_plugin_mmap_commit(snd_pcm_t *pcm, - snd_pcm_uframes_t offset ATTRIBUTE_UNUSED, - snd_pcm_uframes_t size) +snd_pcm_sframes_t snd_pcm_plugin_mmap_commit(snd_pcm_t *pcm, + snd_pcm_uframes_t offset ATTRIBUTE_UNUSED, + snd_pcm_uframes_t size) { snd_pcm_plugin_t *plugin = pcm->private_data; snd_pcm_t *slave = plugin->slave; const snd_pcm_channel_area_t *areas; snd_pcm_uframes_t appl_offset; snd_pcm_sframes_t slave_size; + snd_pcm_sframes_t xfer; if (pcm->stream == SND_PCM_STREAM_CAPTURE) { snd_atomic_write_begin(&plugin->watom); @@ -378,35 +426,49 @@ int snd_pcm_plugin_mmap_commit(snd_pcm_t *pcm, slave_size = snd_pcm_avail_update(slave); if (slave_size < 0) return slave_size; - if ((snd_pcm_uframes_t)slave_size < size) - return -EIO; areas = snd_pcm_mmap_areas(pcm); appl_offset = snd_pcm_mmap_offset(pcm); + xfer = 0; while (size > 0 && slave_size > 0) { snd_pcm_uframes_t frames = size; snd_pcm_uframes_t cont = pcm->buffer_size - appl_offset; const snd_pcm_channel_area_t *slave_areas; snd_pcm_uframes_t slave_offset; snd_pcm_uframes_t slave_frames = ULONG_MAX; + snd_pcm_sframes_t result; + int err; - snd_pcm_mmap_begin(slave, &slave_areas, &slave_offset, &slave_frames); + err = snd_pcm_mmap_begin(slave, &slave_areas, &slave_offset, &slave_frames); + if (err < 0) + return xfer > 0 ? xfer : err; if (frames > cont) frames = cont; frames = plugin->write(pcm, areas, appl_offset, frames, slave_areas, slave_offset, &slave_frames); snd_atomic_write_begin(&plugin->watom); snd_pcm_mmap_appl_forward(pcm, frames); - snd_pcm_mmap_commit(slave, slave_offset, slave_frames); + result = snd_pcm_mmap_commit(slave, slave_offset, slave_frames); snd_atomic_write_end(&plugin->watom); + if (result > 0 && (snd_pcm_uframes_t)result != slave_frames) { + snd_pcm_sframes_t res; + + res = plugin->undo_write(pcm, slave_areas, slave_offset + result, slave_frames, slave_frames - result); + if (res < 0) + return xfer > 0 ? xfer : res; + frames -= res; + } + if (result <= 0) + return xfer > 0 ? xfer : result; if (frames == cont) appl_offset = 0; else - appl_offset += frames; + appl_offset += result; size -= frames; - slave_size -= slave_frames; + slave_size -= frames; + xfer += frames; } assert(size == 0); - return 0; + return xfer; } snd_pcm_sframes_t snd_pcm_plugin_avail_update(snd_pcm_t *pcm) @@ -434,32 +496,48 @@ snd_pcm_sframes_t snd_pcm_plugin_avail_update(snd_pcm_t *pcm) const snd_pcm_channel_area_t *areas; snd_pcm_uframes_t xfer, hw_offset, size; - xfer = snd_pcm_mmap_capture_avail(pcm); - size = pcm->buffer_size - xfer; + size = snd_pcm_mmap_capture_avail(pcm); + size = pcm->buffer_size - size; areas = snd_pcm_mmap_areas(pcm); hw_offset = snd_pcm_mmap_hw_offset(pcm); + xfer = 0; while (size > 0 && slave_size > 0) { - snd_pcm_uframes_t frames = size; + snd_pcm_uframes_t frames = size; snd_pcm_uframes_t cont = pcm->buffer_size - hw_offset; const snd_pcm_channel_area_t *slave_areas; snd_pcm_uframes_t slave_offset; snd_pcm_uframes_t slave_frames = ULONG_MAX; - snd_pcm_mmap_begin(slave, &slave_areas, &slave_offset, &slave_frames); + snd_pcm_sframes_t result; + int err; + + err = snd_pcm_mmap_begin(slave, &slave_areas, &slave_offset, &slave_frames); + if (err < 0) + return xfer > 0 ? xfer : err; if (frames > cont) frames = cont; frames = plugin->read(pcm, areas, hw_offset, frames, slave_areas, slave_offset, &slave_frames); snd_atomic_write_begin(&plugin->watom); snd_pcm_mmap_hw_forward(pcm, frames); - snd_pcm_mmap_commit(slave, slave_offset, slave_frames); + result = snd_pcm_mmap_commit(slave, slave_offset, slave_frames); snd_atomic_write_end(&plugin->watom); - xfer += frames; + if (result > 0 && (snd_pcm_uframes_t)result != slave_frames) { + snd_pcm_sframes_t res; + + res = plugin->undo_read(slave, areas, hw_offset, frames, slave_frames - result); + if (res < 0) + return xfer > 0 ? xfer : res; + frames -= res; + } + if (result <= 0) + return xfer > 0 ? xfer : result; if (frames == cont) hw_offset = 0; else hw_offset += frames; size -= frames; slave_size -= slave_frames; + xfer += frames; } return xfer; } diff --git a/src/pcm/pcm_plugin.h b/src/pcm/pcm_plugin.h index a3297244..cb48ea83 100644 --- a/src/pcm/pcm_plugin.h +++ b/src/pcm/pcm_plugin.h @@ -30,11 +30,20 @@ typedef snd_pcm_uframes_t (*snd_pcm_slave_xfer_areas_func_t) snd_pcm_uframes_t slave_offset, snd_pcm_uframes_t *slave_sizep); +typedef snd_pcm_sframes_t (*snd_pcm_slave_xfer_areas_undo_func_t) + (snd_pcm_t *pcm, + const snd_pcm_channel_area_t *res_areas, /* result areas */ + snd_pcm_uframes_t res_offset, /* offset of result areas */ + snd_pcm_uframes_t res_size, /* size of result areas */ + snd_pcm_uframes_t slave_undo_size); + typedef struct { snd_pcm_t *slave; int close_slave; snd_pcm_slave_xfer_areas_func_t read; snd_pcm_slave_xfer_areas_func_t write; + snd_pcm_slave_xfer_areas_undo_func_t undo_read; + snd_pcm_slave_xfer_areas_undo_func_t undo_write; snd_pcm_sframes_t (*client_frames)(snd_pcm_t *pcm, snd_pcm_sframes_t frames); snd_pcm_sframes_t (*slave_frames)(snd_pcm_t *pcm, snd_pcm_sframes_t frames); int (*init)(snd_pcm_t *pcm); @@ -43,6 +52,7 @@ typedef struct { snd_atomic_write_t watom; } snd_pcm_plugin_t; +void snd_pcm_plugin_init(snd_pcm_plugin_t *plugin); int snd_pcm_plugin_close(snd_pcm_t *pcm); int snd_pcm_plugin_card(snd_pcm_t *pcm); int snd_pcm_plugin_nonblock(snd_pcm_t *pcm, int nonblock); @@ -65,7 +75,7 @@ snd_pcm_sframes_t snd_pcm_plugin_writei(snd_pcm_t *pcm, const void *buffer, snd_ snd_pcm_sframes_t snd_pcm_plugin_writen(snd_pcm_t *pcm, void **bufs, snd_pcm_uframes_t size); snd_pcm_sframes_t snd_pcm_plugin_readi(snd_pcm_t *pcm, void *buffer, snd_pcm_uframes_t size); snd_pcm_sframes_t snd_pcm_plugin_readn(snd_pcm_t *pcm, void **bufs, snd_pcm_uframes_t size); -int snd_pcm_plugin_mmap_commit(snd_pcm_t *pcm, snd_pcm_uframes_t offset, snd_pcm_uframes_t size); +snd_pcm_sframes_t snd_pcm_plugin_mmap_commit(snd_pcm_t *pcm, snd_pcm_uframes_t offset, snd_pcm_uframes_t size); snd_pcm_sframes_t snd_pcm_plugin_avail_update(snd_pcm_t *pcm); int snd_pcm_plugin_mmap_status(snd_pcm_t *pcm); int snd_pcm_plugin_mmap_control(snd_pcm_t *pcm); @@ -79,6 +89,20 @@ int snd_pcm_plugin_hw_refine_slave(snd_pcm_t *pcm, snd_pcm_hw_params_t *params); extern snd_pcm_fast_ops_t snd_pcm_plugin_fast_ops; +snd_pcm_sframes_t snd_pcm_plugin_undo_read_generic + (snd_pcm_t *pcm, + const snd_pcm_channel_area_t *res_areas, /* result areas */ + snd_pcm_uframes_t res_offset, /* offset of result areas */ + snd_pcm_uframes_t res_size, /* size of result areas */ + snd_pcm_uframes_t slave_undo_size); + +snd_pcm_sframes_t snd_pcm_plugin_undo_write_generic + (snd_pcm_t *pcm, + const snd_pcm_channel_area_t *res_areas, /* result areas */ + snd_pcm_uframes_t res_offset, /* offset of result areas */ + snd_pcm_uframes_t res_size, /* size of result areas */ + snd_pcm_uframes_t slave_undo_size); + int snd_pcm_linear_get_index(snd_pcm_format_t src_format, snd_pcm_format_t dst_format); int snd_pcm_linear_put_index(snd_pcm_format_t src_format, snd_pcm_format_t dst_format); int snd_pcm_linear_convert_index(snd_pcm_format_t src_format, snd_pcm_format_t dst_format); diff --git a/src/pcm/pcm_rate.c b/src/pcm/pcm_rate.c index 55abeff2..48fe064b 100644 --- a/src/pcm/pcm_rate.c +++ b/src/pcm/pcm_rate.c @@ -534,6 +534,7 @@ int snd_pcm_rate_open(snd_pcm_t **pcmp, const char *name, snd_pcm_format_t sform if (!rate) { return -ENOMEM; } + snd_pcm_plugin_init(&rate->plug); rate->srate = srate; rate->sformat = sformat; rate->plug.read = snd_pcm_rate_read_areas; diff --git a/src/pcm/pcm_route.c b/src/pcm/pcm_route.c index 40922bef..2b328a42 100644 --- a/src/pcm/pcm_route.c +++ b/src/pcm/pcm_route.c @@ -781,10 +781,13 @@ int snd_pcm_route_open(snd_pcm_t **pcmp, const char *name, if (!route) { return -ENOMEM; } + snd_pcm_plugin_init(&route->plug); route->sformat = sformat; route->schannels = schannels; route->plug.read = snd_pcm_route_read_areas; route->plug.write = snd_pcm_route_write_areas; + route->plug.undo_read = snd_pcm_plugin_undo_read_generic; + route->plug.undo_write = snd_pcm_plugin_undo_write_generic; route->plug.slave = slave; route->plug.close_slave = close_slave; diff --git a/src/pcm/pcm_share.c b/src/pcm/pcm_share.c index 99617e48..40f4a8d3 100644 --- a/src/pcm/pcm_share.c +++ b/src/pcm/pcm_share.c @@ -770,9 +770,9 @@ static snd_pcm_sframes_t snd_pcm_share_avail_update(snd_pcm_t *pcm) } /* Call it with mutex held */ -static int _snd_pcm_share_mmap_commit(snd_pcm_t *pcm, - snd_pcm_uframes_t offset ATTRIBUTE_UNUSED, - snd_pcm_uframes_t size) +static snd_pcm_sframes_t _snd_pcm_share_mmap_commit(snd_pcm_t *pcm, + snd_pcm_uframes_t offset ATTRIBUTE_UNUSED, + snd_pcm_uframes_t size) { snd_pcm_share_t *share = pcm->private_data; snd_pcm_share_slave_t *slave = share->slave; @@ -803,12 +803,12 @@ static int _snd_pcm_share_mmap_commit(snd_pcm_t *pcm, } _snd_pcm_share_update(pcm); } - return 0; + return size; } -static int snd_pcm_share_mmap_commit(snd_pcm_t *pcm, - snd_pcm_uframes_t offset, - snd_pcm_uframes_t size) +static snd_pcm_sframes_t snd_pcm_share_mmap_commit(snd_pcm_t *pcm, + snd_pcm_uframes_t offset, + snd_pcm_uframes_t size) { snd_pcm_share_t *share = pcm->private_data; snd_pcm_share_slave_t *slave = share->slave; @@ -909,8 +909,15 @@ static int snd_pcm_share_start(snd_pcm_t *pcm) xfer += frames; } snd_pcm_mmap_appl_forward(pcm, hw_avail); - if (slave->running_count == 0) - snd_pcm_mmap_commit(spcm, snd_pcm_mmap_offset(spcm), hw_avail); + if (slave->running_count == 0) { + snd_pcm_sframes_t res; + res = snd_pcm_mmap_commit(spcm, snd_pcm_mmap_offset(spcm), hw_avail); + if (res < 0) { + err = res; + goto _end; + } + assert((snd_pcm_uframes_t)res == hw_avail); + } } if (slave->running_count == 0) { err = snd_pcm_start(spcm); diff --git a/src/pcm/pcm_shm.c b/src/pcm/pcm_shm.c index c2a8a923..e5ab2707 100644 --- a/src/pcm/pcm_shm.c +++ b/src/pcm/pcm_shm.c @@ -93,7 +93,7 @@ int receive_fd(int sock, void *data, size_t len, int *fd) } #endif -static int snd_pcm_shm_action(snd_pcm_t *pcm) +static long snd_pcm_shm_action(snd_pcm_t *pcm) { snd_pcm_shm_t *shm = pcm->private_data; int err; @@ -112,7 +112,7 @@ static int snd_pcm_shm_action(snd_pcm_t *pcm) return ctrl->result; } -static int snd_pcm_shm_action_fd(snd_pcm_t *pcm, int *fd) +static long snd_pcm_shm_action_fd(snd_pcm_t *pcm, int *fd) { snd_pcm_shm_t *shm = pcm->private_data; int err; @@ -457,9 +457,9 @@ static int snd_pcm_shm_resume(snd_pcm_t *pcm) return snd_pcm_shm_action(pcm); } -static int snd_pcm_shm_mmap_commit(snd_pcm_t *pcm, - snd_pcm_uframes_t offset ATTRIBUTE_UNUSED, - snd_pcm_uframes_t size) +static snd_pcm_sframes_t snd_pcm_shm_mmap_commit(snd_pcm_t *pcm, + snd_pcm_uframes_t offset ATTRIBUTE_UNUSED, + snd_pcm_uframes_t size) { snd_pcm_shm_t *shm = pcm->private_data; volatile snd_pcm_shm_ctrl_t *ctrl = shm->ctrl; -- 2.47.1