feeder.c revision 53465
1133359Sobrien/*
2133359Sobrien * Copyright (c) 1999 Cameron Grant <gandalf@vilnya.demon.co.uk>
3133359Sobrien * All rights reserved.
4133359Sobrien *
5133359Sobrien * Redistribution and use in source and binary forms, with or without
6133359Sobrien * modification, are permitted provided that the following conditions
7133359Sobrien * are met:
8133359Sobrien * 1. Redistributions of source code must retain the above copyright
9133359Sobrien *    notice, this list of conditions and the following disclaimer.
10133359Sobrien * 2. Redistributions in binary form must reproduce the above copyright
11133359Sobrien *    notice, this list of conditions and the following disclaimer in the
12133359Sobrien *    documentation and/or other materials provided with the distribution.
13133359Sobrien *
14133359Sobrien * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15133359Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16133359Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17133359Sobrien * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18133359Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19133359Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20133359Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21133359Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22133359Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23133359Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24133359Sobrien * SUCH DAMAGE.
25133359Sobrien *
26133359Sobrien * $FreeBSD: head/sys/dev/sound/pcm/feeder.c 53465 1999-11-20 16:50:33Z cg $
2768349Sobrien */
2868349Sobrien
29191736Sobrien#include <dev/sound/pcm/sound.h>
30267843Sdelphij
31191736Sobrienstatic int chn_addfeeder(pcm_channel *c, pcm_feeder *f);
32191736Sobrienstatic int chn_removefeeder(pcm_channel *c);
3368349Sobrien
3468349Sobrien#define FEEDBUFSZ	8192
3568349Sobrien
3668349Sobrienstatic unsigned char ulaw_to_u8[] = {
3768349Sobrien     3,    7,   11,   15,   19,   23,   27,   31,
3868349Sobrien    35,   39,   43,   47,   51,   55,   59,   63,
3968349Sobrien    66,   68,   70,   72,   74,   76,   78,   80,
4068349Sobrien    82,   84,   86,   88,   90,   92,   94,   96,
4168349Sobrien    98,   99,  100,  101,  102,  103,  104,  105,
42186690Sobrien   106,  107,  108,  109,  110,  111,  112,  113,
4368349Sobrien   113,  114,  114,  115,  115,  116,  116,  117,
4468349Sobrien   117,  118,  118,  119,  119,  120,  120,  121,
45169942Sobrien   121,  121,  122,  122,  122,  122,  123,  123,
46169942Sobrien   123,  123,  124,  124,  124,  124,  125,  125,
4768349Sobrien   125,  125,  125,  125,  126,  126,  126,  126,
48169942Sobrien   126,  126,  126,  126,  127,  127,  127,  127,
49186690Sobrien   127,  127,  127,  127,  127,  127,  127,  127,
50226048Sobrien   128,  128,  128,  128,  128,  128,  128,  128,
51267843Sdelphij   128,  128,  128,  128,  128,  128,  128,  128,
52186690Sobrien   128,  128,  128,  128,  128,  128,  128,  128,
53159764Sobrien   253,  249,  245,  241,  237,  233,  229,  225,
5468349Sobrien   221,  217,  213,  209,  205,  201,  197,  193,
55133359Sobrien   190,  188,  186,  184,  182,  180,  178,  176,
5668349Sobrien   174,  172,  170,  168,  166,  164,  162,  160,
57159764Sobrien   158,  157,  156,  155,  154,  153,  152,  151,
58159764Sobrien   150,  149,  148,  147,  146,  145,  144,  143,
59133359Sobrien   143,  142,  142,  141,  141,  140,  140,  139,
60133359Sobrien   139,  138,  138,  137,  137,  136,  136,  135,
61133359Sobrien   135,  135,  134,  134,  134,  134,  133,  133,
62133359Sobrien   133,  133,  132,  132,  132,  132,  131,  131,
63275666Sdelphij   131,  131,  131,  131,  130,  130,  130,  130,
64275666Sdelphij   130,  130,  130,  130,  129,  129,  129,  129,
65275666Sdelphij   129,  129,  129,  129,  129,  129,  129,  129,
66275666Sdelphij   128,  128,  128,  128,  128,  128,  128,  128,
67275666Sdelphij   128,  128,  128,  128,  128,  128,  128,  128,
68275666Sdelphij   128,  128,  128,  128,  128,  128,  128,  128,
69275666Sdelphij};
70275666Sdelphij
71275666Sdelphijstatic unsigned char u8_to_ulaw[] = {
72275666Sdelphij     0,    0,    0,    0,    0,    1,    1,    1,
73275666Sdelphij     1,    2,    2,    2,    2,    3,    3,    3,
74275666Sdelphij     3,    4,    4,    4,    4,    5,    5,    5,
75133359Sobrien     5,    6,    6,    6,    6,    7,    7,    7,
76103373Sobrien     7,    8,    8,    8,    8,    9,    9,    9,
7768349Sobrien     9,   10,   10,   10,   10,   11,   11,   11,
7868349Sobrien    11,   12,   12,   12,   12,   13,   13,   13,
7968349Sobrien    13,   14,   14,   14,   14,   15,   15,   15,
8068349Sobrien    15,   16,   16,   17,   17,   18,   18,   19,
8168349Sobrien    19,   20,   20,   21,   21,   22,   22,   23,
8268349Sobrien    23,   24,   24,   25,   25,   26,   26,   27,
8368349Sobrien    27,   28,   28,   29,   29,   30,   30,   31,
8468349Sobrien    31,   32,   33,   34,   35,   36,   37,   38,
8568349Sobrien    39,   40,   41,   42,   43,   44,   45,   46,
8668349Sobrien    47,   49,   51,   53,   55,   57,   59,   61,
8768349Sobrien    63,   66,   70,   74,   78,   84,   92,  104,
8868349Sobrien   254,  231,  219,  211,  205,  201,  197,  193,
8968349Sobrien   190,  188,  186,  184,  182,  180,  178,  176,
9068349Sobrien   175,  174,  173,  172,  171,  170,  169,  168,
9168349Sobrien   167,  166,  165,  164,  163,  162,  161,  160,
9268349Sobrien   159,  159,  158,  158,  157,  157,  156,  156,
9368349Sobrien   155,  155,  154,  154,  153,  153,  152,  152,
94133359Sobrien   151,  151,  150,  150,  149,  149,  148,  148,
95103373Sobrien   147,  147,  146,  146,  145,  145,  144,  144,
9668349Sobrien   143,  143,  143,  143,  142,  142,  142,  142,
9768349Sobrien   141,  141,  141,  141,  140,  140,  140,  140,
9868349Sobrien   139,  139,  139,  139,  138,  138,  138,  138,
9968349Sobrien   137,  137,  137,  137,  136,  136,  136,  136,
10068349Sobrien   135,  135,  135,  135,  134,  134,  134,  134,
10168349Sobrien   133,  133,  133,  133,  132,  132,  132,  132,
10268349Sobrien   131,  131,  131,  131,  130,  130,  130,  130,
10368349Sobrien   129,  129,  129,  129,  128,  128,  128,  128,
10468349Sobrien};
10568349Sobrien
10668349Sobrien/*****************************************************************************/
10768349Sobrien
10868349Sobrienstatic int
10968349Sobrienfeed_root(pcm_feeder *feeder, pcm_channel *ch, u_int8_t *buffer, u_int32_t count, struct uio *stream)
11068349Sobrien{
11168349Sobrien	int ret, tmp = 0, c = 0;
11268349Sobrien	if (!count) panic("feed_root: count == 0");
11368349Sobrien	count &= ~((1 << ch->align) - 1);
11468349Sobrien	if (!count) panic("feed_root: aligned count == 0");
115133359Sobrien	if (ch->smegcnt > 0) {
116103373Sobrien		c = min(ch->smegcnt, count);
11768349Sobrien		bcopy(ch->smegbuf, buffer, c);
11868349Sobrien		ch->smegcnt -= c;
11968349Sobrien	}
12068349Sobrien	while ((stream->uio_resid > 0) && (c < count)) {
12168349Sobrien		tmp = stream->uio_resid;
12268349Sobrien		ret = uiomove(buffer + c, count - c, stream);
12368349Sobrien		if (ret) panic("feed_root: uiomove failed");
12468349Sobrien		tmp -= stream->uio_resid;
12568349Sobrien		c += tmp;
12668349Sobrien	}
12768349Sobrien	if (!c) panic("feed_root: uiomove didn't");
12868349Sobrien	return c;
12968349Sobrien}
13068349Sobrienpcm_feeder feeder_root = { "root", 0, NULL, NULL, feed_root };
13168349Sobrien
13268349Sobrien/*****************************************************************************/
13368349Sobrien
13468349Sobrienstatic int
13568349Sobrienfeed_8to16(pcm_feeder *f, pcm_channel *c, u_int8_t *b, u_int32_t count, struct uio *stream)
13668349Sobrien{
13768349Sobrien	int i, j, k;
13868349Sobrien	k = f->source->feed(f->source, c, b, count / 2, stream);
13968349Sobrien	j = k - 1;
140186690Sobrien	i = j * 2 + 1;
141186690Sobrien	while (i > 0 && j >= 0) {
142267843Sdelphij		b[i--] = b[j--];
143159764Sobrien		b[i--] = 0;
144186690Sobrien	}
145267843Sdelphij	return k * 2;
146267843Sdelphij}
147186690Sobrienstatic pcm_feeder feeder_8to16 = { "8to16", 0, NULL, NULL, feed_8to16 };
148267843Sdelphij
149267843Sdelphij/*****************************************************************************/
150267843Sdelphij
151186690Sobrienstatic int
152186690Sobrienfeed_16to8_init(pcm_feeder *f)
153226048Sobrien{
154186690Sobrien	f->data = malloc(FEEDBUFSZ, M_DEVBUF, M_NOWAIT);
155186690Sobrien	return (f->data == NULL);
156186690Sobrien}
157186690Sobrien
158186690Sobrienstatic int
159267843Sdelphijfeed_16to8_free(pcm_feeder *f)
160267843Sdelphij{
161267843Sdelphij	if (f->data) free(f->data, M_DEVBUF);
162186690Sobrien	f->data = NULL;
163186690Sobrien	return 0;
16468349Sobrien}
165186690Sobrien
166267843Sdelphijstatic int
167267843Sdelphijfeed_16to8le(pcm_feeder *f, pcm_channel *c, u_int8_t *b, u_int32_t count, struct uio *stream)
168186690Sobrien{
169186690Sobrien	u_int32_t i = 0, toget = count * 2;
170186690Sobrien	int j = 1, k;
171186690Sobrien	k = f->source->feed(f->source, c, f->data, min(toget, FEEDBUFSZ), stream);
172186690Sobrien	while (j < k) {
173186690Sobrien		b[i++] = ((u_int8_t *)f->data)[j];
174186690Sobrien		j += 2;
175186690Sobrien	}
176186690Sobrien	return i;
177186690Sobrien}
178186690Sobrienstatic pcm_feeder feeder_16to8le =
179186690Sobrien	{ "16to8le", 1, feed_16to8_init, feed_16to8_free, feed_16to8le };
180186690Sobrien
181186690Sobrien/*****************************************************************************/
182186690Sobrien
183267843Sdelphijstatic int
184267843Sdelphijfeed_monotostereo8(pcm_feeder *f, pcm_channel *c, u_int8_t *b, u_int32_t count, struct uio *stream)
185186690Sobrien{
186186690Sobrien	int i, j, k = f->source->feed(f->source, c, b, count / 2, stream);
187186690Sobrien	j = k - 1;
188186690Sobrien	i = j * 2 + 1;
189186690Sobrien	while (i > 0 && j >= 0) {
190133359Sobrien		b[i--] = b[j];
191186690Sobrien		b[i--] = b[j];
192186690Sobrien		j--;
193186690Sobrien	}
194186690Sobrien	return k * 2;
195186690Sobrien}
196186690Sobrienstatic pcm_feeder feeder_monotostereo8 =
197186690Sobrien	{ "monotostereo8", 0, NULL, NULL, feed_monotostereo8 };
198186690Sobrien
199186690Sobrien/*****************************************************************************/
200186690Sobrien
201186690Sobrienstatic int
20268349Sobrienfeed_stereotomono8_init(pcm_feeder *f)
203186690Sobrien{
204267843Sdelphij	f->data = malloc(FEEDBUFSZ, M_DEVBUF, M_NOWAIT);
205267843Sdelphij	return (f->data == NULL);
206186690Sobrien}
207186690Sobrien
208186690Sobrienstatic int
209186690Sobrienfeed_stereotomono8_free(pcm_feeder *f)
210186690Sobrien{
211186690Sobrien	if (f->data) free(f->data, M_DEVBUF);
212186690Sobrien	f->data = NULL;
213186690Sobrien	return 0;
214186690Sobrien}
21568349Sobrien
21668349Sobrienstatic int
217186690Sobrienfeed_stereotomono8(pcm_feeder *f, pcm_channel *c, u_int8_t *b, u_int32_t count, struct uio *stream)
218186690Sobrien{
219186690Sobrien	u_int32_t i = 0, toget = count * 2;
220186690Sobrien	int j = 0, k;
221186690Sobrien	k = f->source->feed(f->source, c, f->data, min(toget, FEEDBUFSZ), stream);
222186690Sobrien	while (j < k) {
223186690Sobrien		b[i++] = ((u_int8_t *)f->data)[j];
224186690Sobrien		j += 2;
225186690Sobrien	}
226186690Sobrien	return i;
227186690Sobrien}
228186690Sobrienstatic pcm_feeder feeder_stereotomono8 =
229186690Sobrien	{ "stereotomono8", 1, feed_stereotomono8_init, feed_stereotomono8_free,
230186690Sobrien	feed_stereotomono8 };
231186690Sobrien
232186690Sobrien/*****************************************************************************/
23368349Sobrien
23468349Sobrienstatic int
23568349Sobrienfeed_endian(pcm_feeder *f, pcm_channel *c, u_int8_t *b, u_int32_t count, struct uio *stream)
236186690Sobrien{
237186690Sobrien	u_int8_t t;
238186690Sobrien	int i = 0, j = f->source->feed(f->source, c, b, count, stream);
239186690Sobrien	while (i < j) {
240186690Sobrien		t = b[i];
241186690Sobrien		b[i] = b[i + 1];
242186690Sobrien		b[i + 1] = t;
243186690Sobrien		i += 2;
244186690Sobrien	}
245186690Sobrien	return i;
246186690Sobrien}
247186690Sobrienstatic pcm_feeder feeder_endian = { "endian", -1, NULL, NULL, feed_endian };
248159764Sobrien
24968349Sobrien/*****************************************************************************/
25068349Sobrien
25168349Sobrienstatic int
25268349Sobrienfeed_sign(pcm_feeder *f, pcm_channel *c, u_int8_t *b, u_int32_t count, struct uio *stream)
25368349Sobrien{
254186690Sobrien	int i = 0, j = f->source->feed(f->source, c, b, count, stream);
25568349Sobrien	int ssz = (int)f->data, ofs = ssz - 1;
25668349Sobrien	while (i < j) {
25768349Sobrien		b[i + ofs] ^= 0x80;
25868349Sobrien		i += ssz;
25968349Sobrien	}
26068349Sobrien	return i;
26168349Sobrien}
26268349Sobrienstatic pcm_feeder feeder_sign8 =
26368349Sobrien	{ "sign8", 0, NULL, NULL, feed_sign, (void *)1 };
26468349Sobrienstatic pcm_feeder feeder_sign16 =
26568349Sobrien	{ "sign16", -1, NULL, NULL, feed_sign, (void *)2 };
26668349Sobrien
26768349Sobrien/*****************************************************************************/
268186690Sobrien
269186690Sobrienstatic int
270186690Sobrienfeed_table(pcm_feeder *f, pcm_channel *c, u_int8_t *b, u_int32_t count, struct uio *stream)
271186690Sobrien{
272186690Sobrien	int i = 0, j = f->source->feed(f->source, c, b, count, stream);
273186690Sobrien	while (i < j) {
274186690Sobrien		b[i] = ((u_int8_t *)f->data)[b[i]];
275186690Sobrien		i++;
27668349Sobrien	}
27768349Sobrien	return i;
27868349Sobrien}
27968349Sobrienstatic pcm_feeder feeder_ulawtou8 =
28068349Sobrien	{ "ulawtou8", 0, NULL, NULL, feed_table, ulaw_to_u8 };
28168349Sobrienstatic pcm_feeder feeder_u8toulaw =
28268349Sobrien	{ "u8toulaw", 0, NULL, NULL, feed_table, u8_to_ulaw };
28368349Sobrien
284103373Sobrien/*****************************************************************************/
285103373Sobrien
286103373Sobrienstruct fmtspec {
287103373Sobrien	int stereo;
288103373Sobrien	int sign;
289186690Sobrien	int bit16;
290103373Sobrien	int bigendian;
291103373Sobrien	int ulaw;
292103373Sobrien	int bad;
293103373Sobrien};
294103373Sobrien
295226048Sobrienstruct fmtcvt {
296226048Sobrien	pcm_feeder *f;
297226048Sobrien	struct fmtspec ispec, ospec;
298226048Sobrien};
299226048Sobrien
300159764Sobrienstruct fmtcvt cvttab[] = {
301133359Sobrien	{&feeder_ulawtou8, 	{-1,  0, 0, 0,  1}, 	{-1,  0, 0, 0,  0}},
302186690Sobrien	{&feeder_u8toulaw, 	{-1,  0, 0, 0,  0}, 	{-1,  0, 0, 0,  1}},
303169942Sobrien	{&feeder_sign8,		{-1,  0, 0, 0,  0},	{-1,  1, 0, 0,  0}},
30468349Sobrien	{&feeder_sign8,		{-1,  1, 0, 0,  0},	{-1,  0, 0, 0,  0}},
30568349Sobrien	{&feeder_monotostereo8,	{ 0, -1, 0, 0, -1},	{ 1, -1, 0, 0, -1}},
30668349Sobrien	{&feeder_stereotomono8, { 1, -1, 0, 0, -1},	{ 0, -1, 0, 0, -1}},
307267843Sdelphij	{&feeder_sign16,	{-1,  0, 1, 0,  0},	{-1,  1, 1, 0,  0}},
308133359Sobrien	{&feeder_sign16,	{-1,  1, 1, 0,  0},	{-1,  0, 1, 0,  0}},
309133359Sobrien	{&feeder_8to16,		{-1, -1, 0, 0,  0},	{-1, -1, 1, 0,  0}},
31068349Sobrien	{&feeder_16to8le,	{-1, -1, 1, 0,  0},	{-1, -1, 0, 0,  0}},
311159764Sobrien	{&feeder_endian,	{-1, -1, 1, 0,  0},	{-1, -1, 1, 1,  0}},
312133359Sobrien	{&feeder_endian,	{-1, -1, 1, 1,  0},	{-1, -1, 1, 0,  0}},
313133359Sobrien};
314133359Sobrien#define FEEDERTABSZ (sizeof(cvttab) / sizeof(struct fmtcvt))
315133359Sobrien
316159764Sobrienstatic int
31768349Sobriengetspec(u_int32_t fmt, struct fmtspec *spec)
31868349Sobrien{
31968349Sobrien	spec->stereo = (fmt & AFMT_STEREO)? 1 : 0;
32068349Sobrien	spec->sign = (fmt & AFMT_SIGNED)? 1 : 0;
321267843Sdelphij	spec->bit16 = (fmt & AFMT_16BIT)? 1 : 0;
322133359Sobrien	spec->bigendian = (fmt & AFMT_BIGENDIAN)? 1 : 0;
323133359Sobrien	spec->ulaw = (fmt & AFMT_MU_LAW)? 1 : 0;
324133359Sobrien	spec->bad = (fmt & (AFMT_A_LAW | AFMT_MPEG))? 1 : 0;
325226048Sobrien	return 0;
326226048Sobrien}
327169942Sobrien
328226048Sobrienstatic int
329169942Sobriencmp(int x, int y)
330169942Sobrien{
331169942Sobrien	return (x == -1 || x == y || y == -1)? 1 : 0;
332159764Sobrien}
33368349Sobrien
33468349Sobrienstatic int
33568349Sobriencmpspec(struct fmtspec *x, struct fmtspec *y)
33668349Sobrien{
33768349Sobrien	int i = 0;
33868349Sobrien	if (cmp(x->stereo, y->stereo)) i |= 0x01;
339267843Sdelphij	if (cmp(x->sign, y->sign)) i |= 0x02;
340267843Sdelphij	if (cmp(x->bit16, y->bit16)) i |= 0x04;
341133359Sobrien	if (cmp(x->bigendian, y->bigendian)) i |= 0x08;
342133359Sobrien	if (cmp(x->ulaw, y->ulaw)) i |= 0x10;
343133359Sobrien	return i;
34468349Sobrien}
34568349Sobrien
346133359Sobrienstatic int
34768349Sobriencvtapply(pcm_channel *c, struct fmtcvt *cvt, struct fmtspec *s)
348133359Sobrien{
349186690Sobrien	int i = cmpspec(s, &cvt->ospec);
350133359Sobrien	chn_addfeeder(c, cvt->f);
351133359Sobrien	if (cvt->ospec.stereo != -1) s->stereo = cvt->ospec.stereo;
35268349Sobrien	if (cvt->ospec.sign != -1) s->sign = cvt->ospec.sign;
353133359Sobrien	if (cvt->ospec.bit16 != -1) s->bit16 = cvt->ospec.bit16;
354133359Sobrien	if (cvt->ospec.bigendian != -1) s->bigendian = cvt->ospec.bigendian;
355133359Sobrien	if (cvt->ospec.ulaw != -1) s->ulaw = cvt->ospec.ulaw;
356133359Sobrien	return i;
357133359Sobrien}
358133359Sobrien
359267843Sdelphijint
360267843Sdelphijchn_feedchain(pcm_channel *c)
361267843Sdelphij{
362267843Sdelphij	int i, chosen, iter;
363267843Sdelphij	u_int32_t mask;
364267843Sdelphij	struct fmtspec s, t;
365267843Sdelphij	struct fmtcvt *e;
366267843Sdelphij
367267843Sdelphij	while (chn_removefeeder(c) != -1);
368267843Sdelphij	c->align = 0;
369267843Sdelphij	if ((c->format & chn_getcaps(c)->formats) == c->format)
370267843Sdelphij		return c->format;
371267843Sdelphij	getspec(c->format, &s);
372267843Sdelphij	if (s.bad) return -1;
373267843Sdelphij	getspec(chn_getcaps(c)->bestfmt, &t);
374267843Sdelphij	mask = (~cmpspec(&s, &t)) & 0x1f;
375267843Sdelphij	iter = 0;
376267843Sdelphij	do {
377267843Sdelphij		if (mask == 0 || iter >= 8) break;
378267843Sdelphij		chosen = -1;
379267843Sdelphij		for (i = 0; i < FEEDERTABSZ && chosen == -1; i++) {
380267843Sdelphij			e = &cvttab[i];
381267843Sdelphij			if ((cmpspec(&s, &e->ispec) == 0x1f) &&
382267843Sdelphij			   ((~cmpspec(&e->ispec, &e->ospec)) & mask))
383267843Sdelphij			   chosen = i;
384267843Sdelphij		}
385267843Sdelphij		if (chosen != -1) mask &= cvtapply(c, &cvttab[chosen], &s);
386267843Sdelphij		iter++;
387267843Sdelphij	} while (chosen != -1);
388267843Sdelphij	return (iter < 8)? chn_getcaps(c)->bestfmt : -1;
389267843Sdelphij}
390267843Sdelphij
391267843Sdelphijstatic int
392267843Sdelphijchn_addfeeder(pcm_channel *c, pcm_feeder *f)
393267843Sdelphij{
394267843Sdelphij	pcm_feeder *n;
395267843Sdelphij	n = malloc(sizeof(pcm_feeder), M_DEVBUF, M_NOWAIT);
396267843Sdelphij	*n = *f;
397267843Sdelphij	n->source = c->feeder;
398267843Sdelphij	c->feeder = n;
399267843Sdelphij	if (n->init) n->init(n);
400267843Sdelphij	if (n->align > 0) c->align += n->align;
401267843Sdelphij	else if (n->align < 0 && c->align < -n->align) c->align -= n->align;
402267843Sdelphij	return 0;
403267843Sdelphij}
404267843Sdelphij
405267843Sdelphijstatic int
406267843Sdelphijchn_removefeeder(pcm_channel *c)
407267843Sdelphij{
408267843Sdelphij	pcm_feeder *f;
409267843Sdelphij	if (c->feeder == &feeder_root) return -1;
410267843Sdelphij	f = c->feeder->source;
411267843Sdelphij	if (c->feeder->free) c->feeder->free(c->feeder);
412267843Sdelphij	free(c->feeder, M_DEVBUF);
413267843Sdelphij	c->feeder = f;
414267843Sdelphij	return 0;
415267843Sdelphij}
416267843Sdelphij
417267843Sdelphij