Statistics
| Branch: | Revision:

root / audio / sdlaudio.c @ 86cc1ce0

History | View | Annotate | Download (9.7 kB)

1 85571bc7 bellard
/*
2 1d14ffa9 bellard
 * QEMU SDL audio driver
3 1d14ffa9 bellard
 *
4 1d14ffa9 bellard
 * Copyright (c) 2004-2005 Vassili Karpov (malc)
5 1d14ffa9 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 9f059eca bellard
#include <SDL.h>
25 9f059eca bellard
#include <SDL_thread.h>
26 85571bc7 bellard
#include "vl.h"
27 85571bc7 bellard
28 1d14ffa9 bellard
#define AUDIO_CAP "sdl"
29 1d14ffa9 bellard
#include "audio_int.h"
30 85571bc7 bellard
31 1d14ffa9 bellard
typedef struct SDLVoiceOut {
32 1d14ffa9 bellard
    HWVoiceOut hw;
33 1d14ffa9 bellard
    int live;
34 1d14ffa9 bellard
    int rpos;
35 1d14ffa9 bellard
    int decr;
36 1d14ffa9 bellard
} SDLVoiceOut;
37 85571bc7 bellard
38 85571bc7 bellard
static struct {
39 85571bc7 bellard
    int nb_samples;
40 85571bc7 bellard
} conf = {
41 85571bc7 bellard
    1024
42 85571bc7 bellard
};
43 85571bc7 bellard
44 85571bc7 bellard
struct SDLAudioState {
45 85571bc7 bellard
    int exit;
46 85571bc7 bellard
    SDL_mutex *mutex;
47 85571bc7 bellard
    SDL_sem *sem;
48 85571bc7 bellard
    int initialized;
49 85571bc7 bellard
} glob_sdl;
50 85571bc7 bellard
typedef struct SDLAudioState SDLAudioState;
51 85571bc7 bellard
52 1d14ffa9 bellard
static void GCC_FMT_ATTR (1, 2) sdl_logerr (const char *fmt, ...)
53 85571bc7 bellard
{
54 1d14ffa9 bellard
    va_list ap;
55 1d14ffa9 bellard
56 1d14ffa9 bellard
    va_start (ap, fmt);
57 1d14ffa9 bellard
    AUD_vlog (AUDIO_CAP, fmt, ap);
58 1d14ffa9 bellard
    va_end (ap);
59 1d14ffa9 bellard
60 1d14ffa9 bellard
    AUD_log (AUDIO_CAP, "Reason: %s\n", SDL_GetError ());
61 85571bc7 bellard
}
62 85571bc7 bellard
63 1d14ffa9 bellard
static int sdl_lock (SDLAudioState *s, const char *forfn)
64 85571bc7 bellard
{
65 85571bc7 bellard
    if (SDL_LockMutex (s->mutex)) {
66 1d14ffa9 bellard
        sdl_logerr ("SDL_LockMutex for %s failed\n", forfn);
67 85571bc7 bellard
        return -1;
68 85571bc7 bellard
    }
69 85571bc7 bellard
    return 0;
70 85571bc7 bellard
}
71 85571bc7 bellard
72 1d14ffa9 bellard
static int sdl_unlock (SDLAudioState *s, const char *forfn)
73 85571bc7 bellard
{
74 85571bc7 bellard
    if (SDL_UnlockMutex (s->mutex)) {
75 1d14ffa9 bellard
        sdl_logerr ("SDL_UnlockMutex for %s failed\n", forfn);
76 85571bc7 bellard
        return -1;
77 85571bc7 bellard
    }
78 85571bc7 bellard
    return 0;
79 85571bc7 bellard
}
80 85571bc7 bellard
81 1d14ffa9 bellard
static int sdl_post (SDLAudioState *s, const char *forfn)
82 85571bc7 bellard
{
83 85571bc7 bellard
    if (SDL_SemPost (s->sem)) {
84 1d14ffa9 bellard
        sdl_logerr ("SDL_SemPost for %s failed\n", forfn);
85 85571bc7 bellard
        return -1;
86 85571bc7 bellard
    }
87 85571bc7 bellard
    return 0;
88 85571bc7 bellard
}
89 85571bc7 bellard
90 1d14ffa9 bellard
static int sdl_wait (SDLAudioState *s, const char *forfn)
91 85571bc7 bellard
{
92 85571bc7 bellard
    if (SDL_SemWait (s->sem)) {
93 1d14ffa9 bellard
        sdl_logerr ("SDL_SemWait for %s failed\n", forfn);
94 85571bc7 bellard
        return -1;
95 85571bc7 bellard
    }
96 85571bc7 bellard
    return 0;
97 85571bc7 bellard
}
98 85571bc7 bellard
99 1d14ffa9 bellard
static int sdl_unlock_and_post (SDLAudioState *s, const char *forfn)
100 85571bc7 bellard
{
101 1d14ffa9 bellard
    if (sdl_unlock (s, forfn)) {
102 85571bc7 bellard
        return -1;
103 1d14ffa9 bellard
    }
104 85571bc7 bellard
105 1d14ffa9 bellard
    return sdl_post (s, forfn);
106 85571bc7 bellard
}
107 85571bc7 bellard
108 1d14ffa9 bellard
static int aud_to_sdlfmt (audfmt_e fmt, int *shift)
109 85571bc7 bellard
{
110 85571bc7 bellard
    switch (fmt) {
111 1d14ffa9 bellard
    case AUD_FMT_S8:
112 1d14ffa9 bellard
        *shift = 0;
113 1d14ffa9 bellard
        return AUDIO_S8;
114 1d14ffa9 bellard
115 1d14ffa9 bellard
    case AUD_FMT_U8:
116 1d14ffa9 bellard
        *shift = 0;
117 1d14ffa9 bellard
        return AUDIO_U8;
118 1d14ffa9 bellard
119 1d14ffa9 bellard
    case AUD_FMT_S16:
120 1d14ffa9 bellard
        *shift = 1;
121 1d14ffa9 bellard
        return AUDIO_S16LSB;
122 1d14ffa9 bellard
123 1d14ffa9 bellard
    case AUD_FMT_U16:
124 1d14ffa9 bellard
        *shift = 1;
125 1d14ffa9 bellard
        return AUDIO_U16LSB;
126 1d14ffa9 bellard
127 85571bc7 bellard
    default:
128 1d14ffa9 bellard
        dolog ("Internal logic error: Bad audio format %d\n", fmt);
129 1d14ffa9 bellard
#ifdef DEBUG_AUDIO
130 1d14ffa9 bellard
        abort ();
131 1d14ffa9 bellard
#endif
132 1d14ffa9 bellard
        return AUDIO_U8;
133 85571bc7 bellard
    }
134 85571bc7 bellard
}
135 85571bc7 bellard
136 1d14ffa9 bellard
static int sdl_to_audfmt (int sdlfmt, audfmt_e *fmt, int *endianess)
137 85571bc7 bellard
{
138 1d14ffa9 bellard
    switch (sdlfmt) {
139 1d14ffa9 bellard
    case AUDIO_S8:
140 1d14ffa9 bellard
        *endianess = 0;
141 1d14ffa9 bellard
        *fmt = AUD_FMT_S8;
142 1d14ffa9 bellard
        break;
143 1d14ffa9 bellard
144 1d14ffa9 bellard
    case AUDIO_U8:
145 1d14ffa9 bellard
        *endianess = 0;
146 1d14ffa9 bellard
        *fmt = AUD_FMT_U8;
147 1d14ffa9 bellard
        break;
148 1d14ffa9 bellard
149 1d14ffa9 bellard
    case AUDIO_S16LSB:
150 1d14ffa9 bellard
        *endianess = 0;
151 1d14ffa9 bellard
        *fmt = AUD_FMT_S16;
152 1d14ffa9 bellard
        break;
153 1d14ffa9 bellard
154 1d14ffa9 bellard
    case AUDIO_U16LSB:
155 1d14ffa9 bellard
        *endianess = 0;
156 1d14ffa9 bellard
        *fmt = AUD_FMT_U16;
157 1d14ffa9 bellard
        break;
158 1d14ffa9 bellard
159 1d14ffa9 bellard
    case AUDIO_S16MSB:
160 1d14ffa9 bellard
        *endianess = 1;
161 1d14ffa9 bellard
        *fmt = AUD_FMT_S16;
162 1d14ffa9 bellard
        break;
163 1d14ffa9 bellard
164 1d14ffa9 bellard
    case AUDIO_U16MSB:
165 1d14ffa9 bellard
        *endianess = 1;
166 1d14ffa9 bellard
        *fmt = AUD_FMT_U16;
167 1d14ffa9 bellard
        break;
168 1d14ffa9 bellard
169 85571bc7 bellard
    default:
170 1d14ffa9 bellard
        dolog ("Unrecognized SDL audio format %d\n", sdlfmt);
171 1d14ffa9 bellard
        return -1;
172 85571bc7 bellard
    }
173 1d14ffa9 bellard
174 1d14ffa9 bellard
    return 0;
175 85571bc7 bellard
}
176 85571bc7 bellard
177 85571bc7 bellard
static int sdl_open (SDL_AudioSpec *req, SDL_AudioSpec *obt)
178 85571bc7 bellard
{
179 85571bc7 bellard
    int status;
180 85571bc7 bellard
181 85571bc7 bellard
    status = SDL_OpenAudio (req, obt);
182 85571bc7 bellard
    if (status) {
183 1d14ffa9 bellard
        sdl_logerr ("SDL_OpenAudio failed\n");
184 85571bc7 bellard
    }
185 85571bc7 bellard
    return status;
186 85571bc7 bellard
}
187 85571bc7 bellard
188 85571bc7 bellard
static void sdl_close (SDLAudioState *s)
189 85571bc7 bellard
{
190 85571bc7 bellard
    if (s->initialized) {
191 1d14ffa9 bellard
        sdl_lock (s, "sdl_close");
192 85571bc7 bellard
        s->exit = 1;
193 1d14ffa9 bellard
        sdl_unlock_and_post (s, "sdl_close");
194 85571bc7 bellard
        SDL_PauseAudio (1);
195 85571bc7 bellard
        SDL_CloseAudio ();
196 85571bc7 bellard
        s->initialized = 0;
197 85571bc7 bellard
    }
198 85571bc7 bellard
}
199 85571bc7 bellard
200 85571bc7 bellard
static void sdl_callback (void *opaque, Uint8 *buf, int len)
201 85571bc7 bellard
{
202 1d14ffa9 bellard
    SDLVoiceOut *sdl = opaque;
203 85571bc7 bellard
    SDLAudioState *s = &glob_sdl;
204 1d14ffa9 bellard
    HWVoiceOut *hw = &sdl->hw;
205 1d14ffa9 bellard
    int samples = len >> hw->info.shift;
206 85571bc7 bellard
207 85571bc7 bellard
    if (s->exit) {
208 85571bc7 bellard
        return;
209 85571bc7 bellard
    }
210 85571bc7 bellard
211 85571bc7 bellard
    while (samples) {
212 1d14ffa9 bellard
        int to_mix, decr;
213 85571bc7 bellard
214 85571bc7 bellard
        /* dolog ("in callback samples=%d\n", samples); */
215 1d14ffa9 bellard
        sdl_wait (s, "sdl_callback");
216 85571bc7 bellard
        if (s->exit) {
217 85571bc7 bellard
            return;
218 85571bc7 bellard
        }
219 85571bc7 bellard
220 1d14ffa9 bellard
        if (sdl_lock (s, "sdl_callback")) {
221 1d14ffa9 bellard
            return;
222 1d14ffa9 bellard
        }
223 1d14ffa9 bellard
224 1d14ffa9 bellard
        if (audio_bug (AUDIO_FUNC, sdl->live < 0 || sdl->live > hw->samples)) {
225 1d14ffa9 bellard
            dolog ("sdl->live=%d hw->samples=%d\n",
226 1d14ffa9 bellard
                   sdl->live, hw->samples);
227 1d14ffa9 bellard
            return;
228 1d14ffa9 bellard
        }
229 1d14ffa9 bellard
230 1d14ffa9 bellard
        if (!sdl->live) {
231 85571bc7 bellard
            goto again;
232 1d14ffa9 bellard
        }
233 85571bc7 bellard
234 85571bc7 bellard
        /* dolog ("in callback live=%d\n", live); */
235 1d14ffa9 bellard
        to_mix = audio_MIN (samples, sdl->live);
236 85571bc7 bellard
        decr = to_mix;
237 85571bc7 bellard
        while (to_mix) {
238 85571bc7 bellard
            int chunk = audio_MIN (to_mix, hw->samples - hw->rpos);
239 85571bc7 bellard
            st_sample_t *src = hw->mix_buf + hw->rpos;
240 85571bc7 bellard
241 85571bc7 bellard
            /* dolog ("in callback to_mix %d, chunk %d\n", to_mix, chunk); */
242 85571bc7 bellard
            hw->clip (buf, src, chunk);
243 1d14ffa9 bellard
            sdl->rpos = (sdl->rpos + chunk) % hw->samples;
244 85571bc7 bellard
            to_mix -= chunk;
245 1d14ffa9 bellard
            buf += chunk << hw->info.shift;
246 85571bc7 bellard
        }
247 85571bc7 bellard
        samples -= decr;
248 1d14ffa9 bellard
        sdl->live -= decr;
249 1d14ffa9 bellard
        sdl->decr += decr;
250 85571bc7 bellard
251 85571bc7 bellard
    again:
252 1d14ffa9 bellard
        if (sdl_unlock (s, "sdl_callback")) {
253 1d14ffa9 bellard
            return;
254 1d14ffa9 bellard
        }
255 85571bc7 bellard
    }
256 85571bc7 bellard
    /* dolog ("done len=%d\n", len); */
257 85571bc7 bellard
}
258 85571bc7 bellard
259 1d14ffa9 bellard
static int sdl_write_out (SWVoiceOut *sw, void *buf, int len)
260 85571bc7 bellard
{
261 1d14ffa9 bellard
    return audio_pcm_sw_write (sw, buf, len);
262 1d14ffa9 bellard
}
263 1d14ffa9 bellard
264 1d14ffa9 bellard
static int sdl_run_out (HWVoiceOut *hw)
265 1d14ffa9 bellard
{
266 1d14ffa9 bellard
    int decr, live;
267 1d14ffa9 bellard
    SDLVoiceOut *sdl = (SDLVoiceOut *) hw;
268 1d14ffa9 bellard
    SDLAudioState *s = &glob_sdl;
269 1d14ffa9 bellard
270 1d14ffa9 bellard
    if (sdl_lock (s, "sdl_callback")) {
271 1d14ffa9 bellard
        return 0;
272 1d14ffa9 bellard
    }
273 1d14ffa9 bellard
274 1d14ffa9 bellard
    live = audio_pcm_hw_get_live_out (hw);
275 1d14ffa9 bellard
276 1d14ffa9 bellard
    if (sdl->decr > live) {
277 1d14ffa9 bellard
        ldebug ("sdl->decr %d live %d sdl->live %d\n",
278 1d14ffa9 bellard
                sdl->decr,
279 1d14ffa9 bellard
                live,
280 1d14ffa9 bellard
                sdl->live);
281 1d14ffa9 bellard
    }
282 1d14ffa9 bellard
283 1d14ffa9 bellard
    decr = audio_MIN (sdl->decr, live);
284 1d14ffa9 bellard
    sdl->decr -= decr;
285 1d14ffa9 bellard
286 1d14ffa9 bellard
    sdl->live = live - decr;
287 1d14ffa9 bellard
    hw->rpos = sdl->rpos;
288 1d14ffa9 bellard
289 1d14ffa9 bellard
    if (sdl->live > 0) {
290 1d14ffa9 bellard
        sdl_unlock_and_post (s, "sdl_callback");
291 1d14ffa9 bellard
    }
292 1d14ffa9 bellard
    else {
293 1d14ffa9 bellard
        sdl_unlock (s, "sdl_callback");
294 1d14ffa9 bellard
    }
295 1d14ffa9 bellard
    return decr;
296 1d14ffa9 bellard
}
297 1d14ffa9 bellard
298 1d14ffa9 bellard
static void sdl_fini_out (HWVoiceOut *hw)
299 1d14ffa9 bellard
{
300 1d14ffa9 bellard
    (void) hw;
301 1d14ffa9 bellard
302 85571bc7 bellard
    sdl_close (&glob_sdl);
303 85571bc7 bellard
}
304 85571bc7 bellard
305 c0fe3827 bellard
static int sdl_init_out (HWVoiceOut *hw, audsettings_t *as)
306 85571bc7 bellard
{
307 1d14ffa9 bellard
    SDLVoiceOut *sdl = (SDLVoiceOut *) hw;
308 85571bc7 bellard
    SDLAudioState *s = &glob_sdl;
309 85571bc7 bellard
    SDL_AudioSpec req, obt;
310 85571bc7 bellard
    int shift;
311 1d14ffa9 bellard
    int endianess;
312 1d14ffa9 bellard
    int err;
313 1d14ffa9 bellard
    audfmt_e effective_fmt;
314 c0fe3827 bellard
    audsettings_t obt_as;
315 85571bc7 bellard
316 c0fe3827 bellard
    shift <<= as->nchannels == 2;
317 85571bc7 bellard
318 c0fe3827 bellard
    req.freq = as->freq;
319 c0fe3827 bellard
    req.format = aud_to_sdlfmt (as->fmt, &shift);
320 c0fe3827 bellard
    req.channels = as->nchannels;
321 85571bc7 bellard
    req.samples = conf.nb_samples;
322 85571bc7 bellard
    req.callback = sdl_callback;
323 85571bc7 bellard
    req.userdata = sdl;
324 85571bc7 bellard
325 1d14ffa9 bellard
    if (sdl_open (&req, &obt)) {
326 1d14ffa9 bellard
        return -1;
327 1d14ffa9 bellard
    }
328 1d14ffa9 bellard
329 1d14ffa9 bellard
    err = sdl_to_audfmt (obt.format, &effective_fmt, &endianess);
330 1d14ffa9 bellard
    if (err) {
331 1d14ffa9 bellard
        sdl_close (s);
332 85571bc7 bellard
        return -1;
333 1d14ffa9 bellard
    }
334 85571bc7 bellard
335 c0fe3827 bellard
    obt_as.freq = obt.freq;
336 c0fe3827 bellard
    obt_as.nchannels = obt.channels;
337 c0fe3827 bellard
    obt_as.fmt = effective_fmt;
338 d929eba5 bellard
    obt_as.endianness = endianess;
339 c0fe3827 bellard
340 d929eba5 bellard
    audio_pcm_init_info (&hw->info, &obt_as);
341 c0fe3827 bellard
    hw->samples = obt.samples;
342 85571bc7 bellard
343 85571bc7 bellard
    s->initialized = 1;
344 85571bc7 bellard
    s->exit = 0;
345 85571bc7 bellard
    SDL_PauseAudio (0);
346 85571bc7 bellard
    return 0;
347 85571bc7 bellard
}
348 85571bc7 bellard
349 1d14ffa9 bellard
static int sdl_ctl_out (HWVoiceOut *hw, int cmd, ...)
350 85571bc7 bellard
{
351 85571bc7 bellard
    (void) hw;
352 85571bc7 bellard
353 85571bc7 bellard
    switch (cmd) {
354 85571bc7 bellard
    case VOICE_ENABLE:
355 85571bc7 bellard
        SDL_PauseAudio (0);
356 85571bc7 bellard
        break;
357 85571bc7 bellard
358 85571bc7 bellard
    case VOICE_DISABLE:
359 85571bc7 bellard
        SDL_PauseAudio (1);
360 85571bc7 bellard
        break;
361 85571bc7 bellard
    }
362 85571bc7 bellard
    return 0;
363 85571bc7 bellard
}
364 85571bc7 bellard
365 85571bc7 bellard
static void *sdl_audio_init (void)
366 85571bc7 bellard
{
367 85571bc7 bellard
    SDLAudioState *s = &glob_sdl;
368 85571bc7 bellard
369 85571bc7 bellard
    if (SDL_InitSubSystem (SDL_INIT_AUDIO)) {
370 1d14ffa9 bellard
        sdl_logerr ("SDL failed to initialize audio subsystem\n");
371 85571bc7 bellard
        return NULL;
372 85571bc7 bellard
    }
373 85571bc7 bellard
374 85571bc7 bellard
    s->mutex = SDL_CreateMutex ();
375 85571bc7 bellard
    if (!s->mutex) {
376 1d14ffa9 bellard
        sdl_logerr ("Failed to create SDL mutex\n");
377 85571bc7 bellard
        SDL_QuitSubSystem (SDL_INIT_AUDIO);
378 85571bc7 bellard
        return NULL;
379 85571bc7 bellard
    }
380 85571bc7 bellard
381 85571bc7 bellard
    s->sem = SDL_CreateSemaphore (0);
382 85571bc7 bellard
    if (!s->sem) {
383 1d14ffa9 bellard
        sdl_logerr ("Failed to create SDL semaphore\n");
384 85571bc7 bellard
        SDL_DestroyMutex (s->mutex);
385 85571bc7 bellard
        SDL_QuitSubSystem (SDL_INIT_AUDIO);
386 85571bc7 bellard
        return NULL;
387 85571bc7 bellard
    }
388 85571bc7 bellard
389 85571bc7 bellard
    return s;
390 85571bc7 bellard
}
391 85571bc7 bellard
392 85571bc7 bellard
static void sdl_audio_fini (void *opaque)
393 85571bc7 bellard
{
394 85571bc7 bellard
    SDLAudioState *s = opaque;
395 85571bc7 bellard
    sdl_close (s);
396 85571bc7 bellard
    SDL_DestroySemaphore (s->sem);
397 85571bc7 bellard
    SDL_DestroyMutex (s->mutex);
398 85571bc7 bellard
    SDL_QuitSubSystem (SDL_INIT_AUDIO);
399 85571bc7 bellard
}
400 85571bc7 bellard
401 1d14ffa9 bellard
static struct audio_option sdl_options[] = {
402 1d14ffa9 bellard
    {"SAMPLES", AUD_OPT_INT, &conf.nb_samples,
403 1d14ffa9 bellard
     "Size of SDL buffer in samples", NULL, 0},
404 1d14ffa9 bellard
    {NULL, 0, NULL, NULL, NULL, 0}
405 1d14ffa9 bellard
};
406 1d14ffa9 bellard
407 1d14ffa9 bellard
static struct audio_pcm_ops sdl_pcm_ops = {
408 1d14ffa9 bellard
    sdl_init_out,
409 1d14ffa9 bellard
    sdl_fini_out,
410 1d14ffa9 bellard
    sdl_run_out,
411 1d14ffa9 bellard
    sdl_write_out,
412 1d14ffa9 bellard
    sdl_ctl_out,
413 1d14ffa9 bellard
414 1d14ffa9 bellard
    NULL,
415 1d14ffa9 bellard
    NULL,
416 1d14ffa9 bellard
    NULL,
417 1d14ffa9 bellard
    NULL,
418 1d14ffa9 bellard
    NULL
419 85571bc7 bellard
};
420 85571bc7 bellard
421 1d14ffa9 bellard
struct audio_driver sdl_audio_driver = {
422 1d14ffa9 bellard
    INIT_FIELD (name           = ) "sdl",
423 1d14ffa9 bellard
    INIT_FIELD (descr          = ) "SDL http://www.libsdl.org",
424 1d14ffa9 bellard
    INIT_FIELD (options        = ) sdl_options,
425 1d14ffa9 bellard
    INIT_FIELD (init           = ) sdl_audio_init,
426 1d14ffa9 bellard
    INIT_FIELD (fini           = ) sdl_audio_fini,
427 1d14ffa9 bellard
    INIT_FIELD (pcm_ops        = ) &sdl_pcm_ops,
428 1d14ffa9 bellard
    INIT_FIELD (can_be_default = ) 1,
429 1d14ffa9 bellard
    INIT_FIELD (max_voices_out = ) 1,
430 1d14ffa9 bellard
    INIT_FIELD (max_voices_in  = ) 0,
431 1d14ffa9 bellard
    INIT_FIELD (voice_size_out = ) sizeof (SDLVoiceOut),
432 1d14ffa9 bellard
    INIT_FIELD (voice_size_in  = ) 0
433 85571bc7 bellard
};