version 1.47, 2010/05/08 15:35:45 |
version 1.48, 2010/06/04 06:15:28 |
|
|
static char *pstates[] = { "hel", "ini", "sta", "rdy", "run", "mid" }; |
static char *pstates[] = { "hel", "ini", "sta", "rdy", "run", "mid" }; |
static char *rstates[] = { "rdat", "rmsg", "rret" }; |
static char *rstates[] = { "rdat", "rmsg", "rret" }; |
static char *wstates[] = { "widl", "wmsg", "wdat" }; |
static char *wstates[] = { "widl", "wmsg", "wdat" }; |
|
struct aproc *midi; |
|
|
if (f->slot >= 0 && APROC_OK(dev_midi)) { |
midi = f->dev ? f->dev->midi : NULL; |
dbg_puts(dev_midi->u.ctl.slot[f->slot].name); |
if (f->slot >= 0 && APROC_OK(midi)) { |
dbg_putu(dev_midi->u.ctl.slot[f->slot].unit); |
dbg_puts(midi->u.ctl.slot[f->slot].name); |
|
dbg_putu(midi->u.ctl.slot[f->slot].unit); |
} else |
} else |
dbg_puts(f->pipe.file.name); |
dbg_puts(f->pipe.file.name); |
dbg_puts("/"); |
dbg_puts("/"); |
|
|
void sock_setvol(void *, unsigned); |
void sock_setvol(void *, unsigned); |
void sock_startreq(void *); |
void sock_startreq(void *); |
void sock_stopreq(void *); |
void sock_stopreq(void *); |
|
void sock_quitreq(void *); |
void sock_locreq(void *, unsigned); |
void sock_locreq(void *, unsigned); |
|
|
struct ctl_ops ctl_sockops = { |
struct ctl_ops ctl_sockops = { |
sock_setvol, |
sock_setvol, |
sock_startreq, |
sock_startreq, |
sock_stopreq, |
sock_stopreq, |
sock_locreq |
sock_locreq, |
|
sock_quitreq |
}; |
}; |
|
|
unsigned sock_sesrefs = 0; /* connections to the session */ |
unsigned sock_sesrefs = 0; /* connections to the session */ |
uid_t sock_sesuid; /* owner of the session */ |
uid_t sock_sesuid; /* owner of the session */ |
|
|
void |
void |
sock_close(struct file *f) |
sock_close(struct file *arg) |
{ |
{ |
|
struct sock *f = (struct sock *)arg; |
|
|
sock_sesrefs--; |
sock_sesrefs--; |
pipe_close(f); |
pipe_close(&f->pipe.file); |
dev_unref(); |
if (f->dev) { |
|
dev_unref(f->dev); |
|
f->dev = NULL; |
|
} |
} |
} |
|
|
void |
void |
|
|
f->pipe.file.rproc = NULL; |
f->pipe.file.rproc = NULL; |
if (f->pipe.file.wproc) { |
if (f->pipe.file.wproc) { |
if (f->slot >= 0) |
if (f->slot >= 0) |
ctl_slotdel(dev_midi, f->slot); |
ctl_slotdel(f->dev->midi, f->slot); |
aproc_del(f->pipe.file.wproc); |
aproc_del(f->pipe.file.wproc); |
file_del(&f->pipe.file); |
file_del(&f->pipe.file); |
} |
} |
|
|
f->pipe.file.wproc = NULL; |
f->pipe.file.wproc = NULL; |
if (f->pipe.file.rproc) { |
if (f->pipe.file.rproc) { |
if (f->slot >= 0) |
if (f->slot >= 0) |
ctl_slotdel(dev_midi, f->slot); |
ctl_slotdel(f->dev->midi, f->slot); |
aproc_del(f->pipe.file.rproc); |
aproc_del(f->pipe.file.rproc); |
file_del(&f->pipe.file); |
file_del(&f->pipe.file); |
} |
} |
|
|
close(fd); |
close(fd); |
return NULL; |
return NULL; |
} |
} |
if (!dev_ref()) { |
|
close(fd); |
|
return NULL; |
|
} |
|
f->pstate = SOCK_HELLO; |
f->pstate = SOCK_HELLO; |
f->mode = 0; |
f->mode = 0; |
f->opt = opt_byname("default"); |
f->opt = NULL; |
if (f->opt) { |
f->dev = NULL; |
if (f->opt->mode & MODE_RECMASK) |
|
f->wpar = f->opt->wpar; |
|
if (f->opt->mode & MODE_PLAY) |
|
f->rpar = f->opt->rpar; |
|
} |
|
f->xrun = AMSG_IGNORE; |
f->xrun = AMSG_IGNORE; |
f->bufsz = dev_bufsz; |
|
f->round = dev_round; |
|
f->delta = 0; |
f->delta = 0; |
f->tickpending = 0; |
f->tickpending = 0; |
f->startpending = 0; |
f->startpending = 0; |
|
|
wbuf = LIST_FIRST(&f->pipe.file.wproc->ins); |
wbuf = LIST_FIRST(&f->pipe.file.wproc->ins); |
rbuf = LIST_FIRST(&f->pipe.file.rproc->outs); |
rbuf = LIST_FIRST(&f->pipe.file.rproc->outs); |
if (rbuf || wbuf) |
if (rbuf || wbuf) |
ctl_slotstop(dev_midi, f->slot); |
ctl_slotstop(f->dev->midi, f->slot); |
if (rbuf) |
if (rbuf) |
abuf_eof(rbuf); |
abuf_eof(rbuf); |
if (wbuf) |
if (wbuf) |
|
|
f->pstate = SOCK_START; |
f->pstate = SOCK_START; |
} else { |
} else { |
f->pstate = SOCK_READY; |
f->pstate = SOCK_READY; |
if (ctl_slotstart(dev_midi, f->slot)) |
if (ctl_slotstart(f->dev->midi, f->slot)) |
(void)sock_attach(f, 0); |
(void)sock_attach(f, 0); |
} |
} |
} |
} |
|
|
#endif |
#endif |
return; |
return; |
} |
} |
dev_setvol(rbuf, MIDI_TO_ADATA(vol)); |
dev_setvol(f->dev, rbuf, MIDI_TO_ADATA(vol)); |
} |
} |
|
|
/* |
/* |
|
|
} |
} |
|
|
/* |
/* |
* Attach play and/or record buffers to dev_mix and/or dev_sub. |
* Callback invoked when slot is gone |
*/ |
*/ |
void |
void |
|
sock_quitreq(void *arg) |
|
{ |
|
struct sock *f = (struct sock *)arg; |
|
|
|
#ifdef DEBUG |
|
if (debug_level >= 3) { |
|
sock_dbg(f); |
|
dbg_puts(": slot gone\n"); |
|
} |
|
#endif |
|
file_close(&f->pipe.file); |
|
} |
|
|
|
/* |
|
* Attach play and/or record buffers to dev->mix and/or dev->sub. |
|
*/ |
|
void |
sock_attach(struct sock *f, int force) |
sock_attach(struct sock *f, int force) |
{ |
{ |
struct abuf *rbuf, *wbuf; |
struct abuf *rbuf, *wbuf; |
|
|
* start the device (dev_getpos() and dev_attach() must |
* start the device (dev_getpos() and dev_attach() must |
* be called on a started device |
* be called on a started device |
*/ |
*/ |
dev_wakeup(); |
dev_wakeup(f->dev); |
|
|
/* |
/* |
* get the current position, the origin is when |
* get the current position, the origin is when |
* the first sample is played/recorded |
* the first sample is played/recorded |
*/ |
*/ |
f->delta = dev_getpos() * (int)f->round / (int)dev_round; |
f->delta = dev_getpos(f->dev) * (int)f->round / (int)f->dev->round; |
f->startpending = 1; |
f->startpending = 1; |
f->pstate = SOCK_RUN; |
f->pstate = SOCK_RUN; |
#ifdef DEBUG |
#ifdef DEBUG |
|
|
* because dev_xxx() functions are supposed to |
* because dev_xxx() functions are supposed to |
* work (i.e., not to crash) |
* work (i.e., not to crash) |
*/ |
*/ |
dev_attach(f->pipe.file.name, f->mode, |
dev_attach(f->dev, f->pipe.file.name, f->mode, |
rbuf, &f->rpar, |
rbuf, &f->rpar, |
f->opt->join ? f->opt->rpar.cmax - f->opt->rpar.cmin + 1 : 0, |
f->opt->join ? f->opt->rpar.cmax - f->opt->rpar.cmin + 1 : 0, |
wbuf, &f->wpar, |
wbuf, &f->wpar, |
f->opt->join ? f->opt->wpar.cmax - f->opt->wpar.cmin + 1 : 0, |
f->opt->join ? f->opt->wpar.cmax - f->opt->wpar.cmin + 1 : 0, |
f->xrun, f->opt->maxweight); |
f->xrun, f->opt->maxweight); |
if (f->mode & AMSG_PLAY) |
if (f->mode & AMSG_PLAY) |
dev_setvol(rbuf, MIDI_TO_ADATA(f->vol)); |
dev_setvol(f->dev, rbuf, MIDI_TO_ADATA(f->vol)); |
|
|
/* |
/* |
* Send the initial position, if needed. |
* Send the initial position, if needed. |
|
|
switch (f->pstate) { |
switch (f->pstate) { |
case SOCK_START: |
case SOCK_START: |
case SOCK_READY: |
case SOCK_READY: |
if (ctl_slotstart(dev_midi, f->slot)) { |
if (ctl_slotstart(f->dev->midi, f->slot)) { |
(void)sock_attach(f, 1); |
(void)sock_attach(f, 1); |
f->pstate = SOCK_RUN; |
f->pstate = SOCK_RUN; |
} |
} |
|
|
p->rate = RATE_MIN; |
p->rate = RATE_MIN; |
if (p->rate > RATE_MAX) |
if (p->rate > RATE_MAX) |
p->rate = RATE_MAX; |
p->rate = RATE_MAX; |
f->round = dev_roundof(p->rate); |
f->round = dev_roundof(f->dev, p->rate); |
f->rpar.rate = f->wpar.rate = p->rate; |
f->rpar.rate = f->wpar.rate = p->rate; |
if (!AMSG_ISSET(p->appbufsz)) { |
if (!AMSG_ISSET(p->appbufsz)) { |
p->appbufsz = dev_bufsz / dev_round * f->round; |
p->appbufsz = f->dev->bufsz / f->dev->round * f->round; |
#ifdef DEBUG |
#ifdef DEBUG |
if (debug_level >= 3) { |
if (debug_level >= 3) { |
sock_dbg(f); |
sock_dbg(f); |
|
|
dbg_puts("fr total buffer size\n"); |
dbg_puts("fr total buffer size\n"); |
} |
} |
#endif |
#endif |
min = (dev_bufsz / dev_round) * f->round; |
min = (f->dev->bufsz / f->dev->round) * f->round; |
if (p->bufsz < min) |
if (p->bufsz < min) |
p->bufsz = min; |
p->bufsz = min; |
p->appbufsz = p->bufsz - min; |
p->appbufsz = p->bufsz - min; |
|
|
if (AMSG_ISSET(p->appbufsz)) { |
if (AMSG_ISSET(p->appbufsz)) { |
rate = (f->mode & AMSG_PLAY) ? f->rpar.rate : f->wpar.rate; |
rate = (f->mode & AMSG_PLAY) ? f->rpar.rate : f->wpar.rate; |
min = 1; |
min = 1; |
max = 1 + rate / dev_round; |
max = 1 + rate / f->dev->round; |
min *= f->round; |
min *= f->round; |
max *= f->round; |
max *= f->round; |
p->appbufsz += f->round - 1; |
p->appbufsz += f->round - 1; |
|
|
} |
} |
#ifdef DEBUG |
#ifdef DEBUG |
if (debug_level >= 2) { |
if (debug_level >= 2) { |
if (f->slot >= 0 && dev_midi) { |
if (APROC_OK(f->dev->midi)) { |
dbg_puts(dev_midi->u.ctl.slot[f->slot].name); |
dbg_puts(f->dev->midi->u.ctl.slot[f->slot].name); |
dbg_putu(dev_midi->u.ctl.slot[f->slot].unit); |
dbg_putu(f->dev->midi->u.ctl.slot[f->slot].unit); |
} else |
} else |
dbg_puts(f->pipe.file.name); |
dbg_puts(f->pipe.file.name); |
dbg_puts(": buffer size = "); |
dbg_puts(": buffer size = "); |
|
|
wbuf = abuf_new(MIDI_BUFSZ, &aparams_none); |
wbuf = abuf_new(MIDI_BUFSZ, &aparams_none); |
aproc_setin(f->pipe.file.wproc, wbuf); |
aproc_setin(f->pipe.file.wproc, wbuf); |
} |
} |
dev_midiattach(rbuf, wbuf); |
dev_midiattach(f->dev, rbuf, wbuf); |
} |
} |
|
|
int |
int |
|
|
#endif |
#endif |
return 0; |
return 0; |
} |
} |
/* |
f->opt = opt_byname(p->opt); |
* XXX : dev_midi can no longer be NULL, right ? |
if (f->opt == NULL) |
*/ |
return 0; |
if (APROC_OK(dev_midi) && (p->proto & (AMSG_MIDIIN | AMSG_MIDIOUT))) { |
if (!dev_ref(f->opt->dev)) |
|
return 0; |
|
f->dev = f->opt->dev; |
|
|
|
if (APROC_OK(f->dev->midi) && (p->proto & (AMSG_MIDIIN | AMSG_MIDIOUT))) { |
if (p->proto & ~(AMSG_MIDIIN | AMSG_MIDIOUT)) { |
if (p->proto & ~(AMSG_MIDIIN | AMSG_MIDIOUT)) { |
#ifdef DEBUG |
#ifdef DEBUG |
if (debug_level >= 1) { |
if (debug_level >= 1) { |
|
|
sock_midiattach(f, p->proto); |
sock_midiattach(f, p->proto); |
return 1; |
return 1; |
} |
} |
f->opt = opt_byname(p->opt); |
|
if (f->opt == NULL) |
|
return 0; |
|
if (f->opt->mode & MODE_RECMASK) |
if (f->opt->mode & MODE_RECMASK) |
f->wpar = f->opt->wpar; |
f->wpar = f->opt->wpar; |
if (f->opt->mode & MODE_PLAY) |
if (f->opt->mode & MODE_PLAY) |
f->rpar = f->opt->rpar; |
f->rpar = f->opt->rpar; |
if (f->opt->mmc) |
if (f->opt->mmc) |
f->xrun = AMSG_SYNC; |
f->xrun = AMSG_SYNC; |
|
f->bufsz = f->dev->bufsz; |
|
f->round = f->dev->round; |
if ((p->proto & ~(AMSG_PLAY | AMSG_REC)) != 0 || |
if ((p->proto & ~(AMSG_PLAY | AMSG_REC)) != 0 || |
(p->proto & (AMSG_PLAY | AMSG_REC)) == 0) { |
(p->proto & (AMSG_PLAY | AMSG_REC)) == 0) { |
#ifdef DEBUG |
#ifdef DEBUG |
|
|
} |
} |
f->mode = 0; |
f->mode = 0; |
if (p->proto & AMSG_PLAY) { |
if (p->proto & AMSG_PLAY) { |
if (!APROC_OK(dev_mix) || !(f->opt->mode & MODE_PLAY)) { |
if (!APROC_OK(f->dev->mix) || !(f->opt->mode & MODE_PLAY)) { |
#ifdef DEBUG |
#ifdef DEBUG |
if (debug_level >= 1) { |
if (debug_level >= 1) { |
sock_dbg(f); |
sock_dbg(f); |
|
|
f->mode |= AMSG_PLAY; |
f->mode |= AMSG_PLAY; |
} |
} |
if (p->proto & AMSG_REC) { |
if (p->proto & AMSG_REC) { |
if (!(APROC_OK(dev_sub) && (f->opt->mode & MODE_REC)) && |
if (!(APROC_OK(f->dev->sub) && (f->opt->mode & MODE_REC)) && |
!(APROC_OK(dev_submon) && (f->opt->mode & MODE_MON))) { |
!(APROC_OK(f->dev->submon) && (f->opt->mode & MODE_MON))) { |
#ifdef DEBUG |
#ifdef DEBUG |
if (debug_level >= 1) { |
if (debug_level >= 1) { |
sock_dbg(f); |
sock_dbg(f); |
|
|
} |
} |
f->mode |= (f->opt->mode & MODE_MON) ? AMSG_MON : AMSG_REC; |
f->mode |= (f->opt->mode & MODE_MON) ? AMSG_MON : AMSG_REC; |
} |
} |
if (APROC_OK(dev_midi)) { |
if (APROC_OK(f->dev->midi)) { |
f->slot = ctl_slotnew(dev_midi, |
f->slot = ctl_slotnew(f->dev->midi, |
p->who, &ctl_sockops, f, |
p->who, &ctl_sockops, f, |
f->opt->mmc); |
f->opt->mmc); |
if (f->slot < 0) { |
if (f->slot < 0) { |
|
|
*/ |
*/ |
} |
} |
if ((f->pstate == SOCK_START || f->pstate == SOCK_READY) && |
if ((f->pstate == SOCK_START || f->pstate == SOCK_READY) && |
ctl_slotstart(dev_midi, f->slot)) |
ctl_slotstart(f->dev->midi, f->slot)) |
(void)sock_attach(f, 1); |
(void)sock_attach(f, 1); |
if (f->wstate != SOCK_WDATA || f->wtodo == 0) |
if (f->wstate != SOCK_WDATA || f->wtodo == 0) |
sock_freebuf(f); |
sock_freebuf(f); |
|
|
} |
} |
m->u.par.appbufsz = f->bufsz; |
m->u.par.appbufsz = f->bufsz; |
m->u.par.bufsz = |
m->u.par.bufsz = |
f->bufsz + (dev_bufsz / dev_round) * f->round; |
f->bufsz + (f->dev->bufsz / f->dev->round) * f->round; |
m->u.par.round = f->round; |
m->u.par.round = f->round; |
f->rstate = SOCK_RRET; |
f->rstate = SOCK_RRET; |
f->rtodo = sizeof(struct amsg); |
f->rtodo = sizeof(struct amsg); |
|
|
} |
} |
AMSG_INIT(m); |
AMSG_INIT(m); |
m->cmd = AMSG_GETCAP; |
m->cmd = AMSG_GETCAP; |
m->u.cap.rate = dev_rate; |
m->u.cap.rate = f->dev->rate; |
m->u.cap.pchan = (f->opt->mode & MODE_PLAY) ? |
m->u.cap.pchan = (f->opt->mode & MODE_PLAY) ? |
(f->opt->rpar.cmax - f->opt->rpar.cmin + 1) : 0; |
(f->opt->rpar.cmax - f->opt->rpar.cmin + 1) : 0; |
m->u.cap.rchan = (f->opt->mode & (MODE_PLAY | MODE_REC)) ? |
m->u.cap.rchan = (f->opt->mode & (MODE_PLAY | MODE_REC)) ? |
|
|
} |
} |
sock_setvol(f, m->u.vol.ctl); |
sock_setvol(f, m->u.vol.ctl); |
if (f->slot >= 0) |
if (f->slot >= 0) |
ctl_slotvol(dev_midi, f->slot, m->u.vol.ctl); |
ctl_slotvol(f->dev->midi, f->slot, m->u.vol.ctl); |
f->rtodo = sizeof(struct amsg); |
f->rtodo = sizeof(struct amsg); |
f->rstate = SOCK_RMSG; |
f->rstate = SOCK_RMSG; |
break; |
break; |
|
|
* samples queues, if so ctl_slotstart() will trigger |
* samples queues, if so ctl_slotstart() will trigger |
* other streams, but this one won't start. |
* other streams, but this one won't start. |
*/ |
*/ |
if (f->pstate == SOCK_READY && ctl_slotstart(dev_midi, f->slot)) |
if (f->pstate == SOCK_READY && ctl_slotstart(f->dev->midi, f->slot)) |
(void)sock_attach(f, 0); |
(void)sock_attach(f, 0); |
break; |
break; |
case SOCK_RRET: |
case SOCK_RRET: |