diff mbox

[RFC] audio/sdlaudio: Allow audio playback with SDL2

Message ID 1485852398-2327-1-git-send-email-thuth@redhat.com (mailing list archive)
State New, archived
Headers show

Commit Message

Thomas Huth Jan. 31, 2017, 8:46 a.m. UTC
When compiling with SDL2, the semaphore trick used in sdlaudio.c
does not work - QEMU locks up completely in this case. To avoid
the hang and get at least some audio playback up and running (it's
a little bit crackling, but better than nothing), we can use the
SDL locking functions SDL_LockAudio() and SDL_UnlockAudio() to sync
with the sound playback thread instead.

Signed-off-by: Thomas Huth <thuth@redhat.com>
---
 audio/sdlaudio.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 48 insertions(+)

Comments

Gerd Hoffmann Feb. 1, 2017, 1:25 p.m. UTC | #1
On Di, 2017-01-31 at 09:46 +0100, Thomas Huth wrote:
> When compiling with SDL2, the semaphore trick used in sdlaudio.c
> does not work - QEMU locks up completely in this case. To avoid
> the hang and get at least some audio playback up and running (it's
> a little bit crackling, but better than nothing), we can use the
> SDL locking functions SDL_LockAudio() and SDL_UnlockAudio() to sync
> with the sound playback thread instead.

Does SDL_LockAudio work with sdl1 too?
So we can possibly avoid having all those #ifdefs?

cheers,
  Gerd
Thomas Huth Feb. 1, 2017, 3:30 p.m. UTC | #2
On 01.02.2017 14:25, Gerd Hoffmann wrote:
> On Di, 2017-01-31 at 09:46 +0100, Thomas Huth wrote:
>> When compiling with SDL2, the semaphore trick used in sdlaudio.c
>> does not work - QEMU locks up completely in this case. To avoid
>> the hang and get at least some audio playback up and running (it's
>> a little bit crackling, but better than nothing), we can use the
>> SDL locking functions SDL_LockAudio() and SDL_UnlockAudio() to sync
>> with the sound playback thread instead.
> 
> Does SDL_LockAudio work with sdl1 too?
> So we can possibly avoid having all those #ifdefs?

It somehow works, too, but sound quality is - at least for me - much
worse here than with the semaphore code. Maybe it can be fixed, too, but
I am really not familiar enough with the QEMU internal audio API to
figure out how to fix this (e.g. I don't understand why the run_out
function is called way more often than the callback function, but its
"live" parameter never reaches the full buffer size).
So maybe we can start with the #ifdefs for now and remove them once
somebody figured out how to improve sound quality for SDL1, too? (or
once we remove support for SDL1 from QEMU completely ... or do we want
to carry that with us forever?).

 Thomas
Gerd Hoffmann Feb. 16, 2017, 3:14 p.m. UTC | #3
On Mi, 2017-02-01 at 16:30 +0100, Thomas Huth wrote:
> On 01.02.2017 14:25, Gerd Hoffmann wrote:
> > On Di, 2017-01-31 at 09:46 +0100, Thomas Huth wrote:
> >> When compiling with SDL2, the semaphore trick used in sdlaudio.c
> >> does not work - QEMU locks up completely in this case. To avoid
> >> the hang and get at least some audio playback up and running (it's
> >> a little bit crackling, but better than nothing), we can use the
> >> SDL locking functions SDL_LockAudio() and SDL_UnlockAudio() to sync
> >> with the sound playback thread instead.
> > 
> > Does SDL_LockAudio work with sdl1 too?
> > So we can possibly avoid having all those #ifdefs?
> 
> It somehow works, too, but sound quality is - at least for me - much
> worse here than with the semaphore code. Maybe it can be fixed, too, but
> I am really not familiar enough with the QEMU internal audio API to
> figure out how to fix this (e.g. I don't understand why the run_out
> function is called way more often than the callback function, but its
> "live" parameter never reaches the full buffer size).
> So maybe we can start with the #ifdefs for now and remove them once
> somebody figured out how to improve sound quality for SDL1, too? (or
> once we remove support for SDL1 from QEMU completely ... or do we want
> to carry that with us forever?).

Ok, picked as-is for now.  It's better than nothing, and I'm too busy
with other stuff atm to have a closer look myself.

thanks,
  Gerd
diff mbox

Patch

diff --git a/audio/sdlaudio.c b/audio/sdlaudio.c
index db69fe1..e8d91d2 100644
--- a/audio/sdlaudio.c
+++ b/audio/sdlaudio.c
@@ -38,10 +38,14 @@ 
 #define AUDIO_CAP "sdl"
 #include "audio_int.h"
 
+#define USE_SEMAPHORE (SDL_MAJOR_VERSION < 2)
+
 typedef struct SDLVoiceOut {
     HWVoiceOut hw;
     int live;
+#if USE_SEMAPHORE
     int rpos;
+#endif
     int decr;
 } SDLVoiceOut;
 
@@ -53,8 +57,10 @@  static struct {
 
 static struct SDLAudioState {
     int exit;
+#if USE_SEMAPHORE
     SDL_mutex *mutex;
     SDL_sem *sem;
+#endif
     int initialized;
     bool driver_created;
 } glob_sdl;
@@ -73,31 +79,45 @@  static void GCC_FMT_ATTR (1, 2) sdl_logerr (const char *fmt, ...)
 
 static int sdl_lock (SDLAudioState *s, const char *forfn)
 {
+#if USE_SEMAPHORE
     if (SDL_LockMutex (s->mutex)) {
         sdl_logerr ("SDL_LockMutex for %s failed\n", forfn);
         return -1;
     }
+#else
+    SDL_LockAudio();
+#endif
+
     return 0;
 }
 
 static int sdl_unlock (SDLAudioState *s, const char *forfn)
 {
+#if USE_SEMAPHORE
     if (SDL_UnlockMutex (s->mutex)) {
         sdl_logerr ("SDL_UnlockMutex for %s failed\n", forfn);
         return -1;
     }
+#else
+    SDL_UnlockAudio();
+#endif
+
     return 0;
 }
 
 static int sdl_post (SDLAudioState *s, const char *forfn)
 {
+#if USE_SEMAPHORE
     if (SDL_SemPost (s->sem)) {
         sdl_logerr ("SDL_SemPost for %s failed\n", forfn);
         return -1;
     }
+#endif
+
     return 0;
 }
 
+#if USE_SEMAPHORE
 static int sdl_wait (SDLAudioState *s, const char *forfn)
 {
     if (SDL_SemWait (s->sem)) {
@@ -106,6 +126,7 @@  static int sdl_wait (SDLAudioState *s, const char *forfn)
     }
     return 0;
 }
+#endif
 
 static int sdl_unlock_and_post (SDLAudioState *s, const char *forfn)
 {
@@ -246,6 +267,7 @@  static void sdl_callback (void *opaque, Uint8 *buf, int len)
         int to_mix, decr;
 
         /* dolog ("in callback samples=%d\n", samples); */
+#if USE_SEMAPHORE
         sdl_wait (s, "sdl_callback");
         if (s->exit) {
             return;
@@ -264,6 +286,11 @@  static void sdl_callback (void *opaque, Uint8 *buf, int len)
         if (!sdl->live) {
             goto again;
         }
+#else
+        if (s->exit || !sdl->live) {
+            break;
+        }
+#endif
 
         /* dolog ("in callback live=%d\n", live); */
         to_mix = audio_MIN (samples, sdl->live);
@@ -274,7 +301,11 @@  static void sdl_callback (void *opaque, Uint8 *buf, int len)
 
             /* dolog ("in callback to_mix %d, chunk %d\n", to_mix, chunk); */
             hw->clip (buf, src, chunk);
+#if USE_SEMAPHORE
             sdl->rpos = (sdl->rpos + chunk) % hw->samples;
+#else
+            hw->rpos = (hw->rpos + chunk) % hw->samples;
+#endif
             to_mix -= chunk;
             buf += chunk << hw->info.shift;
         }
@@ -282,12 +313,21 @@  static void sdl_callback (void *opaque, Uint8 *buf, int len)
         sdl->live -= decr;
         sdl->decr += decr;
 
+#if USE_SEMAPHORE
     again:
         if (sdl_unlock (s, "sdl_callback")) {
             return;
         }
+#endif
     }
     /* dolog ("done len=%d\n", len); */
+
+#if (SDL_MAJOR_VERSION >= 2)
+    /* SDL2 does not clear the remaining buffer for us, so do it on our own */
+    if (samples) {
+        memset(buf, 0, samples << hw->info.shift);
+    }
+#endif
 }
 
 static int sdl_write_out (SWVoiceOut *sw, void *buf, int len)
@@ -315,8 +355,12 @@  static int sdl_run_out (HWVoiceOut *hw, int live)
     decr = audio_MIN (sdl->decr, live);
     sdl->decr -= decr;
 
+#if USE_SEMAPHORE
     sdl->live = live - decr;
     hw->rpos = sdl->rpos;
+#else
+    sdl->live = live;
+#endif
 
     if (sdl->live > 0) {
         sdl_unlock_and_post (s, "sdl_run_out");
@@ -405,6 +449,7 @@  static void *sdl_audio_init (void)
         return NULL;
     }
 
+#if USE_SEMAPHORE
     s->mutex = SDL_CreateMutex ();
     if (!s->mutex) {
         sdl_logerr ("Failed to create SDL mutex\n");
@@ -419,6 +464,7 @@  static void *sdl_audio_init (void)
         SDL_QuitSubSystem (SDL_INIT_AUDIO);
         return NULL;
     }
+#endif
 
     s->driver_created = true;
     return s;
@@ -428,8 +474,10 @@  static void sdl_audio_fini (void *opaque)
 {
     SDLAudioState *s = opaque;
     sdl_close (s);
+#if USE_SEMAPHORE
     SDL_DestroySemaphore (s->sem);
     SDL_DestroyMutex (s->mutex);
+#endif
     SDL_QuitSubSystem (SDL_INIT_AUDIO);
     s->driver_created = false;
 }