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

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