#include <string.h>
#include <errno.h>
#include <math.h>
-#include <sys/uio.h>
#include "pcm_local.h"
typedef struct {
- snd_pcm_t *handle;
- unsigned int channels_total;
+ snd_pcm_t *pcm;
+ unsigned int channels_count;
int close_slave;
} snd_pcm_multi_slave_t;
typedef struct {
- unsigned int client_channel;
- unsigned int slave;
+ int slave_idx;
unsigned int slave_channel;
-} snd_pcm_multi_bind_t;
+} snd_pcm_multi_channel_t;
typedef struct {
size_t slaves_count;
snd_pcm_multi_slave_t *slaves;
- size_t bindings_count;
- snd_pcm_multi_bind_t *bindings;
size_t channels_count;
- int xfer_mode, mmap_shape;
+ snd_pcm_multi_channel_t *channels;
+ int xfer_mode;
} snd_pcm_multi_t;
static int snd_pcm_multi_close(snd_pcm_t *pcm)
int err;
snd_pcm_multi_slave_t *slave = &multi->slaves[i];
if (slave->close_slave) {
- err = snd_pcm_close(slave->handle);
+ err = snd_pcm_close(slave->pcm);
if (err < 0)
ret = err;
} else
- snd_pcm_unlink(slave->handle);
+ snd_pcm_unlink(slave->pcm);
}
free(multi->slaves);
- free(multi->bindings);
+ free(multi->channels);
free(multi);
return ret;
}
-static int snd_pcm_multi_nonblock(snd_pcm_t *pcm, int nonblock)
+static int snd_pcm_multi_nonblock(snd_pcm_t *pcm ATTRIBUTE_UNUSED, int nonblock ATTRIBUTE_UNUSED)
{
- snd_pcm_multi_t *multi = pcm->private;
- snd_pcm_t *handle = multi->slaves[0].handle;
- return snd_pcm_nonblock(handle, nonblock);
+ return 0;
}
static int snd_pcm_multi_info(snd_pcm_t *pcm, snd_pcm_info_t *info)
{
snd_pcm_multi_t *multi = pcm->private;
int err;
- snd_pcm_t *handle_0 = multi->slaves[0].handle;
+ snd_pcm_t *slave_0 = multi->slaves[0].pcm;
/* FIXME */
- err = snd_pcm_info(handle_0, info);
+ err = snd_pcm_info(slave_0, info);
if (err < 0)
return err;
return 0;
snd_pcm_multi_t *multi = pcm->private;
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 |
- SND_PCM_PARAMS_MMAP_SHAPE |
- SND_PCM_PARAMS_XFER_MODE);
- err = snd_pcm_params_info(handle_0, info);
+ snd_pcm_t *slave_0 = multi->slaves[0].pcm;
+ unsigned int req_mask = info->req_mask;
+ unsigned int channels = info->req.format.channels;
+ if ((req_mask & SND_PCM_PARAMS_CHANNELS) &&
+ channels != multi->channels_count) {
+ info->req.fail_mask |= SND_PCM_PARAMS_CHANNELS;
+ info->req.fail_reason = SND_PCM_PARAMS_FAIL_INVAL;
+ return -EINVAL;
+ }
+ info->req_mask |= SND_PCM_PARAMS_CHANNELS;
+ info->req.format.channels = multi->slaves[0].channels_count;
+ err = snd_pcm_params_info(slave_0, info);
+ info->req_mask = req_mask;
+ info->req.format.channels = channels;
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_t *slave_i = multi->slaves[i].pcm;
snd_pcm_params_info_t info_i;
info_i = *info;
info_i.req_mask |= SND_PCM_PARAMS_CHANNELS;
- info_i.req.format.channels = multi->slaves[i].channels_total;
- err = snd_pcm_params_info(handle_i, &info_i);
+ info_i.req.format.channels = multi->slaves[i].channels_count;
+ err = snd_pcm_params_info(slave_i, &info_i);
if (err < 0)
return err;
info->formats &= info_i.formats;
info->max_fragments = info_i.max_fragments;
info->flags &= info_i.flags;
}
- info->req_mask = old_mask;
+ if (info->flags & SND_PCM_INFO_INTERLEAVED) {
+ if (multi->slaves_count > 0) {
+ info->flags &= ~SND_PCM_INFO_INTERLEAVED;
+ info->flags |= SND_PCM_INFO_COMPLEX;
+ }
+ } else if (!(info->flags & SND_PCM_INFO_NONINTERLEAVED))
+ info->flags |= SND_PCM_INFO_COMPLEX;
+ info->req_mask = req_mask;
return 0;
}
snd_pcm_multi_t *multi = pcm->private;
unsigned int i;
snd_pcm_params_t p;
- if (params->format.channels != multi->channels_count)
+ int err = 0;
+ if (params->format.channels != multi->channels_count) {
+ params->fail_mask = SND_PCM_PARAMS_CHANNELS;
+ params->fail_reason = SND_PCM_PARAMS_FAIL_INVAL;
return -EINVAL;
- multi->xfer_mode = params->xfer_mode;
- multi->mmap_shape = params->mmap_shape;
+ }
p = *params;
for (i = 0; i < multi->slaves_count; ++i) {
- int err;
- snd_pcm_t *handle = multi->slaves[i].handle;
- if (handle->mmap_data) {
- err = snd_pcm_munmap_data(handle);
+ snd_pcm_t *slave = multi->slaves[i].pcm;
+ if (slave->mmap_data) {
+ err = snd_pcm_munmap_data(slave);
if (err < 0)
return err;
}
- p.xfer_mode = SND_PCM_XFER_UNSPECIFIED;
- p.mmap_shape = SND_PCM_MMAP_UNSPECIFIED;
- p.format.channels = multi->slaves[i].channels_total;
+ p.format.channels = multi->slaves[i].channels_count;
#if 1
- p.xrun_max = ~0;
+ p.xrun_mode = SND_PCM_XRUN_NONE;
#endif
- err = snd_pcm_params(handle, &p);
+ err = snd_pcm_params(slave, &p);
if (err < 0) {
params->fail_mask = p.fail_mask;
params->fail_reason = p.fail_reason;
- return err;
+ break;
}
}
for (i = 0; i < multi->slaves_count; ++i) {
- snd_pcm_t *handle = multi->slaves[i].handle;
- int err = snd_pcm_mmap_data(handle, NULL);
- if (err < 0)
- return err;
- if (pcm->stream == SND_PCM_STREAM_PLAYBACK)
- snd_pcm_areas_silence(handle->mmap_areas, 0, handle->setup.format.channels,
- handle->setup.buffer_size, handle->setup.format.sfmt);
+ snd_pcm_t *slave = multi->slaves[i].pcm;
+ snd_pcm_mmap_data(slave, NULL);
+ if (pcm->stream == SND_PCM_STREAM_PLAYBACK &&
+ err == 0)
+ snd_pcm_areas_silence(slave->mmap_areas, 0, slave->setup.format.channels,
+ slave->setup.buffer_size, slave->setup.format.sfmt);
}
- return 0;
+ if (err == 0)
+ multi->xfer_mode = params->xfer_mode;
+ return err;
}
static int snd_pcm_multi_setup(snd_pcm_t *pcm, snd_pcm_setup_t *setup)
snd_pcm_multi_t *multi = pcm->private;
unsigned int i;
int err;
- size_t frames_alloc;
- err = snd_pcm_setup(multi->slaves[0].handle, setup);
+ err = snd_pcm_setup(multi->slaves[0].pcm, setup);
if (err < 0)
return err;
- frames_alloc = multi->slaves[0].handle->setup.frag_size;
for (i = 1; i < multi->slaves_count; ++i) {
snd_pcm_setup_t s;
- snd_pcm_t *sh = multi->slaves[i].handle;
+ snd_pcm_t *sh = multi->slaves[i].pcm;
err = snd_pcm_setup(sh, &s);
if (err < 0)
return err;
setup->xfer_mode = SND_PCM_XFER_NONINTERLEAVED;
else
setup->xfer_mode = multi->xfer_mode;
- if (multi->mmap_shape != SND_PCM_MMAP_UNSPECIFIED &&
- multi->mmap_shape != setup->mmap_shape)
- return -EINVAL;
return 0;
}
static int snd_pcm_multi_status(snd_pcm_t *pcm, snd_pcm_status_t *status)
{
snd_pcm_multi_t *multi = pcm->private;
- snd_pcm_t *handle = multi->slaves[0].handle;
- return snd_pcm_status(handle, status);
+ snd_pcm_t *slave = multi->slaves[0].pcm;
+ return snd_pcm_status(slave, status);
}
static int snd_pcm_multi_state(snd_pcm_t *pcm)
{
snd_pcm_multi_t *multi = pcm->private;
- snd_pcm_t *handle = multi->slaves[0].handle;
- return snd_pcm_state(handle);
+ snd_pcm_t *slave = multi->slaves[0].pcm;
+ return snd_pcm_state(slave);
}
static int snd_pcm_multi_delay(snd_pcm_t *pcm, ssize_t *delayp)
{
snd_pcm_multi_t *multi = pcm->private;
- snd_pcm_t *handle = multi->slaves[0].handle;
- return snd_pcm_delay(handle, delayp);
+ snd_pcm_t *slave = multi->slaves[0].pcm;
+ return snd_pcm_delay(slave, delayp);
}
static ssize_t snd_pcm_multi_avail_update(snd_pcm_t *pcm)
{
snd_pcm_multi_t *multi = pcm->private;
- snd_pcm_t *handle = multi->slaves[0].handle;
- return snd_pcm_avail_update(handle);
+ snd_pcm_t *slave = multi->slaves[0].pcm;
+ return snd_pcm_avail_update(slave);
}
static int snd_pcm_multi_prepare(snd_pcm_t *pcm)
{
snd_pcm_multi_t *multi = pcm->private;
- return snd_pcm_prepare(multi->slaves[0].handle);
+ return snd_pcm_prepare(multi->slaves[0].pcm);
}
static int snd_pcm_multi_start(snd_pcm_t *pcm)
{
snd_pcm_multi_t *multi = pcm->private;
- return snd_pcm_start(multi->slaves[0].handle);
+ return snd_pcm_start(multi->slaves[0].pcm);
}
-static int snd_pcm_multi_stop(snd_pcm_t *pcm)
+static int snd_pcm_multi_drop(snd_pcm_t *pcm)
{
snd_pcm_multi_t *multi = pcm->private;
- return snd_pcm_stop(multi->slaves[0].handle);
+ return snd_pcm_drop(multi->slaves[0].pcm);
}
static int snd_pcm_multi_drain(snd_pcm_t *pcm)
{
snd_pcm_multi_t *multi = pcm->private;
- return snd_pcm_drain(multi->slaves[0].handle);
+ return snd_pcm_drain(multi->slaves[0].pcm);
}
static int snd_pcm_multi_pause(snd_pcm_t *pcm, int enable)
{
snd_pcm_multi_t *multi = pcm->private;
- return snd_pcm_pause(multi->slaves[0].handle, enable);
+ return snd_pcm_pause(multi->slaves[0].pcm, enable);
}
static int snd_pcm_multi_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t *info)
{
- int err;
snd_pcm_multi_t *multi = pcm->private;
unsigned int channel = info->channel;
- unsigned int i;
- for (i = 0; i < multi->bindings_count; ++i) {
- if (multi->bindings[i].client_channel == channel) {
- info->channel = multi->bindings[i].slave_channel;
- err = snd_pcm_channel_info(multi->slaves[multi->bindings[i].slave].handle, info);
- info->channel = channel;
- return err;
- }
- }
+ snd_pcm_multi_channel_t *c = &multi->channels[channel];
+ int err;
+ if (c->slave_idx < 0)
+ return -ENXIO;
+ info->channel = c->slave_channel;
+ err = snd_pcm_channel_info(multi->slaves[c->slave_idx].pcm, info);
info->channel = channel;
- return -EINVAL;
+ return err;
}
static int snd_pcm_multi_channel_params(snd_pcm_t *pcm, snd_pcm_channel_params_t *params)
{
- int err;
snd_pcm_multi_t *multi = pcm->private;
unsigned int channel = params->channel;
- unsigned int i;
- for (i = 0; i < multi->bindings_count; ++i) {
- if (multi->bindings[i].client_channel == channel) {
- params->channel = multi->bindings[i].slave_channel;
- err = snd_pcm_channel_params(multi->slaves[multi->bindings[i].slave].handle, params);
- params->channel = channel;
- return err;
- }
- }
+ snd_pcm_multi_channel_t *c = &multi->channels[channel];
+ int err;
+ if (c->slave_idx < 0)
+ return -ENXIO;
+ params->channel = c->slave_channel;
+ err = snd_pcm_channel_params(multi->slaves[c->slave_idx].pcm, params);
params->channel = channel;
- return -EINVAL;
+ return err;
}
static int snd_pcm_multi_channel_setup(snd_pcm_t *pcm, snd_pcm_channel_setup_t *setup)
{
- int err;
snd_pcm_multi_t *multi = pcm->private;
unsigned int channel = setup->channel;
- unsigned int i;
- 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;
- }
- }
- memset(setup, 0, sizeof(*setup));
+ snd_pcm_multi_channel_t *c = &multi->channels[channel];
+ int err;
+ if (c->slave_idx < 0)
+ return -ENXIO;
+ setup->channel = c->slave_channel;
+ err = snd_pcm_channel_setup(multi->slaves[c->slave_idx].pcm, setup);
setup->channel = channel;
- return 0;
+ return err;
}
static ssize_t snd_pcm_multi_rewind(snd_pcm_t *pcm, size_t frames)
size_t pos[multi->slaves_count];
memset(pos, 0, sizeof(pos));
for (i = 0; i < multi->slaves_count; ++i) {
- snd_pcm_t *handle_i = multi->slaves[i].handle;
- ssize_t f = snd_pcm_rewind(handle_i, frames);
+ snd_pcm_t *slave_i = multi->slaves[i].pcm;
+ ssize_t f = snd_pcm_rewind(slave_i, frames);
if (f < 0)
return f;
pos[i] = f;
}
/* Realign the pointers */
for (i = 0; i < multi->slaves_count; ++i) {
- snd_pcm_t *handle_i = multi->slaves[i].handle;
+ snd_pcm_t *slave_i = multi->slaves[i].pcm;
size_t f = pos[i] - frames;
if (f > 0)
- snd_pcm_mmap_appl_forward(handle_i, f);
+ snd_pcm_mmap_appl_forward(slave_i, f);
}
return frames;
}
static int snd_pcm_multi_mmap_status(snd_pcm_t *pcm)
{
snd_pcm_multi_t *multi = pcm->private;
- pcm->mmap_status = multi->slaves[0].handle->mmap_status;
+ pcm->mmap_status = multi->slaves[0].pcm->mmap_status;
return 0;
}
static int snd_pcm_multi_mmap_control(snd_pcm_t *pcm)
{
snd_pcm_multi_t *multi = pcm->private;
- pcm->mmap_control = multi->slaves[0].handle->mmap_control;
+ pcm->mmap_control = multi->slaves[0].pcm->mmap_control;
return 0;
}
snd_pcm_multi_t *multi = pcm->private;
unsigned int i;
for (i = 0; i < multi->slaves_count; ++i) {
- snd_pcm_t *handle = multi->slaves[i].handle;
- int err = snd_pcm_mmap_data(handle, 0);
+ snd_pcm_t *slave = multi->slaves[i].pcm;
+ int err = snd_pcm_mmap_data(slave, 0);
snd_pcm_setup_t *setup;
if (err < 0)
return err;
- setup = &handle->setup;
+ setup = &slave->setup;
if (pcm->stream == SND_PCM_STREAM_PLAYBACK) {
snd_pcm_channel_area_t areas[setup->format.channels];
- err = snd_pcm_mmap_get_areas(handle, areas);
+ err = snd_pcm_mmap_get_areas(slave, areas);
if (err < 0)
return err;
err = snd_pcm_areas_silence(areas, 0, setup->format.channels, setup->buffer_size, setup->format.sfmt);
return err;
}
}
- pcm->mmap_data = multi->slaves[0].handle->mmap_data;
+ pcm->mmap_data = multi->slaves[0].pcm->mmap_data;
return 0;
}
unsigned int i;
int ret = 0;
for (i = 0; i < multi->slaves_count; ++i) {
- snd_pcm_t *handle = multi->slaves[i].handle;
- int err = snd_pcm_munmap_data(handle);
+ snd_pcm_t *slave = multi->slaves[i].pcm;
+ int err = snd_pcm_munmap_data(slave);
if (err < 0)
ret = err;
}
unsigned int i;
for (i = 0; i < multi->slaves_count; ++i) {
- snd_pcm_t *handle = multi->slaves[i].handle;
- ssize_t frames = snd_pcm_mmap_forward(handle, size);
+ snd_pcm_t *slave = multi->slaves[i].pcm;
+ ssize_t frames = snd_pcm_mmap_forward(slave, size);
if (frames < 0)
return frames;
if (i == 0) {
bitset_t *cmasks[multi->slaves_count];
int err;
for (i = 0; i < multi->slaves_count; ++i)
- cmasks[i] = bitset_alloc(multi->slaves[i].channels_total);
- for (i = 0; i < multi->bindings_count; ++i) {
- snd_pcm_multi_bind_t *b = &multi->bindings[i];
- if (bitset_get(cmask, b->client_channel))
- bitset_set(cmasks[b->slave], b->slave_channel);
+ cmasks[i] = bitset_alloc(multi->slaves[i].channels_count);
+ for (i = 0; i < multi->channels_count; ++i) {
+ snd_pcm_multi_channel_t *b = &multi->channels[i];
+ if (b->slave_idx < 0)
+ continue;
+ if (bitset_get(cmask, i))
+ bitset_set(cmasks[b->slave_idx], b->slave_channel);
}
for (i = 0; i < multi->slaves_count; ++i) {
- snd_pcm_t *handle = multi->slaves[i].handle;
- err = snd_pcm_channels_mask(handle, cmasks[i]);
+ snd_pcm_t *slave = multi->slaves[i].pcm;
+ err = snd_pcm_channels_mask(slave, cmasks[i]);
if (err < 0) {
for (i = 0; i <= multi->slaves_count; ++i)
free(cmasks[i]);
}
}
bitset_zero(cmask, pcm->setup.format.channels);
- for (i = 0; i < multi->bindings_count; ++i) {
- snd_pcm_multi_bind_t *b = &multi->bindings[i];
- if (bitset_get(cmasks[b->slave], b->slave_channel))
- bitset_set(cmask, b->client_channel);
+ for (i = 0; i < multi->channels_count; ++i) {
+ snd_pcm_multi_channel_t *b = &multi->channels[i];
+ if (b->slave_idx < 0)
+ continue;
+ if (bitset_get(cmasks[b->slave_idx], b->slave_channel))
+ bitset_set(cmask, i);
}
for (i = 0; i < multi->slaves_count; ++i)
free(cmasks[i]);
int snd_pcm_multi_poll_descriptor(snd_pcm_t *pcm)
{
snd_pcm_multi_t *multi = pcm->private;
- snd_pcm_t *handle = multi->slaves[0].handle;
- return snd_pcm_poll_descriptor(handle);
+ snd_pcm_t *slave = multi->slaves[0].pcm;
+ return snd_pcm_poll_descriptor(slave);
}
static void snd_pcm_multi_dump(snd_pcm_t *pcm, FILE *fp)
}
for (k = 0; k < multi->slaves_count; ++k) {
fprintf(fp, "\nSlave #%d: ", k);
- snd_pcm_dump(multi->slaves[k].handle, fp);
+ snd_pcm_dump(multi->slaves[k].pcm, fp);
}
- fprintf(fp, "\nBindings:\n");
- for (k = 0; k < multi->bindings_count; ++k) {
+ fprintf(fp, "\nChannel bindings:\n");
+ for (k = 0; k < multi->channels_count; ++k) {
+ snd_pcm_multi_channel_t *c = &multi->channels[k];
+ if (c->slave_idx < 0)
+ continue;
fprintf(fp, "Channel #%d: slave %d[%d]\n",
- multi->bindings[k].client_channel,
- multi->bindings[k].slave,
- multi->bindings[k].slave_channel);
+ k, c->slave_idx, c->slave_channel);
}
}
delay: snd_pcm_multi_delay,
prepare: snd_pcm_multi_prepare,
start: snd_pcm_multi_start,
- stop: snd_pcm_multi_stop,
+ drop: snd_pcm_multi_drop,
drain: snd_pcm_multi_drain,
pause: snd_pcm_multi_pause,
writei: snd_pcm_mmap_writei,
int snd_pcm_multi_create(snd_pcm_t **handlep, size_t slaves_count,
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,
+ size_t channels_count,
+ int *sidxs, unsigned int *schannels,
int close_slaves)
{
snd_pcm_t *handle;
snd_pcm_multi_t *multi;
- size_t channels = 0;
unsigned int i;
int err;
int stream;
- char client_map[32] = { 0 };
char slave_map[32][32] = { { 0 } };
assert(handlep);
assert(slaves_count > 0 && slaves_handle && schannels_count);
- assert(bindings_count > 0 && bindings_slave && bindings_cchannel && bindings_schannel);
+ assert(channels_count > 0 && sidxs && schannels);
multi = calloc(1, sizeof(snd_pcm_multi_t));
if (!multi) {
multi->slaves_count = slaves_count;
multi->slaves = calloc(slaves_count, sizeof(*multi->slaves));
- multi->bindings_count = bindings_count;
- multi->bindings = calloc(bindings_count, sizeof(*multi->bindings));
+ multi->channels_count = channels_count;
+ multi->channels = calloc(channels_count, sizeof(*multi->channels));
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 = schannels_count[i];
+ slave->pcm = slaves_handle[i];
+ slave->channels_count = 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 < 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];
- assert(!slave_map[bindings_slave[i]][bindings_schannel[i]]);
- slave_map[bindings_slave[i]][bindings_schannel[i]] = 1;
- assert(!client_map[bindings_cchannel[i]]);
- client_map[bindings_cchannel[i]] = 1;
- if (bindings_cchannel[i] >= channels)
- channels = bindings_cchannel[i] + 1;
+ for (i = 0; i < channels_count; ++i) {
+ snd_pcm_multi_channel_t *bind = &multi->channels[i];
+ assert(sidxs[i] < (int)slaves_count);
+ assert(schannels[i] < schannels_count[sidxs[i]]);
+ bind->slave_idx = sidxs[i];
+ bind->slave_channel = schannels[i];
+ if (sidxs[i] < 0)
+ continue;
+ assert(!slave_map[sidxs[i]][schannels[i]]);
+ slave_map[sidxs[i]][schannels[i]] = 1;
}
- multi->channels_count = channels;
+ multi->channels_count = channels_count;
handle = calloc(1, sizeof(snd_pcm_t));
if (!handle) {
}
handle->type = SND_PCM_TYPE_MULTI;
handle->stream = stream;
- handle->mode = multi->slaves[0].handle->mode;
+ handle->mode = multi->slaves[0].pcm->mode;
handle->ops = &snd_pcm_multi_ops;
handle->op_arg = handle;
handle->fast_ops = &snd_pcm_multi_fast_ops;
char **slaves_name = NULL;
snd_pcm_t **slaves_pcm = NULL;
size_t *slaves_channels = NULL;
- unsigned int *bindings_cchannel = NULL;
- unsigned int *bindings_slave = NULL;
- unsigned int *bindings_schannel = NULL;
+ unsigned int *channels_sidx = NULL;
+ unsigned int *channels_schannel = NULL;
size_t slaves_count = 0;
- size_t bindings_count = 0;
+ size_t channels_count = 0;
snd_config_foreach(i, conf) {
snd_config_t *n = snd_config_entry(i);
if (strcmp(n->id, "comment") == 0)
++slaves_count;
}
snd_config_foreach(i, binding) {
- ++bindings_count;
+ int cchannel = -1;
+ char *p;
+ snd_config_t *m = snd_config_entry(i);
+ errno = 0;
+ cchannel = strtol(m->id, &p, 10);
+ if (errno || *p || cchannel < 0)
+ return -EINVAL;
+ if ((unsigned)cchannel > channels_count)
+ channels_count = cchannel + 1;
}
+ if (channels_count == 0)
+ return -EINVAL;
slaves_id = calloc(slaves_count, sizeof(*slaves_id));
slaves_name = calloc(slaves_count, sizeof(*slaves_name));
slaves_pcm = calloc(slaves_count, sizeof(*slaves_pcm));
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));
+ channels_sidx = calloc(channels_count, sizeof(*channels_sidx));
+ channels_schannel = calloc(channels_count, sizeof(*channels_schannel));
idx = 0;
+ for (idx = 0; idx < channels_count; ++idx)
+ channels_sidx[idx] = -1;
snd_config_foreach(i, slave) {
snd_config_t *m = snd_config_entry(i);
- char *pcm = NULL;
+ char *name = 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 (strcmp(n->id, "name") == 0) {
+ err = snd_config_string_get(n, &name);
if (err < 0)
goto _free;
continue;
err = -EINVAL;
goto _free;
}
- if (!pcm || channels < 0) {
+ if (!name || channels < 0) {
err = -EINVAL;
goto _free;
}
- slaves_name[idx] = strdup(pcm);
+ slaves_name[idx] = strdup(name);
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;
+ long cchannel = -1;
+ long schannel = -1;
int slave = -1;
long val;
char *str;
+ cchannel = strtol(m->id, 0, 10);
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) {
+ if (strcmp(n->id, "sidx") == 0) {
char buf[32];
unsigned int k;
err = snd_config_string_get(n, &str);
}
continue;
}
- if (strcmp(n->id, "slave_channel") == 0) {
+ if (strcmp(n->id, "schannel") == 0) {
err = snd_config_integer_get(n, &schannel);
if (err < 0)
goto _free;
err = -EINVAL;
goto _free;
}
- bindings_cchannel[idx] = cchannel;
- bindings_slave[idx] = slave;
- bindings_schannel[idx] = schannel;
- ++idx;
+ channels_sidx[cchannel] = slave;
+ channels_schannel[cchannel] = schannel;
}
for (idx = 0; idx < slaves_count; ++idx) {
}
err = snd_pcm_multi_create(pcmp, slaves_count, slaves_pcm,
slaves_channels,
- bindings_count, bindings_cchannel,
- bindings_slave, bindings_schannel,
+ channels_count,
+ channels_sidx, channels_schannel,
1);
_free:
if (err < 0) {
free(slaves_pcm);
if (slaves_channels)
free(slaves_channels);
- if (bindings_cchannel)
- free(bindings_cchannel);
- if (bindings_slave)
- free(bindings_slave);
- if (bindings_schannel)
- free(bindings_schannel);
+ if (channels_sidx)
+ free(channels_sidx);
+ if (channels_schannel)
+ free(channels_schannel);
return err;
}