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