1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 /*
27 * Copyright (c) 2018, Joyent, Inc.
28 */
29
30 /* Command-line audio play utility */
31
32 #include <stdio.h>
33 #include <errno.h>
34 #include <ctype.h>
35 #include <string.h>
36 #include <stdlib.h>
37 #include <fcntl.h>
38 #include <signal.h>
39 #include <locale.h>
40 #include <limits.h> /* All occurances of INT_MAX used to be ~0 (by MCA) */
41 #include <unistd.h>
42 #include <stropts.h>
43 #include <sys/types.h>
44 #include <sys/file.h>
45 #include <sys/stat.h>
46 #include <sys/param.h>
47 #include <sys/ioctl.h>
48 #include <sys/mman.h>
49 #include <netinet/in.h>
50
51 #include <libaudio.h>
52 #include <audio_device.h>
53 #include <audio_encode.h>
54
55 /* localization stuff */
56 #define MGET(s) (char *)gettext(s)
57
58 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
59 #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */
60 #endif
61
62 #define Error (void) fprintf
63
64
65 /* Local variables */
66 static char *prog;
67
68 static char prog_opts[] = "VEiv:d:?"; /* getopt() flags */
69
70 static char *Stdin;
71
72 #define MAX_GAIN (100) /* maximum gain */
73
74 /*
75 * This defines the tolerable sample rate error as a ratio between the
76 * sample rates of the audio data and the audio device.
77 */
78 #define SAMPLE_RATE_THRESHOLD (.01)
79
80 #define BUFFER_LEN 10 /* seconds - for file i/o */
81 #define ADPCM_SIZE (1000*8) /* adpcm conversion output buf size */
82 #define SWAP_SIZE (8192)
83 /* swap bytes conversion output buf size */
84
85 static unsigned Volume = INT_MAX; /* output volume */
86 static double Savevol; /* saved volume level */
87
88 static int Verbose = FALSE; /* verbose messages */
89 static int Immediate = FALSE;
90 /* don't hang waiting for device */
91 static int Errdetect = FALSE; /* don't worry about underrun */
92 static char *Audio_dev = "/dev/audio";
93
94 static int NetEndian = TRUE; /* endian nature of the machine */
95
96 static int Audio_fd = -1;
97 /* file descriptor for audio device */
98 static int Audio_ctlfd = -1;
99 /* file descriptor for control device */
100 static Audio_hdr Save_hdr;
101 /* saved audio header for device */
102 static Audio_hdr Dev_hdr; /* audio header for device */
103 static char *Ifile; /* current filename */
104 static Audio_hdr File_hdr; /* audio header for file */
105 static unsigned Decode = AUDIO_ENCODING_NONE;
106 /* decode type, if any */
107
108 static unsigned char *buf = NULL; /* dynamically alloc'd */
109 static unsigned bufsiz = 0; /* size of output buffer */
110 static unsigned char adpcm_buf[ADPCM_SIZE + 32];
111 /* for adpcm conversion */
112 static unsigned char swap_buf[SWAP_SIZE + 32];
113 /* for byte swap conversion */
114 static unsigned char *inbuf;
115 /* current input buffer pointer */
116 static unsigned insiz; /* current input buffer size */
117
118 /*
119 * The decode_g72x() function is capable of decoding only one channel
120 * at a time and so multichannel data must be decomposed (using demux()
121 * function below ) into its constituent channels and each passed
122 * separately to the decode_g72x() function. Encoded input channels are
123 * stored in **in_ch_data and decoded output channels in **out_ch_data.
124 * Once each channel has been decoded they are recombined (see mux()
125 * function below) before being written to the audio device. For each
126 * channel and adpcm state structure is created.
127 */
128
129 /* adpcm state structures */
130 static struct audio_g72x_state *adpcm_state = NULL;
131 static unsigned char **in_ch_data = NULL; /* input channels */
132 static unsigned char **out_ch_data = NULL; /* output channels */
133 static int out_ch_size; /* output channel size */
134
135 static char *Audio_path = NULL;
136 /* path to search for audio files */
137
138 /* Global variables */
139 extern int optind;
140 extern char *optarg;
141
142 /* Local functions */
143 static void usage(void);
144 static void sigint(int sig);
145 static void open_audio(void);
146 static int path_open(char *fname, int flags, mode_t mode, char *path);
147 static int parse_unsigned(char *str, unsigned *dst, char *flag);
148 static int reconfig(void);
149 static void initmux(int unitsz, int unitsp);
150 static void demux(int unitsz, int cnt);
151 static void mux(char *);
152 static void freemux(void);
153
154
155 static void
usage(void)156 usage(void)
157 {
158 Error(stderr, MGET("Play an audio file -- usage:\n"
159 "\t%s [-iV] [-v vol] [-d dev] [file ...]\n"
160 "where:\n"
161 "\t-i\tDon't hang if audio device is busy\n"
162 "\t-V\tPrint verbose warning messages\n"
163 "\t-v\tSet output volume (0 - %d)\n"
164 "\t-d\tSpecify audio device (default: /dev/audio)\n"
165 "\tfile\tList of files to play\n"
166 "\t\tIf no files specified, read stdin\n"),
167 prog, MAX_GAIN);
168 exit(1);
169 }
170
171 static void
sigint(int sig)172 sigint(int sig)
173 {
174 /* flush output queues before exiting */
175 if (Audio_fd >= 0) {
176 (void) audio_flush_play(Audio_fd);
177
178 /* restore saved parameters */
179 if (Volume != INT_MAX)
180 (void) audio_set_play_gain(Audio_fd, &Savevol);
181 if ((Audio_ctlfd >= 0) &&
182 (audio_cmp_hdr(&Save_hdr, &Dev_hdr) != 0)) {
183 (void) audio_set_play_config(Audio_fd, &Save_hdr);
184 }
185 }
186 exit(1);
187 }
188
189 /* Open the audio device and initalize it. */
190 static void
open_audio(void)191 open_audio(void)
192 {
193 int err;
194 double vol;
195
196 /* Return if already open */
197 if (Audio_fd >= 0)
198 return;
199
200 /* Try opening without waiting, first */
201 Audio_fd = open(Audio_dev, O_WRONLY | O_NONBLOCK);
202 if ((Audio_fd < 0) && (errno == EBUSY)) {
203 if (Immediate) {
204 Error(stderr, MGET("%s: %s is busy\n"),
205 prog, Audio_dev);
206 exit(1);
207 }
208 if (Verbose) {
209 Error(stderr, MGET("%s: waiting for %s..."),
210 prog, Audio_dev);
211 (void) fflush(stderr);
212 }
213 /* Now hang until it's open */
214 Audio_fd = open(Audio_dev, O_WRONLY);
215 if (Verbose)
216 Error(stderr, (Audio_fd < 0) ? "\n" : MGET("open\n"));
217 }
218 if (Audio_fd < 0) {
219 Error(stderr, MGET("%s: error opening "), prog);
220 perror(Audio_dev);
221 exit(1);
222 }
223
224 /* Clear the non-blocking flag (in System V it persists after open) */
225 (void) fcntl(Audio_fd, F_SETFL,
226 (fcntl(Audio_fd, F_GETFL, 0) & ~(O_NDELAY | O_NONBLOCK)));
227
228 /* Get the device output encoding configuration */
229 if (audio_get_play_config(Audio_fd, &Dev_hdr) != AUDIO_SUCCESS) {
230 Error(stderr, MGET("%s: %s is not an audio device\n"),
231 prog, Audio_dev);
232 exit(1);
233 }
234
235 /* If -v flag, set the output volume now */
236 if (Volume != INT_MAX) {
237 vol = (double)Volume / (double)MAX_GAIN;
238 (void) audio_get_play_gain(Audio_fd, &Savevol);
239 err = audio_set_play_gain(Audio_fd, &vol);
240 if (err != AUDIO_SUCCESS) {
241 Error(stderr,
242 MGET("%s: could not set output volume for %s\n"),
243 prog, Audio_dev);
244 exit(1);
245 }
246 }
247 }
248
249 /* Play a list of audio files. */
250 int
main(int argc,char ** argv)251 main(int argc, char **argv)
252 {
253 int errorStatus = 0;
254 int i;
255 int c;
256 int cnt;
257 int file_type;
258 int rem;
259 int outsiz;
260 int tsize;
261 int len;
262 int err;
263 int ifd;
264 int stdinseen;
265 int regular;
266 int swapBytes;
267 int frame;
268 char *outbuf;
269 caddr_t mapaddr;
270 struct stat st;
271 char *cp;
272 char ctldev[MAXPATHLEN];
273
274 (void) setlocale(LC_ALL, "");
275 (void) textdomain(TEXT_DOMAIN);
276
277 /* Get the program name */
278 prog = strrchr(argv[0], '/');
279 if (prog == NULL)
280 prog = argv[0];
281 else
282 prog++;
283 Stdin = MGET("(stdin)");
284
285 /* Check AUDIODEV environment for audio device name */
286 if (cp = getenv("AUDIODEV")) {
287 Audio_dev = cp;
288 }
289
290 /* Parse the command line arguments */
291 err = 0;
292 while ((i = getopt(argc, argv, prog_opts)) != EOF) {
293 switch (i) {
294 case 'v':
295 if (parse_unsigned(optarg, &Volume, "-v")) {
296 err++;
297 } else if (Volume > MAX_GAIN) {
298 Error(stderr, MGET("%s: invalid value "
299 "for -v\n"), prog);
300 err++;
301 }
302 break;
303 case 'd':
304 Audio_dev = optarg;
305 break;
306 case 'V':
307 Verbose = TRUE;
308 break;
309 case 'E':
310 Errdetect = TRUE;
311 break;
312 case 'i':
313 Immediate = TRUE;
314 break;
315 case '?':
316 usage();
317 /*NOTREACHED*/
318 }
319 }
320 if (err > 0)
321 exit(1);
322
323 argc -= optind; /* update arg pointers */
324 argv += optind;
325
326 /* Validate and open the audio device */
327 err = stat(Audio_dev, &st);
328 if (err < 0) {
329 Error(stderr, MGET("%s: cannot stat "), prog);
330 perror(Audio_dev);
331 exit(1);
332 }
333 if (!S_ISCHR(st.st_mode)) {
334 Error(stderr, MGET("%s: %s is not an audio device\n"), prog,
335 Audio_dev);
336 exit(1);
337 }
338
339 /* This should probably use audio_cntl instead of open_audio */
340 if ((argc <= 0) && isatty(fileno(stdin))) {
341 Error(stderr, MGET("%s: No files and stdin is a tty.\n"), prog);
342 exit(1);
343 }
344
345 /* Check on the -i status now. */
346 Audio_fd = open(Audio_dev, O_WRONLY | O_NONBLOCK);
347 if ((Audio_fd < 0) && (errno == EBUSY)) {
348 if (Immediate) {
349 Error(stderr, MGET("%s: %s is busy\n"), prog,
350 Audio_dev);
351 exit(1);
352 }
353 }
354 (void) close(Audio_fd);
355 Audio_fd = -1;
356
357 /* Try to open the control device and save the current format */
358 (void) snprintf(ctldev, sizeof (ctldev), "%sctl", Audio_dev);
359 Audio_ctlfd = open(ctldev, O_RDWR);
360 if (Audio_ctlfd >= 0) {
361 /*
362 * wait for the device to become available then get the
363 * controls. We want to save the format that is left when the
364 * device is in a quiescent state. So wait until then.
365 */
366 Audio_fd = open(Audio_dev, O_WRONLY);
367 (void) close(Audio_fd);
368 Audio_fd = -1;
369 if (audio_get_play_config(Audio_ctlfd, &Save_hdr)
370 != AUDIO_SUCCESS) {
371 (void) close(Audio_ctlfd);
372 Audio_ctlfd = -1;
373 }
374 }
375
376 /* store AUDIOPATH so we don't keep doing getenv() */
377 Audio_path = getenv("AUDIOPATH");
378
379 /* Set up SIGINT handler to flush output */
380 (void) signal(SIGINT, sigint);
381
382 /* Set the endian nature of the machine. */
383 if ((ulong_t)1 != htonl((ulong_t)1)) {
384 NetEndian = FALSE;
385 }
386
387 /* If no filenames, read stdin */
388 stdinseen = FALSE;
389 if (argc <= 0) {
390 Ifile = Stdin;
391 } else {
392 Ifile = *argv++;
393 argc--;
394 }
395
396 /* Loop through all filenames */
397 do {
398 /* Interpret "-" filename to mean stdin */
399 if (strcmp(Ifile, "-") == 0)
400 Ifile = Stdin;
401
402 if (Ifile == Stdin) {
403 if (stdinseen) {
404 Error(stderr,
405 MGET("%s: stdin already processed\n"),
406 prog);
407 goto nextfile;
408 }
409 stdinseen = TRUE;
410 ifd = fileno(stdin);
411 } else {
412 if ((ifd = path_open(Ifile, O_RDONLY, 0, Audio_path))
413 < 0) {
414 Error(stderr, MGET("%s: cannot open "), prog);
415 perror(Ifile);
416 errorStatus++;
417 goto nextfile;
418 }
419 }
420
421 /* Check to make sure this is an audio file */
422 err = audio_read_filehdr(ifd, &File_hdr, &file_type,
423 (char *)NULL, 0);
424 if (err != AUDIO_SUCCESS) {
425 Error(stderr,
426 MGET("%s: %s is not a valid audio file\n"),
427 prog, Ifile);
428 errorStatus++;
429 goto closeinput;
430 }
431
432 /* If G.72X adpcm, set flags for conversion */
433 if ((File_hdr.encoding == AUDIO_ENCODING_G721) &&
434 (File_hdr.samples_per_unit == 2) &&
435 (File_hdr.bytes_per_unit == 1)) {
436 Decode = AUDIO_ENCODING_G721;
437 File_hdr.encoding = AUDIO_ENCODING_ULAW;
438 File_hdr.samples_per_unit = 1;
439 File_hdr.bytes_per_unit = 1;
440 adpcm_state = (struct audio_g72x_state *)malloc
441 (sizeof (*adpcm_state) * File_hdr.channels);
442 for (i = 0; i < File_hdr.channels; i++) {
443 g721_init_state(&adpcm_state[i]);
444 }
445 } else if ((File_hdr.encoding == AUDIO_ENCODING_G723) &&
446 (File_hdr.samples_per_unit == 8) &&
447 (File_hdr.bytes_per_unit == 3)) {
448 Decode = AUDIO_ENCODING_G723;
449 File_hdr.encoding = AUDIO_ENCODING_ULAW;
450 File_hdr.samples_per_unit = 1;
451 File_hdr.bytes_per_unit = 1;
452 adpcm_state = (struct audio_g72x_state *)malloc
453 (sizeof (*adpcm_state) * File_hdr.channels);
454 for (i = 0; i < File_hdr.channels; i++) {
455 g723_init_state(&adpcm_state[i]);
456 }
457 } else {
458 Decode = AUDIO_ENCODING_NONE;
459 }
460
461 /* Check the device configuration */
462 open_audio();
463 if (audio_cmp_hdr(&Dev_hdr, &File_hdr) != 0) {
464 /*
465 * The device does not match the input file.
466 * Wait for any old output to drain, then attempt
467 * to reconfigure the audio device to match the
468 * input data.
469 */
470 if (audio_drain(Audio_fd, FALSE) != AUDIO_SUCCESS) {
471 /* Flush any remaining audio */
472 (void) ioctl(Audio_fd, I_FLUSH, FLUSHW);
473
474 Error(stderr, MGET("%s: "), prog);
475 perror(MGET("AUDIO_DRAIN error"));
476 exit(1);
477 }
478
479 /* Flush any remaining audio */
480 (void) ioctl(Audio_fd, I_FLUSH, FLUSHW);
481
482 if (!reconfig()) {
483 errorStatus++;
484 goto closeinput;
485 }
486 }
487
488
489 /* try to do the mmaping - for regular files only ... */
490 err = fstat(ifd, &st);
491 if (err < 0) {
492 Error(stderr, MGET("%s: cannot stat "), prog);
493 perror(Ifile);
494 exit(1);
495 }
496 regular = (S_ISREG(st.st_mode));
497
498
499 /* If regular file, map it. Else, allocate a buffer */
500 mapaddr = 0;
501
502 /*
503 * This should compare to MAP_FAILED not -1, can't
504 * find MAP_FAILED
505 */
506 if (regular && ((mapaddr = mmap(0, st.st_size, PROT_READ,
507 MAP_SHARED, ifd, 0)) != MAP_FAILED)) {
508
509 (void) madvise(mapaddr, st.st_size, MADV_SEQUENTIAL);
510
511 /* Skip the file header and set the proper size */
512 cnt = lseek(ifd, 0, SEEK_CUR);
513 if (cnt < 0) {
514 perror("lseek");
515 exit(1);
516 }
517 inbuf = (unsigned char *) mapaddr + cnt;
518 len = cnt = st.st_size - cnt;
519 } else { /* Not a regular file, or map failed */
520
521 /* mark is so. */
522 mapaddr = 0;
523
524 /* Allocate buffer to hold 10 seconds of data */
525 cnt = BUFFER_LEN * File_hdr.sample_rate *
526 File_hdr.bytes_per_unit * File_hdr.channels;
527 if (bufsiz != cnt) {
528 if (buf != NULL) {
529 (void) free(buf);
530 }
531 buf = (unsigned char *) malloc(cnt);
532 if (buf == NULL) {
533 Error(stderr,
534 MGET("%s: couldn't allocate %dK "
535 "buf\n"), prog, bufsiz / 1000);
536 exit(1);
537 }
538 inbuf = buf;
539 bufsiz = cnt;
540 }
541 }
542
543 /* Set buffer sizes and pointers for conversion, if any */
544 switch (Decode) {
545 default:
546 case AUDIO_ENCODING_NONE:
547 insiz = bufsiz;
548 outbuf = (char *)buf;
549 break;
550 case AUDIO_ENCODING_G721:
551 insiz = ADPCM_SIZE / 2;
552 outbuf = (char *)adpcm_buf;
553 initmux(1, 2);
554 break;
555 case AUDIO_ENCODING_G723:
556 insiz = (ADPCM_SIZE * 3) / 8;
557 outbuf = (char *)adpcm_buf;
558 initmux(3, 8);
559 break;
560 }
561
562 /*
563 * 8-bit audio isn't a problem, however 16-bit audio is.
564 * If the file is an endian that is different from the machine
565 * then the bytes will need to be swapped.
566 *
567 * Note: Because the G.72X conversions produce 8bit output,
568 * they don't require a byte swap before display and so
569 * this scheme works just fine. If a conversion is added
570 * that produces a 16 bit result and therefore requires
571 * byte swapping before output, then a mechanism
572 * for chaining the two conversions will have to be built.
573 *
574 * Note: The following if() could be simplified, but then
575 * it gets to be very hard to read. So it's left as is.
576 */
577
578 if (File_hdr.bytes_per_unit == 2 &&
579 ((!NetEndian && file_type == FILE_AIFF) ||
580 (!NetEndian && file_type == FILE_AU) ||
581 (NetEndian && file_type == FILE_WAV))) {
582 swapBytes = TRUE;
583 } else {
584 swapBytes = FALSE;
585 }
586
587 if (swapBytes) {
588 /* Read in interal number of sample frames. */
589 frame = File_hdr.bytes_per_unit * File_hdr.channels;
590 insiz = (SWAP_SIZE / frame) * frame;
591 /* make the output buffer the swap buffer. */
592 outbuf = (char *)swap_buf;
593 }
594
595 /*
596 * At this point, we're all ready to copy the data.
597 */
598 if (mapaddr == 0) { /* Not mmapped, do it a buffer at a time. */
599 inbuf = buf;
600 frame = File_hdr.bytes_per_unit * File_hdr.channels;
601 rem = 0;
602 while ((cnt = read(ifd, inbuf+rem, insiz-rem)) >= 0) {
603 /*
604 * We need to ensure only an integral number of
605 * samples is ever written to the audio device.
606 */
607 cnt = cnt + rem;
608 rem = cnt % frame;
609 cnt = cnt - rem;
610
611 /*
612 * If decoding adpcm, or swapping bytes do it
613 * now.
614 *
615 * We treat the swapping like a separate
616 * encoding here because the G.72X encodings
617 * decode to single byte output samples. If
618 * another encoding is added and it produces
619 * multi-byte output samples this will have to
620 * be changed.
621 */
622 if (Decode == AUDIO_ENCODING_G721) {
623 outsiz = 0;
624 demux(1, cnt / File_hdr.channels);
625 for (c = 0; c < File_hdr.channels; c++) {
626 err = g721_decode(in_ch_data[c],
627 cnt / File_hdr.channels,
628 &File_hdr,
629 (void*)out_ch_data[c],
630 &tsize,
631 &adpcm_state[c]);
632 outsiz = outsiz + tsize;
633 if (err != AUDIO_SUCCESS) {
634 Error(stderr, MGET(
635 "%s: error decoding g721\n"),
636 prog);
637 errorStatus++;
638 break;
639 }
640 }
641 mux(outbuf);
642 cnt = outsiz;
643 } else if (Decode == AUDIO_ENCODING_G723) {
644 outsiz = 0;
645 demux(3, cnt / File_hdr.channels);
646 for (c = 0; c < File_hdr.channels; c++) {
647 err = g723_decode(in_ch_data[c],
648 cnt / File_hdr.channels,
649 &File_hdr,
650 (void*)out_ch_data[c],
651 &tsize,
652 &adpcm_state[c]);
653 outsiz = outsiz + tsize;
654 if (err != AUDIO_SUCCESS) {
655 Error(stderr, MGET(
656 "%s: error decoding g723\n"),
657 prog);
658 errorStatus++;
659 break;
660 }
661 }
662 mux(outbuf);
663 cnt = outsiz;
664 } else if (swapBytes) {
665 swab((char *)inbuf, outbuf, cnt);
666 }
667
668 /* If input EOF, write an eof marker */
669 err = write(Audio_fd, outbuf, cnt);
670
671 if (err < 0) {
672 perror("write");
673 errorStatus++;
674 break;
675 } else if (err != cnt) {
676 Error(stderr,
677 MGET("%s: output error: "), prog);
678 perror("");
679 errorStatus++;
680 break;
681 }
682 if (cnt == 0) {
683 break;
684 }
685 /* Move remainder to the front of the buffer */
686 if (rem != 0) {
687 (void) memcpy(inbuf, inbuf + cnt, rem);
688 }
689
690 }
691 if (cnt < 0) {
692 Error(stderr, MGET("%s: error reading "), prog);
693 perror(Ifile);
694 errorStatus++;
695 }
696 } else { /* We're mmaped */
697 if ((Decode != AUDIO_ENCODING_NONE) || swapBytes) {
698
699 /* Transform data if we have to. */
700 for (i = 0; i <= len; i += cnt) {
701 cnt = insiz;
702 if ((i + cnt) > len) {
703 cnt = len - i;
704 }
705 if (Decode == AUDIO_ENCODING_G721) {
706 outsiz = 0;
707 demux(1, cnt / File_hdr.channels);
708 for (c = 0; c < File_hdr.channels;
709 c++) {
710 err = g721_decode(
711 in_ch_data[c],
712 cnt / File_hdr.channels,
713 &File_hdr,
714 (void*)out_ch_data[c],
715 &tsize,
716 &adpcm_state[c]);
717 outsiz = outsiz + tsize;
718 if (err != AUDIO_SUCCESS) {
719 Error(stderr, MGET(
720 "%s: error decoding "
721 "g721\n"), prog);
722 errorStatus++;
723 break;
724 }
725 }
726 mux(outbuf);
727 } else if
728 (Decode == AUDIO_ENCODING_G723) {
729 outsiz = 0;
730 demux(3,
731 cnt / File_hdr.channels);
732 for (c = 0;
733 c < File_hdr.channels;
734 c++) {
735 err = g723_decode(
736 in_ch_data[c],
737 cnt /
738 File_hdr.channels,
739 &File_hdr,
740 (void*)out_ch_data[c],
741 &tsize,
742 &adpcm_state[c]);
743 outsiz = outsiz + tsize;
744 if (err != AUDIO_SUCCESS) {
745 Error(stderr, MGET(
746 "%s: error "
747 "decoding g723\n"),
748 prog);
749 errorStatus++;
750 break;
751 }
752 }
753 mux(outbuf);
754 } else if (swapBytes) {
755 swab((char *)inbuf, outbuf,
756 cnt);
757 outsiz = cnt;
758 }
759 inbuf += cnt;
760
761 /* If input EOF, write an eof marker */
762 err = write(Audio_fd, (char *)outbuf,
763 outsiz);
764 if (err < 0) {
765 perror("write");
766 errorStatus++;
767 } else if (outsiz == 0) {
768 break;
769 }
770
771 }
772 } else {
773 /* write the whole thing at once! */
774 err = write(Audio_fd, inbuf, len);
775 if (err < 0) {
776 perror("write");
777 errorStatus++;
778 }
779 if (err != len) {
780 Error(stderr,
781 MGET("%s: output error: "), prog);
782 perror("");
783 errorStatus++;
784 }
785 err = write(Audio_fd, inbuf, 0);
786 if (err < 0) {
787 perror("write");
788 errorStatus++;
789 }
790 }
791 }
792
793 /* Free memory if decoding ADPCM */
794 switch (Decode) {
795 case AUDIO_ENCODING_G721:
796 case AUDIO_ENCODING_G723:
797 freemux();
798 break;
799 default:
800 break;
801 }
802
803 closeinput:;
804 if (mapaddr != 0)
805 (void) munmap(mapaddr, st.st_size);
806 (void) close(ifd); /* close input file */
807 if (Errdetect) {
808 cnt = 0;
809 (void) audio_set_play_error(Audio_fd,
810 (unsigned int *)&cnt);
811 if (cnt) {
812 Error(stderr,
813 MGET("%s: output underflow in %s\n"),
814 Ifile, prog);
815 errorStatus++;
816 }
817 }
818 nextfile:;
819 } while ((argc > 0) && (argc--, (Ifile = *argv++) != NULL));
820
821 /*
822 * Though drain is implicit on close(), it's performed here
823 * to ensure that the volume is reset after all output is complete.
824 */
825 (void) audio_drain(Audio_fd, FALSE);
826
827 /* Flush any remaining audio */
828 (void) ioctl(Audio_fd, I_FLUSH, FLUSHW);
829
830 if (Volume != INT_MAX)
831 (void) audio_set_play_gain(Audio_fd, &Savevol);
832 if ((Audio_ctlfd >= 0) && (audio_cmp_hdr(&Save_hdr, &Dev_hdr) != 0)) {
833 (void) audio_set_play_config(Audio_fd, &Save_hdr);
834 }
835 (void) close(Audio_fd); /* close output */
836 return (errorStatus);
837 }
838
839
840 /*
841 * Try to reconfigure the audio device to match the file encoding.
842 * If this fails, we should attempt to make the input data match the
843 * device encoding. For now, we give up on this file.
844 *
845 * Returns TRUE if successful. Returns FALSE if not.
846 */
847 static int
reconfig(void)848 reconfig(void)
849 {
850 int err;
851 char msg[AUDIO_MAX_ENCODE_INFO];
852
853 Dev_hdr = File_hdr;
854 err = audio_set_play_config(Audio_fd, &Dev_hdr);
855
856 switch (err) {
857 case AUDIO_SUCCESS:
858 return (TRUE);
859
860 case AUDIO_ERR_NOEFFECT:
861 /*
862 * Couldn't change the device.
863 * Check to see if we're nearly compatible.
864 * audio_cmp_hdr() returns >0 if only sample rate difference.
865 */
866 if (audio_cmp_hdr(&Dev_hdr, &File_hdr) > 0) {
867 double ratio;
868
869 ratio = (double)abs((int)
870 (Dev_hdr.sample_rate - File_hdr.sample_rate)) /
871 (double)File_hdr.sample_rate;
872 if (ratio <= SAMPLE_RATE_THRESHOLD) {
873 if (Verbose) {
874 Error(stderr,
875 MGET("%s: WARNING: %s sampled at "
876 "%d, playing at %d\n"),
877 prog, Ifile, File_hdr.sample_rate,
878 Dev_hdr.sample_rate);
879 }
880 return (TRUE);
881 }
882 Error(stderr,
883 MGET("%s: %s sample rate %d not available\n"),
884 prog, Ifile, File_hdr.sample_rate);
885 return (FALSE);
886 }
887 (void) audio_enc_to_str(&File_hdr, msg);
888 Error(stderr, MGET("%s: %s encoding not available: %s\n"),
889 prog, Ifile, msg);
890 return (FALSE);
891
892 default:
893 Error(stderr,
894 MGET("%s: %s audio encoding type not available\n"),
895 prog, Ifile);
896 exit(1);
897 }
898 return (TRUE);
899 }
900
901
902 /* Parse an unsigned integer */
903 static int
parse_unsigned(char * str,unsigned * dst,char * flag)904 parse_unsigned(char *str, unsigned *dst, char *flag)
905 {
906 char x;
907
908 if (sscanf(str, "%u%c", dst, &x) != 1) {
909 Error(stderr, MGET("%s: invalid value for %s\n"), prog, flag);
910 return (1);
911 }
912 return (0);
913 }
914
915 /*
916 * Search for fname in path and open. Ignore path not opened O_RDONLY.
917 * Note: in general path can be a list of ':' separated paths to search
918 * through.
919 */
920 static int
path_open(char * fname,int flags,mode_t mode,char * path)921 path_open(char *fname, int flags, mode_t mode, char *path)
922 {
923 char fullpath[MAXPATHLEN]; /* full path of file */
924 char *buf; /* malloc off the tmp buff */
925 char *cp;
926 struct stat st;
927
928 if (!fname) { /* bogus */
929 return (-1);
930 }
931
932 /*
933 * cases where we don't bother checking path:
934 * - no path
935 * - file not opened O_RDONLY
936 * - not a relative path (i.e. starts with /, ./, or ../).
937 */
938
939 if ((!path) || (flags != O_RDONLY) || (*fname == '/') ||
940 (strncmp(fname, "./", strlen("./")) == 0) ||
941 (strncmp(fname, "../", strlen("../")) == 0)) {
942 return (open(fname, flags, mode));
943 }
944
945 /*
946 * Malloc off a buffer to hold the path variable.
947 * This is NOT limited to MAXPATHLEN characters as
948 * it may contain multiple paths.
949 */
950 buf = malloc(strlen(path) + 1);
951
952 /*
953 * if first character is ':', but not the one following it,
954 * skip over it - or it'll be interpreted as "./". it's OK
955 * to have "::" since that does mean "./".
956 */
957
958 if ((path[0] == ':') && (path[1] != ':')) {
959 (void) strncpy(buf, path+1, strlen(path));
960 } else {
961 (void) strncpy(buf, path, strlen(path));
962 }
963
964 for (path = buf; path && *path; ) {
965 if (cp = strchr(path, ':')) {
966 *cp++ = '\0'; /* now pts to next path element */
967 }
968
969 /* the safest way to create the path string :-) */
970 if (*path) {
971 (void) strncpy(fullpath, path, MAXPATHLEN);
972 (void) strncat(fullpath, "/", MAXPATHLEN);
973 } else {
974 /* a NULL path element means "./" */
975 (void) strncpy(fullpath, "./", MAXPATHLEN);
976 }
977 (void) strncat(fullpath, fname, MAXPATHLEN);
978
979 /* see if there's a match */
980 if (stat(fullpath, &st) >= 0) {
981 if (S_ISREG(st.st_mode)) {
982 /* got a match! */
983 if (Verbose) {
984 Error(stderr,
985 MGET("%s: Found %s in path "
986 "at %s\n"),
987 prog, fname, fullpath);
988 }
989 return (open(fullpath, flags, mode));
990 }
991 }
992
993 /* go on to the next one */
994 path = cp;
995 }
996
997 /*
998 * if we fall through with no match, just do a normal file open
999 */
1000 return (open(fname, flags, mode));
1001 }
1002
1003
1004 /*
1005 * initmux()
1006 *
1007 * Description:
1008 * Allocates memory for carrying out demultiplexing/multiplexing.
1009 *
1010 * Arguments:
1011 * int unitsz Bytes per unit
1012 * int unitsp Samples per unit
1013 *
1014 * Returns:
1015 * void
1016 */
1017 static void
initmux(int unitsz,int unitsp)1018 initmux(int unitsz, int unitsp)
1019 {
1020 int c; /* Channel */
1021 int in_ch_size; /* Input channel size */
1022
1023 /* Size of each input channel */
1024 in_ch_size = insiz / File_hdr.channels;
1025
1026 /* Size of each output channel */
1027 out_ch_size = in_ch_size * unitsp / unitsz;
1028
1029 /* Allocate pointers to input channels */
1030 in_ch_data = malloc(sizeof (unsigned char *) * File_hdr.channels);
1031
1032 if (in_ch_data == NULL) {
1033 Error(stderr, MGET("%s: couldn't allocate %dK buf\n"),
1034 prog, sizeof (unsigned char *) * File_hdr.channels / 1000);
1035 exit(1);
1036 }
1037
1038 /* Allocate input channels */
1039 for (c = 0; c < File_hdr.channels; c++) {
1040 in_ch_data[c] = malloc(sizeof (unsigned char) * in_ch_size);
1041
1042 if (in_ch_data[c] == NULL) {
1043 Error(stderr, MGET("%s: couldn't allocate %dK buf\n"),
1044 prog, in_ch_size / 1000);
1045 exit(1);
1046 }
1047 }
1048
1049 /* Allocate pointers to output channels */
1050 out_ch_data = malloc(sizeof (unsigned char *) * File_hdr.channels);
1051
1052 if (out_ch_data == NULL) {
1053 Error(stderr, MGET("%s: couldn't allocate %dK buf\n"),
1054 prog, sizeof (unsigned char *) * File_hdr.channels / 1000);
1055 exit(1);
1056 }
1057
1058 /* Allocate output channels */
1059 for (c = 0; c < File_hdr.channels; c++) {
1060 out_ch_data[c] = malloc(sizeof (unsigned char) * out_ch_size);
1061
1062 if (out_ch_data[c] == NULL) {
1063 Error(stderr, MGET("%s: couldn't allocate %dK buf\n"),
1064 prog, out_ch_size / 1000);
1065 exit(1);
1066 }
1067 }
1068 }
1069
1070 /*
1071 * demux()
1072 *
1073 * Description:
1074 * Split a multichannel signal into separate channels.
1075 *
1076 * Arguments:
1077 * int unitsz Bytes per unit
1078 * int cnt Bytes to process
1079 *
1080 * Returns:
1081 * void
1082 */
1083 static void
demux(int unitsz,int cnt)1084 demux(int unitsz, int cnt)
1085 {
1086 int c; /* Channel */
1087 int s; /* Sample */
1088 int b; /* Byte */
1089 int tp; /* Pointer into current data */
1090 int dp; /* Pointer into target data */
1091
1092 /* Split */
1093 for (c = 0; c < File_hdr.channels; c++) {
1094 for (s = 0; s < cnt / unitsz; s++) {
1095 tp = s * unitsz;
1096 dp = (s * File_hdr.channels + c) * unitsz;
1097 for (b = 0; b < unitsz; b++) {
1098 in_ch_data[c][tp + b] = inbuf[dp + b];
1099 }
1100 }
1101 }
1102 }
1103
1104 /*
1105 * mux()
1106 *
1107 * Description:
1108 * Combine separate channels to produce a multichannel signal.
1109 *
1110 * Arguments:
1111 * char *outbuf Combined signal
1112 *
1113 * Returns:
1114 * void
1115 */
1116 static void
mux(char * outbuf)1117 mux(char *outbuf)
1118 {
1119 int c; /* Channel */
1120 int s; /* Sample */
1121
1122 /* Combine */
1123 for (c = 0; c < File_hdr.channels; c++) {
1124 for (s = 0; s < out_ch_size; s++) {
1125 outbuf[File_hdr.channels * s + c] = out_ch_data[c][s];
1126 }
1127 }
1128 }
1129
1130 /*
1131 * freemux()
1132 *
1133 * Description:
1134 * Free memory used in multiplexing/demultiplexing.
1135 *
1136 * Arguments:
1137 * void
1138 *
1139 * Returns:
1140 * void
1141 */
1142 static void
freemux(void)1143 freemux(void)
1144 {
1145 int c; /* Channel */
1146
1147 /* Free */
1148 for (c = 0; c < File_hdr.channels; c++) {
1149 free(in_ch_data[c]);
1150 free(out_ch_data[c]);
1151 free(&adpcm_state[c]);
1152 }
1153
1154 free(in_ch_data);
1155 free(out_ch_data);
1156 }
1157