fix midithru subscriptions

This commit is contained in:
Alexandre Ratchov 2012-11-29 18:56:59 +01:00
parent 2fd21c86fb
commit 6cb370c626
5 changed files with 135 additions and 153 deletions

View File

@ -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

View File

@ -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");
}

View File

@ -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);

View File

@ -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

View File

@ -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);