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 #include <sys/types.h>
26 #include <sys/ioctl.h>
27 #include <sys/soundcard.h>
31 #include "audio/audio_int.h"
33 typedef struct OSSVoice
{
43 #define dolog(...) AUD_log ("oss", __VA_ARGS__)
45 #define ldebug(...) dolog (__VA_ARGS__)
50 #define QC_OSS_FRAGSIZE "QEMU_OSS_FRAGSIZE"
51 #define QC_OSS_NFRAGS "QEMU_OSS_NFRAGS"
52 #define QC_OSS_MMAP "QEMU_OSS_MMAP"
53 #define QC_OSS_DEV "QEMU_OSS_DEV"
55 #define errstr() strerror (errno)
77 static int oss_hw_write (SWVoice
*sw
, void *buf
, int len
)
79 return pcm_hw_write (sw
, buf
, len
);
82 static int AUD_to_ossfmt (audfmt_e fmt
)
85 case AUD_FMT_S8
: return AFMT_S8
;
86 case AUD_FMT_U8
: return AFMT_U8
;
87 case AUD_FMT_S16
: return AFMT_S16_LE
;
88 case AUD_FMT_U16
: return AFMT_U16_LE
;
90 dolog ("Internal logic error: Bad audio format %d\nAborting\n", fmt
);
95 static int oss_to_audfmt (int fmt
)
98 case AFMT_S8
: return AUD_FMT_S8
;
99 case AFMT_U8
: return AUD_FMT_U8
;
100 case AFMT_S16_LE
: return AUD_FMT_S16
;
101 case AFMT_U16_LE
: return AUD_FMT_U16
;
103 dolog ("Internal logic error: Unrecognized OSS audio format %d\n"
111 static void oss_dump_pcm_info (struct oss_params
*req
, struct oss_params
*obt
)
113 dolog ("parameter | requested value | obtained value\n");
114 dolog ("format | %10d | %10d\n", req
->fmt
, obt
->fmt
);
115 dolog ("channels | %10d | %10d\n", req
->nchannels
, obt
->nchannels
);
116 dolog ("frequency | %10d | %10d\n", req
->freq
, obt
->freq
);
117 dolog ("nfrags | %10d | %10d\n", req
->nfrags
, obt
->nfrags
);
118 dolog ("fragsize | %10d | %10d\n", req
->fragsize
, obt
->fragsize
);
122 static int oss_open (struct oss_params
*req
, struct oss_params
*obt
, int *pfd
)
126 audio_buf_info abinfo
;
127 int fmt
, freq
, nchannels
;
128 const char *dspname
= conf
.dspname
;
130 fd
= open (dspname
, O_RDWR
| O_NONBLOCK
);
132 dolog ("Could not initialize audio hardware. Failed to open `%s':\n"
140 nchannels
= req
->nchannels
;
143 if (ioctl (fd
, SNDCTL_DSP_SAMPLESIZE
, &fmt
)) {
144 dolog ("Could not initialize audio hardware\n"
145 "Failed to set sample size\n"
151 if (ioctl (fd
, SNDCTL_DSP_CHANNELS
, &nchannels
)) {
152 dolog ("Could not initialize audio hardware\n"
153 "Failed to set number of channels\n"
159 if (ioctl (fd
, SNDCTL_DSP_SPEED
, &freq
)) {
160 dolog ("Could not initialize audio hardware\n"
161 "Failed to set frequency\n"
167 if (ioctl (fd
, SNDCTL_DSP_NONBLOCK
)) {
168 dolog ("Could not initialize audio hardware\n"
169 "Failed to set non-blocking mode\n"
175 mmmmssss
= (req
->nfrags
<< 16) | lsbindex (req
->fragsize
);
176 if (ioctl (fd
, SNDCTL_DSP_SETFRAGMENT
, &mmmmssss
)) {
177 dolog ("Could not initialize audio hardware\n"
178 "Failed to set buffer length (%d, %d)\n"
180 conf
.nfrags
, conf
.fragsize
,
185 if (ioctl (fd
, SNDCTL_DSP_GETOSPACE
, &abinfo
)) {
186 dolog ("Could not initialize audio hardware\n"
187 "Failed to get buffer length\n"
194 obt
->nchannels
= nchannels
;
196 obt
->nfrags
= abinfo
.fragstotal
;
197 obt
->fragsize
= abinfo
.fragsize
;
200 if ((req
->fmt
!= obt
->fmt
) ||
201 (req
->nchannels
!= obt
->nchannels
) ||
202 (req
->freq
!= obt
->freq
) ||
203 (req
->fragsize
!= obt
->fragsize
) ||
204 (req
->nfrags
!= obt
->nfrags
)) {
206 dolog ("Audio parameters mismatch\n");
207 oss_dump_pcm_info (req
, obt
);
212 oss_dump_pcm_info (req
, obt
);
221 static void oss_hw_run (HWVoice
*hw
)
223 OSSVoice
*oss
= (OSSVoice
*) hw
;
224 int err
, rpos
, live
, decr
;
228 struct audio_buf_info abinfo
;
229 struct count_info cntinfo
;
231 live
= pcm_hw_get_live (hw
);
238 err
= ioctl (oss
->fd
, SNDCTL_DSP_GETOPTR
, &cntinfo
);
240 dolog ("SNDCTL_DSP_GETOPTR failed\nReason: %s\n", errstr ());
244 if (cntinfo
.ptr
== oss
->old_optr
) {
245 if (abs (hw
->samples
- live
) < 64)
250 if (cntinfo
.ptr
> oss
->old_optr
) {
251 bytes
= cntinfo
.ptr
- oss
->old_optr
;
254 bytes
= hw
->bufsize
+ cntinfo
.ptr
- oss
->old_optr
;
257 decr
= audio_MIN (bytes
>> hw
->shift
, live
);
260 err
= ioctl (oss
->fd
, SNDCTL_DSP_GETOSPACE
, &abinfo
);
262 dolog ("SNDCTL_DSP_GETOSPACE failed\nReason: %s\n", errstr ());
266 decr
= audio_MIN (abinfo
.bytes
>> hw
->shift
, live
);
274 int left_till_end_samples
= hw
->samples
- rpos
;
275 int convert_samples
= audio_MIN (samples
, left_till_end_samples
);
277 src
= advance (hw
->mix_buf
, rpos
* sizeof (st_sample_t
));
278 dst
= advance (oss
->pcm_buf
, rpos
<< hw
->shift
);
280 hw
->clip (dst
, src
, convert_samples
);
284 written
= write (oss
->fd
, dst
, convert_samples
<< hw
->shift
);
285 /* XXX: follow errno recommendations ? */
287 dolog ("Failed to write audio\nReason: %s\n", errstr ());
291 if (written
!= convert_samples
<< hw
->shift
) {
292 int wsamples
= written
>> hw
->shift
;
293 int wbytes
= wsamples
<< hw
->shift
;
294 if (wbytes
!= written
) {
295 dolog ("Unaligned write %d, %d\n", wbytes
, written
);
297 memset (src
, 0, wbytes
);
299 rpos
= (rpos
+ wsamples
) % hw
->samples
;
303 memset (src
, 0, convert_samples
* sizeof (st_sample_t
));
305 rpos
= (rpos
+ convert_samples
) % hw
->samples
;
306 samples
-= convert_samples
;
309 oss
->old_optr
= cntinfo
.ptr
;
312 pcm_hw_dec_live (hw
, decr
);
316 static void oss_hw_fini (HWVoice
*hw
)
319 OSSVoice
*oss
= (OSSVoice
*) hw
;
321 ldebug ("oss_hw_fini\n");
322 err
= close (oss
->fd
);
324 dolog ("Failed to close OSS descriptor\nReason: %s\n", errstr ());
330 err
= munmap (oss
->pcm_buf
, hw
->bufsize
);
332 dolog ("Failed to unmap OSS buffer\nReason: %s\n",
337 qemu_free (oss
->pcm_buf
);
343 static int oss_hw_init (HWVoice
*hw
, int freq
, int nchannels
, audfmt_e fmt
)
345 OSSVoice
*oss
= (OSSVoice
*) hw
;
346 struct oss_params req
, obt
;
349 req
.fmt
= AUD_to_ossfmt (fmt
);
351 req
.nchannels
= nchannels
;
352 req
.fragsize
= conf
.fragsize
;
353 req
.nfrags
= conf
.nfrags
;
355 if (oss_open (&req
, &obt
, &oss
->fd
))
359 hw
->fmt
= oss_to_audfmt (obt
.fmt
);
360 hw
->nchannels
= obt
.nchannels
;
362 oss
->nfrags
= obt
.nfrags
;
363 oss
->fragsize
= obt
.fragsize
;
364 hw
->bufsize
= obt
.nfrags
* obt
.fragsize
;
368 oss
->pcm_buf
= mmap (0, hw
->bufsize
, PROT_READ
| PROT_WRITE
,
369 MAP_SHARED
, oss
->fd
, 0);
370 if (oss
->pcm_buf
== MAP_FAILED
) {
371 dolog ("Failed to mmap OSS device\nReason: %s\n",
376 if (ioctl (oss
->fd
, SNDCTL_DSP_SETTRIGGER
, &trig
) < 0) {
377 dolog ("SNDCTL_DSP_SETTRIGGER 0 failed\nReason: %s\n",
381 trig
= PCM_ENABLE_OUTPUT
;
382 if (ioctl (oss
->fd
, SNDCTL_DSP_SETTRIGGER
, &trig
) < 0) {
383 dolog ("SNDCTL_DSP_SETTRIGGER PCM_ENABLE_OUTPUT failed\n"
384 "Reason: %s\n", errstr ());
392 err
= munmap (oss
->pcm_buf
, hw
->bufsize
);
394 dolog ("Failed to unmap OSS device\nReason: %s\n",
402 oss
->pcm_buf
= qemu_mallocz (hw
->bufsize
);
413 static int oss_hw_ctl (HWVoice
*hw
, int cmd
, ...)
416 OSSVoice
*oss
= (OSSVoice
*) hw
;
423 ldebug ("enabling voice\n");
424 pcm_hw_clear (hw
, oss
->pcm_buf
, hw
->samples
);
425 trig
= PCM_ENABLE_OUTPUT
;
426 if (ioctl (oss
->fd
, SNDCTL_DSP_SETTRIGGER
, &trig
) < 0) {
427 dolog ("SNDCTL_DSP_SETTRIGGER PCM_ENABLE_OUTPUT failed\n"
428 "Reason: %s\n", errstr ());
434 ldebug ("disabling voice\n");
436 if (ioctl (oss
->fd
, SNDCTL_DSP_SETTRIGGER
, &trig
) < 0) {
437 dolog ("SNDCTL_DSP_SETTRIGGER 0 failed\nReason: %s\n",
446 static void *oss_audio_init (void)
448 conf
.fragsize
= audio_get_conf_int (QC_OSS_FRAGSIZE
, conf
.fragsize
);
449 conf
.nfrags
= audio_get_conf_int (QC_OSS_NFRAGS
, conf
.nfrags
);
450 conf
.try_mmap
= audio_get_conf_int (QC_OSS_MMAP
, conf
.try_mmap
);
451 conf
.dspname
= audio_get_conf_str (QC_OSS_DEV
, conf
.dspname
);
455 static void oss_audio_fini (void *opaque
)
459 struct pcm_ops oss_pcm_ops
= {
467 struct audio_output_driver oss_output_driver
= {