|
|
1.1 root 1: /*
1.1.1.2 root 2: * QEMU SDL audio driver
3: *
4: * Copyright (c) 2004-2005 Vassili Karpov (malc)
5: *
1.1 root 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>
1.1.1.4 ! root 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
1.1 root 35:
1.1.1.2 root 36: #define AUDIO_CAP "sdl"
37: #include "audio_int.h"
1.1 root 38:
1.1.1.2 root 39: typedef struct SDLVoiceOut {
40: HWVoiceOut hw;
41: int live;
42: int rpos;
43: int decr;
44: } SDLVoiceOut;
1.1 root 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:
1.1.1.2 root 60: static void GCC_FMT_ATTR (1, 2) sdl_logerr (const char *fmt, ...)
1.1 root 61: {
1.1.1.2 root 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 ());
1.1 root 69: }
70:
1.1.1.2 root 71: static int sdl_lock (SDLAudioState *s, const char *forfn)
1.1 root 72: {
73: if (SDL_LockMutex (s->mutex)) {
1.1.1.2 root 74: sdl_logerr ("SDL_LockMutex for %s failed\n", forfn);
1.1 root 75: return -1;
76: }
77: return 0;
78: }
79:
1.1.1.2 root 80: static int sdl_unlock (SDLAudioState *s, const char *forfn)
1.1 root 81: {
82: if (SDL_UnlockMutex (s->mutex)) {
1.1.1.2 root 83: sdl_logerr ("SDL_UnlockMutex for %s failed\n", forfn);
1.1 root 84: return -1;
85: }
86: return 0;
87: }
88:
1.1.1.2 root 89: static int sdl_post (SDLAudioState *s, const char *forfn)
1.1 root 90: {
91: if (SDL_SemPost (s->sem)) {
1.1.1.2 root 92: sdl_logerr ("SDL_SemPost for %s failed\n", forfn);
1.1 root 93: return -1;
94: }
95: return 0;
96: }
97:
1.1.1.2 root 98: static int sdl_wait (SDLAudioState *s, const char *forfn)
1.1 root 99: {
100: if (SDL_SemWait (s->sem)) {
1.1.1.2 root 101: sdl_logerr ("SDL_SemWait for %s failed\n", forfn);
1.1 root 102: return -1;
103: }
104: return 0;
105: }
106:
1.1.1.2 root 107: static int sdl_unlock_and_post (SDLAudioState *s, const char *forfn)
1.1 root 108: {
1.1.1.2 root 109: if (sdl_unlock (s, forfn)) {
1.1 root 110: return -1;
1.1.1.2 root 111: }
1.1 root 112:
1.1.1.2 root 113: return sdl_post (s, forfn);
1.1 root 114: }
115:
1.1.1.2 root 116: static int aud_to_sdlfmt (audfmt_e fmt, int *shift)
1.1 root 117: {
118: switch (fmt) {
1.1.1.2 root 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:
1.1 root 135: default:
1.1.1.2 root 136: dolog ("Internal logic error: Bad audio format %d\n", fmt);
137: #ifdef DEBUG_AUDIO
138: abort ();
139: #endif
140: return AUDIO_U8;
1.1 root 141: }
142: }
143:
1.1.1.2 root 144: static int sdl_to_audfmt (int sdlfmt, audfmt_e *fmt, int *endianess)
1.1 root 145: {
1.1.1.2 root 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:
1.1 root 177: default:
1.1.1.2 root 178: dolog ("Unrecognized SDL audio format %d\n", sdlfmt);
179: return -1;
1.1 root 180: }
1.1.1.2 root 181:
182: return 0;
1.1 root 183: }
184:
185: static int sdl_open (SDL_AudioSpec *req, SDL_AudioSpec *obt)
186: {
187: int status;
1.1.1.4 ! root 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
1.1 root 195:
196: status = SDL_OpenAudio (req, obt);
197: if (status) {
1.1.1.2 root 198: sdl_logerr ("SDL_OpenAudio failed\n");
1.1 root 199: }
1.1.1.4 ! root 200:
! 201: #ifndef _WIN32
! 202: pthread_sigmask (SIG_SETMASK, &old, 0);
! 203: #endif
1.1 root 204: return status;
205: }
206:
207: static void sdl_close (SDLAudioState *s)
208: {
209: if (s->initialized) {
1.1.1.2 root 210: sdl_lock (s, "sdl_close");
1.1 root 211: s->exit = 1;
1.1.1.2 root 212: sdl_unlock_and_post (s, "sdl_close");
1.1 root 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: {
1.1.1.2 root 221: SDLVoiceOut *sdl = opaque;
1.1 root 222: SDLAudioState *s = &glob_sdl;
1.1.1.2 root 223: HWVoiceOut *hw = &sdl->hw;
224: int samples = len >> hw->info.shift;
1.1 root 225:
226: if (s->exit) {
227: return;
228: }
229:
230: while (samples) {
1.1.1.2 root 231: int to_mix, decr;
1.1 root 232:
233: /* dolog ("in callback samples=%d\n", samples); */
1.1.1.2 root 234: sdl_wait (s, "sdl_callback");
1.1 root 235: if (s->exit) {
236: return;
237: }
238:
1.1.1.2 root 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) {
1.1 root 250: goto again;
1.1.1.2 root 251: }
1.1 root 252:
253: /* dolog ("in callback live=%d\n", live); */
1.1.1.2 root 254: to_mix = audio_MIN (samples, sdl->live);
1.1 root 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);
1.1.1.2 root 262: sdl->rpos = (sdl->rpos + chunk) % hw->samples;
1.1 root 263: to_mix -= chunk;
1.1.1.2 root 264: buf += chunk << hw->info.shift;
1.1 root 265: }
266: samples -= decr;
1.1.1.2 root 267: sdl->live -= decr;
268: sdl->decr += decr;
1.1 root 269:
270: again:
1.1.1.2 root 271: if (sdl_unlock (s, "sdl_callback")) {
272: return;
273: }
1.1 root 274: }
275: /* dolog ("done len=%d\n", len); */
276: }
277:
1.1.1.2 root 278: static int sdl_write_out (SWVoiceOut *sw, void *buf, int len)
1.1 root 279: {
1.1.1.2 root 280: return audio_pcm_sw_write (sw, buf, len);
1.1 root 281: }
282:
1.1.1.2 root 283: static int sdl_run_out (HWVoiceOut *hw)
1.1 root 284: {
1.1.1.2 root 285: int decr, live;
286: SDLVoiceOut *sdl = (SDLVoiceOut *) hw;
1.1 root 287: SDLAudioState *s = &glob_sdl;
288:
1.1.1.2 root 289: if (sdl_lock (s, "sdl_callback")) {
290: return 0;
291: }
1.1 root 292:
1.1.1.2 root 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);
1.1 root 300: }
301:
1.1.1.2 root 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: }
1.1 root 316:
1.1.1.2 root 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;
1.1 root 341: req.callback = sdl_callback;
342: req.userdata = sdl;
343:
1.1.1.2 root 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);
1.1 root 351: return -1;
1.1.1.2 root 352: }
1.1 root 353:
1.1.1.2 root 354: obt_as.freq = obt.freq;
355: obt_as.nchannels = obt.channels;
356: obt_as.fmt = effective_fmt;
1.1.1.3 root 357: obt_as.endianness = endianess;
1.1.1.2 root 358:
1.1.1.3 root 359: audio_pcm_init_info (&hw->info, &obt_as);
1.1.1.2 root 360: hw->samples = obt.samples;
1.1 root 361:
362: s->initialized = 1;
363: s->exit = 0;
364: SDL_PauseAudio (0);
365: return 0;
366: }
367:
1.1.1.2 root 368: static int sdl_ctl_out (HWVoiceOut *hw, int cmd, ...)
1.1 root 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)) {
1.1.1.2 root 389: sdl_logerr ("SDL failed to initialize audio subsystem\n");
1.1 root 390: return NULL;
391: }
392:
393: s->mutex = SDL_CreateMutex ();
394: if (!s->mutex) {
1.1.1.2 root 395: sdl_logerr ("Failed to create SDL mutex\n");
1.1 root 396: SDL_QuitSubSystem (SDL_INIT_AUDIO);
397: return NULL;
398: }
399:
400: s->sem = SDL_CreateSemaphore (0);
401: if (!s->sem) {
1.1.1.2 root 402: sdl_logerr ("Failed to create SDL semaphore\n");
1.1 root 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:
1.1.1.2 root 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
1.1 root 438: };
439:
1.1.1.2 root 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
1.1 root 452: };
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.