1 /* $NetBSD: play.c,v 1.41 2002/12/08 10:49:22 mrg Exp $ */ 2 3 /* 4 * Copyright (c) 1999 Matthew R. Green 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. The name of the author may not be used to endorse or promote products 16 * derived from this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 23 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 25 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 * SUCH DAMAGE. 29 */ 30 31 #include <sys/param.h> 32 #include <sys/audioio.h> 33 #include <sys/ioctl.h> 34 #include <sys/mman.h> 35 #include <sys/stat.h> 36 37 #include <err.h> 38 #include <fcntl.h> 39 #include <signal.h> 40 #include <stdio.h> 41 #include <stdlib.h> 42 #include <string.h> 43 #include <unistd.h> 44 45 #include <paths.h> 46 47 #include "libaudio.h" 48 49 int main(int, char *[]); 50 void usage(void); 51 void play(char *); 52 void play_fd(const char *, int); 53 ssize_t audioctl_write_fromhdr(void *, size_t, int, size_t *, const char *); 54 void cleanup(int) __attribute__((__noreturn__)); 55 56 audio_info_t info; 57 int volume; 58 int balance; 59 int port; 60 int fflag; 61 int qflag; 62 int verbose; 63 int sample_rate; 64 int encoding; 65 char *encoding_str; 66 int precision; 67 int channels; 68 69 char const *play_errstring = NULL; 70 size_t bufsize; 71 int audiofd; 72 int exitstatus = EXIT_SUCCESS; 73 74 int 75 main(argc, argv) 76 int argc; 77 char *argv[]; 78 { 79 size_t len; 80 int ch; 81 int iflag = 0; 82 const char *defdevice = _PATH_SOUND; 83 const char *device = NULL; 84 85 while ((ch = getopt(argc, argv, "b:C:c:d:e:fhip:P:qs:Vv:")) != -1) { 86 switch (ch) { 87 case 'b': 88 decode_int(optarg, &balance); 89 if (balance < 0 || balance > 64) 90 errx(1, "balance must be between 0 and 63"); 91 break; 92 case 'c': 93 decode_int(optarg, &channels); 94 if (channels < 0) 95 errx(1, "channels must be positive"); 96 break; 97 case 'C': 98 /* Ignore, compatibility */ 99 break; 100 case 'd': 101 device = optarg; 102 break; 103 case 'e': 104 encoding_str = optarg; 105 break; 106 case 'f': 107 fflag = 1; 108 break; 109 case 'i': 110 iflag++; 111 break; 112 case 'q': 113 qflag++; 114 break; 115 case 'P': 116 decode_int(optarg, &precision); 117 if (precision != 4 && precision != 8 && 118 precision != 16 && precision != 24 && 119 precision != 32) 120 errx(1, "precision must be between 4, 8, 16, 24 or 32"); 121 break; 122 case 'p': 123 len = strlen(optarg); 124 125 if (strncmp(optarg, "speaker", len) == 0) 126 port |= AUDIO_SPEAKER; 127 else if (strncmp(optarg, "headphone", len) == 0) 128 port |= AUDIO_HEADPHONE; 129 else if (strncmp(optarg, "line", len) == 0) 130 port |= AUDIO_LINE_OUT; 131 else 132 errx(1, 133 "port must be `speaker', `headphone', or `line'"); 134 break; 135 case 's': 136 decode_int(optarg, &sample_rate); 137 if (sample_rate < 0 || sample_rate > 48000 * 2) /* XXX */ 138 errx(1, "sample rate must be between 0 and 96000"); 139 break; 140 case 'V': 141 verbose++; 142 break; 143 case 'v': 144 volume = atoi(optarg); 145 if (volume < 0 || volume > 255) 146 errx(1, "volume must be between 0 and 255"); 147 break; 148 /* case 'h': */ 149 default: 150 usage(); 151 /* NOTREACHED */ 152 } 153 } 154 argc -= optind; 155 argv += optind; 156 157 if (encoding_str) { 158 encoding = audio_enc_to_val(encoding_str); 159 if (encoding == -1) 160 errx(1, "unknown encoding, bailing..."); 161 } 162 163 if (device == NULL && (device = getenv("AUDIODEVICE")) == NULL && 164 (device = getenv("AUDIODEV")) == NULL) /* Sun compatibility */ 165 device = defdevice; 166 167 audiofd = open(device, O_WRONLY); 168 if (audiofd < 0 && device == defdevice) { 169 device = _PATH_SOUND0; 170 audiofd = open(device, O_WRONLY); 171 } 172 173 if (audiofd < 0) 174 err(1, "failed to open %s", device); 175 176 if (ioctl(audiofd, AUDIO_GETINFO, &info) < 0) 177 err(1, "failed to get audio info"); 178 bufsize = info.play.buffer_size; 179 if (bufsize < 32 * 1024) 180 bufsize = 32 * 1024; 181 182 signal(SIGINT, cleanup); 183 signal(SIGTERM, cleanup); 184 signal(SIGHUP, cleanup); 185 186 if (*argv) 187 do 188 play(*argv++); 189 while (*argv); 190 else 191 play_fd("standard input", STDIN_FILENO); 192 193 cleanup(0); 194 } 195 196 void 197 cleanup(signo) 198 int signo; 199 { 200 201 (void)ioctl(audiofd, AUDIO_FLUSH, NULL); 202 (void)ioctl(audiofd, AUDIO_SETINFO, &info); 203 close(audiofd); 204 exit(exitstatus); 205 } 206 207 void 208 play(file) 209 char *file; 210 { 211 struct stat sb; 212 void *addr, *oaddr; 213 off_t filesize; 214 size_t sizet_filesize; 215 size_t datasize = 0; 216 ssize_t hdrlen; 217 int fd; 218 219 if (file[0] == '-' && file[1] == 0) { 220 play_fd("standard input", STDIN_FILENO); 221 return; 222 } 223 224 fd = open(file, O_RDONLY); 225 if (fd < 0) { 226 if (!qflag) 227 warn("could not open %s", file); 228 exitstatus = EXIT_FAILURE; 229 return; 230 } 231 232 if (fstat(fd, &sb) < 0) 233 err(1, "could not fstat %s", file); 234 filesize = sb.st_size; 235 sizet_filesize = (size_t)filesize; 236 237 /* 238 * if the file is not a regular file, doesn't fit in a size_t, 239 * or if we failed to mmap the file, try to read it instead, so 240 * that filesystems, etc, that do not support mmap() work 241 */ 242 if (S_ISREG(sb.st_rdev & S_IFMT) == 0 || 243 ((off_t)sizet_filesize != filesize) || 244 (oaddr = addr = mmap(0, sizet_filesize, PROT_READ, 245 MAP_SHARED, fd, 0)) == MAP_FAILED) { 246 play_fd(file, fd); 247 close(fd); 248 return; 249 } 250 251 /* 252 * give the VM system a bit of a hint about the type 253 * of accesses we will make. 254 */ 255 if (madvise(addr, sizet_filesize, MADV_SEQUENTIAL) < 0 && 256 !qflag) 257 warn("madvise failed, ignoring"); 258 259 /* 260 * get the header length and set up the audio device 261 */ 262 if ((hdrlen = audioctl_write_fromhdr(addr, 263 sizet_filesize, audiofd, &datasize, file)) < 0) { 264 if (play_errstring) 265 errx(1, "%s: %s", play_errstring, file); 266 else 267 errx(1, "unknown audio file: %s", file); 268 } 269 270 filesize -= hdrlen; 271 addr = (char *)addr + hdrlen; 272 if (filesize < datasize || datasize == 0) { 273 if (filesize < datasize) 274 warnx("bogus datasize: %ld", (u_long)datasize); 275 datasize = filesize; 276 } 277 278 while (datasize > bufsize) { 279 if (write(audiofd, addr, bufsize) != bufsize) 280 err(1, "write failed"); 281 addr = (char *)addr + bufsize; 282 datasize -= bufsize; 283 } 284 if (write(audiofd, addr, (size_t)datasize) != (ssize_t)datasize) 285 err(1, "final write failed"); 286 287 if (ioctl(audiofd, AUDIO_DRAIN) < 0 && !qflag) 288 warn("audio drain ioctl failed"); 289 if (munmap(oaddr, sizet_filesize) < 0) 290 err(1, "munmap failed"); 291 292 close(fd); 293 } 294 295 /* 296 * play the file on the file descriptor fd 297 */ 298 void 299 play_fd(file, fd) 300 const char *file; 301 int fd; 302 { 303 char *buffer = malloc(bufsize); 304 ssize_t hdrlen; 305 int nr, nw; 306 size_t datasize = 0; 307 size_t dataout = 0; 308 309 if (buffer == NULL) 310 err(1, "malloc of read buffer failed"); 311 312 nr = read(fd, buffer, bufsize); 313 if (nr < 0) 314 goto read_error; 315 if (nr == 0) { 316 if (fflag) 317 return; 318 err(1, "unexpected EOF"); 319 } 320 hdrlen = audioctl_write_fromhdr(buffer, nr, audiofd, &datasize, file); 321 if (hdrlen < 0) { 322 if (play_errstring) 323 errx(1, "%s: %s", play_errstring, file); 324 else 325 errx(1, "unknown audio file: %s", file); 326 } 327 if (hdrlen > 0) { 328 if (hdrlen >= nr) /* shouldn't happen */ 329 errx(1, "header seems really large"); 330 memmove(buffer, buffer + hdrlen, nr - hdrlen); 331 nr -= hdrlen; 332 } 333 while (datasize == 0 || dataout < datasize) { 334 if (datasize != 0 && dataout + nr > datasize) 335 nr = datasize - dataout; 336 nw = write(audiofd, buffer, nr); 337 if (nw != nr) 338 goto write_error; 339 dataout += nw; 340 nr = read(fd, buffer, bufsize); 341 if (nr == -1) 342 goto read_error; 343 if (nr == 0) 344 break; 345 } 346 /* something to think about: no message given for dataout < datasize */ 347 if (ioctl(audiofd, AUDIO_DRAIN) < 0 && !qflag) 348 warn("audio drain ioctl failed"); 349 return; 350 read_error: 351 err(1, "read of standard input failed"); 352 write_error: 353 err(1, "audio device write failed"); 354 } 355 356 /* 357 * only support sun and wav audio files so far ... 358 * 359 * XXX this should probably be mostly part of libaudio, but it 360 * uses the local "info" variable. blah... fix me! 361 */ 362 ssize_t 363 audioctl_write_fromhdr(hdr, fsz, fd, datasize, file) 364 void *hdr; 365 size_t fsz; 366 int fd; 367 size_t *datasize; 368 const char *file; 369 { 370 sun_audioheader *sunhdr; 371 ssize_t hdr_len; 372 373 AUDIO_INITINFO(&info); 374 sunhdr = hdr; 375 if (ntohl(sunhdr->magic) == AUDIO_FILE_MAGIC) { 376 if (audio_sun_to_encoding(ntohl(sunhdr->encoding), 377 &info.play.encoding, &info.play.precision)) { 378 if (!qflag) 379 warnx("unknown unsupported Sun audio encoding" 380 " format %d", ntohl(sunhdr->encoding)); 381 if (fflag) 382 goto set_audio_mode; 383 return (-1); 384 } 385 386 info.play.sample_rate = ntohl(sunhdr->sample_rate); 387 info.play.channels = ntohl(sunhdr->channels); 388 hdr_len = ntohl(sunhdr->hdr_size); 389 390 *datasize = ntohl(sunhdr->data_size); 391 goto set_audio_mode; 392 } 393 394 hdr_len = audio_wav_parse_hdr(hdr, fsz, &info.play.encoding, 395 &info.play.precision, &info.play.sample_rate, &info.play.channels, 396 datasize); 397 398 switch (hdr_len) { 399 case AUDIO_ESHORTHDR: 400 case AUDIO_EWAVUNSUPP: 401 case AUDIO_EWAVBADPCM: 402 case AUDIO_EWAVNODATA: 403 play_errstring = audio_errstring(hdr_len); 404 /* FALL THROUGH */ 405 case AUDIO_ENOENT: 406 break; 407 default: 408 if (hdr_len < 1) 409 break; 410 goto set_audio_mode; 411 } 412 /* 413 * if we don't know it, bail unless we are forcing. 414 */ 415 if (fflag == 0) 416 return (-1); 417 set_audio_mode: 418 if (port) 419 info.play.port = port; 420 if (volume) 421 info.play.gain = volume; 422 if (balance) 423 info.play.balance = balance; 424 if (fflag) { 425 if (sample_rate) 426 info.play.sample_rate = sample_rate; 427 if (channels) 428 info.play.channels = channels; 429 if (encoding) 430 info.play.encoding = encoding; 431 if (precision) 432 info.play.precision = precision; 433 hdr_len = 0; 434 } 435 info.mode = AUMODE_PLAY_ALL; 436 437 if (verbose) { 438 const char *enc = audio_enc_from_val(info.play.encoding); 439 440 printf("%s: sample_rate=%d channels=%d " 441 "precision=%d%s%s\n", file, 442 info.play.sample_rate, 443 info.play.channels, 444 info.play.precision, 445 enc ? " encoding=" : "", 446 enc ? enc : ""); 447 } 448 449 if (ioctl(fd, AUDIO_SETINFO, &info) < 0) 450 err(1, "failed to set audio info"); 451 452 return (hdr_len); 453 } 454 455 void 456 usage() 457 { 458 459 fprintf(stderr, "Usage: %s [-hiqV] [options] files\n", getprogname()); 460 fprintf(stderr, "Options:\n\t" 461 "-C audio control device\n\t" 462 "-b balance (0-63)\n\t" 463 "-d audio device\n\t" 464 "-f force settings\n\t" 465 "\t-c forced channels\n\t" 466 "\t-e forced encoding\n\t" 467 "\t-P forced precision\n\t" 468 "\t-s forced sample rate\n\t" 469 "-i header information\n\t" 470 "-m monitor volume\n\t" 471 "-p output port\n\t" 472 "-v volume\n"); 473 exit(EXIT_FAILURE); 474 } 475