From: Abramo Bagnara Date: Sat, 26 Aug 2000 08:10:53 +0000 (+0000) Subject: Added support for configured pcm_multi. Changed pcm_plug definition X-Git-Tag: v1.0.3~1165 X-Git-Url: https://git.alsa-project.org/?a=commitdiff_plain;h=1551ce741996d0469191517969b0e601977eb980;p=alsa-lib.git Added support for configured pcm_multi. Changed pcm_plug definition --- diff --git a/src/pcm/pcm.c b/src/pcm/pcm.c index 05982635..ef167b2a 100644 --- a/src/pcm/pcm.c +++ b/src/pcm/pcm.c @@ -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, diff --git a/src/pcm/pcm_multi.c b/src/pcm/pcm_multi.c index 172aaf46..7255dd9b 100644 --- a/src/pcm/pcm_multi.c +++ b/src/pcm/pcm_multi.c @@ -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;