1 /* $NetBSD: play.c,v 1.28 2002/01/13 04:48:33 ross 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 <stdio.h> 40 #include <stdlib.h> 41 #include <string.h> 42 #include <unistd.h> 43 44 #include <paths.h> 45 46 #include "libaudio.h" 47 48 int main (int, char *[]); 49 void usage (void); 50 void play (char *); 51 void play_fd (const char *, int); 52 ssize_t audioctl_write_fromhdr (void *, size_t, int, size_t *); 53 54 audio_info_t info; 55 int volume; 56 int balance; 57 int port; 58 int fflag; 59 int qflag; 60 int sample_rate; 61 int encoding; 62 char *encoding_str; 63 int precision; 64 int channels; 65 66 char const *play_errstring = NULL; 67 size_t bufsize; 68 int audiofd, ctlfd; 69 int exitstatus = EXIT_SUCCESS; 70 71 int 72 main(argc, argv) 73 int argc; 74 char *argv[]; 75 { 76 size_t len; 77 int ch; 78 int iflag = 0; 79 int verbose = 0; 80 const char *device = 0; 81 const char *ctldev = 0; 82 83 while ((ch = getopt(argc, argv, "b:C:c:d:e:fhip:P:qs:Vv:")) != -1) { 84 switch (ch) { 85 case 'b': 86 decode_int(optarg, &balance); 87 if (balance < 0 || balance > 64) 88 errx(1, "balance must be between 0 and 64"); 89 break; 90 case 'c': 91 decode_int(optarg, &channels); 92 if (channels < 0) 93 errx(1, "channels must be positive"); 94 break; 95 case 'C': 96 ctldev = optarg; 97 break; 98 case 'd': 99 device = optarg; 100 break; 101 case 'e': 102 encoding_str = optarg; 103 break; 104 case 'f': 105 fflag = 1; 106 break; 107 case 'i': 108 iflag++; 109 break; 110 case 'q': 111 qflag++; 112 break; 113 case 'P': 114 decode_int(optarg, &precision); 115 if (precision != 4 && precision != 8 && 116 precision != 16 && precision != 24 && 117 precision != 32) 118 errx(1, "precision must be between 4, 8, 16, 24 or 32"); 119 break; 120 case 'p': 121 len = strlen(optarg); 122 123 if (strncmp(optarg, "speaker", len) == 0) 124 port |= AUDIO_SPEAKER; 125 else if (strncmp(optarg, "headphone", len) == 0) 126 port |= AUDIO_HEADPHONE; 127 else if (strncmp(optarg, "line", len) == 0) 128 port |= AUDIO_LINE_OUT; 129 else 130 errx(1, 131 "port must be `speaker', `headphone', or `line'"); 132 break; 133 case 's': 134 decode_int(optarg, &sample_rate); 135 if (sample_rate < 0 || sample_rate > 48000 * 2) /* XXX */ 136 errx(1, "sample rate must be between 0 and 96000\n"); 137 break; 138 case 'V': 139 verbose++; 140 break; 141 case 'v': 142 volume = atoi(optarg); 143 if (volume < 0 || volume > 255) 144 errx(1, "volume must be between 0 and 255\n"); 145 break; 146 /* case 'h': */ 147 default: 148 usage(); 149 /* NOTREACHED */ 150 } 151 } 152 argc -= optind; 153 argv += optind; 154 155 if (encoding_str) { 156 encoding = audio_enc_to_val(encoding_str); 157 if (encoding == -1) 158 errx(1, "unknown encoding, bailing..."); 159 } 160 161 if (device == NULL && (device = getenv("AUDIODEVICE")) == NULL && 162 (device = getenv("AUDIODEV")) == NULL) /* Sun compatibility */ 163 device = _PATH_AUDIO; 164 if (ctldev == NULL && (ctldev = getenv("AUDIOCTLDEVICE")) == NULL) 165 ctldev = _PATH_AUDIOCTL; 166 167 audiofd = open(device, O_WRONLY); 168 #ifdef _PATH_OAUDIO 169 /* Allow the non-unit device to be used. */ 170 if (audiofd < 0 && device == _PATH_AUDIO) { 171 device = _PATH_OAUDIO; 172 ctldev = _PATH_OAUDIOCTL; 173 audiofd = open(device, O_WRONLY); 174 } 175 #endif 176 if (audiofd < 0) 177 err(1, "failed to open %s", device); 178 ctlfd = open(ctldev, O_RDWR); 179 if (ctlfd < 0) 180 err(1, "failed to open %s", ctldev); 181 182 if (ioctl(ctlfd, AUDIO_GETINFO, &info) < 0) 183 err(1, "failed to get audio info"); 184 bufsize = info.play.buffer_size; 185 if (bufsize < 32 * 1024) 186 bufsize = 32 * 1024; 187 188 if (*argv) 189 do 190 play(*argv++); 191 while (*argv); 192 else 193 play_fd("standard input", STDIN_FILENO); 194 195 exit(exitstatus); 196 } 197 198 void 199 play(file) 200 char *file; 201 { 202 struct stat sb; 203 void *addr, *oaddr; 204 off_t filesize; 205 size_t datasize; 206 ssize_t hdrlen; 207 int fd; 208 209 fd = open(file, O_RDONLY); 210 if (fd < 0) { 211 if (!qflag) 212 warn("could not open %s", file); 213 exitstatus = EXIT_FAILURE; 214 return; 215 } 216 217 if (fstat(fd, &sb) < 0) 218 err(1, "could not fstat %s", file); 219 filesize = sb.st_size; 220 221 oaddr = addr = mmap(0, (size_t)filesize, PROT_READ, 222 MAP_SHARED, fd, 0); 223 224 /* 225 * if we failed to mmap the file, try to read it 226 * instead, so that filesystems, etc, that do not 227 * support mmap() work 228 */ 229 if (addr == MAP_FAILED) { 230 play_fd(file, fd); 231 close(fd); 232 return; 233 } 234 235 /* 236 * give the VM system a bit of a hint about the type 237 * of accesses we will make. 238 */ 239 if (madvise(addr, filesize, MADV_SEQUENTIAL) < 0 && 240 !qflag) 241 warn("madvise failed, ignoring"); 242 243 /* 244 * get the header length and set up the audio device 245 */ 246 if ((hdrlen = audioctl_write_fromhdr(addr, 247 (size_t)filesize, ctlfd, &datasize)) < 0) { 248 if (play_errstring) 249 errx(1, "%s: %s", play_errstring, file); 250 else 251 errx(1, "unknown audio file: %s", file); 252 } 253 254 filesize -= hdrlen; 255 addr = (char *)addr + hdrlen; 256 if (filesize < datasize || datasize == 0) { 257 warn("bogus datasize: %lu", (long)datasize); 258 datasize = filesize; 259 } 260 261 while (datasize > bufsize) { 262 if (write(audiofd, addr, bufsize) != bufsize) 263 err(1, "write failed"); 264 addr = (char *)addr + bufsize; 265 datasize -= bufsize; 266 } 267 if (write(audiofd, addr, (size_t)datasize) != (ssize_t)datasize) 268 err(1, "final write failed"); 269 270 if (ioctl(audiofd, AUDIO_DRAIN) < 0 && !qflag) 271 warn("audio drain ioctl failed"); 272 if (munmap(oaddr, (size_t)filesize) < 0) 273 err(1, "munmap failed"); 274 275 close(fd); 276 } 277 278 /* 279 * play the file on on the file descriptor fd 280 */ 281 void 282 play_fd(file, fd) 283 const char *file; 284 int fd; 285 { 286 char *buffer = malloc(bufsize); 287 ssize_t hdrlen; 288 int nr, nw; 289 size_t datasize = 0; 290 size_t dataout = 0; 291 292 if (buffer == NULL) 293 err(1, "malloc of read buffer failed"); 294 nr = read(fd, buffer, bufsize); 295 if (nr < 0) 296 goto read_error; 297 if (nr == 0) { 298 if (fflag) 299 return; 300 else errx(1, "unexpected EOF"); 301 } 302 hdrlen = audioctl_write_fromhdr(buffer, nr, ctlfd, &datasize); 303 if (hdrlen < 0) { 304 if (play_errstring) 305 errx(1, "%s: %s", play_errstring, file); 306 else 307 errx(1, "unknown audio file: %s", file); 308 } 309 if (hdrlen > 0) { 310 if (hdrlen >= nr) /* shouldn't happen */ 311 errx(1, "header seems really large"); 312 memmove(buffer, buffer + hdrlen, nr - hdrlen); 313 nr -= hdrlen; 314 } 315 while(datasize == 0 || dataout < datasize) { 316 if (datasize != 0 && dataout + nr > datasize) 317 nr = datasize - dataout; 318 nw = write(audiofd, buffer, nr); 319 if (nw != nr) 320 goto write_error; 321 dataout += nw; 322 nr = read(fd, buffer, bufsize); 323 if (nr == -1) 324 goto read_error; 325 if (nr == 0) 326 break; 327 } 328 /* something to think about: no message given for dataout < datasize */ 329 if (ioctl(audiofd, AUDIO_DRAIN) < 0 && !qflag) 330 warn("audio drain ioctl failed"); 331 return; 332 read_error: 333 err(1, "read of standard input failed"); 334 write_error: 335 err(1, "audio device write failed"); 336 } 337 338 /* 339 * only support sun and wav audio files so far ... 340 * 341 * XXX this should probably be mostly part of libaudio, but it 342 * uses the local "info" variable. blah... fix me! 343 */ 344 ssize_t 345 audioctl_write_fromhdr(hdr, fsz, fd, datasize) 346 void *hdr; 347 size_t fsz; 348 int fd; 349 size_t *datasize; 350 { 351 sun_audioheader *sunhdr; 352 ssize_t hdr_len; 353 354 AUDIO_INITINFO(&info); 355 sunhdr = hdr; 356 if (ntohl(sunhdr->magic) == AUDIO_FILE_MAGIC) { 357 if (audio_sun_to_encoding(ntohl(sunhdr->encoding), 358 &info.play.encoding, &info.play.precision)) { 359 if (!qflag) 360 warnx("unknown unsupported Sun audio encoding" 361 " format %d", ntohl(sunhdr->encoding)); 362 if (fflag) 363 goto set_audio_mode; 364 return (-1); 365 } 366 367 info.play.sample_rate = ntohl(sunhdr->sample_rate); 368 info.play.channels = ntohl(sunhdr->channels); 369 hdr_len = ntohl(sunhdr->hdr_size); 370 371 *datasize = ntohl(sunhdr->data_size); 372 goto set_audio_mode; 373 } 374 375 hdr_len = audio_parse_wav_hdr(hdr, fsz, &info.play.encoding, 376 &info.play.precision, &info.play.sample_rate, &info.play.channels, datasize); 377 378 switch (hdr_len) { 379 case AUDIO_ESHORTHDR: 380 case AUDIO_EWAVUNSUPP: 381 case AUDIO_EWAVBADPCM: 382 case AUDIO_EWAVNODATA: 383 play_errstring = audio_errstring(hdr_len); 384 /* FALL THROUGH */ 385 case AUDIO_ENOENT: 386 break; 387 default: 388 if (hdr_len < 1) 389 break; 390 goto set_audio_mode; 391 } 392 /* 393 * if we don't know it, bail unless we are forcing. 394 */ 395 if (fflag == 0) 396 return (-1); 397 set_audio_mode: 398 if (port) 399 info.play.port = port; 400 if (volume) 401 info.play.gain = volume; 402 if (balance) 403 info.play.balance = balance; 404 if (fflag) { 405 if (sample_rate) 406 info.play.sample_rate = sample_rate; 407 if (channels) 408 info.play.channels = channels; 409 if (encoding) 410 info.play.encoding = encoding; 411 if (precision) 412 info.play.precision = precision; 413 hdr_len = 0; 414 } 415 info.mode = AUMODE_PLAY_ALL; 416 417 if (ioctl(fd, AUDIO_SETINFO, &info) < 0) 418 err(1, "failed to set audio info"); 419 420 return (hdr_len); 421 } 422 423 void 424 usage() 425 { 426 427 fprintf(stderr, "Usage: %s [-hiqV] [options] files\n", getprogname()); 428 fprintf(stderr, "Options:\n\t" 429 "-C audio control device\n\t" 430 "-b balance (0-63)\n\t" 431 "-d audio device\n\t" 432 "-f force settings\n\t" 433 "\t-c forced channels\n\t" 434 "\t-e forced encoding\n\t" 435 "\t-P forced precision\n\t" 436 "\t-s forced sample rate\n\t" 437 "-i header information\n\t" 438 "-m monitor volume\n\t" 439 "-p output port\n\t" 440 "-v volume\n"); 441 exit(EXIT_FAILURE); 442 } 443