Statistics
| Branch: | Revision:

root / audio / ossaudio.c @ 977d5710

History | View | Annotate | Download (12.7 kB)

1 85571bc7 bellard
/*
2 85571bc7 bellard
 * QEMU OSS audio output driver
3 85571bc7 bellard
 * 
4 85571bc7 bellard
 * Copyright (c) 2003-2004 Vassili Karpov (malc)
5 85571bc7 bellard
 * 
6 85571bc7 bellard
 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 85571bc7 bellard
 * of this software and associated documentation files (the "Software"), to deal
8 85571bc7 bellard
 * in the Software without restriction, including without limitation the rights
9 85571bc7 bellard
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 85571bc7 bellard
 * copies of the Software, and to permit persons to whom the Software is
11 85571bc7 bellard
 * furnished to do so, subject to the following conditions:
12 85571bc7 bellard
 *
13 85571bc7 bellard
 * The above copyright notice and this permission notice shall be included in
14 85571bc7 bellard
 * all copies or substantial portions of the Software.
15 85571bc7 bellard
 *
16 85571bc7 bellard
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 85571bc7 bellard
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 85571bc7 bellard
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 85571bc7 bellard
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 85571bc7 bellard
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 85571bc7 bellard
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 85571bc7 bellard
 * THE SOFTWARE.
23 85571bc7 bellard
 */
24 85571bc7 bellard
#include <sys/mman.h>
25 85571bc7 bellard
#include <sys/types.h>
26 85571bc7 bellard
#include <sys/ioctl.h>
27 85571bc7 bellard
#include <sys/soundcard.h>
28 fb065187 bellard
#include <assert.h>
29 fb065187 bellard
#include "vl.h"
30 fb065187 bellard
31 fb065187 bellard
#include "audio/audio_int.h"
32 fb065187 bellard
33 fb065187 bellard
typedef struct OSSVoice {
34 fb065187 bellard
    HWVoice hw;
35 fb065187 bellard
    void *pcm_buf;
36 fb065187 bellard
    int fd;
37 fb065187 bellard
    int nfrags;
38 fb065187 bellard
    int fragsize;
39 fb065187 bellard
    int mmapped;
40 fb065187 bellard
    int old_optr;
41 fb065187 bellard
} OSSVoice;
42 85571bc7 bellard
43 fb065187 bellard
#define dolog(...) AUD_log ("oss", __VA_ARGS__)
44 fb065187 bellard
#ifdef DEBUG
45 fb065187 bellard
#define ldebug(...) dolog (__VA_ARGS__)
46 fb065187 bellard
#else
47 fb065187 bellard
#define ldebug(...)
48 fb065187 bellard
#endif
49 85571bc7 bellard
50 85571bc7 bellard
#define QC_OSS_FRAGSIZE "QEMU_OSS_FRAGSIZE"
51 85571bc7 bellard
#define QC_OSS_NFRAGS   "QEMU_OSS_NFRAGS"
52 85571bc7 bellard
#define QC_OSS_MMAP     "QEMU_OSS_MMAP"
53 85571bc7 bellard
#define QC_OSS_DEV      "QEMU_OSS_DEV"
54 85571bc7 bellard
55 85571bc7 bellard
#define errstr() strerror (errno)
56 85571bc7 bellard
57 85571bc7 bellard
static struct {
58 85571bc7 bellard
    int try_mmap;
59 85571bc7 bellard
    int nfrags;
60 85571bc7 bellard
    int fragsize;
61 85571bc7 bellard
    const char *dspname;
62 85571bc7 bellard
} conf = {
63 85571bc7 bellard
    .try_mmap = 0,
64 85571bc7 bellard
    .nfrags = 4,
65 85571bc7 bellard
    .fragsize = 4096,
66 85571bc7 bellard
    .dspname = "/dev/dsp"
67 85571bc7 bellard
};
68 85571bc7 bellard
69 85571bc7 bellard
struct oss_params {
70 85571bc7 bellard
    int freq;
71 85571bc7 bellard
    audfmt_e fmt;
72 85571bc7 bellard
    int nchannels;
73 85571bc7 bellard
    int nfrags;
74 85571bc7 bellard
    int fragsize;
75 85571bc7 bellard
};
76 85571bc7 bellard
77 85571bc7 bellard
static int oss_hw_write (SWVoice *sw, void *buf, int len)
78 85571bc7 bellard
{
79 85571bc7 bellard
    return pcm_hw_write (sw, buf, len);
80 85571bc7 bellard
}
81 85571bc7 bellard
82 85571bc7 bellard
static int AUD_to_ossfmt (audfmt_e fmt)
83 85571bc7 bellard
{
84 85571bc7 bellard
    switch (fmt) {
85 85571bc7 bellard
    case AUD_FMT_S8: return AFMT_S8;
86 85571bc7 bellard
    case AUD_FMT_U8: return AFMT_U8;
87 85571bc7 bellard
    case AUD_FMT_S16: return AFMT_S16_LE;
88 85571bc7 bellard
    case AUD_FMT_U16: return AFMT_U16_LE;
89 85571bc7 bellard
    default:
90 85571bc7 bellard
        dolog ("Internal logic error: Bad audio format %d\nAborting\n", fmt);
91 85571bc7 bellard
        exit (EXIT_FAILURE);
92 85571bc7 bellard
    }
93 85571bc7 bellard
}
94 85571bc7 bellard
95 85571bc7 bellard
static int oss_to_audfmt (int fmt)
96 85571bc7 bellard
{
97 85571bc7 bellard
    switch (fmt) {
98 85571bc7 bellard
    case AFMT_S8: return AUD_FMT_S8;
99 85571bc7 bellard
    case AFMT_U8: return AUD_FMT_U8;
100 85571bc7 bellard
    case AFMT_S16_LE: return AUD_FMT_S16;
101 85571bc7 bellard
    case AFMT_U16_LE: return AUD_FMT_U16;
102 85571bc7 bellard
    default:
103 85571bc7 bellard
        dolog ("Internal logic error: Unrecognized OSS audio format %d\n"
104 85571bc7 bellard
               "Aborting\n",
105 85571bc7 bellard
               fmt);
106 85571bc7 bellard
        exit (EXIT_FAILURE);
107 85571bc7 bellard
    }
108 85571bc7 bellard
}
109 85571bc7 bellard
110 85571bc7 bellard
#ifdef DEBUG_PCM
111 85571bc7 bellard
static void oss_dump_pcm_info (struct oss_params *req, struct oss_params *obt)
112 85571bc7 bellard
{
113 85571bc7 bellard
    dolog ("parameter | requested value | obtained value\n");
114 85571bc7 bellard
    dolog ("format    |      %10d |     %10d\n", req->fmt, obt->fmt);
115 85571bc7 bellard
    dolog ("channels  |      %10d |     %10d\n", req->nchannels, obt->nchannels);
116 85571bc7 bellard
    dolog ("frequency |      %10d |     %10d\n", req->freq, obt->freq);
117 85571bc7 bellard
    dolog ("nfrags    |      %10d |     %10d\n", req->nfrags, obt->nfrags);
118 85571bc7 bellard
    dolog ("fragsize  |      %10d |     %10d\n", req->fragsize, obt->fragsize);
119 85571bc7 bellard
}
120 85571bc7 bellard
#endif
121 85571bc7 bellard
122 85571bc7 bellard
static int oss_open (struct oss_params *req, struct oss_params *obt, int *pfd)
123 85571bc7 bellard
{
124 85571bc7 bellard
    int fd;
125 85571bc7 bellard
    int mmmmssss;
126 85571bc7 bellard
    audio_buf_info abinfo;
127 85571bc7 bellard
    int fmt, freq, nchannels;
128 85571bc7 bellard
    const char *dspname = conf.dspname;
129 85571bc7 bellard
130 85571bc7 bellard
    fd = open (dspname, O_RDWR | O_NONBLOCK);
131 85571bc7 bellard
    if (-1 == fd) {
132 85571bc7 bellard
        dolog ("Could not initialize audio hardware. Failed to open `%s':\n"
133 85571bc7 bellard
               "Reason:%s\n",
134 85571bc7 bellard
               dspname,
135 85571bc7 bellard
               errstr ());
136 85571bc7 bellard
        return -1;
137 85571bc7 bellard
    }
138 85571bc7 bellard
139 85571bc7 bellard
    freq = req->freq;
140 85571bc7 bellard
    nchannels = req->nchannels;
141 85571bc7 bellard
    fmt = req->fmt;
142 85571bc7 bellard
143 85571bc7 bellard
    if (ioctl (fd, SNDCTL_DSP_SAMPLESIZE, &fmt)) {
144 85571bc7 bellard
        dolog ("Could not initialize audio hardware\n"
145 85571bc7 bellard
               "Failed to set sample size\n"
146 85571bc7 bellard
               "Reason: %s\n",
147 85571bc7 bellard
               errstr ());
148 85571bc7 bellard
        goto err;
149 85571bc7 bellard
    }
150 85571bc7 bellard
151 85571bc7 bellard
    if (ioctl (fd, SNDCTL_DSP_CHANNELS, &nchannels)) {
152 85571bc7 bellard
        dolog ("Could not initialize audio hardware\n"
153 85571bc7 bellard
               "Failed to set number of channels\n"
154 85571bc7 bellard
               "Reason: %s\n",
155 85571bc7 bellard
               errstr ());
156 85571bc7 bellard
        goto err;
157 85571bc7 bellard
    }
158 85571bc7 bellard
159 85571bc7 bellard
    if (ioctl (fd, SNDCTL_DSP_SPEED, &freq)) {
160 85571bc7 bellard
        dolog ("Could not initialize audio hardware\n"
161 85571bc7 bellard
               "Failed to set frequency\n"
162 85571bc7 bellard
               "Reason: %s\n",
163 85571bc7 bellard
               errstr ());
164 85571bc7 bellard
        goto err;
165 85571bc7 bellard
    }
166 85571bc7 bellard
167 85571bc7 bellard
    if (ioctl (fd, SNDCTL_DSP_NONBLOCK)) {
168 85571bc7 bellard
        dolog ("Could not initialize audio hardware\n"
169 85571bc7 bellard
               "Failed to set non-blocking mode\n"
170 85571bc7 bellard
               "Reason: %s\n",
171 85571bc7 bellard
               errstr ());
172 85571bc7 bellard
        goto err;
173 85571bc7 bellard
    }
174 85571bc7 bellard
175 85571bc7 bellard
    mmmmssss = (req->nfrags << 16) | lsbindex (req->fragsize);
176 85571bc7 bellard
    if (ioctl (fd, SNDCTL_DSP_SETFRAGMENT, &mmmmssss)) {
177 85571bc7 bellard
        dolog ("Could not initialize audio hardware\n"
178 85571bc7 bellard
               "Failed to set buffer length (%d, %d)\n"
179 85571bc7 bellard
               "Reason:%s\n",
180 85571bc7 bellard
               conf.nfrags, conf.fragsize,
181 85571bc7 bellard
               errstr ());
182 85571bc7 bellard
        goto err;
183 85571bc7 bellard
    }
184 85571bc7 bellard
185 85571bc7 bellard
    if (ioctl (fd, SNDCTL_DSP_GETOSPACE, &abinfo)) {
186 85571bc7 bellard
        dolog ("Could not initialize audio hardware\n"
187 85571bc7 bellard
               "Failed to get buffer length\n"
188 85571bc7 bellard
               "Reason:%s\n",
189 85571bc7 bellard
               errstr ());
190 85571bc7 bellard
        goto err;
191 85571bc7 bellard
    }
192 85571bc7 bellard
193 85571bc7 bellard
    obt->fmt = fmt;
194 85571bc7 bellard
    obt->nchannels = nchannels;
195 85571bc7 bellard
    obt->freq = freq;
196 85571bc7 bellard
    obt->nfrags = abinfo.fragstotal;
197 85571bc7 bellard
    obt->fragsize = abinfo.fragsize;
198 85571bc7 bellard
    *pfd = fd;
199 85571bc7 bellard
200 85571bc7 bellard
    if ((req->fmt != obt->fmt) ||
201 85571bc7 bellard
        (req->nchannels != obt->nchannels) ||
202 85571bc7 bellard
        (req->freq != obt->freq) ||
203 85571bc7 bellard
        (req->fragsize != obt->fragsize) ||
204 85571bc7 bellard
        (req->nfrags != obt->nfrags)) {
205 85571bc7 bellard
#ifdef DEBUG_PCM
206 85571bc7 bellard
        dolog ("Audio parameters mismatch\n");
207 85571bc7 bellard
        oss_dump_pcm_info (req, obt);
208 85571bc7 bellard
#endif
209 85571bc7 bellard
    }
210 85571bc7 bellard
211 85571bc7 bellard
#ifdef DEBUG_PCM
212 85571bc7 bellard
    oss_dump_pcm_info (req, obt);
213 85571bc7 bellard
#endif
214 85571bc7 bellard
    return 0;
215 85571bc7 bellard
216 85571bc7 bellard
err:
217 85571bc7 bellard
    close (fd);
218 85571bc7 bellard
    return -1;
219 85571bc7 bellard
}
220 85571bc7 bellard
221 85571bc7 bellard
static void oss_hw_run (HWVoice *hw)
222 85571bc7 bellard
{
223 85571bc7 bellard
    OSSVoice *oss = (OSSVoice *) hw;
224 85571bc7 bellard
    int err, rpos, live, decr;
225 85571bc7 bellard
    int samples;
226 85571bc7 bellard
    uint8_t *dst;
227 85571bc7 bellard
    st_sample_t *src;
228 85571bc7 bellard
    struct audio_buf_info abinfo;
229 85571bc7 bellard
    struct count_info cntinfo;
230 85571bc7 bellard
231 85571bc7 bellard
    live = pcm_hw_get_live (hw);
232 85571bc7 bellard
    if (live <= 0)
233 85571bc7 bellard
        return;
234 85571bc7 bellard
235 85571bc7 bellard
    if (oss->mmapped) {
236 85571bc7 bellard
        int bytes;
237 85571bc7 bellard
238 85571bc7 bellard
        err = ioctl (oss->fd, SNDCTL_DSP_GETOPTR, &cntinfo);
239 85571bc7 bellard
        if (err < 0) {
240 85571bc7 bellard
            dolog ("SNDCTL_DSP_GETOPTR failed\nReason: %s\n", errstr ());
241 85571bc7 bellard
            return;
242 85571bc7 bellard
        }
243 85571bc7 bellard
244 85571bc7 bellard
        if (cntinfo.ptr == oss->old_optr) {
245 85571bc7 bellard
            if (abs (hw->samples - live) < 64)
246 85571bc7 bellard
                dolog ("overrun\n");
247 85571bc7 bellard
            return;
248 85571bc7 bellard
        }
249 85571bc7 bellard
250 85571bc7 bellard
        if (cntinfo.ptr > oss->old_optr) {
251 85571bc7 bellard
            bytes = cntinfo.ptr - oss->old_optr;
252 85571bc7 bellard
        }
253 85571bc7 bellard
        else {
254 85571bc7 bellard
            bytes = hw->bufsize + cntinfo.ptr - oss->old_optr;
255 85571bc7 bellard
        }
256 85571bc7 bellard
257 85571bc7 bellard
        decr = audio_MIN (bytes >> hw->shift, live);
258 85571bc7 bellard
    }
259 85571bc7 bellard
    else {
260 85571bc7 bellard
        err = ioctl (oss->fd, SNDCTL_DSP_GETOSPACE, &abinfo);
261 85571bc7 bellard
        if (err < 0) {
262 85571bc7 bellard
            dolog ("SNDCTL_DSP_GETOSPACE failed\nReason: %s\n", errstr ());
263 85571bc7 bellard
            return;
264 85571bc7 bellard
        }
265 85571bc7 bellard
266 85571bc7 bellard
        decr = audio_MIN (abinfo.bytes >> hw->shift, live);
267 85571bc7 bellard
        if (decr <= 0)
268 85571bc7 bellard
            return;
269 85571bc7 bellard
    }
270 85571bc7 bellard
271 85571bc7 bellard
    samples = decr;
272 85571bc7 bellard
    rpos = hw->rpos;
273 85571bc7 bellard
    while (samples) {
274 85571bc7 bellard
        int left_till_end_samples = hw->samples - rpos;
275 85571bc7 bellard
        int convert_samples = audio_MIN (samples, left_till_end_samples);
276 85571bc7 bellard
277 85571bc7 bellard
        src = advance (hw->mix_buf, rpos * sizeof (st_sample_t));
278 85571bc7 bellard
        dst = advance (oss->pcm_buf, rpos << hw->shift);
279 85571bc7 bellard
280 85571bc7 bellard
        hw->clip (dst, src, convert_samples);
281 85571bc7 bellard
        if (!oss->mmapped) {
282 85571bc7 bellard
            int written;
283 85571bc7 bellard
284 85571bc7 bellard
            written = write (oss->fd, dst, convert_samples << hw->shift);
285 85571bc7 bellard
            /* XXX: follow errno recommendations ? */
286 85571bc7 bellard
            if (written == -1) {
287 85571bc7 bellard
                dolog ("Failed to write audio\nReason: %s\n", errstr ());
288 85571bc7 bellard
                continue;
289 85571bc7 bellard
            }
290 85571bc7 bellard
291 85571bc7 bellard
            if (written != convert_samples << hw->shift) {
292 85571bc7 bellard
                int wsamples = written >> hw->shift;
293 85571bc7 bellard
                int wbytes = wsamples << hw->shift;
294 85571bc7 bellard
                if (wbytes != written) {
295 85571bc7 bellard
                    dolog ("Unaligned write %d, %d\n", wbytes, written);
296 85571bc7 bellard
                }
297 85571bc7 bellard
                memset (src, 0, wbytes);
298 85571bc7 bellard
                decr -= samples;
299 85571bc7 bellard
                rpos = (rpos + wsamples) % hw->samples;
300 85571bc7 bellard
                break;
301 85571bc7 bellard
            }
302 85571bc7 bellard
        }
303 85571bc7 bellard
        memset (src, 0, convert_samples * sizeof (st_sample_t));
304 85571bc7 bellard
305 85571bc7 bellard
        rpos = (rpos + convert_samples) % hw->samples;
306 85571bc7 bellard
        samples -= convert_samples;
307 85571bc7 bellard
    }
308 85571bc7 bellard
    if (oss->mmapped) {
309 85571bc7 bellard
        oss->old_optr = cntinfo.ptr;
310 85571bc7 bellard
    }
311 85571bc7 bellard
312 85571bc7 bellard
    pcm_hw_dec_live (hw, decr);
313 85571bc7 bellard
    hw->rpos = rpos;
314 85571bc7 bellard
}
315 85571bc7 bellard
316 85571bc7 bellard
static void oss_hw_fini (HWVoice *hw)
317 85571bc7 bellard
{
318 85571bc7 bellard
    int err;
319 85571bc7 bellard
    OSSVoice *oss = (OSSVoice *) hw;
320 85571bc7 bellard
321 85571bc7 bellard
    ldebug ("oss_hw_fini\n");
322 85571bc7 bellard
    err = close (oss->fd);
323 85571bc7 bellard
    if (err) {
324 85571bc7 bellard
        dolog ("Failed to close OSS descriptor\nReason: %s\n", errstr ());
325 85571bc7 bellard
    }
326 85571bc7 bellard
    oss->fd = -1;
327 85571bc7 bellard
328 85571bc7 bellard
    if (oss->pcm_buf) {
329 85571bc7 bellard
        if (oss->mmapped) {
330 85571bc7 bellard
            err = munmap (oss->pcm_buf, hw->bufsize);
331 85571bc7 bellard
            if (err) {
332 85571bc7 bellard
                dolog ("Failed to unmap OSS buffer\nReason: %s\n",
333 85571bc7 bellard
                       errstr ());
334 85571bc7 bellard
            }
335 85571bc7 bellard
        }
336 85571bc7 bellard
        else {
337 85571bc7 bellard
            qemu_free (oss->pcm_buf);
338 85571bc7 bellard
        }
339 85571bc7 bellard
        oss->pcm_buf = NULL;
340 85571bc7 bellard
    }
341 85571bc7 bellard
}
342 85571bc7 bellard
343 85571bc7 bellard
static int oss_hw_init (HWVoice *hw, int freq, int nchannels, audfmt_e fmt)
344 85571bc7 bellard
{
345 85571bc7 bellard
    OSSVoice *oss = (OSSVoice *) hw;
346 85571bc7 bellard
    struct oss_params req, obt;
347 85571bc7 bellard
348 85571bc7 bellard
    assert (!oss->fd);
349 85571bc7 bellard
    req.fmt = AUD_to_ossfmt (fmt);
350 85571bc7 bellard
    req.freq = freq;
351 85571bc7 bellard
    req.nchannels = nchannels;
352 85571bc7 bellard
    req.fragsize = conf.fragsize;
353 85571bc7 bellard
    req.nfrags = conf.nfrags;
354 85571bc7 bellard
355 85571bc7 bellard
    if (oss_open (&req, &obt, &oss->fd))
356 85571bc7 bellard
        return -1;
357 85571bc7 bellard
358 85571bc7 bellard
    hw->freq = obt.freq;
359 85571bc7 bellard
    hw->fmt = oss_to_audfmt (obt.fmt);
360 85571bc7 bellard
    hw->nchannels = obt.nchannels;
361 85571bc7 bellard
362 85571bc7 bellard
    oss->nfrags = obt.nfrags;
363 85571bc7 bellard
    oss->fragsize = obt.fragsize;
364 85571bc7 bellard
    hw->bufsize = obt.nfrags * obt.fragsize;
365 85571bc7 bellard
366 85571bc7 bellard
    oss->mmapped = 0;
367 85571bc7 bellard
    if (conf.try_mmap) {
368 85571bc7 bellard
        oss->pcm_buf = mmap (0, hw->bufsize, PROT_READ | PROT_WRITE,
369 85571bc7 bellard
                             MAP_SHARED, oss->fd, 0);
370 85571bc7 bellard
        if (oss->pcm_buf == MAP_FAILED) {
371 85571bc7 bellard
            dolog ("Failed to mmap OSS device\nReason: %s\n",
372 85571bc7 bellard
                   errstr ());
373 44a095a7 bellard
        } else {
374 85571bc7 bellard
            int err;
375 85571bc7 bellard
            int trig = 0;
376 85571bc7 bellard
            if (ioctl (oss->fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) {
377 85571bc7 bellard
                dolog ("SNDCTL_DSP_SETTRIGGER 0 failed\nReason: %s\n",
378 85571bc7 bellard
                       errstr ());
379 85571bc7 bellard
            }
380 44a095a7 bellard
            else {
381 44a095a7 bellard
                trig = PCM_ENABLE_OUTPUT;
382 44a095a7 bellard
                if (ioctl (oss->fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) {
383 44a095a7 bellard
                    dolog ("SNDCTL_DSP_SETTRIGGER PCM_ENABLE_OUTPUT failed\n"
384 44a095a7 bellard
                           "Reason: %s\n", errstr ());
385 44a095a7 bellard
                }
386 44a095a7 bellard
                else {
387 44a095a7 bellard
                    oss->mmapped = 1;
388 44a095a7 bellard
                }
389 85571bc7 bellard
            }
390 85571bc7 bellard
391 44a095a7 bellard
            if (!oss->mmapped) {
392 44a095a7 bellard
                err = munmap (oss->pcm_buf, hw->bufsize);
393 44a095a7 bellard
                if (err) {
394 44a095a7 bellard
                    dolog ("Failed to unmap OSS device\nReason: %s\n",
395 44a095a7 bellard
                           errstr ());
396 44a095a7 bellard
                }
397 85571bc7 bellard
            }
398 85571bc7 bellard
        }
399 85571bc7 bellard
    }
400 85571bc7 bellard
401 85571bc7 bellard
    if (!oss->mmapped) {
402 85571bc7 bellard
        oss->pcm_buf = qemu_mallocz (hw->bufsize);
403 85571bc7 bellard
        if (!oss->pcm_buf) {
404 85571bc7 bellard
            close (oss->fd);
405 85571bc7 bellard
            oss->fd = -1;
406 85571bc7 bellard
            return -1;
407 85571bc7 bellard
        }
408 85571bc7 bellard
    }
409 85571bc7 bellard
410 85571bc7 bellard
    return 0;
411 85571bc7 bellard
}
412 85571bc7 bellard
413 85571bc7 bellard
static int oss_hw_ctl (HWVoice *hw, int cmd, ...)
414 85571bc7 bellard
{
415 85571bc7 bellard
    int trig;
416 85571bc7 bellard
    OSSVoice *oss = (OSSVoice *) hw;
417 85571bc7 bellard
418 85571bc7 bellard
    if (!oss->mmapped)
419 85571bc7 bellard
        return 0;
420 85571bc7 bellard
421 85571bc7 bellard
    switch (cmd) {
422 85571bc7 bellard
    case VOICE_ENABLE:
423 85571bc7 bellard
        ldebug ("enabling voice\n");
424 85571bc7 bellard
        pcm_hw_clear (hw, oss->pcm_buf, hw->samples);
425 85571bc7 bellard
        trig = PCM_ENABLE_OUTPUT;
426 85571bc7 bellard
        if (ioctl (oss->fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) {
427 85571bc7 bellard
            dolog ("SNDCTL_DSP_SETTRIGGER PCM_ENABLE_OUTPUT failed\n"
428 85571bc7 bellard
                   "Reason: %s\n", errstr ());
429 85571bc7 bellard
            return -1;
430 85571bc7 bellard
        }
431 85571bc7 bellard
        break;
432 85571bc7 bellard
433 85571bc7 bellard
    case VOICE_DISABLE:
434 85571bc7 bellard
        ldebug ("disabling voice\n");
435 85571bc7 bellard
        trig = 0;
436 85571bc7 bellard
        if (ioctl (oss->fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) {
437 85571bc7 bellard
            dolog ("SNDCTL_DSP_SETTRIGGER 0 failed\nReason: %s\n",
438 85571bc7 bellard
                   errstr ());
439 85571bc7 bellard
            return -1;
440 85571bc7 bellard
        }
441 85571bc7 bellard
        break;
442 85571bc7 bellard
    }
443 85571bc7 bellard
    return 0;
444 85571bc7 bellard
}
445 85571bc7 bellard
446 85571bc7 bellard
static void *oss_audio_init (void)
447 85571bc7 bellard
{
448 85571bc7 bellard
    conf.fragsize = audio_get_conf_int (QC_OSS_FRAGSIZE, conf.fragsize);
449 85571bc7 bellard
    conf.nfrags = audio_get_conf_int (QC_OSS_NFRAGS, conf.nfrags);
450 85571bc7 bellard
    conf.try_mmap = audio_get_conf_int (QC_OSS_MMAP, conf.try_mmap);
451 85571bc7 bellard
    conf.dspname = audio_get_conf_str (QC_OSS_DEV, conf.dspname);
452 85571bc7 bellard
    return &conf;
453 85571bc7 bellard
}
454 85571bc7 bellard
455 85571bc7 bellard
static void oss_audio_fini (void *opaque)
456 85571bc7 bellard
{
457 85571bc7 bellard
}
458 85571bc7 bellard
459 85571bc7 bellard
struct pcm_ops oss_pcm_ops = {
460 85571bc7 bellard
    oss_hw_init,
461 85571bc7 bellard
    oss_hw_fini,
462 85571bc7 bellard
    oss_hw_run,
463 85571bc7 bellard
    oss_hw_write,
464 85571bc7 bellard
    oss_hw_ctl
465 85571bc7 bellard
};
466 85571bc7 bellard
467 85571bc7 bellard
struct audio_output_driver oss_output_driver = {
468 85571bc7 bellard
    "oss",
469 85571bc7 bellard
    oss_audio_init,
470 85571bc7 bellard
    oss_audio_fini,
471 85571bc7 bellard
    &oss_pcm_ops,
472 85571bc7 bellard
    1,
473 85571bc7 bellard
    INT_MAX,
474 85571bc7 bellard
    sizeof (OSSVoice)
475 85571bc7 bellard
};