2 * QEMU OSS audio driver
4 * Copyright (c) 2003-2005 Vassili Karpov (malc)
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:
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
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
26 #include <sys/types.h>
27 #include <sys/ioctl.h>
29 #include <soundcard.h>
31 #include <sys/soundcard.h>
35 #define AUDIO_CAP "oss"
36 #include "audio_int.h"
38 typedef struct OSSVoiceOut
{
48 typedef struct OSSVoiceIn
{
61 const char *devpath_out
;
62 const char *devpath_in
;
68 .devpath_out
= "/dev/dsp",
69 .devpath_in
= "/dev/dsp",
81 static void GCC_FMT_ATTR (2, 3) oss_logerr (int err
, const char *fmt
, ...)
86 AUD_vlog (AUDIO_CAP
, fmt
, ap
);
89 AUD_log (AUDIO_CAP
, "Reason: %s\n", strerror (err
));
92 static void GCC_FMT_ATTR (3, 4) oss_logerr2 (
101 AUD_log (AUDIO_CAP
, "Could not initialize %s\n", typ
);
104 AUD_vlog (AUDIO_CAP
, fmt
, ap
);
107 AUD_log (AUDIO_CAP
, "Reason: %s\n", strerror (err
));
110 static void oss_anal_close (int *fdp
)
112 int err
= close (*fdp
);
114 oss_logerr (errno
, "Failed to close file(fd=%d)\n", *fdp
);
119 static int oss_write (SWVoiceOut
*sw
, void *buf
, int len
)
121 return audio_pcm_sw_write (sw
, buf
, len
);
124 static int aud_to_ossfmt (audfmt_e fmt
)
140 dolog ("Internal logic error: Bad audio format %d\n", fmt
);
148 static int oss_to_audfmt (int ossfmt
, audfmt_e
*fmt
, int *endianness
)
182 dolog ("Unrecognized audio format %d\n", ossfmt
);
189 #if defined DEBUG_MISMATCHES || defined DEBUG
190 static void oss_dump_info (struct oss_params
*req
, struct oss_params
*obt
)
192 dolog ("parameter | requested value | obtained value\n");
193 dolog ("format | %10d | %10d\n", req
->fmt
, obt
->fmt
);
194 dolog ("channels | %10d | %10d\n",
195 req
->nchannels
, obt
->nchannels
);
196 dolog ("frequency | %10d | %10d\n", req
->freq
, obt
->freq
);
197 dolog ("nfrags | %10d | %10d\n", req
->nfrags
, obt
->nfrags
);
198 dolog ("fragsize | %10d | %10d\n",
199 req
->fragsize
, obt
->fragsize
);
203 static int oss_open (int in
, struct oss_params
*req
,
204 struct oss_params
*obt
, int *pfd
)
208 audio_buf_info abinfo
;
209 int fmt
, freq
, nchannels
;
210 const char *dspname
= in
? conf
.devpath_in
: conf
.devpath_out
;
211 const char *typ
= in
? "ADC" : "DAC";
213 fd
= open (dspname
, (in
? O_RDONLY
: O_WRONLY
) | O_NONBLOCK
);
215 oss_logerr2 (errno
, typ
, "Failed to open `%s'\n", dspname
);
220 nchannels
= req
->nchannels
;
223 if (ioctl (fd
, SNDCTL_DSP_SAMPLESIZE
, &fmt
)) {
224 oss_logerr2 (errno
, typ
, "Failed to set sample size %d\n", req
->fmt
);
228 if (ioctl (fd
, SNDCTL_DSP_CHANNELS
, &nchannels
)) {
229 oss_logerr2 (errno
, typ
, "Failed to set number of channels %d\n",
234 if (ioctl (fd
, SNDCTL_DSP_SPEED
, &freq
)) {
235 oss_logerr2 (errno
, typ
, "Failed to set frequency %d\n", req
->freq
);
239 if (ioctl (fd
, SNDCTL_DSP_NONBLOCK
)) {
240 oss_logerr2 (errno
, typ
, "Failed to set non-blocking mode\n");
244 mmmmssss
= (req
->nfrags
<< 16) | lsbindex (req
->fragsize
);
245 if (ioctl (fd
, SNDCTL_DSP_SETFRAGMENT
, &mmmmssss
)) {
246 oss_logerr2 (errno
, typ
, "Failed to set buffer length (%d, %d)\n",
247 req
->nfrags
, req
->fragsize
);
251 if (ioctl (fd
, in
? SNDCTL_DSP_GETISPACE
: SNDCTL_DSP_GETOSPACE
, &abinfo
)) {
252 oss_logerr2 (errno
, typ
, "Failed to get buffer length\n");
257 obt
->nchannels
= nchannels
;
259 obt
->nfrags
= abinfo
.fragstotal
;
260 obt
->fragsize
= abinfo
.fragsize
;
263 #ifdef DEBUG_MISMATCHES
264 if ((req
->fmt
!= obt
->fmt
) ||
265 (req
->nchannels
!= obt
->nchannels
) ||
266 (req
->freq
!= obt
->freq
) ||
267 (req
->fragsize
!= obt
->fragsize
) ||
268 (req
->nfrags
!= obt
->nfrags
)) {
269 dolog ("Audio parameters mismatch\n");
270 oss_dump_info (req
, obt
);
275 oss_dump_info (req
, obt
);
280 oss_anal_close (&fd
);
284 static int oss_run_out (HWVoiceOut
*hw
)
286 OSSVoiceOut
*oss
= (OSSVoiceOut
*) hw
;
287 int err
, rpos
, live
, decr
;
291 struct audio_buf_info abinfo
;
292 struct count_info cntinfo
;
295 live
= audio_pcm_hw_get_live_out (hw
);
300 bufsize
= hw
->samples
<< hw
->info
.shift
;
305 err
= ioctl (oss
->fd
, SNDCTL_DSP_GETOPTR
, &cntinfo
);
307 oss_logerr (errno
, "SNDCTL_DSP_GETOPTR failed\n");
311 if (cntinfo
.ptr
== oss
->old_optr
) {
312 if (abs (hw
->samples
- live
) < 64) {
313 dolog ("warning: Overrun\n");
318 if (cntinfo
.ptr
> oss
->old_optr
) {
319 bytes
= cntinfo
.ptr
- oss
->old_optr
;
322 bytes
= bufsize
+ cntinfo
.ptr
- oss
->old_optr
;
325 decr
= audio_MIN (bytes
>> hw
->info
.shift
, live
);
328 err
= ioctl (oss
->fd
, SNDCTL_DSP_GETOSPACE
, &abinfo
);
330 oss_logerr (errno
, "SNDCTL_DSP_GETOPTR failed\n");
334 if (abinfo
.bytes
> bufsize
) {
336 dolog ("warning: Invalid available size, size=%d bufsize=%d\n"
337 "please report your OS/audio hw to malc@pulsesoft.com\n",
338 abinfo
.bytes
, bufsize
);
340 abinfo
.bytes
= bufsize
;
343 if (abinfo
.bytes
< 0) {
345 dolog ("warning: Invalid available size, size=%d bufsize=%d\n",
346 abinfo
.bytes
, bufsize
);
351 decr
= audio_MIN (abinfo
.bytes
>> hw
->info
.shift
, live
);
360 int left_till_end_samples
= hw
->samples
- rpos
;
361 int convert_samples
= audio_MIN (samples
, left_till_end_samples
);
363 src
= hw
->mix_buf
+ rpos
;
364 dst
= advance (oss
->pcm_buf
, rpos
<< hw
->info
.shift
);
366 hw
->clip (dst
, src
, convert_samples
);
370 written
= write (oss
->fd
, dst
, convert_samples
<< hw
->info
.shift
);
371 /* XXX: follow errno recommendations ? */
375 "Failed to write %d bytes of audio data from %p\n",
376 convert_samples
<< hw
->info
.shift
,
382 if (written
!= convert_samples
<< hw
->info
.shift
) {
383 int wsamples
= written
>> hw
->info
.shift
;
384 int wbytes
= wsamples
<< hw
->info
.shift
;
385 if (wbytes
!= written
) {
386 dolog ("warning: Misaligned write %d (requested %d), "
388 wbytes
, written
, hw
->info
.align
+ 1);
391 rpos
= (rpos
+ wsamples
) % hw
->samples
;
396 rpos
= (rpos
+ convert_samples
) % hw
->samples
;
397 samples
-= convert_samples
;
400 oss
->old_optr
= cntinfo
.ptr
;
407 static void oss_fini_out (HWVoiceOut
*hw
)
410 OSSVoiceOut
*oss
= (OSSVoiceOut
*) hw
;
412 ldebug ("oss_fini\n");
413 oss_anal_close (&oss
->fd
);
417 err
= munmap (oss
->pcm_buf
, hw
->samples
<< hw
->info
.shift
);
419 oss_logerr (errno
, "Failed to unmap buffer %p, size %d\n",
420 oss
->pcm_buf
, hw
->samples
<< hw
->info
.shift
);
424 qemu_free (oss
->pcm_buf
);
430 static int oss_init_out (HWVoiceOut
*hw
, audsettings_t
*as
)
432 OSSVoiceOut
*oss
= (OSSVoiceOut
*) hw
;
433 struct oss_params req
, obt
;
437 audfmt_e effective_fmt
;
438 audsettings_t obt_as
;
442 req
.fmt
= aud_to_ossfmt (as
->fmt
);
444 req
.nchannels
= as
->nchannels
;
445 req
.fragsize
= conf
.fragsize
;
446 req
.nfrags
= conf
.nfrags
;
448 if (oss_open (0, &req
, &obt
, &fd
)) {
452 err
= oss_to_audfmt (obt
.fmt
, &effective_fmt
, &endianness
);
454 oss_anal_close (&fd
);
458 obt_as
.freq
= obt
.freq
;
459 obt_as
.nchannels
= obt
.nchannels
;
460 obt_as
.fmt
= effective_fmt
;
461 obt_as
.endianness
= endianness
;
463 audio_pcm_init_info (&hw
->info
, &obt_as
);
464 oss
->nfrags
= obt
.nfrags
;
465 oss
->fragsize
= obt
.fragsize
;
467 if (obt
.nfrags
* obt
.fragsize
& hw
->info
.align
) {
468 dolog ("warning: Misaligned DAC buffer, size %d, alignment %d\n",
469 obt
.nfrags
* obt
.fragsize
, hw
->info
.align
+ 1);
472 hw
->samples
= (obt
.nfrags
* obt
.fragsize
) >> hw
->info
.shift
;
476 oss
->pcm_buf
= mmap (
478 hw
->samples
<< hw
->info
.shift
,
479 PROT_READ
| PROT_WRITE
,
484 if (oss
->pcm_buf
== MAP_FAILED
) {
485 oss_logerr (errno
, "Failed to map %d bytes of DAC\n",
486 hw
->samples
<< hw
->info
.shift
);
490 if (ioctl (fd
, SNDCTL_DSP_SETTRIGGER
, &trig
) < 0) {
491 oss_logerr (errno
, "SNDCTL_DSP_SETTRIGGER 0 failed\n");
494 trig
= PCM_ENABLE_OUTPUT
;
495 if (ioctl (fd
, SNDCTL_DSP_SETTRIGGER
, &trig
) < 0) {
498 "SNDCTL_DSP_SETTRIGGER PCM_ENABLE_OUTPUT failed\n"
507 err
= munmap (oss
->pcm_buf
, hw
->samples
<< hw
->info
.shift
);
509 oss_logerr (errno
, "Failed to unmap buffer %p size %d\n",
510 oss
->pcm_buf
, hw
->samples
<< hw
->info
.shift
);
517 oss
->pcm_buf
= audio_calloc (
524 "Could not allocate DAC buffer (%d samples, each %d bytes)\n",
528 oss_anal_close (&fd
);
537 static int oss_ctl_out (HWVoiceOut
*hw
, int cmd
, ...)
540 OSSVoiceOut
*oss
= (OSSVoiceOut
*) hw
;
548 ldebug ("enabling voice\n");
549 audio_pcm_info_clear_buf (&hw
->info
, oss
->pcm_buf
, hw
->samples
);
550 trig
= PCM_ENABLE_OUTPUT
;
551 if (ioctl (oss
->fd
, SNDCTL_DSP_SETTRIGGER
, &trig
) < 0) {
554 "SNDCTL_DSP_SETTRIGGER PCM_ENABLE_OUTPUT failed\n"
561 ldebug ("disabling voice\n");
563 if (ioctl (oss
->fd
, SNDCTL_DSP_SETTRIGGER
, &trig
) < 0) {
564 oss_logerr (errno
, "SNDCTL_DSP_SETTRIGGER 0 failed\n");
572 static int oss_init_in (HWVoiceIn
*hw
, audsettings_t
*as
)
574 OSSVoiceIn
*oss
= (OSSVoiceIn
*) hw
;
575 struct oss_params req
, obt
;
579 audfmt_e effective_fmt
;
580 audsettings_t obt_as
;
584 req
.fmt
= aud_to_ossfmt (as
->fmt
);
586 req
.nchannels
= as
->nchannels
;
587 req
.fragsize
= conf
.fragsize
;
588 req
.nfrags
= conf
.nfrags
;
589 if (oss_open (1, &req
, &obt
, &fd
)) {
593 err
= oss_to_audfmt (obt
.fmt
, &effective_fmt
, &endianness
);
595 oss_anal_close (&fd
);
599 obt_as
.freq
= obt
.freq
;
600 obt_as
.nchannels
= obt
.nchannels
;
601 obt_as
.fmt
= effective_fmt
;
602 obt_as
.endianness
= endianness
;
604 audio_pcm_init_info (&hw
->info
, &obt_as
);
605 oss
->nfrags
= obt
.nfrags
;
606 oss
->fragsize
= obt
.fragsize
;
608 if (obt
.nfrags
* obt
.fragsize
& hw
->info
.align
) {
609 dolog ("warning: Misaligned ADC buffer, size %d, alignment %d\n",
610 obt
.nfrags
* obt
.fragsize
, hw
->info
.align
+ 1);
613 hw
->samples
= (obt
.nfrags
* obt
.fragsize
) >> hw
->info
.shift
;
614 oss
->pcm_buf
= audio_calloc (AUDIO_FUNC
, hw
->samples
, 1 << hw
->info
.shift
);
616 dolog ("Could not allocate ADC buffer (%d samples, each %d bytes)\n",
617 hw
->samples
, 1 << hw
->info
.shift
);
618 oss_anal_close (&fd
);
626 static void oss_fini_in (HWVoiceIn
*hw
)
628 OSSVoiceIn
*oss
= (OSSVoiceIn
*) hw
;
630 oss_anal_close (&oss
->fd
);
633 qemu_free (oss
->pcm_buf
);
638 static int oss_run_in (HWVoiceIn
*hw
)
640 OSSVoiceIn
*oss
= (OSSVoiceIn
*) hw
;
641 int hwshift
= hw
->info
.shift
;
643 int live
= audio_pcm_hw_get_live_in (hw
);
644 int dead
= hw
->samples
- live
;
645 size_t read_samples
= 0;
658 if (hw
->wpos
+ dead
> hw
->samples
) {
659 bufs
[0].len
= (hw
->samples
- hw
->wpos
) << hwshift
;
660 bufs
[1].len
= (dead
- (hw
->samples
- hw
->wpos
)) << hwshift
;
663 bufs
[0].len
= dead
<< hwshift
;
667 for (i
= 0; i
< 2; ++i
) {
671 void *p
= advance (oss
->pcm_buf
, bufs
[i
].add
<< hwshift
);
672 nread
= read (oss
->fd
, p
, bufs
[i
].len
);
675 if (nread
& hw
->info
.align
) {
676 dolog ("warning: Misaligned read %zd (requested %d), "
677 "alignment %d\n", nread
, bufs
[i
].add
<< hwshift
,
680 read_samples
+= nread
>> hwshift
;
681 hw
->conv (hw
->conv_buf
+ bufs
[i
].add
, p
, nread
>> hwshift
,
685 if (bufs
[i
].len
- nread
) {
694 "Failed to read %d bytes of audio (to %p)\n",
705 hw
->wpos
= (hw
->wpos
+ read_samples
) % hw
->samples
;
709 static int oss_read (SWVoiceIn
*sw
, void *buf
, int size
)
711 return audio_pcm_sw_read (sw
, buf
, size
);
714 static int oss_ctl_in (HWVoiceIn
*hw
, int cmd
, ...)
721 static void *oss_audio_init (void)
726 static void oss_audio_fini (void *opaque
)
731 static struct audio_option oss_options
[] = {
732 {"FRAGSIZE", AUD_OPT_INT
, &conf
.fragsize
,
733 "Fragment size in bytes", NULL
, 0},
734 {"NFRAGS", AUD_OPT_INT
, &conf
.nfrags
,
735 "Number of fragments", NULL
, 0},
736 {"MMAP", AUD_OPT_BOOL
, &conf
.try_mmap
,
737 "Try using memory mapped access", NULL
, 0},
738 {"DAC_DEV", AUD_OPT_STR
, &conf
.devpath_out
,
739 "Path to DAC device", NULL
, 0},
740 {"ADC_DEV", AUD_OPT_STR
, &conf
.devpath_in
,
741 "Path to ADC device", NULL
, 0},
742 {"DEBUG", AUD_OPT_BOOL
, &conf
.debug
,
743 "Turn on some debugging messages", NULL
, 0},
744 {NULL
, 0, NULL
, NULL
, NULL
, 0}
747 static struct audio_pcm_ops oss_pcm_ops
= {
761 struct audio_driver oss_audio_driver
= {
762 INIT_FIELD (name
= ) "oss",
763 INIT_FIELD (descr
= ) "OSS http://www.opensound.com",
764 INIT_FIELD (options
= ) oss_options
,
765 INIT_FIELD (init
= ) oss_audio_init
,
766 INIT_FIELD (fini
= ) oss_audio_fini
,
767 INIT_FIELD (pcm_ops
= ) &oss_pcm_ops
,
768 INIT_FIELD (can_be_default
= ) 1,
769 INIT_FIELD (max_voices_out
= ) INT_MAX
,
770 INIT_FIELD (max_voices_in
= ) INT_MAX
,
771 INIT_FIELD (voice_size_out
= ) sizeof (OSSVoiceOut
),
772 INIT_FIELD (voice_size_in
= ) sizeof (OSSVoiceIn
)