|
|
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: #endif
1.1 root 36:
1.1.1.2 root 37: #define AUDIO_CAP "sdl"
38: #include "audio_int.h"
1.1 root 39:
1.1.1.2 root 40: typedef struct SDLVoiceOut {
41: HWVoiceOut hw;
42: int live;
1.1.1.8 root 43: int rpos;
1.1.1.2 root 44: int decr;
45: } SDLVoiceOut;
1.1 root 46:
47: static struct {
48: int nb_samples;
49: } conf = {
1.1.1.7 root 50: .nb_samples = 1024
1.1 root 51: };
52:
1.1.1.5 root 53: static struct SDLAudioState {
1.1 root 54: int exit;
55: SDL_mutex *mutex;
56: SDL_sem *sem;
57: int initialized;
58: } glob_sdl;
59: typedef struct SDLAudioState SDLAudioState;
60:
1.1.1.2 root 61: static void GCC_FMT_ATTR (1, 2) sdl_logerr (const char *fmt, ...)
1.1 root 62: {
1.1.1.2 root 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 ());
1.1 root 70: }
71:
1.1.1.2 root 72: static int sdl_lock (SDLAudioState *s, const char *forfn)
1.1 root 73: {
74: if (SDL_LockMutex (s->mutex)) {
1.1.1.2 root 75: sdl_logerr ("SDL_LockMutex for %s failed\n", forfn);
1.1 root 76: return -1;
77: }
78: return 0;
79: }
80:
1.1.1.2 root 81: static int sdl_unlock (SDLAudioState *s, const char *forfn)
1.1 root 82: {
83: if (SDL_UnlockMutex (s->mutex)) {
1.1.1.2 root 84: sdl_logerr ("SDL_UnlockMutex for %s failed\n", forfn);
1.1 root 85: return -1;
86: }
87: return 0;
88: }
89:
1.1.1.2 root 90: static int sdl_post (SDLAudioState *s, const char *forfn)
1.1 root 91: {
92: if (SDL_SemPost (s->sem)) {
1.1.1.2 root 93: sdl_logerr ("SDL_SemPost for %s failed\n", forfn);
1.1 root 94: return -1;
95: }
96: return 0;
97: }
98:
1.1.1.2 root 99: static int sdl_wait (SDLAudioState *s, const char *forfn)
1.1 root 100: {
101: if (SDL_SemWait (s->sem)) {
1.1.1.2 root 102: sdl_logerr ("SDL_SemWait for %s failed\n", forfn);
1.1 root 103: return -1;
104: }
105: return 0;
106: }
107:
1.1.1.2 root 108: static int sdl_unlock_and_post (SDLAudioState *s, const char *forfn)
1.1 root 109: {
1.1.1.2 root 110: if (sdl_unlock (s, forfn)) {
1.1 root 111: return -1;
1.1.1.2 root 112: }
1.1 root 113:
1.1.1.2 root 114: return sdl_post (s, forfn);
1.1 root 115: }
116:
1.1.1.8 root 117: static int aud_to_sdlfmt (audfmt_e fmt)
1.1 root 118: {
119: switch (fmt) {
1.1.1.2 root 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:
1.1 root 132: default:
1.1.1.2 root 133: dolog ("Internal logic error: Bad audio format %d\n", fmt);
134: #ifdef DEBUG_AUDIO
135: abort ();
136: #endif
137: return AUDIO_U8;
1.1 root 138: }
139: }
140:
1.1.1.10! root 141: static int sdl_to_audfmt(int sdlfmt, audfmt_e *fmt, int *endianness)
1.1 root 142: {
1.1.1.2 root 143: switch (sdlfmt) {
144: case AUDIO_S8:
1.1.1.10! root 145: *endianness = 0;
1.1.1.2 root 146: *fmt = AUD_FMT_S8;
147: break;
148:
149: case AUDIO_U8:
1.1.1.10! root 150: *endianness = 0;
1.1.1.2 root 151: *fmt = AUD_FMT_U8;
152: break;
153:
154: case AUDIO_S16LSB:
1.1.1.10! root 155: *endianness = 0;
1.1.1.2 root 156: *fmt = AUD_FMT_S16;
157: break;
158:
159: case AUDIO_U16LSB:
1.1.1.10! root 160: *endianness = 0;
1.1.1.2 root 161: *fmt = AUD_FMT_U16;
162: break;
163:
164: case AUDIO_S16MSB:
1.1.1.10! root 165: *endianness = 1;
1.1.1.2 root 166: *fmt = AUD_FMT_S16;
167: break;
168:
169: case AUDIO_U16MSB:
1.1.1.10! root 170: *endianness = 1;
1.1.1.2 root 171: *fmt = AUD_FMT_U16;
172: break;
173:
1.1 root 174: default:
1.1.1.2 root 175: dolog ("Unrecognized SDL audio format %d\n", sdlfmt);
176: return -1;
1.1 root 177: }
1.1.1.2 root 178:
179: return 0;
1.1 root 180: }
181:
182: static int sdl_open (SDL_AudioSpec *req, SDL_AudioSpec *obt)
183: {
184: int status;
1.1.1.4 root 185: #ifndef _WIN32
1.1.1.9 root 186: int err;
1.1.1.4 root 187: sigset_t new, old;
188:
189: /* Make sure potential threads created by SDL don't hog signals. */
1.1.1.9 root 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: }
1.1.1.4 root 200: #endif
1.1 root 201:
202: status = SDL_OpenAudio (req, obt);
203: if (status) {
1.1.1.2 root 204: sdl_logerr ("SDL_OpenAudio failed\n");
1.1 root 205: }
1.1.1.4 root 206:
207: #ifndef _WIN32
1.1.1.9 root 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: }
1.1.1.4 root 216: #endif
1.1 root 217: return status;
218: }
219:
220: static void sdl_close (SDLAudioState *s)
221: {
222: if (s->initialized) {
1.1.1.2 root 223: sdl_lock (s, "sdl_close");
1.1 root 224: s->exit = 1;
1.1.1.2 root 225: sdl_unlock_and_post (s, "sdl_close");
1.1 root 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: {
1.1.1.2 root 234: SDLVoiceOut *sdl = opaque;
1.1 root 235: SDLAudioState *s = &glob_sdl;
1.1.1.2 root 236: HWVoiceOut *hw = &sdl->hw;
237: int samples = len >> hw->info.shift;
1.1 root 238:
239: if (s->exit) {
240: return;
241: }
242:
243: while (samples) {
1.1.1.2 root 244: int to_mix, decr;
1.1 root 245:
1.1.1.8 root 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;
1.1.1.2 root 264: }
1.1 root 265:
1.1.1.8 root 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: }
1.1 root 279: samples -= decr;
1.1.1.8 root 280: sdl->live -= decr;
1.1.1.2 root 281: sdl->decr += decr;
1.1 root 282:
1.1.1.8 root 283: again:
284: if (sdl_unlock (s, "sdl_callback")) {
285: return;
286: }
1.1 root 287: }
1.1.1.8 root 288: /* dolog ("done len=%d\n", len); */
1.1 root 289: }
290:
1.1.1.2 root 291: static int sdl_write_out (SWVoiceOut *sw, void *buf, int len)
1.1 root 292: {
1.1.1.2 root 293: return audio_pcm_sw_write (sw, buf, len);
1.1 root 294: }
295:
1.1.1.7 root 296: static int sdl_run_out (HWVoiceOut *hw, int live)
1.1 root 297: {
1.1.1.7 root 298: int decr;
1.1.1.2 root 299: SDLVoiceOut *sdl = (SDLVoiceOut *) hw;
1.1 root 300: SDLAudioState *s = &glob_sdl;
301:
1.1.1.7 root 302: if (sdl_lock (s, "sdl_run_out")) {
1.1.1.2 root 303: return 0;
304: }
1.1 root 305:
1.1.1.8 root 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;
1.1.1.2 root 318:
319: if (sdl->live > 0) {
1.1.1.7 root 320: sdl_unlock_and_post (s, "sdl_run_out");
1.1.1.2 root 321: }
322: else {
1.1.1.7 root 323: sdl_unlock (s, "sdl_run_out");
1.1.1.2 root 324: }
325: return decr;
326: }
1.1 root 327:
1.1.1.2 root 328: static void sdl_fini_out (HWVoiceOut *hw)
329: {
330: (void) hw;
331:
332: sdl_close (&glob_sdl);
333: }
334:
1.1.1.5 root 335: static int sdl_init_out (HWVoiceOut *hw, struct audsettings *as)
1.1.1.2 root 336: {
337: SDLVoiceOut *sdl = (SDLVoiceOut *) hw;
338: SDLAudioState *s = &glob_sdl;
339: SDL_AudioSpec req, obt;
1.1.1.10! root 340: int endianness;
1.1.1.2 root 341: int err;
342: audfmt_e effective_fmt;
1.1.1.5 root 343: struct audsettings obt_as;
1.1.1.2 root 344:
345: req.freq = as->freq;
1.1.1.8 root 346: req.format = aud_to_sdlfmt (as->fmt);
1.1.1.2 root 347: req.channels = as->nchannels;
348: req.samples = conf.nb_samples;
1.1 root 349: req.callback = sdl_callback;
350: req.userdata = sdl;
351:
1.1.1.2 root 352: if (sdl_open (&req, &obt)) {
353: return -1;
354: }
355:
1.1.1.10! root 356: err = sdl_to_audfmt(obt.format, &effective_fmt, &endianness);
1.1.1.2 root 357: if (err) {
358: sdl_close (s);
1.1 root 359: return -1;
1.1.1.2 root 360: }
1.1 root 361:
1.1.1.2 root 362: obt_as.freq = obt.freq;
363: obt_as.nchannels = obt.channels;
364: obt_as.fmt = effective_fmt;
1.1.1.10! root 365: obt_as.endianness = endianness;
1.1.1.2 root 366:
1.1.1.3 root 367: audio_pcm_init_info (&hw->info, &obt_as);
1.1.1.2 root 368: hw->samples = obt.samples;
1.1 root 369:
370: s->initialized = 1;
371: s->exit = 0;
372: SDL_PauseAudio (0);
373: return 0;
374: }
375:
1.1.1.2 root 376: static int sdl_ctl_out (HWVoiceOut *hw, int cmd, ...)
1.1 root 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)) {
1.1.1.2 root 397: sdl_logerr ("SDL failed to initialize audio subsystem\n");
1.1 root 398: return NULL;
399: }
400:
401: s->mutex = SDL_CreateMutex ();
402: if (!s->mutex) {
1.1.1.2 root 403: sdl_logerr ("Failed to create SDL mutex\n");
1.1 root 404: SDL_QuitSubSystem (SDL_INIT_AUDIO);
405: return NULL;
406: }
407:
408: s->sem = SDL_CreateSemaphore (0);
409: if (!s->sem) {
1.1.1.2 root 410: sdl_logerr ("Failed to create SDL semaphore\n");
1.1 root 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:
1.1.1.2 root 428: static struct audio_option sdl_options[] = {
1.1.1.7 root 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 */ }
1.1.1.2 root 436: };
437:
438: static struct audio_pcm_ops sdl_pcm_ops = {
1.1.1.7 root 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,
1.1 root 444: };
445:
1.1.1.2 root 446: struct audio_driver sdl_audio_driver = {
1.1.1.7 root 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
1.1 root 458: };
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.