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