|
|
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 decr;
1.1.1.7 ! root 45: int pending;
1.1.1.2 root 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.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:
1.1.1.7 ! root 228: if (sdl_lock (s, "sdl_callback")) {
! 229: return;
! 230: }
! 231:
1.1 root 232: if (s->exit) {
233: return;
234: }
235:
236: while (samples) {
1.1.1.2 root 237: int to_mix, decr;
1.1 root 238:
1.1.1.7 ! root 239: while (!sdl->pending) {
! 240: if (sdl_unlock (s, "sdl_callback")) {
! 241: return;
! 242: }
! 243:
! 244: sdl_wait (s, "sdl_callback");
! 245: if (s->exit) {
! 246: return;
! 247: }
! 248:
! 249: if (sdl_lock (s, "sdl_callback")) {
! 250: return;
! 251: }
! 252: sdl->pending += sdl->live;
! 253: sdl->live = 0;
1.1.1.2 root 254: }
1.1 root 255:
1.1.1.7 ! root 256: to_mix = audio_MIN (samples, sdl->pending);
! 257: decr = audio_pcm_hw_clip_out (hw, buf, to_mix, 0);
! 258: buf += decr << hw->info.shift;
1.1 root 259: samples -= decr;
1.1.1.2 root 260: sdl->decr += decr;
1.1.1.7 ! root 261: sdl->pending -= decr;
! 262: }
1.1 root 263:
1.1.1.7 ! root 264: if (sdl_unlock (s, "sdl_callback")) {
! 265: return;
1.1 root 266: }
267: }
268:
1.1.1.2 root 269: static int sdl_write_out (SWVoiceOut *sw, void *buf, int len)
1.1 root 270: {
1.1.1.2 root 271: return audio_pcm_sw_write (sw, buf, len);
1.1 root 272: }
273:
1.1.1.7 ! root 274: static int sdl_run_out (HWVoiceOut *hw, int live)
1.1 root 275: {
1.1.1.7 ! root 276: int decr;
1.1.1.2 root 277: SDLVoiceOut *sdl = (SDLVoiceOut *) hw;
1.1 root 278: SDLAudioState *s = &glob_sdl;
279:
1.1.1.7 ! root 280: if (sdl_lock (s, "sdl_run_out")) {
1.1.1.2 root 281: return 0;
282: }
1.1 root 283:
1.1.1.7 ! root 284: sdl->live = live;
! 285: decr = sdl->decr;
! 286: sdl->decr = 0;
1.1.1.2 root 287:
288: if (sdl->live > 0) {
1.1.1.7 ! root 289: sdl_unlock_and_post (s, "sdl_run_out");
1.1.1.2 root 290: }
291: else {
1.1.1.7 ! root 292: sdl_unlock (s, "sdl_run_out");
1.1.1.2 root 293: }
294: return decr;
295: }
1.1 root 296:
1.1.1.2 root 297: static void sdl_fini_out (HWVoiceOut *hw)
298: {
299: (void) hw;
300:
301: sdl_close (&glob_sdl);
302: }
303:
1.1.1.5 root 304: static int sdl_init_out (HWVoiceOut *hw, struct audsettings *as)
1.1.1.2 root 305: {
306: SDLVoiceOut *sdl = (SDLVoiceOut *) hw;
307: SDLAudioState *s = &glob_sdl;
308: SDL_AudioSpec req, obt;
309: int shift;
310: int endianess;
311: int err;
312: audfmt_e effective_fmt;
1.1.1.5 root 313: struct audsettings obt_as;
1.1.1.2 root 314:
315: shift <<= as->nchannels == 2;
316:
317: req.freq = as->freq;
318: req.format = aud_to_sdlfmt (as->fmt, &shift);
319: req.channels = as->nchannels;
320: req.samples = conf.nb_samples;
1.1 root 321: req.callback = sdl_callback;
322: req.userdata = sdl;
323:
1.1.1.2 root 324: if (sdl_open (&req, &obt)) {
325: return -1;
326: }
327:
328: err = sdl_to_audfmt (obt.format, &effective_fmt, &endianess);
329: if (err) {
330: sdl_close (s);
1.1 root 331: return -1;
1.1.1.2 root 332: }
1.1 root 333:
1.1.1.2 root 334: obt_as.freq = obt.freq;
335: obt_as.nchannels = obt.channels;
336: obt_as.fmt = effective_fmt;
1.1.1.3 root 337: obt_as.endianness = endianess;
1.1.1.2 root 338:
1.1.1.3 root 339: audio_pcm_init_info (&hw->info, &obt_as);
1.1.1.2 root 340: hw->samples = obt.samples;
1.1 root 341:
342: s->initialized = 1;
343: s->exit = 0;
344: SDL_PauseAudio (0);
345: return 0;
346: }
347:
1.1.1.2 root 348: static int sdl_ctl_out (HWVoiceOut *hw, int cmd, ...)
1.1 root 349: {
350: (void) hw;
351:
352: switch (cmd) {
353: case VOICE_ENABLE:
354: SDL_PauseAudio (0);
355: break;
356:
357: case VOICE_DISABLE:
358: SDL_PauseAudio (1);
359: break;
360: }
361: return 0;
362: }
363:
364: static void *sdl_audio_init (void)
365: {
366: SDLAudioState *s = &glob_sdl;
367:
368: if (SDL_InitSubSystem (SDL_INIT_AUDIO)) {
1.1.1.2 root 369: sdl_logerr ("SDL failed to initialize audio subsystem\n");
1.1 root 370: return NULL;
371: }
372:
373: s->mutex = SDL_CreateMutex ();
374: if (!s->mutex) {
1.1.1.2 root 375: sdl_logerr ("Failed to create SDL mutex\n");
1.1 root 376: SDL_QuitSubSystem (SDL_INIT_AUDIO);
377: return NULL;
378: }
379:
380: s->sem = SDL_CreateSemaphore (0);
381: if (!s->sem) {
1.1.1.2 root 382: sdl_logerr ("Failed to create SDL semaphore\n");
1.1 root 383: SDL_DestroyMutex (s->mutex);
384: SDL_QuitSubSystem (SDL_INIT_AUDIO);
385: return NULL;
386: }
387:
388: return s;
389: }
390:
391: static void sdl_audio_fini (void *opaque)
392: {
393: SDLAudioState *s = opaque;
394: sdl_close (s);
395: SDL_DestroySemaphore (s->sem);
396: SDL_DestroyMutex (s->mutex);
397: SDL_QuitSubSystem (SDL_INIT_AUDIO);
398: }
399:
1.1.1.2 root 400: static struct audio_option sdl_options[] = {
1.1.1.7 ! root 401: {
! 402: .name = "SAMPLES",
! 403: .tag = AUD_OPT_INT,
! 404: .valp = &conf.nb_samples,
! 405: .descr = "Size of SDL buffer in samples"
! 406: },
! 407: { /* End of list */ }
1.1.1.2 root 408: };
409:
410: static struct audio_pcm_ops sdl_pcm_ops = {
1.1.1.7 ! root 411: .init_out = sdl_init_out,
! 412: .fini_out = sdl_fini_out,
! 413: .run_out = sdl_run_out,
! 414: .write = sdl_write_out,
! 415: .ctl_out = sdl_ctl_out,
1.1 root 416: };
417:
1.1.1.2 root 418: struct audio_driver sdl_audio_driver = {
1.1.1.7 ! root 419: .name = "sdl",
! 420: .descr = "SDL http://www.libsdl.org",
! 421: .options = sdl_options,
! 422: .init = sdl_audio_init,
! 423: .fini = sdl_audio_fini,
! 424: .pcm_ops = &sdl_pcm_ops,
! 425: .can_be_default = 1,
! 426: .max_voices_out = 1,
! 427: .max_voices_in = 0,
! 428: .voice_size_out = sizeof (SDLVoiceOut),
! 429: .voice_size_in = 0
1.1 root 430: };
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.