1 /* $OpenBSD: sio_sun.c,v 1.2 2011/04/16 10:52: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 hdl = malloc(sizeof(struct sio_sun_hdl)); 347 if (hdl == NULL) 348 return NULL; 349 sio_create(&hdl->sio, &sio_sun_ops, mode, nbio); 350 351 snprintf(path, sizeof(path), "/dev/audio%s", str); 352 if (mode == (SIO_PLAY | SIO_REC)) 353 flags = O_RDWR; 354 else 355 flags = (mode & SIO_PLAY) ? O_WRONLY : O_RDONLY; 356 357 while ((fd = open(path, flags | O_NONBLOCK)) < 0) { 358 if (errno == EINTR) 359 continue; 360 DPERROR(path); 361 goto bad_free; 362 } 363 if (fcntl(fd, F_SETFD, FD_CLOEXEC) < 0) { 364 DPERROR("FD_CLOEXEC"); 365 goto bad_close; 366 } 367 368 /* 369 * pause the device 370 */ 371 AUDIO_INITINFO(&aui); 372 if (mode & SIO_PLAY) 373 aui.play.pause = 1; 374 if (mode & SIO_REC) 375 aui.record.pause = 1; 376 if (ioctl(fd, AUDIO_SETINFO, &aui) < 0) { 377 DPERROR("sio_open_sun: setinfo"); 378 goto bad_close; 379 } 380 /* 381 * If both play and record are requested then 382 * set full duplex mode. 383 */ 384 if (mode == (SIO_PLAY | SIO_REC)) { 385 fullduplex = 1; 386 if (ioctl(fd, AUDIO_SETFD, &fullduplex) < 0) { 387 DPRINTF("sio_open_sun: %s: can't set full-duplex\n", path); 388 goto bad_close; 389 } 390 } 391 hdl->fd = fd; 392 393 /* 394 * Default parameters may not be compatible with libsndio (eg. mulaw 395 * encodings, different playback and recording parameters, etc...), so 396 * set parameters to a random value. If the requested parameters are 397 * not supported by the device, then sio_setpar() will pick supported 398 * ones. 399 */ 400 sio_initpar(&par); 401 par.rate = 48000; 402 par.le = SIO_LE_NATIVE; 403 par.sig = 1; 404 par.bits = 16; 405 par.appbufsz = 1200; 406 if (!sio_setpar(&hdl->sio, &par)) 407 goto bad_close; 408 return (struct sio_hdl *)hdl; 409 bad_close: 410 while (close(fd) < 0 && errno == EINTR) 411 ; /* retry */ 412 bad_free: 413 free(hdl); 414 return NULL; 415 } 416 417 static void 418 sio_sun_close(struct sio_hdl *sh) 419 { 420 struct sio_sun_hdl *hdl = (struct sio_sun_hdl *)sh; 421 422 while (close(hdl->fd) < 0 && errno == EINTR) 423 ; /* retry */ 424 free(hdl); 425 } 426 427 static int 428 sio_sun_start(struct sio_hdl *sh) 429 { 430 struct sio_par par; 431 struct sio_sun_hdl *hdl = (struct sio_sun_hdl *)sh; 432 struct audio_info aui; 433 434 if (!sio_getpar(&hdl->sio, &par)) 435 return 0; 436 hdl->obpf = par.pchan * par.bps; 437 hdl->ibpf = par.rchan * par.bps; 438 hdl->ibytes = 0; 439 hdl->obytes = 0; 440 hdl->ierr = 0; 441 hdl->oerr = 0; 442 hdl->offset = 0; 443 hdl->idelta = 0; 444 hdl->odelta = 0; 445 446 if (hdl->sio.mode & SIO_PLAY) { 447 /* 448 * keep the device paused and let sio_sun_write() trigger the 449 * start later, to avoid buffer underruns 450 */ 451 hdl->filling = 1; 452 } else { 453 /* 454 * no play buffers to fill, start now! 455 */ 456 AUDIO_INITINFO(&aui); 457 if (hdl->sio.mode & SIO_REC) 458 aui.record.pause = 0; 459 if (ioctl(hdl->fd, AUDIO_SETINFO, &aui) < 0) { 460 DPERROR("sio_sun_start: setinfo"); 461 hdl->sio.eof = 1; 462 return 0; 463 } 464 hdl->filling = 0; 465 sio_onmove_cb(&hdl->sio, 0); 466 } 467 return 1; 468 } 469 470 static int 471 sio_sun_stop(struct sio_hdl *sh) 472 { 473 struct sio_sun_hdl *hdl = (struct sio_sun_hdl *)sh; 474 struct audio_info aui; 475 int mode; 476 477 if (ioctl(hdl->fd, AUDIO_GETINFO, &aui) < 0) { 478 DPERROR("sio_sun_stop: getinfo"); 479 hdl->sio.eof = 1; 480 return 0; 481 } 482 mode = aui.mode; 483 484 /* 485 * there's no way to drain the device without blocking, so just 486 * stop it until the kernel driver get fixed 487 */ 488 AUDIO_INITINFO(&aui); 489 aui.mode = 0; 490 if (hdl->sio.mode & SIO_PLAY) 491 aui.play.pause = 1; 492 if (hdl->sio.mode & SIO_REC) 493 aui.record.pause = 1; 494 if (ioctl(hdl->fd, AUDIO_SETINFO, &aui) < 0) { 495 DPERROR("sio_sun_stop: setinfo1"); 496 hdl->sio.eof = 1; 497 return 0; 498 } 499 AUDIO_INITINFO(&aui); 500 aui.mode = mode; 501 if (ioctl(hdl->fd, AUDIO_SETINFO, &aui) < 0) { 502 DPERROR("sio_sun_stop: setinfo2"); 503 hdl->sio.eof = 1; 504 return 0; 505 } 506 return 1; 507 } 508 509 static int 510 sio_sun_setpar(struct sio_hdl *sh, struct sio_par *par) 511 { 512 #define NRETRIES 8 513 struct sio_sun_hdl *hdl = (struct sio_sun_hdl *)sh; 514 struct audio_info aui; 515 unsigned i, infr, ibpf, onfr, obpf; 516 unsigned bufsz, round; 517 unsigned rate, req_rate, prec, enc; 518 519 /* 520 * try to set parameters until the device accepts 521 * a common encoding and rate for play and record 522 */ 523 rate = par->rate; 524 prec = par->bits; 525 sio_sun_enctoinfo(hdl, &enc, par); 526 for (i = 0;; i++) { 527 if (i == NRETRIES) { 528 DPRINTF("sio_sun_setpar: couldn't set parameters\n"); 529 hdl->sio.eof = 1; 530 return 0; 531 } 532 AUDIO_INITINFO(&aui); 533 if (hdl->sio.mode & SIO_PLAY) { 534 aui.play.sample_rate = rate; 535 aui.play.precision = prec; 536 aui.play.encoding = enc; 537 aui.play.channels = par->pchan; 538 } 539 if (hdl->sio.mode & SIO_REC) { 540 aui.record.sample_rate = rate; 541 aui.record.precision = prec; 542 aui.record.encoding = enc; 543 aui.record.channels = par->rchan; 544 } 545 DPRINTF("sio_sun_setpar: %i: trying pars = %u/%u/%u\n", 546 i, rate, prec, enc); 547 if (ioctl(hdl->fd, AUDIO_SETINFO, &aui) < 0 && errno != EINVAL) { 548 DPERROR("sio_sun_setpar: setinfo(pars)"); 549 hdl->sio.eof = 1; 550 return 0; 551 } 552 if (ioctl(hdl->fd, AUDIO_GETINFO, &aui) < 0) { 553 DPERROR("sio_sun_setpar: getinfo(pars)"); 554 hdl->sio.eof = 1; 555 return 0; 556 } 557 enc = (hdl->sio.mode & SIO_REC) ? 558 aui.record.encoding : aui.play.encoding; 559 switch (enc) { 560 case AUDIO_ENCODING_SLINEAR_LE: 561 case AUDIO_ENCODING_SLINEAR_BE: 562 case AUDIO_ENCODING_ULINEAR_LE: 563 case AUDIO_ENCODING_ULINEAR_BE: 564 case AUDIO_ENCODING_SLINEAR: 565 case AUDIO_ENCODING_ULINEAR: 566 break; 567 default: 568 DPRINTF("sio_sun_setpar: couldn't set linear encoding\n"); 569 hdl->sio.eof = 1; 570 return 0; 571 } 572 if (hdl->sio.mode != (SIO_REC | SIO_PLAY)) 573 break; 574 if (aui.play.sample_rate == aui.record.sample_rate && 575 aui.play.precision == aui.record.precision && 576 aui.play.encoding == aui.record.encoding) 577 break; 578 if (i < NRETRIES / 2) { 579 rate = aui.play.sample_rate; 580 prec = aui.play.precision; 581 enc = aui.play.encoding; 582 } else { 583 rate = aui.record.sample_rate; 584 prec = aui.record.precision; 585 enc = aui.record.encoding; 586 } 587 } 588 589 /* 590 * If the rate that the hardware is using is different than 591 * the requested rate, scale buffer sizes so they will be the 592 * same time duration as what was requested. This just gets 593 * the rates to use for scaling, that actual scaling is done 594 * later. 595 */ 596 rate = (hdl->sio.mode & SIO_REC) ? aui.record.sample_rate : 597 aui.play.sample_rate; 598 req_rate = rate; 599 if (par->rate && par->rate != ~0U) 600 req_rate = par->rate; 601 602 /* 603 * if block size and buffer size are not both set then 604 * set the blocksize to half the buffer size 605 */ 606 bufsz = par->appbufsz; 607 round = par->round; 608 if (bufsz != ~0U) { 609 bufsz = bufsz * rate / req_rate; 610 if (round == ~0U) 611 round = (bufsz + 1) / 2; 612 else 613 round = round * rate / req_rate; 614 } else if (round != ~0U) { 615 round = round * rate / req_rate; 616 bufsz = round * 2; 617 } else 618 return 1; 619 620 /* 621 * get the play/record frame size in bytes 622 */ 623 if (ioctl(hdl->fd, AUDIO_GETINFO, &aui) < 0) { 624 DPERROR("sio_sun_setpar: GETINFO"); 625 hdl->sio.eof = 1; 626 return 0; 627 } 628 ibpf = (hdl->sio.mode & SIO_REC) ? 629 aui.record.channels * aui.record.bps : 1; 630 obpf = (hdl->sio.mode & SIO_PLAY) ? 631 aui.play.channels * aui.play.bps : 1; 632 633 DPRINTF("sio_sun_setpar: bpf = (%u, %u)\n", ibpf, obpf); 634 635 /* 636 * try to set parameters until the device accepts 637 * a common block size for play and record 638 */ 639 for (i = 0; i < NRETRIES; i++) { 640 AUDIO_INITINFO(&aui); 641 aui.hiwat = (bufsz + round - 1) / round; 642 aui.lowat = aui.hiwat; 643 if (hdl->sio.mode & SIO_REC) 644 aui.record.block_size = round * ibpf; 645 if (hdl->sio.mode & SIO_PLAY) 646 aui.play.block_size = round * obpf; 647 if (ioctl(hdl->fd, AUDIO_SETINFO, &aui) < 0) { 648 DPERROR("sio_sun_setpar2: SETINFO"); 649 hdl->sio.eof = 1; 650 return 0; 651 } 652 if (ioctl(hdl->fd, AUDIO_GETINFO, &aui) < 0) { 653 DPERROR("sio_sun_setpar2: GETINFO"); 654 hdl->sio.eof = 1; 655 return 0; 656 } 657 infr = aui.record.block_size / ibpf; 658 onfr = aui.play.block_size / obpf; 659 DPRINTF("sio_sun_setpar: %i: trying round = %u -> (%u, %u)\n", 660 i, round, infr, onfr); 661 662 /* 663 * if half-duplex or both block sizes match, we're done 664 */ 665 if (hdl->sio.mode != (SIO_REC | SIO_PLAY) || infr == onfr) { 666 DPRINTF("sio_sun_setpar: blocksize ok\n"); 667 return 1; 668 } 669 670 /* 671 * half of the retries, retry with the smaller value, 672 * then with the larger returned value 673 */ 674 if (i < NRETRIES / 2) 675 round = infr < onfr ? infr : onfr; 676 else 677 round = infr < onfr ? onfr : infr; 678 } 679 DPRINTF("sio_sun_setpar: couldn't find a working blocksize\n"); 680 hdl->sio.eof = 1; 681 return 0; 682 #undef NRETRIES 683 } 684 685 static int 686 sio_sun_getpar(struct sio_hdl *sh, struct sio_par *par) 687 { 688 struct sio_sun_hdl *hdl = (struct sio_sun_hdl *)sh; 689 struct audio_info aui; 690 691 if (ioctl(hdl->fd, AUDIO_GETINFO, &aui) < 0) { 692 DPERROR("sio_sun_getpar: getinfo"); 693 hdl->sio.eof = 1; 694 return 0; 695 } 696 if (hdl->sio.mode & SIO_PLAY) { 697 par->rate = aui.play.sample_rate; 698 if (!sio_sun_infotoenc(hdl, &aui.play, par)) 699 return 0; 700 } else if (hdl->sio.mode & SIO_REC) { 701 par->rate = aui.record.sample_rate; 702 if (!sio_sun_infotoenc(hdl, &aui.record, par)) 703 return 0; 704 } else 705 return 0; 706 par->pchan = (hdl->sio.mode & SIO_PLAY) ? 707 aui.play.channels : 0; 708 par->rchan = (hdl->sio.mode & SIO_REC) ? 709 aui.record.channels : 0; 710 par->round = (hdl->sio.mode & SIO_REC) ? 711 aui.record.block_size / (par->bps * par->rchan) : 712 aui.play.block_size / (par->bps * par->pchan); 713 par->appbufsz = aui.hiwat * par->round; 714 par->bufsz = par->appbufsz; 715 return 1; 716 } 717 718 /* 719 * drop recorded samples to compensate xruns 720 */ 721 static int 722 sio_sun_rdrop(struct sio_sun_hdl *hdl) 723 { 724 #define DROP_NMAX 0x1000 725 static char dropbuf[DROP_NMAX]; 726 ssize_t n, todo; 727 728 while (hdl->offset > 0) { 729 todo = hdl->offset * hdl->ibpf; 730 if (todo > DROP_NMAX) 731 todo = DROP_NMAX - DROP_NMAX % hdl->ibpf; 732 while ((n = read(hdl->fd, dropbuf, todo)) < 0) { 733 if (errno == EINTR) 734 continue; 735 if (errno != EAGAIN) { 736 DPERROR("sio_sun_rdrop: read"); 737 hdl->sio.eof = 1; 738 } 739 return 0; 740 } 741 if (n == 0) { 742 DPRINTF("sio_sun_rdrop: eof\n"); 743 hdl->sio.eof = 1; 744 return 0; 745 } 746 hdl->offset -= (int)n / (int)hdl->ibpf; 747 DPRINTF("sio_sun_rdrop: dropped %ld/%ld bytes\n", n, todo); 748 } 749 return 1; 750 } 751 752 static size_t 753 sio_sun_read(struct sio_hdl *sh, void *buf, size_t len) 754 { 755 struct sio_sun_hdl *hdl = (struct sio_sun_hdl *)sh; 756 ssize_t n; 757 758 if (!sio_sun_rdrop(hdl)) 759 return 0; 760 while ((n = read(hdl->fd, buf, len)) < 0) { 761 if (errno == EINTR) 762 continue; 763 if (errno != EAGAIN) { 764 DPERROR("sio_sun_read: read"); 765 hdl->sio.eof = 1; 766 } 767 return 0; 768 } 769 if (n == 0) { 770 DPRINTF("sio_sun_read: eof\n"); 771 hdl->sio.eof = 1; 772 return 0; 773 } 774 return n; 775 } 776 777 static size_t 778 sio_sun_autostart(struct sio_sun_hdl *hdl) 779 { 780 struct audio_info aui; 781 struct pollfd pfd; 782 783 pfd.fd = hdl->fd; 784 pfd.events = POLLOUT; 785 while (poll(&pfd, 1, 0) < 0) { 786 if (errno == EINTR) 787 continue; 788 DPERROR("sio_sun_autostart: poll"); 789 hdl->sio.eof = 1; 790 return 0; 791 } 792 if (!(pfd.revents & POLLOUT)) { 793 hdl->filling = 0; 794 AUDIO_INITINFO(&aui); 795 if (hdl->sio.mode & SIO_PLAY) 796 aui.play.pause = 0; 797 if (hdl->sio.mode & SIO_REC) 798 aui.record.pause = 0; 799 if (ioctl(hdl->fd, AUDIO_SETINFO, &aui) < 0) { 800 DPERROR("sio_sun_autostart: setinfo"); 801 hdl->sio.eof = 1; 802 return 0; 803 } 804 sio_onmove_cb(&hdl->sio, 0); 805 } 806 return 1; 807 } 808 809 /* 810 * insert silence to play to compensate xruns 811 */ 812 static int 813 sio_sun_wsil(struct sio_sun_hdl *hdl) 814 { 815 #define ZERO_NMAX 0x1000 816 static char zero[ZERO_NMAX]; 817 ssize_t n, todo; 818 819 while (hdl->offset < 0) { 820 todo = (int)-hdl->offset * (int)hdl->obpf; 821 if (todo > ZERO_NMAX) 822 todo = ZERO_NMAX - ZERO_NMAX % hdl->obpf; 823 while ((n = write(hdl->fd, zero, todo)) < 0) { 824 if (errno == EINTR) 825 continue; 826 if (errno != EAGAIN) { 827 DPERROR("sio_sun_wsil: write"); 828 hdl->sio.eof = 1; 829 return 0; 830 } 831 return 0; 832 } 833 hdl->offset += (int)n / (int)hdl->obpf; 834 DPRINTF("sio_sun_wsil: inserted %ld/%ld bytes\n", n, todo); 835 } 836 return 1; 837 } 838 839 840 static size_t 841 sio_sun_write(struct sio_hdl *sh, const void *buf, size_t len) 842 { 843 struct sio_sun_hdl *hdl = (struct sio_sun_hdl *)sh; 844 const unsigned char *data = buf; 845 ssize_t n, todo; 846 847 if (!sio_sun_wsil(hdl)) 848 return 0; 849 todo = len; 850 while ((n = write(hdl->fd, data, todo)) < 0) { 851 if (errno == EINTR) 852 continue; 853 if (errno != EAGAIN) { 854 DPERROR("sio_sun_write: write"); 855 hdl->sio.eof = 1; 856 } 857 return 0; 858 } 859 if (hdl->filling) { 860 if (!sio_sun_autostart(hdl)) 861 return 0; 862 } 863 return n; 864 } 865 866 static int 867 sio_sun_nfds(struct sio_hdl *hdl) 868 { 869 return 1; 870 } 871 872 static int 873 sio_sun_pollfd(struct sio_hdl *sh, struct pollfd *pfd, int events) 874 { 875 struct sio_sun_hdl *hdl = (struct sio_sun_hdl *)sh; 876 877 pfd->fd = hdl->fd; 878 pfd->events = events; 879 return 1; 880 } 881 882 int 883 sio_sun_revents(struct sio_hdl *sh, struct pollfd *pfd) 884 { 885 struct sio_sun_hdl *hdl = (struct sio_sun_hdl *)sh; 886 struct audio_offset ao; 887 int xrun, dmove, dierr = 0, doerr = 0, delta; 888 int revents = pfd->revents; 889 890 if (!hdl->sio.started) 891 return pfd->revents; 892 if (hdl->sio.mode & SIO_PLAY) { 893 if (ioctl(hdl->fd, AUDIO_PERROR, &xrun) < 0) { 894 DPERROR("sio_sun_revents: PERROR"); 895 hdl->sio.eof = 1; 896 return POLLHUP; 897 } 898 doerr = xrun - hdl->oerr; 899 hdl->oerr = xrun; 900 if (!(hdl->sio.mode & SIO_REC)) 901 dierr = doerr; 902 } 903 if (hdl->sio.mode & SIO_REC) { 904 if (ioctl(hdl->fd, AUDIO_RERROR, &xrun) < 0) { 905 DPERROR("sio_sun_revents: RERROR"); 906 hdl->sio.eof = 1; 907 return POLLHUP; 908 } 909 dierr = xrun - hdl->ierr; 910 hdl->ierr = xrun; 911 if (!(hdl->sio.mode & SIO_PLAY)) 912 doerr = dierr; 913 } 914 hdl->offset += doerr - dierr; 915 dmove = dierr > doerr ? dierr : doerr; 916 hdl->idelta -= dmove; 917 hdl->odelta -= dmove; 918 919 if ((revents & POLLOUT) && (hdl->sio.mode & SIO_PLAY)) { 920 if (ioctl(hdl->fd, AUDIO_GETOOFFS, &ao) < 0) { 921 DPERROR("sio_sun_revents: GETOOFFS"); 922 hdl->sio.eof = 1; 923 return POLLHUP; 924 } 925 delta = (ao.samples - hdl->obytes) / hdl->obpf; 926 hdl->obytes = ao.samples; 927 hdl->odelta += delta; 928 if (!(hdl->sio.mode & SIO_REC)) 929 hdl->idelta += delta; 930 } 931 if ((revents & POLLIN) && (hdl->sio.mode & SIO_REC)) { 932 if (ioctl(hdl->fd, AUDIO_GETIOFFS, &ao) < 0) { 933 DPERROR("sio_sun_revents: GETIOFFS"); 934 hdl->sio.eof = 1; 935 return POLLHUP; 936 } 937 delta = (ao.samples - hdl->ibytes) / hdl->ibpf; 938 hdl->ibytes = ao.samples; 939 hdl->idelta += delta; 940 if (!(hdl->sio.mode & SIO_PLAY)) 941 hdl->odelta += delta; 942 } 943 delta = (hdl->idelta > hdl->odelta) ? hdl->idelta : hdl->odelta; 944 if (delta > 0) { 945 sio_onmove_cb(&hdl->sio, delta); 946 hdl->idelta -= delta; 947 hdl->odelta -= delta; 948 } 949 950 /* 951 * drop recorded samples or insert silence to play 952 * right now to adjust revents, and avoid busy loops 953 * programs 954 */ 955 if (hdl->filling) 956 revents |= POLLOUT; 957 if ((hdl->sio.mode & SIO_PLAY) && !sio_sun_wsil(hdl)) 958 revents &= ~POLLOUT; 959 if ((hdl->sio.mode & SIO_REC) && !sio_sun_rdrop(hdl)) 960 revents &= ~POLLIN; 961 return revents; 962 } 963