source: contrib/API/lib/unilib.c@ 578

Last change on this file since 578 was 541, checked in by David Azarewicz, 15 years ago

Initial import

File size: 33.8 KB
Line 
1/*
2 * This file is part of uniaud.dll.
3 *
4 * Copyright (c) 2010 Mensys BV
5 * Copyright (c) 2007 Vlad Stelmahovsky aka Vladest
6 *
7 * This library is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU Lesser General Public License as
9 * published by the Free Software Foundation, either version 3 of
10 * the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License and the GNU General Public License along with this library.
19 * If not, see <http://www.gnu.org/licenses/>.
20 */
21#define INCL_DOS
22#define INCL_DOSERRORS
23#include <os2.h>
24#include <stdlib.h>
25#include <stdio.h>
26#include <assert.h>
27#include <string.h>
28#include <strings.h>
29
30#include "internal.h"
31
32/*
33 * redefine ALSA internals to uniaud
34 */
35
36#define snd_pcm_hw_refine _uniaud_pcm_refine_hw_params
37#define snd_pcm_t uniaud_pcm
38
39typedef enum _snd_set_mode {
40 SND_CHANGE,
41 SND_TRY,
42 SND_TEST,
43} snd_set_mode_t;
44
45MASK_INLINE unsigned int ld2(uint32_t v)
46{
47 unsigned r = 0;
48
49 if (v >= 0x10000) {
50 v >>= 16;
51 r += 16;
52 }
53 if (v >= 0x100) {
54 v >>= 8;
55 r += 8;
56 }
57 if (v >= 0x10) {
58 v >>= 4;
59 r += 4;
60 }
61 if (v >= 4) {
62 v >>= 2;
63 r += 2;
64 }
65 if (v >= 2)
66 r++;
67 return r;
68}
69
70void boundary_sub(int a, int adir, int b, int bdir, int *c, int *cdir)
71{
72 adir = adir < 0 ? -1 : (adir > 0 ? 1 : 0);
73 bdir = bdir < 0 ? -1 : (bdir > 0 ? 1 : 0);
74 *c = a - b;
75 *cdir = adir - bdir;
76 if (*cdir == -2) {
77 assert(*c > INT_MIN);
78 (*c)--;
79 } else if (*cdir == 2) {
80 assert(*c < INT_MAX);
81 (*c)++;
82 }
83}
84
85int boundary_lt(unsigned int a, int adir, unsigned int b, int bdir)
86{
87 assert(a > 0 || adir >= 0);
88 assert(b > 0 || bdir >= 0);
89 if (adir < 0) {
90 a--;
91 adir = 1;
92 } else if (adir > 0)
93 adir = 1;
94 if (bdir < 0) {
95 b--;
96 bdir = 1;
97 } else if (bdir > 0)
98 bdir = 1;
99 return a < b || (a == b && adir < bdir);
100}
101
102/* Return 1 if min is nearer to best than max */
103int boundary_nearer(int min, int mindir, int best, int bestdir, int max, int maxdir)
104{
105 int dmin, dmindir;
106 int dmax, dmaxdir;
107 boundary_sub(best, bestdir, min, mindir, &dmin, &dmindir);
108 boundary_sub(max, maxdir, best, bestdir, &dmax, &dmaxdir);
109 return boundary_lt(dmin, dmindir, dmax, dmaxdir);
110}
111
112inline int snd_interval_empty(const snd_interval_t *i)
113{
114 return i->empty;
115}
116
117inline int snd_interval_single(const snd_interval_t *i)
118{
119 assert(!snd_interval_empty(i));
120 return (i->min == i->max ||
121 (i->min + 1 == i->max && i->openmax));
122}
123
124INTERVAL_INLINE int snd_interval_value(const snd_interval_t *i)
125{
126 assert(snd_interval_single(i));
127 return i->min;
128}
129
130inline void snd_mask_none(snd_mask_t *mask)
131{
132 memset(mask, 0, sizeof(*mask));
133}
134
135inline int snd_mask_single(const snd_mask_t *mask)
136{
137 int i, c = 0;
138// assert(!snd_mask_empty(mask));
139 for (i = 0; i < SNDRV_MASK_SIZE; i++) {
140 if (! mask->bits[i])
141 continue;
142 if (mask->bits[i] & (mask->bits[i] - 1))
143 return 0;
144 if (c)
145 return 0;
146 c++;
147 }
148 return 1;
149}
150
151inline void snd_mask_leave(snd_mask_t *mask, unsigned int val)
152{
153 unsigned int v;
154 //assert(val <= SNDRV_MASK_BITS);
155 v = mask->bits[MASK_OFS(val)] & MASK_BIT(val);
156 snd_mask_none(mask);
157 mask->bits[MASK_OFS(val)] = v;
158}
159
160inline int snd_mask_empty(const snd_mask_t *mask)
161{
162 int i;
163 for (i = 0; i < SNDRV_MASK_SIZE; i++)
164 if (mask->bits[i])
165 return 0;
166 return 1;
167}
168
169inline unsigned int snd_mask_min(const snd_mask_t *mask)
170{
171 int i;
172 assert(!snd_mask_empty(mask));
173 for (i = 0; i < MASK_SIZE; i++) {
174 if (mask->bits[i])
175 return ffs(mask->bits[i]) - 1 + (i << 5);
176 }
177 return 0;
178}
179
180MASK_INLINE int snd_mask_refine_first(snd_mask_t *mask)
181{
182 if (snd_mask_empty(mask))
183 return -ENOENT;
184 if (snd_mask_single(mask))
185 return 0;
186 snd_mask_leave(mask, snd_mask_min(mask));
187 return 1;
188}
189
190int snd_interval_refine_first(snd_interval_t *i)
191{
192 if (snd_interval_empty(i))
193 return -ENOENT;
194 if (snd_interval_single(i))
195 return 0;
196 i->max = i->min;
197 i->openmax = i->openmin;
198 if (i->openmax)
199 i->max++;
200 return 1;
201}
202
203INTERVAL_INLINE int snd_interval_max(const snd_interval_t *i)
204{
205 assert(!snd_interval_empty(i));
206 return i->max;
207}
208
209inline void snd_mask_any(snd_mask_t *mask)
210{
211 memset(mask, 0xff, SNDRV_MASK_SIZE * sizeof(uint32_t));
212}
213
214inline void snd_interval_any(snd_interval_t *i)
215{
216 i->min = 0;
217 i->openmin = 0;
218 i->max = UINT_MAX;
219 i->openmax = 0;
220 i->integer = 0;
221 i->empty = 0;
222}
223
224int snd_interval_refine_last(snd_interval_t *i)
225{
226 if (snd_interval_empty(i))
227 return -ENOENT;
228 if (snd_interval_single(i))
229 return 0;
230 i->min = i->max;
231 i->openmin = i->openmax;
232 if (i->openmin)
233 i->min--;
234 return 1;
235}
236
237static inline int hw_is_mask(int var)
238{
239 return var >= SNDRV_PCM_HW_PARAM_FIRST_MASK &&
240 var <= SNDRV_PCM_HW_PARAM_LAST_MASK;
241}
242
243static inline int hw_is_interval(int var)
244{
245 return var >= SNDRV_PCM_HW_PARAM_FIRST_INTERVAL &&
246 var <= SNDRV_PCM_HW_PARAM_LAST_INTERVAL;
247}
248
249static inline snd_mask_t *hw_param_mask(snd_pcm_hw_params_t *params,
250 snd_pcm_hw_param_t var)
251{
252 return &params->masks[var - SNDRV_PCM_HW_PARAM_FIRST_MASK];
253}
254
255#if 0
256inline snd_interval_t *hw_param_interval(snd_pcm_hw_params_t *params,
257 snd_pcm_hw_param_t var)
258{
259 return &params->intervals[var - SNDRV_PCM_HW_PARAM_FIRST_INTERVAL];
260}
261#endif
262
263static inline const snd_interval_t *hw_param_interval_c(const snd_pcm_hw_params_t *params,
264 snd_pcm_hw_param_t var)
265{
266 return (const snd_interval_t *)hw_param_interval((snd_pcm_hw_params_t*) params, var);
267}
268
269inline int snd_mask_refine_set(snd_mask_t *mask, unsigned int val)
270{
271 int changed;
272// assert(!snd_mask_empty(mask));
273 changed = !snd_mask_single(mask);
274 snd_mask_leave(mask, val);
275 if (snd_mask_empty(mask))
276 return -EINVAL;
277 return changed;
278}
279
280MASK_INLINE int snd_mask_value(const snd_mask_t *mask)
281{
282 assert(!snd_mask_empty(mask));
283 return snd_mask_min(mask);
284}
285
286inline void snd_interval_none(snd_interval_t *i)
287{
288 i->empty = 1;
289}
290
291inline int snd_interval_checkempty(const snd_interval_t *i)
292{
293 return (i->min > i->max ||
294 (i->min == i->max && (i->openmin || i->openmax)));
295}
296
297INTERVAL_INLINE int snd_interval_min(const snd_interval_t *i)
298{
299 assert(!snd_interval_empty(i));
300 return i->min;
301}
302
303static inline const snd_mask_t *hw_param_mask_c(const snd_pcm_hw_params_t *params,
304 snd_pcm_hw_param_t var)
305{
306 return (const snd_mask_t *)hw_param_mask((snd_pcm_hw_params_t*) params, var);
307}
308
309int snd_pcm_hw_param_empty(const snd_pcm_hw_params_t *params,
310 snd_pcm_hw_param_t var)
311{
312 if (hw_is_mask(var))
313 return snd_mask_empty(hw_param_mask_c(params, var));
314 if (hw_is_interval(var))
315 return snd_interval_empty(hw_param_interval_c(params, var));
316 assert(0);
317 return -EINVAL;
318}
319
320int snd_interval_refine_min(snd_interval_t *i, unsigned int min, int openmin)
321{
322 int changed = 0;
323 if (snd_interval_empty(i))
324 return -ENOENT;
325 if (i->min < min) {
326 i->min = min;
327 i->openmin = openmin;
328 changed = 1;
329 } else if (i->min == min && !i->openmin && openmin) {
330 i->openmin = 1;
331 changed = 1;
332 }
333 if (i->integer) {
334 if (i->openmin) {
335 i->min++;
336 i->openmin = 0;
337 }
338 }
339 if (snd_interval_checkempty(i)) {
340 snd_interval_none(i);
341 return -EINVAL;
342 }
343 return changed;
344}
345
346int snd_interval_refine_max(snd_interval_t *i, unsigned int max, int openmax)
347{
348 int changed = 0;
349 if (snd_interval_empty(i))
350 return -ENOENT;
351 if (i->max > max) {
352 i->max = max;
353 i->openmax = openmax;
354 changed = 1;
355 } else if (i->max == max && !i->openmax && openmax) {
356 i->openmax = 1;
357 changed = 1;
358 }
359 if (i->integer) {
360 if (i->openmax) {
361 i->max--;
362 i->openmax = 0;
363 }
364 }
365 if (snd_interval_checkempty(i)) {
366 snd_interval_none(i);
367 return -EINVAL;
368 }
369 return changed;
370}
371
372/**
373 * snd_interval_refine - refine the interval value of configurator
374 * @i: the interval value to refine
375 * @v: the interval value to refer to
376 *
377 * Refines the interval value with the reference value.
378 * The interval is changed to the range satisfying both intervals.
379 * The interval status (min, max, integer, etc.) are evaluated.
380 *
381 * Returns non-zero if the value is changed, zero if not changed.
382 */
383int snd_interval_refine(snd_interval_t *i, const snd_interval_t *v)
384{
385 int changed = 0;
386// assert(!snd_interval_empty(i));
387 if (i->min < v->min) {
388 i->min = v->min;
389 i->openmin = v->openmin;
390 changed = 1;
391 } else if (i->min == v->min && !i->openmin && v->openmin) {
392 i->openmin = 1;
393 changed = 1;
394 }
395 if (i->max > v->max) {
396 i->max = v->max;
397 i->openmax = v->openmax;
398 changed = 1;
399 } else if (i->max == v->max && !i->openmax && v->openmax) {
400 i->openmax = 1;
401 changed = 1;
402 }
403 if (!i->integer && v->integer) {
404 i->integer = 1;
405 changed = 1;
406 }
407 if (i->integer) {
408 if (i->openmin) {
409 i->min++;
410 i->openmin = 0;
411 }
412 if (i->openmax) {
413 i->max--;
414 i->openmax = 0;
415 }
416 } else if (!i->openmin && !i->openmax && i->min == i->max)
417 i->integer = 1;
418 if (snd_interval_checkempty(i)) {
419 snd_interval_none(i);
420 return -EINVAL;
421 }
422 return changed;
423}
424
425int snd_interval_refine_set(snd_interval_t *i, unsigned int val)
426{
427 snd_interval_t t;
428 t.empty = 0;
429 t.min = t.max = val;
430 t.openmin = t.openmax = 0;
431 t.integer = 1;
432 return snd_interval_refine(i, &t);
433}
434
435int _snd_pcm_hw_param_set(snd_pcm_hw_params_t *params,
436 snd_pcm_hw_param_t var, unsigned int val, int dir)
437{
438 int changed;
439 if (hw_is_mask(var)) {
440 snd_mask_t *m = hw_param_mask(params, var);
441 if (val == 0 && dir < 0) {
442 changed = -EINVAL;
443 snd_mask_none(m);
444 } else {
445 if (dir > 0)
446 val++;
447 else if (dir < 0)
448 val--;
449 changed = snd_mask_refine_set(hw_param_mask(params, var), val);
450 }
451 } else if (hw_is_interval(var)) {
452 snd_interval_t *i = hw_param_interval(params, var);
453 if (val == 0 && dir < 0) {
454 changed = -EINVAL;
455 snd_interval_none(i);
456 } else if (dir == 0)
457 changed = snd_interval_refine_set(i, val);
458 else {
459 snd_interval_t t;
460 t.openmin = 1;
461 t.openmax = 1;
462 t.empty = 0;
463 t.integer = 0;
464 if (dir < 0) {
465 t.min = val - 1;
466 t.max = val;
467 } else {
468 t.min = val;
469 t.max = val+1;
470 }
471 changed = snd_interval_refine(i, &t);
472 }
473 } else {
474// assert(0);
475 return -EINVAL;
476 }
477 if (changed) {
478 params->cmask |= 1 << var;
479 params->rmask |= 1 << var;
480 }
481 return changed;
482}
483
484void _snd_pcm_hw_param_any(snd_pcm_hw_params_t *params, snd_pcm_hw_param_t var)
485{
486 if (hw_is_mask(var)) {
487 snd_mask_any(hw_param_mask(params, var));
488 params->cmask |= 1 << var;
489 params->rmask |= 1 << var;
490 return;
491 }
492 if (hw_is_interval(var)) {
493 snd_interval_any(hw_param_interval(params, var));
494 params->cmask |= 1 << var;
495 params->rmask |= 1 << var;
496 return;
497 }
498}
499
500void _snd_pcm_hw_params_any(snd_pcm_hw_params_t *params)
501{
502 unsigned int k;
503 memset(params, 0, sizeof(*params));
504 for (k = SNDRV_PCM_HW_PARAM_FIRST_MASK; k <= SNDRV_PCM_HW_PARAM_LAST_MASK; k++)
505 _snd_pcm_hw_param_any(params, k);
506 for (k = SNDRV_PCM_HW_PARAM_FIRST_INTERVAL; k <= SNDRV_PCM_HW_PARAM_LAST_INTERVAL; k++)
507 _snd_pcm_hw_param_any(params, k);
508 params->info = ~0U;
509}
510
511inline void snd_mask_reset_range(snd_mask_t *mask, unsigned int from, unsigned int to)
512{
513 unsigned int i;
514 assert(to <= SND_MASK_MAX && from <= to);
515 for (i = from; i <= to; i++)
516 mask->bits[MASK_OFS(i)] &= ~MASK_BIT(i);
517}
518
519inline int snd_mask_refine_min(snd_mask_t *mask, unsigned int val)
520{
521 if (snd_mask_empty(mask))
522 return -ENOENT;
523 if (snd_mask_min(mask) >= val)
524 return 0;
525 snd_mask_reset_range(mask, 0, val - 1);
526 if (snd_mask_empty(mask))
527 return -EINVAL;
528 return 1;
529}
530
531MASK_INLINE unsigned int snd_mask_max(const snd_mask_t *mask)
532{
533 int i;
534 assert(!snd_mask_empty(mask));
535 for (i = MASK_SIZE - 1; i >= 0; i--) {
536 if (mask->bits[i])
537 return ld2(mask->bits[i]) + (i << 5);
538 }
539 return 0;
540}
541
542MASK_INLINE int snd_mask_refine_max(snd_mask_t *mask, unsigned int val)
543{
544 if (snd_mask_empty(mask))
545 return -ENOENT;
546 if (snd_mask_max(mask) <= val)
547 return 0;
548 snd_mask_reset_range(mask, val + 1, SND_MASK_MAX);
549 if (snd_mask_empty(mask))
550 return -EINVAL;
551 return 1;
552}
553
554MASK_INLINE int snd_mask_refine_last(snd_mask_t *mask)
555{
556 if (snd_mask_empty(mask))
557 return -ENOENT;
558 if (snd_mask_single(mask))
559 return 0;
560 snd_mask_leave(mask, snd_mask_max(mask));
561 return 1;
562}
563
564int _snd_pcm_hw_param_set_min(snd_pcm_hw_params_t *params,
565 snd_pcm_hw_param_t var, unsigned int val, int dir)
566{
567 int changed;
568 int openmin = 0;
569 if (dir) {
570 if (dir > 0) {
571 openmin = 1;
572 } else if (dir < 0) {
573 if (val > 0) {
574 openmin = 1;
575 val--;
576 }
577 }
578 }
579 if (hw_is_mask(var))
580 changed = snd_mask_refine_min(hw_param_mask(params, var), val + !!openmin);
581 else if (hw_is_interval(var))
582 changed = snd_interval_refine_min(hw_param_interval(params, var), val, openmin);
583 else {
584 assert(0);
585 return -EINVAL;
586 }
587 if (changed) {
588 params->cmask |= 1 << var;
589 params->rmask |= 1 << var;
590 }
591 return changed;
592}
593
594/* Return the minimum value for field PAR. */
595int snd_pcm_hw_param_get_min(const snd_pcm_hw_params_t *params, snd_pcm_hw_param_t var,
596 unsigned int *val, int *dir)
597{
598 if (hw_is_mask(var)) {
599 const snd_mask_t *m = hw_param_mask_c(params, var);
600 assert(!snd_mask_empty(m));
601 if (dir)
602 *dir = 0;
603 if (val)
604 *val = snd_mask_min(m);
605 return 0;
606 } else if (hw_is_interval(var)) {
607 const snd_interval_t *i = hw_param_interval_c(params, var);
608 assert(!snd_interval_empty(i));
609 if (dir)
610 *dir = i->openmin;
611 if (val)
612 *val = snd_interval_min(i);
613 return 0;
614 }
615 assert(0);
616 return 0;
617}
618
619/* Inside configuration space defined by PARAMS remove from PAR all
620 values < VAL. Reduce configuration space accordingly.
621 Return new minimum or -EINVAL if the configuration space is empty
622*/
623int snd_pcm_hw_param_set_min(uniaud_pcm *pcm, snd_pcm_hw_params_t *params,
624 snd_set_mode_t mode,
625 snd_pcm_hw_param_t var, unsigned int *val, int *dir)
626{
627 snd_pcm_hw_params_t save;
628 int err;
629 switch (mode) {
630 case SND_CHANGE:
631 break;
632 case SND_TRY:
633 save = *params;
634 break;
635 case SND_TEST:
636 save = *params;
637 params = &save;
638 break;
639 default:
640 assert(0);
641 return -EINVAL;
642 }
643 err = _snd_pcm_hw_param_set_min(params, var, *val, dir ? *dir : 0);
644 if (err < 0)
645 goto _fail;
646 if ((mode != SND_TEST || hw_is_interval(var)) && params->rmask) {
647 err = snd_pcm_hw_refine(pcm, params);
648 if (err < 0)
649 goto _fail;
650 if (snd_pcm_hw_param_empty(params, var)) {
651 err = -ENOENT;
652 goto _fail;
653 }
654 }
655 return snd_pcm_hw_param_get_min(params, var, val, dir);
656 _fail:
657 if (mode == SND_TRY)
658 *params = save;
659 return err;
660}
661
662int _snd_pcm_hw_param_set_max(snd_pcm_hw_params_t *params,
663 snd_pcm_hw_param_t var, unsigned int val, int dir)
664{
665 int changed;
666 int openmax = 0;
667 if (dir) {
668 if (dir < 0) {
669 openmax = 1;
670 } else if (dir > 0) {
671 openmax = 1;
672 val++;
673 }
674 }
675 if (hw_is_mask(var)) {
676 if (val == 0 && openmax) {
677 snd_mask_none(hw_param_mask(params, var));
678 changed = -EINVAL;
679 } else
680 changed = snd_mask_refine_max(hw_param_mask(params, var), val - !!openmax);
681 } else if (hw_is_interval(var))
682 changed = snd_interval_refine_max(hw_param_interval(params, var), val, openmax);
683 else {
684 assert(0);
685 return -EINVAL;
686 }
687 if (changed) {
688 params->cmask |= 1 << var;
689 params->rmask |= 1 << var;
690 }
691 return changed;
692}
693
694/* Return the maximum value for field PAR. */
695int snd_pcm_hw_param_get_max(const snd_pcm_hw_params_t *params, snd_pcm_hw_param_t var,
696 unsigned int *val, int *dir)
697{
698 if (hw_is_mask(var)) {
699 const snd_mask_t *m = hw_param_mask_c(params, var);
700 assert(!snd_mask_empty(m));
701 if (dir)
702 *dir = 0;
703 if (val)
704 *val = snd_mask_max(m);
705 return 0;
706 } else if (hw_is_interval(var)) {
707 const snd_interval_t *i = hw_param_interval_c(params, var);
708 assert(!snd_interval_empty(i));
709 if (dir)
710 *dir = - (int) i->openmax;
711 if (val)
712 *val = snd_interval_max(i);
713 return 0;
714 }
715 assert(0);
716 return 0;
717}
718
719/* Inside configuration space defined by PARAMS remove from PAR all
720 values >= VAL + 1. Reduce configuration space accordingly.
721 Return new maximum or -EINVAL if the configuration space is empty
722*/
723int snd_pcm_hw_param_set_max(uniaud_pcm *pcm, snd_pcm_hw_params_t *params,
724 snd_set_mode_t mode,
725 snd_pcm_hw_param_t var, unsigned int *val, int *dir)
726{
727 snd_pcm_hw_params_t save;
728 int err;
729 switch (mode) {
730 case SND_CHANGE:
731 break;
732 case SND_TRY:
733 save = *params;
734 break;
735 case SND_TEST:
736 save = *params;
737 params = &save;
738 break;
739 default:
740 assert(0);
741 return -EINVAL;
742 }
743 err = _snd_pcm_hw_param_set_max(params, var, *val, dir ? *dir : 0);
744 if (err < 0)
745 goto _fail;
746 if ((mode != SND_TEST || hw_is_interval(var)) && params->rmask) {
747 err = snd_pcm_hw_refine(pcm, params);
748 if (err < 0)
749 goto _fail;
750 if (snd_pcm_hw_param_empty(params, var)) {
751 err = -ENOENT;
752 goto _fail;
753 }
754 }
755 return snd_pcm_hw_param_get_max(params, var, val, dir);
756 _fail:
757 if (mode == SND_TRY)
758 *params = save;
759 return err;
760}
761
762static int _snd_pcm_hw_param_set_last(snd_pcm_hw_params_t *params,
763 snd_pcm_hw_param_t var)
764{
765 int changed;
766 if (hw_is_mask(var))
767 changed = snd_mask_refine_last(hw_param_mask(params, var));
768 else if (hw_is_interval(var))
769 changed = snd_interval_refine_last(hw_param_interval(params, var));
770 else {
771 assert(0);
772 return -EINVAL;
773 }
774 if (changed > 0) {
775 params->cmask |= 1 << var;
776 params->rmask |= 1 << var;
777 }
778 return changed;
779}
780
781/* Return the value for field PAR if it's fixed in configuration space
782 defined by PARAMS. Return -EINVAL otherwise
783*/
784int snd_pcm_hw_param_get(const snd_pcm_hw_params_t *params, snd_pcm_hw_param_t var,
785 unsigned int *val, int *dir)
786{
787 if (hw_is_mask(var)) {
788 const snd_mask_t *mask = hw_param_mask_c(params, var);
789 if (snd_mask_empty(mask) || !snd_mask_single(mask))
790 return -EINVAL;
791 if (dir)
792 *dir = 0;
793 if (val)
794 *val = snd_mask_value(mask);
795 return 0;
796 } else if (hw_is_interval(var)) {
797 const snd_interval_t *i = hw_param_interval_c(params, var);
798 if (snd_interval_empty(i) || !snd_interval_single(i))
799 return -EINVAL;
800 if (dir)
801 *dir = i->openmin;
802 if (val)
803 *val = snd_interval_value(i);
804 return 0;
805 }
806 assert(0);
807 return -EINVAL;
808}
809
810/* Inside configuration space defined by PARAMS remove from PAR all
811 values < maximum. Reduce configuration space accordingly.
812 Return the maximum.
813*/
814int snd_pcm_hw_param_set_last(uniaud_pcm *pcm,
815 snd_pcm_hw_params_t *params,
816 snd_pcm_hw_param_t var,
817 unsigned int *rval, int *dir)
818{
819 int err;
820
821 err = _snd_pcm_hw_param_set_last(params, var);
822 if (err < 0)
823 return err;
824 if (params->rmask) {
825 err = snd_pcm_hw_refine(pcm, params);
826 if (err < 0)
827 return err;
828 }
829 return snd_pcm_hw_param_get(params, var, rval, dir);
830}
831
832static int _snd_pcm_hw_param_set_first(snd_pcm_hw_params_t *params,
833 snd_pcm_hw_param_t var)
834{
835 int changed;
836 if (hw_is_mask(var))
837 changed = snd_mask_refine_first(hw_param_mask(params, var));
838 else if (hw_is_interval(var))
839 changed = snd_interval_refine_first(hw_param_interval(params, var));
840 else {
841 assert(0);
842 return -EINVAL;
843 }
844 if (changed > 0) {
845 params->cmask |= 1 << var;
846 params->rmask |= 1 << var;
847 }
848 return changed;
849}
850
851/* Inside configuration space defined by PARAMS remove from PAR all
852 values > minimum. Reduce configuration space accordingly.
853 Return the minimum.
854*/
855int snd_pcm_hw_param_set_first(uniaud_pcm *pcm,
856 snd_pcm_hw_params_t *params,
857 snd_pcm_hw_param_t var,
858 unsigned int *rval, int *dir)
859{
860 int err;
861
862 err = _snd_pcm_hw_param_set_first(params, var);
863 if (err < 0)
864 return err;
865 if (params->rmask) {
866 err = snd_pcm_hw_refine(pcm, params);
867 if (err < 0)
868 return err;
869 }
870 return snd_pcm_hw_param_get(params, var, rval, dir);
871}
872
873/* Inside configuration space defined by PARAMS set PAR to the available value
874 nearest to VAL. Reduce configuration space accordingly.
875 This function cannot be called for SND_PCM_HW_PARAM_ACCESS,
876 SND_PCM_HW_PARAM_FORMAT, SND_PCM_HW_PARAM_SUBFORMAT.
877 Return the value found.
878 */
879int snd_pcm_hw_param_set_near(uniaud_pcm *pcm, snd_pcm_hw_params_t *params,
880 snd_pcm_hw_param_t var,
881 unsigned int *val, int *dir)
882{
883 snd_pcm_hw_params_t save;
884 int err;
885 unsigned int best = *val, saved_min;
886 int last = 0;
887 int min, max;
888 int mindir, maxdir;
889 int valdir = dir ? *dir : 0;
890 snd_interval_t *i;
891 /* FIXME */
892 if (best > INT_MAX)
893 best = INT_MAX;
894 min = max = best;
895 mindir = maxdir = valdir;
896 if (maxdir > 0)
897 maxdir = 0;
898 else if (maxdir == 0)
899 maxdir = -1;
900 else {
901 maxdir = 1;
902 max--;
903 }
904 save = *params;
905 saved_min = min;
906 err = snd_pcm_hw_param_set_min(pcm, params, SND_CHANGE, var, (unsigned int *)&min, &mindir);
907
908 i = hw_param_interval(params, var);
909 if (!snd_interval_empty(i) && snd_interval_single(i))
910 return snd_pcm_hw_param_get_min(params, var, val, dir);
911
912 if (err >= 0) {
913 snd_pcm_hw_params_t params1;
914 if (max < 0)
915 goto _end;
916 if ((unsigned int)min == saved_min && mindir == valdir)
917 goto _end;
918 params1 = save;
919 err = snd_pcm_hw_param_set_max(pcm, &params1, SND_CHANGE, var, (unsigned int *)&max, &maxdir);
920 if (err < 0)
921 goto _end;
922 if (boundary_nearer(max, maxdir, best, valdir, min, mindir)) {
923 *params = params1;
924 last = 1;
925 }
926 } else {
927 *params = save;
928 err = snd_pcm_hw_param_set_max(pcm, params, SND_CHANGE, var, (unsigned int *)&max, &maxdir);
929 if (err < 0)
930 return err;
931 last = 1;
932 }
933 _end:
934 if (last)
935 err = snd_pcm_hw_param_set_last(pcm, params, var, val, dir);
936 else
937 err = snd_pcm_hw_param_set_first(pcm, params, var, val, dir);
938 return err;
939}
940
941/**
942 * \brief Restrict a configuration space to have rate nearest to a target
943 * \param pcm PCM handle
944 * \param params Configuration space
945 * \param val approximate target rate / returned approximate set rate
946 * \return 0 otherwise a negative error code if configuration space is empty
947 *
948 * target/chosen exact value is <,=,> val following dir (-1,0,1)
949 */
950int snd_pcm_hw_params_set_rate_near(uniaud_pcm *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir)
951{
952 return snd_pcm_hw_param_set_near(pcm, params, SND_PCM_HW_PARAM_RATE, val, dir);
953}
954
955/**
956 * \brief Restrict a configuration space to have buffer time nearest to a target
957 * \param pcm PCM handle
958 * \param params Configuration space
959 * \param val approximate target buffer duration in us / returned chosen approximate target buffer duration
960 * \return 0 otherwise a negative error code if configuration space is empty
961 *
962 * target/chosen exact value is <,=,> val following dir (-1,0,1)
963 */
964int snd_pcm_hw_params_set_buffer_time_near(uniaud_pcm *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir)
965{
966 return snd_pcm_hw_param_set_near(pcm, params, SND_PCM_HW_PARAM_BUFFER_TIME, val, dir);
967}
968
969/**
970 * \brief Restrict a configuration space to have period time nearest to a target
971 * \param pcm PCM handle
972 * \param params Configuration space
973 * \param val approximate target period duration in us / returned chosen approximate target period duration
974 * \return 0 otherwise a negative error code if configuration space is empty
975 *
976 * target/chosen exact value is <,=,> val following dir (-1,0,1)
977 */
978int snd_pcm_hw_params_set_period_time_near(uniaud_pcm *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir)
979{
980 return snd_pcm_hw_param_set_near(pcm, params, SND_PCM_HW_PARAM_PERIOD_TIME, val, dir);
981}
982
983/**
984 * \brief Extract buffer size from a configuration space
985 * \param params Configuration space
986 * \param val Returned buffer size in frames
987 * \return 0 otherwise a negative error code if not exactly one is present
988 */
989int snd_pcm_hw_params_get_buffer_size(const snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val)
990{
991 unsigned int _val;
992 int err = snd_pcm_hw_param_get(params, SND_PCM_HW_PARAM_BUFFER_SIZE, &_val, NULL);
993 if (err >= 0)
994 *val = _val;
995 return err;
996}
997
998/**
999 * \brief Extract period size from a configuration space
1000 * \param params Configuration space
1001 * \param val Returned approximate period size in frames
1002 * \param dir Sub unit direction
1003 * \return 0 otherwise a negative error code if not exactly one is present
1004 *
1005 * Actual exact value is <,=,> the approximate one following dir (-1, 0, 1)
1006 */
1007int snd_pcm_hw_params_get_period_size(const snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val, int *dir)
1008{
1009 unsigned int _val;
1010 int err = snd_pcm_hw_param_get(params, SND_PCM_HW_PARAM_PERIOD_SIZE, &_val, dir);
1011 if (err >= 0)
1012 *val = _val;
1013 return err;
1014}
1015
1016/**
1017 * \brief Return bytes needed to store a quantity of PCM sample
1018 * \param format Sample format
1019 * \param samples Samples count
1020 * \return bytes needed, a negative error code if not integer or unknown
1021 */
1022ssize_t uniaud_pcm_format_size(snd_pcm_format_t format, size_t samples)
1023{
1024 switch (format) {
1025 case SNDRV_PCM_FORMAT_S8:
1026 case SNDRV_PCM_FORMAT_U8:
1027 return samples;
1028 case SNDRV_PCM_FORMAT_S16_LE:
1029 case SNDRV_PCM_FORMAT_S16_BE:
1030 case SNDRV_PCM_FORMAT_U16_LE:
1031 case SNDRV_PCM_FORMAT_U16_BE:
1032 return samples * 2;
1033 case SNDRV_PCM_FORMAT_S18_3LE:
1034 case SNDRV_PCM_FORMAT_S18_3BE:
1035 case SNDRV_PCM_FORMAT_U18_3LE:
1036 case SNDRV_PCM_FORMAT_U18_3BE:
1037 case SNDRV_PCM_FORMAT_S20_3LE:
1038 case SNDRV_PCM_FORMAT_S20_3BE:
1039 case SNDRV_PCM_FORMAT_U20_3LE:
1040 case SNDRV_PCM_FORMAT_U20_3BE:
1041 case SNDRV_PCM_FORMAT_S24_3LE:
1042 case SNDRV_PCM_FORMAT_S24_3BE:
1043 case SNDRV_PCM_FORMAT_U24_3LE:
1044 case SNDRV_PCM_FORMAT_U24_3BE:
1045 return samples * 3;
1046 case SNDRV_PCM_FORMAT_S24_LE:
1047 case SNDRV_PCM_FORMAT_S24_BE:
1048 case SNDRV_PCM_FORMAT_U24_LE:
1049 case SNDRV_PCM_FORMAT_U24_BE:
1050 case SNDRV_PCM_FORMAT_S32_LE:
1051 case SNDRV_PCM_FORMAT_S32_BE:
1052 case SNDRV_PCM_FORMAT_U32_LE:
1053 case SNDRV_PCM_FORMAT_U32_BE:
1054 case SNDRV_PCM_FORMAT_FLOAT_LE:
1055 case SNDRV_PCM_FORMAT_FLOAT_BE:
1056 return samples * 4;
1057 case SNDRV_PCM_FORMAT_FLOAT64_LE:
1058 case SNDRV_PCM_FORMAT_FLOAT64_BE:
1059 return samples * 8;
1060 case SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE:
1061 case SNDRV_PCM_FORMAT_IEC958_SUBFRAME_BE:
1062 return samples * 4;
1063 case SNDRV_PCM_FORMAT_MU_LAW:
1064 case SNDRV_PCM_FORMAT_A_LAW:
1065 return samples;
1066 case SNDRV_PCM_FORMAT_IMA_ADPCM:
1067 if (samples & 1)
1068 return -EINVAL;
1069 return samples / 2;
1070 default:
1071 assert(0);
1072 return -EINVAL;
1073 }
1074}
1075
1076/**
1077 * \brief Fill params with a full configuration space for a PCM
1078 * \param pcm PCM handle
1079 * \param params Configuration space
1080 */
1081int snd_pcm_hw_params_any(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
1082{
1083 _snd_pcm_hw_params_any(params);
1084 return snd_pcm_hw_refine(pcm, params);
1085}
1086
1087/**
1088 * \brief Get delay from a PCM status container (see #snd_pcm_delay)
1089 * \return Delay in frames
1090 *
1091 * Delay is distance between current application frame position and
1092 * sound frame position.
1093 * It's positive and less than buffer size in normal situation,
1094 * negative on playback underrun and greater than buffer size on
1095 * capture overrun.
1096 */
1097snd_pcm_sframes_t snd_pcm_status_get_delay(const snd_pcm_status_t *obj)
1098{
1099 assert(obj);
1100 return obj->delay;
1101}
1102
1103/**
1104 * \brief Get number of frames available from a PCM status container (see #snd_pcm_avail_update)
1105 * \return Number of frames ready to be read/written
1106 */
1107snd_pcm_uframes_t snd_pcm_status_get_avail(const snd_pcm_status_t *obj)
1108{
1109 assert(obj);
1110 return obj->avail;
1111}
1112
1113/**
1114 * \brief Get maximum number of frames available from a PCM status container after last #snd_pcm_status call
1115 * \return Maximum number of frames ready to be read/written
1116 */
1117snd_pcm_uframes_t snd_pcm_status_get_avail_max(const snd_pcm_status_t *obj)
1118{
1119 assert(obj);
1120 return obj->avail_max;
1121}
1122
1123/**
1124 * \brief Get count of ADC overrange detections since last call
1125 * \return Count of ADC overrange detections
1126 */
1127snd_pcm_uframes_t snd_pcm_status_get_overrange(const snd_pcm_status_t *obj)
1128{
1129 assert(obj);
1130 return obj->overrange;
1131}
1132
1133/**
1134 * \brief Restrict a configuration space to have periods count nearest to a target
1135 * \param pcm PCM handle
1136 * \param params Configuration space
1137 * \param val approximate target periods per buffer / returned chosen approximate target periods per buffer
1138 * \return 0 otherwise a negative error code if configuration space is empty
1139 *
1140 * target/chosen exact value is <,=,> val following dir (-1,0,1)
1141 */
1142int snd_pcm_hw_params_set_periods_near(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir)
1143{
1144 return snd_pcm_hw_param_set_near(pcm, params, SND_PCM_HW_PARAM_PERIODS, val, dir);
1145}
1146
1147/**
1148 * \brief Restrict a configuration space to have buffer size nearest to a target
1149 * \param pcm PCM handle
1150 * \param params Configuration space
1151 * \param val approximate target buffer size in frames / returned chosen approximate target buffer size in frames
1152 * \return 0 otherwise a negative error code if configuration space is empty
1153 *
1154 * target/chosen exact value is <,=,> val following dir (-1,0,1)
1155 */
1156int snd_pcm_hw_params_set_buffer_size_near(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val)
1157{
1158 unsigned int _val = *val;
1159 int err = snd_pcm_hw_param_set_near(pcm, params, SND_PCM_HW_PARAM_BUFFER_SIZE, &_val, NULL);
1160 if (err >= 0)
1161 *val = _val;
1162 return err;
1163}
1164
1165/**
1166 * \brief Restrict a configuration space to have period size nearest to a target
1167 * \param pcm PCM handle
1168 * \param params Configuration space
1169 * \param val approximate target period size in frames / returned chosen approximate target period size
1170 * \return 0 otherwise a negative error code if configuration space is empty
1171 *
1172 * target/chosen exact value is <,=,> val following dir (-1,0,1)
1173 */
1174int snd_pcm_hw_params_set_period_size_near(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val, int *dir)
1175{
1176 unsigned int _val = *val;
1177 int err = snd_pcm_hw_param_set_near(pcm, params, SND_PCM_HW_PARAM_PERIOD_SIZE, &_val, dir);
1178 if (err >= 0)
1179 *val = _val;
1180 return err;
1181}
1182
1183/**
1184 * \brief Extract minimum buffer size from a configuration space
1185 * \param params Configuration space
1186 * \param val Returned approximate minimum buffer size in frames
1187 * \param dir Sub unit direction
1188 * \return 0 otherwise a negative error code
1189 *
1190 * Exact value is <,=,> the returned one following dir (-1,0,1)
1191 */
1192int snd_pcm_hw_params_get_buffer_size_min(const snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val)
1193{
1194 unsigned int _val;
1195 int err = snd_pcm_hw_param_get_min(params, SND_PCM_HW_PARAM_BUFFER_SIZE, &_val, NULL);
1196 if (err >= 0)
1197 *val = _val;
1198 return err;
1199}
1200
1201/**
1202 * \brief Extract maximum buffer size from a configuration space
1203 * \param params Configuration space
1204 * \param val Returned approximate maximum buffer size in frames
1205 * \param dir Sub unit direction
1206 * \return 0 otherwise a negative error code
1207 *
1208 * Exact value is <,=,> the returned one following dir (-1,0,1)
1209 */
1210int snd_pcm_hw_params_get_buffer_size_max(const snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val)
1211{
1212 unsigned int _val;
1213 int err = snd_pcm_hw_param_get_max(params, SND_PCM_HW_PARAM_BUFFER_SIZE, &_val, NULL);
1214 if (err >= 0)
1215 *val = _val;
1216 return err;
1217}
1218
1219/**
1220 * \brief Extract minimum period size from a configuration space
1221 * \param params Configuration space
1222 * \param val approximate minimum period size in frames
1223 * \param dir Sub unit direction
1224 * \return 0 otherwise a negative error code
1225 *
1226 * Exact value is <,=,> the returned one following dir (-1,0,1)
1227 */
1228int snd_pcm_hw_params_get_period_size_min(const snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val, int *dir)
1229{
1230 unsigned int _val = *val;
1231 int err = snd_pcm_hw_param_get_min(params, SND_PCM_HW_PARAM_PERIOD_SIZE, &_val, dir);
1232 if (err >= 0)
1233 *val = _val;
1234 return err;
1235}
1236
1237/**
1238 * \brief Extract maximum period size from a configuration space
1239 * \param params Configuration space
1240 * \param val approximate minimum period size in frames
1241 * \param dir Sub unit direction
1242 * \return 0 otherwise a negative error code
1243 *
1244 * Exact value is <,=,> the returned one following dir (-1,0,1)
1245 */
1246int snd_pcm_hw_params_get_period_size_max(const snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val, int *dir)
1247{
1248 unsigned int _val = *val;
1249 int err = snd_pcm_hw_param_get_max(params, SND_PCM_HW_PARAM_PERIOD_SIZE, &_val, dir);
1250 if (err >= 0)
1251 *val = _val;
1252 return err;
1253}
1254
Note: See TracBrowser for help on using the repository browser.