VirtualBox

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

Last change on this file since 10758 was 3785, checked in by vboxsync, 17 years ago

Even more

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