]> git.alsa-project.org Git - alsa-lib.git/commitdiff
More pcm params functions returns an error rather than do assert().
authorJaroslav Kysela <perex@perex.cz>
Sat, 8 Feb 2003 16:35:24 +0000 (16:35 +0000)
committerJaroslav Kysela <perex@perex.cz>
Sat, 8 Feb 2003 16:35:24 +0000 (16:35 +0000)
Some cleanups in refine.
Added more debug code to refine.
Improved dmix refine method.

src/pcm/pcm_dmix.c
src/pcm/pcm_local.h
src/pcm/pcm_params.c
src/pcm/pcm_plug.c

index 4ea253f142ff8ef988ebb288641b578d9dfdca74..0b47dc2daf9c875541eb32a23ecaeb59da5c9456 100644 (file)
@@ -498,6 +498,26 @@ static inline snd_interval_t *hw_param_interval(snd_pcm_hw_params_t *params,
        return &params->intervals[var - SND_PCM_HW_PARAM_FIRST_INTERVAL];
 }
 
+static int hw_param_interval_refine_one(snd_pcm_hw_params_t *params,
+                                       snd_pcm_hw_param_t var,
+                                       snd_pcm_hw_params_t *src)
+{
+       snd_interval_t *i;
+
+       if (!(params->rmask & (1<<var)))        /* nothing to do? */
+               return 0;
+       i = hw_param_interval(params, var);
+       if (snd_interval_empty(i)) {
+               SNDERR("dmix interval %i empty?\n", (int)var);
+               return -EINVAL;
+       }
+       if (snd_interval_refine(i, hw_param_interval(src, var)))
+               params->cmask |= 1<<var;
+       return 0;
+}
+
+#undef REFINE_DEBUG
+
 static int snd_pcm_dmix_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
 {
        snd_pcm_dmix_t *dmix = pcm->private_data;
@@ -508,25 +528,59 @@ static int snd_pcm_dmix_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
                                        (1<<SNDRV_PCM_ACCESS_RW_INTERLEAVED) |
                                        (1<<SNDRV_PCM_ACCESS_RW_NONINTERLEAVED),
                                        0, 0, 0 } };
+       int err;
 
-       snd_mask_refine(hw_param_mask(params, SND_PCM_HW_PARAM_ACCESS), &access);
-       snd_mask_refine_set(hw_param_mask(params, SND_PCM_HW_PARAM_FORMAT),
-                           snd_mask_value(hw_param_mask(hw_params, SND_PCM_HW_PARAM_FORMAT)));
+#ifdef REFINE_DEBUG
+       snd_output_t *log;
+       snd_output_stdio_attach(&log, stderr, 0);
+       snd_output_puts(log, "DMIX REFINE (begin):\n");
+       snd_pcm_hw_params_dump(params, log);
+#endif
+
+       if (params->rmask & (1<<SND_PCM_HW_PARAM_ACCESS)) {
+               if (snd_mask_empty(hw_param_mask(params, SND_PCM_HW_PARAM_ACCESS))) {
+                       SNDERR("dmix access mask empty?\n");
+                       return -EINVAL;
+               }
+               if (snd_mask_refine(hw_param_mask(params, SND_PCM_HW_PARAM_ACCESS), &access))
+                       params->cmask |= 1<<SND_PCM_HW_PARAM_ACCESS;
+       }
+       if (params->rmask & (1<<SND_PCM_HW_PARAM_FORMAT)) {
+               if (snd_mask_empty(hw_param_mask(params, SND_PCM_HW_PARAM_FORMAT))) {
+                       SNDERR("dmix format mask empty?\n");
+                       return -EINVAL;
+               }
+               if (snd_mask_refine_set(hw_param_mask(params, SND_PCM_HW_PARAM_FORMAT),
+                                       snd_mask_value(hw_param_mask(hw_params, SND_PCM_HW_PARAM_FORMAT))))
+                       params->cmask |= 1<<SND_PCM_HW_PARAM_FORMAT;
+       }
        //snd_mask_none(hw_param_mask(params, SND_PCM_HW_PARAM_SUBFORMAT));
-       snd_interval_refine_set(hw_param_interval(params, SND_PCM_HW_PARAM_CHANNELS),
-                               snd_interval_value(hw_param_interval(hw_params, SND_PCM_HW_PARAM_CHANNELS)));
-       snd_interval_refine_set(hw_param_interval(params, SND_PCM_HW_PARAM_RATE),
-                               snd_interval_value(hw_param_interval(hw_params, SND_PCM_HW_PARAM_RATE)));
-       snd_interval_refine_set(hw_param_interval(params, SND_PCM_HW_PARAM_BUFFER_SIZE),
-                               snd_interval_value(hw_param_interval(hw_params, SND_PCM_HW_PARAM_BUFFER_SIZE)));
-       snd_interval_refine_set(hw_param_interval(params, SND_PCM_HW_PARAM_BUFFER_TIME),
-                               snd_interval_value(hw_param_interval(hw_params, SND_PCM_HW_PARAM_BUFFER_TIME)));
-       snd_interval_refine_set(hw_param_interval(params, SND_PCM_HW_PARAM_PERIOD_SIZE),
-                               snd_interval_value(hw_param_interval(hw_params, SND_PCM_HW_PARAM_PERIOD_SIZE)));
-       snd_interval_refine_set(hw_param_interval(params, SND_PCM_HW_PARAM_PERIOD_TIME),
-                               snd_interval_value(hw_param_interval(hw_params, SND_PCM_HW_PARAM_PERIOD_TIME)));
-       snd_interval_refine_set(hw_param_interval(params, SND_PCM_HW_PARAM_PERIODS),
-                               snd_interval_value(hw_param_interval(hw_params, SND_PCM_HW_PARAM_PERIODS)));
+       err = hw_param_interval_refine_one(params, SND_PCM_HW_PARAM_CHANNELS, hw_params);
+       if (err < 0)
+               return err;
+       err = hw_param_interval_refine_one(params, SND_PCM_HW_PARAM_RATE, hw_params);
+       if (err < 0)
+               return err;
+       err = hw_param_interval_refine_one(params, SND_PCM_HW_PARAM_BUFFER_SIZE, hw_params);
+       if (err < 0)
+               return err;
+       err = hw_param_interval_refine_one(params, SND_PCM_HW_PARAM_BUFFER_TIME, hw_params);
+       if (err < 0)
+               return err;
+       err = hw_param_interval_refine_one(params, SND_PCM_HW_PARAM_PERIOD_SIZE, hw_params);
+       if (err < 0)
+               return err;
+       err = hw_param_interval_refine_one(params, SND_PCM_HW_PARAM_PERIOD_TIME, hw_params);
+       if (err < 0)
+               return err;
+       err = hw_param_interval_refine_one(params, SND_PCM_HW_PARAM_PERIODS, hw_params);
+       if (err < 0)
+               return err;
+#ifdef REFINE_DEBUG
+       snd_output_puts(log, "DMIX REFINE (end):\n");
+       snd_pcm_hw_params_dump(params, log);
+       snd_output_close(log);
+#endif
        return 0;
 }
 
@@ -625,20 +679,6 @@ static int snd_pcm_dmix_resume(snd_pcm_t *pcm)
        return 0;
 }
 
-static snd_pcm_sframes_t snd_pcm_dmix_writei(snd_pcm_t *pcm, const void *buffer, snd_pcm_uframes_t size)
-{
-       int res = snd_pcm_mmap_writei(pcm, buffer, size);
-       snd_pcm_dmix_sync_ptr(pcm, size);
-       return res;
-}
-
-static snd_pcm_sframes_t snd_pcm_dmix_writen(snd_pcm_t *pcm, void **bufs, snd_pcm_uframes_t size)
-{
-       int res = snd_pcm_mmap_writen(pcm, bufs, size);
-       snd_pcm_dmix_sync_ptr(pcm, size);
-       return res;
-}
-
 static snd_pcm_sframes_t snd_pcm_dmix_readi(snd_pcm_t *pcm ATTRIBUTE_UNUSED, void *buffer ATTRIBUTE_UNUSED, snd_pcm_uframes_t size ATTRIBUTE_UNUSED)
 {
        return -ENODEV;
@@ -734,8 +774,8 @@ static snd_pcm_fast_ops_t snd_pcm_dmix_fast_ops = {
        pause: snd_pcm_dmix_pause,
        rewind: snd_pcm_dmix_rewind,
        resume: snd_pcm_dmix_resume,
-       writei: snd_pcm_dmix_writei,
-       writen: snd_pcm_dmix_writen,
+       writei: snd_pcm_mmap_writei,
+       writen: snd_pcm_mmap_writen,
        readi: snd_pcm_dmix_readi,
        readn: snd_pcm_dmix_readn,
        avail_update: snd_pcm_dmix_avail_update,
index 8e12a29b066e67c694cc01791fc4c5bdb68badc3..a2be05ea919d1fecfc455dab075ce5341e7f563c 100644 (file)
@@ -486,14 +486,14 @@ int _snd_pcm_hw_param_refine(snd_pcm_hw_params_t *params,
 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);
-void snd_pcm_hw_param_refine_multiple(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_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_refine_multiple(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_empty(const snd_pcm_hw_params_t *params,
                           snd_pcm_hw_param_t var);
 int snd_pcm_hw_param_always_eq(const snd_pcm_hw_params_t *params,
index 234edfda1f5efa7465a16833406b7b6b6095d4aa..0648faf02d0b3ef75f4636fef99222db1cdef972 100644 (file)
@@ -95,6 +95,8 @@ void _snd_pcm_hw_params_any(snd_pcm_hw_params_t *params)
                _snd_pcm_hw_param_any(params, k);
        for (k = SND_PCM_HW_PARAM_FIRST_INTERVAL; k <= SND_PCM_HW_PARAM_LAST_INTERVAL; k++)
                _snd_pcm_hw_param_any(params, k);
+       params->rmask = ~0U;
+       params->cmask = 0;
        params->info = ~0U;
 }
 
@@ -132,13 +134,16 @@ int snd_pcm_hw_param_get_min(const snd_pcm_hw_params_t *params, snd_pcm_hw_param
                             unsigned int *val, int *dir)
 {
        if (hw_is_mask(var)) {
+               const snd_mask_t *m = hw_param_mask_c(params, var);
+               assert(!snd_mask_empty(m));
                if (dir)
                        *dir = 0;
                if (val)
-                       *val = snd_mask_min(hw_param_mask_c(params, var));
+                       *val = snd_mask_min(m);
                return 0;
        } else if (hw_is_interval(var)) {
                const snd_interval_t *i = hw_param_interval_c(params, var);
+               assert(!snd_interval_empty(i));
                if (dir)
                        *dir = i->openmin;
                if (val)
@@ -154,13 +159,16 @@ int snd_pcm_hw_param_get_max(const snd_pcm_hw_params_t *params, snd_pcm_hw_param
                             unsigned int *val, int *dir)
 {
        if (hw_is_mask(var)) {
+               const snd_mask_t *m = hw_param_mask_c(params, var);
+               assert(!snd_mask_empty(m));
                if (dir)
                        *dir = 0;
                if (val)
-                       *val = snd_mask_max(hw_param_mask_c(params, var));
+                       *val = snd_mask_max(m);
                return 0;
        } else if (hw_is_interval(var)) {
                const snd_interval_t *i = hw_param_interval_c(params, var);
+               assert(!snd_interval_empty(i));
                if (dir)
                        *dir = - (int) i->openmax;
                if (val)
@@ -211,7 +219,7 @@ void _snd_pcm_hw_param_set_empty(snd_pcm_hw_params_t *params,
                                 snd_pcm_hw_param_t var)
 {
        if (hw_is_mask(var)) {
-       snd_mask_none(hw_param_mask(params, var));
+               snd_mask_none(hw_param_mask(params, var));
                params->cmask |= 1 << var;
                params->rmask |= 1 << var;
        } else if (hw_is_interval(var)) {
@@ -421,6 +429,10 @@ int snd_pcm_hw_param_set_min(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
                err = snd_pcm_hw_refine(pcm, params);
                if (err < 0)
                        goto _fail;
+               if (snd_pcm_hw_param_empty(params, var)) {
+                       err = -ENOENT;
+                       goto _fail;
+               }
        }
        return snd_pcm_hw_param_get_min(params, var, val, dir);
  _fail:
@@ -492,6 +504,10 @@ int snd_pcm_hw_param_set_max(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
                err = snd_pcm_hw_refine(pcm, params);
                if (err < 0)
                        goto _fail;
+               if (snd_pcm_hw_param_empty(params, var)) {
+                       err = -ENOENT;
+                       goto _fail;
+               }
        }
        return snd_pcm_hw_param_get_max(params, var, val, dir);
  _fail:
@@ -772,6 +788,7 @@ int snd_pcm_hw_param_set_near(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
        int min, max;
        int mindir, maxdir;
        int valdir = dir ? *dir : 0;
+       snd_interval_t *i;
        /* FIXME */
        if (best > INT_MAX)
                best = INT_MAX;
@@ -788,6 +805,11 @@ int snd_pcm_hw_param_set_near(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
        save = *params;
        saved_min = min;
        err = snd_pcm_hw_param_set_min(pcm, params, SND_CHANGE, var, &min, &mindir);
+
+       i = hw_param_interval(params, var);
+       if (!snd_interval_empty(i) && snd_interval_single(i))
+               return snd_pcm_hw_param_get_min(params, var, val, dir);
+       
        if (err >= 0) {
                snd_pcm_hw_params_t params1;
                if (max < 0)
@@ -913,28 +935,33 @@ static int snd_pcm_hw_param_set_near_minmax(snd_pcm_t *pcm,
        }
        err = snd_pcm_hw_param_set_minmax(pcm, params, SND_CHANGE, var, &min, mindir,
                                          &max, maxdir);
-       assert(err >= 0);
+       if (err < 0)
+               return err;
        return 0;
 }
 
-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_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;
+       int mindir, maxdir, err;
 
-       snd_pcm_hw_param_get_min(src, var, &min, &mindir);
-       snd_pcm_hw_param_get_max(src, var, &max, &maxdir);
-       snd_pcm_hw_param_set_near_minmax(pcm, params, var,
-                                        min, &mindir, max, &maxdir);
+       if ((err = snd_pcm_hw_param_get_min(src, var, &min, &mindir)) < 0)
+               return err;
+       if ((err = snd_pcm_hw_param_get_max(src, var, &max, &maxdir)) < 0)
+               return err;
+       if ((err = snd_pcm_hw_param_set_near_minmax(pcm, params, var,
+                                                   min, &mindir, max, &maxdir)) < 0)
+               return err;
+       return 0;
 }
 
-void snd_pcm_hw_param_refine_multiple(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_refine_multiple(snd_pcm_t *pcm,
+                                    snd_pcm_hw_params_t *params,
+                                    snd_pcm_hw_param_t var,
+                                    const snd_pcm_hw_params_t *src)
 {
        const snd_interval_t *it = hw_param_interval_c(src, var);
        const snd_interval_t *st = hw_param_interval_c(params, var);
@@ -945,11 +972,11 @@ void snd_pcm_hw_param_refine_multiple(snd_pcm_t *pcm,
                                break;
                        if (it->min > cur || (it->min == cur && st->openmin))
                                continue;
-                       if (! snd_pcm_hw_param_set(pcm, params, SND_TRY, var, cur, 0))
-                               return; /* ok */
+                       if (snd_pcm_hw_param_set(pcm, params, SND_TRY, var, cur, 0) == 0)
+                               return 0; /* ok */
                }
        }
-       snd_pcm_hw_param_refine_near(pcm, params, var, src);
+       return snd_pcm_hw_param_refine_near(pcm, params, var, src);
 }
 
 /* ---- end of refinement functions ---- */
@@ -971,10 +998,10 @@ int snd_pcm_hw_param_always_eq(const snd_pcm_hw_params_t *params,
 {
        if (hw_is_mask(var))
                return snd_mask_always_eq(hw_param_mask_c(params, var),
-                                     hw_param_mask_c(params1, var));
+                                         hw_param_mask_c(params1, var));
        if (hw_is_interval(var))
                return snd_interval_always_eq(hw_param_interval_c(params, var),
-                                         hw_param_interval_c(params1, var));
+                                             hw_param_interval_c(params1, var));
        assert(0);
        return -EINVAL;
 }
@@ -985,10 +1012,10 @@ int snd_pcm_hw_param_never_eq(const snd_pcm_hw_params_t *params,
 {
        if (hw_is_mask(var))
                return snd_mask_never_eq(hw_param_mask_c(params, var),
-                                     hw_param_mask_c(params1, var));
+                                        hw_param_mask_c(params1, var));
        if (hw_is_interval(var))
                return snd_interval_never_eq(hw_param_interval_c(params, var),
-                                        hw_param_interval_c(params1, var));
+                                            hw_param_interval_c(params1, var));
        assert(0);
        return -EINVAL;
 }
@@ -1903,6 +1930,8 @@ int snd_pcm_hw_refine_soft(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t
 #ifdef RULES_DEBUG
        snd_output_t *log;
        snd_output_stdio_attach(&log, stderr, 0);
+       snd_output_printf(log, "refine_soft '%s' (begin)\n", pcm->name);
+       snd_pcm_hw_params_dump(params, log);
 #endif
 
        for (k = SND_PCM_HW_PARAM_FIRST_MASK; k <= SND_PCM_HW_PARAM_LAST_MASK; k++) {
@@ -1991,6 +2020,8 @@ int snd_pcm_hw_refine_soft(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t
        return 0;
  _err:
 #ifdef RULES_DEBUG
+       snd_output_printf(log, "refine_soft '%s' (end-%i)\n", pcm->name, changed);
+       snd_pcm_hw_params_dump(params, log);
        snd_output_close(log);
 #endif
        return changed;
@@ -2051,19 +2082,25 @@ int snd_pcm_hw_refine_slave(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
                cmask = params->cmask;
                params->cmask = 0;
 #ifdef RULES_DEBUG
-               snd_output_printf(log, "schange '%s'\n", pcm->name);
+               snd_output_printf(log, "schange '%s' (client)\n", pcm->name);
                snd_pcm_hw_params_dump(params, log);
+               snd_output_printf(log, "schange '%s' (slave)\n", pcm->name);
+               snd_pcm_hw_params_dump(&sparams, log);
 #endif
                err = schange(pcm, params, &sparams);
                if (err >= 0) {
 #ifdef RULES_DEBUG
-                       snd_output_printf(log, "srefine '%s'\n", pcm->name);
+                       snd_output_printf(log, "srefine '%s' (client)\n", pcm->name);
+                       snd_pcm_hw_params_dump(params, log);
+                       snd_output_printf(log, "srefine '%s' (slave)\n", pcm->name);
                        snd_pcm_hw_params_dump(&sparams, log);
 #endif
                        err = srefine(pcm, &sparams);
                        if (err < 0) {
 #ifdef RULES_DEBUG
-                               snd_output_printf(log, "srefine '%s', err < 0 (%i)\n", pcm->name, err);
+                               snd_output_printf(log, "srefine '%s', err < 0 (%i) (client)\n", pcm->name, err);
+                               snd_pcm_hw_params_dump(params, log);
+                               snd_output_printf(log, "srefine '%s', err < 0 (%i) (slave)\n", pcm->name, err);
                                snd_pcm_hw_params_dump(&sparams, log);
 #endif
                                cchange(pcm, params, &sparams);
@@ -2071,8 +2108,10 @@ int snd_pcm_hw_refine_slave(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
                        }
                } else {
 #ifdef RULES_DEBUG
-                       snd_output_printf(log, "schange '%s', err < 0 (%i)\n", pcm->name, err);
+                       snd_output_printf(log, "schange '%s', err < 0 (%i) (client)\n", pcm->name, err);
                        snd_pcm_hw_params_dump(params, log);
+                       snd_output_printf(log, "schange '%s', err < 0 (%i) (slave)\n", pcm->name, err);
+                       snd_pcm_hw_params_dump(&sparams, log);
 #endif
                        cchange(pcm, params, &sparams);
                        return err;
index f9ae5e14089233a7d05dace437faa1cacf25e747..e0c05faa3f49c8d31cb86fd010cc36e88ab597af 100644 (file)
@@ -595,16 +595,21 @@ static int snd_pcm_plug_insert_plugins(snd_pcm_t *pcm,
 static int snd_pcm_plug_hw_refine_cprepare(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params)
 {
        unsigned int rate_min, channels_max;
+       int err;
 
        /* HACK: to avoid overflow in PARTBIT_RATE code */
-       snd_pcm_hw_param_get_min(params, SND_PCM_HW_PARAM_RATE, &rate_min, NULL);
+       err = snd_pcm_hw_param_get_min(params, SND_PCM_HW_PARAM_RATE, &rate_min, NULL);
+       if (err < 0)
+               return err;
        if (rate_min < 4000) {
                _snd_pcm_hw_param_set_min(params, SND_PCM_HW_PARAM_RATE, 4000, 0);
                if (snd_pcm_hw_param_empty(params, SND_PCM_HW_PARAM_RATE))
                        return -EINVAL;
        }
        /* HACK: to avoid overflow in PERIOD_SIZE code */
-       snd_pcm_hw_param_get_max(params, SND_PCM_HW_PARAM_CHANNELS, &channels_max, NULL);
+       err = snd_pcm_hw_param_get_max(params, SND_PCM_HW_PARAM_CHANNELS, &channels_max, NULL);
+       if (err < 0)
+               return err;
        if (channels_max > 10000) {
                _snd_pcm_hw_param_set_max(params, SND_PCM_HW_PARAM_CHANNELS, 10000, 0);
                if (snd_pcm_hw_param_empty(params, SND_PCM_HW_PARAM_CHANNELS))
@@ -617,6 +622,8 @@ static int snd_pcm_plug_hw_refine_sprepare(snd_pcm_t *pcm, snd_pcm_hw_params_t *
 {
        snd_pcm_plug_t *plug = pcm->private_data;
        _snd_pcm_hw_params_any(sparams);
+       int err;
+       
        if (plug->sformat >= 0) {
                _snd_pcm_hw_params_set_format(sparams, plug->sformat);
                _snd_pcm_hw_params_set_subformat(sparams, SND_PCM_SUBFORMAT_STD);
@@ -627,11 +634,10 @@ static int snd_pcm_plug_hw_refine_sprepare(snd_pcm_t *pcm, snd_pcm_hw_params_t *
        if (plug->srate > 0)
                _snd_pcm_hw_param_set_minmax(sparams, SND_PCM_HW_PARAM_RATE,
                                              plug->srate, 0, plug->srate + 1, -1);
-        if (plug->sformat >= 0 || plug->schannels > 0 || plug->srate > 0) {
-               int err = snd_pcm_hw_refine(plug->req_slave, sparams);
-               if (err < 0)
-                       return err;
-       }
+       /* reduce the available configurations */
+       err = snd_pcm_hw_refine(plug->req_slave, sparams);
+       if (err < 0)
+               return err;
        return 0;
 }
 
@@ -652,22 +658,23 @@ static int snd_pcm_plug_hw_refine_schange(snd_pcm_t *pcm, snd_pcm_hw_params_t *p
        if (plug->srate == -2)
                links |= SND_PCM_HW_PARBIT_RATE;
        else {
-               snd_pcm_hw_param_refine_multiple(slave, sparams, SND_PCM_HW_PARAM_RATE,
-                                                params);
+               err = snd_pcm_hw_param_refine_multiple(slave, sparams, SND_PCM_HW_PARAM_RATE, params);
+               if (err < 0)
+                       return err;
        }
        
        if (plug->schannels == -2)
                links |= SND_PCM_HW_PARBIT_CHANNELS;
-       else
-               snd_pcm_hw_param_refine_near(slave, sparams, SND_PCM_HW_PARAM_CHANNELS,
-                                            params);
+       else {
+               err = snd_pcm_hw_param_refine_near(slave, sparams, SND_PCM_HW_PARAM_CHANNELS, params);
+               if (err < 0)
+                       return err;
+       }
        if (plug->sformat == -2)
                links |= SND_PCM_HW_PARBIT_FORMAT;
        else {
-               format_mask = snd_pcm_hw_param_get_mask(params,
-                                                       SND_PCM_HW_PARAM_FORMAT);
-               sformat_mask = snd_pcm_hw_param_get_mask(sparams,
-                                                        SND_PCM_HW_PARAM_FORMAT);
+               format_mask = snd_pcm_hw_param_get_mask(params, SND_PCM_HW_PARAM_FORMAT);
+               sformat_mask = snd_pcm_hw_param_get_mask(sparams, SND_PCM_HW_PARAM_FORMAT);
                snd_mask_none(&sfmt_mask);
                for (format = 0; format <= SND_PCM_FORMAT_LAST; format++) {
                        snd_pcm_format_t f;
@@ -749,8 +756,6 @@ static int snd_pcm_plug_hw_refine_cchange(snd_pcm_t *pcm ATTRIBUTE_UNUSED,
        snd_interval_t t;
        const snd_interval_t *sbuffer_size;
        const snd_interval_t *srate, *crate;
-       unsigned int rate_min, srate_min;
-       int rate_mindir, srate_mindir;
 
        if (plug->schannels == -2)
                links |= SND_PCM_HW_PARBIT_CHANNELS;
@@ -801,9 +806,16 @@ static int snd_pcm_plug_hw_refine_cchange(snd_pcm_t *pcm ATTRIBUTE_UNUSED,
        if (plug->srate == -2)
                links |= SND_PCM_HW_PARBIT_RATE;
        else {
+               unsigned int rate_min, srate_min;
+               int rate_mindir, srate_mindir;
+               
                /* This is a temporary hack, waiting for a better solution */
-               snd_pcm_hw_param_get_min(params, SND_PCM_HW_PARAM_RATE, &rate_min, &rate_mindir);
-               snd_pcm_hw_param_get_min(sparams, SND_PCM_HW_PARAM_RATE, &srate_min, &srate_mindir);
+               err = snd_pcm_hw_param_get_min(params, SND_PCM_HW_PARAM_RATE, &rate_min, &rate_mindir);
+               if (err < 0)
+                       return err;
+               err = snd_pcm_hw_param_get_min(sparams, SND_PCM_HW_PARAM_RATE, &srate_min, &srate_mindir);
+               if (err < 0)
+                       return err;
                if (rate_min == srate_min && srate_mindir > rate_mindir) {
                        err = _snd_pcm_hw_param_set_min(params, SND_PCM_HW_PARAM_RATE, srate_min, srate_mindir);
                        if (err < 0)
@@ -820,6 +832,8 @@ static int snd_pcm_plug_hw_refine_cchange(snd_pcm_t *pcm ATTRIBUTE_UNUSED,
                srate = snd_pcm_hw_param_get_interval(sparams, SND_PCM_HW_PARAM_RATE);
                snd_interval_muldiv(sbuffer_size, crate, srate, &t);
                snd_interval_floor(&t);
+               if (snd_interval_empty(&t))
+                       return -EINVAL;
                err = _snd_pcm_hw_param_set_interval(params, SND_PCM_HW_PARAM_BUFFER_SIZE, &t);
                if (err < 0)
                        return err;