audio.c revision 1.1 1 #include <sys/types.h>
2 #include <sys/audioio.h>
3 #include <sys/ioctl.h>
4 #include <sys/time.h>
5
6 #include <ctype.h>
7 #include <err.h>
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11
12 #include "libaudio.h"
13
14 /* back and forth between encodings */
15 struct {
16 char *ename;
17 int eno;
18 } encs[] = {
19 { AudioEmulaw, AUDIO_ENCODING_ULAW },
20 { "ulaw", AUDIO_ENCODING_ULAW },
21 { AudioEalaw, AUDIO_ENCODING_ALAW },
22 { AudioEslinear, AUDIO_ENCODING_SLINEAR },
23 { "linear", AUDIO_ENCODING_SLINEAR },
24 { AudioEulinear, AUDIO_ENCODING_ULINEAR },
25 { AudioEadpcm, AUDIO_ENCODING_ADPCM },
26 { "ADPCM", AUDIO_ENCODING_ADPCM },
27 { AudioEslinear_le, AUDIO_ENCODING_SLINEAR_LE },
28 { "linear_le", AUDIO_ENCODING_SLINEAR_LE },
29 { AudioEulinear_le, AUDIO_ENCODING_ULINEAR_LE },
30 { AudioEslinear_be, AUDIO_ENCODING_SLINEAR_BE },
31 { "linear_be", AUDIO_ENCODING_SLINEAR_BE },
32 { AudioEulinear_be, AUDIO_ENCODING_ULINEAR_BE },
33 { AudioEmpeg_l1_stream, AUDIO_ENCODING_MPEG_L1_STREAM },
34 { AudioEmpeg_l1_packets,AUDIO_ENCODING_MPEG_L1_PACKETS },
35 { AudioEmpeg_l1_system, AUDIO_ENCODING_MPEG_L1_SYSTEM },
36 { AudioEmpeg_l2_stream, AUDIO_ENCODING_MPEG_L2_STREAM },
37 { AudioEmpeg_l2_packets,AUDIO_ENCODING_MPEG_L2_PACKETS },
38 { AudioEmpeg_l2_system, AUDIO_ENCODING_MPEG_L2_SYSTEM },
39 { 0, -1 }
40 };
41
42
43 char *
44 audio_enc_from_val(val)
45 int val;
46 {
47 int i;
48
49 for (i = 0; encs[i].ename; i++)
50 if (encs[i].eno == val)
51 break;
52 return (encs[i].ename);
53 }
54
55 int
56 audio_enc_to_val(enc)
57 const char *enc;
58 {
59 int i;
60
61 for (i = 0; encs[i].ename; i++)
62 if (strcmp(encs[i].ename, enc) == 0)
63 break;
64 if (encs[i].ename)
65 return (encs[i].eno);
66 else
67 return (-1);
68 }
69
70 int
71 audio_parse_encoding(encoding_str, fd, encp, precp)
72 char *encoding_str;
73 int fd;
74 int *encp;
75 int *precp;
76 {
77 int i, prec = 0;
78 char *colon, *star;
79
80 colon = strchr(encoding_str, ':');
81 if (colon) {
82 *colon++ = '\0';
83 if (*colon)
84 prec = atoi(colon);
85 }
86 star = strrchr(encoding_str, '*');
87 if (star)
88 *star = '\0';
89 for (i = 0; ; i++) {
90 audio_encoding_t enc;
91
92 enc.index = i;
93 if (ioctl(fd, AUDIO_GETENC, &enc) < 0)
94 break;
95
96 if (strcasecmp(enc.name, encoding_str) == 0 &&
97 (prec == 0 || prec == enc.precision)) {
98 *encp = enc.encoding;
99 *precp = enc.precision;
100 return (0);
101 }
102
103 }
104 return (1);
105 }
106
107 /*
108 * SunOS/NeXT .au format helpers
109 */
110 struct {
111 int file_encoding;
112 int encoding;
113 int precision;
114 } file2sw_encodings[] = {
115 { AUDIO_FILE_ENCODING_MULAW_8, AUDIO_ENCODING_ULAW, 8 },
116 { AUDIO_FILE_ENCODING_LINEAR_8, AUDIO_ENCODING_ULINEAR_BE, 8 },
117 { AUDIO_FILE_ENCODING_LINEAR_16, AUDIO_ENCODING_ULINEAR_BE, 16 },
118 { AUDIO_FILE_ENCODING_LINEAR_24, AUDIO_ENCODING_ULINEAR_BE, 24 },
119 { AUDIO_FILE_ENCODING_LINEAR_32, AUDIO_ENCODING_ULINEAR_BE, 32 },
120 #if 0
121 { AUDIO_FILE_ENCODING_FLOAT, AUDIO_ENCODING_ULAW, 32 },
122 { AUDIO_FILE_ENCODING_DOUBLE, AUDIO_ENCODING_ULAW, 64 },
123 { AUDIO_FILE_ENCODING_ADPCM_G721, AUDIO_ENCODING_ULAW, 4 },
124 { AUDIO_FILE_ENCODING_ADPCM_G722, AUDIO_ENCODING_ULAW, 0 },
125 { AUDIO_FILE_ENCODING_ADPCM_G723_3, AUDIO_ENCODING_ULAW, 3 },
126 { AUDIO_FILE_ENCODING_ADPCM_G723_5, AUDIO_ENCODING_ULAW, 5 },
127 #endif
128 { AUDIO_FILE_ENCODING_ALAW_8, AUDIO_ENCODING_ALAW, 8 },
129 { -1, -1 }
130 };
131
132 int
133 audio_get_sun_encoding(sun_encoding, encp, precp)
134 int sun_encoding;
135 int *encp;
136 int *precp;
137 {
138 int i;
139
140 for (i = 0; file2sw_encodings[i].file_encoding != -1; i++)
141 if (file2sw_encodings[i].file_encoding == sun_encoding) {
142 *precp = file2sw_encodings[i].precision;
143 *encp = file2sw_encodings[i].encoding;
144 return (0);
145 }
146 return (1);
147 }
148
149 /*
150 * sample header is:
151 *
152 * RIFF\^@^C^@WAVEfmt ^P^@^@^@^A^@^B^@D<AC>^@^@^P<B1>^B^@^D^@^P^@data^@^@^C^@^@^@^@^@^@^@^@^@^@
153 *
154 */
155 /*
156 * WAV format helpers
157 */
158 /*
159 * find a .wav header, etc. returns header length on success
160 */
161 size_t
162 audio_parse_wav_hdr(hdr, sz, enc, prec, sample, channels)
163 void *hdr;
164 size_t sz;
165 int *enc;
166 int *prec;
167 int *sample;
168 int *channels;
169 {
170 char *where = hdr;
171 wav_audioheaderpart *part;
172 wav_audioheaderfmt *fmt;
173 char *end = (((char *)hdr) + sz);
174 int newenc, newprec;
175
176 if (sz < 32)
177 return (AUDIO_ENOENT);
178
179 if (strncmp(where, "RIFF", 4))
180 return (AUDIO_ENOENT);
181 where += 8;
182 if (strncmp(where, "WAVE", 4))
183 return (AUDIO_ENOENT);
184 where += 4;
185
186 do {
187 part = (wav_audioheaderpart *)where;
188 where += getle32(part->len) + 8;
189 } while (where < end && strncmp(part->name, "fmt ", 4));
190
191 /* too short ? */
192 if (where + 16 > end)
193 return (AUDIO_ESHORTHDR);
194
195 fmt = (wav_audioheaderfmt *)(part + 1);
196
197 #if 0
198 printf("fmt header is:\n\t%d\ttag\n\t%d\tchannels\n\t%d\tsample rate\n\t%d\tavg_bps\n\t%d\talignment\n\t%d\tbits per sample\n", getle16(fmt->tag), getle16(fmt->channels), getle32(fmt->sample_rate), getle32(fmt->avg_bps), getle16(fmt->alignment), getle16(fmt->bits_per_sample));
199 #endif
200
201 switch (getle16(fmt->tag)) {
202 case WAVE_FORMAT_UNKNOWN:
203 case WAVE_FORMAT_ADPCM:
204 case WAVE_FORMAT_OKI_ADPCM:
205 case WAVE_FORMAT_DIGISTD:
206 case WAVE_FORMAT_DIGIFIX:
207 case IBM_FORMAT_MULAW:
208 case IBM_FORMAT_ALAW:
209 case IBM_FORMAT_ADPCM:
210 default:
211 return (AUDIO_EWAVUNSUPP);
212
213 case WAVE_FORMAT_PCM:
214 switch (getle16(fmt->bits_per_sample)) {
215 case 8:
216 newprec = 8;
217 break;
218 case 16:
219 newprec = 16;
220 break;
221 case 24:
222 newprec = 24;
223 break;
224 case 32:
225 newprec = 32;
226 break;
227 default:
228 return (AUDIO_EWAVBADPCM);
229 }
230 newenc = AUDIO_ENCODING_ULINEAR;;
231 break;
232 case WAVE_FORMAT_ALAW:
233 newenc = AUDIO_ENCODING_ALAW;
234 newprec = 8;
235 break;
236 case WAVE_FORMAT_MULAW:
237 newenc = AUDIO_ENCODING_ULAW;
238 newprec = 8;
239 break;
240 }
241
242 do {
243 part = (wav_audioheaderpart *)where;
244 where += (getle32(part->len) + 8);
245 } while ((char *)where < end && strncmp(part->name, "data", 4));
246
247 if (where <= end) {
248 *channels = getle16(fmt->channels);
249 *sample = getle32(fmt->sample_rate);
250 *enc = newenc;
251 *prec = newprec;
252 part++;
253 return ((char *)part - (char *)hdr);
254 }
255 return (AUDIO_EWAVNODATA);
256 }
257
258 /*
259 * these belong elsewhere??
260 */
261 void
262 decode_int(arg, intp)
263 const char *arg;
264 int *intp;
265 {
266 char *ep;
267 int ret;
268
269 ret = strtoul(arg, &ep, 0);
270
271 if (ep[0] == '\0') {
272 *intp = ret;
273 return;
274 }
275 errx(1, "argument `%s' not a valid integer", arg);
276 }
277
278 #include <stdio.h>
279 void
280 decode_time(arg, tvp)
281 const char *arg;
282 struct timeval *tvp;
283 {
284 char *s, *colon, *dot;
285 char *copy = strdup(arg);
286 int first;
287
288 if (copy == NULL)
289 err(1, "could not allocate a copy of %s", arg);
290
291 tvp->tv_sec = tvp->tv_usec = 0;
292 s = copy;
293
294 /* handle [hh:]mm:ss.dd */
295 if ((colon = strchr(s, ':'))) {
296 *colon++ = '\0';
297 decode_int(s, &first);
298 tvp->tv_sec = first * 60; /* minutes */
299 s = colon;
300
301 if ((colon = strchr(s, ':'))) {
302 *colon++ = '\0';
303 decode_int(s, &first);
304 tvp->tv_sec += first;
305 tvp->tv_sec *= 60; /* minutes and hours */
306 s = colon;
307 }
308 }
309 if ((dot = strchr(s, '.'))) {
310 int i, base = 100000;
311
312 *dot++ = '\0';
313
314 for (i = 0; i < 6; i++, base /= 10) {
315 if (!dot[i])
316 break;
317 if (!isdigit(dot[i]))
318 errx(1, "argument `%s' is not a value time specification", arg);
319 tvp->tv_usec += base * (dot[i] - '0');
320 }
321 }
322 decode_int(s, &first);
323 tvp->tv_sec += first;
324 #if 0
325 printf("tvp->tv_sec = %ld, tvp->tv_usec = %ld\n", tvp->tv_sec, tvp->tv_usec);
326 #endif
327
328 free(copy);
329 }
330
331 /*
332 * decode a string into an encoding value.
333 */
334 void
335 decode_encoding(arg, encp)
336 const char *arg;
337 int *encp;
338 {
339 size_t len;
340 int i;
341
342 len = strlen(arg);
343 for (i = 0; encs[i].ename; i++)
344 if (strncmp(encs[i].ename, arg, len) == 0) {
345 *encp = encs[i].eno;
346 return;
347 }
348 errx(1, "unknown encoding `%s'", arg);
349 }
350
351 const char *const audio_errlist[] = {
352 "no audio entry",
353 "short header",
354 "unsupported WAV format",
355 "bad (unsupported) WAV PCM format",
356 "no WAV audio data",
357 };
358
359 const char *
360 audio_errstring(errval)
361 int errval;
362 {
363
364 errval = -errval;
365 if (errval < 1 || errval > AUDIO_MAXERRNO)
366 return "Invalid error";
367 return audio_errlist[errval];
368 }
369