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

Annotation of src/usr.bin/aucat/aucat.c, Revision 1.13

1.13    ! uwe         1: /*     $OpenBSD: aucat.c,v 1.12 2006/12/20 06:45:10 steven Exp $       */
1.1       kstailey    2: /*
                      3:  * Copyright (c) 1997 Kenneth Stailey.  All rights reserved.
                      4:  *
                      5:  * Redistribution and use in source and binary forms, with or without
                      6:  * modification, are permitted provided that the following conditions
                      7:  * are met:
                      8:  * 1. Redistributions of source code must retain the above copyright
                      9:  *    notice, this list of conditions and the following disclaimer.
                     10:  * 2. Redistributions in binary form must reproduce the above copyright
                     11:  *    notice, this list of conditions and the following disclaimer in the
                     12:  *    documentation and/or other materials provided with the distribution.
                     13:  * 3. All advertising materials mentioning features or use of this software
                     14:  *    must display the following acknowledgement:
                     15:  *     This product includes software developed by Kenneth Stailey.
                     16:  * 4. The name of the author may not be used to endorse or promote products
                     17:  *    derived from this software without specific prior written permission.
                     18:  *
                     19:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
                     20:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
                     21:  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
                     22:  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
                     23:  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
                     24:  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
                     25:  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
                     26:  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
                     27:  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
                     28:  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
                     29:  */
                     30:
                     31: #include <sys/types.h>
1.13    ! uwe        32: #include <sys/audioio.h>
        !            33: #include <sys/ioctl.h>
        !            34:
1.1       kstailey   35: #include <fcntl.h>
                     36: #include <stdio.h>
1.4       millert    37: #include <stdlib.h>
1.8       david      38: #include <string.h>
1.1       kstailey   39: #include <unistd.h>
1.4       millert    40: #include <err.h>
1.1       kstailey   41:
1.11      jaredy     42: #define _PATH_AUDIO "/dev/audio"
                     43:
1.13    ! uwe        44: /*
        !            45:  * aucat: concatenate and play Sun 8-bit .au files or 8/16-bit
        !            46:  * uncompressed WAVE RIFF files
1.1       kstailey   47:  */
1.7       deraadt    48:
1.13    ! uwe        49: int    playfile(int, char *, audio_info_t *);
        !            50: int    readwaveheader(int, audio_info_t *);
1.11      jaredy     51: void   usage(void) __attribute__((__noreturn__));
1.1       kstailey   52:
1.13    ! uwe        53: int afd = -1;
        !            54:
1.11      jaredy     55: /*
                     56:  * function playfile: given a file which is positioned at the beginning
1.1       kstailey   57:  * of what is assumed to be an .au data stream copy it out to the audio
1.5       millert    58:  * device.  Return 0 on success, -1 on failure.
1.1       kstailey   59:  */
                     60: int
1.13    ! uwe        61: playfile(int fd, char *dev, audio_info_t *audioinfo)
1.1       kstailey   62: {
1.11      jaredy     63:        ssize_t rd;
1.4       millert    64:        char buf[5120];
                     65:
                     66:        if (afd == -1 && (afd = open(dev, O_WRONLY)) < 0) {
                     67:                warn("can't open %s", dev);
                     68:                return(-1);
                     69:        }
1.13    ! uwe        70:
        !            71:        /*
        !            72:         * If we don't wait here, the AUDIO_SETINFO ioctl interrupts
        !            73:         * the playback of the previous file.
        !            74:         */
        !            75:        if (ioctl(afd, AUDIO_DRAIN, NULL) == -1)
        !            76:                warn("AUDIO_DRAIN");
        !            77:
        !            78:        if (ioctl(afd, AUDIO_SETINFO, audioinfo) == -1) {
        !            79:                warn("AUDIO_SETINFO");
        !            80:                return -1;
        !            81:        }
        !            82:
1.11      jaredy     83:        while ((rd = read(fd, buf, sizeof(buf))) > 0)
                     84:                if (write(afd, buf, rd) != rd)
                     85:                        warn("write");
                     86:        if (rd == -1)
                     87:                warn("read");
1.4       millert    88:
                     89:        return (0);
1.1       kstailey   90: }
                     91:
1.13    ! uwe        92: /*
        !            93:  * function readwaveheader: given a file which is positioned at four
        !            94:  * bytes into a RIFF file header, read the rest of the header, check
        !            95:  * to see if it is a simple WAV file that we can handle, seek to the
        !            96:  * beginning of the audio data, and set the playback parameters in
        !            97:  * the audio_info_t structure.  Return 0 on success, -1 on failure.
        !            98:  */
        !            99: int
        !           100: readwaveheader(int fd, audio_info_t *audioinfo)
        !           101: {
        !           102:        /*
        !           103:         * The simplest form of a RIFF file...
        !           104:         */
        !           105:        struct {
        !           106:        /*      u_int32_t riff_chunkid; -- this is read before in main()! */
        !           107:                u_int32_t riff_chunksize;
        !           108:                u_int32_t riff_format;
        !           109:
        !           110:                u_int32_t fmt_subchunkid;
        !           111:                u_int32_t fmt_subchunksize;
        !           112:
        !           113:                u_int16_t fmt_format;           /* 1 = PCM uncompressed */
        !           114:                u_int16_t fmt_channels;         /* 1 = mono, 2 = stereo */
        !           115:                u_int32_t fmt_samplespersec;    /* 8000, 22050, 44100 etc. */
        !           116:                u_int32_t fmt_byterate;         /* total bytes per second */
        !           117:                u_int16_t fmt_blockalign;       /* channels * bitspersample/8 */
        !           118:                u_int16_t fmt_bitspersample;    /* 8 = 8 bits, 16 = 16 bits etc. */
        !           119:        } header;
        !           120:        u_int datatag;
        !           121:        char c;
        !           122:
        !           123:        /*
        !           124:         * Is it an uncompressed wave file?
        !           125:         */
        !           126:        if (read(fd, &header, sizeof(header)) != sizeof(header)) {
        !           127:                warn("read");
        !           128:                return -1;
        !           129:        }
        !           130:        if (strncmp((char *) &header.riff_format, "WAVE", 4) ||
        !           131:            letoh16(header.fmt_format) != 1 ||
        !           132:            strncmp((char *) &header.fmt_subchunkid, "fmt ", 4) ||
        !           133:            (letoh16(header.fmt_bitspersample) != 8 &&
        !           134:             letoh16(header.fmt_bitspersample) != 16))
        !           135:                return -1;
        !           136:
        !           137:        /*
        !           138:         * Seek to the data chunk.
        !           139:         */
        !           140:        for (datatag = 0; datatag < 4; ) {
        !           141:                if (read(fd, &c, 1) != 1) {
        !           142:                        warn("read");
        !           143:                        return -1;
        !           144:                }
        !           145:
        !           146:                switch(datatag) {
        !           147:                case 0:
        !           148:                        if (c == 'd')
        !           149:                                ++datatag;
        !           150:                        break;
        !           151:                case 1:
        !           152:                        if (c == 'a')
        !           153:                                ++datatag;
        !           154:                        break;
        !           155:                case 2:
        !           156:                        if (c == 't')
        !           157:                                ++datatag;
        !           158:                        break;
        !           159:                case 3:
        !           160:                        if (c == 'a')
        !           161:                                ++datatag;
        !           162:                        break;
        !           163:                default:
        !           164:                        datatag = 0;
        !           165:                        break;
        !           166:                }
        !           167:        }
        !           168:        if (datatag != 4) {
        !           169:                warnx("no data chunk found in wave file");
        !           170:                return -1;
        !           171:        }
        !           172:
        !           173:        /*
        !           174:         * Ignore the size of the data chunk.
        !           175:         */
        !           176:        if (lseek(fd, 4, SEEK_CUR) == -1) {
        !           177:                warn("lseek");
        !           178:                return -1;
        !           179:        }
        !           180:
        !           181:        audioinfo->play.sample_rate = letoh32(header.fmt_samplespersec);
        !           182:        audioinfo->play.channels    = letoh16(header.fmt_channels);
        !           183:        audioinfo->play.precision   = letoh16(header.fmt_bitspersample);
        !           184:        audioinfo->play.encoding    = audioinfo->play.precision == 8 ?
        !           185:            AUDIO_ENCODING_ULINEAR : AUDIO_ENCODING_SLINEAR_LE;
        !           186:        return 0;
        !           187: }
        !           188:
1.1       kstailey  189: int
1.6       deraadt   190: main(int argc, char *argv[])
1.1       kstailey  191: {
1.4       millert   192:        int fd, ch;
1.11      jaredy    193:        u_int32_t data;
                    194:        char magic[4];
1.4       millert   195:        char *dev;
1.13    ! uwe       196:        audio_info_t ai;
        !           197:        audio_info_t ai_defaults;
1.4       millert   198:
                    199:        dev = getenv("AUDIODEVICE");
1.11      jaredy    200:        if (dev == NULL)
                    201:                dev = _PATH_AUDIO;
1.4       millert   202:
                    203:        while ((ch = getopt(argc, argv, "f:")) != -1) {
1.11      jaredy    204:                switch (ch) {
1.4       millert   205:                case 'f':
                    206:                        dev = optarg;
                    207:                        break;
1.11      jaredy    208:                default:
                    209:                        usage();
                    210:                        /* NOTREACHED */
1.4       millert   211:                }
                    212:        }
                    213:        argc -= optind;
                    214:        argv += optind;
                    215:
1.11      jaredy    216:        if (argc == 0)
                    217:                usage();
1.13    ! uwe       218:
        !           219:        if (afd == -1 && (afd = open(dev, O_WRONLY)) < 0)
        !           220:                err(1, "can't open %s", dev);
        !           221:
        !           222:        if (ioctl(afd, AUDIO_GETINFO, &ai_defaults) == -1)
        !           223:                err(1, "AUDIO_GETINFO");
        !           224:
1.4       millert   225:        while (argc) {
                    226:                if ((fd = open(*argv, O_RDONLY)) < 0)
                    227:                        err(1, "cannot open %s", *argv);
                    228:
1.13    ! uwe       229:                AUDIO_INITINFO(&ai);
        !           230:
        !           231:                ai.play.sample_rate = ai_defaults.play.sample_rate;
        !           232:                ai.play.channels    = ai_defaults.play.channels;
        !           233:                ai.play.encoding    = ai_defaults.play.encoding;
        !           234:                ai.play.precision   = ai_defaults.play.precision;
        !           235:
1.11      jaredy    236:                if (read(fd, magic, sizeof(magic)) != sizeof(magic) ||
                    237:                    strncmp(magic, ".snd", 4)) {
1.4       millert   238:                        /*
                    239:                         * not an .au file, bad header.
1.13    ! uwe       240:                         * Check if it could be a .wav file and set
        !           241:                         * the playback parameters in ai.
1.4       millert   242:                         */
1.13    ! uwe       243:                        if (strncmp(magic, "RIFF", 4) ||
        !           244:                            readwaveheader(fd, &ai)) {
        !           245:                                /*
        !           246:                                 * Assume raw audio data since that's
        !           247:                                 * what /dev/audio generates by default.
        !           248:                                 */
        !           249:                                if (lseek(fd, 0, SEEK_SET) == -1)
        !           250:                                        warn("lseek");
        !           251:                        }
1.4       millert   252:                } else {
1.11      jaredy    253:                        if (read(fd, &data, sizeof(data)) == sizeof(data)) {
                    254:                                data = ntohl(data);
                    255:                                if (lseek(fd, (off_t)data, SEEK_SET) == -1)
                    256:                                        warn("lseek");
                    257:                        }
1.4       millert   258:                }
1.13    ! uwe       259:
        !           260:                if (playfile(fd, dev, &ai) < 0)
1.4       millert   261:                        exit(1);
1.10      ian       262:                (void) close(fd);
1.4       millert   263:                argc--;
                    264:                argv++;
                    265:        }
                    266:        exit(0);
1.11      jaredy    267: }
                    268:
                    269: void
                    270: usage(void)
                    271: {
                    272:        extern char *__progname;
                    273:
                    274:        fprintf(stderr, "usage: %s [-f device] file ...\n", __progname);
                    275:        exit(1);
1.1       kstailey  276: }