mirror of https://github.com/proxmox/mirror_qemu
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: Thomas Huth <thuth@redhat.com> Message-id: 1485852398-2327-1-git-send-email-thuth@redhat.com Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>master
parent
1ffc266539
commit
bcf19777df
|
@ -38,10 +38,14 @@
|
||||||
#define AUDIO_CAP "sdl"
|
#define AUDIO_CAP "sdl"
|
||||||
#include "audio_int.h"
|
#include "audio_int.h"
|
||||||
|
|
||||||
|
#define USE_SEMAPHORE (SDL_MAJOR_VERSION < 2)
|
||||||
|
|
||||||
typedef struct SDLVoiceOut {
|
typedef struct SDLVoiceOut {
|
||||||
HWVoiceOut hw;
|
HWVoiceOut hw;
|
||||||
int live;
|
int live;
|
||||||
|
#if USE_SEMAPHORE
|
||||||
int rpos;
|
int rpos;
|
||||||
|
#endif
|
||||||
int decr;
|
int decr;
|
||||||
} SDLVoiceOut;
|
} SDLVoiceOut;
|
||||||
|
|
||||||
|
@ -53,8 +57,10 @@ static struct {
|
||||||
|
|
||||||
static struct SDLAudioState {
|
static struct SDLAudioState {
|
||||||
int exit;
|
int exit;
|
||||||
|
#if USE_SEMAPHORE
|
||||||
SDL_mutex *mutex;
|
SDL_mutex *mutex;
|
||||||
SDL_sem *sem;
|
SDL_sem *sem;
|
||||||
|
#endif
|
||||||
int initialized;
|
int initialized;
|
||||||
bool driver_created;
|
bool driver_created;
|
||||||
} glob_sdl;
|
} 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)
|
static int sdl_lock (SDLAudioState *s, const char *forfn)
|
||||||
{
|
{
|
||||||
|
#if USE_SEMAPHORE
|
||||||
if (SDL_LockMutex (s->mutex)) {
|
if (SDL_LockMutex (s->mutex)) {
|
||||||
sdl_logerr ("SDL_LockMutex for %s failed\n", forfn);
|
sdl_logerr ("SDL_LockMutex for %s failed\n", forfn);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
SDL_LockAudio();
|
||||||
|
#endif
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int sdl_unlock (SDLAudioState *s, const char *forfn)
|
static int sdl_unlock (SDLAudioState *s, const char *forfn)
|
||||||
{
|
{
|
||||||
|
#if USE_SEMAPHORE
|
||||||
if (SDL_UnlockMutex (s->mutex)) {
|
if (SDL_UnlockMutex (s->mutex)) {
|
||||||
sdl_logerr ("SDL_UnlockMutex for %s failed\n", forfn);
|
sdl_logerr ("SDL_UnlockMutex for %s failed\n", forfn);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
SDL_UnlockAudio();
|
||||||
|
#endif
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int sdl_post (SDLAudioState *s, const char *forfn)
|
static int sdl_post (SDLAudioState *s, const char *forfn)
|
||||||
{
|
{
|
||||||
|
#if USE_SEMAPHORE
|
||||||
if (SDL_SemPost (s->sem)) {
|
if (SDL_SemPost (s->sem)) {
|
||||||
sdl_logerr ("SDL_SemPost for %s failed\n", forfn);
|
sdl_logerr ("SDL_SemPost for %s failed\n", forfn);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if USE_SEMAPHORE
|
||||||
static int sdl_wait (SDLAudioState *s, const char *forfn)
|
static int sdl_wait (SDLAudioState *s, const char *forfn)
|
||||||
{
|
{
|
||||||
if (SDL_SemWait (s->sem)) {
|
if (SDL_SemWait (s->sem)) {
|
||||||
|
@ -106,6 +126,7 @@ static int sdl_wait (SDLAudioState *s, const char *forfn)
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static int sdl_unlock_and_post (SDLAudioState *s, const char *forfn)
|
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;
|
int to_mix, decr;
|
||||||
|
|
||||||
/* dolog ("in callback samples=%d\n", samples); */
|
/* dolog ("in callback samples=%d\n", samples); */
|
||||||
|
#if USE_SEMAPHORE
|
||||||
sdl_wait (s, "sdl_callback");
|
sdl_wait (s, "sdl_callback");
|
||||||
if (s->exit) {
|
if (s->exit) {
|
||||||
return;
|
return;
|
||||||
|
@ -264,6 +286,11 @@ static void sdl_callback (void *opaque, Uint8 *buf, int len)
|
||||||
if (!sdl->live) {
|
if (!sdl->live) {
|
||||||
goto again;
|
goto again;
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
if (s->exit || !sdl->live) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* dolog ("in callback live=%d\n", live); */
|
/* dolog ("in callback live=%d\n", live); */
|
||||||
to_mix = audio_MIN (samples, sdl->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); */
|
/* dolog ("in callback to_mix %d, chunk %d\n", to_mix, chunk); */
|
||||||
hw->clip (buf, src, chunk);
|
hw->clip (buf, src, chunk);
|
||||||
|
#if USE_SEMAPHORE
|
||||||
sdl->rpos = (sdl->rpos + chunk) % hw->samples;
|
sdl->rpos = (sdl->rpos + chunk) % hw->samples;
|
||||||
|
#else
|
||||||
|
hw->rpos = (hw->rpos + chunk) % hw->samples;
|
||||||
|
#endif
|
||||||
to_mix -= chunk;
|
to_mix -= chunk;
|
||||||
buf += chunk << hw->info.shift;
|
buf += chunk << hw->info.shift;
|
||||||
}
|
}
|
||||||
|
@ -282,12 +313,21 @@ static void sdl_callback (void *opaque, Uint8 *buf, int len)
|
||||||
sdl->live -= decr;
|
sdl->live -= decr;
|
||||||
sdl->decr += decr;
|
sdl->decr += decr;
|
||||||
|
|
||||||
|
#if USE_SEMAPHORE
|
||||||
again:
|
again:
|
||||||
if (sdl_unlock (s, "sdl_callback")) {
|
if (sdl_unlock (s, "sdl_callback")) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
/* dolog ("done len=%d\n", len); */
|
/* 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)
|
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);
|
decr = audio_MIN (sdl->decr, live);
|
||||||
sdl->decr -= decr;
|
sdl->decr -= decr;
|
||||||
|
|
||||||
|
#if USE_SEMAPHORE
|
||||||
sdl->live = live - decr;
|
sdl->live = live - decr;
|
||||||
hw->rpos = sdl->rpos;
|
hw->rpos = sdl->rpos;
|
||||||
|
#else
|
||||||
|
sdl->live = live;
|
||||||
|
#endif
|
||||||
|
|
||||||
if (sdl->live > 0) {
|
if (sdl->live > 0) {
|
||||||
sdl_unlock_and_post (s, "sdl_run_out");
|
sdl_unlock_and_post (s, "sdl_run_out");
|
||||||
|
@ -405,6 +449,7 @@ static void *sdl_audio_init (void)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if USE_SEMAPHORE
|
||||||
s->mutex = SDL_CreateMutex ();
|
s->mutex = SDL_CreateMutex ();
|
||||||
if (!s->mutex) {
|
if (!s->mutex) {
|
||||||
sdl_logerr ("Failed to create SDL mutex\n");
|
sdl_logerr ("Failed to create SDL mutex\n");
|
||||||
|
@ -419,6 +464,7 @@ static void *sdl_audio_init (void)
|
||||||
SDL_QuitSubSystem (SDL_INIT_AUDIO);
|
SDL_QuitSubSystem (SDL_INIT_AUDIO);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
s->driver_created = true;
|
s->driver_created = true;
|
||||||
return s;
|
return s;
|
||||||
|
@ -428,8 +474,10 @@ static void sdl_audio_fini (void *opaque)
|
||||||
{
|
{
|
||||||
SDLAudioState *s = opaque;
|
SDLAudioState *s = opaque;
|
||||||
sdl_close (s);
|
sdl_close (s);
|
||||||
|
#if USE_SEMAPHORE
|
||||||
SDL_DestroySemaphore (s->sem);
|
SDL_DestroySemaphore (s->sem);
|
||||||
SDL_DestroyMutex (s->mutex);
|
SDL_DestroyMutex (s->mutex);
|
||||||
|
#endif
|
||||||
SDL_QuitSubSystem (SDL_INIT_AUDIO);
|
SDL_QuitSubSystem (SDL_INIT_AUDIO);
|
||||||
s->driver_created = false;
|
s->driver_created = false;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue