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

Annotation of src/usr.bin/aucat/siofile.c, Revision 1.7

1.7     ! ratchov     1: /*     $OpenBSD: siofile.c,v 1.6 2010/06/04 06:15:28 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: #include <sys/time.h>
                     19: #include <sys/types.h>
                     20:
                     21: #include <poll.h>
                     22: #include <sndio.h>
                     23: #include <stdio.h>
                     24: #include <stdlib.h>
                     25: #include <string.h>
                     26:
                     27: #include "aparams.h"
                     28: #include "aproc.h"
1.4       ratchov    29: #include "abuf.h"
1.1       ratchov    30: #include "conf.h"
                     31: #include "dev.h"
                     32: #include "file.h"
                     33: #include "siofile.h"
                     34: #ifdef DEBUG
                     35: #include "dbg.h"
                     36: #endif
                     37:
                     38: struct siofile {
                     39:        struct file file;
                     40:        struct sio_hdl *hdl;
1.4       ratchov    41:        unsigned wtickets, wbpf;
                     42:        unsigned rtickets, rbpf;
                     43:        unsigned bufsz;
1.1       ratchov    44:        int started;
1.7     ! ratchov    45: #ifdef DEBUG
        !            46:        long long wtime, utime;
        !            47: #endif
1.1       ratchov    48: };
                     49:
                     50: void siofile_close(struct file *);
                     51: unsigned siofile_read(struct file *, unsigned char *, unsigned);
                     52: unsigned siofile_write(struct file *, unsigned char *, unsigned);
                     53: void siofile_start(struct file *);
                     54: void siofile_stop(struct file *);
                     55: int siofile_nfds(struct file *);
                     56: int siofile_pollfd(struct file *, struct pollfd *, int);
                     57: int siofile_revents(struct file *, struct pollfd *);
                     58:
                     59: struct fileops siofile_ops = {
                     60:        "sio",
                     61:        sizeof(struct siofile),
                     62:        siofile_close,
                     63:        siofile_read,
                     64:        siofile_write,
                     65:        siofile_start,
                     66:        siofile_stop,
                     67:        siofile_nfds,
                     68:        siofile_pollfd,
                     69:        siofile_revents
                     70: };
                     71:
1.4       ratchov    72: int wsio_out(struct aproc *, struct abuf *);
                     73: int rsio_in(struct aproc *, struct abuf *);
                     74:
                     75: struct aproc_ops rsio_ops = {
                     76:        "rsio",
                     77:        rsio_in,
                     78:        rfile_out,
                     79:        rfile_eof,
                     80:        rfile_hup,
                     81:        NULL, /* newin */
                     82:        NULL, /* newout */
                     83:        aproc_ipos,
                     84:        aproc_opos,
                     85:        rfile_done
                     86: };
                     87:
                     88: struct aproc_ops wsio_ops = {
                     89:        "wsio",
                     90:        wfile_in,
                     91:        wsio_out,
                     92:        wfile_eof,
                     93:        wfile_hup,
                     94:        NULL, /* newin */
                     95:        NULL, /* newout */
                     96:        aproc_ipos,
                     97:        aproc_opos,
                     98:        wfile_done
                     99: };
                    100:
                    101: struct aproc *
                    102: rsio_new(struct file *f)
                    103: {
                    104:        struct aproc *p;
                    105:
                    106:        p = aproc_new(&rsio_ops, f->name);
                    107:        p->u.io.file = f;
                    108:        p->u.io.partial = 0;
                    109:        f->rproc = p;
                    110:        return p;
                    111: }
                    112:
                    113: struct aproc *
                    114: wsio_new(struct file *f)
                    115: {
                    116:        struct aproc *p;
                    117:
                    118:        p = aproc_new(&wsio_ops, f->name);
                    119:        p->u.io.file = f;
                    120:        p->u.io.partial = 0;
                    121:        f->wproc = p;
                    122:        return p;
                    123: }
                    124:
                    125: int
                    126: wsio_out(struct aproc *p, struct abuf *obuf)
                    127: {
                    128:        struct siofile *f = (struct siofile *)p->u.io.file;
                    129:
                    130:        if (f->wtickets == 0) {
                    131: #ifdef DEBUG
                    132:                if (debug_level >= 4) {
                    133:                        file_dbg(&f->file);
                    134:                        dbg_puts(": no more write tickets\n");
                    135:                }
                    136: #endif
                    137:                f->file.state &= ~FILE_WOK;
                    138:                return 0;
                    139:        }
                    140:        return wfile_out(p, obuf);
                    141: }
                    142:
                    143: int
                    144: rsio_in(struct aproc *p, struct abuf *ibuf)
                    145: {
                    146:        struct siofile *f = (struct siofile *)p->u.io.file;
                    147:
                    148:        if (f->rtickets == 0) {
                    149: #ifdef DEBUG
                    150:                if (debug_level >= 4) {
                    151:                        file_dbg(&f->file);
                    152:                        dbg_puts(": no more read tickets\n");
                    153:                }
                    154: #endif
                    155:                f->file.state &= ~FILE_ROK;
                    156:                return 0;
                    157:        }
                    158:        return rfile_in(p, ibuf);
                    159: }
                    160:
1.1       ratchov   161: void
                    162: siofile_cb(void *addr, int delta)
                    163: {
                    164:        struct siofile *f = (struct siofile *)addr;
                    165:        struct aproc *p;
                    166:
                    167: #ifdef DEBUG
                    168:        if (delta < 0 || delta > (60 * RATE_MAX)) {
1.4       ratchov   169:                file_dbg(&f->file);
1.1       ratchov   170:                dbg_puts(": ");
                    171:                dbg_puti(delta);
                    172:                dbg_puts(": bogus sndio delta");
                    173:                dbg_panic();
                    174:        }
1.4       ratchov   175:        if (debug_level >= 4) {
                    176:                file_dbg(&f->file);
                    177:                dbg_puts(": tick, delta = ");
                    178:                dbg_puti(delta);
1.7     ! ratchov   179:                dbg_puts(", load = ");
        !           180:                dbg_puti((file_utime - f->utime) / 1000);
        !           181:                dbg_puts(" + ");
        !           182:                dbg_puti((file_wtime - f->wtime) / 1000);
1.4       ratchov   183:                dbg_puts("\n");
                    184:        }
1.7     ! ratchov   185:        f->wtime = file_wtime;
        !           186:        f->utime = file_utime;
1.1       ratchov   187: #endif
                    188:        if (delta != 0) {
                    189:                p = f->file.wproc;
                    190:                if (p && p->ops->opos)
                    191:                        p->ops->opos(p, NULL, delta);
                    192:        }
                    193:        if (delta != 0) {
                    194:                p = f->file.rproc;
                    195:                if (p && p->ops->ipos)
                    196:                        p->ops->ipos(p, NULL, delta);
                    197:        }
1.4       ratchov   198:        f->wtickets += delta * f->wbpf;
                    199:        f->rtickets += delta * f->rbpf;
1.1       ratchov   200: }
                    201:
                    202: /*
                    203:  * Open the device.
                    204:  */
                    205: struct siofile *
1.5       ratchov   206: siofile_new(struct fileops *ops, char *path, unsigned *rmode,
1.1       ratchov   207:     struct aparams *ipar, struct aparams *opar,
                    208:     unsigned *bufsz, unsigned *round)
                    209: {
1.6       ratchov   210:        char *siopath;
1.1       ratchov   211:        struct sio_par par;
                    212:        struct sio_hdl *hdl;
                    213:        struct siofile *f;
1.5       ratchov   214:        unsigned mode = *rmode;
1.1       ratchov   215:
1.6       ratchov   216:        siopath = (strcmp(path, "default") == 0) ? NULL : path;
                    217:        hdl = sio_open(siopath, mode, 1);
1.5       ratchov   218:        if (hdl == NULL) {
                    219:                if (mode != (SIO_PLAY | SIO_REC))
                    220:                        return NULL;
1.6       ratchov   221:                hdl = sio_open(siopath, SIO_PLAY, 1);
1.5       ratchov   222:                if (hdl != NULL)
                    223:                        mode = SIO_PLAY;
                    224:                else {
1.6       ratchov   225:                        hdl = sio_open(siopath, SIO_REC, 1);
1.5       ratchov   226:                        if (hdl != NULL)
                    227:                                mode = SIO_REC;
                    228:                        else
                    229:                                return NULL;
                    230:                }
                    231: #ifdef DEBUG
                    232:                if (debug_level >= 1) {
                    233:                        dbg_puts("warning, device opened in ");
                    234:                        dbg_puts(mode == SIO_PLAY ? "play-only" : "rec-only");
                    235:                        dbg_puts(" mode\n");
                    236:                }
                    237: #endif
                    238:        }
                    239:
1.1       ratchov   240:        sio_initpar(&par);
1.4       ratchov   241:        if (mode & SIO_REC) {
1.1       ratchov   242:                par.bits = ipar->bits;
                    243:                par.bps = ipar->bps;
                    244:                par.sig = ipar->sig;
                    245:                par.le = ipar->le;
                    246:                par.msb = ipar->msb;
                    247:                par.rate = ipar->rate;
                    248:                par.rchan = ipar->cmax - ipar->cmin + 1;
                    249:        } else {
                    250:                par.bits = opar->bits;
                    251:                par.bps = opar->bps;
                    252:                par.sig = opar->sig;
                    253:                par.le = opar->le;
                    254:                par.msb = opar->msb;
                    255:                par.rate = opar->rate;
                    256:        }
1.4       ratchov   257:        if (mode & SIO_PLAY)
1.1       ratchov   258:                par.pchan = opar->cmax - opar->cmin + 1;
                    259:        par.appbufsz = *bufsz;
                    260:        par.round = *round;
                    261:        if (!sio_setpar(hdl, &par))
                    262:                goto bad_close;
                    263:        if (!sio_getpar(hdl, &par))
                    264:                goto bad_close;
1.4       ratchov   265:        if (mode & SIO_REC) {
1.1       ratchov   266:                ipar->bits = par.bits;
                    267:                ipar->bps = par.bps;
                    268:                ipar->sig = par.sig;
                    269:                ipar->le = par.le;
                    270:                ipar->msb = par.msb;
                    271:                ipar->rate = par.rate;
                    272:                ipar->cmax = ipar->cmin + par.rchan - 1;
                    273:        }
1.4       ratchov   274:        if (mode & SIO_PLAY) {
1.1       ratchov   275:                opar->bits = par.bits;
                    276:                opar->bps = par.bps;
                    277:                opar->sig = par.sig;
                    278:                opar->le = par.le;
                    279:                opar->msb = par.msb;
                    280:                opar->rate = par.rate;
                    281:                opar->cmax = opar->cmin + par.pchan - 1;
                    282:        }
1.5       ratchov   283:        *rmode = mode;
1.1       ratchov   284:        *bufsz = par.bufsz;
                    285:        *round = par.round;
                    286:        f = (struct siofile *)file_new(ops, path, sio_nfds(hdl));
                    287:        if (f == NULL)
                    288:                goto bad_close;
                    289:        f->hdl = hdl;
                    290:        f->started = 0;
1.4       ratchov   291:        f->wtickets = 0;
                    292:        f->rtickets = 0;
                    293:        f->wbpf = par.pchan * par.bps;
                    294:        f->rbpf = par.rchan * par.bps;
                    295:        f->bufsz = par.bufsz;
1.1       ratchov   296:        sio_onmove(f->hdl, siofile_cb, f);
                    297:        return f;
                    298:  bad_close:
                    299:        sio_close(hdl);
                    300:        return NULL;
                    301: }
                    302:
                    303: void
                    304: siofile_start(struct file *file)
                    305: {
                    306:        struct siofile *f = (struct siofile *)file;
                    307:
                    308:        if (!sio_start(f->hdl)) {
                    309: #ifdef DEBUG
                    310:                dbg_puts(f->file.name);
                    311:                dbg_puts(": failed to start device\n");
                    312: #endif
                    313:                file_close(file);
                    314:                return;
                    315:        }
                    316:        f->started = 1;
1.4       ratchov   317:        f->wtickets = f->bufsz * f->wbpf;
                    318:        f->rtickets = 0;
1.1       ratchov   319: #ifdef DEBUG
1.7     ! ratchov   320:        f->wtime = file_wtime;
        !           321:        f->utime = file_utime;
1.1       ratchov   322:        if (debug_level >= 3) {
                    323:                file_dbg(&f->file);
                    324:                dbg_puts(": started\n");
                    325:        }
                    326: #endif
                    327: }
                    328:
                    329: void
                    330: siofile_stop(struct file *file)
                    331: {
                    332:        struct siofile *f = (struct siofile *)file;
                    333:
                    334:        f->started = 0;
                    335:        if (!sio_eof(f->hdl) && !sio_stop(f->hdl)) {
                    336: #ifdef DEBUG
                    337:                dbg_puts(f->file.name);
                    338:                dbg_puts(": failed to stop device\n");
                    339: #endif
                    340:                file_close(file);
                    341:                return;
                    342:        }
                    343: #ifdef DEBUG
                    344:        if (debug_level >= 3) {
                    345:                file_dbg(&f->file);
                    346:                dbg_puts(": stopped\n");
                    347:        }
                    348: #endif
                    349: }
                    350:
                    351: unsigned
                    352: siofile_read(struct file *file, unsigned char *data, unsigned count)
                    353: {
                    354:        struct siofile *f = (struct siofile *)file;
                    355:        unsigned n;
                    356:
1.4       ratchov   357: #ifdef DEBUG
                    358:        if (f->rtickets == 0) {
                    359:                file_dbg(&f->file);
                    360:                dbg_puts(": called with no read tickets\n");
                    361:        }
                    362: #endif
                    363:        if (count > f->rtickets)
                    364:                count = f->rtickets;
1.1       ratchov   365:        n = f->started ? sio_read(f->hdl, data, count) : 0;
                    366:        if (n == 0) {
                    367:                f->file.state &= ~FILE_ROK;
                    368:                if (sio_eof(f->hdl)) {
                    369: #ifdef DEBUG
                    370:                        dbg_puts(f->file.name);
                    371:                        dbg_puts(": failed to read from device\n");
                    372: #endif
                    373:                        file_eof(&f->file);
                    374:                } else {
                    375: #ifdef DEBUG
                    376:                        if (debug_level >= 4) {
                    377:                                file_dbg(&f->file);
                    378:                                dbg_puts(": reading blocked\n");
                    379:                        }
                    380: #endif
                    381:                }
                    382:                return 0;
1.4       ratchov   383:        } else {
                    384:                f->rtickets -= n;
                    385:                if (f->rtickets == 0) {
                    386:                        f->file.state &= ~FILE_ROK;
                    387: #ifdef DEBUG
                    388:                        if (debug_level >= 4) {
                    389:                                file_dbg(&f->file);
                    390:                                dbg_puts(": read tickets exhausted\n");
                    391:                        }
                    392: #endif
                    393:                }
1.1       ratchov   394:        }
                    395:        return n;
                    396:
                    397: }
                    398:
                    399: unsigned
                    400: siofile_write(struct file *file, unsigned char *data, unsigned count)
                    401: {
                    402:        struct siofile *f = (struct siofile *)file;
                    403:        unsigned n;
                    404:
1.4       ratchov   405: #ifdef DEBUG
                    406:        if (f->wtickets == 0) {
                    407:                file_dbg(&f->file);
                    408:                dbg_puts(": called with no write tickets\n");
                    409:        }
                    410: #endif
                    411:        if (count > f->wtickets)
                    412:                count = f->wtickets;
1.1       ratchov   413:        n = f->started ? sio_write(f->hdl, data, count) : 0;
                    414:        if (n == 0) {
                    415:                f->file.state &= ~FILE_WOK;
                    416:                if (sio_eof(f->hdl)) {
                    417: #ifdef DEBUG
                    418:                        dbg_puts(f->file.name);
                    419:                        dbg_puts(": failed to write on device\n");
                    420: #endif
                    421:                        file_hup(&f->file);
                    422:                } else {
                    423: #ifdef DEBUG
                    424:                        if (debug_level >= 4) {
                    425:                                file_dbg(&f->file);
                    426:                                dbg_puts(": writing blocked\n");
                    427:                        }
                    428: #endif
                    429:                }
                    430:                return 0;
1.4       ratchov   431:        } else {
                    432:                f->wtickets -= n;
                    433:                if (f->wtickets == 0) {
                    434:                        f->file.state &= ~FILE_WOK;
                    435: #ifdef DEBUG
                    436:                        if (debug_level >= 4) {
                    437:                                file_dbg(&f->file);
                    438:                                dbg_puts(": write tickets exhausted\n");
                    439:                        }
                    440: #endif
                    441:                }
1.1       ratchov   442:        }
                    443:        return n;
                    444: }
                    445:
                    446: int
                    447: siofile_nfds(struct file *file)
                    448: {
                    449:        return sio_nfds(((struct siofile *)file)->hdl);
                    450: }
                    451:
                    452: int
                    453: siofile_pollfd(struct file *file, struct pollfd *pfd, int events)
                    454: {
                    455:        struct siofile *f = (struct siofile *)file;
                    456:
                    457:        if (!f->started)
                    458:                events &= ~(POLLIN | POLLOUT);
                    459:        return sio_pollfd(((struct siofile *)file)->hdl, pfd, events);
                    460: }
                    461:
                    462: int
                    463: siofile_revents(struct file *file, struct pollfd *pfd)
                    464: {
                    465:        return sio_revents(((struct siofile *)file)->hdl, pfd);
                    466: }
                    467:
                    468: void
                    469: siofile_close(struct file *file)
                    470: {
                    471:        struct siofile *f = (struct siofile *)file;
                    472:
                    473:        if (f->started)
                    474:                siofile_stop(&f->file);
                    475:        return sio_close(((struct siofile *)file)->hdl);
                    476: }