1 /* 2 * QEMU OSS audio driver 3 * 4 * Copyright (c) 2003-2005 Vassili Karpov (malc) 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a copy 7 * of this software and associated documentation files (the "Software"), to deal 8 * in the Software without restriction, including without limitation the rights 9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 * copies of the Software, and to permit persons to whom the Software is 11 * furnished to do so, subject to the following conditions: 12 * 13 * The above copyright notice and this permission notice shall be included in 14 * all copies or substantial portions of the Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 * THE SOFTWARE. 23 */ 24 #include <stdlib.h> 25 #include <sys/mman.h> 26 #include <sys/types.h> 27 #include <sys/ioctl.h> 28 #ifdef __OpenBSD__ 29 #include <soundcard.h> 30 #else 31 #include <sys/soundcard.h> 32 #endif 33 #include "qemu-common.h" 34 #include "qemu/main-loop.h" 35 #include "qemu/host-utils.h" 36 #include "audio.h" 37 38 #define AUDIO_CAP "oss" 39 #include "audio_int.h" 40 41 #if defined OSS_GETVERSION && defined SNDCTL_DSP_POLICY 42 #define USE_DSP_POLICY 43 #endif 44 45 typedef struct OSSVoiceOut { 46 HWVoiceOut hw; 47 void *pcm_buf; 48 int fd; 49 int wpos; 50 int nfrags; 51 int fragsize; 52 int mmapped; 53 int pending; 54 } OSSVoiceOut; 55 56 typedef struct OSSVoiceIn { 57 HWVoiceIn hw; 58 void *pcm_buf; 59 int fd; 60 int nfrags; 61 int fragsize; 62 } OSSVoiceIn; 63 64 static struct { 65 int try_mmap; 66 int nfrags; 67 int fragsize; 68 const char *devpath_out; 69 const char *devpath_in; 70 int debug; 71 int exclusive; 72 int policy; 73 } conf = { 74 .try_mmap = 0, 75 .nfrags = 4, 76 .fragsize = 4096, 77 .devpath_out = "/dev/dsp", 78 .devpath_in = "/dev/dsp", 79 .debug = 0, 80 .exclusive = 0, 81 .policy = 5 82 }; 83 84 struct oss_params { 85 int freq; 86 audfmt_e fmt; 87 int nchannels; 88 int nfrags; 89 int fragsize; 90 }; 91 92 static void GCC_FMT_ATTR (2, 3) oss_logerr (int err, const char *fmt, ...) 93 { 94 va_list ap; 95 96 va_start (ap, fmt); 97 AUD_vlog (AUDIO_CAP, fmt, ap); 98 va_end (ap); 99 100 AUD_log (AUDIO_CAP, "Reason: %s\n", strerror (err)); 101 } 102 103 static void GCC_FMT_ATTR (3, 4) oss_logerr2 ( 104 int err, 105 const char *typ, 106 const char *fmt, 107 ... 108 ) 109 { 110 va_list ap; 111 112 AUD_log (AUDIO_CAP, "Could not initialize %s\n", typ); 113 114 va_start (ap, fmt); 115 AUD_vlog (AUDIO_CAP, fmt, ap); 116 va_end (ap); 117 118 AUD_log (AUDIO_CAP, "Reason: %s\n", strerror (err)); 119 } 120 121 static void oss_anal_close (int *fdp) 122 { 123 int err; 124 125 qemu_set_fd_handler (*fdp, NULL, NULL, NULL); 126 err = close (*fdp); 127 if (err) { 128 oss_logerr (errno, "Failed to close file(fd=%d)\n", *fdp); 129 } 130 *fdp = -1; 131 } 132 133 static void oss_helper_poll_out (void *opaque) 134 { 135 (void) opaque; 136 audio_run ("oss_poll_out"); 137 } 138 139 static void oss_helper_poll_in (void *opaque) 140 { 141 (void) opaque; 142 audio_run ("oss_poll_in"); 143 } 144 145 static int oss_poll_out (HWVoiceOut *hw) 146 { 147 OSSVoiceOut *oss = (OSSVoiceOut *) hw; 148 149 return qemu_set_fd_handler (oss->fd, NULL, oss_helper_poll_out, NULL); 150 } 151 152 static int oss_poll_in (HWVoiceIn *hw) 153 { 154 OSSVoiceIn *oss = (OSSVoiceIn *) hw; 155 156 return qemu_set_fd_handler (oss->fd, oss_helper_poll_in, NULL, NULL); 157 } 158 159 static int oss_write (SWVoiceOut *sw, void *buf, int len) 160 { 161 return audio_pcm_sw_write (sw, buf, len); 162 } 163 164 static int aud_to_ossfmt (audfmt_e fmt, int endianness) 165 { 166 switch (fmt) { 167 case AUD_FMT_S8: 168 return AFMT_S8; 169 170 case AUD_FMT_U8: 171 return AFMT_U8; 172 173 case AUD_FMT_S16: 174 if (endianness) { 175 return AFMT_S16_BE; 176 } 177 else { 178 return AFMT_S16_LE; 179 } 180 181 case AUD_FMT_U16: 182 if (endianness) { 183 return AFMT_U16_BE; 184 } 185 else { 186 return AFMT_U16_LE; 187 } 188 189 default: 190 dolog ("Internal logic error: Bad audio format %d\n", fmt); 191 #ifdef DEBUG_AUDIO 192 abort (); 193 #endif 194 return AFMT_U8; 195 } 196 } 197 198 static int oss_to_audfmt (int ossfmt, audfmt_e *fmt, int *endianness) 199 { 200 switch (ossfmt) { 201 case AFMT_S8: 202 *endianness = 0; 203 *fmt = AUD_FMT_S8; 204 break; 205 206 case AFMT_U8: 207 *endianness = 0; 208 *fmt = AUD_FMT_U8; 209 break; 210 211 case AFMT_S16_LE: 212 *endianness = 0; 213 *fmt = AUD_FMT_S16; 214 break; 215 216 case AFMT_U16_LE: 217 *endianness = 0; 218 *fmt = AUD_FMT_U16; 219 break; 220 221 case AFMT_S16_BE: 222 *endianness = 1; 223 *fmt = AUD_FMT_S16; 224 break; 225 226 case AFMT_U16_BE: 227 *endianness = 1; 228 *fmt = AUD_FMT_U16; 229 break; 230 231 default: 232 dolog ("Unrecognized audio format %d\n", ossfmt); 233 return -1; 234 } 235 236 return 0; 237 } 238 239 #if defined DEBUG_MISMATCHES || defined DEBUG 240 static void oss_dump_info (struct oss_params *req, struct oss_params *obt) 241 { 242 dolog ("parameter | requested value | obtained value\n"); 243 dolog ("format | %10d | %10d\n", req->fmt, obt->fmt); 244 dolog ("channels | %10d | %10d\n", 245 req->nchannels, obt->nchannels); 246 dolog ("frequency | %10d | %10d\n", req->freq, obt->freq); 247 dolog ("nfrags | %10d | %10d\n", req->nfrags, obt->nfrags); 248 dolog ("fragsize | %10d | %10d\n", 249 req->fragsize, obt->fragsize); 250 } 251 #endif 252 253 #ifdef USE_DSP_POLICY 254 static int oss_get_version (int fd, int *version, const char *typ) 255 { 256 if (ioctl (fd, OSS_GETVERSION, &version)) { 257 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) 258 /* 259 * Looks like atm (20100109) FreeBSD knows OSS_GETVERSION 260 * since 7.x, but currently only on the mixer device (or in 261 * the Linuxolator), and in the native version that part of 262 * the code is in fact never reached so the ioctl fails anyway. 263 * Until this is fixed, just check the errno and if its what 264 * FreeBSD's sound drivers return atm assume they are new enough. 265 */ 266 if (errno == EINVAL) { 267 *version = 0x040000; 268 return 0; 269 } 270 #endif 271 oss_logerr2 (errno, typ, "Failed to get OSS version\n"); 272 return -1; 273 } 274 return 0; 275 } 276 #endif 277 278 static int oss_open (int in, struct oss_params *req, 279 struct oss_params *obt, int *pfd) 280 { 281 int fd; 282 int oflags = conf.exclusive ? O_EXCL : 0; 283 audio_buf_info abinfo; 284 int fmt, freq, nchannels; 285 int setfragment = 1; 286 const char *dspname = in ? conf.devpath_in : conf.devpath_out; 287 const char *typ = in ? "ADC" : "DAC"; 288 289 /* Kludge needed to have working mmap on Linux */ 290 oflags |= conf.try_mmap ? O_RDWR : (in ? O_RDONLY : O_WRONLY); 291 292 fd = open (dspname, oflags | O_NONBLOCK); 293 if (-1 == fd) { 294 oss_logerr2 (errno, typ, "Failed to open `%s'\n", dspname); 295 return -1; 296 } 297 298 freq = req->freq; 299 nchannels = req->nchannels; 300 fmt = req->fmt; 301 302 if (ioctl (fd, SNDCTL_DSP_SAMPLESIZE, &fmt)) { 303 oss_logerr2 (errno, typ, "Failed to set sample size %d\n", req->fmt); 304 goto err; 305 } 306 307 if (ioctl (fd, SNDCTL_DSP_CHANNELS, &nchannels)) { 308 oss_logerr2 (errno, typ, "Failed to set number of channels %d\n", 309 req->nchannels); 310 goto err; 311 } 312 313 if (ioctl (fd, SNDCTL_DSP_SPEED, &freq)) { 314 oss_logerr2 (errno, typ, "Failed to set frequency %d\n", req->freq); 315 goto err; 316 } 317 318 if (ioctl (fd, SNDCTL_DSP_NONBLOCK, NULL)) { 319 oss_logerr2 (errno, typ, "Failed to set non-blocking mode\n"); 320 goto err; 321 } 322 323 #ifdef USE_DSP_POLICY 324 if (conf.policy >= 0) { 325 int version; 326 327 if (!oss_get_version (fd, &version, typ)) { 328 if (conf.debug) { 329 dolog ("OSS version = %#x\n", version); 330 } 331 332 if (version >= 0x040000) { 333 int policy = conf.policy; 334 if (ioctl (fd, SNDCTL_DSP_POLICY, &policy)) { 335 oss_logerr2 (errno, typ, 336 "Failed to set timing policy to %d\n", 337 conf.policy); 338 goto err; 339 } 340 setfragment = 0; 341 } 342 } 343 } 344 #endif 345 346 if (setfragment) { 347 int mmmmssss = (req->nfrags << 16) | ctz32 (req->fragsize); 348 if (ioctl (fd, SNDCTL_DSP_SETFRAGMENT, &mmmmssss)) { 349 oss_logerr2 (errno, typ, "Failed to set buffer length (%d, %d)\n", 350 req->nfrags, req->fragsize); 351 goto err; 352 } 353 } 354 355 if (ioctl (fd, in ? SNDCTL_DSP_GETISPACE : SNDCTL_DSP_GETOSPACE, &abinfo)) { 356 oss_logerr2 (errno, typ, "Failed to get buffer length\n"); 357 goto err; 358 } 359 360 if (!abinfo.fragstotal || !abinfo.fragsize) { 361 AUD_log (AUDIO_CAP, "Returned bogus buffer information(%d, %d) for %s\n", 362 abinfo.fragstotal, abinfo.fragsize, typ); 363 goto err; 364 } 365 366 obt->fmt = fmt; 367 obt->nchannels = nchannels; 368 obt->freq = freq; 369 obt->nfrags = abinfo.fragstotal; 370 obt->fragsize = abinfo.fragsize; 371 *pfd = fd; 372 373 #ifdef DEBUG_MISMATCHES 374 if ((req->fmt != obt->fmt) || 375 (req->nchannels != obt->nchannels) || 376 (req->freq != obt->freq) || 377 (req->fragsize != obt->fragsize) || 378 (req->nfrags != obt->nfrags)) { 379 dolog ("Audio parameters mismatch\n"); 380 oss_dump_info (req, obt); 381 } 382 #endif 383 384 #ifdef DEBUG 385 oss_dump_info (req, obt); 386 #endif 387 return 0; 388 389 err: 390 oss_anal_close (&fd); 391 return -1; 392 } 393 394 static void oss_write_pending (OSSVoiceOut *oss) 395 { 396 HWVoiceOut *hw = &oss->hw; 397 398 if (oss->mmapped) { 399 return; 400 } 401 402 while (oss->pending) { 403 int samples_written; 404 ssize_t bytes_written; 405 int samples_till_end = hw->samples - oss->wpos; 406 int samples_to_write = audio_MIN (oss->pending, samples_till_end); 407 int bytes_to_write = samples_to_write << hw->info.shift; 408 void *pcm = advance (oss->pcm_buf, oss->wpos << hw->info.shift); 409 410 bytes_written = write (oss->fd, pcm, bytes_to_write); 411 if (bytes_written < 0) { 412 if (errno != EAGAIN) { 413 oss_logerr (errno, "failed to write %d bytes\n", 414 bytes_to_write); 415 } 416 break; 417 } 418 419 if (bytes_written & hw->info.align) { 420 dolog ("misaligned write asked for %d, but got %zd\n", 421 bytes_to_write, bytes_written); 422 return; 423 } 424 425 samples_written = bytes_written >> hw->info.shift; 426 oss->pending -= samples_written; 427 oss->wpos = (oss->wpos + samples_written) % hw->samples; 428 if (bytes_written - bytes_to_write) { 429 break; 430 } 431 } 432 } 433 434 static int oss_run_out (HWVoiceOut *hw, int live) 435 { 436 OSSVoiceOut *oss = (OSSVoiceOut *) hw; 437 int err, decr; 438 struct audio_buf_info abinfo; 439 struct count_info cntinfo; 440 int bufsize; 441 442 bufsize = hw->samples << hw->info.shift; 443 444 if (oss->mmapped) { 445 int bytes, pos; 446 447 err = ioctl (oss->fd, SNDCTL_DSP_GETOPTR, &cntinfo); 448 if (err < 0) { 449 oss_logerr (errno, "SNDCTL_DSP_GETOPTR failed\n"); 450 return 0; 451 } 452 453 pos = hw->rpos << hw->info.shift; 454 bytes = audio_ring_dist (cntinfo.ptr, pos, bufsize); 455 decr = audio_MIN (bytes >> hw->info.shift, live); 456 } 457 else { 458 err = ioctl (oss->fd, SNDCTL_DSP_GETOSPACE, &abinfo); 459 if (err < 0) { 460 oss_logerr (errno, "SNDCTL_DSP_GETOPTR failed\n"); 461 return 0; 462 } 463 464 if (abinfo.bytes > bufsize) { 465 if (conf.debug) { 466 dolog ("warning: Invalid available size, size=%d bufsize=%d\n" 467 "please report your OS/audio hw to av1474@comtv.ru\n", 468 abinfo.bytes, bufsize); 469 } 470 abinfo.bytes = bufsize; 471 } 472 473 if (abinfo.bytes < 0) { 474 if (conf.debug) { 475 dolog ("warning: Invalid available size, size=%d bufsize=%d\n", 476 abinfo.bytes, bufsize); 477 } 478 return 0; 479 } 480 481 decr = audio_MIN (abinfo.bytes >> hw->info.shift, live); 482 if (!decr) { 483 return 0; 484 } 485 } 486 487 decr = audio_pcm_hw_clip_out (hw, oss->pcm_buf, decr, oss->pending); 488 oss->pending += decr; 489 oss_write_pending (oss); 490 491 return decr; 492 } 493 494 static void oss_fini_out (HWVoiceOut *hw) 495 { 496 int err; 497 OSSVoiceOut *oss = (OSSVoiceOut *) hw; 498 499 ldebug ("oss_fini\n"); 500 oss_anal_close (&oss->fd); 501 502 if (oss->pcm_buf) { 503 if (oss->mmapped) { 504 err = munmap (oss->pcm_buf, hw->samples << hw->info.shift); 505 if (err) { 506 oss_logerr (errno, "Failed to unmap buffer %p, size %d\n", 507 oss->pcm_buf, hw->samples << hw->info.shift); 508 } 509 } 510 else { 511 g_free (oss->pcm_buf); 512 } 513 oss->pcm_buf = NULL; 514 } 515 } 516 517 static int oss_init_out (HWVoiceOut *hw, struct audsettings *as) 518 { 519 OSSVoiceOut *oss = (OSSVoiceOut *) hw; 520 struct oss_params req, obt; 521 int endianness; 522 int err; 523 int fd; 524 audfmt_e effective_fmt; 525 struct audsettings obt_as; 526 527 oss->fd = -1; 528 529 req.fmt = aud_to_ossfmt (as->fmt, as->endianness); 530 req.freq = as->freq; 531 req.nchannels = as->nchannels; 532 req.fragsize = conf.fragsize; 533 req.nfrags = conf.nfrags; 534 535 if (oss_open (0, &req, &obt, &fd)) { 536 return -1; 537 } 538 539 err = oss_to_audfmt (obt.fmt, &effective_fmt, &endianness); 540 if (err) { 541 oss_anal_close (&fd); 542 return -1; 543 } 544 545 obt_as.freq = obt.freq; 546 obt_as.nchannels = obt.nchannels; 547 obt_as.fmt = effective_fmt; 548 obt_as.endianness = endianness; 549 550 audio_pcm_init_info (&hw->info, &obt_as); 551 oss->nfrags = obt.nfrags; 552 oss->fragsize = obt.fragsize; 553 554 if (obt.nfrags * obt.fragsize & hw->info.align) { 555 dolog ("warning: Misaligned DAC buffer, size %d, alignment %d\n", 556 obt.nfrags * obt.fragsize, hw->info.align + 1); 557 } 558 559 hw->samples = (obt.nfrags * obt.fragsize) >> hw->info.shift; 560 561 oss->mmapped = 0; 562 if (conf.try_mmap) { 563 oss->pcm_buf = mmap ( 564 NULL, 565 hw->samples << hw->info.shift, 566 PROT_READ | PROT_WRITE, 567 MAP_SHARED, 568 fd, 569 0 570 ); 571 if (oss->pcm_buf == MAP_FAILED) { 572 oss_logerr (errno, "Failed to map %d bytes of DAC\n", 573 hw->samples << hw->info.shift); 574 } 575 else { 576 int err; 577 int trig = 0; 578 if (ioctl (fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) { 579 oss_logerr (errno, "SNDCTL_DSP_SETTRIGGER 0 failed\n"); 580 } 581 else { 582 trig = PCM_ENABLE_OUTPUT; 583 if (ioctl (fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) { 584 oss_logerr ( 585 errno, 586 "SNDCTL_DSP_SETTRIGGER PCM_ENABLE_OUTPUT failed\n" 587 ); 588 } 589 else { 590 oss->mmapped = 1; 591 } 592 } 593 594 if (!oss->mmapped) { 595 err = munmap (oss->pcm_buf, hw->samples << hw->info.shift); 596 if (err) { 597 oss_logerr (errno, "Failed to unmap buffer %p size %d\n", 598 oss->pcm_buf, hw->samples << hw->info.shift); 599 } 600 } 601 } 602 } 603 604 if (!oss->mmapped) { 605 oss->pcm_buf = audio_calloc ( 606 AUDIO_FUNC, 607 hw->samples, 608 1 << hw->info.shift 609 ); 610 if (!oss->pcm_buf) { 611 dolog ( 612 "Could not allocate DAC buffer (%d samples, each %d bytes)\n", 613 hw->samples, 614 1 << hw->info.shift 615 ); 616 oss_anal_close (&fd); 617 return -1; 618 } 619 } 620 621 oss->fd = fd; 622 return 0; 623 } 624 625 static int oss_ctl_out (HWVoiceOut *hw, int cmd, ...) 626 { 627 int trig; 628 OSSVoiceOut *oss = (OSSVoiceOut *) hw; 629 630 switch (cmd) { 631 case VOICE_ENABLE: 632 { 633 va_list ap; 634 int poll_mode; 635 636 va_start (ap, cmd); 637 poll_mode = va_arg (ap, int); 638 va_end (ap); 639 640 ldebug ("enabling voice\n"); 641 if (poll_mode && oss_poll_out (hw)) { 642 poll_mode = 0; 643 } 644 hw->poll_mode = poll_mode; 645 646 if (!oss->mmapped) { 647 return 0; 648 } 649 650 audio_pcm_info_clear_buf (&hw->info, oss->pcm_buf, hw->samples); 651 trig = PCM_ENABLE_OUTPUT; 652 if (ioctl (oss->fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) { 653 oss_logerr ( 654 errno, 655 "SNDCTL_DSP_SETTRIGGER PCM_ENABLE_OUTPUT failed\n" 656 ); 657 return -1; 658 } 659 } 660 break; 661 662 case VOICE_DISABLE: 663 if (hw->poll_mode) { 664 qemu_set_fd_handler (oss->fd, NULL, NULL, NULL); 665 hw->poll_mode = 0; 666 } 667 668 if (!oss->mmapped) { 669 return 0; 670 } 671 672 ldebug ("disabling voice\n"); 673 trig = 0; 674 if (ioctl (oss->fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) { 675 oss_logerr (errno, "SNDCTL_DSP_SETTRIGGER 0 failed\n"); 676 return -1; 677 } 678 break; 679 } 680 return 0; 681 } 682 683 static int oss_init_in (HWVoiceIn *hw, struct audsettings *as) 684 { 685 OSSVoiceIn *oss = (OSSVoiceIn *) hw; 686 struct oss_params req, obt; 687 int endianness; 688 int err; 689 int fd; 690 audfmt_e effective_fmt; 691 struct audsettings obt_as; 692 693 oss->fd = -1; 694 695 req.fmt = aud_to_ossfmt (as->fmt, as->endianness); 696 req.freq = as->freq; 697 req.nchannels = as->nchannels; 698 req.fragsize = conf.fragsize; 699 req.nfrags = conf.nfrags; 700 if (oss_open (1, &req, &obt, &fd)) { 701 return -1; 702 } 703 704 err = oss_to_audfmt (obt.fmt, &effective_fmt, &endianness); 705 if (err) { 706 oss_anal_close (&fd); 707 return -1; 708 } 709 710 obt_as.freq = obt.freq; 711 obt_as.nchannels = obt.nchannels; 712 obt_as.fmt = effective_fmt; 713 obt_as.endianness = endianness; 714 715 audio_pcm_init_info (&hw->info, &obt_as); 716 oss->nfrags = obt.nfrags; 717 oss->fragsize = obt.fragsize; 718 719 if (obt.nfrags * obt.fragsize & hw->info.align) { 720 dolog ("warning: Misaligned ADC buffer, size %d, alignment %d\n", 721 obt.nfrags * obt.fragsize, hw->info.align + 1); 722 } 723 724 hw->samples = (obt.nfrags * obt.fragsize) >> hw->info.shift; 725 oss->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift); 726 if (!oss->pcm_buf) { 727 dolog ("Could not allocate ADC buffer (%d samples, each %d bytes)\n", 728 hw->samples, 1 << hw->info.shift); 729 oss_anal_close (&fd); 730 return -1; 731 } 732 733 oss->fd = fd; 734 return 0; 735 } 736 737 static void oss_fini_in (HWVoiceIn *hw) 738 { 739 OSSVoiceIn *oss = (OSSVoiceIn *) hw; 740 741 oss_anal_close (&oss->fd); 742 743 if (oss->pcm_buf) { 744 g_free (oss->pcm_buf); 745 oss->pcm_buf = NULL; 746 } 747 } 748 749 static int oss_run_in (HWVoiceIn *hw) 750 { 751 OSSVoiceIn *oss = (OSSVoiceIn *) hw; 752 int hwshift = hw->info.shift; 753 int i; 754 int live = audio_pcm_hw_get_live_in (hw); 755 int dead = hw->samples - live; 756 size_t read_samples = 0; 757 struct { 758 int add; 759 int len; 760 } bufs[2] = { 761 { .add = hw->wpos, .len = 0 }, 762 { .add = 0, .len = 0 } 763 }; 764 765 if (!dead) { 766 return 0; 767 } 768 769 if (hw->wpos + dead > hw->samples) { 770 bufs[0].len = (hw->samples - hw->wpos) << hwshift; 771 bufs[1].len = (dead - (hw->samples - hw->wpos)) << hwshift; 772 } 773 else { 774 bufs[0].len = dead << hwshift; 775 } 776 777 for (i = 0; i < 2; ++i) { 778 ssize_t nread; 779 780 if (bufs[i].len) { 781 void *p = advance (oss->pcm_buf, bufs[i].add << hwshift); 782 nread = read (oss->fd, p, bufs[i].len); 783 784 if (nread > 0) { 785 if (nread & hw->info.align) { 786 dolog ("warning: Misaligned read %zd (requested %d), " 787 "alignment %d\n", nread, bufs[i].add << hwshift, 788 hw->info.align + 1); 789 } 790 read_samples += nread >> hwshift; 791 hw->conv (hw->conv_buf + bufs[i].add, p, nread >> hwshift); 792 } 793 794 if (bufs[i].len - nread) { 795 if (nread == -1) { 796 switch (errno) { 797 case EINTR: 798 case EAGAIN: 799 break; 800 default: 801 oss_logerr ( 802 errno, 803 "Failed to read %d bytes of audio (to %p)\n", 804 bufs[i].len, p 805 ); 806 break; 807 } 808 } 809 break; 810 } 811 } 812 } 813 814 hw->wpos = (hw->wpos + read_samples) % hw->samples; 815 return read_samples; 816 } 817 818 static int oss_read (SWVoiceIn *sw, void *buf, int size) 819 { 820 return audio_pcm_sw_read (sw, buf, size); 821 } 822 823 static int oss_ctl_in (HWVoiceIn *hw, int cmd, ...) 824 { 825 OSSVoiceIn *oss = (OSSVoiceIn *) hw; 826 827 switch (cmd) { 828 case VOICE_ENABLE: 829 { 830 va_list ap; 831 int poll_mode; 832 833 va_start (ap, cmd); 834 poll_mode = va_arg (ap, int); 835 va_end (ap); 836 837 if (poll_mode && oss_poll_in (hw)) { 838 poll_mode = 0; 839 } 840 hw->poll_mode = poll_mode; 841 } 842 break; 843 844 case VOICE_DISABLE: 845 if (hw->poll_mode) { 846 hw->poll_mode = 0; 847 qemu_set_fd_handler (oss->fd, NULL, NULL, NULL); 848 } 849 break; 850 } 851 return 0; 852 } 853 854 static void *oss_audio_init (void) 855 { 856 return &conf; 857 } 858 859 static void oss_audio_fini (void *opaque) 860 { 861 (void) opaque; 862 } 863 864 static struct audio_option oss_options[] = { 865 { 866 .name = "FRAGSIZE", 867 .tag = AUD_OPT_INT, 868 .valp = &conf.fragsize, 869 .descr = "Fragment size in bytes" 870 }, 871 { 872 .name = "NFRAGS", 873 .tag = AUD_OPT_INT, 874 .valp = &conf.nfrags, 875 .descr = "Number of fragments" 876 }, 877 { 878 .name = "MMAP", 879 .tag = AUD_OPT_BOOL, 880 .valp = &conf.try_mmap, 881 .descr = "Try using memory mapped access" 882 }, 883 { 884 .name = "DAC_DEV", 885 .tag = AUD_OPT_STR, 886 .valp = &conf.devpath_out, 887 .descr = "Path to DAC device" 888 }, 889 { 890 .name = "ADC_DEV", 891 .tag = AUD_OPT_STR, 892 .valp = &conf.devpath_in, 893 .descr = "Path to ADC device" 894 }, 895 { 896 .name = "EXCLUSIVE", 897 .tag = AUD_OPT_BOOL, 898 .valp = &conf.exclusive, 899 .descr = "Open device in exclusive mode (vmix wont work)" 900 }, 901 #ifdef USE_DSP_POLICY 902 { 903 .name = "POLICY", 904 .tag = AUD_OPT_INT, 905 .valp = &conf.policy, 906 .descr = "Set the timing policy of the device, -1 to use fragment mode", 907 }, 908 #endif 909 { 910 .name = "DEBUG", 911 .tag = AUD_OPT_BOOL, 912 .valp = &conf.debug, 913 .descr = "Turn on some debugging messages" 914 }, 915 { /* End of list */ } 916 }; 917 918 static struct audio_pcm_ops oss_pcm_ops = { 919 .init_out = oss_init_out, 920 .fini_out = oss_fini_out, 921 .run_out = oss_run_out, 922 .write = oss_write, 923 .ctl_out = oss_ctl_out, 924 925 .init_in = oss_init_in, 926 .fini_in = oss_fini_in, 927 .run_in = oss_run_in, 928 .read = oss_read, 929 .ctl_in = oss_ctl_in 930 }; 931 932 struct audio_driver oss_audio_driver = { 933 .name = "oss", 934 .descr = "OSS http://www.opensound.com", 935 .options = oss_options, 936 .init = oss_audio_init, 937 .fini = oss_audio_fini, 938 .pcm_ops = &oss_pcm_ops, 939 .can_be_default = 1, 940 .max_voices_out = INT_MAX, 941 .max_voices_in = INT_MAX, 942 .voice_size_out = sizeof (OSSVoiceOut), 943 .voice_size_in = sizeof (OSSVoiceIn) 944 }; 945