|
|
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;
1.1.1.8 root 44: int rpos;
1.1.1.2 root 45: int decr;
46: } SDLVoiceOut;
1.1 root 47:
48: static struct {
49: int nb_samples;
50: } conf = {
1.1.1.7 root 51: .nb_samples = 1024
1.1 root 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.8 root 118: static int aud_to_sdlfmt (audfmt_e fmt)
1.1 root 119: {
120: switch (fmt) {
1.1.1.2 root 121: case AUD_FMT_S8:
122: return AUDIO_S8;
123:
124: case AUD_FMT_U8:
125: return AUDIO_U8;
126:
127: case AUD_FMT_S16:
128: return AUDIO_S16LSB;
129:
130: case AUD_FMT_U16:
131: return AUDIO_U16LSB;
132:
1.1 root 133: default:
1.1.1.2 root 134: dolog ("Internal logic error: Bad audio format %d\n", fmt);
135: #ifdef DEBUG_AUDIO
136: abort ();
137: #endif
138: return AUDIO_U8;
1.1 root 139: }
140: }
141:
1.1.1.2 root 142: static int sdl_to_audfmt (int sdlfmt, audfmt_e *fmt, int *endianess)
1.1 root 143: {
1.1.1.2 root 144: switch (sdlfmt) {
145: case AUDIO_S8:
146: *endianess = 0;
147: *fmt = AUD_FMT_S8;
148: break;
149:
150: case AUDIO_U8:
151: *endianess = 0;
152: *fmt = AUD_FMT_U8;
153: break;
154:
155: case AUDIO_S16LSB:
156: *endianess = 0;
157: *fmt = AUD_FMT_S16;
158: break;
159:
160: case AUDIO_U16LSB:
161: *endianess = 0;
162: *fmt = AUD_FMT_U16;
163: break;
164:
165: case AUDIO_S16MSB:
166: *endianess = 1;
167: *fmt = AUD_FMT_S16;
168: break;
169:
170: case AUDIO_U16MSB:
171: *endianess = 1;
172: *fmt = AUD_FMT_U16;
173: break;
174:
1.1 root 175: default:
1.1.1.2 root 176: dolog ("Unrecognized SDL audio format %d\n", sdlfmt);
177: return -1;
1.1 root 178: }
1.1.1.2 root 179:
180: return 0;
1.1 root 181: }
182:
183: static int sdl_open (SDL_AudioSpec *req, SDL_AudioSpec *obt)
184: {
185: int status;
1.1.1.4 root 186: #ifndef _WIN32
1.1.1.9 ! root 187: int err;
1.1.1.4 root 188: sigset_t new, old;
189:
190: /* Make sure potential threads created by SDL don't hog signals. */
1.1.1.9 ! root 191: err = sigfillset (&new);
! 192: if (err) {
! 193: dolog ("sdl_open: sigfillset failed: %s\n", strerror (errno));
! 194: return -1;
! 195: }
! 196: err = pthread_sigmask (SIG_BLOCK, &new, &old);
! 197: if (err) {
! 198: dolog ("sdl_open: pthread_sigmask failed: %s\n", strerror (err));
! 199: return -1;
! 200: }
1.1.1.4 root 201: #endif
1.1 root 202:
203: status = SDL_OpenAudio (req, obt);
204: if (status) {
1.1.1.2 root 205: sdl_logerr ("SDL_OpenAudio failed\n");
1.1 root 206: }
1.1.1.4 root 207:
208: #ifndef _WIN32
1.1.1.9 ! root 209: err = pthread_sigmask (SIG_SETMASK, &old, NULL);
! 210: if (err) {
! 211: dolog ("sdl_open: pthread_sigmask (restore) failed: %s\n",
! 212: strerror (errno));
! 213: /* We have failed to restore original signal mask, all bets are off,
! 214: so exit the process */
! 215: exit (EXIT_FAILURE);
! 216: }
1.1.1.4 root 217: #endif
1.1 root 218: return status;
219: }
220:
221: static void sdl_close (SDLAudioState *s)
222: {
223: if (s->initialized) {
1.1.1.2 root 224: sdl_lock (s, "sdl_close");
1.1 root 225: s->exit = 1;
1.1.1.2 root 226: sdl_unlock_and_post (s, "sdl_close");
1.1 root 227: SDL_PauseAudio (1);
228: SDL_CloseAudio ();
229: s->initialized = 0;
230: }
231: }
232:
233: static void sdl_callback (void *opaque, Uint8 *buf, int len)
234: {
1.1.1.2 root 235: SDLVoiceOut *sdl = opaque;
1.1 root 236: SDLAudioState *s = &glob_sdl;
1.1.1.2 root 237: HWVoiceOut *hw = &sdl->hw;
238: int samples = len >> hw->info.shift;
1.1 root 239:
240: if (s->exit) {
241: return;
242: }
243:
244: while (samples) {
1.1.1.2 root 245: int to_mix, decr;
1.1 root 246:
1.1.1.8 root 247: /* dolog ("in callback samples=%d\n", samples); */
248: sdl_wait (s, "sdl_callback");
249: if (s->exit) {
250: return;
251: }
252:
253: if (sdl_lock (s, "sdl_callback")) {
254: return;
255: }
256:
257: if (audio_bug (AUDIO_FUNC, sdl->live < 0 || sdl->live > hw->samples)) {
258: dolog ("sdl->live=%d hw->samples=%d\n",
259: sdl->live, hw->samples);
260: return;
261: }
262:
263: if (!sdl->live) {
264: goto again;
1.1.1.2 root 265: }
1.1 root 266:
1.1.1.8 root 267: /* dolog ("in callback live=%d\n", live); */
268: to_mix = audio_MIN (samples, sdl->live);
269: decr = to_mix;
270: while (to_mix) {
271: int chunk = audio_MIN (to_mix, hw->samples - hw->rpos);
272: struct st_sample *src = hw->mix_buf + hw->rpos;
273:
274: /* dolog ("in callback to_mix %d, chunk %d\n", to_mix, chunk); */
275: hw->clip (buf, src, chunk);
276: sdl->rpos = (sdl->rpos + chunk) % hw->samples;
277: to_mix -= chunk;
278: buf += chunk << hw->info.shift;
279: }
1.1 root 280: samples -= decr;
1.1.1.8 root 281: sdl->live -= decr;
1.1.1.2 root 282: sdl->decr += decr;
1.1 root 283:
1.1.1.8 root 284: again:
285: if (sdl_unlock (s, "sdl_callback")) {
286: return;
287: }
1.1 root 288: }
1.1.1.8 root 289: /* dolog ("done len=%d\n", len); */
1.1 root 290: }
291:
1.1.1.2 root 292: static int sdl_write_out (SWVoiceOut *sw, void *buf, int len)
1.1 root 293: {
1.1.1.2 root 294: return audio_pcm_sw_write (sw, buf, len);
1.1 root 295: }
296:
1.1.1.7 root 297: static int sdl_run_out (HWVoiceOut *hw, int live)
1.1 root 298: {
1.1.1.7 root 299: int decr;
1.1.1.2 root 300: SDLVoiceOut *sdl = (SDLVoiceOut *) hw;
1.1 root 301: SDLAudioState *s = &glob_sdl;
302:
1.1.1.7 root 303: if (sdl_lock (s, "sdl_run_out")) {
1.1.1.2 root 304: return 0;
305: }
1.1 root 306:
1.1.1.8 root 307: if (sdl->decr > live) {
308: ldebug ("sdl->decr %d live %d sdl->live %d\n",
309: sdl->decr,
310: live,
311: sdl->live);
312: }
313:
314: decr = audio_MIN (sdl->decr, live);
315: sdl->decr -= decr;
316:
317: sdl->live = live - decr;
318: hw->rpos = sdl->rpos;
1.1.1.2 root 319:
320: if (sdl->live > 0) {
1.1.1.7 root 321: sdl_unlock_and_post (s, "sdl_run_out");
1.1.1.2 root 322: }
323: else {
1.1.1.7 root 324: sdl_unlock (s, "sdl_run_out");
1.1.1.2 root 325: }
326: return decr;
327: }
1.1 root 328:
1.1.1.2 root 329: static void sdl_fini_out (HWVoiceOut *hw)
330: {
331: (void) hw;
332:
333: sdl_close (&glob_sdl);
334: }
335:
1.1.1.5 root 336: static int sdl_init_out (HWVoiceOut *hw, struct audsettings *as)
1.1.1.2 root 337: {
338: SDLVoiceOut *sdl = (SDLVoiceOut *) hw;
339: SDLAudioState *s = &glob_sdl;
340: SDL_AudioSpec req, obt;
341: int endianess;
342: int err;
343: audfmt_e effective_fmt;
1.1.1.5 root 344: struct audsettings obt_as;
1.1.1.2 root 345:
346: req.freq = as->freq;
1.1.1.8 root 347: req.format = aud_to_sdlfmt (as->fmt);
1.1.1.2 root 348: req.channels = as->nchannels;
349: req.samples = conf.nb_samples;
1.1 root 350: req.callback = sdl_callback;
351: req.userdata = sdl;
352:
1.1.1.2 root 353: if (sdl_open (&req, &obt)) {
354: return -1;
355: }
356:
357: err = sdl_to_audfmt (obt.format, &effective_fmt, &endianess);
358: if (err) {
359: sdl_close (s);
1.1 root 360: return -1;
1.1.1.2 root 361: }
1.1 root 362:
1.1.1.2 root 363: obt_as.freq = obt.freq;
364: obt_as.nchannels = obt.channels;
365: obt_as.fmt = effective_fmt;
1.1.1.3 root 366: obt_as.endianness = endianess;
1.1.1.2 root 367:
1.1.1.3 root 368: audio_pcm_init_info (&hw->info, &obt_as);
1.1.1.2 root 369: hw->samples = obt.samples;
1.1 root 370:
371: s->initialized = 1;
372: s->exit = 0;
373: SDL_PauseAudio (0);
374: return 0;
375: }
376:
1.1.1.2 root 377: static int sdl_ctl_out (HWVoiceOut *hw, int cmd, ...)
1.1 root 378: {
379: (void) hw;
380:
381: switch (cmd) {
382: case VOICE_ENABLE:
383: SDL_PauseAudio (0);
384: break;
385:
386: case VOICE_DISABLE:
387: SDL_PauseAudio (1);
388: break;
389: }
390: return 0;
391: }
392:
393: static void *sdl_audio_init (void)
394: {
395: SDLAudioState *s = &glob_sdl;
396:
397: if (SDL_InitSubSystem (SDL_INIT_AUDIO)) {
1.1.1.2 root 398: sdl_logerr ("SDL failed to initialize audio subsystem\n");
1.1 root 399: return NULL;
400: }
401:
402: s->mutex = SDL_CreateMutex ();
403: if (!s->mutex) {
1.1.1.2 root 404: sdl_logerr ("Failed to create SDL mutex\n");
1.1 root 405: SDL_QuitSubSystem (SDL_INIT_AUDIO);
406: return NULL;
407: }
408:
409: s->sem = SDL_CreateSemaphore (0);
410: if (!s->sem) {
1.1.1.2 root 411: sdl_logerr ("Failed to create SDL semaphore\n");
1.1 root 412: SDL_DestroyMutex (s->mutex);
413: SDL_QuitSubSystem (SDL_INIT_AUDIO);
414: return NULL;
415: }
416:
417: return s;
418: }
419:
420: static void sdl_audio_fini (void *opaque)
421: {
422: SDLAudioState *s = opaque;
423: sdl_close (s);
424: SDL_DestroySemaphore (s->sem);
425: SDL_DestroyMutex (s->mutex);
426: SDL_QuitSubSystem (SDL_INIT_AUDIO);
427: }
428:
1.1.1.2 root 429: static struct audio_option sdl_options[] = {
1.1.1.7 root 430: {
431: .name = "SAMPLES",
432: .tag = AUD_OPT_INT,
433: .valp = &conf.nb_samples,
434: .descr = "Size of SDL buffer in samples"
435: },
436: { /* End of list */ }
1.1.1.2 root 437: };
438:
439: static struct audio_pcm_ops sdl_pcm_ops = {
1.1.1.7 root 440: .init_out = sdl_init_out,
441: .fini_out = sdl_fini_out,
442: .run_out = sdl_run_out,
443: .write = sdl_write_out,
444: .ctl_out = sdl_ctl_out,
1.1 root 445: };
446:
1.1.1.2 root 447: struct audio_driver sdl_audio_driver = {
1.1.1.7 root 448: .name = "sdl",
449: .descr = "SDL http://www.libsdl.org",
450: .options = sdl_options,
451: .init = sdl_audio_init,
452: .fini = sdl_audio_fini,
453: .pcm_ops = &sdl_pcm_ops,
454: .can_be_default = 1,
455: .max_voices_out = 1,
456: .max_voices_in = 0,
457: .voice_size_out = sizeof (SDLVoiceOut),
458: .voice_size_in = 0
1.1 root 459: };
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.