]> git.alsa-project.org Git - alsa-lib.git/commitdiff
Cleaned the mmap_commit implementations in plugins.
authorJaroslav Kysela <perex@perex.cz>
Thu, 21 Feb 2002 15:01:34 +0000 (15:01 +0000)
committerJaroslav Kysela <perex@perex.cz>
Thu, 21 Feb 2002 15:01:34 +0000 (15:01 +0000)
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.

22 files changed:
src/pcm/pcm.c
src/pcm/pcm_adpcm.c
src/pcm/pcm_alaw.c
src/pcm/pcm_copy.c
src/pcm/pcm_file.c
src/pcm/pcm_hooks.c
src/pcm/pcm_hw.c
src/pcm/pcm_ladspa.c
src/pcm/pcm_lfloat.c
src/pcm/pcm_linear.c
src/pcm/pcm_local.h
src/pcm/pcm_meter.c
src/pcm/pcm_mmap.c
src/pcm/pcm_mulaw.c
src/pcm/pcm_multi.c
src/pcm/pcm_null.c
src/pcm/pcm_plugin.c
src/pcm/pcm_plugin.h
src/pcm/pcm_rate.c
src/pcm/pcm_route.c
src/pcm/pcm_share.c
src/pcm/pcm_shm.c

index e7d85a26147218b586f61f7b543f09332961f982..0aa1740ac8adf2b75bafcca9d334d765bd0af7ff 100644 (file)
@@ -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
index 6babec1ebbc84e8a1130a9e418a8fee96a3e4838..1dae39763646cc1576925fb760229db97f353f37 100644 (file)
@@ -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;
index 03641784e950277f019ff293a78213e4ef62c7cb..0566395daba7a2e5d4c4117ee4d6f19d8c5b9b55 100644 (file)
@@ -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;
 
index a0c68fff90ba89beea3091a72d9390e6bcd6ce6a..37e6131dd6d16a0ca568f545fbb5b4f42b4dae92 100644 (file)
@@ -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(&copy->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;
 
index aaebad9068f73db9899e4f1ae4341cad2593a1eb..6f12d59f783ce36892bd65a288c79c6795a0b373 100644 (file)
@@ -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)
index a1d1dd2f4f0c3bdf98d9fbf0240a9594eefabfc2..6c204e1781a1c8a3ef359c07c8a40d689970394b 100644 (file)
@@ -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);
index 1da5044029fcdfb52bb69e89888cc2c5555aa7c8..db4a828ec8af67588074109c40db508e8fec128b 100644 (file)
@@ -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;
 }
index 6e15ea3b27661190816759c139f05732c57fd90d..d932f0a2872ac447f3d32729bea31d723d0be832 100644 (file)
@@ -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;
 
index 5b886a56f7c1b4e133818608c70b87de78d53708..ba1047cd7657010dd2135ebeda79632bebb2f0c2 100644 (file)
@@ -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;
 
index 3ce30c2f7ec35b4f3553bb57c45e719f2ffb3311..4489cdb230e6c7e778e3b73c724a73b7237b0c84 100644 (file)
@@ -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;
 
index 96de21b80a0f2f5d59befdbc6928b31f232d6d41..7dddd4ed05aca6979cf906ed3d9382820596e809 100644 (file)
@@ -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 {
index 63b7d0ebca811a29f74b139875a40e0e5cda1e7e..2775bc520a45b199cd3f407fcc419d07f26b5950 100644 (file)
@@ -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)
index 5bb59e5f496689126fb9c1a1b6964fa3501e4118..893616448c31eb49405fe9ba83dd6949399dc253 100644 (file)
@@ -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;
 }
index 1039af2ea0ad13d4bfe8e63fb451541ef3ab96a5..d6b53047ad5577e283ad3417d8d1fbb7c48df8fb 100644 (file)
@@ -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;
 
index 3a486d76019b606b4075aad3101a2c62f31aadd8..644597586f0a0c71703ccba5af34bba924a893cd 100644 (file)
@@ -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;
 }
index 8c96213cf0e852b78629fcbebc53702aa523ab04..ce981dd57e32686c02347a4b2eba0a8eff975a39 100644 (file)
@@ -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)
index 4ef3789ca1589077764043b0b7aeccfc5fbf1d1b..bbc065c705b4ef74a9fd521ba2a1f3af125eb5b7 100644 (file)
@@ -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;
        }
index a3297244edde5446c8b3a031c0e314c198dbd355..cb48ea8339aa6032241b4750502c7e4d80330d72 100644 (file)
@@ -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);
index 55abeff25a5a289f32e3e7b95a958e47bd88cc1d..48fe064b0a0e901b28ee78f6ea1b1565df409d39 100644 (file)
@@ -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;
index 40922befdeb90578ccf7fbe503e2974e92ed7ff4..2b328a4226161a05886de8ed8bda0050ec188e70 100644 (file)
@@ -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;
 
index 99617e48964bd05357657e8bc72c6a1cf2b95c71..40f4a8d38f89fcadd961d281a2e452316547a4eb 100644 (file)
@@ -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);
index c2a8a923f142f245e369524158ee5170892ee472..e5ab2707ae8a0efab4d8adadb9a882ee2601114f 100644 (file)
@@ -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;