]> git.proxmox.com Git - qemu.git/blob - audio/ossaudio.c
0b391e422ccceda973943bbd73fcf5ac51bdab6b
[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 } OSSVoiceOut;
49
50 typedef struct OSSVoiceIn {
51 HWVoiceIn hw;
52 void *pcm_buf;
53 int fd;
54 int nfrags;
55 int fragsize;
56 } OSSVoiceIn;
57
58 static struct {
59 int try_mmap;
60 int nfrags;
61 int fragsize;
62 const char *devpath_out;
63 const char *devpath_in;
64 int debug;
65 int exclusive;
66 int policy;
67 } conf = {
68 .try_mmap = 0,
69 .nfrags = 4,
70 .fragsize = 4096,
71 .devpath_out = "/dev/dsp",
72 .devpath_in = "/dev/dsp",
73 .debug = 0,
74 .exclusive = 0,
75 .policy = 5
76 };
77
78 struct oss_params {
79 int freq;
80 audfmt_e fmt;
81 int nchannels;
82 int nfrags;
83 int fragsize;
84 };
85
86 static void GCC_FMT_ATTR (2, 3) oss_logerr (int err, const char *fmt, ...)
87 {
88 va_list ap;
89
90 va_start (ap, fmt);
91 AUD_vlog (AUDIO_CAP, fmt, ap);
92 va_end (ap);
93
94 AUD_log (AUDIO_CAP, "Reason: %s\n", strerror (err));
95 }
96
97 static void GCC_FMT_ATTR (3, 4) oss_logerr2 (
98 int err,
99 const char *typ,
100 const char *fmt,
101 ...
102 )
103 {
104 va_list ap;
105
106 AUD_log (AUDIO_CAP, "Could not initialize %s\n", typ);
107
108 va_start (ap, fmt);
109 AUD_vlog (AUDIO_CAP, fmt, ap);
110 va_end (ap);
111
112 AUD_log (AUDIO_CAP, "Reason: %s\n", strerror (err));
113 }
114
115 static void oss_anal_close (int *fdp)
116 {
117 int err;
118
119 qemu_set_fd_handler (*fdp, NULL, NULL, NULL);
120 err = close (*fdp);
121 if (err) {
122 oss_logerr (errno, "Failed to close file(fd=%d)\n", *fdp);
123 }
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, pos;
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 pos = hw->rpos << hw->info.shift;
378 bytes = audio_ring_dist (cntinfo.ptr, pos, bufsize);
379 decr = audio_MIN (bytes >> hw->info.shift, live);
380 }
381 else {
382 err = ioctl (oss->fd, SNDCTL_DSP_GETOSPACE, &abinfo);
383 if (err < 0) {
384 oss_logerr (errno, "SNDCTL_DSP_GETOPTR failed\n");
385 return 0;
386 }
387
388 if (abinfo.bytes > bufsize) {
389 if (conf.debug) {
390 dolog ("warning: Invalid available size, size=%d bufsize=%d\n"
391 "please report your OS/audio hw to malc@pulsesoft.com\n",
392 abinfo.bytes, bufsize);
393 }
394 abinfo.bytes = bufsize;
395 }
396
397 if (abinfo.bytes < 0) {
398 if (conf.debug) {
399 dolog ("warning: Invalid available size, size=%d bufsize=%d\n",
400 abinfo.bytes, bufsize);
401 }
402 return 0;
403 }
404
405 decr = audio_MIN (abinfo.bytes >> hw->info.shift, live);
406 if (!decr) {
407 return 0;
408 }
409 }
410
411 samples = decr;
412 rpos = hw->rpos;
413 while (samples) {
414 int left_till_end_samples = hw->samples - rpos;
415 int convert_samples = audio_MIN (samples, left_till_end_samples);
416
417 src = hw->mix_buf + rpos;
418 dst = advance (oss->pcm_buf, rpos << hw->info.shift);
419
420 hw->clip (dst, src, convert_samples);
421 if (!oss->mmapped) {
422 int written;
423
424 written = write (oss->fd, dst, convert_samples << hw->info.shift);
425 /* XXX: follow errno recommendations ? */
426 if (written == -1) {
427 oss_logerr (
428 errno,
429 "Failed to write %d bytes of audio data from %p\n",
430 convert_samples << hw->info.shift,
431 dst
432 );
433 continue;
434 }
435
436 if (written != convert_samples << hw->info.shift) {
437 int wsamples = written >> hw->info.shift;
438 int wbytes = wsamples << hw->info.shift;
439 if (wbytes != written) {
440 dolog ("warning: Misaligned write %d (requested %d), "
441 "alignment %d\n",
442 wbytes, written, hw->info.align + 1);
443 }
444 decr -= wsamples;
445 rpos = (rpos + wsamples) % hw->samples;
446 break;
447 }
448 }
449
450 rpos = (rpos + convert_samples) % hw->samples;
451 samples -= convert_samples;
452 }
453
454 hw->rpos = rpos;
455 return decr;
456 }
457
458 static void oss_fini_out (HWVoiceOut *hw)
459 {
460 int err;
461 OSSVoiceOut *oss = (OSSVoiceOut *) hw;
462
463 ldebug ("oss_fini\n");
464 oss_anal_close (&oss->fd);
465
466 if (oss->pcm_buf) {
467 if (oss->mmapped) {
468 err = munmap (oss->pcm_buf, hw->samples << hw->info.shift);
469 if (err) {
470 oss_logerr (errno, "Failed to unmap buffer %p, size %d\n",
471 oss->pcm_buf, hw->samples << hw->info.shift);
472 }
473 }
474 else {
475 qemu_free (oss->pcm_buf);
476 }
477 oss->pcm_buf = NULL;
478 }
479 }
480
481 static int oss_init_out (HWVoiceOut *hw, struct audsettings *as)
482 {
483 OSSVoiceOut *oss = (OSSVoiceOut *) hw;
484 struct oss_params req, obt;
485 int endianness;
486 int err;
487 int fd;
488 audfmt_e effective_fmt;
489 struct audsettings obt_as;
490
491 oss->fd = -1;
492
493 req.fmt = aud_to_ossfmt (as->fmt);
494 req.freq = as->freq;
495 req.nchannels = as->nchannels;
496 req.fragsize = conf.fragsize;
497 req.nfrags = conf.nfrags;
498
499 if (oss_open (0, &req, &obt, &fd)) {
500 return -1;
501 }
502
503 err = oss_to_audfmt (obt.fmt, &effective_fmt, &endianness);
504 if (err) {
505 oss_anal_close (&fd);
506 return -1;
507 }
508
509 obt_as.freq = obt.freq;
510 obt_as.nchannels = obt.nchannels;
511 obt_as.fmt = effective_fmt;
512 obt_as.endianness = endianness;
513
514 audio_pcm_init_info (&hw->info, &obt_as);
515 oss->nfrags = obt.nfrags;
516 oss->fragsize = obt.fragsize;
517
518 if (obt.nfrags * obt.fragsize & hw->info.align) {
519 dolog ("warning: Misaligned DAC buffer, size %d, alignment %d\n",
520 obt.nfrags * obt.fragsize, hw->info.align + 1);
521 }
522
523 hw->samples = (obt.nfrags * obt.fragsize) >> hw->info.shift;
524
525 oss->mmapped = 0;
526 if (conf.try_mmap) {
527 oss->pcm_buf = mmap (
528 NULL,
529 hw->samples << hw->info.shift,
530 PROT_READ | PROT_WRITE,
531 MAP_SHARED,
532 fd,
533 0
534 );
535 if (oss->pcm_buf == MAP_FAILED) {
536 oss_logerr (errno, "Failed to map %d bytes of DAC\n",
537 hw->samples << hw->info.shift);
538 }
539 else {
540 int err;
541 int trig = 0;
542 if (ioctl (fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) {
543 oss_logerr (errno, "SNDCTL_DSP_SETTRIGGER 0 failed\n");
544 }
545 else {
546 trig = PCM_ENABLE_OUTPUT;
547 if (ioctl (fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) {
548 oss_logerr (
549 errno,
550 "SNDCTL_DSP_SETTRIGGER PCM_ENABLE_OUTPUT failed\n"
551 );
552 }
553 else {
554 oss->mmapped = 1;
555 }
556 }
557
558 if (!oss->mmapped) {
559 err = munmap (oss->pcm_buf, hw->samples << hw->info.shift);
560 if (err) {
561 oss_logerr (errno, "Failed to unmap buffer %p size %d\n",
562 oss->pcm_buf, hw->samples << hw->info.shift);
563 }
564 }
565 }
566 }
567
568 if (!oss->mmapped) {
569 oss->pcm_buf = audio_calloc (
570 AUDIO_FUNC,
571 hw->samples,
572 1 << hw->info.shift
573 );
574 if (!oss->pcm_buf) {
575 dolog (
576 "Could not allocate DAC buffer (%d samples, each %d bytes)\n",
577 hw->samples,
578 1 << hw->info.shift
579 );
580 oss_anal_close (&fd);
581 return -1;
582 }
583 }
584
585 oss->fd = fd;
586 return 0;
587 }
588
589 static int oss_ctl_out (HWVoiceOut *hw, int cmd, ...)
590 {
591 int trig;
592 va_list ap;
593 int poll_mode;
594 OSSVoiceOut *oss = (OSSVoiceOut *) hw;
595
596 va_start (ap, cmd);
597 poll_mode = va_arg (ap, int);
598 va_end (ap);
599
600 switch (cmd) {
601 case VOICE_ENABLE:
602 ldebug ("enabling voice\n");
603 if (poll_mode && oss_poll_out (hw)) {
604 poll_mode = 0;
605 }
606 hw->poll_mode = poll_mode;
607
608 if (!oss->mmapped) {
609 return 0;
610 }
611
612 audio_pcm_info_clear_buf (&hw->info, oss->pcm_buf, hw->samples);
613 trig = PCM_ENABLE_OUTPUT;
614 if (ioctl (oss->fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) {
615 oss_logerr (
616 errno,
617 "SNDCTL_DSP_SETTRIGGER PCM_ENABLE_OUTPUT failed\n"
618 );
619 return -1;
620 }
621 break;
622
623 case VOICE_DISABLE:
624 if (hw->poll_mode) {
625 qemu_set_fd_handler (oss->fd, NULL, NULL, NULL);
626 hw->poll_mode = 0;
627 }
628
629 if (!oss->mmapped) {
630 return 0;
631 }
632
633 ldebug ("disabling voice\n");
634 trig = 0;
635 if (ioctl (oss->fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) {
636 oss_logerr (errno, "SNDCTL_DSP_SETTRIGGER 0 failed\n");
637 return -1;
638 }
639 break;
640 }
641 return 0;
642 }
643
644 static int oss_init_in (HWVoiceIn *hw, struct audsettings *as)
645 {
646 OSSVoiceIn *oss = (OSSVoiceIn *) hw;
647 struct oss_params req, obt;
648 int endianness;
649 int err;
650 int fd;
651 audfmt_e effective_fmt;
652 struct audsettings obt_as;
653
654 oss->fd = -1;
655
656 req.fmt = aud_to_ossfmt (as->fmt);
657 req.freq = as->freq;
658 req.nchannels = as->nchannels;
659 req.fragsize = conf.fragsize;
660 req.nfrags = conf.nfrags;
661 if (oss_open (1, &req, &obt, &fd)) {
662 return -1;
663 }
664
665 err = oss_to_audfmt (obt.fmt, &effective_fmt, &endianness);
666 if (err) {
667 oss_anal_close (&fd);
668 return -1;
669 }
670
671 obt_as.freq = obt.freq;
672 obt_as.nchannels = obt.nchannels;
673 obt_as.fmt = effective_fmt;
674 obt_as.endianness = endianness;
675
676 audio_pcm_init_info (&hw->info, &obt_as);
677 oss->nfrags = obt.nfrags;
678 oss->fragsize = obt.fragsize;
679
680 if (obt.nfrags * obt.fragsize & hw->info.align) {
681 dolog ("warning: Misaligned ADC buffer, size %d, alignment %d\n",
682 obt.nfrags * obt.fragsize, hw->info.align + 1);
683 }
684
685 hw->samples = (obt.nfrags * obt.fragsize) >> hw->info.shift;
686 oss->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift);
687 if (!oss->pcm_buf) {
688 dolog ("Could not allocate ADC buffer (%d samples, each %d bytes)\n",
689 hw->samples, 1 << hw->info.shift);
690 oss_anal_close (&fd);
691 return -1;
692 }
693
694 oss->fd = fd;
695 return 0;
696 }
697
698 static void oss_fini_in (HWVoiceIn *hw)
699 {
700 OSSVoiceIn *oss = (OSSVoiceIn *) hw;
701
702 oss_anal_close (&oss->fd);
703
704 if (oss->pcm_buf) {
705 qemu_free (oss->pcm_buf);
706 oss->pcm_buf = NULL;
707 }
708 }
709
710 static int oss_run_in (HWVoiceIn *hw)
711 {
712 OSSVoiceIn *oss = (OSSVoiceIn *) hw;
713 int hwshift = hw->info.shift;
714 int i;
715 int live = audio_pcm_hw_get_live_in (hw);
716 int dead = hw->samples - live;
717 size_t read_samples = 0;
718 struct {
719 int add;
720 int len;
721 } bufs[2] = {
722 { .add = hw->wpos, .len = 0 },
723 { .add = 0, .len = 0 }
724 };
725
726 if (!dead) {
727 return 0;
728 }
729
730 if (hw->wpos + dead > hw->samples) {
731 bufs[0].len = (hw->samples - hw->wpos) << hwshift;
732 bufs[1].len = (dead - (hw->samples - hw->wpos)) << hwshift;
733 }
734 else {
735 bufs[0].len = dead << hwshift;
736 }
737
738 for (i = 0; i < 2; ++i) {
739 ssize_t nread;
740
741 if (bufs[i].len) {
742 void *p = advance (oss->pcm_buf, bufs[i].add << hwshift);
743 nread = read (oss->fd, p, bufs[i].len);
744
745 if (nread > 0) {
746 if (nread & hw->info.align) {
747 dolog ("warning: Misaligned read %zd (requested %d), "
748 "alignment %d\n", nread, bufs[i].add << hwshift,
749 hw->info.align + 1);
750 }
751 read_samples += nread >> hwshift;
752 hw->conv (hw->conv_buf + bufs[i].add, p, nread >> hwshift,
753 &nominal_volume);
754 }
755
756 if (bufs[i].len - nread) {
757 if (nread == -1) {
758 switch (errno) {
759 case EINTR:
760 case EAGAIN:
761 break;
762 default:
763 oss_logerr (
764 errno,
765 "Failed to read %d bytes of audio (to %p)\n",
766 bufs[i].len, p
767 );
768 break;
769 }
770 }
771 break;
772 }
773 }
774 }
775
776 hw->wpos = (hw->wpos + read_samples) % hw->samples;
777 return read_samples;
778 }
779
780 static int oss_read (SWVoiceIn *sw, void *buf, int size)
781 {
782 return audio_pcm_sw_read (sw, buf, size);
783 }
784
785 static int oss_ctl_in (HWVoiceIn *hw, int cmd, ...)
786 {
787 va_list ap;
788 int poll_mode;
789 OSSVoiceIn *oss = (OSSVoiceIn *) hw;
790
791 va_start (ap, cmd);
792 poll_mode = va_arg (ap, int);
793 va_end (ap);
794
795 switch (cmd) {
796 case VOICE_ENABLE:
797 if (poll_mode && oss_poll_in (hw)) {
798 poll_mode = 0;
799 }
800 hw->poll_mode = poll_mode;
801 break;
802
803 case VOICE_DISABLE:
804 if (hw->poll_mode) {
805 hw->poll_mode = 0;
806 qemu_set_fd_handler (oss->fd, NULL, NULL, NULL);
807 }
808 break;
809 }
810 return 0;
811 }
812
813 static void *oss_audio_init (void)
814 {
815 return &conf;
816 }
817
818 static void oss_audio_fini (void *opaque)
819 {
820 (void) opaque;
821 }
822
823 static struct audio_option oss_options[] = {
824 {
825 .name = "FRAGSIZE",
826 .tag = AUD_OPT_INT,
827 .valp = &conf.fragsize,
828 .descr = "Fragment size in bytes"
829 },
830 {
831 .name = "NFRAGS",
832 .tag = AUD_OPT_INT,
833 .valp = &conf.nfrags,
834 .descr = "Number of fragments"
835 },
836 {
837 .name = "MMAP",
838 .tag = AUD_OPT_BOOL,
839 .valp = &conf.try_mmap,
840 .descr = "Try using memory mapped access"
841 },
842 {
843 .name = "DAC_DEV",
844 .tag = AUD_OPT_STR,
845 .valp = &conf.devpath_out,
846 .descr = "Path to DAC device"
847 },
848 {
849 .name = "ADC_DEV",
850 .tag = AUD_OPT_STR,
851 .valp = &conf.devpath_in,
852 .descr = "Path to ADC device"
853 },
854 {
855 .name = "EXCLUSIVE",
856 .tag = AUD_OPT_BOOL,
857 .valp = &conf.exclusive,
858 .descr = "Open device in exclusive mode (vmix wont work)"
859 },
860 #ifdef SNDCTL_DSP_POLICY
861 {
862 .name = "POLICY",
863 .tag = AUD_OPT_INT,
864 .valp = &conf.policy,
865 .descr = "Set the timing policy of the device, -1 to use fragment mode",
866 },
867 #endif
868 {
869 .name = "DEBUG",
870 .tag = AUD_OPT_BOOL,
871 .valp = &conf.debug,
872 .descr = "Turn on some debugging messages"
873 },
874 { /* End of list */ }
875 };
876
877 static struct audio_pcm_ops oss_pcm_ops = {
878 .init_out = oss_init_out,
879 .fini_out = oss_fini_out,
880 .run_out = oss_run_out,
881 .write = oss_write,
882 .ctl_out = oss_ctl_out,
883
884 .init_in = oss_init_in,
885 .fini_in = oss_fini_in,
886 .run_in = oss_run_in,
887 .read = oss_read,
888 .ctl_in = oss_ctl_in
889 };
890
891 struct audio_driver oss_audio_driver = {
892 .name = "oss",
893 .descr = "OSS http://www.opensound.com",
894 .options = oss_options,
895 .init = oss_audio_init,
896 .fini = oss_audio_fini,
897 .pcm_ops = &oss_pcm_ops,
898 .can_be_default = 1,
899 .max_voices_out = INT_MAX,
900 .max_voices_in = INT_MAX,
901 .voice_size_out = sizeof (OSSVoiceOut),
902 .voice_size_in = sizeof (OSSVoiceIn)
903 };