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