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