VirtualBox

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

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

some more detailed LogRel about the reason why opening an OSS audio device failed

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 22.2 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 hw->conv (hw->conv_buf + bufs[i].add, p, nread >> hwshift,
786 &nominal_volume);
787 }
788
789 if (bufs[i].len - nread) {
790 if (nread == -1) {
791 switch (errno) {
792 case EINTR:
793 case EAGAIN:
794 break;
795 default:
796 oss_logerr (
797 errno,
798 "Failed to read %d bytes of audio (to %p)\n",
799 bufs[i].len, p
800 );
801 break;
802 }
803 }
804 break;
805 }
806 }
807 }
808
809 hw->wpos = (hw->wpos + read_samples) % hw->samples;
810 return read_samples;
811}
812
813static int oss_read (SWVoiceIn *sw, void *buf, int size)
814{
815 return audio_pcm_sw_read (sw, buf, size);
816}
817
818static int oss_ctl_in (HWVoiceIn *hw, int cmd, ...)
819{
820 (void) hw;
821 (void) cmd;
822 return 0;
823}
824
825static void *oss_audio_init (void)
826{
827 return &conf;
828}
829
830static void oss_audio_fini (void *opaque)
831{
832 (void) opaque;
833}
834
835static struct audio_option oss_options[] = {
836 {"FRAGSIZE", AUD_OPT_INT, &conf.fragsize,
837 "Fragment size in bytes", NULL, 0},
838 {"NFRAGS", AUD_OPT_INT, &conf.nfrags,
839 "Number of fragments", NULL, 0},
840#ifndef __L4ENV__
841 {"MMAP", AUD_OPT_BOOL, &conf.try_mmap,
842 "Try using memory mapped access", NULL, 0},
843#endif
844 {"DAC_DEV", AUD_OPT_STR, &conf.devpath_out,
845 "Path to DAC device", NULL, 0},
846 {"ADC_DEV", AUD_OPT_STR, &conf.devpath_in,
847 "Path to ADC device", NULL, 0},
848 {"DEBUG", AUD_OPT_BOOL, &conf.debug,
849 "Turn on some debugging messages", NULL, 0},
850 {NULL, 0, NULL, NULL, NULL, 0}
851};
852
853static struct audio_pcm_ops oss_pcm_ops = {
854 oss_init_out,
855 oss_fini_out,
856 oss_run_out,
857 oss_write,
858 oss_ctl_out,
859
860 oss_init_in,
861 oss_fini_in,
862 oss_run_in,
863 oss_read,
864 oss_ctl_in
865};
866
867struct audio_driver oss_audio_driver = {
868 INIT_FIELD (name = ) "oss",
869 INIT_FIELD (descr = ) "OSS http://www.opensound.com",
870 INIT_FIELD (options = ) oss_options,
871 INIT_FIELD (init = ) oss_audio_init,
872 INIT_FIELD (fini = ) oss_audio_fini,
873 INIT_FIELD (pcm_ops = ) &oss_pcm_ops,
874 INIT_FIELD (can_be_default = ) 1,
875 INIT_FIELD (max_voices_out = ) INT_MAX,
876 INIT_FIELD (max_voices_in = ) INT_MAX,
877 INIT_FIELD (voice_size_out = ) sizeof (OSSVoiceOut),
878 INIT_FIELD (voice_size_in = ) sizeof (OSSVoiceIn)
879};
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