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