]> git.alsa-project.org Git - alsa-lib.git/commitdiff
Added support for configured pcm_multi. Changed pcm_plug definition
authorAbramo Bagnara <abramo@alsa-project.org>
Sat, 26 Aug 2000 08:10:53 +0000 (08:10 +0000)
committerAbramo Bagnara <abramo@alsa-project.org>
Sat, 26 Aug 2000 08:10:53 +0000 (08:10 +0000)
src/pcm/pcm.c
src/pcm/pcm_multi.c

index 0598263555bd2f05bde0b459ed79b031108c7ac7..ef167b2a9335522426d255b30a51925646cfef7a 100644 (file)
@@ -552,9 +552,9 @@ static int _snd_pcm_open_plug(snd_pcm_t **handlep, snd_config_t *conf,
                              int stream, int mode)
 {
        snd_config_iterator_t i;
-       long card = -1, device = -1, subdevice = -1;
-       char *str;
+       char *slave = NULL;
        int err;
+       snd_pcm_t *slave_handle;
        snd_config_foreach(i, conf) {
                snd_config_t *n = snd_config_entry(i);
                if (strcmp(n->id, "comment") == 0)
@@ -563,43 +563,47 @@ static int _snd_pcm_open_plug(snd_pcm_t **handlep, snd_config_t *conf,
                        continue;
                if (strcmp(n->id, "stream") == 0)
                        continue;
-               if (strcmp(n->id, "card") == 0) {
-                       err = snd_config_integer_get(n, &card);
-                       if (err < 0) {
-                               err = snd_config_string_get(n, &str);
-                               if (err < 0)
-                                       return -EINVAL;
-                               card = snd_card_get_index(str);
-                               if (card < 0)
-                                       return card;
-                       }
-                       continue;
-               }
-               if (strcmp(n->id, "device") == 0) {
-                       err = snd_config_integer_get(n, &device);
-                       if (err < 0)
-                               return err;
-                       continue;
-               }
-               if (strcmp(n->id, "subdevice") == 0) {
-                       err = snd_config_integer_get(n, &subdevice);
+               if (strcmp(n->id, "slave") == 0) {
+                       err = snd_config_string_get(n, &slave);
                        if (err < 0)
-                               return err;
+                               return -EINVAL;
                        continue;
                }
                return -EINVAL;
        }
-       if (card < 0 || device < 0)
+       if (!slave)
                return -EINVAL;
-       return snd_pcm_plug_open_subdevice(handlep, card, device, subdevice, stream, mode);
+       /* This is needed cause snd_config_update may destroy config */
+       slave = strdup(slave);
+       if (!slave)
+               return  -ENOMEM;
+       err = snd_pcm_open(&slave_handle, slave, stream, mode);
+       free(slave);
+       if (err < 0)
+               return err;
+       err = snd_pcm_plug_create(handlep, slave_handle, 1);
+       if (err < 0)
+               snd_pcm_close(slave_handle);
+       return err;
 }
                                
-static int _snd_pcm_open_multi(snd_pcm_t **handle, snd_config_t *conf, 
+static int _snd_pcm_open_multi(snd_pcm_t **handlep, snd_config_t *conf, 
                              int stream, int mode)
 {
-       snd_config_iterator_t i;
-       char *str;
+       snd_config_iterator_t i, j;
+       snd_config_t *slave = NULL;
+       snd_config_t *binding = NULL;
        int err;
+       unsigned int idx;
+       char **slaves_id = NULL;
+       char **slaves_name = NULL;
+       snd_pcm_t **slaves_handle = NULL;
+       size_t *slaves_channels = NULL;
+       unsigned int *bindings_cchannel = NULL;
+       unsigned int *bindings_slave = NULL;
+       unsigned int *bindings_schannel = NULL;
+       size_t slaves_count = 0;
+       size_t bindings_count = 0;
        snd_config_foreach(i, conf) {
                snd_config_t *n = snd_config_entry(i);
                if (strcmp(n->id, "comment") == 0)
@@ -611,18 +615,159 @@ static int _snd_pcm_open_multi(snd_pcm_t **handle, snd_config_t *conf,
                if (strcmp(n->id, "slave") == 0) {
                        if (snd_config_type(n) != SND_CONFIG_TYPE_COMPOUND)
                                return -EINVAL;
-                       /* Not yet implemented */
+                       slave = n;
                        continue;
                }
                if (strcmp(n->id, "binding") == 0) {
                        if (snd_config_type(n) != SND_CONFIG_TYPE_COMPOUND)
                                return -EINVAL;
-                       /* Not yet implemented */
+                       binding = n;
                        continue;
                }
                return -EINVAL;
        }
-       return -ENOSYS;
+       if (!slave || !binding)
+               return -EINVAL;
+       snd_config_foreach(i, slave) {
+               ++slaves_count;
+       }
+       snd_config_foreach(i, binding) {
+               ++bindings_count;
+       }
+       slaves_id = calloc(slaves_count, sizeof(*slaves_id));
+       slaves_name = calloc(slaves_count, sizeof(*slaves_name));
+       slaves_handle = calloc(slaves_count, sizeof(*slaves_handle));
+       slaves_channels = calloc(slaves_count, sizeof(*slaves_channels));
+       bindings_cchannel = calloc(bindings_count, sizeof(*bindings_cchannel));
+       bindings_slave = calloc(bindings_count, sizeof(*bindings_slave));
+       bindings_schannel = calloc(bindings_count, sizeof(*bindings_schannel));
+       idx = 0;
+       snd_config_foreach(i, slave) {
+               snd_config_t *m = snd_config_entry(i);
+               char *pcm = NULL;
+               long channels = -1;
+               slaves_id[idx] = snd_config_id(m);
+               snd_config_foreach(j, m) {
+                       snd_config_t *n = snd_config_entry(j);
+                       if (strcmp(n->id, "comment") == 0)
+                               continue;
+                       if (strcmp(n->id, "pcm") == 0) {
+                               err = snd_config_string_get(n, &pcm);
+                               if (err < 0)
+                                       goto _free;
+                               continue;
+                       }
+                       if (strcmp(n->id, "channels") == 0) {
+                               err = snd_config_integer_get(n, &channels);
+                               if (err < 0)
+                                       goto _free;
+                               continue;
+                       }
+                       err = -EINVAL;
+                       goto _free;
+               }
+               if (!pcm || channels < 0) {
+                       err = -EINVAL;
+                       goto _free;
+               }
+               slaves_name[idx] = strdup(pcm);
+               slaves_channels[idx] = channels;
+               ++idx;
+       }
+
+       idx = 0;
+       snd_config_foreach(i, binding) {
+               snd_config_t *m = snd_config_entry(i);
+               long cchannel = -1, schannel = -1;
+               int slave = -1;
+               long val;
+               char *str;
+               snd_config_foreach(j, m) {
+                       snd_config_t *n = snd_config_entry(j);
+                       if (strcmp(n->id, "comment") == 0)
+                               continue;
+                       if (strcmp(n->id, "client_channel") == 0) {
+                               err = snd_config_integer_get(n, &cchannel);
+                               if (err < 0)
+                                       goto _free;
+                               continue;
+                       }
+                       if (strcmp(n->id, "slave") == 0) {
+                               char buf[32];
+                               unsigned int k;
+                               err = snd_config_string_get(n, &str);
+                               if (err < 0) {
+                                       err = snd_config_integer_get(n, &val);
+                                       if (err < 0)
+                                               goto _free;
+                                       sprintf(buf, "%ld", val);
+                                       str = buf;
+                               }
+                               for (k = 0; k < slaves_count; ++k) {
+                                       if (strcmp(slaves_id[k], str) == 0)
+                                               slave = k;
+                               }
+                               continue;
+                       }
+                       if (strcmp(n->id, "slave_channel") == 0) {
+                               err = snd_config_integer_get(n, &schannel);
+                               if (err < 0)
+                                       goto _free;
+                               continue;
+                       }
+                       err = -EINVAL;
+                       goto _free;
+               }
+               if (cchannel < 0 || slave < 0 || schannel < 0) {
+                       err = -EINVAL;
+                       goto _free;
+               }
+               if ((size_t)slave >= slaves_count) {
+                       err = -EINVAL;
+                       goto _free;
+               }
+               if ((unsigned int) schannel >= slaves_channels[slave]) {
+                       err = -EINVAL;
+                       goto _free;
+               }
+               bindings_cchannel[idx] = cchannel;
+               bindings_slave[idx] = slave;
+               bindings_schannel[idx] = schannel;
+               ++idx;
+       }
+       
+       for (idx = 0; idx < slaves_count; ++idx) {
+               err = snd_pcm_open(&slaves_handle[idx], slaves_name[idx], stream, mode);
+               if (err < 0)
+                       goto _free;
+       }
+       err = snd_pcm_multi_create(handlep, slaves_count, slaves_handle,
+                                  slaves_channels,
+                                  bindings_count, bindings_cchannel,
+                                  bindings_slave, bindings_schannel,
+                                  1);
+_free:
+       if (err < 0) {
+               for (idx = 0; idx < slaves_count; ++idx) {
+                       if (slaves_handle[idx])
+                               snd_pcm_close(slaves_handle[idx]);
+                       if (slaves_name[idx])
+                               free(slaves_name[idx]);
+               }
+       }
+       if (slaves_name)
+               free(slaves_name);
+       if (slaves_handle)
+               free(slaves_handle);
+       if (slaves_channels)
+               free(slaves_channels);
+       if (bindings_cchannel)
+               free(bindings_cchannel);
+       if (bindings_slave)
+               free(bindings_slave);
+       if (bindings_schannel)
+               free(bindings_schannel);
+       return err;
 }
 
 int snd_pcm_open(snd_pcm_t **handlep, char *name, 
index 172aaf4644d2da22288ae9a869c7d038dab01980..7255dd9b4876ca8f0f56d1ac63307a1d1af03d7e 100644 (file)
@@ -47,8 +47,8 @@ typedef struct {
        snd_pcm_t *handle;
        size_t slaves_count;
        snd_pcm_multi_slave_t *slaves;
-       size_t binds_count;
-       snd_pcm_multi_bind_t *binds;
+       size_t bindings_count;
+       snd_pcm_multi_bind_t *bindings;
        size_t channels_count;
        size_t frames_alloc;
        int interleave;
@@ -77,7 +77,7 @@ static int snd_pcm_multi_close(void *private)
                        free(slave->iovec);
        }
        free(multi->slaves);
-       free(multi->binds);
+       free(multi->bindings);
        free(private);
        return ret;
 }
@@ -319,10 +319,10 @@ static int snd_pcm_multi_channel_setup(void *private, snd_pcm_channel_setup_t *s
        snd_pcm_multi_t *multi = (snd_pcm_multi_t*) private;
        unsigned int channel = setup->channel;
        unsigned int i;
-       for (i = 0; i < multi->binds_count; ++i) {
-               if (multi->binds[i].client_channel == channel) {
-                       setup->channel = multi->binds[i].slave_channel;
-                       err = snd_pcm_channel_setup(multi->slaves[multi->binds[i].slave].handle, setup);
+       for (i = 0; i < multi->bindings_count; ++i) {
+               if (multi->bindings[i].client_channel == channel) {
+                       setup->channel = multi->bindings[i].slave_channel;
+                       err = snd_pcm_channel_setup(multi->slaves[multi->bindings[i].slave].handle, setup);
                        setup->channel = channel;
                        return err;
                }
@@ -367,8 +367,8 @@ static int snd_pcm_multi_write_copy(snd_pcm_multi_t *multi, const 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];
+       for (i = 0; i < multi->bindings_count; ++i) {
+               snd_pcm_multi_bind_t *bind = &multi->bindings[i];
                snd_pcm_multi_slave_t *slave = &multi->slaves[bind->slave];
                int err;
                assert(slave->buf);
@@ -392,8 +392,8 @@ static int snd_pcm_multi_writev_copy(snd_pcm_multi_t *multi, const struct iovec
        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];
+       for (i = 0; i < multi->bindings_count; ++i) {
+               snd_pcm_multi_bind_t *bind = &multi->bindings[i];
                snd_pcm_multi_slave_t *slave = &multi->slaves[bind->slave];
                int err;
                area.addr = vec[bind->client_channel].iov_base + 
@@ -633,8 +633,8 @@ static int snd_pcm_multi_channels_mask(void *private, bitset_t *client_vmask)
        int err;
        for (i = 0; i < multi->slaves_count; ++i)
                vmasks[i] = bitset_alloc(multi->slaves[i].channels_total);
-       for (i = 0; i < multi->binds_count; ++i) {
-               snd_pcm_multi_bind_t *b = &multi->binds[i];
+       for (i = 0; i < multi->bindings_count; ++i) {
+               snd_pcm_multi_bind_t *b = &multi->bindings[i];
                if (bitset_get(client_vmask, b->client_channel))
                        bitset_set(vmasks[b->slave], b->slave_channel);
        }
@@ -648,8 +648,8 @@ static int snd_pcm_multi_channels_mask(void *private, bitset_t *client_vmask)
                }
        }
        bitset_zero(client_vmask, multi->handle->setup.format.channels);
-       for (i = 0; i < multi->binds_count; ++i) {
-               snd_pcm_multi_bind_t *b = &multi->binds[i];
+       for (i = 0; i < multi->bindings_count; ++i) {
+               snd_pcm_multi_bind_t *b = &multi->bindings[i];
                if (bitset_get(vmasks[b->slave], b->slave_channel))
                        bitset_set(client_vmask, b->client_channel);
        }
@@ -680,11 +680,11 @@ static void snd_pcm_multi_dump(void *private, FILE *fp)
                snd_pcm_dump(multi->slaves[k].handle, fp);
        }
        fprintf(fp, "\nBindings:\n");
-       for (k = 0; k < multi->binds_count; ++k) {
+       for (k = 0; k < multi->bindings_count; ++k) {
                fprintf(fp, "Channel #%d: slave %d[%d]\n", 
-                       multi->binds[k].client_channel,
-                       multi->binds[k].slave,
-                       multi->binds[k].slave_channel);
+                       multi->bindings[k].client_channel,
+                       multi->bindings[k].slave,
+                       multi->bindings[k].slave_channel);
        }
 }
 
@@ -724,9 +724,9 @@ struct snd_pcm_fast_ops snd_pcm_multi_fast_ops = {
 };
 
 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,
+                        snd_pcm_t **slaves_handle, size_t *schannels_count,
+                        size_t bindings_count,  unsigned int *bindings_cchannel,
+                        unsigned int *bindings_slave, unsigned int *bindings_schannel,
                         int close_slaves)
 {
        snd_pcm_t *handle;
@@ -738,8 +738,8 @@ int snd_pcm_multi_create(snd_pcm_t **handlep, size_t slaves_count,
        char slave_map[32][32] = { { 0 } };
 
        assert(handlep);
-       assert(slaves_count > 0 && slaves_handle && slaves_channels_count);
-       assert(binds_count > 0 && binds_slave && binds_client_channel && binds_slave_channel);
+       assert(slaves_count > 0 && slaves_handle && schannels_count);
+       assert(bindings_count > 0 && bindings_slave && bindings_cchannel && bindings_schannel);
 
        handle = calloc(1, sizeof(snd_pcm_t));
        if (!handle)
@@ -755,36 +755,36 @@ int snd_pcm_multi_create(snd_pcm_t **handlep, size_t slaves_count,
        multi->handle = handle;
        multi->slaves_count = slaves_count;
        multi->slaves = calloc(slaves_count, sizeof(*multi->slaves));
-       multi->binds_count = binds_count;
-       multi->binds = calloc(binds_count, sizeof(*multi->binds));
+       multi->bindings_count = bindings_count;
+       multi->bindings = calloc(bindings_count, sizeof(*multi->bindings));
        for (i = 0; i < slaves_count; ++i) {
                snd_pcm_multi_slave_t *slave = &multi->slaves[i];
                assert(slaves_handle[i]->stream == stream);
                slave->handle = slaves_handle[i];
-               slave->channels_total = slaves_channels_count[i];
+               slave->channels_total = schannels_count[i];
                slave->close_slave = close_slaves;
                if (i != 0)
                        snd_pcm_link(slaves_handle[i-1], slaves_handle[i]);
        }
-       for (i = 0; i < binds_count; ++i) {
-               snd_pcm_multi_bind_t *bind = &multi->binds[i];
-               assert(binds_slave[i] < slaves_count);
-               assert(binds_slave_channel[i] < slaves_channels_count[binds_slave[i]]);
-               bind->client_channel = binds_client_channel[i];
-               bind->slave = binds_slave[i];
-               bind->slave_channel = binds_slave_channel[i];
-               if (slave_map[binds_slave[i]][binds_slave_channel[i]]) {
+       for (i = 0; i < bindings_count; ++i) {
+               snd_pcm_multi_bind_t *bind = &multi->bindings[i];
+               assert(bindings_slave[i] < slaves_count);
+               assert(bindings_schannel[i] < schannels_count[bindings_slave[i]]);
+               bind->client_channel = bindings_cchannel[i];
+               bind->slave = bindings_slave[i];
+               bind->slave_channel = bindings_schannel[i];
+               if (slave_map[bindings_slave[i]][bindings_schannel[i]]) {
                        assert(stream == SND_PCM_STREAM_CAPTURE);
                        multi->one_to_many = 1;
                }
-               slave_map[binds_slave[i]][binds_slave_channel[i]] = 1;
-               if (client_map[binds_client_channel[i]]) {
+               slave_map[bindings_slave[i]][bindings_schannel[i]] = 1;
+               if (client_map[bindings_cchannel[i]]) {
                        assert(stream == SND_PCM_STREAM_PLAYBACK);
                        multi->one_to_many = 1;
                }
-               client_map[binds_client_channel[i]] = 1;
-               if (binds_client_channel[i] >= channels)
-                       channels = binds_client_channel[i] + 1;
+               client_map[bindings_cchannel[i]] = 1;
+               if (bindings_cchannel[i] >= channels)
+                       channels = bindings_cchannel[i] + 1;
        }
        multi->channels_count = channels;