~ubuntu-branches/ubuntu/wily/qemu-kvm-spice/wily

« back to all changes in this revision

Viewing changes to audio/sdlaudio.c

  • Committer: Bazaar Package Importer
  • Author(s): Serge Hallyn
  • Date: 2011-10-19 10:44:56 UTC
  • Revision ID: james.westby@ubuntu.com-20111019104456-xgvskumk3sxi97f4
Tags: upstream-0.15.0+noroms
ImportĀ upstreamĀ versionĀ 0.15.0+noroms

Show diffs side-by-side

added added

removed removed

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