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