]> git.alsa-project.org Git - alsa-lib.git/commitdiff
Added dump facility. Continued pcm_multi implementation
authorAbramo Bagnara <abramo@alsa-project.org>
Mon, 17 Jul 2000 15:33:29 +0000 (15:33 +0000)
committerAbramo Bagnara <abramo@alsa-project.org>
Mon, 17 Jul 2000 15:33:29 +0000 (15:33 +0000)
include/pcm.h
src/pcm/pcm.c
src/pcm/pcm_hw.c
src/pcm/pcm_local.h
src/pcm/pcm_multi.c
src/pcm/pcm_plug.c
src/pcm/plugin/io.c
src/pcm/plugin/mmap.c
src/pcm/plugin/route.c

index 641c5750053c94a706bd304c214896b48753a08b..2bbda9aac92d4c8a398bdc9047e0f059deaa333f 100644 (file)
@@ -146,6 +146,7 @@ ssize_t snd_pcm_read(snd_pcm_t *handle, void *buffer, size_t size);
 ssize_t snd_pcm_writev(snd_pcm_t *handle, const struct iovec *vector, unsigned long  count);
 ssize_t snd_pcm_readv(snd_pcm_t *handle, const struct iovec *vector, unsigned long count);
 int snd_pcm_dump_setup(snd_pcm_t *handle, FILE *fp);
+int snd_pcm_dump(snd_pcm_t *handle, FILE *fp);
 
 int snd_pcm_channels_mask(snd_pcm_t *handle, bitset_t *client_vmask);
 
@@ -176,9 +177,9 @@ ssize_t snd_pcm_mmap_read_frames(snd_pcm_t *handle, const void *buffer, size_t f
 int snd_pcm_mmap_get_areas(snd_pcm_t *handle, snd_pcm_channel_area_t *areas);
 
 
-const char *snd_pcm_get_format_name(int format);
-const char *snd_pcm_get_format_description(int format);
-int snd_pcm_get_format_value(const char* name);
+const char *snd_pcm_format_name(int format);
+const char *snd_pcm_format_description(int format);
+int snd_pcm_format_value(const char* name);
 
 int snd_pcm_area_silence(const snd_pcm_channel_area_t *dst_channel, size_t dst_offset,
                         size_t samples, int format);
@@ -274,6 +275,7 @@ struct snd_stru_pcm_plugin {
        int (*parameter_get)(snd_pcm_plugin_t *plugin,
                             const char *name,
                             unsigned long *value);
+       void (*dump)(snd_pcm_plugin_t *plugin, FILE *fp);
        snd_pcm_plugin_t *prev;
        snd_pcm_plugin_t *next;
        snd_pcm_plug_t *plug;
@@ -290,15 +292,11 @@ struct snd_stru_pcm_plugin {
 int snd_pcm_plug_create(snd_pcm_t **handle, snd_pcm_t *slave, int close_slave);
 int snd_pcm_plug_open_subdevice(snd_pcm_t **handle, int card, int device, int subdevice, int stream, int mode);
 int snd_pcm_plug_open(snd_pcm_t **handle, int card, int device, int stream, int mode);
-int snd_pcm_multi_create(snd_pcm_t **handlep, size_t slaves_count,
-                        snd_pcm_t **slaves_handle, size_t *slaves_channels_count,
-                        size_t binds_count,  unsigned int *binds_client_channel,
-                        unsigned int *binds_slave, unsigned int *binds_slave_channel,
-                        int close_slaves);
 
 int snd_pcm_plugin_free(snd_pcm_plugin_t *plugin);
 int snd_pcm_plugin_insert(snd_pcm_plugin_t *plugin);
 int snd_pcm_plugin_append(snd_pcm_plugin_t *plugin);
+void snd_pcm_plugin_dump(snd_pcm_plugin_t *plugin, FILE *fp);
 int snd_pcm_plug_alloc(snd_pcm_plug_t *plug, size_t frames);
 int snd_pcm_plug_clear(snd_pcm_plug_t *plug);
 snd_pcm_plugin_t *snd_pcm_plug_first(snd_pcm_plug_t *plug);
@@ -371,6 +369,12 @@ int snd_pcm_plugin_build_copy(snd_pcm_plug_t *plug,
                              snd_pcm_format_t *dst_format,
                              snd_pcm_plugin_t **r_plugin);
 
+int snd_pcm_multi_create(snd_pcm_t **handlep, size_t slaves_count,
+                        snd_pcm_t **slaves_handle, size_t *slaves_channels_count,
+                        size_t binds_count,  unsigned int *binds_client_channel,
+                        unsigned int *binds_slave, unsigned int *binds_slave_channel,
+                        int close_slaves);
+
 #ifdef __cplusplus
 }
 #endif
index 7b23a0b505b8f8624c97473997ddeaec7e8c0356..d63e36ca2d4eb07bc6404c2c0ea54069c4a5ed68 100644 (file)
@@ -249,6 +249,8 @@ ssize_t snd_pcm_writev(snd_pcm_t *handle, const struct iovec *vector, unsigned l
        assert(handle);
        assert(count == 0 || vector);
        assert(handle->valid_setup);
+       assert(handle->setup.format.interleave || 
+              count % handle->setup.format.channels == 0);
        return handle->ops->writev(handle->op_arg, -1, vector, count);
 }
 
@@ -366,6 +368,7 @@ int snd_pcm_dump_setup(snd_pcm_t *handle, FILE *fp)
 {
        snd_pcm_setup_t *setup;
        assert(handle);
+       assert(fp);
        assert(handle->valid_setup);
        setup = &handle->setup;
         fprintf(fp, "stream: %s\n", assoc(handle->stream, streams));
@@ -392,7 +395,15 @@ int snd_pcm_dump_setup(snd_pcm_t *handle, FILE *fp)
        return 0;
 }
 
-const char *snd_pcm_get_format_name(int format)
+int snd_pcm_dump(snd_pcm_t *handle, FILE *fp)
+{
+       assert(handle);
+       assert(fp);
+       handle->ops->dump(handle->op_arg, fp);
+       return 0;
+}
+
+const char *snd_pcm_format_name(int format)
 {
        assoc_t *a = assoc_value(format, fmts);
        if (a)
@@ -400,7 +411,7 @@ const char *snd_pcm_get_format_name(int format)
        return 0;
 }
 
-const char *snd_pcm_get_format_description(int format)
+const char *snd_pcm_format_description(int format)
 {
        assoc_t *a = assoc_value(format, fmts);
        if (a)
@@ -408,7 +419,7 @@ const char *snd_pcm_get_format_description(int format)
        return "Unknown";
 }
 
-int snd_pcm_get_format_value(const char* name)
+int snd_pcm_format_value(const char* name)
 {
        assoc_t *a = assoc_name(name, fmts);
        if (a)
index f6d8eae08a8821b84bb34790e95bc0e9b1967f76..dcbc01ce08031f8a01772b23ab3368c8ef658a0e 100644 (file)
@@ -32,6 +32,7 @@
 typedef struct {
        snd_pcm_t *handle;
        int fd;
+       int card, device, subdevice;
 } snd_pcm_hw_t;
 
 #define SND_FILE_PCM_STREAM_PLAYBACK           "/dev/snd/pcmC%iD%ip"
@@ -330,6 +331,21 @@ static int snd_pcm_hw_channels_mask(void *private UNUSED,
        return 0;
 }
 
+static void snd_pcm_hw_dump(void *private, FILE *fp)
+{
+       snd_pcm_hw_t *hw = (snd_pcm_hw_t*) private;
+       snd_pcm_t *handle = hw->handle;
+       char *name = "Unknown";
+       snd_card_get_name(hw->card, &name);
+       fprintf(fp, "Hardware PCM card %d '%s' device %d subdevice %d\n",
+               hw->card, name, hw->device, hw->subdevice);
+       free(name);
+       if (handle->valid_setup) {
+               fprintf(fp, "\nIts setup is:\n");
+               snd_pcm_dump_setup(handle, fp);
+       }
+}
+
 struct snd_pcm_ops snd_pcm_hw_ops = {
        close: snd_pcm_hw_close,
        nonblock: snd_pcm_hw_nonblock,
@@ -359,6 +375,7 @@ struct snd_pcm_ops snd_pcm_hw_ops = {
        munmap_data: snd_pcm_hw_munmap_data,
        file_descriptor: snd_pcm_hw_file_descriptor,
        channels_mask: snd_pcm_hw_channels_mask,
+       dump: snd_pcm_hw_dump,
 };
 
 int snd_pcm_hw_open_subdevice(snd_pcm_t **handlep, int card, int device, int subdevice, int stream, int mode)
@@ -436,6 +453,9 @@ int snd_pcm_hw_open_subdevice(snd_pcm_t **handlep, int card, int device, int sub
                goto __end;
        }
        hw->handle = handle;
+       hw->card = card;
+       hw->device = device;
+       hw->subdevice = subdevice;
        hw->fd = fd;
        handle->type = SND_PCM_TYPE_HW;
        handle->stream = stream;
index dedaa7b0afca707bed6dbcc1052cb6a3df913c53..c569f27bd9a004ae915415c29d7afe13026de69f 100644 (file)
@@ -51,6 +51,7 @@ struct snd_pcm_ops {
        int (*munmap_data)(void *private, void *buffer, size_t bsize);
        int (*file_descriptor)(void *private);
        int (*channels_mask)(void *private, bitset_t *client_vmask);
+       void (*dump)(void *private, FILE *fp);
 };
 
 struct snd_pcm {
index 6dfb62ab74f1576d2f8b41fe474e5b9add67a2aa..9f9b517833cd544dc93991b294e9482c1ecf6d80 100644 (file)
@@ -50,6 +50,7 @@ typedef struct {
        size_t binds_count;
        snd_pcm_multi_bind_t *binds;
        size_t channels_count;
+       size_t frames_alloc;
        int interleave;
        int one_to_many;
 } snd_pcm_multi_t;
@@ -99,6 +100,7 @@ static int snd_pcm_multi_info(void *private, snd_pcm_info_t *info)
        for (i = 1; i < multi->slaves_count; ++i) {
                snd_pcm_t *handle_i = multi->slaves[i].handle;
                snd_pcm_info_t info_i;
+               memset(&info_i, 0, sizeof(info_i));
                err = snd_pcm_info(handle_i, &info_i);
                if (err < 0)
                        return err;
@@ -115,12 +117,17 @@ static int snd_pcm_multi_params_info(void *private, snd_pcm_params_info_t *info)
        unsigned int i;
        int err;
        snd_pcm_t *handle_0 = multi->slaves[0].handle;
+       unsigned int old_mask = info->req_mask;
+       info->req_mask &= ~SND_PCM_PARAMS_CHANNELS;
        err = snd_pcm_params_info(handle_0, info);
        if (err < 0)
                return err;
+       info->min_channels = multi->channels_count;
+       info->max_channels = multi->channels_count;
        for (i = 1; i < multi->slaves_count; ++i) {
                snd_pcm_t *handle_i = multi->slaves[i].handle;
                snd_pcm_params_info_t info_i;
+               info_i = *info;
                err = snd_pcm_params_info(handle_i, &info_i);
                if (err < 0)
                        return err;
@@ -141,6 +148,7 @@ static int snd_pcm_multi_params_info(void *private, snd_pcm_params_info_t *info)
                if (info_i.max_fragments < info->max_fragments)
                        info->max_fragments = info_i.max_fragments;
        }
+       info->req_mask = old_mask;
        return 0;
 }
 
@@ -166,6 +174,9 @@ static int snd_pcm_multi_params(void *private, snd_pcm_params_t *params)
                else if (!(info.flags & SND_PCM_INFO_NONINTERLEAVE))
                        p.format.interleave = 1;
                p.format.channels = multi->slaves[i].channels_total;
+#if 1
+               p.frames_xrun_max = ~0;
+#endif
                err = snd_pcm_params(handle, &p);
                if (err < 0)
                        return err;
@@ -186,9 +197,12 @@ static int snd_pcm_multi_setup(void *private, snd_pcm_setup_t *setup)
        snd_pcm_multi_t *multi = (snd_pcm_multi_t*) private;
        unsigned int i;
        int err;
+       size_t frames_alloc;
        err = snd_pcm_setup(multi->slaves[0].handle, setup);
        if (err < 0)
                return err;
+       frames_alloc = multi->slaves[0].handle->setup.frag_size;
+       multi->frames_alloc = 0;
        for (i = 1; i < multi->slaves_count; ++i) {
                snd_pcm_setup_t s;
                snd_pcm_t *sh = multi->slaves[i].handle;
@@ -219,7 +233,7 @@ static int snd_pcm_multi_setup(void *private, snd_pcm_setup_t *setup)
                        if (!multi->handle->setup.format.interleave)
                                continue;
                }
-               s->buf = malloc(sh->setup.frag_size * sh->bits_per_frame / 8);
+               s->buf = malloc(frames_alloc * sh->bits_per_frame / 8);
                if (!s->buf)
                        return -ENOMEM;
                snd_pcm_format_set_silence(sh->setup.format.format, s->buf,
@@ -237,9 +251,11 @@ static int snd_pcm_multi_setup(void *private, snd_pcm_setup_t *setup)
                                a->addr = s->buf + sh->setup.frag_size * sh->bits_per_sample / 8;
                                a->first = 0;
                                a->step = sh->bits_per_sample;
+                               s->iovec[c].iov_base = a->addr;
                        }
                }
        }
+       multi->frames_alloc = frames_alloc;
        /* Loaded with a value != 0 if mmap is feasible */
        setup->mmap_bytes = !multi->one_to_many;
        return 0;
@@ -376,14 +392,14 @@ static ssize_t snd_pcm_multi_frame_data(void *private, off_t offset)
        }
        return newpos;
 }
-  
-ssize_t snd_pcm_multi_write(void *private, snd_timestamp_t timestamp UNUSED, const void *buf, size_t count)
+
+static int snd_pcm_multi_write_copy(snd_pcm_multi_t *multi, const void *buf,
+                                   size_t offset, size_t count)
 {
-       snd_pcm_multi_t *multi = (snd_pcm_multi_t*) private;
-       snd_pcm_t *handle = multi->handle;
        unsigned int i;
        snd_pcm_channel_area_t area;
-       area.addr = (void *) buf;
+       snd_pcm_t *handle = multi->handle;
+       area.addr = (void *) buf + offset * handle->bits_per_frame;
        area.step = handle->bits_per_frame;
        for (i = 0; i < multi->binds_count; ++i) {
                snd_pcm_multi_bind_t *bind = &multi->binds[i];
@@ -394,41 +410,147 @@ ssize_t snd_pcm_multi_write(void *private, snd_timestamp_t timestamp UNUSED, con
                err = snd_pcm_area_copy(&area, 0, &slave->areas[bind->slave_channel], 0, count, handle->setup.format.format);
                if (err < 0)
                        return err;
-               if (!slave->handle->setup.format.interleave)
-                       slave->iovec[bind->slave_channel].iov_base = slave->areas[bind->slave_channel].addr;
+               if (!slave->handle->setup.format.interleave) {
+                       struct iovec *vec = &slave->iovec[bind->slave_channel];
+                       vec->iov_len = count;
+               }
+       }
+       return 0;
+}
+
+static int snd_pcm_multi_writev_copy(snd_pcm_multi_t *multi, const struct iovec *vec,
+                                    size_t offset, size_t count)
+{
+       unsigned int i;
+       snd_pcm_channel_area_t area;
+       snd_pcm_t *handle = multi->handle;
+       area.first = 0;
+       area.step = handle->bits_per_sample;
+       for (i = 0; i < multi->binds_count; ++i) {
+               snd_pcm_multi_bind_t *bind = &multi->binds[i];
+               snd_pcm_multi_slave_t *slave = &multi->slaves[bind->slave];
+               int err;
+               area.addr = vec[bind->client_channel].iov_base + 
+                       offset * handle->bits_per_sample;
+               if (slave->handle->setup.format.interleave) {
+                       assert(slave->buf);
+                       err = snd_pcm_area_copy(&area, 0, &slave->areas[bind->slave_channel], 0, count, handle->setup.format.format);
+                       if (err < 0)
+                               return err;
+               } else {
+                       struct iovec *vec = &slave->iovec[bind->slave_channel];
+                       vec->iov_base = area.addr;
+                       vec->iov_len = count;
+               }
        }
+       return 0;
+}
+
+static ssize_t snd_pcm_multi_write_io(snd_pcm_multi_t *multi, size_t count)
+{
+       unsigned int i;
+       ssize_t frames = count;
        for (i = 0; i < multi->slaves_count; ++i) {
                snd_pcm_multi_slave_t *slave = &multi->slaves[i];
                snd_pcm_t *sh = slave->handle;
                if (sh->setup.format.interleave) {
-                       count = snd_pcm_write(sh, slave->buf, count);
+                       frames = snd_pcm_write(sh, slave->buf, frames);
                } else {
                        int channels = sh->setup.format.channels;
-                       struct iovec vec[channels];
-                       int c;
-                       for (c = 0; c < channels; ++c)
-                               vec[c].iov_len = count;
-                       count = snd_pcm_writev(sh, vec, channels);
+                       frames = snd_pcm_writev(sh, slave->iovec, channels);
                }
-               if (count <= 0)
+               if (frames <= 0)
                        break;
        }
-       return count;
+       return frames;
 }
 
-ssize_t snd_pcm_multi_read(void *private, snd_timestamp_t timestamp UNUSED, void *buf, size_t count)
+static ssize_t snd_pcm_multi_write(void *private, snd_timestamp_t timestamp UNUSED, const void *buf, size_t count)
 {
        snd_pcm_multi_t *multi = (snd_pcm_multi_t*) private;
-       return -ENOSYS;
+       size_t result = 0;
+       while (count > 0) {
+               int err;
+               ssize_t ret;
+               size_t frames = count;
+               if (frames > multi->frames_alloc)
+                       frames = multi->frames_alloc;
+               err = snd_pcm_multi_write_copy(multi, buf, result, frames);
+               if (err < 0)
+                       return err;
+               ret = snd_pcm_multi_write_io(multi, frames);
+               if (ret > 0)
+                       result += ret;
+               if (ret != (ssize_t)frames) {
+                       if (result > 0)
+                               return result;
+                       return ret;
+               }
+               count -= ret;
+       }
+       return result;
+}
+
+static ssize_t snd_pcm_multi_writev1(snd_pcm_multi_t *multi, const struct iovec *vector, size_t count)
+{
+       size_t result = 0;
+       while (count > 0) {
+               int err;
+               ssize_t ret;
+               size_t frames = count;
+               if (frames > multi->frames_alloc)
+                       frames = multi->frames_alloc;
+               err = snd_pcm_multi_writev_copy(multi, vector, result, frames);
+               if (err < 0)
+                       return err;
+               ret = snd_pcm_multi_write_io(multi, frames);
+               if (ret > 0)
+                       result += ret;
+               if (ret != (ssize_t) frames) {
+                       if (result > 0)
+                               return result;
+                       return ret;
+               }
+               count -= ret;
+       }
+       return result;
+}
+
+static ssize_t snd_pcm_multi_writev(void *private, snd_timestamp_t timestamp UNUSED, const struct iovec *vector, unsigned long count)
+{
+       snd_pcm_multi_t *multi = (snd_pcm_multi_t*) private;
+       snd_pcm_t *handle = multi->handle;
+       unsigned int k, step;
+       size_t result = 0;
+       if (handle->setup.format.interleave)
+               step = 1;
+       else
+               step = handle->setup.format.channels;
+       for (k = 0; k < count; k += step) {
+               ssize_t ret;
+               if (handle->setup.format.interleave)
+                       ret = snd_pcm_multi_write(private, timestamp, vector->iov_base, vector->iov_len);
+               else
+                       ret = snd_pcm_multi_writev1(multi, vector, vector->iov_len);
+               if (ret > 0)
+                       result += ret;
+               if (ret != (ssize_t) vector->iov_len) {
+                       if (result > 0)
+                               return result;
+                       return ret;
+               }
+               vector += step;
+       }
+       return result;
 }
 
-ssize_t snd_pcm_multi_writev(void *private, snd_timestamp_t timestamp UNUSED, const struct iovec *vector, unsigned long count)
+static ssize_t snd_pcm_multi_read(void *private, snd_timestamp_t timestamp UNUSED, void *buf, size_t count)
 {
        snd_pcm_multi_t *multi = (snd_pcm_multi_t*) private;
        return -ENOSYS;
 }
 
-ssize_t snd_pcm_multi_readv(void *private, snd_timestamp_t timestamp UNUSED, const struct iovec *vector, unsigned long count)
+static ssize_t snd_pcm_multi_readv(void *private, snd_timestamp_t timestamp UNUSED, const struct iovec *vector, unsigned long count)
 {
        snd_pcm_multi_t *multi = (snd_pcm_multi_t*) private;
        return -ENOSYS;
@@ -577,6 +699,29 @@ int snd_pcm_multi_file_descriptor(void *private)
        return snd_pcm_file_descriptor(handle);
 }
 
+static void snd_pcm_multi_dump(void *private, FILE *fp)
+{
+       snd_pcm_multi_t *multi = (snd_pcm_multi_t*) private;
+       snd_pcm_t *handle = multi->handle;
+       unsigned int k;
+       fprintf(fp, "Multi PCM\n");
+       if (handle->valid_setup) {
+               fprintf(fp, "\nIts setup is:\n");
+               snd_pcm_dump_setup(handle, fp);
+       }
+       for (k = 0; k < multi->slaves_count; ++k) {
+               fprintf(fp, "\nSlave #%d: ", k);
+               snd_pcm_dump(multi->slaves[k].handle, fp);
+       }
+       fprintf(fp, "\nBindings:\n");
+       for (k = 0; k < multi->binds_count; ++k) {
+               fprintf(fp, "Channel #%d: slave %d[%d]\n", 
+                       multi->binds[k].client_channel,
+                       multi->binds[k].slave,
+                       multi->binds[k].slave_channel);
+       }
+}
+
 struct snd_pcm_ops snd_pcm_multi_ops = {
        close: snd_pcm_multi_close,
        nonblock: snd_pcm_multi_nonblock,
@@ -606,6 +751,7 @@ struct snd_pcm_ops snd_pcm_multi_ops = {
        munmap_data: snd_pcm_multi_munmap_data,
        file_descriptor: snd_pcm_multi_file_descriptor,
        channels_mask: snd_pcm_multi_channels_mask,
+       dump: snd_pcm_multi_dump,
 };
 
 int snd_pcm_multi_create(snd_pcm_t **handlep, size_t slaves_count,
index 8de2134f5fcbf00e91092b30aa0c9f7a9831844d..44677119ba3ee51cf6eb49ffab25362f99a09c8c 100644 (file)
@@ -65,6 +65,35 @@ int snd_pcm_plugin_append(snd_pcm_plugin_t *plugin)
        return 0;
 }
 
+void snd_pcm_plugin_dump(snd_pcm_plugin_t *plugin, FILE *fp)
+{
+       fprintf(fp, "----------- %s\n", plugin->name);
+       fprintf(fp, "Buffer: %d frames\n", plugin->buf_frames);
+       if (plugin->src_format.interleave != plugin->dst_format.interleave) {
+               if (plugin->src_format.interleave)
+                       fprintf(fp, "Interleaved -> Non interleaved\n");
+               else
+                       fprintf(fp, "Non interleaved -> Interleaved\n");
+       }
+       if (plugin->src_format.channels != plugin->dst_format.channels) {
+               fprintf(fp, "Channels: %d -> %d\n", 
+                       plugin->src_format.channels, 
+                       plugin->dst_format.channels);
+       }
+       if (plugin->src_format.format != plugin->dst_format.format) {
+               fprintf(fp, "Format: %s -> %s\n", 
+                       snd_pcm_format_name(plugin->src_format.format),
+                       snd_pcm_format_name(plugin->dst_format.format));
+       }
+       if (plugin->src_format.rate != plugin->dst_format.rate) {
+               fprintf(fp, "Rate: %d -> %d\n", 
+                       plugin->src_format.rate, 
+                       plugin->dst_format.rate);
+       }
+       if (plugin->dump)
+               plugin->dump(plugin, fp);
+}
+
 /* snd_pcm_plug externs */
 
 int snd_pcm_plug_clear(snd_pcm_plug_t *plug)
@@ -378,22 +407,22 @@ ssize_t snd_pcm_plug_writev(void *private, snd_timestamp_t tstamp UNUSED, const
 {
        snd_pcm_plug_t *plug = (snd_pcm_plug_t*) private;
        snd_pcm_t *handle = plug->handle;
-       unsigned int k, step, channels;
-       size_t size = 0;
+       unsigned int k, step;
+       size_t result = 0;
        assert(plug->frames_alloc);
-       channels = handle->setup.format.channels;
        if (handle->setup.format.interleave)
                step = 1;
-       else {
-               step = channels;
-               assert(count % channels == 0);
-       }
+       else
+               step = handle->setup.format.channels;
        for (k = 0; k < count; k += step) {
                snd_pcm_plugin_channel_t *channels;
                ssize_t frames;
-               frames = snd_pcm_plug_client_channels_iovec(plug, vector, count, &channels);
-               if (frames < 0)
+               frames = snd_pcm_plug_client_channels_iovec(plug, vector, step, &channels);
+               if (frames < 0) {
+                       if (result > 0)
+                               return result;
                        return frames;
+               }
                while (1) {
                        unsigned int c;
                        ssize_t ret;
@@ -402,41 +431,42 @@ ssize_t snd_pcm_plug_writev(void *private, snd_timestamp_t tstamp UNUSED, const
                                frames1 = plug->frames_alloc;
                        ret = snd_pcm_plug_write_transfer(plug, channels, frames1);
                        if (ret < 0) {
-                               if (size > 0)
-                                       return size;
+                               if (result > 0)
+                                       return result;
                                return ret;
                        }
-                       size += ret;
+                       result += ret;
                        frames -= ret;
                        if (frames == 0)
                                break;
                        for (c = 0; c < handle->setup.format.channels; ++c)
                                channels[c].area.addr += ret * channels[c].area.step / 8;
                }
+               vector += step;
        }
-       return size;
+       return result;
 }
 
 ssize_t snd_pcm_plug_readv(void *private, snd_timestamp_t tstamp UNUSED, const struct iovec *vector, unsigned long count)
 {
        snd_pcm_plug_t *plug = (snd_pcm_plug_t*) private;
        snd_pcm_t *handle = plug->handle;
-       unsigned int k, step, channels;
-       size_t size = 0;
+       unsigned int k, step;
+       size_t result = 0;
        assert(plug->frames_alloc);
-       channels = handle->setup.format.channels;
        if (handle->setup.format.interleave)
                step = 1;
-       else {
-               step = channels;
-               assert(count % channels == 0);
-       }
+       else
+               step = handle->setup.format.channels;
        for (k = 0; k < count; k += step) {
                snd_pcm_plugin_channel_t *channels;
                ssize_t frames;
-               frames = snd_pcm_plug_client_channels_iovec(plug, vector, count, &channels);
-               if (frames < 0)
+               frames = snd_pcm_plug_client_channels_iovec(plug, vector, step, &channels);
+               if (frames < 0) {
+                       if (result > 0)
+                               return result;
                        return frames;
+               }
                while (1) {
                        unsigned int c;
                        ssize_t ret;
@@ -445,19 +475,20 @@ ssize_t snd_pcm_plug_readv(void *private, snd_timestamp_t tstamp UNUSED, const s
                                frames1 = plug->frames_alloc;
                        ret = snd_pcm_plug_read_transfer(plug, channels, frames1);
                        if (ret < 0) {
-                               if (size > 0)
-                                       return size;
+                               if (result > 0)
+                                       return result;
                                return ret;
                        }
-                       size += ret;
+                       result += ret;
                        frames -= ret;
                        if (frames == 0)
                                break;
                        for (c = 0; c < handle->setup.format.channels; ++c)
                                channels[c].area.addr += ret * channels[c].area.step / 8;
                }
+               vector += step;
        }
-       return size;
+       return result;
 }
 
 ssize_t snd_pcm_plug_write(void *private, snd_timestamp_t tstamp UNUSED, const void *buf, size_t count)
@@ -574,6 +605,25 @@ int snd_pcm_plug_file_descriptor(void *private)
        return snd_pcm_file_descriptor(plug->slave);
 }
 
+static void snd_pcm_plug_dump(void *private, FILE *fp)
+{
+       snd_pcm_plug_t *plug = (snd_pcm_plug_t*) private;
+       snd_pcm_t *handle = plug->handle;
+       snd_pcm_plugin_t *plugin;
+       fprintf(fp, "Plug PCM\n");
+       if (handle->valid_setup) {
+               fprintf(fp, "\nIts setup is:\n");
+               snd_pcm_dump_setup(handle, fp);
+       }
+       fprintf(fp, "\nPlugins:\n");
+       plugin = plug->first;
+       while (plugin) {
+               snd_pcm_plugin_dump(plugin, fp);
+               plugin = plugin->next;
+       }
+       fprintf(fp, "\n");
+}
+
 static int snd_pcm_plug_params(void *private, snd_pcm_params_t *params);
 
 struct snd_pcm_ops snd_pcm_plug_ops = {
@@ -605,6 +655,7 @@ struct snd_pcm_ops snd_pcm_plug_ops = {
        munmap_data: snd_pcm_plug_munmap_data,
        file_descriptor: snd_pcm_plug_file_descriptor,
        channels_mask: snd_pcm_plug_channels_mask,
+       dump: snd_pcm_plug_dump,
 };
 
 static void snd_pcm_plug_slave_params(snd_pcm_plug_t *plug,
index a449ec672f028f2c2dbfc0f9c2830937eff89e44..5848773e5542bb6743ce1c97afbf1c20a9a5db27 100644 (file)
@@ -118,6 +118,17 @@ static ssize_t io_src_channels(snd_pcm_plugin_t *plugin,
        return frames;
 }
 
+#ifndef __KERNEL__
+static void io_dump(snd_pcm_plugin_t *plugin, FILE *fp)
+{
+       snd_pcm_t *slave = plugin->plug->slave;
+       if (slave->valid_setup) {
+               fprintf(fp, "Slave: ");
+               snd_pcm_dump(slave, fp);
+       }
+}
+#endif
+
 int snd_pcm_plugin_build_io(snd_pcm_plug_t *plug,
                            snd_pcm_format_t *format,
                            snd_pcm_plugin_t **r_plugin)
@@ -141,6 +152,9 @@ int snd_pcm_plugin_build_io(snd_pcm_plug_t *plug,
        } else {
                plugin->transfer = io_capture_transfer;
        }
+#ifndef __KERNEL__
+       plugin->dump = io_dump;
+#endif
 
        *r_plugin = plugin;
        return 0;
index 177e04fb7a4443ba6c3c5acbc97dc9885b0951b7..869cda79cbb2b55175ed1fab768d3067d53b3ed2 100644 (file)
@@ -42,8 +42,8 @@ typedef struct mmap_private_data {
 
 
 static ssize_t mmap_src_channels(snd_pcm_plugin_t *plugin,
-                              size_t frames,
-                              snd_pcm_plugin_channel_t **channels)
+                                size_t frames,
+                                snd_pcm_plugin_channel_t **channels)
 {
        mmap_t *data;
         snd_pcm_plugin_channel_t *sv;
@@ -272,7 +272,16 @@ static void mmap_free(snd_pcm_plugin_t *plugin, void *private_data UNUSED)
        if (data->buffer)
                snd_pcm_munmap(plugin->plug->slave);
 }
+
+static void mmap_dump(snd_pcm_plugin_t *plugin, FILE *fp)
+{
+       snd_pcm_t *slave = plugin->plug->slave;
+       if (slave->valid_setup) {
+               fprintf(fp, "Slave: ");
+               snd_pcm_dump(slave, fp);
+       }
+}
+
 int snd_pcm_plugin_build_mmap(snd_pcm_plug_t *plug,
                              snd_pcm_format_t *format,
                              snd_pcm_plugin_t **r_plugin)
@@ -300,6 +309,7 @@ int snd_pcm_plugin_build_mmap(snd_pcm_plug_t *plug,
        }
        plugin->action = mmap_action;
        plugin->private_free = mmap_free;
+       plugin->dump = mmap_dump;
        *r_plugin = plugin;
        return 0;
 }
index 6368df9e10762b1b8b05d57a1fdfa202358e3222..cd439f4dfea3b6025e322df39883d0fefc14f10e 100644 (file)
@@ -61,7 +61,7 @@ typedef struct {
 
 struct ttable_dst {
        int att;        /* Attenuated */
-       int nsrcs;
+       unsigned int nsrcs;
        ttable_src_t* srcs;
        route_channel_f func;
 };
@@ -104,7 +104,7 @@ static void route_to_channel_from_one(snd_pcm_plugin_t *plugin,
        route_t *data = (route_t *)plugin->extra_data;
        void *conv;
        const snd_pcm_plugin_channel_t *src_channel = 0;
-       int srcidx;
+       unsigned int srcidx;
        char *src, *dst;
        int src_step, dst_step;
        for (srcidx = 0; srcidx < ttable->nsrcs; ++srcidx) {
@@ -373,7 +373,7 @@ int route_src_channels_mask(snd_pcm_plugin_t *plugin,
        ttable_dst_t *dp = data->ttable;
        bitset_zero(vmask, schannels);
        for (channel = 0; channel < dchannels; channel++, dp++) {
-               int src;
+               unsigned int src;
                ttable_src_t *sp;
                if (!bitset_get(dst_vmask, channel))
                        continue;
@@ -396,7 +396,7 @@ int route_dst_channels_mask(snd_pcm_plugin_t *plugin,
        ttable_dst_t *dp = data->ttable;
        bitset_zero(vmask, dchannels);
        for (channel = 0; channel < dchannels; channel++, dp++) {
-               int src;
+               unsigned int src;
                ttable_src_t *sp;
                sp = dp->srcs;
                for (src = 0; src < dp->nsrcs; src++, sp++) {
@@ -535,6 +535,38 @@ int getput_index(int format)
        return width * 4 + endian * 2 + sign;
 }
 
+#ifndef __KERNEL__
+static void route_dump(snd_pcm_plugin_t *plugin, FILE *fp)
+{
+       route_t *data;
+       ttable_dst_t *tdp;
+       unsigned int dst_channel, dst_nchannels;
+       data = (route_t *)plugin->extra_data;
+       tdp = data->ttable;
+       dst_nchannels = plugin->dst_format.channels;
+       for (dst_channel = 0; dst_channel < dst_nchannels; ++dst_channel) {
+               unsigned int k;
+               ttable_src_t *tsp = tdp->srcs;
+               fprintf(fp, "Channel %d = ", dst_channel);
+               for (k = 0; k < tdp->nsrcs; ++k) {
+                       if (k > 0)
+                               fprintf(fp, " + ");
+                       fprintf(fp, "[%d]", tsp->channel);
+                       if (tdp->att) {
+#if ROUTE_PLUGIN_USE_FLOAT
+                               fprintf(fp, "*%g", tsp->as_float);
+#else
+                               fprintf(fp, "*%d/%d", tsp->as_int, ROUTE_PLUGIN_RESOLUTION);
+#endif
+                       }
+                       ++tsp;
+               }
+               fprintf(fp, "\n");
+               ++tdp;
+       }
+}
+#endif
+
 int snd_pcm_plugin_build_route(snd_pcm_plug_t *plug,
                               snd_pcm_format_t *src_format,
                               snd_pcm_format_t *dst_format,
@@ -581,6 +613,9 @@ int snd_pcm_plugin_build_route(snd_pcm_plug_t *plug,
        plugin->transfer = route_transfer;
        plugin->src_channels_mask = route_src_channels_mask;
        plugin->dst_channels_mask = route_dst_channels_mask;
+#ifndef __KERNEL__
+       plugin->dump = route_dump;
+#endif
        *r_plugin = plugin;
        return 0;
 }