Print this page
10101 audio tools need smatch fixes
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/cmd/audio/audiorecord/audiorecord.c
+++ new/usr/src/cmd/audio/audiorecord/audiorecord.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
↓ open down ↓ |
15 lines elided |
↑ open up ↑ |
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21 /*
22 22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 23 * Use is subject to license terms.
24 24 */
25 25
26 +/*
27 + * Copyright (c) 2018, Joyent, Inc.
28 + */
29 +
26 30 /* Command-line audio record utility */
27 31
28 32 #include <stdio.h>
29 33 #include <libgen.h>
30 34 #include <errno.h>
31 35 #include <ctype.h>
32 36 #include <math.h>
33 37 #include <stdlib.h>
34 38 #include <unistd.h>
35 39 #include <string.h>
36 40 #include <strings.h>
37 41 #include <locale.h>
38 42 #include <fcntl.h>
39 43 #include <signal.h>
40 44 #include <limits.h> /* All occurances of INT_MAX used to be ~0 (by MCA) */
41 45 #include <sys/types.h>
42 46 #include <sys/file.h>
43 47 #include <sys/stat.h>
44 48 #include <sys/param.h>
45 49 #include <stropts.h>
46 50 #include <poll.h>
47 51 #include <sys/ioctl.h>
48 52 #include <netinet/in.h>
49 53
50 54 #include <libaudio.h>
51 55 #include <audio_device.h>
52 56
53 57 #define irint(d) ((int)d)
54 58
55 59 /* localization stuff */
56 60 #define MGET(s) (char *)gettext(s)
57 61
58 62 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
59 63 #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */
60 64 #endif
61 65
62 66 #define Error (void) fprintf
63 67
64 68 /* Local variables */
65 69 static char *prog;
66 70 static char prog_opts[] = "aft:v:d:i:e:s:c:T:?"; /* getopt() flags */
67 71 static char *Stdout;
68 72
69 73 /* XXX - the input buffer size should depend on sample_rate */
70 74 #define AUDIO_BUFSIZ (1024 * 64)
71 75 static unsigned char buf[AUDIO_BUFSIZ];
72 76 static char swapBuf[AUDIO_BUFSIZ]; /* for byte swapping */
73 77
74 78
75 79 #define MAX_GAIN (100) /* maximum gain */
76 80
77 81 static char *Info = NULL; /* pointer to info data */
78 82 static unsigned Ilen = 0; /* length of info data */
79 83 static unsigned Volume = INT_MAX; /* record volume */
80 84 static double Savevol; /* saved volume */
81 85 static unsigned Sample_rate = 0;
82 86 static unsigned Channels = 0;
83 87 static unsigned Precision = 0; /* based on encoding */
84 88 static unsigned Encoding = 0;
85 89
86 90 static int NetEndian = TRUE; /* endian nature of the machines */
87 91
88 92 static int Append = FALSE; /* append to output file */
89 93 static int Force = FALSE; /* ignore rate differences on append */
90 94 static double Time = -1.; /* recording time */
91 95 static unsigned Limit = AUDIO_UNKNOWN_SIZE; /* recording limit */
92 96 static char *Audio_dev = "/dev/audio";
93 97
94 98 static int Audio_fd = -1;
95 99 /* file descriptor for audio device */
96 100 static Audio_hdr Dev_hdr; /* audio header for device */
97 101 static Audio_hdr Save_hdr; /* saved audio device header */
98 102 static char *Ofile; /* current filename */
99 103 static int File_type = FILE_AU; /* audio file type */
100 104 static int File_type_set = FALSE; /* file type specified as arg */
101 105 static Audio_hdr File_hdr; /* audio header for file */
102 106 static int Cleanup = FALSE; /* SIGINT sets this flag */
103 107 static unsigned Size = 0; /* Size of output file */
104 108 static unsigned Oldsize = 0;
105 109 /* Size of input file, if append */
106 110
107 111 /* Global variables */
108 112 extern int getopt();
109 113 extern int optind;
110 114 extern char *optarg;
111 115
112 116 /* Local Functions */
113 117 static void usage(void);
114 118 static void sigint(int sig);
115 119 static int parse_unsigned(char *str, unsigned *dst, char *flag);
116 120 static int parse_sample_rate(char *s, unsigned *rate);
117 121
118 122
119 123 static void
120 124 usage(void)
121 125 {
122 126 Error(stderr, MGET("Record an audio file -- usage:\n"
123 127 "\t%s [-af] [-v vol]\n"
124 128 "\t%.*s [-c channels] [-s rate] [-e encoding]\n"
125 129 "\t%.*s [-t time] [-i info] [-d dev] [-T au|wav|aif[f]] [file]\n"
126 130 "where:\n"
127 131 "\t-a\tAppend to output file\n"
128 132 "\t-f\tIgnore sample rate differences on append\n"
129 133 "\t-v\tSet record volume (0 - %d)\n"
130 134 "\t-c\tSpecify number of channels to record\n"
131 135 "\t-s\tSpecify rate in samples per second\n"
132 136 "\t-e\tSpecify encoding (ulaw | alaw | [u]linear | linear8 )\n"
133 137 "\t-t\tSpecify record time (hh:mm:ss.dd)\n"
134 138 "\t-i\tSpecify a file header information string\n"
135 139 "\t-d\tSpecify audio device (default: /dev/audio)\n"
136 140 "\t-T\tSpecify the audio file type (default: au)\n"
137 141 "\tfile\tRecord to named file\n"
138 142 "\t\tIf no file specified, write to stdout\n"
139 143 "\t\tDefault audio encoding is ulaw, 8khz, mono\n"
140 144 "\t\tIf -t is not specified, record until ^C\n"),
141 145 prog,
142 146 strlen(prog), " ",
143 147 strlen(prog), " ",
144 148 MAX_GAIN);
145 149 exit(1);
146 150 }
147 151
148 152 static void
149 153 sigint(int sig)
150 154 {
151 155 /* If this is the first ^C, set a flag for the main loop */
152 156 if (!Cleanup && (Audio_fd >= 0)) {
153 157 /* flush input queues before exiting */
154 158 Cleanup = TRUE;
155 159 if (audio_pause_record(Audio_fd) == AUDIO_SUCCESS)
156 160 return;
157 161 Error(stderr, MGET("%s: could not flush input buffer\n"), prog);
158 162 }
159 163
160 164 /* If double ^C, really quit */
161 165 if (Audio_fd >= 0) {
162 166 if (Volume != INT_MAX)
163 167 (void) audio_set_record_gain(Audio_fd, &Savevol);
164 168 if (audio_cmp_hdr(&Save_hdr, &Dev_hdr) != 0) {
165 169 (void) audio_set_record_config(Audio_fd, &Save_hdr);
166 170 }
167 171 }
168 172 exit(1);
169 173 }
170 174
171 175 /*
172 176 * Record from the audio device to a file.
173 177 */
174 178 int
175 179 main(int argc, char **argv)
176 180 {
177 181 int i;
178 182 int cnt;
179 183 int err;
180 184 int file_type;
181 185 int ofd;
182 186 int swapBytes = FALSE;
183 187 double vol;
184 188 struct stat st;
185 189 struct pollfd pfd;
186 190 char *cp;
187 191
188 192 (void) setlocale(LC_ALL, "");
189 193 (void) textdomain(TEXT_DOMAIN);
190 194
191 195 /* Get the program name */
192 196 prog = strrchr(argv[0], '/');
193 197 if (prog == NULL)
194 198 prog = argv[0];
195 199 else
196 200 prog++;
197 201 Stdout = MGET("(stdout)");
198 202
199 203 /* first check AUDIODEV environment for audio device name */
200 204 if (cp = getenv("AUDIODEV")) {
201 205 Audio_dev = cp;
202 206 }
203 207
204 208 /* Set the endian nature of the machine */
205 209 if ((ulong_t)1 != htonl((ulong_t)1)) {
206 210 NetEndian = FALSE;
207 211 }
208 212
209 213 err = 0;
210 214 while ((i = getopt(argc, argv, prog_opts)) != EOF) {
211 215 switch (i) {
212 216 case 'v':
213 217 if (parse_unsigned(optarg, &Volume, "-v")) {
214 218 err++;
215 219 } else if (Volume > MAX_GAIN) {
216 220 Error(stderr, MGET("%s: invalid value for "
217 221 "-v\n"), prog);
218 222 err++;
219 223 }
220 224 break;
221 225 case 't':
222 226 Time = audio_str_to_secs(optarg);
223 227 if ((Time == HUGE_VAL) || (Time < 0.)) {
224 228 Error(stderr, MGET("%s: invalid value for "
225 229 "-t\n"), prog);
226 230 err++;
227 231 }
228 232 break;
229 233 case 'd':
230 234 Audio_dev = optarg;
231 235 break;
232 236 case 'f':
233 237 Force = TRUE;
234 238 break;
235 239 case 'a':
236 240 Append = TRUE;
237 241 break;
238 242 case 'i':
239 243 Info = optarg; /* set information string */
240 244 Ilen = strlen(Info);
241 245 break;
242 246 case 's':
243 247 if (parse_sample_rate(optarg, &Sample_rate)) {
244 248 err++;
245 249 }
246 250 break;
247 251 case 'c':
248 252 if (strncmp(optarg, "mono", strlen(optarg)) == 0) {
249 253 Channels = 1;
250 254 } else if (strncmp(optarg, "stereo",
251 255 strlen(optarg)) == 0) {
252 256 Channels = 2;
253 257 } else if (parse_unsigned(optarg, &Channels, "-c")) {
254 258 err++;
255 259 } else if ((Channels != 1) && (Channels != 2)) {
256 260 Error(stderr, "%s: invalid value for -c\n",
257 261 prog);
258 262 err++;
259 263 }
260 264 break;
261 265 case 'e':
262 266 if (strncmp(optarg, "ulinear", strlen(optarg)) == 0) {
263 267 Encoding = AUDIO_ENCODING_LINEAR8;
264 268 Precision = 8;
265 269 } else if (strncmp(optarg, "linear8",
266 270 strlen("linear8")) == 0) {
267 271 Encoding = AUDIO_ENCODING_LINEAR;
268 272 Precision = 8;
269 273 } else if (strncmp(optarg, "ulaw",
270 274 strlen(optarg)) == 0) {
271 275 Encoding = AUDIO_ENCODING_ULAW;
272 276 Precision = 8;
273 277 } else if (strncmp(optarg, "alaw",
274 278 strlen(optarg)) == 0) {
275 279 Encoding = AUDIO_ENCODING_ALAW;
276 280 Precision = 8;
277 281 } else if ((strncmp(optarg, "linear",
278 282 strlen(optarg)) == 0) || (strncmp(optarg, "pcm",
279 283 strlen(optarg)) == 0)) {
280 284 Encoding = AUDIO_ENCODING_LINEAR;
281 285 Precision = 16;
282 286 } else {
283 287 Error(stderr, MGET("%s: invalid value for "
284 288 "-e\n"), prog);
285 289 err++;
286 290 }
287 291 break;
288 292 case 'T':
289 293 if (strncmp(optarg, "au", strlen(optarg)) == 0) {
290 294 File_type = FILE_AU;
291 295 } else if (strncmp(optarg, "wav",
292 296 strlen(optarg)) == 0) {
293 297 File_type = FILE_WAV;
294 298 } else if (strncmp(optarg, "aif",
295 299 strlen(optarg)) == 0) {
296 300 File_type = FILE_AIFF;
297 301 } else if (strncmp(optarg, "aiff",
298 302 strlen(optarg)) == 0) {
299 303 File_type = FILE_AIFF;
300 304 } else {
301 305 Error(stderr, MGET("%s: invalid value for "
302 306 "-T\n"), prog);
303 307 err++;
304 308 }
305 309 File_type_set = TRUE;
306 310 break;
307 311 case '?':
308 312 usage();
309 313 /*NOTREACHED*/
310 314 }
311 315 }
312 316 if (Append && (Info != NULL)) {
313 317 Error(stderr, MGET("%s: cannot specify -a and -i\n"), prog);
314 318 err++;
315 319 }
316 320 if (err > 0)
317 321 exit(1);
318 322
319 323 argc -= optind; /* update arg pointers */
320 324 argv += optind;
321 325
322 326 /* Open the output file */
323 327 if (argc <= 0) {
324 328 Ofile = Stdout;
325 329 } else {
326 330 Ofile = *argv++;
327 331 argc--;
328 332
329 333 /* Interpret "-" filename to mean stdout */
330 334 if (strcmp(Ofile, "-") == 0)
331 335 Ofile = Stdout;
332 336
333 337 /* if -T not set then we use the file suffix */
334 338 if (File_type_set == FALSE) {
335 339 char *file_name;
336 340 char *start;
337 341
338 342 /* get the file name without the path */
339 343 file_name = basename(Ofile);
340 344
341 345 /* get the true suffix */
342 346 start = strrchr(file_name, '.');
343 347
344 348 /* if no '.' then there's no suffix */
345 349 if (start) {
346 350 /* is this a .au file? */
347 351 if (strcasecmp(start, ".au") == 0) {
348 352 File_type = FILE_AU;
349 353 } else if (strcasecmp(start, ".wav") == 0) {
350 354 File_type = FILE_WAV;
351 355 } else if (strcasecmp(start, ".aif") == 0) {
352 356 File_type = FILE_AIFF;
353 357 } else if (strcasecmp(start, ".aiff") == 0) {
354 358 File_type = FILE_AIFF;
355 359 } else {
356 360 /* the default is .au */
357 361 File_type = FILE_AU;
358 362 }
359 363 } else {
360 364 /* no suffix, so default to .au */
361 365 File_type = FILE_AU;
362 366 }
363 367 }
364 368 }
365 369
366 370 if (Ofile == Stdout) {
367 371 ofd = fileno(stdout);
368 372 Append = FALSE;
369 373 } else {
370 374 ofd = open(Ofile,
371 375 (O_RDWR | O_CREAT | (Append ? 0 : O_TRUNC)), 0666);
372 376 if (ofd < 0) {
373 377 Error(stderr, MGET("%s: cannot open "), prog);
374 378 perror(Ofile);
375 379 exit(1);
376 380 }
377 381 if (Append) {
378 382 /*
379 383 * Check to make sure we're appending to an audio file.
380 384 * It must be a regular file (if zero-length, simply
381 385 * write it from scratch). Also, its file header
382 386 * must match the input device configuration.
383 387 */
384 388 if ((fstat(ofd, &st) < 0) || (!S_ISREG(st.st_mode))) {
385 389 Error(stderr,
386 390 MGET("%s: %s is not a regular file\n"),
387 391 prog, Ofile);
388 392 exit(1);
389 393 }
390 394 if (st.st_size == 0) {
391 395 Append = FALSE;
392 396 goto openinput;
393 397 }
394 398
395 399 err = audio_read_filehdr(ofd, &File_hdr, &file_type,
396 400 (char *)NULL, 0);
397 401
398 402 if (err != AUDIO_SUCCESS) {
399 403 Error(stderr,
400 404 MGET("%s: %s is not a valid audio file\n"),
401 405 prog, Ofile);
402 406 exit(1);
403 407 }
404 408
405 409 /* we need to make sure file types match */
406 410 if (File_type_set == TRUE) {
407 411 /* specified by the command line, must match */
408 412 if (File_type != file_type) {
409 413 Error(stderr,
410 414 MGET("%s: file types must match\n"),
411 415 prog);
412 416 exit(1);
413 417 }
414 418 } else {
415 419 /* not specified, so force */
416 420 File_type = file_type;
417 421 }
418 422
419 423 /*
420 424 * Set the format state to the format
421 425 * in the file header.
422 426 */
423 427 Sample_rate = File_hdr.sample_rate;
424 428 Channels = File_hdr.channels;
425 429 Encoding = File_hdr.encoding;
426 430 Precision = File_hdr.bytes_per_unit * 8;
427 431
428 432 /* make sure we support the encoding method */
429 433 switch (Encoding) {
430 434 case AUDIO_ENCODING_LINEAR8:
431 435 case AUDIO_ENCODING_ULAW:
432 436 case AUDIO_ENCODING_ALAW:
433 437 case AUDIO_ENCODING_LINEAR:
434 438 break;
435 439 default: {
436 440 char msg[AUDIO_MAX_ENCODE_INFO];
437 441 (void) audio_enc_to_str(&File_hdr, msg);
438 442 Error(stderr,
439 443 MGET("%s: Append is not supported "
440 444 "for "), prog);
441 445 Error(stderr,
442 446 MGET("this file encoding:\n\t"
443 447 "[%s]\n"), msg);
444 448 exit(1);
445 449 }
446 450 }
447 451
448 452 /* Get the current size, if possible */
449 453 Oldsize = File_hdr.data_size;
450 454 if ((Oldsize == AUDIO_UNKNOWN_SIZE) &&
451 455 ((err = (int)lseek(ofd, 0L, SEEK_CUR)) >= 0)) {
452 456 if (err < 0) {
453 457 Error(stderr,
454 458 MGET("%s: %s is not a valid audio "
455 459 "file\n"), prog, Ofile);
456 460 exit(1);
457 461 }
458 462 Oldsize = st.st_size - err;
459 463 }
460 464 /* Seek to end to start append */
461 465 if ((int)lseek(ofd, st.st_size, SEEK_SET) < 0) {
462 466 Error(stderr,
463 467 MGET("%s: cannot find end of %s\n"),
464 468 prog, Ofile);
465 469 exit(1);
466 470 }
467 471 }
468 472 }
469 473 openinput:
470 474 /* Validate and open the audio device */
471 475 err = stat(Audio_dev, &st);
472 476 if (err < 0) {
473 477 Error(stderr, MGET("%s: cannot open "), prog);
474 478 perror(Audio_dev);
475 479 exit(1);
476 480 }
477 481 if (!S_ISCHR(st.st_mode)) {
478 482 Error(stderr, MGET("%s: %s is not an audio device\n"), prog,
479 483 Audio_dev);
480 484 exit(1);
481 485 }
482 486
483 487 /*
484 488 * For the mixer environment we need to open the audio device before
485 489 * the control device. If successful we pause right away to keep
486 490 * from queueing up a bunch of useless data.
487 491 */
488 492 Audio_fd = open(Audio_dev, O_RDONLY | O_NONBLOCK);
489 493 if (Audio_fd < 0) {
490 494 if (errno == EBUSY) {
491 495 Error(stderr, MGET("%s: %s is busy\n"),
492 496 prog, Audio_dev);
493 497 } else {
494 498 Error(stderr, MGET("%s: error opening "), prog);
495 499 perror(Audio_dev);
496 500 }
497 501 exit(1);
498 502 }
499 503 if (audio_pause_record(Audio_fd) != AUDIO_SUCCESS) {
500 504 Error(stderr, MGET("%s: not able to pause recording\n"), prog);
501 505 exit(1);
502 506 }
503 507
504 508 /* get the current settings */
505 509 if (audio_get_record_config(Audio_fd, &Save_hdr) != AUDIO_SUCCESS) {
506 510 (void) close(Audio_fd);
507 511 Error(stderr, MGET("%s: %s is not an audio device\n"),
508 512 prog, Audio_dev);
509 513 exit(1);
510 514 }
511 515 /* make a copy into the working data structure */
512 516 bcopy(&Save_hdr, &Dev_hdr, sizeof (Save_hdr));
513 517
514 518 /* flush any queued audio data */
515 519 if (audio_flush_record(Audio_fd) != AUDIO_SUCCESS) {
516 520 Error(stderr, MGET("%s: not able to flush recording\n"), prog);
517 521 exit(1);
518 522 }
519 523
520 524 if (Sample_rate != 0) {
521 525 Dev_hdr.sample_rate = Sample_rate;
522 526 }
523 527 if (Channels != 0) {
524 528 Dev_hdr.channels = Channels;
525 529 }
526 530 if (Precision != 0) {
527 531 Dev_hdr.bytes_per_unit = Precision / 8;
528 532 }
529 533 if (Encoding != 0) {
530 534 Dev_hdr.encoding = Encoding;
531 535 }
532 536
533 537 /*
534 538 * For .wav we always record 8-bit linear as unsigned. Thus we
535 539 * force unsigned linear to make life a lot easier on the user.
536 540 *
537 541 * For .aiff we set the default to 8-bit signed linear, not
538 542 * u-law, if Encoding isn't already set.
539 543 */
540 544 if (File_type == FILE_WAV &&
541 545 Dev_hdr.encoding == AUDIO_ENCODING_LINEAR &&
542 546 Dev_hdr.bytes_per_unit == 1) {
543 547 /* force to unsigned */
544 548 Dev_hdr.encoding = AUDIO_ENCODING_LINEAR8;
545 549 } else if (File_type == FILE_AIFF && Encoding == 0) {
546 550 Dev_hdr.encoding = AUDIO_ENCODING_LINEAR;
547 551 if (Precision == 0) {
548 552 Dev_hdr.bytes_per_unit = AUDIO_PRECISION_8 / 8;
549 553 }
550 554 }
551 555
552 556 if (audio_set_record_config(Audio_fd, &Dev_hdr) != AUDIO_SUCCESS) {
553 557 Error(stderr, MGET(
554 558 "%s: Audio format not supported by the audio device\n"),
555 559 prog);
556 560 exit(1);
557 561 }
558 562
559 563 if (audio_resume_record(Audio_fd) != AUDIO_SUCCESS) {
560 564 Error(stderr, MGET("%s: not able to resume recording\n"), prog);
561 565 exit(1);
562 566 }
563 567
564 568 /* If appending to an existing file, check the configuration */
565 569 if (Append) {
566 570 char msg[AUDIO_MAX_ENCODE_INFO];
567 571
568 572 switch (audio_cmp_hdr(&Dev_hdr, &File_hdr)) {
569 573 case 0: /* configuration matches */
570 574 break;
571 575 case 1: /* all but sample rate matches */
572 576 if (Force) {
573 577 Error(stderr, MGET("%s: WARNING: appending "
574 578 "%.3fkHz data to %s (%.3fkHz)\n"), prog,
575 579 ((double)Dev_hdr.sample_rate / 1000.),
576 580 Ofile,
577 581 ((double)File_hdr.sample_rate / 1000.));
578 582 break;
579 583 } /* if not -f, fall through */
580 584 /* FALLTHROUGH */
581 585 default: /* encoding mismatch */
582 586 (void) audio_enc_to_str(&Dev_hdr, msg);
583 587 Error(stderr,
584 588 MGET("%s: device encoding [%s]\n"), prog, msg);
585 589 (void) audio_enc_to_str(&File_hdr, msg);
586 590 Error(stderr,
587 591 MGET("\tdoes not match file encoding [%s]\n"), msg);
588 592 exit(1);
589 593 }
590 594 } else if (!isatty(ofd)) {
591 595 if (audio_write_filehdr(ofd, &Dev_hdr, File_type, Info,
592 596 Ilen) != AUDIO_SUCCESS) {
593 597 Error(stderr,
594 598 MGET("%s: error writing header for %s\n"), prog,
595 599 Ofile);
596 600 exit(1);
597 601 }
598 602 }
599 603
600 604 /*
601 605 * 8-bit audio isn't a problem, however 16-bit audio is. If the file
602 606 * is an endian that is different from the machine then the bytes
603 607 * will need to be swapped.
604 608 *
605 609 * Note: The following if() could be simplified, but then it gets
606 610 * to be very hard to read. So it's left as is.
607 611 */
608 612 if (Dev_hdr.bytes_per_unit == 2 &&
609 613 ((!NetEndian && File_type == FILE_AIFF) ||
610 614 (!NetEndian && File_type == FILE_AU) ||
611 615 (NetEndian && File_type == FILE_WAV))) {
612 616 swapBytes = TRUE;
613 617 }
614 618
615 619 /* If -v flag, set the record volume now */
616 620 if (Volume != INT_MAX) {
617 621 vol = (double)Volume / (double)MAX_GAIN;
618 622 (void) audio_get_record_gain(Audio_fd, &Savevol);
619 623 err = audio_set_record_gain(Audio_fd, &vol);
620 624 if (err != AUDIO_SUCCESS) {
621 625 Error(stderr,
622 626 MGET("%s: could not set record volume for %s\n"),
623 627 prog, Audio_dev);
624 628 exit(1);
625 629 }
626 630 }
627 631
628 632 if (isatty(ofd)) {
629 633 Error(stderr, MGET("%s: No files and stdout is a tty\n"),
630 634 prog);
631 635 exit(1);
632 636 }
633 637
634 638 /* Set up SIGINT handler so that final buffers may be flushed */
635 639 (void) signal(SIGINT, sigint);
636 640
637 641 /*
638 642 * At this point, we're (finally) ready to copy the data.
639 643 * Init a poll() structure, to use when there's nothing to read.
640 644 */
641 645 if (Time > 0)
642 646 Limit = audio_secs_to_bytes(&Dev_hdr, Time);
643 647 pfd.fd = Audio_fd;
644 648 pfd.events = POLLIN;
645 649 while ((Limit == AUDIO_UNKNOWN_SIZE) || (Limit != 0)) {
646 650 /* Fill the buffer or read to the time limit */
647 651 cnt = read(Audio_fd, (char *)buf,
648 652 ((Limit != AUDIO_UNKNOWN_SIZE) && (Limit < sizeof (buf)) ?
649 653 (int)Limit : sizeof (buf)));
650 654
651 655 if (cnt == 0) /* normally, eof can't happen */
652 656 break;
653 657
654 658 /* If error, probably have to wait for input */
655 659 if (cnt < 0) {
656 660 if (Cleanup)
657 661 break; /* done if ^C seen */
658 662 switch (errno) {
659 663 case EAGAIN:
660 664 (void) poll(&pfd, 1L, -1);
661 665 break;
662 666 case EOVERFLOW: /* Possibly a Large File */
663 667 Error(stderr, MGET("%s: error reading"), prog);
664 668 perror("Large File");
665 669 exit(1);
666 670 default:
667 671 Error(stderr, MGET("%s: error reading"), prog);
668 672 perror(Audio_dev);
669 673 exit(1);
670 674 }
671 675 continue;
672 676 }
673 677
674 678 /* Swab the output if required. */
675 679 if (swapBytes) {
676 680 swab((char *)buf, swapBuf, cnt);
677 681 err = write(ofd, swapBuf, cnt);
678 682 } else {
679 683 err = write(ofd, (char *)buf, cnt);
680 684 }
681 685 if (err < 0) {
682 686 Error(stderr, MGET("%s: error writing "), prog);
683 687 perror(Ofile);
684 688 exit(1);
685 689 }
686 690 if (err != cnt) {
687 691 Error(stderr, MGET("%s: error writing "), prog);
688 692 perror(Ofile);
689 693 break;
690 694 }
691 695 Size += cnt;
692 696 if (Limit != AUDIO_UNKNOWN_SIZE)
693 697 Limit -= cnt;
694 698 }
695 699
696 700 /* Attempt to rewrite the data_size field of the file header */
697 701 if (!Append || (Oldsize != AUDIO_UNKNOWN_SIZE)) {
698 702 if (Append)
699 703 Size += Oldsize;
700 704 (void) audio_rewrite_filesize(ofd, File_type, Size,
701 705 Dev_hdr.channels, Dev_hdr.bytes_per_unit);
702 706 }
703 707
704 708 (void) close(ofd); /* close input file */
705 709
706 710
707 711 /* Check for error during record */
708 712 if (audio_get_record_error(Audio_fd, (unsigned *)&err) != AUDIO_SUCCESS)
709 713 Error(stderr, MGET("%s: error reading device status\n"), prog);
710 714 else if (err)
711 715 Error(stderr, MGET("%s: WARNING: Data overflow occurred\n"),
712 716 prog);
713 717
714 718 /* Reset record volume, encoding */
715 719 if (Volume != INT_MAX)
716 720 (void) audio_set_record_gain(Audio_fd, &Savevol);
717 721 if (audio_cmp_hdr(&Save_hdr, &Dev_hdr) != 0) {
718 722 (void) audio_set_record_config(Audio_fd, &Save_hdr);
719 723 }
720 724 (void) close(Audio_fd);
721 725 return (0);
722 726 }
723 727
724 728 /* Parse an unsigned integer */
725 729 static int
726 730 parse_unsigned(char *str, unsigned *dst, char *flag)
727 731 {
728 732 char x;
729 733
730 734 if (sscanf(str, "%u%c", dst, &x) != 1) {
731 735 Error(stderr, MGET("%s: invalid value for %s\n"), prog, flag);
732 736 return (1);
733 737 }
734 738 return (0);
735 739 }
736 740
737 741 /*
738 742 * set the sample rate. assume anything is ok. check later on to make sure
739 743 * the sample rate is valid.
740 744 */
741 745 static int
742 746 parse_sample_rate(char *s, unsigned *rate)
743 747 {
744 748 char *cp;
745 749 double drate;
746 750
747 751 /*
748 752 * check if it's "cd" or "dat" or "voice". these also set
749 753 * the precision and encoding, etc.
750 754 */
751 755 if (strcasecmp(s, "dat") == 0) {
752 756 drate = 48000.0;
753 757 } else if (strcasecmp(s, "cd") == 0) {
754 758 drate = 44100.0;
755 759 } else if (strcasecmp(s, "voice") == 0) {
756 760 drate = 8000.0;
757 761 } else {
758 762 /* just do an atof */
759 763 drate = atof(s);
760 764
761 765 /*
762 766 * if the first non-digit is a "k" multiply by 1000,
763 767 * if it's an "h", leave it alone. anything else,
764 768 * return an error.
765 769 */
↓ open down ↓ |
730 lines elided |
↑ open up ↑ |
766 770
767 771 /*
768 772 * XXX bug alert: could have multiple "." in string
769 773 * and mess things up.
770 774 */
771 775 for (cp = s; *cp && (isdigit(*cp) || (*cp == '.')); cp++)
772 776 /* NOP */;
773 777 if (*cp != NULL) {
774 778 if ((*cp == 'k') || (*cp == 'K')) {
775 779 drate *= 1000.0;
776 - } else if ((*cp != 'h') || (*cp != 'H')) {
780 + } else if ((*cp != 'h') && (*cp != 'H')) {
777 781 /* bogus! */
778 782 Error(stderr,
779 783 MGET("invalid sample rate: %s\n"), s);
780 784 return (1);
781 785 }
782 786 }
783 787
784 788 }
785 789
786 790 *rate = irint(drate);
787 791 return (0);
788 792 }
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX