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 2009 Sun Microsystems, Inc. All rights reserved. 25 * Use is subject to license terms. 26 */ 27 28 /* 29 * Purpose: Virtual mixing audio input routines 30 * 31 * This file contains the actual mixing and resampling engine for input. 32 */ 33 34 #include <sys/ddi.h> 35 #include <sys/sunddi.h> 36 #include <sys/sysmacros.h> 37 #include "audio_impl.h" 38 39 #ifdef DEBUG 40 int audio_overruns = 0; 41 #endif 42 43 #define DECL_AUDIO_IMPORT(NAME, TYPE, SWAP, SHIFT) \ 44 void \ 45 auimpl_import_##NAME(audio_engine_t *eng, audio_stream_t *sp) \ 46 { \ 47 int nch = eng->e_nchan; \ 48 int32_t *out; \ 49 TYPE *in; \ 50 int ch; \ 51 void *data; \ 52 int vol; \ 53 \ 54 data = sp->s_cnv_src; \ 55 ch = 0; \ 56 in = (void *)(eng->e_data + (eng->e_tidx * eng->e_framesz)); \ 57 out = data; \ 58 vol = sp->s_gain_eff; \ 59 \ 60 do { /* for each channel */ \ 61 TYPE *ip; \ 62 int32_t *op; \ 63 int i; \ 64 \ 65 /* get value and adjust next channel offset */ \ 66 op = out++; \ 67 ip = in++; \ 68 \ 69 i = eng->e_fragfr; \ 70 \ 71 do { /* for each frame */ \ 72 int32_t sample = (TYPE)SWAP(*ip); \ 73 int32_t scaled = sample SHIFT; \ 74 \ 75 scaled *= vol; \ 76 scaled /= AUDIO_VOL_SCALE; \ 77 \ 78 *op = scaled; \ 79 ip += nch; \ 80 op += nch; \ 81 \ 82 } while (--i); \ 83 ch++; \ 84 } while (ch < nch); \ 85 } 86 87 DECL_AUDIO_IMPORT(16ne, int16_t, /* nop */, << 8) 88 DECL_AUDIO_IMPORT(16oe, int16_t, ddi_swap16, << 8) 89 DECL_AUDIO_IMPORT(32ne, int32_t, /* nop */, >> 8) 90 DECL_AUDIO_IMPORT(32oe, int32_t, ddi_swap32, >> 8) 91 DECL_AUDIO_IMPORT(24ne, int32_t, /* nop */, /* nop */) 92 DECL_AUDIO_IMPORT(24oe, int32_t, ddi_swap32, /* nop */) 93 94 /* 95 * Produce a fragment's worth of data. This is called when the data in 96 * the conversion buffer is exhausted, and we need to refill it from the 97 * source buffer. We always consume data from the client in quantities of 98 * a fragment at a time (assuming that a fragment is available.) 99 */ 100 static void 101 auimpl_produce_fragment(audio_stream_t *sp, unsigned count) 102 { 103 unsigned nframes; 104 unsigned framesz; 105 caddr_t cnvsrc; 106 caddr_t data; 107 108 nframes = sp->s_nframes; 109 framesz = sp->s_framesz; 110 111 ASSERT(sp->s_head >= sp->s_tail); 112 ASSERT(sp->s_hidx < nframes); 113 ASSERT(sp->s_tidx < nframes); 114 115 /* 116 * Copy data. We deal properly with wraps. Done as a 117 * do...while to minimize the number of tests. 118 */ 119 cnvsrc = sp->s_cnv_src; 120 data = sp->s_data + (sp->s_hidx * framesz); 121 do { 122 unsigned nf; 123 unsigned nb; 124 125 ASSERT(sp->s_hidx < nframes); 126 nf = min(nframes - sp->s_hidx, count); 127 nb = nf * framesz; 128 129 bcopy(cnvsrc, data, nb); 130 data += nb; 131 cnvsrc += nb; 132 sp->s_hidx += nf; 133 sp->s_head += nf; 134 count -= nf; 135 sp->s_samples += nf; 136 if (sp->s_hidx >= nframes) { 137 sp->s_hidx -= nframes; 138 data -= sp->s_nbytes; 139 } 140 } while (count); 141 142 ASSERT(sp->s_tail <= sp->s_head); 143 ASSERT(sp->s_hidx < nframes); 144 ASSERT(sp->s_tail <= sp->s_head); 145 ASSERT(sp->s_hidx < nframes); 146 } 147 148 void 149 auimpl_input_callback(audio_engine_t *eng) 150 { 151 int fragfr = eng->e_fragfr; 152 boolean_t overrun; 153 audio_client_t *c; 154 155 /* consume all fragments in the buffer */ 156 while ((eng->e_head - eng->e_tail) > fragfr) { 157 158 /* 159 * Consider doing the SYNC outside of the lock. 160 */ 161 ENG_SYNC(eng, fragfr); 162 163 for (audio_stream_t *sp = list_head(&eng->e_streams); 164 sp != NULL; 165 sp = list_next(&eng->e_streams, sp)) { 166 int space; 167 int count; 168 169 c = sp->s_client; 170 171 mutex_enter(&sp->s_lock); 172 /* skip over streams paused or not running */ 173 if (sp->s_paused || (!sp->s_running) || 174 eng->e_suspended) { 175 mutex_exit(&sp->s_lock); 176 continue; 177 } 178 sp->s_cnv_src = sp->s_cnv_buf0; 179 sp->s_cnv_dst = sp->s_cnv_buf1; 180 eng->e_import(eng, sp); 181 182 /* 183 * Optionally convert fragment to requested sample 184 * format and rate. 185 */ 186 if (sp->s_converter != NULL) { 187 count = sp->s_converter(sp, fragfr); 188 } else { 189 count = fragfr; 190 } 191 192 space = sp->s_nframes - (sp->s_head - sp->s_tail); 193 if (count > space) { 194 #ifdef DEBUG 195 audio_overruns++; 196 #endif 197 sp->s_errors += count - space; 198 count = space; 199 overrun = B_TRUE; 200 } else { 201 overrun = B_FALSE; 202 } 203 204 auimpl_produce_fragment(sp, count); 205 206 /* wake blocked threads (blocking reads, etc.) */ 207 cv_broadcast(&sp->s_cv); 208 209 mutex_exit(&sp->s_lock); 210 211 mutex_enter(&c->c_lock); 212 if (overrun) { 213 c->c_do_notify = B_TRUE; 214 } 215 c->c_do_input = B_TRUE; 216 cv_broadcast(&c->c_cv); 217 mutex_exit(&c->c_lock); 218 } 219 220 /* 221 * Update the tail pointer, and the data pointer. 222 */ 223 eng->e_tail += fragfr; 224 eng->e_tidx += fragfr; 225 if (eng->e_tidx >= eng->e_nframes) { 226 eng->e_tidx -= eng->e_nframes; 227 } 228 } 229 } 230