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