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

Annotation of src/usr.bin/sndiod/siofile.c, Revision 1.3

1.3     ! ratchov     1: /*     $OpenBSD: siofile.c,v 1.2 2013/02/01 09:06:27 ratchov Exp $     */
1.1       ratchov     2: /*
                      3:  * Copyright (c) 2008-2012 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: #include <sys/time.h>
                     18: #include <sys/types.h>
                     19:
                     20: #include <poll.h>
                     21: #include <sndio.h>
                     22: #include <stdio.h>
                     23: #include <stdlib.h>
                     24: #include <string.h>
                     25:
                     26: #include "abuf.h"
                     27: #include "defs.h"
                     28: #include "dev.h"
                     29: #include "dsp.h"
                     30: #include "file.h"
                     31: #include "siofile.h"
                     32: #include "utils.h"
                     33:
1.2       ratchov    34: #define WATCHDOG_USEC  2000000         /* 2 seconds */
                     35:
1.3     ! ratchov    36: void dev_sio_onmove(void *, int);
        !            37: void dev_sio_timeout(void *);
1.1       ratchov    38: int dev_sio_pollfd(void *, struct pollfd *);
                     39: int dev_sio_revents(void *, struct pollfd *);
                     40: void dev_sio_run(void *);
                     41: void dev_sio_hup(void *);
                     42:
                     43: struct fileops dev_sio_ops = {
                     44:        "sio",
                     45:        dev_sio_pollfd,
                     46:        dev_sio_revents,
                     47:        dev_sio_run,
                     48:        dev_sio_run,
                     49:        dev_sio_hup
                     50: };
                     51:
                     52: void
                     53: dev_sio_onmove(void *arg, int delta)
                     54: {
                     55:        struct dev *d = arg;
                     56:
                     57: #ifdef DEBUG
                     58:        if (log_level >= 4) {
                     59:                dev_log(d);
                     60:                log_puts(": tick, delta = ");
                     61:                log_puti(delta);
                     62:                log_puts("\n");
                     63:        }
                     64:        d->sio.sum_utime += file_utime - d->sio.utime;
                     65:        d->sio.sum_wtime += file_wtime - d->sio.wtime;
                     66:        d->sio.wtime = file_wtime;
                     67:        d->sio.utime = file_utime;
                     68:        if (d->mode & MODE_PLAY)
                     69:                d->sio.pused -= delta;
                     70:        if (d->mode & MODE_REC)
                     71:                d->sio.rused += delta;
                     72: #endif
                     73:        dev_onmove(d, delta);
                     74: }
                     75:
1.2       ratchov    76: void
                     77: dev_sio_timeout(void *arg)
                     78: {
                     79:        struct dev *d = arg;
                     80:
                     81:        dev_log(d);
                     82:        log_puts(": watchdog timeout\n");
                     83:        dev_close(d);
                     84: }
                     85:
1.1       ratchov    86: /*
                     87:  * open the device.
                     88:  */
                     89: int
                     90: dev_sio_open(struct dev *d)
                     91: {
                     92:        struct sio_par par;
                     93:        unsigned int mode = d->mode & (MODE_PLAY | MODE_REC);
                     94:
                     95:        d->sio.hdl = sio_open(d->path, mode, 1);
                     96:        if (d->sio.hdl == NULL) {
                     97:                if (mode != (SIO_PLAY | SIO_REC))
                     98:                        return 0;
                     99:                d->sio.hdl = sio_open(d->path, SIO_PLAY, 1);
                    100:                if (d->sio.hdl != NULL)
                    101:                        mode = SIO_PLAY;
                    102:                else {
                    103:                        d->sio.hdl = sio_open(d->path, SIO_REC, 1);
                    104:                        if (d->sio.hdl != NULL)
                    105:                                mode = SIO_REC;
                    106:                        else
                    107:                                return 0;
                    108:                }
                    109:                if (log_level >= 1) {
                    110:                        log_puts("warning, device opened in ");
                    111:                        log_puts(mode == SIO_PLAY ? "play-only" : "rec-only");
                    112:                        log_puts(" mode\n");
                    113:                }
                    114:        }
                    115:        sio_initpar(&par);
                    116:        par.bits = d->par.bits;
                    117:        par.bps = d->par.bps;
                    118:        par.sig = d->par.sig;
                    119:        par.le = d->par.le;
                    120:        par.msb = d->par.msb;
                    121:        if (mode & SIO_PLAY)
                    122:                par.pchan = d->pchan;
                    123:        if (mode & SIO_REC)
                    124:                par.rchan = d->rchan;
                    125:        if (d->bufsz)
                    126:                par.appbufsz = d->bufsz;
                    127:        if (d->round)
                    128:                par.round = d->round;
                    129:        if (d->rate)
                    130:                par.rate = d->rate;
                    131:        if (!sio_setpar(d->sio.hdl, &par))
                    132:                goto bad_close;
                    133:        if (!sio_getpar(d->sio.hdl, &par))
                    134:                goto bad_close;
                    135:        d->par.bits = par.bits;
                    136:        d->par.bps = par.bps;
                    137:        d->par.sig = par.sig;
                    138:        d->par.le = par.le;
                    139:        d->par.msb = par.msb;
                    140:        if (mode & SIO_PLAY)
                    141:                d->pchan = par.pchan;
                    142:        if (mode & SIO_REC)
                    143:                d->rchan = par.rchan;
                    144:        d->bufsz = par.bufsz;
                    145:        d->round = par.round;
                    146:        d->rate = par.rate;
                    147:        if (!(mode & MODE_PLAY))
                    148:                d->mode &= ~(MODE_PLAY | MODE_MON);
                    149:        if (!(mode & MODE_REC))
                    150:                d->mode &= ~MODE_REC;
                    151:        sio_onmove(d->sio.hdl, dev_sio_onmove, d);
                    152:        d->sio.file = file_new(&dev_sio_ops, d, d->path, sio_nfds(d->sio.hdl));
1.2       ratchov   153:        timo_set(&d->sio.watchdog, dev_sio_timeout, d);
1.1       ratchov   154:        return 1;
                    155:  bad_close:
                    156:        sio_close(d->sio.hdl);
                    157:        return 0;
                    158: }
                    159:
                    160: void
                    161: dev_sio_close(struct dev *d)
                    162: {
                    163: #ifdef DEBUG
                    164:        if (log_level >= 3) {
                    165:                dev_log(d);
                    166:                log_puts(": closed\n");
                    167:        }
                    168: #endif
                    169:        file_del(d->sio.file);
                    170:        sio_close(d->sio.hdl);
                    171: }
                    172:
                    173: void
                    174: dev_sio_start(struct dev *d)
                    175: {
                    176:        if (!sio_start(d->sio.hdl)) {
                    177:                if (log_level >= 1) {
                    178:                        dev_log(d);
                    179:                        log_puts(": failed to start device\n");
                    180:                }
                    181:                return;
                    182:        }
                    183:        if (d->mode & MODE_PLAY) {
                    184:                d->sio.cstate = DEV_SIO_CYCLE;
                    185:                d->sio.todo = 0;
                    186:        } else {
                    187:                d->sio.cstate = DEV_SIO_READ;
                    188:                d->sio.todo = d->round * d->rchan * d->par.bps;
                    189:        }
                    190: #ifdef DEBUG
                    191:        d->sio.pused = 0;
                    192:        d->sio.rused = 0;
                    193:        d->sio.sum_utime = 0;
                    194:        d->sio.sum_wtime = 0;
                    195:        d->sio.wtime = file_wtime;
                    196:        d->sio.utime = file_utime;
                    197:        if (log_level >= 3) {
                    198:                dev_log(d);
                    199:                log_puts(": started\n");
                    200:        }
                    201: #endif
1.2       ratchov   202:        timo_add(&d->sio.watchdog, WATCHDOG_USEC);
1.1       ratchov   203: }
                    204:
                    205: void
                    206: dev_sio_stop(struct dev *d)
                    207: {
                    208:        if (!sio_eof(d->sio.hdl) && !sio_stop(d->sio.hdl)) {
                    209:                if (log_level >= 1) {
                    210:                        dev_log(d);
                    211:                        log_puts(": failed to stop device\n");
                    212:                }
                    213:                return;
                    214:        }
                    215: #ifdef DEBUG
                    216:        if (log_level >= 3) {
                    217:                dev_log(d);
                    218:                log_puts(": stopped, load avg = ");
                    219:                log_puti(d->sio.sum_utime / 1000);
                    220:                log_puts(" / ");
                    221:                log_puti(d->sio.sum_wtime / 1000);
                    222:                log_puts("\n");
                    223:        }
                    224: #endif
1.2       ratchov   225:        timo_del(&d->sio.watchdog);
1.1       ratchov   226: }
                    227:
                    228: int
                    229: dev_sio_pollfd(void *arg, struct pollfd *pfd)
                    230: {
                    231:        struct dev *d = arg;
                    232:        int events;
                    233:
                    234:        events = (d->sio.cstate == DEV_SIO_READ) ? POLLIN : POLLOUT;
                    235:        return sio_pollfd(d->sio.hdl, pfd, events);
                    236: }
                    237:
                    238: int
                    239: dev_sio_revents(void *arg, struct pollfd *pfd)
                    240: {
                    241:        struct dev *d = arg;
                    242:        int events;
                    243:
                    244:        events = sio_revents(d->sio.hdl, pfd);
                    245: #ifdef DEBUG
                    246:        d->sio.events = events;
                    247: #endif
                    248:        return events;
                    249: }
                    250:
                    251: void
                    252: dev_sio_run(void *arg)
                    253: {
                    254:        struct dev *d = arg;
                    255:        unsigned char *data, *base;
                    256:        unsigned int n;
                    257:
                    258:        /*
                    259:         * sio_read() and sio_write() would block at the end of the
                    260:         * cycle so we *must* return and restart poll()'ing. Otherwise
                    261:         * we may trigger dev_cycle() which would make all clients
                    262:         * underrun (ex, on a play-only device)
                    263:         */
                    264:        for (;;) {
                    265:                if (d->pstate != DEV_RUN)
                    266:                        return;
                    267:                switch (d->sio.cstate) {
                    268:                case DEV_SIO_READ:
                    269: #ifdef DEBUG
                    270:                        if (!(d->sio.events & POLLIN)) {
                    271:                                dev_log(d);
                    272:                                log_puts(": recording, but POLLIN not set\n");
                    273:                                panic();
                    274:                        }
                    275:                        if (d->sio.todo == 0) {
                    276:                                dev_log(d);
                    277:                                log_puts(": can't read data\n");
                    278:                                panic();
                    279:                        }
                    280:                        if (d->prime > 0) {
                    281:                                dev_log(d);
                    282:                                log_puts(": unexpected data\n");
                    283:                                panic();
                    284:                        }
                    285: #endif
                    286:                        base = d->decbuf ? d->decbuf : (unsigned char *)d->rbuf;
                    287:                        data = base +
                    288:                            d->rchan * d->round * d->par.bps -
                    289:                            d->sio.todo;
                    290:                        n = sio_read(d->sio.hdl, data, d->sio.todo);
                    291:                        d->sio.todo -= n;
                    292: #ifdef DEBUG
                    293:                        if (n == 0 && data == base && !sio_eof(d->sio.hdl)) {
                    294:                                dev_log(d);
                    295:                                log_puts(": read blocked at cycle start\n");
                    296:                        }
                    297:                        if (log_level >= 4) {
                    298:                                dev_log(d);
                    299:                                log_puts(": read ");
                    300:                                log_putu(n);
                    301:                                log_puts(": bytes, todo ");
                    302:                                log_putu(d->sio.todo);
                    303:                                log_puts("/");
                    304:                                log_putu(d->round * d->rchan * d->par.bps);
                    305:                                log_puts("\n");
                    306:                        }
                    307: #endif
                    308:                        if (d->sio.todo > 0)
                    309:                                return;
                    310: #ifdef DEBUG
                    311:                        d->sio.rused -= d->round;
                    312:                        if (log_level >= 2) {
                    313:                                if (d->sio.rused >= d->round) {
                    314:                                        dev_log(d);
                    315:                                        log_puts(": rec hw xrun, rused = ");
                    316:                                        log_puti(d->sio.rused);
                    317:                                        log_puts("/");
                    318:                                        log_puti(d->bufsz);
                    319:                                        log_puts("\n");
                    320:                                }
                    321:                                if (d->sio.rused < 0 ||
                    322:                                    d->sio.rused >= d->bufsz) {
                    323:                                        dev_log(d);
                    324:                                        log_puts(": out of bounds rused = ");
                    325:                                        log_puti(d->sio.rused);
                    326:                                        log_puts("/");
                    327:                                        log_puti(d->bufsz);
                    328:                                        log_puts("\n");
                    329:                                }
                    330:                        }
                    331: #endif
                    332:                        d->sio.cstate = DEV_SIO_CYCLE;
                    333:                        break;
                    334:                case DEV_SIO_CYCLE:
1.2       ratchov   335:                        timo_del(&d->sio.watchdog);
                    336:                        timo_add(&d->sio.watchdog, WATCHDOG_USEC);
                    337:
1.1       ratchov   338: #ifdef DEBUG
                    339:                        /*
                    340:                         * check that we're called at cycle boundary:
                    341:                         * either after a recorded block, or when POLLOUT is
                    342:                         * raised
                    343:                         */
                    344:                        if (!((d->mode & MODE_REC) && d->prime == 0) &&
                    345:                            !(d->sio.events & POLLOUT)) {
                    346:                                dev_log(d);
                    347:                                log_puts(": cycle not at block boundary\n");
                    348:                                panic();
                    349:                        }
                    350: #endif
                    351:                        dev_cycle(d);
                    352:                        if (d->mode & MODE_PLAY) {
                    353:                                d->sio.cstate = DEV_SIO_WRITE;
                    354:                                d->sio.todo = d->round * d->pchan * d->par.bps;
                    355:                                break;
                    356:                        } else {
                    357:                                d->sio.cstate = DEV_SIO_READ;
                    358:                                d->sio.todo = d->round * d->rchan * d->par.bps;
                    359:                                return;
                    360:                        }
                    361:                case DEV_SIO_WRITE:
                    362: #ifdef DEBUG
                    363:                        if (d->sio.todo == 0) {
                    364:                                dev_log(d);
                    365:                                log_puts(": can't write data\n");
                    366:                                panic();
                    367:                        }
                    368: #endif
                    369:                        base = d->encbuf ? d->encbuf : (unsigned char *)DEV_PBUF(d);
                    370:                        data = base +
                    371:                            d->pchan * d->round * d->par.bps -
                    372:                            d->sio.todo;
                    373:                        n = sio_write(d->sio.hdl, data, d->sio.todo);
                    374:                        d->sio.todo -= n;
                    375: #ifdef DEBUG
                    376:                        if (n == 0 && data == base && !sio_eof(d->sio.hdl)) {
                    377:                                dev_log(d);
                    378:                                log_puts(": write blocked at cycle start\n");
                    379:                        }
                    380:                        if (log_level >= 4) {
                    381:                                dev_log(d);
                    382:                                log_puts(": wrote ");
                    383:                                log_putu(n);
                    384:                                log_puts(" bytes, todo ");
                    385:                                log_putu(d->sio.todo);
                    386:                                log_puts("/");
                    387:                                log_putu(d->round * d->pchan * d->par.bps);
                    388:                                log_puts("\n");
                    389:                        }
                    390: #endif
                    391:                        if (d->sio.todo > 0)
                    392:                                return;
                    393: #ifdef DEBUG
                    394:                        d->sio.pused += d->round;
                    395:                        if (log_level >= 2) {
                    396:                                if (d->prime == 0 &&
                    397:                                    d->sio.pused <= d->bufsz - d->round) {
                    398:                                        dev_log(d);
                    399:                                        log_puts(": play hw xrun, pused = ");
                    400:                                        log_puti(d->sio.pused);
                    401:                                        log_puts("/");
                    402:                                        log_puti(d->bufsz);
                    403:                                        log_puts("\n");
                    404:                                }
                    405:                                if (d->sio.pused < 0 ||
                    406:                                    d->sio.pused > d->bufsz) {
                    407:                                        /* device driver or libsndio bug */
                    408:                                        dev_log(d);
                    409:                                        log_puts(": out of bounds pused = ");
                    410:                                        log_puti(d->sio.pused);
                    411:                                        log_puts("/");
                    412:                                        log_puti(d->bufsz);
                    413:                                        log_puts("\n");
                    414:                                }
                    415:                        }
                    416: #endif
                    417:                        d->poffs += d->round;
                    418:                        if (d->poffs == d->bufsz)
                    419:                                d->poffs = 0;
                    420:                        if ((d->mode & MODE_REC) && d->prime == 0) {
                    421:                                d->sio.cstate = DEV_SIO_READ;
                    422:                                d->sio.todo = d->round * d->rchan * d->par.bps;
                    423:                        } else
                    424:                                d->sio.cstate = DEV_SIO_CYCLE;
                    425:                        return;
                    426:                }
                    427:        }
                    428: }
                    429:
                    430: void
                    431: dev_sio_hup(void *arg)
                    432: {
                    433:        struct dev *d = arg;
                    434:
                    435:        dev_close(d);
                    436: }