|
|
1.1 root 1: /* 1.1.1.2 ! root 2: * QEMU OSS audio driver ! 3: * ! 4: * Copyright (c) 2003-2005 Vassili Karpov (malc) ! 5: * 1.1 root 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 <sys/mman.h> 25: #include <sys/types.h> 26: #include <sys/ioctl.h> 27: #include <sys/soundcard.h> 28: #include "vl.h" 29: 1.1.1.2 ! root 30: #define AUDIO_CAP "oss" ! 31: #include "audio_int.h" 1.1 root 32: 1.1.1.2 ! root 33: typedef struct OSSVoiceOut { ! 34: HWVoiceOut hw; 1.1 root 35: void *pcm_buf; 36: int fd; 37: int nfrags; 38: int fragsize; 39: int mmapped; 40: int old_optr; 1.1.1.2 ! root 41: } OSSVoiceOut; 1.1 root 42: 1.1.1.2 ! root 43: typedef struct OSSVoiceIn { ! 44: HWVoiceIn hw; ! 45: void *pcm_buf; ! 46: int fd; ! 47: int nfrags; ! 48: int fragsize; ! 49: int old_optr; ! 50: } OSSVoiceIn; 1.1 root 51: 52: static struct { 53: int try_mmap; 54: int nfrags; 55: int fragsize; 1.1.1.2 ! root 56: const char *devpath_out; ! 57: const char *devpath_in; 1.1 root 58: } conf = { 59: .try_mmap = 0, 60: .nfrags = 4, 61: .fragsize = 4096, 1.1.1.2 ! root 62: .devpath_out = "/dev/dsp", ! 63: .devpath_in = "/dev/dsp" 1.1 root 64: }; 65: 66: struct oss_params { 67: int freq; 68: audfmt_e fmt; 69: int nchannels; 70: int nfrags; 71: int fragsize; 72: }; 73: 1.1.1.2 ! root 74: static void GCC_FMT_ATTR (2, 3) oss_logerr (int err, const char *fmt, ...) ! 75: { ! 76: va_list ap; ! 77: ! 78: va_start (ap, fmt); ! 79: AUD_vlog (AUDIO_CAP, fmt, ap); ! 80: va_end (ap); ! 81: ! 82: AUD_log (AUDIO_CAP, "Reason: %s\n", strerror (err)); ! 83: } ! 84: ! 85: static void GCC_FMT_ATTR (3, 4) oss_logerr2 ( ! 86: int err, ! 87: const char *typ, ! 88: const char *fmt, ! 89: ... ! 90: ) ! 91: { ! 92: va_list ap; ! 93: ! 94: AUD_log (AUDIO_CAP, "Could not initialize %s\n", typ); ! 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 oss_anal_close (int *fdp) ! 104: { ! 105: int err = close (*fdp); ! 106: if (err) { ! 107: oss_logerr (errno, "Failed to close file(fd=%d)\n", *fdp); ! 108: } ! 109: *fdp = -1; ! 110: } ! 111: ! 112: static int oss_write (SWVoiceOut *sw, void *buf, int len) 1.1 root 113: { 1.1.1.2 ! root 114: return audio_pcm_sw_write (sw, buf, len); 1.1 root 115: } 116: 1.1.1.2 ! root 117: static int aud_to_ossfmt (audfmt_e fmt) 1.1 root 118: { 119: switch (fmt) { 1.1.1.2 ! root 120: case AUD_FMT_S8: ! 121: return AFMT_S8; ! 122: ! 123: case AUD_FMT_U8: ! 124: return AFMT_U8; ! 125: ! 126: case AUD_FMT_S16: ! 127: return AFMT_S16_LE; ! 128: ! 129: case AUD_FMT_U16: ! 130: return AFMT_U16_LE; ! 131: 1.1 root 132: default: 1.1.1.2 ! root 133: dolog ("Internal logic error: Bad audio format %d\n", fmt); ! 134: #ifdef DEBUG_AUDIO ! 135: abort (); ! 136: #endif ! 137: return AFMT_U8; 1.1 root 138: } 139: } 140: 1.1.1.2 ! root 141: static int oss_to_audfmt (int ossfmt, audfmt_e *fmt, int *endianness) 1.1 root 142: { 1.1.1.2 ! root 143: switch (ossfmt) { ! 144: case AFMT_S8: ! 145: *endianness =0; ! 146: *fmt = AUD_FMT_S8; ! 147: break; ! 148: ! 149: case AFMT_U8: ! 150: *endianness = 0; ! 151: *fmt = AUD_FMT_U8; ! 152: break; ! 153: ! 154: case AFMT_S16_LE: ! 155: *endianness = 0; ! 156: *fmt = AUD_FMT_S16; ! 157: break; ! 158: ! 159: case AFMT_U16_LE: ! 160: *endianness = 0; ! 161: *fmt = AUD_FMT_U16; ! 162: break; ! 163: ! 164: case AFMT_S16_BE: ! 165: *endianness = 1; ! 166: *fmt = AUD_FMT_S16; ! 167: break; ! 168: ! 169: case AFMT_U16_BE: ! 170: *endianness = 1; ! 171: *fmt = AUD_FMT_U16; ! 172: break; ! 173: 1.1 root 174: default: 1.1.1.2 ! root 175: dolog ("Unrecognized audio format %d\n", ossfmt); ! 176: return -1; 1.1 root 177: } 1.1.1.2 ! root 178: ! 179: return 0; 1.1 root 180: } 181: 1.1.1.2 ! root 182: #if defined DEBUG_MISMATCHES || defined DEBUG ! 183: static void oss_dump_info (struct oss_params *req, struct oss_params *obt) 1.1 root 184: { 185: dolog ("parameter | requested value | obtained value\n"); 186: dolog ("format | %10d | %10d\n", req->fmt, obt->fmt); 1.1.1.2 ! root 187: dolog ("channels | %10d | %10d\n", ! 188: req->nchannels, obt->nchannels); 1.1 root 189: dolog ("frequency | %10d | %10d\n", req->freq, obt->freq); 190: dolog ("nfrags | %10d | %10d\n", req->nfrags, obt->nfrags); 1.1.1.2 ! root 191: dolog ("fragsize | %10d | %10d\n", ! 192: req->fragsize, obt->fragsize); 1.1 root 193: } 194: #endif 195: 1.1.1.2 ! root 196: static int oss_open (int in, struct oss_params *req, ! 197: struct oss_params *obt, int *pfd) 1.1 root 198: { 199: int fd; 200: int mmmmssss; 201: audio_buf_info abinfo; 202: int fmt, freq, nchannels; 1.1.1.2 ! root 203: const char *dspname = in ? conf.devpath_in : conf.devpath_out; ! 204: const char *typ = in ? "ADC" : "DAC"; 1.1 root 205: 1.1.1.2 ! root 206: fd = open (dspname, (in ? O_RDONLY : O_WRONLY) | O_NONBLOCK); 1.1 root 207: if (-1 == fd) { 1.1.1.2 ! root 208: oss_logerr2 (errno, typ, "Failed to open `%s'\n", dspname); 1.1 root 209: return -1; 210: } 211: 212: freq = req->freq; 213: nchannels = req->nchannels; 214: fmt = req->fmt; 215: 216: if (ioctl (fd, SNDCTL_DSP_SAMPLESIZE, &fmt)) { 1.1.1.2 ! root 217: oss_logerr2 (errno, typ, "Failed to set sample size %d\n", req->fmt); 1.1 root 218: goto err; 219: } 220: 221: if (ioctl (fd, SNDCTL_DSP_CHANNELS, &nchannels)) { 1.1.1.2 ! root 222: oss_logerr2 (errno, typ, "Failed to set number of channels %d\n", ! 223: req->nchannels); 1.1 root 224: goto err; 225: } 226: 227: if (ioctl (fd, SNDCTL_DSP_SPEED, &freq)) { 1.1.1.2 ! root 228: oss_logerr2 (errno, typ, "Failed to set frequency %d\n", req->freq); 1.1 root 229: goto err; 230: } 231: 232: if (ioctl (fd, SNDCTL_DSP_NONBLOCK)) { 1.1.1.2 ! root 233: oss_logerr2 (errno, typ, "Failed to set non-blocking mode\n"); 1.1 root 234: goto err; 235: } 236: 237: mmmmssss = (req->nfrags << 16) | lsbindex (req->fragsize); 238: if (ioctl (fd, SNDCTL_DSP_SETFRAGMENT, &mmmmssss)) { 1.1.1.2 ! root 239: oss_logerr2 (errno, typ, "Failed to set buffer length (%d, %d)\n", ! 240: req->nfrags, req->fragsize); 1.1 root 241: goto err; 242: } 243: 1.1.1.2 ! root 244: if (ioctl (fd, in ? SNDCTL_DSP_GETISPACE : SNDCTL_DSP_GETOSPACE, &abinfo)) { ! 245: oss_logerr2 (errno, typ, "Failed to get buffer length\n"); 1.1 root 246: goto err; 247: } 248: 249: obt->fmt = fmt; 250: obt->nchannels = nchannels; 251: obt->freq = freq; 252: obt->nfrags = abinfo.fragstotal; 253: obt->fragsize = abinfo.fragsize; 254: *pfd = fd; 255: 1.1.1.2 ! root 256: #ifdef DEBUG_MISMATCHES 1.1 root 257: if ((req->fmt != obt->fmt) || 258: (req->nchannels != obt->nchannels) || 259: (req->freq != obt->freq) || 260: (req->fragsize != obt->fragsize) || 261: (req->nfrags != obt->nfrags)) { 262: dolog ("Audio parameters mismatch\n"); 1.1.1.2 ! root 263: oss_dump_info (req, obt); 1.1 root 264: } 1.1.1.2 ! root 265: #endif 1.1 root 266: 1.1.1.2 ! root 267: #ifdef DEBUG ! 268: oss_dump_info (req, obt); 1.1 root 269: #endif 270: return 0; 271: 1.1.1.2 ! root 272: err: ! 273: oss_anal_close (&fd); 1.1 root 274: return -1; 275: } 276: 1.1.1.2 ! root 277: static int oss_run_out (HWVoiceOut *hw) 1.1 root 278: { 1.1.1.2 ! root 279: OSSVoiceOut *oss = (OSSVoiceOut *) hw; 1.1 root 280: int err, rpos, live, decr; 281: int samples; 282: uint8_t *dst; 283: st_sample_t *src; 284: struct audio_buf_info abinfo; 285: struct count_info cntinfo; 1.1.1.2 ! root 286: int bufsize; ! 287: ! 288: live = audio_pcm_hw_get_live_out (hw); ! 289: if (!live) { ! 290: return 0; ! 291: } 1.1 root 292: 1.1.1.2 ! root 293: bufsize = hw->samples << hw->info.shift; 1.1 root 294: 295: if (oss->mmapped) { 296: int bytes; 297: 298: err = ioctl (oss->fd, SNDCTL_DSP_GETOPTR, &cntinfo); 299: if (err < 0) { 1.1.1.2 ! root 300: oss_logerr (errno, "SNDCTL_DSP_GETOPTR failed\n"); ! 301: return 0; 1.1 root 302: } 303: 304: if (cntinfo.ptr == oss->old_optr) { 1.1.1.2 ! root 305: if (abs (hw->samples - live) < 64) { ! 306: dolog ("warning: Overrun\n"); ! 307: } ! 308: return 0; 1.1 root 309: } 310: 311: if (cntinfo.ptr > oss->old_optr) { 312: bytes = cntinfo.ptr - oss->old_optr; 313: } 314: else { 1.1.1.2 ! root 315: bytes = bufsize + cntinfo.ptr - oss->old_optr; 1.1 root 316: } 317: 1.1.1.2 ! root 318: decr = audio_MIN (bytes >> hw->info.shift, live); 1.1 root 319: } 320: else { 321: err = ioctl (oss->fd, SNDCTL_DSP_GETOSPACE, &abinfo); 322: if (err < 0) { 1.1.1.2 ! root 323: oss_logerr (errno, "SNDCTL_DSP_GETOPTR failed\n"); ! 324: return 0; ! 325: } ! 326: ! 327: if (abinfo.bytes < 0 || abinfo.bytes > bufsize) { ! 328: ldebug ("warning: Invalid available size, size=%d bufsize=%d\n", ! 329: abinfo.bytes, bufsize); ! 330: return 0; 1.1 root 331: } 332: 1.1.1.2 ! root 333: decr = audio_MIN (abinfo.bytes >> hw->info.shift, live); ! 334: if (!decr) { ! 335: return 0; ! 336: } 1.1 root 337: } 338: 339: samples = decr; 340: rpos = hw->rpos; 341: while (samples) { 342: int left_till_end_samples = hw->samples - rpos; 343: int convert_samples = audio_MIN (samples, left_till_end_samples); 344: 1.1.1.2 ! root 345: src = hw->mix_buf + rpos; ! 346: dst = advance (oss->pcm_buf, rpos << hw->info.shift); 1.1 root 347: 348: hw->clip (dst, src, convert_samples); 349: if (!oss->mmapped) { 350: int written; 351: 1.1.1.2 ! root 352: written = write (oss->fd, dst, convert_samples << hw->info.shift); 1.1 root 353: /* XXX: follow errno recommendations ? */ 354: if (written == -1) { 1.1.1.2 ! root 355: oss_logerr ( ! 356: errno, ! 357: "Failed to write %d bytes of audio data from %p\n", ! 358: convert_samples << hw->info.shift, ! 359: dst ! 360: ); 1.1 root 361: continue; 362: } 363: 1.1.1.2 ! root 364: if (written != convert_samples << hw->info.shift) { ! 365: int wsamples = written >> hw->info.shift; ! 366: int wbytes = wsamples << hw->info.shift; 1.1 root 367: if (wbytes != written) { 1.1.1.2 ! root 368: dolog ("warning: Misaligned write %d (requested %d), " ! 369: "alignment %d\n", ! 370: wbytes, written, hw->info.align + 1); 1.1 root 371: } 1.1.1.2 ! root 372: mixeng_clear (src, wsamples); ! 373: decr -= wsamples; 1.1 root 374: rpos = (rpos + wsamples) % hw->samples; 375: break; 376: } 377: } 1.1.1.2 ! root 378: ! 379: mixeng_clear (src, convert_samples); 1.1 root 380: 381: rpos = (rpos + convert_samples) % hw->samples; 382: samples -= convert_samples; 383: } 384: if (oss->mmapped) { 385: oss->old_optr = cntinfo.ptr; 386: } 387: 388: hw->rpos = rpos; 1.1.1.2 ! root 389: return decr; 1.1 root 390: } 391: 1.1.1.2 ! root 392: static void oss_fini_out (HWVoiceOut *hw) 1.1 root 393: { 394: int err; 1.1.1.2 ! root 395: OSSVoiceOut *oss = (OSSVoiceOut *) hw; 1.1 root 396: 1.1.1.2 ! root 397: ldebug ("oss_fini\n"); ! 398: oss_anal_close (&oss->fd); 1.1 root 399: 400: if (oss->pcm_buf) { 401: if (oss->mmapped) { 1.1.1.2 ! root 402: err = munmap (oss->pcm_buf, hw->samples << hw->info.shift); 1.1 root 403: if (err) { 1.1.1.2 ! root 404: oss_logerr (errno, "Failed to unmap buffer %p, size %d\n", ! 405: oss->pcm_buf, hw->samples << hw->info.shift); 1.1 root 406: } 407: } 408: else { 409: qemu_free (oss->pcm_buf); 410: } 411: oss->pcm_buf = NULL; 412: } 413: } 414: 1.1.1.2 ! root 415: static int oss_init_out (HWVoiceOut *hw, audsettings_t *as) 1.1 root 416: { 1.1.1.2 ! root 417: OSSVoiceOut *oss = (OSSVoiceOut *) hw; 1.1 root 418: struct oss_params req, obt; 1.1.1.2 ! root 419: int endianness; ! 420: int err; ! 421: int fd; ! 422: audfmt_e effective_fmt; ! 423: audsettings_t obt_as; ! 424: ! 425: oss->fd = -1; 1.1 root 426: 1.1.1.2 ! root 427: req.fmt = aud_to_ossfmt (as->fmt); ! 428: req.freq = as->freq; ! 429: req.nchannels = as->nchannels; 1.1 root 430: req.fragsize = conf.fragsize; 431: req.nfrags = conf.nfrags; 432: 1.1.1.2 ! root 433: if (oss_open (0, &req, &obt, &fd)) { 1.1 root 434: return -1; 1.1.1.2 ! root 435: } 1.1 root 436: 1.1.1.2 ! root 437: err = oss_to_audfmt (obt.fmt, &effective_fmt, &endianness); ! 438: if (err) { ! 439: oss_anal_close (&fd); ! 440: return -1; ! 441: } 1.1 root 442: 1.1.1.2 ! root 443: obt_as.freq = obt.freq; ! 444: obt_as.nchannels = obt.nchannels; ! 445: obt_as.fmt = effective_fmt; ! 446: ! 447: audio_pcm_init_info ( ! 448: &hw->info, ! 449: &obt_as, ! 450: audio_need_to_swap_endian (endianness) ! 451: ); 1.1 root 452: oss->nfrags = obt.nfrags; 453: oss->fragsize = obt.fragsize; 1.1.1.2 ! root 454: ! 455: if (obt.nfrags * obt.fragsize & hw->info.align) { ! 456: dolog ("warning: Misaligned DAC buffer, size %d, alignment %d\n", ! 457: obt.nfrags * obt.fragsize, hw->info.align + 1); ! 458: } ! 459: ! 460: hw->samples = (obt.nfrags * obt.fragsize) >> hw->info.shift; 1.1 root 461: 462: oss->mmapped = 0; 463: if (conf.try_mmap) { 1.1.1.2 ! root 464: oss->pcm_buf = mmap ( ! 465: 0, ! 466: hw->samples << hw->info.shift, ! 467: PROT_READ | PROT_WRITE, ! 468: MAP_SHARED, ! 469: fd, ! 470: 0 ! 471: ); 1.1 root 472: if (oss->pcm_buf == MAP_FAILED) { 1.1.1.2 ! root 473: oss_logerr (errno, "Failed to map %d bytes of DAC\n", ! 474: hw->samples << hw->info.shift); 1.1 root 475: } else { 476: int err; 477: int trig = 0; 1.1.1.2 ! root 478: if (ioctl (fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) { ! 479: oss_logerr (errno, "SNDCTL_DSP_SETTRIGGER 0 failed\n"); 1.1 root 480: } 481: else { 482: trig = PCM_ENABLE_OUTPUT; 1.1.1.2 ! root 483: if (ioctl (fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) { ! 484: oss_logerr ( ! 485: errno, ! 486: "SNDCTL_DSP_SETTRIGGER PCM_ENABLE_OUTPUT failed\n" ! 487: ); 1.1 root 488: } 489: else { 490: oss->mmapped = 1; 491: } 492: } 493: 494: if (!oss->mmapped) { 1.1.1.2 ! root 495: err = munmap (oss->pcm_buf, hw->samples << hw->info.shift); 1.1 root 496: if (err) { 1.1.1.2 ! root 497: oss_logerr (errno, "Failed to unmap buffer %p size %d\n", ! 498: oss->pcm_buf, hw->samples << hw->info.shift); 1.1 root 499: } 500: } 501: } 502: } 503: 504: if (!oss->mmapped) { 1.1.1.2 ! root 505: oss->pcm_buf = audio_calloc ( ! 506: AUDIO_FUNC, ! 507: hw->samples, ! 508: 1 << hw->info.shift ! 509: ); 1.1 root 510: if (!oss->pcm_buf) { 1.1.1.2 ! root 511: dolog ( ! 512: "Could not allocate DAC buffer (%d samples, each %d bytes)\n", ! 513: hw->samples, ! 514: 1 << hw->info.shift ! 515: ); ! 516: oss_anal_close (&fd); 1.1 root 517: return -1; 518: } 519: } 520: 1.1.1.2 ! root 521: oss->fd = fd; 1.1 root 522: return 0; 523: } 524: 1.1.1.2 ! root 525: static int oss_ctl_out (HWVoiceOut *hw, int cmd, ...) 1.1 root 526: { 527: int trig; 1.1.1.2 ! root 528: OSSVoiceOut *oss = (OSSVoiceOut *) hw; 1.1 root 529: 1.1.1.2 ! root 530: if (!oss->mmapped) { 1.1 root 531: return 0; 1.1.1.2 ! root 532: } 1.1 root 533: 534: switch (cmd) { 535: case VOICE_ENABLE: 536: ldebug ("enabling voice\n"); 1.1.1.2 ! root 537: audio_pcm_info_clear_buf (&hw->info, oss->pcm_buf, hw->samples); 1.1 root 538: trig = PCM_ENABLE_OUTPUT; 539: if (ioctl (oss->fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) { 1.1.1.2 ! root 540: oss_logerr ( ! 541: errno, ! 542: "SNDCTL_DSP_SETTRIGGER PCM_ENABLE_OUTPUT failed\n" ! 543: ); 1.1 root 544: return -1; 545: } 546: break; 547: 548: case VOICE_DISABLE: 549: ldebug ("disabling voice\n"); 550: trig = 0; 551: if (ioctl (oss->fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) { 1.1.1.2 ! root 552: oss_logerr (errno, "SNDCTL_DSP_SETTRIGGER 0 failed\n"); 1.1 root 553: return -1; 554: } 555: break; 556: } 557: return 0; 558: } 559: 1.1.1.2 ! root 560: static int oss_init_in (HWVoiceIn *hw, audsettings_t *as) ! 561: { ! 562: OSSVoiceIn *oss = (OSSVoiceIn *) hw; ! 563: struct oss_params req, obt; ! 564: int endianness; ! 565: int err; ! 566: int fd; ! 567: audfmt_e effective_fmt; ! 568: audsettings_t obt_as; ! 569: ! 570: oss->fd = -1; ! 571: ! 572: req.fmt = aud_to_ossfmt (as->fmt); ! 573: req.freq = as->freq; ! 574: req.nchannels = as->nchannels; ! 575: req.fragsize = conf.fragsize; ! 576: req.nfrags = conf.nfrags; ! 577: if (oss_open (1, &req, &obt, &fd)) { ! 578: return -1; ! 579: } ! 580: ! 581: err = oss_to_audfmt (obt.fmt, &effective_fmt, &endianness); ! 582: if (err) { ! 583: oss_anal_close (&fd); ! 584: return -1; ! 585: } ! 586: ! 587: obt_as.freq = obt.freq; ! 588: obt_as.nchannels = obt.nchannels; ! 589: obt_as.fmt = effective_fmt; ! 590: ! 591: audio_pcm_init_info ( ! 592: &hw->info, ! 593: &obt_as, ! 594: audio_need_to_swap_endian (endianness) ! 595: ); ! 596: oss->nfrags = obt.nfrags; ! 597: oss->fragsize = obt.fragsize; ! 598: ! 599: if (obt.nfrags * obt.fragsize & hw->info.align) { ! 600: dolog ("warning: Misaligned ADC buffer, size %d, alignment %d\n", ! 601: obt.nfrags * obt.fragsize, hw->info.align + 1); ! 602: } ! 603: ! 604: hw->samples = (obt.nfrags * obt.fragsize) >> hw->info.shift; ! 605: oss->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift); ! 606: if (!oss->pcm_buf) { ! 607: dolog ("Could not allocate ADC buffer (%d samples, each %d bytes)\n", ! 608: hw->samples, 1 << hw->info.shift); ! 609: oss_anal_close (&fd); ! 610: return -1; ! 611: } ! 612: ! 613: oss->fd = fd; ! 614: return 0; ! 615: } ! 616: ! 617: static void oss_fini_in (HWVoiceIn *hw) ! 618: { ! 619: OSSVoiceIn *oss = (OSSVoiceIn *) hw; ! 620: ! 621: oss_anal_close (&oss->fd); ! 622: ! 623: if (oss->pcm_buf) { ! 624: qemu_free (oss->pcm_buf); ! 625: oss->pcm_buf = NULL; ! 626: } ! 627: } ! 628: ! 629: static int oss_run_in (HWVoiceIn *hw) ! 630: { ! 631: OSSVoiceIn *oss = (OSSVoiceIn *) hw; ! 632: int hwshift = hw->info.shift; ! 633: int i; ! 634: int live = audio_pcm_hw_get_live_in (hw); ! 635: int dead = hw->samples - live; ! 636: size_t read_samples = 0; ! 637: struct { ! 638: int add; ! 639: int len; ! 640: } bufs[2] = { ! 641: { hw->wpos, 0 }, ! 642: { 0, 0 } ! 643: }; ! 644: ! 645: if (!dead) { ! 646: return 0; ! 647: } ! 648: ! 649: if (hw->wpos + dead > hw->samples) { ! 650: bufs[0].len = (hw->samples - hw->wpos) << hwshift; ! 651: bufs[1].len = (dead - (hw->samples - hw->wpos)) << hwshift; ! 652: } ! 653: else { ! 654: bufs[0].len = dead << hwshift; ! 655: } ! 656: ! 657: ! 658: for (i = 0; i < 2; ++i) { ! 659: ssize_t nread; ! 660: ! 661: if (bufs[i].len) { ! 662: void *p = advance (oss->pcm_buf, bufs[i].add << hwshift); ! 663: nread = read (oss->fd, p, bufs[i].len); ! 664: ! 665: if (nread > 0) { ! 666: if (nread & hw->info.align) { ! 667: dolog ("warning: Misaligned read %zd (requested %d), " ! 668: "alignment %d\n", nread, bufs[i].add << hwshift, ! 669: hw->info.align + 1); ! 670: } ! 671: read_samples += nread >> hwshift; ! 672: hw->conv (hw->conv_buf + bufs[i].add, p, nread >> hwshift, ! 673: &nominal_volume); ! 674: } ! 675: ! 676: if (bufs[i].len - nread) { ! 677: if (nread == -1) { ! 678: switch (errno) { ! 679: case EINTR: ! 680: case EAGAIN: ! 681: break; ! 682: default: ! 683: oss_logerr ( ! 684: errno, ! 685: "Failed to read %d bytes of audio (to %p)\n", ! 686: bufs[i].len, p ! 687: ); ! 688: break; ! 689: } ! 690: } ! 691: break; ! 692: } ! 693: } ! 694: } ! 695: ! 696: hw->wpos = (hw->wpos + read_samples) % hw->samples; ! 697: return read_samples; ! 698: } ! 699: ! 700: static int oss_read (SWVoiceIn *sw, void *buf, int size) ! 701: { ! 702: return audio_pcm_sw_read (sw, buf, size); ! 703: } ! 704: ! 705: static int oss_ctl_in (HWVoiceIn *hw, int cmd, ...) ! 706: { ! 707: (void) hw; ! 708: (void) cmd; ! 709: return 0; ! 710: } ! 711: 1.1 root 712: static void *oss_audio_init (void) 713: { 714: return &conf; 715: } 716: 717: static void oss_audio_fini (void *opaque) 718: { 1.1.1.2 ! root 719: (void) opaque; 1.1 root 720: } 721: 1.1.1.2 ! root 722: static struct audio_option oss_options[] = { ! 723: {"FRAGSIZE", AUD_OPT_INT, &conf.fragsize, ! 724: "Fragment size in bytes", NULL, 0}, ! 725: {"NFRAGS", AUD_OPT_INT, &conf.nfrags, ! 726: "Number of fragments", NULL, 0}, ! 727: {"MMAP", AUD_OPT_BOOL, &conf.try_mmap, ! 728: "Try using memory mapped access", NULL, 0}, ! 729: {"DAC_DEV", AUD_OPT_STR, &conf.devpath_out, ! 730: "Path to DAC device", NULL, 0}, ! 731: {"ADC_DEV", AUD_OPT_STR, &conf.devpath_in, ! 732: "Path to ADC device", NULL, 0}, ! 733: {NULL, 0, NULL, NULL, NULL, 0} ! 734: }; ! 735: ! 736: static struct audio_pcm_ops oss_pcm_ops = { ! 737: oss_init_out, ! 738: oss_fini_out, ! 739: oss_run_out, ! 740: oss_write, ! 741: oss_ctl_out, ! 742: ! 743: oss_init_in, ! 744: oss_fini_in, ! 745: oss_run_in, ! 746: oss_read, ! 747: oss_ctl_in 1.1 root 748: }; 749: 1.1.1.2 ! root 750: struct audio_driver oss_audio_driver = { ! 751: INIT_FIELD (name = ) "oss", ! 752: INIT_FIELD (descr = ) "OSS http://www.opensound.com", ! 753: INIT_FIELD (options = ) oss_options, ! 754: INIT_FIELD (init = ) oss_audio_init, ! 755: INIT_FIELD (fini = ) oss_audio_fini, ! 756: INIT_FIELD (pcm_ops = ) &oss_pcm_ops, ! 757: INIT_FIELD (can_be_default = ) 1, ! 758: INIT_FIELD (max_voices_out = ) INT_MAX, ! 759: INIT_FIELD (max_voices_in = ) INT_MAX, ! 760: INIT_FIELD (voice_size_out = ) sizeof (OSSVoiceOut), ! 761: INIT_FIELD (voice_size_in = ) sizeof (OSSVoiceIn) 1.1 root 762: };
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.