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