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