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

Annotation of src/usr.bin/aucat/safile.c, Revision 1.4

1.4     ! ratchov     1: /*     $OpenBSD: safile.c,v 1.3 2008/11/07 21:01:15 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/types.h>
                     19: #include <sys/time.h>
                     20:
                     21: #include <poll.h>
                     22: #include <stdio.h>
                     23: #include <stdlib.h>
                     24: #include <string.h>
1.2       ratchov    25: #include <sndio.h>
1.1       ratchov    26:
                     27: #include "conf.h"
                     28: #include "file.h"
                     29: #include "aproc.h"
                     30: #include "aparams.h"
                     31: #include "safile.h"
                     32: #include "dev.h"
                     33:
                     34: struct safile {
                     35:        struct file file;
1.2       ratchov    36:        struct sio_hdl *hdl;
1.1       ratchov    37: #ifdef DEBUG
                     38:        struct timeval itv, otv;
                     39: #endif
                     40: };
                     41:
                     42: void safile_close(struct file *);
                     43: unsigned safile_read(struct file *, unsigned char *, unsigned);
                     44: unsigned safile_write(struct file *, unsigned char *, unsigned);
                     45: void safile_start(struct file *);
                     46: void safile_stop(struct file *);
                     47: int safile_nfds(struct file *);
                     48: int safile_pollfd(struct file *, struct pollfd *, int);
                     49: int safile_revents(struct file *, struct pollfd *);
                     50:
                     51: struct fileops safile_ops = {
1.3       ratchov    52:        "sndio",
1.1       ratchov    53:        sizeof(struct safile),
                     54:        safile_close,
                     55:        safile_read,
                     56:        safile_write,
                     57:        safile_start,
                     58:        safile_stop,
                     59:        safile_nfds,
                     60:        safile_pollfd,
                     61:        safile_revents
                     62: };
                     63:
1.3       ratchov    64: /*
                     65:  * list of (rate, block-size) pairs ordered by frequency preference and
                     66:  * then by block size preference (except for jumbo block sizes that are
                     67:  * less prefered than anything else).
                     68:  */
                     69: struct blkdesc {
                     70:        unsigned rate;          /* sample rate */
                     71:        unsigned round;         /* usable block sizes */
                     72: } blkdesc[] = {
                     73:        { 44100,         882 },
                     74:        { 44100,         840 },
                     75:        { 44100,         441 },
                     76:        { 44100,         420 },
                     77:        { 44100,        1764 },
                     78:        { 44100,        1680 },
                     79:        { 48000,         960 },
                     80:        { 48000,         768 },
                     81:        { 48000,         480 },
                     82:        { 48000,         384 },
                     83:        { 48000,        1920 },
                     84:        { 48000,        1536 },
                     85:        { 32000,         640 },
                     86:        { 32000,         512 },
                     87:        { 32000,         320 },
                     88:        { 32000,         256 },
                     89:        { 32000,        1280 },
                     90:        { 32000,        1024 },
                     91:        { 44100,        2940 },
                     92:        { 48000,        2976 },
                     93:        { 32000,        3200 },
                     94:        {  8000,         320 },
                     95:        {  8000,         256 },
                     96:        {     0,           0 }
                     97: };
                     98:
                     99:
                    100: int
                    101: safile_trypar(struct sio_hdl *hdl, struct sio_par *par, int blkio)
                    102: {
                    103:        struct blkdesc *d;
                    104:        struct sio_par np;
                    105:        unsigned rate = par->rate;
                    106:        unsigned round = par->round;
                    107:
                    108:        if (!blkio) {
1.4     ! ratchov   109:                DPRINTF("safile_trypar: not setting block size\n");
1.3       ratchov   110:                if (!sio_setpar(hdl, par))
                    111:                        return 0;
                    112:                if (!sio_getpar(hdl, par))
                    113:                        return 0;
                    114:                return 1;
                    115:        }
                    116:
                    117:        /*
                    118:         * find the rate we want to use
                    119:         */
                    120:        for (d = blkdesc;; d++) {
                    121:                if (d->rate == 0) {
                    122:                        d = blkdesc;
                    123:                        break;
                    124:                }
                    125:                if (d->rate == rate)
                    126:                        break;
                    127:        }
                    128:
                    129:        /*
                    130:         * find the first matching entry, (the blkdesc array is)
                    131:         * sorted by order of preference)
                    132:         */
                    133:        for (;; d++) {
                    134:                if (d->rate == 0)
                    135:                        break;
                    136:                if (d->round > round)
                    137:                        continue;
                    138:                par->rate = d->rate;
                    139:                par->round = d->round;
                    140:                if (!sio_setpar(hdl, par))
                    141:                        return 0;
                    142:                if (!sio_getpar(hdl, &np))
                    143:                        return 0;
                    144:                if (np.rate == d->rate && np.round == d->round) {
                    145:                        *par = np;
                    146:                        if (d->round >= d->rate / 15)
                    147:                                fprintf(stderr,
                    148:                                    "Warning: using jumbo block size, "
                    149:                                    "try to use another sample rate.\n");
                    150:                        return 1;
                    151:                }
                    152:                DPRINTF("safile_trypar: %uHz/%ufr failed, got %uHz/%ufr\n",
                    153:                    d->rate, d->round, np.rate, np.round);
                    154:        }
                    155:        fprintf(stderr, "Couldn't set block size to <%u frames.\n", round);
                    156:        return 0;
                    157: }
                    158:
1.1       ratchov   159: void
                    160: safile_cb(void *addr, int delta)
                    161: {
                    162:        struct safile *f = (struct safile *)addr;
                    163:        struct aproc *p;
                    164:
                    165:        if (delta != 0) {
                    166:                p = f->file.wproc;
                    167:                if (p && p->ops->opos)
                    168:                        p->ops->opos(p, NULL, delta);
                    169:        }
                    170:        if (delta != 0) {
                    171:                p = f->file.rproc;
                    172:                if (p && p->ops->ipos)
                    173:                        p->ops->ipos(p, NULL, delta);
                    174:        }
                    175: }
                    176:
                    177: /*
                    178:  * open the device
                    179:  */
                    180: struct safile *
                    181: safile_new(struct fileops *ops, char *path,
                    182:     struct aparams *ipar, struct aparams *opar,
1.3       ratchov   183:     unsigned *bufsz, unsigned *round, int blkio)
1.1       ratchov   184: {
1.2       ratchov   185:        struct sio_par par;
                    186:        struct sio_hdl *hdl;
1.1       ratchov   187:        struct safile *f;
                    188:        int mode;
                    189:
                    190:        mode = 0;
                    191:        if (ipar)
1.2       ratchov   192:                mode |= SIO_REC;
1.1       ratchov   193:        if (opar)
1.2       ratchov   194:                mode |= SIO_PLAY;
1.4     ! ratchov   195:        if (!mode) {
        !           196:                fprintf(stderr, "select at least play or record mode\n");
        !           197:                return NULL;
        !           198:        }
1.2       ratchov   199:        hdl = sio_open(path, mode, 1);
1.1       ratchov   200:        if (hdl == NULL) {
                    201:                fprintf(stderr, "safile_new: can't open device\n");
                    202:                return NULL;
                    203:        }
1.2       ratchov   204:        sio_initpar(&par);
1.1       ratchov   205:        if (ipar) {
                    206:                par.bits = ipar->bits;
                    207:                par.bps = ipar->bps;
                    208:                par.sig = ipar->sig;
                    209:                par.le = ipar->le;
                    210:                par.msb = ipar->msb;
                    211:                par.rate = ipar->rate;
                    212:                par.rchan = ipar->cmax - ipar->cmin + 1;
                    213:        } else {
                    214:                par.bits = opar->bits;
                    215:                par.bps = opar->bps;
                    216:                par.sig = opar->sig;
                    217:                par.le = opar->le;
                    218:                par.msb = opar->msb;
                    219:                par.rate = opar->rate;
                    220:        }
                    221:        if (opar)
                    222:                par.pchan = opar->cmax - opar->cmin + 1;
1.3       ratchov   223:        par.bufsz = *bufsz;
                    224:        par.round = *round;
                    225:        if (!safile_trypar(hdl, &par, blkio))
1.1       ratchov   226:                exit(1);
                    227:        if (ipar) {
                    228:                ipar->bits = par.bits;
                    229:                ipar->bps = par.bps;
                    230:                ipar->sig = par.sig;
                    231:                ipar->le = par.le;
                    232:                ipar->msb = par.msb;
                    233:                ipar->rate = par.rate;
                    234:                ipar->cmax = par.rchan - 1;
                    235:                ipar->cmin = 0;
                    236:        }
                    237:        if (opar) {
                    238:                opar->bits = par.bits;
                    239:                opar->bps = par.bps;
                    240:                opar->sig = par.sig;
                    241:                opar->le = par.le;
                    242:                opar->msb = par.msb;
                    243:                opar->rate = par.rate;
                    244:                opar->cmax = par.pchan - 1;
                    245:                opar->cmin = 0;
                    246:        }
                    247:        *bufsz = par.bufsz;
                    248:        *round = par.round;
1.3       ratchov   249:        DPRINTF("safile_new: using %u(%u) fpb\n", *bufsz, *round);
1.2       ratchov   250:        f = (struct safile *)file_new(ops, "hdl", sio_nfds(hdl));
1.1       ratchov   251:        f->hdl = hdl;
1.2       ratchov   252:        sio_onmove(f->hdl, safile_cb, f);
1.1       ratchov   253:        return f;
                    254: }
                    255:
                    256: void
                    257: safile_start(struct file *file)
                    258: {
                    259:        struct safile *f = (struct safile *)file;
                    260:
1.2       ratchov   261:        if (!sio_start(f->hdl)) {
                    262:                fprintf(stderr, "safile_start: sio_start() failed\n");
1.1       ratchov   263:                exit(1);
                    264:        }
                    265:        DPRINTF("safile_start: play/rec started\n");
                    266: }
                    267:
                    268: void
                    269: safile_stop(struct file *file)
                    270: {
                    271:        struct safile *f = (struct safile *)file;
                    272:
1.2       ratchov   273:        if (!sio_stop(f->hdl)) {
                    274:                fprintf(stderr, "safile_stop: sio_start() filed\n");
1.1       ratchov   275:                exit(1);
                    276:        }
                    277:        DPRINTF("safile_stop: play/rec stopped\n");
                    278: }
                    279:
                    280: unsigned
                    281: safile_read(struct file *file, unsigned char *data, unsigned count)
                    282: {
                    283:        struct safile *f = (struct safile *)file;
                    284:        unsigned n;
                    285: #ifdef DEBUG
                    286:        struct timeval tv0, tv1, dtv;
                    287:        unsigned us;
                    288:
                    289:        if (!(f->file.state & FILE_ROK)) {
                    290:                DPRINTF("file_read: %s: bad state\n", f->file.name);
                    291:                abort();
                    292:        }
                    293:        gettimeofday(&tv0, NULL);
                    294: #endif
1.2       ratchov   295:        n = sio_read(f->hdl, data, count);
1.1       ratchov   296:        if (n == 0) {
                    297:                f->file.state &= ~FILE_ROK;
1.2       ratchov   298:                if (sio_eof(f->hdl)) {
1.1       ratchov   299:                        fprintf(stderr, "safile_read: eof\n");
                    300:                        file_eof(&f->file);
                    301:                } else {
                    302:                        DPRINTFN(3, "safile_read: %s: blocking...\n",
                    303:                            f->file.name);
                    304:                }
                    305:                return 0;
                    306:        }
                    307: #ifdef DEBUG
                    308:        gettimeofday(&tv1, NULL);
                    309:        timersub(&tv1, &tv0, &dtv);
                    310:        us = dtv.tv_sec * 1000000 + dtv.tv_usec;
                    311:        DPRINTFN(us < 5000 ? 4 : 1,
                    312:            "safile_read: %s: got %d bytes in %uus\n",
                    313:            f->file.name, n, us);
                    314: #endif
                    315:        return n;
                    316:
                    317: }
                    318:
                    319: unsigned
                    320: safile_write(struct file *file, unsigned char *data, unsigned count)
                    321: {
                    322:        struct safile *f = (struct safile *)file;
                    323:        unsigned n;
                    324: #ifdef DEBUG
                    325:        struct timeval tv0, tv1, dtv;
                    326:        unsigned us;
                    327:
                    328:        if (!(f->file.state & FILE_WOK)) {
                    329:                DPRINTF("safile_write: %s: bad state\n", f->file.name);
                    330:                abort();
                    331:        }
                    332:        gettimeofday(&tv0, NULL);
                    333: #endif
1.2       ratchov   334:        n = sio_write(f->hdl, data, count);
1.1       ratchov   335:        if (n == 0) {
                    336:                f->file.state &= ~FILE_WOK;
1.2       ratchov   337:                if (sio_eof(f->hdl)) {
1.1       ratchov   338:                        fprintf(stderr, "safile_write: %s: hup\n", f->file.name);
                    339:                        file_hup(&f->file);
                    340:                } else {
                    341:                        DPRINTFN(3, "safile_write: %s: blocking...\n",
                    342:                            f->file.name);
                    343:                }
                    344:                return 0;
                    345:        }
                    346: #ifdef DEBUG
                    347:        gettimeofday(&tv1, NULL);
                    348:        timersub(&tv1, &tv0, &dtv);
                    349:        us = dtv.tv_sec * 1000000 + dtv.tv_usec;
                    350:        DPRINTFN(us < 5000 ? 4 : 1,
                    351:            "safile_write: %s: wrote %d bytes in %uus\n",
                    352:            f->file.name, n, us);
                    353: #endif
                    354:        return n;
                    355: }
                    356:
                    357: int
                    358: safile_nfds(struct file *file)
                    359: {
1.2       ratchov   360:        return sio_nfds(((struct safile *)file)->hdl);
1.1       ratchov   361: }
                    362:
                    363: int
                    364: safile_pollfd(struct file *file, struct pollfd *pfd, int events)
                    365: {
1.2       ratchov   366:        return sio_pollfd(((struct safile *)file)->hdl, pfd, events);
1.1       ratchov   367: }
                    368:
                    369: int
                    370: safile_revents(struct file *file, struct pollfd *pfd)
                    371: {
1.2       ratchov   372:        return sio_revents(((struct safile *)file)->hdl, pfd);
1.1       ratchov   373: }
                    374:
                    375: void
                    376: safile_close(struct file *file)
                    377: {
1.2       ratchov   378:        return sio_close(((struct safile *)file)->hdl);
1.1       ratchov   379: }