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