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