[BACK]Return to sock.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / aucat

Annotation of src/usr.bin/aucat/sock.c, Revision 1.34

1.34    ! ratchov     1: /*     $OpenBSD: sock.c,v 1.33 2009/10/22 21:41:30 ratchov Exp $       */
1.1       ratchov     2: /*
                      3:  * Copyright (c) 2008 Alexandre Ratchov <alex@caoua.org>
                      4:  *
                      5:  * Permission to use, copy, modify, and distribute this software for any
                      6:  * purpose with or without fee is hereby granted, provided that the above
                      7:  * copyright notice and this permission notice appear in all copies.
                      8:  *
                      9:  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
                     10:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
                     11:  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
                     12:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
                     13:  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
                     14:  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
                     15:  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
                     16:  */
                     17: /*
                     18:  * TODO:
                     19:  *
                     20:  *     change f->bufsz to contain only socket-side buffer,
                     21:  *     because it's less error prone
                     22:  */
                     23:
                     24: #include <stdio.h>
                     25: #include <stdlib.h>
                     26: #include <string.h>
1.20      ratchov    27:
                     28: #include "abuf.h"
1.1       ratchov    29: #include "aproc.h"
1.20      ratchov    30: #include "conf.h"
1.1       ratchov    31: #include "dev.h"
1.19      ratchov    32: #include "midi.h"
                     33: #include "opt.h"
1.20      ratchov    34: #include "sock.h"
1.1       ratchov    35:
                     36: int sock_attach(struct sock *, int);
                     37: int sock_read(struct sock *);
                     38: int sock_write(struct sock *);
                     39: int sock_execmsg(struct sock *);
                     40: void sock_reset(struct sock *);
                     41:
                     42: struct fileops sock_ops = {
                     43:        "sock",
                     44:        sizeof(struct sock),
                     45:                pipe_close,
                     46:        pipe_read,
                     47:        pipe_write,
                     48:        NULL, /* start */
                     49:        NULL, /* stop */
                     50:        pipe_nfds,
                     51:        pipe_pollfd,
                     52:        pipe_revents
                     53: };
1.30      ratchov    54:
1.1       ratchov    55:
1.34    ! ratchov    56: void sock_setvol(void *, unsigned);
        !            57:
        !            58: struct ctl_ops ctl_sockops = {
        !            59:        sock_setvol,
        !            60: };
        !            61:
1.1       ratchov    62: void
                     63: rsock_done(struct aproc *p)
                     64: {
                     65:        struct sock *f = (struct sock *)p->u.io.file;
                     66:
1.11      ratchov    67:        if (f == NULL)
                     68:                return;
1.1       ratchov    69:        sock_reset(f);
                     70:        f->pipe.file.rproc = NULL;
                     71:        if (f->pipe.file.wproc) {
1.34    ! ratchov    72:                if (f->slot >= 0)
1.24      ratchov    73:                        ctl_slotdel(dev_midi, f->slot);
1.1       ratchov    74:                aproc_del(f->pipe.file.wproc);
                     75:                file_del(&f->pipe.file);
                     76:        }
1.11      ratchov    77:        p->u.io.file = NULL;
1.1       ratchov    78: }
                     79:
                     80: int
                     81: rsock_in(struct aproc *p, struct abuf *ibuf_dummy)
                     82: {
                     83:        struct sock *f = (struct sock *)p->u.io.file;
                     84:        struct abuf *obuf;
                     85:
                     86:        if (!sock_read(f))
                     87:                return 0;
                     88:        obuf = LIST_FIRST(&p->obuflist);
1.34    ! ratchov    89:        if (obuf && f->pstate >= SOCK_RUN) {
1.1       ratchov    90:                if (!abuf_flush(obuf))
                     91:                        return 0;
                     92:        }
                     93:        return 1;
                     94: }
                     95:
                     96: int
                     97: rsock_out(struct aproc *p, struct abuf *obuf)
                     98: {
                     99:        struct sock *f = (struct sock *)p->u.io.file;
                    100:
1.19      ratchov   101:        if (f->pipe.file.state & FILE_RINUSE)
1.1       ratchov   102:                return 0;
                    103:
1.12      ratchov   104:        /*
1.20      ratchov   105:         * When calling sock_read(), we may receive a ``STOP'' command,
1.1       ratchov   106:         * and detach ``obuf''. In this case, there's no more caller and
1.20      ratchov   107:         * we'll stop processing further messages, resulting in a deadlock.
1.1       ratchov   108:         * The solution is to iterate over sock_read() in order to
                    109:         * consume all messages().
                    110:         */
                    111:        for (;;) {
                    112:                if (!sock_read(f))
1.12      ratchov   113:                        return 0;
1.1       ratchov   114:        }
                    115:        return 1;
                    116: }
                    117:
                    118: void
                    119: rsock_eof(struct aproc *p, struct abuf *ibuf_dummy)
                    120: {
                    121:        aproc_del(p);
                    122: }
                    123:
                    124: void
                    125: rsock_hup(struct aproc *p, struct abuf *ibuf)
                    126: {
                    127:        aproc_del(p);
                    128: }
                    129:
                    130: void
                    131: rsock_opos(struct aproc *p, struct abuf *obuf, int delta)
                    132: {
                    133:        struct sock *f = (struct sock *)p->u.io.file;
                    134:
1.15      ratchov   135:        if (f->mode & AMSG_REC)
1.14      ratchov   136:                return;
                    137:
                    138:        f->delta += delta;
                    139:        f->tickpending++;
1.1       ratchov   140:        for (;;) {
                    141:                if (!sock_write(f))
                    142:                        break;
                    143:        }
                    144: }
                    145:
                    146: struct aproc_ops rsock_ops = {
                    147:        "rsock",
                    148:        rsock_in,
                    149:        rsock_out,
                    150:        rsock_eof,
                    151:        rsock_hup,
                    152:        NULL, /* newin */
                    153:        NULL, /* newout */
                    154:        NULL, /* ipos */
                    155:        rsock_opos,
                    156:        rsock_done
                    157: };
                    158:
                    159: void
                    160: wsock_done(struct aproc *p)
                    161: {
                    162:        struct sock *f = (struct sock *)p->u.io.file;
                    163:
1.11      ratchov   164:        if (f == NULL)
                    165:                return;
1.1       ratchov   166:        sock_reset(f);
                    167:        f->pipe.file.wproc = NULL;
                    168:        if (f->pipe.file.rproc) {
1.34    ! ratchov   169:                if (f->slot >= 0)
1.24      ratchov   170:                        ctl_slotdel(dev_midi, f->slot);
1.1       ratchov   171:                aproc_del(f->pipe.file.rproc);
                    172:                file_del(&f->pipe.file);
                    173:        }
1.11      ratchov   174:        p->u.io.file = NULL;
1.1       ratchov   175: }
                    176:
                    177: int
                    178: wsock_in(struct aproc *p, struct abuf *ibuf)
                    179: {
                    180:        struct sock *f = (struct sock *)p->u.io.file;
                    181:
1.19      ratchov   182:        if (f->pipe.file.state & FILE_WINUSE)
1.1       ratchov   183:                return 0;
                    184:        /*
1.20      ratchov   185:         * See remark in rsock_out().
1.1       ratchov   186:         */
                    187:        for (;;) {
                    188:                if (!sock_write(f))
                    189:                        return 0;
                    190:        }
                    191:        return 1;
                    192: }
                    193:
                    194: int
                    195: wsock_out(struct aproc *p, struct abuf *obuf_dummy)
                    196: {
                    197:        struct abuf *ibuf = LIST_FIRST(&p->ibuflist);
                    198:        struct sock *f = (struct sock *)p->u.io.file;
                    199:
                    200:        if (ibuf) {
                    201:                if (!abuf_fill(ibuf))
                    202:                        return 0;
                    203:        }
                    204:        if (!sock_write(f))
                    205:                return 0;
                    206:        return 1;
                    207: }
                    208:
                    209: void
                    210: wsock_eof(struct aproc *p, struct abuf *obuf)
                    211: {
                    212:        aproc_del(p);
                    213: }
                    214:
                    215: void
                    216: wsock_hup(struct aproc *p, struct abuf *obuf_dummy)
                    217: {
                    218:        aproc_del(p);
                    219: }
                    220:
                    221: void
                    222: wsock_ipos(struct aproc *p, struct abuf *obuf, int delta)
                    223: {
                    224:        struct sock *f = (struct sock *)p->u.io.file;
                    225:
1.14      ratchov   226:        if (!(f->mode & AMSG_REC))
                    227:                return;
1.1       ratchov   228:
1.14      ratchov   229:        f->delta += delta;
1.33      ratchov   230:        f->tickpending++;
1.1       ratchov   231:        for (;;) {
                    232:                if (!sock_write(f))
                    233:                        break;
                    234:        }
                    235: }
                    236:
                    237: struct aproc_ops wsock_ops = {
                    238:        "wsock",
                    239:        wsock_in,
                    240:        wsock_out,
                    241:        wsock_eof,
                    242:        wsock_hup,
                    243:        NULL, /* newin */
                    244:        NULL, /* newout */
                    245:        wsock_ipos,
                    246:        NULL, /* opos */
                    247:        wsock_done
                    248: };
                    249:
                    250: /*
1.20      ratchov   251:  * Initialise socket in the SOCK_HELLO state with default
                    252:  * parameters.
1.1       ratchov   253:  */
                    254: struct sock *
1.19      ratchov   255: sock_new(struct fileops *ops, int fd)
1.1       ratchov   256: {
                    257:        struct aproc *rproc, *wproc;
                    258:        struct sock *f;
                    259:
1.19      ratchov   260:        f = (struct sock *)pipe_new(ops, fd, "sock");
1.13      ratchov   261:        if (f == NULL)
                    262:                return NULL;
1.18      ratchov   263:        f->pstate = SOCK_HELLO;
1.1       ratchov   264:        f->mode = 0;
1.19      ratchov   265:        f->opt = opt_byname("default");
                    266:        if (f->opt) {
1.31      ratchov   267:                if (dev_sub)
1.19      ratchov   268:                        f->wpar = f->opt->wpar;
1.31      ratchov   269:                if (dev_mix)
1.19      ratchov   270:                        f->rpar = f->opt->rpar;
1.1       ratchov   271:        }
                    272:        f->xrun = AMSG_IGNORE;
1.10      ratchov   273:        f->bufsz = dev_bufsz;
1.1       ratchov   274:        f->round = dev_round;
1.14      ratchov   275:        f->delta = 0;
                    276:        f->tickpending = 0;
1.25      ratchov   277:        f->vol = f->lastvol = MIDI_MAXCTL;
1.24      ratchov   278:        f->slot = -1;
1.1       ratchov   279:
1.19      ratchov   280:        wproc = aproc_new(&wsock_ops, f->pipe.file.name);
1.1       ratchov   281:        wproc->u.io.file = &f->pipe.file;
                    282:        f->pipe.file.wproc = wproc;
                    283:        f->wstate = SOCK_WIDLE;
                    284:        f->wtodo = 0xdeadbeef;
                    285:
1.19      ratchov   286:        rproc = aproc_new(&rsock_ops, f->pipe.file.name);
1.1       ratchov   287:        rproc->u.io.file = &f->pipe.file;
                    288:        f->pipe.file.rproc = rproc;
                    289:        f->rstate = SOCK_RMSG;
                    290:        f->rtodo = sizeof(struct amsg);
                    291:        return f;
                    292: }
                    293:
                    294: /*
1.20      ratchov   295:  * Free buffers.
1.1       ratchov   296:  */
                    297: void
                    298: sock_freebuf(struct sock *f)
                    299: {
                    300:        struct abuf *rbuf, *wbuf;
1.12      ratchov   301:
1.1       ratchov   302:        f->pstate = SOCK_INIT;
                    303:        rbuf = LIST_FIRST(&f->pipe.file.rproc->obuflist);
                    304:        if (rbuf)
                    305:                abuf_eof(rbuf);
                    306:        wbuf = LIST_FIRST(&f->pipe.file.wproc->ibuflist);
                    307:        if (wbuf)
                    308:                abuf_hup(wbuf);
1.32      ratchov   309:        f->tickpending = 0;
1.1       ratchov   310: }
                    311:
                    312: /*
1.20      ratchov   313:  * Allocate buffers, so client can start filling write-end.
1.1       ratchov   314:  */
                    315: void
                    316: sock_allocbuf(struct sock *f)
                    317: {
                    318:        struct abuf *rbuf = NULL, *wbuf = NULL;
                    319:
                    320:        if (f->mode & AMSG_PLAY) {
1.10      ratchov   321:                rbuf = abuf_new(f->bufsz, &f->rpar);
1.1       ratchov   322:                aproc_setout(f->pipe.file.rproc, rbuf);
                    323:        }
                    324:        if (f->mode & AMSG_REC) {
1.10      ratchov   325:                wbuf = abuf_new(f->bufsz, &f->wpar);
1.1       ratchov   326:                aproc_setin(f->pipe.file.wproc, wbuf);
                    327:        }
1.14      ratchov   328:        f->delta = 0;
                    329:        f->tickpending = 0;
1.1       ratchov   330:        f->pstate = SOCK_START;
                    331:        if (!(f->mode & AMSG_PLAY))
                    332:                (void)sock_attach(f, 0);
                    333: }
                    334:
                    335: /*
1.25      ratchov   336:  * Set volume. Callback invoked when volume is modified externally
1.3       ratchov   337:  */
                    338: void
1.25      ratchov   339: sock_setvol(void *arg, unsigned vol)
1.3       ratchov   340: {
1.25      ratchov   341:        struct sock *f = (struct sock *)arg;
1.3       ratchov   342:        struct abuf *rbuf;
1.12      ratchov   343:
1.3       ratchov   344:        f->vol = vol;
1.12      ratchov   345:        rbuf = LIST_FIRST(&f->pipe.file.rproc->obuflist);
1.3       ratchov   346:        if (!rbuf) {
                    347:                return;
                    348:        }
1.25      ratchov   349:        dev_setvol(rbuf, MIDI_TO_ADATA(vol));
1.3       ratchov   350: }
                    351:
                    352: /*
1.20      ratchov   353:  * Attach play and/or record buffers to dev_mix and/or dev_sub.
1.1       ratchov   354:  */
                    355: int
                    356: sock_attach(struct sock *f, int force)
                    357: {
                    358:        struct abuf *rbuf, *wbuf;
                    359:
                    360:        rbuf = LIST_FIRST(&f->pipe.file.rproc->obuflist);
                    361:        wbuf = LIST_FIRST(&f->pipe.file.wproc->ibuflist);
                    362:
                    363:        /*
1.20      ratchov   364:         * If in SOCK_START state, dont attach until
                    365:         * the buffer isn't completely filled.
1.1       ratchov   366:         */
                    367:        if (!force && rbuf && ABUF_WOK(rbuf))
                    368:                return 0;
1.12      ratchov   369:
1.1       ratchov   370:        f->pstate = SOCK_RUN;
                    371:
                    372:        /*
1.20      ratchov   373:         * Attach them to the device.
1.1       ratchov   374:         */
                    375:        dev_attach(f->pipe.file.name,
                    376:            (f->mode & AMSG_PLAY) ? rbuf : NULL, &f->rpar, f->xrun,
1.4       ratchov   377:            (f->mode & AMSG_REC)  ? wbuf : NULL, &f->wpar, f->xrun,
1.19      ratchov   378:            f->opt->maxweight);
1.3       ratchov   379:        if (f->mode & AMSG_PLAY)
1.25      ratchov   380:                dev_setvol(rbuf, MIDI_TO_ADATA(f->vol));
1.3       ratchov   381:
1.1       ratchov   382:        /*
1.20      ratchov   383:         * Send the initial position, if needed.
1.1       ratchov   384:         */
                    385:        for (;;) {
                    386:                if (!sock_write(f))
                    387:                        break;
                    388:        }
                    389:        return 1;
                    390: }
                    391:
                    392: void
                    393: sock_reset(struct sock *f)
                    394: {
                    395:        switch (f->pstate) {
                    396:        case SOCK_START:
                    397:                (void)sock_attach(f, 1);
                    398:                f->pstate = SOCK_RUN;
                    399:                /* PASSTHROUGH */
                    400:        case SOCK_RUN:
                    401:                sock_freebuf(f);
                    402:                f->pstate = SOCK_INIT;
                    403:                /* PASSTHROUGH */
                    404:        case SOCK_INIT:
                    405:                /* nothing yet */
                    406:                break;
                    407:        }
                    408: }
                    409:
                    410: /*
1.20      ratchov   411:  * Read a message from the file descriptor, return 1 if done, 0
                    412:  * otherwise. The message is stored in f->rmsg.
1.1       ratchov   413:  */
                    414: int
                    415: sock_rmsg(struct sock *f)
                    416: {
                    417:        unsigned count;
                    418:        unsigned char *data;
                    419:
                    420:        while (f->rtodo > 0) {
                    421:                if (!(f->pipe.file.state & FILE_ROK)) {
                    422:                        return 0;
                    423:                }
                    424:                data = (unsigned char *)&f->rmsg;
                    425:                data += sizeof(struct amsg) - f->rtodo;
                    426:                count = file_read(&f->pipe.file, data, f->rtodo);
                    427:                if (count == 0)
                    428:                        return 0;
                    429:                f->rtodo -= count;
                    430:        }
                    431:        return 1;
                    432: }
                    433:
                    434: /*
1.20      ratchov   435:  * Write a message to the file descriptor, return 1 if done, 0
1.1       ratchov   436:  * otherwise.  The "m" argument is f->rmsg or f->wmsg, and the "ptodo"
                    437:  * points to the f->rtodo or f->wtodo respectively.
                    438:  */
                    439: int
                    440: sock_wmsg(struct sock *f, struct amsg *m, unsigned *ptodo)
                    441: {
                    442:        unsigned count;
                    443:        unsigned char *data;
                    444:
                    445:        while (*ptodo > 0) {
                    446:                if (!(f->pipe.file.state & FILE_WOK)) {
                    447:                        return 0;
                    448:                }
                    449:                data = (unsigned char *)m;
                    450:                data += sizeof(struct amsg) - *ptodo;
                    451:                count = file_write(&f->pipe.file, data, *ptodo);
                    452:                if (count == 0)
                    453:                        return 0;
                    454:                *ptodo -= count;
                    455:        }
                    456:        return 1;
                    457: }
                    458:
                    459: /*
1.20      ratchov   460:  * Read data chunk from the file descriptor, return 1 if at least one
1.1       ratchov   461:  * byte was read, 0 if the file blocked.
                    462:  */
                    463: int
                    464: sock_rdata(struct sock *f)
                    465: {
                    466:        struct aproc *p;
                    467:        struct abuf *obuf;
                    468:        unsigned char *data;
                    469:        unsigned count, n;
                    470:
                    471:        p = f->pipe.file.rproc;
                    472:        obuf = LIST_FIRST(&p->obuflist);
1.19      ratchov   473:        if (obuf == NULL)
                    474:                return 0;
1.1       ratchov   475:        if (ABUF_FULL(obuf) || !(f->pipe.file.state & FILE_ROK))
                    476:                return 0;
                    477:        data = abuf_wgetblk(obuf, &count, 0);
1.19      ratchov   478:        if (f->pstate != SOCK_MIDI && count > f->rtodo)
1.1       ratchov   479:                count = f->rtodo;
                    480:        n = file_read(&f->pipe.file, data, count);
                    481:        if (n == 0)
                    482:                return 0;
                    483:        abuf_wcommit(obuf, n);
1.19      ratchov   484:        if (f->pstate != SOCK_MIDI)
                    485:                f->rtodo -= n;
1.1       ratchov   486:        return 1;
                    487: }
                    488:
                    489: /*
1.20      ratchov   490:  * Write data chunk to the file descriptor, return 1 if at least one
1.1       ratchov   491:  * byte was written, 0 if the file blocked.
                    492:  */
                    493: int
                    494: sock_wdata(struct sock *f)
                    495: {
                    496:        struct aproc *p;
                    497:        struct abuf *ibuf;
                    498:        unsigned char *data;
                    499:        unsigned count, n;
                    500: #define ZERO_MAX 0x1000
                    501:        static char zero[ZERO_MAX];
                    502:
                    503:        if (!(f->pipe.file.state & FILE_WOK))
                    504:                return 0;
                    505:        p = f->pipe.file.wproc;
                    506:        ibuf = LIST_FIRST(&p->ibuflist);
                    507:        if (ibuf) {
                    508:                if (ABUF_EMPTY(ibuf))
                    509:                        return 0;
                    510:                data = abuf_rgetblk(ibuf, &count, 0);
1.19      ratchov   511:                if (f->pstate != SOCK_MIDI && count > f->wtodo)
1.1       ratchov   512:                        count = f->wtodo;
                    513:                n = file_write(&f->pipe.file, data, count);
                    514:                if (n == 0)
                    515:                        return 0;
                    516:                abuf_rdiscard(ibuf, n);
1.19      ratchov   517:                if (f->pstate != SOCK_MIDI)
                    518:                        f->wtodo -= n;
1.1       ratchov   519:        } else {
1.19      ratchov   520:                if (f->pstate == SOCK_MIDI)
                    521:                        return 0;
1.1       ratchov   522:                /*
1.20      ratchov   523:                 * There's no dev_detach() routine yet,
1.1       ratchov   524:                 * so now we abruptly destroy the buffer.
                    525:                 * Until we implement dev_detach, complete
                    526:                 * the packet with zeros...
                    527:                 */
                    528:                count = ZERO_MAX;
                    529:                if (count > f->wtodo)
                    530:                        count = f->wtodo;
                    531:                n = file_write(&f->pipe.file, zero, count);
                    532:                if (n == 0)
                    533:                        return 0;
                    534:                f->wtodo -= n;
1.12      ratchov   535:        }
1.1       ratchov   536:        return 1;
                    537: }
                    538:
                    539: int
                    540: sock_setpar(struct sock *f)
                    541: {
                    542:        struct amsg_par *p = &f->rmsg.u.par;
1.9       ratchov   543:        unsigned min, max, rate;
1.12      ratchov   544:
1.1       ratchov   545:        if (AMSG_ISSET(p->bits)) {
                    546:                if (p->bits < BITS_MIN || p->bits > BITS_MAX) {
                    547:                        return 0;
                    548:                }
                    549:                if (AMSG_ISSET(p->bps)) {
                    550:                        if (p->bps < ((p->bits + 7) / 8) || p->bps > 4) {
                    551:                                return 0;
                    552:                        }
                    553:                } else
                    554:                        p->bps = APARAMS_BPS(p->bits);
                    555:                f->rpar.bits = f->wpar.bits = p->bits;
                    556:                f->rpar.bps = f->wpar.bps = p->bps;
                    557:        }
                    558:        if (AMSG_ISSET(p->sig))
                    559:                f->rpar.sig = f->wpar.sig = p->sig ? 1 : 0;
                    560:        if (AMSG_ISSET(p->le))
                    561:                f->rpar.le = f->wpar.le = p->le ? 1 : 0;
                    562:        if (AMSG_ISSET(p->msb))
                    563:                f->rpar.msb = f->wpar.msb = p->msb ? 1 : 0;
                    564:        if (AMSG_ISSET(p->rchan) && (f->mode & AMSG_REC)) {
                    565:                if (p->rchan < 1)
                    566:                        p->rchan = 1;
1.6       ratchov   567:                if (p->rchan > NCHAN_MAX)
                    568:                        p->rchan = NCHAN_MAX;
1.19      ratchov   569:                f->wpar.cmin = f->opt->wpar.cmin;
                    570:                f->wpar.cmax = f->opt->wpar.cmin + p->rchan - 1;
                    571:                if (f->wpar.cmax > f->opt->wpar.cmax)
                    572:                        f->wpar.cmax = f->opt->wpar.cmax;
1.1       ratchov   573:        }
                    574:        if (AMSG_ISSET(p->pchan) && (f->mode & AMSG_PLAY)) {
                    575:                if (p->pchan < 1)
                    576:                        p->pchan = 1;
1.6       ratchov   577:                if (p->pchan > NCHAN_MAX)
                    578:                        p->pchan = NCHAN_MAX;
1.19      ratchov   579:                f->rpar.cmin = f->opt->rpar.cmin;
                    580:                f->rpar.cmax = f->opt->rpar.cmin + p->pchan - 1;
                    581:                if (f->rpar.cmax > f->opt->rpar.cmax)
                    582:                        f->rpar.cmax = f->opt->rpar.cmax;
1.1       ratchov   583:        }
                    584:        if (AMSG_ISSET(p->rate)) {
                    585:                if (p->rate < RATE_MIN)
                    586:                        p->rate = RATE_MIN;
                    587:                if (p->rate > RATE_MAX)
                    588:                        p->rate = RATE_MAX;
1.9       ratchov   589:                f->round = dev_roundof(p->rate);
1.1       ratchov   590:                f->rpar.rate = f->wpar.rate = p->rate;
1.10      ratchov   591:                if (!AMSG_ISSET(p->appbufsz)) {
                    592:                        p->appbufsz = dev_bufsz / dev_round * f->round;
                    593:                }
1.1       ratchov   594:        }
                    595:        if (AMSG_ISSET(p->xrun)) {
                    596:                if (p->xrun != AMSG_IGNORE &&
                    597:                    p->xrun != AMSG_SYNC &&
                    598:                    p->xrun != AMSG_ERROR) {
                    599:                        return 0;
                    600:                }
                    601:                f->xrun = p->xrun;
                    602:        }
                    603:        if (AMSG_ISSET(p->bufsz)) {
1.10      ratchov   604:                /*
                    605:                 * XXX: bufsz will become read-only, but for now
                    606:                 *      allow old library to properly work
                    607:                 */
                    608:                min = (dev_bufsz / dev_round) * f->round;
                    609:                if (p->bufsz < min)
                    610:                        p->bufsz = min;
                    611:                p->appbufsz = p->bufsz - min;
                    612:        }
                    613:        if (AMSG_ISSET(p->appbufsz)) {
1.9       ratchov   614:                rate = (f->mode & AMSG_PLAY) ? f->rpar.rate : f->wpar.rate;
1.10      ratchov   615:                min = 1;
                    616:                max = 1 + rate / dev_round;
1.9       ratchov   617:                min *= f->round;
                    618:                max *= f->round;
1.10      ratchov   619:                p->appbufsz += f->round - 1;
                    620:                p->appbufsz -= p->appbufsz % f->round;
                    621:                if (p->appbufsz < min)
                    622:                        p->appbufsz = min;
                    623:                if (p->appbufsz > max)
                    624:                        p->appbufsz = max;
                    625:                f->bufsz = p->appbufsz;
1.1       ratchov   626:        }
                    627:        return 1;
                    628: }
                    629:
1.19      ratchov   630: /*
                    631:  * allocate buffers, so client can start filling write-end.
                    632:  */
                    633: void
                    634: sock_midiattach(struct sock *f, unsigned mode)
                    635: {
                    636:        struct abuf *rbuf = NULL, *wbuf = NULL;
                    637:
                    638:        if (mode & AMSG_MIDIOUT) {
1.22      ratchov   639:                rbuf = abuf_new(MIDI_BUFSZ, &aparams_none);
1.19      ratchov   640:                aproc_setout(f->pipe.file.rproc, rbuf);
                    641:        }
                    642:        if (mode & AMSG_MIDIIN) {
1.22      ratchov   643:                wbuf = abuf_new(MIDI_BUFSZ, &aparams_none);
1.19      ratchov   644:                aproc_setin(f->pipe.file.wproc, wbuf);
                    645:        }
1.23      ratchov   646:        dev_midiattach(rbuf, wbuf);
1.19      ratchov   647: }
                    648:
1.17      ratchov   649: int
                    650: sock_hello(struct sock *f)
                    651: {
                    652:        struct amsg_hello *p = &f->rmsg.u.hello;
                    653:
1.33      ratchov   654:        if (p->version != AMSG_VERSION) {
                    655:                return 0;
                    656:        }
                    657:        /*
                    658:         * XXX : dev_midi can no longer be NULL, right ?
                    659:         */
1.23      ratchov   660:        if (dev_midi && (p->proto & (AMSG_MIDIIN | AMSG_MIDIOUT))) {
1.19      ratchov   661:                if (p->proto & ~(AMSG_MIDIIN | AMSG_MIDIOUT)) {
                    662:                        return 0;
                    663:                }
                    664:                f->mode = p->proto;
                    665:                f->pstate = SOCK_MIDI;
                    666:                sock_midiattach(f, p->proto);
                    667:                return 1;
                    668:        }
                    669:        f->opt = opt_byname(p->opt);
                    670:        if (f->opt == NULL)
                    671:                return 0;
1.31      ratchov   672:        if (dev_sub)
1.19      ratchov   673:                f->wpar = f->opt->wpar;
1.31      ratchov   674:        if (dev_mix)
1.19      ratchov   675:                f->rpar = f->opt->rpar;
1.18      ratchov   676:        if ((p->proto & ~(AMSG_PLAY | AMSG_REC)) != 0 ||
                    677:            (p->proto &  (AMSG_PLAY | AMSG_REC)) == 0) {
1.17      ratchov   678:                return 0;
                    679:        }
1.18      ratchov   680:        f->mode = 0;
                    681:        if (p->proto & AMSG_PLAY) {
                    682:                if (!dev_mix) {
                    683:                        return 0;
                    684:                }
                    685:                f->mode |= AMSG_PLAY;
1.17      ratchov   686:        }
1.18      ratchov   687:        if (p->proto & AMSG_REC) {
                    688:                if (!dev_sub) {
                    689:                        return 0;
                    690:                }
                    691:                f->mode |= AMSG_REC;
1.17      ratchov   692:        }
1.24      ratchov   693:        if (dev_midi) {
1.34    ! ratchov   694:                f->slot = ctl_slotnew(dev_midi, p->who, &ctl_sockops, f);
1.24      ratchov   695:                if (f->slot < 0) {
                    696:                        return 0;
                    697:                }
                    698:        }
1.18      ratchov   699:        f->pstate = SOCK_INIT;
1.17      ratchov   700:        return 1;
                    701: }
                    702:
1.1       ratchov   703: /*
1.20      ratchov   704:  * Execute message in f->rmsg and change the state accordingly; return 1
1.1       ratchov   705:  * on success, and 0 on failure, in which case the socket is destroyed.
                    706:  */
                    707: int
                    708: sock_execmsg(struct sock *f)
                    709: {
                    710:        struct amsg *m = &f->rmsg;
                    711:
                    712:        switch (m->cmd) {
                    713:        case AMSG_DATA:
                    714:                if (f->pstate != SOCK_RUN && f->pstate != SOCK_START) {
1.8       ratchov   715:                        aproc_del(f->pipe.file.rproc);
                    716:                        return 0;
                    717:                }
                    718:                if (!(f->mode & AMSG_PLAY)) {
1.1       ratchov   719:                        aproc_del(f->pipe.file.rproc);
                    720:                        return 0;
                    721:                }
1.34    ! ratchov   722:                if (f->pstate == SOCK_START &&
        !           723:                    ABUF_FULL(LIST_FIRST(&f->pipe.file.rproc->obuflist))) {
        !           724:                        aproc_del(f->pipe.file.rproc);
        !           725:                        return 0;
        !           726:                }
1.1       ratchov   727:                f->rstate = SOCK_RDATA;
                    728:                f->rtodo = m->u.data.size;
                    729:                if (f->rtodo == 0) {
                    730:                        aproc_del(f->pipe.file.rproc);
                    731:                        return 0;
                    732:                }
                    733:                break;
                    734:        case AMSG_START:
                    735:                if (f->pstate != SOCK_INIT) {
                    736:                        aproc_del(f->pipe.file.rproc);
                    737:                        return 0;
                    738:                }
                    739:                sock_allocbuf(f);
                    740:                f->rstate = SOCK_RMSG;
                    741:                f->rtodo = sizeof(struct amsg);
                    742:                break;
                    743:        case AMSG_STOP:
                    744:                if (f->pstate != SOCK_RUN && f->pstate != SOCK_START) {
                    745:                        aproc_del(f->pipe.file.rproc);
                    746:                        return 0;
                    747:                }
                    748:                if (f->pstate == SOCK_START)
                    749:                        (void)sock_attach(f, 1);
                    750:                sock_freebuf(f);
                    751:                AMSG_INIT(m);
                    752:                m->cmd = AMSG_ACK;
                    753:                f->rstate = SOCK_RRET;
                    754:                f->rtodo = sizeof(struct amsg);
                    755:                break;
                    756:        case AMSG_SETPAR:
                    757:                if (f->pstate != SOCK_INIT) {
                    758:                        aproc_del(f->pipe.file.rproc);
                    759:                        return 0;
                    760:                }
                    761:                if (!sock_setpar(f)) {
                    762:                        aproc_del(f->pipe.file.rproc);
                    763:                        return 0;
                    764:                }
                    765:                f->rtodo = sizeof(struct amsg);
                    766:                f->rstate = SOCK_RMSG;
                    767:                break;
                    768:        case AMSG_GETPAR:
                    769:                if (f->pstate != SOCK_INIT) {
                    770:                        aproc_del(f->pipe.file.rproc);
                    771:                        return 0;
                    772:                }
                    773:                AMSG_INIT(m);
                    774:                m->cmd = AMSG_GETPAR;
1.18      ratchov   775:                m->u.par.legacy_mode = f->mode;
1.1       ratchov   776:                m->u.par.bits = f->rpar.bits;
                    777:                m->u.par.bps = f->rpar.bps;
                    778:                m->u.par.sig = f->rpar.sig;
                    779:                m->u.par.le = f->rpar.le;
                    780:                m->u.par.msb = f->rpar.msb;
                    781:                m->u.par.rate = f->rpar.rate;
                    782:                m->u.par.rchan = f->wpar.cmax - f->wpar.cmin + 1;
                    783:                m->u.par.pchan = f->rpar.cmax - f->rpar.cmin + 1;
1.10      ratchov   784:                m->u.par.appbufsz = f->bufsz;
1.12      ratchov   785:                m->u.par.bufsz =
1.10      ratchov   786:                    f->bufsz + (dev_bufsz / dev_round) * f->round;
1.1       ratchov   787:                m->u.par.round = f->round;
                    788:                f->rstate = SOCK_RRET;
                    789:                f->rtodo = sizeof(struct amsg);
                    790:                break;
                    791:        case AMSG_GETCAP:
                    792:                if (f->pstate != SOCK_INIT) {
                    793:                        aproc_del(f->pipe.file.rproc);
                    794:                        return 0;
                    795:                }
                    796:                AMSG_INIT(m);
                    797:                m->cmd = AMSG_GETCAP;
                    798:                m->u.cap.rate = dev_rate;
1.6       ratchov   799:                m->u.cap.pchan = dev_mix ?
1.19      ratchov   800:                    (f->opt->rpar.cmax - f->opt->rpar.cmin + 1) : 0;
1.6       ratchov   801:                m->u.cap.rchan = dev_sub ?
1.19      ratchov   802:                    (f->opt->wpar.cmax - f->opt->wpar.cmin + 1) : 0;
1.1       ratchov   803:                m->u.cap.bits = sizeof(short) * 8;
                    804:                m->u.cap.bps = sizeof(short);
                    805:                f->rstate = SOCK_RRET;
                    806:                f->rtodo = sizeof(struct amsg);
1.3       ratchov   807:                break;
                    808:        case AMSG_SETVOL:
                    809:                if (f->pstate != SOCK_RUN &&
                    810:                    f->pstate != SOCK_START && f->pstate != SOCK_INIT) {
                    811:                        aproc_del(f->pipe.file.rproc);
                    812:                        return 0;
                    813:                }
                    814:                if (m->u.vol.ctl > MIDI_MAXCTL) {
                    815:                        aproc_del(f->pipe.file.rproc);
                    816:                        return 0;
                    817:                }
1.25      ratchov   818:                sock_setvol(f, m->u.vol.ctl);
1.34    ! ratchov   819:                if (f->slot >= 0)
1.24      ratchov   820:                        ctl_slotvol(dev_midi, f->slot, m->u.vol.ctl);
1.3       ratchov   821:                f->rtodo = sizeof(struct amsg);
                    822:                f->rstate = SOCK_RMSG;
1.17      ratchov   823:                break;
                    824:        case AMSG_HELLO:
1.18      ratchov   825:                if (f->pstate != SOCK_HELLO) {
1.17      ratchov   826:                        aproc_del(f->pipe.file.rproc);
                    827:                        return 0;
                    828:                }
                    829:                if (!sock_hello(f)) {
                    830:                        aproc_del(f->pipe.file.rproc);
                    831:                        return 0;
                    832:                }
                    833:                AMSG_INIT(m);
                    834:                m->cmd = AMSG_ACK;
                    835:                f->rstate = SOCK_RRET;
                    836:                f->rtodo = sizeof(struct amsg);
1.1       ratchov   837:                break;
1.28      ratchov   838:        case AMSG_BYE:
1.29      ratchov   839:                if (f->pstate != SOCK_INIT) {
                    840:                }
1.28      ratchov   841:                aproc_del(f->pipe.file.rproc);
                    842:                return 0;
1.1       ratchov   843:        default:
                    844:                aproc_del(f->pipe.file.rproc);
                    845:                return 0;
                    846:        }
                    847:        if (f->rstate == SOCK_RRET) {
                    848:                if (f->wstate != SOCK_WIDLE ||
                    849:                    !sock_wmsg(f, &f->rmsg, &f->rtodo))
                    850:                        return 0;
1.19      ratchov   851:                if (f->pstate == SOCK_MIDI && (f->mode & AMSG_MIDIOUT)) {
                    852:                        f->rstate = SOCK_RDATA;
                    853:                        f->rtodo = 0;
                    854:                } else {
                    855:                        f->rstate = SOCK_RMSG;
                    856:                        f->rtodo = sizeof(struct amsg);
                    857:                }
1.1       ratchov   858:        }
                    859:        return 1;
                    860: }
                    861:
                    862: /*
1.20      ratchov   863:  * Create a new data/pos message.
1.1       ratchov   864:  */
                    865: int
                    866: sock_buildmsg(struct sock *f)
                    867: {
                    868:        struct aproc *p;
                    869:        struct abuf *ibuf;
1.12      ratchov   870:
1.19      ratchov   871:        if (f->pstate == SOCK_MIDI) {
                    872:                f->wstate = SOCK_WDATA;
                    873:                f->wtodo = 0;
                    874:                return 1;
                    875:        }
                    876:
1.1       ratchov   877:        /*
1.20      ratchov   878:         * If pos changed, build a MOVE message.
1.1       ratchov   879:         */
1.33      ratchov   880:        if (f->tickpending) {
1.1       ratchov   881:                AMSG_INIT(&f->wmsg);
                    882:                f->wmsg.cmd = AMSG_MOVE;
1.14      ratchov   883:                f->wmsg.u.ts.delta = f->delta;
1.1       ratchov   884:                f->wtodo = sizeof(struct amsg);
                    885:                f->wstate = SOCK_WMSG;
1.14      ratchov   886:                f->delta = 0;
                    887:                f->tickpending = 0;
1.25      ratchov   888:                return 1;
                    889:        }
                    890:
                    891:        /*
                    892:         * if volume changed build a SETVOL message
                    893:         */
1.27      ratchov   894:        if (f->pstate >= SOCK_START && f->vol != f->lastvol) {
1.25      ratchov   895:                AMSG_INIT(&f->wmsg);
                    896:                f->wmsg.cmd = AMSG_SETVOL;
                    897:                f->wmsg.u.vol.ctl = f->vol;
                    898:                f->wtodo = sizeof(struct amsg);
                    899:                f->wstate = SOCK_WMSG;
                    900:                f->lastvol = f->vol;
1.1       ratchov   901:                return 1;
                    902:        }
                    903:
                    904:        /*
1.20      ratchov   905:         * If data available, build a DATA message.
1.1       ratchov   906:         */
                    907:        p = f->pipe.file.wproc;
                    908:        ibuf = LIST_FIRST(&p->ibuflist);
                    909:        if (ibuf && ABUF_ROK(ibuf)) {
                    910:                AMSG_INIT(&f->wmsg);
                    911:                f->wmsg.cmd = AMSG_DATA;
                    912:                f->wmsg.u.data.size = ibuf->used - (ibuf->used % ibuf->bpf);
                    913:                if (f->wmsg.u.data.size > AMSG_DATAMAX)
                    914:                        f->wmsg.u.data.size =
                    915:                            AMSG_DATAMAX - (AMSG_DATAMAX % ibuf->bpf);
                    916:                f->wtodo = sizeof(struct amsg);
                    917:                f->wstate = SOCK_WMSG;
                    918:                return 1;
                    919:        }
                    920:        f->wstate = SOCK_WIDLE;
                    921:        return 0;
                    922: }
                    923:
                    924: /*
1.20      ratchov   925:  * Read from the socket file descriptor, fill input buffer and update
1.1       ratchov   926:  * the state. Return 1 if at least one message or 1 data byte was
                    927:  * processed, 0 if something blocked.
                    928:  */
                    929: int
                    930: sock_read(struct sock *f)
                    931: {
                    932:        switch (f->rstate) {
                    933:        case SOCK_RMSG:
                    934:                if (!sock_rmsg(f))
                    935:                        return 0;
                    936:                if (!sock_execmsg(f))
                    937:                        return 0;
                    938:                break;
                    939:        case SOCK_RDATA:
                    940:                if (!sock_rdata(f))
                    941:                        return 0;
1.19      ratchov   942:                if (f->pstate != SOCK_MIDI && f->rtodo == 0) {
1.1       ratchov   943:                        f->rstate = SOCK_RMSG;
                    944:                        f->rtodo = sizeof(struct amsg);
                    945:                }
                    946:                if (f->pstate == SOCK_START)
                    947:                        (void)sock_attach(f, 0);
                    948:                break;
                    949:        case SOCK_RRET:
                    950:                return 0;
                    951:        }
                    952:        return 1;
                    953: }
                    954:
                    955: /*
1.20      ratchov   956:  * Process messages to return.
1.1       ratchov   957:  */
                    958: int
                    959: sock_return(struct sock *f)
                    960: {
                    961:        struct aproc *rp;
                    962:
                    963:        while (f->rstate == SOCK_RRET) {
                    964:                if (!sock_wmsg(f, &f->rmsg, &f->rtodo))
                    965:                        return 0;
1.19      ratchov   966:                if (f->pstate == SOCK_MIDI && (f->mode & AMSG_MIDIOUT)) {
                    967:                        f->rstate = SOCK_RDATA;
                    968:                        f->rtodo = 0;
                    969:                } else {
                    970:                        f->rstate = SOCK_RMSG;
                    971:                        f->rtodo = sizeof(struct amsg);
                    972:                }
                    973:                if (f->pipe.file.state & FILE_RINUSE)
                    974:                        break;
                    975:                f->pipe.file.state |= FILE_RINUSE;
1.1       ratchov   976:                for (;;) {
                    977:                        /*
                    978:                         * in() may trigger rsock_done and destroy the
1.20      ratchov   979:                         * wsock.
1.1       ratchov   980:                         */
                    981:                        rp = f->pipe.file.rproc;
                    982:                        if (!rp || !rp->ops->in(rp, NULL))
                    983:                                break;
                    984:                }
1.19      ratchov   985:                f->pipe.file.state &= ~FILE_RINUSE;
1.1       ratchov   986:                if (f->pipe.file.wproc == NULL)
                    987:                        return 0;
                    988:        }
                    989:        return 1;
                    990: }
                    991:
                    992: /*
1.20      ratchov   993:  * Write messages and data on the socket file descriptor. Return 1 if
1.1       ratchov   994:  * at least one message or one data byte was processed, 0 if something
                    995:  * blocked.
                    996:  */
                    997: int
                    998: sock_write(struct sock *f)
                    999: {
                   1000:        switch (f->wstate) {
                   1001:        case SOCK_WMSG:
                   1002:                if (!sock_wmsg(f, &f->wmsg, &f->wtodo))
                   1003:                        return 0;
                   1004:                if (f->wmsg.cmd != AMSG_DATA) {
                   1005:                        f->wstate = SOCK_WIDLE;
                   1006:                        f->wtodo = 0xdeadbeef;
                   1007:                        break;
                   1008:                }
                   1009:                f->wstate = SOCK_WDATA;
                   1010:                f->wtodo = f->wmsg.u.data.size;
                   1011:                /* PASSTHROUGH */
                   1012:        case SOCK_WDATA:
                   1013:                if (!sock_wdata(f))
                   1014:                        return 0;
1.19      ratchov  1015:                if (f->pstate == SOCK_MIDI || f->wtodo > 0)
1.1       ratchov  1016:                        break;
                   1017:                f->wstate = SOCK_WIDLE;
                   1018:                f->wtodo = 0xdeadbeef;
                   1019:                /* PASSTHROUGH */
                   1020:        case SOCK_WIDLE:
                   1021:                if (!sock_return(f))
                   1022:                        return 0;
                   1023:                if (!sock_buildmsg(f))
                   1024:                        return 0;
                   1025:                break;
                   1026:        }
                   1027:        return 1;
                   1028: }