VirtualBox

source: vbox/trunk/src/VBox/Devices/Audio/ossaudio.c@ 400

Last change on this file since 400 was 366, checked in by vboxsync, 18 years ago

made mixing of pcm_in work

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

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette