2 * QEMU OSS audio output driver
4 * Copyright (c) 2003-2004 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
25 /* Temporary kludge */
26 #if defined __linux__ || (defined _BSD && !defined __APPLE__)
31 #include <sys/types.h>
32 #include <sys/ioctl.h>
33 #include <sys/soundcard.h>
35 #define AUDIO_CAP "oss"
36 #include "audio/audio.h"
37 #include "audio/ossaudio.h"
39 #define QC_OSS_FRAGSIZE "QEMU_OSS_FRAGSIZE"
40 #define QC_OSS_NFRAGS "QEMU_OSS_NFRAGS"
41 #define QC_OSS_MMAP "QEMU_OSS_MMAP"
42 #define QC_OSS_DEV "QEMU_OSS_DEV"
44 #define errstr() strerror (errno)
66 static int oss_hw_write (SWVoice
*sw
, void *buf
, int len
)
68 return pcm_hw_write (sw
, buf
, len
);
71 static int AUD_to_ossfmt (audfmt_e fmt
)
74 case AUD_FMT_S8
: return AFMT_S8
;
75 case AUD_FMT_U8
: return AFMT_U8
;
76 case AUD_FMT_S16
: return AFMT_S16_LE
;
77 case AUD_FMT_U16
: return AFMT_U16_LE
;
79 dolog ("Internal logic error: Bad audio format %d\nAborting\n", fmt
);
84 static int oss_to_audfmt (int fmt
)
87 case AFMT_S8
: return AUD_FMT_S8
;
88 case AFMT_U8
: return AUD_FMT_U8
;
89 case AFMT_S16_LE
: return AUD_FMT_S16
;
90 case AFMT_U16_LE
: return AUD_FMT_U16
;
92 dolog ("Internal logic error: Unrecognized OSS audio format %d\n"
100 static void oss_dump_pcm_info (struct oss_params
*req
, struct oss_params
*obt
)
102 dolog ("parameter | requested value | obtained value\n");
103 dolog ("format | %10d | %10d\n", req
->fmt
, obt
->fmt
);
104 dolog ("channels | %10d | %10d\n", req
->nchannels
, obt
->nchannels
);
105 dolog ("frequency | %10d | %10d\n", req
->freq
, obt
->freq
);
106 dolog ("nfrags | %10d | %10d\n", req
->nfrags
, obt
->nfrags
);
107 dolog ("fragsize | %10d | %10d\n", req
->fragsize
, obt
->fragsize
);
111 static int oss_open (struct oss_params
*req
, struct oss_params
*obt
, int *pfd
)
115 audio_buf_info abinfo
;
116 int fmt
, freq
, nchannels
;
117 const char *dspname
= conf
.dspname
;
119 fd
= open (dspname
, O_RDWR
| O_NONBLOCK
);
121 dolog ("Could not initialize audio hardware. Failed to open `%s':\n"
129 nchannels
= req
->nchannels
;
132 if (ioctl (fd
, SNDCTL_DSP_SAMPLESIZE
, &fmt
)) {
133 dolog ("Could not initialize audio hardware\n"
134 "Failed to set sample size\n"
140 if (ioctl (fd
, SNDCTL_DSP_CHANNELS
, &nchannels
)) {
141 dolog ("Could not initialize audio hardware\n"
142 "Failed to set number of channels\n"
148 if (ioctl (fd
, SNDCTL_DSP_SPEED
, &freq
)) {
149 dolog ("Could not initialize audio hardware\n"
150 "Failed to set frequency\n"
156 if (ioctl (fd
, SNDCTL_DSP_NONBLOCK
)) {
157 dolog ("Could not initialize audio hardware\n"
158 "Failed to set non-blocking mode\n"
164 mmmmssss
= (req
->nfrags
<< 16) | lsbindex (req
->fragsize
);
165 if (ioctl (fd
, SNDCTL_DSP_SETFRAGMENT
, &mmmmssss
)) {
166 dolog ("Could not initialize audio hardware\n"
167 "Failed to set buffer length (%d, %d)\n"
169 conf
.nfrags
, conf
.fragsize
,
174 if (ioctl (fd
, SNDCTL_DSP_GETOSPACE
, &abinfo
)) {
175 dolog ("Could not initialize audio hardware\n"
176 "Failed to get buffer length\n"
183 obt
->nchannels
= nchannels
;
185 obt
->nfrags
= abinfo
.fragstotal
;
186 obt
->fragsize
= abinfo
.fragsize
;
189 if ((req
->fmt
!= obt
->fmt
) ||
190 (req
->nchannels
!= obt
->nchannels
) ||
191 (req
->freq
!= obt
->freq
) ||
192 (req
->fragsize
!= obt
->fragsize
) ||
193 (req
->nfrags
!= obt
->nfrags
)) {
195 dolog ("Audio parameters mismatch\n");
196 oss_dump_pcm_info (req
, obt
);
201 oss_dump_pcm_info (req
, obt
);
210 static void oss_hw_run (HWVoice
*hw
)
212 OSSVoice
*oss
= (OSSVoice
*) hw
;
213 int err
, rpos
, live
, decr
;
217 struct audio_buf_info abinfo
;
218 struct count_info cntinfo
;
220 live
= pcm_hw_get_live (hw
);
227 err
= ioctl (oss
->fd
, SNDCTL_DSP_GETOPTR
, &cntinfo
);
229 dolog ("SNDCTL_DSP_GETOPTR failed\nReason: %s\n", errstr ());
233 if (cntinfo
.ptr
== oss
->old_optr
) {
234 if (abs (hw
->samples
- live
) < 64)
239 if (cntinfo
.ptr
> oss
->old_optr
) {
240 bytes
= cntinfo
.ptr
- oss
->old_optr
;
243 bytes
= hw
->bufsize
+ cntinfo
.ptr
- oss
->old_optr
;
246 decr
= audio_MIN (bytes
>> hw
->shift
, live
);
249 err
= ioctl (oss
->fd
, SNDCTL_DSP_GETOSPACE
, &abinfo
);
251 dolog ("SNDCTL_DSP_GETOSPACE failed\nReason: %s\n", errstr ());
255 decr
= audio_MIN (abinfo
.bytes
>> hw
->shift
, live
);
263 int left_till_end_samples
= hw
->samples
- rpos
;
264 int convert_samples
= audio_MIN (samples
, left_till_end_samples
);
266 src
= advance (hw
->mix_buf
, rpos
* sizeof (st_sample_t
));
267 dst
= advance (oss
->pcm_buf
, rpos
<< hw
->shift
);
269 hw
->clip (dst
, src
, convert_samples
);
273 written
= write (oss
->fd
, dst
, convert_samples
<< hw
->shift
);
274 /* XXX: follow errno recommendations ? */
276 dolog ("Failed to write audio\nReason: %s\n", errstr ());
280 if (written
!= convert_samples
<< hw
->shift
) {
281 int wsamples
= written
>> hw
->shift
;
282 int wbytes
= wsamples
<< hw
->shift
;
283 if (wbytes
!= written
) {
284 dolog ("Unaligned write %d, %d\n", wbytes
, written
);
286 memset (src
, 0, wbytes
);
288 rpos
= (rpos
+ wsamples
) % hw
->samples
;
292 memset (src
, 0, convert_samples
* sizeof (st_sample_t
));
294 rpos
= (rpos
+ convert_samples
) % hw
->samples
;
295 samples
-= convert_samples
;
298 oss
->old_optr
= cntinfo
.ptr
;
301 pcm_hw_dec_live (hw
, decr
);
305 static void oss_hw_fini (HWVoice
*hw
)
308 OSSVoice
*oss
= (OSSVoice
*) hw
;
310 ldebug ("oss_hw_fini\n");
311 err
= close (oss
->fd
);
313 dolog ("Failed to close OSS descriptor\nReason: %s\n", errstr ());
319 err
= munmap (oss
->pcm_buf
, hw
->bufsize
);
321 dolog ("Failed to unmap OSS buffer\nReason: %s\n",
326 qemu_free (oss
->pcm_buf
);
332 static int oss_hw_init (HWVoice
*hw
, int freq
, int nchannels
, audfmt_e fmt
)
334 OSSVoice
*oss
= (OSSVoice
*) hw
;
335 struct oss_params req
, obt
;
338 req
.fmt
= AUD_to_ossfmt (fmt
);
340 req
.nchannels
= nchannels
;
341 req
.fragsize
= conf
.fragsize
;
342 req
.nfrags
= conf
.nfrags
;
344 if (oss_open (&req
, &obt
, &oss
->fd
))
348 hw
->fmt
= oss_to_audfmt (obt
.fmt
);
349 hw
->nchannels
= obt
.nchannels
;
351 oss
->nfrags
= obt
.nfrags
;
352 oss
->fragsize
= obt
.fragsize
;
353 hw
->bufsize
= obt
.nfrags
* obt
.fragsize
;
357 oss
->pcm_buf
= mmap (0, hw
->bufsize
, PROT_READ
| PROT_WRITE
,
358 MAP_SHARED
, oss
->fd
, 0);
359 if (oss
->pcm_buf
== MAP_FAILED
) {
360 dolog ("Failed to mmap OSS device\nReason: %s\n",
367 if (ioctl (oss
->fd
, SNDCTL_DSP_SETTRIGGER
, &trig
) < 0) {
368 dolog ("SNDCTL_DSP_SETTRIGGER 0 failed\nReason: %s\n",
373 trig
= PCM_ENABLE_OUTPUT
;
374 if (ioctl (oss
->fd
, SNDCTL_DSP_SETTRIGGER
, &trig
) < 0) {
375 dolog ("SNDCTL_DSP_SETTRIGGER PCM_ENABLE_OUTPUT failed\n"
376 "Reason: %s\n", errstr ());
383 err
= munmap (oss
->pcm_buf
, hw
->bufsize
);
385 dolog ("Failed to unmap OSS device\nReason: %s\n",
392 oss
->pcm_buf
= qemu_mallocz (hw
->bufsize
);
403 static int oss_hw_ctl (HWVoice
*hw
, int cmd
, ...)
406 OSSVoice
*oss
= (OSSVoice
*) hw
;
413 ldebug ("enabling voice\n");
414 pcm_hw_clear (hw
, oss
->pcm_buf
, hw
->samples
);
415 trig
= PCM_ENABLE_OUTPUT
;
416 if (ioctl (oss
->fd
, SNDCTL_DSP_SETTRIGGER
, &trig
) < 0) {
417 dolog ("SNDCTL_DSP_SETTRIGGER PCM_ENABLE_OUTPUT failed\n"
418 "Reason: %s\n", errstr ());
424 ldebug ("disabling voice\n");
426 if (ioctl (oss
->fd
, SNDCTL_DSP_SETTRIGGER
, &trig
) < 0) {
427 dolog ("SNDCTL_DSP_SETTRIGGER 0 failed\nReason: %s\n",
436 static void *oss_audio_init (void)
438 conf
.fragsize
= audio_get_conf_int (QC_OSS_FRAGSIZE
, conf
.fragsize
);
439 conf
.nfrags
= audio_get_conf_int (QC_OSS_NFRAGS
, conf
.nfrags
);
440 conf
.try_mmap
= audio_get_conf_int (QC_OSS_MMAP
, conf
.try_mmap
);
441 conf
.dspname
= audio_get_conf_str (QC_OSS_DEV
, conf
.dspname
);
445 static void oss_audio_fini (void *opaque
)
449 struct pcm_ops oss_pcm_ops
= {
457 struct audio_output_driver oss_output_driver
= {