diff --git a/Makefile.win32 b/Makefile.win32 index 7942a74575..8c286f59cc 100644 --- a/Makefile.win32 +++ b/Makefile.win32 @@ -11,7 +11,7 @@ HAVE_SDL = 1 HAVE_XML = 1 HAVE_FREETYPE = 1 HAVE_XAUDIO = 1 -HAVE_RSOUND = 1 +HAVE_RSOUND = 0 libsnes ?= -lsnes LIBS = diff --git a/audio/rsound.c b/audio/rsound.c index fc293cb4f5..4f4e047991 100644 --- a/audio/rsound.c +++ b/audio/rsound.c @@ -19,15 +19,44 @@ #include "driver.h" #include #include +#include "buffer.h" +#include +#include "SDL.h" typedef struct rsd { rsound_t *rd; - int latency; - int rate; - int nonblock; + bool nonblock; + volatile bool has_error; + + rsound_fifo_buffer_t *buffer; + + SDL_mutex *lock; + SDL_mutex *cond_lock; + SDL_cond *cond; } rsd_t; +static ssize_t audio_cb(void *data, size_t bytes, void *userdata) +{ + rsd_t *rsd = userdata; + + SDL_mutexP(rsd->lock); + size_t avail = rsnd_fifo_read_avail(rsd->buffer); + size_t write_size = bytes > avail ? avail : bytes; + rsnd_fifo_read(rsd->buffer, data, write_size); + SDL_mutexV(rsd->lock); + SDL_CondSignal(rsd->cond); + + return write_size; +} + +static void err_cb(void *userdata) +{ + rsd_t *rsd = userdata; + rsd->has_error = true; + SDL_CondSignal(rsd->cond); +} + static void* __rsd_init(const char* device, int rate, int latency) { rsd_t *rsd = calloc(1, sizeof(rsd_t)); @@ -42,17 +71,26 @@ static void* __rsd_init(const char* device, int rate, int latency) return NULL; } + rsd->lock = SDL_CreateMutex(); + rsd->cond_lock = SDL_CreateMutex(); + rsd->cond = SDL_CreateCond(); + + rsd->buffer = rsnd_fifo_new(1024 * 4); + int channels = 2; int format = RSD_S16_NE; rsd_set_param(rd, RSD_CHANNELS, &channels); rsd_set_param(rd, RSD_SAMPLERATE, &rate); + rsd_set_param(rd, RSD_LATENCY, &latency); if ( device != NULL ) rsd_set_param(rd, RSD_HOST, (void*)device); rsd_set_param(rd, RSD_FORMAT, &format); + rsd_set_callback(rd, audio_cb, err_cb, 256, rsd); + if ( rsd_start(rd) < 0 ) { free(rsd); @@ -60,14 +98,7 @@ static void* __rsd_init(const char* device, int rate, int latency) return NULL; } - int min_latency = (rsd_delay_ms(rd) > latency) ? (rsd_delay_ms(rd) * 3 / 2) : latency; - - rsd_set_param(rd, RSD_LATENCY, &min_latency); - rsd->rd = rd; - rsd->latency = min_latency; - rsd->rate = rate; - return rsd; } @@ -75,26 +106,46 @@ static ssize_t __rsd_write(void* data, const void* buf, size_t size) { rsd_t *rsd = data; - if ( (rsd_delay_ms(rsd->rd) > rsd->latency || rsd_get_avail(rsd->rd) < size) && rsd->nonblock ) - return 0; - - if ( size == 0 ) - return 0; - - rsd_delay_wait(rsd->rd); - if ( rsd_write(rsd->rd, buf, size) == 0 ) + if (rsd->has_error) return -1; - if ( rsd_delay_ms(rsd->rd) < rsd->latency/2 ) + if (rsd->nonblock) { - int ms = rsd->latency/2; - size_t size = (ms * rsd->rate * 4) / 1000; - void *temp = calloc(1, size); - rsd_write(rsd->rd, temp, size); - free(temp); + SDL_mutexP(rsd->lock); + size_t avail = rsnd_fifo_write_avail(rsd->buffer); + size_t write_amt = avail > size ? size : avail; + rsnd_fifo_write(rsd->buffer, buf, write_amt); + SDL_mutexV(rsd->lock); + return write_amt; } + else + { + size_t written = 0; + while (written < size && !rsd->has_error) + { + SDL_mutexP(rsd->lock); + size_t avail = rsnd_fifo_write_avail(rsd->buffer); - return size; + if (avail == 0) + { + SDL_mutexV(rsd->lock); + if (!rsd->has_error) + { + SDL_mutexP(rsd->cond_lock); + SDL_CondWait(rsd->cond, rsd->cond_lock); + SDL_mutexV(rsd->cond_lock); + } + } + else + { + size_t write_amt = size - written > avail ? avail : size - written; + rsnd_fifo_write(rsd->buffer, (const char*)buf + written, write_amt); + SDL_mutexV(rsd->lock); + written += write_amt; + } + } + return written; + } } static bool __rsd_stop(void *data) @@ -126,6 +177,12 @@ static void __rsd_free(void *data) rsd_stop(rsd->rd); rsd_free(rsd->rd); + + rsnd_fifo_free(rsd->buffer); + SDL_DestroyMutex(rsd->lock); + SDL_DestroyMutex(rsd->cond_lock); + SDL_DestroyCond(rsd->cond); + free(rsd); } diff --git a/qb/config.libs.sh b/qb/config.libs.sh index ef796c4d45..d2f48e9dfe 100644 --- a/qb/config.libs.sh +++ b/qb/config.libs.sh @@ -24,7 +24,7 @@ else check_lib AL -lopenal alcOpenDevice fi -check_lib RSOUND -lrsound rsd_init +check_pkgconf RSOUND rsound 1.1 check_lib ROAR -lroar roar_vs_new check_lib JACK -ljack jack_client_open check_pkgconf PULSE libpulse diff --git a/ssnes.c b/ssnes.c index f5c53af2ed..7e4af51677 100644 --- a/ssnes.c +++ b/ssnes.c @@ -975,7 +975,13 @@ static void check_pause(void) { SSNES_LOG("Unpaused!\n"); if (driver.audio_data) - driver.audio->start(driver.audio_data); + { + if (!driver.audio->start(driver.audio_data)) + { + SSNES_ERR("Failed to resume audio driver! Will continue without audio!\n"); + g_extern.audio_active = false; + } + } } } else if (focus && !old_focus) @@ -983,7 +989,13 @@ static void check_pause(void) SSNES_LOG("Unpaused!\n"); g_extern.is_paused = false; if (driver.audio_data) - driver.audio->start(driver.audio_data); + { + if (!driver.audio->start(driver.audio_data)) + { + SSNES_ERR("Failed to resume audio driver! Will continue without audio!\n"); + g_extern.audio_active = false; + } + } } else if (!focus && old_focus) {