1 /* $OpenBSD: sio_aucat.c,v 1.21 2022/04/29 08:30:48 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_flush(struct sio_hdl *); 53 static int sio_aucat_setpar(struct sio_hdl *, struct sio_par *); 54 static int sio_aucat_getpar(struct sio_hdl *, struct sio_par *); 55 static int sio_aucat_getcap(struct sio_hdl *, struct sio_cap *); 56 static size_t sio_aucat_read(struct sio_hdl *, void *, size_t); 57 static size_t sio_aucat_write(struct sio_hdl *, const void *, size_t); 58 static int sio_aucat_nfds(struct sio_hdl *); 59 static int sio_aucat_pollfd(struct sio_hdl *, struct pollfd *, int); 60 static int sio_aucat_revents(struct sio_hdl *, struct pollfd *); 61 static int sio_aucat_setvol(struct sio_hdl *, unsigned int); 62 static void sio_aucat_getvol(struct sio_hdl *); 63 64 static struct sio_ops sio_aucat_ops = { 65 sio_aucat_close, 66 sio_aucat_setpar, 67 sio_aucat_getpar, 68 sio_aucat_getcap, 69 sio_aucat_write, 70 sio_aucat_read, 71 sio_aucat_start, 72 sio_aucat_stop, 73 sio_aucat_flush, 74 sio_aucat_nfds, 75 sio_aucat_pollfd, 76 sio_aucat_revents, 77 sio_aucat_setvol, 78 sio_aucat_getvol 79 }; 80 81 /* 82 * execute the next message, return 0 if blocked 83 */ 84 static int 85 sio_aucat_runmsg(struct sio_aucat_hdl *hdl) 86 { 87 int delta; 88 unsigned int size, ctl; 89 90 if (!_aucat_rmsg(&hdl->aucat, &hdl->sio.eof)) 91 return 0; 92 switch (ntohl(hdl->aucat.rmsg.cmd)) { 93 case AMSG_DATA: 94 size = ntohl(hdl->aucat.rmsg.u.data.size); 95 if (size == 0 || size % hdl->rbpf) { 96 DPRINTF("sio_aucat_runmsg: bad data message\n"); 97 hdl->sio.eof = 1; 98 return 0; 99 } 100 DPRINTFN(3, "aucat: data(%d)\n", size); 101 return 1; 102 case AMSG_FLOWCTL: 103 delta = ntohl(hdl->aucat.rmsg.u.ts.delta); 104 hdl->aucat.maxwrite += delta * (int)hdl->wbpf; 105 DPRINTFN(3, "aucat: flowctl(%d), maxwrite = %d\n", 106 delta, hdl->aucat.maxwrite); 107 break; 108 case AMSG_MOVE: 109 delta = ntohl(hdl->aucat.rmsg.u.ts.delta); 110 hdl->delta += delta; 111 DPRINTFN(3, "aucat: move(%d), delta = %d, maxwrite = %d\n", 112 delta, hdl->delta, hdl->aucat.maxwrite); 113 if (hdl->delta >= 0) { 114 _sio_onmove_cb(&hdl->sio, hdl->delta); 115 hdl->delta = 0; 116 } 117 break; 118 case AMSG_SETVOL: 119 ctl = ntohl(hdl->aucat.rmsg.u.vol.ctl); 120 hdl->curvol = hdl->reqvol = ctl; 121 DPRINTFN(3, "aucat: setvol(%d)\n", ctl); 122 _sio_onvol_cb(&hdl->sio, ctl); 123 break; 124 case AMSG_STOP: 125 DPRINTFN(3, "aucat: stop()\n"); 126 hdl->pstate = PSTATE_INIT; 127 break; 128 default: 129 DPRINTF("sio_aucat_runmsg: unhandled message %u\n", 130 hdl->aucat.rmsg.cmd); 131 hdl->sio.eof = 1; 132 return 0; 133 } 134 hdl->aucat.rstate = RSTATE_MSG; 135 hdl->aucat.rtodo = sizeof(struct amsg); 136 return 1; 137 } 138 139 static int 140 sio_aucat_buildmsg(struct sio_aucat_hdl *hdl) 141 { 142 if (hdl->curvol != hdl->reqvol) { 143 hdl->aucat.wstate = WSTATE_MSG; 144 hdl->aucat.wtodo = sizeof(struct amsg); 145 hdl->aucat.wmsg.cmd = htonl(AMSG_SETVOL); 146 hdl->aucat.wmsg.u.vol.ctl = htonl(hdl->reqvol); 147 hdl->curvol = hdl->reqvol; 148 return _aucat_wmsg(&hdl->aucat, &hdl->sio.eof); 149 } 150 return 0; 151 } 152 153 struct sio_hdl * 154 _sio_aucat_open(const char *str, unsigned int mode, int nbio) 155 { 156 struct sio_aucat_hdl *hdl; 157 158 hdl = malloc(sizeof(struct sio_aucat_hdl)); 159 if (hdl == NULL) 160 return NULL; 161 if (!_aucat_open(&hdl->aucat, str, mode)) { 162 free(hdl); 163 return NULL; 164 } 165 _sio_create(&hdl->sio, &sio_aucat_ops, mode, nbio); 166 hdl->curvol = SIO_MAXVOL; 167 hdl->reqvol = SIO_MAXVOL; 168 hdl->pstate = PSTATE_INIT; 169 hdl->round = 0xdeadbeef; 170 hdl->walign = 0xdeadbeef; 171 return (struct sio_hdl *)hdl; 172 } 173 174 static void 175 sio_aucat_close(struct sio_hdl *sh) 176 { 177 struct sio_aucat_hdl *hdl = (struct sio_aucat_hdl *)sh; 178 179 if (!hdl->sio.eof && hdl->sio.started) 180 (void)sio_aucat_stop(&hdl->sio); 181 _aucat_close(&hdl->aucat, hdl->sio.eof); 182 free(hdl); 183 } 184 185 static int 186 sio_aucat_start(struct sio_hdl *sh) 187 { 188 struct sio_aucat_hdl *hdl = (struct sio_aucat_hdl *)sh; 189 190 hdl->wbpf = hdl->sio.par.bps * hdl->sio.par.pchan; 191 hdl->rbpf = hdl->sio.par.bps * hdl->sio.par.rchan; 192 hdl->aucat.maxwrite = 0; 193 hdl->round = hdl->sio.par.round; 194 hdl->delta = 0; 195 DPRINTFN(2, "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_drain(struct sio_hdl *sh, int drain) 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.wmsg.u.stop.drain = drain; 246 hdl->aucat.wtodo = sizeof(struct amsg); 247 if (!_aucat_wmsg(&hdl->aucat, &hdl->sio.eof)) 248 return 0; 249 250 /* 251 * wait for the STOP ACK 252 */ 253 while (hdl->pstate != PSTATE_INIT) { 254 switch (hdl->aucat.rstate) { 255 case RSTATE_MSG: 256 if (!sio_aucat_runmsg(hdl)) 257 return 0; 258 break; 259 case RSTATE_DATA: 260 if (!sio_aucat_read(&hdl->sio, zero, ZERO_MAX)) 261 return 0; 262 break; 263 } 264 } 265 return 1; 266 } 267 268 static int 269 sio_aucat_stop(struct sio_hdl *sh) 270 { 271 return sio_aucat_drain(sh, 1); 272 } 273 274 static int 275 sio_aucat_flush(struct sio_hdl *sh) 276 { 277 return sio_aucat_drain(sh, 0); 278 } 279 280 static int 281 sio_aucat_setpar(struct sio_hdl *sh, struct sio_par *par) 282 { 283 struct sio_aucat_hdl *hdl = (struct sio_aucat_hdl *)sh; 284 285 AMSG_INIT(&hdl->aucat.wmsg); 286 hdl->aucat.wmsg.cmd = htonl(AMSG_SETPAR); 287 hdl->aucat.wmsg.u.par.bits = par->bits; 288 hdl->aucat.wmsg.u.par.bps = par->bps; 289 hdl->aucat.wmsg.u.par.sig = par->sig; 290 hdl->aucat.wmsg.u.par.le = par->le; 291 hdl->aucat.wmsg.u.par.msb = par->msb; 292 hdl->aucat.wmsg.u.par.rate = htonl(par->rate); 293 hdl->aucat.wmsg.u.par.appbufsz = htonl(par->appbufsz); 294 hdl->aucat.wmsg.u.par.xrun = par->xrun; 295 if (hdl->sio.mode & SIO_REC) 296 hdl->aucat.wmsg.u.par.rchan = htons(par->rchan); 297 if (hdl->sio.mode & SIO_PLAY) 298 hdl->aucat.wmsg.u.par.pchan = htons(par->pchan); 299 hdl->aucat.wtodo = sizeof(struct amsg); 300 if (!_aucat_wmsg(&hdl->aucat, &hdl->sio.eof)) 301 return 0; 302 return 1; 303 } 304 305 static int 306 sio_aucat_getpar(struct sio_hdl *sh, struct sio_par *par) 307 { 308 struct sio_aucat_hdl *hdl = (struct sio_aucat_hdl *)sh; 309 310 AMSG_INIT(&hdl->aucat.wmsg); 311 hdl->aucat.wmsg.cmd = htonl(AMSG_GETPAR); 312 hdl->aucat.wtodo = sizeof(struct amsg); 313 if (!_aucat_wmsg(&hdl->aucat, &hdl->sio.eof)) 314 return 0; 315 hdl->aucat.rtodo = sizeof(struct amsg); 316 if (!_aucat_rmsg(&hdl->aucat, &hdl->sio.eof)) 317 return 0; 318 if (ntohl(hdl->aucat.rmsg.cmd) != AMSG_GETPAR) { 319 DPRINTF("sio_aucat_getpar: protocol err\n"); 320 hdl->sio.eof = 1; 321 return 0; 322 } 323 par->bits = hdl->aucat.rmsg.u.par.bits; 324 par->bps = hdl->aucat.rmsg.u.par.bps; 325 par->sig = hdl->aucat.rmsg.u.par.sig; 326 par->le = hdl->aucat.rmsg.u.par.le; 327 par->msb = hdl->aucat.rmsg.u.par.msb; 328 par->rate = ntohl(hdl->aucat.rmsg.u.par.rate); 329 par->bufsz = ntohl(hdl->aucat.rmsg.u.par.bufsz); 330 par->appbufsz = ntohl(hdl->aucat.rmsg.u.par.appbufsz); 331 par->xrun = hdl->aucat.rmsg.u.par.xrun; 332 par->round = ntohl(hdl->aucat.rmsg.u.par.round); 333 if (hdl->sio.mode & SIO_PLAY) 334 par->pchan = ntohs(hdl->aucat.rmsg.u.par.pchan); 335 if (hdl->sio.mode & SIO_REC) 336 par->rchan = ntohs(hdl->aucat.rmsg.u.par.rchan); 337 return 1; 338 } 339 340 static int 341 sio_aucat_getcap(struct sio_hdl *sh, struct sio_cap *cap) 342 { 343 unsigned int i, bps, le, sig, chan, rindex, rmult; 344 static unsigned int rates[] = { 8000, 11025, 12000 }; 345 346 bps = 1; 347 sig = le = 0; 348 cap->confs[0].enc = 0; 349 for (i = 0; i < SIO_NENC; i++) { 350 if (bps > 4) 351 break; 352 cap->confs[0].enc |= 1 << i; 353 cap->enc[i].bits = bps == 4 ? 24 : bps * 8; 354 cap->enc[i].bps = bps; 355 cap->enc[i].sig = sig ^ 1; 356 cap->enc[i].le = bps > 1 ? le : SIO_LE_NATIVE; 357 cap->enc[i].msb = 1; 358 le++; 359 if (le > 1 || bps == 1) { 360 le = 0; 361 sig++; 362 } 363 if (sig > 1 || (le == 0 && bps > 1)) { 364 sig = 0; 365 bps++; 366 } 367 } 368 chan = 1; 369 cap->confs[0].rchan = 0; 370 for (i = 0; i < SIO_NCHAN; i++) { 371 if (chan > 16) 372 break; 373 cap->confs[0].rchan |= 1 << i; 374 cap->rchan[i] = chan; 375 if (chan >= 12) { 376 chan += 4; 377 } else if (chan >= 2) { 378 chan += 2; 379 } else 380 chan++; 381 } 382 chan = 1; 383 cap->confs[0].pchan = 0; 384 for (i = 0; i < SIO_NCHAN; i++) { 385 if (chan > 16) 386 break; 387 cap->confs[0].pchan |= 1 << i; 388 cap->pchan[i] = chan; 389 if (chan >= 12) { 390 chan += 4; 391 } else if (chan >= 2) { 392 chan += 2; 393 } else 394 chan++; 395 } 396 rindex = 0; 397 rmult = 1; 398 cap->confs[0].rate = 0; 399 for (i = 0; i < SIO_NRATE; i++) { 400 if (rmult >= 32) 401 break; 402 cap->rate[i] = rates[rindex] * rmult; 403 cap->confs[0].rate |= 1 << i; 404 rindex++; 405 if (rindex == sizeof(rates) / sizeof(unsigned int)) { 406 rindex = 0; 407 rmult *= 2; 408 } 409 } 410 cap->nconf = 1; 411 return 1; 412 } 413 414 static size_t 415 sio_aucat_read(struct sio_hdl *sh, void *buf, size_t len) 416 { 417 struct sio_aucat_hdl *hdl = (struct sio_aucat_hdl *)sh; 418 419 while (hdl->aucat.rstate == RSTATE_MSG) { 420 if (!sio_aucat_runmsg(hdl)) 421 return 0; 422 } 423 return _aucat_rdata(&hdl->aucat, buf, len, &hdl->sio.eof); 424 } 425 426 static size_t 427 sio_aucat_write(struct sio_hdl *sh, const void *buf, size_t len) 428 { 429 struct sio_aucat_hdl *hdl = (struct sio_aucat_hdl *)sh; 430 size_t n; 431 432 while (hdl->aucat.wstate == WSTATE_IDLE) { 433 if (!sio_aucat_buildmsg(hdl)) 434 break; 435 } 436 if (len <= 0 || hdl->aucat.maxwrite <= 0) 437 return 0; 438 if (len > hdl->aucat.maxwrite) 439 len = hdl->aucat.maxwrite; 440 if (len > hdl->walign) 441 len = hdl->walign; 442 n = _aucat_wdata(&hdl->aucat, buf, len, hdl->wbpf, &hdl->sio.eof); 443 hdl->aucat.maxwrite -= n; 444 hdl->walign -= n; 445 if (hdl->walign == 0) 446 hdl->walign = hdl->round * hdl->wbpf; 447 return n; 448 } 449 450 static int 451 sio_aucat_nfds(struct sio_hdl *hdl) 452 { 453 return 1; 454 } 455 456 static int 457 sio_aucat_pollfd(struct sio_hdl *sh, struct pollfd *pfd, int events) 458 { 459 struct sio_aucat_hdl *hdl = (struct sio_aucat_hdl *)sh; 460 461 hdl->events = events; 462 if (hdl->aucat.maxwrite <= 0) 463 events &= ~POLLOUT; 464 return _aucat_pollfd(&hdl->aucat, pfd, events); 465 } 466 467 static int 468 sio_aucat_revents(struct sio_hdl *sh, struct pollfd *pfd) 469 { 470 struct sio_aucat_hdl *hdl = (struct sio_aucat_hdl *)sh; 471 int revents = pfd->revents; 472 473 if (revents & POLLIN) { 474 while (hdl->aucat.rstate == RSTATE_MSG) { 475 if (!sio_aucat_runmsg(hdl)) 476 break; 477 } 478 if (hdl->aucat.rstate != RSTATE_DATA) 479 revents &= ~POLLIN; 480 } 481 if (revents & POLLOUT) { 482 if (hdl->aucat.maxwrite <= 0) 483 revents &= ~POLLOUT; 484 } 485 if (hdl->sio.eof) 486 return POLLHUP; 487 DPRINTFN(3, "sio_aucat_revents: %x\n", revents & hdl->events); 488 return revents & (hdl->events | POLLHUP); 489 } 490 491 static int 492 sio_aucat_setvol(struct sio_hdl *sh, unsigned int vol) 493 { 494 struct sio_aucat_hdl *hdl = (struct sio_aucat_hdl *)sh; 495 496 hdl->reqvol = vol; 497 return 1; 498 } 499 500 static void 501 sio_aucat_getvol(struct sio_hdl *sh) 502 { 503 struct sio_aucat_hdl *hdl = (struct sio_aucat_hdl *)sh; 504 505 _sio_onvol_cb(&hdl->sio, hdl->reqvol); 506 return; 507 } 508