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 "host-utils.h" 35 #include "qemu-char.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) 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 return AFMT_S16_LE; 175 176 case AUD_FMT_U16: 177 return AFMT_U16_LE; 178 179 default: 180 dolog ("Internal logic error: Bad audio format %d\n", fmt); 181 #ifdef DEBUG_AUDIO 182 abort (); 183 #endif 184 return AFMT_U8; 185 } 186 } 187 188 static int oss_to_audfmt (int ossfmt, audfmt_e *fmt, int *endianness) 189 { 190 switch (ossfmt) { 191 case AFMT_S8: 192 *endianness = 0; 193 *fmt = AUD_FMT_S8; 194 break; 195 196 case AFMT_U8: 197 *endianness = 0; 198 *fmt = AUD_FMT_U8; 199 break; 200 201 case AFMT_S16_LE: 202 *endianness = 0; 203 *fmt = AUD_FMT_S16; 204 break; 205 206 case AFMT_U16_LE: 207 *endianness = 0; 208 *fmt = AUD_FMT_U16; 209 break; 210 211 case AFMT_S16_BE: 212 *endianness = 1; 213 *fmt = AUD_FMT_S16; 214 break; 215 216 case AFMT_U16_BE: 217 *endianness = 1; 218 *fmt = AUD_FMT_U16; 219 break; 220 221 default: 222 dolog ("Unrecognized audio format %d\n", ossfmt); 223 return -1; 224 } 225 226 return 0; 227 } 228 229 #if defined DEBUG_MISMATCHES || defined DEBUG 230 static void oss_dump_info (struct oss_params *req, struct oss_params *obt) 231 { 232 dolog ("parameter | requested value | obtained value\n"); 233 dolog ("format | %10d | %10d\n", req->fmt, obt->fmt); 234 dolog ("channels | %10d | %10d\n", 235 req->nchannels, obt->nchannels); 236 dolog ("frequency | %10d | %10d\n", req->freq, obt->freq); 237 dolog ("nfrags | %10d | %10d\n", req->nfrags, obt->nfrags); 238 dolog ("fragsize | %10d | %10d\n", 239 req->fragsize, obt->fragsize); 240 } 241 #endif 242 243 #ifdef USE_DSP_POLICY 244 static int oss_get_version (int fd, int *version, const char *typ) 245 { 246 if (ioctl (fd, OSS_GETVERSION, &version)) { 247 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) 248 /* 249 * Looks like atm (20100109) FreeBSD knows OSS_GETVERSION 250 * since 7.x, but currently only on the mixer device (or in 251 * the Linuxolator), and in the native version that part of 252 * the code is in fact never reached so the ioctl fails anyway. 253 * Until this is fixed, just check the errno and if its what 254 * FreeBSD's sound drivers return atm assume they are new enough. 255 */ 256 if (errno == EINVAL) { 257 *version = 0x040000; 258 return 0; 259 } 260 #endif 261 oss_logerr2 (errno, typ, "Failed to get OSS version\n"); 262 return -1; 263 } 264 return 0; 265 } 266 #endif 267 268 static int oss_open (int in, struct oss_params *req, 269 struct oss_params *obt, int *pfd) 270 { 271 int fd; 272 int oflags = conf.exclusive ? O_EXCL : 0; 273 audio_buf_info abinfo; 274 int fmt, freq, nchannels; 275 int setfragment = 1; 276 const char *dspname = in ? conf.devpath_in : conf.devpath_out; 277 const char *typ = in ? "ADC" : "DAC"; 278 279 /* Kludge needed to have working mmap on Linux */ 280 oflags |= conf.try_mmap ? O_RDWR : (in ? O_RDONLY : O_WRONLY); 281 282 fd = open (dspname, oflags | O_NONBLOCK); 283 if (-1 == fd) { 284 oss_logerr2 (errno, typ, "Failed to open `%s'\n", dspname); 285 return -1; 286 } 287 288 freq = req->freq; 289 nchannels = req->nchannels; 290 fmt = req->fmt; 291 292 if (ioctl (fd, SNDCTL_DSP_SAMPLESIZE, &fmt)) { 293 oss_logerr2 (errno, typ, "Failed to set sample size %d\n", req->fmt); 294 goto err; 295 } 296 297 if (ioctl (fd, SNDCTL_DSP_CHANNELS, &nchannels)) { 298 oss_logerr2 (errno, typ, "Failed to set number of channels %d\n", 299 req->nchannels); 300 goto err; 301 } 302 303 if (ioctl (fd, SNDCTL_DSP_SPEED, &freq)) { 304 oss_logerr2 (errno, typ, "Failed to set frequency %d\n", req->freq); 305 goto err; 306 } 307 308 if (ioctl (fd, SNDCTL_DSP_NONBLOCK, NULL)) { 309 oss_logerr2 (errno, typ, "Failed to set non-blocking mode\n"); 310 goto err; 311 } 312 313 #ifdef USE_DSP_POLICY 314 if (conf.policy >= 0) { 315 int version; 316 317 if (!oss_get_version (fd, &version, typ)) { 318 if (conf.debug) { 319 dolog ("OSS version = %#x\n", version); 320 } 321 322 if (version >= 0x040000) { 323 int policy = conf.policy; 324 if (ioctl (fd, SNDCTL_DSP_POLICY, &policy)) { 325 oss_logerr2 (errno, typ, 326 "Failed to set timing policy to %d\n", 327 conf.policy); 328 goto err; 329 } 330 setfragment = 0; 331 } 332 } 333 } 334 #endif 335 336 if (setfragment) { 337 int mmmmssss = (req->nfrags << 16) | ctz32 (req->fragsize); 338 if (ioctl (fd, SNDCTL_DSP_SETFRAGMENT, &mmmmssss)) { 339 oss_logerr2 (errno, typ, "Failed to set buffer length (%d, %d)\n", 340 req->nfrags, req->fragsize); 341 goto err; 342 } 343 } 344 345 if (ioctl (fd, in ? SNDCTL_DSP_GETISPACE : SNDCTL_DSP_GETOSPACE, &abinfo)) { 346 oss_logerr2 (errno, typ, "Failed to get buffer length\n"); 347 goto err; 348 } 349 350 if (!abinfo.fragstotal || !abinfo.fragsize) { 351 AUD_log (AUDIO_CAP, "Returned bogus buffer information(%d, %d) for %s\n", 352 abinfo.fragstotal, abinfo.fragsize, typ); 353 goto err; 354 } 355 356 obt->fmt = fmt; 357 obt->nchannels = nchannels; 358 obt->freq = freq; 359 obt->nfrags = abinfo.fragstotal; 360 obt->fragsize = abinfo.fragsize; 361 *pfd = fd; 362 363 #ifdef DEBUG_MISMATCHES 364 if ((req->fmt != obt->fmt) || 365 (req->nchannels != obt->nchannels) || 366 (req->freq != obt->freq) || 367 (req->fragsize != obt->fragsize) || 368 (req->nfrags != obt->nfrags)) { 369 dolog ("Audio parameters mismatch\n"); 370 oss_dump_info (req, obt); 371 } 372 #endif 373 374 #ifdef DEBUG 375 oss_dump_info (req, obt); 376 #endif 377 return 0; 378 379 err: 380 oss_anal_close (&fd); 381 return -1; 382 } 383 384 static void oss_write_pending (OSSVoiceOut *oss) 385 { 386 HWVoiceOut *hw = &oss->hw; 387 388 if (oss->mmapped) { 389 return; 390 } 391 392 while (oss->pending) { 393 int samples_written; 394 ssize_t bytes_written; 395 int samples_till_end = hw->samples - oss->wpos; 396 int samples_to_write = audio_MIN (oss->pending, samples_till_end); 397 int bytes_to_write = samples_to_write << hw->info.shift; 398 void *pcm = advance (oss->pcm_buf, oss->wpos << hw->info.shift); 399 400 bytes_written = write (oss->fd, pcm, bytes_to_write); 401 if (bytes_written < 0) { 402 if (errno != EAGAIN) { 403 oss_logerr (errno, "failed to write %d bytes\n", 404 bytes_to_write); 405 } 406 break; 407 } 408 409 if (bytes_written & hw->info.align) { 410 dolog ("misaligned write asked for %d, but got %zd\n", 411 bytes_to_write, bytes_written); 412 return; 413 } 414 415 samples_written = bytes_written >> hw->info.shift; 416 oss->pending -= samples_written; 417 oss->wpos = (oss->wpos + samples_written) % hw->samples; 418 if (bytes_written - bytes_to_write) { 419 break; 420 } 421 } 422 } 423 424 static int oss_run_out (HWVoiceOut *hw, int live) 425 { 426 OSSVoiceOut *oss = (OSSVoiceOut *) hw; 427 int err, decr; 428 struct audio_buf_info abinfo; 429 struct count_info cntinfo; 430 int bufsize; 431 432 bufsize = hw->samples << hw->info.shift; 433 434 if (oss->mmapped) { 435 int bytes, pos; 436 437 err = ioctl (oss->fd, SNDCTL_DSP_GETOPTR, &cntinfo); 438 if (err < 0) { 439 oss_logerr (errno, "SNDCTL_DSP_GETOPTR failed\n"); 440 return 0; 441 } 442 443 pos = hw->rpos << hw->info.shift; 444 bytes = audio_ring_dist (cntinfo.ptr, pos, bufsize); 445 decr = audio_MIN (bytes >> hw->info.shift, live); 446 } 447 else { 448 err = ioctl (oss->fd, SNDCTL_DSP_GETOSPACE, &abinfo); 449 if (err < 0) { 450 oss_logerr (errno, "SNDCTL_DSP_GETOPTR failed\n"); 451 return 0; 452 } 453 454 if (abinfo.bytes > bufsize) { 455 if (conf.debug) { 456 dolog ("warning: Invalid available size, size=%d bufsize=%d\n" 457 "please report your OS/audio hw to av1474 (at) comtv.ru\n", 458 abinfo.bytes, bufsize); 459 } 460 abinfo.bytes = bufsize; 461 } 462 463 if (abinfo.bytes < 0) { 464 if (conf.debug) { 465 dolog ("warning: Invalid available size, size=%d bufsize=%d\n", 466 abinfo.bytes, bufsize); 467 } 468 return 0; 469 } 470 471 decr = audio_MIN (abinfo.bytes >> hw->info.shift, live); 472 if (!decr) { 473 return 0; 474 } 475 } 476 477 decr = audio_pcm_hw_clip_out (hw, oss->pcm_buf, decr, oss->pending); 478 oss->pending += decr; 479 oss_write_pending (oss); 480 481 return decr; 482 } 483 484 static void oss_fini_out (HWVoiceOut *hw) 485 { 486 int err; 487 OSSVoiceOut *oss = (OSSVoiceOut *) hw; 488 489 ldebug ("oss_fini\n"); 490 oss_anal_close (&oss->fd); 491 492 if (oss->pcm_buf) { 493 if (oss->mmapped) { 494 err = munmap (oss->pcm_buf, hw->samples << hw->info.shift); 495 if (err) { 496 oss_logerr (errno, "Failed to unmap buffer %p, size %d\n", 497 oss->pcm_buf, hw->samples << hw->info.shift); 498 } 499 } 500 else { 501 qemu_free (oss->pcm_buf); 502 } 503 oss->pcm_buf = NULL; 504 } 505 } 506 507 static int oss_init_out (HWVoiceOut *hw, struct audsettings *as) 508 { 509 OSSVoiceOut *oss = (OSSVoiceOut *) hw; 510 struct oss_params req, obt; 511 int endianness; 512 int err; 513 int fd; 514 audfmt_e effective_fmt; 515 struct audsettings obt_as; 516 517 oss->fd = -1; 518 519 req.fmt = aud_to_ossfmt (as->fmt); 520 req.freq = as->freq; 521 req.nchannels = as->nchannels; 522 req.fragsize = conf.fragsize; 523 req.nfrags = conf.nfrags; 524 525 if (oss_open (0, &req, &obt, &fd)) { 526 return -1; 527 } 528 529 err = oss_to_audfmt (obt.fmt, &effective_fmt, &endianness); 530 if (err) { 531 oss_anal_close (&fd); 532 return -1; 533 } 534 535 obt_as.freq = obt.freq; 536 obt_as.nchannels = obt.nchannels; 537 obt_as.fmt = effective_fmt; 538 obt_as.endianness = endianness; 539 540 audio_pcm_init_info (&hw->info, &obt_as); 541 oss->nfrags = obt.nfrags; 542 oss->fragsize = obt.fragsize; 543 544 if (obt.nfrags * obt.fragsize & hw->info.align) { 545 dolog ("warning: Misaligned DAC buffer, size %d, alignment %d\n", 546 obt.nfrags * obt.fragsize, hw->info.align + 1); 547 } 548 549 hw->samples = (obt.nfrags * obt.fragsize) >> hw->info.shift; 550 551 oss->mmapped = 0; 552 if (conf.try_mmap) { 553 oss->pcm_buf = mmap ( 554 NULL, 555 hw->samples << hw->info.shift, 556 PROT_READ | PROT_WRITE, 557 MAP_SHARED, 558 fd, 559 0 560 ); 561 if (oss->pcm_buf == MAP_FAILED) { 562 oss_logerr (errno, "Failed to map %d bytes of DAC\n", 563 hw->samples << hw->info.shift); 564 } 565 else { 566 int err; 567 int trig = 0; 568 if (ioctl (fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) { 569 oss_logerr (errno, "SNDCTL_DSP_SETTRIGGER 0 failed\n"); 570 } 571 else { 572 trig = PCM_ENABLE_OUTPUT; 573 if (ioctl (fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) { 574 oss_logerr ( 575 errno, 576 "SNDCTL_DSP_SETTRIGGER PCM_ENABLE_OUTPUT failed\n" 577 ); 578 } 579 else { 580 oss->mmapped = 1; 581 } 582 } 583 584 if (!oss->mmapped) { 585 err = munmap (oss->pcm_buf, hw->samples << hw->info.shift); 586 if (err) { 587 oss_logerr (errno, "Failed to unmap buffer %p size %d\n", 588 oss->pcm_buf, hw->samples << hw->info.shift); 589 } 590 } 591 } 592 } 593 594 if (!oss->mmapped) { 595 oss->pcm_buf = audio_calloc ( 596 AUDIO_FUNC, 597 hw->samples, 598 1 << hw->info.shift 599 ); 600 if (!oss->pcm_buf) { 601 dolog ( 602 "Could not allocate DAC buffer (%d samples, each %d bytes)\n", 603 hw->samples, 604 1 << hw->info.shift 605 ); 606 oss_anal_close (&fd); 607 return -1; 608 } 609 } 610 611 oss->fd = fd; 612 return 0; 613 } 614 615 static int oss_ctl_out (HWVoiceOut *hw, int cmd, ...) 616 { 617 int trig; 618 OSSVoiceOut *oss = (OSSVoiceOut *) hw; 619 620 switch (cmd) { 621 case VOICE_ENABLE: 622 { 623 va_list ap; 624 int poll_mode; 625 626 va_start (ap, cmd); 627 poll_mode = va_arg (ap, int); 628 va_end (ap); 629 630 ldebug ("enabling voice\n"); 631 if (poll_mode && oss_poll_out (hw)) { 632 poll_mode = 0; 633 } 634 hw->poll_mode = poll_mode; 635 636 if (!oss->mmapped) { 637 return 0; 638 } 639 640 audio_pcm_info_clear_buf (&hw->info, oss->pcm_buf, hw->samples); 641 trig = PCM_ENABLE_OUTPUT; 642 if (ioctl (oss->fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) { 643 oss_logerr ( 644 errno, 645 "SNDCTL_DSP_SETTRIGGER PCM_ENABLE_OUTPUT failed\n" 646 ); 647 return -1; 648 } 649 } 650 break; 651 652 case VOICE_DISABLE: 653 if (hw->poll_mode) { 654 qemu_set_fd_handler (oss->fd, NULL, NULL, NULL); 655 hw->poll_mode = 0; 656 } 657 658 if (!oss->mmapped) { 659 return 0; 660 } 661 662 ldebug ("disabling voice\n"); 663 trig = 0; 664 if (ioctl (oss->fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) { 665 oss_logerr (errno, "SNDCTL_DSP_SETTRIGGER 0 failed\n"); 666 return -1; 667 } 668 break; 669 } 670 return 0; 671 } 672 673 static int oss_init_in (HWVoiceIn *hw, struct audsettings *as) 674 { 675 OSSVoiceIn *oss = (OSSVoiceIn *) hw; 676 struct oss_params req, obt; 677 int endianness; 678 int err; 679 int fd; 680 audfmt_e effective_fmt; 681 struct audsettings obt_as; 682 683 oss->fd = -1; 684 685 req.fmt = aud_to_ossfmt (as->fmt); 686 req.freq = as->freq; 687 req.nchannels = as->nchannels; 688 req.fragsize = conf.fragsize; 689 req.nfrags = conf.nfrags; 690 if (oss_open (1, &req, &obt, &fd)) { 691 return -1; 692 } 693 694 err = oss_to_audfmt (obt.fmt, &effective_fmt, &endianness); 695 if (err) { 696 oss_anal_close (&fd); 697 return -1; 698 } 699 700 obt_as.freq = obt.freq; 701 obt_as.nchannels = obt.nchannels; 702 obt_as.fmt = effective_fmt; 703 obt_as.endianness = endianness; 704 705 audio_pcm_init_info (&hw->info, &obt_as); 706 oss->nfrags = obt.nfrags; 707 oss->fragsize = obt.fragsize; 708 709 if (obt.nfrags * obt.fragsize & hw->info.align) { 710 dolog ("warning: Misaligned ADC buffer, size %d, alignment %d\n", 711 obt.nfrags * obt.fragsize, hw->info.align + 1); 712 } 713 714 hw->samples = (obt.nfrags * obt.fragsize) >> hw->info.shift; 715 oss->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift); 716 if (!oss->pcm_buf) { 717 dolog ("Could not allocate ADC buffer (%d samples, each %d bytes)\n", 718 hw->samples, 1 << hw->info.shift); 719 oss_anal_close (&fd); 720 return -1; 721 } 722 723 oss->fd = fd; 724 return 0; 725 } 726 727 static void oss_fini_in (HWVoiceIn *hw) 728 { 729 OSSVoiceIn *oss = (OSSVoiceIn *) hw; 730 731 oss_anal_close (&oss->fd); 732 733 if (oss->pcm_buf) { 734 qemu_free (oss->pcm_buf); 735 oss->pcm_buf = NULL; 736 } 737 } 738 739 static int oss_run_in (HWVoiceIn *hw) 740 { 741 OSSVoiceIn *oss = (OSSVoiceIn *) hw; 742 int hwshift = hw->info.shift; 743 int i; 744 int live = audio_pcm_hw_get_live_in (hw); 745 int dead = hw->samples - live; 746 size_t read_samples = 0; 747 struct { 748 int add; 749 int len; 750 } bufs[2] = { 751 { .add = hw->wpos, .len = 0 }, 752 { .add = 0, .len = 0 } 753 }; 754 755 if (!dead) { 756 return 0; 757 } 758 759 if (hw->wpos + dead > hw->samples) { 760 bufs[0].len = (hw->samples - hw->wpos) << hwshift; 761 bufs[1].len = (dead - (hw->samples - hw->wpos)) << hwshift; 762 } 763 else { 764 bufs[0].len = dead << hwshift; 765 } 766 767 for (i = 0; i < 2; ++i) { 768 ssize_t nread; 769 770 if (bufs[i].len) { 771 void *p = advance (oss->pcm_buf, bufs[i].add << hwshift); 772 nread = read (oss->fd, p, bufs[i].len); 773 774 if (nread > 0) { 775 if (nread & hw->info.align) { 776 dolog ("warning: Misaligned read %zd (requested %d), " 777 "alignment %d\n", nread, bufs[i].add << hwshift, 778 hw->info.align + 1); 779 } 780 read_samples += nread >> hwshift; 781 hw->conv (hw->conv_buf + bufs[i].add, p, nread >> hwshift, 782 &nominal_volume); 783 } 784 785 if (bufs[i].len - nread) { 786 if (nread == -1) { 787 switch (errno) { 788 case EINTR: 789 case EAGAIN: 790 break; 791 default: 792 oss_logerr ( 793 errno, 794 "Failed to read %d bytes of audio (to %p)\n", 795 bufs[i].len, p 796 ); 797 break; 798 } 799 } 800 break; 801 } 802 } 803 } 804 805 hw->wpos = (hw->wpos + read_samples) % hw->samples; 806 return read_samples; 807 } 808 809 static int oss_read (SWVoiceIn *sw, void *buf, int size) 810 { 811 return audio_pcm_sw_read (sw, buf, size); 812 } 813 814 static int oss_ctl_in (HWVoiceIn *hw, int cmd, ...) 815 { 816 OSSVoiceIn *oss = (OSSVoiceIn *) hw; 817 818 switch (cmd) { 819 case VOICE_ENABLE: 820 { 821 va_list ap; 822 int poll_mode; 823 824 va_start (ap, cmd); 825 poll_mode = va_arg (ap, int); 826 va_end (ap); 827 828 if (poll_mode && oss_poll_in (hw)) { 829 poll_mode = 0; 830 } 831 hw->poll_mode = poll_mode; 832 } 833 break; 834 835 case VOICE_DISABLE: 836 if (hw->poll_mode) { 837 hw->poll_mode = 0; 838 qemu_set_fd_handler (oss->fd, NULL, NULL, NULL); 839 } 840 break; 841 } 842 return 0; 843 } 844 845 static void *oss_audio_init (void) 846 { 847 return &conf; 848 } 849 850 static void oss_audio_fini (void *opaque) 851 { 852 (void) opaque; 853 } 854 855 static struct audio_option oss_options[] = { 856 { 857 .name = "FRAGSIZE", 858 .tag = AUD_OPT_INT, 859 .valp = &conf.fragsize, 860 .descr = "Fragment size in bytes" 861 }, 862 { 863 .name = "NFRAGS", 864 .tag = AUD_OPT_INT, 865 .valp = &conf.nfrags, 866 .descr = "Number of fragments" 867 }, 868 { 869 .name = "MMAP", 870 .tag = AUD_OPT_BOOL, 871 .valp = &conf.try_mmap, 872 .descr = "Try using memory mapped access" 873 }, 874 { 875 .name = "DAC_DEV", 876 .tag = AUD_OPT_STR, 877 .valp = &conf.devpath_out, 878 .descr = "Path to DAC device" 879 }, 880 { 881 .name = "ADC_DEV", 882 .tag = AUD_OPT_STR, 883 .valp = &conf.devpath_in, 884 .descr = "Path to ADC device" 885 }, 886 { 887 .name = "EXCLUSIVE", 888 .tag = AUD_OPT_BOOL, 889 .valp = &conf.exclusive, 890 .descr = "Open device in exclusive mode (vmix wont work)" 891 }, 892 #ifdef USE_DSP_POLICY 893 { 894 .name = "POLICY", 895 .tag = AUD_OPT_INT, 896 .valp = &conf.policy, 897 .descr = "Set the timing policy of the device, -1 to use fragment mode", 898 }, 899 #endif 900 { 901 .name = "DEBUG", 902 .tag = AUD_OPT_BOOL, 903 .valp = &conf.debug, 904 .descr = "Turn on some debugging messages" 905 }, 906 { /* End of list */ } 907 }; 908 909 static struct audio_pcm_ops oss_pcm_ops = { 910 .init_out = oss_init_out, 911 .fini_out = oss_fini_out, 912 .run_out = oss_run_out, 913 .write = oss_write, 914 .ctl_out = oss_ctl_out, 915 916 .init_in = oss_init_in, 917 .fini_in = oss_fini_in, 918 .run_in = oss_run_in, 919 .read = oss_read, 920 .ctl_in = oss_ctl_in 921 }; 922 923 struct audio_driver oss_audio_driver = { 924 .name = "oss", 925 .descr = "OSS http://www.opensound.com", 926 .options = oss_options, 927 .init = oss_audio_init, 928 .fini = oss_audio_fini, 929 .pcm_ops = &oss_pcm_ops, 930 .can_be_default = 1, 931 .max_voices_out = INT_MAX, 932 .max_voices_in = INT_MAX, 933 .voice_size_out = sizeof (OSSVoiceOut), 934 .voice_size_in = sizeof (OSSVoiceIn) 935 }; 936