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)
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)
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,
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;
free(slave->iovec);
}
free(multi->slaves);
- free(multi->binds);
+ free(multi->bindings);
free(private);
return ret;
}
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;
}
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);
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 +
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);
}
}
}
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);
}
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);
}
}
};
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;
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)
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;