mirror of
https://github.com/alsa-project/alsa-lib.git
synced 2025-12-20 08:56:54 -05:00
Fixed pcm_plug race condition
This commit is contained in:
parent
5c84940c1f
commit
c6f6c231c0
4 changed files with 73 additions and 52 deletions
|
|
@ -381,3 +381,57 @@ void interval_print(const interval_t *i, snd_output_t *out)
|
||||||
i->min, i->max,
|
i->min, i->max,
|
||||||
i->openmax ? ')' : ']');
|
i->openmax ? ')' : ']');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void boundary_abs(int a, int adir, int *b, int *bdir)
|
||||||
|
{
|
||||||
|
if (a < 0 || (a == 0 && adir < 0)) {
|
||||||
|
*b = -a;
|
||||||
|
*bdir = -adir;
|
||||||
|
} else {
|
||||||
|
*b = a;
|
||||||
|
*bdir = adir;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void boundary_sub(int a, int adir, int b, int bdir, int *c, int *cdir)
|
||||||
|
{
|
||||||
|
adir = adir < 0 ? -1 : (adir > 0 ? 1 : 0);
|
||||||
|
bdir = bdir < 0 ? -1 : (bdir > 0 ? 1 : 0);
|
||||||
|
*c = a - b;
|
||||||
|
*cdir = adir - bdir;
|
||||||
|
if (*cdir == -2) {
|
||||||
|
assert(*c > INT_MIN);
|
||||||
|
(*c)--;
|
||||||
|
} else if (*cdir == 2) {
|
||||||
|
assert(*c < INT_MAX);
|
||||||
|
(*c)++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int boundary_lt(unsigned int a, int adir, unsigned int b, int bdir)
|
||||||
|
{
|
||||||
|
assert(a > 0 || adir >= 0);
|
||||||
|
assert(b > 0 || bdir >= 0);
|
||||||
|
if (adir < 0) {
|
||||||
|
a--;
|
||||||
|
adir = 1;
|
||||||
|
} else if (adir > 0)
|
||||||
|
adir = 1;
|
||||||
|
if (bdir < 0) {
|
||||||
|
b--;
|
||||||
|
bdir = 1;
|
||||||
|
} else if (bdir > 0)
|
||||||
|
bdir = 1;
|
||||||
|
return a < b || (a == b && adir < bdir);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return 1 if min is nearer to best than max */
|
||||||
|
int boundary_nearer(int min, int mindir, int best, int bestdir, int max, int maxdir)
|
||||||
|
{
|
||||||
|
int dmin, dmindir;
|
||||||
|
int dmax, dmaxdir;
|
||||||
|
boundary_sub(best, bestdir, min, mindir, &dmin, &dmindir);
|
||||||
|
boundary_sub(max, maxdir, best, bestdir, &dmax, &dmaxdir);
|
||||||
|
return boundary_lt(dmin, dmindir, dmax, dmaxdir);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -57,3 +57,6 @@ int interval_refine(interval_t *i, const interval_t *v);
|
||||||
int interval_refine_first(interval_t *i);
|
int interval_refine_first(interval_t *i);
|
||||||
int interval_refine_last(interval_t *i);
|
int interval_refine_last(interval_t *i);
|
||||||
int interval_refine_set(interval_t *i, unsigned int val);
|
int interval_refine_set(interval_t *i, unsigned int val);
|
||||||
|
void boundary_sub(int a, int adir, int b, int bdir, int *c, int *cdir);
|
||||||
|
int boundary_lt(unsigned int a, int adir, unsigned int b, int bdir);
|
||||||
|
int boundary_nearer(int min, int mindir, int best, int bestdir, int max, int maxdir);
|
||||||
|
|
|
||||||
|
|
@ -25,53 +25,6 @@
|
||||||
#include "interval.h"
|
#include "interval.h"
|
||||||
#include "mask.h"
|
#include "mask.h"
|
||||||
|
|
||||||
static void approx_sub(int a, int adir,
|
|
||||||
int b, int bdir,
|
|
||||||
int *c, int *cdir)
|
|
||||||
{
|
|
||||||
adir = adir < 0 ? -1 : (adir > 0 ? 1 : 0);
|
|
||||||
bdir = bdir < 0 ? -1 : (bdir > 0 ? 1 : 0);
|
|
||||||
*c = a - b;
|
|
||||||
*cdir = adir - bdir;
|
|
||||||
if (*cdir == -2) {
|
|
||||||
assert(*c > INT_MIN);
|
|
||||||
(*c)--;
|
|
||||||
} else if (*cdir == 2) {
|
|
||||||
assert(*c < INT_MAX);
|
|
||||||
(*c)++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static int approx_lt(unsigned int a, int adir,
|
|
||||||
unsigned int b, int bdir)
|
|
||||||
{
|
|
||||||
assert(a > 0 || adir >= 0);
|
|
||||||
assert(b > 0 || bdir >= 0);
|
|
||||||
if (adir < 0) {
|
|
||||||
a--;
|
|
||||||
adir = 1;
|
|
||||||
} else if (adir > 0)
|
|
||||||
adir = 1;
|
|
||||||
if (bdir < 0) {
|
|
||||||
b--;
|
|
||||||
bdir = 1;
|
|
||||||
} else if (bdir > 0)
|
|
||||||
bdir = 1;
|
|
||||||
return a < b || (a == b && adir < bdir);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Return 1 if min is nearer to best than max */
|
|
||||||
static int approx_nearer(int min, int mindir,
|
|
||||||
int best, int bestdir,
|
|
||||||
int max, int maxdir)
|
|
||||||
{
|
|
||||||
int dmin, dmindir;
|
|
||||||
int dmax, dmaxdir;
|
|
||||||
approx_sub(best, bestdir, min, mindir, &dmin, &dmindir);
|
|
||||||
approx_sub(max, maxdir, best, bestdir, &dmax, &dmaxdir);
|
|
||||||
return approx_lt(dmin, dmindir, dmax, dmaxdir);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int hw_is_mask(int var)
|
static inline int hw_is_mask(int var)
|
||||||
{
|
{
|
||||||
return var >= SND_PCM_HW_PARAM_FIRST_MASK &&
|
return var >= SND_PCM_HW_PARAM_FIRST_MASK &&
|
||||||
|
|
@ -771,7 +724,7 @@ int snd_pcm_hw_param_near(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
|
||||||
max = snd_pcm_hw_param_max(pcm, ¶ms1, var, max, &maxdir);
|
max = snd_pcm_hw_param_max(pcm, ¶ms1, var, max, &maxdir);
|
||||||
if (max < 0)
|
if (max < 0)
|
||||||
goto _end;
|
goto _end;
|
||||||
if (approx_nearer(max, maxdir, best, valdir, min, mindir)) {
|
if (boundary_nearer(max, maxdir, best, valdir, min, mindir)) {
|
||||||
*params = params1;
|
*params = params1;
|
||||||
last = 1;
|
last = 1;
|
||||||
}
|
}
|
||||||
|
|
@ -813,7 +766,7 @@ int snd_pcm_hw_param_next(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
|
||||||
/* FIXME */
|
/* FIXME */
|
||||||
if (best > INT_MAX)
|
if (best > INT_MAX)
|
||||||
best = INT_MAX;
|
best = INT_MAX;
|
||||||
approx_sub(val, valdir, best, bestdir, &diff, &diffdir);
|
boundary_sub(val, valdir, best, bestdir, &diff, &diffdir);
|
||||||
if (diff < 0 || (diff == 0 && diffdir < 0)) {
|
if (diff < 0 || (diff == 0 && diffdir < 0)) {
|
||||||
min = best - diff;
|
min = best - diff;
|
||||||
mindir = bestdir - diffdir;
|
mindir = bestdir - diffdir;
|
||||||
|
|
@ -839,7 +792,7 @@ int snd_pcm_hw_param_next(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
|
||||||
max = snd_pcm_hw_param_max(pcm, ¶ms1, var, max, &maxdir);
|
max = snd_pcm_hw_param_max(pcm, ¶ms1, var, max, &maxdir);
|
||||||
if (max < 0)
|
if (max < 0)
|
||||||
goto _end;
|
goto _end;
|
||||||
if (approx_nearer(max, maxdir, best, bestdir, min, mindir)) {
|
if (boundary_nearer(max, maxdir, best, bestdir, min, mindir)) {
|
||||||
*params = params1;
|
*params = params1;
|
||||||
last = 1;
|
last = 1;
|
||||||
}
|
}
|
||||||
|
|
@ -869,13 +822,13 @@ void snd_pcm_hw_param_near_minmax(snd_pcm_t *pcm,
|
||||||
{
|
{
|
||||||
snd_pcm_hw_params_t tmp;
|
snd_pcm_hw_params_t tmp;
|
||||||
int err;
|
int err;
|
||||||
if (!approx_lt(min, *mindir, max, *maxdir)) {
|
if (!boundary_lt(min, *mindir, max, *maxdir)) {
|
||||||
snd_pcm_hw_param_near(pcm, params, var, min, mindir);
|
snd_pcm_hw_param_near(pcm, params, var, min, mindir);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
tmp = *params;
|
tmp = *params;
|
||||||
min = snd_pcm_hw_param_near(pcm, &tmp, var, min, mindir);
|
min = snd_pcm_hw_param_near(pcm, &tmp, var, min, mindir);
|
||||||
if (approx_lt(min, *mindir, max, *maxdir)) {
|
if (boundary_lt(min, *mindir, max, *maxdir)) {
|
||||||
tmp = *params;
|
tmp = *params;
|
||||||
max = snd_pcm_hw_param_near(pcm, &tmp, var, max, maxdir);
|
max = snd_pcm_hw_param_near(pcm, &tmp, var, max, maxdir);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -488,6 +488,8 @@ static int snd_pcm_plug_hw_refine_cchange(snd_pcm_t *pcm ATTRIBUTE_UNUSED,
|
||||||
interval_t t;
|
interval_t t;
|
||||||
const interval_t *sbuffer_size;
|
const interval_t *sbuffer_size;
|
||||||
const interval_t *srate, *crate;
|
const interval_t *srate, *crate;
|
||||||
|
unsigned int rate_min, srate_min;
|
||||||
|
int rate_mindir, srate_mindir;
|
||||||
format_mask = snd_pcm_hw_param_value_mask(params,
|
format_mask = snd_pcm_hw_param_value_mask(params,
|
||||||
SND_PCM_HW_PARAM_FORMAT);
|
SND_PCM_HW_PARAM_FORMAT);
|
||||||
sformat_mask = snd_pcm_hw_param_value_mask(sparams,
|
sformat_mask = snd_pcm_hw_param_value_mask(sparams,
|
||||||
|
|
@ -512,6 +514,15 @@ static int snd_pcm_plug_hw_refine_cchange(snd_pcm_t *pcm ATTRIBUTE_UNUSED,
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
|
/* This is a temporary hack, waiting for a better solution */
|
||||||
|
rate_min = snd_pcm_hw_param_value_min(params, SND_PCM_HW_PARAM_RATE, &rate_mindir);
|
||||||
|
srate_min = snd_pcm_hw_param_value_min(sparams, SND_PCM_HW_PARAM_RATE, &srate_mindir);
|
||||||
|
if (rate_min == srate_min && srate_mindir > rate_mindir) {
|
||||||
|
err = _snd_pcm_hw_param_min(params, SND_PCM_HW_PARAM_RATE, srate_min, srate_mindir);
|
||||||
|
if (err < 0)
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
sbuffer_size = snd_pcm_hw_param_value_interval(sparams, SND_PCM_HW_PARAM_BUFFER_SIZE);
|
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);
|
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);
|
srate = snd_pcm_hw_param_value_interval(sparams, SND_PCM_HW_PARAM_RATE);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue