No empty .Rs/.Re
[netbsd-mini2440.git] / sys / dev / auconv.c
blobcaba6ed40dce5b08f3036379060f5d70ad0d41c9
1 /* $NetBSD: auconv.c,v 1.21 2008/03/04 18:23:44 cube Exp $ */
3 /*
4 * Copyright (c) 1996 The NetBSD Foundation, Inc.
5 * All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by the Computer Systems
18 * Engineering Group at Lawrence Berkeley Laboratory.
19 * 4. Neither the name of the University nor of the Laboratory may be used
20 * to endorse or promote products derived from this software without
21 * specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
37 #include <sys/cdefs.h>
38 __KERNEL_RCSID(0, "$NetBSD: auconv.c,v 1.21 2008/03/04 18:23:44 cube Exp $");
40 #include <sys/types.h>
41 #include <sys/audioio.h>
42 #include <sys/device.h>
43 #include <sys/errno.h>
44 #include <sys/malloc.h>
45 #include <sys/null.h>
46 #include <sys/systm.h>
47 #include <dev/audio_if.h>
48 #include <dev/auconv.h>
49 #include <dev/mulaw.h>
50 #include <machine/limits.h>
51 #ifndef _KERNEL
52 #include <stddef.h>
53 #include <stdio.h>
54 #include <stdlib.h>
55 #include <string.h>
56 #include <stdbool.h>
57 #endif
59 #include <aurateconv.h> /* generated by config(8) */
60 #include <mulaw.h> /* generated by config(8) */
62 /* #define AUCONV_DEBUG */
63 #ifdef AUCONV_DEBUG
64 # define DPRINTF(x) printf x
65 #else
66 # define DPRINTF(x)
67 #endif
69 #if NAURATECONV > 0
70 static int auconv_rateconv_supportable(u_int, u_int, u_int);
71 static int auconv_rateconv_check_channels(const struct audio_format *, int,
72 int, const audio_params_t *,
73 stream_filter_list_t *);
74 static int auconv_rateconv_check_rates(const struct audio_format *, int,
75 int, const audio_params_t *,
76 audio_params_t *,
77 stream_filter_list_t *);
78 #endif
79 #ifdef AUCONV_DEBUG
80 static void auconv_dump_formats(const struct audio_format *, int);
81 #endif
82 static void auconv_dump_params(const audio_params_t *);
83 static int auconv_exact_match(const struct audio_format *, int, int,
84 const struct audio_params *);
85 static u_int auconv_normalize_encoding(u_int, u_int);
86 static int auconv_is_supported_rate(const struct audio_format *, u_int);
87 static int auconv_add_encoding(int, int, int, struct audio_encoding_set **,
88 int *);
90 #ifdef _KERNEL
91 #define AUCONV_MALLOC(size) malloc(size, M_DEVBUF, M_NOWAIT)
92 #define AUCONV_REALLOC(p, size) realloc(p, size, M_DEVBUF, M_NOWAIT)
93 #define AUCONV_FREE(p) free(p, M_DEVBUF)
94 #else
95 #define AUCONV_MALLOC(size) malloc(size)
96 #define AUCONV_REALLOC(p, size) realloc(p, size)
97 #define AUCONV_FREE(p) free(p)
98 #endif
100 struct audio_encoding_set {
101 int size;
102 audio_encoding_t items[1];
104 #define ENCODING_SET_SIZE(n) (offsetof(struct audio_encoding_set, items) \
105 + sizeof(audio_encoding_t) * (n))
107 struct conv_table {
108 u_int encoding;
109 u_int validbits;
110 u_int precision;
111 stream_filter_factory_t *play_conv;
112 stream_filter_factory_t *rec_conv;
115 * SLINEAR-16 or SLINEAR-24 should precede in a table because
116 * aurateconv supports only SLINEAR.
118 static const struct conv_table s8_table[] = {
119 {AUDIO_ENCODING_SLINEAR_LE, 16, 16,
120 linear8_to_linear16, linear16_to_linear8},
121 {AUDIO_ENCODING_SLINEAR_BE, 16, 16,
122 linear8_to_linear16, linear16_to_linear8},
123 {AUDIO_ENCODING_ULINEAR_LE, 8, 8,
124 change_sign8, change_sign8},
125 {0, 0, 0, NULL, NULL}};
126 static const struct conv_table u8_table[] = {
127 {AUDIO_ENCODING_SLINEAR_LE, 16, 16,
128 linear8_to_linear16, linear16_to_linear8},
129 {AUDIO_ENCODING_SLINEAR_BE, 16, 16,
130 linear8_to_linear16, linear16_to_linear8},
131 {AUDIO_ENCODING_SLINEAR_LE, 8, 8,
132 change_sign8, change_sign8},
133 {AUDIO_ENCODING_ULINEAR_LE, 16, 16,
134 linear8_to_linear16, linear16_to_linear8},
135 {AUDIO_ENCODING_ULINEAR_BE, 16, 16,
136 linear8_to_linear16, linear16_to_linear8},
137 {0, 0, 0, NULL, NULL}};
138 static const struct conv_table s16le_table[] = {
139 {AUDIO_ENCODING_SLINEAR_BE, 16, 16,
140 swap_bytes, swap_bytes},
141 {AUDIO_ENCODING_ULINEAR_LE, 16, 16,
142 change_sign16, change_sign16},
143 {AUDIO_ENCODING_ULINEAR_BE, 16, 16,
144 swap_bytes_change_sign16, swap_bytes_change_sign16},
145 {0, 0, 0, NULL, NULL}};
146 static const struct conv_table s16be_table[] = {
147 {AUDIO_ENCODING_SLINEAR_LE, 16, 16,
148 swap_bytes, swap_bytes},
149 {AUDIO_ENCODING_ULINEAR_BE, 16, 16,
150 change_sign16, change_sign16},
151 {AUDIO_ENCODING_ULINEAR_LE, 16, 16,
152 swap_bytes_change_sign16, swap_bytes_change_sign16},
153 {0, 0, 0, NULL, NULL}};
154 static const struct conv_table u16le_table[] = {
155 {AUDIO_ENCODING_SLINEAR_LE, 16, 16,
156 change_sign16, change_sign16},
157 {AUDIO_ENCODING_ULINEAR_BE, 16, 16,
158 swap_bytes, swap_bytes},
159 {AUDIO_ENCODING_SLINEAR_BE, 16, 16,
160 swap_bytes_change_sign16, swap_bytes_change_sign16},
161 {0, 0, 0, NULL, NULL}};
162 static const struct conv_table u16be_table[] = {
163 {AUDIO_ENCODING_SLINEAR_BE, 16, 16,
164 change_sign16, change_sign16},
165 {AUDIO_ENCODING_ULINEAR_LE, 16, 16,
166 swap_bytes, swap_bytes},
167 {AUDIO_ENCODING_SLINEAR_LE, 16, 16,
168 swap_bytes_change_sign16, swap_bytes_change_sign16},
169 {0, 0, 0, NULL, NULL}};
170 #if NMULAW > 0
171 static const struct conv_table mulaw_table[] = {
172 {AUDIO_ENCODING_SLINEAR_LE, 16, 16,
173 mulaw_to_linear16, linear16_to_mulaw},
174 {AUDIO_ENCODING_SLINEAR_BE, 16, 16,
175 mulaw_to_linear16, linear16_to_mulaw},
176 {AUDIO_ENCODING_ULINEAR_LE, 16, 16,
177 mulaw_to_linear16, linear16_to_mulaw},
178 {AUDIO_ENCODING_ULINEAR_BE, 16, 16,
179 mulaw_to_linear16, linear16_to_mulaw},
180 {AUDIO_ENCODING_SLINEAR_LE, 8, 8,
181 mulaw_to_linear8, linear8_to_mulaw},
182 {AUDIO_ENCODING_ULINEAR_LE, 8, 8,
183 mulaw_to_linear8, linear8_to_mulaw},
184 {0, 0, 0, NULL, NULL}};
185 static const struct conv_table alaw_table[] = {
186 {AUDIO_ENCODING_SLINEAR_LE, 16, 16,
187 alaw_to_linear16, linear16_to_alaw},
188 {AUDIO_ENCODING_SLINEAR_BE, 16, 16,
189 alaw_to_linear16, linear16_to_alaw},
190 {AUDIO_ENCODING_ULINEAR_LE, 16, 16,
191 alaw_to_linear16, linear16_to_alaw},
192 {AUDIO_ENCODING_ULINEAR_BE, 16, 16,
193 alaw_to_linear16, linear16_to_alaw},
194 {AUDIO_ENCODING_SLINEAR_LE, 8, 8,
195 alaw_to_linear8, linear8_to_alaw},
196 {AUDIO_ENCODING_ULINEAR_LE, 8, 8,
197 alaw_to_linear8, linear8_to_alaw},
198 {0, 0, 0, NULL, NULL}};
199 #endif
200 #ifdef AUCONV_DEBUG
201 static const char *encoding_dbg_names[] = {
202 "none", AudioEmulaw, AudioEalaw, "pcm16",
203 "pcm8", AudioEadpcm, AudioEslinear_le, AudioEslinear_be,
204 AudioEulinear_le, AudioEulinear_be,
205 AudioEslinear, AudioEulinear,
206 AudioEmpeg_l1_stream, AudioEmpeg_l1_packets,
207 AudioEmpeg_l1_system, AudioEmpeg_l2_stream,
208 AudioEmpeg_l2_packets, AudioEmpeg_l2_system
210 #endif
212 void
213 stream_filter_set_fetcher(stream_filter_t *this, stream_fetcher_t *p)
215 this->prev = p;
218 void
219 stream_filter_set_inputbuffer(stream_filter_t *this, audio_stream_t *stream)
221 this->src = stream;
224 stream_filter_t *
225 auconv_nocontext_filter_factory(
226 int (*fetch_to)(stream_fetcher_t *, audio_stream_t *, int))
228 stream_filter_t *this;
230 this = AUCONV_MALLOC(sizeof(stream_filter_t));
231 if (this == NULL)
232 return NULL;
233 this->base.fetch_to = fetch_to;
234 this->dtor = auconv_nocontext_filter_dtor;
235 this->set_fetcher = stream_filter_set_fetcher;
236 this->set_inputbuffer = stream_filter_set_inputbuffer;
237 this->prev = NULL;
238 this->src = NULL;
239 return this;
242 void
243 auconv_nocontext_filter_dtor(struct stream_filter *this)
245 if (this != NULL)
246 AUCONV_FREE(this);
249 #define DEFINE_FILTER(name) \
250 static int \
251 name##_fetch_to(stream_fetcher_t *, audio_stream_t *, int); \
252 stream_filter_t * \
253 name(struct audio_softc *sc, const audio_params_t *from, \
254 const audio_params_t *to) \
256 return auconv_nocontext_filter_factory(name##_fetch_to); \
258 static int \
259 name##_fetch_to(stream_fetcher_t *self, audio_stream_t *dst, int max_used)
261 DEFINE_FILTER(change_sign8)
263 stream_filter_t *this;
264 int m, err;
266 this = (stream_filter_t *)self;
267 if ((err = this->prev->fetch_to(this->prev, this->src, max_used)))
268 return err;
269 m = dst->end - dst->start;
270 m = min(m, max_used);
271 FILTER_LOOP_PROLOGUE(this->src, 1, dst, 1, m) {
272 *d = *s ^ 0x80;
273 } FILTER_LOOP_EPILOGUE(this->src, dst);
274 return 0;
277 DEFINE_FILTER(change_sign16)
279 stream_filter_t *this;
280 int m, err, enc;
282 this = (stream_filter_t *)self;
283 max_used = (max_used + 1) & ~1; /* round up to even */
284 if ((err = this->prev->fetch_to(this->prev, this->src, max_used)))
285 return err;
286 m = (dst->end - dst->start) & ~1;
287 m = min(m, max_used);
288 enc = dst->param.encoding;
289 if (enc == AUDIO_ENCODING_SLINEAR_LE
290 || enc == AUDIO_ENCODING_ULINEAR_LE) {
291 FILTER_LOOP_PROLOGUE(this->src, 2, dst, 2, m) {
292 d[0] = s[0];
293 d[1] = s[1] ^ 0x80;
294 } FILTER_LOOP_EPILOGUE(this->src, dst);
295 } else {
296 FILTER_LOOP_PROLOGUE(this->src, 2, dst, 2, m) {
297 d[0] = s[0] ^ 0x80;
298 d[1] = s[1];
299 } FILTER_LOOP_EPILOGUE(this->src, dst);
301 return 0;
304 DEFINE_FILTER(swap_bytes)
306 stream_filter_t *this;
307 int m, err;
309 this = (stream_filter_t *)self;
310 max_used = (max_used + 1) & ~1; /* round up to even */
311 if ((err = this->prev->fetch_to(this->prev, this->src, max_used)))
312 return err;
313 m = (dst->end - dst->start) & ~1;
314 m = min(m, max_used);
315 FILTER_LOOP_PROLOGUE(this->src, 2, dst, 2, m) {
316 d[0] = s[1];
317 d[1] = s[0];
318 } FILTER_LOOP_EPILOGUE(this->src, dst);
319 return 0;
322 DEFINE_FILTER(swap_bytes_change_sign16)
324 stream_filter_t *this;
325 int m, err, enc;
327 this = (stream_filter_t *)self;
328 max_used = (max_used + 1) & ~1; /* round up to even */
329 if ((err = this->prev->fetch_to(this->prev, this->src, max_used)))
330 return err;
331 m = (dst->end - dst->start) & ~1;
332 m = min(m, max_used);
333 enc = dst->param.encoding;
334 if (enc == AUDIO_ENCODING_SLINEAR_LE
335 || enc == AUDIO_ENCODING_ULINEAR_LE) {
336 FILTER_LOOP_PROLOGUE(this->src, 2, dst, 2, m) {
337 d[0] = s[1];
338 d[1] = s[0] ^ 0x80;
339 } FILTER_LOOP_EPILOGUE(this->src, dst);
340 } else {
341 FILTER_LOOP_PROLOGUE(this->src, 2, dst, 2, m) {
342 d[0] = s[1] ^ 0x80;
343 d[1] = s[0];
344 } FILTER_LOOP_EPILOGUE(this->src, dst);
346 return 0;
349 DEFINE_FILTER(linear8_to_linear16)
351 stream_filter_t *this;
352 int m, err, enc_dst, enc_src;
354 this = (stream_filter_t *)self;
355 max_used = (max_used + 1) & ~1; /* round up to even */
356 if ((err = this->prev->fetch_to(this->prev, this->src, max_used / 2)))
357 return err;
358 m = (dst->end - dst->start) & ~1;
359 m = min(m, max_used);
360 enc_dst = dst->param.encoding;
361 enc_src = this->src->param.encoding;
362 if ((enc_src == AUDIO_ENCODING_SLINEAR_LE
363 && enc_dst == AUDIO_ENCODING_SLINEAR_LE)
364 || (enc_src == AUDIO_ENCODING_ULINEAR_LE
365 && enc_dst == AUDIO_ENCODING_ULINEAR_LE)) {
367 * slinear8 -> slinear16_le
368 * ulinear8 -> ulinear16_le
370 FILTER_LOOP_PROLOGUE(this->src, 1, dst, 2, m) {
371 d[0] = 0;
372 d[1] = s[0];
373 } FILTER_LOOP_EPILOGUE(this->src, dst);
374 } else if ((enc_src == AUDIO_ENCODING_SLINEAR_LE
375 && enc_dst == AUDIO_ENCODING_SLINEAR_BE)
376 || (enc_src == AUDIO_ENCODING_ULINEAR_LE
377 && enc_dst == AUDIO_ENCODING_ULINEAR_BE)) {
379 * slinear8 -> slinear16_be
380 * ulinear8 -> ulinear16_be
382 FILTER_LOOP_PROLOGUE(this->src, 1, dst, 2, m) {
383 d[0] = s[0];
384 d[1] = 0;
385 } FILTER_LOOP_EPILOGUE(this->src, dst);
386 } else if ((enc_src == AUDIO_ENCODING_SLINEAR_LE
387 && enc_dst == AUDIO_ENCODING_ULINEAR_LE)
388 || (enc_src == AUDIO_ENCODING_ULINEAR_LE
389 && enc_dst == AUDIO_ENCODING_SLINEAR_LE)) {
391 * slinear8 -> ulinear16_le
392 * ulinear8 -> slinear16_le
394 FILTER_LOOP_PROLOGUE(this->src, 1, dst, 2, m) {
395 d[0] = 0;
396 d[1] = s[0] ^ 0x80;
397 } FILTER_LOOP_EPILOGUE(this->src, dst);
398 } else {
400 * slinear8 -> ulinear16_be
401 * ulinear8 -> slinear16_be
403 FILTER_LOOP_PROLOGUE(this->src, 1, dst, 2, m) {
404 d[0] = s[0] ^ 0x80;
405 d[1] = 0;
406 } FILTER_LOOP_EPILOGUE(this->src, dst);
408 return 0;
411 DEFINE_FILTER(linear16_to_linear8)
413 stream_filter_t *this;
414 int m, err, enc_src, enc_dst;
416 this = (stream_filter_t *)self;
417 if ((err = this->prev->fetch_to(this->prev, this->src, max_used * 2)))
418 return err;
419 m = dst->end - dst->start;
420 m = min(m, max_used);
421 enc_dst = dst->param.encoding;
422 enc_src = this->src->param.encoding;
423 if ((enc_src == AUDIO_ENCODING_SLINEAR_LE
424 && enc_dst == AUDIO_ENCODING_SLINEAR_LE)
425 || (enc_src == AUDIO_ENCODING_ULINEAR_LE
426 && enc_dst == AUDIO_ENCODING_ULINEAR_LE)) {
428 * slinear16_le -> slinear8
429 * ulinear16_le -> ulinear8
431 FILTER_LOOP_PROLOGUE(this->src, 2, dst, 1, m) {
432 d[0] = s[1];
433 } FILTER_LOOP_EPILOGUE(this->src, dst);
434 } else if ((enc_src == AUDIO_ENCODING_SLINEAR_LE
435 && enc_dst == AUDIO_ENCODING_ULINEAR_LE)
436 || (enc_src == AUDIO_ENCODING_ULINEAR_LE
437 && enc_dst == AUDIO_ENCODING_SLINEAR_LE)) {
439 * slinear16_le -> ulinear8
440 * ulinear16_le -> slinear8
442 FILTER_LOOP_PROLOGUE(this->src, 2, dst, 1, m) {
443 d[0] = s[1] ^ 0x80;
444 } FILTER_LOOP_EPILOGUE(this->src, dst);
445 } else if ((enc_src == AUDIO_ENCODING_SLINEAR_BE
446 && enc_dst == AUDIO_ENCODING_SLINEAR_LE)
447 || (enc_src == AUDIO_ENCODING_ULINEAR_BE
448 && enc_dst == AUDIO_ENCODING_ULINEAR_LE)) {
450 * slinear16_be -> slinear8
451 * ulinear16_be -> ulinear8
453 FILTER_LOOP_PROLOGUE(this->src, 2, dst, 1, m) {
454 d[0] = s[0];
455 } FILTER_LOOP_EPILOGUE(this->src, dst);
456 } else {
458 * slinear16_be -> ulinear8
459 * ulinear16_be -> slinear8
461 FILTER_LOOP_PROLOGUE(this->src, 2, dst, 1, m) {
462 d[0] = s[0] ^ 0x80;
463 } FILTER_LOOP_EPILOGUE(this->src, dst);
465 return 0;
469 * Set appropriate parameters in `param,' and return the index in
470 * the hardware capability array `formats.'
472 * @param formats [IN] An array of formats which a hardware can support.
473 * @param nformats [IN] The number of elements of the array.
474 * @param mode [IN] Either AUMODE_PLAY or AUMODE_RECORD.
475 * @param param [IN] Requested format. param->sw_code may be set.
476 * @param rateconv [IN] true if aurateconv may be used.
477 * @param list [OUT] stream_filters required for param.
478 * @return The index of selected audio_format entry. -1 if the device
479 * can not support the specified param.
482 auconv_set_converter(const struct audio_format *formats, int nformats,
483 int mode, const audio_params_t *param, int rateconv,
484 stream_filter_list_t *list)
486 audio_params_t work;
487 const struct conv_table *table;
488 stream_filter_factory_t *conv;
489 int enc;
490 int i, j;
492 #ifdef AUCONV_DEBUG
493 DPRINTF(("%s: ENTER rateconv=%d\n", __func__, rateconv));
494 auconv_dump_formats(formats, nformats);
495 #endif
496 enc = auconv_normalize_encoding(param->encoding, param->precision);
498 /* check support by native format */
499 i = auconv_exact_match(formats, nformats, mode, param);
500 if (i >= 0) {
501 DPRINTF(("%s: LEAVE with %d (exact)\n", __func__, i));
502 return i;
505 #if NAURATECONV > 0
506 /* native format with aurateconv */
507 DPRINTF(("%s: native with aurateconv\n", __func__));
508 if (rateconv
509 && auconv_rateconv_supportable(enc, param->precision,
510 param->validbits)) {
511 i = auconv_rateconv_check_channels(formats, nformats,
512 mode, param, list);
513 if (i >= 0) {
514 DPRINTF(("%s: LEAVE with %d (aurateconv1)\n", __func__, i));
515 return i;
518 #endif
520 /* check for emulation */
521 DPRINTF(("%s: encoding emulation\n", __func__));
522 table = NULL;
523 switch (enc) {
524 case AUDIO_ENCODING_SLINEAR_LE:
525 if (param->precision == 8)
526 table = s8_table;
527 else if (param->precision == 16)
528 table = s16le_table;
529 break;
530 case AUDIO_ENCODING_SLINEAR_BE:
531 if (param->precision == 8)
532 table = s8_table;
533 else if (param->precision == 16)
534 table = s16be_table;
535 break;
536 case AUDIO_ENCODING_ULINEAR_LE:
537 if (param->precision == 8)
538 table = u8_table;
539 else if (param->precision == 16)
540 table = u16le_table;
541 break;
542 case AUDIO_ENCODING_ULINEAR_BE:
543 if (param->precision == 8)
544 table = u8_table;
545 else if (param->precision == 16)
546 table = u16be_table;
547 break;
548 #if NMULAW > 0
549 case AUDIO_ENCODING_ULAW:
550 table = mulaw_table;
551 break;
552 case AUDIO_ENCODING_ALAW:
553 table = alaw_table;
554 break;
555 #endif
557 if (table == NULL) {
558 DPRINTF(("%s: LEAVE with -1 (no-emultable)\n", __func__));
559 return -1;
561 work = *param;
562 for (j = 0; table[j].precision != 0; j++) {
563 work.encoding = table[j].encoding;
564 work.precision = table[j].precision;
565 work.validbits = table[j].validbits;
566 i = auconv_exact_match(formats, nformats, mode, &work);
567 if (i >= 0) {
568 conv = mode == AUMODE_PLAY
569 ? table[j].play_conv : table[j].rec_conv;
570 list->append(list, conv, &work);
571 DPRINTF(("%s: LEAVE with %d (emultable)\n", __func__, i));
572 return i;
575 /* not found */
577 #if NAURATECONV > 0
578 /* emulation with aurateconv */
579 DPRINTF(("%s: encoding emulation with aurateconv\n", __func__));
580 if (!rateconv) {
581 DPRINTF(("%s: LEAVE with -1 (no-rateconv)\n", __func__));
582 return -1;
584 work = *param;
585 for (j = 0; table[j].precision != 0; j++) {
586 if (!auconv_rateconv_supportable(table[j].encoding,
587 table[j].precision,
588 table[j].validbits))
589 continue;
590 work.encoding = table[j].encoding;
591 work.precision = table[j].precision;
592 work.validbits = table[j].validbits;
593 i = auconv_rateconv_check_channels(formats, nformats,
594 mode, &work, list);
595 if (i >= 0) {
596 /* work<=>hw conversion is already registered */
597 conv = mode == AUMODE_PLAY
598 ? table[j].play_conv : table[j].rec_conv;
599 /* register userland<=>work conversion */
600 list->append(list, conv, &work);
601 DPRINTF(("%s: LEAVE with %d (rateconv2)\n", __func__, i));
602 return i;
606 #endif
607 DPRINTF(("%s: LEAVE with -1 (bottom)\n", __func__));
608 return -1;
611 #if NAURATECONV > 0
612 static int
613 auconv_rateconv_supportable(u_int encoding, u_int precision, u_int validbits)
615 if (encoding != AUDIO_ENCODING_SLINEAR_LE
616 && encoding != AUDIO_ENCODING_SLINEAR_BE)
617 return false;
618 if (precision != 16 && precision != 24 && precision != 32)
619 return false;
620 if (precision < validbits)
621 return false;
622 return true;
625 static int
626 auconv_rateconv_check_channels(const struct audio_format *formats, int nformats,
627 int mode, const audio_params_t *param,
628 stream_filter_list_t *list)
630 audio_params_t hw_param;
631 int ind, n;
633 hw_param = *param;
634 /* check for the specified number of channels */
635 ind = auconv_rateconv_check_rates(formats, nformats, mode, param,
636 &hw_param, list);
637 if (ind >= 0)
638 return ind;
640 /* check for larger numbers */
641 for (n = param->channels + 1; n <= AUDIO_MAX_CHANNELS; n++) {
642 hw_param.channels = n;
643 ind = auconv_rateconv_check_rates(formats, nformats, mode,
644 param, &hw_param, list);
645 if (ind >= 0)
646 return ind;
649 /* check for stereo:monaural conversion */
650 if (param->channels == 2) {
651 hw_param.channels = 1;
652 ind = auconv_rateconv_check_rates(formats, nformats, mode,
653 param, &hw_param, list);
654 if (ind >= 0)
655 return ind;
657 return -1;
660 static int
661 auconv_rateconv_check_rates(const struct audio_format *formats, int nformats,
662 int mode, const audio_params_t *param,
663 audio_params_t *hw_param, stream_filter_list_t *list)
665 int ind, i, j, enc, f_enc;
666 u_int rate, minrate, maxrate, orig_rate;
668 /* exact match */
669 ind = auconv_exact_match(formats, nformats, mode, hw_param);
670 if (ind >= 0)
671 goto found;
673 /* determine min/max of specified encoding/precision/channels */
674 minrate = UINT_MAX;
675 maxrate = 0;
676 enc = auconv_normalize_encoding(param->encoding,
677 param->precision);
678 for (i = 0; i < nformats; i++) {
679 if (!AUFMT_IS_VALID(&formats[i]))
680 continue;
681 if ((formats[i].mode & mode) == 0)
682 continue;
683 f_enc = auconv_normalize_encoding(formats[i].encoding,
684 formats[i].precision);
685 if (f_enc != enc)
686 continue;
687 if (formats[i].validbits != hw_param->validbits)
688 continue;
689 if (formats[i].precision != hw_param->precision)
690 continue;
691 if (formats[i].channels != hw_param->channels)
692 continue;
693 if (formats[i].frequency_type == 0) {
694 if (formats[i].frequency[0] < minrate)
695 minrate = formats[i].frequency[0];
696 if (formats[i].frequency[1] > maxrate)
697 maxrate = formats[i].frequency[1];
698 } else {
699 for (j = 0; j < formats[i].frequency_type; j++) {
700 if (formats[i].frequency[j] < minrate)
701 minrate = formats[i].frequency[j];
702 if (formats[i].frequency[j] > maxrate)
703 maxrate = formats[i].frequency[j];
707 if (maxrate == 0)
708 return -1;
710 /* try multiples of sample_rate */
711 orig_rate = hw_param->sample_rate;
712 for (i = 2; (rate = param->sample_rate * i) <= maxrate; i++) {
713 hw_param->sample_rate = rate;
714 ind = auconv_exact_match(formats, nformats, mode, hw_param);
715 if (ind >= 0)
716 goto found;
719 hw_param->sample_rate = param->sample_rate >= minrate
720 ? maxrate : minrate;
721 ind = auconv_exact_match(formats, nformats, mode, hw_param);
722 if (ind >= 0)
723 goto found;
724 hw_param->sample_rate = orig_rate;
725 return -1;
727 found:
728 list->append(list, aurateconv, hw_param);
729 return ind;
731 #endif /* NAURATECONV */
733 #ifdef AUCONV_DEBUG
734 static void
735 auconv_dump_formats(const struct audio_format *formats, int nformats)
737 const struct audio_format *f;
738 int i, j;
740 for (i = 0; i < nformats; i++) {
741 f = &formats[i];
742 printf("[%2d]: mode=", i);
743 if (!AUFMT_IS_VALID(f)) {
744 printf("INVALID");
745 } else if (f->mode == AUMODE_PLAY) {
746 printf("PLAY");
747 } else if (f->mode == AUMODE_RECORD) {
748 printf("RECORD");
749 } else if (f->mode == (AUMODE_PLAY | AUMODE_RECORD)) {
750 printf("PLAY|RECORD");
751 } else {
752 printf("0x%x", f->mode);
754 printf(" enc=%s", encoding_dbg_names[f->encoding]);
755 printf(" %u/%ubit", f->validbits, f->precision);
756 printf(" %uch", f->channels);
758 printf(" channel_mask=");
759 if (f->channel_mask == AUFMT_MONAURAL) {
760 printf("MONAURAL");
761 } else if (f->channel_mask == AUFMT_STEREO) {
762 printf("STEREO");
763 } else if (f->channel_mask == AUFMT_SURROUND4) {
764 printf("SURROUND4");
765 } else if (f->channel_mask == AUFMT_DOLBY_5_1) {
766 printf("DOLBY5.1");
767 } else {
768 printf("0x%x", f->channel_mask);
771 if (f->frequency_type == 0) {
772 printf(" %uHz-%uHz", f->frequency[0],
773 f->frequency[1]);
774 } else {
775 printf(" %uHz", f->frequency[0]);
776 for (j = 1; j < f->frequency_type; j++)
777 printf(",%uHz", f->frequency[j]);
779 printf("\n");
783 static void
784 auconv_dump_params(const audio_params_t *p)
786 printf("enc=%s", encoding_dbg_names[p->encoding]);
787 printf(" %u/%ubit", p->validbits, p->precision);
788 printf(" %uch", p->channels);
789 printf(" %uHz", p->sample_rate);
790 printf("\n");
792 #else
793 static void
794 auconv_dump_params(const audio_params_t *p)
797 #endif /* AUCONV_DEBUG */
800 * a sub-routine for auconv_set_converter()
802 static int
803 auconv_exact_match(const struct audio_format *formats, int nformats,
804 int mode, const audio_params_t *param)
806 int i, enc, f_enc;
808 DPRINTF(("%s: ENTER: mode=0x%x target:", __func__, mode));
809 auconv_dump_params(param);
810 enc = auconv_normalize_encoding(param->encoding,
811 param->precision);
812 DPRINTF(("%s: target normalized: %s\n", __func__,
813 encoding_dbg_names[enc]));
814 for (i = 0; i < nformats; i++) {
815 if (!AUFMT_IS_VALID(&formats[i]))
816 continue;
817 if ((formats[i].mode & mode) == 0)
818 continue;
819 f_enc = auconv_normalize_encoding(formats[i].encoding,
820 formats[i].precision);
821 DPRINTF(("%s: format[%d] normalized: %s\n",
822 __func__, i, encoding_dbg_names[f_enc]));
823 if (f_enc != enc)
824 continue;
826 * XXX we need encoding-dependent check.
827 * XXX Is to check precision/channels meaningful for
828 * MPEG encodings?
830 if (formats[i].validbits != param->validbits)
831 continue;
832 if (formats[i].precision != param->precision)
833 continue;
834 if (formats[i].channels != param->channels)
835 continue;
836 if (!auconv_is_supported_rate(&formats[i],
837 param->sample_rate))
838 continue;
839 return i;
841 return -1;
845 * a sub-routine for auconv_set_converter()
846 * SLINEAR ==> SLINEAR_<host-endian>
847 * ULINEAR ==> ULINEAR_<host-endian>
848 * SLINEAR_BE 8bit ==> SLINEAR_LE 8bit
849 * ULINEAR_BE 8bit ==> ULINEAR_LE 8bit
850 * This should be the same rule as audio_check_params()
852 static u_int
853 auconv_normalize_encoding(u_int encoding, u_int precision)
855 int enc;
857 enc = encoding;
858 if (enc == AUDIO_ENCODING_SLINEAR_LE)
859 return enc;
860 if (enc == AUDIO_ENCODING_ULINEAR_LE)
861 return enc;
862 #if BYTE_ORDER == LITTLE_ENDIAN
863 if (enc == AUDIO_ENCODING_SLINEAR)
864 return AUDIO_ENCODING_SLINEAR_LE;
865 else if (enc == AUDIO_ENCODING_ULINEAR)
866 return AUDIO_ENCODING_ULINEAR_LE;
867 #else
868 if (enc == AUDIO_ENCODING_SLINEAR)
869 enc = AUDIO_ENCODING_SLINEAR_BE;
870 else if (enc == AUDIO_ENCODING_ULINEAR)
871 enc = AUDIO_ENCODING_ULINEAR_BE;
872 #endif
873 if (precision == 8 && enc == AUDIO_ENCODING_SLINEAR_BE)
874 return AUDIO_ENCODING_SLINEAR_LE;
875 if (precision == 8 && enc == AUDIO_ENCODING_ULINEAR_BE)
876 return AUDIO_ENCODING_ULINEAR_LE;
877 return enc;
881 * a sub-routine for auconv_set_converter()
883 static int
884 auconv_is_supported_rate(const struct audio_format *format, u_int rate)
886 u_int i;
888 if (format->frequency_type == 0) {
889 return format->frequency[0] <= rate
890 && rate <= format->frequency[1];
892 for (i = 0; i < format->frequency_type; i++) {
893 if (format->frequency[i] == rate)
894 return true;
896 return false;
900 * Create an audio_encoding_set besed on hardware capability represented
901 * by audio_format.
903 * Usage:
904 * foo_attach(...) {
906 * if (auconv_create_encodings(formats, nformats,
907 * &sc->sc_encodings) != 0) {
908 * // attach failure
911 * @param formats [IN] An array of formats which a hardware can support.
912 * @param nformats [IN] The number of elements of the array.
913 * @param encodings [OUT] receives an address of an audio_encoding_set.
914 * @return errno; 0 for success.
917 auconv_create_encodings(const struct audio_format *formats, int nformats,
918 struct audio_encoding_set **encodings)
920 struct audio_encoding_set *buf;
921 int capacity;
922 int i;
923 int err;
925 #define ADD_ENCODING(enc, prec, flags) do { \
926 err = auconv_add_encoding(enc, prec, flags, &buf, &capacity); \
927 if (err != 0) goto err_exit; \
928 } while (/*CONSTCOND*/0)
930 capacity = 10;
931 buf = AUCONV_MALLOC(ENCODING_SET_SIZE(capacity));
932 if (buf == NULL) {
933 err = ENOMEM;
934 goto err_exit;
936 buf->size = 0;
937 for (i = 0; i < nformats; i++) {
938 if (!AUFMT_IS_VALID(&formats[i]))
939 continue;
940 switch (formats[i].encoding) {
941 case AUDIO_ENCODING_SLINEAR_LE:
942 ADD_ENCODING(formats[i].encoding,
943 formats[i].precision, 0);
944 ADD_ENCODING(AUDIO_ENCODING_SLINEAR_BE,
945 formats[i].precision,
946 AUDIO_ENCODINGFLAG_EMULATED);
947 ADD_ENCODING(AUDIO_ENCODING_ULINEAR_LE,
948 formats[i].precision,
949 AUDIO_ENCODINGFLAG_EMULATED);
950 ADD_ENCODING(AUDIO_ENCODING_ULINEAR_BE,
951 formats[i].precision,
952 AUDIO_ENCODINGFLAG_EMULATED);
953 #if NMULAW > 0
954 if (formats[i].precision == 8
955 || formats[i].precision == 16) {
956 ADD_ENCODING(AUDIO_ENCODING_ULAW, 8,
957 AUDIO_ENCODINGFLAG_EMULATED);
958 ADD_ENCODING(AUDIO_ENCODING_ALAW, 8,
959 AUDIO_ENCODINGFLAG_EMULATED);
961 #endif
962 break;
963 case AUDIO_ENCODING_SLINEAR_BE:
964 ADD_ENCODING(formats[i].encoding,
965 formats[i].precision, 0);
966 ADD_ENCODING(AUDIO_ENCODING_SLINEAR_LE,
967 formats[i].precision,
968 AUDIO_ENCODINGFLAG_EMULATED);
969 ADD_ENCODING(AUDIO_ENCODING_ULINEAR_LE,
970 formats[i].precision,
971 AUDIO_ENCODINGFLAG_EMULATED);
972 ADD_ENCODING(AUDIO_ENCODING_ULINEAR_BE,
973 formats[i].precision,
974 AUDIO_ENCODINGFLAG_EMULATED);
975 #if NMULAW > 0
976 if (formats[i].precision == 8
977 || formats[i].precision == 16) {
978 ADD_ENCODING(AUDIO_ENCODING_ULAW, 8,
979 AUDIO_ENCODINGFLAG_EMULATED);
980 ADD_ENCODING(AUDIO_ENCODING_ALAW, 8,
981 AUDIO_ENCODINGFLAG_EMULATED);
983 #endif
984 break;
985 case AUDIO_ENCODING_ULINEAR_LE:
986 ADD_ENCODING(formats[i].encoding,
987 formats[i].precision, 0);
988 ADD_ENCODING(AUDIO_ENCODING_SLINEAR_BE,
989 formats[i].precision,
990 AUDIO_ENCODINGFLAG_EMULATED);
991 ADD_ENCODING(AUDIO_ENCODING_SLINEAR_LE,
992 formats[i].precision,
993 AUDIO_ENCODINGFLAG_EMULATED);
994 ADD_ENCODING(AUDIO_ENCODING_ULINEAR_BE,
995 formats[i].precision,
996 AUDIO_ENCODINGFLAG_EMULATED);
997 #if NMULAW > 0
998 if (formats[i].precision == 8
999 || formats[i].precision == 16) {
1000 ADD_ENCODING(AUDIO_ENCODING_ULAW, 8,
1001 AUDIO_ENCODINGFLAG_EMULATED);
1002 ADD_ENCODING(AUDIO_ENCODING_ALAW, 8,
1003 AUDIO_ENCODINGFLAG_EMULATED);
1005 #endif
1006 break;
1007 case AUDIO_ENCODING_ULINEAR_BE:
1008 ADD_ENCODING(formats[i].encoding,
1009 formats[i].precision, 0);
1010 ADD_ENCODING(AUDIO_ENCODING_SLINEAR_BE,
1011 formats[i].precision,
1012 AUDIO_ENCODINGFLAG_EMULATED);
1013 ADD_ENCODING(AUDIO_ENCODING_ULINEAR_LE,
1014 formats[i].precision,
1015 AUDIO_ENCODINGFLAG_EMULATED);
1016 ADD_ENCODING(AUDIO_ENCODING_SLINEAR_LE,
1017 formats[i].precision,
1018 AUDIO_ENCODINGFLAG_EMULATED);
1019 #if NMULAW > 0
1020 if (formats[i].precision == 8
1021 || formats[i].precision == 16) {
1022 ADD_ENCODING(AUDIO_ENCODING_ULAW, 8,
1023 AUDIO_ENCODINGFLAG_EMULATED);
1024 ADD_ENCODING(AUDIO_ENCODING_ALAW, 8,
1025 AUDIO_ENCODINGFLAG_EMULATED);
1027 #endif
1028 break;
1030 case AUDIO_ENCODING_ULAW:
1031 case AUDIO_ENCODING_ALAW:
1032 case AUDIO_ENCODING_ADPCM:
1033 case AUDIO_ENCODING_MPEG_L1_STREAM:
1034 case AUDIO_ENCODING_MPEG_L1_PACKETS:
1035 case AUDIO_ENCODING_MPEG_L1_SYSTEM:
1036 case AUDIO_ENCODING_MPEG_L2_STREAM:
1037 case AUDIO_ENCODING_MPEG_L2_PACKETS:
1038 case AUDIO_ENCODING_MPEG_L2_SYSTEM:
1039 ADD_ENCODING(formats[i].encoding,
1040 formats[i].precision, 0);
1041 break;
1043 case AUDIO_ENCODING_SLINEAR:
1044 case AUDIO_ENCODING_ULINEAR:
1045 case AUDIO_ENCODING_LINEAR:
1046 case AUDIO_ENCODING_LINEAR8:
1047 default:
1048 printf("%s: invalid encoding value "
1049 "for audio_format: %d\n",
1050 __func__, formats[i].encoding);
1051 break;
1054 *encodings = buf;
1055 return 0;
1057 err_exit:
1058 if (buf != NULL)
1059 AUCONV_FREE(buf);
1060 *encodings = NULL;
1061 return err;
1065 * a sub-routine for auconv_create_encodings()
1067 static int
1068 auconv_add_encoding(int enc, int prec, int flags,
1069 struct audio_encoding_set **buf, int *capacity)
1071 static const char *encoding_names[] = {
1072 NULL, AudioEmulaw, AudioEalaw, NULL,
1073 NULL, AudioEadpcm, AudioEslinear_le, AudioEslinear_be,
1074 AudioEulinear_le, AudioEulinear_be,
1075 AudioEslinear, AudioEulinear,
1076 AudioEmpeg_l1_stream, AudioEmpeg_l1_packets,
1077 AudioEmpeg_l1_system, AudioEmpeg_l2_stream,
1078 AudioEmpeg_l2_packets, AudioEmpeg_l2_system
1080 struct audio_encoding_set *set;
1081 struct audio_encoding_set *new_buf;
1082 audio_encoding_t *e;
1083 int i;
1085 set = *buf;
1086 /* already has the same encoding? */
1087 e = set->items;
1088 for (i = 0; i < set->size; i++, e++) {
1089 if (e->encoding == enc && e->precision == prec) {
1090 /* overwrite EMULATED flag */
1091 if ((e->flags & AUDIO_ENCODINGFLAG_EMULATED)
1092 && (flags & AUDIO_ENCODINGFLAG_EMULATED) == 0) {
1093 e->flags &= ~AUDIO_ENCODINGFLAG_EMULATED;
1095 return 0;
1098 /* We don't have the specified one. */
1100 if (set->size >= *capacity) {
1101 new_buf = AUCONV_REALLOC(set,
1102 ENCODING_SET_SIZE(*capacity + 10));
1103 if (new_buf == NULL)
1104 return ENOMEM;
1105 *buf = new_buf;
1106 set = new_buf;
1107 *capacity += 10;
1110 e = &set->items[set->size];
1111 e->index = 0;
1112 strlcpy(e->name, encoding_names[enc], MAX_AUDIO_DEV_LEN);
1113 e->encoding = enc;
1114 e->precision = prec;
1115 e->flags = flags;
1116 set->size += 1;
1117 return 0;
1121 * Delete an audio_encoding_set created by auconv_create_encodings().
1123 * Usage:
1124 * foo_detach(...) {
1126 * auconv_delete_encodings(sc->sc_encodings);
1130 * @param encodings [IN] An audio_encoding_set which was created by
1131 * auconv_create_encodings().
1132 * @return errno; 0 for success.
1134 int auconv_delete_encodings(struct audio_encoding_set *encodings)
1136 if (encodings != NULL)
1137 AUCONV_FREE(encodings);
1138 return 0;
1142 * Copy the element specified by aep->index.
1144 * Usage:
1145 * int foo_query_encoding(void *v, audio_encoding_t *aep) {
1146 * struct foo_softc *sc = (struct foo_softc *)v;
1147 * return auconv_query_encoding(sc->sc_encodings, aep);
1150 * @param encodings [IN] An audio_encoding_set created by
1151 * auconv_create_encodings().
1152 * @param aep [IN/OUT] resultant audio_encoding_t.
1155 auconv_query_encoding(const struct audio_encoding_set *encodings,
1156 audio_encoding_t *aep)
1158 if (aep->index >= encodings->size)
1159 return EINVAL;
1160 strlcpy(aep->name, encodings->items[aep->index].name,
1161 MAX_AUDIO_DEV_LEN);
1162 aep->encoding = encodings->items[aep->index].encoding;
1163 aep->precision = encodings->items[aep->index].precision;
1164 aep->flags = encodings->items[aep->index].flags;
1165 return 0;