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

View file

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

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_t *slave = alaw->plug.slave;
int err;
unsigned int cmask, lcmask;
snd_pcm_hw_params_t sparams;
mask_t *access_mask = alloca(mask_sizeof());
mask_t *saccess_mask = alloca(mask_sizeof());
mask_load(access_mask, SND_PCM_ACCBIT_PLUGIN);
mask_load(saccess_mask, SND_PCM_ACCBIT_MMAP);
cmask = params->cmask;
params->cmask = 0;
err = _snd_pcm_hw_param_mask(params, SND_PCM_HW_PARAM_ACCESS,
access_mask);
access_mask);
if (err < 0)
return err;
if (alaw->sformat == SND_PCM_FORMAT_A_LAW) {
mask_t *format_mask = alloca(mask_sizeof());
mask_load(format_mask, SND_PCM_FMTBIT_LINEAR);
err = _snd_pcm_hw_param_mask(params,
SND_PCM_HW_PARAM_FORMAT,
format_mask);
if (err < 0)
return err;
err = _snd_pcm_hw_param_mask(params, SND_PCM_HW_PARAM_FORMAT,
format_mask);
} else {
err = _snd_pcm_hw_param_set(params,
SND_PCM_HW_PARAM_FORMAT,
SND_PCM_FORMAT_A_LAW, 0);
if (err < 0)
return err;
SND_PCM_HW_PARAM_FORMAT,
SND_PCM_FORMAT_A_LAW, 0);
}
err = _snd_pcm_hw_param_set(params, SND_PCM_HW_PARAM_SUBFORMAT,
SND_PCM_SUBFORMAT_STD, 0);
if (err < 0)
return err;
lcmask = params->cmask;
params->cmask |= cmask;
_snd_pcm_hw_params_any(&sparams);
_snd_pcm_hw_param_mask(&sparams, SND_PCM_HW_PARAM_ACCESS,
saccess_mask);
_snd_pcm_hw_param_set(&sparams, SND_PCM_HW_PARAM_FORMAT,
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;
err = _snd_pcm_hw_param_set(params, SND_PCM_HW_PARAM_SUBFORMAT,
SND_PCM_SUBFORMAT_STD, 0);
if (err < 0)
return err;
params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
return 0;
}
static int snd_pcm_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)
{
snd_pcm_alaw_t *alaw = pcm->private;
snd_pcm_t *slave = alaw->plug.slave;
int err;
snd_pcm_hw_params_t sparams;
unsigned int links;
mask_t *saccess_mask = alloca(mask_sizeof());
mask_load(saccess_mask, SND_PCM_ACCBIT_MMAP);
_snd_pcm_hw_params_any(&sparams);
_snd_pcm_hw_param_mask(&sparams, SND_PCM_HW_PARAM_ACCESS,
saccess_mask);
_snd_pcm_hw_param_set(&sparams, SND_PCM_HW_PARAM_FORMAT,
alaw->sformat, 0);
_snd_pcm_hw_param_set(&sparams, SND_PCM_HW_PARAM_SUBFORMAT,
SND_PCM_SUBFORMAT_STD, 0);
links = SND_PCM_HW_PARBIT_CHANNELS |
SND_PCM_HW_PARBIT_RATE |
SND_PCM_HW_PARBIT_PERIOD_SIZE |
SND_PCM_HW_PARBIT_BUFFER_SIZE |
SND_PCM_HW_PARBIT_PERIODS |
SND_PCM_HW_PARBIT_PERIOD_TIME |
SND_PCM_HW_PARBIT_BUFFER_TIME |
SND_PCM_HW_PARBIT_TICK_TIME;
err = snd_pcm_hw_params_refine(&sparams, links, params);
assert(err >= 0);
err = snd_pcm_hw_params(slave, &sparams);
params->cmask = 0;
sparams.cmask = ~0U;
snd_pcm_hw_params_refine(params, links, &sparams);
int err = snd_pcm_hw_params_slave(pcm, params,
snd_pcm_alaw_hw_refine_cchange,
snd_pcm_alaw_hw_refine_sprepare,
snd_pcm_alaw_hw_refine_schange,
snd_pcm_plugin_hw_params_slave);
if (err < 0)
return err;
params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
if (pcm->stream == SND_PCM_STREAM_PLAYBACK) {
if (alaw->sformat == SND_PCM_FORMAT_A_LAW) {
alaw->getput_idx = get_index(snd_pcm_hw_param_value(params, SND_PCM_HW_PARAM_FORMAT, 0), SND_PCM_FORMAT_S16);

View file

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

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;
unsigned int cmask, lcmask;
snd_pcm_hw_params_t sparams;
mask_t *access_mask = alloca(mask_sizeof());
mask_t *format_mask = alloca(mask_sizeof());
mask_t *saccess_mask = alloca(mask_sizeof());
mask_load(access_mask, SND_PCM_ACCBIT_PLUGIN);
mask_load(format_mask, SND_PCM_FMTBIT_LINEAR);
mask_load(saccess_mask, SND_PCM_ACCBIT_MMAP);
cmask = params->cmask;
params->cmask = 0;
err = _snd_pcm_hw_param_mask(params, SND_PCM_HW_PARAM_ACCESS,
access_mask);
access_mask);
if (err < 0)
return err;
err = _snd_pcm_hw_param_mask(params, SND_PCM_HW_PARAM_FORMAT,
format_mask);
format_mask);
if (err < 0)
return err;
err = _snd_pcm_hw_param_set(params, SND_PCM_HW_PARAM_SUBFORMAT,
SND_PCM_SUBFORMAT_STD, 0);
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;
SND_PCM_SUBFORMAT_STD, 0);
if (err < 0)
return err;
params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
return 0;
}
static int snd_pcm_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)
{
snd_pcm_linear_t *linear = pcm->private;
snd_pcm_t *slave = linear->plug.slave;
int err;
unsigned int links;
snd_pcm_hw_params_t sparams;
mask_t *saccess_mask = alloca(mask_sizeof());
mask_load(saccess_mask, SND_PCM_ACCBIT_MMAP);
_snd_pcm_hw_params_any(&sparams);
_snd_pcm_hw_param_mask(&sparams, SND_PCM_HW_PARAM_ACCESS,
saccess_mask);
_snd_pcm_hw_param_set(&sparams, SND_PCM_HW_PARAM_FORMAT,
linear->sformat, 0);
_snd_pcm_hw_param_set(&sparams, SND_PCM_HW_PARAM_SUBFORMAT,
SND_PCM_SUBFORMAT_STD, 0);
links = SND_PCM_HW_PARBIT_CHANNELS |
SND_PCM_HW_PARBIT_RATE |
SND_PCM_HW_PARBIT_PERIOD_SIZE |
SND_PCM_HW_PARBIT_BUFFER_SIZE |
SND_PCM_HW_PARBIT_PERIODS |
SND_PCM_HW_PARBIT_PERIOD_TIME |
SND_PCM_HW_PARBIT_BUFFER_TIME |
SND_PCM_HW_PARBIT_TICK_TIME;
err = snd_pcm_hw_params_refine(&sparams, links, params);
assert(err >= 0);
err = snd_pcm_hw_params(slave, &sparams);
params->cmask = 0;
sparams.cmask = ~0U;
snd_pcm_hw_params_refine(params, links, &sparams);
int err = snd_pcm_hw_params_slave(pcm, params,
snd_pcm_linear_hw_refine_cchange,
snd_pcm_linear_hw_refine_sprepare,
snd_pcm_linear_hw_refine_schange,
snd_pcm_plugin_hw_params_slave);
if (err < 0)
return err;
params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
if (pcm->stream == SND_PCM_STREAM_PLAYBACK)
linear->conv_idx = conv_index(snd_pcm_hw_param_value(params, SND_PCM_HW_PARAM_FORMAT, 0),
linear->sformat);

View file

@ -299,7 +299,33 @@ static inline int muldiv_near(int a, int b, int c)
return n;
}
int _snd_pcm_hw_refine(snd_pcm_hw_params_t *params);
int snd_pcm_hw_refine_soft(snd_pcm_t *pcm, snd_pcm_hw_params_t *params);
int snd_pcm_hw_refine_slave(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
int (*cprepare)(snd_pcm_t *pcm,
snd_pcm_hw_params_t *params),
int (*cchange)(snd_pcm_t *pcm,
snd_pcm_hw_params_t *params,
snd_pcm_hw_params_t *sparams),
int (*sprepare)(snd_pcm_t *pcm,
snd_pcm_hw_params_t *params),
int (*schange)(snd_pcm_t *pcm,
snd_pcm_hw_params_t *params,
snd_pcm_hw_params_t *sparams),
int (*srefine)(snd_pcm_t *pcm,
snd_pcm_hw_params_t *sparams));
int snd_pcm_hw_params_slave(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
int (*cchange)(snd_pcm_t *pcm,
snd_pcm_hw_params_t *params,
snd_pcm_hw_params_t *sparams),
int (*sprepare)(snd_pcm_t *pcm,
snd_pcm_hw_params_t *params),
int (*schange)(snd_pcm_t *pcm,
snd_pcm_hw_params_t *params,
snd_pcm_hw_params_t *sparams),
int (*sparams)(snd_pcm_t *pcm,
snd_pcm_hw_params_t *sparams));
void _snd_pcm_hw_params_any(snd_pcm_hw_params_t *params);
int _snd_pcm_hw_param_refine_interval(snd_pcm_hw_params_t *params,
snd_pcm_hw_param_t var,
@ -316,34 +342,16 @@ int _snd_pcm_hw_param_min(snd_pcm_hw_params_t *params,
unsigned int var, unsigned int val, int dir);
int _snd_pcm_hw_param_max(snd_pcm_hw_params_t *params,
unsigned int var, unsigned int val, int dir);
int snd_pcm_hw_param_refine(snd_pcm_hw_params_t *params,
snd_pcm_hw_param_t var,
const snd_pcm_hw_params_t *src);
int snd_pcm_hw_params_refine(snd_pcm_hw_params_t *params,
unsigned int vars,
int _snd_pcm_hw_param_refine(snd_pcm_hw_params_t *params,
snd_pcm_hw_param_t var,
const snd_pcm_hw_params_t *src);
int snd_pcm_generic_hw_link(snd_pcm_hw_params_t *params,
snd_pcm_hw_params_t *sparams,
snd_pcm_t *slave,
unsigned long links);
int snd_pcm_hw_refine2(snd_pcm_hw_params_t *params,
snd_pcm_hw_params_t *sparams,
int (*func)(snd_pcm_hw_params_t *params,
snd_pcm_hw_params_t *sparams,
snd_pcm_t *slave,
unsigned long private),
snd_pcm_t *slave,
unsigned long private);
int snd_pcm_hw_params2(snd_pcm_hw_params_t *params,
snd_pcm_hw_params_t *sparams,
int (*func)(snd_pcm_t *slave,
snd_pcm_hw_params_t *sparams),
snd_pcm_t *slave,
unsigned int links);
void snd_pcm_hw_param_near_copy(snd_pcm_t *pcm,
snd_pcm_hw_params_t *params,
snd_pcm_hw_param_t var,
const snd_pcm_hw_params_t *src);
int _snd_pcm_hw_params_refine(snd_pcm_hw_params_t *params,
unsigned int vars,
const snd_pcm_hw_params_t *src);
void snd_pcm_hw_param_refine_near(snd_pcm_t *pcm,
snd_pcm_hw_params_t *params,
snd_pcm_hw_param_t var,
const snd_pcm_hw_params_t *src);
int snd_pcm_hw_param_always_eq(const snd_pcm_hw_params_t *params,
snd_pcm_hw_param_t var,
const snd_pcm_hw_params_t *params1);

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_t *slave = mulaw->plug.slave;
int err;
unsigned int cmask, lcmask;
snd_pcm_hw_params_t sparams;
mask_t *access_mask = alloca(mask_sizeof());
mask_t *saccess_mask = alloca(mask_sizeof());
mask_load(access_mask, SND_PCM_ACCBIT_PLUGIN);
mask_load(saccess_mask, SND_PCM_ACCBIT_MMAP);
cmask = params->cmask;
params->cmask = 0;
err = _snd_pcm_hw_param_mask(params, SND_PCM_HW_PARAM_ACCESS,
access_mask);
if (err < 0)
@ -248,83 +241,93 @@ static int snd_pcm_mulaw_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
if (mulaw->sformat == SND_PCM_FORMAT_MU_LAW) {
mask_t *format_mask = alloca(mask_sizeof());
mask_load(format_mask, SND_PCM_FMTBIT_LINEAR);
err = _snd_pcm_hw_param_mask(params,
SND_PCM_HW_PARAM_FORMAT,
err = _snd_pcm_hw_param_mask(params, SND_PCM_HW_PARAM_FORMAT,
format_mask);
if (err < 0)
return err;
} else {
err = _snd_pcm_hw_param_set(params,
SND_PCM_HW_PARAM_FORMAT,
SND_PCM_FORMAT_MU_LAW, 0);
if (err < 0)
return err;
}
err = _snd_pcm_hw_param_set(params, SND_PCM_HW_PARAM_SUBFORMAT,
SND_PCM_SUBFORMAT_STD, 0);
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;
SND_PCM_SUBFORMAT_STD, 0);
if (err < 0)
return err;
params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
return 0;
}
static int snd_pcm_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)
{
snd_pcm_mulaw_t *mulaw = pcm->private;
snd_pcm_t *slave = mulaw->plug.slave;
int err;
unsigned int links;
snd_pcm_hw_params_t sparams;
mask_t *saccess_mask = alloca(mask_sizeof());
mask_load(saccess_mask, SND_PCM_ACCBIT_MMAP);
_snd_pcm_hw_params_any(&sparams);
_snd_pcm_hw_param_mask(&sparams, SND_PCM_HW_PARAM_ACCESS,
saccess_mask);
_snd_pcm_hw_param_set(&sparams, SND_PCM_HW_PARAM_FORMAT,
mulaw->sformat, 0);
_snd_pcm_hw_param_set(&sparams, SND_PCM_HW_PARAM_SUBFORMAT,
SND_PCM_SUBFORMAT_STD, 0);
links = SND_PCM_HW_PARBIT_CHANNELS |
SND_PCM_HW_PARBIT_RATE |
SND_PCM_HW_PARBIT_PERIOD_SIZE |
SND_PCM_HW_PARBIT_BUFFER_SIZE |
SND_PCM_HW_PARBIT_PERIODS |
SND_PCM_HW_PARBIT_PERIOD_TIME |
SND_PCM_HW_PARBIT_BUFFER_TIME |
SND_PCM_HW_PARBIT_TICK_TIME;
err = snd_pcm_hw_params_refine(&sparams, links, params);
assert(err >= 0);
err = snd_pcm_hw_params(slave, &sparams);
params->cmask = 0;
sparams.cmask = ~0U;
snd_pcm_hw_params_refine(params, links, &sparams);
int err = snd_pcm_hw_params_slave(pcm, params,
snd_pcm_mulaw_hw_refine_cchange,
snd_pcm_mulaw_hw_refine_sprepare,
snd_pcm_mulaw_hw_refine_schange,
snd_pcm_plugin_hw_params_slave);
if (err < 0)
return err;
params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
if (pcm->stream == SND_PCM_STREAM_PLAYBACK) {
if (mulaw->sformat == SND_PCM_FORMAT_MU_LAW) {
mulaw->getput_idx = get_index(snd_pcm_hw_param_value(params, SND_PCM_HW_PARAM_FORMAT, 0), SND_PCM_FORMAT_S16);

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)
{
return -ENOENT; /* not available */
snd_pcm_multi_t *multi = pcm->private;
if (multi->slaves_count != 1)
return -ENOENT; /* not available */
return snd_pcm_card(multi->slaves[0].pcm);
}
static int snd_pcm_multi_nonblock(snd_pcm_t *pcm ATTRIBUTE_UNUSED, int nonblock ATTRIBUTE_UNUSED)
@ -96,135 +99,188 @@ static int snd_pcm_multi_info(snd_pcm_t *pcm, snd_pcm_info_t *info)
return 0;
}
static int snd_pcm_multi_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
static int snd_pcm_multi_hw_refine_cprepare(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
{
snd_pcm_multi_t *multi = pcm->private;
unsigned int k;
snd_pcm_hw_params_t sparams;
int changed = 0;
int err = 0;
unsigned int cmask, lcmask;
const mask_t *access_mask = snd_pcm_hw_param_value_mask(params, SND_PCM_HW_PARAM_ACCESS);
mask_t *saccess_mask = alloca(mask_sizeof());
if (mask_test(access_mask, SND_PCM_ACCESS_RW_INTERLEAVED) ||
mask_test(access_mask, SND_PCM_ACCESS_RW_NONINTERLEAVED))
mask_load(saccess_mask, SND_PCM_ACCBIT_MMAP);
else {
mask_none(saccess_mask);
if (mask_test(access_mask, SND_PCM_ACCESS_MMAP_INTERLEAVED) &&
multi->slaves_count == 1)
mask_set(saccess_mask, SND_PCM_ACCESS_MMAP_INTERLEAVED);
if (mask_test(access_mask, SND_PCM_ACCESS_MMAP_NONINTERLEAVED))
mask_set(saccess_mask, SND_PCM_ACCESS_MMAP_NONINTERLEAVED);
if (mask_test(access_mask, SND_PCM_ACCESS_MMAP_COMPLEX)) {
mask_set(saccess_mask, SND_PCM_ACCESS_MMAP_COMPLEX);
if (multi->slaves_count > 1)
mask_set(saccess_mask, SND_PCM_ACCESS_MMAP_INTERLEAVED);
}
}
cmask = params->cmask;
params->cmask = 0;
mask_t *access_mask = alloca(mask_sizeof());
int err;
mask_any(access_mask);
mask_reset(access_mask, SND_PCM_ACCESS_MMAP_INTERLEAVED);
err = _snd_pcm_hw_param_mask(params, SND_PCM_HW_PARAM_ACCESS,
access_mask);
if (err < 0)
return err;
err = _snd_pcm_hw_param_set(params, SND_PCM_HW_PARAM_CHANNELS,
multi->channels_count, 0);
if (err < 0)
return err;
lcmask = params->cmask;
cmask |= params->cmask;
params->info = ~0;
return 0;
}
static int snd_pcm_multi_hw_refine_sprepare(snd_pcm_t *pcm, int slave_idx,
snd_pcm_hw_params_t *sparams)
{
snd_pcm_multi_t *multi = pcm->private;
snd_pcm_multi_slave_t *slave = &multi->slaves[slave_idx];
mask_t *saccess_mask = alloca(mask_sizeof());
mask_load(saccess_mask, SND_PCM_ACCBIT_MMAP);
_snd_pcm_hw_params_any(sparams);
_snd_pcm_hw_param_mask(sparams, SND_PCM_HW_PARAM_ACCESS,
saccess_mask);
_snd_pcm_hw_param_set(sparams, SND_PCM_HW_PARAM_CHANNELS,
slave->channels_count, 0);
return 0;
}
static int snd_pcm_multi_hw_refine_schange(snd_pcm_t *pcm ATTRIBUTE_UNUSED,
int slave_idx ATTRIBUTE_UNUSED,
snd_pcm_hw_params_t *params,
snd_pcm_hw_params_t *sparams)
{
int err;
unsigned int links = (SND_PCM_HW_PARBIT_FORMAT |
SND_PCM_HW_PARBIT_SUBFORMAT |
SND_PCM_HW_PARBIT_RATE |
SND_PCM_HW_PARBIT_PERIOD_SIZE |
SND_PCM_HW_PARBIT_PERIOD_TIME |
SND_PCM_HW_PARBIT_PERIODS |
SND_PCM_HW_PARBIT_BUFFER_SIZE |
SND_PCM_HW_PARBIT_BUFFER_TIME |
SND_PCM_HW_PARBIT_TICK_TIME);
const mask_t *access_mask = snd_pcm_hw_param_value_mask(params, SND_PCM_HW_PARAM_ACCESS);
if (!mask_test(access_mask, SND_PCM_ACCESS_RW_INTERLEAVED) &&
!mask_test(access_mask, SND_PCM_ACCESS_RW_NONINTERLEAVED) &&
!mask_test(access_mask, SND_PCM_ACCESS_MMAP_NONINTERLEAVED)) {
mask_t *saccess_mask = alloca(mask_sizeof());
mask_any(saccess_mask);
mask_reset(saccess_mask, SND_PCM_ACCESS_MMAP_NONINTERLEAVED);
err = _snd_pcm_hw_param_mask(sparams, SND_PCM_HW_PARAM_ACCESS,
saccess_mask);
if (err < 0)
return err;
}
err = _snd_pcm_hw_params_refine(sparams, links, params);
if (err < 0)
return err;
return 0;
}
changed = 0;
do {
for (k = 0; k < multi->slaves_count; ++k) {
snd_pcm_t *slave = multi->slaves[k].pcm;
params->cmask = cmask;
_snd_pcm_hw_params_any(&sparams);
_snd_pcm_hw_param_mask(&sparams,
SND_PCM_HW_PARAM_ACCESS,
saccess_mask);
_snd_pcm_hw_param_set(&sparams,
SND_PCM_HW_PARAM_CHANNELS,
multi->slaves[k].channels_count, 0);
err = snd_pcm_hw_refine2(params, &sparams,
snd_pcm_generic_hw_link, slave,
SND_PCM_HW_PARBIT_FORMAT |
SND_PCM_HW_PARBIT_SUBFORMAT |
SND_PCM_HW_PARBIT_RATE |
SND_PCM_HW_PARBIT_PERIOD_SIZE |
SND_PCM_HW_PARBIT_PERIOD_TIME |
SND_PCM_HW_PARBIT_BUFFER_SIZE |
SND_PCM_HW_PARBIT_BUFFER_TIME |
SND_PCM_HW_PARBIT_PERIODS |
SND_PCM_HW_PARBIT_TICK_TIME);
if (params->cmask) {
changed++;
lcmask |= params->cmask;
cmask |= params->cmask;
}
if (err < 0)
goto _end;
static int snd_pcm_multi_hw_refine_cchange(snd_pcm_t *pcm ATTRIBUTE_UNUSED,
int slave_idx ATTRIBUTE_UNUSED,
snd_pcm_hw_params_t *params,
snd_pcm_hw_params_t *sparams)
{
int err;
unsigned int links = (SND_PCM_HW_PARBIT_FORMAT |
SND_PCM_HW_PARBIT_SUBFORMAT |
SND_PCM_HW_PARBIT_RATE |
SND_PCM_HW_PARBIT_PERIOD_SIZE |
SND_PCM_HW_PARBIT_PERIOD_TIME |
SND_PCM_HW_PARBIT_PERIODS |
SND_PCM_HW_PARBIT_BUFFER_SIZE |
SND_PCM_HW_PARBIT_BUFFER_TIME |
SND_PCM_HW_PARBIT_TICK_TIME);
mask_t *access_mask = alloca(mask_sizeof());
const mask_t *saccess_mask = snd_pcm_hw_param_value_mask(sparams, SND_PCM_HW_PARAM_ACCESS);
mask_any(access_mask);
mask_reset(access_mask, SND_PCM_ACCESS_MMAP_INTERLEAVED);
if (!mask_test(saccess_mask, SND_PCM_ACCESS_MMAP_NONINTERLEAVED))
mask_reset(access_mask, SND_PCM_ACCESS_MMAP_NONINTERLEAVED);
if (!mask_test(saccess_mask, SND_PCM_ACCESS_MMAP_COMPLEX) &&
!mask_test(saccess_mask, SND_PCM_ACCESS_MMAP_INTERLEAVED))
mask_reset(access_mask, SND_PCM_ACCESS_MMAP_COMPLEX);
err = _snd_pcm_hw_param_mask(params, SND_PCM_HW_PARAM_ACCESS,
access_mask);
if (err < 0)
return err;
err = _snd_pcm_hw_params_refine(params, links, sparams);
if (err < 0)
return err;
params->info &= sparams->info;
return 0;
}
static int snd_pcm_multi_hw_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:
params->cmask = lcmask;
return err;
}
/* FIXME: loop begin? */
for (k = 0; k < multi->slaves_count; ++k) {
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)
{
snd_pcm_multi_t *multi = pcm->private;
unsigned int k;
snd_pcm_hw_params_t sparams[multi->slaves_count];
int err;
const mask_t *access_mask = snd_pcm_hw_param_value_mask(params, SND_PCM_HW_PARAM_ACCESS);
mask_t *saccess_mask = alloca(mask_sizeof());
unsigned int links;
links = SND_PCM_HW_PARBIT_FORMAT |
SND_PCM_HW_PARBIT_SUBFORMAT |
SND_PCM_HW_PARBIT_RATE |
SND_PCM_HW_PARBIT_PERIOD_SIZE |
SND_PCM_HW_PARBIT_PERIOD_TIME |
SND_PCM_HW_PARBIT_BUFFER_SIZE |
SND_PCM_HW_PARBIT_BUFFER_TIME |
SND_PCM_HW_PARBIT_PERIODS |
SND_PCM_HW_PARBIT_TICK_TIME;
if (mask_test(access_mask, SND_PCM_ACCESS_RW_INTERLEAVED) ||
mask_test(access_mask, SND_PCM_ACCESS_RW_NONINTERLEAVED))
mask_load(saccess_mask, SND_PCM_ACCBIT_MMAP);
else {
mask_none(saccess_mask);
if (mask_test(access_mask, SND_PCM_ACCESS_MMAP_INTERLEAVED) &&
multi->slaves_count == 1)
mask_set(saccess_mask, SND_PCM_ACCESS_MMAP_INTERLEAVED);
if (mask_test(access_mask, SND_PCM_ACCESS_MMAP_NONINTERLEAVED))
mask_set(saccess_mask, SND_PCM_ACCESS_MMAP_NONINTERLEAVED);
if (mask_test(access_mask, SND_PCM_ACCESS_MMAP_COMPLEX)) {
mask_set(saccess_mask, SND_PCM_ACCESS_MMAP_COMPLEX);
if (multi->slaves_count > 1)
mask_set(saccess_mask, SND_PCM_ACCESS_MMAP_INTERLEAVED);
}
}
for (k = 0; k < multi->slaves_count; ++k) {
snd_pcm_t *slave = multi->slaves[k].pcm;
snd_pcm_hw_params_t sparams;
_snd_pcm_hw_params_any(&sparams);
_snd_pcm_hw_param_mask(&sparams, SND_PCM_HW_PARAM_ACCESS,
saccess_mask);
_snd_pcm_hw_param_set(&sparams, SND_PCM_HW_PARAM_CHANNELS,
multi->slaves[k].channels_count, 0);
err = snd_pcm_hw_params_refine(&sparams, links, params);
err = snd_pcm_multi_hw_refine_sprepare(pcm, k, &sparams[k]);
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)
err = snd_pcm_multi_hw_refine_schange(pcm, k, params, &sparams[k]);
assert(err >= 0);
err = snd_pcm_multi_hw_params_slave(pcm, k, &sparams[k]);
if (err < 0) {
snd_pcm_multi_hw_refine_cchange(pcm, k, params, &sparams[k]);
return err;
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;

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)
{
int err = _snd_pcm_hw_refine(params);
int err = snd_pcm_hw_refine_soft(pcm, params);
params->fifo_size = 0;
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)) {
mask_any(hw_param_mask(params, var));
params->cmask |= 1 << var;
params->rmask |= 1 << var;
return;
}
if (hw_is_interval(var)) {
interval_any(hw_param_interval(params, var));
params->cmask |= 1 << var;
params->rmask |= 1 << var;
return;
}
assert(0);
@ -241,8 +243,10 @@ int _snd_pcm_hw_param_refine_interval(snd_pcm_hw_params_t *params,
int changed;
assert(hw_is_interval(var));
changed = interval_refine(hw_param_interval(params, var), val);
if (changed)
if (changed) {
params->cmask |= 1 << var;
params->rmask |= 1 << var;
}
return changed;
}
@ -252,8 +256,10 @@ int _snd_pcm_hw_param_setinteger(snd_pcm_hw_params_t *params,
int changed;
assert(hw_is_interval(var));
changed = interval_setinteger(hw_param_interval(params, var));
if (changed)
if (changed) {
params->cmask |= 1 << var;
params->rmask |= 1 << var;
}
return changed;
}
@ -268,7 +274,7 @@ int snd_pcm_hw_param_setinteger(snd_pcm_t *pcm,
int changed = _snd_pcm_hw_param_setinteger(params, var);
if (changed < 0)
return changed;
if (changed) {
if (params->rmask) {
int err = snd_pcm_hw_refine(pcm, params);
if (err < 0)
return err;
@ -288,8 +294,10 @@ int _snd_pcm_hw_param_first(snd_pcm_hw_params_t *params,
assert(0);
return -EINVAL;
}
if (changed)
if (changed) {
params->cmask |= 1 << var;
params->rmask |= 1 << var;
}
return changed;
}
@ -305,7 +313,7 @@ int snd_pcm_hw_param_first(snd_pcm_t *pcm,
int changed = _snd_pcm_hw_param_first(params, var);
if (changed < 0)
return changed;
if (changed) {
if (params->rmask) {
int err = snd_pcm_hw_refine(pcm, params);
assert(err >= 0);
}
@ -324,8 +332,10 @@ int _snd_pcm_hw_param_last(snd_pcm_hw_params_t *params,
assert(0);
return -EINVAL;
}
if (changed)
if (changed) {
params->cmask |= 1 << var;
params->rmask |= 1 << var;
}
return changed;
}
@ -341,7 +351,7 @@ int snd_pcm_hw_param_last(snd_pcm_t *pcm,
int changed = _snd_pcm_hw_param_last(params, var);
if (changed < 0)
return changed;
if (changed) {
if (params->rmask) {
int err = snd_pcm_hw_refine(pcm, params);
assert(err >= 0);
}
@ -371,8 +381,10 @@ int _snd_pcm_hw_param_min(snd_pcm_hw_params_t *params,
assert(0);
return -EINVAL;
}
if (changed)
if (changed) {
params->cmask |= 1 << var;
params->rmask |= 1 << var;
}
return changed;
}
@ -386,7 +398,7 @@ int snd_pcm_hw_param_min(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
int changed = _snd_pcm_hw_param_min(params, var, val, dir ? *dir : 0);
if (changed < 0)
return changed;
if (changed) {
if (params->rmask) {
int err = snd_pcm_hw_refine(pcm, params);
if (err < 0)
return err;
@ -432,8 +444,10 @@ int _snd_pcm_hw_param_max(snd_pcm_hw_params_t *params,
assert(0);
return -EINVAL;
}
if (changed)
if (changed) {
params->cmask |= 1 << var;
params->rmask |= 1 << var;
}
return changed;
}
@ -447,7 +461,7 @@ int snd_pcm_hw_param_max(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
int changed = _snd_pcm_hw_param_max(params, var, val, dir ? *dir : 0);
if (changed < 0)
return changed;
if (changed) {
if (params->rmask) {
int err = snd_pcm_hw_refine(pcm, params);
if (err < 0)
return err;
@ -527,8 +541,10 @@ int _snd_pcm_hw_param_minmax(snd_pcm_hw_params_t *params,
assert(0);
return -EINVAL;
}
if (changed)
if (changed) {
params->cmask |= 1 << var;
params->rmask |= 1 << var;
}
return changed;
}
@ -546,7 +562,7 @@ int snd_pcm_hw_param_minmax(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
*max, maxdir ? *maxdir : 0);
if (changed < 0)
return changed;
if (changed) {
if (params->rmask) {
int err = snd_pcm_hw_refine(pcm, params);
if (err < 0)
return err;
@ -614,8 +630,10 @@ int _snd_pcm_hw_param_set(snd_pcm_hw_params_t *params,
assert(0);
return -EINVAL;
}
if (changed)
if (changed) {
params->cmask |= 1 << var;
params->rmask |= 1 << var;
}
return changed;
}
@ -629,7 +647,7 @@ int snd_pcm_hw_param_set(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
int changed = _snd_pcm_hw_param_set(params, var, val, dir);
if (changed < 0)
return changed;
if (changed) {
if (params->rmask) {
int err = snd_pcm_hw_refine(pcm, params);
if (err < 0)
return err;
@ -655,8 +673,10 @@ int _snd_pcm_hw_param_mask(snd_pcm_hw_params_t *params,
int changed;
assert(hw_is_mask(var));
changed = mask_refine(hw_param_mask(params, var), val);
if (changed)
if (changed) {
params->cmask |= 1 << var;
params->rmask |= 1 << var;
}
return changed;
}
@ -673,7 +693,7 @@ int snd_pcm_hw_param_mask(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
int changed = _snd_pcm_hw_param_mask(params, var, val);
if (changed < 0)
return changed;
if (changed) {
if (params->rmask) {
int err = snd_pcm_hw_refine(pcm, params);
if (err < 0)
return err;
@ -706,7 +726,6 @@ int snd_pcm_hw_param_near(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
int v;
unsigned int saved_min;
int last = 0;
unsigned int cmask;
int min, max;
int mindir, maxdir;
int valdir = dir ? *dir : 0;
@ -747,12 +766,10 @@ int snd_pcm_hw_param_near(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
last = 1;
}
_end:
cmask = params->cmask;
if (last)
v = snd_pcm_hw_param_last(pcm, params, var, dir);
else
v = snd_pcm_hw_param_first(pcm, params, var, dir);
params->cmask |= cmask;
assert(v >= 0);
return v;
}
@ -773,7 +790,6 @@ int snd_pcm_hw_param_next(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
snd_pcm_hw_params_t save;
int v;
int last = 0;
unsigned int cmask;
int min, max;
int mindir, maxdir;
int diff, diffdir;
@ -821,12 +837,10 @@ int snd_pcm_hw_param_next(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
last = 1;
}
_end:
cmask = params->cmask;
if (last)
v = snd_pcm_hw_param_last(pcm, params, var, dir);
else
v = snd_pcm_hw_param_first(pcm, params, var, dir);
params->cmask |= cmask;
assert(v >= 0);
return v;
}
@ -857,10 +871,10 @@ void snd_pcm_hw_param_near_minmax(snd_pcm_t *pcm,
assert(err >= 0);
}
void snd_pcm_hw_param_near_copy(snd_pcm_t *pcm,
snd_pcm_hw_params_t *params,
snd_pcm_hw_param_t var,
const snd_pcm_hw_params_t *src)
void snd_pcm_hw_param_refine_near(snd_pcm_t *pcm,
snd_pcm_hw_params_t *params,
snd_pcm_hw_param_t var,
const snd_pcm_hw_params_t *src)
{
unsigned int min, max;
int mindir, maxdir;
@ -963,41 +977,30 @@ int snd_pcm_hw_params_info_fifo_size(const snd_pcm_hw_params_t *params)
void snd_pcm_hw_params_choose(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
{
int err;
unsigned int cmask = params->cmask;
err = snd_pcm_hw_param_first(pcm, params, SND_PCM_HW_PARAM_ACCESS, 0);
assert(err >= 0);
cmask |= params->cmask;
err = snd_pcm_hw_param_first(pcm, params, SND_PCM_HW_PARAM_FORMAT, 0);
assert(err >= 0);
cmask |= params->cmask;
err = snd_pcm_hw_param_first(pcm, params, SND_PCM_HW_PARAM_SUBFORMAT, 0);
assert(err >= 0);
cmask |= params->cmask;
err = snd_pcm_hw_param_first(pcm, params, SND_PCM_HW_PARAM_CHANNELS, 0);
assert(err >= 0);
cmask |= params->cmask;
err = snd_pcm_hw_param_first(pcm, params, SND_PCM_HW_PARAM_RATE, 0);
assert(err >= 0);
cmask |= params->cmask;
err = snd_pcm_hw_param_first(pcm, params, SND_PCM_HW_PARAM_PERIOD_TIME, 0);
assert(err >= 0);
cmask |= params->cmask;
err = snd_pcm_hw_param_last(pcm, params, SND_PCM_HW_PARAM_BUFFER_SIZE, 0);
assert(err >= 0);
cmask |= params->cmask;
err = snd_pcm_hw_param_first(pcm, params, SND_PCM_HW_PARAM_TICK_TIME, 0);
assert(err >= 0);
cmask |= params->cmask;
params->cmask = cmask;
}
/* Strategies */
@ -1080,9 +1083,9 @@ unsigned int snd_pcm_hw_param_count(const snd_pcm_hw_params_t *params,
return 0;
}
int snd_pcm_hw_param_refine(snd_pcm_hw_params_t *params,
snd_pcm_hw_param_t var,
const snd_pcm_hw_params_t *src)
int _snd_pcm_hw_param_refine(snd_pcm_hw_params_t *params,
snd_pcm_hw_param_t var,
const snd_pcm_hw_params_t *src)
{
int changed = 0;
if (hw_is_mask(var)) {
@ -1095,23 +1098,29 @@ int snd_pcm_hw_param_refine(snd_pcm_hw_params_t *params,
changed = interval_refine(d, s);
} else
assert(0);
if (changed)
if (changed) {
params->cmask |= 1 << var;
params->rmask |= 1 << var;
}
return changed;
}
void snd_pcm_hw_param_copy(snd_pcm_hw_params_t *params, snd_pcm_hw_param_t var,
void _snd_pcm_hw_param_copy(snd_pcm_hw_params_t *params, snd_pcm_hw_param_t var,
const snd_pcm_hw_params_t *src)
{
if (hw_is_mask(var)) {
mask_t *d = hw_param_mask(params, var);
const mask_t *s = hw_param_mask_c(src, var);
mask_copy(d, s);
params->cmask |= 1 << var;
params->rmask |= 1 << var;
}
if (hw_is_interval(var)) {
interval_t *d = hw_param_interval(params, var);
const interval_t *s = hw_param_interval_c(src, var);
interval_copy(d, s);
params->cmask |= 1 << var;
params->rmask |= 1 << var;
}
assert(0);
}
@ -1138,8 +1147,11 @@ void snd_pcm_hw_param_dump(const snd_pcm_hw_params_t *params,
assert(f);
for (k = 0; k <= MASK_MAX; ++k) {
if (mask_test(mask, k)) {
snd_output_putc(out, ' ');
snd_output_puts(out, f(k));
const char *s = f(k);
if (s) {
snd_output_putc(out, ' ');
snd_output_puts(out, s);
}
}
}
}
@ -1188,14 +1200,11 @@ int snd_pcm_hw_params_strategy(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
best_badness = UINT_MAX;
value = -1;
while (1) {
unsigned int cmask;
params1 = *params;
value = strategy->next_value(&params1, var, value, &dir, pcm, strategy);
if (value < 0)
break;
cmask = params1.cmask;
badness = snd_pcm_hw_params_strategy(pcm, &params1, strategy, badness_min, badness_max);
params1.cmask |= cmask;
if (badness >= 0) {
if ((unsigned int) badness <= badness_min) {
*params = params1;
@ -1475,7 +1484,7 @@ int snd_pcm_hw_params_try_explain_failure1(snd_pcm_t *pcm,
for (var = 0; var <= SND_PCM_HW_PARAM_LAST; var++) {
int err;
i = *success;
snd_pcm_hw_param_copy(&i, var, fail);
_snd_pcm_hw_param_copy(&i, var, fail);
err = snd_pcm_hw_refine(pcm, &i);
if (err == 0 &&
snd_pcm_hw_params_try_explain_failure1(pcm, fail, &i, depth - 1, out) < 0)
@ -1836,50 +1845,53 @@ static interval_t refine_intervals[SND_PCM_HW_PARAM_LAST_INTERVAL - SND_PCM_HW_P
},
};
#undef RULES_DEBUG
int _snd_pcm_hw_refine(snd_pcm_hw_params_t *params)
int snd_pcm_hw_refine_soft(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params)
{
unsigned int k;
interval_t *i;
unsigned int rstamps[RULES];
unsigned int vstamps[SND_PCM_HW_PARAM_LAST + 1];
unsigned int stamp = 2;
int err, changed;
int changed, again;
#ifdef RULES_DEBUG
snd_output_t *log;
snd_output_stdio_attach(&log, stderr, 0);
#endif
for (k = SND_PCM_HW_PARAM_FIRST_MASK; k <= SND_PCM_HW_PARAM_LAST_MASK; k++) {
if (!(params->cmask & (1 << k)))
if (!(params->rmask & (1 << k)))
continue;
err = mask_refine(hw_param_mask(params, k),
changed = mask_refine(hw_param_mask(params, k),
&refine_masks[k - SND_PCM_HW_PARAM_FIRST_MASK]);
if (err < 0)
return err;
if (changed)
params->cmask |= 1 << k;
if (changed < 0)
goto _err;
}
for (k = SND_PCM_HW_PARAM_FIRST_INTERVAL; k <= SND_PCM_HW_PARAM_LAST_INTERVAL; k++) {
if (!(params->cmask & (1 << k)))
if (!(params->rmask & (1 << k)))
continue;
err = interval_refine(hw_param_interval(params, k),
changed = interval_refine(hw_param_interval(params, k),
&refine_intervals[k - SND_PCM_HW_PARAM_FIRST_INTERVAL]);
if (err < 0)
return err;
if (changed)
params->cmask |= 1 << k;
if (changed < 0)
goto _err;
}
for (k = 0; k < RULES; k++)
rstamps[k] = 0;
for (k = 0; k <= SND_PCM_HW_PARAM_LAST; k++)
vstamps[k] = (params->cmask & (1 << k)) ? 1 : 0;
params->cmask = 0;
changed = 1;
while (changed) {
changed = 0;
vstamps[k] = (params->rmask & (1 << k)) ? 1 : 0;
do {
again = 0;
for (k = 0; k < RULES; k++) {
snd_pcm_hw_rule_t *r = &refine_rules[k];
unsigned int d;
int doit = 0;
#ifdef RULES_DEBUG
interval_t *i;
#endif
for (d = 0; r->deps[d] >= 0; d++) {
if (vstamps[r->deps[d]] > rstamps[k]) {
doit = 1;
@ -1889,26 +1901,35 @@ int _snd_pcm_hw_refine(snd_pcm_hw_params_t *params)
if (!doit)
continue;
#ifdef RULES_DEBUG
i = hw_param_interval(params, r->var);
fprintf(stderr, "Rule %d: %u ", k, r->var);
interval_print(i, stderr);
snd_output_printf(log, "Rule %d: ", k);
if (r->var >= 0) {
snd_output_printf(log, "%s=", snd_pcm_hw_param_name(r->var));
snd_pcm_hw_param_dump(params, r->var, log);
snd_output_puts(log, " -> ");
}
#endif
err = r->func(params, r);
changed = r->func(params, r);
#ifdef RULES_DEBUG
interval_print(i, stderr);
putc('\n', stderr);
if (r->var >= 0)
snd_pcm_hw_param_dump(params, r->var, log);
snd_output_putc(log, ' ');
for (d = 0; r->deps[d] >= 0; d++) {
snd_output_printf(log, "%s=", snd_pcm_hw_param_name(r->deps[d]));
snd_pcm_hw_param_dump(params, r->deps[d], log);
}
snd_output_putc(log, '\n');
#endif
rstamps[k] = stamp;
if (err && r->var >= 0) {
if (changed && r->var >= 0) {
params->cmask |= 1 << r->var;
vstamps[r->var] = stamp;
changed = 1;
again = 1;
}
if (err < 0)
return err;
if (changed < 0)
goto _err;
stamp++;
}
}
} while (again);
if (!params->msbits) {
i = hw_param_interval(params, SND_PCM_HW_PARAM_SAMPLE_BITS);
if (interval_single(i))
@ -1922,69 +1943,97 @@ int _snd_pcm_hw_refine(snd_pcm_hw_params_t *params)
params->rate_den = 1;
}
}
params->rmask = 0;
return 0;
_err:
#ifdef RULES_DEBUG
snd_output_close(log);
#endif
return changed;
}
int snd_pcm_hw_params_refine(snd_pcm_hw_params_t *params,
unsigned int vars,
const snd_pcm_hw_params_t *src)
int _snd_pcm_hw_params_refine(snd_pcm_hw_params_t *params,
unsigned int vars,
const snd_pcm_hw_params_t *src)
{
int changed, err = 0;
unsigned int k;
for (k = 0; k <= SND_PCM_HW_PARAM_LAST; ++k) {
if (!(vars & (1 << k)) ||
!((src->cmask & (1 << k))))
if (!(vars & (1 << k)))
continue;
changed = snd_pcm_hw_param_refine(params, k, src);
changed = _snd_pcm_hw_param_refine(params, k, src);
if (changed < 0)
err = changed;
}
return err;
}
/* Accumulate to params->cmask */
/* Reset sparams->cmask */
int snd_pcm_generic_hw_link(snd_pcm_hw_params_t *params,
snd_pcm_hw_params_t *sparams,
snd_pcm_t *slave,
unsigned long links)
int snd_pcm_hw_refine_slave(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
int (*cprepare)(snd_pcm_t *pcm,
snd_pcm_hw_params_t *params),
int (*cchange)(snd_pcm_t *pcm,
snd_pcm_hw_params_t *params,
snd_pcm_hw_params_t *sparams),
int (*sprepare)(snd_pcm_t *pcm,
snd_pcm_hw_params_t *params),
int (*schange)(snd_pcm_t *pcm,
snd_pcm_hw_params_t *params,
snd_pcm_hw_params_t *sparams),
int (*srefine)(snd_pcm_t *pcm,
snd_pcm_hw_params_t *sparams))
{
int err1, err = 0;
err = snd_pcm_hw_params_refine(sparams, links, params);
if (err >= 0) {
unsigned int cmask = sparams->cmask;
err = snd_pcm_hw_refine(slave, sparams);
sparams->cmask |= cmask;
snd_pcm_hw_params_t sparams;
int err;
err = cprepare(pcm, params);
if (err < 0)
return err;
err = sprepare(pcm, &sparams);
if (err < 0) {
ERR("Slave PCM not useable");
return err;
}
err1 = snd_pcm_hw_params_refine(params, links, sparams);
if (err1 < 0)
err = err1;
sparams->cmask = 0;
return err;
/* FIXME: loop begin? */
err = schange(pcm, params, &sparams);
if (err >= 0) {
err = srefine(pcm, &sparams);
}
if (err < 0) {
cchange(pcm, params, &sparams);
return err;
}
err = cchange(pcm, params, &sparams);
if (err < 0)
return err;
err = snd_pcm_hw_refine_soft(pcm, params);
if (err < 0)
return err;
/* FIXME: do we need to loop? */
return 0;
}
int snd_pcm_hw_refine2(snd_pcm_hw_params_t *params,
snd_pcm_hw_params_t *sparams,
int (*func)(snd_pcm_hw_params_t *params,
snd_pcm_hw_params_t *sparams,
snd_pcm_t *slave,
unsigned long private),
snd_pcm_t *slave,
unsigned long private)
int 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))
{
int err = 0;
unsigned int cmask = 0;
while (params->cmask) {
err = func(params, sparams, slave, private);
cmask |= params->cmask;
if (err < 0)
break;
err = _snd_pcm_hw_refine(params);
cmask |= params->cmask;
if (err < 0)
break;
}
params->cmask = cmask;
snd_pcm_hw_params_t slave_params;
int err;
err = sprepare(pcm, &slave_params);
assert(err >= 0);
err = schange(pcm, params, &slave_params);
assert(err >= 0);
err = sparams(pcm, &slave_params);
if (err < 0)
cchange(pcm, params, &slave_params);
return err;
}

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))
/* Accumulate to params->cmask */
/* Reset sparams->cmask */
static int snd_pcm_plug_hw_link(snd_pcm_hw_params_t *params,
snd_pcm_hw_params_t *sparams,
snd_pcm_t *slave,
unsigned long private ATTRIBUTE_UNUSED)
{
int rate_always, channels_always, format_always;
int rate_never, channels_never, format_never;
unsigned int links = (SND_PCM_HW_PARBIT_PERIOD_TIME |
SND_PCM_HW_PARBIT_TICK_TIME);
const mask_t *format_mask, *sformat_mask;
mask_t *fmt_mask = alloca(mask_sizeof());
mask_t *sfmt_mask = alloca(mask_sizeof());
mask_t *access_mask = alloca(mask_sizeof());
int err;
unsigned int format;
unsigned int scmask = sparams->cmask;
snd_pcm_hw_param_near_copy(slave, sparams, SND_PCM_HW_PARAM_RATE,
params);
scmask |= sparams->cmask;
snd_pcm_hw_param_near_copy(slave, sparams, SND_PCM_HW_PARAM_CHANNELS,
params);
scmask |= sparams->cmask;
format_mask = snd_pcm_hw_param_value_mask(params,
SND_PCM_HW_PARAM_FORMAT);
sformat_mask = snd_pcm_hw_param_value_mask(sparams,
SND_PCM_HW_PARAM_FORMAT);
mask_none(sfmt_mask);
mask_none(fmt_mask);
for (format = 0; format <= SND_PCM_FORMAT_LAST; format++) {
int f;
if (!mask_test(format_mask, format))
continue;
if (mask_test(sformat_mask, format))
f = format;
else {
f = snd_pcm_plug_slave_format(format, sformat_mask);
if (f < 0)
continue;
}
mask_set(sfmt_mask, f);
mask_set(fmt_mask, format);
}
err = _snd_pcm_hw_param_mask(params,
SND_PCM_HW_PARAM_FORMAT, fmt_mask);
if (err < 0)
return err;
err = _snd_pcm_hw_param_mask(sparams,
SND_PCM_HW_PARAM_FORMAT, sfmt_mask);
assert(err >= 0);
format_always = snd_pcm_hw_param_always_eq(params,
SND_PCM_HW_PARAM_FORMAT,
sparams);
format_never = (!format_always &&
snd_pcm_hw_param_never_eq(params,
SND_PCM_HW_PARAM_FORMAT,
sparams));
channels_always = snd_pcm_hw_param_always_eq(params,
SND_PCM_HW_PARAM_CHANNELS,
sparams);
channels_never = (!channels_always &&
snd_pcm_hw_param_never_eq(params,
SND_PCM_HW_PARAM_CHANNELS,
sparams));
rate_always = snd_pcm_hw_param_always_eq(params,
SND_PCM_HW_PARAM_RATE,
sparams);
rate_never = (!rate_always &&
snd_pcm_hw_param_never_eq(params,
SND_PCM_HW_PARAM_RATE,
sparams));
if (rate_always)
links |= (SND_PCM_HW_PARBIT_RATE |
SND_PCM_HW_PARBIT_PERIOD_SIZE |
SND_PCM_HW_PARBIT_PERIODS |
SND_PCM_HW_PARBIT_BUFFER_TIME |
SND_PCM_HW_PARBIT_BUFFER_SIZE);
else {
interval_t t;
const interval_t *sbuffer_size, *buffer_size;
const interval_t *srate, *rate;
buffer_size = snd_pcm_hw_param_value_interval(params, SND_PCM_HW_PARAM_BUFFER_SIZE);
sbuffer_size = snd_pcm_hw_param_value_interval(sparams, SND_PCM_HW_PARAM_BUFFER_SIZE);
rate = snd_pcm_hw_param_value_interval(params, SND_PCM_HW_PARAM_RATE);
srate = snd_pcm_hw_param_value_interval(sparams, SND_PCM_HW_PARAM_RATE);
interval_muldiv(sbuffer_size, rate, srate, &t);
interval_round(&t);
err = _snd_pcm_hw_param_refine_interval(params, SND_PCM_HW_PARAM_BUFFER_SIZE, &t);
if (err < 0)
return err;
interval_muldiv(buffer_size, srate, rate, &t);
interval_round(&t);
err = _snd_pcm_hw_param_refine_interval(sparams, SND_PCM_HW_PARAM_BUFFER_SIZE, &t);
assert(err >= 0);
scmask |= sparams->cmask;
}
if (channels_always)
links |= SND_PCM_HW_PARBIT_CHANNELS;
if (format_always) {
links |= (SND_PCM_HW_PARBIT_FORMAT |
SND_PCM_HW_PARBIT_SUBFORMAT |
SND_PCM_HW_PARBIT_SAMPLE_BITS);
if (channels_always) {
links |= SND_PCM_HW_PARBIT_FRAME_BITS;
if (rate_always)
links |= (SND_PCM_HW_PARBIT_PERIOD_BYTES |
SND_PCM_HW_PARBIT_BUFFER_BYTES);
}
}
mask_load(access_mask, SND_PCM_ACCBIT_PLUGIN);
if (format_never || channels_never || rate_never) {
mask_t *mmap_mask = alloca(mask_sizeof());
mask_load(mmap_mask, SND_PCM_ACCBIT_MMAP);
err = _snd_pcm_hw_param_mask(sparams, SND_PCM_HW_PARAM_ACCESS,
mmap_mask);
assert(err >= 0);
} else
mask_union(access_mask, snd_pcm_hw_param_value_mask(sparams, SND_PCM_HW_PARAM_ACCESS));
err = _snd_pcm_hw_param_mask(params, SND_PCM_HW_PARAM_ACCESS,
access_mask);
if (err < 0)
return err;
sparams->cmask |= scmask;
return snd_pcm_generic_hw_link(params, sparams, slave, links);
}
static int snd_pcm_plug_hw_refine1(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
snd_pcm_hw_params_t *sparams)
{
snd_pcm_plug_t *plug = pcm->private;
snd_pcm_t *slave = plug->req_slave;
unsigned int cmask, lcmask;
int err;
cmask = params->cmask;
params->cmask = 0;
err = _snd_pcm_hw_param_min(params, SND_PCM_HW_PARAM_CHANNELS, 1, 0);
if (err < 0)
return err;
err = _snd_pcm_hw_param_max(params, SND_PCM_HW_PARAM_CHANNELS, 1024, 0);
if (err < 0)
return err;
err = _snd_pcm_hw_param_min(params, SND_PCM_HW_PARAM_RATE, RATE_MIN, 0);
if (err < 0)
return err;
err = _snd_pcm_hw_param_max(params, SND_PCM_HW_PARAM_RATE, RATE_MAX, 0);
if (err < 0)
return err;
lcmask = params->cmask;
params->cmask |= cmask;
_snd_pcm_hw_params_any(sparams);
err = snd_pcm_hw_refine2(params, sparams,
snd_pcm_plug_hw_link, slave, 0);
params->cmask |= lcmask;
if (err < 0)
return err;
params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
return 0;
}
static int snd_pcm_plug_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
{
snd_pcm_hw_params_t sparams;
return snd_pcm_plug_hw_refine1(pcm, params, &sparams);
}
static void snd_pcm_plug_clear(snd_pcm_t *pcm)
{
snd_pcm_plug_t *plug = pcm->private;
@ -580,13 +404,164 @@ static int snd_pcm_plug_insert_plugins(snd_pcm_t *pcm,
return 0;
}
static int snd_pcm_plug_hw_refine_cprepare(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params ATTRIBUTE_UNUSED)
{
return 0;
}
static int snd_pcm_plug_hw_refine_sprepare(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *sparams)
{
snd_pcm_plug_t *plug = pcm->private;
snd_pcm_t *slave = plug->req_slave;
return snd_pcm_hw_params_any(slave, sparams);
}
static int snd_pcm_plug_hw_refine_schange(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
snd_pcm_hw_params_t *sparams)
{
snd_pcm_plug_t *plug = pcm->private;
snd_pcm_t *slave = plug->req_slave;
unsigned int links = (SND_PCM_HW_PARBIT_PERIOD_TIME |
SND_PCM_HW_PARBIT_TICK_TIME);
const mask_t *format_mask, *sformat_mask;
mask_t *sfmt_mask = alloca(mask_sizeof());
int err;
unsigned int format;
interval_t t;
const interval_t *buffer_size;
const interval_t *srate, *crate;
err = _snd_pcm_hw_params_refine(sparams, links, params);
if (err < 0)
return err;
snd_pcm_hw_param_refine_near(slave, sparams, SND_PCM_HW_PARAM_RATE,
params);
snd_pcm_hw_param_refine_near(slave, sparams, SND_PCM_HW_PARAM_CHANNELS,
params);
format_mask = snd_pcm_hw_param_value_mask(params,
SND_PCM_HW_PARAM_FORMAT);
sformat_mask = snd_pcm_hw_param_value_mask(sparams,
SND_PCM_HW_PARAM_FORMAT);
mask_none(sfmt_mask);
for (format = 0; format <= SND_PCM_FORMAT_LAST; format++) {
int f;
if (!mask_test(format_mask, format))
continue;
if (mask_test(sformat_mask, format))
f = format;
else {
f = snd_pcm_plug_slave_format(format, sformat_mask);
if (f < 0)
continue;
}
mask_set(sfmt_mask, f);
}
err = snd_pcm_hw_param_mask(slave, sparams,
SND_PCM_HW_PARAM_FORMAT, sfmt_mask);
assert(err >= 0);
if (snd_pcm_hw_param_never_eq(params, SND_PCM_HW_PARAM_FORMAT, sparams) ||
snd_pcm_hw_param_never_eq(params, SND_PCM_HW_PARAM_CHANNELS, sparams) ||
snd_pcm_hw_param_never_eq(params, SND_PCM_HW_PARAM_RATE, sparams) ||
snd_pcm_hw_param_never_eq(params, SND_PCM_HW_PARAM_ACCESS, sparams)) {
mask_t *access_mask = alloca(mask_sizeof());
mask_load(access_mask, SND_PCM_ACCBIT_MMAP);
_snd_pcm_hw_param_mask(sparams, SND_PCM_HW_PARAM_ACCESS,
access_mask);
}
buffer_size = snd_pcm_hw_param_value_interval(params, SND_PCM_HW_PARAM_BUFFER_SIZE);
crate = snd_pcm_hw_param_value_interval(params, SND_PCM_HW_PARAM_RATE);
srate = snd_pcm_hw_param_value_interval(sparams, SND_PCM_HW_PARAM_RATE);
interval_muldiv(buffer_size, srate, crate, &t);
interval_round(&t);
err = _snd_pcm_hw_param_refine_interval(sparams, SND_PCM_HW_PARAM_BUFFER_SIZE, &t);
if (err < 0)
return err;
return 0;
}
static int snd_pcm_plug_hw_refine_cchange(snd_pcm_t *pcm ATTRIBUTE_UNUSED,
snd_pcm_hw_params_t *params,
snd_pcm_hw_params_t *sparams)
{
unsigned int links = (SND_PCM_HW_PARBIT_PERIOD_TIME |
SND_PCM_HW_PARBIT_TICK_TIME);
const mask_t *format_mask, *sformat_mask;
mask_t *fmt_mask = alloca(mask_sizeof());
int err;
unsigned int format;
interval_t t;
const interval_t *sbuffer_size;
const interval_t *srate, *crate;
format_mask = snd_pcm_hw_param_value_mask(params,
SND_PCM_HW_PARAM_FORMAT);
sformat_mask = snd_pcm_hw_param_value_mask(sparams,
SND_PCM_HW_PARAM_FORMAT);
mask_none(fmt_mask);
for (format = 0; format <= SND_PCM_FORMAT_LAST; format++) {
int f;
if (!mask_test(format_mask, format))
continue;
if (mask_test(sformat_mask, format))
f = format;
else {
f = snd_pcm_plug_slave_format(format, sformat_mask);
if (f < 0)
continue;
}
mask_set(fmt_mask, format);
}
err = _snd_pcm_hw_param_mask(params,
SND_PCM_HW_PARAM_FORMAT, fmt_mask);
if (err < 0)
return err;
sbuffer_size = snd_pcm_hw_param_value_interval(sparams, SND_PCM_HW_PARAM_BUFFER_SIZE);
crate = snd_pcm_hw_param_value_interval(params, SND_PCM_HW_PARAM_RATE);
srate = snd_pcm_hw_param_value_interval(sparams, SND_PCM_HW_PARAM_RATE);
interval_muldiv(sbuffer_size, crate, srate, &t);
interval_round(&t);
err = _snd_pcm_hw_param_refine_interval(params, SND_PCM_HW_PARAM_BUFFER_SIZE, &t);
if (err < 0)
return err;
err = _snd_pcm_hw_params_refine(params, links, sparams);
if (err < 0)
return err;
/* FIXME */
params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
return 0;
}
static int snd_pcm_plug_hw_refine_slave(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
{
snd_pcm_plug_t *plug = pcm->private;
return snd_pcm_hw_refine(plug->req_slave, params);
}
static int snd_pcm_plug_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
{
return snd_pcm_hw_refine_slave(pcm, params,
snd_pcm_plug_hw_refine_cprepare,
snd_pcm_plug_hw_refine_cchange,
snd_pcm_plug_hw_refine_sprepare,
snd_pcm_plug_hw_refine_schange,
snd_pcm_plug_hw_refine_slave);
}
static int snd_pcm_plug_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
{
snd_pcm_plug_t *plug = pcm->private;
snd_pcm_t *slave = plug->req_slave;
snd_pcm_plug_params_t clt_params, slv_params;
snd_pcm_hw_params_t sparams;
int err = snd_pcm_plug_hw_refine1(pcm, params, &sparams);
int err;
err = snd_pcm_plug_hw_refine_sprepare(pcm, &sparams);
assert(err >= 0);
err = snd_pcm_plug_hw_refine_schange(pcm, params, &sparams);
assert(err >= 0);
err = snd_pcm_hw_refine_soft(slave, &sparams);
assert(err >= 0);
clt_params.access = snd_pcm_hw_param_value(params, SND_PCM_HW_PARAM_ACCESS, 0);
@ -594,21 +569,14 @@ static int snd_pcm_plug_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
clt_params.channels = snd_pcm_hw_param_value(params, SND_PCM_HW_PARAM_CHANNELS, 0);
clt_params.rate = snd_pcm_hw_param_value(params, SND_PCM_HW_PARAM_RATE, 0);
slv_params.access = snd_pcm_hw_param_first(slave, &sparams, SND_PCM_HW_PARAM_ACCESS, 0);
slv_params.format = snd_pcm_hw_param_value(&sparams, SND_PCM_HW_PARAM_FORMAT, 0);
slv_params.channels = snd_pcm_hw_param_value(&sparams, SND_PCM_HW_PARAM_CHANNELS, 0);
slv_params.rate = snd_pcm_hw_param_value(&sparams, SND_PCM_HW_PARAM_RATE, 0);
snd_pcm_plug_clear(pcm);
if (clt_params.format == slv_params.format &&
clt_params.channels == slv_params.channels &&
clt_params.rate == slv_params.rate &&
snd_pcm_hw_param_test(params, SND_PCM_HW_PARAM_ACCESS, clt_params.access))
slv_params.access = clt_params.access;
else {
slv_params.access = snd_pcm_hw_param_first(slave, &sparams, SND_PCM_HW_PARAM_ACCESS, 0);
err = snd_pcm_plug_insert_plugins(pcm, &clt_params, &slv_params);
if (err < 0)
return err;
}
err = snd_pcm_plug_insert_plugins(pcm, &clt_params, &slv_params);
if (err < 0)
return err;
err = snd_pcm_hw_params(plug->slave, params);
if (err < 0) {
snd_pcm_plug_clear(pcm);

View file

@ -340,6 +340,18 @@ int snd_pcm_plugin_poll_descriptor(snd_pcm_t *pcm)
return snd_pcm_poll_descriptor(plugin->slave);
}
int snd_pcm_plugin_hw_refine_slave(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
{
snd_pcm_plugin_t *plugin = pcm->private;
return snd_pcm_hw_refine(plugin->slave, params);
}
int snd_pcm_plugin_hw_params_slave(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
{
snd_pcm_plugin_t *plugin = pcm->private;
return snd_pcm_hw_params(plugin->slave, params);
}
int conv_index(int src_format, int dst_format)
{
int src_endian, dst_endian, sign, src_width, dst_width;

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 put_index(int src_format, int dst_format);
int conv_index(int src_format, int dst_format);
int snd_pcm_plugin_hw_params_slave(snd_pcm_t *pcm, snd_pcm_hw_params_t *params);
int snd_pcm_plugin_hw_refine_slave(snd_pcm_t *pcm, snd_pcm_hw_params_t *params);
#define SND_PCM_FMTBIT_LINEAR \
((1 << SND_PCM_FORMAT_S8 ) | (1 << SND_PCM_FORMAT_U8) | \

View file

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

View file

@ -425,80 +425,58 @@ static int snd_pcm_route_close(snd_pcm_t *pcm)
return 0;
}
static int snd_pcm_route_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
static int snd_pcm_route_hw_refine_cprepare(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params)
{
snd_pcm_route_t *route = pcm->private;
snd_pcm_t *slave = route->plug.slave;
int err;
unsigned int cmask, lcmask;
snd_pcm_hw_params_t sparams;
unsigned int links = (SND_PCM_HW_PARBIT_RATE |
SND_PCM_HW_PARBIT_PERIODS |
SND_PCM_HW_PARBIT_PERIOD_SIZE |
SND_PCM_HW_PARBIT_PERIOD_TIME |
SND_PCM_HW_PARBIT_BUFFER_SIZE |
SND_PCM_HW_PARBIT_BUFFER_TIME |
SND_PCM_HW_PARBIT_TICK_TIME);
mask_t *access_mask = alloca(mask_sizeof());
mask_t *format_mask = alloca(mask_sizeof());
mask_t *saccess_mask = alloca(mask_sizeof());
mask_load(access_mask, SND_PCM_ACCBIT_PLUGIN);
mask_load(format_mask, SND_PCM_FMTBIT_LINEAR);
mask_load(saccess_mask, SND_PCM_ACCBIT_MMAP);
cmask = params->cmask;
params->cmask = 0;
err = _snd_pcm_hw_param_mask(params, SND_PCM_HW_PARAM_ACCESS,
access_mask);
access_mask);
if (err < 0)
return err;
err = _snd_pcm_hw_param_mask(params, SND_PCM_HW_PARAM_FORMAT,
format_mask);
format_mask);
if (err < 0)
return err;
err = _snd_pcm_hw_param_set(params, SND_PCM_HW_PARAM_SUBFORMAT,
SND_PCM_SUBFORMAT_STD, 0);
if (err < 0)
return err;
err = _snd_pcm_hw_param_min(params, SND_PCM_HW_PARAM_CHANNELS, 1, 0);
if (err < 0)
return err;
lcmask = params->cmask;
params->cmask |= cmask;
_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)
return err;
params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
return 0;
}
static int snd_pcm_route_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params)
static int snd_pcm_route_hw_refine_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_t *slave = route->plug.slave;
int err;
snd_pcm_hw_params_t sparams;
unsigned int links = (SND_PCM_HW_PARBIT_RATE |
SND_PCM_HW_PARBIT_PERIODS |
SND_PCM_HW_PARBIT_PERIOD_SIZE |
@ -506,42 +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_TIME |
SND_PCM_HW_PARBIT_TICK_TIME);
unsigned int src_format, dst_format;
mask_t *saccess_mask = alloca(mask_sizeof());
mask_load(saccess_mask, SND_PCM_ACCBIT_MMAP);
_snd_pcm_hw_params_any(&sparams);
_snd_pcm_hw_param_mask(&sparams, SND_PCM_HW_PARAM_ACCESS,
saccess_mask);
if (route->sformat >= 0) {
_snd_pcm_hw_param_set(&sparams, SND_PCM_HW_PARAM_FORMAT,
route->sformat, 0);
_snd_pcm_hw_param_set(&sparams, SND_PCM_HW_PARAM_SUBFORMAT,
SND_PCM_SUBFORMAT_STD, 0);
} else
if (route->sformat < 0)
links |= (SND_PCM_HW_PARBIT_FORMAT |
SND_PCM_HW_PARBIT_SUBFORMAT |
SND_PCM_HW_PARBIT_SAMPLE_BITS);
if (route->schannels >= 0) {
_snd_pcm_hw_param_set(&sparams, SND_PCM_HW_PARAM_CHANNELS,
route->schannels, 0);
} else {
if (route->schannels < 0)
links |= SND_PCM_HW_PARBIT_CHANNELS;
if (route->sformat < 0)
links |= (SND_PCM_HW_PARBIT_FRAME_BITS |
SND_PCM_HW_PARBIT_PERIOD_BYTES |
SND_PCM_HW_PARBIT_BUFFER_BYTES);
}
err = snd_pcm_hw_params_refine(&sparams, links, params);
assert(err >= 0);
err = snd_pcm_hw_params(slave, &sparams);
params->cmask = 0;
sparams.cmask = ~0U;
snd_pcm_hw_params_refine(params, links, &sparams);
err = _snd_pcm_hw_params_refine(sparams, links, params);
if (err < 0)
return err;
params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
return 0;
}
static int snd_pcm_route_hw_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) {
src_format = snd_pcm_hw_param_value(params, SND_PCM_HW_PARAM_FORMAT, 0);
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)
{
return -ENOENT; /* not available */
snd_pcm_share_t *share = pcm->private;
return snd_pcm_card(share->slave->pcm);
}
static int snd_pcm_share_nonblock(snd_pcm_t *pcm ATTRIBUTE_UNUSED, int nonblock ATTRIBUTE_UNUSED)
@ -455,25 +456,22 @@ static int snd_pcm_share_info(snd_pcm_t *pcm, snd_pcm_info_t *info)
return snd_pcm_info(share->slave->pcm, info);
}
static int snd_pcm_share_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
static int snd_pcm_share_hw_refine_cprepare(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
{
snd_pcm_share_t *share = pcm->private;
snd_pcm_share_slave_t *slave = share->slave;
snd_pcm_hw_params_t sparams;
int err;
unsigned int cmask, lcmask;
mask_t *access_mask = alloca(mask_sizeof());
const mask_t *mmap_mask;
mask_t *saccess_mask = alloca(mask_sizeof());
mask_load(saccess_mask, SND_PCM_ACCBIT_MMAP);
cmask = params->cmask;
params->cmask = 0;
int err;
mask_any(access_mask);
mask_reset(access_mask, SND_PCM_ACCESS_MMAP_INTERLEAVED);
err = _snd_pcm_hw_param_mask(params, SND_PCM_HW_PARAM_ACCESS,
access_mask);
if (err < 0)
return err;
err = _snd_pcm_hw_param_set(params, SND_PCM_HW_PARAM_CHANNELS,
share->channels_count, 0);
if (err < 0)
return err;
if (slave->format >= 0) {
err = _snd_pcm_hw_param_set(params, SND_PCM_HW_PARAM_FORMAT,
slave->format, 0);
@ -487,44 +485,109 @@ static int snd_pcm_share_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
if (err < 0)
return err;
}
lcmask = params->cmask;
params->cmask |= cmask;
_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;
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)
{
snd_pcm_share_t *share = pcm->private;
@ -534,7 +597,6 @@ static int snd_pcm_share_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
Pthread_mutex_lock(&slave->mutex);
if (slave->setup_count > 1 ||
(slave->setup_count == 1 && !pcm->setup)) {
params->cmask = 0;
err = _snd_pcm_hw_param_set(params, SND_PCM_HW_PARAM_FORMAT,
spcm->format, 0);
if (err < 0)
@ -564,30 +626,11 @@ static int snd_pcm_share_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
goto _end;
}
} else {
snd_pcm_hw_params_t sparams;
unsigned int links;
mask_t *saccess_mask = alloca(mask_sizeof());
mask_load(saccess_mask, SND_PCM_ACCBIT_MMAP);
links = SND_PCM_HW_PARBIT_FORMAT |
SND_PCM_HW_PARBIT_SUBFORMAT |
SND_PCM_HW_PARBIT_RATE |
SND_PCM_HW_PARBIT_PERIOD_SIZE |
SND_PCM_HW_PARBIT_PERIOD_TIME |
SND_PCM_HW_PARBIT_BUFFER_SIZE |
SND_PCM_HW_PARBIT_BUFFER_TIME |
SND_PCM_HW_PARBIT_PERIODS |
SND_PCM_HW_PARBIT_TICK_TIME;
_snd_pcm_hw_params_any(&sparams);
_snd_pcm_hw_param_mask(&sparams, SND_PCM_HW_PARAM_ACCESS,
saccess_mask);
_snd_pcm_hw_param_set(&sparams, SND_PCM_HW_PARAM_CHANNELS,
share->channels_count, 0);
err = snd_pcm_hw_params_refine(&sparams, links, params);
assert(err >= 0);
err = snd_pcm_hw_params(slave->pcm, &sparams);
params->cmask = 0;
sparams.cmask = ~0U;
snd_pcm_hw_params_refine(params, links, &sparams);
err = snd_pcm_hw_params_slave(pcm, params,
snd_pcm_share_hw_refine_cchange,
snd_pcm_share_hw_refine_sprepare,
snd_pcm_share_hw_refine_schange,
snd_pcm_share_hw_params_slave);
if (err < 0)
goto _end;
snd_pcm_sw_params_current(slave->pcm, &slave->sw_params);

View file

@ -155,8 +155,61 @@ static int snd_pcm_shm_info(snd_pcm_t *pcm, snd_pcm_info_t * info)
return err;
}
static int _snd_pcm_shm_hw_refine(snd_pcm_t *pcm,
snd_pcm_hw_params_t *params)
static int snd_pcm_shm_hw_refine_cprepare(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params ATTRIBUTE_UNUSED)
{
return 0;
}
static int snd_pcm_shm_hw_refine_sprepare(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *sparams)
{
mask_t *saccess_mask = alloca(mask_sizeof());
mask_load(saccess_mask, SND_PCM_ACCBIT_MMAP);
_snd_pcm_hw_params_any(sparams);
_snd_pcm_hw_param_mask(sparams, SND_PCM_HW_PARAM_ACCESS,
saccess_mask);
return 0;
}
static int snd_pcm_shm_hw_refine_schange(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params,
snd_pcm_hw_params_t *sparams)
{
int err;
unsigned int links = ~SND_PCM_HW_PARBIT_ACCESS;
const mask_t *access_mask = snd_pcm_hw_param_value_mask(params, SND_PCM_HW_PARAM_ACCESS);
if (!mask_test(access_mask, SND_PCM_ACCESS_RW_INTERLEAVED) &&
!mask_test(access_mask, SND_PCM_ACCESS_RW_NONINTERLEAVED)) {
err = _snd_pcm_hw_param_mask(sparams, SND_PCM_HW_PARAM_ACCESS,
access_mask);
if (err < 0)
return err;
}
err = _snd_pcm_hw_params_refine(sparams, links, params);
if (err < 0)
return err;
return 0;
}
static int snd_pcm_shm_hw_refine_cchange(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params,
snd_pcm_hw_params_t *sparams)
{
int err;
unsigned int links = ~SND_PCM_HW_PARBIT_ACCESS;
mask_t *access_mask = alloca(mask_sizeof());
mask_copy(access_mask, snd_pcm_hw_param_value_mask(sparams, SND_PCM_HW_PARAM_ACCESS));
mask_set(access_mask, SND_PCM_ACCESS_RW_INTERLEAVED);
mask_set(access_mask, SND_PCM_ACCESS_RW_NONINTERLEAVED);
err = _snd_pcm_hw_param_mask(sparams, SND_PCM_HW_PARAM_ACCESS,
access_mask);
if (err < 0)
return err;
err = _snd_pcm_hw_params_refine(params, links, sparams);
if (err < 0)
return err;
return 0;
}
static int snd_pcm_shm_hw_refine_slave(snd_pcm_t *pcm,
snd_pcm_hw_params_t *params)
{
snd_pcm_shm_t *shm = pcm->private;
volatile snd_pcm_shm_ctrl_t *ctrl = shm->ctrl;
@ -168,46 +221,18 @@ static int _snd_pcm_shm_hw_refine(snd_pcm_t *pcm,
return err;
}
/* Accumulate to params->cmask */
/* Reset sparams->cmask */
int snd_pcm_shm_hw_link(snd_pcm_hw_params_t *params,
snd_pcm_hw_params_t *sparams,
snd_pcm_t *slave,
unsigned long links)
{
int err1, err = 0;
err = snd_pcm_hw_params_refine(sparams, links, params);
if (err >= 0) {
unsigned int cmask = sparams->cmask;
err = _snd_pcm_shm_hw_refine(slave, sparams);
sparams->cmask |= cmask;
}
err1 = snd_pcm_hw_params_refine(params, links, sparams);
if (err1 < 0)
err = err1;
sparams->cmask = 0;
return err;
}
static int snd_pcm_shm_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
{
snd_pcm_hw_params_t sparams;
const mask_t *access_mask = snd_pcm_hw_param_value_mask(params, SND_PCM_HW_PARAM_ACCESS);
mask_t *saccess_mask = alloca(mask_sizeof());
mask_load(saccess_mask, SND_PCM_ACCBIT_MMAP);
if (!mask_test(access_mask, SND_PCM_ACCESS_RW_INTERLEAVED) &&
!mask_test(access_mask, SND_PCM_ACCESS_RW_NONINTERLEAVED))
mask_intersect(saccess_mask, access_mask);
_snd_pcm_hw_params_any(&sparams);
_snd_pcm_hw_param_mask(&sparams, SND_PCM_HW_PARAM_ACCESS,
saccess_mask);
return snd_pcm_hw_refine2(params, &sparams,
snd_pcm_shm_hw_link, pcm,
~SND_PCM_HW_PARBIT_ACCESS);
return snd_pcm_hw_refine_slave(pcm, params,
snd_pcm_shm_hw_refine_cprepare,
snd_pcm_shm_hw_refine_cchange,
snd_pcm_shm_hw_refine_sprepare,
snd_pcm_shm_hw_refine_schange,
snd_pcm_shm_hw_refine_slave);
}
static int _snd_pcm_shm_hw_params(snd_pcm_t *pcm,
snd_pcm_hw_params_t *params)
static int snd_pcm_shm_hw_params_slave(snd_pcm_t *pcm,
snd_pcm_hw_params_t *params)
{
snd_pcm_shm_t *shm = pcm->private;
volatile snd_pcm_shm_ctrl_t *ctrl = shm->ctrl;
@ -221,27 +246,11 @@ static int _snd_pcm_shm_hw_params(snd_pcm_t *pcm,
static int snd_pcm_shm_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params)
{
snd_pcm_hw_params_t sparams;
unsigned int links = ~SND_PCM_HW_PARBIT_ACCESS;
const mask_t *access_mask = snd_pcm_hw_param_value_mask(params, SND_PCM_HW_PARAM_ACCESS);
mask_t *saccess_mask = alloca(mask_sizeof());
int err;
mask_load(saccess_mask, SND_PCM_ACCBIT_MMAP);
if (!mask_test(access_mask, SND_PCM_ACCESS_RW_INTERLEAVED) &&
!mask_test(access_mask, SND_PCM_ACCESS_RW_NONINTERLEAVED))
mask_intersect(saccess_mask, access_mask);
_snd_pcm_hw_params_any(&sparams);
_snd_pcm_hw_param_mask(&sparams, SND_PCM_HW_PARAM_ACCESS,
saccess_mask);
err = snd_pcm_hw_params_refine(&sparams, links, params);
assert(err >= 0);
err = _snd_pcm_shm_hw_params(pcm, &sparams);
params->cmask = 0;
sparams.cmask = ~0U;
snd_pcm_hw_params_refine(params, links, &sparams);
if (err < 0)
return err;
return 0;
return snd_pcm_hw_params_slave(pcm, params,
snd_pcm_shm_hw_refine_cchange,
snd_pcm_shm_hw_refine_sprepare,
snd_pcm_shm_hw_refine_schange,
snd_pcm_shm_hw_params_slave);
}
static int snd_pcm_shm_sw_params(snd_pcm_t *pcm, snd_pcm_sw_params_t * params)