Annotation of src/usr.bin/aucat/legacy.c, Revision 1.3
1.3 ! ratchov 1: /* $OpenBSD: legacy.c,v 1.2 2008/08/14 09:58:55 ratchov Exp $ */
1.1 ratchov 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:
1.2 ratchov 31: #include <sys/types.h>
32: #include <sys/ioctl.h>
33: #include <sys/audioio.h>
34:
1.1 ratchov 35: #include <fcntl.h>
1.2 ratchov 36: #include <string.h>
1.1 ratchov 37: #include <unistd.h>
38: #include <err.h>
39:
1.3 ! ratchov 40: #include "wav.h"
1.1 ratchov 41:
42:
43: /* headerless data files. played at /dev/audio's defaults.
44: */
45: #define FMT_RAW 0
46:
47: /* Sun/NeXT .au files. header is skipped and /dev/audio is configured
48: * for monaural 8-bit ulaw @ 8kHz, the de facto format for .au files,
49: * as well as the historical default configuration for /dev/audio.
50: */
51: #define FMT_AU 1
52:
53: /* RIFF WAV files. header is parsed for format details which are
54: * applied to /dev/audio.
55: */
56: #define FMT_WAV 2
57:
1.3 ! ratchov 58:
! 59: /*
! 60: * Convert sun device parameters to struct aparams
! 61: */
! 62: int
! 63: sun_infotopar(struct audio_prinfo *ai, struct aparams *par)
! 64: {
! 65: par->rate = ai->sample_rate;
! 66: par->bps = ai->precision / 8;
! 67: par->bits = ai->precision;
! 68: par->cmax = par->cmin + ai->channels - 1;
! 69: if (par->cmax > NCHAN_MAX - 1) {
! 70: warnx("%u:%u: channel range out of bounds",
! 71: par->cmin, par->cmax);
! 72: return 0;
! 73: }
! 74: par->msb = 1;
! 75: switch (ai->encoding) {
! 76: case AUDIO_ENCODING_SLINEAR_LE:
! 77: par->le = 1;
! 78: par->sig = 1;
! 79: break;
! 80: case AUDIO_ENCODING_SLINEAR_BE:
! 81: par->le = 0;
! 82: par->sig = 1;
! 83: break;
! 84: case AUDIO_ENCODING_ULINEAR_LE:
! 85: par->le = 1;
! 86: par->sig = 0;
! 87: break;
! 88: case AUDIO_ENCODING_ULINEAR_BE:
! 89: par->le = 0;
! 90: par->sig = 0;
! 91: break;
! 92: case AUDIO_ENCODING_SLINEAR:
! 93: par->le = NATIVE_LE;
! 94: par->sig = 1;
! 95: break;
! 96: case AUDIO_ENCODING_ULINEAR:
! 97: par->le = NATIVE_LE;
! 98: par->sig = 0;
! 99: break;
! 100: default:
! 101: warnx("only linear encodings are supported for audio devices");
! 102: return 0;
! 103: }
! 104: return 1;
! 105: }
! 106:
! 107: /*
! 108: * Convert struct aparams to sun device parameters.
! 109: */
! 110: void
! 111: sun_partoinfo(struct audio_prinfo *ai, struct aparams *par)
! 112: {
! 113: ai->sample_rate = par->rate;
! 114: ai->precision = par->bps * 8;
! 115: ai->channels = par->cmax - par->cmin + 1;
! 116: if (par->le && par->sig) {
! 117: ai->encoding = AUDIO_ENCODING_SLINEAR_LE;
! 118: } else if (!par->le && par->sig) {
! 119: ai->encoding = AUDIO_ENCODING_SLINEAR_BE;
! 120: } else if (par->le && !par->sig) {
! 121: ai->encoding = AUDIO_ENCODING_ULINEAR_LE;
! 122: } else {
! 123: ai->encoding = AUDIO_ENCODING_ULINEAR_BE;
! 124: }
! 125: }
1.1 ratchov 126:
127: int
128: legacy_play(char *dev, char *aufile)
129: {
130: struct audio_prinfo ai;
131: struct audio_info info;
132: struct aparams par;
133: ssize_t rd;
134: off_t datasz;
135: char buf[5120];
136: int afd, fd, fmt = FMT_RAW;
137: u_int32_t pos = 0;
138: char magic[4];
139:
140: if ((fd = open(aufile, O_RDONLY)) < 0) {
141: warn("cannot open %s", aufile);
142: return(1);
143: }
144:
145: if (read(fd, magic, sizeof(magic)) != sizeof(magic)) {
146: /* read() error, or the file is smaller than sizeof(magic).
147: * treat as a raw file, like previous versions of aucat.
148: */
149: } else if (!strncmp(magic, ".snd", 4)) {
150: fmt = FMT_AU;
151: if (read(fd, &pos, sizeof(pos)) == sizeof(pos))
152: pos = ntohl(pos);
153: } else if (!strncmp(magic, "RIFF", 4) &&
154: wav_readhdr(fd, &par, &datasz)) {
155: fmt = FMT_WAV;
156: }
157:
158: /* seek to start of audio data. wav_readhdr already took care
159: * of this for FMT_WAV.
160: */
161: if (fmt == FMT_RAW || fmt == FMT_AU)
162: if (lseek(fd, (off_t)pos, SEEK_SET) == -1)
163: warn("lseek");
164:
165: if ((afd = open(dev, O_WRONLY)) < 0) {
166: warn("can't open %s", dev);
167: return(1);
168: }
169:
170: AUDIO_INITINFO(&info);
171: ai = info.play;
172:
173: switch(fmt) {
174: case FMT_WAV:
175: sun_partoinfo(&ai, &par);
176: break;
177: case FMT_AU:
178: ai.encoding = AUDIO_ENCODING_ULAW;
179: ai.precision = 8;
180: ai.sample_rate = 8000;
181: ai.channels = 1;
182: break;
183: case FMT_RAW:
184: default:
185: break;
186: }
187:
188: info.play = ai;
189: if (ioctl(afd, AUDIO_SETINFO, &info) < 0) {
190: warn("%s", dev);
191: /* only WAV could fail in previous aucat versions (unless
192: * the parameters returned by AUDIO_GETINFO would fail,
193: * which is unlikely)
194: */
195: if (fmt == FMT_WAV)
196: return(1);
197: }
198:
199: /* parameters may be silently modified. see audio(9)'s
200: * description of set_params. for compatability with previous
201: * aucat versions, continue running if something doesn't match.
202: */
203: (void) ioctl(afd, AUDIO_GETINFO, &info);
204: if (info.play.encoding != ai.encoding ||
205: info.play.precision != ai.precision ||
206: info.play.channels != ai.channels ||
207: /* devices may return a very close rate, such as 44099 when
208: * 44100 was requested. the difference is inaudible. allow
209: * 2% deviation as an example of how to cope.
210: */
211: (info.play.sample_rate > ai.sample_rate * 1.02 ||
212: info.play.sample_rate < ai.sample_rate * 0.98)) {
213: warnx("format not supported by %s", dev);
214: }
215:
216: while ((rd = read(fd, buf, sizeof(buf))) > 0)
217: if (write(afd, buf, rd) != rd)
218: warn("write");
219: if (rd == -1)
220: warn("read");
221:
222: (void) close(afd);
223: (void) close(fd);
224:
225: return(0);
226: }