1/*-
2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3 *
4 * Copyright (c) 2008-2009 Ariff Abdullah <ariff@FreeBSD.org>
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29#ifdef HAVE_KERNEL_OPTION_HEADERS
30#include "opt_snd.h"
31#endif
32
33#include <dev/sound/pcm/sound.h>
34
35#include "feeder_if.h"
36
37SND_DECLARE_FILE("$FreeBSD$");
38
39/* chain state */
40struct feeder_chain_state {
41	uint32_t afmt;				/* audio format */
42	uint32_t rate;				/* sampling rate */
43	struct pcmchan_matrix *matrix;		/* matrix map */
44};
45
46/*
47 * chain descriptor that will be passed around from the beginning until the
48 * end of chain process.
49 */
50struct feeder_chain_desc {
51	struct feeder_chain_state origin;	/* original state */
52	struct feeder_chain_state current;	/* current state */
53	struct feeder_chain_state target;	/* target state */
54	struct pcm_feederdesc desc;		/* feeder descriptor */
55	uint32_t afmt_ne;			/* prefered native endian */
56	int mode;				/* chain mode */
57	int use_eq;				/* need EQ? */
58	int use_matrix;				/* need channel matrixing? */
59	int use_volume;				/* need softpcmvol? */
60	int dummy;				/* dummy passthrough */
61	int expensive;				/* possibly expensive */
62};
63
64#define FEEDER_CHAIN_LEAN		0
65#define FEEDER_CHAIN_16			1
66#define FEEDER_CHAIN_32			2
67#define FEEDER_CHAIN_MULTI		3
68#define FEEDER_CHAIN_FULLMULTI		4
69#define FEEDER_CHAIN_LAST		5
70
71#if defined(SND_FEEDER_FULL_MULTIFORMAT)
72#define FEEDER_CHAIN_DEFAULT		FEEDER_CHAIN_FULLMULTI
73#elif defined(SND_FEEDER_MULTIFORMAT)
74#define FEEDER_CHAIN_DEFAULT		FEEDER_CHAIN_MULTI
75#else
76#define FEEDER_CHAIN_DEFAULT		FEEDER_CHAIN_LEAN
77#endif
78
79/*
80 * List of prefered formats that might be required during
81 * processing. It will be decided through snd_fmtbest().
82 */
83
84/* 'Lean' mode, signed 16 or 32 bit native endian. */
85static uint32_t feeder_chain_formats_lean[] = {
86	AFMT_S16_NE, AFMT_S32_NE,
87	0
88};
89
90/* Force everything to signed 16 bit native endian. */
91static uint32_t feeder_chain_formats_16[] = {
92	AFMT_S16_NE,
93	0
94};
95
96/* Force everything to signed 32 bit native endian. */
97static uint32_t feeder_chain_formats_32[] = {
98	AFMT_S32_NE,
99	0
100};
101
102/* Multiple choices, all except 8 bit. */
103static uint32_t feeder_chain_formats_multi[] = {
104	AFMT_S16_LE, AFMT_S16_BE, AFMT_U16_LE, AFMT_U16_BE,
105	AFMT_S24_LE, AFMT_S24_BE, AFMT_U24_LE, AFMT_U24_BE,
106	AFMT_S32_LE, AFMT_S32_BE, AFMT_U32_LE, AFMT_U32_BE,
107	0
108};
109
110/* Everything that is convertible. */
111static uint32_t feeder_chain_formats_fullmulti[] = {
112	AFMT_S8, AFMT_U8,
113	AFMT_S16_LE, AFMT_S16_BE, AFMT_U16_LE, AFMT_U16_BE,
114	AFMT_S24_LE, AFMT_S24_BE, AFMT_U24_LE, AFMT_U24_BE,
115	AFMT_S32_LE, AFMT_S32_BE, AFMT_U32_LE, AFMT_U32_BE,
116	0
117};
118
119static uint32_t *feeder_chain_formats[FEEDER_CHAIN_LAST] = {
120	[FEEDER_CHAIN_LEAN]      = feeder_chain_formats_lean,
121	[FEEDER_CHAIN_16]        = feeder_chain_formats_16,
122	[FEEDER_CHAIN_32]        = feeder_chain_formats_32,
123	[FEEDER_CHAIN_MULTI]     = feeder_chain_formats_multi,
124	[FEEDER_CHAIN_FULLMULTI] = feeder_chain_formats_fullmulti
125};
126
127static int feeder_chain_mode = FEEDER_CHAIN_DEFAULT;
128
129#if defined(_KERNEL) && defined(SND_DEBUG) && defined(SND_FEEDER_FULL_MULTIFORMAT)
130SYSCTL_INT(_hw_snd, OID_AUTO, feeder_chain_mode, CTLFLAG_RWTUN,
131    &feeder_chain_mode, 0,
132    "feeder chain mode "
133    "(0=lean, 1=16bit, 2=32bit, 3=multiformat, 4=fullmultiformat)");
134#endif
135
136/*
137 * feeder_build_format(): Chain any format converter.
138 */
139static int
140feeder_build_format(struct pcm_channel *c, struct feeder_chain_desc *cdesc)
141{
142	struct feeder_class *fc;
143	struct pcm_feederdesc *desc;
144	int ret;
145
146	desc = &(cdesc->desc);
147	desc->type = FEEDER_FORMAT;
148	desc->in = 0;
149	desc->out = 0;
150	desc->flags = 0;
151
152	fc = feeder_getclass(desc);
153	if (fc == NULL) {
154		device_printf(c->dev,
155		    "%s(): can't find feeder_format\n", __func__);
156		return (ENOTSUP);
157	}
158
159	desc->in = cdesc->current.afmt;
160	desc->out = cdesc->target.afmt;
161
162	ret = chn_addfeeder(c, fc, desc);
163	if (ret != 0) {
164		device_printf(c->dev,
165		    "%s(): can't add feeder_format\n", __func__);
166		return (ret);
167	}
168
169	c->feederflags |= 1 << FEEDER_FORMAT;
170
171	cdesc->current.afmt = cdesc->target.afmt;
172
173	return (0);
174}
175
176/*
177 * feeder_build_formatne(): Chain format converter that suite best for native
178 *                          endian format.
179 */
180static int
181feeder_build_formatne(struct pcm_channel *c, struct feeder_chain_desc *cdesc)
182{
183	struct feeder_chain_state otarget;
184	int ret;
185
186	if (cdesc->afmt_ne == 0 ||
187	    AFMT_ENCODING(cdesc->current.afmt) == cdesc->afmt_ne)
188		return (0);
189
190	otarget = cdesc->target;
191	cdesc->target = cdesc->current;
192	cdesc->target.afmt = SND_FORMAT(cdesc->afmt_ne,
193	    cdesc->current.matrix->channels, cdesc->current.matrix->ext);
194
195	ret = feeder_build_format(c, cdesc);
196	if (ret != 0)
197		return (ret);
198
199	cdesc->target = otarget;
200
201	return (0);
202}
203
204/*
205 * feeder_build_rate(): Chain sample rate converter.
206 */
207static int
208feeder_build_rate(struct pcm_channel *c, struct feeder_chain_desc *cdesc)
209{
210	struct feeder_class *fc;
211	struct pcm_feeder *f;
212	struct pcm_feederdesc *desc;
213	int ret;
214
215	ret = feeder_build_formatne(c, cdesc);
216	if (ret != 0)
217		return (ret);
218
219	desc = &(cdesc->desc);
220	desc->type = FEEDER_RATE;
221	desc->in = 0;
222	desc->out = 0;
223	desc->flags = 0;
224
225	fc = feeder_getclass(desc);
226	if (fc == NULL) {
227		device_printf(c->dev,
228		    "%s(): can't find feeder_rate\n", __func__);
229		return (ENOTSUP);
230	}
231
232	desc->in = cdesc->current.afmt;
233	desc->out = desc->in;
234
235	ret = chn_addfeeder(c, fc, desc);
236	if (ret != 0) {
237		device_printf(c->dev,
238		    "%s(): can't add feeder_rate\n", __func__);
239		return (ret);
240	}
241
242	f = c->feeder;
243
244	/*
245	 * If in 'dummy' mode (possibly due to passthrough mode), set the
246	 * conversion quality to the lowest possible (should be fastest) since
247	 * listener won't be hearing anything. Theoretically we can just
248	 * disable it, but that will cause weird runtime behaviour:
249	 * application appear to play something that is either too fast or too
250	 * slow.
251	 */
252	if (cdesc->dummy != 0) {
253		ret = FEEDER_SET(f, FEEDRATE_QUALITY, 0);
254		if (ret != 0) {
255			device_printf(c->dev,
256			    "%s(): can't set resampling quality\n", __func__);
257			return (ret);
258		}
259	}
260
261	ret = FEEDER_SET(f, FEEDRATE_SRC, cdesc->current.rate);
262	if (ret != 0) {
263		device_printf(c->dev,
264		    "%s(): can't set source rate\n", __func__);
265		return (ret);
266	}
267
268	ret = FEEDER_SET(f, FEEDRATE_DST, cdesc->target.rate);
269	if (ret != 0) {
270		device_printf(c->dev,
271		    "%s(): can't set destination rate\n", __func__);
272		return (ret);
273	}
274
275	c->feederflags |= 1 << FEEDER_RATE;
276
277	cdesc->current.rate = cdesc->target.rate;
278
279	return (0);
280}
281
282/*
283 * feeder_build_matrix(): Chain channel matrixing converter.
284 */
285static int
286feeder_build_matrix(struct pcm_channel *c, struct feeder_chain_desc *cdesc)
287{
288	struct feeder_class *fc;
289	struct pcm_feeder *f;
290	struct pcm_feederdesc *desc;
291	int ret;
292
293	ret = feeder_build_formatne(c, cdesc);
294	if (ret != 0)
295		return (ret);
296
297	desc = &(cdesc->desc);
298	desc->type = FEEDER_MATRIX;
299	desc->in = 0;
300	desc->out = 0;
301	desc->flags = 0;
302
303	fc = feeder_getclass(desc);
304	if (fc == NULL) {
305		device_printf(c->dev,
306		    "%s(): can't find feeder_matrix\n", __func__);
307		return (ENOTSUP);
308	}
309
310	desc->in = cdesc->current.afmt;
311	desc->out = SND_FORMAT(cdesc->current.afmt,
312	    cdesc->target.matrix->channels, cdesc->target.matrix->ext);
313
314	ret = chn_addfeeder(c, fc, desc);
315	if (ret != 0) {
316		device_printf(c->dev,
317		    "%s(): can't add feeder_matrix\n", __func__);
318		return (ret);
319	}
320
321	f = c->feeder;
322	ret = feeder_matrix_setup(f, cdesc->current.matrix,
323	    cdesc->target.matrix);
324	if (ret != 0) {
325		device_printf(c->dev,
326		    "%s(): feeder_matrix_setup() failed\n", __func__);
327		return (ret);
328	}
329
330	c->feederflags |= 1 << FEEDER_MATRIX;
331
332	cdesc->current.afmt = desc->out;
333	cdesc->current.matrix = cdesc->target.matrix;
334	cdesc->use_matrix = 0;
335
336	return (0);
337}
338
339/*
340 * feeder_build_volume(): Chain soft volume.
341 */
342static int
343feeder_build_volume(struct pcm_channel *c, struct feeder_chain_desc *cdesc)
344{
345	struct feeder_class *fc;
346	struct pcm_feeder *f;
347	struct pcm_feederdesc *desc;
348	int ret;
349
350	ret = feeder_build_formatne(c, cdesc);
351	if (ret != 0)
352		return (ret);
353
354	desc = &(cdesc->desc);
355	desc->type = FEEDER_VOLUME;
356	desc->in = 0;
357	desc->out = 0;
358	desc->flags = 0;
359
360	fc = feeder_getclass(desc);
361	if (fc == NULL) {
362		device_printf(c->dev,
363		    "%s(): can't find feeder_volume\n", __func__);
364		return (ENOTSUP);
365	}
366
367	desc->in = cdesc->current.afmt;
368	desc->out = desc->in;
369
370	ret = chn_addfeeder(c, fc, desc);
371	if (ret != 0) {
372		device_printf(c->dev,
373		    "%s(): can't add feeder_volume\n", __func__);
374		return (ret);
375	}
376
377	f = c->feeder;
378
379	/*
380	 * If in 'dummy' mode (possibly due to passthrough mode), set BYPASS
381	 * mode since listener won't be hearing anything. Theoretically we can
382	 * just disable it, but that will confuse volume per channel mixer.
383	 */
384	if (cdesc->dummy != 0) {
385		ret = FEEDER_SET(f, FEEDVOLUME_STATE, FEEDVOLUME_BYPASS);
386		if (ret != 0) {
387			device_printf(c->dev,
388			    "%s(): can't set volume bypass\n", __func__);
389			return (ret);
390		}
391	}
392
393	ret = feeder_volume_apply_matrix(f, cdesc->current.matrix);
394	if (ret != 0) {
395		device_printf(c->dev,
396		    "%s(): feeder_volume_apply_matrix() failed\n", __func__);
397		return (ret);
398	}
399
400	c->feederflags |= 1 << FEEDER_VOLUME;
401
402	cdesc->use_volume = 0;
403
404	return (0);
405}
406
407/*
408 * feeder_build_eq(): Chain parametric software equalizer.
409 */
410static int
411feeder_build_eq(struct pcm_channel *c, struct feeder_chain_desc *cdesc)
412{
413	struct feeder_class *fc;
414	struct pcm_feeder *f;
415	struct pcm_feederdesc *desc;
416	int ret;
417
418	ret = feeder_build_formatne(c, cdesc);
419	if (ret != 0)
420		return (ret);
421
422	desc = &(cdesc->desc);
423	desc->type = FEEDER_EQ;
424	desc->in = 0;
425	desc->out = 0;
426	desc->flags = 0;
427
428	fc = feeder_getclass(desc);
429	if (fc == NULL) {
430		device_printf(c->dev,
431		    "%s(): can't find feeder_eq\n", __func__);
432		return (ENOTSUP);
433	}
434
435	desc->in = cdesc->current.afmt;
436	desc->out = desc->in;
437
438	ret = chn_addfeeder(c, fc, desc);
439	if (ret != 0) {
440		device_printf(c->dev,
441		    "%s(): can't add feeder_eq\n", __func__);
442		return (ret);
443	}
444
445	f = c->feeder;
446
447	ret = FEEDER_SET(f, FEEDEQ_RATE, cdesc->current.rate);
448	if (ret != 0) {
449		device_printf(c->dev,
450		    "%s(): can't set rate on feeder_eq\n", __func__);
451		return (ret);
452	}
453
454	c->feederflags |= 1 << FEEDER_EQ;
455
456	cdesc->use_eq = 0;
457
458	return (0);
459}
460
461/*
462 * feeder_build_root(): Chain root feeder, the top, father of all.
463 */
464static int
465feeder_build_root(struct pcm_channel *c, struct feeder_chain_desc *cdesc)
466{
467	struct feeder_class *fc;
468	int ret;
469
470	fc = feeder_getclass(NULL);
471	if (fc == NULL) {
472		device_printf(c->dev,
473		    "%s(): can't find feeder_root\n", __func__);
474		return (ENOTSUP);
475	}
476
477	ret = chn_addfeeder(c, fc, NULL);
478	if (ret != 0) {
479		device_printf(c->dev,
480		    "%s(): can't add feeder_root\n", __func__);
481		return (ret);
482	}
483
484	c->feederflags |= 1 << FEEDER_ROOT;
485
486	c->feeder->desc->in = cdesc->current.afmt;
487	c->feeder->desc->out = cdesc->current.afmt;
488
489	return (0);
490}
491
492/*
493 * feeder_build_mixer(): Chain software mixer for virtual channels.
494 */
495static int
496feeder_build_mixer(struct pcm_channel *c, struct feeder_chain_desc *cdesc)
497{
498	struct feeder_class *fc;
499	struct pcm_feederdesc *desc;
500	int ret;
501
502	desc = &(cdesc->desc);
503	desc->type = FEEDER_MIXER;
504	desc->in = 0;
505	desc->out = 0;
506	desc->flags = 0;
507
508	fc = feeder_getclass(desc);
509	if (fc == NULL) {
510		device_printf(c->dev,
511		    "%s(): can't find feeder_mixer\n", __func__);
512		return (ENOTSUP);
513	}
514
515	desc->in = cdesc->current.afmt;
516	desc->out = desc->in;
517
518	ret = chn_addfeeder(c, fc, desc);
519	if (ret != 0) {
520		device_printf(c->dev,
521		    "%s(): can't add feeder_mixer\n", __func__);
522		return (ret);
523	}
524
525	c->feederflags |= 1 << FEEDER_MIXER;
526
527	return (0);
528}
529
530/* Macrosses to ease our job doing stuffs later. */
531#define FEEDER_BW(c, t)		((c)->t.matrix->channels * (c)->t.rate)
532
533#define FEEDRATE_UP(c)		((c)->target.rate > (c)->current.rate)
534#define FEEDRATE_DOWN(c)	((c)->target.rate < (c)->current.rate)
535#define FEEDRATE_REQUIRED(c)	(FEEDRATE_UP(c) || FEEDRATE_DOWN(c))
536
537#define FEEDMATRIX_UP(c)	((c)->target.matrix->channels >		\
538				 (c)->current.matrix->channels)
539#define FEEDMATRIX_DOWN(c)	((c)->target.matrix->channels <		\
540				 (c)->current.matrix->channels)
541#define FEEDMATRIX_REQUIRED(c)	(FEEDMATRIX_UP(c) ||			\
542				 FEEDMATRIX_DOWN(c) || (c)->use_matrix != 0)
543
544#define FEEDFORMAT_REQUIRED(c)	(AFMT_ENCODING((c)->current.afmt) !=	\
545				 AFMT_ENCODING((c)->target.afmt))
546
547#define FEEDVOLUME_REQUIRED(c)	((c)->use_volume != 0)
548
549#define FEEDEQ_VALIDRATE(c, t)	(feeder_eq_validrate((c)->t.rate) != 0)
550#define FEEDEQ_ECONOMY(c)	(FEEDER_BW(c, current) < FEEDER_BW(c, target))
551#define FEEDEQ_REQUIRED(c)	((c)->use_eq != 0 &&			\
552				 FEEDEQ_VALIDRATE(c, current))
553
554#define FEEDFORMAT_NE_REQUIRED(c)					\
555	((c)->afmt_ne != AFMT_S32_NE &&					\
556	(((c)->mode == FEEDER_CHAIN_16 &&				\
557	AFMT_ENCODING((c)->current.afmt) != AFMT_S16_NE) ||		\
558	((c)->mode == FEEDER_CHAIN_32 &&				\
559	AFMT_ENCODING((c)->current.afmt) != AFMT_S32_NE) ||		\
560	(c)->mode == FEEDER_CHAIN_FULLMULTI ||				\
561	((c)->mode == FEEDER_CHAIN_MULTI &&				\
562	((c)->current.afmt & AFMT_8BIT)) ||				\
563	((c)->mode == FEEDER_CHAIN_LEAN &&				\
564	!((c)->current.afmt & (AFMT_S16_NE | AFMT_S32_NE)))))
565
566static void
567feeder_default_matrix(struct pcmchan_matrix *m, uint32_t fmt, int id)
568{
569	int x;
570
571	memset(m, 0, sizeof(*m));
572
573	m->id = id;
574	m->channels = AFMT_CHANNEL(fmt);
575	m->ext = AFMT_EXTCHANNEL(fmt);
576	for (x = 0; x != SND_CHN_T_MAX; x++)
577		m->offset[x] = -1;
578}
579
580int
581feeder_chain(struct pcm_channel *c)
582{
583	struct snddev_info *d;
584	struct pcmchan_caps *caps;
585	struct feeder_chain_desc cdesc;
586	struct pcmchan_matrix *hwmatrix, *softmatrix;
587	uint32_t hwfmt, softfmt;
588	int ret;
589
590	CHN_LOCKASSERT(c);
591
592	/* Remove everything first. */
593	while (chn_removefeeder(c) == 0)
594		;
595
596	KASSERT(c->feeder == NULL, ("feeder chain not empty"));
597
598	/* clear and populate chain descriptor. */
599	bzero(&cdesc, sizeof(cdesc));
600
601	switch (feeder_chain_mode) {
602	case FEEDER_CHAIN_LEAN:
603	case FEEDER_CHAIN_16:
604	case FEEDER_CHAIN_32:
605#if defined(SND_FEEDER_MULTIFORMAT) || defined(SND_FEEDER_FULL_MULTIFORMAT)
606	case FEEDER_CHAIN_MULTI:
607#endif
608#if defined(SND_FEEDER_FULL_MULTIFORMAT)
609	case FEEDER_CHAIN_FULLMULTI:
610#endif
611		break;
612	default:
613		feeder_chain_mode = FEEDER_CHAIN_DEFAULT;
614		break;
615	}
616
617	cdesc.mode = feeder_chain_mode;
618	cdesc.expensive = 1;	/* XXX faster.. */
619
620#define VCHAN_PASSTHROUGH(c)	(((c)->flags & (CHN_F_VIRTUAL |		\
621				 CHN_F_PASSTHROUGH)) ==			\
622				 (CHN_F_VIRTUAL | CHN_F_PASSTHROUGH))
623
624	/* Get the best possible hardware format. */
625	if (VCHAN_PASSTHROUGH(c))
626		hwfmt = c->parentchannel->format;
627	else {
628		caps = chn_getcaps(c);
629		if (caps == NULL || caps->fmtlist == NULL) {
630			device_printf(c->dev,
631			    "%s(): failed to get channel caps\n", __func__);
632			return (ENODEV);
633		}
634
635		if ((c->format & AFMT_PASSTHROUGH) &&
636		    !snd_fmtvalid(c->format, caps->fmtlist))
637			return (ENODEV);
638
639		hwfmt = snd_fmtbest(c->format, caps->fmtlist);
640		if (hwfmt == 0 || !snd_fmtvalid(hwfmt, caps->fmtlist)) {
641			device_printf(c->dev,
642			    "%s(): invalid hardware format 0x%08x\n",
643			    __func__, hwfmt);
644			{
645				int i;
646				for (i = 0; caps->fmtlist[i] != 0; i++)
647					printf("0x%08x\n", caps->fmtlist[i]);
648				printf("Req: 0x%08x\n", c->format);
649			}
650			return (ENODEV);
651		}
652	}
653
654	/*
655	 * The 'hardware' possibly have different intepretation of channel
656	 * matrixing, so get it first .....
657	 */
658	hwmatrix = CHANNEL_GETMATRIX(c->methods, c->devinfo, hwfmt);
659	if (hwmatrix == NULL) {
660		/* setup a default matrix */
661		hwmatrix = &c->matrix_scratch;
662		feeder_default_matrix(hwmatrix, hwfmt,
663		    SND_CHN_MATRIX_UNKNOWN);
664	}
665	/* ..... and rebuild hwfmt. */
666	hwfmt = SND_FORMAT(hwfmt, hwmatrix->channels, hwmatrix->ext);
667
668	/* Reset and rebuild default channel format/matrix map. */
669	softfmt = c->format;
670	softmatrix = &c->matrix;
671	if (softmatrix->channels != AFMT_CHANNEL(softfmt) ||
672	    softmatrix->ext != AFMT_EXTCHANNEL(softfmt)) {
673		softmatrix = feeder_matrix_format_map(softfmt);
674		if (softmatrix == NULL) {
675			/* setup a default matrix */
676		  	softmatrix = &c->matrix;
677			feeder_default_matrix(softmatrix, softfmt,
678			    SND_CHN_MATRIX_PCMCHANNEL);
679		} else {
680			c->matrix = *softmatrix;
681			c->matrix.id = SND_CHN_MATRIX_PCMCHANNEL;
682		}
683	}
684	softfmt = SND_FORMAT(softfmt, softmatrix->channels, softmatrix->ext);
685	if (softfmt != c->format)
686		device_printf(c->dev,
687		    "%s(): WARNING: %s Soft format 0x%08x -> 0x%08x\n",
688		    __func__, CHN_DIRSTR(c), c->format, softfmt);
689
690	/*
691	 * PLAY and REC are opposite.
692	 */
693	if (c->direction == PCMDIR_PLAY) {
694		cdesc.origin.afmt    = softfmt;
695		cdesc.origin.matrix  = softmatrix;
696		cdesc.origin.rate    = c->speed;
697		cdesc.target.afmt    = hwfmt;
698		cdesc.target.matrix  = hwmatrix;
699		cdesc.target.rate    = sndbuf_getspd(c->bufhard);
700	} else {
701		cdesc.origin.afmt    = hwfmt;
702		cdesc.origin.matrix  = hwmatrix;
703		cdesc.origin.rate    = sndbuf_getspd(c->bufhard);
704		cdesc.target.afmt    = softfmt;
705		cdesc.target.matrix  = softmatrix;
706		cdesc.target.rate    = c->speed;
707	}
708
709	d = c->parentsnddev;
710
711	/*
712	 * If channel is in bitperfect or passthrough mode, make it appear
713	 * that 'origin' and 'target' identical, skipping mostly chain
714	 * procedures.
715	 */
716	if (CHN_BITPERFECT(c) || (c->format & AFMT_PASSTHROUGH)) {
717		if (c->direction == PCMDIR_PLAY)
718			cdesc.origin = cdesc.target;
719		else
720			cdesc.target = cdesc.origin;
721		c->format = cdesc.target.afmt;
722		c->speed  = cdesc.target.rate;
723	} else {
724		/* hwfmt is not convertible, so 'dummy' it. */
725		if (hwfmt & AFMT_PASSTHROUGH)
726			cdesc.dummy = 1;
727
728		if ((softfmt & AFMT_CONVERTIBLE) &&
729		    (((d->flags & SD_F_VPC) && !(c->flags & CHN_F_HAS_VCHAN)) ||
730		    (!(d->flags & SD_F_VPC) && (d->flags & SD_F_SOFTPCMVOL) &&
731		    !(c->flags & CHN_F_VIRTUAL))))
732			cdesc.use_volume = 1;
733
734		if (feeder_matrix_compare(cdesc.origin.matrix,
735		    cdesc.target.matrix) != 0)
736			cdesc.use_matrix = 1;
737
738		/* Soft EQ only applicable for PLAY. */
739		if (cdesc.dummy == 0 &&
740		    c->direction == PCMDIR_PLAY && (d->flags & SD_F_EQ) &&
741		    (((d->flags & SD_F_EQ_PC) &&
742		    !(c->flags & CHN_F_HAS_VCHAN)) ||
743		    (!(d->flags & SD_F_EQ_PC) && !(c->flags & CHN_F_VIRTUAL))))
744			cdesc.use_eq = 1;
745
746		if (FEEDFORMAT_NE_REQUIRED(&cdesc)) {
747			cdesc.afmt_ne =
748			    (cdesc.dummy != 0) ?
749			    snd_fmtbest(AFMT_ENCODING(softfmt),
750			    feeder_chain_formats[cdesc.mode]) :
751			    snd_fmtbest(AFMT_ENCODING(cdesc.target.afmt),
752			    feeder_chain_formats[cdesc.mode]);
753			if (cdesc.afmt_ne == 0) {
754				device_printf(c->dev,
755				    "%s(): snd_fmtbest failed!\n", __func__);
756				cdesc.afmt_ne =
757				    (((cdesc.dummy != 0) ? softfmt :
758				    cdesc.target.afmt) &
759				    (AFMT_24BIT | AFMT_32BIT)) ?
760				    AFMT_S32_NE : AFMT_S16_NE;
761			}
762		}
763	}
764
765	cdesc.current = cdesc.origin;
766
767	/* Build everything. */
768
769	c->feederflags = 0;
770
771#define FEEDER_BUILD(t)	do {						\
772	ret = feeder_build_##t(c, &cdesc);				\
773	if (ret != 0)							\
774		return (ret);						\
775	} while (0)
776
777	if (!(c->flags & CHN_F_HAS_VCHAN) || c->direction == PCMDIR_REC)
778		FEEDER_BUILD(root);
779	else if (c->direction == PCMDIR_PLAY && (c->flags & CHN_F_HAS_VCHAN))
780		FEEDER_BUILD(mixer);
781	else
782		return (ENOTSUP);
783
784	/*
785	 * The basic idea is: The smaller the bandwidth, the cheaper the
786	 * conversion process, with following constraints:-
787	 *
788	 * 1) Almost all feeders work best in 16/32 native endian.
789	 * 2) Try to avoid 8bit feeders due to poor dynamic range.
790	 * 3) Avoid volume, format, matrix and rate in BITPERFECT or
791	 *    PASSTHROUGH mode.
792	 * 4) Try putting volume before EQ or rate. Should help to
793	 *    avoid/reduce possible clipping.
794	 * 5) EQ require specific, valid rate, unless it allow sloppy
795	 *    conversion.
796	 */
797	if (FEEDMATRIX_UP(&cdesc)) {
798		if (FEEDEQ_REQUIRED(&cdesc) &&
799		    (!FEEDEQ_VALIDRATE(&cdesc, target) ||
800		    (cdesc.expensive == 0 && FEEDEQ_ECONOMY(&cdesc))))
801			FEEDER_BUILD(eq);
802		if (FEEDRATE_REQUIRED(&cdesc))
803			FEEDER_BUILD(rate);
804		FEEDER_BUILD(matrix);
805		if (FEEDVOLUME_REQUIRED(&cdesc))
806			FEEDER_BUILD(volume);
807		if (FEEDEQ_REQUIRED(&cdesc))
808			FEEDER_BUILD(eq);
809	} else if (FEEDMATRIX_DOWN(&cdesc)) {
810		FEEDER_BUILD(matrix);
811		if (FEEDVOLUME_REQUIRED(&cdesc))
812			FEEDER_BUILD(volume);
813		if (FEEDEQ_REQUIRED(&cdesc) &&
814		    (!FEEDEQ_VALIDRATE(&cdesc, target) ||
815		    FEEDEQ_ECONOMY(&cdesc)))
816			FEEDER_BUILD(eq);
817		if (FEEDRATE_REQUIRED(&cdesc))
818			FEEDER_BUILD(rate);
819		if (FEEDEQ_REQUIRED(&cdesc))
820			FEEDER_BUILD(eq);
821	} else {
822		if (FEEDRATE_DOWN(&cdesc)) {
823			if (FEEDEQ_REQUIRED(&cdesc) &&
824			    !FEEDEQ_VALIDRATE(&cdesc, target)) {
825				if (FEEDVOLUME_REQUIRED(&cdesc))
826					FEEDER_BUILD(volume);
827				FEEDER_BUILD(eq);
828			}
829			FEEDER_BUILD(rate);
830		}
831		if (FEEDMATRIX_REQUIRED(&cdesc))
832			FEEDER_BUILD(matrix);
833		if (FEEDVOLUME_REQUIRED(&cdesc))
834			FEEDER_BUILD(volume);
835		if (FEEDRATE_UP(&cdesc)) {
836			if (FEEDEQ_REQUIRED(&cdesc) &&
837			    !FEEDEQ_VALIDRATE(&cdesc, target))
838				FEEDER_BUILD(eq);
839			FEEDER_BUILD(rate);
840		}
841		if (FEEDEQ_REQUIRED(&cdesc))
842			FEEDER_BUILD(eq);
843	}
844
845	if (FEEDFORMAT_REQUIRED(&cdesc))
846		FEEDER_BUILD(format);
847
848	if (c->direction == PCMDIR_REC && (c->flags & CHN_F_HAS_VCHAN))
849		FEEDER_BUILD(mixer);
850
851	sndbuf_setfmt(c->bufsoft, c->format);
852	sndbuf_setspd(c->bufsoft, c->speed);
853
854	sndbuf_setfmt(c->bufhard, hwfmt);
855
856	chn_syncstate(c);
857
858	return (0);
859}
860