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