From 6cb370c626f32a830ea86f9dc0a6803988cf4db3 Mon Sep 17 00:00:00 2001 From: Alexandre Ratchov Date: Thu, 29 Nov 2012 18:56:59 +0100 Subject: [PATCH] fix midithru subscriptions --- sndiod/dev.c | 8 +- sndiod/midi.c | 226 +++++++++++++++++++++++------------------------ sndiod/midi.h | 9 +- sndiod/miofile.c | 18 ++-- sndiod/sock.c | 27 +++--- 5 files changed, 135 insertions(+), 153 deletions(-) diff --git a/sndiod/dev.c b/sndiod/dev.c index 8385056..e0a2395 100644 --- a/sndiod/dev.c +++ b/sndiod/dev.c @@ -467,13 +467,7 @@ dev_midi_omsg(void *arg, unsigned char *msg, int len) void dev_midi_fill(void *arg, int count) { -#ifdef DEBUG - struct dev *d = arg; - - dev_log(d); - log_puts(": can't receive fill input\n"); - panic(); -#endif + /* nothing to do */ } void diff --git a/sndiod/midi.c b/sndiod/midi.c index 18c4a45..d133b55 100644 --- a/sndiod/midi.c +++ b/sndiod/midi.c @@ -61,7 +61,7 @@ struct port *port_list = NULL; unsigned int midi_portnum = 0; struct midithru { - unsigned txmask; + unsigned int txmask, rxmask; #define MIDITHRU_NMAX 32 } midithru[MIDITHRU_NMAX]; @@ -121,18 +121,16 @@ midi_new(struct midiops *ops, void *arg, int mode) ep->idx = 0; ep->st = 0; ep->txmask = 0; - ep->rxmask = 1 << i; + ep->self = 1 << i; + ep->tickets = 0; ep->mode = mode; + /* - * client output is our input (ibuf) and our output (obuf) goes - * to client input + * the output buffer is the client intput */ - if (ep->mode & MODE_MIDIOUT) { - abuf_init(&ep->ibuf, MIDI_BUFSZ); - } - if (ep->mode & MODE_MIDIIN) { + if (ep->mode & MODE_MIDIIN) abuf_init(&ep->obuf, MIDI_BUFSZ); - } + midi_tickets(ep); return ep; } @@ -140,64 +138,82 @@ void midi_del(struct midi *ep) { int i; + struct midi *peer; - for (i = 0; i < MIDI_NEP; i++) - midi_ep[i].txmask &= ~ep->rxmask; - for (i = 0; i < MIDITHRU_NMAX; i++) - midithru[i].txmask &= ~ep->rxmask; - - /* XXX: drain output */ - ep->ops = NULL; - if (ep->mode & MODE_MIDIOUT) { - abuf_done(&ep->ibuf); + ep->txmask = 0; + for (i = 0; i < MIDI_NEP; i++) { + peer = midi_ep + i; + if (peer->txmask & ep->self) { + peer->txmask &= ~ep->self; + midi_tickets(peer); + } } + for (i = 0; i < MIDITHRU_NMAX; i++) { + midithru[i].txmask &= ~ep->self; + midithru[i].rxmask &= ~ep->self; + } + ep->ops = NULL; if (ep->mode & MODE_MIDIIN) { abuf_done(&ep->obuf); } } +/* + * connect two midi endpoints + */ +void +midi_link(struct midi *ep, struct midi *peer) +{ + if (ep->mode & MODE_MIDIOUT) { + ep->txmask |= peer->self; + midi_tickets(ep); + } + if (ep->mode & MODE_MIDIIN) { +#ifdef DEBUG + if (ep->obuf.used > 0) { + midi_log(ep); + log_puts(": linked with non-empty buffer\n"); + panic(); + } +#endif + /* ep has empry buffer, so no need to call midi_tickets() */ + peer->txmask |= ep->self; + } +} + /* * add the midi endpoint in the ``tag'' midi thru box */ void midi_tag(struct midi *ep, unsigned int tag) { + struct midi *peer; + struct midithru *t = midithru + tag; int i; - struct midi *m; - unsigned members; - members = midithru[tag].txmask; - midithru[tag].txmask |= ep->rxmask; - - for (i = 0, m = midi_ep; i < MIDI_NEP; i++, m++) { - if (!(members & (1 << i))) - continue; - if (ep->mode & MODE_MIDIOUT) - ep->txmask |= m->rxmask; - if (ep->mode & MODE_MIDIIN) - m->txmask |= ep->rxmask; + if (ep->mode & MODE_MIDIOUT) { + ep->txmask |= t->txmask; + midi_tickets(ep); } -} - -/* - * remove the midi endpoint from the ``tag'' midi thru box - */ -void -midi_untag(struct midi *ep, unsigned int tag) -{ - int i; - struct midi *m; - unsigned members; - - members = midithru[tag].txmask; - midithru[tag].txmask &= ~ep->rxmask; - - for (i = 0, m = midi_ep;; i++, m++) { - if (!(members & (1 << i))) - continue; - ep->txmask &= ~m->rxmask; - m->txmask &= ~ep->rxmask; + if (ep->mode & MODE_MIDIIN) { +#ifdef DEBUG + if (ep->obuf.used > 0) { + midi_log(ep); + log_puts(": tagged with non-empty buffer\n"); + panic(); + } +#endif + for (i = 0; i < MIDI_NEP; i++) { + if (!(t->rxmask & (1 << i))) + continue; + peer = midi_ep + i; + peer->txmask |= ep->self; + } } + if (ep->mode & MODE_MIDIOUT) + t->rxmask |= ep->self; + if (ep->mode & MODE_MIDIIN) + t->txmask |= ep->self; } /* @@ -242,27 +258,58 @@ midi_send(struct midi *iep, unsigned char *msg, int size) } +/* + * determine if we have gained more input tickets, and if so call the + * fill() call-back to notify the i/o layer that it can send more data + */ void -midi_fill(struct midi *oep) +midi_tickets(struct midi *iep) { - int i, count; - struct midi *iep; + int i, tickets, avail, maxavail; + struct midi *oep; + maxavail = MIDI_BUFSZ; for (i = 0; i < MIDI_NEP ; i++) { - if ((oep->rxmask & (1 << i)) == 0) + if ((iep->txmask & (1 << i)) == 0) continue; - iep = midi_ep + i; - count = midi_in(iep); - if (count) - iep->ops->fill(iep->arg, count); + oep = midi_ep + i; + avail = oep->obuf.len - oep->obuf.used; + if (maxavail > avail) + maxavail = avail; + } + + /* + * in the worst case output message is twice the + * input message (2-byte messages with running status) + */ + tickets = maxavail / 2 - iep->tickets; + if (tickets > 0) { + iep->tickets += tickets; + iep->ops->fill(iep->arg, tickets); } } /* - * parse the give data chunk, and calling imsg() for each message + * recalculate tickets of endpoints sending data to this one */ void -midi_parse(struct midi *iep, unsigned char *idata, int icount) +midi_fill(struct midi *oep) +{ + int i; + struct midi *iep; + + for (i = 0; i < MIDI_NEP; i++) { + iep = midi_ep + i; + if (iep->txmask & oep->self) + midi_tickets(iep); + } +} + +/* + * parse then give data chunk, and calling imsg() for each message + */ +void +midi_in(struct midi *iep, unsigned char *idata, int icount) { int i; unsigned char c; @@ -305,60 +352,9 @@ midi_parse(struct midi *iep, unsigned char *idata, int icount) } } } -} - -/* - * process input data stored in ep->ibuf - */ -int -midi_in(struct midi *iep) -{ - unsigned char *idata; - int i, icount, maxavail, avail, idone; - struct midi *oep; - - /* - * calculate the max message size we can process - */ - maxavail = MIDI_BUFSZ; - for (i = 0; i < MIDI_NEP ; i++) { - if ((iep->txmask & (1 << i)) == 0) - continue; - oep = midi_ep + i; - avail = oep->obuf.len - oep->obuf.used; - if (maxavail > avail) - maxavail = avail; - } - - /* - * in the works case output message is twice the - * input message (2-byte messages with running status) - */ - maxavail /= 2; - idone = 0; - for (;;) { - idata = abuf_rgetblk(&iep->ibuf, &icount); - if (icount > maxavail) - icount = maxavail; - if (icount == 0) - break; - maxavail -= icount; -#ifdef DEBUG - if (log_level >= 4) { - midi_log(iep); - log_puts(": in:"); - for (i = 0; i < icount; i++) { - log_puts(" "); - log_putx(idata[i]); - } - log_puts("\n"); - } -#endif - midi_parse(iep, idata, icount); - abuf_rdiscard(&iep->ibuf, icount); - idone += icount; - } - return idone; + iep->tickets -= icount; + if (iep->tickets < 0) + iep->tickets = 0; } /* @@ -378,7 +374,7 @@ midi_out(struct midi *oep, unsigned char *idata, int icount) #ifdef DEBUG if (log_level >= 2) { midi_log(oep); - log_puts(": overrun, discarding "); + log_puts(": too slow, discarding "); log_putu(oep->obuf.used); log_puts(" bytes\n"); } diff --git a/sndiod/midi.h b/sndiod/midi.h index ae10ec7..5bfbae6 100644 --- a/sndiod/midi.h +++ b/sndiod/midi.h @@ -72,8 +72,8 @@ struct midi { unsigned int idx; /* current ``msg'' size */ unsigned int len; /* expected ``msg'' length */ unsigned int txmask; /* list of ep we send to */ - unsigned int rxmask; /* single ep we accept data for */ - struct abuf ibuf; /* input buffer */ + unsigned int self; /* equal (1 << index) */ + unsigned int tickets; /* max bytes we can process */ struct abuf obuf; /* output buffer */ }; @@ -102,12 +102,13 @@ void midi_done(void); struct midi *midi_new(struct midiops *, void *, int); void midi_del(struct midi *); void midi_log(struct midi *); -int midi_in(struct midi *); +void midi_tickets(struct midi *); +void midi_in(struct midi *, unsigned char *, int); void midi_out(struct midi *, unsigned char *, int); void midi_send(struct midi *, unsigned char *, int); void midi_fill(struct midi *); void midi_tag(struct midi *, unsigned int); -void midi_untag(struct midi *, unsigned int); +void midi_link(struct midi *, struct midi *); struct port *port_new(char *, unsigned int); struct port *port_bynum(int); diff --git a/sndiod/miofile.c b/sndiod/miofile.c index 8fb19f0..8530181 100644 --- a/sndiod/miofile.c +++ b/sndiod/miofile.c @@ -68,7 +68,7 @@ port_mio_pollfd(void *addr, struct pollfd *pfd) struct midi *ep = p->midi; int events = 0; - if ((ep->mode & MODE_MIDIIN) && ep->ibuf.used < ep->ibuf.len) + if (ep->mode & MODE_MIDIIN) events |= POLLIN; if ((ep->mode & MODE_MIDIOUT) && ep->obuf.used > 0) events |= POLLOUT; @@ -86,22 +86,16 @@ port_mio_revents(void *addr, struct pollfd *pfd) void port_mio_in(void *arg) { + unsigned char data[MIDI_BUFSZ]; struct port *p = arg; struct midi *ep = p->midi; - unsigned char *data; - int n, count; + int n; for (;;) { - data = abuf_wgetblk(&ep->ibuf, &count); - if (count == 0) - break; - n = mio_read(p->mio.hdl, data, count); + n = mio_read(p->mio.hdl, data, MIDI_BUFSZ); if (n == 0) break; - abuf_wcommit(&ep->ibuf, n); - midi_in(ep); - if (n < count) - break; + midi_in(ep, data, n); } } @@ -123,8 +117,8 @@ port_mio_out(void *arg) abuf_rdiscard(&ep->obuf, n); if (n < count) break; - midi_fill(ep); } + midi_fill(ep); } void diff --git a/sndiod/sock.c b/sndiod/sock.c index bc235d5..911f925 100644 --- a/sndiod/sock.c +++ b/sndiod/sock.c @@ -505,7 +505,7 @@ sock_wmsg(struct sock *f) int sock_rdata(struct sock *f) { - struct abuf *buf; + unsigned char midibuf[MIDI_BUFSZ]; unsigned char *data; int n, count; @@ -516,19 +516,23 @@ sock_rdata(struct sock *f) panic(); } #endif - if (f->slot) - buf = &f->slot->mix.buf; - else - buf = &f->midi->ibuf; while (f->rtodo > 0) { - data = abuf_wgetblk(buf, &count); + if (f->slot) + data = abuf_wgetblk(&f->slot->mix.buf, &count); + else { + data = midibuf; + count = MIDI_BUFSZ; + } if (count > f->rtodo) count = f->rtodo; n = sock_fdread(f, data, count); if (n == 0) return 0; f->rtodo -= n; - abuf_wcommit(buf, n); + if (f->slot) + abuf_wcommit(&f->slot->mix.buf, n); + else + midi_in(f->midi, midibuf, n); } #ifdef DEBUG if (log_level >= 4) { @@ -538,8 +542,6 @@ sock_rdata(struct sock *f) #endif if (f->slot) slot_write(f->slot); - if (f->midi) - f->fillpending += midi_in(f->midi); return 1; } @@ -864,14 +866,9 @@ sock_hello(struct sock *f) c = port_bynum(p->devnum - 32); if (c == NULL) return 0; - if (mode & MODE_MIDIOUT) - f->midi->txmask |= c->midi->rxmask; - if (mode & MODE_MIDIIN) - c->midi->txmask |= f->midi->rxmask; + midi_link(f->midi, c->midi); } else return 0; - if (mode & MODE_MIDIOUT) - f->fillpending = MIDI_BUFSZ; return 1; } f->opt = opt_byname(p->opt, p->devnum);