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

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