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