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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 */
dump_hw_params(snd_pcm_hw_params_t * params,const char * type,snd_pcm_hw_param_t var,unsigned int val,int err)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
dump_hw_params(snd_pcm_hw_params_t * params,const char * type,snd_pcm_hw_param_t var,unsigned int val,int err)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
hw_is_mask(snd_pcm_hw_param_t var)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
hw_is_interval(snd_pcm_hw_param_t var)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
_snd_pcm_hw_param_any(snd_pcm_hw_params_t * params,snd_pcm_hw_param_t var)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
snd_pcm_hw_param_any(snd_pcm_t * pcm,snd_pcm_hw_params_t * params,snd_pcm_hw_param_t var)107 int snd_pcm_hw_param_any(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
108 snd_pcm_hw_param_t var)
109 {
110 _snd_pcm_hw_param_any(params, var);
111 return snd_pcm_hw_refine(pcm, params);
112 }
113
_snd_pcm_hw_params_any(snd_pcm_hw_params_t * params)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 */
snd_pcm_hw_param_get(const snd_pcm_hw_params_t * params,snd_pcm_hw_param_t var,unsigned int * val,int * dir)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. */
snd_pcm_hw_param_get_min(const snd_pcm_hw_params_t * params,snd_pcm_hw_param_t var,unsigned int * val,int * dir)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. */
snd_pcm_hw_param_get_max(const snd_pcm_hw_params_t * params,snd_pcm_hw_param_t var,unsigned int * val,int * dir)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. */
snd_pcm_hw_param_get_mask(const snd_pcm_hw_params_t * params,snd_pcm_hw_param_t var)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. */
snd_pcm_hw_param_get_interval(const snd_pcm_hw_params_t * params,snd_pcm_hw_param_t var)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
_snd_pcm_hw_param_set_interval(snd_pcm_hw_params_t * params,snd_pcm_hw_param_t var,const snd_interval_t * val)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
_snd_pcm_hw_param_set_empty(snd_pcm_hw_params_t * params,snd_pcm_hw_param_t var)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
_snd_pcm_hw_param_set_integer(snd_pcm_hw_params_t * params,snd_pcm_hw_param_t var)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 */
snd_pcm_hw_param_set_integer(snd_pcm_t * pcm,snd_pcm_hw_params_t * params,snd_set_mode_t mode,snd_pcm_hw_param_t var)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
_snd_pcm_hw_param_set_first(snd_pcm_hw_params_t * params,snd_pcm_hw_param_t var)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 */
snd_pcm_hw_param_set_first(snd_pcm_t * pcm,snd_pcm_hw_params_t * params,snd_pcm_hw_param_t var,unsigned int * rval,int * dir)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
_snd_pcm_hw_param_set_last(snd_pcm_hw_params_t * params,snd_pcm_hw_param_t var)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 */
snd_pcm_hw_param_set_last(snd_pcm_t * pcm,snd_pcm_hw_params_t * params,snd_pcm_hw_param_t var,unsigned int * rval,int * dir)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
_snd_pcm_hw_param_set_min(snd_pcm_hw_params_t * params,snd_pcm_hw_param_t var,unsigned int val,int dir)395 int _snd_pcm_hw_param_set_min(snd_pcm_hw_params_t *params,
396 snd_pcm_hw_param_t var, unsigned int val, int dir)
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 */
snd_pcm_hw_param_set_min(snd_pcm_t * pcm,snd_pcm_hw_params_t * params,snd_set_mode_t mode,snd_pcm_hw_param_t var,unsigned int * val,int * dir)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
_snd_pcm_hw_param_set_max(snd_pcm_hw_params_t * params,snd_pcm_hw_param_t var,unsigned int val,int dir)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 */
snd_pcm_hw_param_set_max(snd_pcm_t * pcm,snd_pcm_hw_params_t * params,snd_set_mode_t mode,snd_pcm_hw_param_t var,unsigned int * val,int * dir)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
_snd_pcm_hw_param_set_minmax(snd_pcm_hw_params_t * params,snd_pcm_hw_param_t var,unsigned int min,int mindir,unsigned int max,int maxdir)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 */
snd_pcm_hw_param_set_minmax(snd_pcm_t * pcm,snd_pcm_hw_params_t * params,snd_set_mode_t mode,snd_pcm_hw_param_t var,unsigned int * min,int * mindir,unsigned int * max,int * maxdir)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
_snd_pcm_hw_param_set(snd_pcm_hw_params_t * params,snd_pcm_hw_param_t var,unsigned int val,int dir)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 */
snd_pcm_hw_param_set(snd_pcm_t * pcm,snd_pcm_hw_params_t * params,snd_set_mode_t mode,snd_pcm_hw_param_t var,unsigned int val,int dir)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
_snd_pcm_hw_param_set_mask(snd_pcm_hw_params_t * params,snd_pcm_hw_param_t var,const snd_mask_t * val)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 */
snd_pcm_hw_param_set_mask(snd_pcm_t * pcm,snd_pcm_hw_params_t * params,snd_set_mode_t mode,snd_pcm_hw_param_t var,const snd_mask_t * val)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 */
snd_pcm_hw_param_set_near(snd_pcm_t * pcm,snd_pcm_hw_params_t * params,snd_pcm_hw_param_t var,unsigned int * val,int * dir)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, ¶ms1, 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, ¶ms1, 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
snd_pcm_hw_param_set_near_minmax(snd_pcm_t * pcm,snd_pcm_hw_params_t * params,snd_pcm_hw_param_t var,unsigned int min,int * mindir,unsigned int max,int * maxdir)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
snd_pcm_hw_param_refine_near(snd_pcm_t * pcm,snd_pcm_hw_params_t * params,snd_pcm_hw_param_t var,const snd_pcm_hw_params_t * src)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
snd_pcm_hw_param_refine_multiple(snd_pcm_t * pcm,snd_pcm_hw_params_t * params,snd_pcm_hw_param_t var,const snd_pcm_hw_params_t * src)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
snd_pcm_hw_param_empty(const snd_pcm_hw_params_t * params,snd_pcm_hw_param_t var)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
snd_pcm_hw_param_always_eq(const snd_pcm_hw_params_t * params,snd_pcm_hw_param_t var,const snd_pcm_hw_params_t * params1)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
snd_pcm_hw_param_never_eq(const snd_pcm_hw_params_t * params,snd_pcm_hw_param_t var,const snd_pcm_hw_params_t * params1)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 */
snd_pcm_hw_params_choose(snd_pcm_t * pcm,snd_pcm_hw_params_t * params)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
_snd_pcm_hw_param_refine(snd_pcm_hw_params_t * params,snd_pcm_hw_param_t var,const snd_pcm_hw_params_t * src)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
snd_pcm_hw_param_dump(const snd_pcm_hw_params_t * params,snd_pcm_hw_param_t var,snd_output_t * out)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
snd_pcm_hw_param_name(snd_pcm_hw_param_t param)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(¶ms1, var, value, &dir, pcm, strategy);
1363 if (value < 0)
1364 break;
1365 badness = snd_pcm_hw_params_strategy(pcm, ¶ms1, 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, ¶ms1, 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
snd_pcm_hw_rule_mul(snd_pcm_hw_params_t * params,const snd_pcm_hw_rule_t * rule)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
snd_pcm_hw_rule_div(snd_pcm_hw_params_t * params,const snd_pcm_hw_rule_t * rule)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
snd_pcm_hw_rule_muldivk(snd_pcm_hw_params_t * params,const snd_pcm_hw_rule_t * rule)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
snd_pcm_hw_rule_mulkdiv(snd_pcm_hw_params_t * params,const snd_pcm_hw_rule_t * rule)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
snd_pcm_hw_rule_format(snd_pcm_hw_params_t * params,const snd_pcm_hw_rule_t * rule)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
snd_pcm_hw_rule_sample_bits(snd_pcm_hw_params_t * params,const snd_pcm_hw_rule_t * rule)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 #define PCM_BIT(x) \
1940 (1U << ((x) < 32 ? (x) : ((x) - 32)))
1941
1942 static const snd_mask_t refine_masks[SND_PCM_HW_PARAM_LAST_MASK - SND_PCM_HW_PARAM_FIRST_MASK + 1] = {
1943 [SND_PCM_HW_PARAM_ACCESS - SND_PCM_HW_PARAM_FIRST_MASK] = {
1944 .bits = {
1945 PCM_BIT(SNDRV_PCM_ACCESS_MMAP_INTERLEAVED) |
1946 PCM_BIT(SNDRV_PCM_ACCESS_MMAP_NONINTERLEAVED) |
1947 PCM_BIT(SNDRV_PCM_ACCESS_MMAP_COMPLEX) |
1948 PCM_BIT(SNDRV_PCM_ACCESS_RW_INTERLEAVED) |
1949 PCM_BIT(SNDRV_PCM_ACCESS_RW_NONINTERLEAVED)
1950 },
1951 },
1952 [SND_PCM_HW_PARAM_FORMAT - SND_PCM_HW_PARAM_FIRST_MASK] = {
1953 .bits = {
1954 /* first 32bits */
1955 PCM_BIT(SNDRV_PCM_FORMAT_S8) |
1956 PCM_BIT(SNDRV_PCM_FORMAT_U8) |
1957 PCM_BIT(SNDRV_PCM_FORMAT_S16_LE) |
1958 PCM_BIT(SNDRV_PCM_FORMAT_S16_BE) |
1959 PCM_BIT(SNDRV_PCM_FORMAT_U16_LE) |
1960 PCM_BIT(SNDRV_PCM_FORMAT_U16_BE) |
1961 PCM_BIT(SNDRV_PCM_FORMAT_S24_LE) |
1962 PCM_BIT(SNDRV_PCM_FORMAT_S24_BE) |
1963 PCM_BIT(SNDRV_PCM_FORMAT_U24_LE) |
1964 PCM_BIT(SNDRV_PCM_FORMAT_U24_BE) |
1965 PCM_BIT(SNDRV_PCM_FORMAT_S32_LE) |
1966 PCM_BIT(SNDRV_PCM_FORMAT_S32_BE) |
1967 PCM_BIT(SNDRV_PCM_FORMAT_U32_LE) |
1968 PCM_BIT(SNDRV_PCM_FORMAT_U32_BE) |
1969 PCM_BIT(SNDRV_PCM_FORMAT_FLOAT_LE) |
1970 PCM_BIT(SNDRV_PCM_FORMAT_FLOAT_BE) |
1971 PCM_BIT(SNDRV_PCM_FORMAT_FLOAT64_LE) |
1972 PCM_BIT(SNDRV_PCM_FORMAT_FLOAT64_BE) |
1973 PCM_BIT(SNDRV_PCM_FORMAT_IEC958_SUBFRAME) |
1974 PCM_BIT(SNDRV_PCM_FORMAT_IEC958_SUBFRAME) |
1975 PCM_BIT(SNDRV_PCM_FORMAT_MU_LAW) |
1976 PCM_BIT(SNDRV_PCM_FORMAT_A_LAW) |
1977 PCM_BIT(SNDRV_PCM_FORMAT_IMA_ADPCM) |
1978 PCM_BIT(SNDRV_PCM_FORMAT_MPEG) |
1979 PCM_BIT(SNDRV_PCM_FORMAT_GSM) |
1980 PCM_BIT(SNDRV_PCM_FORMAT_S20_LE) |
1981 PCM_BIT(SNDRV_PCM_FORMAT_S20_BE) |
1982 PCM_BIT(SNDRV_PCM_FORMAT_U20_LE) |
1983 PCM_BIT(SNDRV_PCM_FORMAT_U20_BE) |
1984 PCM_BIT(SNDRV_PCM_FORMAT_SPECIAL),
1985 /* second 32bits */
1986 PCM_BIT(SNDRV_PCM_FORMAT_S24_3LE) |
1987 PCM_BIT(SNDRV_PCM_FORMAT_S24_3BE) |
1988 PCM_BIT(SNDRV_PCM_FORMAT_U24_3LE) |
1989 PCM_BIT(SNDRV_PCM_FORMAT_U24_3BE) |
1990 PCM_BIT(SNDRV_PCM_FORMAT_S20_3LE) |
1991 PCM_BIT(SNDRV_PCM_FORMAT_S20_3BE) |
1992 PCM_BIT(SNDRV_PCM_FORMAT_U20_3LE) |
1993 PCM_BIT(SNDRV_PCM_FORMAT_U20_3BE) |
1994 PCM_BIT(SNDRV_PCM_FORMAT_S18_3LE) |
1995 PCM_BIT(SNDRV_PCM_FORMAT_S18_3BE) |
1996 PCM_BIT(SNDRV_PCM_FORMAT_U18_3LE) |
1997 PCM_BIT(SNDRV_PCM_FORMAT_U18_3BE) |
1998 PCM_BIT(SNDRV_PCM_FORMAT_G723_24) |
1999 PCM_BIT(SNDRV_PCM_FORMAT_G723_24) |
2000 PCM_BIT(SNDRV_PCM_FORMAT_G723_40) |
2001 PCM_BIT(SNDRV_PCM_FORMAT_G723_40) |
2002 PCM_BIT(SNDRV_PCM_FORMAT_DSD_U8) |
2003 PCM_BIT(SNDRV_PCM_FORMAT_DSD_U16_LE) |
2004 PCM_BIT(SNDRV_PCM_FORMAT_DSD_U32_LE) |
2005 PCM_BIT(SNDRV_PCM_FORMAT_DSD_U16_BE) |
2006 PCM_BIT(SNDRV_PCM_FORMAT_DSD_U32_BE)
2007 },
2008 },
2009 [SND_PCM_HW_PARAM_SUBFORMAT - SND_PCM_HW_PARAM_FIRST_MASK] = {
2010 .bits = {
2011 PCM_BIT(SNDRV_PCM_SUBFORMAT_STD)
2012 },
2013 },
2014 };
2015
2016 static const snd_interval_t refine_intervals[SND_PCM_HW_PARAM_LAST_INTERVAL - SND_PCM_HW_PARAM_FIRST_INTERVAL + 1] = {
2017 [SND_PCM_HW_PARAM_SAMPLE_BITS - SND_PCM_HW_PARAM_FIRST_INTERVAL] = {
2018 .min = 1, .max = UINT_MAX,
2019 .openmin = 0, .openmax = 0, .integer = 1, .empty = 0,
2020 },
2021 [SND_PCM_HW_PARAM_FRAME_BITS - SND_PCM_HW_PARAM_FIRST_INTERVAL] = {
2022 .min = 1, .max = UINT_MAX,
2023 .openmin = 0, .openmax = 0, .integer = 1, .empty = 0,
2024 },
2025 [SND_PCM_HW_PARAM_CHANNELS - SND_PCM_HW_PARAM_FIRST_INTERVAL] = {
2026 .min = 1, .max = UINT_MAX,
2027 .openmin = 0, .openmax = 0, .integer = 1, .empty = 0,
2028 },
2029 [SND_PCM_HW_PARAM_RATE - SND_PCM_HW_PARAM_FIRST_INTERVAL] = {
2030 .min = 1, .max = UINT_MAX,
2031 .openmin = 0, .openmax = 0, .integer = 0, .empty = 0,
2032 },
2033 [SND_PCM_HW_PARAM_PERIOD_TIME - SND_PCM_HW_PARAM_FIRST_INTERVAL] = {
2034 .min = 0, .max = UINT_MAX,
2035 .openmin = 0, .openmax = 0, .integer = 0, .empty = 0,
2036 },
2037 [SND_PCM_HW_PARAM_PERIOD_SIZE - SND_PCM_HW_PARAM_FIRST_INTERVAL] = {
2038 .min = 0, .max = UINT_MAX,
2039 .openmin = 0, .openmax = 0, .integer = 0, .empty = 0,
2040 },
2041 [SND_PCM_HW_PARAM_PERIOD_BYTES - SND_PCM_HW_PARAM_FIRST_INTERVAL] = {
2042 .min = 0, .max = UINT_MAX,
2043 .openmin = 0, .openmax = 0, .integer = 0, .empty = 0,
2044 },
2045 [SND_PCM_HW_PARAM_PERIODS - SND_PCM_HW_PARAM_FIRST_INTERVAL] = {
2046 .min = 0, .max = UINT_MAX,
2047 .openmin = 0, .openmax = 0, .integer = 0, .empty = 0,
2048 },
2049 [SND_PCM_HW_PARAM_BUFFER_TIME - SND_PCM_HW_PARAM_FIRST_INTERVAL] = {
2050 .min = 1, .max = UINT_MAX,
2051 .openmin = 0, .openmax = 0, .integer = 0, .empty = 0,
2052 },
2053 [SND_PCM_HW_PARAM_BUFFER_SIZE - SND_PCM_HW_PARAM_FIRST_INTERVAL] = {
2054 .min = 1, .max = UINT_MAX,
2055 .openmin = 0, .openmax = 0, .integer = 1, .empty = 0,
2056 },
2057 [SND_PCM_HW_PARAM_BUFFER_BYTES - SND_PCM_HW_PARAM_FIRST_INTERVAL] = {
2058 .min = 1, .max = UINT_MAX,
2059 .openmin = 0, .openmax = 0, .integer = 1, .empty = 0,
2060 },
2061 [SND_PCM_HW_PARAM_TICK_TIME - SND_PCM_HW_PARAM_FIRST_INTERVAL] = {
2062 .min = 0, .max = UINT_MAX,
2063 .openmin = 0, .openmax = 0, .integer = 0, .empty = 0,
2064 },
2065 };
2066
2067 #if 0
2068 #define RULES_DEBUG
2069 #endif
2070
snd_pcm_hw_refine_soft(snd_pcm_t * pcm ATTRIBUTE_UNUSED,snd_pcm_hw_params_t * params)2071 int snd_pcm_hw_refine_soft(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params)
2072 {
2073 unsigned int k;
2074 snd_interval_t *i;
2075 unsigned int rstamps[RULES];
2076 unsigned int vstamps[SND_PCM_HW_PARAM_LAST_INTERVAL + 1];
2077 unsigned int stamp = 2;
2078 int changed, again;
2079 #ifdef RULES_DEBUG
2080 snd_output_t *log;
2081 snd_output_stdio_attach(&log, stderr, 0);
2082 snd_output_printf(log, "refine_soft '%s' (begin)\n", pcm->name);
2083 snd_pcm_hw_params_dump(params, log);
2084 #endif
2085
2086 for (k = SND_PCM_HW_PARAM_FIRST_MASK; k <= SND_PCM_HW_PARAM_LAST_MASK; k++) {
2087 if (!(params->rmask & (1 << k)))
2088 continue;
2089 changed = snd_mask_refine(hw_param_mask(params, k),
2090 &refine_masks[k - SND_PCM_HW_PARAM_FIRST_MASK]);
2091 if (changed)
2092 params->cmask |= 1 << k;
2093 if (changed < 0)
2094 goto _err;
2095 }
2096
2097 for (k = SND_PCM_HW_PARAM_FIRST_INTERVAL; k <= SND_PCM_HW_PARAM_LAST_INTERVAL; k++) {
2098 if (!(params->rmask & (1 << k)))
2099 continue;
2100 changed = snd_interval_refine(hw_param_interval(params, k),
2101 &refine_intervals[k - SND_PCM_HW_PARAM_FIRST_INTERVAL]);
2102 if (changed)
2103 params->cmask |= 1 << k;
2104 if (changed < 0)
2105 goto _err;
2106 }
2107
2108 for (k = 0; k < RULES; k++)
2109 rstamps[k] = 0;
2110 for (k = 0; k <= SND_PCM_HW_PARAM_LAST_INTERVAL; k++)
2111 vstamps[k] = (params->rmask & (1 << k)) ? 1 : 0;
2112 do {
2113 again = 0;
2114 for (k = 0; k < RULES; k++) {
2115 const snd_pcm_hw_rule_t *r = &refine_rules[k];
2116 unsigned int d;
2117 int doit = 0;
2118 for (d = 0; r->deps[d] >= 0; d++) {
2119 if (vstamps[r->deps[d]] > rstamps[k]) {
2120 doit = 1;
2121 break;
2122 }
2123 }
2124 if (!doit)
2125 continue;
2126 #ifdef RULES_DEBUG
2127 snd_output_printf(log, "Rule %d (%p): ", k, r->func);
2128 if (r->var >= 0) {
2129 snd_output_printf(log, "%s=", snd_pcm_hw_param_name(r->var));
2130 snd_pcm_hw_param_dump(params, r->var, log);
2131 snd_output_puts(log, " -> ");
2132 }
2133 #endif
2134 changed = r->func(params, r);
2135 #ifdef RULES_DEBUG
2136 if (r->var >= 0)
2137 snd_pcm_hw_param_dump(params, r->var, log);
2138 for (d = 0; r->deps[d] >= 0; d++) {
2139 snd_output_printf(log, " %s=", snd_pcm_hw_param_name(r->deps[d]));
2140 snd_pcm_hw_param_dump(params, r->deps[d], log);
2141 }
2142 snd_output_putc(log, '\n');
2143 #endif
2144 rstamps[k] = stamp;
2145 if (changed && r->var >= 0) {
2146 params->cmask |= 1 << r->var;
2147 vstamps[r->var] = stamp;
2148 again = 1;
2149 }
2150 if (changed < 0)
2151 goto _err;
2152 stamp++;
2153 }
2154 } while (again);
2155 if (!params->msbits) {
2156 i = hw_param_interval(params, SND_PCM_HW_PARAM_SAMPLE_BITS);
2157 if (snd_interval_single(i))
2158 params->msbits = snd_interval_value(i);
2159 }
2160
2161 if (!params->rate_den) {
2162 i = hw_param_interval(params, SND_PCM_HW_PARAM_RATE);
2163 if (snd_interval_single(i)) {
2164 params->rate_num = snd_interval_value(i);
2165 params->rate_den = 1;
2166 }
2167 }
2168 params->rmask = 0;
2169 return 0;
2170 _err:
2171 #ifdef RULES_DEBUG
2172 snd_output_printf(log, "refine_soft '%s' (end-%i)\n", pcm->name, changed);
2173 snd_pcm_hw_params_dump(params, log);
2174 snd_output_close(log);
2175 #endif
2176 return changed;
2177 }
2178
_snd_pcm_hw_params_refine(snd_pcm_hw_params_t * params,unsigned int vars,const snd_pcm_hw_params_t * src)2179 int _snd_pcm_hw_params_refine(snd_pcm_hw_params_t *params,
2180 unsigned int vars,
2181 const snd_pcm_hw_params_t *src)
2182 {
2183 int changed, err = 0;
2184 unsigned int k;
2185 for (k = 0; k <= SND_PCM_HW_PARAM_LAST_INTERVAL; ++k) {
2186 if (!(vars & (1 << k)))
2187 continue;
2188 changed = _snd_pcm_hw_param_refine(params, k, src);
2189 if (changed < 0)
2190 err = changed;
2191 }
2192 params->info &= src->info;
2193 params->flags = src->flags; /* propagate all flags to slave */
2194 return err;
2195 }
2196
snd_pcm_hw_refine_slave(snd_pcm_t * pcm,snd_pcm_hw_params_t * params,int (* cprepare)(snd_pcm_t * pcm,snd_pcm_hw_params_t * params),int (* cchange)(snd_pcm_t * pcm,snd_pcm_hw_params_t * params,snd_pcm_hw_params_t * sparams),int (* sprepare)(snd_pcm_t * pcm,snd_pcm_hw_params_t * params),int (* schange)(snd_pcm_t * pcm,snd_pcm_hw_params_t * params,snd_pcm_hw_params_t * sparams),int (* srefine)(snd_pcm_t * pcm,snd_pcm_hw_params_t * sparams))2197 int snd_pcm_hw_refine_slave(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
2198 int (*cprepare)(snd_pcm_t *pcm,
2199 snd_pcm_hw_params_t *params),
2200 int (*cchange)(snd_pcm_t *pcm,
2201 snd_pcm_hw_params_t *params,
2202 snd_pcm_hw_params_t *sparams),
2203 int (*sprepare)(snd_pcm_t *pcm,
2204 snd_pcm_hw_params_t *params),
2205 int (*schange)(snd_pcm_t *pcm,
2206 snd_pcm_hw_params_t *params,
2207 snd_pcm_hw_params_t *sparams),
2208 int (*srefine)(snd_pcm_t *pcm,
2209 snd_pcm_hw_params_t *sparams))
2210
2211 {
2212 #ifdef RULES_DEBUG
2213 snd_output_t *log;
2214 #endif
2215 snd_pcm_hw_params_t sparams;
2216 int err;
2217 unsigned int cmask, changed;
2218 #ifdef RULES_DEBUG
2219 snd_output_stdio_attach(&log, stderr, 0);
2220 #endif
2221 err = cprepare(pcm, params);
2222 if (err < 0)
2223 return err;
2224 err = sprepare(pcm, &sparams);
2225 if (err < 0) {
2226 SNDERR("Slave PCM not usable");
2227 return err;
2228 }
2229 #ifdef RULES_DEBUG
2230 snd_output_printf(log, "hw_refine_slave - enter '%s'\n", pcm->name);
2231 #endif
2232 do {
2233 cmask = params->cmask;
2234 params->cmask = 0;
2235 #ifdef RULES_DEBUG
2236 snd_output_printf(log, "schange '%s' (client)\n", pcm->name);
2237 snd_pcm_hw_params_dump(params, log);
2238 snd_output_printf(log, "schange '%s' (slave)\n", pcm->name);
2239 snd_pcm_hw_params_dump(&sparams, log);
2240 #endif
2241 err = schange(pcm, params, &sparams);
2242 if (err >= 0) {
2243 #ifdef RULES_DEBUG
2244 snd_output_printf(log, "srefine '%s' (client)\n", pcm->name);
2245 snd_pcm_hw_params_dump(params, log);
2246 snd_output_printf(log, "srefine '%s' (slave)\n", pcm->name);
2247 snd_pcm_hw_params_dump(&sparams, log);
2248 #endif
2249 err = srefine(pcm, &sparams);
2250 if (err < 0) {
2251 #ifdef RULES_DEBUG
2252 snd_output_printf(log, "srefine '%s', err < 0 (%i) (client)\n", pcm->name, err);
2253 snd_pcm_hw_params_dump(params, log);
2254 snd_output_printf(log, "srefine '%s', err < 0 (%i) (slave)\n", pcm->name, err);
2255 snd_pcm_hw_params_dump(&sparams, log);
2256 #endif
2257 cchange(pcm, params, &sparams);
2258 return err;
2259 }
2260 } else {
2261 #ifdef RULES_DEBUG
2262 snd_output_printf(log, "schange '%s', err < 0 (%i) (client)\n", pcm->name, err);
2263 snd_pcm_hw_params_dump(params, log);
2264 snd_output_printf(log, "schange '%s', err < 0 (%i) (slave)\n", pcm->name, err);
2265 snd_pcm_hw_params_dump(&sparams, log);
2266 #endif
2267 cchange(pcm, params, &sparams);
2268 return err;
2269 }
2270 #ifdef RULES_DEBUG
2271 snd_output_printf(log, "cchange '%s'\n", pcm->name);
2272 #endif
2273 err = cchange(pcm, params, &sparams);
2274 if (err < 0)
2275 return err;
2276 #ifdef RULES_DEBUG
2277 snd_output_printf(log, "refine_soft '%s'\n", pcm->name);
2278 #endif
2279 err = snd_pcm_hw_refine_soft(pcm, params);
2280 changed = params->cmask;
2281 params->cmask |= cmask;
2282 if (err < 0)
2283 return err;
2284 #ifdef RULES_DEBUG
2285 snd_output_printf(log, "refine_soft ok '%s'\n", pcm->name);
2286 #endif
2287 } while (changed);
2288 #ifdef RULES_DEBUG
2289 snd_output_printf(log, "refine_slave - leave '%s'\n", pcm->name);
2290 snd_output_close(log);
2291 #endif
2292 return 0;
2293 }
2294
snd_pcm_hw_params_slave(snd_pcm_t * pcm,snd_pcm_hw_params_t * params,int (* cchange)(snd_pcm_t * pcm,snd_pcm_hw_params_t * params,snd_pcm_hw_params_t * sparams),int (* sprepare)(snd_pcm_t * pcm,snd_pcm_hw_params_t * params),int (* schange)(snd_pcm_t * pcm,snd_pcm_hw_params_t * params,snd_pcm_hw_params_t * sparams),int (* sparams)(snd_pcm_t * pcm,snd_pcm_hw_params_t * sparams))2295 int snd_pcm_hw_params_slave(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
2296 int (*cchange)(snd_pcm_t *pcm,
2297 snd_pcm_hw_params_t *params,
2298 snd_pcm_hw_params_t *sparams),
2299 int (*sprepare)(snd_pcm_t *pcm,
2300 snd_pcm_hw_params_t *params),
2301 int (*schange)(snd_pcm_t *pcm,
2302 snd_pcm_hw_params_t *params,
2303 snd_pcm_hw_params_t *sparams),
2304 int (*sparams)(snd_pcm_t *pcm,
2305 snd_pcm_hw_params_t *sparams))
2306
2307 {
2308 snd_pcm_hw_params_t slave_params;
2309 int err;
2310 err = sprepare(pcm, &slave_params);
2311 if (err < 0)
2312 return err;
2313 err = schange(pcm, params, &slave_params);
2314 if (err < 0)
2315 return err;
2316 err = sparams(pcm, &slave_params);
2317 if (err < 0)
2318 cchange(pcm, params, &slave_params);
2319 return err;
2320 }
2321
snd_pcm_sw_params_default(snd_pcm_t * pcm,snd_pcm_sw_params_t * params)2322 static int snd_pcm_sw_params_default(snd_pcm_t *pcm, snd_pcm_sw_params_t *params)
2323 {
2324 assert(pcm && params);
2325 assert(pcm->setup);
2326 params->proto = SNDRV_PCM_VERSION;
2327 params->tstamp_mode = SND_PCM_TSTAMP_NONE;
2328 params->tstamp_type = pcm->tstamp_type;
2329 params->period_step = 1;
2330 params->sleep_min = 0;
2331 params->avail_min = pcm->period_size;
2332 params->xfer_align = 1;
2333 params->start_threshold = 1;
2334 params->stop_threshold = pcm->buffer_size;
2335 params->silence_threshold = 0;
2336 params->silence_size = 0;
2337 params->boundary = pcm->buffer_size;
2338 while (params->boundary * 2 <= LONG_MAX - pcm->buffer_size)
2339 params->boundary *= 2;
2340 return 0;
2341 }
2342
2343 #if 0
2344 #define REFINE_DEBUG
2345 #endif
2346
snd_pcm_hw_refine(snd_pcm_t * pcm,snd_pcm_hw_params_t * params)2347 int snd_pcm_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
2348 {
2349 int res;
2350 #ifdef REFINE_DEBUG
2351 snd_output_t *log;
2352 snd_output_stdio_attach(&log, stderr, 0);
2353 #endif
2354 assert(pcm && params);
2355 #ifdef REFINE_DEBUG
2356 snd_output_printf(log, "REFINE called:\n");
2357 snd_pcm_hw_params_dump(params, log);
2358 #endif
2359 if (pcm->ops->hw_refine)
2360 res = pcm->ops->hw_refine(pcm->op_arg, params);
2361 else
2362 res = -ENOSYS;
2363 #ifdef REFINE_DEBUG
2364 snd_output_printf(log, "refine done - result = %i\n", res);
2365 snd_pcm_hw_params_dump(params, log);
2366 snd_output_close(log);
2367 #endif
2368 return res;
2369 }
2370
2371 /* Install one of the configurations present in configuration
2372 space defined by PARAMS.
2373 The configuration chosen is that obtained fixing in this order:
2374 first access
2375 first format
2376 first subformat
2377 min channels
2378 min rate
2379 min period_size
2380 max periods
2381 Return 0 on success otherwise a negative error code
2382 */
_snd_pcm_hw_params_internal(snd_pcm_t * pcm,snd_pcm_hw_params_t * params)2383 int _snd_pcm_hw_params_internal(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
2384 {
2385 int err;
2386 snd_pcm_sw_params_t sw;
2387 int fb, min_align;
2388 err = snd_pcm_hw_refine(pcm, params);
2389 if (err < 0)
2390 return err;
2391 snd_pcm_hw_params_choose(pcm, params);
2392 if (pcm->setup) {
2393 err = snd_pcm_hw_free(pcm);
2394 if (err < 0)
2395 return err;
2396 }
2397 if (pcm->ops->hw_params)
2398 err = pcm->ops->hw_params(pcm->op_arg, params);
2399 else
2400 err = -ENOSYS;
2401 if (err < 0)
2402 return err;
2403
2404 pcm->setup = 1;
2405 INTERNAL(snd_pcm_hw_params_get_access)(params, &pcm->access);
2406 INTERNAL(snd_pcm_hw_params_get_format)(params, &pcm->format);
2407 INTERNAL(snd_pcm_hw_params_get_subformat)(params, &pcm->subformat);
2408 INTERNAL(snd_pcm_hw_params_get_channels)(params, &pcm->channels);
2409 INTERNAL(snd_pcm_hw_params_get_rate)(params, &pcm->rate, 0);
2410 INTERNAL(snd_pcm_hw_params_get_period_time)(params, &pcm->period_time, 0);
2411 INTERNAL(snd_pcm_hw_params_get_period_size)(params, &pcm->period_size, 0);
2412 INTERNAL(snd_pcm_hw_params_get_buffer_size)(params, &pcm->buffer_size);
2413 pcm->sample_bits = snd_pcm_format_physical_width(pcm->format);
2414 pcm->frame_bits = pcm->sample_bits * pcm->channels;
2415 fb = pcm->frame_bits;
2416 min_align = 1;
2417 while (fb % 8) {
2418 fb *= 2;
2419 min_align *= 2;
2420 }
2421 pcm->min_align = min_align;
2422
2423 pcm->hw_flags = params->flags;
2424 pcm->info = params->info;
2425 pcm->msbits = params->msbits;
2426 pcm->rate_num = params->rate_num;
2427 pcm->rate_den = params->rate_den;
2428 pcm->fifo_size = params->fifo_size;
2429
2430 /* Default sw params */
2431 memset(&sw, 0, sizeof(sw));
2432 snd_pcm_sw_params_default(pcm, &sw);
2433 err = snd_pcm_sw_params(pcm, &sw);
2434 if (err < 0)
2435 return err;
2436
2437 if (pcm->mmap_rw ||
2438 pcm->access == SND_PCM_ACCESS_MMAP_INTERLEAVED ||
2439 pcm->access == SND_PCM_ACCESS_MMAP_NONINTERLEAVED ||
2440 pcm->access == SND_PCM_ACCESS_MMAP_COMPLEX) {
2441 err = snd_pcm_mmap(pcm);
2442 }
2443 if (err < 0)
2444 return err;
2445 return 0;
2446 }
2447
2448