Home | History | Annotate | Download | only in pcm
      1 /*
      2  * \file pcm/pcm_plug.c
      3  * \ingroup PCM_Plugins
      4  * \brief PCM Route & Volume Plugin Interface
      5  * \author Abramo Bagnara <abramo (at) alsa-project.org>
      6  * \date 2000-2001
      7  */
      8 /*
      9  *  PCM - Plug
     10  *  Copyright (c) 2000 by Abramo Bagnara <abramo (at) alsa-project.org>
     11  *
     12  *
     13  *   This library is free software; you can redistribute it and/or modify
     14  *   it under the terms of the GNU Lesser General Public License as
     15  *   published by the Free Software Foundation; either version 2.1 of
     16  *   the License, or (at your option) any later version.
     17  *
     18  *   This program is distributed in the hope that it will be useful,
     19  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
     20  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     21  *   GNU Lesser General Public License for more details.
     22  *
     23  *   You should have received a copy of the GNU Lesser General Public
     24  *   License along with this library; if not, write to the Free Software
     25  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
     26  *
     27  */
     28 
     29 #include "pcm_local.h"
     30 #include "pcm_plugin.h"
     31 
     32 #ifndef PIC
     33 /* entry for static linking */
     34 const char *_snd_module_pcm_plug = "";
     35 #endif
     36 
     37 #ifndef DOC_HIDDEN
     38 
     39 enum snd_pcm_plug_route_policy {
     40 	PLUG_ROUTE_POLICY_NONE,
     41 	PLUG_ROUTE_POLICY_DEFAULT,
     42 	PLUG_ROUTE_POLICY_COPY,
     43 	PLUG_ROUTE_POLICY_AVERAGE,
     44 	PLUG_ROUTE_POLICY_DUP,
     45 };
     46 
     47 typedef struct {
     48 	snd_pcm_generic_t gen;
     49 	snd_pcm_t *req_slave;
     50 	snd_pcm_format_t sformat;
     51 	int schannels;
     52 	int srate;
     53 	const snd_config_t *rate_converter;
     54 	enum snd_pcm_plug_route_policy route_policy;
     55 	snd_pcm_route_ttable_entry_t *ttable;
     56 	int ttable_ok, ttable_last;
     57 	unsigned int tt_ssize, tt_cused, tt_sused;
     58 } snd_pcm_plug_t;
     59 
     60 #endif
     61 
     62 static int snd_pcm_plug_close(snd_pcm_t *pcm)
     63 {
     64 	snd_pcm_plug_t *plug = pcm->private_data;
     65 	int err, result = 0;
     66 	free(plug->ttable);
     67 	assert(plug->gen.slave == plug->req_slave);
     68 	if (plug->gen.close_slave) {
     69 		snd_pcm_unlink_hw_ptr(pcm, plug->req_slave);
     70 		snd_pcm_unlink_appl_ptr(pcm, plug->req_slave);
     71 		err = snd_pcm_close(plug->req_slave);
     72 		if (err < 0)
     73 			result = err;
     74 	}
     75 	free(plug);
     76 	return result;
     77 }
     78 
     79 static int snd_pcm_plug_info(snd_pcm_t *pcm, snd_pcm_info_t *info)
     80 {
     81 	snd_pcm_plug_t *plug = pcm->private_data;
     82 	snd_pcm_t *slave = plug->req_slave;
     83 	int err;
     84 
     85 	if ((err = snd_pcm_info(slave, info)) < 0)
     86 		return err;
     87 	return 0;
     88 }
     89 
     90 static const snd_pcm_format_t linear_preferred_formats[] = {
     91 #ifdef SND_LITTLE_ENDIAN
     92 	SND_PCM_FORMAT_S16_LE,
     93 	SND_PCM_FORMAT_U16_LE,
     94 	SND_PCM_FORMAT_S16_BE,
     95 	SND_PCM_FORMAT_U16_BE,
     96 #else
     97 	SND_PCM_FORMAT_S16_BE,
     98 	SND_PCM_FORMAT_U16_BE,
     99 	SND_PCM_FORMAT_S16_LE,
    100 	SND_PCM_FORMAT_U16_LE,
    101 #endif
    102 #ifdef SND_LITTLE_ENDIAN
    103 	SND_PCM_FORMAT_S32_LE,
    104 	SND_PCM_FORMAT_U32_LE,
    105 	SND_PCM_FORMAT_S32_BE,
    106 	SND_PCM_FORMAT_U32_BE,
    107 #else
    108 	SND_PCM_FORMAT_S32_BE,
    109 	SND_PCM_FORMAT_U32_BE,
    110 	SND_PCM_FORMAT_S32_LE,
    111 	SND_PCM_FORMAT_U32_LE,
    112 #endif
    113 	SND_PCM_FORMAT_S8,
    114 	SND_PCM_FORMAT_U8,
    115 #ifdef SND_LITTLE_ENDIAN
    116 	SND_PCM_FORMAT_FLOAT_LE,
    117 	SND_PCM_FORMAT_FLOAT64_LE,
    118 	SND_PCM_FORMAT_FLOAT_BE,
    119 	SND_PCM_FORMAT_FLOAT64_BE,
    120 #else
    121 	SND_PCM_FORMAT_FLOAT_BE,
    122 	SND_PCM_FORMAT_FLOAT64_BE,
    123 	SND_PCM_FORMAT_FLOAT_LE,
    124 	SND_PCM_FORMAT_FLOAT64_LE,
    125 #endif
    126 #ifdef SND_LITTLE_ENDIAN
    127 	SND_PCM_FORMAT_S24_LE,
    128 	SND_PCM_FORMAT_U24_LE,
    129 	SND_PCM_FORMAT_S24_BE,
    130 	SND_PCM_FORMAT_U24_BE,
    131 #else
    132 	SND_PCM_FORMAT_S24_BE,
    133 	SND_PCM_FORMAT_U24_BE,
    134 	SND_PCM_FORMAT_S24_LE,
    135 	SND_PCM_FORMAT_U24_LE,
    136 #endif
    137 #ifdef SND_LITTLE_ENDIAN
    138 	SND_PCM_FORMAT_S24_3LE,
    139 	SND_PCM_FORMAT_U24_3LE,
    140 	SND_PCM_FORMAT_S24_3BE,
    141 	SND_PCM_FORMAT_U24_3BE,
    142 #else
    143 	SND_PCM_FORMAT_S24_3BE,
    144 	SND_PCM_FORMAT_U24_3BE,
    145 	SND_PCM_FORMAT_S24_3LE,
    146 	SND_PCM_FORMAT_U24_3LE,
    147 #endif
    148 #ifdef SND_LITTLE_ENDIAN
    149 	SND_PCM_FORMAT_S20_3LE,
    150 	SND_PCM_FORMAT_U20_3LE,
    151 	SND_PCM_FORMAT_S20_3BE,
    152 	SND_PCM_FORMAT_U20_3BE,
    153 #else
    154 	SND_PCM_FORMAT_S20_3BE,
    155 	SND_PCM_FORMAT_U20_3BE,
    156 	SND_PCM_FORMAT_S20_3LE,
    157 	SND_PCM_FORMAT_U20_3LE,
    158 #endif
    159 #ifdef SND_LITTLE_ENDIAN
    160 	SND_PCM_FORMAT_S18_3LE,
    161 	SND_PCM_FORMAT_U18_3LE,
    162 	SND_PCM_FORMAT_S18_3BE,
    163 	SND_PCM_FORMAT_U18_3BE,
    164 #else
    165 	SND_PCM_FORMAT_S18_3BE,
    166 	SND_PCM_FORMAT_U18_3BE,
    167 	SND_PCM_FORMAT_S18_3LE,
    168 	SND_PCM_FORMAT_U18_3LE,
    169 #endif
    170 };
    171 
    172 #if defined(BUILD_PCM_PLUGIN_MULAW) || \
    173 	defined(BUILD_PCM_PLUGIN_ALAW) || \
    174 	defined(BUILD_PCM_PLUGIN_ADPCM)
    175 #define BUILD_PCM_NONLINEAR
    176 #endif
    177 
    178 #ifdef BUILD_PCM_NONLINEAR
    179 static const snd_pcm_format_t nonlinear_preferred_formats[] = {
    180 #ifdef BUILD_PCM_PLUGIN_MULAW
    181 	SND_PCM_FORMAT_MU_LAW,
    182 #endif
    183 #ifdef BUILD_PCM_PLUGIN_ALAW
    184 	SND_PCM_FORMAT_A_LAW,
    185 #endif
    186 #ifdef BUILD_PCM_PLUGIN_ADPCM
    187 	SND_PCM_FORMAT_IMA_ADPCM,
    188 #endif
    189 };
    190 #endif
    191 
    192 #ifdef BUILD_PCM_PLUGIN_LFLOAT
    193 static const snd_pcm_format_t float_preferred_formats[] = {
    194 #ifdef SND_LITTLE_ENDIAN
    195 	SND_PCM_FORMAT_FLOAT_LE,
    196 	SND_PCM_FORMAT_FLOAT64_LE,
    197 	SND_PCM_FORMAT_FLOAT_BE,
    198 	SND_PCM_FORMAT_FLOAT64_BE,
    199 #else
    200 	SND_PCM_FORMAT_FLOAT_BE,
    201 	SND_PCM_FORMAT_FLOAT64_BE,
    202 	SND_PCM_FORMAT_FLOAT_LE,
    203 	SND_PCM_FORMAT_FLOAT64_LE,
    204 #endif
    205 };
    206 #endif
    207 
    208 static const char linear_format_widths[32] = {
    209 	0, 0, 0, 0, 0, 0, 0, 1,
    210 	0, 0, 0, 0, 0, 0, 0, 1,
    211 	0, 1, 0, 1, 0, 0, 0, 1,
    212 	0, 0, 0, 0, 0, 0, 0, 1,
    213 };
    214 
    215 static int check_linear_format(const snd_pcm_format_mask_t *format_mask, int wid, int sgn, int ed)
    216 {
    217 	int e, s;
    218 	if (! linear_format_widths[wid - 1])
    219 		return SND_PCM_FORMAT_UNKNOWN;
    220 	for (e = 0; e < 2; e++) {
    221 		for (s = 0; s < 2; s++) {
    222 			int pw = ((wid + 7) / 8) * 8;
    223 			for (; pw <= 32; pw += 8) {
    224 				snd_pcm_format_t f;
    225 				f = snd_pcm_build_linear_format(wid, pw, sgn, ed);
    226 				if (f != SND_PCM_FORMAT_UNKNOWN &&
    227 				    snd_pcm_format_mask_test(format_mask, f))
    228 					return f;
    229 			}
    230 			sgn = !sgn;
    231 		}
    232 		ed = !ed;
    233 	}
    234 	return SND_PCM_FORMAT_UNKNOWN;
    235 }
    236 
    237 static snd_pcm_format_t snd_pcm_plug_slave_format(snd_pcm_format_t format, const snd_pcm_format_mask_t *format_mask)
    238 {
    239 	int w, w1, u, e;
    240 	snd_pcm_format_t f;
    241 	snd_pcm_format_mask_t lin = { SND_PCM_FMTBIT_LINEAR };
    242 	snd_pcm_format_mask_t fl = {
    243 #ifdef BUILD_PCM_PLUGIN_LFLOAT
    244 		SND_PCM_FMTBIT_FLOAT
    245 #else
    246 		{ 0 }
    247 #endif
    248 	};
    249 	if (snd_pcm_format_mask_test(format_mask, format))
    250 		return format;
    251 	if (!snd_pcm_format_mask_test(&lin, format) &&
    252 	    !snd_pcm_format_mask_test(&fl, format)) {
    253 		unsigned int i;
    254 		switch (format) {
    255 #ifdef BUILD_PCM_PLUGIN_MULAW
    256 		case SND_PCM_FORMAT_MU_LAW:
    257 #endif
    258 #ifdef BUILD_PCM_PLUGIN_ALAW
    259 		case SND_PCM_FORMAT_A_LAW:
    260 #endif
    261 #ifdef BUILD_PCM_PLUGIN_ADPCM
    262 		case SND_PCM_FORMAT_IMA_ADPCM:
    263 #endif
    264 			for (i = 0; i < sizeof(linear_preferred_formats) / sizeof(linear_preferred_formats[0]); ++i) {
    265 				snd_pcm_format_t f = linear_preferred_formats[i];
    266 				if (snd_pcm_format_mask_test(format_mask, f))
    267 					return f;
    268 			}
    269 			/* Fall through */
    270 		default:
    271 			return SND_PCM_FORMAT_UNKNOWN;
    272 		}
    273 
    274 	}
    275 	snd_mask_intersect(&lin, format_mask);
    276 	snd_mask_intersect(&fl, format_mask);
    277 	if (snd_mask_empty(&lin) && snd_mask_empty(&fl)) {
    278 #ifdef BUILD_PCM_NONLINEAR
    279 		unsigned int i;
    280 		for (i = 0; i < sizeof(nonlinear_preferred_formats) / sizeof(nonlinear_preferred_formats[0]); ++i) {
    281 			snd_pcm_format_t f = nonlinear_preferred_formats[i];
    282 			if (snd_pcm_format_mask_test(format_mask, f))
    283 				return f;
    284 		}
    285 #endif
    286 		return SND_PCM_FORMAT_UNKNOWN;
    287 	}
    288 #ifdef BUILD_PCM_PLUGIN_LFLOAT
    289 	if (snd_pcm_format_float(format)) {
    290 		if (snd_pcm_format_mask_test(&fl, format)) {
    291 			unsigned int i;
    292 			for (i = 0; i < sizeof(float_preferred_formats) / sizeof(float_preferred_formats[0]); ++i) {
    293 				snd_pcm_format_t f = float_preferred_formats[i];
    294 				if (snd_pcm_format_mask_test(format_mask, f))
    295 					return f;
    296 			}
    297 		}
    298 		w = 32;
    299 		u = 0;
    300 		e = snd_pcm_format_big_endian(format);
    301 	} else
    302 #endif
    303 	if (snd_mask_empty(&lin)) {
    304 #ifdef BUILD_PCM_PLUGIN_LFLOAT
    305 		unsigned int i;
    306 		for (i = 0; i < sizeof(float_preferred_formats) / sizeof(float_preferred_formats[0]); ++i) {
    307 			snd_pcm_format_t f = float_preferred_formats[i];
    308 			if (snd_pcm_format_mask_test(format_mask, f))
    309 				return f;
    310 		}
    311 #endif
    312 		return SND_PCM_FORMAT_UNKNOWN;
    313 	} else {
    314 		w = snd_pcm_format_width(format);
    315 		u = snd_pcm_format_unsigned(format);
    316 		e = snd_pcm_format_big_endian(format);
    317 	}
    318 	for (w1 = w; w1 <= 32; w1++) {
    319 		f = check_linear_format(format_mask, w1, u, e);
    320 		if (f != SND_PCM_FORMAT_UNKNOWN)
    321 			return f;
    322 	}
    323 	for (w1 = w - 1; w1 > 0; w1--) {
    324 		f = check_linear_format(format_mask, w1, u, e);
    325 		if (f != SND_PCM_FORMAT_UNKNOWN)
    326 			return f;
    327 	}
    328 	return SND_PCM_FORMAT_UNKNOWN;
    329 }
    330 
    331 static void snd_pcm_plug_clear(snd_pcm_t *pcm)
    332 {
    333 	snd_pcm_plug_t *plug = pcm->private_data;
    334 	snd_pcm_t *slave = plug->req_slave;
    335 	/* Clear old plugins */
    336 	if (plug->gen.slave != slave) {
    337 		snd_pcm_unlink_hw_ptr(pcm, plug->gen.slave);
    338 		snd_pcm_unlink_appl_ptr(pcm, plug->gen.slave);
    339 		snd_pcm_close(plug->gen.slave);
    340 		plug->gen.slave = slave;
    341 		pcm->fast_ops = slave->fast_ops;
    342 		pcm->fast_op_arg = slave->fast_op_arg;
    343 	}
    344 }
    345 
    346 #ifndef DOC_HIDDEN
    347 typedef struct {
    348 	snd_pcm_access_t access;
    349 	snd_pcm_format_t format;
    350 	unsigned int channels;
    351 	unsigned int rate;
    352 } snd_pcm_plug_params_t;
    353 #endif
    354 
    355 #ifdef BUILD_PCM_PLUGIN_RATE
    356 static int snd_pcm_plug_change_rate(snd_pcm_t *pcm, snd_pcm_t **new, snd_pcm_plug_params_t *clt, snd_pcm_plug_params_t *slv)
    357 {
    358 	snd_pcm_plug_t *plug = pcm->private_data;
    359 	int err;
    360 	if (clt->rate == slv->rate)
    361 		return 0;
    362 	assert(snd_pcm_format_linear(slv->format));
    363 	err = snd_pcm_rate_open(new, NULL, slv->format, slv->rate, plug->rate_converter,
    364 				plug->gen.slave, plug->gen.slave != plug->req_slave);
    365 	if (err < 0)
    366 		return err;
    367 	slv->access = clt->access;
    368 	slv->rate = clt->rate;
    369 	if (snd_pcm_format_linear(clt->format))
    370 		slv->format = clt->format;
    371 	return 1;
    372 }
    373 #endif
    374 
    375 #ifdef BUILD_PCM_PLUGIN_ROUTE
    376 static int snd_pcm_plug_change_channels(snd_pcm_t *pcm, snd_pcm_t **new, snd_pcm_plug_params_t *clt, snd_pcm_plug_params_t *slv)
    377 {
    378 	snd_pcm_plug_t *plug = pcm->private_data;
    379 	unsigned int tt_ssize, tt_cused, tt_sused;
    380 	snd_pcm_route_ttable_entry_t *ttable;
    381 	int err;
    382 	if (clt->channels == slv->channels &&
    383 	    (!plug->ttable || !plug->ttable_last))
    384 		return 0;
    385 	if (clt->rate != slv->rate &&
    386 	    clt->channels > slv->channels)
    387 		return 0;
    388 	assert(snd_pcm_format_linear(slv->format));
    389 	tt_ssize = slv->channels;
    390 	tt_cused = clt->channels;
    391 	tt_sused = slv->channels;
    392 	ttable = alloca(tt_cused * tt_sused * sizeof(*ttable));
    393 	if (plug->ttable) {	/* expand or shrink table */
    394 		unsigned int c = 0, s = 0;
    395 		for (c = 0; c < tt_cused; c++) {
    396 			for (s = 0; s < tt_sused; s++) {
    397 				snd_pcm_route_ttable_entry_t v;
    398 				if (c >= plug->tt_cused)
    399 					v = 0;
    400 				else if (s >= plug->tt_sused)
    401 					v = 0;
    402 				else
    403 					v = plug->ttable[c * plug->tt_ssize + s];
    404 				ttable[c * tt_ssize + s] = v;
    405 			}
    406 		}
    407 		plug->ttable_ok = 1;
    408 	} else {
    409 		unsigned int k;
    410 		unsigned int c = 0, s = 0;
    411 		enum snd_pcm_plug_route_policy rpolicy = plug->route_policy;
    412 		int n;
    413 		for (k = 0; k < tt_cused * tt_sused; ++k)
    414 			ttable[k] = 0;
    415 		if (rpolicy == PLUG_ROUTE_POLICY_DEFAULT) {
    416 			rpolicy = PLUG_ROUTE_POLICY_COPY;
    417 			/* it's hack for mono conversion */
    418 			if (clt->channels == 1 || slv->channels == 1)
    419 				rpolicy = PLUG_ROUTE_POLICY_AVERAGE;
    420 		}
    421 		switch (rpolicy) {
    422 		case PLUG_ROUTE_POLICY_AVERAGE:
    423 		case PLUG_ROUTE_POLICY_DUP:
    424 			if (clt->channels > slv->channels) {
    425 				n = clt->channels;
    426 			} else {
    427 				n = slv->channels;
    428 			}
    429 			while (n-- > 0) {
    430 				snd_pcm_route_ttable_entry_t v = SND_PCM_PLUGIN_ROUTE_FULL;
    431 				if (rpolicy == PLUG_ROUTE_POLICY_AVERAGE) {
    432 					if (pcm->stream == SND_PCM_STREAM_PLAYBACK &&
    433 					    clt->channels > slv->channels) {
    434 						int srcs = clt->channels / slv->channels;
    435 						if (s < clt->channels % slv->channels)
    436 							srcs++;
    437 						v /= srcs;
    438 					} else if (pcm->stream == SND_PCM_STREAM_CAPTURE &&
    439 						   slv->channels > clt->channels) {
    440 							int srcs = slv->channels / clt->channels;
    441 						if (s < slv->channels % clt->channels)
    442 							srcs++;
    443 						v /= srcs;
    444 					}
    445 				}
    446 				ttable[c * tt_ssize + s] = v;
    447 				if (++c == clt->channels)
    448 					c = 0;
    449 				if (++s == slv->channels)
    450 					s = 0;
    451 			}
    452 			break;
    453 		case PLUG_ROUTE_POLICY_COPY:
    454 			if (clt->channels < slv->channels) {
    455 				n = clt->channels;
    456 			} else {
    457 				n = slv->channels;
    458 			}
    459 			for (c = 0; (int)c < n; c++)
    460 				ttable[c * tt_ssize + c] = SND_PCM_PLUGIN_ROUTE_FULL;
    461 			break;
    462 		default:
    463 			SNDERR("Invalid route policy");
    464 			break;
    465 		}
    466 	}
    467 	err = snd_pcm_route_open(new, NULL, slv->format, (int) slv->channels, ttable, tt_ssize, tt_cused, tt_sused, plug->gen.slave, plug->gen.slave != plug->req_slave);
    468 	if (err < 0)
    469 		return err;
    470 	slv->channels = clt->channels;
    471 	slv->access = clt->access;
    472 	if (snd_pcm_format_linear(clt->format))
    473 		slv->format = clt->format;
    474 	return 1;
    475 }
    476 #endif
    477 
    478 static int snd_pcm_plug_change_format(snd_pcm_t *pcm, snd_pcm_t **new, snd_pcm_plug_params_t *clt, snd_pcm_plug_params_t *slv)
    479 {
    480 	snd_pcm_plug_t *plug = pcm->private_data;
    481 	int err;
    482 	snd_pcm_format_t cfmt;
    483 	int (*f)(snd_pcm_t **_pcm, const char *name, snd_pcm_format_t sformat, snd_pcm_t *slave, int close_slave);
    484 
    485 	/* No conversion is needed */
    486 	if (clt->format == slv->format &&
    487 	    clt->rate == slv->rate &&
    488 	    clt->channels == clt->channels)
    489 		return 0;
    490 
    491 	if (snd_pcm_format_linear(slv->format)) {
    492 		/* Conversion is done in another plugin */
    493 		if (clt->rate != slv->rate ||
    494 		    clt->channels != slv->channels)
    495 			return 0;
    496 		cfmt = clt->format;
    497 		switch (clt->format) {
    498 #ifdef BUILD_PCM_PLUGIN_MULAW
    499 		case SND_PCM_FORMAT_MU_LAW:
    500 			f = snd_pcm_mulaw_open;
    501 			break;
    502 #endif
    503 #ifdef BUILD_PCM_PLUGIN_ALAW
    504 		case SND_PCM_FORMAT_A_LAW:
    505 			f = snd_pcm_alaw_open;
    506 			break;
    507 #endif
    508 #ifdef BUILD_PCM_PLUGIN_ADPCM
    509 		case SND_PCM_FORMAT_IMA_ADPCM:
    510 			f = snd_pcm_adpcm_open;
    511 			break;
    512 #endif
    513 		default:
    514 #ifdef BUILD_PCM_PLUGIN_LFLOAT
    515 			if (snd_pcm_format_float(clt->format))
    516 				f = snd_pcm_lfloat_open;
    517 
    518 			else
    519 #endif
    520 				f = snd_pcm_linear_open;
    521 			break;
    522 		}
    523 #ifdef BUILD_PCM_PLUGIN_LFLOAT
    524 	} else if (snd_pcm_format_float(slv->format)) {
    525 		/* Conversion is done in another plugin */
    526 		if (clt->format == slv->format &&
    527 		    clt->rate == slv->rate &&
    528 		    clt->channels == slv->channels)
    529 			return 0;
    530 		cfmt = clt->format;
    531 		if (snd_pcm_format_linear(clt->format))
    532 			f = snd_pcm_lfloat_open;
    533 		else
    534 			return -EINVAL;
    535 #endif
    536 #ifdef BUILD_PCM_NONLINEAR
    537 	} else {
    538 		switch (slv->format) {
    539 #ifdef BUILD_PCM_PLUGIN_MULAW
    540 		case SND_PCM_FORMAT_MU_LAW:
    541 			f = snd_pcm_mulaw_open;
    542 			break;
    543 #endif
    544 #ifdef BUILD_PCM_PLUGIN_ALAW
    545 		case SND_PCM_FORMAT_A_LAW:
    546 			f = snd_pcm_alaw_open;
    547 			break;
    548 #endif
    549 #ifdef BUILD_PCM_PLUGIN_ADPCM
    550 		case SND_PCM_FORMAT_IMA_ADPCM:
    551 			f = snd_pcm_adpcm_open;
    552 			break;
    553 #endif
    554 		default:
    555 			return -EINVAL;
    556 		}
    557 		if (snd_pcm_format_linear(clt->format))
    558 			cfmt = clt->format;
    559 		else
    560 			cfmt = SND_PCM_FORMAT_S16;
    561 #endif /* NONLINEAR */
    562 	}
    563 	err = f(new, NULL, slv->format, plug->gen.slave, plug->gen.slave != plug->req_slave);
    564 	if (err < 0)
    565 		return err;
    566 	slv->format = cfmt;
    567 	slv->access = clt->access;
    568 	return 1;
    569 }
    570 
    571 static int snd_pcm_plug_change_access(snd_pcm_t *pcm, snd_pcm_t **new, snd_pcm_plug_params_t *clt, snd_pcm_plug_params_t *slv)
    572 {
    573 	snd_pcm_plug_t *plug = pcm->private_data;
    574 	int err;
    575 	if (clt->access == slv->access)
    576 		return 0;
    577 	err = snd_pcm_copy_open(new, NULL, plug->gen.slave, plug->gen.slave != plug->req_slave);
    578 	if (err < 0)
    579 		return err;
    580 	slv->access = clt->access;
    581 	return 1;
    582 }
    583 
    584 #ifdef BUILD_PCM_PLUGIN_MMAP_EMUL
    585 static int snd_pcm_plug_change_mmap(snd_pcm_t *pcm, snd_pcm_t **new,
    586 				    snd_pcm_plug_params_t *clt,
    587 				    snd_pcm_plug_params_t *slv)
    588 {
    589 	snd_pcm_plug_t *plug = pcm->private_data;
    590 	int err;
    591 
    592 	if (clt->access == slv->access)
    593 		return 0;
    594 
    595 	switch (slv->access) {
    596 	case SND_PCM_ACCESS_MMAP_INTERLEAVED:
    597 	case SND_PCM_ACCESS_MMAP_NONINTERLEAVED:
    598 	case SND_PCM_ACCESS_MMAP_COMPLEX:
    599 		return 0;
    600 	default:
    601 		break;
    602 	}
    603 
    604 	err = __snd_pcm_mmap_emul_open(new, NULL, plug->gen.slave,
    605 				       plug->gen.slave != plug->req_slave);
    606 	if (err < 0)
    607 		return err;
    608 	slv->access = clt->access;
    609 	return 1;
    610 }
    611 #endif
    612 
    613 static int snd_pcm_plug_insert_plugins(snd_pcm_t *pcm,
    614 				       snd_pcm_plug_params_t *client,
    615 				       snd_pcm_plug_params_t *slave)
    616 {
    617 	snd_pcm_plug_t *plug = pcm->private_data;
    618 	static int (*const funcs[])(snd_pcm_t *_pcm, snd_pcm_t **new, snd_pcm_plug_params_t *s, snd_pcm_plug_params_t *d) = {
    619 #ifdef BUILD_PCM_PLUGIN_MMAP_EMUL
    620 		snd_pcm_plug_change_mmap,
    621 #endif
    622 		snd_pcm_plug_change_format,
    623 #ifdef BUILD_PCM_PLUGIN_ROUTE
    624 		snd_pcm_plug_change_channels,
    625 #endif
    626 #ifdef BUILD_PCM_PLUGIN_RATE
    627 		snd_pcm_plug_change_rate,
    628 #endif
    629 #ifdef BUILD_PCM_PLUGIN_ROUTE
    630 		snd_pcm_plug_change_channels,
    631 #endif
    632 		snd_pcm_plug_change_format,
    633 		snd_pcm_plug_change_access
    634 	};
    635 	snd_pcm_plug_params_t p = *slave;
    636 	unsigned int k = 0;
    637 	plug->ttable_ok = plug->ttable_last = 0;
    638 	while (client->format != p.format ||
    639 	       client->channels != p.channels ||
    640 	       client->rate != p.rate ||
    641 	       client->access != p.access) {
    642 		snd_pcm_t *new;
    643 		int err;
    644 		if (k >= sizeof(funcs)/sizeof(*funcs))
    645 			return -EINVAL;
    646 		err = funcs[k](pcm, &new, client, &p);
    647 		if (err < 0) {
    648 			snd_pcm_plug_clear(pcm);
    649 			return err;
    650 		}
    651 		if (err) {
    652 			plug->gen.slave = new;
    653 			pcm->fast_ops = new->fast_ops;
    654 			pcm->fast_op_arg = new->fast_op_arg;
    655 		}
    656 		k++;
    657 	}
    658 #ifdef BUILD_PCM_PLUGIN_ROUTE
    659 	/* it's exception, user specified ttable, but no reduction/expand */
    660 	if (plug->ttable && !plug->ttable_ok) {
    661 		snd_pcm_t *new;
    662 		int err;
    663 		plug->ttable_last = 1;
    664 		err = snd_pcm_plug_change_channels(pcm, &new, client, &p);
    665 		if (err < 0) {
    666 			snd_pcm_plug_clear(pcm);
    667 			return err;
    668 		}
    669 		assert(err);
    670 		assert(plug->ttable_ok);
    671 		plug->gen.slave = new;
    672 		pcm->fast_ops = new->fast_ops;
    673 		pcm->fast_op_arg = new->fast_op_arg;
    674 	}
    675 #endif
    676 	return 0;
    677 }
    678 
    679 static int snd_pcm_plug_hw_refine_cprepare(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params)
    680 {
    681 	unsigned int rate_min, channels_max;
    682 	int err;
    683 
    684 	/* HACK: to avoid overflow in PARTBIT_RATE code */
    685 	err = snd_pcm_hw_param_get_min(params, SND_PCM_HW_PARAM_RATE, &rate_min, NULL);
    686 	if (err < 0)
    687 		return err;
    688 	if (rate_min < 4000) {
    689 		_snd_pcm_hw_param_set_min(params, SND_PCM_HW_PARAM_RATE, 4000, 0);
    690 		if (snd_pcm_hw_param_empty(params, SND_PCM_HW_PARAM_RATE))
    691 			return -EINVAL;
    692 	}
    693 	/* HACK: to avoid overflow in PERIOD_SIZE code */
    694 	err = snd_pcm_hw_param_get_max(params, SND_PCM_HW_PARAM_CHANNELS, &channels_max, NULL);
    695 	if (err < 0)
    696 		return err;
    697 	if (channels_max > 10000) {
    698 		_snd_pcm_hw_param_set_max(params, SND_PCM_HW_PARAM_CHANNELS, 10000, 0);
    699 		if (snd_pcm_hw_param_empty(params, SND_PCM_HW_PARAM_CHANNELS))
    700 			return -EINVAL;
    701 	}
    702 	return 0;
    703 }
    704 
    705 static int snd_pcm_plug_hw_refine_sprepare(snd_pcm_t *pcm, snd_pcm_hw_params_t *sparams)
    706 {
    707 	snd_pcm_plug_t *plug = pcm->private_data;
    708 	int err;
    709 
    710 	_snd_pcm_hw_params_any(sparams);
    711 	if (plug->sformat >= 0) {
    712 		_snd_pcm_hw_params_set_format(sparams, plug->sformat);
    713 		_snd_pcm_hw_params_set_subformat(sparams, SND_PCM_SUBFORMAT_STD);
    714 	}
    715 	if (plug->schannels > 0)
    716 		_snd_pcm_hw_param_set(sparams, SND_PCM_HW_PARAM_CHANNELS,
    717 				      plug->schannels, 0);
    718 	if (plug->srate > 0)
    719 		_snd_pcm_hw_param_set_minmax(sparams, SND_PCM_HW_PARAM_RATE,
    720 					      plug->srate, 0, plug->srate + 1, -1);
    721 	/* reduce the available configurations */
    722 	err = snd_pcm_hw_refine(plug->req_slave, sparams);
    723 	if (err < 0)
    724 		return err;
    725 	return 0;
    726 }
    727 
    728 static int check_access_change(snd_pcm_hw_params_t *cparams,
    729 			       snd_pcm_hw_params_t *sparams)
    730 {
    731 	snd_pcm_access_mask_t *smask;
    732 #ifdef BUILD_PCM_PLUGIN_MMAP_EMUL
    733 	const snd_pcm_access_mask_t *cmask;
    734 	snd_pcm_access_mask_t mask;
    735 #endif
    736 
    737 	smask = (snd_pcm_access_mask_t *)
    738 		snd_pcm_hw_param_get_mask(sparams,
    739 					  SND_PCM_HW_PARAM_ACCESS);
    740 	if (snd_pcm_access_mask_test(smask, SND_PCM_ACCESS_MMAP_INTERLEAVED) ||
    741 	    snd_pcm_access_mask_test(smask, SND_PCM_ACCESS_MMAP_NONINTERLEAVED) ||
    742 	    snd_pcm_access_mask_test(smask, SND_PCM_ACCESS_MMAP_COMPLEX))
    743 		return 0; /* OK, we have mmap support */
    744 #ifdef BUILD_PCM_PLUGIN_MMAP_EMUL
    745 	/* no mmap support - we need mmap emulation */
    746 	cmask = (const snd_pcm_access_mask_t *)
    747 		snd_pcm_hw_param_get_mask(cparams,
    748 					  SND_PCM_HW_PARAM_ACCESS);
    749 	snd_mask_none(&mask);
    750 	if (snd_pcm_access_mask_test(cmask, SND_PCM_ACCESS_RW_INTERLEAVED) ||
    751 	    snd_pcm_access_mask_test(cmask, SND_PCM_ACCESS_MMAP_INTERLEAVED))
    752 		snd_pcm_access_mask_set(&mask,
    753 					SND_PCM_ACCESS_RW_INTERLEAVED);
    754 	if (snd_pcm_access_mask_test(cmask, SND_PCM_ACCESS_RW_NONINTERLEAVED) ||
    755 	    snd_pcm_access_mask_test(cmask, SND_PCM_ACCESS_MMAP_NONINTERLEAVED))
    756 		snd_pcm_access_mask_set(&mask,
    757 					SND_PCM_ACCESS_RW_NONINTERLEAVED);
    758 	*smask = mask;
    759 	return 0;
    760 #else
    761 	return -EINVAL;
    762 #endif
    763 }
    764 
    765 static int snd_pcm_plug_hw_refine_schange(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
    766 					  snd_pcm_hw_params_t *sparams)
    767 {
    768 	snd_pcm_plug_t *plug = pcm->private_data;
    769 	snd_pcm_t *slave = plug->req_slave;
    770 	unsigned int links = (SND_PCM_HW_PARBIT_PERIOD_TIME |
    771 			      SND_PCM_HW_PARBIT_TICK_TIME);
    772 	const snd_pcm_format_mask_t *format_mask, *sformat_mask;
    773 	snd_pcm_format_mask_t sfmt_mask;
    774 	int err;
    775 	snd_pcm_format_t format;
    776 	snd_interval_t t, buffer_size;
    777 	const snd_interval_t *srate, *crate;
    778 
    779 	if (plug->srate == -2 ||
    780 	    (pcm->mode & SND_PCM_NO_AUTO_RESAMPLE) ||
    781 	    (params->flags & SND_PCM_HW_PARAMS_NORESAMPLE))
    782 		links |= SND_PCM_HW_PARBIT_RATE;
    783 	else {
    784 		err = snd_pcm_hw_param_refine_multiple(slave, sparams, SND_PCM_HW_PARAM_RATE, params);
    785 		if (err < 0)
    786 			return err;
    787 	}
    788 
    789 	if (plug->schannels == -2 || (pcm->mode & SND_PCM_NO_AUTO_CHANNELS))
    790 		links |= SND_PCM_HW_PARBIT_CHANNELS;
    791 	else {
    792 		err = snd_pcm_hw_param_refine_near(slave, sparams, SND_PCM_HW_PARAM_CHANNELS, params);
    793 		if (err < 0)
    794 			return err;
    795 	}
    796 	if (plug->sformat == -2 || (pcm->mode & SND_PCM_NO_AUTO_FORMAT))
    797 		links |= SND_PCM_HW_PARBIT_FORMAT;
    798 	else {
    799 		format_mask = snd_pcm_hw_param_get_mask(params, SND_PCM_HW_PARAM_FORMAT);
    800 		sformat_mask = snd_pcm_hw_param_get_mask(sparams, SND_PCM_HW_PARAM_FORMAT);
    801 		snd_mask_none(&sfmt_mask);
    802 		for (format = 0; format <= SND_PCM_FORMAT_LAST; format++) {
    803 			snd_pcm_format_t f;
    804 			if (!snd_pcm_format_mask_test(format_mask, format))
    805 				continue;
    806 			if (snd_pcm_format_mask_test(sformat_mask, format))
    807 				f = format;
    808 			else {
    809 				f = snd_pcm_plug_slave_format(format, sformat_mask);
    810 				if (f == SND_PCM_FORMAT_UNKNOWN)
    811 					continue;
    812 			}
    813 			snd_pcm_format_mask_set(&sfmt_mask, f);
    814 		}
    815 
    816 		if (snd_pcm_format_mask_empty(&sfmt_mask)) {
    817 			SNDERR("Unable to find an usable slave format for '%s'", pcm->name);
    818 			for (format = 0; format <= SND_PCM_FORMAT_LAST; format++) {
    819 				if (!snd_pcm_format_mask_test(format_mask, format))
    820 					continue;
    821 				SNDERR("Format: %s", snd_pcm_format_name(format));
    822 			}
    823 			for (format = 0; format <= SND_PCM_FORMAT_LAST; format++) {
    824 				if (!snd_pcm_format_mask_test(sformat_mask, format))
    825 					continue;
    826 				SNDERR("Slave format: %s", snd_pcm_format_name(format));
    827 			}
    828 			return -EINVAL;
    829 		}
    830 		err = snd_pcm_hw_param_set_mask(slave, sparams, SND_CHANGE,
    831 						SND_PCM_HW_PARAM_FORMAT, &sfmt_mask);
    832 		if (err < 0)
    833 			return -EINVAL;
    834 	}
    835 
    836 	if (snd_pcm_hw_param_never_eq(params, SND_PCM_HW_PARAM_ACCESS, sparams)) {
    837 		err = check_access_change(params, sparams);
    838 		if (err < 0) {
    839 			SNDERR("Unable to find an usable access for '%s'",
    840 			       pcm->name);
    841 			return err;
    842 		}
    843 	}
    844 
    845 	if ((links & SND_PCM_HW_PARBIT_RATE) ||
    846 	    snd_pcm_hw_param_always_eq(params, SND_PCM_HW_PARAM_RATE, sparams))
    847 		links |= (SND_PCM_HW_PARBIT_PERIOD_SIZE |
    848 			  SND_PCM_HW_PARBIT_BUFFER_SIZE);
    849 	else {
    850 		snd_interval_copy(&buffer_size, snd_pcm_hw_param_get_interval(params, SND_PCM_HW_PARAM_BUFFER_SIZE));
    851 		snd_interval_unfloor(&buffer_size);
    852 		crate = snd_pcm_hw_param_get_interval(params, SND_PCM_HW_PARAM_RATE);
    853 		srate = snd_pcm_hw_param_get_interval(sparams, SND_PCM_HW_PARAM_RATE);
    854 		snd_interval_muldiv(&buffer_size, srate, crate, &t);
    855 		err = _snd_pcm_hw_param_set_interval(sparams, SND_PCM_HW_PARAM_BUFFER_SIZE, &t);
    856 		if (err < 0)
    857 			return err;
    858 	}
    859 	err = _snd_pcm_hw_params_refine(sparams, links, params);
    860 	if (err < 0)
    861 		return err;
    862 	return 0;
    863 }
    864 
    865 static int snd_pcm_plug_hw_refine_cchange(snd_pcm_t *pcm ATTRIBUTE_UNUSED,
    866 					  snd_pcm_hw_params_t *params,
    867 					  snd_pcm_hw_params_t *sparams)
    868 {
    869 	snd_pcm_plug_t *plug = pcm->private_data;
    870 	unsigned int links = (SND_PCM_HW_PARBIT_PERIOD_TIME |
    871 			      SND_PCM_HW_PARBIT_TICK_TIME);
    872 	const snd_pcm_format_mask_t *format_mask, *sformat_mask;
    873 	snd_pcm_format_mask_t fmt_mask;
    874 	int err;
    875 	snd_pcm_format_t format;
    876 	snd_interval_t t;
    877 	const snd_interval_t *sbuffer_size;
    878 	const snd_interval_t *srate, *crate;
    879 
    880 	if (plug->schannels == -2 || (pcm->mode & SND_PCM_NO_AUTO_CHANNELS))
    881 		links |= SND_PCM_HW_PARBIT_CHANNELS;
    882 
    883 	if (plug->sformat == -2 || (pcm->mode & SND_PCM_NO_AUTO_FORMAT))
    884 		links |= SND_PCM_HW_PARBIT_FORMAT;
    885 	else {
    886 		format_mask = snd_pcm_hw_param_get_mask(params,
    887 							SND_PCM_HW_PARAM_FORMAT);
    888 		sformat_mask = snd_pcm_hw_param_get_mask(sparams,
    889 							 SND_PCM_HW_PARAM_FORMAT);
    890 		snd_mask_none(&fmt_mask);
    891 		for (format = 0; format <= SND_PCM_FORMAT_LAST; format++) {
    892 			snd_pcm_format_t f;
    893 			if (!snd_pcm_format_mask_test(format_mask, format))
    894 				continue;
    895 			if (snd_pcm_format_mask_test(sformat_mask, format))
    896 				f = format;
    897 			else {
    898 				f = snd_pcm_plug_slave_format(format, sformat_mask);
    899 				if (f == SND_PCM_FORMAT_UNKNOWN)
    900 					continue;
    901 			}
    902 			snd_pcm_format_mask_set(&fmt_mask, format);
    903 		}
    904 
    905 		if (snd_pcm_format_mask_empty(&fmt_mask)) {
    906 			SNDERR("Unable to find an usable client format");
    907 			for (format = 0; format <= SND_PCM_FORMAT_LAST; format++) {
    908 				if (!snd_pcm_format_mask_test(format_mask, format))
    909 					continue;
    910 				SNDERR("Format: %s", snd_pcm_format_name(format));
    911 			}
    912 			for (format = 0; format <= SND_PCM_FORMAT_LAST; format++) {
    913 				if (!snd_pcm_format_mask_test(sformat_mask, format))
    914 					continue;
    915 				SNDERR("Slave format: %s", snd_pcm_format_name(format));
    916 			}
    917 			return -EINVAL;
    918 		}
    919 
    920 		err = _snd_pcm_hw_param_set_mask(params,
    921 						 SND_PCM_HW_PARAM_FORMAT, &fmt_mask);
    922 		if (err < 0)
    923 			return err;
    924 	}
    925 
    926 	if (plug->srate == -2 ||
    927 	    (pcm->mode & SND_PCM_NO_AUTO_RESAMPLE) ||
    928 	    (params->flags & SND_PCM_HW_PARAMS_NORESAMPLE))
    929 		links |= SND_PCM_HW_PARBIT_RATE;
    930 	else {
    931 		unsigned int rate_min, srate_min;
    932 		int rate_mindir, srate_mindir;
    933 
    934 		/* This is a temporary hack, waiting for a better solution */
    935 		err = snd_pcm_hw_param_get_min(params, SND_PCM_HW_PARAM_RATE, &rate_min, &rate_mindir);
    936 		if (err < 0)
    937 			return err;
    938 		err = snd_pcm_hw_param_get_min(sparams, SND_PCM_HW_PARAM_RATE, &srate_min, &srate_mindir);
    939 		if (err < 0)
    940 			return err;
    941 		if (rate_min == srate_min && srate_mindir > rate_mindir) {
    942 			err = _snd_pcm_hw_param_set_min(params, SND_PCM_HW_PARAM_RATE, srate_min, srate_mindir);
    943 			if (err < 0)
    944 				return err;
    945 		}
    946 	}
    947 	if ((links & SND_PCM_HW_PARBIT_RATE) ||
    948 	    snd_pcm_hw_param_always_eq(params, SND_PCM_HW_PARAM_RATE, sparams))
    949 		links |= (SND_PCM_HW_PARBIT_PERIOD_SIZE |
    950 			  SND_PCM_HW_PARBIT_BUFFER_SIZE);
    951 	else {
    952 		sbuffer_size = snd_pcm_hw_param_get_interval(sparams, SND_PCM_HW_PARAM_BUFFER_SIZE);
    953 		crate = snd_pcm_hw_param_get_interval(params, SND_PCM_HW_PARAM_RATE);
    954 		srate = snd_pcm_hw_param_get_interval(sparams, SND_PCM_HW_PARAM_RATE);
    955 		snd_interval_muldiv(sbuffer_size, crate, srate, &t);
    956 		snd_interval_floor(&t);
    957 		if (snd_interval_empty(&t))
    958 			return -EINVAL;
    959 		err = _snd_pcm_hw_param_set_interval(params, SND_PCM_HW_PARAM_BUFFER_SIZE, &t);
    960 		if (err < 0)
    961 			return err;
    962 	}
    963 	err = _snd_pcm_hw_params_refine(params, links, sparams);
    964 	if (err < 0)
    965 		return err;
    966 	/* FIXME */
    967 	params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
    968 	return 0;
    969 }
    970 
    971 static int snd_pcm_plug_hw_refine_slave(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
    972 {
    973 	snd_pcm_plug_t *plug = pcm->private_data;
    974 	return snd_pcm_hw_refine(plug->req_slave, params);
    975 }
    976 
    977 static int snd_pcm_plug_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
    978 {
    979 	return snd_pcm_hw_refine_slave(pcm, params,
    980 				       snd_pcm_plug_hw_refine_cprepare,
    981 				       snd_pcm_plug_hw_refine_cchange,
    982 				       snd_pcm_plug_hw_refine_sprepare,
    983 				       snd_pcm_plug_hw_refine_schange,
    984 				       snd_pcm_plug_hw_refine_slave);
    985 }
    986 
    987 static int snd_pcm_plug_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
    988 {
    989 	snd_pcm_plug_t *plug = pcm->private_data;
    990 	snd_pcm_t *slave = plug->req_slave;
    991 	snd_pcm_plug_params_t clt_params, slv_params;
    992 	snd_pcm_hw_params_t sparams;
    993 	int err;
    994 
    995 	err = snd_pcm_plug_hw_refine_sprepare(pcm, &sparams);
    996 	if (err < 0)
    997 		return err;
    998 	err = snd_pcm_plug_hw_refine_schange(pcm, params, &sparams);
    999 	if (err < 0)
   1000 		return err;
   1001 	err = snd_pcm_hw_refine_soft(slave, &sparams);
   1002 	if (err < 0)
   1003 		return err;
   1004 
   1005 	INTERNAL(snd_pcm_hw_params_get_access)(params, &clt_params.access);
   1006 	INTERNAL(snd_pcm_hw_params_get_format)(params, &clt_params.format);
   1007 	INTERNAL(snd_pcm_hw_params_get_channels)(params, &clt_params.channels);
   1008 	INTERNAL(snd_pcm_hw_params_get_rate)(params, &clt_params.rate, 0);
   1009 
   1010 	INTERNAL(snd_pcm_hw_params_get_format)(&sparams, &slv_params.format);
   1011 	INTERNAL(snd_pcm_hw_params_get_channels)(&sparams, &slv_params.channels);
   1012 	INTERNAL(snd_pcm_hw_params_get_rate)(&sparams, &slv_params.rate, 0);
   1013 	snd_pcm_plug_clear(pcm);
   1014 	if (!(clt_params.format == slv_params.format &&
   1015 	      clt_params.channels == slv_params.channels &&
   1016 	      clt_params.rate == slv_params.rate &&
   1017 	      !plug->ttable &&
   1018 	      snd_pcm_hw_params_test_access(slave, &sparams,
   1019 					    clt_params.access) >= 0)) {
   1020 		INTERNAL(snd_pcm_hw_params_set_access_first)(slave, &sparams, &slv_params.access);
   1021 		err = snd_pcm_plug_insert_plugins(pcm, &clt_params, &slv_params);
   1022 		if (err < 0)
   1023 			return err;
   1024 	}
   1025 	slave = plug->gen.slave;
   1026 	err = _snd_pcm_hw_params(slave, params);
   1027 	if (err < 0) {
   1028 		snd_pcm_plug_clear(pcm);
   1029 		return err;
   1030 	}
   1031 	snd_pcm_unlink_hw_ptr(pcm, plug->req_slave);
   1032 	snd_pcm_unlink_appl_ptr(pcm, plug->req_slave);
   1033 	snd_pcm_link_hw_ptr(pcm, slave);
   1034 	snd_pcm_link_appl_ptr(pcm, slave);
   1035 	return 0;
   1036 }
   1037 
   1038 static int snd_pcm_plug_hw_free(snd_pcm_t *pcm)
   1039 {
   1040 	snd_pcm_plug_t *plug = pcm->private_data;
   1041 	snd_pcm_t *slave = plug->gen.slave;
   1042 	int err = snd_pcm_hw_free(slave);
   1043 	snd_pcm_plug_clear(pcm);
   1044 	return err;
   1045 }
   1046 
   1047 static void snd_pcm_plug_dump(snd_pcm_t *pcm, snd_output_t *out)
   1048 {
   1049 	snd_pcm_plug_t *plug = pcm->private_data;
   1050 	snd_output_printf(out, "Plug PCM: ");
   1051 	snd_pcm_dump(plug->gen.slave, out);
   1052 }
   1053 
   1054 static const snd_pcm_ops_t snd_pcm_plug_ops = {
   1055 	.close = snd_pcm_plug_close,
   1056 	.info = snd_pcm_plug_info,
   1057 	.hw_refine = snd_pcm_plug_hw_refine,
   1058 	.hw_params = snd_pcm_plug_hw_params,
   1059 	.hw_free = snd_pcm_plug_hw_free,
   1060 	.sw_params = snd_pcm_generic_sw_params,
   1061 	.channel_info = snd_pcm_generic_channel_info,
   1062 	.dump = snd_pcm_plug_dump,
   1063 	.nonblock = snd_pcm_generic_nonblock,
   1064 	.async = snd_pcm_generic_async,
   1065 	.mmap = snd_pcm_generic_mmap,
   1066 	.munmap = snd_pcm_generic_munmap,
   1067 };
   1068 
   1069 /**
   1070  * \brief Creates a new Plug PCM
   1071  * \param pcmp Returns created PCM handle
   1072  * \param name Name of PCM
   1073  * \param sformat Slave (destination) format
   1074  * \param slave Slave PCM handle
   1075  * \param close_slave When set, the slave PCM handle is closed with copy PCM
   1076  * \retval zero on success otherwise a negative error code
   1077  * \warning Using of this function might be dangerous in the sense
   1078  *          of compatibility reasons. The prototype might be freely
   1079  *          changed in future.
   1080  */
   1081 int snd_pcm_plug_open(snd_pcm_t **pcmp,
   1082 		      const char *name,
   1083 		      snd_pcm_format_t sformat, int schannels, int srate,
   1084 		      const snd_config_t *rate_converter,
   1085 		      enum snd_pcm_plug_route_policy route_policy,
   1086 		      snd_pcm_route_ttable_entry_t *ttable,
   1087 		      unsigned int tt_ssize,
   1088 		      unsigned int tt_cused, unsigned int tt_sused,
   1089 		      snd_pcm_t *slave, int close_slave)
   1090 {
   1091 	snd_pcm_t *pcm;
   1092 	snd_pcm_plug_t *plug;
   1093 	int err;
   1094 	assert(pcmp && slave);
   1095 
   1096 	plug = calloc(1, sizeof(snd_pcm_plug_t));
   1097 	if (!plug)
   1098 		return -ENOMEM;
   1099 	plug->sformat = sformat;
   1100 	plug->schannels = schannels;
   1101 	plug->srate = srate;
   1102 	plug->rate_converter = rate_converter;
   1103 	plug->gen.slave = plug->req_slave = slave;
   1104 	plug->gen.close_slave = close_slave;
   1105 	plug->route_policy = route_policy;
   1106 	plug->ttable = ttable;
   1107 	plug->tt_ssize = tt_ssize;
   1108 	plug->tt_cused = tt_cused;
   1109 	plug->tt_sused = tt_sused;
   1110 
   1111 	err = snd_pcm_new(&pcm, SND_PCM_TYPE_PLUG, name, slave->stream, slave->mode);
   1112 	if (err < 0) {
   1113 		free(plug);
   1114 		return err;
   1115 	}
   1116 	pcm->ops = &snd_pcm_plug_ops;
   1117 	pcm->fast_ops = slave->fast_ops;
   1118 	pcm->fast_op_arg = slave->fast_op_arg;
   1119 	pcm->private_data = plug;
   1120 	pcm->poll_fd = slave->poll_fd;
   1121 	pcm->poll_events = slave->poll_events;
   1122 	pcm->mmap_shadow = 1;
   1123 	pcm->monotonic = slave->monotonic;
   1124 	snd_pcm_link_hw_ptr(pcm, slave);
   1125 	snd_pcm_link_appl_ptr(pcm, slave);
   1126 	*pcmp = pcm;
   1127 
   1128 	return 0;
   1129 }
   1130 
   1131 /*! \page pcm_plugins
   1132 
   1133 \section pcm_plugins_plug Automatic conversion plugin
   1134 
   1135 This plugin converts channels, rate and format on request.
   1136 
   1137 \code
   1138 pcm.name {
   1139         type plug               # Automatic conversion PCM
   1140         slave STR               # Slave name
   1141         # or
   1142         slave {                 # Slave definition
   1143                 pcm STR         # Slave PCM name
   1144                 # or
   1145                 pcm { }         # Slave PCM definition
   1146 		[format STR]	# Slave format (default nearest) or "unchanged"
   1147 		[channels INT]	# Slave channels (default nearest) or "unchanged"
   1148 		[rate INT]	# Slave rate (default nearest) or "unchanged"
   1149         }
   1150 	route_policy STR	# route policy for automatic ttable generation
   1151 				# STR can be 'default', 'average', 'copy', 'duplicate'
   1152 				# average: result is average of input channels
   1153 				# copy: only first channels are copied to destination
   1154 				# duplicate: duplicate first set of channels
   1155 				# default: copy policy, except for mono capture - sum
   1156 	ttable {		# Transfer table (bi-dimensional compound of cchannels * schannels numbers)
   1157 		CCHANNEL {
   1158 			SCHANNEL REAL	# route value (0.0 - 1.0)
   1159 		}
   1160 	}
   1161 	rate_converter STR	# type of rate converter
   1162 	# or
   1163 	rate_converter [ STR1 STR2 ... ]
   1164 				# type of rate converter
   1165 				# default value is taken from defaults.pcm.rate_converter
   1166 }
   1167 \endcode
   1168 
   1169 \subsection pcm_plugins_plug_funcref Function reference
   1170 
   1171 <UL>
   1172   <LI>snd_pcm_plug_open()
   1173   <LI>_snd_pcm_plug_open()
   1174 </UL>
   1175 
   1176 */
   1177 
   1178 /**
   1179  * \brief Creates a new Plug PCM
   1180  * \param pcmp Returns created PCM handle
   1181  * \param name Name of PCM
   1182  * \param root Root configuration node
   1183  * \param conf Configuration node with Plug PCM description
   1184  * \param stream Stream type
   1185  * \param mode Stream mode
   1186  * \retval zero on success otherwise a negative error code
   1187  * \warning Using of this function might be dangerous in the sense
   1188  *          of compatibility reasons. The prototype might be freely
   1189  *          changed in future.
   1190  */
   1191 int _snd_pcm_plug_open(snd_pcm_t **pcmp, const char *name,
   1192 		       snd_config_t *root, snd_config_t *conf,
   1193 		       snd_pcm_stream_t stream, int mode)
   1194 {
   1195 	snd_config_iterator_t i, next;
   1196 	int err;
   1197 	snd_pcm_t *spcm;
   1198 	snd_config_t *slave = NULL, *sconf;
   1199 	snd_config_t *tt = NULL;
   1200 	enum snd_pcm_plug_route_policy route_policy = PLUG_ROUTE_POLICY_DEFAULT;
   1201 	snd_pcm_route_ttable_entry_t *ttable = NULL;
   1202 	unsigned int csize, ssize;
   1203 	unsigned int cused, sused;
   1204 	snd_pcm_format_t sformat = SND_PCM_FORMAT_UNKNOWN;
   1205 	int schannels = -1, srate = -1;
   1206 	const snd_config_t *rate_converter = NULL;
   1207 
   1208 	snd_config_for_each(i, next, conf) {
   1209 		snd_config_t *n = snd_config_iterator_entry(i);
   1210 		const char *id;
   1211 		if (snd_config_get_id(n, &id) < 0)
   1212 			continue;
   1213 		if (snd_pcm_conf_generic_id(id))
   1214 			continue;
   1215 		if (strcmp(id, "slave") == 0) {
   1216 			slave = n;
   1217 			continue;
   1218 		}
   1219 #ifdef BUILD_PCM_PLUGIN_ROUTE
   1220 		if (strcmp(id, "ttable") == 0) {
   1221 			route_policy = PLUG_ROUTE_POLICY_NONE;
   1222 			if (snd_config_get_type(n) != SND_CONFIG_TYPE_COMPOUND) {
   1223 				SNDERR("Invalid type for %s", id);
   1224 				return -EINVAL;
   1225 			}
   1226 			tt = n;
   1227 			continue;
   1228 		}
   1229 		if (strcmp(id, "route_policy") == 0) {
   1230 			const char *str;
   1231 			if ((err = snd_config_get_string(n, &str)) < 0) {
   1232 				SNDERR("Invalid type for %s", id);
   1233 				return -EINVAL;
   1234 			}
   1235 			if (tt != NULL)
   1236 				SNDERR("Table is defined, route policy is ignored");
   1237 			if (!strcmp(str, "default"))
   1238 				route_policy = PLUG_ROUTE_POLICY_DEFAULT;
   1239 			else if (!strcmp(str, "average"))
   1240 				route_policy = PLUG_ROUTE_POLICY_AVERAGE;
   1241 			else if (!strcmp(str, "copy"))
   1242 				route_policy = PLUG_ROUTE_POLICY_COPY;
   1243 			else if (!strcmp(str, "duplicate"))
   1244 				route_policy = PLUG_ROUTE_POLICY_DUP;
   1245 			continue;
   1246 		}
   1247 #endif
   1248 #ifdef BUILD_PCM_PLUGIN_RATE
   1249 		if (strcmp(id, "rate_converter") == 0) {
   1250 			rate_converter = n;
   1251 			continue;
   1252 		}
   1253 #endif
   1254 		SNDERR("Unknown field %s", id);
   1255 		return -EINVAL;
   1256 	}
   1257 	if (!slave) {
   1258 		SNDERR("slave is not defined");
   1259 		return -EINVAL;
   1260 	}
   1261 	err = snd_pcm_slave_conf(root, slave, &sconf, 3,
   1262 				 SND_PCM_HW_PARAM_FORMAT, SCONF_UNCHANGED, &sformat,
   1263 				 SND_PCM_HW_PARAM_CHANNELS, SCONF_UNCHANGED, &schannels,
   1264 				 SND_PCM_HW_PARAM_RATE, SCONF_UNCHANGED, &srate);
   1265 	if (err < 0)
   1266 		return err;
   1267 #ifdef BUILD_PCM_PLUGIN_ROUTE
   1268 	if (tt) {
   1269 		err = snd_pcm_route_determine_ttable(tt, &csize, &ssize);
   1270 		if (err < 0) {
   1271 			snd_config_delete(sconf);
   1272 			return err;
   1273 		}
   1274 		ttable = malloc(csize * ssize * sizeof(*ttable));
   1275 		if (ttable == NULL) {
   1276 			snd_config_delete(sconf);
   1277 			return err;
   1278 		}
   1279 		err = snd_pcm_route_load_ttable(tt, ttable, csize, ssize, &cused, &sused, -1);
   1280 		if (err < 0) {
   1281 			snd_config_delete(sconf);
   1282 			return err;
   1283 		}
   1284 	}
   1285 #endif
   1286 
   1287 #ifdef BUILD_PCM_PLUGIN_RATE
   1288 	if (! rate_converter)
   1289 		rate_converter = snd_pcm_rate_get_default_converter(root);
   1290 #endif
   1291 
   1292 	err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode, conf);
   1293 	snd_config_delete(sconf);
   1294 	if (err < 0)
   1295 		return err;
   1296 	err = snd_pcm_plug_open(pcmp, name, sformat, schannels, srate, rate_converter,
   1297 				route_policy, ttable, ssize, cused, sused, spcm, 1);
   1298 	if (err < 0)
   1299 		snd_pcm_close(spcm);
   1300 	return err;
   1301 }
   1302 #ifndef DOC_HIDDEN
   1303 SND_DLSYM_BUILD_VERSION(_snd_pcm_plug_open, SND_PCM_DLSYM_VERSION);
   1304 #endif
   1305