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