FreeBSD/Linux Kernel Cross Reference
sys/dev/auconv.c
1 /* $NetBSD: auconv.c,v 1.12 2005/01/10 22:01:36 kent 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.12 2005/01/10 22:01:36 kent Exp $");
39
40 #include <sys/types.h>
41 #include <sys/audioio.h>
42 #include <sys/errno.h>
43 #include <sys/malloc.h>
44 #include <sys/null.h>
45 #include <sys/systm.h>
46 #include <dev/audio_if.h>
47 #include <dev/auconv.h>
48 #include <dev/mulaw.h>
49 #include <machine/limits.h>
50 #ifndef _KERNEL
51 #include <stddef.h>
52 #include <stdio.h>
53 #include <stdlib.h>
54 #include <string.h>
55 #endif
56
57 #include <aurateconv.h> /* generated by config(8) */
58 #include <mulaw.h> /* generated by config(8) */
59
60 /* #define AUCONV_DEBUG */
61 #ifdef AUCONV_DEBUG
62 # define DPRINTF(x) printf x
63 #else
64 # define DPRINTF(x)
65 #endif
66
67 #if NAURATECONV > 0
68 static int auconv_rateconv_supportable(u_int, u_int, u_int);
69 static int auconv_rateconv_check_channels(const struct audio_format *, int,
70 int, const audio_params_t *,
71 stream_filter_list_t *);
72 static int auconv_rateconv_check_rates(const struct audio_format *, int,
73 int, const audio_params_t *,
74 audio_params_t *,
75 stream_filter_list_t *);
76 #endif
77 #ifdef AUCONV_DEBUG
78 static void auconv_dump_formats(const struct audio_format *, int);
79 #endif
80 static void auconv_dump_params(const audio_params_t *);
81 static int auconv_exact_match(const struct audio_format *, int, int,
82 const struct audio_params *);
83 static u_int auconv_normalize_encoding(u_int, u_int);
84 static int auconv_is_supported_rate(const struct audio_format *, u_int);
85 static int auconv_add_encoding(int, int, int, struct audio_encoding_set **,
86 int *);
87
88 #ifdef _KERNEL
89 #define AUCONV_MALLOC(size) malloc(size, M_DEVBUF, M_NOWAIT)
90 #define AUCONV_REALLOC(p, size) realloc(p, size, M_DEVBUF, M_NOWAIT)
91 #define AUCONV_FREE(p) free(p, M_DEVBUF)
92 #else
93 #define AUCONV_MALLOC(size) malloc(size)
94 #define AUCONV_REALLOC(p, size) realloc(p, size)
95 #define AUCONV_FREE(p) free(p)
96 #define FALSE 0
97 #define TRUE 1
98 #endif
99
100 struct 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
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;
113 };
114 /*
115 * SLINEAR-16 or SLINEAR-24 should precede in a table because
116 * aurateconv supports only SLINEAR.
117 */
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_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 };
210 #endif
211
212 void
213 stream_filter_set_fetcher(stream_filter_t *this, stream_fetcher_t *p)
214 {
215 this->prev = p;
216 }
217
218 void
219 stream_filter_set_inputbuffer(stream_filter_t *this, audio_stream_t *stream)
220 {
221 this->src = stream;
222 }
223
224 stream_filter_t *
225 auconv_nocontext_filter_factory(
226 int (*fetch_to)(stream_fetcher_t *, audio_stream_t *, int))
227 {
228 stream_filter_t *this;
229
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;
240 }
241
242 void
243 auconv_nocontext_filter_dtor(struct stream_filter *this)
244 {
245 if (this != NULL)
246 AUCONV_FREE(this);
247 }
248
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) \
255 { \
256 return auconv_nocontext_filter_factory(name##_fetch_to); \
257 } \
258 static int \
259 name##_fetch_to(stream_fetcher_t *self, audio_stream_t *dst, int max_used)
260
261 DEFINE_FILTER(change_sign8)
262 {
263 stream_filter_t *this;
264 int m, err;
265
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;
275 }
276
277 DEFINE_FILTER(change_sign16)
278 {
279 stream_filter_t *this;
280 int m, err, enc;
281
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);
300 }
301 return 0;
302 }
303
304 DEFINE_FILTER(swap_bytes)
305 {
306 stream_filter_t *this;
307 int m, err;
308
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;
320 }
321
322 DEFINE_FILTER(swap_bytes_change_sign16)
323 {
324 stream_filter_t *this;
325 int m, err, enc;
326
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);
345 }
346 return 0;
347 }
348
349 DEFINE_FILTER(linear8_to_linear16)
350 {
351 stream_filter_t *this;
352 int m, err, enc_dst, enc_src;
353
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)) {
366 /*
367 * slinear8 -> slinear16_le
368 * ulinear8 -> ulinear16_le
369 */
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)) {
378 /*
379 * slinear8 -> slinear16_be
380 * ulinear8 -> ulinear16_be
381 */
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)) {
390 /*
391 * slinear8 -> ulinear16_le
392 * ulinear8 -> slinear16_le
393 */
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 {
399 /*
400 * slinear8 -> ulinear16_be
401 * ulinear8 -> slinear16_be
402 */
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);
407 }
408 return 0;
409 }
410
411 DEFINE_FILTER(linear16_to_linear8)
412 {
413 stream_filter_t *this;
414 int m, err, enc_src, enc_dst;
415
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)) {
427 /*
428 * slinear16_le -> slinear8
429 * ulinear16_le -> ulinear8
430 */
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)) {
438 /*
439 * slinear16_le -> ulinear8
440 * ulinear16_le -> slinear8
441 */
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)) {
449 /*
450 * slinear16_be -> slinear8
451 * ulinear16_be -> ulinear8
452 */
453 FILTER_LOOP_PROLOGUE(this->src, 2, dst, 1, m) {
454 d[0] = s[0];
455 } FILTER_LOOP_EPILOGUE(this->src, dst);
456 } else {
457 /*
458 * slinear16_be -> ulinear8
459 * ulinear16_be -> slinear8
460 */
461 FILTER_LOOP_PROLOGUE(this->src, 2, dst, 1, m) {
462 d[0] = s[0] ^ 0x80;
463 } FILTER_LOOP_EPILOGUE(this->src, dst);
464 }
465 return 0;
466 }
467
468 /**
469 * Set appropriate parameters in `param,' and return the index in
470 * the hardware capability array `formats.'
471 *
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.
480 */
481 int
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)
485 {
486 audio_params_t work;
487 const struct conv_table *table;
488 stream_filter_factory_t *conv;
489 int enc;
490 int i, j;
491
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);
497
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;
503 }
504
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;
516 }
517 }
518 #endif
519
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
556 }
557 if (table == NULL) {
558 DPRINTF(("%s: LEAVE with -1 (no-emultable)\n", __func__));
559 return -1;
560 }
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;
573 }
574 }
575 /* not found */
576
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;
583 }
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;
603 }
604 }
605
606 #endif
607 DPRINTF(("%s: LEAVE with -1 (bottom)\n", __func__));
608 return -1;
609 }
610
611 #if NAURATECONV > 0
612 static int
613 auconv_rateconv_supportable(u_int encoding, u_int precision, u_int validbits)
614 {
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;
623 }
624
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)
629 {
630 audio_params_t hw_param;
631 int ind, n;
632
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;
639
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;
647 }
648
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;
656 }
657 return -1;
658 }
659
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)
664 {
665 int ind, i, j, enc, f_enc;
666 u_int rate, minrate, maxrate, orig_rate;;
667
668 /* exact match */
669 ind = auconv_exact_match(formats, nformats, mode, hw_param);
670 if (ind >= 0)
671 goto found;
672
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];
704 }
705 }
706 }
707 if (maxrate == 0)
708 return -1;
709
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;
717 }
718
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;
726
727 found:
728 list->append(list, aurateconv, hw_param);
729 return ind;
730 }
731 #endif /* NAURATECONV */
732
733 #ifdef AUCONV_DEBUG
734 static void
735 auconv_dump_formats(const struct audio_format *formats, int nformats)
736 {
737 const struct audio_format *f;
738 int i, j;
739
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);
753 }
754 printf(" enc=%s", encoding_names[f->encoding]);
755 printf(" %u/%ubit", f->validbits, f->precision);
756 printf(" %uch", f->channels);
757
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);
769 }
770
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]);
778 }
779 printf("\n");
780 }
781 }
782
783 static void
784 auconv_dump_params(const audio_params_t *p)
785 {
786 printf("enc=%s", encoding_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");
791 }
792 #else
793 static void
794 auconv_dump_params(const audio_params_t *p)
795 {
796 }
797 #endif /* AUCONV_DEBUG */
798
799 /**
800 * a sub-routine for auconv_set_converter()
801 */
802 static int
803 auconv_exact_match(const struct audio_format *formats, int nformats,
804 int mode, const audio_params_t *param)
805 {
806 int i, enc, f_enc;
807
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__, encoding_names[enc]));
813 for (i = 0; i < nformats; i++) {
814 if (!AUFMT_IS_VALID(&formats[i]))
815 continue;
816 if ((formats[i].mode & mode) == 0)
817 continue;
818 f_enc = auconv_normalize_encoding(formats[i].encoding,
819 formats[i].precision);
820 DPRINTF(("%s: formtat[%d] normalized: %s\n",
821 __func__, i, encoding_names[f_enc]));
822 if (f_enc != enc)
823 continue;
824 /**
825 * XXX we need encoding-dependent check.
826 * XXX Is to check precision/channels meaningful for
827 * MPEG encodings?
828 */
829 if (formats[i].validbits != param->validbits)
830 continue;
831 if (formats[i].precision != param->precision)
832 continue;
833 if (formats[i].channels != param->channels)
834 continue;
835 if (!auconv_is_supported_rate(&formats[i],
836 param->sample_rate))
837 continue;
838 return i;
839 }
840 return -1;
841 }
842
843 /**
844 * a sub-routine for auconv_set_converter()
845 * SLINEAR ==> SLINEAR_<host-endian>
846 * ULINEAR ==> ULINEAR_<host-endian>
847 * SLINEAR_BE 8bit ==> SLINEAR_LE 8bit
848 * ULINEAR_BE 8bit ==> ULINEAR_LE 8bit
849 * This should be the same rule as audio_check_params()
850 */
851 static u_int
852 auconv_normalize_encoding(u_int encoding, u_int precision)
853 {
854 int enc;
855
856 enc = encoding;
857 if (enc == AUDIO_ENCODING_SLINEAR_LE)
858 return enc;
859 if (enc == AUDIO_ENCODING_ULINEAR_LE)
860 return enc;
861 #if BYTE_ORDER == LITTLE_ENDIAN
862 if (enc == AUDIO_ENCODING_SLINEAR)
863 return AUDIO_ENCODING_SLINEAR_LE;
864 else if (enc == AUDIO_ENCODING_ULINEAR)
865 return AUDIO_ENCODING_ULINEAR_LE;
866 #else
867 if (enc == AUDIO_ENCODING_SLINEAR)
868 enc = AUDIO_ENCODING_SLINEAR_BE;
869 else if (enc == AUDIO_ENCODING_ULINEAR)
870 enc = AUDIO_ENCODING_ULINEAR_BE;
871 #endif
872 if (precision == 8 && enc == AUDIO_ENCODING_SLINEAR_BE)
873 return AUDIO_ENCODING_SLINEAR_LE;
874 if (precision == 8 && enc == AUDIO_ENCODING_ULINEAR_BE)
875 return AUDIO_ENCODING_ULINEAR_LE;
876 return enc;
877 }
878
879 /**
880 * a sub-routine for auconv_set_converter()
881 */
882 static int
883 auconv_is_supported_rate(const struct audio_format *format, u_int rate)
884 {
885 u_int i;
886
887 if (format->frequency_type == 0) {
888 return format->frequency[0] <= rate
889 && rate <= format->frequency[1];
890 }
891 for (i = 0; i < format->frequency_type; i++) {
892 if (format->frequency[i] == rate)
893 return TRUE;
894 }
895 return FALSE;
896 }
897
898 /**
899 * Create an audio_encoding_set besed on hardware capability represented
900 * by audio_format.
901 *
902 * Usage:
903 * foo_attach(...) {
904 * :
905 * if (auconv_create_encodings(formats, nformats,
906 * &sc->sc_encodings) != 0) {
907 * // attach failure
908 * }
909 *
910 * @param formats [IN] An array of formats which a hardware can support.
911 * @param nformats [IN] The number of elements of the array.
912 * @param encodings [OUT] receives an address of an audio_encoding_set.
913 * @return errno; 0 for success.
914 */
915 int
916 auconv_create_encodings(const struct audio_format *formats, int nformats,
917 struct audio_encoding_set **encodings)
918 {
919 struct audio_encoding_set *buf;
920 int capacity;
921 int i;
922 int err;
923
924 #define ADD_ENCODING(enc, prec, flags) do { \
925 err = auconv_add_encoding(enc, prec, flags, &buf, &capacity); \
926 if (err != 0) goto err_exit; \
927 } while (/*CONSTCOND*/0)
928
929 capacity = 10;
930 buf = AUCONV_MALLOC(ENCODING_SET_SIZE(capacity));
931 buf->size = 0;
932 for (i = 0; i < nformats; i++) {
933 if (!AUFMT_IS_VALID(&formats[i]))
934 continue;
935 switch (formats[i].encoding) {
936 case AUDIO_ENCODING_SLINEAR_LE:
937 ADD_ENCODING(formats[i].encoding,
938 formats[i].precision, 0);
939 ADD_ENCODING(AUDIO_ENCODING_SLINEAR_BE,
940 formats[i].precision,
941 AUDIO_ENCODINGFLAG_EMULATED);
942 ADD_ENCODING(AUDIO_ENCODING_ULINEAR_LE,
943 formats[i].precision,
944 AUDIO_ENCODINGFLAG_EMULATED);
945 ADD_ENCODING(AUDIO_ENCODING_ULINEAR_BE,
946 formats[i].precision,
947 AUDIO_ENCODINGFLAG_EMULATED);
948 #if NMULAW > 0
949 if (formats[i].precision == 8
950 || formats[i].precision == 16) {
951 ADD_ENCODING(AUDIO_ENCODING_ULAW, 8,
952 AUDIO_ENCODINGFLAG_EMULATED);
953 ADD_ENCODING(AUDIO_ENCODING_ALAW, 8,
954 AUDIO_ENCODINGFLAG_EMULATED);
955 }
956 #endif
957 break;
958 case AUDIO_ENCODING_SLINEAR_BE:
959 ADD_ENCODING(formats[i].encoding,
960 formats[i].precision, 0);
961 ADD_ENCODING(AUDIO_ENCODING_SLINEAR_LE,
962 formats[i].precision,
963 AUDIO_ENCODINGFLAG_EMULATED);
964 ADD_ENCODING(AUDIO_ENCODING_ULINEAR_LE,
965 formats[i].precision,
966 AUDIO_ENCODINGFLAG_EMULATED);
967 ADD_ENCODING(AUDIO_ENCODING_ULINEAR_BE,
968 formats[i].precision,
969 AUDIO_ENCODINGFLAG_EMULATED);
970 #if NMULAW > 0
971 if (formats[i].precision == 8
972 || formats[i].precision == 16) {
973 ADD_ENCODING(AUDIO_ENCODING_ULAW, 8,
974 AUDIO_ENCODINGFLAG_EMULATED);
975 ADD_ENCODING(AUDIO_ENCODING_ALAW, 8,
976 AUDIO_ENCODINGFLAG_EMULATED);
977 }
978 #endif
979 break;
980 case AUDIO_ENCODING_ULINEAR_LE:
981 ADD_ENCODING(formats[i].encoding,
982 formats[i].precision, 0);
983 ADD_ENCODING(AUDIO_ENCODING_SLINEAR_BE,
984 formats[i].precision,
985 AUDIO_ENCODINGFLAG_EMULATED);
986 ADD_ENCODING(AUDIO_ENCODING_SLINEAR_LE,
987 formats[i].precision,
988 AUDIO_ENCODINGFLAG_EMULATED);
989 ADD_ENCODING(AUDIO_ENCODING_ULINEAR_BE,
990 formats[i].precision,
991 AUDIO_ENCODINGFLAG_EMULATED);
992 #if NMULAW > 0
993 if (formats[i].precision == 8
994 || formats[i].precision == 16) {
995 ADD_ENCODING(AUDIO_ENCODING_ULAW, 8,
996 AUDIO_ENCODINGFLAG_EMULATED);
997 ADD_ENCODING(AUDIO_ENCODING_ALAW, 8,
998 AUDIO_ENCODINGFLAG_EMULATED);
999 }
1000 #endif
1001 break;
1002 case AUDIO_ENCODING_ULINEAR_BE:
1003 ADD_ENCODING(formats[i].encoding,
1004 formats[i].precision, 0);
1005 ADD_ENCODING(AUDIO_ENCODING_SLINEAR_BE,
1006 formats[i].precision,
1007 AUDIO_ENCODINGFLAG_EMULATED);
1008 ADD_ENCODING(AUDIO_ENCODING_ULINEAR_LE,
1009 formats[i].precision,
1010 AUDIO_ENCODINGFLAG_EMULATED);
1011 ADD_ENCODING(AUDIO_ENCODING_SLINEAR_LE,
1012 formats[i].precision,
1013 AUDIO_ENCODINGFLAG_EMULATED);
1014 #if NMULAW > 0
1015 if (formats[i].precision == 8
1016 || formats[i].precision == 16) {
1017 ADD_ENCODING(AUDIO_ENCODING_ULAW, 8,
1018 AUDIO_ENCODINGFLAG_EMULATED);
1019 ADD_ENCODING(AUDIO_ENCODING_ALAW, 8,
1020 AUDIO_ENCODINGFLAG_EMULATED);
1021 }
1022 #endif
1023 break;
1024
1025 case AUDIO_ENCODING_ULAW:
1026 case AUDIO_ENCODING_ALAW:
1027 case AUDIO_ENCODING_ADPCM:
1028 case AUDIO_ENCODING_MPEG_L1_STREAM:
1029 case AUDIO_ENCODING_MPEG_L1_PACKETS:
1030 case AUDIO_ENCODING_MPEG_L1_SYSTEM:
1031 case AUDIO_ENCODING_MPEG_L2_STREAM:
1032 case AUDIO_ENCODING_MPEG_L2_PACKETS:
1033 case AUDIO_ENCODING_MPEG_L2_SYSTEM:
1034 ADD_ENCODING(formats[i].encoding,
1035 formats[i].precision, 0);
1036 break;
1037
1038 case AUDIO_ENCODING_SLINEAR:
1039 case AUDIO_ENCODING_ULINEAR:
1040 case AUDIO_ENCODING_LINEAR:
1041 case AUDIO_ENCODING_LINEAR8:
1042 default:
1043 printf("%s: invalid encoding value "
1044 "for audio_format: %d\n",
1045 __func__, formats[i].encoding);
1046 break;
1047 }
1048 }
1049 *encodings = buf;
1050 return 0;
1051
1052 err_exit:
1053 if (buf != NULL)
1054 AUCONV_FREE(buf);
1055 *encodings = NULL;
1056 return err;
1057 }
1058
1059 /**
1060 * a sub-routine for auconv_create_encodings()
1061 */
1062 static int
1063 auconv_add_encoding(int enc, int prec, int flags,
1064 struct audio_encoding_set **buf, int *capacity)
1065 {
1066 static const char *encoding_names[] = {
1067 NULL, AudioEmulaw, AudioEalaw, NULL,
1068 NULL, AudioEadpcm, AudioEslinear_le, AudioEslinear_be,
1069 AudioEulinear_le, AudioEulinear_be,
1070 AudioEslinear, AudioEulinear,
1071 AudioEmpeg_l1_stream, AudioEmpeg_l1_packets,
1072 AudioEmpeg_l1_system, AudioEmpeg_l2_stream,
1073 AudioEmpeg_l2_packets, AudioEmpeg_l2_system
1074 };
1075 struct audio_encoding_set *set;
1076 struct audio_encoding_set *new_buf;
1077 audio_encoding_t *e;
1078 int i;
1079
1080 set = *buf;
1081 /* already has the same encoding? */
1082 e = set->items;
1083 for (i = 0; i < set->size; i++, e++) {
1084 if (e->encoding == enc && e->precision == prec) {
1085 /* overwrite EMULATED flag */
1086 if ((e->flags & AUDIO_ENCODINGFLAG_EMULATED)
1087 && (flags & AUDIO_ENCODINGFLAG_EMULATED) == 0) {
1088 e->flags &= ~AUDIO_ENCODINGFLAG_EMULATED;
1089 }
1090 return 0;
1091 }
1092 }
1093 /* We don't have the specified one. */
1094
1095 if (set->size >= *capacity) {
1096 new_buf = AUCONV_REALLOC(set,
1097 ENCODING_SET_SIZE(*capacity + 10));
1098 if (new_buf == NULL)
1099 return ENOMEM;
1100 *buf = new_buf;
1101 set = new_buf;
1102 *capacity += 10;
1103 }
1104
1105 e = &set->items[set->size];
1106 e->index = 0;
1107 strlcpy(e->name, encoding_names[enc], MAX_AUDIO_DEV_LEN);
1108 e->encoding = enc;
1109 e->precision = prec;
1110 e->flags = flags;
1111 set->size += 1;
1112 return 0;
1113 }
1114
1115 /**
1116 * Delete an audio_encoding_set created by auconv_create_encodings().
1117 *
1118 * Usage:
1119 * foo_detach(...) {
1120 * :
1121 * auconv_delete_encodings(sc->sc_encodings);
1122 * :
1123 * }
1124 *
1125 * @param encodings [IN] An audio_encoding_set which was created by
1126 * auconv_create_encodings().
1127 * @return errno; 0 for success.
1128 */
1129 int auconv_delete_encodings(struct audio_encoding_set *encodings)
1130 {
1131 if (encodings != NULL)
1132 AUCONV_FREE(encodings);
1133 return 0;
1134 }
1135
1136 /**
1137 * Copy the element specified by aep->index.
1138 *
1139 * Usage:
1140 * int foo_query_encoding(void *v, audio_encoding_t *aep) {
1141 * struct foo_softc *sc = (struct foo_softc *)v;
1142 * return auconv_query_encoding(sc->sc_encodings, aep);
1143 * }
1144 *
1145 * @param encodings [IN] An audio_encoding_set created by
1146 * auconv_create_encodings().
1147 * @param aep [IN/OUT] resultant audio_encoding_t.
1148 */
1149 int
1150 auconv_query_encoding(const struct audio_encoding_set *encodings,
1151 audio_encoding_t *aep)
1152 {
1153 if (aep->index >= encodings->size)
1154 return EINVAL;
1155 strlcpy(aep->name, encodings->items[aep->index].name,
1156 MAX_AUDIO_DEV_LEN);
1157 aep->encoding = encodings->items[aep->index].encoding;
1158 aep->precision = encodings->items[aep->index].precision;
1159 aep->flags = encodings->items[aep->index].flags;
1160 return 0;
1161 }
Cache object: 51d9c61b31e677b73b566c29b2225a22
|