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 */
62static char *prog;
63
64static char prog_opts[] =	"VEiv:d:?";	/* getopt() flags */
65
66static 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
81static unsigned		Volume = INT_MAX;	/* output volume */
82static double		Savevol;		/* saved volume level */
83
84static int		Verbose = FALSE;	/* verbose messages */
85static int		Immediate = FALSE;
86			/* don't hang waiting for device */
87static int		Errdetect = FALSE;	/* don't worry about underrun */
88static char		*Audio_dev = "/dev/audio";
89
90static int NetEndian = TRUE;		/* endian nature of the machine */
91
92static int		Audio_fd = -1;
93			/* file descriptor for audio device */
94static int		Audio_ctlfd = -1;
95			/* file descriptor for control device */
96static Audio_hdr	Save_hdr;
97			/* saved audio header for device */
98static Audio_hdr	Dev_hdr;		/* audio header for device */
99static char		*Ifile;			/* current filename */
100static Audio_hdr	File_hdr;		/* audio header for file */
101static unsigned		Decode = AUDIO_ENCODING_NONE;
102			/* decode type, if any */
103
104static unsigned char	*buf = NULL;		/* dynamically alloc'd */
105static unsigned		bufsiz = 0;		/* size of output buffer */
106static unsigned char	adpcm_buf[ADPCM_SIZE + 32];
107			/* for adpcm conversion */
108static unsigned char	swap_buf[SWAP_SIZE + 32];
109			/* for byte swap conversion */
110static unsigned char	*inbuf;
111			/* current input buffer pointer */
112static 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 */
126static struct audio_g72x_state *adpcm_state = NULL;
127static unsigned char	**in_ch_data = NULL;	/* input channels */
128static unsigned char	**out_ch_data = NULL;	/* output channels */
129static int		out_ch_size;		/* output channel size */
130
131static char		*Audio_path = NULL;
132			/* path to search for audio files */
133
134/* Global variables */
135extern int	getopt(int, char *const *, const char *);
136extern int	optind;
137extern char	*optarg;
138
139/* Local functions  */
140static void usage(void);
141static void sigint(int sig);
142static void open_audio(void);
143static int path_open(char *fname, int flags, mode_t mode, char *path);
144static int parse_unsigned(char *str, unsigned *dst, char *flag);
145static int reconfig(void);
146static void initmux(int unitsz, int unitsp);
147static void demux(int unitsz, int cnt);
148static void mux(char *);
149static void freemux(void);
150
151
152static void
153usage(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
168static void
169sigint(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. */
187static void
188open_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. */
247int
248main(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
799closeinput:;
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		}
813nextfile:;
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 */
842static int
843reconfig(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 */
898static int
899parse_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 */
915static int
916path_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 */
1012static void
1013initmux(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 */
1078static void
1079demux(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 */
1111static void
1112mux(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 */
1137static void
1138freemux(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