/[qemu]/qemu/audio/sdlaudio.c
ViewVC logotype

Diff of /qemu/audio/sdlaudio.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1.4 by bellard, Tue Apr 26 20:35:05 2005 UTC revision 1.5 by bellard, Sun Oct 30 18:58:22 2005 UTC
# Line 1  Line 1 
1  /*  /*
2   * QEMU SDL audio output driver   * QEMU SDL audio driver
3   *   *
4   * Copyright (c) 2004 Vassili Karpov (malc)   * Copyright (c) 2004-2005 Vassili Karpov (malc)
5   *   *
6   * Permission is hereby granted, free of charge, to any person obtaining a copy   * 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   * of this software and associated documentation files (the "Software"), to deal
8   * in the Software without restriction, including without limitation the rights   * in the Software without restriction, including without limitation the rights
# Line 25  Line 25 
25  #include <SDL_thread.h>  #include <SDL_thread.h>
26  #include "vl.h"  #include "vl.h"
27    
28  #include "audio/audio_int.h"  #define AUDIO_CAP "sdl"
29    #include "audio_int.h"
 typedef struct SDLVoice {  
     HWVoice hw;  
 } SDLVoice;  
   
 #define dolog(...) AUD_log ("sdl", __VA_ARGS__)  
 #ifdef DEBUG  
 #define ldebug(...) dolog (__VA_ARGS__)  
 #else  
 #define ldebug(...)  
 #endif  
   
 #define QC_SDL_SAMPLES "QEMU_SDL_SAMPLES"  
30    
31  #define errstr() SDL_GetError ()  typedef struct SDLVoiceOut {
32        HWVoiceOut hw;
33        int live;
34        int rpos;
35        int decr;
36    } SDLVoiceOut;
37    
38  static struct {  static struct {
39      int nb_samples;      int nb_samples;
# Line 56  struct SDLAudioState { Line 49  struct SDLAudioState {
49  } glob_sdl;  } glob_sdl;
50  typedef struct SDLAudioState SDLAudioState;  typedef struct SDLAudioState SDLAudioState;
51    
52  static void sdl_hw_run (HWVoice *hw)  static void GCC_FMT_ATTR (1, 2) sdl_logerr (const char *fmt, ...)
53  {  {
54      (void) hw;      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 ());
61  }  }
62    
63  static int sdl_lock (SDLAudioState *s)  static int sdl_lock (SDLAudioState *s, const char *forfn)
64  {  {
65      if (SDL_LockMutex (s->mutex)) {      if (SDL_LockMutex (s->mutex)) {
66          dolog ("SDL_LockMutex failed\nReason: %s\n", errstr ());          sdl_logerr ("SDL_LockMutex for %s failed\n", forfn);
67          return -1;          return -1;
68      }      }
69      return 0;      return 0;
70  }  }
71    
72  static int sdl_unlock (SDLAudioState *s)  static int sdl_unlock (SDLAudioState *s, const char *forfn)
73  {  {
74      if (SDL_UnlockMutex (s->mutex)) {      if (SDL_UnlockMutex (s->mutex)) {
75          dolog ("SDL_UnlockMutex failed\nReason: %s\n", errstr ());          sdl_logerr ("SDL_UnlockMutex for %s failed\n", forfn);
76          return -1;          return -1;
77      }      }
78      return 0;      return 0;
79  }  }
80    
81  static int sdl_post (SDLAudioState *s)  static int sdl_post (SDLAudioState *s, const char *forfn)
82  {  {
83      if (SDL_SemPost (s->sem)) {      if (SDL_SemPost (s->sem)) {
84          dolog ("SDL_SemPost failed\nReason: %s\n", errstr ());          sdl_logerr ("SDL_SemPost for %s failed\n", forfn);
85          return -1;          return -1;
86      }      }
87      return 0;      return 0;
88  }  }
89    
90  static int sdl_wait (SDLAudioState *s)  static int sdl_wait (SDLAudioState *s, const char *forfn)
91  {  {
92      if (SDL_SemWait (s->sem)) {      if (SDL_SemWait (s->sem)) {
93          dolog ("SDL_SemWait failed\nReason: %s\n", errstr ());          sdl_logerr ("SDL_SemWait for %s failed\n", forfn);
94          return -1;          return -1;
95      }      }
96      return 0;      return 0;
97  }  }
98    
99  static int sdl_unlock_and_post (SDLAudioState *s)  static int sdl_unlock_and_post (SDLAudioState *s, const char *forfn)
100  {  {
101      if (sdl_unlock (s))      if (sdl_unlock (s, forfn)) {
102          return -1;          return -1;
103        }
104    
105      return sdl_post (s);      return sdl_post (s, forfn);
 }  
   
 static int sdl_hw_write (SWVoice *sw, void *buf, int len)  
 {  
     int ret;  
     SDLAudioState *s = &glob_sdl;  
     sdl_lock (s);  
     ret = pcm_hw_write (sw, buf, len);  
     sdl_unlock_and_post (s);  
     return ret;  
106  }  }
107    
108  static int AUD_to_sdlfmt (audfmt_e fmt, int *shift)  static int aud_to_sdlfmt (audfmt_e fmt, int *shift)
109  {  {
     *shift = 0;  
110      switch (fmt) {      switch (fmt) {
111      case AUD_FMT_S8: return AUDIO_S8;      case AUD_FMT_S8:
112      case AUD_FMT_U8: return AUDIO_U8;          *shift = 0;
113      case AUD_FMT_S16: *shift = 1; return AUDIO_S16LSB;          return AUDIO_S8;
114      case AUD_FMT_U16: *shift = 1; return AUDIO_U16LSB;  
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    
127      default:      default:
128          dolog ("Internal logic error: Bad audio format %d\nAborting\n", fmt);          dolog ("Internal logic error: Bad audio format %d\n", fmt);
129          exit (EXIT_FAILURE);  #ifdef DEBUG_AUDIO
130            abort ();
131    #endif
132            return AUDIO_U8;
133      }      }
134  }  }
135    
136  static int sdl_to_audfmt (int fmt)  static int sdl_to_audfmt (int sdlfmt, audfmt_e *fmt, int *endianess)
137  {  {
138      switch (fmt) {      switch (sdlfmt) {
139      case AUDIO_S8: return AUD_FMT_S8;      case AUDIO_S8:
140      case AUDIO_U8: return AUD_FMT_U8;          *endianess = 0;
141      case AUDIO_S16LSB: return AUD_FMT_S16;          *fmt = AUD_FMT_S8;
142      case AUDIO_U16LSB: return AUD_FMT_U16;          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    
169      default:      default:
170          dolog ("Internal logic error: Unrecognized SDL audio format %d\n"          dolog ("Unrecognized SDL audio format %d\n", sdlfmt);
171                 "Aborting\n", fmt);          return -1;
         exit (EXIT_FAILURE);  
172      }      }
173    
174        return 0;
175  }  }
176    
177  static int sdl_open (SDL_AudioSpec *req, SDL_AudioSpec *obt)  static int sdl_open (SDL_AudioSpec *req, SDL_AudioSpec *obt)
# Line 149  static int sdl_open (SDL_AudioSpec *req, Line 180  static int sdl_open (SDL_AudioSpec *req,
180    
181      status = SDL_OpenAudio (req, obt);      status = SDL_OpenAudio (req, obt);
182      if (status) {      if (status) {
183          dolog ("SDL_OpenAudio failed\nReason: %s\n", errstr ());          sdl_logerr ("SDL_OpenAudio failed\n");
184      }      }
185      return status;      return status;
186  }  }
# Line 157  static int sdl_open (SDL_AudioSpec *req, Line 188  static int sdl_open (SDL_AudioSpec *req,
188  static void sdl_close (SDLAudioState *s)  static void sdl_close (SDLAudioState *s)
189  {  {
190      if (s->initialized) {      if (s->initialized) {
191          sdl_lock (s);          sdl_lock (s, "sdl_close");
192          s->exit = 1;          s->exit = 1;
193          sdl_unlock_and_post (s);          sdl_unlock_and_post (s, "sdl_close");
194          SDL_PauseAudio (1);          SDL_PauseAudio (1);
195          SDL_CloseAudio ();          SDL_CloseAudio ();
196          s->initialized = 0;          s->initialized = 0;
# Line 168  static void sdl_close (SDLAudioState *s) Line 199  static void sdl_close (SDLAudioState *s)
199    
200  static void sdl_callback (void *opaque, Uint8 *buf, int len)  static void sdl_callback (void *opaque, Uint8 *buf, int len)
201  {  {
202      SDLVoice *sdl = opaque;      SDLVoiceOut *sdl = opaque;
203      SDLAudioState *s = &glob_sdl;      SDLAudioState *s = &glob_sdl;
204      HWVoice *hw = &sdl->hw;      HWVoiceOut *hw = &sdl->hw;
205      int samples = len >> hw->shift;      int samples = len >> hw->info.shift;
206    
207      if (s->exit) {      if (s->exit) {
208          return;          return;
209      }      }
210    
211      while (samples) {      while (samples) {
212          int to_mix, live, decr;          int to_mix, decr;
213    
214          /* dolog ("in callback samples=%d\n", samples); */          /* dolog ("in callback samples=%d\n", samples); */
215          sdl_wait (s);          sdl_wait (s, "sdl_callback");
216          if (s->exit) {          if (s->exit) {
217              return;              return;
218          }          }
219    
220          sdl_lock (s);          if (sdl_lock (s, "sdl_callback")) {
221          live = pcm_hw_get_live (hw);              return;
222          if (live <= 0)          }
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) {
231              goto again;              goto again;
232            }
233    
234          /* dolog ("in callback live=%d\n", live); */          /* dolog ("in callback live=%d\n", live); */
235          to_mix = audio_MIN (samples, live);          to_mix = audio_MIN (samples, sdl->live);
236          decr = to_mix;          decr = to_mix;
237          while (to_mix) {          while (to_mix) {
238              int chunk = audio_MIN (to_mix, hw->samples - hw->rpos);              int chunk = audio_MIN (to_mix, hw->samples - hw->rpos);
# Line 200  static void sdl_callback (void *opaque, Line 240  static void sdl_callback (void *opaque,
240    
241              /* dolog ("in callback to_mix %d, chunk %d\n", to_mix, chunk); */              /* dolog ("in callback to_mix %d, chunk %d\n", to_mix, chunk); */
242              hw->clip (buf, src, chunk);              hw->clip (buf, src, chunk);
243              memset (src, 0, chunk * sizeof (st_sample_t));              mixeng_clear (src, chunk);
244              hw->rpos = (hw->rpos + chunk) % hw->samples;              sdl->rpos = (sdl->rpos + chunk) % hw->samples;
245              to_mix -= chunk;              to_mix -= chunk;
246              buf += chunk << hw->shift;              buf += chunk << hw->info.shift;
247          }          }
248          samples -= decr;          samples -= decr;
249          pcm_hw_dec_live (hw, decr);          sdl->live -= decr;
250            sdl->decr += decr;
251    
252      again:      again:
253          sdl_unlock (s);          if (sdl_unlock (s, "sdl_callback")) {
254                return;
255            }
256      }      }
257      /* dolog ("done len=%d\n", len); */      /* dolog ("done len=%d\n", len); */
258  }  }
259    
260  static void sdl_hw_fini (HWVoice *hw)  static int sdl_write_out (SWVoiceOut *sw, void *buf, int len)
261  {  {
262      ldebug ("sdl_hw_fini %d fixed=%d\n",      return audio_pcm_sw_write (sw, buf, len);
263               glob_sdl.initialized, audio_state.fixed_format);  }
264    
265    static int sdl_run_out (HWVoiceOut *hw)
266    {
267        int decr, live;
268        SDLVoiceOut *sdl = (SDLVoiceOut *) hw;
269        SDLAudioState *s = &glob_sdl;
270    
271        if (sdl_lock (s, "sdl_callback")) {
272            return 0;
273        }
274    
275        live = audio_pcm_hw_get_live_out (hw);
276    
277        if (sdl->decr > live) {
278            ldebug ("sdl->decr %d live %d sdl->live %d\n",
279                    sdl->decr,
280                    live,
281                    sdl->live);
282        }
283    
284        decr = audio_MIN (sdl->decr, live);
285        sdl->decr -= decr;
286    
287        sdl->live = live - decr;
288        hw->rpos = sdl->rpos;
289    
290        if (sdl->live > 0) {
291            sdl_unlock_and_post (s, "sdl_callback");
292        }
293        else {
294            sdl_unlock (s, "sdl_callback");
295        }
296        return decr;
297    }
298    
299    static void sdl_fini_out (HWVoiceOut *hw)
300    {
301        (void) hw;
302    
303      sdl_close (&glob_sdl);      sdl_close (&glob_sdl);
304  }  }
305    
306  static int sdl_hw_init (HWVoice *hw, int freq, int nchannels, audfmt_e fmt)  static int sdl_init_out (HWVoiceOut *hw, int freq, int nchannels, audfmt_e fmt)
307  {  {
308      SDLVoice *sdl = (SDLVoice *) hw;      SDLVoiceOut *sdl = (SDLVoiceOut *) hw;
309      SDLAudioState *s = &glob_sdl;      SDLAudioState *s = &glob_sdl;
310      SDL_AudioSpec req, obt;      SDL_AudioSpec req, obt;
311      int shift;      int shift;
312        int endianess;
313      ldebug ("sdl_hw_init %d freq=%d fixed=%d\n",      int err;
314              s->initialized, freq, audio_state.fixed_format);      audfmt_e effective_fmt;
315    
316      if (nchannels != 2) {      if (nchannels != 2) {
317          dolog ("Bogus channel count %d\n", nchannels);          dolog ("Can not init DAC. Bogus channel count %d\n", nchannels);
318          return -1;          return -1;
319      }      }
320    
321      req.freq = freq;      req.freq = freq;
322      req.format = AUD_to_sdlfmt (fmt, &shift);      req.format = aud_to_sdlfmt (fmt, &shift);
323      req.channels = nchannels;      req.channels = nchannels;
324      req.samples = conf.nb_samples;      req.samples = conf.nb_samples;
325      shift <<= nchannels == 2;      shift <<= nchannels == 2;
# Line 245  static int sdl_hw_init (HWVoice *hw, int Line 327  static int sdl_hw_init (HWVoice *hw, int
327      req.callback = sdl_callback;      req.callback = sdl_callback;
328      req.userdata = sdl;      req.userdata = sdl;
329    
330      if (sdl_open (&req, &obt))      if (sdl_open (&req, &obt)) {
331            return -1;
332        }
333    
334        err = sdl_to_audfmt (obt.format, &effective_fmt, &endianess);
335        if (err) {
336            sdl_close (s);
337          return -1;          return -1;
338        }
339    
340      hw->freq = obt.freq;      audio_pcm_init_info (
341      hw->fmt = sdl_to_audfmt (obt.format);          &hw->info,
342      hw->nchannels = obt.channels;          obt.freq,
343            obt.channels,
344            effective_fmt,
345            audio_need_to_swap_endian (endianess)
346            );
347      hw->bufsize = obt.samples << shift;      hw->bufsize = obt.samples << shift;
348    
349      s->initialized = 1;      s->initialized = 1;
# Line 259  static int sdl_hw_init (HWVoice *hw, int Line 352  static int sdl_hw_init (HWVoice *hw, int
352      return 0;      return 0;
353  }  }
354    
355  static int sdl_hw_ctl (HWVoice *hw, int cmd, ...)  static int sdl_ctl_out (HWVoiceOut *hw, int cmd, ...)
356  {  {
357      (void) hw;      (void) hw;
358    
# Line 278  static int sdl_hw_ctl (HWVoice *hw, int Line 371  static int sdl_hw_ctl (HWVoice *hw, int
371  static void *sdl_audio_init (void)  static void *sdl_audio_init (void)
372  {  {
373      SDLAudioState *s = &glob_sdl;      SDLAudioState *s = &glob_sdl;
     conf.nb_samples = audio_get_conf_int (QC_SDL_SAMPLES, conf.nb_samples);  
374    
375      if (SDL_InitSubSystem (SDL_INIT_AUDIO)) {      if (SDL_InitSubSystem (SDL_INIT_AUDIO)) {
376          dolog ("SDL failed to initialize audio subsystem\nReason: %s\n",          sdl_logerr ("SDL failed to initialize audio subsystem\n");
                errstr ());  
377          return NULL;          return NULL;
378      }      }
379    
380      s->mutex = SDL_CreateMutex ();      s->mutex = SDL_CreateMutex ();
381      if (!s->mutex) {      if (!s->mutex) {
382          dolog ("Failed to create SDL mutex\nReason: %s\n", errstr ());          sdl_logerr ("Failed to create SDL mutex\n");
383          SDL_QuitSubSystem (SDL_INIT_AUDIO);          SDL_QuitSubSystem (SDL_INIT_AUDIO);
384          return NULL;          return NULL;
385      }      }
386    
387      s->sem = SDL_CreateSemaphore (0);      s->sem = SDL_CreateSemaphore (0);
388      if (!s->sem) {      if (!s->sem) {
389          dolog ("Failed to create SDL semaphore\nReason: %s\n", errstr ());          sdl_logerr ("Failed to create SDL semaphore\n");
390          SDL_DestroyMutex (s->mutex);          SDL_DestroyMutex (s->mutex);
391          SDL_QuitSubSystem (SDL_INIT_AUDIO);          SDL_QuitSubSystem (SDL_INIT_AUDIO);
392          return NULL;          return NULL;
# Line 313  static void sdl_audio_fini (void *opaque Line 404  static void sdl_audio_fini (void *opaque
404      SDL_QuitSubSystem (SDL_INIT_AUDIO);      SDL_QuitSubSystem (SDL_INIT_AUDIO);
405  }  }
406    
407  struct pcm_ops sdl_pcm_ops = {  static struct audio_option sdl_options[] = {
408      sdl_hw_init,      {"SAMPLES", AUD_OPT_INT, &conf.nb_samples,
409      sdl_hw_fini,       "Size of SDL buffer in samples", NULL, 0},
410      sdl_hw_run,      {NULL, 0, NULL, NULL, NULL, 0}
411      sdl_hw_write,  };
412      sdl_hw_ctl  
413    static struct audio_pcm_ops sdl_pcm_ops = {
414        sdl_init_out,
415        sdl_fini_out,
416        sdl_run_out,
417        sdl_write_out,
418        sdl_ctl_out,
419    
420        NULL,
421        NULL,
422        NULL,
423        NULL,
424        NULL
425  };  };
426    
427  struct audio_output_driver sdl_output_driver = {  struct audio_driver sdl_audio_driver = {
428      "sdl",      INIT_FIELD (name           = ) "sdl",
429      sdl_audio_init,      INIT_FIELD (descr          = ) "SDL http://www.libsdl.org",
430      sdl_audio_fini,      INIT_FIELD (options        = ) sdl_options,
431      &sdl_pcm_ops,      INIT_FIELD (init           = ) sdl_audio_init,
432      1,      INIT_FIELD (fini           = ) sdl_audio_fini,
433      1,      INIT_FIELD (pcm_ops        = ) &sdl_pcm_ops,
434      sizeof (SDLVoice)      INIT_FIELD (can_be_default = ) 1,
435        INIT_FIELD (max_voices_out = ) 1,
436        INIT_FIELD (max_voices_in  = ) 0,
437        INIT_FIELD (voice_size_out = ) sizeof (SDLVoiceOut),
438        INIT_FIELD (voice_size_in  = ) 0
439  };  };

Legend:
Removed from v.1.4  
changed lines
  Added in v.1.5

savannah-hackers-public@gnu.org
ViewVC Help
Powered by ViewVC 1.1.26