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