diff options
Diffstat (limited to 'sys/dev/sound/pcm')
-rw-r--r-- | sys/dev/sound/pcm/channel.c | 483 | ||||
-rw-r--r-- | sys/dev/sound/pcm/channel_if.m | 13 | ||||
-rw-r--r-- | sys/dev/sound/pcm/feeder_fmt.c | 1981 |
3 files changed, 1225 insertions, 1252 deletions
diff --git a/sys/dev/sound/pcm/channel.c b/sys/dev/sound/pcm/channel.c index b3ac7ba4..d099e8b 100644 --- a/sys/dev/sound/pcm/channel.c +++ b/sys/dev/sound/pcm/channel.c @@ -39,13 +39,20 @@ SND_DECLARE_FILE("$FreeBSD$"); #define DMA_ALIGN_MASK (~(DMA_ALIGN_THRESHOLD - 1)) #endif -#define CANCHANGE(c) (!(c->flags & CHN_F_TRIGGERED)) +#define CHN_STARTED(c) ((c)->flags & CHN_F_TRIGGERED) +#define CHN_STOPPED(c) (!CHN_STARTED(c)) +#define CHN_DIRSTR(c) (((c)->direction == PCMDIR_PLAY) ? \ + "PCMDIR_PLAY" : "PCMDIR_REC") #define BUF_PARENT(c, b) \ (((c) != NULL && (c)->parentchannel != NULL && \ (c)->parentchannel->bufhard != NULL) ? \ (c)->parentchannel->bufhard : (b)) +#define CHN_TIMEOUT 5 +#define CHN_TIMEOUT_MIN 1 +#define CHN_TIMEOUT_MAX 10 + /* #define DEB(x) x */ @@ -96,6 +103,40 @@ SYSCTL_PROC(_hw_snd, OID_AUTO, latency_profile, CTLTYPE_INT | CTLFLAG_RW, 0, sizeof(int), sysctl_hw_snd_latency_profile, "I", "buffering latency profile (0=aggresive 1=safe)"); +static int chn_timeout = CHN_TIMEOUT; + +#ifdef SND_DEBUG +static int +sysctl_hw_snd_timeout(SYSCTL_HANDLER_ARGS) +{ + int err, val; + + val = chn_timeout; + err = sysctl_handle_int(oidp, &val, sizeof(val), req); + if (val < CHN_TIMEOUT_MIN || val > CHN_TIMEOUT_MAX) + err = EINVAL; + else + chn_timeout = val; + + return err; +} +SYSCTL_PROC(_hw_snd, OID_AUTO, timeout, CTLTYPE_INT | CTLFLAG_RW, + 0, sizeof(int), sysctl_hw_snd_timeout, "I", + "interrupt timeout (1 - 10)"); +#endif + +static int chn_usefrags = 0; +TUNABLE_INT("hw.snd.usefrags", &chn_usefrags); +static int chn_syncdelay = -1; +TUNABLE_INT("hw.snd.syncdelay", &chn_syncdelay); +#ifdef SND_DEBUG +SYSCTL_INT(_hw_snd, OID_AUTO, usefrags, CTLFLAG_RW, + &chn_usefrags, 1, "prefer setfragments() over setblocksize()"); +SYSCTL_INT(_hw_snd, OID_AUTO, syncdelay, CTLFLAG_RW, + &chn_syncdelay, 1, + "append (0-1000) millisecond trailing buffer delay on each sync"); +#endif + /** * @brief Channel sync group lock * @@ -193,6 +234,7 @@ chn_wakeup(struct pcm_channel *c) if (SLIST_EMPTY(&c->children)) { if (SEL_WAITING(sndbuf_getsel(bs)) && chn_polltrigger(c)) selwakeuppri(sndbuf_getsel(bs), PRIBIO); + wakeup_one(bs); } else { SLIST_FOREACH(pce, &c->children, link) { CHN_LOCK(pce->channel); @@ -200,8 +242,6 @@ chn_wakeup(struct pcm_channel *c) CHN_UNLOCK(pce->channel); } } - - wakeup_one(bs); } static int @@ -247,22 +287,21 @@ chn_dmaupdate(struct pcm_channel *c) ); if (c->direction == PCMDIR_PLAY) { - amt = MIN(delta, sndbuf_getready(b)); + amt = min(delta, sndbuf_getready(b)); amt -= amt % sndbuf_getbps(b); if (amt > 0) sndbuf_dispose(b, NULL, amt); } else { - amt = MIN(delta, sndbuf_getfree(b)); + amt = min(delta, sndbuf_getfree(b)); amt -= amt % sndbuf_getbps(b); if (amt > 0) sndbuf_acquire(b, NULL, amt); } - if (snd_verbose > 2 && (c->flags & CHN_F_TRIGGERED) && delta == 0) { - device_printf(c->dev, "WARNING: PCMDIR_%s DMA completion " + if (snd_verbose > 3 && CHN_STARTED(c) && delta == 0) { + device_printf(c->dev, "WARNING: %s DMA completion " "too fast/slow ! hwptr=%u, old=%u " "delta=%u amt=%u ready=%u free=%u\n", - (c->direction == PCMDIR_PLAY) ? "PLAY" : "REC", - hwptr, old, delta, amt, + CHN_DIRSTR(c), hwptr, old, delta, amt, sndbuf_getready(b), sndbuf_getfree(b)); } @@ -277,7 +316,7 @@ chn_wrupdate(struct pcm_channel *c) CHN_LOCKASSERT(c); KASSERT(c->direction == PCMDIR_PLAY, ("chn_wrupdate on bad channel")); - if ((c->flags & (CHN_F_MAPPED | CHN_F_VIRTUAL)) || !(c->flags & CHN_F_TRIGGERED)) + if ((c->flags & (CHN_F_MAPPED | CHN_F_VIRTUAL)) || CHN_STOPPED(c)) return; chn_dmaupdate(c); ret = chn_wrfeed(c); @@ -321,8 +360,11 @@ chn_wrfeed(struct pcm_channel *c) if (sndbuf_getfree(b) > 0) c->xruns++; +#if 0 if (ret == 0 && sndbuf_getfree(b) < amt) chn_wakeup(c); +#endif + chn_wakeup(c); return ret; } @@ -353,76 +395,59 @@ chn_wrintr(struct pcm_channel *c) int chn_write(struct pcm_channel *c, struct uio *buf) { - int ret, count, sz; struct snd_dbuf *bs = c->bufsoft; void *off; - int t, x, togo, p; + int ret, timeout, sz, t, p; CHN_LOCKASSERT(c); ret = 0; - count = hz; - - while (!ret && (buf->uio_resid > 0) && (count > 0)) { - sz = sndbuf_getfree(bs); - if (sz == 0) { - if (c->flags & CHN_F_NBIO) - ret = EWOULDBLOCK; - else if (c->flags & CHN_F_NOTRIGGER) { - /** - * @todo Evaluate whether EAGAIN is truly desirable. - * 4Front drivers behave like this, but I'm - * not sure if it at all violates the "write - * should be allowed to block" model. - * - * The idea is that, while set with CHN_F_NOTRIGGER, - * a channel isn't playing, *but* without this we - * end up with "interrupt timeout / channel dead". - */ - ret = EAGAIN; - } else { - ret = chn_sleep(c, "pcmwr", c->timeout); - if (ret == EWOULDBLOCK) { - count -= c->timeout; - ret = 0; - } else if (ret == ERESTART || ret == EINTR) { - c->flags |= CHN_F_ABORTING; - return ret; - } else if (ret == 0) - count = hz; - } - } else { - sz = MIN(sz, buf->uio_resid); - KASSERT(sz > 0, ("confusion in chn_write")); - /* printf("sz: %d\n", sz); */ + timeout = chn_timeout * hz; + while (ret == 0 && buf->uio_resid > 0) { + sz = min(buf->uio_resid, sndbuf_getfree(bs)); + if (sz > 0) { /* * The following assumes that the free space in * the buffer can never be less around the * unlock-uiomove-lock sequence. */ - togo = sz; - while (ret == 0 && togo > 0) { + while (ret == 0 && sz > 0) { p = sndbuf_getfreeptr(bs); - t = MIN(togo, sndbuf_getsize(bs) - p); + t = min(sz, sndbuf_getsize(bs) - p); off = sndbuf_getbufofs(bs, p); CHN_UNLOCK(c); ret = uiomove(off, t, buf); CHN_LOCK(c); - togo -= t; - x = sndbuf_acquire(bs, NULL, t); + sz -= t; + sndbuf_acquire(bs, NULL, t); } ret = 0; - if (!(c->flags & CHN_F_TRIGGERED)) + if (CHN_STOPPED(c)) chn_start(c, 0); + } else if (c->flags & (CHN_F_NBIO | CHN_F_NOTRIGGER)) { + /** + * @todo Evaluate whether EAGAIN is truly desirable. + * 4Front drivers behave like this, but I'm + * not sure if it at all violates the "write + * should be allowed to block" model. + * + * The idea is that, while set with CHN_F_NOTRIGGER, + * a channel isn't playing, *but* without this we + * end up with "interrupt timeout / channel dead". + */ + ret = EAGAIN; + } else { + ret = chn_sleep(c, "pcmwr", timeout); + if (ret == EAGAIN) { + ret = EINVAL; + c->flags |= CHN_F_DEAD; + printf("%s: play interrupt timeout, " + "channel dead\n", c->name); + } else if (ret == ERESTART || ret == EINTR) + c->flags |= CHN_F_ABORTING; } } - /* printf("ret: %d left: %d\n", ret, buf->uio_resid); */ - - if (count <= 0) { - c->flags |= CHN_F_DEAD; - printf("%s: play interrupt timeout, channel dead\n", c->name); - } return ret; } @@ -490,7 +515,7 @@ chn_rdupdate(struct pcm_channel *c) CHN_LOCKASSERT(c); KASSERT(c->direction == PCMDIR_REC, ("chn_rdupdate on bad channel")); - if ((c->flags & CHN_F_MAPPED) || !(c->flags & CHN_F_TRIGGERED)) + if ((c->flags & CHN_F_MAPPED) || CHN_STOPPED(c)) return; chn_trigger(c, PCMTRIG_EMLDMARD); chn_dmaupdate(c); @@ -525,60 +550,51 @@ chn_rdintr(struct pcm_channel *c) int chn_read(struct pcm_channel *c, struct uio *buf) { - int ret, sz, count; struct snd_dbuf *bs = c->bufsoft; void *off; - int t, x, togo, p; + int ret, timeout, sz, t, p; CHN_LOCKASSERT(c); - if (!(c->flags & CHN_F_TRIGGERED)) + + if (CHN_STOPPED(c)) chn_start(c, 0); ret = 0; - count = hz; - while (!ret && (buf->uio_resid > 0) && (count > 0)) { - sz = MIN(buf->uio_resid, sndbuf_getready(bs)); + timeout = chn_timeout * hz; + while (ret == 0 && buf->uio_resid > 0) { + sz = min(buf->uio_resid, sndbuf_getready(bs)); if (sz > 0) { /* * The following assumes that the free space in * the buffer can never be less around the * unlock-uiomove-lock sequence. */ - togo = sz; - while (ret == 0 && togo > 0) { + while (ret == 0 && sz > 0) { p = sndbuf_getreadyptr(bs); - t = MIN(togo, sndbuf_getsize(bs) - p); + t = min(sz, sndbuf_getsize(bs) - p); off = sndbuf_getbufofs(bs, p); CHN_UNLOCK(c); ret = uiomove(off, t, buf); CHN_LOCK(c); - togo -= t; - x = sndbuf_dispose(bs, NULL, t); + sz -= t; + sndbuf_dispose(bs, NULL, t); } ret = 0; - } else { - if (c->flags & CHN_F_NBIO) - ret = EWOULDBLOCK; - else { - ret = chn_sleep(c, "pcmrd", c->timeout); - if (ret == EWOULDBLOCK) { - count -= c->timeout; - ret = 0; - } else if (ret == ERESTART || ret == EINTR) { - c->flags |= CHN_F_ABORTING; - return ret; - } else - count = hz; - } + } else if (c->flags & (CHN_F_NBIO | CHN_F_NOTRIGGER)) + ret = EAGAIN; + else { + ret = chn_sleep(c, "pcmrd", timeout); + if (ret == EAGAIN) { + ret = EINVAL; + c->flags |= CHN_F_DEAD; + printf("%s: record interrupt timeout, " + "channel dead\n", c->name); + } else if (ret == ERESTART || ret == EINTR) + c->flags |= CHN_F_ABORTING; } } - if (count <= 0) { - c->flags |= CHN_F_DEAD; - printf("%s: record interrupt timeout, channel dead\n", c->name); - } - return ret; } @@ -603,7 +619,7 @@ chn_start(struct pcm_channel *c, int force) CHN_LOCKASSERT(c); /* if we're running, or if we're prevented from triggering, bail */ - if ((c->flags & CHN_F_TRIGGERED) || ((c->flags & CHN_F_NOTRIGGER) && !force)) + if (CHN_STARTED(c) || ((c->flags & CHN_F_NOTRIGGER) && !force)) return EINVAL; if (force) { @@ -612,20 +628,22 @@ chn_start(struct pcm_channel *c, int force) } else { if (c->direction == PCMDIR_REC) { i = sndbuf_getfree(bs); - j = sndbuf_getready(b); + j = (i > 0) ? 1 : sndbuf_getready(b); } else { - struct snd_dbuf *pb; - - i = sndbuf_getready(bs); + if (sndbuf_getfree(bs) == 0) { + i = 1; + j = 0; + } else { + struct snd_dbuf *pb; - pb = BUF_PARENT(c, b); - j = min(sndbuf_xbytes(sndbuf_getsize(pb), pb, bs), - sndbuf_getsize(bs)); + pb = BUF_PARENT(c, b); + i = sndbuf_xbytes(sndbuf_getready(bs), bs, pb); + j = sndbuf_getbps(pb); + } } if (snd_verbose > 3 && SLIST_EMPTY(&c->children)) - printf("%s: PCMDIR_%s (%s) threshold i=%d j=%d\n", - __func__, - (c->direction == PCMDIR_PLAY) ? "PLAY" : "REC", + printf("%s: %s (%s) threshold i=%d j=%d\n", + __func__, CHN_DIRSTR(c), (c->flags & CHN_F_VIRTUAL) ? "virtual" : "hardware", i, j); } @@ -637,17 +655,20 @@ chn_start(struct pcm_channel *c, int force) c->interrupts = 0; c->xruns = 0; if (c->direction == PCMDIR_PLAY && c->parentchannel == NULL) { - chn_wrfeed(c); + sndbuf_fillsilence(b); if (snd_verbose > 3) printf("%s: %s starting! (%s) (ready=%d " - "force=%d i=%d j=%d intrtimeout=%u)\n", + "force=%d i=%d j=%d intrtimeout=%u " + "latency=%dms)\n", __func__, (c->flags & CHN_F_HAS_VCHAN) ? "VCHAN" : "HW", (c->flags & CHN_F_CLOSING) ? "closing" : "running", sndbuf_getready(b), - force, i, j, c->timeout); + force, i, j, c->timeout, + (sndbuf_getsize(b) * 1000) / + (sndbuf_getbps(b) * sndbuf_getspd(b))); } chn_trigger(c, PCMTRIG_START); return 0; @@ -677,20 +698,22 @@ chn_sync(struct pcm_channel *c, int threshold) { int ret, count, hcount, minflush, resid, residp; struct snd_dbuf *b, *bs; + int syncdelay, blksz; CHN_LOCKASSERT(c); - if (c->flags & (CHN_F_DEAD | CHN_F_ABORTING)) + bs = c->bufsoft; + + if ((c->flags & (CHN_F_DEAD | CHN_F_ABORTING)) || + (threshold < 1 && sndbuf_getready(bs) < 1)) return 0; if (c->direction != PCMDIR_PLAY) return EINVAL; - bs = c->bufsoft; - /* if we haven't yet started and nothing is buffered, else start*/ - if (!(c->flags & CHN_F_TRIGGERED)) { - if (sndbuf_getready(bs) > 0) { + if (CHN_STOPPED(c)) { + if (threshold > 0 || sndbuf_getready(bs) > 0) { ret = chn_start(c, 1); if (ret) return ret; @@ -700,8 +723,22 @@ chn_sync(struct pcm_channel *c, int threshold) b = BUF_PARENT(c, c->bufhard); - threshold += sndbuf_getready(b); - minflush = sndbuf_xbytes(threshold, b, bs); + minflush = threshold + sndbuf_xbytes(sndbuf_getready(b), b, bs); + + syncdelay = chn_syncdelay; + + if (syncdelay < 0 && (threshold > 0 || sndbuf_getready(bs) > 0)) + minflush += sndbuf_xbytes(sndbuf_getsize(b), b, bs); + + /* + * Append (0-1000) millisecond trailing buffer (if needed) + * for slower / high latency hardwares (notably USB audio) + * to avoid audible truncation. + */ + if (syncdelay > 0) + minflush += (sndbuf_getbps(bs) * sndbuf_getspd(bs) * + ((syncdelay > 1000) ? 1000 : syncdelay)) / 1000; + minflush -= minflush % sndbuf_getbps(bs); if (minflush > 0) { @@ -713,17 +750,32 @@ chn_sync(struct pcm_channel *c, int threshold) resid = sndbuf_getready(bs); residp = resid; - count = sndbuf_xbytes(minflush + resid, bs, b) / sndbuf_getblksz(b); + blksz = sndbuf_getblksz(b); + if (blksz < 1) { + printf("%s: WARNING: blksz < 1 ! maxsize=%d [%d/%d/%d]\n", + __func__, sndbuf_getmaxsize(b), sndbuf_getsize(b), + sndbuf_getblksz(b), sndbuf_getblkcnt(b)); + if (sndbuf_getblkcnt(b) > 0) + blksz = sndbuf_getsize(b) / sndbuf_getblkcnt(b); + if (blksz < 1) + blksz = 1; + } + count = sndbuf_xbytes(minflush + resid, bs, b) / blksz; hcount = count; ret = 0; - while (count > 0 && resid > 0) { + if (snd_verbose > 3) + printf("%s: [begin] timeout=%d count=%d " + "minflush=%d resid=%d\n", __func__, c->timeout, count, + minflush, resid); + + while (count > 0 && (resid > 0 || minflush > 0)) { ret = chn_sleep(c, "pcmsyn", c->timeout); if (ret == ERESTART || ret == EINTR) { c->flags |= CHN_F_ABORTING; break; } - if (ret == 0 || ret == EWOULDBLOCK) { + if (ret == 0 || ret == EAGAIN) { resid = sndbuf_getready(bs); if (resid == residp) { --count; @@ -771,7 +823,7 @@ chn_poll(struct pcm_channel *c, int ev, struct thread *td) int ret; CHN_LOCKASSERT(c); - if (!(c->flags & CHN_F_MAPPED) && !(c->flags & CHN_F_TRIGGERED)) + if (!(c->flags & (CHN_F_MAPPED | CHN_F_TRIGGERED))) chn_start(c, 1); ret = 0; if (chn_polltrigger(c) && chn_pollreset(c)) @@ -795,7 +847,7 @@ chn_abort(struct pcm_channel *c) struct snd_dbuf *bs = c->bufsoft; CHN_LOCKASSERT(c); - if (!(c->flags & CHN_F_TRIGGERED)) + if (CHN_STOPPED(c)) return 0; c->flags |= CHN_F_ABORTING; @@ -805,7 +857,7 @@ chn_abort(struct pcm_channel *c) sndbuf_setrun(b, 0); if (!(c->flags & CHN_F_VIRTUAL)) chn_dmaupdate(c); - missing = sndbuf_getready(bs) + sndbuf_getready(b); + missing = sndbuf_getready(bs); c->flags &= ~CHN_F_ABORTING; return missing; @@ -1130,7 +1182,7 @@ chn_kill(struct pcm_channel *c) struct snd_dbuf *b = c->bufhard; struct snd_dbuf *bs = c->bufsoft; - if (c->flags & CHN_F_TRIGGERED) + if (CHN_STARTED(c)) chn_trigger(c, PCMTRIG_ABORT); while (chn_removefeeder(c) == 0); if (CHANNEL_FREE(c->methods, c->devinfo)) @@ -1193,6 +1245,28 @@ round_pow2(u_int32_t v) return ret; } +static u_int32_t +round_blksz(u_int32_t v, int round) +{ + u_int32_t ret, tmp; + + if (round < 1) + round = 1; + + ret = min(round_pow2(v), CHN_2NDBUFMAXSIZE >> 1); + + if (ret > v && (ret >> 1) > 0 && (ret >> 1) >= ((v * 3) >> 2)) + ret >>= 1; + + tmp = ret - (ret % round); + while (tmp < 16 || tmp < round) { + ret <<= 1; + tmp = ret - (ret % round); + } + + return ret; +} + /* * 4Front call it DSP Policy, while we call it "Latency Profile". The idea * is to keep 2nd buffer short so that it doesn't cause long queue during @@ -1285,19 +1359,18 @@ static int chn_calclatency(int dir, int latency, int bps, u_int32_t datarate, u_int32_t max, int *rblksz, int *rblkcnt) { - u_int32_t bufsz; - int blksz, blkcnt; - static int pblkcnts[CHN_LATENCY_PROFILE_MAX+1][CHN_LATENCY_MAX+1] = + static int pblkcnts[CHN_LATENCY_PROFILE_MAX + 1][CHN_LATENCY_MAX + 1] = CHN_LATENCY_PBLKCNT_REF; - static int pbufszs[CHN_LATENCY_PROFILE_MAX+1][CHN_LATENCY_MAX+1] = + static int pbufszs[CHN_LATENCY_PROFILE_MAX + 1][CHN_LATENCY_MAX + 1] = CHN_LATENCY_PBUFSZ_REF; - static int rblkcnts[CHN_LATENCY_PROFILE_MAX+1][CHN_LATENCY_MAX+1] = + static int rblkcnts[CHN_LATENCY_PROFILE_MAX + 1][CHN_LATENCY_MAX + 1] = CHN_LATENCY_RBLKCNT_REF; - static int rbufszs[CHN_LATENCY_PROFILE_MAX+1][CHN_LATENCY_MAX+1] = + static int rbufszs[CHN_LATENCY_PROFILE_MAX + 1][CHN_LATENCY_MAX + 1] = CHN_LATENCY_RBUFSZ_REF; + u_int32_t bufsz; + int lprofile, blksz, blkcnt; - if (CHN_LATENCY_MIN != 0 || CHN_LATENCY_MAX != 10 || - latency < CHN_LATENCY_MIN || latency > CHN_LATENCY_MAX || + if (latency < CHN_LATENCY_MIN || latency > CHN_LATENCY_MAX || bps < 1 || datarate < 1 || !(dir == PCMDIR_PLAY || dir == PCMDIR_REC)) { if (rblksz != NULL) @@ -1310,24 +1383,22 @@ chn_calclatency(int dir, int latency, int bps, u_int32_t datarate, return CHN_2NDBUFMAXSIZE; } + lprofile = chn_latency_profile; + if (dir == PCMDIR_PLAY) { - blkcnt = pblkcnts[chn_latency_profile][latency]; - bufsz = pbufszs[chn_latency_profile][latency]; + blkcnt = pblkcnts[lprofile][latency]; + bufsz = pbufszs[lprofile][latency]; } else { - blkcnt = rblkcnts[chn_latency_profile][latency]; - bufsz = rbufszs[chn_latency_profile][latency]; + blkcnt = rblkcnts[lprofile][latency]; + bufsz = rbufszs[lprofile][latency]; } - bufsz = snd_xbytes(1 << bufsz, CHN_LATENCY_DATA_REF, datarate); + + bufsz = round_pow2(snd_xbytes(1 << bufsz, CHN_LATENCY_DATA_REF, + datarate)); if (bufsz > max) bufsz = max; - if (bufsz < 32) - bufsz = 32; - blksz = bufsz >> blkcnt; - blksz -= blksz % bps; - while (blksz < 16 || blksz < bps) - blksz += bps; - while ((blksz << blkcnt) > bufsz && blkcnt > 1) - blkcnt--; + blksz = round_blksz(bufsz >> blkcnt, bps); + if (rblksz != NULL) *rblksz = blksz; if (rblkcnt != NULL) @@ -1336,22 +1407,17 @@ chn_calclatency(int dir, int latency, int bps, u_int32_t datarate, return blksz << blkcnt; } -/* - * Note that there is no strict requirement to align blksz to the - * nearest ^2, except for hardware CHANNEL_SETBLOCKSIZE. If the application - * trying to act smarter and requesting for specific blksz/blkcnt, so be it. - */ static int chn_resizebuf(struct pcm_channel *c, int latency, int blkcnt, int blksz) { struct snd_dbuf *b, *bs, *pb; - int sblksz, sblkcnt, hblksz, limit = 1; + int sblksz, sblkcnt, hblksz, hblkcnt, limit = 1; int ret; CHN_LOCKASSERT(c); - if (!CANCHANGE(c) || (c->flags & CHN_F_MAPPED) || + if ((c->flags & (CHN_F_MAPPED | CHN_F_TRIGGERED)) || !(c->direction == PCMDIR_PLAY || c->direction == PCMDIR_REC)) return EINVAL; @@ -1399,14 +1465,8 @@ chn_resizebuf(struct pcm_channel *c, int latency, * defeat the purpose of having custom control. The least * we can do is round it to the nearest ^2 and align it. */ - sblksz = round_pow2(blksz); - sblksz -= sblksz % sndbuf_getbps(bs); - sblkcnt = blkcnt; - while (sblksz < 16 || sblksz < sndbuf_getbps(bs)) - sblksz += sndbuf_getbps(bs); - if (snd_verbose > 3 && !(blksz == 0 || blkcnt == -1)) - printf("%s: requested blksz=%d blkcnt=%d -> %d/%d\n", - __func__, blksz, blkcnt, sblksz, sblkcnt); + sblksz = round_blksz(blksz, sndbuf_getbps(bs)); + sblkcnt = round_pow2(blkcnt); limit = 0; } @@ -1419,39 +1479,48 @@ chn_resizebuf(struct pcm_channel *c, int latency, sndbuf_xbytes(sndbuf_getsize(pb), pb, bs) : 0; c->timeout = c->parentchannel->timeout; } else { + hblkcnt = 2; if (c->flags & CHN_F_HAS_SIZE) { - hblksz = sndbuf_xbytes(sblksz, bs, b); - if (snd_verbose > 3) - printf("%s: sblksz=%d -> hblksz=%d\n", - __func__, sblksz, hblksz); + hblksz = round_blksz(sndbuf_xbytes(sblksz, bs, b), + sndbuf_getbps(b)); + hblkcnt = round_pow2(sndbuf_getblkcnt(bs)); } else chn_calclatency(c->direction, latency, sndbuf_getbps(b), sndbuf_getbps(b) * sndbuf_getspd(b), - CHN_2NDBUFMAXSIZE, &hblksz, NULL); + CHN_2NDBUFMAXSIZE, &hblksz, &hblkcnt); - hblksz = round_pow2(hblksz); if ((hblksz << 1) > sndbuf_getmaxsize(b)) - hblksz = sndbuf_getmaxsize(b) >> 1; + hblksz = round_blksz(sndbuf_getmaxsize(b) >> 1, + sndbuf_getbps(b)); + + while ((hblksz * hblkcnt) > sndbuf_getmaxsize(b)) { + if (hblkcnt < 4) + hblksz >>= 1; + else + hblkcnt >>= 1; + } + hblksz -= hblksz % sndbuf_getbps(b); - while (hblksz < 16 || hblksz < sndbuf_getbps(b)) - hblksz += sndbuf_getbps(b); #if 0 hblksz = sndbuf_getmaxsize(b) >> 1; + hblksz -= hblksz % sndbuf_getbps(b); + hblkcnt = 2; #endif + CHN_UNLOCK(c); - sndbuf_setblksz(b, CHANNEL_SETBLOCKSIZE(c->methods, - c->devinfo, hblksz)); + if (chn_usefrags == 0 || + CHANNEL_SETFRAGMENTS(c->methods, c->devinfo, + hblksz, hblkcnt) < 1) + sndbuf_setblksz(b, CHANNEL_SETBLOCKSIZE(c->methods, + c->devinfo, hblksz)); CHN_LOCK(c); if (!SLIST_EMPTY(&c->children)) { - /* - * Virtual channels underneath. Set the biggest - * possible value for their mixing space. - */ - sblksz = CHN_2NDBUFMAXSIZE >> 1; - sblksz -= sblksz % sndbuf_getbps(bs); + sblksz = round_blksz( + sndbuf_xbytes(sndbuf_getsize(b) >> 1, b, bs), + sndbuf_getbps(bs)); sblkcnt = 2; limit = 0; } else if (limit != 0) @@ -1460,24 +1529,34 @@ chn_resizebuf(struct pcm_channel *c, int latency, /* * Interrupt timeout */ - c->timeout = ((u_int64_t)hz * sndbuf_getblksz(b)) / + c->timeout = ((u_int64_t)hz * sndbuf_getsize(b)) / ((u_int64_t)sndbuf_getspd(b) * sndbuf_getbps(b)); if (c->timeout < 1) c->timeout = 1; - c->timeout <<= 1; } if (limit > CHN_2NDBUFMAXSIZE) limit = CHN_2NDBUFMAXSIZE; - hblksz = sblksz; - while ((sblksz * sblkcnt) < limit) { - sblksz += hblksz; - if ((sblksz * sblkcnt) > CHN_2NDBUFMAXSIZE) { - sblksz -= hblksz; +#if 0 + while (limit > 0 && (sblksz * sblkcnt) > limit) { + if (sblkcnt < 4) break; - } + sblkcnt >>= 1; } +#endif + + while ((sblksz * sblkcnt) < limit) + sblkcnt <<= 1; + + while ((sblksz * sblkcnt) > CHN_2NDBUFMAXSIZE) { + if (sblkcnt < 4) + sblksz >>= 1; + else + sblkcnt >>= 1; + } + + sblksz -= sblksz % sndbuf_getbps(bs); if (sndbuf_getblkcnt(bs) != sblkcnt || sndbuf_getblksz(bs) != sblksz || sndbuf_getsize(bs) != (sblkcnt * sblksz)) { @@ -1497,9 +1576,9 @@ chn_resizebuf(struct pcm_channel *c, int latency, chn_resetbuf(c); if (snd_verbose > 3) - printf("%s: PCMDIR_%s (%s) timeout=%u " + printf("%s: %s (%s) timeout=%u " "b[%d/%d/%d] bs[%d/%d/%d] limit=%d\n", - __func__, (c->direction == PCMDIR_REC) ? "REC" : "PLAY", + __func__, CHN_DIRSTR(c), (c->flags & CHN_F_VIRTUAL) ? "virtual" : "hardware", c->timeout, sndbuf_getsize(b), sndbuf_getblksz(b), @@ -1540,7 +1619,7 @@ chn_tryspeed(struct pcm_channel *c, int speed) DEB(printf("want speed %d, ", speed)); if (speed <= 0) return EINVAL; - if (CANCHANGE(c)) { + if (CHN_STOPPED(c)) { r = 0; c->speed = speed; sndbuf_setspd(bs, speed); @@ -1622,7 +1701,7 @@ chn_tryformat(struct pcm_channel *c, u_int32_t fmt) int r; CHN_LOCKASSERT(c); - if (CANCHANGE(c)) { + if (CHN_STOPPED(c)) { DEB(printf("want format %d\n", fmt)); c->format = fmt; r = chn_buildfeeder(c); @@ -1702,7 +1781,7 @@ chn_getptr(struct pcm_channel *c) int hwptr; CHN_LOCKASSERT(c); - hwptr = (c->flags & CHN_F_TRIGGERED)? CHANNEL_GETPTR(c->methods, c->devinfo) : 0; + hwptr = (CHN_STARTED(c)) ? CHANNEL_GETPTR(c->methods, c->devinfo) : 0; return (hwptr - (hwptr % sndbuf_getbps(c->bufhard))); } @@ -1744,7 +1823,8 @@ chn_buildfeeder(struct pcm_channel *c) char fmtstr[AFMTSTR_MAXSZ]; CHN_LOCKASSERT(c); - while (chn_removefeeder(c) == 0); + while (chn_removefeeder(c) == 0) + ; KASSERT((c->feeder == NULL), ("feeder chain not empty")); c->align = sndbuf_getalign(c->bufsoft); @@ -1786,10 +1866,16 @@ chn_buildfeeder(struct pcm_channel *c) } c->feederflags &= ~(1 << FEEDER_VOLUME); if (c->direction == PCMDIR_PLAY && - !(c->flags & CHN_F_VIRTUAL) && - c->parentsnddev && (c->parentsnddev->flags & SD_F_SOFTPCMVOL) && - c->parentsnddev->mixer_dev) + !(c->flags & CHN_F_VIRTUAL) && c->parentsnddev && + (c->parentsnddev->flags & SD_F_SOFTPCMVOL) && + c->parentsnddev->mixer_dev) c->feederflags |= 1 << FEEDER_VOLUME; + if (!(c->flags & CHN_F_VIRTUAL) && c->parentsnddev && + ((c->direction == PCMDIR_PLAY && + (c->parentsnddev->flags & SD_F_PSWAPLR)) || + (c->direction == PCMDIR_REC && + (c->parentsnddev->flags & SD_F_RSWAPLR)))) + c->feederflags |= 1 << FEEDER_SWAPLR; flags = c->feederflags; fmtlist = chn_getcaps(c)->fmtlist; @@ -1830,14 +1916,13 @@ chn_buildfeeder(struct pcm_channel *c) c->feeder->desc->out & AFMT_STEREO) desc.in |= AFMT_STEREO; desc.out = desc.in; - fc = feeder_getclass(&desc); - if (fc != NULL && fc->desc != NULL) - desc.flags = fc->desc->flags; - } else { - fc = feeder_getclass(&desc); - if (fc != NULL && fc->desc != NULL) - desc = *fc->desc; + } else if (type == FEEDER_SWAPLR) { + desc.in = c->feeder->desc->out; + desc.in |= AFMT_STEREO; + desc.out = desc.in; } + + fc = feeder_getclass(&desc); DEB(printf("got %p\n", fc)); if (fc == NULL) { DEB(printf("can't find required feeder type %d\n", type)); @@ -1845,6 +1930,9 @@ chn_buildfeeder(struct pcm_channel *c) return EOPNOTSUPP; } + if (desc.in == 0 || desc.out == 0) + desc = *fc->desc; + DEB(printf("build fmtchain from 0x%08x to 0x%08x: ", c->feeder->desc->out, fc->desc->in)); tmp[0] = desc.in; tmp[1] = 0; @@ -1932,7 +2020,7 @@ chn_notify(struct pcm_channel *c, u_int32_t flags) return ENODEV; } - run = (c->flags & CHN_F_TRIGGERED)? 1 : 0; + run = (CHN_STARTED(c)) ? 1 : 0; /* * if the hwchan is running, we can't change its rate, format or * blocksize @@ -1974,9 +2062,10 @@ chn_notify(struct pcm_channel *c, u_int32_t flags) SLIST_FOREACH(pce, &c->children, link) { child = pce->channel; CHN_LOCK(child); - if (child->flags & CHN_F_TRIGGERED) - nrun = 1; + nrun = CHN_STARTED(child); CHN_UNLOCK(child); + if (nrun) + break; } if (nrun && !run) chn_start(c, 1); diff --git a/sys/dev/sound/pcm/channel_if.m b/sys/dev/sound/pcm/channel_if.m index d0c07c3..3429a33 100644 --- a/sys/dev/sound/pcm/channel_if.m +++ b/sys/dev/sound/pcm/channel_if.m @@ -83,6 +83,12 @@ CODE { return 0; } + static int + channel_nosetfragments(kobj_t obj, void *data, u_int32_t blocksize, u_int32_t blockcount) + { + return 0; + } + }; METHOD void* init { @@ -132,6 +138,13 @@ METHOD u_int32_t setblocksize { u_int32_t blocksize; }; +METHOD int setfragments { + kobj_t obj; + void *data; + u_int32_t blocksize; + u_int32_t blockcount; +} DEFAULT channel_nosetfragments; + METHOD int trigger { kobj_t obj; void *data; diff --git a/sys/dev/sound/pcm/feeder_fmt.c b/sys/dev/sound/pcm/feeder_fmt.c index 0ccc7b9..8698178 100644 --- a/sys/dev/sound/pcm/feeder_fmt.c +++ b/sys/dev/sound/pcm/feeder_fmt.c @@ -41,87 +41,83 @@ SND_DECLARE_FILE("$FreeBSD$"); -MALLOC_DEFINE(M_FMTFEEDER, "fmtfeed", "pcm format feeder"); - -#define FMT_TRACE(x...) /* printf(x) */ -#define FMT_TEST(x, y...) /* if (x) FMT_TRACE(y) */ - -struct feed_fmt_info { - int bps, bufsz; - uint8_t *buffer; +static int feeder_fmt_stereodownmix = 0; +TUNABLE_INT("hw.snd.feeder_fmt_stereodownmix", &feeder_fmt_stereodownmix); +#ifdef SND_DEBUG +SYSCTL_INT(_hw_snd, OID_AUTO, feeder_fmt_stereodownmix, CTLFLAG_RW, + &feeder_fmt_stereodownmix, 1, "averaging stereo downmix"); +#endif + +#define FEEDFMT_RESERVOIR 8 /* 32bit stereo */ + +static uint8_t ulaw_to_u8_tbl[] = { + 3, 7, 11, 15, 19, 23, 27, 31, + 35, 39, 43, 47, 51, 55, 59, 63, + 66, 68, 70, 72, 74, 76, 78, 80, + 82, 84, 86, 88, 90, 92, 94, 96, + 98, 99, 100, 101, 102, 103, 104, 105, + 106, 107, 108, 109, 110, 111, 112, 113, + 113, 114, 114, 115, 115, 116, 116, 117, + 117, 118, 118, 119, 119, 120, 120, 121, + 121, 121, 122, 122, 122, 122, 123, 123, + 123, 123, 124, 124, 124, 124, 125, 125, + 125, 125, 125, 125, 126, 126, 126, 126, + 126, 126, 126, 126, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 253, 249, 245, 241, 237, 233, 229, 225, + 221, 217, 213, 209, 205, 201, 197, 193, + 190, 188, 186, 184, 182, 180, 178, 176, + 174, 172, 170, 168, 166, 164, 162, 160, + 158, 157, 156, 155, 154, 153, 152, 151, + 150, 149, 148, 147, 146, 145, 144, 143, + 143, 142, 142, 141, 141, 140, 140, 139, + 139, 138, 138, 137, 137, 136, 136, 135, + 135, 135, 134, 134, 134, 134, 133, 133, + 133, 133, 132, 132, 132, 132, 131, 131, + 131, 131, 131, 131, 130, 130, 130, 130, + 130, 130, 130, 130, 129, 129, 129, 129, + 129, 129, 129, 129, 129, 129, 129, 129, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, }; -/* - * Sign inverted ulaw/alaw -> 8 table - */ -static uint8_t ulaw_to_s8_tbl[] = { - 131, 135, 139, 143, 147, 151, 155, 159, - 163, 167, 171, 175, 179, 183, 187, 191, - 194, 196, 198, 200, 202, 204, 206, 208, - 210, 212, 214, 216, 218, 220, 222, 224, - 226, 227, 228, 229, 230, 231, 232, 233, - 234, 235, 236, 237, 238, 239, 240, 241, - 241, 242, 242, 243, 243, 244, 244, 245, - 245, 246, 246, 247, 247, 248, 248, 249, - 249, 249, 250, 250, 250, 250, 251, 251, - 251, 251, 252, 252, 252, 252, 253, 253, - 253, 253, 253, 253, 254, 254, 254, 254, - 254, 254, 254, 254, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 125, 121, 117, 113, 109, 105, 101, 97, - 93, 89, 85, 81, 77, 73, 69, 65, - 62, 60, 58, 56, 54, 52, 50, 48, - 46, 44, 42, 40, 38, 36, 34, 32, - 30, 29, 28, 27, 26, 25, 24, 23, - 22, 21, 20, 19, 18, 17, 16, 15, - 15, 14, 14, 13, 13, 12, 12, 11, - 11, 10, 10, 9, 9, 8, 8, 7, - 7, 7, 6, 6, 6, 6, 5, 5, - 5, 5, 4, 4, 4, 4, 3, 3, - 3, 3, 3, 3, 2, 2, 2, 2, - 2, 2, 2, 2, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, -}; - -static uint8_t alaw_to_s8_tbl[] = { - 236, 237, 234, 235, 240, 241, 238, 239, - 228, 229, 226, 227, 232, 233, 230, 231, - 246, 246, 245, 245, 248, 248, 247, 247, - 242, 242, 241, 241, 244, 244, 243, 243, - 171, 175, 163, 167, 187, 191, 179, 183, - 139, 143, 131, 135, 155, 159, 147, 151, - 214, 216, 210, 212, 222, 224, 218, 220, - 198, 200, 194, 196, 206, 208, 202, 204, - 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 251, 251, 251, 251, 252, 252, 252, 252, - 249, 249, 249, 249, 250, 250, 250, 250, - 254, 254, 254, 254, 254, 254, 254, 254, - 253, 253, 253, 253, 253, 253, 253, 253, - 20, 19, 22, 21, 16, 15, 18, 17, - 28, 27, 30, 29, 24, 23, 26, 25, - 10, 10, 11, 11, 8, 8, 9, 9, - 14, 14, 15, 15, 12, 12, 13, 13, - 85, 81, 93, 89, 69, 65, 77, 73, - 117, 113, 125, 121, 101, 97, 109, 105, - 42, 40, 46, 44, 34, 32, 38, 36, - 58, 56, 62, 60, 50, 48, 54, 52, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 5, 5, 5, 5, 4, 4, 4, 4, - 7, 7, 7, 7, 6, 6, 6, 6, - 2, 2, 2, 2, 2, 2, 2, 2, - 3, 3, 3, 3, 3, 3, 3, 3, +static uint8_t alaw_to_u8_tbl[] = { + 108, 109, 106, 107, 112, 113, 110, 111, + 100, 101, 98, 99, 104, 105, 102, 103, + 118, 118, 117, 117, 120, 120, 119, 119, + 114, 114, 113, 113, 116, 116, 115, 115, + 43, 47, 35, 39, 59, 63, 51, 55, + 11, 15, 3, 7, 27, 31, 19, 23, + 86, 88, 82, 84, 94, 96, 90, 92, + 70, 72, 66, 68, 78, 80, 74, 76, + 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 123, 123, 123, 123, 124, 124, 124, 124, + 121, 121, 121, 121, 122, 122, 122, 122, + 126, 126, 126, 126, 126, 126, 126, 126, + 125, 125, 125, 125, 125, 125, 125, 125, + 148, 147, 150, 149, 144, 143, 146, 145, + 156, 155, 158, 157, 152, 151, 154, 153, + 138, 138, 139, 139, 136, 136, 137, 137, + 142, 142, 143, 143, 140, 140, 141, 141, + 213, 209, 221, 217, 197, 193, 205, 201, + 245, 241, 253, 249, 229, 225, 237, 233, + 170, 168, 174, 172, 162, 160, 166, 164, + 186, 184, 190, 188, 178, 176, 182, 180, + 129, 129, 129, 129, 129, 129, 129, 129, + 129, 129, 129, 129, 129, 129, 129, 129, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 133, 133, 133, 133, 132, 132, 132, 132, + 135, 135, 135, 135, 134, 134, 134, 134, + 130, 130, 130, 130, 130, 130, 130, 130, + 131, 131, 131, 131, 131, 131, 131, 131, }; static uint8_t u8_to_ulaw_tbl[] = { @@ -200,17 +196,23 @@ feed_table_8(struct pcm_feeder *f, struct pcm_channel *c, uint8_t *b, { int j, sign, k; uint8_t *tbl = (uint8_t *)f->data; - - if (count < 1) - return 0; + + if (count < PCM_8_BPS) + return (0); + k = FEEDER_FEED(f->source, c, b, count, source); + if (k < PCM_8_BPS) + return (0); + j = k; - sign = (f->desc->out & AFMT_SIGNED) ? 0x00 : 0x80; - while (j > 0) { + sign = (f->desc->out & AFMT_SIGNED) ? 0x80 : 0x00; + + do { j--; b[j] = tbl[b[j]] ^ sign; - } - return k; + } while (j != 0); + + return (k); } static int @@ -219,26 +221,32 @@ feed_table_16(struct pcm_feeder *f, struct pcm_channel *c, uint8_t *b, { int i, j, sign, k; uint8_t *tbl = (uint8_t *)f->data; - - if (count < 2) - return 0; + + if (count < PCM_16_BPS) + return (0); + k = FEEDER_FEED(f->source, c, b, count >> 1, source); + if (k < PCM_8_BPS) + return (0); + i = k; k <<= 1; j = k; - sign = (f->desc->out & AFMT_SIGNED) ? 0x00 : 0x80; + sign = (f->desc->out & AFMT_SIGNED) ? 0x80 : 0x00; + if (f->desc->out & AFMT_BIGENDIAN) { - while (i > 0) { + do { b[--j] = 0; b[--j] = tbl[b[--i]] ^ sign; - } + } while (i != 0); } else { - while (i > 0) { + do { b[--j] = tbl[b[--i]] ^ sign; b[--j] = 0; - } + } while (i != 0); } - return k; + + return (k); } static int @@ -248,100 +256,106 @@ feed_table_xlaw(struct pcm_feeder *f, struct pcm_channel *c, uint8_t *b, int j, sign, k; uint8_t *tbl = (uint8_t *)f->data; - if (count < 1) - return 0; + if (count < PCM_8_BPS) + return (0); + k = FEEDER_FEED(f->source, c, b, count, source); - j = k; + if (k < PCM_8_BPS) + return (0); + + j = k ; sign = (f->desc->in & AFMT_SIGNED) ? 0x80 : 0x00; - while (j > 0) { + + do { j--; b[j] = tbl[b[j] ^ sign]; - } - return k; + } while (j != 0); + + return (k); } static struct pcm_feederdesc feeder_ulawto8_desc[] = { {FEEDER_FMT, AFMT_MU_LAW, AFMT_U8, 0}, - {FEEDER_FMT, AFMT_MU_LAW|AFMT_STEREO, AFMT_U8|AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_MU_LAW | AFMT_STEREO, AFMT_U8 | AFMT_STEREO, 0}, {FEEDER_FMT, AFMT_MU_LAW, AFMT_S8, 0}, - {FEEDER_FMT, AFMT_MU_LAW|AFMT_STEREO, AFMT_S8|AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_MU_LAW | AFMT_STEREO, AFMT_S8 | AFMT_STEREO, 0}, {0, 0, 0, 0}, }; static kobj_method_t feeder_ulawto8_methods[] = { - KOBJMETHOD(feeder_feed, feed_table_8), + KOBJMETHOD(feeder_feed, feed_table_8), {0, 0} }; -FEEDER_DECLARE(feeder_ulawto8, 0, ulaw_to_s8_tbl); +FEEDER_DECLARE(feeder_ulawto8, 0, ulaw_to_u8_tbl); static struct pcm_feederdesc feeder_alawto8_desc[] = { {FEEDER_FMT, AFMT_A_LAW, AFMT_U8, 0}, - {FEEDER_FMT, AFMT_A_LAW|AFMT_STEREO, AFMT_U8|AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_A_LAW | AFMT_STEREO, AFMT_U8 | AFMT_STEREO, 0}, {FEEDER_FMT, AFMT_A_LAW, AFMT_S8, 0}, - {FEEDER_FMT, AFMT_A_LAW|AFMT_STEREO, AFMT_S8|AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_A_LAW | AFMT_STEREO, AFMT_S8 | AFMT_STEREO, 0}, {0, 0, 0, 0}, }; static kobj_method_t feeder_alawto8_methods[] = { - KOBJMETHOD(feeder_feed, feed_table_8), + KOBJMETHOD(feeder_feed, feed_table_8), {0, 0} }; -FEEDER_DECLARE(feeder_alawto8, 0, alaw_to_s8_tbl); +FEEDER_DECLARE(feeder_alawto8, 0, alaw_to_u8_tbl); static struct pcm_feederdesc feeder_ulawto16_desc[] = { {FEEDER_FMT, AFMT_MU_LAW, AFMT_S16_LE, 0}, - {FEEDER_FMT, AFMT_MU_LAW|AFMT_STEREO, AFMT_S16_LE|AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_MU_LAW | AFMT_STEREO, AFMT_S16_LE | AFMT_STEREO, 0}, {FEEDER_FMT, AFMT_MU_LAW, AFMT_U16_LE, 0}, - {FEEDER_FMT, AFMT_MU_LAW|AFMT_STEREO, AFMT_U16_LE|AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_MU_LAW | AFMT_STEREO, AFMT_U16_LE | AFMT_STEREO, 0}, {FEEDER_FMT, AFMT_MU_LAW, AFMT_S16_BE, 0}, - {FEEDER_FMT, AFMT_MU_LAW|AFMT_STEREO, AFMT_S16_BE|AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_MU_LAW | AFMT_STEREO, AFMT_S16_BE | AFMT_STEREO, 0}, {FEEDER_FMT, AFMT_MU_LAW, AFMT_U16_BE, 0}, - {FEEDER_FMT, AFMT_MU_LAW|AFMT_STEREO, AFMT_U16_BE|AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_MU_LAW | AFMT_STEREO, AFMT_U16_BE | AFMT_STEREO, 0}, {0, 0, 0, 0}, }; static kobj_method_t feeder_ulawto16_methods[] = { - KOBJMETHOD(feeder_feed, feed_table_16), + KOBJMETHOD(feeder_feed, feed_table_16), {0, 0} }; -FEEDER_DECLARE(feeder_ulawto16, 0, ulaw_to_s8_tbl); +FEEDER_DECLARE(feeder_ulawto16, 0, ulaw_to_u8_tbl); static struct pcm_feederdesc feeder_alawto16_desc[] = { {FEEDER_FMT, AFMT_A_LAW, AFMT_S16_LE, 0}, - {FEEDER_FMT, AFMT_A_LAW|AFMT_STEREO, AFMT_S16_LE|AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_A_LAW | AFMT_STEREO, AFMT_S16_LE | AFMT_STEREO, 0}, {FEEDER_FMT, AFMT_A_LAW, AFMT_U16_LE, 0}, - {FEEDER_FMT, AFMT_A_LAW|AFMT_STEREO, AFMT_U16_LE|AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_A_LAW | AFMT_STEREO, AFMT_U16_LE | AFMT_STEREO, 0}, {FEEDER_FMT, AFMT_A_LAW, AFMT_S16_BE, 0}, - {FEEDER_FMT, AFMT_A_LAW|AFMT_STEREO, AFMT_S16_BE|AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_A_LAW | AFMT_STEREO, AFMT_S16_BE | AFMT_STEREO, 0}, {FEEDER_FMT, AFMT_A_LAW, AFMT_U16_BE, 0}, - {FEEDER_FMT, AFMT_A_LAW|AFMT_STEREO, AFMT_U16_BE|AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_A_LAW | AFMT_STEREO, AFMT_U16_BE | AFMT_STEREO, 0}, {0, 0, 0, 0}, }; static kobj_method_t feeder_alawto16_methods[] = { - KOBJMETHOD(feeder_feed, feed_table_16), + KOBJMETHOD(feeder_feed, feed_table_16), {0, 0} }; -FEEDER_DECLARE(feeder_alawto16, 0, alaw_to_s8_tbl); +FEEDER_DECLARE(feeder_alawto16, 0, alaw_to_u8_tbl); static struct pcm_feederdesc feeder_8toulaw_desc[] = { {FEEDER_FMT, AFMT_U8, AFMT_MU_LAW, 0}, - {FEEDER_FMT, AFMT_U8|AFMT_STEREO, AFMT_MU_LAW|AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_U8 | AFMT_STEREO, AFMT_MU_LAW | AFMT_STEREO, 0}, {FEEDER_FMT, AFMT_S8, AFMT_MU_LAW, 0}, - {FEEDER_FMT, AFMT_S8|AFMT_STEREO, AFMT_MU_LAW|AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_S8 | AFMT_STEREO, AFMT_MU_LAW | AFMT_STEREO, 0}, {0, 0, 0, 0}, }; static kobj_method_t feeder_8toulaw_methods[] = { - KOBJMETHOD(feeder_feed, feed_table_xlaw), + KOBJMETHOD(feeder_feed, feed_table_xlaw), {0, 0} }; FEEDER_DECLARE(feeder_8toulaw, 0, u8_to_ulaw_tbl); static struct pcm_feederdesc feeder_8toalaw_desc[] = { {FEEDER_FMT, AFMT_U8, AFMT_A_LAW, 0}, - {FEEDER_FMT, AFMT_U8|AFMT_STEREO, AFMT_A_LAW|AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_U8 | AFMT_STEREO, AFMT_A_LAW | AFMT_STEREO, 0}, {FEEDER_FMT, AFMT_S8, AFMT_A_LAW, 0}, - {FEEDER_FMT, AFMT_S8|AFMT_STEREO, AFMT_A_LAW|AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_S8 | AFMT_STEREO, AFMT_A_LAW | AFMT_STEREO, 0}, {0, 0, 0, 0}, }; static kobj_method_t feeder_8toalaw_methods[] = { - KOBJMETHOD(feeder_feed, feed_table_xlaw), + KOBJMETHOD(feeder_feed, feed_table_xlaw), {0, 0} }; FEEDER_DECLARE(feeder_8toalaw, 0, u8_to_alaw_tbl); @@ -350,553 +364,487 @@ FEEDER_DECLARE(feeder_8toalaw, 0, u8_to_alaw_tbl); * All conversion done in byte level to preserve endianess. */ +#define FEEDFMT_SWAP_SIGN(f) (((((f)->desc->in & AFMT_SIGNED) == 0) != \ + (((f)->desc->out & AFMT_SIGNED) == 0)) \ + ? 0x80 : 0x00) + +/* + * Bit conversion + */ + +#define FBIT_DATA(i, o, c) ((intptr_t)((((c) & 0xf) << 6) | \ + (((i) & 0x7) << 3) | ((o) & 0x7))) +#define FBIT_OUTBPS(m) ((m) & 0x7) +#define FBIT_INBPS(m) FBIT_OUTBPS((m) >> 3) +#define FBIT_CHANNELS(m) (((m) >> 6) & 0xf) + static int -feed_fmt_init(struct pcm_feeder *f) +feed_updownbit_init(struct pcm_feeder *f) { - struct feed_fmt_info *info; + int ibps, obps, channels; - info = malloc(sizeof(*info), M_FMTFEEDER, M_NOWAIT | M_ZERO); - if (info == NULL) - return ENOMEM; - - info->bps = 1; - info->bps <<= (f->desc->in & AFMT_STEREO) ? 1 : 0; - if (f->desc->in & AFMT_16BIT) - info->bps <<= 1; - else if (f->desc->in & AFMT_24BIT) - info->bps *= 3; - else if (f->desc->in & AFMT_32BIT) - info->bps <<= 2; - info->bufsz = feeder_buffersize - (feeder_buffersize % info->bps); - - info->buffer = malloc(info->bufsz, M_FMTFEEDER, M_NOWAIT | M_ZERO); - if (info->buffer == NULL) { - free(info, M_FMTFEEDER); - return ENOMEM; - } + if (f->desc->in == f->desc->out || (f->desc->in & AFMT_STEREO) != + (f->desc->out & AFMT_STEREO)) + return (-1); - f->data = info; + channels = (f->desc->in & AFMT_STEREO) ? 2 : 1; - return 0; + if (f->desc->in & AFMT_32BIT) + ibps = PCM_32_BPS; + else if (f->desc->in & AFMT_24BIT) + ibps = PCM_24_BPS; + else if (f->desc->in & AFMT_16BIT) + ibps = PCM_16_BPS; + else + ibps = PCM_8_BPS; + + if (f->desc->out & AFMT_32BIT) + obps = PCM_32_BPS; + else if (f->desc->out & AFMT_24BIT) + obps = PCM_24_BPS; + else if (f->desc->out & AFMT_16BIT) + obps = PCM_16_BPS; + else + obps = PCM_8_BPS; + + f->data = (void *)FBIT_DATA(ibps, obps, channels); + + return (0); } static int -feed_fmt_free(struct pcm_feeder *f) +feed_upbit(struct pcm_feeder *f, struct pcm_channel *c, uint8_t *b, + uint32_t count, void *source) { - struct feed_fmt_info *info = f->data; + int i, j, k, sign, ibps, ialign, obps, oalign, pad; + uint8_t *src, *dst; - if (info) { - if (info->buffer) - free(info->buffer, M_FMTFEEDER); - free(info, M_FMTFEEDER); - } - f->data = NULL; - return 0; -} + ibps = FBIT_INBPS((intptr_t)f->data); + obps = FBIT_OUTBPS((intptr_t)f->data); -#define swap_sign(fdr) \ - (((((fdr)->desc->in & AFMT_SIGNED) && \ - !((fdr)->desc->out & AFMT_SIGNED)) || \ - (!((fdr)->desc->in & AFMT_SIGNED) && \ - ((fdr)->desc->out & AFMT_SIGNED))) ? 0x80 : 0x00) + ialign = ibps * FBIT_CHANNELS((intptr_t)f->data); + oalign = obps * FBIT_CHANNELS((intptr_t)f->data); + + if (count < oalign) + return (0); + + k = FEEDER_FEED(f->source, c, b, (count / oalign) * ialign, source); + if (k < ialign) + return (0); + + k -= k % ialign; + j = (k / ibps) * obps; + pad = obps - ibps; + src = b + k; + dst = b + j; + sign = FEEDFMT_SWAP_SIGN(f); -/* - * Bit conversion - */ -static int -feed_8to16(struct pcm_feeder *f, struct pcm_channel *c, uint8_t *b, - uint32_t count, void *source) -{ - int i, j, k; - int sign; - - if (count < 2) - return 0; - k = FEEDER_FEED(f->source, c, b, count >> 1, source); - i = k; - k <<= 1; - j = k; - sign = swap_sign(f); if (f->desc->out & AFMT_BIGENDIAN) { - while (i > 0) { - b[--j] = 0; - b[--j] = b[--i] ^ sign; - } + do { + i = pad; + do { + *--dst = 0; + } while (--i != 0); + i = ibps; + while (--i != 0) + *--dst = *--src; + *--dst = *--src ^ sign; + } while (dst != b); } else { - while (i > 0) { - b[--j] = b[--i] ^ sign; - b[--j] = 0; - } + do { + *--dst = *--src ^ sign; + i = ibps; + while (--i != 0) + *--dst = *--src; + i = pad; + do { + *--dst = 0; + } while (--i != 0); + } while (dst != b); } - return k; + + return (j); } + static struct pcm_feederdesc feeder_8to16_desc[] = { {FEEDER_FMT, AFMT_U8, AFMT_U16_LE, 0}, - {FEEDER_FMT, AFMT_U8|AFMT_STEREO, AFMT_U16_LE|AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_U8 | AFMT_STEREO, AFMT_U16_LE | AFMT_STEREO, 0}, {FEEDER_FMT, AFMT_S8, AFMT_S16_LE, 0}, - {FEEDER_FMT, AFMT_S8|AFMT_STEREO, AFMT_S16_LE|AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_S8 | AFMT_STEREO, AFMT_S16_LE | AFMT_STEREO, 0}, {FEEDER_FMT, AFMT_U8, AFMT_U16_BE, 0}, - {FEEDER_FMT, AFMT_U8|AFMT_STEREO, AFMT_U16_BE|AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_U8 | AFMT_STEREO, AFMT_U16_BE | AFMT_STEREO, 0}, {FEEDER_FMT, AFMT_S8, AFMT_S16_BE, 0}, - {FEEDER_FMT, AFMT_S8|AFMT_STEREO, AFMT_S16_BE|AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_S8 | AFMT_STEREO, AFMT_S16_BE | AFMT_STEREO, 0}, {FEEDER_FMT, AFMT_U8, AFMT_S16_LE, 0}, - {FEEDER_FMT, AFMT_U8|AFMT_STEREO, AFMT_S16_LE|AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_U8 | AFMT_STEREO, AFMT_S16_LE | AFMT_STEREO, 0}, {FEEDER_FMT, AFMT_S8, AFMT_U16_LE, 0}, - {FEEDER_FMT, AFMT_S8|AFMT_STEREO, AFMT_U16_LE|AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_S8 | AFMT_STEREO, AFMT_U16_LE | AFMT_STEREO, 0}, {FEEDER_FMT, AFMT_U8, AFMT_S16_BE, 0}, - {FEEDER_FMT, AFMT_U8|AFMT_STEREO, AFMT_S16_BE|AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_U8 | AFMT_STEREO, AFMT_S16_BE | AFMT_STEREO, 0}, {FEEDER_FMT, AFMT_S8, AFMT_U16_BE, 0}, - {FEEDER_FMT, AFMT_S8|AFMT_STEREO, AFMT_U16_BE|AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_S8 | AFMT_STEREO, AFMT_U16_BE | AFMT_STEREO, 0}, {0, 0, 0, 0}, }; static kobj_method_t feeder_8to16_methods[] = { - KOBJMETHOD(feeder_feed, feed_8to16), + KOBJMETHOD(feeder_init, feed_updownbit_init), + KOBJMETHOD(feeder_feed, feed_upbit), {0, 0} }; FEEDER_DECLARE(feeder_8to16, 0, NULL); -static int -feed_16to8(struct pcm_feeder *f, struct pcm_channel *c, uint8_t *b, - uint32_t count, void *source) -{ - struct feed_fmt_info *info = f->data; - int i, j, k, sign; - uint8_t *src = info->buffer; - - if (count < 1) - return 0; - k = count << 1; - k = FEEDER_FEED(f->source, c, src, min(k, info->bufsz), source); - if (k < 2) { - FMT_TRACE("%s: Not enough data (Got: %d bytes)\n", - __func__, k); - return 0; - } - FMT_TEST(k & 1, "%s: Bytes not 16bit aligned.\n", __func__); - k &= ~1; - i = k; - j = k >> 1; - sign = swap_sign(f); - if (f->desc->in & AFMT_BIGENDIAN) { - while (i > 1) { - i--; - b[--j] = src[--i] ^ sign; - } - } else { - while (i > 1) { - b[--j] = src[--i] ^ sign; - i--; - } - } - return k >> 1; -} -static struct pcm_feederdesc feeder_16to8_desc[] = { - {FEEDER_FMT, AFMT_U16_LE, AFMT_U8, 0}, - {FEEDER_FMT, AFMT_U16_LE|AFMT_STEREO, AFMT_U8|AFMT_STEREO, 0}, - {FEEDER_FMT, AFMT_S16_LE, AFMT_S8, 0}, - {FEEDER_FMT, AFMT_S16_LE|AFMT_STEREO, AFMT_S8|AFMT_STEREO, 0}, - {FEEDER_FMT, AFMT_U16_BE, AFMT_U8, 0}, - {FEEDER_FMT, AFMT_U16_BE|AFMT_STEREO, AFMT_U8|AFMT_STEREO, 0}, - {FEEDER_FMT, AFMT_S16_BE, AFMT_S8, 0}, - {FEEDER_FMT, AFMT_S16_BE|AFMT_STEREO, AFMT_S8|AFMT_STEREO, 0}, - {FEEDER_FMT, AFMT_U16_LE, AFMT_S8, 0}, - {FEEDER_FMT, AFMT_U16_LE|AFMT_STEREO, AFMT_S8|AFMT_STEREO, 0}, - {FEEDER_FMT, AFMT_S16_LE, AFMT_U8, 0}, - {FEEDER_FMT, AFMT_S16_LE|AFMT_STEREO, AFMT_U8|AFMT_STEREO, 0}, - {FEEDER_FMT, AFMT_U16_BE, AFMT_S8, 0}, - {FEEDER_FMT, AFMT_U16_BE|AFMT_STEREO, AFMT_S8|AFMT_STEREO, 0}, - {FEEDER_FMT, AFMT_S16_BE, AFMT_U8, 0}, - {FEEDER_FMT, AFMT_S16_BE|AFMT_STEREO, AFMT_U8|AFMT_STEREO, 0}, +static struct pcm_feederdesc feeder_8to24_desc[] = { + {FEEDER_FMT, AFMT_U8, AFMT_U24_LE, 0}, + {FEEDER_FMT, AFMT_U8 | AFMT_STEREO, AFMT_U24_LE | AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_S8, AFMT_S24_LE, 0}, + {FEEDER_FMT, AFMT_S8 | AFMT_STEREO, AFMT_S24_LE | AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_U8, AFMT_U24_BE, 0}, + {FEEDER_FMT, AFMT_U8 | AFMT_STEREO, AFMT_U24_BE | AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_S8, AFMT_S24_BE, 0}, + {FEEDER_FMT, AFMT_S8 | AFMT_STEREO, AFMT_S24_BE | AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_U8, AFMT_S24_LE, 0}, + {FEEDER_FMT, AFMT_U8 | AFMT_STEREO, AFMT_S24_LE | AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_S8, AFMT_U24_LE, 0}, + {FEEDER_FMT, AFMT_S8 | AFMT_STEREO, AFMT_U24_LE | AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_U8, AFMT_S24_BE, 0}, + {FEEDER_FMT, AFMT_U8 | AFMT_STEREO, AFMT_S24_BE | AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_S8, AFMT_U24_BE, 0}, + {FEEDER_FMT, AFMT_S8 | AFMT_STEREO, AFMT_U24_BE | AFMT_STEREO, 0}, {0, 0, 0, 0}, }; -static kobj_method_t feeder_16to8_methods[] = { - KOBJMETHOD(feeder_init, feed_fmt_init), - KOBJMETHOD(feeder_free, feed_fmt_free), - KOBJMETHOD(feeder_feed, feed_16to8), +static kobj_method_t feeder_8to24_methods[] = { + KOBJMETHOD(feeder_init, feed_updownbit_init), + KOBJMETHOD(feeder_feed, feed_upbit), {0, 0} }; -FEEDER_DECLARE(feeder_16to8, 0, NULL); +FEEDER_DECLARE(feeder_8to24, 0, NULL); + +static struct pcm_feederdesc feeder_8to32_desc[] = { + {FEEDER_FMT, AFMT_U8, AFMT_U32_LE, 0}, + {FEEDER_FMT, AFMT_U8 | AFMT_STEREO, AFMT_U32_LE | AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_S8, AFMT_S32_LE, 0}, + {FEEDER_FMT, AFMT_S8 | AFMT_STEREO, AFMT_S32_LE | AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_U8, AFMT_U32_BE, 0}, + {FEEDER_FMT, AFMT_U8 | AFMT_STEREO, AFMT_U32_BE | AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_S8, AFMT_S32_BE, 0}, + {FEEDER_FMT, AFMT_S8 | AFMT_STEREO, AFMT_S32_BE | AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_U8, AFMT_S32_LE, 0}, + {FEEDER_FMT, AFMT_U8 | AFMT_STEREO, AFMT_S32_LE | AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_S8, AFMT_U32_LE, 0}, + {FEEDER_FMT, AFMT_S8 | AFMT_STEREO, AFMT_U32_LE | AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_U8, AFMT_S32_BE, 0}, + {FEEDER_FMT, AFMT_U8 | AFMT_STEREO, AFMT_S32_BE | AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_S8, AFMT_U32_BE, 0}, + {FEEDER_FMT, AFMT_S8 | AFMT_STEREO, AFMT_U32_BE | AFMT_STEREO, 0}, + {0, 0, 0, 0}, +}; +static kobj_method_t feeder_8to32_methods[] = { + KOBJMETHOD(feeder_init, feed_updownbit_init), + KOBJMETHOD(feeder_feed, feed_upbit), + {0, 0} +}; +FEEDER_DECLARE(feeder_8to32, 0, NULL); -static int -feed_16to24(struct pcm_feeder *f, struct pcm_channel *c, uint8_t *b, - uint32_t count, void *source) -{ - int i, j, k, sign; - - if (count < 3) - return 0; - k = (count / 3) << 1; - k = FEEDER_FEED(f->source, c, b, k, source); - if (k < 2) { - FMT_TRACE("%s: Not enough data (Got: %d bytes)\n", - __func__, k); - return 0; - } - FMT_TEST(k & 1, "%s: Bytes not 16bit aligned.\n", __func__); - k &= ~1; - i = k; - j = (k >> 1) * 3; - k = j; - sign = swap_sign(f); - if (f->desc->in & AFMT_BIGENDIAN) { - while (i > 1) { - b[--j] = 0; - b[--j] = b[--i]; - b[--j] = b[--i] ^ sign; - } - } else { - while (i > 1) { - b[--j] = b[--i] ^ sign; - b[--j] = b[--i]; - b[--j] = 0; - } - } - return k; -} static struct pcm_feederdesc feeder_16to24_desc[] = { {FEEDER_FMT, AFMT_U16_LE, AFMT_U24_LE, 0}, - {FEEDER_FMT, AFMT_U16_LE|AFMT_STEREO, AFMT_U24_LE|AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_U16_LE | AFMT_STEREO, AFMT_U24_LE | AFMT_STEREO, 0}, {FEEDER_FMT, AFMT_S16_LE, AFMT_S24_LE, 0}, - {FEEDER_FMT, AFMT_S16_LE|AFMT_STEREO, AFMT_S24_LE|AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_S16_LE | AFMT_STEREO, AFMT_S24_LE | AFMT_STEREO, 0}, {FEEDER_FMT, AFMT_U16_BE, AFMT_U24_BE, 0}, - {FEEDER_FMT, AFMT_U16_BE|AFMT_STEREO, AFMT_U24_BE|AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_U16_BE | AFMT_STEREO, AFMT_U24_BE | AFMT_STEREO, 0}, {FEEDER_FMT, AFMT_S16_BE, AFMT_S24_BE, 0}, - {FEEDER_FMT, AFMT_S16_BE|AFMT_STEREO, AFMT_S24_BE|AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_S16_BE | AFMT_STEREO, AFMT_S24_BE | AFMT_STEREO, 0}, {FEEDER_FMT, AFMT_U16_LE, AFMT_S24_LE, 0}, - {FEEDER_FMT, AFMT_U16_LE|AFMT_STEREO, AFMT_S24_LE|AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_U16_LE | AFMT_STEREO, AFMT_S24_LE | AFMT_STEREO, 0}, {FEEDER_FMT, AFMT_S16_LE, AFMT_U24_LE, 0}, - {FEEDER_FMT, AFMT_S16_LE|AFMT_STEREO, AFMT_U24_LE|AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_S16_LE | AFMT_STEREO, AFMT_U24_LE | AFMT_STEREO, 0}, {FEEDER_FMT, AFMT_U16_BE, AFMT_S24_BE, 0}, - {FEEDER_FMT, AFMT_U16_BE|AFMT_STEREO, AFMT_S24_BE|AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_U16_BE | AFMT_STEREO, AFMT_S24_BE | AFMT_STEREO, 0}, {FEEDER_FMT, AFMT_S16_BE, AFMT_U24_BE, 0}, - {FEEDER_FMT, AFMT_S16_BE|AFMT_STEREO, AFMT_U24_BE|AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_S16_BE | AFMT_STEREO, AFMT_U24_BE | AFMT_STEREO, 0}, {0, 0, 0, 0}, }; static kobj_method_t feeder_16to24_methods[] = { - KOBJMETHOD(feeder_feed, feed_16to24), + KOBJMETHOD(feeder_init, feed_updownbit_init), + KOBJMETHOD(feeder_feed, feed_upbit), {0, 0} }; FEEDER_DECLARE(feeder_16to24, 0, NULL); +static struct pcm_feederdesc feeder_16to32_desc[] = { + {FEEDER_FMT, AFMT_U16_LE, AFMT_U32_LE, 0}, + {FEEDER_FMT, AFMT_U16_LE | AFMT_STEREO, AFMT_U32_LE | AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_S16_LE, AFMT_S32_LE, 0}, + {FEEDER_FMT, AFMT_S16_LE | AFMT_STEREO, AFMT_S32_LE | AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_U16_BE, AFMT_U32_BE, 0}, + {FEEDER_FMT, AFMT_U16_BE | AFMT_STEREO, AFMT_U32_BE | AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_S16_BE, AFMT_S32_BE, 0}, + {FEEDER_FMT, AFMT_S16_BE | AFMT_STEREO, AFMT_S32_BE | AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_U16_LE, AFMT_S32_LE, 0}, + {FEEDER_FMT, AFMT_U16_LE | AFMT_STEREO, AFMT_S32_LE | AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_S16_LE, AFMT_U32_LE, 0}, + {FEEDER_FMT, AFMT_S16_LE | AFMT_STEREO, AFMT_U32_LE | AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_U16_BE, AFMT_S32_BE, 0}, + {FEEDER_FMT, AFMT_U16_BE | AFMT_STEREO, AFMT_S32_BE | AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_S16_BE, AFMT_U32_BE, 0}, + {FEEDER_FMT, AFMT_S16_BE | AFMT_STEREO, AFMT_U32_BE | AFMT_STEREO, 0}, + {0, 0, 0, 0}, +}; +static kobj_method_t feeder_16to32_methods[] = { + KOBJMETHOD(feeder_init, feed_updownbit_init), + KOBJMETHOD(feeder_feed, feed_upbit), + {0, 0} +}; +FEEDER_DECLARE(feeder_16to32, 0, NULL); + +static struct pcm_feederdesc feeder_24to32_desc[] = { + {FEEDER_FMT, AFMT_U24_LE, AFMT_U32_LE, 0}, + {FEEDER_FMT, AFMT_U24_LE | AFMT_STEREO, AFMT_U32_LE | AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_S24_LE, AFMT_S32_LE, 0}, + {FEEDER_FMT, AFMT_S24_LE | AFMT_STEREO, AFMT_S32_LE | AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_U24_BE, AFMT_U32_BE, 0}, + {FEEDER_FMT, AFMT_U24_BE | AFMT_STEREO, AFMT_U32_BE | AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_S24_BE, AFMT_S32_BE, 0}, + {FEEDER_FMT, AFMT_S24_BE | AFMT_STEREO, AFMT_S32_BE | AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_U24_LE, AFMT_S32_LE, 0}, + {FEEDER_FMT, AFMT_U24_LE | AFMT_STEREO, AFMT_S32_LE | AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_S24_LE, AFMT_U32_LE, 0}, + {FEEDER_FMT, AFMT_S24_LE | AFMT_STEREO, AFMT_U32_LE | AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_U24_BE, AFMT_S32_BE, 0}, + {FEEDER_FMT, AFMT_U24_BE | AFMT_STEREO, AFMT_S32_BE | AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_S24_BE, AFMT_U32_BE, 0}, + {FEEDER_FMT, AFMT_S24_BE | AFMT_STEREO, AFMT_U32_BE | AFMT_STEREO, 0}, + {0, 0, 0, 0}, +}; +static kobj_method_t feeder_24to32_methods[] = { + KOBJMETHOD(feeder_init, feed_updownbit_init), + KOBJMETHOD(feeder_feed, feed_upbit), + {0, 0} +}; +FEEDER_DECLARE(feeder_24to32, 0, NULL); + static int -feed_24to16(struct pcm_feeder *f, struct pcm_channel *c, uint8_t *b, +feed_downbit(struct pcm_feeder *f, struct pcm_channel *c, uint8_t *b, uint32_t count, void *source) { - struct feed_fmt_info *info = f->data; - int i, j, k, sign; - uint8_t *src = info->buffer; - - if (count < 2) - return 0; - k = (count >> 1) * 3; - k = FEEDER_FEED(f->source, c, src, min(k, info->bufsz), source); - if (k < 3) { - FMT_TRACE("%s: Not enough data (Got: %d bytes)\n", - __func__, k); - return 0; - } - FMT_TEST(k % 3, "%s: Bytes not 24bit aligned.\n", __func__); - k -= k % 3; - i = (k / 3) << 1; - j = i; - sign = swap_sign(f); - if (f->desc->in & AFMT_BIGENDIAN) { - while (i > 1) { - k--; - b[--i] = src[--k]; - b[--i] = src[--k] ^ sign; + int i, j, k, sign, be, ibps, ialign, obps, oalign,dump; + uint8_t *src, *dst, *end; + uint8_t reservoir[FEEDFMT_RESERVOIR]; + + ibps = FBIT_INBPS((intptr_t)f->data); + obps = FBIT_OUTBPS((intptr_t)f->data); + + ialign = ibps * FBIT_CHANNELS((intptr_t)f->data); + oalign = obps * FBIT_CHANNELS((intptr_t)f->data); + + if (count < oalign) + return (0); + + dst = b; + dump = ibps - obps; + sign = FEEDFMT_SWAP_SIGN(f); + be = (f->desc->in & AFMT_BIGENDIAN) ? 1 : 0; + k = count - (count % oalign); + + do { + if (k < oalign) + break; + + if (k < ialign) { + src = reservoir; + j = ialign; + } else { + src = dst; + j = k; } - } else { - while (i > 1) { - b[--i] = src[--k] ^ sign; - b[--i] = src[--k]; - k--; + + j = FEEDER_FEED(f->source, c, src, j - (j % ialign), source); + if (j < ialign) + break; + + j -= j % ialign; + j *= obps; + j /= ibps; + end = dst + j; + + if (be != 0) { + do { + *dst++ = *src++ ^ sign; + i = obps; + while (--i != 0) + *dst++ = *src++; + src += dump; + } while (dst != end); + } else { + do { + src += dump; + i = obps; + while (--i != 0) + *dst++ = *src++; + *dst++ = *src++ ^ sign; + } while (dst != end); } - } - return j; + + k -= j; + } while (k != 0); + + return (dst - b); } + +static struct pcm_feederdesc feeder_16to8_desc[] = { + {FEEDER_FMT, AFMT_U16_LE, AFMT_U8, 0}, + {FEEDER_FMT, AFMT_U16_LE | AFMT_STEREO, AFMT_U8 | AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_S16_LE, AFMT_S8, 0}, + {FEEDER_FMT, AFMT_S16_LE | AFMT_STEREO, AFMT_S8 | AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_U16_BE, AFMT_U8, 0}, + {FEEDER_FMT, AFMT_U16_BE | AFMT_STEREO, AFMT_U8 | AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_S16_BE, AFMT_S8, 0}, + {FEEDER_FMT, AFMT_S16_BE | AFMT_STEREO, AFMT_S8 | AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_U16_LE, AFMT_S8, 0}, + {FEEDER_FMT, AFMT_U16_LE | AFMT_STEREO, AFMT_S8 | AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_S16_LE, AFMT_U8, 0}, + {FEEDER_FMT, AFMT_S16_LE | AFMT_STEREO, AFMT_U8 | AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_U16_BE, AFMT_S8, 0}, + {FEEDER_FMT, AFMT_U16_BE | AFMT_STEREO, AFMT_S8 | AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_S16_BE, AFMT_U8, 0}, + {FEEDER_FMT, AFMT_S16_BE | AFMT_STEREO, AFMT_U8 | AFMT_STEREO, 0}, + {0, 0, 0, 0}, +}; +static kobj_method_t feeder_16to8_methods[] = { + KOBJMETHOD(feeder_init, feed_updownbit_init), + KOBJMETHOD(feeder_feed, feed_downbit), + {0, 0} +}; +FEEDER_DECLARE(feeder_16to8, 0, NULL); + +static struct pcm_feederdesc feeder_24to8_desc[] = { + {FEEDER_FMT, AFMT_U24_LE, AFMT_U8, 0}, + {FEEDER_FMT, AFMT_U24_LE | AFMT_STEREO, AFMT_U8 | AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_S24_LE, AFMT_S8, 0}, + {FEEDER_FMT, AFMT_S24_LE | AFMT_STEREO, AFMT_S8 | AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_U24_BE, AFMT_U8, 0}, + {FEEDER_FMT, AFMT_U24_BE | AFMT_STEREO, AFMT_U8 | AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_S24_BE, AFMT_S8, 0}, + {FEEDER_FMT, AFMT_S24_BE | AFMT_STEREO, AFMT_S8 | AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_U24_LE, AFMT_S8, 0}, + {FEEDER_FMT, AFMT_U24_LE | AFMT_STEREO, AFMT_S8 | AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_S24_LE, AFMT_U8, 0}, + {FEEDER_FMT, AFMT_S24_LE | AFMT_STEREO, AFMT_U8 | AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_U24_BE, AFMT_S8, 0}, + {FEEDER_FMT, AFMT_U24_BE | AFMT_STEREO, AFMT_S8 | AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_S24_BE, AFMT_U8, 0}, + {FEEDER_FMT, AFMT_S24_BE | AFMT_STEREO, AFMT_U8 | AFMT_STEREO, 0}, + {0, 0, 0, 0}, +}; +static kobj_method_t feeder_24to8_methods[] = { + KOBJMETHOD(feeder_init, feed_updownbit_init), + KOBJMETHOD(feeder_feed, feed_downbit), + {0, 0} +}; +FEEDER_DECLARE(feeder_24to8, 0, NULL); + static struct pcm_feederdesc feeder_24to16_desc[] = { {FEEDER_FMT, AFMT_U24_LE, AFMT_U16_LE, 0}, - {FEEDER_FMT, AFMT_U24_LE|AFMT_STEREO, AFMT_U16_LE|AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_U24_LE | AFMT_STEREO, AFMT_U16_LE | AFMT_STEREO, 0}, {FEEDER_FMT, AFMT_S24_LE, AFMT_S16_LE, 0}, - {FEEDER_FMT, AFMT_S24_LE|AFMT_STEREO, AFMT_S16_LE|AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_S24_LE | AFMT_STEREO, AFMT_S16_LE | AFMT_STEREO, 0}, {FEEDER_FMT, AFMT_U24_BE, AFMT_U16_BE, 0}, - {FEEDER_FMT, AFMT_U24_BE|AFMT_STEREO, AFMT_U16_BE|AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_U24_BE | AFMT_STEREO, AFMT_U16_BE | AFMT_STEREO, 0}, {FEEDER_FMT, AFMT_S24_BE, AFMT_S16_BE, 0}, - {FEEDER_FMT, AFMT_S24_BE|AFMT_STEREO, AFMT_S16_BE|AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_S24_BE | AFMT_STEREO, AFMT_S16_BE | AFMT_STEREO, 0}, {FEEDER_FMT, AFMT_U24_LE, AFMT_S16_LE, 0}, - {FEEDER_FMT, AFMT_U24_LE|AFMT_STEREO, AFMT_S16_LE|AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_U24_LE | AFMT_STEREO, AFMT_S16_LE | AFMT_STEREO, 0}, {FEEDER_FMT, AFMT_S24_LE, AFMT_U16_LE, 0}, - {FEEDER_FMT, AFMT_S24_LE|AFMT_STEREO, AFMT_U16_LE|AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_S24_LE | AFMT_STEREO, AFMT_U16_LE | AFMT_STEREO, 0}, {FEEDER_FMT, AFMT_U24_BE, AFMT_S16_BE, 0}, - {FEEDER_FMT, AFMT_U24_BE|AFMT_STEREO, AFMT_S16_BE|AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_U24_BE | AFMT_STEREO, AFMT_S16_BE | AFMT_STEREO, 0}, {FEEDER_FMT, AFMT_S24_BE, AFMT_U16_BE, 0}, - {FEEDER_FMT, AFMT_S24_BE|AFMT_STEREO, AFMT_U16_BE|AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_S24_BE | AFMT_STEREO, AFMT_U16_BE | AFMT_STEREO, 0}, {0, 0, 0, 0}, }; static kobj_method_t feeder_24to16_methods[] = { - KOBJMETHOD(feeder_init, feed_fmt_init), - KOBJMETHOD(feeder_free, feed_fmt_free), - KOBJMETHOD(feeder_feed, feed_24to16), + KOBJMETHOD(feeder_init, feed_updownbit_init), + KOBJMETHOD(feeder_feed, feed_downbit), {0, 0} }; -FEEDER_DECLARE(feeder_24to16, 1, NULL); - -static int -feed_16to32(struct pcm_feeder *f, struct pcm_channel *c, uint8_t *b, - uint32_t count, void *source) -{ - int i, j, sign, k; - - if (count < 4) - return 0; - k = FEEDER_FEED(f->source, c, b, (count & ~3) >> 1, source); - if (k < 2) { - FMT_TRACE("%s: Not enough data (Got: %d bytes)\n", - __func__, k); - return 0; - } - FMT_TEST(k & 1, "%s: Bytes not 16bit aligned.\n", __func__); - k &= ~1; - i = k; - j = k << 1; - k = j; - sign = swap_sign(f); - if (f->desc->in & AFMT_BIGENDIAN) { - while (i > 1) { - b[--j] = 0; - b[--j] = 0; - b[--j] = b[--i]; - b[--j] = b[--i] ^ sign; - } - } else { - while (i > 1) { - b[--j] = b[--i] ^ sign; - b[--j] = b[--i]; - b[--j] = 0; - b[--j] = 0; - } - } - return k; -} -static struct pcm_feederdesc feeder_16to32_desc[] = { - {FEEDER_FMT, AFMT_U16_LE, AFMT_U32_LE, 0}, - {FEEDER_FMT, AFMT_U16_LE|AFMT_STEREO, AFMT_U32_LE|AFMT_STEREO, 0}, - {FEEDER_FMT, AFMT_S16_LE, AFMT_S32_LE, 0}, - {FEEDER_FMT, AFMT_S16_LE|AFMT_STEREO, AFMT_S32_LE|AFMT_STEREO, 0}, - {FEEDER_FMT, AFMT_U16_BE, AFMT_U32_BE, 0}, - {FEEDER_FMT, AFMT_U16_BE|AFMT_STEREO, AFMT_U32_BE|AFMT_STEREO, 0}, - {FEEDER_FMT, AFMT_S16_BE, AFMT_S32_BE, 0}, - {FEEDER_FMT, AFMT_S16_BE|AFMT_STEREO, AFMT_S32_BE|AFMT_STEREO, 0}, - {FEEDER_FMT, AFMT_U16_LE, AFMT_S32_LE, 0}, - {FEEDER_FMT, AFMT_U16_LE|AFMT_STEREO, AFMT_S32_LE|AFMT_STEREO, 0}, - {FEEDER_FMT, AFMT_S16_LE, AFMT_U32_LE, 0}, - {FEEDER_FMT, AFMT_S16_LE|AFMT_STEREO, AFMT_U32_LE|AFMT_STEREO, 0}, - {FEEDER_FMT, AFMT_U16_BE, AFMT_S32_BE, 0}, - {FEEDER_FMT, AFMT_U16_BE|AFMT_STEREO, AFMT_S32_BE|AFMT_STEREO, 0}, - {FEEDER_FMT, AFMT_S16_BE, AFMT_U32_BE, 0}, - {FEEDER_FMT, AFMT_S16_BE|AFMT_STEREO, AFMT_U32_BE|AFMT_STEREO, 0}, +FEEDER_DECLARE(feeder_24to16, 0, NULL); + +static struct pcm_feederdesc feeder_32to8_desc[] = { + {FEEDER_FMT, AFMT_U32_LE, AFMT_U8, 0}, + {FEEDER_FMT, AFMT_U32_LE | AFMT_STEREO, AFMT_U8 | AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_S32_LE, AFMT_S8, 0}, + {FEEDER_FMT, AFMT_S32_LE | AFMT_STEREO, AFMT_S8 | AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_U32_BE, AFMT_U8, 0}, + {FEEDER_FMT, AFMT_U32_BE | AFMT_STEREO, AFMT_U8 | AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_S32_BE, AFMT_S8, 0}, + {FEEDER_FMT, AFMT_S32_BE | AFMT_STEREO, AFMT_S8 | AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_U32_LE, AFMT_S8, 0}, + {FEEDER_FMT, AFMT_U32_LE | AFMT_STEREO, AFMT_S8 | AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_S32_LE, AFMT_U8, 0}, + {FEEDER_FMT, AFMT_S32_LE | AFMT_STEREO, AFMT_U8 | AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_U32_BE, AFMT_S8, 0}, + {FEEDER_FMT, AFMT_U32_BE | AFMT_STEREO, AFMT_S8 | AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_S32_BE, AFMT_U8, 0}, + {FEEDER_FMT, AFMT_S32_BE | AFMT_STEREO, AFMT_U8 | AFMT_STEREO, 0}, {0, 0, 0, 0}, }; -static kobj_method_t feeder_16to32_methods[] = { - KOBJMETHOD(feeder_feed, feed_16to32), +static kobj_method_t feeder_32to8_methods[] = { + KOBJMETHOD(feeder_init, feed_updownbit_init), + KOBJMETHOD(feeder_feed, feed_downbit), {0, 0} }; -FEEDER_DECLARE(feeder_16to32, 0, NULL); +FEEDER_DECLARE(feeder_32to8, 0, NULL); -static int -feed_32to16(struct pcm_feeder *f, struct pcm_channel *c, uint8_t *b, - uint32_t count, void *source) -{ - struct feed_fmt_info *info = f->data; - int i, j, k, sign; - uint8_t *src = info->buffer; - - if (count < 2) - return 0; - k = (count & ~1) << 1; - k = FEEDER_FEED(f->source, c, src, min(k, info->bufsz), source); - if (k < 4) { - FMT_TRACE("%s: Not enough data (Got: %d bytes)\n", - __func__, k); - return 0; - } - FMT_TEST(k & 3, "%s: Bytes not 32bit aligned.\n", __func__); - k &= ~3; - i = k; - k >>= 1; - j = k; - sign = swap_sign(f); - if (f->desc->in & AFMT_BIGENDIAN) { - while (i > 3) { - i -= 2; - b[--j] = src[--i]; - b[--j] = src[--i] ^ sign; - } - } else { - while (i > 3) { - b[--j] = src[--i] ^ sign; - b[--j] = src[--i]; - i -= 2; - } - } - return k; -} static struct pcm_feederdesc feeder_32to16_desc[] = { {FEEDER_FMT, AFMT_U32_LE, AFMT_U16_LE, 0}, - {FEEDER_FMT, AFMT_U32_LE|AFMT_STEREO, AFMT_U16_LE|AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_U32_LE | AFMT_STEREO, AFMT_U16_LE | AFMT_STEREO, 0}, {FEEDER_FMT, AFMT_S32_LE, AFMT_S16_LE, 0}, - {FEEDER_FMT, AFMT_S32_LE|AFMT_STEREO, AFMT_S16_LE|AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_S32_LE | AFMT_STEREO, AFMT_S16_LE | AFMT_STEREO, 0}, {FEEDER_FMT, AFMT_U32_BE, AFMT_U16_BE, 0}, - {FEEDER_FMT, AFMT_U32_BE|AFMT_STEREO, AFMT_U16_BE|AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_U32_BE | AFMT_STEREO, AFMT_U16_BE | AFMT_STEREO, 0}, {FEEDER_FMT, AFMT_S32_BE, AFMT_S16_BE, 0}, - {FEEDER_FMT, AFMT_S32_BE|AFMT_STEREO, AFMT_S16_BE|AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_S32_BE | AFMT_STEREO, AFMT_S16_BE | AFMT_STEREO, 0}, {FEEDER_FMT, AFMT_U32_LE, AFMT_S16_LE, 0}, - {FEEDER_FMT, AFMT_U32_LE|AFMT_STEREO, AFMT_S16_LE|AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_U32_LE | AFMT_STEREO, AFMT_S16_LE | AFMT_STEREO, 0}, {FEEDER_FMT, AFMT_S32_LE, AFMT_U16_LE, 0}, - {FEEDER_FMT, AFMT_S32_LE|AFMT_STEREO, AFMT_U16_LE|AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_S32_LE | AFMT_STEREO, AFMT_U16_LE | AFMT_STEREO, 0}, {FEEDER_FMT, AFMT_U32_BE, AFMT_S16_BE, 0}, - {FEEDER_FMT, AFMT_U32_BE|AFMT_STEREO, AFMT_S16_BE|AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_U32_BE | AFMT_STEREO, AFMT_S16_BE | AFMT_STEREO, 0}, {FEEDER_FMT, AFMT_S32_BE, AFMT_U16_BE, 0}, - {FEEDER_FMT, AFMT_S32_BE|AFMT_STEREO, AFMT_U16_BE|AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_S32_BE | AFMT_STEREO, AFMT_U16_BE | AFMT_STEREO, 0}, {0, 0, 0, 0}, }; static kobj_method_t feeder_32to16_methods[] = { - KOBJMETHOD(feeder_init, feed_fmt_init), - KOBJMETHOD(feeder_free, feed_fmt_free), - KOBJMETHOD(feeder_feed, feed_32to16), + KOBJMETHOD(feeder_init, feed_updownbit_init), + KOBJMETHOD(feeder_feed, feed_downbit), {0, 0} }; -FEEDER_DECLARE(feeder_32to16, 1, NULL); +FEEDER_DECLARE(feeder_32to16, 0, NULL); -static int -feed_24to32(struct pcm_feeder *f, struct pcm_channel *c, uint8_t *b, - uint32_t count, void *source) -{ - int i, j, k, sign; - - if (count < 4) - return 0; - k = FEEDER_FEED(f->source, c, b, (count >> 2) * 3, source); - if (k < 3) { - FMT_TRACE("%s: Not enough data (Got: %d bytes)\n", - __func__, k); - return 0; - } - FMT_TEST(k % 3, "%s: Bytes not 24bit aligned.\n", __func__); - k -= k % 3; - i = k; - k = (k / 3) << 2; - j = k; - sign = swap_sign(f); - if (f->desc->in & AFMT_BIGENDIAN) { - while (i > 2) { - b[--j] = 0; - b[--j] = b[--i]; - b[--j] = b[--i]; - b[--j] = b[--i] ^ sign; - } - } else { - while (i > 2) { - b[--j] = b[--i] ^ sign; - b[--j] = b[--i]; - b[--j] = b[--i]; - b[--j] = 0; - } - } - return k; -} -static struct pcm_feederdesc feeder_24to32_desc[] = { - {FEEDER_FMT, AFMT_U24_LE, AFMT_U32_LE, 0}, - {FEEDER_FMT, AFMT_U24_LE|AFMT_STEREO, AFMT_U32_LE|AFMT_STEREO, 0}, - {FEEDER_FMT, AFMT_S24_LE, AFMT_S32_LE, 0}, - {FEEDER_FMT, AFMT_S24_LE|AFMT_STEREO, AFMT_S32_LE|AFMT_STEREO, 0}, - {FEEDER_FMT, AFMT_U24_BE, AFMT_U32_BE, 0}, - {FEEDER_FMT, AFMT_U24_BE|AFMT_STEREO, AFMT_U32_BE|AFMT_STEREO, 0}, - {FEEDER_FMT, AFMT_S24_BE, AFMT_S32_BE, 0}, - {FEEDER_FMT, AFMT_S24_BE|AFMT_STEREO, AFMT_S32_BE|AFMT_STEREO, 0}, - {FEEDER_FMT, AFMT_U24_LE, AFMT_S32_LE, 0}, - {FEEDER_FMT, AFMT_U24_LE|AFMT_STEREO, AFMT_S32_LE|AFMT_STEREO, 0}, - {FEEDER_FMT, AFMT_S24_LE, AFMT_U32_LE, 0}, - {FEEDER_FMT, AFMT_S24_LE|AFMT_STEREO, AFMT_U32_LE|AFMT_STEREO, 0}, - {FEEDER_FMT, AFMT_U24_BE, AFMT_S32_BE, 0}, - {FEEDER_FMT, AFMT_U24_BE|AFMT_STEREO, AFMT_S32_BE|AFMT_STEREO, 0}, - {FEEDER_FMT, AFMT_S24_BE, AFMT_U32_BE, 0}, - {FEEDER_FMT, AFMT_S24_BE|AFMT_STEREO, AFMT_U32_BE|AFMT_STEREO, 0}, - {0, 0, 0, 0}, -}; -static kobj_method_t feeder_24to32_methods[] = { - KOBJMETHOD(feeder_feed, feed_24to32), - {0, 0} -}; -FEEDER_DECLARE(feeder_24to32, 1, NULL); - -static int -feed_32to24(struct pcm_feeder *f, struct pcm_channel *c, uint8_t *b, - uint32_t count, void *source) -{ - struct feed_fmt_info *info = f->data; - int i, j, k, sign; - uint8_t *src = info->buffer; - - if (count < 3) - return 0; - k = (count / 3) << 2; - k = FEEDER_FEED(f->source, c, src, min(k, info->bufsz), source); - if (k < 4) { - FMT_TRACE("%s: Not enough data (Got: %d bytes)\n", - __func__, k); - return 0; - } - FMT_TEST(k & 3, "%s: Bytes not 32bit aligned.\n", __func__); - k &= ~3; - i = k; - k = (k >> 2) * 3; - j = k; - sign = swap_sign(f); - if (f->desc->in & AFMT_BIGENDIAN) { - while (i > 3) { - --i; - b[--j] = src[--i]; - b[--j] = src[--i]; - b[--j] = src[--i] ^ sign; - } - } else { - while (i > 3) { - b[--j] = src[--i] ^ sign; - b[--j] = src[--i]; - b[--j] = src[--i]; - --i; - } - } - return k; -} static struct pcm_feederdesc feeder_32to24_desc[] = { {FEEDER_FMT, AFMT_U32_LE, AFMT_U24_LE, 0}, - {FEEDER_FMT, AFMT_U32_LE|AFMT_STEREO, AFMT_U24_LE|AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_U32_LE | AFMT_STEREO, AFMT_U24_LE | AFMT_STEREO, 0}, {FEEDER_FMT, AFMT_S32_LE, AFMT_S24_LE, 0}, - {FEEDER_FMT, AFMT_S32_LE|AFMT_STEREO, AFMT_S24_LE|AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_S32_LE | AFMT_STEREO, AFMT_S24_LE | AFMT_STEREO, 0}, {FEEDER_FMT, AFMT_U32_BE, AFMT_U24_BE, 0}, - {FEEDER_FMT, AFMT_U32_BE|AFMT_STEREO, AFMT_U24_BE|AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_U32_BE | AFMT_STEREO, AFMT_U24_BE | AFMT_STEREO, 0}, {FEEDER_FMT, AFMT_S32_BE, AFMT_S24_BE, 0}, - {FEEDER_FMT, AFMT_S32_BE|AFMT_STEREO, AFMT_S24_BE|AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_S32_BE | AFMT_STEREO, AFMT_S24_BE | AFMT_STEREO, 0}, {FEEDER_FMT, AFMT_U32_LE, AFMT_S24_LE, 0}, - {FEEDER_FMT, AFMT_U32_LE|AFMT_STEREO, AFMT_S24_LE|AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_U32_LE | AFMT_STEREO, AFMT_S24_LE | AFMT_STEREO, 0}, {FEEDER_FMT, AFMT_S32_LE, AFMT_U24_LE, 0}, - {FEEDER_FMT, AFMT_S32_LE|AFMT_STEREO, AFMT_U24_LE|AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_S32_LE | AFMT_STEREO, AFMT_U24_LE | AFMT_STEREO, 0}, {FEEDER_FMT, AFMT_U32_BE, AFMT_S24_BE, 0}, - {FEEDER_FMT, AFMT_U32_BE|AFMT_STEREO, AFMT_S24_BE|AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_U32_BE | AFMT_STEREO, AFMT_S24_BE | AFMT_STEREO, 0}, {FEEDER_FMT, AFMT_S32_BE, AFMT_U24_BE, 0}, - {FEEDER_FMT, AFMT_S32_BE|AFMT_STEREO, AFMT_U24_BE|AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_S32_BE | AFMT_STEREO, AFMT_U24_BE | AFMT_STEREO, 0}, {0, 0, 0, 0}, }; static kobj_method_t feeder_32to24_methods[] = { - KOBJMETHOD(feeder_init, feed_fmt_init), - KOBJMETHOD(feeder_free, feed_fmt_free), - KOBJMETHOD(feeder_feed, feed_32to24), + KOBJMETHOD(feeder_init, feed_updownbit_init), + KOBJMETHOD(feeder_feed, feed_downbit), {0, 0} }; -FEEDER_DECLARE(feeder_32to24, 1, NULL); +FEEDER_DECLARE(feeder_32to24, 0, NULL); /* * Bit conversion end */ @@ -905,169 +853,88 @@ FEEDER_DECLARE(feeder_32to24, 1, NULL); * Channel conversion (mono -> stereo) */ static int -feed_monotostereo8(struct pcm_feeder *f, struct pcm_channel *c, uint8_t *b, +feed_monotostereo(struct pcm_feeder *f, struct pcm_channel *c, uint8_t *b, uint32_t count, void *source) { - int i, j, k; + int bps, i, j, k, l; + uint8_t v; - if (count < 2) - return 0; - k = FEEDER_FEED(f->source, c, b, count >> 1, source); - i = k; - j = k << 1; - while (i > 0) { - b[--j] = b[--i]; - b[--j] = b[i]; - } - return k << 1; + bps = (int)((intptr_t)f->data); + if (count < (bps << 1)) + return (0); + + j = FEEDER_FEED(f->source, c, b, (count - (count % bps)) >> 1, source); + if (j < bps) + return (0); + + j -= j % bps; + i = j << 1; + l = i; + + do { + k = bps; + do { + v = b[--j]; + b[--i] = v; + b[i - bps] = v; + } while (--k != 0); + i -= bps; + } while (i != 0); + + return (l); } + static struct pcm_feederdesc feeder_monotostereo8_desc[] = { - {FEEDER_FMT, AFMT_U8, AFMT_U8|AFMT_STEREO, 0}, - {FEEDER_FMT, AFMT_S8, AFMT_S8|AFMT_STEREO, 0}, - {FEEDER_FMT, AFMT_MU_LAW, AFMT_MU_LAW|AFMT_STEREO, 0}, - {FEEDER_FMT, AFMT_A_LAW, AFMT_A_LAW|AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_U8, AFMT_U8 | AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_S8, AFMT_S8 | AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_MU_LAW, AFMT_MU_LAW | AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_A_LAW, AFMT_A_LAW | AFMT_STEREO, 0}, {0, 0, 0, 0}, }; static kobj_method_t feeder_monotostereo8_methods[] = { - KOBJMETHOD(feeder_feed, feed_monotostereo8), + KOBJMETHOD(feeder_feed, feed_monotostereo), {0, 0} }; -FEEDER_DECLARE(feeder_monotostereo8, 0, NULL); +FEEDER_DECLARE(feeder_monotostereo8, 0, (void *)PCM_8_BPS); -static int -feed_monotostereo16(struct pcm_feeder *f, struct pcm_channel *c, uint8_t *b, - uint32_t count, void *source) -{ - int i, j, k; - uint8_t l, m; - - if (count < 4) - return 0; - k = FEEDER_FEED(f->source, c, b, (count & ~3) >> 1, source); - if (k < 2) { - FMT_TRACE("%s: Not enough data (Got: %d bytes)\n", - __func__, k); - return 0; - } - FMT_TEST(k & 1, "%s: Bytes not 16bit aligned.\n", __func__); - k &= ~1; - i = k; - j = k << 1; - while (i > 1) { - l = b[--i]; - m = b[--i]; - b[--j] = l; - b[--j] = m; - b[--j] = l; - b[--j] = m; - } - return k << 1; -} static struct pcm_feederdesc feeder_monotostereo16_desc[] = { - {FEEDER_FMT, AFMT_U16_LE, AFMT_U16_LE|AFMT_STEREO, 0}, - {FEEDER_FMT, AFMT_S16_LE, AFMT_S16_LE|AFMT_STEREO, 0}, - {FEEDER_FMT, AFMT_U16_BE, AFMT_U16_BE|AFMT_STEREO, 0}, - {FEEDER_FMT, AFMT_S16_BE, AFMT_S16_BE|AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_U16_LE, AFMT_U16_LE | AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_S16_LE, AFMT_S16_LE | AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_U16_BE, AFMT_U16_BE | AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_S16_BE, AFMT_S16_BE | AFMT_STEREO, 0}, {0, 0, 0, 0}, }; static kobj_method_t feeder_monotostereo16_methods[] = { - KOBJMETHOD(feeder_feed, feed_monotostereo16), + KOBJMETHOD(feeder_feed, feed_monotostereo), {0, 0} }; -FEEDER_DECLARE(feeder_monotostereo16, 0, NULL); +FEEDER_DECLARE(feeder_monotostereo16, 0, (void *)PCM_16_BPS); -static int -feed_monotostereo24(struct pcm_feeder *f, struct pcm_channel *c, uint8_t *b, - uint32_t count, void *source) -{ - int i, j, k; - uint8_t l, m, n; - - if (count < 6) - return 0; - k = FEEDER_FEED(f->source, c, b, ((count / 6) * 6) >> 1, source); - if (k < 3) { - FMT_TRACE("%s: Not enough data (Got: %d bytes)\n", - __func__, k); - return 0; - } - FMT_TEST(k % 3, "%s: Bytes not 24bit aligned.\n", __func__); - k -= k % 3; - i = k; - j = k << 1; - while (i > 2) { - l = b[--i]; - m = b[--i]; - n = b[--i]; - b[--j] = l; - b[--j] = m; - b[--j] = n; - b[--j] = l; - b[--j] = m; - b[--j] = n; - } - return k << 1; -} static struct pcm_feederdesc feeder_monotostereo24_desc[] = { - {FEEDER_FMT, AFMT_U24_LE, AFMT_U24_LE|AFMT_STEREO, 0}, - {FEEDER_FMT, AFMT_S24_LE, AFMT_S24_LE|AFMT_STEREO, 0}, - {FEEDER_FMT, AFMT_U24_BE, AFMT_U24_BE|AFMT_STEREO, 0}, - {FEEDER_FMT, AFMT_S24_BE, AFMT_S24_BE|AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_U24_LE, AFMT_U24_LE | AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_S24_LE, AFMT_S24_LE | AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_U24_BE, AFMT_U24_BE | AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_S24_BE, AFMT_S24_BE | AFMT_STEREO, 0}, {0, 0, 0, 0}, }; static kobj_method_t feeder_monotostereo24_methods[] = { - KOBJMETHOD(feeder_feed, feed_monotostereo24), + KOBJMETHOD(feeder_feed, feed_monotostereo), {0, 0} }; -FEEDER_DECLARE(feeder_monotostereo24, 0, NULL); +FEEDER_DECLARE(feeder_monotostereo24, 0, (void *)PCM_24_BPS); -static int -feed_monotostereo32(struct pcm_feeder *f, struct pcm_channel *c, uint8_t *b, - uint32_t count, void *source) -{ - int i, j, k; - uint8_t l, m, n, o; - - if (count < 8) - return 0; - k = FEEDER_FEED(f->source, c, b, (count & ~7) >> 1, source); - if (k < 4) { - FMT_TRACE("%s: Not enough data (Got: %d bytes)\n", - __func__, k); - return 0; - } - FMT_TEST(k & 3, "%s: Bytes not 32bit aligned.\n", __func__); - k &= ~3; - i = k; - j = k << 1; - while (i > 3) { - l = b[--i]; - m = b[--i]; - n = b[--i]; - o = b[--i]; - b[--j] = l; - b[--j] = m; - b[--j] = n; - b[--j] = o; - b[--j] = l; - b[--j] = m; - b[--j] = n; - b[--j] = o; - } - return k << 1; -} static struct pcm_feederdesc feeder_monotostereo32_desc[] = { - {FEEDER_FMT, AFMT_U32_LE, AFMT_U32_LE|AFMT_STEREO, 0}, - {FEEDER_FMT, AFMT_S32_LE, AFMT_S32_LE|AFMT_STEREO, 0}, - {FEEDER_FMT, AFMT_U32_BE, AFMT_U32_BE|AFMT_STEREO, 0}, - {FEEDER_FMT, AFMT_S32_BE, AFMT_S32_BE|AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_U32_LE, AFMT_U32_LE | AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_S32_LE, AFMT_S32_LE | AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_U32_BE, AFMT_U32_BE | AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_S32_BE, AFMT_S32_BE | AFMT_STEREO, 0}, {0, 0, 0, 0}, }; static kobj_method_t feeder_monotostereo32_methods[] = { - KOBJMETHOD(feeder_feed, feed_monotostereo32), + KOBJMETHOD(feeder_feed, feed_monotostereo), {0, 0} }; -FEEDER_DECLARE(feeder_monotostereo32, 0, NULL); +FEEDER_DECLARE(feeder_monotostereo32, 0, (void *)PCM_32_BPS); /* * Channel conversion (mono -> stereo) end */ @@ -1075,176 +942,219 @@ FEEDER_DECLARE(feeder_monotostereo32, 0, NULL); /* * Channel conversion (stereo -> mono) */ +#define FEEDER_FMT_STEREODOWNMIX(FMTBIT, FMT_INTCAST, SIGN, \ + SIGNS, ENDIAN, ENDIANS) \ +static void \ +SIGNS##FMTBIT##ENDIANS##_stereodownmix(uint8_t *dst, uint8_t *sx, uint8_t *sy) \ +{ \ + int32_t v; \ + \ + v = ((FMT_INTCAST)PCM_READ_##SIGN##FMTBIT##_##ENDIAN(sx) + \ + PCM_READ_##SIGN##FMTBIT##_##ENDIAN(sy)) >> 1; \ + PCM_WRITE_##SIGN##FMTBIT##_##ENDIAN(dst, v); \ +} + +FEEDER_FMT_STEREODOWNMIX(8, int32_t, S, s, NE, ne); +FEEDER_FMT_STEREODOWNMIX(16, int32_t, S, s, LE, le); +FEEDER_FMT_STEREODOWNMIX(24, int32_t, S, s, LE, le); +FEEDER_FMT_STEREODOWNMIX(32, intpcm_t, S, s, LE, le); +FEEDER_FMT_STEREODOWNMIX(16, int32_t, S, s, BE, be); +FEEDER_FMT_STEREODOWNMIX(24, int32_t, S, s, BE, be); +FEEDER_FMT_STEREODOWNMIX(32, intpcm_t, S, s, BE, be); +FEEDER_FMT_STEREODOWNMIX(8, int32_t, U, u, NE, ne); +FEEDER_FMT_STEREODOWNMIX(16, int32_t, U, u, LE, le); +FEEDER_FMT_STEREODOWNMIX(24, int32_t, U, u, LE, le); +FEEDER_FMT_STEREODOWNMIX(32, intpcm_t, U, u, LE, le); +FEEDER_FMT_STEREODOWNMIX(16, int32_t, U, u, BE, be); +FEEDER_FMT_STEREODOWNMIX(24, int32_t, U, u, BE, be); +FEEDER_FMT_STEREODOWNMIX(32, intpcm_t, U, u, BE, be); + +static void +ulaw_stereodownmix(uint8_t *dst, uint8_t *sx, uint8_t *sy) +{ + uint8_t v; + + v = ((uint32_t)ulaw_to_u8_tbl[*sx] + ulaw_to_u8_tbl[*sy]) >> 1; + *dst = u8_to_ulaw_tbl[v]; +} + +static void +alaw_stereodownmix(uint8_t *dst, uint8_t *sx, uint8_t *sy) +{ + uint8_t v; + + v = ((uint32_t)alaw_to_u8_tbl[*sx] + alaw_to_u8_tbl[*sy]) >> 1; + *dst = u8_to_alaw_tbl[v]; +} + +typedef void (*feed_fmt_stereodownmix_filter)(uint8_t *, + uint8_t *, uint8_t *); + +struct feed_fmt_stereodownmix_info { + uint32_t format; + int bps; + feed_fmt_stereodownmix_filter func[2]; +}; + +static struct feed_fmt_stereodownmix_info feed_fmt_stereodownmix_tbl[] = { + { AFMT_S8, PCM_8_BPS, { NULL, s8ne_stereodownmix }}, + { AFMT_S16_LE, PCM_16_BPS, { NULL, s16le_stereodownmix }}, + { AFMT_S16_BE, PCM_16_BPS, { NULL, s16be_stereodownmix }}, + { AFMT_S24_LE, PCM_24_BPS, { NULL, s24le_stereodownmix }}, + { AFMT_S24_BE, PCM_24_BPS, { NULL, s24be_stereodownmix }}, + { AFMT_S32_LE, PCM_32_BPS, { NULL, s32le_stereodownmix }}, + { AFMT_S32_BE, PCM_32_BPS, { NULL, s32be_stereodownmix }}, + { AFMT_U8, PCM_8_BPS, { NULL, u8ne_stereodownmix }}, + { AFMT_A_LAW, PCM_8_BPS, { NULL, alaw_stereodownmix }}, + { AFMT_MU_LAW, PCM_8_BPS, { NULL, ulaw_stereodownmix }}, + { AFMT_U16_LE, PCM_16_BPS, { NULL, u16le_stereodownmix }}, + { AFMT_U16_BE, PCM_16_BPS, { NULL, u16be_stereodownmix }}, + { AFMT_U24_LE, PCM_24_BPS, { NULL, u24le_stereodownmix }}, + { AFMT_U24_BE, PCM_24_BPS, { NULL, u24be_stereodownmix }}, + { AFMT_U32_LE, PCM_32_BPS, { NULL, u32le_stereodownmix }}, + { AFMT_U32_BE, PCM_32_BPS, { NULL, u32be_stereodownmix }}, +}; + +#define FSM_DATA(i, j) ((intptr_t)((((i) & 0x1f) << 1) | ((j) & 0x1))) +#define FSM_INFOIDX(m) (((m) >> 1) & 0x1f) +#define FSM_FUNCIDX(m) ((m) & 0x1) + static int -feed_stereotomono8(struct pcm_feeder *f, struct pcm_channel *c, uint8_t *b, - uint32_t count, void *source) +feed_stereotomono_init(struct pcm_feeder *f) { - struct feed_fmt_info *info = f->data; - int i, j, k; - uint8_t *src = info->buffer; - - if (count < 1) - return 0; - k = count << 1; - k = FEEDER_FEED(f->source, c, src, min(k, info->bufsz), source); - if (k < 2) { - FMT_TRACE("%s: Not enough data (Got: %d bytes)\n", - __func__, k); - return 0; - } - FMT_TEST(k & 1, "%s: Bytes not 8bit (stereo) aligned.\n", __func__); - k &= ~1; - i = k >> 1; - j = i; - while (i > 0) { - k--; - b[--i] = src[--k]; + int i, funcidx; + + if (!(f->desc->in & AFMT_STEREO) || (f->desc->out & AFMT_STEREO)) + return (-1); + + funcidx = (feeder_fmt_stereodownmix != 0) ? 1 : 0; + + for (i = 0; i < sizeof(feed_fmt_stereodownmix_tbl) / + sizeof(feed_fmt_stereodownmix_tbl[0]); i++) { + if (f->desc->out == feed_fmt_stereodownmix_tbl[i].format) { + f->data = (void *)FSM_DATA(i, funcidx); + return (0); + } } - return j; + + return (-1); +} + +static int +feed_stereotomono(struct pcm_feeder *f, struct pcm_channel *c, uint8_t *b, + uint32_t count, void *source) +{ + struct feed_fmt_stereodownmix_info *info; + feed_fmt_stereodownmix_filter stereodownmix; + int i, j, k, ibps, obps; + uint8_t *src, *dst, *end; + uint8_t reservoir[FEEDFMT_RESERVOIR]; + + info = &feed_fmt_stereodownmix_tbl[FSM_INFOIDX((intptr_t)f->data)]; + obps = info->bps; + + if (count < obps) + return (0); + + stereodownmix = info->func[FSM_FUNCIDX((intptr_t)f->data)]; + ibps = obps << 1; + dst = b; + k = count - (count % obps); + + do { + if (k < obps) + break; + + if (k < ibps) { + src = reservoir; + j = ibps; + } else { + src = dst; + j = k; + } + + j = FEEDER_FEED(f->source, c, src, j - (j % ibps), source); + if (j < ibps) + break; + + j -= j % ibps; + j >>= 1; + end = dst + j; + + if (stereodownmix != NULL) { + do { + stereodownmix(dst, src, src + obps); + dst += obps; + src += ibps; + } while (dst != end); + } else { + do { + i = obps; + do { + *dst++ = *src++; + } while (--i != 0); + src += obps; + } while (dst != end); + } + + k -= j; + } while (k != 0); + + return (dst - b); } + static struct pcm_feederdesc feeder_stereotomono8_desc[] = { - {FEEDER_FMT, AFMT_U8|AFMT_STEREO, AFMT_U8, 0}, - {FEEDER_FMT, AFMT_S8|AFMT_STEREO, AFMT_S8, 0}, - {FEEDER_FMT, AFMT_MU_LAW|AFMT_STEREO, AFMT_MU_LAW, 0}, - {FEEDER_FMT, AFMT_A_LAW|AFMT_STEREO, AFMT_A_LAW, 0}, + {FEEDER_FMT, AFMT_U8 | AFMT_STEREO, AFMT_U8, 0}, + {FEEDER_FMT, AFMT_S8 | AFMT_STEREO, AFMT_S8, 0}, + {FEEDER_FMT, AFMT_MU_LAW | AFMT_STEREO, AFMT_MU_LAW, 0}, + {FEEDER_FMT, AFMT_A_LAW | AFMT_STEREO, AFMT_A_LAW, 0}, {0, 0, 0, 0}, }; static kobj_method_t feeder_stereotomono8_methods[] = { - KOBJMETHOD(feeder_init, feed_fmt_init), - KOBJMETHOD(feeder_free, feed_fmt_free), - KOBJMETHOD(feeder_feed, feed_stereotomono8), + KOBJMETHOD(feeder_init, feed_stereotomono_init), + KOBJMETHOD(feeder_feed, feed_stereotomono), {0, 0} }; FEEDER_DECLARE(feeder_stereotomono8, 0, NULL); -static int -feed_stereotomono16(struct pcm_feeder *f, struct pcm_channel *c, uint8_t *b, - uint32_t count, void *source) -{ - struct feed_fmt_info *info = f->data; - int i, j, k; - uint8_t *src = info->buffer; - - if (count < 2) - return 0; - k = (count & ~1) << 1; - k = FEEDER_FEED(f->source, c, src, min(k, info->bufsz), source); - if (k < 4) { - FMT_TRACE("%s: Not enough data (Got: %d bytes)\n", - __func__, k); - return 0; - } - FMT_TEST(k & 3, "%s: Bytes not 16bit (stereo) aligned.\n", __func__); - k &= ~3; - i = k >> 1; - j = i; - while (i > 1) { - k -= 2; - b[--i] = src[--k]; - b[--i] = src[--k]; - } - return j; -} static struct pcm_feederdesc feeder_stereotomono16_desc[] = { - {FEEDER_FMT, AFMT_U16_LE|AFMT_STEREO, AFMT_U16_LE, 0}, - {FEEDER_FMT, AFMT_S16_LE|AFMT_STEREO, AFMT_S16_LE, 0}, - {FEEDER_FMT, AFMT_U16_BE|AFMT_STEREO, AFMT_U16_BE, 0}, - {FEEDER_FMT, AFMT_S16_BE|AFMT_STEREO, AFMT_S16_BE, 0}, + {FEEDER_FMT, AFMT_U16_LE | AFMT_STEREO, AFMT_U16_LE, 0}, + {FEEDER_FMT, AFMT_S16_LE | AFMT_STEREO, AFMT_S16_LE, 0}, + {FEEDER_FMT, AFMT_U16_BE | AFMT_STEREO, AFMT_U16_BE, 0}, + {FEEDER_FMT, AFMT_S16_BE | AFMT_STEREO, AFMT_S16_BE, 0}, {0, 0, 0, 0}, }; static kobj_method_t feeder_stereotomono16_methods[] = { - KOBJMETHOD(feeder_init, feed_fmt_init), - KOBJMETHOD(feeder_free, feed_fmt_free), - KOBJMETHOD(feeder_feed, feed_stereotomono16), + KOBJMETHOD(feeder_init, feed_stereotomono_init), + KOBJMETHOD(feeder_feed, feed_stereotomono), {0, 0} }; FEEDER_DECLARE(feeder_stereotomono16, 0, NULL); -static int -feed_stereotomono24(struct pcm_feeder *f, struct pcm_channel *c, uint8_t *b, - uint32_t count, void *source) -{ - struct feed_fmt_info *info = f->data; - int i, j, k; - uint8_t *src = info->buffer; - - if (count < 3) - return 0; - k = ((count / 3) * 3) << 1; - k = FEEDER_FEED(f->source, c, src, min(k, info->bufsz), source); - if (k < 6) { - FMT_TRACE("%s: Not enough data (Got: %d bytes)\n", - __func__, k); - return 0; - } - FMT_TEST(k % 6, "%s: Bytes not 24bit (stereo) aligned.\n", __func__); - k -= k % 6; - i = k >> 1; - j = i; - while (i > 2) { - k -= 3; - b[--i] = src[--k]; - b[--i] = src[--k]; - b[--i] = src[--k]; - } - return j; -} static struct pcm_feederdesc feeder_stereotomono24_desc[] = { - {FEEDER_FMT, AFMT_U24_LE|AFMT_STEREO, AFMT_U24_LE, 0}, - {FEEDER_FMT, AFMT_S24_LE|AFMT_STEREO, AFMT_S24_LE, 0}, - {FEEDER_FMT, AFMT_U24_BE|AFMT_STEREO, AFMT_U24_BE, 0}, - {FEEDER_FMT, AFMT_S24_BE|AFMT_STEREO, AFMT_S24_BE, 0}, + {FEEDER_FMT, AFMT_U24_LE | AFMT_STEREO, AFMT_U24_LE, 0}, + {FEEDER_FMT, AFMT_S24_LE | AFMT_STEREO, AFMT_S24_LE, 0}, + {FEEDER_FMT, AFMT_U24_BE | AFMT_STEREO, AFMT_U24_BE, 0}, + {FEEDER_FMT, AFMT_S24_BE | AFMT_STEREO, AFMT_S24_BE, 0}, {0, 0, 0, 0}, }; static kobj_method_t feeder_stereotomono24_methods[] = { - KOBJMETHOD(feeder_init, feed_fmt_init), - KOBJMETHOD(feeder_free, feed_fmt_free), - KOBJMETHOD(feeder_feed, feed_stereotomono24), + KOBJMETHOD(feeder_init, feed_stereotomono_init), + KOBJMETHOD(feeder_feed, feed_stereotomono), {0, 0} }; FEEDER_DECLARE(feeder_stereotomono24, 0, NULL); -static int -feed_stereotomono32(struct pcm_feeder *f, struct pcm_channel *c, uint8_t *b, - uint32_t count, void *source) -{ - struct feed_fmt_info *info = f->data; - int i, j, k; - uint8_t *src = info->buffer; - - if (count < 4) - return 0; - k = (count & ~3) << 1; - k = FEEDER_FEED(f->source, c, src, min(k, info->bufsz), source); - if (k < 8) { - FMT_TRACE("%s: Not enough data (Got: %d bytes)\n", - __func__, k); - return 0; - } - FMT_TEST(k & 7, "%s: Bytes not 32bit (stereo) aligned.\n", __func__); - k &= ~7; - i = k >> 1; - j = i; - while (i > 3) { - k -= 4; - b[--i] = src[--k]; - b[--i] = src[--k]; - b[--i] = src[--k]; - b[--i] = src[--k]; - } - return j; -} static struct pcm_feederdesc feeder_stereotomono32_desc[] = { - {FEEDER_FMT, AFMT_U32_LE|AFMT_STEREO, AFMT_U32_LE, 0}, - {FEEDER_FMT, AFMT_S32_LE|AFMT_STEREO, AFMT_S32_LE, 0}, - {FEEDER_FMT, AFMT_U32_BE|AFMT_STEREO, AFMT_U32_BE, 0}, - {FEEDER_FMT, AFMT_S32_BE|AFMT_STEREO, AFMT_S32_BE, 0}, + {FEEDER_FMT, AFMT_U32_LE | AFMT_STEREO, AFMT_U32_LE, 0}, + {FEEDER_FMT, AFMT_S32_LE | AFMT_STEREO, AFMT_S32_LE, 0}, + {FEEDER_FMT, AFMT_U32_BE | AFMT_STEREO, AFMT_U32_BE, 0}, + {FEEDER_FMT, AFMT_S32_BE | AFMT_STEREO, AFMT_S32_BE, 0}, {0, 0, 0, 0}, }; static kobj_method_t feeder_stereotomono32_methods[] = { - KOBJMETHOD(feeder_init, feed_fmt_init), - KOBJMETHOD(feeder_free, feed_fmt_free), - KOBJMETHOD(feeder_feed, feed_stereotomono32), + KOBJMETHOD(feeder_init, feed_stereotomono_init), + KOBJMETHOD(feeder_feed, feed_stereotomono), {0, 0} }; FEEDER_DECLARE(feeder_stereotomono32, 0, NULL); @@ -1256,307 +1166,268 @@ FEEDER_DECLARE(feeder_stereotomono32, 0, NULL); * Sign conversion */ static int -feed_sign8(struct pcm_feeder *f, struct pcm_channel *c, uint8_t *b, +feed_sign(struct pcm_feeder *f, struct pcm_channel *c, uint8_t *b, uint32_t count, void *source) { - int i, j; - - if (count < 1) - return 0; - j = FEEDER_FEED(f->source, c, b, count, source); - i = j; - while (i > 0) - b[--i] ^= 0x80; - return j; + int i, j, bps, ofs; + + bps = (int)((intptr_t)f->data); + if (count < bps) + return (0); + + i = FEEDER_FEED(f->source, c, b, count - (count % bps), source); + if (i < bps) + return (0); + + i -= i % bps; + j = i; + ofs = (f->desc->in & AFMT_BIGENDIAN) ? bps : 1; + + do { + b[i - ofs] ^= 0x80; + i -= bps; + } while (i != 0); + + return (j); } static struct pcm_feederdesc feeder_sign8_desc[] = { {FEEDER_FMT, AFMT_U8, AFMT_S8, 0}, - {FEEDER_FMT, AFMT_U8|AFMT_STEREO, AFMT_S8|AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_U8 | AFMT_STEREO, AFMT_S8 | AFMT_STEREO, 0}, {FEEDER_FMT, AFMT_S8, AFMT_U8, 0}, - {FEEDER_FMT, AFMT_S8|AFMT_STEREO, AFMT_U8|AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_S8 | AFMT_STEREO, AFMT_U8 | AFMT_STEREO, 0}, {0, 0, 0, 0}, }; static kobj_method_t feeder_sign8_methods[] = { - KOBJMETHOD(feeder_feed, feed_sign8), + KOBJMETHOD(feeder_feed, feed_sign), {0, 0} }; -FEEDER_DECLARE(feeder_sign8, 0, NULL); +FEEDER_DECLARE(feeder_sign8, 0, (void *)PCM_8_BPS); -static int -feed_sign16(struct pcm_feeder *f, struct pcm_channel *c, uint8_t *b, - uint32_t count, void *source) -{ - int i, j; - - if (count < 2) - return 0; - j = FEEDER_FEED(f->source, c, b, count & ~1, source); - if (j < 2) { - FMT_TRACE("%s: Not enough data (Got: %d bytes)\n", - __func__, j); - return 0; - } - FMT_TEST(j & 1, "%s: Bytes not 16bit aligned.\n", __func__); - j &= ~1; - i = j; - if (f->desc->in & AFMT_BIGENDIAN) { - while (i > 1) { - i--; - b[--i] ^= 0x80; - } - } else { - while (i > 1) { - b[--i] ^= 0x80; - i--; - } - } - return j; -} static struct pcm_feederdesc feeder_sign16_desc[] = { {FEEDER_FMT, AFMT_U16_LE, AFMT_S16_LE, 0}, - {FEEDER_FMT, AFMT_U16_LE|AFMT_STEREO, AFMT_S16_LE|AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_U16_LE | AFMT_STEREO, AFMT_S16_LE | AFMT_STEREO, 0}, {FEEDER_FMT, AFMT_S16_LE, AFMT_U16_LE, 0}, - {FEEDER_FMT, AFMT_S16_LE|AFMT_STEREO, AFMT_U16_LE|AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_S16_LE | AFMT_STEREO, AFMT_U16_LE | AFMT_STEREO, 0}, {FEEDER_FMT, AFMT_U16_BE, AFMT_S16_BE, 0}, - {FEEDER_FMT, AFMT_U16_BE|AFMT_STEREO, AFMT_S16_BE|AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_U16_BE | AFMT_STEREO, AFMT_S16_BE | AFMT_STEREO, 0}, {FEEDER_FMT, AFMT_S16_BE, AFMT_U16_BE, 0}, - {FEEDER_FMT, AFMT_S16_BE|AFMT_STEREO, AFMT_U16_BE|AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_S16_BE | AFMT_STEREO, AFMT_U16_BE | AFMT_STEREO, 0}, {0, 0, 0, 0}, }; static kobj_method_t feeder_sign16_methods[] = { - KOBJMETHOD(feeder_feed, feed_sign16), + KOBJMETHOD(feeder_feed, feed_sign), {0, 0} }; -FEEDER_DECLARE(feeder_sign16, 0, NULL); +FEEDER_DECLARE(feeder_sign16, 0, (void *)PCM_16_BPS); -static int -feed_sign24(struct pcm_feeder *f, struct pcm_channel *c, uint8_t *b, - uint32_t count, void *source) -{ - int i, j; - - if (count < 3) - return 0; - j = FEEDER_FEED(f->source, c, b, (count / 3) * 3, source); - if (j < 3) { - FMT_TRACE("%s: Not enough data (Got: %d bytes)\n", - __func__, j); - return 0; - } - FMT_TEST(j % 3, "%s: Bytes not 24bit aligned.\n", __func__); - j -= j % 3; - i = j; - if (f->desc->in & AFMT_BIGENDIAN) { - while (i > 2) { - i -= 2; - b[--i] ^= 0x80; - } - } else { - while (i > 2) { - b[--i] ^= 0x80; - i -= 2; - } - } - return j; -} static struct pcm_feederdesc feeder_sign24_desc[] = { {FEEDER_FMT, AFMT_U24_LE, AFMT_S24_LE, 0}, - {FEEDER_FMT, AFMT_U24_LE|AFMT_STEREO, AFMT_S24_LE|AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_U24_LE | AFMT_STEREO, AFMT_S24_LE | AFMT_STEREO, 0}, {FEEDER_FMT, AFMT_S24_LE, AFMT_U24_LE, 0}, - {FEEDER_FMT, AFMT_S24_LE|AFMT_STEREO, AFMT_U24_LE|AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_S24_LE | AFMT_STEREO, AFMT_U24_LE | AFMT_STEREO, 0}, {FEEDER_FMT, AFMT_U24_BE, AFMT_S24_BE, 0}, - {FEEDER_FMT, AFMT_U24_BE|AFMT_STEREO, AFMT_S24_BE|AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_U24_BE | AFMT_STEREO, AFMT_S24_BE | AFMT_STEREO, 0}, {FEEDER_FMT, AFMT_S24_BE, AFMT_U24_BE, 0}, - {FEEDER_FMT, AFMT_S24_BE|AFMT_STEREO, AFMT_U24_BE|AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_S24_BE | AFMT_STEREO, AFMT_U24_BE | AFMT_STEREO, 0}, {0, 0, 0, 0}, }; static kobj_method_t feeder_sign24_methods[] = { - KOBJMETHOD(feeder_feed, feed_sign24), + KOBJMETHOD(feeder_feed, feed_sign), {0, 0} }; -FEEDER_DECLARE(feeder_sign24, 0, NULL); +FEEDER_DECLARE(feeder_sign24, 0, (void *)PCM_24_BPS); -static int -feed_sign32(struct pcm_feeder *f, struct pcm_channel *c, uint8_t *b, - uint32_t count, void *source) -{ - int i, j; - - if (count < 4) - return 0; - j = FEEDER_FEED(f->source, c, b, count & ~3, source); - if (j < 4) { - FMT_TRACE("%s: Not enough data (Got: %d bytes)\n", - __func__, j); - return 0; - } - FMT_TEST(j & 3, "%s: Bytes not 32bit aligned.\n", __func__); - j &= ~3; - i = j; - if (f->desc->in & AFMT_BIGENDIAN) { - while (i > 3) { - i -= 3; - b[--i] ^= 0x80; - } - } else { - while (i > 3) { - b[--i] ^= 0x80; - i -= 3; - } - } - return j; -} static struct pcm_feederdesc feeder_sign32_desc[] = { {FEEDER_FMT, AFMT_U32_LE, AFMT_S32_LE, 0}, - {FEEDER_FMT, AFMT_U32_LE|AFMT_STEREO, AFMT_S32_LE|AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_U32_LE | AFMT_STEREO, AFMT_S32_LE | AFMT_STEREO, 0}, {FEEDER_FMT, AFMT_S32_LE, AFMT_U32_LE, 0}, - {FEEDER_FMT, AFMT_S32_LE|AFMT_STEREO, AFMT_U32_LE|AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_S32_LE | AFMT_STEREO, AFMT_U32_LE | AFMT_STEREO, 0}, {FEEDER_FMT, AFMT_U32_BE, AFMT_S32_BE, 0}, - {FEEDER_FMT, AFMT_U32_BE|AFMT_STEREO, AFMT_S32_BE|AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_U32_BE | AFMT_STEREO, AFMT_S32_BE | AFMT_STEREO, 0}, {FEEDER_FMT, AFMT_S32_BE, AFMT_U32_BE, 0}, - {FEEDER_FMT, AFMT_S32_BE|AFMT_STEREO, AFMT_U32_BE|AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_S32_BE | AFMT_STEREO, AFMT_U32_BE | AFMT_STEREO, 0}, {0, 0, 0, 0}, }; static kobj_method_t feeder_sign32_methods[] = { - KOBJMETHOD(feeder_feed, feed_sign32), + KOBJMETHOD(feeder_feed, feed_sign), {0, 0} }; -FEEDER_DECLARE(feeder_sign32, 0, NULL); -/* - * Sign conversion end. - */ +FEEDER_DECLARE(feeder_sign32, 0, (void *)PCM_32_BPS); /* - * Endian conversion. + * Endian conversion */ static int -feed_endian16(struct pcm_feeder *f, struct pcm_channel *c, uint8_t *b, +feed_endian(struct pcm_feeder *f, struct pcm_channel *c, uint8_t *b, uint32_t count, void *source) { - int i, j; - uint8_t v; - - if (count < 2) - return 0; - j = FEEDER_FEED(f->source, c, b, count & ~1, source); - if (j < 2) { - FMT_TRACE("%s: Not enough data (Got: %d bytes)\n", - __func__, j); - return 0; - } - FMT_TEST(j & 1, "%s: Bytes not 16bit aligned.\n", __func__); - j &= ~1; - i = j; - while (i > 1) { - v = b[--i]; - b[i] = b[i - 1]; - b[--i] = v; - } - return j; + int i, j, k, bps; + uint8_t *buf, v; + + bps = (int)((intptr_t)f->data); + if (count < bps) + return (0); + + k = FEEDER_FEED(f->source, c, b, count - (count % bps), source); + if (k < bps) + return (0); + + k -= k % bps; + j = bps >> 1; + buf = b + k; + + do { + buf -= bps; + i = j; + do { + v = buf[--i]; + buf[i] = buf[bps - i - 1]; + buf[bps - i - 1] = v; + } while (i != 0); + } while (buf != b); + + return (k); } static struct pcm_feederdesc feeder_endian16_desc[] = { {FEEDER_FMT, AFMT_U16_LE, AFMT_U16_BE, 0}, - {FEEDER_FMT, AFMT_U16_LE|AFMT_STEREO, AFMT_U16_BE|AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_U16_LE | AFMT_STEREO, AFMT_U16_BE | AFMT_STEREO, 0}, {FEEDER_FMT, AFMT_S16_LE, AFMT_S16_BE, 0}, - {FEEDER_FMT, AFMT_S16_LE|AFMT_STEREO, AFMT_S16_BE|AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_S16_LE | AFMT_STEREO, AFMT_S16_BE | AFMT_STEREO, 0}, {FEEDER_FMT, AFMT_U16_BE, AFMT_U16_LE, 0}, - {FEEDER_FMT, AFMT_U16_BE|AFMT_STEREO, AFMT_U16_LE|AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_U16_BE | AFMT_STEREO, AFMT_U16_LE | AFMT_STEREO, 0}, {FEEDER_FMT, AFMT_S16_BE, AFMT_S16_LE, 0}, - {FEEDER_FMT, AFMT_S16_BE|AFMT_STEREO, AFMT_S16_LE|AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_S16_BE | AFMT_STEREO, AFMT_S16_LE | AFMT_STEREO, 0}, {0, 0, 0, 0}, }; static kobj_method_t feeder_endian16_methods[] = { - KOBJMETHOD(feeder_feed, feed_endian16), + KOBJMETHOD(feeder_feed, feed_endian), {0, 0} }; -FEEDER_DECLARE(feeder_endian16, 0, NULL); +FEEDER_DECLARE(feeder_endian16, 0, (void *)PCM_16_BPS); -static int -feed_endian24(struct pcm_feeder *f, struct pcm_channel *c, uint8_t *b, - uint32_t count, void *source) -{ - int i, j; - uint8_t v; - - if (count < 3) - return 0; - j = FEEDER_FEED(f->source, c, b, (count / 3) * 3, source); - if (j < 3) { - FMT_TRACE("%s: Not enough data (Got: %d bytes)\n", - __func__, j); - return 0; - } - FMT_TEST(j % 3, "%s: Bytes not 24bit aligned.\n", __func__); - j -= j % 3; - i = j; - while (i > 2) { - v = b[--i]; - b[i] = b[i - 2]; - b[i -= 2] = v; - } - return j; -} static struct pcm_feederdesc feeder_endian24_desc[] = { {FEEDER_FMT, AFMT_U24_LE, AFMT_U24_BE, 0}, - {FEEDER_FMT, AFMT_U24_LE|AFMT_STEREO, AFMT_U24_BE|AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_U24_LE | AFMT_STEREO, AFMT_U24_BE | AFMT_STEREO, 0}, {FEEDER_FMT, AFMT_S24_LE, AFMT_S24_BE, 0}, - {FEEDER_FMT, AFMT_S24_LE|AFMT_STEREO, AFMT_S24_BE|AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_S24_LE | AFMT_STEREO, AFMT_S24_BE | AFMT_STEREO, 0}, {FEEDER_FMT, AFMT_U24_BE, AFMT_U24_LE, 0}, - {FEEDER_FMT, AFMT_U24_BE|AFMT_STEREO, AFMT_U24_LE|AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_U24_BE | AFMT_STEREO, AFMT_U24_LE | AFMT_STEREO, 0}, {FEEDER_FMT, AFMT_S24_BE, AFMT_S24_LE, 0}, - {FEEDER_FMT, AFMT_S24_BE|AFMT_STEREO, AFMT_S24_LE|AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_S24_BE | AFMT_STEREO, AFMT_S24_LE | AFMT_STEREO, 0}, {0, 0, 0, 0}, }; static kobj_method_t feeder_endian24_methods[] = { - KOBJMETHOD(feeder_feed, feed_endian24), + KOBJMETHOD(feeder_feed, feed_endian), {0, 0} }; -FEEDER_DECLARE(feeder_endian24, 0, NULL); +FEEDER_DECLARE(feeder_endian24, 0, (void *)PCM_24_BPS); -static int -feed_endian32(struct pcm_feeder *f, struct pcm_channel *c, uint8_t *b, - uint32_t count, void *source) -{ - int i, j; - uint8_t l, m; - - if (count < 4) - return 0; - j = FEEDER_FEED(f->source, c, b, count & ~3, source); - if (j < 4) { - FMT_TRACE("%s: Not enough data (Got: %d bytes)\n", - __func__, j); - return 0; - } - FMT_TEST(j & 3, "%s: Bytes not 32bit aligned.\n", __func__); - j &= ~3; - i = j; - while (i > 3) { - l = b[--i]; - m = b[--i]; - b[i] = b[i - 1]; - b[i + 1] = b[i - 2]; - b[--i] = m; - b[--i] = l; - } - return j; -} static struct pcm_feederdesc feeder_endian32_desc[] = { {FEEDER_FMT, AFMT_U32_LE, AFMT_U32_BE, 0}, - {FEEDER_FMT, AFMT_U32_LE|AFMT_STEREO, AFMT_U32_BE|AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_U32_LE | AFMT_STEREO, AFMT_U32_BE | AFMT_STEREO, 0}, {FEEDER_FMT, AFMT_S32_LE, AFMT_S32_BE, 0}, - {FEEDER_FMT, AFMT_S32_LE|AFMT_STEREO, AFMT_S32_BE|AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_S32_LE | AFMT_STEREO, AFMT_S32_BE | AFMT_STEREO, 0}, {FEEDER_FMT, AFMT_U32_BE, AFMT_U32_LE, 0}, - {FEEDER_FMT, AFMT_U32_BE|AFMT_STEREO, AFMT_U32_LE|AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_U32_BE | AFMT_STEREO, AFMT_U32_LE | AFMT_STEREO, 0}, {FEEDER_FMT, AFMT_S32_BE, AFMT_S32_LE, 0}, - {FEEDER_FMT, AFMT_S32_BE|AFMT_STEREO, AFMT_S32_LE|AFMT_STEREO, 0}, + {FEEDER_FMT, AFMT_S32_BE | AFMT_STEREO, AFMT_S32_LE | AFMT_STEREO, 0}, {0, 0, 0, 0}, }; static kobj_method_t feeder_endian32_methods[] = { - KOBJMETHOD(feeder_feed, feed_endian32), + KOBJMETHOD(feeder_feed, feed_endian), {0, 0} }; -FEEDER_DECLARE(feeder_endian32, 0, NULL); +FEEDER_DECLARE(feeder_endian32, 0, (void *)PCM_32_BPS); /* * Endian conversion end */ + +/* + * L/R swap conversion + */ +static int +feed_swaplr(struct pcm_feeder *f, struct pcm_channel *c, uint8_t *b, + uint32_t count, void *source) +{ + int i, j, bps, smpsz; + uint8_t *buf, v; + + bps = (int)((intptr_t)f->data); + smpsz = bps << 1; + if (count < smpsz) + return (0); + + j = FEEDER_FEED(f->source, c, b, count - (count % smpsz), source); + if (j < smpsz) + return (0); + + j -= j % smpsz; + buf = b + j; + + do { + buf -= smpsz; + i = bps; + do { + v = buf[--i]; + buf[i] = buf[bps + i]; + buf[bps + i] = v; + } while (i != 0); + } while (buf != b); + + return (j); +} + +static struct pcm_feederdesc feeder_swaplr8_desc[] = { + {FEEDER_SWAPLR, AFMT_S8 | AFMT_STEREO, AFMT_S8 | AFMT_STEREO, 0}, + {FEEDER_SWAPLR, AFMT_U8 | AFMT_STEREO, AFMT_U8 | AFMT_STEREO, 0}, + {FEEDER_SWAPLR, AFMT_A_LAW | AFMT_STEREO, AFMT_A_LAW | AFMT_STEREO, 0}, + {FEEDER_SWAPLR, AFMT_MU_LAW | AFMT_STEREO, AFMT_A_LAW | AFMT_STEREO, 0}, + {0, 0, 0, 0}, +}; +static kobj_method_t feeder_swaplr8_methods[] = { + KOBJMETHOD(feeder_feed, feed_swaplr), + {0, 0} +}; +FEEDER_DECLARE(feeder_swaplr8, -1, (void *)PCM_8_BPS); + +static struct pcm_feederdesc feeder_swaplr16_desc[] = { + {FEEDER_SWAPLR, AFMT_S16_LE | AFMT_STEREO, AFMT_S16_LE | AFMT_STEREO, 0}, + {FEEDER_SWAPLR, AFMT_S16_BE | AFMT_STEREO, AFMT_S16_BE | AFMT_STEREO, 0}, + {FEEDER_SWAPLR, AFMT_U16_LE | AFMT_STEREO, AFMT_U16_LE | AFMT_STEREO, 0}, + {FEEDER_SWAPLR, AFMT_U16_BE | AFMT_STEREO, AFMT_U16_BE | AFMT_STEREO, 0}, + {0, 0, 0, 0}, +}; +static kobj_method_t feeder_swaplr16_methods[] = { + KOBJMETHOD(feeder_feed, feed_swaplr), + {0, 0} +}; +FEEDER_DECLARE(feeder_swaplr16, -1, (void *)PCM_16_BPS); + +static struct pcm_feederdesc feeder_swaplr24_desc[] = { + {FEEDER_SWAPLR, AFMT_S24_LE | AFMT_STEREO, AFMT_S24_LE | AFMT_STEREO, 0}, + {FEEDER_SWAPLR, AFMT_S24_BE | AFMT_STEREO, AFMT_S24_BE | AFMT_STEREO, 0}, + {FEEDER_SWAPLR, AFMT_U24_LE | AFMT_STEREO, AFMT_U24_LE | AFMT_STEREO, 0}, + {FEEDER_SWAPLR, AFMT_U24_BE | AFMT_STEREO, AFMT_U24_BE | AFMT_STEREO, 0}, + {0, 0, 0, 0}, +}; +static kobj_method_t feeder_swaplr24_methods[] = { + KOBJMETHOD(feeder_feed, feed_swaplr), + {0, 0} +}; +FEEDER_DECLARE(feeder_swaplr24, -1, (void *)PCM_24_BPS); + +static struct pcm_feederdesc feeder_swaplr32_desc[] = { + {FEEDER_SWAPLR, AFMT_S32_LE | AFMT_STEREO, AFMT_S32_LE | AFMT_STEREO, 0}, + {FEEDER_SWAPLR, AFMT_S32_BE | AFMT_STEREO, AFMT_S32_BE | AFMT_STEREO, 0}, + {FEEDER_SWAPLR, AFMT_U32_LE | AFMT_STEREO, AFMT_U32_LE | AFMT_STEREO, 0}, + {FEEDER_SWAPLR, AFMT_U32_BE | AFMT_STEREO, AFMT_U32_BE | AFMT_STEREO, 0}, + {0, 0, 0, 0}, +}; +static kobj_method_t feeder_swaplr32_methods[] = { + KOBJMETHOD(feeder_feed, feed_swaplr), + {0, 0} +}; +FEEDER_DECLARE(feeder_swaplr32, -1, (void *)PCM_32_BPS); +/* + * L/R swap conversion end + */ |