• Home
  • History
  • Annotate
  • Raw
  • Download
  • only in /netgear-R7000-V1.0.7.12_1.2.5/ap/gpl/iserver/alsa-lib-1.0.26/src/pcm/

Lines Matching defs:*

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"
24 #ifndef NDEBUG
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");
32 snd_output_t *out;
34 if (! verbose || ! *verbose || atoi(verbose) < 1)
35 return;
36 if (snd_output_stdio_attach(&out, stderr, 0) < 0)
37 return;
38 fprintf(stderr, "ALSA ERROR hw_params: %s (%s)\n",
39 type, snd_pcm_hw_param_name(var));
40 fprintf(stderr, " value = ");
41 switch (var) {
42 case SND_PCM_HW_PARAM_ACCESS:
43 fprintf(stderr, "%s", snd_pcm_access_name(val));
44 break;
45 case SND_PCM_HW_PARAM_FORMAT:
46 fprintf(stderr, "%s", snd_pcm_format_name(val));
47 break;
48 case SND_PCM_HW_PARAM_SUBFORMAT:
49 fprintf(stderr, "%s", snd_pcm_subformat_name(val));
50 break;
51 default:
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);
58 #else
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)
63 #endif
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;
69 #else
70 return var >= SND_PCM_HW_PARAM_FIRST_MASK &&
71 var <= SND_PCM_HW_PARAM_LAST_MASK;
72 #endif
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;
96 return;
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;
102 return;
104 assert(0);
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)
116 unsigned int k;
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);
122 params->rmask = ~0U;
123 params->cmask = 0;
124 params->info = ~0U;
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))
136 return -EINVAL;
137 if (dir)
138 *dir = 0;
139 if (val)
140 *val = snd_mask_value(mask);
141 return 0;
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))
145 return -EINVAL;
146 if (dir)
147 *dir = i->openmin;
148 if (val)
149 *val = snd_interval_value(i);
150 return 0;
152 assert(0);
153 return -EINVAL;
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));
163 if (dir)
164 *dir = 0;
165 if (val)
166 *val = snd_mask_min(m);
167 return 0;
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));
171 if (dir)
172 *dir = i->openmin;
173 if (val)
174 *val = snd_interval_min(i);
175 return 0;
177 assert(0);
178 return 0;
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));
188 if (dir)
189 *dir = 0;
190 if (val)
191 *val = snd_mask_max(m);
192 return 0;
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));
196 if (dir)
197 *dir = - (int) i->openmax;
198 if (val)
199 *val = snd_interval_max(i);
200 return 0;
202 assert(0);
203 return 0;
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)
232 int changed;
233 assert(hw_is_interval(var));
234 changed = snd_interval_refine(hw_param_interval(params, var), val);
235 if (changed) {
236 params->cmask |= 1 << var;
237 params->rmask |= 1 << var;
239 return changed;
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;
253 } else {
254 assert(0);
258 static int _snd_pcm_hw_param_set_integer(snd_pcm_hw_params_t *params,
259 snd_pcm_hw_param_t var)
261 int changed;
262 assert(hw_is_interval(var));
263 changed = snd_interval_setinteger(hw_param_interval(params, var));
264 if (changed) {
265 params->cmask |= 1 << var;
266 params->rmask |= 1 << var;
268 return changed;
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,
277 snd_set_mode_t mode,
278 snd_pcm_hw_param_t var)
280 snd_pcm_hw_params_t save;
281 int err;
282 switch (mode) {
283 case SND_CHANGE:
284 break;
285 case SND_TRY:
286 save = *params;
287 break;
288 case SND_TEST:
289 save = *params;
290 params = &save;
291 break;
292 default:
293 assert(0);
294 return -EINVAL;
296 err = _snd_pcm_hw_param_set_integer(params, var);
297 if (err < 0)
298 goto _fail;
299 if (params->rmask) {
300 err = snd_pcm_hw_refine(pcm, params);
301 if (err < 0)
302 goto _fail;
304 return 0;
305 _fail:
306 if (mode == SND_TRY)
307 *params = save;
308 return err;
311 static int _snd_pcm_hw_param_set_first(snd_pcm_hw_params_t *params,
312 snd_pcm_hw_param_t var)
314 int changed;
315 if (hw_is_mask(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));
319 else {
320 assert(0);
321 return -EINVAL;
323 if (changed > 0) {
324 params->cmask |= 1 << var;
325 params->rmask |= 1 << var;
327 return changed;
331 /* Inside configuration space defined by PARAMS remove from PAR all
332 values > minimum. Reduce configuration space accordingly.
333 Return the minimum.
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)
340 int err;
342 err = _snd_pcm_hw_param_set_first(params, var);
343 if (err < 0)
344 return err;
345 if (params->rmask) {
346 err = snd_pcm_hw_refine(pcm, params);
347 if (err < 0)
348 return err;
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)
356 int changed;
357 if (hw_is_mask(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));
361 else {
362 assert(0);
363 return -EINVAL;
365 if (changed > 0) {
366 params->cmask |= 1 << var;
367 params->rmask |= 1 << var;
369 return changed;
373 /* Inside configuration space defined by PARAMS remove from PAR all
374 values < maximum. Reduce configuration space accordingly.
375 Return the maximum.
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)
382 int err;
384 err = _snd_pcm_hw_param_set_last(params, var);
385 if (err < 0)
386 return err;
387 if (params->rmask) {
388 err = snd_pcm_hw_refine(pcm, params);
389 if (err < 0)
390 return err;
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)
398 int changed;
399 int openmin = 0;
400 if (dir) {
401 if (dir > 0) {
402 openmin = 1;
403 } else if (dir < 0) {
404 if (val > 0) {
405 openmin = 1;
406 val--;
410 if (hw_is_mask(var))
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);
414 else {
415 assert(0);
416 return -EINVAL;
418 if (changed) {
419 params->cmask |= 1 << var;
420 params->rmask |= 1 << var;
422 return changed;
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,
430 snd_set_mode_t mode,
431 snd_pcm_hw_param_t var, unsigned int *val, int *dir)
433 snd_pcm_hw_params_t save;
434 int err;
435 switch (mode) {
436 case SND_CHANGE:
437 break;
438 case SND_TRY:
439 save = *params;
440 break;
441 case SND_TEST:
442 save = *params;
443 params = &save;
444 break;
445 default:
446 assert(0);
447 return -EINVAL;
449 err = _snd_pcm_hw_param_set_min(params, var, *val, dir ? *dir : 0);
450 if (err < 0)
451 goto _fail;
452 if ((mode != SND_TEST || hw_is_interval(var)) && params->rmask) {
453 err = snd_pcm_hw_refine(pcm, params);
454 if (err < 0)
455 goto _fail;
456 if (snd_pcm_hw_param_empty(params, var)) {
457 err = -ENOENT;
458 goto _fail;
461 return snd_pcm_hw_param_get_min(params, var, val, dir);
462 _fail:
463 if (mode == SND_TRY)
464 *params = save;
465 if (err < 0 && mode == SND_TRY)
466 dump_hw_params(params, "set_min", var, *val, err);
467 return 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)
473 int changed;
474 int openmax = 0;
475 if (dir) {
476 if (dir < 0) {
477 openmax = 1;
478 } else if (dir > 0) {
479 openmax = 1;
480 val++;
483 if (hw_is_mask(var)) {
484 if (val == 0 && openmax) {
485 snd_mask_none(hw_param_mask(params, var));
486 changed = -EINVAL;
487 } else
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);
491 else {
492 assert(0);
493 return -EINVAL;
495 if (changed) {
496 params->cmask |= 1 << var;
497 params->rmask |= 1 << var;
499 return changed;
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,
507 snd_set_mode_t mode,
508 snd_pcm_hw_param_t var, unsigned int *val, int *dir)
510 snd_pcm_hw_params_t save;
511 int err;
512 switch (mode) {
513 case SND_CHANGE:
514 break;
515 case SND_TRY:
516 save = *params;
517 break;
518 case SND_TEST:
519 save = *params;
520 params = &save;
521 break;
522 default:
523 assert(0);
524 return -EINVAL;
526 err = _snd_pcm_hw_param_set_max(params, var, *val, dir ? *dir : 0);
527 if (err < 0)
528 goto _fail;
529 if ((mode != SND_TEST || hw_is_interval(var)) && params->rmask) {
530 err = snd_pcm_hw_refine(pcm, params);
531 if (err < 0)
532 goto _fail;
533 if (snd_pcm_hw_param_empty(params, var)) {
534 err = -ENOENT;
535 goto _fail;
538 return snd_pcm_hw_param_get_max(params, var, val, dir);
539 _fail:
540 if (mode == SND_TRY)
541 *params = save;
542 if (err < 0 && mode == SND_TRY)
543 dump_hw_params(params, "set_max", var, *val, err);
544 return 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)
552 int changed, c1, c2;
553 int openmin = 0, openmax = 0;
554 if (mindir) {
555 if (mindir > 0) {
556 openmin = 1;
557 } else if (mindir < 0) {
558 if (min > 0) {
559 openmin = 1;
560 min--;
564 if (maxdir) {
565 if (maxdir < 0) {
566 openmax = 1;
567 } else if (maxdir > 0) {
568 openmax = 1;
569 max++;
572 if (hw_is_mask(var)) {
573 snd_mask_t *mask = hw_param_mask(params, var);
574 if (max == 0 && openmax) {
575 snd_mask_none(mask);
576 changed = -EINVAL;
577 } else {
578 c1 = snd_mask_refine_min(mask, min + !!openmin);
579 if (c1 < 0)
580 changed = c1;
581 else {
582 c2 = snd_mask_refine_max(mask, max - !!openmax);
583 if (c2 < 0)
584 changed = c2;
585 else
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);
593 if (c1 < 0)
594 changed = c1;
595 else {
596 c2 = snd_interval_refine_max(i, max, openmax);
597 if (c2 < 0)
598 changed = c2;
599 else
600 changed = (c1 || c2);
602 } else {
603 assert(0);
604 return -EINVAL;
606 if (changed) {
607 params->cmask |= 1 << var;
608 params->rmask |= 1 << var;
610 return changed;
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,
618 snd_set_mode_t mode,
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;
624 int err;
625 switch (mode) {
626 case SND_CHANGE:
627 break;
628 case SND_TRY:
629 save = *params;
630 break;
631 case SND_TEST:
632 save = *params;
633 params = &save;
634 break;
635 default:
636 assert(0);
637 return -EINVAL;
639 err = _snd_pcm_hw_param_set_minmax(params, var,
640 *min, mindir ? *mindir : 0,
641 *max, maxdir ? *maxdir : 0);
642 if (err < 0)
643 goto _fail;
644 if ((mode != SND_TEST || hw_is_interval(var)) && params->rmask) {
645 err = snd_pcm_hw_refine(pcm, params);
646 if (err < 0)
647 goto _fail;
649 err = snd_pcm_hw_param_get_min(params, var, min, mindir);
650 if (err < 0)
651 return err;
652 return snd_pcm_hw_param_get_max(params, var, max, maxdir);
653 _fail:
654 if (mode == SND_TRY)
655 *params = save;
656 if (err < 0)
657 dump_hw_params(params, "set_minmax", var, *min, err);
658 return 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)
664 int changed;
665 if (hw_is_mask(var)) {
666 snd_mask_t *m = hw_param_mask(params, var);
667 if (val == 0 && dir < 0) {
668 changed = -EINVAL;
669 snd_mask_none(m);
670 } else {
671 if (dir > 0)
672 val++;
673 else if (dir < 0)
674 val--;
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) {
680 changed = -EINVAL;
681 snd_interval_none(i);
682 } else if (dir == 0)
683 changed = snd_interval_refine_set(i, val);
684 else {
685 snd_interval_t t;
686 t.openmin = 1;
687 t.openmax = 1;
688 t.empty = 0;
689 t.integer = 0;
690 if (dir < 0) {
691 t.min = val - 1;
692 t.max = val;
693 } else {
694 t.min = val;
695 t.max = val+1;
697 changed = snd_interval_refine(i, &t);
699 } else {
700 assert(0);
701 return -EINVAL;
703 if (changed) {
704 params->cmask |= 1 << var;
705 params->rmask |= 1 << var;
707 return changed;
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,
715 snd_set_mode_t mode,
716 snd_pcm_hw_param_t var, unsigned int val, int dir)
718 snd_pcm_hw_params_t save;
719 int err;
720 switch (mode) {
721 case SND_CHANGE:
722 break;
723 case SND_TRY:
724 save = *params;
725 break;
726 case SND_TEST:
727 save = *params;
728 params = &save;
729 break;
730 default:
731 assert(0);
732 return -EINVAL;
734 err = _snd_pcm_hw_param_set(params, var, val, dir);
735 if (err < 0)
736 goto _fail;
737 if ((mode != SND_TEST || hw_is_interval(var)) && params->rmask) {
738 err = snd_pcm_hw_refine(pcm, params);
739 if (err < 0)
740 goto _fail;
742 return 0;
743 _fail:
744 if (mode == SND_TRY)
745 *params = save;
746 if (err < 0 && mode == SND_TRY)
747 dump_hw_params(params, "set", var, val, err);
748 return 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)
754 int changed;
755 assert(hw_is_mask(var));
756 changed = snd_mask_refine(hw_param_mask(params, var), val);
757 if (changed) {
758 params->cmask |= 1 << var;
759 params->rmask |= 1 << var;
761 return changed;
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,
772 snd_set_mode_t mode,
773 snd_pcm_hw_param_t var, const snd_mask_t *val)
775 snd_pcm_hw_params_t save;
776 int err;
777 switch (mode) {
778 case SND_CHANGE:
779 break;
780 case SND_TRY:
781 save = *params;
782 break;
783 case SND_TEST:
784 save = *params;
785 params = &save;
786 break;
787 default:
788 assert(0);
789 return -EINVAL;
791 err = _snd_pcm_hw_param_set_mask(params, var, val);
792 if (err < 0)
793 goto _fail;
794 if (mode != SND_TEST && params->rmask) {
795 err = snd_pcm_hw_refine(pcm, params);
796 if (err < 0)
797 goto _fail;
799 return 0;
800 _fail:
801 if (mode == SND_TRY)
802 *params = save;
803 return err;
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;
817 int err;
818 unsigned int best = *val, saved_min;
819 int last = 0;
820 unsigned int min, max;
821 int mindir, maxdir;
822 int valdir = dir ? *dir : 0;
823 snd_interval_t *i;
824 /* FIXME */
825 if (best > INT_MAX)
826 best = INT_MAX;
827 min = max = best;
828 mindir = maxdir = valdir;
829 if (maxdir > 0)
830 maxdir = 0;
831 else if (maxdir == 0)
832 maxdir = -1;
833 else {
834 maxdir = 1;
835 max--;
837 save = *params;
838 saved_min = min;
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);
844 if (err < 0)
845 dump_hw_params(params, "set_near", var, *val, err);
846 return err;
849 if (err >= 0) {
850 snd_pcm_hw_params_t params1;
851 if (min == saved_min && mindir == valdir)
852 goto _end;
853 params1 = save;
854 err = snd_pcm_hw_param_set_max(pcm, &params1, SND_CHANGE, var, &max, &maxdir);
855 if (err < 0)
856 goto _end;
857 if (boundary_nearer(max, maxdir, best, valdir, min, mindir)) {
858 *params = params1;
859 last = 1;
861 } else {
862 *params = save;
863 err = snd_pcm_hw_param_set_max(pcm, params, SND_CHANGE, var, &max, &maxdir);
864 if (err < 0) {
865 dump_hw_params(params, "set_near", var, *val, err);
866 return err;
868 last = 1;
870 _end:
871 if (last)
872 err = snd_pcm_hw_param_set_last(pcm, params, var, val, dir);
873 else
874 err = snd_pcm_hw_param_set_first(pcm, params, var, val, dir);
875 if (err < 0)
876 dump_hw_params(params, "set_near", var, *val, err);
877 return err;
880 #if 0
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
883 returned first).
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;
895 int v, err;
896 int last = 0;
897 int min, max;
898 int mindir, maxdir;
899 int diff, diffdir;
900 int valdir = dir ? *dir : 0;
901 /* FIXME */
902 if (best > INT_MAX)
903 best = INT_MAX;
904 boundary_sub(val, valdir, best, bestdir, &diff, &diffdir);
905 if (diff < 0 || (diff == 0 && diffdir < 0)) {
906 min = best - diff;
907 mindir = bestdir - diffdir;
908 max = val;
909 maxdir = bestdir - 1;
910 } else {
911 min = val;
912 mindir = bestdir + 1;
913 max = best + diff;
914 maxdir = bestdir + diffdir + 1;
916 min += mindir / 2;
917 mindir %= 2;
918 max += maxdir / 2;
919 maxdir %= 2;
920 save = *params;
921 if (min >= 0 &&
922 (err = snd_pcm_hw_param_set_min(pcm, params, SND_CHANGE, var, &min, &mindir)) >= 0) {
923 snd_pcm_hw_params_t params1;
924 if (max < 0)
925 goto _end;
926 params1 = save;
927 err = snd_pcm_hw_param_set_max(pcm, &params1, SND_CHANGE, var, &max, &maxdir);
928 if (err < 0)
929 goto _end;
930 if (boundary_nearer(max, maxdir, best, bestdir, min, mindir)) {
931 *params = params1;
932 last = 1;
934 } else {
935 if (max < 0)
936 return -EINVAL;
937 *params = save;
938 err = snd_pcm_hw_param_set_max(pcm, params, SND_CHANGE, var, &max, &maxdir);
939 if (err < 0)
940 return max;
941 last = 1;
943 _end:
944 if (last)
945 v = snd_pcm_hw_param_set_last(pcm, params, var, dir);
946 else
947 v = snd_pcm_hw_param_set_first(pcm, params, var, dir);
948 assert(v >= 0);
949 return v;
951 #endif
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;
960 int err;
961 if (!boundary_lt(min, *mindir, max, *maxdir))
962 return snd_pcm_hw_param_set_near(pcm, params, var, &min, mindir);
963 tmp = *params;
964 err = snd_pcm_hw_param_set_near(pcm, &tmp, var, &min, mindir);
965 if (err < 0)
966 return err;
967 if (boundary_lt(min, *mindir, max, *maxdir)) {
968 tmp = *params;
969 err = snd_pcm_hw_param_set_near(pcm, &tmp, var, &max, maxdir);
970 } else {
971 max = min;
972 *maxdir = *mindir;
974 err = snd_pcm_hw_param_set_minmax(pcm, params, SND_CHANGE, var, &min, mindir,
975 &max, maxdir);
976 if (err < 0)
977 return err;
978 return 0;
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)
990 return err;
991 if ((err = snd_pcm_hw_param_get_max(src, var, &max, &maxdir)) < 0)
992 return err;
993 if ((err = snd_pcm_hw_param_set_near_minmax(pcm, params, var,
994 min, &mindir, max, &maxdir)) < 0)
995 return err;
996 return 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;
1008 cur = best;
1009 for (;;) {
1010 if (st->max < cur || (st->max == cur && st->openmax))
1011 break;
1012 if (it->min <= cur && ! (it->min == cur && st->openmin)) {
1013 if (! snd_pcm_hw_param_set(pcm, params, SND_TRY, var, cur, 0))
1014 return 0; /* ok */
1016 prev = cur;
1017 cur += best;
1018 if (cur <= prev)
1019 break;
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));
1034 assert(0);
1035 return -EINVAL;
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));
1048 assert(0);
1049 return -EINVAL;
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));
1062 assert(0);
1063 return -EINVAL;
1066 #if 0
1067 #define CHOOSE_DEBUG
1068 #endif
1070 /* Choose one configuration from configuration space defined by PARAMS
1071 The configuration chosen is that obtained fixing in this order:
1072 first access
1073 first format
1074 first subformat
1075 min channels
1076 min rate
1077 min period time
1078 max buffer size
1079 min tick time
1081 static int snd_pcm_hw_params_choose(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
1083 int err;
1084 #ifdef CHOOSE_DEBUG
1085 snd_output_t *log;
1086 snd_output_stdio_attach(&log, stderr, 0);
1087 snd_output_printf(log, "CHOOSE called:\n");
1088 snd_pcm_hw_params_dump(params, log);
1089 #endif
1091 err = snd_pcm_hw_param_set_first(pcm, params, SND_PCM_HW_PARAM_ACCESS, NULL, 0);
1092 if (err < 0)
1093 return err;
1094 err = snd_pcm_hw_param_set_first(pcm, params, SND_PCM_HW_PARAM_FORMAT, NULL, 0);
1095 if (err < 0)
1096 return err;
1097 err = snd_pcm_hw_param_set_first(pcm, params, SND_PCM_HW_PARAM_SUBFORMAT, NULL, 0);
1098 if (err < 0)
1099 return err;
1100 err = snd_pcm_hw_param_set_first(pcm, params, SND_PCM_HW_PARAM_CHANNELS, NULL, 0);
1101 if (err < 0)
1102 return err;
1103 err = snd_pcm_hw_param_set_first(pcm, params, SND_PCM_HW_PARAM_RATE, NULL, 0);
1104 if (err < 0)
1105 return err;
1106 if (pcm->minperiodtime > 0) {
1107 unsigned int min, max;
1108 int dir = 1;
1109 err = snd_pcm_hw_param_get_min(params, SND_PCM_HW_PARAM_PERIOD_TIME, &min, &dir);
1110 if (err >= 0)
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);
1118 if (pcm->compat) {
1119 /* old mode */
1120 err = snd_pcm_hw_param_set_first(pcm, params, SND_PCM_HW_PARAM_PERIOD_TIME, NULL, 0);
1121 if (err < 0)
1122 return err;
1123 err = snd_pcm_hw_param_set_first(pcm, params, SND_PCM_HW_PARAM_PERIOD_SIZE, NULL, 0);
1124 if (err < 0)
1125 return err;
1126 err = snd_pcm_hw_param_set_last(pcm, params, SND_PCM_HW_PARAM_BUFFER_SIZE, NULL, 0);
1127 if (err < 0)
1128 return err;
1129 } else {
1130 /* determine buffer size first */
1131 err = snd_pcm_hw_param_set_last(pcm, params, SND_PCM_HW_PARAM_BUFFER_SIZE, NULL, 0);
1132 if (err < 0)
1133 return err;
1134 err = snd_pcm_hw_param_set_first(pcm, params, SND_PCM_HW_PARAM_PERIOD_SIZE, NULL, 0);
1135 if (err < 0)
1136 return err;
1137 err = snd_pcm_hw_param_set_first(pcm, params, SND_PCM_HW_PARAM_PERIOD_TIME, NULL, 0);
1138 if (err < 0)
1139 return err;
1141 err = snd_pcm_hw_param_set_first(pcm, params, SND_PCM_HW_PARAM_TICK_TIME, NULL, 0);
1142 if (err < 0)
1143 return err;
1144 #ifdef CHOOSE_DEBUG
1145 snd_output_printf(log, "choose done\n");
1146 snd_pcm_hw_params_dump(params, log);
1147 snd_output_close(log);
1148 #endif
1149 return 0;
1152 #if 0
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;
1164 assert(0);
1165 return 0;
1167 #endif
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)
1173 int changed = 0;
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);
1182 } else
1183 return 0; /* NOP / reserved */
1184 if (changed) {
1185 params->cmask |= 1 << var;
1186 params->rmask |= 1 << var;
1188 return changed;
1191 #if 0
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;
1201 return;
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;
1209 return;
1211 assert(0);
1213 #endif
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");
1224 else {
1225 unsigned int k;
1226 for (k = 0; k <= SND_MASK_MAX; ++k) {
1227 if (snd_mask_test(mask, k)) {
1228 const char *s;
1229 switch (var) {
1230 case SND_PCM_HW_PARAM_ACCESS:
1231 s = snd_pcm_access_name(k);
1232 break;
1233 case SND_PCM_HW_PARAM_FORMAT:
1234 s = snd_pcm_format_name(k);
1235 break;
1236 case SND_PCM_HW_PARAM_SUBFORMAT:
1237 s = snd_pcm_subformat_name(k);
1238 break;
1239 default:
1240 assert(0);
1241 s = NULL;
1243 if (s) {
1244 snd_output_putc(out, ' ');
1245 snd_output_puts(out, s);
1250 return;
1252 if (hw_is_interval(var)) {
1253 snd_interval_print(hw_param_interval_c(params, var), out);
1254 return;
1256 assert(0);
1259 #define HW_PARAM(v) [SND_PCM_HW_PARAM_##v] = #v
1261 static const char *const snd_pcm_hw_param_names[] = {
1262 HW_PARAM(ACCESS),
1263 HW_PARAM(FORMAT),
1264 HW_PARAM(SUBFORMAT),
1265 HW_PARAM(SAMPLE_BITS),
1266 HW_PARAM(FRAME_BITS),
1267 HW_PARAM(CHANNELS),
1268 HW_PARAM(RATE),
1269 HW_PARAM(PERIOD_TIME),
1270 HW_PARAM(PERIOD_SIZE),
1271 HW_PARAM(PERIOD_BYTES),
1272 HW_PARAM(PERIODS),
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];
1285 #if 0
1286 /* Strategies */
1288 struct _snd_pcm_hw_strategy {
1289 unsigned int badness_min, badness_max;
1290 int (*choose_param)(const snd_pcm_hw_params_t *params,
1291 snd_pcm_t *pcm,
1292 const snd_pcm_hw_strategy_t *strategy);
1293 int (*next_value)(snd_pcm_hw_params_t *params,
1294 unsigned int param,
1295 int value, int *dir,
1296 snd_pcm_t *pcm,
1297 const snd_pcm_hw_strategy_t *strategy);
1298 int (*min_badness)(const snd_pcm_hw_params_t *params,
1299 unsigned int max_badness,
1300 snd_pcm_t *pcm,
1301 const snd_pcm_hw_strategy_t *strategy);
1302 void *private_data;
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 {
1310 int valid;
1311 unsigned int order;
1312 int (*next_value)(snd_pcm_hw_params_t *params,
1313 unsigned int param,
1314 int value, int *dir,
1315 snd_pcm_t *pcm,
1316 const snd_pcm_hw_strategy_simple_t *par);
1317 unsigned int (*min_badness)(const snd_pcm_hw_params_t *params,
1318 unsigned int param,
1319 snd_pcm_t *pcm,
1320 const snd_pcm_hw_strategy_simple_t *par);
1321 void *private_data;
1322 void (*free)(snd_pcm_hw_strategy_simple_t *strategy);
1325 typedef struct _snd_pcm_hw_strategy_simple_near {
1326 int best;
1327 unsigned int mul;
1328 } snd_pcm_hw_strategy_simple_near_t;
1330 typedef struct _snd_pcm_hw_strategy_simple_choices {
1331 unsigned int count;
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;
1342 int var;
1343 int value, dir;
1344 unsigned int best_badness;
1345 int badness = strategy->min_badness(params, badness_max, pcm, strategy);
1346 snd_pcm_hw_params_t params1;
1347 #if 0
1348 printf("\nBadness: %d\n", badness);
1349 snd_pcm_hw_params_dump(params, stdout);
1350 #endif
1351 if (badness < 0)
1352 return badness;
1353 if ((unsigned int)badness > badness_min)
1354 badness_min = badness_min;
1355 var = strategy->choose_param(params, pcm, strategy);
1356 if (var < 0)
1357 return badness;
1358 best_badness = UINT_MAX;
1359 value = -1;
1360 while (1) {
1361 params1 = *params;
1362 value = strategy->next_value(&params1, var, value, &dir, pcm, strategy);
1363 if (value < 0)
1364 break;
1365 badness = snd_pcm_hw_params_strategy(pcm, &params1, strategy, badness_min, badness_max);
1366 if (badness >= 0) {
1367 if ((unsigned int) badness <= badness_min) {
1368 *params = params1;
1369 return badness;
1371 best_badness = badness;
1372 best_params = params1;
1373 badness_max = badness - 1;
1376 if (best_badness == UINT_MAX) {
1377 return -EINVAL;
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;
1386 int k;
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]);
1391 free(pars);
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;
1399 int best_var = -1;
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;
1406 if (!p->valid)
1407 continue;
1408 choices = snd_pcm_hw_param_count(params, var);
1409 if (choices == 1)
1410 continue;
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;
1417 best_var = var;
1420 return best_var;
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,
1426 snd_pcm_t *pcm,
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,
1437 snd_pcm_t *pcm,
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) {
1444 unsigned int b;
1445 if (!pars[var].valid)
1446 continue;
1447 b = pars[var].min_badness(params, var, pcm, &pars[var]);
1448 if (b > max_badness || max_badness - b < badness)
1449 return -E2BIG;
1450 badness += b;
1452 return 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;
1459 free(p);
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,
1464 snd_pcm_t *pcm,
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, &params1, var, p->best, 0);
1470 int diff;
1471 assert(value >= 0);
1472 diff = p->best - value;
1473 if (diff < 0)
1474 diff = -diff;
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,
1481 snd_pcm_t *pcm,
1482 const snd_pcm_hw_strategy_simple_t *par)
1484 const snd_pcm_hw_strategy_simple_near_t *p = par->private_data;
1485 if (value < 0) {
1486 *dir = 0;
1487 return snd_pcm_hw_param_set_near(pcm, params, var, p->best, dir);
1488 } else
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);
1496 free(p);
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,
1501 snd_pcm_t *pcm,
1502 const snd_pcm_hw_strategy_simple_t *par)
1504 const snd_pcm_hw_strategy_simple_choices_t *p = par->private_data;
1505 unsigned int k;
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;
1510 assert(0);
1511 return UINT_MAX;
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,
1517 snd_pcm_t *pcm,
1518 const snd_pcm_hw_strategy_simple_t *par)
1520 const snd_pcm_hw_strategy_simple_choices_t *p = par->private_data;
1521 unsigned int k = 0;
1522 if (value >= 0) {
1523 for (; k < p->count; ++k) {
1524 if (p->choices[k].value == (unsigned int) value) {
1525 k++;
1526 break;
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);
1533 if (err < 0)
1534 continue;
1535 *dir = 0;
1536 return v;
1538 return -1;
1541 void snd_pcm_hw_strategy_free(snd_pcm_hw_strategy_t *strategy)
1543 if (strategy->free)
1544 strategy->free(strategy);
1545 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;
1554 assert(strategyp);
1555 data = calloc(SND_PCM_HW_PARAM_LAST_INTERVAL + 1, sizeof(*data));
1556 if (!data)
1557 return -ENOMEM;
1558 s = calloc(1, sizeof(*s));
1559 if (!s) {
1560 free(data);
1561 return -ENOMEM;
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;
1570 *strategyp = s;
1571 return 0;
1574 int snd_pcm_hw_strategy_simple_near(snd_pcm_hw_strategy_t *strategy,
1575 int order,
1576 snd_pcm_hw_param_t var,
1577 unsigned int best,
1578 unsigned int mul)
1580 snd_pcm_hw_strategy_simple_t *s = strategy->private_data;
1581 snd_pcm_hw_strategy_simple_near_t *data;
1582 assert(strategy);
1583 assert(var <= SND_PCM_HW_PARAM_LAST_INTERVAL);
1584 assert(!s->valid);
1585 data = calloc(1, sizeof(*data));
1586 if (!data)
1587 return -ENOMEM;
1588 data->best = best;
1589 data->mul = mul;
1590 s += var;
1591 s->order = order;
1592 s->valid = 1;
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;
1597 return 0;
1600 int snd_pcm_hw_strategy_simple_choices(snd_pcm_hw_strategy_t *strategy,
1601 int order,
1602 snd_pcm_hw_param_t var,
1603 unsigned int count,
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;
1608 assert(strategy);
1609 assert(var <= SND_PCM_HW_PARAM_LAST_INTERVAL);
1610 assert(!s->valid);
1611 data = calloc(1, sizeof(*data));
1612 if (!data)
1613 return -ENOMEM;
1614 data->count = count;
1615 data->choices = choices;
1616 s += var;
1617 s->valid = 1;
1618 s->order = order;
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;
1623 return 0;
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,
1629 unsigned int depth,
1630 snd_output_t *out)
1632 snd_pcm_hw_param_t var;
1633 snd_pcm_hw_params_t i;
1634 if (depth < 1)
1635 return -ENOENT;
1636 for (var = 0; var <= SND_PCM_HW_PARAM_LAST_INTERVAL; var++) {
1637 int err;
1638 i = *success;
1639 _snd_pcm_hw_param_copy(&i, var, fail);
1640 err = snd_pcm_hw_refine(pcm, &i);
1641 if (err == 0 &&
1642 snd_pcm_hw_params_try_explain_failure1(pcm, fail, &i, depth - 1, out) < 0)
1643 continue;
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');
1647 return 0;
1649 return -ENOENT;
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,
1655 unsigned int depth,
1656 snd_output_t *out)
1658 snd_pcm_hw_params_t i, any;
1659 int err;
1660 snd_pcm_hw_param_t var;
1661 int done = 0;
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))
1665 continue;
1666 snd_output_printf(out, "%s is empty\n", snd_pcm_hw_param_name(var));
1667 done = 1;
1669 if (done)
1670 return 0;
1671 i = *fail;
1672 err = snd_pcm_hw_refine(pcm, &i);
1673 if (err == 0) {
1674 snd_output_printf(out, "Configuration is virtually correct\n");
1675 return 0;
1677 if (!success) {
1678 snd_pcm_hw_params_any(pcm, &any);
1679 success = &any;
1681 return snd_pcm_hw_params_try_explain_failure1(pcm, fail, success, depth, out);
1684 #endif
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 {
1692 int var;
1693 snd_pcm_hw_rule_func_t func;
1694 int deps[4];
1695 void *private_data;
1698 static int snd_pcm_hw_rule_mul(snd_pcm_hw_params_t *params,
1699 const snd_pcm_hw_rule_t *rule)
1701 snd_interval_t t;
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)
1710 snd_interval_t t;
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)
1719 snd_interval_t t;
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)
1729 snd_interval_t t;
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)
1739 int changed = 0;
1740 snd_pcm_format_t k;
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++) {
1744 int bits;
1745 if (!snd_pcm_format_mask_test(mask, k))
1746 continue;
1747 bits = snd_pcm_format_physical_width(k);
1748 if (bits < 0)
1749 continue;
1750 if (!snd_interval_test(i, (unsigned int) bits)) {
1751 snd_pcm_format_mask_reset(mask, k);
1752 if (snd_mask_empty(mask))
1753 return -EINVAL;
1754 changed = 1;
1757 return changed;
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;
1765 snd_pcm_format_t k;
1766 snd_interval_t *i = hw_param_interval(params, rule->var);
1767 snd_mask_t *mask = hw_param_mask(params, rule->deps[0]);
1768 int c, changed = 0;
1769 min = UINT_MAX;
1770 max = 0;
1771 for (k = 0; k <= SND_PCM_FORMAT_LAST; k++) {
1772 int bits;
1773 if (!snd_pcm_format_mask_test(mask, k))
1774 continue;
1775 bits = snd_pcm_format_physical_width(k);
1776 if (bits < 0)
1777 continue;
1778 if (min > (unsigned)bits)
1779 min = bits;
1780 if (max < (unsigned)bits)
1781 max = bits;
1783 c = snd_interval_refine_min(i, min, 0);
1784 if (c < 0)
1785 return c;
1786 if (c)
1787 changed = 1;
1788 c = snd_interval_refine_max(i, max, 0);
1789 if (c < 0)
1790 return c;
1791 if (c)
1792 changed = 1;
1793 return changed;
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 },
1801 .private_data = 0,
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 },
1808 .private_data = 0,
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 },
1815 .private_data = 0,
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 },
1822 .private_data = 0,
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 },
1843 .private_data = 0,
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 },
1864 .private_data = 0,
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 },
1871 .private_data = 0,
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 },
1892 .private_data = 0,
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] = {
1942 .bits = { 0x1f },
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] = {
1948 .bits = { 0x1 },
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,
2003 #if 0
2004 #define RULES_DEBUG
2005 #endif
2007 int snd_pcm_hw_refine_soft(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params)
2009 unsigned int k;
2010 snd_interval_t *i;
2011 unsigned int rstamps[RULES];
2012 unsigned int vstamps[SND_PCM_HW_PARAM_LAST_INTERVAL + 1];
2013 unsigned int stamp = 2;
2014 int changed, again;
2015 #ifdef RULES_DEBUG
2016 snd_output_t *log;
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);
2020 #endif
2022 for (k = SND_PCM_HW_PARAM_FIRST_MASK; k <= SND_PCM_HW_PARAM_LAST_MASK; k++) {
2023 if (!(params->rmask & (1 << k)))
2024 continue;
2025 changed = snd_mask_refine(hw_param_mask(params, k),
2026 &refine_masks[k - SND_PCM_HW_PARAM_FIRST_MASK]);
2027 if (changed)
2028 params->cmask |= 1 << k;
2029 if (changed < 0)
2030 goto _err;
2033 for (k = SND_PCM_HW_PARAM_FIRST_INTERVAL; k <= SND_PCM_HW_PARAM_LAST_INTERVAL; k++) {
2034 if (!(params->rmask & (1 << k)))
2035 continue;
2036 changed = snd_interval_refine(hw_param_interval(params, k),
2037 &refine_intervals[k - SND_PCM_HW_PARAM_FIRST_INTERVAL]);
2038 if (changed)
2039 params->cmask |= 1 << k;
2040 if (changed < 0)
2041 goto _err;
2044 for (k = 0; k < RULES; k++)
2045 rstamps[k] = 0;
2046 for (k = 0; k <= SND_PCM_HW_PARAM_LAST_INTERVAL; k++)
2047 vstamps[k] = (params->rmask & (1 << k)) ? 1 : 0;
2048 do {
2049 again = 0;
2050 for (k = 0; k < RULES; k++) {
2051 const snd_pcm_hw_rule_t *r = &refine_rules[k];
2052 unsigned int d;
2053 int doit = 0;
2054 for (d = 0; r->deps[d] >= 0; d++) {
2055 if (vstamps[r->deps[d]] > rstamps[k]) {
2056 doit = 1;
2057 break;
2060 if (!doit)
2061 continue;
2062 #ifdef RULES_DEBUG
2063 snd_output_printf(log, "Rule %d (%p): ", k, r->func);
2064 if (r->var >= 0) {
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, " -> ");
2069 #endif
2070 changed = r->func(params, r);
2071 #ifdef RULES_DEBUG
2072 if (r->var >= 0)
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');
2079 #endif
2080 rstamps[k] = stamp;
2081 if (changed && r->var >= 0) {
2082 params->cmask |= 1 << r->var;
2083 vstamps[r->var] = stamp;
2084 again = 1;
2086 if (changed < 0)
2087 goto _err;
2088 stamp++;
2090 } while (again);
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;
2104 params->rmask = 0;
2105 return 0;
2106 _err:
2107 #ifdef RULES_DEBUG
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);
2111 #endif
2112 return changed;
2115 int _snd_pcm_hw_params_refine(snd_pcm_hw_params_t *params,
2116 unsigned int vars,
2117 const snd_pcm_hw_params_t *src)
2119 int changed, err = 0;
2120 unsigned int k;
2121 for (k = 0; k <= SND_PCM_HW_PARAM_LAST_INTERVAL; ++k) {
2122 if (!(vars & (1 << k)))
2123 continue;
2124 changed = _snd_pcm_hw_param_refine(params, k, src);
2125 if (changed < 0)
2126 err = changed;
2128 params->info &= src->info;
2129 params->flags = src->flags; /* propagate all flags to slave */
2130 return err;
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))
2148 #ifdef RULES_DEBUG
2149 snd_output_t *log;
2150 #endif
2151 snd_pcm_hw_params_t sparams;
2152 int err;
2153 unsigned int cmask, changed;
2154 #ifdef RULES_DEBUG
2155 snd_output_stdio_attach(&log, stderr, 0);
2156 #endif
2157 err = cprepare(pcm, params);
2158 if (err < 0)
2159 return err;
2160 err = sprepare(pcm, &sparams);
2161 if (err < 0) {
2162 SNDERR("Slave PCM not usable");
2163 return err;
2165 #ifdef RULES_DEBUG
2166 snd_output_printf(log, "hw_refine_slave - enter '%s'\n", pcm->name);
2167 #endif
2168 do {
2169 cmask = params->cmask;
2170 params->cmask = 0;
2171 #ifdef RULES_DEBUG
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);
2176 #endif
2177 err = schange(pcm, params, &sparams);
2178 if (err >= 0) {
2179 #ifdef RULES_DEBUG
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);
2184 #endif
2185 err = srefine(pcm, &sparams);
2186 if (err < 0) {
2187 #ifdef RULES_DEBUG
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);
2192 #endif
2193 cchange(pcm, params, &sparams);
2194 return err;
2196 } else {
2197 #ifdef RULES_DEBUG
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);
2202 #endif
2203 cchange(pcm, params, &sparams);
2204 return err;
2206 #ifdef RULES_DEBUG
2207 snd_output_printf(log, "cchange '%s'\n", pcm->name);
2208 #endif
2209 err = cchange(pcm, params, &sparams);
2210 if (err < 0)
2211 return err;
2212 #ifdef RULES_DEBUG
2213 snd_output_printf(log, "refine_soft '%s'\n", pcm->name);
2214 #endif
2215 err = snd_pcm_hw_refine_soft(pcm, params);
2216 changed = params->cmask;
2217 params->cmask |= cmask;
2218 if (err < 0)
2219 return err;
2220 #ifdef RULES_DEBUG
2221 snd_output_printf(log, "refine_soft ok '%s'\n", pcm->name);
2222 #endif
2223 } while (changed);
2224 #ifdef RULES_DEBUG
2225 snd_output_printf(log, "refine_slave - leave '%s'\n", pcm->name);
2226 snd_output_close(log);
2227 #endif
2228 return 0;
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;
2245 int err;
2246 err = sprepare(pcm, &slave_params);
2247 assert(err >= 0);
2248 err = schange(pcm, params, &slave_params);
2249 assert(err >= 0);
2250 err = sparams(pcm, &slave_params);
2251 if (err < 0)
2252 cchange(pcm, params, &slave_params);
2253 return err;
2256 static int snd_pcm_sw_params_default(snd_pcm_t *pcm, snd_pcm_sw_params_t *params)
2258 assert(pcm && params);
2259 assert(pcm->setup);
2260 params->tstamp_mode = SND_PCM_TSTAMP_NONE;
2261 params->period_step = 1;
2262 params->sleep_min = 0;
2263 params->avail_min = pcm->period_size;
2264 params->xfer_align = 1;
2265 params->start_threshold = 1;
2266 params->stop_threshold = pcm->buffer_size;
2267 params->silence_threshold = 0;
2268 params->silence_size = 0;
2269 params->boundary = pcm->buffer_size;
2270 while (params->boundary * 2 <= LONG_MAX - pcm->buffer_size)
2271 params->boundary *= 2;
2272 return 0;
2275 #if 0
2276 #define REFINE_DEBUG
2277 #endif
2279 int snd_pcm_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
2281 int res;
2282 #ifdef REFINE_DEBUG
2283 snd_output_t *log;
2284 snd_output_stdio_attach(&log, stderr, 0);
2285 #endif
2286 assert(pcm && params);
2287 #ifdef REFINE_DEBUG
2288 snd_output_printf(log, "REFINE called:\n");
2289 snd_pcm_hw_params_dump(params, log);
2290 #endif
2291 res = pcm->ops->hw_refine(pcm->op_arg, params);
2292 #ifdef REFINE_DEBUG
2293 snd_output_printf(log, "refine done - result = %i\n", res);
2294 snd_pcm_hw_params_dump(params, log);
2295 snd_output_close(log);
2296 #endif
2297 return res;
2300 /* Install one of the configurations present in configuration
2301 space defined by PARAMS.
2302 The configuration chosen is that obtained fixing in this order:
2303 first access
2304 first format
2305 first subformat
2306 min channels
2307 min rate
2308 min period_size
2309 max periods
2310 Return 0 on success otherwise a negative error code
2312 int _snd_pcm_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
2314 int err;
2315 snd_pcm_sw_params_t sw;
2316 int fb, min_align;
2317 err = snd_pcm_hw_refine(pcm, params);
2318 if (err < 0)
2319 return err;
2320 snd_pcm_hw_params_choose(pcm, params);
2321 if (pcm->setup) {
2322 err = snd_pcm_hw_free(pcm);
2323 if (err < 0)
2324 return err;
2326 err = pcm->ops->hw_params(pcm->op_arg, params);
2327 if (err < 0)
2328 return err;
2330 pcm->setup = 1;
2331 INTERNAL(snd_pcm_hw_params_get_access)(params, &pcm->access);
2332 INTERNAL(snd_pcm_hw_params_get_format)(params, &pcm->format);
2333 INTERNAL(snd_pcm_hw_params_get_subformat)(params, &pcm->subformat);
2334 INTERNAL(snd_pcm_hw_params_get_channels)(params, &pcm->channels);
2335 INTERNAL(snd_pcm_hw_params_get_rate)(params, &pcm->rate, 0);
2336 INTERNAL(snd_pcm_hw_params_get_period_time)(params, &pcm->period_time, 0);
2337 INTERNAL(snd_pcm_hw_params_get_period_size)(params, &pcm->period_size, 0);
2338 INTERNAL(snd_pcm_hw_params_get_buffer_size)(params, &pcm->buffer_size);
2339 pcm->sample_bits = snd_pcm_format_physical_width(pcm->format);
2340 pcm->frame_bits = pcm->sample_bits * pcm->channels;
2341 fb = pcm->frame_bits;
2342 min_align = 1;
2343 while (fb % 8) {
2344 fb *= 2;
2345 min_align *= 2;
2347 pcm->min_align = min_align;
2349 pcm->hw_flags = params->flags;
2350 pcm->info = params->info;
2351 pcm->msbits = params->msbits;
2352 pcm->rate_num = params->rate_num;
2353 pcm->rate_den = params->rate_den;
2354 pcm->fifo_size = params->fifo_size;
2356 /* Default sw params */
2357 memset(&sw, 0, sizeof(sw));
2358 snd_pcm_sw_params_default(pcm, &sw);
2359 err = snd_pcm_sw_params(pcm, &sw);
2360 assert(err >= 0);
2362 if (pcm->mmap_rw ||
2363 pcm->access == SND_PCM_ACCESS_MMAP_INTERLEAVED ||
2364 pcm->access == SND_PCM_ACCESS_MMAP_NONINTERLEAVED ||
2365 pcm->access == SND_PCM_ACCESS_MMAP_COMPLEX) {
2366 err = snd_pcm_mmap(pcm);
2368 if (err < 0)
2369 return err;
2370 return 0;