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