dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / cmd / audio / audioplay / audioplay.c
blob630d846fac90200fa5b61521e49d19364ff7f4a2
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, NULL, 0);
419 if (err != AUDIO_SUCCESS) {
420 Error(stderr,
421 MGET("%s: %s is not a valid audio file\n"),
422 prog, Ifile);
423 errorStatus++;
424 goto closeinput;
427 /* If G.72X adpcm, set flags for conversion */
428 if ((File_hdr.encoding == AUDIO_ENCODING_G721) &&
429 (File_hdr.samples_per_unit == 2) &&
430 (File_hdr.bytes_per_unit == 1)) {
431 Decode = AUDIO_ENCODING_G721;
432 File_hdr.encoding = AUDIO_ENCODING_ULAW;
433 File_hdr.samples_per_unit = 1;
434 File_hdr.bytes_per_unit = 1;
435 adpcm_state = (struct audio_g72x_state *)malloc
436 (sizeof (*adpcm_state) * File_hdr.channels);
437 for (i = 0; i < File_hdr.channels; i++) {
438 g721_init_state(&adpcm_state[i]);
440 } else if ((File_hdr.encoding == AUDIO_ENCODING_G723) &&
441 (File_hdr.samples_per_unit == 8) &&
442 (File_hdr.bytes_per_unit == 3)) {
443 Decode = AUDIO_ENCODING_G723;
444 File_hdr.encoding = AUDIO_ENCODING_ULAW;
445 File_hdr.samples_per_unit = 1;
446 File_hdr.bytes_per_unit = 1;
447 adpcm_state = (struct audio_g72x_state *)malloc
448 (sizeof (*adpcm_state) * File_hdr.channels);
449 for (i = 0; i < File_hdr.channels; i++) {
450 g723_init_state(&adpcm_state[i]);
452 } else {
453 Decode = AUDIO_ENCODING_NONE;
456 /* Check the device configuration */
457 open_audio();
458 if (audio_cmp_hdr(&Dev_hdr, &File_hdr) != 0) {
460 * The device does not match the input file.
461 * Wait for any old output to drain, then attempt
462 * to reconfigure the audio device to match the
463 * input data.
465 if (audio_drain(Audio_fd, FALSE) != AUDIO_SUCCESS) {
466 /* Flush any remaining audio */
467 (void) ioctl(Audio_fd, I_FLUSH, FLUSHW);
469 Error(stderr, MGET("%s: "), prog);
470 perror(MGET("AUDIO_DRAIN error"));
471 exit(1);
474 /* Flush any remaining audio */
475 (void) ioctl(Audio_fd, I_FLUSH, FLUSHW);
477 if (!reconfig()) {
478 errorStatus++;
479 goto closeinput;
484 /* try to do the mmaping - for regular files only ... */
485 err = fstat(ifd, &st);
486 if (err < 0) {
487 Error(stderr, MGET("%s: cannot stat "), prog);
488 perror(Ifile);
489 exit(1);
491 regular = (S_ISREG(st.st_mode));
494 /* If regular file, map it. Else, allocate a buffer */
495 mapaddr = 0;
498 * This should compare to MAP_FAILED not -1, can't
499 * find MAP_FAILED
501 if (regular && ((mapaddr = mmap(NULL, st.st_size, PROT_READ,
502 MAP_SHARED, ifd, 0)) != MAP_FAILED)) {
504 (void) madvise(mapaddr, st.st_size, MADV_SEQUENTIAL);
506 /* Skip the file header and set the proper size */
507 cnt = lseek(ifd, 0, SEEK_CUR);
508 if (cnt < 0) {
509 perror("lseek");
510 exit(1);
512 inbuf = (unsigned char *) mapaddr + cnt;
513 len = cnt = st.st_size - cnt;
514 } else { /* Not a regular file, or map failed */
516 /* mark is so. */
517 mapaddr = 0;
519 /* Allocate buffer to hold 10 seconds of data */
520 cnt = BUFFER_LEN * File_hdr.sample_rate *
521 File_hdr.bytes_per_unit * File_hdr.channels;
522 if (bufsiz != cnt) {
523 if (buf != NULL) {
524 (void) free(buf);
526 buf = (unsigned char *) malloc(cnt);
527 if (buf == NULL) {
528 Error(stderr,
529 MGET("%s: couldn't allocate %dK "
530 "buf\n"), prog, bufsiz / 1000);
531 exit(1);
533 inbuf = buf;
534 bufsiz = cnt;
538 /* Set buffer sizes and pointers for conversion, if any */
539 switch (Decode) {
540 default:
541 case AUDIO_ENCODING_NONE:
542 insiz = bufsiz;
543 outbuf = (char *)buf;
544 break;
545 case AUDIO_ENCODING_G721:
546 insiz = ADPCM_SIZE / 2;
547 outbuf = (char *)adpcm_buf;
548 initmux(1, 2);
549 break;
550 case AUDIO_ENCODING_G723:
551 insiz = (ADPCM_SIZE * 3) / 8;
552 outbuf = (char *)adpcm_buf;
553 initmux(3, 8);
554 break;
558 * 8-bit audio isn't a problem, however 16-bit audio is.
559 * If the file is an endian that is different from the machine
560 * then the bytes will need to be swapped.
562 * Note: Because the G.72X conversions produce 8bit output,
563 * they don't require a byte swap before display and so
564 * this scheme works just fine. If a conversion is added
565 * that produces a 16 bit result and therefore requires
566 * byte swapping before output, then a mechanism
567 * for chaining the two conversions will have to be built.
569 * Note: The following if() could be simplified, but then
570 * it gets to be very hard to read. So it's left as is.
573 if (File_hdr.bytes_per_unit == 2 &&
574 ((!NetEndian && file_type == FILE_AIFF) ||
575 (!NetEndian && file_type == FILE_AU) ||
576 (NetEndian && file_type == FILE_WAV))) {
577 swapBytes = TRUE;
578 } else {
579 swapBytes = FALSE;
582 if (swapBytes) {
583 /* Read in interal number of sample frames. */
584 frame = File_hdr.bytes_per_unit * File_hdr.channels;
585 insiz = (SWAP_SIZE / frame) * frame;
586 /* make the output buffer the swap buffer. */
587 outbuf = (char *)swap_buf;
591 * At this point, we're all ready to copy the data.
593 if (mapaddr == 0) { /* Not mmapped, do it a buffer at a time. */
594 inbuf = buf;
595 frame = File_hdr.bytes_per_unit * File_hdr.channels;
596 rem = 0;
597 while ((cnt = read(ifd, inbuf+rem, insiz-rem)) >= 0) {
599 * We need to ensure only an integral number of
600 * samples is ever written to the audio device.
602 cnt = cnt + rem;
603 rem = cnt % frame;
604 cnt = cnt - rem;
607 * If decoding adpcm, or swapping bytes do it
608 * now.
610 * We treat the swapping like a separate
611 * encoding here because the G.72X encodings
612 * decode to single byte output samples. If
613 * another encoding is added and it produces
614 * multi-byte output samples this will have to
615 * be changed.
617 if (Decode == AUDIO_ENCODING_G721) {
618 outsiz = 0;
619 demux(1, cnt / File_hdr.channels);
620 for (c = 0; c < File_hdr.channels; c++) {
621 err = g721_decode(in_ch_data[c],
622 cnt / File_hdr.channels,
623 &File_hdr,
624 (void*)out_ch_data[c],
625 &tsize,
626 &adpcm_state[c]);
627 outsiz = outsiz + tsize;
628 if (err != AUDIO_SUCCESS) {
629 Error(stderr, MGET(
630 "%s: error decoding g721\n"),
631 prog);
632 errorStatus++;
633 break;
636 mux(outbuf);
637 cnt = outsiz;
638 } else if (Decode == AUDIO_ENCODING_G723) {
639 outsiz = 0;
640 demux(3, cnt / File_hdr.channels);
641 for (c = 0; c < File_hdr.channels; c++) {
642 err = g723_decode(in_ch_data[c],
643 cnt / File_hdr.channels,
644 &File_hdr,
645 (void*)out_ch_data[c],
646 &tsize,
647 &adpcm_state[c]);
648 outsiz = outsiz + tsize;
649 if (err != AUDIO_SUCCESS) {
650 Error(stderr, MGET(
651 "%s: error decoding g723\n"),
652 prog);
653 errorStatus++;
654 break;
657 mux(outbuf);
658 cnt = outsiz;
659 } else if (swapBytes) {
660 swab((char *)inbuf, outbuf, cnt);
663 /* If input EOF, write an eof marker */
664 err = write(Audio_fd, outbuf, cnt);
666 if (err < 0) {
667 perror("write");
668 errorStatus++;
669 break;
670 } else if (err != cnt) {
671 Error(stderr,
672 MGET("%s: output error: "), prog);
673 perror("");
674 errorStatus++;
675 break;
677 if (cnt == 0) {
678 break;
680 /* Move remainder to the front of the buffer */
681 if (rem != 0) {
682 (void *)memcpy(inbuf, inbuf + cnt, rem);
686 if (cnt < 0) {
687 Error(stderr, MGET("%s: error reading "), prog);
688 perror(Ifile);
689 errorStatus++;
691 } else { /* We're mmaped */
692 if ((Decode != AUDIO_ENCODING_NONE) || swapBytes) {
694 /* Transform data if we have to. */
695 for (i = 0; i <= len; i += cnt) {
696 cnt = insiz;
697 if ((i + cnt) > len) {
698 cnt = len - i;
700 if (Decode == AUDIO_ENCODING_G721) {
701 outsiz = 0;
702 demux(1, cnt / File_hdr.channels);
703 for (c = 0; c < File_hdr.channels;
704 c++) {
705 err = g721_decode(
706 in_ch_data[c],
707 cnt / File_hdr.channels,
708 &File_hdr,
709 (void*)out_ch_data[c],
710 &tsize,
711 &adpcm_state[c]);
712 outsiz = outsiz + tsize;
713 if (err != AUDIO_SUCCESS) {
714 Error(stderr, MGET(
715 "%s: error decoding "
716 "g721\n"), prog);
717 errorStatus++;
718 break;
721 mux(outbuf);
722 } else if
723 (Decode == AUDIO_ENCODING_G723) {
724 outsiz = 0;
725 demux(3,
726 cnt / File_hdr.channels);
727 for (c = 0;
728 c < File_hdr.channels;
729 c++) {
730 err = g723_decode(
731 in_ch_data[c],
732 cnt /
733 File_hdr.channels,
734 &File_hdr,
735 (void*)out_ch_data[c],
736 &tsize,
737 &adpcm_state[c]);
738 outsiz = outsiz + tsize;
739 if (err != AUDIO_SUCCESS) {
740 Error(stderr, MGET(
741 "%s: error "
742 "decoding g723\n"),
743 prog);
744 errorStatus++;
745 break;
748 mux(outbuf);
749 } else if (swapBytes) {
750 swab((char *)inbuf, outbuf,
751 cnt);
752 outsiz = cnt;
754 inbuf += cnt;
756 /* If input EOF, write an eof marker */
757 err = write(Audio_fd, (char *)outbuf,
758 outsiz);
759 if (err < 0) {
760 perror("write");
761 errorStatus++;
762 } else if (outsiz == 0) {
763 break;
767 } else {
768 /* write the whole thing at once! */
769 err = write(Audio_fd, inbuf, len);
770 if (err < 0) {
771 perror("write");
772 errorStatus++;
774 if (err != len) {
775 Error(stderr,
776 MGET("%s: output error: "), prog);
777 perror("");
778 errorStatus++;
780 err = write(Audio_fd, inbuf, 0);
781 if (err < 0) {
782 perror("write");
783 errorStatus++;
788 /* Free memory if decoding ADPCM */
789 switch (Decode) {
790 case AUDIO_ENCODING_G721:
791 case AUDIO_ENCODING_G723:
792 freemux();
793 break;
794 default:
795 break;
798 closeinput:;
799 if (mapaddr != 0)
800 (void) munmap(mapaddr, st.st_size);
801 (void) close(ifd); /* close input file */
802 if (Errdetect) {
803 cnt = 0;
804 audio_set_play_error(Audio_fd, (unsigned int *)&cnt);
805 if (cnt) {
806 Error(stderr,
807 MGET("%s: output underflow in %s\n"),
808 Ifile, prog);
809 errorStatus++;
812 nextfile:;
813 } while ((argc > 0) && (argc--, (Ifile = *argv++) != NULL));
816 * Though drain is implicit on close(), it's performed here
817 * to ensure that the volume is reset after all output is complete.
819 (void) audio_drain(Audio_fd, FALSE);
821 /* Flush any remaining audio */
822 (void) ioctl(Audio_fd, I_FLUSH, FLUSHW);
824 if (Volume != INT_MAX)
825 (void) audio_set_play_gain(Audio_fd, &Savevol);
826 if ((Audio_ctlfd >= 0) && (audio_cmp_hdr(&Save_hdr, &Dev_hdr) != 0)) {
827 (void) audio_set_play_config(Audio_fd, &Save_hdr);
829 (void) close(Audio_fd); /* close output */
830 return (errorStatus);
835 * Try to reconfigure the audio device to match the file encoding.
836 * If this fails, we should attempt to make the input data match the
837 * device encoding. For now, we give up on this file.
839 * Returns TRUE if successful. Returns FALSE if not.
841 static int
842 reconfig(void)
844 int err;
845 char msg[AUDIO_MAX_ENCODE_INFO];
847 Dev_hdr = File_hdr;
848 err = audio_set_play_config(Audio_fd, &Dev_hdr);
850 switch (err) {
851 case AUDIO_SUCCESS:
852 return (TRUE);
854 case AUDIO_ERR_NOEFFECT:
856 * Couldn't change the device.
857 * Check to see if we're nearly compatible.
858 * audio_cmp_hdr() returns >0 if only sample rate difference.
860 if (audio_cmp_hdr(&Dev_hdr, &File_hdr) > 0) {
861 double ratio;
863 ratio = (double)abs((int)
864 (Dev_hdr.sample_rate - File_hdr.sample_rate)) /
865 (double)File_hdr.sample_rate;
866 if (ratio <= SAMPLE_RATE_THRESHOLD) {
867 if (Verbose) {
868 Error(stderr,
869 MGET("%s: WARNING: %s sampled at "
870 "%d, playing at %d\n"),
871 prog, Ifile, File_hdr.sample_rate,
872 Dev_hdr.sample_rate);
874 return (TRUE);
876 Error(stderr,
877 MGET("%s: %s sample rate %d not available\n"),
878 prog, Ifile, File_hdr.sample_rate);
879 return (FALSE);
881 (void) audio_enc_to_str(&File_hdr, msg);
882 Error(stderr, MGET("%s: %s encoding not available: %s\n"),
883 prog, Ifile, msg);
884 return (FALSE);
886 default:
887 Error(stderr,
888 MGET("%s: %s audio encoding type not available\n"),
889 prog, Ifile);
890 exit(1);
892 return (TRUE);
896 /* Parse an unsigned integer */
897 static int
898 parse_unsigned(char *str, unsigned *dst, char *flag)
900 char x;
902 if (sscanf(str, "%u%c", dst, &x) != 1) {
903 Error(stderr, MGET("%s: invalid value for %s\n"), prog, flag);
904 return (1);
906 return (0);
910 * Search for fname in path and open. Ignore path not opened O_RDONLY.
911 * Note: in general path can be a list of ':' separated paths to search
912 * through.
914 static int
915 path_open(char *fname, int flags, mode_t mode, char *path)
917 char fullpath[MAXPATHLEN]; /* full path of file */
918 char *buf; /* malloc off the tmp buff */
919 char *cp;
920 struct stat st;
922 if (!fname) { /* bogus */
923 return (-1);
927 * cases where we don't bother checking path:
928 * - no path
929 * - file not opened O_RDONLY
930 * - not a relative path (i.e. starts with /, ./, or ../).
933 if ((!path) || (flags != O_RDONLY) || (*fname == '/') ||
934 (strncmp(fname, "./", strlen("./")) == 0) ||
935 (strncmp(fname, "../", strlen("../")) == 0)) {
936 return (open(fname, flags, mode));
940 * Malloc off a buffer to hold the path variable.
941 * This is NOT limited to MAXPATHLEN characters as
942 * it may contain multiple paths.
944 buf = malloc(strlen(path) + 1);
947 * if first character is ':', but not the one following it,
948 * skip over it - or it'll be interpreted as "./". it's OK
949 * to have "::" since that does mean "./".
952 if ((path[0] == ':') && (path[1] != ':')) {
953 (void) strncpy(buf, path+1, strlen(path));
954 } else {
955 (void) strncpy(buf, path, strlen(path));
958 for (path = buf; path && *path; ) {
959 if (cp = strchr(path, ':')) {
960 *cp++ = '\0'; /* now pts to next path element */
963 /* the safest way to create the path string :-) */
964 if (*path) {
965 (void) strncpy(fullpath, path, MAXPATHLEN);
966 (void) strncat(fullpath, "/", MAXPATHLEN);
967 } else {
968 /* a NULL path element means "./" */
969 (void) strncpy(fullpath, "./", MAXPATHLEN);
971 (void) strncat(fullpath, fname, MAXPATHLEN);
973 /* see if there's a match */
974 if (stat(fullpath, &st) >= 0) {
975 if (S_ISREG(st.st_mode)) {
976 /* got a match! */
977 if (Verbose) {
978 Error(stderr,
979 MGET("%s: Found %s in path "
980 "at %s\n"),
981 prog, fname, fullpath);
983 return (open(fullpath, flags, mode));
987 /* go on to the next one */
988 path = cp;
992 * if we fall through with no match, just do a normal file open
994 return (open(fname, flags, mode));
999 * initmux()
1001 * Description:
1002 * Allocates memory for carrying out demultiplexing/multiplexing.
1004 * Arguments:
1005 * int unitsz Bytes per unit
1006 * int unitsp Samples per unit
1008 * Returns:
1009 * void
1011 static void
1012 initmux(int unitsz, int unitsp)
1014 int c; /* Channel */
1015 int in_ch_size; /* Input channel size */
1017 /* Size of each input channel */
1018 in_ch_size = insiz / File_hdr.channels;
1020 /* Size of each output channel */
1021 out_ch_size = in_ch_size * unitsp / unitsz;
1023 /* Allocate pointers to input channels */
1024 in_ch_data = malloc(sizeof (unsigned char *) * File_hdr.channels);
1026 if (in_ch_data == NULL) {
1027 Error(stderr, MGET("%s: couldn't allocate %dK buf\n"),
1028 prog, sizeof (unsigned char *) * File_hdr.channels / 1000);
1029 exit(1);
1032 /* Allocate input channels */
1033 for (c = 0; c < File_hdr.channels; c++) {
1034 in_ch_data[c] = malloc(sizeof (unsigned char) * in_ch_size);
1036 if (in_ch_data[c] == NULL) {
1037 Error(stderr, MGET("%s: couldn't allocate %dK buf\n"),
1038 prog, in_ch_size / 1000);
1039 exit(1);
1043 /* Allocate pointers to output channels */
1044 out_ch_data = malloc(sizeof (unsigned char *) * File_hdr.channels);
1046 if (out_ch_data == NULL) {
1047 Error(stderr, MGET("%s: couldn't allocate %dK buf\n"),
1048 prog, sizeof (unsigned char *) * File_hdr.channels / 1000);
1049 exit(1);
1052 /* Allocate output channels */
1053 for (c = 0; c < File_hdr.channels; c++) {
1054 out_ch_data[c] = malloc(sizeof (unsigned char) * out_ch_size);
1056 if (out_ch_data[c] == NULL) {
1057 Error(stderr, MGET("%s: couldn't allocate %dK buf\n"),
1058 prog, out_ch_size / 1000);
1059 exit(1);
1065 * demux()
1067 * Description:
1068 * Split a multichannel signal into separate channels.
1070 * Arguments:
1071 * int unitsz Bytes per unit
1072 * int cnt Bytes to process
1074 * Returns:
1075 * void
1077 static void
1078 demux(int unitsz, int cnt)
1080 int c; /* Channel */
1081 int s; /* Sample */
1082 int b; /* Byte */
1083 int tp; /* Pointer into current data */
1084 int dp; /* Pointer into target data */
1086 /* Split */
1087 for (c = 0; c < File_hdr.channels; c++) {
1088 for (s = 0; s < cnt / unitsz; s++) {
1089 tp = s * unitsz;
1090 dp = (s * File_hdr.channels + c) * unitsz;
1091 for (b = 0; b < unitsz; b++) {
1092 in_ch_data[c][tp + b] = inbuf[dp + b];
1099 * mux()
1101 * Description:
1102 * Combine separate channels to produce a multichannel signal.
1104 * Arguments:
1105 * char *outbuf Combined signal
1107 * Returns:
1108 * void
1110 static void
1111 mux(char *outbuf)
1113 int c; /* Channel */
1114 int s; /* Sample */
1116 /* Combine */
1117 for (c = 0; c < File_hdr.channels; c++) {
1118 for (s = 0; s < out_ch_size; s++) {
1119 outbuf[File_hdr.channels * s + c] = out_ch_data[c][s];
1125 * freemux()
1127 * Description:
1128 * Free memory used in multiplexing/demultiplexing.
1130 * Arguments:
1131 * void
1133 * Returns:
1134 * void
1136 static void
1137 freemux(void)
1139 int c; /* Channel */
1141 /* Free */
1142 for (c = 0; c < File_hdr.channels; c++) {
1143 free(in_ch_data[c]);
1144 free(out_ch_data[c]);
1145 free(&adpcm_state[c]);
1148 free(in_ch_data);
1149 free(out_ch_data);