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