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