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