version 1.41, 2010/04/03 17:59:17 |
version 1.42, 2010/04/06 20:07:01 |
|
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
*/ |
*/ |
/* |
|
* TODO: |
|
* |
|
* change f->bufsz to contain only socket-side buffer, |
|
* because it's less error prone |
|
*/ |
|
|
|
#include <stdio.h> |
#include <stdio.h> |
#include <stdlib.h> |
#include <stdlib.h> |
|
|
#include "dbg.h" |
#include "dbg.h" |
#endif |
#endif |
|
|
int sock_attach(struct sock *, int); |
void sock_attach(struct sock *, int); |
int sock_read(struct sock *); |
int sock_read(struct sock *); |
int sock_write(struct sock *); |
int sock_write(struct sock *); |
int sock_execmsg(struct sock *); |
int sock_execmsg(struct sock *); |
|
|
void |
void |
sock_dbg(struct sock *f) |
sock_dbg(struct sock *f) |
{ |
{ |
static char *pstates[] = { "hel", "ini", "sta", "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" }; |
|
|
if (f->slot >= 0 && dev_midi) { |
if (f->slot >= 0 && APROC_OK(dev_midi)) { |
dbg_puts(dev_midi->u.ctl.slot[f->slot].name); |
dbg_puts(dev_midi->u.ctl.slot[f->slot].name); |
dbg_putu(dev_midi->u.ctl.slot[f->slot].unit); |
dbg_putu(dev_midi->u.ctl.slot[f->slot].unit); |
} else |
} else |
|
|
|
|
void sock_setvol(void *, unsigned); |
void sock_setvol(void *, unsigned); |
void sock_startreq(void *); |
void sock_startreq(void *); |
|
void sock_stopreq(void *); |
|
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_locreq |
}; |
}; |
|
|
void |
void |
|
|
{ |
{ |
struct sock *f = (struct sock *)p->u.io.file; |
struct sock *f = (struct sock *)p->u.io.file; |
|
|
if (f->mode & AMSG_REC) |
if (f->mode & AMSG_RECMASK) |
return; |
return; |
|
|
f->delta += delta; |
f->delta += delta; |
|
|
{ |
{ |
struct sock *f = (struct sock *)p->u.io.file; |
struct sock *f = (struct sock *)p->u.io.file; |
|
|
if (!(f->mode & AMSG_REC)) |
if (!(f->mode & AMSG_RECMASK)) |
return; |
return; |
|
|
f->delta += delta; |
f->delta += delta; |
|
|
f->mode = 0; |
f->mode = 0; |
f->opt = opt_byname("default"); |
f->opt = opt_byname("default"); |
if (f->opt) { |
if (f->opt) { |
if (dev_sub) |
if (f->opt->mode & MODE_RECMASK) |
f->wpar = f->opt->wpar; |
f->wpar = f->opt->wpar; |
if (dev_mix) |
if (f->opt->mode & MODE_PLAY) |
f->rpar = f->opt->rpar; |
f->rpar = f->opt->rpar; |
} |
} |
f->xrun = AMSG_IGNORE; |
f->xrun = AMSG_IGNORE; |
|
|
f->round = dev_round; |
f->round = dev_round; |
f->delta = 0; |
f->delta = 0; |
f->tickpending = 0; |
f->tickpending = 0; |
|
f->startpending = 0; |
f->vol = f->lastvol = MIDI_MAXCTL; |
f->vol = f->lastvol = MIDI_MAXCTL; |
f->slot = -1; |
f->slot = -1; |
|
|
wproc = aproc_new(&wsock_ops, f->pipe.file.name); |
wproc = aproc_new(&wsock_ops, f->pipe.file.name); |
wproc->u.io.file = &f->pipe.file; |
wproc->u.io.file = &f->pipe.file; |
|
wproc->u.io.partial = 0; |
f->pipe.file.wproc = wproc; |
f->pipe.file.wproc = wproc; |
f->wstate = SOCK_WIDLE; |
f->wstate = SOCK_WIDLE; |
f->wtodo = 0xdeadbeef; |
f->wtodo = 0xdeadbeef; |
|
|
rproc = aproc_new(&rsock_ops, f->pipe.file.name); |
rproc = aproc_new(&rsock_ops, f->pipe.file.name); |
rproc->u.io.file = &f->pipe.file; |
rproc->u.io.file = &f->pipe.file; |
|
rproc->u.io.partial = 0; |
f->pipe.file.rproc = rproc; |
f->pipe.file.rproc = rproc; |
f->rstate = SOCK_RMSG; |
f->rstate = SOCK_RMSG; |
f->rtodo = sizeof(struct amsg); |
f->rtodo = sizeof(struct amsg); |
|
|
if (wbuf) |
if (wbuf) |
abuf_hup(wbuf); |
abuf_hup(wbuf); |
f->tickpending = 0; |
f->tickpending = 0; |
|
f->startpending = 0; |
} |
} |
|
|
/* |
/* |
|
|
{ |
{ |
struct abuf *rbuf = NULL, *wbuf = NULL; |
struct abuf *rbuf = NULL, *wbuf = NULL; |
|
|
|
f->pstate = SOCK_START; |
if (f->mode & AMSG_PLAY) { |
if (f->mode & AMSG_PLAY) { |
rbuf = abuf_new(f->bufsz, &f->rpar); |
rbuf = abuf_new(f->bufsz, &f->rpar); |
aproc_setout(f->pipe.file.rproc, rbuf); |
aproc_setout(f->pipe.file.rproc, rbuf); |
|
if (!ABUF_WOK(rbuf) || (f->pipe.file.state & FILE_EOF)) |
|
f->pstate = SOCK_READY; |
} |
} |
if (f->mode & AMSG_REC) { |
if (f->mode & AMSG_RECMASK) { |
wbuf = abuf_new(f->bufsz, &f->wpar); |
wbuf = abuf_new(f->bufsz, &f->wpar); |
aproc_setin(f->pipe.file.wproc, wbuf); |
aproc_setin(f->pipe.file.wproc, wbuf); |
f->walign = dev_round * wbuf->bpf; |
f->walign = f->round; |
} |
} |
f->delta = 0; |
f->delta = 0; |
|
f->wmax = 0; |
|
f->rmax = f->bufsz; |
f->tickpending = 0; |
f->tickpending = 0; |
|
f->startpending = 0; |
#ifdef DEBUG |
#ifdef DEBUG |
if (debug_level >= 3) { |
if (debug_level >= 3) { |
sock_dbg(f); |
sock_dbg(f); |
dbg_puts(": allocating "); |
dbg_puts(": allocating "); |
dbg_putu(f->bufsz); |
dbg_putu(f->bufsz); |
dbg_puts(" fr buffers\n"); |
dbg_puts(" fr buffers, rmax = "); |
|
dbg_putu(f->rmax); |
|
dbg_puts("\n"); |
} |
} |
#endif |
#endif |
f->pstate = SOCK_START; |
if (f->mode & AMSG_PLAY) { |
if (!(f->mode & AMSG_PLAY) && ctl_slotstart(dev_midi, f->slot)) |
f->pstate = SOCK_START; |
(void)sock_attach(f, 0); |
} else { |
|
f->pstate = SOCK_READY; |
|
if (ctl_slotstart(dev_midi, f->slot)) |
|
(void)sock_attach(f, 0); |
|
} |
} |
} |
|
|
/* |
/* |
|
|
struct sock *f = (struct sock *)arg; |
struct sock *f = (struct sock *)arg; |
|
|
#ifdef DEBUG |
#ifdef DEBUG |
if (f->pstate != SOCK_START) { |
if (f->pstate != SOCK_READY) { |
sock_dbg(f); |
sock_dbg(f); |
dbg_puts(": not in START state\n"); |
dbg_puts(": not in READY state\n"); |
dbg_panic(); |
dbg_panic(); |
} |
} |
#endif |
#endif |
|
|
} |
} |
|
|
/* |
/* |
|
* Callback invoked by MMC stop |
|
*/ |
|
void |
|
sock_stopreq(void *arg) |
|
{ |
|
#ifdef DEBUG |
|
struct sock *f = (struct sock *)arg; |
|
|
|
if (debug_level >= 3) { |
|
sock_dbg(f); |
|
dbg_puts(": ignored STOP signal\n"); |
|
} |
|
#endif |
|
} |
|
|
|
/* |
|
* Callback invoked by MMC relocate, ignored |
|
*/ |
|
void |
|
sock_locreq(void *arg, unsigned mmcpos) |
|
{ |
|
#ifdef DEBUG |
|
struct sock *f = (struct sock *)arg; |
|
|
|
if (debug_level >= 3) { |
|
sock_dbg(f); |
|
dbg_puts(": ignored RELOCATE signal\n"); |
|
} |
|
#endif |
|
} |
|
|
|
/* |
* Attach play and/or record buffers to dev_mix and/or dev_sub. |
* Attach play and/or record buffers to dev_mix and/or dev_sub. |
*/ |
*/ |
int |
void |
sock_attach(struct sock *f, int force) |
sock_attach(struct sock *f, int force) |
{ |
{ |
struct abuf *rbuf, *wbuf; |
struct abuf *rbuf, *wbuf; |
|
|
* the buffer isn't completely filled. |
* the buffer isn't completely filled. |
*/ |
*/ |
if (!force && rbuf && ABUF_WOK(rbuf)) |
if (!force && rbuf && ABUF_WOK(rbuf)) |
return 0; |
return; |
|
|
|
/* |
|
* get the current position, the origin is when |
|
* the first sample is played/recorded |
|
*/ |
|
f->delta = dev_getpos() * (int)f->round / (int)dev_round; |
|
f->startpending = 1; |
|
f->pstate = SOCK_RUN; |
#ifdef DEBUG |
#ifdef DEBUG |
if (debug_level >= 3) { |
if (debug_level >= 3) { |
sock_dbg(f); |
sock_dbg(f); |
dbg_puts(": attaching to device\n"); |
dbg_puts(": attaching at "); |
|
dbg_puti(f->delta); |
|
dbg_puts("\n"); |
} |
} |
#endif |
#endif |
f->pstate = SOCK_RUN; |
|
|
|
/* |
/* |
* Attach them to the device. |
* We dont check whether the device is dying, |
|
* because dev_xxx() functions are supposed to |
|
* work (i.e., not to crash) |
*/ |
*/ |
dev_attach(f->pipe.file.name, |
dev_attach(f->pipe.file.name, f->mode, |
(f->mode & AMSG_PLAY) ? rbuf : NULL, &f->rpar, f->xrun, |
rbuf, &f->rpar, wbuf, &f->wpar, f->xrun, f->opt->maxweight); |
(f->mode & AMSG_REC) ? wbuf : NULL, &f->wpar, 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(rbuf, MIDI_TO_ADATA(f->vol)); |
|
|
|
|
if (!sock_write(f)) |
if (!sock_write(f)) |
break; |
break; |
} |
} |
return 1; |
|
} |
} |
|
|
void |
void |
|
|
{ |
{ |
switch (f->pstate) { |
switch (f->pstate) { |
case SOCK_START: |
case SOCK_START: |
|
case SOCK_READY: |
if (ctl_slotstart(dev_midi, f->slot)) { |
if (ctl_slotstart(dev_midi, f->slot)) { |
(void)sock_attach(f, 1); |
(void)sock_attach(f, 1); |
f->pstate = SOCK_RUN; |
f->pstate = SOCK_RUN; |
|
|
{ |
{ |
struct aproc *p; |
struct aproc *p; |
struct abuf *obuf; |
struct abuf *obuf; |
unsigned char *data; |
unsigned n; |
unsigned count, n; |
|
|
|
#ifdef DEBUG |
#ifdef DEBUG |
if (f->pstate != SOCK_MIDI && f->rtodo == 0) { |
if (f->pstate != SOCK_MIDI && f->rtodo == 0) { |
|
|
obuf = LIST_FIRST(&p->obuflist); |
obuf = LIST_FIRST(&p->obuflist); |
if (obuf == NULL) |
if (obuf == NULL) |
return 0; |
return 0; |
if (ABUF_FULL(obuf) || !(f->pipe.file.state & FILE_ROK)) |
if (!ABUF_WOK(obuf) || !(f->pipe.file.state & FILE_ROK)) |
return 0; |
return 0; |
data = abuf_wgetblk(obuf, &count, 0); |
if (f->pstate == SOCK_MIDI) { |
if (f->pstate != SOCK_MIDI && count > f->rtodo) |
if (!rfile_do(p, obuf->len, NULL)) |
count = f->rtodo; |
return 0; |
n = file_read(&f->pipe.file, data, count); |
} else { |
if (n == 0) |
if (!rfile_do(p, f->rtodo, &n)) |
return 0; |
return 0; |
abuf_wcommit(obuf, n); |
|
if (f->pstate != SOCK_MIDI) |
|
f->rtodo -= n; |
f->rtodo -= n; |
|
if (f->pstate == SOCK_START) { |
|
if (!ABUF_WOK(obuf) || (f->pipe.file.state & FILE_EOF)) |
|
f->pstate = SOCK_READY; |
|
} |
|
} |
return 1; |
return 1; |
} |
} |
|
|
|
|
{ |
{ |
struct aproc *p; |
struct aproc *p; |
struct abuf *ibuf; |
struct abuf *ibuf; |
unsigned char *data; |
unsigned n; |
unsigned count, n; |
|
#define ZERO_MAX 0x1000 |
|
static unsigned char zero[ZERO_MAX]; |
|
|
|
#ifdef DEBUG |
#ifdef DEBUG |
if (f->pstate != SOCK_MIDI && f->wtodo == 0) { |
if (f->pstate != SOCK_MIDI && f->wtodo == 0) { |
|
|
return 0; |
return 0; |
p = f->pipe.file.wproc; |
p = f->pipe.file.wproc; |
ibuf = LIST_FIRST(&p->ibuflist); |
ibuf = LIST_FIRST(&p->ibuflist); |
if (ibuf) { |
#ifdef DEBUG |
if (ABUF_EMPTY(ibuf)) |
if (f->pstate != SOCK_MIDI && ibuf == NULL) { |
|
sock_dbg(f); |
|
dbg_puts(": attempted to write on detached buffer\n"); |
|
dbg_panic(); |
|
} |
|
#endif |
|
if (ibuf == NULL) |
|
return 0; |
|
if (!ABUF_ROK(ibuf)) |
|
return 0; |
|
if (f->pstate == SOCK_MIDI) { |
|
if (!wfile_do(p, ibuf->len, NULL)) |
return 0; |
return 0; |
data = abuf_rgetblk(ibuf, &count, 0); |
|
if (f->pstate != SOCK_MIDI && count > f->wtodo) |
|
count = f->wtodo; |
|
n = file_write(&f->pipe.file, data, count); |
|
if (n == 0) |
|
return 0; |
|
abuf_rdiscard(ibuf, n); |
|
if (f->pstate != SOCK_MIDI) |
|
f->wtodo -= n; |
|
} else { |
} else { |
if (f->pstate == SOCK_MIDI) |
if (!wfile_do(p, f->wtodo, &n)) |
return 0; |
|
/* |
|
* There's no dev_detach() routine yet, |
|
* so now we abruptly destroy the buffer. |
|
* Until we implement dev_detach, complete |
|
* the packet with zeros... |
|
*/ |
|
count = ZERO_MAX; |
|
if (count > f->wtodo) |
|
count = f->wtodo; |
|
n = file_write(&f->pipe.file, zero, count); |
|
if (n == 0) |
|
return 0; |
return 0; |
f->wtodo -= n; |
f->wtodo -= n; |
} |
} |
|
|
f->rpar.le = f->wpar.le = p->le ? 1 : 0; |
f->rpar.le = f->wpar.le = p->le ? 1 : 0; |
if (AMSG_ISSET(p->msb)) |
if (AMSG_ISSET(p->msb)) |
f->rpar.msb = f->wpar.msb = p->msb ? 1 : 0; |
f->rpar.msb = f->wpar.msb = p->msb ? 1 : 0; |
if (AMSG_ISSET(p->rchan) && (f->mode & AMSG_REC)) { |
if (AMSG_ISSET(p->rchan) && (f->mode & AMSG_RECMASK)) { |
if (p->rchan < 1) |
if (p->rchan < 1) |
p->rchan = 1; |
p->rchan = 1; |
if (p->rchan > NCHAN_MAX) |
if (p->rchan > NCHAN_MAX) |
|
|
} |
} |
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 = 2; |
min = 1; |
max = 2 + rate / dev_round; |
max = 1 + rate / 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 >= -1 && dev_midi) { |
if (f->slot >= 0 && dev_midi) { |
dbg_puts(dev_midi->u.ctl.slot[f->slot].name); |
dbg_puts(dev_midi->u.ctl.slot[f->slot].name); |
dbg_putu(dev_midi->u.ctl.slot[f->slot].unit); |
dbg_putu(dev_midi->u.ctl.slot[f->slot].unit); |
} else |
} else |
|
|
dbg_puts(", play = "); |
dbg_puts(", play = "); |
aparams_dbg(&f->rpar); |
aparams_dbg(&f->rpar); |
} |
} |
if (f->mode & AMSG_REC) { |
if (f->mode & AMSG_RECMASK) { |
dbg_puts(", rec:"); |
dbg_puts(", rec:"); |
aparams_dbg(&f->wpar); |
aparams_dbg(&f->wpar); |
} |
} |
|
|
/* |
/* |
* XXX : dev_midi can no longer be NULL, right ? |
* XXX : dev_midi can no longer be NULL, right ? |
*/ |
*/ |
if (dev_midi && (p->proto & (AMSG_MIDIIN | AMSG_MIDIOUT))) { |
if (APROC_OK(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) { |
|
|
f->opt = opt_byname(p->opt); |
f->opt = opt_byname(p->opt); |
if (f->opt == NULL) |
if (f->opt == NULL) |
return 0; |
return 0; |
if (dev_sub) |
if (f->opt->mode & MODE_RECMASK) |
f->wpar = f->opt->wpar; |
f->wpar = f->opt->wpar; |
if (dev_mix) |
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->mode = 0; |
f->mode = 0; |
if (p->proto & AMSG_PLAY) { |
if (p->proto & AMSG_PLAY) { |
if (!dev_mix) { |
if (!APROC_OK(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 (!dev_sub) { |
if (!(APROC_OK(dev_sub) && (f->opt->mode & MODE_REC)) && |
|
!(APROC_OK(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); |
|
|
#endif |
#endif |
return 0; |
return 0; |
} |
} |
f->mode |= AMSG_REC; |
f->mode |= (f->opt->mode & MODE_MON) ? AMSG_MON : AMSG_REC; |
} |
} |
if (dev_midi) { |
if (APROC_OK(dev_midi)) { |
f->slot = ctl_slotnew(dev_midi, |
f->slot = ctl_slotnew(dev_midi, |
p->who, &ctl_sockops, f, |
p->who, &ctl_sockops, f, |
f->opt->mmc); |
f->opt->mmc); |
|
|
sock_execmsg(struct sock *f) |
sock_execmsg(struct sock *f) |
{ |
{ |
struct amsg *m = &f->rmsg; |
struct amsg *m = &f->rmsg; |
|
struct abuf *obuf; |
|
|
switch (m->cmd) { |
switch (m->cmd) { |
case AMSG_DATA: |
case AMSG_DATA: |
|
|
dbg_puts(": DATA message\n"); |
dbg_puts(": DATA message\n"); |
} |
} |
#endif |
#endif |
if (f->pstate != SOCK_RUN && f->pstate != SOCK_START) { |
if (f->pstate != SOCK_RUN && f->pstate != SOCK_START && |
|
f->pstate != SOCK_READY) { |
#ifdef DEBUG |
#ifdef DEBUG |
if (debug_level >= 1) { |
if (debug_level >= 1) { |
sock_dbg(f); |
sock_dbg(f); |
|
|
aproc_del(f->pipe.file.rproc); |
aproc_del(f->pipe.file.rproc); |
return 0; |
return 0; |
} |
} |
if (f->pstate == SOCK_START && |
obuf = LIST_FIRST(&f->pipe.file.rproc->obuflist); |
ABUF_FULL(LIST_FIRST(&f->pipe.file.rproc->obuflist))) { |
if (f->pstate == SOCK_START && !ABUF_WOK(obuf)) { |
#ifdef DEBUG |
#ifdef DEBUG |
if (debug_level >= 1) { |
if (debug_level >= 1) { |
sock_dbg(f); |
sock_dbg(f); |
|
|
aproc_del(f->pipe.file.rproc); |
aproc_del(f->pipe.file.rproc); |
return 0; |
return 0; |
} |
} |
|
if (m->u.data.size % obuf->bpf != 0) { |
|
#ifdef DEBUG |
|
if (debug_level >= 1) { |
|
sock_dbg(f); |
|
dbg_puts(": unaligned data chunk\n"); |
|
} |
|
#endif |
|
aproc_del(f->pipe.file.rproc); |
|
return 0; |
|
} |
f->rstate = SOCK_RDATA; |
f->rstate = SOCK_RDATA; |
f->rtodo = m->u.data.size; |
f->rtodo = m->u.data.size / obuf->bpf; |
|
#ifdef DEBUG |
|
if (f->rtodo > f->rmax && debug_level >= 2) { |
|
sock_dbg(f); |
|
dbg_puts(": received past current position, rtodo = "); |
|
dbg_putu(f->rtodo); |
|
dbg_puts(", rmax = "); |
|
dbg_putu(f->rmax); |
|
dbg_puts("\n"); |
|
aproc_del(f->pipe.file.rproc); |
|
return 0; |
|
} |
|
#endif |
|
f->rmax -= f->rtodo; |
if (f->rtodo == 0) { |
if (f->rtodo == 0) { |
#ifdef DEBUG |
#ifdef DEBUG |
if (debug_level >= 1) { |
if (debug_level >= 1) { |
|
|
dbg_puts(": STOP message\n"); |
dbg_puts(": STOP message\n"); |
} |
} |
#endif |
#endif |
if (f->pstate != SOCK_RUN && f->pstate != SOCK_START) { |
if (f->pstate != SOCK_RUN && |
|
f->pstate != SOCK_START && f->pstate != SOCK_READY) { |
#ifdef DEBUG |
#ifdef DEBUG |
if (debug_level >= 1) { |
if (debug_level >= 1) { |
sock_dbg(f); |
sock_dbg(f); |
|
|
#endif |
#endif |
aproc_del(f->pipe.file.rproc); |
aproc_del(f->pipe.file.rproc); |
return 0; |
return 0; |
|
/* |
|
* XXX: device could have desappeared at this point, |
|
* see how this is fixed in wav.c |
|
*/ |
} |
} |
if (f->pstate == SOCK_START && |
if ((f->pstate == SOCK_START || f->pstate == SOCK_READY) && |
ctl_slotstart(dev_midi, f->slot)) |
ctl_slotstart(dev_midi, f->slot)) |
(void)sock_attach(f, 1); |
(void)sock_attach(f, 1); |
sock_freebuf(f); |
if (f->wstate != SOCK_WDATA || f->wtodo == 0) |
|
sock_freebuf(f); |
|
else |
|
f->pstate = SOCK_STOP; |
AMSG_INIT(m); |
AMSG_INIT(m); |
m->cmd = AMSG_ACK; |
m->cmd = AMSG_ACK; |
f->rstate = SOCK_RRET; |
f->rstate = SOCK_RRET; |
|
|
AMSG_INIT(m); |
AMSG_INIT(m); |
m->cmd = AMSG_GETPAR; |
m->cmd = AMSG_GETPAR; |
m->u.par.legacy_mode = f->mode; |
m->u.par.legacy_mode = f->mode; |
m->u.par.bits = f->rpar.bits; |
if (f->mode & AMSG_PLAY) { |
m->u.par.bps = f->rpar.bps; |
m->u.par.bits = f->rpar.bits; |
m->u.par.sig = f->rpar.sig; |
m->u.par.bps = f->rpar.bps; |
m->u.par.le = f->rpar.le; |
m->u.par.sig = f->rpar.sig; |
m->u.par.msb = f->rpar.msb; |
m->u.par.le = f->rpar.le; |
m->u.par.rate = f->rpar.rate; |
m->u.par.msb = f->rpar.msb; |
m->u.par.rchan = f->wpar.cmax - f->wpar.cmin + 1; |
m->u.par.rate = f->rpar.rate; |
m->u.par.pchan = f->rpar.cmax - f->rpar.cmin + 1; |
m->u.par.pchan = f->rpar.cmax - f->rpar.cmin + 1; |
|
} |
|
if (f->mode & AMSG_RECMASK) { |
|
m->u.par.bits = f->wpar.bits; |
|
m->u.par.bps = f->wpar.bps; |
|
m->u.par.sig = f->wpar.sig; |
|
m->u.par.le = f->wpar.le; |
|
m->u.par.msb = f->wpar.msb; |
|
m->u.par.rate = f->wpar.rate; |
|
m->u.par.rchan = f->wpar.cmax - f->wpar.cmin + 1; |
|
} |
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 + (dev_bufsz / dev_round) * f->round; |
|
|
AMSG_INIT(m); |
AMSG_INIT(m); |
m->cmd = AMSG_GETCAP; |
m->cmd = AMSG_GETCAP; |
m->u.cap.rate = dev_rate; |
m->u.cap.rate = dev_rate; |
m->u.cap.pchan = dev_mix ? |
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 = dev_sub ? |
m->u.cap.rchan = (f->opt->mode & (MODE_PLAY | MODE_REC)) ? |
(f->opt->wpar.cmax - f->opt->wpar.cmin + 1) : 0; |
(f->opt->wpar.cmax - f->opt->wpar.cmin + 1) : 0; |
m->u.cap.bits = sizeof(short) * 8; |
m->u.cap.bits = sizeof(short) * 8; |
m->u.cap.bps = sizeof(short); |
m->u.cap.bps = sizeof(short); |
|
|
dbg_puts(": SETVOL message\n"); |
dbg_puts(": SETVOL message\n"); |
} |
} |
#endif |
#endif |
if (f->pstate != SOCK_RUN && |
if (f->pstate != SOCK_RUN && f->pstate != SOCK_START && |
f->pstate != SOCK_START && f->pstate != SOCK_INIT) { |
f->pstate != SOCK_INIT && f->pstate != SOCK_READY) { |
#ifdef DEBUG |
#ifdef DEBUG |
if (debug_level >= 1) { |
if (debug_level >= 1) { |
sock_dbg(f); |
sock_dbg(f); |
|
|
{ |
{ |
struct aproc *p; |
struct aproc *p; |
struct abuf *ibuf; |
struct abuf *ibuf; |
unsigned size; |
unsigned size, max; |
|
|
if (f->pstate == SOCK_MIDI) { |
if (f->pstate == SOCK_MIDI) { |
#ifdef DEBUG |
#ifdef DEBUG |
|
|
/* |
/* |
* If pos changed, build a MOVE message. |
* If pos changed, build a MOVE message. |
*/ |
*/ |
if (f->tickpending) { |
if ((f->tickpending && f->delta > 0) || f->startpending) { |
#ifdef DEBUG |
#ifdef DEBUG |
if (debug_level >= 4) { |
if (debug_level >= 4) { |
sock_dbg(f); |
sock_dbg(f); |
|
|
dbg_puts("\n"); |
dbg_puts("\n"); |
} |
} |
#endif |
#endif |
|
f->wmax += f->delta; |
|
if (f->delta > 0) |
|
f->rmax += f->delta; |
AMSG_INIT(&f->wmsg); |
AMSG_INIT(&f->wmsg); |
f->wmsg.cmd = AMSG_MOVE; |
f->wmsg.cmd = AMSG_MOVE; |
f->wmsg.u.ts.delta = f->delta; |
f->wmsg.u.ts.delta = f->delta; |
|
|
f->wstate = SOCK_WMSG; |
f->wstate = SOCK_WMSG; |
f->delta = 0; |
f->delta = 0; |
f->tickpending = 0; |
f->tickpending = 0; |
|
f->startpending = 0; |
return 1; |
return 1; |
} |
} |
|
|
|
|
p = f->pipe.file.wproc; |
p = f->pipe.file.wproc; |
ibuf = LIST_FIRST(&p->ibuflist); |
ibuf = LIST_FIRST(&p->ibuflist); |
if (ibuf && ABUF_ROK(ibuf)) { |
if (ibuf && ABUF_ROK(ibuf)) { |
size = ibuf->used - (ibuf->used % ibuf->bpf); |
#ifdef DEBUG |
if (size > AMSG_DATAMAX) |
if (ibuf->used > f->wmax && debug_level >= 3) { |
size = AMSG_DATAMAX - (AMSG_DATAMAX % ibuf->bpf); |
sock_dbg(f); |
|
dbg_puts(": attempt to send past current position\n"); |
|
} |
|
#endif |
|
max = AMSG_DATAMAX / ibuf->bpf; |
|
size = ibuf->used; |
if (size > f->walign) |
if (size > f->walign) |
size = f->walign; |
size = f->walign; |
|
if (size > f->wmax) |
|
size = f->wmax; |
|
if (size > max) |
|
size = max; |
|
if (size == 0) |
|
return 0; |
f->walign -= size; |
f->walign -= size; |
|
f->wmax -= size; |
if (f->walign == 0) |
if (f->walign == 0) |
f->walign = dev_round * ibuf->bpf; |
f->walign = f->round; |
AMSG_INIT(&f->wmsg); |
AMSG_INIT(&f->wmsg); |
f->wmsg.cmd = AMSG_DATA; |
f->wmsg.cmd = AMSG_DATA; |
f->wmsg.u.data.size = size; |
f->wmsg.u.data.size = size * ibuf->bpf; |
f->wtodo = sizeof(struct amsg); |
f->wtodo = sizeof(struct amsg); |
f->wstate = SOCK_WMSG; |
f->wstate = SOCK_WMSG; |
return 1; |
return 1; |
|
|
f->rtodo = sizeof(struct amsg); |
f->rtodo = sizeof(struct amsg); |
} |
} |
/* |
/* |
* XXX: have to way that the buffer is full before starting |
* XXX: sock_attach() may not start if there's not enough |
|
* samples queues, if so ctl_slotstart() will trigger |
|
* other streams, but this one won't start. |
*/ |
*/ |
if (f->pstate == SOCK_START && ctl_slotstart(dev_midi, f->slot)) |
if (f->pstate == SOCK_READY && ctl_slotstart(dev_midi, f->slot)) |
(void)sock_attach(f, 0); |
(void)sock_attach(f, 0); |
break; |
break; |
case SOCK_RRET: |
case SOCK_RRET: |
|
|
f->wtodo = 0xdeadbeef; |
f->wtodo = 0xdeadbeef; |
break; |
break; |
} |
} |
|
/* |
|
* XXX: why not set f->wtodo in sock_wmsg() ? |
|
*/ |
f->wstate = SOCK_WDATA; |
f->wstate = SOCK_WDATA; |
f->wtodo = f->wmsg.u.data.size; |
f->wtodo = f->wmsg.u.data.size / |
|
LIST_FIRST(&f->pipe.file.wproc->ibuflist)->bpf; |
/* PASSTHROUGH */ |
/* PASSTHROUGH */ |
case SOCK_WDATA: |
case SOCK_WDATA: |
if (!sock_wdata(f)) |
if (!sock_wdata(f)) |
|
|
break; |
break; |
f->wstate = SOCK_WIDLE; |
f->wstate = SOCK_WIDLE; |
f->wtodo = 0xdeadbeef; |
f->wtodo = 0xdeadbeef; |
|
if (f->pstate == SOCK_STOP) |
|
sock_freebuf(f); |
/* PASSTHROUGH */ |
/* PASSTHROUGH */ |
case SOCK_WIDLE: |
case SOCK_WIDLE: |
if (!sock_return(f)) |
if (!sock_return(f)) |