[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.2

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