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