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