1 /* $OpenBSD: sio_aucat.c,v 1.17 2014/03/05 20:40:49 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 DPRINTFN(3, "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(3, "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 184 hdl->wbpf = hdl->sio.par.bps * hdl->sio.par.pchan; 185 hdl->rbpf = hdl->sio.par.bps * hdl->sio.par.rchan; 186 hdl->aucat.maxwrite = 0; 187 hdl->round = hdl->sio.par.round; 188 hdl->delta = 0; 189 DPRINTFN(2, "aucat: start, maxwrite = %d\n", hdl->aucat.maxwrite); 190 191 AMSG_INIT(&hdl->aucat.wmsg); 192 hdl->aucat.wmsg.cmd = htonl(AMSG_START); 193 hdl->aucat.wtodo = sizeof(struct amsg); 194 if (!_aucat_wmsg(&hdl->aucat, &hdl->sio.eof)) 195 return 0; 196 hdl->aucat.rstate = RSTATE_MSG; 197 hdl->aucat.rtodo = sizeof(struct amsg); 198 if (!_aucat_setfl(&hdl->aucat, 1, &hdl->sio.eof)) 199 return 0; 200 hdl->walign = hdl->round * hdl->wbpf; 201 hdl->pstate = PSTATE_RUN; 202 return 1; 203 } 204 205 static int 206 sio_aucat_stop(struct sio_hdl *sh) 207 { 208 #define ZERO_MAX 0x400 209 static unsigned char zero[ZERO_MAX]; 210 struct sio_aucat_hdl *hdl = (struct sio_aucat_hdl *)sh; 211 unsigned int n, count; 212 213 if (!_aucat_setfl(&hdl->aucat, 0, &hdl->sio.eof)) 214 return 0; 215 /* 216 * complete message or data block in progress 217 */ 218 if (hdl->aucat.wstate == WSTATE_MSG) { 219 if (!_aucat_wmsg(&hdl->aucat, &hdl->sio.eof)) 220 return 0; 221 } 222 if (hdl->aucat.wstate == WSTATE_DATA) { 223 hdl->aucat.maxwrite = hdl->aucat.wtodo; 224 while (hdl->aucat.wstate != WSTATE_IDLE) { 225 count = hdl->aucat.wtodo; 226 if (count > ZERO_MAX) 227 count = ZERO_MAX; 228 n = sio_aucat_write(&hdl->sio, zero, count); 229 if (n == 0) 230 return 0; 231 } 232 } 233 234 /* 235 * send stop message 236 */ 237 AMSG_INIT(&hdl->aucat.wmsg); 238 hdl->aucat.wmsg.cmd = htonl(AMSG_STOP); 239 hdl->aucat.wtodo = sizeof(struct amsg); 240 if (!_aucat_wmsg(&hdl->aucat, &hdl->sio.eof)) 241 return 0; 242 243 /* 244 * wait for the STOP ACK 245 */ 246 while (hdl->pstate != PSTATE_INIT) { 247 switch (hdl->aucat.rstate) { 248 case RSTATE_MSG: 249 if (!sio_aucat_runmsg(hdl)) 250 return 0; 251 break; 252 case RSTATE_DATA: 253 if (!sio_aucat_read(&hdl->sio, zero, ZERO_MAX)) 254 return 0; 255 break; 256 } 257 } 258 return 1; 259 } 260 261 static int 262 sio_aucat_setpar(struct sio_hdl *sh, struct sio_par *par) 263 { 264 struct sio_aucat_hdl *hdl = (struct sio_aucat_hdl *)sh; 265 266 AMSG_INIT(&hdl->aucat.wmsg); 267 hdl->aucat.wmsg.cmd = htonl(AMSG_SETPAR); 268 hdl->aucat.wmsg.u.par.bits = par->bits; 269 hdl->aucat.wmsg.u.par.bps = par->bps; 270 hdl->aucat.wmsg.u.par.sig = par->sig; 271 hdl->aucat.wmsg.u.par.le = par->le; 272 hdl->aucat.wmsg.u.par.msb = par->msb; 273 hdl->aucat.wmsg.u.par.rate = htonl(par->rate); 274 hdl->aucat.wmsg.u.par.appbufsz = htonl(par->appbufsz); 275 hdl->aucat.wmsg.u.par.xrun = par->xrun; 276 if (hdl->sio.mode & SIO_REC) 277 hdl->aucat.wmsg.u.par.rchan = htons(par->rchan); 278 if (hdl->sio.mode & SIO_PLAY) 279 hdl->aucat.wmsg.u.par.pchan = htons(par->pchan); 280 hdl->aucat.wtodo = sizeof(struct amsg); 281 if (!_aucat_wmsg(&hdl->aucat, &hdl->sio.eof)) 282 return 0; 283 return 1; 284 } 285 286 static int 287 sio_aucat_getpar(struct sio_hdl *sh, struct sio_par *par) 288 { 289 struct sio_aucat_hdl *hdl = (struct sio_aucat_hdl *)sh; 290 291 AMSG_INIT(&hdl->aucat.wmsg); 292 hdl->aucat.wmsg.cmd = htonl(AMSG_GETPAR); 293 hdl->aucat.wtodo = sizeof(struct amsg); 294 if (!_aucat_wmsg(&hdl->aucat, &hdl->sio.eof)) 295 return 0; 296 hdl->aucat.rtodo = sizeof(struct amsg); 297 if (!_aucat_rmsg(&hdl->aucat, &hdl->sio.eof)) 298 return 0; 299 if (ntohl(hdl->aucat.rmsg.cmd) != AMSG_GETPAR) { 300 DPRINTF("sio_aucat_getpar: protocol err\n"); 301 hdl->sio.eof = 1; 302 return 0; 303 } 304 par->bits = hdl->aucat.rmsg.u.par.bits; 305 par->bps = hdl->aucat.rmsg.u.par.bps; 306 par->sig = hdl->aucat.rmsg.u.par.sig; 307 par->le = hdl->aucat.rmsg.u.par.le; 308 par->msb = hdl->aucat.rmsg.u.par.msb; 309 par->rate = ntohl(hdl->aucat.rmsg.u.par.rate); 310 par->bufsz = ntohl(hdl->aucat.rmsg.u.par.bufsz); 311 par->appbufsz = ntohl(hdl->aucat.rmsg.u.par.appbufsz); 312 par->xrun = hdl->aucat.rmsg.u.par.xrun; 313 par->round = ntohl(hdl->aucat.rmsg.u.par.round); 314 if (hdl->sio.mode & SIO_PLAY) 315 par->pchan = ntohs(hdl->aucat.rmsg.u.par.pchan); 316 if (hdl->sio.mode & SIO_REC) 317 par->rchan = ntohs(hdl->aucat.rmsg.u.par.rchan); 318 return 1; 319 } 320 321 static int 322 sio_aucat_getcap(struct sio_hdl *sh, struct sio_cap *cap) 323 { 324 unsigned int i, bps, le, sig, chan, rindex, rmult; 325 static unsigned int rates[] = { 8000, 11025, 12000 }; 326 327 bps = 1; 328 sig = le = 0; 329 cap->confs[0].enc = 0; 330 for (i = 0; i < SIO_NENC; i++) { 331 if (bps > 4) 332 break; 333 cap->confs[0].enc |= 1 << i; 334 cap->enc[i].bits = bps == 4 ? 24 : bps * 8; 335 cap->enc[i].bps = bps; 336 cap->enc[i].sig = sig ^ 1; 337 cap->enc[i].le = bps > 1 ? le : SIO_LE_NATIVE; 338 cap->enc[i].msb = 1; 339 le++; 340 if (le > 1 || bps == 1) { 341 le = 0; 342 sig++; 343 } 344 if (sig > 1 || (le == 0 && bps > 1)) { 345 sig = 0; 346 bps++; 347 } 348 } 349 chan = 1; 350 cap->confs[0].rchan = 0; 351 for (i = 0; i < SIO_NCHAN; i++) { 352 if (chan > 16) 353 break; 354 cap->confs[0].rchan |= 1 << i; 355 cap->rchan[i] = chan; 356 if (chan >= 12) { 357 chan += 4; 358 } else if (chan >= 2) { 359 chan += 2; 360 } else 361 chan++; 362 } 363 chan = 1; 364 cap->confs[0].pchan = 0; 365 for (i = 0; i < SIO_NCHAN; i++) { 366 if (chan > 16) 367 break; 368 cap->confs[0].pchan |= 1 << i; 369 cap->pchan[i] = chan; 370 if (chan >= 12) { 371 chan += 4; 372 } else if (chan >= 2) { 373 chan += 2; 374 } else 375 chan++; 376 } 377 rindex = 0; 378 rmult = 1; 379 cap->confs[0].rate = 0; 380 for (i = 0; i < SIO_NRATE; i++) { 381 if (rmult >= 32) 382 break; 383 cap->rate[i] = rates[rindex] * rmult; 384 cap->confs[0].rate |= 1 << i; 385 rindex++; 386 if (rindex == sizeof(rates) / sizeof(unsigned int)) { 387 rindex = 0; 388 rmult *= 2; 389 } 390 } 391 cap->nconf = 1; 392 return 1; 393 } 394 395 static size_t 396 sio_aucat_read(struct sio_hdl *sh, void *buf, size_t len) 397 { 398 struct sio_aucat_hdl *hdl = (struct sio_aucat_hdl *)sh; 399 400 while (hdl->aucat.rstate == RSTATE_MSG) { 401 if (!sio_aucat_runmsg(hdl)) 402 return 0; 403 } 404 return _aucat_rdata(&hdl->aucat, buf, len, &hdl->sio.eof); 405 } 406 407 static size_t 408 sio_aucat_write(struct sio_hdl *sh, const void *buf, size_t len) 409 { 410 struct sio_aucat_hdl *hdl = (struct sio_aucat_hdl *)sh; 411 size_t n; 412 413 while (hdl->aucat.wstate == WSTATE_IDLE) { 414 if (!sio_aucat_buildmsg(hdl)) 415 break; 416 } 417 if (len <= 0 || hdl->aucat.maxwrite <= 0) 418 return 0; 419 if (len > hdl->aucat.maxwrite) 420 len = hdl->aucat.maxwrite; 421 if (len > hdl->walign) 422 len = hdl->walign; 423 n = _aucat_wdata(&hdl->aucat, buf, len, hdl->wbpf, &hdl->sio.eof); 424 hdl->aucat.maxwrite -= n; 425 hdl->walign -= n; 426 if (hdl->walign == 0) 427 hdl->walign = hdl->round * hdl->wbpf; 428 return n; 429 } 430 431 static int 432 sio_aucat_nfds(struct sio_hdl *hdl) 433 { 434 return 1; 435 } 436 437 static int 438 sio_aucat_pollfd(struct sio_hdl *sh, struct pollfd *pfd, int events) 439 { 440 struct sio_aucat_hdl *hdl = (struct sio_aucat_hdl *)sh; 441 442 hdl->events = events; 443 if (hdl->aucat.maxwrite <= 0) 444 events &= ~POLLOUT; 445 return _aucat_pollfd(&hdl->aucat, pfd, events); 446 } 447 448 static int 449 sio_aucat_revents(struct sio_hdl *sh, struct pollfd *pfd) 450 { 451 struct sio_aucat_hdl *hdl = (struct sio_aucat_hdl *)sh; 452 int revents = pfd->revents; 453 454 if (revents & POLLIN) { 455 while (hdl->aucat.rstate == RSTATE_MSG) { 456 if (!sio_aucat_runmsg(hdl)) 457 break; 458 } 459 if (hdl->aucat.rstate != RSTATE_DATA) 460 revents &= ~POLLIN; 461 } 462 if (revents & POLLOUT) { 463 if (hdl->aucat.maxwrite <= 0) 464 revents &= ~POLLOUT; 465 } 466 if (hdl->sio.eof) 467 return POLLHUP; 468 DPRINTFN(3, "sio_aucat_revents: %x\n", revents & hdl->events); 469 return revents & (hdl->events | POLLHUP); 470 } 471 472 static int 473 sio_aucat_setvol(struct sio_hdl *sh, unsigned int vol) 474 { 475 struct sio_aucat_hdl *hdl = (struct sio_aucat_hdl *)sh; 476 477 hdl->reqvol = vol; 478 return 1; 479 } 480 481 static void 482 sio_aucat_getvol(struct sio_hdl *sh) 483 { 484 struct sio_aucat_hdl *hdl = (struct sio_aucat_hdl *)sh; 485 486 _sio_onvol_cb(&hdl->sio, hdl->reqvol); 487 return; 488 } 489