summaryrefslogtreecommitdiff
path: root/src/pcm
diff options
context:
space:
mode:
authorAbramo Bagnara <abramo@alsa-project.org>2001-01-22 16:07:11 +0000
committerAbramo Bagnara <abramo@alsa-project.org>2001-01-22 16:07:11 +0000
commitc6f6c231c0b98b8bc4ed1b54da2ecc69a73bc52b (patch)
treef1a7e9bbf876c2b3a133e0021feceba816433c48 /src/pcm
parent5c84940c1f587782de2212fe3977bcc0dba0c8d0 (diff)
downloadalsa-lib-c6f6c231c0b98b8bc4ed1b54da2ecc69a73bc52b.tar.gz
Fixed pcm_plug race condition
Diffstat (limited to 'src/pcm')
-rw-r--r--src/pcm/interval.c54
-rw-r--r--src/pcm/interval.h3
-rw-r--r--src/pcm/pcm_params.c57
-rw-r--r--src/pcm/pcm_plug.c11
4 files changed, 73 insertions, 52 deletions
diff --git a/src/pcm/interval.c b/src/pcm/interval.c
index c7967bc6..f4e7e0cb 100644
--- a/src/pcm/interval.c
+++ b/src/pcm/interval.c
@@ -381,3 +381,57 @@ void interval_print(const interval_t *i, snd_output_t *out)
i->min, i->max,
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);
+}
+
diff --git a/src/pcm/interval.h b/src/pcm/interval.h
index d78fe4e5..3d57f3a8 100644
--- a/src/pcm/interval.h
+++ b/src/pcm/interval.h
@@ -57,3 +57,6 @@ int interval_refine(interval_t *i, const interval_t *v);
int interval_refine_first(interval_t *i);
int interval_refine_last(interval_t *i);
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);
diff --git a/src/pcm/pcm_params.c b/src/pcm/pcm_params.c
index 7b37fcac..772d98b2 100644
--- a/src/pcm/pcm_params.c
+++ b/src/pcm/pcm_params.c
@@ -25,53 +25,6 @@
#include "interval.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)
{
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, &params1, var, max, &maxdir);
if (max < 0)
goto _end;
- if (approx_nearer(max, maxdir, best, valdir, min, mindir)) {
+ if (boundary_nearer(max, maxdir, best, valdir, min, mindir)) {
*params = params1;
last = 1;
}
@@ -813,7 +766,7 @@ int snd_pcm_hw_param_next(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
/* FIXME */
if (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)) {
min = best - diff;
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, &params1, var, max, &maxdir);
if (max < 0)
goto _end;
- if (approx_nearer(max, maxdir, best, bestdir, min, mindir)) {
+ if (boundary_nearer(max, maxdir, best, bestdir, min, mindir)) {
*params = params1;
last = 1;
}
@@ -869,13 +822,13 @@ void snd_pcm_hw_param_near_minmax(snd_pcm_t *pcm,
{
snd_pcm_hw_params_t tmp;
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);
return;
}
tmp = *params;
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;
max = snd_pcm_hw_param_near(pcm, &tmp, var, max, maxdir);
} else {
diff --git a/src/pcm/pcm_plug.c b/src/pcm/pcm_plug.c
index 67f6b097..ebf7a526 100644
--- a/src/pcm/pcm_plug.c
+++ b/src/pcm/pcm_plug.c
@@ -488,6 +488,8 @@ static int snd_pcm_plug_hw_refine_cchange(snd_pcm_t *pcm ATTRIBUTE_UNUSED,
interval_t t;
const interval_t *sbuffer_size;
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,
SND_PCM_HW_PARAM_FORMAT);
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)
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);
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);