From 3126678e72a0e7a4a511cbbcf0a103420682d1f4 Mon Sep 17 00:00:00 2001 From: Abramo Bagnara Date: Thu, 18 Jan 2001 18:20:31 +0000 Subject: [PATCH] Major cleaning to hw_params mechanism for plugins --- src/pcm/interval.c | 18 ++- src/pcm/pcm_adpcm.c | 134 +++++++++-------- src/pcm/pcm_alaw.c | 137 ++++++++--------- src/pcm/pcm_copy.c | 84 ++++++----- src/pcm/pcm_linear.c | 126 ++++++++-------- src/pcm/pcm_local.h | 64 ++++---- src/pcm/pcm_mulaw.c | 129 ++++++++-------- src/pcm/pcm_multi.c | 276 ++++++++++++++++++++-------------- src/pcm/pcm_null.c | 2 +- src/pcm/pcm_params.c | 297 +++++++++++++++++++++---------------- src/pcm/pcm_plug.c | 344 ++++++++++++++++++++----------------------- src/pcm/pcm_plugin.c | 12 ++ src/pcm/pcm_plugin.h | 2 + src/pcm/pcm_rate.c | 151 +++++++++++-------- src/pcm/pcm_route.c | 145 +++++++++--------- src/pcm/pcm_share.c | 163 ++++++++++++-------- src/pcm/pcm_shm.c | 127 ++++++++-------- 17 files changed, 1213 insertions(+), 998 deletions(-) diff --git a/src/pcm/interval.c b/src/pcm/interval.c index fb39af3d..c7967bc6 100644 --- a/src/pcm/interval.c +++ b/src/pcm/interval.c @@ -38,19 +38,28 @@ static inline void div64_32(u_int64_t *n, u_int32_t div, u_int32_t *rem) static inline unsigned int div32(unsigned int a, unsigned int b, unsigned int *r) { + if (b == 0) { + *r = 0; + return UINT_MAX; + } *r = a % b; return a / b; } static inline unsigned int div_down(unsigned int a, unsigned int b) { + if (b == 0) + return UINT_MAX; return a / b; } static inline unsigned int div_up(unsigned int a, unsigned int b) { unsigned int r; - unsigned int q = div32(a, b, &r); + unsigned int q; + if (b == 0) + return UINT_MAX; + q = div32(a, b, &r); if (r) ++q; return q; @@ -83,6 +92,11 @@ static inline unsigned int muldiv32(unsigned int a, unsigned int b, unsigned int c, unsigned int *r) { u_int64_t n = (u_int64_t) a * b; + if (c == 0) { + assert(n > 0); + *r = 0; + return UINT_MAX; + } div64_32(&n, c, r); if (n >= UINT_MAX) { *r = 0; @@ -359,7 +373,7 @@ void interval_print(const interval_t *i, snd_output_t *out) else if (i->min == 0 && i->openmin == 0 && i->max == UINT_MAX && i->openmax == 0) snd_output_printf(out, "ALL"); - else if (interval_single(i)) + else if (interval_single(i) && i->integer) snd_output_printf(out, "%u", interval_value(i)); else snd_output_printf(out, "%c%u %u%c", diff --git a/src/pcm/pcm_adpcm.c b/src/pcm/pcm_adpcm.c index 0e56a856..6928b677 100644 --- a/src/pcm/pcm_adpcm.c +++ b/src/pcm/pcm_adpcm.c @@ -329,103 +329,109 @@ static int snd_pcm_adpcm_close(snd_pcm_t *pcm) return 0; } -static int snd_pcm_adpcm_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) +static int snd_pcm_adpcm_hw_refine_cprepare(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) { snd_pcm_adpcm_t *adpcm = pcm->private; - snd_pcm_t *slave = adpcm->plug.slave; int err; - unsigned int cmask, lcmask; - snd_pcm_hw_params_t sparams; mask_t *access_mask = alloca(mask_sizeof()); - mask_t *saccess_mask = alloca(mask_sizeof()); mask_load(access_mask, SND_PCM_ACCBIT_PLUGIN); - mask_load(saccess_mask, SND_PCM_ACCBIT_MMAP); - cmask = params->cmask; - params->cmask = 0; err = _snd_pcm_hw_param_mask(params, SND_PCM_HW_PARAM_ACCESS, - access_mask); + access_mask); if (err < 0) return err; if (adpcm->sformat == SND_PCM_FORMAT_IMA_ADPCM) { mask_t *format_mask = alloca(mask_sizeof()); mask_load(format_mask, SND_PCM_FMTBIT_LINEAR); - err = _snd_pcm_hw_param_mask(params, - SND_PCM_HW_PARAM_FORMAT, - format_mask); - if (err < 0) - return err; + err = _snd_pcm_hw_param_mask(params, SND_PCM_HW_PARAM_FORMAT, + format_mask); } else { err = _snd_pcm_hw_param_set(params, SND_PCM_HW_PARAM_FORMAT, SND_PCM_FORMAT_IMA_ADPCM, 0); - if (err < 0) - return err; } - err = _snd_pcm_hw_param_set(params, SND_PCM_HW_PARAM_SUBFORMAT, - SND_PCM_SUBFORMAT_STD, 0); if (err < 0) return err; - lcmask = params->cmask; - params->cmask |= cmask; - - _snd_pcm_hw_params_any(&sparams); - _snd_pcm_hw_param_mask(&sparams, SND_PCM_HW_PARAM_ACCESS, - saccess_mask); - _snd_pcm_hw_param_set(&sparams, SND_PCM_HW_PARAM_FORMAT, - adpcm->sformat, 0); - _snd_pcm_hw_param_set(&sparams, SND_PCM_HW_PARAM_SUBFORMAT, - SND_PCM_SUBFORMAT_STD, 0); - err = snd_pcm_hw_refine2(params, &sparams, - snd_pcm_generic_hw_link, slave, - SND_PCM_HW_PARBIT_CHANNELS | - SND_PCM_HW_PARBIT_RATE | - SND_PCM_HW_PARBIT_PERIOD_SIZE | - SND_PCM_HW_PARBIT_BUFFER_SIZE | - SND_PCM_HW_PARBIT_PERIODS | - SND_PCM_HW_PARBIT_PERIOD_TIME | - SND_PCM_HW_PARBIT_BUFFER_TIME | - SND_PCM_HW_PARBIT_TICK_TIME); - params->cmask |= lcmask; + err = _snd_pcm_hw_param_set(params, SND_PCM_HW_PARAM_SUBFORMAT, + SND_PCM_SUBFORMAT_STD, 0); if (err < 0) return err; params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID); return 0; } -static int snd_pcm_adpcm_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params) +static int snd_pcm_adpcm_hw_refine_sprepare(snd_pcm_t *pcm, snd_pcm_hw_params_t *sparams) { snd_pcm_adpcm_t *adpcm = pcm->private; - snd_pcm_t *slave = adpcm->plug.slave; - int err; - snd_pcm_hw_params_t sparams; - unsigned int links; mask_t *saccess_mask = alloca(mask_sizeof()); mask_load(saccess_mask, SND_PCM_ACCBIT_MMAP); - - _snd_pcm_hw_params_any(&sparams); - _snd_pcm_hw_param_mask(&sparams, SND_PCM_HW_PARAM_ACCESS, + _snd_pcm_hw_params_any(sparams); + _snd_pcm_hw_param_mask(sparams, SND_PCM_HW_PARAM_ACCESS, saccess_mask); - _snd_pcm_hw_param_set(&sparams, SND_PCM_HW_PARAM_FORMAT, + _snd_pcm_hw_param_set(sparams, SND_PCM_HW_PARAM_FORMAT, adpcm->sformat, 0); - _snd_pcm_hw_param_set(&sparams, SND_PCM_HW_PARAM_SUBFORMAT, + _snd_pcm_hw_param_set(sparams, SND_PCM_HW_PARAM_SUBFORMAT, SND_PCM_SUBFORMAT_STD, 0); - links = SND_PCM_HW_PARBIT_CHANNELS | - SND_PCM_HW_PARBIT_RATE | - SND_PCM_HW_PARBIT_PERIOD_SIZE | - SND_PCM_HW_PARBIT_BUFFER_SIZE | - SND_PCM_HW_PARBIT_PERIODS | - SND_PCM_HW_PARBIT_PERIOD_TIME | - SND_PCM_HW_PARBIT_BUFFER_TIME | - SND_PCM_HW_PARBIT_TICK_TIME; - err = snd_pcm_hw_params_refine(&sparams, links, params); - assert(err >= 0); - err = snd_pcm_hw_params(slave, &sparams); - params->cmask = 0; - sparams.cmask = ~0U; - snd_pcm_hw_params_refine(params, links, &sparams); + return 0; +} + +static int snd_pcm_adpcm_hw_refine_schange(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params, + snd_pcm_hw_params_t *sparams) +{ + int err; + unsigned int links = (SND_PCM_HW_PARBIT_CHANNELS | + SND_PCM_HW_PARBIT_RATE | + SND_PCM_HW_PARBIT_PERIOD_SIZE | + SND_PCM_HW_PARBIT_BUFFER_SIZE | + SND_PCM_HW_PARBIT_PERIODS | + SND_PCM_HW_PARBIT_PERIOD_TIME | + SND_PCM_HW_PARBIT_BUFFER_TIME | + SND_PCM_HW_PARBIT_TICK_TIME); + err = _snd_pcm_hw_params_refine(sparams, links, params); if (err < 0) return err; - params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID); + return 0; +} + +static int snd_pcm_adpcm_hw_refine_cchange(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params, + snd_pcm_hw_params_t *sparams) +{ + int err; + unsigned int links = (SND_PCM_HW_PARBIT_CHANNELS | + SND_PCM_HW_PARBIT_RATE | + SND_PCM_HW_PARBIT_PERIOD_SIZE | + SND_PCM_HW_PARBIT_BUFFER_SIZE | + SND_PCM_HW_PARBIT_PERIODS | + SND_PCM_HW_PARBIT_PERIOD_TIME | + SND_PCM_HW_PARBIT_BUFFER_TIME | + SND_PCM_HW_PARBIT_TICK_TIME); + err = _snd_pcm_hw_params_refine(params, links, sparams); + if (err < 0) + return err; + return 0; +} + +static int snd_pcm_adpcm_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) +{ + return snd_pcm_hw_refine_slave(pcm, params, + snd_pcm_adpcm_hw_refine_cprepare, + snd_pcm_adpcm_hw_refine_cchange, + snd_pcm_adpcm_hw_refine_sprepare, + snd_pcm_adpcm_hw_refine_schange, + snd_pcm_plugin_hw_refine_slave); +} + +static int snd_pcm_adpcm_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params) +{ + snd_pcm_adpcm_t *adpcm = pcm->private; + int err = snd_pcm_hw_params_slave(pcm, params, + snd_pcm_adpcm_hw_refine_cchange, + snd_pcm_adpcm_hw_refine_sprepare, + snd_pcm_adpcm_hw_refine_schange, + snd_pcm_plugin_hw_params_slave); + if (err < 0) + return err; + + if (pcm->stream == SND_PCM_STREAM_PLAYBACK) { if (adpcm->sformat == SND_PCM_FORMAT_IMA_ADPCM) { adpcm->getput_idx = get_index(snd_pcm_hw_param_value(params, SND_PCM_HW_PARAM_FORMAT, 0), SND_PCM_FORMAT_S16); diff --git a/src/pcm/pcm_alaw.c b/src/pcm/pcm_alaw.c index df11d7c6..c9756d80 100644 --- a/src/pcm/pcm_alaw.c +++ b/src/pcm/pcm_alaw.c @@ -211,103 +211,108 @@ static void alaw_encode(const snd_pcm_channel_area_t *src_areas, } } -static int snd_pcm_alaw_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) +static int snd_pcm_alaw_hw_refine_cprepare(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) { snd_pcm_alaw_t *alaw = pcm->private; - snd_pcm_t *slave = alaw->plug.slave; int err; - unsigned int cmask, lcmask; - snd_pcm_hw_params_t sparams; mask_t *access_mask = alloca(mask_sizeof()); - mask_t *saccess_mask = alloca(mask_sizeof()); mask_load(access_mask, SND_PCM_ACCBIT_PLUGIN); - mask_load(saccess_mask, SND_PCM_ACCBIT_MMAP); - cmask = params->cmask; - params->cmask = 0; err = _snd_pcm_hw_param_mask(params, SND_PCM_HW_PARAM_ACCESS, - access_mask); + access_mask); if (err < 0) return err; if (alaw->sformat == SND_PCM_FORMAT_A_LAW) { mask_t *format_mask = alloca(mask_sizeof()); mask_load(format_mask, SND_PCM_FMTBIT_LINEAR); - err = _snd_pcm_hw_param_mask(params, - SND_PCM_HW_PARAM_FORMAT, - format_mask); - if (err < 0) - return err; + err = _snd_pcm_hw_param_mask(params, SND_PCM_HW_PARAM_FORMAT, + format_mask); } else { err = _snd_pcm_hw_param_set(params, - SND_PCM_HW_PARAM_FORMAT, - SND_PCM_FORMAT_A_LAW, 0); - if (err < 0) - return err; + SND_PCM_HW_PARAM_FORMAT, + SND_PCM_FORMAT_A_LAW, 0); } + if (err < 0) + return err; err = _snd_pcm_hw_param_set(params, SND_PCM_HW_PARAM_SUBFORMAT, SND_PCM_SUBFORMAT_STD, 0); if (err < 0) return err; - lcmask = params->cmask; - params->cmask |= cmask; + params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID); + return 0; +} - _snd_pcm_hw_params_any(&sparams); - _snd_pcm_hw_param_mask(&sparams, SND_PCM_HW_PARAM_ACCESS, - saccess_mask); - _snd_pcm_hw_param_set(&sparams, SND_PCM_HW_PARAM_FORMAT, +static int snd_pcm_alaw_hw_refine_sprepare(snd_pcm_t *pcm, snd_pcm_hw_params_t *sparams) +{ + snd_pcm_alaw_t *alaw = pcm->private; + mask_t *saccess_mask = alloca(mask_sizeof()); + mask_load(saccess_mask, SND_PCM_ACCBIT_MMAP); + _snd_pcm_hw_params_any(sparams); + _snd_pcm_hw_param_mask(sparams, SND_PCM_HW_PARAM_ACCESS, + saccess_mask); + _snd_pcm_hw_param_set(sparams, SND_PCM_HW_PARAM_FORMAT, alaw->sformat, 0); - _snd_pcm_hw_param_set(&sparams, SND_PCM_HW_PARAM_SUBFORMAT, + _snd_pcm_hw_param_set(sparams, SND_PCM_HW_PARAM_SUBFORMAT, SND_PCM_SUBFORMAT_STD, 0); - err = snd_pcm_hw_refine2(params, &sparams, - snd_pcm_generic_hw_link, slave, - SND_PCM_HW_PARBIT_CHANNELS | - SND_PCM_HW_PARBIT_RATE | - SND_PCM_HW_PARBIT_PERIOD_SIZE | - SND_PCM_HW_PARBIT_BUFFER_SIZE | - SND_PCM_HW_PARBIT_PERIODS | - SND_PCM_HW_PARBIT_PERIOD_TIME | - SND_PCM_HW_PARBIT_BUFFER_TIME | - SND_PCM_HW_PARBIT_TICK_TIME); - params->cmask |= lcmask; + return 0; +} + +static int snd_pcm_alaw_hw_refine_schange(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params, + snd_pcm_hw_params_t *sparams) +{ + int err; + unsigned int links = (SND_PCM_HW_PARBIT_CHANNELS | + SND_PCM_HW_PARBIT_RATE | + SND_PCM_HW_PARBIT_PERIOD_SIZE | + SND_PCM_HW_PARBIT_BUFFER_SIZE | + SND_PCM_HW_PARBIT_PERIODS | + SND_PCM_HW_PARBIT_PERIOD_TIME | + SND_PCM_HW_PARBIT_BUFFER_TIME | + SND_PCM_HW_PARBIT_TICK_TIME); + err = _snd_pcm_hw_params_refine(sparams, links, params); + if (err < 0) + return err; + return 0; +} + +static int snd_pcm_alaw_hw_refine_cchange(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params, + snd_pcm_hw_params_t *sparams) +{ + int err; + unsigned int links = (SND_PCM_HW_PARBIT_CHANNELS | + SND_PCM_HW_PARBIT_RATE | + SND_PCM_HW_PARBIT_PERIOD_SIZE | + SND_PCM_HW_PARBIT_BUFFER_SIZE | + SND_PCM_HW_PARBIT_PERIODS | + SND_PCM_HW_PARBIT_PERIOD_TIME | + SND_PCM_HW_PARBIT_BUFFER_TIME | + SND_PCM_HW_PARBIT_TICK_TIME); + err = _snd_pcm_hw_params_refine(params, links, sparams); if (err < 0) return err; - params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID); return 0; } +static int snd_pcm_alaw_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) +{ + return snd_pcm_hw_refine_slave(pcm, params, + snd_pcm_alaw_hw_refine_cprepare, + snd_pcm_alaw_hw_refine_cchange, + snd_pcm_alaw_hw_refine_sprepare, + snd_pcm_alaw_hw_refine_schange, + snd_pcm_plugin_hw_refine_slave); +} + static int snd_pcm_alaw_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params) { snd_pcm_alaw_t *alaw = pcm->private; - snd_pcm_t *slave = alaw->plug.slave; - int err; - snd_pcm_hw_params_t sparams; - unsigned int links; - mask_t *saccess_mask = alloca(mask_sizeof()); - mask_load(saccess_mask, SND_PCM_ACCBIT_MMAP); - - _snd_pcm_hw_params_any(&sparams); - _snd_pcm_hw_param_mask(&sparams, SND_PCM_HW_PARAM_ACCESS, - saccess_mask); - _snd_pcm_hw_param_set(&sparams, SND_PCM_HW_PARAM_FORMAT, - alaw->sformat, 0); - _snd_pcm_hw_param_set(&sparams, SND_PCM_HW_PARAM_SUBFORMAT, - SND_PCM_SUBFORMAT_STD, 0); - links = SND_PCM_HW_PARBIT_CHANNELS | - SND_PCM_HW_PARBIT_RATE | - SND_PCM_HW_PARBIT_PERIOD_SIZE | - SND_PCM_HW_PARBIT_BUFFER_SIZE | - SND_PCM_HW_PARBIT_PERIODS | - SND_PCM_HW_PARBIT_PERIOD_TIME | - SND_PCM_HW_PARBIT_BUFFER_TIME | - SND_PCM_HW_PARBIT_TICK_TIME; - err = snd_pcm_hw_params_refine(&sparams, links, params); - assert(err >= 0); - err = snd_pcm_hw_params(slave, &sparams); - params->cmask = 0; - sparams.cmask = ~0U; - snd_pcm_hw_params_refine(params, links, &sparams); + int err = snd_pcm_hw_params_slave(pcm, params, + snd_pcm_alaw_hw_refine_cchange, + snd_pcm_alaw_hw_refine_sprepare, + snd_pcm_alaw_hw_refine_schange, + snd_pcm_plugin_hw_params_slave); if (err < 0) return err; - params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID); + if (pcm->stream == SND_PCM_STREAM_PLAYBACK) { if (alaw->sformat == SND_PCM_FORMAT_A_LAW) { alaw->getput_idx = get_index(snd_pcm_hw_param_value(params, SND_PCM_HW_PARAM_FORMAT, 0), SND_PCM_FORMAT_S16); diff --git a/src/pcm/pcm_copy.c b/src/pcm/pcm_copy.c index f04cbb9a..9072b530 100644 --- a/src/pcm/pcm_copy.c +++ b/src/pcm/pcm_copy.c @@ -28,62 +28,68 @@ typedef struct { snd_pcm_plugin_t plug; } snd_pcm_copy_t; -static int snd_pcm_copy_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) +static int snd_pcm_copy_hw_refine_cprepare(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params) { - snd_pcm_copy_t *copy = pcm->private; - snd_pcm_t *slave = copy->plug.slave; int err; - unsigned int cmask, lcmask; - snd_pcm_hw_params_t sparams; mask_t *access_mask = alloca(mask_sizeof()); - mask_t *saccess_mask = alloca(mask_sizeof()); mask_load(access_mask, SND_PCM_ACCBIT_PLUGIN); - mask_load(saccess_mask, SND_PCM_ACCBIT_MMAP); - cmask = params->cmask; - params->cmask = 0; err = _snd_pcm_hw_param_mask(params, SND_PCM_HW_PARAM_ACCESS, access_mask); - if (err < 0) - return err; - lcmask = params->cmask; - params->cmask |= cmask; - _snd_pcm_hw_params_any(&sparams); - _snd_pcm_hw_param_mask(&sparams, SND_PCM_HW_PARAM_ACCESS, - saccess_mask); - err = snd_pcm_hw_refine2(params, &sparams, - snd_pcm_generic_hw_link, slave, - ~SND_PCM_HW_PARBIT_ACCESS); - params->cmask |= lcmask; if (err < 0) return err; params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID); - return err; + return 0; } -static int snd_pcm_copy_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) +static int snd_pcm_copy_hw_refine_sprepare(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *sparams) { - snd_pcm_copy_t *copy = pcm->private; - snd_pcm_t *slave = copy->plug.slave; - int err; - unsigned int links; - snd_pcm_hw_params_t sparams; mask_t *saccess_mask = alloca(mask_sizeof()); mask_load(saccess_mask, SND_PCM_ACCBIT_MMAP); + _snd_pcm_hw_params_any(sparams); + _snd_pcm_hw_param_mask(sparams, SND_PCM_HW_PARAM_ACCESS, + saccess_mask); + return 0; +} - _snd_pcm_hw_params_any(&sparams); - _snd_pcm_hw_param_mask(&sparams, SND_PCM_HW_PARAM_ACCESS, - saccess_mask); - links = ~SND_PCM_HW_PARBIT_ACCESS; - err = snd_pcm_hw_params_refine(&sparams, links, params); - assert(err >= 0); - err = snd_pcm_hw_params(slave, &sparams); - params->cmask = 0; - sparams.cmask = ~0U; - snd_pcm_hw_params_refine(params, links, &sparams); +static int snd_pcm_copy_hw_refine_schange(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params, + snd_pcm_hw_params_t *sparams) +{ + int err; + unsigned int links = ~SND_PCM_HW_PARBIT_ACCESS; + err = _snd_pcm_hw_params_refine(sparams, links, params); if (err < 0) return err; - params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID); - return err; + return 0; +} + +static int snd_pcm_copy_hw_refine_cchange(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params, + snd_pcm_hw_params_t *sparams) +{ + int err; + unsigned int links = ~SND_PCM_HW_PARBIT_ACCESS; + err = _snd_pcm_hw_params_refine(params, links, sparams); + if (err < 0) + return err; + return 0; +} + +static int snd_pcm_copy_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) +{ + return snd_pcm_hw_refine_slave(pcm, params, + snd_pcm_copy_hw_refine_cprepare, + snd_pcm_copy_hw_refine_cchange, + snd_pcm_copy_hw_refine_sprepare, + snd_pcm_copy_hw_refine_schange, + snd_pcm_plugin_hw_refine_slave); +} + +static int snd_pcm_copy_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) +{ + return snd_pcm_hw_params_slave(pcm, params, + snd_pcm_copy_hw_refine_cchange, + snd_pcm_copy_hw_refine_sprepare, + snd_pcm_copy_hw_refine_schange, + snd_pcm_plugin_hw_params_slave); } static snd_pcm_sframes_t snd_pcm_copy_write_areas(snd_pcm_t *pcm, diff --git a/src/pcm/pcm_linear.c b/src/pcm/pcm_linear.c index ca028bcd..95c09715 100644 --- a/src/pcm/pcm_linear.c +++ b/src/pcm/pcm_linear.c @@ -72,94 +72,100 @@ static void linear_transfer(const snd_pcm_channel_area_t *src_areas, snd_pcm_ufr } } -static int snd_pcm_linear_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) +static int snd_pcm_linear_hw_refine_cprepare(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params) { - snd_pcm_linear_t *linear = pcm->private; - snd_pcm_t *slave = linear->plug.slave; int err; - unsigned int cmask, lcmask; - snd_pcm_hw_params_t sparams; mask_t *access_mask = alloca(mask_sizeof()); mask_t *format_mask = alloca(mask_sizeof()); - mask_t *saccess_mask = alloca(mask_sizeof()); mask_load(access_mask, SND_PCM_ACCBIT_PLUGIN); mask_load(format_mask, SND_PCM_FMTBIT_LINEAR); - mask_load(saccess_mask, SND_PCM_ACCBIT_MMAP); - cmask = params->cmask; - params->cmask = 0; err = _snd_pcm_hw_param_mask(params, SND_PCM_HW_PARAM_ACCESS, - access_mask); + access_mask); if (err < 0) return err; err = _snd_pcm_hw_param_mask(params, SND_PCM_HW_PARAM_FORMAT, - format_mask); + format_mask); if (err < 0) return err; err = _snd_pcm_hw_param_set(params, SND_PCM_HW_PARAM_SUBFORMAT, - SND_PCM_SUBFORMAT_STD, 0); + SND_PCM_SUBFORMAT_STD, 0); if (err < 0) return err; - lcmask = params->cmask; - params->cmask |= cmask; + params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID); + return 0; +} - _snd_pcm_hw_params_any(&sparams); - _snd_pcm_hw_param_mask(&sparams, SND_PCM_HW_PARAM_ACCESS, - saccess_mask); - _snd_pcm_hw_param_set(&sparams, SND_PCM_HW_PARAM_FORMAT, +static int snd_pcm_linear_hw_refine_sprepare(snd_pcm_t *pcm, snd_pcm_hw_params_t *sparams) +{ + snd_pcm_linear_t *linear = pcm->private; + mask_t *saccess_mask = alloca(mask_sizeof()); + mask_load(saccess_mask, SND_PCM_ACCBIT_MMAP); + _snd_pcm_hw_params_any(sparams); + _snd_pcm_hw_param_mask(sparams, SND_PCM_HW_PARAM_ACCESS, + saccess_mask); + _snd_pcm_hw_param_set(sparams, SND_PCM_HW_PARAM_FORMAT, linear->sformat, 0); - _snd_pcm_hw_param_set(&sparams, SND_PCM_HW_PARAM_SUBFORMAT, + _snd_pcm_hw_param_set(sparams, SND_PCM_HW_PARAM_SUBFORMAT, SND_PCM_SUBFORMAT_STD, 0); - err = snd_pcm_hw_refine2(params, &sparams, - snd_pcm_generic_hw_link, slave, - SND_PCM_HW_PARBIT_CHANNELS | - SND_PCM_HW_PARBIT_RATE | - SND_PCM_HW_PARBIT_PERIOD_SIZE | - SND_PCM_HW_PARBIT_BUFFER_SIZE | - SND_PCM_HW_PARBIT_PERIODS | - SND_PCM_HW_PARBIT_PERIOD_TIME | - SND_PCM_HW_PARBIT_BUFFER_TIME | - SND_PCM_HW_PARBIT_TICK_TIME); - params->cmask |= lcmask; + return 0; +} + +static int snd_pcm_linear_hw_refine_schange(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params, + snd_pcm_hw_params_t *sparams) +{ + int err; + unsigned int links = (SND_PCM_HW_PARBIT_CHANNELS | + SND_PCM_HW_PARBIT_RATE | + SND_PCM_HW_PARBIT_PERIOD_SIZE | + SND_PCM_HW_PARBIT_BUFFER_SIZE | + SND_PCM_HW_PARBIT_PERIODS | + SND_PCM_HW_PARBIT_PERIOD_TIME | + SND_PCM_HW_PARBIT_BUFFER_TIME | + SND_PCM_HW_PARBIT_TICK_TIME); + err = _snd_pcm_hw_params_refine(sparams, links, params); + if (err < 0) + return err; + return 0; +} + +static int snd_pcm_linear_hw_refine_cchange(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params, + snd_pcm_hw_params_t *sparams) +{ + int err; + unsigned int links = (SND_PCM_HW_PARBIT_CHANNELS | + SND_PCM_HW_PARBIT_RATE | + SND_PCM_HW_PARBIT_PERIOD_SIZE | + SND_PCM_HW_PARBIT_BUFFER_SIZE | + SND_PCM_HW_PARBIT_PERIODS | + SND_PCM_HW_PARBIT_PERIOD_TIME | + SND_PCM_HW_PARBIT_BUFFER_TIME | + SND_PCM_HW_PARBIT_TICK_TIME); + err = _snd_pcm_hw_params_refine(params, links, sparams); if (err < 0) return err; - params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID); return 0; } +static int snd_pcm_linear_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) +{ + return snd_pcm_hw_refine_slave(pcm, params, + snd_pcm_linear_hw_refine_cprepare, + snd_pcm_linear_hw_refine_cchange, + snd_pcm_linear_hw_refine_sprepare, + snd_pcm_linear_hw_refine_schange, + snd_pcm_plugin_hw_refine_slave); +} + static int snd_pcm_linear_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) { snd_pcm_linear_t *linear = pcm->private; - snd_pcm_t *slave = linear->plug.slave; - int err; - unsigned int links; - snd_pcm_hw_params_t sparams; - mask_t *saccess_mask = alloca(mask_sizeof()); - mask_load(saccess_mask, SND_PCM_ACCBIT_MMAP); - - _snd_pcm_hw_params_any(&sparams); - _snd_pcm_hw_param_mask(&sparams, SND_PCM_HW_PARAM_ACCESS, - saccess_mask); - _snd_pcm_hw_param_set(&sparams, SND_PCM_HW_PARAM_FORMAT, - linear->sformat, 0); - _snd_pcm_hw_param_set(&sparams, SND_PCM_HW_PARAM_SUBFORMAT, - SND_PCM_SUBFORMAT_STD, 0); - links = SND_PCM_HW_PARBIT_CHANNELS | - SND_PCM_HW_PARBIT_RATE | - SND_PCM_HW_PARBIT_PERIOD_SIZE | - SND_PCM_HW_PARBIT_BUFFER_SIZE | - SND_PCM_HW_PARBIT_PERIODS | - SND_PCM_HW_PARBIT_PERIOD_TIME | - SND_PCM_HW_PARBIT_BUFFER_TIME | - SND_PCM_HW_PARBIT_TICK_TIME; - err = snd_pcm_hw_params_refine(&sparams, links, params); - assert(err >= 0); - err = snd_pcm_hw_params(slave, &sparams); - params->cmask = 0; - sparams.cmask = ~0U; - snd_pcm_hw_params_refine(params, links, &sparams); + int err = snd_pcm_hw_params_slave(pcm, params, + snd_pcm_linear_hw_refine_cchange, + snd_pcm_linear_hw_refine_sprepare, + snd_pcm_linear_hw_refine_schange, + snd_pcm_plugin_hw_params_slave); if (err < 0) return err; - params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID); if (pcm->stream == SND_PCM_STREAM_PLAYBACK) linear->conv_idx = conv_index(snd_pcm_hw_param_value(params, SND_PCM_HW_PARAM_FORMAT, 0), linear->sformat); diff --git a/src/pcm/pcm_local.h b/src/pcm/pcm_local.h index 6ffc08e8..3a5dfe40 100644 --- a/src/pcm/pcm_local.h +++ b/src/pcm/pcm_local.h @@ -299,7 +299,33 @@ static inline int muldiv_near(int a, int b, int c) return n; } -int _snd_pcm_hw_refine(snd_pcm_hw_params_t *params); +int snd_pcm_hw_refine_soft(snd_pcm_t *pcm, snd_pcm_hw_params_t *params); +int snd_pcm_hw_refine_slave(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, + int (*cprepare)(snd_pcm_t *pcm, + snd_pcm_hw_params_t *params), + int (*cchange)(snd_pcm_t *pcm, + snd_pcm_hw_params_t *params, + snd_pcm_hw_params_t *sparams), + int (*sprepare)(snd_pcm_t *pcm, + snd_pcm_hw_params_t *params), + int (*schange)(snd_pcm_t *pcm, + snd_pcm_hw_params_t *params, + snd_pcm_hw_params_t *sparams), + int (*srefine)(snd_pcm_t *pcm, + snd_pcm_hw_params_t *sparams)); +int snd_pcm_hw_params_slave(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, + int (*cchange)(snd_pcm_t *pcm, + snd_pcm_hw_params_t *params, + snd_pcm_hw_params_t *sparams), + int (*sprepare)(snd_pcm_t *pcm, + snd_pcm_hw_params_t *params), + int (*schange)(snd_pcm_t *pcm, + snd_pcm_hw_params_t *params, + snd_pcm_hw_params_t *sparams), + int (*sparams)(snd_pcm_t *pcm, + snd_pcm_hw_params_t *sparams)); + + void _snd_pcm_hw_params_any(snd_pcm_hw_params_t *params); int _snd_pcm_hw_param_refine_interval(snd_pcm_hw_params_t *params, snd_pcm_hw_param_t var, @@ -316,34 +342,16 @@ int _snd_pcm_hw_param_min(snd_pcm_hw_params_t *params, unsigned int var, unsigned int val, int dir); int _snd_pcm_hw_param_max(snd_pcm_hw_params_t *params, unsigned int var, unsigned int val, int dir); -int snd_pcm_hw_param_refine(snd_pcm_hw_params_t *params, - snd_pcm_hw_param_t var, - const snd_pcm_hw_params_t *src); -int snd_pcm_hw_params_refine(snd_pcm_hw_params_t *params, - unsigned int vars, +int _snd_pcm_hw_param_refine(snd_pcm_hw_params_t *params, + snd_pcm_hw_param_t var, const snd_pcm_hw_params_t *src); -int snd_pcm_generic_hw_link(snd_pcm_hw_params_t *params, - snd_pcm_hw_params_t *sparams, - snd_pcm_t *slave, - unsigned long links); -int snd_pcm_hw_refine2(snd_pcm_hw_params_t *params, - snd_pcm_hw_params_t *sparams, - int (*func)(snd_pcm_hw_params_t *params, - snd_pcm_hw_params_t *sparams, - snd_pcm_t *slave, - unsigned long private), - snd_pcm_t *slave, - unsigned long private); -int snd_pcm_hw_params2(snd_pcm_hw_params_t *params, - snd_pcm_hw_params_t *sparams, - int (*func)(snd_pcm_t *slave, - snd_pcm_hw_params_t *sparams), - snd_pcm_t *slave, - unsigned int links); -void snd_pcm_hw_param_near_copy(snd_pcm_t *pcm, - snd_pcm_hw_params_t *params, - snd_pcm_hw_param_t var, - const snd_pcm_hw_params_t *src); +int _snd_pcm_hw_params_refine(snd_pcm_hw_params_t *params, + unsigned int vars, + const snd_pcm_hw_params_t *src); +void snd_pcm_hw_param_refine_near(snd_pcm_t *pcm, + snd_pcm_hw_params_t *params, + snd_pcm_hw_param_t var, + const snd_pcm_hw_params_t *src); int snd_pcm_hw_param_always_eq(const snd_pcm_hw_params_t *params, snd_pcm_hw_param_t var, const snd_pcm_hw_params_t *params1); diff --git a/src/pcm/pcm_mulaw.c b/src/pcm/pcm_mulaw.c index c1a7ccb8..b501e66e 100644 --- a/src/pcm/pcm_mulaw.c +++ b/src/pcm/pcm_mulaw.c @@ -228,19 +228,12 @@ static void mulaw_encode(const snd_pcm_channel_area_t *src_areas, } } -static int snd_pcm_mulaw_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) +static int snd_pcm_mulaw_hw_refine_cprepare(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) { snd_pcm_mulaw_t *mulaw = pcm->private; - snd_pcm_t *slave = mulaw->plug.slave; int err; - unsigned int cmask, lcmask; - snd_pcm_hw_params_t sparams; mask_t *access_mask = alloca(mask_sizeof()); - mask_t *saccess_mask = alloca(mask_sizeof()); mask_load(access_mask, SND_PCM_ACCBIT_PLUGIN); - mask_load(saccess_mask, SND_PCM_ACCBIT_MMAP); - cmask = params->cmask; - params->cmask = 0; err = _snd_pcm_hw_param_mask(params, SND_PCM_HW_PARAM_ACCESS, access_mask); if (err < 0) @@ -248,83 +241,93 @@ static int snd_pcm_mulaw_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) if (mulaw->sformat == SND_PCM_FORMAT_MU_LAW) { mask_t *format_mask = alloca(mask_sizeof()); mask_load(format_mask, SND_PCM_FMTBIT_LINEAR); - err = _snd_pcm_hw_param_mask(params, - SND_PCM_HW_PARAM_FORMAT, + err = _snd_pcm_hw_param_mask(params, SND_PCM_HW_PARAM_FORMAT, format_mask); - if (err < 0) - return err; } else { err = _snd_pcm_hw_param_set(params, SND_PCM_HW_PARAM_FORMAT, SND_PCM_FORMAT_MU_LAW, 0); - if (err < 0) - return err; } err = _snd_pcm_hw_param_set(params, SND_PCM_HW_PARAM_SUBFORMAT, - SND_PCM_SUBFORMAT_STD, 0); + SND_PCM_SUBFORMAT_STD, 0); if (err < 0) return err; - lcmask = params->cmask; - params->cmask |= cmask; + params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID); + return 0; +} - _snd_pcm_hw_params_any(&sparams); - _snd_pcm_hw_param_mask(&sparams, SND_PCM_HW_PARAM_ACCESS, - saccess_mask); - _snd_pcm_hw_param_set(&sparams, SND_PCM_HW_PARAM_FORMAT, +static int snd_pcm_mulaw_hw_refine_sprepare(snd_pcm_t *pcm, snd_pcm_hw_params_t *sparams) +{ + snd_pcm_mulaw_t *mulaw = pcm->private; + mask_t *saccess_mask = alloca(mask_sizeof()); + mask_load(saccess_mask, SND_PCM_ACCBIT_MMAP); + _snd_pcm_hw_params_any(sparams); + _snd_pcm_hw_param_mask(sparams, SND_PCM_HW_PARAM_ACCESS, + saccess_mask); + _snd_pcm_hw_param_set(sparams, SND_PCM_HW_PARAM_FORMAT, mulaw->sformat, 0); - _snd_pcm_hw_param_set(&sparams, SND_PCM_HW_PARAM_SUBFORMAT, + _snd_pcm_hw_param_set(sparams, SND_PCM_HW_PARAM_SUBFORMAT, SND_PCM_SUBFORMAT_STD, 0); - err = snd_pcm_hw_refine2(params, &sparams, - snd_pcm_generic_hw_link, slave, - SND_PCM_HW_PARBIT_CHANNELS | - SND_PCM_HW_PARBIT_RATE | - SND_PCM_HW_PARBIT_PERIOD_SIZE | - SND_PCM_HW_PARBIT_BUFFER_SIZE | - SND_PCM_HW_PARBIT_PERIODS | - SND_PCM_HW_PARBIT_PERIOD_TIME | - SND_PCM_HW_PARBIT_BUFFER_TIME | - SND_PCM_HW_PARBIT_TICK_TIME); - params->cmask |= lcmask; + return 0; +} + +static int snd_pcm_mulaw_hw_refine_schange(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params, + snd_pcm_hw_params_t *sparams) +{ + int err; + unsigned int links = (SND_PCM_HW_PARBIT_CHANNELS | + SND_PCM_HW_PARBIT_RATE | + SND_PCM_HW_PARBIT_PERIOD_SIZE | + SND_PCM_HW_PARBIT_BUFFER_SIZE | + SND_PCM_HW_PARBIT_PERIODS | + SND_PCM_HW_PARBIT_PERIOD_TIME | + SND_PCM_HW_PARBIT_BUFFER_TIME | + SND_PCM_HW_PARBIT_TICK_TIME); + err = _snd_pcm_hw_params_refine(sparams, links, params); if (err < 0) return err; - params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID); return 0; } + +static int snd_pcm_mulaw_hw_refine_cchange(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params, + snd_pcm_hw_params_t *sparams) +{ + int err; + unsigned int links = (SND_PCM_HW_PARBIT_CHANNELS | + SND_PCM_HW_PARBIT_RATE | + SND_PCM_HW_PARBIT_PERIOD_SIZE | + SND_PCM_HW_PARBIT_BUFFER_SIZE | + SND_PCM_HW_PARBIT_PERIODS | + SND_PCM_HW_PARBIT_PERIOD_TIME | + SND_PCM_HW_PARBIT_BUFFER_TIME | + SND_PCM_HW_PARBIT_TICK_TIME); + err = _snd_pcm_hw_params_refine(params, links, sparams); + if (err < 0) + return err; + return 0; +} + +static int snd_pcm_mulaw_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) +{ + return snd_pcm_hw_refine_slave(pcm, params, + snd_pcm_mulaw_hw_refine_cprepare, + snd_pcm_mulaw_hw_refine_cchange, + snd_pcm_mulaw_hw_refine_sprepare, + snd_pcm_mulaw_hw_refine_schange, + snd_pcm_plugin_hw_refine_slave); +} static int snd_pcm_mulaw_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params) { snd_pcm_mulaw_t *mulaw = pcm->private; - snd_pcm_t *slave = mulaw->plug.slave; - int err; - unsigned int links; - snd_pcm_hw_params_t sparams; - mask_t *saccess_mask = alloca(mask_sizeof()); - mask_load(saccess_mask, SND_PCM_ACCBIT_MMAP); - - _snd_pcm_hw_params_any(&sparams); - _snd_pcm_hw_param_mask(&sparams, SND_PCM_HW_PARAM_ACCESS, - saccess_mask); - _snd_pcm_hw_param_set(&sparams, SND_PCM_HW_PARAM_FORMAT, - mulaw->sformat, 0); - _snd_pcm_hw_param_set(&sparams, SND_PCM_HW_PARAM_SUBFORMAT, - SND_PCM_SUBFORMAT_STD, 0); - links = SND_PCM_HW_PARBIT_CHANNELS | - SND_PCM_HW_PARBIT_RATE | - SND_PCM_HW_PARBIT_PERIOD_SIZE | - SND_PCM_HW_PARBIT_BUFFER_SIZE | - SND_PCM_HW_PARBIT_PERIODS | - SND_PCM_HW_PARBIT_PERIOD_TIME | - SND_PCM_HW_PARBIT_BUFFER_TIME | - SND_PCM_HW_PARBIT_TICK_TIME; - err = snd_pcm_hw_params_refine(&sparams, links, params); - assert(err >= 0); - err = snd_pcm_hw_params(slave, &sparams); - params->cmask = 0; - sparams.cmask = ~0U; - snd_pcm_hw_params_refine(params, links, &sparams); + int err = snd_pcm_hw_params_slave(pcm, params, + snd_pcm_mulaw_hw_refine_cchange, + snd_pcm_mulaw_hw_refine_sprepare, + snd_pcm_mulaw_hw_refine_schange, + snd_pcm_plugin_hw_params_slave); if (err < 0) return err; - params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID); + if (pcm->stream == SND_PCM_STREAM_PLAYBACK) { if (mulaw->sformat == SND_PCM_FORMAT_MU_LAW) { mulaw->getput_idx = get_index(snd_pcm_hw_param_value(params, SND_PCM_HW_PARAM_FORMAT, 0), SND_PCM_FORMAT_S16); diff --git a/src/pcm/pcm_multi.c b/src/pcm/pcm_multi.c index e5018f34..53fbbc8d 100644 --- a/src/pcm/pcm_multi.c +++ b/src/pcm/pcm_multi.c @@ -69,7 +69,10 @@ static int snd_pcm_multi_close(snd_pcm_t *pcm) static int snd_pcm_multi_card(snd_pcm_t *pcm ATTRIBUTE_UNUSED) { - return -ENOENT; /* not available */ + snd_pcm_multi_t *multi = pcm->private; + if (multi->slaves_count != 1) + return -ENOENT; /* not available */ + return snd_pcm_card(multi->slaves[0].pcm); } static int snd_pcm_multi_nonblock(snd_pcm_t *pcm ATTRIBUTE_UNUSED, int nonblock ATTRIBUTE_UNUSED) @@ -96,135 +99,188 @@ static int snd_pcm_multi_info(snd_pcm_t *pcm, snd_pcm_info_t *info) return 0; } -static int snd_pcm_multi_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) +static int snd_pcm_multi_hw_refine_cprepare(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) { snd_pcm_multi_t *multi = pcm->private; - unsigned int k; - snd_pcm_hw_params_t sparams; - int changed = 0; - int err = 0; - unsigned int cmask, lcmask; - const mask_t *access_mask = snd_pcm_hw_param_value_mask(params, SND_PCM_HW_PARAM_ACCESS); - mask_t *saccess_mask = alloca(mask_sizeof()); - if (mask_test(access_mask, SND_PCM_ACCESS_RW_INTERLEAVED) || - mask_test(access_mask, SND_PCM_ACCESS_RW_NONINTERLEAVED)) - mask_load(saccess_mask, SND_PCM_ACCBIT_MMAP); - else { - mask_none(saccess_mask); - if (mask_test(access_mask, SND_PCM_ACCESS_MMAP_INTERLEAVED) && - multi->slaves_count == 1) - mask_set(saccess_mask, SND_PCM_ACCESS_MMAP_INTERLEAVED); - if (mask_test(access_mask, SND_PCM_ACCESS_MMAP_NONINTERLEAVED)) - mask_set(saccess_mask, SND_PCM_ACCESS_MMAP_NONINTERLEAVED); - if (mask_test(access_mask, SND_PCM_ACCESS_MMAP_COMPLEX)) { - mask_set(saccess_mask, SND_PCM_ACCESS_MMAP_COMPLEX); - if (multi->slaves_count > 1) - mask_set(saccess_mask, SND_PCM_ACCESS_MMAP_INTERLEAVED); - } - } - - cmask = params->cmask; - params->cmask = 0; + mask_t *access_mask = alloca(mask_sizeof()); + int err; + mask_any(access_mask); + mask_reset(access_mask, SND_PCM_ACCESS_MMAP_INTERLEAVED); + err = _snd_pcm_hw_param_mask(params, SND_PCM_HW_PARAM_ACCESS, + access_mask); + if (err < 0) + return err; err = _snd_pcm_hw_param_set(params, SND_PCM_HW_PARAM_CHANNELS, multi->channels_count, 0); if (err < 0) return err; - lcmask = params->cmask; - cmask |= params->cmask; + params->info = ~0; + return 0; +} + +static int snd_pcm_multi_hw_refine_sprepare(snd_pcm_t *pcm, int slave_idx, + snd_pcm_hw_params_t *sparams) +{ + snd_pcm_multi_t *multi = pcm->private; + snd_pcm_multi_slave_t *slave = &multi->slaves[slave_idx]; + mask_t *saccess_mask = alloca(mask_sizeof()); + mask_load(saccess_mask, SND_PCM_ACCBIT_MMAP); + _snd_pcm_hw_params_any(sparams); + _snd_pcm_hw_param_mask(sparams, SND_PCM_HW_PARAM_ACCESS, + saccess_mask); + _snd_pcm_hw_param_set(sparams, SND_PCM_HW_PARAM_CHANNELS, + slave->channels_count, 0); + return 0; +} + +static int snd_pcm_multi_hw_refine_schange(snd_pcm_t *pcm ATTRIBUTE_UNUSED, + int slave_idx ATTRIBUTE_UNUSED, + snd_pcm_hw_params_t *params, + snd_pcm_hw_params_t *sparams) +{ + int err; + unsigned int links = (SND_PCM_HW_PARBIT_FORMAT | + SND_PCM_HW_PARBIT_SUBFORMAT | + SND_PCM_HW_PARBIT_RATE | + SND_PCM_HW_PARBIT_PERIOD_SIZE | + SND_PCM_HW_PARBIT_PERIOD_TIME | + SND_PCM_HW_PARBIT_PERIODS | + SND_PCM_HW_PARBIT_BUFFER_SIZE | + SND_PCM_HW_PARBIT_BUFFER_TIME | + SND_PCM_HW_PARBIT_TICK_TIME); + const mask_t *access_mask = snd_pcm_hw_param_value_mask(params, SND_PCM_HW_PARAM_ACCESS); + if (!mask_test(access_mask, SND_PCM_ACCESS_RW_INTERLEAVED) && + !mask_test(access_mask, SND_PCM_ACCESS_RW_NONINTERLEAVED) && + !mask_test(access_mask, SND_PCM_ACCESS_MMAP_NONINTERLEAVED)) { + mask_t *saccess_mask = alloca(mask_sizeof()); + mask_any(saccess_mask); + mask_reset(saccess_mask, SND_PCM_ACCESS_MMAP_NONINTERLEAVED); + err = _snd_pcm_hw_param_mask(sparams, SND_PCM_HW_PARAM_ACCESS, + saccess_mask); + if (err < 0) + return err; + } + err = _snd_pcm_hw_params_refine(sparams, links, params); + if (err < 0) + return err; + return 0; +} - changed = 0; - do { - for (k = 0; k < multi->slaves_count; ++k) { - snd_pcm_t *slave = multi->slaves[k].pcm; - params->cmask = cmask; - _snd_pcm_hw_params_any(&sparams); - _snd_pcm_hw_param_mask(&sparams, - SND_PCM_HW_PARAM_ACCESS, - saccess_mask); - _snd_pcm_hw_param_set(&sparams, - SND_PCM_HW_PARAM_CHANNELS, - multi->slaves[k].channels_count, 0); - err = snd_pcm_hw_refine2(params, &sparams, - snd_pcm_generic_hw_link, slave, - SND_PCM_HW_PARBIT_FORMAT | - SND_PCM_HW_PARBIT_SUBFORMAT | - SND_PCM_HW_PARBIT_RATE | - SND_PCM_HW_PARBIT_PERIOD_SIZE | - SND_PCM_HW_PARBIT_PERIOD_TIME | - SND_PCM_HW_PARBIT_BUFFER_SIZE | - SND_PCM_HW_PARBIT_BUFFER_TIME | - SND_PCM_HW_PARBIT_PERIODS | - SND_PCM_HW_PARBIT_TICK_TIME); - if (params->cmask) { - changed++; - lcmask |= params->cmask; - cmask |= params->cmask; - } - if (err < 0) - goto _end; - } - } while (changed && multi->slaves_count > 1); - _end: - params->cmask = lcmask; - return err; +static int snd_pcm_multi_hw_refine_cchange(snd_pcm_t *pcm ATTRIBUTE_UNUSED, + int slave_idx ATTRIBUTE_UNUSED, + snd_pcm_hw_params_t *params, + snd_pcm_hw_params_t *sparams) +{ + int err; + unsigned int links = (SND_PCM_HW_PARBIT_FORMAT | + SND_PCM_HW_PARBIT_SUBFORMAT | + SND_PCM_HW_PARBIT_RATE | + SND_PCM_HW_PARBIT_PERIOD_SIZE | + SND_PCM_HW_PARBIT_PERIOD_TIME | + SND_PCM_HW_PARBIT_PERIODS | + SND_PCM_HW_PARBIT_BUFFER_SIZE | + SND_PCM_HW_PARBIT_BUFFER_TIME | + SND_PCM_HW_PARBIT_TICK_TIME); + mask_t *access_mask = alloca(mask_sizeof()); + const mask_t *saccess_mask = snd_pcm_hw_param_value_mask(sparams, SND_PCM_HW_PARAM_ACCESS); + mask_any(access_mask); + mask_reset(access_mask, SND_PCM_ACCESS_MMAP_INTERLEAVED); + if (!mask_test(saccess_mask, SND_PCM_ACCESS_MMAP_NONINTERLEAVED)) + mask_reset(access_mask, SND_PCM_ACCESS_MMAP_NONINTERLEAVED); + if (!mask_test(saccess_mask, SND_PCM_ACCESS_MMAP_COMPLEX) && + !mask_test(saccess_mask, SND_PCM_ACCESS_MMAP_INTERLEAVED)) + mask_reset(access_mask, SND_PCM_ACCESS_MMAP_COMPLEX); + err = _snd_pcm_hw_param_mask(params, SND_PCM_HW_PARAM_ACCESS, + access_mask); + if (err < 0) + return err; + err = _snd_pcm_hw_params_refine(params, links, sparams); + if (err < 0) + return err; + params->info &= sparams->info; + return 0; } -static int snd_pcm_multi_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) +static int snd_pcm_multi_hw_refine_slave(snd_pcm_t *pcm, + int slave_idx, + snd_pcm_hw_params_t *sparams) +{ + snd_pcm_multi_t *multi = pcm->private; + snd_pcm_t *slave = multi->slaves[slave_idx].pcm; + return snd_pcm_hw_refine(slave, sparams); +} + +static int snd_pcm_multi_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) { snd_pcm_multi_t *multi = pcm->private; unsigned int k; + snd_pcm_hw_params_t sparams[multi->slaves_count]; int err; - const mask_t *access_mask = snd_pcm_hw_param_value_mask(params, SND_PCM_HW_PARAM_ACCESS); - mask_t *saccess_mask = alloca(mask_sizeof()); - unsigned int links; - links = SND_PCM_HW_PARBIT_FORMAT | - SND_PCM_HW_PARBIT_SUBFORMAT | - SND_PCM_HW_PARBIT_RATE | - SND_PCM_HW_PARBIT_PERIOD_SIZE | - SND_PCM_HW_PARBIT_PERIOD_TIME | - SND_PCM_HW_PARBIT_BUFFER_SIZE | - SND_PCM_HW_PARBIT_BUFFER_TIME | - SND_PCM_HW_PARBIT_PERIODS | - SND_PCM_HW_PARBIT_TICK_TIME; - if (mask_test(access_mask, SND_PCM_ACCESS_RW_INTERLEAVED) || - mask_test(access_mask, SND_PCM_ACCESS_RW_NONINTERLEAVED)) - mask_load(saccess_mask, SND_PCM_ACCBIT_MMAP); - else { - mask_none(saccess_mask); - if (mask_test(access_mask, SND_PCM_ACCESS_MMAP_INTERLEAVED) && - multi->slaves_count == 1) - mask_set(saccess_mask, SND_PCM_ACCESS_MMAP_INTERLEAVED); - if (mask_test(access_mask, SND_PCM_ACCESS_MMAP_NONINTERLEAVED)) - mask_set(saccess_mask, SND_PCM_ACCESS_MMAP_NONINTERLEAVED); - if (mask_test(access_mask, SND_PCM_ACCESS_MMAP_COMPLEX)) { - mask_set(saccess_mask, SND_PCM_ACCESS_MMAP_COMPLEX); - if (multi->slaves_count > 1) - mask_set(saccess_mask, SND_PCM_ACCESS_MMAP_INTERLEAVED); + err = snd_pcm_multi_hw_refine_cprepare(pcm, params); + if (err < 0) + return err; + for (k = 0; k < multi->slaves_count; ++k) { + err = snd_pcm_multi_hw_refine_sprepare(pcm, k, &sparams[k]); + if (err < 0) { + ERR("Slave PCM #%d not useable", k); + return err; } } + /* FIXME: loop begin? */ for (k = 0; k < multi->slaves_count; ++k) { - snd_pcm_t *slave = multi->slaves[k].pcm; - snd_pcm_hw_params_t sparams; - _snd_pcm_hw_params_any(&sparams); - _snd_pcm_hw_param_mask(&sparams, SND_PCM_HW_PARAM_ACCESS, - saccess_mask); - _snd_pcm_hw_param_set(&sparams, SND_PCM_HW_PARAM_CHANNELS, - multi->slaves[k].channels_count, 0); - err = snd_pcm_hw_params_refine(&sparams, links, params); - assert(err >= 0); - err = snd_pcm_hw_params(slave, &sparams); - params->cmask = 0; - sparams.cmask = ~0U; - snd_pcm_hw_params_refine(params, links, &sparams); + err = snd_pcm_multi_hw_refine_schange(pcm, k, params, &sparams[k]); + if (err >= 0) + err = snd_pcm_multi_hw_refine_slave(pcm, k, &sparams[k]); + if (err < 0) { + snd_pcm_multi_hw_refine_cchange(pcm, k, params, &sparams[k]); + return err; + } + err = snd_pcm_multi_hw_refine_cchange(pcm, k, params, &sparams[k]); if (err < 0) return err; - err = snd_pcm_areas_silence(slave->running_areas, 0, slave->channels, slave->buffer_size, slave->format); + } + err = snd_pcm_hw_refine_soft(pcm, params); + if (err < 0) + return err; + /* FIXME: do we need to loop? */ + return 0; +} + +static int snd_pcm_multi_hw_params_slave(snd_pcm_t *pcm, + int slave_idx, + snd_pcm_hw_params_t *sparams) +{ + snd_pcm_multi_t *multi = pcm->private; + snd_pcm_t *slave = multi->slaves[slave_idx].pcm; + int err = snd_pcm_hw_refine(slave, sparams); + if (err < 0) + return err; + err = snd_pcm_areas_silence(slave->running_areas, 0, slave->channels, slave->buffer_size, slave->format); + if (err < 0) + return err; + 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; - 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; + } + return 0; +} + +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 k; + snd_pcm_hw_params_t sparams[multi->slaves_count]; + int err; + for (k = 0; k < multi->slaves_count; ++k) { + err = snd_pcm_multi_hw_refine_sprepare(pcm, k, &sparams[k]); + assert(err >= 0); + err = snd_pcm_multi_hw_refine_schange(pcm, k, params, &sparams[k]); + assert(err >= 0); + err = snd_pcm_multi_hw_params_slave(pcm, k, &sparams[k]); + if (err < 0) { + snd_pcm_multi_hw_refine_cchange(pcm, k, params, &sparams[k]); + return err; } } return 0; diff --git a/src/pcm/pcm_null.c b/src/pcm/pcm_null.c index 1007a9d0..1f46659c 100644 --- a/src/pcm/pcm_null.c +++ b/src/pcm/pcm_null.c @@ -231,7 +231,7 @@ static snd_pcm_sframes_t snd_pcm_null_avail_update(snd_pcm_t *pcm) static int snd_pcm_null_hw_refine(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params) { - int err = _snd_pcm_hw_refine(params); + int err = snd_pcm_hw_refine_soft(pcm, params); params->fifo_size = 0; return err; } diff --git a/src/pcm/pcm_params.c b/src/pcm/pcm_params.c index 7bbcab75..b2fe8a0d 100644 --- a/src/pcm/pcm_params.c +++ b/src/pcm/pcm_params.c @@ -115,11 +115,13 @@ void _snd_pcm_hw_param_any(snd_pcm_hw_params_t *params, snd_pcm_hw_param_t var) if (hw_is_mask(var)) { mask_any(hw_param_mask(params, var)); params->cmask |= 1 << var; + params->rmask |= 1 << var; return; } if (hw_is_interval(var)) { interval_any(hw_param_interval(params, var)); params->cmask |= 1 << var; + params->rmask |= 1 << var; return; } assert(0); @@ -241,8 +243,10 @@ int _snd_pcm_hw_param_refine_interval(snd_pcm_hw_params_t *params, int changed; assert(hw_is_interval(var)); changed = interval_refine(hw_param_interval(params, var), val); - if (changed) + if (changed) { params->cmask |= 1 << var; + params->rmask |= 1 << var; + } return changed; } @@ -252,8 +256,10 @@ int _snd_pcm_hw_param_setinteger(snd_pcm_hw_params_t *params, int changed; assert(hw_is_interval(var)); changed = interval_setinteger(hw_param_interval(params, var)); - if (changed) + if (changed) { params->cmask |= 1 << var; + params->rmask |= 1 << var; + } return changed; } @@ -268,7 +274,7 @@ int snd_pcm_hw_param_setinteger(snd_pcm_t *pcm, int changed = _snd_pcm_hw_param_setinteger(params, var); if (changed < 0) return changed; - if (changed) { + if (params->rmask) { int err = snd_pcm_hw_refine(pcm, params); if (err < 0) return err; @@ -288,8 +294,10 @@ int _snd_pcm_hw_param_first(snd_pcm_hw_params_t *params, assert(0); return -EINVAL; } - if (changed) + if (changed) { params->cmask |= 1 << var; + params->rmask |= 1 << var; + } return changed; } @@ -305,7 +313,7 @@ int snd_pcm_hw_param_first(snd_pcm_t *pcm, int changed = _snd_pcm_hw_param_first(params, var); if (changed < 0) return changed; - if (changed) { + if (params->rmask) { int err = snd_pcm_hw_refine(pcm, params); assert(err >= 0); } @@ -324,8 +332,10 @@ int _snd_pcm_hw_param_last(snd_pcm_hw_params_t *params, assert(0); return -EINVAL; } - if (changed) + if (changed) { params->cmask |= 1 << var; + params->rmask |= 1 << var; + } return changed; } @@ -341,7 +351,7 @@ int snd_pcm_hw_param_last(snd_pcm_t *pcm, int changed = _snd_pcm_hw_param_last(params, var); if (changed < 0) return changed; - if (changed) { + if (params->rmask) { int err = snd_pcm_hw_refine(pcm, params); assert(err >= 0); } @@ -371,8 +381,10 @@ int _snd_pcm_hw_param_min(snd_pcm_hw_params_t *params, assert(0); return -EINVAL; } - if (changed) + if (changed) { params->cmask |= 1 << var; + params->rmask |= 1 << var; + } return changed; } @@ -386,7 +398,7 @@ int snd_pcm_hw_param_min(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, int changed = _snd_pcm_hw_param_min(params, var, val, dir ? *dir : 0); if (changed < 0) return changed; - if (changed) { + if (params->rmask) { int err = snd_pcm_hw_refine(pcm, params); if (err < 0) return err; @@ -432,8 +444,10 @@ int _snd_pcm_hw_param_max(snd_pcm_hw_params_t *params, assert(0); return -EINVAL; } - if (changed) + if (changed) { params->cmask |= 1 << var; + params->rmask |= 1 << var; + } return changed; } @@ -447,7 +461,7 @@ int snd_pcm_hw_param_max(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, int changed = _snd_pcm_hw_param_max(params, var, val, dir ? *dir : 0); if (changed < 0) return changed; - if (changed) { + if (params->rmask) { int err = snd_pcm_hw_refine(pcm, params); if (err < 0) return err; @@ -527,8 +541,10 @@ int _snd_pcm_hw_param_minmax(snd_pcm_hw_params_t *params, assert(0); return -EINVAL; } - if (changed) + if (changed) { params->cmask |= 1 << var; + params->rmask |= 1 << var; + } return changed; } @@ -546,7 +562,7 @@ int snd_pcm_hw_param_minmax(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, *max, maxdir ? *maxdir : 0); if (changed < 0) return changed; - if (changed) { + if (params->rmask) { int err = snd_pcm_hw_refine(pcm, params); if (err < 0) return err; @@ -614,8 +630,10 @@ int _snd_pcm_hw_param_set(snd_pcm_hw_params_t *params, assert(0); return -EINVAL; } - if (changed) + if (changed) { params->cmask |= 1 << var; + params->rmask |= 1 << var; + } return changed; } @@ -629,7 +647,7 @@ int snd_pcm_hw_param_set(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, int changed = _snd_pcm_hw_param_set(params, var, val, dir); if (changed < 0) return changed; - if (changed) { + if (params->rmask) { int err = snd_pcm_hw_refine(pcm, params); if (err < 0) return err; @@ -655,8 +673,10 @@ int _snd_pcm_hw_param_mask(snd_pcm_hw_params_t *params, int changed; assert(hw_is_mask(var)); changed = mask_refine(hw_param_mask(params, var), val); - if (changed) + if (changed) { params->cmask |= 1 << var; + params->rmask |= 1 << var; + } return changed; } @@ -673,7 +693,7 @@ int snd_pcm_hw_param_mask(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, int changed = _snd_pcm_hw_param_mask(params, var, val); if (changed < 0) return changed; - if (changed) { + if (params->rmask) { int err = snd_pcm_hw_refine(pcm, params); if (err < 0) return err; @@ -706,7 +726,6 @@ int snd_pcm_hw_param_near(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, int v; unsigned int saved_min; int last = 0; - unsigned int cmask; int min, max; int mindir, maxdir; int valdir = dir ? *dir : 0; @@ -747,12 +766,10 @@ int snd_pcm_hw_param_near(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, last = 1; } _end: - cmask = params->cmask; if (last) v = snd_pcm_hw_param_last(pcm, params, var, dir); else v = snd_pcm_hw_param_first(pcm, params, var, dir); - params->cmask |= cmask; assert(v >= 0); return v; } @@ -773,7 +790,6 @@ int snd_pcm_hw_param_next(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_hw_params_t save; int v; int last = 0; - unsigned int cmask; int min, max; int mindir, maxdir; int diff, diffdir; @@ -821,12 +837,10 @@ int snd_pcm_hw_param_next(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, last = 1; } _end: - cmask = params->cmask; if (last) v = snd_pcm_hw_param_last(pcm, params, var, dir); else v = snd_pcm_hw_param_first(pcm, params, var, dir); - params->cmask |= cmask; assert(v >= 0); return v; } @@ -857,10 +871,10 @@ void snd_pcm_hw_param_near_minmax(snd_pcm_t *pcm, assert(err >= 0); } -void snd_pcm_hw_param_near_copy(snd_pcm_t *pcm, - snd_pcm_hw_params_t *params, - snd_pcm_hw_param_t var, - const snd_pcm_hw_params_t *src) +void snd_pcm_hw_param_refine_near(snd_pcm_t *pcm, + snd_pcm_hw_params_t *params, + snd_pcm_hw_param_t var, + const snd_pcm_hw_params_t *src) { unsigned int min, max; int mindir, maxdir; @@ -963,41 +977,30 @@ int snd_pcm_hw_params_info_fifo_size(const snd_pcm_hw_params_t *params) void snd_pcm_hw_params_choose(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) { int err; - unsigned int cmask = params->cmask; err = snd_pcm_hw_param_first(pcm, params, SND_PCM_HW_PARAM_ACCESS, 0); assert(err >= 0); - cmask |= params->cmask; err = snd_pcm_hw_param_first(pcm, params, SND_PCM_HW_PARAM_FORMAT, 0); assert(err >= 0); - cmask |= params->cmask; err = snd_pcm_hw_param_first(pcm, params, SND_PCM_HW_PARAM_SUBFORMAT, 0); assert(err >= 0); - cmask |= params->cmask; err = snd_pcm_hw_param_first(pcm, params, SND_PCM_HW_PARAM_CHANNELS, 0); assert(err >= 0); - cmask |= params->cmask; err = snd_pcm_hw_param_first(pcm, params, SND_PCM_HW_PARAM_RATE, 0); assert(err >= 0); - cmask |= params->cmask; err = snd_pcm_hw_param_first(pcm, params, SND_PCM_HW_PARAM_PERIOD_TIME, 0); assert(err >= 0); - cmask |= params->cmask; err = snd_pcm_hw_param_last(pcm, params, SND_PCM_HW_PARAM_BUFFER_SIZE, 0); assert(err >= 0); - cmask |= params->cmask; err = snd_pcm_hw_param_first(pcm, params, SND_PCM_HW_PARAM_TICK_TIME, 0); assert(err >= 0); - cmask |= params->cmask; - - params->cmask = cmask; } /* Strategies */ @@ -1080,9 +1083,9 @@ unsigned int snd_pcm_hw_param_count(const snd_pcm_hw_params_t *params, return 0; } -int snd_pcm_hw_param_refine(snd_pcm_hw_params_t *params, - snd_pcm_hw_param_t var, - const snd_pcm_hw_params_t *src) +int _snd_pcm_hw_param_refine(snd_pcm_hw_params_t *params, + snd_pcm_hw_param_t var, + const snd_pcm_hw_params_t *src) { int changed = 0; if (hw_is_mask(var)) { @@ -1095,23 +1098,29 @@ int snd_pcm_hw_param_refine(snd_pcm_hw_params_t *params, changed = interval_refine(d, s); } else assert(0); - if (changed) + if (changed) { params->cmask |= 1 << var; + params->rmask |= 1 << var; + } return changed; } -void snd_pcm_hw_param_copy(snd_pcm_hw_params_t *params, snd_pcm_hw_param_t var, +void _snd_pcm_hw_param_copy(snd_pcm_hw_params_t *params, snd_pcm_hw_param_t var, const snd_pcm_hw_params_t *src) { if (hw_is_mask(var)) { mask_t *d = hw_param_mask(params, var); const mask_t *s = hw_param_mask_c(src, var); mask_copy(d, s); + params->cmask |= 1 << var; + params->rmask |= 1 << var; } if (hw_is_interval(var)) { interval_t *d = hw_param_interval(params, var); const interval_t *s = hw_param_interval_c(src, var); interval_copy(d, s); + params->cmask |= 1 << var; + params->rmask |= 1 << var; } assert(0); } @@ -1138,8 +1147,11 @@ void snd_pcm_hw_param_dump(const snd_pcm_hw_params_t *params, assert(f); for (k = 0; k <= MASK_MAX; ++k) { if (mask_test(mask, k)) { - snd_output_putc(out, ' '); - snd_output_puts(out, f(k)); + const char *s = f(k); + if (s) { + snd_output_putc(out, ' '); + snd_output_puts(out, s); + } } } } @@ -1188,14 +1200,11 @@ int snd_pcm_hw_params_strategy(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, best_badness = UINT_MAX; value = -1; while (1) { - unsigned int cmask; params1 = *params; value = strategy->next_value(¶ms1, var, value, &dir, pcm, strategy); if (value < 0) break; - cmask = params1.cmask; badness = snd_pcm_hw_params_strategy(pcm, ¶ms1, strategy, badness_min, badness_max); - params1.cmask |= cmask; if (badness >= 0) { if ((unsigned int) badness <= badness_min) { *params = params1; @@ -1475,7 +1484,7 @@ int snd_pcm_hw_params_try_explain_failure1(snd_pcm_t *pcm, for (var = 0; var <= SND_PCM_HW_PARAM_LAST; var++) { int err; i = *success; - snd_pcm_hw_param_copy(&i, var, fail); + _snd_pcm_hw_param_copy(&i, var, fail); err = snd_pcm_hw_refine(pcm, &i); if (err == 0 && snd_pcm_hw_params_try_explain_failure1(pcm, fail, &i, depth - 1, out) < 0) @@ -1836,50 +1845,53 @@ static interval_t refine_intervals[SND_PCM_HW_PARAM_LAST_INTERVAL - SND_PCM_HW_P }, }; +#undef RULES_DEBUG - -int _snd_pcm_hw_refine(snd_pcm_hw_params_t *params) +int snd_pcm_hw_refine_soft(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params) { unsigned int k; interval_t *i; unsigned int rstamps[RULES]; unsigned int vstamps[SND_PCM_HW_PARAM_LAST + 1]; unsigned int stamp = 2; - int err, changed; + int changed, again; +#ifdef RULES_DEBUG + snd_output_t *log; + snd_output_stdio_attach(&log, stderr, 0); +#endif for (k = SND_PCM_HW_PARAM_FIRST_MASK; k <= SND_PCM_HW_PARAM_LAST_MASK; k++) { - if (!(params->cmask & (1 << k))) + if (!(params->rmask & (1 << k))) continue; - err = mask_refine(hw_param_mask(params, k), + changed = mask_refine(hw_param_mask(params, k), &refine_masks[k - SND_PCM_HW_PARAM_FIRST_MASK]); - if (err < 0) - return err; + if (changed) + params->cmask |= 1 << k; + if (changed < 0) + goto _err; } for (k = SND_PCM_HW_PARAM_FIRST_INTERVAL; k <= SND_PCM_HW_PARAM_LAST_INTERVAL; k++) { - if (!(params->cmask & (1 << k))) + if (!(params->rmask & (1 << k))) continue; - err = interval_refine(hw_param_interval(params, k), + changed = interval_refine(hw_param_interval(params, k), &refine_intervals[k - SND_PCM_HW_PARAM_FIRST_INTERVAL]); - if (err < 0) - return err; + if (changed) + params->cmask |= 1 << k; + if (changed < 0) + goto _err; } for (k = 0; k < RULES; k++) rstamps[k] = 0; for (k = 0; k <= SND_PCM_HW_PARAM_LAST; k++) - vstamps[k] = (params->cmask & (1 << k)) ? 1 : 0; - params->cmask = 0; - changed = 1; - while (changed) { - changed = 0; + vstamps[k] = (params->rmask & (1 << k)) ? 1 : 0; + do { + again = 0; for (k = 0; k < RULES; k++) { snd_pcm_hw_rule_t *r = &refine_rules[k]; unsigned int d; int doit = 0; -#ifdef RULES_DEBUG - interval_t *i; -#endif for (d = 0; r->deps[d] >= 0; d++) { if (vstamps[r->deps[d]] > rstamps[k]) { doit = 1; @@ -1889,26 +1901,35 @@ int _snd_pcm_hw_refine(snd_pcm_hw_params_t *params) if (!doit) continue; #ifdef RULES_DEBUG - i = hw_param_interval(params, r->var); - fprintf(stderr, "Rule %d: %u ", k, r->var); - interval_print(i, stderr); + snd_output_printf(log, "Rule %d: ", k); + if (r->var >= 0) { + snd_output_printf(log, "%s=", snd_pcm_hw_param_name(r->var)); + snd_pcm_hw_param_dump(params, r->var, log); + snd_output_puts(log, " -> "); + } #endif - err = r->func(params, r); + changed = r->func(params, r); #ifdef RULES_DEBUG - interval_print(i, stderr); - putc('\n', stderr); + if (r->var >= 0) + snd_pcm_hw_param_dump(params, r->var, log); + snd_output_putc(log, ' '); + for (d = 0; r->deps[d] >= 0; d++) { + snd_output_printf(log, "%s=", snd_pcm_hw_param_name(r->deps[d])); + snd_pcm_hw_param_dump(params, r->deps[d], log); + } + snd_output_putc(log, '\n'); #endif rstamps[k] = stamp; - if (err && r->var >= 0) { + if (changed && r->var >= 0) { params->cmask |= 1 << r->var; vstamps[r->var] = stamp; - changed = 1; + again = 1; } - if (err < 0) - return err; + if (changed < 0) + goto _err; stamp++; } - } + } while (again); if (!params->msbits) { i = hw_param_interval(params, SND_PCM_HW_PARAM_SAMPLE_BITS); if (interval_single(i)) @@ -1922,69 +1943,97 @@ int _snd_pcm_hw_refine(snd_pcm_hw_params_t *params) params->rate_den = 1; } } + params->rmask = 0; return 0; + _err: +#ifdef RULES_DEBUG + snd_output_close(log); +#endif + return changed; } -int snd_pcm_hw_params_refine(snd_pcm_hw_params_t *params, - unsigned int vars, - const snd_pcm_hw_params_t *src) +int _snd_pcm_hw_params_refine(snd_pcm_hw_params_t *params, + unsigned int vars, + const snd_pcm_hw_params_t *src) { int changed, err = 0; unsigned int k; for (k = 0; k <= SND_PCM_HW_PARAM_LAST; ++k) { - if (!(vars & (1 << k)) || - !((src->cmask & (1 << k)))) + if (!(vars & (1 << k))) continue; - changed = snd_pcm_hw_param_refine(params, k, src); + changed = _snd_pcm_hw_param_refine(params, k, src); if (changed < 0) err = changed; } return err; } -/* Accumulate to params->cmask */ -/* Reset sparams->cmask */ -int snd_pcm_generic_hw_link(snd_pcm_hw_params_t *params, - snd_pcm_hw_params_t *sparams, - snd_pcm_t *slave, - unsigned long links) +int snd_pcm_hw_refine_slave(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, + int (*cprepare)(snd_pcm_t *pcm, + snd_pcm_hw_params_t *params), + int (*cchange)(snd_pcm_t *pcm, + snd_pcm_hw_params_t *params, + snd_pcm_hw_params_t *sparams), + int (*sprepare)(snd_pcm_t *pcm, + snd_pcm_hw_params_t *params), + int (*schange)(snd_pcm_t *pcm, + snd_pcm_hw_params_t *params, + snd_pcm_hw_params_t *sparams), + int (*srefine)(snd_pcm_t *pcm, + snd_pcm_hw_params_t *sparams)) + { - int err1, err = 0; - err = snd_pcm_hw_params_refine(sparams, links, params); + snd_pcm_hw_params_t sparams; + int err; + err = cprepare(pcm, params); + if (err < 0) + return err; + err = sprepare(pcm, &sparams); + if (err < 0) { + ERR("Slave PCM not useable"); + return err; + } + /* FIXME: loop begin? */ + err = schange(pcm, params, &sparams); if (err >= 0) { - unsigned int cmask = sparams->cmask; - err = snd_pcm_hw_refine(slave, sparams); - sparams->cmask |= cmask; - } - err1 = snd_pcm_hw_params_refine(params, links, sparams); - if (err1 < 0) - err = err1; - sparams->cmask = 0; - return err; + err = srefine(pcm, &sparams); + } + if (err < 0) { + cchange(pcm, params, &sparams); + return err; + } + err = cchange(pcm, params, &sparams); + if (err < 0) + return err; + err = snd_pcm_hw_refine_soft(pcm, params); + if (err < 0) + return err; + /* FIXME: do we need to loop? */ + return 0; } -int snd_pcm_hw_refine2(snd_pcm_hw_params_t *params, - snd_pcm_hw_params_t *sparams, - int (*func)(snd_pcm_hw_params_t *params, - snd_pcm_hw_params_t *sparams, - snd_pcm_t *slave, - unsigned long private), - snd_pcm_t *slave, - unsigned long private) -{ - int err = 0; - unsigned int cmask = 0; - while (params->cmask) { - err = func(params, sparams, slave, private); - cmask |= params->cmask; - if (err < 0) - break; - err = _snd_pcm_hw_refine(params); - cmask |= params->cmask; - if (err < 0) - break; - } - params->cmask = cmask; +int snd_pcm_hw_params_slave(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, + int (*cchange)(snd_pcm_t *pcm, + snd_pcm_hw_params_t *params, + snd_pcm_hw_params_t *sparams), + int (*sprepare)(snd_pcm_t *pcm, + snd_pcm_hw_params_t *params), + int (*schange)(snd_pcm_t *pcm, + snd_pcm_hw_params_t *params, + snd_pcm_hw_params_t *sparams), + int (*sparams)(snd_pcm_t *pcm, + snd_pcm_hw_params_t *sparams)) + +{ + snd_pcm_hw_params_t slave_params; + int err; + err = sprepare(pcm, &slave_params); + assert(err >= 0); + err = schange(pcm, params, &slave_params); + assert(err >= 0); + err = sparams(pcm, &slave_params); + if (err < 0) + cchange(pcm, params, &slave_params); return err; } diff --git a/src/pcm/pcm_plug.c b/src/pcm/pcm_plug.c index 9c6bc2fb..6ee96445 100644 --- a/src/pcm/pcm_plug.c +++ b/src/pcm/pcm_plug.c @@ -192,182 +192,6 @@ static int snd_pcm_plug_slave_format(int format, const mask_t *format_mask) (1 << SND_PCM_FORMAT_IMA_ADPCM)) -/* Accumulate to params->cmask */ -/* Reset sparams->cmask */ -static int snd_pcm_plug_hw_link(snd_pcm_hw_params_t *params, - snd_pcm_hw_params_t *sparams, - snd_pcm_t *slave, - unsigned long private ATTRIBUTE_UNUSED) -{ - int rate_always, channels_always, format_always; - int rate_never, channels_never, format_never; - unsigned int links = (SND_PCM_HW_PARBIT_PERIOD_TIME | - SND_PCM_HW_PARBIT_TICK_TIME); - const mask_t *format_mask, *sformat_mask; - mask_t *fmt_mask = alloca(mask_sizeof()); - mask_t *sfmt_mask = alloca(mask_sizeof()); - mask_t *access_mask = alloca(mask_sizeof()); - int err; - unsigned int format; - unsigned int scmask = sparams->cmask; - snd_pcm_hw_param_near_copy(slave, sparams, SND_PCM_HW_PARAM_RATE, - params); - scmask |= sparams->cmask; - snd_pcm_hw_param_near_copy(slave, sparams, SND_PCM_HW_PARAM_CHANNELS, - params); - scmask |= sparams->cmask; - format_mask = snd_pcm_hw_param_value_mask(params, - SND_PCM_HW_PARAM_FORMAT); - sformat_mask = snd_pcm_hw_param_value_mask(sparams, - SND_PCM_HW_PARAM_FORMAT); - mask_none(sfmt_mask); - mask_none(fmt_mask); - for (format = 0; format <= SND_PCM_FORMAT_LAST; format++) { - int f; - if (!mask_test(format_mask, format)) - continue; - if (mask_test(sformat_mask, format)) - f = format; - else { - f = snd_pcm_plug_slave_format(format, sformat_mask); - if (f < 0) - continue; - } - mask_set(sfmt_mask, f); - mask_set(fmt_mask, format); - } - - err = _snd_pcm_hw_param_mask(params, - SND_PCM_HW_PARAM_FORMAT, fmt_mask); - if (err < 0) - return err; - err = _snd_pcm_hw_param_mask(sparams, - SND_PCM_HW_PARAM_FORMAT, sfmt_mask); - assert(err >= 0); - - format_always = snd_pcm_hw_param_always_eq(params, - SND_PCM_HW_PARAM_FORMAT, - sparams); - format_never = (!format_always && - snd_pcm_hw_param_never_eq(params, - SND_PCM_HW_PARAM_FORMAT, - sparams)); - - channels_always = snd_pcm_hw_param_always_eq(params, - SND_PCM_HW_PARAM_CHANNELS, - sparams); - channels_never = (!channels_always && - snd_pcm_hw_param_never_eq(params, - SND_PCM_HW_PARAM_CHANNELS, - sparams)); - - rate_always = snd_pcm_hw_param_always_eq(params, - SND_PCM_HW_PARAM_RATE, - sparams); - rate_never = (!rate_always && - snd_pcm_hw_param_never_eq(params, - SND_PCM_HW_PARAM_RATE, - sparams)); - - if (rate_always) - links |= (SND_PCM_HW_PARBIT_RATE | - SND_PCM_HW_PARBIT_PERIOD_SIZE | - SND_PCM_HW_PARBIT_PERIODS | - SND_PCM_HW_PARBIT_BUFFER_TIME | - SND_PCM_HW_PARBIT_BUFFER_SIZE); - else { - interval_t t; - const interval_t *sbuffer_size, *buffer_size; - const interval_t *srate, *rate; - buffer_size = snd_pcm_hw_param_value_interval(params, SND_PCM_HW_PARAM_BUFFER_SIZE); - sbuffer_size = snd_pcm_hw_param_value_interval(sparams, SND_PCM_HW_PARAM_BUFFER_SIZE); - rate = snd_pcm_hw_param_value_interval(params, SND_PCM_HW_PARAM_RATE); - srate = snd_pcm_hw_param_value_interval(sparams, SND_PCM_HW_PARAM_RATE); - interval_muldiv(sbuffer_size, rate, srate, &t); - interval_round(&t); - err = _snd_pcm_hw_param_refine_interval(params, SND_PCM_HW_PARAM_BUFFER_SIZE, &t); - if (err < 0) - return err; - interval_muldiv(buffer_size, srate, rate, &t); - interval_round(&t); - err = _snd_pcm_hw_param_refine_interval(sparams, SND_PCM_HW_PARAM_BUFFER_SIZE, &t); - assert(err >= 0); - scmask |= sparams->cmask; - } - if (channels_always) - links |= SND_PCM_HW_PARBIT_CHANNELS; - if (format_always) { - links |= (SND_PCM_HW_PARBIT_FORMAT | - SND_PCM_HW_PARBIT_SUBFORMAT | - SND_PCM_HW_PARBIT_SAMPLE_BITS); - if (channels_always) { - links |= SND_PCM_HW_PARBIT_FRAME_BITS; - if (rate_always) - links |= (SND_PCM_HW_PARBIT_PERIOD_BYTES | - SND_PCM_HW_PARBIT_BUFFER_BYTES); - } - } - - mask_load(access_mask, SND_PCM_ACCBIT_PLUGIN); - if (format_never || channels_never || rate_never) { - mask_t *mmap_mask = alloca(mask_sizeof()); - mask_load(mmap_mask, SND_PCM_ACCBIT_MMAP); - err = _snd_pcm_hw_param_mask(sparams, SND_PCM_HW_PARAM_ACCESS, - mmap_mask); - assert(err >= 0); - } else - mask_union(access_mask, snd_pcm_hw_param_value_mask(sparams, SND_PCM_HW_PARAM_ACCESS)); - err = _snd_pcm_hw_param_mask(params, SND_PCM_HW_PARAM_ACCESS, - access_mask); - if (err < 0) - return err; - sparams->cmask |= scmask; - return snd_pcm_generic_hw_link(params, sparams, slave, links); -} - -static int snd_pcm_plug_hw_refine1(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, - snd_pcm_hw_params_t *sparams) -{ - snd_pcm_plug_t *plug = pcm->private; - snd_pcm_t *slave = plug->req_slave; - unsigned int cmask, lcmask; - int err; - - cmask = params->cmask; - params->cmask = 0; - err = _snd_pcm_hw_param_min(params, SND_PCM_HW_PARAM_CHANNELS, 1, 0); - if (err < 0) - return err; - err = _snd_pcm_hw_param_max(params, SND_PCM_HW_PARAM_CHANNELS, 1024, 0); - if (err < 0) - return err; - err = _snd_pcm_hw_param_min(params, SND_PCM_HW_PARAM_RATE, RATE_MIN, 0); - if (err < 0) - return err; - err = _snd_pcm_hw_param_max(params, SND_PCM_HW_PARAM_RATE, RATE_MAX, 0); - if (err < 0) - return err; - lcmask = params->cmask; - params->cmask |= cmask; - - _snd_pcm_hw_params_any(sparams); - err = snd_pcm_hw_refine2(params, sparams, - snd_pcm_plug_hw_link, slave, 0); - params->cmask |= lcmask; - if (err < 0) - return err; - params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID); - return 0; -} - - - -static int snd_pcm_plug_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) -{ - snd_pcm_hw_params_t sparams; - return snd_pcm_plug_hw_refine1(pcm, params, &sparams); -} - static void snd_pcm_plug_clear(snd_pcm_t *pcm) { snd_pcm_plug_t *plug = pcm->private; @@ -580,13 +404,164 @@ static int snd_pcm_plug_insert_plugins(snd_pcm_t *pcm, return 0; } +static int snd_pcm_plug_hw_refine_cprepare(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params ATTRIBUTE_UNUSED) +{ + return 0; +} + +static int snd_pcm_plug_hw_refine_sprepare(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *sparams) +{ + snd_pcm_plug_t *plug = pcm->private; + snd_pcm_t *slave = plug->req_slave; + return snd_pcm_hw_params_any(slave, sparams); +} + +static int snd_pcm_plug_hw_refine_schange(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, + snd_pcm_hw_params_t *sparams) +{ + snd_pcm_plug_t *plug = pcm->private; + snd_pcm_t *slave = plug->req_slave; + unsigned int links = (SND_PCM_HW_PARBIT_PERIOD_TIME | + SND_PCM_HW_PARBIT_TICK_TIME); + const mask_t *format_mask, *sformat_mask; + mask_t *sfmt_mask = alloca(mask_sizeof()); + int err; + unsigned int format; + interval_t t; + const interval_t *buffer_size; + const interval_t *srate, *crate; + err = _snd_pcm_hw_params_refine(sparams, links, params); + if (err < 0) + return err; + snd_pcm_hw_param_refine_near(slave, sparams, SND_PCM_HW_PARAM_RATE, + params); + snd_pcm_hw_param_refine_near(slave, sparams, SND_PCM_HW_PARAM_CHANNELS, + params); + format_mask = snd_pcm_hw_param_value_mask(params, + SND_PCM_HW_PARAM_FORMAT); + sformat_mask = snd_pcm_hw_param_value_mask(sparams, + SND_PCM_HW_PARAM_FORMAT); + mask_none(sfmt_mask); + for (format = 0; format <= SND_PCM_FORMAT_LAST; format++) { + int f; + if (!mask_test(format_mask, format)) + continue; + if (mask_test(sformat_mask, format)) + f = format; + else { + f = snd_pcm_plug_slave_format(format, sformat_mask); + if (f < 0) + continue; + } + mask_set(sfmt_mask, f); + } + + err = snd_pcm_hw_param_mask(slave, sparams, + SND_PCM_HW_PARAM_FORMAT, sfmt_mask); + assert(err >= 0); + + if (snd_pcm_hw_param_never_eq(params, SND_PCM_HW_PARAM_FORMAT, sparams) || + snd_pcm_hw_param_never_eq(params, SND_PCM_HW_PARAM_CHANNELS, sparams) || + snd_pcm_hw_param_never_eq(params, SND_PCM_HW_PARAM_RATE, sparams) || + snd_pcm_hw_param_never_eq(params, SND_PCM_HW_PARAM_ACCESS, sparams)) { + mask_t *access_mask = alloca(mask_sizeof()); + mask_load(access_mask, SND_PCM_ACCBIT_MMAP); + _snd_pcm_hw_param_mask(sparams, SND_PCM_HW_PARAM_ACCESS, + access_mask); + } + buffer_size = snd_pcm_hw_param_value_interval(params, SND_PCM_HW_PARAM_BUFFER_SIZE); + crate = snd_pcm_hw_param_value_interval(params, SND_PCM_HW_PARAM_RATE); + srate = snd_pcm_hw_param_value_interval(sparams, SND_PCM_HW_PARAM_RATE); + interval_muldiv(buffer_size, srate, crate, &t); + interval_round(&t); + err = _snd_pcm_hw_param_refine_interval(sparams, SND_PCM_HW_PARAM_BUFFER_SIZE, &t); + if (err < 0) + return err; + return 0; +} + +static int snd_pcm_plug_hw_refine_cchange(snd_pcm_t *pcm ATTRIBUTE_UNUSED, + snd_pcm_hw_params_t *params, + snd_pcm_hw_params_t *sparams) +{ + unsigned int links = (SND_PCM_HW_PARBIT_PERIOD_TIME | + SND_PCM_HW_PARBIT_TICK_TIME); + const mask_t *format_mask, *sformat_mask; + mask_t *fmt_mask = alloca(mask_sizeof()); + int err; + unsigned int format; + interval_t t; + const interval_t *sbuffer_size; + const interval_t *srate, *crate; + format_mask = snd_pcm_hw_param_value_mask(params, + SND_PCM_HW_PARAM_FORMAT); + sformat_mask = snd_pcm_hw_param_value_mask(sparams, + SND_PCM_HW_PARAM_FORMAT); + mask_none(fmt_mask); + for (format = 0; format <= SND_PCM_FORMAT_LAST; format++) { + int f; + if (!mask_test(format_mask, format)) + continue; + if (mask_test(sformat_mask, format)) + f = format; + else { + f = snd_pcm_plug_slave_format(format, sformat_mask); + if (f < 0) + continue; + } + mask_set(fmt_mask, format); + } + + err = _snd_pcm_hw_param_mask(params, + SND_PCM_HW_PARAM_FORMAT, fmt_mask); + if (err < 0) + return err; + + sbuffer_size = snd_pcm_hw_param_value_interval(sparams, SND_PCM_HW_PARAM_BUFFER_SIZE); + crate = snd_pcm_hw_param_value_interval(params, SND_PCM_HW_PARAM_RATE); + srate = snd_pcm_hw_param_value_interval(sparams, SND_PCM_HW_PARAM_RATE); + interval_muldiv(sbuffer_size, crate, srate, &t); + interval_round(&t); + err = _snd_pcm_hw_param_refine_interval(params, SND_PCM_HW_PARAM_BUFFER_SIZE, &t); + if (err < 0) + return err; + err = _snd_pcm_hw_params_refine(params, links, sparams); + if (err < 0) + return err; + /* FIXME */ + params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID); + return 0; +} + +static int snd_pcm_plug_hw_refine_slave(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) +{ + snd_pcm_plug_t *plug = pcm->private; + return snd_pcm_hw_refine(plug->req_slave, params); +} + +static int snd_pcm_plug_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) +{ + return snd_pcm_hw_refine_slave(pcm, params, + snd_pcm_plug_hw_refine_cprepare, + snd_pcm_plug_hw_refine_cchange, + snd_pcm_plug_hw_refine_sprepare, + snd_pcm_plug_hw_refine_schange, + snd_pcm_plug_hw_refine_slave); +} + static int snd_pcm_plug_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) { snd_pcm_plug_t *plug = pcm->private; snd_pcm_t *slave = plug->req_slave; snd_pcm_plug_params_t clt_params, slv_params; snd_pcm_hw_params_t sparams; - int err = snd_pcm_plug_hw_refine1(pcm, params, &sparams); + int err; + + err = snd_pcm_plug_hw_refine_sprepare(pcm, &sparams); + assert(err >= 0); + err = snd_pcm_plug_hw_refine_schange(pcm, params, &sparams); + assert(err >= 0); + err = snd_pcm_hw_refine_soft(slave, &sparams); assert(err >= 0); clt_params.access = snd_pcm_hw_param_value(params, SND_PCM_HW_PARAM_ACCESS, 0); @@ -594,21 +569,14 @@ static int snd_pcm_plug_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) clt_params.channels = snd_pcm_hw_param_value(params, SND_PCM_HW_PARAM_CHANNELS, 0); clt_params.rate = snd_pcm_hw_param_value(params, SND_PCM_HW_PARAM_RATE, 0); + slv_params.access = snd_pcm_hw_param_first(slave, &sparams, SND_PCM_HW_PARAM_ACCESS, 0); slv_params.format = snd_pcm_hw_param_value(&sparams, SND_PCM_HW_PARAM_FORMAT, 0); slv_params.channels = snd_pcm_hw_param_value(&sparams, SND_PCM_HW_PARAM_CHANNELS, 0); slv_params.rate = snd_pcm_hw_param_value(&sparams, SND_PCM_HW_PARAM_RATE, 0); snd_pcm_plug_clear(pcm); - if (clt_params.format == slv_params.format && - clt_params.channels == slv_params.channels && - clt_params.rate == slv_params.rate && - snd_pcm_hw_param_test(params, SND_PCM_HW_PARAM_ACCESS, clt_params.access)) - slv_params.access = clt_params.access; - else { - slv_params.access = snd_pcm_hw_param_first(slave, &sparams, SND_PCM_HW_PARAM_ACCESS, 0); - err = snd_pcm_plug_insert_plugins(pcm, &clt_params, &slv_params); - if (err < 0) - return err; - } + err = snd_pcm_plug_insert_plugins(pcm, &clt_params, &slv_params); + if (err < 0) + return err; err = snd_pcm_hw_params(plug->slave, params); if (err < 0) { snd_pcm_plug_clear(pcm); diff --git a/src/pcm/pcm_plugin.c b/src/pcm/pcm_plugin.c index f98d08f7..78eb5583 100644 --- a/src/pcm/pcm_plugin.c +++ b/src/pcm/pcm_plugin.c @@ -340,6 +340,18 @@ int snd_pcm_plugin_poll_descriptor(snd_pcm_t *pcm) return snd_pcm_poll_descriptor(plugin->slave); } +int snd_pcm_plugin_hw_refine_slave(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) +{ + snd_pcm_plugin_t *plugin = pcm->private; + return snd_pcm_hw_refine(plugin->slave, params); +} + +int snd_pcm_plugin_hw_params_slave(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) +{ + snd_pcm_plugin_t *plugin = pcm->private; + return snd_pcm_hw_params(plugin->slave, params); +} + int conv_index(int src_format, int dst_format) { int src_endian, dst_endian, sign, src_width, dst_width; diff --git a/src/pcm/pcm_plugin.h b/src/pcm/pcm_plugin.h index ef723353..62f75ddc 100644 --- a/src/pcm/pcm_plugin.h +++ b/src/pcm/pcm_plugin.h @@ -64,6 +64,8 @@ int snd_pcm_plugin_poll_descriptor(snd_pcm_t *pcm); int get_index(int src_format, int dst_format); int put_index(int src_format, int dst_format); int conv_index(int src_format, int dst_format); +int snd_pcm_plugin_hw_params_slave(snd_pcm_t *pcm, snd_pcm_hw_params_t *params); +int snd_pcm_plugin_hw_refine_slave(snd_pcm_t *pcm, snd_pcm_hw_params_t *params); #define SND_PCM_FMTBIT_LINEAR \ ((1 << SND_PCM_FORMAT_S8 ) | (1 << SND_PCM_FORMAT_U8) | \ diff --git a/src/pcm/pcm_rate.c b/src/pcm/pcm_rate.c index aacdf344..d793be91 100644 --- a/src/pcm/pcm_rate.c +++ b/src/pcm/pcm_rate.c @@ -23,6 +23,7 @@ #include #include "pcm_local.h" #include "pcm_plugin.h" +#include "interval.h" #define DIV (1<<16) @@ -233,30 +234,23 @@ static int snd_pcm_rate_close(snd_pcm_t *pcm) return 0; } -static int snd_pcm_rate_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) +static int snd_pcm_rate_hw_refine_cprepare(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params) { - snd_pcm_rate_t *rate = pcm->private; - snd_pcm_t *slave = rate->plug.slave; int err; - unsigned int cmask, lcmask; - snd_pcm_hw_params_t sparams; - unsigned int links = (SND_PCM_HW_PARBIT_CHANNELS | - SND_PCM_HW_PARBIT_PERIOD_TIME | - SND_PCM_HW_PARBIT_TICK_TIME); mask_t *access_mask = alloca(mask_sizeof()); mask_t *format_mask = alloca(mask_sizeof()); - mask_t *saccess_mask = alloca(mask_sizeof()); mask_load(access_mask, SND_PCM_ACCBIT_PLUGIN); mask_load(format_mask, SND_PCM_FMTBIT_LINEAR); - mask_load(saccess_mask, SND_PCM_ACCBIT_MMAP); - cmask = params->cmask; - params->cmask = 0; err = _snd_pcm_hw_param_mask(params, SND_PCM_HW_PARAM_ACCESS, - access_mask); + access_mask); if (err < 0) return err; err = _snd_pcm_hw_param_mask(params, SND_PCM_HW_PARAM_FORMAT, - format_mask); + format_mask); + if (err < 0) + return err; + err = _snd_pcm_hw_param_set(params, SND_PCM_HW_PARAM_SUBFORMAT, + SND_PCM_SUBFORMAT_STD, 0); if (err < 0) return err; err = _snd_pcm_hw_param_min(params, @@ -267,81 +261,114 @@ static int snd_pcm_rate_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) SND_PCM_HW_PARAM_RATE, RATE_MAX, 0); if (err < 0) return err; - lcmask = params->cmask; - params->cmask |= cmask; + params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID); + return 0; +} - _snd_pcm_hw_params_any(&sparams); - _snd_pcm_hw_param_mask(&sparams, SND_PCM_HW_PARAM_ACCESS, +static int snd_pcm_rate_hw_refine_sprepare(snd_pcm_t *pcm, snd_pcm_hw_params_t *sparams) +{ + snd_pcm_rate_t *rate = pcm->private; + mask_t *saccess_mask = alloca(mask_sizeof()); + mask_load(saccess_mask, SND_PCM_ACCBIT_MMAP); + _snd_pcm_hw_params_any(sparams); + _snd_pcm_hw_param_mask(sparams, SND_PCM_HW_PARAM_ACCESS, saccess_mask); - snd_pcm_hw_param_near_copy(slave, &sparams, - SND_PCM_HW_PARAM_BUFFER_TIME, - params); if (rate->sformat >= 0) { - _snd_pcm_hw_param_set(&sparams, SND_PCM_HW_PARAM_FORMAT, + _snd_pcm_hw_param_set(sparams, SND_PCM_HW_PARAM_FORMAT, rate->sformat, 0); - _snd_pcm_hw_param_set(&sparams, SND_PCM_HW_PARAM_SUBFORMAT, + _snd_pcm_hw_param_set(sparams, SND_PCM_HW_PARAM_SUBFORMAT, SND_PCM_SUBFORMAT_STD, 0); - } else + } + _snd_pcm_hw_param_set(sparams, SND_PCM_HW_PARAM_RATE, + rate->srate, 0); + return 0; +} + +static int snd_pcm_rate_hw_refine_schange(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, + snd_pcm_hw_params_t *sparams) +{ + snd_pcm_rate_t *rate = pcm->private; + interval_t t; + const interval_t *buffer_size; + const interval_t *srate, *crate; + int err; + unsigned int links = (SND_PCM_HW_PARBIT_CHANNELS | + SND_PCM_HW_PARBIT_PERIOD_TIME | + SND_PCM_HW_PARBIT_TICK_TIME); + if (rate->sformat < 0) links |= (SND_PCM_HW_PARBIT_FORMAT | SND_PCM_HW_PARBIT_SUBFORMAT | SND_PCM_HW_PARBIT_SAMPLE_BITS | SND_PCM_HW_PARBIT_FRAME_BITS); - _snd_pcm_hw_param_set(&sparams, SND_PCM_HW_PARAM_RATE, - rate->srate, 0); - - err = snd_pcm_hw_refine2(params, &sparams, - snd_pcm_generic_hw_link, slave, links); - params->cmask |= lcmask; + buffer_size = snd_pcm_hw_param_value_interval(params, SND_PCM_HW_PARAM_BUFFER_SIZE); + crate = snd_pcm_hw_param_value_interval(params, SND_PCM_HW_PARAM_RATE); + srate = snd_pcm_hw_param_value_interval(sparams, SND_PCM_HW_PARAM_RATE); + interval_muldiv(buffer_size, srate, crate, &t); + interval_round(&t); + err = _snd_pcm_hw_param_refine_interval(sparams, SND_PCM_HW_PARAM_BUFFER_SIZE, &t); + if (err < 0) + return err; + err = _snd_pcm_hw_params_refine(sparams, links, params); if (err < 0) return err; - params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID); return 0; } - -static int snd_pcm_rate_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params) + +static int snd_pcm_rate_hw_refine_cchange(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, + snd_pcm_hw_params_t *sparams) { snd_pcm_rate_t *rate = pcm->private; - snd_pcm_t *slave = rate->plug.slave; + interval_t t; + const interval_t *sbuffer_size; + const interval_t *srate, *crate; int err; - snd_pcm_hw_params_t sparams; unsigned int links = (SND_PCM_HW_PARBIT_CHANNELS | SND_PCM_HW_PARBIT_PERIOD_TIME | SND_PCM_HW_PARBIT_TICK_TIME); - unsigned int src_format, dst_format; - unsigned int src_rate, dst_rate; - mask_t *saccess_mask = alloca(mask_sizeof()); - mask_load(saccess_mask, SND_PCM_ACCBIT_MMAP); - - _snd_pcm_hw_params_any(&sparams); - _snd_pcm_hw_param_mask(&sparams, SND_PCM_HW_PARAM_ACCESS, - saccess_mask); - if (rate->sformat >= 0) { - _snd_pcm_hw_param_set(&sparams, SND_PCM_HW_PARAM_FORMAT, - rate->sformat, 0); - _snd_pcm_hw_param_set(&sparams, SND_PCM_HW_PARAM_SUBFORMAT, - SND_PCM_SUBFORMAT_STD, 0); - } else + if (rate->sformat < 0) links |= (SND_PCM_HW_PARBIT_FORMAT | SND_PCM_HW_PARBIT_SUBFORMAT | SND_PCM_HW_PARBIT_SAMPLE_BITS | SND_PCM_HW_PARBIT_FRAME_BITS); + sbuffer_size = snd_pcm_hw_param_value_interval(sparams, SND_PCM_HW_PARAM_BUFFER_SIZE); + crate = snd_pcm_hw_param_value_interval(params, SND_PCM_HW_PARAM_RATE); + srate = snd_pcm_hw_param_value_interval(sparams, SND_PCM_HW_PARAM_RATE); + interval_muldiv(sbuffer_size, crate, srate, &t); + interval_round(&t); + err = _snd_pcm_hw_param_refine_interval(params, SND_PCM_HW_PARAM_BUFFER_SIZE, &t); + if (err < 0) + return err; + err = _snd_pcm_hw_params_refine(params, links, sparams); + if (err < 0) + return err; + return 0; +} - _snd_pcm_hw_param_set(&sparams, SND_PCM_HW_PARAM_RATE, - rate->srate, 0); +static int snd_pcm_rate_hw_refine(snd_pcm_t *pcm, + snd_pcm_hw_params_t *params) +{ + return snd_pcm_hw_refine_slave(pcm, params, + snd_pcm_rate_hw_refine_cprepare, + snd_pcm_rate_hw_refine_cchange, + snd_pcm_rate_hw_refine_sprepare, + snd_pcm_rate_hw_refine_schange, + snd_pcm_plugin_hw_refine_slave); +} - snd_pcm_hw_param_near_copy(slave, &sparams, - SND_PCM_HW_PARAM_BUFFER_TIME, - params); - - err = snd_pcm_hw_params_refine(&sparams, links, params); - assert(err >= 0); - err = snd_pcm_hw_params(slave, &sparams); - params->cmask = 0; - sparams.cmask = ~0U; - snd_pcm_hw_params_refine(params, links, &sparams); +static int snd_pcm_rate_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params) +{ + snd_pcm_rate_t *rate = pcm->private; + snd_pcm_t *slave = rate->plug.slave; + unsigned int src_format, dst_format; + unsigned int src_rate, dst_rate; + int err = snd_pcm_hw_params_slave(pcm, params, + snd_pcm_rate_hw_refine_cchange, + snd_pcm_rate_hw_refine_sprepare, + snd_pcm_rate_hw_refine_schange, + snd_pcm_plugin_hw_params_slave); if (err < 0) return err; - params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID); + if (pcm->stream == SND_PCM_STREAM_PLAYBACK) { src_format = snd_pcm_hw_param_value(params, SND_PCM_HW_PARAM_FORMAT, 0); dst_format = slave->format; diff --git a/src/pcm/pcm_route.c b/src/pcm/pcm_route.c index 01b209ed..afe6ce5f 100644 --- a/src/pcm/pcm_route.c +++ b/src/pcm/pcm_route.c @@ -425,80 +425,82 @@ static int snd_pcm_route_close(snd_pcm_t *pcm) return 0; } -static int snd_pcm_route_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) +static int snd_pcm_route_hw_refine_cprepare(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params) { - snd_pcm_route_t *route = pcm->private; - snd_pcm_t *slave = route->plug.slave; int err; - unsigned int cmask, lcmask; - snd_pcm_hw_params_t sparams; - unsigned int links = (SND_PCM_HW_PARBIT_RATE | - SND_PCM_HW_PARBIT_PERIODS | - SND_PCM_HW_PARBIT_PERIOD_SIZE | - SND_PCM_HW_PARBIT_PERIOD_TIME | - SND_PCM_HW_PARBIT_BUFFER_SIZE | - SND_PCM_HW_PARBIT_BUFFER_TIME | - SND_PCM_HW_PARBIT_TICK_TIME); mask_t *access_mask = alloca(mask_sizeof()); mask_t *format_mask = alloca(mask_sizeof()); - mask_t *saccess_mask = alloca(mask_sizeof()); mask_load(access_mask, SND_PCM_ACCBIT_PLUGIN); mask_load(format_mask, SND_PCM_FMTBIT_LINEAR); - mask_load(saccess_mask, SND_PCM_ACCBIT_MMAP); - cmask = params->cmask; - params->cmask = 0; err = _snd_pcm_hw_param_mask(params, SND_PCM_HW_PARAM_ACCESS, - access_mask); + access_mask); if (err < 0) return err; err = _snd_pcm_hw_param_mask(params, SND_PCM_HW_PARAM_FORMAT, - format_mask); + format_mask); + if (err < 0) + return err; + err = _snd_pcm_hw_param_set(params, SND_PCM_HW_PARAM_SUBFORMAT, + SND_PCM_SUBFORMAT_STD, 0); if (err < 0) return err; err = _snd_pcm_hw_param_min(params, SND_PCM_HW_PARAM_CHANNELS, 1, 0); if (err < 0) return err; - lcmask = params->cmask; - params->cmask |= cmask; + params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID); + return 0; +} - _snd_pcm_hw_params_any(&sparams); - _snd_pcm_hw_param_mask(&sparams, SND_PCM_HW_PARAM_ACCESS, +static int snd_pcm_route_hw_refine_sprepare(snd_pcm_t *pcm, snd_pcm_hw_params_t *sparams) +{ + snd_pcm_route_t *route = pcm->private; + mask_t *saccess_mask = alloca(mask_sizeof()); + mask_load(saccess_mask, SND_PCM_ACCBIT_MMAP); + _snd_pcm_hw_params_any(sparams); + _snd_pcm_hw_param_mask(sparams, SND_PCM_HW_PARAM_ACCESS, saccess_mask); if (route->sformat >= 0) { - _snd_pcm_hw_param_set(&sparams, SND_PCM_HW_PARAM_FORMAT, + _snd_pcm_hw_param_set(sparams, SND_PCM_HW_PARAM_FORMAT, route->sformat, 0); - _snd_pcm_hw_param_set(&sparams, SND_PCM_HW_PARAM_SUBFORMAT, + _snd_pcm_hw_param_set(sparams, SND_PCM_HW_PARAM_SUBFORMAT, SND_PCM_SUBFORMAT_STD, 0); - } else + } + if (route->schannels >= 0) { + _snd_pcm_hw_param_set(sparams, SND_PCM_HW_PARAM_CHANNELS, + route->schannels, 0); + } + return 0; +} + +static int snd_pcm_route_hw_refine_schange(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, + snd_pcm_hw_params_t *sparams) +{ + snd_pcm_route_t *route = pcm->private; + int err; + unsigned int links = (SND_PCM_HW_PARBIT_RATE | + SND_PCM_HW_PARBIT_PERIODS | + SND_PCM_HW_PARBIT_PERIOD_SIZE | + SND_PCM_HW_PARBIT_PERIOD_TIME | + SND_PCM_HW_PARBIT_BUFFER_SIZE | + SND_PCM_HW_PARBIT_BUFFER_TIME | + SND_PCM_HW_PARBIT_TICK_TIME); + if (route->sformat < 0) links |= (SND_PCM_HW_PARBIT_FORMAT | SND_PCM_HW_PARBIT_SUBFORMAT | SND_PCM_HW_PARBIT_SAMPLE_BITS); - if (route->schannels >= 0) { - _snd_pcm_hw_param_set(&sparams, SND_PCM_HW_PARAM_CHANNELS, - route->schannels, 0); - } else { + if (route->schannels < 0) links |= SND_PCM_HW_PARBIT_CHANNELS; - if (route->sformat < 0) - links |= (SND_PCM_HW_PARBIT_FRAME_BITS | - SND_PCM_HW_PARBIT_PERIOD_BYTES | - SND_PCM_HW_PARBIT_BUFFER_BYTES); - } - - err = snd_pcm_hw_refine2(params, &sparams, - snd_pcm_generic_hw_link, slave, links); - params->cmask |= lcmask; + err = _snd_pcm_hw_params_refine(sparams, links, params); if (err < 0) return err; - params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID); return 0; } - -static int snd_pcm_route_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params) + +static int snd_pcm_route_hw_refine_cchange(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, + snd_pcm_hw_params_t *sparams) { snd_pcm_route_t *route = pcm->private; - snd_pcm_t *slave = route->plug.slave; int err; - snd_pcm_hw_params_t sparams; unsigned int links = (SND_PCM_HW_PARBIT_RATE | SND_PCM_HW_PARBIT_PERIODS | SND_PCM_HW_PARBIT_PERIOD_SIZE | @@ -506,42 +508,41 @@ static int snd_pcm_route_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params) SND_PCM_HW_PARBIT_BUFFER_SIZE | SND_PCM_HW_PARBIT_BUFFER_TIME | SND_PCM_HW_PARBIT_TICK_TIME); - unsigned int src_format, dst_format; - mask_t *saccess_mask = alloca(mask_sizeof()); - mask_load(saccess_mask, SND_PCM_ACCBIT_MMAP); - - _snd_pcm_hw_params_any(&sparams); - _snd_pcm_hw_param_mask(&sparams, SND_PCM_HW_PARAM_ACCESS, - saccess_mask); - if (route->sformat >= 0) { - _snd_pcm_hw_param_set(&sparams, SND_PCM_HW_PARAM_FORMAT, - route->sformat, 0); - _snd_pcm_hw_param_set(&sparams, SND_PCM_HW_PARAM_SUBFORMAT, - SND_PCM_SUBFORMAT_STD, 0); - } else + if (route->sformat < 0) links |= (SND_PCM_HW_PARBIT_FORMAT | SND_PCM_HW_PARBIT_SUBFORMAT | SND_PCM_HW_PARBIT_SAMPLE_BITS); - if (route->schannels >= 0) { - _snd_pcm_hw_param_set(&sparams, SND_PCM_HW_PARAM_CHANNELS, - route->schannels, 0); - } else { + if (route->schannels < 0) links |= SND_PCM_HW_PARBIT_CHANNELS; - if (route->sformat < 0) - links |= (SND_PCM_HW_PARBIT_FRAME_BITS | - SND_PCM_HW_PARBIT_PERIOD_BYTES | - SND_PCM_HW_PARBIT_BUFFER_BYTES); - } + err = _snd_pcm_hw_params_refine(params, links, sparams); + if (err < 0) + return err; + return 0; +} - err = snd_pcm_hw_params_refine(&sparams, links, params); - assert(err >= 0); - err = snd_pcm_hw_params(slave, &sparams); - params->cmask = 0; - sparams.cmask = ~0U; - snd_pcm_hw_params_refine(params, links, &sparams); +static int snd_pcm_route_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) +{ + return snd_pcm_hw_refine_slave(pcm, params, + snd_pcm_route_hw_refine_cprepare, + snd_pcm_route_hw_refine_cchange, + snd_pcm_route_hw_refine_sprepare, + snd_pcm_route_hw_refine_schange, + snd_pcm_plugin_hw_refine_slave); +} + +static int snd_pcm_route_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params) +{ + snd_pcm_route_t *route = pcm->private; + snd_pcm_t *slave = route->plug.slave; + unsigned int src_format, dst_format; + int err = snd_pcm_hw_params_slave(pcm, params, + snd_pcm_route_hw_refine_cchange, + snd_pcm_route_hw_refine_sprepare, + snd_pcm_route_hw_refine_schange, + snd_pcm_plugin_hw_params_slave); if (err < 0) return err; - params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID); + if (pcm->stream == SND_PCM_STREAM_PLAYBACK) { src_format = snd_pcm_hw_param_value(params, SND_PCM_HW_PARAM_FORMAT, 0); dst_format = slave->format; diff --git a/src/pcm/pcm_share.c b/src/pcm/pcm_share.c index eb67950c..57c3e573 100644 --- a/src/pcm/pcm_share.c +++ b/src/pcm/pcm_share.c @@ -427,7 +427,8 @@ static void _snd_pcm_share_update(snd_pcm_t *pcm) static int snd_pcm_share_card(snd_pcm_t *pcm ATTRIBUTE_UNUSED) { - return -ENOENT; /* not available */ + snd_pcm_share_t *share = pcm->private; + return snd_pcm_card(share->slave->pcm); } static int snd_pcm_share_nonblock(snd_pcm_t *pcm ATTRIBUTE_UNUSED, int nonblock ATTRIBUTE_UNUSED) @@ -455,25 +456,22 @@ static int snd_pcm_share_info(snd_pcm_t *pcm, snd_pcm_info_t *info) return snd_pcm_info(share->slave->pcm, info); } -static int snd_pcm_share_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) +static int snd_pcm_share_hw_refine_cprepare(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) { snd_pcm_share_t *share = pcm->private; snd_pcm_share_slave_t *slave = share->slave; - snd_pcm_hw_params_t sparams; - int err; - unsigned int cmask, lcmask; mask_t *access_mask = alloca(mask_sizeof()); - const mask_t *mmap_mask; - mask_t *saccess_mask = alloca(mask_sizeof()); - mask_load(saccess_mask, SND_PCM_ACCBIT_MMAP); - - cmask = params->cmask; - params->cmask = 0; + int err; + mask_any(access_mask); + mask_reset(access_mask, SND_PCM_ACCESS_MMAP_INTERLEAVED); + err = _snd_pcm_hw_param_mask(params, SND_PCM_HW_PARAM_ACCESS, + access_mask); + if (err < 0) + return err; err = _snd_pcm_hw_param_set(params, SND_PCM_HW_PARAM_CHANNELS, share->channels_count, 0); if (err < 0) return err; - if (slave->format >= 0) { err = _snd_pcm_hw_param_set(params, SND_PCM_HW_PARAM_FORMAT, slave->format, 0); @@ -487,44 +485,109 @@ static int snd_pcm_share_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) if (err < 0) return err; } - lcmask = params->cmask; - params->cmask |= cmask; + params->info |= SND_PCM_INFO_DOUBLE; + return 0; +} - _snd_pcm_hw_params_any(&sparams); - _snd_pcm_hw_param_mask(&sparams, SND_PCM_HW_PARAM_ACCESS, +static int snd_pcm_share_hw_refine_sprepare(snd_pcm_t *pcm, snd_pcm_hw_params_t *sparams) +{ + snd_pcm_share_t *share = pcm->private; + snd_pcm_share_slave_t *slave = share->slave; + mask_t *saccess_mask = alloca(mask_sizeof()); + mask_load(saccess_mask, SND_PCM_ACCBIT_MMAP); + _snd_pcm_hw_params_any(sparams); + _snd_pcm_hw_param_mask(sparams, SND_PCM_HW_PARAM_ACCESS, saccess_mask); - _snd_pcm_hw_param_set(&sparams, SND_PCM_HW_PARAM_CHANNELS, + _snd_pcm_hw_param_set(sparams, SND_PCM_HW_PARAM_CHANNELS, slave->channels_count, 0); - err = snd_pcm_hw_refine2(params, &sparams, - snd_pcm_generic_hw_link, slave->pcm, - SND_PCM_HW_PARBIT_FORMAT | - SND_PCM_HW_PARBIT_SUBFORMAT | - SND_PCM_HW_PARBIT_RATE | - SND_PCM_HW_PARBIT_PERIOD_SIZE | - SND_PCM_HW_PARBIT_PERIOD_TIME | - SND_PCM_HW_PARBIT_BUFFER_SIZE | - SND_PCM_HW_PARBIT_BUFFER_TIME | - SND_PCM_HW_PARBIT_PERIODS | - SND_PCM_HW_PARBIT_TICK_TIME); + return 0; +} + +static int snd_pcm_share_hw_refine_schange(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params, + snd_pcm_hw_params_t *sparams) +{ + int err; + unsigned int links = (SND_PCM_HW_PARBIT_FORMAT | + SND_PCM_HW_PARBIT_SUBFORMAT | + SND_PCM_HW_PARBIT_RATE | + SND_PCM_HW_PARBIT_PERIOD_SIZE | + SND_PCM_HW_PARBIT_PERIOD_TIME | + SND_PCM_HW_PARBIT_BUFFER_SIZE | + SND_PCM_HW_PARBIT_BUFFER_TIME | + SND_PCM_HW_PARBIT_PERIODS | + SND_PCM_HW_PARBIT_TICK_TIME); + const mask_t *access_mask = snd_pcm_hw_param_value_mask(params, SND_PCM_HW_PARAM_ACCESS); + if (!mask_test(access_mask, SND_PCM_ACCESS_RW_INTERLEAVED) && + !mask_test(access_mask, SND_PCM_ACCESS_RW_NONINTERLEAVED) && + !mask_test(access_mask, SND_PCM_ACCESS_MMAP_NONINTERLEAVED)) { + mask_t *saccess_mask = alloca(mask_sizeof()); + mask_any(saccess_mask); + mask_reset(saccess_mask, SND_PCM_ACCESS_MMAP_NONINTERLEAVED); + err = _snd_pcm_hw_param_mask(sparams, SND_PCM_HW_PARAM_ACCESS, + saccess_mask); + if (err < 0) + return err; + } + err = _snd_pcm_hw_params_refine(sparams, links, params); if (err < 0) return err; - mmap_mask = snd_pcm_hw_param_value_mask(&sparams, SND_PCM_HW_PARAM_ACCESS); + return 0; +} + +static int snd_pcm_share_hw_refine_cchange(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params, + snd_pcm_hw_params_t *sparams) +{ + int err; + unsigned int links = (SND_PCM_HW_PARBIT_FORMAT | + SND_PCM_HW_PARBIT_SUBFORMAT | + SND_PCM_HW_PARBIT_RATE | + SND_PCM_HW_PARBIT_PERIOD_SIZE | + SND_PCM_HW_PARBIT_PERIOD_TIME | + SND_PCM_HW_PARBIT_BUFFER_SIZE | + SND_PCM_HW_PARBIT_BUFFER_TIME | + SND_PCM_HW_PARBIT_PERIODS | + SND_PCM_HW_PARBIT_TICK_TIME); + mask_t *access_mask = alloca(mask_sizeof()); + const mask_t *saccess_mask = snd_pcm_hw_param_value_mask(sparams, SND_PCM_HW_PARAM_ACCESS); mask_any(access_mask); mask_reset(access_mask, SND_PCM_ACCESS_MMAP_INTERLEAVED); - if (!mask_test(mmap_mask, SND_PCM_ACCESS_MMAP_NONINTERLEAVED)) + if (!mask_test(saccess_mask, SND_PCM_ACCESS_MMAP_NONINTERLEAVED)) mask_reset(access_mask, SND_PCM_ACCESS_MMAP_NONINTERLEAVED); - if (!mask_test(mmap_mask, SND_PCM_ACCESS_MMAP_COMPLEX) && - !mask_test(mmap_mask, SND_PCM_ACCESS_MMAP_INTERLEAVED)) + if (!mask_test(saccess_mask, SND_PCM_ACCESS_MMAP_COMPLEX) && + !mask_test(saccess_mask, SND_PCM_ACCESS_MMAP_INTERLEAVED)) mask_reset(access_mask, SND_PCM_ACCESS_MMAP_COMPLEX); err = _snd_pcm_hw_param_mask(params, SND_PCM_HW_PARAM_ACCESS, - access_mask); - params->cmask |= lcmask; + access_mask); + if (err < 0) + return err; + err = _snd_pcm_hw_params_refine(params, links, sparams); if (err < 0) return err; - params->info |= SND_PCM_INFO_DOUBLE; return 0; } +static int snd_pcm_share_hw_refine_slave(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) +{ + snd_pcm_share_t *share = pcm->private; + return snd_pcm_hw_refine(share->slave->pcm, params); +} + +static int snd_pcm_share_hw_params_slave(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) +{ + snd_pcm_share_t *share = pcm->private; + return snd_pcm_hw_params(share->slave->pcm, params); +} + +static int snd_pcm_share_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) +{ + return snd_pcm_hw_refine_slave(pcm, params, + snd_pcm_share_hw_refine_cprepare, + snd_pcm_share_hw_refine_cchange, + snd_pcm_share_hw_refine_sprepare, + snd_pcm_share_hw_refine_schange, + snd_pcm_share_hw_refine_slave); +} + static int snd_pcm_share_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) { snd_pcm_share_t *share = pcm->private; @@ -534,7 +597,6 @@ static int snd_pcm_share_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) Pthread_mutex_lock(&slave->mutex); if (slave->setup_count > 1 || (slave->setup_count == 1 && !pcm->setup)) { - params->cmask = 0; err = _snd_pcm_hw_param_set(params, SND_PCM_HW_PARAM_FORMAT, spcm->format, 0); if (err < 0) @@ -564,30 +626,11 @@ static int snd_pcm_share_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) goto _end; } } else { - snd_pcm_hw_params_t sparams; - unsigned int links; - mask_t *saccess_mask = alloca(mask_sizeof()); - mask_load(saccess_mask, SND_PCM_ACCBIT_MMAP); - links = SND_PCM_HW_PARBIT_FORMAT | - SND_PCM_HW_PARBIT_SUBFORMAT | - SND_PCM_HW_PARBIT_RATE | - SND_PCM_HW_PARBIT_PERIOD_SIZE | - SND_PCM_HW_PARBIT_PERIOD_TIME | - SND_PCM_HW_PARBIT_BUFFER_SIZE | - SND_PCM_HW_PARBIT_BUFFER_TIME | - SND_PCM_HW_PARBIT_PERIODS | - SND_PCM_HW_PARBIT_TICK_TIME; - _snd_pcm_hw_params_any(&sparams); - _snd_pcm_hw_param_mask(&sparams, SND_PCM_HW_PARAM_ACCESS, - saccess_mask); - _snd_pcm_hw_param_set(&sparams, SND_PCM_HW_PARAM_CHANNELS, - share->channels_count, 0); - err = snd_pcm_hw_params_refine(&sparams, links, params); - assert(err >= 0); - err = snd_pcm_hw_params(slave->pcm, &sparams); - params->cmask = 0; - sparams.cmask = ~0U; - snd_pcm_hw_params_refine(params, links, &sparams); + err = snd_pcm_hw_params_slave(pcm, params, + snd_pcm_share_hw_refine_cchange, + snd_pcm_share_hw_refine_sprepare, + snd_pcm_share_hw_refine_schange, + snd_pcm_share_hw_params_slave); if (err < 0) goto _end; snd_pcm_sw_params_current(slave->pcm, &slave->sw_params); diff --git a/src/pcm/pcm_shm.c b/src/pcm/pcm_shm.c index 65e4e6f8..b895bde4 100644 --- a/src/pcm/pcm_shm.c +++ b/src/pcm/pcm_shm.c @@ -155,8 +155,61 @@ static int snd_pcm_shm_info(snd_pcm_t *pcm, snd_pcm_info_t * info) return err; } -static int _snd_pcm_shm_hw_refine(snd_pcm_t *pcm, - snd_pcm_hw_params_t *params) +static int snd_pcm_shm_hw_refine_cprepare(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params ATTRIBUTE_UNUSED) +{ + return 0; +} + +static int snd_pcm_shm_hw_refine_sprepare(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *sparams) +{ + mask_t *saccess_mask = alloca(mask_sizeof()); + mask_load(saccess_mask, SND_PCM_ACCBIT_MMAP); + _snd_pcm_hw_params_any(sparams); + _snd_pcm_hw_param_mask(sparams, SND_PCM_HW_PARAM_ACCESS, + saccess_mask); + return 0; +} + +static int snd_pcm_shm_hw_refine_schange(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params, + snd_pcm_hw_params_t *sparams) +{ + int err; + unsigned int links = ~SND_PCM_HW_PARBIT_ACCESS; + const mask_t *access_mask = snd_pcm_hw_param_value_mask(params, SND_PCM_HW_PARAM_ACCESS); + if (!mask_test(access_mask, SND_PCM_ACCESS_RW_INTERLEAVED) && + !mask_test(access_mask, SND_PCM_ACCESS_RW_NONINTERLEAVED)) { + err = _snd_pcm_hw_param_mask(sparams, SND_PCM_HW_PARAM_ACCESS, + access_mask); + if (err < 0) + return err; + } + err = _snd_pcm_hw_params_refine(sparams, links, params); + if (err < 0) + return err; + return 0; +} + +static int snd_pcm_shm_hw_refine_cchange(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params, + snd_pcm_hw_params_t *sparams) +{ + int err; + unsigned int links = ~SND_PCM_HW_PARBIT_ACCESS; + mask_t *access_mask = alloca(mask_sizeof()); + mask_copy(access_mask, snd_pcm_hw_param_value_mask(sparams, SND_PCM_HW_PARAM_ACCESS)); + mask_set(access_mask, SND_PCM_ACCESS_RW_INTERLEAVED); + mask_set(access_mask, SND_PCM_ACCESS_RW_NONINTERLEAVED); + err = _snd_pcm_hw_param_mask(sparams, SND_PCM_HW_PARAM_ACCESS, + access_mask); + if (err < 0) + return err; + err = _snd_pcm_hw_params_refine(params, links, sparams); + if (err < 0) + return err; + return 0; +} + +static int snd_pcm_shm_hw_refine_slave(snd_pcm_t *pcm, + snd_pcm_hw_params_t *params) { snd_pcm_shm_t *shm = pcm->private; volatile snd_pcm_shm_ctrl_t *ctrl = shm->ctrl; @@ -168,46 +221,18 @@ static int _snd_pcm_shm_hw_refine(snd_pcm_t *pcm, return err; } -/* Accumulate to params->cmask */ -/* Reset sparams->cmask */ -int snd_pcm_shm_hw_link(snd_pcm_hw_params_t *params, - snd_pcm_hw_params_t *sparams, - snd_pcm_t *slave, - unsigned long links) -{ - int err1, err = 0; - err = snd_pcm_hw_params_refine(sparams, links, params); - if (err >= 0) { - unsigned int cmask = sparams->cmask; - err = _snd_pcm_shm_hw_refine(slave, sparams); - sparams->cmask |= cmask; - } - err1 = snd_pcm_hw_params_refine(params, links, sparams); - if (err1 < 0) - err = err1; - sparams->cmask = 0; - return err; -} - static int snd_pcm_shm_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) { - snd_pcm_hw_params_t sparams; - const mask_t *access_mask = snd_pcm_hw_param_value_mask(params, SND_PCM_HW_PARAM_ACCESS); - mask_t *saccess_mask = alloca(mask_sizeof()); - mask_load(saccess_mask, SND_PCM_ACCBIT_MMAP); - if (!mask_test(access_mask, SND_PCM_ACCESS_RW_INTERLEAVED) && - !mask_test(access_mask, SND_PCM_ACCESS_RW_NONINTERLEAVED)) - mask_intersect(saccess_mask, access_mask); - _snd_pcm_hw_params_any(&sparams); - _snd_pcm_hw_param_mask(&sparams, SND_PCM_HW_PARAM_ACCESS, - saccess_mask); - return snd_pcm_hw_refine2(params, &sparams, - snd_pcm_shm_hw_link, pcm, - ~SND_PCM_HW_PARBIT_ACCESS); + return snd_pcm_hw_refine_slave(pcm, params, + snd_pcm_shm_hw_refine_cprepare, + snd_pcm_shm_hw_refine_cchange, + snd_pcm_shm_hw_refine_sprepare, + snd_pcm_shm_hw_refine_schange, + snd_pcm_shm_hw_refine_slave); } -static int _snd_pcm_shm_hw_params(snd_pcm_t *pcm, - snd_pcm_hw_params_t *params) +static int snd_pcm_shm_hw_params_slave(snd_pcm_t *pcm, + snd_pcm_hw_params_t *params) { snd_pcm_shm_t *shm = pcm->private; volatile snd_pcm_shm_ctrl_t *ctrl = shm->ctrl; @@ -221,27 +246,11 @@ static int _snd_pcm_shm_hw_params(snd_pcm_t *pcm, static int snd_pcm_shm_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params) { - snd_pcm_hw_params_t sparams; - unsigned int links = ~SND_PCM_HW_PARBIT_ACCESS; - const mask_t *access_mask = snd_pcm_hw_param_value_mask(params, SND_PCM_HW_PARAM_ACCESS); - mask_t *saccess_mask = alloca(mask_sizeof()); - int err; - mask_load(saccess_mask, SND_PCM_ACCBIT_MMAP); - if (!mask_test(access_mask, SND_PCM_ACCESS_RW_INTERLEAVED) && - !mask_test(access_mask, SND_PCM_ACCESS_RW_NONINTERLEAVED)) - mask_intersect(saccess_mask, access_mask); - _snd_pcm_hw_params_any(&sparams); - _snd_pcm_hw_param_mask(&sparams, SND_PCM_HW_PARAM_ACCESS, - saccess_mask); - err = snd_pcm_hw_params_refine(&sparams, links, params); - assert(err >= 0); - err = _snd_pcm_shm_hw_params(pcm, &sparams); - params->cmask = 0; - sparams.cmask = ~0U; - snd_pcm_hw_params_refine(params, links, &sparams); - if (err < 0) - return err; - return 0; + return snd_pcm_hw_params_slave(pcm, params, + snd_pcm_shm_hw_refine_cchange, + snd_pcm_shm_hw_refine_sprepare, + snd_pcm_shm_hw_refine_schange, + snd_pcm_shm_hw_params_slave); } static int snd_pcm_shm_sw_params(snd_pcm_t *pcm, snd_pcm_sw_params_t * params) -- 2.47.1