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