diff options
Diffstat (limited to 'src/pcm/pcm_multi.c')
-rw-r--r-- | src/pcm/pcm_multi.c | 252 |
1 files changed, 81 insertions, 171 deletions
diff --git a/src/pcm/pcm_multi.c b/src/pcm/pcm_multi.c index 13c9f523..95f63478 100644 --- a/src/pcm/pcm_multi.c +++ b/src/pcm/pcm_multi.c @@ -31,6 +31,7 @@ typedef struct { snd_pcm_t *pcm; unsigned int channels_count; int close_slave; + unsigned int access_mask; } snd_pcm_multi_slave_t; typedef struct { @@ -43,7 +44,6 @@ typedef struct { snd_pcm_multi_slave_t *slaves; size_t channels_count; snd_pcm_multi_channel_t *channels; - int xfer_mode; } snd_pcm_multi_t; static int snd_pcm_multi_close(snd_pcm_t *pcm) @@ -91,176 +91,104 @@ static int snd_pcm_multi_info(snd_pcm_t *pcm, snd_pcm_info_t *info) return 0; } -static int snd_pcm_multi_params_info(snd_pcm_t *pcm, snd_pcm_params_info_t *info) +static int snd_pcm_multi_hw_info(snd_pcm_t *pcm, snd_pcm_hw_info_t *info) { snd_pcm_multi_t *multi = pcm->private; - unsigned int i; - int err; - 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; + unsigned int k; + snd_pcm_hw_info_t i; + unsigned int access_mask = ~0; + int err = 0; + if (info->channels_min < multi->channels_count) + info->channels_min = multi->channels_count; + if (info->channels_max > multi->channels_count) + info->channels_max = multi->channels_count; + if (info->channels_max > info->channels_max) 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 *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_count; - err = snd_pcm_params_info(slave_i, &info_i); + i = *info; + for (k = 0; k < multi->slaves_count; ++k) { + snd_pcm_t *slave = multi->slaves[k].pcm; + i.access_mask = SND_PCM_ACCBIT_MMAP; + i.channels_min = i.channels_max = multi->slaves[k].channels_count; + err = snd_pcm_hw_info(slave, &i); + access_mask &= i.access_mask; if (err < 0) - return err; - info->formats &= info_i.formats; - info->rates &= info_i.rates; - if (info_i.min_rate > info->min_rate) - info->min_rate = info_i.min_rate; - if (info_i.max_rate < info->max_rate) - info->max_rate = info_i.max_rate; - if (info_i.buffer_size < info->buffer_size) - info->buffer_size = info_i.buffer_size; - if (info_i.min_fragment_size > info->min_fragment_size) - info->min_fragment_size = info_i.min_fragment_size; - if (info_i.max_fragment_size < info->max_fragment_size) - info->max_fragment_size = info_i.max_fragment_size; - if (info_i.min_fragments > info->min_fragments) - info->min_fragments = info_i.min_fragments; - if (info_i.max_fragments < info->max_fragments) - info->max_fragments = info_i.max_fragments; - info->flags &= info_i.flags; + break; + multi->slaves[k].access_mask = i.access_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; + *info = i; + if (i.channels_min <= i.channels_max) + info->channels_min = info->channels_max = multi->channels_count; + if (i.access_mask) { + if (!(access_mask & SND_PCM_ACCBIT_MMAP_INTERLEAVED) || + multi->slaves_count > 1) + info->access_mask &= ~SND_PCM_ACCBIT_MMAP_INTERLEAVED; + if (!(access_mask & SND_PCM_ACCBIT_MMAP_NONINTERLEAVED)) + info->access_mask &= ~SND_PCM_ACCBIT_MMAP_NONINTERLEAVED; + } + return err; } -static int snd_pcm_multi_mmap(snd_pcm_t *pcm) +static int snd_pcm_multi_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) { snd_pcm_multi_t *multi = pcm->private; unsigned int i; - size_t count = 0; + snd_pcm_hw_params_t p; + int err; + if (params->channels != multi->channels_count) { + params->fail_mask = SND_PCM_HW_PARBIT_CHANNELS; + return -EINVAL; + } + p = *params; for (i = 0; i < multi->slaves_count; ++i) { snd_pcm_t *slave = multi->slaves[i].pcm; - snd_pcm_setup_t *setup; - int err = snd_pcm_mmap(slave); + if (multi->slaves[i].access_mask & SND_PCM_ACCBIT_MMAP_INTERLEAVED) + p.access = SND_PCM_ACCESS_MMAP_INTERLEAVED; + else if (multi->slaves[i].access_mask & SND_PCM_ACCBIT_MMAP_NONINTERLEAVED) + p.access = SND_PCM_ACCESS_MMAP_NONINTERLEAVED; + else + assert(0); + p.channels = multi->slaves[i].channels_count; + err = snd_pcm_hw_params(slave, &p); + if (err < 0) { + params->fail_mask = p.fail_mask; + return err; + } + err = snd_pcm_areas_silence(slave->running_areas, 0, slave->channels, slave->buffer_size, slave->format); if (err < 0) return err; - count += slave->mmap_info_count; - setup = &slave->setup; - if (pcm->stream == SND_PCM_STREAM_PLAYBACK) { - snd_pcm_channel_area_t r[setup->format.channels]; - snd_pcm_channel_area_t s[setup->format.channels]; - err = snd_pcm_mmap_get_areas(slave, s, r); - if (err < 0) - return err; - err = snd_pcm_areas_silence(s, 0, setup->format.channels, setup->buffer_size, setup->format.sfmt); - if (err < 0) - return err; - err = snd_pcm_areas_silence(r, 0, setup->format.channels, setup->buffer_size, setup->format.sfmt); + if (slave->stopped_areas) { + err = snd_pcm_areas_silence(slave->stopped_areas, 0, slave->channels, slave->buffer_size, slave->format); if (err < 0) return err; } } - pcm->mmap_info_count = count; - pcm->mmap_info = malloc(count * sizeof(*pcm->mmap_info)); - count = 0; - for (i = 0; i < multi->slaves_count; ++i) { - snd_pcm_t *slave = multi->slaves[i].pcm; - memcpy(&pcm->mmap_info[count], slave->mmap_info, slave->mmap_info_count * sizeof(*pcm->mmap_info)); - count += slave->mmap_info_count; - } return 0; } -static int snd_pcm_multi_munmap(snd_pcm_t *pcm) +static int snd_pcm_multi_sw_params(snd_pcm_t *pcm, snd_pcm_sw_params_t *params) { snd_pcm_multi_t *multi = pcm->private; unsigned int i; + int err; for (i = 0; i < multi->slaves_count; ++i) { snd_pcm_t *slave = multi->slaves[i].pcm; - int err = snd_pcm_munmap(slave); + err = snd_pcm_sw_params(slave, params); if (err < 0) return err; } - pcm->mmap_info_count = 0; - free(pcm->mmap_info); - pcm->mmap_info = 0; return 0; } - -static int snd_pcm_multi_params(snd_pcm_t *pcm, snd_pcm_params_t *params) + +static int snd_pcm_multi_dig_info(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_dig_info_t *info ATTRIBUTE_UNUSED) { - snd_pcm_multi_t *multi = pcm->private; - unsigned int i; - snd_pcm_params_t p; - 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; - } - p = *params; - for (i = 0; i < multi->slaves_count; ++i) { - snd_pcm_t *slave = multi->slaves[i].pcm; - p.format.channels = multi->slaves[i].channels_count; - err = snd_pcm_params_mmap(slave, &p); - if (err < 0) { - params->fail_mask = p.fail_mask; - params->fail_reason = p.fail_reason; - break; - } - } - if (err == 0) - multi->xfer_mode = params->xfer_mode; - return err; + /* FIXME */ + return -ENOSYS; } -static int snd_pcm_multi_setup(snd_pcm_t *pcm, snd_pcm_setup_t *setup) +static int snd_pcm_multi_dig_params(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_dig_params_t *params ATTRIBUTE_UNUSED) { - snd_pcm_multi_t *multi = pcm->private; - unsigned int i; - int err; - err = snd_pcm_setup(multi->slaves[0].pcm, setup); - if (err < 0) - return err; - for (i = 1; i < multi->slaves_count; ++i) { - snd_pcm_setup_t s; - snd_pcm_t *sh = multi->slaves[i].pcm; - err = snd_pcm_setup(sh, &s); - if (err < 0) - return err; - if (setup->format.rate != s.format.rate) - return -EINVAL; - if (setup->buffer_size != s.buffer_size) - return -EINVAL; - if (setup->mmap_shape != SND_PCM_MMAP_NONINTERLEAVED || - s.mmap_shape != SND_PCM_MMAP_NONINTERLEAVED) - setup->mmap_shape = SND_PCM_MMAP_COMPLEX; - } - setup->format.channels = multi->channels_count; - if (multi->xfer_mode == SND_PCM_XFER_UNSPECIFIED) - setup->xfer_mode = SND_PCM_XFER_NONINTERLEAVED; - else - setup->xfer_mode = multi->xfer_mode; - return 0; + /* FIXME */ + return -ENOSYS; } static int snd_pcm_multi_status(snd_pcm_t *pcm, snd_pcm_status_t *status) @@ -335,34 +263,6 @@ static int snd_pcm_multi_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t *in return err; } -static int snd_pcm_multi_channel_params(snd_pcm_t *pcm, snd_pcm_channel_params_t *params) -{ - snd_pcm_multi_t *multi = pcm->private; - unsigned int channel = params->channel; - 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 err; -} - -static int snd_pcm_multi_channel_setup(snd_pcm_t *pcm, snd_pcm_channel_setup_t *setup) -{ - snd_pcm_multi_t *multi = pcm->private; - unsigned int channel = setup->channel; - 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 err; -} - static ssize_t snd_pcm_multi_rewind(snd_pcm_t *pcm, size_t frames) { snd_pcm_multi_t *multi = pcm->private; @@ -413,6 +313,16 @@ static int snd_pcm_multi_set_avail_min(snd_pcm_t *pcm, size_t frames) return snd_pcm_set_avail_min(multi->slaves[0].pcm, frames); } +static int snd_pcm_multi_mmap(snd_pcm_t *pcm ATTRIBUTE_UNUSED) +{ + return 0; +} + +static int snd_pcm_multi_munmap(snd_pcm_t *pcm ATTRIBUTE_UNUSED) +{ + return 0; +} + int snd_pcm_multi_poll_descriptor(snd_pcm_t *pcm) { snd_pcm_multi_t *multi = pcm->private; @@ -433,7 +343,7 @@ static void snd_pcm_multi_dump(snd_pcm_t *pcm, FILE *fp) fprintf(fp, "%d: slave %d, channel %d\n", k, c->slave_idx, c->slave_channel); } - if (pcm->valid_setup) { + if (pcm->setup) { fprintf(fp, "\nIts setup is:\n"); snd_pcm_dump_setup(pcm, fp); } @@ -446,12 +356,12 @@ static void snd_pcm_multi_dump(snd_pcm_t *pcm, FILE *fp) snd_pcm_ops_t snd_pcm_multi_ops = { close: snd_pcm_multi_close, info: snd_pcm_multi_info, - params_info: snd_pcm_multi_params_info, - params: snd_pcm_multi_params, - setup: snd_pcm_multi_setup, + hw_info: snd_pcm_multi_hw_info, + hw_params: snd_pcm_multi_hw_params, + sw_params: snd_pcm_multi_sw_params, + dig_info: snd_pcm_multi_dig_info, + dig_params: snd_pcm_multi_dig_params, channel_info: snd_pcm_multi_channel_info, - channel_params: snd_pcm_multi_channel_params, - channel_setup: snd_pcm_multi_channel_setup, dump: snd_pcm_multi_dump, nonblock: snd_pcm_multi_nonblock, async: snd_pcm_multi_async, @@ -538,7 +448,7 @@ int snd_pcm_multi_open(snd_pcm_t **pcmp, char *name, pcm->type = SND_PCM_TYPE_MULTI; pcm->stream = stream; pcm->mode = multi->slaves[0].pcm->mode; - pcm->mmap_auto = 1; + pcm->mmap_rw = 1; pcm->ops = &snd_pcm_multi_ops; pcm->op_arg = pcm; pcm->fast_ops = &snd_pcm_multi_fast_ops; |