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
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 *);
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 
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_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 
213 void
stream_filter_set_fetcher(stream_filter_t * this,stream_fetcher_t * p)214 stream_filter_set_fetcher(stream_filter_t *this, stream_fetcher_t *p)
215 {
216 	this->prev = p;
217 }
218 
219 void
stream_filter_set_inputbuffer(stream_filter_t * this,audio_stream_t * stream)220 stream_filter_set_inputbuffer(stream_filter_t *this, audio_stream_t *stream)
221 {
222 	this->src = stream;
223 }
224 
225 stream_filter_t *
auconv_nocontext_filter_factory(int (* fetch_to)(struct audio_softc *,stream_fetcher_t *,audio_stream_t *,int))226 auconv_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 
244 void
auconv_nocontext_filter_dtor(struct stream_filter * this)245 auconv_nocontext_filter_dtor(struct stream_filter *this)
246 {
247 	if (this != NULL)
248 		AUCONV_FREE(this);
249 }
250 
251 #define DEFINE_FILTER(name)	\
252 static int \
253 name##_fetch_to(struct audio_softc *, stream_fetcher_t *, audio_stream_t *, int); \
254 stream_filter_t * \
255 name(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 } \
260 static int \
261 name##_fetch_to(struct audio_softc *sc, stream_fetcher_t *self, \
262     audio_stream_t *dst, int max_used)
263 
DEFINE_FILTER(change_sign8)264 DEFINE_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 
DEFINE_FILTER(change_sign16)280 DEFINE_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 
DEFINE_FILTER(swap_bytes)307 DEFINE_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 
DEFINE_FILTER(swap_bytes_change_sign16)325 DEFINE_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 
DEFINE_FILTER(linear8_to_linear16)352 DEFINE_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 
DEFINE_FILTER(linear16_to_linear8)414 DEFINE_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  */
484 int
auconv_set_converter(const struct audio_format * formats,int nformats,int mode,const audio_params_t * param,int rateconv,stream_filter_list_t * list)485 auconv_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
615 static int
auconv_rateconv_supportable(u_int encoding,u_int precision,u_int validbits)616 auconv_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 
628 static int
auconv_rateconv_check_channels(const struct audio_format * formats,int nformats,int mode,const audio_params_t * param,stream_filter_list_t * list)629 auconv_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 
663 static int
auconv_rateconv_check_rates(const struct audio_format * formats,int nformats,int mode,const audio_params_t * param,audio_params_t * hw_param,stream_filter_list_t * list)664 auconv_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
737 static void
auconv_dump_formats(const struct audio_format * formats,int nformats)738 auconv_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 
786 static void
auconv_dump_params(const audio_params_t * p)787 auconv_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
796 static void
auconv_dump_params(const audio_params_t * p)797 auconv_dump_params(const audio_params_t *p)
798 {
799 }
800 #endif /* AUCONV_DEBUG */
801 
802 /**
803  * a sub-routine for auconv_set_converter()
804  */
805 static int
auconv_exact_match(const struct audio_format * formats,int nformats,int mode,const audio_params_t * param)806 auconv_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  */
857 static u_int
auconv_normalize_encoding(u_int encoding,u_int precision)858 auconv_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  */
888 static int
auconv_is_supported_rate(const struct audio_format * format,u_int rate)889 auconv_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  */
921 int
auconv_create_encodings(const struct audio_format * formats,int nformats,struct audio_encoding_set ** encodings)922 auconv_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  */
1073 static int
auconv_add_encoding(int enc,int prec,int flags,struct audio_encoding_set ** buf,int * capacity)1074 auconv_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  */
auconv_delete_encodings(struct audio_encoding_set * encodings)1141 int 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  */
1161 int
auconv_query_encoding(const struct audio_encoding_set * encodings,audio_encoding_t * aep)1162 auconv_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