1/* $NetBSD: auconv.c,v 1.25 2011/11/23 23:07:31 jmcneill Exp $ */
2
3/*
4 * Copyright (c) 1996 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
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.
22 *
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.
34 *
35 */
36
37#include <sys/cdefs.h>
38__KERNEL_RCSID(0, "$NetBSD: auconv.c,v 1.25 2011/11/23 23:07:31 jmcneill Exp $");
39
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
58
59#include <aurateconv.h> /* generated by config(8) */
60#include <mulaw.h> /* generated by config(8) */
61
62/* #define AUCONV_DEBUG */
63#ifdef AUCONV_DEBUG
64# define DPRINTF(x) printf x
65#else
66# define DPRINTF(x)
67#endif
68
69#if NAURATECONV > 0
70static int auconv_rateconv_supportable(u_int, u_int, u_int);
71static int auconv_rateconv_check_channels(const struct audio_format *, int,
72 int, const audio_params_t *,
73 stream_filter_list_t *);
74static 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
80static void auconv_dump_formats(const struct audio_format *, int);
81#endif
82static void auconv_dump_params(const audio_params_t *);
83static int auconv_exact_match(const struct audio_format *, int, int,
84 const struct audio_params *);
85static u_int auconv_normalize_encoding(u_int, u_int);
86static int auconv_is_supported_rate(const struct audio_format *, u_int);
87static int auconv_add_encoding(int, int, int, struct audio_encoding_set **,
88 int *);
89
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
99
100struct audio_encoding_set {
101 int size;
102 audio_encoding_t items[1];
103};
104#define ENCODING_SET_SIZE(n) (offsetof(struct audio_encoding_set, items) \
105 + sizeof(audio_encoding_t) * (n))
106
107struct 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;
113};
114/*
115 * SLINEAR-16 or SLINEAR-24 should precede in a table because
116 * aurateconv supports only SLINEAR.
117 */
118static 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}};
126static 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}};
138static 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}};
146static 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}};
154static 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}};
162static 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
171static 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}};
185static 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
201static 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,
209 AudioEac3
210};
211#endif
212
213void
214stream_filter_set_fetcher(stream_filter_t *this, stream_fetcher_t *p)
215{
216 this->prev = p;
217}
218
219void
220stream_filter_set_inputbuffer(stream_filter_t *this, audio_stream_t *stream)
221{
222 this->src = stream;
223}
224
225stream_filter_t *
226auconv_nocontext_filter_factory(
227 int (*fetch_to)(struct audio_softc *, stream_fetcher_t *,
228 audio_stream_t *, int))
229{
230 stream_filter_t *this;
231
232 this = AUCONV_MALLOC(sizeof(stream_filter_t));
233 if (this == NULL)
234 return NULL;
235 this->base.fetch_to = fetch_to;
236 this->dtor = auconv_nocontext_filter_dtor;
237 this->set_fetcher = stream_filter_set_fetcher;
238 this->set_inputbuffer = stream_filter_set_inputbuffer;
239 this->prev = NULL;
240 this->src = NULL;
241 return this;
242}
243
244void
245auconv_nocontext_filter_dtor(struct stream_filter *this)
246{
247 if (this != NULL)
248 AUCONV_FREE(this);
249}
250
251#define DEFINE_FILTER(name) \
252static int \
253name##_fetch_to(struct audio_softc *, stream_fetcher_t *, audio_stream_t *, int); \
254stream_filter_t * \
255name(struct audio_softc *sc, const audio_params_t *from, \
256 const audio_params_t *to) \
257{ \
258 return auconv_nocontext_filter_factory(name##_fetch_to); \
259} \
260static int \
261name##_fetch_to(struct audio_softc *sc, stream_fetcher_t *self, \
262 audio_stream_t *dst, int max_used)
263
264DEFINE_FILTER(change_sign8)
265{
266 stream_filter_t *this;
267 int m, err;
268
269 this = (stream_filter_t *)self;
270 if ((err = this->prev->fetch_to(sc, this->prev, this->src, max_used)))
271 return err;
272 m = dst->end - dst->start;
273 m = min(m, max_used);
274 FILTER_LOOP_PROLOGUE(this->src, 1, dst, 1, m) {
275 *d = *s ^ 0x80;
276 } FILTER_LOOP_EPILOGUE(this->src, dst);
277 return 0;
278}
279
280DEFINE_FILTER(change_sign16)
281{
282 stream_filter_t *this;
283 int m, err, enc;
284
285 this = (stream_filter_t *)self;
286 max_used = (max_used + 1) & ~1; /* round up to even */
287 if ((err = this->prev->fetch_to(sc, this->prev, this->src, max_used)))
288 return err;
289 m = (dst->end - dst->start) & ~1;
290 m = min(m, max_used);
291 enc = dst->param.encoding;
292 if (enc == AUDIO_ENCODING_SLINEAR_LE
293 || enc == AUDIO_ENCODING_ULINEAR_LE) {
294 FILTER_LOOP_PROLOGUE(this->src, 2, dst, 2, m) {
295 d[0] = s[0];
296 d[1] = s[1] ^ 0x80;
297 } FILTER_LOOP_EPILOGUE(this->src, dst);
298 } else {
299 FILTER_LOOP_PROLOGUE(this->src, 2, dst, 2, m) {
300 d[0] = s[0] ^ 0x80;
301 d[1] = s[1];
302 } FILTER_LOOP_EPILOGUE(this->src, dst);
303 }
304 return 0;
305}
306
307DEFINE_FILTER(swap_bytes)
308{
309 stream_filter_t *this;
310 int m, err;
311
312 this = (stream_filter_t *)self;
313 max_used = (max_used + 1) & ~1; /* round up to even */
314 if ((err = this->prev->fetch_to(sc, this->prev, this->src, max_used)))
315 return err;
316 m = (dst->end - dst->start) & ~1;
317 m = min(m, max_used);
318 FILTER_LOOP_PROLOGUE(this->src, 2, dst, 2, m) {
319 d[0] = s[1];
320 d[1] = s[0];
321 } FILTER_LOOP_EPILOGUE(this->src, dst);
322 return 0;
323}
324
325DEFINE_FILTER(swap_bytes_change_sign16)
326{
327 stream_filter_t *this;
328 int m, err, enc;
329
330 this = (stream_filter_t *)self;
331 max_used = (max_used + 1) & ~1; /* round up to even */
332 if ((err = this->prev->fetch_to(sc, this->prev, this->src, max_used)))
333 return err;
334 m = (dst->end - dst->start) & ~1;
335 m = min(m, max_used);
336 enc = dst->param.encoding;
337 if (enc == AUDIO_ENCODING_SLINEAR_LE
338 || enc == AUDIO_ENCODING_ULINEAR_LE) {
339 FILTER_LOOP_PROLOGUE(this->src, 2, dst, 2, m) {
340 d[0] = s[1];
341 d[1] = s[0] ^ 0x80;
342 } FILTER_LOOP_EPILOGUE(this->src, dst);
343 } else {
344 FILTER_LOOP_PROLOGUE(this->src, 2, dst, 2, m) {
345 d[0] = s[1] ^ 0x80;
346 d[1] = s[0];
347 } FILTER_LOOP_EPILOGUE(this->src, dst);
348 }
349 return 0;
350}
351
352DEFINE_FILTER(linear8_to_linear16)
353{
354 stream_filter_t *this;
355 int m, err, enc_dst, enc_src;
356
357 this = (stream_filter_t *)self;
358 max_used = (max_used + 1) & ~1; /* round up to even */
359 if ((err = this->prev->fetch_to(sc, this->prev, this->src, max_used / 2)))
360 return err;
361 m = (dst->end - dst->start) & ~1;
362 m = min(m, max_used);
363 enc_dst = dst->param.encoding;
364 enc_src = this->src->param.encoding;
365 if ((enc_src == AUDIO_ENCODING_SLINEAR_LE
366 && enc_dst == AUDIO_ENCODING_SLINEAR_LE)
367 || (enc_src == AUDIO_ENCODING_ULINEAR_LE
368 && enc_dst == AUDIO_ENCODING_ULINEAR_LE)) {
369 /*
370 * slinear8 -> slinear16_le
371 * ulinear8 -> ulinear16_le
372 */
373 FILTER_LOOP_PROLOGUE(this->src, 1, dst, 2, m) {
374 d[0] = 0;
375 d[1] = s[0];
376 } FILTER_LOOP_EPILOGUE(this->src, dst);
377 } else if ((enc_src == AUDIO_ENCODING_SLINEAR_LE
378 && enc_dst == AUDIO_ENCODING_SLINEAR_BE)
379 || (enc_src == AUDIO_ENCODING_ULINEAR_LE
380 && enc_dst == AUDIO_ENCODING_ULINEAR_BE)) {
381 /*
382 * slinear8 -> slinear16_be
383 * ulinear8 -> ulinear16_be
384 */
385 FILTER_LOOP_PROLOGUE(this->src, 1, dst, 2, m) {
386 d[0] = s[0];
387 d[1] = 0;
388 } FILTER_LOOP_EPILOGUE(this->src, dst);
389 } else if ((enc_src == AUDIO_ENCODING_SLINEAR_LE
390 && enc_dst == AUDIO_ENCODING_ULINEAR_LE)
391 || (enc_src == AUDIO_ENCODING_ULINEAR_LE
392 && enc_dst == AUDIO_ENCODING_SLINEAR_LE)) {
393 /*
394 * slinear8 -> ulinear16_le
395 * ulinear8 -> slinear16_le
396 */
397 FILTER_LOOP_PROLOGUE(this->src, 1, dst, 2, m) {
398 d[0] = 0;
399 d[1] = s[0] ^ 0x80;
400 } FILTER_LOOP_EPILOGUE(this->src, dst);
401 } else {
402 /*
403 * slinear8 -> ulinear16_be
404 * ulinear8 -> slinear16_be
405 */
406 FILTER_LOOP_PROLOGUE(this->src, 1, dst, 2, m) {
407 d[0] = s[0] ^ 0x80;
408 d[1] = 0;
409 } FILTER_LOOP_EPILOGUE(this->src, dst);
410 }
411 return 0;
412}
413
414DEFINE_FILTER(linear16_to_linear8)
415{
416 stream_filter_t *this;
417 int m, err, enc_src, enc_dst;
418
419 this = (stream_filter_t *)self;
420 if ((err = this->prev->fetch_to(sc, this->prev, this->src, max_used * 2)))
421 return err;
422 m = dst->end - dst->start;
423 m = min(m, max_used);
424 enc_dst = dst->param.encoding;
425 enc_src = this->src->param.encoding;
426 if ((enc_src == AUDIO_ENCODING_SLINEAR_LE
427 && enc_dst == AUDIO_ENCODING_SLINEAR_LE)
428 || (enc_src == AUDIO_ENCODING_ULINEAR_LE
429 && enc_dst == AUDIO_ENCODING_ULINEAR_LE)) {
430 /*
431 * slinear16_le -> slinear8
432 * ulinear16_le -> ulinear8
433 */
434 FILTER_LOOP_PROLOGUE(this->src, 2, dst, 1, m) {
435 d[0] = s[1];
436 } FILTER_LOOP_EPILOGUE(this->src, dst);
437 } else if ((enc_src == AUDIO_ENCODING_SLINEAR_LE
438 && enc_dst == AUDIO_ENCODING_ULINEAR_LE)
439 || (enc_src == AUDIO_ENCODING_ULINEAR_LE
440 && enc_dst == AUDIO_ENCODING_SLINEAR_LE)) {
441 /*
442 * slinear16_le -> ulinear8
443 * ulinear16_le -> slinear8
444 */
445 FILTER_LOOP_PROLOGUE(this->src, 2, dst, 1, m) {
446 d[0] = s[1] ^ 0x80;
447 } FILTER_LOOP_EPILOGUE(this->src, dst);
448 } else if ((enc_src == AUDIO_ENCODING_SLINEAR_BE
449 && enc_dst == AUDIO_ENCODING_SLINEAR_LE)
450 || (enc_src == AUDIO_ENCODING_ULINEAR_BE
451 && enc_dst == AUDIO_ENCODING_ULINEAR_LE)) {
452 /*
453 * slinear16_be -> slinear8
454 * ulinear16_be -> ulinear8
455 */
456 FILTER_LOOP_PROLOGUE(this->src, 2, dst, 1, m) {
457 d[0] = s[0];
458 } FILTER_LOOP_EPILOGUE(this->src, dst);
459 } else {
460 /*
461 * slinear16_be -> ulinear8
462 * ulinear16_be -> slinear8
463 */
464 FILTER_LOOP_PROLOGUE(this->src, 2, dst, 1, m) {
465 d[0] = s[0] ^ 0x80;
466 } FILTER_LOOP_EPILOGUE(this->src, dst);
467 }
468 return 0;
469}
470
471/**
472 * Set appropriate parameters in `param,' and return the index in
473 * the hardware capability array `formats.'
474 *
475 * @param formats [IN] An array of formats which a hardware can support.
476 * @param nformats [IN] The number of elements of the array.
477 * @param mode [IN] Either AUMODE_PLAY or AUMODE_RECORD.
478 * @param param [IN] Requested format. param->sw_code may be set.
479 * @param rateconv [IN] true if aurateconv may be used.
480 * @param list [OUT] stream_filters required for param.
481 * @return The index of selected audio_format entry. -1 if the device
482 * can not support the specified param.
483 */
484int
485auconv_set_converter(const struct audio_format *formats, int nformats,
486 int mode, const audio_params_t *param, int rateconv,
487 stream_filter_list_t *list)
488{
489 audio_params_t work;
490 const struct conv_table *table;
491 stream_filter_factory_t *conv;
492 int enc;
493 int i, j;
494
495#ifdef AUCONV_DEBUG
496 DPRINTF(("%s: ENTER rateconv=%d\n", __func__, rateconv));
497 auconv_dump_formats(formats, nformats);
498#endif
499 enc = auconv_normalize_encoding(param->encoding, param->precision);
500
501 /* check support by native format */
502 i = auconv_exact_match(formats, nformats, mode, param);
503 if (i >= 0) {
504 DPRINTF(("%s: LEAVE with %d (exact)\n", __func__, i));
505 return i;
506 }
507
508#if NAURATECONV > 0
509 /* native format with aurateconv */
510 DPRINTF(("%s: native with aurateconv\n", __func__));
511 if (rateconv
512 && auconv_rateconv_supportable(enc, param->precision,
513 param->validbits)) {
514 i = auconv_rateconv_check_channels(formats, nformats,
515 mode, param, list);
516 if (i >= 0) {
517 DPRINTF(("%s: LEAVE with %d (aurateconv1)\n", __func__, i));
518 return i;
519 }
520 }
521#endif
522
523 /* check for emulation */
524 DPRINTF(("%s: encoding emulation\n", __func__));
525 table = NULL;
526 switch (enc) {
527 case AUDIO_ENCODING_SLINEAR_LE:
528 if (param->precision == 8)
529 table = s8_table;
530 else if (param->precision == 16)
531 table = s16le_table;
532 break;
533 case AUDIO_ENCODING_SLINEAR_BE:
534 if (param->precision == 8)
535 table = s8_table;
536 else if (param->precision == 16)
537 table = s16be_table;
538 break;
539 case AUDIO_ENCODING_ULINEAR_LE:
540 if (param->precision == 8)
541 table = u8_table;
542 else if (param->precision == 16)
543 table = u16le_table;
544 break;
545 case AUDIO_ENCODING_ULINEAR_BE:
546 if (param->precision == 8)
547 table = u8_table;
548 else if (param->precision == 16)
549 table = u16be_table;
550 break;
551#if NMULAW > 0
552 case AUDIO_ENCODING_ULAW:
553 table = mulaw_table;
554 break;
555 case AUDIO_ENCODING_ALAW:
556 table = alaw_table;
557 break;
558#endif
559 }
560 if (table == NULL) {
561 DPRINTF(("%s: LEAVE with -1 (no-emultable)\n", __func__));
562 return -1;
563 }
564 work = *param;
565 for (j = 0; table[j].precision != 0; j++) {
566 work.encoding = table[j].encoding;
567 work.precision = table[j].precision;
568 work.validbits = table[j].validbits;
569 i = auconv_exact_match(formats, nformats, mode, &work);
570 if (i >= 0) {
571 conv = mode == AUMODE_PLAY
572 ? table[j].play_conv : table[j].rec_conv;
573 list->append(list, conv, &work);
574 DPRINTF(("%s: LEAVE with %d (emultable)\n", __func__, i));
575 return i;
576 }
577 }
578 /* not found */
579
580#if NAURATECONV > 0
581 /* emulation with aurateconv */
582 DPRINTF(("%s: encoding emulation with aurateconv\n", __func__));
583 if (!rateconv) {
584 DPRINTF(("%s: LEAVE with -1 (no-rateconv)\n", __func__));
585 return -1;
586 }
587 work = *param;
588 for (j = 0; table[j].precision != 0; j++) {
589 if (!auconv_rateconv_supportable(table[j].encoding,
590 table[j].precision,
591 table[j].validbits))
592 continue;
593 work.encoding = table[j].encoding;
594 work.precision = table[j].precision;
595 work.validbits = table[j].validbits;
596 i = auconv_rateconv_check_channels(formats, nformats,
597 mode, &work, list);
598 if (i >= 0) {
599 /* work<=>hw conversion is already registered */
600 conv = mode == AUMODE_PLAY
601 ? table[j].play_conv : table[j].rec_conv;
602 /* register userland<=>work conversion */
603 list->append(list, conv, &work);
604 DPRINTF(("%s: LEAVE with %d (rateconv2)\n", __func__, i));
605 return i;
606 }
607 }
608
609#endif
610 DPRINTF(("%s: LEAVE with -1 (bottom)\n", __func__));
611 return -1;
612}
613
614#if NAURATECONV > 0
615static int
616auconv_rateconv_supportable(u_int encoding, u_int precision, u_int validbits)
617{
618 if (encoding != AUDIO_ENCODING_SLINEAR_LE
619 && encoding != AUDIO_ENCODING_SLINEAR_BE)
620 return false;
621 if (precision != 16 && precision != 24 && precision != 32)
622 return false;
623 if (precision < validbits)
624 return false;
625 return true;
626}
627
628static int
629auconv_rateconv_check_channels(const struct audio_format *formats, int nformats,
630 int mode, const audio_params_t *param,
631 stream_filter_list_t *list)
632{
633 audio_params_t hw_param;
634 int ind, n;
635
636 hw_param = *param;
637 /* check for the specified number of channels */
638 ind = auconv_rateconv_check_rates(formats, nformats, mode, param,
639 &hw_param, list);
640 if (ind >= 0)
641 return ind;
642
643 /* check for larger numbers */
644 for (n = param->channels + 1; n <= AUDIO_MAX_CHANNELS; n++) {
645 hw_param.channels = n;
646 ind = auconv_rateconv_check_rates(formats, nformats, mode,
647 param, &hw_param, list);
648 if (ind >= 0)
649 return ind;
650 }
651
652 /* check for stereo:monaural conversion */
653 if (param->channels == 2) {
654 hw_param.channels = 1;
655 ind = auconv_rateconv_check_rates(formats, nformats, mode,
656 param, &hw_param, list);
657 if (ind >= 0)
658 return ind;
659 }
660 return -1;
661}
662
663static int
664auconv_rateconv_check_rates(const struct audio_format *formats, int nformats,
665 int mode, const audio_params_t *param,
666 audio_params_t *hw_param, stream_filter_list_t *list)
667{
668 int ind, i, j, enc, f_enc;
669 u_int rate, minrate, maxrate, orig_rate;
670
671 /* exact match */
672 ind = auconv_exact_match(formats, nformats, mode, hw_param);
673 if (ind >= 0)
674 goto found;
675
676 /* determine min/max of specified encoding/precision/channels */
677 minrate = UINT_MAX;
678 maxrate = 0;
679 enc = auconv_normalize_encoding(param->encoding,
680 param->precision);
681 for (i = 0; i < nformats; i++) {
682 if (!AUFMT_IS_VALID(&formats[i]))
683 continue;
684 if ((formats[i].mode & mode) == 0)
685 continue;
686 f_enc = auconv_normalize_encoding(formats[i].encoding,
687 formats[i].precision);
688 if (f_enc != enc)
689 continue;
690 if (formats[i].validbits != hw_param->validbits)
691 continue;
692 if (formats[i].precision != hw_param->precision)
693 continue;
694 if (formats[i].channels != hw_param->channels)
695 continue;
696 if (formats[i].frequency_type == 0) {
697 if (formats[i].frequency[0] < minrate)
698 minrate = formats[i].frequency[0];
699 if (formats[i].frequency[1] > maxrate)
700 maxrate = formats[i].frequency[1];
701 } else {
702 for (j = 0; j < formats[i].frequency_type; j++) {
703 if (formats[i].frequency[j] < minrate)
704 minrate = formats[i].frequency[j];
705 if (formats[i].frequency[j] > maxrate)
706 maxrate = formats[i].frequency[j];
707 }
708 }
709 }
710 if (maxrate == 0)
711 return -1;
712
713 /* try multiples of sample_rate */
714 orig_rate = hw_param->sample_rate;
715 for (i = 2; (rate = param->sample_rate * i) <= maxrate; i++) {
716 hw_param->sample_rate = rate;
717 ind = auconv_exact_match(formats, nformats, mode, hw_param);
718 if (ind >= 0)
719 goto found;
720 }
721
722 hw_param->sample_rate = param->sample_rate >= minrate
723 ? maxrate : minrate;
724 ind = auconv_exact_match(formats, nformats, mode, hw_param);
725 if (ind >= 0)
726 goto found;
727 hw_param->sample_rate = orig_rate;
728 return -1;
729
730 found:
731 list->append(list, aurateconv, hw_param);
732 return ind;
733}
734#endif /* NAURATECONV */
735
736#ifdef AUCONV_DEBUG
737static void
738auconv_dump_formats(const struct audio_format *formats, int nformats)
739{
740 const struct audio_format *f;
741 int i, j;
742
743 for (i = 0; i < nformats; i++) {
744 f = &formats[i];
745 printf("[%2d]: mode=", i);
746 if (!AUFMT_IS_VALID(f)) {
747 printf("INVALID");
748 } else if (f->mode == AUMODE_PLAY) {
749 printf("PLAY");
750 } else if (f->mode == AUMODE_RECORD) {
751 printf("RECORD");
752 } else if (f->mode == (AUMODE_PLAY | AUMODE_RECORD)) {
753 printf("PLAY|RECORD");
754 } else {
755 printf("0x%x", f->mode);
756 }
757 printf(" enc=%s", encoding_dbg_names[f->encoding]);
758 printf(" %u/%ubit", f->validbits, f->precision);
759 printf(" %uch", f->channels);
760
761 printf(" channel_mask=");
762 if (f->channel_mask == AUFMT_MONAURAL) {
763 printf("MONAURAL");
764 } else if (f->channel_mask == AUFMT_STEREO) {
765 printf("STEREO");
766 } else if (f->channel_mask == AUFMT_SURROUND4) {
767 printf("SURROUND4");
768 } else if (f->channel_mask == AUFMT_DOLBY_5_1) {
769 printf("DOLBY5.1");
770 } else {
771 printf("0x%x", f->channel_mask);
772 }
773
774 if (f->frequency_type == 0) {
775 printf(" %uHz-%uHz", f->frequency[0],
776 f->frequency[1]);
777 } else {
778 printf(" %uHz", f->frequency[0]);
779 for (j = 1; j < f->frequency_type; j++)
780 printf(",%uHz", f->frequency[j]);
781 }
782 printf("\n");
783 }
784}
785
786static void
787auconv_dump_params(const audio_params_t *p)
788{
789 printf("enc=%s", encoding_dbg_names[p->encoding]);
790 printf(" %u/%ubit", p->validbits, p->precision);
791 printf(" %uch", p->channels);
792 printf(" %uHz", p->sample_rate);
793 printf("\n");
794}
795#else
796static void
797auconv_dump_params(const audio_params_t *p)
798{
799}
800#endif /* AUCONV_DEBUG */
801
802/**
803 * a sub-routine for auconv_set_converter()
804 */
805static int
806auconv_exact_match(const struct audio_format *formats, int nformats,
807 int mode, const audio_params_t *param)
808{
809 int i, enc, f_enc;
810
811 DPRINTF(("%s: ENTER: mode=0x%x target:", __func__, mode));
812 auconv_dump_params(param);
813 enc = auconv_normalize_encoding(param->encoding,
814 param->precision);
815 DPRINTF(("%s: target normalized: %s\n", __func__,
816 encoding_dbg_names[enc]));
817 for (i = 0; i < nformats; i++) {
818 if (!AUFMT_IS_VALID(&formats[i]))
819 continue;
820 if ((formats[i].mode & mode) == 0)
821 continue;
822 f_enc = auconv_normalize_encoding(formats[i].encoding,
823 formats[i].precision);
824 DPRINTF(("%s: format[%d] normalized: %s\n",
825 __func__, i, encoding_dbg_names[f_enc]));
826 if (f_enc != enc)
827 continue;
828 /**
829 * XXX we need encoding-dependent check.
830 * XXX Is to check precision/channels meaningful for
831 * MPEG encodings?
832 */
833 if (enc != AUDIO_ENCODING_AC3) {
834 if (formats[i].validbits != param->validbits)
835 continue;
836 if (formats[i].precision != param->precision)
837 continue;
838 if (formats[i].channels != param->channels)
839 continue;
840 }
841 if (!auconv_is_supported_rate(&formats[i],
842 param->sample_rate))
843 continue;
844 return i;
845 }
846 return -1;
847}
848
849/**
850 * a sub-routine for auconv_set_converter()
851 * SLINEAR ==> SLINEAR_<host-endian>
852 * ULINEAR ==> ULINEAR_<host-endian>
853 * SLINEAR_BE 8bit ==> SLINEAR_LE 8bit
854 * ULINEAR_BE 8bit ==> ULINEAR_LE 8bit
855 * This should be the same rule as audio_check_params()
856 */
857static u_int
858auconv_normalize_encoding(u_int encoding, u_int precision)
859{
860 int enc;
861
862 enc = encoding;
863 if (enc == AUDIO_ENCODING_SLINEAR_LE)
864 return enc;
865 if (enc == AUDIO_ENCODING_ULINEAR_LE)
866 return enc;
867#if BYTE_ORDER == LITTLE_ENDIAN
868 if (enc == AUDIO_ENCODING_SLINEAR)
869 return AUDIO_ENCODING_SLINEAR_LE;
870 else if (enc == AUDIO_ENCODING_ULINEAR)
871 return AUDIO_ENCODING_ULINEAR_LE;
872#else
873 if (enc == AUDIO_ENCODING_SLINEAR)
874 enc = AUDIO_ENCODING_SLINEAR_BE;
875 else if (enc == AUDIO_ENCODING_ULINEAR)
876 enc = AUDIO_ENCODING_ULINEAR_BE;
877#endif
878 if (precision == 8 && enc == AUDIO_ENCODING_SLINEAR_BE)
879 return AUDIO_ENCODING_SLINEAR_LE;
880 if (precision == 8 && enc == AUDIO_ENCODING_ULINEAR_BE)
881 return AUDIO_ENCODING_ULINEAR_LE;
882 return enc;
883}
884
885/**
886 * a sub-routine for auconv_set_converter()
887 */
888static int
889auconv_is_supported_rate(const struct audio_format *format, u_int rate)
890{
891 u_int i;
892
893 if (format->frequency_type == 0) {
894 return format->frequency[0] <= rate
895 && rate <= format->frequency[1];
896 }
897 for (i = 0; i < format->frequency_type; i++) {
898 if (format->frequency[i] == rate)
899 return true;
900 }
901 return false;
902}
903
904/**
905 * Create an audio_encoding_set besed on hardware capability represented
906 * by audio_format.
907 *
908 * Usage:
909 * foo_attach(...) {
910 * :
911 * if (auconv_create_encodings(formats, nformats,
912 * &sc->sc_encodings) != 0) {
913 * // attach failure
914 * }
915 *
916 * @param formats [IN] An array of formats which a hardware can support.
917 * @param nformats [IN] The number of elements of the array.
918 * @param encodings [OUT] receives an address of an audio_encoding_set.
919 * @return errno; 0 for success.
920 */
921int
922auconv_create_encodings(const struct audio_format *formats, int nformats,
923 struct audio_encoding_set **encodings)
924{
925 struct audio_encoding_set *buf;
926 int capacity;
927 int i;
928 int err;
929
930#define ADD_ENCODING(enc, prec, flags) do { \
931 err = auconv_add_encoding(enc, prec, flags, &buf, &capacity); \
932 if (err != 0) goto err_exit; \
933} while (/*CONSTCOND*/0)
934
935 capacity = 10;
936 buf = AUCONV_MALLOC(ENCODING_SET_SIZE(capacity));
937 if (buf == NULL) {
938 err = ENOMEM;
939 goto err_exit;
940 }
941 buf->size = 0;
942 for (i = 0; i < nformats; i++) {
943 if (!AUFMT_IS_VALID(&formats[i]))
944 continue;
945 switch (formats[i].encoding) {
946 case AUDIO_ENCODING_SLINEAR_LE:
947 ADD_ENCODING(formats[i].encoding,
948 formats[i].precision, 0);
949 ADD_ENCODING(AUDIO_ENCODING_SLINEAR_BE,
950 formats[i].precision,
951 AUDIO_ENCODINGFLAG_EMULATED);
952 ADD_ENCODING(AUDIO_ENCODING_ULINEAR_LE,
953 formats[i].precision,
954 AUDIO_ENCODINGFLAG_EMULATED);
955 ADD_ENCODING(AUDIO_ENCODING_ULINEAR_BE,
956 formats[i].precision,
957 AUDIO_ENCODINGFLAG_EMULATED);
958#if NMULAW > 0
959 if (formats[i].precision == 8
960 || formats[i].precision == 16) {
961 ADD_ENCODING(AUDIO_ENCODING_ULAW, 8,
962 AUDIO_ENCODINGFLAG_EMULATED);
963 ADD_ENCODING(AUDIO_ENCODING_ALAW, 8,
964 AUDIO_ENCODINGFLAG_EMULATED);
965 }
966#endif
967 break;
968 case AUDIO_ENCODING_SLINEAR_BE:
969 ADD_ENCODING(formats[i].encoding,
970 formats[i].precision, 0);
971 ADD_ENCODING(AUDIO_ENCODING_SLINEAR_LE,
972 formats[i].precision,
973 AUDIO_ENCODINGFLAG_EMULATED);
974 ADD_ENCODING(AUDIO_ENCODING_ULINEAR_LE,
975 formats[i].precision,
976 AUDIO_ENCODINGFLAG_EMULATED);
977 ADD_ENCODING(AUDIO_ENCODING_ULINEAR_BE,
978 formats[i].precision,
979 AUDIO_ENCODINGFLAG_EMULATED);
980#if NMULAW > 0
981 if (formats[i].precision == 8
982 || formats[i].precision == 16) {
983 ADD_ENCODING(AUDIO_ENCODING_ULAW, 8,
984 AUDIO_ENCODINGFLAG_EMULATED);
985 ADD_ENCODING(AUDIO_ENCODING_ALAW, 8,
986 AUDIO_ENCODINGFLAG_EMULATED);
987 }
988#endif
989 break;
990 case AUDIO_ENCODING_ULINEAR_LE:
991 ADD_ENCODING(formats[i].encoding,
992 formats[i].precision, 0);
993 ADD_ENCODING(AUDIO_ENCODING_SLINEAR_BE,
994 formats[i].precision,
995 AUDIO_ENCODINGFLAG_EMULATED);
996 ADD_ENCODING(AUDIO_ENCODING_SLINEAR_LE,
997 formats[i].precision,
998 AUDIO_ENCODINGFLAG_EMULATED);
999 ADD_ENCODING(AUDIO_ENCODING_ULINEAR_BE,
1000 formats[i].precision,
1001 AUDIO_ENCODINGFLAG_EMULATED);
1002#if NMULAW > 0
1003 if (formats[i].precision == 8
1004 || formats[i].precision == 16) {
1005 ADD_ENCODING(AUDIO_ENCODING_ULAW, 8,
1006 AUDIO_ENCODINGFLAG_EMULATED);
1007 ADD_ENCODING(AUDIO_ENCODING_ALAW, 8,
1008 AUDIO_ENCODINGFLAG_EMULATED);
1009 }
1010#endif
1011 break;
1012 case AUDIO_ENCODING_ULINEAR_BE:
1013 ADD_ENCODING(formats[i].encoding,
1014 formats[i].precision, 0);
1015 ADD_ENCODING(AUDIO_ENCODING_SLINEAR_BE,
1016 formats[i].precision,
1017 AUDIO_ENCODINGFLAG_EMULATED);
1018 ADD_ENCODING(AUDIO_ENCODING_ULINEAR_LE,
1019 formats[i].precision,
1020 AUDIO_ENCODINGFLAG_EMULATED);
1021 ADD_ENCODING(AUDIO_ENCODING_SLINEAR_LE,
1022 formats[i].precision,
1023 AUDIO_ENCODINGFLAG_EMULATED);
1024#if NMULAW > 0
1025 if (formats[i].precision == 8
1026 || formats[i].precision == 16) {
1027 ADD_ENCODING(AUDIO_ENCODING_ULAW, 8,
1028 AUDIO_ENCODINGFLAG_EMULATED);
1029 ADD_ENCODING(AUDIO_ENCODING_ALAW, 8,
1030 AUDIO_ENCODINGFLAG_EMULATED);
1031 }
1032#endif
1033 break;
1034
1035 case AUDIO_ENCODING_ULAW:
1036 case AUDIO_ENCODING_ALAW:
1037 case AUDIO_ENCODING_ADPCM:
1038 case AUDIO_ENCODING_MPEG_L1_STREAM:
1039 case AUDIO_ENCODING_MPEG_L1_PACKETS:
1040 case AUDIO_ENCODING_MPEG_L1_SYSTEM:
1041 case AUDIO_ENCODING_MPEG_L2_STREAM:
1042 case AUDIO_ENCODING_MPEG_L2_PACKETS:
1043 case AUDIO_ENCODING_MPEG_L2_SYSTEM:
1044 case AUDIO_ENCODING_AC3:
1045 ADD_ENCODING(formats[i].encoding,
1046 formats[i].precision, 0);
1047 break;
1048
1049 case AUDIO_ENCODING_SLINEAR:
1050 case AUDIO_ENCODING_ULINEAR:
1051 case AUDIO_ENCODING_LINEAR:
1052 case AUDIO_ENCODING_LINEAR8:
1053 default:
1054 printf("%s: invalid encoding value "
1055 "for audio_format: %d\n",
1056 __func__, formats[i].encoding);
1057 break;
1058 }
1059 }
1060 *encodings = buf;
1061 return 0;
1062
1063 err_exit:
1064 if (buf != NULL)
1065 AUCONV_FREE(buf);
1066 *encodings = NULL;
1067 return err;
1068}
1069
1070/**
1071 * a sub-routine for auconv_create_encodings()
1072 */
1073static int
1074auconv_add_encoding(int enc, int prec, int flags,
1075 struct audio_encoding_set **buf, int *capacity)
1076{
1077 static const char *encoding_names[] = {
1078 NULL, AudioEmulaw, AudioEalaw, NULL,
1079 NULL, AudioEadpcm, AudioEslinear_le, AudioEslinear_be,
1080 AudioEulinear_le, AudioEulinear_be,
1081 AudioEslinear, AudioEulinear,
1082 AudioEmpeg_l1_stream, AudioEmpeg_l1_packets,
1083 AudioEmpeg_l1_system, AudioEmpeg_l2_stream,
1084 AudioEmpeg_l2_packets, AudioEmpeg_l2_system,
1085 AudioEac3
1086 };
1087 struct audio_encoding_set *set;
1088 struct audio_encoding_set *new_buf;
1089 audio_encoding_t *e;
1090 int i;
1091
1092 set = *buf;
1093 /* already has the same encoding? */
1094 e = set->items;
1095 for (i = 0; i < set->size; i++, e++) {
1096 if (e->encoding == enc && e->precision == prec) {
1097 /* overwrite EMULATED flag */
1098 if ((e->flags & AUDIO_ENCODINGFLAG_EMULATED)
1099 && (flags & AUDIO_ENCODINGFLAG_EMULATED) == 0) {
1100 e->flags &= ~AUDIO_ENCODINGFLAG_EMULATED;
1101 }
1102 return 0;
1103 }
1104 }
1105 /* We don't have the specified one. */
1106
1107 if (set->size >= *capacity) {
1108 new_buf = AUCONV_REALLOC(set,
1109 ENCODING_SET_SIZE(*capacity + 10));
1110 if (new_buf == NULL)
1111 return ENOMEM;
1112 *buf = new_buf;
1113 set = new_buf;
1114 *capacity += 10;
1115 }
1116
1117 e = &set->items[set->size];
1118 e->index = 0;
1119 strlcpy(e->name, encoding_names[enc], MAX_AUDIO_DEV_LEN);
1120 e->encoding = enc;
1121 e->precision = prec;
1122 e->flags = flags;
1123 set->size += 1;
1124 return 0;
1125}
1126
1127/**
1128 * Delete an audio_encoding_set created by auconv_create_encodings().
1129 *
1130 * Usage:
1131 * foo_detach(...) {
1132 * :
1133 * auconv_delete_encodings(sc->sc_encodings);
1134 * :
1135 * }
1136 *
1137 * @param encodings [IN] An audio_encoding_set which was created by
1138 * auconv_create_encodings().
1139 * @return errno; 0 for success.
1140 */
1141int auconv_delete_encodings(struct audio_encoding_set *encodings)
1142{
1143 if (encodings != NULL)
1144 AUCONV_FREE(encodings);
1145 return 0;
1146}
1147
1148/**
1149 * Copy the element specified by aep->index.
1150 *
1151 * Usage:
1152 * int foo_query_encoding(void *v, audio_encoding_t *aep) {
1153 * struct foo_softc *sc = (struct foo_softc *)v;
1154 * return auconv_query_encoding(sc->sc_encodings, aep);
1155 * }
1156 *
1157 * @param encodings [IN] An audio_encoding_set created by
1158 * auconv_create_encodings().
1159 * @param aep [IN/OUT] resultant audio_encoding_t.
1160 */
1161int
1162auconv_query_encoding(const struct audio_encoding_set *encodings,
1163 audio_encoding_t *aep)
1164{
1165 if (aep->index >= encodings->size)
1166 return EINVAL;
1167 strlcpy(aep->name, encodings->items[aep->index].name,
1168 MAX_AUDIO_DEV_LEN);
1169 aep->encoding = encodings->items[aep->index].encoding;
1170 aep->precision = encodings->items[aep->index].precision;
1171 aep->flags = encodings->items[aep->index].flags;
1172 return 0;
1173}
1174