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