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