1 /* $NetBSD: cdplay.c,v 1.51 2021/11/27 22:16:41 rillig Exp $ */ 2 3 /* 4 * Copyright (c) 1999, 2000, 2001 Andrew Doran. 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 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 * 28 */ 29 30 /* 31 * Compact Disc Control Utility, originally by Serge V. Vakulenko 32 * <vak (at) cronyx.ru>. First appeared in FreeBSD under the guise of 33 * cdcontrol(1). Based on the non-X based CD player by Jean-Marc 34 * Zucconi and Andrey A. Chernov. Fixed and further modified on 35 * by Jukka Ukkonen <jau (at) funet.fi>. Lots of fixes and improvements 36 * made subsequently by The NetBSD Project. 37 * 38 * from FreeBSD: cdcontrol.c,v 1.17.2.1 1999/01/31 15:36:01 billf Exp 39 */ 40 41 #include <sys/cdefs.h> 42 #ifndef lint 43 __RCSID("$NetBSD: cdplay.c,v 1.51 2021/11/27 22:16:41 rillig Exp $"); 44 #endif /* not lint */ 45 46 #include <sys/types.h> 47 48 #include <sys/endian.h> 49 #include <sys/ioctl.h> 50 #include <sys/file.h> 51 #include <sys/cdio.h> 52 #include <sys/time.h> 53 #include <sys/audioio.h> 54 #include <sys/scsiio.h> 55 56 #include <assert.h> 57 58 #include <ctype.h> 59 #include <err.h> 60 #include <errno.h> 61 #include <histedit.h> 62 #include <limits.h> 63 #include <sched.h> 64 #include <signal.h> 65 #include <stdio.h> 66 #include <stdlib.h> 67 #include <string.h> 68 #include <unistd.h> 69 #include <util.h> 70 71 enum cmd { 72 CMD_ANALOG, 73 CMD_CLOSE, 74 CMD_DIGITAL, 75 CMD_EJECT, 76 CMD_HELP, 77 CMD_INFO, 78 CMD_NEXT, 79 CMD_PAUSE, 80 CMD_PLAY, 81 CMD_PREV, 82 CMD_QUIT, 83 CMD_RESET, 84 CMD_RESUME, 85 CMD_SET, 86 CMD_SHUFFLE, 87 CMD_SINGLE, 88 CMD_SKIP, 89 CMD_STATUS, 90 CMD_STOP, 91 CMD_VOLUME, 92 }; 93 94 static struct cmdtab { 95 enum cmd command; 96 const char *name; 97 u_int min; 98 const char *args; 99 } const cmdtab[] = { 100 { CMD_ANALOG, "analog", 1, NULL }, 101 { CMD_CLOSE, "close", 1, NULL }, 102 { CMD_DIGITAL, "digital", 1, "fpw" }, 103 { CMD_EJECT, "eject", 1, NULL }, 104 { CMD_HELP, "?", 1, 0 }, 105 { CMD_HELP, "help", 1, NULL }, 106 { CMD_INFO, "info", 1, NULL }, 107 { CMD_NEXT, "next", 1, NULL }, 108 { CMD_PAUSE, "pause", 2, NULL }, 109 { CMD_PLAY, "play", 1, "[#block [len]]" }, 110 { CMD_PLAY, "play", 1, "min1:sec1[.fram1] [min2:sec2[.fram2]]" }, 111 { CMD_PLAY, "play", 1, "tr1 m1:s1[.f1] [[tr2] [m2:s2[.f2]]]" }, 112 { CMD_PLAY, "play", 1, "track1[.index1] [track2[.index2]]" }, 113 { CMD_PREV, "prev", 2, NULL }, 114 { CMD_QUIT, "quit", 1, NULL }, 115 { CMD_RESET, "reset", 4, NULL }, 116 { CMD_RESUME, "resume", 4, NULL }, 117 { CMD_SET, "set", 2, "msf | lba" }, 118 { CMD_SHUFFLE, "shuffle", 2, NULL }, 119 { CMD_SINGLE, "single", 2, "[<track>]" }, 120 { CMD_SKIP, "skip", 2, NULL }, 121 { CMD_STATUS, "status", 3, NULL }, 122 { CMD_STOP, "stop", 3, NULL }, 123 { CMD_VOLUME, "volume", 1, "<l> <r>|left|right|mute|mono|stereo" }, 124 }; 125 126 #define IOCTL_SIMPLE(fd, ctl) \ 127 do { \ 128 if (ioctl((fd), (ctl)) >= 0) { \ 129 close(fd); \ 130 fd = -1; \ 131 } else \ 132 warn("ioctl(" #ctl ")");\ 133 } while (0) 134 135 #define CDDA_SIZE 2352 136 137 #define CD_MAX_TRACK 99 /* largest 2 digit BCD number */ 138 139 static struct cd_toc_entry toc_buffer[CD_MAX_TRACK + 1]; 140 141 static const char *cdname; 142 static int fd = -1; 143 static int msf = 1; 144 static int shuffle; 145 static int interactive = 1; 146 static int digital = 0; 147 static int tbvalid = 0; 148 static struct itimerval itv_timer; 149 150 static struct { 151 const char *auname; 152 u_char *audata, *aubuf; 153 int afd; 154 int fpw; 155 int lba_start, lba_end, lba_current; 156 int lowat, hiwat, readseek, playseek; 157 int playing, changed; 158 int read_errors; 159 } da; 160 161 static History *hist; 162 static HistEvent he; 163 static EditLine *elptr; 164 165 static int get_status(int *, int *, int *, int *, int *); 166 static void help(void); 167 static int info(void); 168 static void lba2msf(u_long, u_int *, u_int *, u_int *); 169 static u_int msf2lba(u_int, u_int, u_int); 170 static int opencd(void); 171 static int openaudio(void); 172 static const char *parse(char *, int *); 173 static int play(const char *, int); 174 static int play_blocks(int, int); 175 static int play_digital(u_int, u_int); 176 static int play_msf(u_int, u_int, u_int, u_int, u_int, u_int); 177 static int play_track(int, int, int, int); 178 static int print_status(void); 179 static void print_track(struct cd_toc_entry *); 180 static const char *prompt(void); 181 static int readaudio(int, int, int, u_char *); 182 static int read_toc_entries(size_t); 183 static int run(int, const char *); 184 static int start_analog(void); 185 static int start_digital(const char *); 186 static int setvol(int, int); 187 static void sig_timer(int); 188 static int skip(int, int); 189 static const char *strstatus(int); 190 __dead static void usage(void); 191 192 static void toc2msf(u_int, u_int *, u_int *, u_int *); 193 static int toc2lba(u_int); 194 static void addmsf(u_int *, u_int *, u_int *, u_int, u_int, u_int); 195 196 int 197 main(int argc, char **argv) 198 { 199 const char *arg; 200 char buf[80], *p; 201 static char defdev[16]; 202 int cmd, c; 203 size_t len; 204 char *line; 205 const char *elline; 206 int scratch; 207 struct sigaction sa_timer; 208 const char *use_digital = NULL; /* historical default */ 209 210 cdname = getenv("MUSIC_CD"); 211 if (cdname == NULL) 212 cdname = getenv("CD_DRIVE"); 213 if (cdname == NULL) 214 cdname = getenv("DISC"); 215 if (cdname == NULL) 216 cdname = getenv("CDPLAY"); 217 218 da.auname = getenv("AUDIODEV"); 219 if (!da.auname) 220 da.auname = getenv("SPEAKER"); 221 if (!da.auname) 222 da.auname = "/dev/sound"; 223 224 use_digital = getenv("CDPLAY_DIGITAL"); 225 226 while ((c = getopt(argc, argv, "a:f:h")) != -1) 227 switch (c) { 228 case 'a': 229 da.auname = optarg; 230 if (!use_digital) 231 use_digital = ""; 232 continue; 233 case 'f': 234 cdname = optarg; 235 continue; 236 case 'h': 237 default: 238 usage(); 239 /* NOTREACHED */ 240 } 241 argc -= optind; 242 argv += optind; 243 244 if (argc > 0 && strcasecmp(*argv, "help") == 0) 245 usage(); 246 247 if (cdname == NULL) { 248 snprintf(defdev, sizeof(defdev), "cd0%c", 249 'a' + getrawpartition()); 250 cdname = defdev; 251 } 252 253 opencd(); 254 da.afd = -1; 255 256 sigemptyset(&sa_timer.sa_mask); 257 sa_timer.sa_handler = sig_timer; 258 sa_timer.sa_flags = SA_RESTART; 259 if (sigaction(SIGALRM, &sa_timer, NULL) < 0) 260 err(EXIT_FAILURE, "sigaction()"); 261 262 if (use_digital) 263 start_digital(use_digital); 264 265 if (argc > 0) { 266 interactive = 0; 267 for (p = buf; argc-- > 0; argv++) { 268 len = strlen(*argv); 269 270 if (p + len >= buf + sizeof(buf) - 1) 271 usage(); 272 if (p > buf) 273 *p++ = ' '; 274 275 strlcpy(p, *argv, sizeof(buf) - (p - buf)); 276 p += len; 277 } 278 *p = '\0'; 279 arg = parse(buf, &cmd); 280 return run(cmd, arg); 281 } 282 283 setbuf(stdout, NULL); 284 printf("Type `?' for command list\n\n"); 285 286 hist = history_init(); 287 history(hist, &he, H_SETSIZE, 100); /* 100 elt history buffer */ 288 elptr = el_init(getprogname(), stdin, stdout, stderr); 289 el_set(elptr, EL_EDITOR, "emacs"); 290 el_set(elptr, EL_PROMPT, prompt); 291 el_set(elptr, EL_HIST, history, hist); 292 el_set(elptr, EL_SIGNAL, 1); 293 el_source(elptr, NULL); 294 295 for (;;) { 296 line = NULL; 297 arg = NULL; 298 do { 299 if (((elline = el_gets(elptr, &scratch)) != NULL) 300 && (scratch != 0)){ 301 history(hist, &he, H_ENTER, elline); 302 line = strdup(elline); 303 if (line != NULL) { 304 arg = parse(line, &cmd); 305 free(line); 306 } 307 } else { 308 cmd = CMD_QUIT; 309 fprintf(stderr, "\r\n"); 310 arg = NULL; 311 break; 312 } 313 } while (arg == NULL); 314 315 if (run(cmd, arg) < 0) { 316 if (fd != -1) 317 close(fd); 318 fd = -1; 319 } 320 } 321 /*NOTREACHED*/ 322 el_end(elptr); 323 history_end(hist); 324 exit(EXIT_SUCCESS); 325 } 326 327 static void 328 usage(void) 329 { 330 331 fprintf(stderr, "Usage: %s [-a audio_device] [-f cd_device] [command ...]\n", getprogname()); 332 exit(EXIT_FAILURE); 333 /* NOTREACHED */ 334 } 335 336 static void 337 help(void) 338 { 339 const struct cmdtab *c, *mc; 340 const char *s; 341 int i, n; 342 343 mc = cmdtab + sizeof(cmdtab) / sizeof(cmdtab[0]); 344 for (c = cmdtab; c < mc; c++) { 345 for (i = c->min, s = c->name; *s != '\0'; s++, i--) { 346 n = (i > 0 ? toupper((unsigned char)*s) : *s); 347 putchar(n); 348 } 349 if (c->args != NULL) 350 printf(" %s", c->args); 351 putchar('\n'); 352 } 353 printf( 354 "\nThe word \"play\" is not required for the play commands.\n" 355 "The plain target address is taken as a synonym for play.\n"); 356 } 357 358 static int 359 start_digital(const char *arg) 360 { 361 362 int fpw, intv_usecs, hz_usecs, rv; 363 364 fpw = atoi(arg); 365 if (fpw > 0) 366 da.fpw = fpw; 367 else 368 da.fpw = 5; 369 da.read_errors = 0; 370 371 /* real rate: 75 frames per second */ 372 intv_usecs = 13333 * da.fpw; 373 /* 374 * interrupt earlier for safety, by a value which 375 * doesn't hurt interactive response if we block 376 * in the signal handler 377 */ 378 intv_usecs -= 50000; 379 hz_usecs = (int)(1000000 / sysconf(_SC_CLK_TCK)); 380 if (intv_usecs < hz_usecs) { 381 /* can't have a shorter interval, increase 382 buffer size to compensate */ 383 da.fpw += (hz_usecs - intv_usecs) / 13333; 384 intv_usecs = hz_usecs; 385 } 386 387 da.aubuf = malloc(da.fpw * CDDA_SIZE); 388 if (da.aubuf == NULL) { 389 warn("Not enough memory for audio buffers"); 390 return 1; 391 } 392 if (da.afd == -1 && !openaudio()) { 393 warn("Cannot open audio device"); 394 return 1; 395 } 396 itv_timer.it_interval.tv_sec = itv_timer.it_value.tv_sec = 397 intv_usecs / 1000000; 398 itv_timer.it_interval.tv_usec = itv_timer.it_value.tv_usec = 399 intv_usecs % 1000000; 400 rv = setitimer(ITIMER_REAL, &itv_timer, NULL); 401 if (rv == 0) 402 digital = 1; 403 else 404 warn("setitimer in CMD_DIGITAL"); 405 msf = 0; 406 tbvalid = 0; 407 return rv; 408 } 409 410 static int 411 start_analog(void) 412 { 413 int rv; 414 if (shuffle == 1) 415 itv_timer.it_interval.tv_sec = itv_timer.it_value.tv_sec = 1; 416 else 417 itv_timer.it_interval.tv_sec = itv_timer.it_value.tv_sec = 0; 418 itv_timer.it_interval.tv_usec = itv_timer.it_value.tv_usec = 0; 419 digital = 0; 420 rv = setitimer(ITIMER_REAL, &itv_timer, NULL); 421 free(da.audata); 422 close(da.afd); 423 da.afd = -1; 424 return rv; 425 } 426 427 static int 428 run(int cmd, const char *arg) 429 { 430 int l, r, rv; 431 432 rv = 0; 433 if (cmd == CMD_QUIT) { 434 close(fd); 435 exit(EXIT_SUCCESS); 436 /* NOTREACHED */ 437 } 438 439 if (fd < 0 && !opencd()) 440 return 0; 441 442 switch (cmd) { 443 case CMD_INFO: 444 rv = info(); 445 break; 446 447 case CMD_STATUS: 448 rv = print_status(); 449 break; 450 451 case CMD_PAUSE: 452 if (digital) { 453 da.playing = 0; 454 return 0; 455 } else if ((rv = ioctl(fd, CDIOCPAUSE)) < 0) 456 warn("ioctl(CDIOCPAUSE)"); 457 break; 458 459 case CMD_RESUME: 460 if (digital) { 461 da.playing = 1; 462 return 0; 463 } else if ((rv = ioctl(fd, CDIOCRESUME)) < 0) 464 warn("ioctl(CDIOCRESUME)"); 465 break; 466 467 case CMD_STOP: 468 if (digital) { 469 da.playing = 0; 470 return 0; 471 } else { 472 if ((rv = ioctl(fd, CDIOCSTOP)) < 0) 473 warn("ioctl(CDIOCSTOP)"); 474 if (ioctl(fd, CDIOCALLOW) < 0) 475 warn("ioctl(CDIOCALLOW)"); 476 } 477 break; 478 479 case CMD_RESET: 480 tbvalid = 0; 481 IOCTL_SIMPLE(fd, CDIOCRESET); 482 return 0; 483 484 case CMD_EJECT: 485 tbvalid = 0; 486 if (digital) 487 da.playing = 0; 488 if (shuffle) 489 rv = run(CMD_SHUFFLE, NULL); 490 if (ioctl(fd, CDIOCALLOW) < 0) 491 warn("ioctl(CDIOCALLOW)"); 492 IOCTL_SIMPLE(fd, CDIOCEJECT); 493 break; 494 495 case CMD_CLOSE: 496 if (ioctl(fd, CDIOCALLOW) < 0) 497 warn("ioctl(CDIOCALLOW)"); 498 IOCTL_SIMPLE(fd, CDIOCCLOSE); 499 if (interactive && fd == -1) 500 opencd(); 501 break; 502 503 case CMD_PLAY: 504 while (isspace((unsigned char)*arg)) 505 arg++; 506 rv = play(arg, 1); 507 break; 508 509 case CMD_PREV: 510 rv = skip(-1, 1); 511 break; 512 513 case CMD_NEXT: 514 rv = skip(1, 1); 515 break; 516 517 case CMD_SINGLE: 518 if (interactive == 0) 519 errx(EXIT_FAILURE, 520 "'single' valid only in interactive mode"); 521 /*FALLTHROUGH*/ 522 case CMD_SHUFFLE: 523 if (interactive == 0) 524 errx(EXIT_FAILURE, 525 "`shuffle' valid only in interactive mode"); 526 if (shuffle == 0) { 527 if (digital == 0) { 528 itv_timer.it_interval.tv_sec = 1; 529 itv_timer.it_interval.tv_usec = 0; 530 itv_timer.it_value.tv_sec = 1; 531 itv_timer.it_value.tv_usec = 0; 532 if (setitimer(ITIMER_REAL, &itv_timer, NULL) == 0) { 533 if (cmd == CMD_SHUFFLE) { 534 shuffle = 1; 535 } else { 536 while (isspace((unsigned char)*arg)) 537 arg++; 538 shuffle = -atoi(arg); 539 } 540 } 541 } else 542 shuffle = cmd == CMD_SINGLE ? -atoi(arg) : 1; 543 /* 544 if (shuffle) 545 rv = skip(0, 1); 546 */ 547 } else { 548 if (digital == 0) { 549 itv_timer.it_interval.tv_sec = 0; 550 itv_timer.it_interval.tv_usec = 0; 551 itv_timer.it_value.tv_sec = 0; 552 itv_timer.it_value.tv_usec = 0; 553 setitimer(ITIMER_REAL, &itv_timer, NULL); 554 } 555 shuffle = 0; 556 } 557 if (shuffle < 0) 558 printf("single track:\t%d\n", -shuffle); 559 else 560 printf("shuffle play:\t%s\n", (shuffle != 0) ? "on" : "off"); 561 rv = 0; 562 break; 563 564 case CMD_DIGITAL: 565 if (digital == 0) 566 rv = start_digital(arg); 567 else { 568 warnx("Already in digital mode"); 569 rv = 1; 570 } 571 break; 572 573 case CMD_ANALOG: 574 if (digital == 1) 575 rv = start_analog(); 576 else { 577 warnx("Already in analog mode"); 578 rv = 1; 579 } 580 break; 581 582 case CMD_SKIP: 583 if (!interactive) 584 errx(EXIT_FAILURE, 585 "`skip' valid only in interactive mode"); 586 if (!shuffle) 587 warnx("`skip' valid only in shuffle mode"); 588 else 589 rv = skip(0, 1); 590 break; 591 592 case CMD_SET: 593 tbvalid = 0; 594 if (strcasecmp(arg, "msf") == 0) 595 msf = 1; 596 else if (strcasecmp(arg, "lba") == 0) 597 msf = 0; 598 else 599 warnx("invalid command arguments"); 600 break; 601 602 case CMD_VOLUME: 603 if (digital) { 604 rv = 0; 605 warnx("`volume' is ignored while in digital xfer mode"); 606 } else if (strncasecmp(arg, "left", strlen(arg)) == 0) 607 rv = ioctl(fd, CDIOCSETLEFT); 608 else if (strncasecmp(arg, "right", strlen(arg)) == 0) 609 rv = ioctl(fd, CDIOCSETRIGHT); 610 else if (strncasecmp(arg, "mono", strlen(arg)) == 0) 611 rv = ioctl(fd, CDIOCSETMONO); 612 else if (strncasecmp(arg, "stereo", strlen(arg)) == 0) 613 rv = ioctl(fd, CDIOCSETSTEREO); 614 else if (strncasecmp(arg, "mute", strlen(arg)) == 0) 615 rv = ioctl(fd, CDIOCSETMUTE); 616 else { 617 rv = 0; 618 if (sscanf(arg, "%d %d", &l, &r) != 2) { 619 if (sscanf(arg, "%d", &l) == 1) 620 r = l; 621 else { 622 warnx("invalid command arguments"); 623 break; 624 } 625 } 626 rv = setvol(l, r); 627 } 628 break; 629 630 case CMD_HELP: 631 default: 632 help(); 633 rv = 0; 634 break; 635 } 636 637 return rv; 638 } 639 640 static int 641 play(const char *arg, int fromuser) 642 { 643 int start, end, istart, iend, blk, len, relend; 644 ssize_t rv; 645 u_int n, tr1, tr2, m1, m2, s1, s2, f1, f2, tm, ts, tf; 646 struct ioc_toc_header h; 647 648 if (shuffle && fromuser) { 649 warnx("`play' not valid in shuffle mode"); 650 return 0; 651 } 652 653 if ((rv = ioctl(fd, CDIOREADTOCHEADER, &h)) < 0) { 654 warn("ioctl(CDIOREADTOCHEADER)"); 655 return (int)rv; 656 } 657 658 end = 0; 659 istart = iend = 1; 660 n = h.ending_track - h.starting_track + 1; 661 rv = read_toc_entries((n + 1) * sizeof(struct cd_toc_entry)); 662 if (rv < 0) 663 return (int)rv; 664 665 if (arg == NULL || *arg == '\0') { 666 /* Play the whole disc */ 667 return play_track(h.starting_track, 1, h.ending_track, 99); 668 } 669 670 if (strchr(arg, '#') != NULL) { 671 /* Play block #blk [ len ] */ 672 len = 0; 673 674 if (2 != sscanf(arg, "#%d%d", &blk, &len) && 675 1 != sscanf(arg, "#%d", &blk)) 676 goto Clean_up; 677 678 if (len == 0) { 679 len = toc2lba(n); 680 } 681 return play_blocks(blk, len); 682 } 683 684 if (strchr(arg, ':') != NULL) { 685 /* 686 * Play MSF m1:s1 [ .f1 ] [ m2:s2 [ .f2 ] ] 687 * 688 * Will now also understand timed addresses relative 689 * to the beginning of a track in the form... 690 * 691 * tr1 m1:s1[.f1] [[tr2] [m2:s2[.f2]]] 692 */ 693 relend = 1; 694 tr2 = m2 = s2 = f2 = f1 = 0; 695 if (8 == sscanf(arg, "%u %u:%u.%u %u %u:%u.%u", &tr1, &m1, 696 &s1, &f1, &tr2, &m2, &s2, &f2)) 697 goto Play_Relative_Addresses; 698 699 tr2 = m2 = s2 = f2 = f1 = 0; 700 if (7 == sscanf(arg, "%u %u:%u %u %u:%u.%u", &tr1, &m1, &s1, 701 &tr2, &m2, &s2, &f2)) 702 goto Play_Relative_Addresses; 703 704 tr2 = m2 = s2 = f2 = f1 = 0; 705 if (7 == sscanf(arg, "%u %u:%u.%u %u %u:%u", &tr1, &m1, &s1, 706 &f1, &tr2, &m2, &s2)) 707 goto Play_Relative_Addresses; 708 709 tr2 = m2 = s2 = f2 = f1 = 0; 710 if (7 == sscanf(arg, "%u %u:%u.%u %u:%u.%u", &tr1, &m1, &s1, 711 &f1, &m2, &s2, &f2)) 712 goto Play_Relative_Addresses; 713 714 tr2 = m2 = s2 = f2 = f1 = 0; 715 if (6 == sscanf(arg, "%u %u:%u.%u %u:%u", &tr1, &m1, &s1, &f1, 716 &m2, &s2)) 717 goto Play_Relative_Addresses; 718 719 tr2 = m2 = s2 = f2 = f1 = 0; 720 if (6 == sscanf(arg, "%u %u:%u %u:%u.%u", &tr1, &m1, &s1, &m2, 721 &s2, &f2)) 722 goto Play_Relative_Addresses; 723 724 tr2 = m2 = s2 = f2 = f1 = 0; 725 if (6 == sscanf(arg, "%u %u:%u.%u %u %u", &tr1, &m1, &s1, &f1, 726 &tr2, &m2)) 727 goto Play_Relative_Addresses; 728 729 tr2 = m2 = s2 = f2 = f1 = 0; 730 if (6 == sscanf(arg, "%u %u:%u %u %u:%u", &tr1, &m1, &s1, &tr2, 731 &m2, &s2)) 732 goto Play_Relative_Addresses; 733 734 tr2 = m2 = s2 = f2 = f1 = 0; 735 if (5 == sscanf(arg, "%u %u:%u %u:%u", &tr1, &m1, &s1, &m2, 736 &s2)) 737 goto Play_Relative_Addresses; 738 739 tr2 = m2 = s2 = f2 = f1 = 0; 740 if (5 == sscanf(arg, "%u %u:%u %u %u", &tr1, &m1, &s1, &tr2, 741 &m2)) 742 goto Play_Relative_Addresses; 743 744 relend=0; 745 tr2 = m2 = s2 = f2 = f1 = 0; 746 if (5 == sscanf(arg, "%u %u:%u.%u %u", &tr1, &m1, &s1, &f1, 747 &tr2)) 748 goto Play_Relative_Addresses; 749 750 tr2 = m2 = s2 = f2 = f1 = 0; 751 if (4 == sscanf(arg, "%u %u:%u %u", &tr1, &m1, &s1, &tr2)) 752 goto Play_Relative_Addresses; 753 754 tr2 = m2 = s2 = f2 = f1 = 0; 755 if (4 == sscanf(arg, "%u %u:%u.%u", &tr1, &m1, &s1, &f1)) 756 goto Play_Relative_Addresses; 757 758 tr2 = m2 = s2 = f2 = f1 = 0; 759 if (3 == sscanf(arg, "%u %u:%u", &tr1, &m1, &s1)) 760 goto Play_Relative_Addresses; 761 762 tr2 = m2 = s2 = f2 = f1 = 0; 763 goto Try_Absolute_Timed_Addresses; 764 765 Play_Relative_Addresses: 766 if (!tr1) 767 tr1 = 1; 768 else if (tr1 > n) 769 tr1 = n; 770 771 toc2msf(tr1-1, &tm, &ts, &tf); 772 addmsf(&m1, &s1, &f1, tm, ts, tf); 773 774 toc2msf(tr1, &tm, &ts, &tf); 775 776 if ((m1 > tm) || ((m1 == tm) && ((s1 > ts) || ((s1 == ts) && 777 (f1 > tf))))) { 778 warnx("Track %d is not that long.", tr1); 779 return 0; 780 } 781 tr1--; /* XXXXX ???? */ 782 783 784 if (!tr2) { 785 if (relend) { 786 tr2 = tr1; 787 788 addmsf(&m2, &s2, &f2, m1, s1, f1); 789 } else { 790 tr2 = n; 791 792 toc2msf(n, &m2, &s2, &f2); 793 } 794 } else { 795 if (tr2 > n) { 796 tr2 = n; 797 m2 = s2 = f2 = 0; 798 } else { 799 if (relend) 800 tr2--; 801 802 toc2msf(tr2, &tm, &ts, &tf); 803 addmsf(&m2, &s2, &f2, tm, ts, tf); 804 } 805 } 806 807 toc2msf(n, &tm, &ts, &tf); 808 809 if ((tr2 < n) && ((m2 > tm) || ((m2 == tm) && ((s2 > ts) || 810 ((s2 == ts) && (f2 > tf)))))) { 811 warnx("The playing time of the disc is not that long."); 812 return 0; 813 } 814 815 return play_msf(m1, s1, f1, m2, s2, f2); 816 817 Try_Absolute_Timed_Addresses: 818 m2 = UINT_MAX; 819 820 if (6 != sscanf(arg, "%d:%d.%d%d:%d.%d", 821 &m1, &s1, &f1, &m2, &s2, &f2) && 822 5 != sscanf(arg, "%d:%d.%d%d:%d", &m1, &s1, &f1, &m2, &s2) && 823 5 != sscanf(arg, "%d:%d%d:%d.%d", &m1, &s1, &m2, &s2, &f2) && 824 3 != sscanf(arg, "%d:%d.%d", &m1, &s1, &f1) && 825 4 != sscanf(arg, "%d:%d%d:%d", &m1, &s1, &m2, &s2) && 826 2 != sscanf(arg, "%d:%d", &m1, &s1)) 827 goto Clean_up; 828 829 if (m2 == UINT_MAX) { 830 if (msf) { 831 m2 = toc_buffer[n].addr.msf.minute; 832 s2 = toc_buffer[n].addr.msf.second; 833 f2 = toc_buffer[n].addr.msf.frame; 834 } else { 835 lba2msf(toc_buffer[n].addr.lba, &tm, &ts, &tf); 836 m2 = tm; 837 s2 = ts; 838 f2 = tf; 839 } 840 } 841 return play_msf(m1, s1, f1, m2, s2, f2); 842 } 843 844 /* 845 * Play track trk1 [ .idx1 ] [ trk2 [ .idx2 ] ] 846 */ 847 if (4 != sscanf(arg, "%d.%d%d.%d", &start, &istart, &end, &iend) && 848 3 != sscanf(arg, "%d.%d%d", &start, &istart, &end) && 849 3 != sscanf(arg, "%d%d.%d", &start, &end, &iend) && 850 2 != sscanf(arg, "%d.%d", &start, &istart) && 851 2 != sscanf(arg, "%d%d", &start, &end) && 852 1 != sscanf(arg, "%d", &start)) 853 goto Clean_up; 854 855 if (end == 0) 856 end = n; 857 return play_track(start, istart, end, iend); 858 859 Clean_up: 860 warnx("invalid command arguments"); 861 return 0; 862 } 863 864 static void 865 /*ARGSUSED*/ 866 sig_timer(int sig) 867 { 868 int aulen, fpw; 869 sigset_t anymore; 870 871 sigpending(&anymore); 872 if (sigismember(&anymore, SIGALRM)) 873 return; 874 if (digital) { 875 if (!da.playing) 876 return; 877 if (da.changed) { 878 da.lba_current = da.lba_start; 879 da.changed = 0; 880 } 881 /* read frames into circular buffer */ 882 fpw = da.lba_end - da.lba_current + 1; 883 if (fpw > da.fpw) 884 fpw = da.fpw; 885 if (fpw > 0) { 886 aulen = readaudio(fd, da.lba_current, fpw, da.aubuf); 887 if (aulen > 0) { 888 (void)write(da.afd, da.aubuf, aulen); 889 da.lba_current += fpw; 890 } 891 } 892 if (da.lba_current > da.lba_end) 893 da.playing = 0; 894 } 895 if (shuffle) 896 skip(0, 0); 897 #if 0 898 sched_yield(); 899 #endif 900 setitimer(ITIMER_REAL, &itv_timer, NULL); 901 } 902 903 static int 904 skip(int dir, int fromuser) 905 { 906 char str[16]; 907 int rv, trk, idx, m, s, f; 908 struct ioc_toc_header h; 909 910 if ((rv = ioctl(fd, CDIOREADTOCHEADER, &h)) < 0) { 911 warn("ioctl(CDIOREADTOCHEADER)"); 912 return rv; 913 } 914 if ((rv = get_status(&trk, &idx, &m, &s, &f)) < 0) 915 return rv; 916 917 if (dir == 0 || shuffle != 0) { 918 if (fromuser || (rv != CD_AS_PLAY_IN_PROGRESS && 919 rv != CD_AS_PLAY_PAUSED)) 920 trk = shuffle < 0 ? (-shuffle) : 921 (int)((h.starting_track + 922 arc4random() % (h.ending_track - h.starting_track + 1))); 923 else 924 return 0; 925 } else { 926 trk += dir; 927 if (trk > h.ending_track) 928 trk = h.starting_track; 929 else if(trk < h.starting_track) 930 trk = h.ending_track; 931 } 932 933 if (shuffle) 934 snprintf(str, sizeof(str), "%d %d", trk, trk); 935 else 936 snprintf(str, sizeof(str), "%d", trk); 937 938 return play(str, 0); 939 } 940 941 static const char * 942 strstatus(int sts) 943 { 944 const char *str; 945 946 switch (sts) { 947 case CD_AS_AUDIO_INVALID: 948 str = "invalid"; 949 break; 950 case CD_AS_PLAY_IN_PROGRESS: 951 str = "playing"; 952 break; 953 case CD_AS_PLAY_PAUSED: 954 str = "paused"; 955 break; 956 case CD_AS_PLAY_COMPLETED: 957 str = "completed"; 958 break; 959 case CD_AS_PLAY_ERROR: 960 str = "error"; 961 break; 962 case CD_AS_NO_STATUS: 963 str = "not playing"; 964 break; 965 default: 966 str = "<unknown>"; 967 break; 968 } 969 970 return str; 971 } 972 973 static int 974 print_status(void) 975 { 976 struct cd_sub_channel_info data; 977 struct ioc_read_subchannel ss; 978 int rv, trk, idx, m, s, f; 979 struct ioc_vol v; 980 981 if ((rv = get_status(&trk, &idx, &m, &s, &f)) >= 0) { 982 printf("audio status:\t%s\n", strstatus(rv)); 983 printf("current track:\t%d\n", trk); 984 if (!digital) 985 printf("current index:\t%d\n", idx); 986 printf("position:\t%d:%02d.%02d\n", m, s, f); 987 } else 988 printf("audio status:\tno info available\n"); 989 990 if (shuffle < 0) 991 printf("single track:\t%d\n", -shuffle); 992 else 993 printf("shuffle play:\t%s\n", (shuffle != 0) ? "on" : "off"); 994 if (digital) 995 printf("digital xfer:\tto %s " 996 "(%d frames per wakeup, %lld.%06lds period)\n", 997 da.auname, da.fpw, 998 (long long)itv_timer.it_interval.tv_sec, 999 1000 (long)itv_timer.it_interval.tv_usec); 1001 else 1002 printf("digital xfer:\toff\n"); 1003 1004 bzero(&ss, sizeof(ss)); 1005 ss.data = &data; 1006 ss.data_len = sizeof(data); 1007 ss.address_format = msf ? CD_MSF_FORMAT : CD_LBA_FORMAT; 1008 ss.data_format = CD_MEDIA_CATALOG; 1009 1010 if (!digital && ioctl(fd, CDIOCREADSUBCHANNEL, &ss) >= 0) { 1011 printf("media catalog:\t%sactive", 1012 ss.data->what.media_catalog.mc_valid ? "" : "in"); 1013 if (ss.data->what.media_catalog.mc_valid && 1014 ss.data->what.media_catalog.mc_number[0]) 1015 printf(" (%.15s)", 1016 ss.data->what.media_catalog.mc_number); 1017 putchar('\n'); 1018 } else 1019 printf("media catalog:\tnone\n"); 1020 1021 if (digital) 1022 return 0; 1023 if (ioctl(fd, CDIOCGETVOL, &v) >= 0) { 1024 printf("left volume:\t%d\n", v.vol[0]); 1025 printf("right volume:\t%d\n", v.vol[1]); 1026 } else { 1027 printf("left volume:\tnot available\n"); 1028 printf("right volume:\tnot available\n"); 1029 } 1030 1031 return 0; 1032 } 1033 1034 static int 1035 info(void) 1036 { 1037 struct ioc_toc_header h; 1038 int rc, i, n; 1039 1040 if ((rc = ioctl(fd, CDIOREADTOCHEADER, &h)) < 0) { 1041 warn("ioctl(CDIOREADTOCHEADER)"); 1042 return rc; 1043 } 1044 1045 n = h.ending_track - h.starting_track + 1; 1046 rc = read_toc_entries((n + 1) * sizeof(struct cd_toc_entry)); 1047 if (rc < 0) 1048 return rc; 1049 1050 printf("track start duration block length type\n"); 1051 printf("--------------------------------------------------\n"); 1052 1053 for (i = 0; i < n; i++) { 1054 printf("%5d ", toc_buffer[i].track); 1055 print_track(toc_buffer + i); 1056 } 1057 printf(" - "); /* Lead-out area */ 1058 print_track(toc_buffer + n); 1059 return 0; 1060 } 1061 1062 static void 1063 lba2msf(u_long lba, u_int *m, u_int *s, u_int *f) 1064 { 1065 1066 lba += 150; /* block start offset */ 1067 lba &= 0xffffff; /* negative lbas use only 24 bits */ 1068 *m = (u_int)(lba / (60 * 75)); 1069 lba %= (60 * 75); 1070 *s = (u_int)(lba / 75); 1071 *f = (u_int)(lba % 75); 1072 } 1073 1074 static u_int 1075 msf2lba(u_int m, u_int s, u_int f) 1076 { 1077 1078 return (((m * 60) + s) * 75 + f) - 150; 1079 } 1080 1081 static void 1082 print_track(struct cd_toc_entry *e) 1083 { 1084 int block, next, len; 1085 u_int m, s, f; 1086 1087 if (msf) { 1088 /* Print track start */ 1089 printf("%2d:%02d.%02d ", e->addr.msf.minute, 1090 e->addr.msf.second, e->addr.msf.frame); 1091 1092 block = msf2lba((u_int)e->addr.msf.minute, 1093 (u_int)e->addr.msf.second, (u_int)e->addr.msf.frame); 1094 } else { 1095 block = e->addr.lba; 1096 lba2msf(block, &m, &s, &f); 1097 /* Print track start */ 1098 printf("%2d:%02d.%02d ", m, s, f); 1099 } 1100 if (e->track > CD_MAX_TRACK) { 1101 /* lead-out area -- print block */ 1102 printf(" - %6d - lead-out\n", block); 1103 return; 1104 } 1105 if (msf) 1106 next = msf2lba((u_int)e[1].addr.msf.minute, 1107 (u_int)e[1].addr.msf.second, (u_int)e[1].addr.msf.frame); 1108 else 1109 next = e[1].addr.lba; 1110 len = next - block; 1111 /* XXX: take into account the 150 frame start offset time */ 1112 /* XXX: this is a mis-use of lba2msf() because 'len' is a */ 1113 /* XXX: length in frames and not a LBA! */ 1114 lba2msf(len - 150, &m, &s, &f); 1115 1116 /* Print duration, block, length, type */ 1117 printf("%2d:%02d.%02d %6d %6d %8s\n", m, s, f, block, len, 1118 (e->control & 4) ? "data" : "audio"); 1119 } 1120 1121 static int 1122 play_track(int tstart, int istart, int tend, int iend) 1123 { 1124 struct ioc_play_track t; 1125 int rv; 1126 1127 if (digital) { 1128 tstart--; 1129 if (msf) { 1130 return play_msf( 1131 (u_int)toc_buffer[tstart].addr.msf.minute, 1132 (u_int)toc_buffer[tstart].addr.msf.second, 1133 (u_int)toc_buffer[tstart].addr.msf.frame, 1134 (u_int)toc_buffer[tend].addr.msf.minute, 1135 (u_int)toc_buffer[tend].addr.msf.second, 1136 (u_int)toc_buffer[tend].addr.msf.frame); 1137 } else 1138 return play_digital(toc_buffer[tstart].addr.lba, 1139 toc_buffer[tend].addr.lba); 1140 } 1141 t.start_track = tstart; 1142 t.start_index = istart; 1143 t.end_track = tend; 1144 t.end_index = iend; 1145 1146 if ((rv = ioctl(fd, CDIOCPLAYTRACKS, &t)) < 0) { 1147 int oerrno = errno; 1148 if (errno == EINVAL && start_digital("") == 0) 1149 return play_track(tstart, istart, tend, iend); 1150 errno = oerrno; 1151 warn("ioctl(CDIOCPLAYTRACKS)"); 1152 } 1153 return rv; 1154 } 1155 1156 static int 1157 play_blocks(int blk, int len) 1158 { 1159 struct ioc_play_blocks t; 1160 int rv; 1161 1162 t.blk = blk; 1163 t.len = len; 1164 1165 if ((rv = ioctl(fd, CDIOCPLAYBLOCKS, &t)) < 0) 1166 warn("ioctl(CDIOCPLAYBLOCKS"); 1167 return rv; 1168 } 1169 1170 static int 1171 play_digital(u_int start, u_int end) 1172 { 1173 da.lba_start = start; 1174 da.lba_end = --end; 1175 da.changed = da.playing = 1; 1176 if (!interactive) 1177 while (da.playing) 1178 sleep(1); 1179 return 0; 1180 } 1181 1182 static int 1183 setvol(int left, int right) 1184 { 1185 struct ioc_vol v; 1186 int rv; 1187 1188 v.vol[0] = left; 1189 v.vol[1] = right; 1190 v.vol[2] = 0; 1191 v.vol[3] = 0; 1192 1193 if ((rv = ioctl(fd, CDIOCSETVOL, &v)) < 0) 1194 warn("ioctl(CDIOCSETVOL)"); 1195 return rv; 1196 } 1197 1198 static int 1199 read_toc_entries(size_t len) 1200 { 1201 struct ioc_read_toc_entry t; 1202 int rv; 1203 1204 t.address_format = msf ? CD_MSF_FORMAT : CD_LBA_FORMAT; 1205 t.starting_track = 0; 1206 t.data_len = (int)len; 1207 t.data = toc_buffer; 1208 1209 if ((rv = ioctl(fd, CDIOREADTOCENTRYS, &t)) < 0) 1210 warn("ioctl(CDIOREADTOCENTRYS)"); 1211 tbvalid = 1; 1212 return rv; 1213 } 1214 1215 static int 1216 play_msf(u_int start_m, u_int start_s, u_int start_f, u_int end_m, u_int end_s, 1217 u_int end_f) 1218 { 1219 struct ioc_play_msf a; 1220 int rv; 1221 1222 if (digital) 1223 return play_digital(msf2lba(start_m, start_s, start_f), 1224 msf2lba(end_m, end_s, end_f)); 1225 a.start_m = start_m; 1226 a.start_s = start_s; 1227 a.start_f = start_f; 1228 a.end_m = end_m; 1229 a.end_s = end_s; 1230 a.end_f = end_f; 1231 1232 if ((rv = ioctl(fd, CDIOCPLAYMSF, &a)) < 0) 1233 warn("ioctl(CDIOCPLAYMSF)"); 1234 return rv; 1235 } 1236 1237 static int 1238 get_status(int *trk, int *idx, int *min, int *sec, int *frame) 1239 { 1240 struct ioc_read_subchannel s; 1241 struct cd_sub_channel_info data; 1242 struct ioc_toc_header h; 1243 u_int mm, ss, ff; 1244 int rv; 1245 int i, n, rc; 1246 uint32_t lba; 1247 1248 if (!tbvalid) { 1249 if ((rc = ioctl(fd, CDIOREADTOCHEADER, &h)) < 0) { 1250 warn("ioctl(CDIOREADTOCHEADER)"); 1251 return rc; 1252 } 1253 1254 n = h.ending_track - h.starting_track + 1; 1255 rc = read_toc_entries((n + 1) * sizeof(struct cd_toc_entry)); 1256 if (rc < 0) 1257 return rc; 1258 } 1259 1260 #define SWAPLBA(x) (msf?be32toh(x):(x)) 1261 if (digital && da.playing) { 1262 lba = da.lba_current + 150; 1263 for (i = 1; i < 99; i++) { 1264 if (lba < SWAPLBA(toc_buffer[i].addr.lba)) { 1265 lba -= SWAPLBA(toc_buffer[i - 1].addr.lba); 1266 *trk = i; 1267 break; 1268 } 1269 } 1270 lba2msf(lba - 150, &mm, &ss, &ff); 1271 *min = mm; 1272 *sec = ss; 1273 *frame = ff; 1274 *idx = 0; 1275 return CD_AS_PLAY_IN_PROGRESS; 1276 } 1277 bzero(&s, sizeof(s)); 1278 s.data = &data; 1279 s.data_len = sizeof(data); 1280 s.address_format = msf ? CD_MSF_FORMAT : CD_LBA_FORMAT; 1281 s.data_format = CD_CURRENT_POSITION; 1282 1283 if ((rv = ioctl(fd, CDIOCREADSUBCHANNEL, &s)) < 0) { 1284 warn("ioctl(CDIOCREADSUBCHANNEL)"); 1285 return rv; 1286 } 1287 1288 *trk = s.data->what.position.track_number; 1289 *idx = s.data->what.position.index_number; 1290 if (msf) { 1291 *min = s.data->what.position.reladdr.msf.minute; 1292 *sec = s.data->what.position.reladdr.msf.second; 1293 *frame = s.data->what.position.reladdr.msf.frame; 1294 } else { 1295 lba2msf(s.data->what.position.reladdr.lba, &mm, 1296 &ss, &ff); 1297 *min = mm; 1298 *sec = ss; 1299 *frame = ff; 1300 } 1301 1302 return s.data->header.audio_status; 1303 } 1304 1305 static const char * 1306 prompt(void) 1307 { 1308 1309 return "cdplay> "; 1310 } 1311 1312 static const char * 1313 parse(char *buf, int *cmd) 1314 { 1315 const struct cmdtab *c, *mc; 1316 char *p, *q; 1317 size_t len; 1318 1319 for (p = buf; isspace((unsigned char)*p); p++) 1320 continue; 1321 1322 if (isdigit((unsigned char)*p) || (p[0] == '#' && isdigit((unsigned char)p[1]))) { 1323 *cmd = CMD_PLAY; 1324 return p; 1325 } 1326 1327 for (buf = p; *p != '\0' && !isspace((unsigned char)*p); p++) 1328 continue; 1329 1330 if ((len = p - buf) == 0) 1331 return NULL; 1332 1333 if (*p != '\0') { /* It must be a spacing character! */ 1334 *p++ = 0; 1335 for (q = p; *q != '\0' && *q != '\n' && *q != '\r'; q++) 1336 continue; 1337 *q = 0; 1338 } 1339 1340 *cmd = -1; 1341 1342 mc = cmdtab + sizeof(cmdtab) / sizeof(cmdtab[0]); 1343 for (c = cmdtab; c < mc; c++) { 1344 /* Is it an exact match? */ 1345 if (strcasecmp(buf, c->name) == 0) { 1346 *cmd = c->command; 1347 break; 1348 } 1349 /* Try short hand forms then... */ 1350 if (len >= c->min && strncasecmp(buf, c->name, len) == 0) { 1351 if (*cmd != -1 && *cmd != (int)c->command) { 1352 warnx("ambiguous command"); 1353 return NULL; 1354 } 1355 *cmd = c->command; 1356 } 1357 } 1358 1359 if (*cmd == -1) { 1360 warnx("invalid command, enter ``help'' for commands"); 1361 return NULL; 1362 } 1363 1364 while (isspace((unsigned char)*p)) 1365 p++; 1366 return p; 1367 } 1368 1369 static int 1370 opencd(void) 1371 { 1372 char devbuf[80]; 1373 1374 if (fd > -1) 1375 return 1; 1376 1377 fd = opendisk(cdname, O_RDONLY, devbuf, sizeof(devbuf), 0); 1378 if (fd < 0) { 1379 if (errno == ENXIO) { 1380 /* 1381 * ENXIO has an overloaded meaning here. The 1382 * original "Device not configured" should be 1383 * interpreted as "No disc in drive %s". 1384 */ 1385 warnx("no disc in drive %s", devbuf); 1386 return 0; 1387 } 1388 err(EXIT_FAILURE, "%s", devbuf); 1389 } 1390 return 1; 1391 } 1392 1393 static int 1394 openaudio(void) 1395 { 1396 audio_info_t ai; 1397 audio_encoding_t ae; 1398 int rc, aei; 1399 1400 if (da.afd > -1) 1401 return 1; 1402 da.afd = open(da.auname, O_WRONLY); 1403 if (da.afd < 0) { 1404 warn("openaudio"); 1405 return 0; 1406 } 1407 AUDIO_INITINFO(&ai); 1408 ae.index = 0; 1409 aei = -1; 1410 rc = ioctl(da.afd, AUDIO_GETENC, &ae); 1411 do { 1412 if (ae.encoding == AUDIO_ENCODING_SLINEAR_LE && ae.precision == 16) 1413 aei = ae.index; 1414 ae.index++; 1415 rc = ioctl(da.afd, AUDIO_GETENC, &ae); 1416 } while (rc == 0); 1417 if (aei == -1) { 1418 warn("No suitable audio encoding found!"); 1419 close(da.afd); 1420 da.afd = -1; 1421 return 0; 1422 } 1423 ai.mode = AUMODE_PLAY_ALL; 1424 ai.play.sample_rate = 44100; 1425 ai.play.channels = 2; 1426 ai.play.precision = 16; 1427 ai.play.encoding = AUDIO_ENCODING_SLINEAR_LE; 1428 ai.blocksize = 0; 1429 rc = ioctl(da.afd, AUDIO_SETINFO, &ai); 1430 if (rc < 0) { 1431 warn("AUDIO_SETINFO"); 1432 close(da.afd); 1433 da.afd = -1; 1434 return 0; 1435 } 1436 return 1; 1437 } 1438 1439 static int 1440 readaudio(int afd, int lba, int blocks, u_char *data) 1441 { 1442 struct scsireq sc; 1443 int rc; 1444 1445 memset(&sc, 0, sizeof(sc)); 1446 sc.cmd[0] = 0xBE; 1447 sc.cmd[1] = 1 << 2; 1448 sc.cmd[2] = ((u_int)lba >> 24) & 0xff; 1449 sc.cmd[3] = ((u_int)lba >> 16) & 0xff; 1450 sc.cmd[4] = ((u_int)lba >> 8) & 0xff; 1451 sc.cmd[5] = lba & 0xff; 1452 sc.cmd[6] = ((u_int)blocks >> 16) & 0xff; 1453 sc.cmd[7] = ((u_int)blocks >> 8) & 0xff; 1454 sc.cmd[8] = blocks & 0xff; 1455 sc.cmd[9] = 1 << 4; 1456 sc.cmd[10] = 0; 1457 sc.cmdlen = 12; 1458 sc.databuf = (caddr_t) data; 1459 sc.datalen = CDDA_SIZE * blocks; 1460 sc.senselen = sizeof(sc.sense); 1461 sc.flags = SCCMD_READ; 1462 sc.timeout = 10000; /* 10s */ 1463 rc = ioctl(afd, SCIOCCOMMAND, &sc); 1464 if (rc < 0 || sc.retsts != SCCMD_OK) { 1465 if (da.read_errors < 10) { 1466 warnx("scsi cmd failed: retsts %d status %d", 1467 sc.retsts, sc.status); 1468 } 1469 da.read_errors++; 1470 return -1; 1471 } 1472 return CDDA_SIZE * blocks; 1473 } 1474 1475 static void 1476 toc2msf(u_int i, u_int *m, u_int *s, u_int *f) 1477 { 1478 struct cd_toc_entry *ctep; 1479 1480 assert(i <= CD_MAX_TRACK); 1481 1482 ctep = &toc_buffer[i]; 1483 1484 if (msf) { 1485 *m = ctep->addr.msf.minute; 1486 *s = ctep->addr.msf.second; 1487 *f = ctep->addr.msf.frame; 1488 } else { 1489 lba2msf(ctep->addr.lba, m, s, f); 1490 } 1491 } 1492 1493 static int 1494 toc2lba(u_int i) 1495 { 1496 struct cd_toc_entry *ctep; 1497 1498 assert(i > 0); 1499 assert(i <= CD_MAX_TRACK); 1500 1501 ctep = &toc_buffer[i-1]; 1502 1503 if (msf) { 1504 return msf2lba( 1505 (u_int)ctep->addr.msf.minute, 1506 (u_int)ctep->addr.msf.second, 1507 (u_int)ctep->addr.msf.frame); 1508 } else { 1509 return ctep->addr.lba; 1510 } 1511 } 1512 1513 static void 1514 addmsf(u_int *m, u_int *s, u_int *f, u_int m2, u_int s2, u_int f2) 1515 { 1516 *f += f2; 1517 if (*f > 75) { 1518 *s += *f / 75; 1519 *f %= 75; 1520 } 1521 1522 *s += s2; 1523 if (*s > 60) { 1524 *m += *s / 60; 1525 *s %= 60; 1526 } 1527 1528 *m += m2; 1529 } 1530