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