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