xref: /titanic_52/usr/src/uts/common/io/audio/impl/audio_format.c (revision 2c30fa4582c5d6c659e059e719c5f6163f7ef1e3)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright (C) 4Front Technologies 1996-2008.
23  *
24  * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
25  */
26 
27 /*
28  * Purpose: Audio format conversion routines used by audio.c
29  */
30 
31 #include <sys/types.h>
32 #include <sys/ddi.h>
33 #include <sys/sunddi.h>
34 #include <sys/audio/g711.h>
35 
36 #include "audio_impl.h"
37 #include "audio_grc3.h"
38 
39 extern uint_t	audio_intrhz;
40 
41 /*
42  * Note: In the function below, the division by the number of channels is
43  * probably fairly expensive.  It turns out that we usually deal with stereo
44  * or mono data, so perhaps it would be useful to build custom versions of
45  * this function that only dealt with stereo or mono.
46  */
47 static int
48 do_src(audio_stream_t *sp, void *p1, void *p2, int len, int nchan)
49 {
50 	int ch, size;
51 
52 	/*
53 	 * Note that we presume that we are doing sample rate
54 	 * conversions on AUDIO_FORMAT_S24_NE, which means that have 4
55 	 * byte and 32-bit samples.
56 	 */
57 	size = sp->s_cnv_max / 4;		/* sample size is 4 */
58 	size /= nchan;
59 
60 	for (ch = 0; ch < nchan; ch++) {
61 		grc3_convert(sp->s_src_state[ch], sp->s_src_quality,
62 		    p1, p2, len, size, nchan, ch);
63 	}
64 	return (((grc3state_t *)sp->s_src_state[0])->outsz);
65 }
66 
67 static void
68 setup_src(audio_stream_t *sp, int srate, int trate, int sch, int tch)
69 {
70 	int ch, nch;
71 
72 	nch = min(sch, tch);
73 
74 	ASSERT(nch <= AUDIO_MAX_CHANNELS);
75 
76 	if (sp->s_src_quality < 1)
77 		sp->s_src_quality = 1;
78 	if (sp->s_src_quality > 5)
79 		sp->s_src_quality = 5;
80 
81 	for (ch = 0; ch < nch; ch++) {
82 		grc3_reset(sp->s_src_state[ch]);
83 		grc3_setup(sp->s_src_state[ch], srate, trate);
84 	}
85 }
86 
87 static int
88 cnv_srconly(audio_stream_t *sp, int len)
89 {
90 	void *src = sp->s_cnv_src;
91 	void *dst = sp->s_cnv_dst;
92 
93 	/*
94 	 * We must be using 24-bit native signed.
95 	 */
96 	len = do_src(sp, src, dst, len, sp->s_cnv_src_nchan);
97 
98 	sp->s_cnv_src = dst;
99 	sp->s_cnv_dst = src;
100 
101 	return (len);
102 }
103 
104 static int
105 cnv_s24oe(audio_stream_t *sp, int len)
106 {
107 	/*
108 	 * Endian switch works in both directions.  We do it in place.
109 	 */
110 	int32_t *src = sp->s_cnv_src;
111 
112 	for (int i = len * sp->s_cnv_src_nchan; i; i--) {
113 		*src = ddi_swap32(*src);
114 		src++;
115 	}
116 
117 	return (len);
118 }
119 
120 
121 static int
122 cnv_from_s8(audio_stream_t *sp, int len)
123 {
124 	void *s = sp->s_cnv_src;
125 	void *d = sp->s_cnv_dst;
126 	int8_t *src = s;
127 	int32_t *dst = d;
128 
129 	for (int i = len * sp->s_cnv_src_nchan; i; i--)
130 		*dst++ = (*src++) << 16;
131 
132 	sp->s_cnv_src = d;
133 	sp->s_cnv_dst = s;
134 	return (len);
135 }
136 
137 static int
138 cnv_from_u8(audio_stream_t *sp, int len)
139 {
140 	void *s = sp->s_cnv_src;
141 	void *d = sp->s_cnv_dst;
142 	uint8_t *src = s;
143 	int32_t *dst = d;
144 
145 	for (int i = len * sp->s_cnv_src_nchan; i; i--)
146 		*dst++ = (int8_t)((*src++) ^ 0x80) << 16;
147 
148 	sp->s_cnv_src = d;
149 	sp->s_cnv_dst = s;
150 	return (len);
151 }
152 
153 static int
154 cnv_from_ulaw(audio_stream_t *sp, int len)
155 {
156 	void *s = sp->s_cnv_src;
157 	void *d = sp->s_cnv_dst;
158 	uint8_t *src = s;
159 	int32_t *dst = d;
160 
161 	for (int i = len * sp->s_cnv_src_nchan; i; i--) {
162 		*dst++ = _8ulaw2linear16[(*src++)] << 8;
163 	}
164 	sp->s_cnv_src = d;
165 	sp->s_cnv_dst = s;
166 	return (len);
167 }
168 
169 static int
170 cnv_from_alaw(audio_stream_t *sp, int len)
171 {
172 	void *s = sp->s_cnv_src;
173 	void *d = sp->s_cnv_dst;
174 	uint8_t *src = s;
175 	int32_t *dst = d;
176 
177 	for (int i = len * sp->s_cnv_src_nchan; i; i--) {
178 		*dst++ = _8alaw2linear16[(*src++)] << 8;
179 	}
180 	sp->s_cnv_src = d;
181 	sp->s_cnv_dst = s;
182 	return (len);
183 }
184 
185 static int
186 cnv_from_s16ne(audio_stream_t *sp, int len)
187 {
188 	void *s = sp->s_cnv_src;
189 	void *d = sp->s_cnv_dst;
190 	int16_t *src = s;
191 	int32_t *dst = d;
192 
193 	for (int i = len * sp->s_cnv_src_nchan; i; i--)
194 		*dst++ = (*src++) << 8;
195 
196 	sp->s_cnv_src = d;
197 	sp->s_cnv_dst = s;
198 	return (len);
199 }
200 
201 static int
202 cnv_from_s16oe(audio_stream_t *sp, int len)
203 {
204 	void *s = sp->s_cnv_src;
205 	void *d = sp->s_cnv_dst;
206 	int16_t *src = s;
207 	int32_t *dst = d;
208 
209 	for (int i = len * sp->s_cnv_src_nchan; i; i--)
210 		*dst++ = (int16_t)(ddi_swap16(*src++)) << 8;
211 
212 	sp->s_cnv_src = d;
213 	sp->s_cnv_dst = s;
214 	return (len);
215 }
216 
217 static int
218 cnv_from_u16ne(audio_stream_t *sp, int len)
219 {
220 	void *s = sp->s_cnv_src;
221 	void *d = sp->s_cnv_dst;
222 	uint16_t *src = s;
223 	int32_t *dst = d;
224 
225 	for (int i = len * sp->s_cnv_src_nchan; i; i--)
226 		*dst++ = (int16_t)((*src++) ^ 0x8000) << 8;
227 
228 	sp->s_cnv_src = d;
229 	sp->s_cnv_dst = s;
230 	return (len);
231 }
232 
233 static int
234 cnv_from_u16oe(audio_stream_t *sp, int len)
235 {
236 	void *s = sp->s_cnv_src;
237 	void *d = sp->s_cnv_dst;
238 	uint16_t *src = s;
239 	int32_t *dst = d;
240 
241 	for (int i = len * sp->s_cnv_src_nchan; i; i--)
242 		*dst++ = (int16_t)(ddi_swap16((*src++) ^ 0x8000)) << 8;
243 
244 	sp->s_cnv_src = d;
245 	sp->s_cnv_dst = s;
246 	return (len);
247 }
248 
249 static int
250 cnv_from_s24p(audio_stream_t *sp, int len)
251 {
252 	void *s = sp->s_cnv_src;
253 	void *d = sp->s_cnv_dst;
254 	uint8_t *src = s;
255 	int32_t *dst = d;
256 	int32_t tmp;
257 
258 	for (int i = len * sp->s_cnv_src_nchan; i; i--) {
259 		/* NB: this is a little endian format */
260 		tmp = (*src++);
261 		tmp |= (*src++) << 8;
262 		tmp |= (*src++) << 16;
263 		*dst++ = tmp;
264 	}
265 
266 	sp->s_cnv_src = d;
267 	sp->s_cnv_dst = s;
268 	return (len);
269 }
270 
271 static int
272 cnv_from_s32ne(audio_stream_t *sp, int len)
273 {
274 	/* 32-bit conversions can be done in place */
275 	int32_t *src = sp->s_cnv_src;
276 
277 	for (int i = len * sp->s_cnv_src_nchan; i; i--, src++)
278 		*src = *src >> 8;
279 
280 	return (len);
281 }
282 
283 static int
284 cnv_from_s32oe(audio_stream_t *sp, int len)
285 {
286 	/* 32-bit conversions can be done in place */
287 	int32_t *src = sp->s_cnv_src;
288 
289 	for (int i = len * sp->s_cnv_src_nchan; i; i--, src++)
290 		*src = (int32_t)(ddi_swap32(*src)) >> 8;
291 
292 	return (len);
293 }
294 
295 /*
296  * NB: All the destination format conversions use the same or fewer
297  * bytes as the 24-bit unpacked (32-bits used per sample), so we can
298  * convert all of them in place.
299  */
300 
301 static int
302 cnv_to_u8(audio_stream_t *sp, int len)
303 {
304 	int32_t *src = sp->s_cnv_src;
305 	uint8_t *dst = (void *)src;
306 
307 	for (int i = len * sp->s_cnv_dst_nchan; i; i--)
308 		*dst++ = (*src++ >> 16) ^ 0x80;
309 
310 	return (len);
311 }
312 
313 static int
314 cnv_to_s8(audio_stream_t *sp, int len)
315 {
316 	int32_t *src = sp->s_cnv_src;
317 	int8_t *dst = (void *)src;
318 
319 	for (int i = len * sp->s_cnv_dst_nchan; i; i--)
320 		*dst++ = *src++ >> 16;
321 
322 	return (len);
323 }
324 
325 static int
326 cnv_to_ulaw(audio_stream_t *sp, int len)
327 {
328 	int32_t *src = sp->s_cnv_src;
329 	uint8_t *dst = (void *)src;
330 
331 	for (int i = len * sp->s_cnv_dst_nchan; i; i--) {
332 		int idx = *src++;
333 		idx >>= 10;
334 		idx += G711_ULAW_MIDPOINT;
335 		idx &= 0x3fff;	/* safety precaution */
336 		*dst++ = _14linear2ulaw8[idx];
337 	}
338 
339 	return (len);
340 }
341 
342 static int
343 cnv_to_alaw(audio_stream_t *sp, int len)
344 {
345 	int32_t *src = sp->s_cnv_src;
346 	uint8_t *dst = (void *)src;
347 
348 	for (int i = len * sp->s_cnv_dst_nchan; i; i--) {
349 		int idx = *src++;
350 		idx >>= 11;
351 		idx += G711_ALAW_MIDPOINT;
352 		idx &= 0x1fff;	/* safety precaution */
353 		*dst++ = _13linear2alaw8[idx];
354 	}
355 
356 	return (len);
357 }
358 
359 static int
360 cnv_to_s16ne(audio_stream_t *sp, int len)
361 {
362 	int32_t *src = sp->s_cnv_src;
363 	int16_t *dst = (void *)src;
364 
365 	for (int i = len * sp->s_cnv_dst_nchan; i; i--)
366 		*dst++ = *src++ >> 8;
367 
368 	return (len);
369 }
370 
371 static int
372 cnv_to_s16oe(audio_stream_t *sp, int len)
373 {
374 	int32_t *src = sp->s_cnv_src;
375 	int16_t *dst = (void *)src;
376 
377 	for (int i = len * sp->s_cnv_dst_nchan; i; i--)
378 		*dst++ = ddi_swap16(*src++ >> 8);
379 
380 	return (len);
381 }
382 
383 static int
384 cnv_to_u16ne(audio_stream_t *sp, int len)
385 {
386 	int32_t *src = sp->s_cnv_src;
387 	uint16_t *dst = (void *)src;
388 
389 	for (int i = len * sp->s_cnv_dst_nchan; i; i--)
390 		*dst++ = (*src++ >> 8) ^ 0x8000;
391 
392 	return (len);
393 }
394 
395 static int
396 cnv_to_u16oe(audio_stream_t *sp, int len)
397 {
398 	int32_t *src = sp->s_cnv_src;
399 	uint16_t *dst = (void *)src;
400 
401 	for (int i = len * sp->s_cnv_dst_nchan; i; i--)
402 		*dst++ = ddi_swap16(*src++ >> 8) ^ 0x8000;
403 
404 	return (len);
405 }
406 
407 static int
408 cnv_to_s24p(audio_stream_t *sp, int len)
409 {
410 	int32_t *src = sp->s_cnv_src;
411 	uint8_t *dst = (void *)src;
412 	int32_t d;
413 
414 	for (int i = len * sp->s_cnv_dst_nchan; i; i--) {
415 		/* NB: this is a little endian format */
416 		d = *src++;
417 		*dst++ = d & 0xff;
418 		*dst++ = (d >> 8) & 0xff;
419 		*dst++ = (d >> 16) & 0xff;
420 	}
421 
422 	return (len);
423 }
424 
425 static int
426 cnv_to_s32ne(audio_stream_t *sp, int len)
427 {
428 	int32_t *src = sp->s_cnv_src;
429 
430 	for (int i = len * sp->s_cnv_dst_nchan; i; i--, src++)
431 		*src = *src << 8;
432 
433 	return (len);
434 }
435 
436 static int
437 cnv_to_s32oe(audio_stream_t *sp, int len)
438 {
439 	int32_t *src = sp->s_cnv_src;
440 
441 	for (int i = len * sp->s_cnv_dst_nchan; i; i--, src++)
442 		*src = ddi_swap32(*src << 8);
443 
444 	return (len);
445 }
446 
447 static int
448 cnv_default(audio_stream_t *sp, int len)
449 {
450 	/*
451 	 * Note that the formats were already preverified during
452 	 * select_converter, to ensure that only supported formats are
453 	 * used.
454 	 */
455 
456 	/*
457 	 * Convert samples to 24 bit (32 bit lsb aligned) if
458 	 * necessary.
459 	 */
460 
461 	switch (sp->s_cnv_src_format) {
462 
463 	case AUDIO_FORMAT_U8:
464 		len = cnv_from_u8(sp, len);
465 		break;
466 
467 	case AUDIO_FORMAT_S8:
468 		len = cnv_from_s8(sp, len);
469 		break;
470 
471 	case AUDIO_FORMAT_ULAW:
472 		len = cnv_from_ulaw(sp, len);
473 		break;
474 
475 	case AUDIO_FORMAT_ALAW:
476 		len = cnv_from_alaw(sp, len);
477 		break;
478 
479 	case AUDIO_FORMAT_S16_NE:
480 		len = cnv_from_s16ne(sp, len);
481 		break;
482 
483 	case AUDIO_FORMAT_S16_OE:
484 		len = cnv_from_s16oe(sp, len);
485 		break;
486 
487 	case AUDIO_FORMAT_U16_NE:
488 		len = cnv_from_u16ne(sp, len);
489 		break;
490 
491 	case AUDIO_FORMAT_U16_OE:
492 		len = cnv_from_u16oe(sp, len);
493 		break;
494 
495 	case AUDIO_FORMAT_S32_NE:
496 		len = cnv_from_s32ne(sp, len);
497 		break;
498 
499 	case AUDIO_FORMAT_S32_OE:
500 		len = cnv_from_s32oe(sp, len);
501 		break;
502 
503 	case AUDIO_FORMAT_S24_OE:
504 		len = cnv_s24oe(sp, len);
505 		break;
506 
507 	case AUDIO_FORMAT_S24_PACKED:
508 		len = cnv_from_s24p(sp, len);
509 		break;
510 	}
511 
512 	/*
513 	 * If we aren't decreasing the number of channels, then do the
514 	 * SRC now.  (We prefer to do SRC on the smaller number of channels.)
515 	 */
516 	if (sp->s_cnv_src_rate != sp->s_cnv_dst_rate &&
517 	    sp->s_cnv_src_nchan <= sp->s_cnv_dst_nchan) {
518 		int32_t *src = sp->s_cnv_src;
519 		int32_t *dst = sp->s_cnv_dst;
520 
521 		len = do_src(sp, src, dst, len, sp->s_cnv_src_nchan);
522 
523 		sp->s_cnv_src = dst;
524 		sp->s_cnv_dst = src;
525 	}
526 
527 	/*
528 	 * Convert between mono and stereo
529 	 */
530 
531 	if (sp->s_cnv_src_nchan != sp->s_cnv_dst_nchan) {
532 		int32_t *src = sp->s_cnv_src;
533 		int32_t *dst = sp->s_cnv_dst;
534 		int tc = sp->s_cnv_dst_nchan;
535 		int sc = sp->s_cnv_src_nchan;
536 		int nc;
537 		int i;
538 
539 		sp->s_cnv_src = dst;
540 		sp->s_cnv_dst = src;
541 
542 		if (sc == 1) {
543 			/*
544 			 * Mono expansion.  We expand into the stereo
545 			 * channel, and leave other channels silent.
546 			 */
547 			for (i = len; i; i--) {
548 				*dst++ = *src;
549 				*dst++ = *src++;
550 				for (int j = tc - 2; j > 0; j--) {
551 					*dst++ = 0;
552 				}
553 
554 			}
555 
556 		} else if (sc == 2 && tc == 1) {
557 			/*
558 			 * Stereo -> mono.  We do stereo separately to make
559 			 * the division fast (div by const 2 is just shift).
560 			 */
561 			for (i = len; i; i--) {
562 				/*
563 				 * Take just the left channel sample,
564 				 * discard the right channel.
565 				 */
566 				*dst++ = *src++;	/* left */
567 				src++;			/* right */
568 			}
569 		} else {
570 			/*
571 			 * Multi channel conversions.  We just copy the
572 			 * minimum number of channels.
573 			 */
574 
575 			/* Calculate number of frames */
576 
577 			nc = min(sc, tc);
578 
579 			/* Clear destination */
580 			bzero(dst, (len * tc * sizeof (int32_t)));
581 
582 			for (i = len; i; i--) {
583 				int c;
584 
585 				for (c = 0; c < nc; c++)
586 					dst[c] = src[c];
587 
588 				src += sc;
589 				dst += tc;
590 			}
591 		}
592 	}
593 
594 	/*
595 	 * If we didn't do SRC pre-conversion, then do it now.
596 	 */
597 	if (sp->s_cnv_src_rate != sp->s_cnv_dst_rate &&
598 	    sp->s_cnv_src_nchan > sp->s_cnv_dst_nchan) {
599 
600 		int32_t *src = sp->s_cnv_src;
601 		int32_t *dst = sp->s_cnv_dst;
602 
603 		len = do_src(sp, src, dst, len, sp->s_cnv_dst_nchan);
604 
605 		sp->s_cnv_src = dst;
606 		sp->s_cnv_dst = src;
607 	}
608 
609 	/*
610 	 * Finally convert samples from internal 24 bit format to target format
611 	 */
612 
613 	switch (sp->s_cnv_dst_format) {
614 	case AUDIO_FORMAT_U8:
615 		len = cnv_to_u8(sp, len);
616 		break;
617 
618 	case AUDIO_FORMAT_S8:
619 		len = cnv_to_s8(sp, len);
620 		break;
621 
622 	case AUDIO_FORMAT_S16_NE:
623 		len = cnv_to_s16ne(sp, len);
624 		break;
625 
626 	case AUDIO_FORMAT_S16_OE:
627 		len = cnv_to_s16oe(sp, len);
628 		break;
629 
630 	case AUDIO_FORMAT_U16_NE:
631 		len = cnv_to_u16ne(sp, len);
632 		break;
633 
634 	case AUDIO_FORMAT_U16_OE:
635 		len = cnv_to_u16oe(sp, len);
636 		break;
637 
638 	case AUDIO_FORMAT_S24_OE:
639 		len = cnv_s24oe(sp, len);
640 		break;
641 
642 	case AUDIO_FORMAT_S24_PACKED:
643 		len = cnv_to_s24p(sp, len);
644 		break;
645 
646 	case AUDIO_FORMAT_S32_NE:
647 		len = cnv_to_s32ne(sp, len);
648 		break;
649 
650 	case AUDIO_FORMAT_S32_OE:
651 		len = cnv_to_s32oe(sp, len);
652 		break;
653 
654 	case AUDIO_FORMAT_ULAW:
655 		len = cnv_to_ulaw(sp, len);
656 		break;
657 
658 	case AUDIO_FORMAT_ALAW:
659 		len = cnv_to_alaw(sp, len);
660 		break;
661 	}
662 
663 	return (len);
664 }
665 
666 static const struct audio_format_info {
667 	unsigned		format;
668 	int			sampsize;
669 	audio_cnv_func_t	from;
670 	audio_cnv_func_t	to;
671 } audio_format_info[] = {
672 	{ AUDIO_FORMAT_S8,	1,	cnv_from_s8,		cnv_to_s8 },
673 	{ AUDIO_FORMAT_U8,	1,	cnv_from_u8,		cnv_to_u8 },
674 	{ AUDIO_FORMAT_ULAW,	1,	cnv_from_ulaw,		cnv_to_ulaw },
675 	{ AUDIO_FORMAT_ALAW,	1,	cnv_from_alaw,		cnv_to_alaw },
676 	{ AUDIO_FORMAT_S16_NE,	2,	cnv_from_s16ne,		cnv_to_s16ne },
677 	{ AUDIO_FORMAT_S16_OE,	2,	cnv_from_s16oe,		cnv_to_s16oe },
678 	{ AUDIO_FORMAT_U16_NE,	2,	cnv_from_u16ne,		cnv_to_u16ne },
679 	{ AUDIO_FORMAT_U16_OE,	2,	cnv_from_u16oe,		cnv_to_u16oe },
680 	{ AUDIO_FORMAT_S32_NE,	4,	cnv_from_s32ne,		cnv_to_s32ne },
681 	{ AUDIO_FORMAT_S32_OE,	4,	cnv_from_s32oe,		cnv_to_s32oe },
682 
683 	/* 24-bit formats are "special" */
684 	{ AUDIO_FORMAT_S24_NE,	4,	NULL,			NULL },
685 	{ AUDIO_FORMAT_S24_OE,	4,	cnv_s24oe,		cnv_s24oe },
686 	{ AUDIO_FORMAT_S24_PACKED, 3,	cnv_from_s24p,		cnv_to_s24p },
687 
688 	/* sentinel */
689 	{ AUDIO_FORMAT_NONE,	0,	NULL,			NULL }
690 };
691 
692 int
693 auimpl_format_setup(audio_stream_t *sp, audio_parms_t *parms, uint_t mask)
694 {
695 	audio_parms_t			source;
696 	audio_parms_t			target;
697 	audio_parms_t			*uparms;
698 	audio_cnv_func_t		converter = NULL;
699 	const struct audio_format_info	*info;
700 	int				expand = AUDIO_UNIT_EXPAND;
701 	unsigned			cnv_sampsz = sizeof (uint32_t);
702 	unsigned			cnv_max;
703 	boolean_t			needsrc = B_FALSE;
704 
705 	uint_t				framesz;
706 	uint_t				fragfr;
707 	uint_t				fragbytes;
708 	uint_t				nfrags;
709 
710 	ASSERT(mutex_owned(&sp->s_lock));
711 
712 	source = sp->s_cnv_src_parms;
713 	target = sp->s_cnv_dst_parms;
714 
715 	if (sp == &sp->s_client->c_ostream) {
716 		if (mask & FORMAT_MSK_FMT)
717 			source.p_format = parms->p_format;
718 		if (mask & FORMAT_MSK_RATE)
719 			source.p_rate = parms->p_rate;
720 		if (mask & FORMAT_MSK_CHAN)
721 			source.p_nchan = parms->p_nchan;
722 		uparms = &source;
723 	} else {
724 		if (mask & FORMAT_MSK_FMT)
725 			target.p_format = parms->p_format;
726 		if (mask & FORMAT_MSK_RATE)
727 			target.p_rate = parms->p_rate;
728 		if (mask & FORMAT_MSK_CHAN)
729 			target.p_nchan = parms->p_nchan;
730 		uparms = &target;
731 	}
732 
733 	/*
734 	 * At least one of the source or target are S24_NE.
735 	 *
736 	 * If we have a signed/native endian format, then pick an
737 	 * optimized converter.  While at it, ensure that a valid
738 	 * format is selected.
739 	 *
740 	 * After this function executes, "info" will point to the
741 	 * format information for the user parameters.
742 	 */
743 	if (source.p_format != AUDIO_FORMAT_S24_NE) {
744 		for (info = &audio_format_info[0]; info->sampsize; info++) {
745 			if (source.p_format == info->format) {
746 				converter = info->from;
747 				expand *= sizeof (int32_t);
748 				expand /= info->sampsize;
749 				/* save source frame size */
750 				cnv_sampsz = info->sampsize;
751 				break;
752 			}
753 		}
754 	} else {
755 		/*
756 		 * Target format.  Note that this case is also taken
757 		 * if we're operating on S24_NE data.  In that case
758 		 * the converter will be NULL and expand will not be
759 		 * altered.
760 		 */
761 		for (info = &audio_format_info[0]; info->sampsize; info++) {
762 			if (target.p_format == info->format) {
763 				converter = info->to;
764 				expand *= info->sampsize;
765 				expand /= sizeof (int32_t);
766 				break;
767 			}
768 		}
769 	}
770 	if (info->format == AUDIO_FORMAT_NONE) {
771 		audio_dev_warn(sp->s_client->c_dev, "invalid format selected");
772 		return (EINVAL);
773 	}
774 
775 
776 	ASSERT(info->sampsize);
777 
778 	if (source.p_nchan != target.p_nchan) {
779 		/*
780 		 * if channels need conversion, then we must use the
781 		 * default.
782 		 */
783 		converter = cnv_default;
784 		expand *= target.p_nchan;
785 		expand /= source.p_nchan;
786 	}
787 
788 	if (source.p_rate != target.p_rate) {
789 		needsrc = B_TRUE;
790 		converter = (converter == NULL) ? cnv_srconly : cnv_default;
791 
792 		expand *= target.p_rate;
793 		expand /= source.p_rate;
794 	}
795 
796 	/*
797 	 * Figure out the size of the conversion buffer we need.  We
798 	 * assume room for two full source fragments, which ought to
799 	 * be enough, even with rounding errors.
800 	 */
801 	cnv_max = 2 * (source.p_rate / audio_intrhz) *
802 	    cnv_sampsz * source.p_nchan;
803 
804 	/*
805 	 * If the conversion will cause us to expand fragments, then
806 	 * we need to increase cnv_max.  Scale by AUDIO_UNIT_EXPAND to
807 	 * avoid rouding errors or losing bits when doing reducing
808 	 * conversions.
809 	 */
810 	if (expand > AUDIO_UNIT_EXPAND) {
811 		cnv_max *= expand;
812 		cnv_max /= AUDIO_UNIT_EXPAND;
813 	}
814 
815 	framesz = info->sampsize * uparms->p_nchan;
816 	fragfr = (uparms->p_rate / audio_intrhz);
817 	fragbytes = fragfr * framesz;
818 
819 	/*
820 	 * We need to "tune" the buffer and fragment counts for some
821 	 * uses...  OSS applications may like to configure a low
822 	 * latency, and they rely upon write() to block to prevent too
823 	 * much data from being queued up.
824 	 */
825 	if (sp->s_hintsz) {
826 		nfrags = sp->s_hintsz / fragbytes;
827 	} else if (sp->s_hintfrags) {
828 		nfrags = sp->s_hintfrags;
829 	} else {
830 		nfrags = sp->s_allocsz / fragbytes;
831 	}
832 
833 	/*
834 	 * Now make sure that the hint works -- we need at least 2 fragments,
835 	 * and we need to fit within the room allocated to us.
836 	 */
837 	if (nfrags < 2) {
838 		nfrags = 2;
839 	}
840 	while ((nfrags * fragbytes) > sp->s_allocsz) {
841 		nfrags--;
842 	}
843 	/* if the resulting configuration is invalid, note it */
844 	if (nfrags < 2) {
845 		return (EINVAL);
846 	}
847 
848 	/*
849 	 * Now we need to allocate space.
850 	 *
851 	 * NB: Once the allocation succeeds, we must not fail.  We are
852 	 * modifying the the stream settings and these changes must be
853 	 * made atomically.
854 	 */
855 	if (sp->s_cnv_max < cnv_max) {
856 		uint32_t *buf0, *buf1;
857 
858 		buf0 = kmem_alloc(cnv_max, KM_NOSLEEP);
859 		buf1 = kmem_alloc(cnv_max, KM_NOSLEEP);
860 		if ((buf0 == NULL) || (buf1 == NULL)) {
861 			audio_dev_warn(sp->s_client->c_dev,
862 			    "failed to allocate audio conversion buffer "
863 			    "(%u bytes)", cnv_max);
864 			if (buf0)
865 				kmem_free(buf0, cnv_max);
866 			if (buf1)
867 				kmem_free(buf1, cnv_max);
868 			return (ENOMEM);
869 		}
870 
871 		if (sp->s_cnv_buf0)
872 			kmem_free(sp->s_cnv_buf0, sp->s_cnv_max);
873 		if (sp->s_cnv_buf1)
874 			kmem_free(sp->s_cnv_buf1, sp->s_cnv_max);
875 
876 		sp->s_cnv_buf0 = buf0;
877 		sp->s_cnv_buf1 = buf1;
878 		sp->s_cnv_max = cnv_max;
879 	}
880 
881 	/* Set up the SRC state if we will be using SRC. */
882 	if (needsrc) {
883 		setup_src(sp, source.p_rate, target.p_rate,
884 		    source.p_nchan, target.p_nchan);
885 	}
886 
887 
888 	sp->s_framesz = framesz;
889 	sp->s_fragfr = fragfr;
890 	sp->s_fragbytes = fragbytes;
891 	sp->s_nfrags = nfrags;
892 	sp->s_nframes = nfrags * fragfr;
893 	sp->s_nbytes = sp->s_nframes * framesz;
894 	*sp->s_user_parms = *uparms;
895 	sp->s_converter = converter;
896 
897 	/*
898 	 * Ensure that we toss any stale data -- probably wrong format.
899 	 * Note that as a consequence of this, all of the offsets and
900 	 * counters get reset.  Clients should not rely on these values
901 	 * being preserved when changing formats.
902 	 *
903 	 * Its critical that we reset the indices, in particular,
904 	 * because not only will the data be the wrong format, but the
905 	 * indices themselves are quite possibly going to be invalid.
906 	 */
907 	sp->s_cnv_cnt = 0;
908 	sp->s_tail = sp->s_head = 0;
909 	sp->s_tidx = sp->s_hidx = 0;
910 
911 	return (0);
912 }
913 
914 int
915 auimpl_format_alloc(audio_stream_t *sp)
916 {
917 	int	i;
918 
919 	ASSERT(mutex_owned(&sp->s_lock));
920 	for (i = 0; i < AUDIO_MAX_CHANNELS; i++) {
921 		sp->s_src_state[i] =
922 		    kmem_zalloc(sizeof (grc3state_t), KM_NOSLEEP);
923 		if (sp->s_src_state[i] == NULL) {
924 			audio_dev_warn(sp->s_client->c_dev,
925 			    "unable to allocate SRC state structures");
926 			return (ENOMEM);
927 		}
928 	}
929 	return (0);
930 }
931 
932 void
933 auimpl_format_free(audio_stream_t *sp)
934 {
935 	int	i;
936 
937 	for (i = 0; i < AUDIO_MAX_CHANNELS; i++) {
938 		if (sp->s_src_state[i] != NULL) {
939 			kmem_free(sp->s_src_state[i], sizeof (grc3state_t));
940 			sp->s_src_state[i] = NULL;
941 		}
942 	}
943 }
944