1 /* $OpenBSD: sio_aucat.c,v 1.9 2011/11/15 08:05:22 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 "aucat.h" 31 #include "debug.h" 32 #include "sio_priv.h" 33 34 struct sio_aucat_hdl { 35 struct sio_hdl sio; 36 struct aucat aucat; 37 unsigned rbpf, wbpf; /* read and write bytes-per-frame */ 38 int maxwrite; /* latency constraint */ 39 int events; /* events the user requested */ 40 unsigned curvol, reqvol; /* current and requested volume */ 41 int delta; /* some of received deltas */ 42 #define PSTATE_INIT 0 43 #define PSTATE_RUN 1 44 int pstate; 45 }; 46 47 static void sio_aucat_close(struct sio_hdl *); 48 static int sio_aucat_start(struct sio_hdl *); 49 static int sio_aucat_stop(struct sio_hdl *); 50 static int sio_aucat_setpar(struct sio_hdl *, struct sio_par *); 51 static int sio_aucat_getpar(struct sio_hdl *, struct sio_par *); 52 static int sio_aucat_getcap(struct sio_hdl *, struct sio_cap *); 53 static size_t sio_aucat_read(struct sio_hdl *, void *, size_t); 54 static size_t sio_aucat_write(struct sio_hdl *, const void *, size_t); 55 static int sio_aucat_nfds(struct sio_hdl *); 56 static int sio_aucat_pollfd(struct sio_hdl *, struct pollfd *, int); 57 static int sio_aucat_revents(struct sio_hdl *, struct pollfd *); 58 static int sio_aucat_setvol(struct sio_hdl *, unsigned); 59 static void sio_aucat_getvol(struct sio_hdl *); 60 61 static struct sio_ops sio_aucat_ops = { 62 sio_aucat_close, 63 sio_aucat_setpar, 64 sio_aucat_getpar, 65 sio_aucat_getcap, 66 sio_aucat_write, 67 sio_aucat_read, 68 sio_aucat_start, 69 sio_aucat_stop, 70 sio_aucat_nfds, 71 sio_aucat_pollfd, 72 sio_aucat_revents, 73 sio_aucat_setvol, 74 sio_aucat_getvol 75 }; 76 77 /* 78 * execute the next message, return 0 if blocked 79 */ 80 static int 81 sio_aucat_runmsg(struct sio_aucat_hdl *hdl) 82 { 83 int delta; 84 unsigned size, ctl; 85 86 if (!aucat_rmsg(&hdl->aucat, &hdl->sio.eof)) 87 return 0; 88 switch (ntohl(hdl->aucat.rmsg.cmd)) { 89 case AMSG_DATA: 90 size = ntohl(hdl->aucat.rmsg.u.data.size); 91 if (size == 0 || size % hdl->rbpf) { 92 DPRINTF("sio_aucat_runmsg: bad data message\n"); 93 hdl->sio.eof = 1; 94 return 0; 95 } 96 return 1; 97 case AMSG_POS: 98 delta = ntohl(hdl->aucat.rmsg.u.ts.delta); 99 hdl->maxwrite += delta * (int)hdl->wbpf; 100 DPRINTF("aucat: pos = %d, maxwrite = %d\n", 101 delta, hdl->maxwrite); 102 hdl->delta = delta; 103 if (hdl->delta >= 0) { 104 sio_onmove_cb(&hdl->sio, hdl->delta); 105 hdl->delta = 0; 106 } 107 break; 108 case AMSG_MOVE: 109 delta = ntohl(hdl->aucat.rmsg.u.ts.delta); 110 hdl->maxwrite += delta * hdl->wbpf; 111 hdl->delta += delta; 112 DPRINTFN(2, "aucat: move = %d, delta = %d, maxwrite = %d\n", 113 delta, hdl->delta, hdl->maxwrite); 114 if (hdl->delta >= 0) { 115 sio_onmove_cb(&hdl->sio, hdl->delta); 116 hdl->delta = 0; 117 } 118 break; 119 case AMSG_SETVOL: 120 ctl = ntohl(hdl->aucat.rmsg.u.vol.ctl); 121 hdl->curvol = hdl->reqvol = ctl; 122 sio_onvol_cb(&hdl->sio, ctl); 123 break; 124 case AMSG_STOP: 125 hdl->pstate = PSTATE_INIT; 126 break; 127 default: 128 DPRINTF("sio_aucat_runmsg: unhandled message %u\n", hdl->aucat.rmsg.cmd); 129 hdl->sio.eof = 1; 130 return 0; 131 } 132 hdl->aucat.rstate = RSTATE_MSG; 133 hdl->aucat.rtodo = sizeof(struct amsg); 134 return 1; 135 } 136 137 static int 138 sio_aucat_buildmsg(struct sio_aucat_hdl *hdl) 139 { 140 if (hdl->curvol != hdl->reqvol) { 141 hdl->aucat.wstate = WSTATE_MSG; 142 hdl->aucat.wtodo = sizeof(struct amsg); 143 hdl->aucat.wmsg.cmd = htonl(AMSG_SETVOL); 144 hdl->aucat.wmsg.u.vol.ctl = htonl(hdl->reqvol); 145 hdl->curvol = hdl->reqvol; 146 return aucat_wmsg(&hdl->aucat, &hdl->sio.eof); 147 } 148 return 0; 149 } 150 151 struct sio_hdl * 152 sio_aucat_open(const char *str, unsigned mode, int nbio) 153 { 154 struct sio_aucat_hdl *hdl; 155 156 hdl = malloc(sizeof(struct sio_aucat_hdl)); 157 if (hdl == NULL) 158 return NULL; 159 if (!aucat_open(&hdl->aucat, str, mode, 0)) { 160 free(hdl); 161 return NULL; 162 } 163 sio_create(&hdl->sio, &sio_aucat_ops, mode, nbio); 164 hdl->curvol = SIO_MAXVOL; 165 hdl->reqvol = SIO_MAXVOL; 166 hdl->pstate = PSTATE_INIT; 167 return (struct sio_hdl *)hdl; 168 } 169 170 static void 171 sio_aucat_close(struct sio_hdl *sh) 172 { 173 struct sio_aucat_hdl *hdl = (struct sio_aucat_hdl *)sh; 174 175 if (!hdl->sio.eof && hdl->sio.started) 176 (void)sio_aucat_stop(&hdl->sio); 177 aucat_close(&hdl->aucat, hdl->sio.eof); 178 free(hdl); 179 } 180 181 static int 182 sio_aucat_start(struct sio_hdl *sh) 183 { 184 struct sio_aucat_hdl *hdl = (struct sio_aucat_hdl *)sh; 185 struct sio_par par; 186 187 /* 188 * save bpf 189 */ 190 if (!sio_getpar(&hdl->sio, &par)) 191 return 0; 192 hdl->wbpf = par.bps * par.pchan; 193 hdl->rbpf = par.bps * par.rchan; 194 hdl->maxwrite = hdl->wbpf * par.bufsz; 195 hdl->delta = 0; 196 DPRINTF("aucat: start, maxwrite = %d\n", hdl->maxwrite); 197 198 AMSG_INIT(&hdl->aucat.wmsg); 199 hdl->aucat.wmsg.cmd = htonl(AMSG_START); 200 hdl->aucat.wtodo = sizeof(struct amsg); 201 if (!aucat_wmsg(&hdl->aucat, &hdl->sio.eof)) 202 return 0; 203 hdl->aucat.rstate = RSTATE_MSG; 204 hdl->aucat.rtodo = sizeof(struct amsg); 205 if (!aucat_setfl(&hdl->aucat, 1, &hdl->sio.eof)) 206 return 0; 207 hdl->pstate = PSTATE_RUN; 208 return 1; 209 } 210 211 static int 212 sio_aucat_stop(struct sio_hdl *sh) 213 { 214 #define ZERO_MAX 0x400 215 static unsigned char zero[ZERO_MAX]; 216 struct sio_aucat_hdl *hdl = (struct sio_aucat_hdl *)sh; 217 unsigned n, count; 218 219 if (!aucat_setfl(&hdl->aucat, 0, &hdl->sio.eof)) 220 return 0; 221 /* 222 * complete message or data block in progress 223 */ 224 if (hdl->aucat.wstate == WSTATE_MSG) { 225 if (!aucat_wmsg(&hdl->aucat, &hdl->sio.eof)) 226 return 0; 227 } 228 if (hdl->aucat.wstate == WSTATE_DATA) { 229 hdl->maxwrite = hdl->aucat.wtodo; 230 while (hdl->aucat.wstate != WSTATE_IDLE) { 231 count = hdl->aucat.wtodo; 232 if (count > ZERO_MAX) 233 count = ZERO_MAX; 234 n = sio_aucat_write(&hdl->sio, zero, count); 235 if (n == 0) 236 return 0; 237 } 238 } 239 240 /* 241 * send stop message 242 */ 243 AMSG_INIT(&hdl->aucat.wmsg); 244 hdl->aucat.wmsg.cmd = htonl(AMSG_STOP); 245 hdl->aucat.wtodo = sizeof(struct amsg); 246 if (!aucat_wmsg(&hdl->aucat, &hdl->sio.eof)) 247 return 0; 248 249 /* 250 * wait for the STOP ACK 251 */ 252 while (hdl->pstate != PSTATE_INIT) { 253 switch (hdl->aucat.rstate) { 254 case RSTATE_MSG: 255 if (!sio_aucat_runmsg(hdl)) 256 return 0; 257 break; 258 case RSTATE_DATA: 259 if (!sio_aucat_read(&hdl->sio, zero, ZERO_MAX)) 260 return 0; 261 break; 262 } 263 } 264 return 1; 265 } 266 267 static int 268 sio_aucat_setpar(struct sio_hdl *sh, struct sio_par *par) 269 { 270 struct sio_aucat_hdl *hdl = (struct sio_aucat_hdl *)sh; 271 272 AMSG_INIT(&hdl->aucat.wmsg); 273 hdl->aucat.wmsg.cmd = htonl(AMSG_SETPAR); 274 hdl->aucat.wmsg.u.par.bits = par->bits; 275 hdl->aucat.wmsg.u.par.bps = par->bps; 276 hdl->aucat.wmsg.u.par.sig = par->sig; 277 hdl->aucat.wmsg.u.par.le = par->le; 278 hdl->aucat.wmsg.u.par.msb = par->msb; 279 hdl->aucat.wmsg.u.par.rate = htonl(par->rate); 280 hdl->aucat.wmsg.u.par.appbufsz = htonl(par->appbufsz); 281 hdl->aucat.wmsg.u.par.xrun = par->xrun; 282 if (hdl->sio.mode & SIO_REC) 283 hdl->aucat.wmsg.u.par.rchan = htons(par->rchan); 284 if (hdl->sio.mode & SIO_PLAY) 285 hdl->aucat.wmsg.u.par.pchan = htons(par->pchan); 286 hdl->aucat.wtodo = sizeof(struct amsg); 287 if (!aucat_wmsg(&hdl->aucat, &hdl->sio.eof)) 288 return 0; 289 return 1; 290 } 291 292 static int 293 sio_aucat_getpar(struct sio_hdl *sh, struct sio_par *par) 294 { 295 struct sio_aucat_hdl *hdl = (struct sio_aucat_hdl *)sh; 296 297 AMSG_INIT(&hdl->aucat.wmsg); 298 hdl->aucat.wmsg.cmd = htonl(AMSG_GETPAR); 299 hdl->aucat.wtodo = sizeof(struct amsg); 300 if (!aucat_wmsg(&hdl->aucat, &hdl->sio.eof)) 301 return 0; 302 hdl->aucat.rtodo = sizeof(struct amsg); 303 if (!aucat_rmsg(&hdl->aucat, &hdl->sio.eof)) 304 return 0; 305 if (ntohl(hdl->aucat.rmsg.cmd) != AMSG_GETPAR) { 306 DPRINTF("sio_aucat_getpar: protocol err\n"); 307 hdl->sio.eof = 1; 308 return 0; 309 } 310 par->bits = hdl->aucat.rmsg.u.par.bits; 311 par->bps = hdl->aucat.rmsg.u.par.bps; 312 par->sig = hdl->aucat.rmsg.u.par.sig; 313 par->le = hdl->aucat.rmsg.u.par.le; 314 par->msb = hdl->aucat.rmsg.u.par.msb; 315 par->rate = ntohl(hdl->aucat.rmsg.u.par.rate); 316 par->bufsz = ntohl(hdl->aucat.rmsg.u.par.bufsz); 317 par->appbufsz = ntohl(hdl->aucat.rmsg.u.par.appbufsz); 318 par->xrun = hdl->aucat.rmsg.u.par.xrun; 319 par->round = ntohl(hdl->aucat.rmsg.u.par.round); 320 if (hdl->sio.mode & SIO_PLAY) 321 par->pchan = ntohs(hdl->aucat.rmsg.u.par.pchan); 322 if (hdl->sio.mode & SIO_REC) 323 par->rchan = ntohs(hdl->aucat.rmsg.u.par.rchan); 324 return 1; 325 } 326 327 static int 328 sio_aucat_getcap(struct sio_hdl *sh, struct sio_cap *cap) 329 { 330 unsigned i, bps, le, sig, chan, rindex, rmult; 331 static unsigned rates[] = { 8000, 11025, 12000 }; 332 333 bps = 1; 334 sig = le = 0; 335 cap->confs[0].enc = 0; 336 for (i = 0; i < SIO_NENC; i++) { 337 if (bps > 4) 338 break; 339 cap->confs[0].enc |= 1 << i; 340 cap->enc[i].bits = bps == 4 ? 24 : bps * 8; 341 cap->enc[i].bps = bps; 342 cap->enc[i].sig = sig ^ 1; 343 cap->enc[i].le = bps > 1 ? le : SIO_LE_NATIVE; 344 cap->enc[i].msb = 1; 345 le++; 346 if (le > 1 || bps == 1) { 347 le = 0; 348 sig++; 349 } 350 if (sig > 1 || (le == 0 && bps > 1)) { 351 sig = 0; 352 bps++; 353 } 354 } 355 chan = 1; 356 cap->confs[0].rchan = 0; 357 for (i = 0; i < SIO_NCHAN; i++) { 358 if (chan > 16) 359 break; 360 cap->confs[0].rchan |= 1 << i; 361 cap->rchan[i] = chan; 362 if (chan >= 12) { 363 chan += 4; 364 } else if (chan >= 2) { 365 chan += 2; 366 } else 367 chan++; 368 } 369 chan = 1; 370 cap->confs[0].pchan = 0; 371 for (i = 0; i < SIO_NCHAN; i++) { 372 if (chan > 16) 373 break; 374 cap->confs[0].pchan |= 1 << i; 375 cap->pchan[i] = chan; 376 if (chan >= 12) { 377 chan += 4; 378 } else if (chan >= 2) { 379 chan += 2; 380 } else 381 chan++; 382 } 383 rindex = 0; 384 rmult = 1; 385 cap->confs[0].rate = 0; 386 for (i = 0; i < SIO_NRATE; i++) { 387 if (rmult >= 32) 388 break; 389 cap->rate[i] = rates[rindex] * rmult; 390 cap->confs[0].rate |= 1 << i; 391 rindex++; 392 if (rindex == sizeof(rates) / sizeof(unsigned)) { 393 rindex = 0; 394 rmult *= 2; 395 } 396 } 397 cap->nconf = 1; 398 return 1; 399 } 400 401 static size_t 402 sio_aucat_read(struct sio_hdl *sh, void *buf, size_t len) 403 { 404 struct sio_aucat_hdl *hdl = (struct sio_aucat_hdl *)sh; 405 406 while (hdl->aucat.rstate == RSTATE_MSG) { 407 if (!sio_aucat_runmsg(hdl)) 408 return 0; 409 } 410 return aucat_rdata(&hdl->aucat, buf, len, &hdl->sio.eof); 411 } 412 413 static size_t 414 sio_aucat_write(struct sio_hdl *sh, const void *buf, size_t len) 415 { 416 struct sio_aucat_hdl *hdl = (struct sio_aucat_hdl *)sh; 417 size_t n; 418 419 while (hdl->aucat.wstate == WSTATE_IDLE) { 420 if (!sio_aucat_buildmsg(hdl)) 421 break; 422 } 423 if (len <= 0 || hdl->maxwrite <= 0) 424 return 0; 425 if (len > hdl->maxwrite) 426 len = hdl->maxwrite; 427 n = aucat_wdata(&hdl->aucat, buf, len, hdl->wbpf, &hdl->sio.eof); 428 hdl->maxwrite -= n; 429 return n; 430 } 431 432 static int 433 sio_aucat_nfds(struct sio_hdl *hdl) 434 { 435 return 1; 436 } 437 438 static int 439 sio_aucat_pollfd(struct sio_hdl *sh, struct pollfd *pfd, int events) 440 { 441 struct sio_aucat_hdl *hdl = (struct sio_aucat_hdl *)sh; 442 443 hdl->events = events; 444 if (hdl->maxwrite <= 0) 445 events &= ~POLLOUT; 446 return aucat_pollfd(&hdl->aucat, pfd, events); 447 } 448 449 static int 450 sio_aucat_revents(struct sio_hdl *sh, struct pollfd *pfd) 451 { 452 struct sio_aucat_hdl *hdl = (struct sio_aucat_hdl *)sh; 453 int revents = pfd->revents; 454 455 if (revents & POLLIN) { 456 while (hdl->aucat.rstate == RSTATE_MSG) { 457 if (!sio_aucat_runmsg(hdl)) 458 break; 459 } 460 if (hdl->aucat.rstate != RSTATE_DATA) 461 revents &= ~POLLIN; 462 } 463 if (revents & POLLOUT) { 464 if (hdl->maxwrite <= 0) 465 revents &= ~POLLOUT; 466 } 467 if (hdl->sio.eof) 468 return POLLHUP; 469 DPRINTFN(2, "sio_aucat_revents: %x\n", revents & hdl->events); 470 return revents & (hdl->events | POLLHUP); 471 } 472 473 static int 474 sio_aucat_setvol(struct sio_hdl *sh, unsigned vol) 475 { 476 struct sio_aucat_hdl *hdl = (struct sio_aucat_hdl *)sh; 477 478 hdl->reqvol = vol; 479 return 1; 480 } 481 482 static void 483 sio_aucat_getvol(struct sio_hdl *sh) 484 { 485 struct sio_aucat_hdl *hdl = (struct sio_aucat_hdl *)sh; 486 487 sio_onvol_cb(&hdl->sio, hdl->reqvol); 488 return; 489 } 490