8322 nl: misleading-indentation
[unleashed/tickless.git] / usr / src / cmd / audio / audioplay / audioplay.c
blob882c4d9087d46c0cec756ed6e7960d291eea26f7
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 /* Command-line audio play utility */
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>
47 #include <libaudio.h>
48 #include <audio_device.h>
49 #include <audio_encode.h>
51 /* localization stuff */
52 #define MGET(s) (char *)gettext(s)
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
58 #define Error (void) fprintf
61 /* Local variables */
62 static char *prog;
64 static char prog_opts[] = "VEiv:d:?"; /* getopt() flags */
66 static char *Stdin;
68 #define MAX_GAIN (100) /* maximum gain */
71 * This defines the tolerable sample rate error as a ratio between the
72 * sample rates of the audio data and the audio device.
74 #define SAMPLE_RATE_THRESHOLD (.01)
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 */
81 static unsigned Volume = INT_MAX; /* output volume */
82 static double Savevol; /* saved volume level */
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";
90 static int NetEndian = TRUE; /* endian nature of the machine */
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 */
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 */
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.
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 */
131 static char *Audio_path = NULL;
132 /* path to search for audio files */
134 /* Global variables */
135 extern int getopt(int, char *const *, const char *);
136 extern int optind;
137 extern char *optarg;
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);
152 static void
153 usage(void)
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);
168 static void
169 sigint(int sig)
171 /* flush output queues before exiting */
172 if (Audio_fd >= 0) {
173 (void) audio_flush_play(Audio_fd);
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);
183 exit(1);
186 /* Open the audio device and initalize it. */
187 static void
188 open_audio(void)
190 int err;
191 double vol;
193 /* Return if already open */
194 if (Audio_fd >= 0)
195 return;
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);
205 if (Verbose) {
206 Error(stderr, MGET("%s: waiting for %s..."),
207 prog, Audio_dev);
208 (void) fflush(stderr);
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"));
215 if (Audio_fd < 0) {
216 Error(stderr, MGET("%s: error opening "), prog);
217 perror(Audio_dev);
218 exit(1);
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)));
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);
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);
246 /* Play a list of audio files. */
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];
270 (void) setlocale(LC_ALL, "");
271 (void) textdomain(TEXT_DOMAIN);
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)");
281 /* Check AUDIODEV environment for audio device name */
282 if (cp = getenv("AUDIODEV")) {
283 Audio_dev = cp;
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++;
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*/
316 if (err > 0)
317 exit(1);
319 argc -= optind; /* update arg pointers */
320 argv += optind;
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);
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);
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);
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);
350 (void) close(Audio_fd);
351 Audio_fd = -1;
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) {
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.
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;
372 /* store AUDIOPATH so we don't keep doing getenv() */
373 Audio_path = getenv("AUDIOPATH");
375 /* Set up SIGINT handler to flush output */
376 (void) signal(SIGINT, sigint);
378 /* Set the endian nature of the machine. */
379 if ((ulong_t)1 != htonl((ulong_t)1)) {
380 NetEndian = FALSE;
383 /* If no filenames, read stdin */
384 stdinseen = FALSE;
385 if (argc <= 0) {
386 Ifile = Stdin;
387 } else {
388 Ifile = *argv++;
389 argc--;
392 /* Loop through all filenames */
393 do {
394 /* Interpret "-" filename to mean stdin */
395 if (strcmp(Ifile, "-") == 0)
396 Ifile = Stdin;
398 if (Ifile == Stdin) {
399 if (stdinseen) {
400 Error(stderr,
401 MGET("%s: stdin already processed\n"),
402 prog);
403 goto nextfile;
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;
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;
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]);
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]);
453 } else {
454 Decode = AUDIO_ENCODING_NONE;
457 /* Check the device configuration */
458 open_audio();
459 if (audio_cmp_hdr(&Dev_hdr, &File_hdr) != 0) {
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.
466 if (audio_drain(Audio_fd, FALSE) != AUDIO_SUCCESS) {
467 /* Flush any remaining audio */
468 (void) ioctl(Audio_fd, I_FLUSH, FLUSHW);
470 Error(stderr, MGET("%s: "), prog);
471 perror(MGET("AUDIO_DRAIN error"));
472 exit(1);
475 /* Flush any remaining audio */
476 (void) ioctl(Audio_fd, I_FLUSH, FLUSHW);
478 if (!reconfig()) {
479 errorStatus++;
480 goto closeinput;
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);
492 regular = (S_ISREG(st.st_mode));
495 /* If regular file, map it. Else, allocate a buffer */
496 mapaddr = 0;
499 * This should compare to MAP_FAILED not -1, can't
500 * find MAP_FAILED
502 if (regular && ((mapaddr = mmap(0, st.st_size, PROT_READ,
503 MAP_SHARED, ifd, 0)) != MAP_FAILED)) {
505 (void) madvise(mapaddr, st.st_size, MADV_SEQUENTIAL);
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);
513 inbuf = (unsigned char *) mapaddr + cnt;
514 len = cnt = st.st_size - cnt;
515 } else { /* Not a regular file, or map failed */
517 /* mark is so. */
518 mapaddr = 0;
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);
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);
534 inbuf = buf;
535 bufsiz = cnt;
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;
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.
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.
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.
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;
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;
592 * At this point, we're all ready to copy the data.
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) {
600 * We need to ensure only an integral number of
601 * samples is ever written to the audio device.
603 cnt = cnt + rem;
604 rem = cnt % frame;
605 cnt = cnt - rem;
608 * If decoding adpcm, or swapping bytes do it
609 * now.
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.
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;
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;
658 mux(outbuf);
659 cnt = outsiz;
660 } else if (swapBytes) {
661 swab((char *)inbuf, outbuf, cnt);
664 /* If input EOF, write an eof marker */
665 err = write(Audio_fd, outbuf, cnt);
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;
678 if (cnt == 0) {
679 break;
681 /* Move remainder to the front of the buffer */
682 if (rem != 0) {
683 (void *)memcpy(inbuf, inbuf + cnt, rem);
687 if (cnt < 0) {
688 Error(stderr, MGET("%s: error reading "), prog);
689 perror(Ifile);
690 errorStatus++;
692 } else { /* We're mmaped */
693 if ((Decode != AUDIO_ENCODING_NONE) || swapBytes) {
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;
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;
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;
749 mux(outbuf);
750 } else if (swapBytes) {
751 swab((char *)inbuf, outbuf,
752 cnt);
753 outsiz = cnt;
755 inbuf += cnt;
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;
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++;
775 if (err != len) {
776 Error(stderr,
777 MGET("%s: output error: "), prog);
778 perror("");
779 errorStatus++;
781 err = write(Audio_fd, inbuf, 0);
782 if (err < 0) {
783 perror("write");
784 errorStatus++;
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;
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++;
813 nextfile:;
814 } while ((argc > 0) && (argc--, (Ifile = *argv++) != NULL));
817 * Though drain is implicit on close(), it's performed here
818 * to ensure that the volume is reset after all output is complete.
820 (void) audio_drain(Audio_fd, FALSE);
822 /* Flush any remaining audio */
823 (void) ioctl(Audio_fd, I_FLUSH, FLUSHW);
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);
830 (void) close(Audio_fd); /* close output */
831 return (errorStatus);
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.
840 * Returns TRUE if successful. Returns FALSE if not.
842 static int
843 reconfig(void)
845 int err;
846 char msg[AUDIO_MAX_ENCODE_INFO];
848 Dev_hdr = File_hdr;
849 err = audio_set_play_config(Audio_fd, &Dev_hdr);
851 switch (err) {
852 case AUDIO_SUCCESS:
853 return (TRUE);
855 case AUDIO_ERR_NOEFFECT:
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.
861 if (audio_cmp_hdr(&Dev_hdr, &File_hdr) > 0) {
862 double ratio;
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);
875 return (TRUE);
877 Error(stderr,
878 MGET("%s: %s sample rate %d not available\n"),
879 prog, Ifile, File_hdr.sample_rate);
880 return (FALSE);
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);
887 default:
888 Error(stderr,
889 MGET("%s: %s audio encoding type not available\n"),
890 prog, Ifile);
891 exit(1);
893 return (TRUE);
897 /* Parse an unsigned integer */
898 static int
899 parse_unsigned(char *str, unsigned *dst, char *flag)
901 char x;
903 if (sscanf(str, "%u%c", dst, &x) != 1) {
904 Error(stderr, MGET("%s: invalid value for %s\n"), prog, flag);
905 return (1);
907 return (0);
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.
915 static int
916 path_open(char *fname, int flags, mode_t mode, char *path)
918 char fullpath[MAXPATHLEN]; /* full path of file */
919 char *buf; /* malloc off the tmp buff */
920 char *cp;
921 struct stat st;
923 if (!fname) { /* bogus */
924 return (-1);
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 ../).
934 if ((!path) || (flags != O_RDONLY) || (*fname == '/') ||
935 (strncmp(fname, "./", strlen("./")) == 0) ||
936 (strncmp(fname, "../", strlen("../")) == 0)) {
937 return (open(fname, flags, mode));
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.
945 buf = malloc(strlen(path) + 1);
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 "./".
953 if ((path[0] == ':') && (path[1] != ':')) {
954 (void) strncpy(buf, path+1, strlen(path));
955 } else {
956 (void) strncpy(buf, path, strlen(path));
959 for (path = buf; path && *path; ) {
960 if (cp = strchr(path, ':')) {
961 *cp++ = NULL; /* now pts to next path element */
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);
972 (void) strncat(fullpath, fname, MAXPATHLEN);
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);
984 return (open(fullpath, flags, mode));
988 /* go on to the next one */
989 path = cp;
993 * if we fall through with no match, just do a normal file open
995 return (open(fname, flags, mode));
1000 * initmux()
1002 * Description:
1003 * Allocates memory for carrying out demultiplexing/multiplexing.
1005 * Arguments:
1006 * int unitsz Bytes per unit
1007 * int unitsp Samples per unit
1009 * Returns:
1010 * void
1012 static void
1013 initmux(int unitsz, int unitsp)
1015 int c; /* Channel */
1016 int in_ch_size; /* Input channel size */
1018 /* Size of each input channel */
1019 in_ch_size = insiz / File_hdr.channels;
1021 /* Size of each output channel */
1022 out_ch_size = in_ch_size * unitsp / unitsz;
1024 /* Allocate pointers to input channels */
1025 in_ch_data = malloc(sizeof (unsigned char *) * File_hdr.channels);
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);
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);
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);
1044 /* Allocate pointers to output channels */
1045 out_ch_data = malloc(sizeof (unsigned char *) * File_hdr.channels);
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);
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);
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);
1066 * demux()
1068 * Description:
1069 * Split a multichannel signal into separate channels.
1071 * Arguments:
1072 * int unitsz Bytes per unit
1073 * int cnt Bytes to process
1075 * Returns:
1076 * void
1078 static void
1079 demux(int unitsz, int cnt)
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 */
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];
1100 * mux()
1102 * Description:
1103 * Combine separate channels to produce a multichannel signal.
1105 * Arguments:
1106 * char *outbuf Combined signal
1108 * Returns:
1109 * void
1111 static void
1112 mux(char *outbuf)
1114 int c; /* Channel */
1115 int s; /* Sample */
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];
1126 * freemux()
1128 * Description:
1129 * Free memory used in multiplexing/demultiplexing.
1131 * Arguments:
1132 * void
1134 * Returns:
1135 * void
1137 static void
1138 freemux(void)
1140 int c; /* Channel */
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]);
1149 free(in_ch_data);
1150 free(out_ch_data);