]> git.proxmox.com Git - qemu.git/blobdiff - audio/sdlaudio.c
Update version for 1.5.0 release.
[qemu.git] / audio / sdlaudio.c
index aa39c3379c1961e6027a3310d003b74aed57b02c..d24daa5ead5eb0b813fd368a90031468777f5c18 100644 (file)
@@ -32,7 +32,6 @@
 #elif defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__DragonFly__)
 #include <pthread.h>
 #endif
-#include <signal.h>
 #endif
 
 #define AUDIO_CAP "sdl"
@@ -41,8 +40,8 @@
 typedef struct SDLVoiceOut {
     HWVoiceOut hw;
     int live;
+    int rpos;
     int decr;
-    int pending;
 } SDLVoiceOut;
 
 static struct {
@@ -115,23 +114,19 @@ static int sdl_unlock_and_post (SDLAudioState *s, const char *forfn)
     return sdl_post (s, forfn);
 }
 
-static int aud_to_sdlfmt (audfmt_e fmt, int *shift)
+static int aud_to_sdlfmt (audfmt_e fmt)
 {
     switch (fmt) {
     case AUD_FMT_S8:
-        *shift = 0;
         return AUDIO_S8;
 
     case AUD_FMT_U8:
-        *shift = 0;
         return AUDIO_U8;
 
     case AUD_FMT_S16:
-        *shift = 1;
         return AUDIO_S16LSB;
 
     case AUD_FMT_U16:
-        *shift = 1;
         return AUDIO_U16LSB;
 
     default:
@@ -143,36 +138,36 @@ static int aud_to_sdlfmt (audfmt_e fmt, int *shift)
     }
 }
 
-static int sdl_to_audfmt (int sdlfmt, audfmt_e *fmt, int *endianess)
+static int sdl_to_audfmt(int sdlfmt, audfmt_e *fmt, int *endianness)
 {
     switch (sdlfmt) {
     case AUDIO_S8:
-        *endianess = 0;
+        *endianness = 0;
         *fmt = AUD_FMT_S8;
         break;
 
     case AUDIO_U8:
-        *endianess = 0;
+        *endianness = 0;
         *fmt = AUD_FMT_U8;
         break;
 
     case AUDIO_S16LSB:
-        *endianess = 0;
+        *endianness = 0;
         *fmt = AUD_FMT_S16;
         break;
 
     case AUDIO_U16LSB:
-        *endianess = 0;
+        *endianness = 0;
         *fmt = AUD_FMT_U16;
         break;
 
     case AUDIO_S16MSB:
-        *endianess = 1;
+        *endianness = 1;
         *fmt = AUD_FMT_S16;
         break;
 
     case AUDIO_U16MSB:
-        *endianess = 1;
+        *endianness = 1;
         *fmt = AUD_FMT_U16;
         break;
 
@@ -188,11 +183,20 @@ static int sdl_open (SDL_AudioSpec *req, SDL_AudioSpec *obt)
 {
     int status;
 #ifndef _WIN32
+    int err;
     sigset_t new, old;
 
     /* Make sure potential threads created by SDL don't hog signals.  */
-    sigfillset (&new);
-    pthread_sigmask (SIG_BLOCK, &new, &old);
+    err = sigfillset (&new);
+    if (err) {
+        dolog ("sdl_open: sigfillset failed: %s\n", strerror (errno));
+        return -1;
+    }
+    err = pthread_sigmask (SIG_BLOCK, &new, &old);
+    if (err) {
+        dolog ("sdl_open: pthread_sigmask failed: %s\n", strerror (err));
+        return -1;
+    }
 #endif
 
     status = SDL_OpenAudio (req, obt);
@@ -201,7 +205,14 @@ static int sdl_open (SDL_AudioSpec *req, SDL_AudioSpec *obt)
     }
 
 #ifndef _WIN32
-    pthread_sigmask (SIG_SETMASK, &old, NULL);
+    err = pthread_sigmask (SIG_SETMASK, &old, NULL);
+    if (err) {
+        dolog ("sdl_open: pthread_sigmask (restore) failed: %s\n",
+               strerror (errno));
+        /* We have failed to restore original signal mask, all bets are off,
+           so exit the process */
+        exit (EXIT_FAILURE);
+    }
 #endif
     return status;
 }
@@ -225,10 +236,6 @@ static void sdl_callback (void *opaque, Uint8 *buf, int len)
     HWVoiceOut *hw = &sdl->hw;
     int samples = len >> hw->info.shift;
 
-    if (sdl_lock (s, "sdl_callback")) {
-        return;
-    }
-
     if (s->exit) {
         return;
     }
@@ -236,34 +243,49 @@ static void sdl_callback (void *opaque, Uint8 *buf, int len)
     while (samples) {
         int to_mix, decr;
 
-        while (!sdl->pending) {
-            if (sdl_unlock (s, "sdl_callback")) {
-                return;
-            }
-
-            sdl_wait (s, "sdl_callback");
-            if (s->exit) {
-                return;
-            }
-
-            if (sdl_lock (s, "sdl_callback")) {
-                return;
-            }
-            sdl->pending += sdl->live;
-            sdl->live = 0;
+        /* dolog ("in callback samples=%d\n", samples); */
+        sdl_wait (s, "sdl_callback");
+        if (s->exit) {
+            return;
+        }
+
+        if (sdl_lock (s, "sdl_callback")) {
+            return;
+        }
+
+        if (audio_bug (AUDIO_FUNC, sdl->live < 0 || sdl->live > hw->samples)) {
+            dolog ("sdl->live=%d hw->samples=%d\n",
+                   sdl->live, hw->samples);
+            return;
         }
 
-        to_mix = audio_MIN (samples, sdl->pending);
-        decr = audio_pcm_hw_clip_out (hw, buf, to_mix, 0);
-        buf += decr << hw->info.shift;
+        if (!sdl->live) {
+            goto again;
+        }
+
+        /* dolog ("in callback live=%d\n", live); */
+        to_mix = audio_MIN (samples, sdl->live);
+        decr = to_mix;
+        while (to_mix) {
+            int chunk = audio_MIN (to_mix, hw->samples - hw->rpos);
+            struct st_sample *src = hw->mix_buf + hw->rpos;
+
+            /* dolog ("in callback to_mix %d, chunk %d\n", to_mix, chunk); */
+            hw->clip (buf, src, chunk);
+            sdl->rpos = (sdl->rpos + chunk) % hw->samples;
+            to_mix -= chunk;
+            buf += chunk << hw->info.shift;
+        }
         samples -= decr;
+        sdl->live -= decr;
         sdl->decr += decr;
-        sdl->pending -= decr;
-    }
 
-    if (sdl_unlock (s, "sdl_callback")) {
-        return;
+    again:
+        if (sdl_unlock (s, "sdl_callback")) {
+            return;
+        }
     }
+    /* dolog ("done len=%d\n", len); */
 }
 
 static int sdl_write_out (SWVoiceOut *sw, void *buf, int len)
@@ -281,9 +303,18 @@ static int sdl_run_out (HWVoiceOut *hw, int live)
         return 0;
     }
 
-    sdl->live = live;
-    decr = sdl->decr;
-    sdl->decr = 0;
+    if (sdl->decr > live) {
+        ldebug ("sdl->decr %d live %d sdl->live %d\n",
+                sdl->decr,
+                live,
+                sdl->live);
+    }
+
+    decr = audio_MIN (sdl->decr, live);
+    sdl->decr -= decr;
+
+    sdl->live = live - decr;
+    hw->rpos = sdl->rpos;
 
     if (sdl->live > 0) {
         sdl_unlock_and_post (s, "sdl_run_out");
@@ -306,16 +337,13 @@ static int sdl_init_out (HWVoiceOut *hw, struct audsettings *as)
     SDLVoiceOut *sdl = (SDLVoiceOut *) hw;
     SDLAudioState *s = &glob_sdl;
     SDL_AudioSpec req, obt;
-    int shift;
-    int endianess;
+    int endianness;
     int err;
     audfmt_e effective_fmt;
     struct audsettings obt_as;
 
-    shift <<= as->nchannels == 2;
-
     req.freq = as->freq;
-    req.format = aud_to_sdlfmt (as->fmt, &shift);
+    req.format = aud_to_sdlfmt (as->fmt);
     req.channels = as->nchannels;
     req.samples = conf.nb_samples;
     req.callback = sdl_callback;
@@ -325,7 +353,7 @@ static int sdl_init_out (HWVoiceOut *hw, struct audsettings *as)
         return -1;
     }
 
-    err = sdl_to_audfmt (obt.format, &effective_fmt, &endianess);
+    err = sdl_to_audfmt(obt.format, &effective_fmt, &endianness);
     if (err) {
         sdl_close (s);
         return -1;
@@ -334,7 +362,7 @@ static int sdl_init_out (HWVoiceOut *hw, struct audsettings *as)
     obt_as.freq = obt.freq;
     obt_as.nchannels = obt.channels;
     obt_as.fmt = effective_fmt;
-    obt_as.endianness = endianess;
+    obt_as.endianness = endianness;
 
     audio_pcm_init_info (&hw->info, &obt_as);
     hw->samples = obt.samples;