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