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