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