record.c revision 1.47 1 1.47 lukem /* $NetBSD: record.c,v 1.47 2009/04/11 10:43:10 lukem Exp $ */
2 1.2 mrg
3 1.2 mrg /*
4 1.31 mrg * Copyright (c) 1999, 2002 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.47 lukem __RCSID("$NetBSD: record.c,v 1.47 2009/04/11 10:43:10 lukem Exp $");
36 1.33 agc #endif
37 1.33 agc
38 1.1 mrg
39 1.1 mrg #include <sys/types.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.1 mrg size_t len, bufsize;
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.17 mrg while ((ch = getopt(argc, argv, "ab: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.1 mrg case 'C':
111 1.23 jdolecek /* Ignore, compatibility */
112 1.1 mrg break;
113 1.17 mrg case 'F':
114 1.17 mrg format = audio_format_from_str(optarg);
115 1.17 mrg if (format < 0)
116 1.27 mrg errx(1, "Unknown audio format; supported "
117 1.27 mrg "formats: \"sun\", \"wav\", and \"none\"");
118 1.17 mrg break;
119 1.1 mrg case 'c':
120 1.1 mrg decode_int(optarg, &channels);
121 1.1 mrg if (channels < 0 || channels > 16)
122 1.30 grant errx(1, "channels must be between 0 and 16");
123 1.1 mrg break;
124 1.1 mrg case 'd':
125 1.1 mrg device = optarg;
126 1.1 mrg break;
127 1.1 mrg case 'e':
128 1.1 mrg encoding_str = optarg;
129 1.1 mrg break;
130 1.1 mrg case 'f':
131 1.1 mrg fflag++;
132 1.1 mrg break;
133 1.1 mrg case 'i':
134 1.1 mrg header_info = optarg;
135 1.1 mrg break;
136 1.1 mrg case 'm':
137 1.17 mrg decode_int(optarg, &monitor_gain);
138 1.17 mrg if (monitor_gain < 0 || monitor_gain > 255)
139 1.30 grant errx(1, "monitor volume must be between 0 and 255");
140 1.1 mrg break;
141 1.1 mrg case 'P':
142 1.1 mrg decode_int(optarg, &precision);
143 1.15 minoura if (precision != 4 && precision != 8 &&
144 1.15 minoura precision != 16 && precision != 24 &&
145 1.15 minoura precision != 32)
146 1.15 minoura errx(1, "precision must be between 4, 8, 16, 24 or 32");
147 1.1 mrg break;
148 1.1 mrg case 'p':
149 1.1 mrg len = strlen(optarg);
150 1.1 mrg
151 1.1 mrg if (strncmp(optarg, "mic", len) == 0)
152 1.1 mrg port |= AUDIO_MICROPHONE;
153 1.1 mrg else if (strncmp(optarg, "cd", len) == 0 ||
154 1.1 mrg strncmp(optarg, "internal-cd", len) == 0)
155 1.1 mrg port |= AUDIO_CD;
156 1.1 mrg else if (strncmp(optarg, "line", len) == 0)
157 1.1 mrg port |= AUDIO_LINE_IN;
158 1.1 mrg else
159 1.1 mrg errx(1,
160 1.1 mrg "port must be `cd', `internal-cd', `mic', or `line'");
161 1.1 mrg break;
162 1.1 mrg case 'q':
163 1.1 mrg qflag++;
164 1.1 mrg break;
165 1.1 mrg case 's':
166 1.1 mrg decode_int(optarg, &sample_rate);
167 1.1 mrg if (sample_rate < 0 || sample_rate > 48000 * 2) /* XXX */
168 1.30 grant errx(1, "sample rate must be between 0 and 96000");
169 1.1 mrg break;
170 1.1 mrg case 't':
171 1.8 mrg no_time_limit = 0;
172 1.1 mrg decode_time(optarg, &record_time);
173 1.1 mrg break;
174 1.1 mrg case 'V':
175 1.1 mrg verbose++;
176 1.1 mrg break;
177 1.1 mrg case 'v':
178 1.17 mrg decode_int(optarg, &gain);
179 1.17 mrg if (gain < 0 || gain > 255)
180 1.30 grant errx(1, "volume must be between 0 and 255");
181 1.1 mrg break;
182 1.1 mrg /* case 'h': */
183 1.1 mrg default:
184 1.1 mrg usage();
185 1.1 mrg /* NOTREACHED */
186 1.1 mrg }
187 1.1 mrg }
188 1.1 mrg argc -= optind;
189 1.1 mrg argv += optind;
190 1.1 mrg
191 1.39 mrg if (argc != 1)
192 1.39 mrg usage();
193 1.39 mrg
194 1.1 mrg /*
195 1.40 mrg * convert the encoding string into a value.
196 1.40 mrg */
197 1.40 mrg if (encoding_str) {
198 1.40 mrg encoding = audio_enc_to_val(encoding_str);
199 1.40 mrg if (encoding == -1)
200 1.40 mrg errx(1, "unknown encoding, bailing...");
201 1.40 mrg }
202 1.40 mrg #if 0
203 1.40 mrg else
204 1.40 mrg encoding = AUDIO_ENCODING_ULAW;
205 1.40 mrg #endif
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.1 mrg bufsize = oinfo.record.buffer_size;
250 1.1 mrg if (bufsize < 32 * 1024)
251 1.1 mrg bufsize = 32 * 1024;
252 1.17 mrg omonitor_gain = oinfo.monitor_gain;
253 1.1 mrg
254 1.1 mrg buffer = malloc(bufsize);
255 1.1 mrg if (buffer == NULL)
256 1.1 mrg err(1, "couldn't malloc buffer of %d size", (int)bufsize);
257 1.1 mrg
258 1.1 mrg /*
259 1.17 mrg * set up audio device for recording with the speified parameters
260 1.17 mrg */
261 1.17 mrg AUDIO_INITINFO(&info);
262 1.17 mrg
263 1.17 mrg /*
264 1.17 mrg * for these, get the current values for stuffing into the header
265 1.17 mrg */
266 1.40 mrg #define SETINFO(x) if (x) \
267 1.40 mrg info.record.x = x; \
268 1.40 mrg else \
269 1.40 mrg info.record.x = x = oinfo.record.x;
270 1.40 mrg SETINFO (sample_rate)
271 1.40 mrg SETINFO (channels)
272 1.40 mrg SETINFO (precision)
273 1.40 mrg SETINFO (encoding)
274 1.40 mrg SETINFO (gain)
275 1.40 mrg SETINFO (port)
276 1.40 mrg SETINFO (balance)
277 1.17 mrg #undef SETINFO
278 1.17 mrg
279 1.17 mrg if (monitor_gain)
280 1.17 mrg info.monitor_gain = monitor_gain;
281 1.17 mrg else
282 1.17 mrg monitor_gain = oinfo.monitor_gain;
283 1.1 mrg
284 1.1 mrg info.mode = AUMODE_RECORD;
285 1.23 jdolecek if (ioctl(audiofd, AUDIO_SETINFO, &info) < 0)
286 1.29 mrg err(1, "failed to set audio info");
287 1.1 mrg
288 1.1 mrg signal(SIGINT, cleanup);
289 1.1 mrg write_header();
290 1.1 mrg total_size = 0;
291 1.1 mrg
292 1.27 mrg if (verbose && conv_func) {
293 1.27 mrg const char *s = NULL;
294 1.27 mrg
295 1.27 mrg if (conv_func == swap_bytes)
296 1.27 mrg s = "swap bytes (16 bit)";
297 1.27 mrg else if (conv_func == swap_bytes32)
298 1.27 mrg s = "swap bytes (32 bit)";
299 1.27 mrg else if (conv_func == change_sign16_be)
300 1.27 mrg s = "change sign (big-endian, 16 bit)";
301 1.27 mrg else if (conv_func == change_sign16_le)
302 1.27 mrg s = "change sign (little-endian, 16 bit)";
303 1.27 mrg else if (conv_func == change_sign32_be)
304 1.27 mrg s = "change sign (big-endian, 32 bit)";
305 1.27 mrg else if (conv_func == change_sign32_le)
306 1.27 mrg s = "change sign (little-endian, 32 bit)";
307 1.27 mrg else if (conv_func == change_sign16_swap_bytes_be)
308 1.27 mrg s = "change sign & swap bytes (big-endian, 16 bit)";
309 1.27 mrg else if (conv_func == change_sign16_swap_bytes_le)
310 1.27 mrg s = "change sign & swap bytes (little-endian, 16 bit)";
311 1.27 mrg else if (conv_func == change_sign32_swap_bytes_be)
312 1.27 mrg s = "change sign (big-endian, 32 bit)";
313 1.27 mrg else if (conv_func == change_sign32_swap_bytes_le)
314 1.27 mrg s = "change sign & swap bytes (little-endian, 32 bit)";
315 1.27 mrg
316 1.27 mrg if (s)
317 1.27 mrg fprintf(stderr, "%s: converting, using function: %s\n",
318 1.27 mrg getprogname(), s);
319 1.27 mrg else
320 1.27 mrg fprintf(stderr, "%s: using unnamed conversion "
321 1.27 mrg "function\n", getprogname());
322 1.27 mrg }
323 1.27 mrg
324 1.27 mrg if (verbose)
325 1.27 mrg fprintf(stderr,
326 1.27 mrg "sample_rate=%d channels=%d precision=%d encoding=%s\n",
327 1.27 mrg info.record.sample_rate, info.record.channels,
328 1.27 mrg info.record.precision,
329 1.27 mrg audio_enc_from_val(info.record.encoding));
330 1.32 mrg
331 1.32 mrg if (!no_time_limit && verbose)
332 1.32 mrg fprintf(stderr, "recording for %lu seconds, %lu microseconds\n",
333 1.32 mrg (u_long)record_time.tv_sec, (u_long)record_time.tv_usec);
334 1.27 mrg
335 1.1 mrg (void)gettimeofday(&start_time, NULL);
336 1.8 mrg while (no_time_limit || timeleft(&start_time, &record_time)) {
337 1.47 lukem if ((size_t)read(audiofd, buffer, bufsize) != bufsize)
338 1.1 mrg err(1, "read failed");
339 1.18 mrg if (conv_func)
340 1.19 mrg (*conv_func)(buffer, bufsize);
341 1.47 lukem if ((size_t)write(outfd, buffer, bufsize) != bufsize)
342 1.1 mrg err(1, "write failed");
343 1.1 mrg total_size += bufsize;
344 1.1 mrg }
345 1.1 mrg cleanup(0);
346 1.1 mrg }
347 1.1 mrg
348 1.1 mrg int
349 1.1 mrg timeleft(start_tvp, record_tvp)
350 1.1 mrg struct timeval *start_tvp;
351 1.1 mrg struct timeval *record_tvp;
352 1.1 mrg {
353 1.1 mrg struct timeval now, diff;
354 1.1 mrg
355 1.1 mrg (void)gettimeofday(&now, NULL);
356 1.7 dmcmahil timersub(&now, start_tvp, &diff);
357 1.7 dmcmahil timersub(record_tvp, &diff, &now);
358 1.1 mrg
359 1.1 mrg return (now.tv_sec > 0 || (now.tv_sec == 0 && now.tv_usec > 0));
360 1.1 mrg }
361 1.1 mrg
362 1.1 mrg void
363 1.1 mrg cleanup(signo)
364 1.1 mrg int signo;
365 1.1 mrg {
366 1.1 mrg
367 1.1 mrg rewrite_header();
368 1.1 mrg close(outfd);
369 1.17 mrg if (omonitor_gain) {
370 1.1 mrg AUDIO_INITINFO(&info);
371 1.17 mrg info.monitor_gain = omonitor_gain;
372 1.23 jdolecek if (ioctl(audiofd, AUDIO_SETINFO, &info) < 0)
373 1.1 mrg err(1, "failed to reset audio info");
374 1.1 mrg }
375 1.23 jdolecek close(audiofd);
376 1.44 lukem if (signo != 0) {
377 1.44 lukem (void)raise_default_signal(signo);
378 1.44 lukem }
379 1.1 mrg exit(0);
380 1.1 mrg }
381 1.1 mrg
382 1.17 mrg int
383 1.17 mrg write_header_sun(hdrp, lenp, leftp)
384 1.17 mrg void **hdrp;
385 1.17 mrg size_t *lenp;
386 1.17 mrg int *leftp;
387 1.1 mrg {
388 1.16 mrg static int warned = 0;
389 1.17 mrg static sun_audioheader auh;
390 1.19 mrg int sunenc, oencoding = encoding;
391 1.11 mrg
392 1.27 mrg /* only perform conversions if we don't specify the encoding */
393 1.25 mrg switch (encoding) {
394 1.25 mrg case AUDIO_ENCODING_ULINEAR_LE:
395 1.25 mrg #if BYTE_ORDER == LITTLE_ENDIAN
396 1.25 mrg case AUDIO_ENCODING_ULINEAR:
397 1.25 mrg #endif
398 1.19 mrg if (precision == 16)
399 1.27 mrg conv_func = change_sign16_swap_bytes_le;
400 1.19 mrg else if (precision == 32)
401 1.27 mrg conv_func = change_sign32_swap_bytes_le;
402 1.21 mrg if (conv_func)
403 1.21 mrg encoding = AUDIO_ENCODING_SLINEAR_BE;
404 1.25 mrg break;
405 1.25 mrg
406 1.25 mrg case AUDIO_ENCODING_ULINEAR_BE:
407 1.25 mrg #if BYTE_ORDER == BIG_ENDIAN
408 1.25 mrg case AUDIO_ENCODING_ULINEAR:
409 1.25 mrg #endif
410 1.19 mrg if (precision == 16)
411 1.19 mrg conv_func = change_sign16_be;
412 1.19 mrg else if (precision == 32)
413 1.19 mrg conv_func = change_sign32_be;
414 1.21 mrg if (conv_func)
415 1.21 mrg encoding = AUDIO_ENCODING_SLINEAR_BE;
416 1.25 mrg break;
417 1.25 mrg
418 1.25 mrg case AUDIO_ENCODING_SLINEAR_LE:
419 1.25 mrg #if BYTE_ORDER == LITTLE_ENDIAN
420 1.25 mrg case AUDIO_ENCODING_SLINEAR:
421 1.25 mrg #endif
422 1.19 mrg if (precision == 16)
423 1.27 mrg conv_func = swap_bytes;
424 1.19 mrg else if (precision == 32)
425 1.27 mrg conv_func = swap_bytes32;
426 1.21 mrg if (conv_func)
427 1.21 mrg encoding = AUDIO_ENCODING_SLINEAR_BE;
428 1.25 mrg break;
429 1.25 mrg
430 1.25 mrg #if BYTE_ORDER == BIG_ENDIAN
431 1.25 mrg case AUDIO_ENCODING_SLINEAR:
432 1.25 mrg encoding = AUDIO_ENCODING_SLINEAR_BE;
433 1.25 mrg break;
434 1.25 mrg #endif
435 1.19 mrg }
436 1.19 mrg
437 1.11 mrg /* if we can't express this as a Sun header, don't write any */
438 1.11 mrg if (audio_encoding_to_sun(encoding, precision, &sunenc) != 0) {
439 1.25 mrg if (!qflag && !warned) {
440 1.25 mrg const char *s = audio_enc_from_val(oencoding);
441 1.25 mrg
442 1.25 mrg if (s == NULL)
443 1.25 mrg s = "(unknown)";
444 1.25 mrg warnx("failed to convert to sun encoding from %s "
445 1.25 mrg "(precision %d);\nSun audio header not written",
446 1.25 mrg s, precision);
447 1.25 mrg }
448 1.27 mrg format = AUDIO_FORMAT_NONE;
449 1.19 mrg conv_func = 0;
450 1.16 mrg warned = 1;
451 1.17 mrg return -1;
452 1.11 mrg }
453 1.1 mrg
454 1.1 mrg auh.magic = htonl(AUDIO_FILE_MAGIC);
455 1.1 mrg if (outfd == STDOUT_FILENO)
456 1.1 mrg auh.data_size = htonl(AUDIO_UNKNOWN_SIZE);
457 1.41 mrg else if (total_size != -1)
458 1.41 mrg auh.data_size = htonl(total_size);
459 1.1 mrg else
460 1.41 mrg auh.data_size = 0;
461 1.11 mrg auh.encoding = htonl(sunenc);
462 1.1 mrg auh.sample_rate = htonl(sample_rate);
463 1.1 mrg auh.channels = htonl(channels);
464 1.1 mrg if (header_info) {
465 1.1 mrg int len, infolen;
466 1.1 mrg
467 1.1 mrg infolen = ((len = strlen(header_info)) + 7) & 0xfffffff8;
468 1.17 mrg *leftp = infolen - len;
469 1.1 mrg auh.hdr_size = htonl(sizeof(auh) + infolen);
470 1.1 mrg } else {
471 1.17 mrg *leftp = sizeof(default_info);
472 1.17 mrg auh.hdr_size = htonl(sizeof(auh) + *leftp);
473 1.1 mrg }
474 1.17 mrg *(sun_audioheader **)hdrp = &auh;
475 1.17 mrg *lenp = sizeof auh;
476 1.17 mrg return 0;
477 1.17 mrg }
478 1.1 mrg
479 1.17 mrg int
480 1.17 mrg write_header_wav(hdrp, lenp, leftp)
481 1.17 mrg void **hdrp;
482 1.17 mrg size_t *lenp;
483 1.17 mrg int *leftp;
484 1.17 mrg {
485 1.17 mrg /*
486 1.17 mrg * WAV header we write looks like this:
487 1.17 mrg *
488 1.17 mrg * bytes purpose
489 1.17 mrg * 0-3 "RIFF"
490 1.17 mrg * 4-7 file length (minus 8)
491 1.17 mrg * 8-15 "WAVEfmt "
492 1.17 mrg * 16-19 format size
493 1.17 mrg * 20-21 format tag
494 1.17 mrg * 22-23 number of channels
495 1.17 mrg * 24-27 sample rate
496 1.17 mrg * 28-31 average bytes per second
497 1.17 mrg * 32-33 block alignment
498 1.17 mrg * 34-35 bits per sample
499 1.17 mrg *
500 1.17 mrg * then for ULAW and ALAW outputs, we have an extended chunk size
501 1.17 mrg * and a WAV "fact" to add:
502 1.17 mrg *
503 1.17 mrg * 36-37 length of extension (== 0)
504 1.17 mrg * 38-41 "fact"
505 1.17 mrg * 42-45 fact size
506 1.17 mrg * 46-49 number of samples written
507 1.17 mrg * 50-53 "data"
508 1.17 mrg * 54-57 data length
509 1.17 mrg * 58- raw audio data
510 1.17 mrg *
511 1.17 mrg * for PCM outputs we have just the data remaining:
512 1.17 mrg *
513 1.17 mrg * 36-39 "data"
514 1.17 mrg * 40-43 data length
515 1.17 mrg * 44- raw audio data
516 1.17 mrg *
517 1.17 mrg * RIFF\^@^C^@WAVEfmt ^P^@^@^@^A^@^B^@D<AC>^@^@^P<B1>^B^@^D^@^P^@data^@^@^C^@^@^@^@^@^@^@^@^@^@
518 1.17 mrg */
519 1.17 mrg char wavheaderbuf[64], *p = wavheaderbuf;
520 1.21 mrg const char *riff = "RIFF",
521 1.21 mrg *wavefmt = "WAVEfmt ",
522 1.21 mrg *fact = "fact",
523 1.21 mrg *data = "data";
524 1.17 mrg u_int32_t filelen, fmtsz, sps, abps, factsz = 4, nsample, datalen;
525 1.17 mrg u_int16_t fmttag, nchan, align, bps, extln = 0;
526 1.17 mrg
527 1.17 mrg if (header_info)
528 1.17 mrg warnx("header information not supported for WAV");
529 1.36 fvdl *leftp = 0;
530 1.17 mrg
531 1.17 mrg switch (precision) {
532 1.17 mrg case 8:
533 1.17 mrg bps = 8;
534 1.17 mrg break;
535 1.17 mrg case 16:
536 1.17 mrg bps = 16;
537 1.17 mrg break;
538 1.17 mrg case 32:
539 1.17 mrg bps = 32;
540 1.17 mrg break;
541 1.17 mrg default:
542 1.18 mrg {
543 1.18 mrg static int warned = 0;
544 1.18 mrg
545 1.18 mrg if (warned == 0) {
546 1.30 grant warnx("can not support precision of %d", precision);
547 1.18 mrg warned = 1;
548 1.18 mrg }
549 1.17 mrg }
550 1.17 mrg return (-1);
551 1.17 mrg }
552 1.17 mrg
553 1.17 mrg switch (encoding) {
554 1.17 mrg case AUDIO_ENCODING_ULAW:
555 1.17 mrg fmttag = WAVE_FORMAT_MULAW;
556 1.17 mrg fmtsz = 18;
557 1.17 mrg align = channels;
558 1.17 mrg break;
559 1.26 mrg
560 1.17 mrg case AUDIO_ENCODING_ALAW:
561 1.17 mrg fmttag = WAVE_FORMAT_ALAW;
562 1.17 mrg fmtsz = 18;
563 1.17 mrg align = channels;
564 1.17 mrg break;
565 1.26 mrg
566 1.18 mrg /*
567 1.18 mrg * we could try to support RIFX but it seems to be more portable
568 1.18 mrg * to output little-endian data for WAV files.
569 1.18 mrg */
570 1.18 mrg case AUDIO_ENCODING_ULINEAR_BE:
571 1.26 mrg #if BYTE_ORDER == BIG_ENDIAN
572 1.26 mrg case AUDIO_ENCODING_ULINEAR:
573 1.26 mrg #endif
574 1.20 mrg if (bps == 16)
575 1.20 mrg conv_func = change_sign16_swap_bytes_be;
576 1.20 mrg else if (bps == 32)
577 1.20 mrg conv_func = change_sign32_swap_bytes_be;
578 1.20 mrg goto fmt_pcm;
579 1.26 mrg
580 1.18 mrg case AUDIO_ENCODING_SLINEAR_BE:
581 1.26 mrg #if BYTE_ORDER == BIG_ENDIAN
582 1.26 mrg case AUDIO_ENCODING_SLINEAR:
583 1.26 mrg #endif
584 1.38 mycroft if (bps == 8)
585 1.38 mycroft conv_func = change_sign8;
586 1.38 mycroft else if (bps == 16)
587 1.19 mrg conv_func = swap_bytes;
588 1.18 mrg else if (bps == 32)
589 1.19 mrg conv_func = swap_bytes32;
590 1.20 mrg goto fmt_pcm;
591 1.26 mrg
592 1.20 mrg case AUDIO_ENCODING_ULINEAR_LE:
593 1.26 mrg #if BYTE_ORDER == LITTLE_ENDIAN
594 1.26 mrg case AUDIO_ENCODING_ULINEAR:
595 1.26 mrg #endif
596 1.20 mrg if (bps == 16)
597 1.20 mrg conv_func = change_sign16_le;
598 1.20 mrg else if (bps == 32)
599 1.20 mrg conv_func = change_sign32_le;
600 1.18 mrg /* FALLTHROUGH */
601 1.26 mrg
602 1.20 mrg case AUDIO_ENCODING_SLINEAR_LE:
603 1.17 mrg case AUDIO_ENCODING_PCM16:
604 1.26 mrg #if BYTE_ORDER == LITTLE_ENDIAN
605 1.26 mrg case AUDIO_ENCODING_SLINEAR:
606 1.26 mrg #endif
607 1.38 mycroft if (bps == 8)
608 1.38 mycroft conv_func = change_sign8;
609 1.20 mrg fmt_pcm:
610 1.17 mrg fmttag = WAVE_FORMAT_PCM;
611 1.17 mrg fmtsz = 16;
612 1.17 mrg align = channels * (bps / 8);
613 1.17 mrg break;
614 1.26 mrg
615 1.17 mrg default:
616 1.18 mrg {
617 1.18 mrg static int warned = 0;
618 1.18 mrg
619 1.18 mrg if (warned == 0) {
620 1.26 mrg const char *s = wav_enc_from_val(encoding);
621 1.26 mrg
622 1.26 mrg if (s == NULL)
623 1.30 grant warnx("can not support encoding of %s", s);
624 1.26 mrg else
625 1.30 grant warnx("can not support encoding of %d", encoding);
626 1.18 mrg warned = 1;
627 1.18 mrg }
628 1.17 mrg }
629 1.27 mrg format = AUDIO_FORMAT_NONE;
630 1.17 mrg return (-1);
631 1.17 mrg }
632 1.17 mrg
633 1.17 mrg nchan = channels;
634 1.17 mrg sps = sample_rate;
635 1.17 mrg
636 1.17 mrg /* data length */
637 1.17 mrg if (outfd == STDOUT_FILENO)
638 1.17 mrg datalen = 0;
639 1.41 mrg else if (total_size != -1)
640 1.41 mrg datalen = total_size;
641 1.17 mrg else
642 1.41 mrg datalen = 0;
643 1.17 mrg
644 1.17 mrg /* file length */
645 1.17 mrg filelen = 4 + (8 + fmtsz) + (8 + datalen);
646 1.17 mrg if (fmttag != WAVE_FORMAT_PCM)
647 1.17 mrg filelen += 8 + factsz;
648 1.17 mrg
649 1.17 mrg abps = (double)align*sample_rate / (double)1 + 0.5;
650 1.17 mrg
651 1.17 mrg nsample = (datalen / bps) / sample_rate;
652 1.17 mrg
653 1.17 mrg /*
654 1.17 mrg * now we've calculated the info, write it out!
655 1.17 mrg */
656 1.17 mrg #define put32(x) do { \
657 1.17 mrg u_int32_t _f; \
658 1.17 mrg putle32(_f, (x)); \
659 1.17 mrg memcpy(p, &_f, 4); \
660 1.17 mrg } while (0)
661 1.17 mrg #define put16(x) do { \
662 1.17 mrg u_int16_t _f; \
663 1.17 mrg putle16(_f, (x)); \
664 1.17 mrg memcpy(p, &_f, 2); \
665 1.17 mrg } while (0)
666 1.17 mrg memcpy(p, riff, 4);
667 1.17 mrg p += 4; /* 4 */
668 1.17 mrg put32(filelen);
669 1.17 mrg p += 4; /* 8 */
670 1.17 mrg memcpy(p, wavefmt, 8);
671 1.17 mrg p += 8; /* 16 */
672 1.17 mrg put32(fmtsz);
673 1.17 mrg p += 4; /* 20 */
674 1.17 mrg put16(fmttag);
675 1.17 mrg p += 2; /* 22 */
676 1.17 mrg put16(nchan);
677 1.17 mrg p += 2; /* 24 */
678 1.17 mrg put32(sps);
679 1.17 mrg p += 4; /* 28 */
680 1.17 mrg put32(abps);
681 1.17 mrg p += 4; /* 32 */
682 1.17 mrg put16(align);
683 1.17 mrg p += 2; /* 34 */
684 1.17 mrg put16(bps);
685 1.17 mrg p += 2; /* 36 */
686 1.17 mrg /* NON PCM formats have an extended chunk; write it */
687 1.17 mrg if (fmttag != WAVE_FORMAT_PCM) {
688 1.17 mrg put16(extln);
689 1.17 mrg p += 2; /* 38 */
690 1.17 mrg memcpy(p, fact, 4);
691 1.17 mrg p += 4; /* 42 */
692 1.17 mrg put32(factsz);
693 1.17 mrg p += 4; /* 46 */
694 1.17 mrg put32(nsample);
695 1.17 mrg p += 4; /* 50 */
696 1.17 mrg }
697 1.17 mrg memcpy(p, data, 4);
698 1.17 mrg p += 4; /* 40/54 */
699 1.17 mrg put32(datalen);
700 1.17 mrg p += 4; /* 44/58 */
701 1.17 mrg #undef put32
702 1.17 mrg #undef put16
703 1.17 mrg
704 1.17 mrg *hdrp = wavheaderbuf;
705 1.17 mrg *lenp = (p - wavheaderbuf);
706 1.17 mrg
707 1.17 mrg return 0;
708 1.17 mrg }
709 1.17 mrg
710 1.17 mrg void
711 1.17 mrg write_header()
712 1.17 mrg {
713 1.17 mrg struct iovec iv[3];
714 1.17 mrg int veclen, left, tlen;
715 1.17 mrg void *hdr;
716 1.17 mrg size_t hdrlen;
717 1.17 mrg
718 1.17 mrg switch (format) {
719 1.27 mrg case AUDIO_FORMAT_DEFAULT:
720 1.17 mrg case AUDIO_FORMAT_SUN:
721 1.17 mrg if (write_header_sun(&hdr, &hdrlen, &left) != 0)
722 1.17 mrg return;
723 1.17 mrg break;
724 1.17 mrg case AUDIO_FORMAT_WAV:
725 1.17 mrg if (write_header_wav(&hdr, &hdrlen, &left) != 0)
726 1.17 mrg return;
727 1.17 mrg break;
728 1.17 mrg case AUDIO_FORMAT_NONE:
729 1.17 mrg return;
730 1.17 mrg default:
731 1.17 mrg errx(1, "unknown audio format");
732 1.17 mrg }
733 1.17 mrg
734 1.17 mrg veclen = 0;
735 1.17 mrg tlen = 0;
736 1.17 mrg
737 1.17 mrg if (hdrlen != 0) {
738 1.17 mrg iv[veclen].iov_base = hdr;
739 1.17 mrg iv[veclen].iov_len = hdrlen;
740 1.17 mrg tlen += iv[veclen++].iov_len;
741 1.17 mrg }
742 1.1 mrg if (header_info) {
743 1.1 mrg iv[veclen].iov_base = header_info;
744 1.17 mrg iv[veclen].iov_len = (int)strlen(header_info) + 1;
745 1.1 mrg tlen += iv[veclen++].iov_len;
746 1.1 mrg }
747 1.1 mrg if (left) {
748 1.1 mrg iv[veclen].iov_base = default_info;
749 1.1 mrg iv[veclen].iov_len = left;
750 1.1 mrg tlen += iv[veclen++].iov_len;
751 1.1 mrg }
752 1.1 mrg
753 1.17 mrg if (tlen == 0)
754 1.17 mrg return;
755 1.17 mrg
756 1.1 mrg if (writev(outfd, iv, veclen) != tlen)
757 1.1 mrg err(1, "could not write audio header");
758 1.1 mrg }
759 1.1 mrg
760 1.1 mrg void
761 1.1 mrg rewrite_header()
762 1.1 mrg {
763 1.1 mrg
764 1.1 mrg /* can't do this here! */
765 1.1 mrg if (outfd == STDOUT_FILENO)
766 1.1 mrg return;
767 1.1 mrg
768 1.1 mrg if (lseek(outfd, SEEK_SET, 0) < 0)
769 1.1 mrg err(1, "could not seek to start of file for header rewrite");
770 1.1 mrg write_header();
771 1.1 mrg }
772 1.1 mrg
773 1.1 mrg void
774 1.1 mrg usage()
775 1.1 mrg {
776 1.14 cgd
777 1.14 cgd fprintf(stderr, "Usage: %s [-afhqV] [options] {files ...|-}\n",
778 1.14 cgd getprogname());
779 1.4 mrg fprintf(stderr, "Options:\n\t"
780 1.4 mrg "-b balance (0-63)\n\t"
781 1.4 mrg "-c channels\n\t"
782 1.4 mrg "-d audio device\n\t"
783 1.4 mrg "-e encoding\n\t"
784 1.35 wiz "-F format\n\t"
785 1.4 mrg "-i header information\n\t"
786 1.4 mrg "-m monitor volume\n\t"
787 1.35 wiz "-P precision (4, 8, 16, 24, or 32 bits)\n\t"
788 1.4 mrg "-p input port\n\t"
789 1.4 mrg "-s sample rate\n\t"
790 1.4 mrg "-t recording time\n\t"
791 1.4 mrg "-v volume\n");
792 1.9 kleink exit(EXIT_FAILURE);
793 1.1 mrg }
794