1 /* $OpenBSD: sio_aucat.c,v 1.14 2012/11/23 06:40:26 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 events; /* events the user requested */ 40 unsigned int 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 size_t round; /* write block size */ 46 size_t walign; /* align write packets size to this */ 47 }; 48 49 static void sio_aucat_close(struct sio_hdl *); 50 static int sio_aucat_start(struct sio_hdl *); 51 static int sio_aucat_stop(struct sio_hdl *); 52 static int sio_aucat_setpar(struct sio_hdl *, struct sio_par *); 53 static int sio_aucat_getpar(struct sio_hdl *, struct sio_par *); 54 static int sio_aucat_getcap(struct sio_hdl *, struct sio_cap *); 55 static size_t sio_aucat_read(struct sio_hdl *, void *, size_t); 56 static size_t sio_aucat_write(struct sio_hdl *, const void *, size_t); 57 static int sio_aucat_nfds(struct sio_hdl *); 58 static int sio_aucat_pollfd(struct sio_hdl *, struct pollfd *, int); 59 static int sio_aucat_revents(struct sio_hdl *, struct pollfd *); 60 static int sio_aucat_setvol(struct sio_hdl *, unsigned int); 61 static void sio_aucat_getvol(struct sio_hdl *); 62 63 static struct sio_ops sio_aucat_ops = { 64 sio_aucat_close, 65 sio_aucat_setpar, 66 sio_aucat_getpar, 67 sio_aucat_getcap, 68 sio_aucat_write, 69 sio_aucat_read, 70 sio_aucat_start, 71 sio_aucat_stop, 72 sio_aucat_nfds, 73 sio_aucat_pollfd, 74 sio_aucat_revents, 75 sio_aucat_setvol, 76 sio_aucat_getvol 77 }; 78 79 /* 80 * execute the next message, return 0 if blocked 81 */ 82 static int 83 sio_aucat_runmsg(struct sio_aucat_hdl *hdl) 84 { 85 int delta; 86 unsigned int size, ctl; 87 88 if (!aucat_rmsg(&hdl->aucat, &hdl->sio.eof)) 89 return 0; 90 switch (ntohl(hdl->aucat.rmsg.cmd)) { 91 case AMSG_DATA: 92 size = ntohl(hdl->aucat.rmsg.u.data.size); 93 if (size == 0 || size % hdl->rbpf) { 94 DPRINTF("sio_aucat_runmsg: bad data message\n"); 95 hdl->sio.eof = 1; 96 return 0; 97 } 98 return 1; 99 case AMSG_FLOWCTL: 100 delta = ntohl(hdl->aucat.rmsg.u.ts.delta); 101 hdl->aucat.maxwrite += delta * (int)hdl->wbpf; 102 DPRINTF("aucat: flowctl = %d, maxwrite = %d\n", 103 delta, hdl->aucat.maxwrite); 104 break; 105 case AMSG_MOVE: 106 delta = ntohl(hdl->aucat.rmsg.u.ts.delta); 107 hdl->delta += delta; 108 DPRINTFN(2, "aucat: move = %d, delta = %d, maxwrite = %d\n", 109 delta, hdl->delta, hdl->aucat.maxwrite); 110 if (hdl->delta >= 0) { 111 sio_onmove_cb(&hdl->sio, hdl->delta); 112 hdl->delta = 0; 113 } 114 break; 115 case AMSG_SETVOL: 116 ctl = ntohl(hdl->aucat.rmsg.u.vol.ctl); 117 hdl->curvol = hdl->reqvol = ctl; 118 sio_onvol_cb(&hdl->sio, ctl); 119 break; 120 case AMSG_STOP: 121 hdl->pstate = PSTATE_INIT; 122 break; 123 default: 124 DPRINTF("sio_aucat_runmsg: unhandled message %u\n", hdl->aucat.rmsg.cmd); 125 hdl->sio.eof = 1; 126 return 0; 127 } 128 hdl->aucat.rstate = RSTATE_MSG; 129 hdl->aucat.rtodo = sizeof(struct amsg); 130 return 1; 131 } 132 133 static int 134 sio_aucat_buildmsg(struct sio_aucat_hdl *hdl) 135 { 136 if (hdl->curvol != hdl->reqvol) { 137 hdl->aucat.wstate = WSTATE_MSG; 138 hdl->aucat.wtodo = sizeof(struct amsg); 139 hdl->aucat.wmsg.cmd = htonl(AMSG_SETVOL); 140 hdl->aucat.wmsg.u.vol.ctl = htonl(hdl->reqvol); 141 hdl->curvol = hdl->reqvol; 142 return aucat_wmsg(&hdl->aucat, &hdl->sio.eof); 143 } 144 return 0; 145 } 146 147 struct sio_hdl * 148 sio_aucat_open(const char *str, unsigned int mode, int nbio) 149 { 150 struct sio_aucat_hdl *hdl; 151 152 hdl = malloc(sizeof(struct sio_aucat_hdl)); 153 if (hdl == NULL) 154 return NULL; 155 if (!aucat_open(&hdl->aucat, str, mode, 0)) { 156 free(hdl); 157 return NULL; 158 } 159 sio_create(&hdl->sio, &sio_aucat_ops, mode, nbio); 160 hdl->curvol = SIO_MAXVOL; 161 hdl->reqvol = SIO_MAXVOL; 162 hdl->pstate = PSTATE_INIT; 163 hdl->round = 0xdeadbeef; 164 hdl->walign = 0xdeadbeef; 165 return (struct sio_hdl *)hdl; 166 } 167 168 static void 169 sio_aucat_close(struct sio_hdl *sh) 170 { 171 struct sio_aucat_hdl *hdl = (struct sio_aucat_hdl *)sh; 172 173 if (!hdl->sio.eof && hdl->sio.started) 174 (void)sio_aucat_stop(&hdl->sio); 175 aucat_close(&hdl->aucat, hdl->sio.eof); 176 free(hdl); 177 } 178 179 static int 180 sio_aucat_start(struct sio_hdl *sh) 181 { 182 struct sio_aucat_hdl *hdl = (struct sio_aucat_hdl *)sh; 183 struct sio_par par; 184 185 /* 186 * save bpf 187 */ 188 if (!sio_getpar(&hdl->sio, &par)) 189 return 0; 190 hdl->wbpf = par.bps * par.pchan; 191 hdl->rbpf = par.bps * par.rchan; 192 hdl->aucat.maxwrite = 0; 193 hdl->round = par.round; 194 hdl->delta = 0; 195 DPRINTF("aucat: start, maxwrite = %d\n", hdl->aucat.maxwrite); 196 197 AMSG_INIT(&hdl->aucat.wmsg); 198 hdl->aucat.wmsg.cmd = htonl(AMSG_START); 199 hdl->aucat.wtodo = sizeof(struct amsg); 200 if (!aucat_wmsg(&hdl->aucat, &hdl->sio.eof)) 201 return 0; 202 hdl->aucat.rstate = RSTATE_MSG; 203 hdl->aucat.rtodo = sizeof(struct amsg); 204 if (!aucat_setfl(&hdl->aucat, 1, &hdl->sio.eof)) 205 return 0; 206 hdl->walign = hdl->round * hdl->wbpf; 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 int 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->aucat.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 int i, bps, le, sig, chan, rindex, rmult; 331 static unsigned int 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 int)) { 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->aucat.maxwrite <= 0) 424 return 0; 425 if (len > hdl->aucat.maxwrite) 426 len = hdl->aucat.maxwrite; 427 if (len > hdl->walign) 428 len = hdl->walign; 429 n = aucat_wdata(&hdl->aucat, buf, len, hdl->wbpf, &hdl->sio.eof); 430 hdl->aucat.maxwrite -= n; 431 hdl->walign -= n; 432 if (hdl->walign == 0) 433 hdl->walign = hdl->round * hdl->wbpf; 434 return n; 435 } 436 437 static int 438 sio_aucat_nfds(struct sio_hdl *hdl) 439 { 440 return 1; 441 } 442 443 static int 444 sio_aucat_pollfd(struct sio_hdl *sh, struct pollfd *pfd, int events) 445 { 446 struct sio_aucat_hdl *hdl = (struct sio_aucat_hdl *)sh; 447 448 hdl->events = events; 449 if (hdl->aucat.maxwrite <= 0) 450 events &= ~POLLOUT; 451 return aucat_pollfd(&hdl->aucat, pfd, events); 452 } 453 454 static int 455 sio_aucat_revents(struct sio_hdl *sh, struct pollfd *pfd) 456 { 457 struct sio_aucat_hdl *hdl = (struct sio_aucat_hdl *)sh; 458 int revents = pfd->revents; 459 460 if (revents & POLLIN) { 461 while (hdl->aucat.rstate == RSTATE_MSG) { 462 if (!sio_aucat_runmsg(hdl)) 463 break; 464 } 465 if (hdl->aucat.rstate != RSTATE_DATA) 466 revents &= ~POLLIN; 467 } 468 if (revents & POLLOUT) { 469 if (hdl->aucat.maxwrite <= 0) 470 revents &= ~POLLOUT; 471 } 472 if (hdl->sio.eof) 473 return POLLHUP; 474 DPRINTFN(2, "sio_aucat_revents: %x\n", revents & hdl->events); 475 return revents & (hdl->events | POLLHUP); 476 } 477 478 static int 479 sio_aucat_setvol(struct sio_hdl *sh, unsigned int vol) 480 { 481 struct sio_aucat_hdl *hdl = (struct sio_aucat_hdl *)sh; 482 483 hdl->reqvol = vol; 484 return 1; 485 } 486 487 static void 488 sio_aucat_getvol(struct sio_hdl *sh) 489 { 490 struct sio_aucat_hdl *hdl = (struct sio_aucat_hdl *)sh; 491 492 sio_onvol_cb(&hdl->sio, hdl->reqvol); 493 return; 494 } 495