]> git.alsa-project.org Git - alsa-lib.git/commitdiff
- splitted mmap in logical steps
authorAbramo Bagnara <abramo@alsa-project.org>
Tue, 16 May 2000 15:20:34 +0000 (15:20 +0000)
committerAbramo Bagnara <abramo@alsa-project.org>
Tue, 16 May 2000 15:20:34 +0000 (15:20 +0000)
- optimized mmap transfer
- completed mmap helpers
- renamed pcm_plugin_build.c to pcm_common.c

17 files changed:
TODO
include/pcm.h
src/pcm/Makefile.am
src/pcm/pcm.c
src/pcm/pcm_local.h
src/pcm/pcm_mmap.c
src/pcm/pcm_plug.c
src/pcm/plugin/adpcm.c
src/pcm/plugin/alaw.c
src/pcm/plugin/block.c
src/pcm/plugin/copy.c
src/pcm/plugin/linear.c
src/pcm/plugin/mmap.c
src/pcm/plugin/mulaw.c
src/pcm/plugin/rate.c
src/pcm/plugin/route.c
src/pcm/plugin/stream.c

diff --git a/TODO b/TODO
index d4ae1c7ec8eb2f0923b837d69dd8f6bd2bd37105..2dde5a6423976d6c12be13140356fbda9691dc45 100644 (file)
--- a/TODO
+++ b/TODO
@@ -1,6 +1,5 @@
 M plug sync and pos problems
 M Loopback implementation?
-L break up snd_pcm_mmap_* in logical steps
 L complete mmap emulation (after plug sync and pos thought)
 L add hsearch_r code from glibc (for compatibility with older distributions)
 L move OSS emulation to user space (LD_PRELOAD)
index 57d2320964a37e9499a5e17d928e9eb0560b2bd3..117c7e4d6e4bf07be0dc8e4fee71afab993d92be 100644 (file)
@@ -97,7 +97,6 @@ int snd_pcm_channel_info(snd_pcm_t *handle, snd_pcm_channel_info_t *info);
 int snd_pcm_channel_params(snd_pcm_t *handle, snd_pcm_channel_params_t *params);
 int snd_pcm_channel_setup(snd_pcm_t *handle, snd_pcm_channel_setup_t *setup);
 int snd_pcm_voice_setup(snd_pcm_t *handle, int channel, snd_pcm_voice_setup_t *setup);
-int snd_pcm_all_voices_setup(snd_pcm_t *handle, int channel, snd_pcm_voice_setup_t *setup);
 int snd_pcm_channel_status(snd_pcm_t *handle, snd_pcm_channel_status_t *status);
 int snd_pcm_channel_update(snd_pcm_t *handle, int channel);
 int snd_pcm_playback_prepare(snd_pcm_t *handle);
@@ -126,17 +125,36 @@ int snd_pcm_mmap_data(snd_pcm_t *handle, int channel, void **buffer);
 int snd_pcm_munmap_control(snd_pcm_t *handle, int channel);
 int snd_pcm_munmap_data(snd_pcm_t *handle, int channel);
 int snd_pcm_voices_mask(snd_pcm_t *pcm, int channel, bitset_t *client_vmask);
-int snd_pcm_mmap_frags_used(snd_pcm_t *pcm, int channel, ssize_t *frags);
-int snd_pcm_mmap_frags_free(snd_pcm_t *pcm, int channel, ssize_t *frags);
-int snd_pcm_mmap_bytes_used(snd_pcm_t *pcm, int channel, ssize_t *bytes);
-int snd_pcm_mmap_bytes_free(snd_pcm_t *pcm, int channel, ssize_t *bytes);
 int snd_pcm_mmap_ready(snd_pcm_t *pcm, int channel);
 ssize_t snd_pcm_mmap_write(snd_pcm_t *handle, const void *buffer, size_t size);
 ssize_t snd_pcm_mmap_read(snd_pcm_t *handle, void *buffer, size_t size);
 ssize_t snd_pcm_mmap_writev(snd_pcm_t *pcm, const struct iovec *vector, unsigned long  count);
 ssize_t snd_pcm_mmap_readv(snd_pcm_t *pcm, const struct iovec *vector, unsigned long count);
+int snd_pcm_mmap_samples_used(snd_pcm_t *pcm, int channel, ssize_t *samples);
+int snd_pcm_mmap_samples_free(snd_pcm_t *pcm, int channel, ssize_t *samples);
+ssize_t snd_pcm_mmap_samples_xfer(snd_pcm_t *pcm, int channel, size_t samples);
+ssize_t snd_pcm_mmap_samples_offset(snd_pcm_t *pcm, int channel);
+int snd_pcm_mmap_commit_samples(snd_pcm_t *pcm, int channel, int samples);
+ssize_t snd_pcm_mmap_write_areas(snd_pcm_t *pcm, snd_pcm_voice_area_t *voices, size_t samples);
+ssize_t snd_pcm_mmap_write_samples(snd_pcm_t *pcm, const void *buffer, size_t samples);
+ssize_t snd_pcm_mmap_read_areas(snd_pcm_t *pcm, snd_pcm_voice_area_t *voices, size_t samples);
+ssize_t snd_pcm_mmap_read_samples(snd_pcm_t *pcm, const void *buffer, size_t samples);
+int snd_pcm_mmap_get_areas(snd_pcm_t *pcm, int channel, snd_pcm_voice_area_t *areas);
+
+
 ssize_t snd_pcm_bytes_per_second(snd_pcm_t *pcm, int channel);
 
+int snd_pcm_area_silence(const snd_pcm_voice_area_t *dst_voice, size_t dst_offset,
+                        size_t samples, int format);
+int snd_pcm_areas_silence(const snd_pcm_voice_area_t *dst_voices, size_t dst_offset,
+                         size_t vcount, size_t samples, int format);
+int snd_pcm_area_copy(const snd_pcm_voice_area_t *src_voice, size_t src_offset,
+                     const snd_pcm_voice_area_t *dst_voice, size_t dst_offset,
+                     size_t samples, int format);
+int snd_pcm_areas_copy(const snd_pcm_voice_area_t *src_voices, size_t src_offset,
+                      const snd_pcm_voice_area_t *dst_voices, size_t dst_offset,
+                      size_t vcount, size_t samples, int format);
+
 /* misc */
 
 int snd_pcm_format_signed(int format);
@@ -181,9 +199,7 @@ typedef enum {
 
 typedef struct snd_stru_pcm_plugin_voice {
        void *aptr;                     /* pointer to the allocated area */
-       void *addr;                     /* address to voice samples */
-       unsigned int first;             /* offset to first sample in bits */
-       unsigned int step;              /* samples distance in bits */
+       snd_pcm_voice_area_t area;
        unsigned int enabled:1;         /* voice need to be processed */
        unsigned int wanted:1;          /* voice is wanted */
 } snd_pcm_plugin_voice_t;
index 6820111f2cc0229a362f2d20598e923ebb362ab7..89222aed1c835b5321f1180efc760396290ce792 100644 (file)
@@ -2,7 +2,7 @@ SUBDIRS = plugin
 
 EXTRA_LTLIBRARIES = libpcm.la
 
-libpcm_la_SOURCES = pcm.c pcm_hw.c pcm_plug.c pcm_plugin_build.c pcm_misc.c \
+libpcm_la_SOURCES = pcm.c pcm_hw.c pcm_plug.c pcm_common.c pcm_misc.c \
                    pcm_mmap.c
 libpcm_la_LIBADD = plugin/libpcmplugin.la
 noinst_HEADERS = pcm_local.h
index 20f3a473220380ccb2bf30045e98b30bd71c81f5..5455ddf2425921940bddc10445d07580dc60f5af 100644 (file)
@@ -83,10 +83,6 @@ int snd_pcm_channel_close(snd_pcm_t *pcm, int channel)
                ret = err;
        chan->open = 0;
        chan->valid_setup = 0;
-       if (chan->valid_voices_setup) {
-               chan->valid_voices_setup = 0;
-               free(chan->voices_setup);
-       }
        return ret;
 }      
 
@@ -182,6 +178,9 @@ int snd_pcm_channel_setup(snd_pcm_t *pcm, snd_pcm_channel_setup_t *setup)
        if ((err = pcm->ops->channel_setup(pcm, setup)) < 0)
                return err;
        memcpy(&chan->setup, setup, sizeof(*setup));
+       chan->sample_width = snd_pcm_format_physical_width(setup->format.format);
+       chan->bits_per_sample = chan->sample_width * setup->format.voices;
+       chan->samples_per_frag = setup->frag_size * 8 / chan->bits_per_sample;
        chan->valid_setup = 1;
        return 0;
 }
@@ -209,61 +208,9 @@ int snd_pcm_voice_setup(snd_pcm_t *pcm, int channel, snd_pcm_voice_setup_t *setu
        chan = &pcm->chan[channel];
        if (!chan->open || !chan->valid_setup)
                return -EBADFD;
-       if (chan->valid_voices_setup) {
-               if (setup->voice >= chan->setup.format.voices)
-                       return -EINVAL;
-               memcpy(setup, &chan->voices_setup[setup->voice], sizeof(*setup));
-               return 0;
-       }
        return pcm->ops->voice_setup(pcm, channel, setup);
 }
 
-const snd_pcm_voice_setup_t* snd_pcm_channel_cached_voice_setup(snd_pcm_t *pcm, int channel, unsigned int voice)
-{
-       struct snd_pcm_chan *chan;
-       if (!pcm)
-               return 0;
-       if (channel < 0 || channel > 1)
-               return 0;
-       chan = &pcm->chan[channel];
-       if (!chan->open || !chan->valid_setup)
-               return 0;
-       if (voice >= chan->setup.format.voices)
-               return 0;
-       return &chan->voices_setup[voice];
-}
-
-int snd_pcm_all_voices_setup(snd_pcm_t *pcm, int channel, snd_pcm_voice_setup_t *setup)
-{
-       struct snd_pcm_chan *chan;
-       snd_pcm_voice_setup_t *vs, *v;
-       unsigned int voice;
-       int err;
-       if (!pcm)
-               return -EFAULT;
-       if (channel < 0 || channel > 1)
-               return -EINVAL;
-       chan = &pcm->chan[channel];
-       if (!chan->open || !chan->valid_setup)
-               return -EBADFD;
-       vs = calloc(chan->setup.format.voices, sizeof(*setup));
-       for (voice = 0, v = vs; voice < chan->setup.format.voices; ++voice, ++v) {
-               v->voice = voice;
-               err = snd_pcm_voice_setup(pcm, channel, v);
-               if (err < 0) {
-                       free(vs);
-                       return err;
-               }
-               if (setup) {
-                       memcpy(setup, v, sizeof(*setup));
-                       setup++;
-               }
-       }
-       chan->voices_setup = vs;
-       chan->valid_voices_setup = 1;
-       return 0;
-}
-
 int snd_pcm_channel_status(snd_pcm_t *pcm, snd_pcm_channel_status_t *status)
 {
        if (!pcm || !status)
index 5f3ce7b4428b5adc66771bafb7c76b3ebab1d904..5f7f709b8d0349df4ab461930d24c4026ce827a0 100644 (file)
@@ -82,8 +82,10 @@ struct snd_pcm_chan {
        int mode;
        int valid_setup;
        snd_pcm_channel_setup_t setup;
-       int valid_voices_setup;
-       snd_pcm_voice_setup_t *voices_setup;
+       snd_pcm_voice_area_t *voices;
+       size_t sample_width;
+       size_t bits_per_sample;
+       size_t samples_per_frag;
        snd_pcm_mmap_control_t *mmap_control;
        size_t mmap_control_size;
        int mmap_control_emulation;
@@ -141,13 +143,8 @@ void snd_pcm_plug_buf_unlock(snd_pcm_t *pcm, int channel, void *ptr);
 #define ROUTE_PLUGIN_RESOLUTION 16
 
 int getput_index(int format);
-int copy_index(int format);
 int conv_index(int src_format, int dst_format);
 
-void snd_pcm_plugin_silence_voice(snd_pcm_plugin_t *plugin,
-                                 const snd_pcm_plugin_voice_t *dst_voice,
-                                 size_t samples);
-
 #ifdef PLUGIN_DEBUG
 #define pdprintf( args... ) fprintf(stderr, "plugin: " ##args)
 #else
index f8ad2ebb804c8d05104285ecf25ca8b81023c8ef..cdef4a92ad07124a2914a3c84a399e5f1595b09a 100644 (file)
@@ -31,8 +31,8 @@ static void snd_pcm_mmap_clear(snd_pcm_t *pcm, int channel)
        struct snd_pcm_chan *chan = &pcm->chan[channel];
        chan->mmap_control->frag_io = 0;
        chan->mmap_control->frag_data = 0;
-       chan->mmap_control->pos_io = 0;
-       chan->mmap_control->pos_data = 0;
+       chan->mmap_control->byte_io = 0;
+       chan->mmap_control->byte_data = 0;
 }
 
 void snd_pcm_mmap_status_change(snd_pcm_t *pcm, int channel, int newstatus)
@@ -61,39 +61,69 @@ void snd_pcm_mmap_status_change(snd_pcm_t *pcm, int channel, int newstatus)
        }
 }
 
-static ssize_t snd_pcm_mmap_playback_frags_used(snd_pcm_t *pcm)
+static inline ssize_t snd_pcm_mmap_playback_frags_used(struct snd_pcm_chan *chan)
 {
-       struct snd_pcm_chan *chan;
        ssize_t frags_used;
-       chan = &pcm->chan[SND_PCM_CHANNEL_PLAYBACK];
        frags_used = chan->mmap_control->frag_data - chan->mmap_control->frag_io;
        if (frags_used < (ssize_t)(chan->setup.frags - chan->setup.frag_boundary))
                frags_used += chan->setup.frag_boundary;
        return frags_used;
 }
 
-static size_t snd_pcm_mmap_capture_frags_used(snd_pcm_t *pcm)
+static inline ssize_t snd_pcm_mmap_playback_bytes_used(struct snd_pcm_chan *chan)
+{
+       ssize_t bytes_used;
+       bytes_used = chan->mmap_control->byte_data - chan->mmap_control->byte_io;
+       if (bytes_used < (ssize_t)(chan->setup.buffer_size - chan->setup.byte_boundary))
+               bytes_used += chan->setup.byte_boundary;
+       return bytes_used;
+}
+
+static ssize_t snd_pcm_mmap_playback_samples_used(snd_pcm_t *pcm)
 {
        struct snd_pcm_chan *chan;
+       chan = &pcm->chan[SND_PCM_CHANNEL_PLAYBACK];
+       if (chan->setup.mode == SND_PCM_MODE_BLOCK) {
+               ssize_t frags = snd_pcm_mmap_playback_frags_used(chan);
+               return frags * chan->samples_per_frag;
+       } else {
+               ssize_t bytes = snd_pcm_mmap_playback_bytes_used(chan);
+               return bytes * 8 / chan->bits_per_sample;
+       }
+}
+
+static inline size_t snd_pcm_mmap_capture_frags_used(struct snd_pcm_chan *chan)
+{
        ssize_t frags_used;
-       chan = &pcm->chan[SND_PCM_CHANNEL_CAPTURE];
        frags_used = chan->mmap_control->frag_io - chan->mmap_control->frag_data;
        if (frags_used < 0)
                frags_used += chan->setup.frag_boundary;
        return frags_used;
 }
 
-static size_t snd_pcm_mmap_playback_frags_free(snd_pcm_t *pcm)
+static inline size_t snd_pcm_mmap_capture_bytes_used(struct snd_pcm_chan *chan)
 {
-       return pcm->chan[SND_PCM_CHANNEL_PLAYBACK].setup.frags - snd_pcm_mmap_playback_frags_used(pcm);
+       ssize_t bytes_used;
+       bytes_used = chan->mmap_control->byte_io - chan->mmap_control->byte_data;
+       if (bytes_used < 0)
+               bytes_used += chan->setup.byte_boundary;
+       return bytes_used;
 }
 
-static ssize_t snd_pcm_mmap_capture_frags_free(snd_pcm_t *pcm)
+static size_t snd_pcm_mmap_capture_samples_used(snd_pcm_t *pcm)
 {
-       return pcm->chan[SND_PCM_CHANNEL_CAPTURE].setup.frags - snd_pcm_mmap_capture_frags_used(pcm);
+       struct snd_pcm_chan *chan;
+       chan = &pcm->chan[SND_PCM_CHANNEL_CAPTURE];
+       if (chan->setup.mode == SND_PCM_MODE_BLOCK) {
+               size_t frags = snd_pcm_mmap_capture_frags_used(chan);
+               return frags * chan->samples_per_frag;
+       } else {
+               size_t bytes = snd_pcm_mmap_capture_bytes_used(chan);
+               return bytes * 8 / chan->bits_per_sample;
+       }
 }
 
-int snd_pcm_mmap_frags_used(snd_pcm_t *pcm, int channel, ssize_t *frags)
+int snd_pcm_mmap_samples_used(snd_pcm_t *pcm, int channel, ssize_t *samples)
 {
        struct snd_pcm_chan *chan;
         if (!pcm)
@@ -104,79 +134,60 @@ int snd_pcm_mmap_frags_used(snd_pcm_t *pcm, int channel, ssize_t *frags)
        if (!chan->open || !chan->mmap_control)
                return -EBADFD;
        if (channel == SND_PCM_CHANNEL_PLAYBACK)
-               *frags = snd_pcm_mmap_playback_frags_used(pcm);
+               *samples = snd_pcm_mmap_playback_samples_used(pcm);
        else
-               *frags = snd_pcm_mmap_capture_frags_used(pcm);
+               *samples = snd_pcm_mmap_capture_samples_used(pcm);
        return 0;
 }
 
-int snd_pcm_mmap_frags_free(snd_pcm_t *pcm, int channel, ssize_t *frags)
+static inline size_t snd_pcm_mmap_playback_frags_free(struct snd_pcm_chan *chan)
 {
-       struct snd_pcm_chan *chan;
-        if (!pcm)
-                return -EFAULT;
-        if (channel < 0 || channel > 1)
-                return -EINVAL;
-       chan = &pcm->chan[channel];
-       if (!chan->open || !chan->mmap_control)
-               return -EBADFD;
-       if (channel == SND_PCM_CHANNEL_PLAYBACK)
-               *frags = snd_pcm_mmap_playback_frags_free(pcm);
-       else
-               *frags = snd_pcm_mmap_capture_frags_free(pcm);
-       return 0;
+       return chan->setup.frags - snd_pcm_mmap_playback_frags_used(chan);
 }
 
-static ssize_t snd_pcm_mmap_playback_bytes_used(snd_pcm_t *pcm)
+static inline size_t snd_pcm_mmap_playback_bytes_free(struct snd_pcm_chan *chan)
 {
-       struct snd_pcm_chan *chan;
-       ssize_t bytes_used;
-       chan = &pcm->chan[SND_PCM_CHANNEL_PLAYBACK];
-       bytes_used = chan->mmap_control->pos_data - chan->mmap_control->pos_io;
-       if (bytes_used < (ssize_t)(chan->setup.buffer_size - chan->setup.pos_boundary))
-               bytes_used += chan->setup.pos_boundary;
-       return bytes_used;
+       return chan->setup.buffer_size - snd_pcm_mmap_playback_bytes_used(chan);
 }
 
-static size_t snd_pcm_mmap_capture_bytes_used(snd_pcm_t *pcm)
+static size_t snd_pcm_mmap_playback_samples_free(snd_pcm_t *pcm)
 {
        struct snd_pcm_chan *chan;
-       ssize_t bytes_used;
-       chan = &pcm->chan[SND_PCM_CHANNEL_CAPTURE];
-       bytes_used = chan->mmap_control->pos_io - chan->mmap_control->pos_data;
-       if (bytes_used < 0)
-               bytes_used += chan->setup.pos_boundary;
-       return bytes_used;
+       chan = &pcm->chan[SND_PCM_CHANNEL_PLAYBACK];
+       if (chan->setup.mode == SND_PCM_MODE_BLOCK) {
+               size_t frags = snd_pcm_mmap_playback_frags_free(chan);
+               return frags * chan->samples_per_frag;
+       } else {
+               size_t bytes = snd_pcm_mmap_playback_bytes_free(chan);
+               return bytes * 8 / chan->bits_per_sample;
+       }
 }
 
-int snd_pcm_mmap_bytes_used(snd_pcm_t *pcm, int channel, ssize_t *frags)
+static inline ssize_t snd_pcm_mmap_capture_frags_free(struct snd_pcm_chan *chan)
 {
-       struct snd_pcm_chan *chan;
-        if (!pcm)
-                return -EFAULT;
-        if (channel < 0 || channel > 1)
-                return -EINVAL;
-       chan = &pcm->chan[channel];
-       if (!chan->open || !chan->mmap_control)
-               return -EBADFD;
-       if (channel == SND_PCM_CHANNEL_PLAYBACK)
-               *frags = snd_pcm_mmap_playback_bytes_used(pcm);
-       else
-               *frags = snd_pcm_mmap_capture_bytes_used(pcm);
-       return 0;
+       return chan->setup.frags - snd_pcm_mmap_capture_frags_used(chan);
 }
 
-static size_t snd_pcm_mmap_playback_bytes_free(snd_pcm_t *pcm)
+
+static inline ssize_t snd_pcm_mmap_capture_bytes_free(struct snd_pcm_chan *chan)
 {
-       return pcm->chan[SND_PCM_CHANNEL_PLAYBACK].setup.buffer_size - snd_pcm_mmap_playback_bytes_used(pcm);
+       return chan->setup.buffer_size - snd_pcm_mmap_capture_bytes_used(chan);
 }
 
-static ssize_t snd_pcm_mmap_capture_bytes_free(snd_pcm_t *pcm)
+static ssize_t snd_pcm_mmap_capture_samples_free(snd_pcm_t *pcm)
 {
-       return pcm->chan[SND_PCM_CHANNEL_CAPTURE].setup.buffer_size - snd_pcm_mmap_capture_bytes_used(pcm);
+       struct snd_pcm_chan *chan;
+       chan = &pcm->chan[SND_PCM_CHANNEL_CAPTURE];
+       if (chan->setup.mode == SND_PCM_MODE_BLOCK) {
+               ssize_t frags = snd_pcm_mmap_capture_frags_free(chan);
+               return frags * chan->samples_per_frag;
+       } else {
+               ssize_t bytes = snd_pcm_mmap_capture_bytes_free(chan);
+               return bytes * 8 / chan->bits_per_sample;
+       }
 }
 
-int snd_pcm_mmap_bytes_free(snd_pcm_t *pcm, int channel, ssize_t *frags)
+int snd_pcm_mmap_samples_free(snd_pcm_t *pcm, int channel, ssize_t *samples)
 {
        struct snd_pcm_chan *chan;
         if (!pcm)
@@ -187,9 +198,9 @@ int snd_pcm_mmap_bytes_free(snd_pcm_t *pcm, int channel, ssize_t *frags)
        if (!chan->open || !chan->mmap_control)
                return -EBADFD;
        if (channel == SND_PCM_CHANNEL_PLAYBACK)
-               *frags = snd_pcm_mmap_playback_bytes_free(pcm);
+               *samples = snd_pcm_mmap_playback_samples_free(pcm);
        else
-               *frags = snd_pcm_mmap_capture_bytes_free(pcm);
+               *samples = snd_pcm_mmap_capture_samples_free(pcm);
        return 0;
 }
 
@@ -200,9 +211,9 @@ static int snd_pcm_mmap_playback_ready(snd_pcm_t *pcm)
        if (chan->mmap_control->status == SND_PCM_STATUS_XRUN)
                return -EPIPE;
        if (chan->setup.mode == SND_PCM_MODE_BLOCK) {
-               return (chan->setup.frags - snd_pcm_mmap_playback_frags_used(pcm)) >= chan->setup.buf.block.frags_min;
+               return (chan->setup.frags - snd_pcm_mmap_playback_frags_used(chan)) >= chan->setup.buf.block.frags_min;
        } else {
-               return (chan->setup.buffer_size - snd_pcm_mmap_playback_bytes_used(pcm)) >= chan->setup.buf.stream.bytes_min;
+               return (chan->setup.buffer_size - snd_pcm_mmap_playback_bytes_used(chan)) >= chan->setup.buf.stream.bytes_min;
        }
 }
 
@@ -217,10 +228,10 @@ static int snd_pcm_mmap_capture_ready(snd_pcm_t *pcm)
                        return -EPIPE;
        }
        if (chan->setup.mode == SND_PCM_MODE_BLOCK) {
-               if (snd_pcm_mmap_capture_frags_used(pcm) >= chan->setup.buf.block.frags_min)
+               if (snd_pcm_mmap_capture_frags_used(chan) >= chan->setup.buf.block.frags_min)
                        return 1;
        } else {
-               if (snd_pcm_mmap_capture_bytes_used(pcm) >= chan->setup.buf.stream.bytes_min)
+               if (snd_pcm_mmap_capture_bytes_used(chan) >= chan->setup.buf.stream.bytes_min)
                        return 1;
        }
        return ret;
@@ -247,53 +258,183 @@ int snd_pcm_mmap_ready(snd_pcm_t *pcm, int channel)
        }
 }
 
-/* Bytes transferrable */
-static size_t snd_pcm_mmap_bytes_playback(snd_pcm_t *pcm, size_t size)
+static size_t snd_pcm_mmap_playback_frags_xfer(snd_pcm_t *pcm, size_t frags)
 {
        struct snd_pcm_chan *chan = &pcm->chan[SND_PCM_CHANNEL_PLAYBACK];
        snd_pcm_mmap_control_t *ctrl = chan->mmap_control;
-       size_t bytes_cont, bytes_free;
-       unsigned int pos_data = ctrl->pos_data;
-       unsigned int pos_io = ctrl->pos_io;
-       int bytes_used = pos_data - pos_io;
-       if (bytes_used < -(int)(chan->setup.buf.stream.bytes_xrun_max + chan->setup.frag_size))
-               bytes_used += chan->setup.pos_boundary;
-       bytes_cont = chan->setup.buffer_size - (pos_data % chan->setup.buffer_size);
-       if (bytes_cont < size)
-               size = bytes_cont;
-       bytes_free = chan->setup.buffer_size - bytes_used;
-       if (bytes_free < size)
-               size = (bytes_free / chan->setup.buf.stream.bytes_align) * chan->setup.buf.stream.bytes_align;
-       return size;
+       size_t frags_cont;
+       size_t frag_data = ctrl->frag_data;
+       size_t frags_free = snd_pcm_mmap_playback_frags_free(chan);
+       if (frags_free < frags)
+               frags = frags_free;
+       frags_cont = chan->setup.frags - (frag_data % chan->setup.frags);
+       if (frags_cont < frags)
+               frags = frags_cont;
+       return frags;
 }
 
-/* Bytes transferrable */
-static size_t snd_pcm_mmap_bytes_capture(snd_pcm_t *pcm, size_t size)
+static size_t snd_pcm_mmap_capture_frags_xfer(snd_pcm_t *pcm, size_t frags)
 {
        struct snd_pcm_chan *chan = &pcm->chan[SND_PCM_CHANNEL_CAPTURE];
        snd_pcm_mmap_control_t *ctrl = chan->mmap_control;
+       size_t frags_cont;
+       size_t frag_data = ctrl->frag_data;
+       size_t frags_used = snd_pcm_mmap_capture_frags_used(chan);
+       if (frags_used < frags)
+               frags = frags_used;
+       frags_cont = chan->setup.frags - (frag_data % chan->setup.frags);
+       if (frags_cont < frags)
+               frags = frags_cont;
+       return frags;
+}
+
+static size_t snd_pcm_mmap_playback_bytes_xfer(snd_pcm_t *pcm, size_t bytes)
+{
+       struct snd_pcm_chan *chan = &pcm->chan[SND_PCM_CHANNEL_PLAYBACK];
+       snd_pcm_mmap_control_t *ctrl = chan->mmap_control;
        size_t bytes_cont;
-       unsigned int pos_data = ctrl->pos_data;
-       unsigned int pos_io = ctrl->pos_io;
-       int bytes_used = pos_io - pos_data;
-       if (bytes_used < 0)
-               bytes_used += chan->setup.pos_boundary;
-       bytes_cont = chan->setup.buffer_size - (pos_data % chan->setup.buffer_size);
-       if (bytes_cont < size)
-               size = bytes_cont;
-       if ((size_t) bytes_used < size)
-               size = (bytes_used / chan->setup.buf.stream.bytes_align) * chan->setup.buf.stream.bytes_align;
-       return size;
+       size_t byte_data = ctrl->byte_data;
+       size_t bytes_free = snd_pcm_mmap_playback_bytes_free(chan);
+       if (bytes_free < bytes)
+               bytes = bytes_free;
+       bytes_cont = chan->setup.buffer_size - (byte_data % chan->setup.buffer_size);
+       if (bytes_cont < bytes)
+               bytes = bytes_cont;
+       bytes -= bytes % chan->setup.buf.stream.bytes_align;
+       return bytes;
+}
+
+static size_t snd_pcm_mmap_capture_bytes_xfer(snd_pcm_t *pcm, size_t bytes)
+{
+       struct snd_pcm_chan *chan = &pcm->chan[SND_PCM_CHANNEL_CAPTURE];
+       snd_pcm_mmap_control_t *ctrl = chan->mmap_control;
+       size_t bytes_cont;
+       size_t byte_data = ctrl->byte_data;
+       size_t bytes_used = snd_pcm_mmap_capture_bytes_used(chan);
+       if (bytes_used < bytes)
+               bytes = bytes_used;
+       bytes_cont = chan->setup.buffer_size - (byte_data % chan->setup.buffer_size);
+       if (bytes_cont < bytes)
+               bytes = bytes_cont;
+       bytes -= bytes % chan->setup.buf.stream.bytes_align;
+       return bytes;
 }
 
-typedef int (*transfer_f)(snd_pcm_t *pcm, size_t hwoff, void *data, size_t off, size_t size);
+static ssize_t snd_pcm_mmap_playback_samples_xfer(snd_pcm_t *pcm, size_t samples)
+{
+       struct snd_pcm_chan *chan;
+       chan = &pcm->chan[SND_PCM_CHANNEL_PLAYBACK];
+       if (chan->setup.mode == SND_PCM_MODE_BLOCK) {
+               size_t frags = samples / chan->samples_per_frag;
+               frags = snd_pcm_mmap_playback_frags_xfer(pcm, frags);
+               return frags * chan->samples_per_frag;
+       } else {
+               size_t bytes = samples * chan->bits_per_sample / 8;
+               bytes = snd_pcm_mmap_playback_bytes_xfer(pcm, bytes);
+               return bytes * 8 / chan->bits_per_sample;
+       }
+}
+
+static ssize_t snd_pcm_mmap_capture_samples_xfer(snd_pcm_t *pcm, size_t samples)
+{
+       struct snd_pcm_chan *chan;
+       chan = &pcm->chan[SND_PCM_CHANNEL_CAPTURE];
+       if (chan->setup.mode == SND_PCM_MODE_BLOCK) {
+               size_t frags = samples / chan->samples_per_frag;
+               frags = snd_pcm_mmap_capture_frags_xfer(pcm, frags);
+               return frags * chan->samples_per_frag;
+       } else {
+               size_t bytes = samples * chan->bits_per_sample / 8;
+               bytes = snd_pcm_mmap_capture_bytes_xfer(pcm, bytes);
+               return bytes * 8 / chan->bits_per_sample;
+       }
+}
+
+ssize_t snd_pcm_mmap_samples_xfer(snd_pcm_t *pcm, int channel, size_t samples)
+{
+       struct snd_pcm_chan *chan;
+        if (!pcm)
+                return -EFAULT;
+        if (channel < 0 || channel > 1)
+                return -EINVAL;
+       chan = &pcm->chan[channel];
+       if (!chan->open || !chan->mmap_control)
+               return -EBADFD;
+       if (channel == SND_PCM_CHANNEL_PLAYBACK)
+               return snd_pcm_mmap_playback_samples_xfer(pcm, samples);
+       else
+               return snd_pcm_mmap_capture_samples_xfer(pcm, samples);
+}
+
+ssize_t snd_pcm_mmap_samples_offset(snd_pcm_t *pcm, int channel)
+{
+       struct snd_pcm_chan *chan;
+       snd_pcm_mmap_control_t *ctrl;
+        if (!pcm)
+                return -EFAULT;
+        if (channel < 0 || channel > 1)
+                return -EINVAL;
+       chan = &pcm->chan[channel];
+       if (!chan->open)
+               return -EBADFD;
+       ctrl = chan->mmap_control;
+       if (!ctrl)
+               return -EBADFD;
+       if (chan->setup.mode == SND_PCM_MODE_BLOCK)
+               return (ctrl->frag_data % chan->setup.frags) * chan->samples_per_frag;
+       else
+               return (ctrl->byte_data % chan->setup.buffer_size) * 8 / chan->bits_per_sample;
+}
 
+int snd_pcm_mmap_commit_samples(snd_pcm_t *pcm, int channel, int samples)
+{
+       struct snd_pcm_chan *chan;
+       snd_pcm_mmap_control_t *ctrl;
+        if (!pcm)
+                return -EFAULT;
+        if (channel < 0 || channel > 1)
+                return -EINVAL;
+       chan = &pcm->chan[channel];
+       if (!chan->open)
+               return -EBADFD;
+       ctrl = chan->mmap_control;
+       if (!ctrl)
+               return -EBADFD;
+       if (chan->setup.mode == SND_PCM_MODE_BLOCK) {
+               size_t frag_data, frags;
+               if (samples % chan->samples_per_frag)
+                       return -EINVAL;
+               frags = samples / chan->samples_per_frag;
+               frag_data = ctrl->frag_data + frags;
+               if (frag_data == chan->setup.frag_boundary) {
+                       ctrl->frag_data = 0;
+                       ctrl->byte_data = 0;
+               } else {
+                       ctrl->frag_data = frag_data;
+                       ctrl->byte_data = frag_data * chan->setup.frag_size;
+               }
+       } else {
+               size_t byte_data;
+               size_t bytes = samples * chan->bits_per_sample;
+               if (bytes % 8)
+                       return -EINVAL;
+               bytes /= 8;
+               byte_data = ctrl->byte_data + bytes;
+               if (byte_data == chan->setup.byte_boundary) {
+                       ctrl->byte_data = 0;
+                       ctrl->frag_data = 0;
+               } else {
+                       ctrl->byte_data = byte_data;
+                       ctrl->frag_data = byte_data / chan->setup.frag_size;
+               }
+       }
+       return 0;
+}
 
-static ssize_t snd_pcm_mmap_write1(snd_pcm_t *pcm, const void *data, size_t count, transfer_f transfer)
+ssize_t snd_pcm_mmap_write_areas(snd_pcm_t *pcm, snd_pcm_voice_area_t *voices, size_t samples)
 {
        struct snd_pcm_chan *chan;
        snd_pcm_mmap_control_t *ctrl;
-       size_t frag_size;
        size_t offset = 0;
        size_t result = 0;
        int err;
@@ -302,25 +443,17 @@ static ssize_t snd_pcm_mmap_write1(snd_pcm_t *pcm, const void *data, size_t coun
        ctrl = chan->mmap_control;
        if (ctrl->status < SND_PCM_STATUS_PREPARED)
                return -EBADFD;
-       frag_size = chan->setup.frag_size;
        if (chan->setup.mode == SND_PCM_MODE_BLOCK) {
-               if (count % frag_size != 0)
+               if (samples % chan->samples_per_frag != 0)
                        return -EINVAL;
        } else {
-               int tmp = snd_pcm_format_size(chan->setup.format.format, chan->setup.format.voices);
-               if (tmp > 0) {
-                       int r = count % tmp;
-                       if (r > 0) {
-                               count -= r;
-                               if (count == 0)
-                                       return -EINVAL;
-                       }
-                }
+               if (ctrl->status == SND_PCM_STATUS_RUNNING &&
+                   chan->mode & SND_PCM_NONBLOCK)
+                       snd_pcm_channel_update(pcm, SND_PCM_CHANNEL_PLAYBACK);
        }
-       if (chan->mode & SND_PCM_NONBLOCK)
-               snd_pcm_channel_update(pcm, SND_PCM_CHANNEL_PLAYBACK);
-       while (count > 0) {
-               size_t bytes;
+       while (samples > 0) {
+               ssize_t mmap_offset;
+               size_t samples1;
                int ready = snd_pcm_mmap_playback_ready(pcm);
                if (ready < 0)
                        return ready;
@@ -339,221 +472,148 @@ static ssize_t snd_pcm_mmap_write1(snd_pcm_t *pcm, const void *data, size_t coun
                                return result > 0 ? result : -EPIPE;
                        assert(snd_pcm_mmap_playback_ready(pcm));
                }
-               if (chan->setup.mode == SND_PCM_MODE_BLOCK) {
-                       size_t frag_data, frag;
-                       frag_data = ctrl->frag_data;
-                       frag = frag_data % chan->setup.frags;
-                       err = transfer(pcm, frag_size * frag, (void *) data, offset, frag_size);
-                       if (err < 0) 
-                               return result > 0 ? result : err;
-                       if (ctrl->status == SND_PCM_STATUS_XRUN)
-                               return result > 0 ? result : -EPIPE;
-                       frag_data++;
-                       if (frag_data == chan->setup.frag_boundary) {
-                               ctrl->frag_data = 0;
-                               ctrl->pos_data = 0;
-                       } else {
-                               ctrl->frag_data = frag_data;
-                               ctrl->pos_data += frag_size;
-                       }
-                       bytes = frag_size;
-               } else {
-                       size_t pos_data;
-                       bytes = snd_pcm_mmap_bytes_playback(pcm, count);
-                       pos_data = ctrl->pos_data;
-                       err = transfer(pcm, pos_data % chan->setup.buffer_size, (void *) data, offset, bytes);
-                       if (err < 0) 
+               samples1 = snd_pcm_mmap_playback_samples_xfer(pcm, samples);
+               assert(samples1 > 0);
+               mmap_offset = snd_pcm_mmap_samples_offset(pcm, SND_PCM_CHANNEL_PLAYBACK);
+               snd_pcm_areas_copy(voices, offset, chan->voices, mmap_offset, chan->setup.format.voices, samples1, chan->setup.format.format);
+               if (ctrl->status == SND_PCM_STATUS_XRUN)
+                       return result > 0 ? result : -EPIPE;
+               snd_pcm_mmap_commit_samples(pcm, SND_PCM_CHANNEL_PLAYBACK, samples1);
+               samples -= samples1;
+               offset += samples1;
+               result += samples1;
+               if (ctrl->status == SND_PCM_STATUS_PREPARED &&
+                   (chan->setup.start_mode == SND_PCM_START_DATA ||
+                    (chan->setup.start_mode == SND_PCM_START_FULL &&
+                     !snd_pcm_mmap_playback_ready(pcm)))) {
+                       err = snd_pcm_channel_go(pcm, SND_PCM_CHANNEL_PLAYBACK);
+                       if (err < 0)
                                return result > 0 ? result : err;
-                       if (ctrl->status == SND_PCM_STATUS_XRUN)
-                               return result > 0 ? result : -EPIPE;
-                       pos_data += bytes;
-                       if (pos_data == chan->setup.pos_boundary) {
-                               ctrl->pos_data = 0;
-                               ctrl->frag_data = 0;
-                       } else {
-                               ctrl->pos_data = pos_data;
-                               ctrl->frag_data = pos_data / chan->setup.frags;
-                       }
                }
-               offset += bytes;
-               count -= bytes;
-               result += bytes;
-       }
-       
-       if (ctrl->status == SND_PCM_STATUS_PREPARED &&
-           (chan->setup.start_mode == SND_PCM_START_DATA ||
-            (chan->setup.start_mode == SND_PCM_START_FULL &&
-             !snd_pcm_mmap_playback_ready(pcm)))) {
-               err = snd_pcm_channel_go(pcm, SND_PCM_CHANNEL_PLAYBACK);
-               if (err < 0)
-                       return result > 0 ? result : err;
        }
        return result;
 }
 
-static int transfer_write(snd_pcm_t *pcm, size_t hwoff, void* data, size_t off, size_t size)
+ssize_t snd_pcm_mmap_write_samples(snd_pcm_t *pcm, const void *buffer, size_t samples)
 {
-       struct snd_pcm_chan *chan = &pcm->chan[SND_PCM_CHANNEL_PLAYBACK];
-       const char *buf = data;
-       unsigned int v, voices;
-#define COPY_LABELS
-#include "plugin/plugin_ops.h"
-#undef COPY_LABELS
-       void *copy;
-       snd_pcm_voice_setup_t *vsetup;
-       int idx;
-       size_t vsize, ssize;
-       idx = copy_index(chan->setup.format.format);
-       if (idx < 0)
-               return idx;
-       copy = copy_labels[idx];
-       voices = chan->setup.format.voices;
-       vsetup = chan->voices_setup;
-       vsize = snd_pcm_format_size(chan->setup.format.format, 1);
-       ssize = vsize * chan->setup.format.voices;
-       hwoff /= ssize;
-       size /= ssize;
-       for (v = 0; v < voices; ++v, ++vsetup) {
-               const char *src;
-               char *dst;
-               size_t dst_step;
-               size_t samples = size;
-               if (vsetup->first % 8 != 0 ||
-                   vsetup->step % 8 != 0)
-                       return -EINVAL;
-               src = buf + off + v * vsize;
-               dst_step = vsetup->step / 8;
-               dst = chan->mmap_data + vsetup->addr + (vsetup->first + vsetup->step * hwoff) / 8;
-               while (samples-- > 0) {
-                       goto *copy;
-#define COPY_END after
-#include "plugin/plugin_ops.h"
-#undef COPY_END
-               after:
-                       src += ssize;
-                       dst += dst_step;
+       struct snd_pcm_chan *chan;
+       unsigned int nvoices;
+       if (!pcm)
+               return -EFAULT;
+       chan = &pcm->chan[SND_PCM_CHANNEL_PLAYBACK];
+       if (!chan->open || !chan->valid_setup)
+               return -EBADFD;
+       if (!chan->mmap_data || !chan->mmap_control)
+               return -EBADFD;
+       if (samples > 0 && !buffer)
+               return -EFAULT;
+       nvoices = chan->setup.format.voices;
+       if (!chan->setup.format.interleave && nvoices > 1)
+               return -EINVAL;
+       {
+               snd_pcm_voice_area_t voices[nvoices];
+               unsigned int voice;
+               for (voice = 0; voice < nvoices; ++voice) {
+                       voices[voice].addr = (char*)buffer;
+                       voices[voice].first = chan->sample_width * voice;
+                       voices[voice].step = chan->bits_per_sample;
                }
+               return snd_pcm_mmap_write_areas(pcm, voices, samples);
        }
-       return 0;
 }
 
-ssize_t snd_pcm_mmap_write(snd_pcm_t *pcm, const void *buffer, size_t count)
+ssize_t snd_pcm_mmap_write(snd_pcm_t *pcm, const void *buffer, size_t bytes)
 {
        struct snd_pcm_chan *chan;
+       unsigned int nvoices;
+       ssize_t samples;
        if (!pcm)
                return -EFAULT;
        chan = &pcm->chan[SND_PCM_CHANNEL_PLAYBACK];
-       if (!chan->open || !chan->valid_setup || !chan->valid_voices_setup)
+       if (!chan->open || !chan->valid_setup)
                return -EBADFD;
        if (!chan->mmap_data || !chan->mmap_control)
                return -EBADFD;
-       if (count > 0 && !buffer)
+       if (bytes > 0 && !buffer)
                return -EFAULT;
-       if (!chan->setup.format.interleave && chan->setup.format.voices > 1)
+       nvoices = chan->setup.format.voices;
+       if (!chan->setup.format.interleave && nvoices > 1)
                return -EINVAL;
-       return snd_pcm_mmap_write1(pcm, buffer, count, transfer_write);
-}
-
-static int transfer_writev(snd_pcm_t *pcm, size_t hwoff, void* data, size_t off, size_t size)
-{
-       struct snd_pcm_chan *chan = &pcm->chan[SND_PCM_CHANNEL_PLAYBACK];
-       struct iovec *vec = data;
-       unsigned int v, voices;
-#define COPY_LABELS
-#include "plugin/plugin_ops.h"
-#undef COPY_LABELS
-       void *copy;
-       snd_pcm_voice_setup_t *vsetup;
-       int idx;
-       size_t ssize;
-       idx = copy_index(chan->setup.format.format);
-       if (idx < 0)
-               return idx;
-       copy = copy_labels[idx];
-       voices = chan->setup.format.voices;
-       vsetup = chan->voices_setup;
-       ssize = snd_pcm_format_size(chan->setup.format.format, chan->setup.format.voices);
-       hwoff /= ssize;
-       size /= ssize;
-       off /= voices;
-       for (v = 0; v < voices; ++v, ++vsetup, ++vec) {
-               const char *src;
-               char *dst;
-               size_t dst_step;
-               size_t samples = size;
-               if (vsetup->first % 8 != 0 ||
-                   vsetup->step % 8 != 0)
-                       return -EINVAL;
-               src = vec->iov_base + off;
-               dst_step = vsetup->step / 8;
-               dst = chan->mmap_data + vsetup->addr + (vsetup->first + vsetup->step * hwoff) / 8;
-               while (samples-- > 0) {
-                       goto *copy;
-#define COPY_END after
-#include "plugin/plugin_ops.h"
-#undef COPY_END
-               after:
-                       src += ssize;
-                       dst += dst_step;
-               }
-       }
-       return 0;
+       samples = bytes * 8 / chan->bits_per_sample;
+       samples = snd_pcm_mmap_write_samples(pcm, buffer, samples);
+       if (samples <= 0)
+               return samples;
+       return samples * chan->bits_per_sample / 8;
 }
 
 ssize_t snd_pcm_mmap_writev(snd_pcm_t *pcm, const struct iovec *vector, unsigned long vcount)
 {
        struct snd_pcm_chan *chan;
        size_t result = 0;
-       unsigned int b;
+       unsigned int nvoices;
        if (!pcm)
                return -EFAULT;
        chan = &pcm->chan[SND_PCM_CHANNEL_PLAYBACK];
-       if (!chan->open || !chan->valid_setup || !chan->valid_voices_setup)
+       if (!chan->open || !chan->valid_setup)
                return -EBADFD;
        if (!chan->mmap_data || !chan->mmap_control)
                return -EBADFD;
        if (vcount > 0 && !vector)
                return -EFAULT;
+       nvoices = chan->setup.format.voices;
        if (chan->setup.format.interleave) {
+               unsigned int b;
                for (b = 0; b < vcount; b++) {
-                       int ret;
-                       ret = snd_pcm_mmap_write1(pcm, vector[b].iov_base, vector[b].iov_len, transfer_write);
-                       if (ret < 0)
-                               return result > 0 ? result : ret;
+                       ssize_t ret;
+                       size_t samples = vector[b].iov_len * 8 / chan->bits_per_sample;
+                       ret = snd_pcm_mmap_write_samples(pcm, vector[b].iov_base, samples);
+                       if (ret < 0) {
+                               if (result <= 0)
+                                       return ret;
+                               break;
+                       }
                        result += ret;
                }
        } else {
-               unsigned int voices = chan->setup.format.voices;
+               snd_pcm_voice_area_t voices[nvoices];
                unsigned long bcount;
-               if (vcount % voices)
+               unsigned int b;
+               if (vcount % nvoices)
                        return -EINVAL;
-               bcount = vcount / voices;
+               bcount = vcount / nvoices;
                for (b = 0; b < bcount; b++) {
                        unsigned int v;
-                       int ret;
-                       size_t count = 0;
-                       count = vector[0].iov_len;
-                       for (v = 0; v < voices; ++v) {
-                               if (vector[v].iov_len != count)
+                       ssize_t ret;
+                       size_t bytes = 0;
+                       size_t samples;
+                       bytes = vector[0].iov_len;
+                       for (v = 0; v < nvoices; ++v) {
+                               if (vector[v].iov_len != bytes)
                                        return -EINVAL;
+                               voices[v].addr = vector[v].iov_base;
+                               voices[v].first = 0;
+                               voices[v].step = chan->sample_width;
+                       }
+                       samples = bytes * 8 / chan->sample_width;
+                       ret = snd_pcm_mmap_write_areas(pcm, voices, samples);
+                       if (ret < 0) {
+                               if (result <= 0)
+                                       return ret;
+                               break;
                        }
-                       ret = snd_pcm_mmap_write1(pcm, vector, count * voices, transfer_writev);
-                       if (ret < 0)
-                               return result > 0 ? result : ret;
                        result += ret;
-                       if ((size_t)ret != count * voices)
+                       if ((size_t)ret != samples)
                                break;
-                       vector += voices;
+                       vector += nvoices;
                }
        }
-       return result;
+       return result * chan->bits_per_sample / 8;
 }
 
-static ssize_t snd_pcm_mmap_read1(snd_pcm_t *pcm, void *data, size_t count, transfer_f transfer)
+ssize_t snd_pcm_mmap_read_areas(snd_pcm_t *pcm, snd_pcm_voice_area_t *voices, size_t samples)
 {
        struct snd_pcm_chan *chan;
        snd_pcm_mmap_control_t *ctrl;
-       size_t frag_size;
        size_t offset = 0;
        size_t result = 0;
        int err;
@@ -562,20 +622,13 @@ static ssize_t snd_pcm_mmap_read1(snd_pcm_t *pcm, void *data, size_t count, tran
        ctrl = chan->mmap_control;
        if (ctrl->status < SND_PCM_STATUS_PREPARED)
                return -EBADFD;
-       frag_size = chan->setup.frag_size;
        if (chan->setup.mode == SND_PCM_MODE_BLOCK) {
-               if (count % frag_size != 0)
+               if (samples % chan->samples_per_frag != 0)
                        return -EINVAL;
        } else {
-               int tmp = snd_pcm_format_size(chan->setup.format.format, chan->setup.format.voices);
-               if (tmp > 0) {
-                       int r = count % tmp;
-                       if (r > 0) {
-                               count -= r;
-                               if (count == 0)
-                                       return -EINVAL;
-                       }
-                }
+               if (ctrl->status == SND_PCM_STATUS_RUNNING &&
+                   chan->mode & SND_PCM_NONBLOCK)
+                       snd_pcm_channel_update(pcm, SND_PCM_CHANNEL_CAPTURE);
        }
        if (ctrl->status == SND_PCM_STATUS_PREPARED &&
            chan->setup.start_mode == SND_PCM_START_DATA) {
@@ -583,10 +636,9 @@ static ssize_t snd_pcm_mmap_read1(snd_pcm_t *pcm, void *data, size_t count, tran
                if (err < 0)
                        return err;
        }
-       if (chan->mode & SND_PCM_NONBLOCK)
-               snd_pcm_channel_update(pcm, SND_PCM_CHANNEL_CAPTURE);
-       while (count > 0) {
-               size_t bytes;
+       while (samples > 0) {
+               ssize_t mmap_offset;
+               size_t samples1;
                int ready = snd_pcm_mmap_capture_ready(pcm);
                if (ready < 0)
                        return ready;
@@ -605,208 +657,135 @@ static ssize_t snd_pcm_mmap_read1(snd_pcm_t *pcm, void *data, size_t count, tran
                                return result > 0 ? result : -EPIPE;
                        assert(snd_pcm_mmap_capture_ready(pcm));
                }
-               if (chan->setup.mode == SND_PCM_MODE_BLOCK) {
-                       size_t frag_data, frag;
-                       frag_data = ctrl->frag_data;
-                       frag = frag_data % chan->setup.frags;
-                       err = transfer(pcm, frag_size * frag, data, offset, frag_size);
-                       if (err < 0) 
-                               return result > 0 ? result : err;
-                       if (ctrl->status == SND_PCM_STATUS_XRUN &&
-                           chan->setup.xrun_mode == SND_PCM_XRUN_DRAIN)
-                               return result > 0 ? result : -EPIPE;
-                       frag_data++;
-                       if (frag_data == chan->setup.frag_boundary) {
-                               ctrl->frag_data = 0;
-                               ctrl->pos_data = 0;
-                       } else {
-                               ctrl->frag_data = frag_data;
-                               ctrl->pos_data += frag_size;
-                       }
-                       bytes = frag_size;
-               } else {
-                       size_t pos_data;
-                       bytes = snd_pcm_mmap_bytes_capture(pcm, count);
-                       pos_data = ctrl->pos_data;
-                       err = transfer(pcm, pos_data % chan->setup.buffer_size, data, offset, bytes);
-                       if (err < 0) 
-                               return result > 0 ? result : err;
-                       if (ctrl->status == SND_PCM_STATUS_XRUN &&
-                           chan->setup.xrun_mode == SND_PCM_XRUN_DRAIN)
-                               return result > 0 ? result : -EPIPE;
-                       pos_data += bytes;
-                       if (pos_data == chan->setup.pos_boundary) {
-                               ctrl->pos_data = 0;
-                               ctrl->frag_data = 0;
-                       } else {
-                               ctrl->pos_data = pos_data;
-                               ctrl->frag_data = pos_data / chan->setup.frags;
-                       }
-               }
-               offset += bytes;
-               count -= bytes;
-               result += bytes;
+               samples1 = snd_pcm_mmap_capture_samples_xfer(pcm, samples);
+               assert(samples1 > 0);
+               mmap_offset = snd_pcm_mmap_samples_offset(pcm, SND_PCM_CHANNEL_CAPTURE);
+               snd_pcm_areas_copy(chan->voices, mmap_offset, voices, offset, chan->setup.format.voices, samples1, chan->setup.format.format);
+               if (ctrl->status == SND_PCM_STATUS_XRUN &&
+                   chan->setup.xrun_mode == SND_PCM_XRUN_DRAIN)
+                       return result > 0 ? result : -EPIPE;
+               snd_pcm_mmap_commit_samples(pcm, SND_PCM_CHANNEL_CAPTURE, samples1);
+               samples -= samples1;
+               offset += samples1;
+               result += samples1;
        }
-       
        return result;
 }
 
-static int transfer_read(snd_pcm_t *pcm, size_t hwoff, void* data, size_t off, size_t size)
+ssize_t snd_pcm_mmap_read_samples(snd_pcm_t *pcm, const void *buffer, size_t samples)
 {
-       struct snd_pcm_chan *chan = &pcm->chan[SND_PCM_CHANNEL_CAPTURE];
-       char *buf = data;
-       unsigned int v, voices;
-#define COPY_LABELS
-#include "plugin/plugin_ops.h"
-#undef COPY_LABELS
-       void *copy;
-       snd_pcm_voice_setup_t *vsetup;
-       int idx;
-       size_t vsize, ssize;
-       idx = copy_index(chan->setup.format.format);
-       if (idx < 0)
-               return idx;
-       copy = copy_labels[idx];
-       voices = chan->setup.format.voices;
-       vsetup = chan->voices_setup;
-       vsize = snd_pcm_format_size(chan->setup.format.format, 1);
-       ssize = vsize * chan->setup.format.voices;
-       hwoff /= ssize;
-       size /= ssize;
-       for (v = 0; v < voices; ++v, ++vsetup) {
-               const char *src;
-               size_t src_step;
-               char *dst;
-               size_t samples = size;
-               if (vsetup->first % 8 != 0 ||
-                   vsetup->step % 8 != 0)
-                       return -EINVAL;
-               src_step = vsetup->step / 8;
-               src = chan->mmap_data + vsetup->addr + (vsetup->first + vsetup->step * hwoff) / 8;
-               dst = buf + off + v * vsize;
-               while (samples-- > 0) {
-                       goto *copy;
-#define COPY_END after
-#include "plugin/plugin_ops.h"
-#undef COPY_END
-               after:
-                       src += src_step;
-                       dst += ssize;
+       struct snd_pcm_chan *chan;
+       unsigned int nvoices;
+       if (!pcm)
+               return -EFAULT;
+       chan = &pcm->chan[SND_PCM_CHANNEL_CAPTURE];
+       if (!chan->open || !chan->valid_setup)
+               return -EBADFD;
+       if (!chan->mmap_data || !chan->mmap_control)
+               return -EBADFD;
+       if (samples > 0 && !buffer)
+               return -EFAULT;
+       nvoices = chan->setup.format.voices;
+       if (!chan->setup.format.interleave && nvoices > 1)
+               return -EINVAL;
+       {
+               snd_pcm_voice_area_t voices[nvoices];
+               unsigned int voice;
+               for (voice = 0; voice < nvoices; ++voice) {
+                       voices[voice].addr = (char*)buffer;
+                       voices[voice].first = chan->sample_width * voice;
+                       voices[voice].step = chan->bits_per_sample;
                }
+               return snd_pcm_mmap_read_areas(pcm, voices, samples);
        }
-       return 0;
 }
 
-ssize_t snd_pcm_mmap_read(snd_pcm_t *pcm, void *buffer, size_t count)
+ssize_t snd_pcm_mmap_read(snd_pcm_t *pcm, void *buffer, size_t bytes)
 {
        struct snd_pcm_chan *chan;
+       unsigned int nvoices;
+       ssize_t samples;
        if (!pcm)
                return -EFAULT;
        chan = &pcm->chan[SND_PCM_CHANNEL_CAPTURE];
-       if (!chan->open || !chan->valid_setup || !chan->valid_voices_setup)
+       if (!chan->open || !chan->valid_setup)
                return -EBADFD;
        if (!chan->mmap_data || !chan->mmap_control)
                return -EBADFD;
-       if (count > 0 && !buffer)
+       if (bytes > 0 && !buffer)
                return -EFAULT;
-       if (!chan->setup.format.interleave && chan->setup.format.voices > 1)
+       nvoices = chan->setup.format.voices;
+       if (!chan->setup.format.interleave && nvoices > 1)
                return -EINVAL;
-       return snd_pcm_mmap_read1(pcm, buffer, count, transfer_read);
-}
-
-static int transfer_readv(snd_pcm_t *pcm, size_t hwoff, void* data, size_t off, size_t size)
-{
-       struct snd_pcm_chan *chan = &pcm->chan[SND_PCM_CHANNEL_CAPTURE];
-       struct iovec *vec = data;
-       unsigned int v, voices;
-#define COPY_LABELS
-#include "plugin/plugin_ops.h"
-#undef COPY_LABELS
-       void *copy;
-       snd_pcm_voice_setup_t *vsetup;
-       int idx;
-       size_t ssize;
-       idx = copy_index(chan->setup.format.format);
-       if (idx < 0)
-               return idx;
-       copy = copy_labels[idx];
-       voices = chan->setup.format.voices;
-       vsetup = chan->voices_setup;
-       ssize = snd_pcm_format_size(chan->setup.format.format, chan->setup.format.voices);
-       hwoff /= ssize;
-       size /= ssize;
-       off /= voices;
-       for (v = 0; v < voices; ++v, ++vsetup, ++vec) {
-               const char *src;
-               size_t src_step;
-               char *dst;
-               size_t samples = size;
-               if (vsetup->first % 8 != 0 ||
-                   vsetup->step % 8 != 0)
-                       return -EINVAL;
-               src_step = vsetup->step / 8;
-               src = chan->mmap_data + vsetup->addr + (vsetup->first + vsetup->step * hwoff) / 8;
-               dst = vec->iov_base + off;
-               while (samples-- > 0) {
-                       goto *copy;
-#define COPY_END after
-#include "plugin/plugin_ops.h"
-#undef COPY_END
-               after:
-                       src += src_step;
-                       dst += ssize;
-               }
-       }
-       return 0;
+       samples = bytes * 8 / chan->bits_per_sample;
+       samples = snd_pcm_mmap_read_samples(pcm, buffer, samples);
+       if (samples <= 0)
+               return samples;
+       return samples * chan->bits_per_sample / 8;
 }
 
 ssize_t snd_pcm_mmap_readv(snd_pcm_t *pcm, const struct iovec *vector, unsigned long vcount)
 {
        struct snd_pcm_chan *chan;
        size_t result = 0;
-       unsigned int b;
+       unsigned int nvoices;
        if (!pcm)
                return -EFAULT;
        chan = &pcm->chan[SND_PCM_CHANNEL_CAPTURE];
-       if (!chan->open || !chan->valid_setup || !chan->valid_voices_setup)
+       if (!chan->open || !chan->valid_setup)
                return -EBADFD;
        if (!chan->mmap_data || !chan->mmap_control)
                return -EBADFD;
        if (vcount > 0 && !vector)
                return -EFAULT;
+       nvoices = chan->setup.format.voices;
        if (chan->setup.format.interleave) {
+               unsigned int b;
                for (b = 0; b < vcount; b++) {
-                       int ret;
-                       ret = snd_pcm_mmap_read1(pcm, vector[b].iov_base, vector[b].iov_len, transfer_write);
-                       if (ret < 0)
-                               return result > 0 ? result : ret;
+                       ssize_t ret;
+                       size_t samples = vector[b].iov_len * 8 / chan->bits_per_sample;
+                       ret = snd_pcm_mmap_read_samples(pcm, vector[b].iov_base, samples);
+                       if (ret < 0) {
+                               if (result <= 0)
+                                       return ret;
+                               break;
+                       }
                        result += ret;
                }
        } else {
-               unsigned int voices = chan->setup.format.voices;
+               snd_pcm_voice_area_t voices[nvoices];
                unsigned long bcount;
-               if (vcount % voices)
+               unsigned int b;
+               if (vcount % nvoices)
                        return -EINVAL;
-               bcount = vcount / voices;
+               bcount = vcount / nvoices;
                for (b = 0; b < bcount; b++) {
                        unsigned int v;
-                       int ret;
-                       size_t count = 0;
-                       count = vector[0].iov_len;
-                       for (v = 0; v < voices; ++v) {
-                               if (vector[v].iov_len != count)
+                       ssize_t ret;
+                       size_t bytes = 0;
+                       size_t samples;
+                       bytes = vector[0].iov_len;
+                       for (v = 0; v < nvoices; ++v) {
+                               if (vector[v].iov_len != bytes)
                                        return -EINVAL;
+                               voices[v].addr = vector[v].iov_base;
+                               voices[v].first = 0;
+                               voices[v].step = chan->sample_width;
+                       }
+                       samples = bytes * 8 / chan->sample_width;
+                       ret = snd_pcm_mmap_read_areas(pcm, voices, samples);
+                       if (ret < 0) {
+                               if (result <= 0)
+                                       return ret;
+                               break;
                        }
-                       ret = snd_pcm_mmap_read1(pcm, (void *) vector, count * voices, transfer_readv);
-                       if (ret < 0)
-                               return result > 0 ? result : ret;
                        result += ret;
-                       if ((size_t)ret != count * voices)
+                       if ((size_t)ret != samples)
                                break;
-                       vector += voices;
+                       vector += nvoices;
                }
        }
-       return result;
+       return result * chan->bits_per_sample / 8;
 }
 
 static void *playback_mmap(void *d)
@@ -854,7 +833,7 @@ static void *playback_mmap(void *d)
                }
 
                frag = control->frag_io;
-               if (snd_pcm_mmap_playback_frags_used(pcm) <= 0) {
+               if (snd_pcm_mmap_playback_frags_used(chan) <= 0) {
                        fprintf(stderr, "underrun\n");
                        usleep(10000);
                        continue;
@@ -934,7 +913,7 @@ static void *capture_mmap(void *d)
                }
 
                frag = control->frag_io;
-               if (snd_pcm_mmap_capture_frags_free(pcm) <= 0) {
+               if (snd_pcm_mmap_capture_frags_free(chan) <= 0) {
                        fprintf(stderr, "overrun\n");
                        usleep(10000);
                        continue;
@@ -1003,6 +982,36 @@ int snd_pcm_mmap_control(snd_pcm_t *pcm, int channel, snd_pcm_mmap_control_t **c
        return 0;
 }
 
+int snd_pcm_mmap_get_areas(snd_pcm_t *pcm, int channel, snd_pcm_voice_area_t *areas)
+{
+       struct snd_pcm_chan *chan;
+       snd_pcm_voice_setup_t s;
+       snd_pcm_voice_area_t *a, *ap;
+       unsigned int voice;
+       int err;
+       if (!pcm)
+               return -EFAULT;
+       if (channel < 0 || channel > 1)
+               return -EINVAL;
+       chan = &pcm->chan[channel];
+       if (!chan->open || !chan->valid_setup || !chan->mmap_data)
+               return -EBADFD;
+       a = calloc(chan->setup.format.voices, sizeof(*areas));
+       for (voice = 0, ap = a; voice < chan->setup.format.voices; ++voice, ++ap) {
+               s.voice = voice;
+               err = snd_pcm_voice_setup(pcm, channel, &s);
+               if (err < 0) {
+                       free(a);
+                       return err;
+               }
+               if (areas)
+                       areas[voice] = s.area;
+               *ap = s.area;
+       }
+       chan->voices = a;
+       return 0;
+}
+
 int snd_pcm_mmap_data(snd_pcm_t *pcm, int channel, void **data)
 {
        struct snd_pcm_chan *chan;
@@ -1054,7 +1063,9 @@ int snd_pcm_mmap_data(snd_pcm_t *pcm, int channel, void **data)
        }
        chan->mmap_data = *data;
        chan->mmap_data_size = bsize;
-       snd_pcm_all_voices_setup(pcm, channel, NULL);
+       err = snd_pcm_mmap_get_areas(pcm, channel, NULL);
+       if (err < 0)
+               return err;
        return 0;
 }
 
@@ -1125,6 +1136,7 @@ int snd_pcm_munmap_data(snd_pcm_t *pcm, int channel)
                if ((err = pcm->ops->munmap_data(pcm, channel, chan->mmap_data, chan->mmap_data_size)) < 0)
                        return err;
        }
+       free(chan->voices);
        chan->mmap_data = 0;
        chan->mmap_data_size = 0;
        return 0;
index 953e06dc25d32696035d9d851803013e609d09f5..fd673feacfc435074737b62790521671c2820df9 100644 (file)
@@ -438,6 +438,7 @@ static int snd_pcm_plug_channel_params(snd_pcm_t *pcm, snd_pcm_channel_params_t
        }
 
        /* compute right sizes */
+       slave_params.buffer_size = snd_pcm_plug_slave_size(pcm, channel, slave_params.buffer_size);
        slave_params.frag_size = snd_pcm_plug_slave_size(pcm, channel, slave_params.frag_size);
        if (params->mode == SND_PCM_MODE_STREAM) {
                slave_params.buf.stream.bytes_fill_max = snd_pcm_plug_slave_size(pcm, channel, slave_params.buf.stream.bytes_fill_max);
@@ -471,7 +472,7 @@ static int snd_pcm_plug_channel_setup(snd_pcm_t *pcm, snd_pcm_channel_setup_t *s
        setup->buffer_size = snd_pcm_plug_client_size(pcm, setup->channel, setup->buffer_size);
        setup->frag_size = snd_pcm_plug_client_size(pcm, setup->channel, setup->frag_size);
        /* FIXME: it may overflow */
-       setup->pos_boundary = snd_pcm_plug_client_size(pcm, setup->channel, setup->pos_boundary);
+       setup->byte_boundary = snd_pcm_plug_client_size(pcm, setup->channel, setup->byte_boundary);
        if (setup->mode == SND_PCM_MODE_STREAM) {
                setup->buf.stream.bytes_min = snd_pcm_plug_client_size(pcm, setup->channel, setup->buf.stream.bytes_min);
                setup->buf.stream.bytes_align = snd_pcm_plug_client_size(pcm, setup->channel, setup->buf.stream.bytes_align);
@@ -500,8 +501,8 @@ static int snd_pcm_plug_channel_status(snd_pcm_t *pcm, snd_pcm_channel_status_t
                return 0;
 
        /* FIXME: may overflow */
-       status->pos_io = snd_pcm_plug_client_size(pcm, status->channel, status->pos_io);
-       status->pos_data = snd_pcm_plug_client_size(pcm, status->channel, status->pos_data);
+       status->byte_io = snd_pcm_plug_client_size(pcm, status->channel, status->byte_io);
+       status->byte_data = snd_pcm_plug_client_size(pcm, status->channel, status->byte_data);
        status->bytes_used = snd_pcm_plug_client_size(pcm, status->channel, status->bytes_used);
        status->bytes_free = snd_pcm_plug_client_size(pcm, status->channel, status->bytes_free);
        return 0;       
@@ -605,8 +606,8 @@ static int snd_pcm_plug_voice_setup(snd_pcm_t *pcm, int channel, snd_pcm_voice_s
         memset(setup, 0, sizeof(*setup));
         setup->voice = voice;
        chan = &pcm->chan[channel];
-       if (!chan->mmap_control) {
-               setup->addr = -1;
+       if (!chan->mmap_data) {
+               setup->area.addr = 0;
                return 0;
        }
        if (voice >= chan->setup.format.voices)
@@ -617,14 +618,14 @@ static int snd_pcm_plug_voice_setup(snd_pcm_t *pcm, int channel, snd_pcm_voice_s
                 return width;
        size = chan->mmap_data_size;
        if (chan->setup.format.interleave) {
-                setup->addr = 0;
-                setup->first = voice * width;
-                setup->step = chan->setup.format.voices * width;
+                setup->area.addr = chan->mmap_data;
+                setup->area.first = chan->sample_width;
+                setup->area.step = chan->bits_per_sample;
         } else {
                 size /= chan->setup.format.voices;
-                setup->addr = setup->voice * size;
-                setup->first = 0;
-                setup->step = width;
+                setup->area.addr = chan->mmap_data + setup->voice * size;
+                setup->area.first = 0;
+                setup->area.step = width;
        }
        return 0;
 }
index f85e42a1d27ac55e5c9ec12b85b599d66d057247..fa8df67c9ac38a6ca9c3cd0e553cb4d3fb722c8a 100644 (file)
@@ -231,17 +231,17 @@ static void adpcm_decode(snd_pcm_plugin_t *plugin,
                adpcm_voice_t *state;
                if (!src_voices[voice].enabled) {
                        if (dst_voices[voice].wanted)
-                               snd_pcm_plugin_silence_voice(plugin, &dst_voices[voice], samples);
+                               snd_pcm_area_silence(&dst_voices[voice].area, 0, samples, plugin->dst_format.format);
                        dst_voices[voice].enabled = 0;
                        continue;
                }
                dst_voices[voice].enabled = 1;
-               src = src_voices[voice].addr + src_voices[voice].first / 8;
-               srcbit = src_voices[voice].first % 8;
-               dst = dst_voices[voice].addr + dst_voices[voice].first / 8;
-               src_step = src_voices[voice].step / 8;
-               srcbit_step = src_voices[voice].step % 8;
-               dst_step = dst_voices[voice].step / 8;
+               src = src_voices[voice].area.addr + src_voices[voice].area.first / 8;
+               srcbit = src_voices[voice].area.first % 8;
+               dst = dst_voices[voice].area.addr + dst_voices[voice].area.first / 8;
+               src_step = src_voices[voice].area.step / 8;
+               srcbit_step = src_voices[voice].area.step % 8;
+               dst_step = dst_voices[voice].area.step / 8;
                state = &data->voices[voice];
                samples1 = samples;
                while (samples1-- > 0) {
@@ -290,17 +290,17 @@ static void adpcm_encode(snd_pcm_plugin_t *plugin,
                adpcm_voice_t *state;
                if (!src_voices[voice].enabled) {
                        if (dst_voices[voice].wanted)
-                               snd_pcm_plugin_silence_voice(plugin, &dst_voices[voice], samples);
+                               snd_pcm_area_silence(&dst_voices[voice].area, 0, samples, plugin->dst_format.format);
                        dst_voices[voice].enabled = 0;
                        continue;
                }
                dst_voices[voice].enabled = 1;
-               src = src_voices[voice].addr + src_voices[voice].first / 8;
-               dst = dst_voices[voice].addr + dst_voices[voice].first / 8;
-               dstbit = dst_voices[voice].first % 8;
-               src_step = src_voices[voice].step / 8;
-               dst_step = dst_voices[voice].step / 8;
-               dstbit_step = dst_voices[voice].step % 8;
+               src = src_voices[voice].area.addr + src_voices[voice].area.first / 8;
+               dst = dst_voices[voice].area.addr + dst_voices[voice].area.first / 8;
+               dstbit = dst_voices[voice].area.first % 8;
+               src_step = src_voices[voice].area.step / 8;
+               dst_step = dst_voices[voice].area.step / 8;
+               dstbit_step = dst_voices[voice].area.step % 8;
                state = &data->voices[voice];
                samples1 = samples;
                while (samples1-- > 0) {
@@ -340,16 +340,16 @@ static ssize_t adpcm_transfer(snd_pcm_plugin_t *plugin,
                return 0;
        for (voice = 0; voice < plugin->src_format.voices; voice++) {
                if (plugin->src_format.format == SND_PCM_SFMT_IMA_ADPCM) {
-                       if (src_voices[voice].first % 4 != 0 ||
-                           src_voices[voice].step % 4 != 0 ||
-                           dst_voices[voice].first % 8 != 0 ||
-                           dst_voices[voice].step % 8 != 0)
+                       if (src_voices[voice].area.first % 4 != 0 ||
+                           src_voices[voice].area.step % 4 != 0 ||
+                           dst_voices[voice].area.first % 8 != 0 ||
+                           dst_voices[voice].area.step % 8 != 0)
                                return -EINVAL;
                } else {
-                       if (src_voices[voice].first % 8 != 0 ||
-                           src_voices[voice].step % 8 != 0 ||
-                           dst_voices[voice].first % 4 != 0 ||
-                           dst_voices[voice].step % 4 != 0)
+                       if (src_voices[voice].area.first % 8 != 0 ||
+                           src_voices[voice].area.step % 8 != 0 ||
+                           dst_voices[voice].area.first % 4 != 0 ||
+                           dst_voices[voice].area.step % 4 != 0)
                                return -EINVAL;
                }
        }
index fce035bd1d226be5ec9944c60df0e67ba71a7a0b..27af3e6bab78258cc2fe4189557e6ffe89eba9b2 100644 (file)
@@ -161,15 +161,15 @@ static void alaw_decode(snd_pcm_plugin_t *plugin,
                size_t samples1;
                if (!src_voices[voice].enabled) {
                        if (dst_voices[voice].wanted)
-                               snd_pcm_plugin_silence_voice(plugin, &dst_voices[voice], samples);
+                               snd_pcm_area_silence(&dst_voices[voice].area, 0, samples, plugin->dst_format.format);
                        dst_voices[voice].enabled = 0;
                        continue;
                }
                dst_voices[voice].enabled = 1;
-               src = src_voices[voice].addr + src_voices[voice].first / 8;
-               dst = dst_voices[voice].addr + dst_voices[voice].first / 8;
-               src_step = src_voices[voice].step / 8;
-               dst_step = dst_voices[voice].step / 8;
+               src = src_voices[voice].area.addr + src_voices[voice].area.first / 8;
+               dst = dst_voices[voice].area.addr + dst_voices[voice].area.first / 8;
+               src_step = src_voices[voice].area.step / 8;
+               dst_step = dst_voices[voice].area.step / 8;
                samples1 = samples;
                while (samples1-- > 0) {
                        signed short sample = alaw2linear(*src);
@@ -204,15 +204,15 @@ static void alaw_encode(snd_pcm_plugin_t *plugin,
                size_t samples1;
                if (!src_voices[voice].enabled) {
                        if (dst_voices[voice].wanted)
-                               snd_pcm_plugin_silence_voice(plugin, &dst_voices[voice], samples);
+                               snd_pcm_area_silence(&dst_voices[voice].area, 0, samples, plugin->dst_format.format);
                        dst_voices[voice].enabled = 0;
                        continue;
                }
                dst_voices[voice].enabled = 1;
-               src = src_voices[voice].addr + src_voices[voice].first / 8;
-               dst = dst_voices[voice].addr + dst_voices[voice].first / 8;
-               src_step = src_voices[voice].step / 8;
-               dst_step = dst_voices[voice].step / 8;
+               src = src_voices[voice].area.addr + src_voices[voice].area.first / 8;
+               dst = dst_voices[voice].area.addr + dst_voices[voice].area.first / 8;
+               src_step = src_voices[voice].area.step / 8;
+               dst_step = dst_voices[voice].area.step / 8;
                samples1 = samples;
                while (samples1-- > 0) {
                        goto *get;
@@ -240,11 +240,11 @@ static ssize_t alaw_transfer(snd_pcm_plugin_t *plugin,
        if (samples == 0)
                return 0;
        for (voice = 0; voice < plugin->src_format.voices; voice++) {
-               if (src_voices[voice].first % 8 != 0 || 
-                   src_voices[voice].step % 8 != 0)
+               if (src_voices[voice].area.first % 8 != 0 || 
+                   src_voices[voice].area.step % 8 != 0)
                        return -EINVAL;
-               if (dst_voices[voice].first % 8 != 0 || 
-                   dst_voices[voice].step % 8 != 0)
+               if (dst_voices[voice].area.first % 8 != 0 || 
+                   dst_voices[voice].area.step % 8 != 0)
                        return -EINVAL;
        }
        data = (alaw_t *)plugin->extra_data;
index 7c83e967db1c960f0257525e5bc394b2a324e6b0..e463ebd4a434f41a933a3465a64305e38c7bb8af 100644 (file)
@@ -68,12 +68,12 @@ static ssize_t block_transfer(snd_pcm_plugin_t *plugin,
                        return result;
                count = plugin->src_format.voices;
                if (plugin->src_format.interleave) {
-                       result = snd_pcm_write(data->slave, src_voices->addr, result);
+                       result = snd_pcm_write(data->slave, src_voices->area.addr, result);
                } else {
                        result /= count;
                        for (voice = 0; voice < count; voice++) {
                                if (src_voices[voice].enabled)
-                                       vec[voice].iov_base = src_voices[voice].addr;
+                                       vec[voice].iov_base = src_voices[voice].area.addr;
                                else
                                        vec[voice].iov_base = 0;
                                vec[voice].iov_len = result;
@@ -90,7 +90,7 @@ static ssize_t block_transfer(snd_pcm_plugin_t *plugin,
                        return result;
                count = plugin->dst_format.voices;
                if (plugin->dst_format.interleave) {
-                       result = snd_pcm_read(data->slave, dst_voices->addr, result);
+                       result = snd_pcm_read(data->slave, dst_voices->area.addr, result);
                        for (voice = 0; voice < count; voice++) {
                                dst_voices[voice].enabled = src_voices[voice].enabled;
                        }
@@ -99,7 +99,7 @@ static ssize_t block_transfer(snd_pcm_plugin_t *plugin,
                        for (voice = 0; voice < count; voice++) {
                                dst_voices[voice].enabled = src_voices[voice].enabled;
                                if (dst_voices[voice].enabled)
-                                       vec[voice].iov_base = dst_voices[voice].addr;
+                                       vec[voice].iov_base = dst_voices[voice].area.addr;
                                else
                                        vec[voice].iov_base = 0;
                                vec[voice].iov_len = result;
index 88a61d7526e600c4b02a99124c29f4149460f90e..c985071387fc69fee199d2fd654cd0b25798d724 100644 (file)
 #include "../pcm_local.h"
 #endif
 
-typedef struct copy_private_data {
-       int copy;
-} copy_t;
-
-static void copy(snd_pcm_plugin_t *plugin,
-                const snd_pcm_plugin_voice_t *src_voices,
-                snd_pcm_plugin_voice_t *dst_voices,
-                size_t samples)
-{
-#define COPY_LABELS
-#include "plugin_ops.h"
-#undef COPY_LABELS
-       copy_t *data = (copy_t *)plugin->extra_data;
-       void *copy = copy_labels[data->copy];
-       int voice;
-       int nvoices = plugin->src_format.voices;
-       for (voice = 0; voice < nvoices; ++voice) {
-               char *src;
-               char *dst;
-               int src_step, dst_step;
-               size_t samples1;
-               if (!src_voices[voice].enabled) {
-                       if (dst_voices[voice].wanted)
-                               snd_pcm_plugin_silence_voice(plugin, &dst_voices[voice], samples);
-                       dst_voices[voice].enabled = 0;
-                       continue;
-               }
-               dst_voices[voice].enabled = 1;
-               src = src_voices[voice].addr + src_voices[voice].first / 8;
-               dst = dst_voices[voice].addr + dst_voices[voice].first / 8;
-               src_step = src_voices[voice].step / 8;
-               dst_step = dst_voices[voice].step / 8;
-               samples1 = samples;
-               while (samples1-- > 0) {
-                       goto *copy;
-#define COPY_END after
-#include "plugin_ops.h"
-#undef COPY_END
-               after:
-                       src += src_step;
-                       dst += dst_step;
-               }
-       }
-}
-
 static ssize_t copy_transfer(snd_pcm_plugin_t *plugin,
                             const snd_pcm_plugin_voice_t *src_voices,
                             snd_pcm_plugin_voice_t *dst_voices,
                             size_t samples)
 {
-       copy_t *data;
        unsigned int voice;
+       unsigned int nvoices;
 
        if (plugin == NULL || src_voices == NULL || dst_voices == NULL)
                return -EFAULT;
-       data = (copy_t *)plugin->extra_data;
        if (samples == 0)
                return 0;
-       for (voice = 0; voice < plugin->src_format.voices; voice++) {
-               if (src_voices[voice].first % 8 != 0 || 
-                   src_voices[voice].step % 8 != 0)
+       nvoices = plugin->src_format.voices;
+       for (voice = 0; voice < nvoices; voice++) {
+               if (src_voices[voice].area.first % 8 != 0 || 
+                   src_voices[voice].area.step % 8 != 0)
                        return -EINVAL;
-               if (dst_voices[voice].first % 8 != 0 || 
-                   dst_voices[voice].step % 8 != 0)
+               if (dst_voices[voice].area.first % 8 != 0 || 
+                   dst_voices[voice].area.step % 8 != 0)
                        return -EINVAL;
+               if (!src_voices->enabled) {
+                       if (dst_voices->wanted)
+                               snd_pcm_area_silence(&dst_voices->area, 0, samples, plugin->dst_format.format);
+                       dst_voices->enabled = 0;
+                       continue;
+               }
+               dst_voices[voice].enabled = 1;
+               snd_pcm_area_copy(&src_voices->area, 0, &dst_voices->area, 0, samples, plugin->src_format.format);
        }
-       copy(plugin, src_voices, dst_voices, samples);
        return samples;
 }
 
-int copy_index(int format)
-{
-       int size = snd_pcm_format_physical_width(format);
-       switch (size) {
-       case 8:
-               return 0;
-       case 16:
-               return 1;
-       case 32:
-               return 2;
-       case 64:
-               return 3;
-       default:
-               return -EINVAL;
-       }
-}
-       
 int snd_pcm_plugin_build_copy(snd_pcm_plugin_handle_t *handle,
                              int channel,
                              snd_pcm_format_t *format,
                              snd_pcm_plugin_t **r_plugin)
 {
        int err;
-       struct copy_private_data *data;
        snd_pcm_plugin_t *plugin;
-       int copy;
+       int width;
 
        if (r_plugin == NULL)
                return -EFAULT;
        *r_plugin = NULL;
 
-       copy = copy_index(format->format);
-       if (copy < 0)
+       width = snd_pcm_format_physical_width(format->format);
+       if (width < 0)
                return -EINVAL;
 
        err = snd_pcm_plugin_build(handle, channel,
                                   "copy",
                                   format,
                                   format,
-                                  sizeof(copy_t),
+                                  0,
                                   &plugin);
        if (err < 0)
                return err;
-       data = (copy_t *)plugin->extra_data;
-       data->copy = copy;
        plugin->transfer = copy_transfer;
        *r_plugin = plugin;
        return 0;
index 2ba444bf0680cff1ce7df83f824a1fbf757d208b..12974e35c2ddf873bec813bbad6a2fc2f92847fa 100644 (file)
@@ -63,15 +63,15 @@ static void convert(snd_pcm_plugin_t *plugin,
                size_t samples1;
                if (!src_voices[voice].enabled) {
                        if (dst_voices[voice].wanted)
-                               snd_pcm_plugin_silence_voice(plugin, &dst_voices[voice], samples);
+                               snd_pcm_area_silence(&dst_voices[voice].area, 0, samples, plugin->dst_format.format);
                        dst_voices[voice].enabled = 0;
                        continue;
                }
                dst_voices[voice].enabled = 1;
-               src = src_voices[voice].addr + src_voices[voice].first / 8;
-               dst = dst_voices[voice].addr + dst_voices[voice].first / 8;
-               src_step = src_voices[voice].step / 8;
-               dst_step = dst_voices[voice].step / 8;
+               src = src_voices[voice].area.addr + src_voices[voice].area.first / 8;
+               dst = dst_voices[voice].area.addr + dst_voices[voice].area.first / 8;
+               src_step = src_voices[voice].area.step / 8;
+               dst_step = dst_voices[voice].area.step / 8;
                samples1 = samples;
                while (samples1-- > 0) {
                        goto *conv;
@@ -99,11 +99,11 @@ static ssize_t linear_transfer(snd_pcm_plugin_t *plugin,
        if (samples == 0)
                return 0;
        for (voice = 0; voice < plugin->src_format.voices; voice++) {
-               if (src_voices[voice].first % 8 != 0 || 
-                   src_voices[voice].step % 8 != 0)
+               if (src_voices[voice].area.first % 8 != 0 || 
+                   src_voices[voice].area.step % 8 != 0)
                        return -EINVAL;
-               if (dst_voices[voice].first % 8 != 0 || 
-                   dst_voices[voice].step % 8 != 0)
+               if (dst_voices[voice].area.first % 8 != 0 || 
+                   dst_voices[voice].area.step % 8 != 0)
                        return -EINVAL;
        }
        convert(plugin, src_voices, dst_voices, samples);
index c1751729298eca9bc28924d08b4797115558f443..ccc6b3b8aaee2b60a3f9db6e745449aead3c3df0 100644 (file)
@@ -38,9 +38,7 @@ typedef struct mmap_private_data {
        snd_pcm_mmap_control_t *control;
        void *buffer;
        unsigned int frag;
-       size_t samples_frag_size;
        char *silence;
-       snd_pcm_plugin_voice_t voices[0];
 } mmap_t;
 
 
@@ -50,22 +48,22 @@ static int mmap_src_voices(snd_pcm_plugin_t *plugin,
 {
        mmap_t *data;
        unsigned int voice;
-        snd_pcm_plugin_voice_t *dv, *sv;
+        snd_pcm_plugin_voice_t *sv;
+       snd_pcm_voice_area_t *dv;
        struct snd_pcm_chan *chan;
        snd_pcm_channel_setup_t *setup;
        snd_pcm_mmap_control_t *ctrl;
        int frag, f;
-       struct pollfd pfd;
        int ready;
 
        if (plugin == NULL || voices == NULL)
                return -EINVAL;
        data = (mmap_t *)plugin->extra_data;
-       if (samples != data->samples_frag_size)
+       ctrl = data->control;
+       chan = &data->slave->chan[plugin->channel];
+       if (samples != chan->samples_per_frag)
                return -EINVAL;
 
-       ctrl = data->control;
-       chan = &plugin->handle->chan[plugin->channel];
        setup = &chan->setup;
        if (ctrl->status < SND_PCM_STATUS_PREPARED)
                return -EBADFD;
@@ -74,11 +72,12 @@ static int mmap_src_voices(snd_pcm_plugin_t *plugin,
        if (ready < 0)
                return ready;
        if (!ready) {
+               struct pollfd pfd;
                if (ctrl->status != SND_PCM_STATUS_RUNNING)
                        return -EPIPE;
                if (chan->mode & SND_PCM_NONBLOCK)
                        return -EAGAIN;
-               pfd.fd = snd_pcm_file_descriptor(plugin->handle, plugin->channel);
+               pfd.fd = snd_pcm_file_descriptor(data->slave, plugin->channel);
                pfd.events = POLLOUT | POLLERR;
                ready = poll(&pfd, 1, 10000);
                if (ready < 0)
@@ -90,16 +89,16 @@ static int mmap_src_voices(snd_pcm_plugin_t *plugin,
        frag = ctrl->frag_data;
        f = frag % setup->frags;
 
-       dv = data->voices;
        sv = plugin->src_voices;
+       dv = chan->voices;
        *voices = sv;
        for (voice = 0; voice < plugin->src_format.voices; ++voice) {
                sv->enabled = 1;
                sv->wanted = !data->silence[voice * setup->frags + f];
                sv->aptr = 0;
-               sv->addr = dv->addr + (dv->step * data->samples_frag_size * f) / 8;
-               sv->first = dv->first;
-               sv->step = dv->step;
+               sv->area.addr = dv->addr + (dv->step * chan->samples_per_frag * f) / 8;
+               sv->area.first = dv->first;
+               sv->area.step = dv->step;
                ++sv;
                ++dv;
        }
@@ -114,21 +113,21 @@ static int mmap_dst_voices(snd_pcm_plugin_t *plugin,
        mmap_t *data;
        int err;
        unsigned int voice;
-        snd_pcm_plugin_voice_t *dv, *sv;
+        snd_pcm_plugin_voice_t *dv;
+       snd_pcm_voice_area_t *sv;
        struct snd_pcm_chan *chan;
        snd_pcm_channel_setup_t *setup;
        snd_pcm_mmap_control_t *ctrl;
        int frag, f;
-       struct pollfd pfd;
        int ready;
 
        if (plugin == NULL || voices == NULL)
                return -EINVAL;
        data = (mmap_t *)plugin->extra_data;
-       if (samples != data->samples_frag_size)
+       chan = &data->slave->chan[plugin->channel];
+       if (samples != chan->samples_per_frag)
                return -EINVAL;
 
-       chan = &plugin->handle->chan[plugin->channel];
        setup = &chan->setup;
        ctrl = data->control;
        if (ctrl->status < SND_PCM_STATUS_PREPARED)
@@ -143,17 +142,12 @@ static int mmap_dst_voices(snd_pcm_plugin_t *plugin,
        if (ready < 0)
                return ready;
        if (!ready) {
-               if (ctrl->status == SND_PCM_STATUS_PREPARED &&
-                   chan->setup.start_mode == SND_PCM_START_FULL) {
-                       err = snd_pcm_channel_go(data->slave, plugin->channel);
-                       if (err < 0)
-                               return err;
-               }
+               struct pollfd pfd;
                if (ctrl->status != SND_PCM_STATUS_RUNNING)
                        return -EPIPE;
                if (chan->mode & SND_PCM_NONBLOCK)
                        return -EAGAIN;
-               pfd.fd = snd_pcm_file_descriptor(plugin->handle, plugin->channel);
+               pfd.fd = snd_pcm_file_descriptor(data->slave, plugin->channel);
                pfd.events = POLLIN | POLLERR;
                ready = poll(&pfd, 1, 10000);
                if (ready < 0)
@@ -166,16 +160,16 @@ static int mmap_dst_voices(snd_pcm_plugin_t *plugin,
        frag = ctrl->frag_data;
        f = frag % setup->frags;
 
-       sv = data->voices;
+       sv = chan->voices;
        dv = plugin->dst_voices;
        *voices = dv;
        for (voice = 0; voice < plugin->dst_format.voices; ++voice) {
                dv->enabled = 1;
                dv->wanted = 0;
                dv->aptr = 0;
-               dv->addr = sv->addr + (sv->step * data->samples_frag_size * f) / 8;
-               dv->first = sv->first;
-               dv->step = sv->step;
+               dv->area.addr = sv->addr + (sv->step * chan->samples_per_frag * f) / 8;
+               dv->area.first = sv->first;
+               dv->area.step = sv->step;
                ++sv;
                ++dv;
        }
@@ -218,14 +212,7 @@ static ssize_t mmap_playback_transfer(snd_pcm_plugin_t *plugin,
                        data->silence[voice * setup->frags + f] = 0;
        }
 
-       frag++;
-       if (frag == setup->frag_boundary) {
-               ctrl->frag_data = 0;
-               ctrl->pos_data = 0;
-       } else {
-               ctrl->frag_data = frag;
-               ctrl->pos_data += setup->frag_size;
-       }
+       snd_pcm_mmap_commit_samples(data->slave, SND_PCM_CHANNEL_PLAYBACK, samples);
        if (ctrl->status == SND_PCM_STATUS_PREPARED &&
            (chan->setup.start_mode == SND_PCM_START_DATA ||
             (chan->setup.start_mode == SND_PCM_START_FULL &&
@@ -262,14 +249,7 @@ static ssize_t mmap_capture_transfer(snd_pcm_plugin_t *plugin,
        setup = &data->slave->chan[SND_PCM_CHANNEL_CAPTURE].setup;
 
        /* FIXME: not here the increment */
-       frag++;
-       if (frag == setup->frag_boundary) {
-               ctrl->frag_data = 0;
-               ctrl->pos_data = 0;
-       } else {
-               ctrl->frag_data = frag;
-               ctrl->pos_data += setup->frag_size;
-       }
+       snd_pcm_mmap_commit_samples(data->slave, SND_PCM_CHANNEL_CAPTURE, samples);
        return samples;
 }
  
@@ -285,8 +265,6 @@ static int mmap_action(snd_pcm_plugin_t *plugin,
        if (action == INIT) {
                snd_pcm_channel_setup_t *setup;
                int result;
-               unsigned int voice;
-               snd_pcm_plugin_voice_t *v;
 
                if (data->control)
                        snd_pcm_munmap(data->slave, plugin->channel);
@@ -294,22 +272,7 @@ static int mmap_action(snd_pcm_plugin_t *plugin,
                if (result < 0)
                        return result;
                setup = &data->slave->chan[plugin->channel].setup;
-               data->samples_frag_size = setup->frag_size / snd_pcm_format_size(setup->format.format, setup->format.voices);
 
-               v = data->voices;
-               for (voice = 0; voice < setup->format.voices; ++voice) {
-                       snd_pcm_voice_setup_t vsetup;
-                       
-                       vsetup.voice = voice;
-                       if ((result = snd_pcm_voice_setup(data->slave, plugin->channel, &vsetup)) < 0)
-                               return result;
-                       if (vsetup.addr < 0)
-                               return -EBADFD;
-                       v->addr = data->buffer + vsetup.addr;
-                       v->first = vsetup.first;
-                       v->step = vsetup.step;
-                       v++;
-               }
                if (plugin->channel == SND_PCM_CHANNEL_PLAYBACK) {
                        data->silence = malloc(setup->frags * setup->format.voices);
                        memset(data->silence, 0, setup->frags * setup->format.voices);
index 4e8964abe82ff507268e9a38a649956cf91301ba..ef0fdcffc38760efd2c1d7a81bbc132249f441f3 100644 (file)
@@ -177,15 +177,15 @@ static void mulaw_decode(snd_pcm_plugin_t *plugin,
                size_t samples1;
                if (!src_voices[voice].enabled) {
                        if (dst_voices[voice].wanted)
-                               snd_pcm_plugin_silence_voice(plugin, &dst_voices[voice], samples);
+                               snd_pcm_area_silence(&dst_voices[voice].area, 0, samples, plugin->dst_format.format);
                        dst_voices[voice].enabled = 0;
                        continue;
                }
                dst_voices[voice].enabled = 1;
-               src = src_voices[voice].addr + src_voices[voice].first / 8;
-               dst = dst_voices[voice].addr + dst_voices[voice].first / 8;
-               src_step = src_voices[voice].step / 8;
-               dst_step = dst_voices[voice].step / 8;
+               src = src_voices[voice].area.addr + src_voices[voice].area.first / 8;
+               dst = dst_voices[voice].area.addr + dst_voices[voice].area.first / 8;
+               src_step = src_voices[voice].area.step / 8;
+               dst_step = dst_voices[voice].area.step / 8;
                samples1 = samples;
                while (samples1-- > 0) {
                        signed short sample = ulaw2linear(*src);
@@ -220,15 +220,15 @@ static void mulaw_encode(snd_pcm_plugin_t *plugin,
                size_t samples1;
                if (!src_voices[voice].enabled) {
                        if (dst_voices[voice].wanted)
-                               snd_pcm_plugin_silence_voice(plugin, &dst_voices[voice], samples);
+                               snd_pcm_area_silence(&dst_voices[voice].area, 0, samples, plugin->dst_format.format);
                        dst_voices[voice].enabled = 0;
                        continue;
                }
                dst_voices[voice].enabled = 1;
-               src = src_voices[voice].addr + src_voices[voice].first / 8;
-               dst = dst_voices[voice].addr + dst_voices[voice].first / 8;
-               src_step = src_voices[voice].step / 8;
-               dst_step = dst_voices[voice].step / 8;
+               src = src_voices[voice].area.addr + src_voices[voice].area.first / 8;
+               dst = dst_voices[voice].area.addr + dst_voices[voice].area.first / 8;
+               src_step = src_voices[voice].area.step / 8;
+               dst_step = dst_voices[voice].area.step / 8;
                samples1 = samples;
                while (samples1-- > 0) {
                        goto *get;
@@ -256,11 +256,11 @@ static ssize_t mulaw_transfer(snd_pcm_plugin_t *plugin,
        if (samples == 0)
                return 0;
        for (voice = 0; voice < plugin->src_format.voices; voice++) {
-               if (src_voices[voice].first % 8 != 0 || 
-                   src_voices[voice].step % 8 != 0)
+               if (src_voices[voice].area.first % 8 != 0 || 
+                   src_voices[voice].area.step % 8 != 0)
                        return -EINVAL;
-               if (dst_voices[voice].first % 8 != 0 || 
-                   dst_voices[voice].step % 8 != 0)
+               if (dst_voices[voice].area.first % 8 != 0 || 
+                   dst_voices[voice].area.step % 8 != 0)
                        return -EINVAL;
        }
        data = (mulaw_t *)plugin->extra_data;
index 3afc0272def2a023cac8154b58e86442902ff6c8..43d31ceab67b5194271efc139ed94e57a97e5646 100644 (file)
@@ -106,15 +106,15 @@ static void resample_expand(snd_pcm_plugin_t *plugin,
                S2 = rvoices->last_S2;
                if (!src_voices[voice].enabled) {
                        if (dst_voices[voice].wanted)
-                               snd_pcm_plugin_silence_voice(plugin, &dst_voices[voice], dst_samples);
+                               snd_pcm_area_silence(&dst_voices[voice].area, 0, dst_samples, plugin->dst_format.format);
                        dst_voices[voice].enabled = 0;
                        continue;
                }
                dst_voices[voice].enabled = 1;
-               src = (char *)src_voices[voice].addr + src_voices[voice].first / 8;
-               dst = (char *)dst_voices[voice].addr + dst_voices[voice].first / 8;
-               src_step = src_voices[voice].step / 8;
-               dst_step = dst_voices[voice].step / 8;
+               src = (char *)src_voices[voice].area.addr + src_voices[voice].area.first / 8;
+               dst = (char *)dst_voices[voice].area.addr + dst_voices[voice].area.first / 8;
+               src_step = src_voices[voice].area.step / 8;
+               dst_step = dst_voices[voice].area.step / 8;
                src_samples1 = src_samples;
                dst_samples1 = dst_samples;
                if (pos & ~MASK) {
@@ -190,15 +190,15 @@ static void resample_shrink(snd_pcm_plugin_t *plugin,
                S2 = rvoices->last_S2;
                if (!src_voices[voice].enabled) {
                        if (dst_voices[voice].wanted)
-                               snd_pcm_plugin_silence_voice(plugin, &dst_voices[voice], dst_samples);
+                               snd_pcm_area_silence(&dst_voices[voice].area, 0, dst_samples, plugin->dst_format.format);
                        dst_voices[voice].enabled = 0;
                        continue;
                }
                dst_voices[voice].enabled = 1;
-               src = (char *)src_voices[voice].addr + src_voices[voice].first / 8;
-               dst = (char *)dst_voices[voice].addr + dst_voices[voice].first / 8;
-               src_step = src_voices[voice].step / 8;
-               dst_step = dst_voices[voice].step / 8;
+               src = (char *)src_voices[voice].area.addr + src_voices[voice].area.first / 8;
+               dst = (char *)dst_voices[voice].area.addr + dst_voices[voice].area.first / 8;
+               src_step = src_voices[voice].area.step / 8;
+               dst_step = dst_voices[voice].area.step / 8;
                src_samples1 = src_samples;
                dst_samples1 = dst_samples;
                while (dst_samples1 > 0) {
@@ -313,11 +313,11 @@ static ssize_t rate_transfer(snd_pcm_plugin_t *plugin,
        if (samples == 0)
                return 0;
        for (voice = 0; voice < plugin->src_format.voices; voice++) {
-               if (src_voices[voice].first % 8 != 0 || 
-                   src_voices[voice].step % 8 != 0)
+               if (src_voices[voice].area.first % 8 != 0 || 
+                   src_voices[voice].area.step % 8 != 0)
                        return -EINVAL;
-               if (dst_voices[voice].first % 8 != 0 || 
-                   dst_voices[voice].step % 8 != 0)
+               if (dst_voices[voice].area.first % 8 != 0 || 
+                   dst_voices[voice].area.step % 8 != 0)
                        return -EINVAL;
        }
 
index ba99d8ab8b65d75068cd171b338cdcb37f244219..40b0b70649f48e7d96435d61d644dc43cc5c1b68 100644 (file)
@@ -81,7 +81,7 @@ static void route_to_voice_zero(snd_pcm_plugin_t *plugin,
                                ttable_dst_t* ttable UNUSED, size_t samples)
 {
        if (dst_voice->wanted)
-               snd_pcm_plugin_silence_voice(plugin, dst_voice, samples);
+               snd_pcm_area_silence(&dst_voice->area, 0, samples, plugin->dst_format.format);
        dst_voice->enabled = 0;
 }
 
@@ -101,7 +101,7 @@ static void route_to_voice_one(snd_pcm_plugin_t *plugin,
        int src_step, dst_step;
        for (srcidx = 0; srcidx < ttable->nsrcs; ++srcidx) {
                src_voice = &src_voices[ttable->srcs[srcidx].voice];
-               if (src_voice->addr != NULL)
+               if (src_voice->area.addr != NULL)
                        break;
        }
        if (srcidx == ttable->nsrcs) {
@@ -111,10 +111,10 @@ static void route_to_voice_one(snd_pcm_plugin_t *plugin,
 
        dst_voice->enabled = 1;
        conv = conv_labels[data->conv];
-       src = src_voice->addr + src_voice->first / 8;
-       src_step = src_voice->step / 8;
-       dst = dst_voice->addr + dst_voice->first / 8;
-       dst_step = dst_voice->step / 8;
+       src = src_voice->area.addr + src_voice->area.first / 8;
+       src_step = src_voice->area.step / 8;
+       dst = dst_voice->area.addr + dst_voice->area.first / 8;
+       dst_step = dst_voice->area.step / 8;
        while (samples-- > 0) {
                goto *conv;
 #define CONV_END after
@@ -190,8 +190,8 @@ static void route_to_voice(snd_pcm_plugin_t *plugin,
                const snd_pcm_plugin_voice_t *src_voice = &src_voices[ttable->srcs[srcidx].voice];
                if (!src_voice->enabled)
                        continue;
-               srcs[srcidx1] = src_voice->addr + src_voices->first / 8;
-               src_steps[srcidx1] = src_voice->step / 8;
+               srcs[srcidx1] = src_voice->area.addr + src_voices->area.first / 8;
+               src_steps[srcidx1] = src_voice->area.step / 8;
                src_tt[srcidx1] = ttable->srcs[srcidx];
                srcidx1++;
        }
@@ -210,8 +210,8 @@ static void route_to_voice(snd_pcm_plugin_t *plugin,
        add = add_labels[data->sum_type * 2 + ttable->att];
        norm = norm_labels[data->sum_type * 8 + ttable->att * 4 + 4 - data->src_sample_size];
        put32 = put32_labels[data->put];
-       dst = dst_voice->addr + dst_voice->first / 8;
-       dst_step = dst_voice->step / 8;
+       dst = dst_voice->area.addr + dst_voice->area.first / 8;
+       dst_step = dst_voice->area.step / 8;
 
        while (samples-- > 0) {
                ttable_src_t *ttp = src_tt;
@@ -513,15 +513,15 @@ static ssize_t route_transfer(snd_pcm_plugin_t *plugin,
 
        src_nvoices = plugin->src_format.voices;
        for (src_voice = 0; src_voice < src_nvoices; ++src_voice) {
-               if (src_voices[src_voice].first % 8 != 0 || 
-                   src_voices[src_voice].step % 8 != 0)
+               if (src_voices[src_voice].area.first % 8 != 0 || 
+                   src_voices[src_voice].area.step % 8 != 0)
                        return -EINVAL;
        }
 
        dst_nvoices = plugin->dst_format.voices;
        for (dst_voice = 0; dst_voice < dst_nvoices; ++dst_voice) {
-               if (dst_voices[dst_voice].first % 8 != 0 || 
-                   dst_voices[dst_voice].step % 8 != 0)
+               if (dst_voices[dst_voice].area.first % 8 != 0 || 
+                   dst_voices[dst_voice].area.step % 8 != 0)
                        return -EINVAL;
        }
 
index 57bfe0c49fb16b6792d5a91e37f820fef7533e9f..79ef50e89d4b0e8ccab6c0ce55e1d7d20d8b4d1a 100644 (file)
@@ -58,12 +58,12 @@ static ssize_t stream_transfer(snd_pcm_plugin_t *plugin,
                        return result;
                count = plugin->src_format.voices;
                if (plugin->src_format.interleave) {
-                       result = snd_pcm_write(data->slave, src_voices->addr, result);
+                       result = snd_pcm_write(data->slave, src_voices->area.addr, result);
                } else {
                        result /= count;
                        for (voice = 0; voice < count; voice++) {
                                if (src_voices[voice].enabled)
-                                       vec[voice].iov_base = src_voices[voice].addr;
+                                       vec[voice].iov_base = src_voices[voice].area.addr;
                                else
                                        vec[voice].iov_base = 0;
                                vec[voice].iov_len = result;
@@ -80,7 +80,7 @@ static ssize_t stream_transfer(snd_pcm_plugin_t *plugin,
                        return result;
                count = plugin->dst_format.voices;
                if (plugin->dst_format.interleave) {
-                       result = snd_pcm_read(data->slave, dst_voices->addr, result);
+                       result = snd_pcm_read(data->slave, dst_voices->area.addr, result);
                        for (voice = 0; voice < count; voice++)
                                dst_voices[voice].enabled = src_voices[voice].enabled;
                } else {
@@ -88,7 +88,7 @@ static ssize_t stream_transfer(snd_pcm_plugin_t *plugin,
                        for (voice = 0; voice < count; voice++) {
                                dst_voices[voice].enabled = src_voices[voice].enabled;
                                if (dst_voices[voice].enabled)
-                                       vec[voice].iov_base = dst_voices[voice].addr;
+                                       vec[voice].iov_base = dst_voices[voice].area.addr;
                                else
                                        vec[voice].iov_base = 0;
                                vec[voice].iov_len = result;