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