xref: /illumos-gate/usr/src/uts/common/io/audio/impl/audio_output.c (revision 68c47f65208790c466e5e484f2293d3baed71c6a)
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 2010 Sun Microsystems, Inc.  All rights reserved.
25  * Use is subject to license terms.
26  */
27 
28 /*
29  * Purpose: Virtual mixing audio output routines
30  *
31  * This file contains the actual mixing and resampling engine for output.
32  */
33 
34 #include <sys/ddi.h>
35 #include <sys/sunddi.h>
36 #include <sys/sysmacros.h>
37 #include "audio_impl.h"
38 
39 #define	DECL_AUDIO_EXPORT(NAME, TYPE, SAMPLE)				\
40 void									\
41 auimpl_export_##NAME(audio_engine_t *eng, uint_t nfr, uint_t froff)	\
42 {									\
43 	int		nch = eng->e_nchan;				\
44 	uint_t		hidx = eng->e_hidx;				\
45 	TYPE		*out = (void *)eng->e_data;			\
46 	int		ch = 0;						\
47 									\
48 	do {	/* for each channel */					\
49 		int32_t *ip;						\
50 		TYPE	*op;						\
51 		int	i;						\
52 		int	incr = eng->e_chincr[ch];			\
53 									\
54 		/* get value and adjust next channel offset */		\
55 		op = out + eng->e_choffs[ch] + (hidx * incr);		\
56 		ip = eng->e_chbufs[ch];					\
57 		ip += froff;						\
58 									\
59 		i = nfr;						\
60 									\
61 		do {	/* for each frame */				\
62 			int32_t sample = *ip;				\
63 									\
64 			*op = SAMPLE;					\
65 			op += incr;					\
66 			ip++;						\
67 									\
68 		} while (--i);						\
69 									\
70 		ch++;							\
71 	} while (ch < nch);						\
72 }
73 
74 DECL_AUDIO_EXPORT(16ne, int16_t, sample >> 8)
75 DECL_AUDIO_EXPORT(16oe, int16_t, ddi_swap16(sample >> 8))
76 DECL_AUDIO_EXPORT(32ne, int32_t, sample << 8)
77 DECL_AUDIO_EXPORT(32oe, int32_t, ddi_swap32(sample << 8))
78 DECL_AUDIO_EXPORT(24ne, int32_t, sample)
79 DECL_AUDIO_EXPORT(24oe, int32_t, ddi_swap32(sample))
80 
81 /*
82  * Simple limiter to prevent overflows when using fixed point computations
83  */
84 static void
85 auimpl_output_limiter(audio_engine_t *eng)
86 {
87 	int k, t;
88 	uint_t q, amp, amp2;
89 	int nchan = eng->e_nchan;
90 	uint_t fragfr = eng->e_fragfr;
91 	int32_t **chbufs = eng->e_chbufs;
92 	uint_t statevar = eng->e_limiter_state;
93 
94 	for (t = 0; t < fragfr; t++) {
95 
96 		amp = (uint_t)ABS(chbufs[0][t]);
97 
98 		for (k = 1; k < nchan; k++)	{
99 			amp2 = (uint_t)ABS(chbufs[k][t]);
100 			if (amp2 > amp)
101 				amp = amp2;
102 		}
103 
104 		amp >>= 8;
105 		q = 0x10000;
106 
107 		if (amp > 0x7FFF)
108 			q = 0x7FFF0000 / amp;
109 
110 		if (statevar > q) {
111 			statevar = q;
112 		} else {
113 			q = statevar;
114 
115 			/*
116 			 * Simplier (linear) tracking algo
117 			 * (gives less distortion, but more pumping)
118 			 */
119 			statevar += 2;
120 			if (statevar > 0x10000)
121 				statevar = 0x10000;
122 
123 			/*
124 			 * Classic tracking algo
125 			 * gives more distortion with no-lookahead
126 			 * statevar=0x10000-((0x10000-statevar)*0xFFF4>>16);
127 			 */
128 		}
129 
130 		for (k = 0; k < nchan; k++) {
131 			int32_t in = chbufs[k][t];
132 			int32_t out = 0;
133 			uint_t p;
134 
135 			if (in >= 0) {
136 				p = in;
137 				p = ((p & 0xFFFF) * (q >> 4) >> 12) +
138 				    (p >> 16) * q;
139 				out = p;
140 			} else {
141 				p = -in;
142 				p = ((p & 0xFFFF) * (q >> 4) >> 12) +
143 				    (p >> 16) * q;
144 				out = -p;
145 			}
146 			/* safety code */
147 			/*
148 			 * if output after limiter is clamped, then it
149 			 * can be dropped
150 			 */
151 			if (out > 0x7FFFFF)
152 				out = 0x7FFFFF;
153 			else if (out < -0x7FFFFF)
154 				out = -0x7FFFFF;
155 
156 			chbufs[k][t] = out;
157 		}
158 	}
159 
160 	eng->e_limiter_state = statevar;
161 }
162 
163 /*
164  * Output mixing function.  Assumption: all work is done in 24-bit native PCM.
165  */
166 static void
167 auimpl_output_mix(audio_stream_t *sp, int offset, int nfr)
168 {
169 	audio_engine_t *eng = sp->s_engine;
170 	const int32_t *src;
171 	int choffs;
172 	int nch;
173 	int vol;
174 
175 	/*
176 	 * Initial setup.
177 	 */
178 
179 	src = sp->s_cnv_ptr;
180 	choffs = sp->s_choffs;
181 	nch = sp->s_cnv_dst_nchan;
182 	vol = sp->s_gain_eff;
183 
184 	/*
185 	 * Do the mixing.  We de-interleave the source stream at the
186 	 * same time.
187 	 */
188 	for (int ch = 0; ch < nch; ch++) {
189 		int32_t *op;
190 		const int32_t *ip;
191 
192 
193 		ip = src + ch;
194 		op = eng->e_chbufs[ch + choffs];
195 		op += offset;
196 
197 		for (int i = nfr; i; i--) {
198 
199 			int64_t	samp;
200 
201 			samp = *ip;
202 			samp *= vol;
203 			samp /= AUDIO_VOL_SCALE;
204 
205 			ip += nch;
206 			*op += (int32_t)samp;
207 			op++;
208 		}
209 	}
210 
211 	sp->s_cnv_cnt -= nfr;
212 	sp->s_cnv_ptr += (nch * nfr);
213 }
214 
215 /*
216  * Consume a fragment's worth of data.  This is called when the data in
217  * the conversion buffer is exhausted, and we need to refill it from the
218  * source buffer.  We always consume data from the client in quantities of
219  * a fragment at a time (assuming that a fragment is available.)
220  */
221 static void
222 auimpl_consume_fragment(audio_stream_t *sp)
223 {
224 	uint_t	count;
225 	uint_t	avail;
226 	uint_t	nframes;
227 	uint_t	fragfr;
228 	uint_t	framesz;
229 	caddr_t	cnvbuf;
230 
231 	sp->s_cnv_src = sp->s_cnv_buf0;
232 	sp->s_cnv_dst = sp->s_cnv_buf1;
233 
234 	fragfr = sp->s_fragfr;
235 	nframes = sp->s_nframes;
236 	framesz = sp->s_framesz;
237 
238 	ASSERT(sp->s_head >= sp->s_tail);
239 
240 	avail = sp->s_head - sp->s_tail;
241 	cnvbuf = sp->s_cnv_src;
242 
243 	count = min(avail, fragfr);
244 
245 	/*
246 	 * Copy data.  We deal properly with wraps.  Done as a
247 	 * do...while to minimize the number of tests.
248 	 */
249 	do {
250 		uint_t n;
251 		uint_t nbytes;
252 
253 		n = min(nframes - sp->s_tidx, count);
254 		nbytes = framesz * n;
255 		bcopy(sp->s_data + (sp->s_tidx * framesz), cnvbuf, nbytes);
256 		cnvbuf += nbytes;
257 		count -= n;
258 		sp->s_samples += n;
259 		sp->s_tail += n;
260 		sp->s_tidx += n;
261 		if (sp->s_tidx >= nframes)
262 			sp->s_tidx -= nframes;
263 	} while (count);
264 
265 	/* Note: data conversion is optional! */
266 	count = min(avail, fragfr);
267 	if (sp->s_converter != NULL) {
268 		sp->s_cnv_cnt = sp->s_converter(sp, count);
269 	} else {
270 		sp->s_cnv_cnt = count;
271 	}
272 }
273 
274 static void
275 auimpl_output_callback_impl(audio_engine_t *eng, audio_client_t **output,
276     audio_client_t **drain)
277 {
278 	uint_t	fragfr = eng->e_fragfr;
279 	uint_t	resid;
280 
281 	/* clear any preexisting mix results */
282 	for (int i = 0; i < eng->e_nchan; i++)
283 		bzero(eng->e_chbufs[i], AUDIO_CHBUFS * sizeof (int32_t));
284 
285 	for (audio_stream_t *sp = list_head(&eng->e_streams);
286 	    sp != NULL;
287 	    sp = list_next(&eng->e_streams, sp)) {
288 
289 		int		need;
290 		int		avail;
291 		int		used;
292 		int		offset;
293 		boolean_t	drained = B_FALSE;
294 		audio_client_t	*c = sp->s_client;
295 
296 		/*
297 		 * We need/want a full fragment.  If the client has
298 		 * less than that available, it will cause a client
299 		 * underrun in auimpl_consume_fragment, but in such a
300 		 * case we should get silence bytes.  Assignments done
301 		 * ahead of the lock to minimize lock contention.
302 		 */
303 		need = fragfr;
304 		offset = 0;
305 
306 		mutex_enter(&sp->s_lock);
307 		/* skip over streams not running or paused */
308 		if ((!sp->s_running) || (sp->s_paused)) {
309 			mutex_exit(&sp->s_lock);
310 			continue;
311 		}
312 
313 		do {
314 			/* make sure we have data to chew on */
315 			if ((avail = sp->s_cnv_cnt) == 0) {
316 				auimpl_consume_fragment(sp);
317 				sp->s_cnv_ptr = sp->s_cnv_src;
318 				avail = sp->s_cnv_cnt;
319 			}
320 
321 			/*
322 			 * We might have got more data than we need
323 			 * right now.  (E.g. 8kHz expanding to 48kHz.)
324 			 * Take only what we need.
325 			 */
326 			used = min(avail, need);
327 
328 			/*
329 			 * Mix the results, as much data as we can use
330 			 * this round.
331 			 */
332 			auimpl_output_mix(sp, offset, used);
333 
334 			/*
335 			 * Save the offset for the next round, so we don't
336 			 * remix into the same location.
337 			 */
338 			offset += used;
339 
340 			/*
341 			 * Okay, we mixed some data, but it might not
342 			 * have been all we need.  This can happen
343 			 * either because we just mixed up some
344 			 * partial/residual data, or because the
345 			 * client has a fragment size which expands to
346 			 * less than a full fragment for us. (Such as
347 			 * a client wanting to operate at a higher
348 			 * data rate than the engine.)
349 			 */
350 			need -= used;
351 
352 		} while (need && avail);
353 
354 		if (avail == 0) {
355 			/* underrun or end of data */
356 			if (sp->s_draining) {
357 				if (sp->s_drain_idx == 0) {
358 					sp->s_drain_idx = eng->e_head;
359 				}
360 				if (eng->e_tail >= sp->s_drain_idx) {
361 					sp->s_drain_idx = 0;
362 					sp->s_draining = B_FALSE;
363 					/*
364 					 * After draining, stop the
365 					 * stream cleanly.  This
366 					 * prevents underrun errors.
367 					 *
368 					 * (Stream will auto-start if
369 					 * client submits more data to
370 					 * it.)
371 					 *
372 					 * AC3: When an AC3 stream
373 					 * drains we should probably
374 					 * stop the actual hardware
375 					 * engine.
376 					 */
377 					ASSERT(mutex_owned(&eng->e_lock));
378 					sp->s_running = B_FALSE;
379 					drained = B_TRUE;
380 				}
381 			} else {
382 				sp->s_errors += need;
383 				eng->e_stream_underruns++;
384 			}
385 		}
386 
387 		/* wake threads waiting for stream (blocking writes, etc.) */
388 		cv_broadcast(&sp->s_cv);
389 
390 		mutex_exit(&sp->s_lock);
391 
392 
393 		/*
394 		 * Asynchronously notify clients.  We do as much as
395 		 * possible of this outside of the lock, it avoids
396 		 * s_lock and c_lock contention and eliminates any
397 		 * chance of deadlock.
398 		 */
399 
400 		/*
401 		 * NB: The only lock we are holding now is the engine
402 		 * lock.  But the client can't go away because the
403 		 * closer would have to get the engine lock to remove
404 		 * the client's stream from engine.  So we're safe.
405 		 */
406 
407 		if (output && (c->c_output != NULL) &&
408 		    (c->c_next_output == NULL)) {
409 			auclnt_hold(c);
410 			c->c_next_output = *output;
411 			*output = c;
412 		}
413 
414 		if (drain && drained && (c->c_drain != NULL) &&
415 		    (c->c_next_drain == NULL)) {
416 			auclnt_hold(c);
417 			c->c_next_drain = *drain;
418 			*drain = c;
419 		}
420 	}
421 
422 	/*
423 	 * Deal with 24-bit overflows (from mixing) gracefully.
424 	 */
425 	auimpl_output_limiter(eng);
426 
427 	/*
428 	 * Export the data (a whole fragment) to the device.  Deal
429 	 * properly with wraps.  Note that the test and subtraction is
430 	 * faster for dealing with wrap than modulo.
431 	 */
432 	resid = fragfr;
433 	do {
434 		uint_t part = min(resid, eng->e_nframes - eng->e_hidx);
435 		eng->e_export(eng, part, fragfr - resid);
436 		eng->e_head += part;
437 		eng->e_hidx += part;
438 		if (eng->e_hidx == eng->e_nframes)
439 			eng->e_hidx = 0;
440 		resid -= part;
441 	} while (resid);
442 
443 	/*
444 	 * Consider doing the SYNC outside of the lock.
445 	 */
446 	ENG_SYNC(eng, fragfr);
447 }
448 
449 /*
450  * Outer loop attempts to keep playing until we hit maximum playahead.
451  */
452 
453 void
454 auimpl_output_callback(void *arg)
455 {
456 	audio_engine_t	*e = arg;
457 	int64_t		cnt;
458 	audio_client_t	*c;
459 	audio_client_t	*output = NULL;
460 	audio_client_t	*drain = NULL;
461 	uint64_t	t;
462 
463 	mutex_enter(&e->e_lock);
464 
465 	if (e->e_suspended || e->e_failed) {
466 		mutex_exit(&e->e_lock);
467 		return;
468 	}
469 
470 	if (e->e_need_start) {
471 		int rv;
472 		if ((rv = ENG_START(e)) != 0) {
473 			e->e_failed = B_TRUE;
474 			mutex_exit(&e->e_lock);
475 			audio_dev_warn(e->e_dev,
476 			    "failed starting output, rv = %d", rv);
477 			return;
478 		}
479 		e->e_need_start = B_FALSE;
480 	}
481 
482 	t = ENG_COUNT(e);
483 	if (t < e->e_tail) {
484 		/*
485 		 * This is a sign of a serious bug.  We should
486 		 * probably offline the device via FMA, if we ever
487 		 * support FMA for audio devices.
488 		 */
489 		e->e_failed = B_TRUE;
490 		ENG_STOP(e);
491 		mutex_exit(&e->e_lock);
492 		audio_dev_warn(e->e_dev,
493 		    "device malfunction: broken play back sample counter");
494 		return;
495 
496 	}
497 	e->e_tail = t;
498 
499 	if (e->e_tail > e->e_head) {
500 		/* want more than we have */
501 		e->e_errors++;
502 		e->e_underruns++;
503 	}
504 
505 	cnt = e->e_head - e->e_tail;
506 
507 	/* stay a bit ahead */
508 	while (cnt < e->e_playahead) {
509 		auimpl_output_callback_impl(e, &output, &drain);
510 		cnt = e->e_head - e->e_tail;
511 	}
512 	mutex_exit(&e->e_lock);
513 
514 	/*
515 	 * Notify client personalities.
516 	 */
517 	while ((c = output) != NULL) {
518 
519 		output = c->c_next_output;
520 		c->c_next_output = NULL;
521 		c->c_output(c);
522 		auclnt_release(c);
523 	}
524 
525 	while ((c = drain) != NULL) {
526 
527 		drain = c->c_next_drain;
528 		c->c_next_drain = NULL;
529 		c->c_drain(c);
530 		auclnt_release(c);
531 	}
532 
533 }
534 
535 void
536 auimpl_output_preload(audio_engine_t *e)
537 {
538 	int64_t	cnt;
539 
540 	ASSERT(mutex_owned(&e->e_lock));
541 
542 	if (e->e_tail > e->e_head) {
543 		/* want more than we have */
544 		e->e_errors++;
545 		e->e_underruns++;
546 		e->e_tail = e->e_head;
547 	}
548 	cnt = e->e_head - e->e_tail;
549 
550 	/* stay a bit ahead */
551 	while (cnt < e->e_playahead) {
552 		auimpl_output_callback_impl(e, NULL, NULL);
553 		cnt = e->e_head - e->e_tail;
554 	}
555 }
556