1 /* $OpenBSD: siofile.c,v 1.12 2016/05/25 10:24:24 ratchov Exp $ */ 2 /* 3 * Copyright (c) 2008-2012 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 #include <sys/time.h> 18 #include <sys/types.h> 19 20 #include <poll.h> 21 #include <sndio.h> 22 #include <stdio.h> 23 #include <stdlib.h> 24 #include <string.h> 25 26 #include "abuf.h" 27 #include "defs.h" 28 #include "dev.h" 29 #include "dsp.h" 30 #include "fdpass.h" 31 #include "file.h" 32 #include "siofile.h" 33 #include "utils.h" 34 35 #define WATCHDOG_USEC 4000000 /* 4 seconds */ 36 37 void dev_sio_onmove(void *, int); 38 void dev_sio_timeout(void *); 39 int dev_sio_pollfd(void *, struct pollfd *); 40 int dev_sio_revents(void *, struct pollfd *); 41 void dev_sio_run(void *); 42 void dev_sio_hup(void *); 43 44 struct fileops dev_sio_ops = { 45 "sio", 46 dev_sio_pollfd, 47 dev_sio_revents, 48 dev_sio_run, 49 dev_sio_run, 50 dev_sio_hup 51 }; 52 53 void 54 dev_sio_onmove(void *arg, int delta) 55 { 56 struct dev *d = arg; 57 58 #ifdef DEBUG 59 if (log_level >= 4) { 60 dev_log(d); 61 log_puts(": tick, delta = "); 62 log_puti(delta); 63 log_puts("\n"); 64 } 65 d->sio.sum_utime += file_utime - d->sio.utime; 66 d->sio.sum_wtime += file_wtime - d->sio.wtime; 67 d->sio.wtime = file_wtime; 68 d->sio.utime = file_utime; 69 if (d->mode & MODE_PLAY) 70 d->sio.pused -= delta; 71 if (d->mode & MODE_REC) 72 d->sio.rused += delta; 73 #endif 74 dev_onmove(d, delta); 75 } 76 77 void 78 dev_sio_timeout(void *arg) 79 { 80 struct dev *d = arg; 81 82 dev_log(d); 83 log_puts(": watchdog timeout\n"); 84 dev_close(d); 85 } 86 87 /* 88 * open the device. 89 */ 90 int 91 dev_sio_open(struct dev *d) 92 { 93 struct sio_par par; 94 unsigned int mode = d->mode & (MODE_PLAY | MODE_REC); 95 96 d->sio.hdl = fdpass_sio_open(d->num, mode); 97 if (d->sio.hdl == NULL) { 98 if (mode != (SIO_PLAY | SIO_REC)) 99 return 0; 100 d->sio.hdl = fdpass_sio_open(d->num, SIO_PLAY); 101 if (d->sio.hdl != NULL) 102 mode = SIO_PLAY; 103 else { 104 d->sio.hdl = fdpass_sio_open(d->num, SIO_REC); 105 if (d->sio.hdl != NULL) 106 mode = SIO_REC; 107 else 108 return 0; 109 } 110 if (log_level >= 1) { 111 log_puts("warning, device opened in "); 112 log_puts(mode == SIO_PLAY ? "play-only" : "rec-only"); 113 log_puts(" mode\n"); 114 } 115 } 116 sio_initpar(&par); 117 par.bits = d->par.bits; 118 par.bps = d->par.bps; 119 par.sig = d->par.sig; 120 par.le = d->par.le; 121 par.msb = d->par.msb; 122 if (mode & SIO_PLAY) 123 par.pchan = d->pchan; 124 if (mode & SIO_REC) 125 par.rchan = d->rchan; 126 if (d->bufsz) 127 par.appbufsz = d->bufsz; 128 if (d->round) 129 par.round = d->round; 130 if (d->rate) 131 par.rate = d->rate; 132 if (!sio_setpar(d->sio.hdl, &par)) 133 goto bad_close; 134 if (!sio_getpar(d->sio.hdl, &par)) 135 goto bad_close; 136 137 #ifdef DEBUG 138 /* 139 * We support any parameters combination exposed by the kernel, 140 * and we have no other choice than trusting the kernel for 141 * returning correct parameters. But let's check parameters 142 * early and nicely report kernel bugs rather than crashing 143 * later in memset(), malloc() or alike. 144 */ 145 146 if (par.bits > BITS_MAX) { 147 log_puts(d->path); 148 log_puts(": "); 149 log_putu(par.bits); 150 log_puts(": unsupported number of bits\n"); 151 goto bad_close; 152 } 153 if (par.bps > SIO_BPS(BITS_MAX)) { 154 log_puts(d->path); 155 log_puts(": "); 156 log_putu(par.bits); 157 log_puts(": unsupported sample size\n"); 158 goto bad_close; 159 } 160 if ((mode & SIO_PLAY) && par.pchan > NCHAN_MAX) { 161 log_puts(d->path); 162 log_puts(": "); 163 log_putu(par.pchan); 164 log_puts(": unsupported number of play channels\n"); 165 goto bad_close; 166 } 167 if ((mode & SIO_REC) && par.rchan > NCHAN_MAX) { 168 log_puts(d->path); 169 log_puts(": "); 170 log_putu(par.rchan); 171 log_puts(": unsupported number of rec channels\n"); 172 goto bad_close; 173 } 174 if (par.bufsz == 0 || par.bufsz > RATE_MAX) { 175 log_puts(d->path); 176 log_puts(": "); 177 log_putu(par.bufsz); 178 log_puts(": unsupported buffer size\n"); 179 goto bad_close; 180 } 181 if (par.round == 0 || par.round > par.bufsz || 182 par.bufsz % par.round != 0) { 183 log_puts(d->path); 184 log_puts(": "); 185 log_putu(par.round); 186 log_puts(": unsupported block size\n"); 187 goto bad_close; 188 } 189 if (par.rate == 0 || par.rate > RATE_MAX) { 190 log_puts(d->path); 191 log_puts(": "); 192 log_putu(par.rate); 193 log_puts(": unsupported rate\n"); 194 goto bad_close; 195 } 196 #endif 197 198 d->par.bits = par.bits; 199 d->par.bps = par.bps; 200 d->par.sig = par.sig; 201 d->par.le = par.le; 202 d->par.msb = par.msb; 203 if (mode & SIO_PLAY) 204 d->pchan = par.pchan; 205 if (mode & SIO_REC) 206 d->rchan = par.rchan; 207 d->bufsz = par.bufsz; 208 d->round = par.round; 209 d->rate = par.rate; 210 if (!(mode & MODE_PLAY)) 211 d->mode &= ~(MODE_PLAY | MODE_MON); 212 if (!(mode & MODE_REC)) 213 d->mode &= ~MODE_REC; 214 sio_onmove(d->sio.hdl, dev_sio_onmove, d); 215 d->sio.file = file_new(&dev_sio_ops, d, d->path, sio_nfds(d->sio.hdl)); 216 timo_set(&d->sio.watchdog, dev_sio_timeout, d); 217 return 1; 218 bad_close: 219 sio_close(d->sio.hdl); 220 return 0; 221 } 222 223 void 224 dev_sio_close(struct dev *d) 225 { 226 #ifdef DEBUG 227 if (log_level >= 3) { 228 dev_log(d); 229 log_puts(": closed\n"); 230 } 231 #endif 232 timo_del(&d->sio.watchdog); 233 file_del(d->sio.file); 234 sio_close(d->sio.hdl); 235 } 236 237 void 238 dev_sio_start(struct dev *d) 239 { 240 if (!sio_start(d->sio.hdl)) { 241 if (log_level >= 1) { 242 dev_log(d); 243 log_puts(": failed to start device\n"); 244 } 245 return; 246 } 247 if (d->mode & MODE_PLAY) { 248 d->sio.cstate = DEV_SIO_CYCLE; 249 d->sio.todo = 0; 250 } else { 251 d->sio.cstate = DEV_SIO_READ; 252 d->sio.todo = d->round * d->rchan * d->par.bps; 253 } 254 #ifdef DEBUG 255 d->sio.pused = 0; 256 d->sio.rused = 0; 257 d->sio.sum_utime = 0; 258 d->sio.sum_wtime = 0; 259 d->sio.wtime = file_wtime; 260 d->sio.utime = file_utime; 261 if (log_level >= 3) { 262 dev_log(d); 263 log_puts(": started\n"); 264 } 265 #endif 266 timo_add(&d->sio.watchdog, WATCHDOG_USEC); 267 } 268 269 void 270 dev_sio_stop(struct dev *d) 271 { 272 if (!sio_eof(d->sio.hdl) && !sio_stop(d->sio.hdl)) { 273 if (log_level >= 1) { 274 dev_log(d); 275 log_puts(": failed to stop device\n"); 276 } 277 return; 278 } 279 #ifdef DEBUG 280 if (log_level >= 3) { 281 dev_log(d); 282 log_puts(": stopped, load avg = "); 283 log_puti(d->sio.sum_utime / 1000); 284 log_puts(" / "); 285 log_puti(d->sio.sum_wtime / 1000); 286 log_puts("\n"); 287 } 288 #endif 289 timo_del(&d->sio.watchdog); 290 } 291 292 int 293 dev_sio_pollfd(void *arg, struct pollfd *pfd) 294 { 295 struct dev *d = arg; 296 int events; 297 298 events = (d->sio.cstate == DEV_SIO_READ) ? POLLIN : POLLOUT; 299 return sio_pollfd(d->sio.hdl, pfd, events); 300 } 301 302 int 303 dev_sio_revents(void *arg, struct pollfd *pfd) 304 { 305 struct dev *d = arg; 306 int events; 307 308 events = sio_revents(d->sio.hdl, pfd); 309 #ifdef DEBUG 310 d->sio.events = events; 311 #endif 312 return events; 313 } 314 315 void 316 dev_sio_run(void *arg) 317 { 318 struct dev *d = arg; 319 unsigned char *data, *base; 320 unsigned int n; 321 322 /* 323 * sio_read() and sio_write() would block at the end of the 324 * cycle so we *must* return and restart poll()'ing. Otherwise 325 * we may trigger dev_cycle() which would make all clients 326 * underrun (ex, on a play-only device) 327 */ 328 for (;;) { 329 if (d->pstate != DEV_RUN) 330 return; 331 switch (d->sio.cstate) { 332 case DEV_SIO_READ: 333 #ifdef DEBUG 334 if (!(d->sio.events & POLLIN)) { 335 dev_log(d); 336 log_puts(": recording, but POLLIN not set\n"); 337 panic(); 338 } 339 if (d->sio.todo == 0) { 340 dev_log(d); 341 log_puts(": can't read data\n"); 342 panic(); 343 } 344 if (d->prime > 0) { 345 dev_log(d); 346 log_puts(": unexpected data\n"); 347 panic(); 348 } 349 #endif 350 base = d->decbuf ? d->decbuf : (unsigned char *)d->rbuf; 351 data = base + 352 d->rchan * d->round * d->par.bps - 353 d->sio.todo; 354 n = sio_read(d->sio.hdl, data, d->sio.todo); 355 d->sio.todo -= n; 356 #ifdef DEBUG 357 if (log_level >= 4) { 358 dev_log(d); 359 log_puts(": read "); 360 log_putu(n); 361 log_puts(": bytes, todo "); 362 log_putu(d->sio.todo); 363 log_puts("/"); 364 log_putu(d->round * d->rchan * d->par.bps); 365 log_puts("\n"); 366 } 367 #endif 368 if (d->sio.todo > 0) 369 return; 370 #ifdef DEBUG 371 d->sio.rused -= d->round; 372 if (log_level >= 2) { 373 if (d->sio.rused >= d->round) { 374 dev_log(d); 375 log_puts(": rec hw xrun, rused = "); 376 log_puti(d->sio.rused); 377 log_puts("/"); 378 log_puti(d->bufsz); 379 log_puts("\n"); 380 } 381 if (d->sio.rused < 0 || 382 d->sio.rused >= d->bufsz) { 383 dev_log(d); 384 log_puts(": out of bounds rused = "); 385 log_puti(d->sio.rused); 386 log_puts("/"); 387 log_puti(d->bufsz); 388 log_puts("\n"); 389 } 390 } 391 #endif 392 d->sio.cstate = DEV_SIO_CYCLE; 393 break; 394 case DEV_SIO_CYCLE: 395 timo_del(&d->sio.watchdog); 396 timo_add(&d->sio.watchdog, WATCHDOG_USEC); 397 398 #ifdef DEBUG 399 /* 400 * check that we're called at cycle boundary: 401 * either after a recorded block, or when POLLOUT is 402 * raised 403 */ 404 if (!((d->mode & MODE_REC) && d->prime == 0) && 405 !(d->sio.events & POLLOUT)) { 406 dev_log(d); 407 log_puts(": cycle not at block boundary\n"); 408 panic(); 409 } 410 #endif 411 dev_cycle(d); 412 if (d->mode & MODE_PLAY) { 413 d->sio.cstate = DEV_SIO_WRITE; 414 d->sio.todo = d->round * d->pchan * d->par.bps; 415 break; 416 } else { 417 d->sio.cstate = DEV_SIO_READ; 418 d->sio.todo = d->round * d->rchan * d->par.bps; 419 return; 420 } 421 case DEV_SIO_WRITE: 422 #ifdef DEBUG 423 if (d->sio.todo == 0) { 424 dev_log(d); 425 log_puts(": can't write data\n"); 426 panic(); 427 } 428 #endif 429 base = d->encbuf ? d->encbuf : (unsigned char *)DEV_PBUF(d); 430 data = base + 431 d->pchan * d->round * d->par.bps - 432 d->sio.todo; 433 n = sio_write(d->sio.hdl, data, d->sio.todo); 434 d->sio.todo -= n; 435 #ifdef DEBUG 436 if (log_level >= 4) { 437 dev_log(d); 438 log_puts(": wrote "); 439 log_putu(n); 440 log_puts(" bytes, todo "); 441 log_putu(d->sio.todo); 442 log_puts("/"); 443 log_putu(d->round * d->pchan * d->par.bps); 444 log_puts("\n"); 445 } 446 #endif 447 if (d->sio.todo > 0) 448 return; 449 #ifdef DEBUG 450 d->sio.pused += d->round; 451 if (log_level >= 2) { 452 if (d->prime == 0 && 453 d->sio.pused <= d->bufsz - d->round) { 454 dev_log(d); 455 log_puts(": play hw xrun, pused = "); 456 log_puti(d->sio.pused); 457 log_puts("/"); 458 log_puti(d->bufsz); 459 log_puts("\n"); 460 } 461 if (d->sio.pused < 0 || 462 d->sio.pused > d->bufsz) { 463 /* device driver or libsndio bug */ 464 dev_log(d); 465 log_puts(": out of bounds pused = "); 466 log_puti(d->sio.pused); 467 log_puts("/"); 468 log_puti(d->bufsz); 469 log_puts("\n"); 470 } 471 } 472 #endif 473 d->poffs += d->round; 474 if (d->poffs == d->psize) 475 d->poffs = 0; 476 if ((d->mode & MODE_REC) && d->prime == 0) { 477 d->sio.cstate = DEV_SIO_READ; 478 d->sio.todo = d->round * d->rchan * d->par.bps; 479 } else 480 d->sio.cstate = DEV_SIO_CYCLE; 481 return; 482 } 483 } 484 } 485 486 void 487 dev_sio_hup(void *arg) 488 { 489 struct dev *d = arg; 490 491 #ifdef DEBUG 492 if (log_level >= 2) { 493 dev_log(d); 494 log_puts(": disconnected\n"); 495 } 496 #endif 497 dev_close(d); 498 } 499