version 1.11, 2008/08/20 14:22:50 |
version 1.12, 2008/10/26 08:49:43 |
|
|
* |
* |
* (hard) add a lowpass filter for the resampler. Quality is |
* (hard) add a lowpass filter for the resampler. Quality is |
* not acceptable as is. |
* not acceptable as is. |
|
* |
*/ |
*/ |
#include <err.h> |
#include <err.h> |
#include <limits.h> |
#include <limits.h> |
|
|
void |
void |
aproc_del(struct aproc *p) |
aproc_del(struct aproc *p) |
{ |
{ |
|
struct abuf *i; |
|
|
|
DPRINTF("aproc_del: %s(%s): terminating...\n", p->ops->name, p->name); |
|
|
if (p->ops->done) |
if (p->ops->done) |
p->ops->done(p); |
p->ops->done(p); |
DPRINTF("aproc_del: %s: %s: deleted\n", p->ops->name, p->name); |
|
|
while (!LIST_EMPTY(&p->ibuflist)) { |
|
i = LIST_FIRST(&p->ibuflist); |
|
abuf_hup(i); |
|
} |
|
while (!LIST_EMPTY(&p->obuflist)) { |
|
i = LIST_FIRST(&p->obuflist); |
|
abuf_eof(i); |
|
} |
|
DPRINTF("aproc_del: %s(%s): freed\n", p->ops->name, p->name); |
free(p); |
free(p); |
} |
} |
|
|
|
|
p->ops->newout(p, obuf); |
p->ops->newout(p, obuf); |
} |
} |
|
|
|
void |
|
aproc_ipos(struct aproc *p, struct abuf *ibuf, int delta) |
|
{ |
|
struct abuf *obuf; |
|
|
|
DPRINTFN(3, "aproc_ipos: %s: delta = %d\n", p->name, delta); |
|
|
|
LIST_FOREACH(obuf, &p->obuflist, oent) { |
|
abuf_ipos(obuf, delta); |
|
} |
|
} |
|
|
|
void |
|
aproc_opos(struct aproc *p, struct abuf *obuf, int delta) |
|
{ |
|
struct abuf *ibuf; |
|
|
|
DPRINTFN(3, "aproc_opos: %s: delta = %d\n", p->name, delta); |
|
|
|
LIST_FOREACH(ibuf, &p->ibuflist, ient) { |
|
abuf_opos(ibuf, delta); |
|
} |
|
} |
|
|
int |
int |
rpipe_in(struct aproc *p, struct abuf *ibuf_dummy) |
rpipe_in(struct aproc *p, struct abuf *ibuf_dummy) |
{ |
{ |
|
|
|
|
DPRINTFN(3, "rpipe_in: %s\n", p->name); |
DPRINTFN(3, "rpipe_in: %s\n", p->name); |
|
|
if (ABUF_FULL(obuf)) |
if (ABUF_FULL(obuf) || !(f->state & FILE_ROK)) |
return 0; |
return 0; |
data = abuf_wgetblk(obuf, &count, 0); |
data = abuf_wgetblk(obuf, &count, 0); |
count = file_read(f, data, count); |
count = file_read(f, data, count); |
|
if (count == 0) |
|
return 0; |
abuf_wcommit(obuf, count); |
abuf_wcommit(obuf, count); |
abuf_flush(obuf); |
if (!abuf_flush(obuf)) |
return !ABUF_FULL(obuf); |
return 0; |
|
return 1; |
} |
} |
|
|
int |
int |
|
|
unsigned char *data; |
unsigned char *data; |
unsigned count; |
unsigned count; |
|
|
|
if (f->refs > 0) |
|
return 0; |
DPRINTFN(3, "rpipe_out: %s\n", p->name); |
DPRINTFN(3, "rpipe_out: %s\n", p->name); |
|
|
if (!(f->state & FILE_ROK)) |
if (ABUF_FULL(obuf) || !(f->state & FILE_ROK)) |
return 0; |
return 0; |
data = abuf_wgetblk(obuf, &count, 0); |
data = abuf_wgetblk(obuf, &count, 0); |
count = file_read(f, data, count); |
count = file_read(f, data, count); |
|
if (count == 0) |
|
return 0; |
abuf_wcommit(obuf, count); |
abuf_wcommit(obuf, count); |
return f->state & FILE_ROK; |
return 1; |
} |
} |
|
|
void |
void |
|
|
struct file *f = p->u.io.file; |
struct file *f = p->u.io.file; |
|
|
f->rproc = NULL; |
f->rproc = NULL; |
f->events &= ~POLLIN; |
if (f->wproc == NULL) |
|
file_del(f); |
} |
} |
|
|
void |
void |
rpipe_eof(struct aproc *p, struct abuf *ibuf_dummy) |
rpipe_eof(struct aproc *p, struct abuf *ibuf_dummy) |
{ |
{ |
DPRINTFN(3, "rpipe_eof: %s\n", p->name); |
DPRINTFN(3, "rpipe_eof: %s\n", p->name); |
abuf_eof(LIST_FIRST(&p->obuflist)); |
|
aproc_del(p); |
aproc_del(p); |
} |
} |
|
|
|
|
} |
} |
|
|
struct aproc_ops rpipe_ops = { |
struct aproc_ops rpipe_ops = { |
"rpipe", rpipe_in, rpipe_out, rpipe_eof, rpipe_hup, NULL, NULL, rpipe_done |
"rpipe", |
|
rpipe_in, |
|
rpipe_out, |
|
rpipe_eof, |
|
rpipe_hup, |
|
NULL, /* newin */ |
|
NULL, /* newout */ |
|
aproc_ipos, |
|
aproc_opos, |
|
rpipe_done |
}; |
}; |
|
|
struct aproc * |
struct aproc * |
|
|
|
|
p = aproc_new(&rpipe_ops, f->name); |
p = aproc_new(&rpipe_ops, f->name); |
p->u.io.file = f; |
p->u.io.file = f; |
f->rproc = p; |
f->rproc = p; |
f->events |= POLLIN; |
|
return p; |
return p; |
} |
} |
|
|
|
|
struct file *f = p->u.io.file; |
struct file *f = p->u.io.file; |
|
|
f->wproc = NULL; |
f->wproc = NULL; |
f->events &= ~POLLOUT; |
if (f->rproc == NULL) |
|
file_del(f); |
} |
} |
|
|
int |
int |
|
|
unsigned char *data; |
unsigned char *data; |
unsigned count; |
unsigned count; |
|
|
|
if (f->refs > 0) |
|
return 0; |
DPRINTFN(3, "wpipe_in: %s\n", p->name); |
DPRINTFN(3, "wpipe_in: %s\n", p->name); |
|
|
if (!(f->state & FILE_WOK)) |
if (ABUF_EMPTY(ibuf) || !(f->state & FILE_WOK)) |
return 0; |
return 0; |
|
|
data = abuf_rgetblk(ibuf, &count, 0); |
data = abuf_rgetblk(ibuf, &count, 0); |
count = file_write(f, data, count); |
count = file_write(f, data, count); |
|
if (count == 0) |
|
return 0; |
abuf_rdiscard(ibuf, count); |
abuf_rdiscard(ibuf, count); |
return f->state & FILE_WOK; |
return 1; |
} |
} |
|
|
int |
int |
|
|
|
|
DPRINTFN(3, "wpipe_out: %s\n", p->name); |
DPRINTFN(3, "wpipe_out: %s\n", p->name); |
|
|
if (ABUF_EMPTY(ibuf)) |
if (!abuf_fill(ibuf)) { |
|
DPRINTFN(3, "wpipe_out: fill failed\n"); |
return 0; |
return 0; |
|
} |
|
if (ABUF_EMPTY(ibuf) || !(f->state & FILE_WOK)) |
|
return 0; |
data = abuf_rgetblk(ibuf, &count, 0); |
data = abuf_rgetblk(ibuf, &count, 0); |
count = file_write(f, data, count); |
if (count == 0) { |
abuf_rdiscard(ibuf, count); |
DPRINTF("wpipe_out: %s: underrun\n", p->name); |
if (ABUF_EOF(ibuf)) { |
|
abuf_hup(ibuf); |
|
aproc_del(p); |
|
return 0; |
return 0; |
} |
} |
abuf_fill(ibuf); |
count = file_write(f, data, count); |
|
if (count == 0) |
|
return 0; |
|
abuf_rdiscard(ibuf, count); |
return 1; |
return 1; |
} |
} |
|
|
|
|
wpipe_hup(struct aproc *p, struct abuf *obuf_dummy) |
wpipe_hup(struct aproc *p, struct abuf *obuf_dummy) |
{ |
{ |
DPRINTFN(3, "wpipe_hup: %s\n", p->name); |
DPRINTFN(3, "wpipe_hup: %s\n", p->name); |
abuf_hup(LIST_FIRST(&p->ibuflist)); |
|
aproc_del(p); |
aproc_del(p); |
} |
} |
|
|
struct aproc_ops wpipe_ops = { |
struct aproc_ops wpipe_ops = { |
"wpipe", wpipe_in, wpipe_out, wpipe_eof, wpipe_hup, NULL, NULL, wpipe_done |
"wpipe", |
|
wpipe_in, |
|
wpipe_out, |
|
wpipe_eof, |
|
wpipe_hup, |
|
NULL, /* newin */ |
|
NULL, /* newout */ |
|
aproc_ipos, |
|
aproc_opos, |
|
wpipe_done |
}; |
}; |
|
|
struct aproc * |
struct aproc * |
|
|
p = aproc_new(&wpipe_ops, f->name); |
p = aproc_new(&wpipe_ops, f->name); |
p->u.io.file = f; |
p->u.io.file = f; |
f->wproc = p; |
f->wproc = p; |
f->events |= POLLOUT; |
|
return p; |
return p; |
} |
} |
|
|
|
|
DPRINTFN(4, "mix_bzero: used = %u, todo = %u\n", |
DPRINTFN(4, "mix_bzero: used = %u, todo = %u\n", |
obuf->used, obuf->mixtodo); |
obuf->used, obuf->mixtodo); |
odata = (short *)abuf_wgetblk(obuf, &ocount, obuf->mixtodo); |
odata = (short *)abuf_wgetblk(obuf, &ocount, obuf->mixtodo); |
|
ocount -= ocount % obuf->bpf; |
if (ocount == 0) |
if (ocount == 0) |
return; |
return; |
memset(odata, 0, ocount); |
memset(odata, 0, ocount); |
|
|
obuf->mixtodo, ibuf->mixdone); |
obuf->mixtodo, ibuf->mixdone); |
|
|
idata = (short *)abuf_rgetblk(ibuf, &icount, 0); |
idata = (short *)abuf_rgetblk(ibuf, &icount, 0); |
|
icount -= icount % ibuf->bpf; |
if (icount == 0) |
if (icount == 0) |
return; |
return; |
|
|
odata = (short *)abuf_wgetblk(obuf, &ocount, ibuf->mixdone); |
odata = (short *)abuf_wgetblk(obuf, &ocount, ibuf->mixdone); |
|
ocount -= ocount % obuf->bpf; |
if (ocount == 0) |
if (ocount == 0) |
return; |
return; |
|
|
|
|
scount, ibuf->mixdone, obuf->mixtodo); |
scount, ibuf->mixdone, obuf->mixtodo); |
} |
} |
|
|
/* |
|
* Remove an input stream from the mixer. |
|
*/ |
|
void |
|
mix_rm(struct aproc *p, struct abuf *ibuf) |
|
{ |
|
LIST_REMOVE(ibuf, ient); |
|
DPRINTF("mix_rm: %s\n", p->name); |
|
} |
|
|
|
int |
int |
mix_in(struct aproc *p, struct abuf *ibuf) |
mix_in(struct aproc *p, struct abuf *ibuf) |
{ |
{ |
|
|
DPRINTFN(4, "mix_in: used = %u, done = %u, todo = %u\n", |
DPRINTFN(4, "mix_in: used = %u, done = %u, todo = %u\n", |
ibuf->used, ibuf->mixdone, obuf->mixtodo); |
ibuf->used, ibuf->mixdone, obuf->mixtodo); |
|
|
if (ibuf->mixdone >= obuf->mixtodo) |
if (!ABUF_ROK(ibuf) || ibuf->mixdone == obuf->mixtodo) |
return 0; |
return 0; |
|
|
mix_badd(ibuf, obuf); |
mix_badd(ibuf, obuf); |
ocount = obuf->mixtodo; |
ocount = obuf->mixtodo; |
LIST_FOREACH(i, &p->ibuflist, ient) { |
LIST_FOREACH(i, &p->ibuflist, ient) { |
|
|
return 0; |
return 0; |
|
|
abuf_wcommit(obuf, ocount); |
abuf_wcommit(obuf, ocount); |
|
p->u.mix.lat += ocount / obuf->bpf; |
obuf->mixtodo -= ocount; |
obuf->mixtodo -= ocount; |
abuf_flush(obuf); |
if (!abuf_flush(obuf)) |
|
return 0; /* hup */ |
mix_bzero(p); |
mix_bzero(p); |
for (i = LIST_FIRST(&p->ibuflist); i != LIST_END(&p->ibuflist); i = inext) { |
for (i = LIST_FIRST(&p->ibuflist); i != NULL; i = inext) { |
inext = LIST_NEXT(i, ient); |
inext = LIST_NEXT(i, ient); |
i->mixdone -= ocount; |
i->mixdone -= ocount; |
if (i != ibuf && i->mixdone < obuf->mixtodo) { |
if (i->mixdone < obuf->mixtodo) |
if (ABUF_EOF(i)) { |
|
mix_rm(p, i); |
|
abuf_hup(i); |
|
continue; |
|
} |
|
mix_badd(i, obuf); |
mix_badd(i, obuf); |
abuf_fill(i); |
if (!abuf_fill(i)) |
} |
continue; |
} |
} |
return 1; |
return 1; |
} |
} |
|
|
DPRINTFN(4, "mix_out: used = %u, todo = %u\n", |
DPRINTFN(4, "mix_out: used = %u, todo = %u\n", |
obuf->used, obuf->mixtodo); |
obuf->used, obuf->mixtodo); |
|
|
|
if (!ABUF_WOK(obuf)) |
|
return 0; |
|
|
mix_bzero(p); |
mix_bzero(p); |
ocount = obuf->mixtodo; |
ocount = obuf->mixtodo; |
for (i = LIST_FIRST(&p->ibuflist); i != LIST_END(&p->ibuflist); i = inext) { |
for (i = LIST_FIRST(&p->ibuflist); i != NULL; i = inext) { |
inext = LIST_NEXT(i, ient); |
inext = LIST_NEXT(i, ient); |
|
if (!abuf_fill(i)) |
|
continue; |
if (!ABUF_ROK(i)) { |
if (!ABUF_ROK(i)) { |
if ((p->u.mix.flags & MIX_DROP) && i->mixdone == 0) { |
if ((p->u.mix.flags & MIX_DROP) && i->mixdone == 0) { |
if (i->xrun == XRUN_ERROR) { |
if (i->xrun == XRUN_ERROR) { |
mix_rm(p, i); |
|
abuf_hup(i); |
abuf_hup(i); |
continue; |
continue; |
} |
} |
|
|
i->mixdone += drop; |
i->mixdone += drop; |
if (i->xrun == XRUN_SYNC) |
if (i->xrun == XRUN_SYNC) |
i->drop += drop; |
i->drop += drop; |
|
else { |
|
abuf_opos(i, -(int)(drop / i->bpf)); |
|
if (i->duplex) { |
|
DPRINTF("mix_out: duplex %u\n", |
|
drop); |
|
i->duplex->drop += drop * |
|
i->duplex->bpf / i->bpf; |
|
abuf_ipos(i->duplex, |
|
-(int)(drop / i->bpf)); |
|
} |
|
} |
DPRINTF("mix_out: drop = %u\n", i->drop); |
DPRINTF("mix_out: drop = %u\n", i->drop); |
} |
} |
} else |
} else |
mix_badd(i, obuf); |
mix_badd(i, obuf); |
if (ocount > i->mixdone) |
if (ocount > i->mixdone) |
ocount = i->mixdone; |
ocount = i->mixdone; |
if (ABUF_EOF(i)) { |
|
mix_rm(p, i); |
|
abuf_hup(i); |
|
continue; |
|
} |
|
abuf_fill(i); |
|
} |
} |
if (ocount == 0) |
if (ocount == 0) |
return 0; |
return 0; |
if (LIST_EMPTY(&p->ibuflist) && (p->u.mix.flags & MIX_AUTOQUIT)) { |
if (LIST_EMPTY(&p->ibuflist) && (p->u.mix.flags & MIX_AUTOQUIT)) { |
DPRINTF("mix_out: nothing more to do...\n"); |
DPRINTF("mix_out: nothing more to do...\n"); |
obuf->wproc = NULL; |
|
aproc_del(p); |
aproc_del(p); |
return 0; |
return 0; |
} |
} |
abuf_wcommit(obuf, ocount); |
abuf_wcommit(obuf, ocount); |
|
p->u.mix.lat += ocount / obuf->bpf; |
obuf->mixtodo -= ocount; |
obuf->mixtodo -= ocount; |
LIST_FOREACH(i, &p->ibuflist, ient) { |
LIST_FOREACH(i, &p->ibuflist, ient) { |
i->mixdone -= ocount; |
i->mixdone -= ocount; |
|
|
struct abuf *obuf = LIST_FIRST(&p->obuflist); |
struct abuf *obuf = LIST_FIRST(&p->obuflist); |
|
|
DPRINTF("mix_eof: %s: detached\n", p->name); |
DPRINTF("mix_eof: %s: detached\n", p->name); |
mix_rm(p, ibuf); |
mix_setmaster(p); |
|
|
/* |
/* |
* If there's no more inputs, abuf_run() will trigger the eof |
* If there's no more inputs, abuf_run() will trigger the eof |
* condition and propagate it, so no need to handle it here. |
* condition and propagate it, so no need to handle it here. |
|
|
|
|
while (!LIST_EMPTY(&p->ibuflist)) { |
while (!LIST_EMPTY(&p->ibuflist)) { |
ibuf = LIST_FIRST(&p->ibuflist); |
ibuf = LIST_FIRST(&p->ibuflist); |
mix_rm(p, ibuf); |
|
abuf_hup(ibuf); |
abuf_hup(ibuf); |
} |
} |
DPRINTF("mix_hup: %s: done\n", p->name); |
DPRINTF("mix_hup: %s: done\n", p->name); |
|
|
ibuf->mixdone = 0; |
ibuf->mixdone = 0; |
ibuf->mixvol = ADATA_UNIT; |
ibuf->mixvol = ADATA_UNIT; |
ibuf->xrun = XRUN_IGNORE; |
ibuf->xrun = XRUN_IGNORE; |
|
mix_setmaster(p); |
} |
} |
|
|
void |
void |
|
|
mix_bzero(p); |
mix_bzero(p); |
} |
} |
|
|
|
void |
|
mix_opos(struct aproc *p, struct abuf *obuf, int delta) |
|
{ |
|
DPRINTFN(3, "mix_opos: lat = %d/%d\n", p->u.mix.lat, p->u.mix.maxlat); |
|
p->u.mix.lat -= delta; |
|
aproc_opos(p, obuf, delta); |
|
} |
|
|
struct aproc_ops mix_ops = { |
struct aproc_ops mix_ops = { |
"mix", mix_in, mix_out, mix_eof, mix_hup, mix_newin, mix_newout, NULL |
"mix", |
|
mix_in, |
|
mix_out, |
|
mix_eof, |
|
mix_hup, |
|
mix_newin, |
|
mix_newout, |
|
aproc_ipos, |
|
mix_opos, |
|
NULL |
}; |
}; |
|
|
struct aproc * |
struct aproc * |
mix_new(void) |
mix_new(char *name, int maxlat) |
{ |
{ |
struct aproc *p; |
struct aproc *p; |
|
|
p = aproc_new(&mix_ops, "softmix"); |
p = aproc_new(&mix_ops, name); |
p->u.mix.flags = 0; |
p->u.mix.flags = 0; |
|
p->u.mix.lat = 0; |
|
p->u.mix.maxlat = maxlat; |
return p; |
return p; |
} |
} |
|
|
|
|
struct abuf *obuf = LIST_FIRST(&p->obuflist); |
struct abuf *obuf = LIST_FIRST(&p->obuflist); |
|
|
abuf_wcommit(obuf, obuf->mixtodo); |
abuf_wcommit(obuf, obuf->mixtodo); |
|
p->u.mix.lat += obuf->mixtodo / obuf->bpf; |
obuf->mixtodo = 0; |
obuf->mixtodo = 0; |
abuf_run(obuf); |
abuf_run(obuf); |
mix_bzero(p); |
mix_bzero(p); |
|
|
unsigned icount, ocount, scount; |
unsigned icount, ocount, scount; |
|
|
idata = abuf_rgetblk(ibuf, &icount, obuf->subdone); |
idata = abuf_rgetblk(ibuf, &icount, obuf->subdone); |
|
icount -= icount % ibuf->bpf; |
if (icount == 0) |
if (icount == 0) |
return; |
return; |
odata = abuf_wgetblk(obuf, &ocount, 0); |
odata = abuf_wgetblk(obuf, &ocount, 0); |
|
ocount -= icount % obuf->bpf; |
if (ocount == 0) |
if (ocount == 0) |
return; |
return; |
scount = (icount < ocount) ? icount : ocount; |
scount = (icount < ocount) ? icount : ocount; |
memcpy(odata, idata, scount); |
memcpy(odata, idata, scount); |
abuf_wcommit(obuf, scount); |
abuf_wcommit(obuf, scount); |
obuf->subdone += scount; |
obuf->subdone += scount; |
DPRINTFN(4, "sub_bcopy: %u bytes\n", scount); |
DPRINTFN(4, "sub_bcopy: %u bytes\n", scount); |
} |
} |
|
|
void |
|
sub_rm(struct aproc *p, struct abuf *obuf) |
|
{ |
|
LIST_REMOVE(obuf, oent); |
|
DPRINTF("sub_rm: %s\n", p->name); |
|
} |
|
|
|
int |
int |
sub_in(struct aproc *p, struct abuf *ibuf) |
sub_in(struct aproc *p, struct abuf *ibuf) |
{ |
{ |
struct abuf *i, *inext; |
struct abuf *i, *inext; |
unsigned done, drop; |
unsigned done, drop; |
int again; |
|
|
if (!ABUF_ROK(ibuf)) |
again = 1; |
return 0; |
done = ibuf->used; |
done = ibuf->used; |
for (i = LIST_FIRST(&p->obuflist); i != LIST_END(&p->obuflist); i = inext) { |
for (i = LIST_FIRST(&p->obuflist); i != NULL; i = inext) { |
inext = LIST_NEXT(i, oent); |
inext = LIST_NEXT(i, oent); |
if (!ABUF_WOK(i)) { |
if (!ABUF_WOK(i)) { |
if ((p->u.sub.flags & SUB_DROP) && i->subdone == 0) { |
if ((p->u.sub.flags & SUB_DROP) && i->subdone == 0) { |
if (i->xrun == XRUN_ERROR) { |
if (i->xrun == XRUN_ERROR) { |
sub_rm(p, i); |
|
abuf_eof(i); |
abuf_eof(i); |
continue; |
continue; |
} |
} |
drop = ibuf->used; |
drop = ibuf->used; |
if (i->xrun == XRUN_SYNC) |
if (i->xrun == XRUN_SYNC) |
i->silence += drop; |
i->silence += drop; |
|
else { |
|
abuf_ipos(i, -(int)(drop / i->bpf)); |
|
if (i->duplex) { |
|
DPRINTF("sub_in: duplex %u\n", |
|
drop); |
|
i->duplex->silence += drop * |
|
i->duplex->bpf / i->bpf; |
|
abuf_opos(i->duplex, |
|
-(int)(drop / i->bpf)); |
|
} |
|
} |
i->subdone += drop; |
i->subdone += drop; |
DPRINTF("sub_in: silence = %u\n", i->silence); |
DPRINTF("sub_in: silence = %u\n", i->silence); |
} |
} |
} else { |
} else |
sub_bcopy(ibuf, i); |
sub_bcopy(ibuf, i); |
abuf_flush(i); |
|
} |
|
if (!ABUF_WOK(i)) |
|
again = 0; |
|
if (done > i->subdone) |
if (done > i->subdone) |
done = i->subdone; |
done = i->subdone; |
|
if (!abuf_flush(i)) |
|
continue; |
} |
} |
LIST_FOREACH(i, &p->obuflist, oent) { |
LIST_FOREACH(i, &p->obuflist, oent) { |
i->subdone -= done; |
i->subdone -= done; |
} |
} |
abuf_rdiscard(ibuf, done); |
abuf_rdiscard(ibuf, done); |
return again; |
p->u.sub.lat -= done / ibuf->bpf; |
|
return 1; |
} |
} |
|
|
int |
int |
|
|
struct abuf *i, *inext; |
struct abuf *i, *inext; |
unsigned done; |
unsigned done; |
|
|
if (obuf->subdone >= ibuf->used) |
if (!ABUF_WOK(obuf)) |
return 0; |
return 0; |
|
if (!abuf_fill(ibuf)) { |
|
return 0; |
|
} |
|
if (obuf->subdone == ibuf->used) |
|
return 0; |
|
|
sub_bcopy(ibuf, obuf); |
|
|
|
done = ibuf->used; |
done = ibuf->used; |
LIST_FOREACH(i, &p->obuflist, oent) { |
for (i = LIST_FIRST(&p->obuflist); i != NULL; i = inext) { |
if (i != obuf && ABUF_WOK(i)) { |
inext = LIST_NEXT(i, oent); |
sub_bcopy(ibuf, i); |
if (!abuf_flush(i)) |
abuf_flush(i); |
continue; |
} |
sub_bcopy(ibuf, i); |
if (done > i->subdone) |
if (done > i->subdone) |
done = i->subdone; |
done = i->subdone; |
} |
} |
if (done == 0) |
|
return 0; |
|
LIST_FOREACH(i, &p->obuflist, oent) { |
LIST_FOREACH(i, &p->obuflist, oent) { |
i->subdone -= done; |
i->subdone -= done; |
} |
} |
abuf_rdiscard(ibuf, done); |
abuf_rdiscard(ibuf, done); |
if (ABUF_EOF(ibuf)) { |
p->u.sub.lat -= done / ibuf->bpf; |
abuf_hup(ibuf); |
|
for (i = LIST_FIRST(&p->obuflist); |
|
i != LIST_END(&p->obuflist); |
|
i = inext) { |
|
inext = LIST_NEXT(i, oent); |
|
if (i != ibuf) |
|
abuf_eof(i); |
|
} |
|
ibuf->wproc = NULL; |
|
aproc_del(p); |
|
return 0; |
|
} |
|
abuf_fill(ibuf); |
|
return 1; |
return 1; |
} |
} |
|
|
|
|
|
|
while (!LIST_EMPTY(&p->obuflist)) { |
while (!LIST_EMPTY(&p->obuflist)) { |
obuf = LIST_FIRST(&p->obuflist); |
obuf = LIST_FIRST(&p->obuflist); |
sub_rm(p, obuf); |
|
abuf_eof(obuf); |
abuf_eof(obuf); |
} |
} |
aproc_del(p); |
aproc_del(p); |
|
|
struct abuf *ibuf = LIST_FIRST(&p->ibuflist); |
struct abuf *ibuf = LIST_FIRST(&p->ibuflist); |
|
|
DPRINTF("sub_hup: %s: detached\n", p->name); |
DPRINTF("sub_hup: %s: detached\n", p->name); |
sub_rm(p, obuf); |
abuf_run(ibuf); |
if (LIST_EMPTY(&p->obuflist) && (p->u.sub.flags & SUB_AUTOQUIT)) { |
|
abuf_hup(ibuf); |
|
aproc_del(p); |
|
} else |
|
abuf_run(ibuf); |
|
DPRINTF("sub_hup: done\n"); |
DPRINTF("sub_hup: done\n"); |
} |
} |
|
|
|
|
obuf->xrun = XRUN_IGNORE; |
obuf->xrun = XRUN_IGNORE; |
} |
} |
|
|
|
void |
|
sub_ipos(struct aproc *p, struct abuf *ibuf, int delta) |
|
{ |
|
p->u.sub.lat += delta; |
|
DPRINTFN(3, "sub_ipos: lat = %d/%d\n", p->u.sub.lat, p->u.sub.maxlat); |
|
aproc_ipos(p, ibuf, delta); |
|
} |
|
|
struct aproc_ops sub_ops = { |
struct aproc_ops sub_ops = { |
"sub", sub_in, sub_out, sub_eof, sub_hup, NULL, sub_newout, NULL |
"sub", |
|
sub_in, |
|
sub_out, |
|
sub_eof, |
|
sub_hup, |
|
NULL, |
|
sub_newout, |
|
sub_ipos, |
|
aproc_opos, |
|
NULL |
}; |
}; |
|
|
struct aproc * |
struct aproc * |
sub_new(void) |
sub_new(char *name, int maxlat) |
{ |
{ |
struct aproc *p; |
struct aproc *p; |
|
|
p = aproc_new(&sub_ops, "copy"); |
p = aproc_new(&sub_ops, name); |
p->u.sub.flags = 0; |
p->u.sub.flags = 0; |
|
p->u.sub.lat = 0; |
|
p->u.sub.maxlat = maxlat; |
return p; |
return p; |
} |
} |
|
|
|
|
/* |
/* |
* Convert one block. |
* Convert one block. |
*/ |
*/ |
|
|
*/ |
*/ |
idata = abuf_rgetblk(ibuf, &icount, 0); |
idata = abuf_rgetblk(ibuf, &icount, 0); |
ifr = icount / ibuf->bpf; |
ifr = icount / ibuf->bpf; |
|
icount = ifr * ibuf->bpf; |
|
|
odata = abuf_wgetblk(obuf, &ocount, 0); |
odata = abuf_wgetblk(obuf, &ocount, 0); |
ofr = ocount / obuf->bpf; |
ofr = ocount / obuf->bpf; |
|
ocount = ofr * obuf->bpf; |
|
|
/* |
/* |
* Partially copy structures into local variables, to avoid |
* Partially copy structures into local variables, to avoid |
|
|
{ |
{ |
struct abuf *obuf = LIST_FIRST(&p->obuflist); |
struct abuf *obuf = LIST_FIRST(&p->obuflist); |
|
|
if (!ABUF_WOK(obuf)) |
DPRINTFN(4, "conv_in: %s\n", p->name); |
|
|
|
if (!ABUF_WOK(obuf) || !ABUF_ROK(ibuf)) |
return 0; |
return 0; |
conv_bcopy(&p->u.conv.ist, &p->u.conv.ost, ibuf, obuf); |
conv_bcopy(&p->u.conv.ist, &p->u.conv.ost, ibuf, obuf); |
abuf_flush(obuf); |
if (!abuf_flush(obuf)) |
return ABUF_WOK(obuf); |
return 0; |
|
return 1; |
} |
} |
|
|
int |
int |
|
|
{ |
{ |
struct abuf *ibuf = LIST_FIRST(&p->ibuflist); |
struct abuf *ibuf = LIST_FIRST(&p->ibuflist); |
|
|
if (!ABUF_ROK(ibuf)) |
DPRINTFN(4, "conv_out: %s\n", p->name); |
|
|
|
if (!abuf_fill(ibuf)) |
return 0; |
return 0; |
conv_bcopy(&p->u.conv.ist, &p->u.conv.ost, ibuf, obuf); |
if (!ABUF_WOK(obuf) || !ABUF_ROK(ibuf)) |
if (ABUF_EOF(ibuf)) { |
|
obuf->wproc = NULL; |
|
abuf_hup(ibuf); |
|
aproc_del(p); |
|
return 0; |
return 0; |
} |
conv_bcopy(&p->u.conv.ist, &p->u.conv.ost, ibuf, obuf); |
abuf_fill(ibuf); |
|
return 1; |
return 1; |
} |
} |
|
|
void |
void |
conv_eof(struct aproc *p, struct abuf *ibuf) |
conv_eof(struct aproc *p, struct abuf *ibuf) |
{ |
{ |
abuf_eof(LIST_FIRST(&p->obuflist)); |
DPRINTFN(4, "conv_eof: %s\n", p->name); |
|
|
aproc_del(p); |
aproc_del(p); |
} |
} |
|
|
void |
void |
conv_hup(struct aproc *p, struct abuf *obuf) |
conv_hup(struct aproc *p, struct abuf *obuf) |
{ |
{ |
abuf_hup(LIST_FIRST(&p->ibuflist)); |
DPRINTFN(4, "conv_hup: %s\n", p->name); |
|
|
aproc_del(p); |
aproc_del(p); |
} |
} |
|
|
|
|
st->rate = par->rate; |
st->rate = par->rate; |
st->pos = 0; |
st->pos = 0; |
|
|
for (i = 0; i < CHAN_MAX; i++) |
for (i = 0; i < NCHAN_MAX; i++) |
st->ctx[i] = 0; |
st->ctx[i] = 0; |
} |
} |
|
|
|
void |
|
conv_ipos(struct aproc *p, struct abuf *ibuf, int delta) |
|
{ |
|
struct abuf *obuf = LIST_FIRST(&p->obuflist); |
|
long long ipos; |
|
int ifac, ofac; |
|
|
|
DPRINTFN(3, "conv_ipos: %d\n", delta); |
|
|
|
ifac = p->u.conv.ist.rate; |
|
ofac = p->u.conv.ost.rate; |
|
ipos = p->u.conv.idelta + (long long)delta * ofac; |
|
delta = (ipos + ifac - 1) / ifac; |
|
p->u.conv.idelta = ipos - (long long)delta * ifac; |
|
abuf_ipos(obuf, delta); |
|
} |
|
|
|
void |
|
conv_opos(struct aproc *p, struct abuf *obuf, int delta) |
|
{ |
|
struct abuf *ibuf = LIST_FIRST(&p->ibuflist); |
|
long long opos; |
|
int ifac, ofac; |
|
|
|
DPRINTFN(3, "conv_opos: %d\n", delta); |
|
|
|
ifac = p->u.conv.ist.rate; |
|
ofac = p->u.conv.ost.rate; |
|
opos = p->u.conv.odelta + (long long)delta * ifac; |
|
delta = (opos + ofac - 1) / ofac; |
|
p->u.conv.odelta = opos - (long long)delta * ofac; |
|
abuf_opos(ibuf, delta); |
|
} |
|
|
struct aproc_ops conv_ops = { |
struct aproc_ops conv_ops = { |
"conv", conv_in, conv_out, conv_eof, conv_hup, NULL, NULL, NULL |
"conv", |
|
conv_in, |
|
conv_out, |
|
conv_eof, |
|
conv_hup, |
|
NULL, |
|
NULL, |
|
conv_ipos, |
|
conv_opos, |
|
NULL |
}; |
}; |
|
|
struct aproc * |
struct aproc * |
|
|
p = aproc_new(&conv_ops, name); |
p = aproc_new(&conv_ops, name); |
aconv_init(&p->u.conv.ist, ipar, 1); |
aconv_init(&p->u.conv.ist, ipar, 1); |
aconv_init(&p->u.conv.ost, opar, 0); |
aconv_init(&p->u.conv.ost, opar, 0); |
|
p->u.conv.idelta = 0; |
|
p->u.conv.odelta = 0; |
|
if (debug_level > 0) { |
|
DPRINTF("conv_new: %s: ", p->name); |
|
aparams_print2(ipar, opar); |
|
DPRINTF("\n"); |
|
} |
return p; |
return p; |
} |
} |