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