Imported Upstream version 1.0.29
[platform/upstream/alsa-lib.git] / src / pcm / pcm_params.c
1 /*
2  *  PCM - Params functions
3  *  Copyright (c) 2000 by Abramo Bagnara <abramo@alsa-project.org>
4  *
5  *
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.
10  *
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.
15  *
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
19  *
20  */
21   
22 #include "pcm_local.h"
23
24 #ifndef NDEBUG
25 /*
26  * dump hw_params when $LIBASOUND_DEBUG is set to >= 1
27  */
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)
30 {
31         const char *verbose = getenv("LIBASOUND_DEBUG");
32         snd_output_t *out;
33
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);
53         }
54         fprintf(stderr, " : %s\n", snd_strerror(err));
55         snd_pcm_hw_params_dump(params, out);
56         snd_output_close(out);
57 }
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)
61 {
62 }
63 #endif
64
65 static inline int hw_is_mask(snd_pcm_hw_param_t var)
66 {
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
73 }
74
75 static inline int hw_is_interval(snd_pcm_hw_param_t var)
76 {
77         return var >= SND_PCM_HW_PARAM_FIRST_INTERVAL &&
78                 var <= SND_PCM_HW_PARAM_LAST_INTERVAL;
79 }
80
81 #define hw_param_mask(params,var) \
82         &((params)->masks[(var) - SND_PCM_HW_PARAM_FIRST_MASK])
83
84 #define hw_param_interval(params,var) \
85         &((params)->intervals[(var) - SND_PCM_HW_PARAM_FIRST_INTERVAL])
86
87 #define hw_param_mask_c hw_param_mask
88 #define hw_param_interval_c hw_param_interval
89
90 static void _snd_pcm_hw_param_any(snd_pcm_hw_params_t *params, snd_pcm_hw_param_t var)
91 {
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;
97         }
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;
103         }
104         assert(0);
105 }
106
107 int snd_pcm_hw_param_any(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
108                          snd_pcm_hw_param_t var)
109 {
110         _snd_pcm_hw_param_any(params, var);
111         return snd_pcm_hw_refine(pcm, params);
112 }
113
114 void _snd_pcm_hw_params_any(snd_pcm_hw_params_t *params)
115 {
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;
125 }
126
127 /* Return the value for field PAR if it's fixed in configuration space 
128    defined by PARAMS. Return -EINVAL otherwise
129 */
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)
132 {
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;
151         }
152         assert(0);
153         return -EINVAL;
154 }
155
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)
159 {
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;
176         }
177         assert(0);
178         return 0;
179 }
180
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)
184 {
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;
201         }
202         assert(0);
203         return 0;
204 }
205
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)
211 {
212         assert(hw_is_mask(var));
213         return hw_param_mask_c(params, var);
214 }
215
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)
221 {
222         assert(hw_is_interval(var));
223         return hw_param_interval_c(params, var);
224 }
225
226 /* --- Refinement functions --- */
227
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)
231 {
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;
238         }
239         return changed;
240 }
241
242 void _snd_pcm_hw_param_set_empty(snd_pcm_hw_params_t *params,
243                                  snd_pcm_hw_param_t var)
244 {
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);
255         }
256 }
257
258 static int _snd_pcm_hw_param_set_integer(snd_pcm_hw_params_t *params,
259                                          snd_pcm_hw_param_t var)
260 {
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;
267         }
268         return changed;
269 }
270         
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
274 */
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)
279 {
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;
295         }
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;
303         }
304         return 0;
305  _fail:
306         if (mode == SND_TRY)
307                 *params = save;
308         return err;
309 }
310
311 static int _snd_pcm_hw_param_set_first(snd_pcm_hw_params_t *params,
312                                        snd_pcm_hw_param_t var)
313 {
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;
322         }
323         if (changed > 0) {
324                 params->cmask |= 1 << var;
325                 params->rmask |= 1 << var;
326         }
327         return changed;
328 }
329
330
331 /* Inside configuration space defined by PARAMS remove from PAR all 
332    values > minimum. Reduce configuration space accordingly.
333    Return the minimum.
334 */
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)
339 {
340         int err;
341
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;
349         }
350         return snd_pcm_hw_param_get(params, var, rval, dir);
351 }
352
353 static int _snd_pcm_hw_param_set_last(snd_pcm_hw_params_t *params,
354                                       snd_pcm_hw_param_t var)
355 {
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;
364         }
365         if (changed > 0) {
366                 params->cmask |= 1 << var;
367                 params->rmask |= 1 << var;
368         }
369         return changed;
370 }
371
372
373 /* Inside configuration space defined by PARAMS remove from PAR all 
374    values < maximum. Reduce configuration space accordingly.
375    Return the maximum.
376 */
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)
381 {
382         int err;
383
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;
391         }
392         return snd_pcm_hw_param_get(params, var, rval, dir);
393 }
394
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)
397 {
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--;
407                         }
408                 }
409         }
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;
417         }
418         if (changed) {
419                 params->cmask |= 1 << var;
420                 params->rmask |= 1 << var;
421         }
422         return changed;
423 }
424
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
428 */
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)
432 {
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;
448         }
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;
459                 }
460         }
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;
468 }
469
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)
472 {
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++;
481                 }
482         }
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;
494         }
495         if (changed) {
496                 params->cmask |= 1 << var;
497                 params->rmask |= 1 << var;
498         }
499         return changed;
500 }
501
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
505 */
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)
509 {
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;
525         }
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;
536                 }
537         }
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;
545 }
546
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)
551 {
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--;
561                         }
562                 }
563         }
564         if (maxdir) {
565                 if (maxdir < 0) {
566                         openmax = 1;
567                 } else if (maxdir > 0) {
568                         openmax = 1;
569                         max++;
570                 }
571         }
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);
587                         }
588                 }
589         }
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);
601                 }
602         } else {
603                 assert(0);
604                 return -EINVAL;
605         }
606         if (changed) {
607                 params->cmask |= 1 << var;
608                 params->rmask |= 1 << var;
609         }
610         return changed;
611 }
612
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
616 */
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)
622 {
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;
638         }
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;
648         }
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;
659 }
660
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)
663 {
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);
676                 }
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;
696                         }
697                         changed = snd_interval_refine(i, &t);
698                 }
699         } else {
700                 assert(0);
701                 return -EINVAL;
702         }
703         if (changed) {
704                 params->cmask |= 1 << var;
705                 params->rmask |= 1 << var;
706         }
707         return changed;
708 }
709
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
713 */
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)
717 {
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;
733         }
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;
741         }
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;
749 }
750
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)
753 {
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;
760         }
761         return changed;
762 }
763
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
770 */
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)
774 {
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;
790         }
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;
798         }
799         return 0;
800  _fail:
801         if (mode == SND_TRY)
802                 *params = save;
803         return err;
804 }
805
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.
811  */
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)
815 {
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--;
836         }
837         save = *params;
838         saved_min = min;
839         err = snd_pcm_hw_param_set_min(pcm, params, SND_CHANGE, var, &min, &mindir);
840
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;
847         }
848         
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;
860                 }
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;
867                 }
868                 last = 1;
869         }
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;
878 }
879
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.
888  */
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)
893 {
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;
915         }
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;
933                 }
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;
942         }
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;
950 }
951 #endif
952
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)
958 {
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;
973         }
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;
979 }
980
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)
985 {
986         unsigned int min, max;
987         int mindir, maxdir, err;
988
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;
997 }
998
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)
1003 {
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 */
1015                         }
1016                         prev = cur;
1017                         cur += best;
1018                         if (cur <= prev)
1019                                 break;
1020                 }
1021         }
1022         return snd_pcm_hw_param_refine_near(pcm, params, var, src);
1023 }
1024
1025 /* ---- end of refinement functions ---- */
1026
1027 int snd_pcm_hw_param_empty(const snd_pcm_hw_params_t *params,
1028                            snd_pcm_hw_param_t var)
1029 {
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;
1036 }
1037
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)
1041 {
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;
1050 }
1051
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)
1055 {
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;
1064 }
1065
1066 #if 0
1067 #define CHOOSE_DEBUG
1068 #endif
1069
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
1080 */
1081 static int snd_pcm_hw_params_choose(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
1082 {
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
1090
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);
1116                 }
1117         }
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;
1140         }
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;
1150 }
1151
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)
1155 {
1156         if (hw_is_mask(var)) {
1157                 const snd_mask_t *mask = hw_param_mask_c(params, var);
1158                 return snd_mask_count(mask);
1159         }
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;
1163         }
1164         assert(0);
1165         return 0;
1166 }
1167 #endif
1168
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)
1172 {
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;
1187         }
1188         return changed;
1189 }
1190                              
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)
1194 {
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;
1202         }
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;
1210         }
1211         assert(0);
1212 }
1213 #endif
1214
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)
1217 {
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;
1242                                         }
1243                                         if (s) {
1244                                                 snd_output_putc(out, ' ');
1245                                                 snd_output_puts(out, s);
1246                                         }
1247                                 }
1248                         }
1249                 }
1250                 return;
1251         }
1252         if (hw_is_interval(var)) {
1253                 snd_interval_print(hw_param_interval_c(params, var), out);
1254                 return;
1255         }
1256         assert(0);
1257 }
1258
1259 #define HW_PARAM(v) [SND_PCM_HW_PARAM_##v] = #v
1260
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),
1277 };
1278
1279 const char *snd_pcm_hw_param_name(snd_pcm_hw_param_t param)
1280 {
1281         assert(param <= SND_PCM_HW_PARAM_LAST_INTERVAL);
1282         return snd_pcm_hw_param_names[param];
1283 }
1284
1285 #if 0
1286 /* Strategies */
1287
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);
1304 };
1305
1306 /* Independent badness */
1307 typedef struct _snd_pcm_hw_strategy_simple snd_pcm_hw_strategy_simple_t;
1308
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);
1323 };
1324
1325 typedef struct _snd_pcm_hw_strategy_simple_near {
1326         int best;
1327         unsigned int mul;
1328 } snd_pcm_hw_strategy_simple_near_t;
1329
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;
1335
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)
1340 {
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;
1370                         }
1371                         best_badness = badness;
1372                         best_params = params1;
1373                         badness_max = badness - 1;
1374                 }
1375         }
1376         if (best_badness == UINT_MAX) {
1377                 return -EINVAL;
1378         }
1379         *params = best_params;
1380         return best_badness;
1381 }
1382
1383 void snd_pcm_hw_strategy_simple_free(snd_pcm_hw_strategy_t *strategy)
1384 {
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]);
1390         }
1391         free(pars);
1392 }
1393
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)
1397 {
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;
1418                 }
1419         }
1420         return best_var;
1421 }
1422
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)
1428 {
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]);
1432 }
1433
1434
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)
1439 {
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;
1451         }
1452         return badness;
1453 }
1454
1455
1456 void snd_pcm_hw_strategy_simple_near_free(snd_pcm_hw_strategy_simple_t *par)
1457 {
1458         snd_pcm_hw_strategy_simple_near_t *p = par->private_data;
1459         free(p);
1460 }
1461
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)
1466 {
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;
1476 }
1477         
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)
1483 {
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);
1490 }
1491
1492 void snd_pcm_hw_strategy_simple_choices_free(snd_pcm_hw_strategy_simple_t *par)
1493 {
1494         snd_pcm_hw_strategy_simple_choices_t *p = par->private_data;
1495 //      free(p->choices);
1496         free(p);
1497 }
1498
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)
1503 {
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;
1509         }
1510         assert(0);
1511         return UINT_MAX;
1512 }
1513         
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)
1519 {
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;
1527                         }
1528                 }
1529         }
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;
1537         }
1538         return -1;
1539 }
1540
1541 void snd_pcm_hw_strategy_free(snd_pcm_hw_strategy_t *strategy)
1542 {
1543         if (strategy->free)
1544                 strategy->free(strategy);
1545         free(strategy);
1546 }
1547
1548 int snd_pcm_hw_strategy_simple(snd_pcm_hw_strategy_t **strategyp,
1549                             unsigned int badness_min,
1550                             unsigned int badness_max)
1551 {
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;
1562         }
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;
1572 }
1573
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)
1579 {
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;
1598 }
1599
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)
1605 {
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;
1624 }
1625
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)
1631 {
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;
1648         }
1649         return -ENOENT;
1650 }
1651
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)
1657 {
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;
1668         }
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;
1676         }
1677         if (!success) {
1678                 snd_pcm_hw_params_any(pcm, &any);
1679                 success = &any;
1680         }
1681         return snd_pcm_hw_params_try_explain_failure1(pcm, fail, success, depth, out);
1682 }
1683
1684 #endif
1685
1686 typedef struct _snd_pcm_hw_rule snd_pcm_hw_rule_t;
1687
1688 typedef int (*snd_pcm_hw_rule_func_t)(snd_pcm_hw_params_t *params,
1689                                       const snd_pcm_hw_rule_t *rule);
1690
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;
1696 };
1697
1698 static int snd_pcm_hw_rule_mul(snd_pcm_hw_params_t *params,
1699                                const snd_pcm_hw_rule_t *rule)
1700 {
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);
1705 }
1706
1707 static int snd_pcm_hw_rule_div(snd_pcm_hw_params_t *params,
1708                         const snd_pcm_hw_rule_t *rule)
1709 {
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);
1714 }
1715
1716 static int snd_pcm_hw_rule_muldivk(snd_pcm_hw_params_t *params,
1717                                    const snd_pcm_hw_rule_t *rule)
1718 {
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);
1724 }
1725
1726 static int snd_pcm_hw_rule_mulkdiv(snd_pcm_hw_params_t *params,
1727                                    const snd_pcm_hw_rule_t *rule)
1728 {
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);
1734 }
1735
1736 static int snd_pcm_hw_rule_format(snd_pcm_hw_params_t *params,
1737                                   const snd_pcm_hw_rule_t *rule)
1738 {
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;
1755                 }
1756         }
1757         return changed;
1758 }
1759
1760
1761 static int snd_pcm_hw_rule_sample_bits(snd_pcm_hw_params_t *params,
1762                                        const snd_pcm_hw_rule_t *rule)
1763 {
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;
1782         }
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;
1794 }
1795
1796 static const snd_pcm_hw_rule_t refine_rules[] = {
1797         {
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,
1802         },
1803         {
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,
1809         },
1810         {
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,
1816         },
1817         {
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,
1823         },
1824         {
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,
1830         },
1831         {
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,
1837         },
1838         {
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,
1844         },
1845         {
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,
1851         },
1852         {
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,
1858         },
1859         {
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,
1865         },
1866         {
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,
1872         },
1873         {
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,
1879         },
1880         {
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,
1886         },
1887         {
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,
1893         },
1894         {
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,
1900         },
1901         {
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,
1907         },
1908         {
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,
1914         },
1915         {
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,
1921         },
1922         {
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,
1928         },
1929         {
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,
1935         },
1936 };
1937
1938 #define RULES (sizeof(refine_rules) / sizeof(refine_rules[0]))
1939
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 },
1943         },
1944         [SND_PCM_HW_PARAM_FORMAT - SND_PCM_HW_PARAM_FIRST_MASK] = {
1945                 .bits = { 0x81ffffff, 0xfff},
1946         },
1947         [SND_PCM_HW_PARAM_SUBFORMAT - SND_PCM_HW_PARAM_FIRST_MASK] = {
1948                 .bits = { 0x1 },
1949         },
1950 };
1951   
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,
1956         },
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,
1960         },
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,
1964         },
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,
1968         },
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,
1972         },
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,
1976         },
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,
1980         },
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,
1984         },
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,
1988         },
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,
1992         },
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,
1996         },
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,
2000         },
2001 };
2002
2003 #if 0
2004 #define RULES_DEBUG
2005 #endif
2006
2007 int snd_pcm_hw_refine_soft(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params)
2008 {
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
2021
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;
2031         }
2032
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;
2042         }
2043
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;
2058                                 }
2059                         }
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, " -> ");
2068                         }
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);
2077                         }
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;
2085                         }
2086                         if (changed < 0)
2087                                 goto _err;
2088                         stamp++;
2089                 }
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);
2095         }
2096
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;
2102                 }
2103         }
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;
2113 }
2114
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)
2118 {
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;
2127         }
2128         params->info &= src->info;
2129         params->flags = src->flags; /* propagate all flags to slave */
2130         return err;
2131 }
2132
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))
2146
2147 {
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;
2164         }
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;
2195                         }
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;
2205                 }
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;
2229 }
2230
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))
2242
2243 {
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;
2254 }
2255
2256 static int snd_pcm_sw_params_default(snd_pcm_t *pcm, snd_pcm_sw_params_t *params)
2257 {
2258         assert(pcm && params);
2259         assert(pcm->setup);
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;
2274         return 0;
2275 }
2276
2277 #if 0
2278 #define REFINE_DEBUG
2279 #endif
2280
2281 int snd_pcm_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
2282 {
2283         int res;
2284 #ifdef REFINE_DEBUG
2285         snd_output_t *log;
2286         snd_output_stdio_attach(&log, stderr, 0);
2287 #endif
2288         assert(pcm && params);
2289 #ifdef REFINE_DEBUG
2290         snd_output_printf(log, "REFINE called:\n");
2291         snd_pcm_hw_params_dump(params, log);
2292 #endif
2293         res = pcm->ops->hw_refine(pcm->op_arg, params);
2294 #ifdef REFINE_DEBUG
2295         snd_output_printf(log, "refine done - result = %i\n", res);
2296         snd_pcm_hw_params_dump(params, log);
2297         snd_output_close(log);
2298 #endif
2299         return res;
2300 }
2301
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:
2305    first access
2306    first format
2307    first subformat
2308    min channels
2309    min rate
2310    min period_size
2311    max periods
2312    Return 0 on success otherwise a negative error code
2313 */
2314 int _snd_pcm_hw_params_internal(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
2315 {
2316         int err;
2317         snd_pcm_sw_params_t sw;
2318         int fb, min_align;
2319         err = snd_pcm_hw_refine(pcm, params);
2320         if (err < 0)
2321                 return err;
2322         snd_pcm_hw_params_choose(pcm, params);
2323         if (pcm->setup) {
2324                 err = snd_pcm_hw_free(pcm);
2325                 if (err < 0)
2326                         return err;
2327         }
2328         err = pcm->ops->hw_params(pcm->op_arg, params);
2329         if (err < 0)
2330                 return err;
2331
2332         pcm->setup = 1;
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;
2344         min_align = 1;
2345         while (fb % 8) {
2346                 fb *= 2;
2347                 min_align *= 2;
2348         }
2349         pcm->min_align = min_align;
2350         
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;
2357         
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);
2362         assert(err >= 0);
2363
2364         if (pcm->mmap_rw || 
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);
2369         }
2370         if (err < 0)
2371                 return err;
2372         return 0;
2373 }
2374