1 /* $NetBSD: record.c,v 1.45 2007/12/15 19:44:49 perry 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 #include <sys/cdefs.h> 35 36 #ifndef lint 37 __RCSID("$NetBSD: record.c,v 1.45 2007/12/15 19:44:49 perry Exp $"); 38 #endif 39 40 41 #include <sys/types.h> 42 #include <sys/audioio.h> 43 #include <sys/ioctl.h> 44 #include <sys/time.h> 45 #include <sys/uio.h> 46 47 #include <err.h> 48 #include <fcntl.h> 49 #include <paths.h> 50 #include <signal.h> 51 #include <stdio.h> 52 #include <stdlib.h> 53 #include <string.h> 54 #include <unistd.h> 55 #include <util.h> 56 57 #include "libaudio.h" 58 #include "auconv.h" 59 60 audio_info_t info, oinfo; 61 ssize_t total_size = -1; 62 const char *device; 63 int format = AUDIO_FORMAT_DEFAULT; 64 char *header_info; 65 char default_info[8] = { '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0' }; 66 int audiofd, outfd; 67 int qflag, aflag, fflag; 68 int verbose; 69 int monitor_gain, omonitor_gain; 70 int gain; 71 int balance; 72 int port; 73 int encoding; 74 char *encoding_str; 75 int precision; 76 int sample_rate; 77 int channels; 78 struct timeval record_time; 79 struct timeval start_time; 80 81 void (*conv_func) (u_char *, int); 82 83 void usage (void); 84 int main (int, char *[]); 85 int timeleft (struct timeval *, struct timeval *); 86 void cleanup (int) __dead; 87 int write_header_sun (void **, size_t *, int *); 88 int write_header_wav (void **, size_t *, int *); 89 void write_header (void); 90 void rewrite_header (void); 91 92 int 93 main(argc, argv) 94 int argc; 95 char *argv[]; 96 { 97 u_char *buffer; 98 size_t len, bufsize; 99 int ch, no_time_limit = 1; 100 const char *defdevice = _PATH_SOUND; 101 102 while ((ch = getopt(argc, argv, "ab:C:F:c:d:e:fhi:m:P:p:qt:s:Vv:")) != -1) { 103 switch (ch) { 104 case 'a': 105 aflag++; 106 break; 107 case 'b': 108 decode_int(optarg, &balance); 109 if (balance < 0 || balance > 63) 110 errx(1, "balance must be between 0 and 63"); 111 break; 112 case 'C': 113 /* Ignore, compatibility */ 114 break; 115 case 'F': 116 format = audio_format_from_str(optarg); 117 if (format < 0) 118 errx(1, "Unknown audio format; supported " 119 "formats: \"sun\", \"wav\", and \"none\""); 120 break; 121 case 'c': 122 decode_int(optarg, &channels); 123 if (channels < 0 || channels > 16) 124 errx(1, "channels must be between 0 and 16"); 125 break; 126 case 'd': 127 device = optarg; 128 break; 129 case 'e': 130 encoding_str = optarg; 131 break; 132 case 'f': 133 fflag++; 134 break; 135 case 'i': 136 header_info = optarg; 137 break; 138 case 'm': 139 decode_int(optarg, &monitor_gain); 140 if (monitor_gain < 0 || monitor_gain > 255) 141 errx(1, "monitor volume must be between 0 and 255"); 142 break; 143 case 'P': 144 decode_int(optarg, &precision); 145 if (precision != 4 && precision != 8 && 146 precision != 16 && precision != 24 && 147 precision != 32) 148 errx(1, "precision must be between 4, 8, 16, 24 or 32"); 149 break; 150 case 'p': 151 len = strlen(optarg); 152 153 if (strncmp(optarg, "mic", len) == 0) 154 port |= AUDIO_MICROPHONE; 155 else if (strncmp(optarg, "cd", len) == 0 || 156 strncmp(optarg, "internal-cd", len) == 0) 157 port |= AUDIO_CD; 158 else if (strncmp(optarg, "line", len) == 0) 159 port |= AUDIO_LINE_IN; 160 else 161 errx(1, 162 "port must be `cd', `internal-cd', `mic', or `line'"); 163 break; 164 case 'q': 165 qflag++; 166 break; 167 case 's': 168 decode_int(optarg, &sample_rate); 169 if (sample_rate < 0 || sample_rate > 48000 * 2) /* XXX */ 170 errx(1, "sample rate must be between 0 and 96000"); 171 break; 172 case 't': 173 no_time_limit = 0; 174 decode_time(optarg, &record_time); 175 break; 176 case 'V': 177 verbose++; 178 break; 179 case 'v': 180 decode_int(optarg, &gain); 181 if (gain < 0 || gain > 255) 182 errx(1, "volume must be between 0 and 255"); 183 break; 184 /* case 'h': */ 185 default: 186 usage(); 187 /* NOTREACHED */ 188 } 189 } 190 argc -= optind; 191 argv += optind; 192 193 if (argc != 1) 194 usage(); 195 196 /* 197 * convert the encoding string into a value. 198 */ 199 if (encoding_str) { 200 encoding = audio_enc_to_val(encoding_str); 201 if (encoding == -1) 202 errx(1, "unknown encoding, bailing..."); 203 } 204 #if 0 205 else 206 encoding = AUDIO_ENCODING_ULAW; 207 #endif 208 209 /* 210 * open the output file 211 */ 212 if (argv[0][0] != '-' || argv[0][1] != '\0') { 213 /* intuit the file type from the name */ 214 if (format == AUDIO_FORMAT_DEFAULT) 215 { 216 size_t flen = strlen(*argv); 217 const char *arg = *argv; 218 219 if (strcasecmp(arg + flen - 3, ".au") == 0) 220 format = AUDIO_FORMAT_SUN; 221 else if (strcasecmp(arg + flen - 4, ".wav") == 0) 222 format = AUDIO_FORMAT_WAV; 223 } 224 outfd = open(*argv, O_CREAT|(aflag ? O_APPEND : O_TRUNC)|O_WRONLY, 0666); 225 if (outfd < 0) 226 err(1, "could not open %s", *argv); 227 } else 228 outfd = STDOUT_FILENO; 229 230 /* 231 * open the audio device 232 */ 233 if (device == NULL && (device = getenv("AUDIODEVICE")) == NULL && 234 (device = getenv("AUDIODEV")) == NULL) /* Sun compatibility */ 235 device = defdevice; 236 237 audiofd = open(device, O_RDONLY); 238 if (audiofd < 0 && device == defdevice) { 239 device = _PATH_SOUND0; 240 audiofd = open(device, O_RDONLY); 241 } 242 if (audiofd < 0) 243 err(1, "failed to open %s", device); 244 245 /* 246 * work out the buffer size to use, and allocate it. also work out 247 * what the old monitor gain value is, so that we can reset it later. 248 */ 249 if (ioctl(audiofd, AUDIO_GETINFO, &oinfo) < 0) 250 err(1, "failed to get audio info"); 251 bufsize = oinfo.record.buffer_size; 252 if (bufsize < 32 * 1024) 253 bufsize = 32 * 1024; 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 (read(audiofd, buffer, bufsize) != bufsize) 340 err(1, "read failed"); 341 if (conv_func) 342 (*conv_func)(buffer, bufsize); 343 if (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 balance (0-63)\n\t" 783 "-c channels\n\t" 784 "-d audio device\n\t" 785 "-e encoding\n\t" 786 "-F format\n\t" 787 "-i header information\n\t" 788 "-m monitor volume\n\t" 789 "-P precision (4, 8, 16, 24, or 32 bits)\n\t" 790 "-p input port\n\t" 791 "-s sample rate\n\t" 792 "-t recording time\n\t" 793 "-v volume\n"); 794 exit(EXIT_FAILURE); 795 } 796