1 /* $OpenBSD: aucat.c,v 1.28 2009/08/28 10:52:14 ratchov Exp $ */ 2 /* 3 * Copyright (c) 2008 Alexandre Ratchov <alex@caoua.org> 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 #include <sys/types.h> 19 #include <sys/socket.h> 20 #include <sys/un.h> 21 22 #include <errno.h> 23 #include <fcntl.h> 24 #include <poll.h> 25 #include <stdio.h> 26 #include <stdlib.h> 27 #include <string.h> 28 #include <unistd.h> 29 30 #include "amsg.h" 31 #include "sndio_priv.h" 32 33 struct aucat_hdl { 34 struct sio_hdl sio; 35 int fd; /* socket */ 36 struct amsg rmsg, wmsg; /* temporary messages */ 37 size_t wtodo, rtodo; /* bytes to complete the packet */ 38 #define STATE_IDLE 0 /* nothing to do */ 39 #define STATE_MSG 1 /* message being transferred */ 40 #define STATE_DATA 2 /* data being transferred */ 41 unsigned rstate, wstate; /* one of above */ 42 unsigned rbpf, wbpf; /* read and write bytes-per-frame */ 43 int maxwrite; /* latency constraint */ 44 int events; /* events the user requested */ 45 unsigned curvol, reqvol; /* current and requested volume */ 46 }; 47 48 static void aucat_close(struct sio_hdl *); 49 static int aucat_start(struct sio_hdl *); 50 static int aucat_stop(struct sio_hdl *); 51 static int aucat_setpar(struct sio_hdl *, struct sio_par *); 52 static int aucat_getpar(struct sio_hdl *, struct sio_par *); 53 static int aucat_getcap(struct sio_hdl *, struct sio_cap *); 54 static size_t aucat_read(struct sio_hdl *, void *, size_t); 55 static size_t aucat_write(struct sio_hdl *, const void *, size_t); 56 static int aucat_pollfd(struct sio_hdl *, struct pollfd *, int); 57 static int aucat_revents(struct sio_hdl *, struct pollfd *); 58 static int aucat_setvol(struct sio_hdl *, unsigned); 59 static void aucat_getvol(struct sio_hdl *); 60 61 static struct sio_ops aucat_ops = { 62 aucat_close, 63 aucat_setpar, 64 aucat_getpar, 65 aucat_getcap, 66 aucat_write, 67 aucat_read, 68 aucat_start, 69 aucat_stop, 70 aucat_pollfd, 71 aucat_revents, 72 aucat_setvol, 73 aucat_getvol 74 }; 75 76 /* 77 * read a message, return 0 if blocked 78 */ 79 static int 80 aucat_rmsg(struct aucat_hdl *hdl) 81 { 82 ssize_t n; 83 unsigned char *data; 84 85 while (hdl->rtodo > 0) { 86 data = (unsigned char *)&hdl->rmsg; 87 data += sizeof(struct amsg) - hdl->rtodo; 88 while ((n = read(hdl->fd, data, hdl->rtodo)) < 0) { 89 if (errno == EINTR) 90 continue; 91 if (errno != EAGAIN) { 92 hdl->sio.eof = 1; 93 DPERROR("aucat_rmsg: read"); 94 } 95 return 0; 96 } 97 if (n == 0) { 98 DPRINTF("aucat_rmsg: eof\n"); 99 hdl->sio.eof = 1; 100 return 0; 101 } 102 hdl->rtodo -= n; 103 } 104 return 1; 105 } 106 107 /* 108 * write a message, return 0 if blocked 109 */ 110 static int 111 aucat_wmsg(struct aucat_hdl *hdl) 112 { 113 ssize_t n; 114 unsigned char *data; 115 116 while (hdl->wtodo > 0) { 117 data = (unsigned char *)&hdl->wmsg; 118 data += sizeof(struct amsg) - hdl->wtodo; 119 while ((n = write(hdl->fd, data, hdl->wtodo)) < 0) { 120 if (errno == EINTR) 121 continue; 122 if (errno != EAGAIN) { 123 hdl->sio.eof = 1; 124 DPERROR("aucat_wmsg: write"); 125 } 126 return 0; 127 } 128 hdl->wtodo -= n; 129 } 130 return 1; 131 } 132 133 /* 134 * execute the next message, return 0 if blocked 135 */ 136 static int 137 aucat_runmsg(struct aucat_hdl *hdl) 138 { 139 if (!aucat_rmsg(hdl)) 140 return 0; 141 switch (hdl->rmsg.cmd) { 142 case AMSG_DATA: 143 if (hdl->rmsg.u.data.size == 0 || 144 hdl->rmsg.u.data.size % hdl->rbpf) { 145 DPRINTF("aucat_runmsg: bad data message\n"); 146 hdl->sio.eof = 1; 147 return 0; 148 } 149 hdl->rstate = STATE_DATA; 150 hdl->rtodo = hdl->rmsg.u.data.size; 151 break; 152 case AMSG_MOVE: 153 hdl->maxwrite += hdl->rmsg.u.ts.delta * (int)hdl->wbpf; 154 sio_onmove_cb(&hdl->sio, hdl->rmsg.u.ts.delta); 155 hdl->rstate = STATE_MSG; 156 hdl->rtodo = sizeof(struct amsg); 157 break; 158 case AMSG_SETVOL: 159 hdl->curvol = hdl->reqvol = hdl->rmsg.u.vol.ctl; 160 sio_onvol_cb(&hdl->sio, hdl->curvol); 161 hdl->rstate = STATE_MSG; 162 hdl->rtodo = sizeof(struct amsg); 163 break; 164 case AMSG_GETPAR: 165 case AMSG_ACK: 166 hdl->rstate = STATE_IDLE; 167 hdl->rtodo = 0xdeadbeef; 168 break; 169 default: 170 DPRINTF("aucat_runmsg: unknown message\n"); 171 hdl->sio.eof = 1; 172 return 0; 173 } 174 return 1; 175 } 176 177 struct sio_hdl * 178 sio_open_aucat(const char *str, unsigned mode, int nbio) 179 { 180 extern char *__progname; 181 int s; 182 char unit[4], *sep, *opt; 183 struct aucat_hdl *hdl; 184 struct sockaddr_un ca; 185 socklen_t len = sizeof(struct sockaddr_un); 186 uid_t uid; 187 188 sep = strchr(str, '.'); 189 if (sep == NULL) { 190 opt = "default"; 191 strlcpy(unit, str, sizeof(unit)); 192 } else { 193 opt = sep + 1; 194 if (sep - str >= sizeof(unit)) { 195 DPRINTF("sio_open_aucat: %s: too long\n", str); 196 return NULL; 197 } 198 strlcpy(unit, str, opt - str); 199 } 200 DPRINTF("sio_open_aucat: trying %s -> %s.%s\n", str, unit, opt); 201 uid = geteuid(); 202 if (strchr(str, '/') != NULL) 203 return NULL; 204 snprintf(ca.sun_path, sizeof(ca.sun_path), 205 "/tmp/aucat-%u/softaudio%s", uid, unit); 206 ca.sun_family = AF_UNIX; 207 208 hdl = malloc(sizeof(struct aucat_hdl)); 209 if (hdl == NULL) 210 return NULL; 211 sio_create(&hdl->sio, &aucat_ops, mode, nbio); 212 213 s = socket(AF_UNIX, SOCK_STREAM, 0); 214 if (s < 0) 215 goto bad_free; 216 while (connect(s, (struct sockaddr *)&ca, len) < 0) { 217 if (errno == EINTR) 218 continue; 219 DPERROR("sio_open_aucat: connect"); 220 goto bad_connect; 221 } 222 if (fcntl(s, F_SETFD, FD_CLOEXEC) < 0) { 223 DPERROR("FD_CLOEXEC"); 224 goto bad_connect; 225 } 226 hdl->fd = s; 227 hdl->rstate = STATE_IDLE; 228 hdl->rtodo = 0xdeadbeef; 229 hdl->wstate = STATE_IDLE; 230 hdl->wtodo = 0xdeadbeef; 231 hdl->curvol = SIO_MAXVOL; 232 hdl->reqvol = SIO_MAXVOL; 233 234 /* 235 * say hello to server 236 */ 237 AMSG_INIT(&hdl->wmsg); 238 hdl->wmsg.cmd = AMSG_HELLO; 239 hdl->wmsg.u.hello.proto = 0; 240 if (mode & SIO_PLAY) 241 hdl->wmsg.u.hello.proto |= AMSG_PLAY; 242 if (mode & SIO_REC) 243 hdl->wmsg.u.hello.proto |= AMSG_REC; 244 strlcpy(hdl->wmsg.u.hello.who, __progname, 245 sizeof(hdl->wmsg.u.hello.who)); 246 strlcpy(hdl->wmsg.u.hello.opt, opt, 247 sizeof(hdl->wmsg.u.hello.opt)); 248 hdl->wtodo = sizeof(struct amsg); 249 if (!aucat_wmsg(hdl)) 250 goto bad_connect; 251 hdl->rtodo = sizeof(struct amsg); 252 if (!aucat_rmsg(hdl)) { 253 DPRINTF("sio_open_aucat: mode refused\n"); 254 goto bad_connect; 255 } 256 if (hdl->rmsg.cmd != AMSG_ACK) { 257 DPRINTF("sio_open_aucat: protocol err\n"); 258 goto bad_connect; 259 } 260 return (struct sio_hdl *)hdl; 261 bad_connect: 262 while (close(s) < 0 && errno == EINTR) 263 ; /* retry */ 264 bad_free: 265 free(hdl); 266 return NULL; 267 } 268 269 static void 270 aucat_close(struct sio_hdl *sh) 271 { 272 struct aucat_hdl *hdl = (struct aucat_hdl *)sh; 273 char dummy[1]; 274 275 if (!hdl->sio.eof && hdl->sio.started) 276 (void)aucat_stop(&hdl->sio); 277 if (!hdl->sio.eof) { 278 AMSG_INIT(&hdl->wmsg); 279 hdl->wmsg.cmd = AMSG_BYE; 280 hdl->wtodo = sizeof(struct amsg); 281 if (!aucat_wmsg(hdl)) 282 goto bad_close; 283 while (read(hdl->fd, dummy, 1) < 0 && errno == EINTR) 284 ; /* nothing */ 285 } 286 bad_close: 287 while (close(hdl->fd) < 0 && errno == EINTR) 288 ; /* nothing */ 289 free(hdl); 290 } 291 292 static int 293 aucat_start(struct sio_hdl *sh) 294 { 295 struct aucat_hdl *hdl = (struct aucat_hdl *)sh; 296 struct sio_par par; 297 298 /* 299 * save bpf 300 */ 301 if (!sio_getpar(&hdl->sio, &par)) 302 return 0; 303 hdl->wbpf = par.bps * par.pchan; 304 hdl->rbpf = par.bps * par.rchan; 305 hdl->maxwrite = hdl->wbpf * par.bufsz; 306 307 AMSG_INIT(&hdl->wmsg); 308 hdl->wmsg.cmd = AMSG_START; 309 hdl->wtodo = sizeof(struct amsg); 310 if (!aucat_wmsg(hdl)) 311 return 0; 312 hdl->rstate = STATE_MSG; 313 hdl->rtodo = sizeof(struct amsg); 314 if (fcntl(hdl->fd, F_SETFL, O_NONBLOCK) < 0) { 315 DPERROR("aucat_start: fcntl(0)"); 316 hdl->sio.eof = 1; 317 return 0; 318 } 319 return 1; 320 } 321 322 static int 323 aucat_stop(struct sio_hdl *sh) 324 { 325 #define ZERO_MAX 0x400 326 static unsigned char zero[ZERO_MAX]; 327 struct aucat_hdl *hdl = (struct aucat_hdl *)sh; 328 unsigned n, count, todo; 329 330 if (fcntl(hdl->fd, F_SETFL, 0) < 0) { 331 DPERROR("aucat_stop: fcntl(0)"); 332 hdl->sio.eof = 1; 333 return 0; 334 } 335 336 /* 337 * complete data block in progress 338 */ 339 if (hdl->wstate != STATE_IDLE) { 340 todo = (hdl->wstate == STATE_MSG) ? 341 hdl->wmsg.u.data.size : hdl->wtodo; 342 hdl->maxwrite = todo; 343 memset(zero, 0, ZERO_MAX); 344 while (todo > 0) { 345 count = todo; 346 if (count > ZERO_MAX) 347 count = ZERO_MAX; 348 n = aucat_write(&hdl->sio, zero, count); 349 if (n == 0) 350 return 0; 351 todo -= n; 352 } 353 } 354 355 /* 356 * send stop message 357 */ 358 AMSG_INIT(&hdl->wmsg); 359 hdl->wmsg.cmd = AMSG_STOP; 360 hdl->wtodo = sizeof(struct amsg); 361 if (!aucat_wmsg(hdl)) 362 return 0; 363 if (hdl->rstate == STATE_IDLE) { 364 hdl->rstate = STATE_MSG; 365 hdl->rtodo = sizeof(struct amsg); 366 } 367 368 /* 369 * wait for the STOP ACK 370 */ 371 while (hdl->rstate != STATE_IDLE) { 372 switch (hdl->rstate) { 373 case STATE_MSG: 374 if (!aucat_runmsg(hdl)) 375 return 0; 376 break; 377 case STATE_DATA: 378 if (!aucat_read(&hdl->sio, zero, ZERO_MAX)) 379 return 0; 380 break; 381 } 382 } 383 return 1; 384 } 385 386 static int 387 aucat_setpar(struct sio_hdl *sh, struct sio_par *par) 388 { 389 struct aucat_hdl *hdl = (struct aucat_hdl *)sh; 390 391 AMSG_INIT(&hdl->wmsg); 392 hdl->wmsg.cmd = AMSG_SETPAR; 393 hdl->wmsg.u.par.bits = par->bits; 394 hdl->wmsg.u.par.bps = par->bps; 395 hdl->wmsg.u.par.sig = par->sig; 396 hdl->wmsg.u.par.le = par->le; 397 hdl->wmsg.u.par.msb = par->msb; 398 hdl->wmsg.u.par.rate = par->rate; 399 hdl->wmsg.u.par.appbufsz = par->appbufsz; 400 hdl->wmsg.u.par.xrun = par->xrun; 401 if (hdl->sio.mode & SIO_REC) 402 hdl->wmsg.u.par.rchan = par->rchan; 403 if (hdl->sio.mode & SIO_PLAY) 404 hdl->wmsg.u.par.pchan = par->pchan; 405 hdl->wtodo = sizeof(struct amsg); 406 if (!aucat_wmsg(hdl)) 407 return 0; 408 return 1; 409 } 410 411 static int 412 aucat_getpar(struct sio_hdl *sh, struct sio_par *par) 413 { 414 struct aucat_hdl *hdl = (struct aucat_hdl *)sh; 415 416 AMSG_INIT(&hdl->wmsg); 417 hdl->wmsg.cmd = AMSG_GETPAR; 418 hdl->wtodo = sizeof(struct amsg); 419 if (!aucat_wmsg(hdl)) 420 return 0; 421 hdl->rtodo = sizeof(struct amsg); 422 if (!aucat_rmsg(hdl)) 423 return 0; 424 if (hdl->rmsg.cmd != AMSG_GETPAR) { 425 DPRINTF("aucat_getpar: protocol err\n"); 426 hdl->sio.eof = 1; 427 return 0; 428 } 429 par->bits = hdl->rmsg.u.par.bits; 430 par->bps = hdl->rmsg.u.par.bps; 431 par->sig = hdl->rmsg.u.par.sig; 432 par->le = hdl->rmsg.u.par.le; 433 par->msb = hdl->rmsg.u.par.msb; 434 par->rate = hdl->rmsg.u.par.rate; 435 par->bufsz = hdl->rmsg.u.par.bufsz; 436 par->appbufsz = hdl->rmsg.u.par.appbufsz; 437 par->xrun = hdl->rmsg.u.par.xrun; 438 par->round = hdl->rmsg.u.par.round; 439 if (hdl->sio.mode & SIO_PLAY) 440 par->pchan = hdl->rmsg.u.par.pchan; 441 if (hdl->sio.mode & SIO_REC) 442 par->rchan = hdl->rmsg.u.par.rchan; 443 return 1; 444 } 445 446 static int 447 aucat_getcap(struct sio_hdl *sh, struct sio_cap *cap) 448 { 449 struct aucat_hdl *hdl = (struct aucat_hdl *)sh; 450 451 AMSG_INIT(&hdl->wmsg); 452 hdl->wmsg.cmd = AMSG_GETCAP; 453 hdl->wtodo = sizeof(struct amsg); 454 if (!aucat_wmsg(hdl)) 455 return 0; 456 hdl->rtodo = sizeof(struct amsg); 457 if (!aucat_rmsg(hdl)) 458 return 0; 459 if (hdl->rmsg.cmd != AMSG_GETCAP) { 460 DPRINTF("aucat_getcap: protocol err\n"); 461 hdl->sio.eof = 1; 462 return 0; 463 } 464 cap->enc[0].bits = hdl->rmsg.u.cap.bits; 465 cap->enc[0].bps = SIO_BPS(hdl->rmsg.u.cap.bits); 466 cap->enc[0].sig = 1; 467 cap->enc[0].le = SIO_LE_NATIVE; 468 cap->enc[0].msb = 1; 469 cap->rchan[0] = hdl->rmsg.u.cap.rchan; 470 cap->pchan[0] = hdl->rmsg.u.cap.pchan; 471 cap->rate[0] = hdl->rmsg.u.cap.rate; 472 cap->confs[0].enc = 1; 473 cap->confs[0].rchan = (hdl->rmsg.u.cap.rchan > 0) ? 1 : 0; 474 cap->confs[0].pchan = (hdl->rmsg.u.cap.pchan > 0) ? 1 : 0; 475 cap->confs[0].rate = 1; 476 cap->nconf = 1; 477 return 1; 478 } 479 480 static size_t 481 aucat_read(struct sio_hdl *sh, void *buf, size_t len) 482 { 483 struct aucat_hdl *hdl = (struct aucat_hdl *)sh; 484 ssize_t n; 485 486 while (hdl->rstate != STATE_DATA) { 487 switch (hdl->rstate) { 488 case STATE_MSG: 489 if (!aucat_runmsg(hdl)) 490 return 0; 491 break; 492 case STATE_IDLE: 493 DPRINTF("aucat_read: unexpected idle\n"); 494 break; 495 } 496 } 497 if (len > hdl->rtodo) 498 len = hdl->rtodo; 499 while ((n = read(hdl->fd, buf, len)) < 0) { 500 if (errno == EINTR) 501 continue; 502 if (errno != EAGAIN) { 503 hdl->sio.eof = 1; 504 DPERROR("aucat_read: read"); 505 } 506 return 0; 507 } 508 if (n == 0) { 509 DPRINTF("aucat_read: eof\n"); 510 hdl->sio.eof = 1; 511 return 0; 512 } 513 hdl->rtodo -= n; 514 if (hdl->rtodo == 0) { 515 hdl->rstate = STATE_MSG; 516 hdl->rtodo = sizeof(struct amsg); 517 } 518 return n; 519 } 520 521 static int 522 aucat_buildmsg(struct aucat_hdl *hdl, size_t len) 523 { 524 unsigned sz; 525 526 if (hdl->curvol != hdl->reqvol) { 527 hdl->wstate = STATE_MSG; 528 hdl->wtodo = sizeof(struct amsg); 529 hdl->wmsg.cmd = AMSG_SETVOL; 530 hdl->wmsg.u.vol.ctl = hdl->reqvol; 531 hdl->curvol = hdl->reqvol; 532 return 1; 533 } else if (len > 0) { 534 sz = (len < AMSG_DATAMAX) ? len : AMSG_DATAMAX; 535 sz -= sz % hdl->wbpf; 536 if (sz == 0) 537 sz = hdl->wbpf; 538 hdl->wstate = STATE_MSG; 539 hdl->wtodo = sizeof(struct amsg); 540 hdl->wmsg.cmd = AMSG_DATA; 541 hdl->wmsg.u.data.size = sz; 542 return 1; 543 } 544 return 0; 545 } 546 547 static size_t 548 aucat_write(struct sio_hdl *sh, const void *buf, size_t len) 549 { 550 struct aucat_hdl *hdl = (struct aucat_hdl *)sh; 551 ssize_t n; 552 553 while (hdl->wstate != STATE_DATA) { 554 switch (hdl->wstate) { 555 case STATE_IDLE: 556 if (!aucat_buildmsg(hdl, len)) 557 return 0; 558 /* PASSTHROUGH */ 559 case STATE_MSG: 560 if (!aucat_wmsg(hdl)) 561 return 0; 562 if (hdl->wmsg.cmd == AMSG_DATA) { 563 hdl->wstate = STATE_DATA; 564 hdl->wtodo = hdl->wmsg.u.data.size; 565 } else 566 hdl->wstate = STATE_IDLE; 567 break; 568 default: 569 DPRINTF("aucat_write: bad state\n"); 570 abort(); 571 } 572 } 573 if (hdl->maxwrite <= 0) 574 return 0; 575 if (len > hdl->maxwrite) 576 len = hdl->maxwrite; 577 if (len > hdl->wtodo) 578 len = hdl->wtodo; 579 if (len == 0) { 580 DPRINTF("aucat_write: len == 0\n"); 581 abort(); 582 } 583 while ((n = write(hdl->fd, buf, len)) < 0) { 584 if (errno == EINTR) 585 continue; 586 if (errno != EAGAIN) { 587 hdl->sio.eof = 1; 588 DPERROR("aucat_write: write"); 589 } 590 return 0; 591 } 592 hdl->maxwrite -= n; 593 hdl->wtodo -= n; 594 if (hdl->wtodo == 0) { 595 hdl->wstate = STATE_IDLE; 596 hdl->wtodo = 0xdeadbeef; 597 } 598 return n; 599 } 600 601 static int 602 aucat_pollfd(struct sio_hdl *sh, struct pollfd *pfd, int events) 603 { 604 struct aucat_hdl *hdl = (struct aucat_hdl *)sh; 605 606 hdl->events = events; 607 if (hdl->maxwrite <= 0) 608 events &= ~POLLOUT; 609 if (hdl->rstate == STATE_MSG) 610 events |= POLLIN; 611 pfd->fd = hdl->fd; 612 pfd->events = events; 613 return 1; 614 } 615 616 static int 617 aucat_revents(struct sio_hdl *sh, struct pollfd *pfd) 618 { 619 struct aucat_hdl *hdl = (struct aucat_hdl *)sh; 620 int revents = pfd->revents; 621 622 if (revents & POLLIN) { 623 while (hdl->rstate == STATE_MSG) { 624 if (!aucat_runmsg(hdl)) { 625 revents &= ~POLLIN; 626 break; 627 } 628 } 629 } 630 if (revents & POLLOUT) { 631 if (hdl->maxwrite <= 0) 632 revents &= ~POLLOUT; 633 } 634 if (hdl->sio.eof) 635 return POLLHUP; 636 return revents & (hdl->events | POLLHUP); 637 } 638 639 static int 640 aucat_setvol(struct sio_hdl *sh, unsigned vol) 641 { 642 struct aucat_hdl *hdl = (struct aucat_hdl *)sh; 643 644 hdl->reqvol = vol; 645 return 1; 646 } 647 648 static void 649 aucat_getvol(struct sio_hdl *sh) 650 { 651 struct aucat_hdl *hdl = (struct aucat_hdl *)sh; 652 653 sio_onvol_cb(&hdl->sio, hdl->reqvol); 654 return; 655 } 656