record.c revision 1.48 1 1.48 mrg /* $NetBSD: record.c,v 1.48 2010/12/29 13:09:03 mrg Exp $ */
2 1.2 mrg
3 1.2 mrg /*
4 1.48 mrg * Copyright (c) 1999, 2002, 2003, 2005, 2010 Matthew R. Green
5 1.2 mrg * All rights reserved.
6 1.2 mrg *
7 1.2 mrg * Redistribution and use in source and binary forms, with or without
8 1.2 mrg * modification, are permitted provided that the following conditions
9 1.2 mrg * are met:
10 1.2 mrg * 1. Redistributions of source code must retain the above copyright
11 1.2 mrg * notice, this list of conditions and the following disclaimer.
12 1.2 mrg * 2. Redistributions in binary form must reproduce the above copyright
13 1.2 mrg * notice, this list of conditions and the following disclaimer in the
14 1.2 mrg * documentation and/or other materials provided with the distribution.
15 1.2 mrg *
16 1.2 mrg * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 1.2 mrg * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 1.2 mrg * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 1.2 mrg * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 1.2 mrg * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21 1.2 mrg * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 1.2 mrg * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23 1.2 mrg * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24 1.2 mrg * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 1.2 mrg * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 1.2 mrg * SUCH DAMAGE.
27 1.2 mrg */
28 1.2 mrg
29 1.1 mrg /*
30 1.1 mrg * SunOS compatible audiorecord(1)
31 1.1 mrg */
32 1.33 agc #include <sys/cdefs.h>
33 1.33 agc
34 1.33 agc #ifndef lint
35 1.48 mrg __RCSID("$NetBSD: record.c,v 1.48 2010/12/29 13:09:03 mrg Exp $");
36 1.33 agc #endif
37 1.33 agc
38 1.1 mrg
39 1.48 mrg #include <sys/param.h>
40 1.1 mrg #include <sys/audioio.h>
41 1.1 mrg #include <sys/ioctl.h>
42 1.1 mrg #include <sys/time.h>
43 1.1 mrg #include <sys/uio.h>
44 1.1 mrg
45 1.1 mrg #include <err.h>
46 1.1 mrg #include <fcntl.h>
47 1.1 mrg #include <paths.h>
48 1.1 mrg #include <signal.h>
49 1.1 mrg #include <stdio.h>
50 1.1 mrg #include <stdlib.h>
51 1.1 mrg #include <string.h>
52 1.1 mrg #include <unistd.h>
53 1.44 lukem #include <util.h>
54 1.1 mrg
55 1.1 mrg #include "libaudio.h"
56 1.19 mrg #include "auconv.h"
57 1.1 mrg
58 1.1 mrg audio_info_t info, oinfo;
59 1.1 mrg ssize_t total_size = -1;
60 1.21 mrg const char *device;
61 1.27 mrg int format = AUDIO_FORMAT_DEFAULT;
62 1.1 mrg char *header_info;
63 1.1 mrg char default_info[8] = { '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0' };
64 1.23 jdolecek int audiofd, outfd;
65 1.1 mrg int qflag, aflag, fflag;
66 1.1 mrg int verbose;
67 1.17 mrg int monitor_gain, omonitor_gain;
68 1.17 mrg int gain;
69 1.1 mrg int balance;
70 1.1 mrg int port;
71 1.1 mrg int encoding;
72 1.1 mrg char *encoding_str;
73 1.1 mrg int precision;
74 1.1 mrg int sample_rate;
75 1.1 mrg int channels;
76 1.1 mrg struct timeval record_time;
77 1.32 mrg struct timeval start_time;
78 1.1 mrg
79 1.37 mycroft void (*conv_func) (u_char *, int);
80 1.18 mrg
81 1.12 mrg void usage (void);
82 1.12 mrg int main (int, char *[]);
83 1.12 mrg int timeleft (struct timeval *, struct timeval *);
84 1.45 perry void cleanup (int) __dead;
85 1.17 mrg int write_header_sun (void **, size_t *, int *);
86 1.17 mrg int write_header_wav (void **, size_t *, int *);
87 1.12 mrg void write_header (void);
88 1.12 mrg void rewrite_header (void);
89 1.1 mrg
90 1.1 mrg int
91 1.1 mrg main(argc, argv)
92 1.1 mrg int argc;
93 1.1 mrg char *argv[];
94 1.1 mrg {
95 1.43 mrg u_char *buffer;
96 1.48 mrg size_t len, bufsize = 0;
97 1.8 mrg int ch, no_time_limit = 1;
98 1.24 augustss const char *defdevice = _PATH_SOUND;
99 1.1 mrg
100 1.48 mrg while ((ch = getopt(argc, argv, "ab:B:C:F:c:d:e:fhi:m:P:p:qt:s:Vv:")) != -1) {
101 1.1 mrg switch (ch) {
102 1.1 mrg case 'a':
103 1.1 mrg aflag++;
104 1.1 mrg break;
105 1.1 mrg case 'b':
106 1.1 mrg decode_int(optarg, &balance);
107 1.1 mrg if (balance < 0 || balance > 63)
108 1.30 grant errx(1, "balance must be between 0 and 63");
109 1.1 mrg break;
110 1.48 mrg case 'B':
111 1.48 mrg bufsize = strsuftoll("read buffer size", optarg,
112 1.48 mrg 1, UINT_MAX);
113 1.48 mrg break;
114 1.1 mrg case 'C':
115 1.23 jdolecek /* Ignore, compatibility */
116 1.1 mrg break;
117 1.17 mrg case 'F':
118 1.17 mrg format = audio_format_from_str(optarg);
119 1.17 mrg if (format < 0)
120 1.27 mrg errx(1, "Unknown audio format; supported "
121 1.27 mrg "formats: \"sun\", \"wav\", and \"none\"");
122 1.17 mrg break;
123 1.1 mrg case 'c':
124 1.1 mrg decode_int(optarg, &channels);
125 1.1 mrg if (channels < 0 || channels > 16)
126 1.30 grant errx(1, "channels must be between 0 and 16");
127 1.1 mrg break;
128 1.1 mrg case 'd':
129 1.1 mrg device = optarg;
130 1.1 mrg break;
131 1.1 mrg case 'e':
132 1.1 mrg encoding_str = optarg;
133 1.1 mrg break;
134 1.1 mrg case 'f':
135 1.1 mrg fflag++;
136 1.1 mrg break;
137 1.1 mrg case 'i':
138 1.1 mrg header_info = optarg;
139 1.1 mrg break;
140 1.1 mrg case 'm':
141 1.17 mrg decode_int(optarg, &monitor_gain);
142 1.17 mrg if (monitor_gain < 0 || monitor_gain > 255)
143 1.30 grant errx(1, "monitor volume must be between 0 and 255");
144 1.1 mrg break;
145 1.1 mrg case 'P':
146 1.1 mrg decode_int(optarg, &precision);
147 1.15 minoura if (precision != 4 && precision != 8 &&
148 1.15 minoura precision != 16 && precision != 24 &&
149 1.15 minoura precision != 32)
150 1.15 minoura errx(1, "precision must be between 4, 8, 16, 24 or 32");
151 1.1 mrg break;
152 1.1 mrg case 'p':
153 1.1 mrg len = strlen(optarg);
154 1.1 mrg
155 1.1 mrg if (strncmp(optarg, "mic", len) == 0)
156 1.1 mrg port |= AUDIO_MICROPHONE;
157 1.1 mrg else if (strncmp(optarg, "cd", len) == 0 ||
158 1.1 mrg strncmp(optarg, "internal-cd", len) == 0)
159 1.1 mrg port |= AUDIO_CD;
160 1.1 mrg else if (strncmp(optarg, "line", len) == 0)
161 1.1 mrg port |= AUDIO_LINE_IN;
162 1.1 mrg else
163 1.1 mrg errx(1,
164 1.1 mrg "port must be `cd', `internal-cd', `mic', or `line'");
165 1.1 mrg break;
166 1.1 mrg case 'q':
167 1.1 mrg qflag++;
168 1.1 mrg break;
169 1.1 mrg case 's':
170 1.1 mrg decode_int(optarg, &sample_rate);
171 1.1 mrg if (sample_rate < 0 || sample_rate > 48000 * 2) /* XXX */
172 1.30 grant errx(1, "sample rate must be between 0 and 96000");
173 1.1 mrg break;
174 1.1 mrg case 't':
175 1.8 mrg no_time_limit = 0;
176 1.1 mrg decode_time(optarg, &record_time);
177 1.1 mrg break;
178 1.1 mrg case 'V':
179 1.1 mrg verbose++;
180 1.1 mrg break;
181 1.1 mrg case 'v':
182 1.17 mrg decode_int(optarg, &gain);
183 1.17 mrg if (gain < 0 || gain > 255)
184 1.30 grant errx(1, "volume must be between 0 and 255");
185 1.1 mrg break;
186 1.1 mrg /* case 'h': */
187 1.1 mrg default:
188 1.1 mrg usage();
189 1.1 mrg /* NOTREACHED */
190 1.1 mrg }
191 1.1 mrg }
192 1.1 mrg argc -= optind;
193 1.1 mrg argv += optind;
194 1.1 mrg
195 1.39 mrg if (argc != 1)
196 1.39 mrg usage();
197 1.39 mrg
198 1.1 mrg /*
199 1.40 mrg * convert the encoding string into a value.
200 1.40 mrg */
201 1.40 mrg if (encoding_str) {
202 1.40 mrg encoding = audio_enc_to_val(encoding_str);
203 1.40 mrg if (encoding == -1)
204 1.40 mrg errx(1, "unknown encoding, bailing...");
205 1.40 mrg }
206 1.40 mrg
207 1.40 mrg /*
208 1.40 mrg * open the output file
209 1.40 mrg */
210 1.42 gson if (argv[0][0] != '-' || argv[0][1] != '\0') {
211 1.40 mrg /* intuit the file type from the name */
212 1.40 mrg if (format == AUDIO_FORMAT_DEFAULT)
213 1.40 mrg {
214 1.40 mrg size_t flen = strlen(*argv);
215 1.40 mrg const char *arg = *argv;
216 1.40 mrg
217 1.40 mrg if (strcasecmp(arg + flen - 3, ".au") == 0)
218 1.40 mrg format = AUDIO_FORMAT_SUN;
219 1.40 mrg else if (strcasecmp(arg + flen - 4, ".wav") == 0)
220 1.40 mrg format = AUDIO_FORMAT_WAV;
221 1.40 mrg }
222 1.40 mrg outfd = open(*argv, O_CREAT|(aflag ? O_APPEND : O_TRUNC)|O_WRONLY, 0666);
223 1.40 mrg if (outfd < 0)
224 1.40 mrg err(1, "could not open %s", *argv);
225 1.40 mrg } else
226 1.40 mrg outfd = STDOUT_FILENO;
227 1.40 mrg
228 1.40 mrg /*
229 1.34 mrg * open the audio device
230 1.1 mrg */
231 1.6 kleink if (device == NULL && (device = getenv("AUDIODEVICE")) == NULL &&
232 1.6 kleink (device = getenv("AUDIODEV")) == NULL) /* Sun compatibility */
233 1.24 augustss device = defdevice;
234 1.1 mrg
235 1.1 mrg audiofd = open(device, O_RDONLY);
236 1.24 augustss if (audiofd < 0 && device == defdevice) {
237 1.22 augustss device = _PATH_SOUND0;
238 1.28 uwe audiofd = open(device, O_RDONLY);
239 1.22 augustss }
240 1.1 mrg if (audiofd < 0)
241 1.1 mrg err(1, "failed to open %s", device);
242 1.1 mrg
243 1.1 mrg /*
244 1.1 mrg * work out the buffer size to use, and allocate it. also work out
245 1.1 mrg * what the old monitor gain value is, so that we can reset it later.
246 1.1 mrg */
247 1.23 jdolecek if (ioctl(audiofd, AUDIO_GETINFO, &oinfo) < 0)
248 1.1 mrg err(1, "failed to get audio info");
249 1.48 mrg if (bufsize == 0)
250 1.48 mrg bufsize = oinfo.record.buffer_size;
251 1.1 mrg if (bufsize < 32 * 1024)
252 1.1 mrg bufsize = 32 * 1024;
253 1.17 mrg omonitor_gain = oinfo.monitor_gain;
254 1.1 mrg
255 1.1 mrg buffer = malloc(bufsize);
256 1.1 mrg if (buffer == NULL)
257 1.1 mrg err(1, "couldn't malloc buffer of %d size", (int)bufsize);
258 1.1 mrg
259 1.1 mrg /*
260 1.17 mrg * set up audio device for recording with the speified parameters
261 1.17 mrg */
262 1.17 mrg AUDIO_INITINFO(&info);
263 1.17 mrg
264 1.17 mrg /*
265 1.17 mrg * for these, get the current values for stuffing into the header
266 1.17 mrg */
267 1.40 mrg #define SETINFO(x) if (x) \
268 1.40 mrg info.record.x = x; \
269 1.40 mrg else \
270 1.40 mrg info.record.x = x = oinfo.record.x;
271 1.40 mrg SETINFO (sample_rate)
272 1.40 mrg SETINFO (channels)
273 1.40 mrg SETINFO (precision)
274 1.40 mrg SETINFO (encoding)
275 1.40 mrg SETINFO (gain)
276 1.40 mrg SETINFO (port)
277 1.40 mrg SETINFO (balance)
278 1.17 mrg #undef SETINFO
279 1.17 mrg
280 1.17 mrg if (monitor_gain)
281 1.17 mrg info.monitor_gain = monitor_gain;
282 1.17 mrg else
283 1.17 mrg monitor_gain = oinfo.monitor_gain;
284 1.1 mrg
285 1.1 mrg info.mode = AUMODE_RECORD;
286 1.23 jdolecek if (ioctl(audiofd, AUDIO_SETINFO, &info) < 0)
287 1.29 mrg err(1, "failed to set audio info");
288 1.1 mrg
289 1.1 mrg signal(SIGINT, cleanup);
290 1.1 mrg write_header();
291 1.1 mrg total_size = 0;
292 1.1 mrg
293 1.27 mrg if (verbose && conv_func) {
294 1.27 mrg const char *s = NULL;
295 1.27 mrg
296 1.27 mrg if (conv_func == swap_bytes)
297 1.27 mrg s = "swap bytes (16 bit)";
298 1.27 mrg else if (conv_func == swap_bytes32)
299 1.27 mrg s = "swap bytes (32 bit)";
300 1.27 mrg else if (conv_func == change_sign16_be)
301 1.27 mrg s = "change sign (big-endian, 16 bit)";
302 1.27 mrg else if (conv_func == change_sign16_le)
303 1.27 mrg s = "change sign (little-endian, 16 bit)";
304 1.27 mrg else if (conv_func == change_sign32_be)
305 1.27 mrg s = "change sign (big-endian, 32 bit)";
306 1.27 mrg else if (conv_func == change_sign32_le)
307 1.27 mrg s = "change sign (little-endian, 32 bit)";
308 1.27 mrg else if (conv_func == change_sign16_swap_bytes_be)
309 1.27 mrg s = "change sign & swap bytes (big-endian, 16 bit)";
310 1.27 mrg else if (conv_func == change_sign16_swap_bytes_le)
311 1.27 mrg s = "change sign & swap bytes (little-endian, 16 bit)";
312 1.27 mrg else if (conv_func == change_sign32_swap_bytes_be)
313 1.27 mrg s = "change sign (big-endian, 32 bit)";
314 1.27 mrg else if (conv_func == change_sign32_swap_bytes_le)
315 1.27 mrg s = "change sign & swap bytes (little-endian, 32 bit)";
316 1.27 mrg
317 1.27 mrg if (s)
318 1.27 mrg fprintf(stderr, "%s: converting, using function: %s\n",
319 1.27 mrg getprogname(), s);
320 1.27 mrg else
321 1.27 mrg fprintf(stderr, "%s: using unnamed conversion "
322 1.27 mrg "function\n", getprogname());
323 1.27 mrg }
324 1.27 mrg
325 1.27 mrg if (verbose)
326 1.27 mrg fprintf(stderr,
327 1.27 mrg "sample_rate=%d channels=%d precision=%d encoding=%s\n",
328 1.27 mrg info.record.sample_rate, info.record.channels,
329 1.27 mrg info.record.precision,
330 1.27 mrg audio_enc_from_val(info.record.encoding));
331 1.32 mrg
332 1.32 mrg if (!no_time_limit && verbose)
333 1.32 mrg fprintf(stderr, "recording for %lu seconds, %lu microseconds\n",
334 1.32 mrg (u_long)record_time.tv_sec, (u_long)record_time.tv_usec);
335 1.27 mrg
336 1.1 mrg (void)gettimeofday(&start_time, NULL);
337 1.8 mrg while (no_time_limit || timeleft(&start_time, &record_time)) {
338 1.47 lukem if ((size_t)read(audiofd, buffer, bufsize) != bufsize)
339 1.1 mrg err(1, "read failed");
340 1.18 mrg if (conv_func)
341 1.19 mrg (*conv_func)(buffer, bufsize);
342 1.47 lukem if ((size_t)write(outfd, buffer, bufsize) != bufsize)
343 1.1 mrg err(1, "write failed");
344 1.1 mrg total_size += bufsize;
345 1.1 mrg }
346 1.1 mrg cleanup(0);
347 1.1 mrg }
348 1.1 mrg
349 1.1 mrg int
350 1.1 mrg timeleft(start_tvp, record_tvp)
351 1.1 mrg struct timeval *start_tvp;
352 1.1 mrg struct timeval *record_tvp;
353 1.1 mrg {
354 1.1 mrg struct timeval now, diff;
355 1.1 mrg
356 1.1 mrg (void)gettimeofday(&now, NULL);
357 1.7 dmcmahil timersub(&now, start_tvp, &diff);
358 1.7 dmcmahil timersub(record_tvp, &diff, &now);
359 1.1 mrg
360 1.1 mrg return (now.tv_sec > 0 || (now.tv_sec == 0 && now.tv_usec > 0));
361 1.1 mrg }
362 1.1 mrg
363 1.1 mrg void
364 1.1 mrg cleanup(signo)
365 1.1 mrg int signo;
366 1.1 mrg {
367 1.1 mrg
368 1.1 mrg rewrite_header();
369 1.1 mrg close(outfd);
370 1.17 mrg if (omonitor_gain) {
371 1.1 mrg AUDIO_INITINFO(&info);
372 1.17 mrg info.monitor_gain = omonitor_gain;
373 1.23 jdolecek if (ioctl(audiofd, AUDIO_SETINFO, &info) < 0)
374 1.1 mrg err(1, "failed to reset audio info");
375 1.1 mrg }
376 1.23 jdolecek close(audiofd);
377 1.44 lukem if (signo != 0) {
378 1.44 lukem (void)raise_default_signal(signo);
379 1.44 lukem }
380 1.1 mrg exit(0);
381 1.1 mrg }
382 1.1 mrg
383 1.17 mrg int
384 1.17 mrg write_header_sun(hdrp, lenp, leftp)
385 1.17 mrg void **hdrp;
386 1.17 mrg size_t *lenp;
387 1.17 mrg int *leftp;
388 1.1 mrg {
389 1.16 mrg static int warned = 0;
390 1.17 mrg static sun_audioheader auh;
391 1.19 mrg int sunenc, oencoding = encoding;
392 1.11 mrg
393 1.27 mrg /* only perform conversions if we don't specify the encoding */
394 1.25 mrg switch (encoding) {
395 1.25 mrg case AUDIO_ENCODING_ULINEAR_LE:
396 1.25 mrg #if BYTE_ORDER == LITTLE_ENDIAN
397 1.25 mrg case AUDIO_ENCODING_ULINEAR:
398 1.25 mrg #endif
399 1.19 mrg if (precision == 16)
400 1.27 mrg conv_func = change_sign16_swap_bytes_le;
401 1.19 mrg else if (precision == 32)
402 1.27 mrg conv_func = change_sign32_swap_bytes_le;
403 1.21 mrg if (conv_func)
404 1.21 mrg encoding = AUDIO_ENCODING_SLINEAR_BE;
405 1.25 mrg break;
406 1.25 mrg
407 1.25 mrg case AUDIO_ENCODING_ULINEAR_BE:
408 1.25 mrg #if BYTE_ORDER == BIG_ENDIAN
409 1.25 mrg case AUDIO_ENCODING_ULINEAR:
410 1.25 mrg #endif
411 1.19 mrg if (precision == 16)
412 1.19 mrg conv_func = change_sign16_be;
413 1.19 mrg else if (precision == 32)
414 1.19 mrg conv_func = change_sign32_be;
415 1.21 mrg if (conv_func)
416 1.21 mrg encoding = AUDIO_ENCODING_SLINEAR_BE;
417 1.25 mrg break;
418 1.25 mrg
419 1.25 mrg case AUDIO_ENCODING_SLINEAR_LE:
420 1.25 mrg #if BYTE_ORDER == LITTLE_ENDIAN
421 1.25 mrg case AUDIO_ENCODING_SLINEAR:
422 1.25 mrg #endif
423 1.19 mrg if (precision == 16)
424 1.27 mrg conv_func = swap_bytes;
425 1.19 mrg else if (precision == 32)
426 1.27 mrg conv_func = swap_bytes32;
427 1.21 mrg if (conv_func)
428 1.21 mrg encoding = AUDIO_ENCODING_SLINEAR_BE;
429 1.25 mrg break;
430 1.25 mrg
431 1.25 mrg #if BYTE_ORDER == BIG_ENDIAN
432 1.25 mrg case AUDIO_ENCODING_SLINEAR:
433 1.25 mrg encoding = AUDIO_ENCODING_SLINEAR_BE;
434 1.25 mrg break;
435 1.25 mrg #endif
436 1.19 mrg }
437 1.19 mrg
438 1.11 mrg /* if we can't express this as a Sun header, don't write any */
439 1.11 mrg if (audio_encoding_to_sun(encoding, precision, &sunenc) != 0) {
440 1.25 mrg if (!qflag && !warned) {
441 1.25 mrg const char *s = audio_enc_from_val(oencoding);
442 1.25 mrg
443 1.25 mrg if (s == NULL)
444 1.25 mrg s = "(unknown)";
445 1.25 mrg warnx("failed to convert to sun encoding from %s "
446 1.25 mrg "(precision %d);\nSun audio header not written",
447 1.25 mrg s, precision);
448 1.25 mrg }
449 1.27 mrg format = AUDIO_FORMAT_NONE;
450 1.19 mrg conv_func = 0;
451 1.16 mrg warned = 1;
452 1.17 mrg return -1;
453 1.11 mrg }
454 1.1 mrg
455 1.1 mrg auh.magic = htonl(AUDIO_FILE_MAGIC);
456 1.1 mrg if (outfd == STDOUT_FILENO)
457 1.1 mrg auh.data_size = htonl(AUDIO_UNKNOWN_SIZE);
458 1.41 mrg else if (total_size != -1)
459 1.41 mrg auh.data_size = htonl(total_size);
460 1.1 mrg else
461 1.41 mrg auh.data_size = 0;
462 1.11 mrg auh.encoding = htonl(sunenc);
463 1.1 mrg auh.sample_rate = htonl(sample_rate);
464 1.1 mrg auh.channels = htonl(channels);
465 1.1 mrg if (header_info) {
466 1.1 mrg int len, infolen;
467 1.1 mrg
468 1.1 mrg infolen = ((len = strlen(header_info)) + 7) & 0xfffffff8;
469 1.17 mrg *leftp = infolen - len;
470 1.1 mrg auh.hdr_size = htonl(sizeof(auh) + infolen);
471 1.1 mrg } else {
472 1.17 mrg *leftp = sizeof(default_info);
473 1.17 mrg auh.hdr_size = htonl(sizeof(auh) + *leftp);
474 1.1 mrg }
475 1.17 mrg *(sun_audioheader **)hdrp = &auh;
476 1.17 mrg *lenp = sizeof auh;
477 1.17 mrg return 0;
478 1.17 mrg }
479 1.1 mrg
480 1.17 mrg int
481 1.17 mrg write_header_wav(hdrp, lenp, leftp)
482 1.17 mrg void **hdrp;
483 1.17 mrg size_t *lenp;
484 1.17 mrg int *leftp;
485 1.17 mrg {
486 1.17 mrg /*
487 1.17 mrg * WAV header we write looks like this:
488 1.17 mrg *
489 1.17 mrg * bytes purpose
490 1.17 mrg * 0-3 "RIFF"
491 1.17 mrg * 4-7 file length (minus 8)
492 1.17 mrg * 8-15 "WAVEfmt "
493 1.17 mrg * 16-19 format size
494 1.17 mrg * 20-21 format tag
495 1.17 mrg * 22-23 number of channels
496 1.17 mrg * 24-27 sample rate
497 1.17 mrg * 28-31 average bytes per second
498 1.17 mrg * 32-33 block alignment
499 1.17 mrg * 34-35 bits per sample
500 1.17 mrg *
501 1.17 mrg * then for ULAW and ALAW outputs, we have an extended chunk size
502 1.17 mrg * and a WAV "fact" to add:
503 1.17 mrg *
504 1.17 mrg * 36-37 length of extension (== 0)
505 1.17 mrg * 38-41 "fact"
506 1.17 mrg * 42-45 fact size
507 1.17 mrg * 46-49 number of samples written
508 1.17 mrg * 50-53 "data"
509 1.17 mrg * 54-57 data length
510 1.17 mrg * 58- raw audio data
511 1.17 mrg *
512 1.17 mrg * for PCM outputs we have just the data remaining:
513 1.17 mrg *
514 1.17 mrg * 36-39 "data"
515 1.17 mrg * 40-43 data length
516 1.17 mrg * 44- raw audio data
517 1.17 mrg *
518 1.17 mrg * RIFF\^@^C^@WAVEfmt ^P^@^@^@^A^@^B^@D<AC>^@^@^P<B1>^B^@^D^@^P^@data^@^@^C^@^@^@^@^@^@^@^@^@^@
519 1.17 mrg */
520 1.17 mrg char wavheaderbuf[64], *p = wavheaderbuf;
521 1.21 mrg const char *riff = "RIFF",
522 1.21 mrg *wavefmt = "WAVEfmt ",
523 1.21 mrg *fact = "fact",
524 1.21 mrg *data = "data";
525 1.17 mrg u_int32_t filelen, fmtsz, sps, abps, factsz = 4, nsample, datalen;
526 1.17 mrg u_int16_t fmttag, nchan, align, bps, extln = 0;
527 1.17 mrg
528 1.17 mrg if (header_info)
529 1.17 mrg warnx("header information not supported for WAV");
530 1.36 fvdl *leftp = 0;
531 1.17 mrg
532 1.17 mrg switch (precision) {
533 1.17 mrg case 8:
534 1.17 mrg bps = 8;
535 1.17 mrg break;
536 1.17 mrg case 16:
537 1.17 mrg bps = 16;
538 1.17 mrg break;
539 1.17 mrg case 32:
540 1.17 mrg bps = 32;
541 1.17 mrg break;
542 1.17 mrg default:
543 1.18 mrg {
544 1.18 mrg static int warned = 0;
545 1.18 mrg
546 1.18 mrg if (warned == 0) {
547 1.30 grant warnx("can not support precision of %d", precision);
548 1.18 mrg warned = 1;
549 1.18 mrg }
550 1.17 mrg }
551 1.17 mrg return (-1);
552 1.17 mrg }
553 1.17 mrg
554 1.17 mrg switch (encoding) {
555 1.17 mrg case AUDIO_ENCODING_ULAW:
556 1.17 mrg fmttag = WAVE_FORMAT_MULAW;
557 1.17 mrg fmtsz = 18;
558 1.17 mrg align = channels;
559 1.17 mrg break;
560 1.26 mrg
561 1.17 mrg case AUDIO_ENCODING_ALAW:
562 1.17 mrg fmttag = WAVE_FORMAT_ALAW;
563 1.17 mrg fmtsz = 18;
564 1.17 mrg align = channels;
565 1.17 mrg break;
566 1.26 mrg
567 1.18 mrg /*
568 1.18 mrg * we could try to support RIFX but it seems to be more portable
569 1.18 mrg * to output little-endian data for WAV files.
570 1.18 mrg */
571 1.18 mrg case AUDIO_ENCODING_ULINEAR_BE:
572 1.26 mrg #if BYTE_ORDER == BIG_ENDIAN
573 1.26 mrg case AUDIO_ENCODING_ULINEAR:
574 1.26 mrg #endif
575 1.20 mrg if (bps == 16)
576 1.20 mrg conv_func = change_sign16_swap_bytes_be;
577 1.20 mrg else if (bps == 32)
578 1.20 mrg conv_func = change_sign32_swap_bytes_be;
579 1.20 mrg goto fmt_pcm;
580 1.26 mrg
581 1.18 mrg case AUDIO_ENCODING_SLINEAR_BE:
582 1.26 mrg #if BYTE_ORDER == BIG_ENDIAN
583 1.26 mrg case AUDIO_ENCODING_SLINEAR:
584 1.26 mrg #endif
585 1.38 mycroft if (bps == 8)
586 1.38 mycroft conv_func = change_sign8;
587 1.38 mycroft else if (bps == 16)
588 1.19 mrg conv_func = swap_bytes;
589 1.18 mrg else if (bps == 32)
590 1.19 mrg conv_func = swap_bytes32;
591 1.20 mrg goto fmt_pcm;
592 1.26 mrg
593 1.20 mrg case AUDIO_ENCODING_ULINEAR_LE:
594 1.26 mrg #if BYTE_ORDER == LITTLE_ENDIAN
595 1.26 mrg case AUDIO_ENCODING_ULINEAR:
596 1.26 mrg #endif
597 1.20 mrg if (bps == 16)
598 1.20 mrg conv_func = change_sign16_le;
599 1.20 mrg else if (bps == 32)
600 1.20 mrg conv_func = change_sign32_le;
601 1.18 mrg /* FALLTHROUGH */
602 1.26 mrg
603 1.20 mrg case AUDIO_ENCODING_SLINEAR_LE:
604 1.17 mrg case AUDIO_ENCODING_PCM16:
605 1.26 mrg #if BYTE_ORDER == LITTLE_ENDIAN
606 1.26 mrg case AUDIO_ENCODING_SLINEAR:
607 1.26 mrg #endif
608 1.38 mycroft if (bps == 8)
609 1.38 mycroft conv_func = change_sign8;
610 1.20 mrg fmt_pcm:
611 1.17 mrg fmttag = WAVE_FORMAT_PCM;
612 1.17 mrg fmtsz = 16;
613 1.17 mrg align = channels * (bps / 8);
614 1.17 mrg break;
615 1.26 mrg
616 1.17 mrg default:
617 1.18 mrg {
618 1.18 mrg static int warned = 0;
619 1.18 mrg
620 1.18 mrg if (warned == 0) {
621 1.26 mrg const char *s = wav_enc_from_val(encoding);
622 1.26 mrg
623 1.26 mrg if (s == NULL)
624 1.30 grant warnx("can not support encoding of %s", s);
625 1.26 mrg else
626 1.30 grant warnx("can not support encoding of %d", encoding);
627 1.18 mrg warned = 1;
628 1.18 mrg }
629 1.17 mrg }
630 1.27 mrg format = AUDIO_FORMAT_NONE;
631 1.17 mrg return (-1);
632 1.17 mrg }
633 1.17 mrg
634 1.17 mrg nchan = channels;
635 1.17 mrg sps = sample_rate;
636 1.17 mrg
637 1.17 mrg /* data length */
638 1.17 mrg if (outfd == STDOUT_FILENO)
639 1.17 mrg datalen = 0;
640 1.41 mrg else if (total_size != -1)
641 1.41 mrg datalen = total_size;
642 1.17 mrg else
643 1.41 mrg datalen = 0;
644 1.17 mrg
645 1.17 mrg /* file length */
646 1.17 mrg filelen = 4 + (8 + fmtsz) + (8 + datalen);
647 1.17 mrg if (fmttag != WAVE_FORMAT_PCM)
648 1.17 mrg filelen += 8 + factsz;
649 1.17 mrg
650 1.17 mrg abps = (double)align*sample_rate / (double)1 + 0.5;
651 1.17 mrg
652 1.17 mrg nsample = (datalen / bps) / sample_rate;
653 1.17 mrg
654 1.17 mrg /*
655 1.17 mrg * now we've calculated the info, write it out!
656 1.17 mrg */
657 1.17 mrg #define put32(x) do { \
658 1.17 mrg u_int32_t _f; \
659 1.17 mrg putle32(_f, (x)); \
660 1.17 mrg memcpy(p, &_f, 4); \
661 1.17 mrg } while (0)
662 1.17 mrg #define put16(x) do { \
663 1.17 mrg u_int16_t _f; \
664 1.17 mrg putle16(_f, (x)); \
665 1.17 mrg memcpy(p, &_f, 2); \
666 1.17 mrg } while (0)
667 1.17 mrg memcpy(p, riff, 4);
668 1.17 mrg p += 4; /* 4 */
669 1.17 mrg put32(filelen);
670 1.17 mrg p += 4; /* 8 */
671 1.17 mrg memcpy(p, wavefmt, 8);
672 1.17 mrg p += 8; /* 16 */
673 1.17 mrg put32(fmtsz);
674 1.17 mrg p += 4; /* 20 */
675 1.17 mrg put16(fmttag);
676 1.17 mrg p += 2; /* 22 */
677 1.17 mrg put16(nchan);
678 1.17 mrg p += 2; /* 24 */
679 1.17 mrg put32(sps);
680 1.17 mrg p += 4; /* 28 */
681 1.17 mrg put32(abps);
682 1.17 mrg p += 4; /* 32 */
683 1.17 mrg put16(align);
684 1.17 mrg p += 2; /* 34 */
685 1.17 mrg put16(bps);
686 1.17 mrg p += 2; /* 36 */
687 1.17 mrg /* NON PCM formats have an extended chunk; write it */
688 1.17 mrg if (fmttag != WAVE_FORMAT_PCM) {
689 1.17 mrg put16(extln);
690 1.17 mrg p += 2; /* 38 */
691 1.17 mrg memcpy(p, fact, 4);
692 1.17 mrg p += 4; /* 42 */
693 1.17 mrg put32(factsz);
694 1.17 mrg p += 4; /* 46 */
695 1.17 mrg put32(nsample);
696 1.17 mrg p += 4; /* 50 */
697 1.17 mrg }
698 1.17 mrg memcpy(p, data, 4);
699 1.17 mrg p += 4; /* 40/54 */
700 1.17 mrg put32(datalen);
701 1.17 mrg p += 4; /* 44/58 */
702 1.17 mrg #undef put32
703 1.17 mrg #undef put16
704 1.17 mrg
705 1.17 mrg *hdrp = wavheaderbuf;
706 1.17 mrg *lenp = (p - wavheaderbuf);
707 1.17 mrg
708 1.17 mrg return 0;
709 1.17 mrg }
710 1.17 mrg
711 1.17 mrg void
712 1.17 mrg write_header()
713 1.17 mrg {
714 1.17 mrg struct iovec iv[3];
715 1.17 mrg int veclen, left, tlen;
716 1.17 mrg void *hdr;
717 1.17 mrg size_t hdrlen;
718 1.17 mrg
719 1.17 mrg switch (format) {
720 1.27 mrg case AUDIO_FORMAT_DEFAULT:
721 1.17 mrg case AUDIO_FORMAT_SUN:
722 1.17 mrg if (write_header_sun(&hdr, &hdrlen, &left) != 0)
723 1.17 mrg return;
724 1.17 mrg break;
725 1.17 mrg case AUDIO_FORMAT_WAV:
726 1.17 mrg if (write_header_wav(&hdr, &hdrlen, &left) != 0)
727 1.17 mrg return;
728 1.17 mrg break;
729 1.17 mrg case AUDIO_FORMAT_NONE:
730 1.17 mrg return;
731 1.17 mrg default:
732 1.17 mrg errx(1, "unknown audio format");
733 1.17 mrg }
734 1.17 mrg
735 1.17 mrg veclen = 0;
736 1.17 mrg tlen = 0;
737 1.17 mrg
738 1.17 mrg if (hdrlen != 0) {
739 1.17 mrg iv[veclen].iov_base = hdr;
740 1.17 mrg iv[veclen].iov_len = hdrlen;
741 1.17 mrg tlen += iv[veclen++].iov_len;
742 1.17 mrg }
743 1.1 mrg if (header_info) {
744 1.1 mrg iv[veclen].iov_base = header_info;
745 1.17 mrg iv[veclen].iov_len = (int)strlen(header_info) + 1;
746 1.1 mrg tlen += iv[veclen++].iov_len;
747 1.1 mrg }
748 1.1 mrg if (left) {
749 1.1 mrg iv[veclen].iov_base = default_info;
750 1.1 mrg iv[veclen].iov_len = left;
751 1.1 mrg tlen += iv[veclen++].iov_len;
752 1.1 mrg }
753 1.1 mrg
754 1.17 mrg if (tlen == 0)
755 1.17 mrg return;
756 1.17 mrg
757 1.1 mrg if (writev(outfd, iv, veclen) != tlen)
758 1.1 mrg err(1, "could not write audio header");
759 1.1 mrg }
760 1.1 mrg
761 1.1 mrg void
762 1.1 mrg rewrite_header()
763 1.1 mrg {
764 1.1 mrg
765 1.1 mrg /* can't do this here! */
766 1.1 mrg if (outfd == STDOUT_FILENO)
767 1.1 mrg return;
768 1.1 mrg
769 1.1 mrg if (lseek(outfd, SEEK_SET, 0) < 0)
770 1.1 mrg err(1, "could not seek to start of file for header rewrite");
771 1.1 mrg write_header();
772 1.1 mrg }
773 1.1 mrg
774 1.1 mrg void
775 1.1 mrg usage()
776 1.1 mrg {
777 1.14 cgd
778 1.14 cgd fprintf(stderr, "Usage: %s [-afhqV] [options] {files ...|-}\n",
779 1.14 cgd getprogname());
780 1.4 mrg fprintf(stderr, "Options:\n\t"
781 1.4 mrg "-b balance (0-63)\n\t"
782 1.48 mrg "-B buffer size\n\t"
783 1.4 mrg "-c channels\n\t"
784 1.4 mrg "-d audio device\n\t"
785 1.4 mrg "-e encoding\n\t"
786 1.35 wiz "-F format\n\t"
787 1.4 mrg "-i header information\n\t"
788 1.4 mrg "-m monitor volume\n\t"
789 1.35 wiz "-P precision (4, 8, 16, 24, or 32 bits)\n\t"
790 1.4 mrg "-p input port\n\t"
791 1.4 mrg "-s sample rate\n\t"
792 1.4 mrg "-t recording time\n\t"
793 1.4 mrg "-v volume\n");
794 1.9 kleink exit(EXIT_FAILURE);
795 1.1 mrg }
796