2 * PCM - Params functions
3 * Copyright (c) 2000 by Abramo Bagnara <abramo@alsa-project.org>
6 * This library is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU Lesser General Public License as
8 * published by the Free Software Foundation; either version 2.1 of
9 * the License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #include "pcm_local.h"
26 * dump hw_params when $LIBASOUND_DEBUG is set to >= 1
28 static void dump_hw_params(snd_pcm_hw_params_t *params, const char *type,
29 snd_pcm_hw_param_t var, unsigned int val, int err)
31 const char *verbose = getenv("LIBASOUND_DEBUG");
34 if (! verbose || ! *verbose || atoi(verbose) < 1)
36 if (snd_output_stdio_attach(&out, stderr, 0) < 0)
38 fprintf(stderr, "ALSA ERROR hw_params: %s (%s)\n",
39 type, snd_pcm_hw_param_name(var));
40 fprintf(stderr, " value = ");
42 case SND_PCM_HW_PARAM_ACCESS:
43 fprintf(stderr, "%s", snd_pcm_access_name(val));
45 case SND_PCM_HW_PARAM_FORMAT:
46 fprintf(stderr, "%s", snd_pcm_format_name(val));
48 case SND_PCM_HW_PARAM_SUBFORMAT:
49 fprintf(stderr, "%s", snd_pcm_subformat_name(val));
52 fprintf(stderr, "%u", val);
54 fprintf(stderr, " : %s\n", snd_strerror(err));
55 snd_pcm_hw_params_dump(params, out);
56 snd_output_close(out);
59 static inline void dump_hw_params(snd_pcm_hw_params_t *params, const char *type,
60 snd_pcm_hw_param_t var, unsigned int val, int err)
65 static inline int hw_is_mask(snd_pcm_hw_param_t var)
67 #if SND_PCM_HW_PARAM_FIRST_MASK == 0
68 return var <= SND_PCM_HW_PARAM_LAST_MASK;
70 return var >= SND_PCM_HW_PARAM_FIRST_MASK &&
71 var <= SND_PCM_HW_PARAM_LAST_MASK;
75 static inline int hw_is_interval(snd_pcm_hw_param_t var)
77 return var >= SND_PCM_HW_PARAM_FIRST_INTERVAL &&
78 var <= SND_PCM_HW_PARAM_LAST_INTERVAL;
81 #define hw_param_mask(params,var) \
82 &((params)->masks[(var) - SND_PCM_HW_PARAM_FIRST_MASK])
84 #define hw_param_interval(params,var) \
85 &((params)->intervals[(var) - SND_PCM_HW_PARAM_FIRST_INTERVAL])
87 #define hw_param_mask_c hw_param_mask
88 #define hw_param_interval_c hw_param_interval
90 static void _snd_pcm_hw_param_any(snd_pcm_hw_params_t *params, snd_pcm_hw_param_t var)
92 if (hw_is_mask(var)) {
93 snd_mask_any(hw_param_mask(params, var));
94 params->cmask |= 1 << var;
95 params->rmask |= 1 << var;
98 if (hw_is_interval(var)) {
99 snd_interval_any(hw_param_interval(params, var));
100 params->cmask |= 1 << var;
101 params->rmask |= 1 << var;
107 int snd_pcm_hw_param_any(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
108 snd_pcm_hw_param_t var)
110 _snd_pcm_hw_param_any(params, var);
111 return snd_pcm_hw_refine(pcm, params);
114 void _snd_pcm_hw_params_any(snd_pcm_hw_params_t *params)
117 memset(params, 0, sizeof(*params));
118 for (k = SND_PCM_HW_PARAM_FIRST_MASK; k <= SND_PCM_HW_PARAM_LAST_MASK; k++)
119 _snd_pcm_hw_param_any(params, k);
120 for (k = SND_PCM_HW_PARAM_FIRST_INTERVAL; k <= SND_PCM_HW_PARAM_LAST_INTERVAL; k++)
121 _snd_pcm_hw_param_any(params, k);
127 /* Return the value for field PAR if it's fixed in configuration space
128 defined by PARAMS. Return -EINVAL otherwise
130 int snd_pcm_hw_param_get(const snd_pcm_hw_params_t *params, snd_pcm_hw_param_t var,
131 unsigned int *val, int *dir)
133 if (hw_is_mask(var)) {
134 const snd_mask_t *mask = hw_param_mask_c(params, var);
135 if (snd_mask_empty(mask) || !snd_mask_single(mask))
140 *val = snd_mask_value(mask);
142 } else if (hw_is_interval(var)) {
143 const snd_interval_t *i = hw_param_interval_c(params, var);
144 if (snd_interval_empty(i) || !snd_interval_single(i))
149 *val = snd_interval_value(i);
156 /* Return the minimum value for field PAR. */
157 int snd_pcm_hw_param_get_min(const snd_pcm_hw_params_t *params, snd_pcm_hw_param_t var,
158 unsigned int *val, int *dir)
160 if (hw_is_mask(var)) {
161 const snd_mask_t *m = hw_param_mask_c(params, var);
162 assert(!snd_mask_empty(m));
166 *val = snd_mask_min(m);
168 } else if (hw_is_interval(var)) {
169 const snd_interval_t *i = hw_param_interval_c(params, var);
170 assert(!snd_interval_empty(i));
174 *val = snd_interval_min(i);
181 /* Return the maximum value for field PAR. */
182 int snd_pcm_hw_param_get_max(const snd_pcm_hw_params_t *params, snd_pcm_hw_param_t var,
183 unsigned int *val, int *dir)
185 if (hw_is_mask(var)) {
186 const snd_mask_t *m = hw_param_mask_c(params, var);
187 assert(!snd_mask_empty(m));
191 *val = snd_mask_max(m);
193 } else if (hw_is_interval(var)) {
194 const snd_interval_t *i = hw_param_interval_c(params, var);
195 assert(!snd_interval_empty(i));
197 *dir = - (int) i->openmax;
199 *val = snd_interval_max(i);
206 /* Return the mask for field PAR.
207 This function can be called only for SND_PCM_HW_PARAM_ACCESS,
208 SND_PCM_HW_PARAM_FORMAT, SND_PCM_HW_PARAM_SUBFORMAT. */
209 const snd_mask_t *snd_pcm_hw_param_get_mask(const snd_pcm_hw_params_t *params,
210 snd_pcm_hw_param_t var)
212 assert(hw_is_mask(var));
213 return hw_param_mask_c(params, var);
216 /* Return the interval for field PAR.
217 This function cannot be called for SND_PCM_HW_PARAM_ACCESS,
218 SND_PCM_HW_PARAM_FORMAT, SND_PCM_HW_PARAM_SUBFORMAT. */
219 const snd_interval_t *snd_pcm_hw_param_get_interval(const snd_pcm_hw_params_t *params,
220 snd_pcm_hw_param_t var)
222 assert(hw_is_interval(var));
223 return hw_param_interval_c(params, var);
226 /* --- Refinement functions --- */
228 int _snd_pcm_hw_param_set_interval(snd_pcm_hw_params_t *params,
229 snd_pcm_hw_param_t var,
230 const snd_interval_t *val)
233 assert(hw_is_interval(var));
234 changed = snd_interval_refine(hw_param_interval(params, var), val);
236 params->cmask |= 1 << var;
237 params->rmask |= 1 << var;
242 void _snd_pcm_hw_param_set_empty(snd_pcm_hw_params_t *params,
243 snd_pcm_hw_param_t var)
245 if (hw_is_mask(var)) {
246 snd_mask_none(hw_param_mask(params, var));
247 params->cmask |= 1 << var;
248 params->rmask |= 1 << var;
249 } else if (hw_is_interval(var)) {
250 snd_interval_none(hw_param_interval(params, var));
251 params->cmask |= 1 << var;
252 params->rmask |= 1 << var;
258 static int _snd_pcm_hw_param_set_integer(snd_pcm_hw_params_t *params,
259 snd_pcm_hw_param_t var)
262 assert(hw_is_interval(var));
263 changed = snd_interval_setinteger(hw_param_interval(params, var));
265 params->cmask |= 1 << var;
266 params->rmask |= 1 << var;
271 /* Inside configuration space defined by PARAMS remove from PAR all
272 non integer values. Reduce configuration space accordingly.
273 Return -EINVAL if the configuration space is empty
275 int snd_pcm_hw_param_set_integer(snd_pcm_t *pcm,
276 snd_pcm_hw_params_t *params,
278 snd_pcm_hw_param_t var)
280 snd_pcm_hw_params_t save;
296 err = _snd_pcm_hw_param_set_integer(params, var);
300 err = snd_pcm_hw_refine(pcm, params);
311 static int _snd_pcm_hw_param_set_first(snd_pcm_hw_params_t *params,
312 snd_pcm_hw_param_t var)
316 changed = snd_mask_refine_first(hw_param_mask(params, var));
317 else if (hw_is_interval(var))
318 changed = snd_interval_refine_first(hw_param_interval(params, var));
324 params->cmask |= 1 << var;
325 params->rmask |= 1 << var;
331 /* Inside configuration space defined by PARAMS remove from PAR all
332 values > minimum. Reduce configuration space accordingly.
335 int snd_pcm_hw_param_set_first(snd_pcm_t *pcm,
336 snd_pcm_hw_params_t *params,
337 snd_pcm_hw_param_t var,
338 unsigned int *rval, int *dir)
342 err = _snd_pcm_hw_param_set_first(params, var);
346 err = snd_pcm_hw_refine(pcm, params);
350 return snd_pcm_hw_param_get(params, var, rval, dir);
353 static int _snd_pcm_hw_param_set_last(snd_pcm_hw_params_t *params,
354 snd_pcm_hw_param_t var)
358 changed = snd_mask_refine_last(hw_param_mask(params, var));
359 else if (hw_is_interval(var))
360 changed = snd_interval_refine_last(hw_param_interval(params, var));
366 params->cmask |= 1 << var;
367 params->rmask |= 1 << var;
373 /* Inside configuration space defined by PARAMS remove from PAR all
374 values < maximum. Reduce configuration space accordingly.
377 int snd_pcm_hw_param_set_last(snd_pcm_t *pcm,
378 snd_pcm_hw_params_t *params,
379 snd_pcm_hw_param_t var,
380 unsigned int *rval, int *dir)
384 err = _snd_pcm_hw_param_set_last(params, var);
388 err = snd_pcm_hw_refine(pcm, params);
392 return snd_pcm_hw_param_get(params, var, rval, dir);
395 int _snd_pcm_hw_param_set_min(snd_pcm_hw_params_t *params,
396 snd_pcm_hw_param_t var, unsigned int val, int dir)
403 } else if (dir < 0) {
411 changed = snd_mask_refine_min(hw_param_mask(params, var), val + !!openmin);
412 else if (hw_is_interval(var))
413 changed = snd_interval_refine_min(hw_param_interval(params, var), val, openmin);
419 params->cmask |= 1 << var;
420 params->rmask |= 1 << var;
425 /* Inside configuration space defined by PARAMS remove from PAR all
426 values < VAL. Reduce configuration space accordingly.
427 Return new minimum or -EINVAL if the configuration space is empty
429 int snd_pcm_hw_param_set_min(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
431 snd_pcm_hw_param_t var, unsigned int *val, int *dir)
433 snd_pcm_hw_params_t save;
449 err = _snd_pcm_hw_param_set_min(params, var, *val, dir ? *dir : 0);
452 if ((mode != SND_TEST || hw_is_interval(var)) && params->rmask) {
453 err = snd_pcm_hw_refine(pcm, params);
456 if (snd_pcm_hw_param_empty(params, var)) {
461 return snd_pcm_hw_param_get_min(params, var, val, dir);
465 if (err < 0 && mode == SND_TRY)
466 dump_hw_params(params, "set_min", var, *val, err);
470 int _snd_pcm_hw_param_set_max(snd_pcm_hw_params_t *params,
471 snd_pcm_hw_param_t var, unsigned int val, int dir)
478 } else if (dir > 0) {
483 if (hw_is_mask(var)) {
484 if (val == 0 && openmax) {
485 snd_mask_none(hw_param_mask(params, var));
488 changed = snd_mask_refine_max(hw_param_mask(params, var), val - !!openmax);
489 } else if (hw_is_interval(var))
490 changed = snd_interval_refine_max(hw_param_interval(params, var), val, openmax);
496 params->cmask |= 1 << var;
497 params->rmask |= 1 << var;
502 /* Inside configuration space defined by PARAMS remove from PAR all
503 values >= VAL + 1. Reduce configuration space accordingly.
504 Return new maximum or -EINVAL if the configuration space is empty
506 int snd_pcm_hw_param_set_max(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
508 snd_pcm_hw_param_t var, unsigned int *val, int *dir)
510 snd_pcm_hw_params_t save;
526 err = _snd_pcm_hw_param_set_max(params, var, *val, dir ? *dir : 0);
529 if ((mode != SND_TEST || hw_is_interval(var)) && params->rmask) {
530 err = snd_pcm_hw_refine(pcm, params);
533 if (snd_pcm_hw_param_empty(params, var)) {
538 return snd_pcm_hw_param_get_max(params, var, val, dir);
542 if (err < 0 && mode == SND_TRY)
543 dump_hw_params(params, "set_max", var, *val, err);
547 int _snd_pcm_hw_param_set_minmax(snd_pcm_hw_params_t *params,
548 snd_pcm_hw_param_t var,
549 unsigned int min, int mindir,
550 unsigned int max, int maxdir)
553 int openmin = 0, openmax = 0;
557 } else if (mindir < 0) {
567 } else if (maxdir > 0) {
572 if (hw_is_mask(var)) {
573 snd_mask_t *mask = hw_param_mask(params, var);
574 if (max == 0 && openmax) {
578 c1 = snd_mask_refine_min(mask, min + !!openmin);
582 c2 = snd_mask_refine_max(mask, max - !!openmax);
586 changed = (c1 || c2);
590 else if (hw_is_interval(var)) {
591 snd_interval_t *i = hw_param_interval(params, var);
592 c1 = snd_interval_refine_min(i, min, openmin);
596 c2 = snd_interval_refine_max(i, max, openmax);
600 changed = (c1 || c2);
607 params->cmask |= 1 << var;
608 params->rmask |= 1 << var;
613 /* Inside configuration space defined by PARAMS remove from PAR all
614 values < MIN and all values > MAX. Reduce configuration space accordingly.
615 Return 0 or -EINVAL if the configuration space is empty
617 int snd_pcm_hw_param_set_minmax(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
619 snd_pcm_hw_param_t var,
620 unsigned int *min, int *mindir,
621 unsigned int *max, int *maxdir)
623 snd_pcm_hw_params_t save;
639 err = _snd_pcm_hw_param_set_minmax(params, var,
640 *min, mindir ? *mindir : 0,
641 *max, maxdir ? *maxdir : 0);
644 if ((mode != SND_TEST || hw_is_interval(var)) && params->rmask) {
645 err = snd_pcm_hw_refine(pcm, params);
649 err = snd_pcm_hw_param_get_min(params, var, min, mindir);
652 return snd_pcm_hw_param_get_max(params, var, max, maxdir);
657 dump_hw_params(params, "set_minmax", var, *min, err);
661 int _snd_pcm_hw_param_set(snd_pcm_hw_params_t *params,
662 snd_pcm_hw_param_t var, unsigned int val, int dir)
665 if (hw_is_mask(var)) {
666 snd_mask_t *m = hw_param_mask(params, var);
667 if (val == 0 && dir < 0) {
675 changed = snd_mask_refine_set(hw_param_mask(params, var), val);
677 } else if (hw_is_interval(var)) {
678 snd_interval_t *i = hw_param_interval(params, var);
679 if (val == 0 && dir < 0) {
681 snd_interval_none(i);
683 changed = snd_interval_refine_set(i, val);
697 changed = snd_interval_refine(i, &t);
704 params->cmask |= 1 << var;
705 params->rmask |= 1 << var;
710 /* Inside configuration space defined by PARAMS remove from PAR all
711 values != VAL. Reduce configuration space accordingly.
712 Return -EINVAL if the configuration space is empty
714 int snd_pcm_hw_param_set(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
716 snd_pcm_hw_param_t var, unsigned int val, int dir)
718 snd_pcm_hw_params_t save;
734 err = _snd_pcm_hw_param_set(params, var, val, dir);
737 if ((mode != SND_TEST || hw_is_interval(var)) && params->rmask) {
738 err = snd_pcm_hw_refine(pcm, params);
746 if (err < 0 && mode == SND_TRY)
747 dump_hw_params(params, "set", var, val, err);
751 int _snd_pcm_hw_param_set_mask(snd_pcm_hw_params_t *params,
752 snd_pcm_hw_param_t var, const snd_mask_t *val)
755 assert(hw_is_mask(var));
756 changed = snd_mask_refine(hw_param_mask(params, var), val);
758 params->cmask |= 1 << var;
759 params->rmask |= 1 << var;
764 /* Inside configuration space defined by PARAMS remove from PAR all values
765 not contained in MASK. Reduce configuration space accordingly.
766 This function can be called only for SND_PCM_HW_PARAM_ACCESS,
767 SND_PCM_HW_PARAM_FORMAT, SND_PCM_HW_PARAM_SUBFORMAT.
768 Return 0 on success or -EINVAL
769 if the configuration space is empty
771 int snd_pcm_hw_param_set_mask(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
773 snd_pcm_hw_param_t var, const snd_mask_t *val)
775 snd_pcm_hw_params_t save;
791 err = _snd_pcm_hw_param_set_mask(params, var, val);
794 if (mode != SND_TEST && params->rmask) {
795 err = snd_pcm_hw_refine(pcm, params);
806 /* Inside configuration space defined by PARAMS set PAR to the available value
807 nearest to VAL. Reduce configuration space accordingly.
808 This function cannot be called for SND_PCM_HW_PARAM_ACCESS,
809 SND_PCM_HW_PARAM_FORMAT, SND_PCM_HW_PARAM_SUBFORMAT.
810 Return the value found.
812 int snd_pcm_hw_param_set_near(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
813 snd_pcm_hw_param_t var,
814 unsigned int *val, int *dir)
816 snd_pcm_hw_params_t save;
818 unsigned int best = *val, saved_min;
820 unsigned int min, max;
822 int valdir = dir ? *dir : 0;
828 mindir = maxdir = valdir;
831 else if (maxdir == 0)
839 err = snd_pcm_hw_param_set_min(pcm, params, SND_CHANGE, var, &min, &mindir);
841 i = hw_param_interval(params, var);
842 if (!snd_interval_empty(i) && snd_interval_single(i)) {
843 err = snd_pcm_hw_param_get_min(params, var, val, dir);
845 dump_hw_params(params, "set_near", var, *val, err);
850 snd_pcm_hw_params_t params1;
851 if (min == saved_min && mindir == valdir)
854 err = snd_pcm_hw_param_set_max(pcm, ¶ms1, SND_CHANGE, var, &max, &maxdir);
857 if (boundary_nearer(max, maxdir, best, valdir, min, mindir)) {
863 err = snd_pcm_hw_param_set_max(pcm, params, SND_CHANGE, var, &max, &maxdir);
865 dump_hw_params(params, "set_near", var, *val, err);
872 err = snd_pcm_hw_param_set_last(pcm, params, var, val, dir);
874 err = snd_pcm_hw_param_set_first(pcm, params, var, val, dir);
876 dump_hw_params(params, "set_near", var, *val, err);
881 /* Inside configuration space defined by PARAMS set PAR to the available value
882 nearest to BEST after VAL (on equal difference values less than BEST are
884 Reduce configuration space accordingly.
885 This function cannot be called for SND_PCM_HW_PARAM_ACCESS,
886 SND_PCM_HW_PARAM_FORMAT, SND_PCM_HW_PARAM_SUBFORMAT.
887 Return the value found.
889 int snd_pcm_hw_param_set_next(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
890 snd_pcm_hw_param_t var,
891 unsigned int best, int bestdir,
892 unsigned int val, int *dir)
894 snd_pcm_hw_params_t save;
900 int valdir = dir ? *dir : 0;
904 boundary_sub(val, valdir, best, bestdir, &diff, &diffdir);
905 if (diff < 0 || (diff == 0 && diffdir < 0)) {
907 mindir = bestdir - diffdir;
909 maxdir = bestdir - 1;
912 mindir = bestdir + 1;
914 maxdir = bestdir + diffdir + 1;
922 (err = snd_pcm_hw_param_set_min(pcm, params, SND_CHANGE, var, &min, &mindir)) >= 0) {
923 snd_pcm_hw_params_t params1;
927 err = snd_pcm_hw_param_set_max(pcm, ¶ms1, SND_CHANGE, var, &max, &maxdir);
930 if (boundary_nearer(max, maxdir, best, bestdir, min, mindir)) {
938 err = snd_pcm_hw_param_set_max(pcm, params, SND_CHANGE, var, &max, &maxdir);
945 v = snd_pcm_hw_param_set_last(pcm, params, var, dir);
947 v = snd_pcm_hw_param_set_first(pcm, params, var, dir);
953 static int snd_pcm_hw_param_set_near_minmax(snd_pcm_t *pcm,
954 snd_pcm_hw_params_t *params,
955 snd_pcm_hw_param_t var,
956 unsigned int min, int *mindir,
957 unsigned int max, int *maxdir)
959 snd_pcm_hw_params_t tmp;
961 if (!boundary_lt(min, *mindir, max, *maxdir))
962 return snd_pcm_hw_param_set_near(pcm, params, var, &min, mindir);
964 err = snd_pcm_hw_param_set_near(pcm, &tmp, var, &min, mindir);
967 if (boundary_lt(min, *mindir, max, *maxdir)) {
969 err = snd_pcm_hw_param_set_near(pcm, &tmp, var, &max, maxdir);
974 err = snd_pcm_hw_param_set_minmax(pcm, params, SND_CHANGE, var, &min, mindir,
981 int snd_pcm_hw_param_refine_near(snd_pcm_t *pcm,
982 snd_pcm_hw_params_t *params,
983 snd_pcm_hw_param_t var,
984 const snd_pcm_hw_params_t *src)
986 unsigned int min, max;
987 int mindir, maxdir, err;
989 if ((err = snd_pcm_hw_param_get_min(src, var, &min, &mindir)) < 0)
991 if ((err = snd_pcm_hw_param_get_max(src, var, &max, &maxdir)) < 0)
993 if ((err = snd_pcm_hw_param_set_near_minmax(pcm, params, var,
994 min, &mindir, max, &maxdir)) < 0)
999 int snd_pcm_hw_param_refine_multiple(snd_pcm_t *pcm,
1000 snd_pcm_hw_params_t *params,
1001 snd_pcm_hw_param_t var,
1002 const snd_pcm_hw_params_t *src)
1004 const snd_interval_t *it = hw_param_interval_c(src, var);
1005 const snd_interval_t *st = hw_param_interval_c(params, var);
1006 if (snd_interval_single(it)) {
1007 unsigned int best = snd_interval_min(it), cur, prev;
1010 if (st->max < cur || (st->max == cur && st->openmax))
1012 if (it->min <= cur && ! (it->min == cur && st->openmin)) {
1013 if (! snd_pcm_hw_param_set(pcm, params, SND_TRY, var, cur, 0))
1022 return snd_pcm_hw_param_refine_near(pcm, params, var, src);
1025 /* ---- end of refinement functions ---- */
1027 int snd_pcm_hw_param_empty(const snd_pcm_hw_params_t *params,
1028 snd_pcm_hw_param_t var)
1030 if (hw_is_mask(var))
1031 return snd_mask_empty(hw_param_mask_c(params, var));
1032 if (hw_is_interval(var))
1033 return snd_interval_empty(hw_param_interval_c(params, var));
1038 int snd_pcm_hw_param_always_eq(const snd_pcm_hw_params_t *params,
1039 snd_pcm_hw_param_t var,
1040 const snd_pcm_hw_params_t *params1)
1042 if (hw_is_mask(var))
1043 return snd_mask_always_eq(hw_param_mask_c(params, var),
1044 hw_param_mask_c(params1, var));
1045 if (hw_is_interval(var))
1046 return snd_interval_always_eq(hw_param_interval_c(params, var),
1047 hw_param_interval_c(params1, var));
1052 int snd_pcm_hw_param_never_eq(const snd_pcm_hw_params_t *params,
1053 snd_pcm_hw_param_t var,
1054 const snd_pcm_hw_params_t *params1)
1056 if (hw_is_mask(var))
1057 return snd_mask_never_eq(hw_param_mask_c(params, var),
1058 hw_param_mask_c(params1, var));
1059 if (hw_is_interval(var))
1060 return snd_interval_never_eq(hw_param_interval_c(params, var),
1061 hw_param_interval_c(params1, var));
1067 #define CHOOSE_DEBUG
1070 /* Choose one configuration from configuration space defined by PARAMS
1071 The configuration chosen is that obtained fixing in this order:
1081 static int snd_pcm_hw_params_choose(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
1086 snd_output_stdio_attach(&log, stderr, 0);
1087 snd_output_printf(log, "CHOOSE called:\n");
1088 snd_pcm_hw_params_dump(params, log);
1091 err = snd_pcm_hw_param_set_first(pcm, params, SND_PCM_HW_PARAM_ACCESS, NULL, 0);
1094 err = snd_pcm_hw_param_set_first(pcm, params, SND_PCM_HW_PARAM_FORMAT, NULL, 0);
1097 err = snd_pcm_hw_param_set_first(pcm, params, SND_PCM_HW_PARAM_SUBFORMAT, NULL, 0);
1100 err = snd_pcm_hw_param_set_first(pcm, params, SND_PCM_HW_PARAM_CHANNELS, NULL, 0);
1103 err = snd_pcm_hw_param_set_first(pcm, params, SND_PCM_HW_PARAM_RATE, NULL, 0);
1106 if (pcm->minperiodtime > 0) {
1107 unsigned int min, max;
1109 err = snd_pcm_hw_param_get_min(params, SND_PCM_HW_PARAM_PERIOD_TIME, &min, &dir);
1111 err = snd_pcm_hw_param_get_max(params, SND_PCM_HW_PARAM_PERIOD_TIME, &max, &dir);
1112 if (err >= 0 && (long)min < pcm->minperiodtime &&
1113 (long)max > pcm->minperiodtime) {
1114 min = pcm->minperiodtime; dir = 1;
1115 snd_pcm_hw_param_set_min(pcm, params, SND_CHANGE, SND_PCM_HW_PARAM_PERIOD_TIME, &min, &dir);
1120 err = snd_pcm_hw_param_set_first(pcm, params, SND_PCM_HW_PARAM_PERIOD_TIME, NULL, 0);
1123 err = snd_pcm_hw_param_set_first(pcm, params, SND_PCM_HW_PARAM_PERIOD_SIZE, NULL, 0);
1126 err = snd_pcm_hw_param_set_last(pcm, params, SND_PCM_HW_PARAM_BUFFER_SIZE, NULL, 0);
1130 /* determine buffer size first */
1131 err = snd_pcm_hw_param_set_last(pcm, params, SND_PCM_HW_PARAM_BUFFER_SIZE, NULL, 0);
1134 err = snd_pcm_hw_param_set_first(pcm, params, SND_PCM_HW_PARAM_PERIOD_SIZE, NULL, 0);
1137 err = snd_pcm_hw_param_set_first(pcm, params, SND_PCM_HW_PARAM_PERIOD_TIME, NULL, 0);
1141 err = snd_pcm_hw_param_set_first(pcm, params, SND_PCM_HW_PARAM_TICK_TIME, NULL, 0);
1145 snd_output_printf(log, "choose done\n");
1146 snd_pcm_hw_params_dump(params, log);
1147 snd_output_close(log);
1153 static unsigned int snd_pcm_hw_param_count(const snd_pcm_hw_params_t *params,
1154 snd_pcm_hw_param_t var)
1156 if (hw_is_mask(var)) {
1157 const snd_mask_t *mask = hw_param_mask_c(params, var);
1158 return snd_mask_count(mask);
1160 if (hw_is_interval(var)) {
1161 const snd_interval_t *i = hw_param_interval_c(params, var);
1162 return snd_interval_max(i) - snd_interval_min(i) + 1;
1169 int _snd_pcm_hw_param_refine(snd_pcm_hw_params_t *params,
1170 snd_pcm_hw_param_t var,
1171 const snd_pcm_hw_params_t *src)
1174 if (hw_is_mask(var)) {
1175 snd_mask_t *d = hw_param_mask(params, var);
1176 const snd_mask_t *s = hw_param_mask_c(src, var);
1177 changed = snd_mask_refine(d, s);
1178 } else if (hw_is_interval(var)) {
1179 snd_interval_t *d = hw_param_interval(params, var);
1180 const snd_interval_t *s = hw_param_interval_c(src, var);
1181 changed = snd_interval_refine(d, s);
1183 return 0; /* NOP / reserved */
1185 params->cmask |= 1 << var;
1186 params->rmask |= 1 << var;
1192 static void _snd_pcm_hw_param_copy(snd_pcm_hw_params_t *params, snd_pcm_hw_param_t var,
1193 const snd_pcm_hw_params_t *src)
1195 if (hw_is_mask(var)) {
1196 snd_mask_t *d = hw_param_mask(params, var);
1197 const snd_mask_t *s = hw_param_mask_c(src, var);
1198 snd_mask_copy(d, s);
1199 params->cmask |= 1 << var;
1200 params->rmask |= 1 << var;
1203 if (hw_is_interval(var)) {
1204 snd_interval_t *d = hw_param_interval(params, var);
1205 const snd_interval_t *s = hw_param_interval_c(src, var);
1206 snd_interval_copy(d, s);
1207 params->cmask |= 1 << var;
1208 params->rmask |= 1 << var;
1215 void snd_pcm_hw_param_dump(const snd_pcm_hw_params_t *params,
1216 snd_pcm_hw_param_t var, snd_output_t *out)
1218 if (hw_is_mask(var)) {
1219 const snd_mask_t *mask = hw_param_mask_c(params, var);
1220 if (snd_mask_empty(mask))
1221 snd_output_puts(out, " NONE");
1222 else if (snd_mask_full(mask))
1223 snd_output_puts(out, " ALL");
1226 for (k = 0; k <= SND_MASK_MAX; ++k) {
1227 if (snd_mask_test(mask, k)) {
1230 case SND_PCM_HW_PARAM_ACCESS:
1231 s = snd_pcm_access_name(k);
1233 case SND_PCM_HW_PARAM_FORMAT:
1234 s = snd_pcm_format_name(k);
1236 case SND_PCM_HW_PARAM_SUBFORMAT:
1237 s = snd_pcm_subformat_name(k);
1244 snd_output_putc(out, ' ');
1245 snd_output_puts(out, s);
1252 if (hw_is_interval(var)) {
1253 snd_interval_print(hw_param_interval_c(params, var), out);
1259 #define HW_PARAM(v) [SND_PCM_HW_PARAM_##v] = #v
1261 static const char *const snd_pcm_hw_param_names[] = {
1264 HW_PARAM(SUBFORMAT),
1265 HW_PARAM(SAMPLE_BITS),
1266 HW_PARAM(FRAME_BITS),
1269 HW_PARAM(PERIOD_TIME),
1270 HW_PARAM(PERIOD_SIZE),
1271 HW_PARAM(PERIOD_BYTES),
1273 HW_PARAM(BUFFER_TIME),
1274 HW_PARAM(BUFFER_SIZE),
1275 HW_PARAM(BUFFER_BYTES),
1276 HW_PARAM(TICK_TIME),
1279 const char *snd_pcm_hw_param_name(snd_pcm_hw_param_t param)
1281 assert(param <= SND_PCM_HW_PARAM_LAST_INTERVAL);
1282 return snd_pcm_hw_param_names[param];
1288 struct _snd_pcm_hw_strategy {
1289 unsigned int badness_min, badness_max;
1290 int (*choose_param)(const snd_pcm_hw_params_t *params,
1292 const snd_pcm_hw_strategy_t *strategy);
1293 int (*next_value)(snd_pcm_hw_params_t *params,
1295 int value, int *dir,
1297 const snd_pcm_hw_strategy_t *strategy);
1298 int (*min_badness)(const snd_pcm_hw_params_t *params,
1299 unsigned int max_badness,
1301 const snd_pcm_hw_strategy_t *strategy);
1303 void (*free)(snd_pcm_hw_strategy_t *strategy);
1306 /* Independent badness */
1307 typedef struct _snd_pcm_hw_strategy_simple snd_pcm_hw_strategy_simple_t;
1309 struct _snd_pcm_hw_strategy_simple {
1312 int (*next_value)(snd_pcm_hw_params_t *params,
1314 int value, int *dir,
1316 const snd_pcm_hw_strategy_simple_t *par);
1317 unsigned int (*min_badness)(const snd_pcm_hw_params_t *params,
1320 const snd_pcm_hw_strategy_simple_t *par);
1322 void (*free)(snd_pcm_hw_strategy_simple_t *strategy);
1325 typedef struct _snd_pcm_hw_strategy_simple_near {
1328 } snd_pcm_hw_strategy_simple_near_t;
1330 typedef struct _snd_pcm_hw_strategy_simple_choices {
1332 /* choices need to be sorted on ascending badness */
1333 snd_pcm_hw_strategy_simple_choices_list_t *choices;
1334 } snd_pcm_hw_strategy_simple_choices_t;
1336 int snd_pcm_hw_params_strategy(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
1337 const snd_pcm_hw_strategy_t *strategy,
1338 unsigned int badness_min,
1339 unsigned int badness_max)
1341 snd_pcm_hw_params_t best_params;
1344 unsigned int best_badness;
1345 int badness = strategy->min_badness(params, badness_max, pcm, strategy);
1346 snd_pcm_hw_params_t params1;
1348 printf("\nBadness: %d\n", badness);
1349 snd_pcm_hw_params_dump(params, stdout);
1353 if ((unsigned int)badness > badness_min)
1354 badness_min = badness_min;
1355 var = strategy->choose_param(params, pcm, strategy);
1358 best_badness = UINT_MAX;
1362 value = strategy->next_value(¶ms1, var, value, &dir, pcm, strategy);
1365 badness = snd_pcm_hw_params_strategy(pcm, ¶ms1, strategy, badness_min, badness_max);
1367 if ((unsigned int) badness <= badness_min) {
1371 best_badness = badness;
1372 best_params = params1;
1373 badness_max = badness - 1;
1376 if (best_badness == UINT_MAX) {
1379 *params = best_params;
1380 return best_badness;
1383 void snd_pcm_hw_strategy_simple_free(snd_pcm_hw_strategy_t *strategy)
1385 snd_pcm_hw_strategy_simple_t *pars = strategy->private_data;
1387 for (k = 0; k <= SND_PCM_HW_PARAM_LAST_INTERVAL; ++k) {
1388 if (pars[k].valid && pars[k].free)
1389 pars[k].free(&pars[k]);
1394 int snd_pcm_hw_strategy_simple_choose_param(const snd_pcm_hw_params_t *params,
1395 snd_pcm_t *pcm ATTRIBUTE_UNUSED,
1396 const snd_pcm_hw_strategy_t *strategy)
1398 snd_pcm_hw_param_t var;
1400 const snd_pcm_hw_strategy_simple_t *pars = strategy->private_data;
1401 unsigned int min_choices = UINT_MAX;
1402 unsigned int min_order = UINT_MAX;
1403 for (var = 0; var <= SND_PCM_HW_PARAM_LAST_INTERVAL; ++var) {
1404 const snd_pcm_hw_strategy_simple_t *p = &pars[var];
1405 unsigned int choices;
1408 choices = snd_pcm_hw_param_count(params, var);
1411 assert(choices != 0);
1412 if (p->order < min_order ||
1413 (p->order == min_order &&
1414 choices < min_choices)) {
1415 min_order = p->order;
1416 min_choices = choices;
1423 int snd_pcm_hw_strategy_simple_next_value(snd_pcm_hw_params_t *params,
1424 snd_pcm_hw_param_t var,
1425 int value, int *dir,
1427 const snd_pcm_hw_strategy_t *strategy)
1429 const snd_pcm_hw_strategy_simple_t *pars = strategy->private_data;
1430 assert(pars[var].valid);
1431 return pars[var].next_value(params, var, value, dir, pcm, &pars[var]);
1435 int snd_pcm_hw_strategy_simple_min_badness(const snd_pcm_hw_params_t *params,
1436 unsigned int max_badness,
1438 const snd_pcm_hw_strategy_t *strategy)
1440 snd_pcm_hw_param_t var;
1441 unsigned int badness = 0;
1442 const snd_pcm_hw_strategy_simple_t *pars = strategy->private_data;
1443 for (var = 0; var <= SND_PCM_HW_PARAM_LAST_INTERVAL; ++var) {
1445 if (!pars[var].valid)
1447 b = pars[var].min_badness(params, var, pcm, &pars[var]);
1448 if (b > max_badness || max_badness - b < badness)
1456 void snd_pcm_hw_strategy_simple_near_free(snd_pcm_hw_strategy_simple_t *par)
1458 snd_pcm_hw_strategy_simple_near_t *p = par->private_data;
1462 unsigned int snd_pcm_hw_strategy_simple_near_min_badness(const snd_pcm_hw_params_t *params,
1463 snd_pcm_hw_param_t var,
1465 const snd_pcm_hw_strategy_simple_t *par)
1467 const snd_pcm_hw_strategy_simple_near_t *p = par->private_data;
1468 snd_pcm_hw_params_t params1 = *params;
1469 int value = snd_pcm_hw_param_set_near(pcm, ¶ms1, var, p->best, 0);
1472 diff = p->best - value;
1475 return diff * p->mul;
1478 int snd_pcm_hw_strategy_simple_near_next_value(snd_pcm_hw_params_t *params,
1479 snd_pcm_hw_param_t var,
1480 int value, int *dir,
1482 const snd_pcm_hw_strategy_simple_t *par)
1484 const snd_pcm_hw_strategy_simple_near_t *p = par->private_data;
1487 return snd_pcm_hw_param_set_near(pcm, params, var, p->best, dir);
1489 return snd_pcm_hw_param_set_next(pcm, params, var, p->best, 0, value, dir);
1492 void snd_pcm_hw_strategy_simple_choices_free(snd_pcm_hw_strategy_simple_t *par)
1494 snd_pcm_hw_strategy_simple_choices_t *p = par->private_data;
1495 // free(p->choices);
1499 unsigned int snd_pcm_hw_strategy_simple_choices_min_badness(const snd_pcm_hw_params_t *params,
1500 snd_pcm_hw_param_t var,
1502 const snd_pcm_hw_strategy_simple_t *par)
1504 const snd_pcm_hw_strategy_simple_choices_t *p = par->private_data;
1506 for (k = 0; k < p->count; ++k) {
1507 if (snd_pcm_hw_param_set(pcm, (snd_pcm_hw_params_t *) params, SND_TEST, var, p->choices[k].value, 0))
1508 return p->choices[k].badness;
1514 int snd_pcm_hw_strategy_simple_choices_next_value(snd_pcm_hw_params_t *params,
1515 snd_pcm_hw_param_t var,
1516 int value, int *dir,
1518 const snd_pcm_hw_strategy_simple_t *par)
1520 const snd_pcm_hw_strategy_simple_choices_t *p = par->private_data;
1523 for (; k < p->count; ++k) {
1524 if (p->choices[k].value == (unsigned int) value) {
1530 for (; k < p->count; ++k) {
1531 unsigned int v = p->choices[k].value;
1532 int err = snd_pcm_hw_param_set(pcm, params, SND_TRY, var, v, 0);
1541 void snd_pcm_hw_strategy_free(snd_pcm_hw_strategy_t *strategy)
1544 strategy->free(strategy);
1548 int snd_pcm_hw_strategy_simple(snd_pcm_hw_strategy_t **strategyp,
1549 unsigned int badness_min,
1550 unsigned int badness_max)
1552 snd_pcm_hw_strategy_simple_t *data;
1553 snd_pcm_hw_strategy_t *s;
1555 data = calloc(SND_PCM_HW_PARAM_LAST_INTERVAL + 1, sizeof(*data));
1558 s = calloc(1, sizeof(*s));
1563 s->choose_param = snd_pcm_hw_strategy_simple_choose_param;
1564 s->next_value = snd_pcm_hw_strategy_simple_next_value;
1565 s->min_badness = snd_pcm_hw_strategy_simple_min_badness;
1566 s->badness_min = badness_min;
1567 s->badness_max = badness_max;
1568 s->private_data = data;
1569 s->free = snd_pcm_hw_strategy_simple_free;
1574 int snd_pcm_hw_strategy_simple_near(snd_pcm_hw_strategy_t *strategy,
1576 snd_pcm_hw_param_t var,
1580 snd_pcm_hw_strategy_simple_t *s = strategy->private_data;
1581 snd_pcm_hw_strategy_simple_near_t *data;
1583 assert(var <= SND_PCM_HW_PARAM_LAST_INTERVAL);
1585 data = calloc(1, sizeof(*data));
1593 s->next_value = snd_pcm_hw_strategy_simple_near_next_value;
1594 s->min_badness = snd_pcm_hw_strategy_simple_near_min_badness;
1595 s->private_data = data;
1596 s->free = snd_pcm_hw_strategy_simple_near_free;
1600 int snd_pcm_hw_strategy_simple_choices(snd_pcm_hw_strategy_t *strategy,
1602 snd_pcm_hw_param_t var,
1604 snd_pcm_hw_strategy_simple_choices_list_t *choices)
1606 snd_pcm_hw_strategy_simple_t *s = strategy->private_data;
1607 snd_pcm_hw_strategy_simple_choices_t *data;
1609 assert(var <= SND_PCM_HW_PARAM_LAST_INTERVAL);
1611 data = calloc(1, sizeof(*data));
1614 data->count = count;
1615 data->choices = choices;
1619 s->next_value = snd_pcm_hw_strategy_simple_choices_next_value;
1620 s->min_badness = snd_pcm_hw_strategy_simple_choices_min_badness;
1621 s->private_data = data;
1622 s->free = snd_pcm_hw_strategy_simple_choices_free;
1626 int snd_pcm_hw_params_try_explain_failure1(snd_pcm_t *pcm,
1627 snd_pcm_hw_params_t *fail,
1628 snd_pcm_hw_params_t *success,
1632 snd_pcm_hw_param_t var;
1633 snd_pcm_hw_params_t i;
1636 for (var = 0; var <= SND_PCM_HW_PARAM_LAST_INTERVAL; var++) {
1639 _snd_pcm_hw_param_copy(&i, var, fail);
1640 err = snd_pcm_hw_refine(pcm, &i);
1642 snd_pcm_hw_params_try_explain_failure1(pcm, fail, &i, depth - 1, out) < 0)
1644 snd_output_printf(out, "%s: ", snd_pcm_hw_param_name(var));
1645 snd_pcm_hw_param_dump(fail, var, out);
1646 snd_output_putc(out, '\n');
1652 int snd_pcm_hw_params_try_explain_failure(snd_pcm_t *pcm,
1653 snd_pcm_hw_params_t *fail,
1654 snd_pcm_hw_params_t *success,
1658 snd_pcm_hw_params_t i, any;
1660 snd_pcm_hw_param_t var;
1662 assert(pcm && fail);
1663 for (var = 0; var <= SND_PCM_HW_PARAM_LAST_INTERVAL; var++) {
1664 if (!snd_pcm_hw_param_empty(fail, var))
1666 snd_output_printf(out, "%s is empty\n", snd_pcm_hw_param_name(var));
1672 err = snd_pcm_hw_refine(pcm, &i);
1674 snd_output_printf(out, "Configuration is virtually correct\n");
1678 snd_pcm_hw_params_any(pcm, &any);
1681 return snd_pcm_hw_params_try_explain_failure1(pcm, fail, success, depth, out);
1686 typedef struct _snd_pcm_hw_rule snd_pcm_hw_rule_t;
1688 typedef int (*snd_pcm_hw_rule_func_t)(snd_pcm_hw_params_t *params,
1689 const snd_pcm_hw_rule_t *rule);
1691 struct _snd_pcm_hw_rule {
1693 snd_pcm_hw_rule_func_t func;
1698 static int snd_pcm_hw_rule_mul(snd_pcm_hw_params_t *params,
1699 const snd_pcm_hw_rule_t *rule)
1702 snd_interval_mul(hw_param_interval_c(params, rule->deps[0]),
1703 hw_param_interval_c(params, rule->deps[1]), &t);
1704 return snd_interval_refine(hw_param_interval(params, rule->var), &t);
1707 static int snd_pcm_hw_rule_div(snd_pcm_hw_params_t *params,
1708 const snd_pcm_hw_rule_t *rule)
1711 snd_interval_div(hw_param_interval_c(params, rule->deps[0]),
1712 hw_param_interval_c(params, rule->deps[1]), &t);
1713 return snd_interval_refine(hw_param_interval(params, rule->var), &t);
1716 static int snd_pcm_hw_rule_muldivk(snd_pcm_hw_params_t *params,
1717 const snd_pcm_hw_rule_t *rule)
1720 snd_interval_muldivk(hw_param_interval_c(params, rule->deps[0]),
1721 hw_param_interval_c(params, rule->deps[1]),
1722 (unsigned long) rule->private_data, &t);
1723 return snd_interval_refine(hw_param_interval(params, rule->var), &t);
1726 static int snd_pcm_hw_rule_mulkdiv(snd_pcm_hw_params_t *params,
1727 const snd_pcm_hw_rule_t *rule)
1730 snd_interval_mulkdiv(hw_param_interval_c(params, rule->deps[0]),
1731 (unsigned long) rule->private_data,
1732 hw_param_interval_c(params, rule->deps[1]), &t);
1733 return snd_interval_refine(hw_param_interval(params, rule->var), &t);
1736 static int snd_pcm_hw_rule_format(snd_pcm_hw_params_t *params,
1737 const snd_pcm_hw_rule_t *rule)
1741 snd_mask_t *mask = hw_param_mask(params, rule->var);
1742 snd_interval_t *i = hw_param_interval(params, rule->deps[0]);
1743 for (k = 0; k <= SND_PCM_FORMAT_LAST; k++) {
1745 if (!snd_pcm_format_mask_test(mask, k))
1747 bits = snd_pcm_format_physical_width(k);
1750 if (!snd_interval_test(i, (unsigned int) bits)) {
1751 snd_pcm_format_mask_reset(mask, k);
1752 if (snd_mask_empty(mask))
1761 static int snd_pcm_hw_rule_sample_bits(snd_pcm_hw_params_t *params,
1762 const snd_pcm_hw_rule_t *rule)
1764 unsigned int min, max;
1766 snd_interval_t *i = hw_param_interval(params, rule->var);
1767 snd_mask_t *mask = hw_param_mask(params, rule->deps[0]);
1771 for (k = 0; k <= SND_PCM_FORMAT_LAST; k++) {
1773 if (!snd_pcm_format_mask_test(mask, k))
1775 bits = snd_pcm_format_physical_width(k);
1778 if (min > (unsigned)bits)
1780 if (max < (unsigned)bits)
1783 c = snd_interval_refine_min(i, min, 0);
1788 c = snd_interval_refine_max(i, max, 0);
1796 static const snd_pcm_hw_rule_t refine_rules[] = {
1798 .var = SND_PCM_HW_PARAM_FORMAT,
1799 .func = snd_pcm_hw_rule_format,
1800 .deps = { SND_PCM_HW_PARAM_SAMPLE_BITS, -1 },
1804 .var = SND_PCM_HW_PARAM_SAMPLE_BITS,
1805 .func = snd_pcm_hw_rule_sample_bits,
1806 .deps = { SND_PCM_HW_PARAM_FORMAT,
1807 SND_PCM_HW_PARAM_SAMPLE_BITS, -1 },
1811 .var = SND_PCM_HW_PARAM_SAMPLE_BITS,
1812 .func = snd_pcm_hw_rule_div,
1813 .deps = { SND_PCM_HW_PARAM_FRAME_BITS,
1814 SND_PCM_HW_PARAM_CHANNELS, -1 },
1818 .var = SND_PCM_HW_PARAM_FRAME_BITS,
1819 .func = snd_pcm_hw_rule_mul,
1820 .deps = { SND_PCM_HW_PARAM_SAMPLE_BITS,
1821 SND_PCM_HW_PARAM_CHANNELS, -1 },
1825 .var = SND_PCM_HW_PARAM_FRAME_BITS,
1826 .func = snd_pcm_hw_rule_mulkdiv,
1827 .deps = { SND_PCM_HW_PARAM_PERIOD_BYTES,
1828 SND_PCM_HW_PARAM_PERIOD_SIZE, -1 },
1829 .private_data = (void*) 8,
1832 .var = SND_PCM_HW_PARAM_FRAME_BITS,
1833 .func = snd_pcm_hw_rule_mulkdiv,
1834 .deps = { SND_PCM_HW_PARAM_BUFFER_BYTES,
1835 SND_PCM_HW_PARAM_BUFFER_SIZE, -1 },
1836 .private_data = (void*) 8,
1839 .var = SND_PCM_HW_PARAM_CHANNELS,
1840 .func = snd_pcm_hw_rule_div,
1841 .deps = { SND_PCM_HW_PARAM_FRAME_BITS,
1842 SND_PCM_HW_PARAM_SAMPLE_BITS, -1 },
1846 .var = SND_PCM_HW_PARAM_RATE,
1847 .func = snd_pcm_hw_rule_mulkdiv,
1848 .deps = { SND_PCM_HW_PARAM_PERIOD_SIZE,
1849 SND_PCM_HW_PARAM_PERIOD_TIME, -1 },
1850 .private_data = (void*) 1000000,
1853 .var = SND_PCM_HW_PARAM_RATE,
1854 .func = snd_pcm_hw_rule_mulkdiv,
1855 .deps = { SND_PCM_HW_PARAM_BUFFER_SIZE,
1856 SND_PCM_HW_PARAM_BUFFER_TIME, -1 },
1857 .private_data = (void*) 1000000,
1860 .var = SND_PCM_HW_PARAM_PERIODS,
1861 .func = snd_pcm_hw_rule_div,
1862 .deps = { SND_PCM_HW_PARAM_BUFFER_SIZE,
1863 SND_PCM_HW_PARAM_PERIOD_SIZE, -1 },
1867 .var = SND_PCM_HW_PARAM_PERIOD_SIZE,
1868 .func = snd_pcm_hw_rule_div,
1869 .deps = { SND_PCM_HW_PARAM_BUFFER_SIZE,
1870 SND_PCM_HW_PARAM_PERIODS, -1 },
1874 .var = SND_PCM_HW_PARAM_PERIOD_SIZE,
1875 .func = snd_pcm_hw_rule_mulkdiv,
1876 .deps = { SND_PCM_HW_PARAM_PERIOD_BYTES,
1877 SND_PCM_HW_PARAM_FRAME_BITS, -1 },
1878 .private_data = (void*) 8,
1881 .var = SND_PCM_HW_PARAM_PERIOD_SIZE,
1882 .func = snd_pcm_hw_rule_muldivk,
1883 .deps = { SND_PCM_HW_PARAM_PERIOD_TIME,
1884 SND_PCM_HW_PARAM_RATE, -1 },
1885 .private_data = (void*) 1000000,
1888 .var = SND_PCM_HW_PARAM_BUFFER_SIZE,
1889 .func = snd_pcm_hw_rule_mul,
1890 .deps = { SND_PCM_HW_PARAM_PERIOD_SIZE,
1891 SND_PCM_HW_PARAM_PERIODS, -1 },
1895 .var = SND_PCM_HW_PARAM_BUFFER_SIZE,
1896 .func = snd_pcm_hw_rule_mulkdiv,
1897 .deps = { SND_PCM_HW_PARAM_BUFFER_BYTES,
1898 SND_PCM_HW_PARAM_FRAME_BITS, -1 },
1899 .private_data = (void*) 8,
1902 .var = SND_PCM_HW_PARAM_BUFFER_SIZE,
1903 .func = snd_pcm_hw_rule_muldivk,
1904 .deps = { SND_PCM_HW_PARAM_BUFFER_TIME,
1905 SND_PCM_HW_PARAM_RATE, -1 },
1906 .private_data = (void*) 1000000,
1909 .var = SND_PCM_HW_PARAM_PERIOD_BYTES,
1910 .func = snd_pcm_hw_rule_muldivk,
1911 .deps = { SND_PCM_HW_PARAM_PERIOD_SIZE,
1912 SND_PCM_HW_PARAM_FRAME_BITS, -1 },
1913 .private_data = (void*) 8,
1916 .var = SND_PCM_HW_PARAM_BUFFER_BYTES,
1917 .func = snd_pcm_hw_rule_muldivk,
1918 .deps = { SND_PCM_HW_PARAM_BUFFER_SIZE,
1919 SND_PCM_HW_PARAM_FRAME_BITS, -1 },
1920 .private_data = (void*) 8,
1923 .var = SND_PCM_HW_PARAM_PERIOD_TIME,
1924 .func = snd_pcm_hw_rule_mulkdiv,
1925 .deps = { SND_PCM_HW_PARAM_PERIOD_SIZE,
1926 SND_PCM_HW_PARAM_RATE, -1 },
1927 .private_data = (void*) 1000000,
1930 .var = SND_PCM_HW_PARAM_BUFFER_TIME,
1931 .func = snd_pcm_hw_rule_mulkdiv,
1932 .deps = { SND_PCM_HW_PARAM_BUFFER_SIZE,
1933 SND_PCM_HW_PARAM_RATE, -1 },
1934 .private_data = (void*) 1000000,
1938 #define RULES (sizeof(refine_rules) / sizeof(refine_rules[0]))
1940 static const snd_mask_t refine_masks[SND_PCM_HW_PARAM_LAST_MASK - SND_PCM_HW_PARAM_FIRST_MASK + 1] = {
1941 [SND_PCM_HW_PARAM_ACCESS - SND_PCM_HW_PARAM_FIRST_MASK] = {
1944 [SND_PCM_HW_PARAM_FORMAT - SND_PCM_HW_PARAM_FIRST_MASK] = {
1945 .bits = { 0x81ffffff, 0xfff},
1947 [SND_PCM_HW_PARAM_SUBFORMAT - SND_PCM_HW_PARAM_FIRST_MASK] = {
1952 static const snd_interval_t refine_intervals[SND_PCM_HW_PARAM_LAST_INTERVAL - SND_PCM_HW_PARAM_FIRST_INTERVAL + 1] = {
1953 [SND_PCM_HW_PARAM_SAMPLE_BITS - SND_PCM_HW_PARAM_FIRST_INTERVAL] = {
1954 .min = 1, .max = UINT_MAX,
1955 .openmin = 0, .openmax = 0, .integer = 1, .empty = 0,
1957 [SND_PCM_HW_PARAM_FRAME_BITS - SND_PCM_HW_PARAM_FIRST_INTERVAL] = {
1958 .min = 1, .max = UINT_MAX,
1959 .openmin = 0, .openmax = 0, .integer = 1, .empty = 0,
1961 [SND_PCM_HW_PARAM_CHANNELS - SND_PCM_HW_PARAM_FIRST_INTERVAL] = {
1962 .min = 1, .max = UINT_MAX,
1963 .openmin = 0, .openmax = 0, .integer = 1, .empty = 0,
1965 [SND_PCM_HW_PARAM_RATE - SND_PCM_HW_PARAM_FIRST_INTERVAL] = {
1966 .min = 1, .max = UINT_MAX,
1967 .openmin = 0, .openmax = 0, .integer = 0, .empty = 0,
1969 [SND_PCM_HW_PARAM_PERIOD_TIME - SND_PCM_HW_PARAM_FIRST_INTERVAL] = {
1970 .min = 0, .max = UINT_MAX,
1971 .openmin = 0, .openmax = 0, .integer = 0, .empty = 0,
1973 [SND_PCM_HW_PARAM_PERIOD_SIZE - SND_PCM_HW_PARAM_FIRST_INTERVAL] = {
1974 .min = 0, .max = UINT_MAX,
1975 .openmin = 0, .openmax = 0, .integer = 0, .empty = 0,
1977 [SND_PCM_HW_PARAM_PERIOD_BYTES - SND_PCM_HW_PARAM_FIRST_INTERVAL] = {
1978 .min = 0, .max = UINT_MAX,
1979 .openmin = 0, .openmax = 0, .integer = 0, .empty = 0,
1981 [SND_PCM_HW_PARAM_PERIODS - SND_PCM_HW_PARAM_FIRST_INTERVAL] = {
1982 .min = 0, .max = UINT_MAX,
1983 .openmin = 0, .openmax = 0, .integer = 0, .empty = 0,
1985 [SND_PCM_HW_PARAM_BUFFER_TIME - SND_PCM_HW_PARAM_FIRST_INTERVAL] = {
1986 .min = 1, .max = UINT_MAX,
1987 .openmin = 0, .openmax = 0, .integer = 0, .empty = 0,
1989 [SND_PCM_HW_PARAM_BUFFER_SIZE - SND_PCM_HW_PARAM_FIRST_INTERVAL] = {
1990 .min = 1, .max = UINT_MAX,
1991 .openmin = 0, .openmax = 0, .integer = 1, .empty = 0,
1993 [SND_PCM_HW_PARAM_BUFFER_BYTES - SND_PCM_HW_PARAM_FIRST_INTERVAL] = {
1994 .min = 1, .max = UINT_MAX,
1995 .openmin = 0, .openmax = 0, .integer = 1, .empty = 0,
1997 [SND_PCM_HW_PARAM_TICK_TIME - SND_PCM_HW_PARAM_FIRST_INTERVAL] = {
1998 .min = 0, .max = UINT_MAX,
1999 .openmin = 0, .openmax = 0, .integer = 0, .empty = 0,
2007 int snd_pcm_hw_refine_soft(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params)
2011 unsigned int rstamps[RULES];
2012 unsigned int vstamps[SND_PCM_HW_PARAM_LAST_INTERVAL + 1];
2013 unsigned int stamp = 2;
2017 snd_output_stdio_attach(&log, stderr, 0);
2018 snd_output_printf(log, "refine_soft '%s' (begin)\n", pcm->name);
2019 snd_pcm_hw_params_dump(params, log);
2022 for (k = SND_PCM_HW_PARAM_FIRST_MASK; k <= SND_PCM_HW_PARAM_LAST_MASK; k++) {
2023 if (!(params->rmask & (1 << k)))
2025 changed = snd_mask_refine(hw_param_mask(params, k),
2026 &refine_masks[k - SND_PCM_HW_PARAM_FIRST_MASK]);
2028 params->cmask |= 1 << k;
2033 for (k = SND_PCM_HW_PARAM_FIRST_INTERVAL; k <= SND_PCM_HW_PARAM_LAST_INTERVAL; k++) {
2034 if (!(params->rmask & (1 << k)))
2036 changed = snd_interval_refine(hw_param_interval(params, k),
2037 &refine_intervals[k - SND_PCM_HW_PARAM_FIRST_INTERVAL]);
2039 params->cmask |= 1 << k;
2044 for (k = 0; k < RULES; k++)
2046 for (k = 0; k <= SND_PCM_HW_PARAM_LAST_INTERVAL; k++)
2047 vstamps[k] = (params->rmask & (1 << k)) ? 1 : 0;
2050 for (k = 0; k < RULES; k++) {
2051 const snd_pcm_hw_rule_t *r = &refine_rules[k];
2054 for (d = 0; r->deps[d] >= 0; d++) {
2055 if (vstamps[r->deps[d]] > rstamps[k]) {
2063 snd_output_printf(log, "Rule %d (%p): ", k, r->func);
2065 snd_output_printf(log, "%s=", snd_pcm_hw_param_name(r->var));
2066 snd_pcm_hw_param_dump(params, r->var, log);
2067 snd_output_puts(log, " -> ");
2070 changed = r->func(params, r);
2073 snd_pcm_hw_param_dump(params, r->var, log);
2074 for (d = 0; r->deps[d] >= 0; d++) {
2075 snd_output_printf(log, " %s=", snd_pcm_hw_param_name(r->deps[d]));
2076 snd_pcm_hw_param_dump(params, r->deps[d], log);
2078 snd_output_putc(log, '\n');
2081 if (changed && r->var >= 0) {
2082 params->cmask |= 1 << r->var;
2083 vstamps[r->var] = stamp;
2091 if (!params->msbits) {
2092 i = hw_param_interval(params, SND_PCM_HW_PARAM_SAMPLE_BITS);
2093 if (snd_interval_single(i))
2094 params->msbits = snd_interval_value(i);
2097 if (!params->rate_den) {
2098 i = hw_param_interval(params, SND_PCM_HW_PARAM_RATE);
2099 if (snd_interval_single(i)) {
2100 params->rate_num = snd_interval_value(i);
2101 params->rate_den = 1;
2108 snd_output_printf(log, "refine_soft '%s' (end-%i)\n", pcm->name, changed);
2109 snd_pcm_hw_params_dump(params, log);
2110 snd_output_close(log);
2115 int _snd_pcm_hw_params_refine(snd_pcm_hw_params_t *params,
2117 const snd_pcm_hw_params_t *src)
2119 int changed, err = 0;
2121 for (k = 0; k <= SND_PCM_HW_PARAM_LAST_INTERVAL; ++k) {
2122 if (!(vars & (1 << k)))
2124 changed = _snd_pcm_hw_param_refine(params, k, src);
2128 params->info &= src->info;
2129 params->flags = src->flags; /* propagate all flags to slave */
2133 int snd_pcm_hw_refine_slave(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
2134 int (*cprepare)(snd_pcm_t *pcm,
2135 snd_pcm_hw_params_t *params),
2136 int (*cchange)(snd_pcm_t *pcm,
2137 snd_pcm_hw_params_t *params,
2138 snd_pcm_hw_params_t *sparams),
2139 int (*sprepare)(snd_pcm_t *pcm,
2140 snd_pcm_hw_params_t *params),
2141 int (*schange)(snd_pcm_t *pcm,
2142 snd_pcm_hw_params_t *params,
2143 snd_pcm_hw_params_t *sparams),
2144 int (*srefine)(snd_pcm_t *pcm,
2145 snd_pcm_hw_params_t *sparams))
2151 snd_pcm_hw_params_t sparams;
2153 unsigned int cmask, changed;
2155 snd_output_stdio_attach(&log, stderr, 0);
2157 err = cprepare(pcm, params);
2160 err = sprepare(pcm, &sparams);
2162 SNDERR("Slave PCM not usable");
2166 snd_output_printf(log, "hw_refine_slave - enter '%s'\n", pcm->name);
2169 cmask = params->cmask;
2172 snd_output_printf(log, "schange '%s' (client)\n", pcm->name);
2173 snd_pcm_hw_params_dump(params, log);
2174 snd_output_printf(log, "schange '%s' (slave)\n", pcm->name);
2175 snd_pcm_hw_params_dump(&sparams, log);
2177 err = schange(pcm, params, &sparams);
2180 snd_output_printf(log, "srefine '%s' (client)\n", pcm->name);
2181 snd_pcm_hw_params_dump(params, log);
2182 snd_output_printf(log, "srefine '%s' (slave)\n", pcm->name);
2183 snd_pcm_hw_params_dump(&sparams, log);
2185 err = srefine(pcm, &sparams);
2188 snd_output_printf(log, "srefine '%s', err < 0 (%i) (client)\n", pcm->name, err);
2189 snd_pcm_hw_params_dump(params, log);
2190 snd_output_printf(log, "srefine '%s', err < 0 (%i) (slave)\n", pcm->name, err);
2191 snd_pcm_hw_params_dump(&sparams, log);
2193 cchange(pcm, params, &sparams);
2198 snd_output_printf(log, "schange '%s', err < 0 (%i) (client)\n", pcm->name, err);
2199 snd_pcm_hw_params_dump(params, log);
2200 snd_output_printf(log, "schange '%s', err < 0 (%i) (slave)\n", pcm->name, err);
2201 snd_pcm_hw_params_dump(&sparams, log);
2203 cchange(pcm, params, &sparams);
2207 snd_output_printf(log, "cchange '%s'\n", pcm->name);
2209 err = cchange(pcm, params, &sparams);
2213 snd_output_printf(log, "refine_soft '%s'\n", pcm->name);
2215 err = snd_pcm_hw_refine_soft(pcm, params);
2216 changed = params->cmask;
2217 params->cmask |= cmask;
2221 snd_output_printf(log, "refine_soft ok '%s'\n", pcm->name);
2225 snd_output_printf(log, "refine_slave - leave '%s'\n", pcm->name);
2226 snd_output_close(log);
2231 int snd_pcm_hw_params_slave(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
2232 int (*cchange)(snd_pcm_t *pcm,
2233 snd_pcm_hw_params_t *params,
2234 snd_pcm_hw_params_t *sparams),
2235 int (*sprepare)(snd_pcm_t *pcm,
2236 snd_pcm_hw_params_t *params),
2237 int (*schange)(snd_pcm_t *pcm,
2238 snd_pcm_hw_params_t *params,
2239 snd_pcm_hw_params_t *sparams),
2240 int (*sparams)(snd_pcm_t *pcm,
2241 snd_pcm_hw_params_t *sparams))
2244 snd_pcm_hw_params_t slave_params;
2246 err = sprepare(pcm, &slave_params);
2248 err = schange(pcm, params, &slave_params);
2250 err = sparams(pcm, &slave_params);
2252 cchange(pcm, params, &slave_params);
2256 static int snd_pcm_sw_params_default(snd_pcm_t *pcm, snd_pcm_sw_params_t *params)
2258 assert(pcm && params);
2260 params->proto = SNDRV_PCM_VERSION;
2261 params->tstamp_mode = SND_PCM_TSTAMP_NONE;
2262 params->tstamp_type = pcm->tstamp_type;
2263 params->period_step = 1;
2264 params->sleep_min = 0;
2265 params->avail_min = pcm->period_size;
2266 params->xfer_align = 1;
2267 params->start_threshold = 1;
2268 params->stop_threshold = pcm->buffer_size;
2269 params->silence_threshold = 0;
2270 params->silence_size = 0;
2271 params->boundary = pcm->buffer_size;
2272 while (params->boundary * 2 <= LONG_MAX - pcm->buffer_size)
2273 params->boundary *= 2;
2278 #define REFINE_DEBUG
2281 int snd_pcm_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
2286 snd_output_stdio_attach(&log, stderr, 0);
2288 assert(pcm && params);
2290 snd_output_printf(log, "REFINE called:\n");
2291 snd_pcm_hw_params_dump(params, log);
2293 res = pcm->ops->hw_refine(pcm->op_arg, params);
2295 snd_output_printf(log, "refine done - result = %i\n", res);
2296 snd_pcm_hw_params_dump(params, log);
2297 snd_output_close(log);
2302 /* Install one of the configurations present in configuration
2303 space defined by PARAMS.
2304 The configuration chosen is that obtained fixing in this order:
2312 Return 0 on success otherwise a negative error code
2314 int _snd_pcm_hw_params_internal(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
2317 snd_pcm_sw_params_t sw;
2319 err = snd_pcm_hw_refine(pcm, params);
2322 snd_pcm_hw_params_choose(pcm, params);
2324 err = snd_pcm_hw_free(pcm);
2328 err = pcm->ops->hw_params(pcm->op_arg, params);
2333 INTERNAL(snd_pcm_hw_params_get_access)(params, &pcm->access);
2334 INTERNAL(snd_pcm_hw_params_get_format)(params, &pcm->format);
2335 INTERNAL(snd_pcm_hw_params_get_subformat)(params, &pcm->subformat);
2336 INTERNAL(snd_pcm_hw_params_get_channels)(params, &pcm->channels);
2337 INTERNAL(snd_pcm_hw_params_get_rate)(params, &pcm->rate, 0);
2338 INTERNAL(snd_pcm_hw_params_get_period_time)(params, &pcm->period_time, 0);
2339 INTERNAL(snd_pcm_hw_params_get_period_size)(params, &pcm->period_size, 0);
2340 INTERNAL(snd_pcm_hw_params_get_buffer_size)(params, &pcm->buffer_size);
2341 pcm->sample_bits = snd_pcm_format_physical_width(pcm->format);
2342 pcm->frame_bits = pcm->sample_bits * pcm->channels;
2343 fb = pcm->frame_bits;
2349 pcm->min_align = min_align;
2351 pcm->hw_flags = params->flags;
2352 pcm->info = params->info;
2353 pcm->msbits = params->msbits;
2354 pcm->rate_num = params->rate_num;
2355 pcm->rate_den = params->rate_den;
2356 pcm->fifo_size = params->fifo_size;
2358 /* Default sw params */
2359 memset(&sw, 0, sizeof(sw));
2360 snd_pcm_sw_params_default(pcm, &sw);
2361 err = snd_pcm_sw_params(pcm, &sw);
2365 pcm->access == SND_PCM_ACCESS_MMAP_INTERLEAVED ||
2366 pcm->access == SND_PCM_ACCESS_MMAP_NONINTERLEAVED ||
2367 pcm->access == SND_PCM_ACCESS_MMAP_COMPLEX) {
2368 err = snd_pcm_mmap(pcm);