Major cleaning to hw_params mechanism for plugins

This commit is contained in:
Abramo Bagnara 2001-01-18 18:20:31 +00:00
parent 1747dc039f
commit 3126678e72
17 changed files with 1259 additions and 1044 deletions

View file

@ -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, static inline unsigned int div32(unsigned int a, unsigned int b,
unsigned int *r) unsigned int *r)
{ {
if (b == 0) {
*r = 0;
return UINT_MAX;
}
*r = a % b; *r = a % b;
return a / b; return a / b;
} }
static inline unsigned int div_down(unsigned int a, unsigned int b) static inline unsigned int div_down(unsigned int a, unsigned int b)
{ {
if (b == 0)
return UINT_MAX;
return a / b; return a / b;
} }
static inline unsigned int div_up(unsigned int a, unsigned int b) static inline unsigned int div_up(unsigned int a, unsigned int b)
{ {
unsigned int r; 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) if (r)
++q; ++q;
return q; return q;
@ -83,6 +92,11 @@ static inline unsigned int muldiv32(unsigned int a, unsigned int b,
unsigned int c, unsigned int *r) unsigned int c, unsigned int *r)
{ {
u_int64_t n = (u_int64_t) a * b; 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); div64_32(&n, c, r);
if (n >= UINT_MAX) { if (n >= UINT_MAX) {
*r = 0; *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 && else if (i->min == 0 && i->openmin == 0 &&
i->max == UINT_MAX && i->openmax == 0) i->max == UINT_MAX && i->openmax == 0)
snd_output_printf(out, "ALL"); 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)); snd_output_printf(out, "%u", interval_value(i));
else else
snd_output_printf(out, "%c%u %u%c", snd_output_printf(out, "%c%u %u%c",

View file

@ -329,103 +329,109 @@ static int snd_pcm_adpcm_close(snd_pcm_t *pcm)
return 0; 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_adpcm_t *adpcm = pcm->private;
snd_pcm_t *slave = adpcm->plug.slave;
int err; int err;
unsigned int cmask, lcmask;
snd_pcm_hw_params_t sparams;
mask_t *access_mask = alloca(mask_sizeof()); mask_t *access_mask = alloca(mask_sizeof());
mask_t *saccess_mask = alloca(mask_sizeof());
mask_load(access_mask, SND_PCM_ACCBIT_PLUGIN); 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, err = _snd_pcm_hw_param_mask(params, SND_PCM_HW_PARAM_ACCESS,
access_mask); access_mask);
if (err < 0) if (err < 0)
return err; return err;
if (adpcm->sformat == SND_PCM_FORMAT_IMA_ADPCM) { if (adpcm->sformat == SND_PCM_FORMAT_IMA_ADPCM) {
mask_t *format_mask = alloca(mask_sizeof()); mask_t *format_mask = alloca(mask_sizeof());
mask_load(format_mask, SND_PCM_FMTBIT_LINEAR); mask_load(format_mask, SND_PCM_FMTBIT_LINEAR);
err = _snd_pcm_hw_param_mask(params, err = _snd_pcm_hw_param_mask(params, SND_PCM_HW_PARAM_FORMAT,
SND_PCM_HW_PARAM_FORMAT, format_mask);
format_mask);
if (err < 0)
return err;
} else { } else {
err = _snd_pcm_hw_param_set(params, err = _snd_pcm_hw_param_set(params,
SND_PCM_HW_PARAM_FORMAT, SND_PCM_HW_PARAM_FORMAT,
SND_PCM_FORMAT_IMA_ADPCM, 0); 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) if (err < 0)
return err; return err;
lcmask = params->cmask; err = _snd_pcm_hw_param_set(params, SND_PCM_HW_PARAM_SUBFORMAT,
params->cmask |= cmask; SND_PCM_SUBFORMAT_STD, 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,
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;
if (err < 0) if (err < 0)
return err; return err;
params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID); params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
return 0; return 0;
} }
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;
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,
adpcm->sformat, 0);
_snd_pcm_hw_param_set(sparams, SND_PCM_HW_PARAM_SUBFORMAT,
SND_PCM_SUBFORMAT_STD, 0);
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;
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) static int snd_pcm_adpcm_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params)
{ {
snd_pcm_adpcm_t *adpcm = pcm->private; snd_pcm_adpcm_t *adpcm = pcm->private;
snd_pcm_t *slave = adpcm->plug.slave; int err = snd_pcm_hw_params_slave(pcm, params,
int err; snd_pcm_adpcm_hw_refine_cchange,
snd_pcm_hw_params_t sparams; snd_pcm_adpcm_hw_refine_sprepare,
unsigned int links; snd_pcm_adpcm_hw_refine_schange,
mask_t *saccess_mask = alloca(mask_sizeof()); snd_pcm_plugin_hw_params_slave);
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,
adpcm->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);
if (err < 0) if (err < 0)
return err; return err;
params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
if (pcm->stream == SND_PCM_STREAM_PLAYBACK) { if (pcm->stream == SND_PCM_STREAM_PLAYBACK) {
if (adpcm->sformat == SND_PCM_FORMAT_IMA_ADPCM) { 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); adpcm->getput_idx = get_index(snd_pcm_hw_param_value(params, SND_PCM_HW_PARAM_FORMAT, 0), SND_PCM_FORMAT_S16);

View file

@ -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_alaw_t *alaw = pcm->private;
snd_pcm_t *slave = alaw->plug.slave;
int err; int err;
unsigned int cmask, lcmask;
snd_pcm_hw_params_t sparams;
mask_t *access_mask = alloca(mask_sizeof()); mask_t *access_mask = alloca(mask_sizeof());
mask_t *saccess_mask = alloca(mask_sizeof());
mask_load(access_mask, SND_PCM_ACCBIT_PLUGIN); 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, err = _snd_pcm_hw_param_mask(params, SND_PCM_HW_PARAM_ACCESS,
access_mask); access_mask);
if (err < 0) if (err < 0)
return err; return err;
if (alaw->sformat == SND_PCM_FORMAT_A_LAW) { if (alaw->sformat == SND_PCM_FORMAT_A_LAW) {
mask_t *format_mask = alloca(mask_sizeof()); mask_t *format_mask = alloca(mask_sizeof());
mask_load(format_mask, SND_PCM_FMTBIT_LINEAR); mask_load(format_mask, SND_PCM_FMTBIT_LINEAR);
err = _snd_pcm_hw_param_mask(params, err = _snd_pcm_hw_param_mask(params, SND_PCM_HW_PARAM_FORMAT,
SND_PCM_HW_PARAM_FORMAT, format_mask);
format_mask);
if (err < 0)
return err;
} else { } else {
err = _snd_pcm_hw_param_set(params, err = _snd_pcm_hw_param_set(params,
SND_PCM_HW_PARAM_FORMAT, SND_PCM_HW_PARAM_FORMAT,
SND_PCM_FORMAT_A_LAW, 0); 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) if (err < 0)
return err; return err;
lcmask = params->cmask; err = _snd_pcm_hw_param_set(params, SND_PCM_HW_PARAM_SUBFORMAT,
params->cmask |= cmask; SND_PCM_SUBFORMAT_STD, 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,
alaw->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;
if (err < 0) if (err < 0)
return err; return err;
params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID); params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
return 0; return 0;
} }
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_SUBFORMAT_STD, 0);
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;
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) 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_alaw_t *alaw = pcm->private;
snd_pcm_t *slave = alaw->plug.slave; int err = snd_pcm_hw_params_slave(pcm, params,
int err; snd_pcm_alaw_hw_refine_cchange,
snd_pcm_hw_params_t sparams; snd_pcm_alaw_hw_refine_sprepare,
unsigned int links; snd_pcm_alaw_hw_refine_schange,
mask_t *saccess_mask = alloca(mask_sizeof()); snd_pcm_plugin_hw_params_slave);
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);
if (err < 0) if (err < 0)
return err; return err;
params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
if (pcm->stream == SND_PCM_STREAM_PLAYBACK) { if (pcm->stream == SND_PCM_STREAM_PLAYBACK) {
if (alaw->sformat == SND_PCM_FORMAT_A_LAW) { 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); alaw->getput_idx = get_index(snd_pcm_hw_param_value(params, SND_PCM_HW_PARAM_FORMAT, 0), SND_PCM_FORMAT_S16);

View file

@ -28,62 +28,68 @@ typedef struct {
snd_pcm_plugin_t plug; snd_pcm_plugin_t plug;
} snd_pcm_copy_t; } 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; int err;
unsigned int cmask, lcmask;
snd_pcm_hw_params_t sparams;
mask_t *access_mask = alloca(mask_sizeof()); mask_t *access_mask = alloca(mask_sizeof());
mask_t *saccess_mask = alloca(mask_sizeof());
mask_load(access_mask, SND_PCM_ACCBIT_PLUGIN); 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, err = _snd_pcm_hw_param_mask(params, SND_PCM_HW_PARAM_ACCESS,
access_mask); access_mask);
if (err < 0) if (err < 0)
return err; return err;
lcmask = params->cmask; params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
params->cmask |= cmask; return 0;
_snd_pcm_hw_params_any(&sparams); }
_snd_pcm_hw_param_mask(&sparams, SND_PCM_HW_PARAM_ACCESS,
saccess_mask); static int snd_pcm_copy_hw_refine_sprepare(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *sparams)
err = snd_pcm_hw_refine2(params, &sparams, {
snd_pcm_generic_hw_link, slave, mask_t *saccess_mask = alloca(mask_sizeof());
~SND_PCM_HW_PARBIT_ACCESS); mask_load(saccess_mask, SND_PCM_ACCBIT_MMAP);
params->cmask |= lcmask; _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_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) if (err < 0)
return err; return err;
params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID); return 0;
return err; }
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) static int snd_pcm_copy_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
{ {
snd_pcm_copy_t *copy = pcm->private; return snd_pcm_hw_params_slave(pcm, params,
snd_pcm_t *slave = copy->plug.slave; snd_pcm_copy_hw_refine_cchange,
int err; snd_pcm_copy_hw_refine_sprepare,
unsigned int links; snd_pcm_copy_hw_refine_schange,
snd_pcm_hw_params_t sparams; snd_pcm_plugin_hw_params_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);
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);
if (err < 0)
return err;
params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
return err;
} }
static snd_pcm_sframes_t snd_pcm_copy_write_areas(snd_pcm_t *pcm, static snd_pcm_sframes_t snd_pcm_copy_write_areas(snd_pcm_t *pcm,

View file

@ -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; int err;
unsigned int cmask, lcmask;
snd_pcm_hw_params_t sparams;
mask_t *access_mask = alloca(mask_sizeof()); mask_t *access_mask = alloca(mask_sizeof());
mask_t *format_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(access_mask, SND_PCM_ACCBIT_PLUGIN);
mask_load(format_mask, SND_PCM_FMTBIT_LINEAR); 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, err = _snd_pcm_hw_param_mask(params, SND_PCM_HW_PARAM_ACCESS,
access_mask); access_mask);
if (err < 0) if (err < 0)
return err; return err;
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); format_mask);
if (err < 0) if (err < 0)
return err; return err;
err = _snd_pcm_hw_param_set(params, SND_PCM_HW_PARAM_SUBFORMAT, 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;
_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);
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;
if (err < 0) if (err < 0)
return err; return err;
params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID); params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
return 0; return 0;
} }
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_SUBFORMAT_STD, 0);
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;
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) 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_linear_t *linear = pcm->private;
snd_pcm_t *slave = linear->plug.slave; int err = snd_pcm_hw_params_slave(pcm, params,
int err; snd_pcm_linear_hw_refine_cchange,
unsigned int links; snd_pcm_linear_hw_refine_sprepare,
snd_pcm_hw_params_t sparams; snd_pcm_linear_hw_refine_schange,
mask_t *saccess_mask = alloca(mask_sizeof()); snd_pcm_plugin_hw_params_slave);
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);
if (err < 0) if (err < 0)
return err; return err;
params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
if (pcm->stream == SND_PCM_STREAM_PLAYBACK) 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->conv_idx = conv_index(snd_pcm_hw_param_value(params, SND_PCM_HW_PARAM_FORMAT, 0),
linear->sformat); linear->sformat);

View file

@ -299,7 +299,33 @@ static inline int muldiv_near(int a, int b, int c)
return n; 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); 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, int _snd_pcm_hw_param_refine_interval(snd_pcm_hw_params_t *params,
snd_pcm_hw_param_t var, 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); unsigned int var, unsigned int val, int dir);
int _snd_pcm_hw_param_max(snd_pcm_hw_params_t *params, int _snd_pcm_hw_param_max(snd_pcm_hw_params_t *params,
unsigned int var, unsigned int val, int dir); unsigned int var, unsigned int val, int dir);
int snd_pcm_hw_param_refine(snd_pcm_hw_params_t *params, int _snd_pcm_hw_param_refine(snd_pcm_hw_params_t *params,
snd_pcm_hw_param_t var, 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); const snd_pcm_hw_params_t *src);
int snd_pcm_generic_hw_link(snd_pcm_hw_params_t *params, int _snd_pcm_hw_params_refine(snd_pcm_hw_params_t *params,
snd_pcm_hw_params_t *sparams, unsigned int vars,
snd_pcm_t *slave, const snd_pcm_hw_params_t *src);
unsigned long links); void snd_pcm_hw_param_refine_near(snd_pcm_t *pcm,
int snd_pcm_hw_refine2(snd_pcm_hw_params_t *params, snd_pcm_hw_params_t *params,
snd_pcm_hw_params_t *sparams, snd_pcm_hw_param_t var,
int (*func)(snd_pcm_hw_params_t *params, const snd_pcm_hw_params_t *src);
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_param_always_eq(const snd_pcm_hw_params_t *params, int snd_pcm_hw_param_always_eq(const snd_pcm_hw_params_t *params,
snd_pcm_hw_param_t var, snd_pcm_hw_param_t var,
const snd_pcm_hw_params_t *params1); const snd_pcm_hw_params_t *params1);

View file

@ -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_mulaw_t *mulaw = pcm->private;
snd_pcm_t *slave = mulaw->plug.slave;
int err; int err;
unsigned int cmask, lcmask;
snd_pcm_hw_params_t sparams;
mask_t *access_mask = alloca(mask_sizeof()); mask_t *access_mask = alloca(mask_sizeof());
mask_t *saccess_mask = alloca(mask_sizeof());
mask_load(access_mask, SND_PCM_ACCBIT_PLUGIN); 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, err = _snd_pcm_hw_param_mask(params, SND_PCM_HW_PARAM_ACCESS,
access_mask); access_mask);
if (err < 0) 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) { if (mulaw->sformat == SND_PCM_FORMAT_MU_LAW) {
mask_t *format_mask = alloca(mask_sizeof()); mask_t *format_mask = alloca(mask_sizeof());
mask_load(format_mask, SND_PCM_FMTBIT_LINEAR); mask_load(format_mask, SND_PCM_FMTBIT_LINEAR);
err = _snd_pcm_hw_param_mask(params, err = _snd_pcm_hw_param_mask(params, SND_PCM_HW_PARAM_FORMAT,
SND_PCM_HW_PARAM_FORMAT,
format_mask); format_mask);
if (err < 0)
return err;
} else { } else {
err = _snd_pcm_hw_param_set(params, err = _snd_pcm_hw_param_set(params,
SND_PCM_HW_PARAM_FORMAT, SND_PCM_HW_PARAM_FORMAT,
SND_PCM_FORMAT_MU_LAW, 0); SND_PCM_FORMAT_MU_LAW, 0);
if (err < 0)
return err;
} }
err = _snd_pcm_hw_param_set(params, SND_PCM_HW_PARAM_SUBFORMAT, 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;
_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);
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;
if (err < 0) if (err < 0)
return err; return err;
params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID); params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
return 0; return 0;
} }
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_SUBFORMAT_STD, 0);
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;
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) 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_mulaw_t *mulaw = pcm->private;
snd_pcm_t *slave = mulaw->plug.slave; int err = snd_pcm_hw_params_slave(pcm, params,
int err; snd_pcm_mulaw_hw_refine_cchange,
unsigned int links; snd_pcm_mulaw_hw_refine_sprepare,
snd_pcm_hw_params_t sparams; snd_pcm_mulaw_hw_refine_schange,
mask_t *saccess_mask = alloca(mask_sizeof()); snd_pcm_plugin_hw_params_slave);
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);
if (err < 0) if (err < 0)
return err; return err;
params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
if (pcm->stream == SND_PCM_STREAM_PLAYBACK) { if (pcm->stream == SND_PCM_STREAM_PLAYBACK) {
if (mulaw->sformat == SND_PCM_FORMAT_MU_LAW) { 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); mulaw->getput_idx = get_index(snd_pcm_hw_param_value(params, SND_PCM_HW_PARAM_FORMAT, 0), SND_PCM_FORMAT_S16);

View file

@ -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) 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) 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; 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; snd_pcm_multi_t *multi = pcm->private;
unsigned int k; mask_t *access_mask = alloca(mask_sizeof());
snd_pcm_hw_params_t sparams; int err;
int changed = 0; mask_any(access_mask);
int err = 0; mask_reset(access_mask, SND_PCM_ACCESS_MMAP_INTERLEAVED);
unsigned int cmask, lcmask; err = _snd_pcm_hw_param_mask(params, SND_PCM_HW_PARAM_ACCESS,
const mask_t *access_mask = snd_pcm_hw_param_value_mask(params, SND_PCM_HW_PARAM_ACCESS); access_mask);
mask_t *saccess_mask = alloca(mask_sizeof()); if (err < 0)
if (mask_test(access_mask, SND_PCM_ACCESS_RW_INTERLEAVED) || return err;
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;
err = _snd_pcm_hw_param_set(params, SND_PCM_HW_PARAM_CHANNELS, err = _snd_pcm_hw_param_set(params, SND_PCM_HW_PARAM_CHANNELS,
multi->channels_count, 0); multi->channels_count, 0);
if (err < 0) if (err < 0)
return err; return err;
lcmask = params->cmask; params->info = ~0;
cmask |= params->cmask; 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; static int snd_pcm_multi_hw_refine_cchange(snd_pcm_t *pcm ATTRIBUTE_UNUSED,
do { int slave_idx ATTRIBUTE_UNUSED,
for (k = 0; k < multi->slaves_count; ++k) { snd_pcm_hw_params_t *params,
snd_pcm_t *slave = multi->slaves[k].pcm; snd_pcm_hw_params_t *sparams)
params->cmask = cmask; {
_snd_pcm_hw_params_any(&sparams); int err;
_snd_pcm_hw_param_mask(&sparams, unsigned int links = (SND_PCM_HW_PARBIT_FORMAT |
SND_PCM_HW_PARAM_ACCESS, SND_PCM_HW_PARBIT_SUBFORMAT |
saccess_mask); SND_PCM_HW_PARBIT_RATE |
_snd_pcm_hw_param_set(&sparams, SND_PCM_HW_PARBIT_PERIOD_SIZE |
SND_PCM_HW_PARAM_CHANNELS, SND_PCM_HW_PARBIT_PERIOD_TIME |
multi->slaves[k].channels_count, 0); SND_PCM_HW_PARBIT_PERIODS |
err = snd_pcm_hw_refine2(params, &sparams, SND_PCM_HW_PARBIT_BUFFER_SIZE |
snd_pcm_generic_hw_link, slave, SND_PCM_HW_PARBIT_BUFFER_TIME |
SND_PCM_HW_PARBIT_FORMAT | SND_PCM_HW_PARBIT_TICK_TIME);
SND_PCM_HW_PARBIT_SUBFORMAT | mask_t *access_mask = alloca(mask_sizeof());
SND_PCM_HW_PARBIT_RATE | const mask_t *saccess_mask = snd_pcm_hw_param_value_mask(sparams, SND_PCM_HW_PARAM_ACCESS);
SND_PCM_HW_PARBIT_PERIOD_SIZE | mask_any(access_mask);
SND_PCM_HW_PARBIT_PERIOD_TIME | mask_reset(access_mask, SND_PCM_ACCESS_MMAP_INTERLEAVED);
SND_PCM_HW_PARBIT_BUFFER_SIZE | if (!mask_test(saccess_mask, SND_PCM_ACCESS_MMAP_NONINTERLEAVED))
SND_PCM_HW_PARBIT_BUFFER_TIME | mask_reset(access_mask, SND_PCM_ACCESS_MMAP_NONINTERLEAVED);
SND_PCM_HW_PARBIT_PERIODS | if (!mask_test(saccess_mask, SND_PCM_ACCESS_MMAP_COMPLEX) &&
SND_PCM_HW_PARBIT_TICK_TIME); !mask_test(saccess_mask, SND_PCM_ACCESS_MMAP_INTERLEAVED))
if (params->cmask) { mask_reset(access_mask, SND_PCM_ACCESS_MMAP_COMPLEX);
changed++; err = _snd_pcm_hw_param_mask(params, SND_PCM_HW_PARAM_ACCESS,
lcmask |= params->cmask; access_mask);
cmask |= params->cmask; if (err < 0)
} return err;
if (err < 0) err = _snd_pcm_hw_params_refine(params, links, sparams);
goto _end; if (err < 0)
return err;
params->info &= sparams->info;
return 0;
}
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;
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;
} }
} while (changed && multi->slaves_count > 1); }
_end: /* FIXME: loop begin? */
params->cmask = lcmask; for (k = 0; k < multi->slaves_count; ++k) {
return err; 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_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;
}
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_params(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
{ {
snd_pcm_multi_t *multi = pcm->private; snd_pcm_multi_t *multi = pcm->private;
unsigned int k; unsigned int k;
snd_pcm_hw_params_t sparams[multi->slaves_count];
int err; 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);
}
}
for (k = 0; k < multi->slaves_count; ++k) { for (k = 0; k < multi->slaves_count; ++k) {
snd_pcm_t *slave = multi->slaves[k].pcm; err = snd_pcm_multi_hw_refine_sprepare(pcm, k, &sparams[k]);
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); assert(err >= 0);
err = snd_pcm_hw_params(slave, &sparams); err = snd_pcm_multi_hw_refine_schange(pcm, k, params, &sparams[k]);
params->cmask = 0; assert(err >= 0);
sparams.cmask = ~0U; err = snd_pcm_multi_hw_params_slave(pcm, k, &sparams[k]);
snd_pcm_hw_params_refine(params, links, &sparams); if (err < 0) {
if (err < 0) snd_pcm_multi_hw_refine_cchange(pcm, k, params, &sparams[k]);
return err; 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;
} }
} }
return 0; return 0;

View file

@ -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) 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; params->fifo_size = 0;
return err; return err;
} }

View file

@ -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)) { if (hw_is_mask(var)) {
mask_any(hw_param_mask(params, var)); mask_any(hw_param_mask(params, var));
params->cmask |= 1 << var; params->cmask |= 1 << var;
params->rmask |= 1 << var;
return; return;
} }
if (hw_is_interval(var)) { if (hw_is_interval(var)) {
interval_any(hw_param_interval(params, var)); interval_any(hw_param_interval(params, var));
params->cmask |= 1 << var; params->cmask |= 1 << var;
params->rmask |= 1 << var;
return; return;
} }
assert(0); assert(0);
@ -241,8 +243,10 @@ int _snd_pcm_hw_param_refine_interval(snd_pcm_hw_params_t *params,
int changed; int changed;
assert(hw_is_interval(var)); assert(hw_is_interval(var));
changed = interval_refine(hw_param_interval(params, var), val); changed = interval_refine(hw_param_interval(params, var), val);
if (changed) if (changed) {
params->cmask |= 1 << var; params->cmask |= 1 << var;
params->rmask |= 1 << var;
}
return changed; return changed;
} }
@ -252,8 +256,10 @@ int _snd_pcm_hw_param_setinteger(snd_pcm_hw_params_t *params,
int changed; int changed;
assert(hw_is_interval(var)); assert(hw_is_interval(var));
changed = interval_setinteger(hw_param_interval(params, var)); changed = interval_setinteger(hw_param_interval(params, var));
if (changed) if (changed) {
params->cmask |= 1 << var; params->cmask |= 1 << var;
params->rmask |= 1 << var;
}
return changed; 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); int changed = _snd_pcm_hw_param_setinteger(params, var);
if (changed < 0) if (changed < 0)
return changed; return changed;
if (changed) { if (params->rmask) {
int err = snd_pcm_hw_refine(pcm, params); int err = snd_pcm_hw_refine(pcm, params);
if (err < 0) if (err < 0)
return err; return err;
@ -288,8 +294,10 @@ int _snd_pcm_hw_param_first(snd_pcm_hw_params_t *params,
assert(0); assert(0);
return -EINVAL; return -EINVAL;
} }
if (changed) if (changed) {
params->cmask |= 1 << var; params->cmask |= 1 << var;
params->rmask |= 1 << var;
}
return changed; 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); int changed = _snd_pcm_hw_param_first(params, var);
if (changed < 0) if (changed < 0)
return changed; return changed;
if (changed) { if (params->rmask) {
int err = snd_pcm_hw_refine(pcm, params); int err = snd_pcm_hw_refine(pcm, params);
assert(err >= 0); assert(err >= 0);
} }
@ -324,8 +332,10 @@ int _snd_pcm_hw_param_last(snd_pcm_hw_params_t *params,
assert(0); assert(0);
return -EINVAL; return -EINVAL;
} }
if (changed) if (changed) {
params->cmask |= 1 << var; params->cmask |= 1 << var;
params->rmask |= 1 << var;
}
return changed; 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); int changed = _snd_pcm_hw_param_last(params, var);
if (changed < 0) if (changed < 0)
return changed; return changed;
if (changed) { if (params->rmask) {
int err = snd_pcm_hw_refine(pcm, params); int err = snd_pcm_hw_refine(pcm, params);
assert(err >= 0); assert(err >= 0);
} }
@ -371,8 +381,10 @@ int _snd_pcm_hw_param_min(snd_pcm_hw_params_t *params,
assert(0); assert(0);
return -EINVAL; return -EINVAL;
} }
if (changed) if (changed) {
params->cmask |= 1 << var; params->cmask |= 1 << var;
params->rmask |= 1 << var;
}
return changed; 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); int changed = _snd_pcm_hw_param_min(params, var, val, dir ? *dir : 0);
if (changed < 0) if (changed < 0)
return changed; return changed;
if (changed) { if (params->rmask) {
int err = snd_pcm_hw_refine(pcm, params); int err = snd_pcm_hw_refine(pcm, params);
if (err < 0) if (err < 0)
return err; return err;
@ -432,8 +444,10 @@ int _snd_pcm_hw_param_max(snd_pcm_hw_params_t *params,
assert(0); assert(0);
return -EINVAL; return -EINVAL;
} }
if (changed) if (changed) {
params->cmask |= 1 << var; params->cmask |= 1 << var;
params->rmask |= 1 << var;
}
return changed; 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); int changed = _snd_pcm_hw_param_max(params, var, val, dir ? *dir : 0);
if (changed < 0) if (changed < 0)
return changed; return changed;
if (changed) { if (params->rmask) {
int err = snd_pcm_hw_refine(pcm, params); int err = snd_pcm_hw_refine(pcm, params);
if (err < 0) if (err < 0)
return err; return err;
@ -527,8 +541,10 @@ int _snd_pcm_hw_param_minmax(snd_pcm_hw_params_t *params,
assert(0); assert(0);
return -EINVAL; return -EINVAL;
} }
if (changed) if (changed) {
params->cmask |= 1 << var; params->cmask |= 1 << var;
params->rmask |= 1 << var;
}
return changed; 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); *max, maxdir ? *maxdir : 0);
if (changed < 0) if (changed < 0)
return changed; return changed;
if (changed) { if (params->rmask) {
int err = snd_pcm_hw_refine(pcm, params); int err = snd_pcm_hw_refine(pcm, params);
if (err < 0) if (err < 0)
return err; return err;
@ -614,8 +630,10 @@ int _snd_pcm_hw_param_set(snd_pcm_hw_params_t *params,
assert(0); assert(0);
return -EINVAL; return -EINVAL;
} }
if (changed) if (changed) {
params->cmask |= 1 << var; params->cmask |= 1 << var;
params->rmask |= 1 << var;
}
return changed; 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); int changed = _snd_pcm_hw_param_set(params, var, val, dir);
if (changed < 0) if (changed < 0)
return changed; return changed;
if (changed) { if (params->rmask) {
int err = snd_pcm_hw_refine(pcm, params); int err = snd_pcm_hw_refine(pcm, params);
if (err < 0) if (err < 0)
return err; return err;
@ -655,8 +673,10 @@ int _snd_pcm_hw_param_mask(snd_pcm_hw_params_t *params,
int changed; int changed;
assert(hw_is_mask(var)); assert(hw_is_mask(var));
changed = mask_refine(hw_param_mask(params, var), val); changed = mask_refine(hw_param_mask(params, var), val);
if (changed) if (changed) {
params->cmask |= 1 << var; params->cmask |= 1 << var;
params->rmask |= 1 << var;
}
return changed; 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); int changed = _snd_pcm_hw_param_mask(params, var, val);
if (changed < 0) if (changed < 0)
return changed; return changed;
if (changed) { if (params->rmask) {
int err = snd_pcm_hw_refine(pcm, params); int err = snd_pcm_hw_refine(pcm, params);
if (err < 0) if (err < 0)
return err; return err;
@ -706,7 +726,6 @@ int snd_pcm_hw_param_near(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
int v; int v;
unsigned int saved_min; unsigned int saved_min;
int last = 0; int last = 0;
unsigned int cmask;
int min, max; int min, max;
int mindir, maxdir; int mindir, maxdir;
int valdir = dir ? *dir : 0; 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; last = 1;
} }
_end: _end:
cmask = params->cmask;
if (last) if (last)
v = snd_pcm_hw_param_last(pcm, params, var, dir); v = snd_pcm_hw_param_last(pcm, params, var, dir);
else else
v = snd_pcm_hw_param_first(pcm, params, var, dir); v = snd_pcm_hw_param_first(pcm, params, var, dir);
params->cmask |= cmask;
assert(v >= 0); assert(v >= 0);
return v; 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; snd_pcm_hw_params_t save;
int v; int v;
int last = 0; int last = 0;
unsigned int cmask;
int min, max; int min, max;
int mindir, maxdir; int mindir, maxdir;
int diff, diffdir; 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; last = 1;
} }
_end: _end:
cmask = params->cmask;
if (last) if (last)
v = snd_pcm_hw_param_last(pcm, params, var, dir); v = snd_pcm_hw_param_last(pcm, params, var, dir);
else else
v = snd_pcm_hw_param_first(pcm, params, var, dir); v = snd_pcm_hw_param_first(pcm, params, var, dir);
params->cmask |= cmask;
assert(v >= 0); assert(v >= 0);
return v; return v;
} }
@ -857,10 +871,10 @@ void snd_pcm_hw_param_near_minmax(snd_pcm_t *pcm,
assert(err >= 0); assert(err >= 0);
} }
void snd_pcm_hw_param_near_copy(snd_pcm_t *pcm, void snd_pcm_hw_param_refine_near(snd_pcm_t *pcm,
snd_pcm_hw_params_t *params, snd_pcm_hw_params_t *params,
snd_pcm_hw_param_t var, snd_pcm_hw_param_t var,
const snd_pcm_hw_params_t *src) const snd_pcm_hw_params_t *src)
{ {
unsigned int min, max; unsigned int min, max;
int mindir, maxdir; 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) void snd_pcm_hw_params_choose(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
{ {
int err; int err;
unsigned int cmask = params->cmask;
err = snd_pcm_hw_param_first(pcm, params, SND_PCM_HW_PARAM_ACCESS, 0); err = snd_pcm_hw_param_first(pcm, params, SND_PCM_HW_PARAM_ACCESS, 0);
assert(err >= 0); assert(err >= 0);
cmask |= params->cmask;
err = snd_pcm_hw_param_first(pcm, params, SND_PCM_HW_PARAM_FORMAT, 0); err = snd_pcm_hw_param_first(pcm, params, SND_PCM_HW_PARAM_FORMAT, 0);
assert(err >= 0); assert(err >= 0);
cmask |= params->cmask;
err = snd_pcm_hw_param_first(pcm, params, SND_PCM_HW_PARAM_SUBFORMAT, 0); err = snd_pcm_hw_param_first(pcm, params, SND_PCM_HW_PARAM_SUBFORMAT, 0);
assert(err >= 0); assert(err >= 0);
cmask |= params->cmask;
err = snd_pcm_hw_param_first(pcm, params, SND_PCM_HW_PARAM_CHANNELS, 0); err = snd_pcm_hw_param_first(pcm, params, SND_PCM_HW_PARAM_CHANNELS, 0);
assert(err >= 0); assert(err >= 0);
cmask |= params->cmask;
err = snd_pcm_hw_param_first(pcm, params, SND_PCM_HW_PARAM_RATE, 0); err = snd_pcm_hw_param_first(pcm, params, SND_PCM_HW_PARAM_RATE, 0);
assert(err >= 0); assert(err >= 0);
cmask |= params->cmask;
err = snd_pcm_hw_param_first(pcm, params, SND_PCM_HW_PARAM_PERIOD_TIME, 0); err = snd_pcm_hw_param_first(pcm, params, SND_PCM_HW_PARAM_PERIOD_TIME, 0);
assert(err >= 0); assert(err >= 0);
cmask |= params->cmask;
err = snd_pcm_hw_param_last(pcm, params, SND_PCM_HW_PARAM_BUFFER_SIZE, 0); err = snd_pcm_hw_param_last(pcm, params, SND_PCM_HW_PARAM_BUFFER_SIZE, 0);
assert(err >= 0); assert(err >= 0);
cmask |= params->cmask;
err = snd_pcm_hw_param_first(pcm, params, SND_PCM_HW_PARAM_TICK_TIME, 0); err = snd_pcm_hw_param_first(pcm, params, SND_PCM_HW_PARAM_TICK_TIME, 0);
assert(err >= 0); assert(err >= 0);
cmask |= params->cmask;
params->cmask = cmask;
} }
/* Strategies */ /* Strategies */
@ -1080,9 +1083,9 @@ unsigned int snd_pcm_hw_param_count(const snd_pcm_hw_params_t *params,
return 0; return 0;
} }
int snd_pcm_hw_param_refine(snd_pcm_hw_params_t *params, int _snd_pcm_hw_param_refine(snd_pcm_hw_params_t *params,
snd_pcm_hw_param_t var, snd_pcm_hw_param_t var,
const snd_pcm_hw_params_t *src) const snd_pcm_hw_params_t *src)
{ {
int changed = 0; int changed = 0;
if (hw_is_mask(var)) { 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); changed = interval_refine(d, s);
} else } else
assert(0); assert(0);
if (changed) if (changed) {
params->cmask |= 1 << var; params->cmask |= 1 << var;
params->rmask |= 1 << var;
}
return changed; 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) const snd_pcm_hw_params_t *src)
{ {
if (hw_is_mask(var)) { if (hw_is_mask(var)) {
mask_t *d = hw_param_mask(params, var); mask_t *d = hw_param_mask(params, var);
const mask_t *s = hw_param_mask_c(src, var); const mask_t *s = hw_param_mask_c(src, var);
mask_copy(d, s); mask_copy(d, s);
params->cmask |= 1 << var;
params->rmask |= 1 << var;
} }
if (hw_is_interval(var)) { if (hw_is_interval(var)) {
interval_t *d = hw_param_interval(params, var); interval_t *d = hw_param_interval(params, var);
const interval_t *s = hw_param_interval_c(src, var); const interval_t *s = hw_param_interval_c(src, var);
interval_copy(d, s); interval_copy(d, s);
params->cmask |= 1 << var;
params->rmask |= 1 << var;
} }
assert(0); assert(0);
} }
@ -1138,8 +1147,11 @@ void snd_pcm_hw_param_dump(const snd_pcm_hw_params_t *params,
assert(f); assert(f);
for (k = 0; k <= MASK_MAX; ++k) { for (k = 0; k <= MASK_MAX; ++k) {
if (mask_test(mask, k)) { if (mask_test(mask, k)) {
snd_output_putc(out, ' '); const char *s = f(k);
snd_output_puts(out, 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; best_badness = UINT_MAX;
value = -1; value = -1;
while (1) { while (1) {
unsigned int cmask;
params1 = *params; params1 = *params;
value = strategy->next_value(&params1, var, value, &dir, pcm, strategy); value = strategy->next_value(&params1, var, value, &dir, pcm, strategy);
if (value < 0) if (value < 0)
break; break;
cmask = params1.cmask;
badness = snd_pcm_hw_params_strategy(pcm, &params1, strategy, badness_min, badness_max); badness = snd_pcm_hw_params_strategy(pcm, &params1, strategy, badness_min, badness_max);
params1.cmask |= cmask;
if (badness >= 0) { if (badness >= 0) {
if ((unsigned int) badness <= badness_min) { if ((unsigned int) badness <= badness_min) {
*params = params1; *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++) { for (var = 0; var <= SND_PCM_HW_PARAM_LAST; var++) {
int err; int err;
i = *success; 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); err = snd_pcm_hw_refine(pcm, &i);
if (err == 0 && if (err == 0 &&
snd_pcm_hw_params_try_explain_failure1(pcm, fail, &i, depth - 1, out) < 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_soft(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params)
int _snd_pcm_hw_refine(snd_pcm_hw_params_t *params)
{ {
unsigned int k; unsigned int k;
interval_t *i; interval_t *i;
unsigned int rstamps[RULES]; unsigned int rstamps[RULES];
unsigned int vstamps[SND_PCM_HW_PARAM_LAST + 1]; unsigned int vstamps[SND_PCM_HW_PARAM_LAST + 1];
unsigned int stamp = 2; 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++) { 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; 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]); &refine_masks[k - SND_PCM_HW_PARAM_FIRST_MASK]);
if (err < 0) if (changed)
return err; 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++) { 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; 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]); &refine_intervals[k - SND_PCM_HW_PARAM_FIRST_INTERVAL]);
if (err < 0) if (changed)
return err; params->cmask |= 1 << k;
if (changed < 0)
goto _err;
} }
for (k = 0; k < RULES; k++) for (k = 0; k < RULES; k++)
rstamps[k] = 0; rstamps[k] = 0;
for (k = 0; k <= SND_PCM_HW_PARAM_LAST; k++) for (k = 0; k <= SND_PCM_HW_PARAM_LAST; k++)
vstamps[k] = (params->cmask & (1 << k)) ? 1 : 0; vstamps[k] = (params->rmask & (1 << k)) ? 1 : 0;
params->cmask = 0; do {
changed = 1; again = 0;
while (changed) {
changed = 0;
for (k = 0; k < RULES; k++) { for (k = 0; k < RULES; k++) {
snd_pcm_hw_rule_t *r = &refine_rules[k]; snd_pcm_hw_rule_t *r = &refine_rules[k];
unsigned int d; unsigned int d;
int doit = 0; int doit = 0;
#ifdef RULES_DEBUG
interval_t *i;
#endif
for (d = 0; r->deps[d] >= 0; d++) { for (d = 0; r->deps[d] >= 0; d++) {
if (vstamps[r->deps[d]] > rstamps[k]) { if (vstamps[r->deps[d]] > rstamps[k]) {
doit = 1; doit = 1;
@ -1889,26 +1901,35 @@ int _snd_pcm_hw_refine(snd_pcm_hw_params_t *params)
if (!doit) if (!doit)
continue; continue;
#ifdef RULES_DEBUG #ifdef RULES_DEBUG
i = hw_param_interval(params, r->var); snd_output_printf(log, "Rule %d: ", k);
fprintf(stderr, "Rule %d: %u ", k, r->var); if (r->var >= 0) {
interval_print(i, stderr); 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 #endif
err = r->func(params, r); changed = r->func(params, r);
#ifdef RULES_DEBUG #ifdef RULES_DEBUG
interval_print(i, stderr); if (r->var >= 0)
putc('\n', stderr); 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 #endif
rstamps[k] = stamp; rstamps[k] = stamp;
if (err && r->var >= 0) { if (changed && r->var >= 0) {
params->cmask |= 1 << r->var; params->cmask |= 1 << r->var;
vstamps[r->var] = stamp; vstamps[r->var] = stamp;
changed = 1; again = 1;
} }
if (err < 0) if (changed < 0)
return err; goto _err;
stamp++; stamp++;
} }
} } while (again);
if (!params->msbits) { if (!params->msbits) {
i = hw_param_interval(params, SND_PCM_HW_PARAM_SAMPLE_BITS); i = hw_param_interval(params, SND_PCM_HW_PARAM_SAMPLE_BITS);
if (interval_single(i)) if (interval_single(i))
@ -1922,69 +1943,97 @@ int _snd_pcm_hw_refine(snd_pcm_hw_params_t *params)
params->rate_den = 1; params->rate_den = 1;
} }
} }
params->rmask = 0;
return 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, int _snd_pcm_hw_params_refine(snd_pcm_hw_params_t *params,
unsigned int vars, unsigned int vars,
const snd_pcm_hw_params_t *src) const snd_pcm_hw_params_t *src)
{ {
int changed, err = 0; int changed, err = 0;
unsigned int k; unsigned int k;
for (k = 0; k <= SND_PCM_HW_PARAM_LAST; ++k) { for (k = 0; k <= SND_PCM_HW_PARAM_LAST; ++k) {
if (!(vars & (1 << k)) || if (!(vars & (1 << k)))
!((src->cmask & (1 << k))))
continue; continue;
changed = snd_pcm_hw_param_refine(params, k, src); changed = _snd_pcm_hw_param_refine(params, k, src);
if (changed < 0) if (changed < 0)
err = changed; err = changed;
} }
return err; return err;
} }
/* Accumulate to params->cmask */ int snd_pcm_hw_refine_slave(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
/* Reset sparams->cmask */ int (*cprepare)(snd_pcm_t *pcm,
int snd_pcm_generic_hw_link(snd_pcm_hw_params_t *params, snd_pcm_hw_params_t *params),
snd_pcm_hw_params_t *sparams, int (*cchange)(snd_pcm_t *pcm,
snd_pcm_t *slave, snd_pcm_hw_params_t *params,
unsigned long links) 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; snd_pcm_hw_params_t sparams;
err = snd_pcm_hw_params_refine(sparams, links, params); int err;
if (err >= 0) { err = cprepare(pcm, params);
unsigned int cmask = sparams->cmask; if (err < 0)
err = snd_pcm_hw_refine(slave, sparams); return err;
sparams->cmask |= cmask; err = sprepare(pcm, &sparams);
if (err < 0) {
ERR("Slave PCM not useable");
return err;
} }
err1 = snd_pcm_hw_params_refine(params, links, sparams); /* FIXME: loop begin? */
if (err1 < 0) err = schange(pcm, params, &sparams);
err = err1; if (err >= 0) {
sparams->cmask = 0; err = srefine(pcm, &sparams);
return err; }
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, int snd_pcm_hw_params_slave(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
snd_pcm_hw_params_t *sparams, int (*cchange)(snd_pcm_t *pcm,
int (*func)(snd_pcm_hw_params_t *params, snd_pcm_hw_params_t *params,
snd_pcm_hw_params_t *sparams, snd_pcm_hw_params_t *sparams),
snd_pcm_t *slave, int (*sprepare)(snd_pcm_t *pcm,
unsigned long private), snd_pcm_hw_params_t *params),
snd_pcm_t *slave, int (*schange)(snd_pcm_t *pcm,
unsigned long private) snd_pcm_hw_params_t *params,
snd_pcm_hw_params_t *sparams),
int (*sparams)(snd_pcm_t *pcm,
snd_pcm_hw_params_t *sparams))
{ {
int err = 0; snd_pcm_hw_params_t slave_params;
unsigned int cmask = 0; int err;
while (params->cmask) { err = sprepare(pcm, &slave_params);
err = func(params, sparams, slave, private); assert(err >= 0);
cmask |= params->cmask; err = schange(pcm, params, &slave_params);
if (err < 0) assert(err >= 0);
break; err = sparams(pcm, &slave_params);
err = _snd_pcm_hw_refine(params); if (err < 0)
cmask |= params->cmask; cchange(pcm, params, &slave_params);
if (err < 0)
break;
}
params->cmask = cmask;
return err; return err;
} }

View file

@ -192,182 +192,6 @@ static int snd_pcm_plug_slave_format(int format, const mask_t *format_mask)
(1 << SND_PCM_FORMAT_IMA_ADPCM)) (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) static void snd_pcm_plug_clear(snd_pcm_t *pcm)
{ {
snd_pcm_plug_t *plug = pcm->private; snd_pcm_plug_t *plug = pcm->private;
@ -580,13 +404,164 @@ static int snd_pcm_plug_insert_plugins(snd_pcm_t *pcm,
return 0; 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) 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_plug_t *plug = pcm->private;
snd_pcm_t *slave = plug->req_slave; snd_pcm_t *slave = plug->req_slave;
snd_pcm_plug_params_t clt_params, slv_params; snd_pcm_plug_params_t clt_params, slv_params;
snd_pcm_hw_params_t sparams; 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); assert(err >= 0);
clt_params.access = snd_pcm_hw_param_value(params, SND_PCM_HW_PARAM_ACCESS, 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.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); 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.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.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); slv_params.rate = snd_pcm_hw_param_value(&sparams, SND_PCM_HW_PARAM_RATE, 0);
snd_pcm_plug_clear(pcm); snd_pcm_plug_clear(pcm);
if (clt_params.format == slv_params.format && err = snd_pcm_plug_insert_plugins(pcm, &clt_params, &slv_params);
clt_params.channels == slv_params.channels && if (err < 0)
clt_params.rate == slv_params.rate && return err;
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_hw_params(plug->slave, params); err = snd_pcm_hw_params(plug->slave, params);
if (err < 0) { if (err < 0) {
snd_pcm_plug_clear(pcm); snd_pcm_plug_clear(pcm);

View file

@ -340,6 +340,18 @@ int snd_pcm_plugin_poll_descriptor(snd_pcm_t *pcm)
return snd_pcm_poll_descriptor(plugin->slave); 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 conv_index(int src_format, int dst_format)
{ {
int src_endian, dst_endian, sign, src_width, dst_width; int src_endian, dst_endian, sign, src_width, dst_width;

View file

@ -64,6 +64,8 @@ int snd_pcm_plugin_poll_descriptor(snd_pcm_t *pcm);
int get_index(int src_format, int dst_format); int get_index(int src_format, int dst_format);
int put_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 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 \ #define SND_PCM_FMTBIT_LINEAR \
((1 << SND_PCM_FORMAT_S8 ) | (1 << SND_PCM_FORMAT_U8) | \ ((1 << SND_PCM_FORMAT_S8 ) | (1 << SND_PCM_FORMAT_U8) | \

View file

@ -23,6 +23,7 @@
#include <byteswap.h> #include <byteswap.h>
#include "pcm_local.h" #include "pcm_local.h"
#include "pcm_plugin.h" #include "pcm_plugin.h"
#include "interval.h"
#define DIV (1<<16) #define DIV (1<<16)
@ -233,30 +234,23 @@ static int snd_pcm_rate_close(snd_pcm_t *pcm)
return 0; 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; 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 *access_mask = alloca(mask_sizeof());
mask_t *format_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(access_mask, SND_PCM_ACCBIT_PLUGIN);
mask_load(format_mask, SND_PCM_FMTBIT_LINEAR); 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, err = _snd_pcm_hw_param_mask(params, SND_PCM_HW_PARAM_ACCESS,
access_mask); access_mask);
if (err < 0) if (err < 0)
return err; return err;
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); 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) if (err < 0)
return err; return err;
err = _snd_pcm_hw_param_min(params, 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); SND_PCM_HW_PARAM_RATE, RATE_MAX, 0);
if (err < 0) if (err < 0)
return err; return err;
lcmask = params->cmask; params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
params->cmask |= cmask; return 0;
}
_snd_pcm_hw_params_any(&sparams); static int snd_pcm_rate_hw_refine_sprepare(snd_pcm_t *pcm, snd_pcm_hw_params_t *sparams)
_snd_pcm_hw_param_mask(&sparams, SND_PCM_HW_PARAM_ACCESS, {
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); saccess_mask);
snd_pcm_hw_param_near_copy(slave, &sparams,
SND_PCM_HW_PARAM_BUFFER_TIME,
params);
if (rate->sformat >= 0) { 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); 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); 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 | links |= (SND_PCM_HW_PARBIT_FORMAT |
SND_PCM_HW_PARBIT_SUBFORMAT | SND_PCM_HW_PARBIT_SUBFORMAT |
SND_PCM_HW_PARBIT_SAMPLE_BITS | SND_PCM_HW_PARBIT_SAMPLE_BITS |
SND_PCM_HW_PARBIT_FRAME_BITS); SND_PCM_HW_PARBIT_FRAME_BITS);
_snd_pcm_hw_param_set(&sparams, SND_PCM_HW_PARAM_RATE, buffer_size = snd_pcm_hw_param_value_interval(params, SND_PCM_HW_PARAM_BUFFER_SIZE);
rate->srate, 0); 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);
err = snd_pcm_hw_refine2(params, &sparams, interval_muldiv(buffer_size, srate, crate, &t);
snd_pcm_generic_hw_link, slave, links); interval_round(&t);
params->cmask |= lcmask; 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) if (err < 0)
return err; return err;
params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
return 0; return 0;
} }
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;
interval_t t;
const interval_t *sbuffer_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);
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;
}
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);
}
static int snd_pcm_rate_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params) 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_rate_t *rate = pcm->private;
snd_pcm_t *slave = rate->plug.slave; snd_pcm_t *slave = rate->plug.slave;
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_format, dst_format;
unsigned int src_rate, dst_rate; unsigned int src_rate, dst_rate;
mask_t *saccess_mask = alloca(mask_sizeof()); int err = snd_pcm_hw_params_slave(pcm, params,
mask_load(saccess_mask, SND_PCM_ACCBIT_MMAP); snd_pcm_rate_hw_refine_cchange,
snd_pcm_rate_hw_refine_sprepare,
_snd_pcm_hw_params_any(&sparams); snd_pcm_rate_hw_refine_schange,
_snd_pcm_hw_param_mask(&sparams, SND_PCM_HW_PARAM_ACCESS, snd_pcm_plugin_hw_params_slave);
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
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);
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);
if (err < 0) if (err < 0)
return err; return err;
params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
if (pcm->stream == SND_PCM_STREAM_PLAYBACK) { if (pcm->stream == SND_PCM_STREAM_PLAYBACK) {
src_format = snd_pcm_hw_param_value(params, SND_PCM_HW_PARAM_FORMAT, 0); src_format = snd_pcm_hw_param_value(params, SND_PCM_HW_PARAM_FORMAT, 0);
dst_format = slave->format; dst_format = slave->format;

View file

@ -425,80 +425,58 @@ static int snd_pcm_route_close(snd_pcm_t *pcm)
return 0; 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; 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 *access_mask = alloca(mask_sizeof());
mask_t *format_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(access_mask, SND_PCM_ACCBIT_PLUGIN);
mask_load(format_mask, SND_PCM_FMTBIT_LINEAR); 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, err = _snd_pcm_hw_param_mask(params, SND_PCM_HW_PARAM_ACCESS,
access_mask); access_mask);
if (err < 0) if (err < 0)
return err; return err;
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); 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) if (err < 0)
return err; return err;
err = _snd_pcm_hw_param_min(params, SND_PCM_HW_PARAM_CHANNELS, 1, 0); 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;
_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
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 {
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;
if (err < 0) if (err < 0)
return err; return err;
params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID); params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
return 0; 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_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,
route->sformat, 0);
_snd_pcm_hw_param_set(sparams, SND_PCM_HW_PARAM_SUBFORMAT,
SND_PCM_SUBFORMAT_STD, 0);
}
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; snd_pcm_route_t *route = pcm->private;
snd_pcm_t *slave = route->plug.slave;
int err; int err;
snd_pcm_hw_params_t sparams;
unsigned int links = (SND_PCM_HW_PARBIT_RATE | unsigned int links = (SND_PCM_HW_PARBIT_RATE |
SND_PCM_HW_PARBIT_PERIODS | SND_PCM_HW_PARBIT_PERIODS |
SND_PCM_HW_PARBIT_PERIOD_SIZE | SND_PCM_HW_PARBIT_PERIOD_SIZE |
@ -506,42 +484,65 @@ 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_SIZE |
SND_PCM_HW_PARBIT_BUFFER_TIME | SND_PCM_HW_PARBIT_BUFFER_TIME |
SND_PCM_HW_PARBIT_TICK_TIME); SND_PCM_HW_PARBIT_TICK_TIME);
unsigned int src_format, dst_format; if (route->sformat < 0)
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
links |= (SND_PCM_HW_PARBIT_FORMAT | links |= (SND_PCM_HW_PARBIT_FORMAT |
SND_PCM_HW_PARBIT_SUBFORMAT | SND_PCM_HW_PARBIT_SUBFORMAT |
SND_PCM_HW_PARBIT_SAMPLE_BITS); SND_PCM_HW_PARBIT_SAMPLE_BITS);
if (route->schannels >= 0) { if (route->schannels < 0)
_snd_pcm_hw_param_set(&sparams, SND_PCM_HW_PARAM_CHANNELS,
route->schannels, 0);
} else {
links |= SND_PCM_HW_PARBIT_CHANNELS; links |= SND_PCM_HW_PARBIT_CHANNELS;
if (route->sformat < 0) err = _snd_pcm_hw_params_refine(sparams, links, params);
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(&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);
if (err < 0) if (err < 0)
return err; return err;
params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID); return 0;
}
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;
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)
links |= SND_PCM_HW_PARBIT_CHANNELS;
err = _snd_pcm_hw_params_refine(params, links, sparams);
if (err < 0)
return err;
return 0;
}
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;
if (pcm->stream == SND_PCM_STREAM_PLAYBACK) { if (pcm->stream == SND_PCM_STREAM_PLAYBACK) {
src_format = snd_pcm_hw_param_value(params, SND_PCM_HW_PARAM_FORMAT, 0); src_format = snd_pcm_hw_param_value(params, SND_PCM_HW_PARAM_FORMAT, 0);
dst_format = slave->format; dst_format = slave->format;

View file

@ -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) 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) 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); 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_t *share = pcm->private;
snd_pcm_share_slave_t *slave = share->slave; 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()); mask_t *access_mask = alloca(mask_sizeof());
const mask_t *mmap_mask; int err;
mask_t *saccess_mask = alloca(mask_sizeof()); mask_any(access_mask);
mask_load(saccess_mask, SND_PCM_ACCBIT_MMAP); mask_reset(access_mask, SND_PCM_ACCESS_MMAP_INTERLEAVED);
err = _snd_pcm_hw_param_mask(params, SND_PCM_HW_PARAM_ACCESS,
cmask = params->cmask; access_mask);
params->cmask = 0; if (err < 0)
return err;
err = _snd_pcm_hw_param_set(params, SND_PCM_HW_PARAM_CHANNELS, err = _snd_pcm_hw_param_set(params, SND_PCM_HW_PARAM_CHANNELS,
share->channels_count, 0); share->channels_count, 0);
if (err < 0) if (err < 0)
return err; return err;
if (slave->format >= 0) { if (slave->format >= 0) {
err = _snd_pcm_hw_param_set(params, SND_PCM_HW_PARAM_FORMAT, err = _snd_pcm_hw_param_set(params, SND_PCM_HW_PARAM_FORMAT,
slave->format, 0); 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) if (err < 0)
return err; 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_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);
if (err < 0)
return err;
mmap_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))
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))
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;
if (err < 0)
return err;
params->info |= SND_PCM_INFO_DOUBLE; params->info |= SND_PCM_INFO_DOUBLE;
return 0; return 0;
} }
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,
slave->channels_count, 0);
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;
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(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;
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) static int snd_pcm_share_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
{ {
snd_pcm_share_t *share = pcm->private; 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); Pthread_mutex_lock(&slave->mutex);
if (slave->setup_count > 1 || if (slave->setup_count > 1 ||
(slave->setup_count == 1 && !pcm->setup)) { (slave->setup_count == 1 && !pcm->setup)) {
params->cmask = 0;
err = _snd_pcm_hw_param_set(params, SND_PCM_HW_PARAM_FORMAT, err = _snd_pcm_hw_param_set(params, SND_PCM_HW_PARAM_FORMAT,
spcm->format, 0); spcm->format, 0);
if (err < 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; goto _end;
} }
} else { } else {
snd_pcm_hw_params_t sparams; err = snd_pcm_hw_params_slave(pcm, params,
unsigned int links; snd_pcm_share_hw_refine_cchange,
mask_t *saccess_mask = alloca(mask_sizeof()); snd_pcm_share_hw_refine_sprepare,
mask_load(saccess_mask, SND_PCM_ACCBIT_MMAP); snd_pcm_share_hw_refine_schange,
links = SND_PCM_HW_PARBIT_FORMAT | snd_pcm_share_hw_params_slave);
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);
if (err < 0) if (err < 0)
goto _end; goto _end;
snd_pcm_sw_params_current(slave->pcm, &slave->sw_params); snd_pcm_sw_params_current(slave->pcm, &slave->sw_params);

View file

@ -155,8 +155,61 @@ static int snd_pcm_shm_info(snd_pcm_t *pcm, snd_pcm_info_t * info)
return err; return err;
} }
static int _snd_pcm_shm_hw_refine(snd_pcm_t *pcm, static int snd_pcm_shm_hw_refine_cprepare(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params ATTRIBUTE_UNUSED)
snd_pcm_hw_params_t *params) {
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; snd_pcm_shm_t *shm = pcm->private;
volatile snd_pcm_shm_ctrl_t *ctrl = shm->ctrl; 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; 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) static int snd_pcm_shm_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
{ {
snd_pcm_hw_params_t sparams; return snd_pcm_hw_refine_slave(pcm, params,
const mask_t *access_mask = snd_pcm_hw_param_value_mask(params, SND_PCM_HW_PARAM_ACCESS); snd_pcm_shm_hw_refine_cprepare,
mask_t *saccess_mask = alloca(mask_sizeof()); snd_pcm_shm_hw_refine_cchange,
mask_load(saccess_mask, SND_PCM_ACCBIT_MMAP); snd_pcm_shm_hw_refine_sprepare,
if (!mask_test(access_mask, SND_PCM_ACCESS_RW_INTERLEAVED) && snd_pcm_shm_hw_refine_schange,
!mask_test(access_mask, SND_PCM_ACCESS_RW_NONINTERLEAVED)) snd_pcm_shm_hw_refine_slave);
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);
} }
static int _snd_pcm_shm_hw_params(snd_pcm_t *pcm, static int snd_pcm_shm_hw_params_slave(snd_pcm_t *pcm,
snd_pcm_hw_params_t *params) snd_pcm_hw_params_t *params)
{ {
snd_pcm_shm_t *shm = pcm->private; snd_pcm_shm_t *shm = pcm->private;
volatile snd_pcm_shm_ctrl_t *ctrl = shm->ctrl; 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) static int snd_pcm_shm_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params)
{ {
snd_pcm_hw_params_t sparams; return snd_pcm_hw_params_slave(pcm, params,
unsigned int links = ~SND_PCM_HW_PARBIT_ACCESS; snd_pcm_shm_hw_refine_cchange,
const mask_t *access_mask = snd_pcm_hw_param_value_mask(params, SND_PCM_HW_PARAM_ACCESS); snd_pcm_shm_hw_refine_sprepare,
mask_t *saccess_mask = alloca(mask_sizeof()); snd_pcm_shm_hw_refine_schange,
int err; snd_pcm_shm_hw_params_slave);
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;
} }
static int snd_pcm_shm_sw_params(snd_pcm_t *pcm, snd_pcm_sw_params_t * params) static int snd_pcm_shm_sw_params(snd_pcm_t *pcm, snd_pcm_sw_params_t * params)