1 /* $OpenBSD: sio_sun.c,v 1.4 2011/11/15 08:05:22 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 * TODO: 19 * 20 * remove filling code from sio_sun_write() and create sio_sun_fill() 21 * 22 * allow block size to be set 23 * 24 * call hdl->cb_pos() from sio_sun_read() and sio_sun_write(), or better: 25 * implement generic blocking sio_read() and sio_write() with poll(2) 26 * and use non-blocking sio_ops only 27 */ 28 29 #include <sys/types.h> 30 #include <sys/ioctl.h> 31 #include <sys/audioio.h> 32 #include <sys/stat.h> 33 34 #include <errno.h> 35 #include <fcntl.h> 36 #include <limits.h> 37 #include <poll.h> 38 #include <stdio.h> 39 #include <stdlib.h> 40 #include <string.h> 41 #include <unistd.h> 42 43 #include "debug.h" 44 #include "sio_priv.h" 45 46 struct sio_sun_hdl { 47 struct sio_hdl sio; 48 int fd; 49 int filling; 50 unsigned ibpf, obpf; /* bytes per frame */ 51 unsigned ibytes, obytes; /* bytes the hw transfered */ 52 unsigned ierr, oerr; /* frames the hw dropped */ 53 int offset; /* frames play is ahead of record */ 54 int idelta, odelta; /* position reported to client */ 55 int mix_fd, mix_index; /* /dev/mixerN stuff */ 56 }; 57 58 static void sio_sun_close(struct sio_hdl *); 59 static int sio_sun_start(struct sio_hdl *); 60 static int sio_sun_stop(struct sio_hdl *); 61 static int sio_sun_setpar(struct sio_hdl *, struct sio_par *); 62 static int sio_sun_getpar(struct sio_hdl *, struct sio_par *); 63 static int sio_sun_getcap(struct sio_hdl *, struct sio_cap *); 64 static size_t sio_sun_read(struct sio_hdl *, void *, size_t); 65 static size_t sio_sun_write(struct sio_hdl *, const void *, size_t); 66 static int sio_sun_nfds(struct sio_hdl *); 67 static int sio_sun_pollfd(struct sio_hdl *, struct pollfd *, int); 68 static int sio_sun_revents(struct sio_hdl *, struct pollfd *); 69 70 static struct sio_ops sio_sun_ops = { 71 sio_sun_close, 72 sio_sun_setpar, 73 sio_sun_getpar, 74 sio_sun_getcap, 75 sio_sun_write, 76 sio_sun_read, 77 sio_sun_start, 78 sio_sun_stop, 79 sio_sun_nfds, 80 sio_sun_pollfd, 81 sio_sun_revents, 82 NULL, /* setvol */ 83 NULL, /* getvol */ 84 }; 85 86 /* 87 * convert sun encoding to sio_par encoding 88 */ 89 static int 90 sio_sun_infotoenc(struct sio_sun_hdl *hdl, struct audio_prinfo *ai, struct sio_par *par) 91 { 92 par->msb = ai->msb; 93 par->bits = ai->precision; 94 par->bps = ai->bps; 95 switch (ai->encoding) { 96 case AUDIO_ENCODING_SLINEAR_LE: 97 par->le = 1; 98 par->sig = 1; 99 break; 100 case AUDIO_ENCODING_SLINEAR_BE: 101 par->le = 0; 102 par->sig = 1; 103 break; 104 case AUDIO_ENCODING_ULINEAR_LE: 105 par->le = 1; 106 par->sig = 0; 107 break; 108 case AUDIO_ENCODING_ULINEAR_BE: 109 par->le = 0; 110 par->sig = 0; 111 break; 112 case AUDIO_ENCODING_SLINEAR: 113 par->le = SIO_LE_NATIVE; 114 par->sig = 1; 115 break; 116 case AUDIO_ENCODING_ULINEAR: 117 par->le = SIO_LE_NATIVE; 118 par->sig = 0; 119 break; 120 default: 121 DPRINTF("sio_sun_infotoenc: unsupported encoding\n"); 122 hdl->sio.eof = 1; 123 return 0; 124 } 125 return 1; 126 } 127 128 /* 129 * convert sio_par encoding to sun encoding 130 */ 131 static void 132 sio_sun_enctoinfo(struct sio_sun_hdl *hdl, unsigned *renc, struct sio_par *par) 133 { 134 if (par->le == ~0U && par->sig == ~0U) { 135 *renc = ~0U; 136 } else if (par->le == ~0U || par->sig == ~0U) { 137 *renc = AUDIO_ENCODING_SLINEAR; 138 } else if (par->le && par->sig) { 139 *renc = AUDIO_ENCODING_SLINEAR_LE; 140 } else if (!par->le && par->sig) { 141 *renc = AUDIO_ENCODING_SLINEAR_BE; 142 } else if (par->le && !par->sig) { 143 *renc = AUDIO_ENCODING_ULINEAR_LE; 144 } else { 145 *renc = AUDIO_ENCODING_ULINEAR_BE; 146 } 147 } 148 149 /* 150 * try to set the device to the given parameters and check that the 151 * device can use them; return 1 on success, 0 on failure or error 152 */ 153 static int 154 sio_sun_tryinfo(struct sio_sun_hdl *hdl, struct sio_enc *enc, 155 unsigned pchan, unsigned rchan, unsigned rate) 156 { 157 struct audio_info aui; 158 struct audio_prinfo *pr; 159 160 pr = (hdl->sio.mode & SIO_PLAY) ? &aui.play : &aui.record; 161 162 AUDIO_INITINFO(&aui); 163 if (enc) { 164 if (enc->le && enc->sig) { 165 pr->encoding = AUDIO_ENCODING_SLINEAR_LE; 166 } else if (!enc->le && enc->sig) { 167 pr->encoding = AUDIO_ENCODING_SLINEAR_BE; 168 } else if (enc->le && !enc->sig) { 169 pr->encoding = AUDIO_ENCODING_ULINEAR_LE; 170 } else { 171 pr->encoding = AUDIO_ENCODING_ULINEAR_BE; 172 } 173 pr->precision = enc->bits; 174 } 175 if (rate) 176 pr->sample_rate = rate; 177 if ((hdl->sio.mode & (SIO_PLAY | SIO_REC)) == (SIO_PLAY | SIO_REC)) 178 aui.record = aui.play; 179 if (pchan && (hdl->sio.mode & SIO_PLAY)) 180 aui.play.channels = pchan; 181 if (rchan && (hdl->sio.mode & SIO_REC)) 182 aui.record.channels = rchan; 183 if (ioctl(hdl->fd, AUDIO_SETINFO, &aui) < 0) { 184 if (errno == EINVAL) 185 return 0; 186 DPERROR("sio_sun_tryinfo: setinfo"); 187 hdl->sio.eof = 1; 188 return 0; 189 } 190 if (ioctl(hdl->fd, AUDIO_GETINFO, &aui) < 0) { 191 DPERROR("sio_sun_tryinfo: getinfo"); 192 hdl->sio.eof = 1; 193 return 0; 194 } 195 if (pchan && aui.play.channels != pchan) 196 return 0; 197 if (rchan && aui.record.channels != rchan) 198 return 0; 199 if (rate) { 200 if ((hdl->sio.mode & SIO_PLAY) && 201 (aui.play.sample_rate != rate)) 202 return 0; 203 if ((hdl->sio.mode & SIO_REC) && 204 (aui.record.sample_rate != rate)) 205 return 0; 206 } 207 return 1; 208 } 209 210 /* 211 * guess device capabilities 212 */ 213 static int 214 sio_sun_getcap(struct sio_hdl *sh, struct sio_cap *cap) 215 { 216 #define NCHANS (sizeof(chans) / sizeof(chans[0])) 217 #define NRATES (sizeof(rates) / sizeof(rates[0])) 218 static unsigned chans[] = { 219 1, 2, 4, 6, 8, 10, 12 220 }; 221 static unsigned rates[] = { 222 8000, 11025, 12000, 16000, 22050, 24000, 223 32000, 44100, 48000, 64000, 88200, 96000 224 }; 225 struct sio_sun_hdl *hdl = (struct sio_sun_hdl *)sh; 226 struct sio_par savepar; 227 struct audio_encoding ae; 228 unsigned nenc = 0, nconf = 0; 229 unsigned enc_map = 0, rchan_map = 0, pchan_map = 0, rate_map; 230 unsigned i, j, conf; 231 232 if (!sio_sun_getpar(&hdl->sio, &savepar)) 233 return 0; 234 235 /* 236 * fill encoding list 237 */ 238 for (ae.index = 0; nenc < SIO_NENC; ae.index++) { 239 if (ioctl(hdl->fd, AUDIO_GETENC, &ae) < 0) { 240 if (errno == EINVAL) 241 break; 242 DPERROR("sio_sun_getcap: getenc"); 243 hdl->sio.eof = 1; 244 return 0; 245 } 246 if (ae.flags & AUDIO_ENCODINGFLAG_EMULATED) 247 continue; 248 if (ae.encoding == AUDIO_ENCODING_SLINEAR_LE) { 249 cap->enc[nenc].le = 1; 250 cap->enc[nenc].sig = 1; 251 } else if (ae.encoding == AUDIO_ENCODING_SLINEAR_BE) { 252 cap->enc[nenc].le = 0; 253 cap->enc[nenc].sig = 1; 254 } else if (ae.encoding == AUDIO_ENCODING_ULINEAR_LE) { 255 cap->enc[nenc].le = 1; 256 cap->enc[nenc].sig = 0; 257 } else if (ae.encoding == AUDIO_ENCODING_ULINEAR_BE) { 258 cap->enc[nenc].le = 0; 259 cap->enc[nenc].sig = 0; 260 } else if (ae.encoding == AUDIO_ENCODING_SLINEAR) { 261 cap->enc[nenc].le = SIO_LE_NATIVE; 262 cap->enc[nenc].sig = 1; 263 } else if (ae.encoding == AUDIO_ENCODING_ULINEAR) { 264 cap->enc[nenc].le = SIO_LE_NATIVE; 265 cap->enc[nenc].sig = 0; 266 } else { 267 /* unsipported encoding */ 268 continue; 269 } 270 cap->enc[nenc].bits = ae.precision; 271 cap->enc[nenc].bps = ae.bps; 272 cap->enc[nenc].msb = ae.msb; 273 enc_map |= (1 << nenc); 274 nenc++; 275 } 276 277 /* 278 * fill channels 279 * 280 * for now we're lucky: all kernel devices assume that the 281 * number of channels and the encoding are independent so we can 282 * use the current encoding and try various channels. 283 */ 284 if (hdl->sio.mode & SIO_PLAY) { 285 memcpy(&cap->pchan, chans, NCHANS * sizeof(unsigned)); 286 for (i = 0; i < NCHANS; i++) { 287 if (sio_sun_tryinfo(hdl, NULL, chans[i], 0, 0)) 288 pchan_map |= (1 << i); 289 } 290 } 291 if (hdl->sio.mode & SIO_REC) { 292 memcpy(&cap->rchan, chans, NCHANS * sizeof(unsigned)); 293 for (i = 0; i < NCHANS; i++) { 294 if (sio_sun_tryinfo(hdl, NULL, 0, chans[i], 0)) 295 rchan_map |= (1 << i); 296 } 297 } 298 299 /* 300 * fill rates 301 * 302 * rates are not independent from other parameters (eg. on 303 * uaudio devices), so certain rates may not be allowed with 304 * certain encodings. We have to check rates for all encodings 305 */ 306 memcpy(&cap->rate, rates, NRATES * sizeof(unsigned)); 307 for (j = 0; j < nenc; j++) { 308 rate_map = 0; 309 for (i = 0; i < NRATES; i++) { 310 if (sio_sun_tryinfo(hdl, &cap->enc[j], 0, 0, rates[i])) 311 rate_map |= (1 << i); 312 } 313 for (conf = 0; conf < nconf; conf++) { 314 if (cap->confs[conf].rate == rate_map) { 315 cap->confs[conf].enc |= (1 << j); 316 break; 317 } 318 } 319 if (conf == nconf) { 320 if (nconf == SIO_NCONF) 321 break; 322 cap->confs[nconf].enc = (1 << j); 323 cap->confs[nconf].pchan = pchan_map; 324 cap->confs[nconf].rchan = rchan_map; 325 cap->confs[nconf].rate = rate_map; 326 nconf++; 327 } 328 } 329 cap->nconf = nconf; 330 if (!sio_sun_setpar(&hdl->sio, &savepar)) 331 return 0; 332 return 1; 333 #undef NCHANS 334 #undef NRATES 335 } 336 337 struct sio_hdl * 338 sio_sun_open(const char *str, unsigned mode, int nbio) 339 { 340 int fd, flags, fullduplex; 341 struct audio_info aui; 342 struct sio_sun_hdl *hdl; 343 struct sio_par par; 344 char path[PATH_MAX]; 345 346 switch (*str) { 347 case '/': 348 case ':': /* XXX: for backward compat */ 349 str++; 350 break; 351 default: 352 DPRINTF("sio_sun_open: %s: '/<devnum>' expected\n", str); 353 return NULL; 354 } 355 hdl = malloc(sizeof(struct sio_sun_hdl)); 356 if (hdl == NULL) 357 return NULL; 358 sio_create(&hdl->sio, &sio_sun_ops, mode, nbio); 359 360 snprintf(path, sizeof(path), "/dev/audio%s", str); 361 if (mode == (SIO_PLAY | SIO_REC)) 362 flags = O_RDWR; 363 else 364 flags = (mode & SIO_PLAY) ? O_WRONLY : O_RDONLY; 365 366 while ((fd = open(path, flags | O_NONBLOCK)) < 0) { 367 if (errno == EINTR) 368 continue; 369 DPERROR(path); 370 goto bad_free; 371 } 372 if (fcntl(fd, F_SETFD, FD_CLOEXEC) < 0) { 373 DPERROR("FD_CLOEXEC"); 374 goto bad_close; 375 } 376 377 /* 378 * pause the device 379 */ 380 AUDIO_INITINFO(&aui); 381 if (mode & SIO_PLAY) 382 aui.play.pause = 1; 383 if (mode & SIO_REC) 384 aui.record.pause = 1; 385 if (ioctl(fd, AUDIO_SETINFO, &aui) < 0) { 386 DPERROR("sio_open_sun: setinfo"); 387 goto bad_close; 388 } 389 /* 390 * If both play and record are requested then 391 * set full duplex mode. 392 */ 393 if (mode == (SIO_PLAY | SIO_REC)) { 394 fullduplex = 1; 395 if (ioctl(fd, AUDIO_SETFD, &fullduplex) < 0) { 396 DPRINTF("sio_open_sun: %s: can't set full-duplex\n", path); 397 goto bad_close; 398 } 399 } 400 hdl->fd = fd; 401 402 /* 403 * Default parameters may not be compatible with libsndio (eg. mulaw 404 * encodings, different playback and recording parameters, etc...), so 405 * set parameters to a random value. If the requested parameters are 406 * not supported by the device, then sio_setpar() will pick supported 407 * ones. 408 */ 409 sio_initpar(&par); 410 par.rate = 48000; 411 par.le = SIO_LE_NATIVE; 412 par.sig = 1; 413 par.bits = 16; 414 par.appbufsz = 1200; 415 if (!sio_setpar(&hdl->sio, &par)) 416 goto bad_close; 417 return (struct sio_hdl *)hdl; 418 bad_close: 419 while (close(fd) < 0 && errno == EINTR) 420 ; /* retry */ 421 bad_free: 422 free(hdl); 423 return NULL; 424 } 425 426 static void 427 sio_sun_close(struct sio_hdl *sh) 428 { 429 struct sio_sun_hdl *hdl = (struct sio_sun_hdl *)sh; 430 431 while (close(hdl->fd) < 0 && errno == EINTR) 432 ; /* retry */ 433 free(hdl); 434 } 435 436 static int 437 sio_sun_start(struct sio_hdl *sh) 438 { 439 struct sio_par par; 440 struct sio_sun_hdl *hdl = (struct sio_sun_hdl *)sh; 441 struct audio_info aui; 442 443 if (!sio_getpar(&hdl->sio, &par)) 444 return 0; 445 hdl->obpf = par.pchan * par.bps; 446 hdl->ibpf = par.rchan * par.bps; 447 hdl->ibytes = 0; 448 hdl->obytes = 0; 449 hdl->ierr = 0; 450 hdl->oerr = 0; 451 hdl->offset = 0; 452 hdl->idelta = 0; 453 hdl->odelta = 0; 454 455 if (hdl->sio.mode & SIO_PLAY) { 456 /* 457 * keep the device paused and let sio_sun_write() trigger the 458 * start later, to avoid buffer underruns 459 */ 460 hdl->filling = 1; 461 } else { 462 /* 463 * no play buffers to fill, start now! 464 */ 465 AUDIO_INITINFO(&aui); 466 if (hdl->sio.mode & SIO_REC) 467 aui.record.pause = 0; 468 if (ioctl(hdl->fd, AUDIO_SETINFO, &aui) < 0) { 469 DPERROR("sio_sun_start: setinfo"); 470 hdl->sio.eof = 1; 471 return 0; 472 } 473 hdl->filling = 0; 474 sio_onmove_cb(&hdl->sio, 0); 475 } 476 return 1; 477 } 478 479 static int 480 sio_sun_stop(struct sio_hdl *sh) 481 { 482 struct sio_sun_hdl *hdl = (struct sio_sun_hdl *)sh; 483 struct audio_info aui; 484 int mode; 485 486 if (ioctl(hdl->fd, AUDIO_GETINFO, &aui) < 0) { 487 DPERROR("sio_sun_stop: getinfo"); 488 hdl->sio.eof = 1; 489 return 0; 490 } 491 mode = aui.mode; 492 493 /* 494 * there's no way to drain the device without blocking, so just 495 * stop it until the kernel driver get fixed 496 */ 497 AUDIO_INITINFO(&aui); 498 aui.mode = 0; 499 if (hdl->sio.mode & SIO_PLAY) 500 aui.play.pause = 1; 501 if (hdl->sio.mode & SIO_REC) 502 aui.record.pause = 1; 503 if (ioctl(hdl->fd, AUDIO_SETINFO, &aui) < 0) { 504 DPERROR("sio_sun_stop: setinfo1"); 505 hdl->sio.eof = 1; 506 return 0; 507 } 508 AUDIO_INITINFO(&aui); 509 aui.mode = mode; 510 if (ioctl(hdl->fd, AUDIO_SETINFO, &aui) < 0) { 511 DPERROR("sio_sun_stop: setinfo2"); 512 hdl->sio.eof = 1; 513 return 0; 514 } 515 return 1; 516 } 517 518 static int 519 sio_sun_setpar(struct sio_hdl *sh, struct sio_par *par) 520 { 521 #define NRETRIES 8 522 struct sio_sun_hdl *hdl = (struct sio_sun_hdl *)sh; 523 struct audio_info aui; 524 unsigned i, infr, ibpf, onfr, obpf; 525 unsigned bufsz, round; 526 unsigned rate, req_rate, prec, enc; 527 528 /* 529 * try to set parameters until the device accepts 530 * a common encoding and rate for play and record 531 */ 532 rate = par->rate; 533 prec = par->bits; 534 sio_sun_enctoinfo(hdl, &enc, par); 535 for (i = 0;; i++) { 536 if (i == NRETRIES) { 537 DPRINTF("sio_sun_setpar: couldn't set parameters\n"); 538 hdl->sio.eof = 1; 539 return 0; 540 } 541 AUDIO_INITINFO(&aui); 542 if (hdl->sio.mode & SIO_PLAY) { 543 aui.play.sample_rate = rate; 544 aui.play.precision = prec; 545 aui.play.encoding = enc; 546 aui.play.channels = par->pchan; 547 } 548 if (hdl->sio.mode & SIO_REC) { 549 aui.record.sample_rate = rate; 550 aui.record.precision = prec; 551 aui.record.encoding = enc; 552 aui.record.channels = par->rchan; 553 } 554 DPRINTF("sio_sun_setpar: %i: trying pars = %u/%u/%u\n", 555 i, rate, prec, enc); 556 if (ioctl(hdl->fd, AUDIO_SETINFO, &aui) < 0 && errno != EINVAL) { 557 DPERROR("sio_sun_setpar: setinfo(pars)"); 558 hdl->sio.eof = 1; 559 return 0; 560 } 561 if (ioctl(hdl->fd, AUDIO_GETINFO, &aui) < 0) { 562 DPERROR("sio_sun_setpar: getinfo(pars)"); 563 hdl->sio.eof = 1; 564 return 0; 565 } 566 enc = (hdl->sio.mode & SIO_REC) ? 567 aui.record.encoding : aui.play.encoding; 568 switch (enc) { 569 case AUDIO_ENCODING_SLINEAR_LE: 570 case AUDIO_ENCODING_SLINEAR_BE: 571 case AUDIO_ENCODING_ULINEAR_LE: 572 case AUDIO_ENCODING_ULINEAR_BE: 573 case AUDIO_ENCODING_SLINEAR: 574 case AUDIO_ENCODING_ULINEAR: 575 break; 576 default: 577 DPRINTF("sio_sun_setpar: couldn't set linear encoding\n"); 578 hdl->sio.eof = 1; 579 return 0; 580 } 581 if (hdl->sio.mode != (SIO_REC | SIO_PLAY)) 582 break; 583 if (aui.play.sample_rate == aui.record.sample_rate && 584 aui.play.precision == aui.record.precision && 585 aui.play.encoding == aui.record.encoding) 586 break; 587 if (i < NRETRIES / 2) { 588 rate = aui.play.sample_rate; 589 prec = aui.play.precision; 590 enc = aui.play.encoding; 591 } else { 592 rate = aui.record.sample_rate; 593 prec = aui.record.precision; 594 enc = aui.record.encoding; 595 } 596 } 597 598 /* 599 * If the rate that the hardware is using is different than 600 * the requested rate, scale buffer sizes so they will be the 601 * same time duration as what was requested. This just gets 602 * the rates to use for scaling, that actual scaling is done 603 * later. 604 */ 605 rate = (hdl->sio.mode & SIO_REC) ? aui.record.sample_rate : 606 aui.play.sample_rate; 607 req_rate = rate; 608 if (par->rate && par->rate != ~0U) 609 req_rate = par->rate; 610 611 /* 612 * if block size and buffer size are not both set then 613 * set the blocksize to half the buffer size 614 */ 615 bufsz = par->appbufsz; 616 round = par->round; 617 if (bufsz != ~0U) { 618 bufsz = bufsz * rate / req_rate; 619 if (round == ~0U) 620 round = (bufsz + 1) / 2; 621 else 622 round = round * rate / req_rate; 623 } else if (round != ~0U) { 624 round = round * rate / req_rate; 625 bufsz = round * 2; 626 } else 627 return 1; 628 629 /* 630 * get the play/record frame size in bytes 631 */ 632 if (ioctl(hdl->fd, AUDIO_GETINFO, &aui) < 0) { 633 DPERROR("sio_sun_setpar: GETINFO"); 634 hdl->sio.eof = 1; 635 return 0; 636 } 637 ibpf = (hdl->sio.mode & SIO_REC) ? 638 aui.record.channels * aui.record.bps : 1; 639 obpf = (hdl->sio.mode & SIO_PLAY) ? 640 aui.play.channels * aui.play.bps : 1; 641 642 DPRINTF("sio_sun_setpar: bpf = (%u, %u)\n", ibpf, obpf); 643 644 /* 645 * try to set parameters until the device accepts 646 * a common block size for play and record 647 */ 648 for (i = 0; i < NRETRIES; i++) { 649 AUDIO_INITINFO(&aui); 650 aui.hiwat = (bufsz + round - 1) / round; 651 aui.lowat = aui.hiwat; 652 if (hdl->sio.mode & SIO_REC) 653 aui.record.block_size = round * ibpf; 654 if (hdl->sio.mode & SIO_PLAY) 655 aui.play.block_size = round * obpf; 656 if (ioctl(hdl->fd, AUDIO_SETINFO, &aui) < 0) { 657 DPERROR("sio_sun_setpar2: SETINFO"); 658 hdl->sio.eof = 1; 659 return 0; 660 } 661 if (ioctl(hdl->fd, AUDIO_GETINFO, &aui) < 0) { 662 DPERROR("sio_sun_setpar2: GETINFO"); 663 hdl->sio.eof = 1; 664 return 0; 665 } 666 infr = aui.record.block_size / ibpf; 667 onfr = aui.play.block_size / obpf; 668 DPRINTF("sio_sun_setpar: %i: trying round = %u -> (%u, %u)\n", 669 i, round, infr, onfr); 670 671 /* 672 * if half-duplex or both block sizes match, we're done 673 */ 674 if (hdl->sio.mode != (SIO_REC | SIO_PLAY) || infr == onfr) { 675 DPRINTF("sio_sun_setpar: blocksize ok\n"); 676 return 1; 677 } 678 679 /* 680 * half of the retries, retry with the smaller value, 681 * then with the larger returned value 682 */ 683 if (i < NRETRIES / 2) 684 round = infr < onfr ? infr : onfr; 685 else 686 round = infr < onfr ? onfr : infr; 687 } 688 DPRINTF("sio_sun_setpar: couldn't find a working blocksize\n"); 689 hdl->sio.eof = 1; 690 return 0; 691 #undef NRETRIES 692 } 693 694 static int 695 sio_sun_getpar(struct sio_hdl *sh, struct sio_par *par) 696 { 697 struct sio_sun_hdl *hdl = (struct sio_sun_hdl *)sh; 698 struct audio_info aui; 699 700 if (ioctl(hdl->fd, AUDIO_GETINFO, &aui) < 0) { 701 DPERROR("sio_sun_getpar: getinfo"); 702 hdl->sio.eof = 1; 703 return 0; 704 } 705 if (hdl->sio.mode & SIO_PLAY) { 706 par->rate = aui.play.sample_rate; 707 if (!sio_sun_infotoenc(hdl, &aui.play, par)) 708 return 0; 709 } else if (hdl->sio.mode & SIO_REC) { 710 par->rate = aui.record.sample_rate; 711 if (!sio_sun_infotoenc(hdl, &aui.record, par)) 712 return 0; 713 } else 714 return 0; 715 par->pchan = (hdl->sio.mode & SIO_PLAY) ? 716 aui.play.channels : 0; 717 par->rchan = (hdl->sio.mode & SIO_REC) ? 718 aui.record.channels : 0; 719 par->round = (hdl->sio.mode & SIO_REC) ? 720 aui.record.block_size / (par->bps * par->rchan) : 721 aui.play.block_size / (par->bps * par->pchan); 722 par->appbufsz = aui.hiwat * par->round; 723 par->bufsz = par->appbufsz; 724 return 1; 725 } 726 727 /* 728 * drop recorded samples to compensate xruns 729 */ 730 static int 731 sio_sun_rdrop(struct sio_sun_hdl *hdl) 732 { 733 #define DROP_NMAX 0x1000 734 static char dropbuf[DROP_NMAX]; 735 ssize_t n, todo; 736 737 while (hdl->offset > 0) { 738 todo = hdl->offset * hdl->ibpf; 739 if (todo > DROP_NMAX) 740 todo = DROP_NMAX - DROP_NMAX % hdl->ibpf; 741 while ((n = read(hdl->fd, dropbuf, todo)) < 0) { 742 if (errno == EINTR) 743 continue; 744 if (errno != EAGAIN) { 745 DPERROR("sio_sun_rdrop: read"); 746 hdl->sio.eof = 1; 747 } 748 return 0; 749 } 750 if (n == 0) { 751 DPRINTF("sio_sun_rdrop: eof\n"); 752 hdl->sio.eof = 1; 753 return 0; 754 } 755 hdl->offset -= (int)n / (int)hdl->ibpf; 756 DPRINTF("sio_sun_rdrop: dropped %ld/%ld bytes\n", n, todo); 757 } 758 return 1; 759 } 760 761 static size_t 762 sio_sun_read(struct sio_hdl *sh, void *buf, size_t len) 763 { 764 struct sio_sun_hdl *hdl = (struct sio_sun_hdl *)sh; 765 ssize_t n; 766 767 if (!sio_sun_rdrop(hdl)) 768 return 0; 769 while ((n = read(hdl->fd, buf, len)) < 0) { 770 if (errno == EINTR) 771 continue; 772 if (errno != EAGAIN) { 773 DPERROR("sio_sun_read: read"); 774 hdl->sio.eof = 1; 775 } 776 return 0; 777 } 778 if (n == 0) { 779 DPRINTF("sio_sun_read: eof\n"); 780 hdl->sio.eof = 1; 781 return 0; 782 } 783 return n; 784 } 785 786 static size_t 787 sio_sun_autostart(struct sio_sun_hdl *hdl) 788 { 789 struct audio_info aui; 790 struct pollfd pfd; 791 792 pfd.fd = hdl->fd; 793 pfd.events = POLLOUT; 794 while (poll(&pfd, 1, 0) < 0) { 795 if (errno == EINTR) 796 continue; 797 DPERROR("sio_sun_autostart: poll"); 798 hdl->sio.eof = 1; 799 return 0; 800 } 801 if (!(pfd.revents & POLLOUT)) { 802 hdl->filling = 0; 803 AUDIO_INITINFO(&aui); 804 if (hdl->sio.mode & SIO_PLAY) 805 aui.play.pause = 0; 806 if (hdl->sio.mode & SIO_REC) 807 aui.record.pause = 0; 808 if (ioctl(hdl->fd, AUDIO_SETINFO, &aui) < 0) { 809 DPERROR("sio_sun_autostart: setinfo"); 810 hdl->sio.eof = 1; 811 return 0; 812 } 813 sio_onmove_cb(&hdl->sio, 0); 814 } 815 return 1; 816 } 817 818 /* 819 * insert silence to play to compensate xruns 820 */ 821 static int 822 sio_sun_wsil(struct sio_sun_hdl *hdl) 823 { 824 #define ZERO_NMAX 0x1000 825 static char zero[ZERO_NMAX]; 826 ssize_t n, todo; 827 828 while (hdl->offset < 0) { 829 todo = (int)-hdl->offset * (int)hdl->obpf; 830 if (todo > ZERO_NMAX) 831 todo = ZERO_NMAX - ZERO_NMAX % hdl->obpf; 832 while ((n = write(hdl->fd, zero, todo)) < 0) { 833 if (errno == EINTR) 834 continue; 835 if (errno != EAGAIN) { 836 DPERROR("sio_sun_wsil: write"); 837 hdl->sio.eof = 1; 838 return 0; 839 } 840 return 0; 841 } 842 hdl->offset += (int)n / (int)hdl->obpf; 843 DPRINTF("sio_sun_wsil: inserted %ld/%ld bytes\n", n, todo); 844 } 845 return 1; 846 } 847 848 849 static size_t 850 sio_sun_write(struct sio_hdl *sh, const void *buf, size_t len) 851 { 852 struct sio_sun_hdl *hdl = (struct sio_sun_hdl *)sh; 853 const unsigned char *data = buf; 854 ssize_t n, todo; 855 856 if (!sio_sun_wsil(hdl)) 857 return 0; 858 todo = len; 859 while ((n = write(hdl->fd, data, todo)) < 0) { 860 if (errno == EINTR) 861 continue; 862 if (errno != EAGAIN) { 863 DPERROR("sio_sun_write: write"); 864 hdl->sio.eof = 1; 865 } 866 return 0; 867 } 868 if (hdl->filling) { 869 if (!sio_sun_autostart(hdl)) 870 return 0; 871 } 872 return n; 873 } 874 875 static int 876 sio_sun_nfds(struct sio_hdl *hdl) 877 { 878 return 1; 879 } 880 881 static int 882 sio_sun_pollfd(struct sio_hdl *sh, struct pollfd *pfd, int events) 883 { 884 struct sio_sun_hdl *hdl = (struct sio_sun_hdl *)sh; 885 886 pfd->fd = hdl->fd; 887 pfd->events = events; 888 return 1; 889 } 890 891 int 892 sio_sun_revents(struct sio_hdl *sh, struct pollfd *pfd) 893 { 894 struct sio_sun_hdl *hdl = (struct sio_sun_hdl *)sh; 895 struct audio_offset ao; 896 int xrun, dmove, dierr = 0, doerr = 0, delta; 897 int revents = pfd->revents; 898 899 if (!hdl->sio.started) 900 return pfd->revents; 901 if (hdl->sio.mode & SIO_PLAY) { 902 if (ioctl(hdl->fd, AUDIO_PERROR, &xrun) < 0) { 903 DPERROR("sio_sun_revents: PERROR"); 904 hdl->sio.eof = 1; 905 return POLLHUP; 906 } 907 doerr = xrun - hdl->oerr; 908 hdl->oerr = xrun; 909 if (!(hdl->sio.mode & SIO_REC)) 910 dierr = doerr; 911 } 912 if (hdl->sio.mode & SIO_REC) { 913 if (ioctl(hdl->fd, AUDIO_RERROR, &xrun) < 0) { 914 DPERROR("sio_sun_revents: RERROR"); 915 hdl->sio.eof = 1; 916 return POLLHUP; 917 } 918 dierr = xrun - hdl->ierr; 919 hdl->ierr = xrun; 920 if (!(hdl->sio.mode & SIO_PLAY)) 921 doerr = dierr; 922 } 923 hdl->offset += doerr - dierr; 924 dmove = dierr > doerr ? dierr : doerr; 925 hdl->idelta -= dmove; 926 hdl->odelta -= dmove; 927 928 if ((revents & POLLOUT) && (hdl->sio.mode & SIO_PLAY)) { 929 if (ioctl(hdl->fd, AUDIO_GETOOFFS, &ao) < 0) { 930 DPERROR("sio_sun_revents: GETOOFFS"); 931 hdl->sio.eof = 1; 932 return POLLHUP; 933 } 934 delta = (ao.samples - hdl->obytes) / hdl->obpf; 935 hdl->obytes = ao.samples; 936 hdl->odelta += delta; 937 if (!(hdl->sio.mode & SIO_REC)) 938 hdl->idelta += delta; 939 } 940 if ((revents & POLLIN) && (hdl->sio.mode & SIO_REC)) { 941 if (ioctl(hdl->fd, AUDIO_GETIOFFS, &ao) < 0) { 942 DPERROR("sio_sun_revents: GETIOFFS"); 943 hdl->sio.eof = 1; 944 return POLLHUP; 945 } 946 delta = (ao.samples - hdl->ibytes) / hdl->ibpf; 947 hdl->ibytes = ao.samples; 948 hdl->idelta += delta; 949 if (!(hdl->sio.mode & SIO_PLAY)) 950 hdl->odelta += delta; 951 } 952 delta = (hdl->idelta > hdl->odelta) ? hdl->idelta : hdl->odelta; 953 if (delta > 0) { 954 sio_onmove_cb(&hdl->sio, delta); 955 hdl->idelta -= delta; 956 hdl->odelta -= delta; 957 } 958 959 /* 960 * drop recorded samples or insert silence to play 961 * right now to adjust revents, and avoid busy loops 962 * programs 963 */ 964 if (hdl->filling) 965 revents |= POLLOUT; 966 if ((hdl->sio.mode & SIO_PLAY) && !sio_sun_wsil(hdl)) 967 revents &= ~POLLOUT; 968 if ((hdl->sio.mode & SIO_REC) && !sio_sun_rdrop(hdl)) 969 revents &= ~POLLIN; 970 return revents; 971 } 972