Commit bcf19777 authored by Thomas Huth's avatar Thomas Huth Committed by Gerd Hoffmann
Browse files

audio/sdlaudio: Allow audio playback with SDL2



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: default avatarThomas Huth <thuth@redhat.com>
Message-id: 1485852398-2327-1-git-send-email-thuth@redhat.com
Signed-off-by: default avatarGerd Hoffmann <kraxel@redhat.com>
parent 1ffc2665
Loading
Loading
Loading
Loading
+48 −0
Original line number Diff line number Diff line
@@ -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;
}