VirtualBox

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

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

RT_OS_L4

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 22.3 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 RT_OS_L4
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 RT_OS_L4
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 RT_OS_L4
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(("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(("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(("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(("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(("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(("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(("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(("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(("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#ifndef RT_OS_L4
344 struct count_info cntinfo;
345#endif
346 int bufsize;
347
348 live = audio_pcm_hw_get_live_out (hw);
349 if (!live) {
350 return 0;
351 }
352
353 bufsize = hw->samples << hw->info.shift;
354
355#ifndef RT_OS_L4
356 if (oss->mmapped) {
357 int bytes;
358
359 err = ioctl (oss->fd, SNDCTL_DSP_GETOPTR, &cntinfo);
360 if (err < 0) {
361 oss_logerr (errno, "SNDCTL_DSP_GETOPTR failed\n");
362 return 0;
363 }
364
365 if (cntinfo.ptr == oss->old_optr) {
366 if (abs (hw->samples - live) < 64) {
367 dolog ("warning: Overrun\n");
368 }
369 return 0;
370 }
371
372 if (cntinfo.ptr > oss->old_optr) {
373 bytes = cntinfo.ptr - oss->old_optr;
374 }
375 else {
376 bytes = bufsize + cntinfo.ptr - oss->old_optr;
377 }
378
379 decr = audio_MIN (bytes >> hw->info.shift, live);
380 }
381 else {
382#endif
383 err = ioctl (oss->fd, SNDCTL_DSP_GETOSPACE, &abinfo);
384 if (err < 0) {
385 oss_logerr (errno, "SNDCTL_DSP_GETOPTR failed\n");
386 return 0;
387 }
388
389 if (abinfo.bytes > bufsize) {
390 if (conf.debug) {
391 dolog ("warning: Invalid available size, size=%d bufsize=%d\n"
392 "please report your OS/audio hw to malc@pulsesoft.com\n",
393 abinfo.bytes, bufsize);
394 }
395 abinfo.bytes = bufsize;
396 }
397
398 if (abinfo.bytes < 0) {
399 if (conf.debug) {
400 dolog ("warning: Invalid available size, size=%d bufsize=%d\n",
401 abinfo.bytes, bufsize);
402 }
403 return 0;
404 }
405
406 decr = audio_MIN (abinfo.bytes >> hw->info.shift, live);
407 if (!decr) {
408 return 0;
409 }
410#ifndef RT_OS_L4
411 }
412#endif
413
414 samples = decr;
415 rpos = hw->rpos;
416 while (samples) {
417 int left_till_end_samples = hw->samples - rpos;
418 int convert_samples = audio_MIN (samples, left_till_end_samples);
419
420 src = hw->mix_buf + rpos;
421 dst = advance (oss->pcm_buf, rpos << hw->info.shift);
422
423 hw->clip (dst, src, convert_samples);
424#ifdef RT_OS_L4
425 {
426#else
427 if (!oss->mmapped) {
428#endif
429 int written;
430
431 written = write (oss->fd, dst, convert_samples << hw->info.shift);
432 /* XXX: follow errno recommendations ? */
433 if (written == -1) {
434 oss_logerr (
435 errno,
436 "Failed to write %d bytes of audio data from %p\n",
437 convert_samples << hw->info.shift,
438 dst
439 );
440 continue;
441 }
442
443 if (written != convert_samples << hw->info.shift) {
444 int wsamples = written >> hw->info.shift;
445 int wbytes = wsamples << hw->info.shift;
446 if (wbytes != written) {
447 dolog ("warning: Misaligned write %d (requested %d), "
448 "alignment %d\n",
449 wbytes, written, hw->info.align + 1);
450 }
451#if 0
452 mixeng_sniff_and_clear (hw, src, dst, wsamples);
453#endif
454 decr -= wsamples;
455 rpos = (rpos + wsamples) % hw->samples;
456 break;
457 }
458 }
459
460#if 0
461 mixeng_sniff_and_clear (hw, src, dst, convert_samples);
462#endif
463
464 rpos = (rpos + convert_samples) % hw->samples;
465 samples -= convert_samples;
466 }
467
468#ifndef RT_OS_L4
469 if (oss->mmapped) {
470 oss->old_optr = cntinfo.ptr;
471 }
472#endif
473
474 hw->rpos = rpos;
475 return decr;
476}
477
478static void oss_fini_out (HWVoiceOut *hw)
479{
480#ifndef RT_OS_L4
481 int err;
482#endif
483 OSSVoiceOut *oss = (OSSVoiceOut *) hw;
484
485 ldebug ("oss_fini\n");
486 oss_anal_close (&oss->fd);
487#ifdef VBOX
488 LogRel(("OSS: Closed %s for DAC\n", conf.devpath_out));
489#endif
490
491 if (oss->pcm_buf) {
492#ifdef RT_OS_L4
493 qemu_free (oss->pcm_buf);
494#else
495 if (oss->mmapped) {
496 err = munmap (oss->pcm_buf, hw->samples << hw->info.shift);
497 if (err) {
498 oss_logerr (errno, "Failed to unmap buffer %p, size %d\n",
499 oss->pcm_buf, hw->samples << hw->info.shift);
500 }
501 }
502 else {
503 qemu_free (oss->pcm_buf);
504 }
505#endif
506 oss->pcm_buf = NULL;
507 }
508}
509
510static int oss_init_out (HWVoiceOut *hw, audsettings_t *as)
511{
512 OSSVoiceOut *oss = (OSSVoiceOut *) hw;
513 struct oss_params req, obt;
514 int endianness;
515 int err;
516 int fd;
517 audfmt_e effective_fmt;
518 audsettings_t obt_as;
519
520 oss->fd = -1;
521
522 req.fmt = aud_to_ossfmt (as->fmt);
523 req.freq = as->freq;
524 req.nchannels = as->nchannels;
525 req.fragsize = conf.fragsize;
526 req.nfrags = conf.nfrags;
527
528 if (oss_open (0, &req, &obt, &fd)) {
529 return -1;
530 }
531
532 err = oss_to_audfmt (obt.fmt, &effective_fmt, &endianness);
533 if (err) {
534 oss_anal_close (&fd);
535#ifdef VBOX
536 LogRel(("OSS: Closed %s for DAC\n", conf.devpath_out));
537#endif
538 return -1;
539 }
540
541 obt_as.freq = obt.freq;
542 obt_as.nchannels = obt.nchannels;
543 obt_as.fmt = effective_fmt;
544 obt_as.endianness = endianness;
545
546 audio_pcm_init_info (&hw->info, &obt_as);
547 oss->nfrags = obt.nfrags;
548 oss->fragsize = obt.fragsize;
549
550 if (obt.nfrags * obt.fragsize & hw->info.align) {
551 dolog ("warning: Misaligned DAC buffer, size %d, alignment %d\n",
552 obt.nfrags * obt.fragsize, hw->info.align + 1);
553 }
554
555 hw->samples = (obt.nfrags * obt.fragsize) >> hw->info.shift;
556
557#ifndef RT_OS_L4
558 oss->mmapped = 0;
559 if (conf.try_mmap) {
560 oss->pcm_buf = mmap (
561 0,
562 hw->samples << hw->info.shift,
563 PROT_READ | PROT_WRITE,
564 MAP_SHARED,
565 fd,
566 0
567 );
568 if (oss->pcm_buf == MAP_FAILED) {
569 oss_logerr (errno, "Failed to map %d bytes of DAC\n",
570 hw->samples << hw->info.shift);
571 } else {
572 int err;
573 int trig = 0;
574 if (ioctl (fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) {
575 oss_logerr (errno, "SNDCTL_DSP_SETTRIGGER 0 failed\n");
576 }
577 else {
578 trig = PCM_ENABLE_OUTPUT;
579 if (ioctl (fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) {
580 oss_logerr (
581 errno,
582 "SNDCTL_DSP_SETTRIGGER PCM_ENABLE_OUTPUT failed\n"
583 );
584 }
585 else {
586 oss->mmapped = 1;
587 }
588 }
589
590 if (!oss->mmapped) {
591 err = munmap (oss->pcm_buf, hw->samples << hw->info.shift);
592 if (err) {
593 oss_logerr (errno, "Failed to unmap buffer %p size %d\n",
594 oss->pcm_buf, hw->samples << hw->info.shift);
595 }
596 }
597 }
598 }
599#endif
600
601#ifndef RT_OS_L4
602 if (!oss->mmapped) {
603#endif
604 oss->pcm_buf = audio_calloc (
605 AUDIO_FUNC,
606 hw->samples,
607 1 << hw->info.shift
608 );
609 if (!oss->pcm_buf) {
610 dolog (
611 "Could not allocate DAC buffer (%d samples, each %d bytes)\n",
612 hw->samples,
613 1 << hw->info.shift
614 );
615 oss_anal_close (&fd);
616#ifdef VBOX
617 LogRel(("OSS: Closed %s for DAC\n", conf.devpath_out));
618#endif
619 return -1;
620 }
621#ifndef RT_OS_L4
622 }
623#endif
624
625 oss->fd = fd;
626 return 0;
627}
628
629static int oss_ctl_out (HWVoiceOut *hw, int cmd, ...)
630{
631 int trig;
632 OSSVoiceOut *oss = (OSSVoiceOut *) hw;
633
634#ifdef RT_OS_L4
635 return 0;
636#else
637 if (!oss->mmapped) {
638 return 0;
639 }
640#endif
641
642 switch (cmd) {
643 case VOICE_ENABLE:
644 ldebug ("enabling voice\n");
645 audio_pcm_info_clear_buf (&hw->info, oss->pcm_buf, hw->samples);
646 trig = PCM_ENABLE_OUTPUT;
647 if (ioctl (oss->fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) {
648 oss_logerr (
649 errno,
650 "SNDCTL_DSP_SETTRIGGER PCM_ENABLE_OUTPUT failed\n"
651 );
652 return -1;
653 }
654 break;
655
656 case VOICE_DISABLE:
657 ldebug ("disabling voice\n");
658 trig = 0;
659 if (ioctl (oss->fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) {
660 oss_logerr (errno, "SNDCTL_DSP_SETTRIGGER 0 failed\n");
661 return -1;
662 }
663 break;
664 }
665 return 0;
666}
667
668static int oss_init_in (HWVoiceIn *hw, audsettings_t *as)
669{
670 OSSVoiceIn *oss = (OSSVoiceIn *) hw;
671 struct oss_params req, obt;
672 int endianness;
673 int err;
674 int fd;
675 audfmt_e effective_fmt;
676 audsettings_t obt_as;
677
678 oss->fd = -1;
679
680 req.fmt = aud_to_ossfmt (as->fmt);
681 req.freq = as->freq;
682 req.nchannels = as->nchannels;
683 req.fragsize = conf.fragsize;
684 req.nfrags = conf.nfrags;
685 if (oss_open (1, &req, &obt, &fd)) {
686 return -1;
687 }
688
689 err = oss_to_audfmt (obt.fmt, &effective_fmt, &endianness);
690 if (err) {
691 oss_anal_close (&fd);
692#ifdef VBOX
693 LogRel(("OSS: Closed %s for ADC\n", conf.devpath_in));
694#endif
695 return -1;
696 }
697
698 obt_as.freq = obt.freq;
699 obt_as.nchannels = obt.nchannels;
700 obt_as.fmt = effective_fmt;
701 obt_as.endianness = endianness;
702
703 audio_pcm_init_info (&hw->info, &obt_as);
704 oss->nfrags = obt.nfrags;
705 oss->fragsize = obt.fragsize;
706
707 if (obt.nfrags * obt.fragsize & hw->info.align) {
708 dolog ("warning: Misaligned ADC buffer, size %d, alignment %d\n",
709 obt.nfrags * obt.fragsize, hw->info.align + 1);
710 }
711
712 hw->samples = (obt.nfrags * obt.fragsize) >> hw->info.shift;
713 oss->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift);
714 if (!oss->pcm_buf) {
715 dolog ("Could not allocate ADC buffer (%d samples, each %d bytes)\n",
716 hw->samples, 1 << hw->info.shift);
717 oss_anal_close (&fd);
718#ifdef VBOX
719 LogRel(("OSS: Closed %s for ADC\n", conf.devpath_in));
720#endif
721 return -1;
722 }
723
724 oss->fd = fd;
725 return 0;
726}
727
728static void oss_fini_in (HWVoiceIn *hw)
729{
730 OSSVoiceIn *oss = (OSSVoiceIn *) hw;
731
732 oss_anal_close (&oss->fd);
733#ifdef VBOX
734 LogRel(("OSS: Closed %s for ADC\n", conf.devpath_in));
735#endif
736
737 if (oss->pcm_buf) {
738 qemu_free (oss->pcm_buf);
739 oss->pcm_buf = NULL;
740 }
741}
742
743static int oss_run_in (HWVoiceIn *hw)
744{
745 OSSVoiceIn *oss = (OSSVoiceIn *) hw;
746 int hwshift = hw->info.shift;
747 int i;
748 int live = audio_pcm_hw_get_live_in (hw);
749 int dead = hw->samples - live;
750 size_t read_samples = 0;
751 struct {
752 int add;
753 int len;
754 } bufs[2];
755
756 bufs[0].add = hw->wpos;
757 bufs[0].len = 0;
758 bufs[1].add = 0;
759 bufs[1].len = 0;
760
761 if (!dead) {
762 return 0;
763 }
764
765 if (hw->wpos + dead > hw->samples) {
766 bufs[0].len = (hw->samples - hw->wpos) << hwshift;
767 bufs[1].len = (dead - (hw->samples - hw->wpos)) << hwshift;
768 }
769 else {
770 bufs[0].len = dead << hwshift;
771 }
772
773
774 for (i = 0; i < 2; ++i) {
775 ssize_t nread;
776
777 if (bufs[i].len) {
778 void *p = advance (oss->pcm_buf, bufs[i].add << hwshift);
779 nread = read (oss->fd, p, bufs[i].len);
780
781 if (nread > 0) {
782 if (nread & hw->info.align) {
783 dolog ("warning: Misaligned read %"
784 FMTZ "d (requested %d), "
785 "alignment %d\n", nread, bufs[i].add << hwshift,
786 hw->info.align + 1);
787 }
788 read_samples += nread >> hwshift;
789#ifndef VBOX
790 hw->conv (hw->conv_buf + bufs[i].add, p, nread >> hwshift,
791 &nominal_volume);
792#else
793 hw->conv (hw->conv_buf + bufs[i].add, p, nread >> hwshift,
794 &pcm_in_volume);
795#endif
796 }
797
798 if (bufs[i].len - nread) {
799 if (nread == -1) {
800 switch (errno) {
801 case EINTR:
802 case EAGAIN:
803 break;
804 default:
805 oss_logerr (
806 errno,
807 "Failed to read %d bytes of audio (to %p)\n",
808 bufs[i].len, p
809 );
810 break;
811 }
812 }
813 break;
814 }
815 }
816 }
817
818 hw->wpos = (hw->wpos + read_samples) % hw->samples;
819 return read_samples;
820}
821
822static int oss_read (SWVoiceIn *sw, void *buf, int size)
823{
824 return audio_pcm_sw_read (sw, buf, size);
825}
826
827static int oss_ctl_in (HWVoiceIn *hw, int cmd, ...)
828{
829 (void) hw;
830 (void) cmd;
831 return 0;
832}
833
834static void *oss_audio_init (void)
835{
836 return &conf;
837}
838
839static void oss_audio_fini (void *opaque)
840{
841 (void) opaque;
842}
843
844static struct audio_option oss_options[] = {
845 {"FRAGSIZE", AUD_OPT_INT, &conf.fragsize,
846 "Fragment size in bytes", NULL, 0},
847 {"NFRAGS", AUD_OPT_INT, &conf.nfrags,
848 "Number of fragments", NULL, 0},
849#ifndef RT_OS_L4
850 {"MMAP", AUD_OPT_BOOL, &conf.try_mmap,
851 "Try using memory mapped access", NULL, 0},
852#endif
853 {"DAC_DEV", AUD_OPT_STR, &conf.devpath_out,
854 "Path to DAC device", NULL, 0},
855 {"ADC_DEV", AUD_OPT_STR, &conf.devpath_in,
856 "Path to ADC device", NULL, 0},
857 {"DEBUG", AUD_OPT_BOOL, &conf.debug,
858 "Turn on some debugging messages", NULL, 0},
859 {NULL, 0, NULL, NULL, NULL, 0}
860};
861
862static struct audio_pcm_ops oss_pcm_ops = {
863 oss_init_out,
864 oss_fini_out,
865 oss_run_out,
866 oss_write,
867 oss_ctl_out,
868
869 oss_init_in,
870 oss_fini_in,
871 oss_run_in,
872 oss_read,
873 oss_ctl_in
874};
875
876struct audio_driver oss_audio_driver = {
877 INIT_FIELD (name = ) "oss",
878 INIT_FIELD (descr = ) "OSS http://www.opensound.com",
879 INIT_FIELD (options = ) oss_options,
880 INIT_FIELD (init = ) oss_audio_init,
881 INIT_FIELD (fini = ) oss_audio_fini,
882 INIT_FIELD (pcm_ops = ) &oss_pcm_ops,
883 INIT_FIELD (can_be_default = ) 1,
884 INIT_FIELD (max_voices_out = ) INT_MAX,
885 INIT_FIELD (max_voices_in = ) INT_MAX,
886 INIT_FIELD (voice_size_out = ) sizeof (OSSVoiceOut),
887 INIT_FIELD (voice_size_in = ) sizeof (OSSVoiceIn)
888};
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